Commits

Anonymous committed c535d76 Merge with conflicts

Merge branch 'ml/http'

* ml/http:
http.c: add http.sslCertPasswordProtected option
http.c: prompt for SSL client certificate password

Conflicts:
http.c

Comments (0)

Files changed (2)

Documentation/config.txt

 	over HTTPS. Can be overridden by the 'GIT_SSL_KEY' environment
 	variable.
 
+http.sslCertPasswordProtected::
+	Enable git's password prompt for the SSL certificate.  Otherwise
+	OpenSSL will prompt the user, possibly many times, if the
+	certificate or private key is encrypted.  Can be overridden by the
+	'GIT_SSL_CERT_PASSWORD_PROTECTED' environment variable.
+
 http.sslCAInfo::
 	File containing the certificates to verify the peer with when
 	fetching or pushing over HTTPS. Can be overridden by the
 static const char *curl_http_proxy;
 static char *user_name, *user_pass;
 
+#if LIBCURL_VERSION_NUM >= 0x071700
+/* Use CURLOPT_KEYPASSWD as is */
+#elif LIBCURL_VERSION_NUM >= 0x070903
+#define CURLOPT_KEYPASSWD CURLOPT_SSLKEYPASSWD
+#else
+#define CURLOPT_KEYPASSWD CURLOPT_SSLCERTPASSWD
+#endif
+
+static char *ssl_cert_password;
+static int ssl_cert_password_required;
+
 static struct curl_slist *pragma_header;
 static struct curl_slist *no_pragma_header;
 
 #endif
 	if (!strcmp("http.sslcainfo", var))
 		return git_config_string(&ssl_cainfo, var, value);
+	if (!strcmp("http.sslcertpasswordprotected", var)) {
+		if (git_config_bool(var, value))
+			ssl_cert_password_required = 1;
+		return 0;
+	}
 #ifdef USE_CURL_MULTI
 	if (!strcmp("http.maxrequests", var)) {
 		max_requests = git_config_int(var, value);
 	}
 }
 
+static int has_cert_password(void)
+{
+	if (ssl_cert_password != NULL)
+		return 1;
+	if (ssl_cert == NULL || ssl_cert_password_required != 1)
+		return 0;
+	/* Only prompt the user once. */
+	ssl_cert_password_required = -1;
+	ssl_cert_password = getpass("Certificate Password: ");
+	if (ssl_cert_password != NULL) {
+		ssl_cert_password = xstrdup(ssl_cert_password);
+		return 1;
+	} else
+		return 0;
+}
+
 static CURL *get_curl_handle(void)
 {
 	CURL *result = curl_easy_init();
 
 	if (ssl_cert != NULL)
 		curl_easy_setopt(result, CURLOPT_SSLCERT, ssl_cert);
+	if (has_cert_password())
+		curl_easy_setopt(result, CURLOPT_KEYPASSWD, ssl_cert_password);
 #if LIBCURL_VERSION_NUM >= 0x070903
 	if (ssl_key != NULL)
 		curl_easy_setopt(result, CURLOPT_SSLKEY, ssl_key);
 	if (getenv("GIT_CURL_FTP_NO_EPSV"))
 		curl_ftp_no_epsv = 1;
 
-	if (remote && remote->url && remote->url[0])
+	if (remote && remote->url && remote->url[0]) {
 		http_auth_init(remote->url[0]);
+		if (!ssl_cert_password_required &&
+		    getenv("GIT_SSL_CERT_PASSWORD_PROTECTED") &&
+		    !prefixcmp(remote->url[0], "https://"))
+			ssl_cert_password_required = 1;
+	}
 
 #ifndef NO_CURL_EASY_DUPHANDLE
 	curl_default = get_curl_handle();
 		free((void *)curl_http_proxy);
 		curl_http_proxy = NULL;
 	}
+
+	if (ssl_cert_password != NULL) {
+		memset(ssl_cert_password, 0, strlen(ssl_cert_password));
+		free(ssl_cert_password);
+		ssl_cert_password = NULL;
+	}
+	ssl_cert_password_required = 0;
 }
 
 struct active_request_slot *get_active_slot(void)
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.