tmcc.c 17.2 KB
Newer Older
Leigh B. Stoller's avatar
Leigh B. Stoller committed
1 2
/*
 * EMULAB-COPYRIGHT
3
 * Copyright (c) 2000-2004 University of Utah and the Flux Group.
Leigh B. Stoller's avatar
Leigh B. Stoller committed
4 5
 * All rights reserved.
 */
6 7 8 9 10 11 12 13 14 15 16

#ifdef _WIN32
/*Windows version should be linked to: WS2_32*/
/*g++ -Wall -o tmcc tmcc.c -D_WIN32 -lWS2_32*/
#include <winsock2.h>
#include <unistd.h>
#include <getopt.h>
typedef int socklen_t;
#define ECONNREFUSED WSAECONNREFUSED
#endif

17
#include <sys/types.h>
18
#ifndef _WIN32
19 20
#  include <sys/socket.h>
#  include <netinet/in.h>
21
#endif
22 23
#include <sys/un.h>
#include <sys/fcntl.h>
24 25 26 27 28
#include <stdio.h>
#include <errno.h>
#include <syslog.h>
#include <unistd.h>
#include <signal.h>
29 30 31
#ifdef __CYGWIN__
  typedef _sig_func_ptr sig_t;
#endif /* __CYGWIN__ */
32
#include <stdarg.h>
Mike Hibler's avatar
Mike Hibler committed
33 34
#include <stdlib.h>
#include <string.h>
35
#include <sys/time.h>
36
#include <sys/stat.h>
37 38
#include <time.h>
#include <assert.h>
39
#include <sys/types.h>
40
#ifndef _WIN32
41 42 43
#  include <netinet/in.h>
#  include <arpa/inet.h>
#  include <netdb.h>
44
#endif
45
#include "decls.h"
46
#include "ssl.h"
47
#ifndef STANDALONE
48
#  include "config.h"
49
#endif
50
#ifndef _WIN32
51 52 53 54
#  undef  BOSSNODE
#  if !defined(BOSSNODE) && !defined(__CYGWIN__)
#    include <resolv.h>
#  endif
55
#endif
56
#include <setjmp.h>
57

58
#ifndef KEYFILE
59
#  define KEYFILE		"/etc/emulab.pkey"
60
#endif
61

62 63 64 65 66
/*
 * We search a couple of dirs for the bossnode file.
 */
static char *bossnodedirs[] = {
	"/etc/testbed",
67
	"/etc/emulab",
68 69 70 71 72 73
	"/etc/rc.d/testbed",
	"/usr/local/etc/testbed",
	"/usr/local/etc/emulab",
	0
};

74 75 76 77 78 79 80
/*
 * Need to try several ports cause of firewalling. 
 */
static int portlist[] = {
	TBSERVER_PORT,
	TBSERVER_PORT2,
};
81 82 83 84 85 86
/* Locals */
static int	numports = sizeof(portlist)/sizeof(int);
static int	debug = 0;
static char    *logfile = NULL;

/* Forward decls */
87
static int	getbossnode(char **, int *);
88 89 90 91 92
static int	doudp(char *, int, struct in_addr, int);
static int	dotcp(char *, int, struct in_addr);
static int	dounix(char *, int, char *);
static void	beproxy(char *, struct in_addr, char *);
static int	dooutput(int, char *, int);
93

94
char *usagestr = 
95 96
 "usage: tmcc [options] <command>\n"
 " -d		   Turn on debugging\n"
97
 " -s server	   Specify a tmcd server to connect to\n"
98
 " -p portnum	   Specify a port number to connect to\n"
99
 " -v versnum	   Specify a version number for tmcd\n"
100
 " -n vnodeid	   Specify the vnodeid\n"
101
 " -k keyfile	   Specify the private keyfile\n"
102
 " -u		   Use UDP instead of TCP\n"
103
 " -l path	   Use named unix domain socket instead of TCP\n"
104
 " -t timeout	   Timeout waiting for the controller.\n"
105
 " -x path	   Be a tmcc proxy, using the named unix domain socket\n"
106
 " -o logfile      Specify log file name for -x option\n"
107
 " -i              Do not use SSL protocol\n"
108 109 110 111 112 113 114 115 116
 "\n";

void
usage()
{
	fprintf(stderr, usagestr);
	exit(1);
}

117 118 119 120 121 122 123 124
/*
 * We cannot let remote nodes hang, but they can be slow. If we get connected
 * we give it an extra timeout, and if we make any progress at all, keep
 * giving it extra timeouts.
 */
static int connected = 0;
static int progress  = 0;
static int waitfor   = 0;
125
static sigjmp_buf progtimo;
126 127

static void
128
tooktoolong(void)
129 130 131 132 133 134 135 136 137 138
{
	static int	lastprogress = 0;

	/* If we made progress, keep going (reset timer too) */
	if (connected && progress > lastprogress) {
		lastprogress = progress;
		alarm(waitfor);
		return;
	}

139
	siglongjmp(progtimo, 1);
140
}
141

Mike Hibler's avatar
Mike Hibler committed
142
int
143 144
main(int argc, char **argv)
{
145
	int			n, ch;
146 147
	struct hostent		*he;
	struct in_addr		serverip;
148
	char			buf[MYBUFSIZE], *bp;
149
	FILE			*fp;
150 151
	volatile int		useudp    = 0;
	char			* volatile unixpath = NULL;
152 153 154 155 156 157
	char			*bossnode = NULL;
	int			version   = CURRENT_VERSION;
	char			*vnodeid  = NULL;
	char			*keyfile  = NULL;
	char			*privkey  = NULL;
	char			*proxypath= NULL;
158 159 160
#ifdef _WIN32
        WSADATA wsaData;
#endif
161

162
	while ((ch = getopt(argc, argv, "v:s:p:un:t:k:x:l:do:i")) != -1)
163
		switch(ch) {
164 165 166
		case 'd':
			debug++;
			break;
167
		case 'p':
168 169
			portlist[0] = atoi(optarg);
			numports    = 1;
170
			break;
171 172 173
		case 's':
			bossnode = optarg;
			break;
174 175 176
		case 'n':
			vnodeid = optarg;
			break;
177 178 179
		case 'k':
			keyfile = optarg;
			break;
180 181 182
		case 'v':
			version = atoi(optarg);
			break;
183 184 185
		case 't':
			waitfor = atoi(optarg);
			break;
186 187 188
		case 'u':
			useudp = 1;
			break;
189 190 191 192 193 194 195 196 197
		case 'x':
			proxypath = optarg;
			break;
		case 'l':
			unixpath  = optarg;
			break;
		case 'o':
			logfile  = optarg;
			break;
198 199 200 201 202
		case 'i':
#ifdef WITHSSL
			nousessl = 1;
#endif
			break;
203 204 205 206
		default:
			usage();
		}

207
	argv += optind;
208
	argc -= optind;
209
	if (!proxypath && (argc < 1 || argc > 5)) {
210
		usage();
211
	}
212 213
	if (unixpath && proxypath)
		usage();
214

215 216 217 218
	if (unixpath && (keyfile || bossnode)) {
		fprintf(stderr,
			"You may not use the -k or -s with the -l option\n");
		usage();
219
	}
220

221 222 223 224 225 226 227
#ifdef _WIN32
        /*Windows requires us to start up the version of the network API that we want*/
	if(WSAStartup( MAKEWORD( 2, 2 ), &wsaData )) {
	        fprintf(stderr,"WSAStartup failed\n");
		exit(1);
	}
#endif
228 229 230 231 232 233 234
#ifdef WITHSSL
	/*
	 * Brutal hack for inner elab; see rc.inelab.
	 */
	if (getenv("TMCCNOSSL") != NULL)
		nousessl = 1;
#endif
235

236 237 238 239 240 241 242 243 244 245
	if (!bossnode) {
		int	port = 0;
		
		getbossnode(&bossnode, &port);
		/* In other words, do not override command line port spec! */
		if (port && numports > 1) {
			portlist[0] = port;
			numports    = 1;
		}
	}
246
	
247 248 249 250 251 252 253 254
	he = gethostbyname(bossnode);
	if (he)
		memcpy((char *)&serverip, he->h_addr, he->h_length);
	else {
		fprintf(stderr, "gethostbyname(%s) failed\n", bossnode); 
		exit(1);
	}

255 256 257 258 259 260 261 262
	/*
	 * Handle built-in "bossinfo" command
	 */
	if (!proxypath && (strcmp(argv[0], "bossinfo") == 0)) {
		printf("%s %s\n", bossnode, inet_ntoa(serverip));
		exit(0);
	}

263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284
	/*
	 * Grab the key. Its not an error if we do not find it.
	 */
	if (keyfile) {
		/* Well, if one was specifed it has to exist. */
		if (access(keyfile, R_OK) < 0) {
			perror("keyfile"); 
			exit(1);
		}
	}
	else
		keyfile = KEYFILE;

	if ((fp = fopen(keyfile, "r")) != NULL) {
	    if (fgets(buf, sizeof(buf), fp)) {
		if ((bp = strchr(buf, '\n')))
		    *bp = (char) NULL;
		privkey = strdup(buf);
	    }
	    fclose(fp);
	}

285 286 287 288 289 290 291 292 293 294 295 296 297
	/*
	 * Build up the command request string.
	 */
	buf[0] = '\0';
	
	/* Tack on vnodeid */
	if (vnodeid) {
		sprintf(&buf[strlen(buf)], "VNODEID=%s ", vnodeid);
	}

	/* Tack on privkey */
	if (privkey) {
		sprintf(&buf[strlen(buf)], "PRIVKEY=%s ", privkey);
298 299
	}

300
	/*
301 302
	 * If specified udp with unixpath, then pass through a UDP flag
	 * to the proxy, which will do what it thinks is appropriate.
303
	 */
304 305 306 307 308 309 310 311 312 313
	if (useudp && unixpath) {
		sprintf(&buf[strlen(buf)], "USEUDP=1 ");
		useudp = 0;
	}

	/*
	 * In proxy mode ...
	 */
	if (proxypath) {
		beproxy(proxypath, serverip, buf);
314 315 316
		exit(0);
	}

317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336
	/* Tack on version number */
	sprintf(&buf[strlen(buf)], "VERSION=%d ", version);

	/*
	 * Since we've gone through a getopt() pass, argv[0] is now the
	 * first argument
	 */
	n = strlen(buf);
	while (argc && n < sizeof(buf)) {
		n += snprintf(&buf[n], sizeof(buf) - (n + 1), "%s ", argv[0]);
		argc--;
		argv++;
	}
	if (n >= sizeof(buf)) {
		fprintf(stderr, "Command too large!\n");
		exit(-1);
	}
	buf[n] = '\0';

	/*
337
	 * When a timeout is requested, setup the alarm and die if it triggers.
338 339
	 */
	if (waitfor) {
340 341 342 343 344 345
		if (sigsetjmp(progtimo, 1) != 0) {
			fprintf(stderr,
				"Timed out because there was no progress!\n");
			exit(-1);
		}
		signal(SIGALRM, (sig_t)tooktoolong);
346
		alarm(waitfor);
347
	}
348 349 350 351 352 353 354

	if (useudp)
		n = doudp(buf, fileno(stdout), serverip, portlist[0]);
	else if (unixpath)
		n = dounix(buf, fileno(stdout), unixpath);
	else
		n = dotcp(buf, fileno(stdout), serverip);
355 356
	if (waitfor)
		alarm(0);
357 358 359 360 361 362
	exit(n);
}

/*
 * Find the bossnode name if one was not specified on the command line.
 */
363 364
static int
getbossnode(char **bossnode, int *portp)
365 366
{
#ifdef BOSSNODE
367 368
	*bossnode = strdup(BOSSNODE);
	return 0;
369 370 371 372
#else
	FILE		*fp;
	char		buf[BUFSIZ], **cp = bossnodedirs, *bp;

373 374 375
	/*
	 * Brutal hack for inner elab; see rc.inelab.
	 */
376 377 378 379 380 381 382 383 384 385 386 387 388 389
	if ((bp = getenv("BOSSNAME")) != NULL) {
		strcpy(buf, bp);
		
		/*
		 * Look for port spec
		 */
		if ((bp = strchr(buf, ':'))) {
			*bp++  = (char) NULL;
			*portp = atoi(bp);
		}
		*bossnode = strdup(buf);
		return 0;
	}

390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405
	/*
	 * Search for the file.
	 */
	while (*cp) {
		sprintf(buf, "%s/%s", *cp, BOSSNODE_FILENAME);

		if (access(buf, R_OK) == 0)
			break;
		cp++;
	}
	if (*cp) {
		if ((fp = fopen(buf, "r")) != NULL) {
			if (fgets(buf, sizeof(buf), fp)) {
				if ((bp = strchr(buf, '\n')))
					*bp = (char) NULL;
				fclose(fp);
406 407 408 409
				/*
				 * Look for port spec
				 */
				if ((bp = strchr(buf, ':'))) {
Mike Hibler's avatar
Mike Hibler committed
410
					*bp++  = (char) NULL;
411 412 413 414
					*portp = atoi(bp);
				}
				*bossnode = strdup(buf);
				return 0;
415 416 417 418 419
			}
			fclose(fp);
		}
	}
	
420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436
#  if ! defined(_WIN32) && ! defined(__CYGWIN__)
	{
		/*
		 * Nameserver goo 
		 */
		struct hostent	*he;
		res_init();
		he = gethostbyaddr((char *)&_res.nsaddr.sin_addr,
				   sizeof(struct in_addr), AF_INET);
		if (he && he->h_name) 
			*bossnode = strdup(he->h_name);
		else
			*bossnode = strdup("UNKNOWN");
		return 0;
	}
#  endif
	*bossnode = strdup("UNKNOWN");
437
	return 0;
438
#endif
439 440 441 442 443 444 445 446 447 448 449 450
}

/*
 * TCP version, which uses ssl if compiled in.
 */
static int
dotcp(char *data, int outfd, struct in_addr serverip)
{
	int			n, sock, cc;
	struct sockaddr_in	name;
	char			*bp, buf[MYBUFSIZE];
	
451
#ifdef  WITHSSL
452
	if (!nousessl && tmcd_client_sslinit()) {
453
		printf("SSL initialization failed!\n");
454
		return -1;
455 456
	}
#endif
457
	while (1) {
458 459 460 461
		for (n = 0; n < numports; n++) {
			/* Create socket from which to read. */
			sock = socket(AF_INET, SOCK_STREAM, 0);
			if (sock < 0) {
462
				perror("creating stream socket");
463
				return -1;
464
			}
465

466 467 468 469
			/* Create name. */
			name.sin_family = AF_INET;
			name.sin_addr   = serverip;
			name.sin_port   = htons(portlist[n]);
470

471 472 473 474 475 476 477
			if (CONNECT(sock, (struct sockaddr *) &name,
				    sizeof(name)) == 0) {
				goto foundit;
			}
			if (errno != ECONNREFUSED) {
				perror("connecting stream socket");
				CLOSE(sock);
478
				return -1;
479
			}
480
			CLOSE(sock);
481
		}
482 483 484
		if (debug) 
			fprintf(stderr,
				"Connection to TMCD refused. Waiting ...\n");
485
		sleep(10);
486
	}
487
 foundit:
488
	connected = 1;
489

490
	n = 1;
491
	if (setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (void *)&n, sizeof(n)) < 0) {
492
		perror("setsockopt SO_KEEPALIVE");
493
		goto bad;
494
	}
495

496
	/*
497
	 * Write the command to the socket and wait for the response.
498
	 */
499 500
	bp = data;
	n  = strlen(data);
501
	while (n) {
502
		if ((cc = WRITE(sock, bp, n)) <= 0) {
503
			if (cc < 0) {
504
				perror("Writing to socket");
505
				goto bad;
506 507
			}
			fprintf(stderr, "write aborted");
508
			goto bad;
509 510 511 512 513 514
		}
		bp += cc;
		n  -= cc;
	}

	while (1) {
515
		if ((cc = READ(sock, buf, sizeof(buf) - 1)) <= 0) {
516
			if (cc < 0) {
517
				perror("Reading from socket");
518
				goto bad;
519 520 521
			}
			break;
		}
522
		progress += cc;
523 524
		if (dooutput(outfd, buf, cc) < 0)
			goto bad;
525
	}
526
	CLOSE(sock);
527
	return 0;
528 529
 bad:
	CLOSE(sock);
530
	return -1;
531 532
}

Mike Hibler's avatar
Mike Hibler committed
533 534 535
/*
 * Not very robust, send a single request, read a single reply. 
 */
536 537
static int
doudp(char *data, int outfd, struct in_addr serverip, int portnum)
Mike Hibler's avatar
Mike Hibler committed
538 539 540
{
	int			sock, length, n, cc;
	struct sockaddr_in	name, client;
541
	char			buf[MYBUFSIZE];
Mike Hibler's avatar
Mike Hibler committed
542 543 544 545

	/* Create socket from which to read. */
	sock = socket(AF_INET, SOCK_DGRAM, 0);
	if (sock < 0) {
546
		perror("creating dgram socket");
547
		return -1;
Mike Hibler's avatar
Mike Hibler committed
548 549 550 551 552
	}

	/* Create name. */
	name.sin_family = AF_INET;
	name.sin_addr   = serverip;
553
	name.sin_port   = htons(portnum);
Mike Hibler's avatar
Mike Hibler committed
554 555 556 557

	/*
	 * Write the command to the socket and wait for the response
	 */
558 559
	n  = strlen(data);
	cc = sendto(sock, data, n, 0, (struct sockaddr *)&name, sizeof(name));
Mike Hibler's avatar
Mike Hibler committed
560
	if (cc != n) {
561
		if (cc < 0)
562
			perror("Writing to socket");
563 564 565
		else
			fprintf(stderr, "short write (%d != %d)\n", cc, n);
		close(sock);
566
		return -1;
Mike Hibler's avatar
Mike Hibler committed
567
	}
568
	connected = 1;
Mike Hibler's avatar
Mike Hibler committed
569

Mike Hibler's avatar
Mike Hibler committed
570
	length = sizeof(client);
571
	cc = recvfrom(sock, buf, sizeof(buf) - 1, 0,
Mike Hibler's avatar
Mike Hibler committed
572 573
		      (struct sockaddr *)&client, &length);
	if (cc < 0) {
574
		perror("Reading from socket");
575
		close(sock);
576
		return -1;
Mike Hibler's avatar
Mike Hibler committed
577
	}
578
	close(sock);
579
	progress += cc;
580 581 582 583
	if (dooutput(outfd, buf, cc) < 0)
		return -1;
	return 0;
}
Mike Hibler's avatar
Mike Hibler committed
584

585 586 587 588 589 590
/*
 * Unix domain version.
 */
static int
dounix(char *data, int outfd, char *unixpath)
{
591 592
#if defined(linux) || defined(_WIN32)
	fprintf(stderr, "unix domain socket mode not supported on this platform!\n");
593 594 595 596 597 598 599 600
	return -1;
#else
	int			n, sock, cc, length;
	struct sockaddr_un	sunaddr;
	char			*bp, buf[MYBUFSIZE];

	sunaddr.sun_family = AF_UNIX;
	strlcpy(sunaddr.sun_path, unixpath, sizeof(sunaddr.sun_path));
601 602 603 604
	length = SUN_LEN(&sunaddr)+1;
#  ifndef __CYGWIN__
	sunaddr.sun_len = length;
#  endif /* __CYGWIN__ */
605 606 607 608

	/* Create socket from which to read. */
	sock = socket(AF_UNIX, SOCK_STREAM, 0);
	if (sock < 0) {
609
		perror("creating stream socket");
610 611 612
		return -1;
	}

613 614 615 616 617 618 619
	/*
	 * Retry if the unixpath does not exist. Caller must use timeout option.
	 */
	while (1) {
		if (connect(sock, (struct sockaddr *) &sunaddr, length) == 0)
			break;

620
		if (errno != ENOENT && errno != ECONNREFUSED) {
621 622 623 624 625 626 627 628
			perror("connecting unix domain socket");
			close(sock);
			return -1;
		}

		if (debug) 
			fprintf(stderr,
				"Connection to TMCD refused. Waiting ...\n");
629
		sleep(1);
630
	}
631
	connected = 1;
632 633 634 635 636 637 638 639 640

	/*
	 * Write the command to the socket and wait for the response.
	 */
	bp = data;
	n  = strlen(data);
	while (n) {
		if ((cc = write(sock, bp, n)) <= 0) {
			if (cc < 0) {
641
				perror("Writing to socket");
642 643 644 645 646 647 648 649 650 651 652 653
				goto bad;
			}
			fprintf(stderr, "write aborted");
			goto bad;
		}
		bp += cc;
		n  -= cc;
	}

	while (1) {
		if ((cc = read(sock, buf, sizeof(buf) - 1)) <= 0) {
			if (cc < 0) {
654
				perror("Reading from socket");
655 656 657 658
				goto bad;
			}
			break;
		}
659
		progress += cc;
660 661 662 663 664 665
		if (dooutput(outfd, buf, cc) < 0)
			goto bad;
	}
	close(sock);
	return 0;
 bad:
Mike Hibler's avatar
Mike Hibler committed
666
	close(sock);
667 668
	return -1;
#endif
Mike Hibler's avatar
Mike Hibler committed
669
}
670 671 672 673 674 675 676 677 678 679 680 681 682 683

/*
 * Be a proxy. Basically, listen for requests from the localhost and
 * forward. At the moment this is strictly for the benefit of jailed
 * environments on FreeBSD, hence we use a unix domain socket to provide
 * the security (the socket is visible to the jail only).
 *
 * Note that only TCP traffic goes through the proxy. The jailed tmcc
 * can speak directly to tmcd over udp since it never returns anything
 * sensitive that way.
 */
static void
beproxy(char *localpath, struct in_addr serverip, char *partial)
{
684 685
#if defined(linux) || defined(_WIN32)
	fprintf(stderr, "proxy mode not supported on this platform!\n");
686 687 688 689 690 691 692
	exit(-1);
#else
	int			sock, newsock, cc, length;
	struct sockaddr_un	sunaddr, client;
	char			command[MYBUFSIZE], buf[MYBUFSIZE];
	char			*bp, *cp;
	
693 694 695
	/* don't let a client kill us */
	signal(SIGPIPE, SIG_IGN);

696 697 698 699 700 701 702 703 704 705
	sock = socket(AF_UNIX, SOCK_STREAM, 0);
	if (sock < 0) {
		perror("creating unix domain socket");
		exit(-1);
	}

	unlink(localpath);
	memset(&sunaddr, 0, sizeof(sunaddr));
	sunaddr.sun_family = AF_UNIX;
	strlcpy(sunaddr.sun_path, localpath, sizeof(sunaddr.sun_path));
706 707 708 709 710
	length = SUN_LEN(&sunaddr) + 1;
#  ifndef __CYGWIN__
	sunaddr.sun_len = length;
#  endif /* __CYGWIN__ */
	if (bind(sock, (struct sockaddr *)&sunaddr, length) < 0) {
711 712 713
		perror("binding unix domain socket");
		exit(-1);
	}
714
	chmod(localpath, S_IRWXU|S_IRWXG|S_IRWXO);
715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748
	if (listen(sock, 5) < 0) {
		perror("listen on unix domain socket");
		exit(-1);
	}

	if (logfile) {
		int	fd;

		/*
		 * Detach, but do not daemonize. The caller tracks the
		 * pid and kills us. Needs to be fixed at some point ...
		 */
		if ((fd = open("/dev/null", O_RDONLY, 0)) < 0) {
			perror("Could not open /dev/null");
			exit(-1);
		}
		(void)dup2(fd, STDIN_FILENO);
		if (fd != STDIN_FILENO)
			(void)close(fd);
		
		if ((fd = open(logfile, O_WRONLY|O_CREAT|O_APPEND,0640)) < 0) {
			perror("Could not open logfile");
			exit(-1);
		}
		(void)dup2(fd, STDOUT_FILENO);
		(void)dup2(fd, STDERR_FILENO);
		if (fd > STDERR_FILENO)
			(void)close(fd);
	}

	/*
	 * Wait for TCP connections.
	 */
	while (1) {
749 750
		int	rval;
		volatile int useudp = 0;
751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797
		
		length  = sizeof(client);
		newsock = accept(sock, (struct sockaddr *)&client, &length);
		if (newsock < 0) {
			perror("accepting Unix domain connection");
			continue;
		}

		/*
		 * Read in the command request.
		 */
		if ((cc = read(newsock, buf, sizeof(buf) - 1)) <= 0) {
			if (cc < 0)
				perror("Reading Unix domain request");
			fprintf(stderr, "Unix domain connection aborted\n");
			close(newsock);
			continue;
		}
		buf[cc] = '\0';

		/*
		 * Do not allow PRIVKEY or VNODE options to be specified
		 * by the proxy user. 
		 */
		strcpy(command, partial);
		bp = cp = buf;
		while ((bp = strsep(&cp, " ")) != NULL) {
			if (strstr(bp, "PRIVKEY=") ||
			    strstr(bp, "VNODE=")) {
				if (debug)
					fprintf(stderr,
						"Ignoring option: %s\n", bp);
				continue;
			}
			if (strstr(bp, "USEUDP=1")) {
				useudp = 1;
				continue;
			}
			strcat(command, bp);
			strcat(command, " ");
		}

		if (debug) {
			fprintf(stderr, "%s\n", command);
			fflush(stderr);
		}

798 799 800 801 802 803 804 805 806 807 808 809 810 811
		/*
		 * Set a timeout for the server-side operation
		 */
		if (waitfor) {
			if (sigsetjmp(progtimo, 1) != 0) {
				fprintf(stderr,
					"Server request timeout on: %s\n",
					command);
				close(newsock);
				continue;
			}
			signal(SIGALRM, (sig_t)tooktoolong);
			alarm(waitfor);
		}
812 813 814 815
		if (useudp)
			rval = doudp(command, newsock, serverip, portlist[0]);
		else
			rval = dotcp(command, newsock, serverip);
816 817
		if (waitfor)
			alarm(0);
818 819 820 821 822 823 824
		
		if (rval < 0 && debug) {
			fprintf(stderr, "Request failed!\n");
			fflush(stderr);
		}
		close(newsock);
	}
Mike Hibler's avatar
Mike Hibler committed
825
#endif
826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842
}

/*
 * Little helper to write tmcd response to output. 
 */
static int
dooutput(int fd, char *buf, int len)
{
	int		cc, count = len;

	if (debug) {
		write(fileno(stderr), buf, len);
	}
	
	while (count) {
		if ((cc = write(fd, buf, count)) <= 0) {
			if (cc < 0) {
843
				perror("Writing to output stream");
844 845 846 847 848 849 850 851 852 853
				return -1;
			}
			fprintf(stderr, "write to socket aborted");
			return -1;
		}
		buf   += cc;
		count -= cc;
	}
	return len;
}