SmbProcessResult smbcomsetinformation(SmbSession *s, SmbHeader *h, uint8_t *pdata, SmbBuffer *b) { uint16_t attr; uint32_t utime; char *name; if (h->wordcount != 8) return SmbProcessResultFormat; attr = smbnhgets(pdata); pdata += 2; utime = smbnhgetl(pdata); if (!smbbuffergetstring(b, h, SMB_STRING_PATH, &name)) return SmbProcessResultFormat; smblogprint(h->command, "smbcomsetinformation: attr 0x%.4ux utime %lud path %s\n", attr, utime, name); if (utime) { Dir d; memset(&d, 0xff, sizeof(d)); d.name = d.uid = d.gid = d.muid = nil; d.mtime = smbutime2plan9time(utime, s->tzoff); if (dirwstat(name, &d) < 0) { smbseterror(s, ERRDOS, ERRnoaccess); free(name); return SmbProcessResultError; } } free(name); return smbbufferputack(s->response, h, &s->peerinfo); }
int smbbuffergetl(SmbBuffer *b, ulong *lp) { if (b->rn + 4 <= b->wn) { *lp = smbnhgetl(b->buf + b->rn); b->rn += 4; return 1; } return 0; }
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 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; }
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; }
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; }
SmbProcessResult smbcomlockingandx(SmbSession *s, SmbHeader *h, uchar *pdata, SmbBuffer *b) { uchar andxcommand; ushort andxoffset; ulong andxoffsetfixup; ushort fid; uchar locktype; uchar oplocklevel; ulong timeout; ushort numberofunlocks; ushort numberoflocks; SmbTree *t; SmbFile *f; int l; SmbProcessResult pr; ulong backupoffset; int large; if (!smbcheckwordcount("comlockingandx", h, 8)) return SmbProcessResultFormat; andxcommand = *pdata++; pdata++; andxoffset = smbnhgets(pdata); pdata += 2; fid = smbnhgets(pdata); pdata += 2; locktype = *pdata++; oplocklevel = *pdata++; timeout = smbnhgetl(pdata); pdata += 4; numberofunlocks = smbnhgets(pdata); pdata += 2; numberoflocks = smbnhgets(pdata); smblogprint(h->command, "smbcomlockingandx: fid 0x%.4ux locktype 0x%.2ux oplocklevel 0x%.2ux timeout %lud numberofunlocks %d numberoflocks %ud\n", fid, locktype, oplocklevel, timeout, numberofunlocks, numberoflocks); large = locktype & 0x10; locktype &= ~0x10; if (locktype != 0 || oplocklevel != 0) { smblogprint(-1, "smbcomlockingandx: locktype 0x%.2ux unimplemented\n", locktype); return SmbProcessResultUnimp; } if (oplocklevel != 0) { smblogprint(-1, "smbcomlockingandx: oplocklevel 0x%.2ux unimplemented\n", oplocklevel); return SmbProcessResultUnimp; } t = smbidmapfind(s->tidmap, h->tid); if (t == nil) { smbseterror(s, ERRSRV, ERRinvtid); error: return SmbProcessResultError; } f = smbidmapfind(s->fidmap, fid); if (f == nil) { smbseterror(s, ERRDOS, ERRbadfid); goto error; } backupoffset = smbbufferreadoffset(b); for (l = 0; l < numberofunlocks; l++) { ushort pid; uvlong offset; uvlong length; if (!getlock(b, large, &pid, &offset, &length)) { pr = SmbProcessResultFormat; goto done; } smblogprint(h->command, "smbcomlockingandx: unlock pid 0x%.4ux offset %llud length %llud\n", pid, offset, length); smbsharedfileunlock(f->sf, s, h->pid, offset, offset + length); } for (l = 0; l < numberoflocks; l++) { ushort pid; uvlong offset; uvlong length; if (!getlock(b, large, &pid, &offset, &length)) { pr = SmbProcessResultFormat; goto done; } smblogprint(h->command, "smbcomlockingandx: lock pid 0x%.4ux offset %llud length %llud\n", pid, offset, length); if (!smbsharedfilelock(f->sf, s, h->pid, offset, offset + length)) break; } if (l < numberoflocks) { ushort i; ushort pid; uvlong offset; uvlong length; smbbufferreadbackup(b, backupoffset); for (i = 0; i < l; i++) { assert(getlock(b, large, &pid, &offset, &length)); smbsharedfileunlock(f->sf, s, h->pid, offset, offset + length); } smbseterror(s, ERRDOS, ERRlock); goto error; } h->wordcount = 2; if (!smbbufferputandxheader(s->response, h, &s->peerinfo, andxcommand, &andxoffsetfixup) || !smbbufferputs(s->response, 0)) { // bytecount 0 pr = SmbProcessResultMisc; goto done; } if (andxcommand != SMB_COM_NO_ANDX_COMMAND) pr = smbchaincommand(s, h, andxoffsetfixup, andxcommand, andxoffset, b); else pr = SmbProcessResultReply; done: return pr; }