diff options
author | Rob Landley <rob@landley.net> | 2013-10-16 20:41:56 -0500 |
---|---|---|
committer | Rob Landley <rob@landley.net> | 2013-10-16 20:41:56 -0500 |
commit | 18ec03543c3731e1ea25182ef72c49ac5ec2d1c7 (patch) | |
tree | 7b9b35338a9f42e713833aec0a568c4713b6fcc9 /toys/pending | |
parent | 3403742655702257d5c4972ab6ec23eb95c3fede (diff) | |
download | toybox-18ec03543c3731e1ea25182ef72c49ac5ec2d1c7.tar.gz |
useradd, groupadd, and mkpasswd submitted by Ashwini Sharma.
Diffstat (limited to 'toys/pending')
-rw-r--r-- | toys/pending/groupadd.c | 113 | ||||
-rw-r--r-- | toys/pending/mkpasswd.c | 103 | ||||
-rw-r--r-- | toys/pending/useradd.c | 246 |
3 files changed, 462 insertions, 0 deletions
diff --git a/toys/pending/groupadd.c b/toys/pending/groupadd.c new file mode 100644 index 00000000..ab290e54 --- /dev/null +++ b/toys/pending/groupadd.c @@ -0,0 +1,113 @@ +/* groupadd.c - create a new group + * + * Copyright 2013 Ashwini Kumar <ak.ashwini@gmail.com> + * Copyright 2013 Kyungwan Han <asura321@gmail.com> + * + * 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 n + 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(); + } +} diff --git a/toys/pending/mkpasswd.c b/toys/pending/mkpasswd.c new file mode 100644 index 00000000..87b239e0 --- /dev/null +++ b/toys/pending/mkpasswd.c @@ -0,0 +1,103 @@ +/* mkpasswd.c - encrypt the given passwd using salt + * + * Copyright 2013 Ashwini Kumar <ak.ashwini@gmail.com> + * Copyright 2013 Kyungwan Han <asura321@gmail.com> + * + * No Standard + +USE_MKPASSWD(NEWTOY(mkpasswd, ">2S:m:P#=0<0", TOYFLAG_USR|TOYFLAG_BIN)) + +config MKPASSWD + bool "mkpasswd" + default n + 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)); +} diff --git a/toys/pending/useradd.c b/toys/pending/useradd.c new file mode 100644 index 00000000..ecfd638f --- /dev/null +++ b/toys/pending/useradd.c @@ -0,0 +1,246 @@ +/* useradd.c - add a new user + * + * Copyright 2013 Ashwini Kumar <ak.ashwini@gmail.com> + * Copyright 2013 Kyungwan Han <asura321@gmail.com> + * + * 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 n + 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(); + } +} |