mirror of git://git.suckless.org/ubase
passwd: fix /etc/passwd support, ...
... rewrite parts to use libc functions (supported by musl and glibc).
This commit is contained in:
parent
10a539e744
commit
8fdc7d70bd
237
passwd.c
237
passwd.c
|
@ -25,29 +25,124 @@ usage(void)
|
||||||
eprintf("usage: %s [username]\n", argv0);
|
eprintf("usage: %s [username]\n", argv0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static FILE *
|
||||||
gettempfile(char *template)
|
spw_get_file(const char *user)
|
||||||
{
|
{
|
||||||
int fd;
|
FILE *fp = NULL;
|
||||||
|
char file[PATH_MAX];
|
||||||
|
int r;
|
||||||
|
|
||||||
umask(077);
|
r = snprintf(file, sizeof(file), "/etc/tcb/%s/shadow", user);
|
||||||
fd = mkostemp(template, O_RDWR);
|
if (r < 0 || (size_t)r >= sizeof(file))
|
||||||
if (fd < 0)
|
eprintf("snprintf:");
|
||||||
weprintf("mkstemp:");
|
fp = fopen(file, "r+");
|
||||||
return fd;
|
if (!fp)
|
||||||
|
fp = fopen("/etc/shadow", "r+");
|
||||||
|
return fp;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
spw_write_file(FILE *fp, const struct spwd *spw, char *pwhash)
|
||||||
|
{
|
||||||
|
struct spwd *spwent;
|
||||||
|
int r = -1, w = 0;
|
||||||
|
FILE *tfp = NULL;
|
||||||
|
|
||||||
|
/* 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
|
int
|
||||||
main(int argc, char *argv[])
|
main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
char *cryptpass1 = NULL, *cryptpass2 = NULL, *cryptpass3 = NULL;
|
char *cryptpass1 = NULL, *cryptpass2 = NULL, *cryptpass3 = NULL;
|
||||||
char shadowfile[PATH_MAX], *inpass, *p, *pwd = NULL;
|
char *inpass, *p, *salt = PW_CIPHER, *prevhash = NULL;
|
||||||
char template[] = "/tmp/pw.XXXXXX";
|
|
||||||
struct passwd *pw;
|
struct passwd *pw;
|
||||||
struct spwd *spw = NULL, *spwent;
|
struct spwd *spw = NULL;
|
||||||
uid_t uid;
|
FILE *fp = NULL;
|
||||||
FILE *fp = NULL, *tfp = NULL;
|
int r = -1, status = EXIT_FAILURE;
|
||||||
int ffd = -1, tfd = -1, r, status = EXIT_FAILURE;
|
|
||||||
|
|
||||||
ARGBEGIN {
|
ARGBEGIN {
|
||||||
default:
|
default:
|
||||||
|
@ -55,6 +150,7 @@ main(int argc, char *argv[])
|
||||||
} ARGEND;
|
} ARGEND;
|
||||||
|
|
||||||
pw_init();
|
pw_init();
|
||||||
|
umask(077);
|
||||||
|
|
||||||
errno = 0;
|
errno = 0;
|
||||||
if (argc == 0)
|
if (argc == 0)
|
||||||
|
@ -69,7 +165,7 @@ main(int argc, char *argv[])
|
||||||
}
|
}
|
||||||
|
|
||||||
/* is using shadow entry ? */
|
/* is using shadow entry ? */
|
||||||
if (pw->pw_passwd[0] == 'x') {
|
if (pw->pw_passwd[0] == 'x' && pw->pw_passwd[1] == '\0') {
|
||||||
errno = 0;
|
errno = 0;
|
||||||
spw = getspnam(pw->pw_name);
|
spw = getspnam(pw->pw_name);
|
||||||
if (!spw) {
|
if (!spw) {
|
||||||
|
@ -78,55 +174,46 @@ main(int argc, char *argv[])
|
||||||
else
|
else
|
||||||
eprintf("who are you?\n");
|
eprintf("who are you?\n");
|
||||||
}
|
}
|
||||||
pwd = spw->sp_pwdp;
|
|
||||||
} else {
|
|
||||||
pwd = pw->pw_passwd;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uid = getuid();
|
/* Flush pending input */
|
||||||
if (uid == 0) {
|
ioctl(STDIN_FILENO, TCFLSH, (void *)0);
|
||||||
if (pw->pw_passwd[0] == '!' ||
|
|
||||||
pw->pw_passwd[0] == 'x' ||
|
if (getuid() == 0) {
|
||||||
pw->pw_passwd[0] == '*' ||
|
|
||||||
pw->pw_passwd[0] == '\0')
|
|
||||||
pw->pw_passwd = PW_CIPHER;
|
|
||||||
goto newpass;
|
goto newpass;
|
||||||
} else {
|
} else {
|
||||||
if (pw->pw_passwd[0] == '!' ||
|
if (pw->pw_passwd[0] == '!' ||
|
||||||
pw->pw_passwd[0] == '*')
|
pw->pw_passwd[0] == '*')
|
||||||
eprintf("denied\n");
|
eprintf("denied\n");
|
||||||
if (pw->pw_passwd[0] == '\0') {
|
if (pw->pw_passwd[0] == '\0') {
|
||||||
pw->pw_passwd = PW_CIPHER;
|
|
||||||
goto newpass;
|
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);
|
printf("Changing password for %s\n", pw->pw_name);
|
||||||
inpass = getpass("Old password: ");
|
inpass = getpass("Old password: ");
|
||||||
if (!inpass)
|
if (!inpass)
|
||||||
eprintf("getpass:");
|
eprintf("getpass:");
|
||||||
if (inpass[0] == '\0')
|
if (inpass[0] == '\0')
|
||||||
eprintf("no password supplied\n");
|
eprintf("no password supplied\n");
|
||||||
p = crypt(inpass, pwd);
|
p = crypt(inpass, salt);
|
||||||
if (!p)
|
if (!p)
|
||||||
eprintf("crypt:");
|
eprintf("crypt:");
|
||||||
cryptpass1 = estrdup(p);
|
cryptpass1 = estrdup(p);
|
||||||
if (strcmp(cryptpass1, pwd) != 0)
|
if (strcmp(cryptpass1, prevhash) != 0)
|
||||||
eprintf("incorrect password\n");
|
eprintf("incorrect password\n");
|
||||||
|
|
||||||
newpass:
|
newpass:
|
||||||
/* Flush pending input */
|
|
||||||
ioctl(STDIN_FILENO, TCFLSH, (void *)0);
|
|
||||||
|
|
||||||
inpass = getpass("Enter new password: ");
|
inpass = getpass("Enter new password: ");
|
||||||
if (!inpass)
|
if (!inpass)
|
||||||
eprintf("getpass:");
|
eprintf("getpass:");
|
||||||
if (inpass[0] == '\0')
|
if (inpass[0] == '\0')
|
||||||
eprintf("no password supplied\n");
|
eprintf("no password supplied\n");
|
||||||
p = crypt(inpass, pwd);
|
p = crypt(inpass, salt);
|
||||||
if (!p)
|
if (!p)
|
||||||
eprintf("crypt:");
|
eprintf("crypt:");
|
||||||
cryptpass2 = estrdup(p);
|
cryptpass2 = estrdup(p);
|
||||||
|
@ -141,88 +228,28 @@ newpass:
|
||||||
eprintf("getpass:");
|
eprintf("getpass:");
|
||||||
if (inpass[0] == '\0')
|
if (inpass[0] == '\0')
|
||||||
eprintf("no password supplied\n");
|
eprintf("no password supplied\n");
|
||||||
p = crypt(inpass, pwd);
|
p = crypt(inpass, salt);
|
||||||
if (!p)
|
if (!p)
|
||||||
eprintf("crypt:");
|
eprintf("crypt:");
|
||||||
cryptpass3 = estrdup(p);
|
cryptpass3 = estrdup(p);
|
||||||
if (strcmp(cryptpass2, cryptpass3) != 0)
|
if (strcmp(cryptpass2, cryptpass3) != 0)
|
||||||
eprintf("passwords don't match\n");
|
eprintf("passwords don't match\n");
|
||||||
|
|
||||||
r = snprintf(shadowfile, sizeof(shadowfile), "/etc/tcb/%s/shadow", pw->pw_name);
|
fp = spw_get_file(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+");
|
|
||||||
}
|
|
||||||
if (fp) {
|
if (fp) {
|
||||||
if ((tfd = gettempfile(template)) == -1)
|
r = spw_write_file(fp, spw, cryptpass3);
|
||||||
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));
|
|
||||||
} else {
|
} else {
|
||||||
/* write to /etc/passwd file. */
|
fp = fopen("/etc/passwd", "r+");
|
||||||
ffd = open("/etc/passwd", O_RDWR);
|
if (fp)
|
||||||
if (ffd < 0) {
|
r = pw_write_file(fp, pw, cryptpass3);
|
||||||
weprintf("open %s:", "/etc/passwd");
|
else
|
||||||
goto cleanup;
|
weprintf("fopen:");
|
||||||
}
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
status = EXIT_SUCCESS;
|
if (!r)
|
||||||
|
status = EXIT_SUCCESS;
|
||||||
|
|
||||||
cleanup:
|
|
||||||
if (fp)
|
if (fp)
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
if (tfp)
|
|
||||||
fclose(tfp);
|
|
||||||
if (tfd != -1) {
|
|
||||||
close(tfd);
|
|
||||||
unlink(template);
|
|
||||||
}
|
|
||||||
if (ffd != -1)
|
|
||||||
close(ffd);
|
|
||||||
free(cryptpass3);
|
free(cryptpass3);
|
||||||
free(cryptpass2);
|
free(cryptpass2);
|
||||||
free(cryptpass1);
|
free(cryptpass1);
|
||||||
|
|
4
passwd.h
4
passwd.h
|
@ -1,6 +1,4 @@
|
||||||
/* See LICENSE file for copyright and license details. */
|
/* See LICENSE file for copyright and license details. */
|
||||||
/* passwd.c */
|
/* passwd.c */
|
||||||
int pw_check(struct passwd *, const char *);
|
int pw_check(const struct passwd *, const char *);
|
||||||
int pw_copy(int, int, const struct passwd *);
|
|
||||||
int pw_init(void);
|
int pw_init(void);
|
||||||
int pw_scan(char *, struct passwd *);
|
|
||||||
|
|
109
util/passwd.c
109
util/passwd.c
|
@ -17,7 +17,7 @@
|
||||||
/* Returns -1 on error, 0 for incorrect password
|
/* Returns -1 on error, 0 for incorrect password
|
||||||
* and 1 if all went OK */
|
* and 1 if all went OK */
|
||||||
int
|
int
|
||||||
pw_check(struct passwd *pw, const char *pass)
|
pw_check(const struct passwd *pw, const char *pass)
|
||||||
{
|
{
|
||||||
char *cryptpass, *p;
|
char *cryptpass, *p;
|
||||||
struct spwd *spw;
|
struct spwd *spw;
|
||||||
|
@ -64,53 +64,6 @@ pw_check(struct passwd *pw, const char *pass)
|
||||||
return 1;
|
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);
|
|
||||||
free(buf);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
int
|
||||||
pw_init(void)
|
pw_init(void)
|
||||||
{
|
{
|
||||||
|
@ -122,63 +75,3 @@ pw_init(void)
|
||||||
eprintf("setrlimit:");
|
eprintf("setrlimit:");
|
||||||
return 0;
|
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;
|
|
||||||
}
|
|
||||||
|
|
Loading…
Reference in New Issue