xref: /illumos-gate/usr/src/lib/libnsl/rpc/rpc_soc.c (revision 7c478bd9)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
27 /* All Rights Reserved */
28 /*
29  * Portions of this source code were derived from Berkeley
30  * 4.3 BSD under license from the Regents of the University of
31  * California.
32  */
33 
34 #pragma ident	"%Z%%M%	%I%	%E% SMI"
35 
36 #ifdef PORTMAP
37 /*
38  * rpc_soc.c
39  *
40  * The backward compatibility routines for the earlier implementation
41  * of RPC, where the only transports supported were tcp/ip and udp/ip.
42  * Based on berkeley socket abstraction, now implemented on the top
43  * of TLI/Streams
44  */
45 
46 #include "mt.h"
47 #include "rpc_mt.h"
48 #include <stdio.h>
49 #include <sys/types.h>
50 #include <rpc/trace.h>
51 #include <rpc/rpc.h>
52 #include <netinet/in.h>
53 #include <sys/socket.h>
54 #include <netdb.h>
55 #include <netdir.h>
56 #include <errno.h>
57 #include <sys/syslog.h>
58 #include <rpc/pmap_clnt.h>
59 #include <rpc/pmap_prot.h>
60 #include <rpc/nettype.h>
61 #include <syslog.h>
62 #include <string.h>
63 #include <stdlib.h>
64 #include <unistd.h>
65 
66 int __rpc_bindresvport(int, struct sockaddr_in *, int *, int);
67 int __rpc_bindresvport_ipv6(int, struct sockaddr *, int *, int, char *);
68 void get_myaddress_ipv6(char *, struct sockaddr *);
69 
70 extern mutex_t	rpcsoc_lock;
71 
72 /*
73  * A common clnt create routine
74  */
75 static CLIENT *
76 clnt_com_create(raddr, prog, vers, sockp, sendsz, recvsz, tp)
77 	struct sockaddr_in *raddr;
78 	rpcprog_t prog;
79 	rpcvers_t vers;
80 	int *sockp;
81 	uint_t sendsz;
82 	uint_t recvsz;
83 	char *tp;
84 {
85 	CLIENT *cl;
86 	int madefd = FALSE;
87 	int fd = *sockp;
88 	struct t_info tinfo;
89 	struct netconfig *nconf;
90 	int port;
91 	struct netbuf bindaddr;
92 	extern int __rpc_minfd;
93 	bool_t locked = TRUE;
94 
95 	trace5(TR_clnt_com_create, 0, prog, vers, sendsz, recvsz);
96 	mutex_lock(&rpcsoc_lock);
97 	if ((nconf = __rpc_getconfip(tp)) == NULL) {
98 		rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
99 		mutex_unlock(&rpcsoc_lock);
100 		trace3(TR_clnt_com_create, 1, prog, vers);
101 		return ((CLIENT *)NULL);
102 	}
103 	if (fd == RPC_ANYSOCK) {
104 		fd = t_open(nconf->nc_device, O_RDWR, &tinfo);
105 		if (fd == -1)
106 			goto syserror;
107 		if (fd < __rpc_minfd)
108 			fd = __rpc_raise_fd(fd);
109 		madefd = TRUE;
110 	} else {
111 		if (t_getinfo(fd, &tinfo) == -1)
112 			goto syserror;
113 	}
114 
115 	if (raddr->sin_port == 0) {
116 		uint_t proto;
117 		ushort_t sport;
118 
119 		mutex_unlock(&rpcsoc_lock);	/* pmap_getport is recursive */
120 		proto = strcmp(tp, "udp") == 0 ? IPPROTO_UDP : IPPROTO_TCP;
121 		sport = pmap_getport(raddr, prog, vers, proto);
122 		if (sport == 0) {
123 			locked = FALSE;
124 			goto err;
125 		}
126 		raddr->sin_port = htons(sport);
127 		mutex_lock(&rpcsoc_lock);	/* pmap_getport is recursive */
128 	}
129 
130 	/* Transform sockaddr_in to netbuf */
131 	bindaddr.maxlen = bindaddr.len =  __rpc_get_a_size(tinfo.addr);
132 	bindaddr.buf = (char *)raddr;
133 
134 	(void) __rpc_bindresvport(fd, (struct sockaddr_in *)NULL, &port, 0);
135 	cl = clnt_tli_create(fd, nconf, &bindaddr, prog, vers,
136 				sendsz, recvsz);
137 	if (cl) {
138 		if (madefd == TRUE) {
139 			/*
140 			 * The fd should be closed while destroying the handle.
141 			 */
142 			(void) CLNT_CONTROL(cl, CLSET_FD_CLOSE, (char *)NULL);
143 			*sockp = fd;
144 		}
145 		(void) freenetconfigent(nconf);
146 		mutex_unlock(&rpcsoc_lock);
147 		trace3(TR_clnt_com_create, 1, prog, vers);
148 		return (cl);
149 	}
150 	goto err;
151 
152 syserror:
153 	rpc_createerr.cf_stat = RPC_SYSTEMERROR;
154 	rpc_createerr.cf_error.re_errno = errno;
155 	rpc_createerr.cf_error.re_terrno = t_errno;
156 
157 err:	if (madefd == TRUE)
158 		(void) t_close(fd);
159 	(void) freenetconfigent(nconf);
160 	if (locked == TRUE)
161 		mutex_unlock(&rpcsoc_lock);
162 	trace3(TR_clnt_com_create, 1, prog, vers);
163 	return ((CLIENT *)NULL);
164 }
165 
166 CLIENT *
167 clntudp_bufcreate(raddr, prog, vers, wait, sockp, sendsz, recvsz)
168 	struct sockaddr_in *raddr;
169 	rpcprog_t prog;
170 	rpcvers_t vers;
171 	struct timeval wait;
172 	int *sockp;
173 	uint_t sendsz;
174 	uint_t recvsz;
175 {
176 	CLIENT *cl;
177 
178 	trace5(TR_clntudp_bufcreate, 0, prog, vers, sendsz, recvsz);
179 	cl = clnt_com_create(raddr, prog, vers, sockp, sendsz, recvsz, "udp");
180 	if (cl == (CLIENT *)NULL) {
181 		trace3(TR_clntudp_bufcreate, 1, prog, vers);
182 		return ((CLIENT *)NULL);
183 	}
184 	(void) CLNT_CONTROL(cl, CLSET_RETRY_TIMEOUT, (char *)&wait);
185 	trace3(TR_clntudp_bufcreate, 1, prog, vers);
186 	return (cl);
187 }
188 
189 CLIENT *
190 clntudp_create(raddr, program, version, wait, sockp)
191 	struct sockaddr_in *raddr;
192 	rpcprog_t program;
193 	rpcvers_t version;
194 	struct timeval wait;
195 	int *sockp;
196 {
197 	CLIENT *dummy;
198 
199 	trace3(TR_clntudp_create, 0, program, version);
200 	dummy = clntudp_bufcreate(raddr, program, version, wait, sockp,
201 					UDPMSGSIZE, UDPMSGSIZE);
202 	trace3(TR_clntudp_create, 1, program, version);
203 	return (dummy);
204 }
205 
206 CLIENT *
207 clnttcp_create(raddr, prog, vers, sockp, sendsz, recvsz)
208 	struct sockaddr_in *raddr;
209 	rpcprog_t prog;
210 	rpcvers_t vers;
211 	int *sockp;
212 	uint_t sendsz;
213 	uint_t recvsz;
214 {
215 	CLIENT *dummy;
216 
217 	trace5(TR_clnttcp_create, 0, prog, vers, sendsz, recvsz);
218 	dummy = clnt_com_create(raddr, prog, vers, sockp, sendsz,
219 			recvsz, "tcp");
220 	trace3(TR_clnttcp_create, 1, prog, vers);
221 	return (dummy);
222 }
223 
224 CLIENT *
225 clntraw_create(prog, vers)
226 	rpcprog_t prog;
227 	rpcvers_t vers;
228 {
229 	CLIENT *dummy;
230 
231 	trace3(TR_clntraw_create, 0, prog, vers);
232 	dummy = clnt_raw_create(prog, vers);
233 	trace3(TR_clntraw_create, 1, prog, vers);
234 	return (dummy);
235 }
236 
237 /*
238  * A common server create routine
239  */
240 static SVCXPRT *
241 svc_com_create(fd, sendsize, recvsize, netid)
242 	int fd;
243 	uint_t sendsize;
244 	uint_t recvsize;
245 	char *netid;
246 {
247 	struct netconfig *nconf;
248 	SVCXPRT *svc;
249 	int madefd = FALSE;
250 	int port;
251 	int res;
252 
253 	trace4(TR_svc_com_create, 0, fd, sendsize, recvsize);
254 	if ((nconf = __rpc_getconfip(netid)) == NULL) {
255 		(void) syslog(LOG_ERR, "Could not get %s transport", netid);
256 		trace2(TR_svc_com_create, 1, fd);
257 		return ((SVCXPRT *)NULL);
258 	}
259 	if (fd == RPC_ANYSOCK) {
260 		fd = t_open(nconf->nc_device, O_RDWR, (struct t_info *)NULL);
261 		if (fd == -1) {
262 			char errorstr[100];
263 
264 			__tli_sys_strerror(errorstr, sizeof (errorstr),
265 					t_errno, errno);
266 			(void) syslog(LOG_ERR,
267 			"svc%s_create: could not open connection : %s", netid,
268 				    errorstr);
269 			(void) freenetconfigent(nconf);
270 			trace2(TR_svc_com_create, 1, fd);
271 			return ((SVCXPRT *)NULL);
272 		}
273 		madefd = TRUE;
274 	}
275 
276 	res = __rpc_bindresvport(fd, (struct sockaddr_in *)NULL, &port, 8);
277 	svc = svc_tli_create(fd, nconf, (struct t_bind *)NULL,
278 				sendsize, recvsize);
279 	(void) freenetconfigent(nconf);
280 	if (svc == (SVCXPRT *)NULL) {
281 		if (madefd)
282 			(void) t_close(fd);
283 		trace2(TR_svc_com_create, 1, fd);
284 		return ((SVCXPRT *)NULL);
285 	}
286 	if (res == -1) {
287 		port = (((struct sockaddr_in *)svc->xp_ltaddr.buf)->sin_port);
288 	}
289 	svc->xp_port = ntohs(port);
290 	trace2(TR_svc_com_create, 1, fd);
291 	return (svc);
292 }
293 
294 SVCXPRT *
295 svctcp_create(fd, sendsize, recvsize)
296 	int fd;
297 	uint_t sendsize;
298 	uint_t recvsize;
299 {
300 	SVCXPRT *dummy;
301 
302 	trace4(TR_svctcp_create, 0, fd, sendsize, recvsize);
303 	dummy = svc_com_create(fd, sendsize, recvsize, "tcp");
304 	trace4(TR_svctcp_create, 1, fd, sendsize, recvsize);
305 	return (dummy);
306 }
307 
308 SVCXPRT *
309 svcudp_bufcreate(fd, sendsz, recvsz)
310 	int fd;
311 	uint_t sendsz, recvsz;
312 {
313 	SVCXPRT *dummy;
314 
315 	trace4(TR_svcudp_bufcreate, 0, fd, sendsz, recvsz);
316 	dummy = svc_com_create(fd, sendsz, recvsz, "udp");
317 	trace4(TR_svcudp_bufcreate, 1, fd, sendsz, recvsz);
318 	return (dummy);
319 }
320 
321 SVCXPRT *
322 svcfd_create(fd, sendsize, recvsize)
323 	int fd;
324 	uint_t sendsize;
325 	uint_t recvsize;
326 {
327 	SVCXPRT *dummy;
328 
329 	trace4(TR_svcfd_create, 0, fd, sendsize, recvsize);
330 	dummy = svc_fd_create(fd, sendsize, recvsize);
331 	trace4(TR_svcfd_create, 1, fd, sendsize, recvsize);
332 	return (dummy);
333 }
334 
335 
336 SVCXPRT *
337 svcudp_create(fd)
338 	int fd;
339 {
340 	SVCXPRT *dummy;
341 
342 	trace2(TR_svcudp_create, 0, fd);
343 	dummy = svc_com_create(fd, UDPMSGSIZE, UDPMSGSIZE, "udp");
344 	trace2(TR_svcudp_create, 1, fd);
345 	return (dummy);
346 }
347 
348 SVCXPRT *
349 svcraw_create()
350 {
351 	SVCXPRT *dummy;
352 
353 	trace1(TR_svcraw_create, 0);
354 	dummy = svc_raw_create();
355 	trace1(TR_svcraw_create, 1);
356 	return (dummy);
357 }
358 
359 /*
360  * Bind a fd to a privileged IP port.
361  * This is slightly different from the code in netdir_options
362  * because it has a different interface - main thing is that it
363  * needs to know its own address.  We also wanted to set the qlen.
364  * t_getname() can be used for those purposes and perhaps job can be done.
365  */
366 int
367 __rpc_bindresvport_ipv6(int fd, struct sockaddr *sin, int *portp, int qlen,
368 			char *fmly)
369 {
370 	int res;
371 	static in_port_t port, *sinport;
372 	struct sockaddr_in6 myaddr;
373 	int i;
374 	struct t_bind tbindstr, *tres;
375 	struct t_info tinfo;
376 	extern mutex_t portnum_lock;
377 
378 	/* VARIABLES PROTECTED BY portnum_lock: port */
379 
380 #define	STARTPORT 600
381 #define	ENDPORT (IPPORT_RESERVED - 1)
382 #define	NPORTS	(ENDPORT - STARTPORT + 1)
383 
384 	trace3(TR_bindresvport, 0, fd, qlen);
385 	if (sin == 0 && fmly == 0) {
386 		errno = EINVAL;
387 		trace2(TR_bindresvport, 1, fd);
388 		return (-1);
389 	}
390 	if (geteuid()) {
391 		errno = EACCES;
392 		trace2(TR_bindresvport, 1, fd);
393 		return (-1);
394 	}
395 	if ((i = t_getstate(fd)) != T_UNBND) {
396 		if (t_errno == TBADF)
397 			errno = EBADF;
398 		if (i != -1)
399 			errno = EISCONN;
400 		trace2(TR_bindresvport, 1, fd);
401 		return (-1);
402 	}
403 	if (sin == 0) {
404 		sin = (struct sockaddr *)&myaddr;
405 		get_myaddress_ipv6(fmly, sin);
406 	}
407 	if (sin->sa_family == AF_INET) {
408 		sinport = &((struct sockaddr_in *)sin)->sin_port;
409 	} else if (sin->sa_family == AF_INET6) {
410 		sinport = &((struct sockaddr_in6 *)sin)->sin6_port;
411 	} else {
412 		errno = EPFNOSUPPORT;
413 		trace2(TR_bindresvport, 1, fd);
414 		return (-1);
415 	}
416 
417 	/* Transform sockaddr to netbuf */
418 	if (t_getinfo(fd, &tinfo) == -1) {
419 		trace2(TR_bindresvport, 1, fd);
420 		return (-1);
421 	}
422 	tres = (struct t_bind *)t_alloc(fd, T_BIND, T_ADDR);
423 	if (tres == NULL) {
424 		trace2(TR_bindresvport, 1, fd);
425 		return (-1);
426 	}
427 
428 	tbindstr.qlen = qlen;
429 	tbindstr.addr.buf = (char *)sin;
430 	tbindstr.addr.len = tbindstr.addr.maxlen = __rpc_get_a_size(tinfo.addr);
431 	sin = (struct sockaddr *)tbindstr.addr.buf;
432 
433 	res = -1;
434 	mutex_lock(&portnum_lock);
435 	if (port == 0)
436 		port = (getpid() % NPORTS) + STARTPORT;
437 	for (i = 0; i < NPORTS; i++) {
438 		*sinport = htons(port++);
439 		if (port > ENDPORT)
440 			port = STARTPORT;
441 		res = t_bind(fd, &tbindstr, tres);
442 		if (res == 0) {
443 			if ((tbindstr.addr.len == tres->addr.len) &&
444 				(memcmp(tbindstr.addr.buf, tres->addr.buf,
445 					(int)tres->addr.len) == 0))
446 				break;
447 			(void) t_unbind(fd);
448 			res = -1;
449 		} else if (t_errno != TSYSERR || errno != EADDRINUSE)
450 			break;
451 	}
452 	mutex_unlock(&portnum_lock);
453 
454 	if ((portp != NULL) && (res == 0))
455 		*portp = *sinport;
456 	(void) t_free((char *)tres, T_BIND);
457 	trace2(TR_bindresvport, 1, fd);
458 	return (res);
459 }
460 
461 int
462 __rpc_bindresvport(int fd, struct sockaddr_in *sin, int *portp, int qlen)
463 {
464 	return (__rpc_bindresvport_ipv6(fd, (struct sockaddr *)sin, portp,
465 					qlen, NC_INET));
466 }
467 
468 /*
469  * Get clients IP address.
470  * don't use gethostbyname, which would invoke yellow pages
471  * Remains only for backward compatibility reasons.
472  * Used mainly by the portmapper so that it can register
473  * with itself. Also used by pmap*() routines
474  */
475 void
476 get_myaddress_ipv6(char *fmly, struct sockaddr *addr)
477 {
478 	trace1(TR_get_myaddress, 0);
479 	if (fmly != 0 && strcmp(fmly, NC_INET6) == 0) {
480 		struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)addr;
481 		memset(sin6, 0, sizeof (*sin6));
482 		sin6->sin6_family = AF_INET6;
483 		sin6->sin6_port = htons(PMAPPORT);
484 		if (__can_use_af(AF_INET6)) {
485 			/* Local copy of in6addr_any to avoid -lsocket */
486 			struct in6_addr in6addr_any = IN6ADDR_ANY_INIT;
487 			sin6->sin6_addr = in6addr_any;
488 		} else {
489 			struct in_addr in4;
490 			in4.s_addr = INADDR_ANY;
491 			IN6_INADDR_TO_V4MAPPED(&in4, &sin6->sin6_addr);
492 		}
493 	} else {
494 		struct sockaddr_in	*sin = (struct sockaddr_in *)addr;
495 		memset(sin, 0, sizeof (*sin));
496 		sin->sin_family = AF_INET;
497 		sin->sin_port = htons(PMAPPORT);
498 		sin->sin_addr.s_addr = INADDR_ANY;
499 	}
500 	trace1(TR_get_myaddress, 1);
501 }
502 
503 void
504 get_myaddress(struct sockaddr_in *addr)
505 {
506 	get_myaddress_ipv6(0, (struct sockaddr *)addr);
507 }
508 
509 /*
510  * Get port used by specified service on specified host.
511  * Exists for source compatibility only.
512  * Obsoleted by rpcb_getaddr().
513  */
514 ushort_t
515 getrpcport(char *host, rpcprog_t prognum, rpcvers_t versnum,
516 	rpcprot_t proto)
517 {
518 	struct sockaddr_in addr;
519 	struct hostent *hp;
520 
521 	if ((hp = gethostbyname(host)) == NULL)
522 		return (0);
523 	memcpy((char *)&addr.sin_addr, hp->h_addr, hp->h_length);
524 	addr.sin_family = AF_INET;
525 	addr.sin_port =  0;
526 	return (pmap_getport(&addr, prognum, versnum, proto));
527 }
528 
529 /*
530  * For connectionless "udp" transport. Obsoleted by rpc_call().
531  */
532 int
533 callrpc(host, prognum, versnum, procnum, inproc, in, outproc, out)
534 	char *host;
535 	rpcprog_t prognum;
536 	rpcvers_t versnum;
537 	rpcproc_t procnum;
538 	xdrproc_t inproc, outproc;
539 	char *in, *out;
540 {
541 	int dummy;
542 
543 	trace4(TR_callrpc, 0, prognum, versnum, procnum);
544 	dummy = (int)rpc_call(host, prognum, versnum, procnum, inproc,
545 				in, outproc, out, "udp");
546 	trace4(TR_callrpc, 1, prognum, versnum, procnum);
547 	return (dummy);
548 }
549 
550 /*
551  * For connectionless kind of transport. Obsoleted by rpc_reg()
552  */
553 int
554 registerrpc(prognum, versnum, procnum, progname, inproc, outproc)
555 	rpcprog_t prognum;
556 	rpcvers_t versnum;
557 	rpcproc_t procnum;
558 	char *(*progname)();
559 	xdrproc_t inproc, outproc;
560 {
561 	int dummy;
562 
563 	trace4(TR_registerrpc, 0, prognum, versnum, procnum);
564 	dummy = rpc_reg(prognum, versnum, procnum, progname, inproc,
565 				outproc, "udp");
566 	trace4(TR_registerrpc, 1, prognum, versnum, procnum);
567 	return (dummy);
568 }
569 
570 /*
571  * All the following clnt_broadcast stuff is convulated; it supports
572  * the earlier calling style of the callback function
573  */
574 static pthread_key_t	clnt_broadcast_key;
575 static resultproc_t	clnt_broadcast_result_main;
576 
577 /*
578  * Need to translate the netbuf address into sockaddr_in address.
579  * Dont care about netid here.
580  */
581 static bool_t
582 rpc_wrap_bcast(resultp, addr, nconf)
583 	char *resultp;		/* results of the call */
584 	struct netbuf *addr;	/* address of the guy who responded */
585 	struct netconfig *nconf; /* Netconf of the transport */
586 {
587 	bool_t dummy;
588 	resultproc_t clnt_broadcast_result;
589 
590 	trace1(TR_rpc_wrap_bcast, 0);
591 	clnt_broadcast_result = thr_main()? clnt_broadcast_result_main :
592 		(resultproc_t)pthread_getspecific(clnt_broadcast_key);
593 	dummy = (*clnt_broadcast_result)(resultp,
594 				(struct sockaddr_in *)addr->buf);
595 	trace1(TR_rpc_wrap_bcast, 1);
596 	return (dummy);
597 }
598 
599 /*
600  * Broadcasts on UDP transport. Obsoleted by rpc_broadcast().
601  */
602 enum clnt_stat
603 clnt_broadcast(prog, vers, proc, xargs, argsp, xresults, resultsp, eachresult)
604 	rpcprog_t	prog;		/* program number */
605 	rpcvers_t	vers;		/* version number */
606 	rpcproc_t	proc;		/* procedure number */
607 	xdrproc_t	xargs;		/* xdr routine for args */
608 	caddr_t		argsp;		/* pointer to args */
609 	xdrproc_t	xresults;	/* xdr routine for results */
610 	caddr_t		resultsp;	/* pointer to results */
611 	resultproc_t	eachresult;	/* call with each result obtained */
612 {
613 	enum clnt_stat dummy;
614 	extern mutex_t tsd_lock;
615 
616 	trace4(TR_clnt_broadcast, 0, prog, vers, proc);
617 	if (thr_main())
618 		clnt_broadcast_result_main = eachresult;
619 	else {
620 		if (clnt_broadcast_key == 0) {
621 			mutex_lock(&tsd_lock);
622 			if (clnt_broadcast_key == 0)
623 				pthread_key_create(&clnt_broadcast_key, NULL);
624 			mutex_unlock(&tsd_lock);
625 		}
626 		pthread_setspecific(clnt_broadcast_key, (void *) eachresult);
627 	}
628 	dummy = rpc_broadcast(prog, vers, proc, xargs, argsp, xresults,
629 				resultsp, (resultproc_t)rpc_wrap_bcast, "udp");
630 	trace4(TR_clnt_broadcast, 1, prog, vers, proc);
631 	return (dummy);
632 }
633 
634 /*
635  * Create the client des authentication object. Obsoleted by
636  * authdes_seccreate().
637  */
638 AUTH *
639 authdes_create(servername, window, syncaddr, ckey)
640 	char *servername;		/* network name of server */
641 	uint_t window;			/* time to live */
642 	struct sockaddr_in *syncaddr;	/* optional hostaddr to sync with */
643 	des_block *ckey;		/* optional conversation key to use */
644 {
645 	char *hostname = NULL;
646 	AUTH *dummy;
647 
648 	trace2(TR_authdes_create, 0, window);
649 	if (syncaddr) {
650 		/*
651 		 * Change addr to hostname, because that is the way
652 		 * new interface takes it.
653 		 */
654 		struct netconfig *nconf;
655 		struct netbuf nb_syncaddr;
656 		struct nd_hostservlist *hlist;
657 		AUTH *nauth;
658 		int fd;
659 		struct t_info tinfo;
660 
661 		if ((nconf = __rpc_getconfip("udp")) == NULL &&
662 		    (nconf = __rpc_getconfip("tcp")) == NULL)
663 			goto fallback;
664 
665 		/* Transform sockaddr_in to netbuf */
666 		if ((fd = t_open(nconf->nc_device, O_RDWR, &tinfo)) == -1) {
667 			(void) freenetconfigent(nconf);
668 			goto fallback;
669 		}
670 		(void) t_close(fd);
671 		nb_syncaddr.maxlen = nb_syncaddr.len =
672 			__rpc_get_a_size(tinfo.addr);
673 		nb_syncaddr.buf = (char *)syncaddr;
674 		if (netdir_getbyaddr(nconf, &hlist, &nb_syncaddr)) {
675 			(void) freenetconfigent(nconf);
676 			goto fallback;
677 		}
678 		if (hlist && hlist->h_cnt > 0 && hlist->h_hostservs)
679 			hostname = hlist->h_hostservs->h_host;
680 		nauth = authdes_seccreate(servername, window, hostname, ckey);
681 		(void) netdir_free((char *)hlist, ND_HOSTSERVLIST);
682 		(void) freenetconfigent(nconf);
683 		trace2(TR_authdes_create, 1, window);
684 		return (nauth);
685 	}
686 fallback:
687 	dummy = authdes_seccreate(servername, window, hostname, ckey);
688 	trace2(TR_authdes_create, 1, window);
689 	return (dummy);
690 }
691 
692 #endif /* PORTMAP */
693