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