commit 8fdc7d70bd76b43ed760a4ab7e113a9720da9ca1
parent 10a539e7445ed00f3c6914bf17e3c9d84906c031
Author: Hiltjo Posthuma <hiltjo@codemadness.org>
Date: Sun, 13 Jul 2014 19:55:46 +0000
passwd: fix /etc/passwd support, ...
... rewrite parts to use libc functions (supported by musl and glibc).
Diffstat:
M | passwd.c | | | 235 | ++++++++++++++++++++++++++++++++++++++++++++----------------------------------- |
M | passwd.h | | | 4 | +--- |
M | util/passwd.c | | | 109 | +------------------------------------------------------------------------------ |
3 files changed, 133 insertions(+), 215 deletions(-)
diff --git a/passwd.c b/passwd.c
@@ -25,29 +25,124 @@ usage(void)
eprintf("usage: %s [username]\n", argv0);
}
+static FILE *
+spw_get_file(const char *user)
+{
+ FILE *fp = NULL;
+ char file[PATH_MAX];
+ int r;
+
+ r = snprintf(file, sizeof(file), "/etc/tcb/%s/shadow", user);
+ if (r < 0 || (size_t)r >= sizeof(file))
+ eprintf("snprintf:");
+ fp = fopen(file, "r+");
+ if (!fp)
+ fp = fopen("/etc/shadow", "r+");
+ return fp;
+}
+
static int
-gettempfile(char *template)
+spw_write_file(FILE *fp, const struct spwd *spw, char *pwhash)
{
- int fd;
+ struct spwd *spwent;
+ int r = -1, w = 0;
+ FILE *tfp = NULL;
- umask(077);
- fd = mkostemp(template, O_RDWR);
- if (fd < 0)
- weprintf("mkstemp:");
- return fd;
+ /* write to temporary file. */
+ tfp = tmpfile();
+ if (!tfp) {
+ weprintf("tmpfile:");
+ goto cleanup;
+ }
+ while ((spwent = fgetspent(fp))) {
+ /* update entry on name match */
+ if (strcmp(spwent->sp_namp, spw->sp_namp) == 0) {
+ spwent->sp_pwdp = pwhash;
+ w++;
+ }
+ errno = 0;
+ if (putspent(spwent, tfp) == -1) {
+ weprintf("putspent:");
+ goto cleanup;
+ }
+ }
+ if (!w) {
+ weprintf("shadow: no matching entry to write to\n");
+ goto cleanup;
+ }
+ fflush(tfp);
+
+ if (fseek(fp, 0, SEEK_SET) == -1 || fseek(tfp, 0, SEEK_SET) == -1) {
+ weprintf("fseek:");
+ goto cleanup;
+ }
+
+ /* write temporary file to (tcb) shadow file */
+ concat(tfp, "tmpfile", fp, "shadow");
+ ftruncate(fileno(fp), ftell(tfp));
+
+ r = 0; /* success */
+cleanup:
+ if (tfp)
+ fclose(tfp);
+ return r;
+}
+
+static
+int pw_write_file(FILE *fp, const struct passwd *pw, char *pwhash) {
+ struct passwd *pwent;
+ int r = -1, w = 0;
+ FILE *tfp = NULL;
+
+ /* write to temporary file. */
+ tfp = tmpfile();
+ if (!tfp) {
+ weprintf("tmpfile:");
+ goto cleanup;
+ }
+ while ((pwent = fgetpwent(fp))) {
+ /* update entry on name match */
+ if (strcmp(pwent->pw_name, pw->pw_name) == 0) {
+ pwent->pw_passwd = pwhash;
+ w++;
+ }
+ errno = 0;
+ if (putpwent(pwent, tfp) == -1) {
+ weprintf("putpwent:");
+ goto cleanup;
+ }
+ }
+ if (!w) {
+ weprintf("passwd: no matching entry to write to\n");
+ goto cleanup;
+ }
+ fflush(tfp);
+
+ if (fseek(fp, 0, SEEK_SET) == -1 || fseek(tfp, 0, SEEK_SET) == -1) {
+ weprintf("fseek:");
+ goto cleanup;
+ }
+
+ /* write to passwd file. */
+ concat(tfp, "tmpfile", fp, "passwd");
+ ftruncate(fileno(fp), ftell(tfp));
+
+ r = 0; /* success */
+cleanup:
+ if (tfp)
+ fclose(tfp);
+ return r;
}
int
main(int argc, char *argv[])
{
char *cryptpass1 = NULL, *cryptpass2 = NULL, *cryptpass3 = NULL;
- char shadowfile[PATH_MAX], *inpass, *p, *pwd = NULL;
- char template[] = "/tmp/pw.XXXXXX";
+ char *inpass, *p, *salt = PW_CIPHER, *prevhash = NULL;
struct passwd *pw;
- struct spwd *spw = NULL, *spwent;
- uid_t uid;
- FILE *fp = NULL, *tfp = NULL;
- int ffd = -1, tfd = -1, r, status = EXIT_FAILURE;
+ struct spwd *spw = NULL;
+ FILE *fp = NULL;
+ int r = -1, status = EXIT_FAILURE;
ARGBEGIN {
default:
@@ -55,6 +150,7 @@ main(int argc, char *argv[])
} ARGEND;
pw_init();
+ umask(077);
errno = 0;
if (argc == 0)
@@ -69,7 +165,7 @@ main(int argc, char *argv[])
}
/* is using shadow entry ? */
- if (pw->pw_passwd[0] == 'x') {
+ if (pw->pw_passwd[0] == 'x' && pw->pw_passwd[1] == '\0') {
errno = 0;
spw = getspnam(pw->pw_name);
if (!spw) {
@@ -78,55 +174,46 @@ main(int argc, char *argv[])
else
eprintf("who are you?\n");
}
- pwd = spw->sp_pwdp;
- } else {
- pwd = pw->pw_passwd;
}
- uid = getuid();
- if (uid == 0) {
- if (pw->pw_passwd[0] == '!' ||
- pw->pw_passwd[0] == 'x' ||
- pw->pw_passwd[0] == '*' ||
- pw->pw_passwd[0] == '\0')
- pw->pw_passwd = PW_CIPHER;
+ /* Flush pending input */
+ ioctl(STDIN_FILENO, TCFLSH, (void *)0);
+
+ if (getuid() == 0) {
goto newpass;
} else {
if (pw->pw_passwd[0] == '!' ||
pw->pw_passwd[0] == '*')
eprintf("denied\n");
if (pw->pw_passwd[0] == '\0') {
- pw->pw_passwd = PW_CIPHER;
goto newpass;
}
+ if (pw->pw_passwd[0] == 'x')
+ prevhash = salt = spw->sp_pwdp;
+ else
+ prevhash = salt = pw->pw_passwd;
}
- /* Flush pending input */
- ioctl(STDIN_FILENO, TCFLSH, (void *)0);
-
printf("Changing password for %s\n", pw->pw_name);
inpass = getpass("Old password: ");
if (!inpass)
eprintf("getpass:");
if (inpass[0] == '\0')
eprintf("no password supplied\n");
- p = crypt(inpass, pwd);
+ p = crypt(inpass, salt);
if (!p)
eprintf("crypt:");
cryptpass1 = estrdup(p);
- if (strcmp(cryptpass1, pwd) != 0)
+ if (strcmp(cryptpass1, prevhash) != 0)
eprintf("incorrect password\n");
newpass:
- /* Flush pending input */
- ioctl(STDIN_FILENO, TCFLSH, (void *)0);
-
inpass = getpass("Enter new password: ");
if (!inpass)
eprintf("getpass:");
if (inpass[0] == '\0')
eprintf("no password supplied\n");
- p = crypt(inpass, pwd);
+ p = crypt(inpass, salt);
if (!p)
eprintf("crypt:");
cryptpass2 = estrdup(p);
@@ -141,88 +228,28 @@ newpass:
eprintf("getpass:");
if (inpass[0] == '\0')
eprintf("no password supplied\n");
- p = crypt(inpass, pwd);
+ p = crypt(inpass, salt);
if (!p)
eprintf("crypt:");
cryptpass3 = estrdup(p);
if (strcmp(cryptpass2, cryptpass3) != 0)
eprintf("passwords don't match\n");
- r = snprintf(shadowfile, sizeof(shadowfile), "/etc/tcb/%s/shadow", pw->pw_name);
- if (r < 0 || (size_t)r >= sizeof(shadowfile))
- eprintf("snprintf:");
- fp = fopen(shadowfile, "r+");
- if (!fp) {
- strlcpy(shadowfile, "/etc/shadow", sizeof(shadowfile));
- fp = fopen(shadowfile, "r+");
- }
+ fp = spw_get_file(pw->pw_name);
if (fp) {
- if ((tfd = gettempfile(template)) == -1)
- goto cleanup;
-
- /* write to (tcb) shadow file. */
- if (!(tfp = fdopen(tfd, "w+"))) {
- weprintf("fdopen:");
- goto cleanup;
- }
- while ((spwent = fgetspent(fp))) {
- /* update entry on name match */
- if (strcmp(spwent->sp_namp, spw->sp_namp) == 0)
- spwent->sp_pwdp = cryptpass3;
- errno = 0;
- if (putspent(spwent, tfp) == -1) {
- weprintf("putspent:");
- goto cleanup;
- }
- }
- fflush(tfp);
-
- if (fseek(fp, 0, SEEK_SET) == -1 || fseek(tfp, 0, SEEK_SET) == -1) {
- weprintf("rewind:");
- goto cleanup;
- }
-
- /* old shadow file with temporary file data. */
- concat(tfp, template, fp, shadowfile);
- ftruncate(tfd, ftell(tfp));
+ r = spw_write_file(fp, spw, cryptpass3);
} else {
- /* write to /etc/passwd file. */
- ffd = open("/etc/passwd", O_RDWR);
- if (ffd < 0) {
- weprintf("open %s:", "/etc/passwd");
- goto cleanup;
- }
- pw->pw_passwd = cryptpass3;
-
- if ((tfd = gettempfile(template)) == -1)
- goto cleanup;
-
- r = pw_copy(ffd, tfd, pw);
- if (r < 0)
- goto cleanup;
- r = lseek(ffd, 0, SEEK_SET);
- if (r < 0)
- goto cleanup;
- r = lseek(tfd, 0, SEEK_SET);
- if (r < 0)
- goto cleanup;
- r = pw_copy(tfd, ffd, NULL);
- if (r < 0)
- goto cleanup;
+ fp = fopen("/etc/passwd", "r+");
+ if (fp)
+ r = pw_write_file(fp, pw, cryptpass3);
+ else
+ weprintf("fopen:");
}
- status = EXIT_SUCCESS;
+ if (!r)
+ status = EXIT_SUCCESS;
-cleanup:
if (fp)
fclose(fp);
- if (tfp)
- fclose(tfp);
- if (tfd != -1) {
- close(tfd);
- unlink(template);
- }
- if (ffd != -1)
- close(ffd);
free(cryptpass3);
free(cryptpass2);
free(cryptpass1);
diff --git a/passwd.h b/passwd.h
@@ -1,6 +1,4 @@
/* See LICENSE file for copyright and license details. */
/* passwd.c */
-int pw_check(struct passwd *, const char *);
-int pw_copy(int, int, const struct passwd *);
+int pw_check(const struct passwd *, const char *);
int pw_init(void);
-int pw_scan(char *, struct passwd *);
diff --git a/util/passwd.c b/util/passwd.c
@@ -17,7 +17,7 @@
/* Returns -1 on error, 0 for incorrect password
* and 1 if all went OK */
int
-pw_check(struct passwd *pw, const char *pass)
+pw_check(const struct passwd *pw, const char *pass)
{
char *cryptpass, *p;
struct spwd *spw;
@@ -65,53 +65,6 @@ pw_check(struct passwd *pw, const char *pass)
}
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);
- free(buf);
- return 0;
-}
-
-int
pw_init(void)
{
struct rlimit rlim;
@@ -122,63 +75,3 @@ pw_init(void)
eprintf("setrlimit:");
return 0;
}
-
-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;
-}