Index: src/cgi.c ================================================================== --- src/cgi.c +++ src/cgi.c @@ -354,11 +354,11 @@ /* ** Do a redirect request to the URL given in the argument. ** ** The URL must be relative to the base of the fossil server. */ -NORETURN static void cgi_redirect_with_status( +NORETURN void cgi_redirect_with_status( const char *zURL, int iStat, const char *zStat ){ char *zLocation; Index: src/login.c ================================================================== --- src/login.c +++ src/login.c @@ -549,34 +549,11 @@ const char *zIpAddr; /* IP address of requestor */ const char *zReferer; int noAnon = P("noanon")!=0; login_check_credentials(); - if( login_wants_https_redirect() ){ - const char *zQS = P("QUERY_STRING"); - if( P("redir")!=0 ){ - style_header("Insecure Connection"); - @

Unable To Establish An Encrypted Connection

- @

This website requires that login credentials be sent over - @ an encrypted connection. The current connection is not encrypted - @ across the entire route between your browser and the server. - @ An attempt was made to redirect to %h(g.zHttpsURL) but - @ the connection is still insecure even after the redirect.

- @

This is probably some kind of configuration problem. Please - @ contact your sysadmin.

- @

Sorry it did not work out.

- style_footer(); - return; - } - if( zQS==0 ){ - zQS = "?redir=1"; - }else if( zQS[0]!=0 ){ - zQS = mprintf("?%s&redir=1", zQS); - } - cgi_redirectf("%s%T%s", g.zHttpsURL, P("PATH_INFO"), zQS); - return; - } + fossil_redirect_to_https_if_needed(1); sqlite3_create_function(g.db, "constant_time_cmp", 2, SQLITE_UTF8, 0, constant_time_cmp_function, 0, 0); zUsername = P("u"); zPasswd = P("p"); anonFlag = g.zLogin==0 && PB("anon"); @@ -914,26 +891,10 @@ " AND constant_time_cmp(cookie,%Q)=0", zLogin, zRemoteAddr, zCookie ); return uid; } - -/* -** Return true if it is appropriate to redirect login requests to HTTPS. -** -** Redirect to https is appropriate if all of the above are true: -** (1) The redirect-to-https flag is set -** (2) The current connection is http, not https or ssh -** (3) The sslNotAvailable flag is clear -*/ -int login_wants_https_redirect(void){ - if( g.sslNotAvailable ) return 0; - if( db_get_boolean("redirect-to-https",0)==0 ) return 0; - if( P("HTTPS")!=0 ) return 0; - return 1; -} - /* ** Attempt to use Basic Authentication to establish the user. Return the ** (non-zero) uid if successful. Return 0 if it does not work. */ @@ -1461,11 +1422,11 @@ { const char *zUrl = PD("REQUEST_URI", "index"); const char *zQS = P("QUERY_STRING"); Blob redir; blob_init(&redir, 0, 0); - if( login_wants_https_redirect() && !g.sslNotAvailable ){ + if( fossil_wants_https(1) ){ blob_appendf(&redir, "%s/login?g=%T", g.zHttpsURL, zUrl); }else{ blob_appendf(&redir, "%R/login?g=%T", zUrl); } if( anonOk ) blob_append(&redir, "&anon", 5); Index: src/main.c ================================================================== --- src/main.c +++ src/main.c @@ -1334,10 +1334,60 @@ } #endif db_panic_close(); exit(1); } + +/* +** Return true if it is appropriate to redirect requests to HTTPS. +** +** Redirect to https is appropriate if all of the above are true: +** (1) The redirect-to-https flag has a valud of iLevel or greater. +** (2) The current connection is http, not https or ssh +** (3) The sslNotAvailable flag is clear +*/ +int fossil_wants_https(int iLevel){ + if( g.sslNotAvailable ) return 0; + if( db_get_int("redirect-to-https",0)Unable To Establish An Encrypted Connection + @

This website requires an encrypted connection. + @ The current connection is not encrypted + @ across the entire route between your browser and the server. + @ An attempt was made to redirect to %h(g.zHttpsURL) but + @ the connection is still insecure even after the redirect.

+ @

This is probably some kind of configuration problem. Please + @ contact your sysadmin.

+ @

Sorry it did not work out.

+ style_footer(); + cgi_reply(); + return 1; + } + if( zQS==0 || zQS[0]==0 ){ + zURL = mprintf("%s%T?redir=1", g.zHttpsURL, P("PATH_INFO")); + }else if( zQS[0]!=0 ){ + zURL = mprintf("%s%T?%s&redir=1", g.zHttpsURL, P("PATH_INFO"), zQS); + } + cgi_redirect_with_status(zURL, 301, "Moved Permanently"); + return 1; + } + return 0; +} /* ** Preconditions: ** ** * Environment variables are set up according to the CGI standard. @@ -1609,10 +1659,11 @@ /* Use the first element of PATH_INFO as the page name ** and deliver the appropriate page back to the user. */ set_base_url(0); + if( fossil_redirect_to_https_if_needed(2) ) return; if( zPathInfo==0 || zPathInfo[0]==0 || (zPathInfo[0]=='/' && zPathInfo[1]==0) ){ /* Second special case: If the PATH_INFO is blank, issue a redirect to ** the home page identified by the "index-page" setting in the repository ** CONFIG table, to "/index" if there no "index-page" setting. */ @@ -2427,11 +2478,12 @@ ** --https signal a request coming in via https ** --max-latency N Do not let any single HTTP request run for more than N ** seconds (only works on unix) ** --nocompress Do not compress HTTP replies ** --nojail Drop root privileges but do not enter the chroot jail -** --nossl signal that no SSL connections are available +** --nossl signal that no SSL connections are available (Always +** set by default for the "ui" command) ** --notfound URL Redirect ** -P|--port TCPPORT listen to request on port TCPPORT ** --th-trace trace TH1 execution (for debugging purposes) ** --repolist If REPOSITORY is dir, URL "/" lists repos. ** --scgi Accept SCGI rather than HTTP @@ -2498,11 +2550,11 @@ fCreate = find_option("create",0,0)!=0; if( find_option("scgi", 0, 0)!=0 ) flags |= HTTP_SERVER_SCGI; if( zAltBase ){ set_base_url(zAltBase); } - g.sslNotAvailable = find_option("nossl", 0, 0)!=0; + g.sslNotAvailable = find_option("nossl", 0, 0)!=0 || isUiCmd; if( find_option("https",0,0)!=0 ){ cgi_replace_parameter("HTTPS","on"); } if( find_option("localhost", 0, 0)!=0 ){ flags |= HTTP_SERVER_LOCALHOST; Index: src/setup.c ================================================================== --- src/setup.c +++ src/setup.c @@ -284,11 +284,11 @@ const char *zLabel, /* The text label on the menu */ const char *zVar, /* The corresponding row in the VAR table */ const char *zQP, /* The query parameter */ const char *zDflt, /* Default value if VAR table entry does not exist */ int nChoice, /* Number of choices */ - const char *const *azChoice /* Choices. 2 per choice: (VAR value, Display) */ + const char *const *azChoice /* Choices in pairs (VAR value, Display) */ ){ const char *z = db_get(zVar, zDflt); const char *zQ = P(zQP); int i; if( zQ && fossil_strcmp(zQ,z)!=0){ @@ -312,10 +312,15 @@ ** WEBPAGE: setup_access ** ** The access-control settings page. Requires Setup privileges. */ void setup_access(void){ + static const char * const azRedirectOpts[] = { + "0", "Off", + "1", "Login Page Only", + "2", "All Pages" + }; login_check_credentials(); if( !g.perm.Setup ){ login_needed(0); return; } @@ -324,18 +329,21 @@ db_begin_transaction(); @
login_insert_csrf_secret(); @

@
- onoff_attribute("Redirect to HTTPS on the Login page", - "redirect-to-https", "redirhttps", 0, 0); - @

When selected, force the use of HTTPS for the Login page. - @

Details: When enabled, this option causes the $secureurl TH1 + multiple_choice_attribute("Redirect to HTTPS", + "redirect-to-https", "redirhttps", "0", + count(azRedirectOpts)/2, azRedirectOpts); + @

Force the use of HTTPS by redirecting to HTTPS when an + @ unencrypted request is received. This feature can be enabled + @ for the Login page only, or for all pages. + @

Further details: When enabled, this option causes the $secureurl TH1 @ variable is set to an "https:" variant of $baseurl. Otherwise, - @ $secureurl is just an alias for $baseurl. Also when enabled, the - @ Login page redirects to https if accessed via http. - @ (Property: "redirect-to-https") + @ $secureurl is just an alias for $baseurl. + @ (Property: "redirect-to-https". "0" for off, "1" for Login page only, + @ "2" otherwise.) @


onoff_attribute("Require password for local access", "localauth", "localauth", 0, 0); @

When enabled, the password sign-in is always required for @ web access. When disabled, unrestricted web access from 127.0.0.1 Index: src/style.c ================================================================== --- src/style.c +++ src/style.c @@ -412,11 +412,11 @@ Th_Store("nonce", style_nonce()); Th_Store("project_name", db_get("project-name","Unnamed Fossil Project")); Th_Store("project_description", db_get("project-description","")); if( zTitle ) Th_Store("title", zTitle); Th_Store("baseurl", g.zBaseURL); - Th_Store("secureurl", login_wants_https_redirect()? g.zHttpsURL: g.zBaseURL); + Th_Store("secureurl", fossil_wants_https(1)? g.zHttpsURL: g.zBaseURL); Th_Store("home", g.zTop); Th_Store("index_page", db_get("index-page","/home")); if( local_zCurrentPage==0 ) style_set_current_page("%T", g.zPath); Th_Store("current_page", local_zCurrentPage); Th_Store("csrf_token", g.zCsrfToken); @@ -914,11 +914,11 @@ /* Process through TH1 in order to give an opportunity to substitute ** variables such as $baseurl. */ Th_Store("baseurl", g.zBaseURL); - Th_Store("secureurl", login_wants_https_redirect()? g.zHttpsURL: g.zBaseURL); + Th_Store("secureurl", fossil_wants_https(1)? g.zHttpsURL: g.zBaseURL); Th_Store("home", g.zTop); image_url_var("logo"); image_url_var("background"); Th_Render(blob_str(&css));