int
rresvport(int *alport )
{
	struct sockaddr_in sin;
	int s;

	bzero(&sin, sizeof sin);
	sin.sin_len = sizeof(struct sockaddr_in);
	sin.sin_family = AF_INET;
	sin.sin_addr.s_addr = INADDR_ANY;
	s = socket(AF_INET, SOCK_STREAM, 0);
	if (s < 0)
		return (-1);
#if 0 /* compat_exact_traditional_rresvport_semantics */
	sin.sin_port = htons((u_short)*alport);
	if (bind(s, (struct sockaddr *)&sin, sizeof(sin)) >= 0)
		return (s);
	if (errno != EADDRINUSE) {
		(void)close(s);
		return (-1);
	}
#endif
	sin.sin_port = 0;
	if (bindresvport(s, &sin) == -1) {
		(void)close(s);
		return (-1);
	}
	*alport = (int)ntohs(sin.sin_port);
	return (s);
}
Beispiel #2
0
/*
 * Usage:
 *      xprt = svctcp_create(sock, send_buf_size, recv_buf_size);
 *
 * Creates, registers, and returns a (rpc) tcp based transporter.
 * Once *xprt is initialized, it is registered as a transporter
 * see (svc.h, xprt_register).  This routine returns
 * a NULL if a problem occurred.
 *
 * If sock<0 then a socket is created, else sock is used.
 * If the socket, sock is not bound to a port then svctcp_create
 * binds it to an arbitrary port.  The routine then starts a tcp
 * listener on the socket's associated port.  In any (successful) case,
 * xprt->xp_sock is the registered socket number and xprt->xp_port is the
 * associated port number.
 *
 * Since tcp streams do buffered io similar to stdio, the caller can specify
 * how big the send and receive buffers are via the second and third parms;
 * 0 => use the system default.
 */
SVCXPRT *
svctcp_create (int sock, u_int sendsize, u_int recvsize)
{
  bool_t madesock = FALSE;
  SVCXPRT *xprt;
  struct tcp_rendezvous *r;
  struct sockaddr_in addr;
  socklen_t len = sizeof (struct sockaddr_in);

  if (sock == RPC_ANYSOCK)
    {
      if ((sock = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
	{
	  perror (_("svc_tcp.c - tcp socket creation problem"));
	  return (SVCXPRT *) NULL;
	}
      madesock = TRUE;
    }
  bzero ((char *) &addr, sizeof (addr));
  addr.sin_family = AF_INET;
  if (bindresvport (sock, &addr))
    {
      addr.sin_port = 0;
      (void) bind (sock, (struct sockaddr *) &addr, len);
    }
  if ((getsockname (sock, (struct sockaddr *) &addr, &len) != 0) ||
      (listen (sock, 2) != 0))
    {
      perror (_("svc_tcp.c - cannot getsockname or listen"));
      if (madesock)
	(void) close (sock);
      return (SVCXPRT *) NULL;
    }
  r = (struct tcp_rendezvous *) mem_alloc (sizeof (*r));
  xprt = (SVCXPRT *) mem_alloc (sizeof (SVCXPRT));
  if (r == NULL || xprt == NULL)
    {
#ifdef USE_IN_LIBIO
      if (_IO_fwide (stderr, 0) > 0)
	(void) __fwprintf (stderr, L"%s", _("svctcp_create: out of memory\n"));
      else
#endif
	(void) fputs (_("svctcp_create: out of memory\n"), stderr);
      mem_free (r, sizeof (*r));
      mem_free (xprt, sizeof (SVCXPRT));
      return NULL;
    }
  r->sendsize = sendsize;
  r->recvsize = recvsize;
  xprt->xp_p2 = NULL;
  xprt->xp_p1 = (caddr_t) r;
  xprt->xp_verf = _null_auth;
  xprt->xp_ops = &svctcp_rendezvous_op;
  xprt->xp_port = ntohs (addr.sin_port);
  xprt->xp_sock = sock;
  xprt_register (xprt);
  return xprt;
}
Beispiel #3
0
/*
 * A common server create routine
 */
static SVCXPRT *
svc_com_create(int fd, u_int sendsize, u_int recvsize, const char *netid)
{
	struct netconfig *nconf;
	SVCXPRT *svc;
	int madefd = FALSE;
	int port;
	struct sockaddr_in sccsin;

	_DIAGASSERT(netid != NULL);

	if ((nconf = __rpc_getconfip(netid)) == NULL) {
		(void) syslog(LOG_ERR, "Could not get %s transport", netid);
		return (NULL);
	}
	if (fd == RPC_ANYSOCK) {
		fd = __rpc_nconf2fd(nconf);
		if (fd == -1) {
			(void) freenetconfigent(nconf);
			(void) syslog(LOG_ERR,
			"svc%s_create: could not open connection", netid);
			return (NULL);
		}
		madefd = TRUE;
	}

	memset(&sccsin, 0, sizeof sccsin);
	sccsin.sin_family = AF_INET;
	(void)bindresvport(fd, &sccsin);

	switch (nconf->nc_semantics) {
	case NC_TPI_COTS:
	case NC_TPI_COTS_ORD:
		if (listen(fd, SOMAXCONN) == -1) {
			(void) syslog(LOG_ERR,
			    "svc%s_create: listen(2) failed: %s",
			    netid, strerror(errno));
			(void) freenetconfigent(nconf);
			goto out;
		}
		break;
	default:
		break;
	}

	svc = svc_tli_create(fd, nconf, NULL, sendsize, recvsize);
	(void) freenetconfigent(nconf);
	if (svc == NULL)
		goto out;
	port = (((struct sockaddr_in *)svc->xp_ltaddr.buf)->sin_port);
	svc->xp_port = ntohs(port);
	return svc;
out:
	if (madefd)
		(void) close(fd);
	return NULL;
}
Beispiel #4
0
/*
 * Usage:
 *	xprt = svcudp_create(sock);
 *
 * If sock<0 then a socket is created, else sock is used.
 * If the socket, sock is not bound to a port then svcudp_create
 * binds it to an arbitrary port.  In any (successful) case,
 * xprt->xp_sock is the registered socket number and xprt->xp_port is the
 * associated port number.
 * Once *xprt is initialized, it is registered as a transporter;
 * see (svc.h, xprt_register).
 * The routines returns NULL if a problem occurred.
 */
SVCXPRT *
svcudp_bufcreate(
	register int sock,
	unsigned sendsz,
	unsigned recvsz)
{
	bool_t madesock = FALSE;
	register SVCXPRT *xprt;
	register struct svcudp_data *su;
	struct sockaddr_in addr;
	socklen_t len = sizeof(struct sockaddr_in);

	if (sock == RPC_ANYSOCK) {
		if ((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
			perror("svcudp_create: socket creation problem");
			return ((SVCXPRT *)NULL);
		}
		madesock = TRUE;
	}
	bzero((char *)&addr, sizeof (addr));
	addr.sin_family = AF_INET;
	if (bindresvport(sock, &addr)) {
		addr.sin_port = 0;
		(void)bind(sock, (struct sockaddr *)&addr, len);
	}
	if (getsockname(sock, (struct sockaddr *)&addr, &len) != 0) {
		perror("svcudp_create - cannot getsockname");
		if (madesock)
			(void)close(sock);
		return ((SVCXPRT *)NULL);
	}
	xprt = (SVCXPRT *)mem_alloc(sizeof(SVCXPRT));
	if (xprt == NULL) {
		(void)fprintf(stderr, "svcudp_create: out of memory\n");
		return (NULL);
	}
	su = (struct svcudp_data *)mem_alloc(sizeof(*su));
	if (su == NULL) {
		(void)fprintf(stderr, "svcudp_create: out of memory\n");
		return (NULL);
	}
	su->su_iosz = ((MAX(sendsz, recvsz) + 3) / 4) * 4;
	if ((rpc_buffer(xprt) = mem_alloc(su->su_iosz)) == NULL) {
		(void)fprintf(stderr, "svcudp_create: out of memory\n");
		return (NULL);
	}
	xdrmem_create(
	    &(su->su_xdrs), rpc_buffer(xprt), su->su_iosz, XDR_DECODE);
	su->su_cache = NULL;
	xprt->xp_p2 = (char*)su;
	xprt->xp_verf.oa_base = su->su_verfbody;
	xprt->xp_ops = &svcudp_op;
	xprt->xp_port = ntohs(addr.sin_port);
	xprt->xp_sock = sock;
	xprt_register(xprt);
	return (xprt);
}
Beispiel #5
0
struct client *udp_client(uint32_t server, uint16_t port, uint32_t flags)
{
	struct client *clnt = malloc(sizeof(*clnt));
	struct sockaddr_in addr;
	int sock;

	if (clnt == NULL) {
		perror("malloc");
		goto bail;
	}

	memset(clnt, 0, sizeof(*clnt));

	if ((sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) {
		perror("socket");
		goto bail;
	}

	if ((flags & CLI_RESVPORT) && bindresvport(sock, 0) == -1) {
		perror("bindresvport");
		goto bail;
	} else {
		struct sockaddr_in me;

		me.sin_family = AF_INET;
		me.sin_port = 0;
		me.sin_addr.s_addr = INADDR_ANY;

		if (0 && bind(sock, (struct sockaddr *)&me, sizeof(me)) == -1) {
			perror("bind");
			goto bail;
		}
	}

	clnt->sock = sock;
	clnt->call_stub = rpc_call_udp;

	addr.sin_family = AF_INET;
	addr.sin_port = htons(port);
	addr.sin_addr.s_addr = server;

	if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
		perror("connect");
		goto bail;
	}

	goto done;
      bail:
	if (clnt) {
		free(clnt);
		clnt = NULL;
	}
      done:
	return clnt;
}
Beispiel #6
0
/*
 * Usage:
 *	xprt = svctcp_create(sock, send_buf_size, recv_buf_size);
 *
 * Creates, registers, and returns a (rpc) tcp based transporter.
 * Once *xprt is initialized, it is registered as a transporter
 * see (svc.h, xprt_register).  This routine returns
 * a NULL if a problem occurred.
 *
 * If sock<0 then a socket is created, else sock is used.
 * If the socket, sock is not bound to a port then svctcp_create
 * binds it to an arbitrary port.  The routine then starts a tcp
 * listener on the socket's associated port.  In any (successful) case,
 * xprt->xp_sock is the registered socket number and xprt->xp_port is the
 * associated port number.
 *
 * Since tcp streams do buffered io similar to stdio, the caller can specify
 * how big the send and receive buffers are via the second and third parms;
 * 0 => use the system default.
 */
SVCXPRT *
svctcp_create(
	register int sock,
	unsigned sendsize,
	unsigned recvsize)
{
	bool_t madesock = FALSE;
	register SVCXPRT *xprt;
	register struct tcp_rendezvous *r;
	struct sockaddr_in addr;
	socklen_t len = (socklen_t)sizeof(struct sockaddr_in);

	if (sock == RPC_ANYSOCK) {
		if ((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
			perror("svctcp_.c - udp socket creation problem");
			return ((SVCXPRT *)NULL);
		}
		madesock = TRUE;
	}
	bzero((char *)&addr, sizeof (addr));
	addr.sin_family = AF_INET;
	if (bindresvport(sock, &addr)) {
		addr.sin_port = 0;
		(void)bind(sock, (struct sockaddr *)&addr, len);
	}
	if ((getsockname(sock, (struct sockaddr *)&addr, &len) != 0)  ||
	    (listen(sock, 2) != 0)) {
		perror("svctcp_.c - cannot getsockname or listen");
		if (madesock)
		       (void)close(sock);
		return ((SVCXPRT *)NULL);
	}
	r = (struct tcp_rendezvous *)mem_alloc(sizeof(*r));
	if (r == NULL) {
		(void) fprintf(stderr, "svctcp_create: out of memory\n");
		return (NULL);
	}
	r->sendsize = sendsize;
	r->recvsize = recvsize;
	xprt = (SVCXPRT *)mem_alloc(sizeof(SVCXPRT));
	if (xprt == NULL) {
		(void) fprintf(stderr, "svctcp_create: out of memory\n");
		return (NULL);
	}
	xprt->xp_p2 = NULL;
	xprt->xp_p1 = (char*)r;
	xprt->xp_verf = _null_auth;
	xprt->xp_ops = &svctcp_rendezvous_op;
	xprt->xp_port = ntohs(addr.sin_port);
	xprt->xp_sock = sock;
	xprt_register(xprt);
	return (xprt);
}
Beispiel #7
0
SVCXPRT *Svctcp_create(register int sock, u_int sendsize, u_int recvsize)
{
  bool_t madesock = FALSE;
  register SVCXPRT *xprt;
  register struct tcp_rendezvous *r;
  struct sockaddr_in addr;
  unsigned long len = sizeof(struct sockaddr_in);

  if(sock == RPC_ANYSOCK)
    {
      if((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
        {
          perror("svctcp_.c - udp socket creation problem");
          return ((SVCXPRT *) NULL);
        }
      madesock = TRUE;
    }
  memset(&addr, 0, sizeof(addr));
  addr.sin_family = AF_INET;
  if(bindresvport(sock, &addr))
    {
      addr.sin_port = 0;
      (void)bind(sock, (struct sockaddr *)&addr, len);
    }
  if((getsockname(sock, (struct sockaddr *)&addr, (socklen_t *) & len) != 0) ||
     (listen(sock, SOMAXCONN) != 0))
    {
      perror("svctcp_.c - cannot getsockname or listen");
      if(madesock)
        (void)close(sock);
      return ((SVCXPRT *) NULL);
    }
  r = (struct tcp_rendezvous *)Mem_Alloc(sizeof(*r));
  if(r == NULL)
    {
      return (NULL);
    }
  r->sendsize = sendsize;
  r->recvsize = recvsize;
  xprt = (SVCXPRT *) Mem_Alloc(sizeof(SVCXPRT));
  if(xprt == NULL)
    {
      return (NULL);
    }
  xprt->xp_p2 = NULL;
  xprt->xp_p1 = (caddr_t) r;
  xprt->xp_verf = _null_auth;
  xprt->xp_ops = &Svctcp_rendezvous_op;
  xprt->xp_port = ntohs(addr.sin_port);
  xprt->XP_SOCK = sock;
  Xprt_register(xprt);
  return (xprt);
}
/*
 * A common server create routine
 */
static SVCXPRT *
svc_com_create(int fd, u_int sendsize, u_int recvsize, char *netid)
{
	struct netconfig *nconf;
	SVCXPRT *svc;
	int madefd = FALSE;
	int port;
	struct sockaddr_in sin;

	if ((nconf = __rpc_getconfip(netid)) == NULL) {
		(void) syslog(LOG_ERR, "Could not get %s transport", netid);
		return (NULL);
	}
	if (fd == RPC_ANYSOCK) {
		fd = __rpc_nconf2fd(nconf);
		if (fd == -1) {
			(void) freenetconfigent(nconf);
			(void) syslog(LOG_ERR,
			"svc%s_create: could not open connection", netid);
			return (NULL);
		}
		madefd = TRUE;
	}

	memset(&sin, 0, sizeof sin);
	sin.sin_family = AF_INET;
	bindresvport(fd, &sin);
	_listen(fd, SOMAXCONN);
	svc = svc_tli_create(fd, nconf, NULL, sendsize, recvsize);
	(void) freenetconfigent(nconf);
	if (svc == NULL) {
		if (madefd)
			(void)_close(fd);
		return (NULL);
	}
	port = (((struct sockaddr_in *)svc->xp_ltaddr.buf)->sin_port);
	svc->xp_port = ntohs(port);
	return (svc);
}
Beispiel #9
0
/*
 * Initialize socket used to notify lockd of peer reboots.
 *
 * Returns the file descriptor of the new socket if successful;
 * otherwise returns -1 and logs an error.
 *
 * Lockd rejects such requests if the source port is not privileged.
 * statd_get_socket() must be invoked while statd still holds root
 * privileges in order for the socket to acquire a privileged source
 * port.
 */
int
statd_get_socket(void)
{
	struct sockaddr_in	sin;
	struct servent *se;
	int loopcnt = 100;

	if (sockfd >= 0)
		return sockfd;

	while (loopcnt-- > 0) {

		if (sockfd >= 0) close(sockfd);

		if ((sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
			xlog(L_ERROR, "%s: Can't create socket: %m", __func__);
			return -1;
		}


		memset(&sin, 0, sizeof(sin));
		sin.sin_family = AF_INET;
		sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);

		if (bindresvport(sockfd, &sin) < 0) {
			xlog(D_GENERAL, "%s: can't bind to reserved port",
					__func__);
			break;
		}
		se = getservbyport(sin.sin_port, "udp");
		if (se == NULL)
			break;
		/* rather not use that port, try again */
	}
	FD_SET(sockfd, &SVC_FDSET);
	return sockfd;
}
Beispiel #10
0
static
struct conn_t *conn_new(struct sockaddr_in *raddr, struct sockaddr_in *laddr) {
    struct conn_t *c;
    int lsize, errnosave;
    struct sockaddr_in tmp;

    c = smalloc(sizeof(*c));
    memset(c, 0, sizeof(*c));
    c->state = CONN_NEW;
    INIT_LIST_HEAD(&c->reqs);

    if ((c->fd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
	errnosave = errno;
	syslog(LOG_ERR, "socket: %s", strerror(errno));
	free(c);
	errno = errnosave;
	return 0;
    }

    /* If this is not the first connection, do a non-blocking connect */
    if (!list_empty(&clist))
	set_non_block(c->fd);

    tmp = *laddr;		/* use a temp here because
				 * bindresvport writes it. */
    if (laddr->sin_port ||
	bindresvport(c->fd, &tmp) == -1) {
	    syslog(LOG_ERR, "bindresvport: %s (ignoring)", strerror(errno));
	    /* If we specified a port or failed to bind to a reserved
	     * port for some reason, try a normal bind. */
	    if (bind(c->fd, (struct sockaddr *) laddr, sizeof(*laddr)) == -1) {
		errnosave = errno;
		syslog(LOG_ERR, "bind(%s:%d): %s (ignoring)",
		       inet_ntoa(laddr->sin_addr), ntohs(laddr->sin_port),
		       strerror(errno));
		close(c->fd);
		free(c);
		errno = errnosave;
		return 0;
	    }
    }

    if (verbose)
	syslog(LOG_INFO, "Connecting to %s:%d...",
	       inet_ntoa(raddr->sin_addr), ntohs(raddr->sin_port));

    if (connect(c->fd, (struct sockaddr *) raddr, sizeof(*raddr)) == -1) {
	if (errno != EINPROGRESS) {
	    errnosave = errno;
	    syslog(LOG_ERR, "connect(%s:%d): %s",
		   inet_ntoa(raddr->sin_addr), ntohs(raddr->sin_port),
		   strerror(errno));
	    close(c->fd);
	    free(c);
	    errno = errnosave;
	    return 0;
	}
    }

    /* Make note of our local address */
    lsize = sizeof(c->laddr);
    getsockname(c->fd, (struct sockaddr *)&c->laddr, &lsize);
    c->raddr = *raddr;

    /* Prime output buffer with version information and cookie */
    conn_send_version(c);

    set_keep_alive(c->fd);
    set_no_delay(c->fd);
    set_non_block(c->fd);

    /* Append to list of connections */
    list_add_tail(&c->list, &clist);
    return c;
}
Beispiel #11
0
// NB: mp->xxx fields may be trashed on exit
static int nfsmount(struct mntent *mp, int vfsflags, char *filteropts)
{
	CLIENT *mclient;
	char *hostname;
	char *pathname;
	char *mounthost;
	struct nfs_mount_data data;
	char *opt;
	struct hostent *hp;
	struct sockaddr_in server_addr;
	struct sockaddr_in mount_server_addr;
	int msock, fsock;
	union {
		struct fhstatus nfsv2;
		struct mountres3 nfsv3;
	} status;
	int daemonized;
	char *s;
	int port;
	int mountport;
	int proto;
	int bg;
	int soft;
	int intr;
	int posix;
	int nocto;
	int noac;
	int nolock;
	int retry;
	int tcp;
	int mountprog;
	int mountvers;
	int nfsprog;
	int nfsvers;
	int retval;

	find_kernel_nfs_mount_version();

	daemonized = 0;
	mounthost = NULL;
	retval = ETIMEDOUT;
	msock = fsock = -1;
	mclient = NULL;

	/* NB: hostname, mounthost, filteropts must be free()d prior to return */

	filteropts = xstrdup(filteropts); /* going to trash it later... */

	hostname = xstrdup(mp->mnt_fsname);
	/* mount_main() guarantees that ':' is there */
	s = strchr(hostname, ':');
	pathname = s + 1;
	*s = '\0';
	/* Ignore all but first hostname in replicated mounts
	   until they can be fully supported. ([email protected]) */
	s = strchr(hostname, ',');
	if (s) {
		*s = '\0';
		bb_error_msg("warning: multiple hostnames not supported");
	}

	server_addr.sin_family = AF_INET;
	if (!inet_aton(hostname, &server_addr.sin_addr)) {
		hp = gethostbyname(hostname);
		if (hp == NULL) {
			bb_herror_msg("%s", hostname);
			goto fail;
		}
		if (hp->h_length > sizeof(struct in_addr)) {
			bb_error_msg("got bad hp->h_length");
			hp->h_length = sizeof(struct in_addr);
		}
		memcpy(&server_addr.sin_addr,
				hp->h_addr, hp->h_length);
	}

	memcpy(&mount_server_addr, &server_addr, sizeof(mount_server_addr));

	/* add IP address to mtab options for use when unmounting */

	if (!mp->mnt_opts) { /* TODO: actually mp->mnt_opts is never NULL */
		mp->mnt_opts = xasprintf("addr=%s", inet_ntoa(server_addr.sin_addr));
	} else {
		char *tmp = xasprintf("%s%saddr=%s", mp->mnt_opts,
					mp->mnt_opts[0] ? "," : "",
					inet_ntoa(server_addr.sin_addr));
		free(mp->mnt_opts);
		mp->mnt_opts = tmp;
	}

	/* Set default options.
	 * rsize/wsize (and bsize, for ver >= 3) are left 0 in order to
	 * let the kernel decide.
	 * timeo is filled in after we know whether it'll be TCP or UDP. */
	memset(&data, 0, sizeof(data));
	data.retrans	= 3;
	data.acregmin	= 3;
	data.acregmax	= 60;
	data.acdirmin	= 30;
	data.acdirmax	= 60;
	data.namlen	= NAME_MAX;

	bg = 0;
	soft = 0;
	intr = 0;
	posix = 0;
	nocto = 0;
	nolock = 0;
	noac = 0;
	retry = 10000;		/* 10000 minutes ~ 1 week */
	tcp = 0;

	mountprog = MOUNTPROG;
	mountvers = 0;
	port = 0;
	mountport = 0;
	nfsprog = 100003;
	nfsvers = 0;

	/* parse options */
	if (filteropts)	for (opt = strtok(filteropts, ","); opt; opt = strtok(NULL, ",")) {
		char *opteq = strchr(opt, '=');
		if (opteq) {
			static const char *const options[] = {
				/* 0 */ "rsize",
				/* 1 */ "wsize",
				/* 2 */ "timeo",
				/* 3 */ "retrans",
				/* 4 */ "acregmin",
				/* 5 */ "acregmax",
				/* 6 */ "acdirmin",
				/* 7 */ "acdirmax",
				/* 8 */ "actimeo",
				/* 9 */ "retry",
				/* 10 */ "port",
				/* 11 */ "mountport",
				/* 12 */ "mounthost",
				/* 13 */ "mountprog",
				/* 14 */ "mountvers",
				/* 15 */ "nfsprog",
				/* 16 */ "nfsvers",
				/* 17 */ "vers",
				/* 18 */ "proto",
				/* 19 */ "namlen",
				/* 20 */ "addr",
				NULL
			};
			int val = xatoi_u(opteq + 1);
			*opteq = '\0';
			switch (index_in_str_array(options, opt)) {
			case 0: // "rsize"
				data.rsize = val;
				break;
			case 1: // "wsize"
				data.wsize = val;
				break;
			case 2: // "timeo"
				data.timeo = val;
				break;
			case 3: // "retrans"
				data.retrans = val;
				break;
			case 4: // "acregmin"
				data.acregmin = val;
				break;
			case 5: // "acregmax"
				data.acregmax = val;
				break;
			case 6: // "acdirmin"
				data.acdirmin = val;
				break;
			case 7: // "acdirmax"
				data.acdirmax = val;
				break;
			case 8: // "actimeo"
				data.acregmin = val;
				data.acregmax = val;
				data.acdirmin = val;
				data.acdirmax = val;
				break;
			case 9: // "retry"
				retry = val;
				break;
			case 10: // "port"
				port = val;
				break;
			case 11: // "mountport"
				mountport = val;
				break;
			case 12: // "mounthost"
				mounthost = xstrndup(opteq+1,
						strcspn(opteq+1," \t\n\r,"));
				break;
			case 13: // "mountprog"
				mountprog = val;
				break;
			case 14: // "mountvers"
				mountvers = val;
				break;
			case 15: // "nfsprog"
				nfsprog = val;
				break;
			case 16: // "nfsvers"
			case 17: // "vers"
				nfsvers = val;
				break;
			case 18: // "proto"
				if (!strncmp(opteq+1, "tcp", 3))
					tcp = 1;
				else if (!strncmp(opteq+1, "udp", 3))
					tcp = 0;
				else
					bb_error_msg("warning: unrecognized proto= option");
				break;
			case 19: // "namlen"
				if (nfs_mount_version >= 2)
					data.namlen = val;
				else
					bb_error_msg("warning: option namlen is not supported\n");
				break;
			case 20: // "addr" - ignore
				break;
			default:
				bb_error_msg("unknown nfs mount parameter: %s=%d", opt, val);
				goto fail;
			}
		}
		else {
			static const char *const options[] = {
				"bg",
				"fg",
				"soft",
				"hard",
				"intr",
				"posix",
				"cto",
				"ac",
				"tcp",
				"udp",
				"lock",
				NULL
			};
			int val = 1;
			if (!strncmp(opt, "no", 2)) {
				val = 0;
				opt += 2;
			}
			switch (index_in_str_array(options, opt)) {
			case 0: // "bg"
				bg = val;
				break;
			case 1: // "fg"
				bg = !val;
				break;
			case 2: // "soft"
				soft = val;
				break;
			case 3: // "hard"
				soft = !val;
				break;
			case 4: // "intr"
				intr = val;
				break;
			case 5: // "posix"
				posix = val;
				break;
			case 6: // "cto"
				nocto = !val;
				break;
			case 7: // "ac"
				noac = !val;
				break;
			case 8: // "tcp"
				tcp = val;
				break;
			case 9: // "udp"
				tcp = !val;
				break;
			case 10: // "lock"
				if (nfs_mount_version >= 3)
					nolock = !val;
				else
					bb_error_msg("warning: option nolock is not supported");
				break;
			default:
				bb_error_msg("unknown nfs mount option: %s%s", val ? "" : "no", opt);
				goto fail;
			}
		}
	}
	proto = (tcp) ? IPPROTO_TCP : IPPROTO_UDP;

	data.flags = (soft ? NFS_MOUNT_SOFT : 0)
		| (intr ? NFS_MOUNT_INTR : 0)
		| (posix ? NFS_MOUNT_POSIX : 0)
		| (nocto ? NFS_MOUNT_NOCTO : 0)
		| (noac ? NFS_MOUNT_NOAC : 0);
	if (nfs_mount_version >= 2)
		data.flags |= (tcp ? NFS_MOUNT_TCP : 0);
	if (nfs_mount_version >= 3)
		data.flags |= (nolock ? NFS_MOUNT_NONLM : 0);
	if (nfsvers > MAX_NFSPROT || mountvers > MAX_NFSPROT) {
		bb_error_msg("NFSv%d not supported", nfsvers);
		goto fail;
	}
	if (nfsvers && !mountvers)
		mountvers = (nfsvers < 3) ? 1 : nfsvers;
	if (nfsvers && nfsvers < mountvers) {
		mountvers = nfsvers;
	}

	/* Adjust options if none specified */
	if (!data.timeo)
		data.timeo = tcp ? 70 : 7;

	data.version = nfs_mount_version;

	if (vfsflags & MS_REMOUNT)
		goto do_mount;

	/*
	 * If the previous mount operation on the same host was
	 * backgrounded, and the "bg" for this mount is also set,
	 * give up immediately, to avoid the initial timeout.
	 */
	if (bg && we_saw_this_host_before(hostname)) {
		daemonized = daemonize(); /* parent or error */
		if (daemonized <= 0) { /* parent or error */
			retval = -daemonized;
			goto ret;
		}
	}

	/* create mount daemon client */
	/* See if the nfs host = mount host. */
	if (mounthost) {
		if (mounthost[0] >= '0' && mounthost[0] <= '9') {
			mount_server_addr.sin_family = AF_INET;
			mount_server_addr.sin_addr.s_addr = inet_addr(hostname);
		} else {
			hp = gethostbyname(mounthost);
			if (hp == NULL) {
				bb_herror_msg("%s", mounthost);
				goto fail;
			} else {
				if (hp->h_length > sizeof(struct in_addr)) {
					bb_error_msg("got bad hp->h_length?");
					hp->h_length = sizeof(struct in_addr);
				}
				mount_server_addr.sin_family = AF_INET;
				memcpy(&mount_server_addr.sin_addr,
						hp->h_addr, hp->h_length);
			}
		}
	}

	/*
	 * The following loop implements the mount retries. When the mount
	 * times out, and the "bg" option is set, we background ourself
	 * and continue trying.
	 *
	 * The case where the mount point is not present and the "bg"
	 * option is set, is treated as a timeout. This is done to
	 * support nested mounts.
	 *
	 * The "retry" count specified by the user is the number of
	 * minutes to retry before giving up.
	 */
	{
		struct timeval total_timeout;
		struct timeval retry_timeout;
		struct pmap* pm_mnt;
		time_t t;
		time_t prevt;
		time_t timeout;

		retry_timeout.tv_sec = 3;
		retry_timeout.tv_usec = 0;
		total_timeout.tv_sec = 20;
		total_timeout.tv_usec = 0;
		timeout = time(NULL) + 60 * retry;
		prevt = 0;
		t = 30;
retry:
		/* be careful not to use too many CPU cycles */
		if (t - prevt < 30)
			sleep(30);

		pm_mnt = get_mountport(&mount_server_addr,
				mountprog,
				mountvers,
				proto,
				mountport);
		nfsvers = (pm_mnt->pm_vers < 2) ? 2 : pm_mnt->pm_vers;

		/* contact the mount daemon via TCP */
		mount_server_addr.sin_port = htons(pm_mnt->pm_port);
		msock = RPC_ANYSOCK;

		switch (pm_mnt->pm_prot) {
		case IPPROTO_UDP:
			mclient = clntudp_create(&mount_server_addr,
						 pm_mnt->pm_prog,
						 pm_mnt->pm_vers,
						 retry_timeout,
						 &msock);
			if (mclient)
				break;
			mount_server_addr.sin_port = htons(pm_mnt->pm_port);
			msock = RPC_ANYSOCK;
		case IPPROTO_TCP:
			mclient = clnttcp_create(&mount_server_addr,
						 pm_mnt->pm_prog,
						 pm_mnt->pm_vers,
						 &msock, 0, 0);
			break;
		default:
			mclient = 0;
		}
		if (!mclient) {
			if (!daemonized && prevt == 0)
				error_msg_rpc(clnt_spcreateerror(" "));
		} else {
			enum clnt_stat clnt_stat;
			/* try to mount hostname:pathname */
			mclient->cl_auth = authunix_create_default();

			/* make pointers in xdr_mountres3 NULL so
			 * that xdr_array allocates memory for us
			 */
			memset(&status, 0, sizeof(status));

			if (pm_mnt->pm_vers == 3)
				clnt_stat = clnt_call(mclient, MOUNTPROC3_MNT,
					      (xdrproc_t) xdr_dirpath,
					      (caddr_t) &pathname,
					      (xdrproc_t) xdr_mountres3,
					      (caddr_t) &status,
					      total_timeout);
			else
				clnt_stat = clnt_call(mclient, MOUNTPROC_MNT,
					      (xdrproc_t) xdr_dirpath,
					      (caddr_t) &pathname,
					      (xdrproc_t) xdr_fhstatus,
					      (caddr_t) &status,
					      total_timeout);

			if (clnt_stat == RPC_SUCCESS)
				goto prepare_kernel_data; /* we're done */
			if (errno != ECONNREFUSED) {
				error_msg_rpc(clnt_sperror(mclient, " "));
				goto fail;	/* don't retry */
			}
			/* Connection refused */
			if (!daemonized && prevt == 0) /* print just once */
				error_msg_rpc(clnt_sperror(mclient, " "));
			auth_destroy(mclient->cl_auth);
			clnt_destroy(mclient);
			mclient = 0;
			close(msock);
		}

		/* Timeout. We are going to retry... maybe */

		if (!bg)
			goto fail;
		if (!daemonized) {
			daemonized = daemonize();
			if (daemonized <= 0) { /* parent or error */
				retval = -daemonized;
				goto ret;
			}
		}
		prevt = t;
		t = time(NULL);
		if (t >= timeout)
			/* TODO error message */
			goto fail;

		goto retry;
	}

prepare_kernel_data:

	if (nfsvers == 2) {
		if (status.nfsv2.fhs_status != 0) {
			bb_error_msg("%s:%s failed, reason given by server: %s",
				hostname, pathname,
				nfs_strerror(status.nfsv2.fhs_status));
			goto fail;
		}
		memcpy(data.root.data,
				(char *) status.nfsv2.fhstatus_u.fhs_fhandle,
				NFS_FHSIZE);
		data.root.size = NFS_FHSIZE;
		memcpy(data.old_root.data,
				(char *) status.nfsv2.fhstatus_u.fhs_fhandle,
				NFS_FHSIZE);
	} else {
		fhandle3 *my_fhandle;
		if (status.nfsv3.fhs_status != 0) {
			bb_error_msg("%s:%s failed, reason given by server: %s",
				hostname, pathname,
				nfs_strerror(status.nfsv3.fhs_status));
			goto fail;
		}
		my_fhandle = &status.nfsv3.mountres3_u.mountinfo.fhandle;
		memset(data.old_root.data, 0, NFS_FHSIZE);
		memset(&data.root, 0, sizeof(data.root));
		data.root.size = my_fhandle->fhandle3_len;
		memcpy(data.root.data,
				(char *) my_fhandle->fhandle3_val,
				my_fhandle->fhandle3_len);

		data.flags |= NFS_MOUNT_VER3;
	}

	/* create nfs socket for kernel */

	if (tcp) {
		if (nfs_mount_version < 3) {
			bb_error_msg("NFS over TCP is not supported");
			goto fail;
		}
		fsock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	} else
		fsock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
	if (fsock < 0) {
		bb_perror_msg("nfs socket");
		goto fail;
	}
	if (bindresvport(fsock, 0) < 0) {
		bb_perror_msg("nfs bindresvport");
		goto fail;
	}
	if (port == 0) {
		server_addr.sin_port = PMAPPORT;
		port = pmap_getport(&server_addr, nfsprog, nfsvers,
					tcp ? IPPROTO_TCP : IPPROTO_UDP);
		if (port == 0)
			port = NFS_PORT;
	}
	server_addr.sin_port = htons(port);

	/* prepare data structure for kernel */

	data.fd = fsock;
	memcpy((char *) &data.addr, (char *) &server_addr, sizeof(data.addr));
	strncpy(data.hostname, hostname, sizeof(data.hostname));

	/* clean up */

	auth_destroy(mclient->cl_auth);
	clnt_destroy(mclient);
	close(msock);

	if (bg) {
		/* We must wait until mount directory is available */
		struct stat statbuf;
		int delay = 1;
		while (stat(mp->mnt_dir, &statbuf) == -1) {
			if (!daemonized) {
				daemonized = daemonize();
				if (daemonized <= 0) { /* parent or error */
					retval = -daemonized;
					goto ret;
				}
			}
			sleep(delay);	/* 1, 2, 4, 8, 16, 30, ... */
			delay *= 2;
			if (delay > 30)
				delay = 30;
		}
	}

do_mount: /* perform actual mount */

	mp->mnt_type = (char*)"nfs";
	retval = mount_it_now(mp, vfsflags, (char*)&data);
	goto ret;

fail:	/* abort */

	if (msock != -1) {
		if (mclient) {
			auth_destroy(mclient->cl_auth);
			clnt_destroy(mclient);
		}
		close(msock);
	}
	if (fsock != -1)
		close(fsock);

ret:
	free(hostname);
	free(mounthost);
	free(filteropts);
	return retval;
}
Beispiel #12
0
/*
 * Generic client creation:  returns client handle.
 * Default options are set, which the user can
 * change using the rpc equivalent of _ioctl()'s : clnt_control().
 * If fd is RPC_ANYFD, it will be opened using nconf.
 * It will be bound if not so.
 * If sizes are 0; appropriate defaults will be chosen.
 */
CLIENT *
clnt_tli_create(int fd, const struct netconfig *nconf,
	struct netbuf *svcaddr, rpcprog_t prog, rpcvers_t vers,
	uint sendsz, uint recvsz)
{
	CLIENT *cl;			/* client handle */
	bool_t madefd = FALSE;		/* whether fd opened here */
	long servtype;
	int one = 1;
	struct __rpc_sockinfo si;
	extern int __rpc_minfd;

	if (fd == RPC_ANYFD) {
		if (nconf == NULL) {
			rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
			return (NULL);
		}

		fd = __rpc_nconf2fd(nconf);

		if (fd == -1)
			goto err;
		if (fd < __rpc_minfd)
			fd = __rpc_raise_fd(fd);
		madefd = TRUE;
		servtype = nconf->nc_semantics;
		if (!__rpc_fd2sockinfo(fd, &si))
			goto err;
		bindresvport(fd, NULL);
	} else {
		if (!__rpc_fd2sockinfo(fd, &si))
			goto err;
		servtype = __rpc_socktype2seman(si.si_socktype);
		if (servtype == -1) {
			rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
			return (NULL);
		}
	}

	if (si.si_af != ((struct sockaddr *)svcaddr->buf)->sa_family) {
		rpc_createerr.cf_stat = RPC_UNKNOWNHOST;	/* XXX */
		goto err1;
	}

	switch (servtype) {
	case NC_TPI_COTS:
		cl = clnt_vc_create(fd, svcaddr, prog, vers, sendsz, recvsz);
		break;
	case NC_TPI_COTS_ORD:
		if (nconf &&
		    ((strcmp(nconf->nc_protofmly, "inet") == 0) ||
		     (strcmp(nconf->nc_protofmly, "inet6") == 0))) {
			setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &one,
			    sizeof (one));
		}
		cl = clnt_vc_create(fd, svcaddr, prog, vers, sendsz, recvsz);
		break;
	case NC_TPI_CLTS:
		cl = clnt_dg_create(fd, svcaddr, prog, vers, sendsz, recvsz);
		break;
	default:
		goto err;
	}

	if (cl == NULL)
		goto err1; /* borrow errors from clnt_dg/vc creates */
	if (nconf) {
		cl->cl_netid = strdup(nconf->nc_netid);
		cl->cl_tp = strdup(nconf->nc_device);
	} else {
		cl->cl_netid = "";
		cl->cl_tp = "";
	}
	if (madefd) {
		(void) CLNT_CONTROL(cl, CLSET_FD_CLOSE, NULL);
/*		(void) CLNT_CONTROL(cl, CLSET_POP_TIMOD, NULL);  */
	};

	return (cl);

err:
	rpc_createerr.cf_stat = RPC_SYSTEMERROR;
	rpc_createerr.cf_error.re_errno = errno;
err1:	if (madefd)
		(void)close(fd);
	return (NULL);
}
Beispiel #13
0
int
main(int argc, char **argv)
{
	int			sock, ch, rc, retval = EXIT_FAILURE;
	int			port = SERVERPORT;
	char		       *server = BOSSNODE;
	struct sockaddr_in	sin;
	whoami_t		whoami;

	while ((ch = getopt(argc, argv, "ds:p:")) != -1)
		switch(ch) {
		case 's':
			server = optarg;
			break;
		case 'p':
			port = atoi(optarg);
			break;
		case 'd':
			debug++;
			break;
		case 'h':
		case '?':
		default:
			usage();
		}
	argc -= optind;
	argv += optind;

	if (argc != 1)
		usage();
	
	if (strlen(argv[0]) >= sizeof(whoami.name))
		fprintf(stderr, "Name too long: %s\n", argv[0]);
	
	if (getuid() != 0)
		fprintf(stderr, "Must be run as root\n");

	memset(&whoami, 0, sizeof(whoami));
	strcpy(whoami.name, argv[0]);
	whoami.portnum = -1;
	
	if (!mygethostbyname(&sin, server, port))
		fprintf(stderr, "Bad server name: %s\n", server);

	if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
		perror("socket");
	else if (bindresvport(sock, NULL) < 0)
		perror("bindresvport");
	else if (connect(sock, (struct sockaddr *)&sin, sizeof(sin)) < 0)
		perror("connect");
	else if (write(sock, &whoami, sizeof(whoami)) != sizeof(whoami))
		perror("write");
	else if ((rc = read(sock, &port, sizeof(port))) != sizeof(port))
		perror("read");
	else {
		printf("%d\n", port);
		retval = EXIT_SUCCESS;
	}

	close(sock);

	return retval;
}
Beispiel #14
0
/*
 * Set the date in the machines controlled by timedaemons by communicating the
 * new date to the local timedaemon.  If the timedaemon is in the master state,
 * it performs the correction on all slaves.  If it is in the slave state, it
 * notifies the master that a correction is needed.
 * Returns 0 on success.  Returns > 0 on failure, setting retval to 2;
 */
int
netsettime(time_t tval)
{
    struct timeval tout;
    struct servent *sp;
    struct tsp msg;
    struct sockaddr_in sin, dest, from;
    int fdsn;
    fd_set *fdsp = NULL;
    long waittime;
    int s, timed_ack, found, error;
    socklen_t length;
    char hostname[MAXHOSTNAMELEN];

    if ((sp = getservbyname("timed", "udp")) == NULL) {
        warnx("udp/timed: unknown service");
        return (retval = 2);
    }

    memset(&dest, 0, sizeof(dest));
    dest.sin_len = sizeof(struct sockaddr_in);
    dest.sin_family = AF_INET;
    dest.sin_port = sp->s_port;
    dest.sin_addr.s_addr = htonl(INADDR_ANY);
    s = socket(AF_INET, SOCK_DGRAM, 0);
    if (s < 0) {
        if (errno != EPROTONOSUPPORT)
            warn("timed");
        return (retval = 2);
    }

    memset(&sin, 0, sizeof(sin));
    sin.sin_len = sizeof(struct sockaddr_in);
    sin.sin_family = AF_INET;
    if (bindresvport(s, &sin) < 0) {
        warnx("all ports in use");
        goto bad;
    }
    msg.tsp_type = TSP_SETDATE;
    msg.tsp_vers = TSPVERSION;
    if (gethostname(hostname, sizeof(hostname))) {
        warn("gethostname");
        goto bad;
    }
    (void)strlcpy(msg.tsp_name, hostname, sizeof(msg.tsp_name));
    msg.tsp_seq = htons((u_short)0);
    msg.tsp_time.tv_sec = htonl((u_long)tval);
    msg.tsp_time.tv_usec = htonl((u_long)0);
    length = sizeof(struct sockaddr_in);
    if (connect(s, (struct sockaddr *)&dest, length) < 0) {
        warn("connect");
        goto bad;
    }
    if (send(s, &msg, sizeof(struct tsp), 0) < 0) {
        if (errno != ECONNREFUSED)
            warn("send");
        goto bad;
    }

    timed_ack = -1;
    waittime = WAITACK;

    fdsn = howmany(s+1, NFDBITS) * sizeof(fd_mask);
    if ((fdsp = malloc(fdsn)) == NULL)
        err(1, "malloc");
loop:
    tout.tv_sec = waittime;
    tout.tv_usec = 0;

    memset(fdsp, 0, fdsn);
    FD_SET(s, fdsp);
    found = select(s+1, fdsp, NULL, NULL, &tout);

    length = sizeof(error);
    if (!getsockopt(s,
                    SOL_SOCKET, SO_ERROR, &error, &length) && error) {
        if (error != ECONNREFUSED)
            warn("send (delayed error)");
        goto bad;
    }

    if (found > 0 && FD_ISSET(s, fdsp)) {
        length = sizeof(struct sockaddr_in);
        if (recvfrom(s, &msg, sizeof(struct tsp), 0,
                     (struct sockaddr *)&from, &length) < 0) {
            if (errno != ECONNREFUSED)
                warn("recvfrom");
            goto bad;
        }
        msg.tsp_seq = ntohs(msg.tsp_seq);
        msg.tsp_time.tv_sec = ntohl(msg.tsp_time.tv_sec);
        msg.tsp_time.tv_usec = ntohl(msg.tsp_time.tv_usec);
        switch (msg.tsp_type) {
        case TSP_ACK:
            timed_ack = TSP_ACK;
            waittime = WAITDATEACK;
            goto loop;
        case TSP_DATEACK:
            (void)close(s);
            free(fdsp);
            return (0);
        default:
            warnx("wrong ack received from timed: %s",
                  tsptype[msg.tsp_type]);
            timed_ack = -1;
            break;
        }
    }
    if (timed_ack == -1)
        warnx("can't reach time daemon, time set locally");

bad:
    if (fdsp)
        free(fdsp);
    (void)close(s);
    return (retval = 2);
}
Beispiel #15
0
/*
 * Create a client handle for a tcp/ip connection.
 * If *sockp<0, *sockp is set to a newly created TCP socket and it is
 * connected to raddr.  If *sockp non-negative then
 * raddr is ignored.  The rpc/tcp package does buffering
 * similar to stdio, so the client must pick send and receive buffer sizes,];
 * 0 => use the default.
 * If raddr->sin_port is 0, then a binder on the remote machine is
 * consulted for the right port number.
 * NB: *sockp is copied into a private area.
 * NB: It is the client's responsibility to close *sockp, unless
 *     clnttcp_create() was called with *sockp = -1 (so it created
 *     the socket), and CLNT_DESTROY() is used.
 * NB: The rpch->cl_auth is set null authentication.  Caller may wish to set this
 * something more useful.
 */
CLIENT *
clnttcp_create(struct sockaddr_in *raddr, u_long prog, u_long vers, int *sockp,
    u_int sendsz, u_int recvsz)
{
	CLIENT *h;
	struct ct_data *ct = NULL;
	struct timeval now;
	struct rpc_msg call_msg;

	h  = (CLIENT *)mem_alloc(sizeof(*h));
	if (h == NULL) {
		rpc_createerr.cf_stat = RPC_SYSTEMERROR;
		rpc_createerr.cf_error.re_errno = errno;
		goto fooy;
	}
	ct = (struct ct_data *)mem_alloc(sizeof(*ct));
	if (ct == NULL) {
		rpc_createerr.cf_stat = RPC_SYSTEMERROR;
		rpc_createerr.cf_error.re_errno = errno;
		goto fooy;
	}

	/*
	 * If no port number given ask the pmap for one
	 */
	if (raddr->sin_port == 0) {
		u_short port;
		if ((port = pmap_getport(raddr, prog, vers, IPPROTO_TCP)) == 0) {
			mem_free((caddr_t)ct, sizeof(struct ct_data));
			mem_free((caddr_t)h, sizeof(CLIENT));
			return (NULL);
		}
		raddr->sin_port = htons(port);
	}

	/*
	 * If no socket given, open one
	 */
	if (*sockp < 0) {
		*sockp = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
		(void)bindresvport(*sockp, NULL);
		if ((*sockp < 0)
		    || (connect(*sockp, (struct sockaddr *)raddr,
		    sizeof(*raddr)) < 0)) {
			rpc_createerr.cf_stat = RPC_SYSTEMERROR;
			rpc_createerr.cf_error.re_errno = errno;
			if (*sockp != -1)
				(void)close(*sockp);
			goto fooy;
		}
		ct->ct_closeit = TRUE;
	} else {
		ct->ct_closeit = FALSE;
	}

	/*
	 * Set up private data struct
	 */
	ct->ct_sock = *sockp;
	ct->ct_wait.tv_usec = 0;
	ct->ct_waitset = FALSE;
	ct->ct_addr = *raddr;

	/*
	 * Initialize call message
	 */
	(void)gettimeofday(&now, NULL);
	call_msg.rm_xid = arc4random();
	call_msg.rm_direction = CALL;
	call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION;
	call_msg.rm_call.cb_prog = prog;
	call_msg.rm_call.cb_vers = vers;

	/*
	 * pre-serialize the static part of the call msg and stash it away
	 */
	xdrmem_create(&(ct->ct_xdrs), ct->ct_mcall, MCALL_MSG_SIZE,
	    XDR_ENCODE);
	if (! xdr_callhdr(&(ct->ct_xdrs), &call_msg)) {
		if (ct->ct_closeit) {
			(void)close(*sockp);
		}
		goto fooy;
	}
	ct->ct_mpos = XDR_GETPOS(&(ct->ct_xdrs));
	XDR_DESTROY(&(ct->ct_xdrs));

	/*
	 * Create a client handle which uses xdrrec for serialization
	 * and authnone for authentication.
	 */
	xdrrec_create(&(ct->ct_xdrs), sendsz, recvsz,
	    (caddr_t)ct, (int(*)(caddr_t, caddr_t, int))readtcp,
	    (int(*)(caddr_t, caddr_t, int))writetcp);
	h->cl_ops = &tcp_ops;
	h->cl_private = (caddr_t) ct;
	h->cl_auth = authnone_create();
	if (h->cl_auth == NULL) {
		rpc_createerr.cf_stat = RPC_SYSTEMERROR;
		rpc_createerr.cf_error.re_errno = errno;
		goto fooy;
	}
	return (h);

fooy:
	/*
	 * Something goofed, free stuff and barf
	 */
	if (ct)
		mem_free((caddr_t)ct, sizeof(struct ct_data));
	if (h)
		mem_free((caddr_t)h, sizeof(CLIENT));
	return (NULL);
}
Beispiel #16
0
CLIENT *
clnttcp_create (struct sockaddr_in *raddr, u_long prog, u_long vers,
		int *sockp, u_int sendsz, u_int recvsz)
{
  CLIENT *h;
  struct ct_data *ct;
  struct rpc_msg call_msg;

  h = (CLIENT *) mem_alloc (sizeof (*h));
  ct = (struct ct_data *) mem_alloc (sizeof (*ct));
  if (h == NULL || ct == NULL)
    {
      struct rpc_createerr *ce = &get_rpc_createerr ();
#ifdef USE_IN_LIBIO
      if (_IO_fwide (stderr, 0) > 0)
	(void) fwprintf (stderr, L"%s",
			   _("clnttcp_create: out of memory\n"));
      else
#endif
	(void) fputs (_("clnttcp_create: out of memory\n"), stderr);
      ce->cf_stat = RPC_SYSTEMERROR;
      ce->cf_error.re_errno = ENOMEM;
      goto fooy;
    }

  /*
   * If no port number given ask the pmap for one
   */
  if (raddr->sin_port == 0)
    {
      u_short port;
      if ((port = pmap_getport (raddr, prog, vers, IPPROTO_TCP)) == 0)
	{
	  mem_free ((caddr_t) ct, sizeof (struct ct_data));
	  mem_free ((caddr_t) h, sizeof (CLIENT));
	  return ((CLIENT *) NULL);
	}
      raddr->sin_port = htons (port);
    }

  /*
   * If no socket given, open one
   */
  if (*sockp < 0)
    {
      *sockp = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
      (void) bindresvport (*sockp, (struct sockaddr_in *) 0);
      if ((*sockp < 0)
	  || (connect (*sockp, (struct sockaddr *) raddr,
			 sizeof (*raddr)) < 0))
	{
	  struct rpc_createerr *ce = &get_rpc_createerr ();
	  ce->cf_stat = RPC_SYSTEMERROR;
	  ce->cf_error.re_errno = errno;
	  if (*sockp >= 0)
	    (void) close (*sockp);
	  goto fooy;
	}
      ct->ct_closeit = TRUE;
    }
  else
    {
      ct->ct_closeit = FALSE;
    }

  /*
   * Set up private data struct
   */
  ct->ct_sock = *sockp;
  ct->ct_wait.tv_usec = 0;
  ct->ct_waitset = FALSE;
  ct->ct_addr = *raddr;

  /*
   * Initialize call message
   */
  call_msg.rm_xid = _create_xid ();
  call_msg.rm_direction = CALL;
  call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION;
  call_msg.rm_call.cb_prog = prog;
  call_msg.rm_call.cb_vers = vers;

  /*
   * pre-serialize the static part of the call msg and stash it away
   */
  xdrmem_create (&(ct->ct_xdrs), ct->ct_mcall, MCALL_MSG_SIZE,
		 XDR_ENCODE);
  if (!xdr_callhdr (&(ct->ct_xdrs), &call_msg))
    {
      if (ct->ct_closeit)
	{
	  (void) close (*sockp);
	}
      goto fooy;
    }
  ct->ct_mpos = XDR_GETPOS (&(ct->ct_xdrs));
  XDR_DESTROY (&(ct->ct_xdrs));

  /*
   * Create a client handle which uses xdrrec for serialization
   * and authnone for authentication.
   */
  xdrrec_create (&(ct->ct_xdrs), sendsz, recvsz,
		 (caddr_t) ct, readtcp, writetcp);
  h->cl_ops = &tcp_ops;
  h->cl_private = (caddr_t) ct;
  h->cl_auth = authnone_create ();
  return h;

fooy:
  /*
   * Something goofed, free stuff and barf
   */
  mem_free ((caddr_t) ct, sizeof (struct ct_data));
  mem_free ((caddr_t) h, sizeof (CLIENT));
  return ((CLIENT *) NULL);
}
Beispiel #17
0
/*
 * Create a UDP based client handle.
 * If *sockp<0, *sockp is set to a newly created UPD socket.
 * If raddr->sin_port is 0 a binder on the remote machine
 * is consulted for the correct port number.
 * NB: It is the clients responsibility to close *sockp.
 * NB: The rpch->cl_auth is initialized to null authentication.
 *     Caller may wish to set this something more useful.
 *
 * wait is the amount of time used between retransmitting a call if
 * no response has been heard; retransmission occurs until the actual
 * rpc call times out.
 *
 * sendsz and recvsz are the maximum allowable packet sizes that can be
 * sent and received.
 */
CLIENT *
__libc_clntudp_bufcreate (struct sockaddr_in *raddr, u_long program,
			  u_long version, struct timeval wait, int *sockp,
			  u_int sendsz, u_int recvsz, int flags)
{
  CLIENT *cl;
  struct cu_data *cu = NULL;
  struct rpc_msg call_msg;

  cl = (CLIENT *) mem_alloc (sizeof (CLIENT));
  sendsz = ((sendsz + 3) / 4) * 4;
  recvsz = ((recvsz + 3) / 4) * 4;
  cu = (struct cu_data *) mem_alloc (sizeof (*cu) + sendsz + recvsz);
  if (cl == NULL || cu == NULL)
    {
      struct rpc_createerr *ce = &get_rpc_createerr ();
      (void) __fxprintf (NULL, "%s: %s",
			 "clntudp_create", _("out of memory\n"));
      ce->cf_stat = RPC_SYSTEMERROR;
      ce->cf_error.re_errno = ENOMEM;
      goto fooy;
    }
  cu->cu_outbuf = &cu->cu_inbuf[recvsz];

  if (raddr->sin_port == 0)
    {
      u_short port;
      if ((port =
	   pmap_getport (raddr, program, version, IPPROTO_UDP)) == 0)
	{
	  goto fooy;
	}
      raddr->sin_port = htons (port);
    }
  cl->cl_ops = (struct clnt_ops *) &udp_ops;
  cl->cl_private = (caddr_t) cu;
  cu->cu_raddr = *raddr;
  cu->cu_rlen = sizeof (cu->cu_raddr);
  cu->cu_wait = wait;
  cu->cu_total.tv_sec = -1;
  cu->cu_total.tv_usec = -1;
  cu->cu_sendsz = sendsz;
  cu->cu_recvsz = recvsz;
  call_msg.rm_xid = _create_xid ();
  call_msg.rm_direction = CALL;
  call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION;
  call_msg.rm_call.cb_prog = program;
  call_msg.rm_call.cb_vers = version;
  xdrmem_create (&(cu->cu_outxdrs), cu->cu_outbuf, sendsz, XDR_ENCODE);
  if (!xdr_callhdr (&(cu->cu_outxdrs), &call_msg))
    {
      goto fooy;
    }
  cu->cu_xdrpos = XDR_GETPOS (&(cu->cu_outxdrs));
  if (*sockp < 0)
    {
#ifdef SOCK_NONBLOCK
# ifndef __ASSUME_SOCK_CLOEXEC
      if (__have_sock_cloexec >= 0)
# endif
	{
	  *sockp = __socket (AF_INET, SOCK_DGRAM|SOCK_NONBLOCK|flags,
			     IPPROTO_UDP);
# ifndef __ASSUME_SOCK_CLOEXEC
	  if (__have_sock_cloexec == 0)
	    __have_sock_cloexec = *sockp >= 0 || errno != EINVAL ? 1 : -1;
# endif
	}
#endif
#ifndef __ASSUME_SOCK_CLOEXEC
# ifdef SOCK_CLOEXEC
      if (__have_sock_cloexec < 0)
# endif
	{
	  *sockp = __socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP);
# ifdef SOCK_CLOEXEC
	  if (flags & SOCK_CLOEXEC)
	    __fcntl (*sockp, F_SETFD, FD_CLOEXEC);
# endif
	}
#endif
      if (__builtin_expect (*sockp < 0, 0))
	{
	  struct rpc_createerr *ce = &get_rpc_createerr ();
	  ce->cf_stat = RPC_SYSTEMERROR;
	  ce->cf_error.re_errno = errno;
	  goto fooy;
	}
      /* attempt to bind to prov port */
      (void) bindresvport (*sockp, (struct sockaddr_in *) 0);
#ifndef __ASSUME_SOCK_CLOEXEC
# ifdef SOCK_CLOEXEC
      if (__have_sock_cloexec < 0)
# endif
	{
	  /* the sockets rpc controls are non-blocking */
	  int dontblock = 1;
	  (void) __ioctl (*sockp, FIONBIO, (char *) &dontblock);
	}
#endif
#ifdef IP_RECVERR
      {
	int on = 1;
	__setsockopt (*sockp, SOL_IP, IP_RECVERR, &on, sizeof(on));
      }
#endif
      cu->cu_closeit = TRUE;
    }
  else
    {
      cu->cu_closeit = FALSE;
    }
  cu->cu_sock = *sockp;
  cl->cl_auth = authnone_create ();
  return cl;
fooy:
  if (cu)
    mem_free ((caddr_t) cu, sizeof (*cu) + sendsz + recvsz);
  if (cl)
    mem_free ((caddr_t) cl, sizeof (CLIENT));
  return (CLIENT *) NULL;
}
Beispiel #18
0
int openrm(

  char         *host,  /* I */
  unsigned int  port)  /* I (optional,0=DEFAULT) */

  {
  int                 stream;
  int                 rc;
  int                 retries = 0;

  static unsigned int gotport = 0;

  if (port == 0)
    {
    if (gotport == 0)
      {
      gotport = get_svrport((char *)PBS_MANAGER_SERVICE_NAME, (char *)"tcp",
                            PBS_MANAGER_SERVICE_PORT);
      }  /* END if (gotport == 0) */

    port = gotport;
    }

  if ((stream = socket(AF_INET, SOCK_STREAM, 0)) != -1)
    {

    struct sockaddr_in  addr;
    struct addrinfo    *addr_info;

    if (pbs_getaddrinfo(host, NULL, &addr_info) != 0)
      {
      DBPRT(("host %s not found\n", host))
      close(stream);

      return(ENOENT * -1);
      }

    memset(&addr, '\0', sizeof(addr));

    addr.sin_family = AF_INET;
    addr.sin_addr.s_addr = htonl(INADDR_ANY);

    while (retries++ < MAX_RETRIES)
      {
      rc = bindresvport(stream, &addr);
      if (rc != 0)
        {
        if (retries >= MAX_RETRIES)
          {
          close(stream);
          return(-1*errno);
          }
        sleep(1);
        }
      else
        break;
      }

    memset(&addr, '\0', sizeof(addr));

    addr.sin_addr = ((struct sockaddr_in *)addr_info->ai_addr)->sin_addr;
    addr.sin_family = AF_INET;
    addr.sin_port = htons((unsigned short)port);

    if (connect(stream, (struct sockaddr *)&addr, sizeof(addr)) == -1)
      {
      close(stream);

      return(-1 * errno);
      }
    }    /* END if ((stream = socket(AF_INET,SOCK_STREAM,0)) != -1) */

  if (stream < 0)
    {
    return(-1 * errno);
    }

  if (addrm(stream) == -1)
    {
    close(stream);

    return(-1 * errno);
    }

  return(stream);
  }  /* END openrm() */
Beispiel #19
0
static int
nd_init(vnode_t *dumpvp, TIUSER **tiptr)
{
	int 		error;

	if (*tiptr)
		return (0);

	/*
	 * If dump info hasn't yet been initialized (because dump
	 * device was chosen at user-level, rather than at boot time
	 * in nfs_swapvp) fill it in now.
	 */
	if (nfsdump_maxcount == 0) {
		nfsdump_version = VTOMI(dumpvp)->mi_vers;
		switch (nfsdump_version) {
		case NFS_VERSION:
			nfsdump_fhandle2 = *VTOFH(dumpvp);
			break;
		case NFS_V3:
			nfsdump_fhandle3 = *VTOFH3(dumpvp);
			break;
		default:
			return (EIO);
		}
		nfsdump_maxcount = (int)dumpvp_size;
		nfsdump_addr = VTOMI(dumpvp)->mi_curr_serv->sv_addr;
		nfsdump_cf = *(VTOMI(dumpvp)->mi_curr_serv->sv_knconf);
		if (nfsdump_cf.knc_semantics != NC_TPI_CLTS) {
			int v6 = 1;
			nd_log("nfs_dump: not connectionless!\n");
			if ((strcmp(nfsdump_cf.knc_protofmly, NC_INET) == 0) ||
			    ((v6 = strcmp(nfsdump_cf.knc_protofmly, NC_INET6))\
			    == 0)) {
				major_t clone_maj;

				nfsdump_cf.knc_proto = NC_UDP;
				nfsdump_cf.knc_semantics = NC_TPI_CLTS;
				nd_log("nfs_dump: grabbing UDP major number\n");
				clone_maj = ddi_name_to_major("clone");
				nd_log("nfs_dump: making UDP device\n");
				nfsdump_cf.knc_rdev = makedevice(clone_maj,
				    ddi_name_to_major(v6?"udp":"udp6"));
			} else {
				error = EIO;
				nfs_perror(error, "\nnfs_dump: cannot dump over"
				    " protocol %s: %m\n", nfsdump_cf.knc_proto);
				return (error);
			}
		}
	}

	nd_log("nfs_dump: calling t_kopen\n");

	if (error = t_kopen(NULL, nfsdump_cf.knc_rdev,
	    FREAD|FWRITE|FNDELAY, tiptr, CRED())) {
		nfs_perror(error, "\nnfs_dump: t_kopen failed: %m\n");
		return (EIO);
	}

	if ((strcmp(nfsdump_cf.knc_protofmly, NC_INET) == 0) ||
	    (strcmp(nfsdump_cf.knc_protofmly, NC_INET6) == 0)) {
		nd_log("nfs_dump: calling bindresvport\n");
		if (error = bindresvport(*tiptr, NULL, NULL, FALSE)) {
			nfs_perror(error,
			    "\nnfs_dump: bindresvport failed: %m\n");
			return (EIO);
		}
	} else {
		nd_log("nfs_dump: calling t_kbind\n");
		if ((error = t_kbind(*tiptr, NULL, NULL)) != 0) {
			nfs_perror(error, "\nnfs_dump: t_kbind failed: %m\n");
			return (EIO);
		}
	}
	return (0);
}
Beispiel #20
0
static enum clnt_stat
clnt_reconnect_connect(CLIENT *cl)
{
	struct thread *td = curthread;
	struct rc_data *rc = (struct rc_data *)cl->cl_private;
	struct socket *so;
	enum clnt_stat stat;
	int error;
	int one = 1;
	struct ucred *oldcred;
	CLIENT *newclient = NULL;

	mtx_lock(&rc->rc_lock);
	while (rc->rc_connecting) {
		error = msleep(rc, &rc->rc_lock,
		    rc->rc_intr ? PCATCH : 0, "rpcrecon", 0);
		if (error) {
			mtx_unlock(&rc->rc_lock);
			return (RPC_INTR);
		}
	}
	if (rc->rc_closed) {
		mtx_unlock(&rc->rc_lock);
		return (RPC_CANTSEND);
	}
	if (rc->rc_client) {
		mtx_unlock(&rc->rc_lock);
		return (RPC_SUCCESS);
	}

	/*
	 * My turn to attempt a connect. The rc_connecting variable
	 * serializes the following code sequence, so it is guaranteed
	 * that rc_client will still be NULL after it is re-locked below,
	 * since that is the only place it is set non-NULL.
	 */
	rc->rc_connecting = TRUE;
	mtx_unlock(&rc->rc_lock);

	oldcred = td->td_ucred;
	td->td_ucred = rc->rc_ucred;
	so = __rpc_nconf2socket(rc->rc_nconf);
	if (!so) {
		stat = rpc_createerr.cf_stat = RPC_TLIERROR;
		rpc_createerr.cf_error.re_errno = 0;
		td->td_ucred = oldcred;
		goto out;
	}

	if (rc->rc_privport)
		bindresvport(so, NULL);

	if (rc->rc_nconf->nc_semantics == NC_TPI_CLTS)
		newclient = clnt_dg_create(so,
		    (struct sockaddr *) &rc->rc_addr, rc->rc_prog, rc->rc_vers,
		    rc->rc_sendsz, rc->rc_recvsz);
	else
		newclient = clnt_vc_create(so,
		    (struct sockaddr *) &rc->rc_addr, rc->rc_prog, rc->rc_vers,
		    rc->rc_sendsz, rc->rc_recvsz, rc->rc_intr);
	td->td_ucred = oldcred;

	if (!newclient) {
		soclose(so);
		rc->rc_err = rpc_createerr.cf_error;
		stat = rpc_createerr.cf_stat;
		goto out;
	}

	CLNT_CONTROL(newclient, CLSET_FD_CLOSE, 0);
	CLNT_CONTROL(newclient, CLSET_CONNECT, &one);
	CLNT_CONTROL(newclient, CLSET_TIMEOUT, &rc->rc_timeout);
	CLNT_CONTROL(newclient, CLSET_RETRY_TIMEOUT, &rc->rc_retry);
	CLNT_CONTROL(newclient, CLSET_WAITCHAN, rc->rc_waitchan);
	CLNT_CONTROL(newclient, CLSET_INTERRUPTIBLE, &rc->rc_intr);
	if (rc->rc_backchannel != NULL)
		CLNT_CONTROL(newclient, CLSET_BACKCHANNEL, rc->rc_backchannel);
	stat = RPC_SUCCESS;

out:
	mtx_lock(&rc->rc_lock);
	KASSERT(rc->rc_client == NULL, ("rc_client not null"));
	if (!rc->rc_closed) {
		rc->rc_client = newclient;
		newclient = NULL;
	}
	rc->rc_connecting = FALSE;
	wakeup(rc);
	mtx_unlock(&rc->rc_lock);

	if (newclient) {
		/*
		 * It has been closed, so discard the new client.
		 * nb: clnt_[dg|vc]_close()/clnt_[dg|vc]_destroy() cannot
		 * be called with the rc_lock mutex held, since they may
		 * msleep() while holding a different mutex.
		 */
		CLNT_CLOSE(newclient);
		CLNT_RELEASE(newclient);
	}

	return (stat);
}
Beispiel #21
0
/*
 * Usage:
 *      xprt = svcudp_create(sock);
 *
 * If sock<0 then a socket is created, else sock is used.
 * If the socket, sock is not bound to a port then svcudp_create
 * binds it to an arbitrary port.  In any (successful) case,
 * xprt->xp_sock is the registered socket number and xprt->xp_port is the
 * associated port number.
 * Once *xprt is initialized, it is registered as a transporter;
 * see (svc.h, xprt_register).
 * The routines returns NULL if a problem occurred.
 */
SVCXPRT *
svcudp_bufcreate (int sock, u_int sendsz, u_int recvsz)
{
  bool_t madesock = FALSE;
  SVCXPRT *xprt;
  struct svcudp_data *su;
  struct sockaddr_in addr;
  socklen_t len = sizeof (struct sockaddr_in);
  int pad;
  void *buf;

  if (sock == RPC_ANYSOCK)
    {
      if ((sock = socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
	{
	  perror (_("svcudp_create: socket creation problem"));
	  return (SVCXPRT *) NULL;
	}
      madesock = TRUE;
    }
  memset ((char *) &addr, 0, sizeof (addr));
  addr.sin_family = AF_INET;
  if (bindresvport (sock, &addr))
    {
      addr.sin_port = 0;
      (void) bind (sock, (struct sockaddr *) &addr, len);
    }
  if (getsockname (sock, (struct sockaddr *) &addr, &len) != 0)
    {
      perror (_("svcudp_create - cannot getsockname"));
      if (madesock)
	(void) close (sock);
      return (SVCXPRT *) NULL;
    }
  xprt = (SVCXPRT *) mem_alloc (sizeof (SVCXPRT));
  su = (struct svcudp_data *) mem_alloc (sizeof (*su));
  buf = mem_alloc (((MAX (sendsz, recvsz) + 3) / 4) * 4);
  if (xprt == NULL || su == NULL || buf == NULL)
    {
#ifdef USE_IN_LIBIO
      if (_IO_fwide (stderr, 0) > 0)
	(void) fwprintf (stderr, L"%s", _("svcudp_create: out of memory\n"));
      else
#endif
	(void) fputs (_("svcudp_create: out of memory\n"), stderr);
      mem_free (xprt, sizeof (SVCXPRT));
      mem_free (su, sizeof (*su));
      mem_free (buf, ((MAX (sendsz, recvsz) + 3) / 4) * 4);
      return NULL;
    }
  su->su_iosz = ((MAX (sendsz, recvsz) + 3) / 4) * 4;
  rpc_buffer (xprt) = buf;
  xdrmem_create (&(su->su_xdrs), rpc_buffer (xprt), su->su_iosz, XDR_DECODE);
  su->su_cache = NULL;
  xprt->xp_p2 = (caddr_t) su;
  xprt->xp_verf.oa_base = su->su_verfbody;
  xprt->xp_ops = &svcudp_op;
  xprt->xp_port = ntohs (addr.sin_port);
  xprt->xp_sock = sock;

#ifdef IP_PKTINFO
  if ((sizeof (struct iovec) + sizeof (struct msghdr)
       + sizeof(struct cmsghdr) + sizeof (struct in_pktinfo))
      > sizeof (xprt->xp_pad))
    {
# ifdef USE_IN_LIBIO
      if (_IO_fwide (stderr, 0) > 0)
	(void) fwprintf (stderr, L"%s",
			   _("svcudp_create: xp_pad is too small for IP_PKTINFO\n"));
      else
# endif
	(void) fputs (_("svcudp_create: xp_pad is too small for IP_PKTINFO\n"),
		      stderr);
      return NULL;
    }
  pad = 1;
  if (setsockopt (sock, SOL_IP, IP_PKTINFO, (void *) &pad,
		  sizeof (pad)) == 0)
    /* Set the padding to all 1s. */
    pad = 0xff;
  else
#endif
    /* Clear the padding. */
    pad = 0;
  memset (&xprt->xp_pad [0], pad, sizeof (xprt->xp_pad));

  xprt_register (xprt);
  return xprt;
}
Beispiel #22
0
/*
 * A common clnt create routine
 */
static CLIENT *
clnt_com_create(struct sockaddr_in *raddr, rpcprog_t prog, rpcvers_t vers,
	int *sockp, u_int sendsz, u_int recvsz, const char *tp)
{
	CLIENT *cl;
	int madefd = FALSE;
	int fd;
	struct netconfig *nconf;
	struct netbuf bindaddr;

	_DIAGASSERT(raddr != NULL);
	_DIAGASSERT(sockp != NULL);
	_DIAGASSERT(tp != NULL);

	fd = *sockp;

	mutex_lock(&rpcsoc_lock);
	if ((nconf = __rpc_getconfip(tp)) == NULL) {
		rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
		mutex_unlock(&rpcsoc_lock);
		return (NULL);
	}
	if (fd == RPC_ANYSOCK) {
		fd = __rpc_nconf2fd(nconf);
		if (fd == -1)
			goto syserror;
		madefd = TRUE;
	}

	if (raddr->sin_port == 0) {
		u_int proto;
		u_short sport;

		mutex_unlock(&rpcsoc_lock);	/* pmap_getport is recursive */
		proto = strcmp(tp, "udp") == 0 ? IPPROTO_UDP : IPPROTO_TCP;
		sport = pmap_getport(raddr, (u_long)prog, (u_long)vers,
		    proto);
		if (sport == 0) {
			goto err;
		}
		raddr->sin_port = htons(sport);
		mutex_lock(&rpcsoc_lock);	/* pmap_getport is recursive */
	}

	/* Transform sockaddr_in to netbuf */
	bindaddr.maxlen = bindaddr.len =  sizeof (struct sockaddr_in);
	bindaddr.buf = raddr;

	(void)bindresvport(fd, NULL);
	cl = clnt_tli_create(fd, nconf, &bindaddr, prog, vers,
				sendsz, recvsz);
	if (cl) {
		if (madefd == TRUE) {
			/*
			 * The fd should be closed while destroying the handle.
			 */
			(void) CLNT_CONTROL(cl, CLSET_FD_CLOSE, NULL);
			*sockp = fd;
		}
		(void) freenetconfigent(nconf);
		mutex_unlock(&rpcsoc_lock);
		return (cl);
	}
	goto err;

syserror:
	rpc_createerr.cf_stat = RPC_SYSTEMERROR;
	rpc_createerr.cf_error.re_errno = errno;

err:	if (madefd == TRUE)
		(void) close(fd);
	(void) freenetconfigent(nconf);
	mutex_unlock(&rpcsoc_lock);
	return (NULL);
}
Beispiel #23
0
/* libc_hidden_proto(clntudp_bufcreate) */
CLIENT *
clntudp_bufcreate (struct sockaddr_in *raddr, u_long program, u_long version,
		   struct timeval wait, int *sockp, u_int sendsz,
		   u_int recvsz)
{
  CLIENT *cl;
  struct cu_data *cu = NULL;
  struct rpc_msg call_msg;

  cl = (CLIENT *) mem_alloc (sizeof (CLIENT));
  sendsz = ((sendsz + 3) / 4) * 4;
  recvsz = ((recvsz + 3) / 4) * 4;
  cu = (struct cu_data *) mem_alloc (sizeof (*cu) + sendsz + recvsz);
  if (cl == NULL || cu == NULL)
    {
      struct rpc_createerr *ce = &get_rpc_createerr ();
#ifdef USE_IN_LIBIO
      if (_IO_fwide (stderr, 0) > 0)
	(void) fwprintf (stderr, L"%s",
			   _("clntudp_create: out of memory\n"));
      else
#endif
	(void) fputs (_("clntudp_create: out of memory\n"), stderr);
      ce->cf_stat = RPC_SYSTEMERROR;
      ce->cf_error.re_errno = ENOMEM;
      goto fooy;
    }
  cu->cu_outbuf = &cu->cu_inbuf[recvsz];

  if (raddr->sin_port == 0)
    {
      u_short port;
      if ((port =
	   pmap_getport (raddr, program, version, IPPROTO_UDP)) == 0)
	{
	  goto fooy;
	}
      raddr->sin_port = htons (port);
    }
  cl->cl_ops = &udp_ops;
  cl->cl_private = (caddr_t) cu;
  cu->cu_raddr = *raddr;
  cu->cu_rlen = sizeof (cu->cu_raddr);
  cu->cu_wait = wait;
  cu->cu_total.tv_sec = -1;
  cu->cu_total.tv_usec = -1;
  cu->cu_sendsz = sendsz;
  cu->cu_recvsz = recvsz;
  call_msg.rm_xid = _create_xid ();
  call_msg.rm_direction = CALL;
  call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION;
  call_msg.rm_call.cb_prog = program;
  call_msg.rm_call.cb_vers = version;
  xdrmem_create (&(cu->cu_outxdrs), cu->cu_outbuf,
		 sendsz, XDR_ENCODE);
  if (!xdr_callhdr (&(cu->cu_outxdrs), &call_msg))
    {
      goto fooy;
    }
  cu->cu_xdrpos = XDR_GETPOS (&(cu->cu_outxdrs));
  if (*sockp < 0)
    {
      int dontblock = 1;

      *sockp = socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP);
      if (*sockp < 0)
	{
	  struct rpc_createerr *ce = &get_rpc_createerr ();
	  ce->cf_stat = RPC_SYSTEMERROR;
	  ce->cf_error.re_errno = errno;
	  goto fooy;
	}
      /* attempt to bind to prov port */
      (void) bindresvport (*sockp, (struct sockaddr_in *) 0);
      /* the sockets rpc controls are non-blocking */
      (void) ioctl (*sockp, FIONBIO, (char *) &dontblock);
#ifdef IP_RECVERR
      {
	int on = 1;
	setsockopt(*sockp, SOL_IP, IP_RECVERR, &on, sizeof(on));
      }
#endif
      cu->cu_closeit = TRUE;
    }
  else
    {
      cu->cu_closeit = FALSE;
    }
  cu->cu_sock = *sockp;
  cl->cl_auth = authnone_create ();
  return cl;
fooy:
  if (cu)
    mem_free ((caddr_t) cu, sizeof (*cu) + sendsz + recvsz);
  if (cl)
    mem_free ((caddr_t) cl, sizeof (CLIENT));
  return (CLIENT *) NULL;
}
Beispiel #24
0
/*
 * Create a UDP based client handle.
 * If *sockp<0, *sockp is set to a newly created UPD socket.
 * If raddr->sin_port is 0 a binder on the remote machine
 * is consulted for the correct port number.
 * NB: It is the clients responsibility to close *sockp.
 * NB: The rpch->cl_auth is initialized to null authentication.
 *     Caller may wish to set this something more useful.
 *
 * wait is the amount of time used between retransmitting a call if
 * no response has been heard;  retransmition occurs until the actual
 * rpc call times out.
 *
 * sendsz and recvsz are the maximum allowable packet sizes that can be
 * sent and received.
 */
CLIENT *clntudp_bufcreate(struct sockaddr_in *raddr, 
	unsigned long program, 
	unsigned long version,
	struct timeval wait, 
	int *sockp, 
	unsigned int sendsz,
	unsigned int recvsz)
{
	CLIENT *cl;
	register struct cu_data *cu = NULL;
	struct timeval now;
	struct rpc_msg call_msg;
	static uintptr_t disrupt = 0;

	cl = (CLIENT *) sys_malloc (sizeof(CLIENT));
	if (cl == NULL)
	{
		fprintf(stderr, "rpc : clntudp_create: out of memory\n");
		goto fooy;
	}
	sendsz = ((sendsz + 3) / 4) * 4;
	recvsz = ((recvsz + 3) / 4) * 4;
	cu = (struct cu_data *) sys_malloc (sizeof(*cu) + sendsz + recvsz);
	if (cu == NULL)
	{
	    fprintf(stderr, "rpc : clntudp_create: out of memory\n");
		goto fooy;
	}
	cu->cu_outbuf = &cu->cu_inbuf[recvsz];

    (void)gettimeofday(&now, (struct timezone *)0);
	if (raddr->sin_port == 0) {
		unsigned short port;

		if ((port =
			 pmap_getport(raddr, program, version, IPPROTO_UDP)) == 0) {
			goto fooy;
		}
		raddr->sin_port = htons(port);
	}

	cl->cl_ops = &udp_ops;
	cl->cl_private = (char*) cu;
	cu->cu_raddr = *raddr;
	cu->cu_rlen = sizeof(cu->cu_raddr);
	cu->cu_wait = wait;
	cu->cu_total.tv_sec = -1;
	cu->cu_total.tv_usec = -1;
	cu->cu_sendsz = sendsz;
	cu->cu_recvsz = recvsz;
	call_msg.rm_xid = (++disrupt) ^ getpid() ^ now.tv_sec ^ now.tv_usec;
	call_msg.rm_direction = CALL;
	call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION;
	call_msg.rm_call.cb_prog = program;
	call_msg.rm_call.cb_vers = version;
	xdrmem_create(&(cu->cu_outxdrs), cu->cu_outbuf, sendsz, XDR_ENCODE);
	if (!xdr_callhdr(&(cu->cu_outxdrs), &call_msg))
	{
		goto fooy;
	}
	cu->cu_xdrpos = XDR_GETPOS(&(cu->cu_outxdrs));
	if (*sockp < 0)
	{
		int dontblock = 1;

		*sockp = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
		if (*sockp < 0)
		{
		    fprintf(stderr, "rpc : create socket error\n");
			goto fooy;
		}
		/* attempt to bind to prov port */
		(void)bindresvport(*sockp, (struct sockaddr_in *)0);
		cu->cu_closeit = TRUE;
	}
	else
	{
		cu->cu_closeit = FALSE;
	}
	cu->cu_sock = *sockp;
	cl->cl_auth = authnone_create();
	
	/* sylixos fix this bug new socket must set timeout argments 2012.03.10 */
    clnt_control(cl, CLSET_TIMEOUT, (char*)&wait);
	return (cl);

fooy:
	if (cu) sys_free(cu);
	if (cl) sys_free(cl);

	return ((CLIENT *) NULL);
}
int socket_get_tcp_priv()

{
    int priv_port = 0, local_socket = 0;
    int cntr = 0;
#ifdef HAVE_RRESVPORT
    int on = 1;
    struct linger l_delay;
#endif
    int rc = PBSE_NONE;
    struct sockaddr_in local;
    int flags;
    memset(&local, 0, sizeof(struct sockaddr_in));
    local.sin_family = AF_INET;

    /* If any of the following 2 succeed (negative conditions) jump to else below
     * else run the default */
#ifdef HAVE_RRESVPORT
    memset(&l_delay, 0, sizeof(struct linger));
    l_delay.l_onoff = 0;
    if ((local_socket = rresvport(&priv_port)) != -1)
    {
        if (setsockopt(local_socket, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(int)) == -1)
        {
            rc = PBSE_SOCKET_FAULT;
        }
        else if (setsockopt(local_socket, SOL_SOCKET, SO_LINGER, &l_delay, sizeof(struct linger)) == -1)
        {
            rc = PBSE_SOCKET_FAULT;
        }
    }
    if (rc == PBSE_NONE)
    {
        /* Success case */
        priv_port = local_socket;
    }
    else if ((local_socket = socket_get_tcp()) > 0)
#else
#ifdef HAVE_BINDRESVPORT
    if ((local_socket = socket_get_tcp()) > 0)
    {
        if ((rc = bindresvport(local_socket, &local)) == 0)
        {
            /* Success case */
            priv_port = ntohs(local.sin_port);
        }
        else
        {
            rc = PBSE_SOCKET_FAULT;
        }
    }
    else
        rc = PBSE_SOCKET_FAULT;
    if (rc != PBSE_NONE)
#else /* Default */
    if ((local_socket = socket_get_tcp()) > 0)
#endif
#endif
    {
        /* According to the notes in the previous code:
         * bindresvport seems to cause connect() failures in some odd corner case
         * when talking to a local daemon.  So we'll only try this once and
         * fallback to the slow loop around bind() if connect() fails
         * with EADDRINUSE or EADDRNOTAVAIL.
         * http://www.supercluster.org/pipermail/torqueusers/2006-June/003740.html
         */

        flags = fcntl(local_socket, F_GETFL);
        flags |= O_NONBLOCK;
        fcntl(local_socket, F_SETFL, flags);

        priv_port = get_random_reserved_port();
        while (cntr < RES_PORT_RETRY)
        {
            if (++priv_port >= RES_PORT_END)
                priv_port = RES_PORT_START;
            local.sin_port = htons(priv_port);
            if (((rc = bind(local_socket, (struct sockaddr *)&local, sizeof(struct sockaddr))) < 0) &&
                    ((rc == EADDRINUSE) ||
                     (errno == EADDRNOTAVAIL) ||
                     (errno == EINVAL) ||
                     (rc == EINPROGRESS)))
            {
                cntr++;
            }
            else
            {
                rc = PBSE_NONE;
                break;
            }
        }
        if (cntr >= RES_PORT_RETRY)
        {
            close(local_socket);
            rc = PBSE_SOCKET_FAULT;
            errno = PBSE_SOCKET_FAULT;
            local_socket = -1;
        }
    }
    else
    {
        /* If something worked the first time you end up here */
        rc = PBSE_NONE;
    }
    if (rc != PBSE_NONE)
    {
        local_socket = -1;
    }
    return local_socket;
} /* END socket_get_tcp_priv() */
Beispiel #26
0
/*
 * Usage:
 *      xprt = svctcp_create(sock, send_buf_size, recv_buf_size);
 *
 * Creates, registers, and returns a (rpc) tcp based transporter.
 * Once *xprt is initialized, it is registered as a transporter
 * see (svc.h, xprt_register).  This routine returns
 * a NULL if a problem occurred.
 *
 * If sock<0 then a socket is created, else sock is used.
 * If the socket, @var{sock}, is not bound to a port then svctcp_create
 * binds it to an arbitrary port.  The routine then starts a tcp
 * listener on the socket's associated port.  In any (successful) case,
 * xprt->xp_sock is the registered socket number and xprt->xp_port is the
 * associated port number.
 *
 * Since tcp streams do buffered io similar to stdio, the caller can specify
 * how big the send and receive buffers are via the second and third parms;
 * 0 => use the system default.
 */
SVCXPRT *
svctcp_create_with_lock(int sock, u_int sendsize, u_int recvsize)
{
    bool_t madesock;
    SVCXPRT *xprt;
    mtxprt_t *mtxprt;
    struct tcp_rendezvous *r;
    struct sockaddr_in addr;
    socklen_t len;
    int ret;
    int err;

#ifdef DEBUG_BUFSIZE_8K
    if (sendsize == 0) {
        sendsize = 8192;        // Magic number.  For debugging only.
    }
    if (recvsize == 0) {
        recvsize = 8192;        // Magic number.  For debugging only.
    }
#endif /* DEBUG_BUFSIZE_8K */

    tprintf(2, "sock=%d, sendsize=%u, recvsize=%u\n",
        sock, sendsize, recvsize);
    madesock = FALSE;
    len = sizeof (struct sockaddr_in);

    if (sock == RPC_ANYSOCK) {
        sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
        tprintf(2, "socket() => %d\n", sock);
        if (sock < 0) {
            svc_perror(errno, "svc_tcp.c - tcp socket creation problem");
            return ((SVCXPRT *)NULL);
        }
        madesock = TRUE;
    }
    bzero((char *)&addr, sizeof (addr));
    addr.sin_family = AF_INET;
    if (bindresvport(sock, &addr)) {
        addr.sin_port = 0;
        (void) bind(sock, (struct sockaddr *)&addr, len);
    }

    ret = getsockname(sock, (struct sockaddr *)&addr, &len);
    if (ret != 0) {
        err = errno;
        svc_perror(err, "svc_tcp.c - getsockname(...) failed");
    }
    else {
        ret = listen(sock, SOMAXCONN);
        if (ret != 0) {
            err = errno;
            svc_perror(err, "svc_tcp.c - listen() failed");
        }
    }

    if (ret != 0) {
        if (madesock) {
            (void) close(sock);
        }
        return ((SVCXPRT *)NULL);
    }

    r = (struct tcp_rendezvous *)guard_malloc(sizeof (*r));
    xprt = alloc_xprt();

    /*
     * Constructor for @type{SVCXPRT}, including the additional @type{mtxprt_t}
     * Order of construction is important.
     * We want to create a lock for each @type{SVCXPRT}.
     * The rest of the contructor should all be done while the lock is held.
     * Even if it is not _really_ necessary, it will keep Valgrind/Helgrind
     * happy.  And they are our friends.
     * Second step is to initialize the "magic" value, so that other
     * helper functions that validate it will be happy.
     */

    mtxprt = xprt_to_mtxprt_nocheck(xprt);

    if (pthread_mutex_init(&(mtxprt->mtxp_lock), NULL) != 0) {
        abort();
    }

    if (pthread_mutex_init(&(mtxprt->mtxp_progress_lock), NULL) != 0) {
        abort();
    }

    if (pthread_mutex_init(&(mtxprt->mtxp_mtready), NULL) != 0) {
        abort();
    }

    // Start off locked.  svctcp_getargs() will unlock it.
    if (pthread_mutex_lock(&(mtxprt->mtxp_mtready)) != 0) {
        abort();
    }

    /*
     * Do not use xprt_lock(xprt) here.
     * The constructor has not progressed far enough, yet.
     */
    if (pthread_mutex_lock(&(mtxprt->mtxp_lock)) != 0) {
        abort();
    }

    /*
     * Set "magic", right away.
     * Other functions validate it.  Keep them happy.
     */
    mtxprt->mtxp_magic = MTXPRT_MAGIC;

    r->sendsize = sendsize;
    r->recvsize = recvsize;
    mtxprt->mtxp_progress = 0;
    mtxprt->mtxp_busy = 0;
    xprt->xp_p2 = NULL;
    xprt->xp_p1 = (caddr_t)r;
    xprt->xp_verf = _null_auth;
    xprt->xp_ops = &svctcp_rendezvous_op;
    xprt->xp_port = ntohs(addr.sin_port);
    xprt->xp_sock = sock;

    mtxprt->mtxp_creator = pthread_self();
    mtxprt->mtxp_id = XPRT_ID_INVALID;
    mtxprt->mtxp_clone  = NULL;
    mtxprt->mtxp_parent = NO_PARENT;
    mtxprt->mtxp_refcnt = 0;
#ifdef CHECK_CREDENTIALS
    memset(mtxprt->mtxp_cred, 0, sizeof (mtxprt->mtxp_cred));
#endif
    memcpy(mtxprt->mtxp_guard, MTXPRT_GUARD, sizeof (mtxprt->mtxp_guard));
    xprt_unlock(xprt);
    xprt_register(xprt);
    return (xprt);
}
Beispiel #27
0
CLIENT *
get_client(struct sockaddr *host_addr, rpcvers_t vers)
{
	CLIENT *client;
	struct timeval retry_time, time_now;
	int error, i;
	const char *netid;
	struct netconfig *nconf;
	char host[NI_MAXHOST];
	uid_t old_euid;
	int clnt_fd;

	gettimeofday(&time_now, NULL);

	/*
	 * Search for the given client in the cache, zapping any expired
	 * entries that we happen to notice in passing.
	 */
	for (i = 0; i < CLIENT_CACHE_SIZE; i++) {
		client = clnt_cache_ptr[i];
		if (client && ((clnt_cache_time[i] + CLIENT_CACHE_LIFETIME)
		    < time_now.tv_sec)) {
			/* Cache entry has expired. */
			if (debug_level > 3)
				syslog(LOG_DEBUG, "Expired CLIENT* in cache");
			clnt_cache_time[i] = 0L;
			clnt_destroy(client);
			clnt_cache_ptr[i] = NULL;
			client = NULL;
		}
		if (client && !addrcmp((struct sockaddr *)&clnt_cache_addr[i],
		    host_addr) && clnt_cache_vers[i] == vers) {
			/* Found it! */
			if (debug_level > 3)
				syslog(LOG_DEBUG, "Found CLIENT* in cache");
			return (client);
		}
	}

	if (debug_level > 3)
		syslog(LOG_DEBUG, "CLIENT* not found in cache, creating");

	/* Not found in cache.  Free the next entry if it is in use. */
	if (clnt_cache_ptr[clnt_cache_next_to_use]) {
		clnt_destroy(clnt_cache_ptr[clnt_cache_next_to_use]);
		clnt_cache_ptr[clnt_cache_next_to_use] = NULL;
	}

	/*
	 * Need a host string for clnt_tp_create. Use NI_NUMERICHOST
	 * to avoid DNS lookups.
	 */
	error = getnameinfo(host_addr, host_addr->sa_len, host, sizeof host,
			    NULL, 0, NI_NUMERICHOST);
	if (error != 0) {
		syslog(LOG_ERR, "unable to get name string for caller: %s",
		       gai_strerror(error));
		return NULL;
	}

#if 1
	if (host_addr->sa_family == AF_INET6)
		netid = "udp6";
	else
		netid = "udp";
#else 
	if (host_addr->sa_family == AF_INET6)
		netid = "tcp6";
	else
		netid = "tcp";
#endif
	nconf = getnetconfigent(netid);
	if (nconf == NULL) {
		syslog(LOG_ERR, "could not get netconfig info for '%s': "
				"no /etc/netconfig file?", netid);
		return NULL;
	}

	client = clnt_tp_create(host, NLM_PROG, vers, nconf);
	freenetconfigent(nconf);

	if (!client) {
		syslog(LOG_ERR, "%s", clnt_spcreateerror("clntudp_create"));
		syslog(LOG_ERR, "Unable to return result to %s", host);
		return NULL;
	}

	/* Get the FD of the client, for bindresvport. */ 
	clnt_control(client, CLGET_FD, &clnt_fd);

	/* Regain root privileges, for bindresvport. */
	old_euid = geteuid();
	seteuid(0);

	/*
	 * Bind the client FD to a reserved port.
	 * Some NFS servers reject any NLM request from a non-reserved port. 
	 */ 
	bindresvport(clnt_fd, NULL);

	/* Drop root privileges again. */
	seteuid(old_euid);

	/* Success - update the cache entry */
	clnt_cache_ptr[clnt_cache_next_to_use] = client;
	memcpy(&clnt_cache_addr[clnt_cache_next_to_use], host_addr,
	    host_addr->sa_len);
	clnt_cache_vers[clnt_cache_next_to_use] = vers;
	clnt_cache_time[clnt_cache_next_to_use] = time_now.tv_sec;
	if (++clnt_cache_next_to_use >= CLIENT_CACHE_SIZE)
		clnt_cache_next_to_use = 0;

	/*
	 * Disable the default timeout, so we can specify our own in calls
	 * to clnt_call().  (Note that the timeout is a different concept
	 * from the retry period set in clnt_udp_create() above.)
	 */
	retry_time.tv_sec = -1;
	retry_time.tv_usec = -1;
	clnt_control(client, CLSET_TIMEOUT, (char *)&retry_time);

	if (debug_level > 3)
		syslog(LOG_DEBUG, "Created CLIENT* for %s", host);
	return client;
}
Beispiel #28
0
int nfsmount(const char *spec, const char *node, int *flags,
	     char **extra_opts, char **mount_opts, int running_bg)
{
	static char *prev_bg_host;
	char hostdir[1024];
	CLIENT *mclient;
	char *hostname;
	char *pathname;
	char *old_opts;
	char *mounthost=NULL;
	char new_opts[1024];
	struct timeval total_timeout;
	enum clnt_stat clnt_stat;
	static struct nfs_mount_data data;
	char *opt, *opteq;
	int val;
	struct hostent *hp;
	struct sockaddr_in server_addr;
	struct sockaddr_in mount_server_addr;
	struct pmap* pm_mnt;
	int msock, fsock;
	struct timeval retry_timeout;
	union {
		struct fhstatus nfsv2;
		struct mountres3 nfsv3;
	} status;
	struct stat statbuf;
	char *s;
	int port;
	int mountport;
	int proto;
	int bg;
	int soft;
	int intr;
	int posix;
	int nocto;
	int noac;
	int nolock;
	int retry;
	int tcp;
	int mountprog;
	int mountvers;
	int nfsprog;
	int nfsvers;
	int retval;
	time_t t;
	time_t prevt;
	time_t timeout;

	find_kernel_nfs_mount_version();

	retval = EX_FAIL;
	msock = fsock = -1;
	mclient = NULL;
	if (strlen(spec) >= sizeof(hostdir)) {
		bb_error_msg("excessively long host:dir argument");
		goto fail;
	}
	strcpy(hostdir, spec);
	if ((s = strchr(hostdir, ':'))) {
		hostname = hostdir;
		pathname = s + 1;
		*s = '\0';
		/* Ignore all but first hostname in replicated mounts
		   until they can be fully supported. ([email protected]) */
		if ((s = strchr(hostdir, ','))) {
			*s = '\0';
			bb_error_msg("warning: multiple hostnames not supported");
		}
	} else {
		bb_error_msg("directory to mount not in host:dir format");
		goto fail;
	}

	server_addr.sin_family = AF_INET;
#ifdef HAVE_inet_aton
	if (!inet_aton(hostname, &server_addr.sin_addr))
#endif
	{
		if ((hp = gethostbyname(hostname)) == NULL) {
			bb_herror_msg("%s", hostname);
			goto fail;
		} else {
			if (hp->h_length > sizeof(struct in_addr)) {
				bb_error_msg("got bad hp->h_length");
				hp->h_length = sizeof(struct in_addr);
			}
			memcpy(&server_addr.sin_addr,
			       hp->h_addr, hp->h_length);
		}
	}

	memcpy (&mount_server_addr, &server_addr, sizeof (mount_server_addr));

	/* add IP address to mtab options for use when unmounting */

	s = inet_ntoa(server_addr.sin_addr);
	old_opts = *extra_opts;
	if (!old_opts)
		old_opts = "";
	if (strlen(old_opts) + strlen(s) + 10 >= sizeof(new_opts)) {
		bb_error_msg("excessively long option argument");
		goto fail;
	}
	sprintf(new_opts, "%s%saddr=%s",
		old_opts, *old_opts ? "," : "", s);
	*extra_opts = bb_xstrdup(new_opts);

	/* Set default options.
	 * rsize/wsize (and bsize, for ver >= 3) are left 0 in order to
	 * let the kernel decide.
	 * timeo is filled in after we know whether it'll be TCP or UDP. */
	memset(&data, 0, sizeof(data));
	data.retrans	= 3;
	data.acregmin	= 3;
	data.acregmax	= 60;
	data.acdirmin	= 30;
	data.acdirmax	= 60;
#if NFS_MOUNT_VERSION >= 2
	data.namlen	= NAME_MAX;
#endif

	bg = 0;
	soft = 0;
	intr = 0;
	posix = 0;
	nocto = 0;
	nolock = 0;
	noac = 0;
	retry = 10000;		/* 10000 minutes ~ 1 week */
	tcp = 0;

	mountprog = MOUNTPROG;
	mountvers = 0;
	port = 0;
	mountport = 0;
	nfsprog = NFS_PROGRAM;
	nfsvers = 0;

	/* parse options */

	for (opt = strtok(old_opts, ","); opt; opt = strtok(NULL, ",")) {
		if ((opteq = strchr(opt, '='))) {
			val = atoi(opteq + 1);	
			*opteq = '\0';
			if (!strcmp(opt, "rsize"))
				data.rsize = val;
			else if (!strcmp(opt, "wsize"))
				data.wsize = val;
			else if (!strcmp(opt, "timeo"))
				data.timeo = val;
			else if (!strcmp(opt, "retrans"))
				data.retrans = val;
			else if (!strcmp(opt, "acregmin"))
				data.acregmin = val;
			else if (!strcmp(opt, "acregmax"))
				data.acregmax = val;
			else if (!strcmp(opt, "acdirmin"))
				data.acdirmin = val;
			else if (!strcmp(opt, "acdirmax"))
				data.acdirmax = val;
			else if (!strcmp(opt, "actimeo")) {
				data.acregmin = val;
				data.acregmax = val;
				data.acdirmin = val;
				data.acdirmax = val;
			}
			else if (!strcmp(opt, "retry"))
				retry = val;
			else if (!strcmp(opt, "port"))
				port = val;
			else if (!strcmp(opt, "mountport"))
			        mountport = val;
			else if (!strcmp(opt, "mounthost"))
			        mounthost=bb_xstrndup(opteq+1,
						  strcspn(opteq+1," \t\n\r,"));
			else if (!strcmp(opt, "mountprog"))
				mountprog = val;
			else if (!strcmp(opt, "mountvers"))
				mountvers = val;
			else if (!strcmp(opt, "nfsprog"))
				nfsprog = val;
			else if (!strcmp(opt, "nfsvers") ||
				 !strcmp(opt, "vers"))
				nfsvers = val;
			else if (!strcmp(opt, "proto")) {
				if (!strncmp(opteq+1, "tcp", 3))
					tcp = 1;
				else if (!strncmp(opteq+1, "udp", 3))
					tcp = 0;
				else
					printf(_("Warning: Unrecognized proto= option.\n"));
			} else if (!strcmp(opt, "namlen")) {
#if NFS_MOUNT_VERSION >= 2
				if (nfs_mount_version >= 2)
					data.namlen = val;
				else
#endif
				printf(_("Warning: Option namlen is not supported.\n"));
			} else if (!strcmp(opt, "addr"))
				/* ignore */;
			else {
				printf(_("unknown nfs mount parameter: "
				       "%s=%d\n"), opt, val);
				goto fail;
			}
		}
		else {
			val = 1;
			if (!strncmp(opt, "no", 2)) {
				val = 0;
				opt += 2;
			}
			if (!strcmp(opt, "bg")) 
				bg = val;
			else if (!strcmp(opt, "fg")) 
				bg = !val;
			else if (!strcmp(opt, "soft"))
				soft = val;
			else if (!strcmp(opt, "hard"))
				soft = !val;
			else if (!strcmp(opt, "intr"))
				intr = val;
			else if (!strcmp(opt, "posix"))
				posix = val;
			else if (!strcmp(opt, "cto"))
				nocto = !val;
			else if (!strcmp(opt, "ac"))
				noac = !val;
			else if (!strcmp(opt, "tcp"))
				tcp = val;
			else if (!strcmp(opt, "udp"))
				tcp = !val;
			else if (!strcmp(opt, "lock")) {
				if (nfs_mount_version >= 3)
					nolock = !val;
				else
					printf(_("Warning: option nolock is not supported.\n"));
			} else {
				printf(_("unknown nfs mount option: "
					   "%s%s\n"), val ? "" : "no", opt);
				goto fail;
			}
		}
	}
	proto = (tcp) ? IPPROTO_TCP : IPPROTO_UDP;

	data.flags = (soft ? NFS_MOUNT_SOFT : 0)
		| (intr ? NFS_MOUNT_INTR : 0)
		| (posix ? NFS_MOUNT_POSIX : 0)
		| (nocto ? NFS_MOUNT_NOCTO : 0)
		| (noac ? NFS_MOUNT_NOAC : 0);
#if NFS_MOUNT_VERSION >= 2
	if (nfs_mount_version >= 2)
		data.flags |= (tcp ? NFS_MOUNT_TCP : 0);
#endif
#if NFS_MOUNT_VERSION >= 3
	if (nfs_mount_version >= 3)
		data.flags |= (nolock ? NFS_MOUNT_NONLM : 0);
#endif
	if (nfsvers > MAX_NFSPROT) {
		bb_error_msg("NFSv%d not supported!", nfsvers);
		return 0;
	}
	if (mountvers > MAX_NFSPROT) {
		bb_error_msg("NFSv%d not supported!", nfsvers);
		return 0;
	}
	if (nfsvers && !mountvers)
		mountvers = (nfsvers < 3) ? 1 : nfsvers;
	if (nfsvers && nfsvers < mountvers) {
		mountvers = nfsvers;
	}

	/* Adjust options if none specified */
	if (!data.timeo)
		data.timeo = tcp ? 70 : 7;

#ifdef NFS_MOUNT_DEBUG
	printf("rsize = %d, wsize = %d, timeo = %d, retrans = %d\n",
		data.rsize, data.wsize, data.timeo, data.retrans);
	printf("acreg (min, max) = (%d, %d), acdir (min, max) = (%d, %d)\n",
		data.acregmin, data.acregmax, data.acdirmin, data.acdirmax);
	printf("port = %d, bg = %d, retry = %d, flags = %.8x\n",
		port, bg, retry, data.flags);
	printf("mountprog = %d, mountvers = %d, nfsprog = %d, nfsvers = %d\n",
		mountprog, mountvers, nfsprog, nfsvers);
	printf("soft = %d, intr = %d, posix = %d, nocto = %d, noac = %d\n",
		(data.flags & NFS_MOUNT_SOFT) != 0,
		(data.flags & NFS_MOUNT_INTR) != 0,
		(data.flags & NFS_MOUNT_POSIX) != 0,
		(data.flags & NFS_MOUNT_NOCTO) != 0,
		(data.flags & NFS_MOUNT_NOAC) != 0);
#if NFS_MOUNT_VERSION >= 2
	printf("tcp = %d\n",
		(data.flags & NFS_MOUNT_TCP) != 0);
#endif
#endif

	data.version = nfs_mount_version;
	*mount_opts = (char *) &data;

	if (*flags & MS_REMOUNT)
		return 0;

	/*
	 * If the previous mount operation on the same host was
	 * backgrounded, and the "bg" for this mount is also set,
	 * give up immediately, to avoid the initial timeout.
	 */
	if (bg && !running_bg &&
	    prev_bg_host && strcmp(hostname, prev_bg_host) == 0) {
		if (retry > 0)
			retval = EX_BG;
		return retval;
	}

	/* create mount deamon client */
	/* See if the nfs host = mount host. */
	if (mounthost) {
	  if (mounthost[0] >= '0' && mounthost[0] <= '9') {
	    mount_server_addr.sin_family = AF_INET;
	    mount_server_addr.sin_addr.s_addr = inet_addr(hostname);
	  } else {
		  if ((hp = gethostbyname(mounthost)) == NULL) {
			  bb_herror_msg("%s", mounthost);
			  goto fail;
		  } else {
			  if (hp->h_length > sizeof(struct in_addr)) {
				  bb_error_msg("got bad hp->h_length?");
				  hp->h_length = sizeof(struct in_addr);
			  }
			  mount_server_addr.sin_family = AF_INET;
			  memcpy(&mount_server_addr.sin_addr,
				 hp->h_addr, hp->h_length);
		  }
	  }
	}

	/*
	 * The following loop implements the mount retries. On the first
	 * call, "running_bg" is 0. When the mount times out, and the
	 * "bg" option is set, the exit status EX_BG will be returned.
	 * For a backgrounded mount, there will be a second call by the
	 * child process with "running_bg" set to 1.
	 *
	 * The case where the mount point is not present and the "bg"
	 * option is set, is treated as a timeout. This is done to
	 * support nested mounts.
	 *
	 * The "retry" count specified by the user is the number of
	 * minutes to retry before giving up.
	 *
	 * Only the first error message will be displayed.
	 */
	retry_timeout.tv_sec = 3;
	retry_timeout.tv_usec = 0;
	total_timeout.tv_sec = 20;
	total_timeout.tv_usec = 0;
	timeout = time(NULL) + 60 * retry;
	prevt = 0;
	t = 30;
	val = 1;
	for (;;) {
		if (bg && stat(node, &statbuf) == -1) {
			if (running_bg) {
				sleep(val);	/* 1, 2, 4, 8, 16, 30, ... */
				val *= 2;
				if (val > 30)
					val = 30;
			}
		} else {
			/* be careful not to use too many CPU cycles */
			if (t - prevt < 30)
				sleep(30);

			pm_mnt = get_mountport(&mount_server_addr,
				       mountprog,
				       mountvers,
				       proto,
 				       mountport);

			/* contact the mount daemon via TCP */
			mount_server_addr.sin_port = htons(pm_mnt->pm_port);
			msock = RPC_ANYSOCK;

			switch (pm_mnt->pm_prot) {
			case IPPROTO_UDP:
				mclient = clntudp_create(&mount_server_addr,
						 pm_mnt->pm_prog,
						 pm_mnt->pm_vers,
						 retry_timeout,
						 &msock);
		  if (mclient)
			  break;
		  mount_server_addr.sin_port = htons(pm_mnt->pm_port);
		  msock = RPC_ANYSOCK;
		case IPPROTO_TCP:
			mclient = clnttcp_create(&mount_server_addr,
						 pm_mnt->pm_prog,
						 pm_mnt->pm_vers,
						 &msock, 0, 0);
			break;
		default:
			mclient = 0;
			}
			if (mclient) {
				/* try to mount hostname:pathname */
				mclient->cl_auth = authunix_create_default();

			/* make pointers in xdr_mountres3 NULL so
			 * that xdr_array allocates memory for us
			 */
			memset(&status, 0, sizeof(status));

			if (pm_mnt->pm_vers == 3)
				clnt_stat = clnt_call(mclient, MOUNTPROC3_MNT,
						      (xdrproc_t) xdr_dirpath,
						      (caddr_t) &pathname,
						      (xdrproc_t) xdr_mountres3,
						      (caddr_t) &status,
					total_timeout);
			else
				clnt_stat = clnt_call(mclient, MOUNTPROC_MNT,
						      (xdrproc_t) xdr_dirpath,
						      (caddr_t) &pathname,
						      (xdrproc_t) xdr_fhstatus,
						      (caddr_t) &status,
						      total_timeout);

				if (clnt_stat == RPC_SUCCESS)
					break;		/* we're done */
				if (errno != ECONNREFUSED) {
					clnt_perror(mclient, "mount");
					goto fail;	/* don't retry */
				}
				if (!running_bg && prevt == 0)
					clnt_perror(mclient, "mount");
				auth_destroy(mclient->cl_auth);
				clnt_destroy(mclient);
				mclient = 0;
				close(msock);
			} else {
				if (!running_bg && prevt == 0)
					clnt_pcreateerror("mount");
			}
			prevt = t;
		}
		if (!bg)
		        goto fail;
		if (!running_bg) {
			prev_bg_host = bb_xstrdup(hostname);
			if (retry > 0)
				retval = EX_BG;
			goto fail;
		}
		t = time(NULL);
		if (t >= timeout)
			goto fail;
	}
	nfsvers = (pm_mnt->pm_vers < 2) ? 2 : pm_mnt->pm_vers;

	if (nfsvers == 2) {
		if (status.nfsv2.fhs_status != 0) {
			bb_error_msg("%s:%s failed, reason given by server: %s",
				hostname, pathname,
				nfs_strerror(status.nfsv2.fhs_status));
			goto fail;
		}
		memcpy(data.root.data,
		       (char *) status.nfsv2.fhstatus_u.fhs_fhandle,
		       NFS_FHSIZE);
#if NFS_MOUNT_VERSION >= 4
		data.root.size = NFS_FHSIZE;
		memcpy(data.old_root.data,
		       (char *) status.nfsv2.fhstatus_u.fhs_fhandle,
		       NFS_FHSIZE);
#endif
	} else {
#if NFS_MOUNT_VERSION >= 4
		fhandle3 *my_fhandle;
		if (status.nfsv3.fhs_status != 0) {
			bb_error_msg("%s:%s failed, reason given by server: %s",
				hostname, pathname,
				nfs_strerror(status.nfsv3.fhs_status));
			goto fail;
		}
		my_fhandle = &status.nfsv3.mountres3_u.mountinfo.fhandle;
		memset(data.old_root.data, 0, NFS_FHSIZE);
		memset(&data.root, 0, sizeof(data.root));
		data.root.size = my_fhandle->fhandle3_len;
		memcpy(data.root.data,
		       (char *) my_fhandle->fhandle3_val,
		       my_fhandle->fhandle3_len);

		data.flags |= NFS_MOUNT_VER3;
#endif
	}

	/* create nfs socket for kernel */

	if (tcp) {
		if (nfs_mount_version < 3) {
	     		printf(_("NFS over TCP is not supported.\n"));
			goto fail;
		}
		fsock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	} else
		fsock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
	if (fsock < 0) {
		perror(_("nfs socket"));
		goto fail;
	}
	if (bindresvport(fsock, 0) < 0) {
		perror(_("nfs bindresvport"));
		goto fail;
	}
	if (port == 0) {
		server_addr.sin_port = PMAPPORT;
		port = pmap_getport(&server_addr, nfsprog, nfsvers,
			tcp ? IPPROTO_TCP : IPPROTO_UDP);
		if (port == 0)
			port = NFS_PORT;
#ifdef NFS_MOUNT_DEBUG
		else
			printf(_("used portmapper to find NFS port\n"));
#endif
	}
#ifdef NFS_MOUNT_DEBUG
	printf(_("using port %d for nfs deamon\n"), port);
#endif
	server_addr.sin_port = htons(port);
	 /*
	  * connect() the socket for kernels 1.3.10 and below only,
	  * to avoid problems with multihomed hosts.
	  * --Swen
	  */
	if (get_kernel_revision() <= 66314
	    && connect(fsock, (struct sockaddr *) &server_addr,
		       sizeof (server_addr)) < 0) {
		perror(_("nfs connect"));
		goto fail;
	}

	/* prepare data structure for kernel */

	data.fd = fsock;
	memcpy((char *) &data.addr, (char *) &server_addr, sizeof(data.addr));
	strncpy(data.hostname, hostname, sizeof(data.hostname));

	/* clean up */

	auth_destroy(mclient->cl_auth);
	clnt_destroy(mclient);
	close(msock);
	return 0;

	/* abort */

fail:
	if (msock != -1) {
		if (mclient) {
			auth_destroy(mclient->cl_auth);
			clnt_destroy(mclient);
		}
		close(msock);
	}
	if (fsock != -1)
		close(fsock);
	return retval;
}	
Beispiel #29
0
/* returns an initialised client, or NULL on error */
CLIENT *create_rpc_client(struct sockaddr_in *client_sock, struct addrinfo *hints, unsigned long prognum, unsigned long version, struct timeval timeout, struct sockaddr_in src_ip) {
    CLIENT *client = NULL;
    int sock;
    long unsigned protocol; /* for portmapper */
    char src[INET_ADDRSTRLEN];
    char dst[INET_ADDRSTRLEN];
    struct sockaddr_in getaddr; /* for getsockname */
    socklen_t len = sizeof(getaddr);

    /* Even if you specify a source address the portmapper will use the default one */
    /* this applies to pmap_getport or clnt*_create */
    /* so use our own get_rpc_port */

    /* check if we need to use the portmapper, 0 = yes */
    if (client_sock->sin_port == 0) {
        client_sock->sin_port = htons(PMAPPORT); /* 111 */

        sock = socket(AF_INET, hints->ai_socktype, 0);
        if (sock < 0) {
            perror("create_rpc_client(socket)");
            return NULL;
        }

        /* set the source address if specified */
        if (src_ip.sin_addr.s_addr) {
            /* portmapper doesn't need a reserved port */
            src_ip.sin_port = 0;

            if (bind(sock, (struct sockaddr *) &src_ip, sizeof(src_ip)) == -1) {
                perror("create_rpc_client(bind)");
                return NULL;
            }
        }

        if (connect(sock, (struct sockaddr *)client_sock, sizeof(struct sockaddr)) == 0) {
            /* TCP */
            if (hints->ai_socktype == SOCK_STREAM) {
                protocol = PMAP_IPPROTO_TCP;
                    client = clnttcp_create(client_sock, PMAPPROG, PMAPVERS, &sock, 0, 0);
                    if (client == NULL) {
                        clnt_pcreateerror("clnttcp_create");
                    }
            /* UDP */
            } else {
                protocol = PMAP_IPPROTO_UDP;
                client = clntudp_create(client_sock, PMAPPROG, PMAPVERS, timeout, &sock);
                if (client == NULL) {
                    clnt_pcreateerror("clntudp_create");
                }
            }
        } else {
            perror("create_rpc_client(connect)");
            return NULL;
        }

        if (verbose) {
            if (getsockname(sock, (struct sockaddr *)&getaddr, &len) == -1) {
                perror("create_rpc_client(getsockname)");
                /* this is just verbose output so don't return an error */
            } else {
                inet_ntop(AF_INET, (struct sockaddr_in *)&getaddr.sin_addr, src, INET_ADDRSTRLEN);
                //inet_ntop(AF_INET, &(((struct sockaddr_in *)&client_sock)->sin_addr), dst, INET_ADDRSTRLEN);
                inet_ntop(AF_INET, &(client_sock->sin_addr), dst, INET_ADDRSTRLEN);
                debug("portmap request = %s:%u -> %s:%u\n", src, ntohs(getaddr.sin_port), dst, ntohs(client_sock->sin_port));
            }
        }

        /* query the portmapper */
        client_sock->sin_port = get_rpc_port(client, prognum, version, protocol);

        /* close the portmapper connection */
        client = destroy_rpc_client(client);

        /* by this point we should know which port we're talking to */
        debug("portmapper = %s:%u\n", dst, ntohs(client_sock->sin_port));
    }

    /* now make the client connection */

    /* by now we should have a port defined unless the program isn't registered */
    if (client_sock->sin_port) {
        /* Make sure and make new sockets for each new connection */
        /* clnttcp_create will happily reuse open sockets */
        sock = socket(AF_INET, hints->ai_socktype, 0);
        if (sock < 0) {
            perror("create_rpc_client(socket)");
            return NULL;
        }

        /* always try and bind to a low port first */
        /* could check for root here but there are other mechanisms for allowing processes to bind to low ports */
        if (bindresvport(sock, &src_ip) == -1) {
            /* permission denied, ie we aren't root */
            if (errno == EACCES) {
                /* try an ephemeral port */
                src_ip.sin_port = htons(0);
            } else {
                perror("create_rpc_client(bindresvport)");
                return NULL;
            }
        }

        /* now we're bound to a local socket, try and connect to the server */
        if (connect(sock, (struct sockaddr *)client_sock, sizeof(struct sockaddr)) == 0) {
            /* TCP */
            if (hints->ai_socktype == SOCK_STREAM) {
                    /* TODO set recvsz and sendsz to the NFS blocksize */
                    client = clnttcp_create(client_sock, prognum, version, &sock, 0, 0);
                    if (client == NULL) {
                        clnt_pcreateerror("clnttcp_create");
                    }
            /* UDP */
            } else {
                client = clntudp_create(client_sock, prognum, version, timeout, &sock);
                if (client == NULL) {
                    clnt_pcreateerror("clntudp_create");
                }
            }
        } else {
            perror("create_rpc_client(connect)");
            return NULL;
        }

        if (verbose) {
            if (getsockname(sock, (struct sockaddr *)&getaddr, &len) == -1) {
                perror("create_rpc_client(getsockname)");
                /* this is just verbose output so don't return an error */
            } else {
                inet_ntop(AF_INET, (struct sockaddr_in *)&getaddr.sin_addr, src, INET_ADDRSTRLEN);
                inet_ntop(AF_INET, &(client_sock->sin_addr), dst, INET_ADDRSTRLEN);
                debug("Connected = %s:%u -> %s:%u\n", src, ntohs(getaddr.sin_port), dst, ntohs(client_sock->sin_port));
            }
        }
    }

    if (client) {
        /* TODO check return values */
        /* use AUTH_NONE authentication by default */
        client->cl_auth = authnone_create();
        /* set the RPC timeout */
        clnt_control(client, CLSET_TIMEOUT, (char *)&timeout);
        /* set the socket to close when the client is destroyed */
        clnt_control(client, CLSET_FD_CLOSE, NULL);
    }

    return client;
}
Beispiel #30
0
SVCXPRT *Svcudp_bufcreate(register int sock, u_int sendsz, u_int recvsz)
{
  bool_t madesock = FALSE;
  register SVCXPRT *xprt;
  register struct Svcudp_data *su;
  struct sockaddr_in addr;
  unsigned long len = sizeof(struct sockaddr_in);

  if(sock == RPC_ANYSOCK)
    {
      if((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
        {
          perror("Svcudp_create: socket creation problem");
          return ((SVCXPRT *) NULL);
        }
      madesock = TRUE;
    }

  memset(&addr, 0, sizeof(addr));
  addr.sin_family = AF_INET;
  if(bindresvport(sock, &addr))
    {
      addr.sin_port = 0;
      (void)bind(sock, (struct sockaddr *)&addr, len);
    }

  if(getsockname(sock, (struct sockaddr *)&addr, (socklen_t *) & len) != 0)
    {
      perror("Svcudp_create - cannot getsockname");
      if(madesock)
        (void)close(sock);
      return ((SVCXPRT *) NULL);
    }

  xprt = (SVCXPRT *) Mem_Alloc(sizeof(SVCXPRT));
  if(xprt == NULL)
    {
      return (NULL);
    }

  su = (struct Svcudp_data *)Mem_Alloc(sizeof(*su));

  if(su == NULL)
    {
      return (NULL);
    }
  su->su_iosz = ((MAX(sendsz, recvsz) + 3) / 4) * 4;
  if((rpc_buffer(xprt) = Mem_Alloc(su->su_iosz)) == NULL)
    {
      return (NULL);
    }

  xdrmem_create(&(su->su_xdrs), rpc_buffer(xprt), su->su_iosz, XDR_DECODE);
  xprt->xp_p2 = (caddr_t) su;
  xprt->xp_verf.oa_base = su->su_verfbody;
  xprt->xp_ops = &Svcudp_op;
  xprt->xp_port = ntohs(addr.sin_port);
#ifdef _FREEBSD
  xprt->xp_fd = sock;
#else
  xprt->xp_sock = sock;
#endif

  Xprt_register(xprt);

  return (xprt);
}