NPTL: Remove gratuitous Linuxisms from gai_misc.h.
[platform/upstream/glibc.git] / nis / nis_lookup.c
1 /* Copyright (C) 1997-2014 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)