Subversion Repositories planix.SVN

Rev

Rev 2 | Blame | Compare with Previous | Last modification | View Log | RSS feed

#include "ssh.h"
#include <bio.h>
#include <ndb.h>

char Edecode[] = "error decoding input packet";
char Eencode[] = "out of space encoding output packet (BUG)";
char Ehangup[] = "hungup connection";
char Ememory[] = "out of memory";

int debuglevel;
int doabort;

void
error(char *fmt, ...)
{
        va_list arg;
        char buf[2048];

        va_start(arg, fmt);
        vseprint(buf, buf+sizeof(buf), fmt, arg);
        va_end(arg);
        fprint(2, "%s: %s\n", argv0, buf);
        if(doabort)
                abort();
        exits(buf);
}

void
debug(int level, char *fmt, ...)
{
        va_list arg;

        if((level&debuglevel) == 0)
                return;
        va_start(arg, fmt);
        vfprint(2, fmt, arg);
        va_end(arg);
}

void*
emalloc(long n)
{
        void *a;

        a = mallocz(n, 1);
        if(a == nil)
                error(Ememory);
        setmalloctag(a, getcallerpc(&n));
        return a;
}

void*
erealloc(void *v, long n)
{
        v = realloc(v, n);
        if(v == nil)
                error(Ememory);
        setrealloctag(v, getcallerpc(&v));
        return v;
}


static int killpid[32];
static int nkillpid;
void
atexitkiller(void)
{
        int i, pid;

        pid = getpid();
        debug(DBG, "atexitkiller: nkillpid=%d mypid=%d\n", nkillpid, pid);
        for(i=0; i<nkillpid; i++)
                if(pid != killpid[i]){
                        debug(DBG, "killing %d\n", killpid[i]);
                        postnote(PNPROC, killpid[i], "kill");
                }
}
void
atexitkill(int pid)
{
        killpid[nkillpid++] = pid;
}

int
readstrnl(int fd, char *buf, int nbuf)
{
        int i;

        for(i=0; i<nbuf; i++){
                switch(read(fd, buf+i, 1)){
                case -1:
                        return -1;
                case 0:
                        werrstr("unexpected EOF");
                        return -1;
                default:
                        if(buf[i]=='\n'){
                                buf[i] = '\0';
                                return 0;
                        }
                        break;
                }
        }
        werrstr("line too long");
        return -1;
}

void
calcsessid(Conn *c)
{
        int n;
        uchar buf[1024];

        n = mptobe(c->hostkey->n, buf, sizeof buf, nil);
        n += mptobe(c->serverkey->n, buf+n, sizeof buf-n, nil);
        memmove(buf+n, c->cookie, COOKIELEN);
        n += COOKIELEN;
        md5(buf, n, c->sessid, nil);
}

void
sshlog(char *f, ...)
{
        char *s;
        va_list arg;
        Fmt fmt;
        static int pid;

        if(pid == 0)
                pid = getpid();

        va_start(arg, f);
        va_end(arg);

        if(fmtstrinit(&fmt) < 0)
                sysfatal("fmtstrinit: %r");

        fmtprint(&fmt, "[%d] ", pid);
        fmtvprint(&fmt, f, arg);

        s = fmtstrflush(&fmt);
        if(s == nil)
                sysfatal("fmtstrflush: %r");
        syslog(0, "ssh", "%s", s);
        free(s);
}

/*
 * this is far too smart.
 */
static int
pstrcmp(const void *a, const void *b)
{
        return strcmp(*(char**)a, *(char**)b);
}

static char*
trim(char *s)
{
        char *t;
        int i, last, n, nf;
        char **f;
        char *p;

        t = emalloc(strlen(s)+1);
        t[0] = '\0';
        n = 1;
        for(p=s; *p; p++)
                if(*p == ' ')
                        n++;
        f = emalloc((n+1)*sizeof(f[0]));
        nf = tokenize(s, f, n+1);
        qsort(f, nf, sizeof(f[0]), pstrcmp);
        last=-1;
        for(i=0; i<nf; i++){
                if(last==-1 || strcmp(f[last], f[i])!=0){
                        if(last >= 0)
                                strcat(t, ",");
                        strcat(t, f[i]);
                        last = i;
                }
        }
        return t;       
}

static void
usetuple(Conn *c, Ndbtuple *t, int scanentries)
{
        int first;
        Ndbtuple *l, *e;
        char *s;

        first=1;
        s = c->host;
        for(l=t; first||l!=t; l=l->line, first=0){
                if(scanentries){
                        for(e=l; e; e=e->entry){
                                if(strcmp(e->val, c->host) != 0 &&
                                  (strcmp(e->attr, "ip")==0 || strcmp(e->attr, "dom")==0 || strcmp(e->attr, "sys")==0)){
                                        s = smprint("%s %s", s, e->val);
                                        if(s == nil)
                                                error("out of memory");
                                }
                        }
                }
                if(strcmp(l->val, c->host) != 0 &&
                  (strcmp(l->attr, "ip")==0 || strcmp(l->attr, "dom")==0 || strcmp(l->attr, "sys")==0)){
                        s = smprint("%s %s", s, l->val);
                        if(s == nil)
                                error("out of memory");
                }
        }
        s = trim(s);
        c->aliases = s;
}

void
setaliases(Conn *c, char *name)
{
        char *p, *net;
        char *attr[2];
        Ndbtuple *t;

        net = "/net";
        if(name[0]=='/'){
                p = strchr(name+1, '/');
                if(p){
                        net = emalloc(p-name+1);
                        memmove(net, name, p-name);
                }
        }
        if(p = strchr(name, '!'))
                name = p+1;

        c->host = emalloc(strlen(name)+1);
        strcpy(c->host, name);

        c->aliases = c->host;
        attr[0] = "dom";
        attr[1] = "ip";
        t = csipinfo(nil, ipattr(name), name, attr, 2);
        if(t != nil){
                usetuple(c, t, 0);
                ndbfree(t);
        }else{
                t = dnsquery(net, name, "ip");
                if(t != nil){
                        usetuple(c, t, 1);
                        ndbfree(t);
                }
        }
}

void
privatefactotum(void)
{
        char *user;
        Dir *d;

        if((user=getuser()) && (d=dirstat("/mnt/factotum/rpc")) && strcmp(user, d->uid)!=0){
                /* grab the terminal's factotum */
                rfork(RFNAMEG); /* was RFNOTEG, which makes little sense */
                if(access("/mnt/term/mnt/factotum", AEXIST) >= 0){
//                      fprint(2, "binding terminal's factotum\n");
                        if(bind("/mnt/term/mnt/factotum", "/mnt/factotum", MREPL) < 0)
                                sysfatal("cannot find factotum");
                }
        }
}