1178825Sdfr/*
2178825Sdfr * Copyright (c) 2005, PADL Software Pty Ltd.
3178825Sdfr * All rights reserved.
4178825Sdfr *
5233294Sstas * Portions Copyright (c) 2009 Apple Inc. All rights reserved.
6233294Sstas *
7178825Sdfr * Redistribution and use in source and binary forms, with or without
8178825Sdfr * modification, are permitted provided that the following conditions
9178825Sdfr * are met:
10178825Sdfr *
11178825Sdfr * 1. Redistributions of source code must retain the above copyright
12178825Sdfr *    notice, this list of conditions and the following disclaimer.
13178825Sdfr *
14178825Sdfr * 2. Redistributions in binary form must reproduce the above copyright
15178825Sdfr *    notice, this list of conditions and the following disclaimer in the
16178825Sdfr *    documentation and/or other materials provided with the distribution.
17178825Sdfr *
18178825Sdfr * 3. Neither the name of PADL Software nor the names of its contributors
19178825Sdfr *    may be used to endorse or promote products derived from this software
20178825Sdfr *    without specific prior written permission.
21178825Sdfr *
22178825Sdfr * THIS SOFTWARE IS PROVIDED BY PADL SOFTWARE AND CONTRIBUTORS ``AS IS'' AND
23178825Sdfr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24178825Sdfr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25178825Sdfr * ARE DISCLAIMED.  IN NO EVENT SHALL PADL SOFTWARE OR CONTRIBUTORS BE LIABLE
26178825Sdfr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27178825Sdfr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28178825Sdfr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29178825Sdfr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30178825Sdfr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31178825Sdfr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32178825Sdfr * SUCH DAMAGE.
33178825Sdfr */
34178825Sdfr
35178825Sdfr#include "kcm_locl.h"
36178825Sdfr#include <getarg.h>
37178825Sdfr#include <parse_bytes.h>
38178825Sdfr
39178825Sdfrstatic const char *config_file;	/* location of kcm config file */
40178825Sdfr
41178825Sdfrsize_t max_request = 0;		/* maximal size of a request */
42178825Sdfrchar *socket_path = NULL;
43178825Sdfrchar *door_path = NULL;
44178825Sdfr
45178825Sdfrstatic char *max_request_str;	/* `max_request' as a string */
46178825Sdfr
47233294Sstas#ifdef SUPPORT_DETACH
48178825Sdfrint detach_from_console = -1;
49178825Sdfr#define DETACH_IS_DEFAULT FALSE
50233294Sstas#endif
51178825Sdfr
52178825Sdfrstatic const char *system_cache_name = NULL;
53178825Sdfrstatic const char *system_keytab = NULL;
54178825Sdfrstatic const char *system_principal = NULL;
55178825Sdfrstatic const char *system_server = NULL;
56178825Sdfrstatic const char *system_perms = NULL;
57178825Sdfrstatic const char *system_user = NULL;
58178825Sdfrstatic const char *system_group = NULL;
59178825Sdfr
60178825Sdfrstatic const char *renew_life = NULL;
61178825Sdfrstatic const char *ticket_life = NULL;
62178825Sdfr
63233294Sstasint launchd_flag = 0;
64233294Sstasint disallow_getting_krbtgt = 0;
65178825Sdfrint name_constraints = -1;
66178825Sdfr
67178825Sdfrstatic int help_flag;
68178825Sdfrstatic int version_flag;
69178825Sdfr
70178825Sdfrstatic struct getargs args[] = {
71233294Sstas    {
72233294Sstas	"cache-name",	0,	arg_string,	&system_cache_name,
73233294Sstas	"system cache name", "cachename"
74178825Sdfr    },
75233294Sstas    {
76233294Sstas	"config-file",	'c',	arg_string,	&config_file,
77233294Sstas	"location of config file",	"file"
78178825Sdfr    },
79233294Sstas    {
80233294Sstas	"group",	'g',	arg_string,	&system_group,
81233294Sstas	"system cache group",	"group"
82178825Sdfr    },
83233294Sstas    {
84233294Sstas	"max-request",	0,	arg_string, &max_request,
85178825Sdfr	"max size for a kcm-request", "size"
86178825Sdfr    },
87233294Sstas    {
88233294Sstas	"launchd",	0,	arg_flag, &launchd_flag,
89233294Sstas	"when in use by launchd"
90233294Sstas    },
91233294Sstas#ifdef SUPPORT_DETACH
92178825Sdfr#if DETACH_IS_DEFAULT
93178825Sdfr    {
94233294Sstas	"detach",       'D',      arg_negative_flag, &detach_from_console,
95178825Sdfr	"don't detach from console"
96178825Sdfr    },
97178825Sdfr#else
98178825Sdfr    {
99233294Sstas	"detach",       0 ,      arg_flag, &detach_from_console,
100178825Sdfr	"detach from console"
101178825Sdfr    },
102178825Sdfr#endif
103233294Sstas#endif
104178825Sdfr    {	"help",		'h',	arg_flag,   &help_flag },
105233294Sstas    {
106233294Sstas	"system-principal",	'k',	arg_string,	&system_principal,
107233294Sstas	"system principal name",	"principal"
108178825Sdfr    },
109178825Sdfr    {
110178825Sdfr	"lifetime",	'l', arg_string, &ticket_life,
111178825Sdfr	"lifetime of system tickets", "time"
112178825Sdfr    },
113178825Sdfr    {
114178825Sdfr	"mode",		'm', arg_string, &system_perms,
115178825Sdfr	"octal mode of system cache", "mode"
116178825Sdfr    },
117178825Sdfr    {
118178825Sdfr	"name-constraints",	'n', arg_negative_flag, &name_constraints,
119178825Sdfr	"disable credentials cache name constraints"
120178825Sdfr    },
121178825Sdfr    {
122178825Sdfr	"disallow-getting-krbtgt", 0, arg_flag, &disallow_getting_krbtgt,
123178825Sdfr	"disable fetching krbtgt from the cache"
124178825Sdfr    },
125178825Sdfr    {
126178825Sdfr	"renewable-life",	'r', arg_string, &renew_life,
127178825Sdfr    	"renewable lifetime of system tickets", "time"
128178825Sdfr    },
129178825Sdfr    {
130178825Sdfr	"socket-path",		's', arg_string, &socket_path,
131178825Sdfr    	"path to kcm domain socket", "path"
132178825Sdfr    },
133178825Sdfr#ifdef HAVE_DOOR_CREATE
134178825Sdfr    {
135178825Sdfr	"door-path",		's', arg_string, &door_path,
136178825Sdfr    	"path to kcm door", "path"
137178825Sdfr    },
138178825Sdfr#endif
139178825Sdfr    {
140178825Sdfr	"server",		'S', arg_string, &system_server,
141178825Sdfr    	"server to get system ticket for", "principal"
142178825Sdfr    },
143233294Sstas    {
144233294Sstas	"keytab",	't',	arg_string,	&system_keytab,
145233294Sstas	"system keytab name",	"keytab"
146178825Sdfr    },
147233294Sstas    {
148233294Sstas	"user",		'u',	arg_string,	&system_user,
149233294Sstas	"system cache owner",	"user"
150178825Sdfr    },
151178825Sdfr    {	"version",	'v',	arg_flag,   &version_flag }
152178825Sdfr};
153178825Sdfr
154178825Sdfrstatic int num_args = sizeof(args) / sizeof(args[0]);
155178825Sdfr
156178825Sdfrstatic void
157178825Sdfrusage(int ret)
158178825Sdfr{
159178825Sdfr    arg_printusage (args, num_args, NULL, "");
160178825Sdfr    exit (ret);
161178825Sdfr}
162178825Sdfr
163178825Sdfrstatic int parse_owners(kcm_ccache ccache)
164178825Sdfr{
165178825Sdfr    uid_t uid = 0;
166178825Sdfr    gid_t gid = 0;
167178825Sdfr    struct passwd *pw;
168178825Sdfr    struct group *gr;
169178825Sdfr    int uid_p = 0;
170178825Sdfr    int gid_p = 0;
171178825Sdfr
172178825Sdfr    if (system_user != NULL) {
173178825Sdfr	if (isdigit((unsigned char)system_user[0])) {
174178825Sdfr	    pw = getpwuid(atoi(system_user));
175178825Sdfr	} else {
176178825Sdfr	    pw = getpwnam(system_user);
177178825Sdfr	}
178178825Sdfr	if (pw == NULL) {
179178825Sdfr	    return errno;
180178825Sdfr	}
181178825Sdfr
182178825Sdfr	system_user = strdup(pw->pw_name);
183178825Sdfr	if (system_user == NULL) {
184178825Sdfr	    return ENOMEM;
185178825Sdfr	}
186178825Sdfr
187178825Sdfr	uid = pw->pw_uid; uid_p = 1;
188178825Sdfr	gid = pw->pw_gid; gid_p = 1;
189178825Sdfr    }
190178825Sdfr
191178825Sdfr    if (system_group != NULL) {
192178825Sdfr	if (isdigit((unsigned char)system_group[0])) {
193178825Sdfr	    gr = getgrgid(atoi(system_group));
194178825Sdfr	} else {
195178825Sdfr	    gr = getgrnam(system_group);
196178825Sdfr	}
197178825Sdfr	if (gr == NULL) {
198178825Sdfr	    return errno;
199178825Sdfr	}
200178825Sdfr
201178825Sdfr	gid = gr->gr_gid; gid_p = 1;
202178825Sdfr    }
203178825Sdfr
204178825Sdfr    if (uid_p)
205178825Sdfr	ccache->uid = uid;
206178825Sdfr    else
207178825Sdfr	ccache->uid = 0; /* geteuid() XXX */
208178825Sdfr
209178825Sdfr    if (gid_p)
210178825Sdfr	ccache->gid = gid;
211178825Sdfr    else
212178825Sdfr	ccache->gid = 0; /* getegid() XXX */
213178825Sdfr
214178825Sdfr    return 0;
215178825Sdfr}
216178825Sdfr
217178825Sdfrstatic const char *
218178825Sdfrkcm_system_config_get_string(const char *string)
219178825Sdfr{
220178825Sdfr    return krb5_config_get_string(kcm_context, NULL, "kcm",
221178825Sdfr				  "system_ccache", string, NULL);
222178825Sdfr}
223178825Sdfr
224178825Sdfrstatic krb5_error_code
225178825Sdfrccache_init_system(void)
226178825Sdfr{
227178825Sdfr    kcm_ccache ccache;
228178825Sdfr    krb5_error_code ret;
229178825Sdfr
230178825Sdfr    if (system_cache_name == NULL)
231178825Sdfr	system_cache_name = kcm_system_config_get_string("cc_name");
232178825Sdfr
233178825Sdfr    ret = kcm_ccache_new(kcm_context,
234178825Sdfr			 system_cache_name ? system_cache_name : "SYSTEM",
235178825Sdfr			 &ccache);
236178825Sdfr    if (ret)
237178825Sdfr	return ret;
238178825Sdfr
239178825Sdfr    ccache->flags |= KCM_FLAGS_OWNER_IS_SYSTEM;
240178825Sdfr    ccache->flags |= KCM_FLAGS_USE_KEYTAB;
241178825Sdfr
242178825Sdfr    ret = parse_owners(ccache);
243178825Sdfr    if (ret)
244178825Sdfr	return ret;
245178825Sdfr
246178825Sdfr    ret = krb5_parse_name(kcm_context, system_principal, &ccache->client);
247178825Sdfr    if (ret) {
248233294Sstas	kcm_release_ccache(kcm_context, ccache);
249178825Sdfr	return ret;
250178825Sdfr    }
251178825Sdfr
252178825Sdfr    if (system_server == NULL)
253178825Sdfr	system_server = kcm_system_config_get_string("server");
254178825Sdfr
255178825Sdfr    if (system_server != NULL) {
256178825Sdfr	ret = krb5_parse_name(kcm_context, system_server, &ccache->server);
257178825Sdfr	if (ret) {
258233294Sstas	    kcm_release_ccache(kcm_context, ccache);
259178825Sdfr	    return ret;
260178825Sdfr	}
261178825Sdfr    }
262178825Sdfr
263178825Sdfr    if (system_keytab == NULL)
264178825Sdfr	system_keytab = kcm_system_config_get_string("keytab_name");
265178825Sdfr
266178825Sdfr    if (system_keytab != NULL) {
267178825Sdfr	ret = krb5_kt_resolve(kcm_context, system_keytab, &ccache->key.keytab);
268178825Sdfr    } else {
269178825Sdfr	ret = krb5_kt_default(kcm_context, &ccache->key.keytab);
270178825Sdfr    }
271178825Sdfr    if (ret) {
272233294Sstas	kcm_release_ccache(kcm_context, ccache);
273178825Sdfr	return ret;
274178825Sdfr    }
275178825Sdfr
276178825Sdfr    if (renew_life == NULL)
277178825Sdfr	renew_life = kcm_system_config_get_string("renew_life");
278178825Sdfr
279178825Sdfr    if (renew_life == NULL)
280178825Sdfr	renew_life = "1 month";
281178825Sdfr
282178825Sdfr    if (renew_life != NULL) {
283178825Sdfr	ccache->renew_life = parse_time(renew_life, "s");
284178825Sdfr	if (ccache->renew_life < 0) {
285233294Sstas	    kcm_release_ccache(kcm_context, ccache);
286178825Sdfr	    return EINVAL;
287178825Sdfr	}
288178825Sdfr    }
289178825Sdfr
290178825Sdfr    if (ticket_life == NULL)
291178825Sdfr	ticket_life = kcm_system_config_get_string("ticket_life");
292178825Sdfr
293178825Sdfr    if (ticket_life != NULL) {
294178825Sdfr	ccache->tkt_life = parse_time(ticket_life, "s");
295178825Sdfr	if (ccache->tkt_life < 0) {
296233294Sstas	    kcm_release_ccache(kcm_context, ccache);
297178825Sdfr	    return EINVAL;
298178825Sdfr	}
299178825Sdfr    }
300178825Sdfr
301178825Sdfr    if (system_perms == NULL)
302178825Sdfr	system_perms = kcm_system_config_get_string("mode");
303178825Sdfr
304178825Sdfr    if (system_perms != NULL) {
305178825Sdfr	int mode;
306178825Sdfr
307178825Sdfr	if (sscanf(system_perms, "%o", &mode) != 1)
308178825Sdfr	    return EINVAL;
309178825Sdfr
310178825Sdfr	ccache->mode = mode;
311178825Sdfr    }
312178825Sdfr
313178825Sdfr    if (disallow_getting_krbtgt == -1) {
314178825Sdfr	disallow_getting_krbtgt =
315178825Sdfr	    krb5_config_get_bool_default(kcm_context, NULL, FALSE, "kcm",
316178825Sdfr					 "disallow-getting-krbtgt", NULL);
317178825Sdfr    }
318178825Sdfr
319178825Sdfr    /* enqueue default actions for credentials cache */
320178825Sdfr    ret = kcm_ccache_enqueue_default(kcm_context, ccache, NULL);
321178825Sdfr
322233294Sstas    kcm_release_ccache(kcm_context, ccache); /* retained by event queue */
323178825Sdfr
324178825Sdfr    return ret;
325178825Sdfr}
326178825Sdfr
327178825Sdfrvoid
328178825Sdfrkcm_configure(int argc, char **argv)
329178825Sdfr{
330178825Sdfr    krb5_error_code ret;
331178825Sdfr    int optind = 0;
332178825Sdfr    const char *p;
333233294Sstas
334178825Sdfr    while(getarg(args, num_args, argc, argv, &optind))
335178825Sdfr	warnx("error at argument `%s'", argv[optind]);
336178825Sdfr
337178825Sdfr    if(help_flag)
338178825Sdfr	usage (0);
339178825Sdfr
340178825Sdfr    if (version_flag) {
341178825Sdfr	print_version(NULL);
342178825Sdfr	exit(0);
343178825Sdfr    }
344178825Sdfr
345178825Sdfr    argc -= optind;
346178825Sdfr    argv += optind;
347178825Sdfr
348178825Sdfr    if (argc != 0)
349178825Sdfr	usage(1);
350233294Sstas
351178825Sdfr    {
352178825Sdfr	char **files;
353178825Sdfr
354178825Sdfr	if(config_file == NULL)
355178825Sdfr	    config_file = _PATH_KCM_CONF;
356178825Sdfr
357178825Sdfr	ret = krb5_prepend_config_files_default(config_file, &files);
358178825Sdfr	if (ret)
359178825Sdfr	    krb5_err(kcm_context, 1, ret, "getting configuration files");
360233294Sstas
361178825Sdfr	ret = krb5_set_config_files(kcm_context, files);
362178825Sdfr	krb5_free_config_files(files);
363233294Sstas	if(ret)
364178825Sdfr	    krb5_err(kcm_context, 1, ret, "reading configuration files");
365178825Sdfr    }
366178825Sdfr
367178825Sdfr    if(max_request_str)
368178825Sdfr	max_request = parse_bytes(max_request_str, NULL);
369178825Sdfr
370178825Sdfr    if(max_request == 0){
371178825Sdfr	p = krb5_config_get_string (kcm_context,
372178825Sdfr				    NULL,
373178825Sdfr				    "kcm",
374178825Sdfr				    "max-request",
375178825Sdfr				    NULL);
376178825Sdfr	if(p)
377178825Sdfr	    max_request = parse_bytes(p, NULL);
378178825Sdfr    }
379178825Sdfr
380178825Sdfr    if (system_principal == NULL) {
381178825Sdfr	system_principal = kcm_system_config_get_string("principal");
382178825Sdfr    }
383178825Sdfr
384178825Sdfr    if (system_principal != NULL) {
385178825Sdfr	ret = ccache_init_system();
386178825Sdfr	if (ret)
387178825Sdfr	    krb5_err(kcm_context, 1, ret, "initializing system ccache");
388178825Sdfr    }
389178825Sdfr
390233294Sstas#ifdef SUPPORT_DETACH
391233294Sstas    if(detach_from_console == -1)
392178825Sdfr	detach_from_console = krb5_config_get_bool_default(kcm_context, NULL,
393178825Sdfr							   DETACH_IS_DEFAULT,
394178825Sdfr							   "kcm",
395178825Sdfr							   "detach", NULL);
396233294Sstas#endif
397178825Sdfr    kcm_openlog();
398178825Sdfr    if(max_request == 0)
399178825Sdfr	max_request = 64 * 1024;
400178825Sdfr}
401178825Sdfr
402