Imported Upstream version 1.10.2
[platform/upstream/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 #if defined(NEED_DAEMON_PROTO)
63 extern int daemon(int, int);
64 #endif
65
66 #define TIMEOUT 15
67
68 gss_name_t gss_changepw_name = NULL, gss_oldchangepw_name = NULL;
69 gss_name_t gss_kadmin_name = NULL;
70 void *global_server_handle;
71
72 extern krb5_keylist_node  *master_keylist;
73
74 char *build_princ_name(char *name, char *realm);
75 void log_badauth(OM_uint32 major, OM_uint32 minor,
76                  struct sockaddr_in *addr, char *data);
77 void log_badverf(gss_name_t client_name, gss_name_t server_name,
78                  struct svc_req *rqst, struct rpc_msg *msg,
79                  char *data);
80 void log_miscerr(struct svc_req *rqst, struct rpc_msg *msg, char
81                  *error, char *data);
82 void log_badauth_display_status(char *msg, OM_uint32 major, OM_uint32 minor);
83 void log_badauth_display_status_1(char *m, OM_uint32 code, int type,
84                                   int rec);
85
86 int schpw;
87 void do_schpw(int s, kadm5_config_params *params);
88
89 #ifndef DISABLE_IPROP
90 int ipropfd;
91 #endif
92
93 #ifdef USE_PASSWORD_SERVER
94 void kadm5_set_use_password_server (void);
95 #endif
96
97 /*
98  * Function: usage
99  *
100  * Purpose: print out the server usage message
101  *
102  * Arguments:
103  * Requires:
104  * Effects:
105  * Modifies:
106  */
107
108 static void usage()
109 {
110     fprintf(stderr, _("Usage: kadmind [-x db_args]* [-r realm] [-m] [-nofork] "
111                       "[-port port-number]\n"
112                       "\t\t[-P pid_file]\n"
113                       "\nwhere,\n\t[-x db_args]* - any number of database "
114                       "specific arguments.\n"
115                       "\t\t\tLook at each database documentation for "
116                       "supported arguments\n"));
117     exit(1);
118 }
119
120 /*
121  * Function: display_status
122  *
123  * Purpose: displays GSS-API messages
124  *
125  * Arguments:
126  *
127  *      msg             a string to be displayed with the message
128  *      maj_stat        the GSS-API major status code
129  *      min_stat        the GSS-API minor status code
130  *
131  * Effects:
132  *
133  * The GSS-API messages associated with maj_stat and min_stat are
134  * displayed on stderr, each preceeded by "GSS-API error <msg>: " and
135  * followed by a newline.
136  */
137 static void display_status_1(char *, OM_uint32, int);
138
139 static void display_status(msg, maj_stat, min_stat)
140     char *msg;
141     OM_uint32 maj_stat;
142     OM_uint32 min_stat;
143 {
144     display_status_1(msg, maj_stat, GSS_C_GSS_CODE);
145     display_status_1(msg, min_stat, GSS_C_MECH_CODE);
146 }
147
148 static void display_status_1(m, code, type)
149     char *m;
150     OM_uint32 code;
151     int type;
152 {
153     OM_uint32 maj_stat, min_stat;
154     gss_buffer_desc msg;
155     OM_uint32 msg_ctx;
156
157     msg_ctx = 0;
158     while (1) {
159         maj_stat = gss_display_status(&min_stat, code,
160                                       type, GSS_C_NULL_OID,
161                                       &msg_ctx, &msg);
162         fprintf(stderr, _("GSS-API error %s: %s\n"), m, (char *)msg.value);
163         (void) gss_release_buffer(&min_stat, &msg);
164
165         if (!msg_ctx)
166             break;
167     }
168 }
169
170 /*
171  * Function: write_pid_file
172  *
173  * Purpose: writes the current process PID to a file
174  *
175  * Arguments:
176  *
177  *      pid_file        path to output file
178  *      <return value>  0 on success, error code on failure
179  *
180  * Effects:
181  *
182  * The current process PID, obtained from getpid(), is written to the path
183  * given in pid_file, overwriting the existing contents if the file already
184  * exists.  The PID will be followed by a newline.
185  */
186 static int
187 write_pid_file(const char *pid_file)
188 {
189     FILE *file;
190     unsigned long pid;
191
192     file = fopen(pid_file, "w");
193     if (file == NULL)
194         return errno;
195     pid = (unsigned long) getpid();
196     if (fprintf(file, "%ld\n", pid) < 0 || fclose(file) == EOF)
197         return errno;
198     return 0;
199 }
200
201 /* XXX yuck.  the signal handlers need this */
202 static krb5_context context;
203
204 static krb5_context hctx;
205
206 int nofork = 0;
207
208 int main(int argc, char *argv[])
209 {
210     extern     char *optarg;
211     extern     int optind, opterr;
212     int ret;
213     OM_uint32 OMret, major_status, minor_status;
214     char *whoami;
215     gss_buffer_desc in_buf;
216     auth_gssapi_name names[4];
217     gss_buffer_desc gssbuf;
218     gss_OID nt_krb5_name_oid;
219     kadm5_config_params params;
220     char **db_args      = NULL;
221     int    db_args_size = 0;
222     char *errmsg;
223     int i;
224     int strong_random = 1;
225     const char *pid_file = NULL;
226
227     kdb_log_context *log_ctx;
228
229     verto_ctx *ctx;
230
231     setlocale(LC_MESSAGES, "");
232     setvbuf(stderr, NULL, _IONBF, 0);
233
234     /* This is OID value the Krb5_Name NameType */
235     gssbuf.value = "{1 2 840 113554 1 2 2 1}";
236     gssbuf.length = strlen(gssbuf.value);
237     major_status = gss_str_to_oid(&minor_status, &gssbuf, &nt_krb5_name_oid);
238     if (major_status != GSS_S_COMPLETE) {
239         fprintf(stderr, _("Couldn't create KRB5 Name NameType OID\n"));
240         display_status("str_to_oid", major_status, minor_status);
241         exit(1);
242     }
243
244     names[0].name = names[1].name = names[2].name = names[3].name = NULL;
245     names[0].type = names[1].type = names[2].type = names[3].type =
246         nt_krb5_name_oid;
247
248     whoami = (strrchr(argv[0], '/') ? strrchr(argv[0], '/')+1 : argv[0]);
249
250     nofork = 0;
251
252     memset(&params, 0, sizeof(params));
253
254     argc--; argv++;
255     while (argc) {
256         if (strcmp(*argv, "-x") == 0) {
257             argc--; argv++;
258             if (!argc)
259                 usage();
260             db_args_size++;
261             {
262                 char **temp = realloc( db_args, sizeof(char*) * (db_args_size+1)); /* one for NULL */
263                 if( temp == NULL )
264                 {
265                     fprintf(stderr, _("%s: cannot initialize. Not enough "
266                                       "memory\n"), whoami);
267                     exit(1);
268                 }
269                 db_args = temp;
270             }
271             db_args[db_args_size-1] = *argv;
272             db_args[db_args_size]   = NULL;
273         }else if (strcmp(*argv, "-r") == 0) {
274             argc--; argv++;
275             if (!argc)
276                 usage();
277             params.realm = *argv;
278             params.mask |= KADM5_CONFIG_REALM;
279             argc--; argv++;
280             continue;
281         } else if (strcmp(*argv, "-m") == 0) {
282             params.mkey_from_kbd = 1;
283             params.mask |= KADM5_CONFIG_MKEY_FROM_KBD;
284         } else if (strcmp(*argv, "-nofork") == 0) {
285             nofork = 1;
286 #ifdef USE_PASSWORD_SERVER
287         } else if (strcmp(*argv, "-passwordserver") == 0) {
288             kadm5_set_use_password_server ();
289 #endif
290         } else if(strcmp(*argv, "-port") == 0) {
291             argc--; argv++;
292             if(!argc)
293                 usage();
294             params.kadmind_port = atoi(*argv);
295             params.mask |= KADM5_CONFIG_KADMIND_PORT;
296         } else if (strcmp(*argv, "-P") == 0) {
297             argc--; argv++;
298             if (!argc)
299                 usage();
300             pid_file = *argv;
301         } else if (strcmp(*argv, "-W") == 0) {
302             strong_random = 0;
303         } else
304             break;
305         argc--; argv++;
306     }
307
308     if (argc != 0)
309         usage();
310
311     if ((ret = kadm5_init_krb5_context(&context))) {
312         fprintf(stderr, _("%s: %s while initializing context, aborting\n"),
313                 whoami, error_message(ret));
314         exit(1);
315     }
316
317     krb5_klog_init(context, "admin_server", whoami, 1);
318
319     if((ret = kadm5_init(context, "kadmind", NULL,
320                          NULL, &params,
321                          KADM5_STRUCT_VERSION,
322                          KADM5_API_VERSION_3,
323                          db_args,
324                          &global_server_handle)) != KADM5_OK) {
325         const char *e_txt = krb5_get_error_message (context, ret);
326         krb5_klog_syslog(LOG_ERR, _("%s while initializing, aborting"), e_txt);
327         fprintf(stderr, _("%s: %s while initializing, aborting\n"),
328                 whoami, e_txt);
329         krb5_klog_close(context);
330         exit(1);
331     }
332
333     if ((ret = kadm5_get_config_params(context, 1, &params,
334                                        &params))) {
335         const char *e_txt = krb5_get_error_message (context, ret);
336         krb5_klog_syslog(LOG_ERR, _("%s: %s while initializing, aborting"),
337                          whoami, e_txt);
338         fprintf(stderr, _("%s: %s while initializing, aborting\n"),
339                 whoami, e_txt);
340         kadm5_destroy(global_server_handle);
341         krb5_klog_close(context);
342         exit(1);
343     }
344
345 #define REQUIRED_PARAMS (KADM5_CONFIG_REALM | KADM5_CONFIG_ACL_FILE)
346
347     if ((params.mask & REQUIRED_PARAMS) != REQUIRED_PARAMS) {
348         krb5_klog_syslog(LOG_ERR,
349                          _("%s: Missing required configuration values "
350                            "(%lx) while initializing, aborting"), whoami,
351                          (params.mask & REQUIRED_PARAMS) ^ REQUIRED_PARAMS);
352         fprintf(stderr, _("%s: Missing required configuration values "
353                           "(%lx) while initializing, aborting\n"), whoami,
354                 (params.mask & REQUIRED_PARAMS) ^ REQUIRED_PARAMS);
355         krb5_klog_close(context);
356         kadm5_destroy(global_server_handle);
357         exit(1);
358     }
359
360     ctx = loop_init(VERTO_EV_TYPE_SIGNAL);
361     if (!ctx) {
362         krb5_klog_syslog(LOG_ERR,
363                          _("%s: could not initialize loop, aborting"),
364                          whoami);
365         fprintf(stderr, _("%s: could not initialize loop, aborting\n"),
366                 whoami);
367         kadm5_destroy(global_server_handle);
368         krb5_klog_close(context);
369         exit(1);
370     }
371
372     if ((ret = loop_setup_signals(ctx, global_server_handle, NULL))) {
373         const char *e_txt = krb5_get_error_message (context, ret);
374         krb5_klog_syslog(LOG_ERR, _("%s: %s while initializing signal "
375                                     "handlers, aborting"), whoami, e_txt);
376         fprintf(stderr, _("%s: %s while initializing signal "
377                           "handlers, aborting\n"), whoami, e_txt);
378         loop_free(ctx);
379         kadm5_destroy(global_server_handle);
380         krb5_klog_close(context);
381         exit(1);
382     }
383
384 #define server_handle ((kadm5_server_handle_t)global_server_handle)
385     if ((ret = loop_add_udp_port(server_handle->params.kpasswd_port))
386         || (ret = loop_add_tcp_port(server_handle->params.kpasswd_port))
387         || (ret = loop_add_rpc_service(server_handle->params.kadmind_port,
388                                        KADM, KADMVERS, kadm_1))
389 #ifndef DISABLE_IPROP
390         || (server_handle->params.iprop_enabled
391             ? (ret = loop_add_rpc_service(server_handle->params.iprop_port,
392                                           KRB5_IPROP_PROG, KRB5_IPROP_VERS,
393                                           krb5_iprop_prog_1))
394             : 0)
395 #endif
396 #undef server_handle
397         || (ret = loop_setup_routing_socket(ctx, global_server_handle, whoami))
398         || (ret = loop_setup_network(ctx, global_server_handle, whoami))) {
399         const char *e_txt = krb5_get_error_message (context, ret);
400         krb5_klog_syslog(LOG_ERR, _("%s: %s while initializing network, "
401                                     "aborting"), whoami, e_txt);
402         fprintf(stderr, _("%s: %s while initializing network, aborting\n"),
403                 whoami, e_txt);
404         loop_free(ctx);
405         kadm5_destroy(global_server_handle);
406         krb5_klog_close(context);
407         exit(1);
408     }
409
410     names[0].name = build_princ_name(KADM5_ADMIN_SERVICE, params.realm);
411     names[1].name = build_princ_name(KADM5_CHANGEPW_SERVICE, params.realm);
412     if (names[0].name == NULL || names[1].name == NULL) {
413         krb5_klog_syslog(LOG_ERR, _("Cannot build GSS-API authentication "
414                                     "names, failing."));
415         fprintf(stderr, _("%s: Cannot build GSS-API authentication names.\n"),
416                 whoami);
417         loop_free(ctx);
418         kadm5_destroy(global_server_handle);
419         krb5_klog_close(context);
420         exit(1);
421     }
422
423     /*
424      * Go through some contortions to point gssapi at a kdb keytab.
425      * This prevents kadmind from needing to use an actual file-based
426      * keytab.
427      */
428     /* XXX extract kadm5's krb5_context */
429     hctx = ((kadm5_server_handle_t)global_server_handle)->context;
430     /* Set ktkdb's internal krb5_context. */
431     ret = krb5_ktkdb_set_context(hctx);
432     if (ret) {
433         krb5_klog_syslog(LOG_ERR,
434                          _("Can't set kdb keytab's internal context."));
435         goto kterr;
436     }
437     ret = krb5_kt_register(context, &krb5_kt_kdb_ops);
438     if (ret) {
439         krb5_klog_syslog(LOG_ERR, _("Can't register kdb keytab."));
440         goto kterr;
441     }
442     /* Tell gssapi about the kdb keytab. */
443     ret = krb5_gss_register_acceptor_identity("KDB:");
444     if (ret) {
445         krb5_klog_syslog(LOG_ERR, _("Can't register acceptor keytab."));
446         goto kterr;
447     }
448 kterr:
449     if (ret) {
450         krb5_klog_syslog(LOG_ERR, "%s", krb5_get_error_message (context, ret));
451         fprintf(stderr, _("%s: Can't set up keytab for RPC.\n"), whoami);
452         loop_free(ctx);
453         kadm5_destroy(global_server_handle);
454         krb5_klog_close(context);
455         exit(1);
456     }
457
458     if (svcauth_gssapi_set_names(names, 2) == FALSE) {
459         krb5_klog_syslog(LOG_ERR, _("Cannot set GSS-API authentication names "
460                                     "(keytab not present?), failing."));
461         fprintf(stderr, _("%s: Cannot set GSS-API authentication names.\n"),
462                 whoami);
463         svcauth_gssapi_unset_names();
464         loop_free(ctx);
465         kadm5_destroy(global_server_handle);
466         krb5_klog_close(context);
467         exit(1);
468     }
469
470     /* if set_names succeeded, this will too */
471     in_buf.value = names[1].name;
472     in_buf.length = strlen(names[1].name) + 1;
473     (void) gss_import_name(&OMret, &in_buf, nt_krb5_name_oid,
474                            &gss_changepw_name);
475
476     svcauth_gssapi_set_log_badauth_func(log_badauth, NULL);
477     svcauth_gssapi_set_log_badverf_func(log_badverf, NULL);
478     svcauth_gssapi_set_log_miscerr_func(log_miscerr, NULL);
479
480     svcauth_gss_set_log_badauth_func(log_badauth, NULL);
481     svcauth_gss_set_log_badverf_func(log_badverf, NULL);
482     svcauth_gss_set_log_miscerr_func(log_miscerr, NULL);
483
484     if (svcauth_gss_set_svc_name(GSS_C_NO_NAME) != TRUE) {
485         fprintf(stderr, _("%s: Cannot initialize RPCSEC_GSS service name.\n"),
486                 whoami);
487         loop_free(ctx);
488         exit(1);
489     }
490
491     if ((ret = kadm5int_acl_init(context, 0, params.acl_file))) {
492         errmsg = krb5_get_error_message (context, ret);
493         krb5_klog_syslog(LOG_ERR, _("Cannot initialize acl file: %s"), errmsg);
494         fprintf(stderr, _("%s: Cannot initialize acl file: %s\n"),
495                 whoami, errmsg);
496         svcauth_gssapi_unset_names();
497         loop_free(ctx);
498         kadm5_destroy(global_server_handle);
499         krb5_klog_close(context);
500         exit(1);
501     }
502
503     if (!nofork && (ret = daemon(0, 0))) {
504         ret = errno;
505         errmsg = krb5_get_error_message (context, ret);
506         krb5_klog_syslog(LOG_ERR, _("Cannot detach from tty: %s"), errmsg);
507         fprintf(stderr, _("%s: Cannot detach from tty: %s\n"), whoami, errmsg);
508         svcauth_gssapi_unset_names();
509         loop_free(ctx);
510         kadm5_destroy(global_server_handle);
511         krb5_klog_close(context);
512         exit(1);
513     }
514     if (pid_file != NULL) {
515         ret = write_pid_file(pid_file);
516         if (ret) {
517             errmsg = krb5_get_error_message(context, ret);
518             krb5_klog_syslog(LOG_ERR, _("Cannot create PID file %s: %s"),
519                              pid_file, errmsg);
520             svcauth_gssapi_unset_names();
521             loop_free(ctx);
522             kadm5_destroy(global_server_handle);
523             krb5_klog_close(context);
524             exit(1);
525         }
526     }
527
528     krb5_klog_syslog(LOG_INFO, _("Seeding random number generator"));
529     ret = krb5_c_random_os_entropy(context, strong_random, NULL);
530     if (ret) {
531         krb5_klog_syslog(LOG_ERR, _("Error getting random seed: %s, aborting"),
532                          krb5_get_error_message(context, ret));
533         svcauth_gssapi_unset_names();
534         loop_free(ctx);
535         kadm5_destroy(global_server_handle);
536         krb5_klog_close(context);
537         exit(1);
538     }
539
540     if (params.iprop_enabled == TRUE)
541         ulog_set_role(hctx, IPROP_MASTER);
542     else
543         ulog_set_role(hctx, IPROP_NULL);
544
545     log_ctx = hctx->kdblog_context;
546
547     if (log_ctx && (log_ctx->iproprole == IPROP_MASTER)) {
548         /*
549          * IProp is enabled, so let's map in the update log
550          * and setup the service.
551          */
552         if ((ret = ulog_map(hctx, params.iprop_logfile,
553                             params.iprop_ulogsize, FKADMIND, db_args)) != 0) {
554             fprintf(stderr,
555                     _("%s: %s while mapping update log (`%s.ulog')\n"),
556                     whoami, error_message(ret), params.dbname);
557             krb5_klog_syslog(LOG_ERR,
558                              _("%s while mapping update log (`%s.ulog')"),
559                              error_message(ret), params.dbname);
560             loop_free(ctx);
561             krb5_klog_close(context);
562             exit(1);
563         }
564
565
566         if (nofork)
567             fprintf(stderr,
568                     _("%s: create IPROP svc (PROG=%d, VERS=%d)\n"),
569                     whoami, KRB5_IPROP_PROG, KRB5_IPROP_VERS);
570
571 #if 0
572         if (!svc_create(krb5_iprop_prog_1,
573                         KRB5_IPROP_PROG, KRB5_IPROP_VERS,
574                         "circuit_v")) {
575             fprintf(stderr,
576                     _("%s: Cannot create IProp RPC service (PROG=%d, VERS=%d)\n"),
577                     whoami,
578                     KRB5_IPROP_PROG, KRB5_IPROP_VERS);
579             krb5_klog_syslog(LOG_ERR,
580                              _("Cannot create IProp RPC service (PROG=%d, VERS=%d), failing."),
581                              KRB5_IPROP_PROG, KRB5_IPROP_VERS);
582             loop_free(ctx);
583             krb5_klog_close(context);
584             exit(1);
585         }
586 #endif
587
588 #if 0 /* authgss only? */
589         if ((ret = kiprop_get_adm_host_srv_name(context,
590                                                 params.realm,
591                                                 &kiprop_name)) != 0) {
592             krb5_klog_syslog(LOG_ERR,
593                              _("%s while getting IProp svc name, failing"),
594                              error_message(ret));
595             fprintf(stderr,
596                     _("%s: %s while getting IProp svc name, failing\n"),
597                     whoami, error_message(ret));
598             loop_free(ctx);
599             krb5_klog_close(context);
600             exit(1);
601         }
602
603         auth_gssapi_name iprop_name;
604         iprop_name.name = build_princ_name(foo, bar);
605         if (iprop_name.name == NULL) {
606             foo error;
607         }
608         iprop_name.type = nt_krb5_name_oid;
609         if (svcauth_gssapi_set_names(&iprop_name, 1) == FALSE) {
610             foo error;
611         }
612         if (!rpc_gss_set_svc_name(kiprop_name, "kerberos_v5", 0,
613                                   KRB5_IPROP_PROG, KRB5_IPROP_VERS)) {
614             rpc_gss_error_t err;
615             (void) rpc_gss_get_error(&err);
616
617             krb5_klog_syslog(LOG_ERR,
618                              _("Unable to set RPCSEC_GSS service name (`%s'), failing."),
619                              kiprop_name ? kiprop_name : "<null>");
620
621             fprintf(stderr,
622                     _("%s: Unable to set RPCSEC_GSS service name (`%s'), failing.\n"),
623                     whoami,
624                     kiprop_name ? kiprop_name : "<null>");
625
626             if (nofork) {
627                 fprintf(stderr,
628                         "%s: set svc name (rpcsec err=%d, sys err=%d)\n",
629                         whoami,
630                         err.rpc_gss_error,
631                         err.system_error);
632             }
633
634             loop_free(ctx);
635             exit(1);
636         }
637         free(kiprop_name);
638 #endif
639     }
640
641     krb5_klog_syslog(LOG_INFO, _("starting"));
642     if (nofork)
643         fprintf(stderr, _("%s: starting...\n"), whoami);
644
645     verto_run(ctx);
646     krb5_klog_syslog(LOG_INFO, _("finished, exiting"));
647
648     /* Clean up memory, etc */
649     svcauth_gssapi_unset_names();
650     kadm5_destroy(global_server_handle);
651     loop_free(ctx);
652     kadm5int_acl_finish(context, 0);
653     if(gss_changepw_name) {
654         (void) gss_release_name(&OMret, &gss_changepw_name);
655     }
656     if(gss_oldchangepw_name) {
657         (void) gss_release_name(&OMret, &gss_oldchangepw_name);
658     }
659     for(i = 0 ; i < 4; i++) {
660         if (names[i].name) {
661             free(names[i].name);
662         }
663     }
664
665     krb5_klog_close(context);
666     krb5_free_context(context);
667     exit(2);
668 }
669
670 /*
671  * Function: build_princ_name
672  *
673  * Purpose: takes a name and a realm and builds a string that can be
674  *          consumed by krb5_parse_name.
675  *
676  * Arguments:
677  *      name                (input) name to be part of principal
678  *      realm               (input) realm part of principal
679  *      <return value>      char * pointing to "name@realm"
680  *
681  * Requires:
682  *      name be non-null.
683  *
684  * Effects:
685  * Modifies:
686  */
687
688 char *build_princ_name(char *name, char *realm)
689 {
690     char *fullname;
691
692     if (realm) {
693         if (asprintf(&fullname, "%s@%s", name, realm) < 0)
694             fullname = NULL;
695     } else
696         fullname = strdup(name);
697
698     return fullname;
699 }
700
701 /*
702  * Function: log_badverf
703  *
704  * Purpose: Call from GSS-API Sun RPC for garbled/forged/replayed/etc
705  * messages.
706  *
707  * Argiments:
708  *      client_name     (r) GSS-API client name
709  *      server_name     (r) GSS-API server name
710  *      rqst            (r) RPC service request
711  *      msg             (r) RPC message
712  *      data            (r) arbitrary data (NULL), not used
713  *
714  * Effects:
715  *
716  * Logs the invalid request via krb5_klog_syslog(); see functional spec for
717  * format.
718  */
719 void log_badverf(gss_name_t client_name, gss_name_t server_name,
720                  struct svc_req *rqst, struct rpc_msg *msg, char
721                  *data)
722 {
723     struct procnames {
724         rpcproc_t proc;
725         const char *proc_name;
726     };
727     static const struct procnames proc_names[] = {
728         {1, "CREATE_PRINCIPAL"},
729         {2, "DELETE_PRINCIPAL"},
730         {3, "MODIFY_PRINCIPAL"},
731         {4, "RENAME_PRINCIPAL"},
732         {5, "GET_PRINCIPAL"},
733         {6, "CHPASS_PRINCIPAL"},
734         {7, "CHRAND_PRINCIPAL"},
735         {8, "CREATE_POLICY"},
736         {9, "DELETE_POLICY"},
737         {10, "MODIFY_POLICY"},
738         {11, "GET_POLICY"},
739         {12, "GET_PRIVS"},
740         {13, "INIT"},
741         {14, "GET_PRINCS"},
742         {15, "GET_POLS"},
743         {16, "SETKEY_PRINCIPAL"},
744         {17, "SETV4KEY_PRINCIPAL"},
745         {18, "CREATE_PRINCIPAL3"},
746         {19, "CHPASS_PRINCIPAL3"},
747         {20, "CHRAND_PRINCIPAL3"},
748         {21, "SETKEY_PRINCIPAL3"},
749         {22, "PURGEKEYS"},
750         {23, "GET_STRINGS"},
751         {24, "SET_STRING"}
752     };
753 #define NPROCNAMES (sizeof (proc_names) / sizeof (struct procnames))
754     OM_uint32 minor;
755     gss_buffer_desc client, server;
756     gss_OID gss_type;
757     char *a;
758     rpcproc_t proc;
759     unsigned int i;
760     const char *procname;
761     size_t clen, slen;
762     char *cdots, *sdots;
763
764     client.length = 0;
765     client.value = NULL;
766     server.length = 0;
767     server.value = NULL;
768
769     (void) gss_display_name(&minor, client_name, &client, &gss_type);
770     (void) gss_display_name(&minor, server_name, &server, &gss_type);
771     if (client.value == NULL) {
772         client.value = "(null)";
773         clen = sizeof("(null)") -1;
774     } else {
775         clen = client.length;
776     }
777     trunc_name(&clen, &cdots);
778     if (server.value == NULL) {
779         server.value = "(null)";
780         slen = sizeof("(null)") - 1;
781     } else {
782         slen = server.length;
783     }
784     trunc_name(&slen, &sdots);
785     a = inet_ntoa(rqst->rq_xprt->xp_raddr.sin_addr);
786
787     proc = msg->rm_call.cb_proc;
788     procname = NULL;
789     for (i = 0; i < NPROCNAMES; i++) {
790         if (proc_names[i].proc == proc) {
791             procname = proc_names[i].proc_name;
792             break;
793         }
794     }
795     if (procname != NULL)
796         krb5_klog_syslog(LOG_NOTICE,
797                          _("WARNING! Forged/garbled request: %s, claimed "
798                            "client = %.*s%s, server = %.*s%s, addr = %s"),
799                          procname, (int) clen, (char *) client.value, cdots,
800                          (int) slen, (char *) server.value, sdots, a);
801     else
802         krb5_klog_syslog(LOG_NOTICE,
803                          _("WARNING! Forged/garbled request: %d, claimed "
804                            "client = %.*s%s, server = %.*s%s, addr = %s"),
805                          proc, (int) clen, (char *) client.value, cdots,
806                          (int) slen, (char *) server.value, sdots, a);
807
808     (void) gss_release_buffer(&minor, &client);
809     (void) gss_release_buffer(&minor, &server);
810 }
811
812 /*
813  * Function: log_miscerr
814  *
815  * Purpose: Callback from GSS-API Sun RPC for miscellaneous errors
816  *
817  * Arguments:
818  *      rqst            (r) RPC service request
819  *      msg             (r) RPC message
820  *      error           (r) error message from RPC
821  *      data            (r) arbitrary data (NULL), not used
822  *
823  * Effects:
824  *
825  * Logs the error via krb5_klog_syslog(); see functional spec for
826  * format.
827  */
828 void log_miscerr(struct svc_req *rqst, struct rpc_msg *msg,
829                  char *error, char *data)
830 {
831     char *a;
832
833     a = inet_ntoa(rqst->rq_xprt->xp_raddr.sin_addr);
834     krb5_klog_syslog(LOG_NOTICE, _("Miscellaneous RPC error: %s, %s"), a,
835                      error);
836 }
837
838
839
840 /*
841  * Function: log_badauth
842  *
843  * Purpose: Callback from GSS-API Sun RPC for authentication
844  * failures/errors.
845  *
846  * Arguments:
847  *      major           (r) GSS-API major status
848  *      minor           (r) GSS-API minor status
849  *      addr            (r) originating address
850  *      data            (r) arbitrary data (NULL), not used
851  *
852  * Effects:
853  *
854  * Logs the GSS-API error via krb5_klog_syslog(); see functional spec for
855  * format.
856  */
857 void log_badauth(OM_uint32 major, OM_uint32 minor,
858                  struct sockaddr_in *addr, char *data)
859 {
860     char *a;
861
862     /* Authentication attempt failed: <IP address>, <GSS-API error */
863     /* strings> */
864
865     a = inet_ntoa(addr->sin_addr);
866
867     krb5_klog_syslog(LOG_NOTICE, _("Authentication attempt failed: %s, "
868                                    "GSS-API error strings are:"), a);
869     log_badauth_display_status("   ", major, minor);
870     krb5_klog_syslog(LOG_NOTICE, _("   GSS-API error strings complete."));
871 }
872
873 void log_badauth_display_status(char *msg, OM_uint32 major, OM_uint32 minor)
874 {
875     log_badauth_display_status_1(msg, major, GSS_C_GSS_CODE, 0);
876     log_badauth_display_status_1(msg, minor, GSS_C_MECH_CODE, 0);
877 }
878
879 void log_badauth_display_status_1(char *m, OM_uint32 code, int type,
880                                   int rec)
881 {
882     OM_uint32 gssstat, minor_stat;
883     gss_buffer_desc msg;
884     OM_uint32 msg_ctx;
885
886     msg_ctx = 0;
887     while (1) {
888         gssstat = gss_display_status(&minor_stat, code,
889                                      type, GSS_C_NULL_OID,
890                                      &msg_ctx, &msg);
891         if (gssstat != GSS_S_COMPLETE) {
892             if (!rec) {
893                 log_badauth_display_status_1(m,gssstat,GSS_C_GSS_CODE,1);
894                 log_badauth_display_status_1(m, minor_stat,
895                                              GSS_C_MECH_CODE, 1);
896             } else
897                 krb5_klog_syslog(LOG_ERR,
898                                  _("GSS-API authentication error %.*s: "
899                                    "recursive failure!"), (int) msg.length,
900                                  (char *) msg.value);
901             return;
902         }
903
904         krb5_klog_syslog(LOG_NOTICE, "%s %.*s", m, (int)msg.length,
905                          (char *)msg.value);
906         (void) gss_release_buffer(&minor_stat, &msg);
907
908         if (!msg_ctx)
909             break;
910     }
911 }