#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; }