xf.li | bdd93d5 | 2023-05-12 07:10:14 -0700 | [diff] [blame^] | 1 | /* Copyright (C) 1997-2016 Free Software Foundation, Inc. |
| 2 | This file is part of the GNU C Library. |
| 3 | Contributed by Thorsten Kukuk <kukuk@uni-paderborn.de>, 1997. |
| 4 | |
| 5 | The GNU C Library is free software; you can redistribute it and/or |
| 6 | modify it under the terms of the GNU Lesser General Public |
| 7 | License as published by the Free Software Foundation; either |
| 8 | version 2.1 of the License, or (at your option) any later version. |
| 9 | |
| 10 | The GNU C Library is distributed in the hope that it will be useful, |
| 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| 13 | Lesser General Public License for more details. |
| 14 | |
| 15 | You should have received a copy of the GNU Lesser General Public |
| 16 | License along with the GNU C Library; if not, see |
| 17 | <http://www.gnu.org/licenses/>. */ |
| 18 | |
| 19 | #include <string.h> |
| 20 | #include <rpcsvc/nis.h> |
| 21 | #include "nis_xdr.h" |
| 22 | #include "nis_intern.h" |
| 23 | #include <libnsl.h> |
| 24 | |
| 25 | |
| 26 | nis_result * |
| 27 | nis_lookup (const_nis_name name, const unsigned int flags) |
| 28 | { |
| 29 | nis_result *res = calloc (1, sizeof (nis_result)); |
| 30 | struct ns_request req; |
| 31 | nis_name *names; |
| 32 | nis_error status; |
| 33 | int link_first_try = 0; |
| 34 | int count_links = 0; /* We will follow only 16 links in the deep */ |
| 35 | int done = 0; |
| 36 | int name_nr = 0; |
| 37 | nis_name namebuf[2] = {NULL, NULL}; |
| 38 | |
| 39 | if (res == NULL) |
| 40 | return NULL; |
| 41 | |
| 42 | if ((flags & EXPAND_NAME) && (name[strlen (name) - 1] != '.')) |
| 43 | { |
| 44 | names = nis_getnames (name); |
| 45 | if (names == NULL) |
| 46 | { |
| 47 | NIS_RES_STATUS (res) = NIS_NAMEUNREACHABLE; |
| 48 | return res; |
| 49 | } |
| 50 | } |
| 51 | else |
| 52 | { |
| 53 | names = namebuf; |
| 54 | names[0] = (nis_name)name; |
| 55 | } |
| 56 | |
| 57 | req.ns_name = names[0]; |
| 58 | while (!done) |
| 59 | { |
| 60 | dir_binding bptr; |
| 61 | directory_obj *dir = NULL; |
| 62 | req.ns_object.ns_object_len = 0; |
| 63 | req.ns_object.ns_object_val = NULL; |
| 64 | |
| 65 | status = __prepare_niscall (req.ns_name, &dir, &bptr, flags); |
| 66 | if (__glibc_unlikely (status != NIS_SUCCESS)) |
| 67 | { |
| 68 | NIS_RES_STATUS (res) = status; |
| 69 | goto out; |
| 70 | } |
| 71 | |
| 72 | do |
| 73 | { |
| 74 | static const struct timeval RPCTIMEOUT = {10, 0}; |
| 75 | enum clnt_stat result; |
| 76 | |
| 77 | again: |
| 78 | result = clnt_call (bptr.clnt, NIS_LOOKUP, |
| 79 | (xdrproc_t) _xdr_ns_request, |
| 80 | (caddr_t) &req, (xdrproc_t) _xdr_nis_result, |
| 81 | (caddr_t) res, RPCTIMEOUT); |
| 82 | |
| 83 | if (result != RPC_SUCCESS) |
| 84 | status = NIS_RPCERROR; |
| 85 | else |
| 86 | { |
| 87 | status = NIS_SUCCESS; |
| 88 | |
| 89 | if (NIS_RES_STATUS (res) == NIS_SUCCESS) |
| 90 | { |
| 91 | if (__type_of (NIS_RES_OBJECT (res)) == NIS_LINK_OBJ |
| 92 | && (flags & FOLLOW_LINKS)) /* We are following links */ |
| 93 | { |
| 94 | /* if we hit the link limit, bail */ |
| 95 | if (count_links > NIS_MAXLINKS) |
| 96 | { |
| 97 | NIS_RES_STATUS (res) = NIS_LINKNAMEERROR; |
| 98 | break; |
| 99 | } |
| 100 | ++count_links; |
| 101 | req.ns_name = |
| 102 | strdupa (NIS_RES_OBJECT (res)->LI_data.li_name); |
| 103 | |
| 104 | /* The following is a non-obvious optimization. A |
| 105 | nis_freeresult call would call xdr_free as the |
| 106 | following code. But it also would unnecessarily |
| 107 | free the result structure. We avoid this here |
| 108 | along with the necessary tests. */ |
| 109 | xdr_free ((xdrproc_t) _xdr_nis_result, (char *) res); |
| 110 | memset (res, '\0', sizeof (*res)); |
| 111 | |
| 112 | link_first_try = 1; /* Try at first the old binding */ |
| 113 | goto again; |
| 114 | } |
| 115 | } |
| 116 | else |
| 117 | if (NIS_RES_STATUS (res) == NIS_SYSTEMERROR |
| 118 | || NIS_RES_STATUS (res) == NIS_NOSUCHNAME |
| 119 | || NIS_RES_STATUS (res) == NIS_NOT_ME) |
| 120 | { |
| 121 | if (link_first_try) |
| 122 | { |
| 123 | __nisbind_destroy (&bptr); |
| 124 | nis_free_directory (dir); |
| 125 | /* Otherwise __nisfind_server will not do anything. */ |
| 126 | dir = NULL; |
| 127 | |
| 128 | if (__nisfind_server (req.ns_name, 1, &dir, &bptr, |
| 129 | flags & ~MASTER_ONLY) |
| 130 | != NIS_SUCCESS) |
| 131 | goto out; |
| 132 | } |
| 133 | else |
| 134 | if (__nisbind_next (&bptr) != NIS_SUCCESS) |
| 135 | { |
| 136 | /* No more servers to search. Try parent. */ |
| 137 | const char *ndomain = __nis_domain_of (req.ns_name); |
| 138 | req.ns_name = strdupa (ndomain); |
| 139 | if (strcmp (req.ns_name, ".") == 0) |
| 140 | { |
| 141 | NIS_RES_STATUS (res) = NIS_NAMEUNREACHABLE; |
| 142 | goto out; |
| 143 | } |
| 144 | |
| 145 | __nisbind_destroy (&bptr); |
| 146 | nis_free_directory (dir); |
| 147 | dir = NULL; |
| 148 | status = __prepare_niscall (req.ns_name, &dir, |
| 149 | &bptr, flags); |
| 150 | if (__glibc_unlikely (status != NIS_SUCCESS)) |
| 151 | { |
| 152 | NIS_RES_STATUS (res) = status; |
| 153 | goto out; |
| 154 | } |
| 155 | goto again; |
| 156 | } |
| 157 | |
| 158 | while (__nisbind_connect (&bptr) != NIS_SUCCESS) |
| 159 | { |
| 160 | if (__nisbind_next (&bptr) != NIS_SUCCESS) |
| 161 | { |
| 162 | nis_free_directory (dir); |
| 163 | goto out; |
| 164 | } |
| 165 | } |
| 166 | goto again; |
| 167 | } |
| 168 | break; |
| 169 | } |
| 170 | link_first_try = 0; /* Set it back */ |
| 171 | } |
| 172 | while ((flags & HARD_LOOKUP) && status == NIS_RPCERROR); |
| 173 | |
| 174 | __nisbind_destroy (&bptr); |
| 175 | nis_free_directory (dir); |
| 176 | |
| 177 | if (status != NIS_SUCCESS) |
| 178 | { |
| 179 | NIS_RES_STATUS (res) = status; |
| 180 | goto out; |
| 181 | } |
| 182 | |
| 183 | switch (NIS_RES_STATUS (res)) |
| 184 | { |
| 185 | case NIS_PARTIAL: |
| 186 | case NIS_SUCCESS: |
| 187 | case NIS_S_SUCCESS: |
| 188 | case NIS_LINKNAMEERROR: /* We follow to max links */ |
| 189 | case NIS_UNAVAIL: /* NIS+ is not installed, or all servers are down */ |
| 190 | ++done; |
| 191 | break; |
| 192 | default: |
| 193 | /* Try the next domainname if we don't follow a link */ |
| 194 | if (count_links) |
| 195 | { |
| 196 | free (req.ns_name); |
| 197 | NIS_RES_STATUS (res) = NIS_LINKNAMEERROR; |
| 198 | ++done; |
| 199 | break; |
| 200 | } |
| 201 | ++name_nr; |
| 202 | if (names[name_nr] == NULL) |
| 203 | { |
| 204 | ++done; |
| 205 | break; |
| 206 | } |
| 207 | req.ns_name = names[name_nr]; |
| 208 | break; |
| 209 | } |
| 210 | } |
| 211 | |
| 212 | out: |
| 213 | if (names != namebuf) |
| 214 | nis_freenames (names); |
| 215 | |
| 216 | return res; |
| 217 | } |
| 218 | libnsl_hidden_def (nis_lookup) |