END_TEST START_TEST (inet_generate_socket_event_test) { int res; const char *name; server_rec *s; res = pr_inet_generate_socket_event(NULL, NULL, NULL, -1); fail_unless(res < 0, "Failed to handle null arguments"); fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL, strerror(errno), errno); name = "foo.bar"; res = pr_inet_generate_socket_event(name, NULL, NULL, -1); fail_unless(res < 0, "Failed to handle null server_rec"); fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL, strerror(errno), errno); s = pcalloc(p, sizeof(server_rec)); res = pr_inet_generate_socket_event(name, s, NULL, -1); fail_unless(res < 0, "Failed to handle null address"); fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL, strerror(errno), errno); }
conn_t *pr_ipbind_get_listening_conn(server_rec *server, pr_netaddr_t *addr, unsigned int port) { conn_t *l; pool *p; struct listener_rec *lr; if (listening_conn_list) { for (lr = (struct listener_rec *) listening_conn_list->xas_list; lr; lr = lr->next) { int use_elt = FALSE; pr_signals_handle(); if (addr != NULL && lr->addr != NULL) { const char *lr_ipstr = NULL; lr_ipstr = pr_netaddr_get_ipstr(lr->addr); /* Note: lr_ipstr should never be null. If it is, it means that * the lr->addr object never had its IP address resolved/stashed, * and in attempting to do, getnameinfo(3) failed for some reason. * * The IP address on which it's listening, if not available via * lr->addr, should thus be available via lr->conn->local_addr. */ if (lr_ipstr == NULL && lr->conn != NULL) { lr_ipstr = pr_netaddr_get_ipstr(lr->conn->local_addr); } if (lr_ipstr != NULL) { if (strcmp(pr_netaddr_get_ipstr(addr), lr_ipstr) == 0 && port == lr->port) { use_elt = TRUE; } } } else if (addr == NULL && port == lr->port) { use_elt = TRUE; } if (use_elt) { lr->claimed = TRUE; return lr->conn; } } } if (listening_conn_pool == NULL) { listening_conn_pool = make_sub_pool(permanent_pool); pr_pool_tag(listening_conn_pool, "Listening Connection Pool"); listening_conn_list = xaset_create(listening_conn_pool, NULL); } p = make_sub_pool(listening_conn_pool); pr_pool_tag(p, "Listening conn subpool"); l = pr_inet_create_conn(p, -1, addr, port, FALSE); if (l == NULL) { return NULL; } /* Inform any interested listeners that this socket was opened. */ pr_inet_generate_socket_event("core.ctrl-listen", server, l->local_addr, l->listen_fd); lr = pcalloc(p, sizeof(struct listener_rec)); lr->pool = p; lr->conn = l; lr->addr = pr_netaddr_dup(p, addr); if (lr->addr == NULL && errno != EINVAL) { return NULL; } lr->port = port; lr->claimed = TRUE; xaset_insert(listening_conn_list, (xasetmember_t *) lr); return l; }
static int init_inetd_bindings(void) { int res = 0; server_rec *serv = NULL; unsigned char *default_server = NULL, is_default = FALSE; /* We explicitly do NOT use the get_listening_conn() function here, since * inetd-run daemons will not a) handle restarts, and thus b) will not have * already-open connections to choose from. */ main_server->listen = pr_inet_create_conn(main_server->pool, STDIN_FILENO, NULL, INPORT_ANY, FALSE); if (main_server->listen == NULL) { return -1; } /* Note: Since we are being called via inetd/xinetd, any socket options * which may be attempted by listeners for this event may not work. */ pr_inet_generate_socket_event("core.ctrl-listen", main_server, main_server->addr, main_server->listen->listen_fd); /* Fill in all the important connection information. */ if (pr_inet_get_conn_info(main_server->listen, STDIN_FILENO) == -1) { int xerrno = errno; pr_log_pri(PR_LOG_WARNING, "fatal: unable to get connection info: %s", strerror(xerrno)); if (xerrno == ENOTSOCK) { pr_log_pri(PR_LOG_ERR, "(Running from command line? " "Use `ServerType standalone' in config file!)"); } exit(1); } default_server = get_param_ptr(main_server->conf, "DefaultServer", FALSE); if (default_server != NULL && *default_server == TRUE) { is_default = TRUE; } PR_CREATE_IPBIND(main_server, main_server->addr, main_server->ServerPort); PR_OPEN_IPBIND(main_server->addr, main_server->ServerPort, main_server->listen, is_default, TRUE, TRUE); PR_ADD_IPBINDS(main_server); /* Now attach the faked connection to all virtual servers. */ for (serv = main_server->next; serv; serv = serv->next) { /* Because this server is sharing the connection with the * main server, we need a cleanup handler to remove * the server's reference when the original connection's * pool is destroyed. */ serv->listen = main_server->listen; register_cleanup(serv->listen->pool, &serv->listen, server_cleanup_cb, server_cleanup_cb); is_default = FALSE; default_server = get_param_ptr(serv->conf, "DefaultServer", FALSE); if (default_server != NULL && *default_server == TRUE) { is_default = TRUE; } PR_CREATE_IPBIND(serv, serv->addr, serv->ServerPort); PR_OPEN_IPBIND(serv->addr, serv->ServerPort, serv->listen, is_default, FALSE, TRUE); PR_ADD_IPBINDS(serv); } return 0; }
static int data_active_open(char *reason, off_t size) { conn_t *c; int rev; pr_netaddr_t *bind_addr; if (!reason && session.xfer.filename) reason = session.xfer.filename; if (pr_netaddr_get_family(session.c->local_addr) == pr_netaddr_get_family(session.c->remote_addr)) { bind_addr = session.c->local_addr; } else { /* In this scenario, the server has an IPv6 socket, but the remote client * is an IPv4 (or IPv4-mapped IPv6) peer. */ bind_addr = pr_netaddr_v6tov4(session.xfer.p, session.c->local_addr); } session.d = pr_inet_create_conn(session.pool, -1, bind_addr, session.c->local_port-1, TRUE); /* Set the "stalled" timer, if any, to prevent the connection * open from taking too long */ if (timeout_stalled) { pr_timer_add(timeout_stalled, PR_TIMER_STALLED, NULL, stalled_timeout_cb, "TimeoutStalled"); } rev = pr_netaddr_set_reverse_dns(ServerUseReverseDNS); /* Protocol and socket options should be set before handshaking. */ if (session.xfer.direction == PR_NETIO_IO_RD) { pr_inet_set_socket_opts(session.d->pool, session.d, (main_server->tcp_rcvbuf_override ? main_server->tcp_rcvbuf_len : 0), 0); } else { pr_inet_set_socket_opts(session.d->pool, session.d, 0, (main_server->tcp_sndbuf_override ? main_server->tcp_sndbuf_len : 0)); } /* Make sure that the necessary socket options are set on the socket prior * to the call to connect(2). */ pr_inet_set_proto_opts(session.pool, session.d, main_server->tcp_mss_len, 0, IPTOS_THROUGHPUT, 1); pr_inet_generate_socket_event("core.data-connect", main_server, session.d->local_addr, session.d->listen_fd); if (pr_inet_connect(session.d->pool, session.d, &session.data_addr, session.data_port) == -1) { pr_response_add_err(R_425, _("Unable to build data connection: %s"), strerror(session.d->xerrno)); destroy_pool(session.d->pool); session.d = NULL; return -1; } c = pr_inet_openrw(session.pool, session.d, NULL, PR_NETIO_STRM_DATA, session.d->listen_fd, -1, -1, TRUE); pr_netaddr_set_reverse_dns(rev); if (c) { pr_log_debug(DEBUG4, "active data connection opened - local : %s:%d", pr_netaddr_get_ipstr(session.d->local_addr), session.d->local_port); pr_log_debug(DEBUG4, "active data connection opened - remote : %s:%d", pr_netaddr_get_ipstr(session.d->remote_addr), session.d->remote_port); if (session.xfer.xfer_type != STOR_UNIQUE) { if (size) pr_response_send(R_150, _("Opening %s mode data connection for %s " "(%" PR_LU " bytes)"), MODE_STRING, reason, (pr_off_t) size); else pr_response_send(R_150, _("Opening %s mode data connection for %s"), MODE_STRING, reason); } else { /* Format of 150 responses for STOU is explicitly dictated by * RFC 1123: * * 4.1.2.9 STOU Command: RFC-959 Section 4.1.3 * * The STOU command stores into a uniquely named file. When it * receives an STOU command, a Server-FTP MUST return the * actual file name in the "125 Transfer Starting" or the "150 * Opening Data Connection" message that precedes the transfer * (the 250 reply code mentioned in RFC-959 is incorrect). The * exact format of these messages is hereby defined to be as * follows: * * 125 FILE: pppp * 150 FILE: pppp * * where pppp represents the unique pathname of the file that * will be written. */ pr_response_send(R_150, "FILE: %s", reason); } pr_inet_close(session.pool, session.d); pr_inet_set_nonblock(session.pool, session.d); session.d = c; return 0; } pr_response_add_err(R_425, _("Unable to build data connection: %s"), strerror(session.d->xerrno)); destroy_pool(session.d->pool); session.d = NULL; return -1; }
static int data_active_open(char *reason, off_t size) { conn_t *c; int bind_port, rev; pr_netaddr_t *bind_addr; unsigned char *root_revoke = NULL; if (!reason && session.xfer.filename) reason = session.xfer.filename; if (pr_netaddr_get_family(session.c->local_addr) == pr_netaddr_get_family(session.c->remote_addr)) { bind_addr = session.c->local_addr; } else { /* In this scenario, the server has an IPv6 socket, but the remote client * is an IPv4 (or IPv4-mapped IPv6) peer. */ bind_addr = pr_netaddr_v6tov4(session.xfer.p, session.c->local_addr); } /* Default source port to which to bind for the active transfer, as * per RFC959. */ bind_port = session.c->local_port-1; /* A RootRevoke value of 0 indicates 'false', 1 indicates 'true', and * 2 indicates 'NonCompliantActiveTransfer'. We change the source port for * a RootRevoke value of 2. */ root_revoke = get_param_ptr(TOPLEVEL_CONF, "RootRevoke", FALSE); if (root_revoke != NULL && *root_revoke == 2) { bind_port = INPORT_ANY; } session.d = pr_inet_create_conn(session.pool, -1, bind_addr, bind_port, TRUE); /* Default remote address to which to connect for an active transfer, * if the client has not specified a different address via PORT/EPRT, * as per RFC 959. */ if (pr_netaddr_get_family(&session.data_addr) == AF_UNSPEC) { pr_log_debug(DEBUG6, "Client has not sent previous PORT/EPRT command, " "defaulting to %s#%u for active transfer", pr_netaddr_get_ipstr(session.c->remote_addr), session.c->remote_port); pr_netaddr_set_family(&session.data_addr, pr_netaddr_get_family(session.c->remote_addr)); pr_netaddr_set_sockaddr(&session.data_addr, pr_netaddr_get_sockaddr(session.c->remote_addr)); } /* Set the "stalled" timer, if any, to prevent the connection * open from taking too long */ if (timeout_stalled) { pr_timer_add(timeout_stalled, PR_TIMER_STALLED, NULL, stalled_timeout_cb, "TimeoutStalled"); } rev = pr_netaddr_set_reverse_dns(ServerUseReverseDNS); /* Protocol and socket options should be set before handshaking. */ if (session.xfer.direction == PR_NETIO_IO_RD) { pr_inet_set_socket_opts(session.d->pool, session.d, (main_server->tcp_rcvbuf_override ? main_server->tcp_rcvbuf_len : 0), 0, main_server->tcp_keepalive); } else { pr_inet_set_socket_opts(session.d->pool, session.d, 0, (main_server->tcp_sndbuf_override ? main_server->tcp_sndbuf_len : 0), main_server->tcp_keepalive); } /* Make sure that the necessary socket options are set on the socket prior * to the call to connect(2). */ pr_inet_set_proto_opts(session.pool, session.d, main_server->tcp_mss_len, 0, IPTOS_THROUGHPUT, 1); pr_inet_generate_socket_event("core.data-connect", main_server, session.d->local_addr, session.d->listen_fd); if (pr_inet_connect(session.d->pool, session.d, &session.data_addr, session.data_port) == -1) { pr_log_debug(DEBUG6, "Error connecting to %s#%u for active data transfer: %s", pr_netaddr_get_ipstr(&session.data_addr), session.data_port, strerror(session.d->xerrno)); pr_response_add_err(R_425, _("Unable to build data connection: %s"), strerror(session.d->xerrno)); errno = session.d->xerrno; destroy_pool(session.d->pool); session.d = NULL; return -1; } c = pr_inet_openrw(session.pool, session.d, NULL, PR_NETIO_STRM_DATA, session.d->listen_fd, -1, -1, TRUE); pr_netaddr_set_reverse_dns(rev); if (c) { pr_log_debug(DEBUG4, "active data connection opened - local : %s:%d", pr_netaddr_get_ipstr(session.d->local_addr), session.d->local_port); pr_log_debug(DEBUG4, "active data connection opened - remote : %s:%d", pr_netaddr_get_ipstr(session.d->remote_addr), session.d->remote_port); if (session.xfer.xfer_type != STOR_UNIQUE) { if (size) { pr_response_send(R_150, _("Opening %s mode data connection for %s " "(%" PR_LU " bytes)"), MODE_STRING, reason, (pr_off_t) size); } else { pr_response_send(R_150, _("Opening %s mode data connection for %s"), MODE_STRING, reason); } } else { /* Format of 150 responses for STOU is explicitly dictated by * RFC 1123: * * 4.1.2.9 STOU Command: RFC-959 Section 4.1.3 * * The STOU command stores into a uniquely named file. When it * receives an STOU command, a Server-FTP MUST return the * actual file name in the "125 Transfer Starting" or the "150 * Opening Data Connection" message that precedes the transfer * (the 250 reply code mentioned in RFC-959 is incorrect). The * exact format of these messages is hereby defined to be as * follows: * * 125 FILE: pppp * 150 FILE: pppp * * where pppp represents the unique pathname of the file that * will be written. */ pr_response_send(R_150, "FILE: %s", reason); } pr_inet_close(session.pool, session.d); pr_inet_set_nonblock(session.pool, session.d); session.d = c; return 0; } pr_response_add_err(R_425, _("Unable to build data connection: %s"), strerror(session.d->xerrno)); errno = session.d->xerrno; destroy_pool(session.d->pool); session.d = NULL; return -1; }