Subversion Repositories planix.SVN

Rev

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

#include "headers.h"
#include <mp.h>
#include <libsec.h>

SmbProcessResult
smbcomsessionsetupandx(SmbSession *s, SmbHeader *h, uchar *pdata, SmbBuffer *b)
{
        uchar andxcommand;
        ushort andxoffset;
        ulong andxfixupoffset;
        ushort vcnumber;
        ulong sessionkey;
        ushort caseinsensitivepasswordlength;
        ushort casesensitivepasswordlength;
        ushort bytecountfixup, offset;
        uchar *mschapreply;
        AuthInfo *ai;
        char *sp;
        SmbProcessResult pr;
        char *accountname = nil;
        char *primarydomain = nil;
        char *nativeos = nil;
        char *nativelanman = nil;

        if (!smbcheckwordcount("comsessionsetupandx", h, 13)) {
        fmtfail:
                pr = SmbProcessResultFormat;
                goto done;
        }

        andxcommand = *pdata++;
        switch (andxcommand) {
        case SMB_COM_TREE_CONNECT_ANDX:
        case SMB_COM_OPEN_ANDX:
        case SMB_COM_CREATE_NEW:
        case SMB_COM_DELETE:
        case SMB_COM_FIND:
        case SMB_COM_COPY:
        case SMB_COM_NT_RENAME:
        case SMB_COM_QUERY_INFORMATION:
        case SMB_COM_NO_ANDX_COMMAND:
        case SMB_COM_OPEN:
        case SMB_COM_CREATE:
        case SMB_COM_CREATE_DIRECTORY:
        case SMB_COM_DELETE_DIRECTORY:
        case SMB_COM_FIND_UNIQUE:
        case SMB_COM_RENAME:
        case SMB_COM_CHECK_DIRECTORY:
        case SMB_COM_SET_INFORMATION:
        case SMB_COM_OPEN_PRINT_FILE:
                break;
        default:
                smblogprint(h->command, "smbcomsessionsetupandx: invalid andxcommand %s (0x%.2ux)\n",
                        smboptable[andxcommand].name, andxcommand);
                goto fmtfail;
        }
        pdata++;
        andxoffset = smbnhgets(pdata); pdata += 2;
        s->peerinfo.maxlen = smbnhgets(pdata); pdata += 2;
        smbresponseinit(s, s->peerinfo.maxlen);
        s->client.maxmpxcount = smbnhgets(pdata); pdata += 2;
        vcnumber = smbnhgets(pdata); pdata += 2;
        sessionkey = smbnhgetl(pdata); pdata += 4;
        caseinsensitivepasswordlength = smbnhgets(pdata); pdata += 2;
        casesensitivepasswordlength = smbnhgets(pdata); pdata += 2;
        pdata += 4;
        s->peerinfo.capabilities = smbnhgetl(pdata); /*pdata += 4;*/
smbloglock();
smblogprint(h->command, "andxcommand: %s offset %ud\n", smboptable[andxcommand].name, andxoffset);
smblogprint(h->command, "client.maxbuffersize: %ud\n", s->peerinfo.maxlen);
smblogprint(h->command, "client.maxmpxcount: %ud\n", s->client.maxmpxcount);
smblogprint(h->command, "vcnumber: %ud\n", vcnumber);
smblogprint(h->command, "sessionkey: 0x%.8lux\n", sessionkey);
smblogprint(h->command, "caseinsensitivepasswordlength: %ud\n", caseinsensitivepasswordlength);
smblogprint(h->command, "casesensitivepasswordlength: %ud\n", casesensitivepasswordlength);
smblogprint(h->command, "clientcapabilities: 0x%.8lux\n", s->peerinfo.capabilities);
smblogunlock();

        mschapreply = smbbufferreadpointer(b);

        if (!smbbuffergetbytes(b, nil, caseinsensitivepasswordlength + casesensitivepasswordlength)) {
                smblogprint(h->command, "smbcomsessionsetupandx: not enough bdata for passwords\n");
                goto fmtfail;
        }
        if (!smbbuffergetstring(b, h, 0, &accountname)
                || !smbbuffergetstring(b, h, 0, &primarydomain)
                || !smbbuffergetstring(b, h, 0, &nativeos)
                || !smbbuffergetstring(b, h, 0, &nativelanman)) {
                smblogprint(h->command, "smbcomsessionsetupandx: not enough bytes for strings\n");
                goto fmtfail;
        }

        for (sp = accountname; *sp; sp++)
                *sp = tolower(*sp);

smblogprint(h->command, "account: %s\n", accountname);
smblogprint(h->command, "primarydomain: %s\n", primarydomain);
smblogprint(h->command, "nativeos: %s\n", nativeos);
smblogprint(h->command, "nativelanman: %s\n", nativelanman);

        if (s->client.accountname && accountname[0] && strcmp(s->client.accountname, accountname) != 0) {
                smblogprint(h->command, "smbcomsessionsetupandx: more than one user on VC (before %s, now %s)\n",
                        s->client.accountname, accountname);
                smbseterror(s, ERRSRV, ERRtoomanyuids);
        errordone:
                pr = SmbProcessResultError;
                goto done;
        }

        if (s->client.accountname == nil) {
                /* first time */
                if (accountname[0] == 0) {
                        smbseterror(s, ERRSRV, ERRbaduid);
                        goto errordone;
                }
                if ((casesensitivepasswordlength != 24 || caseinsensitivepasswordlength != 24)) {
                        smblogprint(h->command,
                                "smbcomsessionsetupandx: case sensitive/insensitive password length not 24\n");
                        smbseterror(s, ERRSRV, ERRbadpw);
                        goto errordone;
                }
                memcpy(&s->client.mschapreply, mschapreply, sizeof(s->client.mschapreply));
                if(s->cs == nil){
                        smbseterror(s, ERRSRV, ERRerror);
                        goto errordone;
                }
                s->cs->user = accountname;
                s->cs->resp = &s->client.mschapreply;
                s->cs->nresp = sizeof(MSchapreply);
                ai = auth_response(s->cs);
                if (ai == nil) {
                        smblogprint(h->command, "authentication failed\n");
                        smbseterror(s, ERRSRV, ERRbadpw);
                        goto errordone;
                }
                smblogprint(h->command, "authentication succeeded\n");
                if (auth_chuid(ai, nil) < 0) {
                        smblogprint(h->command, "smbcomsessionsetupandx: chuid failed: %r\n");
                        auth_freeAI(ai);
                miscerror:
                        pr = SmbProcessResultMisc;
                        goto done;
                }
                auth_freeAI(ai);
                h->uid = 1;
                s->client.accountname = accountname;
                s->client.primarydomain = primarydomain;
                s->client.nativeos = nativeos;
                s->client.nativelanman = nativelanman;
                accountname = nil;
                primarydomain = nil;
                nativeos = nil;
                nativelanman = nil;
        }
        else {
                if (caseinsensitivepasswordlength == 24 && casesensitivepasswordlength == 24
                        && memcmp(&s->client.mschapreply, mschapreply, sizeof(MSchapreply)) != 0) {
                        smblogprint(h->command, "second time authentication failed\n");
                        smbseterror(s, ERRSRV, ERRbadpw);
                        goto errordone;
                }
        }

        /* CIFS says 4 with or without extended security, samba/ms says 3 without */
        h->wordcount = 3;
        if (!smbresponseputandxheader(s, h, andxcommand, &andxfixupoffset))
                goto miscerror;
        if (!smbresponseputs(s, 0))
                goto miscerror;
        bytecountfixup = smbresponseoffset(s);
        if (!smbresponseputs(s, 0))
                goto miscerror;
        if (!smbresponseputstring(s, 1, smbglobals.nativeos)
                || !smbresponseputstring(s, 1, smbglobals.serverinfo.nativelanman)
                || !smbresponseputstring(s, 1, smbglobals.primarydomain))
                goto miscerror;
        offset = smbresponseoffset(s);
        smbresponseoffsetputs(s, bytecountfixup, offset - bytecountfixup - 2);
        s->state = SmbSessionEstablished;
        if (andxcommand != SMB_COM_NO_ANDX_COMMAND)
                pr = smbchaincommand(s, h, andxfixupoffset, andxcommand, andxoffset, b);
        else
                pr = SmbProcessResultReply;
done:
        free(accountname);
        free(primarydomain);
        free(nativeos);
        free(nativelanman);
        return pr;
}