ubase

suckless linux base utils
git clone git://git.2f30.org/ubase
Log | Files | Refs | README | LICENSE

commit 1ec996439ab06930041afb534a230cd8dd3d95ee
parent d3709f91a2028ffdee6721c96b5d082f696bddb9
Author: sin <sin@2f30.org>
Date:   Thu,  5 Jun 2014 12:48:45 +0100

Add initial implementation of passwd(1)

No shadow support yet.

Diffstat:
MMakefile | 5++++-
MREADME | 6+++---
MTODO | 1-
Apasswd.c | 142+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Apasswd.h | 4++++
Atext.h | 11+++++++++++
Autil/agetline.c | 13+++++++++++++
Autil/passwd.c | 113+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
8 files changed, 290 insertions(+), 5 deletions(-)

diff --git a/Makefile b/Makefile @@ -3,15 +3,17 @@ include config.mk .POSIX: .SUFFIXES: .c .o -HDR = arg.h config.def.h proc.h reboot.h rtc.h util.h +HDR = arg.h config.def.h passwd.h proc.h reboot.h rtc.h text.h util.h LIB = \ util/agetcwd.o \ + util/agetline.o \ util/apathmax.o \ util/ealloc.o \ util/eprintf.o \ util/estrtol.o \ util/estrtoul.o \ util/explicit_bzero.o \ + util/passwd.o \ util/proc.o \ util/putword.o \ util/recurse.o \ @@ -43,6 +45,7 @@ SRC = \ mount.c \ mountpoint.c \ pagesize.c \ + passwd.c \ pidof.c \ pivot_root.c \ ps.c \ diff --git a/README b/README @@ -8,9 +8,9 @@ The following programs are currently implemented: chvt clear ctrlaltdel dd df dmesg eject fallocate free getty halt hwclock id insmod killall5 login lsmod lsusb mknod mkswap mount - mountpoint pagesize pidof pivot_root ps respawn rmmod stat su - swapoff swapon switch_root sysctl truncate umount unshare uptime - watch who + mountpoint pagesize passwd pidof pivot_root ps respawn rmmod stat + su swapoff swapon switch_root sysctl truncate umount unshare + uptime watch who The complement of ubase is sbase[1] which mostly follows POSIX and provides all the portable tools. Together they are intended to form a diff --git a/TODO b/TODO @@ -9,7 +9,6 @@ Tools to be implemented * losetup(8) * lspci * mkswap [-L] - * passwd * adduser * addgroup * rmuser diff --git a/passwd.c b/passwd.c @@ -0,0 +1,142 @@ +/* See LICENSE file for copyright and license details. */ +#include <errno.h> +#include <fcntl.h> +#include <pwd.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/ioctl.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <unistd.h> +#include "passwd.h" +#include "util.h" + +static void +usage(void) +{ + eprintf("usage: %s login\n", argv0); +} + +int +main(int argc, char *argv[]) +{ + char *pass, *cryptpass1, *cryptpass2, *cryptpass3; + char *p; + char template[] = "/tmp/pw.XXXXXX"; + struct passwd *pw; + int ffd, tfd; + int r; + + ARGBEGIN { + default: + usage(); + } ARGEND; + + if (argc != 1) + usage(); + + errno = 0; + pw = getpwnam(argv[0]); + if (errno) + eprintf("getpwnam: %s:", argv[0]); + else if (!pw) + eprintf("who are you?\n"); + + switch (pw->pw_passwd[0]) { + case '!': + case '*': + eprintf("denied\n"); + } + + if (pw->pw_passwd[0] == '\0') + goto newpass; + + if (pw->pw_passwd[0] == 'x' && pw->pw_passwd[1] == '\0') + eprintf("no shadow support\n"); + + /* Flush pending input */ + ioctl(STDIN_FILENO, TCFLSH, (void *)0); + + pass = getpass("Current password: "); + putchar('\n'); + if (!pass) + eprintf("getpass:"); + p = crypt(pass, pw->pw_passwd); + if (!p) + eprintf("crypt:"); + cryptpass1 = estrdup(p); + if (strcmp(cryptpass1, pw->pw_passwd) != 0) + eprintf("incorrect password\n"); + +newpass: + /* Flush pending input */ + ioctl(STDIN_FILENO, TCFLSH, (void *)0); + + pass = getpass("Enter new password: "); + putchar('\n'); + if (!pass) + eprintf("getpass:"); + p = crypt(pass, pw->pw_passwd); + if (!p) + eprintf("crypt:"); + cryptpass2 = estrdup(p); + if (strcmp(cryptpass1, cryptpass2) == 0) + eprintf("password left unchanged\n"); + + /* Flush pending input */ + ioctl(STDIN_FILENO, TCFLSH, (void *)0); + + pass = getpass("Retype new password: "); + putchar('\n'); + if (!pass) + eprintf("getpass:"); + p = crypt(pass, pw->pw_passwd); + if (!p) + eprintf("crypt:"); + cryptpass3 = estrdup(p); + if (strcmp(cryptpass2, cryptpass3) != 0) + eprintf("passwords don't match\n"); + + pw->pw_passwd = cryptpass3; + + ffd = open("/etc/passwd", O_RDWR); + if (ffd < 0) + eprintf("open %s:", "/etc/passwd"); + + tfd = mkostemp(template, O_RDWR); + if (tfd < 0) + eprintf("mkstemp:"); + + r = pw_copy(ffd, tfd, pw); + if (r < 0) { + unlink(template); + exit(EXIT_FAILURE); + } + + r = lseek(ffd, 0, SEEK_SET); + if (r < 0) { + unlink(template); + exit(EXIT_FAILURE); + } + r = lseek(tfd, 0, SEEK_SET); + if (r < 0) { + unlink(template); + exit(EXIT_FAILURE); + } + + r = pw_copy(tfd, ffd, NULL); + if (r < 0) { + unlink(template); + exit(EXIT_FAILURE); + } + + close(tfd); + close(ffd); + unlink(template); + free(cryptpass3); + free(cryptpass2); + free(cryptpass1); + + return EXIT_SUCCESS; +} diff --git a/passwd.h b/passwd.h @@ -0,0 +1,4 @@ +/* See LICENSE file for copyright and license details. */ +/* passwd.c */ +int pw_scan(char *, struct passwd *); +int pw_copy(int, int, const struct passwd *); diff --git a/text.h b/text.h @@ -0,0 +1,11 @@ +/* See LICENSE file for copyright and license details. */ + +struct linebuf { + char **lines; + long nlines; + long capacity; +}; +#define EMPTY_LINEBUF {NULL, 0, 0,} +void getlines(FILE *, struct linebuf *); + +ssize_t agetline(char **, size_t *, FILE *); diff --git a/util/agetline.c b/util/agetline.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "../text.h" +#include "../util.h" + +ssize_t +agetline(char **p, size_t *size, FILE *fp) +{ + return getline(p, size, fp); +} diff --git a/util/passwd.c b/util/passwd.c @@ -0,0 +1,113 @@ +/* See LICENSE file for copyright and license details. */ +#include <pwd.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "../text.h" +#include "../util.h" + +int +pw_scan(char *bp, struct passwd *pw) +{ + char *p; + + memset(pw, 0, sizeof(*pw)); + + /* login name */ + p = strsep(&bp, ":"); + if (!p || *p == '\0') + goto corrupt; + pw->pw_name = p; + + /* passwd */ + p = strsep(&bp, ":"); + if (!p) + goto corrupt; + pw->pw_passwd = p; + + /* uid */ + p = strsep(&bp, ":"); + if (!p) + goto corrupt; + pw->pw_uid = estrtol(p, 10); + + /* gid */ + p = strsep(&bp, ":"); + if (!p) + goto corrupt; + pw->pw_gid = estrtol(p, 10); + + /* user name or comment */ + p = strsep(&bp, ":"); + if (!p) + goto corrupt; + pw->pw_gecos = p; + + /* home directory */ + p = strsep(&bp, ":"); + if (!p) + goto corrupt; + pw->pw_dir = p; + + /* optional shell */ + p = strsep(&bp, ":"); + if (!p) + goto corrupt; + pw->pw_shell = p; + + /* look for redundant entries */ + p = strsep(&bp, ":"); + if (p) + goto corrupt; + + return 0; +corrupt: + weprintf("corrupted passwd entry\n"); + return -1; +} + +int +pw_copy(int ffd, int tfd, const struct passwd *newpw) +{ + struct passwd pw; + char *buf = NULL, *p; + size_t size = 0; + FILE *from, *to; + + from = fdopen(ffd, "r"); + if (!from) { + weprintf("fdopen:"); + return -1; + } + to = fdopen(tfd, "w"); + if (!to) { + weprintf("fdopen:"); + return -1; + } + while (agetline(&buf, &size, from) != -1) { + p = strdup(buf); + if (!p) { + weprintf("strdup:"); + return -1; + } + if (newpw) { + if (pw_scan(p, &pw) < 0) + return -1; + if (strcmp(pw.pw_name, newpw->pw_name) == 0) { + fprintf(to, "%s:%s:%u:%u:%s:%s:%s\n", + newpw->pw_name, + newpw->pw_passwd, + newpw->pw_uid, + newpw->pw_gid, + newpw->pw_gecos, + newpw->pw_dir, + newpw->pw_shell); + continue; + } + } + fprintf(to, "%s", buf); + free(p); + } + fflush(to); + return 0; +}