xref: /plan9/sys/src/cmd/auth/login.c (revision d854de5991c7e0df387efa3ede5edcfdd69b65da)
1 #include <u.h>
2 #include <libc.h>
3 #include <auth.h>
4 #include <authsrv.h>
5 
6 void
readln(char * prompt,char * line,int len,int raw)7 readln(char *prompt, char *line, int len, int raw)
8 {
9 	char *p;
10 	int fdin, fdout, ctl, n, nr;
11 
12 	fdin = open("/dev/cons", OREAD);
13 	fdout = open("/dev/cons", OWRITE);
14 	fprint(fdout, "%s", prompt);
15 	if(raw){
16 		ctl = open("/dev/consctl", OWRITE);
17 		if(ctl < 0){
18 			fprint(2, "login: couldn't set raw mode");
19 			exits("readln");
20 		}
21 		write(ctl, "rawon", 5);
22 	} else
23 		ctl = -1;
24 	nr = 0;
25 	p = line;
26 	for(;;){
27 		n = read(fdin, p, 1);
28 		if(n < 0){
29 			close(ctl);
30 			close(fdin);
31 			close(fdout);
32 			fprint(2, "login: can't read cons");
33 			exits("readln");
34 		}
35 		if(*p == 0x7f)
36 			exits(0);
37 		if(n == 0 || *p == '\n' || *p == '\r'){
38 			*p = '\0';
39 			if(raw){
40 				write(ctl, "rawoff", 6);
41 				write(fdout, "\n", 1);
42 			}
43 			close(ctl);
44 			close(fdin);
45 			close(fdout);
46 			return;
47 		}
48 		if(*p == '\b'){
49 			if(nr > 0){
50 				nr--;
51 				p--;
52 			}
53 		}else{
54 			nr++;
55 			p++;
56 		}
57 		if(nr == len){
58 			fprint(fdout, "line too long; try again\n");
59 			nr = 0;
60 			p = line;
61 		}
62 	}
63 }
64 
65 void
setenv(char * var,char * val)66 setenv(char *var, char *val)
67 {
68 	int fd;
69 
70 	fd = create(var, OWRITE, 0644);
71 	if(fd < 0)
72 		print("init: can't open %s\n", var);
73 	else{
74 		fprint(fd, val);
75 		close(fd);
76 	}
77 }
78 
79 /*
80  *  become the authenticated user
81  */
82 void
chuid(AuthInfo * ai)83 chuid(AuthInfo *ai)
84 {
85 	int rv, fd;
86 
87 	/* change uid */
88 	fd = open("#¤/capuse", OWRITE);
89 	if(fd < 0)
90 		sysfatal("can't change uid: %r");
91 	rv = write(fd, ai->cap, strlen(ai->cap));
92 	close(fd);
93 	if(rv < 0)
94 		sysfatal("can't change uid: %r");
95 }
96 
97 /*
98  *  mount a factotum
99  */
100 void
mountfactotum(char * srvname)101 mountfactotum(char *srvname)
102 {
103 	int fd;
104 
105 	/* mount it */
106 	fd = open(srvname, ORDWR);
107 	if(fd < 0)
108 		sysfatal("opening factotum: %r");
109 	mount(fd, -1, "/mnt", MBEFORE, "");
110 	close(fd);
111 }
112 
113 /*
114  *  start a new factotum and pass it the username and password
115  */
116 void
startfactotum(char * user,char * password,char * srvname)117 startfactotum(char *user, char *password, char *srvname)
118 {
119 	int fd;
120 
121 	strcpy(srvname, "/srv/factotum.XXXXXXXXXXX");
122 	mktemp(srvname);
123 
124 	switch(fork()){
125 	case -1:
126 		sysfatal("can't start factotum: %r");
127 	case 0:
128 		execl("/boot/factotum", "loginfactotum", "-ns", srvname+5, nil);
129 		sysfatal("starting factotum: %r");
130 		break;
131 	}
132 
133 	/* wait for agent to really be there */
134 	while(access(srvname, 0) < 0)
135 		sleep(250);
136 
137 	/* mount it */
138 	mountfactotum(srvname);
139 
140 	/* write in new key */
141 	fd = open("/mnt/factotum/ctl", ORDWR);
142 	if(fd < 0)
143 		sysfatal("opening factotum: %r");
144 	fprint(fd, "key proto=p9sk1 dom=cs.bell-labs.com user=%q !password=%q", user, password);
145 	close(fd);
146 }
147 
148 void
main(int argc,char * argv[])149 main(int argc, char *argv[])
150 {
151 	char pass[ANAMELEN];
152 	char buf[2*ANAMELEN];
153 	char home[2*ANAMELEN];
154 	char srvname[2*ANAMELEN];
155 	char *user, *sysname, *tz, *cputype, *service;
156 	AuthInfo *ai;
157 
158 	ARGBEGIN{
159 	}ARGEND;
160 
161 	rfork(RFENVG|RFNAMEG);
162 
163 	service = getenv("service");
164 	if(strcmp(service, "cpu") == 0)
165 		fprint(2, "login: warning: running on a cpu server!\n");
166 	if(argc != 1){
167 		fprint(2, "usage: login username\n");
168 		exits("usage");
169 	}
170 	user = argv[0];
171 	memset(pass, 0, sizeof(pass));
172 	readln("Password: ", pass, sizeof(pass), 1);
173 
174 	/* authenticate */
175 	ai = auth_userpasswd(user, pass);
176 	if(ai == nil || ai->cap == nil)
177 		sysfatal("login incorrect");
178 
179 	/* change uid */
180 	chuid(ai);
181 
182 	/* start a new factotum and hand it a new key */
183 	startfactotum(user, pass, srvname);
184 
185 	/* set up new namespace */
186 	newns(ai->cuid, nil);
187 	auth_freeAI(ai);
188 
189 	/* remount the factotum */
190 	mountfactotum(srvname);
191 
192 	/* set up a new environment */
193 	cputype = getenv("cputype");
194 	sysname = getenv("sysname");
195 	tz = getenv("timezone");
196 	rfork(RFCENVG);
197 	setenv("#e/service", "con");
198 	setenv("#e/user", user);
199 	snprint(home, sizeof(home), "/usr/%s", user);
200 	setenv("#e/home", home);
201 	setenv("#e/cputype", cputype);
202 	setenv("#e/objtype", cputype);
203 	if(sysname != nil)
204 		setenv("#e/sysname", sysname);
205 	if(tz != nil)
206 		setenv("#e/timezone", tz);
207 
208 	/* go to new home directory */
209 	snprint(buf, sizeof(buf), "/usr/%s", user);
210 	if(chdir(buf) < 0)
211 		chdir("/");
212 
213 	/* read profile and start interactive rc */
214 	execl("/bin/rc", "rc", "-li", nil);
215 	exits(0);
216 }
217