]>
Commit | Line | Data |
---|---|---|
ac9f45cf | 1 | /* Copyright (C) 1997, 1998 Free Software Foundation, Inc. |
e61abf83 UD |
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 | ||
36a8586d | 20 | #include <errno.h> |
2d7da676 | 21 | #include <fcntl.h> |
e61abf83 UD |
22 | #include <string.h> |
23 | #include <rpc/rpc.h> | |
24 | #include <rpc/auth.h> | |
25 | #include <rpcsvc/nis.h> | |
26 | #include <sys/socket.h> | |
27 | #include <netinet/in.h> | |
28 | #include <arpa/inet.h> | |
91eee4dd UD |
29 | |
30 | #include "nis_xdr.h" | |
e61abf83 UD |
31 | #include "nis_intern.h" |
32 | ||
cc3fa755 UD |
33 | static struct timeval RPCTIMEOUT = {10, 0}; |
34 | static struct timeval UDPTIMEOUT = {5, 0}; | |
2d7da676 | 35 | |
26a60f90 UD |
36 | extern u_short __pmap_getnisport (struct sockaddr_in *address, u_long program, |
37 | u_long version, u_int protocol); | |
38 | ||
3996f34b | 39 | unsigned long |
e61abf83 UD |
40 | inetstr2int (const char *str) |
41 | { | |
42 | char buffer[strlen (str) + 3]; | |
43 | size_t buflen; | |
44 | size_t i, j; | |
45 | ||
46 | buflen = stpcpy (buffer, str) - buffer; | |
47 | ||
48 | j = 0; | |
49 | for (i = 0; i < buflen; ++i) | |
50 | if (buffer[i] == '.') | |
51 | { | |
52 | ++j; | |
53 | if (j == 4) | |
54 | { | |
55 | buffer[i] = '\0'; | |
56 | break; | |
57 | } | |
58 | } | |
59 | ||
60 | return inet_addr (buffer); | |
61 | } | |
62 | ||
2d7da676 UD |
63 | static void |
64 | __bind_destroy (dir_binding *bind) | |
e61abf83 | 65 | { |
2d7da676 | 66 | if (bind->clnt != NULL) |
e61abf83 | 67 | { |
2d7da676 UD |
68 | if (bind->use_auth) |
69 | auth_destroy (bind->clnt->cl_auth); | |
70 | clnt_destroy (bind->clnt); | |
71 | } | |
72 | free (bind->server_val); | |
73 | free (bind); | |
74 | } | |
75 | ||
76 | static nis_error | |
77 | __bind_next (dir_binding *bind) | |
78 | { | |
3996f34b | 79 | u_int j; |
2d7da676 UD |
80 | |
81 | if (bind->clnt != NULL) | |
82 | { | |
83 | if (bind->use_auth) | |
84 | auth_destroy (bind->clnt->cl_auth); | |
85 | clnt_destroy (bind->clnt); | |
86 | bind->clnt = NULL; | |
87 | } | |
3996f34b UD |
88 | |
89 | if (bind->trys >= bind->server_len) | |
90 | return NIS_FAIL; | |
91 | ||
92 | for (j = bind->current_ep + 1; | |
93 | j < bind->server_val[bind->server_used].ep.ep_len; ++j) | |
94 | if (strcmp (bind->server_val[bind->server_used].ep.ep_val[j].family, | |
95 | "inet") == 0) | |
96 | if (strcmp (bind->server_val[bind->server_used].ep.ep_val[j].proto, | |
97 | "-") == 0) | |
98 | { | |
99 | bind->current_ep = j; | |
100 | return NIS_SUCCESS; | |
101 | } | |
102 | ||
103 | ++bind->trys; | |
104 | ++bind->server_used; | |
105 | if (bind->server_used >= bind->server_len) | |
106 | bind->server_used = 0; | |
107 | ||
650425ce | 108 | for (j = 0; j < bind->server_val[bind->server_used].ep.ep_len; ++j) |
3996f34b UD |
109 | if (strcmp (bind->server_val[bind->server_used].ep.ep_val[j].family, |
110 | "inet") == 0) | |
111 | if (strcmp (bind->server_val[bind->server_used].ep.ep_val[j].proto, | |
112 | "-") == 0) | |
113 | { | |
114 | bind->current_ep = j; | |
115 | return NIS_SUCCESS; | |
116 | } | |
117 | ||
118 | return NIS_FAIL; | |
2d7da676 UD |
119 | } |
120 | ||
121 | static nis_error | |
122 | __bind_connect (dir_binding *dbp) | |
123 | { | |
124 | struct sockaddr_in check; | |
125 | nis_server *serv; | |
126 | int checklen; | |
2d7da676 UD |
127 | |
128 | if (dbp == NULL) | |
129 | return NIS_FAIL; | |
130 | ||
131 | serv = &dbp->server_val[dbp->server_used]; | |
132 | ||
133 | memset (&dbp->addr, '\0', sizeof (dbp->addr)); | |
134 | dbp->addr.sin_family = AF_INET; | |
3996f34b UD |
135 | |
136 | dbp->addr.sin_addr.s_addr = | |
137 | inetstr2int (serv->ep.ep_val[dbp->current_ep].uaddr); | |
138 | ||
2d7da676 UD |
139 | if (dbp->addr.sin_addr.s_addr == 0) |
140 | return NIS_FAIL; | |
141 | ||
26a60f90 UD |
142 | /* Check, if the host is online and rpc.nisd is running. Much faster |
143 | then the clnt*_create functions: */ | |
144 | if (__pmap_getnisport (&dbp->addr, NIS_PROG, NIS_VERSION, IPPROTO_UDP) == 0) | |
145 | return NIS_RPCERROR; | |
146 | ||
2d7da676 UD |
147 | dbp->socket = RPC_ANYSOCK; |
148 | if (dbp->use_udp) | |
149 | dbp->clnt = clntudp_create (&dbp->addr, NIS_PROG, NIS_VERSION, | |
cc3fa755 | 150 | UDPTIMEOUT, &dbp->socket); |
2d7da676 UD |
151 | else |
152 | dbp->clnt = clnttcp_create (&dbp->addr, NIS_PROG, NIS_VERSION, | |
153 | &dbp->socket, 0, 0); | |
3996f34b | 154 | |
2d7da676 UD |
155 | if (dbp->clnt == NULL) |
156 | return NIS_RPCERROR; | |
3996f34b | 157 | |
cc3fa755 | 158 | clnt_control (dbp->clnt, CLSET_TIMEOUT, (caddr_t)&RPCTIMEOUT); |
2d7da676 UD |
159 | /* If the program exists, close the socket */ |
160 | if (fcntl (dbp->socket, F_SETFD, 1) == -1) | |
161 | perror (_("fcntl: F_SETFD")); | |
3996f34b | 162 | |
2d7da676 UD |
163 | if (dbp->use_auth) |
164 | { | |
26a60f90 | 165 | if (serv->key_type == NIS_PK_DH && key_secretkey_is_set ()) |
e61abf83 | 166 | { |
2d7da676 UD |
167 | char netname[MAXNETNAMELEN+1]; |
168 | char *p; | |
3996f34b | 169 | |
2d7da676 UD |
170 | p = stpcpy (netname, "unix."); |
171 | strncpy (p, serv->name,MAXNETNAMELEN-5); | |
172 | netname[MAXNETNAMELEN] = '\0'; | |
173 | p = strchr (netname, '.'); | |
174 | *p = '@'; | |
175 | dbp->clnt->cl_auth = | |
176 | authdes_pk_create (netname, &serv->pkey, 300, NULL, NULL); | |
177 | if (!dbp->clnt->cl_auth) | |
178 | dbp->clnt->cl_auth = authunix_create_default (); | |
e61abf83 | 179 | } |
2d7da676 | 180 | else |
2d7da676 UD |
181 | dbp->clnt->cl_auth = authunix_create_default (); |
182 | dbp->use_auth = TRUE; | |
183 | } | |
3996f34b | 184 | |
2d7da676 UD |
185 | /* Get port for sanity checks later */ |
186 | checklen = sizeof (struct sockaddr_in); | |
187 | memset (&check, 0, checklen); | |
188 | if (dbp->use_udp) | |
189 | bind (dbp->socket, (struct sockaddr *)&check, checklen); | |
190 | check.sin_family = AF_INET; | |
191 | if (!getsockname (dbp->socket, (struct sockaddr *)&check, &checklen)) | |
192 | dbp->port = check.sin_port; | |
193 | ||
194 | dbp->create = time (NULL); | |
195 | ||
196 | return NIS_SUCCESS; | |
197 | } | |
26dee9c4 | 198 | |
2d7da676 | 199 | static dir_binding * |
ac9f45cf UD |
200 | __bind_create (const nis_server *serv_val, u_int serv_len, u_long flags, |
201 | cache2_info *cinfo) | |
2d7da676 UD |
202 | { |
203 | dir_binding *dbp; | |
204 | u_int i; | |
3996f34b | 205 | |
2d7da676 UD |
206 | dbp = calloc (1, sizeof (dir_binding)); |
207 | if (dbp == NULL) | |
208 | return NULL; | |
3996f34b | 209 | |
2d7da676 UD |
210 | dbp->server_len = serv_len; |
211 | dbp->server_val = calloc (1, sizeof (nis_server) * serv_len); | |
212 | if (dbp->server_val == NULL) | |
213 | { | |
214 | free (dbp); | |
215 | return NULL; | |
216 | } | |
3996f34b UD |
217 | |
218 | if (flags & USE_DGRAM) | |
219 | dbp->use_udp = TRUE; | |
220 | else | |
221 | dbp->use_udp = FALSE; | |
222 | ||
223 | if (flags & NO_AUTHINFO) | |
224 | dbp->use_auth = FALSE; | |
225 | else | |
226 | dbp->use_auth = TRUE; | |
227 | ||
228 | if (flags & MASTER_ONLY) | |
229 | dbp->master_only = TRUE; | |
230 | else | |
231 | dbp->master_only = FALSE; | |
232 | ||
26a60f90 | 233 | /* We try the first server */ |
3996f34b UD |
234 | dbp->trys = 1; |
235 | ||
2d7da676 UD |
236 | for (i = 0; i < serv_len; ++i) |
237 | { | |
238 | if (serv_val[i].name != NULL) | |
239 | dbp->server_val[i].name = strdup (serv_val[i].name); | |
3996f34b | 240 | |
2d7da676 UD |
241 | dbp->server_val[i].ep.ep_len = serv_val[i].ep.ep_len; |
242 | if (dbp->server_val[i].ep.ep_len > 0) | |
26dee9c4 | 243 | { |
2d7da676 | 244 | unsigned long j; |
3996f34b | 245 | |
2d7da676 UD |
246 | dbp->server_val[i].ep.ep_val = |
247 | malloc (serv_val[i].ep.ep_len * sizeof (endpoint)); | |
248 | for (j = 0; j < dbp->server_val[i].ep.ep_len; ++j) | |
26dee9c4 | 249 | { |
2d7da676 UD |
250 | if (serv_val[i].ep.ep_val[j].uaddr) |
251 | dbp->server_val[i].ep.ep_val[j].uaddr = | |
252 | strdup (serv_val[i].ep.ep_val[j].uaddr); | |
253 | else | |
254 | dbp->server_val[i].ep.ep_val[j].uaddr = NULL; | |
255 | if (serv_val[i].ep.ep_val[j].family) | |
256 | dbp->server_val[i].ep.ep_val[j].family = | |
257 | strdup (serv_val[i].ep.ep_val[j].family); | |
258 | else | |
259 | dbp->server_val[i].ep.ep_val[j].family = NULL; | |
260 | if (serv_val[i].ep.ep_val[j].proto) | |
261 | dbp->server_val[i].ep.ep_val[j].proto = | |
262 | strdup (serv_val[i].ep.ep_val[j].proto); | |
263 | else | |
264 | dbp->server_val[i].ep.ep_val[j].proto = NULL; | |
26dee9c4 | 265 | } |
26dee9c4 | 266 | } |
2d7da676 UD |
267 | else |
268 | dbp->server_val[i].ep.ep_val = NULL; | |
269 | dbp->server_val[i].key_type = serv_val[i].key_type; | |
270 | dbp->server_val[i].pkey.n_len = serv_val[i].pkey.n_len; | |
271 | if (serv_val[i].pkey.n_len > 0) | |
272 | { | |
273 | dbp->server_val[i].pkey.n_bytes = | |
274 | malloc (serv_val[i].pkey.n_len); | |
275 | if (dbp->server_val[i].pkey.n_bytes == NULL) | |
276 | return NULL; | |
277 | memcpy (dbp->server_val[i].pkey.n_bytes, serv_val[i].pkey.n_bytes, | |
278 | serv_val[i].pkey.n_len); | |
279 | } | |
280 | else | |
281 | dbp->server_val[i].pkey.n_bytes = NULL; | |
e61abf83 | 282 | } |
2d7da676 | 283 | |
ac9f45cf UD |
284 | dbp->class = -1; |
285 | if (cinfo != NULL && cinfo->server_used >= 0) | |
286 | { | |
287 | dbp->server_used = cinfo->server_used; | |
288 | dbp->current_ep = cinfo->current_ep; | |
289 | dbp->class = cinfo->class; | |
290 | } | |
291 | else if (__nis_findfastest (dbp) < 1) | |
3996f34b UD |
292 | { |
293 | __bind_destroy (dbp); | |
294 | return NULL; | |
295 | } | |
2d7da676 UD |
296 | |
297 | return dbp; | |
e61abf83 UD |
298 | } |
299 | ||
300 | nis_error | |
43b0e40f UD |
301 | __do_niscall2 (const nis_server *server, u_int server_len, u_long prog, |
302 | xdrproc_t xargs, caddr_t req, xdrproc_t xres, caddr_t resp, | |
ac9f45cf | 303 | u_long flags, nis_cb *cb, cache2_info *cinfo) |
e61abf83 | 304 | { |
2d7da676 UD |
305 | enum clnt_stat result; |
306 | nis_error retcode; | |
307 | dir_binding *dbp; | |
308 | ||
3996f34b | 309 | if (flags & MASTER_ONLY) |
2d7da676 | 310 | server_len = 1; |
3996f34b | 311 | |
ac9f45cf UD |
312 | dbp = __bind_create (server, server_len, flags, cinfo); |
313 | if (dbp == NULL) | |
a5a0310d | 314 | return NIS_NAMEUNREACHABLE; |
2d7da676 | 315 | while (__bind_connect (dbp) != NIS_SUCCESS) |
e61abf83 | 316 | { |
2d7da676 | 317 | if (__bind_next (dbp) != NIS_SUCCESS) |
e61abf83 | 318 | { |
2d7da676 UD |
319 | __bind_destroy (dbp); |
320 | return NIS_NAMEUNREACHABLE; | |
e61abf83 UD |
321 | } |
322 | } | |
323 | ||
2d7da676 | 324 | do |
43b0e40f | 325 | { |
2d7da676 | 326 | again: |
cc3fa755 | 327 | result = clnt_call (dbp->clnt, prog, xargs, req, xres, resp, RPCTIMEOUT); |
3996f34b | 328 | |
43b0e40f UD |
329 | if (result != RPC_SUCCESS) |
330 | { | |
2d7da676 UD |
331 | __bind_destroy (dbp); |
332 | retcode = NIS_RPCERROR; | |
43b0e40f UD |
333 | } |
334 | else | |
2d7da676 UD |
335 | { |
336 | switch (prog) | |
337 | { | |
650425ce UD |
338 | case NIS_IBLIST: |
339 | if ((((nis_result *)resp)->status == NIS_CBRESULTS) && | |
340 | (cb != NULL)) | |
341 | { | |
342 | __nis_do_callback(dbp, &((nis_result *)resp)->cookie, cb); | |
343 | break; | |
344 | } | |
345 | /* Yes, this is correct. If we doesn't have to start | |
346 | a callback, look if we have to search another server */ | |
2d7da676 UD |
347 | case NIS_LOOKUP: |
348 | case NIS_ADD: | |
349 | case NIS_MODIFY: | |
350 | case NIS_REMOVE: | |
2d7da676 UD |
351 | case NIS_IBADD: |
352 | case NIS_IBMODIFY: | |
353 | case NIS_IBREMOVE: | |
354 | case NIS_IBFIRST: | |
355 | case NIS_IBNEXT: | |
650425ce UD |
356 | if ((((nis_result *)resp)->status == NIS_NOTFOUND) || |
357 | (((nis_result *)resp)->status == NIS_NOSUCHNAME) || | |
358 | (((nis_result *)resp)->status == NIS_NOT_ME)) | |
3996f34b UD |
359 | { |
360 | if (__bind_next (dbp) == NIS_SUCCESS) | |
650425ce UD |
361 | { |
362 | while (__bind_connect (dbp) != NIS_SUCCESS) | |
363 | { | |
364 | if (__bind_next (dbp) != NIS_SUCCESS) | |
365 | { | |
366 | __bind_destroy (dbp); | |
367 | return NIS_SUCCESS; | |
368 | } | |
369 | } | |
370 | } | |
371 | else | |
372 | break; /* No more servers to search in */ | |
2d7da676 | 373 | goto again; |
3996f34b | 374 | } |
a5a0310d | 375 | break; |
2d7da676 | 376 | case NIS_FINDDIRECTORY: |
650425ce UD |
377 | if ((((fd_result *)resp)->status == NIS_NOTFOUND) || |
378 | (((fd_result *)resp)->status == NIS_NOSUCHNAME) || | |
379 | (((fd_result *)resp)->status == NIS_NOT_ME)) | |
3996f34b UD |
380 | { |
381 | if (__bind_next (dbp) == NIS_SUCCESS) | |
650425ce UD |
382 | { |
383 | while (__bind_connect (dbp) != NIS_SUCCESS) | |
384 | { | |
385 | if (__bind_next (dbp) != NIS_SUCCESS) | |
386 | { | |
387 | __bind_destroy (dbp); | |
388 | return NIS_SUCCESS; | |
389 | } | |
390 | } | |
391 | } | |
392 | else | |
393 | break; /* No more servers to search in */ | |
2d7da676 | 394 | goto again; |
3996f34b | 395 | } |
2d7da676 UD |
396 | break; |
397 | case NIS_DUMPLOG: /* log_result */ | |
398 | case NIS_DUMP: | |
650425ce UD |
399 | if ((((log_result *)resp)->lr_status == NIS_NOTFOUND) || |
400 | (((log_result *)resp)->lr_status == NIS_NOSUCHNAME) || | |
401 | (((log_result *)resp)->lr_status == NIS_NOT_ME)) | |
3996f34b UD |
402 | { |
403 | if (__bind_next (dbp) == NIS_SUCCESS) | |
650425ce UD |
404 | { |
405 | while (__bind_connect (dbp) != NIS_SUCCESS) | |
406 | { | |
407 | if (__bind_next (dbp) != NIS_SUCCESS) | |
408 | { | |
409 | __bind_destroy (dbp); | |
410 | return NIS_SUCCESS; | |
411 | } | |
412 | } | |
413 | } | |
414 | else | |
415 | break; /* No more servers to search in */ | |
3996f34b UD |
416 | goto again; |
417 | } | |
2d7da676 | 418 | break; |
2d7da676 UD |
419 | default: |
420 | break; | |
421 | } | |
422 | __bind_destroy (dbp); | |
423 | retcode = NIS_SUCCESS; | |
424 | } | |
43b0e40f | 425 | } |
2d7da676 | 426 | while ((flags & HARD_LOOKUP) && retcode == NIS_RPCERROR); |
3996f34b UD |
427 | |
428 | return retcode; | |
43b0e40f UD |
429 | } |
430 | ||
431 | static directory_obj * | |
3996f34b UD |
432 | rec_dirsearch (const_nis_name name, directory_obj *dir, u_long flags, |
433 | nis_error *status) | |
43b0e40f | 434 | { |
2d7da676 UD |
435 | fd_result *fd_res; |
436 | XDR xdrs; | |
43b0e40f | 437 | |
26a60f90 | 438 | switch (nis_dir_cmp (name, dir->do_name)) |
43b0e40f UD |
439 | { |
440 | case SAME_NAME: | |
3996f34b | 441 | *status = NIS_SUCCESS; |
43b0e40f UD |
442 | return dir; |
443 | case NOT_SEQUENTIAL: | |
444 | /* NOT_SEQUENTIAL means, go one up and try it there ! */ | |
445 | case HIGHER_NAME: | |
446 | { /* We need data from a parent domain */ | |
447 | directory_obj *obj; | |
448 | char ndomain [strlen (name) + 3]; | |
449 | ||
450 | nis_domain_of_r (dir->do_name, ndomain, sizeof (ndomain)); | |
451 | ||
452 | /* The root server of our domain is a replica of the parent | |
453 | domain ! (Now I understand why a root server must be a | |
454 | replica of the parent domain) */ | |
2d7da676 | 455 | fd_res = __nis_finddirectory (dir, ndomain); |
3996f34b | 456 | *status = fd_res->status; |
2d7da676 UD |
457 | if (fd_res->status != NIS_SUCCESS) |
458 | { | |
26a60f90 | 459 | /* Try the current directory obj, maybe it works */ |
af6f3906 | 460 | __free_fdresult (fd_res); |
26a60f90 | 461 | return dir; |
2d7da676 | 462 | } |
2d7da676 UD |
463 | obj = calloc(1, sizeof(directory_obj)); |
464 | xdrmem_create(&xdrs, fd_res->dir_data.dir_data_val, | |
465 | fd_res->dir_data.dir_data_len, XDR_DECODE); | |
91eee4dd | 466 | _xdr_directory_obj(&xdrs, obj); |
2d7da676 | 467 | xdr_destroy(&xdrs); |
dfd2257a | 468 | __free_fdresult (fd_res); |
43b0e40f UD |
469 | if (obj != NULL) |
470 | { | |
471 | /* We have found a NIS+ server serving ndomain, now | |
472 | let us search for "name" */ | |
473 | nis_free_directory (dir); | |
3996f34b | 474 | return rec_dirsearch (name, obj, flags, status); |
43b0e40f UD |
475 | } |
476 | else | |
477 | { | |
478 | /* Ups, very bad. Are we already the root server ? */ | |
479 | nis_free_directory (dir); | |
480 | return NULL; | |
481 | } | |
482 | } | |
2d7da676 | 483 | break; |
43b0e40f UD |
484 | case LOWER_NAME: |
485 | { | |
486 | directory_obj *obj; | |
a53bad16 UD |
487 | size_t namelen = strlen (name); |
488 | char leaf [namelen + 3]; | |
489 | char domain [namelen + 3]; | |
490 | char ndomain [namelen + 3]; | |
714a562f | 491 | char *cp; |
26a60f90 UD |
492 | u_int run = 0; |
493 | ||
494 | strcpy (domain, name); | |
3996f34b | 495 | |
43b0e40f UD |
496 | do |
497 | { | |
a53bad16 | 498 | if (domain[0] == '\0') |
43b0e40f UD |
499 | { |
500 | nis_free_directory (dir); | |
501 | return NULL; | |
502 | } | |
503 | nis_leaf_of_r (domain, leaf, sizeof (leaf)); | |
504 | nis_domain_of_r (domain, ndomain, sizeof (ndomain)); | |
505 | strcpy (domain, ndomain); | |
26a60f90 | 506 | ++run; |
43b0e40f UD |
507 | } |
508 | while (nis_dir_cmp (domain, dir->do_name) != SAME_NAME); | |
26a60f90 UD |
509 | |
510 | if (run == 1) | |
511 | { | |
512 | /* We have found the directory above. Use it. */ | |
513 | return dir; | |
514 | } | |
515 | ||
714a562f UD |
516 | cp = strchr (leaf, '\0'); |
517 | *cp++ = '.'; | |
518 | strcpy (cp, domain); | |
3996f34b | 519 | |
2d7da676 | 520 | fd_res = __nis_finddirectory (dir, leaf); |
3996f34b | 521 | *status = fd_res->status; |
2d7da676 | 522 | if (fd_res->status != NIS_SUCCESS) |
43b0e40f | 523 | { |
26a60f90 | 524 | /* Try the current directory object, maybe it works */ |
af6f3906 | 525 | __free_fdresult (fd_res); |
26a60f90 | 526 | return dir; |
2d7da676 | 527 | } |
2d7da676 UD |
528 | obj = calloc(1, sizeof(directory_obj)); |
529 | xdrmem_create(&xdrs, fd_res->dir_data.dir_data_val, | |
530 | fd_res->dir_data.dir_data_len, XDR_DECODE); | |
91eee4dd | 531 | _xdr_directory_obj(&xdrs, obj); |
2d7da676 | 532 | xdr_destroy(&xdrs); |
dfd2257a | 533 | __free_fdresult (fd_res); |
2d7da676 UD |
534 | if (obj != NULL) |
535 | { | |
536 | /* We have found a NIS+ server serving ndomain, now | |
537 | let us search for "name" */ | |
538 | nis_free_directory (dir); | |
3996f34b | 539 | return rec_dirsearch (name, obj, flags, status); |
43b0e40f UD |
540 | } |
541 | } | |
2d7da676 | 542 | break; |
43b0e40f UD |
543 | case BAD_NAME: |
544 | nis_free_directory (dir); | |
3996f34b | 545 | *status = NIS_BADNAME; |
43b0e40f UD |
546 | return NULL; |
547 | } | |
548 | nis_free_directory (dir); | |
3996f34b | 549 | *status = NIS_FAIL; |
43b0e40f UD |
550 | return NULL; |
551 | } | |
552 | ||
26a60f90 UD |
553 | /* We try to query the current server for the searched object, |
554 | maybe he know about it ? */ | |
555 | static directory_obj * | |
556 | first_shoot (const_nis_name name, directory_obj *dir, u_long flags) | |
557 | { | |
558 | directory_obj *obj; | |
559 | fd_result *fd_res; | |
560 | XDR xdrs; | |
561 | char domain [strlen (name) + 3]; | |
562 | ||
563 | if (nis_dir_cmp (name, dir->do_name) == SAME_NAME) | |
564 | return dir; | |
565 | ||
566 | nis_domain_of_r (name, domain, sizeof (domain)); | |
567 | ||
568 | if (nis_dir_cmp (domain, dir->do_name) == SAME_NAME) | |
569 | return dir; | |
570 | ||
571 | fd_res = __nis_finddirectory (dir, domain); | |
572 | if (fd_res->status != NIS_SUCCESS) | |
573 | { | |
574 | __free_fdresult (fd_res); | |
575 | return NULL; | |
576 | } | |
577 | obj = calloc(1, sizeof(directory_obj)); | |
578 | if (obj == NULL) | |
579 | return NULL; | |
580 | xdrmem_create(&xdrs, fd_res->dir_data.dir_data_val, | |
581 | fd_res->dir_data.dir_data_len, XDR_DECODE); | |
91eee4dd UD |
582 | _xdr_directory_obj (&xdrs, obj); |
583 | xdr_destroy (&xdrs); | |
26a60f90 UD |
584 | __free_fdresult (fd_res); |
585 | if (obj != NULL) | |
586 | { | |
587 | nis_free_directory (dir); | |
588 | return obj; | |
589 | } | |
590 | return NULL; | |
591 | } | |
592 | ||
43b0e40f UD |
593 | nis_error |
594 | __do_niscall (const_nis_name name, u_long prog, xdrproc_t xargs, | |
650425ce UD |
595 | caddr_t req, xdrproc_t xres, caddr_t resp, u_long flags, |
596 | nis_cb *cb) | |
43b0e40f | 597 | { |
2d7da676 | 598 | nis_error retcode; |
43b0e40f | 599 | directory_obj *dir = NULL; |
2d7da676 | 600 | nis_server *server; |
43b0e40f | 601 | u_int server_len; |
ac9f45cf | 602 | cache2_info cinfo = {-1, -1, -1}; |
36a8586d | 603 | int saved_errno = errno; |
43b0e40f | 604 | |
2d7da676 UD |
605 | if (name == NULL) |
606 | return NIS_BADNAME; | |
43b0e40f | 607 | |
ac9f45cf UD |
608 | /* Search in local cache. In the moment, we ignore the fastest server */ |
609 | if (!(flags & NO_CACHE)) | |
610 | dir = __nis_cache_search (name, flags, &cinfo); | |
611 | ||
2d7da676 | 612 | if (dir == NULL) |
43b0e40f | 613 | { |
3996f34b | 614 | nis_error status; |
26a60f90 UD |
615 | directory_obj *obj; |
616 | ||
2d7da676 UD |
617 | dir = readColdStartFile (); |
618 | if (dir == NULL) /* No /var/nis/NIS_COLD_START->no NIS+ installed */ | |
36a8586d UD |
619 | { |
620 | __set_errno (saved_errno); | |
621 | return NIS_UNAVAIL; | |
622 | } | |
3996f34b | 623 | |
26a60f90 UD |
624 | /* Try at first, if servers in "dir" know our object */ |
625 | obj = first_shoot (name, dir, flags); | |
626 | if (obj == NULL) | |
a788b6c2 | 627 | { |
26a60f90 UD |
628 | dir = rec_dirsearch (name, dir, flags, &status); |
629 | if (dir == NULL) | |
630 | { | |
631 | __set_errno (saved_errno); | |
632 | return status; | |
633 | } | |
a788b6c2 | 634 | } |
26a60f90 UD |
635 | else |
636 | dir = obj; | |
43b0e40f | 637 | } |
43b0e40f | 638 | |
3996f34b | 639 | if (flags & MASTER_ONLY) |
2d7da676 UD |
640 | { |
641 | server = dir->do_servers.do_servers_val; | |
642 | server_len = 1; | |
643 | } | |
644 | else | |
645 | { | |
646 | server = dir->do_servers.do_servers_val; | |
647 | server_len = dir->do_servers.do_servers_len; | |
648 | } | |
3996f34b UD |
649 | |
650 | ||
2d7da676 | 651 | retcode = __do_niscall2 (server, server_len, prog, xargs, req, xres, resp, |
ac9f45cf | 652 | flags, cb, &cinfo); |
3996f34b | 653 | |
2d7da676 | 654 | nis_free_directory (dir); |
43b0e40f | 655 | |
a788b6c2 UD |
656 | __set_errno (saved_errno); |
657 | ||
2d7da676 | 658 | return retcode; |
e61abf83 | 659 | } |