| 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) |