transp_sockets.c revision 310490
1151497Sru/*
2151497Sru * Copyright (c) 1997-2014 Erez Zadok
3151497Sru * Copyright (c) 1990 Jan-Simon Pendry
4151497Sru * Copyright (c) 1990 Imperial College of Science, Technology & Medicine
5151497Sru * Copyright (c) 1990 The Regents of the University of California.
6151497Sru * All rights reserved.
7151497Sru *
8151497Sru * This code is derived from software contributed to Berkeley by
9151497Sru * Jan-Simon Pendry at Imperial College, London.
10151497Sru *
11151497Sru * Redistribution and use in source and binary forms, with or without
12151497Sru * modification, are permitted provided that the following conditions
13151497Sru * are met:
14151497Sru * 1. Redistributions of source code must retain the above copyright
15151497Sru *    notice, this list of conditions and the following disclaimer.
16151497Sru * 2. Redistributions in binary form must reproduce the above copyright
17151497Sru *    notice, this list of conditions and the following disclaimer in the
18151497Sru *    documentation and/or other materials provided with the distribution.
19151497Sru * 3. Neither the name of the University nor the names of its contributors
20151497Sru *    may be used to endorse or promote products derived from this software
21151497Sru *    without specific prior written permission.
22151497Sru *
23151497Sru * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24151497Sru * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25151497Sru * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26151497Sru * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27151497Sru * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28151497Sru * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29151497Sru * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30151497Sru * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31151497Sru * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32151497Sru * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33151497Sru * SUCH DAMAGE.
34151497Sru *
35151497Sru *
36151497Sru * File: am-utils/conf/transp/transp_sockets.c
37151497Sru *
38151497Sru * Socket specific utilities.
39151497Sru *      -Erez Zadok <ezk@cs.columbia.edu>
40151497Sru */
41151497Sru
42151497Sru#ifdef HAVE_CONFIG_H
43151497Sru# include <config.h>
44151497Sru#endif /* HAVE_CONFIG_H */
45151497Sru#include <am_defs.h>
46151497Sru#include <amu.h>
47151497Sru
48151497Sru
49151497Sru/*
50151497Sru * find the IP address that can be used to connect to the local host
51151497Sru */
52151497Sruvoid
53151497Sruamu_get_myaddress(struct in_addr *iap, const char *preferred_localhost)
54151497Sru{
55151497Sru  struct hostent *hp;
56151497Sru  char dq[20];
57151497Sru
58151497Sru#ifdef DEBUG_off
59151497Sru#error this code is old and probably not useful any longer.
60151497Sru#error Erez, Jan 21, 2004.
61151497Sru  struct sockaddr_in sin;
62151497Sru
63151497Sru  /*
64151497Sru   * Most modern systems should use 127.0.0.1 as the localhost address over
65151497Sru   * which you can do NFS mounts.  In the past we found that some NFS
66151497Sru   * clients may not allow mounts from localhost.  So we used
67151497Sru   * get_myaddress() and that seemed to work.  Alas, on some other systems,
68151497Sru   * get_myaddress() may return one of the interface addresses at random,
69151497Sru   * and thus use a less efficient IP address than 127.0.0.1.  The solution
70151497Sru   * is to hard-code 127.0.0.1, but still check if get_myaddress() returns a
71151497Sru   * different value and warn about it.
72151497Sru   */
73151497Sru  memset((char *) &sin, 0, sizeof(sin));
74151497Sru  get_myaddress(&sin);
75151497Sru  if (sin.sin_addr.s_addr != htonl(INADDR_LOOPBACK))
76151497Sru    dlog("amu_get_myaddress: myaddress conflict (0x%x vs. 0x%lx)",
77151497Sru	 sin.sin_addr.s_addr, (u_long) htonl(INADDR_LOOPBACK));
78151497Sru#endif /* DEBUG_off */
79151497Sru
80151497Sru  if (preferred_localhost == NULL)
81151497Sru    goto out;
82151497Sru
83151497Sru  /* if specified preferred locahost, then try to use it */
84151497Sru  hp = gethostbyname(preferred_localhost);
85151497Sru  if (hp == NULL) {
86151497Sru    /* XXX: if hstrerror()/h_errno aren't portable, then need to port the next statement */
87151497Sru    plog(XLOG_ERROR, "Unable to resolve localhost_address \"%s\" (%s): using default",
88151497Sru	 preferred_localhost, hstrerror(h_errno));
89151497Sru    goto out;
90151497Sru  }
91151497Sru  if (hp->h_addr_list == NULL) {
92151497Sru    plog(XLOG_ERROR, "localhost_address \"%s\" has no IP addresses: using default",
93151497Sru	 preferred_localhost);
94151497Sru    goto out;
95151497Sru  }
96151497Sru  if (hp->h_addr_list[1] != NULL) {
97151497Sru    plog(XLOG_ERROR, "localhost_address \"%s\" has more than one IP addresses: using first",
98151497Sru	 preferred_localhost);
99151497Sru    goto out;
100151497Sru  }
101151497Sru  memmove((voidp) &iap->s_addr, (voidp) hp->h_addr_list[0], sizeof(iap->s_addr));
102151497Sru  plog(XLOG_INFO, "localhost_address \"%s\" requested, using %s",
103151497Sru       preferred_localhost, inet_dquad(dq, sizeof(dq), iap->s_addr));
104151497Sru  return;
105151497Sru
106151497Sru out:
107151497Sru  iap->s_addr = htonl(INADDR_LOOPBACK);
108151497Sru}
109151497Sru
110151497Sru
111151497Sru/*
112151497Sru * How to bind to reserved ports.
113151497Sru * Note: if *pp is non-null and is greater than 0, then *pp will not be modified.
114151497Sru */
115151497Sruint
116151497Srubind_resv_port(int so, u_short *pp)
117151497Sru{
118151497Sru  struct sockaddr_in sin;
119151497Sru  int rc;
120151497Sru  u_short port;
121151497Sru
122151497Sru  memset((voidp) &sin, 0, sizeof(sin));
123151497Sru  sin.sin_family = AF_INET;
124151497Sru
125151497Sru  if (pp && *pp > 0) {
126151497Sru    sin.sin_port = htons(*pp);
127151497Sru    rc = bind(so, (struct sockaddr *) &sin, sizeof(sin));
128151497Sru  } else {
129151497Sru    port = IPPORT_RESERVED;
130151497Sru
131151497Sru    do {
132151497Sru      --port;
133151497Sru      sin.sin_port = htons(port);
134151497Sru      rc = bind(so, (struct sockaddr *) &sin, sizeof(sin));
135151497Sru    } while (rc < 0 && (int) port > IPPORT_RESERVED / 2);
136151497Sru
137151497Sru    if (pp && rc == 0)
138151497Sru      *pp = port;
139151497Sru  }
140151497Sru
141151497Sru  return rc;
142151497Sru}
143151497Sru
144151497Sru
145151497Sru/*
146151497Sru * close a descriptor, Sockets style
147151497Sru */
148151497Sruint
149151497Sruamu_close(int fd)
150151497Sru{
151151497Sru  return close(fd);
152151497Sru}
153151497Sru
154151497Sru
155151497Sru/*
156151497Sru * Create an rpc client attached to the mount daemon.
157151497Sru */
158151497SruCLIENT *
159151497Sruget_mount_client(char *unused_host, struct sockaddr_in *sin, struct timeval *tv, int *sock, u_long mnt_version)
160151497Sru{
161151497Sru  CLIENT *client;
162151497Sru
163151497Sru  /*
164151497Sru   * First try a TCP socket
165151497Sru   */
166151497Sru  if ((*sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) > 0) {
167151497Sru    /*
168151497Sru     * Bind to a privileged port
169151497Sru     */
170151497Sru    if (bind_resv_port(*sock, (u_short *) NULL) < 0)
171151497Sru      plog(XLOG_ERROR, "can't bind privileged port (socket)");
172151497Sru
173151497Sru    /*
174151497Sru     * Find mountd port to connect to.
175151497Sru     * Connect to mountd.
176151497Sru     * Create a tcp client.
177151497Sru     */
178151497Sru    if ((sin->sin_port = htons(pmap_getport(sin, MOUNTPROG, mnt_version, IPPROTO_TCP))) != 0) {
179151497Sru      if (connect(*sock, (struct sockaddr *) sin, sizeof(*sin)) >= 0
180151497Sru	  && ((client = clnttcp_create(sin, MOUNTPROG, mnt_version, sock, 0, 0)) != NULL))
181151497Sru	return client;
182151497Sru    }
183151497Sru    /*
184151497Sru     * Failed so close socket
185151497Sru     */
186151497Sru    (void) close(*sock);
187151497Sru  }				/* tcp socket opened */
188151497Sru  /* TCP failed so try UDP */
189151497Sru  if ((*sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
190151497Sru    plog(XLOG_ERROR, "Can't create socket to connect to mountd: %m");
191151497Sru    *sock = RPC_ANYSOCK;
192151497Sru    return NULL;
193151497Sru  }
194151497Sru  /*
195151497Sru   * Bind to a privileged port
196151497Sru   */
197151497Sru  if (bind_resv_port(*sock, (u_short *) NULL) < 0)
198151497Sru    plog(XLOG_ERROR, "can't bind privileged port");
199151497Sru
200151497Sru  /*
201151497Sru   * Zero out the port - make sure we recompute
202151497Sru   */
203151497Sru  sin->sin_port = 0;
204151497Sru
205151497Sru  /*
206151497Sru   * Make a UDP client
207151497Sru   */
208151497Sru  if ((client = clntudp_create(sin, MOUNTPROG, mnt_version, *tv, sock)) == NULL) {
209151497Sru    (void) close(*sock);
210151497Sru    *sock = RPC_ANYSOCK;
211151497Sru    return NULL;
212151497Sru  }
213151497Sru  dlog("get_mount_client: Using udp, port %d", sin->sin_port);
214151497Sru  return client;
215151497Sru}
216151497Sru
217151497Sru
218151497Sru/*
219151497Sru * find the address of the caller of an RPC procedure.
220151497Sru */
221151497Srustruct sockaddr_in *
222151497Sruamu_svc_getcaller(SVCXPRT *xprt)
223151497Sru{
224151497Sru  /* glibc 2.2 returns a sockaddr_storage ??? */
225151497Sru  return (struct sockaddr_in *) svc_getcaller(xprt);
226151497Sru}
227151497Sru
228151497Sru
229151497Sru/*
230151497Sru * Register an RPC server:
231151497Sru * return 1 on success, 0 otherwise.
232151497Sru */
233151497Sruint
234151497Sruamu_svc_register(SVCXPRT *xprt, u_long prognum, u_long versnum,
235151497Sru		 void (*dispatch)(struct svc_req *rqstp, SVCXPRT *transp),
236151497Sru		 u_long protocol, struct netconfig *dummy)
237151497Sru{
238151497Sru  /* on Sockets: svc_register returns 1 on success, 0 otherwise */
239151497Sru  return svc_register(xprt, prognum, versnum, dispatch, protocol);
240151497Sru}
241151497Sru
242151497Sru
243151497Sru/*
244151497Sru * Create the nfs service for amd
245151497Sru */
246151497Sruint
247151497Srucreate_nfs_service(int *soNFSp, u_short *nfs_portp, SVCXPRT **nfs_xprtp, void (*dispatch_fxn)(struct svc_req *rqstp, SVCXPRT *transp), u_long nfs_version)
248151497Sru{
249151497Sru  *soNFSp = socket(AF_INET, SOCK_DGRAM, 0);
250151497Sru
251151497Sru  if (*soNFSp < 0 || bind_resv_port(*soNFSp, nfs_portp) < 0) {
252151497Sru    plog(XLOG_FATAL, "Can't create privileged nfs port (socket)");
253151497Sru    if (*soNFSp >= 0)
254151497Sru      close(*soNFSp);
255151497Sru    return 1;
256151497Sru  }
257151497Sru  if ((*nfs_xprtp = svcudp_create(*soNFSp)) == NULL) {
258151497Sru    plog(XLOG_FATAL, "cannot create rpc/udp service");
259151497Sru    close(*soNFSp);
260151497Sru    return 2;
261151497Sru  }
262151497Sru  if ((*nfs_portp = (*nfs_xprtp)->xp_port) >= IPPORT_RESERVED) {
263151497Sru    plog(XLOG_FATAL, "Can't create privileged nfs port");
264151497Sru    svc_destroy(*nfs_xprtp);
265151497Sru    close(*soNFSp);
266151497Sru    return 1;
267151497Sru  }
268151497Sru  if (!svc_register(*nfs_xprtp, NFS_PROGRAM, nfs_version, dispatch_fxn, 0)) {
269151497Sru    plog(XLOG_FATAL, "unable to register (%lu, %lu, 0)",
270151497Sru	 (u_long) NFS_PROGRAM, nfs_version);
271151497Sru    svc_destroy(*nfs_xprtp);
272151497Sru    close(*soNFSp);
273151497Sru    return 3;
274151497Sru  }
275151497Sru
276151497Sru  return 0;			/* all is well */
277151497Sru}
278151497Sru
279151497Sru
280151497Sru/*
281151497Sru * Create the amq service for amd (both TCP and UDP)
282151497Sru */
283151497Sruint
284151497Srucreate_amq_service(int *udp_soAMQp,
285151497Sru		   SVCXPRT **udp_amqpp,
286151497Sru		   struct netconfig **dummy1,
287151497Sru		   int *tcp_soAMQp,
288151497Sru		   SVCXPRT **tcp_amqpp,
289151497Sru		   struct netconfig **dummy2,
290151497Sru		   u_short preferred_amq_port)
291151497Sru{
292151497Sru  /* first create TCP service */
293151497Sru  if (tcp_soAMQp) {
294151497Sru    *tcp_soAMQp = socket(AF_INET, SOCK_STREAM, 0);
295151497Sru    if (*tcp_soAMQp < 0) {
296151497Sru      plog(XLOG_FATAL, "cannot create tcp socket for amq service: %m");
297151497Sru      return 1;
298151497Sru    }
299151497Sru
300151497Sru    /* next, bind to a specific (TCP) port if asked for */
301151497Sru    if (preferred_amq_port > 0) {
302151497Sru      /*
303151497Sru       * Note: if &preferred_amq_port is non-null and is greater than 0,
304151497Sru       * then the pointer will not be modified.  We don't want it to be
305151497Sru       * modified because it was passed down to create_amq_service as a
306151497Sru       * non-pointer (a variable on the stack, not to be modified!)
307151497Sru       */
308151497Sru      if (bind_resv_port(*tcp_soAMQp, &preferred_amq_port) < 0) {
309151497Sru	plog(XLOG_FATAL, "can't bind amq service to requested TCP port %d: %m)", preferred_amq_port);
310151497Sru	return 1;
311151497Sru      }
312151497Sru    }
313151497Sru
314151497Sru    /* now create RPC service handle for amq */
315151497Sru    if (tcp_amqpp &&
316151497Sru	(*tcp_amqpp = svctcp_create(*tcp_soAMQp, AMQ_SIZE, AMQ_SIZE)) == NULL) {
317151497Sru      plog(XLOG_FATAL, "cannot create tcp service for amq: soAMQp=%d", *tcp_soAMQp);
318151497Sru      return 1;
319151497Sru    }
320151497Sru
321151497Sru#ifdef SVCSET_CONNMAXREC
322151497Sru    /*
323151497Sru     * This is *BSD at its best.
324151497Sru     * They just had to do things differently than everyone else
325151497Sru     * so they fixed a library DoS issue by forcing client-side changes...
326151497Sru     */
327151497Sru# ifndef RPC_MAXDATASIZE
328151497Sru#  define RPC_MAXDATASIZE 9000
329151497Sru# endif /* not RPC_MAXDATASIZE */
330151497Sru    if (tcp_amqpp) {
331151497Sru      int maxrec = RPC_MAXDATASIZE;
332151497Sru      SVC_CONTROL(*tcp_amqpp, SVCSET_CONNMAXREC, &maxrec);
333151497Sru    }
334151497Sru#endif /* not SVCSET_CONNMAXREC */
335151497Sru  }
336151497Sru
337151497Sru  /* next create UDP service */
338151497Sru  if (udp_soAMQp) {
339151497Sru    *udp_soAMQp = socket(AF_INET, SOCK_DGRAM, 0);
340151497Sru    if (*udp_soAMQp < 0) {
341151497Sru      plog(XLOG_FATAL, "cannot create udp socket for amq service: %m");
342151497Sru      return 1;
343151497Sru    }
344151497Sru
345151497Sru    /* next, bind to a specific (UDP) port if asked for */
346151497Sru    if (preferred_amq_port > 0) {
347151497Sru      /*
348151497Sru       * Note: see comment about using &preferred_amq_port above in this
349151497Sru       * function.
350151497Sru       */
351151497Sru      if (bind_resv_port(*udp_soAMQp, &preferred_amq_port) < 0) {
352151497Sru	plog(XLOG_FATAL, "can't bind amq service to requested UDP port %d: %m)", preferred_amq_port);
353151497Sru	return 1;
354151497Sru      }
355151497Sru    }
356151497Sru
357151497Sru    /* now create RPC service handle for amq */
358151497Sru    if (udp_amqpp &&
359151497Sru	(*udp_amqpp = svcudp_bufcreate(*udp_soAMQp, AMQ_SIZE, AMQ_SIZE)) == NULL) {
360151497Sru      plog(XLOG_FATAL, "cannot create udp service for amq: soAMQp=%d", *udp_soAMQp);
361151497Sru      return 1;
362151497Sru    }
363151497Sru  }
364151497Sru
365151497Sru  return 0;			/* all is well */
366151497Sru}
367151497Sru
368151497Sru
369151497Sru/*
370151497Sru * Check if the portmapper is running and reachable: 0==down, 1==up
371151497Sru */
372151497Sruint check_pmap_up(char *host, struct sockaddr_in* sin)
373151497Sru{
374151497Sru  CLIENT *client;
375151497Sru  enum clnt_stat clnt_stat = RPC_TIMEDOUT; /* assume failure */
376151497Sru  int socket = RPC_ANYSOCK;
377151497Sru  struct timeval timeout;
378151497Sru
379151497Sru  timeout.tv_sec = 2;
380151497Sru  timeout.tv_usec = 0;
381151497Sru  sin->sin_port = htons(PMAPPORT);
382151497Sru  client = clntudp_create(sin, PMAPPROG, PMAPVERS, timeout, &socket);
383151497Sru
384151497Sru  if (client == (CLIENT *) NULL) {
385151497Sru    plog(XLOG_ERROR,
386151497Sru	 "%s: cannot create connection to contact portmapper on host \"%s\"%s",
387151497Sru	 __func__, host, clnt_spcreateerror(""));
388151497Sru    return 0;
389151497Sru  }
390151497Sru
391151497Sru  timeout.tv_sec = 6;
392151497Sru  /* Ping the portmapper on a remote system by calling the nullproc */
393151497Sru  clnt_stat = clnt_call(client,
394151497Sru			PMAPPROC_NULL,
395151497Sru			(XDRPROC_T_TYPE) xdr_void,
396151497Sru			NULL,
397151497Sru			(XDRPROC_T_TYPE) xdr_void,
398151497Sru			NULL,
399151497Sru			timeout);
400151497Sru  clnt_destroy(client);
401151497Sru  close(socket);
402151497Sru  sin->sin_port = 0;
403151497Sru
404151497Sru  if (clnt_stat == RPC_TIMEDOUT) {
405151497Sru    plog(XLOG_ERROR,
406151497Sru	 "%s: failed to contact portmapper on host \"%s\": %s",
407151497Sru	 __func__, host, clnt_sperrno(clnt_stat));
408151497Sru    return 0;
409151497Sru  }
410151497Sru  return 1;
411151497Sru}
412151497Sru
413151497Sru
414151497Sru/*
415151497Sru * Find the best NFS version for a host and protocol.
416151497Sru */
417151497Sruu_long
418151497Sruget_nfs_version(char *host, struct sockaddr_in *sin, u_long nfs_version, const char *proto, u_long def)
419151497Sru{
420151497Sru  CLIENT *clnt;
421151497Sru  int again = 0;
422151497Sru  enum clnt_stat clnt_stat;
423151497Sru  struct timeval tv;
424151497Sru  int sock;
425151497Sru  char *errstr;
426151497Sru
427151497Sru  /*
428151497Sru   * If not set or set wrong, then try from NFS_VERS_MAX on down. If
429151497Sru   * set, then try from nfs_version on down.
430151497Sru   */
431151497Sru  if (!nfs_valid_version(nfs_version)) {
432151497Sru    if (nfs_valid_version(def))
433151497Sru      nfs_version = def;
434151497Sru    else
435151497Sru      nfs_version = NFS_VERS_MAX;
436151497Sru    again = 1;
437151497Sru  }
438151497Sru  tv.tv_sec = 2;		/* retry every 2 seconds, but also timeout */
439151497Sru  tv.tv_usec = 0;
440151497Sru
441151497Sru  for (; nfs_version >= NFS_VERS_MIN; nfs_version--) {
442151497Sru
443151497Sru    sock = RPC_ANYSOCK;
444151497Sru    errstr = NULL;
445151497Sru    if (STREQ(proto, "tcp"))
446151497Sru      clnt = clnttcp_create(sin, NFS_PROGRAM, nfs_version, &sock, 0, 0);
447151497Sru    else if (STREQ(proto, "udp"))
448151497Sru      clnt = clntudp_create(sin, NFS_PROGRAM, nfs_version, tv, &sock);
449151497Sru    else
450151497Sru      clnt = NULL;
451151497Sru
452151497Sru    if (clnt != NULL) {
453151497Sru      /* Try three times (6/2=3) to verify the CLIENT handle. */
454151497Sru      tv.tv_sec = 6;
455151497Sru      clnt_stat = clnt_call(clnt,
456151497Sru			    NFSPROC_NULL,
457151497Sru			    (XDRPROC_T_TYPE) xdr_void,
458151497Sru			    0,
459151497Sru			    (XDRPROC_T_TYPE) xdr_void,
460151497Sru			    0,
461151497Sru			    tv);
462151497Sru
463151497Sru      if (clnt_stat != RPC_SUCCESS)
464151497Sru	errstr = clnt_sperrno(clnt_stat);
465151497Sru
466151497Sru      close(sock);
467151497Sru      clnt_destroy(clnt);
468151497Sru      if (clnt_stat == RPC_SUCCESS)
469151497Sru	break;
470151497Sru    } else {
471151497Sru  #ifdef HAVE_CLNT_SPCREATEERROR
472151497Sru      errstr = clnt_spcreateerror("");
473151497Sru  #else /* not HAVE_CLNT_SPCREATEERROR */
474151497Sru      errstr = "";
475151497Sru  #endif /* not HAVE_CLNT_SPCREATEERROR */
476151497Sru    }
477151497Sru
478151497Sru    if (errstr) {
479151497Sru      plog(XLOG_INFO, "%s: NFS(%lu,%s) failed for %s: %s", __func__,
480151497Sru	   nfs_version, proto, host, errstr);
481151497Sru    }
482151497Sru  }
483151497Sru
484151497Sru  if (nfs_version < NFS_VERS_MIN)
485151497Sru    nfs_version = 0;
486151497Sru
487151497Sru  plog(XLOG_INFO, "%s: returning NFS(%lu,%s) on host %s", __func__,
488151497Sru       nfs_version, proto, host);
489151497Sru  return nfs_version;
490151497Sru}
491151497Sru
492151497Sru
493151497Sru#if defined(HAVE_FS_AUTOFS) && defined(AUTOFS_PROG)
494151497Sru/*
495151497Sru * Register the autofs service for amd
496151497Sru */
497151497Sruint
498151497Sruregister_autofs_service(char *autofs_conftype, void (*autofs_dispatch)(struct svc_req *rqstp, SVCXPRT *transp))
499151497Sru{
500151497Sru  int autofs_socket;
501151497Sru  SVCXPRT *autofs_xprt = NULL;
502151497Sru
503151497Sru  autofs_socket = socket(AF_INET, SOCK_DGRAM, 0);
504151497Sru
505151497Sru  if (autofs_socket < 0 || bind_resv_port(autofs_socket, NULL) < 0) {
506151497Sru    plog(XLOG_FATAL, "Can't create privileged autofs port (socket)");
507151497Sru    return 1;
508151497Sru  }
509151497Sru  if ((autofs_xprt = svcudp_create(autofs_socket)) == NULL) {
510151497Sru    plog(XLOG_FATAL, "Can't create autofs rpc/udp service");
511151497Sru    return 2;
512151497Sru  }
513151497Sru  if (autofs_xprt->xp_port >= IPPORT_RESERVED) {
514151497Sru    plog(XLOG_FATAL, "Can't create privileged autofs port");
515151497Sru    return 1;
516151497Sru  }
517151497Sru  if (!svc_register(autofs_xprt, AUTOFS_PROG, AUTOFS_VERS, autofs_dispatch, 0)) {
518151497Sru    plog(XLOG_FATAL, "unable to register (%ld, %ld, 0)",
519151497Sru	 (u_long) AUTOFS_PROG, (u_long) AUTOFS_VERS);
520151497Sru    return 3;
521151497Sru  }
522151497Sru
523151497Sru  return 0;			/* all is well */
524151497Sru}
525151497Sru
526151497Sru
527151497Sruint
528151497Sruunregister_autofs_service(char *autofs_conftype)
529151497Sru{
530151497Sru  svc_unregister(AUTOFS_PROG, AUTOFS_VERS);
531151497Sru  return 0;
532151497Sru}
533151497Sru#endif /* HAVE_FS_AUTOFS && AUTOFS_PROG */
534151497Sru