From 0f51bfc50c0ddf5dd44976672d43d9ffa8680459 Mon Sep 17 00:00:00 2001 From: Rob Landley Date: Sun, 5 Dec 2021 05:15:43 -0600 Subject: [PATCH] Clean up password plumbing. --- lib/password.c | 174 ++++++++++++++++++---------------------------- lib/pending.h | 4 +- toys/lsb/passwd.c | 22 +++--- 3 files changed, 79 insertions(+), 121 deletions(-) diff --git a/lib/password.c b/lib/password.c index 3a39d9e6..3497176a 100644 --- a/lib/password.c +++ b/lib/password.c @@ -6,7 +6,6 @@ */ #include "toys.h" -#include // generate ID prefix and random salt for given encryption algorithm. int get_salt(char *salt, char *algo) @@ -27,7 +26,7 @@ int get_salt(char *salt, char *algo) xgetrandom(libbuf, ((len*6)+7)/8, 0); // Grab 6 bit chunks and convert to characters in ./0-9a-zA-Z - for (i=0; i> (bitpos&7)) & 0x3f; @@ -50,150 +49,109 @@ int get_salt(char *salt, char *algo) int read_password(char *buf, int buflen, char *mesg) { struct termios oldtermio; - struct sigaction sa, oldsa; + struct sigaction sa = {.sa_handler = generic_signal}, oldsa; int i, tty = tty_fd(), ret = 1; - // NOP signal handler to return from the read. Use sigaction() instead - // of xsignal() because we want to restore the old handler afterwards. - memset(&sa, 0, sizeof(sa)); - sa.sa_handler = generic_signal; + // Set NOP signal handler to return from the read. sigaction(SIGINT, &sa, &oldsa); - tcflush(tty, TCIFLUSH); xset_terminal(tty, 1, 0, &oldtermio); dprintf(tty, "%s", mesg); + // Loop assembling password. (Too long = fail) for (i = 0; ifcntl(fileno(ofp), F_SETLK, &lock)) { + perror_msg("%s", filename); goto free_storage; } - *sfx = '-'; + // Delete old backup, link new backup. (Failure here isn't fatal.) unlink(filenamesfx); - ret = link(filename, filenamesfx); - if (ret < 0) error_msg("can't create backup file"); - - *sfx = '+'; - lock.l_type = F_WRLCK; - lock.l_whence = SEEK_SET; - lock.l_start = 0; - lock.l_len = 0; - - ret = fcntl(fileno(exfp), F_SETLK, &lock); - if (ret < 0) perror_msg("Couldn't lock file %s",filename); - - lock.l_type = F_UNLCK; //unlocking at a later stage + if (0>link(filename, filenamesfx)) perror_msg("%s", filenamesfx); - newfp = fopen(filenamesfx, "w+"); - if (!newfp) { - error_msg("couldn't open file for writing"); - ret = -1; - fclose(exfp); + // Open new file to copy entries to + filenamesfx[strlen(filenamesfx)-1] = '+'; + if (!(nfp = fopen(filenamesfx, "w+"))) { + perror_msg("%s", filenamesfx); goto free_storage; } - ret = 0; - namesfx = xmprintf("%s:",username); - while ((n = getline(&line, &allocated_length, exfp)) > 0) { - line[n-1] = 0; - if (strncmp(line, namesfx, strlen(namesfx))) - fprintf(newfp, "%s\n", line); - else if (entry) { - char *current_ptr = NULL; - - 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") || - !strcmp(toys.which->name, "delgroup") || - !strcmp(toys.which->name, "groupdel")){ - current_ptr = get_nextcolon(line, 3); //past gid/admin list - *current_ptr = '\0'; - fprintf(newfp, "%s", line); - fprintf(newfp, "%s\n", entry); + // Loop through lines + while (getline(&line, (void *)&ll, ofp)) { + // find matching line + start = end = line; + if (strncmp(chomp(line), username, len) || line[len]!=':') { + found++; + if (!entry) continue; + + // Find start and end of span to replace + for (ii = pos;;) { + while (*end != ':') { + if (!*end) break; + end++; + } + if (ii) { + start = ++end; + ii--; + } else break; } + 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)); } free(line); - free(namesfx); - if (!found && entry) fprintf(newfp, "%s\n", entry); - fcntl(fileno(exfp), F_SETLK, &lock); - fclose(exfp); - - errno = 0; - fflush(newfp); - fsync(fileno(newfp)); - fclose(newfp); - rename(filenamesfx, filename); - if (errno) { - perror_msg("File Writing/Saving failed: "); + fflush(nfp); + fsync(fileno(nfp)); + fclose(nfp); // 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); - ret = -1; - } + } else ret = 1; free_storage: + if (ofp) fclose(ofp); free(filenamesfx); + return ret; } diff --git a/lib/pending.h b/lib/pending.h index c67d81c8..ccbd1024 100644 --- a/lib/pending.h +++ b/lib/pending.h @@ -2,5 +2,5 @@ // 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 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 8ff010e2..8c17dc6d 100644 --- a/toys/lsb/passwd.c +++ b/toys/lsb/passwd.c @@ -58,7 +58,6 @@ void passwd_main(void) struct passwd *pw = 0; struct spwd *sp; char *pass, *name, *encrypted = 0, salt[MAX_SALT_LEN]; - int ret = -1; // 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))) { @@ -72,19 +71,20 @@ void passwd_main(void) name = pw->pw_name; if (*(pass = pw->pw_passwd)=='x' && (sp = getspnam(name))) pass = sp->sp_pwdp; - if (toys.optflags & FLAG_l) { + if (FLAG(l)) { if (*pass=='!') error_exit("already locked"); printf("Locking '%s'\n", name); encrypted = xmprintf("!%s", pass); - } else if (toys.optflags & FLAG_u) { + } else if (FLAG(u)) { if (*pass!='!') error_exit("already unlocked"); printf("Unlocking '%s'\n", name); encrypted = pass+1; - } else if (toys.optflags & FLAG_d) { + } else if (FLAG(d)) { printf("Deleting password for '%s'\n", name); - encrypted = ""; + *(encrypted = toybuf) = 0; } else { - if (get_salt(salt, TT.a ? TT.a : "des")<0) error_exit("bad -a '%s'", TT.a); + if (!TT.a) TT.a = "des"; + if (get_salt(salt, TT.a)<0) error_exit("bad -a '%s'", TT.a); printf("Changing password for %s\n", name); if (myuid) { @@ -105,11 +105,11 @@ void passwd_main(void) } // Update the passwd - ret = update_password(*pw->pw_passwd=='x' ? "/etc/shadow" : "/etc/passwd", - name, encrypted); - - if (ret) error_msg("Failure"); + if (update_password(*pw->pw_passwd=='x' ? "/etc/shadow" : "/etc/passwd", + name, encrypted, 1)) error_msg("Failure"); else fprintf(stderr, "Success\n"); - if (CFG_TOYBOX_FREE && (toys.optflags & FLAG_l)) free(encrypted); + memset(toybuf, 0, sizeof(toybuf)); + memset(encrypted, 0, strlen(encrypted)); + free(encrypted); } -- 2.39.2