diff -burp docs/curl.1 docs/curl.1 --- docs/curl.1 Wed Mar 15 15:21:35 2006 +++ docs/curl.1 Thu Jul 6 23:53:48 2006 @@ -396,6 +396,11 @@ in 7.11.0) If this option is used several times, the following occurrences make no difference. +.IP "--ftp-alternative-to-user " +(FTP) If authenticating with the USER and PASS commands fails, send +this command. When connecting to Tumbleweed's Secure Transport server +over FTPS using a client certificate, using "SITE AUTH" will tell the +server to retrieve the username from the certificate. (Added in x.xx.x) .IP "--ftp-skip-pasv-ip" (FTP) Tell curl to not use the IP address the server suggests in its response to curl's PASV command when curl connects the data connection. Instead curl diff -burp docs/libcurl/curl_easy_setopt.3 docs/libcurl/curl_easy_setopt.3 --- docs/libcurl/curl_easy_setopt.3 Fri Jul 7 10:14:52 2006 +++ docs/libcurl/curl_easy_setopt.3 Fri Jul 7 10:14:52 2006 @@ -809,6 +809,11 @@ recommended that if used in conjunction with \fICURLOPT_TIMEOUT\fP, you set \fICURLOPT_FTP_RESPONSE_TIMEOUT\fP to a value smaller than \fICURLOPT_TIMEOUT\fP. (Added in 7.10.8) +.IP CURLOPT_FTP_ALTERNATIVE_TO_USER +Pass a char * as parameter, pointing to a string which will be used +to authenticate if the usual "USER user" and "PASS password" negotiation +fails. This is currently only required when connecting to Tumbleweed's +Secure Transport FTPS server using client certificates for authentication. .IP CURLOPT_FTP_SKIP_PASV_IP Pass a long. If set to a non-zero value, it instructs libcurl to not use the IP address the server suggests in its 227-response to libcurl's PASV command diff -burp include/curl/curl.h include/curl/curl.h --- include/curl/curl.h Mon Mar 13 18:05:15 2006 +++ include/curl/curl.h Thu Jul 6 23:53:48 2006 @@ -937,6 +937,9 @@ typedef enum { extracting it with CURLINFO_LASTSOCKET */ CINIT(CONNECT_ONLY, LONG, 141), + /* Pointer to command string to send if USER/PASS fails. */ + CINIT(FTP_ALTERNATIVE_TO_USER, OBJECTPOINT, 142), + CURLOPT_LASTENTRY /* the last unused */ } CURLoption; diff -burp lib/ftp.c lib/ftp.c --- lib/ftp.c Mon Mar 13 17:33:46 2006 +++ lib/ftp.c Thu Jul 6 23:53:48 2006 @@ -699,6 +699,7 @@ static CURLcode ftp_state_user(struct co NBFTPSENDF(conn, "USER %s", ftp->user?ftp->user:""); state(conn, FTP_USER); + conn->data->state.ftp_trying_alternative = FALSE; return CURLE_OK; } @@ -2302,8 +2303,19 @@ static CURLcode ftp_state_user_resp(stru 530 User ... access denied (the server denies to log the specified user) */ - failf(data, "Access denied: %03d", ftpcode); - result = CURLE_LOGIN_DENIED; + + if (conn->data->set.ftp_alternative_to_user && + !conn->data->state.ftp_trying_alternative) { + /* Ok, USER failed. Let's try the supplied command. */ + NBFTPSENDF(conn, "%s", conn->data->set.ftp_alternative_to_user); + conn->data->state.ftp_trying_alternative = TRUE; + state(conn, FTP_USER); + result = CURLE_OK; + } + else { + failf(data, "Access denied: %03d", ftpcode); + result = CURLE_LOGIN_DENIED; + } } return result; } diff -burp lib/url.c lib/url.c --- lib/url.c Tue Mar 7 17:11:42 2006 +++ lib/url.c Thu Jul 6 23:53:48 2006 @@ -1486,6 +1486,10 @@ CURLcode Curl_setopt(struct SessionHandl data->set.connect_only = va_arg(param, long)?TRUE:FALSE; break; + case CURLOPT_FTP_ALTERNATIVE_TO_USER: + data->set.ftp_alternative_to_user = va_arg(param, char *); + break; + default: /* unknown tag and its companion, just ignore: */ result = CURLE_FAILED_INIT; /* correct this */ diff -burp lib/urldata.h lib/urldata.h --- lib/urldata.h Tue Mar 7 17:11:42 2006 +++ lib/urldata.h Thu Jul 6 23:53:48 2006 @@ -937,6 +937,9 @@ struct UrlState { /* a place to store the most recenlty set FTP entrypath */ char *most_recent_ftp_entrypath; + /* set after initial USER failure, to prevent an authentication loop */ + bool ftp_trying_alternative; + #ifndef WIN32 /* do FTP line-end conversions on most platforms */ #define CURL_DO_LINEEND_CONV @@ -1052,6 +1055,7 @@ struct UserDefined { bool cookiesession; /* new cookie session? */ bool crlf; /* convert crlf on ftp upload(?) */ char *ftp_account; /* ftp account data */ + char *ftp_alternative_to_user; /* command to send if USER/PASS fails */ struct curl_slist *quote; /* after connection is established */ struct curl_slist *postquote; /* after the transfer */ struct curl_slist *prequote; /* before the transfer, after type */ --- src/main.c Mon Mar 13 18:07:21 2006 +++ src/main.c Thu Jul 6 23:53:48 2006 @@ -358,6 +358,7 @@ struct Configurable { struct curl_slist *tp_postquote; struct curl_slist *tp_prequote; char *ftp_account; /* for ACCT */ + char *ftp_alternative_to_user; /* send command if USER/PASS fails */ int ftp_filemethod; bool ignorecl; /* --ignore-content-length */ @@ -1338,6 +1339,7 @@ static ParameterError getparameter(char {"$r", "ftp-method", TRUE}, {"$s", "local-port", TRUE}, {"$t", "socks4", TRUE}, + {"$u", "ftp-alternative-to-user", TRUE}, {"0", "http1.0", FALSE}, {"1", "tlsv1", FALSE}, @@ -1774,6 +1776,9 @@ static ParameterError getparameter(char } } break; + case 'u': /* --ftp-alternative-to-user */ + GetStr(&config->ftp_alternative_to_user, nextarg); + break; } break; case '#': /* --progress-bar */ @@ -4012,6 +4017,9 @@ operate(struct Configurable *config, int curl_easy_setopt(curl, CURLOPT_LOCALPORT, config->localport); curl_easy_setopt(curl, CURLOPT_LOCALPORTRANGE, config->localportrange); } + + /* curl x.xx.x */ + curl_easy_setopt(curl, CURLOPT_FTP_ALTERNATIVE_TO_USER, config->ftp_alternative_to_user); retry_numretries = config->req_retry;