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