diff options
| author | Charles.Forsyth <devnull@localhost> | 2006-12-22 17:07:39 +0000 |
|---|---|---|
| committer | Charles.Forsyth <devnull@localhost> | 2006-12-22 17:07:39 +0000 |
| commit | 37da2899f40661e3e9631e497da8dc59b971cbd0 (patch) | |
| tree | cbc6d4680e347d906f5fa7fca73214418741df72 /appl/cmd/auth/changelogin.b | |
| parent | 54bc8ff236ac10b3eaa928fd6bcfc0cdb2ba46ae (diff) | |
20060303a
Diffstat (limited to 'appl/cmd/auth/changelogin.b')
| -rw-r--r-- | appl/cmd/auth/changelogin.b | 305 |
1 files changed, 305 insertions, 0 deletions
diff --git a/appl/cmd/auth/changelogin.b b/appl/cmd/auth/changelogin.b new file mode 100644 index 00000000..97141408 --- /dev/null +++ b/appl/cmd/auth/changelogin.b @@ -0,0 +1,305 @@ +implement Changelogin; + +include "sys.m"; + sys: Sys; + +include "daytime.m"; + daytime: Daytime; + +include "draw.m"; + +include "keyring.m"; + kr: Keyring; + +Changelogin: module +{ + init: fn(ctxt: ref Draw->Context, argv: list of string); +}; + +stderr, stdin, stdout: ref Sys->FD; +keydb := "/mnt/keys"; + +init(nil: ref Draw->Context, args: list of string) +{ + ok: int; + word: string; + + sys = load Sys Sys->PATH; + kr = load Keyring Keyring->PATH; + + stdin = sys->fildes(0); + stdout = sys->fildes(1); + stderr = sys->fildes(2); + + argv0 := hd args; + args = tl args; + + if(args == nil){ + sys->fprint(stderr, "usage: %s userid\n", argv0); + raise "fail:usage"; + } + + daytime = load Daytime Daytime->PATH; + if(daytime == nil) { + sys->fprint(stderr, "%s: can't load Daytime: %r\n", argv0); + raise "fail:load"; + } + + # get password + id := hd args; + (dbdir, secret, expiry, err) := getuser(id); + if(dbdir == nil){ + if(err != nil){ + sys->fprint(stderr, "%s: can't get auth info for %s in %s: %s\n", argv0, id, keydb, err); + raise "fail:no key"; + } + sys->print("new account\n"); + } + for(;;){ + if(secret != nil) + sys->print("secret [default = don't change]: "); + else + sys->print("secret: "); + (ok, word) = readline(stdin, "rawon"); + if(!ok) + exit; + if(word == "" && secret != nil) + break; + if(len word >= 8) + break; + sys->print("!secret must be at least 8 characters\n"); + } + newsecret: array of byte; + if(word != ""){ + # confirm password change + word1 := word; + sys->print("confirm: "); + (ok, word) = readline(stdin, "rawon"); + if(!ok || word != word1) { + sys->print("Entries do not match. Authinfo record unchanged.\n"); + raise "fail:mismatch"; + } + + pwbuf := array of byte word; + newsecret = array[Keyring->SHA1dlen] of byte; + kr->sha1(pwbuf, len pwbuf, newsecret, nil); + } + + # get expiration time (midnight of date specified) + maxdate := "17012038"; # largest date possible without incurring integer overflow + now := daytime->now(); + tm := daytime->local(now); + tm.sec = 59; + tm.min = 59; + tm.hour = 23; + tm.year += 1; + if(dbdir == nil) + expsecs := daytime->tm2epoch(tm); # set expiration date to 23:59:59 one year from today + else + expsecs = expiry; + for(;;){ + defexpdate := "permanent"; + if(expsecs != 0) { + otm := daytime->local(expsecs); + defexpdate = sys->sprint("%2.2d%2.2d%4.4d", otm.mday, otm.mon+1, otm.year+1900); + } + sys->print("expires [DDMMYYYY/permanent, return = %s]: ", defexpdate); + (ok, word) = readline(stdin, "rawoff"); + if(!ok) + exit; + if(word == "") + word = defexpdate; + if(word == "permanent"){ + expsecs = 0; + break; + } + if(len word != 8){ + sys->print("!bad date format %s\n", word); + continue; + } + tm.mday = int word[0:2]; + if(tm.mday > 31 || tm.mday < 1){ + sys->print("!bad day of month %d\n", tm.mday); + continue; + } + tm.mon = int word[2:4] - 1; + if(tm.mon > 11 || tm.mday < 0){ + sys->print("!bad month %d\n", tm.mon + 1); + continue; + } + tm.year = int word[4:8] - 1900; + if(tm.year < 70){ + sys->print("!bad year %d (year may be no earlier than 1970)\n", tm.year + 1900); + continue; + } + expsecs = daytime->tm2epoch(tm); + if(expsecs > now) + break; + else { + newexpdate := sys->sprint("%2.2d%2.2d%4.4d", tm.mday, tm.mon+1, tm.year+1900); + tm = daytime->local(daytime->now()); + today := sys->sprint("%2.2d%2.2d%4.4d", tm.mday, tm.mon+1, tm.year+1900); + sys->print("!bad expiration date %s (must be between %s and %s)\n", newexpdate, today, maxdate); + expsecs = now; + } + } + newexpiry := expsecs; + +# # get the free form field +# if(pw != nil) +# npw.other = pw.other; +# else +# npw.other = ""; +# sys->print("free form info [return = %s]: ", npw.other); +# (ok, word) = readline(stdin,"rawoff"); +# if(!ok) +# exit; +# if(word != "") +# npw.other = word; + + if(dbdir == nil){ + dbdir = keydb+"/"+id; + fd := sys->create(dbdir, Sys->OREAD, Sys->DMDIR|8r700); + if(fd == nil){ + sys->fprint(stderr, "%s: can't create account %s: %r\n", argv0, id); + raise "fail:create user"; + } + } + changed := 0; + if(!eq(newsecret, secret)){ + if(putsecret(dbdir, newsecret) < 0){ + sys->fprint(stderr, "%s: can't update secret for %s: %r\n", argv0, id); + raise "fail:update"; + } + changed = 1; + } + if(newexpiry != expiry){ + if(putexpiry(dbdir, newexpiry) < 0){ + sys->fprint(stderr, "%s: can't update expiry time for %s: %r\n", argv0, id); + raise "fail:update"; + } + changed = 1; + } + sys->print("change written\n"); +} + +getuser(id: string): (string, array of byte, int, string) +{ + (ok, nil) := sys->stat(keydb); + if(ok < 0) + return (nil, nil, 0, sys->sprint("can't stat %s: %r", id)); + dbdir := keydb+"/"+id; + (ok, nil) = sys->stat(dbdir); + if(ok < 0) + return (nil, nil, 0, nil); + fd := sys->open(dbdir+"/secret", Sys->OREAD); + if(fd == nil) + return (nil, nil, 0, sys->sprint("can't open %s/secret: %r", id)); + d: Sys->Dir; + (ok, d) = sys->fstat(fd); + if(ok < 0) + return (nil, nil, 0, sys->sprint("can't stat %s/secret: %r", id)); + l := int d.length; + secret: array of byte; + if(l > 0){ + secret = array[l] of byte; + if(sys->read(fd, secret, len secret) != len secret) + return (nil, nil, 0, sys->sprint("error reading %s/secret: %r", id)); + } + expiry := 0; + fd = sys->open(dbdir+"/expire", Sys->OREAD); + if(fd == nil) + return (nil, nil, 0, sys->sprint("can't open %s/expiry: %r", id)); + b := array[32] of byte; + n := sys->read(fd, b, len b); + if(n <= 0) + return (nil, nil, 0, sys->sprint("error reading %s/expiry: %r", id)); + return (dbdir, secret, int string b[0:n], nil); +} + +eq(a, b: array of byte): int +{ + if(len a != len b) + return 0; + for(i := 0; i < len a; i++) + if(a[i] != b[i]) + return 0; + return 1; +} + +putsecret(dir: string, secret: array of byte): int +{ + fd := sys->create(dir+"/secret", Sys->OWRITE, 8r600); + if(fd == nil) + return -1; + return sys->write(fd, secret, len secret); +} + +putexpiry(dir: string, expiry: int): int +{ + fd := sys->open(dir+"/expire", Sys->OWRITE); + if(fd == nil) + return -1; + return sys->fprint(fd, "%d", expiry); +} + +readline(io: ref Sys->FD, mode: string): (int, string) +{ + r : int; + line : string; + buf := array[8192] of byte; + fdctl : ref Sys->FD; + rawoff := array of byte "rawoff"; + + # + # Change console mode to rawon + # + if(mode == "rawon"){ + fdctl = sys->open("/dev/consctl", sys->OWRITE); + if(fdctl == nil || sys->write(fdctl,array of byte mode,len mode) != len mode){ + sys->fprint(stderr, "unable to change console mode"); + return (0,nil); + } + } + + # + # Read up to the CRLF + # + line = ""; + for(;;) { + r = sys->read(io, buf, len buf); + if(r <= 0){ + sys->fprint(stderr, "error read from console mode"); + if(mode == "rawon") + sys->write(fdctl,rawoff,6); + return (0, nil); + } + + line += string buf[0:r]; + if ((len line >= 1) && (line[(len line)-1] == '\n')){ + if(mode == "rawon"){ + r = sys->write(stdout,array of byte "\n",1); + if(r <= 0) { + sys->write(fdctl,rawoff,6); + return (0, nil); + } + } + break; + } + else { + if(mode == "rawon"){ + #r = sys->write(stdout, array of byte "*",1); + if(r <= 0) { + sys->write(fdctl,rawoff,6); + return (0, nil); + } + } + } + } + + if(mode == "rawon") + sys->write(fdctl,rawoff,6); + + # Total success! + return (1, line[0:len line - 1]); +} |
