]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/cifs/netbios.c
cifs: merge with steve simons latest version. thank you very much!
[plan9front.git] / sys / src / cmd / cifs / netbios.c
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
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
53 GL16(uchar **p)
54 {
55         ushort n;
56
57         n  = *(*p)++;
58         n |= *(*p)++ << 8;
59         return n;
60 }
61
62 void
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
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
85 GB16(uchar **p)
86 {
87         ushort n;
88
89         n  = *(*p)++ << 8;
90         n |= *(*p)++;
91         return n;
92 }
93
94 static uchar
95 G8(uchar **p)
96 {
97         return *(*p)++;
98 }
99
100 static void
101 PB16(uchar **p, uint n)
102 {
103         *(*p)++ = n >> 8;
104         *(*p)++ = n;
105 }
106
107 static void
108 P8(uchar **p, uint n)
109 {
110         *(*p)++ = n;
111 }
112
113
114 static void
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
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
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
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
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
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%06zx\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 }