Blob


1 #include <u.h>
2 #include <libc.h>
3 #include <mp.h>
4 #include <libsec.h>
5 #include "SConn.h"
6 #include "secstore.h"
8 int verbose;
10 static void userinput(char *, int);
11 char *SECSTORE_DIR;
13 static void
14 ensure_exists(char *f, ulong perm)
15 {
16 int fd;
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 }
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;
42 SECSTORE_DIR = unsharp("#9/secstore");
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 }
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);
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 }
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 }
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");
106 if(strcmp(pass, passck) != 0){
107 print("passwords didn't match\n");
108 exits("no match");
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;
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;
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;
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;
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;
147 tm->year = atoi(buf+4) - 1900;
148 if(tm->year < 70){
149 print("!bad year: %d\n", tm->year + 1900);
150 continue;
152 tm->sec = 59;
153 tm->min = 59;
154 tm->hour = 23;
155 tm->yday = 0;
156 expsecs = tm2sec(tm);
157 break;
159 pw->expire = expsecs;
161 /* failed logins */
162 if(pw->failed != 0 )
163 print("clearing %d failed login attempts\n", pw->failed);
164 pw->failed = 0;
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;
179 if(buf[0]=='D' || buf[0]=='d'){
180 pw->status = pw->status & ~Enabled;
181 break;
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;
194 if(buf[0]=='N' || buf[0]=='n'){
195 pw->status = pw->status & ~STA;
196 break;
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");
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);
221 exits("");
222 return 1; /* keep other compilers happy */
226 static void
227 userinput(char *buf, int blen)
229 int n;
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;
239 buf += n; blen -= n;
240 if(blen<=0)
241 exits("input too large");