1/*****************************************************************************
2 *
3 * saslauthd-main.c
4 *
5 * Description:  Main program source.
6 *
7 * Copyright (c) 1997-2000 Messaging Direct Ltd.
8 * All rights reserved.
9 *
10 * Portions Copyright (c) 2003 Jeremy Rumpf
11 * jrumpf@heavyload.net
12 *
13 * Redistribution and use in source and binary forms, with or without
14 * modification, are permitted provided that the following conditions
15 * are met:
16 *
17 * 1. Redistributions of source code must retain the above copyright
18 *    notice, this list of conditions and the following disclaimer.
19 *
20 * 2. Redistributions in binary form must reproduce the above copyright
21 *    notice, this list of conditions and the following disclaimer in the
22 *    documentation and/or other materials provided with the distribution.
23 *
24 * THIS SOFTWARE IS PROVIDED BY MESSAGING DIRECT LTD. ``AS IS'' AND ANY
25 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
27 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL MESSAGING DIRECT LTD. OR
28 * ITS EMPLOYEES OR AGENTS BE LIABLE FOR ANY DIRECT, INDIRECT,
29 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
30 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
31 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
32 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
33 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
34 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
35 * DAMAGE.
36 *
37 *
38 * HISTORY
39 *
40 * saslauthd is a re-implementation of the pwcheck utility included
41 * with the CMU Cyrus IMAP server circa 1997. This implementation
42 * was written by Lyndon Nerenberg of Messaging Direct Inc. (which
43 * at that time was the Esys Corporation) and was included in the
44 * company's IMAP message store product (Simeon Message Service) as
45 * the smsauthd utility.
46 *
47 * This implementation was contributed to CMU by Messaging Direct Ltd.
48 * in September 2000.
49 *
50 * September 2001 (Ken Murchison of Oceana Matrix Ltd.):
51 * - Modified the protocol to use counted length strings instead of
52 *   nul delimited strings.
53 * - Augmented the protocol to accept the service name and user realm.
54 *
55 * Feb 2003: Partial rewrite and cleanup  by Jeremy Rumpf jrumpf@heavyload.net
56 * - Merge the doors and unix IPC methods under a common framework.
57 *
58 *   OVERVIEW
59 *
60 * saslauthd provides an interface between the SASL library and various
61 * external authentication mechanisms. The primary goal is to isolate
62 * code that requires superuser privileges (for example, access to
63 * the shadow password file) into a single easily audited module. It
64 * can also act as an authentication proxy between plaintext-equivelent
65 * authentication schemes (i.e. CRAM-MD5) and more secure authentication
66 * services such as Kerberos, although such usage is STRONGLY discouraged
67 * because it exposes the strong credentials via the insecure plaintext
68 * mechanisms.
69 *
70 * The program listens for connections on a UNIX domain socket. Access to
71 * the service is controlled by the UNIX filesystem permissions on the
72 * socket.
73 *
74 * The service speaks a very simple protocol. The client connects and
75 * sends the authentication identifier, the plaintext password, the
76 * service name and user realm as counted length strings (a 16-bit
77 * unsigned integer in network byte order followed by the string
78 * itself). The server returns a single response as a counted length
79 * string. The response begins with "OK" or "NO", and is followed by
80 * an optional text string (separated from the OK/NO by a single space
81 * character), and a NUL. The server then closes the connection.
82 *
83 * An "OK" response indicates the authentication credentials are valid.
84 * A "NO" response indicates the authentication failed.
85 *
86 * The optional text string may be used to indicate an exceptional
87 * condition in the authentication environment that should be communicated
88 * to the client.
89 *
90 *****************************************************************************/
91
92#include <unistd.h>
93#include <stdlib.h>
94#include <stdio.h>
95#include <errno.h>
96#include <string.h>
97
98#ifdef _AIX
99# include <strings.h>
100#endif /* _AIX */
101
102#include <syslog.h>
103#include <signal.h>
104#include <sys/file.h>
105#include <sys/types.h>
106#include <sys/stat.h>
107#include <sys/socket.h>
108#include <sys/un.h>
109#include <sys/wait.h>
110#include <fcntl.h>
111#include <sys/uio.h>
112
113#include "globals.h"
114#include "saslauthd-main.h"
115#include "cache.h"
116#include "utils.h"
117
118/* max login + max realm + '@' */
119#define MAX_LOGIN_REALM_LEN (MAX_REQ_LEN * 2) + 1
120
121/****************************************
122 * declarations/protos
123 *****************************************/
124static void	show_version();
125static void	show_usage();
126
127/****************************************
128 * application globals
129 *****************************************/
130int		flags = 0;		/* Runtime flags                     */
131int		g_argc;			/* Copy of argc for those who need it*/
132char		**g_argv;		/* Copy of argv for those who need it*/
133char		*run_path = NULL;	/* path to our working directory     */
134authmech_t	*auth_mech = NULL;	/* Authentication mechanism to use   */
135char		*mech_option = NULL;	/* mechanism-specific option	     */
136int		num_procs = 5;		/* The max number of worker processes*/
137
138
139/****************************************
140 * module globals
141*****************************************/
142extern char 	*optarg;		/* For getopt()                          */
143static int     	master_pid;		/* Pid of the master process             */
144static int 	pid_fd;                 /* Descriptor to the open pid file       */
145static int 	pid_file_lock_fd; 		/* Descriptor to the open pid lock file  */
146static char	*pid_file;		/* Pid file name                         */
147static char	*pid_file_lock;		/* Pid lock file name                    */
148static int       startup_pipe[2] = { -1, -1 };
149
150int main(int argc, char **argv) {
151	int		option;
152	int 		rc;
153	int 		x;
154	struct flock	lockinfo;
155	char            *auth_mech_name = NULL;
156	size_t		pid_file_size;
157
158	/* XXX  force openlog() before any of our mechs try syslog() */
159	logger(L_INFO, L_FUNC, "starting %s", argv[0]);
160
161	SET_AUTH_PARAMETERS(argc, argv);
162
163	g_argc = argc;
164	g_argv = argv;
165
166	/* default flags */
167	flags |= USE_ACCEPT_LOCK;
168	flags |= DETACH_TTY;
169	flags |= LOG_USE_SYSLOG;
170	flags |= LOG_USE_STDERR;
171	flags |= AM_MASTER;
172
173	while ((option = getopt(argc, argv, "a:cdhO:lm:n:rs:t:vV")) != -1) {
174		switch(option) {
175			case 'a':
176			        /* Only one at a time, please! */
177			        if(auth_mech_name) {
178				    show_usage();
179				    break;
180				}
181
182				auth_mech_name = strdup(optarg);
183				if (!auth_mech_name) {
184				    logger(L_ERR, L_FUNC,
185					   "could not allocate memory");
186				    exit(1);
187				}
188				break;
189
190			case 'c':
191				flags |= CACHE_ENABLED;
192				break;
193
194			case 'd':
195				flags |= VERBOSE;
196				flags &= ~DETACH_TTY;
197				break;
198
199			case 'h':
200				show_usage();
201				break;
202
203			case 'O':
204				set_mech_option(optarg);
205				break;
206
207			case 'l':
208				flags &= ~USE_ACCEPT_LOCK;
209				break;
210
211			case 'm':
212				set_run_path(optarg);
213				break;
214
215			case 'n':
216				set_max_procs(optarg);
217				break;
218
219			case 'r':
220				flags |= CONCAT_LOGIN_REALM;
221				break;
222
223			case 's':
224				cache_set_table_size(optarg);
225				break;
226
227			case 't':
228				cache_set_timeout(optarg);
229				break;
230
231		        case 'V':
232				flags |= VERBOSE;
233				break;
234
235			case 'v':
236				show_version();
237				break;
238
239			default:
240				show_usage();
241				break;
242		}
243	}
244
245	if (run_path == NULL)
246    		run_path = PATH_SASLAUTHD_RUNDIR;
247
248    	if (auth_mech_name == NULL) {
249		logger(L_ERR, L_FUNC, "no authentication mechanism specified");
250		show_usage();
251		exit(1);
252	}
253
254	/* Create our working directory */
255	if (mkdir(run_path, 0755) == -1 && errno != EEXIST) {
256		logger(L_ERR, L_FUNC, "can not mkdir: %s", run_path);
257		logger(L_ERR, L_FUNC, "Check to make sure the parent directory exists and is");
258		logger(L_ERR, L_FUNC, "writeable by the user this process runs as.");
259		exit(1);
260	}
261
262	set_auth_mech(auth_mech_name);
263
264	if (flags & VERBOSE)  {
265		logger(L_DEBUG, L_FUNC, "num_procs  : %d", num_procs);
266
267		if (mech_option == NULL)
268			logger(L_DEBUG, L_FUNC, "mech_option: NULL");
269		else
270			logger(L_DEBUG, L_FUNC, "mech_option: %s", mech_option);
271
272		logger(L_DEBUG, L_FUNC, "run_path   : %s", run_path);
273		logger(L_DEBUG, L_FUNC, "auth_mech  : %s", auth_mech->name);
274	}
275
276	/*********************************************************
277	 * Change our working directory to the dir where the
278	 * run path is set to, core dumps will go there to keep
279	 * them intact.
280	 **********************************************************/
281	if (chdir(run_path) == -1) {
282		rc = errno;
283		logger(L_ERR, L_FUNC, "could not chdir to: %s", run_path);
284		logger(L_ERR, L_FUNC, "chdir: %s", strerror(rc));
285		logger(L_ERR, L_FUNC, "Check to make sure the directory exists and is");
286		logger(L_ERR, L_FUNC, "writeable by the user this process runs as.");
287		exit(1);
288	}
289
290	umask(0077);
291
292	pid_file_size = strlen(run_path) + sizeof(PID_FILE_LOCK) + 1;
293	if ((pid_file_lock = malloc(pid_file_size)) == NULL) {
294		logger(L_ERR, L_FUNC, "could not allocate memory");
295		exit(1);
296	}
297
298	strlcpy(pid_file_lock, run_path, pid_file_size);
299	strlcat(pid_file_lock, PID_FILE_LOCK, pid_file_size);
300
301	if ((pid_file_lock_fd = open(pid_file_lock, O_CREAT|O_TRUNC|O_RDWR, 0644)) < 0) {
302		rc = errno;
303		logger(L_ERR, L_FUNC, "could not open pid lock file: %s", pid_file_lock);
304		logger(L_ERR, L_FUNC, "open: %s", strerror(rc));
305		logger(L_ERR, L_FUNC,
306		       "Check to make sure the directory exists and is");
307		logger(L_ERR, L_FUNC, "writeable by the user this process runs as.");
308		exit(1);
309	}
310
311	lockinfo.l_type = F_WRLCK;
312	lockinfo.l_start = 0;
313	lockinfo.l_len = 0;
314	lockinfo.l_whence = SEEK_SET;
315
316	if (fcntl(pid_file_lock_fd, F_SETLK, &lockinfo) == -1) {
317		rc = errno;
318		logger(L_ERR, L_FUNC, "could not lock pid lock file: %s", pid_file_lock);
319		logger(L_ERR, L_FUNC, "fcntl: %s", strerror(rc));
320		exit(1);
321	}
322
323	if(pipe(startup_pipe) == -1) {
324		logger(L_ERR, L_FUNC, "can't create startup pipe");
325		exit(1);
326	}
327
328	/*********************************************************
329	 * Enable signal handlers.
330	 **********************************************************/
331	signal_setup();
332
333	/*********************************************************
334	 * Cache setup, exit if it doesn't succeed (optional would
335	 * be to disable the cache and log a warning).
336	 **********************************************************/
337	if (cache_init() != 0)
338		exit(1);
339
340	/*********************************************************
341	 * Call the ipc specific initializer. This should also
342	 * call detach_tty() at the appropriate point.
343	 **********************************************************/
344	ipc_init();
345
346	/*********************************************************
347	 * Enable general cleanup.
348	 **********************************************************/
349	atexit(server_exit);
350
351	/*********************************************************
352	 * If required, enable the process model.
353	 **********************************************************/
354	if (flags & USE_PROCESS_MODEL) {
355        	if (flags & VERBOSE)
356                	logger(L_DEBUG, L_FUNC, "using process model");
357
358        	for (x = 1; x < num_procs; x++) {
359			if (have_baby() != 0)
360				continue;		/* parent */
361
362                	break;				/* child  */
363        	}
364	}
365
366	/*********************************************************
367	 * Enter the ipc loop, we should never return.
368	 **********************************************************/
369	ipc_loop();
370
371	exit(0);
372}
373
374
375/*************************************************************
376 * Performs all authentication centric duties. We should be
377 * getting callbacks from the ipc method here. We'll simply
378 * return a pointer to a string to send back to the client.
379 * The caller is responsible for freeing the pointer.
380 **************************************************************/
381char *do_auth(const char *_login, const char *password, const char *service, const char *realm) {
382
383	struct cache_result	lkup_result;
384	char			*response;
385	int			cached = 0;
386	char			login_buff[MAX_LOGIN_REALM_LEN];
387	char			*login;
388
389
390	/***********************************************************
391	 * Check to concat the login and realm into a single login.
392	 * Aka, login: foo realm: bar becomes login: foo@bar.
393	 * We do this because some mechs have no concept of a realm.
394	 * Ie. auth_pam and friends.
395	 ***********************************************************/
396	if ((flags & CONCAT_LOGIN_REALM) && realm && realm[0] != '\0') {
397	    strlcpy(login_buff, _login, sizeof(login_buff));
398	    strlcat(login_buff, "@", sizeof(login_buff));
399	    strlcat(login_buff, realm, sizeof(login_buff));
400
401	    login = login_buff;
402	} else {
403	    login = (char *)_login;
404	}
405
406	if (cache_lookup(login, realm, service, password, &lkup_result) == CACHE_OK) {
407		response = strdup("OK");
408		cached = 1;
409	} else {
410		response = auth_mech->authenticate(login, password, service, realm);
411
412		if (response == NULL) {
413			logger(L_ERR, L_FUNC, "internal mechanism failure: %s", auth_mech->name);
414			response = strdup("NO internal mechanism failure");
415		}
416	}
417
418	if (strncmp(response, "OK", 2) == 0) {
419		cache_commit(&lkup_result);
420
421		if (flags & VERBOSE) {
422			if (cached)
423				logger(L_DEBUG, L_FUNC, "auth success (cached): [user=%s] [service=%s] [realm=%s]", \
424					login, service, realm);
425			else
426				logger(L_DEBUG, L_FUNC, "auth success: [user=%s] [service=%s] [realm=%s] [mech=%s]", \
427					login, service, realm, auth_mech->name);
428		}
429		return response;
430	}
431
432	if (strncmp(response, "NO", 2) == 0) {
433		logger(L_INFO, L_FUNC, "auth failure: [user=%s] [service=%s] [realm=%s] [mech=%s] [reason=%s]", \
434			login, service, realm, auth_mech->name,
435		        strlen(response) >= 4 ? response+3 : "Unknown");
436
437		return response;
438	}
439
440	logger(L_ERR, L_FUNC, "mechanism returned unknown response: %s", auth_mech->name);
441	response = strdup("NO internal mechanism failure");
442
443	return response;
444}
445
446
447/*************************************************************
448 * Allow someone to set the auth mech to use
449 **************************************************************/
450void set_auth_mech(const char *mech) {
451	for (auth_mech = mechanisms; auth_mech->name != NULL; auth_mech++) {
452		if (strcasecmp(auth_mech->name, mech) == 0)
453			break;
454	}
455
456	if (auth_mech->name == NULL) {
457		logger(L_ERR, L_FUNC, "unknown authentication mechanism: %s", mech);
458		exit(1);
459	}
460
461	if (auth_mech->initialize) {
462		if(auth_mech->initialize() != 0) {
463		    logger(L_ERR, L_FUNC, "failed to initialize mechanism %s",
464			   auth_mech->name);
465		    exit(1);
466		}
467	}
468}
469
470
471/*************************************************************
472 * Allow someone to set the number of worker processes we
473 * will use. Only applicable to unix ipc.
474 **************************************************************/
475void set_max_procs(const char *procs) {
476	num_procs = atoi(procs);
477
478	if(num_procs < 0) {
479		logger(L_ERR, L_FUNC, "invalid number of worker processes defined");
480		exit(1);
481	}
482
483	return;
484}
485
486
487/*************************************************************
488 * Allow someone to set the mechanism specific option
489 **************************************************************/
490void set_mech_option(const char *option) {
491
492	free(mech_option);
493	mech_option = NULL;
494
495	if ((mech_option = strdup(option)) == NULL) {
496		logger(L_ERR, L_FUNC, "could not allocate memory");
497		exit(1);
498	}
499
500	return;
501}
502
503
504/*************************************************************
505 * Allow someone to set the path to our working directory
506 **************************************************************/
507void set_run_path(const char *path) {
508
509	if (*path != '/') {
510		logger(L_ERR, L_FUNC, "-m requires an absolute pathname");
511		exit(1);
512	}
513
514	free(run_path);
515	run_path = NULL;
516
517	if ((run_path = strdup(path)) == NULL) {
518		logger(L_ERR, L_FUNC, "could not allocate memory");
519		exit(1);
520	}
521
522	return;
523}
524
525
526
527/*************************************************************
528 * Setup all the proper signal masks.
529 **************************************************************/
530void signal_setup() {
531
532	static struct sigaction act_sigchld;
533	static struct sigaction act_sigalrm;
534	static struct sigaction act_sigterm;
535	static struct sigaction act_sigpipe;
536	static struct sigaction act_sighup;
537	static struct sigaction act_sigint;
538	int			rc;
539
540	/**************************************************************
541	 * Handler for SIGCHLD
542	 **************************************************************/
543	act_sigchld.sa_handler = handle_sigchld;
544	sigemptyset(&act_sigchld.sa_mask);
545
546	if (sigaction(SIGCHLD, &act_sigchld, NULL) != 0) {
547		rc = errno;
548		logger(L_ERR, L_FUNC, "failed to set sigaction for SIGCHLD");
549		logger(L_ERR, L_FUNC, "sigaction: %s", strerror(rc));
550		exit(1);
551	}
552
553	/**************************************************************
554	 * Handler for SIGALRM  (IGNORE)
555	 **************************************************************/
556	act_sigalrm.sa_handler = SIG_IGN;
557	sigemptyset(&act_sigalrm.sa_mask);
558
559	if (sigaction(SIGALRM, &act_sigalrm, NULL) != 0) {
560		rc = errno;
561		logger(L_ERR, L_FUNC, "failed to set sigaction for SIGALRM");
562		logger(L_ERR, L_FUNC, "sigaction: %s", strerror(rc));
563		exit(1);
564	}
565
566	/**************************************************************
567	 * Handler for SIGPIPE  (IGNORE)
568	 **************************************************************/
569	act_sigpipe.sa_handler = SIG_IGN;
570	sigemptyset(&act_sigpipe.sa_mask);
571
572	if (sigaction(SIGPIPE, &act_sigpipe, NULL) != 0) {
573		rc = errno;
574		logger(L_ERR, L_FUNC, "failed to set sigaction for SIGPIPE");
575		logger(L_ERR, L_FUNC, "sigaction: %s", strerror(rc));
576		exit(1);
577	}
578
579	/**************************************************************
580	 * Handler for SIGHUP  (IGNORE)
581	 **************************************************************/
582	act_sighup.sa_handler = SIG_IGN;
583	sigemptyset(&act_sighup.sa_mask);
584
585	if (sigaction(SIGHUP, &act_sighup, NULL) != 0) {
586		rc = errno;
587		logger(L_ERR, L_FUNC, "failed to set sigaction for SIGHUP");
588		logger(L_ERR, L_FUNC, "sigaction: %s", strerror(rc));
589		exit(1);
590	}
591
592	/**************************************************************
593	 * Handler for SIGTERM
594	 **************************************************************/
595	act_sigterm.sa_handler = server_exit;
596	sigemptyset(&act_sigterm.sa_mask);
597
598	if (sigaction(SIGTERM, &act_sigterm, NULL) != 0) {
599		rc = errno;
600		logger(L_ERR, L_FUNC, "failed to set sigaction for SIGTERM");
601		logger(L_ERR, L_FUNC, "sigaction: %s", strerror(rc));
602		exit(1);
603	}
604
605	/**************************************************************
606	 * Handler for SIGINT
607	 **************************************************************/
608	act_sigint.sa_handler = server_exit;
609	sigemptyset(&act_sigint.sa_mask);
610
611	if (sigaction(SIGINT, &act_sigint, NULL) != 0) {
612		rc = errno;
613		logger(L_ERR, L_FUNC, "failed to set sigaction for SIGINT");
614		logger(L_ERR, L_FUNC, "sigaction: %s", strerror(rc));
615		exit(1);
616	}
617
618	return;
619}
620
621
622/*************************************************************
623 * Detaches us from the controlling tty (aka daemonize).
624 * More than likely this will be called from an ipc_init()
625 * function as we want to stay in the foreground for as long
626 * as possible.
627 **************************************************************/
628void detach_tty() {
629    int		x;
630    int		rc;
631    int		null_fd;
632    int         exit_result;
633    pid_t      	pid;
634    char       	pid_buf[100];
635    struct flock	lockinfo;
636
637    /**************************************************************
638     * Make sure we're supposed to do this, the user may have
639     * requested us to stay in the foreground.
640     **************************************************************/
641    if (flags & DETACH_TTY) {
642	for(x=5; x; x--) {
643	    pid = fork();
644
645	    if ((pid == -1) && (errno == EAGAIN)) {
646		logger(L_ERR, L_FUNC,
647		       "fork failed, retrying");
648		sleep(5);
649		continue;
650	    }
651
652	    break;
653	}
654
655	if (pid == -1) {
656	    /* Non retryable error. */
657	    rc = errno;
658	    logger(L_ERR, L_FUNC, "Cannot start saslauthd");
659	    logger(L_ERR, L_FUNC, "saslauthd master fork failed: %s",
660		   strerror(rc));
661	    exit(1);
662	} else if (pid != 0) {
663	    int exit_code;
664
665	    /* Parent, wait for child */
666	    if(read(startup_pipe[0], &exit_code, sizeof(exit_code)) == -1) {
667		logger(L_ERR, L_FUNC,
668		       "Cannot start saslauthd");
669		logger(L_ERR, L_FUNC,
670		       "could not read from startup_pipe");
671		unlink(pid_file_lock);
672		exit(1);
673	    } else {
674		if (exit_code != 0) {
675		    logger(L_ERR, L_FUNC, "Cannot start saslauthd");
676		    if (exit_code == 2) {
677			logger(L_ERR, L_FUNC,
678			       "Another instance of saslauthd is currently running");
679		    } else {
680			logger(L_ERR, L_FUNC, "Check syslog for errors");
681		    }
682		}
683		unlink(pid_file_lock);
684		exit(exit_code);
685	    }
686	}
687
688	/* Child! */
689	close(startup_pipe[0]);
690
691	free(pid_file_lock);
692
693	if (setsid() == -1) {
694	    exit_result = 1;
695	    rc = errno;
696
697	    logger(L_ERR, L_FUNC, "failed to set session id: %s",
698		   strerror(rc));
699
700	    /* Tell our parent that we failed. */
701	    write(startup_pipe[1], &exit_result, sizeof(exit_result));
702
703	    exit(1);
704	}
705
706	if ((null_fd = open("/dev/null", O_RDWR, 0)) == -1) {
707	    exit_result = 1;
708	    rc = errno;
709
710	    logger(L_ERR, L_FUNC, "failed to open /dev/null: %s",
711		   strerror(rc));
712
713	    /* Tell our parent that we failed. */
714	    write(startup_pipe[1], &exit_result, sizeof(exit_result));
715
716	    exit(1);
717	}
718
719	/*********************************************************
720	 * From this point on, stop printing errors out to stderr.
721	 **********************************************************/
722	flags &= ~LOG_USE_STDERR;
723
724	close(STDIN_FILENO);
725	close(STDOUT_FILENO);
726	close(STDERR_FILENO);
727
728	dup2(null_fd, STDIN_FILENO);
729	dup2(null_fd, STDOUT_FILENO);
730	dup2(null_fd, STDERR_FILENO);
731
732	if (null_fd > 2)
733	    close(null_fd);
734
735	/*********************************************************
736	 * Locks don't persist across forks. Relock the pid file
737	 * to keep folks from having duplicate copies running...
738	 *********************************************************/
739	if (!(pid_file = malloc(strlen(run_path) + sizeof(PID_FILE) + 1))) {
740	    exit_result = 1;
741	    logger(L_ERR, L_FUNC, "could not allocate memory");
742	    write(startup_pipe[1], &exit_result, sizeof(exit_result));
743	    exit(1);
744	}
745
746	strcpy(pid_file, run_path);
747	strcat(pid_file, PID_FILE);
748
749	/* Write out the pidfile */
750	pid_fd = open(pid_file, O_CREAT|O_RDWR, 0644);
751	if(pid_fd == -1) {
752	    rc = errno;
753	    exit_result = 1;
754
755	    logger(L_ERR, L_FUNC, "could not open pid file %s: %s",
756		   pid_file, strerror(rc));
757
758	    /* Tell our parent that we failed. */
759	    write(startup_pipe[1], &exit_result, sizeof(exit_result));
760
761	    exit(1);
762	} else {
763	    char buf[100];
764
765	    lockinfo.l_type = F_WRLCK;
766	    lockinfo.l_start = 0;
767	    lockinfo.l_len = 0;
768	    lockinfo.l_whence = SEEK_SET;
769
770	    if (fcntl(pid_fd, F_SETLK, &lockinfo) == -1) {
771		exit_result = 2;
772		rc = errno;
773
774		logger(L_ERR, L_FUNC, "could not lock pid file %s: %s",
775		       pid_file, strerror(rc));
776
777		/* Tell our parent that we failed. */
778		write(startup_pipe[1], &exit_result, sizeof(exit_result));
779
780		exit(2);
781	    } else {
782		int pid_fd_flags = fcntl(pid_fd, F_GETFD, 0);
783
784		if (pid_fd_flags != -1) {
785		    pid_fd_flags =
786			fcntl(pid_fd, F_SETFD, pid_fd_flags | FD_CLOEXEC);
787		}
788
789		if (pid_fd_flags == -1) {
790		    int exit_result = 1;
791
792		    logger(L_ERR, L_FUNC, "unable to set close-on-exec for pidfile");
793
794		    /* Tell our parent that we failed. */
795		    write(startup_pipe[1], &exit_result, sizeof(exit_result));
796
797		    exit(1);
798		}
799
800		/* Write PID */
801		master_pid = getpid();
802		snprintf(buf, sizeof(buf), "%lu\n", (unsigned long)master_pid);
803		if (lseek(pid_fd, 0, SEEK_SET) == -1 ||
804		    ftruncate(pid_fd, 0) == -1 ||
805		    write(pid_fd, buf, strlen(buf)) == -1) {
806		    int exit_result = 1;
807		    rc = errno;
808
809		    logger(L_ERR, L_FUNC, "could not write to pid file %s: %s", pid_file, strerror(rc));
810
811		    /* Tell our parent that we failed. */
812		    write(startup_pipe[1], &exit_result, sizeof(exit_result));
813
814		    exit(1);
815		}
816		fsync(pid_fd);
817	    }
818	}
819
820	{
821	    int exit_result = 0;
822
823	    /* success! */
824	    if(write(startup_pipe[1], &exit_result, sizeof(exit_result)) == -1) {
825		logger(L_ERR, L_FUNC,
826		       "could not write success result to startup pipe");
827		exit(1);
828	    }
829	}
830
831	close(startup_pipe[1]);
832	if(pid_file_lock_fd != -1) close(pid_file_lock_fd);
833    }
834
835    logger(L_INFO, L_FUNC, "master pid is: %lu", (unsigned long)master_pid);
836
837    return;
838}
839
840
841/*************************************************************
842 * Fork off a copy of ourselves. Return 0 if we're the child,
843 * > 0 for the parent. Die if we can't fork (the environment
844 * is probably unstable?).
845 **************************************************************/
846pid_t have_baby() {
847        pid_t   pid;
848        int     rc;
849
850        pid = fork();
851
852        if (pid < 0) {
853                rc = errno;
854                logger(L_ERR, L_FUNC, "could not fork child process");
855                logger(L_ERR, L_FUNC, "fork: %s", strerror(rc));
856                exit(1);
857        }
858
859	/*********************************************************
860	 * If we're the child, clear the AM_MASTER flag.
861	 **********************************************************/
862	if (pid == 0) {
863		flags &= ~AM_MASTER;
864        	return pid;
865	}
866
867        if (flags & VERBOSE) {
868                logger(L_DEBUG, L_FUNC, "forked child: %lu",
869		       (unsigned long)pid);
870	}
871
872        return pid;
873}
874
875
876/*************************************************************
877 * Reap in all the dead children
878 **************************************************************/
879void handle_sigchld() {
880	pid_t pid;
881
882	while ((pid = waitpid(-1, 0, WNOHANG)) > 0) {
883		if (flags & VERBOSE)
884			logger(L_DEBUG, L_FUNC, "child exited: %lu", (unsigned long)pid);
885
886	}
887
888	return;
889}
890
891
892/*************************************************************
893 * Do some final cleanup here.
894 **************************************************************/
895void server_exit() {
896	struct flock    lock_st;
897
898	/*********************************************************
899	 * If we're not the master process, don't do anything
900	 **********************************************************/
901	if (!(flags & AM_MASTER)) {
902		if (flags & VERBOSE)
903			logger(L_DEBUG, L_FUNC, "child exited: %d", getpid());
904
905		_exit(0);
906	}
907
908	kill(-master_pid, SIGTERM);
909
910	/*********************************************************
911	 * Tidy up and delete the pid_file. (close will release the lock)
912         * besides, we want to unlink it first anyway to avoid a race.
913	 * Note that only one process (the master, in our case) should
914	 * unlink it.
915	 **********************************************************/
916	if(flags & DETACH_TTY) {
917	    if(getpid() == master_pid) unlink(pid_file);
918	    close(pid_fd);
919
920	    if (flags & VERBOSE)
921		logger(L_DEBUG, L_FUNC, "pid file removed: %s", pid_file);
922
923	    free(pid_file);
924	} else {
925	    /* Tidy up and delete the pid_file_lock. (in the detached
926	       case this is covered by the parent process already */
927
928	    unlink(pid_file_lock);
929	    close(pid_file_lock_fd);
930
931	    if (flags & VERBOSE)
932		logger(L_DEBUG, L_FUNC, "pid file lock removed: %s",
933		       pid_file_lock);
934	    free(pid_file_lock);
935	}
936
937
938
939	/*********************************************************
940 	 * Cleanup the cache, if it's enabled
941	 **********************************************************/
942	if (flags & CACHE_ENABLED) {
943		cache_cleanup_lock();
944		cache_cleanup_mm();
945	}
946
947	/*********************************************************
948	 * Tell the IPC method to clean its room.
949	 **********************************************************/
950	ipc_cleanup();
951
952	/*********************************************************
953	 * Any other cleanup should go here
954	 **********************************************************/
955
956	logger(L_INFO, L_FUNC, "master exited: %d", master_pid);
957
958	_exit(0);
959}
960
961
962/*************************************************************
963 * Dump out our version and all the auth mechs we support
964 **************************************************************/
965void show_version() {
966    authmech_t *authmech;
967
968    fprintf(stderr, "saslauthd %s\nauthentication mechanisms:", VERSION);
969
970    for (authmech = mechanisms; authmech->name != NULL; authmech++) {
971	fprintf(stderr, " %s", authmech->name);
972    }
973
974    fprintf(stderr, "\n\n");
975    exit(0);
976}
977
978
979/*************************************************************
980 * Dump out our usage info and tag a show_version after it
981 **************************************************************/
982void show_usage() {
983    fprintf(stderr, "usage: saslauthd [options]\n\n");
984    fprintf(stderr, "option information:\n");
985    fprintf(stderr, "  -a <authmech>  Selects the authentication mechanism to use.\n");
986    fprintf(stderr, "  -c             Enable credential caching.\n");
987    fprintf(stderr, "  -d             Debugging (don't detach from tty, implies -V)\n");
988    fprintf(stderr, "  -r             Combine the realm with the login before passing to authentication mechanism\n");
989    fprintf(stderr, "                 Ex. login: \"foo\" realm: \"bar\" will get passed as login: \"foo@bar\"\n");
990    fprintf(stderr, "                 The realm name is passed untouched.\n");
991    fprintf(stderr, "  -O <option>    Optional argument to pass to the authentication\n");
992    fprintf(stderr, "                 mechanism.\n");
993    fprintf(stderr, "  -l             Disable accept() locking. Increases performance, but\n");
994    fprintf(stderr, "                 may not be compatible with some operating systems.\n");
995    fprintf(stderr, "  -m <path>      Alternate path for the saslauthd working directory,\n");
996    fprintf(stderr, "                 must be absolute.\n");
997    fprintf(stderr, "  -n <procs>     Number of worker processes to create.\n");
998    fprintf(stderr, "  -s <kilobytes> Size of the credential cache (in kilobytes)\n");
999    fprintf(stderr, "  -t <seconds>   Timeout for items in the credential cache (in seconds)\n");
1000    fprintf(stderr, "  -v             Display version information and available mechs\n");
1001    fprintf(stderr, "  -V             Enable verbose logging\n");
1002    fprintf(stderr, "  -h             Display this message.\n\n");
1003
1004    show_version();
1005    exit(0);
1006}
1007
1008