(root)/
glibc-2.38/
inet/
rexec.c
       1  /*
       2   * Copyright (c) 1980, 1993
       3   *	The Regents of the University of California.  All rights reserved.
       4   *
       5   * Redistribution and use in source and binary forms, with or without
       6   * modification, are permitted provided that the following conditions
       7   * are met:
       8   * 1. Redistributions of source code must retain the above copyright
       9   *    notice, this list of conditions and the following disclaimer.
      10   * 2. Redistributions in binary form must reproduce the above copyright
      11   *    notice, this list of conditions and the following disclaimer in the
      12   *    documentation and/or other materials provided with the distribution.
      13   * 4. Neither the name of the University nor the names of its contributors
      14   *    may be used to endorse or promote products derived from this software
      15   *    without specific prior written permission.
      16   *
      17   * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
      18   * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
      19   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
      20   * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
      21   * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
      22   * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
      23   * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
      24   * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
      25   * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
      26   * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
      27   * SUCH DAMAGE.
      28   */
      29  
      30  #include <sys/types.h>
      31  #include <sys/socket.h>
      32  
      33  #include <netinet/in.h>
      34  
      35  #include <alloca.h>
      36  #include <stdio.h>
      37  #include <netdb.h>
      38  #include <errno.h>
      39  #include <stdlib.h>
      40  #include <string.h>
      41  #include <unistd.h>
      42  #include <sys/uio.h>
      43  #include <set-freeres.h>
      44  
      45  int	rexecoptions;
      46  static char *ahostbuf;
      47  
      48  int
      49  rexec_af (char **ahost, int rport, const char *name, const char *pass,
      50  	  const char *cmd, int *fd2p, sa_family_t af)
      51  {
      52  	struct sockaddr_storage from;
      53  	struct addrinfo hints, *res0;
      54  	const char *orig_name = name;
      55  	const char *orig_pass = pass;
      56  	u_short port = 0;
      57  	int s, timo = 1, s3;
      58  	char c;
      59  	int gai;
      60  	char servbuff[NI_MAXSERV];
      61  
      62  	__snprintf(servbuff, sizeof(servbuff), "%d", ntohs(rport));
      63  	servbuff[sizeof(servbuff) - 1] = '\0';
      64  
      65  	memset(&hints, '\0', sizeof(hints));
      66  	hints.ai_family = af;
      67  	hints.ai_socktype = SOCK_STREAM;
      68  	hints.ai_flags = AI_CANONNAME;
      69  	gai = getaddrinfo(*ahost, servbuff, &hints, &res0);
      70  	if (gai){
      71  		/* XXX: set errno? */
      72  		return -1;
      73  	}
      74  
      75  	if (res0->ai_canonname){
      76  		free (ahostbuf);
      77  		ahostbuf = __strdup (res0->ai_canonname);
      78  		if (ahostbuf == NULL) {
      79  			perror ("rexec: strdup");
      80  			goto bad2;
      81  		}
      82  		*ahost = ahostbuf;
      83  	} else {
      84  		*ahost = NULL;
      85  		__set_errno (ENOENT);
      86  		goto bad2;
      87  	}
      88  	ruserpass(res0->ai_canonname, &name, &pass);
      89  retry:
      90  	/* NB: No SOCK_CLOEXEC for backwards compatibility.  */
      91  	s = __socket(res0->ai_family, res0->ai_socktype, 0);
      92  	if (s < 0) {
      93  		perror("rexec: socket");
      94  		goto bad2;
      95  	}
      96  	if (__connect(s, res0->ai_addr, res0->ai_addrlen) < 0) {
      97  		if (errno == ECONNREFUSED && timo <= 16) {
      98  			(void) __close(s);
      99  			__sleep(timo);
     100  			timo *= 2;
     101  			goto retry;
     102  		}
     103  		perror(res0->ai_canonname);
     104  		goto bad;
     105  	}
     106  	if (fd2p == 0) {
     107  		(void) __write(s, "", 1);
     108  		port = 0;
     109  	} else {
     110  		char num[32];
     111  		int s2;
     112  		union
     113  		{
     114  		  struct sockaddr_storage ss;
     115  		  struct sockaddr sa;
     116  		} sa2;
     117  		socklen_t sa2len;
     118  
     119  		s2 = __socket(res0->ai_family, res0->ai_socktype, 0);
     120  		if (s2 < 0)
     121  			goto bad;
     122  
     123  		__listen(s2, 1);
     124  		sa2len = sizeof (sa2);
     125  		if (__getsockname(s2, &sa2.sa, &sa2len) < 0) {
     126  			perror("getsockname");
     127  			(void) __close(s2);
     128  			goto bad;
     129  		} else if (sa2len != SA_LEN(&sa2.sa)) {
     130  			__set_errno(EINVAL);
     131  			(void) __close(s2);
     132  			goto bad;
     133  		}
     134  		port = 0;
     135  		if (!getnameinfo(&sa2.sa, sa2len,
     136  				 NULL, 0, servbuff, sizeof(servbuff),
     137  				 NI_NUMERICSERV))
     138  			port = strtol(servbuff, NULL, 10);
     139  		(void) sprintf(num, "%u", port);
     140  		(void) __write(s, num, strlen(num)+1);
     141  		{ socklen_t len = sizeof (from);
     142  		  s3 = TEMP_FAILURE_RETRY (accept(s2, (struct sockaddr *)&from,
     143  						  &len));
     144  		  __close(s2);
     145  		  if (s3 < 0) {
     146  			perror("accept");
     147  			port = 0;
     148  			goto bad;
     149  		  }
     150  		}
     151  		*fd2p = s3;
     152  	}
     153  
     154  	struct iovec iov[3] =
     155  	  {
     156  	    [0] = { .iov_base = (void *) name, .iov_len = strlen (name) + 1 },
     157  	    /* should public key encrypt the password here */
     158  	    [1] = { .iov_base = (void *) pass, .iov_len = strlen (pass) + 1 },
     159  	    [2] = { .iov_base = (void *) cmd, .iov_len = strlen (cmd) + 1 }
     160  	  };
     161  	(void) TEMP_FAILURE_RETRY (__writev (s, iov, 3));
     162  
     163  	/* We don't need the memory allocated for the name and the password
     164  	   in ruserpass anymore.  */
     165  	if (name != orig_name)
     166  	  free ((char *) name);
     167  	if (pass != orig_pass)
     168  	  free ((char *) pass);
     169  
     170  	if (__read(s, &c, 1) != 1) {
     171  		perror(*ahost);
     172  		goto bad;
     173  	}
     174  	if (c != 0) {
     175  		while (__read(s, &c, 1) == 1) {
     176  			(void) __write(2, &c, 1);
     177  			if (c == '\n')
     178  				break;
     179  		}
     180  		goto bad;
     181  	}
     182  	freeaddrinfo(res0);
     183  	return (s);
     184  bad:
     185  	if (port)
     186  		(void) __close(*fd2p);
     187  	(void) __close(s);
     188  bad2:
     189  	freeaddrinfo(res0);
     190  	return (-1);
     191  }
     192  libc_hidden_def (rexec_af)
     193  
     194  int
     195  rexec (char **ahost, int rport, const char *name, const char *pass,
     196         const char *cmd, int *fd2p)
     197  {
     198  	return rexec_af(ahost, rport, name, pass, cmd, fd2p, AF_INET);
     199  }
     200  
     201  weak_alias (ahostbuf, __libc_rexec_freemem_ptr)