(nis_getnames): Add trailing dot to NIS_PATH components which lack them.
[kopensolaris-gnu/glibc.git] / nis / nis_lookup.c
1 /* Copyright (C) 1997-1999, 2004, 2005, 2006 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, write to the Free
17    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
18    02111-1307 USA.  */
19
20 #include <string.h>
21 #include <rpcsvc/nis.h>
22 #include "nis_xdr.h"
23 #include "nis_intern.h"
24 #include <libnsl.h>
25
26
27 nis_result *
28 nis_lookup (const_nis_name name, const unsigned int flags)
29 {
30   nis_result *res = calloc (1, sizeof (nis_result));
31   struct ns_request req;
32   nis_name *names;
33   nis_error status;
34   int link_first_try = 0;
35   int count_links = 0;   /* We will follow only 16 links in the deep */
36   int done = 0;
37   int name_nr = 0;
38   nis_name namebuf[2] = {NULL, NULL};
39
40   if (res == NULL)
41     return NULL;
42
43   if ((flags & EXPAND_NAME) && (name[strlen (name) - 1] != '.'))
44     {
45       names = nis_getnames (name);
46       if (names == NULL)
47         {
48           NIS_RES_STATUS (res) = NIS_NAMEUNREACHABLE;
49           return res;
50         }
51     }
52   else
53     {
54       names = namebuf;
55       names[0] = (nis_name)name;
56     }
57
58   req.ns_name = names[0];
59   while (!done)
60     {
61       dir_binding bptr;
62       directory_obj *dir = NULL;
63       req.ns_object.ns_object_len = 0;
64       req.ns_object.ns_object_val = NULL;
65
66       status = __prepare_niscall (req.ns_name, &dir, &bptr, flags);
67       if (__builtin_expect (status != NIS_SUCCESS, 0))
68         {
69           NIS_RES_STATUS (res) = status;
70           goto out;
71         }
72
73       do
74         {
75           static const struct timeval RPCTIMEOUT = {10, 0};
76           enum clnt_stat result;
77           char ndomain[strlen (req.ns_name) + 1];
78
79         again:
80           result = clnt_call (bptr.clnt, NIS_LOOKUP,
81                               (xdrproc_t) _xdr_ns_request,
82                               (caddr_t) &req, (xdrproc_t) _xdr_nis_result,
83                               (caddr_t) res, RPCTIMEOUT);
84
85           if (result != RPC_SUCCESS)
86             status = NIS_RPCERROR;
87           else
88             {
89               status = NIS_SUCCESS;
90
91               if (NIS_RES_STATUS (res) == NIS_SUCCESS)
92                 {
93                     if (__type_of (NIS_RES_OBJECT (res)) == NIS_LINK_OBJ
94                         && (flags & FOLLOW_LINKS)) /* We are following links */
95                       {
96                         /* if we hit the link limit, bail */
97                         if (count_links > NIS_MAXLINKS)
98                           {
99                             NIS_RES_STATUS (res) = NIS_LINKNAMEERROR;
100                             break;
101                           }
102                         ++count_links;
103                         req.ns_name =
104                           strdupa (NIS_RES_OBJECT (res)->LI_data.li_name);
105
106                         /* The following is a non-obvious optimization.  A
107                            nis_freeresult call would call xdr_free as the
108                            following code.  But it also would unnecessarily
109                            free the result structure.  We avoid this here
110                            along with the necessary tests.  */
111                         xdr_free ((xdrproc_t) _xdr_nis_result, (char *) res);
112                         memset (res, '\0', sizeof (*res));
113
114                         link_first_try = 1; /* Try at first the old binding */
115                         goto again;
116                       }
117                 }
118               else
119                 if (NIS_RES_STATUS (res) == NIS_SYSTEMERROR
120                     || NIS_RES_STATUS (res) == NIS_NOSUCHNAME
121                     || NIS_RES_STATUS (res) == NIS_NOT_ME)
122                   {
123                     if (link_first_try)
124                       {
125                         __nisbind_destroy (&bptr);
126                         nis_free_directory (dir);
127                         /* Otherwise __nisfind_server will not do anything.  */
128                         dir = NULL;
129
130                         if (__nisfind_server (req.ns_name, 1, &dir)
131                             != NIS_SUCCESS)
132                           goto out;
133
134                         if (__nisbind_create (&bptr,
135                                               dir->do_servers.do_servers_val,
136                                               dir->do_servers.do_servers_len,
137                                               flags) != NIS_SUCCESS)
138                           {
139                             nis_free_directory (dir);
140                             goto out;
141                           }
142                       }
143                     else
144                       if (__nisbind_next (&bptr) != NIS_SUCCESS)
145                         {
146                           /* No more servers to search.  Try parent.  */
147                           nis_domain_of_r (req.ns_name, ndomain,
148                                            sizeof (ndomain));
149                           req.ns_name = strdupa (ndomain);
150                           if (strcmp (ndomain, ".") == 0)
151                             {
152                               NIS_RES_STATUS (res) = NIS_NAMEUNREACHABLE;
153                               goto out;
154                             }
155
156                           __nisbind_destroy (&bptr);
157                           nis_free_directory (dir);
158                           dir = NULL;
159                           status = __prepare_niscall (req.ns_name, &dir,
160                                                       &bptr, flags);
161                           if (__builtin_expect (status != NIS_SUCCESS, 0))
162                             {
163                               NIS_RES_STATUS (res) = status;
164                               goto out;
165                             }
166                           goto again;
167                         }
168
169                     while (__nisbind_connect (&bptr) != NIS_SUCCESS)
170                       {
171                         if (__nisbind_next (&bptr) != NIS_SUCCESS)
172                           {
173                             nis_free_directory (dir);
174                             goto out;
175                           }
176                       }
177                     goto again;
178                   }
179               break;
180             }
181           link_first_try = 0; /* Set it back */
182         }
183       while ((flags & HARD_LOOKUP) && status == NIS_RPCERROR);
184
185       __nisbind_destroy (&bptr);
186       nis_free_directory (dir);
187
188       if (status != NIS_SUCCESS)
189         {
190           NIS_RES_STATUS (res) = status;
191           goto out;
192         }
193
194       switch (NIS_RES_STATUS (res))
195         {
196         case NIS_PARTIAL:
197         case NIS_SUCCESS:
198         case NIS_S_SUCCESS:
199         case NIS_LINKNAMEERROR: /* We follow to max links */
200         case NIS_UNAVAIL: /* NIS+ is not installed, or all servers are down */
201           ++done;
202           break;
203         default:
204           /* Try the next domainname if we don't follow a link */
205           if (count_links)
206             {
207               free (req.ns_name);
208               NIS_RES_STATUS (res) = NIS_LINKNAMEERROR;
209               ++done;
210               break;
211             }
212           ++name_nr;
213           if (names[name_nr] == NULL)
214             {
215               ++done;
216               break;
217             }
218           req.ns_name = names[name_nr];
219           break;
220         }
221     }
222
223  out:
224   if (names != namebuf)
225     nis_freenames (names);
226
227   return res;
228 }
229 libnsl_hidden_def (nis_lookup)