tmcd.c 370 KB
Newer Older
Leigh Stoller's avatar
Leigh Stoller committed
1
/*
2
 * Copyright (c) 2000-2019 University of Utah and the Flux Group.
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
 * 
 * {{{EMULAB-LICENSE
 * 
 * This file is part of the Emulab network testbed software.
 * 
 * This file is free software: you can redistribute it and/or modify it
 * under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or (at
 * your option) any later version.
 * 
 * This file is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Affero General Public
 * License for more details.
 * 
 * You should have received a copy of the GNU Affero General Public License
 * along with this file.  If not, see <http://www.gnu.org/licenses/>.
 * 
 * }}}
Leigh Stoller's avatar
Leigh Stoller committed
22 23
 */

24 25 26
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
Mike Hibler's avatar
Mike Hibler committed
27
#include <arpa/inet.h>
28
#include <netdb.h>
Mike Hibler's avatar
Mike Hibler committed
29
#include <ctype.h>
30
#include <stdio.h>
Mike Hibler's avatar
Mike Hibler committed
31
#include <stdlib.h>
32
#include <errno.h>
Mike Hibler's avatar
Mike Hibler committed
33 34
#include <string.h>
#include <unistd.h>
35 36 37 38
#include <syslog.h>
#include <signal.h>
#include <stdarg.h>
#include <assert.h>
39
#include <sys/wait.h>
40
#include <sys/fcntl.h>
41 42
#include <sys/syscall.h>
#include <sys/stat.h>
Kirk Webb's avatar
Kirk Webb committed
43
#include <sys/param.h>
44
#include <paths.h>
Austin Clements's avatar
Austin Clements committed
45
#include <setjmp.h>
46 47
#include <pwd.h>
#include <grp.h>
48
#include <mysql/mysql.h>
49
#include "tmcd.h"
50
#include "config.h"
51 52
#include "ssl.h"
#include "log.h"
53
#include "tbdefs.h"
54
#include "bsdefs.h"
Leigh Stoller's avatar
Leigh Stoller committed
55 56
#include "bootwhat.h"
#include "bootinfo.h"
57

58 59 60 61
#ifdef EVENTSYS
#include "event.h"
#endif

62 63 64
/* XXX: Not sure this is okay! */
#include "tpm.h"

65 66 67
/*
 * XXX This needs to be localized!
 */
68 69 70
#define FSPROJDIR	FSNODE ":" FSDIR_PROJ
#define FSGROUPDIR	FSNODE ":" FSDIR_GROUPS
#define FSUSERDIR	FSNODE ":" FSDIR_USERS
71 72 73
#ifdef  FSDIR_SHARE
#define FSSHAREDIR	FSNODE ":" FSDIR_SHARE
#endif
74 75 76
#ifdef  FSDIR_SCRATCH
#define FSSCRATCHDIR	FSNODE ":" FSDIR_SCRATCH
#endif
77 78
/* XXX InstaGeni Rack Hack. Hack until I decide on a better way */
#define FSJAILIP       "172.17.253.254"
79 80 81 82 83
#define PROJDIR		PROJROOT_DIR
#define GROUPDIR	GROUPSROOT_DIR
#define USERDIR		USERSROOT_DIR
#define SCRATCHDIR	SCRATCHROOT_DIR
#define SHAREDIR	SHAREROOT_DIR
84
#define NETBEDDIR	"/netbed"
Kirk Webb's avatar
Kirk Webb committed
85
#define PLISALIVELOGDIR "/usr/testbed/log/plabisalive"
86 87
#define RELOADPID	"emulab-ops"
#define RELOADEID	"reloading"
88
#define FSHOSTID	"/usr/testbed/etc/fshostid"
89
#define DOTSFS		".sfs"
90 91
#define RUNASUSER	"nobody"
#define RUNASGROUP	"nobody"
Mike Hibler's avatar
Mike Hibler committed
92
#ifndef NTPSERVER
93
#define NTPSERVER       "ntp1"
Mike Hibler's avatar
Mike Hibler committed
94
#endif
95
#define PROTOUSER	"elabman"
96 97 98 99
#define PRIVKEY_LEN	128
#define URN_LEN		128
#define XSTRINGIFY(s)   STRINGIFY(s)
#define STRINGIFY(s)	#s
100

101 102 103 104 105
/* XXX backward compat */
#ifndef TBCOREDIR
#define	TBCOREDIR	TBROOT "/tmp"
#endif

106 107 108 109
/* socket read/write timeouts in ms */
#define READTIMO	3000
#define WRITETIMO	3000

110
#define TESTMODE
111 112 113 114 115 116 117 118 119 120 121 122
#define DEFAULTNETMASK	"255.255.255.0"
/* This can be tossed once all the changes are in place */
static char *
CHECKMASK(char *arg)
{
	if (arg && arg[0])
		return arg;

	error("No netmask defined!\n");
	return DEFAULTNETMASK;
}
/* #define CHECKMASK(arg)  ((arg) && (arg[0]) ? (arg) : DEFAULTNETMASK) */
123

124 125 126
#define DISKTYPE	"ad"
#define DISKNUM		0

127 128
/* Compiled in slothd parameters
 *
129
 * 1 - reg_interval  2 - agg_interval  3 - load_thresh
130 131 132 133
 * 4 - expt_thresh   5 - ctl_thresh
 */
#define SDPARAMS        "reg=300 agg=5 load=1 expt=5 ctl=1000"

134 135 136 137 138 139 140 141 142 143
/*
 * Compiled in tarball/rpm param.
 * Should come out of the DB.
 */
#ifdef SPEWFROMOPS
#define TARRPM_SERVER	USERNODE
#else
#define TARRPM_SERVER	BOSSNODE
#endif

144 145 146 147 148 149
#ifdef IMAGEPROVENANCE
#define WITHPROVENANCE	1
#else
#define WITHPROVENANCE	0
#endif

150 151 152 153 154 155 156
#ifdef WITHZFS
#undef WITHZFS
#define WITHZFS	1
#else
#define WITHZFS	0
#endif

157 158
/* Defined in configure and passed in via the makefile */
#define DBNAME_SIZE	64
Austin Clements's avatar
Austin Clements committed
159
#define HOSTID_SIZE	(32+64)
160 161
#define DEFAULT_DBNAME	TBDBNAME

Robert P Ricci's avatar
Robert P Ricci committed
162 163 164 165
/* For secure disk loading */
#define SECURELOAD_OPMODE "SECURELOAD"
#define SECURELOAD_STATE  "RELOADSETUP"

166 167 168
/* Our answer to "geni-get --version" */
#define GENI_VERSION "1"

169 170 171 172 173 174 175 176
/* Taint support */
#define TB_TAINTSTATE_BLACKBOX  1
#define TB_TAINTSTATE_USERONLY  2
#define TB_TAINTSTATE_DANGEROUS 4
#define HAS_ANY_TAINTS(tset, tcheck) (tset & tcheck)
#define HAS_ALL_TAINTS(tset, tcheck) ((tset & tcheck) == tcheck)
#define HAS_TAINT(tset, tcheck) HAS_ALL_TAINTS(tset, tcheck)

177 178 179 180 181 182
/* Per-experiment root keypair support */
#define TB_ROOTKEYS_NONE	0
#define TB_ROOTKEYS_PRIVATE	1
#define TB_ROOTKEYS_PUBLIC	2
#define TB_ROOTKEYS_BOTH	3

183 184 185 186 187
typedef struct {
	char pid[TBDB_FLEN_PID];
	char gid[TBDB_FLEN_GID];
	char name[TBDB_FLEN_IMAGENAME];
	char version[11]; /* Max size of a 32-bit int in string form. */
188
	char *path; /* A dynamically-allocated path string, if relevant. */
189 190
} imstrings_t;

191
int		debug = 0;
192
static int	verbose = 0;
193
static int	insecure = 0;
194
static int	byteswritten = 0;
Leigh Stoller's avatar
Leigh Stoller committed
195
static char	pidfile[MAXPATHLEN];
196
static char     dbname[DBNAME_SIZE];
197
static struct in_addr myipaddr;
198
static struct in_addr cnet, cmask, jnet, jmask;
Austin Clements's avatar
Austin Clements committed
199
static char	fshostid[HOSTID_SIZE];
Leigh Stoller's avatar
Leigh Stoller committed
200
static int	nodeidtoexp(char *nodeid, char *pid, char *eid, char *gid);
201 202
static void	tcpserver(int sock, int portnum);
static void	udpserver(int sock, int portnum);
203
static int      handle_request(int, struct sockaddr_in *, char *, int, int);
204
static int      checkcerts(char*);
205
static int	makesockets(int portnum, int *udpsockp, int *tcpsockp);
Mike Hibler's avatar
Mike Hibler committed
206 207
int		client_writeback(int sock, void *buf, int len, int tcp);
void		client_writeback_done(int sock, struct sockaddr_in *client);
208 209
MYSQL_RES *	mydb_query(char *query, int ncols, ...);
int		mydb_update(char *query, ...);
210
static int	safesymlink(char *name1, char *name2);
211
static int      getImageInfo(char *path, char *nodeid, char *pid, char *imagename,
212
			     unsigned int *mtime, off_t *isize);
213
static int	getrandomchars(char *buf, int len);
214

215 216 217 218
/* socket timeouts */
static int	readtimo = READTIMO;
static int	writetimo = WRITETIMO;

219
/* thread support */
220
#define MAXCHILDREN	20
221
#define MINCHILDREN	8
222
static int	numchildren;
223 224 225 226
static int	maxchildren       = 13;
static int      num_udpservers    = 3;
static int      num_altudpservers = 1;
static int      num_alttcpservers = 1;
227
static int	mypid;
228
static volatile int killme;
229

230 231 232 233 234
/* Output macro to check for string overflow */
#define OUTPUT(buf, size, format...) \
({ \
	int __count__ = snprintf((buf), (size), ##format); \
        \
235
        if (__count__ >= (size)) { \
236 237 238 239 240 241
		error("Not enough room in output buffer! line %d.\n", __LINE__);\
		return 1; \
	} \
	__count__; \
})

242 243 244 245 246
/*
 * This structure is passed to each request function. The intent is to
 * reduce the number of DB queries per request to a minimum.
 */
typedef struct {
Leigh Stoller's avatar
Leigh Stoller committed
247
	struct in_addr  client;
248 249 250
	int		allocated;
	int		jailflag;
	int		isvnode;
251
	int		isroutable_vnode; /* only valid if isvnode==1 */
252
	int		asvnode;
253
	int		issubnode;
254
	int		islocal;
255
	int		isdedicatedwa;
256
	int		iscontrol;
257
	int		isplabdslice;
258
	int		isplabsvc;
259
	int		elab_in_elab;
260
        int		singlenet;	  /* Modifier for elab_in_elab */
261
	int		update_accounts;
262
	int		exptidx;
263 264 265
	int		creator_idx;
	int		swapper_idx;
	int		swapper_isadmin;
266
        int		genisliver_idx;
267
        int		geniflags;
268
	int		isnonlocal_pid;
269
	int		usejumboframes;
270 271
	unsigned short  taintstates;
	unsigned short  experiment_keys;
272
	char            nfsmounts[TBDB_FLEN_TINYTEXT];
273 274
	char		nodeid[TBDB_FLEN_NODEID];
	char		vnodeid[TBDB_FLEN_NODEID];
Leigh Stoller's avatar
Leigh Stoller committed
275
	char		pnodeid[TBDB_FLEN_NODEID]; /* XXX */
276 277 278 279 280
	char		pid[TBDB_FLEN_PID];
	char		eid[TBDB_FLEN_EID];
	char		gid[TBDB_FLEN_GID];
	char		nickname[TBDB_FLEN_VNAME];
	char		type[TBDB_FLEN_NODETYPE];
281
	char		class[TBDB_FLEN_NODECLASS];
282 283
        char		ptype[TBDB_FLEN_NODETYPE];	/* Of physnode */
	char		pclass[TBDB_FLEN_NODECLASS];	/* Of physnode */
284 285
	char		creator[TBDB_FLEN_UID];
	char		swapper[TBDB_FLEN_UID];
286
	char		syncserver[TBDB_FLEN_VNAME];	/* The vname */
287
	char		keyhash[TBDB_FLEN_PRIVKEY];
288
	char		eventkey[TBDB_FLEN_PRIVKEY];
289
	char		sfshostid[TBDB_FLEN_SFSHOSTID];
290
	char		testdb[TBDB_FLEN_TINYTEXT];
291
	char		sharing_mode[TBDB_FLEN_TINYTEXT];
292
	char		erole[TBDB_FLEN_TINYTEXT];
293
	char            privkey[PRIVKEY_LEN+1];
294
	char		nodeuuid[TBDB_FLEN_UUID];
295 296
        /* This key is a replacement for privkey, on protogeni resources */
	char            external_key[PRIVKEY_LEN+1];
297
} tmcdreq_t;
298
static int	iptonodeid(struct in_addr, tmcdreq_t *, char*);
299
static int	checkdbredirect(tmcdreq_t *);
300
static int      sendstoreconf(int sock, int tcp, tmcdreq_t *reqp, char *bscmd, 
301
			      char *vname, int dopersist, char *localproto);
302
static int      get_imagestrings(tmcdreq_t *reqp, imstrings_t *imstrings);
303
static void     free_imagestrings_content(imstrings_t *imstrings);
304

305 306 307 308 309
#ifdef EVENTSYS
int			myevent_send(address_tuple_t address);
static event_handle_t	event_handle = NULL;
#endif

310 311 312
/*
 * Commands we support.
 */
313 314
#define COMMAND_PROTOTYPE(x) \
	static int \
315
	x(int sock, tmcdreq_t *reqp, char *rdata, int tcp, int vers)
316 317

COMMAND_PROTOTYPE(doreboot);
318
COMMAND_PROTOTYPE(donodeid);
319
COMMAND_PROTOTYPE(donodetype);
320
COMMAND_PROTOTYPE(donodeuuid);
David Johnson's avatar
David Johnson committed
321
COMMAND_PROTOTYPE(domanifest);
322 323 324
COMMAND_PROTOTYPE(dostatus);
COMMAND_PROTOTYPE(doifconfig);
COMMAND_PROTOTYPE(doaccounts);
325
COMMAND_PROTOTYPE(dobridges);
326
COMMAND_PROTOTYPE(dodelay);
327
COMMAND_PROTOTYPE(dolinkdelay);
328 329 330 331
COMMAND_PROTOTYPE(dohosts);
COMMAND_PROTOTYPE(dorpms);
COMMAND_PROTOTYPE(dodeltas);
COMMAND_PROTOTYPE(dotarballs);
332
COMMAND_PROTOTYPE(doblobs);
333 334 335 336
COMMAND_PROTOTYPE(dostartcmd);
COMMAND_PROTOTYPE(dostartstat);
COMMAND_PROTOTYPE(doready);
COMMAND_PROTOTYPE(doreadycount);
337
COMMAND_PROTOTYPE(dostorageconfig);
338
COMMAND_PROTOTYPE(domounts);
Austin Clements's avatar
Austin Clements committed
339
COMMAND_PROTOTYPE(dosfshostid);
340 341 342 343 344 345 346
COMMAND_PROTOTYPE(doloadinfo);
COMMAND_PROTOTYPE(doreset);
COMMAND_PROTOTYPE(dorouting);
COMMAND_PROTOTYPE(dotrafgens);
COMMAND_PROTOTYPE(donseconfigs);
COMMAND_PROTOTYPE(dostate);
COMMAND_PROTOTYPE(docreator);
347
COMMAND_PROTOTYPE(dotunnels);
348
COMMAND_PROTOTYPE(dovnodelist);
349
COMMAND_PROTOTYPE(dosubnodelist);
350
COMMAND_PROTOTYPE(doisalive);
351
COMMAND_PROTOTYPE(doipodinfo);
352 353
COMMAND_PROTOTYPE(dontpinfo);
COMMAND_PROTOTYPE(dontpdrift);
354
COMMAND_PROTOTYPE(dojailconfig);
355
COMMAND_PROTOTYPE(doplabconfig);
356 357
COMMAND_PROTOTYPE(dosubconfig);
COMMAND_PROTOTYPE(doixpconfig);
358
COMMAND_PROTOTYPE(doslothdparams);
359
COMMAND_PROTOTYPE(doprogagents);
360
COMMAND_PROTOTYPE(dosyncserver);
361
COMMAND_PROTOTYPE(dokeyhash);
362
COMMAND_PROTOTYPE(doeventkey);
363
COMMAND_PROTOTYPE(dofullconfig);
364 365
COMMAND_PROTOTYPE(doroutelist);
COMMAND_PROTOTYPE(dorole);
366
COMMAND_PROTOTYPE(dorusage);
367
COMMAND_PROTOTYPE(dodoginfo);
368
COMMAND_PROTOTYPE(dohostkeys);
Mike Hibler's avatar
Mike Hibler committed
369
COMMAND_PROTOTYPE(dotmcctest);
370
COMMAND_PROTOTYPE(dofwinfo);
371
COMMAND_PROTOTYPE(dohostinfo);
372
COMMAND_PROTOTYPE(doemulabconfig);
373
COMMAND_PROTOTYPE(doeplabconfig);
374
COMMAND_PROTOTYPE(dolocalize);
375
COMMAND_PROTOTYPE(dorootpswd);
376 377
COMMAND_PROTOTYPE(dobooterrno);
COMMAND_PROTOTYPE(dobootlog);
Timothy Stack's avatar
Timothy Stack committed
378
COMMAND_PROTOTYPE(dobattery);
379
COMMAND_PROTOTYPE(dotopomap);
Timothy Stack's avatar
Timothy Stack committed
380
COMMAND_PROTOTYPE(douserenv);
Timothy Stack's avatar
Timothy Stack committed
381 382
COMMAND_PROTOTYPE(dotiptunnels);
COMMAND_PROTOTYPE(dorelayconfig);
383
COMMAND_PROTOTYPE(dotraceconfig);
384
COMMAND_PROTOTYPE(doltmap);
385
COMMAND_PROTOTYPE(doltpmap);
Kirk Webb's avatar
Kirk Webb committed
386
COMMAND_PROTOTYPE(doelvindport);
Kirk Webb's avatar
Kirk Webb committed
387
COMMAND_PROTOTYPE(doplabeventkeys);
388
COMMAND_PROTOTYPE(dointfcmap);
389
COMMAND_PROTOTYPE(domotelog);
390
COMMAND_PROTOTYPE(doportregister);
Leigh Stoller's avatar
Leigh Stoller committed
391
COMMAND_PROTOTYPE(dobootwhat);
392 393
COMMAND_PROTOTYPE(dotpmblob);
COMMAND_PROTOTYPE(dotpmpubkey);
394
COMMAND_PROTOTYPE(dotpmdummy);
395
COMMAND_PROTOTYPE(dodhcpdconf);
396
COMMAND_PROTOTYPE(dosecurestate);
397
COMMAND_PROTOTYPE(doquoteprep);
398
COMMAND_PROTOTYPE(doimagekey);
399
COMMAND_PROTOTYPE(donodeattributes);
400
COMMAND_PROTOTYPE(dodisks);
401
COMMAND_PROTOTYPE(doarpinfo);
402
COMMAND_PROTOTYPE(dohwinfo);
403
COMMAND_PROTOTYPE(dotiplineinfo);
404
COMMAND_PROTOTYPE(doimageid);
405
COMMAND_PROTOTYPE(doimagesize);
406
COMMAND_PROTOTYPE(dopnetnodeattrs);
407
COMMAND_PROTOTYPE(doserviceinfo);
Mike Hibler's avatar
Mike Hibler committed
408
COMMAND_PROTOTYPE(dosubbossinfo);
409
COMMAND_PROTOTYPE(dopublicaddrinfo);
410 411 412 413 414 415 416 417
#if PROTOGENI_SUPPORT
COMMAND_PROTOTYPE(dogeniclientid);
COMMAND_PROTOTYPE(dogenisliceurn);
COMMAND_PROTOTYPE(dogenisliceemail);
COMMAND_PROTOTYPE(dogeniuserurn);
COMMAND_PROTOTYPE(dogeniuseremail);
COMMAND_PROTOTYPE(dogenigeniuser);
COMMAND_PROTOTYPE(dogenimanifest);
418 419
COMMAND_PROTOTYPE(dogenicert);
COMMAND_PROTOTYPE(dogenikey);
420 421 422 423
COMMAND_PROTOTYPE(dogenicontrolmac);
COMMAND_PROTOTYPE(dogeniversion);
COMMAND_PROTOTYPE(dogenigetversion);
COMMAND_PROTOTYPE(dogenisliverstatus);
424 425
COMMAND_PROTOTYPE(dogenistatus);
COMMAND_PROTOTYPE(dogenicommands);
426
COMMAND_PROTOTYPE(dogeniall);
427
COMMAND_PROTOTYPE(dogeniparam);
428
COMMAND_PROTOTYPE(dogenirpccert);
429
COMMAND_PROTOTYPE(dogeniinvalid);
430
#endif
431

432 433
/*
 * The fullconfig slot determines what routines get called when pushing
434
 * out a full configuration. Physnodes get slightly different
435
 * than vnodes, and at some point we might want to distinguish different
436 437 438 439 440
 * types of vnodes (jailed, plab).
 */
#define FULLCONFIG_NONE		0x0
#define FULLCONFIG_PHYS		0x1
#define FULLCONFIG_VIRT		0x2
441 442 443 444 445
#define FULLCONFIG_ALL		(FULLCONFIG_PHYS|FULLCONFIG_VIRT)

/*
 * Flags encode a few other random properties of commands
 */
446 447 448 449 450
#define F_REMUDP	0x01	/* remote nodes can request using UDP */
#define F_MINLOG	0x02	/* record minimal logging info normally */
#define F_MAXLOG	0x04	/* record maximal logging info normally */
#define F_ALLOCATED	0x08	/* node must be allocated to make call */
#define F_REMNOSSL	0x10	/* remote nodes can request without SSL */
451
#define F_REMREQSSL	0x20	/* remote nodes must connect with SSL */
452
#define F_REQTPM	0x40	/* require TPM on client */
453

454 455
struct command {
	char	*cmdname;
456
	int	fullconfig;
457
	int	flags;
458
	int    (*func)(int, tmcdreq_t *, char *, int, int);
459
} command_array[] = {
460 461
	{ "reboot",	  FULLCONFIG_NONE, 0, doreboot },
	{ "nodeid",	  FULLCONFIG_ALL,  0, donodeid },
462
	{ "nodetype",	  FULLCONFIG_ALL,  0, donodetype },
463
	{ "nodeuuid",	  FULLCONFIG_ALL,  0, donodeuuid },
David Johnson's avatar
David Johnson committed
464
	{ "manifest",	  FULLCONFIG_ALL,  0, domanifest },
465
	{ "status",	  FULLCONFIG_NONE, 0, dostatus },
466
	{ "ifconfig",	  FULLCONFIG_ALL,  F_ALLOCATED, doifconfig },
467
	{ "accounts",	  FULLCONFIG_ALL,  F_REMREQSSL, doaccounts },
468
	{ "delay",	  FULLCONFIG_ALL,  F_ALLOCATED, dodelay },
469
	{ "bridges",	  FULLCONFIG_ALL,  F_ALLOCATED, dobridges },
470 471 472 473 474
	{ "linkdelay",	  FULLCONFIG_ALL,  F_ALLOCATED, dolinkdelay },
	{ "hostnames",	  FULLCONFIG_NONE, F_ALLOCATED, dohosts },
	{ "rpms",	  FULLCONFIG_ALL,  F_ALLOCATED, dorpms },
	{ "deltas",	  FULLCONFIG_NONE, F_ALLOCATED, dodeltas },
	{ "tarballs",	  FULLCONFIG_ALL,  F_ALLOCATED, dotarballs },
475
	{ "blobs",	  FULLCONFIG_ALL,  F_ALLOCATED, doblobs },
476 477
	{ "startupcmd",	  FULLCONFIG_ALL,  F_ALLOCATED, dostartcmd },
	{ "startstatus",  FULLCONFIG_NONE, F_ALLOCATED, dostartstat }, /* Before startstat*/
478
	{ "startstat",	  FULLCONFIG_NONE, 0, dostartstat },
479 480
	{ "readycount",   FULLCONFIG_NONE, F_ALLOCATED, doreadycount },
	{ "ready",	  FULLCONFIG_NONE, F_ALLOCATED, doready },
481
	{ "storageconfig", FULLCONFIG_ALL, F_ALLOCATED, dostorageconfig},
482 483
	{ "mounts",	  FULLCONFIG_ALL,  F_ALLOCATED, domounts },
	{ "sfshostid",	  FULLCONFIG_NONE, F_ALLOCATED, dosfshostid },
484 485
	{ "loadinfo",	  FULLCONFIG_NONE, 0, doloadinfo},
	{ "reset",	  FULLCONFIG_NONE, 0, doreset},
486 487 488 489
	{ "routing",	  FULLCONFIG_ALL,  F_ALLOCATED, dorouting},
	{ "trafgens",	  FULLCONFIG_ALL,  F_ALLOCATED, dotrafgens},
	{ "nseconfigs",	  FULLCONFIG_ALL,  F_ALLOCATED, donseconfigs},
	{ "creator",	  FULLCONFIG_ALL,  F_ALLOCATED, docreator},
490
	{ "state",	  FULLCONFIG_NONE, 0, dostate},
491
	{ "tunnels",	  FULLCONFIG_ALL,  F_ALLOCATED, dotunnels},
492
	{ "vnodelist",	  FULLCONFIG_PHYS, 0, dovnodelist},
Timothy Stack's avatar
Timothy Stack committed
493
	{ "subnodelist",  FULLCONFIG_PHYS, 0, dosubnodelist},
494
	{ "isalive",	  FULLCONFIG_NONE, F_REMUDP|F_MINLOG, doisalive},
495
	{ "ipodinfo",	  FULLCONFIG_PHYS, 0, doipodinfo},
496 497
	{ "ntpinfo",	  FULLCONFIG_PHYS, 0, dontpinfo},
	{ "ntpdrift",	  FULLCONFIG_NONE, 0, dontpdrift},
498 499
	{ "jailconfig",	  FULLCONFIG_VIRT, F_ALLOCATED, dojailconfig},
	{ "plabconfig",	  FULLCONFIG_VIRT, F_ALLOCATED, doplabconfig},
Timothy Stack's avatar
Timothy Stack committed
500
	{ "subconfig",	  FULLCONFIG_NONE, 0, dosubconfig},
501
        { "sdparams",     FULLCONFIG_PHYS, 0, doslothdparams},
502 503
        { "programs",     FULLCONFIG_ALL,  F_ALLOCATED, doprogagents},
        { "syncserver",   FULLCONFIG_ALL,  F_ALLOCATED, dosyncserver},
504
        { "keyhash",      FULLCONFIG_ALL,  F_ALLOCATED|F_REMREQSSL, dokeyhash},
505
        { "eventkey",     FULLCONFIG_ALL,  F_ALLOCATED|F_REMREQSSL, doeventkey},
506 507 508
        { "fullconfig",   FULLCONFIG_NONE, F_ALLOCATED, dofullconfig},
        { "routelist",	  FULLCONFIG_PHYS, F_ALLOCATED, doroutelist},
        { "role",	  FULLCONFIG_PHYS, F_ALLOCATED, dorole},
509
        { "rusage",	  FULLCONFIG_NONE, F_REMUDP|F_MINLOG, dorusage},
510
        { "watchdoginfo", FULLCONFIG_ALL,  F_REMUDP|F_MINLOG, dodoginfo},
511
        { "hostkeys",     FULLCONFIG_NONE, 0, dohostkeys},
Mike Hibler's avatar
Mike Hibler committed
512
        { "tmcctest",     FULLCONFIG_NONE, F_MINLOG, dotmcctest},
513
        { "firewallinfo", FULLCONFIG_ALL,  0, dofwinfo},
514
        { "hostinfo",     FULLCONFIG_NONE, 0, dohostinfo},
515
	{ "emulabconfig", FULLCONFIG_NONE, F_ALLOCATED, doemulabconfig},
516
	{ "eplabconfig",  FULLCONFIG_NONE, F_ALLOCATED, doeplabconfig},
517
	{ "localization", FULLCONFIG_PHYS, 0, dolocalize},
518
	{ "rootpswd",     FULLCONFIG_NONE, F_REMREQSSL, dorootpswd},
519 520
	{ "booterrno",    FULLCONFIG_NONE, 0, dobooterrno},
	{ "bootlog",      FULLCONFIG_NONE, 0, dobootlog},
Timothy Stack's avatar
Timothy Stack committed
521
	{ "battery",      FULLCONFIG_NONE, F_REMUDP|F_MINLOG, dobattery},
522
	{ "topomap",      FULLCONFIG_NONE, F_MINLOG|F_ALLOCATED, dotopomap},
523
	{ "userenv",      FULLCONFIG_ALL,  F_ALLOCATED, douserenv},
Timothy Stack's avatar
Timothy Stack committed
524
	{ "tiptunnels",	  FULLCONFIG_ALL,  F_ALLOCATED, dotiptunnels},
525
	{ "traceinfo",	  FULLCONFIG_ALL,  F_ALLOCATED, dotraceconfig },
Kirk Webb's avatar
Kirk Webb committed
526
	{ "ltmap",        FULLCONFIG_NONE, F_MINLOG|F_ALLOCATED, doltmap},
527
	{ "ltpmap",       FULLCONFIG_NONE, F_MINLOG|F_ALLOCATED, doltpmap},
Kirk Webb's avatar
Kirk Webb committed
528
	{ "elvindport",   FULLCONFIG_NONE, 0, doelvindport},
529
	{ "plabeventkeys",FULLCONFIG_NONE, F_REMREQSSL, doplabeventkeys},
530
	{ "intfcmap",     FULLCONFIG_NONE, 0, dointfcmap},
531 532
	{ "motelog",      FULLCONFIG_ALL,  F_ALLOCATED, domotelog},
	{ "portregister", FULLCONFIG_NONE, F_REMNOSSL, doportregister},
Leigh Stoller's avatar
Leigh Stoller committed
533
	{ "bootwhat",	  FULLCONFIG_NONE, 0, dobootwhat },
534 535
	{ "tpmblob",	  FULLCONFIG_ALL, 0, dotpmblob },
	{ "tpmpubkey",	  FULLCONFIG_ALL, 0, dotpmpubkey },
536
	{ "tpmdummy",	  FULLCONFIG_ALL, F_REQTPM, dotpmdummy },
537
	{ "dhcpdconf",	  FULLCONFIG_ALL, 0, dodhcpdconf },
538 539
	{ "securestate",  FULLCONFIG_NONE, F_REMREQSSL, dosecurestate},
	{ "quoteprep",    FULLCONFIG_NONE, F_REMREQSSL, doquoteprep},
540
	{ "imagekey",     FULLCONFIG_NONE, F_REQTPM, doimagekey},
541
	{ "nodeattributes", FULLCONFIG_ALL, 0, donodeattributes},
542
	{ "disks",	  FULLCONFIG_ALL, 0, dodisks},
543
	{ "arpinfo",	  FULLCONFIG_NONE, 0, doarpinfo},
544
	{ "hwinfo",	  FULLCONFIG_NONE, 0, dohwinfo},
545
	{ "tiplineinfo",  FULLCONFIG_NONE,  F_ALLOCATED, dotiplineinfo},
546
	{ "imageinfo",      FULLCONFIG_NONE,  F_ALLOCATED, doimageid},
547
	{ "imagesize",   FULLCONFIG_NONE,  F_ALLOCATED, doimagesize},
Kirk Webb's avatar
Kirk Webb committed
548
	{ "pnetnodeattrs", FULLCONFIG_NONE, F_ALLOCATED, dopnetnodeattrs},
Mike Hibler's avatar
Mike Hibler committed
549 550
	{ "serviceinfo",  FULLCONFIG_NONE, 0, doserviceinfo },
	{ "subbossinfo",  FULLCONFIG_NONE, 0, dosubbossinfo },
551
	{ "publicaddrinfo",  FULLCONFIG_NONE, F_ALLOCATED, dopublicaddrinfo },
552 553 554 555 556 557 558 559 560
#if PROTOGENI_SUPPORT
	{ "geni_client_id", FULLCONFIG_NONE, 0, dogeniclientid },
	{ "geni_slice_urn", FULLCONFIG_NONE, 0, dogenisliceurn },
	{ "geni_slice_email", FULLCONFIG_NONE, 0, dogenisliceemail },
	{ "geni_user_urn", FULLCONFIG_NONE, 0, dogeniuserurn },
	{ "geni_user_email", FULLCONFIG_NONE, 0, dogeniuseremail },
	/* Yes, "geni_user" is a stupid name.  Wasn't my idea. */
	{ "geni_geni_user", FULLCONFIG_NONE, 0, dogenigeniuser },
	{ "geni_manifest", FULLCONFIG_NONE, 0, dogenimanifest },
561 562
	{ "geni_certificate", FULLCONFIG_NONE, 0, dogenicert },
	{ "geni_key", FULLCONFIG_NONE, 0, dogenikey },
563 564 565 566
	{ "geni_control_mac", FULLCONFIG_NONE, 0, dogenicontrolmac },
	{ "geni_version", FULLCONFIG_NONE, 0, dogeniversion },
	{ "geni_getversion", FULLCONFIG_NONE, 0, dogenigetversion },
	{ "geni_sliverstatus", FULLCONFIG_NONE, 0, dogenisliverstatus },
567 568
	{ "geni_status", FULLCONFIG_NONE, 0, dogenistatus },
	{ "geni_commands", FULLCONFIG_NONE, 0, dogenicommands },
569
	{ "geni_all",     FULLCONFIG_NONE, 0, dogeniall },
570
	{ "geni_param",   FULLCONFIG_NONE, 0, dogeniparam },
571
	{ "geni_rpccert",   FULLCONFIG_NONE, 0, dogenirpccert },
572 573 574
	/* A rather ugly hack to avoid making error handling a special case.
	   THIS MUST BE THE LAST ENTRY IN THE ARRAY! */
	{ "geni_invalid", FULLCONFIG_NONE, 0, dogeniinvalid }
575
#endif
576 577 578
};
static int numcommands = sizeof(command_array)/sizeof(struct command);

579
char *usagestr =
580 581 582
 "usage: tmcd [-d] [-p #]\n"
 " -d              Turn on debugging. Multiple -d options increase output\n"
 " -p portnum	   Specify a port number to listen on\n"
583
 " -c num	   Specify number of servers (must be %d <= x <= %d)\n"
584
 " -v              More verbose logging\n"
585
 " -i ipaddr       Sets the boss IP addr to return (for multi-homed servers)\n"
586 587 588 589 590
 "\n";

void
usage()
{
591
	fprintf(stderr, usagestr, MINCHILDREN, MAXCHILDREN);
592 593 594
	exit(1);
}

595 596 597 598 599
static void
cleanup()
{
	signal(SIGHUP, SIG_IGN);
	killme = 1;
600
	killpg(0, SIGHUP);
Leigh Stoller's avatar
Leigh Stoller committed
601
	unlink(pidfile);
602 603
}

604 605 606 607
static void
setverbose(int sig)
{
	signal(sig, SIG_IGN);
608

609 610 611 612
	if (sig == SIGUSR1)
		verbose = 1;
	else
		verbose = 0;
613 614
	info("verbose logging turned %s\n", verbose ? "on" : "off");

615 616 617 618 619 620
	/* Just the parent sends this */
	if (numchildren)
		killpg(0, sig);
	signal(sig, setverbose);
}

Mike Hibler's avatar
Mike Hibler committed
621 622
int
main(int argc, char **argv)
623
{
624
	int			tcpsock, udpsock, i, ch;
625 626 627
	int			alttcpsock, altudpsock;
	int			status, pid;
	int			portnum = TBSERVER_PORT;
628 629
	FILE			*fp;
	char			buf[BUFSIZ];
630
	struct hostent		*he;
631
	extern char		build_info[];
632 633 634 635 636
	int			server_counts[4]; /* udp,tcp,altudp,alttcp */
	struct {
		int	pid;
		int	which;
	} servers[MAXCHILDREN];
637

638
	while ((ch = getopt(argc, argv, "dp:c:Xvi:")) != -1)
639 640 641 642 643 644
		switch(ch) {
		case 'p':
			portnum = atoi(optarg);
			break;
		case 'd':
			debug++;
645
			break;
646 647 648
		case 'c':
			maxchildren = atoi(optarg);
			break;
649 650 651
		case 'X':
			insecure = 1;
			break;
652 653 654
		case 'v':
			verbose++;
			break;
655 656 657 658 659 660 661
		case 'i':
			if (inet_aton(optarg, &myipaddr) == 0) {
				fprintf(stderr, "invalid IP address %s\n",
					optarg);
				usage();
			}
			break;
662 663 664 665 666 667 668 669 670 671
		case 'h':
		case '?':
		default:
			usage();
		}
	argc -= optind;
	argv += optind;

	if (argc)
		usage();
672 673
	if (maxchildren < MINCHILDREN || maxchildren > MAXCHILDREN)
		usage();
674

675 676 677 678 679 680
#ifdef  WITHSSL
	if (tmcd_server_sslinit()) {
		error("SSL init failed!\n");
		exit(1);
	}
#endif
681
	if (debug)
682 683 684
		loginit(0, 0);
	else {
		/* Become a daemon */
685 686 687 688 689
		if (chdir(TBCOREDIR)) {
			daemon(0, 0);
		} else {
			daemon(1, 0);
		}
690 691 692 693
		loginit(1, "tmcd");
	}
	info("daemon starting (version %d)\n", CURRENT_VERSION);
	info("%s\n", build_info);
Mike Hibler's avatar
Mike Hibler committed
694

Austin Clements's avatar
Austin Clements committed
695 696 697 698 699 700 701 702 703 704 705 706 707 708
	/*
	 * Get FS's SFS hostid
	 * XXX This approach is somewhat kludgy
	 */
	strcpy(fshostid, "");
	if (access(FSHOSTID,R_OK) == 0) {
		fp = fopen(FSHOSTID, "r");
		if (!fp) {
			error("Failed to get FS's hostid");
		}
		else {
			fgets(fshostid, HOSTID_SIZE, fp);
			if (rindex(fshostid, '\n')) {
				*rindex(fshostid, '\n') = 0;
709 710 711
				if (debug) {
				    info("fshostid: %s\n", fshostid);
				}
Austin Clements's avatar
Austin Clements committed
712 713 714 715 716 717 718 719
			}
			else {
				error("fshostid from %s may be corrupt: %s",
				      FSHOSTID, fshostid);
			}
			fclose(fp);
		}
	}
720

721 722 723
	/*
	 * Grab our IP for security check below.
	 */
724
	if (myipaddr.s_addr == 0) {
725
#ifdef	LBS
726
		strcpy(buf, BOSSNODE);
727
#else
728 729
		if (gethostname(buf, sizeof(buf)) < 0)
			pfatal("getting hostname");
730
#endif
731 732 733 734 735 736
		if ((he = gethostbyname(buf)) == NULL) {
			error("Could not get IP (%s) - %s\n",
			      buf, hstrerror(h_errno));
			exit(1);
		}
		memcpy((char *)&myipaddr, he->h_addr, he->h_length);
737 738
	}

739
	/*
740
	 * If we were given a port on the command line, don't open the
741 742 743 744
	 * alternate ports
	 */
	if (portnum != TBSERVER_PORT) {
	    if (makesockets(portnum, &udpsock, &tcpsock) < 0) {
745 746
		error("Could not make sockets!");
		exit(1);
747
	    }
748
	    num_alttcpservers = num_altudpservers = 0;
749 750 751 752 753 754
	} else {
	    if (makesockets(portnum, &udpsock, &tcpsock) < 0 ||
		makesockets(TBSERVER_PORT2, &altudpsock, &alttcpsock) < 0) {
		    error("Could not make sockets!");
		    exit(1);
	    }
755 756
	}

757 758 759 760 761 762 763 764 765 766 767 768 769
	/*
	 * Get control net info into a usable form.
	 */
	if (!inet_aton(CONTROL_NETWORK, &cnet) ||
	    !inet_aton(CONTROL_NETMASK, &cmask) ||
	    !inet_aton(JAILIPBASE, &jnet) ||
	    !inet_aton(JAILIPMASK, &jmask)) {
		error("Could not convert control net addrs/masks");
		exit(1);
	}
	cnet.s_addr &= cmask.s_addr;
	jnet.s_addr &= jmask.s_addr;

770 771 772
	signal(SIGTERM, cleanup);
	signal(SIGINT, cleanup);
	signal(SIGHUP, cleanup);
773 774
	signal(SIGUSR1, setverbose);
	signal(SIGUSR2, setverbose);
775 776 777 778

	/*
	 * Stash the pid away.
	 */
779
	mypid = getpid();
Leigh Stoller's avatar
Leigh Stoller committed
780 781
	sprintf(pidfile, "%s/tmcd.pid", _PATH_VARRUN);
	fp = fopen(pidfile, "w");
782
	if (fp != NULL) {
783
		fprintf(fp, "%d\n", mypid);
784 785 786
		(void) fclose(fp);
	}

787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819
	/*
	 * Change to non-root user!
	 */
	if (geteuid() == 0) {
		struct passwd	*pw;
		uid_t		uid;
		gid_t		gid;

		/*
		 * Must be a valid user of course.
		 */
		if ((pw = getpwnam(RUNASUSER)) == NULL) {
			error("invalid user: %s", RUNASUSER);
			exit(1);
		}
		uid = pw->pw_uid;
		gid = pw->pw_gid;

		if (setgroups(1, &gid)) {
			errorc("setgroups");
			exit(1);
		}
		if (setgid(gid)) {
			errorc("setgid");
			exit(1);
		}
		if (setuid(uid)) {
			errorc("setuid");
			exit(1);
		}
		info("Flipped to user/group %d/%d\n", uid, gid);
	}

820 821
	/*
	 * Now fork a set of children to handle requests. We keep the
822 823 824 825 826 827 828
	 * pool at a set level. There are 4 types of servers, each getting
	 * a different number of servers. We do it this cause otherwise
	 * we have to deal with the select storm problem; a bunch of processes
	 * select on the same set of file descriptors, and all get woken up
	 * when something comes in, then all read from the socket but only
	 * one gets it and the others go back to sleep. There are various ways
	 * to deal with this problem, but all of them are a lot more code!
829
	 */
830 831 832 833 834 835
	server_counts[0] = num_udpservers;
	server_counts[1] = num_altudpservers;
	server_counts[2] = num_alttcpservers;
	server_counts[3] = maxchildren -
		(num_udpservers + num_altudpservers + num_altudpservers);
	bzero(servers, sizeof(servers));
836

837 838
	while (1) {
		while (!killme && numchildren < maxchildren) {
839
			int which = 3;
840

841 842 843 844 845 846 847 848
			/*
			 * Find which kind of server is short one.
			 */
			for (i = 0; i < 4; i++) {
				if (server_counts[i]) {
					which = i;
					break;
				}
849
			}
850

851 852 853 854 855
			if ((pid = fork()) < 0) {
				errorc("forking server");
				goto done;
			}
			if (pid) {
856 857 858 859 860 861 862 863 864 865
				server_counts[which]--;
				/*
				 * Find free slot
				 */
				for (i = 0; i < maxchildren; i++) {
					if (!servers[i].pid)
						break;
				}
				servers[i].pid   = pid;
				servers[i].which = which;
866 867 868
				numchildren++;
				continue;
			}
869 870 871
			/* Poor way of knowing parent/child */
			numchildren = 0;
			mypid = getpid();
872

873 874 875 876
			/* Child does useful work! Never Returns! */
			signal(SIGTERM, SIG_DFL);
			signal(SIGINT, SIG_DFL);
			signal(SIGHUP, SIG_DFL);
877

878
			switch (which) {
879
			case 0: udpserver(udpsock, portnum);
880
				break;
881
			case 1: udpserver(altudpsock, TBSERVER_PORT2);
882
				break;
883
			case 2: tcpserver(alttcpsock, TBSERVER_PORT2);
884
				break;
885
			case 3: tcpserver(tcpsock, portnum);
886 887 888 889 890 891 892 893 894 895 896 897
				break;
			}
			exit(-1);
		}

		/*
		 * Parent waits.
		 */
		pid = waitpid(-1, &status, 0);
		if (pid < 0) {
			errorc("waitpid failed");
			continue;
898
		}
899 900 901
		if (WIFSIGNALED(status)) {
			error("server %d exited with signal %d!\n",
			      pid, WTERMSIG(status));
902
		}
903 904
		else if (WIFEXITED(status)) {
			error("server %d exited with status %d!\n",
905
			      pid, WEXITSTATUS(status));
906
		}
907
		numchildren--;
908 909 910 911 912 913 914 915 916 917

		/*
		 * Figure out which and what kind of server it was that died.
		 */
		for (i = 0; i < maxchildren; i++) {
			if (servers[i].pid == pid) {
				servers[i].pid = 0;
				server_counts[servers[i].which]++;
				break;
			}
918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935
		}
		if (killme && !numchildren)
			break;
	}
 done:
	CLOSE(tcpsock);
	close(udpsock);
	info("daemon terminating\n");
	exit(0);
}

/*
 * Create sockets on specified port.
 */
static int
makesockets(int portnum, int *udpsockp, int *tcpsockp)
{
	struct sockaddr_in	name;
Mike Hibler's avatar
Mike Hibler committed
936 937
	socklen_t		length;
	int			i, udpsock, tcpsock;
938

Mike Hibler's avatar
Mike Hibler committed
939
	/*
940
	 * Setup TCP socket for incoming connections.
Mike Hibler's avatar
Mike Hibler committed
941 942
	 */

943
	/* Create socket from which to read. */
Mike Hibler's avatar
Mike Hibler committed
944 945
	tcpsock = socket(AF_INET, SOCK_STREAM, 0);
	if (tcpsock < 0) {
946
		pfatal("opening stream socket");
947 948
	}

949
	i = 1;
Mike Hibler's avatar
Mike Hibler committed
950
	if (setsockopt(tcpsock, SOL_SOCKET, SO_REUSEADDR,
951
		       (char *)&i, sizeof(i)) < 0)
952
		pwarning("setsockopt(SO_REUSEADDR)");;
953

954 955 956
	/* Create name. */
	name.sin_family = AF_INET;
	name.sin_addr.s_addr = INADDR_ANY;
957
	name.sin_port = htons((u_short) portnum);
Mike Hibler's avatar
Mike Hibler committed
958
	if (bind(tcpsock, (struct sockaddr *) &name, sizeof(name))) {
959
		pfatal("binding stream socket");
960 961 962
	}
	/* Find assigned port value and print it out. */
	length = sizeof(name);
Mike Hibler's avatar
Mike Hibler committed
963
	if (getsockname(tcpsock, (struct sockaddr *) &name, &length)) {
964
		pfatal("getsockname");
965
	}
966
	if (listen(tcpsock, 512) < 0) {
967
		pfatal("listen");
968
	}
969
	info("listening on TCP port %d\n", ntohs(name.sin_port));
970

Mike Hibler's avatar
Mike Hibler committed
971 972 973 974 975 976 977
	/*
	 * Setup UDP socket
	 */

	/* Create socket from which to read. */
	udpsock = socket(AF_INET, SOCK_DGRAM, 0);
	if (udpsock < 0) {
978
		pfatal("opening dgram socket");
Mike Hibler's avatar
Mike Hibler committed
979 980 981 982 983
	}

	i = 1;
	if (setsockopt(udpsock, SOL_SOCKET, SO_REUSEADDR,
		       (char *)&i, sizeof(i)) < 0)
984
		pwarning("setsockopt(SO_REUSEADDR)");;
985 986 987 988

	i = 128 * 1024;
	if (setsockopt(udpsock, SOL_SOCKET, SO_RCVBUF, &i, sizeof(i)) < 0)
		pwarning("setsockopt(SO_RCVBUF)");
989

Mike Hibler's avatar
Mike Hibler committed
990 991 992
	/* Create name. */
	name.sin_family = AF_INET;
	name.sin_addr.s_addr = INADDR_ANY;
993
	name.sin_port = htons((u_short) portnum);
Mike Hibler's avatar
Mike Hibler committed
994
	if (bind(udpsock, (struct sockaddr *) &name, sizeof(name))) {
995
		pfatal("binding dgram socket");
Mike Hibler's avatar
Mike Hibler committed
996 997 998 999 1000
	}

	/* Find assigned port value and print it out. */
	length = sizeof(name);
	if (getsockname(udpsock, (struct sockaddr *) &name, &length)) {
1001
		pfatal("getsockname");
Mike Hibler's avatar
Mike Hibler committed
1002
	}
1003
	info("listening on UDP port %d\n", ntohs(name.sin_port));
1004

1005 1006 1007
	*tcpsockp = tcpsock;
	*udpsockp = udpsock;
	return 0;
1008
}
1009

1010
/*
1011
 * Listen for UDP requests. This is not a secure channel, and so this should
1012 1013 1014
 * eventually be killed off.
 */
static void
1015
udpserver(int sock, int portnum)
1016 1017 1018
{
	char			buf[MYBUFSIZE];
	struct sockaddr_in	client;
Mike Hibler's avatar
Mike Hibler committed
1019 1020
	socklen_t		length;
	int			cc;
1021
	unsigned int		nreq = 0;
1022

1023 1024
	info("udpserver starting: pid=%d sock=%d portnum=%d\n",
	     mypid, sock, portnum);
1025 1026 1027 1028 1029

	/*
	 * Wait for udp connections.
	 */
	while (1) {
1030
		setproctitle("UDP %d: %u done", portnum, nreq);
1031
		length = sizeof(client);
1032
		cc = recvfrom(sock, buf, sizeof(buf) - 1,
1033 1034 1035
			      0, (struct sockaddr *)&client, &length);
		if (cc <= 0) {
			if (cc < 0)
1036 1037
				errorc("Reading UDP request");
			error("UDP Connection aborted\n");
1038
			continue;
1039
		}
1040
		buf[cc] = '\0';
1041
		handle_request(sock, &client, buf, cc, 0);
1042
		nreq++;
1043 1044 1045 1046
	}
	exit(1);
}

1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072
int
tmcd_accept(int sock, struct sockaddr *addr, socklen_t *addrlen, int ms)
{
	int	newsock;

	if ((newsock = accept(sock, addr, addrlen)) < 0)
		return -1;

	/*
	 * Set timeout value to keep us from hanging due to a
	 * malfunctioning or malicious client.
	 */
	if (ms > 0) {
		struct timeval tv;

		tv.tv_sec = ms / 1000;
		tv.tv_usec = (ms % 1000) * 1000;
		if (setsockopt(newsock, SOL_SOCKET, SO_RCVTIMEO,
			       &tv, sizeof(tv)) < 0) {
			errorc("setting SO_RCVTIMEO");
		}
	}

	return newsock;
}

1073
/*
1074
 * Listen for TCP requests.
1075 1076
 */
static void
1077
tcpserver(int sock, int portnum)
1078
{
1079
	char			buf[MAXTMCDPACKET];
1080
	struct sockaddr_in	client;
Mike Hibler's avatar
Mike Hibler committed
1081 1082
	socklen_t		length;
	int			cc, newsock;
1083
	unsigned int		nreq = 0;
1084
	struct timeval		tv;
1085

1086 1087
	info("tcpserver starting: pid=%d sock=%d portnum=%d\n",
	     mypid, sock, portnum);
1088 1089 1090 1091 1092

	/*
	 * Wait for TCP connections.
	 */
	while (1) {
1093
		setproctitle("TCP %d: %u done", portnum, nreq);
1094
		length  = sizeof(client);
1095 1096
		newsock = ACCEPT(sock, (struct sockaddr *)&client, &length,
				 readtimo);
1097
		if (newsock < 0) {
1098
			errorc("accepting TCP connection");
1099
			continue;
1100
		}
Mike Hibler's avatar
Mike Hibler committed
1101

1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115
		/*
		 * Set write timeout value to keep us from hanging due to a
		 * malfunctioning or malicious client.
		 * NOTE: ACCEPT function sets read timeout.
		 */
		tv.tv_sec = writetimo / 1000;
		tv.tv_usec = (writetimo % 1000) * 1000;
		if (setsockopt(newsock, SOL_SOCKET, SO_SNDTIMEO,
			       &tv, sizeof(tv)) < 0) {
			errorc("setting SO_SNDTIMEO");
			CLOSE(newsock);
			continue;
		}

Mike Hibler's avatar
Mike Hibler committed
1116
		/*
1117
		 * Read in the command request.
Mike Hibler's avatar
Mike Hibler committed
1118
		 */
1119
		if ((cc = READ(newsock, buf, sizeof(buf) - 1)) <= 0) {
1120 1121 1122 1123 1124 1125
			if (cc < 0) {
				if (errno == EWOULDBLOCK)
					errorc("Timeout reading TCP request");
				else
					errorc("Error reading TCP request");
			}
1126 1127
			error("TCP connection aborted\n");
			CLOSE(newsock);
1128
			continue;
1129
		}
1130
		buf[cc] = '\0';
1131
		handle_request(newsock, &client, buf, cc, 1);
1132
		CLOSE(newsock);
1133
		nreq++;
1134 1135 1136
	}
	exit(1);
}
Mike Hibler's avatar
Mike Hibler committed
1137

1138 1139 1140
//#define error(x...)	fprintf(stderr, ##x)
//#define info(x...)	fprintf(stderr, ##x)

1141
static int
1142
handle_request(int sock, struct sockaddr_in *client, char *rdata, int rdatalen, int istcp)
1143 1144
{
	struct sockaddr_in redirect_client;
1145
	int		   redirect = 0;
1146
	char		   buf[BUFSIZ], *bp, *cp, *ordata;
1147 1148
	char		   privkeybuf[PRIVKEY_LEN];
	char		   *privkey = (char *) NULL;
1149
	int		   i, overbose = 0, err = 0;
1150
	int		   version = DEFAULT_VERSION;
1151 1152
	tmcdreq_t	   tmcdreq, *reqp = &tmcdreq;

1153
	byteswritten = 0;
1154 1155 1156 1157 1158
#ifdef	WITHSSL
	cp = (istcp ? (isssl ? "SSL" : "TCP") : "UDP");
#else
	cp = (istcp ? "TCP" : "UDP");
#endif
1159
	setproctitle("%s: %s", inet_ntoa(client->sin_addr), cp);
1160

1161 1162 1163 1164
	/*
	 * Init the req structure.
	 */
	bzero(reqp, sizeof(*reqp));
Mike Hibler's avatar
Mike Hibler committed
1165

1166
	/*
1167
	 * Look for special tags.
1168
	 */
1169
	bp = ordata = rdata;