From 6c30b3534205719650bce51a498492b7748228d1 Mon Sep 17 00:00:00 2001 From: Rob Landley Date: Sat, 26 Aug 2023 12:58:47 -0500 Subject: [PATCH] Redo lib/password.c to remove shadow.h. Implement internal common plumbing to modify colon separated files. Doesn't handle "pam" but the design of pam is incompatible with static linking. --- lib/lib.h | 7 +- lib/password.c | 149 ++++++++++++++++++++++------------------ lib/pending.h | 6 -- toys/lsb/passwd.c | 14 ++-- toys/other/mkpasswd.c | 23 ++++--- toys/pending/chsh.c | 32 ++++----- toys/pending/groupadd.c | 110 ++++++++++++++--------------- toys/pending/groupdel.c | 6 +- toys/pending/useradd.c | 5 +- toys/pending/userdel.c | 4 +- 10 files changed, 174 insertions(+), 182 deletions(-) delete mode 100644 lib/pending.h diff --git a/lib/lib.h b/lib/lib.h index 6165ac112..bae750c25 100644 --- a/lib/lib.h +++ b/lib/lib.h @@ -356,7 +356,9 @@ char *escape_url(char *str, char *and); char *unescape_url(char *str, int do_cut); // password.c -int get_salt(char *salt, char * algo); +int get_salt(char *salt, char *algo, int rand); +int read_password(char *buff, int buflen, char *mesg); +int update_password(char *filename, char *username, char *entry, int pos); // commas.c void comma_args(struct arg_list *al, void *data, char *err, @@ -423,6 +425,3 @@ pid_t __attribute__((returns_twice)) xvforkwrap(pid_t pid); #define minof(a, b) ({typeof(a) aa = (a); typeof(b) bb = (b); aabb ? aa : bb;}) - -// Functions in need of further review/cleanup -#include "lib/pending.h" diff --git a/lib/password.c b/lib/password.c index 6bea3d70e..c1891aab5 100644 --- a/lib/password.c +++ b/lib/password.c @@ -1,45 +1,48 @@ /* password.c - password read/update helper functions. * * Copyright 2012 Ashwini Kumar - * - * TODO: cleanup */ #include "toys.h" +// generate $id$salt$hash given a password and algorithm. Generates salt if NULL +//char *toy_crypt(char *pass, char *salt, char *algo) // generate ID prefix and random salt for given encryption algorithm. -int get_salt(char *salt, char *algo) +int get_salt(char *salt, char *algo, int rand) { struct { char *type, id, len; } al[] = {{"des", 0, 2}, {"md5", 1, 8}, {"sha256", 5, 16}, {"sha512", 6, 16}}; - int i; + char *s; + int i, len; for (i = 0; i < ARRAY_LEN(al); i++) { - if (!strcmp(algo, al[i].type)) { - int len = al[i].len; - char *s = salt; - - if (al[i].id) s += sprintf(s, "$%c$", '0'+al[i].id); + for (s = al[i].type, len = 0; algo[len]; len++) { + while (ispunct(algo[len])) len++; + if (tolower(algo[len]) != tolower(*s++)) break; + } + if (algo[len]) continue; - // Read appropriate number of random bytes for salt - xgetrandom(libbuf, ((len*6)+7)/8); + len = al[i].len; + s = salt + (al[i].id ? sprintf(salt, "$%c$", '0'+al[i].id) : 0); - // Grab 6 bit chunks and convert to characters in ./0-9a-zA-Z - for (i = 0; i> (bitpos&7)) & 0x3f; - bits += 46; - if (bits > 57) bits += 7; - if (bits > 90) bits += 6; + // Grab 6 bit chunks and convert to characters in ./0-9a-zA-Z + for (i = 0; i> (bitpos&7)) & 0x3f; + bits += 46; + if (bits > 57) bits += 7; + if (bits > 90) bits += 6; - return s-salt; + s[i] = bits; } + s[len] = 0; + + return s-salt; } return -1; @@ -79,79 +82,91 @@ int read_password(char *buf, int buflen, char *mesg) return ret; } -/* update colon-separated text files ala /etc/{passwd,shadow,group,gshadow} - * username = string match for first entry in line - * entry = new entry (NULL deletes matching line from file) - * pos = which entry to replace with "entry" (0 is first) - */ -// filename+ = new copy being written, filename- = backup of old version +// update colon-separated text files ala /etc/{passwd,shadow,group,gshadow} // returns 1 for success, 0 for failure + +// username = string match for first entry in line +// entry = new entry (NULL deletes matching line, contains : adds/replaces line) +// pos = if no : in "entry", which field to replace (0 is first) +// filename+ = new copy being written, filename- = backup of old version + int update_password(char *filename, char *username, char *entry, int pos) { - char *filenamesfx = xmprintf("%s-", filename), *line = 0, *start, *end; - FILE *ofp, *nfp; - int ret = 0, found = 0, len = strlen(username)*!strchr(username, ':'), ii; + char *ff = xmprintf("%s-", filename), *line = 0, *start, *end, *out, *oo; + FILE *ofp; + int len = strlen(username)*!strchr(username,':'), rc = 0, ret = 0, found = 0, + nfd; struct flock lock = {.l_type = F_WRLCK}; + struct stat st; long long ll = 0; - // Open old filename ("r" won't let us lock), get blocking lock - if (!(ofp = fopen(filename, "w+")) || 0>fcntl(fileno(ofp), F_SETLK, &lock)) { - perror_msg("%s", filename); + // Open old filename ("r" won't let us lock) and get blocking lock + if (!(ofp = fopen(filename, "w+")) || 0>fcntl(fileno(ofp), F_SETLK, &lock)\ + || fstat(fileno(ofp), &st)) + { + perror_msg_raw(filename); goto free_storage; } // Delete old backup, link new backup. (Failure here isn't fatal.) - unlink(filenamesfx); - if (0>link(filename, filenamesfx)) perror_msg("%s", filenamesfx); + unlink(ff); + if (0>link(filename, ff)) perror_msg_raw(ff); // Open new file to copy entries to - filenamesfx[strlen(filenamesfx)-1] = '+'; - if (!(nfp = fopen(filenamesfx, "w+"))) { - perror_msg("%s", filenamesfx); + ff[strlen(ff)-1] = '+'; + if (-1 == (nfd = xcreate(ff, O_CREAT|O_EXCL|O_WRONLY, st.st_mode))) { + perror_msg_raw(ff); goto free_storage; } // Loop through lines - while (getline(&line, (void *)&ll, ofp)) { + for (; getline(&line, (void *)&ll, ofp)!=-1; memset(line, 0, strlen(line))) { // find matching line - start = end = line; - if (strncmp(chomp(line), username, len) || line[len]!=':') { + oo = 0; + start = end = chomp(line); + if (strncmp(line, username, len) || !(line[len] && line[len]!=':')) + out = line; + else { found++; - if (!entry) continue; - // Find start and end of span to replace - for (ii = pos;;) { - while (*end != ':') { - if (!*end) break; - end++; + // Delete or replace whole line? + if (!entry) out = 0; + else if (strchr(entry, ':')) out = entry; + + // Replace entry at pos + else { + for (;; pos--, start = ++end) { + while (*end && *end != ':') end++; + if (!pos || !*end) break; } - if (ii) { - start = ++end; - ii--; - } else break; + if (pos>=0) out = line; + else oo = out = xmprintf("%*s%s%s\n", (int)(start-line),line,entry,end); } - if (ii) start = end = line; } - - // Write with replacement (if any) - fprintf(nfp, "%*s%s%s\n", (int)(start-line), line, - (start==line) ? "" : entry, end); - memset(line, 0, strlen(line)); + if (out) { + rc = dprintf(nfd, "%s\n", out); + free(out); + if (rc<0) { + perror_msg_raw(ff); + goto free_storage; + } + free(oo); + } } free(line); - fflush(nfp); - fsync(fileno(nfp)); - fclose(nfp); // automatically unlocks + if (!found && entry && strchr(entry, ':')) dprintf(nfd, "%s\n", entry); + fsync(nfd); + close(nfd); // automatically unlocks - if (!found || rename(filenamesfx, filename)) { - if (found) perror_msg("%s -> %s", filenamesfx, filename); - else if (entry) fprintf(nfp, "%s\n", entry); - unlink(filenamesfx); - } else ret = 1; + if (!found || rename(ff, filename)) { + if (found) perror_msg("%s -> %s", ff, filename); + else if (entry) error_msg("No %s in %s", username, filename); + } else ret = 1, *ff = 0; free_storage: if (ofp) fclose(ofp); - free(filenamesfx); + if (ff && *ff) unlink(ff); + free(ff); return ret; } diff --git a/lib/pending.h b/lib/pending.h deleted file mode 100644 index ccbd1024e..000000000 --- a/lib/pending.h +++ /dev/null @@ -1,6 +0,0 @@ -// pending.h - header for pending.c - -// password.c -#define MAX_SALT_LEN 20 //3 for id, 16 for key, 1 for '\0' -int read_password(char *buff, int buflen, char *mesg); -int update_password(char *filename, char *username, char *encrypted, int pos); diff --git a/toys/lsb/passwd.c b/toys/lsb/passwd.c index da8e1e970..869214094 100644 --- a/toys/lsb/passwd.c +++ b/toys/lsb/passwd.c @@ -1,4 +1,4 @@ -/* passwd.c - Program to update user password. +/* passwd.c - update user password. * * Copyright 2012 Ashwini Kumar * Modified 2012 Jason Kyungwan Han @@ -13,9 +13,9 @@ config PASSWD help usage: passwd [-a ALGO] [-dlu] [USER] - Update user's authentication tokens. Defaults to current user. + Update user's login password. Defaults to current user. - -a ALGO Encryption method (des, md5, sha256, sha512) default: des + -a ALGO Encryption method (des, md5, sha256, sha512) default: md5 -d Set password to '' -l Lock (disable) account -u Unlock (enable) account @@ -53,17 +53,17 @@ static void weak_check(char *new, char *old, char *user) void passwd_main(void) { - uid_t myuid; + uid_t myuid = getuid(); struct passwd *pw = 0; struct spwd *sp; char *pass, *name, *encrypted = 0, salt[32]; // If we're root or not -lud, load specified user. Exit if not allowed. - if (!(myuid = getuid()) || !(toys.optflags&(FLAG_l|FLAG_u|FLAG_d))) { + if (!myuid || !(toys.optflags&(FLAG_l|FLAG_u|FLAG_d))) { if (*toys.optargs) pw = xgetpwnam(*toys.optargs); else pw = xgetpwuid(myuid); } - if (!pw || (myuid && (myuid != pw->pw_uid))) error_exit("Not root"); + if (!pw || (myuid && myuid != pw->pw_uid)) error_exit("Not root"); // Get password from /etc/passwd or /etc/shadow // TODO: why still support non-shadow passwords...? @@ -83,7 +83,7 @@ void passwd_main(void) *(encrypted = toybuf) = 0; } else { if (!TT.a) TT.a = "des"; - if (get_salt(salt, TT.a)<0) error_exit("bad -a '%s'", TT.a); + if (get_salt(salt, TT.a, 1)<0) error_exit("bad -a '%s'", TT.a); printf("Changing password for %s\n", name); if (myuid) { diff --git a/toys/other/mkpasswd.c b/toys/other/mkpasswd.c index 6ff578ff0..b27e8d0dc 100644 --- a/toys/other/mkpasswd.c +++ b/toys/other/mkpasswd.c @@ -14,11 +14,10 @@ config MKPASSWD help usage: mkpasswd [-P FD] [-m TYPE] [-S SALT] [PASSWORD] [SALT] - Crypt PASSWORD using crypt(3) + Encrypt PASSWORD using crypt(3), with either random or provided SALT. -P FD Read password from file descriptor FD -m TYPE Encryption method (des, md5, sha256, or sha512; default is des) - -S SALT */ #define FOR_mkpasswd @@ -31,24 +30,26 @@ GLOBALS( void mkpasswd_main(void) { - char salt[MAX_SALT_LEN] = {0,}; + char salt[32] = {0,}; int i; - if (!TT.m) TT.m = "des"; if (toys.optc == 2) { if (TT.S) error_exit("duplicate salt"); TT.S = toys.optargs[1]; } - if (-1 == (i = get_salt(salt, TT.m))) error_exit("bad -m"); + if (-1 == (i = get_salt(salt, TT.m ? : "des", !TT.S))) error_exit("bad -m"); if (TT.S) { - char *s = TT.S; + char *mirv = strrchr(salt, '$'), *s = TT.S; - // In C locale, isalnum() means [A-Za-Z0-0] - while (isalnum(*s) || *s == '.' || *s == '/') s++; - if (*s) error_exit("salt not in [./A-Za-z0-9]"); + if (mirv) mirv++; + else mirv = salt; - snprintf(salt+i, sizeof(salt)-i, "%s", TT.S); + // In C locale, isalnum() means [a-zA-Z0-9] + while (isalnum(*s) || *s == '.' || *s == '/') s++; + if (*s || s-TT.S!=strlen(mirv)) + error_exit("bad SALT (need [a-zA-Z0-9] len %d)", (int)strlen(mirv)); + strcpy(mirv, TT.S); } // Because read_password() doesn't have an fd argument @@ -73,5 +74,5 @@ void mkpasswd_main(void) } // encrypt & print the password - xprintf("%s\n",crypt(*toys.optargs ? *toys.optargs : toybuf, salt)); + xprintf("%s\n", crypt(*toys.optargs ? *toys.optargs : toybuf, salt)); } diff --git a/toys/pending/chsh.c b/toys/pending/chsh.c index 8d3390ee2..6dd28e819 100644 --- a/toys/pending/chsh.c +++ b/toys/pending/chsh.c @@ -4,17 +4,18 @@ * * See http://refspecs.linuxfoundation.org/LSB_4.1.0/LSB-Core-generic/LSB-Core-generic/chsh.html -USE_CHSH(NEWTOY(chsh, "s:", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_STAYROOT)) +USE_CHSH(NEWTOY(chsh, ">1R:s:a", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_STAYROOT)) config CHSH bool "chsh" default n help - usage: chsh [-s SHELL] [USER] + usage: chsh [-s SHELL] [-R CHROOT_DIR] [USER] Change user's login shell. -s Use SHELL instead of prompting + -R Act on CHROOT_DIR instead of host Non-root users can only change their own shell to one listed in /etc/shells. */ @@ -23,7 +24,7 @@ config CHSH #include "toys.h" GLOBALS( - char *s; + char *s, *R; ) void chsh_main() @@ -36,18 +37,14 @@ void chsh_main() // Get uid user information, may be discarded later if ((user = *toys.optargs)) { - passwd_info = xgetpwnam(user); - if (geteuid() && strcmp(passwd_info->pw_name, user)) - error_exit("Permission denied\n"); - } else { - passwd_info = xgetpwuid(getuid()); - user = passwd_info->pw_name; - } + if (strcmp((passwd_info = xgetpwnam(user))->pw_name, user)) + if (geteuid()) errno = EPERM, error_exit(0); + } else user = (passwd_info = xgetpwuid(getuid()))->pw_name; // Get a password, encrypt it, wipe it, and check it if (mlock(toybuf, sizeof(toybuf))) perror_exit("mlock"); if (!(shadow_info = getspnam(passwd_info->pw_name))) perror_exit("getspnam"); - if (read_password(toybuf, sizeof(toybuf), "Password: ")) perror_exit("woaj"); //xexit(); + if (read_password(toybuf, sizeof(toybuf), "Password: ")) *toybuf = 0; if (!(encrypted = crypt(toybuf, shadow_info->sp_pwdp))) perror_exit("crypt"); memset(toybuf, 0, sizeof(toybuf)); munlock(toybuf, sizeof(toybuf)); // prevents memset from "optimizing" away. @@ -57,21 +54,16 @@ void chsh_main() file = xfopen("/etc/shells", "r"); if (toys.optflags) shell = TT.s; else { - xprintf("Changing the login shell for %s\n" - "Enter the new value, or press ENTER for default\n" - " Login shell [%s]: ", user, passwd_info->pw_shell); + xprintf("Login shell for %s [%s]:", user, passwd_info->pw_shell); if (!(shell = xgetline(stdin))) xexit(); + if (!*shell) xexit(); } // Verify supplied shell in /etc/shells, or get default shell - if (strlen(shell)) - while ((line = xgetline(file)) && strcmp(shell, line)) free(line); + if (*shell) while ((line = xgetline(file)) && strcmp(shell, line)) free(line); else do line = xgetline(file); while (line && *line != '/'); if (!line) error_exit("Shell not found in '/etc/shells'"); // Update /etc/passwd - passwd_info->pw_shell = line; - if (-1 == update_password("/etc/passwd", user, NULL)) perror_exit("Failed to remove passwd entry"); - file = xfopen("/etc/passwd", "a"); - if (putpwent(passwd_info, file)) perror_exit("putwent"); + if (!update_password("/etc/passwd", user, line,6)) perror_exit("/etc/passwd"); } diff --git a/toys/pending/groupadd.c b/toys/pending/groupadd.c index 642b4a083..efb3f941a 100644 --- a/toys/pending/groupadd.c +++ b/toys/pending/groupadd.c @@ -5,7 +5,7 @@ * * 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(NEWTOY(groupadd, "<1>2R:g#<0>2147483647S", TOYFLAG_NEEDROOT|TOYFLAG_SBIN)) USE_GROUPADD(OLDTOY(addgroup, groupadd, TOYFLAG_NEEDROOT|TOYFLAG_SBIN)) config GROUPADD @@ -14,20 +14,19 @@ config GROUPADD help usage: groupadd [-S] [-g GID] [USER] GROUP - Add a group or add a user to a group + Add a user to a group, or create a new group. - -g GID Group id - -S Create a system group + -g GID Group id + -R Operate within chroot + -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; + long g; + char *R; ) /* Add a new group to the system, if GID is given then that is validated @@ -35,67 +34,58 @@ GLOBALS( * 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; - - if (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 (FLAG(S)) TT.gid = CFG_TOYBOX_UID_SYS; - else TT.gid = CFG_TOYBOX_UID_USR; - //find unused gid - while (getgrgid(TT.gid)) TT.gid++; - } - - entry = xmprintf("%s:%s:%ld:", *toys.optargs, "x", TT.gid); - update_password(GROUP_PATH, *toys.optargs, entry); - free(entry); - entry = xmprintf("%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; + struct group *grp = 0; + char *entry = 0, *s, *gfile = "/etc/group", *gsfile = "/etc/gshadow"; + int i, len; - if (toys.optflags && toys.optc == 2) - help_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 - xgetpwnam(*toys.optargs); - if (!(grp = getgrnam(toys.optargs[1]))) - error_exit("group '%s' does not exist", toys.optargs[1]); - if (!grp->gr_mem) entry = xmprintf("%s", *toys.optargs); - else { - int i; + if (TT.R) { + gfile = xmprintf("%s%s", TT.R, gfile); + gsfile = xmprintf("%s%s", TT.R, gsfile); + } - for (i = 0; grp->gr_mem[i]; i++) - if (!strcmp(grp->gr_mem[i], *toys.optargs)) return; + // Add user to group? + if (toys.optc == 2) { + if (FLAG(g)|FLAG(S)) help_exit("No -gS with USER+GROUP"); + if (!(grp = getgrnam(s = toys.optargs[1]))) error_exit("no group '%s'", s); + len = strlen(s)+1; + xgetpwnam(s = *toys.optargs); - 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, ","); + // Is this user already in this group? + for (i = 0; grp->gr_mem[i]; i++) { + if (!strcmp(grp->gr_mem[i], s)) return; + len += strlen(grp->gr_mem[i])+1; + } + s = entry = xmalloc(len); + for (i = 0;; i++) { + if (i) *s++ = ','; + if (!grp->gr_mem[i]) { + strcpy(s, toys.optargs[1]); + break; } - entry = xrealloc(entry, strlen(entry) + strlen(*toys.optargs) + 1); - strcat(entry, *toys.optargs); + s = stpcpy(s, grp->gr_mem[i]); } - update_password(GROUP_PATH, grp->gr_name, entry); - update_password(SECURE_GROUP_PATH, grp->gr_name, entry); + update_password(gfile, grp->gr_name, entry, 3); + update_password(gsfile, grp->gr_name, entry, 3); free(entry); - } else { //new group to be created - char *s = *toys.optargs; - /* investigate the group to be created */ - if (getgrnam(s)) error_exit("'%s' in use", s); - if (s[strcspn(s, ":/\n")] || strlen(s) > LOGIN_NAME_MAX) - error_exit("bad name"); - new_group(); + return; } + + // create new group + if (getgrnam(s = *toys.optargs)) error_exit("'%s' in use", s); + if (s[strcspn(s, ":/\n")] || strlen(s)>256) error_exit("bad '%s'", s); + + // Find next unused GID or confirm selected GID isn't in use + if (!FLAG(g)) { + TT.g = FLAG(S) ? CFG_TOYBOX_UID_SYS : CFG_TOYBOX_UID_USR; + while (getgrgid(TT.g)) TT.g++; + } else if (getgrgid(TT.g)) error_exit("group '%ld' in use", TT.g); + + sprintf(toybuf, "%s:x:%ld:", s, TT.g); + update_password(gfile, s, toybuf, 0); + sprintf(toybuf, "%s:!::", s); + update_password(gsfile, s, toybuf, 0); } diff --git a/toys/pending/groupdel.c b/toys/pending/groupdel.c index 483ac59ca..4c3eae5f2 100644 --- a/toys/pending/groupdel.c +++ b/toys/pending/groupdel.c @@ -5,7 +5,7 @@ * * See http://refspecs.linuxfoundation.org/LSB_4.1.0/LSB-Core-generic/LSB-Core-generic/groupdel.html -USE_GROUPDEL(NEWTOY(groupdel, "<1>2", TOYFLAG_NEEDROOT|TOYFLAG_SBIN)) +USE_GROUPDEL(NEWTOY(groupdel, "<1>2?", TOYFLAG_NEEDROOT|TOYFLAG_SBIN)) USE_GROUPDEL(OLDTOY(delgroup, groupdel, TOYFLAG_NEEDROOT|TOYFLAG_SBIN)) config GROUPDEL @@ -55,7 +55,7 @@ void groupdel_main(void) if (CFG_TOYBOX_FREE) endpwent(); } - update_password("/etc/group", grp->gr_name, entry); - update_password("/etc/gshadow", grp->gr_name, entry); + update_password("/etc/group", grp->gr_name, entry, 3); + update_password("/etc/gshadow", grp->gr_name, entry, 3); if (CFG_TOYBOX_FREE) free(entry); } diff --git a/toys/pending/useradd.c b/toys/pending/useradd.c index d0ad03ab9..c421498ec 100644 --- a/toys/pending/useradd.c +++ b/toys/pending/useradd.c @@ -39,6 +39,7 @@ GLOBALS( long gid; ) +// TODO user exists error void useradd_main(void) { char *s = *toys.optargs, *entry; @@ -119,7 +120,7 @@ void useradd_main(void) entry = xmprintf("%s:%s:%ld:%ld:%s:%s:%s", pwd.pw_name, pwd.pw_passwd, (long)pwd.pw_uid, (long)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"); + update_password("/etc/passwd", pwd.pw_name, entry, 0); free(entry); if (toys.optflags & FLAG_S) @@ -127,7 +128,7 @@ void useradd_main(void) (unsigned)(time(NULL))/(24*60*60)); //passwd is not set initially else entry = xmprintf("%s:!!:%u:0:99999:7:::", pwd.pw_name, (unsigned)(time(0))/(24*60*60)); //passwd is not set initially - update_password("/etc/shadow", pwd.pw_name, entry); + update_password("/etc/shadow", pwd.pw_name, entry, 0); free(entry); // create home dir & copy skel dir to home diff --git a/toys/pending/userdel.c b/toys/pending/userdel.c index 51ee67c95..69c520aa5 100644 --- a/toys/pending/userdel.c +++ b/toys/pending/userdel.c @@ -92,8 +92,8 @@ void userdel_main(void) { struct passwd *pwd = xgetpwnam(*toys.optargs); - update_password("/etc/passwd", pwd->pw_name, NULL); - update_password("/etc/shadow", pwd->pw_name, NULL); + update_password("/etc/passwd", pwd->pw_name, 0, 0); + update_password("/etc/shadow", pwd->pw_name, 0, 0); // delete the group named USER, and remove user from group. // could update_password() be used for this?