Back to index

glibc  2.9
nis_lookup.c
Go to the documentation of this file.
00001 /* Copyright (C) 1997-1999, 2004, 2005, 2006, 2007
00002    Free Software Foundation, Inc.
00003    This file is part of the GNU C Library.
00004    Contributed by Thorsten Kukuk <kukuk@uni-paderborn.de>, 1997.
00005 
00006    The GNU C Library is free software; you can redistribute it and/or
00007    modify it under the terms of the GNU Lesser General Public
00008    License as published by the Free Software Foundation; either
00009    version 2.1 of the License, or (at your option) any later version.
00010 
00011    The GNU C Library is distributed in the hope that it will be useful,
00012    but WITHOUT ANY WARRANTY; without even the implied warranty of
00013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014    Lesser General Public License for more details.
00015 
00016    You should have received a copy of the GNU Lesser General Public
00017    License along with the GNU C Library; if not, write to the Free
00018    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
00019    02111-1307 USA.  */
00020 
00021 #include <string.h>
00022 #include <rpcsvc/nis.h>
00023 #include "nis_xdr.h"
00024 #include "nis_intern.h"
00025 #include <libnsl.h>
00026 
00027 
00028 nis_result *
00029 nis_lookup (const_nis_name name, const unsigned int flags)
00030 {
00031   nis_result *res = calloc (1, sizeof (nis_result));
00032   struct ns_request req;
00033   nis_name *names;
00034   nis_error status;
00035   int link_first_try = 0;
00036   int count_links = 0;       /* We will follow only 16 links in the deep */
00037   int done = 0;
00038   int name_nr = 0;
00039   nis_name namebuf[2] = {NULL, NULL};
00040 
00041   if (res == NULL)
00042     return NULL;
00043 
00044   if ((flags & EXPAND_NAME) && (name[strlen (name) - 1] != '.'))
00045     {
00046       names = nis_getnames (name);
00047       if (names == NULL)
00048        {
00049          NIS_RES_STATUS (res) = NIS_NAMEUNREACHABLE;
00050          return res;
00051        }
00052     }
00053   else
00054     {
00055       names = namebuf;
00056       names[0] = (nis_name)name;
00057     }
00058 
00059   req.ns_name = names[0];
00060   while (!done)
00061     {
00062       dir_binding bptr;
00063       directory_obj *dir = NULL;
00064       req.ns_object.ns_object_len = 0;
00065       req.ns_object.ns_object_val = NULL;
00066 
00067       status = __prepare_niscall (req.ns_name, &dir, &bptr, flags);
00068       if (__builtin_expect (status != NIS_SUCCESS, 0))
00069        {
00070          NIS_RES_STATUS (res) = status;
00071          goto out;
00072        }
00073 
00074       do
00075        {
00076          static const struct timeval RPCTIMEOUT = {10, 0};
00077          enum clnt_stat result;
00078 
00079        again:
00080          result = clnt_call (bptr.clnt, NIS_LOOKUP,
00081                            (xdrproc_t) _xdr_ns_request,
00082                            (caddr_t) &req, (xdrproc_t) _xdr_nis_result,
00083                            (caddr_t) res, RPCTIMEOUT);
00084 
00085          if (result != RPC_SUCCESS)
00086            status = NIS_RPCERROR;
00087          else
00088            {
00089              status = NIS_SUCCESS;
00090 
00091              if (NIS_RES_STATUS (res) == NIS_SUCCESS)
00092               {
00093                   if (__type_of (NIS_RES_OBJECT (res)) == NIS_LINK_OBJ
00094                      && (flags & FOLLOW_LINKS)) /* We are following links */
00095                     {
00096                      /* if we hit the link limit, bail */
00097                      if (count_links > NIS_MAXLINKS)
00098                        {
00099                          NIS_RES_STATUS (res) = NIS_LINKNAMEERROR;
00100                          break;
00101                        }
00102                      ++count_links;
00103                      req.ns_name =
00104                        strdupa (NIS_RES_OBJECT (res)->LI_data.li_name);
00105 
00106                      /* The following is a non-obvious optimization.  A
00107                         nis_freeresult call would call xdr_free as the
00108                         following code.  But it also would unnecessarily
00109                         free the result structure.  We avoid this here
00110                         along with the necessary tests.  */
00111                      xdr_free ((xdrproc_t) _xdr_nis_result, (char *) res);
00112                      memset (res, '\0', sizeof (*res));
00113 
00114                      link_first_try = 1; /* Try at first the old binding */
00115                      goto again;
00116                     }
00117               }
00118              else
00119               if (NIS_RES_STATUS (res) == NIS_SYSTEMERROR
00120                   || NIS_RES_STATUS (res) == NIS_NOSUCHNAME
00121                   || NIS_RES_STATUS (res) == NIS_NOT_ME)
00122                 {
00123                   if (link_first_try)
00124                     {
00125                      __nisbind_destroy (&bptr);
00126                      nis_free_directory (dir);
00127                      /* Otherwise __nisfind_server will not do anything.  */
00128                      dir = NULL;
00129 
00130                      if (__nisfind_server (req.ns_name, 1, &dir, &bptr,
00131                                          flags & ~MASTER_ONLY)
00132                          != NIS_SUCCESS)
00133                        goto out;
00134                     }
00135                   else
00136                     if (__nisbind_next (&bptr) != NIS_SUCCESS)
00137                      {
00138                        /* No more servers to search.  Try parent.  */
00139                        const char *ndomain = __nis_domain_of (req.ns_name);
00140                        req.ns_name = strdupa (ndomain);
00141                        if (strcmp (req.ns_name, ".") == 0)
00142                          {
00143                            NIS_RES_STATUS (res) = NIS_NAMEUNREACHABLE;
00144                            goto out;
00145                          }
00146 
00147                        __nisbind_destroy (&bptr);
00148                        nis_free_directory (dir);
00149                        dir = NULL;
00150                        status = __prepare_niscall (req.ns_name, &dir,
00151                                                 &bptr, flags);
00152                        if (__builtin_expect (status != NIS_SUCCESS, 0))
00153                          {
00154                            NIS_RES_STATUS (res) = status;
00155                            goto out;
00156                          }
00157                        goto again;
00158                      }
00159 
00160                   while (__nisbind_connect (&bptr) != NIS_SUCCESS)
00161                     {
00162                      if (__nisbind_next (&bptr) != NIS_SUCCESS)
00163                        {
00164                          nis_free_directory (dir);
00165                          goto out;
00166                        }
00167                     }
00168                   goto again;
00169                 }
00170              break;
00171            }
00172          link_first_try = 0; /* Set it back */
00173        }
00174       while ((flags & HARD_LOOKUP) && status == NIS_RPCERROR);
00175 
00176       __nisbind_destroy (&bptr);
00177       nis_free_directory (dir);
00178 
00179       if (status != NIS_SUCCESS)
00180        {
00181          NIS_RES_STATUS (res) = status;
00182          goto out;
00183        }
00184 
00185       switch (NIS_RES_STATUS (res))
00186        {
00187        case NIS_PARTIAL:
00188        case NIS_SUCCESS:
00189        case NIS_S_SUCCESS:
00190        case NIS_LINKNAMEERROR: /* We follow to max links */
00191        case NIS_UNAVAIL: /* NIS+ is not installed, or all servers are down */
00192          ++done;
00193          break;
00194        default:
00195          /* Try the next domainname if we don't follow a link */
00196          if (count_links)
00197            {
00198              free (req.ns_name);
00199              NIS_RES_STATUS (res) = NIS_LINKNAMEERROR;
00200              ++done;
00201              break;
00202            }
00203          ++name_nr;
00204          if (names[name_nr] == NULL)
00205            {
00206              ++done;
00207              break;
00208            }
00209          req.ns_name = names[name_nr];
00210          break;
00211        }
00212     }
00213 
00214  out:
00215   if (names != namebuf)
00216     nis_freenames (names);
00217 
00218   return res;
00219 }
00220 libnsl_hidden_def (nis_lookup)