static int findbothflatten(SmbBuffer *b, SmbPeerInfo *p, Dir *d, ulong resumekey, ulong *nameoffsetp) { vlong mtime, atime; ulong fixup; fixup = smbbufferwriteoffset(b); mtime = smbplan9time2time(d->mtime); atime = smbplan9time2time(d->atime); poolcheck(mainmem); if (!smbbufferputl(b, 0) || !smbbufferputl(b, resumekey) || !smbbufferputv(b, mtime) || !smbbufferputv(b, atime) || !smbbufferputv(b, mtime) || !smbbufferputv(b, mtime) || !smbbufferputv(b, d->length) || !smbbufferputv(b, smbl2roundupvlong(d->length, smbglobals.l2allocationsize)) // ha || !smbbufferputl(b, (d->qid.type & QTDIR) ? 0x10 : 0x80) || !smbbufferputl(b, smbstringlen(p, d->name)) || !smbbufferputl(b, 0) || !smbbufferputb(b, 0) || !smbbufferputb(b, 0) || !smbbufferfill(b, 0, 24)) return 0; poolcheck(mainmem); *nameoffsetp = smbbufferwriteoffset(b); if (!smbbufferputstring(b, p, 0, d->name) || !smbbufferalignl2(b, 2)) return 0; poolcheck(mainmem); return smbbufferfixuprelativeinclusivel(b, fixup); }
static int standardflatten(SmbSession *s, SmbBuffer *b, Dir *d, ulong *nameoffsetp) { ushort mdate, mtime; ushort adate, atime; ushort fnlfixupoffset; smbplan9time2datetime(d->mtime, s->tzoff, &mdate, &mtime); smbplan9time2datetime(d->atime, s->tzoff, &adate, &atime); if (!smbbufferputs(b, mdate) || !smbbufferputs(b, mtime) || !smbbufferputs(b, adate) || !smbbufferputs(b, atime) || !smbbufferputs(b, mdate) || !smbbufferputs(b, mtime) || !smbbufferputl(b, d->length) || !smbbufferputl(b, 512) // ha || !smbbufferputs(b, (d->qid.type & QTDIR) ? 0x10 : 0)) return 0; fnlfixupoffset = smbbufferwriteoffset(b); if (!smbbufferputs(b, 0)) return 0; *nameoffsetp = smbbufferwriteoffset(b); if (!smbbufferputstring(b, &s->peerinfo, 0, d->name)) return 0; return smbbufferfixuprelatives(b, fnlfixupoffset); }
int smbclientopen(SmbClient *c, uint16_t mode, char *name, uint8_t *errclassp, uint16_t *errorp, uint16_t *fidp, uint16_t *attrp, uint32_t *mtimep, uint32_t *sizep, uint16_t *accessallowedp, char **errmsgp) { SmbBuffer *b; SmbHeader h; uint32_t bytecountfixup; int32_t n; uint8_t *pdata; uint16_t bytecount; b = smbbuffernew(65535); h = c->protoh; h.tid = c->sharetid; h.command = SMB_COM_OPEN; h.wordcount = 2; smbbufferputheader(b, &h, &c->peerinfo); smbbufferputs(b, mode); smbbufferputs(b, 0); bytecountfixup = smbbufferwriteoffset(b); smbbufferputs(b, 0); smbbufferputb(b, 4); smbbufferputstring(b, &c->peerinfo, SMB_STRING_REVPATH, name); smbbufferfixuprelatives(b, bytecountfixup); nbsswrite(c->nbss, smbbufferreadpointer(b), smbbufferwriteoffset(b)); smbbufferreset(b); n = nbssread(c->nbss, smbbufferwritepointer(b), smbbufferwritespace(b)); if (n < 0) { smbstringprint(errmsgp, "read error: %r"); smbbufferfree(&b); return 0; } smbbuffersetreadlen(b, n); if (!smbbuffergetandcheckheader(b, &h, h.command, 7, &pdata, &bytecount, errmsgp)) { smbbufferfree(&b); return 0; } if (h.errclass) { *errclassp = h.errclass; *errorp = h.error; smbbufferfree(&b); return 0; } *fidp = smbnhgets(pdata); pdata += 2; *attrp = smbnhgets(pdata); pdata += 2; *mtimep = smbnhgetl(pdata); pdata += 4; *sizep = smbnhgets(pdata); pdata += 4; *accessallowedp = smbnhgets(pdata); 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 smbbufferputheader(SmbBuffer *b, SmbHeader *h, SmbPeerInfo *p) { SmbRawHeader *rh; if (offsetof(SmbRawHeader, parameterwords[0]) > smbbufferwritespace(b)) return 0; if (smbbufferwriteoffset(b) == 0) { rh = (SmbRawHeader *)smbbufferwritepointer(b); rh->protocol[0] = 0xff; memcpy(rh->protocol + 1, "SMB", 3); rh->flags = SMB_FLAGS_SERVER_TO_REDIR | SmbHeaderFlagCaseless; rh->command = h->command; smbhnputs(rh->flags2, BASE_FLAGS | (smbsendunicode(p) ? SMB_FLAGS2_UNICODE : 0)); memset(rh->extra, 0, sizeof(rh->extra)); if (!smbbufferputbytes(b, nil, offsetof(SmbRawHeader, parameterwords[0]))) return 0; rh->wordcount = h->wordcount; } else { rh = (SmbRawHeader *)smbbufferreadpointer(b); smbbufferputb(b, h->wordcount); } rh->status[0] = h->errclass; rh->status[1] = 0; smbhnputs(rh->status + 2, h->error); smbhnputs(rh->tid, h->tid); smbhnputs(rh->pid, h->pid); smbhnputs(rh->uid, h->uid); smbhnputs(rh->mid, h->mid); return 1; }
int smbbufferputandxheader(SmbBuffer *b, SmbHeader *h, SmbPeerInfo *p, uchar andxcommand, ulong *andxoffsetfixupp) { if (!smbbufferputheader(b, h, p) || !smbbufferputb(b, andxcommand) || !smbbufferputb(b, 0)) return 0; *andxoffsetfixupp = smbbufferwriteoffset(b); return smbbufferputbytes(b, nil, 2); }
static void populate(SmbSession *s, SmbDirCache *dc, Reprog *r, ushort informationlevel, ushort flags, ushort scount, ushort *ep, ulong *nameoffsetp) { ushort e; ulong nameoffset; e = 0; nameoffset = 0; while (dc->i < dc->n && e < scount) { ulong backup; int rv; if (!smbmatch(dc->buf[dc->i].name, r)) { dc->i++; continue; } rv = 0; backup = smbbufferwriteoffset(s->transaction.out.data); switch (informationlevel) { case SMB_INFO_STANDARD: if (flags & SMB_FIND_RETURN_RESUME_KEYS) { if (!smbbufferputl(s->transaction.out.data, dc->i)) { rv = 0; break; } } rv = standardflatten(s, s->transaction.out.data, dc->buf + dc->i, &nameoffset); break; case SMB_FIND_FILE_BOTH_DIRECTORY_INFO: rv = findbothflatten(s->transaction.out.data, &s->peerinfo, dc->buf + dc->i, dc->i, &nameoffset); break; } if (rv == 0) { smbbufferwritebackup(s->transaction.out.data, backup); break; } dc->i++; e++; } *ep = e; *nameoffsetp = nameoffset; }
SmbProcessResult smbcomecho(SmbSession *s, SmbHeader *h, uchar *pdata, SmbBuffer *b) { ushort echocount, e; if (!smbcheckwordcount("comecho", h, 1)) return SmbProcessResultFormat; echocount = smbnhgets(pdata); for (e = 0; e < echocount; e++) { ulong bytecountfixupoffset; SmbProcessResult pr; if (!smbbufferputheader(s->response, h, &s->peerinfo) || !smbbufferputs(s->response, e)) return SmbProcessResultMisc; bytecountfixupoffset = smbbufferwriteoffset(s->response); if (!smbbufferputbytes(s->response, smbbufferreadpointer(b), smbbufferreadspace(b)) || !smbbufferfixuprelatives(s->response, bytecountfixupoffset)) return SmbProcessResultMisc; pr = smbresponsesend(s); if (pr != SmbProcessResultOk) return SmbProcessResultDie; } return SmbProcessResultOk; }
SmbProcessResult smbnegotiate(SmbSession *s, SmbHeader *h, uchar *, SmbBuffer *b) { ushort index; int i; uchar bufferformat; if (!smbcheckwordcount("negotiate", h, 0)) return SmbProcessResultFormat; if (s->state != SmbSessionNeedNegotiate) { /* this acts as a complete session reset */ smblogprint(-1, "smbnegotiate: called when already negotiated\n"); return SmbProcessResultUnimp; } i = 0; index = 0xffff; while (smbbuffergetb(b, &bufferformat)) { char *s; if (bufferformat != 0x02) { smblogprint(-1, "smbnegotiate: unrecognised buffer format 0x%.2ux\n", bufferformat); return SmbProcessResultFormat; } if (!smbbuffergetstr(b, 0, &s)) { smblogprint(-1, "smbnegotiate: no null found\n"); return SmbProcessResultFormat; } smblogprint(h->command, "smbnegotiate: '%s'\n", s); if (index == 0xffff && strcmp(s, "NT LM 0.12") == 0) index = i; i++; free(s); } if (index != 0xffff) { Tm *tm; ulong capabilities; ulong bytecountfixupoffset; h->wordcount = 17; if (!smbbufferputheader(s->response, h, nil) || !smbbufferputs(s->response, index) || !smbbufferputb(s->response, 3) /* user security, encrypted */ || !smbbufferputs(s->response, 1) /* max mux */ || !smbbufferputs(s->response, 1) /* max vc */ || !smbbufferputl(s->response, smbglobals.maxreceive) /* max buffer size */ || !smbbufferputl(s->response, 0x10000) /* max raw */ || !smbbufferputl(s->response, threadid())) /* session key */ goto die; /* <= Win2k insist upon this being set to ensure that they observe the prototol (!) */ capabilities = CAP_NT_SMBS; if (smbglobals.unicode) capabilities |= CAP_UNICODE; tm = localtime(time(nil)); s->tzoff = tm->tzoff; if (!smbbufferputl(s->response, capabilities) || !smbbufferputv(s->response, nsec() / 100 + (vlong)10000000 * 11644473600LL) || !smbbufferputs(s->response, -s->tzoff / 60) || !smbbufferputb(s->response, 8)) /* crypt len */ goto die; bytecountfixupoffset = smbbufferwriteoffset(s->response); if (!smbbufferputs(s->response, 0)) goto die; s->cs = auth_challenge("proto=mschap role=server"); if (s->cs == nil) { smblogprint(h->command, "smbnegotiate: couldn't get mschap challenge\n"); return SmbProcessResultMisc; } if (s->cs->nchal != 8) { smblogprint(h->command, "smbnegotiate: nchal %d\n", s->cs->nchal); return SmbProcessResultMisc; } if (!smbbufferputbytes(s->response, s->cs->chal, s->cs->nchal) || !smbbufferputstring(s->response, nil, SMB_STRING_UNICODE, smbglobals.primarydomain) || !smbbufferfixuprelatives(s->response, bytecountfixupoffset)) goto die; } else { h->wordcount = 1; if (!smbbufferputheader(s->response, h, nil) || !smbbufferputs(s->response, index) || !smbbufferputs(s->response, 0)) goto die; } s->state = SmbSessionNeedSetup; return SmbProcessResultReply; die: return SmbProcessResultDie; }
ushort smbresponseoffset(SmbSession *s) { return smbbufferwriteoffset(s->response); }
SmbProcessResult smbcomtreeconnectandx(SmbSession *s, SmbHeader *h, uint8_t *pdata, SmbBuffer *b) { uint8_t andxcommand; uint16_t andxoffset; char *path = nil; char *service = nil; uint16_t flags; uint16_t passwordlength; // ushort bytecount; uint8_t errclass; uint16_t error; SmbService *serv; SmbTree *tree; uint32_t andxfixupoffset, bytecountfixup; SmbProcessResult pr; if (!smbcheckwordcount("comtreeconnectandx", h, 4)) { fmtfail: pr = SmbProcessResultFormat; goto done; } switch (s->state) { case SmbSessionNeedNegotiate: smblogprint(-1, "smbcomtreeconnectandx: called when negotiate expected\n"); return SmbProcessResultUnimp; case SmbSessionNeedSetup: smbseterror(s, ERRDOS, ERRbadpw); return SmbProcessResultError; } andxcommand = *pdata++; switch (andxcommand) { case SMB_COM_OPEN: case SMB_COM_CREATE_NEW: case SMB_COM_DELETE_DIRECTORY: case SMB_COM_FIND_UNIQUE: case SMB_COM_CHECK_DIRECTORY: case SMB_COM_GET_PRINT_QUEUE: case SMB_COM_TRANSACTION: case SMB_COM_SET_INFORMATION: case SMB_COM_OPEN_ANDX: case SMB_COM_CREATE_DIRECTORY: case SMB_COM_FIND: case SMB_COM_RENAME: case SMB_COM_QUERY_INFORMATION: case SMB_COM_OPEN_PRINT_FILE: case SMB_COM_NO_ANDX_COMMAND: case SMB_COM_NT_RENAME: case SMB_COM_CREATE: case SMB_COM_DELETE: case SMB_COM_COPY: break; default: smblogprint(h->command, "smbcomtreeconnectandx: invalid andxcommand %s (0x%.2ux)\n", smboptable[andxcommand].name, andxcommand); goto fmtfail; } pdata++; andxoffset = smbnhgets(pdata); pdata += 2; flags = smbnhgets(pdata); pdata += 2; passwordlength = smbnhgets(pdata); //pdata += 2; // bytecount = smbnhgets(pdata); pdata += 2; smblogprint(h->command, "passwordlength: %ud\n", passwordlength); smblogprint(h->command, "flags: 0x%.4ux\n", flags); if (!smbbuffergetbytes(b, nil, passwordlength)) { smblogprint(h->command, "smbcomtreeconnectandx: not enough bytes for password\n"); goto fmtfail; } smblogprint(h->command, "offset %lud limit %lud\n", smbbufferreadoffset(b), smbbufferwriteoffset(b)); if (!smbbuffergetstring(b, h, SMB_STRING_PATH, &path) || !smbbuffergetstr(b, 0, &service)) { smblogprint(h->command, "smbcomtreeconnectandx: not enough bytes for strings\n"); goto fmtfail; } smblogprint(h->command, "path: %s\n", path); smblogprint(h->command, "service: %s\n", service); if (flags & 1) smbtreedisconnectbyid(s, h->tid); serv = smbservicefind(s, path, service, &errclass, &error); if (serv == nil) { pr = SmbProcessResultError; smbseterror(s, errclass, error); goto done; } tree = smbtreeconnect(s, serv); h->tid = tree->id; h->wordcount = 3; if (!smbresponseputandxheader(s, h, andxcommand, &andxfixupoffset) || !smbresponseputs(s, 1)) { misc: pr = SmbProcessResultMisc; goto done; } bytecountfixup = smbresponseoffset(s); if (!smbresponseputs(s, 0) || !smbresponseputstr(s, serv->type) || !smbresponseputstring(s, 1, s9p2000)) goto misc; if (!smbbufferfixuprelatives(s->response, bytecountfixup)) goto misc; if (andxcommand != SMB_COM_NO_ANDX_COMMAND) { pr = smbchaincommand(s, h, andxfixupoffset, andxcommand, andxoffset, b); } else pr = SmbProcessResultReply; done: free(path); free(service); return pr; }
SmbProcessResult smbcomwriteandx(SmbSession *s, SmbHeader *h, uchar *pdata, SmbBuffer *b) { uchar andxcommand; ushort andxoffset; ulong andxoffsetfixup; SmbTree *t; SmbFile *f; ushort dataoff, fid, count; vlong offset; long nb; if (h->wordcount != 12 && h->wordcount != 14) return SmbProcessResultFormat; andxcommand = *pdata++; // andx command pdata++; // reserved andxoffset = smbnhgets(pdata); pdata += 2; // andx offset fid = smbnhgets(pdata); pdata += 2; // fid offset = smbnhgetl(pdata); pdata += 4; // offset in file pdata += 4; // timeout pdata += 2; // write mode pdata += 2; // (Remaining) bytes waiting to be written pdata += 2; // Reserved count = smbnhgets(pdata); pdata += 2; // LSBs of length dataoff = smbnhgets(pdata); pdata += 2; // offset to data in packet if (dataoff + count > smbbufferwriteoffset(b)) return SmbProcessResultFormat; if(h->wordcount == 14) offset |= (vlong)smbnhgetl(pdata)<<32; smblogprint(SMB_COM_WRITE_ANDX, "smbcomwriteandx: fid 0x%.4ux count 0x%.4ux offset 0x%.llux\n", fid, count, offset); t = smbidmapfind(s->tidmap, h->tid); if (t == nil) { smbseterror(s, ERRSRV, ERRinvtid); return SmbProcessResultError; } f = smbidmapfind(s->fidmap, fid); if (f == nil) { smbseterror(s, ERRDOS, ERRbadfid); return SmbProcessResultError; } if (!f->ioallowed) { smbseterror(s, ERRDOS, ERRbadaccess); return SmbProcessResultError; } seek(f->fd, offset, 0); nb = write(f->fd, smbbufferpointer(b, dataoff), count); if (nb < 0) { smbseterror(s, ERRDOS, ERRnoaccess); return SmbProcessResultError; } h->wordcount = 6; if (!smbbufferputandxheader(s->response, h, &s->peerinfo, andxcommand, &andxoffsetfixup)) return SmbProcessResultMisc; if (!smbbufferputs(s->response, nb) // Count || !smbbufferputs(s->response, 0) // Available || !smbbufferputl(s->response, 0) // Reserved || !smbbufferputs(s->response, 0)) // byte count in reply return SmbProcessResultMisc; if (andxcommand != SMB_COM_NO_ANDX_COMMAND) return smbchaincommand(s, h, andxoffsetfixup, andxcommand, andxoffset, b); return SmbProcessResultReply; }
int smbtransactionexecute(SmbTransaction *t, SmbHeader *h, SmbPeerInfo *p, SmbBuffer *iob, SmbTransactionMethod *method, void *magic, SmbHeader *rhp, char **errmsgp) { uint8_t sentwordcount; uint16_t 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) { uint8_t wordcount; uint16_t 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 { uint8_t *pdata; uint16_t 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; }
int _transactionencoderesponse(SmbTransaction *t, SmbHeader *h, SmbPeerInfo *p, SmbBuffer *ob, uint8_t cmd, char **errmsgp) { SmbHeader mh; uint32_t countsfixupoffset, bytecountfixupoffset; int palign, dalign; uint32_t pbytecount, dbytecount; uint32_t 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(uint16_t)) || !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; }
static int _transactionencodeprimary(SmbTransaction *t, uint8_t cmd, SmbHeader *h, SmbPeerInfo *p, SmbBuffer *ob, uint8_t *wordcountp, uint16_t *bytecountp, char **errmsgp) { SmbHeader mh; uint32_t 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) { uint32_t align = smbbufferwriteoffset(ob) & 1; uint32_t 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) { uint32_t align = smbbufferwriteoffset(ob) & 1; uint32_t 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 _smbtransactiondecodeprimary(SmbTransaction *t, SmbHeader *h, uint8_t *pdata, SmbBuffer *b, int hasname, char **errmsgp) { uint16_t 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(uint16_t)); 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; }