]>
Commit | Line | Data |
---|---|---|
e61abf83 UD |
1 | /* Copyright (C) 1997 Free Software Foundation, Inc. |
2 | This file is part of the GNU C Library. | |
3 | Contributed by Thorsten Kukuk <kukuk@vt.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 Library General Public License as | |
7 | published by the Free Software Foundation; either version 2 of the | |
8 | 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 | Library General Public License for more details. | |
14 | ||
15 | You should have received a copy of the GNU Library General Public | |
16 | License along with the GNU C Library; see the file COPYING.LIB. If not, | |
17 | write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, | |
18 | Boston, MA 02111-1307, USA. */ | |
19 | ||
20 | #include <string.h> | |
21 | #include <rpc/rpc.h> | |
22 | #include <rpc/auth.h> | |
23 | #include <rpcsvc/nis.h> | |
24 | #include <sys/socket.h> | |
25 | #include <netinet/in.h> | |
26 | #include <arpa/inet.h> | |
27 | #include "nis_intern.h" | |
28 | ||
29 | static struct timeval TIMEOUT = {25, 0}; | |
30 | static int const MAXTRIES = 3; | |
31 | ||
32 | static unsigned long | |
33 | inetstr2int (const char *str) | |
34 | { | |
35 | char buffer[strlen (str) + 3]; | |
36 | size_t buflen; | |
37 | size_t i, j; | |
38 | ||
39 | buflen = stpcpy (buffer, str) - buffer; | |
40 | ||
41 | j = 0; | |
42 | for (i = 0; i < buflen; ++i) | |
43 | if (buffer[i] == '.') | |
44 | { | |
45 | ++j; | |
46 | if (j == 4) | |
47 | { | |
48 | buffer[i] = '\0'; | |
49 | break; | |
50 | } | |
51 | } | |
52 | ||
53 | return inet_addr (buffer); | |
54 | } | |
55 | ||
56 | static CLIENT * | |
57 | __nis_dobind (const nis_server *server, u_long flags) | |
58 | { | |
59 | struct sockaddr_in clnt_saddr; | |
60 | int clnt_sock; | |
61 | size_t i; | |
62 | CLIENT *client = NULL; | |
e61abf83 | 63 | |
26dee9c4 UD |
64 | memset (&clnt_saddr, '\0', sizeof clnt_saddr); |
65 | clnt_saddr.sin_family = AF_INET; | |
e61abf83 UD |
66 | for (i = 0; i < server->ep.ep_len; i++) |
67 | { | |
714a562f | 68 | if (strcmp (server->ep.ep_val[i].family, "loopback") == 0) |
e61abf83 UD |
69 | { |
70 | if (server->ep.ep_val[i].uaddr[i] == '-') | |
71 | clnt_saddr.sin_addr.s_addr = htonl (INADDR_LOOPBACK); | |
72 | else | |
714a562f | 73 | if (strcmp (server->ep.ep_val[i].proto, "udp") == 0) |
e61abf83 UD |
74 | { |
75 | if ((flags & USE_DGRAM) == USE_DGRAM) | |
76 | clnt_saddr.sin_addr.s_addr = htonl (INADDR_LOOPBACK); | |
77 | else | |
78 | continue; | |
79 | } | |
26dee9c4 | 80 | else |
714a562f | 81 | if (strcmp (server->ep.ep_val[i].proto, "tcp") == 0) |
26dee9c4 UD |
82 | { |
83 | if ((flags & USE_DGRAM) == USE_DGRAM) | |
84 | continue; | |
85 | else | |
86 | clnt_saddr.sin_addr.s_addr = htonl (INADDR_LOOPBACK); | |
87 | } | |
e61abf83 UD |
88 | } |
89 | else | |
714a562f | 90 | if (strcmp (server->ep.ep_val[i].family, "inet") == 0) |
e61abf83 UD |
91 | { |
92 | if (server->ep.ep_val[i].uaddr[i] == '-') | |
93 | clnt_saddr.sin_addr.s_addr = | |
94 | inetstr2int (server->ep.ep_val[i].uaddr); | |
95 | else | |
714a562f | 96 | if (strcmp (server->ep.ep_val[i].proto, "udp") == 0) |
e61abf83 UD |
97 | { |
98 | if ((flags & USE_DGRAM) == USE_DGRAM) | |
99 | clnt_saddr.sin_addr.s_addr = | |
100 | inetstr2int (server->ep.ep_val[i].uaddr); | |
101 | else | |
102 | continue; | |
103 | } | |
104 | else | |
714a562f | 105 | if (strcmp (server->ep.ep_val[i].proto, "tcp") == 0) |
e61abf83 UD |
106 | { |
107 | if ((flags & USE_DGRAM) == USE_DGRAM) | |
108 | continue; | |
109 | else | |
110 | clnt_saddr.sin_addr.s_addr = | |
111 | inetstr2int (server->ep.ep_val[i].uaddr); | |
112 | } | |
113 | } | |
114 | else | |
115 | continue; | |
7799b7b3 | 116 | |
e61abf83 UD |
117 | clnt_sock = RPC_ANYSOCK; |
118 | if ((flags & USE_DGRAM) == USE_DGRAM) | |
119 | client = clntudp_create (&clnt_saddr, NIS_PROG, NIS_VERSION, | |
120 | TIMEOUT, &clnt_sock); | |
121 | else | |
122 | client = clnttcp_create (&clnt_saddr, NIS_PROG, NIS_VERSION, | |
123 | &clnt_sock, 0, 0); | |
7799b7b3 | 124 | |
e61abf83 UD |
125 | if (client == NULL) |
126 | continue; | |
e61abf83 | 127 | if (clnt_call (client, 0, (xdrproc_t) xdr_void, NULL, |
26dee9c4 | 128 | (xdrproc_t) xdr_void, NULL, TIMEOUT) != RPC_SUCCESS) |
e61abf83 UD |
129 | { |
130 | clnt_destroy (client); | |
131 | continue; | |
132 | } | |
26dee9c4 | 133 | |
e61abf83 | 134 | if ((flags & NO_AUTHINFO) != NO_AUTHINFO) |
26dee9c4 UD |
135 | { |
136 | #if defined(HAVE_SECURE_RPC) | |
51702635 | 137 | if (server->key_type == NIS_PK_DH && getenv ("NO_SECURE_RPC") == NULL) |
26dee9c4 UD |
138 | { |
139 | char netname[MAXNETNAMELEN+1]; | |
140 | char *p; | |
7799b7b3 | 141 | |
26dee9c4 UD |
142 | p = stpcpy (netname, "unix."); |
143 | strncpy (p, server->name,MAXNETNAMELEN-5); | |
144 | netname[MAXNETNAMELEN] = '\0'; | |
145 | p = strchr (netname, '.'); | |
146 | *p = '@'; | |
147 | client->cl_auth = | |
148 | authdes_pk_create (netname, &server->pkey, 300, NULL, NULL); | |
149 | if (!client->cl_auth) | |
150 | client->cl_auth = authunix_create_default (); | |
151 | } | |
152 | else | |
e61abf83 | 153 | #endif |
26dee9c4 UD |
154 | client->cl_auth = authunix_create_default (); |
155 | } | |
e61abf83 UD |
156 | return client; |
157 | } | |
7799b7b3 | 158 | |
e61abf83 UD |
159 | return NULL; |
160 | } | |
161 | ||
162 | nis_error | |
43b0e40f UD |
163 | __do_niscall2 (const nis_server *server, u_int server_len, u_long prog, |
164 | xdrproc_t xargs, caddr_t req, xdrproc_t xres, caddr_t resp, | |
165 | u_long flags) | |
e61abf83 UD |
166 | { |
167 | CLIENT *clnt; | |
7799b7b3 | 168 | int try, result; |
e61abf83 | 169 | |
43b0e40f UD |
170 | try = 0; |
171 | result = NIS_NAMEUNREACHABLE; | |
e61abf83 | 172 | |
26dee9c4 UD |
173 | if (((flags & MASTER_ONLY) == MASTER_ONLY) && server_len > 1) |
174 | server_len = 1; /* The first entry is the master */ | |
175 | ||
e61abf83 UD |
176 | while (try < MAXTRIES && result != RPC_SUCCESS) |
177 | { | |
178 | unsigned int i; | |
7799b7b3 | 179 | |
26dee9c4 UD |
180 | if ((flags & HARD_LOOKUP) == 0) |
181 | ++try; | |
7799b7b3 | 182 | |
e61abf83 UD |
183 | for (i = 0; i < server_len; i++) |
184 | { | |
185 | if ((clnt = __nis_dobind (&server[i], flags)) == NULL) | |
186 | continue; | |
187 | ||
188 | result = clnt_call (clnt, prog, xargs, req, xres, resp, TIMEOUT); | |
189 | ||
190 | if (result != RPC_SUCCESS) | |
191 | { | |
26dee9c4 | 192 | clnt_perror (clnt, "do_niscall: clnt_call"); |
e61abf83 UD |
193 | clnt_destroy (clnt); |
194 | result = NIS_RPCERROR; | |
195 | } | |
196 | else | |
197 | clnt_destroy (clnt); | |
198 | } | |
199 | } | |
200 | ||
43b0e40f UD |
201 | return result; |
202 | } | |
203 | ||
204 | static directory_obj * | |
205 | dir_lookup (const_nis_name name, nis_server *serv, u_long flags) | |
206 | { | |
207 | CLIENT *clnt; | |
208 | int try, result; | |
209 | nis_result *res; | |
210 | struct ns_request req; | |
211 | directory_obj *dir; | |
212 | ||
213 | res = calloc (1, sizeof (nis_result)); | |
214 | req.ns_name = (char *)name; | |
215 | req.ns_object.ns_object_len = 0; | |
216 | req.ns_object.ns_object_val = NULL; | |
217 | try = 0; | |
218 | result = NIS_NAMEUNREACHABLE; | |
219 | ||
220 | while (try < MAXTRIES && result != RPC_SUCCESS) | |
221 | { | |
222 | if ((clnt = __nis_dobind (serv, flags)) == NULL) | |
223 | continue; | |
224 | ||
225 | result = clnt_call (clnt, NIS_LOOKUP, (xdrproc_t) xdr_ns_request, | |
226 | (caddr_t) &req, (xdrproc_t) xdr_nis_result, | |
227 | (caddr_t) res, TIMEOUT); | |
228 | ||
229 | if (result != RPC_SUCCESS) | |
230 | { | |
231 | clnt_perror (clnt, "do_niscall: clnt_call"); | |
232 | clnt_destroy (clnt); | |
233 | result = NIS_RPCERROR; | |
234 | } | |
235 | else | |
236 | clnt_destroy (clnt); | |
237 | } | |
238 | if (result != RPC_SUCCESS || res->status != NIS_SUCCESS) | |
239 | return NULL; | |
240 | ||
241 | dir = nis_clone_directory (&res->objects.objects_val->DI_data, NULL); | |
242 | nis_freeresult (res); | |
243 | ||
244 | return dir; | |
245 | } | |
246 | ||
247 | static directory_obj * | |
248 | rec_dirsearch (const_nis_name name, directory_obj *dir, u_long flags) | |
249 | { | |
250 | char domain [strlen (name) + 3]; | |
251 | ||
252 | nis_domain_of_r (name, domain, sizeof (domain)); | |
253 | if (strncmp (domain, "org_dir.", 8) == 0) | |
254 | { | |
255 | char tmp[strlen (name) + 3]; | |
256 | ||
257 | nis_domain_of_r (domain, tmp, sizeof (tmp)); | |
258 | strcpy (domain, tmp); | |
259 | } | |
260 | else | |
261 | if (strncmp (domain, "groups_dir.", 11) == 0) | |
262 | { | |
263 | char tmp[strlen (name) + 3]; | |
264 | ||
265 | nis_domain_of_r (domain, tmp, sizeof (tmp)); | |
266 | strcpy (domain, tmp); | |
267 | } | |
268 | else | |
269 | { | |
270 | /* We have no grous_dir or org_dir, so try the complete name */ | |
271 | strcpy (domain, name); | |
272 | } | |
273 | ||
274 | switch (nis_dir_cmp (domain, dir->do_name)) | |
275 | { | |
276 | case SAME_NAME: | |
277 | return dir; | |
278 | case NOT_SEQUENTIAL: | |
279 | /* NOT_SEQUENTIAL means, go one up and try it there ! */ | |
280 | case HIGHER_NAME: | |
281 | { /* We need data from a parent domain */ | |
282 | directory_obj *obj; | |
283 | char ndomain [strlen (name) + 3]; | |
284 | ||
285 | nis_domain_of_r (dir->do_name, ndomain, sizeof (ndomain)); | |
286 | ||
287 | /* The root server of our domain is a replica of the parent | |
288 | domain ! (Now I understand why a root server must be a | |
289 | replica of the parent domain) */ | |
290 | obj = dir_lookup (ndomain, dir->do_servers.do_servers_val, | |
291 | flags); | |
292 | if (obj != NULL) | |
293 | { | |
294 | /* We have found a NIS+ server serving ndomain, now | |
295 | let us search for "name" */ | |
296 | nis_free_directory (dir); | |
297 | return rec_dirsearch (name, obj, flags); | |
298 | } | |
299 | else | |
300 | { | |
301 | /* Ups, very bad. Are we already the root server ? */ | |
302 | nis_free_directory (dir); | |
303 | return NULL; | |
304 | } | |
305 | } | |
306 | break; | |
307 | case LOWER_NAME: | |
308 | { | |
309 | directory_obj *obj; | |
310 | char leaf [strlen (name) + 3]; | |
311 | char ndomain [strlen (name) + 3]; | |
312 | u_int i; | |
714a562f | 313 | char *cp; |
43b0e40f UD |
314 | |
315 | do | |
316 | { | |
317 | if (strlen (domain) == 0) | |
318 | { | |
319 | nis_free_directory (dir); | |
320 | return NULL; | |
321 | } | |
322 | nis_leaf_of_r (domain, leaf, sizeof (leaf)); | |
323 | nis_domain_of_r (domain, ndomain, sizeof (ndomain)); | |
324 | strcpy (domain, ndomain); | |
325 | } | |
326 | while (nis_dir_cmp (domain, dir->do_name) != SAME_NAME); | |
714a562f UD |
327 | cp = strchr (leaf, '\0'); |
328 | *cp++ = '.'; | |
329 | strcpy (cp, domain); | |
43b0e40f UD |
330 | |
331 | for (i = 0; i < dir->do_servers.do_servers_len; ++i) | |
332 | { | |
333 | obj = dir_lookup (leaf, &dir->do_servers.do_servers_val[i], | |
334 | flags); | |
335 | if (obj != NULL) | |
336 | { | |
337 | /* We have found a NIS+ server serving ndomain, now | |
338 | let us search for "name" */ | |
339 | nis_free_directory (dir); | |
340 | return rec_dirsearch (name, obj, flags); | |
341 | } | |
342 | } | |
343 | } | |
344 | break; | |
345 | case BAD_NAME: | |
346 | nis_free_directory (dir); | |
347 | return NULL; | |
348 | } | |
349 | nis_free_directory (dir); | |
350 | return NULL; | |
351 | } | |
352 | ||
353 | nis_error | |
354 | __do_niscall (const_nis_name name, u_long prog, xdrproc_t xargs, | |
355 | caddr_t req, xdrproc_t xres, caddr_t resp, u_long flags) | |
356 | { | |
357 | nis_error result; | |
358 | directory_obj *dir = NULL; | |
359 | const nis_server *server; | |
360 | u_int server_len; | |
361 | ||
362 | ||
363 | dir = readColdStartFile (); | |
364 | if (dir == NULL) /* No /var/nis/NIS_COLD_START -> no NIS+ installed */ | |
365 | return NIS_UNAVAIL; | |
366 | ||
367 | if (name != NULL) | |
368 | { | |
369 | dir = rec_dirsearch (name, dir, flags); | |
370 | if (dir == NULL) | |
371 | { | |
372 | if (nis_dir_cmp (nis_local_directory(), name) == NOT_SEQUENTIAL) | |
373 | return NIS_NAMEUNREACHABLE; | |
374 | else | |
375 | return NIS_NOTFOUND; | |
376 | } | |
377 | } | |
378 | server = dir->do_servers.do_servers_val; | |
379 | server_len = dir->do_servers.do_servers_len; | |
380 | ||
381 | if (((flags & MASTER_ONLY) == MASTER_ONLY) && server_len > 1) | |
382 | server_len = 1; /* The first entry is the master */ | |
383 | ||
384 | result = __do_niscall2 (server, server_len, prog, xargs, req, xres, | |
385 | resp, flags); | |
e61abf83 UD |
386 | if (dir != NULL) |
387 | nis_free_directory (dir); | |
43b0e40f | 388 | |
e61abf83 UD |
389 | return result; |
390 | } |