2 |
- |
1 |
#include "headers.h"
|
|
|
2 |
|
|
|
3 |
SmbClient *
|
|
|
4 |
smbconnect(char *to, char *share, char **errmsgp)
|
|
|
5 |
{
|
|
|
6 |
NbSession *nbs;
|
|
|
7 |
SmbBuffer *b;
|
|
|
8 |
SmbHeader h, rh;
|
|
|
9 |
long n;
|
|
|
10 |
ushort bytecountfixupoffset;
|
|
|
11 |
ushort andxfixupoffset;
|
|
|
12 |
uchar *pdata;
|
|
|
13 |
SmbPeerInfo peerinfo;
|
|
|
14 |
ushort index;
|
|
|
15 |
vlong utcintenthsofaus;
|
|
|
16 |
ulong secssince1970;
|
|
|
17 |
ushort bytecount;
|
|
|
18 |
int x;
|
|
|
19 |
MSchapreply mschapreply;
|
|
|
20 |
NbName nbto;
|
|
|
21 |
SmbClient *c;
|
|
|
22 |
char namebuf[100];
|
|
|
23 |
ushort ipctid, sharetid;
|
|
|
24 |
|
|
|
25 |
nbmknamefromstringandtype(nbto, to, 0x20);
|
|
|
26 |
|
|
|
27 |
peerinfo.encryptionkey = nil;
|
|
|
28 |
peerinfo.oemdomainname = nil;
|
|
|
29 |
assert(smbglobals.nbname[0] != 0);
|
|
|
30 |
nbs = nbssconnect(nbto, smbglobals.nbname);
|
|
|
31 |
if (nbs == nil)
|
|
|
32 |
return nil;
|
|
|
33 |
print("netbios session established\n");
|
|
|
34 |
b = smbbuffernew(65535);
|
|
|
35 |
memset(&h, 0, sizeof(h));
|
|
|
36 |
h.command = SMB_COM_NEGOTIATE;
|
|
|
37 |
h.flags2 = SMB_FLAGS2_KNOWS_LONG_NAMES | SMB_FLAGS2_IS_LONG_NAME | SMB_FLAGS2_UNICODE;
|
|
|
38 |
h.wordcount = 0;
|
|
|
39 |
h.pid = 42;
|
|
|
40 |
smbbufferputheader(b, &h, &peerinfo);
|
|
|
41 |
bytecountfixupoffset = smbbufferwriteoffset(b);
|
|
|
42 |
smbbufferputbytes(b, nil, 2);
|
|
|
43 |
smbbufferputb(b, 2);
|
|
|
44 |
smbbufferputstring(b, nil, SMB_STRING_ASCII, "NT LM 0.12");
|
|
|
45 |
smbbufferoffsetputs(b, bytecountfixupoffset, smbbufferwriteoffset(b) - bytecountfixupoffset - 2);
|
|
|
46 |
nbdumpdata(smbbufferreadpointer(b), smbbufferwriteoffset(b));
|
|
|
47 |
nbsswrite(nbs, smbbufferreadpointer(b), smbbufferwriteoffset(b));
|
|
|
48 |
/*
|
|
|
49 |
* now receive a reply
|
|
|
50 |
*/
|
|
|
51 |
smbbufferreset(b);
|
|
|
52 |
n = nbssread(nbs, smbbufferwritepointer(b), smbbufferwritespace(b));
|
|
|
53 |
if (n < 0) {
|
|
|
54 |
smbstringprint(errmsgp, "smbconnect: read error: %r");
|
|
|
55 |
goto fail;
|
|
|
56 |
}
|
|
|
57 |
smbbuffersetreadlen(b, n);
|
|
|
58 |
nbdumpdata(smbbufferreadpointer(b), smbbufferwriteoffset(b));
|
|
|
59 |
if (!smbbuffergetandcheckheader(b, &rh, h.command, 1, &pdata, &bytecount, errmsgp))
|
|
|
60 |
goto fail;
|
|
|
61 |
if (!smbsuccess(&rh, errmsgp))
|
|
|
62 |
goto fail;
|
|
|
63 |
if (rh.wordcount == 0) {
|
|
|
64 |
smbstringprint(errmsgp, "no parameters in negotiate response");
|
|
|
65 |
goto fail;
|
|
|
66 |
}
|
|
|
67 |
index = smbnhgets(pdata); pdata += 2;
|
|
|
68 |
if (index != 0) {
|
|
|
69 |
smbstringprint(errmsgp, "no agreement on protocol");
|
|
|
70 |
goto fail;
|
|
|
71 |
}
|
|
|
72 |
if (rh.wordcount != 17) {
|
|
|
73 |
smbstringprint(errmsgp, "wrong number of parameters for negotiate response");
|
|
|
74 |
goto fail;
|
|
|
75 |
}
|
|
|
76 |
peerinfo.securitymode = *pdata++;
|
|
|
77 |
peerinfo.maxmpxcount = smbnhgets(pdata); pdata += 2;
|
|
|
78 |
peerinfo.maxnumbervcs = smbnhgets(pdata); pdata += 2;
|
|
|
79 |
peerinfo.maxbuffersize = smbnhgetl(pdata); pdata += 4;
|
|
|
80 |
peerinfo.maxrawsize = smbnhgetl(pdata); pdata += 4;
|
|
|
81 |
peerinfo.sessionkey = smbnhgets(pdata); pdata += 4;
|
|
|
82 |
peerinfo.capabilities = smbnhgets(pdata); pdata += 4;
|
|
|
83 |
utcintenthsofaus = smbnhgetv(pdata); pdata += 8;
|
|
|
84 |
secssince1970 = utcintenthsofaus / 10000000 - 11644473600LL;
|
|
|
85 |
peerinfo.utc = (vlong)secssince1970 * (vlong)1000000000 + (utcintenthsofaus % 10000000) * 100;
|
|
|
86 |
peerinfo.tzoff = -smbnhgets(pdata) * 60; pdata += 2;
|
|
|
87 |
peerinfo.encryptionkeylength = *pdata++;
|
|
|
88 |
print("securitymode: 0x%.2ux\n", peerinfo.securitymode);
|
|
|
89 |
print("maxmpxcount: 0x%.4ux\n", peerinfo.maxmpxcount);
|
|
|
90 |
print("maxnumbervcs: 0x%.4ux\n", peerinfo.maxnumbervcs);
|
|
|
91 |
print("maxbuffersize: 0x%.8lux\n", peerinfo.maxbuffersize);
|
|
|
92 |
print("maxrawsize: 0x%.8lux\n", peerinfo.maxrawsize);
|
|
|
93 |
print("sessionkey: 0x%.8lux\n", peerinfo.sessionkey);
|
|
|
94 |
print("capabilities: 0x%.8lux\n", peerinfo.capabilities);
|
|
|
95 |
print("utc: %s(and %lld μs)\n", asctime(gmtime(peerinfo.utc / 1000000000)), peerinfo.utc % 1000000000);
|
|
|
96 |
print("tzoff: %d\n", peerinfo.tzoff);
|
|
|
97 |
print("encryptionkeylength: %d\n", peerinfo.encryptionkeylength);
|
|
|
98 |
smberealloc(&peerinfo.encryptionkey, peerinfo.encryptionkeylength);
|
|
|
99 |
if (!smbbuffergetbytes(b, peerinfo.encryptionkey, peerinfo.encryptionkeylength)) {
|
|
|
100 |
smbstringprint(errmsgp, "not enough data for encryption key");
|
|
|
101 |
goto fail;
|
|
|
102 |
}
|
|
|
103 |
print("encryptionkey: ");
|
|
|
104 |
for (x = 0; x < peerinfo.encryptionkeylength; x++)
|
|
|
105 |
print("%.2ux", peerinfo.encryptionkey[x]);
|
|
|
106 |
print("\n");
|
|
|
107 |
if (!smbbuffergetucs2(b, 0, &peerinfo.oemdomainname)) {
|
|
|
108 |
smbstringprint(errmsgp, "not enough data for oemdomainname");
|
|
|
109 |
goto fail;
|
|
|
110 |
}
|
|
|
111 |
print("oemdomainname: %s\n", peerinfo.oemdomainname);
|
|
|
112 |
if (peerinfo.capabilities & CAP_EXTENDED_SECURITY) {
|
|
|
113 |
smbstringprint(errmsgp, "server wants extended security");
|
|
|
114 |
goto fail;
|
|
|
115 |
}
|
|
|
116 |
/*
|
|
|
117 |
* ok - now send SMB_COM_SESSION_SETUP_ANDX
|
|
|
118 |
* fix the flags to reflect what the peer can do
|
|
|
119 |
*/
|
|
|
120 |
smbbufferreset(b);
|
|
|
121 |
h.command = SMB_COM_SESSION_SETUP_ANDX;
|
|
|
122 |
h.wordcount = 13;
|
|
|
123 |
h.flags2 &= ~SMB_FLAGS2_UNICODE;
|
|
|
124 |
if (smbsendunicode(&peerinfo))
|
|
|
125 |
h.flags2 |= SMB_FLAGS2_UNICODE;
|
|
|
126 |
smbbufferputheader(b, &h, &peerinfo);
|
|
|
127 |
smbbufferputb(b, SMB_COM_TREE_CONNECT_ANDX);
|
|
|
128 |
smbbufferputb(b, 0);
|
|
|
129 |
andxfixupoffset = smbbufferwriteoffset(b);
|
|
|
130 |
smbbufferputs(b, 0);
|
|
|
131 |
smbbufferputs(b, 0xffff);
|
|
|
132 |
smbbufferputs(b, 1);
|
|
|
133 |
smbbufferputs(b, 0);
|
|
|
134 |
smbbufferputl(b, peerinfo.sessionkey);
|
|
|
135 |
smbbufferputs(b, sizeof(mschapreply.LMresp));
|
|
|
136 |
smbbufferputs(b, sizeof(mschapreply.NTresp));
|
|
|
137 |
smbbufferputl(b, 0);
|
|
|
138 |
smbbufferputl(b, CAP_UNICODE | CAP_LARGE_FILES);
|
|
|
139 |
bytecountfixupoffset = smbbufferwriteoffset(b);
|
|
|
140 |
smbbufferputs(b, 0);
|
|
|
141 |
if (auth_respond(peerinfo.encryptionkey, peerinfo.encryptionkeylength,
|
|
|
142 |
nil, 0,
|
|
|
143 |
&mschapreply, sizeof(mschapreply), auth_getkey,
|
|
|
144 |
"proto=mschap role=client server=%s", "cher") != sizeof(mschapreply)) {
|
|
|
145 |
print("auth_respond failed: %r\n");
|
|
|
146 |
goto fail;
|
|
|
147 |
}
|
|
|
148 |
smbbufferputbytes(b, &mschapreply, sizeof(mschapreply));
|
|
|
149 |
smbbufferputstring(b, &peerinfo, 0, smbglobals.accountname);
|
|
|
150 |
smbbufferputstring(b, &peerinfo, 0, smbglobals.primarydomain);
|
|
|
151 |
smbbufferputstring(b, &peerinfo, 0, smbglobals.nativeos);
|
|
|
152 |
smbbufferputstring(b, &peerinfo, 0, "");
|
|
|
153 |
smbbufferoffsetputs(b, bytecountfixupoffset, smbbufferwriteoffset(b) - bytecountfixupoffset - 2);
|
|
|
154 |
smbbufferalignl2(b, 2);
|
|
|
155 |
smbbufferoffsetputs(b, andxfixupoffset, smbbufferwriteoffset(b));
|
|
|
156 |
smbbufferputb(b, 4);
|
|
|
157 |
smbbufferputb(b, SMB_COM_NO_ANDX_COMMAND);
|
|
|
158 |
smbbufferputb(b, 0);
|
|
|
159 |
smbbufferputs(b, 0);
|
|
|
160 |
smbbufferputs(b, 0);
|
|
|
161 |
smbbufferputs(b, 0);
|
|
|
162 |
bytecountfixupoffset = smbbufferwriteoffset(b);
|
|
|
163 |
smbbufferputs(b, 0);
|
|
|
164 |
strcpy(namebuf, "\\\\");
|
|
|
165 |
strcat(namebuf, to);
|
|
|
166 |
strcat(namebuf, "\\IPC$");
|
|
|
167 |
smbbufferputstring(b, &peerinfo, SMB_STRING_UPCASE, namebuf);
|
|
|
168 |
smbbufferputstring(b, nil, SMB_STRING_ASCII, "?????");
|
|
|
169 |
smbbufferoffsetputs(b, bytecountfixupoffset, smbbufferwriteoffset(b) - bytecountfixupoffset - 2);
|
|
|
170 |
nbdumpdata(smbbufferreadpointer(b), smbbufferwriteoffset(b));
|
|
|
171 |
nbsswrite(nbs, smbbufferreadpointer(b), smbbufferwriteoffset(b));
|
|
|
172 |
smbbufferreset(b);
|
|
|
173 |
n = nbssread(nbs, smbbufferwritepointer(b), smbbufferwritespace(b));
|
|
|
174 |
if (n < 0) {
|
|
|
175 |
smbstringprint(errmsgp, "read error: %r");
|
|
|
176 |
goto fail;
|
|
|
177 |
}
|
|
|
178 |
smbbuffersetreadlen(b, n);
|
|
|
179 |
nbdumpdata(smbbufferreadpointer(b), smbbufferwriteoffset(b));
|
|
|
180 |
if (!smbbuffergetandcheckheader(b, &rh, h.command, 1, &pdata, &bytecount, errmsgp))
|
|
|
181 |
goto fail;
|
|
|
182 |
if (!smbsuccess(&rh, errmsgp))
|
|
|
183 |
goto fail;
|
|
|
184 |
h.uid = rh.uid;
|
|
|
185 |
ipctid = rh.tid;
|
|
|
186 |
/*
|
|
|
187 |
* now do another TREE_CONNECT if needed
|
|
|
188 |
*/
|
|
|
189 |
if (share) {
|
|
|
190 |
smbbufferreset(b);
|
|
|
191 |
h.command = SMB_COM_TREE_CONNECT_ANDX;
|
|
|
192 |
h.wordcount = 4;
|
|
|
193 |
h.tid = 0;
|
|
|
194 |
smbbufferputheader(b, &h, &peerinfo);
|
|
|
195 |
smbbufferputb(b, SMB_COM_NO_ANDX_COMMAND);
|
|
|
196 |
smbbufferputb(b, 0);
|
|
|
197 |
smbbufferputs(b, 0);
|
|
|
198 |
smbbufferputs(b, 0);
|
|
|
199 |
smbbufferputs(b, 0);
|
|
|
200 |
bytecountfixupoffset = smbbufferwriteoffset(b);
|
|
|
201 |
smbbufferputs(b, 0);
|
|
|
202 |
strcpy(namebuf, "\\\\");
|
|
|
203 |
strcat(namebuf, to);
|
|
|
204 |
strcat(namebuf, "\\");
|
|
|
205 |
strcat(namebuf, share);
|
|
|
206 |
smbbufferputstring(b, &peerinfo, SMB_STRING_UPCASE, namebuf);
|
|
|
207 |
smbbufferputstring(b, nil, SMB_STRING_ASCII, "A:");
|
|
|
208 |
smbbufferoffsetputs(b, bytecountfixupoffset, smbbufferwriteoffset(b) - bytecountfixupoffset - 2);
|
|
|
209 |
nbdumpdata(smbbufferreadpointer(b), smbbufferwriteoffset(b));
|
|
|
210 |
nbsswrite(nbs, smbbufferreadpointer(b), smbbufferwriteoffset(b));
|
|
|
211 |
smbbufferreset(b);
|
|
|
212 |
n = nbssread(nbs, smbbufferwritepointer(b), smbbufferwritespace(b));
|
|
|
213 |
if (n < 0) {
|
|
|
214 |
smbstringprint(errmsgp, "read error: %r");
|
|
|
215 |
goto fail;
|
|
|
216 |
}
|
|
|
217 |
smbbuffersetreadlen(b, n);
|
|
|
218 |
nbdumpdata(smbbufferreadpointer(b), smbbufferwriteoffset(b));
|
|
|
219 |
if (!smbbuffergetandcheckheader(b, &rh, h.command, 3, &pdata, &bytecount, errmsgp))
|
|
|
220 |
goto fail;
|
|
|
221 |
if (!smbsuccess(&rh, errmsgp))
|
|
|
222 |
goto fail;
|
|
|
223 |
sharetid = rh.tid;
|
|
|
224 |
}
|
|
|
225 |
else
|
|
|
226 |
sharetid = -2;
|
|
|
227 |
c = smbemalloc(sizeof(*c));
|
|
|
228 |
c->peerinfo = peerinfo;
|
|
|
229 |
c->ipctid = ipctid;
|
|
|
230 |
c->sharetid = sharetid;
|
|
|
231 |
c->b = b;
|
|
|
232 |
c->protoh = h;
|
|
|
233 |
c->nbss = nbs;
|
|
|
234 |
return c;
|
|
|
235 |
fail:
|
|
|
236 |
smbbufferfree(&b);
|
|
|
237 |
free(peerinfo.encryptionkey);
|
|
|
238 |
free(peerinfo.oemdomainname);
|
|
|
239 |
return nil;
|
|
|
240 |
}
|
|
|
241 |
|
|
|
242 |
void
|
|
|
243 |
smbclientfree(SmbClient *c)
|
|
|
244 |
{
|
|
|
245 |
if (c) {
|
|
|
246 |
free(c->peerinfo.encryptionkey);
|
|
|
247 |
free(c->peerinfo.oemdomainname);
|
|
|
248 |
free(c);
|
|
|
249 |
smbbufferfree(&c->b);
|
|
|
250 |
}
|
|
|
251 |
}
|
|
|
252 |
|
|
|
253 |
int
|
|
|
254 |
smbtransactionclientsend(void *magic, SmbBuffer *ob, char **)
|
|
|
255 |
{
|
|
|
256 |
SmbClient *c = magic;
|
|
|
257 |
smblogprint(-1, "sending:\n");
|
|
|
258 |
smblogdata(-1, smblogprint, smbbufferreadpointer(ob), smbbufferwriteoffset(ob), 256);
|
|
|
259 |
return nbsswrite(c->nbss, smbbufferreadpointer(ob), smbbufferwriteoffset(ob)) == 0;
|
|
|
260 |
}
|
|
|
261 |
|
|
|
262 |
int
|
|
|
263 |
smbtransactionclientreceive(void *magic, SmbBuffer *ib, char **)
|
|
|
264 |
{
|
|
|
265 |
long n;
|
|
|
266 |
SmbClient *c = magic;
|
|
|
267 |
smbbufferreset(ib);
|
|
|
268 |
n = nbssread(c->nbss, smbbufferwritepointer(ib), smbbufferwritespace(ib));
|
|
|
269 |
if (n >= 0) {
|
|
|
270 |
assert(smbbufferputbytes(ib, nil, n));
|
|
|
271 |
return 1;
|
|
|
272 |
}
|
|
|
273 |
return 0;
|
|
|
274 |
}
|
|
|
275 |
|