summaryrefslogtreecommitdiff
path: root/sys/src/cmd/cifs/netbios.c
diff options
context:
space:
mode:
authorTaru Karttunen <taruti@taruti.net>2011-03-30 15:46:40 +0300
committerTaru Karttunen <taruti@taruti.net>2011-03-30 15:46:40 +0300
commite5888a1ffdae813d7575f5fb02275c6bb07e5199 (patch)
treed8d51eac403f07814b9e936eed0c9a79195e2450 /sys/src/cmd/cifs/netbios.c
Import sources from 2011-03-30 iso image
Diffstat (limited to 'sys/src/cmd/cifs/netbios.c')
-rwxr-xr-xsys/src/cmd/cifs/netbios.c475
1 files changed, 475 insertions, 0 deletions
diff --git a/sys/src/cmd/cifs/netbios.c b/sys/src/cmd/cifs/netbios.c
new file mode 100755
index 000000000..708dd41a1
--- /dev/null
+++ b/sys/src/cmd/cifs/netbios.c
@@ -0,0 +1,475 @@
+/*
+ * netbios dial, read, write
+ */
+
+#include <u.h>
+#include <libc.h>
+#include <ctype.h>
+#include <fcall.h>
+#include <thread.h>
+#include <9p.h>
+#include "cifs.h"
+
+enum {
+ MAXNBPKT = 8096, /* max netbios packet size */
+ NBquery = 0, /* packet type - query */
+
+ NBAdapterStatus = 0x21, /* get host interface info */
+ NBInternet = 1, /* scope for info */
+
+ NBmessage = 0x00, /* Netbios packet types */
+ NBrequest = 0x81,
+ NBpositive,
+ NBnegative,
+ NBretarget,
+ NBkeepalive,
+
+ ISgroup = 0x8000,
+};
+
+
+static char *NBerr[] = {
+ [0] "not listening on called name",
+ [1] "not listening for calling name",
+ [2] "called name not present",
+ [3] "insufficient resources",
+ [15] "unspecified error"
+};
+
+
+static ulong
+GL32(uchar **p)
+{
+ ulong n;
+
+ n = *(*p)++;
+ n |= *(*p)++ << 8;
+ n |= *(*p)++ << 16;
+ n |= *(*p)++ << 24;
+ return n;
+}
+
+static ushort
+GL16(uchar **p)
+{
+ ushort n;
+
+ n = *(*p)++;
+ n |= *(*p)++ << 8;
+ return n;
+}
+
+void
+Gmem(uchar **p, void *v, int n)
+{
+ uchar *str = v;
+
+ while(n--)
+ *str++ = *(*p)++;
+}
+
+
+static ulong
+GB32(uchar **p)
+{
+ ulong n;
+
+ n = *(*p)++ << 24;
+ n |= *(*p)++ << 16;
+ n |= *(*p)++ << 8;
+ n |= *(*p)++;
+ return n;
+}
+
+static ushort
+GB16(uchar **p)
+{
+ ushort n;
+
+ n = *(*p)++ << 8;
+ n |= *(*p)++;
+ return n;
+}
+
+static uchar
+G8(uchar **p)
+{
+ return *(*p)++;
+}
+
+static void
+PB16(uchar **p, uint n)
+{
+ *(*p)++ = n >> 8;
+ *(*p)++ = n;
+}
+
+static void
+P8(uchar **p, uint n)
+{
+ *(*p)++ = n;
+}
+
+
+static void
+nbname(uchar **p, char *name, char pad)
+{
+ char c;
+ int i;
+ int done = 0;
+
+ *(*p)++ = 0x20;
+ for(i = 0; i < 16; i++) {
+ c = pad;
+ if(!done && name[i] == '\0')
+ done = 1;
+ if(!done)
+ c = toupper(name[i]);
+ *(*p)++ = ((uchar)c >> 4) + 'A';
+ *(*p)++ = (c & 0xf) + 'A';
+ }
+ *(*p)++ = 0;
+}
+
+int
+calledname(char *host, char *name)
+{
+ char *addr;
+ uchar buf[1024], *p;
+ static char tmp[20];
+ int num, flg, svs, j, i, fd, trn;
+
+ trn = (getpid() ^ time(0)) & 0xffff;
+ if((addr = netmkaddr(host, "udp", "137")) == nil)
+ return -1;
+
+ if((fd = dial(addr, "137", 0, 0)) < 0)
+ return -1;
+ p = buf;
+
+ PB16(&p, trn); /* TRNid */
+ P8(&p, 0); /* flags */
+ P8(&p, 0x10); /* type */
+ PB16(&p, 1); /* # questions */
+ PB16(&p, 0); /* # answers */
+ PB16(&p, 0); /* # authority RRs */
+ PB16(&p, 0); /* # Aditional RRs */
+ nbname(&p, "*", 0);
+ PB16(&p, NBAdapterStatus);
+ PB16(&p, NBInternet);
+
+ if(Debug && strstr(Debug, "dump"))
+ xd(nil, buf, p-buf);
+
+ if(write(fd, buf, p-buf) != p-buf)
+ return -1;
+
+ p = buf;
+ for(i = 0; i < 3; i++){
+ memset(buf, 0, sizeof(buf));
+ alarm(NBNSTOUT);
+ read(fd, buf, sizeof(buf));
+ alarm(0);
+ if(GB16(&p) == trn)
+ break;
+ }
+ close(fd);
+ if(i >= 3)
+ return -1;
+
+ p = buf +56;
+ num = G8(&p); /* number of names */
+
+ for(i = 0; i < num; i++){
+ memset(tmp, 0, sizeof(tmp));
+ Gmem(&p, tmp, 15);
+ svs = G8(&p);
+ flg = GB16(&p);
+ for(j = 14; j >= 0 && tmp[j] == ' '; j--)
+ tmp[j] = 0;
+ if(svs == 0 && !(flg & ISgroup))
+ strcpy(name, tmp);
+ }
+ return 0;
+}
+
+
+int
+nbtdial(char *addr, char *called, char *sysname)
+{
+ char redir[20];
+ uchar *p, *lenp, buf[1024];
+ int type, len, err, fd, nkeepalive, nretarg;
+
+ nretarg = 0;
+ nkeepalive = 0;
+Redial:
+ if((addr = netmkaddr(addr, "tcp", "139")) == nil ||
+ (fd = dial(addr, 0, 0, 0)) < 0)
+ return -1;
+
+ memset(buf, 0, sizeof(buf));
+
+ p = buf;
+ P8(&p, NBrequest); /* type */
+ P8(&p, 0); /* flags */
+ lenp = p; PB16(&p, 0); /* length placeholder */
+ nbname(&p, called, ' '); /* remote NetBios name */
+ nbname(&p, sysname, ' '); /* our machine name */
+ PB16(&lenp, p-lenp -2); /* length re-write */
+
+ if(Debug && strstr(Debug, "dump"))
+ xd(nil, buf, p-buf);
+ if(write(fd, buf, p-buf) != p-buf)
+ goto Error;
+Reread:
+ p = buf;
+ memset(buf, 0, sizeof(buf));
+ if(readn(fd, buf, 4) < 4)
+ goto Error;
+
+ type = G8(&p);
+ G8(&p); /* flags */
+ len = GB16(&p);
+
+ if(readn(fd, buf +4, len -4) < len -4)
+ goto Error;
+
+ if(Debug && strstr(Debug, "dump"))
+ xd(nil, buf, len+4);
+
+ switch(type) {
+ case NBpositive:
+ return fd;
+ case NBnegative:
+ if(len < 1) {
+ werrstr("nbdial: bad error pkt");
+ goto Error;
+ }
+ err = G8(&p);
+ if(err < 0 || err > nelem(NBerr) || NBerr[err] == nil)
+ werrstr("NBT: %d - unknown error", err);
+ else
+ werrstr("NBT: %s", NBerr[err]);
+
+ goto Error;
+ case NBkeepalive:
+ if(++nkeepalive >= 16){
+ werrstr("nbdial: too many keepalives");
+ goto Error;
+ }
+ goto Reread;
+
+ case NBretarget:
+ if(++nretarg >= 16) {
+ werrstr("nbdial: too many redirects");
+ goto Error;
+ }
+ if(len < 4) {
+ werrstr("nbdial: bad redirect pkt");
+ goto Error;
+ }
+ sprint(redir, "%d.%d.%d.%d", p[0], p[1], p[2], p[3]);
+ addr = redir;
+ goto Redial;
+
+ default:
+ werrstr("nbdial: 0x%x - unknown packet in netbios handshake", type);
+ goto Error;
+ }
+Error:
+ close(fd);
+ return -1;
+}
+
+void
+nbthdr(Pkt *p)
+{
+ p->pos = p->buf;
+ memset(p->buf, 0xa5, MTU);
+
+ p8(p, NBmessage); /* type */
+ p8(p, 0); /* flags */
+ pb16(p, 0); /* length (filled in later) */
+}
+
+int
+nbtrpc(Pkt *p)
+{
+ int len, got, type, nkeep;
+
+ len = p->pos - p->buf;
+
+ p->pos = p->buf +2;
+ pb16(p, len - NBHDRLEN); /* length */
+
+ if(Debug && strstr(Debug, "dump"))
+ xd("tx", p->buf, len);
+
+ alarm(NBRPCTOUT);
+ if(write(p->s->fd, p->buf, len) != len){
+ werrstr("nbtrpc: write failed - %r");
+ alarm(0);
+ return -1;
+ }
+
+ nkeep = 0;
+retry:
+ p->pos = p->buf;
+ memset(p->buf, 0xa5, MTU);
+
+ got = readn(p->s->fd, p->buf, NBHDRLEN);
+
+ if(got < NBHDRLEN){
+ werrstr("nbtrpc: short read - %r");
+ alarm(0);
+ return -1;
+ }
+ p->eop = p->buf + got;
+
+ type = g8(p); /* NBT type (session) */
+ if(type == NBkeepalive){
+ if(++nkeep > 16) {
+ werrstr("nbtrpc: too many keepalives (%d attempts)", nkeep);
+ alarm(0);
+ return -1;
+ }
+ goto retry;
+ }
+
+ g8(p); /* NBT flags (none) */
+
+ len = gb16(p); /* NBT payload length */
+ if((len +NBHDRLEN) > MTU){
+ werrstr("nbtrpc: packet bigger than MTU, (%d > %d)", len, MTU);
+ alarm(0);
+ return -1;
+ }
+
+ got = readn(p->s->fd, p->buf +NBHDRLEN, len);
+ alarm(0);
+
+ if(Debug && strstr(Debug, "dump"))
+ xd("rx", p->buf, got +NBHDRLEN);
+
+ if(got < 0)
+ return -1;
+ p->eop = p->buf + got +NBHDRLEN;
+ return got+NBHDRLEN;
+}
+
+
+void
+xd(char *str, void *buf, int n)
+{
+ int fd, flg, flags2, cmd;
+ uint sum;
+ long err;
+ uchar *p, *end;
+
+ if(n == 0)
+ return;
+
+ p = buf;
+ end = (uchar *)buf +n;
+
+ if(Debug && strstr(Debug, "log") != nil){
+ if((fd = open("pkt.log", ORDWR)) == -1)
+ return;
+ seek(fd, 0, 2);
+ fprint(fd, "%d ", 0);
+ while(p < end)
+ fprint(fd, "%02x ", *p++);
+ fprint(fd, "\n");
+ close(fd);
+ return;
+ }
+
+ if(!str)
+ goto Raw;
+
+ p = (uchar *)buf + 4;
+ if(GL32(&p) == 0x424d53ff){
+ buf = (uchar *)buf + 4;
+ n -= 4;
+ }
+ end = (uchar *)buf + n;
+
+ sum = 0;
+ p = buf;
+ while(p < end)
+ sum += *p++;
+ p = buf;
+
+ fprint(2, "%s : len=%ud sum=%d\n", str, n, sum);
+
+ fprint(2, "mag=0x%ulx ", GL32(&p));
+ fprint(2, "cmd=0x%ux ", cmd = G8(&p));
+ fprint(2, "err=0x%ulx ", err=GL32(&p));
+ fprint(2, "flg=0x%02ux ", flg = G8(&p));
+ fprint(2, "flg2=0x%04ux\n", flags2= GL16(&p));
+ fprint(2, "dfs=%s\n", (flags2 & FL2_DFS)? "y": "n");
+
+ fprint(2, "pidl=%ud ", GL16(&p));
+ fprint(2, "res=%uld ", GL32(&p));
+ fprint(2, "sid=%ud ", GL16(&p));
+ fprint(2, "seq=0x%ux ", GL16(&p));
+ fprint(2, "pad=%ud ", GL16(&p));
+
+ fprint(2, "tid=%ud ", GL16(&p));
+ fprint(2, "pid=%ud ", GL16(&p));
+ fprint(2, "uid=%ud ", GL16(&p));
+ fprint(2, "mid=%ud\n", GL16(&p));
+
+ if(cmd == 0x32 && (flg & 0x80) == 0){ /* TRANS 2, TX */
+ fprint(2, "words=%ud ", G8(&p));
+ fprint(2, "totparams=%ud ", GL16(&p));
+ fprint(2, "totdata=%ud ", GL16(&p));
+ fprint(2, "maxparam=%ud ", GL16(&p));
+ fprint(2, "maxdata=%ud\n", GL16(&p));
+ fprint(2, "maxsetup=%ud ", G8(&p));
+ fprint(2, "reserved=%ud ", G8(&p));
+ fprint(2, "flags=%ud ", GL16(&p));
+ fprint(2, "timeout=%uld\n", GL32(&p));
+ fprint(2, "reserved=%ud ", GL16(&p));
+ fprint(2, "paramcnt=%ud ", GL16(&p));
+ fprint(2, "paramoff=%ud ", GL16(&p));
+ fprint(2, "datacnt=%ud ", GL16(&p));
+ fprint(2, "dataoff=%ud ", GL16(&p));
+ fprint(2, "setupcnt=%ud ", G8(&p));
+ fprint(2, "reserved=%ud\n", G8(&p));
+ fprint(2, "trans2=0x%02x ", GL16(&p));
+ fprint(2, "data-words=%d ", G8(&p));
+ fprint(2, "padding=%d\n", G8(&p));
+ }
+ if(cmd == 0x32 && (flg & 0x80) == 0x80){ /* TRANS 2, RX */
+ fprint(2, "words=%ud ", G8(&p));
+ fprint(2, "totparams=%ud ", GL16(&p));
+ fprint(2, "totdata=%ud ", GL16(&p));
+ fprint(2, "reserved=%ud ", GL16(&p));
+ fprint(2, "paramcnt=%ud\n", GL16(&p));
+ fprint(2, "paramoff=%ud ", GL16(&p));
+ fprint(2, "paramdisp=%ud ", GL16(&p));
+ fprint(2, "datacnt=%ud\n", GL16(&p));
+ fprint(2, "dataoff=%ud ", GL16(&p));
+ fprint(2, "datadisp=%ud ", GL16(&p));
+ fprint(2, "setupcnt=%ud ", G8(&p));
+ fprint(2, "reserved=%ud\n", G8(&p));
+ }
+ if(err)
+ if(flags2 & FL2_NT_ERRCODES)
+ fprint(2, "err=%s\n", nterrstr(err));
+ else
+ fprint(2, "err=%s\n", doserrstr(err));
+Raw:
+ fprint(2, "\n");
+ for(; p < end; p++){
+ if((p - (uchar *)buf) % 16 == 0)
+ fprint(2, "\n%06lx\t", p - (uchar *)buf);
+ if(isprint((char)*p))
+ fprint(2, "%c ", (char )*p);
+ else
+ fprint(2, "%02ux ", *p);
+ }
+ fprint(2, "\n");
+}