xref: /plan9/sys/src/cmd/auth/login.c (revision d854de5991c7e0df387efa3ede5edcfdd69b65da)
17dd7cddfSDavid du Colombier #include <u.h>
27dd7cddfSDavid du Colombier #include <libc.h>
37dd7cddfSDavid du Colombier #include <auth.h>
49a747e4fSDavid du Colombier #include <authsrv.h>
57dd7cddfSDavid du Colombier 
67dd7cddfSDavid du Colombier void
readln(char * prompt,char * line,int len,int raw)77dd7cddfSDavid du Colombier readln(char *prompt, char *line, int len, int raw)
87dd7cddfSDavid du Colombier {
97dd7cddfSDavid du Colombier 	char *p;
107dd7cddfSDavid du Colombier 	int fdin, fdout, ctl, n, nr;
117dd7cddfSDavid du Colombier 
127dd7cddfSDavid du Colombier 	fdin = open("/dev/cons", OREAD);
137dd7cddfSDavid du Colombier 	fdout = open("/dev/cons", OWRITE);
147dd7cddfSDavid du Colombier 	fprint(fdout, "%s", prompt);
157dd7cddfSDavid du Colombier 	if(raw){
167dd7cddfSDavid du Colombier 		ctl = open("/dev/consctl", OWRITE);
177dd7cddfSDavid du Colombier 		if(ctl < 0){
18*d854de59SDavid du Colombier 			fprint(2, "login: couldn't set raw mode");
197dd7cddfSDavid du Colombier 			exits("readln");
207dd7cddfSDavid du Colombier 		}
217dd7cddfSDavid du Colombier 		write(ctl, "rawon", 5);
227dd7cddfSDavid du Colombier 	} else
237dd7cddfSDavid du Colombier 		ctl = -1;
247dd7cddfSDavid du Colombier 	nr = 0;
257dd7cddfSDavid du Colombier 	p = line;
267dd7cddfSDavid du Colombier 	for(;;){
277dd7cddfSDavid du Colombier 		n = read(fdin, p, 1);
287dd7cddfSDavid du Colombier 		if(n < 0){
297dd7cddfSDavid du Colombier 			close(ctl);
307dd7cddfSDavid du Colombier 			close(fdin);
317dd7cddfSDavid du Colombier 			close(fdout);
32*d854de59SDavid du Colombier 			fprint(2, "login: can't read cons");
337dd7cddfSDavid du Colombier 			exits("readln");
347dd7cddfSDavid du Colombier 		}
357dd7cddfSDavid du Colombier 		if(*p == 0x7f)
367dd7cddfSDavid du Colombier 			exits(0);
377dd7cddfSDavid du Colombier 		if(n == 0 || *p == '\n' || *p == '\r'){
387dd7cddfSDavid du Colombier 			*p = '\0';
397dd7cddfSDavid du Colombier 			if(raw){
407dd7cddfSDavid du Colombier 				write(ctl, "rawoff", 6);
417dd7cddfSDavid du Colombier 				write(fdout, "\n", 1);
427dd7cddfSDavid du Colombier 			}
437dd7cddfSDavid du Colombier 			close(ctl);
447dd7cddfSDavid du Colombier 			close(fdin);
457dd7cddfSDavid du Colombier 			close(fdout);
467dd7cddfSDavid du Colombier 			return;
477dd7cddfSDavid du Colombier 		}
487dd7cddfSDavid du Colombier 		if(*p == '\b'){
497dd7cddfSDavid du Colombier 			if(nr > 0){
507dd7cddfSDavid du Colombier 				nr--;
517dd7cddfSDavid du Colombier 				p--;
527dd7cddfSDavid du Colombier 			}
537dd7cddfSDavid du Colombier 		}else{
547dd7cddfSDavid du Colombier 			nr++;
557dd7cddfSDavid du Colombier 			p++;
567dd7cddfSDavid du Colombier 		}
577dd7cddfSDavid du Colombier 		if(nr == len){
587dd7cddfSDavid du Colombier 			fprint(fdout, "line too long; try again\n");
597dd7cddfSDavid du Colombier 			nr = 0;
607dd7cddfSDavid du Colombier 			p = line;
617dd7cddfSDavid du Colombier 		}
627dd7cddfSDavid du Colombier 	}
637dd7cddfSDavid du Colombier }
647dd7cddfSDavid du Colombier 
657dd7cddfSDavid du Colombier void
setenv(char * var,char * val)667dd7cddfSDavid du Colombier setenv(char *var, char *val)
677dd7cddfSDavid du Colombier {
687dd7cddfSDavid du Colombier 	int fd;
697dd7cddfSDavid du Colombier 
707dd7cddfSDavid du Colombier 	fd = create(var, OWRITE, 0644);
717dd7cddfSDavid du Colombier 	if(fd < 0)
727dd7cddfSDavid du Colombier 		print("init: can't open %s\n", var);
737dd7cddfSDavid du Colombier 	else{
747dd7cddfSDavid du Colombier 		fprint(fd, val);
757dd7cddfSDavid du Colombier 		close(fd);
767dd7cddfSDavid du Colombier 	}
777dd7cddfSDavid du Colombier }
787dd7cddfSDavid du Colombier 
796b6b9ac8SDavid du Colombier /*
806b6b9ac8SDavid du Colombier  *  become the authenticated user
816b6b9ac8SDavid du Colombier  */
826b6b9ac8SDavid du Colombier void
chuid(AuthInfo * ai)836b6b9ac8SDavid du Colombier chuid(AuthInfo *ai)
846b6b9ac8SDavid du Colombier {
856b6b9ac8SDavid du Colombier 	int rv, fd;
866b6b9ac8SDavid du Colombier 
876b6b9ac8SDavid du Colombier 	/* change uid */
886b6b9ac8SDavid du Colombier 	fd = open("#¤/capuse", OWRITE);
896b6b9ac8SDavid du Colombier 	if(fd < 0)
906b6b9ac8SDavid du Colombier 		sysfatal("can't change uid: %r");
916b6b9ac8SDavid du Colombier 	rv = write(fd, ai->cap, strlen(ai->cap));
926b6b9ac8SDavid du Colombier 	close(fd);
936b6b9ac8SDavid du Colombier 	if(rv < 0)
946b6b9ac8SDavid du Colombier 		sysfatal("can't change uid: %r");
956b6b9ac8SDavid du Colombier }
966b6b9ac8SDavid du Colombier 
976b6b9ac8SDavid du Colombier /*
986b6b9ac8SDavid du Colombier  *  mount a factotum
996b6b9ac8SDavid du Colombier  */
1006b6b9ac8SDavid du Colombier void
mountfactotum(char * srvname)1016b6b9ac8SDavid du Colombier mountfactotum(char *srvname)
1026b6b9ac8SDavid du Colombier {
1036b6b9ac8SDavid du Colombier 	int fd;
1046b6b9ac8SDavid du Colombier 
1056b6b9ac8SDavid du Colombier 	/* mount it */
1066b6b9ac8SDavid du Colombier 	fd = open(srvname, ORDWR);
1076b6b9ac8SDavid du Colombier 	if(fd < 0)
1086b6b9ac8SDavid du Colombier 		sysfatal("opening factotum: %r");
1096b6b9ac8SDavid du Colombier 	mount(fd, -1, "/mnt", MBEFORE, "");
1106b6b9ac8SDavid du Colombier 	close(fd);
1116b6b9ac8SDavid du Colombier }
1126b6b9ac8SDavid du Colombier 
1136b6b9ac8SDavid du Colombier /*
1146b6b9ac8SDavid du Colombier  *  start a new factotum and pass it the username and password
1156b6b9ac8SDavid du Colombier  */
1166b6b9ac8SDavid du Colombier void
startfactotum(char * user,char * password,char * srvname)1176b6b9ac8SDavid du Colombier startfactotum(char *user, char *password, char *srvname)
1186b6b9ac8SDavid du Colombier {
1196b6b9ac8SDavid du Colombier 	int fd;
1206b6b9ac8SDavid du Colombier 
1216b6b9ac8SDavid du Colombier 	strcpy(srvname, "/srv/factotum.XXXXXXXXXXX");
1226b6b9ac8SDavid du Colombier 	mktemp(srvname);
1236b6b9ac8SDavid du Colombier 
1246b6b9ac8SDavid du Colombier 	switch(fork()){
1256b6b9ac8SDavid du Colombier 	case -1:
1266b6b9ac8SDavid du Colombier 		sysfatal("can't start factotum: %r");
1276b6b9ac8SDavid du Colombier 	case 0:
128f19e7b74SDavid du Colombier 		execl("/boot/factotum", "loginfactotum", "-ns", srvname+5, nil);
1296b6b9ac8SDavid du Colombier 		sysfatal("starting factotum: %r");
1306b6b9ac8SDavid du Colombier 		break;
1316b6b9ac8SDavid du Colombier 	}
1326b6b9ac8SDavid du Colombier 
1336b6b9ac8SDavid du Colombier 	/* wait for agent to really be there */
1346b6b9ac8SDavid du Colombier 	while(access(srvname, 0) < 0)
1356b6b9ac8SDavid du Colombier 		sleep(250);
1366b6b9ac8SDavid du Colombier 
1376b6b9ac8SDavid du Colombier 	/* mount it */
1386b6b9ac8SDavid du Colombier 	mountfactotum(srvname);
1396b6b9ac8SDavid du Colombier 
1406b6b9ac8SDavid du Colombier 	/* write in new key */
1416b6b9ac8SDavid du Colombier 	fd = open("/mnt/factotum/ctl", ORDWR);
1426b6b9ac8SDavid du Colombier 	if(fd < 0)
1436b6b9ac8SDavid du Colombier 		sysfatal("opening factotum: %r");
1446b6b9ac8SDavid du Colombier 	fprint(fd, "key proto=p9sk1 dom=cs.bell-labs.com user=%q !password=%q", user, password);
1456b6b9ac8SDavid du Colombier 	close(fd);
1466b6b9ac8SDavid du Colombier }
1476b6b9ac8SDavid du Colombier 
1487dd7cddfSDavid du Colombier void
main(int argc,char * argv[])1497dd7cddfSDavid du Colombier main(int argc, char *argv[])
1507dd7cddfSDavid du Colombier {
1519a747e4fSDavid du Colombier 	char pass[ANAMELEN];
1529a747e4fSDavid du Colombier 	char buf[2*ANAMELEN];
1539a747e4fSDavid du Colombier 	char home[2*ANAMELEN];
1546b6b9ac8SDavid du Colombier 	char srvname[2*ANAMELEN];
1557dd7cddfSDavid du Colombier 	char *user, *sysname, *tz, *cputype, *service;
1566b6b9ac8SDavid du Colombier 	AuthInfo *ai;
1576b6b9ac8SDavid du Colombier 
1586b6b9ac8SDavid du Colombier 	ARGBEGIN{
1596b6b9ac8SDavid du Colombier 	}ARGEND;
1607dd7cddfSDavid du Colombier 
161d9306527SDavid du Colombier 	rfork(RFENVG|RFNAMEG);
162d9306527SDavid du Colombier 
1637dd7cddfSDavid du Colombier 	service = getenv("service");
1646b6b9ac8SDavid du Colombier 	if(strcmp(service, "cpu") == 0)
165*d854de59SDavid du Colombier 		fprint(2, "login: warning: running on a cpu server!\n");
1666b6b9ac8SDavid du Colombier 	if(argc != 1){
1677dd7cddfSDavid du Colombier 		fprint(2, "usage: login username\n");
1687dd7cddfSDavid du Colombier 		exits("usage");
1697dd7cddfSDavid du Colombier 	}
1706b6b9ac8SDavid du Colombier 	user = argv[0];
1717dd7cddfSDavid du Colombier 	memset(pass, 0, sizeof(pass));
1727dd7cddfSDavid du Colombier 	readln("Password: ", pass, sizeof(pass), 1);
1736b6b9ac8SDavid du Colombier 
1746b6b9ac8SDavid du Colombier 	/* authenticate */
1756b6b9ac8SDavid du Colombier 	ai = auth_userpasswd(user, pass);
1766b6b9ac8SDavid du Colombier 	if(ai == nil || ai->cap == nil)
1776b6b9ac8SDavid du Colombier 		sysfatal("login incorrect");
1786b6b9ac8SDavid du Colombier 
1796b6b9ac8SDavid du Colombier 	/* change uid */
1806b6b9ac8SDavid du Colombier 	chuid(ai);
1816b6b9ac8SDavid du Colombier 
1826b6b9ac8SDavid du Colombier 	/* start a new factotum and hand it a new key */
1836b6b9ac8SDavid du Colombier 	startfactotum(user, pass, srvname);
1846b6b9ac8SDavid du Colombier 
1856b6b9ac8SDavid du Colombier 	/* set up new namespace */
1866b6b9ac8SDavid du Colombier 	newns(ai->cuid, nil);
1876b6b9ac8SDavid du Colombier 	auth_freeAI(ai);
1886b6b9ac8SDavid du Colombier 
1896b6b9ac8SDavid du Colombier 	/* remount the factotum */
1906b6b9ac8SDavid du Colombier 	mountfactotum(srvname);
1917dd7cddfSDavid du Colombier 
1927dd7cddfSDavid du Colombier 	/* set up a new environment */
1937dd7cddfSDavid du Colombier 	cputype = getenv("cputype");
1947dd7cddfSDavid du Colombier 	sysname = getenv("sysname");
19580ee5cbfSDavid du Colombier 	tz = getenv("timezone");
1967dd7cddfSDavid du Colombier 	rfork(RFCENVG);
1977dd7cddfSDavid du Colombier 	setenv("#e/service", "con");
1987dd7cddfSDavid du Colombier 	setenv("#e/user", user);
1997dd7cddfSDavid du Colombier 	snprint(home, sizeof(home), "/usr/%s", user);
2007dd7cddfSDavid du Colombier 	setenv("#e/home", home);
2017dd7cddfSDavid du Colombier 	setenv("#e/cputype", cputype);
2027dd7cddfSDavid du Colombier 	setenv("#e/objtype", cputype);
2037dd7cddfSDavid du Colombier 	if(sysname != nil)
2047dd7cddfSDavid du Colombier 		setenv("#e/sysname", sysname);
2057dd7cddfSDavid du Colombier 	if(tz != nil)
2067dd7cddfSDavid du Colombier 		setenv("#e/timezone", tz);
2077dd7cddfSDavid du Colombier 
2087dd7cddfSDavid du Colombier 	/* go to new home directory */
2097dd7cddfSDavid du Colombier 	snprint(buf, sizeof(buf), "/usr/%s", user);
2107dd7cddfSDavid du Colombier 	if(chdir(buf) < 0)
2117dd7cddfSDavid du Colombier 		chdir("/");
2127dd7cddfSDavid du Colombier 
2137dd7cddfSDavid du Colombier 	/* read profile and start interactive rc */
214f19e7b74SDavid du Colombier 	execl("/bin/rc", "rc", "-li", nil);
2157dd7cddfSDavid du Colombier 	exits(0);
2167dd7cddfSDavid du Colombier }
217