nis_subr_proc.c revision 49e7ca4919cec3229f6fab9730bafc7cf24dab23
1N/A * The contents of this file are subject to the terms of the 1N/A * Common Development and Distribution License, Version 1.0 only 1N/A * (the "License"). You may not use this file except in compliance 1N/A * See the License for the specific language governing permissions 1N/A * and limitations under the License. 1N/A * When distributing Covered Code, include this CDDL HEADER in each 1N/A * If applicable, add the following below this CDDL HEADER, with the 1N/A * fields enclosed by brackets "[]" replaced with your own identifying 1N/A * information: Portions Copyright [yyyy] [name of copyright owner] 1N/A * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 1N/A * Use is subject to license terms. 1N/A * This module contains subroutines that are used by the NIS+ service but 1N/A * _not_ the NIS+ clients. NIS+ client routines are in the library module 1N/A#
pragma ident "%Z%%M% %I% %E% SMI" 1N/A/* routines for registering server's availability wrt given dirctory */ 1N/A * Release cached directory object. Intended for use by the cleanup 1N/A * code, executed when the thread is about to return to the RPC dispatch. 1N/A * Called when function is done with the directory_item, but release 1N/A * should be deferred until the thread is done with the current RPC 1N/A * request, or exits. 1N/A * Destroy a directory cache item. 1N/A * This function will remove a directory_item from the cache. The memory 1N/A * will be re-used when no thread is referencing it anymore. 1N/A * 1. Flush server's local directory cache. 1N/A * 2. Flush cachemgr's cache, using one of the following 1N/A * a. given directory object 1N/A * b. if none given and directory is in local cache, use its dir object. 1N/A * c. if directory is not in local cache, look it up from cachemgr, 1N/A * if found, delete it. 1N/A * 3. Flush the associated table cache. 1N/A /* Flush given directory object from cachemgr. */ 1N/A /* Update server's local directory cache. */ 1N/A /* Update cachemgr if have not done so yet. */ 1N/A * Since we cache the table for this dir object, 1N/A * we will flush that away as well. 1N/A * Refresh it from the master. 1N/A * XXX: We may have some scalability problems 1N/A * if all servers go to the master at the same time. Hopefully 1N/A * directory objects would not be updated very frequently, so it 1N/A * should not be such a big problem. 1N/A * Flush all cached directory objects from dircache and cachemgr. 1N/A * Since a destructor is in effect for this list, 1N/A * we have nothing to do; 'dd' will be freed when 1N/A * it's no longer in use. 1N/A * Flushes the local TABLE cache. Called when the database changes. 1N/A * We've established an item destructor for the table_cache, 1N/A * so the item will be destroyed automatically when it's 1N/A * no longer referenced. 1N/A * Flushes all TABLE caches. 1N/A * We've established an item destructor for the 1N/A * table_cache, so the item will be destroyed 1N/A * automatically when it's no longer referenced. 1N/A * Flushes a specific item from the group cache. 1N/A * Flushes all group caches. 1N/A * A convenient wrapper around __nis_cast_proc(). 1N/A * We need this function, since the root object is stored as a directory 1N/A * obj structure and not a nis_object. directory_obj strucs don't have the 1N/A * Note: Synchronization of access to 'tbl' is the responsibility of the 1N/A * We're not accumulating updates, so we only allow 1N/A * the mtime to go backwards. 1N/A /* Leave pp->mtime unchanged */ 1N/A * Reset update time and backoff delta, since it appears 1N/A * that we can talk to the master. 1N/A "add_pingitem: Couldn't add '%s' to pinglist (no memory)",
1N/A "add_pingitem: Couldn't add '%s' to pinglist (no memory)",
1N/A /* Update time (utime) == 0 means resync ASAP */ 1N/A * Only to be called from update_dl_item() via nis_scan_table() 1N/A * If the master server of the directory in the hash entry matches the 1N/A * master that isn't responding reset the expiry time to some point in 1N/A * the future. This is only applied to directories due to expire before 1N/A * the new expiry time. "expiry for directory %s to %d",
"directory %s, expiry %d is later",
"directory %s as master (%s) doesn't match",
/* Return false as true would terminate the scan */ * Updates directory item with given information. * If directory requires update, add it to 'upd_list'. * If directory is root directory, check whether root object requires int retry_time =
1800;
/* Backoff time for a dead master */ * Add it to the list of directories served by this * server if not already listed. * schedule update for directory contents but don't * If timestamp == 0, (i.e., failed to retrieve a timestamp * from the master), force the directory object to expire 30 * minutes later so that we can check the master again. In * the meantime, we will use the expired directory cache. * We use nis_scan_table_mt() to reset the expiry time on * all cached directories from this master server. "unable to get timestamp for %s " /* Update the hash list */ * The current entry may not be on the hash * list yet so we explicitly reset it here. * We have a valid timestamp from the master. Check and * update upd_list accordingly. /* If root object, schedule update for object itself too */ * These statistics are used to calculate the effectiveness of the * directory object cache. You can retrieve them with a TAG_DIRCACHE * This function is used to search for directory objects that describe * directories that this server serves. When called it will either * return a directory object which describes a directory that is served * or NULL if the directory is not served by this server. * It takes three parameters, name, ticks and is_master. Name is * presumed to be the NIS+ name of the directory we're looking for, ticks * points to a ticks structure that we can fill in with some statistics * and is_master indicates that not only should we serve the directory * but also we must be the master server for that directory. * A sanity check, if nis_name_of() returns NULL then either the * name passed is identical to the local directory (in which case * we can't possibly serve it unless we are a root server of a * local root), or the name isn't in our tree at all (shares * no common path). In which case we can't possibly serve it. * XXX intermediate workaround, until the next source * crank. The is_master "boolean" gets expanded here to * be a set of bit flags. In particular, the new flag * "NO_CACHE" is used to identify when the function calling * this function wants it to retrieve a new copy of the * directory object from the cache. /* get latest copy of directory object */ /* some statistics stuff ... */ * Now we check the cache to see if we have it cached locally. * If we found it in the cache, and we're asking for the * "no cache" version, then we flush the cache and * cause it to be re-looked up. * Found it in the cache. First we check to see if it * has expired, and then we check to see if we are the * master server. (we must serve it, otherwise it wouldn't * Check the expiration date on the object /* Should never happen */ /* Else it is expired so we're refreshing it. */ * At this point we either don't have it in our cache (dd == NULL) * or it is expired (dd != NULL) so we have to go looking for it * from either inside (our database) or outside (our parent). * First, we check to see if we are a root server and they want "__directory_object: internal database error.");
* (db result-> no such table ) * Ask the "parent" of "name" since this should not * recurse to the same server, we don't * worry about screwing up the current * server clock (clock(2)). But we will * get ticks back from the other server * so we return those in the ticks structure. /* It no longer exists */ "__directory_object: Failed to lookup %s, status %s",
/* It no longer exists */ * At this point, if d_obj is null then we couldn't find * it. We check to see if we have an expired cached version * and if so, log a warning and go ahead and use it. If * we don't have a cached version we just return NOTFOUND. "__directory_object: Using expired directory object for %s",
name);
/* If we found one, and it isn't a directory abort */ /* If the cache had one toss it out */ * We could re-acquire the item with a write lock, * and update it in place. However, in order to reduce * contention with other threads that might be using * the directory item, we instead remove it from the list, * and insert a new one with the updated info. * Some other thread got there before us. * Look in the cache for a new copy. * It's disappeared. Inform the * Ok we found the directory object, do we really serve it ? * Check to see if this server is supposed to serve this * domain. (Must be master to manipulate the name space) /* Check the master requirement */ * Returns the NIS+ principal name of the person making the request * XXX This is set up to use Secure RPC only at the moment, it should * be possible for any authentication scheme to be incorporated if it * has a "full name" that we can return as the principal name. * Check security conf file for classic des compat entry. * Return TRUE if entry found or if no valid mech entries * exist, else return FALSE. * Check conf file list of mech entries to see if this raw cred mechanism * type is permitted. Stop processing if the "des" compat entry is reached. * Return TRUE on validation, else FALSE. * Given a RPC netname, return the NIS+ principal. char *
name,
/* NIS+ principal (out) */ char srch[
2048];
/* search criteria */ "RPC request is NULL: returning '%s'",
nobody);
"nis_getprincipal: flavor = NONE: returning '%s'",
nobody);
"nis_getprincipal: flavor = SYS: returning '%s'",
"nis_getprincipal: flavor = SYS: returning '%s'",
name);
"[auth_name=\"%d\", auth_type=LOCAL], cred.org_dir.%s",
"nis_getprincipal: AUTH_DES not permitted: returning '%s'",
"nis_getprincipal: flavor = DES: returning from cache '%s'",
"[auth_name=%s, auth_type=DES], cred.org_dir.%s",
"nis_getprincipal: flavor = DES: returning '%s'",
"nis_getprincipal: GSS getcred failure: returning '%s'",
"nis_getprincipal: RPC GSS mechanism '%s' not permitted: returning nobody",
"nis_getprincipal: can't extract netname from RPC GSS cred: returning nobody");
"nis_getprincipal: flavor = GSS: returning '%s' from cache",
"nis_getprincipal: GSS mechname '%s' not found: returning nobody",
"[auth_name=%s, auth_type=%s], cred.org_dir.%s",
"nis_getprincipal: no alias was found for mechname '%s': returning 'nobody'",
"nis_getprincipal: flavor = GSS: returning '%s'",
"nis_getprincipal: flavor = %d(unknown): returning '%s'",
"nis_getprincipal: calling list with name '%s' and type '%s'",
"nis_getprincipal: calling list with uid (LOCAL) '%d'",
"nis_getprincipal: error doing nis_list: %s",
"nis_getprincipal: buffer overflow, returning '%s'",
nobody);
"nis_getprincipal: caching '%s'/'%s'",
"nis_getprincipal: flavor = %s: returning : '%s'",
* This function returns true if the given principal has the right to * do the requested function on the given object. It could be a define * if that would save time. At the moment it is a function. * NOTE: It recursively calls NIS by doing the lookup on the group if * the conditional gets that far. * N.B. If the principal passed is 'null' then we're recursing and don't * need to check it. (we always let ourselves look at the data) unsigned long right;
/* The Access right we desire */ int size;
/* Size in bytes of the buffer */ int size;
/* Size in bytes of the buffer */ * get an array of entry columns int n;
/* required array size */ * get an array of table columns int n;
/* required array size */ * get an array of nis attributes int n;
/* required array size */ * Stability functions. These functions check to see if a transaction * has been propogated to all replicas. * This function checks to see if an update has been propogated to all * of the replicates for the given domain. If so, the log code will be * free to delete it, otherwise we will continue to hold it until the * replicate picks up the change. If we can't figure out if it is stable * or not we return 0 and hold onto it. * get object for the domain, if this is the first time we're * "visitin" this domain then get a fresh copy (NO_CACHE) * If we aren't the master any more, or the directory doesn't exist * anymore we can toss this update. * If we encountered a problem trying to get the directory object * we hold on to the update. * If we look at the object and there is only one server then * the update has by definition propogated. * Otherwise we go ahead and check to see if it is stable. * In the single-threaded case, the find_item will always work * if the __directory_object() call worked. Not necessarily true * in MT case, where other threads may do work in between * __directory_object() and nis_find_item(). /* Fetch the time from the replica */ * This function will put "fenceposts" into the log for each directory we * serve. This makes the "lastupdate()" function faster and is essential * for directories that have been stable long enough that there are no * This function applies a log entry that we've received from the master * for a given domain to the log and the database. msg =
"Failed to add object ";
msg =
"Failed to modify object ";
msg =
"Failed to remove object ";
/* For old modified objects, just add this to the log */ msg =
"Failed to add entry ";
msg =
"Failed to remove entry ";
/* ignore these as they are both NOPs */ msg =
"Illegal transaction type on ";
* This function will restores a directory to "virgin" status. This is * accomplished by deleting any databases (tables) that are contained in * that directory, then destroying and recreating the database for the if (n <
1 || n >
sizeof (
namebuf)) {
"clear_directory: buffer (%d) insufficient for \"%s.%s\" (%d)",
"clear_directory: Could not destroy table \"%s\": %s.",
/* Not a table, so just remove the object */ "clear_directory: Could not remove object \"%s\": %s",
"clear_directory: could not get object list for \"%s\": %s",
* else (tables->status == NIS_NOTFOUND), which is fine by us; * someone already did our work. "Could not destroy table %s: %s.",
/* Make a clean version. */ "Could not create table %s: %s.",
* This function prints out a nice name for a objects. for (i = 0; i <
ncols; i++) {
* During full resyncs, repl_objs caches the table objects, so that * we don't have to look them up every time we add an entry to /* This is the callback for nis_dump (Full Resyncs) */ * Once entered this if block returns to the caller. /* Build a fully specified name from the entry */ "update_directory: out of memory resync aborted.");
for (i = 0,
na = 0; i <
mc; i++) {
"update_directory : %d objects, still running.",
"replica_update (update_directory): adding %s returned %s",
"replica_update (update_directory): adding entry to %s returned %s",
* At this point it isn't an ENTRY object so we're not adding * xxx sometimes clear_directory doesn't successfully * clear out tables (bug), this tries again before * giving up on the table object. * Make sure the directory exists, if it doesn't then we've * missed a create somewhere or we were just added as a replica "verify_table_exists: cannot create table for %s:%s.",
"verify_table_exists: unexpected database error for %s: %s.",
* Update root object (creating it if not there before) or remove root object * depending on whether we're still listed as a root replica. * Affects root_server flag. * Returns 1 if successful; 0 otherwise. char *
myself =
"root_replica_update";
/* If we're reading the root dir from LDAP, do nothing */ #
endif /* NIS_LDAP_DEBUG */ "%s: Mapping root dir object from LDAP",
myself);
"root_replica_update: update failed '%s': could not fetch object from master.",
return (0);
/* failed, try again later. */ "root_replica_update: updating '%s'",
return (0);
/* failed, try again later. */ "root_replica_update: removing '%s'",
* Return 1 if all objects in the directory 'dirname' are read mapped * from LDAP, 0 otherwise. For table objects, the definition of "all * objects" includes the table object itself, as well as entried in * Most of the code to retrieve a directory listing and traverse same * was borrowed from clear_directory(). #
endif /* NIS_LDAP_DEBUG */ "%s: Unable to get directory list for \"%s\": %s",
if (n <
1 || n >
sizeof (
namebuf)) {
#
endif /* NIS_LDAP_DEBUG */ "%s: Buffer size (%d) insufficient for \"%s.%s\" (need %d)",
#
endif /* NIS_LDAP_DEBUG */ "%s: No read mapping for obj \"%s\"",
#
endif /* NIS_LDAP_DEBUG */ "%s: No read mapping for entries in \"%s\"",
* Returns 1 if the log_entry:s 'l1' and 'l2' pertain to the same * entry object, 0 otherwise. * Since this function works on log entries alone, it may not * correctly handle cases where different attribute selector lists * resolve to the same entry. For example, it's quite possible that * '[key1=abc]tab.org_dir' and '[key2=def]tab.org_dir' unambiguously * specify the same entry, but we wouldn't know without looking * in the DB (and even that wouldn't work if one of the operations * is an ADD, in which case the entry migh tnot exist yet). /* Must both be entry objects */ /* Same number of entry selector attributes */ * Check the selector attribute names/values. For simplicity, * we require that they're in the same order. /* define buffer size for ctime_r() */ * This function is used by the replicas to keep themselves up to date * with the master server. When called, it iteratively removes the names * of directories that have changed from it's list. * Note: replica_update() is called either from main() before we go MT, * of from check_updaters() with an exclusive lock on the 'upd_list'. * Thus, there's no need to enforce exclusion in replica_update() /* timestamp used to write back into log when full resync is done */ /* If a full dump fails, is it unsafe to return (i.e., try again) ? */ char *
myself =
"replica_update";
/* check to see if we're replicating the root object */ "host %s thinks that it is the replica for %s, but it is the master!",
return (0);
/* failed, try again later. */ * If every object in the directory, including table entries, are * mapped from LDAP, we just get the update time from the master, * and write an UPDATE time stamp to trans.log. "%s: All objects in \"%s\" mapped from LDAP; " "setting update time to %s",
"%s: Unable to get update time for \"%s\" from \"%s\"",
/* Fall through to normal resync */ * We now intend do things that might want to update the trans.log. * While the actual transactions are protected by begin_transaction()/ * end_transaction(), we don't want to have some other thread changing * the trans.log under our feet from this point on, so we acquire * a write lock on the trans.log. * If ttime is non-zero, then get the delta from the master using * If ttime is zero, then go directly to the full resync section. * There is no need to even try to get the delta from the master. /* get the delta from transaction log */ "replica_update: dumping master's log.\n");
"replica_update: Couldn't contact '%s' serving '%s' for an update.",
"replica_update: master server is busy, will try later.");
"replica_update: %d updates from '%s'",
"replica_update: %d updates from '%s'\n",
"replica_update: master server returned NIS_SUCCESS, but 0 updates!");
* If there are objects in the directory that are mapped * from LDAP, we intend to skip those during the resync. * This means that the time stamp of the last update in * trans.log after the resync isn't necessarily the same * as the last update known to the master. Hence, we * save the latter in 'xttime'. /* invalidate this directory in case of crash */ "%s: Temporarily setting update time for " "replica_update: offline DB error %d for \"%s\"",
for (i = 0; i <
nument; i++) {
* Is the object mapped from LDAP ? If so, * skip the update, but consider the * application of the change a success. /* Fall through to entry obj */ #
endif /* NIS_LDAP_DEBUG */ "%s: skipping LDAP-mapped entry for \"%s\"",
* If the current operation is an entry * removal, and the next one is an add * of the same entry, tell the DB that * we're in a modify, so that it can * If we had informed the DB that this was * part of a modify, and we've done the * add (or the log update failed), turn * off the modify indicaton. "Failed to apply update.\n");
"replica_update: Unable to apply update.");
"Add update #%d to trans.log\n", i+
1);
"Added update to trans.log.\n");
"Successfully updated.\n");
"replica_update: online DB error %d for \"%s\"",
* This should never happen, otherwise * this can force the replica to go "replica_update: WARNING: last_update(%s) returned 0!",
* If we skipped updates because the object * was mapped from LDAP, 'ttime' may not be * valid, so we use the time from the master * that we saved in 'xttime'. "%s: Setting update time for \"%s\" to %s",
"replica_update: online DB error %d for \"%s\"",
"replica_update: nis_dumplog failed: srv='%s', dir='%s', err='%s'",
"replica_update: nis_dumplog failed: srv='%s', dir='%s', err='%s'\n",
}
/* end of delta update */ * Our log and the masters are sufficently out of date that we * need to completely resync. fprintf(
cons,
"replica_update: Full dump required.\n");
* The following code handles full dump (resync) from the * master. Full dump only happens if the local timestamp * returned from last_update(): * 2) cannot be found in on the master. "replica_update: offline DB error %d for \"%s\"",
/* Haven't actually done anything, so return failure */ /* clear_directory(name); */ /* we might serve stale data */ * Note we *don't* transact this because if we fail we'll simply * restart from the beginning. However, we hang on to the trans.log * lock in order to prevent other threads from performing updates. * The case where all objects in the directory were mapped from LDAP * was already handled above. If we get here, it may be that _some_ * of the objects are mapped from LDAP, but we also know that we're * out-of-sync with the master for at least one object. * The usual reason that we get to this point is that this is a * newly created replica, and we'd probably like to build up its * disk database ASAP. For this reason, and in the interest of * simplicity (don't want to make libnsl, where nis_dump() lives, * aware of LDAP mapping), we let the full dump get everything * from the master, whether or not it's mapped from LDAP. * Free up the cache of table objects * If lres indicates success, mark the error, * but continue so that repl_objs will be * cleaned up. The status in lres will "replica_update: master server busy, rescheduling the resync.");
"%s: Setting update time for \"%s\" to 0x%lx",
* Note, we are not addressing the case when several replicas * are initialized simultaneously i.e several nismkdir -s * are executed before a nisping. "replica_update: online DB error %d for \"%s\"",
"replica_update: trying a full resync again");
* Returning zero makes sure that this directory is not * deleted from the upd_list. We'll try again after our "%s: Setting update time for \"%s\" to 0x%lx",
* Put back online, since the directory would not have been "replica_update: online DB error %d for \"%s\"",
"replica_update: trying a full resync again");
return (0);
/* don't delete from upd_list */ "%s: nis_dump failed: srv='%s', dir='%s', " "%s: Setting update time for \"%s\" to 0x%lx",
* Put back online, nothing more we can do "replica_update: online DB error %d for \"%s\"",
return (
1);
/* do delete from upd_list */ "replica_update: nis_dump failed: srv='%s', dir='%s', err='%s'",
"%s: Setting update time for \"%s\" to 0x%lx",
"replica_update: online DB error %d for \"%s\"",
* Wait before retrying, abort dump if we've used up the * allowed number of attempts. However, if rollback failed, * we disregard 'dumpRetry.attempts' and always continue * trying (since the data may not only be stale, but * inconsistent or corrupted). "replica_update: Used %d dump attempts for \"%s\", serving stale data",
"replica_update: offline DB error %d for \"%s\"",
"replica_update: errors during resync : srv='%s', dir='%s'",
"%s: Setting update time for \"%s\" to 0x%lx",
"replica_update: online DB error %d for \"%s\"",
* Wait before retrying, abort dump if we've used up the * allowed number of attempts. However, if rollback failed, * we disregard 'dumpRetry.attempts' and always continue * trying (since the data may not only be stale, but * inconsistent or corrupted). "replica_update: Used %d dump attempts for \"%s\", serving stale data",
"replica_update: offline DB error %d for \"%s\"",
* Mark the now resync'd directory as stable. * This is done by comparing the latest timestamp of * all the objects we've seen with the latest timestamp * from the master. This is required because the master * stamps "remove" operations but they won't show up "replica_update: downrev version of NIS+ service serving dir %s as master.",
"replica_update: directory %s updated",
name);
/* Add it to the list of directories that it serves */ "replica_update: online DB error %d for \"%s\"",
* The full resync is now complete. We need to put the * current timestamp for the directory in the local * NOTE: variable "xttime" contains the valid timestamp * for the directory. It should never be 0. However, * if we do get this, we'll have to assume that there * were some problem and we should force another resync. * Always stamp with valid timestamp. * We only stamp with timestamp of 0 if there * isn't already a timestamp of 0 in the "%s: Setting update time for \"%s\" after " "replica_update: timestamp=0 after full resync completed!");
* This function will send a "ping" to the replicas for a given directory * indicating that they should be ready to get updates to the database. * It creates a thread to send the ping. * NOTE: The main thread destroys the ping_item "pung" when * ping_replicas() returns. To avoid problems, the * ping_item is first cloned. The cloned ping_item * must be destroyed in the thread. * Once the thr_create is successful the operation is presumed to complete. "ping_replicas: Error (%d) zeroing mask for %s",
"ping_replicas: Error (%d) setting mask for %s",
"ping_replicas: Error (%d) restoring mask for %s",
"ping_replicas: Error (%d) creating ping thread for %s",
"ping_replicas: Created ping thread %d for %s",
* Recursion Safe versions of the lookup internals. * These functions are the internal functions that are used by the * lookup and list functions in the library. When the server is linked * against libnsl, these functions replace those in the library and make * it safe for use to call nis_lookup() or nis_list(). * Lookup the requested information by calling the services listsvc or * lookup_svc entry points. void *
cbdata;
/* Callback data */ int (*
cback)();
/* Callback (for list calls) */ * Depending on name or list_op either * list it or look it up in the namespace. /* sanity check on object name */ "nis_local_lookup: bad name '%s'",
* Now duplicate the result for the client so that the * client can call nis_freeresult() with impunity. * return TRUE if an RPC call to this directory might call us * XXX NB: if the server name doesn't match but the * address does, then we'll miss this check and recurse * The bones of the lookup and list function, this function binds to, then * calls the appropriate NIS+ server for the given name. If the HARD_LOOKUP * flag is set it is ignored because the server cannot afford to block. * NB: This function now follows links if flags is set up correctly. THis * localized this policy to this function and eliminated about 4 * implementations of the same code in other modules. void *
cbdata;
/* Callback data */ int (*
cback)();
/* Callback (for list calls) */ * AS THE SERVICE, we don't support callbacks * special handling for root replicas. * If the following conditions are met : * 1) the directory we're going to query == our domain name * 2) we allegedly serve it. * 3) we don't have the "root_server" flag set * Then we are a root_replica and we need to shunt this * request to the master root server who will read the * root object and return it to us. * As a server, we may serve the indicated directory, if we * do then we *DON'T* do an RPC, rather we just call our * selves. Note this *can* recurse. * We supposedly serve the directory, but we don't * have a database for it (or the table), yet. * Try the master for now, until we get the * directory back in sync. Of course, we shouldn't * do this if we are the master. * This function will ask one of the servers of the given directory * where some unknown directory "name" is. This function is called * from within the __nis_CacheBind() code so is generally not needed by * the client. If the directory cannot be found it returns NULL. * special case the root replica servers. ns =
1;
/* effectively "master only" */ * If this server is on the list and we have a database for it, * just call the svc routine for (i = 0; i <
ns; i++) {
/* Make sure we've got a database for it. */ * Note, we "clone" the find directory result * because the cache client code will free it. /* _fd_res puts returned obj on rags list */ /* clone fd_result for cache to free */ /* Make an RPC call to locate the directory. */ for (i = 0; i <
nsrv; i++) {
* XXX Maybe this can be cached and updated whenever * update_root_object is called instead of being reread ???