コード例 #1
0
ファイル: sockaddr-util.c プロジェクト: B-Rich/amanda
int
str_to_sockaddr(
	const char *src,
	sockaddr_union *dst)
{
    int result;

    g_debug("parsing %s", src);
    /* try AF_INET first */
    SU_INIT(dst, AF_INET);
    if ((result = inet_pton(AF_INET, src, &dst->sin.sin_addr)) == 1)
	return result;

    /* otherwise try AF_INET6, if supported */
#ifdef WORKING_IPV6
    SU_INIT(dst, AF_INET6);
    return inet_pton(AF_INET6, src, &dst->sin6.sin6_addr);
#else
    return result;
#endif
}
コード例 #2
0
ファイル: sockaddr-util.c プロジェクト: duckhead/amanda
static sockaddr_union *
unmap_v4mapped(
    sockaddr_union *sa,
    sockaddr_union *tmp)
{
    if (SU_GET_FAMILY(sa) == AF_INET6 && IN6_IS_ADDR_V4MAPPED(&sa->sin6.sin6_addr)) {
	SU_INIT(tmp, AF_INET);
	SU_SET_PORT(tmp, SU_GET_PORT(sa));
	/* extract the v4 address from byte 12 of the v6 address */
	memcpy(&tmp->sin.sin_addr.s_addr,
	       &sa->sin6.sin6_addr.s6_addr[12],
	       sizeof(struct in_addr));
	return tmp;
    }

    return sa;
}
コード例 #3
0
ファイル: ssh-security.c プロジェクト: fuzzynoise/amanda
/* like sec_accept, but first it gets the remote system's hostname */
static void
ssh_accept(
    const security_driver_t *driver,
    char       *(*conf_fn)(char *, void *),
    int		in,
    int		out,
    void	(*fn)(security_handle_t *, pkt_t *),
    void       *datap)
{
    struct sec_handle *rh;
    struct tcp_conn *rc = sec_tcp_conn_get(NULL, "", 0);
    char *ssh_connection, *p;
    char *errmsg = NULL;
    sockaddr_union addr;
    int result;

    /* "Accepting" an SSH connection means that amandad was invoked via sshd, so
     * we should have anSSH_CONNECTION env var.  If not, then this probably isn't
     * a real SSH connection and we should bail out. */
    ssh_connection = getenv("SSH_CONNECTION");
    if (!ssh_connection) {
	errmsg = g_strdup("$SSH_CONNECTION not set - was amandad started by sshd?");
	goto error;
    }

    /* make a local copy, to munge */
    ssh_connection = g_strdup(ssh_connection);

    /* strip off the first component - the ASCII IP address */
    if ((p = strchr(ssh_connection, ' ')) == NULL) {
	errmsg = g_strdup("$SSH_CONNECTION malformed");
	goto error;
    }
    *p = '\0';

    /* ---- everything from here on is just a warning, leaving hostname at "" */

    SU_INIT(&addr, AF_INET);

    /* turn the string address into a sockaddr */
    if ((result = str_to_sockaddr(ssh_connection, &addr)) != 1) {
	if (result == 0) {
	    g_warning("Could not parse peer address %s", ssh_connection);
	} else {
	    g_warning("Parsing peer address %s: %s", ssh_connection, gai_strerror(result));
	}
	goto done;
    }

    /* find the hostname */
    result = getnameinfo((struct sockaddr *)&addr, SS_LEN(&addr),
		 rc->hostname, sizeof(rc->hostname), NULL, 0, 0);
    if (result != 0) {
	g_warning("Could not get hostname for SSH client %s: %s", ssh_connection,
		gai_strerror(result));
	goto done;
    }

    /* and verify it */
    if (check_name_give_sockaddr(rc->hostname,
				 (struct sockaddr *)&addr, &errmsg) < 0) {
	rc->hostname[0] = '\0'; /* null out the bad hostname */
	g_warning("Checking SSH client DNS: %s", errmsg);
	amfree(errmsg);
	goto done;
    }

done:
    g_free(ssh_connection);

    rc->read = in;
    rc->write = out;
    rc->accept_fn = fn;
    rc->driver = driver;
    rc->conf_fn = conf_fn;
    rc->datap = datap;
    sec_tcp_conn_read(rc);
    return;

error:
    if (ssh_connection)
	g_free(ssh_connection);

    /* make up a fake handle for the error */
    rh = g_new0(struct sec_handle, 1);
    security_handleinit(&rh->sech, driver);
    security_seterror((security_handle_t*)rh, "ssh_accept: %s", errmsg);
    amfree(errmsg);
    (*fn)(&rh->sech, NULL);
}
コード例 #4
0
ファイル: stream.c プロジェクト: B-Rich/amanda
int
stream_server(
    int family,
    in_port_t *portp,
    size_t sendsize,
    size_t recvsize,
    int    priv)
{
    int server_socket, retries;
    socklen_t_equiv len;
#if defined(SO_KEEPALIVE) || defined(USE_REUSEADDR)
    const int on = 1;
    int r;
#endif
    sockaddr_union server;
    int save_errno;
    int *portrange;
    socklen_t_equiv socklen;
    int socket_family;

    *portp = USHRT_MAX;				/* in case we error exit */
    if (family == -1) {
	socket_family = AF_NATIVE;
    } else {
	socket_family = family;
    }
    g_debug("stream_server opening socket with family %d (requested family was %d)", socket_family, family);
    server_socket = socket(socket_family, SOCK_STREAM, 0);

#ifdef WORKING_IPV6
    /* if that address family actually isn't supported, just try AF_INET */
    if (server_socket == -1 && errno == EAFNOSUPPORT) {
	g_debug("stream_server retrying socket with AF_INET");
	socket_family = AF_INET;
	server_socket = socket(AF_INET, SOCK_STREAM, 0);
    }
#endif
    if (server_socket == -1) {
	save_errno = errno;
	g_debug(_("stream_server: socket() failed: %s"),
		  strerror(save_errno));
	errno = save_errno;
	return -1;
    }
    if(server_socket < 0 || server_socket >= (int)FD_SETSIZE) {
	aclose(server_socket);
	errno = EMFILE;				/* out of range */
	save_errno = errno;
	g_debug(_("stream_server: socket out of range: %d"),
		  server_socket);
	errno = save_errno;
	return -1;
    }

    SU_INIT(&server, socket_family);
    SU_SET_INADDR_ANY(&server);

#ifdef USE_REUSEADDR
    r = setsockopt(server_socket, SOL_SOCKET, SO_REUSEADDR,
	(void *)&on, (socklen_t_equiv)sizeof(on));
    if (r < 0) {
	g_debug(_("stream_server: setsockopt(SO_REUSEADDR) failed: %s"),
		  strerror(errno));
    }
#endif

    try_socksize(server_socket, SO_SNDBUF, sendsize);
    try_socksize(server_socket, SO_RCVBUF, recvsize);

    /*
     * If a port range was specified, we try to get a port in that
     * range first.  Next, we try to get a reserved port.  If that
     * fails, we just go for any port.
     * 
     * In all cases, not to use port that's assigned to other services. 
     *
     * It is up to the caller to make sure we have the proper permissions
     * to get the desired port, and to make sure we return a port that
     * is within the range it requires.
     */
    for (retries = 0; ; retries++) {
	if (priv) {
	    portrange = getconf_intrange(CNF_RESERVED_TCP_PORT);
	} else {
	    portrange = getconf_intrange(CNF_UNRESERVED_TCP_PORT);
	}

	if (portrange[0] != 0 && portrange[1] != 0) {
	    if (bind_portrange(server_socket, &server, (in_port_t)portrange[0],
			       (in_port_t)portrange[1], "tcp") == 0)
		goto out;
	    g_debug(_("stream_server: Could not bind to port in range: %d - %d."),
		      portrange[0], portrange[1]);
	} else {
	    socklen = SS_LEN(&server);
	    if (bind(server_socket, (struct sockaddr *)&server, socklen) == 0)
		goto out;
	    g_debug(_("stream_server: Could not bind to any port: %s"),
		      strerror(errno));
	}

	if (retries >= BIND_CYCLE_RETRIES)
	    break;

	g_debug(_("stream_server: Retrying entire range after 10 second delay."));

	sleep(15);
    }

    save_errno = errno;
    g_debug(_("stream_server: bind(in6addr_any) failed: %s"),
		  strerror(save_errno));
    aclose(server_socket);
    errno = save_errno;
    return -1;

out:
    listen(server_socket, 1);

    /* find out what port was actually used */

    len = sizeof(server);
    if(getsockname(server_socket, (struct sockaddr *)&server, &len) == -1) {
	save_errno = errno;
	g_debug(_("stream_server: getsockname() failed: %s"),
		  strerror(save_errno));
	aclose(server_socket);
	errno = save_errno;
	return -1;
    }

#ifdef SO_KEEPALIVE
    r = setsockopt(server_socket, SOL_SOCKET, SO_KEEPALIVE,
	(void *)&on, (socklen_t_equiv)sizeof(on));
    if(r == -1) {
	save_errno = errno;
	g_debug(_("stream_server: setsockopt(SO_KEEPALIVE) failed: %s"),
		  strerror(save_errno));
        aclose(server_socket);
	errno = save_errno;
        return -1;
    }
#endif

    *portp = SU_GET_PORT(&server);
    g_debug(_("stream_server: waiting for connection: %s"),
	      str_sockaddr(&server));
    return server_socket;
}
コード例 #5
0
ファイル: stream.c プロジェクト: B-Rich/amanda
static int
stream_client_internal(
    const char *hostname,
    in_port_t port,
    size_t sendsize,
    size_t recvsize,
    in_port_t *localport,
    int nonblock,
    int priv)
{
    sockaddr_union svaddr, claddr;
    int save_errno = 0;
    int client_socket = 0;
    int *portrange = NULL;
    int result;
    struct addrinfo *res, *res_addr;

    result = resolve_hostname(hostname, SOCK_STREAM, &res, NULL);
    if(result != 0) {
	g_debug(_("resolve_hostname(%s): %s"), hostname, gai_strerror(result));
	errno = EHOSTUNREACH;
	return -1;
    }
    if(!res) {
	g_debug(_("resolve_hostname(%s): no results"), hostname);
	errno = EHOSTUNREACH;
	return -1;
    }

    for (res_addr = res; res_addr != NULL; res_addr = res_addr->ai_next) {
	/* copy the first (preferred) address we found */
	copy_sockaddr(&svaddr, (sockaddr_union *)res_addr->ai_addr);
	SU_SET_PORT(&svaddr, port);

	SU_INIT(&claddr, SU_GET_FAMILY(&svaddr));
	SU_SET_INADDR_ANY(&claddr);

	/*
	 * If a privileged port range was requested, we try to get a port in
	 * that range first and fail if it is not available.  Next, we try
	 * to get a port in the range built in when Amanda was configured.
	 * If that fails, we just go for any port.
	 *
	 * It is up to the caller to make sure we have the proper permissions
	 * to get the desired port, and to make sure we return a port that
	 * is within the range it requires.
	 */
	if (priv) {
	    portrange = getconf_intrange(CNF_RESERVED_TCP_PORT);
	} else {
	    portrange = getconf_intrange(CNF_UNRESERVED_TCP_PORT);
	}
	client_socket = connect_portrange(&claddr, (in_port_t)portrange[0],
					  (in_port_t)portrange[1],
					  "tcp", &svaddr, nonblock);
	save_errno = errno;
	if (client_socket > 0)
	    break;
    }

    freeaddrinfo(res);
					  
    if (client_socket > 0)
	goto out;

    g_debug(_("stream_client: Could not bind to port in range %d-%d."),
	      portrange[0], portrange[1]);

    errno = save_errno;
    return -1;

out:
    try_socksize(client_socket, SO_SNDBUF, sendsize);
    try_socksize(client_socket, SO_RCVBUF, recvsize);
    if (localport != NULL)
	*localport = SU_GET_PORT(&claddr);
    return client_socket;
}
コード例 #6
0
ファイル: dgram.c プロジェクト: Zealsathish/amanda
int
dgram_bind(
    dgram_t *	dgram,
    sa_family_t family,
    in_port_t *	portp)
{
    int s, retries;
    socklen_t_equiv len;
    sockaddr_union name;
    int save_errno;
    int *portrange;
    int sndbufsize = MAX_DGRAM;

    portrange = getconf_intrange(CNF_RESERVED_UDP_PORT);
    *portp = (in_port_t)0;
    g_debug("dgram_bind: setting up a socket with family %d", family);
    if((s = socket(family, SOCK_DGRAM, 0)) == -1) {
	save_errno = errno;
	dbprintf(_("dgram_bind: socket() failed: %s\n"),
		  strerror(save_errno));
	errno = save_errno;
	return -1;
    }
    if(s < 0 || s >= (int)FD_SETSIZE) {
	dbprintf(_("dgram_bind: socket out of range: %d\n"),
		  s);
	aclose(s);
	errno = EMFILE;				/* out of range */
	return -1;
    }

    /* try setting the buffer size (= maximum allowable UDP packet size) */
    if (setsockopt(s, SOL_SOCKET, SO_SNDBUF,
		   (void *) &sndbufsize, sizeof(sndbufsize)) < 0) {
       dbprintf("dgram_bind: could not set udp send buffer to %d: %s (ignored)\n",
		 sndbufsize, strerror(errno));
    }

    SU_INIT(&name, family);
    SU_SET_INADDR_ANY(&name);

    /*
     * If a port range was specified, we try to get a port in that
     * range first.  Next, we try to get a reserved port.  If that
     * fails, we just go for any port.
     * 
     * In all cases, not to use port that's assigned to other services. 
     *
     * It is up to the caller to make sure we have the proper permissions
     * to get the desired port, and to make sure we return a port that
     * is within the range it requires.
     */
    for (retries = 0; ; retries++) {
	if (bind_portrange(s, &name, portrange[0], portrange[1], "udp") == 0)
	    goto out;
	dbprintf(_("dgram_bind: Could not bind to port in range: %d - %d.\n"),
		  portrange[0], portrange[1]);
	if (retries >= BIND_CYCLE_RETRIES) {
	    dbprintf(_("dgram_bind: Giving up...\n"));
	    break;
	}

	dbprintf(_("dgram_bind: Retrying entire range after 10 second delay.\n"));
	sleep(15);
    }

    save_errno = errno;
    dbprintf(_("dgram_bind: bind(in6addr_any) failed: %s\n"),
		  strerror(save_errno));
    aclose(s);
    errno = save_errno;
    return -1;

out:
    /* find out what name was actually used */

    len = (socklen_t_equiv)sizeof(name);
    if(getsockname(s, (struct sockaddr *)&name, &len) == -1) {
	save_errno = errno;
	dbprintf(_("dgram_bind: getsockname() failed: %s\n"), strerror(save_errno));
	errno = save_errno;
	aclose(s);
	return -1;
    }
    *portp = SU_GET_PORT(&name);
    dgram->socket = s;

    dbprintf(_("dgram_bind: socket %d bound to %s\n"),
	      dgram->socket, str_sockaddr(&name));
    return 0;
}