morpheus-base

morpheus base system
git clone git://git.2f30.org/morpheus-base
Log | Files | Refs

passwd.c (5069B)


      1 /* See LICENSE file for copyright and license details. */
      2 #include <sys/ioctl.h>
      3 #include <sys/stat.h>
      4 #include <sys/types.h>
      5 
      6 #include <errno.h>
      7 #include <fcntl.h>
      8 #include <limits.h>
      9 #include <pwd.h>
     10 #include <shadow.h>
     11 #include <stdio.h>
     12 #include <stdlib.h>
     13 #include <string.h>
     14 #include <unistd.h>
     15 
     16 #include "config.h"
     17 #include "passwd.h"
     18 #include "text.h"
     19 #include "util.h"
     20 
     21 static void
     22 usage(void)
     23 {
     24 	eprintf("usage: %s [username]\n", argv0);
     25 }
     26 
     27 static FILE *
     28 spw_get_file(const char *user)
     29 {
     30 	FILE *fp = NULL;
     31 	char file[PATH_MAX];
     32 	int r;
     33 
     34 	r = snprintf(file, sizeof(file), "/etc/tcb/%s/shadow", user);
     35 	if (r < 0 || (size_t)r >= sizeof(file))
     36 		eprintf("snprintf:");
     37 	fp = fopen(file, "r+");
     38 	if (!fp)
     39 		fp = fopen("/etc/shadow", "r+");
     40 	return fp;
     41 }
     42 
     43 static int
     44 spw_write_file(FILE *fp, const struct spwd *spw, char *pwhash)
     45 {
     46 	struct spwd *spwent;
     47 	int r = -1, w = 0;
     48 	FILE *tfp = NULL;
     49 
     50 	/* write to temporary file. */
     51 	tfp = tmpfile();
     52 	if (!tfp) {
     53 		weprintf("tmpfile:");
     54 		goto cleanup;
     55 	}
     56 	while ((spwent = fgetspent(fp))) {
     57 		/* update entry on name match */
     58 		if (strcmp(spwent->sp_namp, spw->sp_namp) == 0) {
     59 			spwent->sp_pwdp = pwhash;
     60 			w++;
     61 		}
     62 		errno = 0;
     63 		if (putspent(spwent, tfp) == -1) {
     64 			weprintf("putspent:");
     65 			goto cleanup;
     66 		}
     67 	}
     68 	if (!w) {
     69 		weprintf("shadow: no matching entry to write to\n");
     70 		goto cleanup;
     71 	}
     72 	fflush(tfp);
     73 
     74 	if (fseek(fp, 0, SEEK_SET) == -1 || fseek(tfp, 0, SEEK_SET) == -1) {
     75 		weprintf("fseek:");
     76 		goto cleanup;
     77 	}
     78 
     79 	/* write temporary file to (tcb) shadow file */
     80 	concat(tfp, "tmpfile", fp, "shadow");
     81 	ftruncate(fileno(fp), ftell(tfp));
     82 
     83 	r = 0; /* success */
     84 cleanup:
     85 	if (tfp)
     86 		fclose(tfp);
     87 	return r;
     88 }
     89 
     90 static
     91 int pw_write_file(FILE *fp, const struct passwd *pw, char *pwhash) {
     92 	struct passwd *pwent;
     93 	int r = -1, w = 0;
     94 	FILE *tfp = NULL;
     95 
     96 	/* write to temporary file. */
     97 	tfp = tmpfile();
     98 	if (!tfp) {
     99 		weprintf("tmpfile:");
    100 		goto cleanup;
    101 	}
    102 	while ((pwent = fgetpwent(fp))) {
    103 		/* update entry on name match */
    104 		if (strcmp(pwent->pw_name, pw->pw_name) == 0) {
    105 			pwent->pw_passwd = pwhash;
    106 			w++;
    107 		}
    108 		errno = 0;
    109 		if (putpwent(pwent, tfp) == -1) {
    110 			weprintf("putpwent:");
    111 			goto cleanup;
    112 		}
    113 	}
    114 	if (!w) {
    115 		weprintf("passwd: no matching entry to write to\n");
    116 		goto cleanup;
    117 	}
    118 	fflush(tfp);
    119 
    120 	if (fseek(fp, 0, SEEK_SET) == -1 || fseek(tfp, 0, SEEK_SET) == -1) {
    121 		weprintf("fseek:");
    122 		goto cleanup;
    123 	}
    124 
    125 	/* write to passwd file. */
    126 	concat(tfp, "tmpfile", fp, "passwd");
    127 	ftruncate(fileno(fp), ftell(tfp));
    128 
    129 	r = 0; /* success */
    130 cleanup:
    131 	if (tfp)
    132 		fclose(tfp);
    133 	return r;
    134 }
    135 
    136 int
    137 main(int argc, char *argv[])
    138 {
    139 	char *cryptpass1 = NULL, *cryptpass2 = NULL, *cryptpass3 = NULL;
    140 	char *inpass, *p, *salt = PW_CIPHER, *prevhash = NULL;
    141 	struct passwd *pw;
    142 	struct spwd *spw = NULL;
    143 	FILE *fp = NULL;
    144 	int r = -1, status = 1;
    145 
    146 	ARGBEGIN {
    147 	default:
    148 		usage();
    149 	} ARGEND;
    150 
    151 	pw_init();
    152 	umask(077);
    153 
    154 	errno = 0;
    155 	if (argc == 0)
    156 		pw = getpwuid(getuid());
    157 	else
    158 		pw = getpwnam(argv[0]);
    159 	if (!pw) {
    160 		if (errno)
    161 			eprintf("getpwnam: %s:", argv[0]);
    162 		else
    163 			eprintf("who are you?\n");
    164 	}
    165 
    166 	/* is using shadow entry ? */
    167 	if (pw->pw_passwd[0] == 'x' && pw->pw_passwd[1] == '\0') {
    168 		errno = 0;
    169 		spw = getspnam(pw->pw_name);
    170 		if (!spw) {
    171 			if (errno)
    172 				eprintf("getspnam: %s:", pw->pw_name);
    173 			else
    174 				eprintf("who are you?\n");
    175 		}
    176 	}
    177 
    178 	/* Flush pending input */
    179 	ioctl(0, TCFLSH, (void *)0);
    180 
    181 	if (getuid() == 0) {
    182 		goto newpass;
    183 	} else {
    184 		if (pw->pw_passwd[0] == '!' ||
    185 		    pw->pw_passwd[0] == '*')
    186 			eprintf("denied\n");
    187 		if (pw->pw_passwd[0] == '\0') {
    188 			goto newpass;
    189 		}
    190 		if (pw->pw_passwd[0] == 'x')
    191 			prevhash = salt = spw->sp_pwdp;
    192 		else
    193 			prevhash = salt = pw->pw_passwd;
    194 	}
    195 
    196 	printf("Changing password for %s\n", pw->pw_name);
    197 	inpass = getpass("Old password: ");
    198 	if (!inpass)
    199 		eprintf("getpass:");
    200 	if (inpass[0] == '\0')
    201 		eprintf("no password supplied\n");
    202 	p = crypt(inpass, salt);
    203 	if (!p)
    204 		eprintf("crypt:");
    205 	cryptpass1 = estrdup(p);
    206 	if (strcmp(cryptpass1, prevhash) != 0)
    207 		eprintf("incorrect password\n");
    208 
    209 newpass:
    210 	inpass = getpass("Enter new password: ");
    211 	if (!inpass)
    212 		eprintf("getpass:");
    213 	if (inpass[0] == '\0')
    214 		eprintf("no password supplied\n");
    215 	p = crypt(inpass, salt);
    216 	if (!p)
    217 		eprintf("crypt:");
    218 	cryptpass2 = estrdup(p);
    219 	if (cryptpass1 && strcmp(cryptpass1, cryptpass2) == 0)
    220 		eprintf("password left unchanged\n");
    221 
    222 	/* Flush pending input */
    223 	ioctl(0, TCFLSH, (void *)0);
    224 
    225 	inpass = getpass("Retype new password: ");
    226 	if (!inpass)
    227 		eprintf("getpass:");
    228 	if (inpass[0] == '\0')
    229 		eprintf("no password supplied\n");
    230 	p = crypt(inpass, salt);
    231 	if (!p)
    232 		eprintf("crypt:");
    233 	cryptpass3 = estrdup(p);
    234 	if (strcmp(cryptpass2, cryptpass3) != 0)
    235 		eprintf("passwords don't match\n");
    236 
    237 	fp = spw_get_file(pw->pw_name);
    238 	if (fp) {
    239 		r = spw_write_file(fp, spw, cryptpass3);
    240 	} else {
    241 		fp = fopen("/etc/passwd", "r+");
    242 		if (fp)
    243 			r = pw_write_file(fp, pw, cryptpass3);
    244 		else
    245 			weprintf("fopen:");
    246 	}
    247 	if (!r)
    248 		status = 0;
    249 
    250 	if (fp)
    251 		fclose(fp);
    252 	free(cryptpass3);
    253 	free(cryptpass2);
    254 	free(cryptpass1);
    255 
    256 	return status;
    257 }