123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507 |
- #include "headers.h"
- typedef struct Args Args;
- struct Args {
- ulong pcount;
- ulong poffset;
- ulong pdisplacement;
- ulong dcount;
- ulong doffset;
- ulong ddisplacement;
- uchar scount;
- };
- int
- _smbtransactiondecodeprimary(SmbTransaction *t, SmbHeader *h, uchar *pdata, SmbBuffer *b, int hasname, char **errmsgp)
- {
- ushort poffset, doffset;
- if (h->wordcount < 14) {
- smbstringprint(errmsgp, "word count less than 14");
- return -1;
- }
- t->in.scount = pdata[13 * 2];
- if (h->wordcount != 14 + t->in.scount) {
- smbstringprint(errmsgp, "smbcomtransaction: word count invalid\n");
- return -1;
- }
- t->in.tpcount = smbnhgets(pdata); pdata += 2;
- t->in.tdcount = smbnhgets(pdata); pdata += 2;
- t->in.maxpcount = smbnhgets(pdata); pdata += 2;
- t->in.maxdcount = smbnhgets(pdata); pdata += 2;
- t->in.maxscount = *pdata++;
- pdata++;
- t->in.flags = smbnhgets(pdata); pdata += 2;
- pdata += 4; /* timeout */
- pdata += 2;
- t->in.pcount = smbnhgets(pdata); pdata += 2;
- poffset = smbnhgets(pdata); pdata += 2;
- t->in.dcount = smbnhgets(pdata); pdata += 2;
- doffset = smbnhgets(pdata); pdata += 2;
- pdata++; /* scount */
- pdata++; /* reserved */
- smbfree(&t->in.setup);
- if (t->in.scount) {
- int x;
- t->in.setup = smbemalloc(t->in.scount * sizeof(ushort));
- for (x = 0; x < t->in.scount; x++) {
- t->in.setup[x] = smbnhgets(pdata);
- pdata += 2;
- }
- }
- smbfree(&t->in.name);
- if (hasname && !smbbuffergetstring(b, h, SMB_STRING_PATH, &t->in.name)) {
- smbstringprint(errmsgp, "not enough bdata for name");
- return -1;
- }
- if (poffset + t->in.pcount > smbbufferwriteoffset(b)) {
- smbstringprint(errmsgp, "not enough bdata for parameters");
- return -1;
- }
- if (t->in.pcount > t->in.tpcount) {
- smbstringprint(errmsgp, "too many parameters");
- return -1;
- }
- smbfree(&t->in.parameters);
- t->in.parameters = smbemalloc(t->in.tpcount);
- memcpy(t->in.parameters, smbbufferpointer(b, poffset), t->in.pcount);
- if (doffset + t->in.dcount > smbbufferwriteoffset(b)) {
- smbstringprint(errmsgp, "not enough bdata for data");
- return -1;
- }
- if (t->in.dcount > t->in.tdcount) {
- smbstringprint(errmsgp, "too much data");
- return -1;
- }
- smbfree(&t->in.data);
- t->in.data = smbemalloc(t->in.tdcount);
- memcpy(t->in.data, smbbufferpointer(b, doffset), t->in.dcount);
- if (t->in.dcount < t->in.tdcount || t->in.pcount < t->in.tpcount)
- return 0;
- return 1;
- }
- int
- decoderesponse(SmbTransaction *t, Args *a, SmbBuffer *b, char **errmsgp)
- {
- if (t->out.tpcount > smbbufferwritemaxoffset(t->out.parameters)) {
- smbstringprint(errmsgp, "decoderesponse: too many parameters for buffer");
- return 0;
- }
- if (t->out.tdcount > smbbufferwritemaxoffset(t->out.data)) {
- smbstringprint(errmsgp, "decoderesponse: too much data for buffer");
- return 0;
- }
- if (a->pdisplacement + a->pcount > t->out.tpcount) {
- smbstringprint(errmsgp, "decoderesponse: more parameters than tpcount");
- return 0;
- }
- if (a->pdisplacement != smbbufferwriteoffset(t->out.parameters)) {
- smbstringprint(errmsgp, "decoderesponse: parameter displacement inconsistent");
- return 0;
- }
- if (a->ddisplacement + a->dcount > t->out.tdcount) {
- smbstringprint(errmsgp, "decoderesponse: more data than tdcount");
- return 0;
- }
- if (a->ddisplacement != smbbufferwriteoffset(t->out.data)) {
- smbstringprint(errmsgp, "decoderesponse: data displacement inconsistent");
- return 0;
- }
- assert(a->scount == 0);
- if (a->pcount) {
- if (!smbbufferreadskipto(b, a->poffset)) {
- smbstringprint(errmsgp, "smbtransactiondecoderesponse: invalid parameter offset");
- return 0;
- }
- if (!smbbuffercopy(t->out.parameters, b, a->pcount)) {
- smbstringprint(errmsgp, "smbtransactiondecoderesponse: not enough data for parameters");
- return 0;
- }
- }
- if (a->dcount) {
- if (!smbbufferreadskipto(b, a->doffset)) {
- smbstringprint(errmsgp, "smbtransactiondecoderesponse: invalid data offset");
- return 0;
- }
- if (!smbbuffercopy(t->out.data, b, a->dcount)) {
- smbstringprint(errmsgp, "smbtransactiondecoderesponse: not enough data for data");
- return 0;
- }
- }
- return 1;
- }
- int
- smbtransactiondecoderesponse(SmbTransaction *t, SmbHeader *h, uchar *pdata, SmbBuffer *b, char **errmsgp)
- {
- Args a;
- if (h->command != SMB_COM_TRANSACTION) {
- smbstringprint(errmsgp, "smbtransactiondecoderesponse: not an SMB_COM_TRANSACTION");
- return 0;
- }
- if (h->wordcount < 10) {
- smbstringprint(errmsgp, "smbtransactiondecoderesponse: word count less than 10");
- return -1;
- }
- t->out.tpcount = smbnhgets(pdata); pdata += 2;
- t->out.tdcount = smbnhgets(pdata); pdata += 2;
- pdata += 2;
- a.pcount = smbnhgets(pdata); pdata += 2;
- a.poffset = smbnhgets(pdata); pdata += 2;
- a.pdisplacement = smbnhgets(pdata); pdata += 2;
- a.dcount = smbnhgets(pdata); pdata += 2;
- a.doffset = smbnhgets(pdata); pdata += 2;
- a.ddisplacement = smbnhgets(pdata); pdata += 2;
- a.scount = *pdata;
- if (a.scount != h->wordcount - 10) {
- smbstringprint(errmsgp, "smbtransactiondecoderesponse: scount inconsistent");
- return 0;
- }
- return decoderesponse(t, &a, b, errmsgp);
- }
- int
- smbtransactiondecoderesponse2(SmbTransaction *t, SmbHeader *h, uchar *pdata, SmbBuffer *b, char **errmsgp)
- {
- Args a;
- if (h->command != SMB_COM_TRANSACTION2) {
- smbstringprint(errmsgp, "smbtransactiondecoderesponse2: not an SMB_COM_TRANSACTION2");
- return 0;
- }
- if (h->wordcount < 10) {
- smbstringprint(errmsgp, "smbtransactiondecoderesponse2: word count less than 10");
- return -1;
- }
- t->out.tpcount = smbnhgets(pdata); pdata += 2;
- t->out.tdcount = smbnhgets(pdata); pdata += 2;
- pdata += 2;
- a.pcount = smbnhgets(pdata); pdata += 2;
- a.poffset = smbnhgets(pdata); pdata += 2;
- a.pdisplacement = smbnhgets(pdata); pdata += 2;
- a.dcount = smbnhgets(pdata); pdata += 2;
- a.doffset = smbnhgets(pdata); pdata += 2;
- a.ddisplacement = smbnhgets(pdata); pdata += 2;
- a.scount = *pdata;
- if (a.scount != h->wordcount - 10) {
- smbstringprint(errmsgp, "smbtransactiondecoderesponse2: scount inconsistent");
- return 0;
- }
- return decoderesponse(t, &a, b, errmsgp);
- }
- int
- smbtransactiondecodeprimary(SmbTransaction *t, SmbHeader *h, uchar *pdata, SmbBuffer *b, char **errmsgp)
- {
- return _smbtransactiondecodeprimary(t, h, pdata, b, 1, errmsgp);
- }
- int
- smbtransactiondecodeprimary2(SmbTransaction *t, SmbHeader *h, uchar *pdata, SmbBuffer *b, char **errmsgp)
- {
- return _smbtransactiondecodeprimary(t, h, pdata, b, 0, errmsgp);
- }
- void
- smbtransactionfree(SmbTransaction *t)
- {
- free(t->in.parameters);
- free(t->in.data);
- free(t->in.setup);
- free(t->in.name);
- smbbufferfree(&t->out.parameters);
- smbbufferfree(&t->out.data);
- }
- static int
- _transactionencodeprimary(SmbTransaction *t, uchar cmd, SmbHeader *h, SmbPeerInfo *p, SmbBuffer *ob,
- uchar *wordcountp, ushort *bytecountp, char **errmsgp)
- {
- SmbHeader mh;
- ulong countsfixupoffset, bytecountfixupoffset;
- int x;
- mh = *h;
- *wordcountp = mh.wordcount = 14 + t->in.scount;
- mh.flags &= ~SMB_FLAGS_SERVER_TO_REDIR;
- mh.command = cmd;
- if (!smbbufferputheader(ob, &mh, p)) {
- toosmall:
- smbstringprint(errmsgp, "output buffer too small");
- return 0;
- }
- if (t->in.tpcount > 65535 || t->in.tdcount > 65535 || t->in.maxpcount > 65535 || t->in.maxdcount > 65535) {
- smbstringprint(errmsgp, "counts too big");
- return 0;
- }
- if (!smbbufferputs(ob, t->in.tpcount)
- || !smbbufferputs(ob, t->in.tdcount)
- || !smbbufferputs(ob, t->in.maxpcount)
- || !smbbufferputs(ob, t->in.maxdcount)
- || !smbbufferputb(ob, t->in.maxscount)
- || !smbbufferputb(ob, 0)
- || !smbbufferputs(ob, t->in.flags)
- || !smbbufferputl(ob, 0)
- || !smbbufferputs(ob, 0))
- goto toosmall;
- countsfixupoffset = smbbufferwriteoffset(ob);
- if (!smbbufferputs(ob, 0)
- || !smbbufferputs(ob, 0)
- || !smbbufferputs(ob, 0)
- || !smbbufferputs(ob, 0))
- goto toosmall;
- if (!smbbufferputb(ob, t->in.scount)
- || !smbbufferputb(ob, 0))
- goto toosmall;
- for (x = 0; x < t->in.scount; x++)
- if (!smbbufferputs(ob, t->in.setup[x]))
- goto toosmall;
- bytecountfixupoffset = smbbufferwriteoffset(ob);
- if (!smbbufferputs(ob, 0))
- goto toosmall;
- smbbufferwritelimit(ob, smbbufferwriteoffset(ob) + 65535);
- if (!smbbufferputstring(ob, p, SMB_STRING_UPCASE, t->in.name))
- goto toosmall;
- if (t->in.pcount < t->in.tpcount) {
- ulong align = smbbufferwriteoffset(ob) & 1;
- ulong pthistime;
- pthistime = smbbufferwritespace(ob) - align;
- if (pthistime > t->in.tpcount - t->in.pcount)
- pthistime = t->in.tpcount - t->in.pcount;
- if (pthistime > 65535)
- pthistime = 65535;
- if (smbbufferwriteoffset(ob) > 65535)
- pthistime = 0;
- if (pthistime) {
- assert(smbbufferalignl2(ob, 0));
- assert(smbbufferoffsetputs(ob, countsfixupoffset, pthistime));
- assert(smbbufferoffsetputs(ob, countsfixupoffset + 2, smbbufferwriteoffset(ob)));
- assert(smbbufferputbytes(ob, t->in.parameters + t->in.pcount, pthistime));
- }
- t->in.pcount += pthistime;
- }
- if (t->in.dcount < t->in.tdcount) {
- ulong align = smbbufferwriteoffset(ob) & 1;
- ulong dthistime;
- dthistime = smbbufferwritespace(ob) - align;
- if (dthistime > t->in.tdcount - t->in.dcount)
- dthistime = t->in.tdcount - t->in.dcount;
- if (dthistime > 65535)
- dthistime = 65535;
- if (smbbufferwriteoffset(ob) > 65535)
- dthistime = 0;
- if (dthistime) {
- assert(smbbufferalignl2(ob, 0));
- assert(smbbufferoffsetputs(ob, countsfixupoffset + 4, dthistime));
- assert(smbbufferoffsetputs(ob, countsfixupoffset + 6, smbbufferwriteoffset(ob)));
- assert(smbbufferputbytes(ob, t->in.data + t->in.dcount, dthistime));
- }
- t->in.dcount += dthistime;
- }
- *bytecountp = smbbufferwriteoffset(ob) - bytecountfixupoffset - 2;
- assert(smbbufferoffsetputs(ob, bytecountfixupoffset, *bytecountp));
- return 1;
- }
- int
- smbtransactionencodeprimary(SmbTransaction *t, SmbHeader *h, SmbPeerInfo *p, SmbBuffer *ob,
- uchar *wordcountp, ushort *bytecountp, char **errmsgp)
- {
- return _transactionencodeprimary(t, SMB_COM_TRANSACTION, h, p,ob, wordcountp, bytecountp, errmsgp);
- };
- int
- smbtransactionencodeprimary2(SmbTransaction *t, SmbHeader *h, SmbPeerInfo *p, SmbBuffer *ob,
- uchar *wordcountp, ushort *bytecountp, char **errmsgp)
- {
- return _transactionencodeprimary(t, SMB_COM_TRANSACTION2, h, p,ob, wordcountp, bytecountp, errmsgp);
- };
- int
- _transactionencoderesponse(SmbTransaction *t, SmbHeader *h, SmbPeerInfo *p, SmbBuffer *ob, uchar cmd,
- char **errmsgp)
- {
- SmbHeader mh;
- ulong countsfixupoffset, bytecountfixupoffset;
- int palign, dalign;
- ulong pbytecount, dbytecount;
- ulong poffset, doffset;
- if (t->in.maxpcount > 65535 || t->in.maxdcount > 65535) {
- smbstringprint(errmsgp, "counts too big");
- return 0;
- }
- mh = *h;
- mh.wordcount = 10;
- mh.flags &= ~SMB_FLAGS_SERVER_TO_REDIR;
- mh.command = cmd;
- mh.errclass = SUCCESS;
- mh.error = SUCCESS;
- if (!smbbufferputheader(ob, &mh, p)
- || !smbbufferputs(ob, smbbufferwriteoffset(t->out.parameters))
- || !smbbufferputs(ob, smbbufferwriteoffset(t->out.data))
- || !smbbufferputs(ob, 0)) {
- toosmall:
- smbstringprint(errmsgp, "output buffer too small");
- goto toosmall;
- }
- countsfixupoffset = smbbufferwriteoffset(ob);
- if (!smbbufferputbytes(ob, nil, 6 * sizeof(ushort))
- || !smbbufferputb(ob, 0) // scount == 0
- || !smbbufferputb(ob, 0)) // reserved2
- goto toosmall;
- /* now the byte count */
- bytecountfixupoffset = smbbufferwriteoffset(ob);
- if (!smbbufferputs(ob, 0))
- goto toosmall;
- smbbufferwritelimit(ob, smbbufferwriteoffset(ob) + 65535);
- palign = bytecountfixupoffset & 1;
- if (palign && !smbbufferputb(ob, 0))
- goto toosmall;
- pbytecount = smbbufferreadspace(t->out.parameters);
- if (pbytecount > smbbufferwritespace(ob))
- pbytecount = smbbufferwritespace(ob);
- poffset = smbbufferwriteoffset(ob);
- if (poffset > 65535)
- goto toosmall;
- if (!smbbufferputbytes(ob, smbbufferreadpointer(t->out.parameters), pbytecount))
- goto toosmall;
- dalign = smbbufferwritespace(ob) > 0 && (smbbufferwriteoffset(ob) & 1) != 0;
- if (dalign && !smbbufferputb(ob, 0))
- goto toosmall;
- dbytecount = smbbufferreadspace(t->out.data);
- if (dbytecount > smbbufferwritespace(ob))
- dbytecount = smbbufferwritespace(ob);
- doffset = smbbufferwriteoffset(ob);
- if (doffset > 65535)
- goto toosmall;
- if (!smbbufferputbytes(ob, smbbufferreadpointer(t->out.data), dbytecount))
- goto toosmall;
- if (!smbbufferoffsetputs(ob, bytecountfixupoffset, palign + pbytecount + dalign + dbytecount)
- || !smbbufferoffsetputs(ob, countsfixupoffset, pbytecount)
- || !smbbufferoffsetputs(ob, countsfixupoffset + 2, poffset)
- || !smbbufferoffsetputs(ob, countsfixupoffset + 4, smbbufferreadoffset(t->out.parameters))
- || !smbbufferoffsetputs(ob, countsfixupoffset + 6, dbytecount)
- || !smbbufferoffsetputs(ob, countsfixupoffset + 8, doffset)
- || !smbbufferoffsetputs(ob, countsfixupoffset + 10, smbbufferreadoffset(t->out.data)))
- goto toosmall;
- assert(smbbufferoffsetputs(ob, bytecountfixupoffset, smbbufferwriteoffset(ob) - bytecountfixupoffset - 2));
- smbbuffergetbytes(t->out.parameters, nil, pbytecount);
- smbbuffergetbytes(t->out.data, nil, dbytecount);
- return 1;
- }
- int
- smbtransactionencoderesponse(SmbTransaction *t, SmbHeader *h, SmbPeerInfo *p, SmbBuffer *ob, char **errmsgp)
- {
- return _transactionencoderesponse(t, h, p, ob, SMB_COM_TRANSACTION, errmsgp);
- }
- int
- smbtransactionencoderesponse2(SmbTransaction *t, SmbHeader *h, SmbPeerInfo *p, SmbBuffer *ob, char **errmsgp)
- {
- return _transactionencoderesponse(t, h, p, ob, SMB_COM_TRANSACTION2, errmsgp);
- }
- int
- smbtransactionrespond(SmbTransaction *t, SmbHeader *h, SmbPeerInfo *p, SmbBuffer *ob, SmbTransactionMethod *method, void *magic, char **errmsgp)
- {
- /* generate one or more responses */
- while (smbbufferreadspace(t->out.parameters) || smbbufferreadspace(t->out.data)) {
- assert(method->encoderesponse);
- if (!(*method->encoderesponse)(t, h, p, ob, errmsgp))
- return 0;
- assert(method->sendresponse);
- if (!(*method->sendresponse)(magic, ob, errmsgp))
- return 0;
- }
- return 1;
- }
- int
- smbtransactionnbdgramsend(void *magic, SmbBuffer *ob, char **errmsgp)
- {
- NbDgramSendParameters *p = magic;
- //print("sending to %B\n", p->to);
- //nbdumpdata(smbbufferreadpointer(ob), smbbufferreadspace(ob));
- if (!nbdgramsend(p, smbbufferreadpointer(ob), smbbufferreadspace(ob))) {
- smbstringprint(errmsgp, "dgram send failed");
- return 0;
- }
- return 1;
- }
- SmbTransactionMethod smbtransactionmethoddgram = {
- .encodeprimary = smbtransactionencodeprimary,
- .sendrequest = smbtransactionnbdgramsend,
- .encoderesponse = smbtransactionencoderesponse,
- };
- int
- smbtransactionexecute(SmbTransaction *t, SmbHeader *h, SmbPeerInfo *p, SmbBuffer *iob, SmbTransactionMethod *method, void *magic, SmbHeader *rhp, char **errmsgp)
- {
- uchar sentwordcount;
- ushort sentbytecount;
- SmbHeader rh;
- smbbufferreset(iob);
- if (!(*method->encodeprimary)(t, h, p, iob, &sentwordcount, &sentbytecount, errmsgp))
- return 0;
- // smblogprint(-1, "sent...\n");
- // smblogdata(-1, smblogprint, smbbufferreadpointer(iob), smbbufferreadspace(iob));
- if (!(*method->sendrequest)(magic, iob, errmsgp))
- return 0;
- if (t->in.pcount < t->in.tpcount || t->in.dcount < t->in.tdcount) {
- uchar wordcount;
- ushort bytecount;
- /* secondary needed */
- if (method->encodesecondary == nil || method->receiveintermediate == nil) {
- smbstringprint(errmsgp, "buffer too small and secondaries not allowed");
- return 0;
- }
- if (!(*method->receiveintermediate)(magic, &wordcount, &bytecount, errmsgp))
- return 0;
- if (sentwordcount != wordcount || sentbytecount != bytecount) {
- smbstringprint(errmsgp, "server intermediate reply counts differ");
- return 0;
- }
- do {
- if (!(*method->encodesecondary)(t, h, iob, errmsgp))
- return 0;
- if (!(*method->sendrequest)(magic, iob, errmsgp))
- return 0;
- } while (t->in.pcount < t->in.tpcount || t->in.dcount < t->in.tdcount);
- }
- if (method->receiveresponse == nil || method->decoderesponse == nil)
- return 1;
- do {
- uchar *pdata;
- ushort bytecount;
- if (!(*method->receiveresponse)(magic, iob, errmsgp))
- return 0;
- if (!smbbuffergetheader(iob, &rh, &pdata, &bytecount)) {
- smbstringprint(errmsgp, "smbtransactionexecute: invalid response header");
- return 0;
- }
- if (!smbcheckheaderdirection(&rh, 1, errmsgp))
- return 0;
- if (rh.errclass != SUCCESS) {
- smbstringprint(errmsgp, "smbtransactionexecute: remote error %d/%d", rh.errclass, rh.error);
- return 0;
- }
- if (!smbbuffertrimreadlen(iob, bytecount)) {
- smbstringprint(errmsgp, "smbtransactionexecute: invalid bytecount");
- return 0;
- }
- // smblogprint(-1, "received...\n");
- // smblogdata(-1, smblogprint, smbbufferreadpointer(iob), smbbufferreadspace(iob));
- if (!(*method->decoderesponse)(t, &rh, pdata, iob, errmsgp))
- return 0;
- } while (smbbufferwriteoffset(t->out.parameters) < t->out.tpcount || smbbufferwriteoffset(t->out.data) < t->out.tdcount);
- if (rhp)
- *rhp = rh;
- return 1;
- }
|