xref: /onnv-gate/usr/src/cmd/krb5/kadmin/server/ovsec_kadmd.c (revision 11208:2efe153f06fe)
10Sstevel@tonic-gate /*
211157SMark.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 
60Sstevel@tonic-gate 
70Sstevel@tonic-gate /*
80Sstevel@tonic-gate  * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
90Sstevel@tonic-gate  *
100Sstevel@tonic-gate  *	Openvision retains the copyright to derivative works of
110Sstevel@tonic-gate  *	this source code.	Do *NOT* create a derivative of this
120Sstevel@tonic-gate  *	source code before consulting with your legal department.
130Sstevel@tonic-gate  *	Do *NOT* integrate *ANY* of this source code into another
140Sstevel@tonic-gate  *	product before consulting with your legal department.
150Sstevel@tonic-gate  *
160Sstevel@tonic-gate  *	For further information, read the top-level Openvision
170Sstevel@tonic-gate  *	copyright which is contained in the top-level MIT Kerberos
180Sstevel@tonic-gate  *	copyright.
190Sstevel@tonic-gate  *
200Sstevel@tonic-gate  * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
210Sstevel@tonic-gate  *
220Sstevel@tonic-gate  */
230Sstevel@tonic-gate 
240Sstevel@tonic-gate /*
250Sstevel@tonic-gate  * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved
267934SMark.Phalan@Sun.COM  *
270Sstevel@tonic-gate  */
280Sstevel@tonic-gate 
290Sstevel@tonic-gate /*
302881Smp153739  * Copyright (C) 1998 by the FundsXpress, INC.
312881Smp153739  *
322881Smp153739  * All rights reserved.
332881Smp153739  *
342881Smp153739  * Export of this software from the United States of America may require
352881Smp153739  * a specific license from the United States Government.  It is the
362881Smp153739  * responsibility of any person or organization contemplating export to
372881Smp153739  * obtain such a license before exporting.
382881Smp153739  *
392881Smp153739  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
402881Smp153739  * distribute this software and its documentation for any purpose and
412881Smp153739  * without fee is hereby granted, provided that the above copyright
422881Smp153739  * notice appear in all copies and that both that copyright notice and
432881Smp153739  * this permission notice appear in supporting documentation, and that
442881Smp153739  * the name of FundsXpress. not be used in advertising or publicity pertaining
452881Smp153739  * to distribution of the software without specific, written prior
462881Smp153739  * permission.  FundsXpress makes no representations about the suitability of
472881Smp153739  * this software for any purpose.  It is provided "as is" without express
482881Smp153739  * or implied warranty.
492881Smp153739  *
502881Smp153739  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
512881Smp153739  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
522881Smp153739  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
532881Smp153739  */
542881Smp153739 
552881Smp153739 
562881Smp153739 /*
570Sstevel@tonic-gate  * SUNWresync121 XXX
580Sstevel@tonic-gate  * Beware future resyncers, this file is much diff from MIT (1.0...)
590Sstevel@tonic-gate  */
600Sstevel@tonic-gate 
612881Smp153739 #include    <stdio.h>
622881Smp153739 #include    <stdio_ext.h>
632881Smp153739 #include    <signal.h>
642881Smp153739 #include    <syslog.h>
652881Smp153739 #include    <sys/types.h>
662881Smp153739 #ifdef _AIX
672881Smp153739 #include    <sys/select.h>
682881Smp153739 #endif
692881Smp153739 #include    <sys/time.h>
702881Smp153739 #include    <sys/socket.h>
712881Smp153739 #include    <unistd.h>
722881Smp153739 #include    <netinet/in.h>
732881Smp153739 #include    <arpa/inet.h>  /* inet_ntoa */
742881Smp153739 #include    <gssapi/gssapi.h>
757934SMark.Phalan@Sun.COM #include    "gssapiP_krb5.h" /* for kg_get_context */
762881Smp153739 #include    <rpc/rpc.h>
772881Smp153739 #include    <kadm5/admin.h>
782881Smp153739 #include    <kadm5/kadm_rpc.h>
792881Smp153739 #include    <server_acl.h>
802881Smp153739 #include    <krb5/adm_proto.h>
817934SMark.Phalan@Sun.COM #include    "kdb_kt.h"	/* for krb5_ktkdb_set_context */
822881Smp153739 #include    <string.h>
832881Smp153739 #include    <kadm5/server_internal.h>
842881Smp153739 #include    <gssapi_krb5.h>
852881Smp153739 #include    <libintl.h>
862881Smp153739 #include    <locale.h>
872881Smp153739 #include    <sys/resource.h>
882881Smp153739 #include    <kdb/kdb_log.h>
894960Swillf #include    <kdb_kt.h>
900Sstevel@tonic-gate 
910Sstevel@tonic-gate #include <rpc/rpcsec_gss.h>
922881Smp153739 #include    "misc.h"
930Sstevel@tonic-gate 
947934SMark.Phalan@Sun.COM #ifdef PURIFY
957934SMark.Phalan@Sun.COM #include    "purify.h"
967934SMark.Phalan@Sun.COM 
977934SMark.Phalan@Sun.COM int	signal_pure_report = 0;
987934SMark.Phalan@Sun.COM int	signal_pure_clear = 0;
997934SMark.Phalan@Sun.COM void	request_pure_report(int);
1007934SMark.Phalan@Sun.COM void	request_pure_clear(int);
1017934SMark.Phalan@Sun.COM #endif /* PURIFY */
1027934SMark.Phalan@Sun.COM 
1037934SMark.Phalan@Sun.COM 
1040Sstevel@tonic-gate #ifndef	FD_SETSIZE
1050Sstevel@tonic-gate #define	FD_SETSIZE	256
1060Sstevel@tonic-gate #endif
1070Sstevel@tonic-gate 
1080Sstevel@tonic-gate #ifndef MAX
1090Sstevel@tonic-gate #define	MAX(a, b)	(((a) > (b)) ? (a) : (b))
1100Sstevel@tonic-gate #endif
1110Sstevel@tonic-gate 
1122881Smp153739 #if defined(NEED_DAEMON_PROTO)
1132881Smp153739 extern int daemon(int, int);
1142881Smp153739 #endif
1152881Smp153739 
1167934SMark.Phalan@Sun.COM static int	signal_request_exit = 0;
1170Sstevel@tonic-gate kadm5_config_params chgpw_params;
1187934SMark.Phalan@Sun.COM void    setup_signal_handlers(iprop_role iproprole);
1197934SMark.Phalan@Sun.COM void	request_exit(int);
1207934SMark.Phalan@Sun.COM void	sig_pipe(int);
1217934SMark.Phalan@Sun.COM void	kadm_svc_run(void);
1220Sstevel@tonic-gate 
1230Sstevel@tonic-gate #ifdef POSIX_SIGNALS
1240Sstevel@tonic-gate static struct sigaction s_action;
1250Sstevel@tonic-gate #endif /* POSIX_SIGNALS */
1260Sstevel@tonic-gate 
1272881Smp153739 
1280Sstevel@tonic-gate #define	TIMEOUT	15
1290Sstevel@tonic-gate 
1300Sstevel@tonic-gate typedef struct _auth_gssapi_name {
1310Sstevel@tonic-gate 	char *name;
1320Sstevel@tonic-gate 	gss_OID type;
1330Sstevel@tonic-gate } auth_gssapi_name;
1340Sstevel@tonic-gate 
1350Sstevel@tonic-gate gss_name_t gss_changepw_name = NULL, gss_oldchangepw_name = NULL;
1360Sstevel@tonic-gate void *global_server_handle;
1370Sstevel@tonic-gate 
1380Sstevel@tonic-gate /*
1390Sstevel@tonic-gate  * This is a kludge, but the server needs these constants to be
1402881Smp153739  * compatible with old clients.  They are defined in <kadm5/admin.h>,
1410Sstevel@tonic-gate  * but only if USE_KADM5_API_VERSION == 1.
1420Sstevel@tonic-gate  */
1437934SMark.Phalan@Sun.COM #define OVSEC_KADM_ADMIN_SERVICE_P	"ovsec_adm@admin"
1447934SMark.Phalan@Sun.COM #define OVSEC_KADM_CHANGEPW_SERVICE_P	"ovsec_adm@changepw"
1450Sstevel@tonic-gate 
1460Sstevel@tonic-gate 
1470Sstevel@tonic-gate extern void krb5_iprop_prog_1();
1480Sstevel@tonic-gate extern kadm5_ret_t kiprop_get_adm_host_srv_name(
1490Sstevel@tonic-gate 	krb5_context,
1500Sstevel@tonic-gate 	const char *,
1510Sstevel@tonic-gate 	char **);
1520Sstevel@tonic-gate 
1537934SMark.Phalan@Sun.COM static int schpw;
1540Sstevel@tonic-gate 
1552881Smp153739 
1560Sstevel@tonic-gate in_port_t l_port = 0;	/* global local port num, for BSM audits */
1570Sstevel@tonic-gate 
1580Sstevel@tonic-gate int nofork = 0; /* global; don't fork (debug mode) */
1590Sstevel@tonic-gate 
1600Sstevel@tonic-gate 
1610Sstevel@tonic-gate /*
1620Sstevel@tonic-gate  * Function: usage
1632881Smp153739  *
1640Sstevel@tonic-gate  * Purpose: print out the server usage message
1650Sstevel@tonic-gate  *
1660Sstevel@tonic-gate  * Arguments:
1670Sstevel@tonic-gate  * Requires:
1680Sstevel@tonic-gate  * Effects:
1690Sstevel@tonic-gate  * Modifies:
1700Sstevel@tonic-gate  */
1710Sstevel@tonic-gate 
usage()1722881Smp153739 static void usage()
1730Sstevel@tonic-gate {
1747934SMark.Phalan@Sun.COM      fprintf(stderr, gettext("Usage: kadmind [-x db_args]* [-r realm] [-m] [-d] "
1757934SMark.Phalan@Sun.COM          "[-p port-number]\n"));
1767934SMark.Phalan@Sun.COM      exit(1);
1770Sstevel@tonic-gate }
1780Sstevel@tonic-gate 
1790Sstevel@tonic-gate /*
1800Sstevel@tonic-gate  * Function: display_status
1810Sstevel@tonic-gate  *
1820Sstevel@tonic-gate  * Purpose: displays GSS-API messages
1830Sstevel@tonic-gate  *
1840Sstevel@tonic-gate  * Arguments:
1850Sstevel@tonic-gate  *
1860Sstevel@tonic-gate  * 	msg		a string to be displayed with the message
1870Sstevel@tonic-gate  * 	maj_stat	the GSS-API major status code
1880Sstevel@tonic-gate  * 	min_stat	the GSS-API minor status code
1890Sstevel@tonic-gate  *
1900Sstevel@tonic-gate  * Effects:
1910Sstevel@tonic-gate  *
1920Sstevel@tonic-gate  * The GSS-API messages associated with maj_stat and min_stat are
1930Sstevel@tonic-gate  * displayed on stderr, each preceeded by "GSS-API error <msg>: " and
1940Sstevel@tonic-gate  * followed by a newline.
1950Sstevel@tonic-gate  */
1962881Smp153739 static void display_status_1(char *, OM_uint32, int);
1970Sstevel@tonic-gate 
display_status(msg,maj_stat,min_stat)1982881Smp153739 static void display_status(msg, maj_stat, min_stat)
1990Sstevel@tonic-gate      char *msg;
2000Sstevel@tonic-gate      OM_uint32 maj_stat;
2010Sstevel@tonic-gate      OM_uint32 min_stat;
2020Sstevel@tonic-gate {
2030Sstevel@tonic-gate      display_status_1(msg, maj_stat, GSS_C_GSS_CODE);
2040Sstevel@tonic-gate      display_status_1(msg, min_stat, GSS_C_MECH_CODE);
2050Sstevel@tonic-gate }
2060Sstevel@tonic-gate 
display_status_1(m,code,type)2070Sstevel@tonic-gate static void display_status_1(m, code, type)
2080Sstevel@tonic-gate      char *m;
2090Sstevel@tonic-gate      OM_uint32 code;
2100Sstevel@tonic-gate      int type;
2110Sstevel@tonic-gate {
2120Sstevel@tonic-gate 	OM_uint32 maj_stat, min_stat;
2130Sstevel@tonic-gate 	gss_buffer_desc msg;
2140Sstevel@tonic-gate 	OM_uint32 msg_ctx;
2150Sstevel@tonic-gate 
2160Sstevel@tonic-gate 	msg_ctx = 0;
2170Sstevel@tonic-gate 	while (1) {
2180Sstevel@tonic-gate 		maj_stat = gss_display_status(&min_stat, code,
2190Sstevel@tonic-gate 					      type, GSS_C_NULL_OID,
2200Sstevel@tonic-gate 					      &msg_ctx, &msg);
2210Sstevel@tonic-gate 		fprintf(stderr, "GSS-API error %s: %s\n", m,
2220Sstevel@tonic-gate 			(char *)msg.value);
2230Sstevel@tonic-gate 		(void) gss_release_buffer(&min_stat, &msg);
2240Sstevel@tonic-gate 
2250Sstevel@tonic-gate 		if (!msg_ctx)
2260Sstevel@tonic-gate 			break;
2270Sstevel@tonic-gate 	}
2280Sstevel@tonic-gate }
2290Sstevel@tonic-gate 
2300Sstevel@tonic-gate 
2310Sstevel@tonic-gate /*
2320Sstevel@tonic-gate  * Solaris Kerberos: the following prototypes are needed because these are
2330Sstevel@tonic-gate  * private interfaces that do not have prototypes in any .h
2340Sstevel@tonic-gate  */
2350Sstevel@tonic-gate 
2360Sstevel@tonic-gate extern struct hostent   *res_getipnodebyaddr(const void *, size_t, int, int *);
2370Sstevel@tonic-gate extern void             res_freehostent(struct hostent *);
2380Sstevel@tonic-gate 
2390Sstevel@tonic-gate static void
freedomnames(char ** npp)2400Sstevel@tonic-gate freedomnames(char **npp)
2410Sstevel@tonic-gate {
2420Sstevel@tonic-gate 	char **tpp;
2430Sstevel@tonic-gate 
2440Sstevel@tonic-gate 	if (npp) {
2450Sstevel@tonic-gate 		tpp = npp;
2460Sstevel@tonic-gate 		while (*tpp++) {
2470Sstevel@tonic-gate 			free(*(tpp-1));
2480Sstevel@tonic-gate 		}
2490Sstevel@tonic-gate 		free(npp);
2500Sstevel@tonic-gate 	}
2510Sstevel@tonic-gate }
2520Sstevel@tonic-gate 
2530Sstevel@tonic-gate /*
2540Sstevel@tonic-gate  * Construct a list of uniq FQDNs of all the net interfaces (except
2550Sstevel@tonic-gate  * krb5.conf master dups) and return it in arg 'dnames'.
2560Sstevel@tonic-gate  *
2570Sstevel@tonic-gate  * On successful return (0), caller must call freedomnames()
2580Sstevel@tonic-gate  * to free memory.
2590Sstevel@tonic-gate  */
2600Sstevel@tonic-gate static int
getdomnames(krb5_context ctx,char * realm,char *** dnames)2610Sstevel@tonic-gate getdomnames(krb5_context ctx, char *realm, char ***dnames)
2620Sstevel@tonic-gate {
2630Sstevel@tonic-gate 	krb5_address **addresses = NULL;
2640Sstevel@tonic-gate 	krb5_address *a = NULL;
2650Sstevel@tonic-gate 	struct hostent *hp = NULL;
2660Sstevel@tonic-gate 	int ret, i, result=0, error;
2670Sstevel@tonic-gate 	char **npp = NULL, **tpp=NULL;
2680Sstevel@tonic-gate 	int dup=0, n = 0;
2690Sstevel@tonic-gate 	char *cfhost = NULL; /* krb5 conf file master hostname */
2700Sstevel@tonic-gate 
2710Sstevel@tonic-gate 	if (ret = kadm5_get_master(ctx, realm, &cfhost)) {
2720Sstevel@tonic-gate 		return (ret);
2730Sstevel@tonic-gate 	}
2740Sstevel@tonic-gate 
2750Sstevel@tonic-gate 	ret = krb5_os_localaddr(ctx, &addresses);
2760Sstevel@tonic-gate 	if (ret != 0) {
2770Sstevel@tonic-gate 		if (nofork)
2780Sstevel@tonic-gate 			(void) fprintf(stderr,
2790Sstevel@tonic-gate 				    "kadmind: get localaddrs failed: %s",
2800Sstevel@tonic-gate 				    error_message(ret));
2810Sstevel@tonic-gate 		result = ret;
2820Sstevel@tonic-gate 		goto err;
2830Sstevel@tonic-gate 	}
2840Sstevel@tonic-gate 
2850Sstevel@tonic-gate 
2860Sstevel@tonic-gate 	for (i=0; addresses[i]; i++) {
2870Sstevel@tonic-gate 		a = addresses[i];
2880Sstevel@tonic-gate 		hp = res_getipnodebyaddr(a->contents, a->length,
2890Sstevel@tonic-gate 					a->addrtype == ADDRTYPE_INET
2900Sstevel@tonic-gate 					? AF_INET : AF_INET6,
2910Sstevel@tonic-gate 					&error);
2920Sstevel@tonic-gate 		if (hp != NULL) {
2930Sstevel@tonic-gate 
2940Sstevel@tonic-gate 			/* skip master host in krb5.conf */
2950Sstevel@tonic-gate 			if (strcasecmp(cfhost, hp->h_name) == 0) {
2960Sstevel@tonic-gate 				res_freehostent(hp);
2970Sstevel@tonic-gate 				hp = NULL;
2980Sstevel@tonic-gate 				continue;
2990Sstevel@tonic-gate 			}
3000Sstevel@tonic-gate 
3010Sstevel@tonic-gate 			dup = 0;
3020Sstevel@tonic-gate 			tpp = npp;
3030Sstevel@tonic-gate 			/* skip if hostname already exists in list */
3040Sstevel@tonic-gate 			while (tpp && *tpp++) {
3050Sstevel@tonic-gate 				if (strcasecmp(*(tpp-1), hp->h_name) == 0) {
3060Sstevel@tonic-gate 					dup++;
3070Sstevel@tonic-gate 					break;
3080Sstevel@tonic-gate 				}
3090Sstevel@tonic-gate 			}
3100Sstevel@tonic-gate 
3110Sstevel@tonic-gate 			if (dup) {
3120Sstevel@tonic-gate 				res_freehostent(hp);
3130Sstevel@tonic-gate 				hp = NULL;
3140Sstevel@tonic-gate 				continue;
3150Sstevel@tonic-gate 			}
3160Sstevel@tonic-gate 
3170Sstevel@tonic-gate 			npp = realloc(npp, sizeof(char *) * (n + 2));
3180Sstevel@tonic-gate 			if (!npp) {
3190Sstevel@tonic-gate 				result = ENOMEM;
3200Sstevel@tonic-gate 				goto err;
3210Sstevel@tonic-gate 			}
3220Sstevel@tonic-gate 			npp[n] = strdup(hp->h_name);
3230Sstevel@tonic-gate 			if (!npp[n]) {
3240Sstevel@tonic-gate 				result = ENOMEM;
3250Sstevel@tonic-gate 				goto err;
3260Sstevel@tonic-gate 			}
3270Sstevel@tonic-gate 			npp[n+1] = NULL;
3280Sstevel@tonic-gate 			n++;
3290Sstevel@tonic-gate 
3300Sstevel@tonic-gate 			res_freehostent(hp);
3310Sstevel@tonic-gate 			hp = NULL;
3320Sstevel@tonic-gate 			result = 0;
3330Sstevel@tonic-gate 		}
3340Sstevel@tonic-gate 
3350Sstevel@tonic-gate 	}
3360Sstevel@tonic-gate 
3370Sstevel@tonic-gate #ifdef DEBUG
3380Sstevel@tonic-gate 	printf("getdomnames: n=%d, i=%d, npp=%p\n", n, i, npp);
3390Sstevel@tonic-gate 	tpp = npp;
3400Sstevel@tonic-gate 	while (tpp && *tpp++) {
3410Sstevel@tonic-gate 		printf("tpp=%s\n", *(tpp-1));
3420Sstevel@tonic-gate 	}
3430Sstevel@tonic-gate #endif
3440Sstevel@tonic-gate 
3450Sstevel@tonic-gate 	goto out;
3460Sstevel@tonic-gate 
3470Sstevel@tonic-gate err:
3480Sstevel@tonic-gate 	if (npp) {
3490Sstevel@tonic-gate 		freedomnames(npp);
3500Sstevel@tonic-gate 		npp = NULL;
3510Sstevel@tonic-gate 	}
3520Sstevel@tonic-gate 
3530Sstevel@tonic-gate 	if (hp) {
3540Sstevel@tonic-gate 		res_freehostent(hp);
3550Sstevel@tonic-gate 		hp = NULL;
3560Sstevel@tonic-gate 	}
3570Sstevel@tonic-gate 
3580Sstevel@tonic-gate out:
3590Sstevel@tonic-gate 	if (cfhost) {
3600Sstevel@tonic-gate 		free (cfhost);
3610Sstevel@tonic-gate 		cfhost = NULL;
3620Sstevel@tonic-gate 	}
3630Sstevel@tonic-gate 	if (addresses) {
3640Sstevel@tonic-gate 		krb5_free_addresses(ctx, addresses);
3650Sstevel@tonic-gate 		addresses = NULL;
3660Sstevel@tonic-gate 	}
3670Sstevel@tonic-gate 
3680Sstevel@tonic-gate 	if (result == 0)
3690Sstevel@tonic-gate 		*dnames = npp;
3700Sstevel@tonic-gate 
3710Sstevel@tonic-gate 	return (result);
3720Sstevel@tonic-gate }
3730Sstevel@tonic-gate 
3740Sstevel@tonic-gate /*
3750Sstevel@tonic-gate  * Set the rpcsec_gss svc names for all net interfaces.
3760Sstevel@tonic-gate  */
3770Sstevel@tonic-gate static void
set_svc_domnames(char * svcname,char ** dnames,u_int program,u_int version)3780Sstevel@tonic-gate set_svc_domnames(char *svcname, char **dnames,
3790Sstevel@tonic-gate 		u_int program, u_int version)
3800Sstevel@tonic-gate {
3810Sstevel@tonic-gate 	bool_t ret;
3820Sstevel@tonic-gate 	char **tpp = dnames;
3830Sstevel@tonic-gate 
3840Sstevel@tonic-gate 	if (!tpp)
3850Sstevel@tonic-gate 		return;
3860Sstevel@tonic-gate 
3870Sstevel@tonic-gate 	while (*tpp++) {
3880Sstevel@tonic-gate 		/* MAX_NAME_LEN from rpc/rpcsec_gss.h */
3890Sstevel@tonic-gate 		char name[MAXHOSTNAMELEN+MAX_NAME_LEN+2] = {0};
3900Sstevel@tonic-gate 		(void) snprintf(name, sizeof(name), "%s@%s",
3910Sstevel@tonic-gate 				svcname, *(tpp-1));
3920Sstevel@tonic-gate 		ret = rpc_gss_set_svc_name(name,
3930Sstevel@tonic-gate 					"kerberos_v5", 0,
3940Sstevel@tonic-gate 					program, version);
3950Sstevel@tonic-gate 		if (nofork && ret)
3960Sstevel@tonic-gate 			(void) fprintf(stderr,
3970Sstevel@tonic-gate 				    "rpc_gss_set_svc_name success: %s\n",
3980Sstevel@tonic-gate 				    name);
3990Sstevel@tonic-gate 	}
4000Sstevel@tonic-gate }
4010Sstevel@tonic-gate 
4027934SMark.Phalan@Sun.COM /* XXX yuck.  the signal handlers need this */
4037934SMark.Phalan@Sun.COM static krb5_context context;
4040Sstevel@tonic-gate 
4057934SMark.Phalan@Sun.COM static krb5_context hctx;
4067934SMark.Phalan@Sun.COM 
main(int argc,char * argv[])4077934SMark.Phalan@Sun.COM int main(int argc, char *argv[])
4080Sstevel@tonic-gate {
4097934SMark.Phalan@Sun.COM      register	SVCXPRT *transp;
4107934SMark.Phalan@Sun.COM      extern	char *optarg;
4117934SMark.Phalan@Sun.COM      extern	int optind, opterr;
4127934SMark.Phalan@Sun.COM      int ret, rlen, oldnames = 0;
4137934SMark.Phalan@Sun.COM      OM_uint32 OMret, major_status, minor_status;
4147934SMark.Phalan@Sun.COM      char *whoami;
4157934SMark.Phalan@Sun.COM      FILE *acl_file;
4167934SMark.Phalan@Sun.COM      gss_buffer_desc in_buf;
4177934SMark.Phalan@Sun.COM      struct servent *srv;
4187934SMark.Phalan@Sun.COM      struct sockaddr_in addr;
4197934SMark.Phalan@Sun.COM      struct sockaddr_in *sin;
4207934SMark.Phalan@Sun.COM      int s;
4217934SMark.Phalan@Sun.COM      auth_gssapi_name names[6];
4227934SMark.Phalan@Sun.COM      gss_buffer_desc gssbuf;
4237934SMark.Phalan@Sun.COM      gss_OID nt_krb5_name_oid;
4247934SMark.Phalan@Sun.COM      int optchar;
4257934SMark.Phalan@Sun.COM      struct netconfig *nconf;
4267934SMark.Phalan@Sun.COM      void *handlep;
4277934SMark.Phalan@Sun.COM      int fd;
4287934SMark.Phalan@Sun.COM      struct t_info tinfo;
4297934SMark.Phalan@Sun.COM      struct t_bind tbindstr, *tres;
4300Sstevel@tonic-gate 
4317934SMark.Phalan@Sun.COM      struct t_optmgmt req, resp;
4327934SMark.Phalan@Sun.COM      struct opthdr *opt;
4337934SMark.Phalan@Sun.COM      char reqbuf[128];
4347934SMark.Phalan@Sun.COM      struct rlimit rl;
4357934SMark.Phalan@Sun.COM 
4367934SMark.Phalan@Sun.COM      char *kiprop_name = NULL; /* IProp svc name */
4377934SMark.Phalan@Sun.COM      kdb_log_context *log_ctx;
4387934SMark.Phalan@Sun.COM      kadm5_server_handle_t handle;
4397934SMark.Phalan@Sun.COM      krb5_context ctx;
4407934SMark.Phalan@Sun.COM 
4417934SMark.Phalan@Sun.COM      kadm5_config_params params;
4427934SMark.Phalan@Sun.COM      char **db_args      = NULL;
4437934SMark.Phalan@Sun.COM      int    db_args_size = 0;
4447934SMark.Phalan@Sun.COM      const char *errmsg;
4457934SMark.Phalan@Sun.COM      char **dnames = NULL;
4467934SMark.Phalan@Sun.COM      int retdn;
4477934SMark.Phalan@Sun.COM      int iprop_supported;
4486426Smp153739 
4497934SMark.Phalan@Sun.COM      /* Solaris Kerberos: Stores additional error messages */
4507934SMark.Phalan@Sun.COM      char *emsg = NULL;
4517934SMark.Phalan@Sun.COM 
4527934SMark.Phalan@Sun.COM      /* Solaris Kerberos: Indicates whether loalhost is master or not */
4537934SMark.Phalan@Sun.COM      krb5_boolean is_master;
4547934SMark.Phalan@Sun.COM 
4557934SMark.Phalan@Sun.COM      /* Solaris Kerberos: Used for checking acl file */
4567934SMark.Phalan@Sun.COM      gss_name_t name;
4570Sstevel@tonic-gate 
4587934SMark.Phalan@Sun.COM      /* This is OID value the Krb5_Name NameType */
4597934SMark.Phalan@Sun.COM      gssbuf.value = "{1 2 840 113554 1 2 2 1}";
4607934SMark.Phalan@Sun.COM      gssbuf.length = strlen(gssbuf.value);
4617934SMark.Phalan@Sun.COM      major_status = gss_str_to_oid(&minor_status, &gssbuf, &nt_krb5_name_oid);
4627934SMark.Phalan@Sun.COM      if (major_status != GSS_S_COMPLETE) {
4637934SMark.Phalan@Sun.COM 	     fprintf(stderr,
4647934SMark.Phalan@Sun.COM 	         gettext("Couldn't create KRB5 Name NameType OID\n"));
4657934SMark.Phalan@Sun.COM 	     display_status("str_to_oid", major_status, minor_status);
4667934SMark.Phalan@Sun.COM 	     exit(1);
4677934SMark.Phalan@Sun.COM      }
4680Sstevel@tonic-gate 
4697934SMark.Phalan@Sun.COM      names[0].name = names[1].name = names[2].name = names[3].name = NULL;
4707934SMark.Phalan@Sun.COM      names[4].name  = names[5].name =NULL;
4717934SMark.Phalan@Sun.COM      names[0].type = names[1].type = names[2].type = names[3].type =
4727934SMark.Phalan@Sun.COM 	    (gss_OID) nt_krb5_name_oid;
4737934SMark.Phalan@Sun.COM      names[4].type = names[5].type = (gss_OID) nt_krb5_name_oid;
4747934SMark.Phalan@Sun.COM 
4757934SMark.Phalan@Sun.COM #ifdef PURIFY
4767934SMark.Phalan@Sun.COM      purify_start_batch();
4777934SMark.Phalan@Sun.COM #endif /* PURIFY */
4787934SMark.Phalan@Sun.COM      whoami = (strrchr(argv[0], '/') ? strrchr(argv[0], '/')+1 : argv[0]);
4790Sstevel@tonic-gate 
4800Sstevel@tonic-gate 	(void) setlocale(LC_ALL, "");
4810Sstevel@tonic-gate 
4820Sstevel@tonic-gate #if !defined(TEXT_DOMAIN)  /* Should be defined by cc -D */
4830Sstevel@tonic-gate #define	TEXT_DOMAIN	"SYS_TEST"	/* Use this only if it weren't */
4840Sstevel@tonic-gate #endif
4850Sstevel@tonic-gate 
4860Sstevel@tonic-gate 	(void) textdomain(TEXT_DOMAIN);
4870Sstevel@tonic-gate 
4887934SMark.Phalan@Sun.COM      nofork = 0;
4890Sstevel@tonic-gate 
4907934SMark.Phalan@Sun.COM      memset((char *) &params, 0, sizeof(params));
4910Sstevel@tonic-gate 
4924960Swillf 	while ((optchar = getopt(argc, argv, "r:mdp:x:")) != EOF) {
4930Sstevel@tonic-gate 		switch (optchar) {
4940Sstevel@tonic-gate 		case 'r':
4950Sstevel@tonic-gate 			if (!optarg)
4960Sstevel@tonic-gate 				usage();
4970Sstevel@tonic-gate 			params.realm = optarg;
4980Sstevel@tonic-gate 			params.mask |= KADM5_CONFIG_REALM;
4990Sstevel@tonic-gate 			break;
5000Sstevel@tonic-gate 		case 'm':
5010Sstevel@tonic-gate 			params.mkey_from_kbd = 1;
5020Sstevel@tonic-gate 			params.mask |= KADM5_CONFIG_MKEY_FROM_KBD;
5030Sstevel@tonic-gate 			break;
5040Sstevel@tonic-gate 		case 'd':
5050Sstevel@tonic-gate 			nofork = 1;
5060Sstevel@tonic-gate 			break;
5070Sstevel@tonic-gate 		case 'p':
5080Sstevel@tonic-gate 			if (!optarg)
5090Sstevel@tonic-gate 				usage();
5100Sstevel@tonic-gate 			params.kadmind_port = atoi(optarg);
5110Sstevel@tonic-gate 			params.mask |= KADM5_CONFIG_KADMIND_PORT;
5120Sstevel@tonic-gate 			break;
5134960Swillf 		case 'x':
5144960Swillf 			if (!optarg)
5154960Swillf 				usage();
5164960Swillf 			db_args_size++;
5174960Swillf 			{
5184960Swillf 			    char **temp = realloc( db_args,
5194960Swillf 				sizeof(char*) * (db_args_size+1)); /* one for NULL */
5204960Swillf 			    if( temp == NULL )
5214960Swillf 			    {
5224960Swillf 				fprintf(stderr, gettext("%s: cannot initialize. Not enough memory\n"),
5234960Swillf 				    whoami);
5244960Swillf 				exit(1);
5254960Swillf 			    }
5264960Swillf 			    db_args = temp;
5274960Swillf 			}
5284960Swillf 			db_args[db_args_size-1] = optarg;
5294960Swillf 			db_args[db_args_size]   = NULL;
5304960Swillf 			break;
5310Sstevel@tonic-gate 		case '?':
5320Sstevel@tonic-gate 		default:
5330Sstevel@tonic-gate 			usage();
5340Sstevel@tonic-gate 		}
5350Sstevel@tonic-gate 	}
5360Sstevel@tonic-gate 
5370Sstevel@tonic-gate 
5380Sstevel@tonic-gate 	if (getrlimit(RLIMIT_NOFILE, &rl) == 0) {
5390Sstevel@tonic-gate 		rl.rlim_cur = rl.rlim_max = MAX(rl.rlim_max, FD_SETSIZE);
5401914Scasper 		(void) setrlimit(RLIMIT_NOFILE, &rl);
5411914Scasper 		(void) enable_extended_FILE_stdio(-1, -1);
5420Sstevel@tonic-gate 	}
5430Sstevel@tonic-gate 
5447934SMark.Phalan@Sun.COM      if ((ret = kadm5_init_krb5_context(&context))) {
5457934SMark.Phalan@Sun.COM 	  fprintf(stderr,
5467934SMark.Phalan@Sun.COM 	      gettext("%s: %s while initializing context, aborting\n"),
5477934SMark.Phalan@Sun.COM 		  whoami, error_message(ret));
5487934SMark.Phalan@Sun.COM 	  exit(1);
5497934SMark.Phalan@Sun.COM      }
5507934SMark.Phalan@Sun.COM 
5517934SMark.Phalan@Sun.COM      krb5_klog_init(context, "admin_server", whoami, 1);
5527934SMark.Phalan@Sun.COM 
5537934SMark.Phalan@Sun.COM      /* Solaris Kerberos */
5547934SMark.Phalan@Sun.COM      if((ret = kadm5_init2("kadmind", NULL,
5557934SMark.Phalan@Sun.COM 			  NULL, &params,
5567934SMark.Phalan@Sun.COM 			  KADM5_STRUCT_VERSION,
5577934SMark.Phalan@Sun.COM 			  KADM5_API_VERSION_2,
5587934SMark.Phalan@Sun.COM 			  db_args,
5597934SMark.Phalan@Sun.COM 			  &global_server_handle,
5607934SMark.Phalan@Sun.COM 			  &emsg)) != KADM5_OK) {
5617934SMark.Phalan@Sun.COM 	  krb5_klog_syslog(LOG_ERR,
5627934SMark.Phalan@Sun.COM 		gettext("%s while initializing, aborting"),
5637934SMark.Phalan@Sun.COM 			   (emsg ? emsg : error_message(ret)));
5647934SMark.Phalan@Sun.COM 	  fprintf(stderr,
5657934SMark.Phalan@Sun.COM      	    gettext("%s: %s while initializing, aborting\n"),
5667934SMark.Phalan@Sun.COM 		  whoami, (emsg ? emsg : error_message(ret)));
5677934SMark.Phalan@Sun.COM 	  if (emsg)
5687934SMark.Phalan@Sun.COM 		free(emsg);
5697934SMark.Phalan@Sun.COM 	  krb5_klog_close(context);
5707934SMark.Phalan@Sun.COM 	  exit(1);
5717934SMark.Phalan@Sun.COM      }
5720Sstevel@tonic-gate 
5737934SMark.Phalan@Sun.COM      if( db_args )
5747934SMark.Phalan@Sun.COM      {
5757934SMark.Phalan@Sun.COM 	 free(db_args), db_args=NULL;
5767934SMark.Phalan@Sun.COM      }
5777934SMark.Phalan@Sun.COM 
5787934SMark.Phalan@Sun.COM      if ((ret = kadm5_get_config_params(context, 1, &params,
5797934SMark.Phalan@Sun.COM 					&params))) {
5807934SMark.Phalan@Sun.COM 	  const char *e_txt = krb5_get_error_message (context, ret);
5817934SMark.Phalan@Sun.COM 	  /* Solaris Kerberos: Remove double "whoami" */
5827934SMark.Phalan@Sun.COM 	  krb5_klog_syslog(LOG_ERR, gettext("%s while initializing, aborting"),
5837934SMark.Phalan@Sun.COM 			   e_txt);
5847934SMark.Phalan@Sun.COM 	  fprintf(stderr,
5857934SMark.Phalan@Sun.COM 		  gettext("%s: %s while initializing, aborting\n"),
5867934SMark.Phalan@Sun.COM 		  whoami, e_txt);
5877934SMark.Phalan@Sun.COM 	  kadm5_destroy(global_server_handle);
5887934SMark.Phalan@Sun.COM 	  krb5_klog_close(context);
5897934SMark.Phalan@Sun.COM 	  exit(1);
5907934SMark.Phalan@Sun.COM      }
5917934SMark.Phalan@Sun.COM 
5927934SMark.Phalan@Sun.COM #define REQUIRED_PARAMS (KADM5_CONFIG_REALM | KADM5_CONFIG_ACL_FILE)
5937934SMark.Phalan@Sun.COM 
5947934SMark.Phalan@Sun.COM      if ((params.mask & REQUIRED_PARAMS) != REQUIRED_PARAMS) {
5957934SMark.Phalan@Sun.COM 	  /* Solaris Kerberos: Keep error messages consistent */
5967934SMark.Phalan@Sun.COM 	  krb5_klog_syslog(LOG_ERR,
5977934SMark.Phalan@Sun.COM 		gettext("Missing required configuration values (%lx)"
5987934SMark.Phalan@Sun.COM 			   "while initializing, aborting"),
5997934SMark.Phalan@Sun.COM 			   (params.mask & REQUIRED_PARAMS) ^ REQUIRED_PARAMS);
6007934SMark.Phalan@Sun.COM 	  fprintf(stderr,
6017934SMark.Phalan@Sun.COM 		    gettext("%s: Missing required configuration values "
6027934SMark.Phalan@Sun.COM 			"(%lx) while initializing, aborting\n"), whoami,
6037934SMark.Phalan@Sun.COM 		  (params.mask & REQUIRED_PARAMS) ^ REQUIRED_PARAMS);
6047934SMark.Phalan@Sun.COM 	  krb5_klog_close(context);
6057934SMark.Phalan@Sun.COM 	  kadm5_destroy(global_server_handle);
6067934SMark.Phalan@Sun.COM 	  exit(1);
6077934SMark.Phalan@Sun.COM      }
6080Sstevel@tonic-gate 
6090Sstevel@tonic-gate 	/*
6100Sstevel@tonic-gate 	 * When using the Horowitz/IETF protocol for
6110Sstevel@tonic-gate 	 * password changing, the default port is 464
6120Sstevel@tonic-gate 	 * (officially recognized by IANA)
6130Sstevel@tonic-gate 	 *
6140Sstevel@tonic-gate 	 * DEFAULT_KPASSWD_PORT -> 464
6150Sstevel@tonic-gate 	 */
6160Sstevel@tonic-gate 	chgpw_params.kpasswd_port = DEFAULT_KPASSWD_PORT;
6170Sstevel@tonic-gate 	chgpw_params.mask |= KADM5_CONFIG_KPASSWD_PORT;
6180Sstevel@tonic-gate 	chgpw_params.kpasswd_protocol = KRB5_CHGPWD_CHANGEPW_V2;
6190Sstevel@tonic-gate 	chgpw_params.mask |= KADM5_CONFIG_KPASSWD_PROTOCOL;
6200Sstevel@tonic-gate 
6217934SMark.Phalan@Sun.COM      if (ret = kadm5_get_config_params(context, 1, &chgpw_params,
6227934SMark.Phalan@Sun.COM      	&chgpw_params)) {
6237934SMark.Phalan@Sun.COM 	/* Solaris Kerberos: Remove double "whoami" */
6247934SMark.Phalan@Sun.COM      	krb5_klog_syslog(LOG_ERR, gettext("%s while initializing,"
6257934SMark.Phalan@Sun.COM      			" aborting"), error_message(ret));
6267934SMark.Phalan@Sun.COM      	fprintf(stderr,
6277934SMark.Phalan@Sun.COM      	    gettext("%s: %s while initializing, aborting\n"),
6287934SMark.Phalan@Sun.COM      	    whoami, error_message(ret));
6297934SMark.Phalan@Sun.COM      	krb5_klog_close(context);
6307934SMark.Phalan@Sun.COM      	exit(1);
6317934SMark.Phalan@Sun.COM      }
6320Sstevel@tonic-gate 
6330Sstevel@tonic-gate 	/*
6340Sstevel@tonic-gate 	 * We now setup the socket and bind() to port 464, so that
6350Sstevel@tonic-gate 	 * kadmind can now listen to and process change-pwd requests
6360Sstevel@tonic-gate 	 * from non-Solaris Kerberos V5 clients such as Microsoft,
6370Sstevel@tonic-gate 	 * MIT, AIX, HP etc
6380Sstevel@tonic-gate 	 */
6397934SMark.Phalan@Sun.COM      if ((schpw = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
6407934SMark.Phalan@Sun.COM 	 const char *e_txt = krb5_get_error_message (context, ret);
6417934SMark.Phalan@Sun.COM 	 krb5_klog_syslog(LOG_ERR,
6427934SMark.Phalan@Sun.COM 			 gettext( "Cannot create simple " "chpw socket: %s"),
6437934SMark.Phalan@Sun.COM 			  e_txt);
6447934SMark.Phalan@Sun.COM 	 fprintf(stderr, gettext("Cannot create simple chpw socket: %s"),
6457934SMark.Phalan@Sun.COM 		 e_txt);
6467934SMark.Phalan@Sun.COM 	 kadm5_destroy(global_server_handle);
6477934SMark.Phalan@Sun.COM 	 krb5_klog_close(context);
6487934SMark.Phalan@Sun.COM 	 exit(1);
6497934SMark.Phalan@Sun.COM      }
6506426Smp153739 
6516426Smp153739 	/* Solaris Kerberos: Ensure that kadmind is only run on a master kdc */
6526426Smp153739 	if (ret = kadm5_is_master(context, params.realm, &is_master)){
6536426Smp153739 		krb5_klog_syslog(LOG_ERR,
6546426Smp153739 		    gettext("Failed to determine whether host is master "
6556426Smp153739 		    "KDC for realm %s: %s"), params.realm,
6566426Smp153739 		    error_message(ret));
6576426Smp153739 		fprintf(stderr,
6586426Smp153739 		    gettext("%s: Failed to determine whether host is master "
6596426Smp153739 		    "KDC for realm %s: %s\n"), whoami, params.realm,
6606426Smp153739 		    error_message(ret));
6616426Smp153739 		krb5_klog_close(context);
6626426Smp153739 		exit(1);
6636426Smp153739 	}
6646426Smp153739 
6656426Smp153739 	if (is_master == FALSE) {
6666426Smp153739 		char *master = NULL;
6676426Smp153739 		kadm5_get_master(context, params.realm, &master);
6686426Smp153739 
6696426Smp153739 		krb5_klog_syslog(LOG_ERR,
6706426Smp153739 		    gettext("%s can only be run on the master KDC, %s, for "
6716426Smp153739 		    "realm %s"), whoami, master ? master : "unknown",
6726426Smp153739 		    params.realm);
6736426Smp153739 		fprintf(stderr,
6746426Smp153739 		    gettext("%s: %s can only be run on the master KDC, %s, for "
6756426Smp153739 		    "realm %s\n"), whoami, whoami, master ? master: "unknown",
6766426Smp153739 		    params.realm);
6776426Smp153739 		krb5_klog_close(context);
6786426Smp153739 		exit(1);
6796426Smp153739 	}
6806426Smp153739 
6817934SMark.Phalan@Sun.COM      memset((char *) &addr, 0, sizeof (struct sockaddr_in));
6827934SMark.Phalan@Sun.COM      addr.sin_family = AF_INET;
6837934SMark.Phalan@Sun.COM      addr.sin_addr.s_addr = INADDR_ANY;
6847934SMark.Phalan@Sun.COM      l_port = addr.sin_port = htons(params.kadmind_port);
6857934SMark.Phalan@Sun.COM      sin = &addr;
6860Sstevel@tonic-gate 
6870Sstevel@tonic-gate 	if ((handlep = setnetconfig()) == (void *) NULL) {
6880Sstevel@tonic-gate 		(void) krb5_klog_syslog(LOG_ERR,
6890Sstevel@tonic-gate 		    gettext("cannot get any transport information"));
6900Sstevel@tonic-gate 		krb5_klog_close(context);
6910Sstevel@tonic-gate 		exit(1);
6920Sstevel@tonic-gate 	}
6937934SMark.Phalan@Sun.COM 
6940Sstevel@tonic-gate 	while (nconf = getnetconfig(handlep)) {
6950Sstevel@tonic-gate 		if ((nconf->nc_semantics == NC_TPI_COTS_ORD) &&
6960Sstevel@tonic-gate 		    (strcmp(nconf->nc_protofmly, NC_INET) == 0) &&
6970Sstevel@tonic-gate 		    (strcmp(nconf->nc_proto, NC_TCP) == 0))
6980Sstevel@tonic-gate 			break;
6990Sstevel@tonic-gate 	}
7000Sstevel@tonic-gate 
7010Sstevel@tonic-gate 	if (nconf == (struct netconfig *) NULL) {
7020Sstevel@tonic-gate 		(void) endnetconfig(handlep);
7030Sstevel@tonic-gate 		krb5_klog_close(context);
7040Sstevel@tonic-gate 		exit(1);
7050Sstevel@tonic-gate 	}
7060Sstevel@tonic-gate 	fd = t_open(nconf->nc_device, O_RDWR, &tinfo);
7070Sstevel@tonic-gate 	if (fd == -1) {
7080Sstevel@tonic-gate 		krb5_klog_syslog(LOG_ERR,
7090Sstevel@tonic-gate 		    gettext("unable to open connection for ADMIN server"));
7100Sstevel@tonic-gate 		krb5_klog_close(context);
7110Sstevel@tonic-gate 		exit(1);
7120Sstevel@tonic-gate 	}
7130Sstevel@tonic-gate 	/* LINTED */
7140Sstevel@tonic-gate 	opt = (struct opthdr *) reqbuf;
7150Sstevel@tonic-gate 	opt->level = SOL_SOCKET;
7160Sstevel@tonic-gate 	opt->name = SO_REUSEADDR;
7170Sstevel@tonic-gate 	opt->len = sizeof (int);
7180Sstevel@tonic-gate 
7190Sstevel@tonic-gate 	/*
7200Sstevel@tonic-gate 	 * The option value is "1".  This will allow the server to restart
7210Sstevel@tonic-gate 	 * whilst the previous process is cleaning up after itself in a
7220Sstevel@tonic-gate 	 * FIN_WAIT_2 or TIME_WAIT state.  If another process is started
7230Sstevel@tonic-gate 	 * outside of smf(5) then bind will fail anyway, which is what we want.
7240Sstevel@tonic-gate 	 */
7250Sstevel@tonic-gate 	reqbuf[sizeof (struct opthdr)] = 1;
7260Sstevel@tonic-gate 
7270Sstevel@tonic-gate 	req.flags = T_NEGOTIATE;
7280Sstevel@tonic-gate 	req.opt.len = sizeof (struct opthdr) + opt->len;
7290Sstevel@tonic-gate 	req.opt.buf = (char *) opt;
7300Sstevel@tonic-gate 
7310Sstevel@tonic-gate 	resp.flags = 0;
7320Sstevel@tonic-gate 	resp.opt.buf = reqbuf;
7330Sstevel@tonic-gate 	resp.opt.maxlen = sizeof (reqbuf);
7340Sstevel@tonic-gate 
7350Sstevel@tonic-gate 	if (t_optmgmt(fd, &req, &resp) < 0 || resp.flags != T_SUCCESS) {
7360Sstevel@tonic-gate 		t_error("t_optmgmt");
7370Sstevel@tonic-gate 		exit(1);
7380Sstevel@tonic-gate 	}
7390Sstevel@tonic-gate 	/* Transform addr to netbuf */
7400Sstevel@tonic-gate 
7410Sstevel@tonic-gate 	tres = (struct t_bind *) t_alloc(fd, T_BIND, T_ADDR);
7420Sstevel@tonic-gate 	if (tres == NULL) {
7430Sstevel@tonic-gate 		(void) t_close(fd);
7440Sstevel@tonic-gate 		(void) krb5_klog_syslog(LOG_ERR,
7450Sstevel@tonic-gate 					gettext("cannot allocate netbuf"));
7460Sstevel@tonic-gate 		krb5_klog_close(context);
7470Sstevel@tonic-gate 		exit(1);
7480Sstevel@tonic-gate 	}
7490Sstevel@tonic-gate 	tbindstr.qlen = 8;
7500Sstevel@tonic-gate 	tbindstr.addr.buf = (char *) sin;
7510Sstevel@tonic-gate 	tbindstr.addr.len = tbindstr.addr.maxlen = __rpc_get_a_size(tinfo.addr);
7520Sstevel@tonic-gate 	sin = (struct sockaddr_in *) tbindstr.addr.buf;
7530Sstevel@tonic-gate 	/* SUNWresync121 XXX (void) memset(&addr, 0, sizeof(addr)); */
7540Sstevel@tonic-gate 
7557934SMark.Phalan@Sun.COM      if (t_bind(fd, &tbindstr, tres) < 0) {
7567934SMark.Phalan@Sun.COM 	  int oerrno = errno;
7577934SMark.Phalan@Sun.COM 	  const char *e_txt = krb5_get_error_message (context, errno);
7587934SMark.Phalan@Sun.COM 	  fprintf(stderr, gettext("%s: Cannot bind socket.\n"), whoami);
7597934SMark.Phalan@Sun.COM 	  fprintf(stderr, gettext("bind: %s\n"), e_txt);
7607934SMark.Phalan@Sun.COM 	  errno = oerrno;
7617934SMark.Phalan@Sun.COM 	  krb5_klog_syslog(LOG_ERR, gettext("Cannot bind socket: %s"), e_txt);
7627934SMark.Phalan@Sun.COM 	  if(oerrno == EADDRINUSE) {
7637934SMark.Phalan@Sun.COM 	       char *w = strrchr(whoami, '/');
7647934SMark.Phalan@Sun.COM 	       if (w) {
7657934SMark.Phalan@Sun.COM 		    w++;
7667934SMark.Phalan@Sun.COM 	       }
7677934SMark.Phalan@Sun.COM 	       else {
7687934SMark.Phalan@Sun.COM 		    w = whoami;
7697934SMark.Phalan@Sun.COM 	       }
7707934SMark.Phalan@Sun.COM 	       fprintf(stderr, gettext(
7717934SMark.Phalan@Sun.COM "This probably means that another %s process is already\n"
7727934SMark.Phalan@Sun.COM "running, or that another program is using the server port (number %d)\n"
7737934SMark.Phalan@Sun.COM "after being assigned it by the RPC portmap daemon.  If another\n"
7747934SMark.Phalan@Sun.COM "%s is already running, you should kill it before\n"
7757934SMark.Phalan@Sun.COM "restarting the server.  If, on the other hand, another program is\n"
7767934SMark.Phalan@Sun.COM "using the server port, you should kill it before running\n"
7777934SMark.Phalan@Sun.COM "%s, and ensure that the conflict does not occur in the\n"
7787934SMark.Phalan@Sun.COM "future by making sure that %s is started on reboot\n"
7797934SMark.Phalan@Sun.COM 		       "before portmap.\n"), w, ntohs(addr.sin_port), w, w, w);
7807934SMark.Phalan@Sun.COM 	       krb5_klog_syslog(LOG_ERR, gettext("Check for already-running %s or for "
7817934SMark.Phalan@Sun.COM 		      "another process using port %d"), w,
7827934SMark.Phalan@Sun.COM 		      htons(addr.sin_port));
7837934SMark.Phalan@Sun.COM 	  }
7847934SMark.Phalan@Sun.COM 	  kadm5_destroy(global_server_handle);
7857934SMark.Phalan@Sun.COM 	  krb5_klog_close(context);
7867934SMark.Phalan@Sun.COM 	  exit(1);
7877934SMark.Phalan@Sun.COM      }
7887934SMark.Phalan@Sun.COM      memset(&addr, 0, sizeof(addr));
7897934SMark.Phalan@Sun.COM      addr.sin_family = AF_INET;
7907934SMark.Phalan@Sun.COM      addr.sin_addr.s_addr = INADDR_ANY;
7917934SMark.Phalan@Sun.COM 
7927934SMark.Phalan@Sun.COM      addr.sin_port = htons(chgpw_params.kpasswd_port);
7930Sstevel@tonic-gate 
7947934SMark.Phalan@Sun.COM      if (bind(schpw, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
7957934SMark.Phalan@Sun.COM 	  char portbuf[32];
7967934SMark.Phalan@Sun.COM 	  int oerrno = errno;
7977934SMark.Phalan@Sun.COM 	  const char *e_txt = krb5_get_error_message (context, errno);
7987934SMark.Phalan@Sun.COM 	  fprintf(stderr, gettext("%s: Cannot bind socket.\n"), whoami);
7997934SMark.Phalan@Sun.COM 	  fprintf(stderr, gettext("bind: %s\n"), e_txt);
8007934SMark.Phalan@Sun.COM 	  errno = oerrno;
8017934SMark.Phalan@Sun.COM 	  (void) snprintf(portbuf, sizeof (portbuf), "%d", ntohs(addr.sin_port));
8027934SMark.Phalan@Sun.COM 	  krb5_klog_syslog(LOG_ERR, gettext("cannot bind simple chpw socket: %s"),
8037934SMark.Phalan@Sun.COM 			   e_txt);
8047934SMark.Phalan@Sun.COM 	  if(oerrno == EADDRINUSE) {
8057934SMark.Phalan@Sun.COM 	       char *w = strrchr(whoami, '/');
8067934SMark.Phalan@Sun.COM 	       if (w) {
8077934SMark.Phalan@Sun.COM 		    w++;
8087934SMark.Phalan@Sun.COM 	       }
8097934SMark.Phalan@Sun.COM 	       else {
8107934SMark.Phalan@Sun.COM 		    w = whoami;
8117934SMark.Phalan@Sun.COM 	       }
8127934SMark.Phalan@Sun.COM 	       fprintf(stderr, gettext(
8137934SMark.Phalan@Sun.COM "This probably means that another %s process is already\n"
8147934SMark.Phalan@Sun.COM "running, or that another program is using the server port (number %d).\n"
8157934SMark.Phalan@Sun.COM "If another %s is already running, you should kill it before\n"
8167934SMark.Phalan@Sun.COM "restarting the server.\n"),
8177934SMark.Phalan@Sun.COM 		       w, ntohs(addr.sin_port), w);
8187934SMark.Phalan@Sun.COM  	  }
8197934SMark.Phalan@Sun.COM  	  krb5_klog_close(context);
8207934SMark.Phalan@Sun.COM 	  exit(1);
8217934SMark.Phalan@Sun.COM      }
8227934SMark.Phalan@Sun.COM 
8237934SMark.Phalan@Sun.COM      transp = svc_tli_create(fd, nconf, NULL, 0, 0);
8247934SMark.Phalan@Sun.COM      (void) t_free((char *) tres, T_BIND);
8257934SMark.Phalan@Sun.COM      (void) endnetconfig(handlep);
8267934SMark.Phalan@Sun.COM      if(transp == NULL) {
8277934SMark.Phalan@Sun.COM 	  fprintf(stderr, gettext("%s: Cannot create RPC service.\n"), whoami);
8287934SMark.Phalan@Sun.COM 	  krb5_klog_syslog(LOG_ERR, gettext("Cannot create RPC service: %m"));
8297934SMark.Phalan@Sun.COM 	  kadm5_destroy(global_server_handle);
8307934SMark.Phalan@Sun.COM 	  krb5_klog_close(context);
8317934SMark.Phalan@Sun.COM 	  exit(1);
8327934SMark.Phalan@Sun.COM      }
8337934SMark.Phalan@Sun.COM      if(!svc_register(transp, KADM, KADMVERS, kadm_1, 0)) {
8347934SMark.Phalan@Sun.COM 	  fprintf(stderr, gettext("%s: Cannot register RPC service.\n"), whoami);
8357934SMark.Phalan@Sun.COM 	  krb5_klog_syslog(LOG_ERR, gettext("Cannot register RPC service, failing."));
8367934SMark.Phalan@Sun.COM 	  kadm5_destroy(global_server_handle);
8377934SMark.Phalan@Sun.COM 	  krb5_klog_close(context);
8387934SMark.Phalan@Sun.COM 	  exit(1);
8397934SMark.Phalan@Sun.COM      }
8400Sstevel@tonic-gate 
8410Sstevel@tonic-gate 
8421474Smp153739 	/* Solaris Kerberos:
8431474Smp153739 	 * The only service principals which matter here are
8441474Smp153739 	 *  -> names[0].name (kadmin/<fqdn>)
8451474Smp153739 	 *  -> names[1].name (changepw/<fqdn>)
8461474Smp153739 	 * KADM5_ADMIN_SERVICE_P, KADM5_CHANGEPW_SERVICE_P,
8471474Smp153739 	 * OVSEC_KADM_ADMIN_SERVICE_P, OVSEC_KADM_CHANGEPW_SERVICE_P
8481474Smp153739 	 * are all legacy service princs and calls to rpc_gss_set_svc_name()
8491474Smp153739 	 * using these principals will always fail as they are not host
8501474Smp153739 	 * based principals.
8511474Smp153739 	 */
8521474Smp153739 
8536426Smp153739 	if (ret = kadm5_get_adm_host_srv_name(context, params.realm,
8546426Smp153739 	    &names[0].name)) {
8556426Smp153739 		krb5_klog_syslog(LOG_ERR,
8566426Smp153739 		    gettext("Cannot get host based service name for admin "
8576426Smp153739 		    "principal in realm %s: %s"), params.realm,
8586426Smp153739 		    error_message(ret));
8596426Smp153739 		fprintf(stderr,
8606426Smp153739 		    gettext("%s: Cannot get host based service name for admin "
8616426Smp153739 		    "principal in realm %s: %s\n"), whoami, params.realm,
8626426Smp153739 		    error_message(ret));
8636426Smp153739 		krb5_klog_close(context);
8646426Smp153739 		exit(1);
8656426Smp153739 	}
8666426Smp153739 
8676426Smp153739 	if (ret = kadm5_get_cpw_host_srv_name(context, params.realm,
8686426Smp153739 	    &names[1].name)) {
8696426Smp153739 		krb5_klog_syslog(LOG_ERR,
8706426Smp153739 		    gettext("Cannot get host based service name for changepw "
8716426Smp153739 		    "principal in realm %s: %s"), params.realm,
8726426Smp153739 		    error_message(ret));
8736426Smp153739 		fprintf(stderr,
8746426Smp153739 		    gettext("%s: Cannot get host based service name for "
8756426Smp153739 		    "changepw principal in realm %s: %s\n"), whoami, params.realm,
8766426Smp153739 		    error_message(ret));
8776426Smp153739 		krb5_klog_close(context);
8786426Smp153739 		exit(1);
8796426Smp153739 	}
8800Sstevel@tonic-gate 	names[2].name = KADM5_ADMIN_SERVICE_P;
8810Sstevel@tonic-gate 	names[3].name = KADM5_CHANGEPW_SERVICE_P;
8820Sstevel@tonic-gate 	names[4].name = OVSEC_KADM_ADMIN_SERVICE_P;
8830Sstevel@tonic-gate 	names[5].name = OVSEC_KADM_CHANGEPW_SERVICE_P;
8840Sstevel@tonic-gate 
8857934SMark.Phalan@Sun.COM 	if (names[0].name == NULL || names[1].name == NULL ||
8867934SMark.Phalan@Sun.COM 	    names[2].name == NULL || names[3].name == NULL ||
8877934SMark.Phalan@Sun.COM 	    names[4].name == NULL || names[5].name == NULL) {
8887934SMark.Phalan@Sun.COM 		krb5_klog_syslog(LOG_ERR,
8897934SMark.Phalan@Sun.COM 		    gettext("Cannot initialize GSS-API authentication, "
8907934SMark.Phalan@Sun.COM 			"failing."));
8917934SMark.Phalan@Sun.COM 		fprintf(stderr,
8927934SMark.Phalan@Sun.COM 		    gettext("%s: Cannot initialize "
8937934SMark.Phalan@Sun.COM 			"GSS-API authentication.\n"),
8947934SMark.Phalan@Sun.COM 		    whoami);
8957934SMark.Phalan@Sun.COM 		krb5_klog_close(context);
8967934SMark.Phalan@Sun.COM 		exit(1);
8977934SMark.Phalan@Sun.COM 	}
8987934SMark.Phalan@Sun.COM 
8997934SMark.Phalan@Sun.COM      /*
9007934SMark.Phalan@Sun.COM       * Go through some contortions to point gssapi at a kdb keytab.
9017934SMark.Phalan@Sun.COM       * This prevents kadmind from needing to use an actual file-based
9027934SMark.Phalan@Sun.COM       * keytab.
9037934SMark.Phalan@Sun.COM       */
9047934SMark.Phalan@Sun.COM      /* XXX extract kadm5's krb5_context */
9057934SMark.Phalan@Sun.COM      hctx = ((kadm5_server_handle_t)global_server_handle)->context;
9067934SMark.Phalan@Sun.COM      /* Set ktkdb's internal krb5_context. */
9077934SMark.Phalan@Sun.COM      ret = krb5_ktkdb_set_context(hctx);
9087934SMark.Phalan@Sun.COM      if (ret) {
9097934SMark.Phalan@Sun.COM 	  krb5_klog_syslog(LOG_ERR, "Can't set kdb keytab's internal context.");
9107934SMark.Phalan@Sun.COM 	  goto kterr;
9117934SMark.Phalan@Sun.COM      }
9127934SMark.Phalan@Sun.COM      /* Solaris Kerberos */
9137934SMark.Phalan@Sun.COM      ret = krb5_db_set_mkey(hctx, &((kadm5_server_handle_t)global_server_handle)->master_keyblock);
9147934SMark.Phalan@Sun.COM      if (ret) {
9157934SMark.Phalan@Sun.COM 	  krb5_klog_syslog(LOG_ERR, "Can't set master key for kdb keytab.");
9167934SMark.Phalan@Sun.COM 	  goto kterr;
9177934SMark.Phalan@Sun.COM      }
9187934SMark.Phalan@Sun.COM      ret = krb5_kt_register(context, &krb5_kt_kdb_ops);
9197934SMark.Phalan@Sun.COM      if (ret) {
9207934SMark.Phalan@Sun.COM 	  krb5_klog_syslog(LOG_ERR, "Can't register kdb keytab.");
9217934SMark.Phalan@Sun.COM 	  goto kterr;
9227934SMark.Phalan@Sun.COM      }
9237934SMark.Phalan@Sun.COM      /* Tell gssapi about the kdb keytab. */
9247934SMark.Phalan@Sun.COM      ret = krb5_gss_register_acceptor_identity("KDB:");
9257934SMark.Phalan@Sun.COM      if (ret) {
9267934SMark.Phalan@Sun.COM 	  krb5_klog_syslog(LOG_ERR, "Can't register acceptor keytab.");
9277934SMark.Phalan@Sun.COM 	  goto kterr;
9287934SMark.Phalan@Sun.COM      }
9297934SMark.Phalan@Sun.COM kterr:
9307934SMark.Phalan@Sun.COM      if (ret) {
9317934SMark.Phalan@Sun.COM 	  krb5_klog_syslog(LOG_ERR, "%s", krb5_get_error_message (context, ret));
9327934SMark.Phalan@Sun.COM 	  fprintf(stderr, "%s: Can't set up keytab for RPC.\n", whoami);
9337934SMark.Phalan@Sun.COM 	  kadm5_destroy(global_server_handle);
9347934SMark.Phalan@Sun.COM 	  krb5_klog_close(context);
9357934SMark.Phalan@Sun.COM 	  exit(1);
9367934SMark.Phalan@Sun.COM      }
9377934SMark.Phalan@Sun.COM 
9387934SMark.Phalan@Sun.COM      /*
9397934SMark.Phalan@Sun.COM       * Try to acquire creds for the old OV services as well as the
9407934SMark.Phalan@Sun.COM       * new names, but if that fails just fall back on the new names.
9417934SMark.Phalan@Sun.COM       */
9427934SMark.Phalan@Sun.COM 
9430Sstevel@tonic-gate 	if (rpc_gss_set_svc_name(names[5].name,
9440Sstevel@tonic-gate 				"kerberos_v5", 0, KADM, KADMVERS) &&
9450Sstevel@tonic-gate 	    rpc_gss_set_svc_name(names[4].name,
9460Sstevel@tonic-gate 				"kerberos_v5", 0, KADM, KADMVERS))
9470Sstevel@tonic-gate 		oldnames++;
9480Sstevel@tonic-gate 	if (rpc_gss_set_svc_name(names[3].name,
9490Sstevel@tonic-gate 				"kerberos_v5", 0, KADM, KADMVERS))
9500Sstevel@tonic-gate 		oldnames++;
9510Sstevel@tonic-gate 	if (rpc_gss_set_svc_name(names[2].name,
9520Sstevel@tonic-gate 				"kerberos_v5", 0, KADM, KADMVERS))
9530Sstevel@tonic-gate 		oldnames++;
9541474Smp153739 
9551474Smp153739     /* If rpc_gss_set_svc_name() fails for either kadmin/<fqdn> or
9561474Smp153739      * for changepw/<fqdn> then try to determine if this is caused
9571474Smp153739      * by a missing keytab file or entry. If so, log it and continue.
9581474Smp153739      */
9590Sstevel@tonic-gate 	if (rpc_gss_set_svc_name(names[0].name,
9600Sstevel@tonic-gate 				"kerberos_v5", 0, KADM, KADMVERS))
9610Sstevel@tonic-gate 		oldnames++;
9627934SMark.Phalan@Sun.COM 
9630Sstevel@tonic-gate 	if (rpc_gss_set_svc_name(names[1].name,
9640Sstevel@tonic-gate 				"kerberos_v5", 0, KADM, KADMVERS))
9650Sstevel@tonic-gate 		oldnames++;
9660Sstevel@tonic-gate 
9670Sstevel@tonic-gate 	retdn = getdomnames(context, params.realm, &dnames);
9680Sstevel@tonic-gate 	if (retdn == 0 && dnames) {
9690Sstevel@tonic-gate 		/*
9700Sstevel@tonic-gate 		 * Multi-homed KDCs sometimes may need to set svc names
9710Sstevel@tonic-gate 		 * for multiple net interfaces so we set them for
9720Sstevel@tonic-gate 		 * all interfaces just in case.
9730Sstevel@tonic-gate 		 */
9740Sstevel@tonic-gate 		set_svc_domnames(KADM5_ADMIN_HOST_SERVICE,
9750Sstevel@tonic-gate 				dnames, KADM, KADMVERS);
9760Sstevel@tonic-gate 		set_svc_domnames(KADM5_CHANGEPW_HOST_SERVICE,
9770Sstevel@tonic-gate 				dnames, KADM, KADMVERS);
9780Sstevel@tonic-gate 	}
9790Sstevel@tonic-gate 
9807934SMark.Phalan@Sun.COM      /* if set_names succeeded, this will too */
9817934SMark.Phalan@Sun.COM      in_buf.value = names[1].name;
9827934SMark.Phalan@Sun.COM      in_buf.length = strlen(names[1].name) + 1;
9837934SMark.Phalan@Sun.COM      (void) gss_import_name(&OMret, &in_buf, (gss_OID) nt_krb5_name_oid,
9847934SMark.Phalan@Sun.COM 			    &gss_changepw_name);
9857934SMark.Phalan@Sun.COM      if (oldnames) {
9867934SMark.Phalan@Sun.COM 	  in_buf.value = names[3].name;
9877934SMark.Phalan@Sun.COM 	  in_buf.length = strlen(names[3].name) + 1;
9887934SMark.Phalan@Sun.COM 	  (void) gss_import_name(&OMret, &in_buf, (gss_OID) nt_krb5_name_oid,
9897934SMark.Phalan@Sun.COM 				 &gss_oldchangepw_name);
9907934SMark.Phalan@Sun.COM      }
9917934SMark.Phalan@Sun.COM 
9927934SMark.Phalan@Sun.COM      if ((ret = kadm5int_acl_init(context, 0, params.acl_file))) {
9937934SMark.Phalan@Sun.COM 	  errmsg = krb5_get_error_message (context, ret);
9947934SMark.Phalan@Sun.COM 	  krb5_klog_syslog(LOG_ERR, gettext("Cannot initialize acl file: %s"),
9957934SMark.Phalan@Sun.COM 		 errmsg);
9967934SMark.Phalan@Sun.COM 	  fprintf(stderr, gettext("%s: Cannot initialize acl file: %s\n"),
9977934SMark.Phalan@Sun.COM 		  whoami, errmsg);
9987934SMark.Phalan@Sun.COM 	  kadm5_destroy(global_server_handle);
9997934SMark.Phalan@Sun.COM 	  krb5_klog_close(context);
10007934SMark.Phalan@Sun.COM 	  exit(1);
10017934SMark.Phalan@Sun.COM      }
10026426Smp153739 
10036426Smp153739 	/*
10046426Smp153739 	 * Solaris Kerberos:
100511157SMark.Phalan@Sun.COM 	 * Warn if the acl file contains an entry for a principal matching the
100611157SMark.Phalan@Sun.COM 	 * default (unconfigured) acl rule.
10076426Smp153739 	 */
100811157SMark.Phalan@Sun.COM 	gssbuf.length = strlen("x/admin@___default_realm___");
100911157SMark.Phalan@Sun.COM 	gssbuf.value = "x/admin@___default_realm___";
101011157SMark.Phalan@Sun.COM 	/* Use any value as the first component - 'x' in this case */
101111157SMark.Phalan@Sun.COM 	if (gss_import_name(&minor_status, &gssbuf, GSS_C_NT_USER_NAME, &name)
101211157SMark.Phalan@Sun.COM 	    == GSS_S_COMPLETE) {
101311157SMark.Phalan@Sun.COM 		if (kadm5int_acl_check(context, name, ACL_MODIFY, NULL, NULL)) {
101411157SMark.Phalan@Sun.COM 			krb5_klog_syslog(LOG_WARNING,
101511157SMark.Phalan@Sun.COM 			    gettext("acls may not be properly configured: "
101611157SMark.Phalan@Sun.COM 			    "found an acl matching \"___default_realm___\" in "
101711157SMark.Phalan@Sun.COM 			    " %s"), params.acl_file);
101811157SMark.Phalan@Sun.COM 			(void) fprintf(stderr, gettext("%s: Warning: "
101911157SMark.Phalan@Sun.COM 			    "acls may not be properly configured: found an acl "
102011157SMark.Phalan@Sun.COM 			    "matching \"___default_realm___\" in %s\n"),
102111157SMark.Phalan@Sun.COM 			    whoami, params.acl_file);
10226426Smp153739 		}
102311157SMark.Phalan@Sun.COM 		(void) gss_release_name(&minor_status, &name);
10246426Smp153739 	}
102511157SMark.Phalan@Sun.COM 	gssbuf.value = NULL;
10266426Smp153739 	gssbuf.length = 0;
10276426Smp153739 
10286426Smp153739 	/*
10296426Smp153739 	 * Solaris Kerberos:
10306426Smp153739 	 * List the logs (FILE, STDERR, etc) which are currently being
10316426Smp153739 	 * logged to and print to stderr. Useful when trying to
10326426Smp153739 	 * track down a failure via SMF.
10336426Smp153739 	 */
10346426Smp153739 	if (ret = krb5_klog_list_logs(whoami)) {
10356426Smp153739 		fprintf(stderr, gettext("%s: %s while listing logs\n"),
10366426Smp153739 		    whoami, error_message(ret));
10376426Smp153739 		krb5_klog_syslog(LOG_ERR, gettext("%s while listing logs"),
10386426Smp153739 		    error_message(ret));
10396426Smp153739 	}
10406426Smp153739 
10417934SMark.Phalan@Sun.COM      if (!nofork && (ret = daemon(0, 0))) {
10427934SMark.Phalan@Sun.COM 	  ret = errno;
10437934SMark.Phalan@Sun.COM 	  errmsg = krb5_get_error_message (context, ret);
10447934SMark.Phalan@Sun.COM 	  krb5_klog_syslog(LOG_ERR,
10457934SMark.Phalan@Sun.COM 		    gettext("Cannot detach from tty: %s"), errmsg);
10467934SMark.Phalan@Sun.COM 	  fprintf(stderr, gettext("%s: Cannot detach from tty: %s\n"),
10477934SMark.Phalan@Sun.COM 		  whoami, errmsg);
10487934SMark.Phalan@Sun.COM 	  kadm5_destroy(global_server_handle);
10497934SMark.Phalan@Sun.COM 	  krb5_klog_close(context);
10507934SMark.Phalan@Sun.COM 	  exit(1);
10517934SMark.Phalan@Sun.COM      }
10527934SMark.Phalan@Sun.COM 
10537934SMark.Phalan@Sun.COM     /* SUNW14resync */
10547934SMark.Phalan@Sun.COM #if 0
10557934SMark.Phalan@Sun.COM      krb5_klog_syslog(LOG_INFO, "Seeding random number generator");
10567934SMark.Phalan@Sun.COM      ret = krb5_c_random_os_entropy(context, 1, NULL);
10577934SMark.Phalan@Sun.COM      if (ret) {
10587934SMark.Phalan@Sun.COM 	  krb5_klog_syslog(LOG_ERR, "Error getting random seed: %s, aborting",
10597934SMark.Phalan@Sun.COM 			   krb5_get_error_message(context, ret));
10607934SMark.Phalan@Sun.COM 	  kadm5_destroy(global_server_handle);
10617934SMark.Phalan@Sun.COM 	  krb5_klog_close(context);
10627934SMark.Phalan@Sun.COM 	  exit(1);
10637934SMark.Phalan@Sun.COM      }
10647934SMark.Phalan@Sun.COM #endif
10657934SMark.Phalan@Sun.COM 
10664960Swillf 
10670Sstevel@tonic-gate 	handle = global_server_handle;
10680Sstevel@tonic-gate 	ctx = handle->context;
10694960Swillf 	if (params.iprop_enabled == TRUE) {
10704960Swillf 		if (ret = krb5_db_supports_iprop(ctx, &iprop_supported)) {
10714960Swillf 			fprintf(stderr,
10724960Swillf 				gettext("%s: %s while trying to determine if KDB "
10734960Swillf 				"plugin supports iprop\n"), whoami,
10744960Swillf 				error_message(ret));
10754960Swillf 			krb5_klog_syslog(LOG_ERR,
10764960Swillf 				gettext("%s while trying to determine if KDB "
10774960Swillf 				"plugin supports iprop"), error_message(ret));
10784960Swillf 			krb5_klog_close(ctx);
10794960Swillf 			exit(1);
10804960Swillf 		}
10814960Swillf 
10824960Swillf 		if (!iprop_supported) {
10834960Swillf 			fprintf(stderr,
10844960Swillf 				gettext("%s: Warning, current KDB "
10854960Swillf 				"plugin does not support iprop, continuing "
10864960Swillf 				"with iprop disabled\n"), whoami);
10874960Swillf 			krb5_klog_syslog(LOG_WARNING,
10885867Smp153739 				gettext("Warning, current KDB "
10894960Swillf 				"plugin does not support iprop, continuing "
10904960Swillf 				"with iprop disabled"));
10914960Swillf 
10924960Swillf 			ulog_set_role(ctx, IPROP_NULL);
10934960Swillf 		} else
10944960Swillf 			ulog_set_role(ctx, IPROP_MASTER);
10954960Swillf 	} else
10960Sstevel@tonic-gate 		ulog_set_role(ctx, IPROP_NULL);
10970Sstevel@tonic-gate 
10980Sstevel@tonic-gate 	log_ctx = ctx->kdblog_context;
10990Sstevel@tonic-gate 
11000Sstevel@tonic-gate 	if (log_ctx && (log_ctx->iproprole == IPROP_MASTER)) {
11010Sstevel@tonic-gate 		/*
11020Sstevel@tonic-gate 		 * IProp is enabled, so let's map in the update log
11030Sstevel@tonic-gate 		 * and setup the service.
11040Sstevel@tonic-gate 		 */
11050Sstevel@tonic-gate 		if (ret = ulog_map(ctx, &params, FKADMIND)) {
11060Sstevel@tonic-gate 			fprintf(stderr,
11070Sstevel@tonic-gate 				gettext("%s: %s while mapping update log "
11080Sstevel@tonic-gate 				"(`%s.ulog')\n"), whoami, error_message(ret),
11090Sstevel@tonic-gate 				params.dbname);
11100Sstevel@tonic-gate 			krb5_klog_syslog(LOG_ERR,
11110Sstevel@tonic-gate 				gettext("%s while mapping update log "
11120Sstevel@tonic-gate 				"(`%s.ulog')"), error_message(ret),
11130Sstevel@tonic-gate 				params.dbname);
11140Sstevel@tonic-gate 			krb5_klog_close(ctx);
11150Sstevel@tonic-gate 			exit(1);
11160Sstevel@tonic-gate 		}
11170Sstevel@tonic-gate 
11180Sstevel@tonic-gate 
11190Sstevel@tonic-gate 		if (nofork)
11200Sstevel@tonic-gate 			fprintf(stderr,
11210Sstevel@tonic-gate 				"%s: create IPROP svc (PROG=%d, VERS=%d)\n",
11220Sstevel@tonic-gate 				whoami, KRB5_IPROP_PROG, KRB5_IPROP_VERS);
11230Sstevel@tonic-gate 
11240Sstevel@tonic-gate 		if (!svc_create(krb5_iprop_prog_1,
11250Sstevel@tonic-gate 				KRB5_IPROP_PROG, KRB5_IPROP_VERS,
11260Sstevel@tonic-gate 				"circuit_v")) {
11270Sstevel@tonic-gate 			fprintf(stderr,
11280Sstevel@tonic-gate     gettext("%s: Cannot create IProp RPC service (PROG=%d, VERS=%d)\n"),
11290Sstevel@tonic-gate 				whoami,
11300Sstevel@tonic-gate 				KRB5_IPROP_PROG, KRB5_IPROP_VERS);
11310Sstevel@tonic-gate 			krb5_klog_syslog(LOG_ERR,
11320Sstevel@tonic-gate     gettext("Cannot create IProp RPC service (PROG=%d, VERS=%d), failing."),
11330Sstevel@tonic-gate 					KRB5_IPROP_PROG, KRB5_IPROP_VERS);
11340Sstevel@tonic-gate 			krb5_klog_close(ctx);
11350Sstevel@tonic-gate 			exit(1);
11360Sstevel@tonic-gate 		}
11370Sstevel@tonic-gate 
11380Sstevel@tonic-gate 		if (ret = kiprop_get_adm_host_srv_name(ctx,
11390Sstevel@tonic-gate 							params.realm,
11400Sstevel@tonic-gate 							&kiprop_name)) {
11410Sstevel@tonic-gate 			krb5_klog_syslog(LOG_ERR,
11420Sstevel@tonic-gate 			gettext("%s while getting IProp svc name, failing"),
11430Sstevel@tonic-gate 					error_message(ret));
11440Sstevel@tonic-gate 			fprintf(stderr,
11450Sstevel@tonic-gate 		gettext("%s: %s while getting IProp svc name, failing\n"),
11460Sstevel@tonic-gate 				whoami, error_message(ret));
11470Sstevel@tonic-gate 			krb5_klog_close(ctx);
11480Sstevel@tonic-gate 			exit(1);
11490Sstevel@tonic-gate 		}
11500Sstevel@tonic-gate 
11510Sstevel@tonic-gate 		if (!rpc_gss_set_svc_name(kiprop_name, "kerberos_v5", 0,
11520Sstevel@tonic-gate 					KRB5_IPROP_PROG, KRB5_IPROP_VERS)) {
11530Sstevel@tonic-gate 			rpc_gss_error_t err;
11540Sstevel@tonic-gate 			(void) rpc_gss_get_error(&err);
11550Sstevel@tonic-gate 
11560Sstevel@tonic-gate 			krb5_klog_syslog(LOG_ERR,
11570Sstevel@tonic-gate     gettext("Unable to set RPCSEC_GSS service name (`%s'), failing."),
11580Sstevel@tonic-gate 					kiprop_name ? kiprop_name : "<null>");
11590Sstevel@tonic-gate 			fprintf(stderr,
11600Sstevel@tonic-gate     gettext("%s: Unable to set RPCSEC_GSS service name (`%s'), failing.\n"),
11610Sstevel@tonic-gate 				whoami,
11620Sstevel@tonic-gate 				kiprop_name ? kiprop_name : "<null>");
11630Sstevel@tonic-gate 
11640Sstevel@tonic-gate 			if (nofork) {
11650Sstevel@tonic-gate 				fprintf(stderr,
11660Sstevel@tonic-gate 			"%s: set svc name (rpcsec err=%d, sys err=%d)\n",
11670Sstevel@tonic-gate 					whoami,
11680Sstevel@tonic-gate 					err.rpc_gss_error,
11690Sstevel@tonic-gate 					err.system_error);
11700Sstevel@tonic-gate 			}
11710Sstevel@tonic-gate 
11720Sstevel@tonic-gate 			exit(1);
11730Sstevel@tonic-gate 		}
11740Sstevel@tonic-gate 		free(kiprop_name);
11750Sstevel@tonic-gate 
11760Sstevel@tonic-gate 		if (retdn == 0 && dnames) {
11770Sstevel@tonic-gate 			set_svc_domnames(KADM5_KIPROP_HOST_SERVICE,
11780Sstevel@tonic-gate 					dnames,
11790Sstevel@tonic-gate 					KRB5_IPROP_PROG, KRB5_IPROP_VERS);
11800Sstevel@tonic-gate 		}
11810Sstevel@tonic-gate 
11821446Smp153739 	} else {
11831446Smp153739 		if (!oldnames) {
11841446Smp153739 		/* rpc_gss_set_svc_name failed for both kadmin/<fqdn> and
11851446Smp153739 		 * changepw/<fqdn>.
11861446Smp153739 		 */
11871446Smp153739 			krb5_klog_syslog(LOG_ERR,
11881446Smp153739 					gettext("Unable to set RPCSEC_GSS service names "
11891446Smp153739 						"('%s, %s')"),
11901446Smp153739 					names[0].name, names[1].name);
11911446Smp153739 			fprintf(stderr,
11921446Smp153739 					gettext("%s: Unable to set RPCSEC_GSS service names "
11931446Smp153739 						"('%s, %s')\n"),
11941446Smp153739 					whoami,
11951446Smp153739 					names[0].name, names[1].name);
11961446Smp153739 			krb5_klog_close(context);
11971446Smp153739 			exit(1);
11981446Smp153739 		}
11990Sstevel@tonic-gate 	}
12000Sstevel@tonic-gate 
12010Sstevel@tonic-gate 	if (dnames)
12020Sstevel@tonic-gate 		freedomnames(dnames);
12030Sstevel@tonic-gate 
12040Sstevel@tonic-gate 	setup_signal_handlers(log_ctx->iproprole);
12050Sstevel@tonic-gate 	krb5_klog_syslog(LOG_INFO, gettext("starting"));
12060Sstevel@tonic-gate 	if (nofork)
12070Sstevel@tonic-gate 		fprintf(stderr, "%s: starting...\n", whoami);
12080Sstevel@tonic-gate 
12090Sstevel@tonic-gate 
12100Sstevel@tonic-gate 	/*
12110Sstevel@tonic-gate 	 * We now call our own customized async event processing
12120Sstevel@tonic-gate 	 * function kadm_svc_run(), as opposed to svc_run() earlier,
12130Sstevel@tonic-gate 	 * since this enables kadmind to also listen-to/process
12140Sstevel@tonic-gate 	 * non-RPCSEC_GSS based change-pwd requests apart from the
12150Sstevel@tonic-gate 	 * regular, RPCSEC_GSS kpasswd requests from Solaris Krb5 clients.
12160Sstevel@tonic-gate 	 */
12170Sstevel@tonic-gate 	kadm_svc_run();
12180Sstevel@tonic-gate 
12190Sstevel@tonic-gate 	krb5_klog_syslog(LOG_INFO, gettext("finished, exiting"));
12200Sstevel@tonic-gate 	kadm5_destroy(global_server_handle);
12210Sstevel@tonic-gate 	t_close(fd);
12220Sstevel@tonic-gate 	krb5_klog_close(context);
12230Sstevel@tonic-gate 	exit(0);
12240Sstevel@tonic-gate }
12250Sstevel@tonic-gate 
12260Sstevel@tonic-gate /*
12270Sstevel@tonic-gate  * Function: kadm_svc_run
12280Sstevel@tonic-gate  *
12290Sstevel@tonic-gate  * Purpose: modified version of sunrpc svc_run.
12300Sstevel@tonic-gate  *	    which closes the database every TIMEOUT seconds.
12310Sstevel@tonic-gate  *
12320Sstevel@tonic-gate  * Arguments:
12330Sstevel@tonic-gate  * Requires:
12340Sstevel@tonic-gate  * Effects:
12350Sstevel@tonic-gate  * Modifies:
12360Sstevel@tonic-gate  */
12377934SMark.Phalan@Sun.COM 
kadm_svc_run(void)12387934SMark.Phalan@Sun.COM void kadm_svc_run(void)
12390Sstevel@tonic-gate {
12407934SMark.Phalan@Sun.COM      struct pollfd	*rfd = 0;
12417934SMark.Phalan@Sun.COM      struct	timeval	    timeout;
12427934SMark.Phalan@Sun.COM      int pollret;
12437934SMark.Phalan@Sun.COM      int nfds = 0;
12447934SMark.Phalan@Sun.COM      int i;
12450Sstevel@tonic-gate 
12467934SMark.Phalan@Sun.COM      while(signal_request_exit == 0) {
12470Sstevel@tonic-gate 		timeout.tv_sec = TIMEOUT;
12480Sstevel@tonic-gate 		timeout.tv_usec = 0;
12490Sstevel@tonic-gate 
12500Sstevel@tonic-gate 		if (nfds != svc_max_pollfd) {
12510Sstevel@tonic-gate 			rfd = realloc(rfd, sizeof (pollfd_t) * svc_max_pollfd);
12520Sstevel@tonic-gate 			nfds = svc_max_pollfd;
12530Sstevel@tonic-gate 		}
12540Sstevel@tonic-gate 
12550Sstevel@tonic-gate 		(void) memcpy(rfd, svc_pollfd,
12560Sstevel@tonic-gate 			sizeof (pollfd_t) * svc_max_pollfd);
12570Sstevel@tonic-gate 
12580Sstevel@tonic-gate 		for (i = 0; i < nfds; i++) {
12590Sstevel@tonic-gate 			if (rfd[i].fd == -1) {
12600Sstevel@tonic-gate 				rfd[i].fd = schpw;
12610Sstevel@tonic-gate 				rfd[i].events = POLLIN;
12620Sstevel@tonic-gate 				break;
12630Sstevel@tonic-gate 			}
12640Sstevel@tonic-gate 		}
12650Sstevel@tonic-gate 
12660Sstevel@tonic-gate 		switch(pollret = poll(rfd, nfds,
12670Sstevel@tonic-gate 				__rpc_timeval_to_msec(&timeout))) {
12680Sstevel@tonic-gate 		case -1:
12690Sstevel@tonic-gate 			if(errno == EINTR)
12700Sstevel@tonic-gate 				continue;
12710Sstevel@tonic-gate 			perror("poll");
12720Sstevel@tonic-gate 			return;
12730Sstevel@tonic-gate 		case 0:
12740Sstevel@tonic-gate 			continue;
12750Sstevel@tonic-gate 		default:
12760Sstevel@tonic-gate 			for (i = 0; i < nfds; i++) {
12770Sstevel@tonic-gate 				if (rfd[i].revents & POLLIN) {
12780Sstevel@tonic-gate 					if (rfd[i].fd == schpw)
12790Sstevel@tonic-gate 						handle_chpw(context, schpw,
12800Sstevel@tonic-gate 							global_server_handle,
12810Sstevel@tonic-gate 							&chgpw_params);
12820Sstevel@tonic-gate 					else
12830Sstevel@tonic-gate 						svc_getreq_poll(rfd, pollret);
12840Sstevel@tonic-gate 					break;
12850Sstevel@tonic-gate 				} else {
12860Sstevel@tonic-gate 					if (i == (nfds - 1))
12870Sstevel@tonic-gate 						perror("poll");
12880Sstevel@tonic-gate 				}
12890Sstevel@tonic-gate 			}
12900Sstevel@tonic-gate 			break;
12910Sstevel@tonic-gate 		}
12920Sstevel@tonic-gate 	}
12930Sstevel@tonic-gate }
12940Sstevel@tonic-gate 
12950Sstevel@tonic-gate 
12960Sstevel@tonic-gate /*
12970Sstevel@tonic-gate  * Function: setup_signal_handlers
12980Sstevel@tonic-gate  *
1299*11208SPeter.Shoults@Sun.COM  * Purpose: Setup signal handling functions with either
1300*11208SPeter.Shoults@Sun.COM  * System V's signal() or POSIX_SIGNALS.
13010Sstevel@tonic-gate  */
setup_signal_handlers(iprop_role iproprole)13020Sstevel@tonic-gate void setup_signal_handlers(iprop_role iproprole) {
1303*11208SPeter.Shoults@Sun.COM #ifdef POSIX_SIGNALS
1304*11208SPeter.Shoults@Sun.COM 	(void) sigemptyset(&s_action.sa_mask);
1305*11208SPeter.Shoults@Sun.COM 	s_action.sa_handler = request_exit;
1306*11208SPeter.Shoults@Sun.COM 	(void) sigaction(SIGINT, &s_action, (struct sigaction *) NULL);
1307*11208SPeter.Shoults@Sun.COM 	(void) sigaction(SIGTERM, &s_action, (struct sigaction *) NULL);
1308*11208SPeter.Shoults@Sun.COM 	(void) sigaction(SIGQUIT, &s_action, (struct sigaction *) NULL);
1309*11208SPeter.Shoults@Sun.COM 	s_action.sa_handler = sig_pipe;
1310*11208SPeter.Shoults@Sun.COM 	(void) sigaction(SIGPIPE, &s_action, (struct sigaction *) NULL);
1311*11208SPeter.Shoults@Sun.COM 
1312*11208SPeter.Shoults@Sun.COM 	/*
1313*11208SPeter.Shoults@Sun.COM 	 * IProp will fork for a full-resync, we don't want to
1314*11208SPeter.Shoults@Sun.COM 	 * wait on it and we don't want the living dead procs either.
1315*11208SPeter.Shoults@Sun.COM 	 */
1316*11208SPeter.Shoults@Sun.COM 	if (iproprole == IPROP_MASTER) {
1317*11208SPeter.Shoults@Sun.COM 		s_action.sa_handler = SIG_IGN;
1318*11208SPeter.Shoults@Sun.COM 		(void) sigaction(SIGCHLD, &s_action, (struct sigaction *) NULL);
1319*11208SPeter.Shoults@Sun.COM 	}
1320*11208SPeter.Shoults@Sun.COM #else
13217934SMark.Phalan@Sun.COM      signal(SIGINT, request_exit);
13227934SMark.Phalan@Sun.COM      signal(SIGTERM, request_exit);
13237934SMark.Phalan@Sun.COM      signal(SIGQUIT, request_exit);
13247934SMark.Phalan@Sun.COM      signal(SIGPIPE, sig_pipe);
13250Sstevel@tonic-gate 
13260Sstevel@tonic-gate 	/*
13270Sstevel@tonic-gate 	 * IProp will fork for a full-resync, we don't want to
13280Sstevel@tonic-gate 	 * wait on it and we don't want the living dead procs either.
13290Sstevel@tonic-gate 	 */
13300Sstevel@tonic-gate 	if (iproprole == IPROP_MASTER)
13310Sstevel@tonic-gate 		(void) signal(SIGCHLD, SIG_IGN);
13320Sstevel@tonic-gate 
1333*11208SPeter.Shoults@Sun.COM #endif /* POSIX_SIGNALS */
13340Sstevel@tonic-gate 	return;
13350Sstevel@tonic-gate }
13360Sstevel@tonic-gate 
13370Sstevel@tonic-gate 
13380Sstevel@tonic-gate /*
13397934SMark.Phalan@Sun.COM  * Function: request_exit
13407934SMark.Phalan@Sun.COM  *
13410Sstevel@tonic-gate  * Purpose: sets flags saying the server got a signal and that it
13427934SMark.Phalan@Sun.COM  *	    should exit when convient.
13430Sstevel@tonic-gate  *
13447934SMark.Phalan@Sun.COM  * Arguments:
13457934SMark.Phalan@Sun.COM  * Requires:
13460Sstevel@tonic-gate  * Effects:
13477934SMark.Phalan@Sun.COM  *	modifies signal_request_exit which ideally makes the server exit
13487934SMark.Phalan@Sun.COM  *	at some point.
13490Sstevel@tonic-gate  *
13500Sstevel@tonic-gate  * Modifies:
13517934SMark.Phalan@Sun.COM  *	signal_request_exit
13520Sstevel@tonic-gate  */
13537934SMark.Phalan@Sun.COM 
request_exit(int signum)13547934SMark.Phalan@Sun.COM void request_exit(int signum)
13550Sstevel@tonic-gate {
13567934SMark.Phalan@Sun.COM      krb5_klog_syslog(LOG_NOTICE, gettext("Got signal to request exit"));
13577934SMark.Phalan@Sun.COM      signal_request_exit = 1;
13587934SMark.Phalan@Sun.COM      return;
13590Sstevel@tonic-gate }
13600Sstevel@tonic-gate 
13610Sstevel@tonic-gate /*
13620Sstevel@tonic-gate  * Function: sig_pipe
13630Sstevel@tonic-gate  *
13640Sstevel@tonic-gate  * Purpose: SIGPIPE handler
13650Sstevel@tonic-gate  *
13667934SMark.Phalan@Sun.COM  * Effects: krb5_klog_syslogs a message that a SIGPIPE occurred and returns,
13670Sstevel@tonic-gate  * thus causing the read() or write() to fail and, presumable, the RPC
13687934SMark.Phalan@Sun.COM  * to recover.  Otherwise, the process aborts.
13690Sstevel@tonic-gate  */
sig_pipe(int unused)13707934SMark.Phalan@Sun.COM void sig_pipe(int unused)
13710Sstevel@tonic-gate {
1372*11208SPeter.Shoults@Sun.COM #ifndef POSIX_SIGNALS
1373*11208SPeter.Shoults@Sun.COM      signal(SIGPIPE, sig_pipe);
1374*11208SPeter.Shoults@Sun.COM #endif /* POSIX_SIGNALS */
13757934SMark.Phalan@Sun.COM      krb5_klog_syslog(LOG_NOTICE, gettext("Warning: Received a SIGPIPE; "
13767934SMark.Phalan@Sun.COM 	    "probably a client aborted.  Continuing."));
13777934SMark.Phalan@Sun.COM      return;
13780Sstevel@tonic-gate }
13791474Smp153739 
1380