plan9port

fork of plan9port with libvec, libstr and libsdb
Log | Files | Refs | README | LICENSE

secuser.c (5194B)


      1 #include <u.h>
      2 #include <libc.h>
      3 #include <mp.h>
      4 #include <libsec.h>
      5 #include "SConn.h"
      6 #include "secstore.h"
      7 
      8 int verbose;
      9 
     10 static void userinput(char *, int);
     11 char *SECSTORE_DIR;
     12 
     13 static void
     14 ensure_exists(char *f, ulong perm)
     15 {
     16 	int fd;
     17 
     18 	if(access(f, AEXIST) >= 0)
     19 		return;
     20 	if(verbose)
     21 		fprint(2,"first time setup for secstore: create %s %lo\n", f, perm);
     22 	fd = create(f, OREAD, perm);
     23 	if(fd < 0){
     24 		fprint(2, "unable to create %s\n", f);
     25 		exits("secstored directories");
     26 	}
     27 	close(fd);
     28 }
     29 
     30 
     31 int
     32 main(int argc, char **argv)
     33 {
     34 	int isnew;
     35 	char *id, buf[Maxmsg], home[Maxmsg], prompt[100], *hexHi;
     36 	char *pass, *passck;
     37 	long expsecs;
     38 	mpint *H = mpnew(0), *Hi = mpnew(0);
     39 	PW *pw;
     40 	Tm *tm;
     41 
     42 	SECSTORE_DIR = unsharp("#9/secstore");
     43 
     44 	ARGBEGIN{
     45 	case 'v':
     46 		verbose++;
     47 		break;
     48 	}ARGEND;
     49 	if(argc!=1){
     50 		print("usage: secuser [-v] <user>\n");
     51 		exits("usage");
     52 	}
     53 
     54 	ensure_exists(SECSTORE_DIR, DMDIR|0755L);
     55 	snprint(home, sizeof(home), "%s/who", SECSTORE_DIR);
     56 	ensure_exists(home, DMDIR|0755L);
     57 	snprint(home, sizeof(home), "%s/store", SECSTORE_DIR);
     58 	ensure_exists(home, DMDIR|0700L);
     59 
     60 	id = argv[0];
     61 	if(verbose)
     62 		fprint(2,"secuser %s\n", id);
     63 	if((pw = getPW(id,1)) == nil){
     64 		isnew = 1;
     65 		print("new account (because %s/%s %r)\n", SECSTORE_DIR, id);
     66 		pw = emalloc(sizeof(*pw));
     67 		pw->id = estrdup(id);
     68 		snprint(home, sizeof(home), "%s/store/%s", SECSTORE_DIR, id);
     69 		if(access(home, AEXIST) == 0){
     70 			print("new user, but directory %s already exists\n", home);
     71 			exits(home);
     72 		}
     73 	}else{
     74 		isnew = 0;
     75 	}
     76 
     77 	/* get main password for id */
     78 	for(;;){
     79 		if(isnew)
     80 			snprint(prompt, sizeof(prompt), "%s password", id);
     81 		else
     82 			snprint(prompt, sizeof(prompt), "%s password [default = don't change]", id);
     83 		pass = readcons(prompt, nil, 1);
     84 		if(pass == nil){
     85 			print("getpass failed\n");
     86 			exits("getpass failed");
     87 		}
     88 		if(verbose)
     89 			print("%ld characters\n", strlen(pass));
     90 		if(pass[0] == '\0' && isnew == 0)
     91 			break;
     92 		if(strlen(pass) >= 7)
     93 			break;
     94 		print("password must be at least 7 characters\n");
     95 	}
     96 
     97 	if(pass[0] != '\0'){
     98 		snprint(prompt, sizeof(prompt), "retype password");
     99 		if(verbose)
    100 			print("confirming...\n");
    101 		passck = readcons(prompt, nil, 1);
    102 		if(passck == nil){
    103 			print("getpass failed\n");
    104 			exits("getpass failed");
    105 		}
    106 		if(strcmp(pass, passck) != 0){
    107 			print("passwords didn't match\n");
    108 			exits("no match");
    109 		}
    110 		memset(passck, 0, strlen(passck));
    111 		free(passck);
    112 		hexHi = PAK_Hi(id, pass, H, Hi);
    113 		memset(pass, 0, strlen(pass));
    114 		free(pass);
    115 		free(hexHi);
    116 		mpfree(H);
    117 		pw->Hi = Hi;
    118 	}
    119 
    120 	/* get expiration time (midnight of date specified) */
    121 	if(isnew)
    122 		expsecs = time(0) + 365*24*60*60;
    123 	else
    124 		expsecs = pw->expire;
    125 
    126 	for(;;){
    127 		tm = localtime(expsecs);
    128 		print("expires [DDMMYYYY, default = %2.2d%2.2d%4.4d]: ",
    129 				tm->mday, tm->mon, tm->year+1900);
    130 		userinput(buf, sizeof(buf));
    131 		if(strlen(buf) == 0)
    132 			break;
    133 		if(strlen(buf) != 8){
    134 			print("!bad date format: %s\n", buf);
    135 			continue;
    136 		}
    137 		tm->mday = (buf[0]-'0')*10 + (buf[1]-'0');
    138 		if(tm->mday > 31 || tm->mday < 1){
    139 			print("!bad day of month: %d\n", tm->mday);
    140 			continue;
    141 		}
    142 		tm->mon = (buf[2]-'0')*10 + (buf[3]-'0') - 1;
    143 		if(tm->mon > 11 || tm->mday < 0){
    144 			print("!bad month: %d\n", tm->mon + 1);
    145 			continue;
    146 		}
    147 		tm->year = atoi(buf+4) - 1900;
    148 		if(tm->year < 70){
    149 			print("!bad year: %d\n", tm->year + 1900);
    150 			continue;
    151 		}
    152 		tm->sec = 59;
    153 		tm->min = 59;
    154 		tm->hour = 23;
    155 		tm->yday = 0;
    156 		expsecs = tm2sec(tm);
    157 		break;
    158 	}
    159 	pw->expire = expsecs;
    160 
    161 	/* failed logins */
    162 	if(pw->failed != 0 )
    163 		print("clearing %d failed login attempts\n", pw->failed);
    164 	pw->failed = 0;
    165 
    166 	/* status bits */
    167 	if(isnew)
    168 		pw->status = Enabled;
    169 	for(;;){
    170 		print("Enabled or Disabled [default %s]: ",
    171 			(pw->status & Enabled) ? "Enabled" : "Disabled" );
    172 		userinput(buf, sizeof(buf));
    173 		if(strlen(buf) == 0)
    174 			break;
    175 		if(buf[0]=='E' || buf[0]=='e'){
    176 			pw->status |= Enabled;
    177 			break;
    178 		}
    179 		if(buf[0]=='D' || buf[0]=='d'){
    180 			pw->status = pw->status & ~Enabled;
    181 			break;
    182 		}
    183 	}
    184 	for(;;){
    185 		print("require STA? [default %s]: ",
    186 			(pw->status & STA) ? "yes" : "no" );
    187 		userinput(buf, sizeof(buf));
    188 		if(strlen(buf) == 0)
    189 			break;
    190 		if(buf[0]=='Y' || buf[0]=='y'){
    191 			pw->status |= STA;
    192 			break;
    193 		}
    194 		if(buf[0]=='N' || buf[0]=='n'){
    195 			pw->status = pw->status & ~STA;
    196 			break;
    197 		}
    198 	}
    199 
    200 	/* free form field */
    201 	if(isnew)
    202 		pw->other = nil;
    203 	print("comments [default = %s]: ", (pw->other == nil) ? "" : pw->other);
    204 	userinput(buf, 72);  /* 72 comes from password.h */
    205 	if(buf[0])
    206 		if((pw->other = strdup(buf)) == nil)
    207 			sysfatal("strdup");
    208 
    209 	syslog(0, LOG, "CHANGELOGIN for '%s'", pw->id);
    210 	if(putPW(pw) < 0){
    211 		print("error writing entry: %r\n");
    212 		exits("can't write password file");
    213 	}else{
    214 		print("change written\n");
    215 		if(isnew && create(home, OREAD, DMDIR | 0775L) < 0){
    216 			print("unable to create %s: %r\n", home);
    217 			exits(home);
    218 		}
    219 	}
    220 
    221 	exits("");
    222 	return 1;  /* keep  other compilers happy */
    223 }
    224 
    225 
    226 static void
    227 userinput(char *buf, int blen)
    228 {
    229 	int n;
    230 
    231 	while(1){
    232 		n = read(0, buf, blen);
    233 		if(n<=0)
    234 			exits("read error");
    235 		if(buf[n-1]=='\n'){
    236 			buf[n-1] = '\0';
    237 			return;
    238 		}
    239 		buf += n;  blen -= n;
    240 		if(blen<=0)
    241 			exits("input too large");
    242 	}
    243 }