Fossil SCM
Simplify the Basic Authentication implementation, removing the need for the strtok_r() library function.
Commit
2e76b99f5ce5301c4cf82f06d069ec608da888cce543cf8d736d51b110eff6d2
Parent
0541af5f8c7ef54…
1 file changed
+54
-91
+54
-91
| --- src/login.c | ||
| +++ src/login.c | ||
| @@ -49,48 +49,10 @@ | ||
| 49 | 49 | # define sleep Sleep /* windows does not have sleep, but Sleep */ |
| 50 | 50 | # endif |
| 51 | 51 | #endif |
| 52 | 52 | #include <time.h> |
| 53 | 53 | |
| 54 | -#ifdef _WIN32 | |
| 55 | -/* | |
| 56 | -** MinGW doesn't have strtok_r in its libc. Here's a public domain one | |
| 57 | -** found at StackOverflow as a work-around, with formatting adjusted to | |
| 58 | -** make it more like the usual style here. This is certainly the wrong | |
| 59 | -** place for it, which is emphasized by making the function static. | |
| 60 | -** | |
| 61 | -** See http://stackoverflow.com/a/12979321/68204 | |
| 62 | -** | |
| 63 | -** public domain strtok_r() by Charlie Gordon | |
| 64 | -** from comp.lang.c 9/14/2007 | |
| 65 | -** http://groups.google.com/group/comp.lang.c/msg/2ab1ecbb86646684 | |
| 66 | -** (Declaration that it's public domain): | |
| 67 | -** http://groups.google.com/group/comp.lang.c/msg/7c7b39328fefab9c | |
| 68 | -*/ | |
| 69 | -static char* win32_strtok_r( | |
| 70 | - char *str, | |
| 71 | - const char *delim, | |
| 72 | - char **nextp | |
| 73 | -){ | |
| 74 | - char *ret; | |
| 75 | - if( str == NULL ){ | |
| 76 | - str = *nextp; | |
| 77 | - } | |
| 78 | - str += strspn(str, delim); | |
| 79 | - if( *str == '\0' ){ | |
| 80 | - return NULL; | |
| 81 | - } | |
| 82 | - ret = str; | |
| 83 | - str += strcspn(str, delim); | |
| 84 | - if( *str ){ | |
| 85 | - *str++ = '\0'; | |
| 86 | - } | |
| 87 | - *nextp = str; | |
| 88 | - return ret; | |
| 89 | -} | |
| 90 | -#define strtok_r win32_strtok_r | |
| 91 | -#endif | |
| 92 | 54 | |
| 93 | 55 | /* |
| 94 | 56 | ** Return the login-group name. Or return 0 if this repository is |
| 95 | 57 | ** not a member of a login-group. |
| 96 | 58 | */ |
| @@ -885,10 +847,62 @@ | ||
| 885 | 847 | if( db_get_boolean("redirect-to-https",0)==0 ) return 0; |
| 886 | 848 | if( P("HTTPS")!=0 ) return 0; |
| 887 | 849 | return 1; |
| 888 | 850 | } |
| 889 | 851 | |
| 852 | + | |
| 853 | +/* | |
| 854 | +** Attempt to use Basic Authentication to establish the user. Return the | |
| 855 | +** (non-zero) uid if successful. Return 0 if it does not work. | |
| 856 | +*/ | |
| 857 | +static logic_basic_authentication(const char *zIpAddr){ | |
| 858 | + const char *zAuth = PD("HTTP_AUTHORIZATION", 0); | |
| 859 | + int i; | |
| 860 | + int uid = 0; | |
| 861 | + int nDecode = 0; | |
| 862 | + char *zDecode = 0; | |
| 863 | + const char *zUsername = 0; | |
| 864 | + const char *zPasswd = 0; | |
| 865 | + | |
| 866 | + | |
| 867 | + if( zAuth==0 ) return 0; /* Fail: No Authentication: header */ | |
| 868 | + while( fossil_isspace(zAuth[0]) ) zAuth++; /* Skip leading whitespace */ | |
| 869 | + if( strncmp(zAuth, "Basic ", 6)!=0 ) return 0; /* Fail: Not Basic Authentication */ | |
| 870 | + | |
| 871 | + /* Parse out the username and password, separated by a ":" */ | |
| 872 | + zAuth += 6; | |
| 873 | + while( fossil_isspace(zAuth[0]) ) zAuth++; | |
| 874 | + zDecode = decode64(zAuth, &nDecode); | |
| 875 | + | |
| 876 | + for(i=0; zDecode[i] && zDecode[i]!=':'; i++){} | |
| 877 | + if( zDecode[i] ){ | |
| 878 | + zDecode[i] = 0; | |
| 879 | + zUsername = zDecode; | |
| 880 | + zPasswd = &zDecode[i+1]; | |
| 881 | + | |
| 882 | + /* Attempting to log in as the user provided by HTTP | |
| 883 | + ** basic auth | |
| 884 | + */ | |
| 885 | + uid = login_search_uid(zUsername, zPasswd); | |
| 886 | + if( uid>0 ){ | |
| 887 | + record_login_attempt(zUsername, zIpAddr, 1); | |
| 888 | + }else{ | |
| 889 | + record_login_attempt(zUsername, zIpAddr, 0); | |
| 890 | + | |
| 891 | + /* The user attempted to login specifically with HTTP basic | |
| 892 | + ** auth, but provided invalid credentials. Inform them of | |
| 893 | + ** the failed login attempt via 401. | |
| 894 | + */ | |
| 895 | + cgi_set_status(401, "Unauthorized"); | |
| 896 | + cgi_reply(); | |
| 897 | + fossil_exit(0); | |
| 898 | + } | |
| 899 | + } | |
| 900 | + fossil_free(zDecode); | |
| 901 | + return uid; | |
| 902 | +} | |
| 903 | + | |
| 890 | 904 | /* |
| 891 | 905 | ** This routine examines the login cookie to see if it exists and |
| 892 | 906 | ** is valid. If the login cookie checks out, it then sets global |
| 893 | 907 | ** variables appropriately. |
| 894 | 908 | ** |
| @@ -1010,63 +1024,12 @@ | ||
| 1010 | 1024 | |
| 1011 | 1025 | /* If the request didn't provide a login cookie or the login cookie didn't |
| 1012 | 1026 | ** match a known valid user, check the HTTP "Authorization" header and |
| 1013 | 1027 | ** see if those credentials are valid for a known user. |
| 1014 | 1028 | */ |
| 1015 | - if( uid==0 ){ | |
| 1016 | - const char *zHTTPAuth = PD("HTTP_AUTHORIZATION", 0); | |
| 1017 | - | |
| 1018 | - /* Check to see if the HTTP "Authorization" header is present | |
| 1019 | - */ | |
| 1020 | - if( zHTTPAuth!=0 && zHTTPAuth[0]!=0 | |
| 1021 | - && db_get_boolean("http_authentication_ok",0) | |
| 1022 | - ){ | |
| 1023 | - char *zBuf = fossil_strdup(zHTTPAuth); | |
| 1024 | - | |
| 1025 | - if( zBuf!=0 ){ | |
| 1026 | - char *zPos; | |
| 1027 | - char *zTok = strtok_r(zBuf, " ", &zPos); | |
| 1028 | - | |
| 1029 | - if( zTok != 0 ){ | |
| 1030 | - /* Check to see if the authorization scheme is HTTP | |
| 1031 | - ** basic auth. | |
| 1032 | - */ | |
| 1033 | - if (strncmp(zTok, "Basic", zTok - zBuf) == 0) { | |
| 1034 | - zTok = strtok_r(NULL, " ", &zPos); | |
| 1035 | - int zBytesDecoded = 0; | |
| 1036 | - char *zDecodedAuth = decode64(zTok, &zBytesDecoded); | |
| 1037 | - | |
| 1038 | - char *zUsername = strtok_r(zDecodedAuth, ":", &zPos); | |
| 1039 | - char *zPasswd = strtok_r(NULL, ":", &zPos); | |
| 1040 | - | |
| 1041 | - if( zUsername!=0 && zPasswd!=0 && zPasswd[0]!=0 ){ | |
| 1042 | - /* Attempting to log in as the user provided by HTTP | |
| 1043 | - ** basic auth | |
| 1044 | - */ | |
| 1045 | - uid = login_search_uid(zUsername, zPasswd); | |
| 1046 | - if( uid>0 ){ | |
| 1047 | - record_login_attempt(zUsername, zIpAddr, 1); | |
| 1048 | - }else{ | |
| 1049 | - record_login_attempt(zUsername, zIpAddr, 0); | |
| 1050 | - | |
| 1051 | - /* The user attempted to login specifically with HTTP basic | |
| 1052 | - ** auth, but provided invalid credentials. Inform them of | |
| 1053 | - ** the failed login attempt via 401. | |
| 1054 | - */ | |
| 1055 | - cgi_set_status(401, "Unauthorized"); | |
| 1056 | - cgi_reply(); | |
| 1057 | - fossil_exit(0); | |
| 1058 | - } | |
| 1059 | - } | |
| 1060 | - | |
| 1061 | - fossil_free(zDecodedAuth); | |
| 1062 | - } | |
| 1063 | - } | |
| 1064 | - | |
| 1065 | - fossil_free(zBuf); | |
| 1066 | - } | |
| 1067 | - } | |
| 1029 | + if( uid==0 && db_get_boolean("http_authentication_ok",0) ){ | |
| 1030 | + uid = logic_basic_authentication(zIpAddr); | |
| 1068 | 1031 | } |
| 1069 | 1032 | |
| 1070 | 1033 | /* If no user found yet, try to log in as "nobody" */ |
| 1071 | 1034 | if( uid==0 ){ |
| 1072 | 1035 | uid = db_int(0, "SELECT uid FROM user WHERE login='nobody'"); |
| 1073 | 1036 |
| --- src/login.c | |
| +++ src/login.c | |
| @@ -49,48 +49,10 @@ | |
| 49 | # define sleep Sleep /* windows does not have sleep, but Sleep */ |
| 50 | # endif |
| 51 | #endif |
| 52 | #include <time.h> |
| 53 | |
| 54 | #ifdef _WIN32 |
| 55 | /* |
| 56 | ** MinGW doesn't have strtok_r in its libc. Here's a public domain one |
| 57 | ** found at StackOverflow as a work-around, with formatting adjusted to |
| 58 | ** make it more like the usual style here. This is certainly the wrong |
| 59 | ** place for it, which is emphasized by making the function static. |
| 60 | ** |
| 61 | ** See http://stackoverflow.com/a/12979321/68204 |
| 62 | ** |
| 63 | ** public domain strtok_r() by Charlie Gordon |
| 64 | ** from comp.lang.c 9/14/2007 |
| 65 | ** http://groups.google.com/group/comp.lang.c/msg/2ab1ecbb86646684 |
| 66 | ** (Declaration that it's public domain): |
| 67 | ** http://groups.google.com/group/comp.lang.c/msg/7c7b39328fefab9c |
| 68 | */ |
| 69 | static char* win32_strtok_r( |
| 70 | char *str, |
| 71 | const char *delim, |
| 72 | char **nextp |
| 73 | ){ |
| 74 | char *ret; |
| 75 | if( str == NULL ){ |
| 76 | str = *nextp; |
| 77 | } |
| 78 | str += strspn(str, delim); |
| 79 | if( *str == '\0' ){ |
| 80 | return NULL; |
| 81 | } |
| 82 | ret = str; |
| 83 | str += strcspn(str, delim); |
| 84 | if( *str ){ |
| 85 | *str++ = '\0'; |
| 86 | } |
| 87 | *nextp = str; |
| 88 | return ret; |
| 89 | } |
| 90 | #define strtok_r win32_strtok_r |
| 91 | #endif |
| 92 | |
| 93 | /* |
| 94 | ** Return the login-group name. Or return 0 if this repository is |
| 95 | ** not a member of a login-group. |
| 96 | */ |
| @@ -885,10 +847,62 @@ | |
| 885 | if( db_get_boolean("redirect-to-https",0)==0 ) return 0; |
| 886 | if( P("HTTPS")!=0 ) return 0; |
| 887 | return 1; |
| 888 | } |
| 889 | |
| 890 | /* |
| 891 | ** This routine examines the login cookie to see if it exists and |
| 892 | ** is valid. If the login cookie checks out, it then sets global |
| 893 | ** variables appropriately. |
| 894 | ** |
| @@ -1010,63 +1024,12 @@ | |
| 1010 | |
| 1011 | /* If the request didn't provide a login cookie or the login cookie didn't |
| 1012 | ** match a known valid user, check the HTTP "Authorization" header and |
| 1013 | ** see if those credentials are valid for a known user. |
| 1014 | */ |
| 1015 | if( uid==0 ){ |
| 1016 | const char *zHTTPAuth = PD("HTTP_AUTHORIZATION", 0); |
| 1017 | |
| 1018 | /* Check to see if the HTTP "Authorization" header is present |
| 1019 | */ |
| 1020 | if( zHTTPAuth!=0 && zHTTPAuth[0]!=0 |
| 1021 | && db_get_boolean("http_authentication_ok",0) |
| 1022 | ){ |
| 1023 | char *zBuf = fossil_strdup(zHTTPAuth); |
| 1024 | |
| 1025 | if( zBuf!=0 ){ |
| 1026 | char *zPos; |
| 1027 | char *zTok = strtok_r(zBuf, " ", &zPos); |
| 1028 | |
| 1029 | if( zTok != 0 ){ |
| 1030 | /* Check to see if the authorization scheme is HTTP |
| 1031 | ** basic auth. |
| 1032 | */ |
| 1033 | if (strncmp(zTok, "Basic", zTok - zBuf) == 0) { |
| 1034 | zTok = strtok_r(NULL, " ", &zPos); |
| 1035 | int zBytesDecoded = 0; |
| 1036 | char *zDecodedAuth = decode64(zTok, &zBytesDecoded); |
| 1037 | |
| 1038 | char *zUsername = strtok_r(zDecodedAuth, ":", &zPos); |
| 1039 | char *zPasswd = strtok_r(NULL, ":", &zPos); |
| 1040 | |
| 1041 | if( zUsername!=0 && zPasswd!=0 && zPasswd[0]!=0 ){ |
| 1042 | /* Attempting to log in as the user provided by HTTP |
| 1043 | ** basic auth |
| 1044 | */ |
| 1045 | uid = login_search_uid(zUsername, zPasswd); |
| 1046 | if( uid>0 ){ |
| 1047 | record_login_attempt(zUsername, zIpAddr, 1); |
| 1048 | }else{ |
| 1049 | record_login_attempt(zUsername, zIpAddr, 0); |
| 1050 | |
| 1051 | /* The user attempted to login specifically with HTTP basic |
| 1052 | ** auth, but provided invalid credentials. Inform them of |
| 1053 | ** the failed login attempt via 401. |
| 1054 | */ |
| 1055 | cgi_set_status(401, "Unauthorized"); |
| 1056 | cgi_reply(); |
| 1057 | fossil_exit(0); |
| 1058 | } |
| 1059 | } |
| 1060 | |
| 1061 | fossil_free(zDecodedAuth); |
| 1062 | } |
| 1063 | } |
| 1064 | |
| 1065 | fossil_free(zBuf); |
| 1066 | } |
| 1067 | } |
| 1068 | } |
| 1069 | |
| 1070 | /* If no user found yet, try to log in as "nobody" */ |
| 1071 | if( uid==0 ){ |
| 1072 | uid = db_int(0, "SELECT uid FROM user WHERE login='nobody'"); |
| 1073 |
| --- src/login.c | |
| +++ src/login.c | |
| @@ -49,48 +49,10 @@ | |
| 49 | # define sleep Sleep /* windows does not have sleep, but Sleep */ |
| 50 | # endif |
| 51 | #endif |
| 52 | #include <time.h> |
| 53 | |
| 54 | |
| 55 | /* |
| 56 | ** Return the login-group name. Or return 0 if this repository is |
| 57 | ** not a member of a login-group. |
| 58 | */ |
| @@ -885,10 +847,62 @@ | |
| 847 | if( db_get_boolean("redirect-to-https",0)==0 ) return 0; |
| 848 | if( P("HTTPS")!=0 ) return 0; |
| 849 | return 1; |
| 850 | } |
| 851 | |
| 852 | |
| 853 | /* |
| 854 | ** Attempt to use Basic Authentication to establish the user. Return the |
| 855 | ** (non-zero) uid if successful. Return 0 if it does not work. |
| 856 | */ |
| 857 | static logic_basic_authentication(const char *zIpAddr){ |
| 858 | const char *zAuth = PD("HTTP_AUTHORIZATION", 0); |
| 859 | int i; |
| 860 | int uid = 0; |
| 861 | int nDecode = 0; |
| 862 | char *zDecode = 0; |
| 863 | const char *zUsername = 0; |
| 864 | const char *zPasswd = 0; |
| 865 | |
| 866 | |
| 867 | if( zAuth==0 ) return 0; /* Fail: No Authentication: header */ |
| 868 | while( fossil_isspace(zAuth[0]) ) zAuth++; /* Skip leading whitespace */ |
| 869 | if( strncmp(zAuth, "Basic ", 6)!=0 ) return 0; /* Fail: Not Basic Authentication */ |
| 870 | |
| 871 | /* Parse out the username and password, separated by a ":" */ |
| 872 | zAuth += 6; |
| 873 | while( fossil_isspace(zAuth[0]) ) zAuth++; |
| 874 | zDecode = decode64(zAuth, &nDecode); |
| 875 | |
| 876 | for(i=0; zDecode[i] && zDecode[i]!=':'; i++){} |
| 877 | if( zDecode[i] ){ |
| 878 | zDecode[i] = 0; |
| 879 | zUsername = zDecode; |
| 880 | zPasswd = &zDecode[i+1]; |
| 881 | |
| 882 | /* Attempting to log in as the user provided by HTTP |
| 883 | ** basic auth |
| 884 | */ |
| 885 | uid = login_search_uid(zUsername, zPasswd); |
| 886 | if( uid>0 ){ |
| 887 | record_login_attempt(zUsername, zIpAddr, 1); |
| 888 | }else{ |
| 889 | record_login_attempt(zUsername, zIpAddr, 0); |
| 890 | |
| 891 | /* The user attempted to login specifically with HTTP basic |
| 892 | ** auth, but provided invalid credentials. Inform them of |
| 893 | ** the failed login attempt via 401. |
| 894 | */ |
| 895 | cgi_set_status(401, "Unauthorized"); |
| 896 | cgi_reply(); |
| 897 | fossil_exit(0); |
| 898 | } |
| 899 | } |
| 900 | fossil_free(zDecode); |
| 901 | return uid; |
| 902 | } |
| 903 | |
| 904 | /* |
| 905 | ** This routine examines the login cookie to see if it exists and |
| 906 | ** is valid. If the login cookie checks out, it then sets global |
| 907 | ** variables appropriately. |
| 908 | ** |
| @@ -1010,63 +1024,12 @@ | |
| 1024 | |
| 1025 | /* If the request didn't provide a login cookie or the login cookie didn't |
| 1026 | ** match a known valid user, check the HTTP "Authorization" header and |
| 1027 | ** see if those credentials are valid for a known user. |
| 1028 | */ |
| 1029 | if( uid==0 && db_get_boolean("http_authentication_ok",0) ){ |
| 1030 | uid = logic_basic_authentication(zIpAddr); |
| 1031 | } |
| 1032 | |
| 1033 | /* If no user found yet, try to log in as "nobody" */ |
| 1034 | if( uid==0 ){ |
| 1035 | uid = db_int(0, "SELECT uid FROM user WHERE login='nobody'"); |
| 1036 |