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