/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include "lint.h"
#include <mtlib.h>
#include <errno.h>
#include <pwd.h>
#include <nss_dbdefs.h>
#include <stdio.h>
#include <string.h>
#include <synch.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <getxby_door.h>
#include <procfs.h>
#include <door.h>
#include "libc.h"
#include "tsd.h"
#include "base_conversion.h"
/* nss<->door hints */
/* library<->nscd door interaction apis */
/*
*
* Routine that actually performs the door call.
* Note that we cache a file descriptor. We do
* the following to prevent disasters:
*
* 1) Never use 0,1 or 2; if we get this from the open
* we dup it upwards.
*
* 2) Set the close on exec flags so descriptor remains available
* to child processes.
*
* 3) Verify that the door is still the same one we had before
* by using door_info on the client side.
*
* Note that we never close the file descriptor if it isn't one
* we allocated; we check this with door info. The rather tricky
* logic is designed to be fast in the normal case (fd is already
* allocated and is ok) while handling the case where the application
* closed it underneath us or where the nscd dies or re-execs itself
* and we're a multi-threaded application. Note that we cannot protect
* the application if it closes the fd and it is multi-threaded.
*
* int _nsc_trydoorcall(void *dptr, size_t *bufsize, size_t *actualsize);
*
* *dptr IN: points to arg buffer OUT: points to results buffer
* *bufsize IN: overall size of buffer OUT: overall size of buffer
* *actualsize IN: size of call data OUT: size of return data
*
* Note that *dptr may change if provided space as defined by *bufsize is
* inadequate. In this case the door call mmaps more space and places
* the answer there and sets dptr to contain a pointer to the space, which
* should be freed with munmap.
*
* Returns 0 if the door call reached the server, -1 if contact was not made.
*
*/
/*
* Max size for list of db names supported by the private nscd
* No implied max here, any size will do, fixed size chosen to
* reduce yet another malloc
*/
typedef struct _nsc_door_t {
int doorfd;
} nsc_door_t;
};
/* assumed to be locked by using nsc_door[1] mutex */
/*
* Check for a valid and matching db in the list.
* assume list is in the locked state.
*/
static int
{
char **ndb;
return (1);
}
}
return (0);
}
/*
* flush private db lists
*/
static void
{
if (nsc_db_buf != NULL) {
libc_free((void *)nsc_db_buf);
nsc_db_buf = NULL;
}
if (nsc_db_list != NULL) {
libc_free((void *)nsc_db_list);
nsc_db_list = NULL;
}
}
/*
* db's to be processed by a private nscd.
* This function assumes it has a well formed string from nscd.
*/
static int
{
int buflen = 0;
int arrlen = 0;
return (0);
/* reset db list */
/* rebuild fresh list */
arrlen++;
return (0);
arrlen += 2;
if (nsc_db_buf == (char *)NULL)
return (0);
if (nsc_db_list == (char **)NULL) {
libc_free((void *)nsc_db_buf);
nsc_db_buf = NULL;
return (0);
}
lp = nsc_db_list;
*lp++ = nsc_db_buf;
*cp++ = '\0';
} else
cp++;
}
return (1);
}
/*
* _nsc_initdoor_fp attempts to validate the given door and
* confirm that it is still available for use. The options are:
* Front door:
* If it's not open, attempt to open or error
* If it's open attempt to validate.
* If it's not validatable, reset fd and try again.
* Other wise it open and validated, return success
* Per user (back) door:
* This door is passed to the client through th front door
* attempt to validate it. If it can't be validated, it
* must be reset. Then send a NSS_ALTRESET error, so nscd can
* forward another fd if desired.
*/
static nss_status_t
{
return (NSS_ERROR);
}
/*
* the first time in we try and open and validate the front door.
* A front door request may return an alternate private back door
* that the client should use instead.
*
* To validate a door the door must have been created with
* the name service door cookie. The front door is file
* attached, owned by root and readonly by user, group and
* other. If any of these validations fail we refuse to use
* the door. A back door is delivered from the front door
* via a door_desc_t, and have the same cooke notification.
*/
int i;
return (NSS_ERROR);
}
/*
* dup up the file descriptor if we have 0 - 2
*/
i = 0;
while (i--)
return (NSS_ERROR);
}
}
while (i--)
/*
* mark this door descriptor as close on exec
*/
/*
* we should close doorfd because we just opened it
*/
'\0', sizeof (door_info_t));
return (NSS_ERROR);
}
} else {
/*
* don't close it -
* someone else has clobbered fd
*/
'\0', sizeof (door_info_t));
/* flush invalid db list */
return (NSS_ALTRESET);
}
goto try_again;
}
'\0', sizeof (door_info_t));
/* flush invalid db list */
return (NSS_ALTRESET);
}
goto try_again;
}
}
return (NSS_SUCCESS);
}
/*
* Try the door request once only, to the specified connection.
* return the results or error.
*/
static nss_status_t
{
int ret;
if (ret != NSS_SUCCESS)
return (ret);
if (ret < 0) {
return (NSS_ERROR);
}
/* have an alt descriptor */
/* got a NSS_ALTRETRY command */
return (NSS_ALTRETRY);
}
return (NSS_ERROR); /* other error? */
}
return (NSS_ERROR);
}
return (NSS_SUCCESS);
}
/*
* Backwards compatible API
*/
{
}
/*
* Send the request to the designated door, based on the supplied db
* Retry on the alternate door fd if possible.
*/
{
int fd;
char *dbl;
int fb2frontd = 0;
int reset_frontd = 0;
/*
* save away a copy of the header, in case the request needs
* to be sent to nscd more than once. In that case, this
* original header can be copied back to the door buffer
* to replace the possibly changed header
*/
/* try private (back) door first if it exists and applies */
_nsc_use_backdoor(db)) {
if (ret == NSS_ALTRESET) {
/*
* received NSS_ALTRESET command,
* retry on front door
*/
'\0', sizeof (door_info_t));
/* flush now invalid db list */
continue;
} else if (ret == NSS_ALTRETRY) {
/*
* received NSS_ALTRETRY command,
* fall back and retry on front door
*/
fb2frontd = 1;
/*
* restore the buffer size and header
* data so that the front door will
* see the original request
*/
*ndata = ndata_save;
*adata = adata_save;
/*
* tell the front door server, this is
* a fallback call
*/
continue;
}
/* return the result or error */
break;
}
/* try the front door */
fd = -1;
if (ret != NSS_ALTRETRY) {
/*
* got a success or failure result.
* but front door should never send NSS_ALTRESET
*/
if (ret == NSS_ALTRESET)
/* reset the front door */
reset_frontd = 1;
else
/*
* not NSS_ALTRETRY and not NSS_ALTRESET
* return the result or error
*/
break;
} else if (fb2frontd == 1) {
/*
* front door should never send NSS_ALTRETRY
* in a fallback call. Reset the front door.
*/
reset_frontd = 1;
}
if (reset_frontd == 1) {
'\0', sizeof (door_info_t));
/* error out */
break;
}
/* process NSS_ALTRETRY request from front door */
if (fd < 0)
continue; /* no new door given, try again */
/* update and try alternate door */
/* unexpected open alt door - clean up, continue */
}
/* set up back door fd */
/* set up back door db list */
if (_nsc_init_private_db(dbl) == 0) {
/* could not init db list, try again */
continue;
}
/* doorfd bad, or must not really be open */
'\0', sizeof (door_info_t));
}
/* NSS_ALTRETRY new back door */
/*
* restore the buffer size and header
* data so that the back door will
* see the original request
*/
*ndata = ndata_save;
*adata = adata_save;
}
return (ret);
}
/*
* Get the current (but growable) buffer size for a NSS2 packet.
* Heuristic algorithm used:
* 1) Make sure it's at least NSS_BUFLEN_DOOR in length (16k default)
* 2) if an incoming user buffer is > larger than the current size
* Make the buffer at least NSS_BUFLEN_DOOR/2+user buffer size
* This should account for any reasonable nss_pheader, keys
* extended area etc.
* to change any preconfigured value if needed(?)
*/
static size_t
{
if (!door_bsize) {
if (!door_bsize) {
/* future work - get nscd hint & use hint size */
if (door_bsize < NSS_BUFLEN_DOOR) {
}
}
}
}
}
return (door_bsize);
}
static void
{
}
}
/*
* _nsc_getdoorbuf - return the client side per thread door buffer
* Elsewhere, it is assumed that the header is 0'd upon return from here.
*/
int
{
char *bp;
return (-1);
/* Get thread specific pointer to door buffer */
return (-1);
/* if door buffer does not exist create it */
/* setup a door buffer with a total length of dsize */
return (-1);
} else {
/* check old buffer size and resize if needed */
if (*bufsize) {
return (-1);
}
}
/* freshly malloc'd door bufs are 0'd */
/* 0 header for now. Zero entire buf(?) TDB */
(size_t)sizeof (nss_pheader_t));
}
return (0);
}
void
{
/* signal to update if new door size is desired */
door_nbsize = bsize;
}
/*
* If it is set the appropriate flags and allow policy reconfiguration.
*/
int
{
int ret;
int fd;
if (proc_is_cache >= 0)
return (proc_is_cache);
if (proc_is_cache >= 0) {
return (proc_is_cache);
}
proc_is_cache = 0;
/* It can't be nscd if it's not running as root... */
if (getuid() != 0) {
return (0);
}
/* process runs as root and is named nscd */
/* that's good enough for now */
proc_is_cache = 1;
}
}
}
return (proc_is_cache);
}