File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / rsync / clientname.c
Revision 1.1.1.3 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue Nov 1 09:54:32 2016 UTC (7 years, 7 months ago) by misho
Branches: rsync, MAIN
CVS tags: v3_1_2p5, HEAD
rsync 3.1.2

    1: /*
    2:  * Functions for looking up the remote name or addr of a socket.
    3:  *
    4:  * Copyright (C) 1992-2001 Andrew Tridgell <tridge@samba.org>
    5:  * Copyright (C) 2001, 2002 Martin Pool <mbp@samba.org>
    6:  * Copyright (C) 2002-2015 Wayne Davison
    7:  *
    8:  * This program is free software; you can redistribute it and/or modify
    9:  * it under the terms of the GNU General Public License as published by
   10:  * the Free Software Foundation; either version 3 of the License, or
   11:  * (at your option) any later version.
   12:  *
   13:  * This program is distributed in the hope that it will be useful,
   14:  * but WITHOUT ANY WARRANTY; without even the implied warranty of
   15:  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   16:  * GNU General Public License for more details.
   17:  *
   18:  * You should have received a copy of the GNU General Public License along
   19:  * with this program; if not, visit the http://fsf.org website.
   20:  */
   21: 
   22: /*
   23:  * This file is now converted to use the new-style getaddrinfo()
   24:  * interface, which supports IPv6 but is also supported on recent
   25:  * IPv4-only machines.  On systems that don't have that interface, we
   26:  * emulate it using the KAME implementation.
   27:  */
   28: 
   29: #include "rsync.h"
   30: 
   31: static const char default_name[] = "UNKNOWN";
   32: extern int am_server;
   33: 
   34: 
   35: /**
   36:  * Return the IP addr of the client as a string
   37:  **/
   38: char *client_addr(int fd)
   39: {
   40: 	static char addr_buf[100];
   41: 	static int initialised;
   42: 	struct sockaddr_storage ss;
   43: 	socklen_t length = sizeof ss;
   44: 
   45: 	if (initialised)
   46: 		return addr_buf;
   47: 
   48: 	initialised = 1;
   49: 
   50: 	if (am_server) {	/* daemon over --rsh mode */
   51: 		char *env_str;
   52: 		strlcpy(addr_buf, "0.0.0.0", sizeof addr_buf);
   53: 		if ((env_str = getenv("REMOTE_HOST")) != NULL
   54: 		 || (env_str = getenv("SSH_CONNECTION")) != NULL
   55: 		 || (env_str = getenv("SSH_CLIENT")) != NULL
   56: 		 || (env_str = getenv("SSH2_CLIENT")) != NULL) {
   57: 			char *p;
   58: 			strlcpy(addr_buf, env_str, sizeof addr_buf);
   59: 			/* Truncate the value to just the IP address. */
   60: 			if ((p = strchr(addr_buf, ' ')) != NULL)
   61: 				*p = '\0';
   62: 		}
   63: 	} else {
   64: 		client_sockaddr(fd, &ss, &length);
   65: 		getnameinfo((struct sockaddr *)&ss, length,
   66: 			    addr_buf, sizeof addr_buf, NULL, 0, NI_NUMERICHOST);
   67: 	}
   68: 
   69: 	return addr_buf;
   70: }
   71: 
   72: 
   73: static int get_sockaddr_family(const struct sockaddr_storage *ss)
   74: {
   75: 	return ((struct sockaddr *) ss)->sa_family;
   76: }
   77: 
   78: 
   79: /**
   80:  * Return the DNS name of the client.
   81:  *
   82:  * The name is statically cached so that repeated lookups are quick,
   83:  * so there is a limit of one lookup per customer.
   84:  *
   85:  * If anything goes wrong, including the name->addr->name check, then
   86:  * we just use "UNKNOWN", so you can use that value in hosts allow
   87:  * lines.
   88:  *
   89:  * After translation from sockaddr to name we do a forward lookup to
   90:  * make sure nobody is spoofing PTR records.
   91:  **/
   92: char *client_name(int fd)
   93: {
   94: 	static char name_buf[100];
   95: 	static char port_buf[100];
   96: 	static int initialised;
   97: 	struct sockaddr_storage ss;
   98: 	socklen_t ss_len;
   99: 
  100: 	if (initialised)
  101: 		return name_buf;
  102: 
  103: 	strlcpy(name_buf, default_name, sizeof name_buf);
  104: 	initialised = 1;
  105: 
  106: 	memset(&ss, 0, sizeof ss);
  107: 
  108: 	if (am_server) {	/* daemon over --rsh mode */
  109: 		char *addr = client_addr(fd);
  110: 		struct addrinfo hint, *answer;
  111: 		int err;
  112: 
  113: 		if (strcmp(addr, "0.0.0.0") == 0)
  114: 			return name_buf;
  115: 
  116: 		memset(&hint, 0, sizeof hint);
  117: 
  118: #ifdef AI_NUMERICHOST
  119: 		hint.ai_flags = AI_NUMERICHOST;
  120: #endif
  121: 		hint.ai_socktype = SOCK_STREAM;
  122: 
  123: 		if ((err = getaddrinfo(addr, NULL, &hint, &answer)) != 0) {
  124: 			rprintf(FLOG, "malformed address %s: %s\n",
  125: 			        addr, gai_strerror(err));
  126: 			return name_buf;
  127: 		}
  128: 
  129: 		switch (answer->ai_family) {
  130: 		case AF_INET:
  131: 			ss_len = sizeof (struct sockaddr_in);
  132: 			memcpy(&ss, answer->ai_addr, ss_len);
  133: 			break;
  134: #ifdef INET6
  135: 		case AF_INET6:
  136: 			ss_len = sizeof (struct sockaddr_in6);
  137: 			memcpy(&ss, answer->ai_addr, ss_len);
  138: 			break;
  139: #endif
  140: 		default:
  141: 			exit_cleanup(RERR_SOCKETIO);
  142: 		}
  143: 		freeaddrinfo(answer);
  144: 	} else {
  145: 		ss_len = sizeof ss;
  146: 		client_sockaddr(fd, &ss, &ss_len);
  147: 	}
  148: 
  149: 	if (lookup_name(fd, &ss, ss_len, name_buf, sizeof name_buf,
  150: 			port_buf, sizeof port_buf) == 0)
  151: 		check_name(fd, &ss, name_buf, sizeof name_buf);
  152: 
  153: 	return name_buf;
  154: }
  155: 
  156: 
  157: 
  158: /**
  159:  * Get the sockaddr for the client.
  160:  *
  161:  * If it comes in as an ipv4 address mapped into IPv6 format then we
  162:  * convert it back to a regular IPv4.
  163:  **/
  164: void client_sockaddr(int fd,
  165: 		     struct sockaddr_storage *ss,
  166: 		     socklen_t *ss_len)
  167: {
  168: 	memset(ss, 0, sizeof *ss);
  169: 
  170: 	if (getpeername(fd, (struct sockaddr *) ss, ss_len)) {
  171: 		/* FIXME: Can we really not continue? */
  172: 		rsyserr(FLOG, errno, "getpeername on fd%d failed", fd);
  173: 		exit_cleanup(RERR_SOCKETIO);
  174: 	}
  175: 
  176: #ifdef INET6
  177: 	if (get_sockaddr_family(ss) == AF_INET6 &&
  178: 	    IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)ss)->sin6_addr)) {
  179: 		/* OK, so ss is in the IPv6 family, but it is really
  180: 		 * an IPv4 address: something like
  181: 		 * "::ffff:10.130.1.2".  If we use it as-is, then the
  182: 		 * reverse lookup might fail or perhaps something else
  183: 		 * bad might happen.  So instead we convert it to an
  184: 		 * equivalent address in the IPv4 address family.  */
  185: 		struct sockaddr_in6 sin6;
  186: 		struct sockaddr_in *sin;
  187: 
  188: 		memcpy(&sin6, ss, sizeof sin6);
  189: 		sin = (struct sockaddr_in *)ss;
  190: 		memset(sin, 0, sizeof *sin);
  191: 		sin->sin_family = AF_INET;
  192: 		*ss_len = sizeof (struct sockaddr_in);
  193: #ifdef HAVE_SOCKADDR_IN_LEN
  194: 		sin->sin_len = *ss_len;
  195: #endif
  196: 		sin->sin_port = sin6.sin6_port;
  197: 
  198: 		/* There is a macro to extract the mapped part
  199: 		 * (IN6_V4MAPPED_TO_SINADDR ?), but it does not seem
  200: 		 * to be present in the Linux headers. */
  201: 		memcpy(&sin->sin_addr, &sin6.sin6_addr.s6_addr[12],
  202: 		    sizeof sin->sin_addr);
  203: 	}
  204: #endif
  205: }
  206: 
  207: 
  208: /**
  209:  * Look up a name from @p ss into @p name_buf.
  210:  *
  211:  * @param fd file descriptor for client socket.
  212:  **/
  213: int lookup_name(int fd, const struct sockaddr_storage *ss,
  214: 		socklen_t ss_len,
  215: 		char *name_buf, size_t name_buf_size,
  216: 		char *port_buf, size_t port_buf_size)
  217: {
  218: 	int name_err;
  219: 
  220: 	/* reverse lookup */
  221: 	name_err = getnameinfo((struct sockaddr *) ss, ss_len,
  222: 			       name_buf, name_buf_size,
  223: 			       port_buf, port_buf_size,
  224: 			       NI_NAMEREQD | NI_NUMERICSERV);
  225: 	if (name_err != 0) {
  226: 		strlcpy(name_buf, default_name, name_buf_size);
  227: 		rprintf(FLOG, "name lookup failed for %s: %s\n",
  228: 			client_addr(fd), gai_strerror(name_err));
  229: 		return name_err;
  230: 	}
  231: 
  232: 	return 0;
  233: }
  234: 
  235: 
  236: 
  237: /**
  238:  * Compare an addrinfo from the resolver to a sockinfo.
  239:  *
  240:  * Like strcmp, returns 0 for identical.
  241:  **/
  242: int compare_addrinfo_sockaddr(const struct addrinfo *ai,
  243: 			      const struct sockaddr_storage *ss)
  244: {
  245: 	int ss_family = get_sockaddr_family(ss);
  246: 	const char fn[] = "compare_addrinfo_sockaddr";
  247: 
  248: 	if (ai->ai_family != ss_family) {
  249: 		rprintf(FLOG, "%s: response family %d != %d\n",
  250: 			fn, ai->ai_family, ss_family);
  251: 		return 1;
  252: 	}
  253: 
  254: 	/* The comparison method depends on the particular AF. */
  255: 	if (ss_family == AF_INET) {
  256: 		const struct sockaddr_in *sin1, *sin2;
  257: 
  258: 		sin1 = (const struct sockaddr_in *) ss;
  259: 		sin2 = (const struct sockaddr_in *) ai->ai_addr;
  260: 
  261: 		return memcmp(&sin1->sin_addr, &sin2->sin_addr,
  262: 			      sizeof sin1->sin_addr);
  263: 	}
  264: 
  265: #ifdef INET6
  266: 	if (ss_family == AF_INET6) {
  267: 		const struct sockaddr_in6 *sin1, *sin2;
  268: 
  269: 		sin1 = (const struct sockaddr_in6 *) ss;
  270: 		sin2 = (const struct sockaddr_in6 *) ai->ai_addr;
  271: 
  272: 		if (ai->ai_addrlen < sizeof (struct sockaddr_in6)) {
  273: 			rprintf(FLOG, "%s: too short sockaddr_in6; length=%d\n",
  274: 				fn, (int)ai->ai_addrlen);
  275: 			return 1;
  276: 		}
  277: 
  278: 		if (memcmp(&sin1->sin6_addr, &sin2->sin6_addr,
  279: 			   sizeof sin1->sin6_addr))
  280: 			return 1;
  281: 
  282: #ifdef HAVE_SOCKADDR_IN6_SCOPE_ID
  283: 		if (sin1->sin6_scope_id != sin2->sin6_scope_id)
  284: 			return 1;
  285: #endif
  286: 		return 0;
  287: 	}
  288: #endif /* INET6 */
  289: 
  290: 	/* don't know */
  291: 	return 1;
  292: }
  293: 
  294: 
  295: /**
  296:  * Do a forward lookup on @p name_buf and make sure it corresponds to
  297:  * @p ss -- otherwise we may be being spoofed.  If we suspect we are,
  298:  * then we don't abort the connection but just emit a warning, and
  299:  * change @p name_buf to be "UNKNOWN".
  300:  *
  301:  * We don't do anything with the service when checking the name,
  302:  * because it doesn't seem that it could be spoofed in any way, and
  303:  * getaddrinfo on random service names seems to cause problems on AIX.
  304:  **/
  305: int check_name(int fd,
  306: 	       const struct sockaddr_storage *ss,
  307: 	       char *name_buf, size_t name_buf_size)
  308: {
  309: 	struct addrinfo hints, *res, *res0;
  310: 	int error;
  311: 	int ss_family = get_sockaddr_family(ss);
  312: 
  313: 	memset(&hints, 0, sizeof hints);
  314: 	hints.ai_family = ss_family;
  315: 	hints.ai_flags = AI_CANONNAME;
  316: 	hints.ai_socktype = SOCK_STREAM;
  317: 	error = getaddrinfo(name_buf, NULL, &hints, &res0);
  318: 	if (error) {
  319: 		rprintf(FLOG, "forward name lookup for %s failed: %s\n",
  320: 			name_buf, gai_strerror(error));
  321: 		strlcpy(name_buf, default_name, name_buf_size);
  322: 		return error;
  323: 	}
  324: 
  325: 	/* Given all these results, we expect that one of them will be
  326: 	 * the same as ss.  The comparison is a bit complicated. */
  327: 	for (res = res0; res; res = res->ai_next) {
  328: 		if (!compare_addrinfo_sockaddr(res, ss))
  329: 			break;	/* OK, identical */
  330: 	}
  331: 
  332: 	if (!res0) {
  333: 		/* We hit the end of the list without finding an
  334: 		 * address that was the same as ss. */
  335: 		rprintf(FLOG, "no known address for \"%s\": "
  336: 			"spoofed address?\n", name_buf);
  337: 		strlcpy(name_buf, default_name, name_buf_size);
  338: 	} else if (res == NULL) {
  339: 		/* We hit the end of the list without finding an
  340: 		 * address that was the same as ss. */
  341: 		rprintf(FLOG, "%s is not a known address for \"%s\": "
  342: 			"spoofed address?\n", client_addr(fd), name_buf);
  343: 		strlcpy(name_buf, default_name, name_buf_size);
  344: 	}
  345: 
  346: 	freeaddrinfo(res0);
  347: 	return 0;
  348: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>