shithub: 9ferno

ref: 670f4e90ee6028ffee399e5a96fb5e4cd72fc7bc

View raw version
implement WmGetauthinfo;

include "sys.m";
	sys: Sys;

include "security.m";
	login: Login;

include "draw.m";
	draw: Draw;

include "tk.m";
	tk: Tk;

include "tkclient.m";
	tkclient: Tkclient;

include "dialog.m";
	dialog: Dialog;

include "keyring.m";
	kr: Keyring;

include "string.m";

include "sh.m";

#
# Tk version of getauthinfo command
#
WmGetauthinfo: module 
{
	init: fn(ctxt: ref Draw->Context, argv: list of string);
};

Wm: module
{
	init:	fn(ctxt: ref Draw->Context, argv: list of string);
};

cfg := array[] of {
	"frame .all -borderwidth 2 -relief raised",

	"frame .u",
	"label .u.l -text {User    } -anchor w",
	"entry .u.e",
	"pack .u.l .u.e -side left -in .u -expand 1",
	"bind .u.e <Key-\n> {send cmd u}",
	"focus .u.e",

	"frame .p",
	"label .p.l -text {Password} -anchor w",
	"entry .p.e -show *",
	"pack .p.l .p.e -side left -in .p -expand 1",
	"bind .p.e <Key-\n> {send cmd p}",

	"frame .s",
	"label .s.l -text {Signer  } -anchor w",
	"entry .s.e",
	"pack .s.l .s.e -side left -in .s -expand 1",
	"bind .s.e <Key-\n> {send cmd s}",

	"frame .f",
	"label .f.l -text {Save key} -anchor w",
	"entry .f.e",
	"pack .f.l .f.e -side left -in .f -expand 1",
	"bind .f.e <Key-\n> {send cmd f}",

	"frame .b",
	"radiobutton .b.p -variable save -value p -anchor w -text '" + "Permanent",
	"radiobutton .b.t -variable save -value t -anchor w -text '" + "Temporary",
	"pack .b.p .b.t -side right -in .b -expand 1",
	".b.p invoke",
	"pack .u .p .s .f .b -in .all",
	"pack .Wm_t .all -fill x -expand 1",
	"update"
};

about : con "Generate keys and\n" + 
	    "request certificate for\n" +
	    "mounting remote server";


init(ctxt: ref Draw->Context, nil: list of string)
{
	sys = load Sys Sys->PATH;
	if (ctxt == nil) {
		sys->fprint(sys->fildes(2), "getauthinfo: no window context\n");
		raise "fail:bad context";
	}
	kr = load Keyring Keyring->PATH;
	str := load String String->PATH;

	draw = load Draw Draw->PATH;
	tk = load Tk Tk->PATH;

	tkclient = load Tkclient Tkclient->PATH;
	dialog = load Dialog Dialog->PATH;
	tkclient->init();
	dialog->init();

	(top, wmctl) := tkclient->toplevel(ctxt, "",
		"Obtain Certificate for Server", Tkclient->Help);
	for (c:=0; c<len cfg; c++)
		tk->cmd(top, cfg[c]);
	cmd := chan of string;
	tk->namechan(top, cmd, "cmd");

	login = load Login Login->PATH;
	if(login == nil){
		dialog->prompt(ctxt, top.image, "error -fg red", "Error", 
			"Cannot load " + Login->PATH, 0, "Exit"::nil);
		exit;
	}

	# start interactive
	usr := user();
	passwd := "";
	signer := defaultsigner();
	dir:= "";
	file := "net!";
	path := "";
	tk->cmd(top, ".u.e insert end '" + usr);
	tk->cmd(top, ".s.e insert end '" + signer);
	tk->cmd(top, "update");
	tkclient->onscreen(top, nil);
	tkclient->startinput(top, "kbd"::"ptr"::nil);
	info : ref Keyring->Authinfo;
	for(;;){
		alt {
		s := <-top.ctxt.kbd =>
			tk->keyboard(top, s);
		s := <-top.ctxt.ptr =>
			tk->pointer(top, *s);
		s := <-top.ctxt.ctl or
		s = <-top.wreq =>
			tkclient->wmctl(top, s);
		menu := <-wmctl =>
			case menu {
			"exit" =>
				exit;
			"help" =>
				dialog->prompt(ctxt, top.image, "info -fg green", "About", 
				  about, 0, "OK"::nil);
			}
			tkclient->wmctl(top, menu);
		rdy := <-cmd =>
			case (rdy[0]) {
			'u' =>
				usr = tk->cmd(top, ".u.e get");
				if(usr == "")
					tk->cmd(top, "focus .u.e; update");
				else {
					dir = "/usr/" + usr + "/keyring/";
					path = dir + file;
					tk->cmd(top, ".f.e delete 0 end");
					tk->cmd(top, ".f.e insert end '" + path);
					tk->cmd(top, "focus .p.e; update");
				}
				continue;
			'p' =>
				passwd = tk->cmd(top, ".p.e get");	
				if(passwd == "")
					tk->cmd(top, "focus .p.e; update");
				else
					tk->cmd(top, "focus .s.e; update");
				continue;
			's' =>
				signer = tk->cmd(top, ".s.e get");
				if(signer == "")
					tk->cmd(top, "focus .s.e");
				else {
					file = "net!" + signer;
					path = dir + file;
					tk->cmd(top, ".f.e delete 0 end");
					tk->cmd(top, ".f.e insert end " + path);
					tk->cmd(top, "focus .f.e; update");
				}
				continue;
			'f' =>
				path = tk->cmd(top, ".f.e get");
				if(path == "") {
					tk->cmd(top, "focus .f.e; update");
					continue;
				}

				# start encrypt key exchange
				addr := "net!"+signer+"!inflogin";
				tk->cmd(top, "cursor -bitmap cursor.wait");
				err: string;	
				(err, info) = login->login(usr, passwd, addr);
				tk->cmd(top, "cursor -default");
				if(info == nil){
					dialog->prompt(ctxt, top.image, "warning -fg yellow", "Warning", 
						err, 0, "Continue"::nil);
					tk->cmd(top, ".p.e delete 0 end");
					tk->cmd(top, "focus .p.e");
					continue;
				}

				# save the info for later access
				save := tk->cmd(top, "variable save");
				(dir, file) = str->splitr(path, "/");
				if(save[0] == 't')
					spawn save2file(dir, file);

				tk->cmd(top, "cursor -default");			
				if(kr->writeauthinfo(path, info) < 0){
					dialog->prompt(ctxt, top.image, "error -fg red", "Error", 
						"Can't write to " + path, 0, "Exit"::nil);
					exit;
				}	
				if(save[0] == 'p')
					dialog->prompt(ctxt, top.image, "info -fg green", "Notice", 
						"Authentication information is\nsaved in file:\n" 
						+ path, 0, "OK"::nil);
				else
					dialog->prompt(ctxt, top.image, "info -fg green", "Notice", 
						"Authentication information is\nheld in a temporary file:\n" 
						+ path, 0, "OK"::nil);

				return;

			}
		}
	}
}


user(): string
{
	sys = load Sys Sys->PATH;

	fd := sys->open("/dev/user", sys->OREAD);
	if(fd == nil)
		return "";

	buf := array[Sys->NAMEMAX] of byte;
	n := sys->read(fd, buf, len buf);
	if(n < 0)
		return "";

	return string buf[0:n];	
}

save2file(dir, file: string)
{
	if(sys->bind("#s", dir, Sys->MBEFORE) < 0)
		exit;
	fileio := sys->file2chan(dir, file);
	if(fileio != nil)
		exit;

	sys->pctl(Sys->NEWPGRP, nil);

	infodata := array[0] of byte;

	for(;;) alt {
	(off, nbytes, fid, rc) := <-fileio.read =>
		if(rc == nil)
			break;
		if(off > big len infodata){
			rc <-= (infodata[int off:int off], nil); # TODO potential bug truncating big to int
		} else {
			if(off + big nbytes > big len infodata)
				nbytes = len infodata - int off; # TODO potential bug truncating big to int
			rc <-= (infodata[int off:int off+nbytes], nil); # TODO potential bug truncating big to int
		}

	(off, data, fid, wc) := <-fileio.write =>
		if(wc == nil)
			break;

		if(off != big len infodata){
			wc <-= (0, "cannot be rewritten");
		} else {
			nid := array[len infodata+len data] of byte;
			nid[0:] = infodata;
			nid[len infodata:] = data;
			infodata = nid;
			wc <-= (len data, nil);
		}
		data = nil;
	}
}

# get default signer server name
defaultsigner(): string
{
	return "$SIGNER";
}