Hi list, Attached are the implementations for groupadd, useradd and mkpasswd commands.
Patches are as follows
1. __lib.patch__ : this includes changes made to lib/lib.h and
__lib/password.c__.
lib/passowrd.c is modified to share the function __update_password()__
among groupadd, useradd commands.
This also has the factored out code, common to both, for __passwd__ and
__mkpasswd__.
Also has the cosmetic cleanup changes.
2. __passwd.c.patch__ : this file is modified due to the common code
factoring out and cosmetic cleanup changes.
3. groupadd and useradd has alias for addgroup and adduser, due to the
requirement constraint at my end.
_adduser_ does invoke the passwd utility to set the user password on
creation.
Looking forward to your comments. Add to the tree if it can be.
regards,
Ashwini
lib.patch
Description: Binary data
passwd.c.patch
Description: Binary data
/* groupadd.c - create a new group * * Copyright 2013 Ashwini Kumar <[email protected]> * Copyright 2013 Kyungwan Han <[email protected]> * * See http://refspecs.linuxfoundation.org/LSB_4.1.0/LSB-Core-generic/LSB-Core-generic/groupadd.html USE_GROUPADD(NEWTOY(groupadd, "<1>2g#<0S", TOYFLAG_NEEDROOT|TOYFLAG_SBIN)) USE_GROUPADD(OLDTOY(addgroup, groupadd, OPTSTR_groupadd, TOYFLAG_NEEDROOT|TOYFLAG_SBIN)) config GROUPADD bool "groupadd" default y help usage: groupadd [-S] [-g GID] [USER] GROUP Add a group or add a user to a group -g GID Group id -S Create a system group */ #define FOR_groupadd #include "toys.h" #define GROUP_PATH "/etc/group" #define SECURE_GROUP_PATH "/etc/gshadow" GLOBALS( long gid; ) /* Add a new group to the system, if GID is given then that is validated * to be free, else a free GID is choosen by self. * SYSTEM IDs are considered in the range 100 ... 999 * update_group(), updates the entries in /etc/group, /etc/gshadow files */ static void new_group() { char *entry = NULL; int max = INT_MAX; if (toys.optflags & FLAG_g) { if (TT.gid > INT_MAX) error_exit("gid should be less than '%d' ", INT_MAX); if (getgrgid(TT.gid)) error_exit("group '%ld' is in use", TT.gid); } else { if (toys.optflags & FLAG_S) { TT.gid = SYS_FIRST_ID; max = SYS_LAST_ID; } else { TT.gid = SYS_LAST_ID + 1; //i.e. starting from 1000 max = 60000; // as per config file on Linux desktop } //find unused gid while (TT.gid <= max) { if (!getgrgid(TT.gid)) break; if (TT.gid == max) error_exit("no more free gids left"); TT.gid++; } } entry = xmsprintf("%s:%s:%d:", *toys.optargs, "x", TT.gid); update_password(GROUP_PATH, *toys.optargs, entry); free(entry); entry = xmsprintf("%s:%s::", *toys.optargs, "!"); update_password(SECURE_GROUP_PATH, *toys.optargs, entry); free(entry); } void groupadd_main(void) { struct group *grp = NULL; char *entry = NULL; if (toys.optflags && toys.optc == 2) { toys.exithelp = 1; error_exit("options, user and group can't be together"); } if (toys.optc == 2) { //add user to group //toys.optargs[0]- user, toys.optargs[1] - group if (!getpwnam(toys.optargs[0])) error_exit("user '%s' does not exist", toys.optargs[0]); if (!(grp = getgrnam(toys.optargs[1]))) error_exit("group '%s' does not exist", toys.optargs[1]); if (!grp->gr_mem) entry = xmsprintf("%s", *toys.optargs); else { int i; for (i = 0; grp->gr_mem[i]; i++) if (!strcmp(grp->gr_mem[i], *toys.optargs)) return; entry = xstrdup(""); for (i=0; grp->gr_mem[i]; i++) { entry = xrealloc(entry, strlen(entry) + strlen(grp->gr_mem[i]) + 2); strcat(entry, grp->gr_mem[i]); strcat(entry, ","); } entry = xrealloc(entry, strlen(entry) + strlen(*toys.optargs) + 1); strcat(entry, *toys.optargs); } update_password(GROUP_PATH, grp->gr_name, entry); update_password(SECURE_GROUP_PATH, grp->gr_name, entry); free(entry); } else { //new group to be created /* investigate the group to be created */ if ((grp = getgrnam(*toys.optargs))) error_exit("group '%s' is in use", *toys.optargs); setlocale(LC_ALL, "C"); is_valid_username(*toys.optargs); new_group(); } }
/* useradd.c - add a new user * * Copyright 2013 Ashwini Kumar <[email protected]> * Copyright 2013 Kyungwan Han <[email protected]> * * See http://refspecs.linuxfoundation.org/LSB_4.1.0/LSB-Core-generic/LSB-Core-generic/useradd.html USE_USERADD(NEWTOY(useradd, "<1>2u#<0G:s:g:h:SDH", TOYFLAG_NEEDROOT|TOYFLAG_SBIN)) USE_USERADD(OLDTOY(adduser, useradd, OPTSTR_useradd, TOYFLAG_NEEDROOT|TOYFLAG_SBIN)) config USERADD bool "useradd" default y help usage: useradd [-SDH] [-hDIR] [-sSHELL] [-G GRP] [-gGECOS] [-uUID] USER [GROUP] Create new user, or add USER to GROUP -h DIR Home directory -g GECOS GECOS field -s SHELL Login shell -G GRP Add user to existing group -S Create a system user -D Don't assign a password -H Don't create home directory -u UID User id */ #define FOR_useradd #include "toys.h" GLOBALS( char *dir; char *gecos; char *shell; char *u_grp; long uid; long gid; ) static char* get_shell(void) { char *shell = getenv("SHELL"); if (!shell) { struct passwd *pw; pw = getpwuid(getuid()); if (pw && pw->pw_shell && pw->pw_shell[0]) shell = pw->pw_shell; else shell = "/bin/sh"; } return xstrdup(shell); } /* exec_wait() function does a fork(), and exec the command, * waits for the child to exit and return the status to parent */ static int exec_wait(char **args) { int status = 0; pid_t pid = fork(); if (!pid) xexec(args); else if (pid > 0) waitpid(pid, &status, 0); else perror_exit("fork failed"); return WEXITSTATUS(status); } /* create_copy_skel(), This function will create the home directory of the * user, by copying /etc/skel/ contents to /home/<username>. * Then change the ownership of home dir to the UID and GID of new user, * and Mode to 0700, i.e. rwx------ for user. */ static void create_copy_skel(char *skel, char *hdir) { char *args[5]; struct stat sb; if (toys.optflags & FLAG_H) return; umask(0); args[4] = NULL; if (stat(hdir, &sb)) { args[0] = "cp"; args[1] = "-R"; args[2] = skel; args[3] = hdir; // Copy /etc/skel to home dir toys.exitval = exec_wait(args); args[0] = "chown"; args[1] = "-R"; args[2] = xmsprintf("%u:%u", TT.uid, TT.gid); args[3] = hdir; //Change ownership to that of UID and GID of new user toys.exitval = exec_wait(args); } else xprintf("Warning: home directory for the user already exists\n" "Not copying any file from skel directory into it.\n"); if (chown(hdir, TT.uid, TT.gid) || chmod(hdir, 0700)) perror_exit("chown/chmod failed for '%s'", hdir); } /* Add a new group to the system, if UID is given then that is validated * to be free, else a free UID is choosen by self. * SYSTEM IDs are considered in the range 100 ... 999 * add_user(), add a new entry in /etc/passwd, /etc/shadow files */ static void new_user() { struct passwd pwd; char *entry, *args[4]; int max = INT_MAX; pwd.pw_name = *toys.optargs; pwd.pw_passwd = (char *)"x"; if (toys.optflags & FLAG_g) pwd.pw_gecos = TT.gecos; else pwd.pw_gecos = "Linux User,"; if (toys.optflags & FLAG_h) pwd.pw_dir = TT.dir; else pwd.pw_dir = xmsprintf("/home/%s", *toys.optargs); if (toys.optflags & FLAG_s) pwd.pw_shell = TT.shell; else pwd.pw_shell = get_shell(); if (toys.optflags & FLAG_u) { if (TT.uid > INT_MAX) error_exit("uid should be less than '%d' ", INT_MAX); if (getpwuid(TT.uid)) error_exit("user '%ld' is in use", TT.uid); pwd.pw_uid = TT.uid; } else { if (toys.optflags & FLAG_S) { TT.uid = SYS_FIRST_ID; max = SYS_LAST_ID; } else { TT.uid = SYS_LAST_ID + 1; //i.e. starting from 1000 max = 60000; // as per config file on Linux desktop } //find unused uid while (TT.uid <= max) { if (!getpwuid(TT.uid)) break; if (TT.uid == max) error_exit("no more free uids left"); TT.uid++; } pwd.pw_uid = TT.uid; } if (toys.optflags & FLAG_G) { struct group *gr = getgrnam(TT.u_grp); if (!gr) error_exit("The group '%s' doesn't exist", TT.u_grp); TT.gid = gr->gr_gid; } else { // Set the GID for the user, if not specified if (toys.optflags & FLAG_S) { TT.gid = SYS_FIRST_ID; max = SYS_LAST_ID; } else TT.gid = ((TT.uid > SYS_LAST_ID) ? TT.uid : SYS_LAST_ID + 1); if (getgrnam(pwd.pw_name)) error_exit("group '%s' is in use", pwd.pw_name); //find unused gid while (TT.gid <= max) { if (!getgrgid(TT.gid)) break; if (TT.gid == max) error_exit("no more free gids left"); TT.gid++; } } pwd.pw_gid = TT.gid; if (!(toys.optflags & FLAG_G)) { // Create a new group for user //add group, invoke addgroup command args[0] = "groupadd"; args[1] = toys.optargs[0]; args[2] = xmsprintf("-g%ld", pwd.pw_gid); args[3] = NULL; if (exec_wait(args)) error_msg("addgroup fail"); } /*add user to system * 1. add an entry to /etc/passwd and /etcshadow file * 2. Copy /etc/skel dir contents to use home dir * 3. update the user passwd by running 'passwd' utility */ // 1. add an entry to /etc/passwd and /etc/shadow file entry = xmsprintf("%s:%s:%ld:%ld:%s:%s:%s", pwd.pw_name, pwd.pw_passwd, pwd.pw_uid, pwd.pw_gid, pwd.pw_gecos, pwd.pw_dir, pwd.pw_shell); if (update_password("/etc/passwd", pwd.pw_name, entry)) error_exit("updating passwd file failed"); free(entry); if (toys.optflags & FLAG_S) entry = xmsprintf("%s:!!:%u::::::", pwd.pw_name, (unsigned)(time(NULL))/(24*60*60)); //passwd is not set initially else entry = xmsprintf("%s:!!:%u:%ld:%ld:%ld:::", pwd.pw_name, (unsigned)(time(NULL))/(24*60*60), 0, 99999, 7); //passwd is not set initially update_password("/etc/shadow", pwd.pw_name, entry); free(entry); //2. craete home dir & copy skel dir to home if (!(toys.optflags & FLAG_S)) create_copy_skel("/etc/skel", pwd.pw_dir); //3. update the user passwd by running 'passwd' utility if (!(toys.optflags & FLAG_D)) { args[0] = "passwd"; args[1] = pwd.pw_name; args[2] = NULL; if (exec_wait(args)) error_exit("changing user passwd failed"); } if (toys.optflags & FLAG_G) { /*add user to the existing group, invoke addgroup command */ args[0] = "groupadd"; args[1] = toys.optargs[0]; args[2] = TT.u_grp; args[3] = NULL; if (exec_wait(args)) error_exit("adding user to group Failed"); } } /* Entry point for useradd feature * Specifying options and User, Group at cmdline is treated as error. * If only 2 parameters (Non-Option) are given, then User is added to the * Group */ void useradd_main(void) { struct passwd *pwd = NULL; if (toys.optflags && toys.optc == 2) { toys.exithelp = 1; error_exit("options, user and group can't be together"); } if (toys.optc == 2) { //add user to group //toys.optargs[0]- user, toys.optargs[1] - group char *args[4]; args[0] = "groupadd"; args[1] = toys.optargs[0]; args[2] = toys.optargs[1]; args[3] = NULL; toys.exitval = exec_wait(args); } else { //new user to be created // investigate the user to be created if ((pwd = getpwnam(*toys.optargs))) error_exit("user '%s' is in use", *toys.optargs); is_valid_username(*toys.optargs); //validate the user name new_user(); } }
/* mkpasswd.c - encrypt the given passwd using salt * * Copyright 2013 Ashwini Kumar <[email protected]> * Copyright 2013 Kyungwan Han <[email protected]> * * No Standard USE_MKPASSWD(NEWTOY(mkpasswd, ">2S:m:P#=0<0", TOYFLAG_USR|TOYFLAG_BIN)) config MKPASSWD bool "mkpasswd" default y help usage: mkpasswd [OPTIONS] [PASSWORD] [SALT] Crypt PASSWORD using crypt(3) -P N Read password from fd N -m TYPE Encryption method, when TYPE='help', then show the methods available -S SALT */ #define FOR_mkpasswd #include "toys.h" #include "lib/xregcomp.h" GLOBALS( long pfd; char *method; char *salt; ) /* * validate the salt provided by user. * the allowed character set for salt is [./A-Za-z0-9] */ static void is_salt_valid(char *salt) { regex_t rp; regmatch_t rm[1]; char *regex = "[./A-Za-z0-9]*"; //salt REGEX xregcomp(&rp, regex, REG_NEWLINE); /* compare string against pattern -- remember that patterns are anchored to the beginning of the line */ if (regexec(&rp, salt, 1, rm, 0) == 0 && rm[0].rm_so == 0 && rm[0].rm_eo == strlen(salt)) return; error_exit("salt should be in character set [./A-Za-z0-9]"); } void mkpasswd_main(void) { int offset = 0; char salt[MAX_SALT_LEN] = {0,}; if (!(toys.optflags & FLAG_m)) TT.method = "des"; else if (!strcmp(TT.method, "help")) { xprintf("Available encryption methods are:\n" " des\n md5\n sha256\n sha512\n"); return; } // If arguments are there, then the second argument is Salt, can be NULL also if ((toys.optc == 2) && !(toys.optflags & FLAG_S)) TT.salt = toys.optargs[1]; offset= get_salt(salt, TT.method); if (offset == -1) error_exit("unknown encryption method"); if (TT.salt) { is_salt_valid(TT.salt); snprintf(salt + offset, MAX_SALT_LEN - offset, "%s", TT.salt); } if (toys.optflags & FLAG_P) { if (dup2(TT.pfd, STDIN_FILENO) == -1) perror_exit("fd"); close(TT.pfd); } if (!toys.optc) { if (isatty(STDIN_FILENO)) { if (read_password(toybuf, sizeof(toybuf), "Password: ")) perror_exit("password read failed"); } else { // read from the given FD int i = 0; while (1) { int ret = read(0, &toybuf[i], 1); if ( ret < 0 ) perror_exit("password read failed"); else if (ret == 0 || toybuf[i] == '\n' || toybuf[i] == '\r' || sizeof(toybuf) == i+1) { toybuf[i] = '\0'; break; } i++; } } } else snprintf(toybuf, sizeof(toybuf), "%s", toys.optargs[0]); // encrypt & print the password xprintf("%s\n",crypt(toybuf, salt)); }
_______________________________________________ Toybox mailing list [email protected] http://lists.landley.net/listinfo.cgi/toybox-landley.net
