SmbProcessResult smbcomtreedisconnect(SmbSession *s, SmbHeader *h, uchar *, SmbBuffer *) { if (!smbcheckwordcount("comtreedisconnect", h, 0)) return SmbProcessResultFormat; smbtreedisconnectbyid(s, h->tid); return smbbufferputack(s->response, h, &s->peerinfo); }
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; }
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 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 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; }