xref: /onnv-gate/usr/src/lib/libtsol/common/call_labeld.c (revision 2248:4609e8bb25ad)
11676Sjpk /*
21676Sjpk  * CDDL HEADER START
31676Sjpk  *
41676Sjpk  * The contents of this file are subject to the terms of the
51676Sjpk  * Common Development and Distribution License (the "License").
61676Sjpk  * You may not use this file except in compliance with the License.
71676Sjpk  *
81676Sjpk  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
91676Sjpk  * or http://www.opensolaris.org/os/licensing.
101676Sjpk  * See the License for the specific language governing permissions
111676Sjpk  * and limitations under the License.
121676Sjpk  *
131676Sjpk  * When distributing Covered Code, include this CDDL HEADER in each
141676Sjpk  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
151676Sjpk  * If applicable, add the following below this CDDL HEADER, with the
161676Sjpk  * fields enclosed by brackets "[]" replaced with your own identifying
171676Sjpk  * information: Portions Copyright [yyyy] [name of copyright owner]
181676Sjpk  *
191676Sjpk  * CDDL HEADER END
201676Sjpk  */
21*2248Sraf 
221676Sjpk /*
231676Sjpk  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
241676Sjpk  * Use is subject to license terms.
251676Sjpk  */
261676Sjpk 
271676Sjpk #pragma ident	"%Z%%M%	%I%	%E% SMI"
281676Sjpk 
291676Sjpk #include <door.h>
301676Sjpk #include <errno.h>
311676Sjpk #include <fcntl.h>
321676Sjpk #include <stdio.h>
331676Sjpk #include <stdlib.h>
341676Sjpk #include <synch.h>
351676Sjpk #include <time.h>
361676Sjpk #include <unistd.h>
371676Sjpk 
381676Sjpk #include <sys/param.h>
391676Sjpk #include <sys/stat.h>
401676Sjpk #include <sys/types.h>
411676Sjpk 
421676Sjpk #include "labeld.h"
431676Sjpk 
441676Sjpk #ifndef	DEBUG
451676Sjpk #define	perror(e)
461676Sjpk #endif	/* !DEBUG */
471676Sjpk 
481676Sjpk /*
491676Sjpk  *	This is cloned from _nsc_trydoorcall used by the nscd client.
501676Sjpk  *
511676Sjpk  * Routine that actually performs the door call.
521676Sjpk  * Note that we cache a file descriptor.  We do
531676Sjpk  * the following to prevent disasters:
541676Sjpk  *
551676Sjpk  * 1) Never use 0, 1 or 2; if we get this from the open
561676Sjpk  *    we dup it upwards.
571676Sjpk  *
581676Sjpk  * 2) Set the close on exec flags so descriptor remains available
591676Sjpk  *    to child processes.
601676Sjpk  *
611676Sjpk  * 3) Verify that the door is still the same one we had before
621676Sjpk  *    by using door_info on the client side.
631676Sjpk  *
641676Sjpk  *	Note that we never close the file descriptor if it isn't one
651676Sjpk  *	we allocated; we check this with door info.  The rather tricky
661676Sjpk  *	logic is designed to be fast in the normal case (fd is already
671676Sjpk  *	allocated and is ok) while handling the case where the application
681676Sjpk  *	closed it underneath us or where the nscd dies or re-execs itself
691676Sjpk  *	and we're a multi-threaded application.  Note that we cannot protect
701676Sjpk  *	the application if it closes the fd and it is multi-threaded.
711676Sjpk  *
721676Sjpk  *  int __call_labeld(label_door_op **dptr, int *ndata, int *adata);
731676Sjpk  *
741676Sjpk  *      *dptr	IN: points to arg buffer OUT: points to results buffer
751676Sjpk  *      *ndata	IN: overall size of buffer OUT: overall size of buffer
761676Sjpk  *      *adata	IN: size of call data OUT: size of return data
771676Sjpk  *
781676Sjpk  *  Note that *dptr may change if provided space as defined by *bufsize is
791676Sjpk  *  inadequate.  In this case the door call mmaps more space and places
801676Sjpk  *  the answer there and sets dptr to contain a pointer to the space, which
811676Sjpk  *  should be freed with munmap.
821676Sjpk  *
831676Sjpk  *  Returns 0 if the door call reached the server, -1 if contact was not made.
841676Sjpk  *
851676Sjpk  */
861676Sjpk 
871676Sjpk 
881676Sjpk static mutex_t	_door_lock = DEFAULTMUTEX;
891676Sjpk 
901676Sjpk int
__call_labeld(labeld_data_t ** dptr,size_t * ndata,size_t * adata)911676Sjpk __call_labeld(labeld_data_t **dptr, size_t *ndata, size_t *adata)
921676Sjpk {
931676Sjpk 	static	int 		doorfd = -1;
941676Sjpk 	static	door_info_t 	real_door;
951676Sjpk 	struct stat		st;
961676Sjpk 	door_info_t 		my_door;
971676Sjpk 	door_arg_t		param;
981676Sjpk 	char			door_name[MAXPATHLEN];
991676Sjpk 	struct timespec		ts;
1001676Sjpk 	int			busy = 0;	/* number of busy loops */
1011676Sjpk 
1021676Sjpk #ifdef	DEBUG
1031676Sjpk 	labeld_data_t		*callptr = *dptr;
1041676Sjpk 	int			buf_size = *ndata;
1051676Sjpk 	int			return_size = *adata;
1061676Sjpk #endif	/* DEBUG */
1071676Sjpk 
1081676Sjpk 	/*
1091676Sjpk 	 * the first time in we try and open and validate the door.
1101676Sjpk 	 * the validations are that the door must have been
1111676Sjpk 	 * created with the label service door cookie and
1121676Sjpk 	 * that it has the same door ID.  If any of these
1131676Sjpk 	 * validations fail we refuse to use the door.
1141676Sjpk 	 */
1151676Sjpk 	ts.tv_sec = 0;		/* initialize nanosecond retry timer */
1161676Sjpk 	ts.tv_nsec = 100;
1171676Sjpk 	(void) mutex_lock(&_door_lock);
1181676Sjpk 
1191676Sjpk try_again:
1201676Sjpk 	if (doorfd == -1) {
1211676Sjpk 		int	tbc[3];
1221676Sjpk 		int	i;
1231676Sjpk 
1241676Sjpk 		(void) snprintf(door_name, sizeof (door_name), "%s%s",
1251676Sjpk 		    DOOR_PATH, DOOR_NAME);
1261676Sjpk 		if ((doorfd = open64(door_name, O_RDONLY, 0)) < 0) {
1271676Sjpk 			(void) mutex_unlock(&_door_lock);
1281676Sjpk 			perror("server door open");
1291676Sjpk 			return (NOSERVER);
1301676Sjpk 		}
1311676Sjpk 
1321676Sjpk 		/*
1331676Sjpk 		 * dup up the file descriptor if we have 0 - 2
1341676Sjpk 		 * to avoid problems with shells stdin/out/err
1351676Sjpk 		 */
1361676Sjpk 		i = 0;
1371676Sjpk 		while (doorfd < 3) { /* we have a reserved fd */
1381676Sjpk 			tbc[i++] = doorfd;
1391676Sjpk 			if ((doorfd = dup(doorfd)) < 0) {
1401676Sjpk 				perror("couldn't dup");
1411676Sjpk 				while (i--)
1421676Sjpk 				    (void) close(tbc[i]);
1431676Sjpk 				doorfd = -1;
1441676Sjpk 				(void) mutex_unlock(&_door_lock);
1451676Sjpk 				return (NOSERVER);
1461676Sjpk 			}
1471676Sjpk 		}
1481676Sjpk 		while (i--)
1491676Sjpk 		    (void) close(tbc[i]);
1501676Sjpk 
1511676Sjpk 		/*
1521676Sjpk 		 * mark this door descriptor as close on exec
1531676Sjpk 		 */
1541676Sjpk 		(void) fcntl(doorfd, F_SETFD, FD_CLOEXEC);
1551676Sjpk 		if (door_info(doorfd, &real_door) < 0) {
1561676Sjpk 			/*
1571676Sjpk 			 * we should close doorfd because we just opened it
1581676Sjpk 			 */
1591676Sjpk 			perror("real door door_info");
1601676Sjpk 			(void) close(doorfd);
1611676Sjpk 			doorfd = -1;
1621676Sjpk 			(void) mutex_unlock(&_door_lock);
1631676Sjpk 			return (NOSERVER);
1641676Sjpk 		}
1651676Sjpk 		if (fstat(doorfd, &st) < 0) {
1661676Sjpk 			perror("real door fstat");
1671676Sjpk 			return (NOSERVER);
1681676Sjpk 		}
1691676Sjpk #ifdef	DEBUG
1701676Sjpk 		(void) printf("\treal door %s\n", door_name);
1711676Sjpk 		(void) printf("\t\tuid = %d, gid = %d, mode = %o\n", st.st_uid,
1721676Sjpk 		    st.st_gid, st.st_mode);
1731676Sjpk 		(void) printf("\t\toutstanding requests = %d\n", st.st_nlink-1);
1741676Sjpk 		(void) printf("\t\t pid = %d\n", real_door.di_target);
1751676Sjpk 		(void) printf("\t\t procedure = %llx\n", real_door.di_proc);
1761676Sjpk 		(void) printf("\t\t cookie = %llx\n",  real_door.di_data);
1771676Sjpk 		(void) printf("\t\t attributes = %x\n",
1781676Sjpk 		    real_door.di_attributes);
1791676Sjpk 		if (real_door.di_attributes & DOOR_UNREF)
1801676Sjpk 			(void) printf("\t\t\t UNREF\n");
1811676Sjpk 		if (real_door.di_attributes & DOOR_PRIVATE)
1821676Sjpk 			(void) printf("\t\t\t PRIVATE\n");
1831676Sjpk 		if (real_door.di_attributes & DOOR_LOCAL)
1841676Sjpk 			(void) printf("\t\t\t LOCAL\n");
1851676Sjpk 		if (real_door.di_attributes & DOOR_REVOKED)
1861676Sjpk 			(void) printf("\t\t\t REVOKED\n");
1871676Sjpk 		if (real_door.di_attributes & DOOR_DESCRIPTOR)
1881676Sjpk 			(void) printf("\t\t\t DESCRIPTOR\n");
1891676Sjpk 		if (real_door.di_attributes & DOOR_RELEASE)
1901676Sjpk 			(void) printf("\t\t\t RELEASE\n");
1911676Sjpk 		if (real_door.di_attributes & DOOR_DELAY)
1921676Sjpk 			(void) printf("\t\t\t DELAY\n");
1931676Sjpk 		(void) printf("\t\t id = %llx\n", real_door.di_uniquifier);
1941676Sjpk #endif	/* DEBUG */
1951676Sjpk 		if ((real_door.di_attributes & DOOR_REVOKED) ||
1961676Sjpk 		    (real_door.di_data != (door_ptr_t)COOKIE)) {
1971676Sjpk #ifdef	DEBUG
1981676Sjpk 			(void) printf("real door revoked\n");
1991676Sjpk #endif	/* DEBUG */
2001676Sjpk 			(void) close(doorfd);
2011676Sjpk 			doorfd = -1;
2021676Sjpk 			(void) mutex_unlock(&_door_lock);
2031676Sjpk 			return (NOSERVER);
2041676Sjpk 		}
2051676Sjpk 	} else {
2061676Sjpk 		if ((door_info(doorfd, &my_door) < 0) ||
2071676Sjpk 		    (my_door.di_data != (door_ptr_t)COOKIE) ||
2081676Sjpk 			(my_door.di_uniquifier != real_door.di_uniquifier)) {
2091676Sjpk 			perror("my door door_info");
2101676Sjpk 			/*
2111676Sjpk 			 * don't close it - someone else has clobbered fd
2121676Sjpk 			 */
2131676Sjpk 			doorfd = -1;
2141676Sjpk 			goto try_again;
2151676Sjpk 		}
2161676Sjpk 		if (fstat(doorfd, &st) < 0) {
2171676Sjpk 			perror("my door fstat");
2181676Sjpk 			goto try_again;
2191676Sjpk 		}
2201676Sjpk #ifdef	DEBUG
2211676Sjpk 		(void) sprintf(door_name, "%s%s", DOOR_PATH, DOOR_NAME);
2221676Sjpk 		(void) printf("\tmy door %s\n", door_name);
2231676Sjpk 		(void) printf("\t\tuid = %d, gid = %d, mode = %o\n", st.st_uid,
2241676Sjpk 		    st.st_gid, st.st_mode);
2251676Sjpk 		(void) printf("\t\toutstanding requests = %d\n", st.st_nlink-1);
2261676Sjpk 		(void) printf("\t\t pid = %d\n", my_door.di_target);
2271676Sjpk 		(void) printf("\t\t procedure = %llx\n", my_door.di_proc);
2281676Sjpk 		(void) printf("\t\t cookie = %llx\n",  my_door.di_data);
2291676Sjpk 		(void) printf("\t\t attributes = %x\n", my_door.di_attributes);
2301676Sjpk 		if (my_door.di_attributes & DOOR_UNREF)
2311676Sjpk 			(void) printf("\t\t\t UNREF\n");
2321676Sjpk 		if (my_door.di_attributes & DOOR_PRIVATE)
2331676Sjpk 			(void) printf("\t\t\t PRIVATE\n");
2341676Sjpk 		if (my_door.di_attributes & DOOR_LOCAL)
2351676Sjpk 			(void) printf("\t\t\t LOCAL\n");
2361676Sjpk 		if (my_door.di_attributes & DOOR_REVOKED)
2371676Sjpk 			(void) printf("\t\t\t REVOKED\n");
2381676Sjpk 		if (my_door.di_attributes & DOOR_DESCRIPTOR)
2391676Sjpk 			(void) printf("\t\t\t DESCRIPTOR\n");
2401676Sjpk 		if (my_door.di_attributes & DOOR_RELEASE)
2411676Sjpk 			(void) printf("\t\t\t RELEASE\n");
2421676Sjpk 		if (my_door.di_attributes & DOOR_DELAY)
2431676Sjpk 			(void) printf("\t\t\t DELAY\n");
2441676Sjpk 		(void) printf("\t\t id = %llx\n", my_door.di_uniquifier);
2451676Sjpk #endif	/* DEBUG */
2461676Sjpk 		if (my_door.di_attributes & DOOR_REVOKED) {
2471676Sjpk #ifdef	DEBUG
2481676Sjpk 			(void) printf("my door revoked\n");
2491676Sjpk #endif	/* DEBUG */
2501676Sjpk 			(void) close(doorfd);	/* labeld exited .... */
2511676Sjpk 			doorfd = -1;	/* try and restart connection */
2521676Sjpk 			goto try_again;
2531676Sjpk 		}
2541676Sjpk 	}
2551676Sjpk 	(void) mutex_unlock(&_door_lock);
2561676Sjpk 
2571676Sjpk 	param.data_ptr = (char *)*dptr;
2581676Sjpk 	param.data_size = *adata;
2591676Sjpk 	param.desc_ptr = NULL;
2601676Sjpk 	param.desc_num = 0;
2611676Sjpk 	param.rbuf = (char *)*dptr;
2621676Sjpk 	param.rsize = *ndata;
2631676Sjpk 
2641676Sjpk 	if (door_call(doorfd, &param) < 0) {
2651676Sjpk 		if (errno == EAGAIN && busy++ < 10) {
2661676Sjpk 			/* adjust backoff */
2671676Sjpk 			if ((ts.tv_nsec *= 10) >= NANOSEC) {
2681676Sjpk 				ts.tv_sec++;
2691676Sjpk 				ts.tv_nsec = 100;
2701676Sjpk 			}
271*2248Sraf 			(void) nanosleep(&ts, NULL);
2721676Sjpk #ifdef	DEBUG
2731676Sjpk 			(void) printf("door_call failed EAGAIN # %d\n", busy);
2741676Sjpk #endif	/* DEBUG */
2751676Sjpk 			(void) mutex_lock(&_door_lock);
2761676Sjpk 			goto try_again;
2771676Sjpk 		}
2781676Sjpk 		perror("door call");
2791676Sjpk 		return (NOSERVER);
2801676Sjpk 	}
2811676Sjpk 
2821676Sjpk 	*adata = (int)param.data_size;
2831676Sjpk 	*ndata = (int)param.rsize;
2841676Sjpk 	/*LINTED*/
2851676Sjpk 	*dptr = (labeld_data_t *)param.data_ptr;
2861676Sjpk 
2871676Sjpk 	if (*adata == 0 || *dptr == NULL) {
2881676Sjpk #ifdef	DEBUG
2891676Sjpk 		(void) printf("\tNo data returned, size = %lu, dptr = %p\n",
2901676Sjpk 		    (unsigned long)*adata, (void *)*dptr);
2911676Sjpk #endif	/* DEBUG */
2921676Sjpk 		return (NOSERVER);
2931676Sjpk 	}
2941676Sjpk #ifdef	DEBUG
2951676Sjpk 	(void) printf("call buf = %x, buf size  = %d, call size = %d\n",
2961676Sjpk 	    callptr, buf_size, return_size);
2971676Sjpk 	(void) printf("retn buf = %x, buf size  = %d, retn size = %d\n",
2981676Sjpk 	    *dptr, *ndata, *adata);
2991676Sjpk 	(void) printf("\treply status = %d\n", (*dptr)->param.aret.ret);
3001676Sjpk #endif	/* DEBUG */
3011676Sjpk 	return ((*dptr)->param.aret.ret);
3021676Sjpk 
3031676Sjpk }  /* __call_labeld */
304