Print this page
4729 __rpcb_findaddr_timed should try rpcbind protocol 4 first
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/lib/libnsl/rpc/rpcb_clnt.c
+++ new/usr/src/lib/libnsl/rpc/rpcb_clnt.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License, Version 1.0 only
6 6 * (the "License"). You may not use this file except in compliance
7 7 * with the License.
8 8 *
9 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 10 * or http://www.opensolaris.org/os/licensing.
11 11 * See the License for the specific language governing permissions
12 12 * and limitations under the License.
13 13 *
↓ open down ↓ |
13 lines elided |
↑ open up ↑ |
14 14 * When distributing Covered Code, include this CDDL HEADER in each
15 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 16 * If applicable, add the following below this CDDL HEADER, with the
17 17 * fields enclosed by brackets "[]" replaced with your own identifying
18 18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 19 *
20 20 * CDDL HEADER END
21 21 */
22 22
23 23 /*
24 + * Copyright (c) 2014 Gary Mills
24 25 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
25 26 * Use is subject to license terms.
26 27 */
27 28
28 29 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
29 30 /* All Rights Reserved */
30 31 /*
31 32 * Portions of this source code were derived from Berkeley
32 33 * 4.3 BSD under license from the Regents of the University of
33 34 * California.
34 35 */
35 36
36 -#pragma ident "%Z%%M% %I% %E% SMI"
37 -
38 37 /*
39 38 * interface to rpcbind rpc service.
40 39 */
41 40
42 41 #include "mt.h"
43 42 #include "rpc_mt.h"
44 43 #include <assert.h>
45 44 #include <rpc/rpc.h>
46 45 #include <rpc/rpcb_prot.h>
47 46 #include <netconfig.h>
48 47 #include <netdir.h>
49 48 #include <rpc/nettype.h>
50 49 #include <syslog.h>
51 50 #ifdef PORTMAP
52 51 #include <netinet/in.h> /* FOR IPPROTO_TCP/UDP definitions */
53 52 #include <rpc/pmap_prot.h>
54 53 #endif
55 54 #ifdef ND_DEBUG
56 55 #include <stdio.h>
57 56 #endif
58 57 #include <sys/utsname.h>
59 58 #include <errno.h>
60 59 #include <stdlib.h>
61 60 #include <string.h>
62 61 #include <unistd.h>
63 62
64 63 static struct timeval tottimeout = { 60, 0 };
65 64 static const struct timeval rmttimeout = { 3, 0 };
66 65 static struct timeval rpcbrmttime = { 15, 0 };
67 66
68 67 extern bool_t xdr_wrapstring(XDR *, char **);
69 68
70 69 static const char nullstring[] = "\000";
71 70
72 71 extern CLIENT *_clnt_tli_create_timed(int, const struct netconfig *,
73 72 struct netbuf *, rpcprog_t, rpcvers_t, uint_t, uint_t,
74 73 const struct timeval *);
75 74
76 75 static CLIENT *_getclnthandle_timed(char *, struct netconfig *, char **,
77 76 struct timeval *);
78 77
79 78
80 79 /*
81 80 * The life time of a cached entry should not exceed 5 minutes
82 81 * since automountd attempts an unmount every 5 minutes.
83 82 * It is arbitrarily set a little lower (3 min = 180 sec)
84 83 * to reduce the time during which an entry is stale.
85 84 */
86 85 #define CACHE_TTL 180
87 86 #define CACHESIZE 6
88 87
89 88 struct address_cache {
90 89 char *ac_host;
91 90 char *ac_netid;
92 91 char *ac_uaddr;
93 92 struct netbuf *ac_taddr;
94 93 struct address_cache *ac_next;
95 94 time_t ac_maxtime;
96 95 };
97 96
98 97 static struct address_cache *front;
99 98 static int cachesize;
100 99
101 100 extern int lowvers;
102 101 extern int authdes_cachesz;
103 102 /*
104 103 * This routine adjusts the timeout used for calls to the remote rpcbind.
105 104 * Also, this routine can be used to set the use of portmapper version 2
106 105 * only when doing rpc_broadcasts
107 106 * These are private routines that may not be provided in future releases.
108 107 */
109 108 bool_t
110 109 __rpc_control(int request, void *info)
111 110 {
112 111 switch (request) {
113 112 case CLCR_GET_RPCB_TIMEOUT:
114 113 *(struct timeval *)info = tottimeout;
115 114 break;
116 115 case CLCR_SET_RPCB_TIMEOUT:
117 116 tottimeout = *(struct timeval *)info;
118 117 break;
119 118 case CLCR_GET_LOWVERS:
120 119 *(int *)info = lowvers;
121 120 break;
122 121 case CLCR_SET_LOWVERS:
123 122 lowvers = *(int *)info;
124 123 break;
125 124 case CLCR_GET_RPCB_RMTTIME:
126 125 *(struct timeval *)info = rpcbrmttime;
127 126 break;
128 127 case CLCR_SET_RPCB_RMTTIME:
129 128 rpcbrmttime = *(struct timeval *)info;
130 129 break;
131 130 case CLCR_GET_CRED_CACHE_SZ:
132 131 *(int *)info = authdes_cachesz;
133 132 break;
134 133 case CLCR_SET_CRED_CACHE_SZ:
135 134 authdes_cachesz = *(int *)info;
136 135 break;
137 136 default:
138 137 return (FALSE);
139 138 }
140 139 return (TRUE);
141 140 }
142 141
143 142 /*
144 143 * It might seem that a reader/writer lock would be more reasonable here.
145 144 * However because getclnthandle(), the only user of the cache functions,
146 145 * may do a delete_cache() operation if a check_cache() fails to return an
147 146 * address useful to clnt_tli_create(), we may as well use a mutex.
148 147 */
149 148 /*
150 149 * As it turns out, if the cache lock is *not* a reader/writer lock, we will
151 150 * block all clnt_create's if we are trying to connect to a host that's down,
152 151 * since the lock will be held all during that time.
153 152 */
154 153 extern rwlock_t rpcbaddr_cache_lock;
155 154
156 155 /*
157 156 * The routines check_cache(), add_cache(), delete_cache() manage the
158 157 * cache of rpcbind addresses for (host, netid).
159 158 */
160 159
161 160 static struct address_cache *
↓ open down ↓ |
114 lines elided |
↑ open up ↑ |
162 161 check_cache(char *host, char *netid)
163 162 {
164 163 struct address_cache *cptr;
165 164
166 165 /* READ LOCK HELD ON ENTRY: rpcbaddr_cache_lock */
167 166
168 167 assert(RW_READ_HELD(&rpcbaddr_cache_lock));
169 168 for (cptr = front; cptr != NULL; cptr = cptr->ac_next) {
170 169 if ((strcmp(cptr->ac_host, host) == 0) &&
171 170 (strcmp(cptr->ac_netid, netid) == 0) &&
172 - (time(NULL) <= cptr->ac_maxtime)) {
171 + (time(NULL) <= cptr->ac_maxtime)) {
173 172 #ifdef ND_DEBUG
174 173 fprintf(stderr, "Found cache entry for %s: %s\n",
175 - host, netid);
174 + host, netid);
176 175 #endif
177 176 return (cptr);
178 177 }
179 178 }
180 179 return (NULL);
181 180 }
182 181
183 182 static void
184 183 delete_cache(struct netbuf *addr)
185 184 {
186 185 struct address_cache *cptr, *prevptr = NULL;
187 186
188 187 /* WRITE LOCK HELD ON ENTRY: rpcbaddr_cache_lock */
189 188 assert(RW_WRITE_HELD(&rpcbaddr_cache_lock));
190 189 for (cptr = front; cptr != NULL; cptr = cptr->ac_next) {
191 190 if (!memcmp(cptr->ac_taddr->buf, addr->buf, addr->len)) {
192 191 free(cptr->ac_host);
193 192 free(cptr->ac_netid);
194 193 free(cptr->ac_taddr->buf);
195 194 free(cptr->ac_taddr);
196 195 if (cptr->ac_uaddr)
197 196 free(cptr->ac_uaddr);
198 197 if (prevptr)
199 198 prevptr->ac_next = cptr->ac_next;
200 199 else
201 200 front = cptr->ac_next;
202 201 free(cptr);
203 202 cachesize--;
204 203 break;
205 204 }
206 205 prevptr = cptr;
207 206 }
208 207 }
209 208
210 209 static void
211 210 add_cache(char *host, char *netid, struct netbuf *taddr, char *uaddr)
212 211 {
213 212 struct address_cache *ad_cache, *cptr, *prevptr;
214 213
↓ open down ↓ |
29 lines elided |
↑ open up ↑ |
215 214 ad_cache = malloc(sizeof (struct address_cache));
216 215 if (!ad_cache) {
217 216 goto memerr;
218 217 }
219 218 ad_cache->ac_maxtime = time(NULL) + CACHE_TTL;
220 219 ad_cache->ac_host = strdup(host);
221 220 ad_cache->ac_netid = strdup(netid);
222 221 ad_cache->ac_uaddr = uaddr ? strdup(uaddr) : NULL;
223 222 ad_cache->ac_taddr = malloc(sizeof (struct netbuf));
224 223 if (!ad_cache->ac_host || !ad_cache->ac_netid || !ad_cache->ac_taddr ||
225 - (uaddr && !ad_cache->ac_uaddr)) {
224 + (uaddr && !ad_cache->ac_uaddr)) {
226 225 goto memerr1;
227 226 }
228 227
229 228 ad_cache->ac_taddr->len = ad_cache->ac_taddr->maxlen = taddr->len;
230 229 ad_cache->ac_taddr->buf = malloc(taddr->len);
231 230 if (ad_cache->ac_taddr->buf == NULL) {
232 231 goto memerr1;
233 232 }
234 233
235 234 (void) memcpy(ad_cache->ac_taddr->buf, taddr->buf, taddr->len);
236 235 #ifdef ND_DEBUG
237 236 (void) fprintf(stderr, "Added to cache: %s : %s\n", host, netid);
238 237 #endif
239 238
240 239 /* VARIABLES PROTECTED BY rpcbaddr_cache_lock: cptr */
241 240
242 241 (void) rw_wrlock(&rpcbaddr_cache_lock);
243 242 if (cachesize < CACHESIZE) {
244 243 ad_cache->ac_next = front;
245 244 front = ad_cache;
246 245 cachesize++;
247 246 } else {
↓ open down ↓ |
12 lines elided |
↑ open up ↑ |
248 247 /* Free the last entry */
249 248 cptr = front;
250 249 prevptr = NULL;
251 250 while (cptr->ac_next) {
252 251 prevptr = cptr;
253 252 cptr = cptr->ac_next;
254 253 }
255 254
256 255 #ifdef ND_DEBUG
257 256 fprintf(stderr, "Deleted from cache: %s : %s\n",
258 - cptr->ac_host, cptr->ac_netid);
257 + cptr->ac_host, cptr->ac_netid);
259 258 #endif
260 259 free(cptr->ac_host);
261 260 free(cptr->ac_netid);
262 261 free(cptr->ac_taddr->buf);
263 262 free(cptr->ac_taddr);
264 263 if (cptr->ac_uaddr)
265 264 free(cptr->ac_uaddr);
266 265
267 266 if (prevptr) {
268 267 prevptr->ac_next = NULL;
269 268 ad_cache->ac_next = front;
270 269 front = ad_cache;
271 270 } else {
272 271 front = ad_cache;
273 272 ad_cache->ac_next = NULL;
274 273 }
275 274 free(cptr);
276 275 }
277 276 (void) rw_unlock(&rpcbaddr_cache_lock);
278 277 return;
279 278 memerr1:
280 279 if (ad_cache->ac_host)
281 280 free(ad_cache->ac_host);
282 281 if (ad_cache->ac_netid)
283 282 free(ad_cache->ac_netid);
284 283 if (ad_cache->ac_uaddr)
285 284 free(ad_cache->ac_uaddr);
286 285 if (ad_cache->ac_taddr)
287 286 free(ad_cache->ac_taddr);
288 287 free(ad_cache);
289 288 memerr:
290 289 syslog(LOG_ERR, "add_cache : out of memory.");
291 290 }
292 291
293 292 /*
294 293 * This routine will return a client handle that is connected to the
295 294 * rpcbind. Returns NULL on error and free's everything.
296 295 */
297 296 static CLIENT *
298 297 getclnthandle(char *host, struct netconfig *nconf, char **targaddr)
299 298 {
300 299 return (_getclnthandle_timed(host, nconf, targaddr, NULL));
301 300 }
302 301
303 302 /*
304 303 * Same as getclnthandle() except it takes an extra timeout argument.
305 304 * This is for bug 4049792: clnt_create_timed does not timeout.
306 305 *
307 306 * If tp is NULL, use default timeout to get a client handle.
308 307 */
309 308 static CLIENT *
310 309 _getclnthandle_timed(char *host, struct netconfig *nconf, char **targaddr,
311 310 struct timeval *tp)
312 311 {
313 312 CLIENT *client = NULL;
314 313 struct netbuf *addr;
315 314 struct netbuf addr_to_delete;
316 315 struct nd_addrlist *nas;
317 316 struct nd_hostserv rpcbind_hs;
318 317 struct address_cache *ad_cache;
319 318 char *tmpaddr;
320 319 int neterr;
321 320 int j;
↓ open down ↓ |
53 lines elided |
↑ open up ↑ |
322 321
323 322 /* VARIABLES PROTECTED BY rpcbaddr_cache_lock: ad_cache */
324 323
325 324 /* Get the address of the rpcbind. Check cache first */
326 325 addr_to_delete.len = 0;
327 326 (void) rw_rdlock(&rpcbaddr_cache_lock);
328 327 ad_cache = check_cache(host, nconf->nc_netid);
329 328 if (ad_cache != NULL) {
330 329 addr = ad_cache->ac_taddr;
331 330 client = _clnt_tli_create_timed(RPC_ANYFD, nconf, addr,
332 - RPCBPROG, RPCBVERS4, 0, 0, tp);
331 + RPCBPROG, RPCBVERS4, 0, 0, tp);
333 332 if (client != NULL) {
334 333 if (targaddr) {
335 334 /*
336 335 * case where a client handle is created
337 336 * without a targaddr and the handle is
338 337 * requested with a targaddr
339 338 */
340 339 if (ad_cache->ac_uaddr != NULL) {
341 340 *targaddr = strdup(ad_cache->ac_uaddr);
342 341 if (*targaddr == NULL) {
343 342 syslog(LOG_ERR,
344 343 "_getclnthandle_timed: strdup "
345 344 "failed.");
346 345 rpc_createerr.cf_stat =
347 - RPC_SYSTEMERROR;
346 + RPC_SYSTEMERROR;
348 347 (void) rw_unlock(
349 - &rpcbaddr_cache_lock);
348 + &rpcbaddr_cache_lock);
350 349 return (NULL);
351 350 }
352 351 } else {
353 352 *targaddr = NULL;
354 353 }
355 354 }
356 355 (void) rw_unlock(&rpcbaddr_cache_lock);
357 356 return (client);
358 357 }
359 358 if (rpc_createerr.cf_stat == RPC_SYSTEMERROR) {
360 359 (void) rw_unlock(&rpcbaddr_cache_lock);
361 360 return (NULL);
362 361 }
363 362 addr_to_delete.len = addr->len;
364 363 addr_to_delete.buf = malloc(addr->len);
365 364 if (addr_to_delete.buf == NULL) {
366 365 addr_to_delete.len = 0;
367 366 } else {
368 367 (void) memcpy(addr_to_delete.buf, addr->buf, addr->len);
369 368 }
370 369 }
371 370 (void) rw_unlock(&rpcbaddr_cache_lock);
372 371 if (addr_to_delete.len != 0) {
373 372 /*
374 373 * Assume this may be due to cache data being
375 374 * outdated
376 375 */
↓ open down ↓ |
17 lines elided |
↑ open up ↑ |
377 376 (void) rw_wrlock(&rpcbaddr_cache_lock);
378 377 delete_cache(&addr_to_delete);
379 378 (void) rw_unlock(&rpcbaddr_cache_lock);
380 379 free(addr_to_delete.buf);
381 380 }
382 381 rpcbind_hs.h_host = host;
383 382 rpcbind_hs.h_serv = "rpcbind";
384 383 #ifdef ND_DEBUG
385 384 fprintf(stderr, "rpcbind client routines: diagnostics :\n");
386 385 fprintf(stderr, "\tGetting address for (%s, %s, %s) ... \n",
387 - rpcbind_hs.h_host, rpcbind_hs.h_serv, nconf->nc_netid);
386 + rpcbind_hs.h_host, rpcbind_hs.h_serv, nconf->nc_netid);
388 387 #endif
389 388
390 389 if ((neterr = netdir_getbyname(nconf, &rpcbind_hs, &nas)) != 0) {
391 390 if (neterr == ND_NOHOST)
392 391 rpc_createerr.cf_stat = RPC_UNKNOWNHOST;
393 392 else
394 393 rpc_createerr.cf_stat = RPC_N2AXLATEFAILURE;
395 394 return (NULL);
396 395 }
397 396 /* XXX nas should perhaps be cached for better performance */
398 397
399 398 for (j = 0; j < nas->n_cnt; j++) {
400 399 addr = &(nas->n_addrs[j]);
↓ open down ↓ |
3 lines elided |
↑ open up ↑ |
401 400 #ifdef ND_DEBUG
402 401 {
403 402 int i;
404 403 char *ua;
405 404
406 405 ua = taddr2uaddr(nconf, &(nas->n_addrs[j]));
407 406 fprintf(stderr, "Got it [%s]\n", ua);
408 407 free(ua);
409 408
410 409 fprintf(stderr, "\tnetbuf len = %d, maxlen = %d\n",
411 - addr->len, addr->maxlen);
410 + addr->len, addr->maxlen);
412 411 fprintf(stderr, "\tAddress is ");
413 412 for (i = 0; i < addr->len; i++)
414 413 fprintf(stderr, "%u.", addr->buf[i]);
415 414 fprintf(stderr, "\n");
416 415 }
417 416 #endif
418 417 client = _clnt_tli_create_timed(RPC_ANYFD, nconf, addr, RPCBPROG,
419 418 RPCBVERS4, 0, 0, tp);
420 419 if (client)
421 420 break;
422 421 }
423 422 #ifdef ND_DEBUG
424 423 if (!client) {
425 424 clnt_pcreateerror("rpcbind clnt interface");
426 425 }
427 426 #endif
428 427
429 428 if (client) {
430 429 tmpaddr = targaddr ? taddr2uaddr(nconf, addr) : NULL;
431 430 add_cache(host, nconf->nc_netid, addr, tmpaddr);
432 431 if (targaddr) {
433 432 *targaddr = tmpaddr;
434 433 }
435 434 }
436 435 netdir_free((char *)nas, ND_ADDRLIST);
437 436 return (client);
438 437 }
439 438
440 439 /*
441 440 * This routine will return a client handle that is connected to the local
442 441 * rpcbind. Returns NULL on error and free's everything.
443 442 */
444 443 static CLIENT *
445 444 local_rpcb(void)
446 445 {
447 446 static struct netconfig *loopnconf;
448 447 static char *hostname;
449 448 extern mutex_t loopnconf_lock;
450 449
↓ open down ↓ |
29 lines elided |
↑ open up ↑ |
451 450 /* VARIABLES PROTECTED BY loopnconf_lock: loopnconf */
452 451 (void) mutex_lock(&loopnconf_lock);
453 452 if (loopnconf == NULL) {
454 453 struct utsname utsname;
455 454 struct netconfig *nconf, *tmpnconf = NULL;
456 455 void *nc_handle;
457 456
458 457 if (hostname == NULL) {
459 458 #if defined(__i386) && !defined(__amd64)
460 459 if ((_nuname(&utsname) == -1) ||
460 + ((hostname = strdup(utsname.nodename)) == NULL)) {
461 461 #else
462 462 if ((uname(&utsname) == -1) ||
463 -#endif
464 463 ((hostname = strdup(utsname.nodename)) == NULL)) {
464 +#endif
465 465 syslog(LOG_ERR, "local_rpcb : strdup failed.");
466 466 rpc_createerr.cf_stat = RPC_UNKNOWNHOST;
467 467 (void) mutex_unlock(&loopnconf_lock);
468 468 return (NULL);
469 469 }
470 470 }
471 471 nc_handle = setnetconfig();
472 472 if (nc_handle == NULL) {
473 473 /* fails to open netconfig file */
474 474 rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
475 475 (void) mutex_unlock(&loopnconf_lock);
476 476 return (NULL);
477 477 }
478 478 while (nconf = getnetconfig(nc_handle)) {
479 479 if (strcmp(nconf->nc_protofmly, NC_LOOPBACK) == 0) {
480 480 tmpnconf = nconf;
481 481 if (nconf->nc_semantics == NC_TPI_CLTS)
482 482 break;
483 483 }
484 484 }
485 485 if (tmpnconf == NULL) {
486 486 rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
487 487 (void) mutex_unlock(&loopnconf_lock);
488 488 return (NULL);
489 489 }
490 490 loopnconf = getnetconfigent(tmpnconf->nc_netid);
491 491 /* loopnconf is never freed */
492 492 (void) endnetconfig(nc_handle);
493 493 }
494 494 (void) mutex_unlock(&loopnconf_lock);
495 495 return (getclnthandle(hostname, loopnconf, NULL));
496 496 }
497 497
498 498 /*
499 499 * Set a mapping between program, version and address.
500 500 * Calls the rpcbind service to do the mapping.
501 501 */
502 502 bool_t
503 503 rpcb_set(const rpcprog_t program, const rpcvers_t version,
504 504 const struct netconfig *nconf, const struct netbuf *address)
505 505 {
506 506 CLIENT *client;
507 507 bool_t rslt = FALSE;
508 508 RPCB parms;
509 509 char uidbuf[32];
510 510
511 511 /* parameter checking */
512 512 if (nconf == NULL) {
513 513 rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
514 514 return (FALSE);
↓ open down ↓ |
40 lines elided |
↑ open up ↑ |
515 515 }
516 516 if (address == NULL) {
517 517 rpc_createerr.cf_stat = RPC_UNKNOWNADDR;
518 518 return (FALSE);
519 519 }
520 520 client = local_rpcb();
521 521 if (!client)
522 522 return (FALSE);
523 523
524 524 parms.r_addr = taddr2uaddr((struct netconfig *)nconf,
525 - (struct netbuf *)address); /* convert to universal */
525 + (struct netbuf *)address); /* convert to universal */
526 526 if (!parms.r_addr) {
527 527 rpc_createerr.cf_stat = RPC_N2AXLATEFAILURE;
528 528 return (FALSE); /* no universal address */
529 529 }
530 530 parms.r_prog = program;
531 531 parms.r_vers = version;
532 532 parms.r_netid = nconf->nc_netid;
533 533 /*
534 534 * Though uid is not being used directly, we still send it for
535 535 * completeness. For non-unix platforms, perhaps some other
536 536 * string or an empty string can be sent.
537 537 */
538 538 (void) sprintf(uidbuf, "%d", (int)geteuid());
539 539 parms.r_owner = uidbuf;
540 540
541 541 CLNT_CALL(client, RPCBPROC_SET, (xdrproc_t)xdr_rpcb, (char *)&parms,
542 - (xdrproc_t)xdr_bool, (char *)&rslt, tottimeout);
542 + (xdrproc_t)xdr_bool, (char *)&rslt, tottimeout);
543 543
544 544 CLNT_DESTROY(client);
545 545 free(parms.r_addr);
546 546 return (rslt);
547 547 }
548 548
549 549 /*
550 550 * Remove the mapping between program, version and netbuf address.
551 551 * Calls the rpcbind service to do the un-mapping.
552 552 * If netbuf is NULL, unset for all the transports, otherwise unset
553 553 * only for the given transport.
554 554 */
555 555 bool_t
556 556 rpcb_unset(const rpcprog_t program, const rpcvers_t version,
557 557 const struct netconfig *nconf)
558 558 {
559 559 CLIENT *client;
560 560 bool_t rslt = FALSE;
561 561 RPCB parms;
562 562 char uidbuf[32];
563 563
564 564 client = local_rpcb();
565 565 if (!client)
566 566 return (FALSE);
567 567
568 568 parms.r_prog = program;
↓ open down ↓ |
16 lines elided |
↑ open up ↑ |
569 569 parms.r_vers = version;
570 570 if (nconf)
571 571 parms.r_netid = nconf->nc_netid;
572 572 else
573 573 parms.r_netid = (char *)&nullstring[0]; /* unsets all */
574 574 parms.r_addr = (char *)&nullstring[0];
575 575 (void) sprintf(uidbuf, "%d", (int)geteuid());
576 576 parms.r_owner = uidbuf;
577 577
578 578 CLNT_CALL(client, RPCBPROC_UNSET, (xdrproc_t)xdr_rpcb, (char *)&parms,
579 - (xdrproc_t)xdr_bool, (char *)&rslt, tottimeout);
579 + (xdrproc_t)xdr_bool, (char *)&rslt, tottimeout);
580 580
581 581 CLNT_DESTROY(client);
582 582 return (rslt);
583 583 }
584 584
585 585 /*
586 586 * From the merged list, find the appropriate entry
587 587 */
588 588 static struct netbuf *
589 589 got_entry(rpcb_entry_list_ptr relp, struct netconfig *nconf)
590 590 {
591 591 struct netbuf *na = NULL;
592 592 rpcb_entry_list_ptr sp;
593 593 rpcb_entry *rmap;
↓ open down ↓ |
4 lines elided |
↑ open up ↑ |
594 594
595 595 for (sp = relp; sp != NULL; sp = sp->rpcb_entry_next) {
596 596 rmap = &sp->rpcb_entry_map;
597 597 if ((strcmp(nconf->nc_proto, rmap->r_nc_proto) == 0) &&
598 598 (strcmp(nconf->nc_protofmly, rmap->r_nc_protofmly) == 0) &&
599 599 (nconf->nc_semantics == rmap->r_nc_semantics) &&
600 600 (rmap->r_maddr != NULL) && (rmap->r_maddr[0] != NULL)) {
601 601 na = uaddr2taddr(nconf, rmap->r_maddr);
602 602 #ifdef ND_DEBUG
603 603 fprintf(stderr, "\tRemote address is [%s].\n",
604 - rmap->r_maddr);
604 + rmap->r_maddr);
605 605 if (!na)
606 606 fprintf(stderr,
607 607 "\tCouldn't resolve remote address!\n");
608 608 #endif
609 609 break;
610 610 }
611 611 }
612 612 return (na);
613 613 }
614 614
615 615 /*
616 616 * Quick check to see if rpcbind is up. Tries to connect over
617 617 * local transport.
618 618 */
619 619 bool_t
620 620 __rpcbind_is_up(void)
621 621 {
622 622 struct utsname name;
623 623 char uaddr[SYS_NMLN];
624 624 struct netbuf *addr;
625 625 int fd;
626 626 struct t_call *sndcall;
627 627 struct netconfig *netconf;
628 628 bool_t res;
629 629
630 630 #if defined(__i386) && !defined(__amd64)
631 631 if (_nuname(&name) == -1)
632 632 #else
633 633 if (uname(&name) == -1)
634 634 #endif
635 635 return (TRUE);
636 636
637 637 if ((fd = t_open("/dev/ticotsord", O_RDWR, NULL)) == -1)
638 638 return (TRUE);
639 639
640 640 if (t_bind(fd, NULL, NULL) == -1) {
641 641 (void) t_close(fd);
642 642 return (TRUE);
643 643 }
644 644
645 645 /* LINTED pointer cast */
646 646 if ((sndcall = (struct t_call *)t_alloc(fd, T_CALL, 0)) == NULL) {
647 647 (void) t_close(fd);
648 648 return (TRUE);
649 649 }
650 650
651 651 uaddr[0] = '\0';
652 652 (void) strcpy(uaddr, name.nodename);
653 653 (void) strcat(uaddr, ".rpc");
654 654 if ((netconf = getnetconfigent("ticotsord")) == NULL) {
655 655 (void) t_free((char *)sndcall, T_CALL);
656 656 (void) t_close(fd);
657 657 return (FALSE);
658 658 }
659 659 addr = uaddr2taddr(netconf, uaddr);
660 660 freenetconfigent(netconf);
661 661 if (addr == NULL || addr->buf == NULL) {
662 662 if (addr)
663 663 free(addr);
664 664 (void) t_free((char *)sndcall, T_CALL);
665 665 (void) t_close(fd);
666 666 return (FALSE);
667 667 }
668 668 sndcall->addr.maxlen = addr->maxlen;
669 669 sndcall->addr.len = addr->len;
670 670 sndcall->addr.buf = addr->buf;
671 671
672 672 if (t_connect(fd, sndcall, NULL) == -1)
673 673 res = FALSE;
674 674 else
675 675 res = TRUE;
676 676
677 677 sndcall->addr.maxlen = sndcall->addr.len = 0;
678 678 sndcall->addr.buf = NULL;
↓ open down ↓ |
64 lines elided |
↑ open up ↑ |
679 679 (void) t_free((char *)sndcall, T_CALL);
680 680 free(addr->buf);
681 681 free(addr);
682 682 (void) t_close(fd);
683 683
684 684 return (res);
685 685 }
686 686
687 687
688 688 /*
689 - * An internal function which optimizes rpcb_getaddr function. It also
689 + * An internal function which optimizes rpcb_getaddr function. It returns
690 + * the universal address of the remote service or NULL. It also optionally
690 691 * returns the client handle that it uses to contact the remote rpcbind.
691 692 *
692 - * The algorithm used: If the transports is TCP or UDP, it first tries
693 - * version 2 (portmap), 4 and then 3 (svr4). This order should be
694 - * changed in the next OS release to 4, 2 and 3. We are assuming that by
695 - * that time, version 4 would be available on many machines on the network.
693 + * The algorithm used: First try version 4. Then try version 3 (svr4).
694 + * Finally, if the transport is TCP or UDP, try version 2 (portmap).
695 + * We assume that version 4 is now available on many machines on the network.
696 696 * With this algorithm, we get performance as well as a plan for
697 697 * obsoleting version 2.
698 698 *
699 - * For all other transports, the algorithm remains as 4 and then 3.
700 - *
701 699 * XXX: Due to some problems with t_connect(), we do not reuse the same client
702 700 * handle for COTS cases and hence in these cases we do not return the
703 701 * client handle. This code will change if t_connect() ever
704 702 * starts working properly. Also look under clnt_vc.c.
705 703 */
706 704 struct netbuf *
707 705 __rpcb_findaddr_timed(rpcprog_t program, rpcvers_t version,
708 706 struct netconfig *nconf, char *host, CLIENT **clpp, struct timeval *tp)
709 707 {
710 708 static bool_t check_rpcbind = TRUE;
711 709 CLIENT *client = NULL;
712 710 RPCB parms;
713 711 enum clnt_stat clnt_st;
714 712 char *ua = NULL;
715 713 uint_t vers;
716 714 struct netbuf *address = NULL;
717 - uint_t start_vers = RPCBVERS4;
715 + void *handle;
716 + rpcb_entry_list_ptr relp = NULL;
717 + bool_t tmp_client = FALSE;
718 718
719 719 /* parameter checking */
720 720 if (nconf == NULL) {
721 721 rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
722 722 return (NULL);
723 723 }
724 724
725 725 parms.r_addr = NULL;
726 726
727 727 /*
728 728 * Use default total timeout if no timeout is specified.
729 729 */
730 730 if (tp == NULL)
731 731 tp = &tottimeout;
732 732
733 -#ifdef PORTMAP
734 - /* Try version 2 for TCP or UDP */
735 - if (strcmp(nconf->nc_protofmly, NC_INET) == 0) {
736 - ushort_t port = 0;
737 - struct netbuf remote;
738 - uint_t pmapvers = 2;
739 - struct pmap pmapparms;
740 -
741 - /*
742 - * Try UDP only - there are some portmappers out
743 - * there that use UDP only.
744 - */
745 - if (strcmp(nconf->nc_proto, NC_TCP) == 0) {
746 - struct netconfig *newnconf;
747 - void *handle;
748 -
749 - if ((handle = __rpc_setconf("udp")) == NULL) {
750 - rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
751 - return (NULL);
752 - }
753 -
754 - /*
755 - * The following to reinforce that you can
756 - * only request for remote address through
757 - * the same transport you are requesting.
758 - * ie. requesting unversial address
759 - * of IPv4 has to be carried through IPv4.
760 - * Can't use IPv6 to send out the request.
761 - * The mergeaddr in rpcbind can't handle
762 - * this.
763 - */
764 - for (;;) {
765 - if ((newnconf = __rpc_getconf(handle))
766 - == NULL) {
767 - __rpc_endconf(handle);
768 - rpc_createerr.cf_stat =
769 - RPC_UNKNOWNPROTO;
770 - return (NULL);
771 - }
772 - /*
773 - * here check the protocol family to
774 - * be consistent with the request one
775 - */
776 - if (strcmp(newnconf->nc_protofmly,
777 - nconf->nc_protofmly) == NULL)
778 - break;
779 - }
780 -
781 - client = _getclnthandle_timed(host, newnconf,
782 - &parms.r_addr, tp);
783 - __rpc_endconf(handle);
784 - } else {
785 - client = _getclnthandle_timed(host, nconf,
786 - &parms.r_addr, tp);
787 - }
788 - if (client == NULL)
789 - return (NULL);
790 -
791 - /*
792 - * Set version and retry timeout.
793 - */
794 - CLNT_CONTROL(client, CLSET_RETRY_TIMEOUT, (char *)&rpcbrmttime);
795 - CLNT_CONTROL(client, CLSET_VERS, (char *)&pmapvers);
796 -
797 - pmapparms.pm_prog = program;
798 - pmapparms.pm_vers = version;
799 - pmapparms.pm_prot = strcmp(nconf->nc_proto, NC_TCP) ?
800 - IPPROTO_UDP : IPPROTO_TCP;
801 - pmapparms.pm_port = 0; /* not needed */
802 - clnt_st = CLNT_CALL(client, PMAPPROC_GETPORT,
803 - (xdrproc_t)xdr_pmap, (caddr_t)&pmapparms,
804 - (xdrproc_t)xdr_u_short, (caddr_t)&port,
805 - *tp);
806 - if (clnt_st != RPC_SUCCESS) {
807 - if ((clnt_st == RPC_PROGVERSMISMATCH) ||
808 - (clnt_st == RPC_PROGUNAVAIL))
809 - goto try_rpcbind; /* Try different versions */
810 - rpc_createerr.cf_stat = RPC_PMAPFAILURE;
811 - clnt_geterr(client, &rpc_createerr.cf_error);
812 - goto error;
813 - } else if (port == 0) {
814 - address = NULL;
815 - rpc_createerr.cf_stat = RPC_PROGNOTREGISTERED;
816 - goto error;
817 - }
818 - port = htons(port);
819 - CLNT_CONTROL(client, CLGET_SVC_ADDR, (char *)&remote);
820 - if (((address = malloc(sizeof (struct netbuf))) == NULL) ||
821 - ((address->buf = malloc(remote.len)) == NULL)) {
822 - rpc_createerr.cf_stat = RPC_SYSTEMERROR;
823 - clnt_geterr(client, &rpc_createerr.cf_error);
824 - if (address) {
825 - free(address);
826 - address = NULL;
827 - }
828 - goto error;
829 - }
830 - (void) memcpy(address->buf, remote.buf, remote.len);
831 - (void) memcpy(&address->buf[sizeof (short)], &port,
832 - sizeof (short));
833 - address->len = address->maxlen = remote.len;
834 - goto done;
835 - }
836 -#endif
837 -
838 -try_rpcbind:
839 733 /*
840 734 * Check if rpcbind is up. This prevents needless delays when
841 735 * accessing applications such as the keyserver while booting
842 736 * disklessly.
843 737 */
844 738 if (check_rpcbind && strcmp(nconf->nc_protofmly, NC_LOOPBACK) == 0) {
845 739 if (!__rpcbind_is_up()) {
846 740 rpc_createerr.cf_stat = RPC_PMAPFAILURE;
847 741 rpc_createerr.cf_error.re_errno = 0;
848 742 rpc_createerr.cf_error.re_terrno = 0;
849 743 goto error;
850 744 }
851 745 check_rpcbind = FALSE;
852 746 }
853 747
854 748 /*
855 - * Now we try version 4 and then 3.
856 - * We also send the remote system the address we used to
857 - * contact it in case it can help to connect back with us
749 + * First try version 4.
858 750 */
859 751 parms.r_prog = program;
860 752 parms.r_vers = version;
861 753 parms.r_owner = (char *)&nullstring[0]; /* not needed; */
862 754 /* just for xdring */
863 755 parms.r_netid = nconf->nc_netid; /* not really needed */
864 756
865 757 /*
866 758 * If a COTS transport is being used, try getting address via CLTS
867 759 * transport. This works only with version 4.
868 760 */
869 761 if (nconf->nc_semantics == NC_TPI_COTS_ORD ||
870 762 nconf->nc_semantics == NC_TPI_COTS) {
871 - void *handle;
763 + handle = __rpc_setconf("datagram_v");
764 + } else {
765 + handle = __rpc_setconf(nconf->nc_proto);
766 + }
767 +
768 + if (handle != NULL) {
872 769 struct netconfig *nconf_clts;
873 - rpcb_entry_list_ptr relp = NULL;
874 770
875 - if (client == NULL) {
876 - /* This did not go through the above PORTMAP/TCP code */
877 - if ((handle = __rpc_setconf("datagram_v")) != NULL) {
878 - while ((nconf_clts = __rpc_getconf(handle))
879 - != NULL) {
880 - if (strcmp(nconf_clts->nc_protofmly,
881 - nconf->nc_protofmly) != 0) {
882 - continue;
883 - }
884 - client = _getclnthandle_timed(host,
885 - nconf_clts, &parms.r_addr,
886 - tp);
887 - break;
888 - }
889 - __rpc_endconf(handle);
771 + while ((nconf_clts = __rpc_getconf(handle))
772 + != NULL) {
773 + if (strcmp(nconf_clts->nc_protofmly,
774 + nconf->nc_protofmly) != 0) {
775 + continue;
890 776 }
891 - if (client == NULL)
892 - goto regular_rpcbind; /* Go the regular way */
893 - } else {
894 - /* This is a UDP PORTMAP handle. Change to version 4 */
895 - vers = RPCBVERS4;
896 - CLNT_CONTROL(client, CLSET_VERS, (char *)&vers);
777 + client = _getclnthandle_timed(host,
778 + nconf_clts, &parms.r_addr,
779 + tp);
780 + break;
897 781 }
782 + __rpc_endconf(handle);
783 + }
784 + if (client != NULL) {
785 +
786 + if (nconf->nc_semantics == NC_TPI_COTS_ORD ||
787 + nconf->nc_semantics == NC_TPI_COTS)
788 + tmp_client = TRUE;
789 +
790 + /* Set rpcbind version 4 */
791 + vers = RPCBVERS4;
792 + CLNT_CONTROL(client, CLSET_VERS, (char *)&vers);
793 +
898 794 /*
899 795 * We also send the remote system the address we used to
900 796 * contact it in case it can help it connect back with us
901 797 */
902 798 if (parms.r_addr == NULL) {
903 799 parms.r_addr = strdup(""); /* for XDRing */
904 800 if (parms.r_addr == NULL) {
905 801 syslog(LOG_ERR, "__rpcb_findaddr_timed: "
906 - "strdup failed.");
802 + "strdup failed.");
907 803 rpc_createerr.cf_stat = RPC_SYSTEMERROR;
908 804 address = NULL;
909 805 goto error;
910 806 }
911 807 }
912 808
913 - CLNT_CONTROL(client, CLSET_RETRY_TIMEOUT, (char *)&rpcbrmttime);
809 + CLNT_CONTROL(client, CLSET_RETRY_TIMEOUT,
810 + (char *)&rpcbrmttime);
914 811
915 812 clnt_st = CLNT_CALL(client, RPCBPROC_GETADDRLIST,
916 - (xdrproc_t)xdr_rpcb, (char *)&parms,
917 - (xdrproc_t)xdr_rpcb_entry_list_ptr,
918 - (char *)&relp, *tp);
919 - if (clnt_st == RPC_SUCCESS) {
813 + (xdrproc_t)xdr_rpcb, (char *)&parms,
814 + (xdrproc_t)xdr_rpcb_entry_list_ptr,
815 + (char *)&relp, *tp);
816 + switch (clnt_st) {
817 + case RPC_SUCCESS:
920 818 if (address = got_entry(relp, nconf)) {
921 819 xdr_free((xdrproc_t)xdr_rpcb_entry_list_ptr,
922 - (char *)&relp);
820 + (char *)&relp);
923 821 goto done;
924 822 }
925 823 /* Entry not found for this transport */
926 824 xdr_free((xdrproc_t)xdr_rpcb_entry_list_ptr,
927 - (char *)&relp);
825 + (char *)&relp);
928 826 /*
929 827 * XXX: should have perhaps returned with error but
930 828 * since the remote machine might not always be able
931 829 * to send the address on all transports, we try the
932 - * regular way with regular_rpcbind
830 + * regular way with version 3, then 2
933 831 */
934 - goto regular_rpcbind;
935 - } else if ((clnt_st == RPC_PROGVERSMISMATCH) ||
936 - (clnt_st == RPC_PROGUNAVAIL)) {
937 - start_vers = RPCBVERS; /* Try version 3 now */
938 - goto regular_rpcbind; /* Try different versions */
939 - } else {
832 + /* Try the next version */
833 + break;
834 + case RPC_PROGVERSMISMATCH:
835 + case RPC_PROGUNAVAIL:
836 + /* Try the next version */
837 + break;
838 + default:
940 839 rpc_createerr.cf_stat = RPC_PMAPFAILURE;
941 840 clnt_geterr(client, &rpc_createerr.cf_error);
942 841 goto error;
842 + break;
943 843 }
944 - }
844 + } /* End of version 4 */
945 845
946 -regular_rpcbind:
846 + /*
847 + * Try version 3
848 + */
947 849
948 850 /* Now the same transport is to be used to get the address */
949 851 if (client && ((nconf->nc_semantics == NC_TPI_COTS_ORD) ||
950 852 (nconf->nc_semantics == NC_TPI_COTS))) {
951 853 /* A CLTS type of client - destroy it */
952 854 CLNT_DESTROY(client);
953 855 client = NULL;
954 856 free(parms.r_addr);
955 857 parms.r_addr = NULL;
956 858 }
957 859
958 860 if (client == NULL) {
959 861 client = _getclnthandle_timed(host, nconf, &parms.r_addr, tp);
960 - if (client == NULL) {
961 - address = NULL;
962 - goto error;
963 - }
964 862 }
965 - if (parms.r_addr == NULL) {
966 - parms.r_addr = strdup(""); /* for XDRing */
863 + if (client != NULL) {
864 + tmp_client = FALSE;
967 865 if (parms.r_addr == NULL) {
968 - syslog(LOG_ERR, "__rpcb_findaddr_timed: "
969 - "strdup failed.");
970 - address = NULL;
971 - rpc_createerr.cf_stat = RPC_SYSTEMERROR;
972 - goto error;
866 + parms.r_addr = strdup(""); /* for XDRing */
867 + if (parms.r_addr == NULL) {
868 + syslog(LOG_ERR, "__rpcb_findaddr_timed: "
869 + "strdup failed.");
870 + address = NULL;
871 + rpc_createerr.cf_stat = RPC_SYSTEMERROR;
872 + goto error;
873 + }
973 874 }
974 - }
975 875
976 - /* First try from start_vers and then version 3 (RPCBVERS) */
977 -
978 - CLNT_CONTROL(client, CLSET_RETRY_TIMEOUT, (char *)&rpcbrmttime);
979 - for (vers = start_vers; vers >= RPCBVERS; vers--) {
980 - /* Set the version */
876 + CLNT_CONTROL(client, CLSET_RETRY_TIMEOUT,
877 + (char *)&rpcbrmttime);
878 + vers = RPCBVERS; /* Set the version */
981 879 CLNT_CONTROL(client, CLSET_VERS, (char *)&vers);
982 880 clnt_st = CLNT_CALL(client, RPCBPROC_GETADDR,
983 - (xdrproc_t)xdr_rpcb, (char *)&parms,
984 - (xdrproc_t)xdr_wrapstring,
985 - (char *)&ua, *tp);
986 - if (clnt_st == RPC_SUCCESS) {
987 - if ((ua == NULL) || (ua[0] == NULL)) {
988 - if (ua != NULL)
989 - xdr_free(xdr_wrapstring, (char *)&ua);
990 -
991 - /* address unknown */
992 - rpc_createerr.cf_stat = RPC_PROGNOTREGISTERED;
993 - goto error;
881 + (xdrproc_t)xdr_rpcb, (char *)&parms,
882 + (xdrproc_t)xdr_wrapstring,
883 + (char *)&ua, *tp);
884 + switch (clnt_st) {
885 + case RPC_SUCCESS:
886 + if ((ua != NULL) && (ua[0] != '\0')) {
887 + address = uaddr2taddr(nconf, ua);
888 +#ifdef ND_DEBUG
889 + fprintf(stderr, "\tRemote address is [%s]\n",
890 + ua);
891 +#endif
892 + xdr_free((xdrproc_t)xdr_wrapstring,
893 + (char *)&ua);
894 + } else if (ua != NULL) {
895 + xdr_free(xdr_wrapstring, (char *)&ua);
994 896 }
995 - address = uaddr2taddr(nconf, ua);
897 +
898 + if (ua != NULL && address != NULL) {
899 + goto done;
900 + } else if (address == NULL) {
901 + /* We don't know about your universal addr */
996 902 #ifdef ND_DEBUG
997 - fprintf(stderr, "\tRemote address is [%s]\n", ua);
998 - if (!address)
999 903 fprintf(stderr,
1000 - "\tCouldn't resolve remote address!\n");
904 + "\tCouldn't resolve remote address!\n");
1001 905 #endif
1002 - xdr_free((xdrproc_t)xdr_wrapstring, (char *)&ua);
1003 -
1004 - if (!address) {
1005 - /* We don't know about your universal address */
1006 - rpc_createerr.cf_stat = RPC_N2AXLATEFAILURE;
906 + rpc_createerr.cf_stat = RPC_PROGNOTREGISTERED;
1007 907 goto error;
1008 908 }
1009 - goto done;
909 + /* Try the next version */
910 + break;
911 + case RPC_PROGVERSMISMATCH:
912 + clnt_geterr(client, &rpc_createerr.cf_error);
913 + if (rpc_createerr.cf_error.re_vers.low > RPCBVERS4)
914 + goto error; /* a new version, can't handle */
915 + /* Try the next version */
916 + break;
917 + case RPC_PROGUNAVAIL:
918 + /* Try the next version */
919 + break;
920 + default:
921 + clnt_geterr(client, &rpc_createerr.cf_error);
922 + rpc_createerr.cf_stat = RPC_PMAPFAILURE;
923 + goto error;
924 + break;
1010 925 }
1011 - if (clnt_st == RPC_PROGVERSMISMATCH) {
1012 - struct rpc_err rpcerr;
926 + } else {
927 + address = NULL;
928 + } /* End of version 3 */
1013 929
1014 - clnt_geterr(client, &rpcerr);
1015 - if (rpcerr.re_vers.low > RPCBVERS4)
1016 - goto error; /* a new version, can't handle */
1017 - } else if (clnt_st != RPC_PROGUNAVAIL) {
1018 - /* Cant handle this error */
930 + /*
931 + * Try version 2
932 + */
933 +
934 +#ifdef PORTMAP
935 + /* Try version 2 for TCP or UDP */
936 + if (strcmp(nconf->nc_protofmly, NC_INET) == 0) {
937 + ushort_t port = 0;
938 + struct netbuf remote;
939 + uint_t pmapvers = 2;
940 + struct pmap pmapparms;
941 +
942 + /*
943 + * Try UDP only - there are some portmappers out
944 + * there that use UDP only.
945 + */
946 + if (strcmp(nconf->nc_proto, NC_TCP) == 0) {
947 + struct netconfig *newnconf;
948 +
949 + if (client) {
950 + CLNT_DESTROY(client);
951 + client = NULL;
952 + free(parms.r_addr);
953 + parms.r_addr = NULL;
954 + }
955 + if ((handle = __rpc_setconf("udp")) == NULL) {
956 + rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
957 + return (NULL);
958 + }
959 +
960 + /*
961 + * The following to reinforce that you can
962 + * only request for remote address through
963 + * the same transport you are requesting.
964 + * ie. requesting unversial address
965 + * of IPv4 has to be carried through IPv4.
966 + * Can't use IPv6 to send out the request.
967 + * The mergeaddr in rpcbind can't handle
968 + * this.
969 + */
970 + for (;;) {
971 + if ((newnconf = __rpc_getconf(handle))
972 + == NULL) {
973 + __rpc_endconf(handle);
974 + rpc_createerr.cf_stat =
975 + RPC_UNKNOWNPROTO;
976 + return (NULL);
977 + }
978 + /*
979 + * here check the protocol family to
980 + * be consistent with the request one
981 + */
982 + if (strcmp(newnconf->nc_protofmly,
983 + nconf->nc_protofmly) == NULL)
984 + break;
985 + }
986 +
987 + client = _getclnthandle_timed(host, newnconf,
988 + &parms.r_addr, tp);
989 + __rpc_endconf(handle);
990 + }
991 + if (client == NULL)
992 + return (NULL);
993 +
994 + if (strcmp(nconf->nc_proto, NC_TCP) == 0)
995 + tmp_client = TRUE;
996 +
997 + /*
998 + * Set version and retry timeout.
999 + */
1000 + CLNT_CONTROL(client, CLSET_RETRY_TIMEOUT, (char *)&rpcbrmttime);
1001 + CLNT_CONTROL(client, CLSET_VERS, (char *)&pmapvers);
1002 +
1003 + pmapparms.pm_prog = program;
1004 + pmapparms.pm_vers = version;
1005 + pmapparms.pm_prot = strcmp(nconf->nc_proto, NC_TCP) ?
1006 + IPPROTO_UDP : IPPROTO_TCP;
1007 + pmapparms.pm_port = 0; /* not needed */
1008 + clnt_st = CLNT_CALL(client, PMAPPROC_GETPORT,
1009 + (xdrproc_t)xdr_pmap, (caddr_t)&pmapparms,
1010 + (xdrproc_t)xdr_u_short, (caddr_t)&port,
1011 + *tp);
1012 + if (clnt_st != RPC_SUCCESS) {
1013 + rpc_createerr.cf_stat = RPC_PMAPFAILURE;
1014 + clnt_geterr(client, &rpc_createerr.cf_error);
1019 1015 goto error;
1016 + } else if (port == 0) {
1017 + address = NULL;
1018 + rpc_createerr.cf_stat = RPC_PROGNOTREGISTERED;
1019 + goto error;
1020 1020 }
1021 + port = htons(port);
1022 + CLNT_CONTROL(client, CLGET_SVC_ADDR, (char *)&remote);
1023 + if (((address = malloc(sizeof (struct netbuf))) == NULL) ||
1024 + ((address->buf = malloc(remote.len)) == NULL)) {
1025 + rpc_createerr.cf_stat = RPC_SYSTEMERROR;
1026 + clnt_geterr(client, &rpc_createerr.cf_error);
1027 + if (address) {
1028 + free(address);
1029 + address = NULL;
1030 + }
1031 + goto error;
1032 + }
1033 + (void) memcpy(address->buf, remote.buf, remote.len);
1034 + (void) memcpy(&address->buf[sizeof (short)], &port,
1035 + sizeof (short));
1036 + address->len = address->maxlen = remote.len;
1037 + goto done;
1021 1038 }
1039 +#endif
1022 1040
1023 - if ((address == NULL) || (address->len == 0)) {
1024 - rpc_createerr.cf_stat = RPC_PROGNOTREGISTERED;
1025 - clnt_geterr(client, &rpc_createerr.cf_error);
1026 - }
1027 -
1028 1041 error:
1042 + /* Return NULL address and NULL client */
1029 1043 if (client) {
1030 1044 CLNT_DESTROY(client);
1031 1045 client = NULL;
1032 1046 }
1047 +
1033 1048 done:
1034 - if (nconf->nc_semantics != NC_TPI_CLTS) {
1035 - /* This client is the connectionless one */
1049 + /* Return an address and optional client */
1050 + if (tmp_client) {
1051 + /* This client is the temporary one */
1036 1052 if (client) {
1037 1053 CLNT_DESTROY(client);
1038 1054 client = NULL;
1039 1055 }
1040 1056 }
1041 1057 if (clpp) {
1042 1058 *clpp = client;
1043 1059 } else if (client) {
1044 1060 CLNT_DESTROY(client);
1045 1061 }
1046 1062 if (parms.r_addr)
1047 1063 free(parms.r_addr);
1048 1064 return (address);
1049 1065 }
1050 1066
1051 1067
1052 1068 /*
1053 1069 * Find the mapped address for program, version.
1054 1070 * Calls the rpcbind service remotely to do the lookup.
1055 1071 * Uses the transport specified in nconf.
1056 1072 * Returns FALSE (0) if no map exists, else returns 1.
1057 1073 *
1058 1074 * Assuming that the address is all properly allocated
1059 1075 */
1060 1076 int
1061 1077 rpcb_getaddr(const rpcprog_t program, const rpcvers_t version,
1062 1078 const struct netconfig *nconf, struct netbuf *address, const char *host)
1063 1079 {
1064 1080 struct netbuf *na;
1065 1081
1066 1082 if ((na = __rpcb_findaddr_timed(program, version,
1067 1083 (struct netconfig *)nconf, (char *)host, NULL, NULL)) == NULL)
1068 1084 return (FALSE);
1069 1085
1070 1086 if (na->len > address->maxlen) {
1071 1087 /* Too long address */
1072 1088 netdir_free((char *)na, ND_ADDR);
1073 1089 rpc_createerr.cf_stat = RPC_FAILED;
1074 1090 return (FALSE);
1075 1091 }
1076 1092 (void) memcpy(address->buf, na->buf, (int)na->len);
1077 1093 address->len = na->len;
1078 1094 netdir_free((char *)na, ND_ADDR);
1079 1095 return (TRUE);
1080 1096 }
1081 1097
1082 1098 /*
1083 1099 * Get a copy of the current maps.
1084 1100 * Calls the rpcbind service remotely to get the maps.
1085 1101 *
1086 1102 * It returns only a list of the services
1087 1103 * It returns NULL on failure.
↓ open down ↓ |
42 lines elided |
↑ open up ↑ |
1088 1104 */
1089 1105 rpcblist *
1090 1106 rpcb_getmaps(const struct netconfig *nconf, const char *host)
1091 1107 {
1092 1108 rpcblist_ptr head = NULL;
1093 1109 CLIENT *client;
1094 1110 enum clnt_stat clnt_st;
1095 1111 int vers = 0;
1096 1112
1097 1113 client = getclnthandle((char *)host,
1098 - (struct netconfig *)nconf, NULL);
1114 + (struct netconfig *)nconf, NULL);
1099 1115 if (client == NULL)
1100 1116 return (NULL);
1101 1117
1102 1118 clnt_st = CLNT_CALL(client, RPCBPROC_DUMP,
1103 - (xdrproc_t)xdr_void, NULL,
1104 - (xdrproc_t)xdr_rpcblist_ptr,
1105 - (char *)&head, tottimeout);
1119 + (xdrproc_t)xdr_void, NULL,
1120 + (xdrproc_t)xdr_rpcblist_ptr,
1121 + (char *)&head, tottimeout);
1106 1122 if (clnt_st == RPC_SUCCESS)
1107 1123 goto done;
1108 1124
1109 1125 if ((clnt_st != RPC_PROGVERSMISMATCH) &&
1110 - (clnt_st != RPC_PROGUNAVAIL)) {
1126 + (clnt_st != RPC_PROGUNAVAIL)) {
1111 1127 rpc_createerr.cf_stat = RPC_RPCBFAILURE;
1112 1128 clnt_geterr(client, &rpc_createerr.cf_error);
1113 1129 goto done;
1114 1130 }
1115 1131
1116 1132 /* fall back to earlier version */
1117 1133 CLNT_CONTROL(client, CLGET_VERS, (char *)&vers);
1118 1134 if (vers == RPCBVERS4) {
1119 1135 vers = RPCBVERS;
1120 1136 CLNT_CONTROL(client, CLSET_VERS, (char *)&vers);
1121 1137 if (CLNT_CALL(client, RPCBPROC_DUMP,
1122 - (xdrproc_t)xdr_void,
1123 - NULL, (xdrproc_t)xdr_rpcblist_ptr,
1124 - (char *)&head, tottimeout) == RPC_SUCCESS)
1138 + (xdrproc_t)xdr_void,
1139 + NULL, (xdrproc_t)xdr_rpcblist_ptr,
1140 + (char *)&head, tottimeout) == RPC_SUCCESS)
1125 1141 goto done;
1126 1142 }
1127 1143 rpc_createerr.cf_stat = RPC_RPCBFAILURE;
1128 1144 clnt_geterr(client, &rpc_createerr.cf_error);
1129 1145
1130 1146 done:
1131 1147 CLNT_DESTROY(client);
1132 1148 return (head);
1133 1149 }
1134 1150
1135 1151 /*
1136 1152 * rpcbinder remote-call-service interface.
1137 1153 * This routine is used to call the rpcbind remote call service
1138 1154 * which will look up a service program in the address maps, and then
1139 1155 * remotely call that routine with the given parameters. This allows
1140 1156 * programs to do a lookup and call in one step.
1141 1157 */
1142 1158 enum clnt_stat
1143 1159 rpcb_rmtcall(const struct netconfig *nconf, const char *host,
1144 1160 const rpcprog_t prog, const rpcvers_t vers, const rpcproc_t proc,
1145 1161 const xdrproc_t xdrargs, const caddr_t argsp, const xdrproc_t xdrres,
1146 1162 const caddr_t resp, const struct timeval tout, struct netbuf *addr_ptr)
1147 1163 {
1148 1164 CLIENT *client;
1149 1165 enum clnt_stat stat;
1150 1166 struct r_rpcb_rmtcallargs a;
1151 1167 struct r_rpcb_rmtcallres r;
1152 1168 int rpcb_vers;
1153 1169
1154 1170 client = getclnthandle((char *)host, (struct netconfig *)nconf, NULL);
1155 1171 if (client == NULL)
1156 1172 return (RPC_FAILED);
1157 1173 CLNT_CONTROL(client, CLSET_RETRY_TIMEOUT, (char *)&rmttimeout);
1158 1174 a.prog = prog;
1159 1175 a.vers = vers;
↓ open down ↓ |
25 lines elided |
↑ open up ↑ |
1160 1176 a.proc = proc;
1161 1177 a.args.args_val = argsp;
1162 1178 a.xdr_args = xdrargs;
1163 1179 r.addr = NULL;
1164 1180 r.results.results_val = resp;
1165 1181 r.xdr_res = xdrres;
1166 1182
1167 1183 for (rpcb_vers = RPCBVERS4; rpcb_vers >= RPCBVERS; rpcb_vers--) {
1168 1184 CLNT_CONTROL(client, CLSET_VERS, (char *)&rpcb_vers);
1169 1185 stat = CLNT_CALL(client, RPCBPROC_CALLIT,
1170 - (xdrproc_t)xdr_rpcb_rmtcallargs, (char *)&a,
1171 - (xdrproc_t)xdr_rpcb_rmtcallres, (char *)&r, tout);
1186 + (xdrproc_t)xdr_rpcb_rmtcallargs, (char *)&a,
1187 + (xdrproc_t)xdr_rpcb_rmtcallres, (char *)&r, tout);
1172 1188 if ((stat == RPC_SUCCESS) && (addr_ptr != NULL)) {
1173 1189 struct netbuf *na;
1174 1190
1175 1191 na = uaddr2taddr((struct netconfig *)nconf, r.addr);
1176 1192 if (!na) {
1177 1193 stat = RPC_N2AXLATEFAILURE;
1178 1194 ((struct netbuf *)addr_ptr)->len = 0;
1179 1195 goto error;
1180 1196 }
1181 1197 if (na->len > addr_ptr->maxlen) {
1182 1198 /* Too long address */
1183 1199 stat = RPC_FAILED; /* XXX A better error no */
↓ open down ↓ |
2 lines elided |
↑ open up ↑ |
1184 1200 netdir_free((char *)na, ND_ADDR);
1185 1201 ((struct netbuf *)addr_ptr)->len = 0;
1186 1202 goto error;
1187 1203 }
1188 1204 (void) memcpy(addr_ptr->buf, na->buf, (int)na->len);
1189 1205 ((struct netbuf *)addr_ptr)->len = na->len;
1190 1206 netdir_free((char *)na, ND_ADDR);
1191 1207 break;
1192 1208 }
1193 1209 if ((stat != RPC_PROGVERSMISMATCH) &&
1194 - (stat != RPC_PROGUNAVAIL))
1210 + (stat != RPC_PROGUNAVAIL))
1195 1211 goto error;
1196 1212 }
1197 1213 error:
1198 1214 CLNT_DESTROY(client);
1199 1215 if (r.addr)
1200 1216 xdr_free((xdrproc_t)xdr_wrapstring, (char *)&r.addr);
1201 1217 return (stat);
1202 1218 }
1203 1219
1204 1220 /*
1205 1221 * Gets the time on the remote host.
1206 1222 * Returns 1 if succeeds else 0.
1207 1223 */
1208 1224 bool_t
1209 1225 rpcb_gettime(const char *host, time_t *timep)
1210 1226 {
1211 1227 CLIENT *client = NULL;
1212 1228 void *handle;
1213 1229 struct netconfig *nconf;
1214 1230 int vers;
1215 1231 enum clnt_stat st;
1216 1232
1217 1233 if ((host == NULL) || (host[0] == NULL)) {
1218 1234 (void) time(timep);
1219 1235 return (TRUE);
1220 1236 }
1221 1237
1222 1238 if ((handle = __rpc_setconf("netpath")) == NULL) {
1223 1239 rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
1224 1240 return (FALSE);
1225 1241 }
1226 1242 rpc_createerr.cf_stat = RPC_SUCCESS;
1227 1243 while (client == NULL) {
1228 1244 if ((nconf = __rpc_getconf(handle)) == NULL) {
1229 1245 if (rpc_createerr.cf_stat == RPC_SUCCESS)
1230 1246 rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
1231 1247 break;
↓ open down ↓ |
27 lines elided |
↑ open up ↑ |
1232 1248 }
1233 1249 client = getclnthandle((char *)host, nconf, NULL);
1234 1250 if (client)
1235 1251 break;
1236 1252 }
1237 1253 __rpc_endconf(handle);
1238 1254 if (client == NULL)
1239 1255 return (FALSE);
1240 1256
1241 1257 st = CLNT_CALL(client, RPCBPROC_GETTIME,
1242 - (xdrproc_t)xdr_void, NULL,
1243 - (xdrproc_t)xdr_time_t, (char *)timep, tottimeout);
1258 + (xdrproc_t)xdr_void, NULL,
1259 + (xdrproc_t)xdr_time_t, (char *)timep, tottimeout);
1244 1260
1245 1261 if ((st == RPC_PROGVERSMISMATCH) || (st == RPC_PROGUNAVAIL)) {
1246 1262 CLNT_CONTROL(client, CLGET_VERS, (char *)&vers);
1247 1263 if (vers == RPCBVERS4) {
1248 1264 /* fall back to earlier version */
1249 1265 vers = RPCBVERS;
1250 1266 CLNT_CONTROL(client, CLSET_VERS, (char *)&vers);
1251 1267 st = CLNT_CALL(client, RPCBPROC_GETTIME,
1252 - (xdrproc_t)xdr_void, NULL,
1253 - (xdrproc_t)xdr_time_t, (char *)timep,
1254 - tottimeout);
1268 + (xdrproc_t)xdr_void, NULL,
1269 + (xdrproc_t)xdr_time_t, (char *)timep,
1270 + tottimeout);
1255 1271 }
1256 1272 }
1257 1273 CLNT_DESTROY(client);
1258 1274 return (st == RPC_SUCCESS? TRUE : FALSE);
1259 1275 }
1260 1276
1261 1277 /*
1262 1278 * Converts taddr to universal address. This routine should never
1263 1279 * really be called because local n2a libraries are always provided.
1264 1280 */
1265 1281 char *
1266 1282 rpcb_taddr2uaddr(struct netconfig *nconf, struct netbuf *taddr)
1267 1283 {
1268 1284 CLIENT *client;
1269 1285 char *uaddr = NULL;
1270 1286
1271 1287 /* parameter checking */
1272 1288 if (nconf == NULL) {
1273 1289 rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
1274 1290 return (NULL);
↓ open down ↓ |
10 lines elided |
↑ open up ↑ |
1275 1291 }
1276 1292 if (taddr == NULL) {
1277 1293 rpc_createerr.cf_stat = RPC_UNKNOWNADDR;
1278 1294 return (NULL);
1279 1295 }
1280 1296 client = local_rpcb();
1281 1297 if (!client)
1282 1298 return (NULL);
1283 1299
1284 1300 CLNT_CALL(client, RPCBPROC_TADDR2UADDR, (xdrproc_t)xdr_netbuf,
1285 - (char *)taddr, (xdrproc_t)xdr_wrapstring, (char *)&uaddr,
1286 - tottimeout);
1301 + (char *)taddr, (xdrproc_t)xdr_wrapstring, (char *)&uaddr,
1302 + tottimeout);
1287 1303 CLNT_DESTROY(client);
1288 1304 return (uaddr);
1289 1305 }
1290 1306
1291 1307 /*
1292 1308 * Converts universal address to netbuf. This routine should never
1293 1309 * really be called because local n2a libraries are always provided.
1294 1310 */
1295 1311 struct netbuf *
1296 1312 rpcb_uaddr2taddr(struct netconfig *nconf, char *uaddr)
1297 1313 {
1298 1314 CLIENT *client;
1299 1315 struct netbuf *taddr;
1300 1316
1301 1317 /* parameter checking */
1302 1318 if (nconf == NULL) {
1303 1319 rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
1304 1320 return (NULL);
1305 1321 }
1306 1322 if (uaddr == NULL) {
1307 1323 rpc_createerr.cf_stat = RPC_UNKNOWNADDR;
1308 1324 return (NULL);
1309 1325 }
1310 1326 client = local_rpcb();
↓ open down ↓ |
14 lines elided |
↑ open up ↑ |
1311 1327 if (!client)
1312 1328 return (NULL);
1313 1329
1314 1330 taddr = calloc(1, sizeof (struct netbuf));
1315 1331 if (taddr == NULL) {
1316 1332 CLNT_DESTROY(client);
1317 1333 return (NULL);
1318 1334 }
1319 1335
1320 1336 if (CLNT_CALL(client, RPCBPROC_UADDR2TADDR, (xdrproc_t)xdr_wrapstring,
1321 - (char *)&uaddr, (xdrproc_t)xdr_netbuf, (char *)taddr,
1322 - tottimeout) != RPC_SUCCESS) {
1337 + (char *)&uaddr, (xdrproc_t)xdr_netbuf, (char *)taddr,
1338 + tottimeout) != RPC_SUCCESS) {
1323 1339 free(taddr);
1324 1340 taddr = NULL;
1325 1341 }
1326 1342 CLNT_DESTROY(client);
1327 1343 return (taddr);
1328 1344 }
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX