On Monday 01 August 2011 22:01, Tito wrote: > Hi, > this patch improves the checks performed on usernames > with the die_if_bad_username() function by adduser and addgroup. > The changes are: > 1) better comments; > 2) use of the portable filename character set plus '@' and '$'; > 3) don't use isalnum as it will allow non-ASCII letters in legacy 8-bit > locales as pointed out by Rich Felker;
We use ASCII-only isalnum throughout bbox anyway. But ok. > 3) enforce minimum length of 1 char (or at least 2 chars if '$' is used as > last char); This was already the case, I think. > 4) enforce maximum length of LOGIN_NAME_MAX (including null termination); Ok. > 5) don't use goto to jump into the loop (requested by Matthias Andree); Don't see why. It's efficient. > 6) don't allow '$', '.', '@' and '-' as first char; > 7) allow '$' only as last char. Ok. > 8) don't print the illegal char in error message as if it is a wide char it > will be unreadable. Ok. On Tuesday 02 August 2011 21:57, Tito wrote: > Hi, > minor improvements vs. v2 patch: > 1) some more comments added. > 2) we now print the position of the illegal character. > > Hints, critics, improvements are welcome. > Thanks to all who helped. > > Ciao, > Tito > > void FAST_FUNC die_if_bad_username(const char *name) > { > const char *s = name; > > assert(name != NULL); > > /* The minimum size of the login name is one char or two if > * last char is the '$', this exception is catched later > * as the dollar sign could not be the first char. > * The maximum size of the login name is LOGIN_NAME_MAX > * including the terminating null byte. > */ > if (!*name || strlen(name) + 1 > LOGIN_NAME_MAX) > bb_error_msg_and_die("illegal name length"); We can check length at the end by calcualting (name - s). This way, we don't need strlen call. Zero-length check is not necessary as this case is already caught by the checking loop. > do { > /* We don't use isalnum as it will allow locale-specific > non-ASCII */ > /* letters in legacy 8-bit locales. */ > if (((*name == '-' || *name == '.' || *name == '@') && name != > s) /* not as first char */ > || (*name == '$' && (!name[1] && name != s)) /* not as first, > only as last char */ Come to think about it, '@' can't be used in usernames: @ is used to delimit username from hostname: user@host > || *name == '_' > || (*name >= 48 && *name <= 57) /* 0-9 */ > || (*name >= 65 && *name <= 90) /* A-Z */ > || (*name >= 97 && *name <= 122) /* a-z */ > ) { > continue; > } > bb_error_msg_and_die("illegal character at position '%d'", name > - s); > } while (*++name); > } How about this? void FAST_FUNC die_if_bad_username(const char *name) { const char *start = name; /* 1st char being dash or dot isn't valid: * for example, name like ".." can make adduser * chown "/home/.." recursively - NOT GOOD. * Name of just a single "$" is also rejected. */ goto skip; do { unsigned char ch; /* These chars are valid unless they are at the 1st pos: */ if (*name == '-' || *name == '.' /* $ is allowed if it's the last char: */ || (*name == '$' && !name[1]) ) { continue; } skip: ch = *name; if (ch == '_' /* || ch == '@' -- we disallow this too. Think about "user@host" */ /* open-coded isalnum: */ || (ch >= '0' && ch <= '9') || ((ch|0x20) >= 'a' && (ch|0x20) <= 'z') ) { continue; } bb_error_msg_and_die("illegal character with code %u at position %u", (unsigned)ch, (unsigned)(name - start)); } while (*++name); /* The minimum size of the login name is one char or two if * last char is the '$'. Violations of this are caught above. * The maximum size of the login name is LOGIN_NAME_MAX * including the terminating null byte. */ if (name - start >= LOGIN_NAME_MAX) bb_error_msg_and_die("name is too long"); } function old new delta die_if_bad_username 77 97 +20 -- vda _______________________________________________ busybox mailing list busybox@busybox.net http://lists.busybox.net/mailman/listinfo/busybox