shithub: rd

ref: baf602582a840a0253900d41a2f1cce7156dd770
dir: /rd.c/

View raw version
#include <u.h>
#include <libc.h>
#include <auth.h>
#include <draw.h>
#include "dat.h"
#include "fns.h"

Rdp rd = {
	.fd = -1,
	.chan = RGB16,
	.depth = 16,
	.dim = {800, 600},
	.windom = "",
	.passwd = "",
	.shell = "",
	.rwd = "",
};

char Eshort[]=	"short data";
char Esmall[]=	"buffer too small";
char Ebignum[]=	"number too big";

static void
usage(void)
{
	fprint(2, "usage: rd [-0A] [-T title] [-a depth] [-c wdir] [-d dom] [-k keyspec] [-n term] [-s shell] [net!]server[!port]\n");
	exits("usage");
}

long
writen(int fd, void* buf, long nbytes)
{
	long n, sofar;

	sofar = 0;
	while(sofar < nbytes){
		n = write(fd, buf, nbytes-sofar);
		if(n <= 0)
			break;
		sofar += n;
	}
	return sofar;
}

static int
startmouseproc(void)
{
	int mpid;

	switch(mpid = rfork(RFPROC|RFMEM)){
	case -1:
		sysfatal("rfork: %r");
	case 0:
		break;
	default:
		return mpid;
	}
	atexit(atexitkiller);
	readdevmouse();
	exits("mouse eof");
	return 0;
}

static int
startkbdproc(void)
{
	int pid;
	switch(pid = rfork(RFPROC|RFMEM)){
	case -1:
		sysfatal("rfork: %r");
	case 0:
		break;
	default:
		return pid;
	}
	atexit(atexitkiller);
	readkbd();
	exits("kbd eof");
	return 0;
}

static int
startsnarfproc(void)
{
	int pid;

	switch(pid = rfork(RFPROC|RFMEM)){
	case -1:
		sysfatal("rfork: %r");
	case 0:
		break;
	default:
		return pid;
	}
	atexit(atexitkiller);
	pollsnarf();
	exits("snarf eof");
	return 0;
}

static int killpid[32];
static int nkillpid;

void
atexitkiller(void)
{
	int i, pid;

	pid = getpid();
	for(i=0; i<nkillpid; i++)
		if(pid != killpid[i])
			postnote(PNPROC, killpid[i], "kill");
}
void
atexitkill(int pid)
{
	killpid[nkillpid++] = pid;
}

void
main(int argc, char *argv[])
{
	int doauth, fd;
	char *server, *addr, *keyspec;
	UserPasswd *creds;

	rd.local = getenv("sysname");
	rd.user = getenv("user");

	keyspec = "";
	doauth = 1;

	ARGBEGIN {
	case 'A':
		doauth = 0;
		break;
	case 'k':
		keyspec = EARGF(usage());
		break;
	case 'T':
		rd.label = strdup(EARGF(usage()));
		break;
	case 'd':
		rd.windom = strdup(EARGF(usage()));
		break;
	case 's':
		rd.shell = strdup(EARGF(usage()));
		break;
	case 'c':
		rd.rwd = strdup(EARGF(usage()));
		break;
	case 'n':
		rd.local = estrdup(EARGF(usage()));
		break;
	case 'a':
		rd.depth = atol(EARGF(usage()));
		switch(rd.depth){
		case 8:
			rd.chan = CMAP8;
			break;
		case 15:
			rd.chan = RGB15;
			break;
		case 16:
			rd.chan = RGB16;
			break;
		case 24:
			rd.chan = RGB24;
			break;
		case 32:
			rd.chan = XRGB32;
			break;
		default:
			sysfatal("bad color depth");
		}
		break;
	case '0':
		rd.wantconsole = 1;
		break;
	default:
		usage();
	} ARGEND

	if (argc != 1)
		usage();

	server = argv[0];
	if(rd.local == nil)
		sysfatal("set $sysname or use -n\n");
	if(rd.user == nil)
		sysfatal("set $user");
	if (rd.label == nil)
		rd.label = smprint("rd %s", server);

	if(doauth){
		creds = auth_getuserpasswd(auth_getkey, "proto=pass service=rdp %s", keyspec);
		if(creds == nil)
			fprint(2, "factotum: %r\n");
		else {
			rd.user = creds->user;
			rd.passwd = creds->passwd;
			rd.autologon = 1;
		}
	}

	addr = netmkaddr(server, "tcp", "3389");
	fd = dial(addr, nil, nil, nil);
	if(fd < 0)
		sysfatal("dial %s: %r", addr);
	rd.fd = fd;
	if(x224connect(fd) < 0)
		sysfatal("initial handshake failed: %r");

	if(initdraw(drawerror, nil, rd.label) < 0)
		sysfatal("initdraw: %r");
	display->locking = 1;
	unlockdisplay(display);

	rd.dim.y = Dy(screen->r);
	rd.dim.x = Dx(screen->r);
	rd.dim.x = (rd.dim.x + 3) & ~3;	/* ensure width divides by 4 */

	if(rdphandshake(fd) < 0)
		sysfatal("handshake failed: %r");

	atexit(atexitkiller);
	atexitkill(getpid());
	atexitkill(startmouseproc());
	atexitkill(startkbdproc());
	initsnarf();
	atexitkill(startsnarfproc());

	readnet(rd.fd);

	x224disconnect(rd.fd);
	close(rd.fd);
	lockdisplay(display);
	closedisplay(display);

	if(!rd.active)
		exits(nil);
	if(rd.hupreason)
		sysfatal("hangup: %d", rd.hupreason);
	sysfatal("hangup");
}

void*
emalloc(ulong n)
{
	void *b;

	b = mallocz(n, 1);
	if(b == nil)
		sysfatal("out of memory allocating %lud: %r", n);
	setmalloctag(b, getcallerpc(&n));
	return b;
}

void*
erealloc(void *a, ulong n)
{
	void *b;

	b = realloc(a, n);
	if(b == nil)
		sysfatal("out of memory re-allocating %lud: %r", n);
	setrealloctag(b, getcallerpc(&a));
	return b;
}

char*
estrdup(const char *s)
{
	char *b;

	b = strdup(s);
	if(b == nil)
		sysfatal("strdup: %r");
	setmalloctag(b, getcallerpc(&s));
	return b;
}