#include "headers.h"
SmbClient *
smbconnect(char *to, char *share, char **errmsgp)
{
NbSession *nbs;
SmbBuffer *b;
SmbHeader h, rh;
long n;
ushort bytecountfixupoffset;
ushort andxfixupoffset;
uchar *pdata;
SmbPeerInfo peerinfo;
ushort index;
vlong utcintenthsofaus;
ulong secssince1970;
ushort bytecount;
int x;
MSchapreply mschapreply;
NbName nbto;
SmbClient *c;
char namebuf[100];
ushort ipctid, sharetid;
nbmknamefromstringandtype(nbto, to, 0x20);
peerinfo.encryptionkey = nil;
peerinfo.oemdomainname = nil;
assert(smbglobals.nbname[0] != 0);
nbs = nbssconnect(nbto, smbglobals.nbname);
if (nbs == nil)
return nil;
print("netbios session established\n");
b = smbbuffernew(65535);
memset(&h, 0, sizeof(h));
h.command = SMB_COM_NEGOTIATE;
h.flags2 = SMB_FLAGS2_KNOWS_LONG_NAMES | SMB_FLAGS2_IS_LONG_NAME | SMB_FLAGS2_UNICODE;
h.wordcount = 0;
h.pid = 42;
smbbufferputheader(b, &h, &peerinfo);
bytecountfixupoffset = smbbufferwriteoffset(b);
smbbufferputbytes(b, nil, 2);
smbbufferputb(b, 2);
smbbufferputstring(b, nil, SMB_STRING_ASCII, "NT LM 0.12");
smbbufferoffsetputs(b, bytecountfixupoffset, smbbufferwriteoffset(b) - bytecountfixupoffset - 2);
nbdumpdata(smbbufferreadpointer(b), smbbufferwriteoffset(b));
nbsswrite(nbs, smbbufferreadpointer(b), smbbufferwriteoffset(b));
/*
* now receive a reply
*/
smbbufferreset(b);
n = nbssread(nbs, smbbufferwritepointer(b), smbbufferwritespace(b));
if (n < 0) {
smbstringprint(errmsgp, "smbconnect: read error: %r");
goto fail;
}
smbbuffersetreadlen(b, n);
nbdumpdata(smbbufferreadpointer(b), smbbufferwriteoffset(b));
if (!smbbuffergetandcheckheader(b, &rh, h.command, 1, &pdata, &bytecount, errmsgp))
goto fail;
if (!smbsuccess(&rh, errmsgp))
goto fail;
if (rh.wordcount == 0) {
smbstringprint(errmsgp, "no parameters in negotiate response");
goto fail;
}
index = smbnhgets(pdata); pdata += 2;
if (index != 0) {
smbstringprint(errmsgp, "no agreement on protocol");
goto fail;
}
if (rh.wordcount != 17) {
smbstringprint(errmsgp, "wrong number of parameters for negotiate response");
goto fail;
}
peerinfo.securitymode = *pdata++;
peerinfo.maxmpxcount = smbnhgets(pdata); pdata += 2;
peerinfo.maxnumbervcs = smbnhgets(pdata); pdata += 2;
peerinfo.maxbuffersize = smbnhgetl(pdata); pdata += 4;
peerinfo.maxrawsize = smbnhgetl(pdata); pdata += 4;
peerinfo.sessionkey = smbnhgets(pdata); pdata += 4;
peerinfo.capabilities = smbnhgets(pdata); pdata += 4;
utcintenthsofaus = smbnhgetv(pdata); pdata += 8;
secssince1970 = utcintenthsofaus / 10000000 - 11644473600LL;
peerinfo.utc = (vlong)secssince1970 * (vlong)1000000000 + (utcintenthsofaus % 10000000) * 100;
peerinfo.tzoff = -smbnhgets(pdata) * 60; pdata += 2;
peerinfo.encryptionkeylength = *pdata++;
print("securitymode: 0x%.2ux\n", peerinfo.securitymode);
print("maxmpxcount: 0x%.4ux\n", peerinfo.maxmpxcount);
print("maxnumbervcs: 0x%.4ux\n", peerinfo.maxnumbervcs);
print("maxbuffersize: 0x%.8lux\n", peerinfo.maxbuffersize);
print("maxrawsize: 0x%.8lux\n", peerinfo.maxrawsize);
print("sessionkey: 0x%.8lux\n", peerinfo.sessionkey);
print("capabilities: 0x%.8lux\n", peerinfo.capabilities);
print("utc: %s(and %lld μs)\n", asctime(gmtime(peerinfo.utc / 1000000000)), peerinfo.utc % 1000000000);
print("tzoff: %d\n", peerinfo.tzoff);
print("encryptionkeylength: %d\n", peerinfo.encryptionkeylength);
smberealloc(&peerinfo.encryptionkey, peerinfo.encryptionkeylength);
if (!smbbuffergetbytes(b, peerinfo.encryptionkey, peerinfo.encryptionkeylength)) {
smbstringprint(errmsgp, "not enough data for encryption key");
goto fail;
}
print("encryptionkey: ");
for (x = 0; x < peerinfo.encryptionkeylength; x++)
print("%.2ux", peerinfo.encryptionkey[x]);
print("\n");
if (!smbbuffergetucs2(b, 0, &peerinfo.oemdomainname)) {
smbstringprint(errmsgp, "not enough data for oemdomainname");
goto fail;
}
print("oemdomainname: %s\n", peerinfo.oemdomainname);
if (peerinfo.capabilities & CAP_EXTENDED_SECURITY) {
smbstringprint(errmsgp, "server wants extended security");
goto fail;
}
/*
* ok - now send SMB_COM_SESSION_SETUP_ANDX
* fix the flags to reflect what the peer can do
*/
smbbufferreset(b);
h.command = SMB_COM_SESSION_SETUP_ANDX;
h.wordcount = 13;
h.flags2 &= ~SMB_FLAGS2_UNICODE;
if (smbsendunicode(&peerinfo))
h.flags2 |= SMB_FLAGS2_UNICODE;
smbbufferputheader(b, &h, &peerinfo);
smbbufferputb(b, SMB_COM_TREE_CONNECT_ANDX);
smbbufferputb(b, 0);
andxfixupoffset = smbbufferwriteoffset(b);
smbbufferputs(b, 0);
smbbufferputs(b, 0xffff);
smbbufferputs(b, 1);
smbbufferputs(b, 0);
smbbufferputl(b, peerinfo.sessionkey);
smbbufferputs(b, sizeof(mschapreply.LMresp));
smbbufferputs(b, sizeof(mschapreply.NTresp));
smbbufferputl(b, 0);
smbbufferputl(b, CAP_UNICODE | CAP_LARGE_FILES);
bytecountfixupoffset = smbbufferwriteoffset(b);
smbbufferputs(b, 0);
if (auth_respond(peerinfo.encryptionkey, peerinfo.encryptionkeylength,
nil, 0,
&mschapreply, sizeof(mschapreply), auth_getkey,
"proto=mschap role=client server=%s", "cher") != sizeof(mschapreply)) {
print("auth_respond failed: %r\n");
goto fail;
}
smbbufferputbytes(b, &mschapreply, sizeof(mschapreply));
smbbufferputstring(b, &peerinfo, 0, smbglobals.accountname);
smbbufferputstring(b, &peerinfo, 0, smbglobals.primarydomain);
smbbufferputstring(b, &peerinfo, 0, smbglobals.nativeos);
smbbufferputstring(b, &peerinfo, 0, "");
smbbufferoffsetputs(b, bytecountfixupoffset, smbbufferwriteoffset(b) - bytecountfixupoffset - 2);
smbbufferalignl2(b, 2);
smbbufferoffsetputs(b, andxfixupoffset, smbbufferwriteoffset(b));
smbbufferputb(b, 4);
smbbufferputb(b, SMB_COM_NO_ANDX_COMMAND);
smbbufferputb(b, 0);
smbbufferputs(b, 0);
smbbufferputs(b, 0);
smbbufferputs(b, 0);
bytecountfixupoffset = smbbufferwriteoffset(b);
smbbufferputs(b, 0);
strcpy(namebuf, "\\\\");
strcat(namebuf, to);
strcat(namebuf, "\\IPC$");
smbbufferputstring(b, &peerinfo, SMB_STRING_UPCASE, namebuf);
smbbufferputstring(b, nil, SMB_STRING_ASCII, "?????");
smbbufferoffsetputs(b, bytecountfixupoffset, smbbufferwriteoffset(b) - bytecountfixupoffset - 2);
nbdumpdata(smbbufferreadpointer(b), smbbufferwriteoffset(b));
nbsswrite(nbs, smbbufferreadpointer(b), smbbufferwriteoffset(b));
smbbufferreset(b);
n = nbssread(nbs, smbbufferwritepointer(b), smbbufferwritespace(b));
if (n < 0) {
smbstringprint(errmsgp, "read error: %r");
goto fail;
}
smbbuffersetreadlen(b, n);
nbdumpdata(smbbufferreadpointer(b), smbbufferwriteoffset(b));
if (!smbbuffergetandcheckheader(b, &rh, h.command, 1, &pdata, &bytecount, errmsgp))
goto fail;
if (!smbsuccess(&rh, errmsgp))
goto fail;
h.uid = rh.uid;
ipctid = rh.tid;
/*
* now do another TREE_CONNECT if needed
*/
if (share) {
smbbufferreset(b);
h.command = SMB_COM_TREE_CONNECT_ANDX;
h.wordcount = 4;
h.tid = 0;
smbbufferputheader(b, &h, &peerinfo);
smbbufferputb(b, SMB_COM_NO_ANDX_COMMAND);
smbbufferputb(b, 0);
smbbufferputs(b, 0);
smbbufferputs(b, 0);
smbbufferputs(b, 0);
bytecountfixupoffset = smbbufferwriteoffset(b);
smbbufferputs(b, 0);
strcpy(namebuf, "\\\\");
strcat(namebuf, to);
strcat(namebuf, "\\");
strcat(namebuf, share);
smbbufferputstring(b, &peerinfo, SMB_STRING_UPCASE, namebuf);
smbbufferputstring(b, nil, SMB_STRING_ASCII, "A:");
smbbufferoffsetputs(b, bytecountfixupoffset, smbbufferwriteoffset(b) - bytecountfixupoffset - 2);
nbdumpdata(smbbufferreadpointer(b), smbbufferwriteoffset(b));
nbsswrite(nbs, smbbufferreadpointer(b), smbbufferwriteoffset(b));
smbbufferreset(b);
n = nbssread(nbs, smbbufferwritepointer(b), smbbufferwritespace(b));
if (n < 0) {
smbstringprint(errmsgp, "read error: %r");
goto fail;
}
smbbuffersetreadlen(b, n);
nbdumpdata(smbbufferreadpointer(b), smbbufferwriteoffset(b));
if (!smbbuffergetandcheckheader(b, &rh, h.command, 3, &pdata, &bytecount, errmsgp))
goto fail;
if (!smbsuccess(&rh, errmsgp))
goto fail;
sharetid = rh.tid;
}
else
sharetid = -2;
c = smbemalloc(sizeof(*c));
c->peerinfo = peerinfo;
c->ipctid = ipctid;
c->sharetid = sharetid;
c->b = b;
c->protoh = h;
c->nbss = nbs;
return c;
fail:
smbbufferfree(&b);
free(peerinfo.encryptionkey);
free(peerinfo.oemdomainname);
return nil;
}
void
smbclientfree(SmbClient *c)
{
if (c) {
free(c->peerinfo.encryptionkey);
free(c->peerinfo.oemdomainname);
free(c);
smbbufferfree(&c->b);
}
}
int
smbtransactionclientsend(void *magic, SmbBuffer *ob, char **)
{
SmbClient *c = magic;
smblogprint(-1, "sending:\n");
smblogdata(-1, smblogprint, smbbufferreadpointer(ob), smbbufferwriteoffset(ob), 256);
return nbsswrite(c->nbss, smbbufferreadpointer(ob), smbbufferwriteoffset(ob)) == 0;
}
int
smbtransactionclientreceive(void *magic, SmbBuffer *ib, char **)
{
long n;
SmbClient *c = magic;
smbbufferreset(ib);
n = nbssread(c->nbss, smbbufferwritepointer(ib), smbbufferwritespace(ib));
if (n >= 0) {
assert(smbbufferputbytes(ib, nil, n));
return 1;
}
return 0;
}
|