xref: /plan9/sys/src/cmd/cifs/netbios.c (revision 671dfc474d1a5bcbeda8be1356d2abfa05b91489)
1 /*
2  * netbios dial, read, write
3  */
4 
5 #include <u.h>
6 #include <libc.h>
7 #include <ctype.h>
8 #include <fcall.h>
9 #include <thread.h>
10 #include <9p.h>
11 #include "cifs.h"
12 
13 enum {
14 	MAXNBPKT		= 8096,		/* max netbios packet size */
15 	NBquery			= 0,		/* packet type - query */
16 
17 	NBAdapterStatus		= 0x21,		/* get host interface info */
18 	NBInternet		= 1,		/* scope for info */
19 
20 	NBmessage 		= 0x00,		/* Netbios packet types */
21 	NBrequest 		= 0x81,
22 	NBpositive,
23 	NBnegative,
24 	NBretarget,
25 	NBkeepalive,
26 
27 	ISgroup			= 0x8000,
28 };
29 
30 
31 static char *NBerr[] = {
32 	[0]	"not listening on called name",
33 	[1]	"not listening for calling name",
34 	[2]	"called name not present",
35 	[3]	"insufficient resources",
36 	[15]	"unspecified error"
37 };
38 
39 
40 static ulong
GL32(uchar ** p)41 GL32(uchar **p)
42 {
43 	ulong n;
44 
45 	n  = *(*p)++;
46 	n |= *(*p)++ << 8;
47 	n |= *(*p)++ << 16;
48 	n |= *(*p)++ << 24;
49 	return n;
50 }
51 
52 static ushort
GL16(uchar ** p)53 GL16(uchar **p)
54 {
55 	ushort n;
56 
57 	n  = *(*p)++;
58 	n |= *(*p)++ << 8;
59 	return n;
60 }
61 
62 void
Gmem(uchar ** p,void * v,int n)63 Gmem(uchar **p, void *v, int n)
64 {
65 	uchar *str = v;
66 
67 	while(n--)
68 		*str++ = *(*p)++;
69 }
70 
71 
72 static ulong
GB32(uchar ** p)73 GB32(uchar **p)
74 {
75 	ulong n;
76 
77 	n  = *(*p)++ << 24;
78 	n |= *(*p)++ << 16;
79 	n |= *(*p)++ << 8;
80 	n |= *(*p)++;
81 	return n;
82 }
83 
84 static ushort
GB16(uchar ** p)85 GB16(uchar **p)
86 {
87 	ushort n;
88 
89 	n  = *(*p)++ << 8;
90 	n |= *(*p)++;
91 	return n;
92 }
93 
94 static uchar
G8(uchar ** p)95 G8(uchar **p)
96 {
97 	return *(*p)++;
98 }
99 
100 static void
PB16(uchar ** p,uint n)101 PB16(uchar **p, uint n)
102 {
103 	*(*p)++ = n >> 8;
104 	*(*p)++ = n;
105 }
106 
107 static void
P8(uchar ** p,uint n)108 P8(uchar **p, uint n)
109 {
110 	*(*p)++ = n;
111 }
112 
113 
114 static void
nbname(uchar ** p,char * name,char pad)115 nbname(uchar **p, char *name, char pad)
116 {
117 	char c;
118 	int i;
119 	int done = 0;
120 
121 	*(*p)++ = 0x20;
122 	for(i = 0; i < 16; i++) {
123 		c = pad;
124 		if(!done && name[i] == '\0')
125 			done = 1;
126 		if(!done)
127 			c = toupper(name[i]);
128 		*(*p)++ = ((uchar)c >> 4) + 'A';
129 		*(*p)++ = (c & 0xf) + 'A';
130 	}
131 	*(*p)++ = 0;
132 }
133 
134 int
calledname(char * host,char * name)135 calledname(char *host, char *name)
136 {
137 	char *addr;
138 	uchar buf[1024], *p;
139 	static char tmp[20];
140 	int num, flg, svs, j, i, fd, trn;
141 
142 	trn = (getpid() ^ time(0)) & 0xffff;
143 	if((addr = netmkaddr(host, "udp", "137")) == nil)
144 		return -1;
145 
146 	if((fd = dial(addr, "137", 0, 0)) < 0)
147 		return -1;
148 	p = buf;
149 
150 	PB16(&p, trn);			/* TRNid */
151 	P8(&p, 0);			/* flags */
152 	P8(&p, 0x10);			/* type */
153 	PB16(&p, 1);			/* # questions */
154 	PB16(&p, 0);			/* # answers */
155 	PB16(&p, 0);			/* # authority RRs */
156 	PB16(&p, 0);			/* # Aditional RRs */
157 	nbname(&p, "*", 0);
158 	PB16(&p, NBAdapterStatus);
159 	PB16(&p, NBInternet);
160 
161 	if(Debug && strstr(Debug, "dump"))
162 		xd(nil, buf, p-buf);
163 
164 	if(write(fd, buf, p-buf) != p-buf)
165 		return -1;
166 
167 	p = buf;
168 	for(i = 0; i < 3; i++){
169 		memset(buf, 0, sizeof(buf));
170 		alarm(NBNSTOUT);
171 		read(fd, buf, sizeof(buf));
172 		alarm(0);
173 		if(GB16(&p) == trn)
174 			break;
175 	}
176 	close(fd);
177 	if(i >= 3)
178 		return -1;
179 
180 	p = buf +56;
181 	num = G8(&p);			/* number of names */
182 
183 	for(i = 0; i < num; i++){
184 		memset(tmp, 0, sizeof(tmp));
185 		Gmem(&p, tmp, 15);
186 		svs = G8(&p);
187 		flg = GB16(&p);
188 		for(j = 14; j >= 0 && tmp[j] == ' '; j--)
189 			tmp[j] = 0;
190 		if(svs == 0 && !(flg & ISgroup))
191 			strcpy(name, tmp);
192 	}
193 	return 0;
194 }
195 
196 
197 int
nbtdial(char * addr,char * called,char * sysname)198 nbtdial(char *addr, char *called, char *sysname)
199 {
200 	char redir[20];
201 	uchar *p, *lenp, buf[1024];
202 	int type, len, err, fd, nkeepalive, nretarg;
203 
204 	nretarg = 0;
205 	nkeepalive = 0;
206 Redial:
207 	if((addr = netmkaddr(addr, "tcp", "139")) == nil ||
208 	    (fd = dial(addr, 0, 0, 0)) < 0)
209 		return -1;
210 
211 	memset(buf, 0, sizeof(buf));
212 
213 	p = buf;
214 	P8(&p, NBrequest);		/* type */
215 	P8(&p, 0);			/* flags */
216 	lenp = p; PB16(&p, 0);		/* length placeholder */
217 	nbname(&p, called, ' ');	/* remote NetBios name */
218 	nbname(&p, sysname, ' ');	/* our machine name */
219 	PB16(&lenp, p-lenp -2);		/* length re-write */
220 
221 	if(Debug && strstr(Debug, "dump"))
222 		xd(nil, buf, p-buf);
223 	if(write(fd, buf, p-buf) != p-buf)
224 		goto Error;
225 Reread:
226 	p = buf;
227 	memset(buf, 0, sizeof(buf));
228 	if(readn(fd, buf, 4) < 4)
229 		goto Error;
230 
231 	type = G8(&p);
232 	G8(&p);				/* flags */
233 	len = GB16(&p);
234 
235 	if(readn(fd, buf +4, len -4) < len -4)
236 		goto Error;
237 
238 	if(Debug && strstr(Debug, "dump"))
239 		xd(nil, buf, len+4);
240 
241 	switch(type) {
242 	case NBpositive:
243 		return fd;
244 	case NBnegative:
245 		if(len < 1) {
246 			werrstr("nbdial: bad error pkt");
247 			goto Error;
248 		}
249 		err = G8(&p);
250 		if(err < 0 || err > nelem(NBerr) || NBerr[err] == nil)
251 			werrstr("NBT: %d - unknown error", err);
252 		else
253 			werrstr("NBT: %s", NBerr[err]);
254 
255 		goto Error;
256 	case NBkeepalive:
257 		if(++nkeepalive >= 16){
258 			werrstr("nbdial: too many keepalives");
259 			goto Error;
260 		}
261 		goto Reread;
262 
263 	case NBretarget:
264 		if(++nretarg >= 16) {
265 			werrstr("nbdial: too many redirects");
266 			goto Error;
267 		}
268 		if(len < 4) {
269 			werrstr("nbdial: bad redirect pkt");
270 			goto Error;
271 		}
272 		sprint(redir, "%d.%d.%d.%d", p[0], p[1], p[2], p[3]);
273 		addr = redir;
274 		goto Redial;
275 
276 	default:
277 		werrstr("nbdial: 0x%x - unknown packet in netbios handshake", type);
278 		goto Error;
279 	}
280 Error:
281 	close(fd);
282 	return -1;
283 }
284 
285 void
nbthdr(Pkt * p)286 nbthdr(Pkt *p)
287 {
288 	p->pos = p->buf;
289 	memset(p->buf, 0xa5, MTU);
290 
291 	p8(p, NBmessage);		/* type */
292 	p8(p, 0);			/* flags */
293 	pb16(p, 0);			/* length (filled in later) */
294 }
295 
296 int
nbtrpc(Pkt * p)297 nbtrpc(Pkt *p)
298 {
299 	int len, got, type, nkeep;
300 
301 	len = p->pos - p->buf;
302 
303 	p->pos = p->buf +2;
304 	pb16(p, len - NBHDRLEN);	/* length */
305 
306 	if(Debug && strstr(Debug, "dump"))
307 		xd("tx", p->buf, len);
308 
309 	alarm(NBRPCTOUT);
310 	if(write(p->s->fd, p->buf, len) != len){
311 		werrstr("nbtrpc: write failed - %r");
312 		alarm(0);
313 		return -1;
314 	}
315 
316 	nkeep = 0;
317 retry:
318 	p->pos = p->buf;
319 	memset(p->buf, 0xa5, MTU);
320 
321 	got = readn(p->s->fd, p->buf, NBHDRLEN);
322 
323 	if(got < NBHDRLEN){
324 		werrstr("nbtrpc: short read - %r");
325 		alarm(0);
326 		return -1;
327 	}
328 	p->eop = p->buf + got;
329 
330 	type = g8(p);			/* NBT type (session) */
331 	if(type == NBkeepalive){
332 		if(++nkeep > 16) {
333 			werrstr("nbtrpc: too many keepalives (%d attempts)", nkeep);
334 			alarm(0);
335 			return -1;
336 		}
337 		goto retry;
338 	}
339 
340 	g8(p);				/* NBT flags (none) */
341 
342 	len = gb16(p);			/* NBT payload length */
343 	if((len +NBHDRLEN) > MTU){
344 		werrstr("nbtrpc: packet bigger than MTU, (%d > %d)", len, MTU);
345 		alarm(0);
346 		return -1;
347 	}
348 
349 	got = readn(p->s->fd, p->buf +NBHDRLEN, len);
350 	alarm(0);
351 
352 	if(Debug && strstr(Debug, "dump"))
353 		xd("rx", p->buf, got +NBHDRLEN);
354 
355 	if(got < 0)
356 		return -1;
357 	p->eop = p->buf + got +NBHDRLEN;
358 	return got+NBHDRLEN;
359 }
360 
361 
362 void
xd(char * str,void * buf,int n)363 xd(char *str, void *buf, int n)
364 {
365 	int fd, flg, flags2, cmd;
366 	uint sum;
367 	long err;
368 	uchar *p, *end;
369 
370 	if(n == 0)
371 		return;
372 
373 	p = buf;
374 	end = (uchar *)buf +n;
375 
376 	if(Debug && strstr(Debug, "log") != nil){
377 		if((fd = open("pkt.log", ORDWR)) == -1)
378 			return;
379 		seek(fd, 0, 2);
380 		fprint(fd, "%d	", 0);
381 		while(p < end)
382 			fprint(fd, "%02x ", *p++);
383 		fprint(fd, "\n");
384 		close(fd);
385 		return;
386 	}
387 
388 	if(!str)
389 		goto Raw;
390 
391 	p = (uchar *)buf + 4;
392 	if(GL32(&p) == 0x424d53ff){
393 		buf = (uchar *)buf + 4;
394 		n -= 4;
395 	}
396 	end = (uchar *)buf + n;
397 
398 	sum = 0;
399 	p = buf;
400 	while(p < end)
401 		sum += *p++;
402 	p = buf;
403 
404 	fprint(2, "%s : len=%ud sum=%d\n", str, n, sum);
405 
406 	fprint(2, "mag=0x%ulx ", GL32(&p));
407 	fprint(2, "cmd=0x%ux ", cmd = G8(&p));
408 	fprint(2, "err=0x%ulx ", err=GL32(&p));
409 	fprint(2, "flg=0x%02ux ", flg = G8(&p));
410 	fprint(2, "flg2=0x%04ux\n", flags2= GL16(&p));
411 	fprint(2, "dfs=%s\n", (flags2 & FL2_DFS)? "y": "n");
412 
413 	fprint(2, "pidl=%ud ", GL16(&p));
414 	fprint(2, "res=%uld ", GL32(&p));
415 	fprint(2, "sid=%ud ", GL16(&p));
416 	fprint(2, "seq=0x%ux ", GL16(&p));
417 	fprint(2, "pad=%ud ", GL16(&p));
418 
419 	fprint(2, "tid=%ud ", GL16(&p));
420 	fprint(2, "pid=%ud ", GL16(&p));
421 	fprint(2, "uid=%ud ", GL16(&p));
422 	fprint(2, "mid=%ud\n", GL16(&p));
423 
424 	if(cmd == 0x32 && (flg & 0x80) == 0){		/* TRANS 2, TX */
425 		fprint(2, "words=%ud ", G8(&p));
426 		fprint(2, "totparams=%ud ", GL16(&p));
427 		fprint(2, "totdata=%ud ", GL16(&p));
428 		fprint(2, "maxparam=%ud ", GL16(&p));
429 		fprint(2, "maxdata=%ud\n", GL16(&p));
430 		fprint(2, "maxsetup=%ud ", G8(&p));
431 		fprint(2, "reserved=%ud ", G8(&p));
432 		fprint(2, "flags=%ud ", GL16(&p));
433 		fprint(2, "timeout=%uld\n", GL32(&p));
434 		fprint(2, "reserved=%ud ", GL16(&p));
435 		fprint(2, "paramcnt=%ud ", GL16(&p));
436 		fprint(2, "paramoff=%ud ", GL16(&p));
437 		fprint(2, "datacnt=%ud ", GL16(&p));
438 		fprint(2, "dataoff=%ud ", GL16(&p));
439 		fprint(2, "setupcnt=%ud ", G8(&p));
440 		fprint(2, "reserved=%ud\n", G8(&p));
441 		fprint(2, "trans2=0x%02x ", GL16(&p));
442 		fprint(2, "data-words=%d ", G8(&p));
443 		fprint(2, "padding=%d\n", G8(&p));
444 	}
445 	if(cmd == 0x32 && (flg & 0x80) == 0x80){	/* TRANS 2, RX */
446 		fprint(2, "words=%ud ", G8(&p));
447 		fprint(2, "totparams=%ud ", GL16(&p));
448 		fprint(2, "totdata=%ud ", GL16(&p));
449 		fprint(2, "reserved=%ud ", GL16(&p));
450 		fprint(2, "paramcnt=%ud\n", GL16(&p));
451 		fprint(2, "paramoff=%ud ", GL16(&p));
452 		fprint(2, "paramdisp=%ud ", GL16(&p));
453 		fprint(2, "datacnt=%ud\n", GL16(&p));
454 		fprint(2, "dataoff=%ud ", GL16(&p));
455 		fprint(2, "datadisp=%ud ", GL16(&p));
456 		fprint(2, "setupcnt=%ud ", G8(&p));
457 		fprint(2, "reserved=%ud\n", G8(&p));
458 	}
459 	if(err)
460 		if(flags2 & FL2_NT_ERRCODES)
461 			fprint(2, "err=%s\n", nterrstr(err));
462 		else
463 			fprint(2, "err=%s\n", doserrstr(err));
464 Raw:
465 	fprint(2, "\n");
466 	for(; p < end; p++){
467 		if((p - (uchar *)buf) % 16 == 0)
468 			fprint(2, "\n%06lx\t", p - (uchar *)buf);
469 		if(isprint((char)*p))
470 			fprint(2, "%c  ", (char )*p);
471 		else
472 			fprint(2, "%02ux ", *p);
473 	}
474 	fprint(2, "\n");
475 }
476