diff options
author | Rob Landley <rob@landley.net> | 2013-10-16 19:30:17 -0500 |
---|---|---|
committer | Rob Landley <rob@landley.net> | 2013-10-16 19:30:17 -0500 |
commit | d0f7935f637df5d4794aa782def96cc3db8779ed (patch) | |
tree | e2ba730174003a026302abf6ce57c9126c7f884b /lib | |
parent | 26f52eb13eb27c5aefdb644d96408376b5d63783 (diff) | |
download | toybox-d0f7935f637df5d4794aa782def96cc3db8779ed.tar.gz |
Prep work for useradd by Ashwini Sharma.
Diffstat (limited to 'lib')
-rw-r--r-- | lib/lib.h | 5 | ||||
-rw-r--r-- | lib/password.c | 172 |
2 files changed, 147 insertions, 30 deletions
@@ -187,6 +187,11 @@ mode_t string_to_mode(char *mode_str, mode_t base); void mode_to_string(mode_t mode, char *buf); // password helper functions +#define MAX_SALT_LEN 20 //3 for id, 16 for key, 1 for '\0' +#define SYS_FIRST_ID 100 +#define SYS_LAST_ID 999 +int get_salt(char *salt, char * algo); +void is_valid_username(const char *name); int read_password(char * buff, int buflen, char* mesg); int update_password(char *filename, char* username, char* encrypted); diff --git a/lib/password.c b/lib/password.c index d1489eb3..b340ef48 100644 --- a/lib/password.c +++ b/lib/password.c @@ -1,19 +1,87 @@ -/* pwdutils.c - password read/update helper functions. +/* password.c - password read/update helper functions. * * Copyright 2012 Ashwini Kumar <ak.ashwini@gmail.com> */ #include "toys.h" +#include "xregcomp.h" #include <time.h> +static unsigned int random_number_generator(int fd) +{ + unsigned int randnum; + + xreadall(fd, &randnum, sizeof(randnum)); + return randnum; +} + +static char inttoc(int i) +{ + // salt value uses 64 chracters in "./0-9a-zA-Z" + const char character_set[]="./0123456789abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + + i &= 0x3f; // masking for using 10 bits only + return character_set[i]; +} + +int get_salt(char *salt, char *algo) +{ + int i, randfd, salt_length = 0, offset; + + if (!strcmp(algo,"des")){ + // 2 bytes salt value is used in des + salt_length = 2; + offset = 0; + } else { + *salt++ = '$'; + if (!strcmp(algo,"md5")){ + *salt++ = '1'; + // 8 bytes salt value is used in md5 + salt_length = 8; + } else if (!strcmp(algo,"sha256")){ + *salt++ = '5'; + // 16 bytes salt value is used in sha256 + salt_length = 16; + } else if (!strcmp(algo,"sha512")){ + *salt++ = '6'; + // 16 bytes salt value is used in sha512 + salt_length = 16; + } else return -1; + + *salt++ = '$'; + offset = 3; + } + + randfd = xopen("/dev/urandom", O_RDONLY); + for (i=0; i<salt_length; i++) + salt[i] = inttoc(random_number_generator(randfd)); + salt[salt_length+1] = '\0'; + xclose(randfd); + + return offset; +} + +static void handle(int signo) +{ + //Dummy.. so that read breaks on the signal, + //instead of the applocation exit +} + int read_password(char * buff, int buflen, char* mesg) { int i = 0; struct termios termio, oldtermio; + struct sigaction sa, oldsa; + tcgetattr(0, &oldtermio); tcflush(0, TCIFLUSH); termio = oldtermio; + memset(&sa, 0, sizeof(sa)); + sa.sa_handler = handle; + sigaction(SIGINT, &sa, &oldsa); + termio.c_iflag &= ~(IUCLC|IXON|IXOFF|IXANY); termio.c_lflag &= ~(ECHO|ECHOE|ECHOK|ECHONL|TOSTOP); tcsetattr(0, TCSANOW, &termio); @@ -25,7 +93,10 @@ int read_password(char * buff, int buflen, char* mesg) int ret = read(0, &buff[i], 1); if ( ret < 0 ) { buff[0] = 0; + sigaction(SIGINT, &oldsa, NULL); tcsetattr(0, TCSANOW, &oldtermio); + xputc('\n'); + fflush(stdout); return 1; } else if (ret == 0 || buff[i] == '\n' || buff[i] == '\r' || buflen == i+1) { @@ -34,35 +105,45 @@ int read_password(char * buff, int buflen, char* mesg) } i++; } - + sigaction(SIGINT, &oldsa, NULL); tcsetattr(0, TCSANOW, &oldtermio); puts(""); fflush(stdout); return 0; } -static char *get_nextcolon(const char *line, char delim) +static char *get_nextcolon(char *line, int cnt) { - char *current_ptr = NULL; - if((current_ptr = strchr(line, ':')) == NULL) error_exit("Invalid Entry\n"); - return current_ptr; + while (cnt--) { + if (!(line = strchr(line, ':'))) error_exit("Invalid Entry\n"); + line++; //jump past the colon + } + return line; } -int update_password(char *filename, char* username, char* encrypted) +/*update_password is used by multiple utilities to update /etc/passwd, + * /etc/shadow, /etc/group and /etc/gshadow files, + * which are used as user, group databeses + * entry can be + * 1. encrypted password, when updating user password. + * 2. complete entry for user details, when creating new user + * 3. group members comma',' separated list, when adding user to group + * 4. complete entry for group details, when creating new group + */ +int update_password(char *filename, char* username, char* entry) { - char *filenamesfx = NULL, *namesfx = NULL; - char *shadow = NULL, *sfx = NULL; + char *filenamesfx = NULL, *namesfx = NULL, *shadow = NULL, + *sfx = NULL, *line = NULL; FILE *exfp, *newfp; - int ret = -1; //fail + int ret = -1, found = 0; struct flock lock; - char *line = NULL; shadow = strstr(filename, "shadow"); filenamesfx = xmsprintf("%s+", filename); sfx = strchr(filenamesfx, '+'); exfp = fopen(filename, "r+"); - if(!exfp) { + if (!exfp) { perror_msg("Couldn't open file %s",filename); goto free_storage; } @@ -70,7 +151,7 @@ int update_password(char *filename, char* username, char* encrypted) *sfx = '-'; ret = unlink(filenamesfx); ret = link(filename, filenamesfx); - if(ret < 0) error_msg("can't create backup file"); + if (ret < 0) error_msg("can't create backup file"); *sfx = '+'; lock.l_type = F_WRLCK; @@ -79,12 +160,12 @@ int update_password(char *filename, char* username, char* encrypted) lock.l_len = 0; ret = fcntl(fileno(exfp), F_SETLK, &lock); - if(ret < 0) perror_msg("Couldn't lock file %s",filename); + if (ret < 0) perror_msg("Couldn't lock file %s",filename); lock.l_type = F_UNLCK; //unlocking at a later stage newfp = fopen(filenamesfx, "w+"); - if(!newfp) { + if (!newfp) { error_msg("couldn't open file for writing"); ret = -1; fclose(exfp); @@ -93,29 +174,34 @@ int update_password(char *filename, char* username, char* encrypted) ret = 0; namesfx = xmsprintf("%s:",username); - while((line = get_line(fileno(exfp))) != NULL) + while ((line = get_line(fileno(exfp))) != NULL) { - if(strncmp(line, namesfx, strlen(namesfx)) != 0) + if (strncmp(line, namesfx, strlen(namesfx))) fprintf(newfp, "%s\n", line); else { char *current_ptr = NULL; - fprintf(newfp, "%s%s:",namesfx,encrypted); - current_ptr = get_nextcolon(line, ':'); //past username - current_ptr++; //past colon ':' after username - current_ptr = get_nextcolon(current_ptr, ':'); //past passwd - current_ptr++; //past colon ':' after passwd - if(shadow) { - fprintf(newfp, "%u:",(unsigned)(time(NULL))/(24*60*60)); - current_ptr = get_nextcolon(current_ptr, ':'); - current_ptr++; //past time stamp colon. - fprintf(newfp, "%s\n",current_ptr); + + found = 1; + if (!strcmp(toys.which->name, "passwd")) { + fprintf(newfp, "%s%s:",namesfx, entry); + current_ptr = get_nextcolon(line, 2); //past passwd + if (shadow) { + fprintf(newfp, "%u:",(unsigned)(time(NULL))/(24*60*60)); + current_ptr = get_nextcolon(current_ptr, 1); + fprintf(newfp, "%s\n",current_ptr); + } else fprintf(newfp, "%s\n",current_ptr); + } else if (!strcmp(toys.which->name, "groupadd") || + !strcmp(toys.which->name, "addgroup")){ + current_ptr = get_nextcolon(line, 3); //past gid/admin list + *current_ptr = '\0'; + fprintf(newfp, "%s", line); + fprintf(newfp, "%s\n", entry); } - else fprintf(newfp, "%s\n",current_ptr); } - free(line); } free(namesfx); + if (!found) fprintf(newfp, "%s\n", entry); fcntl(fileno(exfp), F_SETLK, &lock); fclose(exfp); @@ -124,7 +210,7 @@ int update_password(char *filename, char* username, char* encrypted) fsync(fileno(newfp)); fclose(newfp); rename(filenamesfx, filename); - if(errno) { + if (errno) { perror_msg("File Writing/Saving failed: "); unlink(filenamesfx); ret = -1; @@ -134,3 +220,29 @@ free_storage: free(filenamesfx); return ret; } + +void is_valid_username(const char *name) +{ + regex_t rp; + regmatch_t rm[1]; + int eval; + char *regex = "^[_.A-Za-z0-9][-_.A-Za-z0-9]*"; //User name REGEX + + xregcomp(&rp, regex, REG_NEWLINE); + + /* compare string against pattern -- remember that patterns + are anchored to the beginning of the line */ + eval = regexec(&rp, name, 1, rm, 0); + regfree(&rp); + if (!eval && !rm[0].rm_so) { + int len = strlen(name); + if ((rm[0].rm_eo == len) || + (rm[0].rm_eo == len - 1 && name[len - 1] == '$')) { + if (len >= LOGIN_NAME_MAX) error_exit("name is too long"); + else return; + } + } + error_exit("'%s', not valid %sname",name, + (((toys.which->name[3] == 'g') || + (toys.which->name[0] == 'g'))? "group" : "user")); +} |