145916cd2Sjpk /* 245916cd2Sjpk * CDDL HEADER START 345916cd2Sjpk * 445916cd2Sjpk * The contents of this file are subject to the terms of the 545916cd2Sjpk * Common Development and Distribution License (the "License"). 645916cd2Sjpk * You may not use this file except in compliance with the License. 745916cd2Sjpk * 845916cd2Sjpk * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 945916cd2Sjpk * or http://www.opensolaris.org/os/licensing. 1045916cd2Sjpk * See the License for the specific language governing permissions 1145916cd2Sjpk * and limitations under the License. 1245916cd2Sjpk * 1345916cd2Sjpk * When distributing Covered Code, include this CDDL HEADER in each 1445916cd2Sjpk * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 1545916cd2Sjpk * If applicable, add the following below this CDDL HEADER, with the 1645916cd2Sjpk * fields enclosed by brackets "[]" replaced with your own identifying 1745916cd2Sjpk * information: Portions Copyright [yyyy] [name of copyright owner] 1845916cd2Sjpk * 1945916cd2Sjpk * CDDL HEADER END 2045916cd2Sjpk */ 21f841f6adSraf 2245916cd2Sjpk /* 2345916cd2Sjpk * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 2445916cd2Sjpk * Use is subject to license terms. 2545916cd2Sjpk */ 2645916cd2Sjpk 2745916cd2Sjpk #include <door.h> 2845916cd2Sjpk #include <errno.h> 2945916cd2Sjpk #include <fcntl.h> 3045916cd2Sjpk #include <stdio.h> 3145916cd2Sjpk #include <stdlib.h> 3245916cd2Sjpk #include <synch.h> 3345916cd2Sjpk #include <time.h> 3445916cd2Sjpk #include <unistd.h> 3545916cd2Sjpk 3645916cd2Sjpk #include <sys/param.h> 3745916cd2Sjpk #include <sys/stat.h> 3845916cd2Sjpk #include <sys/types.h> 3945916cd2Sjpk 4045916cd2Sjpk #include "labeld.h" 4145916cd2Sjpk 4245916cd2Sjpk #ifndef DEBUG 4345916cd2Sjpk #define perror(e) 4445916cd2Sjpk #endif /* !DEBUG */ 4545916cd2Sjpk 4645916cd2Sjpk /* 4745916cd2Sjpk * This is cloned from _nsc_trydoorcall used by the nscd client. 4845916cd2Sjpk * 4945916cd2Sjpk * Routine that actually performs the door call. 5045916cd2Sjpk * Note that we cache a file descriptor. We do 5145916cd2Sjpk * the following to prevent disasters: 5245916cd2Sjpk * 5345916cd2Sjpk * 1) Never use 0, 1 or 2; if we get this from the open 5445916cd2Sjpk * we dup it upwards. 5545916cd2Sjpk * 5645916cd2Sjpk * 2) Set the close on exec flags so descriptor remains available 5745916cd2Sjpk * to child processes. 5845916cd2Sjpk * 5945916cd2Sjpk * 3) Verify that the door is still the same one we had before 6045916cd2Sjpk * by using door_info on the client side. 6145916cd2Sjpk * 6245916cd2Sjpk * Note that we never close the file descriptor if it isn't one 6345916cd2Sjpk * we allocated; we check this with door info. The rather tricky 6445916cd2Sjpk * logic is designed to be fast in the normal case (fd is already 6545916cd2Sjpk * allocated and is ok) while handling the case where the application 6645916cd2Sjpk * closed it underneath us or where the nscd dies or re-execs itself 6745916cd2Sjpk * and we're a multi-threaded application. Note that we cannot protect 6845916cd2Sjpk * the application if it closes the fd and it is multi-threaded. 6945916cd2Sjpk * 7045916cd2Sjpk * int __call_labeld(label_door_op **dptr, int *ndata, int *adata); 7145916cd2Sjpk * 7245916cd2Sjpk * *dptr IN: points to arg buffer OUT: points to results buffer 7345916cd2Sjpk * *ndata IN: overall size of buffer OUT: overall size of buffer 7445916cd2Sjpk * *adata IN: size of call data OUT: size of return data 7545916cd2Sjpk * 7645916cd2Sjpk * Note that *dptr may change if provided space as defined by *bufsize is 7745916cd2Sjpk * inadequate. In this case the door call mmaps more space and places 7845916cd2Sjpk * the answer there and sets dptr to contain a pointer to the space, which 7945916cd2Sjpk * should be freed with munmap. 8045916cd2Sjpk * 8145916cd2Sjpk * Returns 0 if the door call reached the server, -1 if contact was not made. 8245916cd2Sjpk * 8345916cd2Sjpk */ 8445916cd2Sjpk 8545916cd2Sjpk 8645916cd2Sjpk static mutex_t _door_lock = DEFAULTMUTEX; 8745916cd2Sjpk 8845916cd2Sjpk int 8945916cd2Sjpk __call_labeld(labeld_data_t **dptr, size_t *ndata, size_t *adata) 9045916cd2Sjpk { 9145916cd2Sjpk static int doorfd = -1; 9245916cd2Sjpk static door_info_t real_door; 9345916cd2Sjpk struct stat st; 9445916cd2Sjpk door_info_t my_door; 9545916cd2Sjpk door_arg_t param; 9645916cd2Sjpk char door_name[MAXPATHLEN]; 9745916cd2Sjpk struct timespec ts; 9845916cd2Sjpk int busy = 0; /* number of busy loops */ 9945916cd2Sjpk 10045916cd2Sjpk #ifdef DEBUG 10145916cd2Sjpk labeld_data_t *callptr = *dptr; 10245916cd2Sjpk int buf_size = *ndata; 10345916cd2Sjpk int return_size = *adata; 10445916cd2Sjpk #endif /* DEBUG */ 10545916cd2Sjpk 10645916cd2Sjpk /* 10745916cd2Sjpk * the first time in we try and open and validate the door. 10845916cd2Sjpk * the validations are that the door must have been 10945916cd2Sjpk * created with the label service door cookie and 11045916cd2Sjpk * that it has the same door ID. If any of these 11145916cd2Sjpk * validations fail we refuse to use the door. 11245916cd2Sjpk */ 11345916cd2Sjpk ts.tv_sec = 0; /* initialize nanosecond retry timer */ 11445916cd2Sjpk ts.tv_nsec = 100; 11545916cd2Sjpk (void) mutex_lock(&_door_lock); 11645916cd2Sjpk 11745916cd2Sjpk try_again: 11845916cd2Sjpk if (doorfd == -1) { 11945916cd2Sjpk int tbc[3]; 12045916cd2Sjpk int i; 12145916cd2Sjpk 12245916cd2Sjpk (void) snprintf(door_name, sizeof (door_name), "%s%s", 12345916cd2Sjpk DOOR_PATH, DOOR_NAME); 12445916cd2Sjpk if ((doorfd = open64(door_name, O_RDONLY, 0)) < 0) { 12545916cd2Sjpk (void) mutex_unlock(&_door_lock); 12645916cd2Sjpk perror("server door open"); 12745916cd2Sjpk return (NOSERVER); 12845916cd2Sjpk } 12945916cd2Sjpk 13045916cd2Sjpk /* 13145916cd2Sjpk * dup up the file descriptor if we have 0 - 2 13245916cd2Sjpk * to avoid problems with shells stdin/out/err 13345916cd2Sjpk */ 13445916cd2Sjpk i = 0; 13545916cd2Sjpk while (doorfd < 3) { /* we have a reserved fd */ 13645916cd2Sjpk tbc[i++] = doorfd; 13745916cd2Sjpk if ((doorfd = dup(doorfd)) < 0) { 13845916cd2Sjpk perror("couldn't dup"); 13945916cd2Sjpk while (i--) 14045916cd2Sjpk (void) close(tbc[i]); 14145916cd2Sjpk doorfd = -1; 14245916cd2Sjpk (void) mutex_unlock(&_door_lock); 14345916cd2Sjpk return (NOSERVER); 14445916cd2Sjpk } 14545916cd2Sjpk } 14645916cd2Sjpk while (i--) 14745916cd2Sjpk (void) close(tbc[i]); 14845916cd2Sjpk 14945916cd2Sjpk /* 15045916cd2Sjpk * mark this door descriptor as close on exec 15145916cd2Sjpk */ 15245916cd2Sjpk (void) fcntl(doorfd, F_SETFD, FD_CLOEXEC); 15345916cd2Sjpk if (door_info(doorfd, &real_door) < 0) { 15445916cd2Sjpk /* 15545916cd2Sjpk * we should close doorfd because we just opened it 15645916cd2Sjpk */ 15745916cd2Sjpk perror("real door door_info"); 15845916cd2Sjpk (void) close(doorfd); 15945916cd2Sjpk doorfd = -1; 16045916cd2Sjpk (void) mutex_unlock(&_door_lock); 16145916cd2Sjpk return (NOSERVER); 16245916cd2Sjpk } 16345916cd2Sjpk if (fstat(doorfd, &st) < 0) { 16445916cd2Sjpk perror("real door fstat"); 16545916cd2Sjpk return (NOSERVER); 16645916cd2Sjpk } 16745916cd2Sjpk #ifdef DEBUG 16845916cd2Sjpk (void) printf("\treal door %s\n", door_name); 16945916cd2Sjpk (void) printf("\t\tuid = %d, gid = %d, mode = %o\n", st.st_uid, 17045916cd2Sjpk st.st_gid, st.st_mode); 17145916cd2Sjpk (void) printf("\t\toutstanding requests = %d\n", st.st_nlink-1); 17245916cd2Sjpk (void) printf("\t\t pid = %d\n", real_door.di_target); 17345916cd2Sjpk (void) printf("\t\t procedure = %llx\n", real_door.di_proc); 17445916cd2Sjpk (void) printf("\t\t cookie = %llx\n", real_door.di_data); 17545916cd2Sjpk (void) printf("\t\t attributes = %x\n", 17645916cd2Sjpk real_door.di_attributes); 17745916cd2Sjpk if (real_door.di_attributes & DOOR_UNREF) 17845916cd2Sjpk (void) printf("\t\t\t UNREF\n"); 17945916cd2Sjpk if (real_door.di_attributes & DOOR_PRIVATE) 18045916cd2Sjpk (void) printf("\t\t\t PRIVATE\n"); 18145916cd2Sjpk if (real_door.di_attributes & DOOR_LOCAL) 18245916cd2Sjpk (void) printf("\t\t\t LOCAL\n"); 18345916cd2Sjpk if (real_door.di_attributes & DOOR_REVOKED) 18445916cd2Sjpk (void) printf("\t\t\t REVOKED\n"); 18545916cd2Sjpk if (real_door.di_attributes & DOOR_DESCRIPTOR) 18645916cd2Sjpk (void) printf("\t\t\t DESCRIPTOR\n"); 18745916cd2Sjpk if (real_door.di_attributes & DOOR_RELEASE) 18845916cd2Sjpk (void) printf("\t\t\t RELEASE\n"); 18945916cd2Sjpk if (real_door.di_attributes & DOOR_DELAY) 19045916cd2Sjpk (void) printf("\t\t\t DELAY\n"); 19145916cd2Sjpk (void) printf("\t\t id = %llx\n", real_door.di_uniquifier); 19245916cd2Sjpk #endif /* DEBUG */ 19345916cd2Sjpk if ((real_door.di_attributes & DOOR_REVOKED) || 194*b30a53d0SRichard Lowe (real_door.di_data != COOKIE)) { 19545916cd2Sjpk #ifdef DEBUG 19645916cd2Sjpk (void) printf("real door revoked\n"); 19745916cd2Sjpk #endif /* DEBUG */ 19845916cd2Sjpk (void) close(doorfd); 19945916cd2Sjpk doorfd = -1; 20045916cd2Sjpk (void) mutex_unlock(&_door_lock); 20145916cd2Sjpk return (NOSERVER); 20245916cd2Sjpk } 20345916cd2Sjpk } else { 20445916cd2Sjpk if ((door_info(doorfd, &my_door) < 0) || 205*b30a53d0SRichard Lowe (my_door.di_data != COOKIE) || 20645916cd2Sjpk (my_door.di_uniquifier != real_door.di_uniquifier)) { 20745916cd2Sjpk perror("my door door_info"); 20845916cd2Sjpk /* 20945916cd2Sjpk * don't close it - someone else has clobbered fd 21045916cd2Sjpk */ 21145916cd2Sjpk doorfd = -1; 21245916cd2Sjpk goto try_again; 21345916cd2Sjpk } 21445916cd2Sjpk if (fstat(doorfd, &st) < 0) { 21545916cd2Sjpk perror("my door fstat"); 21645916cd2Sjpk goto try_again; 21745916cd2Sjpk } 21845916cd2Sjpk #ifdef DEBUG 21945916cd2Sjpk (void) sprintf(door_name, "%s%s", DOOR_PATH, DOOR_NAME); 22045916cd2Sjpk (void) printf("\tmy door %s\n", door_name); 22145916cd2Sjpk (void) printf("\t\tuid = %d, gid = %d, mode = %o\n", st.st_uid, 22245916cd2Sjpk st.st_gid, st.st_mode); 22345916cd2Sjpk (void) printf("\t\toutstanding requests = %d\n", st.st_nlink-1); 22445916cd2Sjpk (void) printf("\t\t pid = %d\n", my_door.di_target); 22545916cd2Sjpk (void) printf("\t\t procedure = %llx\n", my_door.di_proc); 22645916cd2Sjpk (void) printf("\t\t cookie = %llx\n", my_door.di_data); 22745916cd2Sjpk (void) printf("\t\t attributes = %x\n", my_door.di_attributes); 22845916cd2Sjpk if (my_door.di_attributes & DOOR_UNREF) 22945916cd2Sjpk (void) printf("\t\t\t UNREF\n"); 23045916cd2Sjpk if (my_door.di_attributes & DOOR_PRIVATE) 23145916cd2Sjpk (void) printf("\t\t\t PRIVATE\n"); 23245916cd2Sjpk if (my_door.di_attributes & DOOR_LOCAL) 23345916cd2Sjpk (void) printf("\t\t\t LOCAL\n"); 23445916cd2Sjpk if (my_door.di_attributes & DOOR_REVOKED) 23545916cd2Sjpk (void) printf("\t\t\t REVOKED\n"); 23645916cd2Sjpk if (my_door.di_attributes & DOOR_DESCRIPTOR) 23745916cd2Sjpk (void) printf("\t\t\t DESCRIPTOR\n"); 23845916cd2Sjpk if (my_door.di_attributes & DOOR_RELEASE) 23945916cd2Sjpk (void) printf("\t\t\t RELEASE\n"); 24045916cd2Sjpk if (my_door.di_attributes & DOOR_DELAY) 24145916cd2Sjpk (void) printf("\t\t\t DELAY\n"); 24245916cd2Sjpk (void) printf("\t\t id = %llx\n", my_door.di_uniquifier); 24345916cd2Sjpk #endif /* DEBUG */ 24445916cd2Sjpk if (my_door.di_attributes & DOOR_REVOKED) { 24545916cd2Sjpk #ifdef DEBUG 24645916cd2Sjpk (void) printf("my door revoked\n"); 24745916cd2Sjpk #endif /* DEBUG */ 24845916cd2Sjpk (void) close(doorfd); /* labeld exited .... */ 24945916cd2Sjpk doorfd = -1; /* try and restart connection */ 25045916cd2Sjpk goto try_again; 25145916cd2Sjpk } 25245916cd2Sjpk } 25345916cd2Sjpk (void) mutex_unlock(&_door_lock); 25445916cd2Sjpk 25545916cd2Sjpk param.data_ptr = (char *)*dptr; 25645916cd2Sjpk param.data_size = *adata; 25745916cd2Sjpk param.desc_ptr = NULL; 25845916cd2Sjpk param.desc_num = 0; 25945916cd2Sjpk param.rbuf = (char *)*dptr; 26045916cd2Sjpk param.rsize = *ndata; 26145916cd2Sjpk 26245916cd2Sjpk if (door_call(doorfd, ¶m) < 0) { 26345916cd2Sjpk if (errno == EAGAIN && busy++ < 10) { 26445916cd2Sjpk /* adjust backoff */ 26545916cd2Sjpk if ((ts.tv_nsec *= 10) >= NANOSEC) { 26645916cd2Sjpk ts.tv_sec++; 26745916cd2Sjpk ts.tv_nsec = 100; 26845916cd2Sjpk } 269f841f6adSraf (void) nanosleep(&ts, NULL); 27045916cd2Sjpk #ifdef DEBUG 27145916cd2Sjpk (void) printf("door_call failed EAGAIN # %d\n", busy); 27245916cd2Sjpk #endif /* DEBUG */ 27345916cd2Sjpk (void) mutex_lock(&_door_lock); 27445916cd2Sjpk goto try_again; 27545916cd2Sjpk } 27645916cd2Sjpk perror("door call"); 27745916cd2Sjpk return (NOSERVER); 27845916cd2Sjpk } 27945916cd2Sjpk 28045916cd2Sjpk *adata = (int)param.data_size; 28145916cd2Sjpk *ndata = (int)param.rsize; 28245916cd2Sjpk /*LINTED*/ 28345916cd2Sjpk *dptr = (labeld_data_t *)param.data_ptr; 28445916cd2Sjpk 28545916cd2Sjpk if (*adata == 0 || *dptr == NULL) { 28645916cd2Sjpk #ifdef DEBUG 28745916cd2Sjpk (void) printf("\tNo data returned, size = %lu, dptr = %p\n", 28845916cd2Sjpk (unsigned long)*adata, (void *)*dptr); 28945916cd2Sjpk #endif /* DEBUG */ 29045916cd2Sjpk return (NOSERVER); 29145916cd2Sjpk } 29245916cd2Sjpk #ifdef DEBUG 29345916cd2Sjpk (void) printf("call buf = %x, buf size = %d, call size = %d\n", 29445916cd2Sjpk callptr, buf_size, return_size); 29545916cd2Sjpk (void) printf("retn buf = %x, buf size = %d, retn size = %d\n", 29645916cd2Sjpk *dptr, *ndata, *adata); 29745916cd2Sjpk (void) printf("\treply status = %d\n", (*dptr)->param.aret.ret); 29845916cd2Sjpk #endif /* DEBUG */ 29945916cd2Sjpk return ((*dptr)->param.aret.ret); 30045916cd2Sjpk 30145916cd2Sjpk } /* __call_labeld */ 302