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 }