int proxy_ftp_sess_send_auth_tls(pool *p, struct proxy_session *proxy_sess) { int uri_tls, use_tls, xerrno; char *auth_feat; array_header *auth_feats = NULL; pool *tmp_pool; cmd_rec *cmd; pr_response_t *resp; unsigned int resp_nlines = 0; use_tls = proxy_tls_use_tls(); if (use_tls == PROXY_TLS_ENGINE_OFF) { pr_trace_msg(trace_channel, 19, "TLS support not enabled/desired, skipping"); return 0; } /* Check for any per-URI scheme-based TLS requirements. */ uri_tls = proxy_conn_get_tls(proxy_sess->dst_pconn); auth_feat = pr_table_get(proxy_sess->backend_features, C_AUTH, NULL); if (auth_feat == NULL) { /* Backend server does not indicate that it supports AUTH via FEAT. * * Even though this is the case, we will still try to send the AUTH * command. A malicious attacker could be modifying the plaintext * FEAT listing, to make us think that TLS is not supported, and thus * prevent us from encrypting the session (a la "SSL stripping"). */ /* If TLS is required, then complain loudly. */ if (uri_tls == PROXY_TLS_ENGINE_ON || use_tls == PROXY_TLS_ENGINE_ON) { const char *ip_str; ip_str = pr_netaddr_get_ipstr(proxy_sess->backend_ctrl_conn->remote_addr); if (uri_tls == PROXY_TLS_ENGINE_ON) { (void) pr_log_writefile(proxy_logfd, MOD_PROXY_VERSION, "backend server %s does not support AUTH TLS (see FEAT response) but " "URI '%.100s' requires TLS, attempting anyway", ip_str, proxy_conn_get_uri(proxy_sess->dst_pconn)); } else if (use_tls == PROXY_TLS_ENGINE_ON) { (void) pr_log_writefile(proxy_logfd, MOD_PROXY_VERSION, "backend server %s does not support AUTH TLS (see FEAT response) but " "ProxyTLSEngine requires TLS, attempting anyway", ip_str); } } pr_trace_msg(trace_channel, 9, "backend server does not support AUTH TLS (via FEAT)"); } tmp_pool = make_sub_pool(p); /* Note: the FEAT response against IIS servers shows e.g.: * * 211-Extended features supported: * LANG EN* * UTF8 * AUTH TLS;TLS-C;SSL;TLS-P; * PBSZ * PROT C;P; * CCC * HOST * SIZE * MDTM * REST STREAM * 211 END * * Note how the AUTH and PROT values are not exactly as specified * in RFC 4217. This means we'll need to deal with it as is. There will * be other servers with other FEAT response formats, too. */ if (parse_feat(tmp_pool, auth_feat, &auth_feats) > 0) { register unsigned int i; pr_trace_msg(trace_channel, 9, "parsed FEAT value '%s' into %d values", auth_feat, auth_feats->nelts); for (i = 0; i < auth_feats->nelts; i++) { char *val; val = ((char **) auth_feats->elts)[i]; pr_trace_msg(trace_channel, 9, " %s", val); } } /* XXX How should we interoperate with servers that support/want the * older formats, e.g.: * * AUTH SSL (which automatically assumes PBSZ 0, PROT P) * AUTH TLS-P (synonym for AUTH SSL) * AUTH TLS-C (synonym for AUTH TLS) */ cmd = pr_cmd_alloc(tmp_pool, 2, C_AUTH, "TLS"); cmd->arg = pstrdup(tmp_pool, "TLS"); resp = send_recv(tmp_pool, proxy_sess->backend_ctrl_conn, cmd, &resp_nlines); if (resp == NULL) { xerrno = errno; proxy_netio_use(PR_NETIO_STRM_CTRL, NULL); destroy_pool(tmp_pool); errno = xerrno; return -1; } if (resp->num[0] != '2') { /* XXX Some older servers might respond with a 334 response code, per * RFC 2228. See, for example: * http://serverfault.com/questions/640978/ftp-alter-server-response-in-transit */ pr_trace_msg(trace_channel, 4, "received unexpected %s response code %s from backend", (char *) cmd->argv[0], resp->num); proxy_netio_use(PR_NETIO_STRM_CTRL, NULL); destroy_pool(tmp_pool); errno = EPERM; return -1; } destroy_pool(tmp_pool); return 0; }
int proxy_ftp_sess_send_auth_tls(pool *p, struct proxy_session *proxy_sess) { int uri_tls, use_tls, xerrno; char *auth_feat; array_header *auth_feats = NULL; pool *tmp_pool; cmd_rec *cmd; pr_response_t *resp; unsigned int resp_nlines = 0; use_tls = proxy_tls_use_tls(); if (use_tls == PROXY_TLS_ENGINE_OFF) { pr_trace_msg(trace_channel, 19, "TLS support not enabled/desired, skipping"); return 0; } /* Check for any per-URI scheme-based TLS requirements. */ uri_tls = proxy_conn_get_tls(proxy_sess->dst_pconn); auth_feat = pr_table_get(proxy_sess->backend_features, C_AUTH, NULL); if (auth_feat == NULL) { /* Backend server does not indicate that it supports AUTH via FEAT. */ /* If TLS is required, then fail now. */ if (uri_tls == PROXY_TLS_ENGINE_ON || use_tls == PROXY_TLS_ENGINE_ON) { const char *ip_str; ip_str = pr_netaddr_get_ipstr(proxy_sess->backend_ctrl_conn->remote_addr); if (uri_tls == PROXY_TLS_ENGINE_ON) { (void) pr_log_writefile(proxy_logfd, MOD_PROXY_VERSION, "backend server %s does not support AUTH TLS (see FEAT response) but " "URI '%.100s' requires TLS, failing connection", ip_str, proxy_conn_get_uri(proxy_sess->dst_pconn)); } else if (use_tls == PROXY_TLS_ENGINE_ON) { (void) pr_log_writefile(proxy_logfd, MOD_PROXY_VERSION, "backend server %s does not support AUTH TLS (see FEAT response) but " "ProxyTLSEngine requires TLS, failing connection", ip_str); } errno = EPERM; return -1; } /* Tell the Proxy NetIO API to NOT try to use our TLS NetIO. */ proxy_netio_use(PR_NETIO_STRM_CTRL, NULL); pr_trace_msg(trace_channel, 9, "backend server does not support AUTH TLS (via FEAT), skipping"); return 0; } tmp_pool = make_sub_pool(p); /* Note: the FEAT response against IIS servers shows e.g.: * * 211-Extended features supported: * LANG EN* * UTF8 * AUTH TLS;TLS-C;SSL;TLS-P; * PBSZ * PROT C;P; * CCC * HOST * SIZE * MDTM * REST STREAM * 211 END * * Note how the AUTH and PROT values are not exactly as specified * in RFC 4217. This means we'll need to deal with as is. There will * be other servers with other FEAT response formats, too. */ if (parse_feat(tmp_pool, auth_feat, &auth_feats) > 0) { register unsigned int i; pr_trace_msg(trace_channel, 9, "parsed FEAT value '%s' into %d values", auth_feat, auth_feats->nelts); for (i = 0; i < auth_feats->nelts; i++) { char *val; val = ((char **) auth_feats->elts)[i]; pr_trace_msg(trace_channel, 9, " %s", val); } } cmd = pr_cmd_alloc(tmp_pool, 2, C_AUTH, "TLS"); cmd->arg = pstrdup(tmp_pool, "TLS"); resp = send_recv(tmp_pool, proxy_sess->backend_ctrl_conn, cmd, &resp_nlines); if (resp == NULL) { xerrno = errno; proxy_netio_use(PR_NETIO_STRM_CTRL, NULL); destroy_pool(tmp_pool); errno = xerrno; return -1; } if (resp->num[0] != '2') { pr_trace_msg(trace_channel, 4, "received unexpected %s response code %s from backend", (char *) cmd->argv[0], resp->num); proxy_netio_use(PR_NETIO_STRM_CTRL, NULL); destroy_pool(tmp_pool); errno = EPERM; return -1; } destroy_pool(tmp_pool); return 0; }