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