xref: /onnv-gate/usr/src/cmd/krb5/kadmin/server/ovsec_kadmd.c (revision 1446:a2129b6a7098)
10Sstevel@tonic-gate /*
2*1446Smp153739  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
30Sstevel@tonic-gate  * Use is subject to license terms.
40Sstevel@tonic-gate  */
50Sstevel@tonic-gate 
60Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
70Sstevel@tonic-gate 
80Sstevel@tonic-gate /*
90Sstevel@tonic-gate  * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
100Sstevel@tonic-gate  *
110Sstevel@tonic-gate  *	Openvision retains the copyright to derivative works of
120Sstevel@tonic-gate  *	this source code.	Do *NOT* create a derivative of this
130Sstevel@tonic-gate  *	source code before consulting with your legal department.
140Sstevel@tonic-gate  *	Do *NOT* integrate *ANY* of this source code into another
150Sstevel@tonic-gate  *	product before consulting with your legal department.
160Sstevel@tonic-gate  *
170Sstevel@tonic-gate  *	For further information, read the top-level Openvision
180Sstevel@tonic-gate  *	copyright which is contained in the top-level MIT Kerberos
190Sstevel@tonic-gate  *	copyright.
200Sstevel@tonic-gate  *
210Sstevel@tonic-gate  * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
220Sstevel@tonic-gate  *
230Sstevel@tonic-gate  */
240Sstevel@tonic-gate 
250Sstevel@tonic-gate 
260Sstevel@tonic-gate /*
270Sstevel@tonic-gate  * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved
280Sstevel@tonic-gate  */
290Sstevel@tonic-gate 
300Sstevel@tonic-gate /*
310Sstevel@tonic-gate  * SUNWresync121 XXX
320Sstevel@tonic-gate  * Beware future resyncers, this file is much diff from MIT (1.0...)
330Sstevel@tonic-gate  */
340Sstevel@tonic-gate 
350Sstevel@tonic-gate #include <stdio.h>
360Sstevel@tonic-gate #include <signal.h>
370Sstevel@tonic-gate #include <syslog.h>
380Sstevel@tonic-gate #include <sys/types.h>
390Sstevel@tonic-gate #include <sys/time.h>
400Sstevel@tonic-gate #include <sys/socket.h>
410Sstevel@tonic-gate #include <unistd.h>
420Sstevel@tonic-gate #include <netinet/in.h>
430Sstevel@tonic-gate #include <arpa/inet.h>	/* inet_ntoa */
440Sstevel@tonic-gate #include <netdb.h>
450Sstevel@tonic-gate #include <gssapi/gssapi.h>
460Sstevel@tonic-gate #include <rpc/rpc.h>
470Sstevel@tonic-gate #include <kadm5/admin.h>
480Sstevel@tonic-gate #include <kadm5/kadm_rpc.h>
490Sstevel@tonic-gate #include <kadm5/server_internal.h>
500Sstevel@tonic-gate #include <server_acl.h>
510Sstevel@tonic-gate #include <krb5/adm_proto.h>
520Sstevel@tonic-gate #include <string.h>
530Sstevel@tonic-gate #include <gssapi_krb5.h>
540Sstevel@tonic-gate #include <libintl.h>
550Sstevel@tonic-gate #include <locale.h>
560Sstevel@tonic-gate #include <sys/resource.h>
570Sstevel@tonic-gate #include <kdb/kdb_log.h>
580Sstevel@tonic-gate 
590Sstevel@tonic-gate #include <rpc/rpcsec_gss.h>
600Sstevel@tonic-gate 
610Sstevel@tonic-gate #ifndef	FD_SETSIZE
620Sstevel@tonic-gate #define	FD_SETSIZE	256
630Sstevel@tonic-gate #endif
640Sstevel@tonic-gate 
650Sstevel@tonic-gate #ifndef MAX
660Sstevel@tonic-gate #define	MAX(a, b)	(((a) > (b)) ? (a) : (b))
670Sstevel@tonic-gate #endif
680Sstevel@tonic-gate 
690Sstevel@tonic-gate static int signal_request_exit = 0;
700Sstevel@tonic-gate static int schpw;
710Sstevel@tonic-gate kadm5_config_params chgpw_params;
720Sstevel@tonic-gate void kadm_svc_run(void);
730Sstevel@tonic-gate void setup_signal_handlers(iprop_role iproprole);
740Sstevel@tonic-gate void sig_exit(int);
750Sstevel@tonic-gate void sig_pipe(int);
760Sstevel@tonic-gate 
770Sstevel@tonic-gate #ifdef POSIX_SIGNALS
780Sstevel@tonic-gate static struct sigaction s_action;
790Sstevel@tonic-gate #endif /* POSIX_SIGNALS */
800Sstevel@tonic-gate 
810Sstevel@tonic-gate #define	TIMEOUT	15
820Sstevel@tonic-gate 
830Sstevel@tonic-gate typedef struct _auth_gssapi_name {
840Sstevel@tonic-gate 	char *name;
850Sstevel@tonic-gate 	gss_OID type;
860Sstevel@tonic-gate } auth_gssapi_name;
870Sstevel@tonic-gate 
880Sstevel@tonic-gate gss_name_t gss_changepw_name = NULL, gss_oldchangepw_name = NULL;
890Sstevel@tonic-gate void *global_server_handle;
900Sstevel@tonic-gate 
910Sstevel@tonic-gate /*
920Sstevel@tonic-gate  * This is a kludge, but the server needs these constants to be
930Sstevel@tonic-gate  * compatible with old clients.	They are defined in <kadm5/admin.h>,
940Sstevel@tonic-gate  * but only if USE_KADM5_API_VERSION == 1.
950Sstevel@tonic-gate  */
960Sstevel@tonic-gate #define	OVSEC_KADM_ADMIN_SERVICE_P	"ovsec_adm@admin"
970Sstevel@tonic-gate #define	OVSEC_KADM_CHANGEPW_SERVICE_P	"ovsec_adm@changepw"
980Sstevel@tonic-gate 
990Sstevel@tonic-gate /*
1000Sstevel@tonic-gate  * This enables us to set the keytab that gss_acquire_cred uses, but
1010Sstevel@tonic-gate  * it also restricts us to linking against the Kv5 GSS-API library.
1020Sstevel@tonic-gate  * Since this is *k*admind, that shouldn't be a problem.
1030Sstevel@tonic-gate  */
1040Sstevel@tonic-gate extern char *krb5_overridekeyname;
1050Sstevel@tonic-gate 
1060Sstevel@tonic-gate extern void krb5_iprop_prog_1();
1070Sstevel@tonic-gate extern kadm5_ret_t kiprop_get_adm_host_srv_name(
1080Sstevel@tonic-gate 	krb5_context,
1090Sstevel@tonic-gate 	const char *,
1100Sstevel@tonic-gate 	char **);
1110Sstevel@tonic-gate 
1120Sstevel@tonic-gate static krb5_context context;  /* XXX yuck.  the signal handlers need this */
1130Sstevel@tonic-gate 
1140Sstevel@tonic-gate in_port_t l_port = 0;	/* global local port num, for BSM audits */
1150Sstevel@tonic-gate 
1160Sstevel@tonic-gate int nofork = 0; /* global; don't fork (debug mode) */
1170Sstevel@tonic-gate 
1180Sstevel@tonic-gate 
1190Sstevel@tonic-gate /*
1200Sstevel@tonic-gate  * Function: usage
1210Sstevel@tonic-gate  *
1220Sstevel@tonic-gate  * Purpose: print out the server usage message
1230Sstevel@tonic-gate  *
1240Sstevel@tonic-gate  * Arguments:
1250Sstevel@tonic-gate  * Requires:
1260Sstevel@tonic-gate  * Effects:
1270Sstevel@tonic-gate  * Modifies:
1280Sstevel@tonic-gate  */
1290Sstevel@tonic-gate 
1300Sstevel@tonic-gate void
1310Sstevel@tonic-gate usage()
1320Sstevel@tonic-gate {
1330Sstevel@tonic-gate 	fprintf(stderr, gettext("Usage: kadmind [-r realm] [-m] [-d] "
1340Sstevel@tonic-gate 	    "[-p port-number]\n"));
1350Sstevel@tonic-gate 	exit(1);
1360Sstevel@tonic-gate }
1370Sstevel@tonic-gate 
1380Sstevel@tonic-gate /*
1390Sstevel@tonic-gate  * Function: display_status
1400Sstevel@tonic-gate  *
1410Sstevel@tonic-gate  * Purpose: displays GSS-API messages
1420Sstevel@tonic-gate  *
1430Sstevel@tonic-gate  * Arguments:
1440Sstevel@tonic-gate  *
1450Sstevel@tonic-gate  * 	msg		a string to be displayed with the message
1460Sstevel@tonic-gate  * 	maj_stat	the GSS-API major status code
1470Sstevel@tonic-gate  * 	min_stat	the GSS-API minor status code
1480Sstevel@tonic-gate  *
1490Sstevel@tonic-gate  * Effects:
1500Sstevel@tonic-gate  *
1510Sstevel@tonic-gate  * The GSS-API messages associated with maj_stat and min_stat are
1520Sstevel@tonic-gate  * displayed on stderr, each preceeded by "GSS-API error <msg>: " and
1530Sstevel@tonic-gate  * followed by a newline.
1540Sstevel@tonic-gate  */
1550Sstevel@tonic-gate static void display_status_1();
1560Sstevel@tonic-gate 
1570Sstevel@tonic-gate void display_status(msg, maj_stat, min_stat)
1580Sstevel@tonic-gate      char *msg;
1590Sstevel@tonic-gate      OM_uint32 maj_stat;
1600Sstevel@tonic-gate      OM_uint32 min_stat;
1610Sstevel@tonic-gate {
1620Sstevel@tonic-gate      display_status_1(msg, maj_stat, GSS_C_GSS_CODE);
1630Sstevel@tonic-gate      display_status_1(msg, min_stat, GSS_C_MECH_CODE);
1640Sstevel@tonic-gate }
1650Sstevel@tonic-gate 
1660Sstevel@tonic-gate static void display_status_1(m, code, type)
1670Sstevel@tonic-gate      char *m;
1680Sstevel@tonic-gate      OM_uint32 code;
1690Sstevel@tonic-gate      int type;
1700Sstevel@tonic-gate {
1710Sstevel@tonic-gate 	OM_uint32 maj_stat, min_stat;
1720Sstevel@tonic-gate 	gss_buffer_desc msg;
1730Sstevel@tonic-gate 	OM_uint32 msg_ctx;
1740Sstevel@tonic-gate 
1750Sstevel@tonic-gate 	msg_ctx = 0;
1760Sstevel@tonic-gate 	while (1) {
1770Sstevel@tonic-gate 		maj_stat = gss_display_status(&min_stat, code,
1780Sstevel@tonic-gate 					      type, GSS_C_NULL_OID,
1790Sstevel@tonic-gate 					      &msg_ctx, &msg);
1800Sstevel@tonic-gate 		fprintf(stderr, "GSS-API error %s: %s\n", m,
1810Sstevel@tonic-gate 			(char *)msg.value);
1820Sstevel@tonic-gate 		(void) gss_release_buffer(&min_stat, &msg);
1830Sstevel@tonic-gate 
1840Sstevel@tonic-gate 		if (!msg_ctx)
1850Sstevel@tonic-gate 			break;
1860Sstevel@tonic-gate 	}
1870Sstevel@tonic-gate }
1880Sstevel@tonic-gate 
1890Sstevel@tonic-gate 
1900Sstevel@tonic-gate /*
1910Sstevel@tonic-gate  * Solaris Kerberos: the following prototypes are needed because these are
1920Sstevel@tonic-gate  * private interfaces that do not have prototypes in any .h
1930Sstevel@tonic-gate  */
1940Sstevel@tonic-gate 
1950Sstevel@tonic-gate extern struct hostent   *res_getipnodebyaddr(const void *, size_t, int, int *);
1960Sstevel@tonic-gate extern void             res_freehostent(struct hostent *);
1970Sstevel@tonic-gate 
1980Sstevel@tonic-gate static void
1990Sstevel@tonic-gate freedomnames(char **npp)
2000Sstevel@tonic-gate {
2010Sstevel@tonic-gate 	char **tpp;
2020Sstevel@tonic-gate 
2030Sstevel@tonic-gate 	if (npp) {
2040Sstevel@tonic-gate 		tpp = npp;
2050Sstevel@tonic-gate 		while (*tpp++) {
2060Sstevel@tonic-gate 			free(*(tpp-1));
2070Sstevel@tonic-gate 		}
2080Sstevel@tonic-gate 		free(npp);
2090Sstevel@tonic-gate 	}
2100Sstevel@tonic-gate }
2110Sstevel@tonic-gate 
2120Sstevel@tonic-gate /*
2130Sstevel@tonic-gate  * Construct a list of uniq FQDNs of all the net interfaces (except
2140Sstevel@tonic-gate  * krb5.conf master dups) and return it in arg 'dnames'.
2150Sstevel@tonic-gate  *
2160Sstevel@tonic-gate  * On successful return (0), caller must call freedomnames()
2170Sstevel@tonic-gate  * to free memory.
2180Sstevel@tonic-gate  */
2190Sstevel@tonic-gate static int
2200Sstevel@tonic-gate getdomnames(krb5_context ctx, char *realm, char ***dnames)
2210Sstevel@tonic-gate {
2220Sstevel@tonic-gate 	krb5_address **addresses = NULL;
2230Sstevel@tonic-gate 	krb5_address *a = NULL;
2240Sstevel@tonic-gate 	struct hostent *hp = NULL;
2250Sstevel@tonic-gate 	int ret, i, result=0, error;
2260Sstevel@tonic-gate 	char **npp = NULL, **tpp=NULL;
2270Sstevel@tonic-gate 	int dup=0, n = 0;
2280Sstevel@tonic-gate 	char *cfhost = NULL; /* krb5 conf file master hostname */
2290Sstevel@tonic-gate 
2300Sstevel@tonic-gate 	if (ret = kadm5_get_master(ctx, realm, &cfhost)) {
2310Sstevel@tonic-gate 		return (ret);
2320Sstevel@tonic-gate 	}
2330Sstevel@tonic-gate 
2340Sstevel@tonic-gate 	ret = krb5_os_localaddr(ctx, &addresses);
2350Sstevel@tonic-gate 	if (ret != 0) {
2360Sstevel@tonic-gate 		if (nofork)
2370Sstevel@tonic-gate 			(void) fprintf(stderr,
2380Sstevel@tonic-gate 				    "kadmind: get localaddrs failed: %s",
2390Sstevel@tonic-gate 				    error_message(ret));
2400Sstevel@tonic-gate 		result = ret;
2410Sstevel@tonic-gate 		goto err;
2420Sstevel@tonic-gate 	}
2430Sstevel@tonic-gate 
2440Sstevel@tonic-gate 
2450Sstevel@tonic-gate 	for (i=0; addresses[i]; i++) {
2460Sstevel@tonic-gate 		a = addresses[i];
2470Sstevel@tonic-gate 		hp = res_getipnodebyaddr(a->contents, a->length,
2480Sstevel@tonic-gate 					a->addrtype == ADDRTYPE_INET
2490Sstevel@tonic-gate 					? AF_INET : AF_INET6,
2500Sstevel@tonic-gate 					&error);
2510Sstevel@tonic-gate 		if (hp != NULL) {
2520Sstevel@tonic-gate 
2530Sstevel@tonic-gate 			/* skip master host in krb5.conf */
2540Sstevel@tonic-gate 			if (strcasecmp(cfhost, hp->h_name) == 0) {
2550Sstevel@tonic-gate 				res_freehostent(hp);
2560Sstevel@tonic-gate 				hp = NULL;
2570Sstevel@tonic-gate 				continue;
2580Sstevel@tonic-gate 			}
2590Sstevel@tonic-gate 
2600Sstevel@tonic-gate 			dup = 0;
2610Sstevel@tonic-gate 			tpp = npp;
2620Sstevel@tonic-gate 			/* skip if hostname already exists in list */
2630Sstevel@tonic-gate 			while (tpp && *tpp++) {
2640Sstevel@tonic-gate 				if (strcasecmp(*(tpp-1), hp->h_name) == 0) {
2650Sstevel@tonic-gate 					dup++;
2660Sstevel@tonic-gate 					break;
2670Sstevel@tonic-gate 				}
2680Sstevel@tonic-gate 			}
2690Sstevel@tonic-gate 
2700Sstevel@tonic-gate 			if (dup) {
2710Sstevel@tonic-gate 				res_freehostent(hp);
2720Sstevel@tonic-gate 				hp = NULL;
2730Sstevel@tonic-gate 				continue;
2740Sstevel@tonic-gate 			}
2750Sstevel@tonic-gate 
2760Sstevel@tonic-gate 			npp = realloc(npp, sizeof(char *) * (n + 2));
2770Sstevel@tonic-gate 			if (!npp) {
2780Sstevel@tonic-gate 				result = ENOMEM;
2790Sstevel@tonic-gate 				goto err;
2800Sstevel@tonic-gate 			}
2810Sstevel@tonic-gate 			npp[n] = strdup(hp->h_name);
2820Sstevel@tonic-gate 			if (!npp[n]) {
2830Sstevel@tonic-gate 				result = ENOMEM;
2840Sstevel@tonic-gate 				goto err;
2850Sstevel@tonic-gate 			}
2860Sstevel@tonic-gate 			npp[n+1] = NULL;
2870Sstevel@tonic-gate 			n++;
2880Sstevel@tonic-gate 
2890Sstevel@tonic-gate 			res_freehostent(hp);
2900Sstevel@tonic-gate 			hp = NULL;
2910Sstevel@tonic-gate 			result = 0;
2920Sstevel@tonic-gate 		}
2930Sstevel@tonic-gate 
2940Sstevel@tonic-gate 	}
2950Sstevel@tonic-gate 
2960Sstevel@tonic-gate #ifdef DEBUG
2970Sstevel@tonic-gate 	printf("getdomnames: n=%d, i=%d, npp=%p\n", n, i, npp);
2980Sstevel@tonic-gate 	tpp = npp;
2990Sstevel@tonic-gate 	while (tpp && *tpp++) {
3000Sstevel@tonic-gate 		printf("tpp=%s\n", *(tpp-1));
3010Sstevel@tonic-gate 	}
3020Sstevel@tonic-gate #endif
3030Sstevel@tonic-gate 
3040Sstevel@tonic-gate 	goto out;
3050Sstevel@tonic-gate 
3060Sstevel@tonic-gate err:
3070Sstevel@tonic-gate 	if (npp) {
3080Sstevel@tonic-gate 		freedomnames(npp);
3090Sstevel@tonic-gate 		npp = NULL;
3100Sstevel@tonic-gate 	}
3110Sstevel@tonic-gate 
3120Sstevel@tonic-gate 	if (hp) {
3130Sstevel@tonic-gate 		res_freehostent(hp);
3140Sstevel@tonic-gate 		hp = NULL;
3150Sstevel@tonic-gate 	}
3160Sstevel@tonic-gate 
3170Sstevel@tonic-gate out:
3180Sstevel@tonic-gate 	if (cfhost) {
3190Sstevel@tonic-gate 		free (cfhost);
3200Sstevel@tonic-gate 		cfhost = NULL;
3210Sstevel@tonic-gate 	}
3220Sstevel@tonic-gate 	if (addresses) {
3230Sstevel@tonic-gate 		krb5_free_addresses(ctx, addresses);
3240Sstevel@tonic-gate 		addresses = NULL;
3250Sstevel@tonic-gate 	}
3260Sstevel@tonic-gate 
3270Sstevel@tonic-gate 	if (result == 0)
3280Sstevel@tonic-gate 		*dnames = npp;
3290Sstevel@tonic-gate 
3300Sstevel@tonic-gate 	return (result);
3310Sstevel@tonic-gate }
3320Sstevel@tonic-gate 
3330Sstevel@tonic-gate /*
3340Sstevel@tonic-gate  * Set the rpcsec_gss svc names for all net interfaces.
3350Sstevel@tonic-gate  */
3360Sstevel@tonic-gate static void
3370Sstevel@tonic-gate set_svc_domnames(char *svcname, char **dnames,
3380Sstevel@tonic-gate 		u_int program, u_int version)
3390Sstevel@tonic-gate {
3400Sstevel@tonic-gate 	bool_t ret;
3410Sstevel@tonic-gate 	char **tpp = dnames;
3420Sstevel@tonic-gate 
3430Sstevel@tonic-gate 	if (!tpp)
3440Sstevel@tonic-gate 		return;
3450Sstevel@tonic-gate 
3460Sstevel@tonic-gate 	while (*tpp++) {
3470Sstevel@tonic-gate 		/* MAX_NAME_LEN from rpc/rpcsec_gss.h */
3480Sstevel@tonic-gate 		char name[MAXHOSTNAMELEN+MAX_NAME_LEN+2] = {0};
3490Sstevel@tonic-gate 		(void) snprintf(name, sizeof(name), "%s@%s",
3500Sstevel@tonic-gate 				svcname, *(tpp-1));
3510Sstevel@tonic-gate 		ret = rpc_gss_set_svc_name(name,
3520Sstevel@tonic-gate 					"kerberos_v5", 0,
3530Sstevel@tonic-gate 					program, version);
3540Sstevel@tonic-gate 		if (nofork && ret)
3550Sstevel@tonic-gate 			(void) fprintf(stderr,
3560Sstevel@tonic-gate 				    "rpc_gss_set_svc_name success: %s\n",
3570Sstevel@tonic-gate 				    name);
3580Sstevel@tonic-gate 	}
3590Sstevel@tonic-gate }
3600Sstevel@tonic-gate 
3610Sstevel@tonic-gate 
3620Sstevel@tonic-gate 
3630Sstevel@tonic-gate 
3640Sstevel@tonic-gate int
3650Sstevel@tonic-gate main(int argc, char *argv[])
3660Sstevel@tonic-gate {
3670Sstevel@tonic-gate 	void kadm_1(struct svc_req *, SVCXPRT *);
3680Sstevel@tonic-gate 	SVCXPRT *transp;
3690Sstevel@tonic-gate 	extern char *optarg;
3700Sstevel@tonic-gate 	extern int optind, opterr;
3710Sstevel@tonic-gate 	int ret, rlen, oldnames = 0;
3720Sstevel@tonic-gate 	OM_uint32 OMret, major_status, minor_status;
3730Sstevel@tonic-gate 	char *whoami;
3740Sstevel@tonic-gate 	FILE *acl_file;
3750Sstevel@tonic-gate 	gss_buffer_desc in_buf;
3760Sstevel@tonic-gate 	struct servent *srv;
3770Sstevel@tonic-gate 	struct sockaddr_in addr;
3780Sstevel@tonic-gate 	struct sockaddr_in *sin;
3790Sstevel@tonic-gate 	int s;
3800Sstevel@tonic-gate 	int optchar;
3810Sstevel@tonic-gate 	struct netconfig *nconf;
3820Sstevel@tonic-gate 	void *handlep;
3830Sstevel@tonic-gate 	int fd;
3840Sstevel@tonic-gate 	struct t_info tinfo;
3850Sstevel@tonic-gate 	struct t_bind tbindstr, *tres;
3860Sstevel@tonic-gate 
3870Sstevel@tonic-gate 	struct t_optmgmt req, resp;
3880Sstevel@tonic-gate 	struct opthdr *opt;
3890Sstevel@tonic-gate 	char reqbuf[128];
3900Sstevel@tonic-gate 	struct rlimit rl;
3910Sstevel@tonic-gate 
3920Sstevel@tonic-gate 	char *kiprop_name = NULL; /* IProp svc name */
3930Sstevel@tonic-gate 	kdb_log_context *log_ctx;
3940Sstevel@tonic-gate 	kadm5_server_handle_t handle;
3950Sstevel@tonic-gate 	krb5_context ctx;
3960Sstevel@tonic-gate 
3970Sstevel@tonic-gate 	kadm5_config_params params;
3980Sstevel@tonic-gate 	auth_gssapi_name names[6];
3990Sstevel@tonic-gate      	gss_buffer_desc gssbuf;
4000Sstevel@tonic-gate      	gss_OID nt_krb5_name_oid;
4010Sstevel@tonic-gate 
4020Sstevel@tonic-gate 	char **dnames = NULL;
4030Sstevel@tonic-gate 	int retdn;
4040Sstevel@tonic-gate 
4050Sstevel@tonic-gate 	/* This is OID value the Krb5_Name NameType */
4060Sstevel@tonic-gate      	gssbuf.value = "{1 2 840 113554 1 2 2 1}";
4070Sstevel@tonic-gate      	gssbuf.length = strlen(gssbuf.value);
4080Sstevel@tonic-gate      	major_status = gss_str_to_oid(&minor_status, &gssbuf,
4090Sstevel@tonic-gate 				    &nt_krb5_name_oid);
4100Sstevel@tonic-gate      	if (major_status != GSS_S_COMPLETE) {
4110Sstevel@tonic-gate 		fprintf(stderr,
4120Sstevel@tonic-gate 			gettext("Couldn't create KRB5 Name NameType OID\n"));
4130Sstevel@tonic-gate 		display_status("str_to_oid", major_status, minor_status);
4140Sstevel@tonic-gate 		exit(1);
4150Sstevel@tonic-gate      	}
4160Sstevel@tonic-gate 
4170Sstevel@tonic-gate 	names[0].name = names[1].name = names[2].name =
4180Sstevel@tonic-gate 		names[3].name = names[4].name  = names[5].name =NULL;
4190Sstevel@tonic-gate 	names[0].type = names[1].type = names[2].type =
4200Sstevel@tonic-gate 		names[3].type = names[4].type = names[5].type =
4210Sstevel@tonic-gate 		(gss_OID) nt_krb5_name_oid;
4220Sstevel@tonic-gate 
4230Sstevel@tonic-gate 	whoami = (strrchr(argv[0], '/') ? strrchr(argv[0], '/') + 1 : argv[0]);
4240Sstevel@tonic-gate 
4250Sstevel@tonic-gate 	(void) setlocale(LC_ALL, "");
4260Sstevel@tonic-gate 
4270Sstevel@tonic-gate #if !defined(TEXT_DOMAIN)  /* Should be defined by cc -D */
4280Sstevel@tonic-gate #define	TEXT_DOMAIN	"SYS_TEST"	/* Use this only if it weren't */
4290Sstevel@tonic-gate #endif
4300Sstevel@tonic-gate 
4310Sstevel@tonic-gate 	(void) textdomain(TEXT_DOMAIN);
4320Sstevel@tonic-gate 
4330Sstevel@tonic-gate 	nofork = 0;
4340Sstevel@tonic-gate 
4350Sstevel@tonic-gate 	memset((char *) &params, 0, sizeof (params));
4360Sstevel@tonic-gate 
4370Sstevel@tonic-gate 	while ((optchar = getopt(argc, argv, "r:mdp:")) != EOF) {
4380Sstevel@tonic-gate 		switch (optchar) {
4390Sstevel@tonic-gate 		case 'r':
4400Sstevel@tonic-gate 			if (!optarg)
4410Sstevel@tonic-gate 				usage();
4420Sstevel@tonic-gate 			params.realm = optarg;
4430Sstevel@tonic-gate 			params.mask |= KADM5_CONFIG_REALM;
4440Sstevel@tonic-gate 			break;
4450Sstevel@tonic-gate 		case 'm':
4460Sstevel@tonic-gate 			params.mkey_from_kbd = 1;
4470Sstevel@tonic-gate 			params.mask |= KADM5_CONFIG_MKEY_FROM_KBD;
4480Sstevel@tonic-gate 			break;
4490Sstevel@tonic-gate 		case 'd':
4500Sstevel@tonic-gate 			nofork = 1;
4510Sstevel@tonic-gate 			break;
4520Sstevel@tonic-gate 		case 'p':
4530Sstevel@tonic-gate 			if (!optarg)
4540Sstevel@tonic-gate 				usage();
4550Sstevel@tonic-gate 			params.kadmind_port = atoi(optarg);
4560Sstevel@tonic-gate 			params.mask |= KADM5_CONFIG_KADMIND_PORT;
4570Sstevel@tonic-gate 			break;
4580Sstevel@tonic-gate 		case '?':
4590Sstevel@tonic-gate 		default:
4600Sstevel@tonic-gate 			usage();
4610Sstevel@tonic-gate 		}
4620Sstevel@tonic-gate 	}
4630Sstevel@tonic-gate 
4640Sstevel@tonic-gate 
4650Sstevel@tonic-gate 	if (getrlimit(RLIMIT_NOFILE, &rl) == 0) {
4660Sstevel@tonic-gate 		rl.rlim_cur = rl.rlim_max = MAX(rl.rlim_max, FD_SETSIZE);
4670Sstevel@tonic-gate 		setrlimit(RLIMIT_NOFILE, &rl);
4680Sstevel@tonic-gate 	}
4690Sstevel@tonic-gate 
4700Sstevel@tonic-gate 	if (!nofork && (ret = daemon(0, 0))) {
4710Sstevel@tonic-gate 		ret = errno;
4720Sstevel@tonic-gate 		krb5_klog_syslog(LOG_ERR,
4730Sstevel@tonic-gate 		    gettext("Cannot detach from tty: %s"),
4740Sstevel@tonic-gate 		    error_message(ret));
4750Sstevel@tonic-gate 		fprintf(stderr, gettext("%s: Cannot detach from tty: %s\n"),
4760Sstevel@tonic-gate 		    whoami, error_message(ret));
4770Sstevel@tonic-gate 		krb5_klog_close(context);
4780Sstevel@tonic-gate 		exit(1);
4790Sstevel@tonic-gate 	}
4800Sstevel@tonic-gate 
4810Sstevel@tonic-gate 	if (ret = krb5_init_context(&context)) {
4820Sstevel@tonic-gate 		fprintf(stderr,
4830Sstevel@tonic-gate 		    gettext("%s: %s while initializing context, aborting\n"),
4840Sstevel@tonic-gate 		    whoami, error_message(ret));
4850Sstevel@tonic-gate 		exit(1);
4860Sstevel@tonic-gate 	}
4870Sstevel@tonic-gate 
4880Sstevel@tonic-gate 	krb5_klog_init(context, "admin_server", whoami, 1);
4890Sstevel@tonic-gate 
4900Sstevel@tonic-gate 
4910Sstevel@tonic-gate 	/*
4920Sstevel@tonic-gate 	 * When using the Horowitz/IETF protocol for
4930Sstevel@tonic-gate 	 * password changing, the default port is 464
4940Sstevel@tonic-gate 	 * (officially recognized by IANA)
4950Sstevel@tonic-gate 	 *
4960Sstevel@tonic-gate 	 * DEFAULT_KPASSWD_PORT -> 464
4970Sstevel@tonic-gate 	 */
4980Sstevel@tonic-gate 	chgpw_params.kpasswd_port = DEFAULT_KPASSWD_PORT;
4990Sstevel@tonic-gate 	chgpw_params.mask |= KADM5_CONFIG_KPASSWD_PORT;
5000Sstevel@tonic-gate 	chgpw_params.kpasswd_protocol = KRB5_CHGPWD_CHANGEPW_V2;
5010Sstevel@tonic-gate 	chgpw_params.mask |= KADM5_CONFIG_KPASSWD_PROTOCOL;
5020Sstevel@tonic-gate 
5030Sstevel@tonic-gate 	if (ret = kadm5_get_config_params(context, NULL, NULL, &chgpw_params,
5040Sstevel@tonic-gate 		&chgpw_params)) {
5050Sstevel@tonic-gate 		krb5_klog_syslog(LOG_ERR, gettext("%s: %s while initializing,"
5060Sstevel@tonic-gate 				" aborting"), whoami, error_message(ret));
5070Sstevel@tonic-gate 		fprintf(stderr,
5080Sstevel@tonic-gate 		    gettext("%s: %s while initializing, aborting\n"),
5090Sstevel@tonic-gate 		    whoami, error_message(ret));
5100Sstevel@tonic-gate 		krb5_klog_close(context);
5110Sstevel@tonic-gate 		exit(1);
5120Sstevel@tonic-gate 	}
5130Sstevel@tonic-gate 
5140Sstevel@tonic-gate 	/*
5150Sstevel@tonic-gate 	 * We now setup the socket and bind() to port 464, so that
5160Sstevel@tonic-gate 	 * kadmind can now listen to and process change-pwd requests
5170Sstevel@tonic-gate 	 * from non-Solaris Kerberos V5 clients such as Microsoft,
5180Sstevel@tonic-gate 	 * MIT, AIX, HP etc
5190Sstevel@tonic-gate 	 */
5200Sstevel@tonic-gate 	if ((schpw = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
5210Sstevel@tonic-gate 		krb5_klog_syslog(LOG_ERR, gettext( "cannot create simple "
5220Sstevel@tonic-gate 				"chpw socket: %s"), error_message(errno));
5230Sstevel@tonic-gate 		fprintf(stderr, gettext("Cannot create simple chpw "
5240Sstevel@tonic-gate 					"socket: %s"), error_message(errno));
5250Sstevel@tonic-gate 		krb5_klog_close(context);
5260Sstevel@tonic-gate 		exit(1);
5270Sstevel@tonic-gate 	}
5280Sstevel@tonic-gate 
5290Sstevel@tonic-gate 	memset(&addr, 0, sizeof(addr));
5300Sstevel@tonic-gate 	addr.sin_family = AF_INET;
5310Sstevel@tonic-gate 	addr.sin_addr.s_addr = INADDR_ANY;
5320Sstevel@tonic-gate 	addr.sin_port = htons(chgpw_params.kpasswd_port);
5330Sstevel@tonic-gate 
5340Sstevel@tonic-gate 	if (bind(schpw, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
5350Sstevel@tonic-gate 		char portbuf[32];
5360Sstevel@tonic-gate 		int oerrno = errno;
5370Sstevel@tonic-gate 		fprintf(stderr, gettext("%s: Cannot bind socket.\n"), whoami);
5380Sstevel@tonic-gate 		fprintf(stderr, gettext("bind: %s\n"), error_message(oerrno));
5390Sstevel@tonic-gate 		errno = oerrno;
5400Sstevel@tonic-gate 		(void) snprintf(portbuf, sizeof (portbuf), "%d",
5410Sstevel@tonic-gate 				ntohs(addr.sin_port));
5420Sstevel@tonic-gate 		krb5_klog_syslog(LOG_ERR, gettext("cannot bind simple "
5430Sstevel@tonic-gate 				"chpw socket: %s"), error_message(oerrno));
5440Sstevel@tonic-gate 		if(oerrno == EADDRINUSE) {
5450Sstevel@tonic-gate 			char *w = strrchr(whoami, '/');
5460Sstevel@tonic-gate 			if (w) {
5470Sstevel@tonic-gate 				w++;
5480Sstevel@tonic-gate 			}
5490Sstevel@tonic-gate 			else {
5500Sstevel@tonic-gate 				w = whoami;
5510Sstevel@tonic-gate 			}
5520Sstevel@tonic-gate 			fprintf(stderr, gettext(
5530Sstevel@tonic-gate 				"This probably means that another %s process\n"
5540Sstevel@tonic-gate 				"is already running, or that another program\n"
5550Sstevel@tonic-gate 				"is using the server port (number %d).\n"
5560Sstevel@tonic-gate 				"If another %s is already running, you should\n"
5570Sstevel@tonic-gate 				"kill it before restarting the server.\n"),
5580Sstevel@tonic-gate 				w, ntohs(addr.sin_port), w);
5590Sstevel@tonic-gate 		}
5600Sstevel@tonic-gate 		krb5_klog_close(context);
5610Sstevel@tonic-gate 		exit(1);
5620Sstevel@tonic-gate 	}
5630Sstevel@tonic-gate 
5640Sstevel@tonic-gate 	if (ret = kadm5_get_config_params(context, NULL, NULL, &params,
5650Sstevel@tonic-gate 		&params)) {
5660Sstevel@tonic-gate 		krb5_klog_syslog(LOG_ERR, gettext("%s: %s while initializing,"
5670Sstevel@tonic-gate 				" aborting"), whoami, error_message(ret));
5680Sstevel@tonic-gate 		fprintf(stderr,
5690Sstevel@tonic-gate 		    gettext("%s: %s while initializing, aborting\n"),
5700Sstevel@tonic-gate 		    whoami, error_message(ret));
5710Sstevel@tonic-gate 		krb5_klog_close(context);
5720Sstevel@tonic-gate 		exit(1);
5730Sstevel@tonic-gate 	}
5740Sstevel@tonic-gate #define	REQUIRED_PARAMS (KADM5_CONFIG_REALM | KADM5_CONFIG_ACL_FILE | \
5750Sstevel@tonic-gate 			KADM5_CONFIG_ADMIN_KEYTAB)
5760Sstevel@tonic-gate 
5770Sstevel@tonic-gate 	if ((params.mask & REQUIRED_PARAMS) != REQUIRED_PARAMS) {
5780Sstevel@tonic-gate 		krb5_klog_syslog(LOG_ERR,
5790Sstevel@tonic-gate 		    gettext("%s: Missing required configuration values "
5800Sstevel@tonic-gate 			"while initializing, aborting"), whoami,
5810Sstevel@tonic-gate 		    (params.mask & REQUIRED_PARAMS) ^ REQUIRED_PARAMS);
5820Sstevel@tonic-gate 		fprintf(stderr,
5830Sstevel@tonic-gate 		    gettext("%s: Missing required configuration values "
5840Sstevel@tonic-gate 			"(%x) while initializing, aborting\n"), whoami,
5850Sstevel@tonic-gate 		    (params.mask & REQUIRED_PARAMS) ^ REQUIRED_PARAMS);
5860Sstevel@tonic-gate 		krb5_klog_close(context);
5870Sstevel@tonic-gate 		exit(1);
5880Sstevel@tonic-gate 	}
5890Sstevel@tonic-gate 	memset((char *) &addr, 0, sizeof (struct sockaddr_in));
5900Sstevel@tonic-gate 	addr.sin_family = AF_INET;
5910Sstevel@tonic-gate 	addr.sin_addr.s_addr = INADDR_ANY;
5920Sstevel@tonic-gate 	l_port = addr.sin_port = htons(params.kadmind_port);
5930Sstevel@tonic-gate 	sin = &addr;
5940Sstevel@tonic-gate 
5950Sstevel@tonic-gate 	if ((handlep = setnetconfig()) == (void *) NULL) {
5960Sstevel@tonic-gate 		(void) krb5_klog_syslog(LOG_ERR,
5970Sstevel@tonic-gate 		    gettext("cannot get any transport information"));
5980Sstevel@tonic-gate 		krb5_klog_close(context);
5990Sstevel@tonic-gate 		exit(1);
6000Sstevel@tonic-gate 	}
6010Sstevel@tonic-gate 	while (nconf = getnetconfig(handlep)) {
6020Sstevel@tonic-gate 		if ((nconf->nc_semantics == NC_TPI_COTS_ORD) &&
6030Sstevel@tonic-gate 		    (strcmp(nconf->nc_protofmly, NC_INET) == 0) &&
6040Sstevel@tonic-gate 		    (strcmp(nconf->nc_proto, NC_TCP) == 0))
6050Sstevel@tonic-gate 			break;
6060Sstevel@tonic-gate 	}
6070Sstevel@tonic-gate 
6080Sstevel@tonic-gate 	if (nconf == (struct netconfig *) NULL) {
6090Sstevel@tonic-gate 		(void) endnetconfig(handlep);
6100Sstevel@tonic-gate 		krb5_klog_close(context);
6110Sstevel@tonic-gate 		exit(1);
6120Sstevel@tonic-gate 	}
6130Sstevel@tonic-gate 	fd = t_open(nconf->nc_device, O_RDWR, &tinfo);
6140Sstevel@tonic-gate 	if (fd == -1) {
6150Sstevel@tonic-gate 		krb5_klog_syslog(LOG_ERR,
6160Sstevel@tonic-gate 		    gettext("unable to open connection for ADMIN server"));
6170Sstevel@tonic-gate 		krb5_klog_close(context);
6180Sstevel@tonic-gate 		exit(1);
6190Sstevel@tonic-gate 	}
6200Sstevel@tonic-gate 	/* LINTED */
6210Sstevel@tonic-gate 	opt = (struct opthdr *) reqbuf;
6220Sstevel@tonic-gate 	opt->level = SOL_SOCKET;
6230Sstevel@tonic-gate 	opt->name = SO_REUSEADDR;
6240Sstevel@tonic-gate 	opt->len = sizeof (int);
6250Sstevel@tonic-gate 
6260Sstevel@tonic-gate 	/*
6270Sstevel@tonic-gate 	 * The option value is "1".  This will allow the server to restart
6280Sstevel@tonic-gate 	 * whilst the previous process is cleaning up after itself in a
6290Sstevel@tonic-gate 	 * FIN_WAIT_2 or TIME_WAIT state.  If another process is started
6300Sstevel@tonic-gate 	 * outside of smf(5) then bind will fail anyway, which is what we want.
6310Sstevel@tonic-gate 	 */
6320Sstevel@tonic-gate 	reqbuf[sizeof (struct opthdr)] = 1;
6330Sstevel@tonic-gate 
6340Sstevel@tonic-gate 	req.flags = T_NEGOTIATE;
6350Sstevel@tonic-gate 	req.opt.len = sizeof (struct opthdr) + opt->len;
6360Sstevel@tonic-gate 	req.opt.buf = (char *) opt;
6370Sstevel@tonic-gate 
6380Sstevel@tonic-gate 	resp.flags = 0;
6390Sstevel@tonic-gate 	resp.opt.buf = reqbuf;
6400Sstevel@tonic-gate 	resp.opt.maxlen = sizeof (reqbuf);
6410Sstevel@tonic-gate 
6420Sstevel@tonic-gate 	if (t_optmgmt(fd, &req, &resp) < 0 || resp.flags != T_SUCCESS) {
6430Sstevel@tonic-gate 		t_error("t_optmgmt");
6440Sstevel@tonic-gate 		exit(1);
6450Sstevel@tonic-gate 	}
6460Sstevel@tonic-gate 	/* Transform addr to netbuf */
6470Sstevel@tonic-gate 
6480Sstevel@tonic-gate 	tres = (struct t_bind *) t_alloc(fd, T_BIND, T_ADDR);
6490Sstevel@tonic-gate 	if (tres == NULL) {
6500Sstevel@tonic-gate 		(void) t_close(fd);
6510Sstevel@tonic-gate 		(void) krb5_klog_syslog(LOG_ERR,
6520Sstevel@tonic-gate 					gettext("cannot allocate netbuf"));
6530Sstevel@tonic-gate 		krb5_klog_close(context);
6540Sstevel@tonic-gate 		exit(1);
6550Sstevel@tonic-gate 	}
6560Sstevel@tonic-gate 	tbindstr.qlen = 8;
6570Sstevel@tonic-gate 	tbindstr.addr.buf = (char *) sin;
6580Sstevel@tonic-gate 	tbindstr.addr.len = tbindstr.addr.maxlen = __rpc_get_a_size(tinfo.addr);
6590Sstevel@tonic-gate 	sin = (struct sockaddr_in *) tbindstr.addr.buf;
6600Sstevel@tonic-gate 	/* SUNWresync121 XXX (void) memset(&addr, 0, sizeof(addr)); */
6610Sstevel@tonic-gate 
6620Sstevel@tonic-gate 	if (t_bind(fd, &tbindstr, tres) < 0) {
6630Sstevel@tonic-gate 		int oerrno = errno;
6640Sstevel@tonic-gate 		fprintf(stderr, gettext("%s: Cannot bind socket.\n"), whoami);
6650Sstevel@tonic-gate 		fprintf(stderr, gettext("bind: %s\n"), error_message(oerrno));
6660Sstevel@tonic-gate 		errno = oerrno;
6670Sstevel@tonic-gate 		krb5_klog_syslog(LOG_ERR, gettext("Cannot bind socket: %s"),
6680Sstevel@tonic-gate 		    error_message(errno));
6690Sstevel@tonic-gate 		if (oerrno == EADDRINUSE) {
6700Sstevel@tonic-gate 			char *w = strrchr(whoami, '/');
6710Sstevel@tonic-gate 
6720Sstevel@tonic-gate 			if (w) {
6730Sstevel@tonic-gate 				w++;
6740Sstevel@tonic-gate 			} else {
6750Sstevel@tonic-gate 				w = whoami;
6760Sstevel@tonic-gate 			}
6770Sstevel@tonic-gate 			fprintf(stderr, gettext(
6780Sstevel@tonic-gate 				"This probably means that another %s "
6790Sstevel@tonic-gate 				"process is already\n"
6800Sstevel@tonic-gate 				"running, or that another program is using "
6810Sstevel@tonic-gate 				"the server port (number %d)\n"
6820Sstevel@tonic-gate 				"after being assigned it by the RPC "
6830Sstevel@tonic-gate 				"portmap deamon.	If another\n"
6840Sstevel@tonic-gate 				"%s is already running, you should kill "
6850Sstevel@tonic-gate 				"it before\n"
6860Sstevel@tonic-gate 				"restarting the server. If, on the other hand, "
6870Sstevel@tonic-gate 				"another program is\n"
6880Sstevel@tonic-gate 				"using the server port, you should kill it "
6890Sstevel@tonic-gate 				"before running\n"
6900Sstevel@tonic-gate 				"%s, and ensure that the conflict does "
6910Sstevel@tonic-gate 				"not occur in the\n"
6920Sstevel@tonic-gate 				"future by making sure that %s is started "
6930Sstevel@tonic-gate 				"on reboot\n"
6940Sstevel@tonic-gate 				"before portmap.\n"),
6950Sstevel@tonic-gate 			    w, ntohs(addr.sin_port), w, w, w);
6960Sstevel@tonic-gate 			krb5_klog_syslog(LOG_ERR,
6970Sstevel@tonic-gate 			    gettext("Check for already-running %s or for "
6980Sstevel@tonic-gate 				"another process using port %d"), w,
6990Sstevel@tonic-gate 			    htons(addr.sin_port));
7000Sstevel@tonic-gate 		}
7010Sstevel@tonic-gate 		krb5_klog_close(context);
7020Sstevel@tonic-gate 		exit(1);
7030Sstevel@tonic-gate 	}
7040Sstevel@tonic-gate 	transp = svc_tli_create(fd, nconf, NULL, 0, 0);
7050Sstevel@tonic-gate 	(void) t_free((char *) tres, T_BIND);
7060Sstevel@tonic-gate 	if (transp == NULL) {
7070Sstevel@tonic-gate 		fprintf(stderr, gettext("%s: Cannot create RPC service.\n"),
7080Sstevel@tonic-gate 			whoami);
7090Sstevel@tonic-gate 		krb5_klog_syslog(LOG_ERR, gettext("Cannot create RPC service: %m"));
7100Sstevel@tonic-gate 		krb5_klog_close(context);
7110Sstevel@tonic-gate 		exit(1);
7120Sstevel@tonic-gate 	}
7130Sstevel@tonic-gate 	if (!svc_register(transp, KADM, KADMVERS, kadm_1, 0)) {
7140Sstevel@tonic-gate 		fprintf(stderr,
7150Sstevel@tonic-gate 		    gettext("%s: Cannot register RPC service.\n"), whoami);
7160Sstevel@tonic-gate 		krb5_klog_syslog(LOG_ERR,
7170Sstevel@tonic-gate 		    gettext("Cannot register RPC service, failing."));
7180Sstevel@tonic-gate 		krb5_klog_close(context);
7190Sstevel@tonic-gate 		exit(1);
7200Sstevel@tonic-gate 	}
7210Sstevel@tonic-gate 
7220Sstevel@tonic-gate 	/*
7230Sstevel@tonic-gate 	 * XXX krb5_defkeyname is an internal library global and should go
7240Sstevel@tonic-gate 	 * away
7250Sstevel@tonic-gate 	 */
7260Sstevel@tonic-gate 	krb5_overridekeyname = params.admin_keytab;
7270Sstevel@tonic-gate 
7280Sstevel@tonic-gate 	(void) kadm5_get_adm_host_srv_name(context,
7290Sstevel@tonic-gate 					   params.realm, &names[0].name);
7300Sstevel@tonic-gate 	(void) kadm5_get_cpw_host_srv_name(context,
7310Sstevel@tonic-gate 					   params.realm, &names[1].name);
7320Sstevel@tonic-gate 	names[2].name = KADM5_ADMIN_SERVICE_P;
7330Sstevel@tonic-gate 	names[3].name = KADM5_CHANGEPW_SERVICE_P;
7340Sstevel@tonic-gate 	names[4].name = OVSEC_KADM_ADMIN_SERVICE_P;
7350Sstevel@tonic-gate 	names[5].name = OVSEC_KADM_CHANGEPW_SERVICE_P;
7360Sstevel@tonic-gate 
7370Sstevel@tonic-gate 	if (names[0].name == NULL || names[1].name == NULL ||
7380Sstevel@tonic-gate 	    names[2].name == NULL || names[3].name == NULL ||
7390Sstevel@tonic-gate 	    names[4].name == NULL || names[5].name == NULL) {
7400Sstevel@tonic-gate 		krb5_klog_syslog(LOG_ERR,
7410Sstevel@tonic-gate 		    gettext("Cannot initialize GSS-API authentication, "
7420Sstevel@tonic-gate 			"failing."));
7430Sstevel@tonic-gate 		fprintf(stderr,
7440Sstevel@tonic-gate 		    gettext("%s: Cannot initialize "
7450Sstevel@tonic-gate 			"GSS-API authentication.\n"),
7460Sstevel@tonic-gate 		    whoami);
7470Sstevel@tonic-gate 		krb5_klog_close(context);
7480Sstevel@tonic-gate 		exit(1);
7490Sstevel@tonic-gate 	}
7500Sstevel@tonic-gate 
7510Sstevel@tonic-gate 
7520Sstevel@tonic-gate 	/*
7530Sstevel@tonic-gate 	 * Try to acquire creds for the old OV services as well as the new
7540Sstevel@tonic-gate 	 * names, but if that fails just fall back on the new names.
7550Sstevel@tonic-gate 	 */
7560Sstevel@tonic-gate 
7570Sstevel@tonic-gate 	if (rpc_gss_set_svc_name(names[5].name,
7580Sstevel@tonic-gate 				"kerberos_v5", 0, KADM, KADMVERS) &&
7590Sstevel@tonic-gate 	    rpc_gss_set_svc_name(names[4].name,
7600Sstevel@tonic-gate 				"kerberos_v5", 0, KADM, KADMVERS))
7610Sstevel@tonic-gate 		oldnames++;
7620Sstevel@tonic-gate 	if (rpc_gss_set_svc_name(names[3].name,
7630Sstevel@tonic-gate 				"kerberos_v5", 0, KADM, KADMVERS))
7640Sstevel@tonic-gate 		oldnames++;
7650Sstevel@tonic-gate 	if (rpc_gss_set_svc_name(names[2].name,
7660Sstevel@tonic-gate 				"kerberos_v5", 0, KADM, KADMVERS))
7670Sstevel@tonic-gate 		oldnames++;
7680Sstevel@tonic-gate 	if (rpc_gss_set_svc_name(names[0].name,
7690Sstevel@tonic-gate 				"kerberos_v5", 0, KADM, KADMVERS))
7700Sstevel@tonic-gate 		oldnames++;
7710Sstevel@tonic-gate 	if (rpc_gss_set_svc_name(names[1].name,
7720Sstevel@tonic-gate 				"kerberos_v5", 0, KADM, KADMVERS))
7730Sstevel@tonic-gate 		oldnames++;
7740Sstevel@tonic-gate 
7750Sstevel@tonic-gate 	retdn = getdomnames(context, params.realm, &dnames);
7760Sstevel@tonic-gate 	if (retdn == 0 && dnames) {
7770Sstevel@tonic-gate 		/*
7780Sstevel@tonic-gate 		 * Multi-homed KDCs sometimes may need to set svc names
7790Sstevel@tonic-gate 		 * for multiple net interfaces so we set them for
7800Sstevel@tonic-gate 		 * all interfaces just in case.
7810Sstevel@tonic-gate 		 */
7820Sstevel@tonic-gate 		set_svc_domnames(KADM5_ADMIN_HOST_SERVICE,
7830Sstevel@tonic-gate 				dnames, KADM, KADMVERS);
7840Sstevel@tonic-gate 		set_svc_domnames(KADM5_CHANGEPW_HOST_SERVICE,
7850Sstevel@tonic-gate 				dnames, KADM, KADMVERS);
7860Sstevel@tonic-gate 	}
7870Sstevel@tonic-gate 
7880Sstevel@tonic-gate 	/* if set_names succeeded, this will too */
7890Sstevel@tonic-gate 	in_buf.value = names[1].name;
7900Sstevel@tonic-gate 	in_buf.length = strlen(names[1].name) + 1;
7910Sstevel@tonic-gate 	(void) gss_import_name(&OMret, &in_buf, (gss_OID) nt_krb5_name_oid,
7920Sstevel@tonic-gate 	    &gss_changepw_name);
7930Sstevel@tonic-gate 	if (oldnames) {
7940Sstevel@tonic-gate 		in_buf.value = names[3].name;
7950Sstevel@tonic-gate 		in_buf.length = strlen(names[3].name) + 1;
7960Sstevel@tonic-gate 		(void) gss_import_name(&OMret, &in_buf,
7970Sstevel@tonic-gate 					(gss_OID) nt_krb5_name_oid,
7980Sstevel@tonic-gate 					&gss_oldchangepw_name);
7990Sstevel@tonic-gate 	}
8000Sstevel@tonic-gate 	if (ret = acl_init(context, 0, params.acl_file)) {
8010Sstevel@tonic-gate 		krb5_klog_syslog(LOG_ERR, gettext("Cannot initialize acl file: %s"),
8020Sstevel@tonic-gate 		    error_message(ret));
8030Sstevel@tonic-gate 		fprintf(stderr, gettext("%s: Cannot initialize acl file: %s\n"),
8040Sstevel@tonic-gate 		    whoami, error_message(ret));
8050Sstevel@tonic-gate 		krb5_klog_close(context);
8060Sstevel@tonic-gate 		exit(1);
8070Sstevel@tonic-gate 	}
8080Sstevel@tonic-gate 	if ((ret = kadm5_init("kadmind", NULL,
8090Sstevel@tonic-gate 		    NULL, &params,
8100Sstevel@tonic-gate 		    KADM5_STRUCT_VERSION,
8110Sstevel@tonic-gate 		    KADM5_API_VERSION_2,
8120Sstevel@tonic-gate 		    &global_server_handle)) != KADM5_OK) {
8130Sstevel@tonic-gate 		krb5_klog_syslog(LOG_ERR,
8140Sstevel@tonic-gate 		    gettext("%s while initializing, aborting"),
8150Sstevel@tonic-gate 		    error_message(ret));
8160Sstevel@tonic-gate 		fprintf(stderr,
8170Sstevel@tonic-gate 		    gettext("%s: %s while initializing, aborting\n"),
8180Sstevel@tonic-gate 		    whoami, error_message(ret));
8190Sstevel@tonic-gate 		krb5_klog_close(context);
8200Sstevel@tonic-gate 		exit(1);
8210Sstevel@tonic-gate 	}
8220Sstevel@tonic-gate 
8230Sstevel@tonic-gate 	handle = global_server_handle;
8240Sstevel@tonic-gate 	ctx = handle->context;
8250Sstevel@tonic-gate 	if (params.iprop_enabled == TRUE)
8260Sstevel@tonic-gate 		ulog_set_role(ctx, IPROP_MASTER);
8270Sstevel@tonic-gate 	else
8280Sstevel@tonic-gate 		ulog_set_role(ctx, IPROP_NULL);
8290Sstevel@tonic-gate 
8300Sstevel@tonic-gate 	log_ctx = ctx->kdblog_context;
8310Sstevel@tonic-gate 
8320Sstevel@tonic-gate 	if (log_ctx && (log_ctx->iproprole == IPROP_MASTER)) {
8330Sstevel@tonic-gate 		/*
8340Sstevel@tonic-gate 		 * IProp is enabled, so let's map in the update log
8350Sstevel@tonic-gate 		 * and setup the service.
8360Sstevel@tonic-gate 		 */
8370Sstevel@tonic-gate 		if (ret = ulog_map(ctx, &params, FKADMIND)) {
8380Sstevel@tonic-gate 			fprintf(stderr,
8390Sstevel@tonic-gate 				gettext("%s: %s while mapping update log "
8400Sstevel@tonic-gate 				"(`%s.ulog')\n"), whoami, error_message(ret),
8410Sstevel@tonic-gate 				params.dbname);
8420Sstevel@tonic-gate 			krb5_klog_syslog(LOG_ERR,
8430Sstevel@tonic-gate 				gettext("%s while mapping update log "
8440Sstevel@tonic-gate 				"(`%s.ulog')"), error_message(ret),
8450Sstevel@tonic-gate 				params.dbname);
8460Sstevel@tonic-gate 			krb5_klog_close(ctx);
8470Sstevel@tonic-gate 			exit(1);
8480Sstevel@tonic-gate 		}
8490Sstevel@tonic-gate 
8500Sstevel@tonic-gate 
8510Sstevel@tonic-gate 		if (nofork)
8520Sstevel@tonic-gate 			fprintf(stderr,
8530Sstevel@tonic-gate 				"%s: create IPROP svc (PROG=%d, VERS=%d)\n",
8540Sstevel@tonic-gate 				whoami, KRB5_IPROP_PROG, KRB5_IPROP_VERS);
8550Sstevel@tonic-gate 
8560Sstevel@tonic-gate 		if (!svc_create(krb5_iprop_prog_1,
8570Sstevel@tonic-gate 				KRB5_IPROP_PROG, KRB5_IPROP_VERS,
8580Sstevel@tonic-gate 				"circuit_v")) {
8590Sstevel@tonic-gate 			fprintf(stderr,
8600Sstevel@tonic-gate     gettext("%s: Cannot create IProp RPC service (PROG=%d, VERS=%d)\n"),
8610Sstevel@tonic-gate 				whoami,
8620Sstevel@tonic-gate 				KRB5_IPROP_PROG, KRB5_IPROP_VERS);
8630Sstevel@tonic-gate 			krb5_klog_syslog(LOG_ERR,
8640Sstevel@tonic-gate     gettext("Cannot create IProp RPC service (PROG=%d, VERS=%d), failing."),
8650Sstevel@tonic-gate 					KRB5_IPROP_PROG, KRB5_IPROP_VERS);
8660Sstevel@tonic-gate 			krb5_klog_close(ctx);
8670Sstevel@tonic-gate 			exit(1);
8680Sstevel@tonic-gate 		}
8690Sstevel@tonic-gate 
8700Sstevel@tonic-gate 		if (ret = kiprop_get_adm_host_srv_name(ctx,
8710Sstevel@tonic-gate 							params.realm,
8720Sstevel@tonic-gate 							&kiprop_name)) {
8730Sstevel@tonic-gate 			krb5_klog_syslog(LOG_ERR,
8740Sstevel@tonic-gate 			gettext("%s while getting IProp svc name, failing"),
8750Sstevel@tonic-gate 					error_message(ret));
8760Sstevel@tonic-gate 			fprintf(stderr,
8770Sstevel@tonic-gate 		gettext("%s: %s while getting IProp svc name, failing\n"),
8780Sstevel@tonic-gate 				whoami, error_message(ret));
8790Sstevel@tonic-gate 			krb5_klog_close(ctx);
8800Sstevel@tonic-gate 			exit(1);
8810Sstevel@tonic-gate 		}
8820Sstevel@tonic-gate 
8830Sstevel@tonic-gate 		if (!rpc_gss_set_svc_name(kiprop_name, "kerberos_v5", 0,
8840Sstevel@tonic-gate 					KRB5_IPROP_PROG, KRB5_IPROP_VERS)) {
8850Sstevel@tonic-gate 			rpc_gss_error_t err;
8860Sstevel@tonic-gate 			(void) rpc_gss_get_error(&err);
8870Sstevel@tonic-gate 
8880Sstevel@tonic-gate 			krb5_klog_syslog(LOG_ERR,
8890Sstevel@tonic-gate     gettext("Unable to set RPCSEC_GSS service name (`%s'), failing."),
8900Sstevel@tonic-gate 					kiprop_name ? kiprop_name : "<null>");
8910Sstevel@tonic-gate 
8920Sstevel@tonic-gate 			fprintf(stderr,
8930Sstevel@tonic-gate     gettext("%s: Unable to set RPCSEC_GSS service name (`%s'), failing.\n"),
8940Sstevel@tonic-gate 				whoami,
8950Sstevel@tonic-gate 				kiprop_name ? kiprop_name : "<null>");
8960Sstevel@tonic-gate 
8970Sstevel@tonic-gate 			if (nofork) {
8980Sstevel@tonic-gate 				fprintf(stderr,
8990Sstevel@tonic-gate 			"%s: set svc name (rpcsec err=%d, sys err=%d)\n",
9000Sstevel@tonic-gate 					whoami,
9010Sstevel@tonic-gate 					err.rpc_gss_error,
9020Sstevel@tonic-gate 					err.system_error);
9030Sstevel@tonic-gate 			}
9040Sstevel@tonic-gate 
9050Sstevel@tonic-gate 			exit(1);
9060Sstevel@tonic-gate 		}
9070Sstevel@tonic-gate 		free(kiprop_name);
9080Sstevel@tonic-gate 
9090Sstevel@tonic-gate 		if (retdn == 0 && dnames) {
9100Sstevel@tonic-gate 			set_svc_domnames(KADM5_KIPROP_HOST_SERVICE,
9110Sstevel@tonic-gate 					dnames,
9120Sstevel@tonic-gate 					KRB5_IPROP_PROG, KRB5_IPROP_VERS);
9130Sstevel@tonic-gate 		}
9140Sstevel@tonic-gate 
915*1446Smp153739 	} else {
916*1446Smp153739 		if (!oldnames) {
917*1446Smp153739 		/* rpc_gss_set_svc_name failed for both kadmin/<fqdn> and
918*1446Smp153739 		 * changepw/<fqdn>.
919*1446Smp153739 		 */
920*1446Smp153739 			krb5_klog_syslog(LOG_ERR,
921*1446Smp153739 					gettext("Unable to set RPCSEC_GSS service names "
922*1446Smp153739 						"('%s, %s')"),
923*1446Smp153739 					names[0].name, names[1].name);
924*1446Smp153739 			fprintf(stderr,
925*1446Smp153739 					gettext("%s: Unable to set RPCSEC_GSS service names "
926*1446Smp153739 						"('%s, %s')\n"),
927*1446Smp153739 					whoami,
928*1446Smp153739 					names[0].name, names[1].name);
929*1446Smp153739 			krb5_klog_close(context);
930*1446Smp153739 			exit(1);
931*1446Smp153739 		}
9320Sstevel@tonic-gate 	}
9330Sstevel@tonic-gate 
9340Sstevel@tonic-gate 	if (dnames)
9350Sstevel@tonic-gate 		freedomnames(dnames);
9360Sstevel@tonic-gate 
9370Sstevel@tonic-gate 	setup_signal_handlers(log_ctx->iproprole);
9380Sstevel@tonic-gate 	krb5_klog_syslog(LOG_INFO, gettext("starting"));
9390Sstevel@tonic-gate 	if (nofork)
9400Sstevel@tonic-gate 		fprintf(stderr, "%s: starting...\n", whoami);
9410Sstevel@tonic-gate 
9420Sstevel@tonic-gate 
9430Sstevel@tonic-gate 	/*
9440Sstevel@tonic-gate 	 * We now call our own customized async event processing
9450Sstevel@tonic-gate 	 * function kadm_svc_run(), as opposed to svc_run() earlier,
9460Sstevel@tonic-gate 	 * since this enables kadmind to also listen-to/process
9470Sstevel@tonic-gate 	 * non-RPCSEC_GSS based change-pwd requests apart from the
9480Sstevel@tonic-gate 	 * regular, RPCSEC_GSS kpasswd requests from Solaris Krb5 clients.
9490Sstevel@tonic-gate 	 */
9500Sstevel@tonic-gate 	kadm_svc_run();
9510Sstevel@tonic-gate 
9520Sstevel@tonic-gate 	krb5_klog_syslog(LOG_INFO, gettext("finished, exiting"));
9530Sstevel@tonic-gate 	kadm5_destroy(global_server_handle);
9540Sstevel@tonic-gate 	t_close(fd);
9550Sstevel@tonic-gate 	krb5_klog_close(context);
9560Sstevel@tonic-gate 	exit(0);
9570Sstevel@tonic-gate }
9580Sstevel@tonic-gate 
9590Sstevel@tonic-gate 
9600Sstevel@tonic-gate /*
9610Sstevel@tonic-gate  * Function: kadm_svc_run
9620Sstevel@tonic-gate  *
9630Sstevel@tonic-gate  * Purpose: modified version of sunrpc svc_run.
9640Sstevel@tonic-gate  *	    which closes the database every TIMEOUT seconds.
9650Sstevel@tonic-gate  *
9660Sstevel@tonic-gate  * Arguments:
9670Sstevel@tonic-gate  * Requires:
9680Sstevel@tonic-gate  * Effects:
9690Sstevel@tonic-gate  * Modifies:
9700Sstevel@tonic-gate  */
9710Sstevel@tonic-gate void
9720Sstevel@tonic-gate kadm_svc_run(void)
9730Sstevel@tonic-gate {
9740Sstevel@tonic-gate 	struct pollfd	*rfd = 0;
9750Sstevel@tonic-gate 	struct	timeval	    timeout;
9760Sstevel@tonic-gate 	int pollret;
9770Sstevel@tonic-gate 	int nfds = 0;
9780Sstevel@tonic-gate 	int i;
9790Sstevel@tonic-gate 
9800Sstevel@tonic-gate 	while(signal_request_exit == 0) {
9810Sstevel@tonic-gate 		timeout.tv_sec = TIMEOUT;
9820Sstevel@tonic-gate 		timeout.tv_usec = 0;
9830Sstevel@tonic-gate 
9840Sstevel@tonic-gate 		if (nfds != svc_max_pollfd) {
9850Sstevel@tonic-gate 			rfd = realloc(rfd, sizeof (pollfd_t) * svc_max_pollfd);
9860Sstevel@tonic-gate 			nfds = svc_max_pollfd;
9870Sstevel@tonic-gate 		}
9880Sstevel@tonic-gate 
9890Sstevel@tonic-gate 		(void) memcpy(rfd, svc_pollfd,
9900Sstevel@tonic-gate 			sizeof (pollfd_t) * svc_max_pollfd);
9910Sstevel@tonic-gate 
9920Sstevel@tonic-gate 		for (i = 0; i < nfds; i++) {
9930Sstevel@tonic-gate 			if (rfd[i].fd == -1) {
9940Sstevel@tonic-gate 				rfd[i].fd = schpw;
9950Sstevel@tonic-gate 				rfd[i].events = POLLIN;
9960Sstevel@tonic-gate 				break;
9970Sstevel@tonic-gate 			}
9980Sstevel@tonic-gate 		}
9990Sstevel@tonic-gate 
10000Sstevel@tonic-gate 		switch(pollret = poll(rfd, nfds,
10010Sstevel@tonic-gate 				__rpc_timeval_to_msec(&timeout))) {
10020Sstevel@tonic-gate 		case -1:
10030Sstevel@tonic-gate 			if(errno == EINTR)
10040Sstevel@tonic-gate 				continue;
10050Sstevel@tonic-gate 			perror("poll");
10060Sstevel@tonic-gate 			return;
10070Sstevel@tonic-gate 		case 0:
10080Sstevel@tonic-gate 			continue;
10090Sstevel@tonic-gate 		default:
10100Sstevel@tonic-gate 			for (i = 0; i < nfds; i++) {
10110Sstevel@tonic-gate 				if (rfd[i].revents & POLLIN) {
10120Sstevel@tonic-gate 					if (rfd[i].fd == schpw)
10130Sstevel@tonic-gate 						handle_chpw(context, schpw,
10140Sstevel@tonic-gate 							global_server_handle,
10150Sstevel@tonic-gate 							&chgpw_params);
10160Sstevel@tonic-gate 					else
10170Sstevel@tonic-gate 						svc_getreq_poll(rfd, pollret);
10180Sstevel@tonic-gate 					break;
10190Sstevel@tonic-gate 				} else {
10200Sstevel@tonic-gate 					if (i == (nfds - 1))
10210Sstevel@tonic-gate 						perror("poll");
10220Sstevel@tonic-gate 				}
10230Sstevel@tonic-gate 			}
10240Sstevel@tonic-gate 			break;
10250Sstevel@tonic-gate 		}
10260Sstevel@tonic-gate 	}
10270Sstevel@tonic-gate }
10280Sstevel@tonic-gate 
10290Sstevel@tonic-gate 
10300Sstevel@tonic-gate /*
10310Sstevel@tonic-gate  * Function: setup_signal_handlers
10320Sstevel@tonic-gate  *
10330Sstevel@tonic-gate  * Purpose: Setup signal handling functions with System V's signal().
10340Sstevel@tonic-gate  */
10350Sstevel@tonic-gate void setup_signal_handlers(iprop_role iproprole) {
10360Sstevel@tonic-gate 	signal(SIGINT, sig_exit);
10370Sstevel@tonic-gate 	signal(SIGTERM, sig_exit);
10380Sstevel@tonic-gate 	signal(SIGQUIT, sig_exit);
10390Sstevel@tonic-gate 	signal(SIGPIPE, sig_pipe);
10400Sstevel@tonic-gate 
10410Sstevel@tonic-gate 	/*
10420Sstevel@tonic-gate 	 * IProp will fork for a full-resync, we don't want to
10430Sstevel@tonic-gate 	 * wait on it and we don't want the living dead procs either.
10440Sstevel@tonic-gate 	 */
10450Sstevel@tonic-gate 	if (iproprole == IPROP_MASTER)
10460Sstevel@tonic-gate 		(void) signal(SIGCHLD, SIG_IGN);
10470Sstevel@tonic-gate 
10480Sstevel@tonic-gate 	return;
10490Sstevel@tonic-gate }
10500Sstevel@tonic-gate 
10510Sstevel@tonic-gate 
10520Sstevel@tonic-gate /*
10530Sstevel@tonic-gate  * Function: sig_exit
10540Sstevel@tonic-gate  *
10550Sstevel@tonic-gate  * Purpose: sets flags saying the server got a signal and that it
10560Sstevel@tonic-gate  *          should exit when convenient.
10570Sstevel@tonic-gate  *
10580Sstevel@tonic-gate  * Effects:
10590Sstevel@tonic-gate  *      Modifies signal_request_exit which ideally makes the server exit
10600Sstevel@tonic-gate  *      at some point.
10610Sstevel@tonic-gate  *
10620Sstevel@tonic-gate  * Modifies:
10630Sstevel@tonic-gate  *      Signal_request_exit
10640Sstevel@tonic-gate  */
10650Sstevel@tonic-gate void sig_exit(int signum)
10660Sstevel@tonic-gate {
10670Sstevel@tonic-gate 	krb5_klog_syslog(LOG_NOTICE, gettext("Got signal to request exit"));
10680Sstevel@tonic-gate 	signal_request_exit = 1;
10690Sstevel@tonic-gate 	return;
10700Sstevel@tonic-gate }
10710Sstevel@tonic-gate 
10720Sstevel@tonic-gate 
10730Sstevel@tonic-gate /*
10740Sstevel@tonic-gate  * Function: sig_pipe
10750Sstevel@tonic-gate  *
10760Sstevel@tonic-gate  * Purpose: SIGPIPE handler
10770Sstevel@tonic-gate  *
10780Sstevel@tonic-gate  * Effects: krb5_klog_syslog a message that a SIGPIPE occurred and returns,
10790Sstevel@tonic-gate  * thus causing the read() or write() to fail and, presumable, the RPC
10800Sstevel@tonic-gate  * to recover.	Otherwise, the process aborts.
10810Sstevel@tonic-gate  */
10820Sstevel@tonic-gate void
10830Sstevel@tonic-gate sig_pipe(int unused)
10840Sstevel@tonic-gate {
10850Sstevel@tonic-gate 	krb5_klog_syslog(LOG_NOTICE, gettext("Warning: Received a SIGPIPE; "
10860Sstevel@tonic-gate 		"probably a client aborted.  Continuing."));
10870Sstevel@tonic-gate }
1088