aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/auth/passwd.c
blob: 0b5e0453b979ff797ea63a2f2fff6b9410ad6fa0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
#include <u.h>
#include <libc.h>
#include <libsec.h>
#include <authsrv.h>

static char *pbmsg = "AS protocol botch";

int
asrdresp(int fd, char *buf, int len)
{
	char error[AERRLEN];

	if(read(fd, buf, 1) != 1){
		werrstr(pbmsg);
		return -1;
	}

	switch(buf[0]){
	case AuthOK:
		if(readn(fd, buf, len) < 0){
			werrstr(pbmsg);
			return -1;
		}
		break;
	case AuthErr:
		if(readn(fd, error, AERRLEN) < 0){
			werrstr(pbmsg);
			return -1;
		}
		error[AERRLEN-1] = 0;
		werrstr(error);
		return -1;
	default:
		werrstr(pbmsg);
		return -1;
	}
	return 0;
}

void
readln(char *prompt, char *buf, int nbuf, int secret)
{
	char *p;

	p = readcons(prompt, nil, secret);
	if(p == nil)
		sysfatal("user terminated input");
	if(strlen(p) >= nbuf)
		sysfatal("too long");
	strcpy(buf, p);
	memset(p, 0, strlen(p));
	free(p);
}

void
main(int argc, char **argv)
{
	int fd;
	Ticketreq tr;
	Ticket t;
	Passwordreq pr;
	char tbuf[TICKETLEN];
	char key[DESKEYLEN];
	char buf[512];
	char *s, *user;

	user = getuser();

	ARGBEGIN{
	}ARGEND

	s = nil;
	if(argc > 0){
		user = argv[0];
		s = strchr(user, '@');
		if(s != nil)
			*s++ = 0;
		if(*user == 0)
			user = getuser();
	}

	fd = authdial(nil, s);
	if(fd < 0)
		sysfatal("protocol botch: %r");

	/* send ticket request to AS */
	memset(&tr, 0, sizeof(tr));
	strcpy(tr.uid, user);
	tr.type = AuthPass;
	convTR2M(&tr, buf);
	if(write(fd, buf, TICKREQLEN) != TICKREQLEN)
		sysfatal("protocol botch: %r");
	if(asrdresp(fd, buf, TICKETLEN) < 0)
		sysfatal("%r");
	memmove(tbuf, buf, TICKETLEN);

	/*
	 *  get a password from the user and try to decrypt the
	 *  ticket.  If it doesn't work we've got a bad password,
	 *  give up.
	 */
	readln("Plan 9 Password", pr.old, sizeof pr.old, 1);
	passtokey(key, pr.old);
	convM2T(tbuf, &t, key);
	if(t.num != AuthTp || strcmp(t.cuid, tr.uid))
		sysfatal("bad password");

	/* loop trying new passwords */
	for(;;){
		pr.changesecret = 0;
		*pr.new = 0;
		readln("change Plan 9 Password? (y/n)", buf, sizeof buf, 0);
		if(*buf == 'y' || *buf == 'Y'){
			readln("Password(8 to 31 characters)", pr.new,
				sizeof pr.new, 1);
			readln("Confirm", buf, sizeof buf, 1);
			if(strcmp(pr.new, buf)){
				print("!mismatch\n");
				continue;
			}
		}
		readln("change Inferno/POP password? (y/n)", buf, sizeof buf, 0);
		if(*buf == 'y' || *buf == 'Y'){
			pr.changesecret = 1;
			readln("make it the same as your plan 9 password? (y/n)",
				buf, sizeof buf, 0);
			if(*buf == 'y' || *buf == 'Y'){
				if(*pr.new == 0)
					strcpy(pr.secret, pr.old);
				else
					strcpy(pr.secret, pr.new);
			} else {
				readln("Secret(0 to 256 characters)", pr.secret,
					sizeof pr.secret, 1);
				readln("Confirm", buf, sizeof buf, 1);
				if(strcmp(pr.secret, buf)){
					print("!mismatch\n");
					continue;
				}
			}
		}
		pr.num = AuthPass;
		convPR2M(&pr, buf, t.key);
		if(write(fd, buf, PASSREQLEN) != PASSREQLEN)
			sysfatal("AS protocol botch: %r");
		if(asrdresp(fd, buf, 0) == 0)
			break;
		fprint(2, "refused: %r\n");
	}
	close(fd);

	exits(0);
}