Add initial implementation of passwd(1)

No shadow support yet.
This commit is contained in:
sin 2014-06-05 12:48:45 +01:00
parent d3709f91a2
commit 1ec996439a
8 changed files with 290 additions and 5 deletions

View File

@ -3,15 +3,17 @@ include config.mk
.POSIX: .POSIX:
.SUFFIXES: .c .o .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 = \ LIB = \
util/agetcwd.o \ util/agetcwd.o \
util/agetline.o \
util/apathmax.o \ util/apathmax.o \
util/ealloc.o \ util/ealloc.o \
util/eprintf.o \ util/eprintf.o \
util/estrtol.o \ util/estrtol.o \
util/estrtoul.o \ util/estrtoul.o \
util/explicit_bzero.o \ util/explicit_bzero.o \
util/passwd.o \
util/proc.o \ util/proc.o \
util/putword.o \ util/putword.o \
util/recurse.o \ util/recurse.o \
@ -43,6 +45,7 @@ SRC = \
mount.c \ mount.c \
mountpoint.c \ mountpoint.c \
pagesize.c \ pagesize.c \
passwd.c \
pidof.c \ pidof.c \
pivot_root.c \ pivot_root.c \
ps.c \ ps.c \

6
README
View File

@ -8,9 +8,9 @@ The following programs are currently implemented:
chvt clear ctrlaltdel dd df dmesg eject fallocate free getty halt chvt clear ctrlaltdel dd df dmesg eject fallocate free getty halt
hwclock id insmod killall5 login lsmod lsusb mknod mkswap mount hwclock id insmod killall5 login lsmod lsusb mknod mkswap mount
mountpoint pagesize pidof pivot_root ps respawn rmmod stat su mountpoint pagesize passwd pidof pivot_root ps respawn rmmod stat
swapoff swapon switch_root sysctl truncate umount unshare uptime su swapoff swapon switch_root sysctl truncate umount unshare
watch who uptime watch who
The complement of ubase is sbase[1] which mostly follows POSIX and The complement of ubase is sbase[1] which mostly follows POSIX and
provides all the portable tools. Together they are intended to form a provides all the portable tools. Together they are intended to form a

1
TODO
View File

@ -9,7 +9,6 @@ Tools to be implemented
* losetup(8) * losetup(8)
* lspci * lspci
* mkswap [-L] * mkswap [-L]
* passwd
* adduser * adduser
* addgroup * addgroup
* rmuser * rmuser

142
passwd.c Normal file
View File

@ -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;
}

4
passwd.h Normal file
View File

@ -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 *);

11
text.h Normal file
View File

@ -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 *);

13
util/agetline.c Normal file
View File

@ -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);
}

113
util/passwd.c Normal file
View File

@ -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;
}