1/*
2 * Copyright (c) 1997-2005 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
4 * All rights reserved.
5 *
6 * Portions Copyright (c) 2009 Apple Inc. All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 *
12 * 1. Redistributions of source code must retain the above copyright
13 *    notice, this list of conditions and the following disclaimer.
14 *
15 * 2. Redistributions in binary form must reproduce the above copyright
16 *    notice, this list of conditions and the following disclaimer in the
17 *    documentation and/or other materials provided with the distribution.
18 *
19 * 3. Neither the name of the Institute nor the names of its contributors
20 *    may be used to endorse or promote products derived from this software
21 *    without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 */
35
36#include "kdc_locl.h"
37#ifdef HAVE_UTIL_H
38#include <util.h>
39#endif
40
41#ifdef __APPLE__
42#include <sandbox.h>
43
44int sandbox_flag = 1;
45#endif
46
47#ifdef HAVE_CAPNG
48#include <cap-ng.h>
49#endif
50
51static void terminated(void *ctx) __attribute__((noreturn));
52
53
54#ifdef SUPPORT_DETACH
55int detach_from_console = -1;
56#endif
57
58/*
59 * Allow dropping root bit, since heimdal reopens the database all the
60 * time the database needs to be owned by the user you are switched
61 * too. A better solution is to split the kdc in to more processes and
62 * run the network facing part with very low privilege.
63 */
64
65static void
66switch_environment(void)
67{
68#ifdef HAVE_GETEUID
69    if ((runas_string || chroot_string) && geteuid() != 0)
70	errx(1, "no running as root, can't switch user/chroot");
71
72    if (chroot_string && chroot(chroot_string) != 0)
73	errx(1, "chroot(%s)", "chroot_string failed");
74
75    if (runas_string) {
76	struct passwd *pw;
77
78	pw = getpwnam(runas_string);
79	if (pw == NULL)
80	    errx(1, "unknown user %s", runas_string);
81
82	if (initgroups(pw->pw_name, pw->pw_gid) < 0)
83	    err(1, "initgroups failed");
84
85#ifndef HAVE_CAPNG
86	if (setgid(pw->pw_gid) < 0)
87	    err(1, "setgid(%s) failed", runas_string);
88
89	if (setuid(pw->pw_uid) < 0)
90	    err(1, "setuid(%s)", runas_string);
91#else
92	capng_clear (CAPNG_EFFECTIVE | CAPNG_PERMITTED);
93	if (capng_updatev (CAPNG_ADD, CAPNG_EFFECTIVE | CAPNG_PERMITTED,
94	                   CAP_NET_BIND_SERVICE, CAP_SETPCAP, -1) < 0)
95	    err(1, "capng_updateev");
96
97	if (capng_change_id(pw->pw_uid, pw->pw_gid,
98	                    CAPNG_CLEAR_BOUNDING) < 0)
99	    err(1, "capng_change_id(%s)", runas_string);
100#endif
101    }
102#endif
103}
104
105static krb5_context context;
106static krb5_kdc_configuration *config;
107
108static heim_array_t
109get_realms(void)
110{
111    heim_array_t array;
112    char **realms, **r;
113    unsigned int i;
114    int ret;
115
116    array = heim_array_create();
117
118    for(i = 0; i < config->num_db; i++) {
119
120	if (config->db[i]->hdb_get_realms == NULL)
121	    continue;
122
123	ret = (config->db[i]->hdb_get_realms)(context, config->db[i], &realms);
124	if (ret == 0) {
125	    for (r = realms; r && *r; r++) {
126		heim_string_t s = heim_string_create(*r);
127		if (s)
128		    heim_array_append_value(array, s);
129		heim_release(s);
130	    }
131	    krb5_free_host_realm(context, realms);
132	}
133    }
134
135    return array;
136}
137
138static void
139terminated(void *ctx)
140{
141    kdc_log(context, config, 0, "Terminated: %s", (char *)ctx);
142    exit(1);
143}
144
145int
146main(int argc, char **argv)
147{
148    krb5_error_code ret;
149
150    setprogname(argv[0]);
151
152    ret = krb5_init_context(&context);
153    if (ret == KRB5_CONFIG_BADFORMAT)
154	errx (1, "krb5_init_context failed to parse configuration file");
155    else if (ret)
156	errx (1, "krb5_init_context failed: %d", ret);
157
158    ret = krb5_kt_register(context, &hdb_kt_ops);
159    if (ret)
160	errx (1, "krb5_kt_register(HDB) failed: %d", ret);
161
162    config = configure(context, argc, argv);
163
164#ifdef SIGPIPE
165#ifdef HAVE_SIGACTION
166    {
167	struct sigaction sa;
168
169	sa.sa_flags = 0;
170	sigemptyset(&sa.sa_mask);
171
172	sa.sa_handler = SIG_IGN;
173	sigaction(SIGPIPE, &sa, NULL);
174    }
175#else
176    signal(SIGPIPE, SIG_IGN);
177#endif
178#endif /* SIGPIPE */
179
180
181
182#ifdef SUPPORT_DETACH
183    if (detach_from_console)
184	daemon(0, 0);
185#endif
186#ifdef __APPLE__
187    if (sandbox_flag) {
188	char *errorstring;
189	ret = sandbox_init("kdc", SANDBOX_NAMED, &errorstring);
190	if (ret)
191	    errx(1, "sandbox_init failed: %d: %s", ret, errorstring);
192    }
193    bonjour_announce(get_realms);
194#endif /* __APPLE__ */
195    pidfile(NULL);
196
197    switch_environment();
198
199    setup_listeners(context, config, listen_on_ipc, listen_on_network);
200
201    heim_sipc_signal_handler(SIGINT, terminated, "SIGINT");
202    heim_sipc_signal_handler(SIGTERM, terminated, "SIGTERM");
203#ifdef SIGXCPU
204    heim_sipc_signal_handler(SIGXCPU, terminated, "CPU time limit exceeded");
205#endif
206
207    heim_ipc_main();
208}
209