Subversion Repositories planix.SVN

Rev

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

#include "headers.h"

typedef struct RapTableEntry RapTableEntry;

struct RapTableEntry {
        char *name;
        SmbProcessResult (*procedure)(SmbBuffer *inparam, SmbBuffer *outparam, SmbBuffer *outdata);
};

typedef int INFOSIZEFN(ushort level, void *data);
typedef int INFOPUTFN(SmbBuffer *b, ushort level, void *data);
typedef int INFOPUTSTRINGSFN(SmbBuffer *b, ushort level, int instance, void *data);
typedef void *INFOENUMERATEFN(void *magic, int i);

typedef struct InfoMethod {
        INFOSIZEFN *size;
        INFOPUTFN *put;
        INFOPUTSTRINGSFN *putstrings;
        INFOENUMERATEFN *enumerate;
} InfoMethod;

static int
serverinfosize(ushort level, void *data)
{
        SmbServerInfo *si = data;
        switch (level) {
        case 0:
                return 16;
        case 1:
                return 26 + smbstrlen(si->remark);
        default:
                return 0;
        }
}

static int
serverinfoput(SmbBuffer *b, ushort level, void *data)
{
        SmbServerInfo *si = data;
        if (!smbbufferputstrn(b, si->name, 16, 1))
                return 0;
        if (level > 0) {
                if (!smbbufferputb(b, si->vmaj)
                        || !smbbufferputb(b, si->vmin)
                        || !smbbufferputl(b, si->stype)
                        || !smbbufferputl(b, 0))
                        return 0;
        }
        if (level > 1)
                return 0;
        return 1;
}

static int
serverinfoputstrings(SmbBuffer *b, ushort level, int instance, void *data)
{
        SmbServerInfo *si = data;
        if (level == 1) {
                if (!smbbufferfixupabsolutel(b, instance * 26 + 22)
                        || !smbbufferputstring(b, nil, SMB_STRING_ASCII, si->remark))
                        return 0;
        }
        return 1;
}

static void *
serverinfoenumerate(void *magic, int i)
{
        if (magic) {
                SmbServerInfo **si = magic;
                return si[i];
        }
        if (i == 0)
                return &smbglobals.serverinfo;
        return nil;
}

InfoMethod serverinfo = {
        serverinfosize,
        serverinfoput,
        serverinfoputstrings,
        serverinfoenumerate,
};

static int
shareinfosize(ushort level, void *data)
{
        SmbService *serv = data;
        switch (level) {
        case 0:
                return 13;
        case 1:
                return 20 + smbstrlen(serv->remark);
        case 2:
                return 40 + smbstrlen(serv->remark) + smbstrlen(serv->path);
        default:
                return 0;
        }
}

static int
shareinfoput(SmbBuffer *b, ushort level, void *data)
{
        SmbService *serv = data;
        if (!smbbufferputstrn(b, serv->name, 13, 0))
                return 0;
        if (level > 0) {
                if (!smbbufferputb(b, 0)
                        || !smbbufferputs(b, serv->stype)
                        || !smbbufferputl(b, 0))
                        return 0;
        }
        if (level > 1) {
                if (!smbbufferputs(b, 7)
                        || !smbbufferputs(b, -1)
                        || !smbbufferputs(b, serv->ref)
                        || !smbbufferputl(b, 0)
                        || !smbbufferfill(b, 0, 10))
                        return 0;
        }
        if (level > 2)
                return 0;
        return 1;
}

static int
shareinfoputstrings(SmbBuffer *b, ushort level, int instance, void *data)
{
        SmbService *serv = data;
        switch (level) {
        case 0:
                break;
        case 1:
                if (!smbbufferfixupabsolutel(b, instance * 20 + 16)
                        || !smbbufferputstring(b, nil, SMB_STRING_ASCII, serv->remark))
                        return 0;
                break;
        case 2:
                if (!smbbufferfixupabsolutel(b, instance * 40 + 16)
                        || !smbbufferputstring(b, nil, SMB_STRING_ASCII, serv->remark)
                        || !smbbufferfixupabsolutel(b, instance * 40 + 26)
                        || !smbbufferputstring(b, nil, SMB_STRING_ASCII, serv->path))
                        return 0;
                break;
        default:
                return 0;
        }
        return 1;
}

static void *
shareinfoenumerate(void *, int i)
{
        SmbService *serv;
        for (serv = smbservices; i-- > 0 && serv; serv = serv->next)
                ;
        return serv;
}

static InfoMethod shareinfo = {
        shareinfosize,
        shareinfoput,
        shareinfoputstrings,
        shareinfoenumerate,
};

static SmbProcessResult
thingfill(SmbBuffer *outparam, SmbBuffer *outdata, InfoMethod *m, ushort level, void *magic)
{
        int sentthings, totalthings;
        int i;
        int totalbytes;

        sentthings = 0;
        totalbytes = 0;
        for (i = 0; ; i++) {
                int len;
                void *thing = (*m->enumerate)(magic, i);
                if (thing == nil)
                        break;
                len = (*m->size)(level, thing);
                if (totalbytes + len <= smbbufferspace(outdata)) {
                        assert((*m->put)(outdata, level, thing));
                        sentthings++;
                }
                totalbytes += len;
        }
        totalthings = i;
        for (i = 0; i < sentthings; i++) {
                void *thing = (*m->enumerate)(magic, i);
                assert(thing);
                assert((*m->putstrings)(outdata, level, i, thing));
        }
        if (!smbbufferputs(outparam, sentthings < totalthings ? SMB_RAP_ERROR_MORE_DATA : SMB_RAP_NERR_SUCCESS)
                || !smbbufferputs(outparam, 0)
                || !smbbufferputs(outparam, totalthings)
                || !smbbufferputs(outparam, sentthings))
                return SmbProcessResultFormat;
        return SmbProcessResultReply;
}

static SmbProcessResult
onethingfill(SmbBuffer *outparam, SmbBuffer *outdata, InfoMethod *m, ushort level, void *thing)
{
        int moredata;
        int totalbytes = (*m->size)(level, thing);
        if (totalbytes <= smbbufferspace(outdata)) {
                assert((*m->put)(outdata, level, thing));
                assert((*m->putstrings)(outdata, level, 0, thing));
                moredata = 0;
        }
        else
                moredata = 1;
        if (!smbbufferputs(outparam, moredata ? SMB_RAP_ERROR_MORE_DATA : SMB_RAP_NERR_SUCCESS)
                || !smbbufferputs(outparam, 0)
                || !smbbufferputs(outparam, totalbytes))
                return SmbProcessResultFormat;
        return SmbProcessResultReply;
}

static SmbProcessResult
netshareenum(SmbBuffer *inparam, SmbBuffer *outparam, SmbBuffer *outdata)
{
        ushort level;

        /* WrLeh */
        /* ushort sLevel, RCVBUF pbBuffer, RCVBUFLEN cbBuffer, ENTCOUNT pcEntriesRead, ushort *pcTotalAvail */

        if (!smbbuffergets(inparam, &level))
                return SmbProcessResultFormat;
        
        smblogprintif(smbglobals.log.rap2, "netshareenum(%lud, %lud)\n",
                level, smbbufferwritespace(outdata));

        if (level != 1)
                return SmbProcessResultFormat;

        return thingfill(outparam, outdata, &shareinfo, level, nil);
}

static SmbProcessResult
netserverenum2(SmbBuffer *inparam, SmbBuffer *outparam, SmbBuffer *outdata)
{
        ushort level, rbl;
        char *domain;
        ulong servertype;
        SmbProcessResult pr;
        SmbServerInfo *si[3];
        SmbServerInfo domainsi;
        int entries;

        /* WrLehDz
         * ushort sLevel, RCVBUF pbBuffer, RCVBUFLEN cbBuffer, ENTCOUNT pcEntriesRead, ushort *pcTotalAvail,
         * ulong fServerType, char *pszDomain
        */

        if (!smbbuffergets(inparam, &level)
                || !smbbuffergets(inparam, &rbl)
                || !smbbuffergetl(inparam, &servertype)
                || !smbbuffergetstr(inparam, 0, &domain)) {
        fmtfail:
                pr = SmbProcessResultFormat;
                goto done;
        }
        
        smblogprintif(smbglobals.log.rap2, "netserverenum2(%lud, %lud, 0x%.8lux, %s)\n",
                level, smbbufferwritespace(outdata), servertype, domain);

        if (level > 1)
                goto fmtfail;

        if (servertype == 0xffffffff)
                servertype &= ~(SV_TYPE_DOMAIN_ENUM | SV_TYPE_LOCAL_LIST_ONLY);

        if ((servertype & SV_TYPE_LOCAL_LIST_ONLY) != 0 && (servertype & SV_TYPE_DOMAIN_ENUM) == 0) 
                servertype = SV_TYPE_ALL & ~(SV_TYPE_DOMAIN_ENUM);

        entries = 0;

        if ((servertype & SV_TYPE_SERVER) != 0
                && (domain[0] == 0 || cistrcmp(domain, smbglobals.primarydomain) == 0)) {
                si[entries++] = &smbglobals.serverinfo;
        }

        if ((servertype & SV_TYPE_DOMAIN_ENUM) != 0) {
                /* there's only one that I know about */
                memset(&domainsi, 0, sizeof(domainsi));
                domainsi.name = smbglobals.primarydomain;
                domainsi.stype = SV_TYPE_DOMAIN_ENUM;
                si[entries++] = &domainsi;
        }
        si[entries] = 0;

        pr = thingfill(outparam, outdata, &serverinfo, level, si);
                        
done:
        free(domain);
        return pr;
}

static SmbProcessResult
netsharegetinfo(SmbBuffer *inparam, SmbBuffer *outparam, SmbBuffer *outdata)
{
        char *netname;
        ushort level;
        SmbProcessResult pr;
        SmbService *serv;

        /*
         * zWrLh
         * char *pszNetName, ushort sLevel, RCVBUF pbBuffer, RCVBUFLEN cbBuffer, ushort *pcbTotalAvail
        */

        if (!smbbuffergetstrinline(inparam, &netname)
                || !smbbuffergets(inparam, &level)) {
        fmtfail:
                pr = SmbProcessResultFormat;
                goto done;
        }
        
        smblogprintif(smbglobals.log.rap2, "netsharegetinfo(%s, %lud, %lud)\n",
                netname, level, smbbufferwritespace(outdata));

        if (level > 2)
                goto fmtfail;

        for (serv = smbservices; serv; serv = serv->next)
                if (cistrcmp(serv->name, netname) == 0)
                        break;

        if (serv == nil) {
                smblogprint(-1, "netsharegetinfo: service %s unimplemented\n", netname);
                pr = SmbProcessResultUnimp;
                goto done;
        }

        pr = onethingfill(outparam, outdata, &shareinfo, level, serv);

done:
        return pr;
}

static SmbProcessResult
netservergetinfo(SmbBuffer *inparam, SmbBuffer *outparam, SmbBuffer *outdata)
{
        ushort level;
        SmbProcessResult pr;

        /* WrLh
         * ushort sLevel, RCVBUF pbBuffer, RCVBUFLEN cbBuffer, ushort *pcbTotalAvail
        */

        if (!smbbuffergets(inparam, &level)) {
        fmtfail:
                pr = SmbProcessResultFormat;
                goto done;
        }
        
        smblogprintif(smbglobals.log.rap2, "netservergetinfo(%lud, %lud)\n",
                level, smbbufferwritespace(outdata));

        if (level > 1)
                goto fmtfail;

        pr = onethingfill(outparam, outdata, &shareinfo, level, &smbglobals.serverinfo);
                        
done:
        return pr;
}

static SmbProcessResult
netwkstagetinfo(SmbBuffer *inparam, SmbBuffer *outparam, SmbBuffer *outdata)
{
        ushort level;
        ushort usefulbytes;
        SmbProcessResult pr;
        int moredata;

        /* WrLh
         * ushort sLevel, RCVBUF pbBuffer, RCVBUFLEN cbBuffer, ushort *pcbTotalAvail
        */

        if (!smbbuffergets(inparam, &level)) {
        fmtfail:
                pr = SmbProcessResultFormat;
                goto done;
        }
        
        smblogprintif(smbglobals.log.rap2, "netwkstagetinfo(%lud, %lud)\n",
                level, smbbufferwritespace(outdata));

        if (level != 10)
                goto fmtfail;

        usefulbytes = 22 + smbstrlen(smbglobals.serverinfo.name) + smbstrlen(getuser())
                + 3 * smbstrlen(smbglobals.primarydomain);

        moredata = usefulbytes > smbbufferwritespace(outdata);

        assert(smbbufferputl(outdata, 0));
        assert(smbbufferputl(outdata, 0));
        assert(smbbufferputl(outdata, 0));
        assert(smbbufferputb(outdata, smbglobals.serverinfo.vmaj));
        assert(smbbufferputb(outdata, smbglobals.serverinfo.vmin));
        assert(smbbufferputl(outdata, 0));
        assert(smbbufferputl(outdata, 0));
        assert(smbbufferfixupabsolutel(outdata, 0));
        assert(smbbufferputstring(outdata, nil, SMB_STRING_ASCII, smbglobals.serverinfo.name));
        assert(smbbufferfixupabsolutel(outdata, 4));
        assert(smbbufferputstring(outdata, nil, SMB_STRING_ASCII, getuser()));
        assert(smbbufferfixupabsolutel(outdata, 8));
        assert(smbbufferputstring(outdata, nil, SMB_STRING_ASCII, smbglobals.primarydomain));
        assert(smbbufferfixupabsolutel(outdata, 14));
        assert(smbbufferputstring(outdata, nil, SMB_STRING_ASCII, smbglobals.primarydomain));
        assert(smbbufferfixupabsolutel(outdata, 18));
        assert(smbbufferputstring(outdata, nil, SMB_STRING_ASCII, smbglobals.primarydomain));

        if (!smbbufferputs(outparam, moredata ? SMB_RAP_ERROR_MORE_DATA : SMB_RAP_NERR_SUCCESS)
                || !smbbufferputs(outparam, 0)
                || !smbbufferputs(outparam, usefulbytes)) {
                pr = SmbProcessResultFormat;
                goto done;
        }
        
        pr = SmbProcessResultReply;
                        
done:
        return pr;
}

static RapTableEntry raptable[] = {
[RapNetShareGetInfo] { "NetShareGetInfo", netsharegetinfo },
[RapNetShareEnum] { "NetShareEnum", netshareenum },
[RapNetServerGetInfo] {"NetServerGetInfo", netservergetinfo },
[RapNetWkstaGetInfo] { "NetWkstaGetInfo", netwkstagetinfo },
[RapNetServerEnum2] { "NetServerEnum2", netserverenum2 },
};

SmbProcessResult
smbrap2(SmbSession *s)
{
        char *pstring;
        char *dstring;
        ushort pno;
        RapTableEntry *e;
        SmbProcessResult pr;
        SmbBuffer *inparam;

        inparam = smbbufferinit(s->transaction.in.parameters, s->transaction.in.parameters, s->transaction.in.tpcount);
        if (!smbbuffergets(inparam, &pno)
                || !smbbuffergetstrinline(inparam, &pstring)
                || !smbbuffergetstrinline(inparam, &dstring)) {
                smblogprintif(smbglobals.log.rap2, "smbrap2: not enough parameters\n");
                pr = SmbProcessResultFormat;
                goto done;
        }
        if (pno > nelem(raptable) || raptable[pno].name == nil) {
                smblogprint(-1, "smbrap2: unsupported procedure %ud\n", pno);
                pr = SmbProcessResultUnimp;
                goto done;
        }
        e = raptable + pno;
        pr = (*e->procedure)(inparam, s->transaction.out.parameters, s->transaction.out.data);
done:
        smbbufferfree(&inparam);
        return pr;
}