1 /*
2 	master.c
3 
4 	A master server for Tremulous
5 
6 	Copyright (C) 2002-2005  Mathieu Olivier
7 
8 	This program is free software; you can redistribute it and/or modify
9 	it under the terms of the GNU General Public License as published by
10 	the Free Software Foundation; either version 2 of the License, or
11 	(at your option) any later version.
12 
13 	This program is distributed in the hope that it will be useful,
14 	but WITHOUT ANY WARRANTY; without even the implied warranty of
15 	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 	GNU General Public License for more details.
17 
18 	You should have received a copy of the GNU General Public License
19 	along with this program; if not, write to the Free Software
20 	Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21 */
22 
23 
24 #include <stdarg.h>
25 #include <signal.h>
26 
27 #ifndef WIN32
28 # include <pwd.h>
29 # include <unistd.h>
30 #endif
31 
32 #include "common.h"
33 #include "messages.h"
34 #include "servers.h"
35 
36 
37 // ---------- Constants ---------- //
38 
39 // Version of dpmaster
40 #define VERSION "1.6"
41 
42 // Default master port
43 #define DEFAULT_MASTER_PORT 30710
44 
45 // Maximum and minimum sizes for a valid packet
46 #define MAX_PACKET_SIZE 2048
47 #define MIN_PACKET_SIZE 5
48 
49 #ifndef WIN32
50 // Default path we use for chroot
51 # define DEFAULT_JAIL_PATH "/var/empty/"
52 
53 // User we use by default for dropping super-user privileges
54 # define DEFAULT_LOW_PRIV_USER "nobody"
55 #endif
56 
57 
58 // ---------- Types ---------- //
59 
60 #ifdef WIN32
61 typedef int socklen_t;
62 #endif
63 
64 
65 // ---------- Private variables ---------- //
66 
67 // The port we use
68 static unsigned short master_port = DEFAULT_MASTER_PORT;
69 
70 // Local address we listen on, if any
71 static const char* listen_name = NULL;
72 static struct in_addr listen_addr;
73 
74 #ifndef WIN32
75 // On UNIX systems, we can run as a daemon
76 static qboolean daemon_mode = qfalse;
77 
78 // Path we use for chroot
79 static const char* jail_path = DEFAULT_JAIL_PATH;
80 
81 // Low privileges user
82 static const char* low_priv_user = DEFAULT_LOW_PRIV_USER;
83 #endif
84 
85 
86 // ---------- Public variables ---------- //
87 
88 // The master socket
89 int sock = -1;
90 
91 // The current time (updated every time we receive a packet)
92 time_t crt_time;
93 
94 // Maximum level for a message to be printed
95 msg_level_t max_msg_level = MSG_NORMAL;
96 
97 // Peer address. We rebuild it every time we receive a new packet
98 char peer_address [128];
99 
100 
101 // ---------- Private functions ---------- //
102 
103 /*
104 ====================
105 PrintPacket
106 
107 Print the contents of a packet on stdout
108 ====================
109 */
PrintPacket(const char * packet,size_t length)110 static void PrintPacket (const char* packet, size_t length)
111 {
112 	size_t i;
113 
114 	// Exceptionally, we use MSG_NOPRINT here because if the function is
115 	// called, the user probably wants this text to be displayed
116 	// whatever the maximum message level is.
117 	MsgPrint (MSG_NOPRINT, "\"");
118 
119 	for (i = 0; i < length; i++)
120 	{
121 		char c = packet[i];
122 		if (c == '\\')
123 			MsgPrint (MSG_NOPRINT, "\\\\");
124 		else if (c == '\"')
125 			MsgPrint (MSG_NOPRINT, "\"");
126 		else if (c >= 32 && (qbyte)c <= 127)
127 		 	MsgPrint (MSG_NOPRINT, "%c", c);
128 		else
129 			MsgPrint (MSG_NOPRINT, "\\x%02X", c);
130 	}
131 
132 	MsgPrint (MSG_NOPRINT, "\" (%u bytes)\n", length);
133 }
134 
135 
136 /*
137 ====================
138 SysInit
139 
140 System dependent initializations
141 ====================
142 */
SysInit(void)143 static qboolean SysInit (void)
144 {
145 #ifdef WIN32
146 	WSADATA winsockdata;
147 
148 	if (WSAStartup (MAKEWORD (1, 1), &winsockdata))
149 	{
150 		MsgPrint (MSG_ERROR, "ERROR: can't initialize winsocks\n");
151 		return qfalse;
152 	}
153 #endif
154 
155 	return qtrue;
156 }
157 
158 
159 /*
160 ====================
161 UnsecureInit
162 
163 System independent initializations, called BEFORE the security initializations.
164 We need this intermediate step because DNS requests may not be able to resolve
165 after the security initializations, due to chroot.
166 ====================
167 */
UnsecureInit(void)168 static qboolean UnsecureInit (void)
169 {
170 	// Resolve the address mapping list
171 	if (! Sv_ResolveAddressMappings ())
172 		return qfalse;
173 
174 	// Resolve the listen address if one was specified
175 	if (listen_name != NULL)
176 	{
177 		struct hostent* itf;
178 
179 		itf = gethostbyname (listen_name);
180 		if (itf == NULL)
181 		{
182 			MsgPrint (MSG_ERROR, "ERROR: can't resolve %s\n", listen_name);
183 			return qfalse;
184 		}
185 		if (itf->h_addrtype != AF_INET)
186 		{
187 			MsgPrint (MSG_ERROR, "ERROR: %s is not an IPv4 address\n",
188 					  listen_name);
189 			return qfalse;
190 		}
191 
192 		memcpy (&listen_addr.s_addr, itf->h_addr,
193 				sizeof (listen_addr.s_addr));
194 	}
195 
196 	return qtrue;
197 }
198 
199 
200 /*
201 ====================
202 SecInit
203 
204 Security initializations (system dependent)
205 ====================
206 */
SecInit(void)207 static qboolean SecInit (void)
208 {
209 #ifndef WIN32
210 	// Should we run as a daemon?
211 	if (daemon_mode && daemon (0, 0))
212 	{
213 		MsgPrint (MSG_NOPRINT, "ERROR: daemonization failed (%s)\n",
214 				  strerror (errno));
215 		return qfalse;
216 	}
217 
218 	// UNIX allows us to be completely paranoid, so let's go for it
219 	if (geteuid () == 0)
220 	{
221 		struct passwd* pw;
222 
223 		MsgPrint (MSG_WARNING,
224 				  "WARNING: running with super-user privileges\n");
225 
226 		// We must get the account infos before the calls to chroot and chdir
227 		pw = getpwnam (low_priv_user);
228 		if (pw == NULL)
229 		{
230 			MsgPrint (MSG_ERROR, "ERROR: can't get user \"%s\" properties\n",
231 					  low_priv_user);
232 			return qfalse;
233 		}
234 
235 		// Chroot ourself
236 		MsgPrint (MSG_NORMAL, "  - chrooting myself to %s... ", jail_path);
237 		if (chroot (jail_path) || chdir ("/"))
238 		{
239 			MsgPrint (MSG_ERROR, "FAILED (%s)\n", strerror (errno));
240 			return qfalse;
241 		}
242 		MsgPrint (MSG_NORMAL, "succeeded\n");
243 
244 		// Switch to lower privileges
245 		MsgPrint (MSG_NORMAL, "  - switching to user \"%s\" privileges... ",
246 				  low_priv_user);
247 		if (setgid (pw->pw_gid) || setuid (pw->pw_uid))
248 		{
249 			MsgPrint (MSG_ERROR, "FAILED (%s)\n", strerror (errno));
250 			return qfalse;
251 		}
252 		MsgPrint (MSG_NORMAL, "succeeded (UID: %u, GID: %u)\n",
253 				  pw->pw_uid, pw->pw_gid);
254 
255 		MsgPrint (MSG_NORMAL, "\n");
256 	}
257 #endif
258 
259 	return qtrue;
260 }
261 
262 
263 /*
264 ====================
265 ParseCommandLine
266 
267 Parse the options passed by the command line
268 ====================
269 */
ParseCommandLine(int argc,const char * argv[])270 static qboolean ParseCommandLine (int argc, const char* argv [])
271 {
272 	int ind = 1;
273 	unsigned int vlevel = max_msg_level;
274 	qboolean valid_options = qtrue;
275 
276 	while (ind < argc && valid_options)
277 	{
278 		// If it doesn't even look like an option, why bother?
279 		if (argv[ind][0] != '-')
280 			valid_options = qfalse;
281 
282 		else switch (argv[ind][1])
283 		{
284 #ifndef WIN32
285 			// Daemon mode
286 			case 'D':
287 				daemon_mode = qtrue;
288 				break;
289 #endif
290 
291 			// Help
292 			case 'h':
293 				valid_options = qfalse;
294 				break;
295 
296 			// Hash size
297 			case 'H':
298 				ind++;
299 				if (ind < argc)
300 					valid_options = Sv_SetHashSize (atoi (argv[ind]));
301 				else
302 					valid_options = qfalse;
303 				break;
304 
305 #ifndef WIN32
306 			// Jail path
307 			case 'j':
308 				ind++;
309 				if (ind < argc)
310 					jail_path = argv[ind];
311 				else
312 					valid_options = qfalse;
313 				break;
314 #endif
315 
316 			// Listen address
317 			case 'l':
318 				ind++;
319 				if (ind >= argc || argv[ind][0] == '\0')
320 					valid_options = qfalse;
321 				else
322 					listen_name = argv[ind];
323 				break;
324 
325 			// Address mapping
326 			case 'm':
327 				ind++;
328 				if (ind < argc)
329 					valid_options = Sv_AddAddressMapping (argv[ind]);
330 				else
331 					valid_options = qfalse;
332 				break;
333 
334 			// Maximum number of servers
335 			case 'n':
336 				ind++;
337 				if (ind < argc)
338 					valid_options = Sv_SetMaxNbServers (atoi (argv[ind]));
339 				else
340 					valid_options = qfalse;
341 				break;
342 
343 			// Port number
344 			case 'p':
345 			{
346 				unsigned short port_num = 0;
347 				ind++;
348 				if (ind < argc)
349 					port_num = atoi (argv[ind]);
350 				if (!port_num)
351 					valid_options = qfalse;
352 				else
353 					master_port = port_num;
354 				break;
355 			}
356 
357 #ifndef WIN32
358 			// Low privileges user
359 			case 'u':
360 				ind++;
361 				if (ind < argc)
362 					low_priv_user = argv[ind];
363 				else
364 					valid_options = qfalse;
365 				break;
366 #endif
367 
368 			// Verbose level
369 			case 'v':
370 				// If a verbose level has been specified
371 				if (ind + 1 < argc && argv[ind + 1][0] != '-')
372 				{
373 					ind++;
374 					vlevel = atoi (argv[ind]);
375 					if (vlevel > MSG_DEBUG)
376 						valid_options = qfalse;
377 				}
378 				else
379 					vlevel = MSG_DEBUG;
380 				break;
381 
382 			default:
383 				valid_options = qfalse;
384 		}
385 
386 		ind++;
387 	}
388 
389 	// If the command line is OK, we can set the verbose level now
390 	if (valid_options)
391 	{
392 #ifndef WIN32
393 		// If we run as a daemon, don't bother printing anything
394 		if (daemon_mode)
395 			max_msg_level = MSG_NOPRINT;
396 		else
397 #endif
398 			max_msg_level = vlevel;
399 	}
400 
401 	return valid_options;
402 }
403 
404 
405 /*
406 ====================
407 PrintHelp
408 
409 Print the command line syntax and the available options
410 ====================
411 */
PrintHelp(void)412 static void PrintHelp (void)
413 {
414 	MsgPrint (MSG_ERROR,
415 			  "Syntax: dpmaster [options]\n"
416 			  "Available options are:\n"
417 #ifndef WIN32
418 			  "  -D               : run as a daemon\n"
419 #endif
420 			  "  -h               : this help\n"
421 			  "  -H <hash_size>   : hash size in bits, up to %u (default: %u)\n"
422 #ifndef WIN32
423 			  "  -j <jail_path>   : use <jail_path> as chroot path (default: %s)\n"
424 			  "                     only available when running with super-user privileges\n"
425 #endif
426 			  "  -l <address>     : listen on local address <address>\n"
427 			  "  -m <a1>=<a2>     : map address <a1> to <a2> when sending it to clients\n"
428 			  "                     addresses can contain a port number (ex: myaddr.net:1234)\n"
429 			  "  -n <max_servers> : maximum number of servers recorded (default: %u)\n"
430 			  "  -p <port_num>    : use port <port_num> (default: %u)\n"
431 #ifndef WIN32
432 			  "  -u <user>        : use <user> privileges (default: %s)\n"
433 			  "                     only available when running with super-user privileges\n"
434 #endif
435 			  "  -v [verbose_lvl] : verbose level, up to %u (default: %u; no value means max)\n"
436 			  "\n",
437 			  MAX_HASH_SIZE, DEFAULT_HASH_SIZE,
438 #ifndef WIN32
439 			  DEFAULT_JAIL_PATH,
440 #endif
441 			  DEFAULT_MAX_NB_SERVERS,
442 			  DEFAULT_MASTER_PORT,
443 #ifndef WIN32
444 			  DEFAULT_LOW_PRIV_USER,
445 #endif
446 			  MSG_DEBUG, MSG_NORMAL);
447 }
448 
449 
450 /*
451 ====================
452 SecureInit
453 
454 System independent initializations, called AFTER the security initializations
455 ====================
456 */
SecureInit(void)457 static qboolean SecureInit (void)
458 {
459 	struct sockaddr_in address;
460 
461 	// Init the time and the random seed
462 	crt_time = time (NULL);
463 	srand (crt_time);
464 
465 	// Initialize the server list and hash table
466 	if (!Sv_Init ())
467 		return qfalse;
468 
469 	// Open the socket
470 	sock = socket (PF_INET, SOCK_DGRAM, IPPROTO_UDP);
471 	if (sock < 0)
472 	{
473 		MsgPrint (MSG_ERROR, "ERROR: socket creation failed (%s)\n",
474 				  strerror (errno));
475 		return qfalse;
476 	}
477 
478 	// Bind it to the master port
479 	memset (&address, 0, sizeof (address));
480 	address.sin_family = AF_INET;
481 	if (listen_name != NULL)
482 	{
483 		MsgPrint (MSG_NORMAL, "Listening on address %s (%s)\n",
484 				  listen_name, inet_ntoa (listen_addr));
485 		address.sin_addr.s_addr = listen_addr.s_addr;
486 	}
487 	else
488 		address.sin_addr.s_addr = htonl (INADDR_ANY);
489 	address.sin_port = htons (master_port);
490 	if (bind (sock, (struct sockaddr*)&address, sizeof (address)) != 0)
491 	{
492 		MsgPrint (MSG_ERROR, "ERROR: socket binding failed (%s)\n",
493 				  strerror (errno));
494 #ifdef WIN32
495 		closesocket (sock);
496 #else
497 		close (sock);
498 #endif
499 		return qfalse;
500 	}
501 	MsgPrint (MSG_NORMAL, "Listening on UDP port %hu\n",
502 			  ntohs (address.sin_port));
503 
504 	return qtrue;
505 }
506 
507 static qboolean exitNow = qfalse;
508 
509 /*
510 ===============
511 cleanUp
512 
513 Clean up
514 ===============
515 */
cleanUp(int signal)516 static void cleanUp( int signal )
517 {
518 	MsgPrint( MSG_NORMAL, "Caught signal %d, exiting...\n", signal );
519 
520 	exitNow = qtrue;
521 }
522 
523 /*
524 ====================
525 main
526 
527 Main function
528 ====================
529 */
main(int argc,const char * argv[])530 int main (int argc, const char* argv [])
531 {
532 	struct sockaddr_in address;
533 	socklen_t addrlen;
534 	int nb_bytes;
535 	char packet [MAX_PACKET_SIZE + 1];  // "+ 1" because we append a '\0'
536 	qboolean valid_options;
537 	fd_set rfds;
538 	struct timeval tv;
539 
540 
541 	signal( SIGINT, cleanUp );
542 	signal( SIGTERM, cleanUp );
543 
544 	// Get the options from the command line
545 	valid_options = ParseCommandLine (argc, argv);
546 
547 	MsgPrint (MSG_NORMAL,
548 			"tremmaster (version " VERSION " " __DATE__ " " __TIME__ ")\n" );
549 
550 	// If there was a mistake in the command line, print the help and exit
551 	if (!valid_options)
552 	{
553 		PrintHelp ();
554 		return EXIT_FAILURE;
555 	}
556 
557 	// Initializations
558 	if (!SysInit () || !UnsecureInit () || !SecInit () || !SecureInit ())
559 		return EXIT_FAILURE;
560 	MsgPrint (MSG_NORMAL, "\n");
561 
562 	// Until the end of times...
563 	while( !exitNow )
564 	{
565 		FD_ZERO( &rfds );
566 		FD_SET( sock, &rfds );
567 		tv.tv_sec = tv.tv_usec = 0;
568 
569 		// Check for new data every 100ms
570 		if( select( sock + 1, &rfds, NULL, NULL, &tv ) <= 0 )
571 		{
572 #ifdef _WIN32
573       Sleep( 100 );
574 #else
575 			usleep( 100000 );
576 #endif
577 			continue;
578 		}
579 
580 		// Get the next valid message
581 		addrlen = sizeof (address);
582 		nb_bytes = recvfrom (sock, packet, sizeof (packet) - 1, 0,
583 							 (struct sockaddr*)&address, &addrlen);
584 		if (nb_bytes <= 0)
585 		{
586 			MsgPrint (MSG_WARNING,
587 					  "WARNING: \"recvfrom\" returned %d\n", nb_bytes);
588 			continue;
589 		}
590 
591 		// If we may have to print something, rebuild the peer address buffer
592 		if (max_msg_level != MSG_NOPRINT)
593 			snprintf (peer_address, sizeof (peer_address), "%s:%hu",
594 					  inet_ntoa (address.sin_addr), ntohs (address.sin_port));
595 
596 		// We print the packet contents if necessary
597 		// TODO: print the current time here
598 		if (max_msg_level >= MSG_DEBUG)
599 		{
600 			MsgPrint (MSG_DEBUG, "New packet received from %s: ",
601 					  peer_address);
602 			PrintPacket (packet, nb_bytes);
603 		}
604 
605 		// A few sanity checks
606 		if (nb_bytes < MIN_PACKET_SIZE)
607 		{
608 			MsgPrint (MSG_WARNING,
609 					  "WARNING: rejected packet from %s (size = %d bytes)\n",
610 					  peer_address, nb_bytes);
611 			continue;
612 		}
613 		if (*((unsigned int*)packet) != 0xFFFFFFFF)
614 		{
615 			MsgPrint (MSG_WARNING,
616 					  "WARNING: rejected packet from %s (invalid header)\n",
617 					  peer_address);
618 			continue;
619 		}
620 		if (! ntohs (address.sin_port))
621 		{
622 			MsgPrint (MSG_WARNING,
623 					  "WARNING: rejected packet from %s (source port = 0)\n",
624 					  peer_address);
625 			continue;
626 		}
627 
628 		// Append a '\0' to make the parsing easier and update the current time
629 		packet[nb_bytes] = '\0';
630 		crt_time = time (NULL);
631 
632 		// Call HandleMessage with the remaining contents
633 		HandleMessage (packet + 4, nb_bytes - 4, &address);
634 	}
635 
636 	return 0;
637 }
638 
639 
640 // ---------- Public functions ---------- //
641 
642 /*
643 ====================
644 MsgPrint
645 
646 Print a message to screen, depending on its verbose level
647 ====================
648 */
MsgPrint(msg_level_t msg_level,const char * format,...)649 int MsgPrint (msg_level_t msg_level, const char* format, ...)
650 {
651 	va_list args;
652 	int result;
653 
654 	// If the message level is above the maximum level, don't print it
655 	if (msg_level > max_msg_level)
656 		return 0;
657 
658 	va_start (args, format);
659 	result = vprintf (format, args);
660 	va_end (args);
661 
662 	fflush (stdout);
663 
664 	return result;
665 }
666