Subversion Repositories planix.SVN

Rev

Blame | Last modification | View Log | RSS feed

/*
 * Test various aspects of the authentication setup.
 */

#include <u.h>
#include <libc.h>
#include <bio.h>
#include <ndb.h>
#include <auth.h>
#include <authsrv.h>

/* private copy with added debugging */
int
authdial(char *netroot, char *dom)
{
        char *p;
        int rv;
        
        if(dom != nil){
                /* look up an auth server in an authentication domain */
                p = csgetvalue(netroot, "authdom", dom, "auth", nil);

                /* if that didn't work, just try the IP domain */
                if(p == nil)
                        p = csgetvalue(netroot, "dom", dom, "auth", nil);
                if(p == nil){
                        werrstr("no auth server found for %s", dom);
                        return -1;
                }
                print("\tdialing auth server %s\n",
                        netmkaddr(p, netroot, "ticket"));
                rv = dial(netmkaddr(p, netroot, "ticket"), 0, 0, 0);
                free(p);
                return rv;
        } else
                /* look for one relative to my machine */
                return dial(netmkaddr("$auth", netroot, "ticket"), 0, 0, 0);
}

void
usage(void)
{
        fprint(2, "usage: auth/debug\n");
        exits("usage");
}

static char*
readcons(char *prompt, char *def, int raw, char *buf, int nbuf)
{
        int fdin, fdout, ctl, n, m;
        char line[10];

        fdin = open("/dev/cons", OREAD);
        if(fdin < 0)
                fdin = 0;
        fdout = open("/dev/cons", OWRITE);
        if(fdout < 0)
                fdout = 1;
        if(def != nil)
                fprint(fdout, "%s[%s]: ", prompt, def);
        else
                fprint(fdout, "%s: ", prompt);
        if(raw){
                ctl = open("/dev/consctl", OWRITE);
                if(ctl >= 0)
                        write(ctl, "rawon", 5);
        } else
                ctl = -1;

        m = 0;
        for(;;){
                n = read(fdin, line, 1);
                if(n == 0){
                        close(ctl);
                        werrstr("readcons: EOF");
                        return nil;
                }
                if(n < 0){
                        close(ctl);
                        werrstr("can't read cons");
                        return nil;
                }
                if(line[0] == 0x7f)
                        exits(0);
                if(n == 0 || line[0] == '\n' || line[0] == '\r'){
                        if(raw){
                                write(ctl, "rawoff", 6);
                                write(fdout, "\n", 1);
                                close(ctl);
                        }
                        buf[m] = '\0';
                        if(buf[0]=='\0' && def)
                                strcpy(buf, def);
                        return buf;
                }
                if(line[0] == '\b'){
                        if(m > 0)
                                m--;
                }else if(line[0] == 0x15){      /* ^U: line kill */
                        m = 0;
                        if(def != nil)
                                fprint(fdout, "%s[%s]: ", prompt, def);
                        else
                                fprint(fdout, "%s: ", prompt);
                }else{
                        if(m >= nbuf-1){
                                fprint(fdout, "line too long\n");
                                m = 0;
                                if(def != nil)
                                        fprint(fdout, "%s[%s]: ", prompt, def);
                                else
                                        fprint(fdout, "%s: ", prompt);
                        }else
                                buf[m++] = line[0];
                }
        }
}

void authdialfutz(char*, char*);
void authfutz(char*, char*);

/* scan factotum for p9sk1 keys; check them */
void
debugfactotumkeys(void)
{
        char *s, *dom, *proto, *user;
        int found;
        Attr *a;
        Biobuf *b;

        b = Bopen("/mnt/factotum/ctl", OREAD);
        if(b == nil){
                fprint(2, "debug: cannot open /mnt/factotum/ctl\n");
                return;
        }
        found = 0;
        while((s = Brdstr(b, '\n', 1)) != nil){
                if(strncmp(s, "key ", 4) != 0){
                        print("malformed ctl line: %s\n", s);
                        free(s);
                        continue;
                }
                a = _parseattr(s+4);
                free(s);
                proto = _strfindattr(a, "proto");
                if(proto==nil || strcmp(proto, "p9sk1")!=0)
                        continue;
                dom = _strfindattr(a, "dom");
                if(dom == nil){
                        print("p9sk1 key with no dom: %A\n", a);
                        _freeattr(a);
                        continue;
                }
                user = _strfindattr(a, "user");
                if(user == nil){
                        print("p9sk1 key with no user: %A\n", a);
                        _freeattr(a);
                        continue;
                }
                print("p9sk1 key: %A\n", a);
                found = 1;
                authdialfutz(dom, user);
                _freeattr(a);
        }
        if(!found)
                print("no p9sk1 keys found in factotum\n");
}

void
authdialfutz(char *dom, char *user)
{
        int fd;
        char *server;
        char *addr;

        fd = authdial(nil, dom);
        if(fd >= 0){
                print("\tsuccessfully dialed auth server\n");
                close(fd);
                authfutz(dom, user);
                return;
        }
        print("\tcannot dial auth server: %r\n");
        server = csgetvalue(nil, "authdom", dom, "auth", nil);
        if(server){
                print("\tcsquery authdom=%q auth=%s\n", dom, server);
                free(server);
                return;
        }
        print("\tcsquery authdom=%q auth=* failed\n", dom);
        server = csgetvalue(nil, "dom", dom, "auth", nil);
        if(server){
                print("\tcsquery dom=%q auth=%q\n", dom, server);
                free(server);
                return;
        }
        print("\tcsquery dom=%q auth=*\n", dom);

        fd = dial(addr=netmkaddr("$auth", nil, "ticket"), 0, 0, 0);
        if(fd >= 0){
                print("\tdial %s succeeded\n", addr);
                close(fd);
                return;
        }
        print("\tdial %s failed: %r\n", addr);
}

void
authfutz(char *dom, char *user)
{
        int fd, nobootes;
        char pw[128], prompt[128], key[DESKEYLEN], booteskey[DESKEYLEN], tbuf[2*TICKETLEN],
                trbuf[TICKREQLEN];
        Ticket t;
        Ticketreq tr;

        snprint(prompt, sizeof prompt, "\tpassword for %s@%s [hit enter to skip test]", user, dom);
        readcons(prompt, nil, 1, pw, sizeof pw);
        if(pw[0] == '\0')
                return;
        passtokey(key, pw);

        fd = authdial(nil, dom);
        if(fd < 0){
                print("\tauthdial failed(!): %r\n");
                return;
        }

        /* try ticket request using just user key */
        tr.type = AuthTreq;
        strecpy(tr.authid, tr.authid+sizeof tr.authid, user);
        strecpy(tr.authdom, tr.authdom+sizeof tr.authdom, dom);
        strecpy(tr.hostid, tr.hostid+sizeof tr.hostid, user);
        strecpy(tr.uid, tr.uid+sizeof tr.uid, user);
        memset(tr.chal, 0xAA, sizeof tr.chal);
        convTR2M(&tr, trbuf);
        if(_asgetticket(fd, trbuf, tbuf) < 0){
                close(fd);
                print("\t_asgetticket failed: %r\n");
                return;
        }
        convM2T(tbuf, &t, key);
        if(t.num != AuthTc){
                print("\tcannot decrypt ticket1 from auth server (bad t.num=0x%.2ux)\n", t.num);
                print("\tauth server and you do not agree on key for %s@%s\n", user, dom);
                return;
        }
        if(memcmp(t.chal, tr.chal, sizeof tr.chal) != 0){
                print("\tbad challenge1 from auth server got %.*H wanted %.*H\n",
                        sizeof t.chal, t.chal, sizeof tr.chal, tr.chal);
                print("\tauth server is rogue\n");
                return;
        }

        convM2T(tbuf+TICKETLEN, &t, key);
        if(t.num != AuthTs){
                print("\tcannot decrypt ticket2 from auth server (bad t.num=0x%.2ux)\n", t.num);
                print("\tauth server and you do not agree on key for %s@%s\n", user, dom);
                return;
        }
        if(memcmp(t.chal, tr.chal, sizeof tr.chal) != 0){
                print("\tbad challenge2 from auth server got %.*H wanted %.*H\n",
                        sizeof t.chal, t.chal, sizeof tr.chal, tr.chal);
                print("\tauth server is rogue\n");
                return;
        }
        print("\tticket request using %s@%s key succeeded\n", user, dom);

        /* try ticket request using bootes key */
        snprint(prompt, sizeof prompt, "\tcpu server owner for domain %s ", dom);
        readcons(prompt, "bootes", 0, tr.authid, sizeof tr.authid);
        convTR2M(&tr, trbuf);
        if(_asgetticket(fd, trbuf, tbuf) < 0){
                close(fd);
                print("\t_asgetticket failed: %r\n");
                return;
        }
        convM2T(tbuf, &t, key);
        if(t.num != AuthTc){
                print("\tcannot decrypt ticket1 from auth server (bad t.num=0x%.2ux)\n", t.num);
                print("\tauth server and you do not agree on key for %s@%s\n", user, dom);
                return;
        }
        if(memcmp(t.chal, tr.chal, sizeof tr.chal) != 0){
                print("\tbad challenge1 from auth server got %.*H wanted %.*H\n",
                        sizeof t.chal, t.chal, sizeof tr.chal, tr.chal);
                print("\tauth server is rogue\n");
                return;
        }

        snprint(prompt, sizeof prompt, "\tpassword for %s@%s [hit enter to skip test]", tr.authid, dom);
        readcons(prompt, nil, 1, pw, sizeof pw);
        if(pw[0] == '\0'){
                nobootes=1;
                goto Nobootes;
        }
        nobootes = 0;
        passtokey(booteskey, pw);

        convM2T(tbuf+TICKETLEN, &t, booteskey);
        if(t.num != AuthTs){
                print("\tcannot decrypt ticket2 from auth server (bad t.num=0x%.2ux)\n", t.num);
                print("\tauth server and you do not agree on key for %s@%s\n", tr.authid, dom);
                return;
        }
        if(memcmp(t.chal, tr.chal, sizeof tr.chal) != 0){
                print("\tbad challenge2 from auth server got %.*H wanted %.*H\n",
                        sizeof t.chal, t.chal, sizeof tr.chal, tr.chal);
                print("\tauth server is rogue\n");
                return;
        }
        print("\tticket request using %s@%s key succeeded\n", tr.authid, dom);

Nobootes:;
        USED(nobootes);

        /* try p9sk1 exchange with local factotum to test that key is right */


        /*
         * try p9sk1 exchange with factotum on
         * auth server (assumes running cpu service)
         * to test that bootes key is right over there
         */

}

void
main(int argc, char **argv)
{
        quotefmtinstall();
        fmtinstall('A', _attrfmt);
        fmtinstall('H', encodefmt);

        ARGBEGIN{
        default:
                usage();
        }ARGEND

        if(argc != 0)
                usage();

        debugfactotumkeys();
}