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