code: 9ferno

ref: 6bfe4cf8107de7a01ff8a0667db7f28f08e4d238
dir: /appl/cmd/auth/ai2key.b/

View raw version
implement Ai2fact;

# authinfo to factotum key set
#	intermediate version, for use until revised Inferno authentication is ready


# converts an old authinfo entry in keyring directory to a key for factotum
#
# keys are in proto=infauth, and include the data for the signed certificate, and the diffie-helman parameters

include "sys.m";
	sys: Sys;

include "draw.m";

include "keyring.m";
	keyring: Keyring;
	Certificate, IPint, PK, SK: import keyring;

include "daytime.m";
	daytime: Daytime;

include "arg.m";

Ai2fact: module
{
	init: fn(nil: ref Draw->Context, nil: list of string);
};

init(nil: ref Draw->Context, args: list of string)
{
	sys = load Sys Sys->PATH;
	keyring = load Keyring Keyring->PATH;
	daytime = load Daytime Daytime->PATH;

	arg := load Arg Arg->PATH;
	arg->init(args);
	arg->setusage("ai2key [-t 'attr=value attr=value ...'] keyfile ...");
	tag: string;
	while((o := arg->opt()) != 0)
		case o {
		't' =>
			tag = arg->earg();
		* =>
			arg->usage();
		}
	args = arg->argv();
	if(args == nil)
		arg->usage();
	arg = nil;

	now := daytime->now();
	for(; args != nil; args = tl args){
		keyfile := hd args;
		ai := keyring->readauthinfo(keyfile);
		if(ai == nil)
			error(sys->sprint("cannot read %s: %r", keyfile));
		if(ai.cert.exp != 0 && ai.cert.exp <= now){
			sys->fprint(sys->fildes(2), "ai2key: %s: certificate expired -- key ignored\n", keyfile);
			continue;
		}

		if(ai.cert.exp != 0)
			expires := sys->sprint(" expires=%ud", ai.cert.exp);
		ha := ai.cert.ha;
		if(ha == "sha")
			ha = "sha1";

		if(tag != nil)
			tag = " "+tag;

		sys->print("key proto=infauth%s %s sigalg=%s-%s user=%q signer=%q pk=%s !sk=%s spk=%s cert=%s dh-alpha=%s dh-p=%s%s\n",
			tag, locations(filename(keyfile)), ai.cert.sa.name, ha, ai.mypk.owner, ai.spk.owner, pktostr(ai.mypk), sktostr(ai.mysk),
			pktostr(ai.spk), certtostr(ai.cert), ai.alpha.iptostr(16), ai.p.iptostr(16), expires);
	}
}

error(e: string)
{
	sys->fprint(sys->fildes(2), "ai2key: %s\n", e);
	raise "fail:error";
}

filename(s: string): string
{
	(nil, fld) := sys->tokenize(s, "/");
	for(; fld != nil && tl fld != nil; fld = tl fld){
		# skip
	}
	return hd fld;
}

# guess plausible domain, server and service attributes from the file name
locations(file: string): string
{
	if(file == "default")
		return "dom=* server=*";
	(nf, flds) := sys->tokenize(file, "!");
	case nf {
	* =>
		return sys->sprint("%s", server(file));
	2 =>
		return sys->sprint("%s", server(hd tl flds));
	3 =>
		# ignore network component
		return sys->sprint("%s service=%q", server(hd tl flds), hd tl tl flds);
	}
}

server(name: string): string
{
	# if the name contains dot(s), we'll treat it as a domain name
	if(sys->tokenize(name, ".").t0 > 1)
		return sys->sprint("dom=%q server=%q", name, name);
	return sys->sprint("server=%q", name);
}

certtostr(c: ref Certificate): string
{
	return dnl(keyring->certtostr(c));
}

pktostr(pk: ref PK): string
{
	return dnl(keyring->pktostr(pk));
}

sktostr(sk: ref SK): string
{
	return dnl(keyring->sktostr(sk));
}

dnl(s: string): string
{
	for(i := 0; i < len s; i++)
		if(s[i] == '\n')
			s[i] = '^';
	while(--i > 0 && s[i] == '^'){
		# skip
	}
	if(i != len s)
		return s[0: i+1];
	return s;
}