xref: /titanic_50/usr/src/cmd/krb5/slave/kpropd.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
3*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
4*7c478bd9Sstevel@tonic-gate  *
5*7c478bd9Sstevel@tonic-gate  * All rights reserved.
6*7c478bd9Sstevel@tonic-gate  *
7*7c478bd9Sstevel@tonic-gate  * Export of this software from the United States of America may require
8*7c478bd9Sstevel@tonic-gate  * a specific license from the United States Government.  It is the
9*7c478bd9Sstevel@tonic-gate  * responsibility of any person or organization contemplating export to
10*7c478bd9Sstevel@tonic-gate  * obtain such a license before exporting.
11*7c478bd9Sstevel@tonic-gate  *
12*7c478bd9Sstevel@tonic-gate  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
13*7c478bd9Sstevel@tonic-gate  * distribute this software and its documentation for any purpose and
14*7c478bd9Sstevel@tonic-gate  * without fee is hereby granted, provided that the above copyright
15*7c478bd9Sstevel@tonic-gate  * notice appear in all copies and that both that copyright notice and
16*7c478bd9Sstevel@tonic-gate  * this permission notice appear in supporting documentation, and that
17*7c478bd9Sstevel@tonic-gate  * the name of FundsXpress. not be used in advertising or publicity pertaining
18*7c478bd9Sstevel@tonic-gate  * to distribution of the software without specific, written prior
19*7c478bd9Sstevel@tonic-gate  * permission.  FundsXpress makes no representations about the suitability of
20*7c478bd9Sstevel@tonic-gate  * this software for any purpose.  It is provided "as is" without express
21*7c478bd9Sstevel@tonic-gate  * or implied warranty.
22*7c478bd9Sstevel@tonic-gate  *
23*7c478bd9Sstevel@tonic-gate  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
24*7c478bd9Sstevel@tonic-gate  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
25*7c478bd9Sstevel@tonic-gate  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
26*7c478bd9Sstevel@tonic-gate  */
27*7c478bd9Sstevel@tonic-gate 
28*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
29*7c478bd9Sstevel@tonic-gate 
30*7c478bd9Sstevel@tonic-gate /*
31*7c478bd9Sstevel@tonic-gate  * slave/kpropd.c
32*7c478bd9Sstevel@tonic-gate  *
33*7c478bd9Sstevel@tonic-gate  * Copyright 1990,1991 by the Massachusetts Institute of Technology.
34*7c478bd9Sstevel@tonic-gate  * All Rights Reserved.
35*7c478bd9Sstevel@tonic-gate  *
36*7c478bd9Sstevel@tonic-gate  * Export of this software from the United States of America may
37*7c478bd9Sstevel@tonic-gate  *   require a specific license from the United States Government.
38*7c478bd9Sstevel@tonic-gate  *   It is the responsibility of any person or organization contemplating
39*7c478bd9Sstevel@tonic-gate  *   export to obtain such a license before exporting.
40*7c478bd9Sstevel@tonic-gate  *
41*7c478bd9Sstevel@tonic-gate  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
42*7c478bd9Sstevel@tonic-gate  * distribute this software and its documentation for any purpose and
43*7c478bd9Sstevel@tonic-gate  * without fee is hereby granted, provided that the above copyright
44*7c478bd9Sstevel@tonic-gate  * notice appear in all copies and that both that copyright notice and
45*7c478bd9Sstevel@tonic-gate  * this permission notice appear in supporting documentation, and that
46*7c478bd9Sstevel@tonic-gate  * the name of M.I.T. not be used in advertising or publicity pertaining
47*7c478bd9Sstevel@tonic-gate  * to distribution of the software without specific, written prior
48*7c478bd9Sstevel@tonic-gate  * permission.  Furthermore if you modify this software you must label
49*7c478bd9Sstevel@tonic-gate  * your software as modified software and not distribute it in such a
50*7c478bd9Sstevel@tonic-gate  * fashion that it might be confused with the original M.I.T. software.
51*7c478bd9Sstevel@tonic-gate  * M.I.T. makes no representations about the suitability of
52*7c478bd9Sstevel@tonic-gate  * this software for any purpose.  It is provided "as is" without express
53*7c478bd9Sstevel@tonic-gate  * or implied warranty.
54*7c478bd9Sstevel@tonic-gate  *
55*7c478bd9Sstevel@tonic-gate  *
56*7c478bd9Sstevel@tonic-gate  * XXX We need to modify the protocol so that an acknowledge is set
57*7c478bd9Sstevel@tonic-gate  * after each block, instead after the entire series is sent over.
58*7c478bd9Sstevel@tonic-gate  * The reason for this is so that error packets can get interpreted
59*7c478bd9Sstevel@tonic-gate  * right away.  If you don't do this, the sender may never get the
60*7c478bd9Sstevel@tonic-gate  * error packet, because it will die an EPIPE trying to complete the
61*7c478bd9Sstevel@tonic-gate  * write...
62*7c478bd9Sstevel@tonic-gate  */
63*7c478bd9Sstevel@tonic-gate 
64*7c478bd9Sstevel@tonic-gate #include <stdio.h>
65*7c478bd9Sstevel@tonic-gate #include <ctype.h>
66*7c478bd9Sstevel@tonic-gate #include <sys/file.h>
67*7c478bd9Sstevel@tonic-gate #include <signal.h>
68*7c478bd9Sstevel@tonic-gate #include <string.h>
69*7c478bd9Sstevel@tonic-gate #ifndef POSIX_TERMIOS
70*7c478bd9Sstevel@tonic-gate #include <sgtty.h>
71*7c478bd9Sstevel@tonic-gate #endif
72*7c478bd9Sstevel@tonic-gate #include <fcntl.h>
73*7c478bd9Sstevel@tonic-gate #include <sys/types.h>
74*7c478bd9Sstevel@tonic-gate #include <sys/time.h>
75*7c478bd9Sstevel@tonic-gate #include <sys/stat.h>
76*7c478bd9Sstevel@tonic-gate #include <sys/socket.h>
77*7c478bd9Sstevel@tonic-gate #include <sys/wait.h>
78*7c478bd9Sstevel@tonic-gate #include <netinet/in.h>
79*7c478bd9Sstevel@tonic-gate #include <arpa/inet.h>
80*7c478bd9Sstevel@tonic-gate #include <sys/param.h>
81*7c478bd9Sstevel@tonic-gate #include <netdb.h>
82*7c478bd9Sstevel@tonic-gate #include <syslog.h>
83*7c478bd9Sstevel@tonic-gate #include <libintl.h>
84*7c478bd9Sstevel@tonic-gate #include <locale.h>
85*7c478bd9Sstevel@tonic-gate #include <k5-int.h>
86*7c478bd9Sstevel@tonic-gate #include <socket-utils.h>
87*7c478bd9Sstevel@tonic-gate #include "com_err.h"
88*7c478bd9Sstevel@tonic-gate #include <errno.h>
89*7c478bd9Sstevel@tonic-gate 
90*7c478bd9Sstevel@tonic-gate #include "kprop.h"
91*7c478bd9Sstevel@tonic-gate #include <iprop_hdr.h>
92*7c478bd9Sstevel@tonic-gate #include "iprop.h"
93*7c478bd9Sstevel@tonic-gate #include <kadm5/admin.h>
94*7c478bd9Sstevel@tonic-gate #include <kdb/kdb_log.h>
95*7c478bd9Sstevel@tonic-gate 
96*7c478bd9Sstevel@tonic-gate #define SYSLOG_CLASS LOG_DAEMON
97*7c478bd9Sstevel@tonic-gate 
98*7c478bd9Sstevel@tonic-gate char *poll_time = NULL;
99*7c478bd9Sstevel@tonic-gate char *def_realm = NULL;
100*7c478bd9Sstevel@tonic-gate boolean_t runonce = B_FALSE;
101*7c478bd9Sstevel@tonic-gate 
102*7c478bd9Sstevel@tonic-gate /*
103*7c478bd9Sstevel@tonic-gate  * This struct simulates the use of _kadm5_server_handle_t
104*7c478bd9Sstevel@tonic-gate  */
105*7c478bd9Sstevel@tonic-gate typedef struct _kadm5_iprop_handle_t {
106*7c478bd9Sstevel@tonic-gate 	krb5_ui_4	magic_number;
107*7c478bd9Sstevel@tonic-gate 	krb5_ui_4	struct_version;
108*7c478bd9Sstevel@tonic-gate 	krb5_ui_4	api_version;
109*7c478bd9Sstevel@tonic-gate 	char 		*cache_name;
110*7c478bd9Sstevel@tonic-gate 	int		destroy_cache;
111*7c478bd9Sstevel@tonic-gate 	CLIENT		*clnt;
112*7c478bd9Sstevel@tonic-gate 	krb5_context	context;
113*7c478bd9Sstevel@tonic-gate 	kadm5_config_params params;
114*7c478bd9Sstevel@tonic-gate 	struct _kadm5_iprop_handle_t *lhandle;
115*7c478bd9Sstevel@tonic-gate } *kadm5_iprop_handle_t;
116*7c478bd9Sstevel@tonic-gate 
117*7c478bd9Sstevel@tonic-gate static char *kprop_version = KPROP_PROT_VERSION;
118*7c478bd9Sstevel@tonic-gate 
119*7c478bd9Sstevel@tonic-gate char	*progname;
120*7c478bd9Sstevel@tonic-gate int     debug = 0;
121*7c478bd9Sstevel@tonic-gate char	*srvtab = 0;
122*7c478bd9Sstevel@tonic-gate int	standalone = 0;
123*7c478bd9Sstevel@tonic-gate 
124*7c478bd9Sstevel@tonic-gate krb5_principal	server;		/* This is our server principal name */
125*7c478bd9Sstevel@tonic-gate krb5_principal	client;		/* This is who we're talking to */
126*7c478bd9Sstevel@tonic-gate krb5_context kpropd_context;
127*7c478bd9Sstevel@tonic-gate krb5_auth_context auth_context;
128*7c478bd9Sstevel@tonic-gate char	*realm = NULL;		/* Our realm */
129*7c478bd9Sstevel@tonic-gate char	*file = KPROPD_DEFAULT_FILE;
130*7c478bd9Sstevel@tonic-gate char	*temp_file_name;
131*7c478bd9Sstevel@tonic-gate char	*kdb5_util = KPROPD_DEFAULT_KDB5_UTIL;
132*7c478bd9Sstevel@tonic-gate char	*kerb_database = NULL;
133*7c478bd9Sstevel@tonic-gate char	*acl_file_name = KPROPD_ACL_FILE;
134*7c478bd9Sstevel@tonic-gate 
135*7c478bd9Sstevel@tonic-gate int		database_fd;
136*7c478bd9Sstevel@tonic-gate krb5_address	sender_addr;
137*7c478bd9Sstevel@tonic-gate krb5_address	receiver_addr;
138*7c478bd9Sstevel@tonic-gate short 		port = 0;
139*7c478bd9Sstevel@tonic-gate 
140*7c478bd9Sstevel@tonic-gate void	PRS
141*7c478bd9Sstevel@tonic-gate 	 (int, char**);
142*7c478bd9Sstevel@tonic-gate int	do_standalone
143*7c478bd9Sstevel@tonic-gate 	 (iprop_role iproprole);
144*7c478bd9Sstevel@tonic-gate void	doit
145*7c478bd9Sstevel@tonic-gate 	 (int);
146*7c478bd9Sstevel@tonic-gate krb5_error_code	do_iprop(kdb_log_context *log_ctx);
147*7c478bd9Sstevel@tonic-gate 
148*7c478bd9Sstevel@tonic-gate void	kerberos_authenticate
149*7c478bd9Sstevel@tonic-gate 	 (krb5_context,
150*7c478bd9Sstevel@tonic-gate 		   int,
151*7c478bd9Sstevel@tonic-gate 		   krb5_principal *,
152*7c478bd9Sstevel@tonic-gate 		   krb5_enctype *,
153*7c478bd9Sstevel@tonic-gate 		   struct sockaddr_storage);
154*7c478bd9Sstevel@tonic-gate 
155*7c478bd9Sstevel@tonic-gate krb5_boolean authorized_principal
156*7c478bd9Sstevel@tonic-gate 	 (krb5_context,
157*7c478bd9Sstevel@tonic-gate     		   krb5_principal,
158*7c478bd9Sstevel@tonic-gate 		   krb5_enctype);
159*7c478bd9Sstevel@tonic-gate void	recv_database
160*7c478bd9Sstevel@tonic-gate 	 (krb5_context,
161*7c478bd9Sstevel@tonic-gate 		   int,
162*7c478bd9Sstevel@tonic-gate 		   int,
163*7c478bd9Sstevel@tonic-gate 		   krb5_data *);
164*7c478bd9Sstevel@tonic-gate void	load_database
165*7c478bd9Sstevel@tonic-gate 	 (krb5_context,
166*7c478bd9Sstevel@tonic-gate     		   char *,
167*7c478bd9Sstevel@tonic-gate     		   char *);
168*7c478bd9Sstevel@tonic-gate void	send_error
169*7c478bd9Sstevel@tonic-gate 	 (krb5_context,
170*7c478bd9Sstevel@tonic-gate     		   int,
171*7c478bd9Sstevel@tonic-gate 		   krb5_error_code,
172*7c478bd9Sstevel@tonic-gate     		   char	*);
173*7c478bd9Sstevel@tonic-gate void	recv_error
174*7c478bd9Sstevel@tonic-gate 	 (krb5_context,
175*7c478bd9Sstevel@tonic-gate     		   krb5_data *);
176*7c478bd9Sstevel@tonic-gate int	convert_polltime
177*7c478bd9Sstevel@tonic-gate 	(char *);
178*7c478bd9Sstevel@tonic-gate unsigned int	backoff_from_master
179*7c478bd9Sstevel@tonic-gate 	(int *);
180*7c478bd9Sstevel@tonic-gate 
181*7c478bd9Sstevel@tonic-gate static void usage()
182*7c478bd9Sstevel@tonic-gate {
183*7c478bd9Sstevel@tonic-gate 	fprintf(stderr,
184*7c478bd9Sstevel@tonic-gate 		gettext("\nUsage: %s\n"), /* progname may be a long pathname */
185*7c478bd9Sstevel@tonic-gate 		progname);
186*7c478bd9Sstevel@tonic-gate 
187*7c478bd9Sstevel@tonic-gate 	fprintf(stderr,
188*7c478bd9Sstevel@tonic-gate 		gettext("\t[-r realm] [-s srvtab] [-dS] [-f slave_file]\n"));
189*7c478bd9Sstevel@tonic-gate 
190*7c478bd9Sstevel@tonic-gate 	fprintf(stderr,
191*7c478bd9Sstevel@tonic-gate 		gettext("\t[-F kerberos_db_file ] [-p kdb5_util_pathname]\n"));
192*7c478bd9Sstevel@tonic-gate 
193*7c478bd9Sstevel@tonic-gate 	fprintf(stderr, gettext("\t[-P port] [-a acl_file]\n"));
194*7c478bd9Sstevel@tonic-gate 
195*7c478bd9Sstevel@tonic-gate 	exit(1);
196*7c478bd9Sstevel@tonic-gate }
197*7c478bd9Sstevel@tonic-gate 
198*7c478bd9Sstevel@tonic-gate int
199*7c478bd9Sstevel@tonic-gate main(argc, argv)
200*7c478bd9Sstevel@tonic-gate 	int	argc;
201*7c478bd9Sstevel@tonic-gate 	char	**argv;
202*7c478bd9Sstevel@tonic-gate {
203*7c478bd9Sstevel@tonic-gate 	krb5_error_code retval;
204*7c478bd9Sstevel@tonic-gate 	int ret = 0;
205*7c478bd9Sstevel@tonic-gate 	kdb_log_context	*log_ctx;
206*7c478bd9Sstevel@tonic-gate 
207*7c478bd9Sstevel@tonic-gate 	PRS(argc, argv);
208*7c478bd9Sstevel@tonic-gate 
209*7c478bd9Sstevel@tonic-gate 	log_ctx = kpropd_context->kdblog_context;
210*7c478bd9Sstevel@tonic-gate 
211*7c478bd9Sstevel@tonic-gate 	if (log_ctx && (log_ctx->iproprole == IPROP_SLAVE)) {
212*7c478bd9Sstevel@tonic-gate 		/*
213*7c478bd9Sstevel@tonic-gate 		 * We wanna do iprop !
214*7c478bd9Sstevel@tonic-gate 		 */
215*7c478bd9Sstevel@tonic-gate 		retval = do_iprop(log_ctx);
216*7c478bd9Sstevel@tonic-gate 		if (retval) {
217*7c478bd9Sstevel@tonic-gate 			com_err(progname, retval,
218*7c478bd9Sstevel@tonic-gate 					gettext("do_iprop failed.\n"));
219*7c478bd9Sstevel@tonic-gate 			exit(1);
220*7c478bd9Sstevel@tonic-gate 		}
221*7c478bd9Sstevel@tonic-gate 
222*7c478bd9Sstevel@tonic-gate 	} else {
223*7c478bd9Sstevel@tonic-gate 		if (standalone)
224*7c478bd9Sstevel@tonic-gate 			ret = do_standalone(IPROP_NULL);
225*7c478bd9Sstevel@tonic-gate 		else
226*7c478bd9Sstevel@tonic-gate 			doit(0);
227*7c478bd9Sstevel@tonic-gate 	}
228*7c478bd9Sstevel@tonic-gate 
229*7c478bd9Sstevel@tonic-gate 	exit(ret);
230*7c478bd9Sstevel@tonic-gate }
231*7c478bd9Sstevel@tonic-gate 
232*7c478bd9Sstevel@tonic-gate int do_standalone(iprop_role iproprole)
233*7c478bd9Sstevel@tonic-gate {
234*7c478bd9Sstevel@tonic-gate     struct	linger linger;
235*7c478bd9Sstevel@tonic-gate     struct	servent *sp;
236*7c478bd9Sstevel@tonic-gate     int	finet, fromlen, s;
237*7c478bd9Sstevel@tonic-gate     int	on = 1;
238*7c478bd9Sstevel@tonic-gate     int	ret, status = 0;
239*7c478bd9Sstevel@tonic-gate     struct	sockaddr_in6 sin6 = { AF_INET6 };
240*7c478bd9Sstevel@tonic-gate     int sin6_size = sizeof (sin6);
241*7c478bd9Sstevel@tonic-gate 
242*7c478bd9Sstevel@tonic-gate     /* listen for either ipv4 or ipv6 */
243*7c478bd9Sstevel@tonic-gate     finet = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP);
244*7c478bd9Sstevel@tonic-gate     if (finet < 0 ) {
245*7c478bd9Sstevel@tonic-gate 	com_err(progname, errno, gettext("while obtaining socket"));
246*7c478bd9Sstevel@tonic-gate 	exit(1);
247*7c478bd9Sstevel@tonic-gate     }
248*7c478bd9Sstevel@tonic-gate 
249*7c478bd9Sstevel@tonic-gate     if(!port) {
250*7c478bd9Sstevel@tonic-gate 	sp = getservbyname(KPROP_SERVICE, "tcp");
251*7c478bd9Sstevel@tonic-gate 	if (sp == NULL) {
252*7c478bd9Sstevel@tonic-gate 	    com_err(progname, 0, gettext("%s/tcp: unknown service"),
253*7c478bd9Sstevel@tonic-gate 		    KPROP_SERVICE);
254*7c478bd9Sstevel@tonic-gate 	    exit(1);
255*7c478bd9Sstevel@tonic-gate 	}
256*7c478bd9Sstevel@tonic-gate 	sin6.sin6_port = sp->s_port;
257*7c478bd9Sstevel@tonic-gate     } else
258*7c478bd9Sstevel@tonic-gate 	sin6.sin6_port = port;
259*7c478bd9Sstevel@tonic-gate 
260*7c478bd9Sstevel@tonic-gate     /*
261*7c478bd9Sstevel@tonic-gate      * We need to close the socket immediately if iprop is enabled,
262*7c478bd9Sstevel@tonic-gate      * since back-to-back full resyncs are possible, so we do not
263*7c478bd9Sstevel@tonic-gate      * linger around for too long
264*7c478bd9Sstevel@tonic-gate      */
265*7c478bd9Sstevel@tonic-gate     if (iproprole == IPROP_SLAVE) {
266*7c478bd9Sstevel@tonic-gate 	    if (setsockopt(finet, SOL_SOCKET, SO_REUSEADDR,
267*7c478bd9Sstevel@tonic-gate 			(char *)&on, sizeof(on)) < 0)
268*7c478bd9Sstevel@tonic-gate 		    com_err(progname, errno,
269*7c478bd9Sstevel@tonic-gate 			    gettext("in setsockopt(SO_REUSEADDR)"));
270*7c478bd9Sstevel@tonic-gate 	    linger.l_onoff = 1;
271*7c478bd9Sstevel@tonic-gate 	    linger.l_linger = 2;
272*7c478bd9Sstevel@tonic-gate 	    if (setsockopt(finet, SOL_SOCKET, SO_LINGER,
273*7c478bd9Sstevel@tonic-gate 			(void *)&linger, sizeof(linger)) < 0)
274*7c478bd9Sstevel@tonic-gate 		    com_err(progname, errno,
275*7c478bd9Sstevel@tonic-gate 			    gettext("in setsockopt(SO_LINGER)"));
276*7c478bd9Sstevel@tonic-gate     }
277*7c478bd9Sstevel@tonic-gate     if ((ret = bind(finet, (struct sockaddr *)&sin6, sizeof(sin6))) < 0) {
278*7c478bd9Sstevel@tonic-gate 	if (debug) {
279*7c478bd9Sstevel@tonic-gate 	    on = 1;
280*7c478bd9Sstevel@tonic-gate 	    fprintf(stderr,
281*7c478bd9Sstevel@tonic-gate 		    gettext("%s: attempting to rebind socket "
282*7c478bd9Sstevel@tonic-gate 		    "with SO_REUSEADDR\n"), progname);
283*7c478bd9Sstevel@tonic-gate 	    if (setsockopt(finet, SOL_SOCKET, SO_REUSEADDR,
284*7c478bd9Sstevel@tonic-gate 			(char *)&on, sizeof(on)) < 0) {
285*7c478bd9Sstevel@tonic-gate 		com_err(progname, errno,
286*7c478bd9Sstevel@tonic-gate 			gettext("in setsockopt(SO_REUSEADDR)"));
287*7c478bd9Sstevel@tonic-gate 	    }
288*7c478bd9Sstevel@tonic-gate 	    ret = bind(finet, (struct sockaddr *) &sin6, sizeof(sin6));
289*7c478bd9Sstevel@tonic-gate 	}
290*7c478bd9Sstevel@tonic-gate 
291*7c478bd9Sstevel@tonic-gate 	if (ret < 0) {
292*7c478bd9Sstevel@tonic-gate 	    perror(gettext("bind"));
293*7c478bd9Sstevel@tonic-gate 	    com_err(progname, errno,
294*7c478bd9Sstevel@tonic-gate 		    gettext("while binding listener socket"));
295*7c478bd9Sstevel@tonic-gate 	    exit(1);
296*7c478bd9Sstevel@tonic-gate 	}
297*7c478bd9Sstevel@tonic-gate     }
298*7c478bd9Sstevel@tonic-gate 
299*7c478bd9Sstevel@tonic-gate     if (!debug && (iproprole != IPROP_SLAVE))
300*7c478bd9Sstevel@tonic-gate 	daemon(1, 0);
301*7c478bd9Sstevel@tonic-gate 
302*7c478bd9Sstevel@tonic-gate #ifdef PID_FILE
303*7c478bd9Sstevel@tonic-gate     if ((pidfile = fopen(PID_FILE, "w")) != NULL) {
304*7c478bd9Sstevel@tonic-gate 	fprintf(pidfile, gettext("%d\n"), getpid());
305*7c478bd9Sstevel@tonic-gate 	fclose(pidfile);
306*7c478bd9Sstevel@tonic-gate     } else
307*7c478bd9Sstevel@tonic-gate 	com_err(progname, errno,
308*7c478bd9Sstevel@tonic-gate 		gettext("while opening pid file %s for writing"),
309*7c478bd9Sstevel@tonic-gate 		PID_FILE);
310*7c478bd9Sstevel@tonic-gate #endif
311*7c478bd9Sstevel@tonic-gate 
312*7c478bd9Sstevel@tonic-gate     if (listen(finet, 5) < 0) {
313*7c478bd9Sstevel@tonic-gate 	com_err(progname, errno, gettext("in listen call"));
314*7c478bd9Sstevel@tonic-gate 	exit(1);
315*7c478bd9Sstevel@tonic-gate     }
316*7c478bd9Sstevel@tonic-gate 
317*7c478bd9Sstevel@tonic-gate     while (1) {
318*7c478bd9Sstevel@tonic-gate 	int child_pid;
319*7c478bd9Sstevel@tonic-gate 
320*7c478bd9Sstevel@tonic-gate 	s = accept(finet, (struct sockaddr *) &sin6, &sin6_size);
321*7c478bd9Sstevel@tonic-gate 
322*7c478bd9Sstevel@tonic-gate 	if (s < 0) {
323*7c478bd9Sstevel@tonic-gate 	    if (errno != EINTR)
324*7c478bd9Sstevel@tonic-gate 		com_err(progname, errno,
325*7c478bd9Sstevel@tonic-gate 		    gettext("from accept system call"));
326*7c478bd9Sstevel@tonic-gate 	    continue;
327*7c478bd9Sstevel@tonic-gate 	}
328*7c478bd9Sstevel@tonic-gate 
329*7c478bd9Sstevel@tonic-gate 	if (debug && (iproprole != IPROP_SLAVE))
330*7c478bd9Sstevel@tonic-gate 	    child_pid = 0;
331*7c478bd9Sstevel@tonic-gate 	else
332*7c478bd9Sstevel@tonic-gate 	    child_pid = fork();
333*7c478bd9Sstevel@tonic-gate 
334*7c478bd9Sstevel@tonic-gate 	switch (child_pid) {
335*7c478bd9Sstevel@tonic-gate 	case -1:
336*7c478bd9Sstevel@tonic-gate 	    com_err(progname, errno, gettext("while forking"));
337*7c478bd9Sstevel@tonic-gate 	    exit(1);
338*7c478bd9Sstevel@tonic-gate 	    /*NOTREACHED*/
339*7c478bd9Sstevel@tonic-gate 	case 0:
340*7c478bd9Sstevel@tonic-gate 	    /* child */
341*7c478bd9Sstevel@tonic-gate 	    (void) close(finet);
342*7c478bd9Sstevel@tonic-gate 	    doit(s);
343*7c478bd9Sstevel@tonic-gate 	    close(s);
344*7c478bd9Sstevel@tonic-gate 	    _exit(0);
345*7c478bd9Sstevel@tonic-gate 	    /*NOTREACHED*/
346*7c478bd9Sstevel@tonic-gate 	default:
347*7c478bd9Sstevel@tonic-gate 	    /* parent */
348*7c478bd9Sstevel@tonic-gate 	    if (wait(&status) < 0) {
349*7c478bd9Sstevel@tonic-gate 		com_err(progname, errno,
350*7c478bd9Sstevel@tonic-gate 		    gettext("while waiting to receive database"));
351*7c478bd9Sstevel@tonic-gate 		exit(1);
352*7c478bd9Sstevel@tonic-gate 	    }
353*7c478bd9Sstevel@tonic-gate 
354*7c478bd9Sstevel@tonic-gate 	    close(s);
355*7c478bd9Sstevel@tonic-gate 	    if (iproprole == IPROP_SLAVE)
356*7c478bd9Sstevel@tonic-gate 		close(finet);
357*7c478bd9Sstevel@tonic-gate 
358*7c478bd9Sstevel@tonic-gate 	    if ((ret = WEXITSTATUS(status)) != 0)
359*7c478bd9Sstevel@tonic-gate 		return (ret);
360*7c478bd9Sstevel@tonic-gate 	}
361*7c478bd9Sstevel@tonic-gate 
362*7c478bd9Sstevel@tonic-gate 	if (iproprole == IPROP_SLAVE)
363*7c478bd9Sstevel@tonic-gate 	    break;
364*7c478bd9Sstevel@tonic-gate     }
365*7c478bd9Sstevel@tonic-gate 
366*7c478bd9Sstevel@tonic-gate     return (0);
367*7c478bd9Sstevel@tonic-gate }
368*7c478bd9Sstevel@tonic-gate 
369*7c478bd9Sstevel@tonic-gate void doit(fd)
370*7c478bd9Sstevel@tonic-gate 	int	fd;
371*7c478bd9Sstevel@tonic-gate {
372*7c478bd9Sstevel@tonic-gate 	struct sockaddr_storage from;
373*7c478bd9Sstevel@tonic-gate 	socklen_t fromlen;
374*7c478bd9Sstevel@tonic-gate 	int on = 1;
375*7c478bd9Sstevel@tonic-gate 	struct hostent	*hp;
376*7c478bd9Sstevel@tonic-gate 	krb5_error_code	retval;
377*7c478bd9Sstevel@tonic-gate 	krb5_data confmsg;
378*7c478bd9Sstevel@tonic-gate 	int lock_fd;
379*7c478bd9Sstevel@tonic-gate 	int omask;
380*7c478bd9Sstevel@tonic-gate 	krb5_enctype etype;
381*7c478bd9Sstevel@tonic-gate 	char ntop[NI_MAXHOST] = "";
382*7c478bd9Sstevel@tonic-gate 	krb5_context doit_context;
383*7c478bd9Sstevel@tonic-gate 	kdb_log_context *log_ctx;
384*7c478bd9Sstevel@tonic-gate 
385*7c478bd9Sstevel@tonic-gate 	retval = krb5_init_context(&doit_context);
386*7c478bd9Sstevel@tonic-gate 	if (retval) {
387*7c478bd9Sstevel@tonic-gate 		com_err(progname, retval, gettext("while initializing krb5"));
388*7c478bd9Sstevel@tonic-gate 		exit(1);
389*7c478bd9Sstevel@tonic-gate 	}
390*7c478bd9Sstevel@tonic-gate 	log_ctx = kpropd_context->kdblog_context;
391*7c478bd9Sstevel@tonic-gate 	if (log_ctx && (log_ctx->iproprole == IPROP_SLAVE))
392*7c478bd9Sstevel@tonic-gate 		ulog_set_role(doit_context, IPROP_SLAVE);
393*7c478bd9Sstevel@tonic-gate 
394*7c478bd9Sstevel@tonic-gate 	fromlen = (socklen_t)sizeof (from);
395*7c478bd9Sstevel@tonic-gate 
396*7c478bd9Sstevel@tonic-gate 	if (getpeername(fd, (struct sockaddr *) &from, &fromlen) < 0) {
397*7c478bd9Sstevel@tonic-gate 		fprintf(stderr, "%s: ", progname);
398*7c478bd9Sstevel@tonic-gate 		perror(gettext("getpeername"));
399*7c478bd9Sstevel@tonic-gate 		exit(1);
400*7c478bd9Sstevel@tonic-gate 	}
401*7c478bd9Sstevel@tonic-gate 	if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (caddr_t) &on,
402*7c478bd9Sstevel@tonic-gate 		       sizeof (on)) < 0) {
403*7c478bd9Sstevel@tonic-gate 		com_err(progname, errno,
404*7c478bd9Sstevel@tonic-gate 		gettext("while attempting setsockopt (SO_KEEPALIVE)"));
405*7c478bd9Sstevel@tonic-gate 	}
406*7c478bd9Sstevel@tonic-gate 
407*7c478bd9Sstevel@tonic-gate 	if (getnameinfo((struct sockaddr *)&from, fromlen, ntop, sizeof(ntop),
408*7c478bd9Sstevel@tonic-gate 		NULL, 0, NI_NUMERICHOST) != 0) {
409*7c478bd9Sstevel@tonic-gate 
410*7c478bd9Sstevel@tonic-gate 		/* getnameifo failed so use inet_ntop() to get printable addresses */
411*7c478bd9Sstevel@tonic-gate 		if (from.ss_family == AF_INET) {
412*7c478bd9Sstevel@tonic-gate 
413*7c478bd9Sstevel@tonic-gate 			inet_ntop(AF_INET,
414*7c478bd9Sstevel@tonic-gate 			    (const void *)&ss2sin(&from)->sin_addr,
415*7c478bd9Sstevel@tonic-gate 			    ntop, sizeof(ntop));
416*7c478bd9Sstevel@tonic-gate 
417*7c478bd9Sstevel@tonic-gate 		} else if (from.ss_family == AF_INET6 &&
418*7c478bd9Sstevel@tonic-gate 			! IN6_IS_ADDR_V4MAPPED(&ss2sin6(&from)->sin6_addr)) {
419*7c478bd9Sstevel@tonic-gate 
420*7c478bd9Sstevel@tonic-gate 			ipaddr_t v4addr;
421*7c478bd9Sstevel@tonic-gate 
422*7c478bd9Sstevel@tonic-gate 			inet_ntop(AF_INET6,
423*7c478bd9Sstevel@tonic-gate 				(const void *)&ss2sin6(&from)->sin6_addr, ntop,
424*7c478bd9Sstevel@tonic-gate 				sizeof(ntop));
425*7c478bd9Sstevel@tonic-gate 		}
426*7c478bd9Sstevel@tonic-gate 		/* ipv4 mapped ipv6 addrs handled later */
427*7c478bd9Sstevel@tonic-gate 	}
428*7c478bd9Sstevel@tonic-gate 
429*7c478bd9Sstevel@tonic-gate 	if (from.ss_family == AF_INET || from.ss_family == AF_INET6) {
430*7c478bd9Sstevel@tonic-gate 
431*7c478bd9Sstevel@tonic-gate 		if (from.ss_family == AF_INET6 &&
432*7c478bd9Sstevel@tonic-gate 			IN6_IS_ADDR_V4MAPPED(&ss2sin6(&from)->sin6_addr)) {
433*7c478bd9Sstevel@tonic-gate 
434*7c478bd9Sstevel@tonic-gate 			ipaddr_t v4addr;
435*7c478bd9Sstevel@tonic-gate 
436*7c478bd9Sstevel@tonic-gate 			/* coerce ipv4 mapped ipv6 addr to normal ipv4 addr */
437*7c478bd9Sstevel@tonic-gate 			IN6_V4MAPPED_TO_IPADDR(&(ss2sin6(&from)->sin6_addr),
438*7c478bd9Sstevel@tonic-gate 				v4addr);
439*7c478bd9Sstevel@tonic-gate 
440*7c478bd9Sstevel@tonic-gate 			inet_ntop(AF_INET, (const void *) &v4addr,
441*7c478bd9Sstevel@tonic-gate 				ntop, sizeof(ntop));
442*7c478bd9Sstevel@tonic-gate 		}
443*7c478bd9Sstevel@tonic-gate 
444*7c478bd9Sstevel@tonic-gate 		syslog(LOG_INFO, gettext("Connection from %s"), ntop);
445*7c478bd9Sstevel@tonic-gate 
446*7c478bd9Sstevel@tonic-gate 		if (debug)
447*7c478bd9Sstevel@tonic-gate 			printf("Connection from %s\n", ntop);
448*7c478bd9Sstevel@tonic-gate 
449*7c478bd9Sstevel@tonic-gate 	} else {
450*7c478bd9Sstevel@tonic-gate 		/* address family isn't either AF_INET || AF_INET6 */
451*7c478bd9Sstevel@tonic-gate 		syslog(LOG_INFO,
452*7c478bd9Sstevel@tonic-gate 		    gettext("Connection from unknown address family:%d"),
453*7c478bd9Sstevel@tonic-gate 		    from.ss_family);
454*7c478bd9Sstevel@tonic-gate 
455*7c478bd9Sstevel@tonic-gate 		if (debug) {
456*7c478bd9Sstevel@tonic-gate 			printf(gettext("Connection from unknown address family:%d"),
457*7c478bd9Sstevel@tonic-gate 			    from.ss_family);
458*7c478bd9Sstevel@tonic-gate 		}
459*7c478bd9Sstevel@tonic-gate 	}
460*7c478bd9Sstevel@tonic-gate 
461*7c478bd9Sstevel@tonic-gate 	/*
462*7c478bd9Sstevel@tonic-gate 	 * Now do the authentication
463*7c478bd9Sstevel@tonic-gate 	 */
464*7c478bd9Sstevel@tonic-gate 	kerberos_authenticate(doit_context, fd, &client, &etype, from);
465*7c478bd9Sstevel@tonic-gate 
466*7c478bd9Sstevel@tonic-gate 	if (!authorized_principal(doit_context, client, etype)) {
467*7c478bd9Sstevel@tonic-gate 	    char	*name;
468*7c478bd9Sstevel@tonic-gate 
469*7c478bd9Sstevel@tonic-gate 	    if (retval = krb5_unparse_name(doit_context, client, &name)) {
470*7c478bd9Sstevel@tonic-gate 		com_err(progname, retval,
471*7c478bd9Sstevel@tonic-gate 		    gettext("While unparsing client name"));
472*7c478bd9Sstevel@tonic-gate 		exit(1);
473*7c478bd9Sstevel@tonic-gate 	    }
474*7c478bd9Sstevel@tonic-gate 	    syslog(LOG_WARNING,
475*7c478bd9Sstevel@tonic-gate 		gettext("Rejected connection from unauthorized principal %s"),
476*7c478bd9Sstevel@tonic-gate 		name);
477*7c478bd9Sstevel@tonic-gate 	    free(name);
478*7c478bd9Sstevel@tonic-gate 	    exit(1);
479*7c478bd9Sstevel@tonic-gate 	}
480*7c478bd9Sstevel@tonic-gate 	omask = umask(077);
481*7c478bd9Sstevel@tonic-gate 	lock_fd = open(temp_file_name, O_RDWR|O_CREAT, 0600);
482*7c478bd9Sstevel@tonic-gate 	(void) umask(omask);
483*7c478bd9Sstevel@tonic-gate 	retval = krb5_lock_file(doit_context, lock_fd,
484*7c478bd9Sstevel@tonic-gate 				KRB5_LOCKMODE_EXCLUSIVE|KRB5_LOCKMODE_DONTBLOCK);
485*7c478bd9Sstevel@tonic-gate 	if (retval) {
486*7c478bd9Sstevel@tonic-gate 	    com_err(progname, retval,
487*7c478bd9Sstevel@tonic-gate 			gettext("while trying to lock '%s'"),
488*7c478bd9Sstevel@tonic-gate 		    temp_file_name);
489*7c478bd9Sstevel@tonic-gate 	    exit(1);
490*7c478bd9Sstevel@tonic-gate 	}
491*7c478bd9Sstevel@tonic-gate 	if ((database_fd = open(temp_file_name,
492*7c478bd9Sstevel@tonic-gate 				O_WRONLY|O_CREAT|O_TRUNC, 0600)) < 0) {
493*7c478bd9Sstevel@tonic-gate 		com_err(progname, errno,
494*7c478bd9Sstevel@tonic-gate 			gettext("while opening database file, '%s'"),
495*7c478bd9Sstevel@tonic-gate 			temp_file_name);
496*7c478bd9Sstevel@tonic-gate 		exit(1);
497*7c478bd9Sstevel@tonic-gate 	}
498*7c478bd9Sstevel@tonic-gate 	recv_database(doit_context, fd, database_fd, &confmsg);
499*7c478bd9Sstevel@tonic-gate 	if (rename(temp_file_name, file)) {
500*7c478bd9Sstevel@tonic-gate 		com_err(progname, errno,
501*7c478bd9Sstevel@tonic-gate 			gettext("While renaming %s to %s"),
502*7c478bd9Sstevel@tonic-gate 			temp_file_name, file);
503*7c478bd9Sstevel@tonic-gate 		exit(1);
504*7c478bd9Sstevel@tonic-gate 	}
505*7c478bd9Sstevel@tonic-gate 	retval = krb5_lock_file(doit_context, lock_fd, KRB5_LOCKMODE_SHARED);
506*7c478bd9Sstevel@tonic-gate 	if (retval) {
507*7c478bd9Sstevel@tonic-gate 	    com_err(progname, retval,
508*7c478bd9Sstevel@tonic-gate 			gettext("while downgrading lock on '%s'"),
509*7c478bd9Sstevel@tonic-gate 		    temp_file_name);
510*7c478bd9Sstevel@tonic-gate 	    exit(1);
511*7c478bd9Sstevel@tonic-gate 	}
512*7c478bd9Sstevel@tonic-gate 	load_database(doit_context, kdb5_util, file);
513*7c478bd9Sstevel@tonic-gate 	retval = krb5_lock_file(doit_context, lock_fd, KRB5_LOCKMODE_UNLOCK);
514*7c478bd9Sstevel@tonic-gate 	if (retval) {
515*7c478bd9Sstevel@tonic-gate 	    com_err(progname, retval,
516*7c478bd9Sstevel@tonic-gate 		gettext("while unlocking '%s'"), temp_file_name);
517*7c478bd9Sstevel@tonic-gate 	    exit(1);
518*7c478bd9Sstevel@tonic-gate 	}
519*7c478bd9Sstevel@tonic-gate 	(void)close(lock_fd);
520*7c478bd9Sstevel@tonic-gate 
521*7c478bd9Sstevel@tonic-gate 	/*
522*7c478bd9Sstevel@tonic-gate 	 * Send the acknowledgement message generated in
523*7c478bd9Sstevel@tonic-gate 	 * recv_database, then close the socket.
524*7c478bd9Sstevel@tonic-gate 	 */
525*7c478bd9Sstevel@tonic-gate 	if (retval = krb5_write_message(doit_context, (void *) &fd,
526*7c478bd9Sstevel@tonic-gate 					&confmsg)) {
527*7c478bd9Sstevel@tonic-gate 		krb5_free_data_contents(doit_context, &confmsg);
528*7c478bd9Sstevel@tonic-gate 		com_err(progname, retval,
529*7c478bd9Sstevel@tonic-gate 			gettext("while sending # of received bytes"));
530*7c478bd9Sstevel@tonic-gate 		exit(1);
531*7c478bd9Sstevel@tonic-gate 	}
532*7c478bd9Sstevel@tonic-gate 	krb5_free_data_contents(doit_context, &confmsg);
533*7c478bd9Sstevel@tonic-gate 	if (close(fd) < 0) {
534*7c478bd9Sstevel@tonic-gate 		com_err(progname, errno,
535*7c478bd9Sstevel@tonic-gate 			gettext("while trying to close database file"));
536*7c478bd9Sstevel@tonic-gate 		exit(1);
537*7c478bd9Sstevel@tonic-gate 	}
538*7c478bd9Sstevel@tonic-gate 
539*7c478bd9Sstevel@tonic-gate 	exit(0);
540*7c478bd9Sstevel@tonic-gate }
541*7c478bd9Sstevel@tonic-gate 
542*7c478bd9Sstevel@tonic-gate 
543*7c478bd9Sstevel@tonic-gate /*
544*7c478bd9Sstevel@tonic-gate  * Routine to handle incremental update transfer(s) from master KDC
545*7c478bd9Sstevel@tonic-gate  */
546*7c478bd9Sstevel@tonic-gate krb5_error_code do_iprop(kdb_log_context *log_ctx) {
547*7c478bd9Sstevel@tonic-gate 	CLIENT *cl;
548*7c478bd9Sstevel@tonic-gate 	kadm5_ret_t retval;
549*7c478bd9Sstevel@tonic-gate 	kadm5_config_params params;
550*7c478bd9Sstevel@tonic-gate 	krb5_ccache cc;
551*7c478bd9Sstevel@tonic-gate 	krb5_principal iprop_svc_principal;
552*7c478bd9Sstevel@tonic-gate 	void *server_handle = NULL;
553*7c478bd9Sstevel@tonic-gate 	char *iprop_svc_princstr = NULL;
554*7c478bd9Sstevel@tonic-gate 	char *master_svc_princstr = NULL;
555*7c478bd9Sstevel@tonic-gate 	char *admin_server = NULL;
556*7c478bd9Sstevel@tonic-gate 	char *keytab_name = NULL;
557*7c478bd9Sstevel@tonic-gate 	unsigned int pollin, backoff_time;
558*7c478bd9Sstevel@tonic-gate 	int backoff_cnt = 0;
559*7c478bd9Sstevel@tonic-gate 	int reinit_cnt = 0;
560*7c478bd9Sstevel@tonic-gate 	int ret;
561*7c478bd9Sstevel@tonic-gate 	boolean_t frdone = B_FALSE;
562*7c478bd9Sstevel@tonic-gate 
563*7c478bd9Sstevel@tonic-gate 	kdb_incr_result_t *incr_ret;
564*7c478bd9Sstevel@tonic-gate 	static kdb_last_t mylast;
565*7c478bd9Sstevel@tonic-gate 
566*7c478bd9Sstevel@tonic-gate 	kdb_fullresync_result_t *full_ret;
567*7c478bd9Sstevel@tonic-gate 	char *full_resync_arg = NULL;
568*7c478bd9Sstevel@tonic-gate 
569*7c478bd9Sstevel@tonic-gate 	kadm5_iprop_handle_t handle;
570*7c478bd9Sstevel@tonic-gate 	kdb_hlog_t *ulog;
571*7c478bd9Sstevel@tonic-gate 
572*7c478bd9Sstevel@tonic-gate 	if (!debug)
573*7c478bd9Sstevel@tonic-gate 		daemon(0, 0);
574*7c478bd9Sstevel@tonic-gate 
575*7c478bd9Sstevel@tonic-gate 	pollin = (unsigned int)0;
576*7c478bd9Sstevel@tonic-gate 	(void) memset((char *)&params, 0, sizeof (params));
577*7c478bd9Sstevel@tonic-gate 	ulog = log_ctx->ulog;
578*7c478bd9Sstevel@tonic-gate 
579*7c478bd9Sstevel@tonic-gate 	params.mask |= KADM5_CONFIG_REALM;
580*7c478bd9Sstevel@tonic-gate 	params.realm = def_realm;
581*7c478bd9Sstevel@tonic-gate 
582*7c478bd9Sstevel@tonic-gate 	if (master_svc_princstr == NULL) {
583*7c478bd9Sstevel@tonic-gate 		if (retval = kadm5_get_kiprop_host_srv_name(kpropd_context,
584*7c478bd9Sstevel@tonic-gate 					def_realm, &master_svc_princstr)) {
585*7c478bd9Sstevel@tonic-gate 			com_err(progname, retval,
586*7c478bd9Sstevel@tonic-gate 				gettext("%s: unable to get kiprop host based "
587*7c478bd9Sstevel@tonic-gate 					"service name for realm %s\n"),
588*7c478bd9Sstevel@tonic-gate 					progname, def_realm);
589*7c478bd9Sstevel@tonic-gate 			exit(1);
590*7c478bd9Sstevel@tonic-gate 		}
591*7c478bd9Sstevel@tonic-gate 	}
592*7c478bd9Sstevel@tonic-gate 
593*7c478bd9Sstevel@tonic-gate 	/*
594*7c478bd9Sstevel@tonic-gate 	 * Set cc to the default credentials cache
595*7c478bd9Sstevel@tonic-gate 	 */
596*7c478bd9Sstevel@tonic-gate 	if (retval = krb5_cc_default(kpropd_context, &cc)) {
597*7c478bd9Sstevel@tonic-gate 		com_err(progname, retval,
598*7c478bd9Sstevel@tonic-gate 			gettext("while opening default "
599*7c478bd9Sstevel@tonic-gate 				"credentials cache"));
600*7c478bd9Sstevel@tonic-gate 		exit(1);
601*7c478bd9Sstevel@tonic-gate 	}
602*7c478bd9Sstevel@tonic-gate 
603*7c478bd9Sstevel@tonic-gate 	retval = krb5_sname_to_principal(kpropd_context, NULL, KIPROP_SVC_NAME,
604*7c478bd9Sstevel@tonic-gate 				KRB5_NT_SRV_HST, &iprop_svc_principal);
605*7c478bd9Sstevel@tonic-gate 	if (retval) {
606*7c478bd9Sstevel@tonic-gate 		com_err(progname, retval, gettext("while trying to construct "
607*7c478bd9Sstevel@tonic-gate 						"host service principal"));
608*7c478bd9Sstevel@tonic-gate 		exit(1);
609*7c478bd9Sstevel@tonic-gate 	}
610*7c478bd9Sstevel@tonic-gate 
611*7c478bd9Sstevel@tonic-gate 	if (retval = krb5_unparse_name(kpropd_context, iprop_svc_principal,
612*7c478bd9Sstevel@tonic-gate 				&iprop_svc_princstr)) {
613*7c478bd9Sstevel@tonic-gate 		com_err(progname, retval,
614*7c478bd9Sstevel@tonic-gate 			gettext("while canonicalizing "
615*7c478bd9Sstevel@tonic-gate 				"principal name"));
616*7c478bd9Sstevel@tonic-gate 		krb5_free_principal(kpropd_context, iprop_svc_principal);
617*7c478bd9Sstevel@tonic-gate 		exit(1);
618*7c478bd9Sstevel@tonic-gate 	}
619*7c478bd9Sstevel@tonic-gate 	krb5_free_principal(kpropd_context, iprop_svc_principal);
620*7c478bd9Sstevel@tonic-gate 
621*7c478bd9Sstevel@tonic-gate reinit:
622*7c478bd9Sstevel@tonic-gate 	/*
623*7c478bd9Sstevel@tonic-gate 	 * Authentication, initialize rpcsec_gss handle etc.
624*7c478bd9Sstevel@tonic-gate 	 */
625*7c478bd9Sstevel@tonic-gate 	retval = kadm5_init_with_skey(iprop_svc_princstr, keytab_name,
626*7c478bd9Sstevel@tonic-gate 				    master_svc_princstr,
627*7c478bd9Sstevel@tonic-gate 				    &params,
628*7c478bd9Sstevel@tonic-gate 				    KADM5_STRUCT_VERSION,
629*7c478bd9Sstevel@tonic-gate 				    KADM5_API_VERSION_2,
630*7c478bd9Sstevel@tonic-gate  				    &server_handle);
631*7c478bd9Sstevel@tonic-gate 
632*7c478bd9Sstevel@tonic-gate 	if (retval) {
633*7c478bd9Sstevel@tonic-gate 		if (retval == KADM5_RPC_ERROR) {
634*7c478bd9Sstevel@tonic-gate 			reinit_cnt++;
635*7c478bd9Sstevel@tonic-gate 			if (server_handle)
636*7c478bd9Sstevel@tonic-gate 				kadm5_destroy((void *) server_handle);
637*7c478bd9Sstevel@tonic-gate 			server_handle = (void *)NULL;
638*7c478bd9Sstevel@tonic-gate 			handle = (kadm5_iprop_handle_t)NULL;
639*7c478bd9Sstevel@tonic-gate 
640*7c478bd9Sstevel@tonic-gate 			com_err(progname, retval, gettext(
641*7c478bd9Sstevel@tonic-gate 					"while attempting to connect"
642*7c478bd9Sstevel@tonic-gate 					" to master KDC ... retrying"));
643*7c478bd9Sstevel@tonic-gate 			backoff_time = backoff_from_master(&reinit_cnt);
644*7c478bd9Sstevel@tonic-gate 			(void) sleep(backoff_time);
645*7c478bd9Sstevel@tonic-gate 			goto reinit;
646*7c478bd9Sstevel@tonic-gate 		} else {
647*7c478bd9Sstevel@tonic-gate 			com_err(progname, retval,
648*7c478bd9Sstevel@tonic-gate                                 gettext("while initializing %s interface"),
649*7c478bd9Sstevel@tonic-gate 				progname);
650*7c478bd9Sstevel@tonic-gate 			if (retval == KADM5_BAD_CLIENT_PARAMS ||
651*7c478bd9Sstevel@tonic-gate 			    retval == KADM5_BAD_SERVER_PARAMS)
652*7c478bd9Sstevel@tonic-gate 				usage();
653*7c478bd9Sstevel@tonic-gate 			exit(1);
654*7c478bd9Sstevel@tonic-gate                 }
655*7c478bd9Sstevel@tonic-gate 	}
656*7c478bd9Sstevel@tonic-gate 
657*7c478bd9Sstevel@tonic-gate 	/*
658*7c478bd9Sstevel@tonic-gate 	 * Reset re-initialization count to zero now.
659*7c478bd9Sstevel@tonic-gate 	 */
660*7c478bd9Sstevel@tonic-gate 	reinit_cnt = backoff_time = 0;
661*7c478bd9Sstevel@tonic-gate 
662*7c478bd9Sstevel@tonic-gate 	/*
663*7c478bd9Sstevel@tonic-gate 	 * Reset the handle to the correct type for the RPC call
664*7c478bd9Sstevel@tonic-gate 	 */
665*7c478bd9Sstevel@tonic-gate 	handle = server_handle;
666*7c478bd9Sstevel@tonic-gate 
667*7c478bd9Sstevel@tonic-gate 	/*
668*7c478bd9Sstevel@tonic-gate 	 * If we have reached this far, we have succesfully established
669*7c478bd9Sstevel@tonic-gate 	 * a RPCSEC_GSS connection; we now start polling for updates
670*7c478bd9Sstevel@tonic-gate 	 */
671*7c478bd9Sstevel@tonic-gate 	if (poll_time == NULL) {
672*7c478bd9Sstevel@tonic-gate 		if ((poll_time = (char *)strdup("2m")) == NULL) {
673*7c478bd9Sstevel@tonic-gate 			com_err(progname, ENOMEM,
674*7c478bd9Sstevel@tonic-gate 				gettext("Unable to allocate poll_time"));
675*7c478bd9Sstevel@tonic-gate 			exit(1);
676*7c478bd9Sstevel@tonic-gate 		}
677*7c478bd9Sstevel@tonic-gate 	}
678*7c478bd9Sstevel@tonic-gate 
679*7c478bd9Sstevel@tonic-gate 	if (pollin == (unsigned int)0)
680*7c478bd9Sstevel@tonic-gate 		pollin = convert_polltime(poll_time);
681*7c478bd9Sstevel@tonic-gate 
682*7c478bd9Sstevel@tonic-gate 	for (;;) {
683*7c478bd9Sstevel@tonic-gate 		incr_ret = NULL;
684*7c478bd9Sstevel@tonic-gate 		full_ret = NULL;
685*7c478bd9Sstevel@tonic-gate 
686*7c478bd9Sstevel@tonic-gate 		/*
687*7c478bd9Sstevel@tonic-gate 		 * Get the most recent ulog entry sno + ts, which
688*7c478bd9Sstevel@tonic-gate 		 * we package in the request to the master KDC
689*7c478bd9Sstevel@tonic-gate 		 */
690*7c478bd9Sstevel@tonic-gate 		mylast.last_sno = ulog->kdb_last_sno;
691*7c478bd9Sstevel@tonic-gate 		mylast.last_time = ulog->kdb_last_time;
692*7c478bd9Sstevel@tonic-gate 
693*7c478bd9Sstevel@tonic-gate 		/*
694*7c478bd9Sstevel@tonic-gate 		 * Loop continuously on an iprop_get_updates_1(),
695*7c478bd9Sstevel@tonic-gate 		 * so that we can keep probing the master for updates
696*7c478bd9Sstevel@tonic-gate 		 * or (if needed) do a full resync of the krb5 db.
697*7c478bd9Sstevel@tonic-gate 		 */
698*7c478bd9Sstevel@tonic-gate 
699*7c478bd9Sstevel@tonic-gate 		incr_ret = iprop_get_updates_1(&mylast, handle->clnt);
700*7c478bd9Sstevel@tonic-gate 		if (incr_ret == (kdb_incr_result_t *)NULL) {
701*7c478bd9Sstevel@tonic-gate 			clnt_perror(handle->clnt,
702*7c478bd9Sstevel@tonic-gate 				    "iprop_get_updates call failed");
703*7c478bd9Sstevel@tonic-gate 			if (server_handle)
704*7c478bd9Sstevel@tonic-gate 				kadm5_destroy((void *)server_handle);
705*7c478bd9Sstevel@tonic-gate 			server_handle = (void *)NULL;
706*7c478bd9Sstevel@tonic-gate 			handle = (kadm5_iprop_handle_t)NULL;
707*7c478bd9Sstevel@tonic-gate 			goto reinit;
708*7c478bd9Sstevel@tonic-gate 		}
709*7c478bd9Sstevel@tonic-gate 
710*7c478bd9Sstevel@tonic-gate 		switch (incr_ret->ret) {
711*7c478bd9Sstevel@tonic-gate 
712*7c478bd9Sstevel@tonic-gate 		case UPDATE_FULL_RESYNC_NEEDED:
713*7c478bd9Sstevel@tonic-gate 			/*
714*7c478bd9Sstevel@tonic-gate 			 * We dont do a full resync again, if the last
715*7c478bd9Sstevel@tonic-gate 			 * X'fer was a resync and if the master sno is
716*7c478bd9Sstevel@tonic-gate 			 * still "0", i.e. no updates so far.
717*7c478bd9Sstevel@tonic-gate 			 */
718*7c478bd9Sstevel@tonic-gate 			if ((frdone == B_TRUE) && (incr_ret->lastentry.last_sno
719*7c478bd9Sstevel@tonic-gate 						== 0)) {
720*7c478bd9Sstevel@tonic-gate 				break;
721*7c478bd9Sstevel@tonic-gate 			} else {
722*7c478bd9Sstevel@tonic-gate 
723*7c478bd9Sstevel@tonic-gate 				full_ret = iprop_full_resync_1((void *)
724*7c478bd9Sstevel@tonic-gate 						&full_resync_arg, handle->clnt);
725*7c478bd9Sstevel@tonic-gate 
726*7c478bd9Sstevel@tonic-gate 				if (full_ret == (kdb_fullresync_result_t *)
727*7c478bd9Sstevel@tonic-gate 							NULL) {
728*7c478bd9Sstevel@tonic-gate 					clnt_perror(handle->clnt,
729*7c478bd9Sstevel@tonic-gate 					    "iprop_full_resync call failed");
730*7c478bd9Sstevel@tonic-gate 					if (server_handle)
731*7c478bd9Sstevel@tonic-gate 						kadm5_destroy((void *)
732*7c478bd9Sstevel@tonic-gate 							server_handle);
733*7c478bd9Sstevel@tonic-gate 					server_handle = (void *)NULL;
734*7c478bd9Sstevel@tonic-gate 					handle = (kadm5_iprop_handle_t)NULL;
735*7c478bd9Sstevel@tonic-gate 					goto reinit;
736*7c478bd9Sstevel@tonic-gate 				}
737*7c478bd9Sstevel@tonic-gate 			}
738*7c478bd9Sstevel@tonic-gate 
739*7c478bd9Sstevel@tonic-gate 			switch (full_ret->ret) {
740*7c478bd9Sstevel@tonic-gate 			case UPDATE_OK:
741*7c478bd9Sstevel@tonic-gate 				backoff_cnt = 0;
742*7c478bd9Sstevel@tonic-gate 				/*
743*7c478bd9Sstevel@tonic-gate 				 * We now listen on the kprop port for
744*7c478bd9Sstevel@tonic-gate 				 * the full dump
745*7c478bd9Sstevel@tonic-gate 				 */
746*7c478bd9Sstevel@tonic-gate 				ret = do_standalone(log_ctx->iproprole);
747*7c478bd9Sstevel@tonic-gate 				if (ret)
748*7c478bd9Sstevel@tonic-gate 					syslog(LOG_WARNING,
749*7c478bd9Sstevel@tonic-gate 					    gettext("kpropd: Full resync, "
750*7c478bd9Sstevel@tonic-gate 					    "invalid return."));
751*7c478bd9Sstevel@tonic-gate 				if (debug)
752*7c478bd9Sstevel@tonic-gate 					if (ret)
753*7c478bd9Sstevel@tonic-gate 						fprintf(stderr,
754*7c478bd9Sstevel@tonic-gate 						    gettext("Full resync "
755*7c478bd9Sstevel@tonic-gate 						    "was unsuccessful\n"));
756*7c478bd9Sstevel@tonic-gate 					else
757*7c478bd9Sstevel@tonic-gate 						fprintf(stderr,
758*7c478bd9Sstevel@tonic-gate 						    gettext("Full resync "
759*7c478bd9Sstevel@tonic-gate 						    "was successful\n"));
760*7c478bd9Sstevel@tonic-gate 				frdone = B_TRUE;
761*7c478bd9Sstevel@tonic-gate 				break;
762*7c478bd9Sstevel@tonic-gate 
763*7c478bd9Sstevel@tonic-gate 			case UPDATE_BUSY:
764*7c478bd9Sstevel@tonic-gate 				/*
765*7c478bd9Sstevel@tonic-gate 				 * Exponential backoff
766*7c478bd9Sstevel@tonic-gate 				 */
767*7c478bd9Sstevel@tonic-gate 				backoff_cnt++;
768*7c478bd9Sstevel@tonic-gate 				break;
769*7c478bd9Sstevel@tonic-gate 
770*7c478bd9Sstevel@tonic-gate 			case UPDATE_FULL_RESYNC_NEEDED:
771*7c478bd9Sstevel@tonic-gate 			case UPDATE_NIL:
772*7c478bd9Sstevel@tonic-gate 			default:
773*7c478bd9Sstevel@tonic-gate 				backoff_cnt = 0;
774*7c478bd9Sstevel@tonic-gate 				frdone = B_FALSE;
775*7c478bd9Sstevel@tonic-gate 				syslog(LOG_ERR, gettext("kpropd: Full resync,"
776*7c478bd9Sstevel@tonic-gate 					" invalid return from master KDC."));
777*7c478bd9Sstevel@tonic-gate 				break;
778*7c478bd9Sstevel@tonic-gate 
779*7c478bd9Sstevel@tonic-gate 			case UPDATE_PERM_DENIED:
780*7c478bd9Sstevel@tonic-gate 				syslog(LOG_ERR, gettext("kpropd: Full resync,"
781*7c478bd9Sstevel@tonic-gate 					" permission denied."));
782*7c478bd9Sstevel@tonic-gate 				goto error;
783*7c478bd9Sstevel@tonic-gate 
784*7c478bd9Sstevel@tonic-gate 			case UPDATE_ERROR:
785*7c478bd9Sstevel@tonic-gate 				syslog(LOG_ERR, gettext("kpropd: Full resync,"
786*7c478bd9Sstevel@tonic-gate 					" error returned from master KDC."));
787*7c478bd9Sstevel@tonic-gate 				goto error;
788*7c478bd9Sstevel@tonic-gate 			}
789*7c478bd9Sstevel@tonic-gate 			break;
790*7c478bd9Sstevel@tonic-gate 
791*7c478bd9Sstevel@tonic-gate 		case UPDATE_OK:
792*7c478bd9Sstevel@tonic-gate 			backoff_cnt = 0;
793*7c478bd9Sstevel@tonic-gate 			frdone = B_FALSE;
794*7c478bd9Sstevel@tonic-gate 
795*7c478bd9Sstevel@tonic-gate 			/*
796*7c478bd9Sstevel@tonic-gate 			 * ulog_replay() will convert the ulog updates to db
797*7c478bd9Sstevel@tonic-gate 			 * entries using the kdb conv api and will commit
798*7c478bd9Sstevel@tonic-gate 			 * the entries to the slave kdc database
799*7c478bd9Sstevel@tonic-gate 			 */
800*7c478bd9Sstevel@tonic-gate 			retval = ulog_replay(kpropd_context, incr_ret);
801*7c478bd9Sstevel@tonic-gate 
802*7c478bd9Sstevel@tonic-gate 			if (retval) {
803*7c478bd9Sstevel@tonic-gate 				syslog(LOG_ERR, gettext("kpropd: ulog_replay"
804*7c478bd9Sstevel@tonic-gate 					" failed, updates not registered."));
805*7c478bd9Sstevel@tonic-gate 				break;
806*7c478bd9Sstevel@tonic-gate 			}
807*7c478bd9Sstevel@tonic-gate 
808*7c478bd9Sstevel@tonic-gate 			if (debug)
809*7c478bd9Sstevel@tonic-gate 				fprintf(stderr, gettext("Update transfer "
810*7c478bd9Sstevel@tonic-gate 					"from master was OK\n"));
811*7c478bd9Sstevel@tonic-gate 			break;
812*7c478bd9Sstevel@tonic-gate 
813*7c478bd9Sstevel@tonic-gate 		case UPDATE_PERM_DENIED:
814*7c478bd9Sstevel@tonic-gate 			syslog(LOG_ERR, gettext("kpropd: get_updates,"
815*7c478bd9Sstevel@tonic-gate 						" permission denied."));
816*7c478bd9Sstevel@tonic-gate 			goto error;
817*7c478bd9Sstevel@tonic-gate 
818*7c478bd9Sstevel@tonic-gate 		case UPDATE_ERROR:
819*7c478bd9Sstevel@tonic-gate 			syslog(LOG_ERR, gettext("kpropd: get_updates, error "
820*7c478bd9Sstevel@tonic-gate 						"returned from master KDC."));
821*7c478bd9Sstevel@tonic-gate 			goto error;
822*7c478bd9Sstevel@tonic-gate 
823*7c478bd9Sstevel@tonic-gate 		case UPDATE_BUSY:
824*7c478bd9Sstevel@tonic-gate 			/*
825*7c478bd9Sstevel@tonic-gate 			 * Exponential backoff
826*7c478bd9Sstevel@tonic-gate 			 */
827*7c478bd9Sstevel@tonic-gate 			backoff_cnt++;
828*7c478bd9Sstevel@tonic-gate 			break;
829*7c478bd9Sstevel@tonic-gate 
830*7c478bd9Sstevel@tonic-gate 		case UPDATE_NIL:
831*7c478bd9Sstevel@tonic-gate 			/*
832*7c478bd9Sstevel@tonic-gate 			 * Master-slave are in sync
833*7c478bd9Sstevel@tonic-gate 			 */
834*7c478bd9Sstevel@tonic-gate 			if (debug)
835*7c478bd9Sstevel@tonic-gate 				fprintf(stderr, gettext("Master, slave KDC's "
836*7c478bd9Sstevel@tonic-gate 					"are in-sync, no updates\n"));
837*7c478bd9Sstevel@tonic-gate 			backoff_cnt = 0;
838*7c478bd9Sstevel@tonic-gate 			frdone = B_FALSE;
839*7c478bd9Sstevel@tonic-gate 			break;
840*7c478bd9Sstevel@tonic-gate 
841*7c478bd9Sstevel@tonic-gate 		default:
842*7c478bd9Sstevel@tonic-gate 			backoff_cnt = 0;
843*7c478bd9Sstevel@tonic-gate 			syslog(LOG_ERR, gettext("kpropd: get_updates,"
844*7c478bd9Sstevel@tonic-gate 					" invalid return from master KDC."));
845*7c478bd9Sstevel@tonic-gate 			break;
846*7c478bd9Sstevel@tonic-gate 		}
847*7c478bd9Sstevel@tonic-gate 
848*7c478bd9Sstevel@tonic-gate 		if (runonce == B_TRUE)
849*7c478bd9Sstevel@tonic-gate 			goto done;
850*7c478bd9Sstevel@tonic-gate 
851*7c478bd9Sstevel@tonic-gate 		/*
852*7c478bd9Sstevel@tonic-gate 		 * Sleep for the specified poll interval (Default is 2 mts),
853*7c478bd9Sstevel@tonic-gate 		 * or do a binary exponential backoff if we get an
854*7c478bd9Sstevel@tonic-gate 		 * UPDATE_BUSY signal
855*7c478bd9Sstevel@tonic-gate 		 */
856*7c478bd9Sstevel@tonic-gate 		if (backoff_cnt > 0) {
857*7c478bd9Sstevel@tonic-gate 			backoff_time = backoff_from_master(&backoff_cnt);
858*7c478bd9Sstevel@tonic-gate 			if (debug)
859*7c478bd9Sstevel@tonic-gate 				fprintf(stderr, gettext("Busy signal received "
860*7c478bd9Sstevel@tonic-gate 					"from master, backoff for %d secs\n"),
861*7c478bd9Sstevel@tonic-gate 					backoff_time);
862*7c478bd9Sstevel@tonic-gate 			(void) sleep(backoff_time);
863*7c478bd9Sstevel@tonic-gate 		}
864*7c478bd9Sstevel@tonic-gate 		else
865*7c478bd9Sstevel@tonic-gate 			(void) sleep(pollin);
866*7c478bd9Sstevel@tonic-gate 
867*7c478bd9Sstevel@tonic-gate 	}
868*7c478bd9Sstevel@tonic-gate 
869*7c478bd9Sstevel@tonic-gate 
870*7c478bd9Sstevel@tonic-gate error:
871*7c478bd9Sstevel@tonic-gate 	if (debug)
872*7c478bd9Sstevel@tonic-gate 		fprintf(stderr, gettext("ERROR returned by master, bailing\n"));
873*7c478bd9Sstevel@tonic-gate 	syslog(LOG_ERR, gettext("kpropd: ERROR returned by master KDC,"
874*7c478bd9Sstevel@tonic-gate 			" bailing.\n"));
875*7c478bd9Sstevel@tonic-gate done:
876*7c478bd9Sstevel@tonic-gate 	if (poll_time)
877*7c478bd9Sstevel@tonic-gate 		free(poll_time);
878*7c478bd9Sstevel@tonic-gate 	if(iprop_svc_princstr)
879*7c478bd9Sstevel@tonic-gate 		free(iprop_svc_princstr);
880*7c478bd9Sstevel@tonic-gate 	if (master_svc_princstr)
881*7c478bd9Sstevel@tonic-gate 		free(master_svc_princstr);
882*7c478bd9Sstevel@tonic-gate 	if (retval = krb5_cc_close(kpropd_context, cc)) {
883*7c478bd9Sstevel@tonic-gate 		com_err(progname, retval,
884*7c478bd9Sstevel@tonic-gate 			gettext("while closing default ccache"));
885*7c478bd9Sstevel@tonic-gate 		exit(1);
886*7c478bd9Sstevel@tonic-gate 	}
887*7c478bd9Sstevel@tonic-gate 	if (def_realm)
888*7c478bd9Sstevel@tonic-gate 		free(def_realm);
889*7c478bd9Sstevel@tonic-gate 	if (server_handle)
890*7c478bd9Sstevel@tonic-gate 		kadm5_destroy((void *)server_handle);
891*7c478bd9Sstevel@tonic-gate 	if (kpropd_context)
892*7c478bd9Sstevel@tonic-gate 		krb5_free_context(kpropd_context);
893*7c478bd9Sstevel@tonic-gate 
894*7c478bd9Sstevel@tonic-gate 	if (runonce == B_TRUE)
895*7c478bd9Sstevel@tonic-gate 		return (0);
896*7c478bd9Sstevel@tonic-gate 	else
897*7c478bd9Sstevel@tonic-gate 		exit(1);
898*7c478bd9Sstevel@tonic-gate }
899*7c478bd9Sstevel@tonic-gate 
900*7c478bd9Sstevel@tonic-gate 
901*7c478bd9Sstevel@tonic-gate /*
902*7c478bd9Sstevel@tonic-gate  * Do exponential backoff, since master KDC is BUSY or down
903*7c478bd9Sstevel@tonic-gate  */
904*7c478bd9Sstevel@tonic-gate unsigned int backoff_from_master(int *cnt) {
905*7c478bd9Sstevel@tonic-gate 	unsigned int btime;
906*7c478bd9Sstevel@tonic-gate 
907*7c478bd9Sstevel@tonic-gate 	btime = (unsigned int)(2<<(*cnt));
908*7c478bd9Sstevel@tonic-gate 	if (btime > MAX_BACKOFF) {
909*7c478bd9Sstevel@tonic-gate 		btime = MAX_BACKOFF;
910*7c478bd9Sstevel@tonic-gate 		*cnt--;
911*7c478bd9Sstevel@tonic-gate 	}
912*7c478bd9Sstevel@tonic-gate 
913*7c478bd9Sstevel@tonic-gate 	return (btime);
914*7c478bd9Sstevel@tonic-gate }
915*7c478bd9Sstevel@tonic-gate 
916*7c478bd9Sstevel@tonic-gate 
917*7c478bd9Sstevel@tonic-gate /*
918*7c478bd9Sstevel@tonic-gate  * Routine to convert the `pollstr' string to seconds
919*7c478bd9Sstevel@tonic-gate  */
920*7c478bd9Sstevel@tonic-gate int convert_polltime(char *pollstr) {
921*7c478bd9Sstevel@tonic-gate 	char *tokenptr = NULL;
922*7c478bd9Sstevel@tonic-gate 	int len, polltime;
923*7c478bd9Sstevel@tonic-gate 
924*7c478bd9Sstevel@tonic-gate 	len = polltime = 0;
925*7c478bd9Sstevel@tonic-gate 
926*7c478bd9Sstevel@tonic-gate 	if ((len = strcspn(pollstr, "s")) < strlen(pollstr)) {
927*7c478bd9Sstevel@tonic-gate 		tokenptr = malloc((len + 1) * sizeof(char));
928*7c478bd9Sstevel@tonic-gate 		(void) strlcpy(tokenptr, pollstr, len + 1);
929*7c478bd9Sstevel@tonic-gate 		polltime = atoi(tokenptr);
930*7c478bd9Sstevel@tonic-gate 	}
931*7c478bd9Sstevel@tonic-gate 
932*7c478bd9Sstevel@tonic-gate 	if ((len = strcspn(pollstr, "m")) < strlen(pollstr)) {
933*7c478bd9Sstevel@tonic-gate 		tokenptr = malloc((len + 1) * sizeof(char));
934*7c478bd9Sstevel@tonic-gate 		(void) strlcpy(tokenptr, pollstr, len + 1);
935*7c478bd9Sstevel@tonic-gate 		polltime = atoi(tokenptr) * 60;
936*7c478bd9Sstevel@tonic-gate 	}
937*7c478bd9Sstevel@tonic-gate 
938*7c478bd9Sstevel@tonic-gate 	if ((len = strcspn(pollstr, "h")) < strlen(pollstr)) {
939*7c478bd9Sstevel@tonic-gate 		tokenptr = malloc((len + 1) * sizeof(char));
940*7c478bd9Sstevel@tonic-gate 		(void) strlcpy(tokenptr, pollstr, len + 1);
941*7c478bd9Sstevel@tonic-gate 		polltime = atoi(tokenptr) * 3600;
942*7c478bd9Sstevel@tonic-gate 	}
943*7c478bd9Sstevel@tonic-gate 
944*7c478bd9Sstevel@tonic-gate 	if (tokenptr != NULL)
945*7c478bd9Sstevel@tonic-gate 		free(tokenptr);
946*7c478bd9Sstevel@tonic-gate 	/*
947*7c478bd9Sstevel@tonic-gate 	 * If we have a bogus pollstr value, set polltime to the
948*7c478bd9Sstevel@tonic-gate 	 * default of 2 mts (120 seconds).
949*7c478bd9Sstevel@tonic-gate 	 */
950*7c478bd9Sstevel@tonic-gate 	if (polltime == 0)
951*7c478bd9Sstevel@tonic-gate 		polltime = 120;
952*7c478bd9Sstevel@tonic-gate 	return (polltime);
953*7c478bd9Sstevel@tonic-gate }
954*7c478bd9Sstevel@tonic-gate 
955*7c478bd9Sstevel@tonic-gate static void
956*7c478bd9Sstevel@tonic-gate kpropd_com_err_proc(whoami, code, fmt, args)
957*7c478bd9Sstevel@tonic-gate 	const char	*whoami;
958*7c478bd9Sstevel@tonic-gate 	long		code;
959*7c478bd9Sstevel@tonic-gate 	const char	*fmt;
960*7c478bd9Sstevel@tonic-gate 	va_list		args;
961*7c478bd9Sstevel@tonic-gate {
962*7c478bd9Sstevel@tonic-gate 	char	error_buf[8096];
963*7c478bd9Sstevel@tonic-gate 
964*7c478bd9Sstevel@tonic-gate 	error_buf[0] = '\0';
965*7c478bd9Sstevel@tonic-gate 	if (fmt)
966*7c478bd9Sstevel@tonic-gate 		vsprintf(error_buf, fmt, args);
967*7c478bd9Sstevel@tonic-gate 	syslog(LOG_ERR, "%s%s%s%s%s", whoami ? whoami : "", whoami ? ": " : "",
968*7c478bd9Sstevel@tonic-gate 	       code ? error_message(code) : "", code ? " " : "", error_buf);
969*7c478bd9Sstevel@tonic-gate }
970*7c478bd9Sstevel@tonic-gate 
971*7c478bd9Sstevel@tonic-gate void PRS(argc,argv)
972*7c478bd9Sstevel@tonic-gate 	int	argc;
973*7c478bd9Sstevel@tonic-gate 	char	**argv;
974*7c478bd9Sstevel@tonic-gate {
975*7c478bd9Sstevel@tonic-gate 	register char	*word, ch;
976*7c478bd9Sstevel@tonic-gate 	char	*cp;
977*7c478bd9Sstevel@tonic-gate 	int c;
978*7c478bd9Sstevel@tonic-gate 	struct hostent *hp;
979*7c478bd9Sstevel@tonic-gate 	char	my_host_name[MAXHOSTNAMELEN], buf[BUFSIZ];
980*7c478bd9Sstevel@tonic-gate 	krb5_error_code	retval;
981*7c478bd9Sstevel@tonic-gate 	static const char	tmp[] = ".temp";
982*7c478bd9Sstevel@tonic-gate 	kadm5_config_params	params;
983*7c478bd9Sstevel@tonic-gate 
984*7c478bd9Sstevel@tonic-gate 	(void) setlocale(LC_ALL, "");
985*7c478bd9Sstevel@tonic-gate 
986*7c478bd9Sstevel@tonic-gate #if !defined(TEXT_DOMAIN)		/* Should be defined by cc -D */
987*7c478bd9Sstevel@tonic-gate #define	TEXT_DOMAIN	"KPROPD_TEST"	/* Use this only if it weren't */
988*7c478bd9Sstevel@tonic-gate #endif
989*7c478bd9Sstevel@tonic-gate 
990*7c478bd9Sstevel@tonic-gate 	(void) textdomain(TEXT_DOMAIN);
991*7c478bd9Sstevel@tonic-gate 
992*7c478bd9Sstevel@tonic-gate 	(void) memset((char *) &params, 0, sizeof (params));
993*7c478bd9Sstevel@tonic-gate 
994*7c478bd9Sstevel@tonic-gate 	retval = krb5_init_context(&kpropd_context);
995*7c478bd9Sstevel@tonic-gate 	if (retval) {
996*7c478bd9Sstevel@tonic-gate 		com_err(argv[0], retval,
997*7c478bd9Sstevel@tonic-gate 			gettext("while initializing krb5"));
998*7c478bd9Sstevel@tonic-gate 		exit(1);
999*7c478bd9Sstevel@tonic-gate 	}
1000*7c478bd9Sstevel@tonic-gate 	progname = argv[0];
1001*7c478bd9Sstevel@tonic-gate 	while ((c = getopt(argc, argv, "dtf:F:p:P:r:s:Sa:")) != EOF){
1002*7c478bd9Sstevel@tonic-gate 		switch (c) {
1003*7c478bd9Sstevel@tonic-gate 		case 'd':
1004*7c478bd9Sstevel@tonic-gate 			debug++;
1005*7c478bd9Sstevel@tonic-gate 			break;
1006*7c478bd9Sstevel@tonic-gate 		case 't':
1007*7c478bd9Sstevel@tonic-gate 			/*
1008*7c478bd9Sstevel@tonic-gate 			 * Undocumented option - for testing only.
1009*7c478bd9Sstevel@tonic-gate 			 *
1010*7c478bd9Sstevel@tonic-gate 			 * Option to run the kpropd server exactly
1011*7c478bd9Sstevel@tonic-gate 			 * once (this is true only if iprop is enabled).
1012*7c478bd9Sstevel@tonic-gate 			 */
1013*7c478bd9Sstevel@tonic-gate 			runonce = B_TRUE;
1014*7c478bd9Sstevel@tonic-gate 			break;
1015*7c478bd9Sstevel@tonic-gate 
1016*7c478bd9Sstevel@tonic-gate 		case 'f':
1017*7c478bd9Sstevel@tonic-gate 			file = optarg;
1018*7c478bd9Sstevel@tonic-gate 			if (!file)
1019*7c478bd9Sstevel@tonic-gate 				usage();
1020*7c478bd9Sstevel@tonic-gate 			break;
1021*7c478bd9Sstevel@tonic-gate 		case 'F':
1022*7c478bd9Sstevel@tonic-gate 			kerb_database = optarg;
1023*7c478bd9Sstevel@tonic-gate 			if (!kerb_database)
1024*7c478bd9Sstevel@tonic-gate 				usage();
1025*7c478bd9Sstevel@tonic-gate 			break;
1026*7c478bd9Sstevel@tonic-gate 		case 'p':
1027*7c478bd9Sstevel@tonic-gate 			kdb5_util = optarg;
1028*7c478bd9Sstevel@tonic-gate 			if (!kdb5_util)
1029*7c478bd9Sstevel@tonic-gate 				usage();
1030*7c478bd9Sstevel@tonic-gate 			break;
1031*7c478bd9Sstevel@tonic-gate 		case 'P':
1032*7c478bd9Sstevel@tonic-gate 			port = htons(atoi(optarg));
1033*7c478bd9Sstevel@tonic-gate 			if (!port)
1034*7c478bd9Sstevel@tonic-gate 				usage();
1035*7c478bd9Sstevel@tonic-gate 			break;
1036*7c478bd9Sstevel@tonic-gate 		case 'r':
1037*7c478bd9Sstevel@tonic-gate 			realm = optarg;
1038*7c478bd9Sstevel@tonic-gate 			if (!realm)
1039*7c478bd9Sstevel@tonic-gate 				usage();
1040*7c478bd9Sstevel@tonic-gate 			params.realm = realm;
1041*7c478bd9Sstevel@tonic-gate 			params.mask |= KADM5_CONFIG_REALM;
1042*7c478bd9Sstevel@tonic-gate 			break;
1043*7c478bd9Sstevel@tonic-gate 		case 's':
1044*7c478bd9Sstevel@tonic-gate 			srvtab = optarg;
1045*7c478bd9Sstevel@tonic-gate 			if (!srvtab)
1046*7c478bd9Sstevel@tonic-gate 				usage();
1047*7c478bd9Sstevel@tonic-gate 			break;
1048*7c478bd9Sstevel@tonic-gate 		case 'S':
1049*7c478bd9Sstevel@tonic-gate 			standalone++;
1050*7c478bd9Sstevel@tonic-gate 			break;
1051*7c478bd9Sstevel@tonic-gate 		case 'a':
1052*7c478bd9Sstevel@tonic-gate 			acl_file_name = optarg;
1053*7c478bd9Sstevel@tonic-gate 			if (!acl_file_name)
1054*7c478bd9Sstevel@tonic-gate 				usage();
1055*7c478bd9Sstevel@tonic-gate 			break;
1056*7c478bd9Sstevel@tonic-gate 		case '?':
1057*7c478bd9Sstevel@tonic-gate 				default:
1058*7c478bd9Sstevel@tonic-gate 					usage();
1059*7c478bd9Sstevel@tonic-gate 				}
1060*7c478bd9Sstevel@tonic-gate 
1061*7c478bd9Sstevel@tonic-gate 			}
1062*7c478bd9Sstevel@tonic-gate 	/*
1063*7c478bd9Sstevel@tonic-gate 	 * If not in debug mode, switch com_err reporting to syslog
1064*7c478bd9Sstevel@tonic-gate 	 */
1065*7c478bd9Sstevel@tonic-gate 	if (! debug) {
1066*7c478bd9Sstevel@tonic-gate 	    openlog("kpropd", LOG_PID | LOG_ODELAY, SYSLOG_CLASS);
1067*7c478bd9Sstevel@tonic-gate 	    set_com_err_hook(kpropd_com_err_proc);
1068*7c478bd9Sstevel@tonic-gate 	}
1069*7c478bd9Sstevel@tonic-gate 	/*
1070*7c478bd9Sstevel@tonic-gate 	 * Get my hostname, so we can construct my service name
1071*7c478bd9Sstevel@tonic-gate 	 */
1072*7c478bd9Sstevel@tonic-gate 	retval = krb5_sname_to_principal(kpropd_context,
1073*7c478bd9Sstevel@tonic-gate 					 NULL, KPROP_SERVICE_NAME,
1074*7c478bd9Sstevel@tonic-gate 					 KRB5_NT_SRV_HST, &server);
1075*7c478bd9Sstevel@tonic-gate 	if (retval) {
1076*7c478bd9Sstevel@tonic-gate 		com_err(progname, retval,
1077*7c478bd9Sstevel@tonic-gate 			gettext("While trying to construct my service name"));
1078*7c478bd9Sstevel@tonic-gate 		exit(1);
1079*7c478bd9Sstevel@tonic-gate 	}
1080*7c478bd9Sstevel@tonic-gate 	if (realm) {
1081*7c478bd9Sstevel@tonic-gate 	    (void) krb5_xfree(krb5_princ_realm(context, server)->data);
1082*7c478bd9Sstevel@tonic-gate 	    krb5_princ_set_realm_length(context, server, strlen(realm));
1083*7c478bd9Sstevel@tonic-gate 	    krb5_princ_set_realm_data(context, server, strdup(realm));
1084*7c478bd9Sstevel@tonic-gate 	}
1085*7c478bd9Sstevel@tonic-gate 	/*
1086*7c478bd9Sstevel@tonic-gate 	 * Construct the name of the temporary file.
1087*7c478bd9Sstevel@tonic-gate 	 */
1088*7c478bd9Sstevel@tonic-gate 	if ((temp_file_name = (char *) malloc(strlen(file) +
1089*7c478bd9Sstevel@tonic-gate 					       strlen(tmp) + 1)) == NULL) {
1090*7c478bd9Sstevel@tonic-gate 		com_err(progname, ENOMEM,
1091*7c478bd9Sstevel@tonic-gate 			gettext("while allocating filename for temp file"));
1092*7c478bd9Sstevel@tonic-gate 		exit(1);
1093*7c478bd9Sstevel@tonic-gate 	}
1094*7c478bd9Sstevel@tonic-gate 	strcpy(temp_file_name, file);
1095*7c478bd9Sstevel@tonic-gate 	strcat(temp_file_name, tmp);
1096*7c478bd9Sstevel@tonic-gate 
1097*7c478bd9Sstevel@tonic-gate 	retval = kadm5_get_config_params(kpropd_context, NULL, NULL, &params,
1098*7c478bd9Sstevel@tonic-gate 	    &params);
1099*7c478bd9Sstevel@tonic-gate 	if (retval) {
1100*7c478bd9Sstevel@tonic-gate 		com_err(progname, retval, gettext("while initializing"));
1101*7c478bd9Sstevel@tonic-gate 		exit(1);
1102*7c478bd9Sstevel@tonic-gate 	}
1103*7c478bd9Sstevel@tonic-gate 	if (params.iprop_enabled == TRUE) {
1104*7c478bd9Sstevel@tonic-gate 		ulog_set_role(kpropd_context, IPROP_SLAVE);
1105*7c478bd9Sstevel@tonic-gate 		poll_time = params.iprop_polltime;
1106*7c478bd9Sstevel@tonic-gate 
1107*7c478bd9Sstevel@tonic-gate 		if (ulog_map(kpropd_context, &params, FKPROPD)) {
1108*7c478bd9Sstevel@tonic-gate  			com_err(progname, errno,
1109*7c478bd9Sstevel@tonic-gate 			    gettext("Unable to map log!\n"));
1110*7c478bd9Sstevel@tonic-gate 			exit(1);
1111*7c478bd9Sstevel@tonic-gate 		}
1112*7c478bd9Sstevel@tonic-gate 	}
1113*7c478bd9Sstevel@tonic-gate 
1114*7c478bd9Sstevel@tonic-gate 	/*
1115*7c478bd9Sstevel@tonic-gate 	 * Grab the realm info and check if iprop is enabled.
1116*7c478bd9Sstevel@tonic-gate 	 */
1117*7c478bd9Sstevel@tonic-gate 	if (def_realm == NULL) {
1118*7c478bd9Sstevel@tonic-gate 		retval = krb5_get_default_realm(kpropd_context, &def_realm);
1119*7c478bd9Sstevel@tonic-gate 		if (retval) {
1120*7c478bd9Sstevel@tonic-gate 			com_err(progname, retval,
1121*7c478bd9Sstevel@tonic-gate 				gettext("Unable to get default realm"));
1122*7c478bd9Sstevel@tonic-gate 			exit(1);
1123*7c478bd9Sstevel@tonic-gate 		}
1124*7c478bd9Sstevel@tonic-gate 	}
1125*7c478bd9Sstevel@tonic-gate }
1126*7c478bd9Sstevel@tonic-gate 
1127*7c478bd9Sstevel@tonic-gate /*
1128*7c478bd9Sstevel@tonic-gate  * Figure out who's calling on the other end of the connection....
1129*7c478bd9Sstevel@tonic-gate  */
1130*7c478bd9Sstevel@tonic-gate void
1131*7c478bd9Sstevel@tonic-gate kerberos_authenticate(context, fd, clientp, etype, ss)
1132*7c478bd9Sstevel@tonic-gate     krb5_context 	  context;
1133*7c478bd9Sstevel@tonic-gate     int		 	  fd;
1134*7c478bd9Sstevel@tonic-gate     krb5_principal	* clientp;
1135*7c478bd9Sstevel@tonic-gate     krb5_enctype	* etype;
1136*7c478bd9Sstevel@tonic-gate     struct sockaddr_storage	  ss;
1137*7c478bd9Sstevel@tonic-gate {
1138*7c478bd9Sstevel@tonic-gate     krb5_error_code	  retval;
1139*7c478bd9Sstevel@tonic-gate     krb5_ticket		* ticket;
1140*7c478bd9Sstevel@tonic-gate     struct sockaddr_storage	  r_ss;
1141*7c478bd9Sstevel@tonic-gate     int			  ss_length;
1142*7c478bd9Sstevel@tonic-gate     krb5_keytab		  keytab = NULL;
1143*7c478bd9Sstevel@tonic-gate 
1144*7c478bd9Sstevel@tonic-gate     /*
1145*7c478bd9Sstevel@tonic-gate      * Set recv_addr and send_addr
1146*7c478bd9Sstevel@tonic-gate      */
1147*7c478bd9Sstevel@tonic-gate     if (cvtkaddr(&ss, &sender_addr) == NULL) {
1148*7c478bd9Sstevel@tonic-gate 	com_err(progname, errno,
1149*7c478bd9Sstevel@tonic-gate 		gettext("while converting socket address"));
1150*7c478bd9Sstevel@tonic-gate 	exit(1);
1151*7c478bd9Sstevel@tonic-gate     }
1152*7c478bd9Sstevel@tonic-gate 
1153*7c478bd9Sstevel@tonic-gate     ss_length = sizeof (r_ss);
1154*7c478bd9Sstevel@tonic-gate     if (getsockname(fd, (struct sockaddr *) &r_ss, &ss_length)) {
1155*7c478bd9Sstevel@tonic-gate 	com_err(progname, errno,
1156*7c478bd9Sstevel@tonic-gate 		gettext("while getting local socket address"));
1157*7c478bd9Sstevel@tonic-gate 	exit(1);
1158*7c478bd9Sstevel@tonic-gate     }
1159*7c478bd9Sstevel@tonic-gate 
1160*7c478bd9Sstevel@tonic-gate     if (cvtkaddr(&r_ss, &receiver_addr) == NULL) {
1161*7c478bd9Sstevel@tonic-gate 	com_err(progname, errno,
1162*7c478bd9Sstevel@tonic-gate 		gettext("while converting socket address"));
1163*7c478bd9Sstevel@tonic-gate 	exit(1);
1164*7c478bd9Sstevel@tonic-gate     }
1165*7c478bd9Sstevel@tonic-gate 
1166*7c478bd9Sstevel@tonic-gate     if (debug) {
1167*7c478bd9Sstevel@tonic-gate 	char *name;
1168*7c478bd9Sstevel@tonic-gate 	if (retval = krb5_unparse_name(context, server, &name)) {
1169*7c478bd9Sstevel@tonic-gate 	    com_err(progname, retval, gettext("While unparsing server name"));
1170*7c478bd9Sstevel@tonic-gate 	    exit(1);
1171*7c478bd9Sstevel@tonic-gate 	}
1172*7c478bd9Sstevel@tonic-gate 	printf(gettext("krb5_recvauth(%d, %s, %s, ...)\n"), fd, kprop_version,
1173*7c478bd9Sstevel@tonic-gate 	    name);
1174*7c478bd9Sstevel@tonic-gate 	free(name);
1175*7c478bd9Sstevel@tonic-gate     }
1176*7c478bd9Sstevel@tonic-gate 
1177*7c478bd9Sstevel@tonic-gate     if (retval = krb5_auth_con_init(context, &auth_context)) {
1178*7c478bd9Sstevel@tonic-gate 	syslog(LOG_ERR, gettext("Error in krb5_auth_con_init: %s"),
1179*7c478bd9Sstevel@tonic-gate 	    error_message(retval));
1180*7c478bd9Sstevel@tonic-gate     	exit(1);
1181*7c478bd9Sstevel@tonic-gate     }
1182*7c478bd9Sstevel@tonic-gate 
1183*7c478bd9Sstevel@tonic-gate     if (retval = krb5_auth_con_setflags(context, auth_context,
1184*7c478bd9Sstevel@tonic-gate 					KRB5_AUTH_CONTEXT_DO_SEQUENCE)) {
1185*7c478bd9Sstevel@tonic-gate 	syslog(LOG_ERR, gettext("Error in krb5_auth_con_setflags: %s"),
1186*7c478bd9Sstevel@tonic-gate 	       error_message(retval));
1187*7c478bd9Sstevel@tonic-gate 	exit(1);
1188*7c478bd9Sstevel@tonic-gate     }
1189*7c478bd9Sstevel@tonic-gate 
1190*7c478bd9Sstevel@tonic-gate     if (retval = krb5_auth_con_setaddrs(context, auth_context, &receiver_addr,
1191*7c478bd9Sstevel@tonic-gate 				        &sender_addr)) {
1192*7c478bd9Sstevel@tonic-gate 	syslog(LOG_ERR, gettext("Error in krb5_auth_con_setaddrs: %s"),
1193*7c478bd9Sstevel@tonic-gate 	       error_message(retval));
1194*7c478bd9Sstevel@tonic-gate 	exit(1);
1195*7c478bd9Sstevel@tonic-gate     }
1196*7c478bd9Sstevel@tonic-gate 
1197*7c478bd9Sstevel@tonic-gate     if (srvtab) {
1198*7c478bd9Sstevel@tonic-gate 	if (retval = krb5_kt_resolve(context, srvtab, &keytab)) {
1199*7c478bd9Sstevel@tonic-gate 	  syslog(LOG_ERR, gettext("Error in krb5_kt_resolve: %s"), error_message(retval));
1200*7c478bd9Sstevel@tonic-gate 	  exit(1);
1201*7c478bd9Sstevel@tonic-gate 	}
1202*7c478bd9Sstevel@tonic-gate     }
1203*7c478bd9Sstevel@tonic-gate 
1204*7c478bd9Sstevel@tonic-gate     if (retval = krb5_recvauth(context, &auth_context, (void *) &fd,
1205*7c478bd9Sstevel@tonic-gate 			       kprop_version, server, 0, keytab, &ticket)){
1206*7c478bd9Sstevel@tonic-gate 	syslog(LOG_ERR, gettext("Error in krb5_recvauth: %s"),
1207*7c478bd9Sstevel@tonic-gate 	    error_message(retval));
1208*7c478bd9Sstevel@tonic-gate 	exit(1);
1209*7c478bd9Sstevel@tonic-gate     }
1210*7c478bd9Sstevel@tonic-gate 
1211*7c478bd9Sstevel@tonic-gate     if (retval = krb5_copy_principal(context,
1212*7c478bd9Sstevel@tonic-gate 				     ticket->enc_part2->client, clientp)) {
1213*7c478bd9Sstevel@tonic-gate 	syslog(LOG_ERR, gettext("Error in krb5_copy_prinicpal: %s"),
1214*7c478bd9Sstevel@tonic-gate 	       error_message(retval));
1215*7c478bd9Sstevel@tonic-gate 	exit(1);
1216*7c478bd9Sstevel@tonic-gate     }
1217*7c478bd9Sstevel@tonic-gate 
1218*7c478bd9Sstevel@tonic-gate     *etype = ticket->enc_part.enctype;
1219*7c478bd9Sstevel@tonic-gate 
1220*7c478bd9Sstevel@tonic-gate     if (debug) {
1221*7c478bd9Sstevel@tonic-gate 	char * name;
1222*7c478bd9Sstevel@tonic-gate 	char etypebuf[100];
1223*7c478bd9Sstevel@tonic-gate 
1224*7c478bd9Sstevel@tonic-gate 	if (retval = krb5_unparse_name(context, *clientp, &name)) {
1225*7c478bd9Sstevel@tonic-gate 	    com_err(progname, retval,
1226*7c478bd9Sstevel@tonic-gate 		gettext("While unparsing client name"));
1227*7c478bd9Sstevel@tonic-gate 	    exit(1);
1228*7c478bd9Sstevel@tonic-gate 	}
1229*7c478bd9Sstevel@tonic-gate 
1230*7c478bd9Sstevel@tonic-gate 	if (retval = krb5_enctype_to_string(*etype, etypebuf,
1231*7c478bd9Sstevel@tonic-gate 					    sizeof(etypebuf))) {
1232*7c478bd9Sstevel@tonic-gate 	    com_err(progname, retval, gettext("While unparsing ticket etype"));
1233*7c478bd9Sstevel@tonic-gate 	    exit(1);
1234*7c478bd9Sstevel@tonic-gate 	}
1235*7c478bd9Sstevel@tonic-gate 
1236*7c478bd9Sstevel@tonic-gate 	printf("authenticated client: %s (etype == %s)\n", name, etypebuf);
1237*7c478bd9Sstevel@tonic-gate 	free(name);
1238*7c478bd9Sstevel@tonic-gate     }
1239*7c478bd9Sstevel@tonic-gate 
1240*7c478bd9Sstevel@tonic-gate     krb5_free_ticket(context, ticket);
1241*7c478bd9Sstevel@tonic-gate }
1242*7c478bd9Sstevel@tonic-gate 
1243*7c478bd9Sstevel@tonic-gate krb5_boolean
1244*7c478bd9Sstevel@tonic-gate authorized_principal(context, p, auth_etype)
1245*7c478bd9Sstevel@tonic-gate     krb5_context context;
1246*7c478bd9Sstevel@tonic-gate     krb5_principal p;
1247*7c478bd9Sstevel@tonic-gate     krb5_enctype auth_etype;
1248*7c478bd9Sstevel@tonic-gate {
1249*7c478bd9Sstevel@tonic-gate     char		*name, *ptr;
1250*7c478bd9Sstevel@tonic-gate     char		buf[1024];
1251*7c478bd9Sstevel@tonic-gate     krb5_error_code	retval;
1252*7c478bd9Sstevel@tonic-gate     FILE		*acl_file;
1253*7c478bd9Sstevel@tonic-gate     int			end;
1254*7c478bd9Sstevel@tonic-gate     krb5_enctype	acl_etype;
1255*7c478bd9Sstevel@tonic-gate 
1256*7c478bd9Sstevel@tonic-gate     retval = krb5_unparse_name(context, p, &name);
1257*7c478bd9Sstevel@tonic-gate     if (retval)
1258*7c478bd9Sstevel@tonic-gate 	return FALSE;
1259*7c478bd9Sstevel@tonic-gate 
1260*7c478bd9Sstevel@tonic-gate     acl_file = fopen(acl_file_name, "r");
1261*7c478bd9Sstevel@tonic-gate     if (!acl_file)
1262*7c478bd9Sstevel@tonic-gate 	return FALSE;
1263*7c478bd9Sstevel@tonic-gate 
1264*7c478bd9Sstevel@tonic-gate     while (!feof(acl_file)) {
1265*7c478bd9Sstevel@tonic-gate 	if (!fgets(buf, sizeof(buf), acl_file))
1266*7c478bd9Sstevel@tonic-gate 	    break;
1267*7c478bd9Sstevel@tonic-gate 	end = strlen(buf) - 1;
1268*7c478bd9Sstevel@tonic-gate 	if (buf[end] == '\n')
1269*7c478bd9Sstevel@tonic-gate 	    buf[end] = '\0';
1270*7c478bd9Sstevel@tonic-gate 	if (!strncmp(name, buf, strlen(name))) {
1271*7c478bd9Sstevel@tonic-gate 	    ptr = buf+strlen(name);
1272*7c478bd9Sstevel@tonic-gate 
1273*7c478bd9Sstevel@tonic-gate 	    /* if the next character is not whitespace or nul, then
1274*7c478bd9Sstevel@tonic-gate 	       the match is only partial.  continue on to new lines. */
1275*7c478bd9Sstevel@tonic-gate 	    if (*ptr && !isspace(*ptr))
1276*7c478bd9Sstevel@tonic-gate 		continue;
1277*7c478bd9Sstevel@tonic-gate 
1278*7c478bd9Sstevel@tonic-gate 	    /* otherwise, skip trailing whitespace */
1279*7c478bd9Sstevel@tonic-gate 	    for (; *ptr && isspace(*ptr); ptr++) ;
1280*7c478bd9Sstevel@tonic-gate 
1281*7c478bd9Sstevel@tonic-gate 	    /* now, look for an etype string. if there isn't one,
1282*7c478bd9Sstevel@tonic-gate 	       return true.  if there is an invalid string, continue.
1283*7c478bd9Sstevel@tonic-gate 	       If there is a valid string, return true only if it
1284*7c478bd9Sstevel@tonic-gate 	       matches the etype passed in, otherwise continue */
1285*7c478bd9Sstevel@tonic-gate 
1286*7c478bd9Sstevel@tonic-gate 	    if ((*ptr) &&
1287*7c478bd9Sstevel@tonic-gate 		((retval = krb5_string_to_enctype(ptr, &acl_etype)) ||
1288*7c478bd9Sstevel@tonic-gate 		 (acl_etype != auth_etype)))
1289*7c478bd9Sstevel@tonic-gate 		continue;
1290*7c478bd9Sstevel@tonic-gate 
1291*7c478bd9Sstevel@tonic-gate 	    free(name);
1292*7c478bd9Sstevel@tonic-gate 	    fclose(acl_file);
1293*7c478bd9Sstevel@tonic-gate 	    return TRUE;
1294*7c478bd9Sstevel@tonic-gate 	}
1295*7c478bd9Sstevel@tonic-gate     }
1296*7c478bd9Sstevel@tonic-gate     free(name);
1297*7c478bd9Sstevel@tonic-gate     fclose(acl_file);
1298*7c478bd9Sstevel@tonic-gate     return FALSE;
1299*7c478bd9Sstevel@tonic-gate }
1300*7c478bd9Sstevel@tonic-gate 
1301*7c478bd9Sstevel@tonic-gate void
1302*7c478bd9Sstevel@tonic-gate recv_database(context, fd, database_fd, confmsg)
1303*7c478bd9Sstevel@tonic-gate     krb5_context context;
1304*7c478bd9Sstevel@tonic-gate     int	fd;
1305*7c478bd9Sstevel@tonic-gate     int	database_fd;
1306*7c478bd9Sstevel@tonic-gate     krb5_data *confmsg;
1307*7c478bd9Sstevel@tonic-gate {
1308*7c478bd9Sstevel@tonic-gate 	int	database_size;
1309*7c478bd9Sstevel@tonic-gate 	int	received_size, n;
1310*7c478bd9Sstevel@tonic-gate 	char		buf[1024];
1311*7c478bd9Sstevel@tonic-gate 	krb5_data	inbuf, outbuf;
1312*7c478bd9Sstevel@tonic-gate 	krb5_error_code	retval;
1313*7c478bd9Sstevel@tonic-gate 
1314*7c478bd9Sstevel@tonic-gate 	/*
1315*7c478bd9Sstevel@tonic-gate 	 * Receive and decode size from client
1316*7c478bd9Sstevel@tonic-gate 	 */
1317*7c478bd9Sstevel@tonic-gate 	if (retval = krb5_read_message(context, (void *) &fd, &inbuf)) {
1318*7c478bd9Sstevel@tonic-gate 		send_error(context, fd, retval, gettext("while reading database size"));
1319*7c478bd9Sstevel@tonic-gate 		com_err(progname, retval,
1320*7c478bd9Sstevel@tonic-gate 			gettext("while reading size of database from client"));
1321*7c478bd9Sstevel@tonic-gate 		exit(1);
1322*7c478bd9Sstevel@tonic-gate 	}
1323*7c478bd9Sstevel@tonic-gate 	if (krb5_is_krb_error(&inbuf))
1324*7c478bd9Sstevel@tonic-gate 		recv_error(context, &inbuf);
1325*7c478bd9Sstevel@tonic-gate 	if (retval = krb5_rd_safe(context,auth_context,&inbuf,&outbuf,NULL)) {
1326*7c478bd9Sstevel@tonic-gate 		send_error(context, fd, retval, gettext("while decoding database size"));
1327*7c478bd9Sstevel@tonic-gate 		krb5_free_data_contents(context, &inbuf);
1328*7c478bd9Sstevel@tonic-gate 		com_err(progname, retval,
1329*7c478bd9Sstevel@tonic-gate 			gettext("while decoding database size from client"));
1330*7c478bd9Sstevel@tonic-gate 		exit(1);
1331*7c478bd9Sstevel@tonic-gate 	}
1332*7c478bd9Sstevel@tonic-gate 	memcpy((char *) &database_size, outbuf.data, sizeof(database_size));
1333*7c478bd9Sstevel@tonic-gate 	krb5_free_data_contents(context, &inbuf);
1334*7c478bd9Sstevel@tonic-gate 	krb5_free_data_contents(context, &outbuf);
1335*7c478bd9Sstevel@tonic-gate 	database_size = ntohl(database_size);
1336*7c478bd9Sstevel@tonic-gate 
1337*7c478bd9Sstevel@tonic-gate     /*
1338*7c478bd9Sstevel@tonic-gate      * Initialize the initial vector.
1339*7c478bd9Sstevel@tonic-gate      */
1340*7c478bd9Sstevel@tonic-gate     if (retval = krb5_auth_con_initivector(context, auth_context)) {
1341*7c478bd9Sstevel@tonic-gate 	send_error(context, fd, retval, gettext("failed while initializing i_vector"));
1342*7c478bd9Sstevel@tonic-gate 	com_err(progname, retval, gettext("while initializing i_vector"));
1343*7c478bd9Sstevel@tonic-gate 	exit(1);
1344*7c478bd9Sstevel@tonic-gate     }
1345*7c478bd9Sstevel@tonic-gate 
1346*7c478bd9Sstevel@tonic-gate 	/*
1347*7c478bd9Sstevel@tonic-gate 	 * Now start receiving the database from the net
1348*7c478bd9Sstevel@tonic-gate 	 */
1349*7c478bd9Sstevel@tonic-gate 	received_size = 0;
1350*7c478bd9Sstevel@tonic-gate 	while (received_size < database_size) {
1351*7c478bd9Sstevel@tonic-gate 		if (retval = krb5_read_message(context, (void *) &fd, &inbuf)) {
1352*7c478bd9Sstevel@tonic-gate 			snprintf(buf, sizeof (buf),
1353*7c478bd9Sstevel@tonic-gate 			gettext("while reading database block starting at offset %d"),
1354*7c478bd9Sstevel@tonic-gate 				received_size);
1355*7c478bd9Sstevel@tonic-gate 			com_err(progname, retval, buf);
1356*7c478bd9Sstevel@tonic-gate 			send_error(context, fd, retval, buf);
1357*7c478bd9Sstevel@tonic-gate 			exit(1);
1358*7c478bd9Sstevel@tonic-gate 		}
1359*7c478bd9Sstevel@tonic-gate 		if (krb5_is_krb_error(&inbuf))
1360*7c478bd9Sstevel@tonic-gate 			recv_error(context, &inbuf);
1361*7c478bd9Sstevel@tonic-gate 		if (retval = krb5_rd_priv(context, auth_context, &inbuf,
1362*7c478bd9Sstevel@tonic-gate 					  &outbuf, NULL)) {
1363*7c478bd9Sstevel@tonic-gate 			snprintf(buf, sizeof (buf),
1364*7c478bd9Sstevel@tonic-gate 		gettext("while decoding database block starting at offset %d"),
1365*7c478bd9Sstevel@tonic-gate 				received_size);
1366*7c478bd9Sstevel@tonic-gate 			com_err(progname, retval, buf);
1367*7c478bd9Sstevel@tonic-gate 			send_error(context, fd, retval, buf);
1368*7c478bd9Sstevel@tonic-gate 			krb5_free_data_contents(context, &inbuf);
1369*7c478bd9Sstevel@tonic-gate 			exit(1);
1370*7c478bd9Sstevel@tonic-gate 		}
1371*7c478bd9Sstevel@tonic-gate 		n = write(database_fd, outbuf.data, outbuf.length);
1372*7c478bd9Sstevel@tonic-gate 		if (n < 0) {
1373*7c478bd9Sstevel@tonic-gate 			snprintf(buf, sizeof (buf),
1374*7c478bd9Sstevel@tonic-gate 				gettext(
1375*7c478bd9Sstevel@tonic-gate "while writing database block starting at offset %d"),
1376*7c478bd9Sstevel@tonic-gate 				received_size);
1377*7c478bd9Sstevel@tonic-gate 			send_error(context, fd, errno, buf);
1378*7c478bd9Sstevel@tonic-gate 		} else if (n != outbuf.length) {
1379*7c478bd9Sstevel@tonic-gate 			snprintf(buf, sizeof (buf),
1380*7c478bd9Sstevel@tonic-gate 				gettext(
1381*7c478bd9Sstevel@tonic-gate "incomplete write while writing database block starting at\n"
1382*7c478bd9Sstevel@tonic-gate "offset %d (%d written, %d expected)"),
1383*7c478bd9Sstevel@tonic-gate 				received_size, n, outbuf.length);
1384*7c478bd9Sstevel@tonic-gate 			send_error(context, fd, KRB5KRB_ERR_GENERIC, buf);
1385*7c478bd9Sstevel@tonic-gate 		}
1386*7c478bd9Sstevel@tonic-gate 		received_size += outbuf.length;
1387*7c478bd9Sstevel@tonic-gate 		/* SUNWresync121: our krb5...contents sets length to 0 */
1388*7c478bd9Sstevel@tonic-gate 		krb5_free_data_contents(context, &inbuf);
1389*7c478bd9Sstevel@tonic-gate 		krb5_free_data_contents(context, &outbuf);
1390*7c478bd9Sstevel@tonic-gate 	}
1391*7c478bd9Sstevel@tonic-gate 	/*
1392*7c478bd9Sstevel@tonic-gate 	 * OK, we've seen the entire file.  Did we get too many bytes?
1393*7c478bd9Sstevel@tonic-gate 	 */
1394*7c478bd9Sstevel@tonic-gate 	if (received_size > database_size) {
1395*7c478bd9Sstevel@tonic-gate 		snprintf(buf, sizeof (buf),
1396*7c478bd9Sstevel@tonic-gate 		gettext("Received %d bytes, expected %d bytes for database file"),
1397*7c478bd9Sstevel@tonic-gate 			received_size, database_size);
1398*7c478bd9Sstevel@tonic-gate 		send_error(context, fd, KRB5KRB_ERR_GENERIC, buf);
1399*7c478bd9Sstevel@tonic-gate 	}
1400*7c478bd9Sstevel@tonic-gate 	/*
1401*7c478bd9Sstevel@tonic-gate 	 * Create message acknowledging number of bytes received, but
1402*7c478bd9Sstevel@tonic-gate 	 * don't send it until kdb5_util returns successfully.
1403*7c478bd9Sstevel@tonic-gate 	 */
1404*7c478bd9Sstevel@tonic-gate 	database_size = htonl(database_size);
1405*7c478bd9Sstevel@tonic-gate 	inbuf.data = (char *) &database_size;
1406*7c478bd9Sstevel@tonic-gate 	inbuf.length = sizeof(database_size);
1407*7c478bd9Sstevel@tonic-gate 	if (retval = krb5_mk_safe(context,auth_context,&inbuf,confmsg,NULL)) {
1408*7c478bd9Sstevel@tonic-gate 		com_err(progname, retval,
1409*7c478bd9Sstevel@tonic-gate 			gettext("while encoding # of receieved bytes"));
1410*7c478bd9Sstevel@tonic-gate 		send_error(context, fd, retval,
1411*7c478bd9Sstevel@tonic-gate 			   gettext("while encoding # of received bytes"));
1412*7c478bd9Sstevel@tonic-gate 		exit(1);
1413*7c478bd9Sstevel@tonic-gate 	}
1414*7c478bd9Sstevel@tonic-gate }
1415*7c478bd9Sstevel@tonic-gate 
1416*7c478bd9Sstevel@tonic-gate 
1417*7c478bd9Sstevel@tonic-gate void
1418*7c478bd9Sstevel@tonic-gate send_error(context, fd, err_code, err_text)
1419*7c478bd9Sstevel@tonic-gate     krb5_context context;
1420*7c478bd9Sstevel@tonic-gate     int	fd;
1421*7c478bd9Sstevel@tonic-gate     krb5_error_code	err_code;
1422*7c478bd9Sstevel@tonic-gate     char	*err_text;
1423*7c478bd9Sstevel@tonic-gate {
1424*7c478bd9Sstevel@tonic-gate 	krb5_error	error;
1425*7c478bd9Sstevel@tonic-gate 	const char	*text;
1426*7c478bd9Sstevel@tonic-gate 	krb5_data	outbuf;
1427*7c478bd9Sstevel@tonic-gate 	char		buf[1024];
1428*7c478bd9Sstevel@tonic-gate 
1429*7c478bd9Sstevel@tonic-gate 	memset((char *)&error, 0, sizeof(error));
1430*7c478bd9Sstevel@tonic-gate 	krb5_us_timeofday(context, &error.stime, &error.susec);
1431*7c478bd9Sstevel@tonic-gate 	error.server = server;
1432*7c478bd9Sstevel@tonic-gate 	error.client = client;
1433*7c478bd9Sstevel@tonic-gate 
1434*7c478bd9Sstevel@tonic-gate 	if (err_text)
1435*7c478bd9Sstevel@tonic-gate 		text = err_text;
1436*7c478bd9Sstevel@tonic-gate 	else
1437*7c478bd9Sstevel@tonic-gate 		text = error_message(err_code);
1438*7c478bd9Sstevel@tonic-gate 
1439*7c478bd9Sstevel@tonic-gate 	error.error = err_code - ERROR_TABLE_BASE_krb5;
1440*7c478bd9Sstevel@tonic-gate 	if (error.error > 127) {
1441*7c478bd9Sstevel@tonic-gate 		error.error = KRB_ERR_GENERIC;
1442*7c478bd9Sstevel@tonic-gate 		if (err_text) {
1443*7c478bd9Sstevel@tonic-gate 			sprintf(buf, "%s %s", error_message(err_code),
1444*7c478bd9Sstevel@tonic-gate 				err_text);
1445*7c478bd9Sstevel@tonic-gate 			text = buf;
1446*7c478bd9Sstevel@tonic-gate 		}
1447*7c478bd9Sstevel@tonic-gate 	}
1448*7c478bd9Sstevel@tonic-gate 	error.text.length = strlen(text) + 1;
1449*7c478bd9Sstevel@tonic-gate 	if (error.text.data = malloc(error.text.length)) {
1450*7c478bd9Sstevel@tonic-gate 		strcpy(error.text.data, text);
1451*7c478bd9Sstevel@tonic-gate 		if (!krb5_mk_error(context, &error, &outbuf)) {
1452*7c478bd9Sstevel@tonic-gate 			(void) krb5_write_message(context, (void *)&fd,&outbuf);
1453*7c478bd9Sstevel@tonic-gate 			krb5_free_data_contents(context, &outbuf);
1454*7c478bd9Sstevel@tonic-gate 		}
1455*7c478bd9Sstevel@tonic-gate 		free(error.text.data);
1456*7c478bd9Sstevel@tonic-gate 	}
1457*7c478bd9Sstevel@tonic-gate }
1458*7c478bd9Sstevel@tonic-gate 
1459*7c478bd9Sstevel@tonic-gate void
1460*7c478bd9Sstevel@tonic-gate recv_error(context, inbuf)
1461*7c478bd9Sstevel@tonic-gate     krb5_context context;
1462*7c478bd9Sstevel@tonic-gate     krb5_data	*inbuf;
1463*7c478bd9Sstevel@tonic-gate {
1464*7c478bd9Sstevel@tonic-gate 	krb5_error	*error;
1465*7c478bd9Sstevel@tonic-gate 	krb5_error_code	retval;
1466*7c478bd9Sstevel@tonic-gate 
1467*7c478bd9Sstevel@tonic-gate 	if (retval = krb5_rd_error(context, inbuf, &error)) {
1468*7c478bd9Sstevel@tonic-gate 		com_err(progname, retval,
1469*7c478bd9Sstevel@tonic-gate 			gettext("while decoding error packet from client"));
1470*7c478bd9Sstevel@tonic-gate 		exit(1);
1471*7c478bd9Sstevel@tonic-gate 	}
1472*7c478bd9Sstevel@tonic-gate 	if (error->error == KRB_ERR_GENERIC) {
1473*7c478bd9Sstevel@tonic-gate 		if (error->text.data)
1474*7c478bd9Sstevel@tonic-gate 			fprintf(stderr,
1475*7c478bd9Sstevel@tonic-gate 				gettext("Generic remote error: %s\n"),
1476*7c478bd9Sstevel@tonic-gate 				error->text.data);
1477*7c478bd9Sstevel@tonic-gate 	} else if (error->error) {
1478*7c478bd9Sstevel@tonic-gate 		com_err(progname, error->error + ERROR_TABLE_BASE_krb5,
1479*7c478bd9Sstevel@tonic-gate 			gettext("signalled from server"));
1480*7c478bd9Sstevel@tonic-gate 		if (error->text.data)
1481*7c478bd9Sstevel@tonic-gate 			fprintf(stderr,
1482*7c478bd9Sstevel@tonic-gate 				gettext("Error text from client: %s\n"),
1483*7c478bd9Sstevel@tonic-gate 				error->text.data);
1484*7c478bd9Sstevel@tonic-gate 	}
1485*7c478bd9Sstevel@tonic-gate 	krb5_free_error(context, error);
1486*7c478bd9Sstevel@tonic-gate 	exit(1);
1487*7c478bd9Sstevel@tonic-gate }
1488*7c478bd9Sstevel@tonic-gate 
1489*7c478bd9Sstevel@tonic-gate void
1490*7c478bd9Sstevel@tonic-gate load_database(context, kdb5_util, database_file_name)
1491*7c478bd9Sstevel@tonic-gate     krb5_context context;
1492*7c478bd9Sstevel@tonic-gate     char *kdb5_util;
1493*7c478bd9Sstevel@tonic-gate     char *database_file_name;
1494*7c478bd9Sstevel@tonic-gate {
1495*7c478bd9Sstevel@tonic-gate 	static char	*edit_av[10];
1496*7c478bd9Sstevel@tonic-gate 	int	error_ret, save_stderr;
1497*7c478bd9Sstevel@tonic-gate 	int	child_pid;
1498*7c478bd9Sstevel@tonic-gate 	int 	count;
1499*7c478bd9Sstevel@tonic-gate 	int	waitb;
1500*7c478bd9Sstevel@tonic-gate 	krb5_error_code	retval;
1501*7c478bd9Sstevel@tonic-gate 	kdb_log_context	*log_ctx;
1502*7c478bd9Sstevel@tonic-gate 
1503*7c478bd9Sstevel@tonic-gate 	if (debug)
1504*7c478bd9Sstevel@tonic-gate 		printf(gettext("calling kdb5_util to load database\n"));
1505*7c478bd9Sstevel@tonic-gate 
1506*7c478bd9Sstevel@tonic-gate 	log_ctx = context->kdblog_context;
1507*7c478bd9Sstevel@tonic-gate 
1508*7c478bd9Sstevel@tonic-gate 	edit_av[0] = kdb5_util;
1509*7c478bd9Sstevel@tonic-gate 	count = 1;
1510*7c478bd9Sstevel@tonic-gate 	if (realm) {
1511*7c478bd9Sstevel@tonic-gate 		edit_av[count++] = "-r";
1512*7c478bd9Sstevel@tonic-gate 		edit_av[count++] = realm;
1513*7c478bd9Sstevel@tonic-gate 	}
1514*7c478bd9Sstevel@tonic-gate 	edit_av[count++] = "load";
1515*7c478bd9Sstevel@tonic-gate 	if (kerb_database) {
1516*7c478bd9Sstevel@tonic-gate 		edit_av[count++] = "-d";
1517*7c478bd9Sstevel@tonic-gate 		edit_av[count++] = kerb_database;
1518*7c478bd9Sstevel@tonic-gate 	}
1519*7c478bd9Sstevel@tonic-gate 
1520*7c478bd9Sstevel@tonic-gate 	if (log_ctx && (log_ctx->iproprole == IPROP_SLAVE)) {
1521*7c478bd9Sstevel@tonic-gate 		edit_av[count++] = "-i";
1522*7c478bd9Sstevel@tonic-gate 	}
1523*7c478bd9Sstevel@tonic-gate 	edit_av[count++] = database_file_name;
1524*7c478bd9Sstevel@tonic-gate 	edit_av[count++] = NULL;
1525*7c478bd9Sstevel@tonic-gate 
1526*7c478bd9Sstevel@tonic-gate 	switch(child_pid = fork()) {
1527*7c478bd9Sstevel@tonic-gate 	case -1:
1528*7c478bd9Sstevel@tonic-gate 		com_err(progname, errno, gettext("while trying to fork %s"),
1529*7c478bd9Sstevel@tonic-gate 			kdb5_util);
1530*7c478bd9Sstevel@tonic-gate 		exit(1);
1531*7c478bd9Sstevel@tonic-gate 		/*NOTREACHED*/
1532*7c478bd9Sstevel@tonic-gate 	case 0:
1533*7c478bd9Sstevel@tonic-gate 		if (!debug) {
1534*7c478bd9Sstevel@tonic-gate 			save_stderr = dup(2);
1535*7c478bd9Sstevel@tonic-gate 			close(0);
1536*7c478bd9Sstevel@tonic-gate 			close(1);
1537*7c478bd9Sstevel@tonic-gate 			close(2);
1538*7c478bd9Sstevel@tonic-gate 			open("/dev/null", O_RDWR);
1539*7c478bd9Sstevel@tonic-gate 			dup(0);
1540*7c478bd9Sstevel@tonic-gate 			dup(0);
1541*7c478bd9Sstevel@tonic-gate 		}
1542*7c478bd9Sstevel@tonic-gate 
1543*7c478bd9Sstevel@tonic-gate 		execv(kdb5_util, edit_av);
1544*7c478bd9Sstevel@tonic-gate 		retval = errno;
1545*7c478bd9Sstevel@tonic-gate 		if (!debug)
1546*7c478bd9Sstevel@tonic-gate 			dup2(save_stderr, 2);
1547*7c478bd9Sstevel@tonic-gate 		com_err(progname, retval, gettext("while trying to exec %s"),
1548*7c478bd9Sstevel@tonic-gate 			kdb5_util);
1549*7c478bd9Sstevel@tonic-gate 		_exit(1);
1550*7c478bd9Sstevel@tonic-gate 		/*NOTREACHED*/
1551*7c478bd9Sstevel@tonic-gate 	default:
1552*7c478bd9Sstevel@tonic-gate 		if (debug)
1553*7c478bd9Sstevel@tonic-gate 		    printf(gettext("Child PID is %d\n"), child_pid);
1554*7c478bd9Sstevel@tonic-gate 		if (wait(&waitb) < 0) {
1555*7c478bd9Sstevel@tonic-gate 			com_err(progname, errno, gettext("while waiting for %s"),
1556*7c478bd9Sstevel@tonic-gate 				kdb5_util);
1557*7c478bd9Sstevel@tonic-gate 			exit(1);
1558*7c478bd9Sstevel@tonic-gate 		}
1559*7c478bd9Sstevel@tonic-gate 	}
1560*7c478bd9Sstevel@tonic-gate 
1561*7c478bd9Sstevel@tonic-gate 	if ((error_ret = WEXITSTATUS(waitb)) != 0) {
1562*7c478bd9Sstevel@tonic-gate 		com_err(progname, 0,
1563*7c478bd9Sstevel@tonic-gate 		    gettext("%s returned a bad exit status (%d)"), kdb5_util,
1564*7c478bd9Sstevel@tonic-gate 		    error_ret);
1565*7c478bd9Sstevel@tonic-gate 		exit(1);
1566*7c478bd9Sstevel@tonic-gate 	}
1567*7c478bd9Sstevel@tonic-gate 	return;
1568*7c478bd9Sstevel@tonic-gate }
1569