3e81d9dca4f444129fdb952b7ce77877070eb316
[krb5.git] / src / kadmin / server / ovsec_kadmd.c
1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /*
3  * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved
4  *
5  */
6
7 /*
8  * Copyright (C) 1998 by the FundsXpress, INC.
9  *
10  * All rights reserved.
11  *
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.
16  *
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.
27  *
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.
31  */
32
33 #include    <errno.h>
34 #include    <stdio.h>
35 #include    <signal.h>
36 #include    <syslog.h>
37 #include    <sys/types.h>
38 #ifdef _AIX
39 #include    <sys/select.h>
40 #endif
41 #include    <sys/time.h>
42 #include    <sys/socket.h>
43 #include    <unistd.h>
44 #include    <netinet/in.h>
45 #include    <arpa/inet.h>  /* inet_ntoa */
46 #include    <netdb.h>
47 #include    <gssrpc/rpc.h>
48 #include    <gssapi/gssapi.h>
49 #include    "gssapiP_krb5.h" /* for kg_get_context */
50 #include    <gssrpc/auth_gssapi.h>
51 #include    <kadm5/admin.h>
52 #include    <kadm5/kadm_rpc.h>
53 #include    <kadm5/server_acl.h>
54 #include    <adm_proto.h>
55 #include    "kdb_kt.h"  /* for krb5_ktkdb_set_context */
56 #include    <string.h>
57 #include    "kadm5/server_internal.h" /* XXX for kadm5_server_handle_t */
58 #include    <kdb_log.h>
59
60 #include    "misc.h"
61
62 #ifdef PURIFY
63 #include    "purify.h"
64
65 int     signal_pure_report = 0;
66 int     signal_pure_clear = 0;
67 void    request_pure_report(int);
68 void    request_pure_clear(int);
69 #endif /* PURIFY */
70
71 #if defined(NEED_DAEMON_PROTO)
72 extern int daemon(int, int);
73 #endif
74
75 void    setup_signal_handlers(iprop_role iproprole);
76 void    request_exit(int);
77 void    request_hup(int);
78 void    reset_db(void);
79
80 #ifdef POSIX_SIGNALS
81 static struct sigaction s_action;
82 #endif /* POSIX_SIGNALS */
83
84
85 #define TIMEOUT 15
86
87 gss_name_t gss_changepw_name = NULL, gss_oldchangepw_name = NULL;
88 gss_name_t gss_kadmin_name = NULL;
89 void *global_server_handle;
90
91 extern krb5_keylist_node  *master_keylist;
92
93 char *build_princ_name(char *name, char *realm);
94 void log_badauth(OM_uint32 major, OM_uint32 minor,
95                  struct sockaddr_in *addr, char *data);
96 void log_badverf(gss_name_t client_name, gss_name_t server_name,
97                  struct svc_req *rqst, struct rpc_msg *msg,
98                  char *data);
99 void log_miscerr(struct svc_req *rqst, struct rpc_msg *msg, char
100                  *error, char *data);
101 void log_badauth_display_status(char *msg, OM_uint32 major, OM_uint32 minor);
102 void log_badauth_display_status_1(char *m, OM_uint32 code, int type,
103                                   int rec);
104
105 int schpw;
106 void do_schpw(int s, kadm5_config_params *params);
107
108 #ifndef DISABLE_IPROP
109 int ipropfd;
110 #endif
111
112 #ifdef USE_PASSWORD_SERVER
113 void kadm5_set_use_password_server (void);
114 #endif
115
116 /*
117  * Function: usage
118  *
119  * Purpose: print out the server usage message
120  *
121  * Arguments:
122  * Requires:
123  * Effects:
124  * Modifies:
125  */
126
127 static void usage()
128 {
129     fprintf(stderr, _("Usage: kadmind [-x db_args]* [-r realm] [-m] [-nofork] "
130                       "[-port port-number]\n"
131                       "\t\t[-P pid_file]\n"
132                       "\nwhere,\n\t[-x db_args]* - any number of database "
133                       "specific arguments.\n"
134                       "\t\t\tLook at each database documentation for "
135                       "supported arguments\n"));
136     exit(1);
137 }
138
139 /*
140  * Function: display_status
141  *
142  * Purpose: displays GSS-API messages
143  *
144  * Arguments:
145  *
146  *      msg             a string to be displayed with the message
147  *      maj_stat        the GSS-API major status code
148  *      min_stat        the GSS-API minor status code
149  *
150  * Effects:
151  *
152  * The GSS-API messages associated with maj_stat and min_stat are
153  * displayed on stderr, each preceeded by "GSS-API error <msg>: " and
154  * followed by a newline.
155  */
156 static void display_status_1(char *, OM_uint32, int);
157
158 static void display_status(msg, maj_stat, min_stat)
159     char *msg;
160     OM_uint32 maj_stat;
161     OM_uint32 min_stat;
162 {
163     display_status_1(msg, maj_stat, GSS_C_GSS_CODE);
164     display_status_1(msg, min_stat, GSS_C_MECH_CODE);
165 }
166
167 static void display_status_1(m, code, type)
168     char *m;
169     OM_uint32 code;
170     int type;
171 {
172     OM_uint32 maj_stat, min_stat;
173     gss_buffer_desc msg;
174     OM_uint32 msg_ctx;
175
176     msg_ctx = 0;
177     while (1) {
178         maj_stat = gss_display_status(&min_stat, code,
179                                       type, GSS_C_NULL_OID,
180                                       &msg_ctx, &msg);
181         fprintf(stderr, _("GSS-API error %s: %s\n"), m, (char *)msg.value);
182         (void) gss_release_buffer(&min_stat, &msg);
183
184         if (!msg_ctx)
185             break;
186     }
187 }
188
189 /*
190  * Function: write_pid_file
191  *
192  * Purpose: writes the current process PID to a file
193  *
194  * Arguments:
195  *
196  *      pid_file        path to output file
197  *      <return value>  0 on success, error code on failure
198  *
199  * Effects:
200  *
201  * The current process PID, obtained from getpid(), is written to the path
202  * given in pid_file, overwriting the existing contents if the file already
203  * exists.  The PID will be followed by a newline.
204  */
205 static int
206 write_pid_file(const char *pid_file)
207 {
208     FILE *file;
209     unsigned long pid;
210
211     file = fopen(pid_file, "w");
212     if (file == NULL)
213         return errno;
214     pid = (unsigned long) getpid();
215     if (fprintf(file, "%ld\n", pid) < 0 || fclose(file) == EOF)
216         return errno;
217     return 0;
218 }
219
220 /* XXX yuck.  the signal handlers need this */
221 static krb5_context context;
222
223 static krb5_context hctx;
224
225 int nofork = 0;
226
227 int main(int argc, char *argv[])
228 {
229     extern     char *optarg;
230     extern     int optind, opterr;
231     int ret;
232     OM_uint32 OMret, major_status, minor_status;
233     char *whoami;
234     gss_buffer_desc in_buf;
235     auth_gssapi_name names[4];
236     gss_buffer_desc gssbuf;
237     gss_OID nt_krb5_name_oid;
238     kadm5_config_params params;
239     char **db_args      = NULL;
240     int    db_args_size = 0;
241     char *errmsg;
242     int i;
243     int strong_random = 1;
244     const char *pid_file = NULL;
245
246     kdb_log_context *log_ctx;
247
248     setlocale(LC_MESSAGES, "");
249     setvbuf(stderr, NULL, _IONBF, 0);
250
251     /* This is OID value the Krb5_Name NameType */
252     gssbuf.value = "{1 2 840 113554 1 2 2 1}";
253     gssbuf.length = strlen(gssbuf.value);
254     major_status = gss_str_to_oid(&minor_status, &gssbuf, &nt_krb5_name_oid);
255     if (major_status != GSS_S_COMPLETE) {
256         fprintf(stderr, _("Couldn't create KRB5 Name NameType OID\n"));
257         display_status("str_to_oid", major_status, minor_status);
258         exit(1);
259     }
260
261     names[0].name = names[1].name = names[2].name = names[3].name = NULL;
262     names[0].type = names[1].type = names[2].type = names[3].type =
263         nt_krb5_name_oid;
264
265 #ifdef PURIFY
266     purify_start_batch();
267 #endif /* PURIFY */
268     whoami = (strrchr(argv[0], '/') ? strrchr(argv[0], '/')+1 : argv[0]);
269
270     nofork = 0;
271
272     memset(&params, 0, sizeof(params));
273
274     argc--; argv++;
275     while (argc) {
276         if (strcmp(*argv, "-x") == 0) {
277             argc--; argv++;
278             if (!argc)
279                 usage();
280             db_args_size++;
281             {
282                 char **temp = realloc( db_args, sizeof(char*) * (db_args_size+1)); /* one for NULL */
283                 if( temp == NULL )
284                 {
285                     fprintf(stderr, _("%s: cannot initialize. Not enough "
286                                       "memory\n"), whoami);
287                     exit(1);
288                 }
289                 db_args = temp;
290             }
291             db_args[db_args_size-1] = *argv;
292             db_args[db_args_size]   = NULL;
293         }else if (strcmp(*argv, "-r") == 0) {
294             argc--; argv++;
295             if (!argc)
296                 usage();
297             params.realm = *argv;
298             params.mask |= KADM5_CONFIG_REALM;
299             argc--; argv++;
300             continue;
301         } else if (strcmp(*argv, "-m") == 0) {
302             params.mkey_from_kbd = 1;
303             params.mask |= KADM5_CONFIG_MKEY_FROM_KBD;
304         } else if (strcmp(*argv, "-nofork") == 0) {
305             nofork = 1;
306 #ifdef USE_PASSWORD_SERVER
307         } else if (strcmp(*argv, "-passwordserver") == 0) {
308             kadm5_set_use_password_server ();
309 #endif
310         } else if(strcmp(*argv, "-port") == 0) {
311             argc--; argv++;
312             if(!argc)
313                 usage();
314             params.kadmind_port = atoi(*argv);
315             params.mask |= KADM5_CONFIG_KADMIND_PORT;
316         } else if (strcmp(*argv, "-P") == 0) {
317             argc--; argv++;
318             if (!argc)
319                 usage();
320             pid_file = *argv;
321         } else if (strcmp(*argv, "-W") == 0) {
322             strong_random = 0;
323         } else
324             break;
325         argc--; argv++;
326     }
327
328     if (argc != 0)
329         usage();
330
331     if ((ret = kadm5_init_krb5_context(&context))) {
332         fprintf(stderr, _("%s: %s while initializing context, aborting\n"),
333                 whoami, error_message(ret));
334         exit(1);
335     }
336
337     krb5_klog_init(context, "admin_server", whoami, 1);
338
339     if((ret = kadm5_init(context, "kadmind", NULL,
340                          NULL, &params,
341                          KADM5_STRUCT_VERSION,
342                          KADM5_API_VERSION_3,
343                          db_args,
344                          &global_server_handle)) != KADM5_OK) {
345         const char *e_txt = krb5_get_error_message (context, ret);
346         krb5_klog_syslog(LOG_ERR, _("%s while initializing, aborting"), e_txt);
347         fprintf(stderr, _("%s: %s while initializing, aborting\n"),
348                 whoami, e_txt);
349         krb5_klog_close(context);
350         exit(1);
351     }
352
353     if ((ret = kadm5_get_config_params(context, 1, &params,
354                                        &params))) {
355         const char *e_txt = krb5_get_error_message (context, ret);
356         krb5_klog_syslog(LOG_ERR, _("%s: %s while initializing, aborting"),
357                          whoami, e_txt);
358         fprintf(stderr, _("%s: %s while initializing, aborting\n"),
359                 whoami, e_txt);
360         kadm5_destroy(global_server_handle);
361         krb5_klog_close(context);
362         exit(1);
363     }
364
365 #define REQUIRED_PARAMS (KADM5_CONFIG_REALM | KADM5_CONFIG_ACL_FILE)
366
367     if ((params.mask & REQUIRED_PARAMS) != REQUIRED_PARAMS) {
368         krb5_klog_syslog(LOG_ERR,
369                          _("%s: Missing required configuration values "
370                            "(%lx) while initializing, aborting"), whoami,
371                          (params.mask & REQUIRED_PARAMS) ^ REQUIRED_PARAMS);
372         fprintf(stderr, _("%s: Missing required configuration values "
373                           "(%lx) while initializing, aborting\n"), whoami,
374                 (params.mask & REQUIRED_PARAMS) ^ REQUIRED_PARAMS);
375         krb5_klog_close(context);
376         kadm5_destroy(global_server_handle);
377         exit(1);
378     }
379
380 #define server_handle ((kadm5_server_handle_t)global_server_handle)
381     if ((ret = loop_add_udp_port(server_handle->params.kpasswd_port))
382         || (ret = loop_add_tcp_port(server_handle->params.kpasswd_port))
383         || (ret = loop_add_rpc_service(server_handle->params.kadmind_port,
384                                   KADM, KADMVERS, kadm_1))
385 #ifndef DISABLE_IPROP
386         || (server_handle->params.iprop_enabled
387             ? (ret = loop_add_rpc_service(server_handle->params.iprop_port,
388                                      KRB5_IPROP_PROG, KRB5_IPROP_VERS,
389                                      krb5_iprop_prog_1))
390             : 0)
391 #endif
392 #undef server_handle
393         || (ret = loop_setup_network(global_server_handle, whoami, 0))) {
394         const char *e_txt = krb5_get_error_message (context, ret);
395         krb5_klog_syslog(LOG_ERR, _("%s: %s while initializing network, "
396                                     "aborting"), whoami, e_txt);
397         fprintf(stderr, _("%s: %s while initializing network, aborting\n"),
398                 whoami, e_txt);
399         kadm5_destroy(global_server_handle);
400         krb5_klog_close(context);
401         exit(1);
402     }
403
404     names[0].name = build_princ_name(KADM5_ADMIN_SERVICE, params.realm);
405     names[1].name = build_princ_name(KADM5_CHANGEPW_SERVICE, params.realm);
406     if (names[0].name == NULL || names[1].name == NULL) {
407         krb5_klog_syslog(LOG_ERR, _("Cannot build GSS-API authentication "
408                                     "names, failing."));
409         fprintf(stderr, _("%s: Cannot build GSS-API authentication names.\n"),
410                 whoami);
411         kadm5_destroy(global_server_handle);
412         krb5_klog_close(context);
413         exit(1);
414     }
415
416     /*
417      * Go through some contortions to point gssapi at a kdb keytab.
418      * This prevents kadmind from needing to use an actual file-based
419      * keytab.
420      */
421     /* XXX extract kadm5's krb5_context */
422     hctx = ((kadm5_server_handle_t)global_server_handle)->context;
423     /* Set ktkdb's internal krb5_context. */
424     ret = krb5_ktkdb_set_context(hctx);
425     if (ret) {
426         krb5_klog_syslog(LOG_ERR,
427                          _("Can't set kdb keytab's internal context."));
428         goto kterr;
429     }
430     ret = krb5_kt_register(context, &krb5_kt_kdb_ops);
431     if (ret) {
432         krb5_klog_syslog(LOG_ERR, _("Can't register kdb keytab."));
433         goto kterr;
434     }
435     /* Tell gssapi about the kdb keytab. */
436     ret = krb5_gss_register_acceptor_identity("KDB:");
437     if (ret) {
438         krb5_klog_syslog(LOG_ERR, _("Can't register acceptor keytab."));
439         goto kterr;
440     }
441 kterr:
442     if (ret) {
443         krb5_klog_syslog(LOG_ERR, "%s", krb5_get_error_message (context, ret));
444         fprintf(stderr, _("%s: Can't set up keytab for RPC.\n"), whoami);
445         kadm5_destroy(global_server_handle);
446         krb5_klog_close(context);
447         exit(1);
448     }
449
450     if (svcauth_gssapi_set_names(names, 2) == FALSE) {
451         krb5_klog_syslog(LOG_ERR, _("Cannot set GSS-API authentication names "
452                                     "(keytab not present?), failing."));
453         fprintf(stderr, _("%s: Cannot set GSS-API authentication names.\n"),
454                 whoami);
455         svcauth_gssapi_unset_names();
456         kadm5_destroy(global_server_handle);
457         krb5_klog_close(context);
458         exit(1);
459     }
460
461     /* if set_names succeeded, this will too */
462     in_buf.value = names[1].name;
463     in_buf.length = strlen(names[1].name) + 1;
464     (void) gss_import_name(&OMret, &in_buf, nt_krb5_name_oid,
465                            &gss_changepw_name);
466
467     svcauth_gssapi_set_log_badauth_func(log_badauth, NULL);
468     svcauth_gssapi_set_log_badverf_func(log_badverf, NULL);
469     svcauth_gssapi_set_log_miscerr_func(log_miscerr, NULL);
470
471     svcauth_gss_set_log_badauth_func(log_badauth, NULL);
472     svcauth_gss_set_log_badverf_func(log_badverf, NULL);
473     svcauth_gss_set_log_miscerr_func(log_miscerr, NULL);
474
475     if (svcauth_gss_set_svc_name(GSS_C_NO_NAME) != TRUE) {
476         fprintf(stderr, _("%s: Cannot initialize RPCSEC_GSS service name.\n"),
477                 whoami);
478         exit(1);
479     }
480
481     if ((ret = kadm5int_acl_init(context, 0, params.acl_file))) {
482         errmsg = krb5_get_error_message (context, ret);
483         krb5_klog_syslog(LOG_ERR, _("Cannot initialize acl file: %s"), errmsg);
484         fprintf(stderr, _("%s: Cannot initialize acl file: %s\n"),
485                 whoami, errmsg);
486         svcauth_gssapi_unset_names();
487         kadm5_destroy(global_server_handle);
488         krb5_klog_close(context);
489         exit(1);
490     }
491
492     if (!nofork && (ret = daemon(0, 0))) {
493         ret = errno;
494         errmsg = krb5_get_error_message (context, ret);
495         krb5_klog_syslog(LOG_ERR, _("Cannot detach from tty: %s"), errmsg);
496         fprintf(stderr, _("%s: Cannot detach from tty: %s\n"), whoami, errmsg);
497         svcauth_gssapi_unset_names();
498         kadm5_destroy(global_server_handle);
499         krb5_klog_close(context);
500         exit(1);
501     }
502     if (pid_file != NULL) {
503         ret = write_pid_file(pid_file);
504         if (ret) {
505             errmsg = krb5_get_error_message(context, ret);
506             krb5_klog_syslog(LOG_ERR, _("Cannot create PID file %s: %s"),
507                              pid_file, errmsg);
508             svcauth_gssapi_unset_names();
509             kadm5_destroy(global_server_handle);
510             krb5_klog_close(context);
511             exit(1);
512         }
513     }
514
515     krb5_klog_syslog(LOG_INFO, _("Seeding random number generator"));
516     ret = krb5_c_random_os_entropy(context, strong_random, NULL);
517     if (ret) {
518         krb5_klog_syslog(LOG_ERR, _("Error getting random seed: %s, aborting"),
519                          krb5_get_error_message(context, ret));
520         svcauth_gssapi_unset_names();
521         kadm5_destroy(global_server_handle);
522         krb5_klog_close(context);
523         exit(1);
524     }
525
526     if (params.iprop_enabled == TRUE)
527         ulog_set_role(hctx, IPROP_MASTER);
528     else
529         ulog_set_role(hctx, IPROP_NULL);
530
531     log_ctx = hctx->kdblog_context;
532
533     if (log_ctx && (log_ctx->iproprole == IPROP_MASTER)) {
534         /*
535          * IProp is enabled, so let's map in the update log
536          * and setup the service.
537          */
538         if ((ret = ulog_map(hctx, params.iprop_logfile,
539                             params.iprop_ulogsize, FKADMIND, db_args)) != 0) {
540             fprintf(stderr,
541                     _("%s: %s while mapping update log (`%s.ulog')\n"),
542                     whoami, error_message(ret), params.dbname);
543             krb5_klog_syslog(LOG_ERR,
544                              _("%s while mapping update log (`%s.ulog')"),
545                              error_message(ret), params.dbname);
546             krb5_klog_close(context);
547             exit(1);
548         }
549
550
551         if (nofork)
552             fprintf(stderr,
553                     _("%s: create IPROP svc (PROG=%d, VERS=%d)\n"),
554                     whoami, KRB5_IPROP_PROG, KRB5_IPROP_VERS);
555
556 #if 0
557         if (!svc_create(krb5_iprop_prog_1,
558                         KRB5_IPROP_PROG, KRB5_IPROP_VERS,
559                         "circuit_v")) {
560             fprintf(stderr,
561                     _("%s: Cannot create IProp RPC service (PROG=%d, VERS=%d)\n"),
562                     whoami,
563                     KRB5_IPROP_PROG, KRB5_IPROP_VERS);
564             krb5_klog_syslog(LOG_ERR,
565                              _("Cannot create IProp RPC service (PROG=%d, VERS=%d), failing."),
566                              KRB5_IPROP_PROG, KRB5_IPROP_VERS);
567             krb5_klog_close(context);
568             exit(1);
569         }
570 #endif
571
572 #if 0 /* authgss only? */
573         if ((ret = kiprop_get_adm_host_srv_name(context,
574                                                 params.realm,
575                                                 &kiprop_name)) != 0) {
576             krb5_klog_syslog(LOG_ERR,
577                              _("%s while getting IProp svc name, failing"),
578                              error_message(ret));
579             fprintf(stderr,
580                     _("%s: %s while getting IProp svc name, failing\n"),
581                     whoami, error_message(ret));
582             krb5_klog_close(context);
583             exit(1);
584         }
585
586         auth_gssapi_name iprop_name;
587         iprop_name.name = build_princ_name(foo, bar);
588         if (iprop_name.name == NULL) {
589             foo error;
590         }
591         iprop_name.type = nt_krb5_name_oid;
592         if (svcauth_gssapi_set_names(&iprop_name, 1) == FALSE) {
593             foo error;
594         }
595         if (!rpc_gss_set_svc_name(kiprop_name, "kerberos_v5", 0,
596                                   KRB5_IPROP_PROG, KRB5_IPROP_VERS)) {
597             rpc_gss_error_t err;
598             (void) rpc_gss_get_error(&err);
599
600             krb5_klog_syslog(LOG_ERR,
601                              _("Unable to set RPCSEC_GSS service name (`%s'), failing."),
602                              kiprop_name ? kiprop_name : "<null>");
603
604             fprintf(stderr,
605                     _("%s: Unable to set RPCSEC_GSS service name (`%s'), failing.\n"),
606                     whoami,
607                     kiprop_name ? kiprop_name : "<null>");
608
609             if (nofork) {
610                 fprintf(stderr,
611                         "%s: set svc name (rpcsec err=%d, sys err=%d)\n",
612                         whoami,
613                         err.rpc_gss_error,
614                         err.system_error);
615             }
616
617             exit(1);
618         }
619         free(kiprop_name);
620 #endif
621     }
622
623     setup_signal_handlers(log_ctx->iproprole);
624     krb5_klog_syslog(LOG_INFO, _("starting"));
625     if (nofork)
626         fprintf(stderr, _("%s: starting...\n"), whoami);
627
628     loop_listen_and_process(global_server_handle, whoami, reset_db);
629     krb5_klog_syslog(LOG_INFO, _("finished, exiting"));
630
631     /* Clean up memory, etc */
632     svcauth_gssapi_unset_names();
633     kadm5_destroy(global_server_handle);
634     loop_closedown_network();
635     kadm5int_acl_finish(context, 0);
636     if(gss_changepw_name) {
637         (void) gss_release_name(&OMret, &gss_changepw_name);
638     }
639     if(gss_oldchangepw_name) {
640         (void) gss_release_name(&OMret, &gss_oldchangepw_name);
641     }
642     for(i = 0 ; i < 4; i++) {
643         if (names[i].name) {
644             free(names[i].name);
645         }
646     }
647
648     krb5_klog_close(context);
649     krb5_free_context(context);
650     exit(2);
651 }
652
653 /*
654  * Function: setup_signal_handlers
655  *
656  * Purpose: Setup signal handling functions using POSIX's sigaction()
657  * if possible, otherwise with System V's signal().
658  */
659
660 void setup_signal_handlers(iprop_role iproprole) {
661 #ifdef POSIX_SIGNALS
662     (void) sigemptyset(&s_action.sa_mask);
663     s_action.sa_handler = request_exit;
664     (void) sigaction(SIGINT, &s_action, (struct sigaction *) NULL);
665     (void) sigaction(SIGTERM, &s_action, (struct sigaction *) NULL);
666     (void) sigaction(SIGQUIT, &s_action, (struct sigaction *) NULL);
667     s_action.sa_handler = request_hup;
668     (void) sigaction(SIGHUP, &s_action, (struct sigaction *) NULL);
669     s_action.sa_handler = SIG_IGN;
670     (void) sigaction(SIGPIPE, &s_action, (struct sigaction *) NULL);
671 #ifdef PURIFY
672     s_action.sa_handler = request_pure_report;
673     (void) sigaction(SIGUSR1, &s_action, (struct sigaction *) NULL);
674     s_action.sa_handler = request_pure_clear;
675     (void) sigaction(SIGUSR2, &s_action, (struct sigaction *) NULL);
676 #endif /* PURIFY */
677
678     /*
679      * IProp will fork for a full-resync, we don't want to
680      * wait on it and we don't want the living dead procs either.
681      */
682     if (iproprole == IPROP_MASTER) {
683         s_action.sa_handler = SIG_IGN;
684         (void) sigaction(SIGCHLD, &s_action, (struct sigaction *) NULL);
685     }
686 #else /* POSIX_SIGNALS */
687     signal(SIGINT, request_exit);
688     signal(SIGTERM, request_exit);
689     signal(SIGQUIT, request_exit);
690     signal(SIGHUP, request_hup);
691     signal(SIGPIPE, SIG_IGN);
692 #ifdef PURIFY
693     signal(SIGUSR1, request_pure_report);
694     signal(SIGUSR2, request_pure_clear);
695 #endif /* PURIFY */
696
697     /*
698      * IProp will fork for a full-resync, we don't want to
699      * wait on it and we don't want the living dead procs either.
700      */
701     if (iproprole == IPROP_MASTER)
702         (void) signal(SIGCHLD, SIG_IGN);
703 #endif /* POSIX_SIGNALS */
704 }
705
706 #ifdef PURIFY
707 /*
708  * Function: request_pure_report
709  *
710  * Purpose: sets flag saying the server got a signal and that it should
711  *              dump a purify report when convenient.
712  *
713  * Arguments:
714  * Requires:
715  * Effects:
716  * Modifies:
717  *      sets signal_pure_report to one
718  */
719
720 void request_pure_report(int signum)
721 {
722     krb5_klog_syslog(LOG_DEBUG, "Got signal to request a Purify report");
723     signal_pure_report = 1;
724     return;
725 }
726
727 /*
728  * Function: request_pure_clear
729  *
730  * Purpose: sets flag saying the server got a signal and that it should
731  *              dump a purify report when convenient, then clear the
732  *              purify tables.
733  *
734  * Arguments:
735  * Requires:
736  * Effects:
737  * Modifies:
738  *      sets signal_pure_report to one
739  *      sets signal_pure_clear to one
740  */
741
742 void request_pure_clear(int signum)
743 {
744     krb5_klog_syslog(LOG_DEBUG, "Got signal to request a Purify report and clear the old Purify info");
745     signal_pure_report = 1;
746     signal_pure_clear = 1;
747     return;
748 }
749 #endif /* PURIFY */
750
751 /*
752  * Function: request_hup
753  *
754  * Purpose: sets flag saying the server got a signal and that it should
755  *              reset the database files when convenient.
756  *
757  * Arguments:
758  * Requires:
759  * Effects:
760  * Modifies:
761  *      sets signal_requests_reset to one
762  */
763
764 void request_hup(int signum)
765 {
766     signal_requests_reset = 1;
767     return;
768 }
769
770 /*
771  * Function: reset_db
772  *
773  * Purpose: flushes the currently opened database files to disk.
774  *
775  * Arguments:
776  * Requires:
777  * Effects:
778  *
779  * Currently, just sets signal_requests_reset to 0.  The kdb and adb
780  * libraries used to be sufficiently broken that it was prudent to
781  * close and reopen the databases periodically.  They are no longer
782  * that broken, so this function is not necessary.
783  */
784 void reset_db(void)
785 {
786 #ifdef notdef
787     kadm5_ret_t ret;
788     char *errmsg;
789
790     if (ret = kadm5_flush(global_server_handle)) {
791         krb5_klog_syslog(LOG_ERR, "FATAL ERROR!  %s while flushing databases.  "
792                          "Databases may be corrupt!  Aborting.",
793                          krb5_get_error_message (context, ret));
794         krb5_klog_close(context);
795         exit(3);
796     }
797 #endif
798
799     return;
800 }
801
802 /*
803  * Function: request_exit
804  *
805  * Purpose: sets flags saying the server got a signal and that it
806  *          should exit when convient.
807  *
808  * Arguments:
809  * Requires:
810  * Effects:
811  *      modifies signal_requests_exit which ideally makes the server exit
812  *      at some point.
813  *
814  * Modifies:
815  *      signal_requests_exit
816  */
817
818 void request_exit(int signum)
819 {
820     krb5_klog_syslog(LOG_DEBUG, _("Got signal to request exit"));
821     signal_requests_exit = 1;
822     return;
823 }
824
825 /*
826  * Function: build_princ_name
827  *
828  * Purpose: takes a name and a realm and builds a string that can be
829  *          consumed by krb5_parse_name.
830  *
831  * Arguments:
832  *      name                (input) name to be part of principal
833  *      realm               (input) realm part of principal
834  *      <return value>      char * pointing to "name@realm"
835  *
836  * Requires:
837  *      name be non-null.
838  *
839  * Effects:
840  * Modifies:
841  */
842
843 char *build_princ_name(char *name, char *realm)
844 {
845     char *fullname;
846
847     if (realm) {
848         if (asprintf(&fullname, "%s@%s", name, realm) < 0)
849             fullname = NULL;
850     } else
851         fullname = strdup(name);
852
853     return fullname;
854 }
855
856 /*
857  * Function: log_badverf
858  *
859  * Purpose: Call from GSS-API Sun RPC for garbled/forged/replayed/etc
860  * messages.
861  *
862  * Argiments:
863  *      client_name     (r) GSS-API client name
864  *      server_name     (r) GSS-API server name
865  *      rqst            (r) RPC service request
866  *      msg             (r) RPC message
867  *      data            (r) arbitrary data (NULL), not used
868  *
869  * Effects:
870  *
871  * Logs the invalid request via krb5_klog_syslog(); see functional spec for
872  * format.
873  */
874 void log_badverf(gss_name_t client_name, gss_name_t server_name,
875                  struct svc_req *rqst, struct rpc_msg *msg, char
876                  *data)
877 {
878     struct procnames {
879         rpcproc_t proc;
880         const char *proc_name;
881     };
882     static const struct procnames proc_names[] = {
883         {1, "CREATE_PRINCIPAL"},
884         {2, "DELETE_PRINCIPAL"},
885         {3, "MODIFY_PRINCIPAL"},
886         {4, "RENAME_PRINCIPAL"},
887         {5, "GET_PRINCIPAL"},
888         {6, "CHPASS_PRINCIPAL"},
889         {7, "CHRAND_PRINCIPAL"},
890         {8, "CREATE_POLICY"},
891         {9, "DELETE_POLICY"},
892         {10, "MODIFY_POLICY"},
893         {11, "GET_POLICY"},
894         {12, "GET_PRIVS"},
895         {13, "INIT"},
896         {14, "GET_PRINCS"},
897         {15, "GET_POLS"},
898         {16, "SETKEY_PRINCIPAL"},
899         {17, "SETV4KEY_PRINCIPAL"},
900         {18, "CREATE_PRINCIPAL3"},
901         {19, "CHPASS_PRINCIPAL3"},
902         {20, "CHRAND_PRINCIPAL3"},
903         {21, "SETKEY_PRINCIPAL3"},
904         {22, "PURGEKEYS"}
905     };
906 #define NPROCNAMES (sizeof (proc_names) / sizeof (struct procnames))
907     OM_uint32 minor;
908     gss_buffer_desc client, server;
909     gss_OID gss_type;
910     char *a;
911     rpcproc_t proc;
912     unsigned int i;
913     const char *procname;
914     size_t clen, slen;
915     char *cdots, *sdots;
916
917     client.length = 0;
918     client.value = NULL;
919     server.length = 0;
920     server.value = NULL;
921
922     (void) gss_display_name(&minor, client_name, &client, &gss_type);
923     (void) gss_display_name(&minor, server_name, &server, &gss_type);
924     if (client.value == NULL) {
925         client.value = "(null)";
926         clen = sizeof("(null)") -1;
927     } else {
928         clen = client.length;
929     }
930     trunc_name(&clen, &cdots);
931     if (server.value == NULL) {
932         server.value = "(null)";
933         slen = sizeof("(null)") - 1;
934     } else {
935         slen = server.length;
936     }
937     trunc_name(&slen, &sdots);
938     a = inet_ntoa(rqst->rq_xprt->xp_raddr.sin_addr);
939
940     proc = msg->rm_call.cb_proc;
941     procname = NULL;
942     for (i = 0; i < NPROCNAMES; i++) {
943         if (proc_names[i].proc == proc) {
944             procname = proc_names[i].proc_name;
945             break;
946         }
947     }
948     if (procname != NULL)
949         krb5_klog_syslog(LOG_NOTICE,
950                          _("WARNING! Forged/garbled request: %s, claimed "
951                            "client = %.*s%s, server = %.*s%s, addr = %s"),
952                          procname, (int) clen, (char *) client.value, cdots,
953                          (int) slen, (char *) server.value, sdots, a);
954     else
955         krb5_klog_syslog(LOG_NOTICE,
956                          _("WARNING! Forged/garbled request: %d, claimed "
957                            "client = %.*s%s, server = %.*s%s, addr = %s"),
958                          proc, (int) clen, (char *) client.value, cdots,
959                          (int) slen, (char *) server.value, sdots, a);
960
961     (void) gss_release_buffer(&minor, &client);
962     (void) gss_release_buffer(&minor, &server);
963 }
964
965 /*
966  * Function: log_miscerr
967  *
968  * Purpose: Callback from GSS-API Sun RPC for miscellaneous errors
969  *
970  * Arguments:
971  *      rqst            (r) RPC service request
972  *      msg             (r) RPC message
973  *      error           (r) error message from RPC
974  *      data            (r) arbitrary data (NULL), not used
975  *
976  * Effects:
977  *
978  * Logs the error via krb5_klog_syslog(); see functional spec for
979  * format.
980  */
981 void log_miscerr(struct svc_req *rqst, struct rpc_msg *msg,
982                  char *error, char *data)
983 {
984     char *a;
985
986     a = inet_ntoa(rqst->rq_xprt->xp_raddr.sin_addr);
987     krb5_klog_syslog(LOG_NOTICE, _("Miscellaneous RPC error: %s, %s"), a,
988                      error);
989 }
990
991
992
993 /*
994  * Function: log_badauth
995  *
996  * Purpose: Callback from GSS-API Sun RPC for authentication
997  * failures/errors.
998  *
999  * Arguments:
1000  *      major           (r) GSS-API major status
1001  *      minor           (r) GSS-API minor status
1002  *      addr            (r) originating address
1003  *      data            (r) arbitrary data (NULL), not used
1004  *
1005  * Effects:
1006  *
1007  * Logs the GSS-API error via krb5_klog_syslog(); see functional spec for
1008  * format.
1009  */
1010 void log_badauth(OM_uint32 major, OM_uint32 minor,
1011                  struct sockaddr_in *addr, char *data)
1012 {
1013     char *a;
1014
1015     /* Authentication attempt failed: <IP address>, <GSS-API error */
1016     /* strings> */
1017
1018     a = inet_ntoa(addr->sin_addr);
1019
1020     krb5_klog_syslog(LOG_NOTICE, _("Authentication attempt failed: %s, "
1021                                    "GSS-API error strings are:"), a);
1022     log_badauth_display_status("   ", major, minor);
1023     krb5_klog_syslog(LOG_NOTICE, _("   GSS-API error strings complete."));
1024 }
1025
1026 void log_badauth_display_status(char *msg, OM_uint32 major, OM_uint32 minor)
1027 {
1028     log_badauth_display_status_1(msg, major, GSS_C_GSS_CODE, 0);
1029     log_badauth_display_status_1(msg, minor, GSS_C_MECH_CODE, 0);
1030 }
1031
1032 void log_badauth_display_status_1(char *m, OM_uint32 code, int type,
1033                                   int rec)
1034 {
1035     OM_uint32 gssstat, minor_stat;
1036     gss_buffer_desc msg;
1037     OM_uint32 msg_ctx;
1038
1039     msg_ctx = 0;
1040     while (1) {
1041         gssstat = gss_display_status(&minor_stat, code,
1042                                      type, GSS_C_NULL_OID,
1043                                      &msg_ctx, &msg);
1044         if (gssstat != GSS_S_COMPLETE) {
1045             if (!rec) {
1046                 log_badauth_display_status_1(m,gssstat,GSS_C_GSS_CODE,1);
1047                 log_badauth_display_status_1(m, minor_stat,
1048                                              GSS_C_MECH_CODE, 1);
1049             } else
1050                 krb5_klog_syslog(LOG_ERR,
1051                                  _("GSS-API authentication error %.*s: "
1052                                    "recursive failure!"), (int) msg.length,
1053                                  (char *) msg.value);
1054             return;
1055         }
1056
1057         krb5_klog_syslog(LOG_NOTICE, "%s %.*s", m, (int)msg.length,
1058                          (char *)msg.value);
1059         (void) gss_release_buffer(&minor_stat, &msg);
1060
1061         if (!msg_ctx)
1062             break;
1063     }
1064 }