| | @@ -21,10 +21,30 @@ |
| 21 | 21 | ** http://www.hwaci.com/drh/ |
| 22 | 22 | ** |
| 23 | 23 | ******************************************************************************* |
| 24 | 24 | ** |
| 25 | 25 | ** This file contains code for generating the login and logout screens. |
| 26 | +** |
| 27 | +** Notes: |
| 28 | +** |
| 29 | +** There are two special-case user-ids: "anonymous" and "nobody". |
| 30 | +** The capabilities of the nobody user are available to anyone, |
| 31 | +** regardless of whether or not they are logged in. The capabilities |
| 32 | +** of anonymous are only available after logging in, but the login |
| 33 | +** screen displays the password for the anonymous login, so this |
| 34 | +** should not prevent a human user from doing so. |
| 35 | +** |
| 36 | +** The nobody user has capabilities that you want spiders to have. |
| 37 | +** The anonymous user has capabilities that you want people without |
| 38 | +** logins to have. |
| 39 | +** |
| 40 | +** Of course, a sophisticated spider could easily circumvent the |
| 41 | +** anonymous login requirement and walk the website. But that is |
| 42 | +** not really the point. The anonymous login keeps search-engine |
| 43 | +** crawlers and site download tools like wget from walking change |
| 44 | +** logs and downloading diffs of very version of the archive that |
| 45 | +** has ever existed, and things like that. |
| 26 | 46 | */ |
| 27 | 47 | #include "config.h" |
| 28 | 48 | #include "login.h" |
| 29 | 49 | #include <time.h> |
| 30 | 50 | |
| | @@ -42,10 +62,11 @@ |
| 42 | 62 | ** Generate the login page |
| 43 | 63 | */ |
| 44 | 64 | void login_page(void){ |
| 45 | 65 | const char *zUsername, *zPasswd, *zGoto; |
| 46 | 66 | const char *zNew1, *zNew2; |
| 67 | + const char *zAnonPw; |
| 47 | 68 | char *zErrMsg = ""; |
| 48 | 69 | |
| 49 | 70 | login_check_credentials(); |
| 50 | 71 | zUsername = P("u"); |
| 51 | 72 | zPasswd = P("p"); |
| | @@ -53,11 +74,11 @@ |
| 53 | 74 | if( P("out")!=0 ){ |
| 54 | 75 | const char *zCookieName = login_cookie_name(); |
| 55 | 76 | cgi_set_cookie(zCookieName, "", 0, -86400); |
| 56 | 77 | cgi_redirect(zGoto); |
| 57 | 78 | } |
| 58 | | - if( !g.isAnon && zPasswd && (zNew1 = P("n1"))!=0 && (zNew2 = P("n2"))!=0 ){ |
| 79 | + if( g.okPassword && zPasswd && (zNew1 = P("n1"))!=0 && (zNew2 = P("n2"))!=0 ){ |
| 59 | 80 | if( db_int(1, "SELECT 0 FROM user" |
| 60 | 81 | " WHERE uid=%d AND pw=%Q", g.userUid, zPasswd) ){ |
| 61 | 82 | sleep(1); |
| 62 | 83 | zErrMsg = |
| 63 | 84 | @ <p><font color="red"> |
| | @@ -78,36 +99,39 @@ |
| 78 | 99 | ); |
| 79 | 100 | cgi_redirect("index"); |
| 80 | 101 | return; |
| 81 | 102 | } |
| 82 | 103 | } |
| 83 | | - if( zUsername!=0 && zPasswd!=0 && strcmp(zUsername,"anonymous")!=0 ){ |
| 104 | + if( zUsername!=0 && zPasswd!=0 ){ |
| 84 | 105 | int uid = db_int(0, |
| 85 | 106 | "SELECT uid FROM user" |
| 86 | 107 | " WHERE login=%Q AND pw=%Q", zUsername, zPasswd); |
| 87 | | - if( uid<=0 ){ |
| 108 | + if( uid<=0 || strcmp(zUsername,"nobody")==0 ){ |
| 88 | 109 | sleep(1); |
| 89 | 110 | zErrMsg = |
| 90 | 111 | @ <p><font color="red"> |
| 91 | 112 | @ You entered an unknown user or an incorrect password. |
| 92 | 113 | @ </font></p> |
| 93 | 114 | ; |
| 94 | 115 | }else{ |
| 95 | 116 | char *zCookie; |
| 96 | 117 | const char *zCookieName = login_cookie_name(); |
| 97 | | - const char *zIpAddr = PD("REMOTE_ADDR","nil"); |
| 98 | 118 | const char *zExpire = db_get("cookie-expire","8766"); |
| 99 | | - int expires; |
| 100 | | - |
| 101 | | - zCookie = db_text(0, "SELECT '%d/' || hex(randomblob(25))", uid); |
| 102 | | - expires = atoi(zExpire)*3600; |
| 103 | | - cgi_set_cookie(zCookieName, zCookie, 0, expires); |
| 104 | | - db_multi_exec( |
| 105 | | - "UPDATE user SET cookie=%Q, ipaddr=%Q, " |
| 106 | | - " cexpire=julianday('now')+%d/86400.0 WHERE uid=%d", |
| 107 | | - zCookie, zIpAddr, expires, uid |
| 108 | | - ); |
| 119 | + int expires = atoi(zExpire)*3600; |
| 120 | + const char *zIpAddr = PD("REMOTE_ADDR","nil"); |
| 121 | + |
| 122 | + if( strcmp(zUsername, "anonymous")==0 ){ |
| 123 | + cgi_set_cookie(zCookieName, "anonymous", 0, expires); |
| 124 | + }else{ |
| 125 | + zCookie = db_text(0, "SELECT '%d/' || hex(randomblob(25))", uid); |
| 126 | + cgi_set_cookie(zCookieName, zCookie, 0, expires); |
| 127 | + db_multi_exec( |
| 128 | + "UPDATE user SET cookie=%Q, ipaddr=%Q, " |
| 129 | + " cexpire=julianday('now')+%d/86400.0 WHERE uid=%d", |
| 130 | + zCookie, zIpAddr, expires, uid |
| 131 | + ); |
| 132 | + } |
| 109 | 133 | cgi_redirect(zGoto); |
| 110 | 134 | } |
| 111 | 135 | } |
| 112 | 136 | style_header("Login/Logout"); |
| 113 | 137 | @ %s(zErrMsg) |
| | @@ -127,32 +151,40 @@ |
| 127 | 151 | @ <tr> |
| 128 | 152 | @ <td></td> |
| 129 | 153 | @ <td><input type="submit" name="in" value="Login"></td> |
| 130 | 154 | @ </tr> |
| 131 | 155 | @ </table> |
| 132 | | - if( g.isAnon || g.zLogin==0 || g.zLogin[0]==0 ){ |
| 156 | + if( g.zLogin==0 ){ |
| 133 | 157 | @ <p>To login |
| 134 | 158 | }else{ |
| 135 | 159 | @ <p>You are current logged in as <b>%h(g.zLogin)</b></p> |
| 136 | 160 | @ <p>To change your login to a different user |
| 137 | 161 | } |
| 138 | 162 | @ enter the user-id and password at the left and press the |
| 139 | 163 | @ "Login" button. Your user name will be stored in a browser cookie. |
| 140 | 164 | @ You must configure your web browser to accept cookies in order for |
| 141 | 165 | @ the login to take.</p> |
| 142 | | - if( db_exists("SELECT uid FROM user WHERE login='anonymous'") ){ |
| 143 | | - @ <p>This server is configured to allow limited access to users |
| 144 | | - @ who are not logged in.</p> |
| 166 | + if( g.zLogin==0 ){ |
| 167 | + zAnonPw = db_text(0, "SELECT pw FROM user" |
| 168 | + " WHERE login='anonymous'" |
| 169 | + " AND cap!=''"); |
| 170 | + if( zAnonPw ){ |
| 171 | + @ <p>If you do not have a user-id, enter "<b>anonymous</b>" with a |
| 172 | + @ password of "<b>%h(zAnonPw)</b>".</p> |
| 173 | + }else{ |
| 174 | + @ <p>A valid user-id and password is required. Anonymous access |
| 175 | + @ is not allowed on this installation.</p> |
| 176 | + } |
| 145 | 177 | } |
| 146 | | - if( !g.isAnon ){ |
| 178 | + if( g.zLogin ){ |
| 147 | 179 | @ <br clear="both"><hr> |
| 148 | 180 | @ <p>To log off the system (and delete your login cookie) |
| 149 | 181 | @ press the following button:<br> |
| 150 | 182 | @ <input type="submit" name="out" value="Logout"></p> |
| 151 | 183 | } |
| 152 | 184 | @ </form> |
| 153 | | - if( !g.isAnon ){ |
| 185 | + if( g.okPassword ){ |
| 154 | 186 | @ <br clear="both"><hr> |
| 155 | 187 | @ <p>To change your password, enter your old password and your |
| 156 | 188 | @ new password twice below then press the "Change Password" |
| 157 | 189 | @ button.</p> |
| 158 | 190 | @ <form action="login" method="POST"> |
| | @@ -184,11 +216,11 @@ |
| 184 | 216 | const char *zCookie; |
| 185 | 217 | const char *zRemoteAddr; |
| 186 | 218 | const char *zCap = 0; |
| 187 | 219 | |
| 188 | 220 | /* Only run this check once. */ |
| 189 | | - if( g.zLogin!=0 ) return; |
| 221 | + if( g.userUid!=0 ) return; |
| 190 | 222 | |
| 191 | 223 | |
| 192 | 224 | /* If the HTTP connection is coming over 127.0.0.1 and if |
| 193 | 225 | ** local login is disabled, then there is no need to check |
| 194 | 226 | ** user credentials. |
| | @@ -198,45 +230,50 @@ |
| 198 | 230 | && db_get_int("authenticate-localhost",1)==0 ){ |
| 199 | 231 | uid = db_int(0, "SELECT uid FROM user WHERE cap LIKE '%%s%%'"); |
| 200 | 232 | g.zLogin = db_text("?", "SELECT login FROM user WHERE uid=%d", uid); |
| 201 | 233 | zCap = "s"; |
| 202 | 234 | g.noPswd = 1; |
| 203 | | - g.isAnon = 0; |
| 204 | 235 | } |
| 205 | 236 | |
| 206 | 237 | /* Check the login cookie to see if it matches a known valid user. |
| 207 | 238 | */ |
| 208 | | - if( uid==0 ){ |
| 209 | | - if( (zCookie = P(login_cookie_name()))!=0 ){ |
| 239 | + if( uid==0 && (zCookie = P(login_cookie_name()))!=0 ){ |
| 240 | + if( isdigit(zCookie[0]) ){ |
| 210 | 241 | uid = db_int(0, |
| 211 | 242 | "SELECT uid FROM user" |
| 212 | 243 | " WHERE uid=%d" |
| 213 | 244 | " AND cookie=%Q" |
| 214 | 245 | " AND ipaddr=%Q" |
| 215 | 246 | " AND cexpire>julianday('now')", |
| 216 | 247 | atoi(zCookie), zCookie, zRemoteAddr |
| 217 | 248 | ); |
| 218 | | - }else{ |
| 249 | + }else if( zCookie[0]=='a' ){ |
| 219 | 250 | uid = db_int(0, "SELECT uid FROM user WHERE login='anonymous'"); |
| 220 | 251 | } |
| 221 | 252 | } |
| 222 | 253 | |
| 223 | 254 | if( uid==0 ){ |
| 224 | | - g.isAnon = 1; |
| 225 | | - g.zLogin = ""; |
| 226 | | - zCap = db_get("nologin-cap","onrj"); |
| 227 | | - }else if( zCap==0 ){ |
| 228 | | - Stmt s; |
| 229 | | - db_prepare(&s, "SELECT login, cap FROM user WHERE uid=%d", uid); |
| 230 | | - db_step(&s); |
| 231 | | - g.zLogin = db_column_malloc(&s, 0); |
| 232 | | - zCap = db_column_malloc(&s, 1); |
| 233 | | - g.isAnon = 0; |
| 234 | | - db_finalize(&s); |
| 255 | + uid = db_int(0, "SELECT uid FROM user WHERE login='nobody'"); |
| 256 | + if( uid==0 ){ |
| 257 | + uid = -1; |
| 258 | + zCap = ""; |
| 259 | + } |
| 260 | + } |
| 261 | + if( zCap==0 ){ |
| 262 | + if( uid ){ |
| 263 | + Stmt s; |
| 264 | + db_prepare(&s, "SELECT login, cap FROM user WHERE uid=%d", uid); |
| 265 | + db_step(&s); |
| 266 | + g.zLogin = db_column_malloc(&s, 0); |
| 267 | + zCap = db_column_malloc(&s, 1); |
| 268 | + db_finalize(&s); |
| 269 | + } |
| 270 | + if( zCap==0 ){ |
| 271 | + zCap = ""; |
| 272 | + } |
| 235 | 273 | } |
| 236 | 274 | g.userUid = uid; |
| 237 | | - |
| 238 | 275 | login_set_capabilities(zCap); |
| 239 | 276 | } |
| 240 | 277 | |
| 241 | 278 | /* |
| 242 | 279 | ** Set the global capability flags based on a capability string. |
| 243 | 280 | |