nis_rpc.c revision 61961e0f20c7637a3846bb39786bb9dffa91dfb9
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (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 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
*
* This module contains some grungy RPC binding functions that are
* used by the client library.
*/
#include "mt.h"
#include <syslog.h>
#include <stdlib.h>
#include <malloc.h>
#include <unistd.h>
#include <string.h>
#include "nis_clnt.h"
#include "nis_local.h"
#if defined(sparc)
#else /* !sparc */
#endif /* sparc */
uint_t, int, int, char *);
/*
* This internal structure is used to track the bindings. NOTE
* the client structure comes first because it is cast to a CLIENT *
* by other functions. This keeps the private stuff out of our hair
* in those other functions.
*/
struct server {
char *rpcb_uaddr; /* address of rpcbind for server */
char *serv_uaddr; /* address of actual server */
char *netid; /* netconfig id */
unsigned int flags; /* flags for this */
int bpc; /* Binding policy control */
int key_type; /* Type of authentication to use */
unsigned int ref_cnt; /* reference count */
int fd; /* fd from clnt handle */
};
extern int __nis_debuglevel;
extern FILE *__nis_debug_file;
extern int __nis_debug_bind;
/*
* Prototypes for static functions.
*/
static void remove_server(server *);
static int check_rdev(server *);
static int srv_count = 0;
/*
* A weak attempt was made to make the preferred server code be
* mt-safe. But it doesn't quite work because the name of the
* preferred server is held in a global variable. It must be
* made into a per-thread variable to allow separate threads
* to have different preferred servers.
*/
/* protected by _nis_preferred_lock */
/*
* our own version of rand() so we don't perturb the one in libc
*/
static int32_t __nis_randx = 0;
__nis_librand(void)
{
if (__nis_randx == 0) {
(void) gettimeofday(&tp, 0);
}
return (rx);
}
void
{
(void) strcpy(__nis_test_server, s);
}
void
__nis_no_preference(void)
{
}
static void
{
if (srv_listhead == srv)
if (srv_listtail == srv)
}
/*
* This STUPID function is provided TEMPORARILY to get around a csh BUG.
*/
extern int __nis_destroy_callback();
void
__nis_reset_state(void)
{
/* WARNING: calling this function from a MT program */
/* is dangerous, it should be avoid at all cost */
cur = srv_listhead;
while (cur) {
/* XXX: Force reference to zero, otherwise */
/* entry will not be freed. */
cur = srv_listhead;
}
}
/*
* Cleans up local list of bad servers
* Procedure called by nis_handle
*/
static
void
{
/*
* Clean up RPC bindings. All entries inside this list
* will be deleted, regardless of their reference count.
* Free dynamic memory content.
*/
next_srv = 0;
(void) check_rdev(scan);
}
}
static
CLIENT *
{
int fd;
int bpc; /* binding policy control */
int srv_cached = 1;
return (0);
return (0);
} else {
return (0);
}
/*
* Determine the binding policy :
* 0 - authenticated virtual circuit
* 1 - authenticated datagram
* 2 - unauthenticated virtual circuit;
* 3 - unauthenticated datagram;
*/
if (__nis_debuglevel)
"NIS+: nis_client_handle: wants (%s, %s())",
/*
* To perform the search and keep the LRU cache as small as possible:
* 1. Look in cache for a binding match. While doing so:
* a. Check for invalid bindings
* - if invalid - move to cleanup list
* b. Look for matches
* - if match, assign a pointer to it
* 2. If we don't have a cached match
* a. Create a new entry into the cache
* b. Rstabilish an RPC binding
* 3. Release all locks and clean up invalid entries
* 4. Return binding as result
*/
/* Look for the binding in our unlimited- entry LRU cache */
/*
* Starting cache access operation - grab lock
* Scan the list for matches
*/
/*
* First save the next pointer in case
* we delete this one.
*/
/*
* Four things can cause us to throw out a cached
* handle :
* a) someone has called "bad_server()" on it.
* b) Some other process created it (we're a
* forked child process, or a vforked process.)
* c) application closed or changed file
* descriptor in clnt
* d) the process has done a setuid on it and it
* wants to do a authenticated operation.
*/
(!check_rdev(cur)) ||
srv_toclean = cur;
srv_count--;
}
continue;
}
/*
* If the server's transport address has
* changed, then throw out the client
* handle. Of course, comparing the uaddrs
* is only meaningful if the transport types
* match.
*/
if (__nis_debug_bind) {
(void) fprintf(__nis_debug_file,
"server %s restarted\n",
}
srv_toclean = cur;
srv_count--;
}
continue;
}
break;
/* sometimes non-exact matches can be reused */
/*
* DG+UNAUTH: do not worry about key_type.
* VC+UNAUTH and DG+UNAUTH can be reused.
*/
break;
/*
* DG+AUTH: match key_types
* VC+AUTH can be reused.
*/
(bpc == 1) &&
break;
#ifdef NIS_NON_EXACT
/*
* These may be too ambitious.
* authenticated handles may not work
* sometimes when unauthenticated ones would.
* (e.g. if caller cannot be authenticated).
*/
/* DG+unauth can reuse any existing binding */
if (bpc == 3)
break;
/*
* VC+auth can be used for
* VC+unauth
* DG+auth if key_types are the same
*/
(bpc == 2 ||
(bpc == 1 &&
break;
#endif /* NIS_NON_EXACT */
}
}
/*
* If 'cur' has a non-NULL value, a match has been found.
* If no match was found, then try to create new node.
*/
if (!cur) {
srv_cached = 0;
/*
* Release lock to allow other threads to run while new binding
* is being created.
*/
/* Check if allowed to create new node */
if (!create) {
return (NULL);
}
/*
* We need to create a new client handle. Be careful to
* not create handles to "bad" endpoints.
*/
return (0);
}
switch (bpc) {
case 0 : /* auth + circuit */
if (__nis_debug_bind) {
(void) fprintf(__nis_debug_file,
"create handle: VC+AUTH\n");
}
break;
case 1 : /* auth + datagram */
if (__nis_debug_bind) {
(void) fprintf(__nis_debug_file,
"create handle: DG+AUTH\n");
}
break;
case 2 : /* circuit */
if (__nis_debug_bind) {
(void) fprintf(__nis_debug_file,
"create handle: VC\n");
}
break;
case 3 : /* datagram */
if (__nis_debug_bind) {
(void) fprintf(__nis_debug_file,
"create handle: DG\n");
}
ZMH_DG, 0, 0,
break;
default : /* error */
break;
}
/*
* We can't create a handle even though we have
* the address of the server. The server address
* must be bad (server restarted or gone).
*/
if (__nis_CacheRefreshAddress(bep))
goto new_address;
if (__nis_debuglevel) {
"NIS+: __bind_rpc: could not "
"create handle to %s (%s, %s(%d))",
"VC" : "DG",
"auth" : "no auth",
}
return (NULL);
}
if (__nis_debuglevel) {
"NIS+: __bind_rpc: "
"created handle to %s (%s, %s(%d))",
}
/*
* We have created a new RPC binding.
* Insert new entry into LRU cache.
*/
/*
* We must rescan the list, searching for duplicates.
* If a duplicate has been created by another thread,
* we simply return the duplicate.
* Strict checking - only exact matches allowed.
*/
break;
}
/* Match found in the cache */
if (srv_listhead != dupcur) {
}
(void) fprintf(__nis_debug_file,
}
"NIS+: __bind_rpc: "
"reusing handle to %s (%s, %s(%d))",
"VC" : "DG",
"auth" : "no auth",
}
/*
* Delete duplicate connection, so that
* fd's are not leaked. Release fd.
*/
}
}
/*
* Allocate new server binding entry.
*/
srv_count++;
if (!srv_new) {
/* no free entry, so give up... */
if (__nis_debuglevel) {
(void) printf(
"can not create binding cache entry: "
"out of memory\n");
}
/* clean up */
return (NULL);
} else {
if (srv_listhead)
if (! srv_listtail)
srv_listtail = cur;
srv_listhead = cur;
}
}
/*
* At this point, an entry has either been found in
* the cache or a new entry has been created.
*/
if (srv_cached == 0) {
/* New entry */
/* make it "close on exec" */
} else {
/* Match found in the cache */
if (srv_listhead != cur) {
srv_listhead = cur;
}
(void) fprintf(__nis_debug_file,
}
"NIS+: __bind_rpc: "
"reusing handle to %s (%s, %s(%d))",
"VC" : "DG",
"auth" : "no auth",
}
}
}
CLIENT *
{
}
CLIENT *
{
}
static void
{
srv_count--;
(void) check_rdev(srv);
/* Finished critical ops - reacquire lock */
}
static
void
{
}
char *
{
break;
}
}
return (name);
}
/*
* Return the name of the server associated with a client handle.
* We search for the client handle and then return a copy of
* the server name.
*/
char *
{
char *s = NULL;
return (NULL);
return (s);
}
/*
* __nis_release_server()
*
* This function decreament the server reference count,
* without destroying the client handle.
*
*/
void
{
switch (status) {
case RPC_AUTHERROR:
return;
case RPC_CANTSEND:
case RPC_CANTRECV:
/*
* If we get either of these errors on a datagram
* endpoint, then there was some sort of transport
* error. We set nis_error to NIS_RPCERROR (if
* it isn't already set to something else).
*/
}
break;
case RPC_TIMEDOUT:
case RPC_SUCCESS:
break;
default:
break;
}
if (__nis_debug_bind) {
(void) fprintf(__nis_debug_file,
"release %s, status = %d\n",
}
if (status != RPC_SUCCESS) {
/*
* If the server is restarted, datagram
* clients will get RPC_TIMEDOUT and
* virtual circuit clients will get
* RPC_CANTSEND. If we get either of
* these errors, try to refresh the address.
* If we can refresh it, then try the
* endpoint again.
*/
if (state &&
(status == RPC_TIMEDOUT ||
status == RPC_CANTSEND)) {
if (__nis_debug_bind) {
"refreshing address");
}
if (__nis_CacheRefreshAddress(bep)) {
if (__nis_debug_bind) {
"refreshed");
}
} else {
if (__nis_debug_bind) {
"refresh failed");
}
}
}
} else {
}
break;
}
}
}
/*
* Same as nis_bad_server except
* 1. it marks the flag as SRV_AUTH_INVALID to prevent deletion __bind_rpc
* 2. it marks all other authenticated handles for same server as bad too.
*/
void
{
break;
}
}
if (cur) {
/* found it, now mark other auth handles as invalid too. */
/* Mark all other authenticated handles as invalid */
}
}
}
}
#define S_INIT 0
#define S_HAVEBINDING 1
#define S_REFRESH 2
#define S_BINDFAIL 3
void
{
}
void
{
}
static
void
{
int rank;
if (init) {
} else {
}
}
} else {
}
}
static
int
{
int i;
for (i = 0; i < nsrv; i++) {
return (i);
}
return (-1);
}
CLIENT *
{
int i;
int n;
(void) __start_clock(CLOCK_CACHE);
for (;;) {
case S_INIT:
if (__nis_debug_bind) {
(void) fprintf(__nis_debug_file,
"binding to server %s\n",
}
if (__nis_debug_bind) {
(void) fprintf(__nis_debug_file,
"binding to directory %s%s%s\n",
? " (parent first)"
: " (name first)",
? " (master only)"
: "");
}
n = __nis_server_index(
state->server_name);
if (n == -1) {
"__nis_get_server: can't find server %s in directory %s",
return (NULL);
} else if (n != 0) {
&srv[n], 1,
if (err == NIS_SUCCESS &&
old_binding != NULL)
}
}
err = NIS_SUCCESS;
if (__nis_debug_bind) {
(void) fprintf(__nis_debug_file,
"binding passed in\n");
}
} else {
if (__nis_debug_bind) {
(void) fprintf(__nis_debug_file,
"no binding information\n");
}
}
if (err != NIS_SUCCESS) {
if (__nis_debug_bind) {
(void) fprintf(__nis_debug_file,
"bind failed\n");
}
return (NULL);
}
if (__nis_debug_bind) {
(void) fprintf(__nis_debug_file,
"bind succeeded\n");
}
break;
case S_HAVEBINDING:
if (clnt) {
return (clnt);
}
}
if (clnt) {
return (clnt);
}
set_bep_range(state, 0);
} else {
}
break;
case S_REFRESH:
if (__nis_debug_bind) {
(void) fprintf(__nis_debug_file,
"refreshing binding\n");
}
state->refresh_count == 0) {
/*
* We don't have to refresh a binding
* obtained through __nis_CacheBindServer
* because there is no directory
* associated with it.
*/
} else {
return (NULL);
}
break;
case S_BINDFAIL:
if (__nis_debug_bind) {
(void) fprintf(__nis_debug_file,
"binding failure\n");
}
return (NULL);
}
}
/*NOTREACHED*/
}
static
void
{
int fd;
return;
}
}
static
int
{
return (1); /* can't check it, assume it is okay */
/* could be because file descriptor was closed */
/* it's not our file descriptor, so don't try to close it */
return (0);
}
"NIS+: fd %d changed, old=0x%lx, new=0x%lx",
/* it's not our file descriptor, so don't try to close it */
return (0);
}
return (1); /* fd is okay */
}