Subversion Repositories planix.SVN

Rev

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

#include "headers.h"

SmbClient *
smbconnect(char *to, char *share, char **errmsgp)
{
        NbSession *nbs;
        SmbBuffer *b;
        SmbHeader h, rh;
        long n;
        ushort bytecountfixupoffset;
        ushort andxfixupoffset;
        uchar *pdata;
        SmbPeerInfo peerinfo;
        ushort index;
        vlong utcintenthsofaus;
        ulong secssince1970;
        ushort bytecount;
        int x;
        MSchapreply mschapreply;
        NbName nbto;
        SmbClient *c;
        char namebuf[100];
        ushort ipctid, sharetid;

        nbmknamefromstringandtype(nbto, to, 0x20);

        peerinfo.encryptionkey = nil;
        peerinfo.oemdomainname = nil;
        assert(smbglobals.nbname[0] != 0);
        nbs = nbssconnect(nbto, smbglobals.nbname);
        if (nbs == nil)
                return nil;
print("netbios session established\n");
        b = smbbuffernew(65535);
        memset(&h, 0, sizeof(h));
        h.command = SMB_COM_NEGOTIATE;
        h.flags2 = SMB_FLAGS2_KNOWS_LONG_NAMES | SMB_FLAGS2_IS_LONG_NAME | SMB_FLAGS2_UNICODE;
        h.wordcount = 0;
        h.pid = 42;
        smbbufferputheader(b, &h, &peerinfo);
        bytecountfixupoffset = smbbufferwriteoffset(b);
        smbbufferputbytes(b, nil, 2);
        smbbufferputb(b, 2);
        smbbufferputstring(b, nil, SMB_STRING_ASCII, "NT LM 0.12");
        smbbufferoffsetputs(b, bytecountfixupoffset, smbbufferwriteoffset(b) - bytecountfixupoffset - 2);
        nbdumpdata(smbbufferreadpointer(b), smbbufferwriteoffset(b));
        nbsswrite(nbs, smbbufferreadpointer(b), smbbufferwriteoffset(b));
        /*
         * now receive a reply
         */
        smbbufferreset(b);
        n = nbssread(nbs, smbbufferwritepointer(b), smbbufferwritespace(b));
        if (n < 0) {
                smbstringprint(errmsgp, "smbconnect: read error: %r");
                goto fail;
        }
        smbbuffersetreadlen(b, n);
        nbdumpdata(smbbufferreadpointer(b), smbbufferwriteoffset(b));
        if (!smbbuffergetandcheckheader(b, &rh, h.command, 1, &pdata, &bytecount, errmsgp))
                goto fail;
        if (!smbsuccess(&rh, errmsgp))
                goto fail;
        if (rh.wordcount == 0) {
                smbstringprint(errmsgp, "no parameters in negotiate response");
                goto fail;
        }
        index = smbnhgets(pdata); pdata += 2;
        if (index != 0) {
                smbstringprint(errmsgp, "no agreement on protocol");
                goto fail;
        }
        if (rh.wordcount != 17) {
                smbstringprint(errmsgp, "wrong number of parameters for negotiate response");
                goto fail;
        }
        peerinfo.securitymode = *pdata++;
        peerinfo.maxmpxcount = smbnhgets(pdata); pdata += 2;
        peerinfo.maxnumbervcs = smbnhgets(pdata); pdata += 2;
        peerinfo.maxbuffersize = smbnhgetl(pdata); pdata += 4;
        peerinfo.maxrawsize = smbnhgetl(pdata); pdata += 4;
        peerinfo.sessionkey = smbnhgets(pdata); pdata += 4;
        peerinfo.capabilities = smbnhgets(pdata); pdata += 4;
        utcintenthsofaus = smbnhgetv(pdata); pdata += 8;
        secssince1970 = utcintenthsofaus / 10000000 - 11644473600LL;
        peerinfo.utc =  (vlong)secssince1970 * (vlong)1000000000 + (utcintenthsofaus % 10000000) * 100;
        peerinfo.tzoff = -smbnhgets(pdata) * 60; pdata += 2;
        peerinfo.encryptionkeylength = *pdata++;
        print("securitymode: 0x%.2ux\n", peerinfo.securitymode);
        print("maxmpxcount: 0x%.4ux\n", peerinfo.maxmpxcount);
        print("maxnumbervcs: 0x%.4ux\n", peerinfo.maxnumbervcs);
        print("maxbuffersize: 0x%.8lux\n", peerinfo.maxbuffersize);
        print("maxrawsize: 0x%.8lux\n", peerinfo.maxrawsize);
        print("sessionkey: 0x%.8lux\n", peerinfo.sessionkey);
        print("capabilities: 0x%.8lux\n", peerinfo.capabilities);
        print("utc: %s(and %lld μs)\n", asctime(gmtime(peerinfo.utc / 1000000000)), peerinfo.utc % 1000000000);
        print("tzoff: %d\n", peerinfo.tzoff);
        print("encryptionkeylength: %d\n", peerinfo.encryptionkeylength);
        smberealloc(&peerinfo.encryptionkey, peerinfo.encryptionkeylength);
        if (!smbbuffergetbytes(b, peerinfo.encryptionkey, peerinfo.encryptionkeylength)) {
                smbstringprint(errmsgp, "not enough data for encryption key");
                goto fail;
        }
        print("encryptionkey: ");
        for (x = 0; x < peerinfo.encryptionkeylength; x++)
                print("%.2ux", peerinfo.encryptionkey[x]);
        print("\n");
        if (!smbbuffergetucs2(b, 0, &peerinfo.oemdomainname)) {
                smbstringprint(errmsgp, "not enough data for oemdomainname");
                goto fail;
        }
        print("oemdomainname: %s\n", peerinfo.oemdomainname);
        if (peerinfo.capabilities & CAP_EXTENDED_SECURITY) {
                smbstringprint(errmsgp, "server wants extended security");
                goto fail;
        }
        /*
         * ok - now send SMB_COM_SESSION_SETUP_ANDX
         * fix the flags to reflect what the peer can do
         */
        smbbufferreset(b);
        h.command = SMB_COM_SESSION_SETUP_ANDX;
        h.wordcount = 13;
        h.flags2 &= ~SMB_FLAGS2_UNICODE;
        if (smbsendunicode(&peerinfo))
                h.flags2 |= SMB_FLAGS2_UNICODE;
        smbbufferputheader(b, &h, &peerinfo);
        smbbufferputb(b, SMB_COM_TREE_CONNECT_ANDX);
        smbbufferputb(b, 0);
        andxfixupoffset = smbbufferwriteoffset(b);
        smbbufferputs(b, 0);
        smbbufferputs(b, 0xffff);
        smbbufferputs(b, 1);
        smbbufferputs(b, 0);
        smbbufferputl(b, peerinfo.sessionkey);
        smbbufferputs(b, sizeof(mschapreply.LMresp));
        smbbufferputs(b, sizeof(mschapreply.NTresp));
        smbbufferputl(b, 0);
        smbbufferputl(b, CAP_UNICODE | CAP_LARGE_FILES);
        bytecountfixupoffset = smbbufferwriteoffset(b);
        smbbufferputs(b, 0);
        if (auth_respond(peerinfo.encryptionkey, peerinfo.encryptionkeylength,
                nil, 0,
                &mschapreply, sizeof(mschapreply), auth_getkey,
                "proto=mschap role=client server=%s", "cher") != sizeof(mschapreply)) {
                print("auth_respond failed: %r\n");
                goto fail;
        }
        smbbufferputbytes(b, &mschapreply, sizeof(mschapreply));
        smbbufferputstring(b, &peerinfo, 0, smbglobals.accountname);
        smbbufferputstring(b, &peerinfo, 0, smbglobals.primarydomain);
        smbbufferputstring(b, &peerinfo, 0, smbglobals.nativeos);
        smbbufferputstring(b, &peerinfo, 0, "");
        smbbufferoffsetputs(b, bytecountfixupoffset, smbbufferwriteoffset(b) - bytecountfixupoffset - 2);
        smbbufferalignl2(b, 2);
        smbbufferoffsetputs(b, andxfixupoffset, smbbufferwriteoffset(b));
        smbbufferputb(b, 4);
        smbbufferputb(b, SMB_COM_NO_ANDX_COMMAND);
        smbbufferputb(b, 0);
        smbbufferputs(b, 0);
        smbbufferputs(b, 0);
        smbbufferputs(b, 0);
        bytecountfixupoffset = smbbufferwriteoffset(b);
        smbbufferputs(b, 0);
        strcpy(namebuf, "\\\\");
        strcat(namebuf, to);
        strcat(namebuf, "\\IPC$");
        smbbufferputstring(b, &peerinfo, SMB_STRING_UPCASE, namebuf);
        smbbufferputstring(b, nil, SMB_STRING_ASCII, "?????");
        smbbufferoffsetputs(b, bytecountfixupoffset, smbbufferwriteoffset(b) - bytecountfixupoffset - 2);
        nbdumpdata(smbbufferreadpointer(b), smbbufferwriteoffset(b));
        nbsswrite(nbs, smbbufferreadpointer(b), smbbufferwriteoffset(b));
        smbbufferreset(b);
        n = nbssread(nbs, smbbufferwritepointer(b), smbbufferwritespace(b));
        if (n < 0) {
                smbstringprint(errmsgp, "read error: %r");
                goto fail;
        }
        smbbuffersetreadlen(b, n);
        nbdumpdata(smbbufferreadpointer(b), smbbufferwriteoffset(b));
        if (!smbbuffergetandcheckheader(b, &rh, h.command, 1, &pdata, &bytecount, errmsgp))
                goto fail;
        if (!smbsuccess(&rh, errmsgp))
                goto fail;
        h.uid = rh.uid;
        ipctid = rh.tid;
        /*
         * now do another TREE_CONNECT if needed
         */
        if (share) {
                smbbufferreset(b);
                h.command = SMB_COM_TREE_CONNECT_ANDX;
                h.wordcount = 4;
                h.tid = 0;
                smbbufferputheader(b, &h, &peerinfo);
                smbbufferputb(b, SMB_COM_NO_ANDX_COMMAND);
                smbbufferputb(b, 0);
                smbbufferputs(b, 0);
                smbbufferputs(b, 0);
                smbbufferputs(b, 0);
                bytecountfixupoffset = smbbufferwriteoffset(b);
                smbbufferputs(b, 0);
                strcpy(namebuf, "\\\\");
                strcat(namebuf, to);
                strcat(namebuf, "\\");
                strcat(namebuf, share);
                smbbufferputstring(b, &peerinfo, SMB_STRING_UPCASE, namebuf);
                smbbufferputstring(b, nil, SMB_STRING_ASCII, "A:");
                smbbufferoffsetputs(b, bytecountfixupoffset, smbbufferwriteoffset(b) - bytecountfixupoffset - 2);
                nbdumpdata(smbbufferreadpointer(b), smbbufferwriteoffset(b));
                nbsswrite(nbs, smbbufferreadpointer(b), smbbufferwriteoffset(b));
                smbbufferreset(b);
                n = nbssread(nbs, smbbufferwritepointer(b), smbbufferwritespace(b));
                if (n < 0) {
                        smbstringprint(errmsgp, "read error: %r");
                        goto fail;
                }
                smbbuffersetreadlen(b, n);
                nbdumpdata(smbbufferreadpointer(b), smbbufferwriteoffset(b));
                if (!smbbuffergetandcheckheader(b, &rh, h.command, 3, &pdata, &bytecount, errmsgp))
                        goto fail;
                if (!smbsuccess(&rh, errmsgp))
                        goto fail;
                sharetid = rh.tid;
        }
        else
                sharetid = -2;
        c = smbemalloc(sizeof(*c));
        c->peerinfo = peerinfo;
        c->ipctid = ipctid;
        c->sharetid = sharetid;
        c->b = b;
        c->protoh = h;
        c->nbss = nbs;
        return c;
fail:
        smbbufferfree(&b);
        free(peerinfo.encryptionkey);
        free(peerinfo.oemdomainname);
        return nil;
}

void
smbclientfree(SmbClient *c)
{
        if (c) {
                free(c->peerinfo.encryptionkey);
                free(c->peerinfo.oemdomainname);
                free(c);
                smbbufferfree(&c->b);
        }
}

int
smbtransactionclientsend(void *magic, SmbBuffer *ob, char **)
{
        SmbClient *c = magic;
smblogprint(-1, "sending:\n");
smblogdata(-1, smblogprint, smbbufferreadpointer(ob), smbbufferwriteoffset(ob), 256);
        return nbsswrite(c->nbss, smbbufferreadpointer(ob), smbbufferwriteoffset(ob)) == 0;
}

int
smbtransactionclientreceive(void *magic, SmbBuffer *ib, char **)
{
        long n; 
        SmbClient *c = magic;
        smbbufferreset(ib);
        n = nbssread(c->nbss, smbbufferwritepointer(ib), smbbufferwritespace(ib));
        if (n >= 0) {
                assert(smbbufferputbytes(ib, nil, n));
                return 1;
        }
        return 0;
}