Plan 9 from Bell Labs’s /usr/web/sources/contrib/quanstro/root/sys/src/cmd/auth/factotum/main.c

Copyright © 2021 Plan 9 Foundation.
Distributed under the MIT License.
Download the Plan 9 distribution.


#include "std.h"
#include "dat.h"

int mainstacksize = 64*1024;
int extrafactotumdir;
int debug;
int doprivate = 1;
int trysecstore = 1;
int kflag;
int sflag;
int uflag;
int askforkeys;
char *factname = "factotum";
char *service;
char *owner;
char *authaddr;
static void private(void);
void gflag(char*);

void
usage(void)
{
	fprint(2, "usage: factotum [-DSdknpu] [-a authaddr] [-m mtpt] [-s service]\n");
	fprint(2, " or   factotum -g keypattern\n");
	fprint(2, " or   factotum -g 'badkeyattr\\nmsg\\nkeypattern'\n");
	threadexitsall("usage");
}

void
threadmain(int argc, char *argv[])
{
	char *mtpt, *s;
	char *secstorepw;
	char err[ERRMAX];
	Dir d;

	mtpt = "/mnt";
	extrafactotumdir = 1;
	secstorepw = nil;
	quotefmtinstall();
	fmtinstall('A', attrfmt);
	fmtinstall('H', encodefmt);
	fmtinstall('N', attrnamefmt);

	if(argc == 3 && strcmp(argv[1], "-g") == 0){
		gflag(argv[2]);
		threadexitsall(nil);
	}

	rfork(RFNOTEG);

	ARGBEGIN{
	default:
		usage();
	case 'D':
		chatty9p++;
		break;
	case 'S':		/* server: read nvram, no prompting for keys */
		askforkeys = 0;
		trysecstore = 0;
		sflag = 1;
		break;
	case 'a':
		authaddr = EARGF(usage());
		break;
	case 'd':
		debug = 1;
		doprivate = 0;
		break;
	case 'g':
		usage();
	case 'k':		/* reinitialize nvram */
		kflag = 1;
		break;
	case 'm':
		mtpt = EARGF(usage());
		break;
	case 'n':
		trysecstore = 0;
		break;
	case 'p':
		doprivate = 0;
		break;
	case 's':
		service = EARGF(usage());
		break;
	case 'u':		/* user: set hostowner */
		uflag = 1;
		break;
	case 'x':
		extrafactotumdir = 0;
		break;
	}ARGEND

	if(argc != 0)
		usage();
	if(doprivate)
		private();

	initcap();

	if(sflag){
		s = getnvramkey(kflag ? NVwrite : NVwriteonerr, &secstorepw);
		if(s == nil)
			fprint(2, "factotum warning: cannot read nvram: %r\n");
		else if(ctlwrite(s) < 0)
			fprint(2, "factotum warning: cannot add nvram key: %r\n");
		if(secstorepw != nil)
			trysecstore = 1;
		if (s != nil) {
			memset(s, 0, strlen(s));
			free(s);
		}
	} else if(uflag)
		promptforhostowner();
	owner = getuser();

	if(trysecstore && havesecstore()){
		while(secstorefetch(secstorepw) < 0){
			rerrstr(err, sizeof err);
			if(strcmp(err, "cancel") == 0)
				break;
			fprint(2, "secstorefetch: %r\n");
			fprint(2, "Enter an empty password to quit.\n");
			free(secstorepw);
			secstorepw = nil; /* just try nvram pw once */
		}
	}
	
	fsinit0();
	threadpostmountsrv(&fs, service, mtpt, MBEFORE);
	if(service){
		nulldir(&d);
		d.mode = 0666;
		s = emalloc(10+strlen(service));
		strcpy(s, "/srv/");
		strcat(s, service);
		if(dirwstat(s, &d) < 0)
			fprint(2, "factotum warning: cannot chmod 666 %s: %r\n", s);
		free(s);
	}
	threadexits(nil);
}

char *pmsg = "Warning! %s can't protect itself from debugging: %r\n";
char *smsg = "Warning! %s can't turn off swapping: %r\n";

/* don't allow other processes to debug us and steal keys */
static void
private(void)
{
	int fd;
	char buf[64];

	snprint(buf, sizeof(buf), "#p/%d/ctl", getpid());
	fd = open(buf, OWRITE);
	if(fd < 0){
		fprint(2, pmsg, argv0);
		return;
	}
	if(fprint(fd, "private") < 0)
		fprint(2, pmsg, argv0);
	if(fprint(fd, "noswap") < 0)
		fprint(2, smsg, argv0);
	close(fd);
}

/*
 *  prompt user for a key.  don't care about memory leaks, runs standalone
 */
static Attr*
promptforkey(int fd, char *params)
{
	char *def, *v;
	Attr *a, *attr;

	attr = _parseattr(params);
	fprint(fd, "\n!Adding key:");
	for(a=attr; a; a=a->next)
		if(a->type != AttrQuery && a->name[0] != '!')
			fprint(fd, " %q=%q", a->name, a->val);
	fprint(fd, "\n");

	for(a=attr; a; a=a->next){
		v = a->name;
		if(a->type != AttrQuery || v[0]=='!')
			continue;
		def = nil;
		if(strcmp(v, "user") == 0)
			def = getuser();
		a->val = readcons(v, def, 0);
		if(a->val == nil)
			sysfatal("user terminated key input");
		a->type = AttrNameval;
	}
	for(a=attr; a; a=a->next){
		v = a->name;
		if(a->type != AttrQuery || v[0]!='!')
			continue;
		def = nil;
		if(strcmp(v+1, "user") == 0)
			def = getuser();
		a->val = readcons(v+1, def, 1);
		if(a->val == nil)
			sysfatal("user terminated key input");
		a->type = AttrNameval;
	}
	fprint(fd, "!\n");
	return attr;
}

/*
 *  send a key to the mounted factotum
 */
static int
sendkey(Attr *attr)
{
	char buf[8192];
	int rv, fd;
	
	fd = open("/mnt/factotum/ctl", OWRITE);
	if(fd < 0)
		sysfatal("opening factotum/ctl: %r");
	snprint(buf, sizeof buf, "key %A\n", attr);
	rv = write(fd, buf, strlen(buf));
	close(fd);
	return rv;
}

/* askuser */
void
askuser(int fd, char *params)
{
	Attr *attr;

	attr = promptforkey(fd, params);
	if(attr == nil)
		sysfatal("no key supplied");
	if(sendkey(attr) < 0)
		sysfatal("sending key to factotum: %r");
}

void
gflag(char *s)
{
	char *f[4];
	int nf, fd;

	fd = open("/dev/cons", ORDWR);
	if(fd < 0)
		sysfatal("opening /dev/cons: %r");
	nf = getfields(s, f, nelem(f), 0, "\n");
	if(nf == 1){	/* needkey or old badkey */
		askuser(fd, s);
		threadexitsall(nil);
	}
	if(nf == 3){	/* new badkey */
		fprint(fd, "\n");
		fprint(fd, "!replace: %s\n", f[0]);
		fprint(fd, "!because: %s\n", f[1]);
		askuser(fd, f[2]);
		threadexitsall(nil);
	}
	usage();
}

Bell Labs OSI certified Powered by Plan 9

(Return to Plan 9 Home Page)

Copyright © 2021 Plan 9 Foundation. All Rights Reserved.
Comments to webmaster@9p.io.