summaryrefslogtreecommitdiff
path: root/appl/wm/logon.b
diff options
context:
space:
mode:
Diffstat (limited to 'appl/wm/logon.b')
-rw-r--r--appl/wm/logon.b339
1 files changed, 339 insertions, 0 deletions
diff --git a/appl/wm/logon.b b/appl/wm/logon.b
new file mode 100644
index 00000000..00643e87
--- /dev/null
+++ b/appl/wm/logon.b
@@ -0,0 +1,339 @@
+implement WmLogon;
+#
+# Logon program for Wm environment
+#
+include "sys.m";
+ sys: Sys;
+
+include "draw.m";
+ draw: Draw;
+ Screen, Display, Image, Context, Point, Rect: import draw;
+ ctxt: ref Context;
+
+include "tk.m";
+ tk: Tk;
+
+include "tkclient.m";
+ tkclient: Tkclient;
+
+include "readdir.m";
+
+include "arg.m";
+include "sh.m";
+include "newns.m";
+include "keyring.m";
+include "security.m";
+
+WmLogon: module
+{
+ init: fn(ctxt: ref Draw->Context, argv: list of string);
+};
+
+cfg := array[] of {
+ "label .p -bitmap @/icons/inferno.bit -borderwidth 2 -relief raised",
+ "frame .l -bg red",
+ "label .l.u -fg black -bg silver -text {User Name:} -anchor w",
+ "pack .l.u -fill x",
+ "frame .e",
+ "entry .e.u -bg white",
+ "pack .e.u -fill x",
+ "frame .f -borderwidth 2 -relief raised",
+ "pack .l .e -side left -in .f",
+ "pack .p .f -fill x",
+ "bind .e.u <Key-\n> {send cmd ok}",
+ "focus .e.u"
+};
+
+listcfg := array[] of {
+ "frame .f",
+ "listbox .f.lb -yscrollcommand {.f.sb set}",
+ "scrollbar .f.sb -orient vertical -command {.f.lb yview}",
+ "button .login -text {Login} -command {send cmd login}",
+ "pack .f.sb .f.lb -in .f -side left -fill both -expand 1",
+ "pack .f -side top -anchor center -fill y -expand 1",
+ "pack .login -side top",
+# "pack propagate . 0",
+};
+
+init(actxt: ref Draw->Context, args: list of string)
+{
+ sys = load Sys Sys->PATH;
+ draw = load Draw Draw->PATH;
+ tk = load Tk Tk->PATH;
+ tkclient = load Tkclient Tkclient->PATH;
+ if(tkclient == nil){
+ sys->fprint(stderr(), "logon: cannot load %s: %r\n", Tkclient->PATH);
+ raise "fail:bad module";
+ }
+ sys->pctl(Sys->NEWPGRP|Sys->FORKFD, nil);
+ tkclient->init();
+ ctxt = actxt;
+
+ dolist := 0;
+ usr := "";
+ nsfile := "namespace";
+ arg := load Arg Arg->PATH;
+ if(arg != nil){
+ arg->init(args);
+ arg->setusage("logon [-l] [-n namespace] [-u user]");
+ while((opt := arg->opt()) != 0){
+ case opt{
+ 'u' =>
+ usr = arg->earg();
+ 'l' =>
+ dolist = 1;
+ 'n' =>
+ nsfile = arg->earg();
+ * =>
+ arg->usage();
+ }
+ }
+ args = arg->argv();
+ arg = nil;
+ } else
+ args = nil;
+ if(ctxt == nil)
+ sys->fprint(stderr(), "logon: must run under a window manager\n");
+
+ (ctlwin, nil) := tkclient->toplevel(ctxt, nil, nil, Tkclient->Plain);
+ if(sys->fprint(ctlwin.ctxt.connfd, "request") == -1){
+ sys->fprint(stderr(), "logon: must be run as principal wm application\n");
+ raise "fail:lack of control";
+ }
+
+ if(dolist)
+ usr = chooseuser(ctxt);
+
+ if (usr == nil || !logon(usr)) {
+ (panel, cmd) := makepanel(ctxt, cfg);
+ stop := chan of int;
+ spawn tkclient->handler(panel, stop);
+ for(;;) {
+ tk->cmd(panel, "focus .e.u; update");
+ <-cmd;
+ usr = tk->cmd(panel, ".e.u get");
+ if(usr == "") {
+ notice("You must supply a user name to login");
+ continue;
+ }
+ if(logon(usr)) {
+ panel = nil;
+ stop <-= 1;
+ break;
+ }
+ tk->cmd(panel, ".e.u delete 0 end");
+ }
+ }
+ ok: int;
+ if(nsfile != nil){
+ (ok, nil) = sys->stat(nsfile);
+ if(ok < 0){
+ nsfile = nil;
+ (ok, nil) = sys->stat("namespace");
+ }
+ }else
+ (ok, nil) = sys->stat("namespace");
+ if(ok >= 0) {
+ ns := load Newns Newns->PATH;
+ if(ns == nil)
+ notice("failed to load namespace builder");
+ else if ((nserr := ns->newns(nil, nsfile)) != nil)
+ notice("namespace error:\n"+nserr);
+ }
+ tkclient->wmctl(ctlwin, "endcontrol");
+ errch := chan of string;
+ spawn exec(ctxt, args, errch);
+ err := <-errch;
+ if (err != nil) {
+ sys->fprint(stderr(), "logon: %s\n", err);
+ raise "fail:exec failed";
+ }
+}
+
+makepanel(ctxt: ref Draw->Context, cmds: array of string): (ref Tk->Toplevel, chan of string)
+{
+ (t, nil) := tkclient->toplevel(ctxt, "-bg silver", nil, Tkclient->Plain);
+
+ cmd := chan of string;
+ tk->namechan(t, cmd, "cmd");
+
+ for(i := 0; i < len cmds; i++)
+ tk->cmd(t, cmds[i]);
+ err := tk->cmd(t, "variable lasterr");
+ if(err != nil) {
+ sys->fprint(stderr(), "logon: tk error: %s\n", err);
+ raise "fail:config error";
+ }
+ tk->cmd(t, "update");
+ centre(t);
+ tkclient->startinput(t, "kbd" :: "ptr" :: nil);
+ tkclient->onscreen(t, "onscreen");
+ return (t, cmd);
+}
+
+exec(ctxt: ref Draw->Context, argv: list of string, errch: chan of string)
+{
+ sys->pctl(sys->NEWFD, 0 :: 1 :: 2 :: nil);
+ {
+ argv = "/dis/wm/toolbar.dis" :: nil;
+ cmd := load Command hd argv;
+ if (cmd == nil) {
+ errch <-= sys->sprint("cannot load %s: %r", hd argv);
+ } else {
+ errch <-= nil;
+ spawn cmd->init(ctxt, argv);
+ }
+ }exception{
+ "fail:*" =>
+ exit;
+ }
+}
+
+logon(user: string): int
+{
+ userdir := "/usr/"+user;
+ if(sys->chdir(userdir) < 0) {
+ notice("There is no home directory for \""+
+ user+"\"\nmounted on this machine");
+ return 0;
+ }
+
+ chmod("/chan", Sys->DMDIR|8r777);
+ chmod("/chan/wmrect", 8r666);
+ chmod("/chan/wmctl", 8r666);
+
+ #
+ # Set the user id
+ #
+ fd := sys->open("/dev/user", sys->OWRITE);
+ if(fd == nil) {
+ notice(sys->sprint("failed to open /dev/user: %r"));
+ return 0;
+ }
+ b := array of byte user;
+ if(sys->write(fd, b, len b) < 0) {
+ notice("failed to write /dev/user\nwith error "+sys->sprint("%r"));
+ return 0;
+ }
+
+ return 1;
+}
+
+chmod(file: string, mode: int): int
+{
+ d := sys->nulldir;
+ d.mode = mode;
+ if(sys->wstat(file, d) < 0){
+ notice(sys->sprint("failed to chmod %s: %r", file));
+ return -1;
+ }
+ return 0;
+}
+
+chooseuser(ctxt: ref Draw->Context): string
+{
+ (t, cmd) := makepanel(ctxt, listcfg);
+ usrlist := getusers();
+ if(usrlist == nil)
+ usrlist = "inferno" :: nil;
+ for(; usrlist != nil; usrlist = tl usrlist)
+ tkcmd(t, ".f.lb insert end '" + hd usrlist);
+ tkcmd(t, "update");
+ stop := chan of int;
+ spawn tkclient->handler(t, stop);
+ u := "";
+ for(;;){
+ <-cmd;
+ sel := tkcmd(t, ".f.lb curselection");
+ if(sel == nil)
+ continue;
+ u = tkcmd(t, ".f.lb get " + sel);
+ if(u != nil)
+ break;
+ }
+ stop <-= 1;
+ return u;
+}
+
+getusers(): list of string
+{
+ readdir := load Readdir Readdir->PATH;
+ if(readdir == nil)
+ return nil;
+ (dirs, nil) := readdir->init("/usr", Readdir->NAME);
+ n: list of string;
+ for (i := len dirs -1; i >=0; i--)
+ if (dirs[i].qid.qtype & Sys->QTDIR)
+ n = dirs[i].name :: n;
+ return n;
+}
+
+notecmd := array[] of {
+ "frame .f",
+ "label .f.l -bitmap error -foreground red",
+ "button .b -text Continue -command {send cmd done}",
+ "focus .f",
+ "bind .f <Key-\n> {send cmd done}",
+ "pack .f.l .f.m -side left -expand 1",
+ "pack .f .b",
+ "pack propagate . 0",
+};
+
+centre(t: ref Tk->Toplevel)
+{
+ org: Point;
+ ir := tk->rect(t, ".", Tk->Border|Tk->Required);
+ org.x = t.screenr.dx() / 2 - ir.dx() / 2;
+ org.y = t.screenr.dy() / 3 - ir.dy() / 2;
+#sys->print("ir: %d %d %d %d\n", ir.min.x, ir.min.y, ir.max.x, ir.max.y);
+ if (org.y < 0)
+ org.y = 0;
+ tk->cmd(t, ". configure -x " + string org.x + " -y " + string org.y);
+}
+
+notice(message: string)
+{
+ (t, nil) := tkclient->toplevel(ctxt, "-borderwidth 2 -relief raised", nil, Tkclient->Plain);
+ cmd := chan of string;
+ tk->namechan(t, cmd, "cmd");
+ tk->cmd(t, "label .f.m -anchor nw -text '"+message);
+ for(i := 0; i < len notecmd; i++)
+ tk->cmd(t, notecmd[i]);
+ centre(t);
+ tkclient->onscreen(t, "onscreen");
+ tkclient->startinput(t, "kbd"::"ptr"::nil);
+ stop := chan of int;
+ spawn tkclient->handler(t, stop);
+ tk->cmd(t, "update; cursor -default");
+ <-cmd;
+ stop <-= 1;
+}
+
+tkcmd(t: ref Tk->Toplevel, cmd: string): string
+{
+ s := tk->cmd(t, cmd);
+ if (s != nil && s[0] == '!') {
+ sys->print("%s\n", cmd);
+ sys->print("tk error: %s\n", s);
+ }
+ return s;
+}
+
+stderr(): ref Sys->FD
+{
+ return sys->fildes(2);
+}
+
+rf(path: string) : string
+{
+ fd := sys->open(path, sys->OREAD);
+ if(fd == nil)
+ return nil;
+
+ buf := array[512] of byte;
+ n := sys->read(fd, buf, len buf);
+ if(n <= 0)
+ return nil;
+
+ return string buf[0:n];
+}