xref: /onnv-gate/usr/src/cmd/krb5/slave/kpropd.c (revision 9033:9ae57594b26c)
10Sstevel@tonic-gate /*
28714SMark.Phalan@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
30Sstevel@tonic-gate  * Use is subject to license terms.
40Sstevel@tonic-gate  *
50Sstevel@tonic-gate  * All rights reserved.
60Sstevel@tonic-gate  *
70Sstevel@tonic-gate  * Export of this software from the United States of America may require
80Sstevel@tonic-gate  * a specific license from the United States Government.  It is the
90Sstevel@tonic-gate  * responsibility of any person or organization contemplating export to
100Sstevel@tonic-gate  * obtain such a license before exporting.
110Sstevel@tonic-gate  *
120Sstevel@tonic-gate  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
130Sstevel@tonic-gate  * distribute this software and its documentation for any purpose and
140Sstevel@tonic-gate  * without fee is hereby granted, provided that the above copyright
150Sstevel@tonic-gate  * notice appear in all copies and that both that copyright notice and
160Sstevel@tonic-gate  * this permission notice appear in supporting documentation, and that
170Sstevel@tonic-gate  * the name of FundsXpress. not be used in advertising or publicity pertaining
180Sstevel@tonic-gate  * to distribution of the software without specific, written prior
190Sstevel@tonic-gate  * permission.  FundsXpress makes no representations about the suitability of
200Sstevel@tonic-gate  * this software for any purpose.  It is provided "as is" without express
210Sstevel@tonic-gate  * or implied warranty.
220Sstevel@tonic-gate  *
230Sstevel@tonic-gate  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
240Sstevel@tonic-gate  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
250Sstevel@tonic-gate  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
260Sstevel@tonic-gate  */
270Sstevel@tonic-gate 
280Sstevel@tonic-gate /*
290Sstevel@tonic-gate  * slave/kpropd.c
300Sstevel@tonic-gate  *
310Sstevel@tonic-gate  * Copyright 1990,1991 by the Massachusetts Institute of Technology.
320Sstevel@tonic-gate  * All Rights Reserved.
330Sstevel@tonic-gate  *
340Sstevel@tonic-gate  * Export of this software from the United States of America may
350Sstevel@tonic-gate  *   require a specific license from the United States Government.
360Sstevel@tonic-gate  *   It is the responsibility of any person or organization contemplating
370Sstevel@tonic-gate  *   export to obtain such a license before exporting.
380Sstevel@tonic-gate  *
390Sstevel@tonic-gate  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
400Sstevel@tonic-gate  * distribute this software and its documentation for any purpose and
410Sstevel@tonic-gate  * without fee is hereby granted, provided that the above copyright
420Sstevel@tonic-gate  * notice appear in all copies and that both that copyright notice and
430Sstevel@tonic-gate  * this permission notice appear in supporting documentation, and that
440Sstevel@tonic-gate  * the name of M.I.T. not be used in advertising or publicity pertaining
450Sstevel@tonic-gate  * to distribution of the software without specific, written prior
460Sstevel@tonic-gate  * permission.  Furthermore if you modify this software you must label
470Sstevel@tonic-gate  * your software as modified software and not distribute it in such a
480Sstevel@tonic-gate  * fashion that it might be confused with the original M.I.T. software.
490Sstevel@tonic-gate  * M.I.T. makes no representations about the suitability of
500Sstevel@tonic-gate  * this software for any purpose.  It is provided "as is" without express
510Sstevel@tonic-gate  * or implied warranty.
520Sstevel@tonic-gate  *
530Sstevel@tonic-gate  *
540Sstevel@tonic-gate  * XXX We need to modify the protocol so that an acknowledge is set
550Sstevel@tonic-gate  * after each block, instead after the entire series is sent over.
560Sstevel@tonic-gate  * The reason for this is so that error packets can get interpreted
570Sstevel@tonic-gate  * right away.  If you don't do this, the sender may never get the
580Sstevel@tonic-gate  * error packet, because it will die an EPIPE trying to complete the
590Sstevel@tonic-gate  * write...
600Sstevel@tonic-gate  */
610Sstevel@tonic-gate 
622881Smp153739 
630Sstevel@tonic-gate #include <stdio.h>
640Sstevel@tonic-gate #include <ctype.h>
650Sstevel@tonic-gate #include <sys/file.h>
660Sstevel@tonic-gate #include <signal.h>
670Sstevel@tonic-gate #include <string.h>
680Sstevel@tonic-gate #include <fcntl.h>
690Sstevel@tonic-gate #include <sys/types.h>
700Sstevel@tonic-gate #include <sys/time.h>
710Sstevel@tonic-gate #include <sys/stat.h>
720Sstevel@tonic-gate #include <sys/socket.h>
730Sstevel@tonic-gate #include <sys/wait.h>
740Sstevel@tonic-gate #include <netinet/in.h>
750Sstevel@tonic-gate #include <arpa/inet.h>
760Sstevel@tonic-gate #include <sys/param.h>
770Sstevel@tonic-gate #include <netdb.h>
780Sstevel@tonic-gate #include <syslog.h>
790Sstevel@tonic-gate #include <libintl.h>
800Sstevel@tonic-gate #include <locale.h>
810Sstevel@tonic-gate #include <k5-int.h>
820Sstevel@tonic-gate #include <socket-utils.h>
830Sstevel@tonic-gate #include "com_err.h"
840Sstevel@tonic-gate #include <errno.h>
850Sstevel@tonic-gate 
860Sstevel@tonic-gate #include "kprop.h"
870Sstevel@tonic-gate #include <iprop_hdr.h>
880Sstevel@tonic-gate #include "iprop.h"
890Sstevel@tonic-gate #include <kadm5/admin.h>
900Sstevel@tonic-gate #include <kdb/kdb_log.h>
910Sstevel@tonic-gate 
926426Smp153739 /* Solaris Kerberos */
936426Smp153739 #include <libgen.h>
946426Smp153739 
950Sstevel@tonic-gate #define SYSLOG_CLASS LOG_DAEMON
96*9033SPeter.Shoults@Sun.COM #define	INITIAL_TIMER 10
970Sstevel@tonic-gate 
980Sstevel@tonic-gate char *poll_time = NULL;
990Sstevel@tonic-gate char *def_realm = NULL;
1000Sstevel@tonic-gate boolean_t runonce = B_FALSE;
1010Sstevel@tonic-gate 
1020Sstevel@tonic-gate /*
103*9033SPeter.Shoults@Sun.COM  * Global fd to close upon alarm time-out.
104*9033SPeter.Shoults@Sun.COM  */
105*9033SPeter.Shoults@Sun.COM volatile int gfd = -1;
106*9033SPeter.Shoults@Sun.COM 
107*9033SPeter.Shoults@Sun.COM /*
1080Sstevel@tonic-gate  * This struct simulates the use of _kadm5_server_handle_t
1090Sstevel@tonic-gate  */
1100Sstevel@tonic-gate typedef struct _kadm5_iprop_handle_t {
1110Sstevel@tonic-gate 	krb5_ui_4	magic_number;
1120Sstevel@tonic-gate 	krb5_ui_4	struct_version;
1130Sstevel@tonic-gate 	krb5_ui_4	api_version;
1140Sstevel@tonic-gate 	char 		*cache_name;
1150Sstevel@tonic-gate 	int		destroy_cache;
1160Sstevel@tonic-gate 	CLIENT		*clnt;
1170Sstevel@tonic-gate 	krb5_context	context;
1180Sstevel@tonic-gate 	kadm5_config_params params;
1190Sstevel@tonic-gate 	struct _kadm5_iprop_handle_t *lhandle;
1200Sstevel@tonic-gate } *kadm5_iprop_handle_t;
1210Sstevel@tonic-gate 
1220Sstevel@tonic-gate static char *kprop_version = KPROP_PROT_VERSION;
1230Sstevel@tonic-gate 
1240Sstevel@tonic-gate char	*progname;
1250Sstevel@tonic-gate int     debug = 0;
1260Sstevel@tonic-gate char	*srvtab = 0;
1270Sstevel@tonic-gate int	standalone = 0;
1280Sstevel@tonic-gate 
1290Sstevel@tonic-gate krb5_principal	server;		/* This is our server principal name */
1300Sstevel@tonic-gate krb5_principal	client;		/* This is who we're talking to */
1310Sstevel@tonic-gate krb5_context kpropd_context;
1320Sstevel@tonic-gate krb5_auth_context auth_context;
1330Sstevel@tonic-gate char	*realm = NULL;		/* Our realm */
1340Sstevel@tonic-gate char	*file = KPROPD_DEFAULT_FILE;
1350Sstevel@tonic-gate char	*temp_file_name;
1360Sstevel@tonic-gate char	*kdb5_util = KPROPD_DEFAULT_KDB5_UTIL;
1370Sstevel@tonic-gate char	*kerb_database = NULL;
1380Sstevel@tonic-gate char	*acl_file_name = KPROPD_ACL_FILE;
1390Sstevel@tonic-gate 
1400Sstevel@tonic-gate krb5_address	sender_addr;
1410Sstevel@tonic-gate krb5_address	receiver_addr;
1420Sstevel@tonic-gate short 		port = 0;
1430Sstevel@tonic-gate 
1440Sstevel@tonic-gate void	PRS
1450Sstevel@tonic-gate 	 (int, char**);
1460Sstevel@tonic-gate int	do_standalone
1470Sstevel@tonic-gate 	 (iprop_role iproprole);
1480Sstevel@tonic-gate void	doit
1492881Smp153739 	(int);
1500Sstevel@tonic-gate krb5_error_code	do_iprop(kdb_log_context *log_ctx);
1510Sstevel@tonic-gate 
1528714SMark.Phalan@Sun.COM /* Solaris Kerberos */
1530Sstevel@tonic-gate void	kerberos_authenticate
1542881Smp153739 	(krb5_context,
1550Sstevel@tonic-gate 		   int,
1560Sstevel@tonic-gate 		   krb5_principal *,
1570Sstevel@tonic-gate 		   krb5_enctype *,
1588714SMark.Phalan@Sun.COM 		   struct sockaddr_storage *);
1590Sstevel@tonic-gate krb5_boolean authorized_principal
1602881Smp153739 	(krb5_context,
1610Sstevel@tonic-gate     		   krb5_principal,
1620Sstevel@tonic-gate 		   krb5_enctype);
1630Sstevel@tonic-gate void	recv_database
1642881Smp153739 	(krb5_context,
1650Sstevel@tonic-gate 		   int,
1660Sstevel@tonic-gate 		   int,
1670Sstevel@tonic-gate 		   krb5_data *);
1680Sstevel@tonic-gate void	load_database
1692881Smp153739 	(krb5_context,
1700Sstevel@tonic-gate     		   char *,
1710Sstevel@tonic-gate     		   char *);
1720Sstevel@tonic-gate void	send_error
1732881Smp153739 	(krb5_context,
1740Sstevel@tonic-gate     		   int,
1750Sstevel@tonic-gate 		   krb5_error_code,
1760Sstevel@tonic-gate     		   char	*);
1770Sstevel@tonic-gate void	recv_error
1782881Smp153739 	(krb5_context,
1790Sstevel@tonic-gate     		   krb5_data *);
1800Sstevel@tonic-gate int	convert_polltime
1810Sstevel@tonic-gate 	(char *);
1820Sstevel@tonic-gate unsigned int	backoff_from_master
1830Sstevel@tonic-gate 	(int *);
1840Sstevel@tonic-gate 
usage()1850Sstevel@tonic-gate static void usage()
1860Sstevel@tonic-gate {
1870Sstevel@tonic-gate 	fprintf(stderr,
1880Sstevel@tonic-gate 		gettext("\nUsage: %s\n"), /* progname may be a long pathname */
1890Sstevel@tonic-gate 		progname);
1900Sstevel@tonic-gate 
1910Sstevel@tonic-gate 	fprintf(stderr,
1920Sstevel@tonic-gate 		gettext("\t[-r realm] [-s srvtab] [-dS] [-f slave_file]\n"));
1930Sstevel@tonic-gate 
1940Sstevel@tonic-gate 	fprintf(stderr,
1950Sstevel@tonic-gate 		gettext("\t[-F kerberos_db_file ] [-p kdb5_util_pathname]\n"));
1960Sstevel@tonic-gate 
1970Sstevel@tonic-gate 	fprintf(stderr, gettext("\t[-P port] [-a acl_file]\n"));
1980Sstevel@tonic-gate 
1990Sstevel@tonic-gate 	exit(1);
2000Sstevel@tonic-gate }
2010Sstevel@tonic-gate 
2020Sstevel@tonic-gate int
main(argc,argv)2030Sstevel@tonic-gate main(argc, argv)
2040Sstevel@tonic-gate 	int	argc;
2050Sstevel@tonic-gate 	char	**argv;
2060Sstevel@tonic-gate {
2070Sstevel@tonic-gate 	krb5_error_code retval;
2080Sstevel@tonic-gate 	int ret = 0;
2090Sstevel@tonic-gate 	kdb_log_context	*log_ctx;
2104960Swillf 	int iprop_supported;
2116426Smp153739 	krb5_boolean is_master = FALSE;
2120Sstevel@tonic-gate 
2130Sstevel@tonic-gate 	PRS(argc, argv);
2140Sstevel@tonic-gate 
2150Sstevel@tonic-gate 	log_ctx = kpropd_context->kdblog_context;
2160Sstevel@tonic-gate 
2170Sstevel@tonic-gate 	if (log_ctx && (log_ctx->iproprole == IPROP_SLAVE)) {
2180Sstevel@tonic-gate 		/*
2190Sstevel@tonic-gate 		 * We wanna do iprop !
2200Sstevel@tonic-gate 		 */
2214960Swillf 		retval = krb5_db_supports_iprop(kpropd_context,
2224960Swillf 		    &iprop_supported);
2234960Swillf 		if (retval) {
2246426Smp153739 			/* Solaris Kerberos: Keep error messages consistent */
2254960Swillf 			com_err(progname, retval,
2266426Smp153739 				gettext("while determining if dbmodule plugin "
2276426Smp153739 					    "supports iprop"));
2284960Swillf 			exit(1);
2294960Swillf 		}
2304960Swillf 		if (!iprop_supported) {
2316426Smp153739 			/* Solaris Kerberos: Keep error messages consistent */
2326426Smp153739 			com_err(progname, 0,
2334960Swillf 				gettext("Current dbmodule plugin does not support "
2346426Smp153739 				    "iprop"));
2356426Smp153739 			exit(1);
2366426Smp153739 		}
2376426Smp153739 
2386426Smp153739 		/*
2396426Smp153739 		 * Solaris Kerberos:
2406426Smp153739 		 * Ensure that kpropd is only run on a slave
2416426Smp153739 		 */
2426426Smp153739 		if (retval = kadm5_is_master(kpropd_context, def_realm,
2436426Smp153739 		    &is_master)) {
2446426Smp153739 			com_err(progname, retval,
2456426Smp153739 			    gettext("while trying to determine whether host is "
2466426Smp153739 			    "master KDC for realm %s"), def_realm);
2476426Smp153739 			exit(1);
2486426Smp153739 		}
2496426Smp153739 
2506426Smp153739 		if (is_master == TRUE) {
2516426Smp153739 			char *master = NULL;
2526426Smp153739 			kadm5_get_master(kpropd_context, def_realm, &master);
2536426Smp153739 
2546426Smp153739 			com_err(progname, 0,
2556426Smp153739 			    gettext("%s is the master KDC for the realm %s. "
2566426Smp153739 			    "%s can only be run on a slave KDC"),
2576426Smp153739 			    master ? master : "unknown", def_realm, progname);
2584960Swillf 			exit(1);
2594960Swillf 		}
2604960Swillf 
2610Sstevel@tonic-gate 		retval = do_iprop(log_ctx);
2620Sstevel@tonic-gate 		if (retval) {
2636426Smp153739 			/* Solaris Kerberos: Keep error messages consistent */
2640Sstevel@tonic-gate 			com_err(progname, retval,
2656426Smp153739 			    gettext("while doing iprop"));
2660Sstevel@tonic-gate 			exit(1);
2670Sstevel@tonic-gate 		}
2680Sstevel@tonic-gate 
2690Sstevel@tonic-gate 	} else {
2706426Smp153739 
2716426Smp153739 		/*
2726426Smp153739 		 * Solaris Kerberos:
2736426Smp153739 		 * Ensure that the kpropd.acl file exists and contains at least
2746426Smp153739 		 * 1 entry.
2756426Smp153739 		 */
2766426Smp153739 		FILE *tmp_acl_file;
2776426Smp153739 		int seen_file = 0;
2786426Smp153739 		char buf[1024];
2796426Smp153739 
2806426Smp153739 		tmp_acl_file = fopen(acl_file_name, "r");
2816426Smp153739 		if (!tmp_acl_file) {
2826426Smp153739 			com_err(progname, errno,
2836426Smp153739 			    gettext("while opening acl file %s"),
2846426Smp153739 			    acl_file_name);
2856426Smp153739 			exit(1);
2866426Smp153739 		}
2876426Smp153739 
2886426Smp153739 		while (!feof(tmp_acl_file) && !seen_file ) {
2896426Smp153739 			if (!fgets(buf, sizeof(buf), tmp_acl_file))
2906426Smp153739 				break;
2916426Smp153739 
2926426Smp153739 			if (buf[0] != '#' && !isspace(buf[0]))
2936426Smp153739 				seen_file = 1;
2946426Smp153739 		}
2956426Smp153739 		if (!seen_file) {
2966426Smp153739 			com_err(progname, 0,
2976426Smp153739 			    gettext("No entries found in %s. Can't "
2986426Smp153739 			    "authorize propagation requests"), acl_file_name);
2996426Smp153739 			exit(1);
3006426Smp153739 		}
3016426Smp153739 		fclose(tmp_acl_file);
3026426Smp153739 
3030Sstevel@tonic-gate 		if (standalone)
3040Sstevel@tonic-gate 			ret = do_standalone(IPROP_NULL);
3050Sstevel@tonic-gate 		else
3060Sstevel@tonic-gate 			doit(0);
3070Sstevel@tonic-gate 	}
3080Sstevel@tonic-gate 
3090Sstevel@tonic-gate 	exit(ret);
3100Sstevel@tonic-gate }
3110Sstevel@tonic-gate 
resync_alarm(int sn)312*9033SPeter.Shoults@Sun.COM void resync_alarm(int sn)
313*9033SPeter.Shoults@Sun.COM {
314*9033SPeter.Shoults@Sun.COM 	close(gfd);
315*9033SPeter.Shoults@Sun.COM 	if (debug)
316*9033SPeter.Shoults@Sun.COM 		fprintf(stderr, gettext("resync_alarm: closing fd: %d\n"), gfd);
317*9033SPeter.Shoults@Sun.COM 	gfd = -1;
318*9033SPeter.Shoults@Sun.COM }
319*9033SPeter.Shoults@Sun.COM 
do_standalone(iprop_role iproprole)3200Sstevel@tonic-gate int do_standalone(iprop_role iproprole)
3210Sstevel@tonic-gate {
3220Sstevel@tonic-gate     struct	linger linger;
3230Sstevel@tonic-gate     struct	servent *sp;
3240Sstevel@tonic-gate     int	finet, fromlen, s;
3250Sstevel@tonic-gate     int	on = 1;
3260Sstevel@tonic-gate     int	ret, status = 0;
3270Sstevel@tonic-gate     struct	sockaddr_in6 sin6 = { AF_INET6 };
3280Sstevel@tonic-gate     int sin6_size = sizeof (sin6);
329*9033SPeter.Shoults@Sun.COM     /*
330*9033SPeter.Shoults@Sun.COM      * Timer for accept/read calls, in case of network type errors.
331*9033SPeter.Shoults@Sun.COM      */
332*9033SPeter.Shoults@Sun.COM     int backoff_timer = INITIAL_TIMER;
333*9033SPeter.Shoults@Sun.COM 
334*9033SPeter.Shoults@Sun.COM retry:
3350Sstevel@tonic-gate 
3360Sstevel@tonic-gate     /* listen for either ipv4 or ipv6 */
3370Sstevel@tonic-gate     finet = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP);
3380Sstevel@tonic-gate     if (finet < 0 ) {
3390Sstevel@tonic-gate 	com_err(progname, errno, gettext("while obtaining socket"));
3400Sstevel@tonic-gate 	exit(1);
3410Sstevel@tonic-gate     }
3420Sstevel@tonic-gate 
3430Sstevel@tonic-gate     if(!port) {
3440Sstevel@tonic-gate 	sp = getservbyname(KPROP_SERVICE, "tcp");
3450Sstevel@tonic-gate 	if (sp == NULL) {
3460Sstevel@tonic-gate 	    com_err(progname, 0, gettext("%s/tcp: unknown service"),
3470Sstevel@tonic-gate 		    KPROP_SERVICE);
3480Sstevel@tonic-gate 	    exit(1);
3490Sstevel@tonic-gate 	}
3500Sstevel@tonic-gate 	sin6.sin6_port = sp->s_port;
3510Sstevel@tonic-gate     } else
3520Sstevel@tonic-gate 	sin6.sin6_port = port;
3530Sstevel@tonic-gate 
3540Sstevel@tonic-gate     /*
3550Sstevel@tonic-gate      * We need to close the socket immediately if iprop is enabled,
3560Sstevel@tonic-gate      * since back-to-back full resyncs are possible, so we do not
3570Sstevel@tonic-gate      * linger around for too long
3580Sstevel@tonic-gate      */
3590Sstevel@tonic-gate     if (iproprole == IPROP_SLAVE) {
3600Sstevel@tonic-gate 	    if (setsockopt(finet, SOL_SOCKET, SO_REUSEADDR,
3610Sstevel@tonic-gate 			(char *)&on, sizeof(on)) < 0)
3620Sstevel@tonic-gate 		    com_err(progname, errno,
3636426Smp153739 			    gettext("while setting socket option (SO_REUSEADDR)"));
3640Sstevel@tonic-gate 	    linger.l_onoff = 1;
3650Sstevel@tonic-gate 	    linger.l_linger = 2;
3660Sstevel@tonic-gate 	    if (setsockopt(finet, SOL_SOCKET, SO_LINGER,
3670Sstevel@tonic-gate 			(void *)&linger, sizeof(linger)) < 0)
3680Sstevel@tonic-gate 		    com_err(progname, errno,
3696426Smp153739 			    gettext("while setting socket option (SO_LINGER)"));
370*9033SPeter.Shoults@Sun.COM 	    /*
371*9033SPeter.Shoults@Sun.COM 	     * We also want to set a timer so that the slave is not waiting
372*9033SPeter.Shoults@Sun.COM 	     * until infinity for an update from the master.
373*9033SPeter.Shoults@Sun.COM 	     */
374*9033SPeter.Shoults@Sun.COM 	    gfd = finet;
375*9033SPeter.Shoults@Sun.COM 	    signal(SIGALRM, resync_alarm);
376*9033SPeter.Shoults@Sun.COM 	    if (debug) {
377*9033SPeter.Shoults@Sun.COM 		fprintf(stderr, "do_standalone: setting resync alarm to %d\n",
378*9033SPeter.Shoults@Sun.COM 		    backoff_timer);
379*9033SPeter.Shoults@Sun.COM 	    }
380*9033SPeter.Shoults@Sun.COM 	    if (alarm(backoff_timer) != 0) {
381*9033SPeter.Shoults@Sun.COM 		if (debug) {
382*9033SPeter.Shoults@Sun.COM 		    fprintf(stderr,
383*9033SPeter.Shoults@Sun.COM 			gettext("%s: alarm already set\n"), progname);
384*9033SPeter.Shoults@Sun.COM 		}
385*9033SPeter.Shoults@Sun.COM 	    }
386*9033SPeter.Shoults@Sun.COM 	    backoff_timer *= 2;
3870Sstevel@tonic-gate     }
3880Sstevel@tonic-gate     if ((ret = bind(finet, (struct sockaddr *)&sin6, sizeof(sin6))) < 0) {
3890Sstevel@tonic-gate 	if (debug) {
3900Sstevel@tonic-gate 	    on = 1;
3910Sstevel@tonic-gate 	    fprintf(stderr,
3920Sstevel@tonic-gate 		    gettext("%s: attempting to rebind socket "
3930Sstevel@tonic-gate 		    "with SO_REUSEADDR\n"), progname);
3940Sstevel@tonic-gate 	    if (setsockopt(finet, SOL_SOCKET, SO_REUSEADDR,
3950Sstevel@tonic-gate 			(char *)&on, sizeof(on)) < 0) {
3960Sstevel@tonic-gate 		com_err(progname, errno,
3976426Smp153739 			gettext("while setting socket option (SO_REUSEADDR)"));
3980Sstevel@tonic-gate 	    }
3990Sstevel@tonic-gate 	    ret = bind(finet, (struct sockaddr *) &sin6, sizeof(sin6));
4002881Smp153739 	    }
4010Sstevel@tonic-gate 
4022881Smp153739 	    if (ret < 0) {
4036426Smp153739 	/*
4046426Smp153739 	 * Solaris Kerberos:
4056426Smp153739 	 * com_err will print the err msg associated with errno
4066426Smp153739 	 */
4076426Smp153739 #if 0
4082881Smp153739 		perror(gettext("bind"));
4096426Smp153739 #endif
4102881Smp153739 		com_err(progname, errno,
4112881Smp153739 		    gettext("while binding listener socket"));
4122881Smp153739 		exit(1);
4132881Smp153739 	    }
4142881Smp153739 	}
4156426Smp153739 	if (!debug && (iproprole != IPROP_SLAVE)) {
4166426Smp153739 	/* Solaris Kerberos: Indicate where further messages will be sent */
4176426Smp153739 		fprintf(stderr,
4186426Smp153739 		    gettext("%s: Logging to SYSLOG with LOG_DAEMON facility\n"),
4196426Smp153739 		    progname);
4206426Smp153739 		if (daemon(1, 0)) {
4216426Smp153739 			com_err(progname, errno, gettext("while daemonizing"));
4226426Smp153739 			exit(1);
4236426Smp153739 		}
4246426Smp153739 		rem_default_com_err_hook();
4256426Smp153739 	}
4266426Smp153739 
4270Sstevel@tonic-gate #ifdef PID_FILE
4282881Smp153739 	if ((pidfile = fopen(PID_FILE, "w")) != NULL) {
4292881Smp153739 		fprintf(pidfile, gettext("%d\n"), getpid());
4302881Smp153739 		fclose(pidfile);
4312881Smp153739 	} else
4322881Smp153739 		com_err(progname, errno,
4330Sstevel@tonic-gate 		gettext("while opening pid file %s for writing"),
4340Sstevel@tonic-gate 		PID_FILE);
4350Sstevel@tonic-gate #endif
4362881Smp153739 	if (listen(finet, 5) < 0) {
4376426Smp153739 		/* Solaris Kerberos: Keep error messages consistent */
4386426Smp153739 		com_err(progname, errno, gettext("while listening on socket"));
4392881Smp153739 		exit(1);
4402881Smp153739 	}
4412881Smp153739 	while (1) {
4422881Smp153739 		int child_pid;
4430Sstevel@tonic-gate 
4442881Smp153739 		s = accept(finet, (struct sockaddr *) &sin6, &sin6_size);
4450Sstevel@tonic-gate 
4462881Smp153739 		if (s < 0) {
447*9033SPeter.Shoults@Sun.COM 			int e = errno;
448*9033SPeter.Shoults@Sun.COM 			if (e != EINTR) {
449*9033SPeter.Shoults@Sun.COM 				/*
450*9033SPeter.Shoults@Sun.COM 				 * Solaris Kerberos: Keep error messages
451*9033SPeter.Shoults@Sun.COM 				 * consistent
452*9033SPeter.Shoults@Sun.COM 				 */
453*9033SPeter.Shoults@Sun.COM 				com_err(progname, e,
454*9033SPeter.Shoults@Sun.COM 				    gettext("while accepting connection"));
455*9033SPeter.Shoults@Sun.COM 				backoff_timer = INITIAL_TIMER;
4566426Smp153739 			}
457*9033SPeter.Shoults@Sun.COM 			/*
458*9033SPeter.Shoults@Sun.COM 			 * If we got EBADF, an alarm signal handler closed
459*9033SPeter.Shoults@Sun.COM 			 * the file descriptor on us.
460*9033SPeter.Shoults@Sun.COM 			 */
461*9033SPeter.Shoults@Sun.COM 			if (e != EBADF)
462*9033SPeter.Shoults@Sun.COM 				close(finet);
463*9033SPeter.Shoults@Sun.COM 			/*
464*9033SPeter.Shoults@Sun.COM 			 * An alarm could have been set and the fd closed, we
465*9033SPeter.Shoults@Sun.COM 			 * should retry in case of transient network error for
466*9033SPeter.Shoults@Sun.COM 			 * up to a couple of minutes.
467*9033SPeter.Shoults@Sun.COM 			 */
468*9033SPeter.Shoults@Sun.COM 			if (backoff_timer > 120)
469*9033SPeter.Shoults@Sun.COM 				return (EINTR);
470*9033SPeter.Shoults@Sun.COM 			goto retry;
4712881Smp153739 		}
472*9033SPeter.Shoults@Sun.COM 		alarm(0);
473*9033SPeter.Shoults@Sun.COM 		gfd = -1;
4742881Smp153739 		if (debug && (iproprole != IPROP_SLAVE))
4752881Smp153739 			child_pid = 0;
4762881Smp153739 		else
4772881Smp153739 			child_pid = fork();
4782881Smp153739 		switch (child_pid) {
4792881Smp153739 		case -1:
4802881Smp153739 			com_err(progname, errno, gettext("while forking"));
4812881Smp153739 			exit(1);
4822881Smp153739 	    /*NOTREACHED*/
4832881Smp153739 		case 0:
4842881Smp153739 	    /* child */
4852881Smp153739 			(void) close(finet);
4860Sstevel@tonic-gate 
4872881Smp153739 			doit(s);
4882881Smp153739 			close(s);
4892881Smp153739 			_exit(0);
4900Sstevel@tonic-gate 	    /*NOTREACHED*/
4912881Smp153739 		default:
4920Sstevel@tonic-gate 	    /* parent */
493*9033SPeter.Shoults@Sun.COM 	    /*
494*9033SPeter.Shoults@Sun.COM 	     * Errors should not be considered fatal in the iprop case as we
495*9033SPeter.Shoults@Sun.COM 	     * could have transient type errors, such as network outage, etc.
496*9033SPeter.Shoults@Sun.COM 	     * Sleeping 3s for 2s linger interval.
497*9033SPeter.Shoults@Sun.COM 	     */
4980Sstevel@tonic-gate 	    if (wait(&status) < 0) {
4990Sstevel@tonic-gate 		com_err(progname, errno,
5000Sstevel@tonic-gate 		    gettext("while waiting to receive database"));
501*9033SPeter.Shoults@Sun.COM 		if (iproprole != IPROP_SLAVE)
502*9033SPeter.Shoults@Sun.COM 		    exit(1);
503*9033SPeter.Shoults@Sun.COM 		sleep(3);
5040Sstevel@tonic-gate 	    }
5050Sstevel@tonic-gate 
5060Sstevel@tonic-gate 	    close(s);
5070Sstevel@tonic-gate 	    if (iproprole == IPROP_SLAVE)
5080Sstevel@tonic-gate 		close(finet);
5090Sstevel@tonic-gate 
5100Sstevel@tonic-gate 	    if ((ret = WEXITSTATUS(status)) != 0)
5110Sstevel@tonic-gate 		return (ret);
5120Sstevel@tonic-gate 	}
5130Sstevel@tonic-gate 
5140Sstevel@tonic-gate 	if (iproprole == IPROP_SLAVE)
5150Sstevel@tonic-gate 	    break;
5160Sstevel@tonic-gate     }
5170Sstevel@tonic-gate 
5180Sstevel@tonic-gate     return (0);
5190Sstevel@tonic-gate }
5200Sstevel@tonic-gate 
doit(fd)5210Sstevel@tonic-gate void doit(fd)
5220Sstevel@tonic-gate 	int	fd;
5230Sstevel@tonic-gate {
5240Sstevel@tonic-gate 	struct sockaddr_storage from;
5250Sstevel@tonic-gate 	socklen_t fromlen;
5260Sstevel@tonic-gate 	int on = 1;
5270Sstevel@tonic-gate 	struct hostent	*hp;
5280Sstevel@tonic-gate 	krb5_error_code	retval;
5290Sstevel@tonic-gate 	krb5_data confmsg;
5300Sstevel@tonic-gate 	int lock_fd;
5312881Smp153739 	mode_t omask;
5320Sstevel@tonic-gate 	krb5_enctype etype;
5332881Smp153739 	int database_fd;
5340Sstevel@tonic-gate 	char ntop[NI_MAXHOST] = "";
5350Sstevel@tonic-gate 	krb5_context doit_context;
5360Sstevel@tonic-gate 	kdb_log_context *log_ctx;
5370Sstevel@tonic-gate 
5380Sstevel@tonic-gate 	retval = krb5_init_context(&doit_context);
5390Sstevel@tonic-gate 	if (retval) {
5400Sstevel@tonic-gate 		com_err(progname, retval, gettext("while initializing krb5"));
5410Sstevel@tonic-gate 		exit(1);
5420Sstevel@tonic-gate 	}
5430Sstevel@tonic-gate 	log_ctx = kpropd_context->kdblog_context;
544*9033SPeter.Shoults@Sun.COM 	if (log_ctx && (log_ctx->iproprole == IPROP_SLAVE)) {
5450Sstevel@tonic-gate 		ulog_set_role(doit_context, IPROP_SLAVE);
546*9033SPeter.Shoults@Sun.COM 		/*
547*9033SPeter.Shoults@Sun.COM 		 * We also want to set a timer so that the slave is not waiting
548*9033SPeter.Shoults@Sun.COM 		 * until infinity for an update from the master.
549*9033SPeter.Shoults@Sun.COM 		 */
550*9033SPeter.Shoults@Sun.COM 		if (debug)
551*9033SPeter.Shoults@Sun.COM 			fprintf(stderr, "doit: setting resync alarm to %ds\n",
552*9033SPeter.Shoults@Sun.COM 			    INITIAL_TIMER);
553*9033SPeter.Shoults@Sun.COM 		signal(SIGALRM, resync_alarm);
554*9033SPeter.Shoults@Sun.COM 		gfd = fd;
555*9033SPeter.Shoults@Sun.COM 		if (alarm(INITIAL_TIMER) != 0) {
556*9033SPeter.Shoults@Sun.COM 			if (debug) {
557*9033SPeter.Shoults@Sun.COM 				fprintf(stderr,
558*9033SPeter.Shoults@Sun.COM 				    gettext("%s: alarm already set\n"), progname);
559*9033SPeter.Shoults@Sun.COM 			}
560*9033SPeter.Shoults@Sun.COM 		}
561*9033SPeter.Shoults@Sun.COM 	}
5620Sstevel@tonic-gate 
5630Sstevel@tonic-gate 	fromlen = (socklen_t)sizeof (from);
5640Sstevel@tonic-gate 	if (getpeername(fd, (struct sockaddr *) &from, &fromlen) < 0) {
5650Sstevel@tonic-gate 		fprintf(stderr, "%s: ", progname);
5660Sstevel@tonic-gate 		perror(gettext("getpeername"));
5670Sstevel@tonic-gate 		exit(1);
5680Sstevel@tonic-gate 	}
5690Sstevel@tonic-gate 	if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (caddr_t) &on,
5700Sstevel@tonic-gate 		       sizeof (on)) < 0) {
5710Sstevel@tonic-gate 		com_err(progname, errno,
5720Sstevel@tonic-gate 		gettext("while attempting setsockopt (SO_KEEPALIVE)"));
5730Sstevel@tonic-gate 	}
5740Sstevel@tonic-gate 
5750Sstevel@tonic-gate 	if (getnameinfo((struct sockaddr *)&from, fromlen, ntop, sizeof(ntop),
5760Sstevel@tonic-gate 		NULL, 0, NI_NUMERICHOST) != 0) {
5770Sstevel@tonic-gate 
5780Sstevel@tonic-gate 		/* getnameifo failed so use inet_ntop() to get printable addresses */
5790Sstevel@tonic-gate 		if (from.ss_family == AF_INET) {
5800Sstevel@tonic-gate 
5810Sstevel@tonic-gate 			inet_ntop(AF_INET,
5820Sstevel@tonic-gate 			    (const void *)&ss2sin(&from)->sin_addr,
5830Sstevel@tonic-gate 			    ntop, sizeof(ntop));
5840Sstevel@tonic-gate 
5850Sstevel@tonic-gate 		} else if (from.ss_family == AF_INET6 &&
5860Sstevel@tonic-gate 			! IN6_IS_ADDR_V4MAPPED(&ss2sin6(&from)->sin6_addr)) {
5870Sstevel@tonic-gate 
5880Sstevel@tonic-gate 			ipaddr_t v4addr;
5890Sstevel@tonic-gate 
5900Sstevel@tonic-gate 			inet_ntop(AF_INET6,
5910Sstevel@tonic-gate 				(const void *)&ss2sin6(&from)->sin6_addr, ntop,
5920Sstevel@tonic-gate 				sizeof(ntop));
5930Sstevel@tonic-gate 		}
5940Sstevel@tonic-gate 		/* ipv4 mapped ipv6 addrs handled later */
5950Sstevel@tonic-gate 	}
5960Sstevel@tonic-gate 
5970Sstevel@tonic-gate 	if (from.ss_family == AF_INET || from.ss_family == AF_INET6) {
5980Sstevel@tonic-gate 
5990Sstevel@tonic-gate 		if (from.ss_family == AF_INET6 &&
6000Sstevel@tonic-gate 			IN6_IS_ADDR_V4MAPPED(&ss2sin6(&from)->sin6_addr)) {
6010Sstevel@tonic-gate 
6020Sstevel@tonic-gate 			ipaddr_t v4addr;
6030Sstevel@tonic-gate 
6040Sstevel@tonic-gate 			/* coerce ipv4 mapped ipv6 addr to normal ipv4 addr */
6050Sstevel@tonic-gate 			IN6_V4MAPPED_TO_IPADDR(&(ss2sin6(&from)->sin6_addr),
6060Sstevel@tonic-gate 				v4addr);
6070Sstevel@tonic-gate 
6080Sstevel@tonic-gate 			inet_ntop(AF_INET, (const void *) &v4addr,
6090Sstevel@tonic-gate 				ntop, sizeof(ntop));
6100Sstevel@tonic-gate 		}
6110Sstevel@tonic-gate 
6120Sstevel@tonic-gate 		syslog(LOG_INFO, gettext("Connection from %s"), ntop);
6130Sstevel@tonic-gate 
6140Sstevel@tonic-gate 		if (debug)
6150Sstevel@tonic-gate 			printf("Connection from %s\n", ntop);
6160Sstevel@tonic-gate 
6170Sstevel@tonic-gate 	} else {
6180Sstevel@tonic-gate 		/* address family isn't either AF_INET || AF_INET6 */
6190Sstevel@tonic-gate 		syslog(LOG_INFO,
6200Sstevel@tonic-gate 		    gettext("Connection from unknown address family:%d"),
6210Sstevel@tonic-gate 		    from.ss_family);
6220Sstevel@tonic-gate 
6230Sstevel@tonic-gate 		if (debug) {
6240Sstevel@tonic-gate 			printf(gettext("Connection from unknown address family:%d"),
6250Sstevel@tonic-gate 			    from.ss_family);
6260Sstevel@tonic-gate 		}
6270Sstevel@tonic-gate 	}
6280Sstevel@tonic-gate 
6290Sstevel@tonic-gate 	/*
6300Sstevel@tonic-gate 	 * Now do the authentication
6310Sstevel@tonic-gate 	 */
6328714SMark.Phalan@Sun.COM 	/* Solaris Kerberos */
6338714SMark.Phalan@Sun.COM 	kerberos_authenticate(doit_context, fd, &client, &etype, &from);
6340Sstevel@tonic-gate 
635*9033SPeter.Shoults@Sun.COM 	/*
636*9033SPeter.Shoults@Sun.COM 	 * Turn off alarm upon successful authentication from master.
637*9033SPeter.Shoults@Sun.COM 	 */
638*9033SPeter.Shoults@Sun.COM 	alarm(0);
639*9033SPeter.Shoults@Sun.COM 	gfd = -1;
640*9033SPeter.Shoults@Sun.COM 
6410Sstevel@tonic-gate 	if (!authorized_principal(doit_context, client, etype)) {
6422881Smp153739 		char	*name;
6430Sstevel@tonic-gate 
6442881Smp153739 		retval = krb5_unparse_name(doit_context, client, &name);
6452881Smp153739 		if (retval) {
6466426Smp153739 			/* Solaris Kerberos: Keep error messages consistent */
6472881Smp153739 			com_err(progname, retval,
6486426Smp153739 		    gettext("while unparsing client name"));
6492881Smp153739 			exit(1);
6502881Smp153739 		}
6512881Smp153739 		syslog(LOG_WARNING,
6522881Smp153739 		gettext("Rejected connection from unauthorized principal %s"),
6532881Smp153739 		       name);
6542881Smp153739 		free(name);
6550Sstevel@tonic-gate 		exit(1);
6560Sstevel@tonic-gate 	}
6570Sstevel@tonic-gate 	omask = umask(077);
6580Sstevel@tonic-gate 	lock_fd = open(temp_file_name, O_RDWR|O_CREAT, 0600);
6590Sstevel@tonic-gate 	(void) umask(omask);
6600Sstevel@tonic-gate 	retval = krb5_lock_file(doit_context, lock_fd,
6610Sstevel@tonic-gate 				KRB5_LOCKMODE_EXCLUSIVE|KRB5_LOCKMODE_DONTBLOCK);
6620Sstevel@tonic-gate 	if (retval) {
6630Sstevel@tonic-gate 	    com_err(progname, retval,
6640Sstevel@tonic-gate 			gettext("while trying to lock '%s'"),
6650Sstevel@tonic-gate 		    temp_file_name);
6660Sstevel@tonic-gate 	    exit(1);
6670Sstevel@tonic-gate 	}
6680Sstevel@tonic-gate 	if ((database_fd = open(temp_file_name,
6690Sstevel@tonic-gate 				O_WRONLY|O_CREAT|O_TRUNC, 0600)) < 0) {
6700Sstevel@tonic-gate 		com_err(progname, errno,
6710Sstevel@tonic-gate 			gettext("while opening database file, '%s'"),
6720Sstevel@tonic-gate 			temp_file_name);
6730Sstevel@tonic-gate 		exit(1);
6740Sstevel@tonic-gate 	}
6750Sstevel@tonic-gate 	recv_database(doit_context, fd, database_fd, &confmsg);
6760Sstevel@tonic-gate 	if (rename(temp_file_name, file)) {
6776426Smp153739 		/* Solaris Kerberos: Keep error messages consistent */
6780Sstevel@tonic-gate 		com_err(progname, errno,
6796426Smp153739 			gettext("while renaming %s to %s"),
6800Sstevel@tonic-gate 			temp_file_name, file);
6810Sstevel@tonic-gate 		exit(1);
6820Sstevel@tonic-gate 	}
6830Sstevel@tonic-gate 	retval = krb5_lock_file(doit_context, lock_fd, KRB5_LOCKMODE_SHARED);
6840Sstevel@tonic-gate 	if (retval) {
6850Sstevel@tonic-gate 	    com_err(progname, retval,
6860Sstevel@tonic-gate 			gettext("while downgrading lock on '%s'"),
6870Sstevel@tonic-gate 		    temp_file_name);
6880Sstevel@tonic-gate 	    exit(1);
6890Sstevel@tonic-gate 	}
6900Sstevel@tonic-gate 	load_database(doit_context, kdb5_util, file);
6910Sstevel@tonic-gate 	retval = krb5_lock_file(doit_context, lock_fd, KRB5_LOCKMODE_UNLOCK);
6920Sstevel@tonic-gate 	if (retval) {
6930Sstevel@tonic-gate 	    com_err(progname, retval,
6940Sstevel@tonic-gate 		gettext("while unlocking '%s'"), temp_file_name);
6950Sstevel@tonic-gate 	    exit(1);
6960Sstevel@tonic-gate 	}
6970Sstevel@tonic-gate 	(void)close(lock_fd);
6980Sstevel@tonic-gate 
6990Sstevel@tonic-gate 	/*
7000Sstevel@tonic-gate 	 * Send the acknowledgement message generated in
7010Sstevel@tonic-gate 	 * recv_database, then close the socket.
7020Sstevel@tonic-gate 	 */
7032881Smp153739 	retval = krb5_write_message(doit_context, (void *) &fd, &confmsg);
7042881Smp153739 	if (retval) {
7050Sstevel@tonic-gate 		krb5_free_data_contents(doit_context, &confmsg);
7060Sstevel@tonic-gate 		com_err(progname, retval,
7070Sstevel@tonic-gate 			gettext("while sending # of received bytes"));
7080Sstevel@tonic-gate 		exit(1);
7090Sstevel@tonic-gate 	}
7100Sstevel@tonic-gate 	krb5_free_data_contents(doit_context, &confmsg);
7110Sstevel@tonic-gate 	if (close(fd) < 0) {
7120Sstevel@tonic-gate 		com_err(progname, errno,
7130Sstevel@tonic-gate 			gettext("while trying to close database file"));
7140Sstevel@tonic-gate 		exit(1);
7150Sstevel@tonic-gate 	}
7162881Smp153739 
7170Sstevel@tonic-gate 	exit(0);
7180Sstevel@tonic-gate }
7190Sstevel@tonic-gate 
7200Sstevel@tonic-gate 
7210Sstevel@tonic-gate /*
7220Sstevel@tonic-gate  * Routine to handle incremental update transfer(s) from master KDC
7230Sstevel@tonic-gate  */
do_iprop(kdb_log_context * log_ctx)7240Sstevel@tonic-gate krb5_error_code do_iprop(kdb_log_context *log_ctx) {
7250Sstevel@tonic-gate 	CLIENT *cl;
7260Sstevel@tonic-gate 	kadm5_ret_t retval;
7270Sstevel@tonic-gate 	kadm5_config_params params;
7280Sstevel@tonic-gate 	krb5_ccache cc;
7290Sstevel@tonic-gate 	krb5_principal iprop_svc_principal;
7300Sstevel@tonic-gate 	void *server_handle = NULL;
7310Sstevel@tonic-gate 	char *iprop_svc_princstr = NULL;
7320Sstevel@tonic-gate 	char *master_svc_princstr = NULL;
7330Sstevel@tonic-gate 	char *admin_server = NULL;
7340Sstevel@tonic-gate 	char *keytab_name = NULL;
7350Sstevel@tonic-gate 	unsigned int pollin, backoff_time;
7360Sstevel@tonic-gate 	int backoff_cnt = 0;
7370Sstevel@tonic-gate 	int reinit_cnt = 0;
7380Sstevel@tonic-gate 	int ret;
7390Sstevel@tonic-gate 	boolean_t frdone = B_FALSE;
7400Sstevel@tonic-gate 
7410Sstevel@tonic-gate 	kdb_incr_result_t *incr_ret;
7420Sstevel@tonic-gate 	static kdb_last_t mylast;
7430Sstevel@tonic-gate 
7440Sstevel@tonic-gate 	kdb_fullresync_result_t *full_ret;
7450Sstevel@tonic-gate 	char *full_resync_arg = NULL;
7460Sstevel@tonic-gate 
7470Sstevel@tonic-gate 	kadm5_iprop_handle_t handle;
7480Sstevel@tonic-gate 	kdb_hlog_t *ulog;
7490Sstevel@tonic-gate 
7506426Smp153739 	krb5_keytab kt;
7516426Smp153739 	krb5_keytab_entry entry;
7526426Smp153739 	char kt_name[MAX_KEYTAB_NAME_LEN];
7536426Smp153739 
7546426Smp153739 	/*
7556426Smp153739 	 * Solaris Kerberos:
7566426Smp153739 	 * Delay daemonizing until some basic configuration checks have been
7576426Smp153739 	 * performed
7586426Smp153739 	 */
7596426Smp153739 #if 0
7600Sstevel@tonic-gate 	if (!debug)
7610Sstevel@tonic-gate 		daemon(0, 0);
7626426Smp153739 #endif
7630Sstevel@tonic-gate 	pollin = (unsigned int)0;
7640Sstevel@tonic-gate 	(void) memset((char *)&params, 0, sizeof (params));
7650Sstevel@tonic-gate 	ulog = log_ctx->ulog;
7660Sstevel@tonic-gate 
7670Sstevel@tonic-gate 	params.mask |= KADM5_CONFIG_REALM;
7680Sstevel@tonic-gate 	params.realm = def_realm;
7690Sstevel@tonic-gate 
7700Sstevel@tonic-gate 	if (master_svc_princstr == NULL) {
7710Sstevel@tonic-gate 		if (retval = kadm5_get_kiprop_host_srv_name(kpropd_context,
7720Sstevel@tonic-gate 					def_realm, &master_svc_princstr)) {
7736426Smp153739 			/* Solaris Kerberos: keep error messages consistent */
7740Sstevel@tonic-gate 			com_err(progname, retval,
7756426Smp153739 				gettext("while getting kiprop host based "
7766426Smp153739 					"service name for realm %s"), def_realm);
7770Sstevel@tonic-gate 			exit(1);
7780Sstevel@tonic-gate 		}
7790Sstevel@tonic-gate 	}
7800Sstevel@tonic-gate 
7810Sstevel@tonic-gate 	/*
7820Sstevel@tonic-gate 	 * Set cc to the default credentials cache
7830Sstevel@tonic-gate 	 */
7840Sstevel@tonic-gate 	if (retval = krb5_cc_default(kpropd_context, &cc)) {
7850Sstevel@tonic-gate 		com_err(progname, retval,
7860Sstevel@tonic-gate 			gettext("while opening default "
7870Sstevel@tonic-gate 				"credentials cache"));
7880Sstevel@tonic-gate 		exit(1);
7890Sstevel@tonic-gate 	}
7900Sstevel@tonic-gate 
7910Sstevel@tonic-gate 	retval = krb5_sname_to_principal(kpropd_context, NULL, KIPROP_SVC_NAME,
7920Sstevel@tonic-gate 				KRB5_NT_SRV_HST, &iprop_svc_principal);
7930Sstevel@tonic-gate 	if (retval) {
7940Sstevel@tonic-gate 		com_err(progname, retval, gettext("while trying to construct "
7950Sstevel@tonic-gate 						"host service principal"));
7960Sstevel@tonic-gate 		exit(1);
7970Sstevel@tonic-gate 	}
7980Sstevel@tonic-gate 
7997934SMark.Phalan@Sun.COM 	/* Solaris Kerberos */
8007934SMark.Phalan@Sun.COM 	if (krb5_is_referral_realm(krb5_princ_realm(kpropd_context,
8017934SMark.Phalan@Sun.COM 	    iprop_svc_principal))) {
8027934SMark.Phalan@Sun.COM 		krb5_data *r = krb5_princ_realm(kpropd_context,
8037934SMark.Phalan@Sun.COM 		    iprop_svc_principal);
8047934SMark.Phalan@Sun.COM 		assert(def_realm != NULL);
8057934SMark.Phalan@Sun.COM 		r->length = strlen(def_realm);
8067934SMark.Phalan@Sun.COM 		r->data = strdup(def_realm);
8077934SMark.Phalan@Sun.COM 		if (r->data == NULL) {
8087934SMark.Phalan@Sun.COM 			com_err(progname, retval,
8097934SMark.Phalan@Sun.COM 			    ("while determining local service principal name"));
8107934SMark.Phalan@Sun.COM 			exit(1);
8117934SMark.Phalan@Sun.COM 		}
8127934SMark.Phalan@Sun.COM 	}
8137934SMark.Phalan@Sun.COM 
8140Sstevel@tonic-gate 	if (retval = krb5_unparse_name(kpropd_context, iprop_svc_principal,
8150Sstevel@tonic-gate 				&iprop_svc_princstr)) {
8160Sstevel@tonic-gate 		com_err(progname, retval,
8170Sstevel@tonic-gate 			gettext("while canonicalizing "
8180Sstevel@tonic-gate 				"principal name"));
8190Sstevel@tonic-gate 		krb5_free_principal(kpropd_context, iprop_svc_principal);
8200Sstevel@tonic-gate 		exit(1);
8210Sstevel@tonic-gate 	}
8226426Smp153739 
8236426Smp153739 	/*
8246426Smp153739 	 * Solaris Kerberos:
8256426Smp153739 	 * Check to see if kiprop/<fqdn>@REALM is in the keytab
8266426Smp153739 	 */
8276426Smp153739 	kt_name[0] = '\0';
8286426Smp153739 	if (retval = krb5_kt_default_name(kpropd_context, kt_name,
8296426Smp153739 	    MAX_KEYTAB_NAME_LEN)){
8306426Smp153739 		com_err(progname, retval, gettext ("while resolving the "
8316426Smp153739 		    "name of the default keytab"));
8326426Smp153739 	}
8336426Smp153739 
8346426Smp153739 	if (retval = krb5_kt_default(kpropd_context, &kt)) {
8356426Smp153739 		com_err(progname, retval, gettext ("while resolving default "
8366426Smp153739 		    "keytab"));
8376426Smp153739 		krb5_free_principal(kpropd_context, iprop_svc_principal);
8386426Smp153739 		exit(1);
8396426Smp153739 	}
8406426Smp153739 
8416426Smp153739 	if (retval = krb5_kt_get_entry(kpropd_context, kt, iprop_svc_principal,
8426426Smp153739 	    0, 0, &entry)) {
8436426Smp153739 		com_err(progname, retval, gettext("while retrieving entry %s "
8446426Smp153739 		    "from %s"), iprop_svc_princstr,
8456426Smp153739 		    kt_name[0] ? kt_name : "default keytab");
8466426Smp153739 		krb5_kt_close(kpropd_context,kt);
8476426Smp153739 		krb5_free_principal(kpropd_context, iprop_svc_principal);
8486426Smp153739 		exit(1);
8496426Smp153739 	}
8506426Smp153739 
8516426Smp153739 	krb5_kt_close(kpropd_context,kt);
8520Sstevel@tonic-gate 	krb5_free_principal(kpropd_context, iprop_svc_principal);
8530Sstevel@tonic-gate 
8546426Smp153739 	if (!debug) {
8556426Smp153739 	/* Solaris Kerberos: Indicate where further messages will be sent */
8566426Smp153739 		fprintf(stderr, gettext("%s: Logging to SYSLOG\n"), progname);
8576426Smp153739 		if (daemon(0, 0)) {
8586426Smp153739 			com_err(progname, errno, gettext("while daemonizing"));
8596426Smp153739 			exit(1);
8606426Smp153739 		}
8616426Smp153739 		rem_default_com_err_hook();
8626426Smp153739 	}
8636426Smp153739 
8640Sstevel@tonic-gate reinit:
8650Sstevel@tonic-gate 	/*
8660Sstevel@tonic-gate 	 * Authentication, initialize rpcsec_gss handle etc.
8670Sstevel@tonic-gate 	 */
8680Sstevel@tonic-gate 	retval = kadm5_init_with_skey(iprop_svc_princstr, keytab_name,
8690Sstevel@tonic-gate 				    master_svc_princstr,
8700Sstevel@tonic-gate 				    &params,
8710Sstevel@tonic-gate 				    KADM5_STRUCT_VERSION,
8720Sstevel@tonic-gate 				    KADM5_API_VERSION_2,
8734960Swillf 				    NULL,
8740Sstevel@tonic-gate  				    &server_handle);
8750Sstevel@tonic-gate 
8760Sstevel@tonic-gate 	if (retval) {
8770Sstevel@tonic-gate 		if (retval == KADM5_RPC_ERROR) {
8780Sstevel@tonic-gate 			reinit_cnt++;
8790Sstevel@tonic-gate 			if (server_handle)
8800Sstevel@tonic-gate 				kadm5_destroy((void *) server_handle);
8810Sstevel@tonic-gate 			server_handle = (void *)NULL;
8820Sstevel@tonic-gate 			handle = (kadm5_iprop_handle_t)NULL;
8830Sstevel@tonic-gate 
8840Sstevel@tonic-gate 			com_err(progname, retval, gettext(
8850Sstevel@tonic-gate 					"while attempting to connect"
8860Sstevel@tonic-gate 					" to master KDC ... retrying"));
8870Sstevel@tonic-gate 			backoff_time = backoff_from_master(&reinit_cnt);
8880Sstevel@tonic-gate 			(void) sleep(backoff_time);
8890Sstevel@tonic-gate 			goto reinit;
8900Sstevel@tonic-gate 		} else {
8916426Smp153739 			/* Solaris Kerberos: Be more verbose */
8920Sstevel@tonic-gate 			com_err(progname, retval,
8936426Smp153739                                 gettext("while initializing %s interface for "
8946426Smp153739 				    "%s"), progname, iprop_svc_princstr);
8950Sstevel@tonic-gate 			if (retval == KADM5_BAD_CLIENT_PARAMS ||
8960Sstevel@tonic-gate 			    retval == KADM5_BAD_SERVER_PARAMS)
8970Sstevel@tonic-gate 				usage();
8980Sstevel@tonic-gate 			exit(1);
8990Sstevel@tonic-gate                 }
9000Sstevel@tonic-gate 	}
9010Sstevel@tonic-gate 
9020Sstevel@tonic-gate 	/*
9030Sstevel@tonic-gate 	 * Reset re-initialization count to zero now.
9040Sstevel@tonic-gate 	 */
9050Sstevel@tonic-gate 	reinit_cnt = backoff_time = 0;
9060Sstevel@tonic-gate 
9070Sstevel@tonic-gate 	/*
9080Sstevel@tonic-gate 	 * Reset the handle to the correct type for the RPC call
9090Sstevel@tonic-gate 	 */
9100Sstevel@tonic-gate 	handle = server_handle;
9110Sstevel@tonic-gate 
9120Sstevel@tonic-gate 	/*
9130Sstevel@tonic-gate 	 * If we have reached this far, we have succesfully established
9140Sstevel@tonic-gate 	 * a RPCSEC_GSS connection; we now start polling for updates
9150Sstevel@tonic-gate 	 */
9160Sstevel@tonic-gate 	if (poll_time == NULL) {
9170Sstevel@tonic-gate 		if ((poll_time = (char *)strdup("2m")) == NULL) {
9186426Smp153739 			/* Solaris Kerberos: Keep error messages consistent */
9190Sstevel@tonic-gate 			com_err(progname, ENOMEM,
9206426Smp153739 				gettext("while allocating poll_time"));
9210Sstevel@tonic-gate 			exit(1);
9220Sstevel@tonic-gate 		}
9230Sstevel@tonic-gate 	}
9240Sstevel@tonic-gate 
9250Sstevel@tonic-gate 	if (pollin == (unsigned int)0)
9260Sstevel@tonic-gate 		pollin = convert_polltime(poll_time);
9270Sstevel@tonic-gate 
9280Sstevel@tonic-gate 	for (;;) {
9290Sstevel@tonic-gate 		incr_ret = NULL;
9300Sstevel@tonic-gate 		full_ret = NULL;
9310Sstevel@tonic-gate 
9320Sstevel@tonic-gate 		/*
9330Sstevel@tonic-gate 		 * Get the most recent ulog entry sno + ts, which
9340Sstevel@tonic-gate 		 * we package in the request to the master KDC
9350Sstevel@tonic-gate 		 */
9360Sstevel@tonic-gate 		mylast.last_sno = ulog->kdb_last_sno;
9370Sstevel@tonic-gate 		mylast.last_time = ulog->kdb_last_time;
9380Sstevel@tonic-gate 
9390Sstevel@tonic-gate 		/*
9400Sstevel@tonic-gate 		 * Loop continuously on an iprop_get_updates_1(),
9410Sstevel@tonic-gate 		 * so that we can keep probing the master for updates
9420Sstevel@tonic-gate 		 * or (if needed) do a full resync of the krb5 db.
9430Sstevel@tonic-gate 		 */
9440Sstevel@tonic-gate 
9450Sstevel@tonic-gate 		incr_ret = iprop_get_updates_1(&mylast, handle->clnt);
9460Sstevel@tonic-gate 		if (incr_ret == (kdb_incr_result_t *)NULL) {
9470Sstevel@tonic-gate 			clnt_perror(handle->clnt,
9480Sstevel@tonic-gate 				    "iprop_get_updates call failed");
9490Sstevel@tonic-gate 			if (server_handle)
9500Sstevel@tonic-gate 				kadm5_destroy((void *)server_handle);
9510Sstevel@tonic-gate 			server_handle = (void *)NULL;
9520Sstevel@tonic-gate 			handle = (kadm5_iprop_handle_t)NULL;
9530Sstevel@tonic-gate 			goto reinit;
9540Sstevel@tonic-gate 		}
9550Sstevel@tonic-gate 
9560Sstevel@tonic-gate 		switch (incr_ret->ret) {
9570Sstevel@tonic-gate 
9580Sstevel@tonic-gate 		case UPDATE_FULL_RESYNC_NEEDED:
9590Sstevel@tonic-gate 			/*
9600Sstevel@tonic-gate 			 * We dont do a full resync again, if the last
9610Sstevel@tonic-gate 			 * X'fer was a resync and if the master sno is
9620Sstevel@tonic-gate 			 * still "0", i.e. no updates so far.
9630Sstevel@tonic-gate 			 */
9640Sstevel@tonic-gate 			if ((frdone == B_TRUE) && (incr_ret->lastentry.last_sno
9650Sstevel@tonic-gate 						== 0)) {
9660Sstevel@tonic-gate 				break;
9670Sstevel@tonic-gate 			} else {
9680Sstevel@tonic-gate 
9690Sstevel@tonic-gate 				full_ret = iprop_full_resync_1((void *)
9700Sstevel@tonic-gate 						&full_resync_arg, handle->clnt);
9710Sstevel@tonic-gate 
9720Sstevel@tonic-gate 				if (full_ret == (kdb_fullresync_result_t *)
9730Sstevel@tonic-gate 							NULL) {
9740Sstevel@tonic-gate 					clnt_perror(handle->clnt,
9750Sstevel@tonic-gate 					    "iprop_full_resync call failed");
9760Sstevel@tonic-gate 					if (server_handle)
9770Sstevel@tonic-gate 						kadm5_destroy((void *)
9780Sstevel@tonic-gate 							server_handle);
9790Sstevel@tonic-gate 					server_handle = (void *)NULL;
9800Sstevel@tonic-gate 					handle = (kadm5_iprop_handle_t)NULL;
9810Sstevel@tonic-gate 					goto reinit;
9820Sstevel@tonic-gate 				}
9830Sstevel@tonic-gate 			}
9840Sstevel@tonic-gate 
9850Sstevel@tonic-gate 			switch (full_ret->ret) {
9860Sstevel@tonic-gate 			case UPDATE_OK:
9870Sstevel@tonic-gate 				backoff_cnt = 0;
9880Sstevel@tonic-gate 				/*
9890Sstevel@tonic-gate 				 * We now listen on the kprop port for
9900Sstevel@tonic-gate 				 * the full dump
9910Sstevel@tonic-gate 				 */
9920Sstevel@tonic-gate 				ret = do_standalone(log_ctx->iproprole);
9930Sstevel@tonic-gate 				if (debug)
9940Sstevel@tonic-gate 					if (ret)
9950Sstevel@tonic-gate 						fprintf(stderr,
9960Sstevel@tonic-gate 						    gettext("Full resync "
9970Sstevel@tonic-gate 						    "was unsuccessful\n"));
9980Sstevel@tonic-gate 					else
9990Sstevel@tonic-gate 						fprintf(stderr,
10000Sstevel@tonic-gate 						    gettext("Full resync "
10010Sstevel@tonic-gate 						    "was successful\n"));
1002*9033SPeter.Shoults@Sun.COM 				if (ret) {
1003*9033SPeter.Shoults@Sun.COM 					syslog(LOG_WARNING,
1004*9033SPeter.Shoults@Sun.COM 					    gettext("kpropd: Full resync, "
1005*9033SPeter.Shoults@Sun.COM 					    "invalid return."));
1006*9033SPeter.Shoults@Sun.COM 					/*
1007*9033SPeter.Shoults@Sun.COM 					 * Start backing-off immediately after
1008*9033SPeter.Shoults@Sun.COM 					 * failure.
1009*9033SPeter.Shoults@Sun.COM 					 */
1010*9033SPeter.Shoults@Sun.COM 					backoff_cnt++;
1011*9033SPeter.Shoults@Sun.COM 					frdone = B_FALSE;
1012*9033SPeter.Shoults@Sun.COM 				} else
1013*9033SPeter.Shoults@Sun.COM 					frdone = B_TRUE;
10140Sstevel@tonic-gate 				break;
10150Sstevel@tonic-gate 
10160Sstevel@tonic-gate 			case UPDATE_BUSY:
10170Sstevel@tonic-gate 				/*
10180Sstevel@tonic-gate 				 * Exponential backoff
10190Sstevel@tonic-gate 				 */
10200Sstevel@tonic-gate 				backoff_cnt++;
10210Sstevel@tonic-gate 				break;
10220Sstevel@tonic-gate 
10230Sstevel@tonic-gate 			case UPDATE_FULL_RESYNC_NEEDED:
10240Sstevel@tonic-gate 			case UPDATE_NIL:
10250Sstevel@tonic-gate 			default:
10260Sstevel@tonic-gate 				backoff_cnt = 0;
10270Sstevel@tonic-gate 				frdone = B_FALSE;
10280Sstevel@tonic-gate 				syslog(LOG_ERR, gettext("kpropd: Full resync,"
10290Sstevel@tonic-gate 					" invalid return from master KDC."));
10300Sstevel@tonic-gate 				break;
10310Sstevel@tonic-gate 
10320Sstevel@tonic-gate 			case UPDATE_PERM_DENIED:
10330Sstevel@tonic-gate 				syslog(LOG_ERR, gettext("kpropd: Full resync,"
10340Sstevel@tonic-gate 					" permission denied."));
10350Sstevel@tonic-gate 				goto error;
10360Sstevel@tonic-gate 
10370Sstevel@tonic-gate 			case UPDATE_ERROR:
10380Sstevel@tonic-gate 				syslog(LOG_ERR, gettext("kpropd: Full resync,"
10390Sstevel@tonic-gate 					" error returned from master KDC."));
10400Sstevel@tonic-gate 				goto error;
10410Sstevel@tonic-gate 			}
10420Sstevel@tonic-gate 			break;
10430Sstevel@tonic-gate 
10440Sstevel@tonic-gate 		case UPDATE_OK:
10450Sstevel@tonic-gate 			backoff_cnt = 0;
10460Sstevel@tonic-gate 			frdone = B_FALSE;
10470Sstevel@tonic-gate 
10480Sstevel@tonic-gate 			/*
10490Sstevel@tonic-gate 			 * ulog_replay() will convert the ulog updates to db
10500Sstevel@tonic-gate 			 * entries using the kdb conv api and will commit
10510Sstevel@tonic-gate 			 * the entries to the slave kdc database
10520Sstevel@tonic-gate 			 */
10530Sstevel@tonic-gate 			retval = ulog_replay(kpropd_context, incr_ret);
10540Sstevel@tonic-gate 
10550Sstevel@tonic-gate 			if (retval) {
10560Sstevel@tonic-gate 				syslog(LOG_ERR, gettext("kpropd: ulog_replay"
10570Sstevel@tonic-gate 					" failed, updates not registered."));
10580Sstevel@tonic-gate 				break;
10590Sstevel@tonic-gate 			}
10600Sstevel@tonic-gate 
10610Sstevel@tonic-gate 			if (debug)
10620Sstevel@tonic-gate 				fprintf(stderr, gettext("Update transfer "
10630Sstevel@tonic-gate 					"from master was OK\n"));
10640Sstevel@tonic-gate 			break;
10650Sstevel@tonic-gate 
10660Sstevel@tonic-gate 		case UPDATE_PERM_DENIED:
10670Sstevel@tonic-gate 			syslog(LOG_ERR, gettext("kpropd: get_updates,"
10680Sstevel@tonic-gate 						" permission denied."));
10690Sstevel@tonic-gate 			goto error;
10700Sstevel@tonic-gate 
10710Sstevel@tonic-gate 		case UPDATE_ERROR:
10720Sstevel@tonic-gate 			syslog(LOG_ERR, gettext("kpropd: get_updates, error "
10730Sstevel@tonic-gate 						"returned from master KDC."));
10740Sstevel@tonic-gate 			goto error;
10750Sstevel@tonic-gate 
10760Sstevel@tonic-gate 		case UPDATE_BUSY:
10770Sstevel@tonic-gate 			/*
10780Sstevel@tonic-gate 			 * Exponential backoff
10790Sstevel@tonic-gate 			 */
10800Sstevel@tonic-gate 			backoff_cnt++;
10810Sstevel@tonic-gate 			break;
10820Sstevel@tonic-gate 
10830Sstevel@tonic-gate 		case UPDATE_NIL:
10840Sstevel@tonic-gate 			/*
10850Sstevel@tonic-gate 			 * Master-slave are in sync
10860Sstevel@tonic-gate 			 */
10870Sstevel@tonic-gate 			if (debug)
10880Sstevel@tonic-gate 				fprintf(stderr, gettext("Master, slave KDC's "
10890Sstevel@tonic-gate 					"are in-sync, no updates\n"));
10900Sstevel@tonic-gate 			backoff_cnt = 0;
10910Sstevel@tonic-gate 			frdone = B_FALSE;
10920Sstevel@tonic-gate 			break;
10930Sstevel@tonic-gate 
10940Sstevel@tonic-gate 		default:
10950Sstevel@tonic-gate 			backoff_cnt = 0;
10960Sstevel@tonic-gate 			syslog(LOG_ERR, gettext("kpropd: get_updates,"
10970Sstevel@tonic-gate 					" invalid return from master KDC."));
10980Sstevel@tonic-gate 			break;
10990Sstevel@tonic-gate 		}
11000Sstevel@tonic-gate 
11010Sstevel@tonic-gate 		if (runonce == B_TRUE)
11020Sstevel@tonic-gate 			goto done;
11030Sstevel@tonic-gate 
11040Sstevel@tonic-gate 		/*
11050Sstevel@tonic-gate 		 * Sleep for the specified poll interval (Default is 2 mts),
11060Sstevel@tonic-gate 		 * or do a binary exponential backoff if we get an
11070Sstevel@tonic-gate 		 * UPDATE_BUSY signal
11080Sstevel@tonic-gate 		 */
11090Sstevel@tonic-gate 		if (backoff_cnt > 0) {
11100Sstevel@tonic-gate 			backoff_time = backoff_from_master(&backoff_cnt);
11110Sstevel@tonic-gate 			if (debug)
11120Sstevel@tonic-gate 				fprintf(stderr, gettext("Busy signal received "
11130Sstevel@tonic-gate 					"from master, backoff for %d secs\n"),
11140Sstevel@tonic-gate 					backoff_time);
11150Sstevel@tonic-gate 			(void) sleep(backoff_time);
11160Sstevel@tonic-gate 		}
11170Sstevel@tonic-gate 		else
11180Sstevel@tonic-gate 			(void) sleep(pollin);
11190Sstevel@tonic-gate 
11200Sstevel@tonic-gate 	}
11210Sstevel@tonic-gate 
11220Sstevel@tonic-gate 
11230Sstevel@tonic-gate error:
11240Sstevel@tonic-gate 	if (debug)
11250Sstevel@tonic-gate 		fprintf(stderr, gettext("ERROR returned by master, bailing\n"));
11260Sstevel@tonic-gate 	syslog(LOG_ERR, gettext("kpropd: ERROR returned by master KDC,"
11270Sstevel@tonic-gate 			" bailing.\n"));
11280Sstevel@tonic-gate done:
11290Sstevel@tonic-gate 	if (poll_time)
11300Sstevel@tonic-gate 		free(poll_time);
11310Sstevel@tonic-gate 	if(iprop_svc_princstr)
11320Sstevel@tonic-gate 		free(iprop_svc_princstr);
11330Sstevel@tonic-gate 	if (master_svc_princstr)
11340Sstevel@tonic-gate 		free(master_svc_princstr);
11350Sstevel@tonic-gate 	if (retval = krb5_cc_close(kpropd_context, cc)) {
11360Sstevel@tonic-gate 		com_err(progname, retval,
11370Sstevel@tonic-gate 			gettext("while closing default ccache"));
11380Sstevel@tonic-gate 		exit(1);
11390Sstevel@tonic-gate 	}
11400Sstevel@tonic-gate 	if (def_realm)
11410Sstevel@tonic-gate 		free(def_realm);
11420Sstevel@tonic-gate 	if (server_handle)
11430Sstevel@tonic-gate 		kadm5_destroy((void *)server_handle);
11440Sstevel@tonic-gate 	if (kpropd_context)
11450Sstevel@tonic-gate 		krb5_free_context(kpropd_context);
11460Sstevel@tonic-gate 
11470Sstevel@tonic-gate 	if (runonce == B_TRUE)
11480Sstevel@tonic-gate 		return (0);
11490Sstevel@tonic-gate 	else
11500Sstevel@tonic-gate 		exit(1);
11510Sstevel@tonic-gate }
11520Sstevel@tonic-gate 
11530Sstevel@tonic-gate 
11540Sstevel@tonic-gate /*
11550Sstevel@tonic-gate  * Do exponential backoff, since master KDC is BUSY or down
11560Sstevel@tonic-gate  */
backoff_from_master(int * cnt)11570Sstevel@tonic-gate unsigned int backoff_from_master(int *cnt) {
11580Sstevel@tonic-gate 	unsigned int btime;
11590Sstevel@tonic-gate 
11600Sstevel@tonic-gate 	btime = (unsigned int)(2<<(*cnt));
11610Sstevel@tonic-gate 	if (btime > MAX_BACKOFF) {
11620Sstevel@tonic-gate 		btime = MAX_BACKOFF;
11630Sstevel@tonic-gate 		*cnt--;
11640Sstevel@tonic-gate 	}
11650Sstevel@tonic-gate 
11660Sstevel@tonic-gate 	return (btime);
11670Sstevel@tonic-gate }
11680Sstevel@tonic-gate 
11690Sstevel@tonic-gate 
11700Sstevel@tonic-gate /*
11710Sstevel@tonic-gate  * Routine to convert the `pollstr' string to seconds
11720Sstevel@tonic-gate  */
convert_polltime(char * pollstr)11730Sstevel@tonic-gate int convert_polltime(char *pollstr) {
11740Sstevel@tonic-gate 	char *tokenptr = NULL;
11750Sstevel@tonic-gate 	int len, polltime;
11760Sstevel@tonic-gate 
11770Sstevel@tonic-gate 	len = polltime = 0;
11780Sstevel@tonic-gate 
11790Sstevel@tonic-gate 	if ((len = strcspn(pollstr, "s")) < strlen(pollstr)) {
11800Sstevel@tonic-gate 		tokenptr = malloc((len + 1) * sizeof(char));
11810Sstevel@tonic-gate 		(void) strlcpy(tokenptr, pollstr, len + 1);
11820Sstevel@tonic-gate 		polltime = atoi(tokenptr);
11830Sstevel@tonic-gate 	}
11840Sstevel@tonic-gate 
11850Sstevel@tonic-gate 	if ((len = strcspn(pollstr, "m")) < strlen(pollstr)) {
11860Sstevel@tonic-gate 		tokenptr = malloc((len + 1) * sizeof(char));
11870Sstevel@tonic-gate 		(void) strlcpy(tokenptr, pollstr, len + 1);
11880Sstevel@tonic-gate 		polltime = atoi(tokenptr) * 60;
11890Sstevel@tonic-gate 	}
11900Sstevel@tonic-gate 
11910Sstevel@tonic-gate 	if ((len = strcspn(pollstr, "h")) < strlen(pollstr)) {
11920Sstevel@tonic-gate 		tokenptr = malloc((len + 1) * sizeof(char));
11930Sstevel@tonic-gate 		(void) strlcpy(tokenptr, pollstr, len + 1);
11940Sstevel@tonic-gate 		polltime = atoi(tokenptr) * 3600;
11950Sstevel@tonic-gate 	}
11960Sstevel@tonic-gate 
11970Sstevel@tonic-gate 	if (tokenptr != NULL)
11980Sstevel@tonic-gate 		free(tokenptr);
11990Sstevel@tonic-gate 	/*
12000Sstevel@tonic-gate 	 * If we have a bogus pollstr value, set polltime to the
12010Sstevel@tonic-gate 	 * default of 2 mts (120 seconds).
12020Sstevel@tonic-gate 	 */
12030Sstevel@tonic-gate 	if (polltime == 0)
12040Sstevel@tonic-gate 		polltime = 120;
12050Sstevel@tonic-gate 	return (polltime);
12060Sstevel@tonic-gate }
12070Sstevel@tonic-gate 
12080Sstevel@tonic-gate static void
kpropd_com_err_proc(whoami,code,fmt,args)12090Sstevel@tonic-gate kpropd_com_err_proc(whoami, code, fmt, args)
12100Sstevel@tonic-gate 	const char	*whoami;
12110Sstevel@tonic-gate 	long		code;
12120Sstevel@tonic-gate 	const char	*fmt;
12130Sstevel@tonic-gate 	va_list		args;
12140Sstevel@tonic-gate {
12150Sstevel@tonic-gate 	char	error_buf[8096];
12160Sstevel@tonic-gate 
12170Sstevel@tonic-gate 	error_buf[0] = '\0';
12180Sstevel@tonic-gate 	if (fmt)
12190Sstevel@tonic-gate 		vsprintf(error_buf, fmt, args);
12200Sstevel@tonic-gate 	syslog(LOG_ERR, "%s%s%s%s%s", whoami ? whoami : "", whoami ? ": " : "",
12210Sstevel@tonic-gate 	       code ? error_message(code) : "", code ? " " : "", error_buf);
12220Sstevel@tonic-gate }
12230Sstevel@tonic-gate 
PRS(argc,argv)12240Sstevel@tonic-gate void PRS(argc,argv)
12250Sstevel@tonic-gate 	int	argc;
12260Sstevel@tonic-gate 	char	**argv;
12270Sstevel@tonic-gate {
12280Sstevel@tonic-gate 	register char	*word, ch;
12290Sstevel@tonic-gate 	char	*cp;
12300Sstevel@tonic-gate 	int c;
12310Sstevel@tonic-gate 	struct hostent *hp;
12320Sstevel@tonic-gate 	char	my_host_name[MAXHOSTNAMELEN], buf[BUFSIZ];
12330Sstevel@tonic-gate 	krb5_error_code	retval;
12340Sstevel@tonic-gate 	static const char	tmp[] = ".temp";
12350Sstevel@tonic-gate 	kadm5_config_params	params;
12360Sstevel@tonic-gate 
12370Sstevel@tonic-gate 	(void) setlocale(LC_ALL, "");
12380Sstevel@tonic-gate 
12390Sstevel@tonic-gate #if !defined(TEXT_DOMAIN)		/* Should be defined by cc -D */
12400Sstevel@tonic-gate #define	TEXT_DOMAIN	"KPROPD_TEST"	/* Use this only if it weren't */
12410Sstevel@tonic-gate #endif
12420Sstevel@tonic-gate 
12430Sstevel@tonic-gate 	(void) textdomain(TEXT_DOMAIN);
12440Sstevel@tonic-gate 
12450Sstevel@tonic-gate 	(void) memset((char *) &params, 0, sizeof (params));
12460Sstevel@tonic-gate 
12470Sstevel@tonic-gate 	retval = krb5_init_context(&kpropd_context);
12480Sstevel@tonic-gate 	if (retval) {
12490Sstevel@tonic-gate 		com_err(argv[0], retval,
12500Sstevel@tonic-gate 			gettext("while initializing krb5"));
12510Sstevel@tonic-gate 		exit(1);
12520Sstevel@tonic-gate 	}
12536426Smp153739 
12546426Smp153739 	/* Solaris Kerberos: Sanitize progname */
12556426Smp153739 	progname = basename(argv[0]);
12566426Smp153739 
12570Sstevel@tonic-gate 	while ((c = getopt(argc, argv, "dtf:F:p:P:r:s:Sa:")) != EOF){
12580Sstevel@tonic-gate 		switch (c) {
12590Sstevel@tonic-gate 		case 'd':
12600Sstevel@tonic-gate 			debug++;
12610Sstevel@tonic-gate 			break;
12620Sstevel@tonic-gate 		case 't':
12630Sstevel@tonic-gate 			/*
12640Sstevel@tonic-gate 			 * Undocumented option - for testing only.
12650Sstevel@tonic-gate 			 *
12660Sstevel@tonic-gate 			 * Option to run the kpropd server exactly
12670Sstevel@tonic-gate 			 * once (this is true only if iprop is enabled).
12680Sstevel@tonic-gate 			 */
12690Sstevel@tonic-gate 			runonce = B_TRUE;
12700Sstevel@tonic-gate 			break;
12710Sstevel@tonic-gate 
12720Sstevel@tonic-gate 		case 'f':
12730Sstevel@tonic-gate 			file = optarg;
12740Sstevel@tonic-gate 			if (!file)
12750Sstevel@tonic-gate 				usage();
12760Sstevel@tonic-gate 			break;
12770Sstevel@tonic-gate 		case 'F':
12780Sstevel@tonic-gate 			kerb_database = optarg;
12790Sstevel@tonic-gate 			if (!kerb_database)
12800Sstevel@tonic-gate 				usage();
12810Sstevel@tonic-gate 			break;
12820Sstevel@tonic-gate 		case 'p':
12830Sstevel@tonic-gate 			kdb5_util = optarg;
12840Sstevel@tonic-gate 			if (!kdb5_util)
12850Sstevel@tonic-gate 				usage();
12860Sstevel@tonic-gate 			break;
12870Sstevel@tonic-gate 		case 'P':
12880Sstevel@tonic-gate 			port = htons(atoi(optarg));
12890Sstevel@tonic-gate 			if (!port)
12900Sstevel@tonic-gate 				usage();
12910Sstevel@tonic-gate 			break;
12920Sstevel@tonic-gate 		case 'r':
12930Sstevel@tonic-gate 			realm = optarg;
12940Sstevel@tonic-gate 			if (!realm)
12950Sstevel@tonic-gate 				usage();
12960Sstevel@tonic-gate 			params.realm = realm;
12970Sstevel@tonic-gate 			params.mask |= KADM5_CONFIG_REALM;
12980Sstevel@tonic-gate 			break;
12990Sstevel@tonic-gate 		case 's':
13000Sstevel@tonic-gate 			srvtab = optarg;
13010Sstevel@tonic-gate 			if (!srvtab)
13020Sstevel@tonic-gate 				usage();
13030Sstevel@tonic-gate 			break;
13040Sstevel@tonic-gate 		case 'S':
13050Sstevel@tonic-gate 			standalone++;
13060Sstevel@tonic-gate 			break;
13070Sstevel@tonic-gate 		case 'a':
13080Sstevel@tonic-gate 			acl_file_name = optarg;
13090Sstevel@tonic-gate 			if (!acl_file_name)
13100Sstevel@tonic-gate 				usage();
13110Sstevel@tonic-gate 			break;
13120Sstevel@tonic-gate 		case '?':
13130Sstevel@tonic-gate 				default:
13140Sstevel@tonic-gate 					usage();
13150Sstevel@tonic-gate 				}
13160Sstevel@tonic-gate 
13170Sstevel@tonic-gate 			}
13180Sstevel@tonic-gate 	/*
13190Sstevel@tonic-gate 	 * If not in debug mode, switch com_err reporting to syslog
13200Sstevel@tonic-gate 	 */
13210Sstevel@tonic-gate 	if (! debug) {
13220Sstevel@tonic-gate 	    openlog("kpropd", LOG_PID | LOG_ODELAY, SYSLOG_CLASS);
13236426Smp153739 	    /*
13246426Smp153739 	     * Solaris Kerberos:
13256426Smp153739 	     * Don't replace default logging. Add a new logging channel.
13266426Smp153739 	     * Stop logging to stderr when daemonizing
13276426Smp153739 	     */
13286426Smp153739 	    add_com_err_hook(kpropd_com_err_proc);
13290Sstevel@tonic-gate 	}
13300Sstevel@tonic-gate 	/*
13310Sstevel@tonic-gate 	 * Get my hostname, so we can construct my service name
13320Sstevel@tonic-gate 	 */
13330Sstevel@tonic-gate 	retval = krb5_sname_to_principal(kpropd_context,
13340Sstevel@tonic-gate 					 NULL, KPROP_SERVICE_NAME,
13350Sstevel@tonic-gate 					 KRB5_NT_SRV_HST, &server);
13360Sstevel@tonic-gate 	if (retval) {
13376426Smp153739 		/* Solaris Kerberos: Keep error messages consistent */
13380Sstevel@tonic-gate 		com_err(progname, retval,
13396426Smp153739 			gettext("while trying to construct my service name"));
13400Sstevel@tonic-gate 		exit(1);
13410Sstevel@tonic-gate 	}
13420Sstevel@tonic-gate 	if (realm) {
13432881Smp153739 	    retval = krb5_set_principal_realm(kpropd_context, server, realm);
13442881Smp153739 	    if (retval) {
13452881Smp153739 	        com_err(progname, errno,
13462881Smp153739 			gettext("while constructing my service realm"));
13472881Smp153739 		exit(1);
13482881Smp153739 	    }
13490Sstevel@tonic-gate 	}
13500Sstevel@tonic-gate 	/*
13510Sstevel@tonic-gate 	 * Construct the name of the temporary file.
13520Sstevel@tonic-gate 	 */
13530Sstevel@tonic-gate 	if ((temp_file_name = (char *) malloc(strlen(file) +
13540Sstevel@tonic-gate 					       strlen(tmp) + 1)) == NULL) {
13550Sstevel@tonic-gate 		com_err(progname, ENOMEM,
13560Sstevel@tonic-gate 			gettext("while allocating filename for temp file"));
13570Sstevel@tonic-gate 		exit(1);
13580Sstevel@tonic-gate 	}
13590Sstevel@tonic-gate 	strcpy(temp_file_name, file);
13600Sstevel@tonic-gate 	strcat(temp_file_name, tmp);
13610Sstevel@tonic-gate 
13627934SMark.Phalan@Sun.COM 	retval = kadm5_get_config_params(kpropd_context, 1, NULL, &params,
13630Sstevel@tonic-gate 	    &params);
13640Sstevel@tonic-gate 	if (retval) {
13650Sstevel@tonic-gate 		com_err(progname, retval, gettext("while initializing"));
13660Sstevel@tonic-gate 		exit(1);
13670Sstevel@tonic-gate 	}
13680Sstevel@tonic-gate 	if (params.iprop_enabled == TRUE) {
13690Sstevel@tonic-gate 		ulog_set_role(kpropd_context, IPROP_SLAVE);
13700Sstevel@tonic-gate 		poll_time = params.iprop_polltime;
13710Sstevel@tonic-gate 
13720Sstevel@tonic-gate 		if (ulog_map(kpropd_context, &params, FKPROPD)) {
13736426Smp153739 		/* Solaris Kerberos: Keep error messages consistent */
13740Sstevel@tonic-gate  			com_err(progname, errno,
13756426Smp153739 			    gettext("while mapping log"));
13760Sstevel@tonic-gate 			exit(1);
13770Sstevel@tonic-gate 		}
13780Sstevel@tonic-gate 	}
13790Sstevel@tonic-gate 
13800Sstevel@tonic-gate 	/*
13810Sstevel@tonic-gate 	 * Grab the realm info and check if iprop is enabled.
13820Sstevel@tonic-gate 	 */
13830Sstevel@tonic-gate 	if (def_realm == NULL) {
13840Sstevel@tonic-gate 		retval = krb5_get_default_realm(kpropd_context, &def_realm);
13850Sstevel@tonic-gate 		if (retval) {
13866426Smp153739 			/* Solaris Kerberos: Keep error messages consistent */
13870Sstevel@tonic-gate 			com_err(progname, retval,
13886426Smp153739 				gettext("while retrieving default realm"));
13890Sstevel@tonic-gate 			exit(1);
13900Sstevel@tonic-gate 		}
13910Sstevel@tonic-gate 	}
13920Sstevel@tonic-gate }
13930Sstevel@tonic-gate 
13940Sstevel@tonic-gate /*
13950Sstevel@tonic-gate  * Figure out who's calling on the other end of the connection....
13960Sstevel@tonic-gate  */
13978714SMark.Phalan@Sun.COM /* Solaris Kerberos */
13980Sstevel@tonic-gate void
kerberos_authenticate(context,fd,clientp,etype,ss)13990Sstevel@tonic-gate kerberos_authenticate(context, fd, clientp, etype, ss)
14000Sstevel@tonic-gate     krb5_context 	  context;
14010Sstevel@tonic-gate     int		 	  fd;
14020Sstevel@tonic-gate     krb5_principal	* clientp;
14030Sstevel@tonic-gate     krb5_enctype	* etype;
14048714SMark.Phalan@Sun.COM     struct sockaddr_storage	* ss;
14050Sstevel@tonic-gate {
14060Sstevel@tonic-gate     krb5_error_code	  retval;
14070Sstevel@tonic-gate     krb5_ticket		* ticket;
14080Sstevel@tonic-gate     struct sockaddr_storage	  r_ss;
14090Sstevel@tonic-gate     int			  ss_length;
14100Sstevel@tonic-gate     krb5_keytab		  keytab = NULL;
14110Sstevel@tonic-gate 
14120Sstevel@tonic-gate     /*
14130Sstevel@tonic-gate      * Set recv_addr and send_addr
14140Sstevel@tonic-gate      */
14158714SMark.Phalan@Sun.COM     /* Solaris Kerberos */
14168714SMark.Phalan@Sun.COM     if (cvtkaddr(ss, &sender_addr) == NULL) {
14170Sstevel@tonic-gate 	com_err(progname, errno,
14180Sstevel@tonic-gate 		gettext("while converting socket address"));
14190Sstevel@tonic-gate 	exit(1);
14200Sstevel@tonic-gate     }
14210Sstevel@tonic-gate 
14220Sstevel@tonic-gate     ss_length = sizeof (r_ss);
14230Sstevel@tonic-gate     if (getsockname(fd, (struct sockaddr *) &r_ss, &ss_length)) {
14240Sstevel@tonic-gate 	com_err(progname, errno,
14250Sstevel@tonic-gate 		gettext("while getting local socket address"));
14260Sstevel@tonic-gate 	exit(1);
14270Sstevel@tonic-gate     }
14280Sstevel@tonic-gate 
14290Sstevel@tonic-gate     if (cvtkaddr(&r_ss, &receiver_addr) == NULL) {
14300Sstevel@tonic-gate 	com_err(progname, errno,
14310Sstevel@tonic-gate 		gettext("while converting socket address"));
14320Sstevel@tonic-gate 	exit(1);
14330Sstevel@tonic-gate     }
14340Sstevel@tonic-gate 
14350Sstevel@tonic-gate     if (debug) {
14360Sstevel@tonic-gate 	char *name;
14372881Smp153739 
14382881Smp153739 	retval = krb5_unparse_name(context, server, &name);
14392881Smp153739 	if (retval) {
14406426Smp153739 	    /* Solaris Kerberos: Keep error messages consistent */
14416426Smp153739 	    com_err(progname, retval, gettext("while unparsing server name"));
14420Sstevel@tonic-gate 	    exit(1);
14430Sstevel@tonic-gate 	}
14440Sstevel@tonic-gate 	printf(gettext("krb5_recvauth(%d, %s, %s, ...)\n"), fd, kprop_version,
14450Sstevel@tonic-gate 	    name);
14460Sstevel@tonic-gate 	free(name);
14470Sstevel@tonic-gate     }
14480Sstevel@tonic-gate 
14492881Smp153739     retval = krb5_auth_con_init(context, &auth_context);
14502881Smp153739     if (retval) {
14510Sstevel@tonic-gate 	syslog(LOG_ERR, gettext("Error in krb5_auth_con_init: %s"),
14522881Smp153739 	       error_message(retval));
14530Sstevel@tonic-gate     	exit(1);
14540Sstevel@tonic-gate     }
14550Sstevel@tonic-gate 
14562881Smp153739     retval = krb5_auth_con_setflags(context, auth_context,
14572881Smp153739 				    KRB5_AUTH_CONTEXT_DO_SEQUENCE);
14582881Smp153739     if (retval) {
14590Sstevel@tonic-gate 	syslog(LOG_ERR, gettext("Error in krb5_auth_con_setflags: %s"),
14600Sstevel@tonic-gate 	       error_message(retval));
14610Sstevel@tonic-gate 	exit(1);
14620Sstevel@tonic-gate     }
14630Sstevel@tonic-gate 
14642881Smp153739     retval = krb5_auth_con_setaddrs(context, auth_context, &receiver_addr,
14652881Smp153739 				    &sender_addr);
14662881Smp153739     if (retval) {
14670Sstevel@tonic-gate 	syslog(LOG_ERR, gettext("Error in krb5_auth_con_setaddrs: %s"),
14680Sstevel@tonic-gate 	       error_message(retval));
14690Sstevel@tonic-gate 	exit(1);
14700Sstevel@tonic-gate     }
14710Sstevel@tonic-gate 
14720Sstevel@tonic-gate     if (srvtab) {
14732881Smp153739         retval = krb5_kt_resolve(context, srvtab, &keytab);
14742881Smp153739 	if (retval) {
14750Sstevel@tonic-gate 	  syslog(LOG_ERR, gettext("Error in krb5_kt_resolve: %s"), error_message(retval));
14760Sstevel@tonic-gate 	  exit(1);
14770Sstevel@tonic-gate 	}
14780Sstevel@tonic-gate     }
14790Sstevel@tonic-gate 
14802881Smp153739     retval = krb5_recvauth(context, &auth_context, (void *) &fd,
14812881Smp153739 			   kprop_version, server, 0, keytab, &ticket);
14822881Smp153739     if (retval) {
14832881Smp153739 	syslog(LOG_ERR, gettext("Error in krb5_recvauth: %s"), error_message(retval));
14840Sstevel@tonic-gate 	exit(1);
14850Sstevel@tonic-gate     }
14860Sstevel@tonic-gate 
14872881Smp153739     retval = krb5_copy_principal(context, ticket->enc_part2->client, clientp);
14882881Smp153739     if (retval) {
14890Sstevel@tonic-gate 	syslog(LOG_ERR, gettext("Error in krb5_copy_prinicpal: %s"),
14900Sstevel@tonic-gate 	       error_message(retval));
14910Sstevel@tonic-gate 	exit(1);
14920Sstevel@tonic-gate     }
14930Sstevel@tonic-gate 
14940Sstevel@tonic-gate     *etype = ticket->enc_part.enctype;
14950Sstevel@tonic-gate 
14960Sstevel@tonic-gate     if (debug) {
14970Sstevel@tonic-gate 	char * name;
14980Sstevel@tonic-gate 	char etypebuf[100];
14990Sstevel@tonic-gate 
15002881Smp153739 	retval = krb5_unparse_name(context, *clientp, &name);
15012881Smp153739 	if (retval) {
15026426Smp153739 	    /* Solaris Kerberos: Keep error messages consistent */
15030Sstevel@tonic-gate 	    com_err(progname, retval,
15046426Smp153739 		gettext("while unparsing client name"));
15050Sstevel@tonic-gate 	    exit(1);
15060Sstevel@tonic-gate 	}
15070Sstevel@tonic-gate 
15082881Smp153739 	retval = krb5_enctype_to_string(*etype, etypebuf, sizeof(etypebuf));
15092881Smp153739 	if (retval) {
15106426Smp153739 	    /* Solaris Kerberos: Keep error messages consistent */
15116426Smp153739 	    com_err(progname, retval, gettext("while unparsing ticket etype"));
15120Sstevel@tonic-gate 	    exit(1);
15130Sstevel@tonic-gate 	}
15140Sstevel@tonic-gate 
15150Sstevel@tonic-gate 	printf("authenticated client: %s (etype == %s)\n", name, etypebuf);
15160Sstevel@tonic-gate 	free(name);
15170Sstevel@tonic-gate     }
15180Sstevel@tonic-gate 
15190Sstevel@tonic-gate     krb5_free_ticket(context, ticket);
15200Sstevel@tonic-gate }
15210Sstevel@tonic-gate 
15220Sstevel@tonic-gate krb5_boolean
authorized_principal(context,p,auth_etype)15230Sstevel@tonic-gate authorized_principal(context, p, auth_etype)
15240Sstevel@tonic-gate     krb5_context context;
15250Sstevel@tonic-gate     krb5_principal p;
15260Sstevel@tonic-gate     krb5_enctype auth_etype;
15270Sstevel@tonic-gate {
15280Sstevel@tonic-gate     char		*name, *ptr;
15290Sstevel@tonic-gate     char		buf[1024];
15300Sstevel@tonic-gate     krb5_error_code	retval;
15310Sstevel@tonic-gate     FILE		*acl_file;
15320Sstevel@tonic-gate     int			end;
15330Sstevel@tonic-gate     krb5_enctype	acl_etype;
15340Sstevel@tonic-gate 
15350Sstevel@tonic-gate     retval = krb5_unparse_name(context, p, &name);
15360Sstevel@tonic-gate     if (retval)
15370Sstevel@tonic-gate 	return FALSE;
15380Sstevel@tonic-gate 
15390Sstevel@tonic-gate     acl_file = fopen(acl_file_name, "r");
15400Sstevel@tonic-gate     if (!acl_file)
15410Sstevel@tonic-gate 	return FALSE;
15420Sstevel@tonic-gate 
15430Sstevel@tonic-gate     while (!feof(acl_file)) {
15440Sstevel@tonic-gate 	if (!fgets(buf, sizeof(buf), acl_file))
15450Sstevel@tonic-gate 	    break;
15460Sstevel@tonic-gate 	end = strlen(buf) - 1;
15470Sstevel@tonic-gate 	if (buf[end] == '\n')
15480Sstevel@tonic-gate 	    buf[end] = '\0';
15490Sstevel@tonic-gate 	if (!strncmp(name, buf, strlen(name))) {
15500Sstevel@tonic-gate 	    ptr = buf+strlen(name);
15510Sstevel@tonic-gate 
15520Sstevel@tonic-gate 	    /* if the next character is not whitespace or nul, then
15530Sstevel@tonic-gate 	       the match is only partial.  continue on to new lines. */
15542881Smp153739 	    if (*ptr && !isspace((int) *ptr))
15550Sstevel@tonic-gate 		continue;
15560Sstevel@tonic-gate 
15570Sstevel@tonic-gate 	    /* otherwise, skip trailing whitespace */
15582881Smp153739 	    for (; *ptr && isspace((int) *ptr); ptr++) ;
15590Sstevel@tonic-gate 
15600Sstevel@tonic-gate 	    /* now, look for an etype string. if there isn't one,
15610Sstevel@tonic-gate 	       return true.  if there is an invalid string, continue.
15620Sstevel@tonic-gate 	       If there is a valid string, return true only if it
15630Sstevel@tonic-gate 	       matches the etype passed in, otherwise continue */
15640Sstevel@tonic-gate 
15650Sstevel@tonic-gate 	    if ((*ptr) &&
15660Sstevel@tonic-gate 		((retval = krb5_string_to_enctype(ptr, &acl_etype)) ||
15670Sstevel@tonic-gate 		 (acl_etype != auth_etype)))
15680Sstevel@tonic-gate 		continue;
15690Sstevel@tonic-gate 
15700Sstevel@tonic-gate 	    free(name);
15710Sstevel@tonic-gate 	    fclose(acl_file);
15720Sstevel@tonic-gate 	    return TRUE;
15730Sstevel@tonic-gate 	}
15740Sstevel@tonic-gate     }
15750Sstevel@tonic-gate     free(name);
15760Sstevel@tonic-gate     fclose(acl_file);
15770Sstevel@tonic-gate     return FALSE;
15780Sstevel@tonic-gate }
15790Sstevel@tonic-gate 
15800Sstevel@tonic-gate void
recv_database(context,fd,database_fd,confmsg)15810Sstevel@tonic-gate recv_database(context, fd, database_fd, confmsg)
15820Sstevel@tonic-gate     krb5_context context;
15830Sstevel@tonic-gate     int	fd;
15840Sstevel@tonic-gate     int	database_fd;
15850Sstevel@tonic-gate     krb5_data *confmsg;
15860Sstevel@tonic-gate {
15872881Smp153739 	krb5_ui_4	database_size; /* This must be 4 bytes */
15880Sstevel@tonic-gate 	int	received_size, n;
15890Sstevel@tonic-gate 	char		buf[1024];
15900Sstevel@tonic-gate 	krb5_data	inbuf, outbuf;
15910Sstevel@tonic-gate 	krb5_error_code	retval;
15920Sstevel@tonic-gate 
15930Sstevel@tonic-gate 	/*
15940Sstevel@tonic-gate 	 * Receive and decode size from client
15950Sstevel@tonic-gate 	 */
15962881Smp153739 	retval = krb5_read_message(context, (void *) &fd, &inbuf);
15972881Smp153739 	if (retval) {
15980Sstevel@tonic-gate 		send_error(context, fd, retval, gettext("while reading database size"));
15990Sstevel@tonic-gate 		com_err(progname, retval,
16000Sstevel@tonic-gate 			gettext("while reading size of database from client"));
16010Sstevel@tonic-gate 		exit(1);
16020Sstevel@tonic-gate 	}
16030Sstevel@tonic-gate 	if (krb5_is_krb_error(&inbuf))
16040Sstevel@tonic-gate 		recv_error(context, &inbuf);
16052881Smp153739 	retval = krb5_rd_safe(context,auth_context,&inbuf,&outbuf,NULL);
16062881Smp153739 	if (retval) {
16072881Smp153739 		send_error(context, fd, retval, gettext(
16082881Smp153739 			   "while decoding database size"));
16090Sstevel@tonic-gate 		krb5_free_data_contents(context, &inbuf);
16100Sstevel@tonic-gate 		com_err(progname, retval,
16110Sstevel@tonic-gate 			gettext("while decoding database size from client"));
16120Sstevel@tonic-gate 		exit(1);
16130Sstevel@tonic-gate 	}
16140Sstevel@tonic-gate 	memcpy((char *) &database_size, outbuf.data, sizeof(database_size));
16150Sstevel@tonic-gate 	krb5_free_data_contents(context, &inbuf);
16160Sstevel@tonic-gate 	krb5_free_data_contents(context, &outbuf);
16170Sstevel@tonic-gate 	database_size = ntohl(database_size);
16180Sstevel@tonic-gate 
16192881Smp153739 	/*
16202881Smp153739 	 * Initialize the initial vector.
16212881Smp153739 	 */
16222881Smp153739 	retval = krb5_auth_con_initivector(context, auth_context);
16232881Smp153739 	if (retval) {
16242881Smp153739 	  send_error(context, fd, retval, gettext(
16252881Smp153739 		     "failed while initializing i_vector"));
16262881Smp153739 	  com_err(progname, retval, gettext("while initializing i_vector"));
16272881Smp153739 	  exit(1);
16282881Smp153739 	}
16290Sstevel@tonic-gate 
16300Sstevel@tonic-gate 	/*
16310Sstevel@tonic-gate 	 * Now start receiving the database from the net
16320Sstevel@tonic-gate 	 */
16330Sstevel@tonic-gate 	received_size = 0;
16340Sstevel@tonic-gate 	while (received_size < database_size) {
16352881Smp153739 	        retval = krb5_read_message(context, (void *) &fd, &inbuf);
16362881Smp153739 		if (retval) {
16370Sstevel@tonic-gate 			snprintf(buf, sizeof (buf),
16380Sstevel@tonic-gate 			gettext("while reading database block starting at offset %d"),
16390Sstevel@tonic-gate 				received_size);
16400Sstevel@tonic-gate 			com_err(progname, retval, buf);
16410Sstevel@tonic-gate 			send_error(context, fd, retval, buf);
16420Sstevel@tonic-gate 			exit(1);
16430Sstevel@tonic-gate 		}
16440Sstevel@tonic-gate 		if (krb5_is_krb_error(&inbuf))
16450Sstevel@tonic-gate 			recv_error(context, &inbuf);
16462881Smp153739 		retval = krb5_rd_priv(context, auth_context, &inbuf,
16472881Smp153739 				      &outbuf, NULL);
16482881Smp153739 		if (retval) {
16490Sstevel@tonic-gate 			snprintf(buf, sizeof (buf),
16500Sstevel@tonic-gate 		gettext("while decoding database block starting at offset %d"),
16510Sstevel@tonic-gate 				received_size);
16520Sstevel@tonic-gate 			com_err(progname, retval, buf);
16530Sstevel@tonic-gate 			send_error(context, fd, retval, buf);
16540Sstevel@tonic-gate 			krb5_free_data_contents(context, &inbuf);
16550Sstevel@tonic-gate 			exit(1);
16560Sstevel@tonic-gate 		}
16570Sstevel@tonic-gate 		n = write(database_fd, outbuf.data, outbuf.length);
16580Sstevel@tonic-gate 		if (n < 0) {
16590Sstevel@tonic-gate 			snprintf(buf, sizeof (buf),
16600Sstevel@tonic-gate 				gettext(
16610Sstevel@tonic-gate "while writing database block starting at offset %d"),
16620Sstevel@tonic-gate 				received_size);
16630Sstevel@tonic-gate 			send_error(context, fd, errno, buf);
16640Sstevel@tonic-gate 		} else if (n != outbuf.length) {
16650Sstevel@tonic-gate 			snprintf(buf, sizeof (buf),
16660Sstevel@tonic-gate 				gettext(
16670Sstevel@tonic-gate "incomplete write while writing database block starting at\n"
16680Sstevel@tonic-gate "offset %d (%d written, %d expected)"),
16690Sstevel@tonic-gate 				received_size, n, outbuf.length);
16700Sstevel@tonic-gate 			send_error(context, fd, KRB5KRB_ERR_GENERIC, buf);
16710Sstevel@tonic-gate 		}
16720Sstevel@tonic-gate 		received_size += outbuf.length;
16730Sstevel@tonic-gate 		/* SUNWresync121: our krb5...contents sets length to 0 */
16740Sstevel@tonic-gate 		krb5_free_data_contents(context, &inbuf);
16750Sstevel@tonic-gate 		krb5_free_data_contents(context, &outbuf);
16762881Smp153739 
16770Sstevel@tonic-gate 	}
16780Sstevel@tonic-gate 	/*
16790Sstevel@tonic-gate 	 * OK, we've seen the entire file.  Did we get too many bytes?
16800Sstevel@tonic-gate 	 */
16810Sstevel@tonic-gate 	if (received_size > database_size) {
16820Sstevel@tonic-gate 		snprintf(buf, sizeof (buf),
16830Sstevel@tonic-gate 		gettext("Received %d bytes, expected %d bytes for database file"),
16840Sstevel@tonic-gate 			received_size, database_size);
16850Sstevel@tonic-gate 		send_error(context, fd, KRB5KRB_ERR_GENERIC, buf);
16860Sstevel@tonic-gate 	}
16870Sstevel@tonic-gate 	/*
16880Sstevel@tonic-gate 	 * Create message acknowledging number of bytes received, but
16890Sstevel@tonic-gate 	 * don't send it until kdb5_util returns successfully.
16900Sstevel@tonic-gate 	 */
16910Sstevel@tonic-gate 	database_size = htonl(database_size);
16920Sstevel@tonic-gate 	inbuf.data = (char *) &database_size;
16930Sstevel@tonic-gate 	inbuf.length = sizeof(database_size);
16942881Smp153739 	retval = krb5_mk_safe(context,auth_context,&inbuf,confmsg,NULL);
16952881Smp153739 	if (retval) {
16960Sstevel@tonic-gate 		com_err(progname, retval,
16970Sstevel@tonic-gate 			gettext("while encoding # of receieved bytes"));
16980Sstevel@tonic-gate 		send_error(context, fd, retval,
16990Sstevel@tonic-gate 			   gettext("while encoding # of received bytes"));
17000Sstevel@tonic-gate 		exit(1);
17010Sstevel@tonic-gate 	}
17020Sstevel@tonic-gate }
17030Sstevel@tonic-gate 
17040Sstevel@tonic-gate 
17050Sstevel@tonic-gate void
send_error(context,fd,err_code,err_text)17060Sstevel@tonic-gate send_error(context, fd, err_code, err_text)
17070Sstevel@tonic-gate     krb5_context context;
17080Sstevel@tonic-gate     int	fd;
17090Sstevel@tonic-gate     krb5_error_code	err_code;
17100Sstevel@tonic-gate     char	*err_text;
17110Sstevel@tonic-gate {
17120Sstevel@tonic-gate 	krb5_error	error;
17130Sstevel@tonic-gate 	const char	*text;
17140Sstevel@tonic-gate 	krb5_data	outbuf;
17150Sstevel@tonic-gate 	char		buf[1024];
17160Sstevel@tonic-gate 
17170Sstevel@tonic-gate 	memset((char *)&error, 0, sizeof(error));
17180Sstevel@tonic-gate 	krb5_us_timeofday(context, &error.stime, &error.susec);
17190Sstevel@tonic-gate 	error.server = server;
17200Sstevel@tonic-gate 	error.client = client;
17210Sstevel@tonic-gate 
17220Sstevel@tonic-gate 	if (err_text)
17230Sstevel@tonic-gate 		text = err_text;
17240Sstevel@tonic-gate 	else
17250Sstevel@tonic-gate 		text = error_message(err_code);
17260Sstevel@tonic-gate 
17270Sstevel@tonic-gate 	error.error = err_code - ERROR_TABLE_BASE_krb5;
17280Sstevel@tonic-gate 	if (error.error > 127) {
17290Sstevel@tonic-gate 		error.error = KRB_ERR_GENERIC;
17300Sstevel@tonic-gate 		if (err_text) {
17310Sstevel@tonic-gate 			sprintf(buf, "%s %s", error_message(err_code),
17320Sstevel@tonic-gate 				err_text);
17330Sstevel@tonic-gate 			text = buf;
17340Sstevel@tonic-gate 		}
17350Sstevel@tonic-gate 	}
17360Sstevel@tonic-gate 	error.text.length = strlen(text) + 1;
17372881Smp153739 	error.text.data = malloc(error.text.length);
17382881Smp153739 	if (error.text.data) {
17390Sstevel@tonic-gate 		strcpy(error.text.data, text);
17400Sstevel@tonic-gate 		if (!krb5_mk_error(context, &error, &outbuf)) {
17410Sstevel@tonic-gate 			(void) krb5_write_message(context, (void *)&fd,&outbuf);
17420Sstevel@tonic-gate 			krb5_free_data_contents(context, &outbuf);
17430Sstevel@tonic-gate 		}
17440Sstevel@tonic-gate 		free(error.text.data);
17450Sstevel@tonic-gate 	}
17460Sstevel@tonic-gate }
17470Sstevel@tonic-gate 
17480Sstevel@tonic-gate void
recv_error(context,inbuf)17490Sstevel@tonic-gate recv_error(context, inbuf)
17500Sstevel@tonic-gate     krb5_context context;
17510Sstevel@tonic-gate     krb5_data	*inbuf;
17520Sstevel@tonic-gate {
17530Sstevel@tonic-gate 	krb5_error	*error;
17540Sstevel@tonic-gate 	krb5_error_code	retval;
17550Sstevel@tonic-gate 
17562881Smp153739 	retval = krb5_rd_error(context, inbuf, &error);
17572881Smp153739 	if (retval) {
17580Sstevel@tonic-gate 		com_err(progname, retval,
17590Sstevel@tonic-gate 			gettext("while decoding error packet from client"));
17600Sstevel@tonic-gate 		exit(1);
17610Sstevel@tonic-gate 	}
17620Sstevel@tonic-gate 	if (error->error == KRB_ERR_GENERIC) {
17630Sstevel@tonic-gate 		if (error->text.data)
17640Sstevel@tonic-gate 			fprintf(stderr,
17650Sstevel@tonic-gate 				gettext("Generic remote error: %s\n"),
17660Sstevel@tonic-gate 				error->text.data);
17670Sstevel@tonic-gate 	} else if (error->error) {
17680Sstevel@tonic-gate 		com_err(progname, error->error + ERROR_TABLE_BASE_krb5,
1769*9033SPeter.Shoults@Sun.COM 			gettext("signaled from server"));
17700Sstevel@tonic-gate 		if (error->text.data)
17710Sstevel@tonic-gate 			fprintf(stderr,
17720Sstevel@tonic-gate 				gettext("Error text from client: %s\n"),
17730Sstevel@tonic-gate 				error->text.data);
17740Sstevel@tonic-gate 	}
17750Sstevel@tonic-gate 	krb5_free_error(context, error);
17760Sstevel@tonic-gate 	exit(1);
17770Sstevel@tonic-gate }
17780Sstevel@tonic-gate 
17790Sstevel@tonic-gate void
load_database(context,kdb_util,database_file_name)17802881Smp153739 load_database(context, kdb_util, database_file_name)
17810Sstevel@tonic-gate     krb5_context context;
17822881Smp153739     char *kdb_util;
17830Sstevel@tonic-gate     char *database_file_name;
17840Sstevel@tonic-gate {
17850Sstevel@tonic-gate 	static char	*edit_av[10];
17862881Smp153739 	int	error_ret, save_stderr = -1;
17870Sstevel@tonic-gate 	int	child_pid;
17880Sstevel@tonic-gate 	int 	count;
17892881Smp153739 
17902881Smp153739 	/* <sys/param.h> has been included, so BSD will be defined on
17912881Smp153739 	   BSD systems */
17922881Smp153739 #if BSD > 0 && BSD <= 43
17932881Smp153739 #ifndef WEXITSTATUS
17942881Smp153739 #define	WEXITSTATUS(w) (w).w_retcode
17952881Smp153739 #endif
17962881Smp153739 	union wait	waitb;
17972881Smp153739 #else
17980Sstevel@tonic-gate 	int	waitb;
17992881Smp153739 #endif
18000Sstevel@tonic-gate 	krb5_error_code	retval;
18010Sstevel@tonic-gate 	kdb_log_context	*log_ctx;
18020Sstevel@tonic-gate 
18030Sstevel@tonic-gate 	if (debug)
18042881Smp153739 		printf(gettext("calling kdb_util to load database\n"));
18050Sstevel@tonic-gate 
18060Sstevel@tonic-gate 	log_ctx = context->kdblog_context;
18070Sstevel@tonic-gate 
18082881Smp153739 	edit_av[0] = kdb_util;
18090Sstevel@tonic-gate 	count = 1;
18100Sstevel@tonic-gate 	if (realm) {
18110Sstevel@tonic-gate 		edit_av[count++] = "-r";
18120Sstevel@tonic-gate 		edit_av[count++] = realm;
18130Sstevel@tonic-gate 	}
18140Sstevel@tonic-gate 	edit_av[count++] = "load";
18150Sstevel@tonic-gate 	if (kerb_database) {
18160Sstevel@tonic-gate 		edit_av[count++] = "-d";
18170Sstevel@tonic-gate 		edit_av[count++] = kerb_database;
18180Sstevel@tonic-gate 	}
18190Sstevel@tonic-gate 
18200Sstevel@tonic-gate 	if (log_ctx && (log_ctx->iproprole == IPROP_SLAVE)) {
18210Sstevel@tonic-gate 		edit_av[count++] = "-i";
18220Sstevel@tonic-gate 	}
18230Sstevel@tonic-gate 	edit_av[count++] = database_file_name;
18240Sstevel@tonic-gate 	edit_av[count++] = NULL;
18250Sstevel@tonic-gate 
18260Sstevel@tonic-gate 	switch(child_pid = fork()) {
18270Sstevel@tonic-gate 	case -1:
18280Sstevel@tonic-gate 		com_err(progname, errno, gettext("while trying to fork %s"),
18292881Smp153739 			kdb_util);
18300Sstevel@tonic-gate 		exit(1);
18310Sstevel@tonic-gate 		/*NOTREACHED*/
18320Sstevel@tonic-gate 	case 0:
18330Sstevel@tonic-gate 		if (!debug) {
18340Sstevel@tonic-gate 			save_stderr = dup(2);
18350Sstevel@tonic-gate 			close(0);
18360Sstevel@tonic-gate 			close(1);
18370Sstevel@tonic-gate 			close(2);
18380Sstevel@tonic-gate 			open("/dev/null", O_RDWR);
18390Sstevel@tonic-gate 			dup(0);
18400Sstevel@tonic-gate 			dup(0);
18410Sstevel@tonic-gate 		}
18420Sstevel@tonic-gate 
18432881Smp153739 		execv(kdb_util, edit_av);
18440Sstevel@tonic-gate 		retval = errno;
18450Sstevel@tonic-gate 		if (!debug)
18460Sstevel@tonic-gate 			dup2(save_stderr, 2);
18470Sstevel@tonic-gate 		com_err(progname, retval, gettext("while trying to exec %s"),
18482881Smp153739 			kdb_util);
18490Sstevel@tonic-gate 		_exit(1);
18500Sstevel@tonic-gate 		/*NOTREACHED*/
18510Sstevel@tonic-gate 	default:
18520Sstevel@tonic-gate 		if (debug)
18530Sstevel@tonic-gate 		    printf(gettext("Child PID is %d\n"), child_pid);
18540Sstevel@tonic-gate 		if (wait(&waitb) < 0) {
18550Sstevel@tonic-gate 			com_err(progname, errno, gettext("while waiting for %s"),
18562881Smp153739 				kdb_util);
18570Sstevel@tonic-gate 			exit(1);
18580Sstevel@tonic-gate 		}
18590Sstevel@tonic-gate 	}
18600Sstevel@tonic-gate 
18612881Smp153739 	error_ret = WEXITSTATUS(waitb);
18622881Smp153739 	if (error_ret) {
18630Sstevel@tonic-gate 		com_err(progname, 0,
18642881Smp153739 		    gettext("%s returned a bad exit status (%d)"),
18652881Smp153739 			kdb_util, error_ret);
18660Sstevel@tonic-gate 		exit(1);
18670Sstevel@tonic-gate 	}
18680Sstevel@tonic-gate 	return;
18690Sstevel@tonic-gate }
1870