diff options
Diffstat (limited to 'REORG.TODO/nis/nis_lookup.c')
-rw-r--r-- | REORG.TODO/nis/nis_lookup.c | 219 |
1 files changed, 219 insertions, 0 deletions
diff --git a/REORG.TODO/nis/nis_lookup.c b/REORG.TODO/nis/nis_lookup.c new file mode 100644 index 0000000000..f6d84abecd --- /dev/null +++ b/REORG.TODO/nis/nis_lookup.c @@ -0,0 +1,219 @@ +/* Copyright (C) 1997-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Thorsten Kukuk <kukuk@uni-paderborn.de>, 1997. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <string.h> +#include <rpcsvc/nis.h> +#include "nis_xdr.h" +#include "nis_intern.h" +#include <libnsl.h> +#include <shlib-compat.h> + + +nis_result * +nis_lookup (const_nis_name name, const unsigned int flags) +{ + nis_result *res = calloc (1, sizeof (nis_result)); + struct ns_request req; + nis_name *names; + nis_error status; + int link_first_try = 0; + int count_links = 0; /* We will follow only 16 links in the deep */ + int done = 0; + int name_nr = 0; + nis_name namebuf[2] = {NULL, NULL}; + + if (res == NULL) + return NULL; + + if ((flags & EXPAND_NAME) && (name[strlen (name) - 1] != '.')) + { + names = nis_getnames (name); + if (names == NULL) + { + NIS_RES_STATUS (res) = NIS_NAMEUNREACHABLE; + return res; + } + } + else + { + names = namebuf; + names[0] = (nis_name)name; + } + + req.ns_name = names[0]; + while (!done) + { + dir_binding bptr; + directory_obj *dir = NULL; + req.ns_object.ns_object_len = 0; + req.ns_object.ns_object_val = NULL; + + status = __prepare_niscall (req.ns_name, &dir, &bptr, flags); + if (__glibc_unlikely (status != NIS_SUCCESS)) + { + NIS_RES_STATUS (res) = status; + goto out; + } + + do + { + static const struct timeval RPCTIMEOUT = {10, 0}; + enum clnt_stat result; + + again: + result = clnt_call (bptr.clnt, NIS_LOOKUP, + (xdrproc_t) _xdr_ns_request, + (caddr_t) &req, (xdrproc_t) _xdr_nis_result, + (caddr_t) res, RPCTIMEOUT); + + if (result != RPC_SUCCESS) + status = NIS_RPCERROR; + else + { + status = NIS_SUCCESS; + + if (NIS_RES_STATUS (res) == NIS_SUCCESS) + { + if (__type_of (NIS_RES_OBJECT (res)) == NIS_LINK_OBJ + && (flags & FOLLOW_LINKS)) /* We are following links */ + { + /* if we hit the link limit, bail */ + if (count_links > NIS_MAXLINKS) + { + NIS_RES_STATUS (res) = NIS_LINKNAMEERROR; + break; + } + ++count_links; + req.ns_name = + strdupa (NIS_RES_OBJECT (res)->LI_data.li_name); + + /* The following is a non-obvious optimization. A + nis_freeresult call would call xdr_free as the + following code. But it also would unnecessarily + free the result structure. We avoid this here + along with the necessary tests. */ + xdr_free ((xdrproc_t) _xdr_nis_result, (char *) res); + memset (res, '\0', sizeof (*res)); + + link_first_try = 1; /* Try at first the old binding */ + goto again; + } + } + else + if (NIS_RES_STATUS (res) == NIS_SYSTEMERROR + || NIS_RES_STATUS (res) == NIS_NOSUCHNAME + || NIS_RES_STATUS (res) == NIS_NOT_ME) + { + if (link_first_try) + { + __nisbind_destroy (&bptr); + nis_free_directory (dir); + /* Otherwise __nisfind_server will not do anything. */ + dir = NULL; + + if (__nisfind_server (req.ns_name, 1, &dir, &bptr, + flags & ~MASTER_ONLY) + != NIS_SUCCESS) + goto out; + } + else + if (__nisbind_next (&bptr) != NIS_SUCCESS) + { + /* No more servers to search. Try parent. */ + const char *ndomain = __nis_domain_of (req.ns_name); + req.ns_name = strdupa (ndomain); + if (strcmp (req.ns_name, ".") == 0) + { + NIS_RES_STATUS (res) = NIS_NAMEUNREACHABLE; + goto out; + } + + __nisbind_destroy (&bptr); + nis_free_directory (dir); + dir = NULL; + status = __prepare_niscall (req.ns_name, &dir, + &bptr, flags); + if (__glibc_unlikely (status != NIS_SUCCESS)) + { + NIS_RES_STATUS (res) = status; + goto out; + } + goto again; + } + + while (__nisbind_connect (&bptr) != NIS_SUCCESS) + { + if (__nisbind_next (&bptr) != NIS_SUCCESS) + { + nis_free_directory (dir); + goto out; + } + } + goto again; + } + break; + } + link_first_try = 0; /* Set it back */ + } + while ((flags & HARD_LOOKUP) && status == NIS_RPCERROR); + + __nisbind_destroy (&bptr); + nis_free_directory (dir); + + if (status != NIS_SUCCESS) + { + NIS_RES_STATUS (res) = status; + goto out; + } + + switch (NIS_RES_STATUS (res)) + { + case NIS_PARTIAL: + case NIS_SUCCESS: + case NIS_S_SUCCESS: + case NIS_LINKNAMEERROR: /* We follow to max links */ + case NIS_UNAVAIL: /* NIS+ is not installed, or all servers are down */ + ++done; + break; + default: + /* Try the next domainname if we don't follow a link */ + if (count_links) + { + free (req.ns_name); + NIS_RES_STATUS (res) = NIS_LINKNAMEERROR; + ++done; + break; + } + ++name_nr; + if (names[name_nr] == NULL) + { + ++done; + break; + } + req.ns_name = names[name_nr]; + break; + } + } + + out: + if (names != namebuf) + nis_freenames (names); + + return res; +} +libnsl_hidden_nolink_def (nis_lookup, GLIBC_2_1) |