tmcd.c 330 KB
Newer Older
Leigh B. Stoller's avatar
Leigh B. Stoller committed
1
/*
2
 * Copyright (c) 2000-2014 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 B. Stoller's avatar
Leigh B. 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>
Leigh B. Stoller's avatar
Leigh B. Stoller committed
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 B. Stoller's avatar
Leigh B. 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"
Austin Clements's avatar
Austin Clements committed
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 183
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. */
} imstrings_t;

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

208 209 210 211
/* socket timeouts */
static int	readtimo = READTIMO;
static int	writetimo = WRITETIMO;

212
/* thread support */
213
#define MAXCHILDREN	20
214
#define MINCHILDREN	8
215
static int	numchildren;
216 217 218 219
static int	maxchildren       = 13;
static int      num_udpservers    = 3;
static int      num_altudpservers = 1;
static int      num_alttcpservers = 1;
220
static int	mypid;
221
static volatile int killme;
222

223 224 225 226 227
/* Output macro to check for string overflow */
#define OUTPUT(buf, size, format...) \
({ \
	int __count__ = snprintf((buf), (size), ##format); \
        \
228
        if (__count__ >= (size)) { \
229 230 231 232 233 234
		error("Not enough room in output buffer! line %d.\n", __LINE__);\
		return 1; \
	} \
	__count__; \
})

235 236 237 238 239
/*
 * 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 B. Stoller's avatar
Leigh B. Stoller committed
240
	struct in_addr  client;
241 242 243
	int		allocated;
	int		jailflag;
	int		isvnode;
244
	int		asvnode;
245
	int		issubnode;
246
	int		islocal;
247
	int		isdedicatedwa;
248
	int		iscontrol;
249
	int		isplabdslice;
250
	int		isplabsvc;
251
	int		elab_in_elab;
252
        int		singlenet;	  /* Modifier for elab_in_elab */
253
	int		update_accounts;
254
	int		exptidx;
255 256 257
	int		creator_idx;
	int		swapper_idx;
	int		swapper_isadmin;
258
        int		genisliver_idx;
259
        int		geniflags;
260
        int		nonfsmounts;
261
	unsigned int    taintstates;
262 263
	char		nodeid[TBDB_FLEN_NODEID];
	char		vnodeid[TBDB_FLEN_NODEID];
Leigh B. Stoller's avatar
Leigh B. Stoller committed
264
	char		pnodeid[TBDB_FLEN_NODEID]; /* XXX */
265 266 267 268 269
	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];
270
	char		class[TBDB_FLEN_NODECLASS];
271 272
        char		ptype[TBDB_FLEN_NODETYPE];	/* Of physnode */
	char		pclass[TBDB_FLEN_NODECLASS];	/* Of physnode */
273 274
	char		creator[TBDB_FLEN_UID];
	char		swapper[TBDB_FLEN_UID];
275
	char		syncserver[TBDB_FLEN_VNAME];	/* The vname */
276
	char		keyhash[TBDB_FLEN_PRIVKEY];
277
	char		eventkey[TBDB_FLEN_PRIVKEY];
278
	char		sfshostid[TBDB_FLEN_SFSHOSTID];
279
	char		testdb[TBDB_FLEN_TINYTEXT];
280
	char		sharing_mode[TBDB_FLEN_TINYTEXT];
281
	char		erole[TBDB_FLEN_TINYTEXT];
282
	char            privkey[PRIVKEY_LEN+1];
283
	char		nodeuuid[TBDB_FLEN_UUID];
284 285
        /* This key is a replacement for privkey, on protogeni resources */
	char            external_key[PRIVKEY_LEN+1];
286
} tmcdreq_t;
287
static int	iptonodeid(struct in_addr, tmcdreq_t *, char*);
288
static int	checkdbredirect(tmcdreq_t *);
289
static int      sendstoreconf(int sock, int tcp, tmcdreq_t *reqp, char *bscmd, 
290
			      char *vname, int dopersist);
291
static int      get_imagestrings(tmcdreq_t *reqp, imstrings_t *imstrings);
292

293 294 295 296 297
#ifdef EVENTSYS
int			myevent_send(address_tuple_t address);
static event_handle_t	event_handle = NULL;
#endif

298 299 300
/*
 * Commands we support.
 */
301 302
#define COMMAND_PROTOTYPE(x) \
	static int \
303
	x(int sock, tmcdreq_t *reqp, char *rdata, int tcp, int vers)
304 305

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

410 411
/*
 * The fullconfig slot determines what routines get called when pushing
412
 * out a full configuration. Physnodes get slightly different
413
 * than vnodes, and at some point we might want to distinguish different
414 415 416 417 418
 * types of vnodes (jailed, plab).
 */
#define FULLCONFIG_NONE		0x0
#define FULLCONFIG_PHYS		0x1
#define FULLCONFIG_VIRT		0x2
419 420 421 422 423
#define FULLCONFIG_ALL		(FULLCONFIG_PHYS|FULLCONFIG_VIRT)

/*
 * Flags encode a few other random properties of commands
 */
424 425 426 427 428
#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 */
429
#define F_REMREQSSL	0x20	/* remote nodes must connect with SSL */
430
#define F_REQTPM	0x40	/* require TPM on client */
431

432 433
struct command {
	char	*cmdname;
434
	int	fullconfig;
435
	int	flags;
436
	int    (*func)(int, tmcdreq_t *, char *, int, int);
437
} command_array[] = {
438 439
	{ "reboot",	  FULLCONFIG_NONE, 0, doreboot },
	{ "nodeid",	  FULLCONFIG_ALL,  0, donodeid },
440
	{ "nodeuuid",	  FULLCONFIG_ALL,  0, donodeuuid },
David Johnson's avatar
David Johnson committed
441
	{ "manifest",	  FULLCONFIG_ALL,  0, domanifest },
442
	{ "status",	  FULLCONFIG_NONE, 0, dostatus },
443
	{ "ifconfig",	  FULLCONFIG_ALL,  F_ALLOCATED, doifconfig },
444
	{ "accounts",	  FULLCONFIG_ALL,  F_REMREQSSL, doaccounts },
445
	{ "delay",	  FULLCONFIG_ALL,  F_ALLOCATED, dodelay },
446
	{ "bridges",	  FULLCONFIG_ALL,  F_ALLOCATED, dobridges },
447 448 449 450 451
	{ "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 },
452
	{ "blobs",	  FULLCONFIG_ALL,  F_ALLOCATED, doblobs },
453 454
	{ "startupcmd",	  FULLCONFIG_ALL,  F_ALLOCATED, dostartcmd },
	{ "startstatus",  FULLCONFIG_NONE, F_ALLOCATED, dostartstat }, /* Before startstat*/
455
	{ "startstat",	  FULLCONFIG_NONE, 0, dostartstat },
456 457
	{ "readycount",   FULLCONFIG_NONE, F_ALLOCATED, doreadycount },
	{ "ready",	  FULLCONFIG_NONE, F_ALLOCATED, doready },
458
	{ "storageconfig", FULLCONFIG_ALL, F_ALLOCATED, dostorageconfig},
459 460
	{ "mounts",	  FULLCONFIG_ALL,  F_ALLOCATED, domounts },
	{ "sfshostid",	  FULLCONFIG_NONE, F_ALLOCATED, dosfshostid },
461 462
	{ "loadinfo",	  FULLCONFIG_NONE, 0, doloadinfo},
	{ "reset",	  FULLCONFIG_NONE, 0, doreset},
463 464 465 466
	{ "routing",	  FULLCONFIG_ALL,  F_ALLOCATED, dorouting},
	{ "trafgens",	  FULLCONFIG_ALL,  F_ALLOCATED, dotrafgens},
	{ "nseconfigs",	  FULLCONFIG_ALL,  F_ALLOCATED, donseconfigs},
	{ "creator",	  FULLCONFIG_ALL,  F_ALLOCATED, docreator},
467
	{ "state",	  FULLCONFIG_NONE, 0, dostate},
468
	{ "tunnels",	  FULLCONFIG_ALL,  F_ALLOCATED, dotunnels},
469
	{ "vnodelist",	  FULLCONFIG_PHYS, 0, dovnodelist},
Timothy Stack's avatar
 
Timothy Stack committed
470
	{ "subnodelist",  FULLCONFIG_PHYS, 0, dosubnodelist},
471
	{ "isalive",	  FULLCONFIG_NONE, F_REMUDP|F_MINLOG, doisalive},
472
	{ "ipodinfo",	  FULLCONFIG_PHYS, 0, doipodinfo},
473 474
	{ "ntpinfo",	  FULLCONFIG_PHYS, 0, dontpinfo},
	{ "ntpdrift",	  FULLCONFIG_NONE, 0, dontpdrift},
475 476
	{ "jailconfig",	  FULLCONFIG_VIRT, F_ALLOCATED, dojailconfig},
	{ "plabconfig",	  FULLCONFIG_VIRT, F_ALLOCATED, doplabconfig},
Timothy Stack's avatar
 
Timothy Stack committed
477
	{ "subconfig",	  FULLCONFIG_NONE, 0, dosubconfig},
478
        { "sdparams",     FULLCONFIG_PHYS, 0, doslothdparams},
479 480
        { "programs",     FULLCONFIG_ALL,  F_ALLOCATED, doprogagents},
        { "syncserver",   FULLCONFIG_ALL,  F_ALLOCATED, dosyncserver},
481
        { "keyhash",      FULLCONFIG_ALL,  F_ALLOCATED|F_REMREQSSL, dokeyhash},
482
        { "eventkey",     FULLCONFIG_ALL,  F_ALLOCATED|F_REMREQSSL, doeventkey},
483 484 485
        { "fullconfig",   FULLCONFIG_NONE, F_ALLOCATED, dofullconfig},
        { "routelist",	  FULLCONFIG_PHYS, F_ALLOCATED, doroutelist},
        { "role",	  FULLCONFIG_PHYS, F_ALLOCATED, dorole},
486
        { "rusage",	  FULLCONFIG_NONE, F_REMUDP|F_MINLOG, dorusage},
487
        { "watchdoginfo", FULLCONFIG_ALL,  F_REMUDP|F_MINLOG, dodoginfo},
Mike Hibler's avatar
Mike Hibler committed
488
        { "hostkeys",     FULLCONFIG_NONE, 0, dohostkeys},
Mike Hibler's avatar
Mike Hibler committed
489
        { "tmcctest",     FULLCONFIG_NONE, F_MINLOG, dotmcctest},
490
        { "firewallinfo", FULLCONFIG_ALL,  0, dofwinfo},
491
        { "hostinfo",     FULLCONFIG_NONE, 0, dohostinfo},
492
	{ "emulabconfig", FULLCONFIG_NONE, F_ALLOCATED, doemulabconfig},
493
	{ "eplabconfig",  FULLCONFIG_NONE, F_ALLOCATED, doeplabconfig},
494
	{ "localization", FULLCONFIG_PHYS, 0, dolocalize},
495
	{ "rootpswd",     FULLCONFIG_NONE, F_REMREQSSL, dorootpswd},
496 497
	{ "booterrno",    FULLCONFIG_NONE, 0, dobooterrno},
	{ "bootlog",      FULLCONFIG_NONE, 0, dobootlog},
Timothy Stack's avatar
 
Timothy Stack committed
498
	{ "battery",      FULLCONFIG_NONE, F_REMUDP|F_MINLOG, dobattery},
499
	{ "topomap",      FULLCONFIG_NONE, F_MINLOG|F_ALLOCATED, dotopomap},
500
	{ "userenv",      FULLCONFIG_ALL,  F_ALLOCATED, douserenv},
Timothy Stack's avatar
 
Timothy Stack committed
501
	{ "tiptunnels",	  FULLCONFIG_ALL,  F_ALLOCATED, dotiptunnels},
502
	{ "traceinfo",	  FULLCONFIG_ALL,  F_ALLOCATED, dotraceconfig },
Kirk Webb's avatar
 
Kirk Webb committed
503
	{ "ltmap",        FULLCONFIG_NONE, F_MINLOG|F_ALLOCATED, doltmap},
504
	{ "ltpmap",       FULLCONFIG_NONE, F_MINLOG|F_ALLOCATED, doltpmap},
Kirk Webb's avatar
 
Kirk Webb committed
505
	{ "elvindport",   FULLCONFIG_NONE, 0, doelvindport},
506
	{ "plabeventkeys",FULLCONFIG_NONE, F_REMREQSSL, doplabeventkeys},
507
	{ "intfcmap",     FULLCONFIG_NONE, 0, dointfcmap},
508 509
	{ "motelog",      FULLCONFIG_ALL,  F_ALLOCATED, domotelog},
	{ "portregister", FULLCONFIG_NONE, F_REMNOSSL, doportregister},
Leigh B. Stoller's avatar
Leigh B. Stoller committed
510
	{ "bootwhat",	  FULLCONFIG_NONE, 0, dobootwhat },
511 512
	{ "tpmblob",	  FULLCONFIG_ALL, 0, dotpmblob },
	{ "tpmpubkey",	  FULLCONFIG_ALL, 0, dotpmpubkey },
513
	{ "tpmdummy",	  FULLCONFIG_ALL, F_REQTPM, dotpmdummy },
514
	{ "dhcpdconf",	  FULLCONFIG_ALL, 0, dodhcpdconf },
515 516
	{ "securestate",  FULLCONFIG_NONE, F_REMREQSSL, dosecurestate},
	{ "quoteprep",    FULLCONFIG_NONE, F_REMREQSSL, doquoteprep},
517
	{ "imagekey",     FULLCONFIG_NONE, F_REQTPM, doimagekey},
518
	{ "nodeattributes", FULLCONFIG_ALL, 0, donodeattributes},
519
	{ "disks",	  FULLCONFIG_ALL, 0, dodisks},
520
	{ "arpinfo",	  FULLCONFIG_NONE, 0, doarpinfo},
Mike Hibler's avatar
Mike Hibler committed
521
	{ "hwinfo",	  FULLCONFIG_NONE, 0, dohwinfo},
522
	{ "tiplineinfo",  FULLCONFIG_NONE,  F_ALLOCATED, dotiplineinfo},
523
	{ "imageinfo",      FULLCONFIG_NONE,  F_ALLOCATED, doimageid},
524 525 526 527 528 529 530 531 532 533 534 535 536
#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 },
	{ "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 },
537 538
	{ "geni_status", FULLCONFIG_NONE, 0, dogenistatus },
	{ "geni_commands", FULLCONFIG_NONE, 0, dogenicommands },
539
	{ "geni_all",     FULLCONFIG_NONE, 0, dogeniall },
540 541 542
	/* 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 }
543
#endif
544 545 546
};
static int numcommands = sizeof(command_array)/sizeof(struct command);

547
char *usagestr =
548 549 550
 "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"
551
 " -c num	   Specify number of servers (must be %d <= x <= %d)\n"
552
 " -v              More verbose logging\n"
553
 " -i ipaddr       Sets the boss IP addr to return (for multi-homed servers)\n"
554 555 556 557 558
 "\n";

void
usage()
{
559
	fprintf(stderr, usagestr, MINCHILDREN, MAXCHILDREN);
560 561 562
	exit(1);
}

563 564 565 566 567
static void
cleanup()
{
	signal(SIGHUP, SIG_IGN);
	killme = 1;
568
	killpg(0, SIGHUP);
Leigh B Stoller's avatar
Leigh B Stoller committed
569
	unlink(pidfile);
570 571
}

572 573 574 575
static void
setverbose(int sig)
{
	signal(sig, SIG_IGN);
576

577 578 579 580
	if (sig == SIGUSR1)
		verbose = 1;
	else
		verbose = 0;
581 582
	info("verbose logging turned %s\n", verbose ? "on" : "off");

583 584 585 586 587 588
	/* Just the parent sends this */
	if (numchildren)
		killpg(0, sig);
	signal(sig, setverbose);
}

Mike Hibler's avatar
Mike Hibler committed
589 590
int
main(int argc, char **argv)
591
{
592
	int			tcpsock, udpsock, i, ch;
593 594 595
	int			alttcpsock, altudpsock;
	int			status, pid;
	int			portnum = TBSERVER_PORT;
596 597
	FILE			*fp;
	char			buf[BUFSIZ];
598
	struct hostent		*he;
599
	extern char		build_info[];
600 601 602 603 604
	int			server_counts[4]; /* udp,tcp,altudp,alttcp */
	struct {
		int	pid;
		int	which;
	} servers[MAXCHILDREN];
605

606
	while ((ch = getopt(argc, argv, "dp:c:Xvi:")) != -1)
607 608 609 610 611 612
		switch(ch) {
		case 'p':
			portnum = atoi(optarg);
			break;
		case 'd':
			debug++;
613
			break;
614 615 616
		case 'c':
			maxchildren = atoi(optarg);
			break;
617 618 619
		case 'X':
			insecure = 1;
			break;
620 621 622
		case 'v':
			verbose++;
			break;
623 624 625 626 627 628 629
		case 'i':
			if (inet_aton(optarg, &myipaddr) == 0) {
				fprintf(stderr, "invalid IP address %s\n",
					optarg);
				usage();
			}
			break;
630 631 632 633 634 635 636 637 638 639
		case 'h':
		case '?':
		default:
			usage();
		}
	argc -= optind;
	argv += optind;

	if (argc)
		usage();
640 641
	if (maxchildren < MINCHILDREN || maxchildren > MAXCHILDREN)
		usage();
642

643 644 645 646 647 648
#ifdef  WITHSSL
	if (tmcd_server_sslinit()) {
		error("SSL init failed!\n");
		exit(1);
	}
#endif
649
	if (debug)
650 651 652
		loginit(0, 0);
	else {
		/* Become a daemon */
653 654 655 656 657
		if (chdir(TBCOREDIR)) {
			daemon(0, 0);
		} else {
			daemon(1, 0);
		}
658 659 660 661
		loginit(1, "tmcd");
	}
	info("daemon starting (version %d)\n", CURRENT_VERSION);
	info("%s\n", build_info);
Mike Hibler's avatar
Mike Hibler committed
662

Austin Clements's avatar
Austin Clements committed
663 664 665 666 667 668 669 670 671 672 673 674 675 676
	/*
	 * 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;
677 678 679
				if (debug) {
				    info("fshostid: %s\n", fshostid);
				}
Austin Clements's avatar
Austin Clements committed
680 681 682 683 684 685 686 687
			}
			else {
				error("fshostid from %s may be corrupt: %s",
				      FSHOSTID, fshostid);
			}
			fclose(fp);
		}
	}
688

689 690 691
	/*
	 * Grab our IP for security check below.
	 */
692
	if (myipaddr.s_addr == 0) {
693
#ifdef	LBS
694
		strcpy(buf, BOSSNODE);
695
#else
696 697
		if (gethostname(buf, sizeof(buf)) < 0)
			pfatal("getting hostname");
698
#endif
699 700 701 702 703 704
		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);
705 706
	}

707
	/*
708
	 * If we were given a port on the command line, don't open the
709 710 711 712
	 * alternate ports
	 */
	if (portnum != TBSERVER_PORT) {
	    if (makesockets(portnum, &udpsock, &tcpsock) < 0) {
713 714
		error("Could not make sockets!");
		exit(1);
715
	    }
716
	    num_alttcpservers = num_altudpservers = 0;
717 718 719 720 721 722
	} else {
	    if (makesockets(portnum, &udpsock, &tcpsock) < 0 ||
		makesockets(TBSERVER_PORT2, &altudpsock, &alttcpsock) < 0) {
		    error("Could not make sockets!");
		    exit(1);
	    }
723 724
	}

Mike Hibler's avatar
Mike Hibler committed
725 726 727 728 729 730 731 732 733 734 735 736 737
	/*
	 * 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;

738 739 740
	signal(SIGTERM, cleanup);
	signal(SIGINT, cleanup);
	signal(SIGHUP, cleanup);
741 742
	signal(SIGUSR1, setverbose);
	signal(SIGUSR2, setverbose);
743 744 745 746

	/*
	 * Stash the pid away.
	 */
747
	mypid = getpid();
Leigh B Stoller's avatar
Leigh B Stoller committed
748 749
	sprintf(pidfile, "%s/tmcd.pid", _PATH_VARRUN);
	fp = fopen(pidfile, "w");
750
	if (fp != NULL) {
751
		fprintf(fp, "%d\n", mypid);
752 753 754
		(void) fclose(fp);
	}

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
	/*
	 * 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);
	}

788 789
	/*
	 * Now fork a set of children to handle requests. We keep the
790 791 792 793 794 795 796
	 * 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!
797
	 */
798 799 800 801 802 803
	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));
804

805 806
	while (1) {
		while (!killme && numchildren < maxchildren) {
807
			int which = 3;
808

809 810 811 812 813 814 815 816
			/*
			 * Find which kind of server is short one.
			 */
			for (i = 0; i < 4; i++) {
				if (server_counts[i]) {
					which = i;
					break;
				}
817
			}
818

819 820 821 822 823
			if ((pid = fork()) < 0) {
				errorc("forking server");
				goto done;
			}
			if (pid) {
824 825 826 827 828 829 830 831 832 833
				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;
834 835 836
				numchildren++;
				continue;
			}
837 838 839
			/* Poor way of knowing parent/child */
			numchildren = 0;
			mypid = getpid();
840

841 842 843 844
			/* Child does useful work! Never Returns! */
			signal(SIGTERM, SIG_DFL);
			signal(SIGINT, SIG_DFL);
			signal(SIGHUP, SIG_DFL);
845

846
			switch (which) {
847
			case 0: udpserver(udpsock, portnum);
848
				break;
849
			case 1: udpserver(altudpsock, TBSERVER_PORT2);
850
				break;
851
			case 2: tcpserver(alttcpsock, TBSERVER_PORT2);
852
				break;
853
			case 3: tcpserver(tcpsock, portnum);
854 855 856 857 858 859 860 861 862 863 864 865
				break;
			}
			exit(-1);
		}

		/*
		 * Parent waits.
		 */
		pid = waitpid(-1, &status, 0);
		if (pid < 0) {
			errorc("waitpid failed");
			continue;
866
		}
867 868 869
		if (WIFSIGNALED(status)) {
			error("server %d exited with signal %d!\n",
			      pid, WTERMSIG(status));
870
		}
871 872
		else if (WIFEXITED(status)) {
			error("server %d exited with status %d!\n",
873
			      pid, WEXITSTATUS(status));
874
		}
875
		numchildren--;
876 877 878 879 880 881 882 883 884 885

		/*
		 * 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;
			}
886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903
		}
		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
lint  
Mike Hibler committed
904 905
	socklen_t		length;
	int			i, udpsock, tcpsock;
906

Mike Hibler's avatar
Mike Hibler committed
907
	/*
908
	 * Setup TCP socket for incoming connections.
Mike Hibler's avatar
Mike Hibler committed
909 910
	 */

911
	/* Create socket from which to read. */
Mike Hibler's avatar
Mike Hibler committed
912 913
	tcpsock = socket(AF_INET, SOCK_STREAM, 0);
	if (tcpsock < 0) {
914
		pfatal("opening stream socket");
915 916
	}

917
	i = 1;
Mike Hibler's avatar
Mike Hibler committed
918
	if (setsockopt(tcpsock, SOL_SOCKET, SO_REUSEADDR,
919
		       (char *)&i, sizeof(i)) < 0)
920
		pwarning("setsockopt(SO_REUSEADDR)");;
921

922 923 924
	/* Create name. */
	name.sin_family = AF_INET;
	name.sin_addr.s_addr = INADDR_ANY;
925
	name.sin_port = htons((u_short) portnum);
Mike Hibler's avatar
Mike Hibler committed
926
	if (bind(tcpsock, (struct sockaddr *) &name, sizeof(name))) {
927
		pfatal("binding stream socket");
928 929 930
	}
	/* Find assigned port value and print it out. */
	length = sizeof(name);
Mike Hibler's avatar
Mike Hibler committed
931
	if (getsockname(tcpsock, (struct sockaddr *) &name, &length)) {
932
		pfatal("getsockname");
933
	}
934
	if (listen(tcpsock, 128) < 0) {
935
		pfatal("listen");
936
	}
937
	info("listening on TCP port %d\n", ntohs(name.sin_port));
938

Mike Hibler's avatar
Mike Hibler committed
939 940 941 942 943 944 945
	/*
	 * Setup UDP socket
	 */

	/* Create socket from which to read. */
	udpsock = socket(AF_INET, SOCK_DGRAM, 0);
	if (udpsock < 0) {
946
		pfatal("opening dgram socket");
Mike Hibler's avatar
Mike Hibler committed
947 948 949 950 951
	}

	i = 1;
	if (setsockopt(udpsock, SOL_SOCKET, SO_REUSEADDR,
		       (char *)&i, sizeof(i)) < 0)
952
		pwarning("setsockopt(SO_REUSEADDR)");;
953 954 955 956

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

Mike Hibler's avatar
Mike Hibler committed
958 959 960
	/* Create name. */
	name.sin_family = AF_INET;
	name.sin_addr.s_addr = INADDR_ANY;
961
	name.sin_port = htons((u_short) portnum);
Mike Hibler's avatar
Mike Hibler committed
962
	if (bind(udpsock, (struct sockaddr *) &name, sizeof(name))) {
963
		pfatal("binding dgram socket");
Mike Hibler's avatar
Mike Hibler committed
964 965 966 967 968
	}

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

973 974 975
	*tcpsockp = tcpsock;
	*udpsockp = udpsock;
	return 0;
976
}
977

978
/*
979
 * Listen for UDP requests. This is not a secure channel, and so this should
980 981 982
 * eventually be killed off.
 */
static void
983
udpserver(int sock, int portnum)