1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
3 * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved
8 * Copyright (C) 1998 by the FundsXpress, INC.
10 * All rights reserved.
12 * Export of this software from the United States of America may require
13 * a specific license from the United States Government. It is the
14 * responsibility of any person or organization contemplating export to
15 * obtain such a license before exporting.
17 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
18 * distribute this software and its documentation for any purpose and
19 * without fee is hereby granted, provided that the above copyright
20 * notice appear in all copies and that both that copyright notice and
21 * this permission notice appear in supporting documentation, and that
22 * the name of FundsXpress. not be used in advertising or publicity pertaining
23 * to distribution of the software without specific, written prior
24 * permission. FundsXpress makes no representations about the suitability of
25 * this software for any purpose. It is provided "as is" without express
26 * or implied warranty.
28 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
29 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
30 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
33 #include <k5-platform.h>
39 #include <sys/types.h>
41 #include <sys/select.h>
44 #include <sys/socket.h>
46 #include <netinet/in.h>
48 #include <gssrpc/rpc.h>
49 #include <gssapi/gssapi.h>
50 #include "gssapiP_krb5.h" /* for kg_get_context */
51 #include <gssrpc/auth_gssapi.h>
52 #include <kadm5/admin.h>
53 #include <kadm5/kadm_rpc.h>
54 #include <adm_proto.h>
55 #include "kdb_kt.h" /* for krb5_ktkdb_set_context */
62 #if defined(NEED_DAEMON_PROTO)
68 gss_name_t gss_changepw_name = NULL, gss_oldchangepw_name = NULL;
69 void *global_server_handle;
71 char *kdb5_util = KPROPD_DEFAULT_KDB5_UTIL;
72 char *kprop = KPROPD_DEFAULT_KPROP;
73 char *dump_file = KPROP_DEFAULT_FILE;
74 char *kprop_port = NULL;
76 static krb5_context context;
77 static char *progname;
79 #ifdef USE_PASSWORD_SERVER
80 void kadm5_set_use_password_server(void);
86 fprintf(stderr, _("Usage: kadmind [-x db_args]* [-r realm] [-m] [-nofork] "
87 "[-port port-number]\n"
88 "\t\t[-proponly] [-p path-to-kdb5_util] [-F dump-file]\n"
89 "\t\t[-K path-to-kprop] [-k kprop-port] [-P pid_file]\n"
90 "\nwhere,\n\t[-x db_args]* - any number of database "
91 "specific arguments.\n"
92 "\t\t\tLook at each database documentation for "
93 "supported arguments\n"));
98 * Output a message to stderr and the admin server log, and exit with status 1.
99 * msg should not be punctuated. If code is given, msg should indicate what
100 * operation was taking place in the present progressive. Otherwise msg should
101 * be capitalized and should indicate what went wrong.
104 fail_to_start(krb5_error_code code, const char *msg)
109 errmsg = krb5_get_error_message(context, code);
110 fprintf(stderr, _("%s: %s while %s, aborting\n"), progname, errmsg,
112 krb5_klog_syslog(LOG_ERR, _("%s while %s, aborting\n"), errmsg, msg);
114 fprintf(stderr, _("%s: %s, aborting\n"), progname, msg);
115 krb5_klog_syslog(LOG_ERR, _("%s, aborting"), msg);
121 write_pid_file(const char *pid_file)
127 file = fopen(pid_file, "w");
130 pid = (unsigned long)getpid();
131 st1 = (fprintf(file, "%ld\n", pid) < 0) ? errno : 0;
132 st2 = (fclose(file) == EOF) ? errno : 0;
133 return st1 ? st1 : st2;
136 /* Set up the main loop. If proponly is set, don't set up ports for kpasswd or
137 * kadmin. May set *ctx_out even on error. */
138 static krb5_error_code
139 setup_loop(kadm5_config_params *params, int proponly, verto_ctx **ctx_out)
144 *ctx_out = ctx = loop_init(VERTO_EV_TYPE_SIGNAL);
147 ret = loop_setup_signals(ctx, global_server_handle, NULL);
151 ret = loop_add_udp_address(params->kpasswd_port,
152 params->kpasswd_listen);
155 ret = loop_add_tcp_address(params->kpasswd_port,
156 params->kpasswd_listen);
159 ret = loop_add_rpc_service(params->kadmind_port,
160 params->kadmind_listen,
161 KADM, KADMVERS, kadm_1);
165 #ifndef DISABLE_IPROP
166 if (params->iprop_enabled) {
167 ret = loop_add_rpc_service(params->iprop_port, params->iprop_listen,
168 KRB5_IPROP_PROG, KRB5_IPROP_VERS,
174 return loop_setup_network(ctx, global_server_handle, progname,
175 DEFAULT_TCP_LISTEN_BACKLOG);
178 /* Point GSSAPI at the KDB keytab so we don't need an actual file keytab. */
179 static krb5_error_code
184 ret = krb5_ktkdb_set_context(context);
187 ret = krb5_db_register_keytab(context);
190 return krb5_gss_register_acceptor_identity("KDB:");
194 /* Return "name@realm". */
196 build_princ_name(char *name, char *realm)
200 if (asprintf(&fullname, "%s@%s", name, realm) < 0)
205 /* Callback from GSSRPC for garbled/forged/replayed/etc messages. */
207 log_badverf(gss_name_t client_name, gss_name_t server_name,
208 struct svc_req *rqst, struct rpc_msg *msg, char *data)
210 static const struct {
212 const char *proc_name;
214 {1, "CREATE_PRINCIPAL"},
215 {2, "DELETE_PRINCIPAL"},
216 {3, "MODIFY_PRINCIPAL"},
217 {4, "RENAME_PRINCIPAL"},
218 {5, "GET_PRINCIPAL"},
219 {6, "CHPASS_PRINCIPAL"},
220 {7, "CHRAND_PRINCIPAL"},
221 {8, "CREATE_POLICY"},
222 {9, "DELETE_POLICY"},
223 {10, "MODIFY_POLICY"},
229 {16, "SETKEY_PRINCIPAL"},
230 {17, "SETV4KEY_PRINCIPAL"},
231 {18, "CREATE_PRINCIPAL3"},
232 {19, "CHPASS_PRINCIPAL3"},
233 {20, "CHRAND_PRINCIPAL3"},
234 {21, "SETKEY_PRINCIPAL3"},
240 gss_buffer_desc client, server;
245 const char *procname;
254 (void)gss_display_name(&minor, client_name, &client, &gss_type);
255 (void)gss_display_name(&minor, server_name, &server, &gss_type);
256 if (client.value == NULL) {
257 client.value = "(null)";
258 clen = sizeof("(null)") - 1;
260 clen = client.length;
262 trunc_name(&clen, &cdots);
263 if (server.value == NULL) {
264 server.value = "(null)";
265 slen = sizeof("(null)") - 1;
267 slen = server.length;
269 trunc_name(&slen, &sdots);
270 a = client_addr(rqst->rq_xprt);
272 proc = msg->rm_call.cb_proc;
274 for (i = 0; i < sizeof(proc_names) / sizeof(*proc_names); i++) {
275 if (proc_names[i].proc == proc) {
276 procname = proc_names[i].proc_name;
280 if (procname != NULL) {
281 krb5_klog_syslog(LOG_NOTICE,
282 _("WARNING! Forged/garbled request: %s, claimed "
283 "client = %.*s%s, server = %.*s%s, addr = %s"),
284 procname, (int)clen, (char *)client.value, cdots,
285 (int)slen, (char *)server.value, sdots, a);
287 krb5_klog_syslog(LOG_NOTICE,
288 _("WARNING! Forged/garbled request: %d, claimed "
289 "client = %.*s%s, server = %.*s%s, addr = %s"),
290 proc, (int)clen, (char *)client.value, cdots,
291 (int)slen, (char *)server.value, sdots, a);
294 (void)gss_release_buffer(&minor, &client);
295 (void)gss_release_buffer(&minor, &server);
298 /* Callback from GSSRPC for miscellaneous errors */
300 log_miscerr(struct svc_req *rqst, struct rpc_msg *msg, char *error, char *data)
302 krb5_klog_syslog(LOG_NOTICE, _("Miscellaneous RPC error: %s, %s"),
303 client_addr(rqst->rq_xprt), error);
307 log_badauth_display_status_1(char *m, OM_uint32 code, int type)
309 OM_uint32 gssstat, minor_stat;
315 gssstat = gss_display_status(&minor_stat, code, type, GSS_C_NULL_OID,
317 if (gssstat != GSS_S_COMPLETE) {
318 krb5_klog_syslog(LOG_ERR, _("%s Cannot decode status %d"), m,
323 krb5_klog_syslog(LOG_NOTICE, "%s %.*s", m, (int)msg.length,
325 (void)gss_release_buffer(&minor_stat, &msg);
332 /* Callback from GSSRPC for authentication failures */
334 log_badauth(OM_uint32 major, OM_uint32 minor, SVCXPRT *xprt, char *data)
336 krb5_klog_syslog(LOG_NOTICE, _("Authentication attempt failed: %s, "
337 "GSS-API error strings are:"),
339 log_badauth_display_status_1(" ", major, GSS_C_GSS_CODE);
340 log_badauth_display_status_1(" ", minor, GSS_C_MECH_CODE);
341 krb5_klog_syslog(LOG_NOTICE, _(" GSS-API error strings complete."));
345 main(int argc, char *argv[])
347 OM_uint32 minor_status;
348 gss_buffer_desc in_buf;
349 gss_OID nt_krb5_name_oid = (gss_OID)GSS_KRB5_NT_PRINCIPAL_NAME;
350 auth_gssapi_name names[4];
351 kadm5_config_params params;
353 const char *pid_file = NULL;
354 char **db_args = NULL, **tmpargs;
355 const char *acl_file;
356 int ret, i, db_args_size = 0, strong_random = 1, proponly = 0;
358 setlocale(LC_ALL, "");
359 setvbuf(stderr, NULL, _IONBF, 0);
361 names[0].name = names[1].name = names[2].name = names[3].name = NULL;
362 names[0].type = names[1].type = names[2].type = names[3].type =
365 progname = (strrchr(argv[0], '/') != NULL) ? strrchr(argv[0], '/') + 1 :
368 memset(¶ms, 0, sizeof(params));
372 if (strcmp(*argv, "-x") == 0) {
377 tmpargs = realloc(db_args, sizeof(char *) * (db_args_size + 1));
378 if (tmpargs == NULL) {
379 fprintf(stderr, _("%s: cannot initialize. Not enough "
380 "memory\n"), progname);
384 db_args[db_args_size - 1] = *argv;
385 db_args[db_args_size] = NULL;
386 } else if (strcmp(*argv, "-r") == 0) {
390 params.realm = *argv;
391 params.mask |= KADM5_CONFIG_REALM;
394 } else if (strcmp(*argv, "-m") == 0) {
395 params.mkey_from_kbd = 1;
396 params.mask |= KADM5_CONFIG_MKEY_FROM_KBD;
397 } else if (strcmp(*argv, "-nofork") == 0) {
399 #ifdef USE_PASSWORD_SERVER
400 } else if (strcmp(*argv, "-passwordserver") == 0) {
401 kadm5_set_use_password_server();
403 #ifndef DISABLE_IPROP
404 } else if (strcmp(*argv, "-proponly") == 0) {
407 } else if (strcmp(*argv, "-port") == 0) {
411 params.kadmind_port = atoi(*argv);
412 params.mask |= KADM5_CONFIG_KADMIND_PORT;
413 } else if (strcmp(*argv, "-P") == 0) {
418 } else if (strcmp(*argv, "-W") == 0) {
420 } else if (strcmp(*argv, "-p") == 0) {
425 } else if (strcmp(*argv, "-F") == 0) {
430 } else if (strcmp(*argv, "-K") == 0) {
435 } else if (strcmp(*argv, "-k") == 0) {
449 ret = kadm5_init_krb5_context(&context);
451 fprintf(stderr, _("%s: %s while initializing context, aborting\n"),
452 progname, error_message(ret));
456 krb5_klog_init(context, "admin_server", progname, 1);
458 ret = kadm5_init(context, "kadmind", NULL, NULL, ¶ms,
459 KADM5_STRUCT_VERSION, KADM5_API_VERSION_4, db_args,
460 &global_server_handle);
462 fail_to_start(ret, _("initializing"));
464 ret = kadm5_get_config_params(context, 1, ¶ms, ¶ms);
466 fail_to_start(ret, _("getting config parameters"));
467 if (!(params.mask & KADM5_CONFIG_REALM))
468 fail_to_start(0, _("Missing required realm configuration"));
469 if (!(params.mask & KADM5_CONFIG_ACL_FILE))
470 fail_to_start(0, _("Missing required ACL file configuration"));
471 if (proponly && !params.iprop_enabled) {
472 fail_to_start(0, _("-proponly can only be used when "
473 "iprop_enable is true"));
476 ret = setup_loop(¶ms, proponly, &vctx);
478 fail_to_start(ret, _("initializing network"));
480 names[0].name = build_princ_name(KADM5_ADMIN_SERVICE, params.realm);
481 names[1].name = build_princ_name(KADM5_CHANGEPW_SERVICE, params.realm);
482 if (names[0].name == NULL || names[1].name == NULL)
483 fail_to_start(0, _("Cannot build GSSAPI auth names"));
485 ret = setup_kdb_keytab();
487 fail_to_start(0, _("Cannot set up KDB keytab"));
489 if (svcauth_gssapi_set_names(names, 2) == FALSE)
490 fail_to_start(0, _("Cannot set GSSAPI authentication names"));
492 /* if set_names succeeded, this will too */
493 in_buf.value = names[1].name;
494 in_buf.length = strlen(names[1].name) + 1;
495 (void)gss_import_name(&minor_status, &in_buf, nt_krb5_name_oid,
498 svcauth_gssapi_set_log_badauth2_func(log_badauth, NULL);
499 svcauth_gssapi_set_log_badverf_func(log_badverf, NULL);
500 svcauth_gssapi_set_log_miscerr_func(log_miscerr, NULL);
502 svcauth_gss_set_log_badauth2_func(log_badauth, NULL);
503 svcauth_gss_set_log_badverf_func(log_badverf, NULL);
504 svcauth_gss_set_log_miscerr_func(log_miscerr, NULL);
506 if (svcauth_gss_set_svc_name(GSS_C_NO_NAME) != TRUE)
507 fail_to_start(0, _("Cannot initialize GSSAPI service name"));
509 acl_file = (*params.acl_file != '\0') ? params.acl_file : NULL;
510 ret = auth_init(context, acl_file);
512 fail_to_start(ret, _("initializing ACL file"));
514 if (!nofork && daemon(0, 0) != 0)
515 fail_to_start(errno, _("spawning daemon process"));
516 if (pid_file != NULL) {
517 ret = write_pid_file(pid_file);
519 fail_to_start(ret, _("creating PID file"));
522 krb5_klog_syslog(LOG_INFO, _("Seeding random number generator"));
523 ret = krb5_c_random_os_entropy(context, strong_random, NULL);
525 fail_to_start(ret, _("getting random seed"));
527 if (params.iprop_enabled == TRUE) {
528 ulog_set_role(context, IPROP_MASTER);
530 ret = ulog_map(context, params.iprop_logfile, params.iprop_ulogsize);
532 fail_to_start(ret, _("mapping update log"));
536 _("%s: create IPROP svc (PROG=%d, VERS=%d)\n"),
537 progname, KRB5_IPROP_PROG, KRB5_IPROP_VERS);
541 if (kprop_port == NULL)
542 kprop_port = getenv("KPROP_PORT");
544 krb5_klog_syslog(LOG_INFO, _("starting"));
546 fprintf(stderr, _("%s: starting...\n"), progname);
549 krb5_klog_syslog(LOG_INFO, _("finished, exiting"));
551 /* Clean up memory, etc */
552 svcauth_gssapi_unset_names();
553 kadm5_destroy(global_server_handle);
556 (void)gss_release_name(&minor_status, &gss_changepw_name);
557 (void)gss_release_name(&minor_status, &gss_oldchangepw_name);
558 for (i = 0; i < 4; i++)
561 krb5_klog_close(context);
562 krb5_free_context(context);