SmbProcessResult smbresponsesend(SmbSession *s) { uchar cmd; SmbProcessResult pr; assert(smbbufferoffsetgetb(s->response, 4, &cmd)); smbloglock(); smblogprint(cmd, "sending:\n"); smblogdata(cmd, smblogprint, smbbufferreadpointer(s->response), smbbufferreadspace(s->response), 256); smblogunlock(); if (s->nbss) { NbScatterGather a[2]; a[0].p = smbbufferreadpointer(s->response); a[0].l = smbbufferreadspace(s->response); a[1].p = nil; nbssgatherwrite(s->nbss, a); pr = SmbProcessResultOk; } else if (s->cifss) { ulong l = smbbufferreadspace(s->response); uchar nl[4]; hnputl(nl, l); write(s->cifss->fd, nl, 4); write(s->cifss->fd, smbbufferreadpointer(s->response), l); pr = SmbProcessResultOk; } else pr = SmbProcessResultDie; smbbufferreset(s->response); return pr; }
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 smbbuffergetheader(SmbBuffer *b, SmbHeader *h, uint8_t **parametersp, uint16_t *bytecountp) { SmbOpTableEntry *ote; SmbRawHeader *rh; rh = (SmbRawHeader *)smbbufferreadpointer(b); if (!smbbuffergetbytes(b, nil, (int32_t)offsetof(SmbRawHeader, parameterwords[0]))) { smblogprint(-1, "smbgetheader: short packet\n"); return 0; } if (rh->protocol[0] != 0xff || memcmp(rh->protocol + 1, "SMB", 3) != 0) { smblogprint(-1, "smbgetheader: invalid protocol\n"); return 0; } h->command = rh->command; ote = smboptable + h->command; if (ote->name == nil) { smblogprint(-1, "smbgetheader: illegal opcode 0x%.2ux\n", h->command); return 0; } h->errclass = rh->status[0]; h->error = smbnhgets(rh->status + 2); h->flags = rh->flags; h->flags2 = smbnhgets(rh->flags2); if (h->flags & ~(SmbHeaderFlagCaseless | SMB_FLAGS_SERVER_TO_REDIR | SmbHeaderFlagReserved | SmbHeaderFlagServerIgnore)) smblogprint(-1, "smbgetheader: warning: unexpected flags 0x%.2ux\n", h->flags); h->wordcount = rh->wordcount; if (parametersp) *parametersp = smbbufferreadpointer(b); if (!smbbuffergetbytes(b, nil, h->wordcount * 2)) { smblogprint(-1, "smbgetheader: not enough data for parameter words\n"); return 0; } h->tid = smbnhgets(rh->tid); h->pid = smbnhgets(rh->pid); h->uid = smbnhgets(rh->uid); h->mid = smbnhgets(rh->mid); if (!smbbuffergets(b, bytecountp)) *bytecountp = 0; if (!smbbufferpushreadlimit(b, smbbufferreadoffset(b) + *bytecountp)) return 0; smblogprint(h->command, "%s %s: tid 0x%.4ux pid 0x%.4ux uid 0x%.4ux mid 0x%.4ux\n", ote->name, (h->flags & SMB_FLAGS_SERVER_TO_REDIR) ? "response" : "request", h->tid, h->pid, h->uid, h->mid); return 1; }
int smbbuffercopy(SmbBuffer *to, SmbBuffer *from, ulong amount) { if (smbbufferreadspace(from) < amount) return 0; if (smbbufferputbytes(to, smbbufferreadpointer(from), amount)) { assert(smbbuffergetbytes(from, nil, amount)); return 1; } return 0; }
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; }
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 smbclienttrans2(SmbClient *c, uchar scount, ushort *setup, SmbBuffer *inparam, SmbBuffer *outparam, SmbBuffer *outdata, SmbHeader *rh, char **errmsgp) { SmbTransaction transaction; SmbHeader h; memset(&transaction, 0, sizeof(transaction)); transaction.in.scount = scount; transaction.in.setup = setup; transaction.in.parameters = smbbufferreadpointer(inparam); transaction.in.tpcount = smbbufferreadspace(inparam); transaction.in.maxpcount = smbbufferwritespace(outparam); transaction.in.maxdcount = smbbufferwritespace(outdata); transaction.out.parameters = outparam; transaction.out.data = outdata; h = c->protoh; h.tid = c->sharetid; h.mid = 0; return smbtransactionexecute(&transaction, &h, &c->peerinfo, c->b, &method, c, rh, errmsgp); }
int smbclientrap(SmbClient *c, SmbBuffer *inparam, SmbBuffer *outparam, SmbBuffer *outdata, char **errmsgp) { SmbTransaction transaction; SmbHeader h; memset(&transaction, 0, sizeof(transaction)); transaction.in.name = smbglobals.pipelanman; transaction.in.parameters = smbbufferreadpointer(inparam); transaction.in.tpcount = smbbufferreadspace(inparam); transaction.in.maxpcount = smbbufferwritespace(outparam); transaction.in.maxdcount = smbbufferwritespace(outdata); transaction.out.parameters = outparam; transaction.out.data = outdata; h = c->protoh; h.tid = c->ipctid; h.mid = 0; return smbtransactionexecute(&transaction, &h, &c->peerinfo, c->b, &smbtransactionmethodrap, c, nil, errmsgp); }
SmbProcessResult smbchaincommand(SmbSession *s, SmbHeader *h, uint32_t andxoffsetfixup, uint8_t cmd, uint16_t offset, SmbBuffer *b) { SmbOpTableEntry *ote; uint8_t *pdata; uint16_t bytecount; h->command = cmd; ote = smboptable + cmd; if (ote->process == nil) { smblogprint(-1, "smbchaincommand: %s (0x%.2ux) not implemented\n", ote->name, cmd); return SmbProcessResultUnimp; } if (!smbresponsealignl2(s, 2) || !smbresponseoffsetputs(s, andxoffsetfixup, smbresponseoffset(s)) || !smbbufferpopreadlimit(b)) return SmbProcessResultMisc; if (!smbbufferreadskipto(b, offset)) { smblogprint(-1, "smbchaincommand: illegal offset\n"); return SmbProcessResultFormat; } if (!smbbuffergetb(b, &h->wordcount)) { smblogprint(-1, "smbchaincommand: not enough space for wordcount\n"); return SmbProcessResultFormat; } pdata = smbbufferreadpointer(b); if (!smbbuffergetbytes(b, nil, h->wordcount * 2)) { smblogprint(-1, "smbchaincommand: not enough space for parameters\n"); return SmbProcessResultFormat; } if (!smbbuffergets(b, &bytecount)) { smblogprint(-1, "smbchaincommand: not enough space for bytecount\n"); return SmbProcessResultFormat; } if (!smbbufferpushreadlimit(b, smbbufferreadoffset(b) + bytecount)) { smblogprint(-1, "smbchaincommand: not enough space for bytes\n"); return SmbProcessResultFormat; } smblogprint(cmd, "chaining to %s\n", ote->name); return (*ote->process)(s, h, pdata, b); }
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; }
int smbclienttrans2findfirst2(SmbClient *c, ushort searchcount, char *filename, ushort *sidp, ushort *searchcountp, ushort *endofsearchp,SmbFindFileBothDirectoryInfo *ip, char **errmsgp) { int rv; ushort setup; SmbBuffer *inparam; SmbBuffer *outparam; SmbBuffer *outdata; SmbHeader rh; setup = SMB_TRANS2_FIND_FIRST2; inparam = smbbuffernew(512); smbbufferputs(inparam, 0x16); smbbufferputs(inparam, searchcount); smbbufferputs(inparam, 7); smbbufferputs(inparam, SMB_FIND_FILE_BOTH_DIRECTORY_INFO); smbbufferputl(inparam, 0); smbbufferputstring(inparam, &c->peerinfo, 0, filename); outparam = smbbuffernew(10); outdata = smbbuffernew(65535); rv = smbclienttrans2(c, 1, &setup, inparam, outparam, outdata, &rh, errmsgp); smbbufferfree(&inparam); if (rv) { ushort eaerroroffset, lastnameoffset; ulong nextentry; int i; if (!smbbuffergets(outparam, sidp) || !smbbuffergets(outparam, searchcountp) || !smbbuffergets(outparam, endofsearchp) || !smbbuffergets(outparam, &eaerroroffset) || !smbbuffergets(outparam, &lastnameoffset)) { smbstringprint(errmsgp, "smbclienttrans2findfirst2: not enough parameters returned"); rv = 0; goto done; } nextentry = 0; smblogprint(-1, "returned data:\n"); smblogdata(-1, smblogprint, smbbufferreadpointer(outdata), smbbufferreadspace(outdata), 256); for (i = 0; i < *searchcountp; i++) { SmbFindFileBothDirectoryInfo *info = ip + i; ulong neo, filenamelength, easize; uchar shortnamelength; if (i && !smbbufferreadskipto(outdata, nextentry)) { underflow: smbstringprint(errmsgp, "smbclientrans2findfirst2: not enough data returned"); rv = 0; goto done; } if (!smbbuffergetl(outdata, &neo)) goto underflow; nextentry = smbbufferreadoffset(outdata) + neo - 4; print("neo 0x%.8lux\n", neo); if (!smbbuffergetl(outdata, &info->fileindex) || !smbbuffergetv(outdata, &info->creationtime) || !smbbuffergetv(outdata, &info->lastaccesstime) || !smbbuffergetv(outdata, &info->lastwritetime) || !smbbuffergetv(outdata, &info->changetime) || !smbbuffergetv(outdata, &info->endoffile) || !smbbuffergetv(outdata, &info->allocationsize)) goto underflow; print("got here\n"); if (!smbbuffergetl(outdata, &info->extfileattributes) || !smbbuffergetl(outdata, &filenamelength) || !smbbuffergetl(outdata, &easize) || !smbbuffergetb(outdata, &shortnamelength) || !smbbuffergetbytes(outdata, nil, 1) || !smbbuffergetbytes(outdata, nil, 24) || !smbbuffergetstring(outdata, &rh, SMB_STRING_REVPATH, &info->filename)) goto underflow; print("got here as well\n"); } } done: smbbufferfree(&outparam); smbbufferfree(&outdata); return rv; }
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; }
SmbProcessResult smbcomwrite(SmbSession *s, SmbHeader *h, uchar *pdata, SmbBuffer *b) { SmbTree *t; SmbFile *f; ushort fid; ushort count; ulong offset; long nb; ushort yacount; uchar fmt; if (h->wordcount != 5) return SmbProcessResultFormat; fid = smbnhgets(pdata); pdata += 2; count = smbnhgets(pdata); pdata += 2; offset = smbnhgetl(pdata); smblogprint(SMB_COM_WRITE, "smbcomwrite: fid 0x%.4ux count 0x%.4ux offset 0x%.8lux\n", fid, count, offset); if (!smbbuffergetb(b, &fmt) || fmt != 1 || !smbbuffergets(b, &yacount) || yacount != count || smbbufferreadspace(b) < count) return SmbProcessResultFormat; 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; } if (count == 0) { SmbProcessResult pr = smbtruncatefile(s, f, offset); if (pr != SmbProcessResultReply) return pr; nb = 0; } else { seek(f->fd, offset, 0); nb = write(f->fd, smbbufferreadpointer(b), count); if (nb < 0) { smbseterror(s, ERRDOS, ERRnoaccess); return SmbProcessResultError; } } h->wordcount = 1; if (!smbbufferputheader(s->response, h, &s->peerinfo) || !smbbufferputs(s->response, nb) || !smbbufferputs(s->response, 0)) return SmbProcessResultMisc; return SmbProcessResultReply; }
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; }