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); }
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; }
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; }
int smbresponsecpy(SmbSession *s, uchar *data, ushort datalen) { return smbbufferputbytes(s->response, data, datalen); }
int smbresponseskip(SmbSession *sess, ushort amount) { return smbbufferputbytes(sess->response, nil, amount); }
int smbresponsecpy(SmbSession *s, uint8_t *data, uint16_t datalen) { return smbbufferputbytes(s->response, data, datalen); }
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; }