160 lines
4.2 KiB
C
160 lines
4.2 KiB
C
#include <string.h>
|
|
#include <stdio.h>
|
|
#include <syslog.h>
|
|
#include <errno.h>
|
|
#include <libintl.h>
|
|
#include <locale.h>
|
|
|
|
#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");
|
|
}
|
|
}
|