Merge branch 'vendor/DHCPCD'
[dragonfly.git] / lib / libc / rpc / clnt_generic.c
1 /*
2  * The contents of this file are subject to the Sun Standards
3  * License Version 1.0 the (the "License";) You may not use
4  * this file except in compliance with the License.  You may
5  * obtain a copy of the License at lib/libc/rpc/LICENSE
6  *
7  * Software distributed under the License is distributed on
8  * an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either
9  * express or implied.  See the License for the specific
10  * language governing rights and limitations under the License.
11  *
12  * The Original Code is Copyright 1998 by Sun Microsystems, Inc
13  *
14  * The Initial Developer of the Original Code is:  Sun
15  * Microsystems, Inc.
16  *
17  * All Rights Reserved.
18  *
19  * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
20  * unrestricted use provided that this legend is included on all tape
21  * media and as a part of the software program in whole or part.  Users
22  * may copy or modify Sun RPC without charge, but are not authorized
23  * to license or distribute it to anyone else except as part of a product or
24  * program developed by the user.
25  *
26  * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
27  * WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
28  * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
29  *
30  * Sun RPC is provided with no support and without any obligation on the
31  * part of Sun Microsystems, Inc. to assist in its use, correction,
32  * modification or enhancement.
33  *
34  * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
35  * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
36  * OR ANY PART THEREOF.
37  *
38  * In no event will Sun Microsystems, Inc. be liable for any lost revenue
39  * or profits or other special, indirect and consequential damages, even if
40  * Sun has been advised of the possibility of such damages.
41  *
42  * Sun Microsystems, Inc.
43  * 2550 Garcia Avenue
44  * Mountain View, California  94043
45  *
46  * @(#)clnt_generic.c 1.4 87/08/11 (C) 1987 SMI
47  * @(#)clnt_generic.c   2.2 88/08/01 4.0 RPCSRC
48  * @(#)clnt_generic.c   1.40    99/04/21 SMI
49  * $NetBSD: clnt_generic.c,v 1.18 2000/07/06 03:10:34 christos Exp $
50  * $FreeBSD: src/lib/libc/rpc/clnt_generic.c,v 1.15 2004/10/16 06:11:34 obrien Exp $
51  */
52
53 /*
54  * Copyright (c) 1986-1996,1998 by Sun Microsystems, Inc.
55  * All rights reserved.
56  */
57 #include "namespace.h"
58 #include "reentrant.h"
59 #include <sys/types.h>
60 #include <sys/fcntl.h>
61 #include <sys/socket.h>
62 #include <netinet/in.h>
63 #include <netinet/tcp.h>
64 #include <stdio.h>
65 #include <errno.h>
66 #include <netdb.h>
67 #include <syslog.h>
68 #include <rpc/rpc.h>
69 #include <rpc/nettype.h>
70 #include <string.h>
71 #include <stdlib.h>
72 #include <unistd.h>
73 #include "un-namespace.h"
74 #include "rpc_com.h"
75
76 extern bool_t   __rpc_is_local_host(const char *);
77 int             __rpc_raise_fd(int);
78
79 #ifndef NETIDLEN
80 #define NETIDLEN 32
81 #endif
82
83
84 /*
85  * Generic client creation with version checking the value of
86  * vers_out is set to the highest server supported value
87  * vers_low <= vers_out <= vers_high  AND an error results
88  * if this can not be done.
89  *
90  * It calls clnt_create_vers_timed() with a NULL value for the timeout
91  * pointer, which indicates that the default timeout should be used.
92  */
93 CLIENT *
94 clnt_create_vers(const char *hostname, rpcprog_t prog, rpcvers_t *vers_out,
95                  rpcvers_t vers_low, rpcvers_t vers_high, const char *nettype)
96 {
97
98         return (clnt_create_vers_timed(hostname, prog, vers_out, vers_low,
99                                 vers_high, nettype, NULL));
100 }
101
102 /*
103  * This the routine has the same definition as clnt_create_vers(),
104  * except it takes an additional timeout parameter - a pointer to
105  * a timeval structure.  A NULL value for the pointer indicates
106  * that the default timeout value should be used.
107  */
108 CLIENT *
109 clnt_create_vers_timed(const char *hostname, rpcprog_t prog,
110     rpcvers_t *vers_out, rpcvers_t vers_low, rpcvers_t vers_high,
111     const char *nettype, const struct timeval *tp)
112 {
113         CLIENT *clnt;
114         struct timeval to;
115         enum clnt_stat rpc_stat;
116         struct rpc_err rpcerr;
117
118         clnt = clnt_create_timed(hostname, prog, vers_high, nettype, tp);
119         if (clnt == NULL) {
120                 return (NULL);
121         }
122         to.tv_sec = 10;
123         to.tv_usec = 0;
124         rpc_stat = clnt_call(clnt, NULLPROC, (xdrproc_t)xdr_void,
125                         NULL, (xdrproc_t)xdr_void, NULL, to);
126         if (rpc_stat == RPC_SUCCESS) {
127                 *vers_out = vers_high;
128                 return (clnt);
129         }
130         while (rpc_stat == RPC_PROGVERSMISMATCH && vers_high > vers_low) {
131                 unsigned int minvers, maxvers;
132
133                 clnt_geterr(clnt, &rpcerr);
134                 minvers = rpcerr.re_vers.low;
135                 maxvers = rpcerr.re_vers.high;
136                 if (maxvers < vers_high)
137                         vers_high = maxvers;
138                 else
139                         vers_high--;
140                 if (minvers > vers_low)
141                         vers_low = minvers;
142                 if (vers_low > vers_high) {
143                         goto error;
144                 }
145                 CLNT_CONTROL(clnt, CLSET_VERS, (char *)&vers_high);
146                 rpc_stat = clnt_call(clnt, NULLPROC, (xdrproc_t)xdr_void,
147                                 NULL, (xdrproc_t)xdr_void,
148                                 NULL, to);
149                 if (rpc_stat == RPC_SUCCESS) {
150                         *vers_out = vers_high;
151                         return (clnt);
152                 }
153         }
154         clnt_geterr(clnt, &rpcerr);
155
156 error:
157         rpc_createerr.cf_stat = rpc_stat;
158         rpc_createerr.cf_error = rpcerr;
159         clnt_destroy(clnt);
160         return (NULL);
161 }
162
163 /*
164  * Top level client creation routine.
165  * Generic client creation: takes (servers name, program-number, nettype) and
166  * returns client handle. Default options are set, which the user can
167  * change using the rpc equivalent of _ioctl()'s.
168  *
169  * It tries for all the netids in that particular class of netid until
170  * it succeeds.
171  * XXX The error message in the case of failure will be the one
172  * pertaining to the last create error.
173  *
174  * It calls clnt_create_timed() with the default timeout.
175  */
176 CLIENT *
177 clnt_create(const char *hostname, rpcprog_t prog, rpcvers_t vers,
178     const char *nettype)
179 {
180
181         return (clnt_create_timed(hostname, prog, vers, nettype, NULL));
182 }
183
184 /*
185  * This the routine has the same definition as clnt_create(),
186  * except it takes an additional timeout parameter - a pointer to
187  * a timeval structure.  A NULL value for the pointer indicates
188  * that the default timeout value should be used.
189  *
190  * This function calls clnt_tp_create_timed().
191  */
192 CLIENT *
193 clnt_create_timed(const char *hostname, rpcprog_t prog, rpcvers_t vers,
194     const char *netclass, const struct timeval *tp)
195 {
196         struct netconfig *nconf;
197         CLIENT *clnt = NULL;
198         void *handle;
199         enum clnt_stat  save_cf_stat = RPC_SUCCESS;
200         struct rpc_err  save_cf_error;
201         char nettype_array[NETIDLEN];
202         char *nettype = &nettype_array[0];
203
204         if (netclass == NULL)
205                 nettype = NULL;
206         else {
207                 size_t len = strlen(netclass);
208                 if (len >= sizeof (nettype_array)) {
209                         rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
210                         return (NULL);
211                 }
212                 strcpy(nettype, netclass);
213         }
214
215         if ((handle = __rpc_setconf((char *)nettype)) == NULL) {
216                 rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
217                 return (NULL);
218         }
219         rpc_createerr.cf_stat = RPC_SUCCESS;
220         while (clnt == NULL) {
221                 if ((nconf = __rpc_getconf(handle)) == NULL) {
222                         if (rpc_createerr.cf_stat == RPC_SUCCESS)
223                                 rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
224                         break;
225                 }
226 #ifdef CLNT_DEBUG
227                 printf("trying netid %s\n", nconf->nc_netid);
228 #endif
229                 clnt = clnt_tp_create_timed(hostname, prog, vers, nconf, tp);
230                 if (clnt)
231                         break;
232                 else
233                         /*
234                          *      Since we didn't get a name-to-address
235                          *      translation failure here, we remember
236                          *      this particular error.  The object of
237                          *      this is to enable us to return to the
238                          *      caller a more-specific error than the
239                          *      unhelpful ``Name to address translation
240                          *      failed'' which might well occur if we
241                          *      merely returned the last error (because
242                          *      the local loopbacks are typically the
243                          *      last ones in /etc/netconfig and the most
244                          *      likely to be unable to translate a host
245                          *      name).  We also check for a more
246                          *      meaningful error than ``unknown host
247                          *      name'' for the same reasons.
248                          */
249                         if (rpc_createerr.cf_stat != RPC_N2AXLATEFAILURE &&
250                             rpc_createerr.cf_stat != RPC_UNKNOWNHOST) {
251                                 save_cf_stat = rpc_createerr.cf_stat;
252                                 save_cf_error = rpc_createerr.cf_error;
253                         }
254         }
255
256         /*
257          *      Attempt to return an error more specific than ``Name to address
258          *      translation failed'' or ``unknown host name''
259          */
260         if ((rpc_createerr.cf_stat == RPC_N2AXLATEFAILURE ||
261                                 rpc_createerr.cf_stat == RPC_UNKNOWNHOST) &&
262                                         (save_cf_stat != RPC_SUCCESS)) {
263                 rpc_createerr.cf_stat = save_cf_stat;
264                 rpc_createerr.cf_error = save_cf_error;
265         }
266         __rpc_endconf(handle);
267         return (clnt);
268 }
269
270 /*
271  * Generic client creation: takes (servers name, program-number, netconf) and
272  * returns client handle. Default options are set, which the user can
273  * change using the rpc equivalent of _ioctl()'s : clnt_control()
274  * It finds out the server address from rpcbind and calls clnt_tli_create().
275  *
276  * It calls clnt_tp_create_timed() with the default timeout.
277  */
278 CLIENT *
279 clnt_tp_create(const char *hostname, rpcprog_t prog, rpcvers_t vers,
280     const struct netconfig *nconf)
281 {
282
283         return (clnt_tp_create_timed(hostname, prog, vers, nconf, NULL));
284 }
285
286 /*
287  * This has the same definition as clnt_tp_create(), except it
288  * takes an additional parameter - a pointer to a timeval structure.
289  * A NULL value for the timeout pointer indicates that the default
290  * value for the timeout should be used.
291  */
292 CLIENT *
293 clnt_tp_create_timed(const char *hostname, rpcprog_t prog, rpcvers_t vers,
294     const struct netconfig *nconf, const struct timeval *tp)
295 {
296         struct netbuf *svcaddr;                 /* servers address */
297         CLIENT *cl = NULL;                      /* client handle */
298
299         if (nconf == NULL) {
300                 rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
301                 return (NULL);
302         }
303
304         /*
305          * Get the address of the server
306          */
307         if ((svcaddr = __rpcb_findaddr_timed(prog, vers,
308                         (struct netconfig *)nconf, (char *)hostname,
309                         &cl, (struct timeval *)tp)) == NULL) {
310                 /* appropriate error number is set by rpcbind libraries */
311                 return (NULL);
312         }
313         if (cl == NULL) {
314                 cl = clnt_tli_create(RPC_ANYFD, nconf, svcaddr,
315                                         prog, vers, 0, 0);
316         } else {
317                 /* Reuse the CLIENT handle and change the appropriate fields */
318                 if (CLNT_CONTROL(cl, CLSET_SVC_ADDR, (void *)svcaddr) == TRUE) {
319                         if (cl->cl_netid == NULL)
320                                 cl->cl_netid = strdup(nconf->nc_netid);
321                         if (cl->cl_tp == NULL)
322                                 cl->cl_tp = strdup(nconf->nc_device);
323                         CLNT_CONTROL(cl, CLSET_PROG, (void *)&prog);
324                         CLNT_CONTROL(cl, CLSET_VERS, (void *)&vers);
325                 } else {
326                         CLNT_DESTROY(cl);
327                         cl = clnt_tli_create(RPC_ANYFD, nconf, svcaddr,
328                                         prog, vers, 0, 0);
329                 }
330         }
331         free(svcaddr->buf);
332         free(svcaddr);
333         return (cl);
334 }
335
336 /*
337  * Generic client creation:  returns client handle.
338  * Default options are set, which the user can
339  * change using the rpc equivalent of _ioctl()'s : clnt_control().
340  * If fd is RPC_ANYFD, it will be opened using nconf.
341  * It will be bound if not so.
342  * If sizes are 0; appropriate defaults will be chosen.
343  */
344 CLIENT *
345 clnt_tli_create(int fd, const struct netconfig *nconf,
346         struct netbuf *svcaddr, rpcprog_t prog, rpcvers_t vers,
347         uint sendsz, uint recvsz)
348 {
349         CLIENT *cl;                     /* client handle */
350         bool_t madefd = FALSE;          /* whether fd opened here */
351         long servtype;
352         int one = 1;
353         struct __rpc_sockinfo si;
354         extern int __rpc_minfd;
355
356         if (fd == RPC_ANYFD) {
357                 if (nconf == NULL) {
358                         rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
359                         return (NULL);
360                 }
361
362                 fd = __rpc_nconf2fd(nconf);
363
364                 if (fd == -1)
365                         goto err;
366                 if (fd < __rpc_minfd)
367                         fd = __rpc_raise_fd(fd);
368                 madefd = TRUE;
369                 servtype = nconf->nc_semantics;
370                 if (!__rpc_fd2sockinfo(fd, &si))
371                         goto err;
372                 bindresvport(fd, NULL);
373         } else {
374                 if (!__rpc_fd2sockinfo(fd, &si))
375                         goto err;
376                 servtype = __rpc_socktype2seman(si.si_socktype);
377                 if (servtype == -1) {
378                         rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
379                         return (NULL);
380                 }
381         }
382
383         if (si.si_af != ((struct sockaddr *)svcaddr->buf)->sa_family) {
384                 rpc_createerr.cf_stat = RPC_UNKNOWNHOST;        /* XXX */
385                 goto err1;
386         }
387
388         switch (servtype) {
389         case NC_TPI_COTS:
390                 cl = clnt_vc_create(fd, svcaddr, prog, vers, sendsz, recvsz);
391                 break;
392         case NC_TPI_COTS_ORD:
393                 if (nconf && ((strcmp(nconf->nc_protofmly, "inet") == 0))) {
394                         _setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &one,
395                             sizeof (one));
396                 }
397                 cl = clnt_vc_create(fd, svcaddr, prog, vers, sendsz, recvsz);
398                 break;
399         case NC_TPI_CLTS:
400                 cl = clnt_dg_create(fd, svcaddr, prog, vers, sendsz, recvsz);
401                 break;
402         default:
403                 goto err;
404         }
405
406         if (cl == NULL)
407                 goto err1; /* borrow errors from clnt_dg/vc creates */
408         if (nconf) {
409                 cl->cl_netid = strdup(nconf->nc_netid);
410                 cl->cl_tp = strdup(nconf->nc_device);
411         } else {
412                 cl->cl_netid = "";
413                 cl->cl_tp = "";
414         }
415         if (madefd) {
416                 CLNT_CONTROL(cl, CLSET_FD_CLOSE, NULL);
417 /*              CLNT_CONTROL(cl, CLSET_POP_TIMOD, NULL);  */
418         }
419
420         return (cl);
421
422 err:
423         rpc_createerr.cf_stat = RPC_SYSTEMERROR;
424         rpc_createerr.cf_error.re_errno = errno;
425 err1:   if (madefd)
426                 _close(fd);
427         return (NULL);
428 }
429
430 /*
431  *  To avoid conflicts with the "magic" file descriptors (0, 1, and 2),
432  *  we try to not use them.  The __rpc_raise_fd() routine will dup
433  *  a descriptor to a higher value.  If we fail to do it, we continue
434  *  to use the old one (and hope for the best).
435  */
436 int __rpc_minfd = 3;
437
438 int
439 __rpc_raise_fd(int fd)
440 {
441         int nfd;
442
443         if (fd >= __rpc_minfd)
444                 return (fd);
445
446         if ((nfd = _fcntl(fd, F_DUPFD, __rpc_minfd)) == -1)
447                 return (fd);
448
449         if (_fsync(nfd) == -1) {
450                 _close(nfd);
451                 return (fd);
452         }
453
454         if (_close(fd) == -1) {
455                 /* this is okay, we will syslog an error, then use the new fd */
456                 syslog(LOG_ERR, "could not close() fd %d; mem & fd leak", fd);
457         }
458
459         return (nfd);
460 }