#include #include #include #include #include #include #include "kylin-chkname.h" #define USERNAME_MAXLEN 32 #define RESERVED_NAMES "/usr/share/kylin-chkname/reserved-names" #define _(STRING) gettext(STRING) static int reserve_check(const char *name) { FILE *fp; char buf[USERNAME_MAXLEN+2]; int find = 0; fp = fopen(RESERVED_NAMES, "r"); if (NULL == fp) { syslog(LOG_INFO, "Open reserved-names file failed: %s", strerror(errno)); find = 2; return find; } while (fgets(buf, USERNAME_MAXLEN+2, fp) != NULL) { if (!strlen(buf) || !strncmp(buf, "#", 1)) continue; buf[strlen(buf) - 1] = '\0'; if (!strcmp(name, buf)) { find = 1; break; } } fclose(fp); return find; } int kylin_username_check(const char *name, int reserve) { /* * User/group names must match gnu e-regex: * [a-zA-Z0-9_.][a-zA-Z0-9_.-]{0,30}[a-zA-Z0-9_.$-]? * * as a non-POSIX, extension, allow "$" as the last char for * sake of Samba 3.x "add machine script" * * Also do not allow fully numeric, hexadecimal, octal number names * or just "." or "..". */ if (name == NULL) return NAME_ERROR; if (strlen(name) == 0 || strlen(name) > USERNAME_MAXLEN) return LENGTH_ERROR; if (reserve && reserve_check(name)) { if (reserve_check(name) == 1) return RESERVED_ERROR; else return OPEN_RESERVED_NAMES_ERROR; } if ('.' == *name && (('.' == name[1] && '\0' == name[2]) || '\0' == name[1])) return REGEX_ERROR; if (!((*name >= 'a' && *name <= 'z') || (*name >= 'A' && *name <= 'Z') || (*name >= '0' && *name <= '9') || *name == '_' || *name == '.')) return FIRST_CHAR_ERROR; int numberic = 1; int hex = 1; int octal = 1; int chars_checked = 1; if (*name != '0' || *(name + 1) != 'x') hex = 0; if (*name != '0' || *(name + 1) != 'o') octal = 0; if (*name < '0' || *name > '9') numberic = 0; while ('\0' != *++name) { if (!((*name >= 'a' && *name <= 'z') || (*name >= 'A' && *name <= 'Z') || (*name >= '0' && *name <= '9') || *name == '_' || *name == '.' || *name == '-' || (*name == '$' && name[1] == '\0'))) return REGEX_ERROR; if (hex && chars_checked >= 2) { if ((*name < '0' || *name > '9') && (*name < 'A' || *name > 'F') && (*name < 'a' || *name > 'f')) hex = 0; } if (octal && chars_checked >= 2) { if (*name < '0' || *name > '7') octal = 0; } if (numberic) { if (*name < '0' || *name > '9') numberic = 0; } chars_checked++; } if (hex) return HEX_ERROR; if (octal) return OCTAL_ERROR; if (numberic) return NUMBERIC_ERROR; return CHECK_SUCCESS; } char *kylin_username_strerror(int err_num) { setlocale(LC_ALL, ""); bindtextdomain("kylin-chkname", "/usr/share/locale"); textdomain("kylin-chkname"); switch(err_num) { case CHECK_SUCCESS: return _("Success"); case LENGTH_ERROR: return _("Username's length must be between 1 and 32 characters"); case REGEX_ERROR: return _("Invalid username regex"); case RESERVED_ERROR: return _("Reserved username"); case NAME_ERROR: return _("Parameter name is null"); case OPEN_RESERVED_NAMES_ERROR: return _("Open reserved-names file failed"); case FIRST_CHAR_ERROR: return _("Username must start with a letter, number, dot, or underscore"); case HEX_ERROR: return _("Username cannot be a hexadecimal number"); case OCTAL_ERROR: return _("Username cannot be octal number"); case NUMBERIC_ERROR: return _("Username cannot be fully numeric"); default: return _("Unknown error"); } }