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