484 lines · 9.2 KB · C
RawDownload
/*  * 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");}