int smbtransactiondecoderesponse2(SmbTransaction *t, SmbHeader *h, uint8_t *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 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; }
SmbService * smbservicefind(SmbSession *s, char *uncpath, char *servicetype, uint8_t *errclassp, uint16_t *errorp) { char *p, *q; if ((uncpath[0] == '/' && uncpath[1] == '/') || (uncpath[0] == '\\' && uncpath[1] == '\\')) { /* check that the server name matches mine */ p = uncpath + 2; q = strchr(p, uncpath[0]); if (q == nil) goto bad; *q++ = 0; // if (cistrcmp(p, smbglobals.serverinfo.name) != 0) // goto bad; } else q = uncpath + 1; if (strcmp(servicetype, "?????") == 0 && strcmp(q, "IPC$") == 0) return &ipc; if ((strcmp(servicetype, "?????") == 0 || strcmp(servicetype, "A:") == 0)) { SmbService *serv; if (cistrcmp(q, local.name) == 0) return &local; /* try the session specific list */ for (serv = s->serv; serv; serv = serv->next) if (cistrcmp(q, serv->name) == 0) return serv; /* exec "9fs q" in case it invents /n/q */ for (p = q; *p; p++) if (*p >= 'A' && *p <= 'Z') *p = tolower(*p); if (run9fs(q) >= 0) { serv = smbemallocz(sizeof(*serv), 1); serv->name = smbestrdup(q); serv->type = smbestrdup("A:"); serv->stype = STYPE_DISKTREE; smbstringprint(&serv->remark, "9fs %s", q); smbstringprint(&serv->path, "/n/%s", q); serv->next = s->serv; s->serv = serv; return serv; } } bad: *errclassp = ERRDOS; *errorp = ERRbadpath; return nil; }
SmbProcessResult smbcomcreatedirectory(SmbSession *s, SmbHeader *h, uint8_t *, SmbBuffer *b) { int fd; char *path; char *fullpath = nil; SmbTree *t; uint8_t fmt; if (h->wordcount != 0) return SmbProcessResultFormat; if (!smbbuffergetb(b, &fmt) || fmt != 0x04 || !smbbuffergetstring(b, h, SMB_STRING_PATH, &path)) return SmbProcessResultFormat; smblogprint(h->command, "smbcomcreatedirectory: %s\n", path); t = smbidmapfind(s->tidmap, h->tid); if (t == nil) { smbseterror(s, ERRSRV, ERRinvtid); return SmbProcessResultError; } smbstringprint(&fullpath, "%s%s", t->serv->path, path); fd = create(fullpath, OREAD, DMDIR | 0775); if (fd < 0) { smblogprint(h->command, "smbcomcreatedirectory failed: %r\n"); smbseterror(s, ERRDOS, ERRnoaccess); free(path); return SmbProcessResultError; } close(fd); free(fullpath); free(path); return smbbufferputack(s->response, h, &s->peerinfo); }
int smbbuffergetandcheckheader(SmbBuffer *b, SmbHeader *h, uchar command, int response, uchar **pdatap, ushort *bytecountp, char **errmsgp) { if (!smbbuffergetheader(b, h, pdatap, bytecountp)) { smbstringprint(errmsgp, "smbbuffergetandcheckheader: not enough data for header"); return 0; } return smbcheckheader(h, command, response, errmsgp); }
int smbcheckheaderdirection(SmbHeader *h, int response, char **errmsgp) { if (((h->flags & SMB_FLAGS_SERVER_TO_REDIR) == 0) == response) { smbstringprint(errmsgp, "unexpected %s", response ? "request" : "response"); return 0; } return 1; }
int smbsuccess(SmbHeader *h, char **errmsgp) { if (h->errclass != SUCCESS) { smbstringprint(errmsgp, "%s returned error %d/%d", smboptable[h->command].name, h->errclass, h->error); return 0; } return 1; }
int smbcheckheader(SmbHeader *h, uint8_t command, int response, char **errmsgp) { if (response && h->command != command) { smbstringprint(errmsgp, "sent %.2uc request, got %.2ux response", command, h->command); return 0; } if (!smbcheckheaderdirection(h, response, 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; }
static int sendresponse(void *magic, SmbBuffer *, char **errmsgp) { int rv; SmbSession *s = magic; rv = smbresponsesend(s); if (rv < 0) { smbstringprint(errmsgp, "sendresponse 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; }
SmbProcessResult smbtruncatefile(SmbSession *s, SmbFile *f, vlong offset) { Dir *d; ulong o; uchar *db = nil; vlong length; int rv; SmbProcessResult pr; d = dirfstat(f->fd); assert(d); length = d->length; free(d); if (length == offset) return SmbProcessResultReply; rv = dirfwstatlength(f->fd, offset); if (rv == 0) { pr = SmbProcessResultReply; goto done; } //smblogprint(-1, "dirfwstatlength failed: %r\n"); if (length > offset) { int nfd; char *fullpath; if (offset > INMEMORYTRUNCTHRESH) { smblogprint(-1, "smbcomwrite: truncation beyond %lud not supported\n", offset); pr = SmbProcessResultUnimp; goto done; } db = smbemalloc(offset); if (pread(f->fd, db, offset, 0) != offset) { pr = SmbProcessResultMisc; goto done; } fullpath = nil; smbstringprint(&fullpath, "%s%s", f->t->serv->path, f->name); nfd = open(fullpath, f->p9mode | OTRUNC); free(fullpath); if (nfd < 0) { smbseterror(s, ERRDOS, ERRnoaccess); pr = SmbProcessResultError; goto done; } close(nfd); if (pwrite(f->fd, db, offset, 0) != offset) { pr = SmbProcessResultMisc; goto done; } pr = SmbProcessResultReply; } else { db = smbemalloc(16384); memset(db, 0, 16384); o = length; while (o < offset) { long tt = 16384; if (tt > offset - o) tt = offset - o; if (pwrite(f->fd, db, tt, o) != tt) { smbseterror(s, ERRDOS, ERRnoaccess); pr = SmbProcessResultError; goto done; } o += tt; } pr = SmbProcessResultReply; } done: free(db); return pr; }
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; }
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 _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; }
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; }
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 smbnetserverenum2(SmbClient *c, uint32_t stype, char *domain, int *entriesp, SmbRapServerInfo1 **sip, char **errmsgp) { int rv; uint16_t ec, entries, total, converter; SmbRapServerInfo1 *si = nil; SmbBuffer *ipb = smbbuffernew(512); SmbBuffer *odb = smbbuffernew(65535); SmbBuffer *opb = smbbuffernew(8); smbbufferputs(ipb, 104); smbbufferputstring(ipb, nil, SMB_STRING_ASCII, "WrLehDz"); smbbufferputstring(ipb, nil, SMB_STRING_ASCII, "B16BBDz"); smbbufferputs(ipb, 1); smbbufferputs(ipb, smbbufferwritespace(odb)); smbbufferputl(ipb, stype); smbbufferputstring(ipb, nil, SMB_STRING_ASCII, domain); rv = !smbclientrap(c, ipb, opb, odb, errmsgp); smbbufferfree(&ipb); if (rv == 0) { char *remark, *eremark; int remarkspace; int i; if (!smbbuffergets(opb, &ec) || !smbbuffergets(opb, &converter) || !smbbuffergets(opb, &entries) || !smbbuffergets(opb, &total)) { smbstringprint(errmsgp, "smbnetserverenum2: not enough return parameters"); rv = -1; goto done; } if (ec != 0) { rv = ec; goto done; } if (smbbufferreadspace(odb) < entries * 26) { smbstringprint(errmsgp, "smbnetserverenum2: not enough return data"); rv = -1; goto done; } remarkspace = smbbufferreadspace(odb) - entries * 26; si = smbemalloc(entries * sizeof(SmbRapServerInfo1) + remarkspace); remark = (char *)&si[entries]; eremark = remark + remarkspace; for (i = 0; i < entries; i++) { uint32_t offset; int remarklen; assert(smbbuffergetbytes(odb, si[i].name, 16)); assert(smbbuffergetb(odb, &si[i].vmaj)); assert(smbbuffergetb(odb, &si[i].vmin)); assert(smbbuffergetl(odb, &si[i].type)); assert(smbbuffergetl(odb, &offset)); offset -= converter; if (!smbbufferoffsetcopystr(odb, offset, remark, eremark - remark, &remarklen)) { smbstringprint(errmsgp, "smbnetserverenum2: invalid string offset"); rv = -1; goto done; } si[i].remark = remark; remark += remarklen; } *sip = si; si = nil; *entriesp = entries; } else rv = -1; done: free(si); smbbufferfree(&opb); smbbufferfree(&odb); return rv; }
SmbProcessResult smbtrans2setpathinformation(SmbSession *s, SmbHeader *h) { char *fullpath, *path; SmbTree *t; ushort infolevel; SmbBuffer *b; SmbProcessResult pr; ushort atime, adate, mtime, mdate; ulong attr; ulong mode; ulong size; // uvlong length; t = smbidmapfind(s->tidmap, h->tid); if (t == nil) { smbseterror(s, ERRSRV, ERRinvtid); pr = SmbProcessResultError; goto done; } b = smbbufferinit(s->transaction.in.parameters, s->transaction.in.parameters, s->transaction.in.tpcount); path = nil; if (!smbbuffergets(b, &infolevel) || !smbbuffergetbytes(b, nil, 4) || !smbbuffergetstring(b, h, SMB_STRING_PATH, &path)) { misc: pr = SmbProcessResultMisc; goto done; } fullpath = nil; smbstringprint(&fullpath, "%s%s", t->serv->path, path); translogprint(s->transaction.in.setup[0], "path %s\n", path); translogprint(s->transaction.in.setup[0], "infolevel 0x%.4ux\n", infolevel); translogprint(s->transaction.in.setup[0], "fullpath %s\n", fullpath); switch (infolevel) { case SMB_INFO_STANDARD: if (s->transaction.in.tdcount < 6 * 4 + 2 * 2) goto misc; adate = smbnhgets(s->transaction.in.data + 6); atime = smbnhgets(s->transaction.in.data + 4); mdate = smbnhgets(s->transaction.in.data + 10); mtime = smbnhgets(s->transaction.in.data + 8); size = smbnhgetl(s->transaction.in.data + 12); attr = smbnhgets(s->transaction.in.data + 20); if (attr) { Dir *od = dirstat(fullpath); if (od == nil) goto noaccess; mode = smbdosattr2plan9wstatmode(od->mode, attr); free(od); } else mode = 0xffffffff; translogprint(s->transaction.in.setup[0], "mode 0%od\n", mode); // if (size) // length = size; // else // length = ~0LL; translogprint(s->transaction.in.setup[0], "size %lld\n", size); translogprint(s->transaction.in.setup[0], "adate %d atime %d", adate, atime); translogprint(s->transaction.in.setup[0], "mdate %d mtime %d\n", mdate, mtime); if (size || adate || atime || mdate || mtime || mode != 0xffffffff) { Dir d; memset(&d, 0xff, sizeof(d)); d.name = d.uid = d.gid = d.muid = nil; if (adate || atime) d.atime = smbdatetime2plan9time(adate, atime, s->tzoff); if (mdate || mtime) d.mtime = smbdatetime2plan9time(mdate, mtime, s->tzoff); d.mode = mode; d.length = size; if (dirwstat(fullpath, &d) < 0) { noaccess: smbseterror(s, ERRDOS, ERRnoaccess); pr = SmbProcessResultError; goto done; } } if (!smbbufferputs(s->transaction.out.parameters, 0)) goto misc; pr = SmbProcessResultReply; break; default: smblogprint(-1, "smbtrans2setpathinformation: infolevel 0x%.4ux not implemented\n", infolevel); smbseterror(s, ERRDOS, ERRunknownlevel); pr = SmbProcessResultError; break; } done: smbbufferfree(&b); return pr; }