]>
Commit | Line | Data |
---|---|---|
af69217f | 1 | /* Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc. |
6259ec0d UD |
2 | This file is part of the GNU C Library. |
3 | Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1996. | |
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 | ||
ee74a442 | 20 | #include <errno.h> |
cc3fa755 | 21 | #include <fcntl.h> |
6259ec0d UD |
22 | #include <string.h> |
23 | #include <unistd.h> | |
26dee9c4 | 24 | #include <rpc/rpc.h> |
f21acc89 | 25 | #include <rpcsvc/nis.h> |
6259ec0d UD |
26 | #include <rpcsvc/yp.h> |
27 | #include <rpcsvc/ypclnt.h> | |
28 | #include <rpcsvc/ypupd.h> | |
9931ba24 | 29 | #include <sys/uio.h> |
cc3fa755 | 30 | #include <bits/libc-lock.h> |
6259ec0d | 31 | |
9931ba24 UD |
32 | /* This should only be defined on systems with a BSD compatible ypbind */ |
33 | #ifndef BINDINGDIR | |
34 | # define BINDINGDIR "/var/yp/binding" | |
35 | #endif | |
36 | ||
6259ec0d UD |
37 | struct dom_binding |
38 | { | |
39 | struct dom_binding *dom_pnext; | |
40 | char dom_domain[YPMAXDOMAIN + 1]; | |
41 | struct sockaddr_in dom_server_addr; | |
42 | int dom_socket; | |
43 | CLIENT *dom_client; | |
44 | long int dom_vers; | |
45 | }; | |
46 | typedef struct dom_binding dom_binding; | |
47 | ||
cc3fa755 UD |
48 | static struct timeval RPCTIMEOUT = {25, 0}; |
49 | static struct timeval UDPTIMEOUT = {5, 0}; | |
6259ec0d | 50 | static int const MAXTRIES = 5; |
f21acc89 | 51 | static char __ypdomainname[NIS_MAXNAMELEN + 1] = "\0"; |
6259ec0d UD |
52 | __libc_lock_define_initialized (static, ypbindlist_lock) |
53 | static dom_binding *__ypbindlist = NULL; | |
54 | ||
f8b87ef0 | 55 | |
6259ec0d | 56 | static int |
cc3fa755 | 57 | __yp_bind (const char *domain, dom_binding **ypdb) |
6259ec0d UD |
58 | { |
59 | struct sockaddr_in clnt_saddr; | |
60 | struct ypbind_resp ypbr; | |
cc3fa755 | 61 | dom_binding *ysd = NULL; |
6259ec0d UD |
62 | int clnt_sock; |
63 | CLIENT *client; | |
64 | int is_new = 0; | |
65 | int try; | |
66 | ||
a53bad16 | 67 | if ((domain == NULL) || (domain[0] == '\0')) |
6259ec0d UD |
68 | return YPERR_BADARGS; |
69 | ||
cc3fa755 | 70 | if (ypdb != NULL) |
6259ec0d | 71 | { |
cc3fa755 UD |
72 | ysd = *ypdb; |
73 | while (ysd != NULL) | |
74 | { | |
75 | if (strcmp (domain, ysd->dom_domain) == 0) | |
76 | break; | |
77 | ysd = ysd->dom_pnext; | |
78 | } | |
6259ec0d UD |
79 | } |
80 | ||
81 | if (ysd == NULL) | |
82 | { | |
83 | is_new = 1; | |
bd355af0 | 84 | ysd = (dom_binding *) calloc (1, sizeof *ysd); |
6259ec0d UD |
85 | ysd->dom_socket = -1; |
86 | ysd->dom_vers = -1; | |
87 | } | |
88 | ||
89 | try = 0; | |
90 | ||
91 | do | |
92 | { | |
0c6cee5d | 93 | ++try; |
6259ec0d UD |
94 | if (try > MAXTRIES) |
95 | { | |
96 | if (is_new) | |
97 | free (ysd); | |
98 | return YPERR_YPBIND; | |
99 | } | |
100 | ||
9931ba24 | 101 | #if USE_BINDINGDIR |
0c6cee5d | 102 | if (ysd->dom_vers < 1 && try == 1) /* Try binding dir only first time */ |
9931ba24 UD |
103 | { |
104 | char path[sizeof (BINDINGDIR) - 1 + strlen (domain) + 10]; | |
105 | struct iovec vec[2]; | |
106 | u_short port; | |
107 | int fd; | |
108 | ||
109 | sprintf (path, "%s/%s.%ld", BINDINGDIR, domain, YPBINDVERS); | |
110 | fd = open (path, O_RDONLY); | |
111 | if (fd >= 0) | |
112 | { | |
113 | /* We have a binding file and could save a RPC call */ | |
114 | vec[0].iov_base = &port; | |
115 | vec[0].iov_len = sizeof (port); | |
116 | vec[1].iov_base = &ypbr; | |
117 | vec[1].iov_len = sizeof (ypbr); | |
118 | ||
119 | if (readv (fd, vec, 2) == vec[0].iov_len + vec[1].iov_len) | |
120 | { | |
121 | memset (&ysd->dom_server_addr, '\0', | |
122 | sizeof ysd->dom_server_addr); | |
123 | ysd->dom_server_addr.sin_family = AF_INET; | |
124 | memcpy (&ysd->dom_server_addr.sin_port, | |
125 | ypbr.ypbind_resp_u.ypbind_bindinfo.ypbind_binding_port, | |
126 | sizeof (ysd->dom_server_addr.sin_port)); | |
127 | memcpy (&ysd->dom_server_addr.sin_addr.s_addr, | |
128 | ypbr.ypbind_resp_u.ypbind_bindinfo.ypbind_binding_addr, | |
129 | sizeof (ysd->dom_server_addr.sin_addr.s_addr)); | |
130 | ysd->dom_vers = YPVERS; | |
131 | strncpy (ysd->dom_domain, domain, YPMAXDOMAIN); | |
132 | ysd->dom_domain[YPMAXDOMAIN] = '\0'; | |
133 | } | |
134 | close (fd); | |
135 | } | |
136 | } | |
137 | #endif /* USE_BINDINGDIR */ | |
138 | ||
6259ec0d | 139 | if (ysd->dom_vers == -1) |
36a8586d | 140 | { |
36a8586d UD |
141 | if(ysd->dom_client) |
142 | { | |
143 | clnt_destroy(ysd->dom_client); | |
144 | ysd->dom_client = NULL; | |
145 | ysd->dom_socket = -1; | |
146 | } | |
6259ec0d UD |
147 | memset (&clnt_saddr, '\0', sizeof clnt_saddr); |
148 | clnt_saddr.sin_family = AF_INET; | |
149 | clnt_saddr.sin_addr.s_addr = htonl (INADDR_LOOPBACK); | |
150 | clnt_sock = RPC_ANYSOCK; | |
151 | client = clnttcp_create (&clnt_saddr, YPBINDPROG, YPBINDVERS, | |
152 | &clnt_sock, 0, 0); | |
153 | if (client == NULL) | |
154 | { | |
155 | if (is_new) | |
156 | free (ysd); | |
157 | return YPERR_YPBIND; | |
158 | } | |
159 | /* | |
160 | ** Check the port number -- should be < IPPORT_RESERVED. | |
161 | ** If not, it's possible someone has registered a bogus | |
162 | ** ypbind with the portmapper and is trying to trick us. | |
163 | */ | |
9931ba24 | 164 | if (ntohs (clnt_saddr.sin_port) >= IPPORT_RESERVED) |
6259ec0d | 165 | { |
9931ba24 | 166 | clnt_destroy (client); |
6259ec0d | 167 | if (is_new) |
9931ba24 UD |
168 | free (ysd); |
169 | return YPERR_YPBIND; | |
6259ec0d UD |
170 | } |
171 | ||
172 | if (clnt_call (client, YPBINDPROC_DOMAIN, | |
3e5f5557 | 173 | (xdrproc_t) xdr_domainname, (caddr_t) &domain, |
6259ec0d | 174 | (xdrproc_t) xdr_ypbind_resp, |
cc3fa755 | 175 | (caddr_t) &ypbr, RPCTIMEOUT) != RPC_SUCCESS) |
6259ec0d UD |
176 | { |
177 | clnt_destroy (client); | |
3996f34b | 178 | close (clnt_sock); |
6259ec0d UD |
179 | if (is_new) |
180 | free (ysd); | |
181 | return YPERR_YPBIND; | |
182 | } | |
183 | ||
184 | clnt_destroy (client); | |
3996f34b UD |
185 | close (clnt_sock); |
186 | ||
6259ec0d UD |
187 | if (ypbr.ypbind_status != YPBIND_SUCC_VAL) |
188 | { | |
cc3fa755 UD |
189 | fprintf (stderr, _("YPBINDPROC_DOMAIN: %s\n"), |
190 | ypbinderr_string (ypbr.ypbind_resp_u.ypbind_error)); | |
191 | if (is_new) | |
192 | free (ysd); | |
193 | return YPERR_DOMAIN; | |
194 | } | |
6259ec0d UD |
195 | memset (&ysd->dom_server_addr, '\0', sizeof ysd->dom_server_addr); |
196 | ysd->dom_server_addr.sin_family = AF_INET; | |
197 | memcpy (&ysd->dom_server_addr.sin_port, | |
198 | ypbr.ypbind_resp_u.ypbind_bindinfo.ypbind_binding_port, | |
199 | sizeof (ysd->dom_server_addr.sin_port)); | |
200 | memcpy (&ysd->dom_server_addr.sin_addr.s_addr, | |
201 | ypbr.ypbind_resp_u.ypbind_bindinfo.ypbind_binding_addr, | |
202 | sizeof (ysd->dom_server_addr.sin_addr.s_addr)); | |
203 | ysd->dom_vers = YPVERS; | |
0d8733c4 UD |
204 | strncpy (ysd->dom_domain, domain, YPMAXDOMAIN); |
205 | ysd->dom_domain[YPMAXDOMAIN] = '\0'; | |
6259ec0d UD |
206 | } |
207 | ||
208 | if (ysd->dom_client) | |
3996f34b UD |
209 | { |
210 | clnt_destroy (ysd->dom_client); | |
211 | close (ysd->dom_socket); | |
212 | } | |
6259ec0d UD |
213 | ysd->dom_socket = RPC_ANYSOCK; |
214 | ysd->dom_client = clntudp_create (&ysd->dom_server_addr, YPPROG, YPVERS, | |
cc3fa755 | 215 | UDPTIMEOUT, &ysd->dom_socket); |
6259ec0d UD |
216 | if (ysd->dom_client == NULL) |
217 | ysd->dom_vers = -1; | |
218 | ||
219 | } | |
220 | while (ysd->dom_client == NULL); | |
221 | ||
222 | /* If the program exists, close the socket */ | |
223 | if (fcntl (ysd->dom_socket, F_SETFD, 1) == -1) | |
d111572f | 224 | perror ("fcntl: F_SETFD"); |
6259ec0d | 225 | |
cc3fa755 | 226 | if (is_new && ypdb != NULL) |
6259ec0d | 227 | { |
cc3fa755 UD |
228 | ysd->dom_pnext = *ypdb; |
229 | *ypdb = ysd; | |
6259ec0d UD |
230 | } |
231 | ||
6259ec0d UD |
232 | return YPERR_SUCCESS; |
233 | } | |
234 | ||
235 | static void | |
236 | __yp_unbind (dom_binding *ydb) | |
237 | { | |
238 | clnt_destroy (ydb->dom_client); | |
239 | ydb->dom_client = NULL; | |
240 | ydb->dom_socket = -1; | |
241 | } | |
242 | ||
243 | static int | |
244 | do_ypcall (const char *domain, u_long prog, xdrproc_t xargs, | |
245 | caddr_t req, xdrproc_t xres, caddr_t resp) | |
246 | { | |
247 | dom_binding *ydb = NULL; | |
cc3fa755 | 248 | bool_t use_ypbindlist = FALSE; |
d111572f UD |
249 | int try, status; |
250 | enum clnt_stat result; | |
a788b6c2 | 251 | int saved_errno = errno; |
6259ec0d UD |
252 | |
253 | try = 0; | |
d111572f | 254 | status = YPERR_YPERR; |
6259ec0d | 255 | |
cc3fa755 UD |
256 | __libc_lock_lock (ypbindlist_lock); |
257 | if (__ypbindlist != NULL) | |
6259ec0d | 258 | { |
cc3fa755 UD |
259 | ydb = __ypbindlist; |
260 | while (ydb != NULL) | |
261 | { | |
262 | if (strcmp (domain, ydb->dom_domain) == 0) | |
263 | break; | |
264 | ydb = ydb->dom_pnext; | |
265 | } | |
266 | if (ydb != NULL) | |
267 | use_ypbindlist = TRUE; | |
268 | else | |
269 | __libc_lock_unlock (ypbindlist_lock); | |
270 | } | |
271 | else | |
272 | __libc_lock_unlock (ypbindlist_lock); | |
6259ec0d | 273 | |
a588b67d | 274 | while (try < MAXTRIES && status != YPERR_SUCCESS) |
cc3fa755 | 275 | { |
6259ec0d UD |
276 | if (__yp_bind (domain, &ydb) != 0) |
277 | { | |
cc3fa755 UD |
278 | if (use_ypbindlist) |
279 | __libc_lock_unlock (ypbindlist_lock); | |
a788b6c2 | 280 | __set_errno (saved_errno); |
6259ec0d UD |
281 | return YPERR_DOMAIN; |
282 | } | |
283 | ||
284 | result = clnt_call (ydb->dom_client, prog, | |
cc3fa755 | 285 | xargs, req, xres, resp, RPCTIMEOUT); |
6259ec0d UD |
286 | |
287 | if (result != RPC_SUCCESS) | |
288 | { | |
289 | clnt_perror (ydb->dom_client, "do_ypcall: clnt_call"); | |
290 | ydb->dom_vers = -1; | |
cc3fa755 UD |
291 | if (!use_ypbindlist) |
292 | { | |
293 | __yp_unbind (ydb); | |
294 | free (ydb); | |
295 | ydb = NULL; | |
296 | } | |
d111572f | 297 | status = YPERR_RPC;; |
6259ec0d | 298 | } |
d111572f UD |
299 | else |
300 | status = YPERR_SUCCESS; | |
301 | ||
6259ec0d UD |
302 | try++; |
303 | } | |
cc3fa755 UD |
304 | if (use_ypbindlist) |
305 | { | |
306 | __libc_lock_unlock (ypbindlist_lock); | |
307 | use_ypbindlist = FALSE; | |
308 | } | |
309 | else | |
bd355af0 UD |
310 | if (ydb != NULL) |
311 | { | |
312 | __yp_unbind (ydb); | |
313 | free (ydb); | |
314 | ydb = NULL; | |
315 | } | |
6259ec0d | 316 | |
a788b6c2 UD |
317 | __set_errno (saved_errno); |
318 | ||
d111572f | 319 | return status; |
6259ec0d UD |
320 | } |
321 | ||
322 | int | |
323 | yp_bind (const char *indomain) | |
324 | { | |
325 | int status; | |
326 | ||
327 | __libc_lock_lock (ypbindlist_lock); | |
328 | ||
cc3fa755 | 329 | status = __yp_bind (indomain, &__ypbindlist); |
6259ec0d UD |
330 | |
331 | __libc_lock_unlock (ypbindlist_lock); | |
332 | ||
333 | return status; | |
334 | } | |
335 | ||
336 | void | |
337 | yp_unbind (const char *indomain) | |
338 | { | |
339 | dom_binding *ydbptr, *ydbptr2; | |
340 | ||
341 | __libc_lock_lock (ypbindlist_lock); | |
342 | ||
343 | ydbptr2 = NULL; | |
344 | ydbptr = __ypbindlist; | |
345 | while (ydbptr != NULL) | |
346 | { | |
347 | if (strcmp (ydbptr->dom_domain, indomain) == 0) | |
348 | { | |
349 | dom_binding *work; | |
350 | ||
351 | work = ydbptr; | |
352 | if (ydbptr2 == NULL) | |
353 | __ypbindlist = __ypbindlist->dom_pnext; | |
354 | else | |
355 | ydbptr2 = ydbptr->dom_pnext; | |
356 | __yp_unbind (work); | |
357 | free (work); | |
358 | break; | |
359 | } | |
360 | ydbptr2 = ydbptr; | |
361 | ydbptr = ydbptr->dom_pnext; | |
362 | } | |
363 | ||
364 | __libc_lock_unlock (ypbindlist_lock); | |
365 | ||
366 | return; | |
367 | } | |
368 | ||
369 | __libc_lock_define_initialized (static, domainname_lock) | |
370 | ||
371 | int | |
372 | yp_get_default_domain (char **outdomain) | |
373 | { | |
374 | int result = YPERR_SUCCESS;; | |
375 | *outdomain = NULL; | |
376 | ||
377 | __libc_lock_lock (domainname_lock); | |
378 | ||
379 | if (__ypdomainname[0] == '\0') | |
380 | { | |
f21acc89 | 381 | if (getdomainname (__ypdomainname, NIS_MAXNAMELEN)) |
6259ec0d | 382 | result = YPERR_NODOM; |
ee74a442 UD |
383 | else if (strcmp (__ypdomainname, "(none)") == 0) |
384 | { | |
385 | /* If domainname is not set, some Systems will return "(none)" */ | |
386 | __ypdomainname[0] = '\0'; | |
387 | result = YPERR_NODOM; | |
388 | } | |
6259ec0d UD |
389 | else |
390 | *outdomain = __ypdomainname; | |
391 | } | |
392 | else | |
393 | *outdomain = __ypdomainname; | |
394 | ||
395 | __libc_lock_unlock (domainname_lock); | |
396 | ||
397 | return result; | |
398 | } | |
399 | ||
400 | int | |
401 | __yp_check (char **domain) | |
402 | { | |
403 | char *unused; | |
404 | ||
405 | if (__ypdomainname[0] == '\0') | |
406 | if (yp_get_default_domain (&unused)) | |
407 | return 0; | |
6259ec0d UD |
408 | |
409 | if (domain) | |
410 | *domain = __ypdomainname; | |
411 | ||
412 | if (yp_bind (__ypdomainname) == 0) | |
413 | return 1; | |
414 | return 0; | |
415 | } | |
416 | ||
417 | int | |
418 | yp_match (const char *indomain, const char *inmap, const char *inkey, | |
419 | const int inkeylen, char **outval, int *outvallen) | |
420 | { | |
421 | ypreq_key req; | |
422 | ypresp_val resp; | |
d111572f | 423 | enum clnt_stat result; |
6259ec0d UD |
424 | |
425 | if (indomain == NULL || indomain[0] == '\0' || | |
426 | inmap == NULL || inmap[0] == '\0' || | |
427 | inkey == NULL || inkey[0] == '\0' || inkeylen <= 0) | |
428 | return YPERR_BADARGS; | |
429 | ||
68dbb3a6 UD |
430 | req.domain = (char *) indomain; |
431 | req.map = (char *) inmap; | |
432 | req.key.keydat_val = (char *) inkey; | |
6259ec0d UD |
433 | req.key.keydat_len = inkeylen; |
434 | ||
435 | *outval = NULL; | |
436 | *outvallen = 0; | |
437 | memset (&resp, '\0', sizeof (resp)); | |
438 | ||
439 | result = do_ypcall (indomain, YPPROC_MATCH, (xdrproc_t) xdr_ypreq_key, | |
440 | (caddr_t) & req, (xdrproc_t) xdr_ypresp_val, | |
441 | (caddr_t) & resp); | |
442 | ||
4bca4c17 UD |
443 | if (result != YPERR_SUCCESS) |
444 | return result; | |
6259ec0d UD |
445 | if (resp.stat != YP_TRUE) |
446 | return ypprot_err (resp.stat); | |
447 | ||
448 | *outvallen = resp.val.valdat_len; | |
449 | *outval = malloc (*outvallen + 1); | |
450 | memcpy (*outval, resp.val.valdat_val, *outvallen); | |
451 | (*outval)[*outvallen] = '\0'; | |
452 | ||
453 | xdr_free ((xdrproc_t) xdr_ypresp_val, (char *) &resp); | |
454 | ||
455 | return YPERR_SUCCESS; | |
456 | } | |
457 | ||
458 | int | |
459 | yp_first (const char *indomain, const char *inmap, char **outkey, | |
460 | int *outkeylen, char **outval, int *outvallen) | |
461 | { | |
462 | ypreq_nokey req; | |
463 | ypresp_key_val resp; | |
d111572f | 464 | enum clnt_stat result; |
6259ec0d UD |
465 | |
466 | if (indomain == NULL || indomain[0] == '\0' || | |
467 | inmap == NULL || inmap[0] == '\0') | |
468 | return YPERR_BADARGS; | |
469 | ||
68dbb3a6 UD |
470 | req.domain = (char *) indomain; |
471 | req.map = (char *) inmap; | |
6259ec0d UD |
472 | |
473 | *outkey = *outval = NULL; | |
474 | *outkeylen = *outvallen = 0; | |
475 | memset (&resp, '\0', sizeof (resp)); | |
476 | ||
477 | result = do_ypcall (indomain, YPPROC_FIRST, (xdrproc_t) xdr_ypreq_nokey, | |
478 | (caddr_t) & req, (xdrproc_t) xdr_ypresp_key_val, | |
479 | (caddr_t) & resp); | |
480 | ||
481 | if (result != RPC_SUCCESS) | |
d111572f | 482 | return YPERR_RPC; |
6259ec0d UD |
483 | if (resp.stat != YP_TRUE) |
484 | return ypprot_err (resp.stat); | |
485 | ||
486 | *outkeylen = resp.key.keydat_len; | |
487 | *outkey = malloc (*outkeylen + 1); | |
488 | memcpy (*outkey, resp.key.keydat_val, *outkeylen); | |
489 | (*outkey)[*outkeylen] = '\0'; | |
490 | *outvallen = resp.val.valdat_len; | |
491 | *outval = malloc (*outvallen + 1); | |
492 | memcpy (*outval, resp.val.valdat_val, *outvallen); | |
493 | (*outval)[*outvallen] = '\0'; | |
494 | ||
495 | xdr_free ((xdrproc_t) xdr_ypresp_key_val, (char *) &resp); | |
496 | ||
497 | return YPERR_SUCCESS; | |
498 | } | |
499 | ||
500 | int | |
501 | yp_next (const char *indomain, const char *inmap, const char *inkey, | |
502 | const int inkeylen, char **outkey, int *outkeylen, char **outval, | |
503 | int *outvallen) | |
504 | { | |
505 | ypreq_key req; | |
506 | ypresp_key_val resp; | |
d111572f | 507 | enum clnt_stat result; |
6259ec0d UD |
508 | |
509 | if (indomain == NULL || indomain[0] == '\0' || | |
510 | inmap == NULL || inmap[0] == '\0' || | |
511 | inkeylen <= 0 || inkey == NULL || inkey[0] == '\0') | |
512 | return YPERR_BADARGS; | |
513 | ||
68dbb3a6 UD |
514 | req.domain = (char *) indomain; |
515 | req.map = (char *) inmap; | |
516 | req.key.keydat_val = (char *) inkey; | |
6259ec0d UD |
517 | req.key.keydat_len = inkeylen; |
518 | ||
519 | *outkey = *outval = NULL; | |
520 | *outkeylen = *outvallen = 0; | |
521 | memset (&resp, '\0', sizeof (resp)); | |
522 | ||
523 | result = do_ypcall (indomain, YPPROC_NEXT, (xdrproc_t) xdr_ypreq_key, | |
524 | (caddr_t) & req, (xdrproc_t) xdr_ypresp_key_val, | |
525 | (caddr_t) & resp); | |
526 | ||
4bca4c17 UD |
527 | if (result != YPERR_SUCCESS) |
528 | return result; | |
6259ec0d UD |
529 | if (resp.stat != YP_TRUE) |
530 | return ypprot_err (resp.stat); | |
531 | ||
532 | *outkeylen = resp.key.keydat_len; | |
533 | *outkey = malloc (*outkeylen + 1); | |
534 | memcpy (*outkey, resp.key.keydat_val, *outkeylen); | |
535 | (*outkey)[*outkeylen] = '\0'; | |
536 | *outvallen = resp.val.valdat_len; | |
537 | *outval = malloc (*outvallen + 1); | |
538 | memcpy (*outval, resp.val.valdat_val, *outvallen); | |
539 | (*outval)[*outvallen] = '\0'; | |
540 | ||
541 | xdr_free ((xdrproc_t) xdr_ypresp_key_val, (char *) &resp); | |
542 | ||
543 | return YPERR_SUCCESS; | |
544 | } | |
545 | ||
546 | int | |
547 | yp_master (const char *indomain, const char *inmap, char **outname) | |
548 | { | |
549 | ypreq_nokey req; | |
550 | ypresp_master resp; | |
d111572f | 551 | enum clnt_stat result; |
6259ec0d UD |
552 | |
553 | if (indomain == NULL || indomain[0] == '\0' || | |
554 | inmap == NULL || inmap[0] == '\0') | |
555 | return YPERR_BADARGS; | |
556 | ||
68dbb3a6 UD |
557 | req.domain = (char *) indomain; |
558 | req.map = (char *) inmap; | |
6259ec0d UD |
559 | |
560 | memset (&resp, '\0', sizeof (ypresp_master)); | |
561 | ||
562 | result = do_ypcall (indomain, YPPROC_MASTER, (xdrproc_t) xdr_ypreq_nokey, | |
563 | (caddr_t) & req, (xdrproc_t) xdr_ypresp_master, (caddr_t) & resp); | |
564 | ||
4bca4c17 UD |
565 | if (result != YPERR_SUCCESS) |
566 | return result; | |
6259ec0d UD |
567 | if (resp.stat != YP_TRUE) |
568 | return ypprot_err (resp.stat); | |
569 | ||
570 | *outname = strdup (resp.peer); | |
571 | xdr_free ((xdrproc_t) xdr_ypresp_master, (char *) &resp); | |
572 | ||
d111572f | 573 | return *outname == NULL ? YPERR_YPERR : YPERR_SUCCESS; |
6259ec0d UD |
574 | } |
575 | ||
576 | int | |
577 | yp_order (const char *indomain, const char *inmap, unsigned int *outorder) | |
578 | { | |
579 | struct ypreq_nokey req; | |
580 | struct ypresp_order resp; | |
d111572f | 581 | enum clnt_stat result; |
6259ec0d UD |
582 | |
583 | if (indomain == NULL || indomain[0] == '\0' || | |
584 | inmap == NULL || inmap == '\0') | |
585 | return YPERR_BADARGS; | |
586 | ||
68dbb3a6 UD |
587 | req.domain = (char *) indomain; |
588 | req.map = (char *) inmap; | |
6259ec0d UD |
589 | |
590 | memset (&resp, '\0', sizeof (resp)); | |
591 | ||
592 | result = do_ypcall (indomain, YPPROC_ORDER, (xdrproc_t) xdr_ypreq_nokey, | |
593 | (caddr_t) & req, (xdrproc_t) xdr_ypresp_order, (caddr_t) & resp); | |
594 | ||
4bca4c17 UD |
595 | if (result != YPERR_SUCCESS) |
596 | return result; | |
6259ec0d UD |
597 | if (resp.stat != YP_TRUE) |
598 | return ypprot_err (resp.stat); | |
599 | ||
600 | *outorder = resp.ordernum; | |
601 | xdr_free ((xdrproc_t) xdr_ypresp_order, (char *) &resp); | |
602 | ||
603 | return YPERR_SUCCESS; | |
604 | } | |
605 | ||
606 | static void *ypall_data; | |
3e5f5557 UD |
607 | static int (*ypall_foreach) __P ((int status, char *key, int keylen, |
608 | char *val, int vallen, char *data)); | |
6259ec0d UD |
609 | |
610 | static bool_t | |
611 | __xdr_ypresp_all (XDR * xdrs, u_long * objp) | |
612 | { | |
613 | while (1) | |
614 | { | |
615 | struct ypresp_all resp; | |
616 | ||
617 | memset (&resp, '\0', sizeof (struct ypresp_all)); | |
618 | if (!xdr_ypresp_all (xdrs, &resp)) | |
619 | { | |
620 | xdr_free ((xdrproc_t) xdr_ypresp_all, (char *) &resp); | |
621 | *objp = YP_YPERR; | |
d111572f | 622 | return FALSE; |
6259ec0d UD |
623 | } |
624 | if (resp.more == 0) | |
625 | { | |
626 | xdr_free ((xdrproc_t) xdr_ypresp_all, (char *) &resp); | |
627 | *objp = YP_NOMORE; | |
d111572f | 628 | return TRUE; |
6259ec0d UD |
629 | } |
630 | ||
631 | switch (resp.ypresp_all_u.val.stat) | |
632 | { | |
633 | case YP_TRUE: | |
634 | { | |
635 | char key[resp.ypresp_all_u.val.key.keydat_len + 1]; | |
636 | char val[resp.ypresp_all_u.val.val.valdat_len + 1]; | |
637 | int keylen = resp.ypresp_all_u.val.key.keydat_len; | |
638 | int vallen = resp.ypresp_all_u.val.val.valdat_len; | |
639 | ||
640 | *objp = YP_TRUE; | |
641 | memcpy (key, resp.ypresp_all_u.val.key.keydat_val, keylen); | |
642 | key[keylen] = '\0'; | |
643 | memcpy (val, resp.ypresp_all_u.val.val.valdat_val, vallen); | |
644 | val[vallen] = '\0'; | |
645 | xdr_free ((xdrproc_t) xdr_ypresp_all, (char *) &resp); | |
646 | if ((*ypall_foreach) (*objp, key, keylen, | |
647 | val, vallen, ypall_data)) | |
648 | return TRUE; | |
649 | } | |
650 | break; | |
651 | case YP_NOMORE: | |
652 | *objp = YP_NOMORE; | |
653 | xdr_free ((xdrproc_t) xdr_ypresp_all, (char *) &resp); | |
654 | return TRUE; | |
655 | break; | |
656 | default: | |
657 | *objp = resp.ypresp_all_u.val.stat; | |
658 | xdr_free ((xdrproc_t) xdr_ypresp_all, (char *) &resp); | |
659 | return TRUE; | |
660 | } | |
661 | } | |
662 | } | |
663 | ||
664 | int | |
665 | yp_all (const char *indomain, const char *inmap, | |
666 | const struct ypall_callback *incallback) | |
667 | { | |
668 | struct ypreq_nokey req; | |
cc3fa755 | 669 | dom_binding *ydb = NULL; |
d111572f UD |
670 | int try, res; |
671 | enum clnt_stat result; | |
6259ec0d UD |
672 | struct sockaddr_in clnt_sin; |
673 | CLIENT *clnt; | |
674 | unsigned long status; | |
675 | int clnt_sock; | |
a788b6c2 | 676 | int saved_errno = errno; |
6259ec0d UD |
677 | |
678 | if (indomain == NULL || indomain[0] == '\0' || | |
679 | inmap == NULL || inmap == '\0') | |
680 | return YPERR_BADARGS; | |
681 | ||
682 | try = 0; | |
d111572f | 683 | res = YPERR_YPERR; |
6259ec0d | 684 | |
d111572f | 685 | while (try < MAXTRIES && res != YPERR_SUCCESS) |
6259ec0d | 686 | { |
6259ec0d UD |
687 | if (__yp_bind (indomain, &ydb) != 0) |
688 | { | |
a788b6c2 | 689 | __set_errno (saved_errno); |
6259ec0d UD |
690 | return YPERR_DOMAIN; |
691 | } | |
692 | ||
693 | /* YPPROC_ALL get its own TCP channel to ypserv */ | |
694 | clnt_sock = RPC_ANYSOCK; | |
695 | clnt_sin = ydb->dom_server_addr; | |
696 | clnt_sin.sin_port = 0; | |
697 | clnt = clnttcp_create (&clnt_sin, YPPROG, YPVERS, &clnt_sock, 0, 0); | |
698 | if (clnt == NULL) | |
a788b6c2 UD |
699 | { |
700 | __set_errno (saved_errno); | |
701 | return YPERR_PMAP; | |
702 | } | |
68dbb3a6 UD |
703 | req.domain = (char *) indomain; |
704 | req.map = (char *) inmap; | |
6259ec0d UD |
705 | |
706 | ypall_foreach = incallback->foreach; | |
707 | ypall_data = (void *) incallback->data; | |
708 | ||
3e5f5557 UD |
709 | result = clnt_call (clnt, YPPROC_ALL, (xdrproc_t) xdr_ypreq_nokey, |
710 | (caddr_t) &req, (xdrproc_t) __xdr_ypresp_all, | |
cc3fa755 | 711 | (caddr_t) &status, RPCTIMEOUT); |
6259ec0d UD |
712 | |
713 | if (result != RPC_SUCCESS) | |
714 | { | |
d111572f UD |
715 | clnt_perror (clnt, "yp_all: clnt_call"); |
716 | res = YPERR_RPC; | |
6259ec0d UD |
717 | } |
718 | else | |
d111572f UD |
719 | res = YPERR_SUCCESS; |
720 | ||
721 | clnt_destroy (clnt); | |
722 | close (clnt_sock); | |
6259ec0d | 723 | |
6259ec0d | 724 | if (status != YP_NOMORE) |
a788b6c2 UD |
725 | { |
726 | __set_errno (saved_errno); | |
727 | return ypprot_err (status); | |
728 | } | |
729 | ++try; | |
6259ec0d UD |
730 | } |
731 | ||
a788b6c2 UD |
732 | __set_errno (saved_errno); |
733 | ||
d111572f | 734 | return res; |
6259ec0d UD |
735 | } |
736 | ||
737 | int | |
738 | yp_maplist (const char *indomain, struct ypmaplist **outmaplist) | |
739 | { | |
740 | struct ypresp_maplist resp; | |
d111572f | 741 | enum clnt_stat result; |
6259ec0d UD |
742 | |
743 | if (indomain == NULL || indomain[0] == '\0') | |
744 | return YPERR_BADARGS; | |
745 | ||
746 | memset (&resp, '\0', sizeof (resp)); | |
747 | ||
748 | result = do_ypcall (indomain, YPPROC_MAPLIST, (xdrproc_t) xdr_domainname, | |
749 | (caddr_t) & indomain, (xdrproc_t) xdr_ypresp_maplist, (caddr_t) & resp); | |
750 | ||
4bca4c17 UD |
751 | if (result != YPERR_SUCCESS) |
752 | return result; | |
6259ec0d UD |
753 | if (resp.stat != YP_TRUE) |
754 | return ypprot_err (resp.stat); | |
755 | ||
756 | *outmaplist = resp.maps; | |
757 | /* We give the list not free, this will be done by ypserv | |
758 | xdr_free((xdrproc_t)xdr_ypresp_maplist, (char *)&resp); */ | |
759 | ||
760 | return YPERR_SUCCESS; | |
761 | } | |
762 | ||
763 | const char * | |
764 | yperr_string (const int error) | |
765 | { | |
766 | switch (error) | |
767 | { | |
768 | case YPERR_SUCCESS: | |
769 | return _("Success"); | |
770 | case YPERR_BADARGS: | |
771 | return _("Request arguments bad"); | |
772 | case YPERR_RPC: | |
773 | return _("RPC failure on NIS operation"); | |
774 | case YPERR_DOMAIN: | |
775 | return _("Can't bind to server which serves this domain"); | |
776 | case YPERR_MAP: | |
777 | return _("No such map in server's domain"); | |
778 | case YPERR_KEY: | |
779 | return _("No such key in map"); | |
780 | case YPERR_YPERR: | |
781 | return _("Internal NIS error"); | |
782 | case YPERR_RESRC: | |
783 | return _("Local resource allocation failure"); | |
784 | case YPERR_NOMORE: | |
785 | return _("No more records in map database"); | |
786 | case YPERR_PMAP: | |
787 | return _("Can't communicate with portmapper"); | |
788 | case YPERR_YPBIND: | |
789 | return _("Can't communicate with ypbind"); | |
790 | case YPERR_YPSERV: | |
791 | return _("Can't communicate with ypserv"); | |
792 | case YPERR_NODOM: | |
793 | return _("Local domain name not set"); | |
794 | case YPERR_BADDB: | |
bd355af0 | 795 | return _("NIS map database is bad"); |
6259ec0d UD |
796 | case YPERR_VERS: |
797 | return _("NIS client/server version mismatch - can't supply service"); | |
798 | case YPERR_ACCESS: | |
799 | return _("Permission denied"); | |
800 | case YPERR_BUSY: | |
801 | return _("Database is busy"); | |
802 | } | |
803 | return _("Unknown NIS error code"); | |
804 | } | |
805 | ||
806 | int | |
807 | ypprot_err (const int code) | |
808 | { | |
809 | switch (code) | |
810 | { | |
811 | case YP_TRUE: | |
812 | return YPERR_SUCCESS; | |
813 | case YP_NOMORE: | |
814 | return YPERR_NOMORE; | |
815 | case YP_FALSE: | |
816 | return YPERR_YPERR; | |
817 | case YP_NOMAP: | |
818 | return YPERR_MAP; | |
819 | case YP_NODOM: | |
820 | return YPERR_DOMAIN; | |
821 | case YP_NOKEY: | |
822 | return YPERR_KEY; | |
823 | case YP_BADOP: | |
824 | return YPERR_YPERR; | |
825 | case YP_BADDB: | |
826 | return YPERR_BADDB; | |
827 | case YP_YPERR: | |
828 | return YPERR_YPERR; | |
829 | case YP_BADARGS: | |
830 | return YPERR_BADARGS; | |
831 | case YP_VERS: | |
832 | return YPERR_VERS; | |
833 | } | |
834 | return YPERR_YPERR; | |
835 | } | |
836 | ||
837 | const char * | |
838 | ypbinderr_string (const int error) | |
839 | { | |
840 | switch (error) | |
841 | { | |
842 | case 0: | |
843 | return _("Success"); | |
844 | case YPBIND_ERR_ERR: | |
845 | return _("Internal ypbind error"); | |
846 | case YPBIND_ERR_NOSERV: | |
847 | return _("Domain not bound"); | |
848 | case YPBIND_ERR_RESC: | |
849 | return _("System resource allocation failure"); | |
850 | default: | |
851 | return _("Unknown ypbind error"); | |
852 | } | |
853 | } | |
854 | ||
855 | ||
856 | #define WINDOW 60 | |
857 | ||
858 | int | |
859 | yp_update (char *domain, char *map, unsigned ypop, | |
860 | char *key, int keylen, char *data, int datalen) | |
861 | { | |
6259ec0d UD |
862 | union |
863 | { | |
864 | ypupdate_args update_args; | |
865 | ypdelete_args delete_args; | |
866 | } | |
867 | args; | |
868 | xdrproc_t xdr_argument; | |
869 | unsigned res = 0; | |
870 | CLIENT *clnt; | |
871 | char *master; | |
872 | struct sockaddr saddr; | |
873 | char servername[MAXNETNAMELEN + 1]; | |
874 | int r; | |
875 | ||
876 | if (!domain || !map || !key || (ypop != YPOP_DELETE && !data)) | |
877 | return YPERR_BADARGS; | |
878 | ||
879 | args.update_args.mapname = map; | |
880 | args.update_args.key.yp_buf_len = keylen; | |
881 | args.update_args.key.yp_buf_val = key; | |
882 | args.update_args.datum.yp_buf_len = datalen; | |
883 | args.update_args.datum.yp_buf_val = data; | |
884 | ||
885 | if ((r = yp_master (domain, map, &master)) != 0) | |
886 | return r; | |
887 | ||
888 | if (!host2netname (servername, master, domain)) | |
889 | { | |
890 | fputs (_("yp_update: cannot convert host to netname\n"), stderr); | |
891 | return YPERR_YPERR; | |
892 | } | |
893 | ||
894 | if ((clnt = clnt_create (master, YPU_PROG, YPU_VERS, "tcp")) == NULL) | |
895 | { | |
896 | clnt_pcreateerror ("yp_update: clnt_create"); | |
897 | return YPERR_RPC; | |
898 | } | |
899 | ||
900 | if (!clnt_control (clnt, CLGET_SERVER_ADDR, (char *) &saddr)) | |
901 | { | |
902 | fputs (_("yp_update: cannot get server address\n"), stderr); | |
903 | return YPERR_RPC; | |
904 | } | |
905 | ||
906 | switch (ypop) | |
907 | { | |
908 | case YPOP_CHANGE: | |
909 | case YPOP_INSERT: | |
910 | case YPOP_STORE: | |
911 | xdr_argument = (xdrproc_t) xdr_ypupdate_args; | |
912 | break; | |
913 | case YPOP_DELETE: | |
914 | xdr_argument = (xdrproc_t) xdr_ypdelete_args; | |
915 | break; | |
916 | default: | |
917 | return YPERR_BADARGS; | |
918 | break; | |
919 | } | |
920 | ||
921 | clnt->cl_auth = authdes_create (servername, WINDOW, &saddr, NULL); | |
922 | ||
923 | if (clnt->cl_auth == NULL) | |
924 | clnt->cl_auth = authunix_create_default (); | |
925 | ||
926 | again: | |
26dee9c4 | 927 | r = clnt_call (clnt, ypop, xdr_argument, (caddr_t) &args, |
cc3fa755 | 928 | (xdrproc_t) xdr_u_int, (caddr_t) &res, RPCTIMEOUT); |
6259ec0d UD |
929 | |
930 | if (r == RPC_AUTHERROR) | |
931 | { | |
932 | if (clnt->cl_auth->ah_cred.oa_flavor == AUTH_DES) | |
933 | { | |
934 | clnt->cl_auth = authunix_create_default (); | |
935 | goto again; | |
936 | } | |
937 | else | |
938 | return YPERR_ACCESS; | |
939 | } | |
940 | if (r != RPC_SUCCESS) | |
941 | { | |
942 | clnt_perror (clnt, "yp_update: clnt_call"); | |
943 | return YPERR_RPC; | |
944 | } | |
945 | return res; | |
6259ec0d | 946 | } |