/* * This file is part of the UCB release of Plan 9. It is subject to the license * terms in the LICENSE file found in the top-level directory of this * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No * part of the UCB release of Plan 9, including this file, may be copied, * modified, propagated, or distributed except according to the terms contained * in the LICENSE file. */ /* * 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 ulongGL32(uchar **p){ ulong n; n = *(*p)++; n |= *(*p)++ << 8; n |= *(*p)++ << 16; n |= *(*p)++ << 24; return n;} static ushortGL16(uchar **p){ ushort n; n = *(*p)++; n |= *(*p)++ << 8; return n;} voidGmem(uchar **p, void *v, int n){ uchar *str = v; while(n--) *str++ = *(*p)++;} static ulongGB32(uchar **p){ ulong n; n = *(*p)++ << 24; n |= *(*p)++ << 16; n |= *(*p)++ << 8; n |= *(*p)++; return n;} static ushortGB16(uchar **p){ ushort n; n = *(*p)++ << 8; n |= *(*p)++; return n;} static ucharG8(uchar **p){ return *(*p)++;} static voidPB16(uchar **p, uint n){ *(*p)++ = n >> 8; *(*p)++ = n;} static voidP8(uchar **p, uint n){ *(*p)++ = n;} static voidnbname(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;} intcalledname(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;} intnbtdial(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;} voidnbthdr(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) */} intnbtrpc(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;} voidxd(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");}
/*
* This file is part of the UCB release of Plan 9. It is subject to the license
* terms in the LICENSE file found in the top-level directory of this
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
* part of the UCB release of Plan 9, including this file, may be copied,
* modified, propagated, or distributed except according to the terms contained
* in the LICENSE file.
*/
/*
* 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");
}