Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 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
}