xref: /plan9/sys/src/cmd/aquarela/smbconnect.c (revision 8ccd4a6360d974db7bd7bbd4f37e7018419ea908)
1 #include "headers.h"
2 
3 SmbClient *
smbconnect(char * to,char * share,char ** errmsgp)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
smbclientfree(SmbClient * c)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
smbtransactionclientsend(void * magic,SmbBuffer * ob,char **)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
smbtransactionclientreceive(void * magic,SmbBuffer * ib,char **)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 
276