xref: /freebsd/crypto/krb5/src/kprop/kpropd.c (revision 7f2fe78b9dd5f51c821d771b63d2e096f6fd49e9)
1*7f2fe78bSCy Schubert /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2*7f2fe78bSCy Schubert /* kprop/kpropd.c */
3*7f2fe78bSCy Schubert /*
4*7f2fe78bSCy Schubert  * Copyright (C) 1998 by the FundsXpress, INC.
5*7f2fe78bSCy Schubert  *
6*7f2fe78bSCy Schubert  * All rights reserved.
7*7f2fe78bSCy Schubert  *
8*7f2fe78bSCy Schubert  * Export of this software from the United States of America may require
9*7f2fe78bSCy Schubert  * a specific license from the United States Government.  It is the
10*7f2fe78bSCy Schubert  * responsibility of any person or organization contemplating export to
11*7f2fe78bSCy Schubert  * obtain such a license before exporting.
12*7f2fe78bSCy Schubert  *
13*7f2fe78bSCy Schubert  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
14*7f2fe78bSCy Schubert  * distribute this software and its documentation for any purpose and
15*7f2fe78bSCy Schubert  * without fee is hereby granted, provided that the above copyright
16*7f2fe78bSCy Schubert  * notice appear in all copies and that both that copyright notice and
17*7f2fe78bSCy Schubert  * this permission notice appear in supporting documentation, and that
18*7f2fe78bSCy Schubert  * the name of FundsXpress. not be used in advertising or publicity pertaining
19*7f2fe78bSCy Schubert  * to distribution of the software without specific, written prior
20*7f2fe78bSCy Schubert  * permission.  FundsXpress makes no representations about the suitability of
21*7f2fe78bSCy Schubert  * this software for any purpose.  It is provided "as is" without express
22*7f2fe78bSCy Schubert  * or implied warranty.
23*7f2fe78bSCy Schubert  *
24*7f2fe78bSCy Schubert  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
25*7f2fe78bSCy Schubert  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
26*7f2fe78bSCy Schubert  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
27*7f2fe78bSCy Schubert  */
28*7f2fe78bSCy Schubert 
29*7f2fe78bSCy Schubert /*
30*7f2fe78bSCy Schubert  * Copyright 1990,1991,2007 by the Massachusetts Institute of Technology.
31*7f2fe78bSCy Schubert  * All Rights Reserved.
32*7f2fe78bSCy Schubert  *
33*7f2fe78bSCy Schubert  * Export of this software from the United States of America may
34*7f2fe78bSCy Schubert  *   require a specific license from the United States Government.
35*7f2fe78bSCy Schubert  *   It is the responsibility of any person or organization contemplating
36*7f2fe78bSCy Schubert  *   export to obtain such a license before exporting.
37*7f2fe78bSCy Schubert  *
38*7f2fe78bSCy Schubert  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
39*7f2fe78bSCy Schubert  * distribute this software and its documentation for any purpose and
40*7f2fe78bSCy Schubert  * without fee is hereby granted, provided that the above copyright
41*7f2fe78bSCy Schubert  * notice appear in all copies and that both that copyright notice and
42*7f2fe78bSCy Schubert  * this permission notice appear in supporting documentation, and that
43*7f2fe78bSCy Schubert  * the name of M.I.T. not be used in advertising or publicity pertaining
44*7f2fe78bSCy Schubert  * to distribution of the software without specific, written prior
45*7f2fe78bSCy Schubert  * permission.  Furthermore if you modify this software you must label
46*7f2fe78bSCy Schubert  * your software as modified software and not distribute it in such a
47*7f2fe78bSCy Schubert  * fashion that it might be confused with the original M.I.T. software.
48*7f2fe78bSCy Schubert  * M.I.T. makes no representations about the suitability of
49*7f2fe78bSCy Schubert  * this software for any purpose.  It is provided "as is" without express
50*7f2fe78bSCy Schubert  * or implied warranty.
51*7f2fe78bSCy Schubert  */
52*7f2fe78bSCy Schubert 
53*7f2fe78bSCy Schubert 
54*7f2fe78bSCy Schubert #include "k5-int.h"
55*7f2fe78bSCy Schubert #include "com_err.h"
56*7f2fe78bSCy Schubert #include "fake-addrinfo.h"
57*7f2fe78bSCy Schubert 
58*7f2fe78bSCy Schubert #include <inttypes.h>
59*7f2fe78bSCy Schubert #include <locale.h>
60*7f2fe78bSCy Schubert #include <ctype.h>
61*7f2fe78bSCy Schubert #include <sys/file.h>
62*7f2fe78bSCy Schubert #include <signal.h>
63*7f2fe78bSCy Schubert #include <fcntl.h>
64*7f2fe78bSCy Schubert #include <sys/types.h>
65*7f2fe78bSCy Schubert #include <sys/time.h>
66*7f2fe78bSCy Schubert #include <sys/stat.h>
67*7f2fe78bSCy Schubert #include <sys/socket.h>
68*7f2fe78bSCy Schubert #include <sys/wait.h>
69*7f2fe78bSCy Schubert #include <netinet/in.h>
70*7f2fe78bSCy Schubert #include <arpa/inet.h>
71*7f2fe78bSCy Schubert #include <sys/param.h>
72*7f2fe78bSCy Schubert #include <netdb.h>
73*7f2fe78bSCy Schubert #include <syslog.h>
74*7f2fe78bSCy Schubert 
75*7f2fe78bSCy Schubert #include "kprop.h"
76*7f2fe78bSCy Schubert #include <iprop_hdr.h>
77*7f2fe78bSCy Schubert #include "iprop.h"
78*7f2fe78bSCy Schubert #include <kadm5/admin.h>
79*7f2fe78bSCy Schubert #include <kdb_log.h>
80*7f2fe78bSCy Schubert 
81*7f2fe78bSCy Schubert #ifndef GETSOCKNAME_ARG3_TYPE
82*7f2fe78bSCy Schubert #define GETSOCKNAME_ARG3_TYPE unsigned int
83*7f2fe78bSCy Schubert #endif
84*7f2fe78bSCy Schubert #ifndef GETPEERNAME_ARG3_TYPE
85*7f2fe78bSCy Schubert #define GETPEERNAME_ARG3_TYPE unsigned int
86*7f2fe78bSCy Schubert #endif
87*7f2fe78bSCy Schubert 
88*7f2fe78bSCy Schubert #if defined(NEED_DAEMON_PROTO)
89*7f2fe78bSCy Schubert extern int daemon(int, int);
90*7f2fe78bSCy Schubert #endif
91*7f2fe78bSCy Schubert 
92*7f2fe78bSCy Schubert #define SYSLOG_CLASS LOG_DAEMON
93*7f2fe78bSCy Schubert 
94*7f2fe78bSCy Schubert int runonce = 0;
95*7f2fe78bSCy Schubert 
96*7f2fe78bSCy Schubert /*
97*7f2fe78bSCy Schubert  * This struct simulates the use of _kadm5_server_handle_t
98*7f2fe78bSCy Schubert  *
99*7f2fe78bSCy Schubert  * This is a COPY of kadm5_server_handle_t from
100*7f2fe78bSCy Schubert  * lib/kadm5/clnt/client_internal.h!
101*7f2fe78bSCy Schubert  */
102*7f2fe78bSCy Schubert typedef struct _kadm5_iprop_handle_t {
103*7f2fe78bSCy Schubert     krb5_ui_4 magic_number;
104*7f2fe78bSCy Schubert     krb5_ui_4 struct_version;
105*7f2fe78bSCy Schubert     krb5_ui_4 api_version;
106*7f2fe78bSCy Schubert     char *cache_name;
107*7f2fe78bSCy Schubert     int destroy_cache;
108*7f2fe78bSCy Schubert     CLIENT *clnt;
109*7f2fe78bSCy Schubert     krb5_context context;
110*7f2fe78bSCy Schubert     kadm5_config_params params;
111*7f2fe78bSCy Schubert     struct _kadm5_iprop_handle_t *lhandle;
112*7f2fe78bSCy Schubert } *kadm5_iprop_handle_t;
113*7f2fe78bSCy Schubert 
114*7f2fe78bSCy Schubert static char *kprop_version = KPROP_PROT_VERSION;
115*7f2fe78bSCy Schubert 
116*7f2fe78bSCy Schubert static kadm5_config_params params;
117*7f2fe78bSCy Schubert 
118*7f2fe78bSCy Schubert static char *progname;
119*7f2fe78bSCy Schubert static int debug = 0;
120*7f2fe78bSCy Schubert static int nodaemon = 0;
121*7f2fe78bSCy Schubert static char *keytab_path = NULL;
122*7f2fe78bSCy Schubert static int standalone = 0;
123*7f2fe78bSCy Schubert static const char *pid_file = NULL;
124*7f2fe78bSCy Schubert 
125*7f2fe78bSCy Schubert static pid_t fullprop_child = (pid_t)-1;
126*7f2fe78bSCy Schubert 
127*7f2fe78bSCy Schubert static krb5_principal server;   /* This is our server principal name */
128*7f2fe78bSCy Schubert static krb5_principal client;   /* This is who we're talking to */
129*7f2fe78bSCy Schubert static krb5_context kpropd_context;
130*7f2fe78bSCy Schubert static krb5_auth_context auth_context;
131*7f2fe78bSCy Schubert static char *realm = NULL;      /* Our realm */
132*7f2fe78bSCy Schubert static char *def_realm = NULL;  /* Ref pointer for default realm */
133*7f2fe78bSCy Schubert static char *file = KPROPD_DEFAULT_FILE;
134*7f2fe78bSCy Schubert static char *temp_file_name;
135*7f2fe78bSCy Schubert static char *kdb5_util = KPROPD_DEFAULT_KDB5_UTIL;
136*7f2fe78bSCy Schubert static char *kerb_database = NULL;
137*7f2fe78bSCy Schubert static char *acl_file_name = KPROPD_ACL_FILE;
138*7f2fe78bSCy Schubert 
139*7f2fe78bSCy Schubert static krb5_address *receiver_addr;
140*7f2fe78bSCy Schubert static const char *port = KPROP_SERVICE;
141*7f2fe78bSCy Schubert 
142*7f2fe78bSCy Schubert static char **db_args = NULL;
143*7f2fe78bSCy Schubert static int db_args_size = 0;
144*7f2fe78bSCy Schubert 
145*7f2fe78bSCy Schubert static void parse_args(int argc, char **argv);
146*7f2fe78bSCy Schubert static void do_standalone(void);
147*7f2fe78bSCy Schubert static void doit(int fd);
148*7f2fe78bSCy Schubert static krb5_error_code do_iprop(void);
149*7f2fe78bSCy Schubert static void kerberos_authenticate(krb5_context context, int fd,
150*7f2fe78bSCy Schubert                                   krb5_principal *clientp, krb5_enctype *etype,
151*7f2fe78bSCy Schubert                                   struct sockaddr_storage *my_sin);
152*7f2fe78bSCy Schubert static krb5_boolean authorized_principal(krb5_context context,
153*7f2fe78bSCy Schubert                                          krb5_principal p,
154*7f2fe78bSCy Schubert                                          krb5_enctype auth_etype);
155*7f2fe78bSCy Schubert static void recv_database(krb5_context context, int fd, int database_fd,
156*7f2fe78bSCy Schubert                           krb5_data *confmsg);
157*7f2fe78bSCy Schubert static void load_database(krb5_context context, char *kdb_util,
158*7f2fe78bSCy Schubert                           char *database_file_name);
159*7f2fe78bSCy Schubert static void send_error(krb5_context context, int fd, krb5_error_code err_code,
160*7f2fe78bSCy Schubert                        char *err_text);
161*7f2fe78bSCy Schubert static void recv_error(krb5_context context, krb5_data *inbuf);
162*7f2fe78bSCy Schubert static unsigned int backoff_from_primary(int *cnt);
163*7f2fe78bSCy Schubert static kadm5_ret_t kadm5_get_kiprop_host_srv_name(krb5_context context,
164*7f2fe78bSCy Schubert                                                   const char *realm_name,
165*7f2fe78bSCy Schubert                                                   char **host_service_name);
166*7f2fe78bSCy Schubert 
167*7f2fe78bSCy Schubert static void
usage()168*7f2fe78bSCy Schubert usage()
169*7f2fe78bSCy Schubert {
170*7f2fe78bSCy Schubert     fprintf(stderr,
171*7f2fe78bSCy Schubert             _("\nUsage: %s [-r realm] [-s keytab] [-d] [-D] [-S]\n"
172*7f2fe78bSCy Schubert               "\t[-f replica_file] [-F kerberos_db_file ]\n"
173*7f2fe78bSCy Schubert               "\t[-p kdb5_util_pathname] [-x db_args]* [-P port]\n"
174*7f2fe78bSCy Schubert               "\t[-a acl_file] [-A admin_server] [--pid-file=pid_file]\n"),
175*7f2fe78bSCy Schubert             progname);
176*7f2fe78bSCy Schubert     exit(1);
177*7f2fe78bSCy Schubert }
178*7f2fe78bSCy Schubert 
179*7f2fe78bSCy Schubert static krb5_error_code
write_pid_file(const char * path)180*7f2fe78bSCy Schubert write_pid_file(const char *path)
181*7f2fe78bSCy Schubert {
182*7f2fe78bSCy Schubert     FILE *fp;
183*7f2fe78bSCy Schubert     unsigned long pid;
184*7f2fe78bSCy Schubert 
185*7f2fe78bSCy Schubert     fp = fopen(path, "w");
186*7f2fe78bSCy Schubert     if (fp == NULL)
187*7f2fe78bSCy Schubert         return errno;
188*7f2fe78bSCy Schubert     pid = (unsigned long)getpid();
189*7f2fe78bSCy Schubert     if (fprintf(fp, "%ld\n", pid) < 0 || fclose(fp) == EOF)
190*7f2fe78bSCy Schubert         return errno;
191*7f2fe78bSCy Schubert     return 0;
192*7f2fe78bSCy Schubert }
193*7f2fe78bSCy Schubert 
194*7f2fe78bSCy Schubert typedef void (*sig_handler_fn)(int sig);
195*7f2fe78bSCy Schubert 
196*7f2fe78bSCy Schubert static void
signal_wrapper(int sig,sig_handler_fn handler)197*7f2fe78bSCy Schubert signal_wrapper(int sig, sig_handler_fn handler)
198*7f2fe78bSCy Schubert {
199*7f2fe78bSCy Schubert #ifdef POSIX_SIGNALS
200*7f2fe78bSCy Schubert     struct sigaction s_action;
201*7f2fe78bSCy Schubert 
202*7f2fe78bSCy Schubert     memset(&s_action, 0, sizeof(s_action));
203*7f2fe78bSCy Schubert     sigemptyset(&s_action.sa_mask);
204*7f2fe78bSCy Schubert     s_action.sa_handler = handler;
205*7f2fe78bSCy Schubert     sigaction(sig, &s_action, NULL);
206*7f2fe78bSCy Schubert #else
207*7f2fe78bSCy Schubert     signal(sig, handler);
208*7f2fe78bSCy Schubert #endif
209*7f2fe78bSCy Schubert }
210*7f2fe78bSCy Schubert 
211*7f2fe78bSCy Schubert static void
alarm_handler(int sig)212*7f2fe78bSCy Schubert alarm_handler(int sig)
213*7f2fe78bSCy Schubert {
214*7f2fe78bSCy Schubert     static char *timeout_msg = "Full propagation timed out\n";
215*7f2fe78bSCy Schubert 
216*7f2fe78bSCy Schubert     write(STDERR_FILENO, timeout_msg, strlen(timeout_msg));
217*7f2fe78bSCy Schubert     exit(1);
218*7f2fe78bSCy Schubert }
219*7f2fe78bSCy Schubert 
220*7f2fe78bSCy Schubert static void
usr1_handler(int sig)221*7f2fe78bSCy Schubert usr1_handler(int sig)
222*7f2fe78bSCy Schubert {
223*7f2fe78bSCy Schubert     /* Nothing to do, just let the signal interrupt sleep(). */
224*7f2fe78bSCy Schubert }
225*7f2fe78bSCy Schubert 
226*7f2fe78bSCy Schubert static void
kill_do_standalone(int sig)227*7f2fe78bSCy Schubert kill_do_standalone(int sig)
228*7f2fe78bSCy Schubert {
229*7f2fe78bSCy Schubert     if (fullprop_child > 0) {
230*7f2fe78bSCy Schubert         if (debug) {
231*7f2fe78bSCy Schubert             fprintf(stderr, _("Killing fullprop child (%d)\n"),
232*7f2fe78bSCy Schubert                     (int)fullprop_child);
233*7f2fe78bSCy Schubert         }
234*7f2fe78bSCy Schubert         kill(fullprop_child, sig);
235*7f2fe78bSCy Schubert     }
236*7f2fe78bSCy Schubert     /* Make sure our exit status code reflects our having been signaled */
237*7f2fe78bSCy Schubert     signal_wrapper(sig, SIG_DFL);
238*7f2fe78bSCy Schubert     kill(getpid(), sig);
239*7f2fe78bSCy Schubert }
240*7f2fe78bSCy Schubert 
241*7f2fe78bSCy Schubert static void
atexit_kill_do_standalone(void)242*7f2fe78bSCy Schubert atexit_kill_do_standalone(void)
243*7f2fe78bSCy Schubert {
244*7f2fe78bSCy Schubert     if (fullprop_child > 0)
245*7f2fe78bSCy Schubert         kill(fullprop_child, SIGHUP);
246*7f2fe78bSCy Schubert }
247*7f2fe78bSCy Schubert 
248*7f2fe78bSCy Schubert int
main(int argc,char ** argv)249*7f2fe78bSCy Schubert main(int argc, char **argv)
250*7f2fe78bSCy Schubert {
251*7f2fe78bSCy Schubert     krb5_error_code retval;
252*7f2fe78bSCy Schubert     kdb_log_context *log_ctx;
253*7f2fe78bSCy Schubert     int devnull, sock;
254*7f2fe78bSCy Schubert     struct stat st;
255*7f2fe78bSCy Schubert 
256*7f2fe78bSCy Schubert     setlocale(LC_ALL, "");
257*7f2fe78bSCy Schubert     parse_args(argc, argv);
258*7f2fe78bSCy Schubert 
259*7f2fe78bSCy Schubert     if (fstat(0, &st) == -1) {
260*7f2fe78bSCy Schubert         com_err(progname, errno, _("while checking if stdin is a socket"));
261*7f2fe78bSCy Schubert         exit(1);
262*7f2fe78bSCy Schubert     }
263*7f2fe78bSCy Schubert     /*
264*7f2fe78bSCy Schubert      * Detect whether we're running from inetd; if not then we're in
265*7f2fe78bSCy Schubert      * standalone mode.
266*7f2fe78bSCy Schubert      */
267*7f2fe78bSCy Schubert     standalone = !S_ISSOCK(st.st_mode);
268*7f2fe78bSCy Schubert 
269*7f2fe78bSCy Schubert     log_ctx = kpropd_context->kdblog_context;
270*7f2fe78bSCy Schubert 
271*7f2fe78bSCy Schubert     signal_wrapper(SIGPIPE, SIG_IGN);
272*7f2fe78bSCy Schubert 
273*7f2fe78bSCy Schubert     if (standalone) {
274*7f2fe78bSCy Schubert         /* "ready" is a sentinel for the test framework. */
275*7f2fe78bSCy Schubert         if (!debug && !nodaemon) {
276*7f2fe78bSCy Schubert             daemon(0, 0);
277*7f2fe78bSCy Schubert         } else {
278*7f2fe78bSCy Schubert             printf(_("ready\n"));
279*7f2fe78bSCy Schubert             fflush(stdout);
280*7f2fe78bSCy Schubert         }
281*7f2fe78bSCy Schubert         if (pid_file != NULL) {
282*7f2fe78bSCy Schubert             retval = write_pid_file(pid_file);
283*7f2fe78bSCy Schubert             if (retval) {
284*7f2fe78bSCy Schubert                 syslog(LOG_ERR, _("Could not write pid file %s: %s"),
285*7f2fe78bSCy Schubert                        pid_file, strerror(errno));
286*7f2fe78bSCy Schubert                 exit(1);
287*7f2fe78bSCy Schubert             }
288*7f2fe78bSCy Schubert         }
289*7f2fe78bSCy Schubert     } else {
290*7f2fe78bSCy Schubert         /*
291*7f2fe78bSCy Schubert          * We're an inetd nowait service.  Let's not risk anything
292*7f2fe78bSCy Schubert          * read/write from/to the inetd socket unintentionally.
293*7f2fe78bSCy Schubert          */
294*7f2fe78bSCy Schubert         devnull = open("/dev/null", O_RDWR);
295*7f2fe78bSCy Schubert         if (devnull == -1) {
296*7f2fe78bSCy Schubert             syslog(LOG_ERR, _("Could not open /dev/null: %s"),
297*7f2fe78bSCy Schubert                    strerror(errno));
298*7f2fe78bSCy Schubert             exit(1);
299*7f2fe78bSCy Schubert         }
300*7f2fe78bSCy Schubert 
301*7f2fe78bSCy Schubert         sock = dup(0);
302*7f2fe78bSCy Schubert         if (sock == -1) {
303*7f2fe78bSCy Schubert             syslog(LOG_ERR, _("Could not dup the inetd socket: %s"),
304*7f2fe78bSCy Schubert                    strerror(errno));
305*7f2fe78bSCy Schubert             exit(1);
306*7f2fe78bSCy Schubert         }
307*7f2fe78bSCy Schubert 
308*7f2fe78bSCy Schubert         dup2(devnull, STDIN_FILENO);
309*7f2fe78bSCy Schubert         dup2(devnull, STDOUT_FILENO);
310*7f2fe78bSCy Schubert         dup2(devnull, STDERR_FILENO);
311*7f2fe78bSCy Schubert         close(devnull);
312*7f2fe78bSCy Schubert         doit(sock);
313*7f2fe78bSCy Schubert         exit(0);
314*7f2fe78bSCy Schubert     }
315*7f2fe78bSCy Schubert 
316*7f2fe78bSCy Schubert     if (log_ctx == NULL || log_ctx->iproprole != IPROP_REPLICA) {
317*7f2fe78bSCy Schubert         do_standalone();
318*7f2fe78bSCy Schubert         /* do_standalone() should never return */
319*7f2fe78bSCy Schubert         assert(0);
320*7f2fe78bSCy Schubert     }
321*7f2fe78bSCy Schubert 
322*7f2fe78bSCy Schubert     /*
323*7f2fe78bSCy Schubert      * This is the iprop case.  We'll fork a child to run do_standalone().  The
324*7f2fe78bSCy Schubert      * parent will run do_iprop().  We try to kill the child if we get killed.
325*7f2fe78bSCy Schubert      * Catch SIGUSR1, which can be used to interrupt the sleep timer and force
326*7f2fe78bSCy Schubert      * an iprop request.
327*7f2fe78bSCy Schubert      */
328*7f2fe78bSCy Schubert     signal_wrapper(SIGHUP, kill_do_standalone);
329*7f2fe78bSCy Schubert     signal_wrapper(SIGINT, kill_do_standalone);
330*7f2fe78bSCy Schubert     signal_wrapper(SIGQUIT, kill_do_standalone);
331*7f2fe78bSCy Schubert     signal_wrapper(SIGTERM, kill_do_standalone);
332*7f2fe78bSCy Schubert     signal_wrapper(SIGSEGV, kill_do_standalone);
333*7f2fe78bSCy Schubert     signal_wrapper(SIGUSR1, usr1_handler);
334*7f2fe78bSCy Schubert     atexit(atexit_kill_do_standalone);
335*7f2fe78bSCy Schubert     fullprop_child = fork();
336*7f2fe78bSCy Schubert     switch (fullprop_child) {
337*7f2fe78bSCy Schubert     case -1:
338*7f2fe78bSCy Schubert         com_err(progname, errno, _("do_iprop failed.\n"));
339*7f2fe78bSCy Schubert         break;
340*7f2fe78bSCy Schubert     case 0:
341*7f2fe78bSCy Schubert         do_standalone();
342*7f2fe78bSCy Schubert         /* do_standalone() should never return */
343*7f2fe78bSCy Schubert         /* NOTREACHED */
344*7f2fe78bSCy Schubert         break;
345*7f2fe78bSCy Schubert     default:
346*7f2fe78bSCy Schubert         retval = do_iprop();
347*7f2fe78bSCy Schubert         /* do_iprop() can return due to failures and runonce. */
348*7f2fe78bSCy Schubert         kill(fullprop_child, SIGHUP);
349*7f2fe78bSCy Schubert         wait(NULL);
350*7f2fe78bSCy Schubert         if (retval)
351*7f2fe78bSCy Schubert             com_err(progname, retval, _("do_iprop failed.\n"));
352*7f2fe78bSCy Schubert         else
353*7f2fe78bSCy Schubert             exit(0);
354*7f2fe78bSCy Schubert     }
355*7f2fe78bSCy Schubert 
356*7f2fe78bSCy Schubert     exit(1);
357*7f2fe78bSCy Schubert }
358*7f2fe78bSCy Schubert 
359*7f2fe78bSCy Schubert /* Use getaddrinfo to determine a wildcard listener address, preferring
360*7f2fe78bSCy Schubert  * IPv6 if available. */
361*7f2fe78bSCy Schubert static int
get_wildcard_addr(struct addrinfo ** res)362*7f2fe78bSCy Schubert get_wildcard_addr(struct addrinfo **res)
363*7f2fe78bSCy Schubert {
364*7f2fe78bSCy Schubert     struct addrinfo hints;
365*7f2fe78bSCy Schubert     int error;
366*7f2fe78bSCy Schubert 
367*7f2fe78bSCy Schubert     memset(&hints, 0, sizeof(hints));
368*7f2fe78bSCy Schubert     hints.ai_socktype = SOCK_STREAM;
369*7f2fe78bSCy Schubert     hints.ai_flags = AI_PASSIVE | AI_ADDRCONFIG;
370*7f2fe78bSCy Schubert     hints.ai_family = AF_INET6;
371*7f2fe78bSCy Schubert     error = getaddrinfo(NULL, port, &hints, res);
372*7f2fe78bSCy Schubert     if (error == 0)
373*7f2fe78bSCy Schubert         return 0;
374*7f2fe78bSCy Schubert     hints.ai_family = AF_INET;
375*7f2fe78bSCy Schubert     return getaddrinfo(NULL, port, &hints, res);
376*7f2fe78bSCy Schubert }
377*7f2fe78bSCy Schubert 
378*7f2fe78bSCy Schubert static void
do_standalone()379*7f2fe78bSCy Schubert do_standalone()
380*7f2fe78bSCy Schubert {
381*7f2fe78bSCy Schubert     struct sockaddr_in frominet;
382*7f2fe78bSCy Schubert     struct addrinfo *res;
383*7f2fe78bSCy Schubert     GETPEERNAME_ARG3_TYPE fromlen;
384*7f2fe78bSCy Schubert     int finet, s, ret, error, val, status;
385*7f2fe78bSCy Schubert     pid_t child_pid;
386*7f2fe78bSCy Schubert     pid_t wait_pid;
387*7f2fe78bSCy Schubert 
388*7f2fe78bSCy Schubert     error = get_wildcard_addr(&res);
389*7f2fe78bSCy Schubert     if (error != 0) {
390*7f2fe78bSCy Schubert         fprintf(stderr, _("getaddrinfo: %s\n"), gai_strerror(error));
391*7f2fe78bSCy Schubert         exit(1);
392*7f2fe78bSCy Schubert     }
393*7f2fe78bSCy Schubert 
394*7f2fe78bSCy Schubert     finet = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
395*7f2fe78bSCy Schubert     if (finet < 0) {
396*7f2fe78bSCy Schubert         com_err(progname, errno, _("while obtaining socket"));
397*7f2fe78bSCy Schubert         exit(1);
398*7f2fe78bSCy Schubert     }
399*7f2fe78bSCy Schubert 
400*7f2fe78bSCy Schubert     val = 1;
401*7f2fe78bSCy Schubert     if (setsockopt(finet, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) < 0)
402*7f2fe78bSCy Schubert         com_err(progname, errno, _("while setting SO_REUSEADDR option"));
403*7f2fe78bSCy Schubert 
404*7f2fe78bSCy Schubert #if defined(IPV6_V6ONLY)
405*7f2fe78bSCy Schubert     /* Make sure dual-stack support is enabled on IPv6 listener sockets if
406*7f2fe78bSCy Schubert      * possible. */
407*7f2fe78bSCy Schubert     val = 0;
408*7f2fe78bSCy Schubert     if (res->ai_family == AF_INET6 &&
409*7f2fe78bSCy Schubert         setsockopt(finet, IPPROTO_IPV6, IPV6_V6ONLY, &val, sizeof(val)) < 0)
410*7f2fe78bSCy Schubert         com_err(progname, errno, _("while unsetting IPV6_V6ONLY option"));
411*7f2fe78bSCy Schubert #endif
412*7f2fe78bSCy Schubert 
413*7f2fe78bSCy Schubert     ret = bind(finet, res->ai_addr, res->ai_addrlen);
414*7f2fe78bSCy Schubert     if (ret < 0) {
415*7f2fe78bSCy Schubert         com_err(progname, errno, _("while binding listener socket"));
416*7f2fe78bSCy Schubert         exit(1);
417*7f2fe78bSCy Schubert     }
418*7f2fe78bSCy Schubert     if (listen(finet, 5) < 0) {
419*7f2fe78bSCy Schubert         com_err(progname, errno, "in listen call");
420*7f2fe78bSCy Schubert         exit(1);
421*7f2fe78bSCy Schubert     }
422*7f2fe78bSCy Schubert     for (;;) {
423*7f2fe78bSCy Schubert         memset(&frominet, 0, sizeof(frominet));
424*7f2fe78bSCy Schubert         fromlen = sizeof(frominet);
425*7f2fe78bSCy Schubert         if (debug)
426*7f2fe78bSCy Schubert             fprintf(stderr, _("waiting for a kprop connection\n"));
427*7f2fe78bSCy Schubert         s = accept(finet, (struct sockaddr *) &frominet, &fromlen);
428*7f2fe78bSCy Schubert 
429*7f2fe78bSCy Schubert         if (s < 0) {
430*7f2fe78bSCy Schubert             int e = errno;
431*7f2fe78bSCy Schubert             if (e != EINTR) {
432*7f2fe78bSCy Schubert                 com_err(progname, e, _("while accepting connection"));
433*7f2fe78bSCy Schubert             }
434*7f2fe78bSCy Schubert         }
435*7f2fe78bSCy Schubert         child_pid = fork();
436*7f2fe78bSCy Schubert         switch (child_pid) {
437*7f2fe78bSCy Schubert         case -1:
438*7f2fe78bSCy Schubert             com_err(progname, errno, _("while forking"));
439*7f2fe78bSCy Schubert             exit(1);
440*7f2fe78bSCy Schubert         case 0:
441*7f2fe78bSCy Schubert             close(finet);
442*7f2fe78bSCy Schubert 
443*7f2fe78bSCy Schubert             doit(s);
444*7f2fe78bSCy Schubert             close(s);
445*7f2fe78bSCy Schubert             _exit(0);
446*7f2fe78bSCy Schubert         default:
447*7f2fe78bSCy Schubert             do {
448*7f2fe78bSCy Schubert                 wait_pid = waitpid(child_pid, &status, 0);
449*7f2fe78bSCy Schubert             } while (wait_pid == -1 && errno == EINTR);
450*7f2fe78bSCy Schubert             if (wait_pid == -1) {
451*7f2fe78bSCy Schubert                 /* Something bad happened; panic. */
452*7f2fe78bSCy Schubert                 if (debug) {
453*7f2fe78bSCy Schubert                     fprintf(stderr, _("waitpid() failed to wait for doit() "
454*7f2fe78bSCy Schubert                                       "(%d %s)\n"), errno, strerror(errno));
455*7f2fe78bSCy Schubert                 }
456*7f2fe78bSCy Schubert                 com_err(progname, errno,
457*7f2fe78bSCy Schubert                         _("while waiting to receive database"));
458*7f2fe78bSCy Schubert                 exit(1);
459*7f2fe78bSCy Schubert             }
460*7f2fe78bSCy Schubert             if (debug) {
461*7f2fe78bSCy Schubert                 fprintf(stderr, _("Database load process for full propagation "
462*7f2fe78bSCy Schubert                                   "completed.\n"));
463*7f2fe78bSCy Schubert             }
464*7f2fe78bSCy Schubert 
465*7f2fe78bSCy Schubert             close(s);
466*7f2fe78bSCy Schubert 
467*7f2fe78bSCy Schubert             /* If we are the fullprop child in iprop mode, notify the parent
468*7f2fe78bSCy Schubert              * process that it should poll for incremental updates. */
469*7f2fe78bSCy Schubert             if (fullprop_child == 0)
470*7f2fe78bSCy Schubert                 kill(getppid(), SIGUSR1);
471*7f2fe78bSCy Schubert             else if (runonce)
472*7f2fe78bSCy Schubert                 exit(0);
473*7f2fe78bSCy Schubert         }
474*7f2fe78bSCy Schubert     }
475*7f2fe78bSCy Schubert     exit(0);
476*7f2fe78bSCy Schubert }
477*7f2fe78bSCy Schubert 
478*7f2fe78bSCy Schubert static void
doit(int fd)479*7f2fe78bSCy Schubert doit(int fd)
480*7f2fe78bSCy Schubert {
481*7f2fe78bSCy Schubert     struct sockaddr_storage from;
482*7f2fe78bSCy Schubert     int on = 1;
483*7f2fe78bSCy Schubert     GETPEERNAME_ARG3_TYPE fromlen;
484*7f2fe78bSCy Schubert     krb5_error_code retval;
485*7f2fe78bSCy Schubert     krb5_data confmsg;
486*7f2fe78bSCy Schubert     int lock_fd;
487*7f2fe78bSCy Schubert     mode_t omask;
488*7f2fe78bSCy Schubert     krb5_enctype etype;
489*7f2fe78bSCy Schubert     int database_fd;
490*7f2fe78bSCy Schubert     char host[INET6_ADDRSTRLEN + 1];
491*7f2fe78bSCy Schubert 
492*7f2fe78bSCy Schubert     signal_wrapper(SIGALRM, alarm_handler);
493*7f2fe78bSCy Schubert     alarm(params.iprop_resync_timeout);
494*7f2fe78bSCy Schubert     fromlen = sizeof(from);
495*7f2fe78bSCy Schubert     if (getpeername(fd, (struct sockaddr *)&from, &fromlen) < 0) {
496*7f2fe78bSCy Schubert #ifdef ENOTSOCK
497*7f2fe78bSCy Schubert         if (errno == ENOTSOCK && fd == 0 && !standalone) {
498*7f2fe78bSCy Schubert             fprintf(stderr,
499*7f2fe78bSCy Schubert                     _("%s: Standard input does not appear to be a network "
500*7f2fe78bSCy Schubert                       "socket.\n"
501*7f2fe78bSCy Schubert                       "\t(Not run from inetd, and missing the -S option?)\n"),
502*7f2fe78bSCy Schubert                     progname);
503*7f2fe78bSCy Schubert             exit(1);
504*7f2fe78bSCy Schubert         }
505*7f2fe78bSCy Schubert #endif
506*7f2fe78bSCy Schubert         fprintf(stderr, "%s: ", progname);
507*7f2fe78bSCy Schubert         perror("getpeername");
508*7f2fe78bSCy Schubert         exit(1);
509*7f2fe78bSCy Schubert     }
510*7f2fe78bSCy Schubert     if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof(on)) < 0) {
511*7f2fe78bSCy Schubert         com_err(progname, errno,
512*7f2fe78bSCy Schubert                 _("while attempting setsockopt (SO_KEEPALIVE)"));
513*7f2fe78bSCy Schubert     }
514*7f2fe78bSCy Schubert 
515*7f2fe78bSCy Schubert     if (getnameinfo((const struct sockaddr *) &from, fromlen,
516*7f2fe78bSCy Schubert                     host, sizeof(host), NULL, 0, 0) == 0) {
517*7f2fe78bSCy Schubert         syslog(LOG_INFO, _("Connection from %s"), host);
518*7f2fe78bSCy Schubert         if (debug)
519*7f2fe78bSCy Schubert             fprintf(stderr, "Connection from %s\n", host);
520*7f2fe78bSCy Schubert     }
521*7f2fe78bSCy Schubert 
522*7f2fe78bSCy Schubert     /*
523*7f2fe78bSCy Schubert      * Now do the authentication
524*7f2fe78bSCy Schubert      */
525*7f2fe78bSCy Schubert     kerberos_authenticate(kpropd_context, fd, &client, &etype, &from);
526*7f2fe78bSCy Schubert 
527*7f2fe78bSCy Schubert     if (!authorized_principal(kpropd_context, client, etype)) {
528*7f2fe78bSCy Schubert         char *name;
529*7f2fe78bSCy Schubert 
530*7f2fe78bSCy Schubert         retval = krb5_unparse_name(kpropd_context, client, &name);
531*7f2fe78bSCy Schubert         if (retval) {
532*7f2fe78bSCy Schubert             com_err(progname, retval, "While unparsing client name");
533*7f2fe78bSCy Schubert             exit(1);
534*7f2fe78bSCy Schubert         }
535*7f2fe78bSCy Schubert         if (debug) {
536*7f2fe78bSCy Schubert             fprintf(stderr,
537*7f2fe78bSCy Schubert                     _("Rejected connection from unauthorized principal %s\n"),
538*7f2fe78bSCy Schubert                     name);
539*7f2fe78bSCy Schubert         }
540*7f2fe78bSCy Schubert         syslog(LOG_WARNING,
541*7f2fe78bSCy Schubert                _("Rejected connection from unauthorized principal %s"),
542*7f2fe78bSCy Schubert                name);
543*7f2fe78bSCy Schubert         free(name);
544*7f2fe78bSCy Schubert         exit(1);
545*7f2fe78bSCy Schubert     }
546*7f2fe78bSCy Schubert     omask = umask(077);
547*7f2fe78bSCy Schubert     lock_fd = open(temp_file_name, O_RDWR | O_CREAT, 0600);
548*7f2fe78bSCy Schubert     (void)umask(omask);
549*7f2fe78bSCy Schubert     retval = krb5_lock_file(kpropd_context, lock_fd,
550*7f2fe78bSCy Schubert                             KRB5_LOCKMODE_EXCLUSIVE | KRB5_LOCKMODE_DONTBLOCK);
551*7f2fe78bSCy Schubert     if (retval) {
552*7f2fe78bSCy Schubert         com_err(progname, retval, _("while trying to lock '%s'"),
553*7f2fe78bSCy Schubert                 temp_file_name);
554*7f2fe78bSCy Schubert         exit(1);
555*7f2fe78bSCy Schubert     }
556*7f2fe78bSCy Schubert     database_fd = open(temp_file_name, O_WRONLY | O_CREAT | O_TRUNC, 0600);
557*7f2fe78bSCy Schubert     if (database_fd < 0) {
558*7f2fe78bSCy Schubert         com_err(progname, errno, _("while opening database file, '%s'"),
559*7f2fe78bSCy Schubert                 temp_file_name);
560*7f2fe78bSCy Schubert         exit(1);
561*7f2fe78bSCy Schubert     }
562*7f2fe78bSCy Schubert     recv_database(kpropd_context, fd, database_fd, &confmsg);
563*7f2fe78bSCy Schubert     if (rename(temp_file_name, file)) {
564*7f2fe78bSCy Schubert         com_err(progname, errno, _("while renaming %s to %s"),
565*7f2fe78bSCy Schubert                 temp_file_name, file);
566*7f2fe78bSCy Schubert         exit(1);
567*7f2fe78bSCy Schubert     }
568*7f2fe78bSCy Schubert     retval = krb5_lock_file(kpropd_context, lock_fd, KRB5_LOCKMODE_SHARED);
569*7f2fe78bSCy Schubert     if (retval) {
570*7f2fe78bSCy Schubert         com_err(progname, retval, _("while downgrading lock on '%s'"),
571*7f2fe78bSCy Schubert                 temp_file_name);
572*7f2fe78bSCy Schubert         exit(1);
573*7f2fe78bSCy Schubert     }
574*7f2fe78bSCy Schubert     load_database(kpropd_context, kdb5_util, file);
575*7f2fe78bSCy Schubert     retval = krb5_lock_file(kpropd_context, lock_fd, KRB5_LOCKMODE_UNLOCK);
576*7f2fe78bSCy Schubert     if (retval) {
577*7f2fe78bSCy Schubert         com_err(progname, retval, _("while unlocking '%s'"), temp_file_name);
578*7f2fe78bSCy Schubert         exit(1);
579*7f2fe78bSCy Schubert     }
580*7f2fe78bSCy Schubert     close(lock_fd);
581*7f2fe78bSCy Schubert 
582*7f2fe78bSCy Schubert     /*
583*7f2fe78bSCy Schubert      * Send the acknowledgement message generated in
584*7f2fe78bSCy Schubert      * recv_database, then close the socket.
585*7f2fe78bSCy Schubert      */
586*7f2fe78bSCy Schubert     retval = krb5_write_message(kpropd_context, &fd, &confmsg);
587*7f2fe78bSCy Schubert     if (retval) {
588*7f2fe78bSCy Schubert         krb5_free_data_contents(kpropd_context, &confmsg);
589*7f2fe78bSCy Schubert         com_err(progname, retval, _("while sending # of received bytes"));
590*7f2fe78bSCy Schubert         exit(1);
591*7f2fe78bSCy Schubert     }
592*7f2fe78bSCy Schubert     krb5_free_data_contents(kpropd_context, &confmsg);
593*7f2fe78bSCy Schubert     if (close(fd) < 0) {
594*7f2fe78bSCy Schubert         com_err(progname, errno,
595*7f2fe78bSCy Schubert                 _("while trying to close database file"));
596*7f2fe78bSCy Schubert         exit(1);
597*7f2fe78bSCy Schubert     }
598*7f2fe78bSCy Schubert 
599*7f2fe78bSCy Schubert     exit(0);
600*7f2fe78bSCy Schubert }
601*7f2fe78bSCy Schubert 
602*7f2fe78bSCy Schubert /* Default timeout can be changed using clnt_control() */
603*7f2fe78bSCy Schubert static struct timeval full_resync_timeout = { 25, 0 };
604*7f2fe78bSCy Schubert 
605*7f2fe78bSCy Schubert static kdb_fullresync_result_t *
full_resync(CLIENT * clnt)606*7f2fe78bSCy Schubert full_resync(CLIENT *clnt)
607*7f2fe78bSCy Schubert {
608*7f2fe78bSCy Schubert     static kdb_fullresync_result_t clnt_res;
609*7f2fe78bSCy Schubert     uint32_t vers = IPROPX_VERSION_1; /* max version we support */
610*7f2fe78bSCy Schubert     enum clnt_stat status;
611*7f2fe78bSCy Schubert 
612*7f2fe78bSCy Schubert     memset(&clnt_res, 0, sizeof(clnt_res));
613*7f2fe78bSCy Schubert 
614*7f2fe78bSCy Schubert     status = clnt_call(clnt, IPROP_FULL_RESYNC_EXT, (xdrproc_t)xdr_u_int32,
615*7f2fe78bSCy Schubert                        &vers, (xdrproc_t)xdr_kdb_fullresync_result_t,
616*7f2fe78bSCy Schubert                        &clnt_res, full_resync_timeout);
617*7f2fe78bSCy Schubert     if (status == RPC_PROCUNAVAIL) {
618*7f2fe78bSCy Schubert         status = clnt_call(clnt, IPROP_FULL_RESYNC, (xdrproc_t)xdr_void,
619*7f2fe78bSCy Schubert                            &vers, (xdrproc_t)xdr_kdb_fullresync_result_t,
620*7f2fe78bSCy Schubert                            &clnt_res, full_resync_timeout);
621*7f2fe78bSCy Schubert     }
622*7f2fe78bSCy Schubert 
623*7f2fe78bSCy Schubert     return (status == RPC_SUCCESS) ? &clnt_res : NULL;
624*7f2fe78bSCy Schubert }
625*7f2fe78bSCy Schubert 
626*7f2fe78bSCy Schubert /*
627*7f2fe78bSCy Schubert  * Beg for incrementals from the KDC.
628*7f2fe78bSCy Schubert  *
629*7f2fe78bSCy Schubert  * Returns 0 on success IFF runonce is true.
630*7f2fe78bSCy Schubert  * Returns non-zero on failure due to errors.
631*7f2fe78bSCy Schubert  */
632*7f2fe78bSCy Schubert krb5_error_code
do_iprop()633*7f2fe78bSCy Schubert do_iprop()
634*7f2fe78bSCy Schubert {
635*7f2fe78bSCy Schubert     kadm5_ret_t retval;
636*7f2fe78bSCy Schubert     krb5_principal iprop_svc_principal = NULL;
637*7f2fe78bSCy Schubert     void *server_handle = NULL;
638*7f2fe78bSCy Schubert     char *iprop_svc_princstr = NULL, *primary_svc_princstr = NULL;
639*7f2fe78bSCy Schubert     unsigned int pollin, backoff_time;
640*7f2fe78bSCy Schubert     int backoff_cnt = 0, reinit_cnt = 0;
641*7f2fe78bSCy Schubert     struct timeval iprop_start, iprop_end;
642*7f2fe78bSCy Schubert     unsigned long usec;
643*7f2fe78bSCy Schubert     time_t frrequested = 0, now;
644*7f2fe78bSCy Schubert     kdb_incr_result_t *incr_ret;
645*7f2fe78bSCy Schubert     kdb_last_t mylast;
646*7f2fe78bSCy Schubert     kdb_fullresync_result_t *full_ret;
647*7f2fe78bSCy Schubert     kadm5_iprop_handle_t handle;
648*7f2fe78bSCy Schubert 
649*7f2fe78bSCy Schubert     if (debug)
650*7f2fe78bSCy Schubert         fprintf(stderr, _("Incremental propagation enabled\n"));
651*7f2fe78bSCy Schubert 
652*7f2fe78bSCy Schubert     pollin = params.iprop_poll_time;
653*7f2fe78bSCy Schubert     if (pollin == 0)
654*7f2fe78bSCy Schubert         pollin = 10;
655*7f2fe78bSCy Schubert 
656*7f2fe78bSCy Schubert     retval = kadm5_get_kiprop_host_srv_name(kpropd_context, realm,
657*7f2fe78bSCy Schubert                                             &primary_svc_princstr);
658*7f2fe78bSCy Schubert     if (retval) {
659*7f2fe78bSCy Schubert         com_err(progname, retval, _("%s: unable to get kiprop host based "
660*7f2fe78bSCy Schubert                                     "service name for realm %s\n"),
661*7f2fe78bSCy Schubert                 progname, realm);
662*7f2fe78bSCy Schubert         goto done;
663*7f2fe78bSCy Schubert     }
664*7f2fe78bSCy Schubert 
665*7f2fe78bSCy Schubert     retval = sn2princ_realm(kpropd_context, NULL, KIPROP_SVC_NAME, realm,
666*7f2fe78bSCy Schubert                             &iprop_svc_principal);
667*7f2fe78bSCy Schubert     if (retval) {
668*7f2fe78bSCy Schubert         com_err(progname, retval,
669*7f2fe78bSCy Schubert                 _("while trying to construct host service principal"));
670*7f2fe78bSCy Schubert         goto done;
671*7f2fe78bSCy Schubert     }
672*7f2fe78bSCy Schubert 
673*7f2fe78bSCy Schubert     retval = krb5_unparse_name(kpropd_context, iprop_svc_principal,
674*7f2fe78bSCy Schubert                                &iprop_svc_princstr);
675*7f2fe78bSCy Schubert     if (retval) {
676*7f2fe78bSCy Schubert         com_err(progname, retval,
677*7f2fe78bSCy Schubert                 _("while canonicalizing principal name"));
678*7f2fe78bSCy Schubert         goto done;
679*7f2fe78bSCy Schubert     }
680*7f2fe78bSCy Schubert 
681*7f2fe78bSCy Schubert reinit:
682*7f2fe78bSCy Schubert     /*
683*7f2fe78bSCy Schubert      * Authentication, initialize rpcsec_gss handle etc.
684*7f2fe78bSCy Schubert      */
685*7f2fe78bSCy Schubert     if (debug) {
686*7f2fe78bSCy Schubert         fprintf(stderr, _("Initializing kadm5 as client %s\n"),
687*7f2fe78bSCy Schubert                 iprop_svc_princstr);
688*7f2fe78bSCy Schubert     }
689*7f2fe78bSCy Schubert     retval = kadm5_init_with_skey(kpropd_context, iprop_svc_princstr,
690*7f2fe78bSCy Schubert                                   keytab_path,
691*7f2fe78bSCy Schubert                                   primary_svc_princstr,
692*7f2fe78bSCy Schubert                                   &params,
693*7f2fe78bSCy Schubert                                   KADM5_STRUCT_VERSION,
694*7f2fe78bSCy Schubert                                   KADM5_API_VERSION_4,
695*7f2fe78bSCy Schubert                                   db_args,
696*7f2fe78bSCy Schubert                                   &server_handle);
697*7f2fe78bSCy Schubert 
698*7f2fe78bSCy Schubert     if (retval) {
699*7f2fe78bSCy Schubert         if (debug)
700*7f2fe78bSCy Schubert             fprintf(stderr, _("kadm5 initialization failed!\n"));
701*7f2fe78bSCy Schubert         if (retval == KADM5_RPC_ERROR) {
702*7f2fe78bSCy Schubert             reinit_cnt++;
703*7f2fe78bSCy Schubert             if (server_handle)
704*7f2fe78bSCy Schubert                 kadm5_destroy(server_handle);
705*7f2fe78bSCy Schubert             server_handle = NULL;
706*7f2fe78bSCy Schubert             handle = NULL;
707*7f2fe78bSCy Schubert 
708*7f2fe78bSCy Schubert             com_err(progname, retval, _(
709*7f2fe78bSCy Schubert                         "while attempting to connect"
710*7f2fe78bSCy Schubert                         " to primary KDC ... retrying"));
711*7f2fe78bSCy Schubert             backoff_time = backoff_from_primary(&reinit_cnt);
712*7f2fe78bSCy Schubert             if (debug) {
713*7f2fe78bSCy Schubert                 fprintf(stderr, _("Sleeping %d seconds to re-initialize "
714*7f2fe78bSCy Schubert                                   "kadm5 (RPC ERROR)\n"), backoff_time);
715*7f2fe78bSCy Schubert             }
716*7f2fe78bSCy Schubert             sleep(backoff_time);
717*7f2fe78bSCy Schubert             goto reinit;
718*7f2fe78bSCy Schubert         } else {
719*7f2fe78bSCy Schubert             if (retval == KADM5_BAD_CLIENT_PARAMS ||
720*7f2fe78bSCy Schubert                 retval == KADM5_BAD_SERVER_PARAMS) {
721*7f2fe78bSCy Schubert                 com_err(progname, retval,
722*7f2fe78bSCy Schubert                         _("while initializing %s interface"),
723*7f2fe78bSCy Schubert                         progname);
724*7f2fe78bSCy Schubert 
725*7f2fe78bSCy Schubert                 usage();
726*7f2fe78bSCy Schubert             }
727*7f2fe78bSCy Schubert             reinit_cnt++;
728*7f2fe78bSCy Schubert             com_err(progname, retval,
729*7f2fe78bSCy Schubert                     _("while initializing %s interface, retrying"),
730*7f2fe78bSCy Schubert                     progname);
731*7f2fe78bSCy Schubert             backoff_time = backoff_from_primary(&reinit_cnt);
732*7f2fe78bSCy Schubert             if (debug) {
733*7f2fe78bSCy Schubert                 fprintf(stderr, _("Sleeping %d seconds to re-initialize "
734*7f2fe78bSCy Schubert                                   "kadm5 (krb5kdc not running?)\n"),
735*7f2fe78bSCy Schubert                         backoff_time);
736*7f2fe78bSCy Schubert             }
737*7f2fe78bSCy Schubert             sleep(backoff_time);
738*7f2fe78bSCy Schubert             goto reinit;
739*7f2fe78bSCy Schubert         }
740*7f2fe78bSCy Schubert     }
741*7f2fe78bSCy Schubert 
742*7f2fe78bSCy Schubert     if (debug)
743*7f2fe78bSCy Schubert         fprintf(stderr, _("kadm5 initialization succeeded\n"));
744*7f2fe78bSCy Schubert 
745*7f2fe78bSCy Schubert     /*
746*7f2fe78bSCy Schubert      * Reset re-initialization count to zero now.
747*7f2fe78bSCy Schubert      */
748*7f2fe78bSCy Schubert     reinit_cnt = backoff_time = 0;
749*7f2fe78bSCy Schubert 
750*7f2fe78bSCy Schubert     /*
751*7f2fe78bSCy Schubert      * Reset the handle to the correct type for the RPC call
752*7f2fe78bSCy Schubert      */
753*7f2fe78bSCy Schubert     handle = server_handle;
754*7f2fe78bSCy Schubert 
755*7f2fe78bSCy Schubert     for (;;) {
756*7f2fe78bSCy Schubert         incr_ret = NULL;
757*7f2fe78bSCy Schubert         full_ret = NULL;
758*7f2fe78bSCy Schubert 
759*7f2fe78bSCy Schubert         /*
760*7f2fe78bSCy Schubert          * Get the most recent ulog entry sno + ts, which
761*7f2fe78bSCy Schubert          * we package in the request to the primary KDC
762*7f2fe78bSCy Schubert          */
763*7f2fe78bSCy Schubert         retval = ulog_get_last(kpropd_context, &mylast);
764*7f2fe78bSCy Schubert         if (retval) {
765*7f2fe78bSCy Schubert             com_err(progname, retval, _("reading update log header"));
766*7f2fe78bSCy Schubert             goto done;
767*7f2fe78bSCy Schubert         }
768*7f2fe78bSCy Schubert 
769*7f2fe78bSCy Schubert         /*
770*7f2fe78bSCy Schubert          * Loop continuously on an iprop_get_updates_1(),
771*7f2fe78bSCy Schubert          * so that we can keep probing the primary for updates
772*7f2fe78bSCy Schubert          * or (if needed) do a full resync of the krb5 db.
773*7f2fe78bSCy Schubert          */
774*7f2fe78bSCy Schubert 
775*7f2fe78bSCy Schubert         if (debug) {
776*7f2fe78bSCy Schubert             fprintf(stderr, _("Calling iprop_get_updates_1 "
777*7f2fe78bSCy Schubert                               "(sno=%u sec=%u usec=%u)\n"),
778*7f2fe78bSCy Schubert                     (unsigned int)mylast.last_sno,
779*7f2fe78bSCy Schubert                     (unsigned int)mylast.last_time.seconds,
780*7f2fe78bSCy Schubert                     (unsigned int)mylast.last_time.useconds);
781*7f2fe78bSCy Schubert         }
782*7f2fe78bSCy Schubert         gettimeofday(&iprop_start, NULL);
783*7f2fe78bSCy Schubert         incr_ret = iprop_get_updates_1(&mylast, handle->clnt);
784*7f2fe78bSCy Schubert         if (incr_ret == (kdb_incr_result_t *)NULL) {
785*7f2fe78bSCy Schubert             clnt_perror(handle->clnt,
786*7f2fe78bSCy Schubert                         _("iprop_get_updates call failed"));
787*7f2fe78bSCy Schubert             if (server_handle)
788*7f2fe78bSCy Schubert                 kadm5_destroy(server_handle);
789*7f2fe78bSCy Schubert             server_handle = NULL;
790*7f2fe78bSCy Schubert             handle = (kadm5_iprop_handle_t)NULL;
791*7f2fe78bSCy Schubert             if (debug) {
792*7f2fe78bSCy Schubert                 fprintf(stderr, _("Reinitializing iprop because get updates "
793*7f2fe78bSCy Schubert                                   "failed\n"));
794*7f2fe78bSCy Schubert             }
795*7f2fe78bSCy Schubert             goto reinit;
796*7f2fe78bSCy Schubert         }
797*7f2fe78bSCy Schubert 
798*7f2fe78bSCy Schubert         switch (incr_ret->ret) {
799*7f2fe78bSCy Schubert 
800*7f2fe78bSCy Schubert         case UPDATE_FULL_RESYNC_NEEDED:
801*7f2fe78bSCy Schubert             /*
802*7f2fe78bSCy Schubert              * If we're already asked for a full resync and we still
803*7f2fe78bSCy Schubert              * need one and the last one hasn't timed out then just keep
804*7f2fe78bSCy Schubert              * asking for updates as eventually the resync will finish
805*7f2fe78bSCy Schubert              * (or, if it times out we'll just try again).  Note that
806*7f2fe78bSCy Schubert              * doit() also applies a timeout to the full resync, thus
807*7f2fe78bSCy Schubert              * it's OK for us to do the same here.
808*7f2fe78bSCy Schubert              */
809*7f2fe78bSCy Schubert             now = time(NULL);
810*7f2fe78bSCy Schubert             if (frrequested &&
811*7f2fe78bSCy Schubert                 (now - frrequested) < params.iprop_resync_timeout) {
812*7f2fe78bSCy Schubert                 if (debug)
813*7f2fe78bSCy Schubert                     fprintf(stderr, _("Still waiting for full resync\n"));
814*7f2fe78bSCy Schubert                 break;
815*7f2fe78bSCy Schubert             } else {
816*7f2fe78bSCy Schubert                 frrequested = now;
817*7f2fe78bSCy Schubert                 if (debug)
818*7f2fe78bSCy Schubert                     fprintf(stderr, _("Full resync needed\n"));
819*7f2fe78bSCy Schubert                 syslog(LOG_INFO, _("kpropd: Full resync needed."));
820*7f2fe78bSCy Schubert 
821*7f2fe78bSCy Schubert                 full_ret = full_resync(handle->clnt);
822*7f2fe78bSCy Schubert                 if (full_ret == NULL) {
823*7f2fe78bSCy Schubert                     clnt_perror(handle->clnt,
824*7f2fe78bSCy Schubert                                 _("iprop_full_resync call failed"));
825*7f2fe78bSCy Schubert                     kadm5_destroy(server_handle);
826*7f2fe78bSCy Schubert                     server_handle = NULL;
827*7f2fe78bSCy Schubert                     handle = NULL;
828*7f2fe78bSCy Schubert                     goto reinit;
829*7f2fe78bSCy Schubert                 }
830*7f2fe78bSCy Schubert             }
831*7f2fe78bSCy Schubert 
832*7f2fe78bSCy Schubert             switch (full_ret->ret) {
833*7f2fe78bSCy Schubert             case UPDATE_OK:
834*7f2fe78bSCy Schubert                 if (debug)
835*7f2fe78bSCy Schubert                     fprintf(stderr, _("Full resync request granted\n"));
836*7f2fe78bSCy Schubert                 syslog(LOG_INFO, _("Full resync request granted."));
837*7f2fe78bSCy Schubert                 backoff_cnt = 0;
838*7f2fe78bSCy Schubert                 break;
839*7f2fe78bSCy Schubert 
840*7f2fe78bSCy Schubert             case UPDATE_BUSY:
841*7f2fe78bSCy Schubert                 /*
842*7f2fe78bSCy Schubert                  * Exponential backoff
843*7f2fe78bSCy Schubert                  */
844*7f2fe78bSCy Schubert                 if (debug)
845*7f2fe78bSCy Schubert                     fprintf(stderr, _("Exponential backoff\n"));
846*7f2fe78bSCy Schubert                 backoff_cnt++;
847*7f2fe78bSCy Schubert                 break;
848*7f2fe78bSCy Schubert 
849*7f2fe78bSCy Schubert             case UPDATE_PERM_DENIED:
850*7f2fe78bSCy Schubert                 if (debug)
851*7f2fe78bSCy Schubert                     fprintf(stderr, _("Full resync permission denied\n"));
852*7f2fe78bSCy Schubert                 syslog(LOG_ERR, _("Full resync, permission denied."));
853*7f2fe78bSCy Schubert                 goto error;
854*7f2fe78bSCy Schubert 
855*7f2fe78bSCy Schubert             case UPDATE_ERROR:
856*7f2fe78bSCy Schubert                 if (debug)
857*7f2fe78bSCy Schubert                     fprintf(stderr, _("Full resync error from primary\n"));
858*7f2fe78bSCy Schubert                 syslog(LOG_ERR, _(" Full resync, "
859*7f2fe78bSCy Schubert                        "error returned from primary KDC."));
860*7f2fe78bSCy Schubert                 goto error;
861*7f2fe78bSCy Schubert 
862*7f2fe78bSCy Schubert             default:
863*7f2fe78bSCy Schubert                 backoff_cnt = 0;
864*7f2fe78bSCy Schubert                 if (debug) {
865*7f2fe78bSCy Schubert                     fprintf(stderr,
866*7f2fe78bSCy Schubert                             _("Full resync invalid result from primary\n"));
867*7f2fe78bSCy Schubert                 }
868*7f2fe78bSCy Schubert                 syslog(LOG_ERR, _("Full resync, "
869*7f2fe78bSCy Schubert                                   "invalid return from primary KDC."));
870*7f2fe78bSCy Schubert                 break;
871*7f2fe78bSCy Schubert             }
872*7f2fe78bSCy Schubert             break;
873*7f2fe78bSCy Schubert 
874*7f2fe78bSCy Schubert         case UPDATE_OK:
875*7f2fe78bSCy Schubert             backoff_cnt = 0;
876*7f2fe78bSCy Schubert             frrequested = 0;
877*7f2fe78bSCy Schubert 
878*7f2fe78bSCy Schubert             /*
879*7f2fe78bSCy Schubert              * ulog_replay() will convert the ulog updates to db
880*7f2fe78bSCy Schubert              * entries using the kdb conv api and will commit
881*7f2fe78bSCy Schubert              * the entries to the replica kdc database
882*7f2fe78bSCy Schubert              */
883*7f2fe78bSCy Schubert             if (debug) {
884*7f2fe78bSCy Schubert                 fprintf(stderr, _("Got incremental updates "
885*7f2fe78bSCy Schubert                                   "(sno=%u sec=%u usec=%u)\n"),
886*7f2fe78bSCy Schubert                         (unsigned int)incr_ret->lastentry.last_sno,
887*7f2fe78bSCy Schubert                         (unsigned int)incr_ret->lastentry.last_time.seconds,
888*7f2fe78bSCy Schubert                         (unsigned int)incr_ret->lastentry.last_time.useconds);
889*7f2fe78bSCy Schubert             }
890*7f2fe78bSCy Schubert             retval = ulog_replay(kpropd_context, incr_ret, db_args);
891*7f2fe78bSCy Schubert 
892*7f2fe78bSCy Schubert             if (retval) {
893*7f2fe78bSCy Schubert                 const char *msg =
894*7f2fe78bSCy Schubert                     krb5_get_error_message(kpropd_context, retval);
895*7f2fe78bSCy Schubert                 if (debug) {
896*7f2fe78bSCy Schubert                     fprintf(stderr, _("ulog_replay failed (%s), updates not "
897*7f2fe78bSCy Schubert                                       "registered\n"), msg);
898*7f2fe78bSCy Schubert                 }
899*7f2fe78bSCy Schubert                 syslog(LOG_ERR, _("ulog_replay failed (%s), updates "
900*7f2fe78bSCy Schubert                        "not registered."), msg);
901*7f2fe78bSCy Schubert                 krb5_free_error_message(kpropd_context, msg);
902*7f2fe78bSCy Schubert                 break;
903*7f2fe78bSCy Schubert             }
904*7f2fe78bSCy Schubert 
905*7f2fe78bSCy Schubert             gettimeofday(&iprop_end, NULL);
906*7f2fe78bSCy Schubert             usec = (iprop_end.tv_sec - iprop_start.tv_sec) * 1000000 +
907*7f2fe78bSCy Schubert                 iprop_end.tv_usec - iprop_start.tv_usec;
908*7f2fe78bSCy Schubert             syslog(LOG_INFO, _("Incremental updates: %d updates / %lu us"),
909*7f2fe78bSCy Schubert                    incr_ret->updates.kdb_ulog_t_len, usec);
910*7f2fe78bSCy Schubert             if (debug) {
911*7f2fe78bSCy Schubert                 fprintf(stderr, _("Incremental updates: %d updates / "
912*7f2fe78bSCy Schubert                                   "%lu us\n"),
913*7f2fe78bSCy Schubert                         incr_ret->updates.kdb_ulog_t_len, usec);
914*7f2fe78bSCy Schubert             }
915*7f2fe78bSCy Schubert             break;
916*7f2fe78bSCy Schubert 
917*7f2fe78bSCy Schubert         case UPDATE_PERM_DENIED:
918*7f2fe78bSCy Schubert             if (debug)
919*7f2fe78bSCy Schubert                 fprintf(stderr, _("get_updates permission denied\n"));
920*7f2fe78bSCy Schubert             syslog(LOG_ERR, _("get_updates, permission denied."));
921*7f2fe78bSCy Schubert             goto error;
922*7f2fe78bSCy Schubert 
923*7f2fe78bSCy Schubert         case UPDATE_ERROR:
924*7f2fe78bSCy Schubert             if (debug)
925*7f2fe78bSCy Schubert                 fprintf(stderr, _("get_updates error from primary\n"));
926*7f2fe78bSCy Schubert             syslog(LOG_ERR,
927*7f2fe78bSCy Schubert                    _("get_updates, error returned from primary KDC."));
928*7f2fe78bSCy Schubert             goto error;
929*7f2fe78bSCy Schubert 
930*7f2fe78bSCy Schubert         case UPDATE_BUSY:
931*7f2fe78bSCy Schubert             /*
932*7f2fe78bSCy Schubert              * Exponential backoff
933*7f2fe78bSCy Schubert              */
934*7f2fe78bSCy Schubert             if (debug)
935*7f2fe78bSCy Schubert                 fprintf(stderr, _("get_updates primary busy; backoff\n"));
936*7f2fe78bSCy Schubert             backoff_cnt++;
937*7f2fe78bSCy Schubert             break;
938*7f2fe78bSCy Schubert 
939*7f2fe78bSCy Schubert         case UPDATE_NIL:
940*7f2fe78bSCy Schubert             /*
941*7f2fe78bSCy Schubert              * Primary-replica are in sync
942*7f2fe78bSCy Schubert              */
943*7f2fe78bSCy Schubert             if (debug)
944*7f2fe78bSCy Schubert                 fprintf(stderr, _("KDC is synchronized with primary.\n"));
945*7f2fe78bSCy Schubert             backoff_cnt = 0;
946*7f2fe78bSCy Schubert             frrequested = 0;
947*7f2fe78bSCy Schubert             break;
948*7f2fe78bSCy Schubert 
949*7f2fe78bSCy Schubert         default:
950*7f2fe78bSCy Schubert             backoff_cnt = 0;
951*7f2fe78bSCy Schubert             if (debug) {
952*7f2fe78bSCy Schubert                 fprintf(stderr,
953*7f2fe78bSCy Schubert                         _("get_updates invalid result from primary\n"));
954*7f2fe78bSCy Schubert             }
955*7f2fe78bSCy Schubert             syslog(LOG_ERR,
956*7f2fe78bSCy Schubert                    _("get_updates, invalid return from primary KDC."));
957*7f2fe78bSCy Schubert             break;
958*7f2fe78bSCy Schubert         }
959*7f2fe78bSCy Schubert 
960*7f2fe78bSCy Schubert         if (runonce == 1 && incr_ret->ret != UPDATE_FULL_RESYNC_NEEDED)
961*7f2fe78bSCy Schubert             goto done;
962*7f2fe78bSCy Schubert 
963*7f2fe78bSCy Schubert         /*
964*7f2fe78bSCy Schubert          * Sleep for the specified poll interval (Default is 2 mts),
965*7f2fe78bSCy Schubert          * or do a binary exponential backoff if we get an
966*7f2fe78bSCy Schubert          * UPDATE_BUSY signal
967*7f2fe78bSCy Schubert          */
968*7f2fe78bSCy Schubert         if (backoff_cnt > 0) {
969*7f2fe78bSCy Schubert             backoff_time = backoff_from_primary(&backoff_cnt);
970*7f2fe78bSCy Schubert             if (debug) {
971*7f2fe78bSCy Schubert                 fprintf(stderr, _("Busy signal received "
972*7f2fe78bSCy Schubert                                   "from primary, backoff for %d secs\n"),
973*7f2fe78bSCy Schubert                         backoff_time);
974*7f2fe78bSCy Schubert             }
975*7f2fe78bSCy Schubert             sleep(backoff_time);
976*7f2fe78bSCy Schubert         } else {
977*7f2fe78bSCy Schubert             if (debug) {
978*7f2fe78bSCy Schubert                 fprintf(stderr, _("Waiting for %d seconds before checking "
979*7f2fe78bSCy Schubert                                   "for updates again\n"), pollin);
980*7f2fe78bSCy Schubert             }
981*7f2fe78bSCy Schubert             sleep(pollin);
982*7f2fe78bSCy Schubert         }
983*7f2fe78bSCy Schubert 
984*7f2fe78bSCy Schubert     }
985*7f2fe78bSCy Schubert 
986*7f2fe78bSCy Schubert 
987*7f2fe78bSCy Schubert error:
988*7f2fe78bSCy Schubert     if (debug)
989*7f2fe78bSCy Schubert         fprintf(stderr, _("ERROR returned by primary, bailing\n"));
990*7f2fe78bSCy Schubert     syslog(LOG_ERR, _("ERROR returned by primary KDC, bailing.\n"));
991*7f2fe78bSCy Schubert done:
992*7f2fe78bSCy Schubert     free(iprop_svc_princstr);
993*7f2fe78bSCy Schubert     free(primary_svc_princstr);
994*7f2fe78bSCy Schubert     krb5_free_principal(kpropd_context, iprop_svc_principal);
995*7f2fe78bSCy Schubert     krb5_free_default_realm(kpropd_context, def_realm);
996*7f2fe78bSCy Schubert     kadm5_destroy(server_handle);
997*7f2fe78bSCy Schubert     krb5_db_fini(kpropd_context);
998*7f2fe78bSCy Schubert     ulog_fini(kpropd_context);
999*7f2fe78bSCy Schubert     krb5_free_context(kpropd_context);
1000*7f2fe78bSCy Schubert 
1001*7f2fe78bSCy Schubert     return (runonce == 1) ? 0 : 1;
1002*7f2fe78bSCy Schubert }
1003*7f2fe78bSCy Schubert 
1004*7f2fe78bSCy Schubert 
1005*7f2fe78bSCy Schubert /* Do exponential backoff, since primary KDC is BUSY or down. */
1006*7f2fe78bSCy Schubert static unsigned int
backoff_from_primary(int * cnt)1007*7f2fe78bSCy Schubert backoff_from_primary(int *cnt)
1008*7f2fe78bSCy Schubert {
1009*7f2fe78bSCy Schubert     unsigned int btime;
1010*7f2fe78bSCy Schubert 
1011*7f2fe78bSCy Schubert     btime = (unsigned int)(2<<(*cnt));
1012*7f2fe78bSCy Schubert     if (btime > MAX_BACKOFF) {
1013*7f2fe78bSCy Schubert         btime = MAX_BACKOFF;
1014*7f2fe78bSCy Schubert         (*cnt)--;
1015*7f2fe78bSCy Schubert     }
1016*7f2fe78bSCy Schubert 
1017*7f2fe78bSCy Schubert     return btime;
1018*7f2fe78bSCy Schubert }
1019*7f2fe78bSCy Schubert 
1020*7f2fe78bSCy Schubert static void
1021*7f2fe78bSCy Schubert kpropd_com_err_proc(const char *whoami, long code, const char *fmt,
1022*7f2fe78bSCy Schubert                     va_list args)
1023*7f2fe78bSCy Schubert #if !defined(__cplusplus) && (__GNUC__ > 2)
1024*7f2fe78bSCy Schubert     __attribute__((__format__(__printf__, 3, 0)))
1025*7f2fe78bSCy Schubert #endif
1026*7f2fe78bSCy Schubert     ;
1027*7f2fe78bSCy Schubert 
1028*7f2fe78bSCy Schubert static void
kpropd_com_err_proc(const char * whoami,long code,const char * fmt,va_list args)1029*7f2fe78bSCy Schubert kpropd_com_err_proc(const char *whoami, long code, const char *fmt,
1030*7f2fe78bSCy Schubert                     va_list args)
1031*7f2fe78bSCy Schubert {
1032*7f2fe78bSCy Schubert     char error_buf[8096];
1033*7f2fe78bSCy Schubert 
1034*7f2fe78bSCy Schubert     error_buf[0] = '\0';
1035*7f2fe78bSCy Schubert     if (fmt)
1036*7f2fe78bSCy Schubert         vsnprintf(error_buf, sizeof(error_buf), fmt, args);
1037*7f2fe78bSCy Schubert     syslog(LOG_ERR, "%s%s%s%s%s", whoami ? whoami : "", whoami ? ": " : "",
1038*7f2fe78bSCy Schubert            code ? error_message(code) : "", code ? " " : "", error_buf);
1039*7f2fe78bSCy Schubert }
1040*7f2fe78bSCy Schubert 
1041*7f2fe78bSCy Schubert static void
parse_args(int argc,char ** argv)1042*7f2fe78bSCy Schubert parse_args(int argc, char **argv)
1043*7f2fe78bSCy Schubert {
1044*7f2fe78bSCy Schubert     char **newargs;
1045*7f2fe78bSCy Schubert     int c;
1046*7f2fe78bSCy Schubert     krb5_error_code retval;
1047*7f2fe78bSCy Schubert     enum { PID_FILE = 256 };
1048*7f2fe78bSCy Schubert     struct option long_options[] = {
1049*7f2fe78bSCy Schubert         { "pid-file", 1, NULL, PID_FILE },
1050*7f2fe78bSCy Schubert         { NULL, 0, NULL, 0 },
1051*7f2fe78bSCy Schubert     };
1052*7f2fe78bSCy Schubert 
1053*7f2fe78bSCy Schubert     memset(&params, 0, sizeof(params));
1054*7f2fe78bSCy Schubert 
1055*7f2fe78bSCy Schubert     /* Since we may modify the KDB with ulog_replay(), we must read the KDC
1056*7f2fe78bSCy Schubert      * profile. */
1057*7f2fe78bSCy Schubert     retval = krb5int_init_context_kdc(&kpropd_context);
1058*7f2fe78bSCy Schubert     if (retval) {
1059*7f2fe78bSCy Schubert         com_err(argv[0], retval, _("while initializing krb5"));
1060*7f2fe78bSCy Schubert         exit(1);
1061*7f2fe78bSCy Schubert     }
1062*7f2fe78bSCy Schubert 
1063*7f2fe78bSCy Schubert     progname = argv[0];
1064*7f2fe78bSCy Schubert     while ((c = getopt_long(argc, argv, "A:f:F:p:P:r:s:DdSa:tx:",
1065*7f2fe78bSCy Schubert                             long_options, NULL)) != -1) {
1066*7f2fe78bSCy Schubert         switch (c) {
1067*7f2fe78bSCy Schubert         case 'A':
1068*7f2fe78bSCy Schubert             params.mask |= KADM5_CONFIG_ADMIN_SERVER;
1069*7f2fe78bSCy Schubert             params.admin_server = optarg;
1070*7f2fe78bSCy Schubert             break;
1071*7f2fe78bSCy Schubert         case 'f':
1072*7f2fe78bSCy Schubert             file = optarg;
1073*7f2fe78bSCy Schubert             break;
1074*7f2fe78bSCy Schubert         case 'F':
1075*7f2fe78bSCy Schubert             kerb_database = optarg;
1076*7f2fe78bSCy Schubert             break;
1077*7f2fe78bSCy Schubert         case 'p':
1078*7f2fe78bSCy Schubert             kdb5_util = optarg;
1079*7f2fe78bSCy Schubert             break;
1080*7f2fe78bSCy Schubert         case 'P':
1081*7f2fe78bSCy Schubert             port = optarg;
1082*7f2fe78bSCy Schubert             break;
1083*7f2fe78bSCy Schubert         case 'r':
1084*7f2fe78bSCy Schubert             realm = optarg;
1085*7f2fe78bSCy Schubert             break;
1086*7f2fe78bSCy Schubert         case 's':
1087*7f2fe78bSCy Schubert             keytab_path = optarg;
1088*7f2fe78bSCy Schubert             break;
1089*7f2fe78bSCy Schubert         case 'D':
1090*7f2fe78bSCy Schubert             nodaemon++;
1091*7f2fe78bSCy Schubert             break;
1092*7f2fe78bSCy Schubert         case 'd':
1093*7f2fe78bSCy Schubert             debug++;
1094*7f2fe78bSCy Schubert             break;
1095*7f2fe78bSCy Schubert         case 'S':
1096*7f2fe78bSCy Schubert             /* Standalone mode is now auto-detected; see main(). */
1097*7f2fe78bSCy Schubert             break;
1098*7f2fe78bSCy Schubert         case 'a':
1099*7f2fe78bSCy Schubert             acl_file_name = optarg;
1100*7f2fe78bSCy Schubert             break;
1101*7f2fe78bSCy Schubert         case 't':
1102*7f2fe78bSCy Schubert             /* Undocumented option - for testing only.  Run the kpropd
1103*7f2fe78bSCy Schubert              * server exactly once. */
1104*7f2fe78bSCy Schubert             runonce = 1;
1105*7f2fe78bSCy Schubert             break;
1106*7f2fe78bSCy Schubert         case 'x':
1107*7f2fe78bSCy Schubert             newargs = realloc(db_args, (db_args_size + 2) * sizeof(*db_args));
1108*7f2fe78bSCy Schubert             if (newargs == NULL) {
1109*7f2fe78bSCy Schubert                 com_err(argv[0], errno, _("copying db args"));
1110*7f2fe78bSCy Schubert                 exit(1);
1111*7f2fe78bSCy Schubert             }
1112*7f2fe78bSCy Schubert             db_args = newargs;
1113*7f2fe78bSCy Schubert             db_args[db_args_size] = optarg;
1114*7f2fe78bSCy Schubert             db_args[db_args_size + 1] = NULL;
1115*7f2fe78bSCy Schubert             db_args_size++;
1116*7f2fe78bSCy Schubert             break;
1117*7f2fe78bSCy Schubert         case PID_FILE:
1118*7f2fe78bSCy Schubert             pid_file = optarg;
1119*7f2fe78bSCy Schubert             break;
1120*7f2fe78bSCy Schubert         default:
1121*7f2fe78bSCy Schubert             usage();
1122*7f2fe78bSCy Schubert         }
1123*7f2fe78bSCy Schubert     }
1124*7f2fe78bSCy Schubert     if (optind != argc)
1125*7f2fe78bSCy Schubert         usage();
1126*7f2fe78bSCy Schubert 
1127*7f2fe78bSCy Schubert     openlog("kpropd", LOG_PID | LOG_ODELAY, SYSLOG_CLASS);
1128*7f2fe78bSCy Schubert     if (!debug)
1129*7f2fe78bSCy Schubert         set_com_err_hook(kpropd_com_err_proc);
1130*7f2fe78bSCy Schubert 
1131*7f2fe78bSCy Schubert     if (realm == NULL) {
1132*7f2fe78bSCy Schubert         retval = krb5_get_default_realm(kpropd_context, &def_realm);
1133*7f2fe78bSCy Schubert         if (retval) {
1134*7f2fe78bSCy Schubert             com_err(progname, retval, _("Unable to get default realm"));
1135*7f2fe78bSCy Schubert             exit(1);
1136*7f2fe78bSCy Schubert         }
1137*7f2fe78bSCy Schubert         realm = def_realm;
1138*7f2fe78bSCy Schubert     } else {
1139*7f2fe78bSCy Schubert         retval = krb5_set_default_realm(kpropd_context, realm);
1140*7f2fe78bSCy Schubert         if (retval) {
1141*7f2fe78bSCy Schubert             com_err(progname, retval, _("Unable to set default realm"));
1142*7f2fe78bSCy Schubert             exit(1);
1143*7f2fe78bSCy Schubert         }
1144*7f2fe78bSCy Schubert     }
1145*7f2fe78bSCy Schubert 
1146*7f2fe78bSCy Schubert     /* Construct service name from local hostname. */
1147*7f2fe78bSCy Schubert     retval = sn2princ_realm(kpropd_context, NULL, KPROP_SERVICE_NAME, realm,
1148*7f2fe78bSCy Schubert                             &server);
1149*7f2fe78bSCy Schubert     if (retval) {
1150*7f2fe78bSCy Schubert         com_err(progname, retval,
1151*7f2fe78bSCy Schubert                 _("while trying to construct my service name"));
1152*7f2fe78bSCy Schubert         exit(1);
1153*7f2fe78bSCy Schubert     }
1154*7f2fe78bSCy Schubert 
1155*7f2fe78bSCy Schubert     /* Construct the name of the temporary file. */
1156*7f2fe78bSCy Schubert     if (asprintf(&temp_file_name, "%s.temp", file) < 0) {
1157*7f2fe78bSCy Schubert         com_err(progname, ENOMEM,
1158*7f2fe78bSCy Schubert                 _("while allocating filename for temp file"));
1159*7f2fe78bSCy Schubert         exit(1);
1160*7f2fe78bSCy Schubert     }
1161*7f2fe78bSCy Schubert 
1162*7f2fe78bSCy Schubert     params.realm = realm;
1163*7f2fe78bSCy Schubert     params.mask |= KADM5_CONFIG_REALM;
1164*7f2fe78bSCy Schubert     retval = kadm5_get_config_params(kpropd_context, 1, &params, &params);
1165*7f2fe78bSCy Schubert     if (retval) {
1166*7f2fe78bSCy Schubert         com_err(progname, retval, _("while initializing"));
1167*7f2fe78bSCy Schubert         exit(1);
1168*7f2fe78bSCy Schubert     }
1169*7f2fe78bSCy Schubert     if (params.iprop_enabled == TRUE) {
1170*7f2fe78bSCy Schubert         ulog_set_role(kpropd_context, IPROP_REPLICA);
1171*7f2fe78bSCy Schubert 
1172*7f2fe78bSCy Schubert         if (ulog_map(kpropd_context, params.iprop_logfile,
1173*7f2fe78bSCy Schubert                      params.iprop_ulogsize)) {
1174*7f2fe78bSCy Schubert             com_err(progname, errno, _("Unable to map log!\n"));
1175*7f2fe78bSCy Schubert             exit(1);
1176*7f2fe78bSCy Schubert         }
1177*7f2fe78bSCy Schubert     }
1178*7f2fe78bSCy Schubert }
1179*7f2fe78bSCy Schubert 
1180*7f2fe78bSCy Schubert /*
1181*7f2fe78bSCy Schubert  * Figure out who's calling on the other end of the connection....
1182*7f2fe78bSCy Schubert  */
1183*7f2fe78bSCy Schubert static void
kerberos_authenticate(krb5_context context,int fd,krb5_principal * clientp,krb5_enctype * etype,struct sockaddr_storage * my_sin)1184*7f2fe78bSCy Schubert kerberos_authenticate(krb5_context context, int fd, krb5_principal *clientp,
1185*7f2fe78bSCy Schubert                       krb5_enctype *etype, struct sockaddr_storage *my_sin)
1186*7f2fe78bSCy Schubert {
1187*7f2fe78bSCy Schubert     krb5_error_code retval;
1188*7f2fe78bSCy Schubert     krb5_ticket *ticket;
1189*7f2fe78bSCy Schubert     struct sockaddr_storage r_sin;
1190*7f2fe78bSCy Schubert     GETSOCKNAME_ARG3_TYPE sin_length;
1191*7f2fe78bSCy Schubert     krb5_keytab keytab = NULL;
1192*7f2fe78bSCy Schubert     char *name, etypebuf[100];
1193*7f2fe78bSCy Schubert 
1194*7f2fe78bSCy Schubert     sin_length = sizeof(r_sin);
1195*7f2fe78bSCy Schubert     if (getsockname(fd, (struct sockaddr *)&r_sin, &sin_length)) {
1196*7f2fe78bSCy Schubert         com_err(progname, errno, _("while getting local socket address"));
1197*7f2fe78bSCy Schubert         exit(1);
1198*7f2fe78bSCy Schubert     }
1199*7f2fe78bSCy Schubert 
1200*7f2fe78bSCy Schubert     sockaddr2krbaddr(context, r_sin.ss_family, (struct sockaddr *)&r_sin,
1201*7f2fe78bSCy Schubert                      &receiver_addr);
1202*7f2fe78bSCy Schubert 
1203*7f2fe78bSCy Schubert     if (debug) {
1204*7f2fe78bSCy Schubert         retval = krb5_unparse_name(context, server, &name);
1205*7f2fe78bSCy Schubert         if (retval) {
1206*7f2fe78bSCy Schubert             com_err(progname, retval, _("while unparsing client name"));
1207*7f2fe78bSCy Schubert             exit(1);
1208*7f2fe78bSCy Schubert         }
1209*7f2fe78bSCy Schubert         fprintf(stderr, "krb5_recvauth(%d, %s, %s, ...)\n", fd, kprop_version,
1210*7f2fe78bSCy Schubert                 name);
1211*7f2fe78bSCy Schubert         free(name);
1212*7f2fe78bSCy Schubert     }
1213*7f2fe78bSCy Schubert 
1214*7f2fe78bSCy Schubert     retval = krb5_auth_con_init(context, &auth_context);
1215*7f2fe78bSCy Schubert     if (retval) {
1216*7f2fe78bSCy Schubert         syslog(LOG_ERR, _("Error in krb5_auth_con_ini: %s"),
1217*7f2fe78bSCy Schubert                error_message(retval));
1218*7f2fe78bSCy Schubert         exit(1);
1219*7f2fe78bSCy Schubert     }
1220*7f2fe78bSCy Schubert 
1221*7f2fe78bSCy Schubert     retval = krb5_auth_con_setflags(context, auth_context,
1222*7f2fe78bSCy Schubert                                     KRB5_AUTH_CONTEXT_DO_SEQUENCE);
1223*7f2fe78bSCy Schubert     if (retval) {
1224*7f2fe78bSCy Schubert         syslog(LOG_ERR, _("Error in krb5_auth_con_setflags: %s"),
1225*7f2fe78bSCy Schubert                error_message(retval));
1226*7f2fe78bSCy Schubert         exit(1);
1227*7f2fe78bSCy Schubert     }
1228*7f2fe78bSCy Schubert 
1229*7f2fe78bSCy Schubert     /*
1230*7f2fe78bSCy Schubert      * Do not set a remote address, to allow replication over a NAT that
1231*7f2fe78bSCy Schubert      * changes the client address.  A reflection attack against kpropd is
1232*7f2fe78bSCy Schubert      * impossible because kpropd only sends one message at the end.
1233*7f2fe78bSCy Schubert      */
1234*7f2fe78bSCy Schubert     retval = krb5_auth_con_setaddrs(context, auth_context, receiver_addr,
1235*7f2fe78bSCy Schubert                                     NULL);
1236*7f2fe78bSCy Schubert     if (retval) {
1237*7f2fe78bSCy Schubert         syslog(LOG_ERR, _("Error in krb5_auth_con_setaddrs: %s"),
1238*7f2fe78bSCy Schubert                error_message(retval));
1239*7f2fe78bSCy Schubert         exit(1);
1240*7f2fe78bSCy Schubert     }
1241*7f2fe78bSCy Schubert 
1242*7f2fe78bSCy Schubert     if (keytab_path != NULL) {
1243*7f2fe78bSCy Schubert         retval = krb5_kt_resolve(context, keytab_path, &keytab);
1244*7f2fe78bSCy Schubert         if (retval) {
1245*7f2fe78bSCy Schubert             syslog(LOG_ERR, _("Error in krb5_kt_resolve: %s"),
1246*7f2fe78bSCy Schubert                    error_message(retval));
1247*7f2fe78bSCy Schubert             exit(1);
1248*7f2fe78bSCy Schubert         }
1249*7f2fe78bSCy Schubert     }
1250*7f2fe78bSCy Schubert 
1251*7f2fe78bSCy Schubert     retval = krb5_recvauth(context, &auth_context, &fd, kprop_version, server,
1252*7f2fe78bSCy Schubert                            0, keytab, &ticket);
1253*7f2fe78bSCy Schubert     if (retval) {
1254*7f2fe78bSCy Schubert         syslog(LOG_ERR, _("Error in krb5_recvauth: %s"),
1255*7f2fe78bSCy Schubert                error_message(retval));
1256*7f2fe78bSCy Schubert         exit(1);
1257*7f2fe78bSCy Schubert     }
1258*7f2fe78bSCy Schubert 
1259*7f2fe78bSCy Schubert     retval = krb5_copy_principal(context, ticket->enc_part2->client, clientp);
1260*7f2fe78bSCy Schubert     if (retval) {
1261*7f2fe78bSCy Schubert         syslog(LOG_ERR, _("Error in krb5_copy_prinicpal: %s"),
1262*7f2fe78bSCy Schubert                error_message(retval));
1263*7f2fe78bSCy Schubert         exit(1);
1264*7f2fe78bSCy Schubert     }
1265*7f2fe78bSCy Schubert 
1266*7f2fe78bSCy Schubert     *etype = ticket->enc_part.enctype;
1267*7f2fe78bSCy Schubert 
1268*7f2fe78bSCy Schubert     if (debug) {
1269*7f2fe78bSCy Schubert         retval = krb5_unparse_name(context, *clientp, &name);
1270*7f2fe78bSCy Schubert         if (retval) {
1271*7f2fe78bSCy Schubert             com_err(progname, retval, _("while unparsing client name"));
1272*7f2fe78bSCy Schubert             exit(1);
1273*7f2fe78bSCy Schubert         }
1274*7f2fe78bSCy Schubert 
1275*7f2fe78bSCy Schubert         retval = krb5_enctype_to_name(*etype, FALSE, etypebuf,
1276*7f2fe78bSCy Schubert                                       sizeof(etypebuf));
1277*7f2fe78bSCy Schubert         if (retval) {
1278*7f2fe78bSCy Schubert             com_err(progname, retval, _("while unparsing ticket etype"));
1279*7f2fe78bSCy Schubert             exit(1);
1280*7f2fe78bSCy Schubert         }
1281*7f2fe78bSCy Schubert 
1282*7f2fe78bSCy Schubert         fprintf(stderr, _("authenticated client: %s (etype == %s)\n"),
1283*7f2fe78bSCy Schubert                 name, etypebuf);
1284*7f2fe78bSCy Schubert         free(name);
1285*7f2fe78bSCy Schubert     }
1286*7f2fe78bSCy Schubert 
1287*7f2fe78bSCy Schubert     krb5_free_ticket(context, ticket);
1288*7f2fe78bSCy Schubert }
1289*7f2fe78bSCy Schubert 
1290*7f2fe78bSCy Schubert static krb5_boolean
authorized_principal(krb5_context context,krb5_principal p,krb5_enctype auth_etype)1291*7f2fe78bSCy Schubert authorized_principal(krb5_context context, krb5_principal p,
1292*7f2fe78bSCy Schubert                      krb5_enctype auth_etype)
1293*7f2fe78bSCy Schubert {
1294*7f2fe78bSCy Schubert     char *name, *ptr, buf[1024];
1295*7f2fe78bSCy Schubert     krb5_error_code retval;
1296*7f2fe78bSCy Schubert     FILE *acl_file;
1297*7f2fe78bSCy Schubert     int end;
1298*7f2fe78bSCy Schubert     krb5_enctype acl_etype;
1299*7f2fe78bSCy Schubert 
1300*7f2fe78bSCy Schubert     retval = krb5_unparse_name(context, p, &name);
1301*7f2fe78bSCy Schubert     if (retval)
1302*7f2fe78bSCy Schubert         return FALSE;
1303*7f2fe78bSCy Schubert 
1304*7f2fe78bSCy Schubert     acl_file = fopen(acl_file_name, "r");
1305*7f2fe78bSCy Schubert     if (acl_file == NULL)
1306*7f2fe78bSCy Schubert         return FALSE;
1307*7f2fe78bSCy Schubert 
1308*7f2fe78bSCy Schubert     while (!feof(acl_file)) {
1309*7f2fe78bSCy Schubert         if (!fgets(buf, sizeof(buf), acl_file))
1310*7f2fe78bSCy Schubert             break;
1311*7f2fe78bSCy Schubert         end = strlen(buf) - 1;
1312*7f2fe78bSCy Schubert         if (buf[end] == '\n')
1313*7f2fe78bSCy Schubert             buf[end] = '\0';
1314*7f2fe78bSCy Schubert         if (!strncmp(name, buf, strlen(name))) {
1315*7f2fe78bSCy Schubert             ptr = buf + strlen(name);
1316*7f2fe78bSCy Schubert 
1317*7f2fe78bSCy Schubert             /* If the next character is not whitespace or null, then the match
1318*7f2fe78bSCy Schubert              * is only partial.  Continue on to new lines. */
1319*7f2fe78bSCy Schubert             if (*ptr != '\0' && !isspace((int)*ptr))
1320*7f2fe78bSCy Schubert                 continue;
1321*7f2fe78bSCy Schubert 
1322*7f2fe78bSCy Schubert             /* Otherwise, skip trailing whitespace. */
1323*7f2fe78bSCy Schubert             for (; *ptr != '\0' && isspace((int)*ptr); ptr++) ;
1324*7f2fe78bSCy Schubert 
1325*7f2fe78bSCy Schubert             /*
1326*7f2fe78bSCy Schubert              * Now, look for an etype string.  If there isn't one, return true.
1327*7f2fe78bSCy Schubert              * If there is an invalid string, continue.  If there is a valid
1328*7f2fe78bSCy Schubert              * string, return true only if it matches the etype passed in,
1329*7f2fe78bSCy Schubert              * otherwise continue.
1330*7f2fe78bSCy Schubert              */
1331*7f2fe78bSCy Schubert             if (*ptr != '\0' &&
1332*7f2fe78bSCy Schubert                 ((retval = krb5_string_to_enctype(ptr, &acl_etype)) ||
1333*7f2fe78bSCy Schubert                  (acl_etype != auth_etype)))
1334*7f2fe78bSCy Schubert                 continue;
1335*7f2fe78bSCy Schubert 
1336*7f2fe78bSCy Schubert             free(name);
1337*7f2fe78bSCy Schubert             fclose(acl_file);
1338*7f2fe78bSCy Schubert             return TRUE;
1339*7f2fe78bSCy Schubert         }
1340*7f2fe78bSCy Schubert     }
1341*7f2fe78bSCy Schubert     free(name);
1342*7f2fe78bSCy Schubert     fclose(acl_file);
1343*7f2fe78bSCy Schubert     return FALSE;
1344*7f2fe78bSCy Schubert }
1345*7f2fe78bSCy Schubert 
1346*7f2fe78bSCy Schubert static void
recv_database(krb5_context context,int fd,int database_fd,krb5_data * confmsg)1347*7f2fe78bSCy Schubert recv_database(krb5_context context, int fd, int database_fd,
1348*7f2fe78bSCy Schubert               krb5_data *confmsg)
1349*7f2fe78bSCy Schubert {
1350*7f2fe78bSCy Schubert     uint64_t database_size, received_size;
1351*7f2fe78bSCy Schubert     int n;
1352*7f2fe78bSCy Schubert     char buf[1024];
1353*7f2fe78bSCy Schubert     char dbsize_buf[KPROP_DBSIZE_MAX_BUFSIZ];
1354*7f2fe78bSCy Schubert     krb5_data inbuf, outbuf;
1355*7f2fe78bSCy Schubert     krb5_error_code retval;
1356*7f2fe78bSCy Schubert 
1357*7f2fe78bSCy Schubert     /* Receive and decode size from client. */
1358*7f2fe78bSCy Schubert     retval = krb5_read_message(context, &fd, &inbuf);
1359*7f2fe78bSCy Schubert     if (retval) {
1360*7f2fe78bSCy Schubert         send_error(context, fd, retval, "while reading database size");
1361*7f2fe78bSCy Schubert         com_err(progname, retval,
1362*7f2fe78bSCy Schubert                 _("while reading size of database from client"));
1363*7f2fe78bSCy Schubert         exit(1);
1364*7f2fe78bSCy Schubert     }
1365*7f2fe78bSCy Schubert     if (krb5_is_krb_error(&inbuf))
1366*7f2fe78bSCy Schubert         recv_error(context, &inbuf);
1367*7f2fe78bSCy Schubert     retval = krb5_rd_safe(context,auth_context,&inbuf,&outbuf,NULL);
1368*7f2fe78bSCy Schubert     if (retval) {
1369*7f2fe78bSCy Schubert         send_error(context, fd, retval, "while decoding database size");
1370*7f2fe78bSCy Schubert         krb5_free_data_contents(context, &inbuf);
1371*7f2fe78bSCy Schubert         com_err(progname, retval,
1372*7f2fe78bSCy Schubert                 _("while decoding database size from client"));
1373*7f2fe78bSCy Schubert         exit(1);
1374*7f2fe78bSCy Schubert     }
1375*7f2fe78bSCy Schubert 
1376*7f2fe78bSCy Schubert     retval = decode_database_size(&outbuf, &database_size);
1377*7f2fe78bSCy Schubert     if (retval) {
1378*7f2fe78bSCy Schubert         send_error(context, fd, retval, "malformed database size message");
1379*7f2fe78bSCy Schubert         com_err(progname, retval,
1380*7f2fe78bSCy Schubert                 _("malformed database size message from client"));
1381*7f2fe78bSCy Schubert         exit(1);
1382*7f2fe78bSCy Schubert     }
1383*7f2fe78bSCy Schubert 
1384*7f2fe78bSCy Schubert     krb5_free_data_contents(context, &inbuf);
1385*7f2fe78bSCy Schubert     krb5_free_data_contents(context, &outbuf);
1386*7f2fe78bSCy Schubert 
1387*7f2fe78bSCy Schubert     /* Initialize the initial vector. */
1388*7f2fe78bSCy Schubert     retval = krb5_auth_con_initivector(context, auth_context);
1389*7f2fe78bSCy Schubert     if (retval) {
1390*7f2fe78bSCy Schubert         send_error(context, fd, retval,
1391*7f2fe78bSCy Schubert                    "failed while initializing i_vector");
1392*7f2fe78bSCy Schubert         com_err(progname, retval, _("while initializing i_vector"));
1393*7f2fe78bSCy Schubert         exit(1);
1394*7f2fe78bSCy Schubert     }
1395*7f2fe78bSCy Schubert 
1396*7f2fe78bSCy Schubert     if (debug)
1397*7f2fe78bSCy Schubert         fprintf(stderr, _("Full propagation transfer started.\n"));
1398*7f2fe78bSCy Schubert 
1399*7f2fe78bSCy Schubert     /* Now start receiving the database from the net. */
1400*7f2fe78bSCy Schubert     received_size = 0;
1401*7f2fe78bSCy Schubert     while (received_size < database_size) {
1402*7f2fe78bSCy Schubert         retval = krb5_read_message(context, &fd, &inbuf);
1403*7f2fe78bSCy Schubert         if (retval) {
1404*7f2fe78bSCy Schubert             snprintf(buf, sizeof(buf),
1405*7f2fe78bSCy Schubert                      "while reading database block starting at offset %"PRIu64,
1406*7f2fe78bSCy Schubert                      received_size);
1407*7f2fe78bSCy Schubert             com_err(progname, retval, "%s", buf);
1408*7f2fe78bSCy Schubert             send_error(context, fd, retval, buf);
1409*7f2fe78bSCy Schubert             exit(1);
1410*7f2fe78bSCy Schubert         }
1411*7f2fe78bSCy Schubert         if (krb5_is_krb_error(&inbuf))
1412*7f2fe78bSCy Schubert             recv_error(context, &inbuf);
1413*7f2fe78bSCy Schubert         retval = krb5_rd_priv(context, auth_context, &inbuf, &outbuf, NULL);
1414*7f2fe78bSCy Schubert         if (retval) {
1415*7f2fe78bSCy Schubert             snprintf(buf, sizeof(buf),
1416*7f2fe78bSCy Schubert                      "while decoding database block starting at offset %"
1417*7f2fe78bSCy Schubert                      PRIu64, received_size);
1418*7f2fe78bSCy Schubert             com_err(progname, retval, "%s", buf);
1419*7f2fe78bSCy Schubert             send_error(context, fd, retval, buf);
1420*7f2fe78bSCy Schubert             krb5_free_data_contents(context, &inbuf);
1421*7f2fe78bSCy Schubert             exit(1);
1422*7f2fe78bSCy Schubert         }
1423*7f2fe78bSCy Schubert         n = write(database_fd, outbuf.data, outbuf.length);
1424*7f2fe78bSCy Schubert         krb5_free_data_contents(context, &inbuf);
1425*7f2fe78bSCy Schubert         if (n < 0) {
1426*7f2fe78bSCy Schubert             snprintf(buf, sizeof(buf),
1427*7f2fe78bSCy Schubert                      "while writing database block starting at offset %"PRIu64,
1428*7f2fe78bSCy Schubert                      received_size);
1429*7f2fe78bSCy Schubert             send_error(context, fd, errno, buf);
1430*7f2fe78bSCy Schubert         } else if ((unsigned int)n != outbuf.length) {
1431*7f2fe78bSCy Schubert             snprintf(buf, sizeof(buf),
1432*7f2fe78bSCy Schubert                      "incomplete write while writing database block starting "
1433*7f2fe78bSCy Schubert                      "at \noffset %"PRIu64" (%d written, %d expected)",
1434*7f2fe78bSCy Schubert                      received_size, n, outbuf.length);
1435*7f2fe78bSCy Schubert             send_error(context, fd, KRB5KRB_ERR_GENERIC, buf);
1436*7f2fe78bSCy Schubert         }
1437*7f2fe78bSCy Schubert         received_size += outbuf.length;
1438*7f2fe78bSCy Schubert         krb5_free_data_contents(context, &outbuf);
1439*7f2fe78bSCy Schubert     }
1440*7f2fe78bSCy Schubert 
1441*7f2fe78bSCy Schubert     /* OK, we've seen the entire file.  Did we get too many bytes? */
1442*7f2fe78bSCy Schubert     if (received_size > database_size) {
1443*7f2fe78bSCy Schubert         snprintf(buf, sizeof(buf),
1444*7f2fe78bSCy Schubert                  "Received %"PRIu64" bytes, expected %"PRIu64
1445*7f2fe78bSCy Schubert                  " bytes for database file",
1446*7f2fe78bSCy Schubert                  received_size, database_size);
1447*7f2fe78bSCy Schubert         send_error(context, fd, KRB5KRB_ERR_GENERIC, buf);
1448*7f2fe78bSCy Schubert     }
1449*7f2fe78bSCy Schubert 
1450*7f2fe78bSCy Schubert     if (debug)
1451*7f2fe78bSCy Schubert         fprintf(stderr, _("Full propagation transfer finished.\n"));
1452*7f2fe78bSCy Schubert 
1453*7f2fe78bSCy Schubert     /* Create message acknowledging number of bytes received, but
1454*7f2fe78bSCy Schubert      * don't send it until kdb5_util returns successfully. */
1455*7f2fe78bSCy Schubert     inbuf = make_data(dbsize_buf, sizeof(dbsize_buf));
1456*7f2fe78bSCy Schubert     encode_database_size(database_size, &inbuf);
1457*7f2fe78bSCy Schubert     retval = krb5_mk_safe(context,auth_context,&inbuf,confmsg,NULL);
1458*7f2fe78bSCy Schubert     if (retval) {
1459*7f2fe78bSCy Schubert         com_err(progname, retval, "while encoding # of received bytes");
1460*7f2fe78bSCy Schubert         send_error(context, fd, retval, "while encoding # of received bytes");
1461*7f2fe78bSCy Schubert         exit(1);
1462*7f2fe78bSCy Schubert     }
1463*7f2fe78bSCy Schubert }
1464*7f2fe78bSCy Schubert 
1465*7f2fe78bSCy Schubert 
1466*7f2fe78bSCy Schubert static void
send_error(krb5_context context,int fd,krb5_error_code err_code,char * err_text)1467*7f2fe78bSCy Schubert send_error(krb5_context context, int fd, krb5_error_code err_code,
1468*7f2fe78bSCy Schubert            char *err_text)
1469*7f2fe78bSCy Schubert {
1470*7f2fe78bSCy Schubert     krb5_error error;
1471*7f2fe78bSCy Schubert     const char *text;
1472*7f2fe78bSCy Schubert     krb5_data outbuf;
1473*7f2fe78bSCy Schubert     char buf[1024];
1474*7f2fe78bSCy Schubert 
1475*7f2fe78bSCy Schubert     memset(&error, 0, sizeof(error));
1476*7f2fe78bSCy Schubert     krb5_us_timeofday(context, &error.stime, &error.susec);
1477*7f2fe78bSCy Schubert     error.server = server;
1478*7f2fe78bSCy Schubert     error.client = client;
1479*7f2fe78bSCy Schubert 
1480*7f2fe78bSCy Schubert     text = (err_text != NULL) ? err_text : error_message(err_code);
1481*7f2fe78bSCy Schubert 
1482*7f2fe78bSCy Schubert     error.error = err_code - ERROR_TABLE_BASE_krb5;
1483*7f2fe78bSCy Schubert     if (error.error > 127) {
1484*7f2fe78bSCy Schubert         error.error = KRB_ERR_GENERIC;
1485*7f2fe78bSCy Schubert         if (err_text) {
1486*7f2fe78bSCy Schubert             snprintf(buf, sizeof(buf), "%s %s", error_message(err_code),
1487*7f2fe78bSCy Schubert                      err_text);
1488*7f2fe78bSCy Schubert             text = buf;
1489*7f2fe78bSCy Schubert         }
1490*7f2fe78bSCy Schubert     }
1491*7f2fe78bSCy Schubert     error.text.length = strlen(text) + 1;
1492*7f2fe78bSCy Schubert     error.text.data = strdup(text);
1493*7f2fe78bSCy Schubert     if (error.text.data) {
1494*7f2fe78bSCy Schubert         if (!krb5_mk_error(context, &error, &outbuf)) {
1495*7f2fe78bSCy Schubert             (void)krb5_write_message(context, &fd, &outbuf);
1496*7f2fe78bSCy Schubert             krb5_free_data_contents(context, &outbuf);
1497*7f2fe78bSCy Schubert         }
1498*7f2fe78bSCy Schubert         free(error.text.data);
1499*7f2fe78bSCy Schubert     }
1500*7f2fe78bSCy Schubert }
1501*7f2fe78bSCy Schubert 
1502*7f2fe78bSCy Schubert void
recv_error(krb5_context context,krb5_data * inbuf)1503*7f2fe78bSCy Schubert recv_error(krb5_context context, krb5_data *inbuf)
1504*7f2fe78bSCy Schubert {
1505*7f2fe78bSCy Schubert     krb5_error *error;
1506*7f2fe78bSCy Schubert     krb5_error_code retval;
1507*7f2fe78bSCy Schubert 
1508*7f2fe78bSCy Schubert     retval = krb5_rd_error(context, inbuf, &error);
1509*7f2fe78bSCy Schubert     if (retval) {
1510*7f2fe78bSCy Schubert         com_err(progname, retval,
1511*7f2fe78bSCy Schubert                 _("while decoding error packet from client"));
1512*7f2fe78bSCy Schubert         exit(1);
1513*7f2fe78bSCy Schubert     }
1514*7f2fe78bSCy Schubert     if (error->error == KRB_ERR_GENERIC) {
1515*7f2fe78bSCy Schubert         if (error->text.data)
1516*7f2fe78bSCy Schubert             fprintf(stderr, _("Generic remote error: %s\n"), error->text.data);
1517*7f2fe78bSCy Schubert     } else if (error->error) {
1518*7f2fe78bSCy Schubert         com_err(progname,
1519*7f2fe78bSCy Schubert                 (krb5_error_code)error->error + ERROR_TABLE_BASE_krb5,
1520*7f2fe78bSCy Schubert                 _("signaled from server"));
1521*7f2fe78bSCy Schubert         if (error->text.data) {
1522*7f2fe78bSCy Schubert             fprintf(stderr, _("Error text from client: %s\n"),
1523*7f2fe78bSCy Schubert                     error->text.data);
1524*7f2fe78bSCy Schubert         }
1525*7f2fe78bSCy Schubert     }
1526*7f2fe78bSCy Schubert     krb5_free_error(context, error);
1527*7f2fe78bSCy Schubert     exit(1);
1528*7f2fe78bSCy Schubert }
1529*7f2fe78bSCy Schubert 
1530*7f2fe78bSCy Schubert static void
load_database(krb5_context context,char * kdb_util,char * database_file_name)1531*7f2fe78bSCy Schubert load_database(krb5_context context, char *kdb_util, char *database_file_name)
1532*7f2fe78bSCy Schubert {
1533*7f2fe78bSCy Schubert     static char *edit_av[10];
1534*7f2fe78bSCy Schubert     int error_ret, child_pid, count;
1535*7f2fe78bSCy Schubert 
1536*7f2fe78bSCy Schubert     /* <sys/param.h> has been included, so BSD will be defined on
1537*7f2fe78bSCy Schubert      * BSD systems. */
1538*7f2fe78bSCy Schubert #if BSD > 0 && BSD <= 43
1539*7f2fe78bSCy Schubert #ifndef WEXITSTATUS
1540*7f2fe78bSCy Schubert #define WEXITSTATUS(w) (w).w_retcode
1541*7f2fe78bSCy Schubert #endif
1542*7f2fe78bSCy Schubert     union wait waitb;
1543*7f2fe78bSCy Schubert #else
1544*7f2fe78bSCy Schubert     int waitb;
1545*7f2fe78bSCy Schubert #endif
1546*7f2fe78bSCy Schubert     kdb_log_context *log_ctx;
1547*7f2fe78bSCy Schubert 
1548*7f2fe78bSCy Schubert     if (debug)
1549*7f2fe78bSCy Schubert         fprintf(stderr, "calling kdb5_util to load database\n");
1550*7f2fe78bSCy Schubert 
1551*7f2fe78bSCy Schubert     log_ctx = context->kdblog_context;
1552*7f2fe78bSCy Schubert 
1553*7f2fe78bSCy Schubert     edit_av[0] = kdb_util;
1554*7f2fe78bSCy Schubert     count = 1;
1555*7f2fe78bSCy Schubert     if (realm) {
1556*7f2fe78bSCy Schubert         edit_av[count++] = "-r";
1557*7f2fe78bSCy Schubert         edit_av[count++] = realm;
1558*7f2fe78bSCy Schubert     }
1559*7f2fe78bSCy Schubert     edit_av[count++] = "load";
1560*7f2fe78bSCy Schubert     if (kerb_database) {
1561*7f2fe78bSCy Schubert         edit_av[count++] = "-d";
1562*7f2fe78bSCy Schubert         edit_av[count++] = kerb_database;
1563*7f2fe78bSCy Schubert     }
1564*7f2fe78bSCy Schubert     if (log_ctx && log_ctx->iproprole == IPROP_REPLICA)
1565*7f2fe78bSCy Schubert         edit_av[count++] = "-i";
1566*7f2fe78bSCy Schubert     edit_av[count++] = database_file_name;
1567*7f2fe78bSCy Schubert     edit_av[count++] = NULL;
1568*7f2fe78bSCy Schubert 
1569*7f2fe78bSCy Schubert     switch (child_pid = fork()) {
1570*7f2fe78bSCy Schubert     case -1:
1571*7f2fe78bSCy Schubert         com_err(progname, errno, _("while trying to fork %s"), kdb_util);
1572*7f2fe78bSCy Schubert         exit(1);
1573*7f2fe78bSCy Schubert     case 0:
1574*7f2fe78bSCy Schubert         execv(kdb_util, edit_av);
1575*7f2fe78bSCy Schubert         com_err(progname, errno, _("while trying to exec %s"), kdb_util);
1576*7f2fe78bSCy Schubert         _exit(1);
1577*7f2fe78bSCy Schubert         /*NOTREACHED*/
1578*7f2fe78bSCy Schubert     default:
1579*7f2fe78bSCy Schubert         if (debug)
1580*7f2fe78bSCy Schubert             fprintf(stderr, "Load PID is %d\n", child_pid);
1581*7f2fe78bSCy Schubert         if (wait(&waitb) < 0) {
1582*7f2fe78bSCy Schubert             com_err(progname, errno, _("while waiting for %s"), kdb_util);
1583*7f2fe78bSCy Schubert             exit(1);
1584*7f2fe78bSCy Schubert         }
1585*7f2fe78bSCy Schubert     }
1586*7f2fe78bSCy Schubert 
1587*7f2fe78bSCy Schubert     if (!WIFEXITED(waitb)) {
1588*7f2fe78bSCy Schubert         com_err(progname, 0, _("%s load terminated"), kdb_util);
1589*7f2fe78bSCy Schubert         exit(1);
1590*7f2fe78bSCy Schubert     }
1591*7f2fe78bSCy Schubert 
1592*7f2fe78bSCy Schubert     error_ret = WEXITSTATUS(waitb);
1593*7f2fe78bSCy Schubert     if (error_ret) {
1594*7f2fe78bSCy Schubert         com_err(progname, 0, _("%s returned a bad exit status (%d)"),
1595*7f2fe78bSCy Schubert                 kdb_util, error_ret);
1596*7f2fe78bSCy Schubert         exit(1);
1597*7f2fe78bSCy Schubert     }
1598*7f2fe78bSCy Schubert     return;
1599*7f2fe78bSCy Schubert }
1600*7f2fe78bSCy Schubert 
1601*7f2fe78bSCy Schubert /*
1602*7f2fe78bSCy Schubert  * Get the host base service name for the kiprop principal. Returns
1603*7f2fe78bSCy Schubert  * KADM5_OK on success. Caller must free the storage allocated
1604*7f2fe78bSCy Schubert  * for host_service_name.
1605*7f2fe78bSCy Schubert  */
1606*7f2fe78bSCy Schubert static kadm5_ret_t
kadm5_get_kiprop_host_srv_name(krb5_context context,const char * realm_name,char ** host_service_name)1607*7f2fe78bSCy Schubert kadm5_get_kiprop_host_srv_name(krb5_context context, const char *realm_name,
1608*7f2fe78bSCy Schubert                                char **host_service_name)
1609*7f2fe78bSCy Schubert {
1610*7f2fe78bSCy Schubert     char *name, *host;
1611*7f2fe78bSCy Schubert 
1612*7f2fe78bSCy Schubert     host = params.admin_server; /* XXX */
1613*7f2fe78bSCy Schubert     if (asprintf(&name, "%s/%s", KADM5_KIPROP_HOST_SERVICE, host) < 0) {
1614*7f2fe78bSCy Schubert         free(host);
1615*7f2fe78bSCy Schubert         return ENOMEM;
1616*7f2fe78bSCy Schubert     }
1617*7f2fe78bSCy Schubert     *host_service_name = name;
1618*7f2fe78bSCy Schubert 
1619*7f2fe78bSCy Schubert     return KADM5_OK;
1620*7f2fe78bSCy Schubert }
1621