1implement WmLogon; 2# 3# Logon program for Wm environment 4# 5include "sys.m"; 6 sys: Sys; 7 8include "draw.m"; 9 draw: Draw; 10 Screen, Display, Image, Context, Point, Rect: import draw; 11 ctxt: ref Context; 12 13include "tk.m"; 14 tk: Tk; 15 16include "tkclient.m"; 17 tkclient: Tkclient; 18 19include "readdir.m"; 20 21include "arg.m"; 22include "sh.m"; 23include "newns.m"; 24include "keyring.m"; 25include "security.m"; 26 27WmLogon: module 28{ 29 init: fn(ctxt: ref Draw->Context, argv: list of string); 30}; 31 32cfg := array[] of { 33 "label .p -bitmap @/icons/inferno.bit -borderwidth 2 -relief raised", 34 "frame .l -bg red", 35 "label .l.u -fg black -bg silver -text {User Name:} -anchor w", 36 "pack .l.u -fill x", 37 "frame .e", 38 "entry .e.u -bg white", 39 "pack .e.u -fill x", 40 "frame .f -borderwidth 2 -relief raised", 41 "pack .l .e -side left -in .f", 42 "pack .p .f -fill x", 43 "bind .e.u <Key-\n> {send cmd ok}", 44 "focus .e.u" 45}; 46 47listcfg := array[] of { 48 "frame .f", 49 "listbox .f.lb -yscrollcommand {.f.sb set}", 50 "scrollbar .f.sb -orient vertical -command {.f.lb yview}", 51 "button .login -text {Login} -command {send cmd login}", 52 "pack .f.sb .f.lb -in .f -side left -fill both -expand 1", 53 "pack .f -side top -anchor center -fill y -expand 1", 54 "pack .login -side top", 55# "pack propagate . 0", 56}; 57 58init(actxt: ref Draw->Context, args: list of string) 59{ 60 sys = load Sys Sys->PATH; 61 draw = load Draw Draw->PATH; 62 tk = load Tk Tk->PATH; 63 tkclient = load Tkclient Tkclient->PATH; 64 if(tkclient == nil){ 65 sys->fprint(stderr(), "logon: cannot load %s: %r\n", Tkclient->PATH); 66 raise "fail:bad module"; 67 } 68 sys->pctl(Sys->NEWPGRP|Sys->FORKFD, nil); 69 tkclient->init(); 70 ctxt = actxt; 71 72 dolist := 0; 73 usr := ""; 74 nsfile := "namespace"; 75 arg := load Arg Arg->PATH; 76 if(arg != nil){ 77 arg->init(args); 78 arg->setusage("logon [-l] [-n namespace] [-u user]"); 79 while((opt := arg->opt()) != 0){ 80 case opt{ 81 'u' => 82 usr = arg->earg(); 83 'l' => 84 dolist = 1; 85 'n' => 86 nsfile = arg->earg(); 87 * => 88 arg->usage(); 89 } 90 } 91 args = arg->argv(); 92 arg = nil; 93 } else 94 args = nil; 95 if(ctxt == nil) 96 sys->fprint(stderr(), "logon: must run under a window manager\n"); 97 98 (ctlwin, nil) := tkclient->toplevel(ctxt, nil, nil, Tkclient->Plain); 99 if(sys->fprint(ctlwin.ctxt.connfd, "request") == -1){ 100 sys->fprint(stderr(), "logon: must be run as principal wm application\n"); 101 raise "fail:lack of control"; 102 } 103 104 if(dolist) 105 usr = chooseuser(ctxt); 106 107 if (usr == nil || !logon(usr)) { 108 (panel, cmd) := makepanel(ctxt, cfg); 109 stop := chan of int; 110 spawn tkclient->handler(panel, stop); 111 for(;;) { 112 tk->cmd(panel, "focus .e.u; update"); 113 <-cmd; 114 usr = tk->cmd(panel, ".e.u get"); 115 if(usr == "") { 116 notice("You must supply a user name to login"); 117 continue; 118 } 119 if(logon(usr)) { 120 panel = nil; 121 stop <-= 1; 122 break; 123 } 124 tk->cmd(panel, ".e.u delete 0 end"); 125 } 126 } 127 ok: int; 128 if(nsfile != nil){ 129 (ok, nil) = sys->stat(nsfile); 130 if(ok < 0){ 131 nsfile = nil; 132 (ok, nil) = sys->stat("namespace"); 133 } 134 }else 135 (ok, nil) = sys->stat("namespace"); 136 if(ok >= 0) { 137 ns := load Newns Newns->PATH; 138 if(ns == nil) 139 notice("failed to load namespace builder"); 140 else if ((nserr := ns->newns(nil, nsfile)) != nil) 141 notice("namespace error:\n"+nserr); 142 } 143 tkclient->wmctl(ctlwin, "endcontrol"); 144 errch := chan of string; 145 spawn exec(ctxt, args, errch); 146 err := <-errch; 147 if (err != nil) { 148 sys->fprint(stderr(), "logon: %s\n", err); 149 raise "fail:exec failed"; 150 } 151} 152 153makepanel(ctxt: ref Draw->Context, cmds: array of string): (ref Tk->Toplevel, chan of string) 154{ 155 (t, nil) := tkclient->toplevel(ctxt, "-bg silver", nil, Tkclient->Plain); 156 157 cmd := chan of string; 158 tk->namechan(t, cmd, "cmd"); 159 160 for(i := 0; i < len cmds; i++) 161 tk->cmd(t, cmds[i]); 162 err := tk->cmd(t, "variable lasterr"); 163 if(err != nil) { 164 sys->fprint(stderr(), "logon: tk error: %s\n", err); 165 raise "fail:config error"; 166 } 167 tk->cmd(t, "update"); 168 centre(t); 169 tkclient->startinput(t, "kbd" :: "ptr" :: nil); 170 tkclient->onscreen(t, "onscreen"); 171 return (t, cmd); 172} 173 174exec(ctxt: ref Draw->Context, argv: list of string, errch: chan of string) 175{ 176 sys->pctl(sys->NEWFD, 0 :: 1 :: 2 :: nil); 177 { 178 argv = "/dis/wm/toolbar.dis" :: nil; 179 cmd := load Command hd argv; 180 if (cmd == nil) { 181 errch <-= sys->sprint("cannot load %s: %r", hd argv); 182 } else { 183 errch <-= nil; 184 spawn cmd->init(ctxt, argv); 185 } 186 }exception{ 187 "fail:*" => 188 exit; 189 } 190} 191 192logon(user: string): int 193{ 194 userdir := "/usr/"+user; 195 if(sys->chdir(userdir) < 0) { 196 notice("There is no home directory for \""+ 197 user+"\"\nmounted on this machine"); 198 return 0; 199 } 200 201 chmod("/chan", Sys->DMDIR|8r777); 202 chmod("/chan/wmrect", 8r666); 203 chmod("/chan/wmctl", 8r666); 204 205 # 206 # Set the user id 207 # 208 fd := sys->open("/dev/user", sys->OWRITE); 209 if(fd == nil) { 210 notice(sys->sprint("failed to open /dev/user: %r")); 211 return 0; 212 } 213 b := array of byte user; 214 if(sys->write(fd, b, len b) < 0) { 215 notice("failed to write /dev/user\nwith error "+sys->sprint("%r")); 216 return 0; 217 } 218 219 return 1; 220} 221 222chmod(file: string, mode: int): int 223{ 224 d := sys->nulldir; 225 d.mode = mode; 226 if(sys->wstat(file, d) < 0){ 227 notice(sys->sprint("failed to chmod %s: %r", file)); 228 return -1; 229 } 230 return 0; 231} 232 233chooseuser(ctxt: ref Draw->Context): string 234{ 235 (t, cmd) := makepanel(ctxt, listcfg); 236 usrlist := getusers(); 237 if(usrlist == nil) 238 usrlist = "inferno" :: nil; 239 for(; usrlist != nil; usrlist = tl usrlist) 240 tkcmd(t, ".f.lb insert end '" + hd usrlist); 241 tkcmd(t, "update"); 242 stop := chan of int; 243 spawn tkclient->handler(t, stop); 244 u := ""; 245 for(;;){ 246 <-cmd; 247 sel := tkcmd(t, ".f.lb curselection"); 248 if(sel == nil) 249 continue; 250 u = tkcmd(t, ".f.lb get " + sel); 251 if(u != nil) 252 break; 253 } 254 stop <-= 1; 255 return u; 256} 257 258getusers(): list of string 259{ 260 readdir := load Readdir Readdir->PATH; 261 if(readdir == nil) 262 return nil; 263 (dirs, nil) := readdir->init("/usr", Readdir->NAME); 264 n: list of string; 265 for (i := len dirs -1; i >=0; i--) 266 if (dirs[i].qid.qtype & Sys->QTDIR) 267 n = dirs[i].name :: n; 268 return n; 269} 270 271notecmd := array[] of { 272 "frame .f", 273 "label .f.l -bitmap error -foreground red", 274 "button .b -text Continue -command {send cmd done}", 275 "focus .f", 276 "bind .f <Key-\n> {send cmd done}", 277 "pack .f.l .f.m -side left -expand 1", 278 "pack .f .b", 279 "pack propagate . 0", 280}; 281 282centre(t: ref Tk->Toplevel) 283{ 284 org: Point; 285 ir := tk->rect(t, ".", Tk->Border|Tk->Required); 286 org.x = t.screenr.dx() / 2 - ir.dx() / 2; 287 org.y = t.screenr.dy() / 3 - ir.dy() / 2; 288#sys->print("ir: %d %d %d %d\n", ir.min.x, ir.min.y, ir.max.x, ir.max.y); 289 if (org.y < 0) 290 org.y = 0; 291 tk->cmd(t, ". configure -x " + string org.x + " -y " + string org.y); 292} 293 294notice(message: string) 295{ 296 (t, nil) := tkclient->toplevel(ctxt, "-borderwidth 2 -relief raised", nil, Tkclient->Plain); 297 cmd := chan of string; 298 tk->namechan(t, cmd, "cmd"); 299 tk->cmd(t, "label .f.m -anchor nw -text '"+message); 300 for(i := 0; i < len notecmd; i++) 301 tk->cmd(t, notecmd[i]); 302 centre(t); 303 tkclient->onscreen(t, "onscreen"); 304 tkclient->startinput(t, "kbd"::"ptr"::nil); 305 stop := chan of int; 306 spawn tkclient->handler(t, stop); 307 tk->cmd(t, "update; cursor -default"); 308 <-cmd; 309 stop <-= 1; 310} 311 312tkcmd(t: ref Tk->Toplevel, cmd: string): string 313{ 314 s := tk->cmd(t, cmd); 315 if (s != nil && s[0] == '!') { 316 sys->print("%s\n", cmd); 317 sys->print("tk error: %s\n", s); 318 } 319 return s; 320} 321 322stderr(): ref Sys->FD 323{ 324 return sys->fildes(2); 325} 326 327rf(path: string) : string 328{ 329 fd := sys->open(path, sys->OREAD); 330 if(fd == nil) 331 return nil; 332 333 buf := array[512] of byte; 334 n := sys->read(fd, buf, len buf); 335 if(n <= 0) 336 return nil; 337 338 return string buf[0:n]; 339} 340