tmcd.c 282 KB
Newer Older
Leigh B. Stoller's avatar
Leigh B. Stoller committed
1
/*
Leigh B Stoller's avatar
Leigh B Stoller committed
2
 * Copyright (c) 2000-2013 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
77
78
79
80
81
#ifdef  FSDIR_SCRATCH
#define FSSCRATCHDIR	FSNODE ":" FSDIR_SCRATCH
#endif
#define PROJDIR		PROJROOT_DIR
#define GROUPDIR	GROUPSROOT_DIR
#define USERDIR		USERSROOT_DIR
#define SCRATCHDIR	SCRATCHROOT_DIR
#define SHAREDIR	SHAREROOT_DIR
82
#define NETBEDDIR	"/netbed"
Kirk Webb's avatar
   
Kirk Webb committed
83
#define PLISALIVELOGDIR "/usr/testbed/log/plabisalive"
84
85
#define RELOADPID	"emulab-ops"
#define RELOADEID	"reloading"
Austin Clements's avatar
Austin Clements committed
86
#define FSHOSTID	"/usr/testbed/etc/fshostid"
87
#define DOTSFS		".sfs"
88
89
#define RUNASUSER	"nobody"
#define RUNASGROUP	"nobody"
90
#define NTPSERVER       "ntp1"
91
#define PROTOUSER	"elabman"
92
93
94
95
#define PRIVKEY_LEN	128
#define URN_LEN		128
#define XSTRINGIFY(s)   STRINGIFY(s)
#define STRINGIFY(s)	#s
96

97
98
99
100
101
/* XXX backward compat */
#ifndef TBCOREDIR
#define	TBCOREDIR	TBROOT "/tmp"
#endif

102
103
104
105
/* socket read/write timeouts in ms */
#define READTIMO	3000
#define WRITETIMO	3000

106
#define TESTMODE
107
108
109
110
111
112
113
114
115
116
117
118
#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) */
119

120
121
122
#define DISKTYPE	"ad"
#define DISKNUM		0

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

130
131
132
133
134
135
136
137
138
139
/*
 * Compiled in tarball/rpm param.
 * Should come out of the DB.
 */
#ifdef SPEWFROMOPS
#define TARRPM_SERVER	USERNODE
#else
#define TARRPM_SERVER	BOSSNODE
#endif

140
141
/* Defined in configure and passed in via the makefile */
#define DBNAME_SIZE	64
Austin Clements's avatar
Austin Clements committed
142
#define HOSTID_SIZE	(32+64)
143
144
#define DEFAULT_DBNAME	TBDBNAME

Robert P Ricci's avatar
Robert P Ricci committed
145
146
147
148
/* For secure disk loading */
#define SECURELOAD_OPMODE "SECURELOAD"
#define SECURELOAD_STATE  "RELOADSETUP"

149
int		debug = 0;
150
static int	verbose = 0;
151
static int	insecure = 0;
152
static int	byteswritten = 0;
Leigh B Stoller's avatar
Leigh B Stoller committed
153
static char	pidfile[MAXPATHLEN];
154
static char     dbname[DBNAME_SIZE];
155
static struct in_addr myipaddr;
Mike Hibler's avatar
Mike Hibler committed
156
static struct in_addr cnet, cmask, jnet, jmask;
Austin Clements's avatar
Austin Clements committed
157
static char	fshostid[HOSTID_SIZE];
Leigh B. Stoller's avatar
Leigh B. Stoller committed
158
static int	nodeidtoexp(char *nodeid, char *pid, char *eid, char *gid);
159
160
static void	tcpserver(int sock, int portnum);
static void	udpserver(int sock, int portnum);
161
static int      handle_request(int, struct sockaddr_in *, char *, int);
162
static int      checkcerts(char*);
163
static int	makesockets(int portnum, int *udpsockp, int *tcpsockp);
Mike Hibler's avatar
Mike Hibler committed
164
165
int		client_writeback(int sock, void *buf, int len, int tcp);
void		client_writeback_done(int sock, struct sockaddr_in *client);
166
167
MYSQL_RES *	mydb_query(char *query, int ncols, ...);
int		mydb_update(char *query, ...);
168
static int	safesymlink(char *name1, char *name2);
169

170
171
172
173
/* socket timeouts */
static int	readtimo = READTIMO;
static int	writetimo = WRITETIMO;

174
/* thread support */
175
#define MAXCHILDREN	20
176
#define MINCHILDREN	8
177
static int	numchildren;
178
179
180
181
static int	maxchildren       = 13;
static int      num_udpservers    = 3;
static int      num_altudpservers = 1;
static int      num_alttcpservers = 1;
182
static int	mypid;
183
static volatile int killme;
184

185
186
187
188
189
/* Output macro to check for string overflow */
#define OUTPUT(buf, size, format...) \
({ \
	int __count__ = snprintf((buf), (size), ##format); \
        \
190
        if (__count__ >= (size)) { \
191
192
193
194
195
196
		error("Not enough room in output buffer! line %d.\n", __LINE__);\
		return 1; \
	} \
	__count__; \
})

197
198
199
200
201
/*
 * 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
202
	struct in_addr  client;
203
204
205
	int		allocated;
	int		jailflag;
	int		isvnode;
206
	int		issubnode;
207
	int		islocal;
208
	int		isdedicatedwa;
209
	int		iscontrol;
210
	int		isplabdslice;
211
	int		isplabsvc;
212
	int		elab_in_elab;
213
        int		singlenet;	  /* Modifier for elab_in_elab */
214
	int		update_accounts;
215
	int		exptidx;
216
217
218
	int		creator_idx;
	int		swapper_idx;
	int		swapper_isadmin;
219
        int		genisliver_idx;
220
        int		geniflags;
221
222
	char		nodeid[TBDB_FLEN_NODEID];
	char		vnodeid[TBDB_FLEN_NODEID];
Leigh B. Stoller's avatar
Leigh B. Stoller committed
223
	char		pnodeid[TBDB_FLEN_NODEID]; /* XXX */
224
225
226
227
228
	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];
229
	char		class[TBDB_FLEN_NODECLASS];
230
231
        char		ptype[TBDB_FLEN_NODETYPE];	/* Of physnode */
	char		pclass[TBDB_FLEN_NODECLASS];	/* Of physnode */
232
233
	char		creator[TBDB_FLEN_UID];
	char		swapper[TBDB_FLEN_UID];
234
	char		syncserver[TBDB_FLEN_VNAME];	/* The vname */
235
	char		keyhash[TBDB_FLEN_PRIVKEY];
236
	char		eventkey[TBDB_FLEN_PRIVKEY];
237
	char		sfshostid[TBDB_FLEN_SFSHOSTID];
238
	char		testdb[TBDB_FLEN_TINYTEXT];
239
	char		sharing_mode[TBDB_FLEN_TINYTEXT];
240
	char            privkey[PRIVKEY_LEN+1];
241
	char		nodeuuid[TBDB_FLEN_UUID];
242
243
        /* This key is a replacement for privkey, on protogeni resources */
	char            external_key[PRIVKEY_LEN+1];
244
} tmcdreq_t;
245
static int	iptonodeid(struct in_addr, tmcdreq_t *, char*);
246
static int	checkdbredirect(tmcdreq_t *);
247
248
static int      sendstoreconf(int sock, int tcp, tmcdreq_t *reqp, char *bscmd, 
			      char *vname);
249

250
251
252
253
254
#ifdef EVENTSYS
int			myevent_send(address_tuple_t address);
static event_handle_t	event_handle = NULL;
#endif

255
256
257
/*
 * Commands we support.
 */
258
259
#define COMMAND_PROTOTYPE(x) \
	static int \
260
	x(int sock, tmcdreq_t *reqp, char *rdata, int tcp, int vers)
261
262

COMMAND_PROTOTYPE(doreboot);
263
COMMAND_PROTOTYPE(donodeid);
264
COMMAND_PROTOTYPE(donodeuuid);
David Johnson's avatar
David Johnson committed
265
COMMAND_PROTOTYPE(domanifest);
266
267
268
COMMAND_PROTOTYPE(dostatus);
COMMAND_PROTOTYPE(doifconfig);
COMMAND_PROTOTYPE(doaccounts);
269
COMMAND_PROTOTYPE(dobridges);
270
COMMAND_PROTOTYPE(dodelay);
271
COMMAND_PROTOTYPE(dolinkdelay);
272
273
274
275
COMMAND_PROTOTYPE(dohosts);
COMMAND_PROTOTYPE(dorpms);
COMMAND_PROTOTYPE(dodeltas);
COMMAND_PROTOTYPE(dotarballs);
276
COMMAND_PROTOTYPE(doblobs);
277
278
279
280
COMMAND_PROTOTYPE(dostartcmd);
COMMAND_PROTOTYPE(dostartstat);
COMMAND_PROTOTYPE(doready);
COMMAND_PROTOTYPE(doreadycount);
281
COMMAND_PROTOTYPE(dostorageconfig);
282
COMMAND_PROTOTYPE(domounts);
Austin Clements's avatar
Austin Clements committed
283
COMMAND_PROTOTYPE(dosfshostid);
284
285
286
287
288
289
290
COMMAND_PROTOTYPE(doloadinfo);
COMMAND_PROTOTYPE(doreset);
COMMAND_PROTOTYPE(dorouting);
COMMAND_PROTOTYPE(dotrafgens);
COMMAND_PROTOTYPE(donseconfigs);
COMMAND_PROTOTYPE(dostate);
COMMAND_PROTOTYPE(docreator);
291
COMMAND_PROTOTYPE(dotunnels);
292
COMMAND_PROTOTYPE(dovnodelist);
293
COMMAND_PROTOTYPE(dosubnodelist);
294
COMMAND_PROTOTYPE(doisalive);
295
COMMAND_PROTOTYPE(doipodinfo);
296
297
COMMAND_PROTOTYPE(dontpinfo);
COMMAND_PROTOTYPE(dontpdrift);
298
COMMAND_PROTOTYPE(dojailconfig);
299
COMMAND_PROTOTYPE(doplabconfig);
300
301
COMMAND_PROTOTYPE(dosubconfig);
COMMAND_PROTOTYPE(doixpconfig);
302
COMMAND_PROTOTYPE(doslothdparams);
303
COMMAND_PROTOTYPE(doprogagents);
304
COMMAND_PROTOTYPE(dosyncserver);
305
COMMAND_PROTOTYPE(dokeyhash);
306
COMMAND_PROTOTYPE(doeventkey);
307
COMMAND_PROTOTYPE(dofullconfig);
308
309
COMMAND_PROTOTYPE(doroutelist);
COMMAND_PROTOTYPE(dorole);
310
COMMAND_PROTOTYPE(dorusage);
311
COMMAND_PROTOTYPE(dodoginfo);
Mike Hibler's avatar
Mike Hibler committed
312
COMMAND_PROTOTYPE(dohostkeys);
Mike Hibler's avatar
Mike Hibler committed
313
COMMAND_PROTOTYPE(dotmcctest);
314
COMMAND_PROTOTYPE(dofwinfo);
315
COMMAND_PROTOTYPE(dohostinfo);
316
COMMAND_PROTOTYPE(doemulabconfig);
317
COMMAND_PROTOTYPE(doeplabconfig);
318
COMMAND_PROTOTYPE(dolocalize);
319
COMMAND_PROTOTYPE(dorootpswd);
320
321
COMMAND_PROTOTYPE(dobooterrno);
COMMAND_PROTOTYPE(dobootlog);
Timothy Stack's avatar
   
Timothy Stack committed
322
COMMAND_PROTOTYPE(dobattery);
323
COMMAND_PROTOTYPE(dotopomap);
Timothy Stack's avatar
   
Timothy Stack committed
324
COMMAND_PROTOTYPE(douserenv);
Timothy Stack's avatar
   
Timothy Stack committed
325
326
COMMAND_PROTOTYPE(dotiptunnels);
COMMAND_PROTOTYPE(dorelayconfig);
327
COMMAND_PROTOTYPE(dotraceconfig);
328
COMMAND_PROTOTYPE(doltmap);
329
COMMAND_PROTOTYPE(doltpmap);
Kirk Webb's avatar
   
Kirk Webb committed
330
COMMAND_PROTOTYPE(doelvindport);
Kirk Webb's avatar
   
Kirk Webb committed
331
COMMAND_PROTOTYPE(doplabeventkeys);
332
COMMAND_PROTOTYPE(dointfcmap);
333
COMMAND_PROTOTYPE(domotelog);
334
COMMAND_PROTOTYPE(doportregister);
Leigh B. Stoller's avatar
Leigh B. Stoller committed
335
COMMAND_PROTOTYPE(dobootwhat);
336
337
COMMAND_PROTOTYPE(dotpmblob);
COMMAND_PROTOTYPE(dotpmpubkey);
338
COMMAND_PROTOTYPE(dotpmdummy);
339
COMMAND_PROTOTYPE(dodhcpdconf);
340
COMMAND_PROTOTYPE(dosecurestate);
341
COMMAND_PROTOTYPE(doquoteprep);
342
COMMAND_PROTOTYPE(doimagekey);
343
COMMAND_PROTOTYPE(donodeattributes);
344
COMMAND_PROTOTYPE(dodisks);
345
COMMAND_PROTOTYPE(doarpinfo);
Mike Hibler's avatar
Mike Hibler committed
346
COMMAND_PROTOTYPE(dohwinfo);
347

348
349
/*
 * The fullconfig slot determines what routines get called when pushing
350
 * out a full configuration. Physnodes get slightly different
351
 * than vnodes, and at some point we might want to distinguish different
352
353
354
355
356
 * types of vnodes (jailed, plab).
 */
#define FULLCONFIG_NONE		0x0
#define FULLCONFIG_PHYS		0x1
#define FULLCONFIG_VIRT		0x2
357
358
359
360
361
#define FULLCONFIG_ALL		(FULLCONFIG_PHYS|FULLCONFIG_VIRT)

/*
 * Flags encode a few other random properties of commands
 */
362
363
364
365
366
#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 */
367
#define F_REMREQSSL	0x20	/* remote nodes must connect with SSL */
368
#define F_REQTPM	0x40	/* require TPM on client */
369

370
371
struct command {
	char	*cmdname;
372
	int	fullconfig;
373
	int	flags;
374
	int    (*func)(int, tmcdreq_t *, char *, int, int);
375
} command_array[] = {
376
377
	{ "reboot",	  FULLCONFIG_NONE, 0, doreboot },
	{ "nodeid",	  FULLCONFIG_ALL,  0, donodeid },
378
	{ "nodeuuid",	  FULLCONFIG_ALL,  0, donodeuuid },
David Johnson's avatar
David Johnson committed
379
	{ "manifest",	  FULLCONFIG_ALL,  0, domanifest },
380
	{ "status",	  FULLCONFIG_NONE, 0, dostatus },
381
	{ "ifconfig",	  FULLCONFIG_ALL,  F_ALLOCATED, doifconfig },
382
	{ "accounts",	  FULLCONFIG_ALL,  F_REMREQSSL, doaccounts },
383
	{ "delay",	  FULLCONFIG_ALL,  F_ALLOCATED, dodelay },
384
	{ "bridges",	  FULLCONFIG_ALL,  F_ALLOCATED, dobridges },
385
386
387
388
389
	{ "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 },
390
	{ "blobs",	  FULLCONFIG_ALL,  F_ALLOCATED, doblobs },
391
392
	{ "startupcmd",	  FULLCONFIG_ALL,  F_ALLOCATED, dostartcmd },
	{ "startstatus",  FULLCONFIG_NONE, F_ALLOCATED, dostartstat }, /* Before startstat*/
393
	{ "startstat",	  FULLCONFIG_NONE, 0, dostartstat },
394
395
	{ "readycount",   FULLCONFIG_NONE, F_ALLOCATED, doreadycount },
	{ "ready",	  FULLCONFIG_NONE, F_ALLOCATED, doready },
396
	{ "storageconfig", FULLCONFIG_ALL, F_ALLOCATED, dostorageconfig},
397
398
	{ "mounts",	  FULLCONFIG_ALL,  F_ALLOCATED, domounts },
	{ "sfshostid",	  FULLCONFIG_NONE, F_ALLOCATED, dosfshostid },
399
400
	{ "loadinfo",	  FULLCONFIG_NONE, 0, doloadinfo},
	{ "reset",	  FULLCONFIG_NONE, 0, doreset},
401
402
403
404
	{ "routing",	  FULLCONFIG_ALL,  F_ALLOCATED, dorouting},
	{ "trafgens",	  FULLCONFIG_ALL,  F_ALLOCATED, dotrafgens},
	{ "nseconfigs",	  FULLCONFIG_ALL,  F_ALLOCATED, donseconfigs},
	{ "creator",	  FULLCONFIG_ALL,  F_ALLOCATED, docreator},
405
	{ "state",	  FULLCONFIG_NONE, 0, dostate},
406
	{ "tunnels",	  FULLCONFIG_ALL,  F_ALLOCATED, dotunnels},
407
	{ "vnodelist",	  FULLCONFIG_PHYS, 0, dovnodelist},
Timothy Stack's avatar
   
Timothy Stack committed
408
	{ "subnodelist",  FULLCONFIG_PHYS, 0, dosubnodelist},
409
	{ "isalive",	  FULLCONFIG_NONE, F_REMUDP|F_MINLOG, doisalive},
410
	{ "ipodinfo",	  FULLCONFIG_PHYS, 0, doipodinfo},
411
412
	{ "ntpinfo",	  FULLCONFIG_PHYS, 0, dontpinfo},
	{ "ntpdrift",	  FULLCONFIG_NONE, 0, dontpdrift},
413
414
	{ "jailconfig",	  FULLCONFIG_VIRT, F_ALLOCATED, dojailconfig},
	{ "plabconfig",	  FULLCONFIG_VIRT, F_ALLOCATED, doplabconfig},
Timothy Stack's avatar
   
Timothy Stack committed
415
	{ "subconfig",	  FULLCONFIG_NONE, 0, dosubconfig},
416
        { "sdparams",     FULLCONFIG_PHYS, 0, doslothdparams},
417
418
        { "programs",     FULLCONFIG_ALL,  F_ALLOCATED, doprogagents},
        { "syncserver",   FULLCONFIG_ALL,  F_ALLOCATED, dosyncserver},
419
        { "keyhash",      FULLCONFIG_ALL,  F_ALLOCATED|F_REMREQSSL, dokeyhash},
420
        { "eventkey",     FULLCONFIG_ALL,  F_ALLOCATED|F_REMREQSSL, doeventkey},
421
422
423
        { "fullconfig",   FULLCONFIG_NONE, F_ALLOCATED, dofullconfig},
        { "routelist",	  FULLCONFIG_PHYS, F_ALLOCATED, doroutelist},
        { "role",	  FULLCONFIG_PHYS, F_ALLOCATED, dorole},
424
        { "rusage",	  FULLCONFIG_NONE, F_REMUDP|F_MINLOG, dorusage},
425
        { "watchdoginfo", FULLCONFIG_ALL,  F_REMUDP|F_MINLOG, dodoginfo},
Mike Hibler's avatar
Mike Hibler committed
426
        { "hostkeys",     FULLCONFIG_NONE, 0, dohostkeys},
Mike Hibler's avatar
Mike Hibler committed
427
        { "tmcctest",     FULLCONFIG_NONE, F_MINLOG, dotmcctest},
428
        { "firewallinfo", FULLCONFIG_ALL,  0, dofwinfo},
429
        { "hostinfo",     FULLCONFIG_NONE, 0, dohostinfo},
430
	{ "emulabconfig", FULLCONFIG_NONE, F_ALLOCATED, doemulabconfig},
431
	{ "eplabconfig",  FULLCONFIG_NONE, F_ALLOCATED, doeplabconfig},
432
	{ "localization", FULLCONFIG_PHYS, 0, dolocalize},
433
	{ "rootpswd",     FULLCONFIG_NONE, F_REMREQSSL, dorootpswd},
434
435
	{ "booterrno",    FULLCONFIG_NONE, 0, dobooterrno},
	{ "bootlog",      FULLCONFIG_NONE, 0, dobootlog},
Timothy Stack's avatar
   
Timothy Stack committed
436
	{ "battery",      FULLCONFIG_NONE, F_REMUDP|F_MINLOG, dobattery},
437
	{ "topomap",      FULLCONFIG_NONE, F_MINLOG|F_ALLOCATED, dotopomap},
438
	{ "userenv",      FULLCONFIG_ALL,  F_ALLOCATED, douserenv},
Timothy Stack's avatar
   
Timothy Stack committed
439
	{ "tiptunnels",	  FULLCONFIG_ALL,  F_ALLOCATED, dotiptunnels},
440
	{ "traceinfo",	  FULLCONFIG_ALL,  F_ALLOCATED, dotraceconfig },
Kirk Webb's avatar
   
Kirk Webb committed
441
	{ "ltmap",        FULLCONFIG_NONE, F_MINLOG|F_ALLOCATED, doltmap},
442
	{ "ltpmap",       FULLCONFIG_NONE, F_MINLOG|F_ALLOCATED, doltpmap},
Kirk Webb's avatar
   
Kirk Webb committed
443
	{ "elvindport",   FULLCONFIG_NONE, 0, doelvindport},
444
	{ "plabeventkeys",FULLCONFIG_NONE, F_REMREQSSL, doplabeventkeys},
445
	{ "intfcmap",     FULLCONFIG_NONE, 0, dointfcmap},
446
447
	{ "motelog",      FULLCONFIG_ALL,  F_ALLOCATED, domotelog},
	{ "portregister", FULLCONFIG_NONE, F_REMNOSSL, doportregister},
Leigh B. Stoller's avatar
Leigh B. Stoller committed
448
	{ "bootwhat",	  FULLCONFIG_NONE, 0, dobootwhat },
449
450
	{ "tpmblob",	  FULLCONFIG_ALL, 0, dotpmblob },
	{ "tpmpubkey",	  FULLCONFIG_ALL, 0, dotpmpubkey },
451
	{ "tpmdummy",	  FULLCONFIG_ALL, F_REQTPM, dotpmdummy },
452
	{ "dhcpdconf",	  FULLCONFIG_ALL, 0, dodhcpdconf },
453
454
	{ "securestate",  FULLCONFIG_NONE, F_REMREQSSL, dosecurestate},
	{ "quoteprep",    FULLCONFIG_NONE, F_REMREQSSL, doquoteprep},
455
	{ "imagekey",     FULLCONFIG_NONE, F_REQTPM, doimagekey},
456
	{ "nodeattributes", FULLCONFIG_ALL, 0, donodeattributes},
457
	{ "disks",	  FULLCONFIG_ALL, 0, dodisks},
458
	{ "arpinfo",	  FULLCONFIG_NONE, 0, doarpinfo},
Mike Hibler's avatar
Mike Hibler committed
459
	{ "hwinfo",	  FULLCONFIG_NONE, 0, dohwinfo},
460
461
462
};
static int numcommands = sizeof(command_array)/sizeof(struct command);

463
char *usagestr =
464
465
466
 "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"
467
 " -c num	   Specify number of servers (must be %d <= x <= %d)\n"
468
 " -v              More verbose logging\n"
469
 " -i ipaddr       Sets the boss IP addr to return (for multi-homed servers)\n"
470
471
472
473
474
 "\n";

void
usage()
{
475
	fprintf(stderr, usagestr, MINCHILDREN, MAXCHILDREN);
476
477
478
	exit(1);
}

479
480
481
482
483
static void
cleanup()
{
	signal(SIGHUP, SIG_IGN);
	killme = 1;
484
	killpg(0, SIGHUP);
Leigh B Stoller's avatar
Leigh B Stoller committed
485
	unlink(pidfile);
486
487
}

488
489
490
491
static void
setverbose(int sig)
{
	signal(sig, SIG_IGN);
492

493
494
495
496
	if (sig == SIGUSR1)
		verbose = 1;
	else
		verbose = 0;
497
498
	info("verbose logging turned %s\n", verbose ? "on" : "off");

499
500
501
502
503
504
	/* Just the parent sends this */
	if (numchildren)
		killpg(0, sig);
	signal(sig, setverbose);
}

Mike Hibler's avatar
Mike Hibler committed
505
506
int
main(int argc, char **argv)
507
{
508
	int			tcpsock, udpsock, i, ch;
509
510
511
	int			alttcpsock, altudpsock;
	int			status, pid;
	int			portnum = TBSERVER_PORT;
512
513
	FILE			*fp;
	char			buf[BUFSIZ];
514
	struct hostent		*he;
515
	extern char		build_info[];
516
517
518
519
520
	int			server_counts[4]; /* udp,tcp,altudp,alttcp */
	struct {
		int	pid;
		int	which;
	} servers[MAXCHILDREN];
521

522
	while ((ch = getopt(argc, argv, "dp:c:Xvi:")) != -1)
523
524
525
526
527
528
		switch(ch) {
		case 'p':
			portnum = atoi(optarg);
			break;
		case 'd':
			debug++;
529
			break;
530
531
532
		case 'c':
			maxchildren = atoi(optarg);
			break;
533
534
535
		case 'X':
			insecure = 1;
			break;
536
537
538
		case 'v':
			verbose++;
			break;
539
540
541
542
543
544
545
		case 'i':
			if (inet_aton(optarg, &myipaddr) == 0) {
				fprintf(stderr, "invalid IP address %s\n",
					optarg);
				usage();
			}
			break;
546
547
548
549
550
551
552
553
554
555
		case 'h':
		case '?':
		default:
			usage();
		}
	argc -= optind;
	argv += optind;

	if (argc)
		usage();
556
557
	if (maxchildren < MINCHILDREN || maxchildren > MAXCHILDREN)
		usage();
558

559
560
561
562
563
564
#ifdef  WITHSSL
	if (tmcd_server_sslinit()) {
		error("SSL init failed!\n");
		exit(1);
	}
#endif
565
	if (debug)
566
567
568
		loginit(0, 0);
	else {
		/* Become a daemon */
569
570
571
572
573
		if (chdir(TBCOREDIR)) {
			daemon(0, 0);
		} else {
			daemon(1, 0);
		}
574
575
576
577
		loginit(1, "tmcd");
	}
	info("daemon starting (version %d)\n", CURRENT_VERSION);
	info("%s\n", build_info);
Mike Hibler's avatar
Mike Hibler committed
578

Austin Clements's avatar
Austin Clements committed
579
580
581
582
583
584
585
586
587
588
589
590
591
592
	/*
	 * 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;
593
594
595
				if (debug) {
				    info("fshostid: %s\n", fshostid);
				}
Austin Clements's avatar
Austin Clements committed
596
597
598
599
600
601
602
603
			}
			else {
				error("fshostid from %s may be corrupt: %s",
				      FSHOSTID, fshostid);
			}
			fclose(fp);
		}
	}
604

605
606
607
	/*
	 * Grab our IP for security check below.
	 */
608
	if (myipaddr.s_addr == 0) {
609
#ifdef	LBS
610
		strcpy(buf, BOSSNODE);
611
#else
612
613
		if (gethostname(buf, sizeof(buf)) < 0)
			pfatal("getting hostname");
614
#endif
615
616
617
618
619
620
		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);
621
622
	}

623
	/*
624
	 * If we were given a port on the command line, don't open the
625
626
627
628
	 * alternate ports
	 */
	if (portnum != TBSERVER_PORT) {
	    if (makesockets(portnum, &udpsock, &tcpsock) < 0) {
629
630
		error("Could not make sockets!");
		exit(1);
631
	    }
632
	    num_alttcpservers = num_altudpservers = 0;
633
634
635
636
637
638
	} else {
	    if (makesockets(portnum, &udpsock, &tcpsock) < 0 ||
		makesockets(TBSERVER_PORT2, &altudpsock, &alttcpsock) < 0) {
		    error("Could not make sockets!");
		    exit(1);
	    }
639
640
	}

Mike Hibler's avatar
Mike Hibler committed
641
642
643
644
645
646
647
648
649
650
651
652
653
	/*
	 * 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;

654
655
656
	signal(SIGTERM, cleanup);
	signal(SIGINT, cleanup);
	signal(SIGHUP, cleanup);
657
658
	signal(SIGUSR1, setverbose);
	signal(SIGUSR2, setverbose);
659
660
661
662

	/*
	 * Stash the pid away.
	 */
663
	mypid = getpid();
Leigh B Stoller's avatar
Leigh B Stoller committed
664
665
	sprintf(pidfile, "%s/tmcd.pid", _PATH_VARRUN);
	fp = fopen(pidfile, "w");
666
	if (fp != NULL) {
667
		fprintf(fp, "%d\n", mypid);
668
669
670
		(void) fclose(fp);
	}

671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
	/*
	 * 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);
	}

704
705
	/*
	 * Now fork a set of children to handle requests. We keep the
706
707
708
709
710
711
712
	 * 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!
713
	 */
714
715
716
717
718
719
	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));
720

721
722
	while (1) {
		while (!killme && numchildren < maxchildren) {
723
			int which = 3;
724

725
726
727
728
729
730
731
732
			/*
			 * Find which kind of server is short one.
			 */
			for (i = 0; i < 4; i++) {
				if (server_counts[i]) {
					which = i;
					break;
				}
733
			}
734

735
736
737
738
739
			if ((pid = fork()) < 0) {
				errorc("forking server");
				goto done;
			}
			if (pid) {
740
741
742
743
744
745
746
747
748
749
				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;
750
751
752
				numchildren++;
				continue;
			}
753
754
755
			/* Poor way of knowing parent/child */
			numchildren = 0;
			mypid = getpid();
756

757
758
759
760
			/* Child does useful work! Never Returns! */
			signal(SIGTERM, SIG_DFL);
			signal(SIGINT, SIG_DFL);
			signal(SIGHUP, SIG_DFL);
761

762
			switch (which) {
763
			case 0: udpserver(udpsock, portnum);
764
				break;
765
			case 1: udpserver(altudpsock, TBSERVER_PORT2);
766
				break;
767
			case 2: tcpserver(alttcpsock, TBSERVER_PORT2);
768
				break;
769
			case 3: tcpserver(tcpsock, portnum);
770
771
772
773
774
775
776
777
778
779
780
781
				break;
			}
			exit(-1);
		}

		/*
		 * Parent waits.
		 */
		pid = waitpid(-1, &status, 0);
		if (pid < 0) {
			errorc("waitpid failed");
			continue;
782
		}
783
784
785
		if (WIFSIGNALED(status)) {
			error("server %d exited with signal %d!\n",
			      pid, WTERMSIG(status));
786
		}
787
788
		else if (WIFEXITED(status)) {
			error("server %d exited with status %d!\n",
789
			      pid, WEXITSTATUS(status));
790
		}
791
		numchildren--;
792
793
794
795
796
797
798
799
800
801

		/*
		 * 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;
			}
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
		}
		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
820
821
	socklen_t		length;
	int			i, udpsock, tcpsock;
822

Mike Hibler's avatar
Mike Hibler committed
823
	/*
824
	 * Setup TCP socket for incoming connections.
Mike Hibler's avatar
Mike Hibler committed
825
826
	 */

827
	/* Create socket from which to read. */
Mike Hibler's avatar
Mike Hibler committed
828
829
	tcpsock = socket(AF_INET, SOCK_STREAM, 0);
	if (tcpsock < 0) {
830
		pfatal("opening stream socket");
831
832
	}

833
	i = 1;
Mike Hibler's avatar
Mike Hibler committed
834
	if (setsockopt(tcpsock, SOL_SOCKET, SO_REUSEADDR,
835
		       (char *)&i, sizeof(i)) < 0)
836
		pwarning("setsockopt(SO_REUSEADDR)");;
837

838
839
840
	/* Create name. */
	name.sin_family = AF_INET;
	name.sin_addr.s_addr = INADDR_ANY;
841
	name.sin_port = htons((u_short) portnum);
Mike Hibler's avatar
Mike Hibler committed
842
	if (bind(tcpsock, (struct sockaddr *) &name, sizeof(name))) {
843
		pfatal("binding stream socket");
844
845
846
	}
	/* Find assigned port value and print it out. */
	length = sizeof(name);
Mike Hibler's avatar
Mike Hibler committed
847
	if (getsockname(tcpsock, (struct sockaddr *) &name, &length)) {
848
		pfatal("getsockname");
849
	}
850
	if (listen(tcpsock, 128) < 0) {
851
		pfatal("listen");
852
	}
853
	info("listening on TCP port %d\n", ntohs(name.sin_port));
854

Mike Hibler's avatar
Mike Hibler committed
855
856
857
858
859
860
861
	/*
	 * Setup UDP socket
	 */

	/* Create socket from which to read. */
	udpsock = socket(AF_INET, SOCK_DGRAM, 0);
	if (udpsock < 0) {
862
		pfatal("opening dgram socket");
Mike Hibler's avatar
Mike Hibler committed
863
864
865
866
867
	}

	i = 1;
	if (setsockopt(udpsock, SOL_SOCKET, SO_REUSEADDR,
		       (char *)&i, sizeof(i)) < 0)
868
		pwarning("setsockopt(SO_REUSEADDR)");;
869
870
871
872

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

Mike Hibler's avatar
Mike Hibler committed
874
875
876
	/* Create name. */
	name.sin_family = AF_INET;
	name.sin_addr.s_addr = INADDR_ANY;
877
	name.sin_port = htons((u_short) portnum);
Mike Hibler's avatar
Mike Hibler committed
878
	if (bind(udpsock, (struct sockaddr *) &name, sizeof(name))) {
879
		pfatal("binding dgram socket");
Mike Hibler's avatar
Mike Hibler committed
880
881
882
883
884
	}

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

889
890
891
	*tcpsockp = tcpsock;
	*udpsockp = udpsock;
	return 0;
892
}
893

894
/*
895
 * Listen for UDP requests. This is not a secure channel, and so this should
896
897
898
 * eventually be killed off.
 */
static void
899
udpserver(int sock, int portnum)
900
901
902
{
	char			buf[MYBUFSIZE];
	struct sockaddr_in	client;
Mike Hibler's avatar
lint    
Mike Hibler committed
903
904
	socklen_t		length;
	int			cc;
905
	unsigned int		nreq = 0;
906

907
908
	info("udpserver starting: pid=%d sock=%d portnum=%d\n",
	     mypid, sock, portnum);
909
910
911
912
913

	/*
	 * Wait for udp connections.
	 */
	while (1) {
914
		setproctitle("UDP %d: %u done", portnum, nreq);
915
		length = sizeof(client);
916
		cc = recvfrom(sock, buf, sizeof(buf) - 1,
917
918
919
			      0, (struct sockaddr *)&client, &length);
		if (cc <= 0) {
			if (cc < 0)
920
921
				errorc("Reading UDP request");
			error("UDP Connection aborted\n");
922
			continue;
923
		}
924
925
		buf[cc] = '\0';
		handle_request(sock, &client, buf, 0);
926
		nreq++;
927
928
929
930
	}
	exit(1);
}

931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
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;
}

957
/*
958
 * Listen for TCP requests.
959
960
 */
static void
961
tcpserver(int sock, int portnum)
962
{
963
	char			buf[MAXTMCDPACKET];
964
	struct sockaddr_in	client;
Mike Hibler's avatar
lint    
Mike Hibler committed
965
966
	socklen_t		length;
	int			cc, newsock;
967
	unsigned int		nreq = 0;
968
	struct timeval		tv;
969

970
971
	info("tcpserver starting: pid=%d sock=%d portnum=%d\n",
	     mypid, sock, portnum);
972
973
974
975
976

	/*
	 * Wait for TCP connections.
	 */
	while (1) {
977
		setproctitle("TCP %d: %u done", portnum, nreq);
978
		length  = sizeof(client);
979
980
		newsock = ACCEPT(sock, (struct sockaddr *)&client, &length,
				 readtimo);
981
		if (newsock < 0) {
982
			errorc("accepting TCP connection");
983
			continue;
984
		}
Mike Hibler's avatar
Mike Hibler committed
985

986
987
988
989
990
991
992
993
994
995
996
997
998
999
		/*
		 * 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
1000
		/*