xref: /onnv-gate/usr/src/cmd/krb5/kadmin/server/ovsec_kadmd.c (revision 0:68f95e015346)
1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
3*0Sstevel@tonic-gate  * Use is subject to license terms.
4*0Sstevel@tonic-gate  */
5*0Sstevel@tonic-gate 
6*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
7*0Sstevel@tonic-gate 
8*0Sstevel@tonic-gate /*
9*0Sstevel@tonic-gate  * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
10*0Sstevel@tonic-gate  *
11*0Sstevel@tonic-gate  *	Openvision retains the copyright to derivative works of
12*0Sstevel@tonic-gate  *	this source code.	Do *NOT* create a derivative of this
13*0Sstevel@tonic-gate  *	source code before consulting with your legal department.
14*0Sstevel@tonic-gate  *	Do *NOT* integrate *ANY* of this source code into another
15*0Sstevel@tonic-gate  *	product before consulting with your legal department.
16*0Sstevel@tonic-gate  *
17*0Sstevel@tonic-gate  *	For further information, read the top-level Openvision
18*0Sstevel@tonic-gate  *	copyright which is contained in the top-level MIT Kerberos
19*0Sstevel@tonic-gate  *	copyright.
20*0Sstevel@tonic-gate  *
21*0Sstevel@tonic-gate  * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
22*0Sstevel@tonic-gate  *
23*0Sstevel@tonic-gate  */
24*0Sstevel@tonic-gate 
25*0Sstevel@tonic-gate 
26*0Sstevel@tonic-gate /*
27*0Sstevel@tonic-gate  * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved
28*0Sstevel@tonic-gate  */
29*0Sstevel@tonic-gate 
30*0Sstevel@tonic-gate /*
31*0Sstevel@tonic-gate  * SUNWresync121 XXX
32*0Sstevel@tonic-gate  * Beware future resyncers, this file is much diff from MIT (1.0...)
33*0Sstevel@tonic-gate  */
34*0Sstevel@tonic-gate 
35*0Sstevel@tonic-gate #include <stdio.h>
36*0Sstevel@tonic-gate #include <signal.h>
37*0Sstevel@tonic-gate #include <syslog.h>
38*0Sstevel@tonic-gate #include <sys/types.h>
39*0Sstevel@tonic-gate #include <sys/time.h>
40*0Sstevel@tonic-gate #include <sys/socket.h>
41*0Sstevel@tonic-gate #include <unistd.h>
42*0Sstevel@tonic-gate #include <netinet/in.h>
43*0Sstevel@tonic-gate #include <arpa/inet.h>	/* inet_ntoa */
44*0Sstevel@tonic-gate #include <netdb.h>
45*0Sstevel@tonic-gate #include <gssapi/gssapi.h>
46*0Sstevel@tonic-gate #include <rpc/rpc.h>
47*0Sstevel@tonic-gate #include <kadm5/admin.h>
48*0Sstevel@tonic-gate #include <kadm5/kadm_rpc.h>
49*0Sstevel@tonic-gate #include <kadm5/server_internal.h>
50*0Sstevel@tonic-gate #include <server_acl.h>
51*0Sstevel@tonic-gate #include <krb5/adm_proto.h>
52*0Sstevel@tonic-gate #include <string.h>
53*0Sstevel@tonic-gate #include <gssapi_krb5.h>
54*0Sstevel@tonic-gate #include <libintl.h>
55*0Sstevel@tonic-gate #include <locale.h>
56*0Sstevel@tonic-gate #include <sys/resource.h>
57*0Sstevel@tonic-gate #include <kdb/kdb_log.h>
58*0Sstevel@tonic-gate 
59*0Sstevel@tonic-gate #include <rpc/rpcsec_gss.h>
60*0Sstevel@tonic-gate 
61*0Sstevel@tonic-gate #ifndef	FD_SETSIZE
62*0Sstevel@tonic-gate #define	FD_SETSIZE	256
63*0Sstevel@tonic-gate #endif
64*0Sstevel@tonic-gate 
65*0Sstevel@tonic-gate #ifndef MAX
66*0Sstevel@tonic-gate #define	MAX(a, b)	(((a) > (b)) ? (a) : (b))
67*0Sstevel@tonic-gate #endif
68*0Sstevel@tonic-gate 
69*0Sstevel@tonic-gate static int signal_request_exit = 0;
70*0Sstevel@tonic-gate static int schpw;
71*0Sstevel@tonic-gate kadm5_config_params chgpw_params;
72*0Sstevel@tonic-gate void kadm_svc_run(void);
73*0Sstevel@tonic-gate void setup_signal_handlers(iprop_role iproprole);
74*0Sstevel@tonic-gate void sig_exit(int);
75*0Sstevel@tonic-gate void sig_pipe(int);
76*0Sstevel@tonic-gate 
77*0Sstevel@tonic-gate #ifdef POSIX_SIGNALS
78*0Sstevel@tonic-gate static struct sigaction s_action;
79*0Sstevel@tonic-gate #endif /* POSIX_SIGNALS */
80*0Sstevel@tonic-gate 
81*0Sstevel@tonic-gate #define	TIMEOUT	15
82*0Sstevel@tonic-gate 
83*0Sstevel@tonic-gate typedef struct _auth_gssapi_name {
84*0Sstevel@tonic-gate 	char *name;
85*0Sstevel@tonic-gate 	gss_OID type;
86*0Sstevel@tonic-gate } auth_gssapi_name;
87*0Sstevel@tonic-gate 
88*0Sstevel@tonic-gate gss_name_t gss_changepw_name = NULL, gss_oldchangepw_name = NULL;
89*0Sstevel@tonic-gate void *global_server_handle;
90*0Sstevel@tonic-gate 
91*0Sstevel@tonic-gate /*
92*0Sstevel@tonic-gate  * This is a kludge, but the server needs these constants to be
93*0Sstevel@tonic-gate  * compatible with old clients.	They are defined in <kadm5/admin.h>,
94*0Sstevel@tonic-gate  * but only if USE_KADM5_API_VERSION == 1.
95*0Sstevel@tonic-gate  */
96*0Sstevel@tonic-gate #define	OVSEC_KADM_ADMIN_SERVICE_P	"ovsec_adm@admin"
97*0Sstevel@tonic-gate #define	OVSEC_KADM_CHANGEPW_SERVICE_P	"ovsec_adm@changepw"
98*0Sstevel@tonic-gate 
99*0Sstevel@tonic-gate /*
100*0Sstevel@tonic-gate  * This enables us to set the keytab that gss_acquire_cred uses, but
101*0Sstevel@tonic-gate  * it also restricts us to linking against the Kv5 GSS-API library.
102*0Sstevel@tonic-gate  * Since this is *k*admind, that shouldn't be a problem.
103*0Sstevel@tonic-gate  */
104*0Sstevel@tonic-gate extern char *krb5_overridekeyname;
105*0Sstevel@tonic-gate 
106*0Sstevel@tonic-gate extern void krb5_iprop_prog_1();
107*0Sstevel@tonic-gate extern kadm5_ret_t kiprop_get_adm_host_srv_name(
108*0Sstevel@tonic-gate 	krb5_context,
109*0Sstevel@tonic-gate 	const char *,
110*0Sstevel@tonic-gate 	char **);
111*0Sstevel@tonic-gate 
112*0Sstevel@tonic-gate static krb5_context context;  /* XXX yuck.  the signal handlers need this */
113*0Sstevel@tonic-gate 
114*0Sstevel@tonic-gate in_port_t l_port = 0;	/* global local port num, for BSM audits */
115*0Sstevel@tonic-gate 
116*0Sstevel@tonic-gate int nofork = 0; /* global; don't fork (debug mode) */
117*0Sstevel@tonic-gate 
118*0Sstevel@tonic-gate 
119*0Sstevel@tonic-gate /*
120*0Sstevel@tonic-gate  * Function: usage
121*0Sstevel@tonic-gate  *
122*0Sstevel@tonic-gate  * Purpose: print out the server usage message
123*0Sstevel@tonic-gate  *
124*0Sstevel@tonic-gate  * Arguments:
125*0Sstevel@tonic-gate  * Requires:
126*0Sstevel@tonic-gate  * Effects:
127*0Sstevel@tonic-gate  * Modifies:
128*0Sstevel@tonic-gate  */
129*0Sstevel@tonic-gate 
130*0Sstevel@tonic-gate void
131*0Sstevel@tonic-gate usage()
132*0Sstevel@tonic-gate {
133*0Sstevel@tonic-gate 	fprintf(stderr, gettext("Usage: kadmind [-r realm] [-m] [-d] "
134*0Sstevel@tonic-gate 	    "[-p port-number]\n"));
135*0Sstevel@tonic-gate 	exit(1);
136*0Sstevel@tonic-gate }
137*0Sstevel@tonic-gate 
138*0Sstevel@tonic-gate /*
139*0Sstevel@tonic-gate  * Function: display_status
140*0Sstevel@tonic-gate  *
141*0Sstevel@tonic-gate  * Purpose: displays GSS-API messages
142*0Sstevel@tonic-gate  *
143*0Sstevel@tonic-gate  * Arguments:
144*0Sstevel@tonic-gate  *
145*0Sstevel@tonic-gate  * 	msg		a string to be displayed with the message
146*0Sstevel@tonic-gate  * 	maj_stat	the GSS-API major status code
147*0Sstevel@tonic-gate  * 	min_stat	the GSS-API minor status code
148*0Sstevel@tonic-gate  *
149*0Sstevel@tonic-gate  * Effects:
150*0Sstevel@tonic-gate  *
151*0Sstevel@tonic-gate  * The GSS-API messages associated with maj_stat and min_stat are
152*0Sstevel@tonic-gate  * displayed on stderr, each preceeded by "GSS-API error <msg>: " and
153*0Sstevel@tonic-gate  * followed by a newline.
154*0Sstevel@tonic-gate  */
155*0Sstevel@tonic-gate static void display_status_1();
156*0Sstevel@tonic-gate 
157*0Sstevel@tonic-gate void display_status(msg, maj_stat, min_stat)
158*0Sstevel@tonic-gate      char *msg;
159*0Sstevel@tonic-gate      OM_uint32 maj_stat;
160*0Sstevel@tonic-gate      OM_uint32 min_stat;
161*0Sstevel@tonic-gate {
162*0Sstevel@tonic-gate      display_status_1(msg, maj_stat, GSS_C_GSS_CODE);
163*0Sstevel@tonic-gate      display_status_1(msg, min_stat, GSS_C_MECH_CODE);
164*0Sstevel@tonic-gate }
165*0Sstevel@tonic-gate 
166*0Sstevel@tonic-gate static void display_status_1(m, code, type)
167*0Sstevel@tonic-gate      char *m;
168*0Sstevel@tonic-gate      OM_uint32 code;
169*0Sstevel@tonic-gate      int type;
170*0Sstevel@tonic-gate {
171*0Sstevel@tonic-gate 	OM_uint32 maj_stat, min_stat;
172*0Sstevel@tonic-gate 	gss_buffer_desc msg;
173*0Sstevel@tonic-gate 	OM_uint32 msg_ctx;
174*0Sstevel@tonic-gate 
175*0Sstevel@tonic-gate 	msg_ctx = 0;
176*0Sstevel@tonic-gate 	while (1) {
177*0Sstevel@tonic-gate 		maj_stat = gss_display_status(&min_stat, code,
178*0Sstevel@tonic-gate 					      type, GSS_C_NULL_OID,
179*0Sstevel@tonic-gate 					      &msg_ctx, &msg);
180*0Sstevel@tonic-gate 		fprintf(stderr, "GSS-API error %s: %s\n", m,
181*0Sstevel@tonic-gate 			(char *)msg.value);
182*0Sstevel@tonic-gate 		(void) gss_release_buffer(&min_stat, &msg);
183*0Sstevel@tonic-gate 
184*0Sstevel@tonic-gate 		if (!msg_ctx)
185*0Sstevel@tonic-gate 			break;
186*0Sstevel@tonic-gate 	}
187*0Sstevel@tonic-gate }
188*0Sstevel@tonic-gate 
189*0Sstevel@tonic-gate 
190*0Sstevel@tonic-gate /*
191*0Sstevel@tonic-gate  * Solaris Kerberos: the following prototypes are needed because these are
192*0Sstevel@tonic-gate  * private interfaces that do not have prototypes in any .h
193*0Sstevel@tonic-gate  */
194*0Sstevel@tonic-gate 
195*0Sstevel@tonic-gate extern struct hostent   *res_getipnodebyaddr(const void *, size_t, int, int *);
196*0Sstevel@tonic-gate extern void             res_freehostent(struct hostent *);
197*0Sstevel@tonic-gate 
198*0Sstevel@tonic-gate static void
199*0Sstevel@tonic-gate freedomnames(char **npp)
200*0Sstevel@tonic-gate {
201*0Sstevel@tonic-gate 	char **tpp;
202*0Sstevel@tonic-gate 
203*0Sstevel@tonic-gate 	if (npp) {
204*0Sstevel@tonic-gate 		tpp = npp;
205*0Sstevel@tonic-gate 		while (*tpp++) {
206*0Sstevel@tonic-gate 			free(*(tpp-1));
207*0Sstevel@tonic-gate 		}
208*0Sstevel@tonic-gate 		free(npp);
209*0Sstevel@tonic-gate 	}
210*0Sstevel@tonic-gate }
211*0Sstevel@tonic-gate 
212*0Sstevel@tonic-gate /*
213*0Sstevel@tonic-gate  * Construct a list of uniq FQDNs of all the net interfaces (except
214*0Sstevel@tonic-gate  * krb5.conf master dups) and return it in arg 'dnames'.
215*0Sstevel@tonic-gate  *
216*0Sstevel@tonic-gate  * On successful return (0), caller must call freedomnames()
217*0Sstevel@tonic-gate  * to free memory.
218*0Sstevel@tonic-gate  */
219*0Sstevel@tonic-gate static int
220*0Sstevel@tonic-gate getdomnames(krb5_context ctx, char *realm, char ***dnames)
221*0Sstevel@tonic-gate {
222*0Sstevel@tonic-gate 	krb5_address **addresses = NULL;
223*0Sstevel@tonic-gate 	krb5_address *a = NULL;
224*0Sstevel@tonic-gate 	struct hostent *hp = NULL;
225*0Sstevel@tonic-gate 	int ret, i, result=0, error;
226*0Sstevel@tonic-gate 	char **npp = NULL, **tpp=NULL;
227*0Sstevel@tonic-gate 	int dup=0, n = 0;
228*0Sstevel@tonic-gate 	char *cfhost = NULL; /* krb5 conf file master hostname */
229*0Sstevel@tonic-gate 
230*0Sstevel@tonic-gate 	if (ret = kadm5_get_master(ctx, realm, &cfhost)) {
231*0Sstevel@tonic-gate 		return (ret);
232*0Sstevel@tonic-gate 	}
233*0Sstevel@tonic-gate 
234*0Sstevel@tonic-gate 	ret = krb5_os_localaddr(ctx, &addresses);
235*0Sstevel@tonic-gate 	if (ret != 0) {
236*0Sstevel@tonic-gate 		if (nofork)
237*0Sstevel@tonic-gate 			(void) fprintf(stderr,
238*0Sstevel@tonic-gate 				    "kadmind: get localaddrs failed: %s",
239*0Sstevel@tonic-gate 				    error_message(ret));
240*0Sstevel@tonic-gate 		result = ret;
241*0Sstevel@tonic-gate 		goto err;
242*0Sstevel@tonic-gate 	}
243*0Sstevel@tonic-gate 
244*0Sstevel@tonic-gate 
245*0Sstevel@tonic-gate 	for (i=0; addresses[i]; i++) {
246*0Sstevel@tonic-gate 		a = addresses[i];
247*0Sstevel@tonic-gate 		hp = res_getipnodebyaddr(a->contents, a->length,
248*0Sstevel@tonic-gate 					a->addrtype == ADDRTYPE_INET
249*0Sstevel@tonic-gate 					? AF_INET : AF_INET6,
250*0Sstevel@tonic-gate 					&error);
251*0Sstevel@tonic-gate 		if (hp != NULL) {
252*0Sstevel@tonic-gate 
253*0Sstevel@tonic-gate 			/* skip master host in krb5.conf */
254*0Sstevel@tonic-gate 			if (strcasecmp(cfhost, hp->h_name) == 0) {
255*0Sstevel@tonic-gate 				res_freehostent(hp);
256*0Sstevel@tonic-gate 				hp = NULL;
257*0Sstevel@tonic-gate 				continue;
258*0Sstevel@tonic-gate 			}
259*0Sstevel@tonic-gate 
260*0Sstevel@tonic-gate 			dup = 0;
261*0Sstevel@tonic-gate 			tpp = npp;
262*0Sstevel@tonic-gate 			/* skip if hostname already exists in list */
263*0Sstevel@tonic-gate 			while (tpp && *tpp++) {
264*0Sstevel@tonic-gate 				if (strcasecmp(*(tpp-1), hp->h_name) == 0) {
265*0Sstevel@tonic-gate 					dup++;
266*0Sstevel@tonic-gate 					break;
267*0Sstevel@tonic-gate 				}
268*0Sstevel@tonic-gate 			}
269*0Sstevel@tonic-gate 
270*0Sstevel@tonic-gate 			if (dup) {
271*0Sstevel@tonic-gate 				res_freehostent(hp);
272*0Sstevel@tonic-gate 				hp = NULL;
273*0Sstevel@tonic-gate 				continue;
274*0Sstevel@tonic-gate 			}
275*0Sstevel@tonic-gate 
276*0Sstevel@tonic-gate 			npp = realloc(npp, sizeof(char *) * (n + 2));
277*0Sstevel@tonic-gate 			if (!npp) {
278*0Sstevel@tonic-gate 				result = ENOMEM;
279*0Sstevel@tonic-gate 				goto err;
280*0Sstevel@tonic-gate 			}
281*0Sstevel@tonic-gate 			npp[n] = strdup(hp->h_name);
282*0Sstevel@tonic-gate 			if (!npp[n]) {
283*0Sstevel@tonic-gate 				result = ENOMEM;
284*0Sstevel@tonic-gate 				goto err;
285*0Sstevel@tonic-gate 			}
286*0Sstevel@tonic-gate 			npp[n+1] = NULL;
287*0Sstevel@tonic-gate 			n++;
288*0Sstevel@tonic-gate 
289*0Sstevel@tonic-gate 			res_freehostent(hp);
290*0Sstevel@tonic-gate 			hp = NULL;
291*0Sstevel@tonic-gate 			result = 0;
292*0Sstevel@tonic-gate 		}
293*0Sstevel@tonic-gate 
294*0Sstevel@tonic-gate 	}
295*0Sstevel@tonic-gate 
296*0Sstevel@tonic-gate #ifdef DEBUG
297*0Sstevel@tonic-gate 	printf("getdomnames: n=%d, i=%d, npp=%p\n", n, i, npp);
298*0Sstevel@tonic-gate 	tpp = npp;
299*0Sstevel@tonic-gate 	while (tpp && *tpp++) {
300*0Sstevel@tonic-gate 		printf("tpp=%s\n", *(tpp-1));
301*0Sstevel@tonic-gate 	}
302*0Sstevel@tonic-gate #endif
303*0Sstevel@tonic-gate 
304*0Sstevel@tonic-gate 	goto out;
305*0Sstevel@tonic-gate 
306*0Sstevel@tonic-gate err:
307*0Sstevel@tonic-gate 	if (npp) {
308*0Sstevel@tonic-gate 		freedomnames(npp);
309*0Sstevel@tonic-gate 		npp = NULL;
310*0Sstevel@tonic-gate 	}
311*0Sstevel@tonic-gate 
312*0Sstevel@tonic-gate 	if (hp) {
313*0Sstevel@tonic-gate 		res_freehostent(hp);
314*0Sstevel@tonic-gate 		hp = NULL;
315*0Sstevel@tonic-gate 	}
316*0Sstevel@tonic-gate 
317*0Sstevel@tonic-gate out:
318*0Sstevel@tonic-gate 	if (cfhost) {
319*0Sstevel@tonic-gate 		free (cfhost);
320*0Sstevel@tonic-gate 		cfhost = NULL;
321*0Sstevel@tonic-gate 	}
322*0Sstevel@tonic-gate 	if (addresses) {
323*0Sstevel@tonic-gate 		krb5_free_addresses(ctx, addresses);
324*0Sstevel@tonic-gate 		addresses = NULL;
325*0Sstevel@tonic-gate 	}
326*0Sstevel@tonic-gate 
327*0Sstevel@tonic-gate 	if (result == 0)
328*0Sstevel@tonic-gate 		*dnames = npp;
329*0Sstevel@tonic-gate 
330*0Sstevel@tonic-gate 	return (result);
331*0Sstevel@tonic-gate }
332*0Sstevel@tonic-gate 
333*0Sstevel@tonic-gate /*
334*0Sstevel@tonic-gate  * Set the rpcsec_gss svc names for all net interfaces.
335*0Sstevel@tonic-gate  */
336*0Sstevel@tonic-gate static void
337*0Sstevel@tonic-gate set_svc_domnames(char *svcname, char **dnames,
338*0Sstevel@tonic-gate 		u_int program, u_int version)
339*0Sstevel@tonic-gate {
340*0Sstevel@tonic-gate 	bool_t ret;
341*0Sstevel@tonic-gate 	char **tpp = dnames;
342*0Sstevel@tonic-gate 
343*0Sstevel@tonic-gate 	if (!tpp)
344*0Sstevel@tonic-gate 		return;
345*0Sstevel@tonic-gate 
346*0Sstevel@tonic-gate 	while (*tpp++) {
347*0Sstevel@tonic-gate 		/* MAX_NAME_LEN from rpc/rpcsec_gss.h */
348*0Sstevel@tonic-gate 		char name[MAXHOSTNAMELEN+MAX_NAME_LEN+2] = {0};
349*0Sstevel@tonic-gate 		(void) snprintf(name, sizeof(name), "%s@%s",
350*0Sstevel@tonic-gate 				svcname, *(tpp-1));
351*0Sstevel@tonic-gate 		ret = rpc_gss_set_svc_name(name,
352*0Sstevel@tonic-gate 					"kerberos_v5", 0,
353*0Sstevel@tonic-gate 					program, version);
354*0Sstevel@tonic-gate 		if (nofork && ret)
355*0Sstevel@tonic-gate 			(void) fprintf(stderr,
356*0Sstevel@tonic-gate 				    "rpc_gss_set_svc_name success: %s\n",
357*0Sstevel@tonic-gate 				    name);
358*0Sstevel@tonic-gate 	}
359*0Sstevel@tonic-gate }
360*0Sstevel@tonic-gate 
361*0Sstevel@tonic-gate 
362*0Sstevel@tonic-gate 
363*0Sstevel@tonic-gate 
364*0Sstevel@tonic-gate int
365*0Sstevel@tonic-gate main(int argc, char *argv[])
366*0Sstevel@tonic-gate {
367*0Sstevel@tonic-gate 	void kadm_1(struct svc_req *, SVCXPRT *);
368*0Sstevel@tonic-gate 	SVCXPRT *transp;
369*0Sstevel@tonic-gate 	extern char *optarg;
370*0Sstevel@tonic-gate 	extern int optind, opterr;
371*0Sstevel@tonic-gate 	int ret, rlen, oldnames = 0;
372*0Sstevel@tonic-gate 	OM_uint32 OMret, major_status, minor_status;
373*0Sstevel@tonic-gate 	char *whoami;
374*0Sstevel@tonic-gate 	FILE *acl_file;
375*0Sstevel@tonic-gate 	gss_buffer_desc in_buf;
376*0Sstevel@tonic-gate 	struct servent *srv;
377*0Sstevel@tonic-gate 	struct sockaddr_in addr;
378*0Sstevel@tonic-gate 	struct sockaddr_in *sin;
379*0Sstevel@tonic-gate 	int s;
380*0Sstevel@tonic-gate 	int optchar;
381*0Sstevel@tonic-gate 	struct netconfig *nconf;
382*0Sstevel@tonic-gate 	void *handlep;
383*0Sstevel@tonic-gate 	int fd;
384*0Sstevel@tonic-gate 	struct t_info tinfo;
385*0Sstevel@tonic-gate 	struct t_bind tbindstr, *tres;
386*0Sstevel@tonic-gate 
387*0Sstevel@tonic-gate 	struct t_optmgmt req, resp;
388*0Sstevel@tonic-gate 	struct opthdr *opt;
389*0Sstevel@tonic-gate 	char reqbuf[128];
390*0Sstevel@tonic-gate 	struct rlimit rl;
391*0Sstevel@tonic-gate 
392*0Sstevel@tonic-gate 	char *kiprop_name = NULL; /* IProp svc name */
393*0Sstevel@tonic-gate 	kdb_log_context *log_ctx;
394*0Sstevel@tonic-gate 	kadm5_server_handle_t handle;
395*0Sstevel@tonic-gate 	krb5_context ctx;
396*0Sstevel@tonic-gate 
397*0Sstevel@tonic-gate 	kadm5_config_params params;
398*0Sstevel@tonic-gate 	auth_gssapi_name names[6];
399*0Sstevel@tonic-gate      	gss_buffer_desc gssbuf;
400*0Sstevel@tonic-gate      	gss_OID nt_krb5_name_oid;
401*0Sstevel@tonic-gate 
402*0Sstevel@tonic-gate 	char **dnames = NULL;
403*0Sstevel@tonic-gate 	int retdn;
404*0Sstevel@tonic-gate 
405*0Sstevel@tonic-gate 	/* This is OID value the Krb5_Name NameType */
406*0Sstevel@tonic-gate      	gssbuf.value = "{1 2 840 113554 1 2 2 1}";
407*0Sstevel@tonic-gate      	gssbuf.length = strlen(gssbuf.value);
408*0Sstevel@tonic-gate      	major_status = gss_str_to_oid(&minor_status, &gssbuf,
409*0Sstevel@tonic-gate 				    &nt_krb5_name_oid);
410*0Sstevel@tonic-gate      	if (major_status != GSS_S_COMPLETE) {
411*0Sstevel@tonic-gate 		fprintf(stderr,
412*0Sstevel@tonic-gate 			gettext("Couldn't create KRB5 Name NameType OID\n"));
413*0Sstevel@tonic-gate 		display_status("str_to_oid", major_status, minor_status);
414*0Sstevel@tonic-gate 		exit(1);
415*0Sstevel@tonic-gate      	}
416*0Sstevel@tonic-gate 
417*0Sstevel@tonic-gate 	names[0].name = names[1].name = names[2].name =
418*0Sstevel@tonic-gate 		names[3].name = names[4].name  = names[5].name =NULL;
419*0Sstevel@tonic-gate 	names[0].type = names[1].type = names[2].type =
420*0Sstevel@tonic-gate 		names[3].type = names[4].type = names[5].type =
421*0Sstevel@tonic-gate 		(gss_OID) nt_krb5_name_oid;
422*0Sstevel@tonic-gate 
423*0Sstevel@tonic-gate 	whoami = (strrchr(argv[0], '/') ? strrchr(argv[0], '/') + 1 : argv[0]);
424*0Sstevel@tonic-gate 
425*0Sstevel@tonic-gate 	(void) setlocale(LC_ALL, "");
426*0Sstevel@tonic-gate 
427*0Sstevel@tonic-gate #if !defined(TEXT_DOMAIN)  /* Should be defined by cc -D */
428*0Sstevel@tonic-gate #define	TEXT_DOMAIN	"SYS_TEST"	/* Use this only if it weren't */
429*0Sstevel@tonic-gate #endif
430*0Sstevel@tonic-gate 
431*0Sstevel@tonic-gate 	(void) textdomain(TEXT_DOMAIN);
432*0Sstevel@tonic-gate 
433*0Sstevel@tonic-gate 	nofork = 0;
434*0Sstevel@tonic-gate 
435*0Sstevel@tonic-gate 	memset((char *) &params, 0, sizeof (params));
436*0Sstevel@tonic-gate 
437*0Sstevel@tonic-gate 	while ((optchar = getopt(argc, argv, "r:mdp:")) != EOF) {
438*0Sstevel@tonic-gate 		switch (optchar) {
439*0Sstevel@tonic-gate 		case 'r':
440*0Sstevel@tonic-gate 			if (!optarg)
441*0Sstevel@tonic-gate 				usage();
442*0Sstevel@tonic-gate 			params.realm = optarg;
443*0Sstevel@tonic-gate 			params.mask |= KADM5_CONFIG_REALM;
444*0Sstevel@tonic-gate 			break;
445*0Sstevel@tonic-gate 		case 'm':
446*0Sstevel@tonic-gate 			params.mkey_from_kbd = 1;
447*0Sstevel@tonic-gate 			params.mask |= KADM5_CONFIG_MKEY_FROM_KBD;
448*0Sstevel@tonic-gate 			break;
449*0Sstevel@tonic-gate 		case 'd':
450*0Sstevel@tonic-gate 			nofork = 1;
451*0Sstevel@tonic-gate 			break;
452*0Sstevel@tonic-gate 		case 'p':
453*0Sstevel@tonic-gate 			if (!optarg)
454*0Sstevel@tonic-gate 				usage();
455*0Sstevel@tonic-gate 			params.kadmind_port = atoi(optarg);
456*0Sstevel@tonic-gate 			params.mask |= KADM5_CONFIG_KADMIND_PORT;
457*0Sstevel@tonic-gate 			break;
458*0Sstevel@tonic-gate 		case '?':
459*0Sstevel@tonic-gate 		default:
460*0Sstevel@tonic-gate 			usage();
461*0Sstevel@tonic-gate 		}
462*0Sstevel@tonic-gate 	}
463*0Sstevel@tonic-gate 
464*0Sstevel@tonic-gate 
465*0Sstevel@tonic-gate 	if (getrlimit(RLIMIT_NOFILE, &rl) == 0) {
466*0Sstevel@tonic-gate 		rl.rlim_cur = rl.rlim_max = MAX(rl.rlim_max, FD_SETSIZE);
467*0Sstevel@tonic-gate 		setrlimit(RLIMIT_NOFILE, &rl);
468*0Sstevel@tonic-gate 	}
469*0Sstevel@tonic-gate 
470*0Sstevel@tonic-gate 	if (!nofork && (ret = daemon(0, 0))) {
471*0Sstevel@tonic-gate 		ret = errno;
472*0Sstevel@tonic-gate 		krb5_klog_syslog(LOG_ERR,
473*0Sstevel@tonic-gate 		    gettext("Cannot detach from tty: %s"),
474*0Sstevel@tonic-gate 		    error_message(ret));
475*0Sstevel@tonic-gate 		fprintf(stderr, gettext("%s: Cannot detach from tty: %s\n"),
476*0Sstevel@tonic-gate 		    whoami, error_message(ret));
477*0Sstevel@tonic-gate 		krb5_klog_close(context);
478*0Sstevel@tonic-gate 		exit(1);
479*0Sstevel@tonic-gate 	}
480*0Sstevel@tonic-gate 
481*0Sstevel@tonic-gate 	if (ret = krb5_init_context(&context)) {
482*0Sstevel@tonic-gate 		fprintf(stderr,
483*0Sstevel@tonic-gate 		    gettext("%s: %s while initializing context, aborting\n"),
484*0Sstevel@tonic-gate 		    whoami, error_message(ret));
485*0Sstevel@tonic-gate 		exit(1);
486*0Sstevel@tonic-gate 	}
487*0Sstevel@tonic-gate 
488*0Sstevel@tonic-gate 	krb5_klog_init(context, "admin_server", whoami, 1);
489*0Sstevel@tonic-gate 
490*0Sstevel@tonic-gate 
491*0Sstevel@tonic-gate 	/*
492*0Sstevel@tonic-gate 	 * When using the Horowitz/IETF protocol for
493*0Sstevel@tonic-gate 	 * password changing, the default port is 464
494*0Sstevel@tonic-gate 	 * (officially recognized by IANA)
495*0Sstevel@tonic-gate 	 *
496*0Sstevel@tonic-gate 	 * DEFAULT_KPASSWD_PORT -> 464
497*0Sstevel@tonic-gate 	 */
498*0Sstevel@tonic-gate 	chgpw_params.kpasswd_port = DEFAULT_KPASSWD_PORT;
499*0Sstevel@tonic-gate 	chgpw_params.mask |= KADM5_CONFIG_KPASSWD_PORT;
500*0Sstevel@tonic-gate 	chgpw_params.kpasswd_protocol = KRB5_CHGPWD_CHANGEPW_V2;
501*0Sstevel@tonic-gate 	chgpw_params.mask |= KADM5_CONFIG_KPASSWD_PROTOCOL;
502*0Sstevel@tonic-gate 
503*0Sstevel@tonic-gate 	if (ret = kadm5_get_config_params(context, NULL, NULL, &chgpw_params,
504*0Sstevel@tonic-gate 		&chgpw_params)) {
505*0Sstevel@tonic-gate 		krb5_klog_syslog(LOG_ERR, gettext("%s: %s while initializing,"
506*0Sstevel@tonic-gate 				" aborting"), whoami, error_message(ret));
507*0Sstevel@tonic-gate 		fprintf(stderr,
508*0Sstevel@tonic-gate 		    gettext("%s: %s while initializing, aborting\n"),
509*0Sstevel@tonic-gate 		    whoami, error_message(ret));
510*0Sstevel@tonic-gate 		krb5_klog_close(context);
511*0Sstevel@tonic-gate 		exit(1);
512*0Sstevel@tonic-gate 	}
513*0Sstevel@tonic-gate 
514*0Sstevel@tonic-gate 	/*
515*0Sstevel@tonic-gate 	 * We now setup the socket and bind() to port 464, so that
516*0Sstevel@tonic-gate 	 * kadmind can now listen to and process change-pwd requests
517*0Sstevel@tonic-gate 	 * from non-Solaris Kerberos V5 clients such as Microsoft,
518*0Sstevel@tonic-gate 	 * MIT, AIX, HP etc
519*0Sstevel@tonic-gate 	 */
520*0Sstevel@tonic-gate 	if ((schpw = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
521*0Sstevel@tonic-gate 		krb5_klog_syslog(LOG_ERR, gettext( "cannot create simple "
522*0Sstevel@tonic-gate 				"chpw socket: %s"), error_message(errno));
523*0Sstevel@tonic-gate 		fprintf(stderr, gettext("Cannot create simple chpw "
524*0Sstevel@tonic-gate 					"socket: %s"), error_message(errno));
525*0Sstevel@tonic-gate 		krb5_klog_close(context);
526*0Sstevel@tonic-gate 		exit(1);
527*0Sstevel@tonic-gate 	}
528*0Sstevel@tonic-gate 
529*0Sstevel@tonic-gate 	memset(&addr, 0, sizeof(addr));
530*0Sstevel@tonic-gate 	addr.sin_family = AF_INET;
531*0Sstevel@tonic-gate 	addr.sin_addr.s_addr = INADDR_ANY;
532*0Sstevel@tonic-gate 	addr.sin_port = htons(chgpw_params.kpasswd_port);
533*0Sstevel@tonic-gate 
534*0Sstevel@tonic-gate 	if (bind(schpw, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
535*0Sstevel@tonic-gate 		char portbuf[32];
536*0Sstevel@tonic-gate 		int oerrno = errno;
537*0Sstevel@tonic-gate 		fprintf(stderr, gettext("%s: Cannot bind socket.\n"), whoami);
538*0Sstevel@tonic-gate 		fprintf(stderr, gettext("bind: %s\n"), error_message(oerrno));
539*0Sstevel@tonic-gate 		errno = oerrno;
540*0Sstevel@tonic-gate 		(void) snprintf(portbuf, sizeof (portbuf), "%d",
541*0Sstevel@tonic-gate 				ntohs(addr.sin_port));
542*0Sstevel@tonic-gate 		krb5_klog_syslog(LOG_ERR, gettext("cannot bind simple "
543*0Sstevel@tonic-gate 				"chpw socket: %s"), error_message(oerrno));
544*0Sstevel@tonic-gate 		if(oerrno == EADDRINUSE) {
545*0Sstevel@tonic-gate 			char *w = strrchr(whoami, '/');
546*0Sstevel@tonic-gate 			if (w) {
547*0Sstevel@tonic-gate 				w++;
548*0Sstevel@tonic-gate 			}
549*0Sstevel@tonic-gate 			else {
550*0Sstevel@tonic-gate 				w = whoami;
551*0Sstevel@tonic-gate 			}
552*0Sstevel@tonic-gate 			fprintf(stderr, gettext(
553*0Sstevel@tonic-gate 				"This probably means that another %s process\n"
554*0Sstevel@tonic-gate 				"is already running, or that another program\n"
555*0Sstevel@tonic-gate 				"is using the server port (number %d).\n"
556*0Sstevel@tonic-gate 				"If another %s is already running, you should\n"
557*0Sstevel@tonic-gate 				"kill it before restarting the server.\n"),
558*0Sstevel@tonic-gate 				w, ntohs(addr.sin_port), w);
559*0Sstevel@tonic-gate 		}
560*0Sstevel@tonic-gate 		krb5_klog_close(context);
561*0Sstevel@tonic-gate 		exit(1);
562*0Sstevel@tonic-gate 	}
563*0Sstevel@tonic-gate 
564*0Sstevel@tonic-gate 	if (ret = kadm5_get_config_params(context, NULL, NULL, &params,
565*0Sstevel@tonic-gate 		&params)) {
566*0Sstevel@tonic-gate 		krb5_klog_syslog(LOG_ERR, gettext("%s: %s while initializing,"
567*0Sstevel@tonic-gate 				" aborting"), whoami, error_message(ret));
568*0Sstevel@tonic-gate 		fprintf(stderr,
569*0Sstevel@tonic-gate 		    gettext("%s: %s while initializing, aborting\n"),
570*0Sstevel@tonic-gate 		    whoami, error_message(ret));
571*0Sstevel@tonic-gate 		krb5_klog_close(context);
572*0Sstevel@tonic-gate 		exit(1);
573*0Sstevel@tonic-gate 	}
574*0Sstevel@tonic-gate #define	REQUIRED_PARAMS (KADM5_CONFIG_REALM | KADM5_CONFIG_ACL_FILE | \
575*0Sstevel@tonic-gate 			KADM5_CONFIG_ADMIN_KEYTAB)
576*0Sstevel@tonic-gate 
577*0Sstevel@tonic-gate 	if ((params.mask & REQUIRED_PARAMS) != REQUIRED_PARAMS) {
578*0Sstevel@tonic-gate 		krb5_klog_syslog(LOG_ERR,
579*0Sstevel@tonic-gate 		    gettext("%s: Missing required configuration values "
580*0Sstevel@tonic-gate 			"while initializing, aborting"), whoami,
581*0Sstevel@tonic-gate 		    (params.mask & REQUIRED_PARAMS) ^ REQUIRED_PARAMS);
582*0Sstevel@tonic-gate 		fprintf(stderr,
583*0Sstevel@tonic-gate 		    gettext("%s: Missing required configuration values "
584*0Sstevel@tonic-gate 			"(%x) while initializing, aborting\n"), whoami,
585*0Sstevel@tonic-gate 		    (params.mask & REQUIRED_PARAMS) ^ REQUIRED_PARAMS);
586*0Sstevel@tonic-gate 		krb5_klog_close(context);
587*0Sstevel@tonic-gate 		exit(1);
588*0Sstevel@tonic-gate 	}
589*0Sstevel@tonic-gate 	memset((char *) &addr, 0, sizeof (struct sockaddr_in));
590*0Sstevel@tonic-gate 	addr.sin_family = AF_INET;
591*0Sstevel@tonic-gate 	addr.sin_addr.s_addr = INADDR_ANY;
592*0Sstevel@tonic-gate 	l_port = addr.sin_port = htons(params.kadmind_port);
593*0Sstevel@tonic-gate 	sin = &addr;
594*0Sstevel@tonic-gate 
595*0Sstevel@tonic-gate 	if ((handlep = setnetconfig()) == (void *) NULL) {
596*0Sstevel@tonic-gate 		(void) krb5_klog_syslog(LOG_ERR,
597*0Sstevel@tonic-gate 		    gettext("cannot get any transport information"));
598*0Sstevel@tonic-gate 		krb5_klog_close(context);
599*0Sstevel@tonic-gate 		exit(1);
600*0Sstevel@tonic-gate 	}
601*0Sstevel@tonic-gate 	while (nconf = getnetconfig(handlep)) {
602*0Sstevel@tonic-gate 		if ((nconf->nc_semantics == NC_TPI_COTS_ORD) &&
603*0Sstevel@tonic-gate 		    (strcmp(nconf->nc_protofmly, NC_INET) == 0) &&
604*0Sstevel@tonic-gate 		    (strcmp(nconf->nc_proto, NC_TCP) == 0))
605*0Sstevel@tonic-gate 			break;
606*0Sstevel@tonic-gate 	}
607*0Sstevel@tonic-gate 
608*0Sstevel@tonic-gate 	if (nconf == (struct netconfig *) NULL) {
609*0Sstevel@tonic-gate 		(void) endnetconfig(handlep);
610*0Sstevel@tonic-gate 		krb5_klog_close(context);
611*0Sstevel@tonic-gate 		exit(1);
612*0Sstevel@tonic-gate 	}
613*0Sstevel@tonic-gate 	fd = t_open(nconf->nc_device, O_RDWR, &tinfo);
614*0Sstevel@tonic-gate 	if (fd == -1) {
615*0Sstevel@tonic-gate 		krb5_klog_syslog(LOG_ERR,
616*0Sstevel@tonic-gate 		    gettext("unable to open connection for ADMIN server"));
617*0Sstevel@tonic-gate 		krb5_klog_close(context);
618*0Sstevel@tonic-gate 		exit(1);
619*0Sstevel@tonic-gate 	}
620*0Sstevel@tonic-gate 	/* LINTED */
621*0Sstevel@tonic-gate 	opt = (struct opthdr *) reqbuf;
622*0Sstevel@tonic-gate 	opt->level = SOL_SOCKET;
623*0Sstevel@tonic-gate 	opt->name = SO_REUSEADDR;
624*0Sstevel@tonic-gate 	opt->len = sizeof (int);
625*0Sstevel@tonic-gate 
626*0Sstevel@tonic-gate 	/*
627*0Sstevel@tonic-gate 	 * The option value is "1".  This will allow the server to restart
628*0Sstevel@tonic-gate 	 * whilst the previous process is cleaning up after itself in a
629*0Sstevel@tonic-gate 	 * FIN_WAIT_2 or TIME_WAIT state.  If another process is started
630*0Sstevel@tonic-gate 	 * outside of smf(5) then bind will fail anyway, which is what we want.
631*0Sstevel@tonic-gate 	 */
632*0Sstevel@tonic-gate 	reqbuf[sizeof (struct opthdr)] = 1;
633*0Sstevel@tonic-gate 
634*0Sstevel@tonic-gate 	req.flags = T_NEGOTIATE;
635*0Sstevel@tonic-gate 	req.opt.len = sizeof (struct opthdr) + opt->len;
636*0Sstevel@tonic-gate 	req.opt.buf = (char *) opt;
637*0Sstevel@tonic-gate 
638*0Sstevel@tonic-gate 	resp.flags = 0;
639*0Sstevel@tonic-gate 	resp.opt.buf = reqbuf;
640*0Sstevel@tonic-gate 	resp.opt.maxlen = sizeof (reqbuf);
641*0Sstevel@tonic-gate 
642*0Sstevel@tonic-gate 	if (t_optmgmt(fd, &req, &resp) < 0 || resp.flags != T_SUCCESS) {
643*0Sstevel@tonic-gate 		t_error("t_optmgmt");
644*0Sstevel@tonic-gate 		exit(1);
645*0Sstevel@tonic-gate 	}
646*0Sstevel@tonic-gate 	/* Transform addr to netbuf */
647*0Sstevel@tonic-gate 
648*0Sstevel@tonic-gate 	tres = (struct t_bind *) t_alloc(fd, T_BIND, T_ADDR);
649*0Sstevel@tonic-gate 	if (tres == NULL) {
650*0Sstevel@tonic-gate 		(void) t_close(fd);
651*0Sstevel@tonic-gate 		(void) krb5_klog_syslog(LOG_ERR,
652*0Sstevel@tonic-gate 					gettext("cannot allocate netbuf"));
653*0Sstevel@tonic-gate 		krb5_klog_close(context);
654*0Sstevel@tonic-gate 		exit(1);
655*0Sstevel@tonic-gate 	}
656*0Sstevel@tonic-gate 	tbindstr.qlen = 8;
657*0Sstevel@tonic-gate 	tbindstr.addr.buf = (char *) sin;
658*0Sstevel@tonic-gate 	tbindstr.addr.len = tbindstr.addr.maxlen = __rpc_get_a_size(tinfo.addr);
659*0Sstevel@tonic-gate 	sin = (struct sockaddr_in *) tbindstr.addr.buf;
660*0Sstevel@tonic-gate 	/* SUNWresync121 XXX (void) memset(&addr, 0, sizeof(addr)); */
661*0Sstevel@tonic-gate 
662*0Sstevel@tonic-gate 	if (t_bind(fd, &tbindstr, tres) < 0) {
663*0Sstevel@tonic-gate 		int oerrno = errno;
664*0Sstevel@tonic-gate 		fprintf(stderr, gettext("%s: Cannot bind socket.\n"), whoami);
665*0Sstevel@tonic-gate 		fprintf(stderr, gettext("bind: %s\n"), error_message(oerrno));
666*0Sstevel@tonic-gate 		errno = oerrno;
667*0Sstevel@tonic-gate 		krb5_klog_syslog(LOG_ERR, gettext("Cannot bind socket: %s"),
668*0Sstevel@tonic-gate 		    error_message(errno));
669*0Sstevel@tonic-gate 		if (oerrno == EADDRINUSE) {
670*0Sstevel@tonic-gate 			char *w = strrchr(whoami, '/');
671*0Sstevel@tonic-gate 
672*0Sstevel@tonic-gate 			if (w) {
673*0Sstevel@tonic-gate 				w++;
674*0Sstevel@tonic-gate 			} else {
675*0Sstevel@tonic-gate 				w = whoami;
676*0Sstevel@tonic-gate 			}
677*0Sstevel@tonic-gate 			fprintf(stderr, gettext(
678*0Sstevel@tonic-gate 				"This probably means that another %s "
679*0Sstevel@tonic-gate 				"process is already\n"
680*0Sstevel@tonic-gate 				"running, or that another program is using "
681*0Sstevel@tonic-gate 				"the server port (number %d)\n"
682*0Sstevel@tonic-gate 				"after being assigned it by the RPC "
683*0Sstevel@tonic-gate 				"portmap deamon.	If another\n"
684*0Sstevel@tonic-gate 				"%s is already running, you should kill "
685*0Sstevel@tonic-gate 				"it before\n"
686*0Sstevel@tonic-gate 				"restarting the server. If, on the other hand, "
687*0Sstevel@tonic-gate 				"another program is\n"
688*0Sstevel@tonic-gate 				"using the server port, you should kill it "
689*0Sstevel@tonic-gate 				"before running\n"
690*0Sstevel@tonic-gate 				"%s, and ensure that the conflict does "
691*0Sstevel@tonic-gate 				"not occur in the\n"
692*0Sstevel@tonic-gate 				"future by making sure that %s is started "
693*0Sstevel@tonic-gate 				"on reboot\n"
694*0Sstevel@tonic-gate 				"before portmap.\n"),
695*0Sstevel@tonic-gate 			    w, ntohs(addr.sin_port), w, w, w);
696*0Sstevel@tonic-gate 			krb5_klog_syslog(LOG_ERR,
697*0Sstevel@tonic-gate 			    gettext("Check for already-running %s or for "
698*0Sstevel@tonic-gate 				"another process using port %d"), w,
699*0Sstevel@tonic-gate 			    htons(addr.sin_port));
700*0Sstevel@tonic-gate 		}
701*0Sstevel@tonic-gate 		krb5_klog_close(context);
702*0Sstevel@tonic-gate 		exit(1);
703*0Sstevel@tonic-gate 	}
704*0Sstevel@tonic-gate 	transp = svc_tli_create(fd, nconf, NULL, 0, 0);
705*0Sstevel@tonic-gate 	(void) t_free((char *) tres, T_BIND);
706*0Sstevel@tonic-gate 	if (transp == NULL) {
707*0Sstevel@tonic-gate 		fprintf(stderr, gettext("%s: Cannot create RPC service.\n"),
708*0Sstevel@tonic-gate 			whoami);
709*0Sstevel@tonic-gate 		krb5_klog_syslog(LOG_ERR, gettext("Cannot create RPC service: %m"));
710*0Sstevel@tonic-gate 		krb5_klog_close(context);
711*0Sstevel@tonic-gate 		exit(1);
712*0Sstevel@tonic-gate 	}
713*0Sstevel@tonic-gate 	if (!svc_register(transp, KADM, KADMVERS, kadm_1, 0)) {
714*0Sstevel@tonic-gate 		fprintf(stderr,
715*0Sstevel@tonic-gate 		    gettext("%s: Cannot register RPC service.\n"), whoami);
716*0Sstevel@tonic-gate 		krb5_klog_syslog(LOG_ERR,
717*0Sstevel@tonic-gate 		    gettext("Cannot register RPC service, failing."));
718*0Sstevel@tonic-gate 		krb5_klog_close(context);
719*0Sstevel@tonic-gate 		exit(1);
720*0Sstevel@tonic-gate 	}
721*0Sstevel@tonic-gate 
722*0Sstevel@tonic-gate 	/*
723*0Sstevel@tonic-gate 	 * XXX krb5_defkeyname is an internal library global and should go
724*0Sstevel@tonic-gate 	 * away
725*0Sstevel@tonic-gate 	 */
726*0Sstevel@tonic-gate 	krb5_overridekeyname = params.admin_keytab;
727*0Sstevel@tonic-gate 
728*0Sstevel@tonic-gate 	(void) kadm5_get_adm_host_srv_name(context,
729*0Sstevel@tonic-gate 					   params.realm, &names[0].name);
730*0Sstevel@tonic-gate 	(void) kadm5_get_cpw_host_srv_name(context,
731*0Sstevel@tonic-gate 					   params.realm, &names[1].name);
732*0Sstevel@tonic-gate 	names[2].name = KADM5_ADMIN_SERVICE_P;
733*0Sstevel@tonic-gate 	names[3].name = KADM5_CHANGEPW_SERVICE_P;
734*0Sstevel@tonic-gate 	names[4].name = OVSEC_KADM_ADMIN_SERVICE_P;
735*0Sstevel@tonic-gate 	names[5].name = OVSEC_KADM_CHANGEPW_SERVICE_P;
736*0Sstevel@tonic-gate 
737*0Sstevel@tonic-gate 	if (names[0].name == NULL || names[1].name == NULL ||
738*0Sstevel@tonic-gate 	    names[2].name == NULL || names[3].name == NULL ||
739*0Sstevel@tonic-gate 	    names[4].name == NULL || names[5].name == NULL) {
740*0Sstevel@tonic-gate 		krb5_klog_syslog(LOG_ERR,
741*0Sstevel@tonic-gate 		    gettext("Cannot initialize GSS-API authentication, "
742*0Sstevel@tonic-gate 			"failing."));
743*0Sstevel@tonic-gate 		fprintf(stderr,
744*0Sstevel@tonic-gate 		    gettext("%s: Cannot initialize "
745*0Sstevel@tonic-gate 			"GSS-API authentication.\n"),
746*0Sstevel@tonic-gate 		    whoami);
747*0Sstevel@tonic-gate 		krb5_klog_close(context);
748*0Sstevel@tonic-gate 		exit(1);
749*0Sstevel@tonic-gate 	}
750*0Sstevel@tonic-gate 
751*0Sstevel@tonic-gate 
752*0Sstevel@tonic-gate 	/*
753*0Sstevel@tonic-gate 	 * Try to acquire creds for the old OV services as well as the new
754*0Sstevel@tonic-gate 	 * names, but if that fails just fall back on the new names.
755*0Sstevel@tonic-gate 	 */
756*0Sstevel@tonic-gate 
757*0Sstevel@tonic-gate 	if (rpc_gss_set_svc_name(names[5].name,
758*0Sstevel@tonic-gate 				"kerberos_v5", 0, KADM, KADMVERS) &&
759*0Sstevel@tonic-gate 	    rpc_gss_set_svc_name(names[4].name,
760*0Sstevel@tonic-gate 				"kerberos_v5", 0, KADM, KADMVERS))
761*0Sstevel@tonic-gate 		oldnames++;
762*0Sstevel@tonic-gate 	if (rpc_gss_set_svc_name(names[3].name,
763*0Sstevel@tonic-gate 				"kerberos_v5", 0, KADM, KADMVERS))
764*0Sstevel@tonic-gate 		oldnames++;
765*0Sstevel@tonic-gate 	if (rpc_gss_set_svc_name(names[2].name,
766*0Sstevel@tonic-gate 				"kerberos_v5", 0, KADM, KADMVERS))
767*0Sstevel@tonic-gate 		oldnames++;
768*0Sstevel@tonic-gate 	if (rpc_gss_set_svc_name(names[0].name,
769*0Sstevel@tonic-gate 				"kerberos_v5", 0, KADM, KADMVERS))
770*0Sstevel@tonic-gate 		oldnames++;
771*0Sstevel@tonic-gate 	if (rpc_gss_set_svc_name(names[1].name,
772*0Sstevel@tonic-gate 				"kerberos_v5", 0, KADM, KADMVERS))
773*0Sstevel@tonic-gate 		oldnames++;
774*0Sstevel@tonic-gate 	if (!oldnames) {
775*0Sstevel@tonic-gate 		krb5_klog_syslog(LOG_ERR,
776*0Sstevel@tonic-gate 		    gettext("Cannot initialize GSS-API authentication, "
777*0Sstevel@tonic-gate 			"failing."));
778*0Sstevel@tonic-gate 		fprintf(stderr,
779*0Sstevel@tonic-gate 		    gettext("%s:Cannot initialize GSS-API authentication.\n"),
780*0Sstevel@tonic-gate 		    whoami);
781*0Sstevel@tonic-gate 		krb5_klog_close(context);
782*0Sstevel@tonic-gate 		exit(1);
783*0Sstevel@tonic-gate 	}
784*0Sstevel@tonic-gate 
785*0Sstevel@tonic-gate 	retdn = getdomnames(context, params.realm, &dnames);
786*0Sstevel@tonic-gate 	if (retdn == 0 && dnames) {
787*0Sstevel@tonic-gate 		/*
788*0Sstevel@tonic-gate 		 * Multi-homed KDCs sometimes may need to set svc names
789*0Sstevel@tonic-gate 		 * for multiple net interfaces so we set them for
790*0Sstevel@tonic-gate 		 * all interfaces just in case.
791*0Sstevel@tonic-gate 		 */
792*0Sstevel@tonic-gate 		set_svc_domnames(KADM5_ADMIN_HOST_SERVICE,
793*0Sstevel@tonic-gate 				dnames, KADM, KADMVERS);
794*0Sstevel@tonic-gate 		set_svc_domnames(KADM5_CHANGEPW_HOST_SERVICE,
795*0Sstevel@tonic-gate 				dnames, KADM, KADMVERS);
796*0Sstevel@tonic-gate 	}
797*0Sstevel@tonic-gate 
798*0Sstevel@tonic-gate 	/* if set_names succeeded, this will too */
799*0Sstevel@tonic-gate 	in_buf.value = names[1].name;
800*0Sstevel@tonic-gate 	in_buf.length = strlen(names[1].name) + 1;
801*0Sstevel@tonic-gate 	(void) gss_import_name(&OMret, &in_buf, (gss_OID) nt_krb5_name_oid,
802*0Sstevel@tonic-gate 	    &gss_changepw_name);
803*0Sstevel@tonic-gate 	if (oldnames) {
804*0Sstevel@tonic-gate 		in_buf.value = names[3].name;
805*0Sstevel@tonic-gate 		in_buf.length = strlen(names[3].name) + 1;
806*0Sstevel@tonic-gate 		(void) gss_import_name(&OMret, &in_buf,
807*0Sstevel@tonic-gate 					(gss_OID) nt_krb5_name_oid,
808*0Sstevel@tonic-gate 					&gss_oldchangepw_name);
809*0Sstevel@tonic-gate 	}
810*0Sstevel@tonic-gate 	if (ret = acl_init(context, 0, params.acl_file)) {
811*0Sstevel@tonic-gate 		krb5_klog_syslog(LOG_ERR, gettext("Cannot initialize acl file: %s"),
812*0Sstevel@tonic-gate 		    error_message(ret));
813*0Sstevel@tonic-gate 		fprintf(stderr, gettext("%s: Cannot initialize acl file: %s\n"),
814*0Sstevel@tonic-gate 		    whoami, error_message(ret));
815*0Sstevel@tonic-gate 		krb5_klog_close(context);
816*0Sstevel@tonic-gate 		exit(1);
817*0Sstevel@tonic-gate 	}
818*0Sstevel@tonic-gate 	if ((ret = kadm5_init("kadmind", NULL,
819*0Sstevel@tonic-gate 		    NULL, &params,
820*0Sstevel@tonic-gate 		    KADM5_STRUCT_VERSION,
821*0Sstevel@tonic-gate 		    KADM5_API_VERSION_2,
822*0Sstevel@tonic-gate 		    &global_server_handle)) != KADM5_OK) {
823*0Sstevel@tonic-gate 		krb5_klog_syslog(LOG_ERR,
824*0Sstevel@tonic-gate 		    gettext("%s while initializing, aborting"),
825*0Sstevel@tonic-gate 		    error_message(ret));
826*0Sstevel@tonic-gate 		fprintf(stderr,
827*0Sstevel@tonic-gate 		    gettext("%s: %s while initializing, aborting\n"),
828*0Sstevel@tonic-gate 		    whoami, error_message(ret));
829*0Sstevel@tonic-gate 		krb5_klog_close(context);
830*0Sstevel@tonic-gate 		exit(1);
831*0Sstevel@tonic-gate 	}
832*0Sstevel@tonic-gate 
833*0Sstevel@tonic-gate 	handle = global_server_handle;
834*0Sstevel@tonic-gate 	ctx = handle->context;
835*0Sstevel@tonic-gate 	if (params.iprop_enabled == TRUE)
836*0Sstevel@tonic-gate 		ulog_set_role(ctx, IPROP_MASTER);
837*0Sstevel@tonic-gate 	else
838*0Sstevel@tonic-gate 		ulog_set_role(ctx, IPROP_NULL);
839*0Sstevel@tonic-gate 
840*0Sstevel@tonic-gate 	log_ctx = ctx->kdblog_context;
841*0Sstevel@tonic-gate 
842*0Sstevel@tonic-gate 	if (log_ctx && (log_ctx->iproprole == IPROP_MASTER)) {
843*0Sstevel@tonic-gate 		/*
844*0Sstevel@tonic-gate 		 * IProp is enabled, so let's map in the update log
845*0Sstevel@tonic-gate 		 * and setup the service.
846*0Sstevel@tonic-gate 		 */
847*0Sstevel@tonic-gate 		if (ret = ulog_map(ctx, &params, FKADMIND)) {
848*0Sstevel@tonic-gate 			fprintf(stderr,
849*0Sstevel@tonic-gate 				gettext("%s: %s while mapping update log "
850*0Sstevel@tonic-gate 				"(`%s.ulog')\n"), whoami, error_message(ret),
851*0Sstevel@tonic-gate 				params.dbname);
852*0Sstevel@tonic-gate 			krb5_klog_syslog(LOG_ERR,
853*0Sstevel@tonic-gate 				gettext("%s while mapping update log "
854*0Sstevel@tonic-gate 				"(`%s.ulog')"), error_message(ret),
855*0Sstevel@tonic-gate 				params.dbname);
856*0Sstevel@tonic-gate 			krb5_klog_close(ctx);
857*0Sstevel@tonic-gate 			exit(1);
858*0Sstevel@tonic-gate 		}
859*0Sstevel@tonic-gate 
860*0Sstevel@tonic-gate 
861*0Sstevel@tonic-gate 		if (nofork)
862*0Sstevel@tonic-gate 			fprintf(stderr,
863*0Sstevel@tonic-gate 				"%s: create IPROP svc (PROG=%d, VERS=%d)\n",
864*0Sstevel@tonic-gate 				whoami, KRB5_IPROP_PROG, KRB5_IPROP_VERS);
865*0Sstevel@tonic-gate 
866*0Sstevel@tonic-gate 		if (!svc_create(krb5_iprop_prog_1,
867*0Sstevel@tonic-gate 				KRB5_IPROP_PROG, KRB5_IPROP_VERS,
868*0Sstevel@tonic-gate 				"circuit_v")) {
869*0Sstevel@tonic-gate 			fprintf(stderr,
870*0Sstevel@tonic-gate     gettext("%s: Cannot create IProp RPC service (PROG=%d, VERS=%d)\n"),
871*0Sstevel@tonic-gate 				whoami,
872*0Sstevel@tonic-gate 				KRB5_IPROP_PROG, KRB5_IPROP_VERS);
873*0Sstevel@tonic-gate 			krb5_klog_syslog(LOG_ERR,
874*0Sstevel@tonic-gate     gettext("Cannot create IProp RPC service (PROG=%d, VERS=%d), failing."),
875*0Sstevel@tonic-gate 					KRB5_IPROP_PROG, KRB5_IPROP_VERS);
876*0Sstevel@tonic-gate 			krb5_klog_close(ctx);
877*0Sstevel@tonic-gate 			exit(1);
878*0Sstevel@tonic-gate 		}
879*0Sstevel@tonic-gate 
880*0Sstevel@tonic-gate 		if (ret = kiprop_get_adm_host_srv_name(ctx,
881*0Sstevel@tonic-gate 							params.realm,
882*0Sstevel@tonic-gate 							&kiprop_name)) {
883*0Sstevel@tonic-gate 			krb5_klog_syslog(LOG_ERR,
884*0Sstevel@tonic-gate 			gettext("%s while getting IProp svc name, failing"),
885*0Sstevel@tonic-gate 					error_message(ret));
886*0Sstevel@tonic-gate 			fprintf(stderr,
887*0Sstevel@tonic-gate 		gettext("%s: %s while getting IProp svc name, failing\n"),
888*0Sstevel@tonic-gate 				whoami, error_message(ret));
889*0Sstevel@tonic-gate 			krb5_klog_close(ctx);
890*0Sstevel@tonic-gate 			exit(1);
891*0Sstevel@tonic-gate 		}
892*0Sstevel@tonic-gate 
893*0Sstevel@tonic-gate 		if (!rpc_gss_set_svc_name(kiprop_name, "kerberos_v5", 0,
894*0Sstevel@tonic-gate 					KRB5_IPROP_PROG, KRB5_IPROP_VERS)) {
895*0Sstevel@tonic-gate 			rpc_gss_error_t err;
896*0Sstevel@tonic-gate 			(void) rpc_gss_get_error(&err);
897*0Sstevel@tonic-gate 
898*0Sstevel@tonic-gate 			krb5_klog_syslog(LOG_ERR,
899*0Sstevel@tonic-gate     gettext("Unable to set RPCSEC_GSS service name (`%s'), failing."),
900*0Sstevel@tonic-gate 					kiprop_name ? kiprop_name : "<null>");
901*0Sstevel@tonic-gate 
902*0Sstevel@tonic-gate 			fprintf(stderr,
903*0Sstevel@tonic-gate     gettext("%s: Unable to set RPCSEC_GSS service name (`%s'), failing.\n"),
904*0Sstevel@tonic-gate 				whoami,
905*0Sstevel@tonic-gate 				kiprop_name ? kiprop_name : "<null>");
906*0Sstevel@tonic-gate 
907*0Sstevel@tonic-gate 			if (nofork) {
908*0Sstevel@tonic-gate 				fprintf(stderr,
909*0Sstevel@tonic-gate 			"%s: set svc name (rpcsec err=%d, sys err=%d)\n",
910*0Sstevel@tonic-gate 					whoami,
911*0Sstevel@tonic-gate 					err.rpc_gss_error,
912*0Sstevel@tonic-gate 					err.system_error);
913*0Sstevel@tonic-gate 			}
914*0Sstevel@tonic-gate 
915*0Sstevel@tonic-gate 			exit(1);
916*0Sstevel@tonic-gate 		}
917*0Sstevel@tonic-gate 		free(kiprop_name);
918*0Sstevel@tonic-gate 
919*0Sstevel@tonic-gate 		if (retdn == 0 && dnames) {
920*0Sstevel@tonic-gate 			set_svc_domnames(KADM5_KIPROP_HOST_SERVICE,
921*0Sstevel@tonic-gate 					dnames,
922*0Sstevel@tonic-gate 					KRB5_IPROP_PROG, KRB5_IPROP_VERS);
923*0Sstevel@tonic-gate 		}
924*0Sstevel@tonic-gate 
925*0Sstevel@tonic-gate 	}
926*0Sstevel@tonic-gate 
927*0Sstevel@tonic-gate 	if (dnames)
928*0Sstevel@tonic-gate 		freedomnames(dnames);
929*0Sstevel@tonic-gate 
930*0Sstevel@tonic-gate 	setup_signal_handlers(log_ctx->iproprole);
931*0Sstevel@tonic-gate 	krb5_klog_syslog(LOG_INFO, gettext("starting"));
932*0Sstevel@tonic-gate 	if (nofork)
933*0Sstevel@tonic-gate 		fprintf(stderr, "%s: starting...\n", whoami);
934*0Sstevel@tonic-gate 
935*0Sstevel@tonic-gate 
936*0Sstevel@tonic-gate 	/*
937*0Sstevel@tonic-gate 	 * We now call our own customized async event processing
938*0Sstevel@tonic-gate 	 * function kadm_svc_run(), as opposed to svc_run() earlier,
939*0Sstevel@tonic-gate 	 * since this enables kadmind to also listen-to/process
940*0Sstevel@tonic-gate 	 * non-RPCSEC_GSS based change-pwd requests apart from the
941*0Sstevel@tonic-gate 	 * regular, RPCSEC_GSS kpasswd requests from Solaris Krb5 clients.
942*0Sstevel@tonic-gate 	 */
943*0Sstevel@tonic-gate 	kadm_svc_run();
944*0Sstevel@tonic-gate 
945*0Sstevel@tonic-gate 	krb5_klog_syslog(LOG_INFO, gettext("finished, exiting"));
946*0Sstevel@tonic-gate 	kadm5_destroy(global_server_handle);
947*0Sstevel@tonic-gate 	t_close(fd);
948*0Sstevel@tonic-gate 	krb5_klog_close(context);
949*0Sstevel@tonic-gate 	exit(0);
950*0Sstevel@tonic-gate }
951*0Sstevel@tonic-gate 
952*0Sstevel@tonic-gate 
953*0Sstevel@tonic-gate /*
954*0Sstevel@tonic-gate  * Function: kadm_svc_run
955*0Sstevel@tonic-gate  *
956*0Sstevel@tonic-gate  * Purpose: modified version of sunrpc svc_run.
957*0Sstevel@tonic-gate  *	    which closes the database every TIMEOUT seconds.
958*0Sstevel@tonic-gate  *
959*0Sstevel@tonic-gate  * Arguments:
960*0Sstevel@tonic-gate  * Requires:
961*0Sstevel@tonic-gate  * Effects:
962*0Sstevel@tonic-gate  * Modifies:
963*0Sstevel@tonic-gate  */
964*0Sstevel@tonic-gate void
965*0Sstevel@tonic-gate kadm_svc_run(void)
966*0Sstevel@tonic-gate {
967*0Sstevel@tonic-gate 	struct pollfd	*rfd = 0;
968*0Sstevel@tonic-gate 	struct	timeval	    timeout;
969*0Sstevel@tonic-gate 	int pollret;
970*0Sstevel@tonic-gate 	int nfds = 0;
971*0Sstevel@tonic-gate 	int i;
972*0Sstevel@tonic-gate 
973*0Sstevel@tonic-gate 	while(signal_request_exit == 0) {
974*0Sstevel@tonic-gate 		timeout.tv_sec = TIMEOUT;
975*0Sstevel@tonic-gate 		timeout.tv_usec = 0;
976*0Sstevel@tonic-gate 
977*0Sstevel@tonic-gate 		if (nfds != svc_max_pollfd) {
978*0Sstevel@tonic-gate 			rfd = realloc(rfd, sizeof (pollfd_t) * svc_max_pollfd);
979*0Sstevel@tonic-gate 			nfds = svc_max_pollfd;
980*0Sstevel@tonic-gate 		}
981*0Sstevel@tonic-gate 
982*0Sstevel@tonic-gate 		(void) memcpy(rfd, svc_pollfd,
983*0Sstevel@tonic-gate 			sizeof (pollfd_t) * svc_max_pollfd);
984*0Sstevel@tonic-gate 
985*0Sstevel@tonic-gate 		for (i = 0; i < nfds; i++) {
986*0Sstevel@tonic-gate 			if (rfd[i].fd == -1) {
987*0Sstevel@tonic-gate 				rfd[i].fd = schpw;
988*0Sstevel@tonic-gate 				rfd[i].events = POLLIN;
989*0Sstevel@tonic-gate 				break;
990*0Sstevel@tonic-gate 			}
991*0Sstevel@tonic-gate 		}
992*0Sstevel@tonic-gate 
993*0Sstevel@tonic-gate 		switch(pollret = poll(rfd, nfds,
994*0Sstevel@tonic-gate 				__rpc_timeval_to_msec(&timeout))) {
995*0Sstevel@tonic-gate 		case -1:
996*0Sstevel@tonic-gate 			if(errno == EINTR)
997*0Sstevel@tonic-gate 				continue;
998*0Sstevel@tonic-gate 			perror("poll");
999*0Sstevel@tonic-gate 			return;
1000*0Sstevel@tonic-gate 		case 0:
1001*0Sstevel@tonic-gate 			continue;
1002*0Sstevel@tonic-gate 		default:
1003*0Sstevel@tonic-gate 			for (i = 0; i < nfds; i++) {
1004*0Sstevel@tonic-gate 				if (rfd[i].revents & POLLIN) {
1005*0Sstevel@tonic-gate 					if (rfd[i].fd == schpw)
1006*0Sstevel@tonic-gate 						handle_chpw(context, schpw,
1007*0Sstevel@tonic-gate 							global_server_handle,
1008*0Sstevel@tonic-gate 							&chgpw_params);
1009*0Sstevel@tonic-gate 					else
1010*0Sstevel@tonic-gate 						svc_getreq_poll(rfd, pollret);
1011*0Sstevel@tonic-gate 					break;
1012*0Sstevel@tonic-gate 				} else {
1013*0Sstevel@tonic-gate 					if (i == (nfds - 1))
1014*0Sstevel@tonic-gate 						perror("poll");
1015*0Sstevel@tonic-gate 				}
1016*0Sstevel@tonic-gate 			}
1017*0Sstevel@tonic-gate 			break;
1018*0Sstevel@tonic-gate 		}
1019*0Sstevel@tonic-gate 	}
1020*0Sstevel@tonic-gate }
1021*0Sstevel@tonic-gate 
1022*0Sstevel@tonic-gate 
1023*0Sstevel@tonic-gate /*
1024*0Sstevel@tonic-gate  * Function: setup_signal_handlers
1025*0Sstevel@tonic-gate  *
1026*0Sstevel@tonic-gate  * Purpose: Setup signal handling functions with System V's signal().
1027*0Sstevel@tonic-gate  */
1028*0Sstevel@tonic-gate void setup_signal_handlers(iprop_role iproprole) {
1029*0Sstevel@tonic-gate 	signal(SIGINT, sig_exit);
1030*0Sstevel@tonic-gate 	signal(SIGTERM, sig_exit);
1031*0Sstevel@tonic-gate 	signal(SIGQUIT, sig_exit);
1032*0Sstevel@tonic-gate 	signal(SIGPIPE, sig_pipe);
1033*0Sstevel@tonic-gate 
1034*0Sstevel@tonic-gate 	/*
1035*0Sstevel@tonic-gate 	 * IProp will fork for a full-resync, we don't want to
1036*0Sstevel@tonic-gate 	 * wait on it and we don't want the living dead procs either.
1037*0Sstevel@tonic-gate 	 */
1038*0Sstevel@tonic-gate 	if (iproprole == IPROP_MASTER)
1039*0Sstevel@tonic-gate 		(void) signal(SIGCHLD, SIG_IGN);
1040*0Sstevel@tonic-gate 
1041*0Sstevel@tonic-gate 	return;
1042*0Sstevel@tonic-gate }
1043*0Sstevel@tonic-gate 
1044*0Sstevel@tonic-gate 
1045*0Sstevel@tonic-gate /*
1046*0Sstevel@tonic-gate  * Function: sig_exit
1047*0Sstevel@tonic-gate  *
1048*0Sstevel@tonic-gate  * Purpose: sets flags saying the server got a signal and that it
1049*0Sstevel@tonic-gate  *          should exit when convenient.
1050*0Sstevel@tonic-gate  *
1051*0Sstevel@tonic-gate  * Effects:
1052*0Sstevel@tonic-gate  *      Modifies signal_request_exit which ideally makes the server exit
1053*0Sstevel@tonic-gate  *      at some point.
1054*0Sstevel@tonic-gate  *
1055*0Sstevel@tonic-gate  * Modifies:
1056*0Sstevel@tonic-gate  *      Signal_request_exit
1057*0Sstevel@tonic-gate  */
1058*0Sstevel@tonic-gate void sig_exit(int signum)
1059*0Sstevel@tonic-gate {
1060*0Sstevel@tonic-gate 	krb5_klog_syslog(LOG_NOTICE, gettext("Got signal to request exit"));
1061*0Sstevel@tonic-gate 	signal_request_exit = 1;
1062*0Sstevel@tonic-gate 	return;
1063*0Sstevel@tonic-gate }
1064*0Sstevel@tonic-gate 
1065*0Sstevel@tonic-gate 
1066*0Sstevel@tonic-gate /*
1067*0Sstevel@tonic-gate  * Function: sig_pipe
1068*0Sstevel@tonic-gate  *
1069*0Sstevel@tonic-gate  * Purpose: SIGPIPE handler
1070*0Sstevel@tonic-gate  *
1071*0Sstevel@tonic-gate  * Effects: krb5_klog_syslog a message that a SIGPIPE occurred and returns,
1072*0Sstevel@tonic-gate  * thus causing the read() or write() to fail and, presumable, the RPC
1073*0Sstevel@tonic-gate  * to recover.	Otherwise, the process aborts.
1074*0Sstevel@tonic-gate  */
1075*0Sstevel@tonic-gate void
1076*0Sstevel@tonic-gate sig_pipe(int unused)
1077*0Sstevel@tonic-gate {
1078*0Sstevel@tonic-gate 	krb5_klog_syslog(LOG_NOTICE, gettext("Warning: Received a SIGPIPE; "
1079*0Sstevel@tonic-gate 		"probably a client aborted.  Continuing."));
1080*0Sstevel@tonic-gate }
1081