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 ¶ms,
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(¶ms, 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, ¶ms, ¶ms);
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