Check-in [1f1d96529c]
Not logged in
Overview

SHA1 Hash:1f1d96529c64ef5e9afda16af7d405aade92cb3d
Date: 2008-08-03 16:47:43
User: drh
Comment:Users unconditionally inherit capabilities of "anonymous". New capability "v" means to inherit capabilities of user "developer". Login is prohibited if the password is empty.
Timelines: ancestors | descendants | both | trunk
Other Links: files | ZIP archive | manifest

Tags And Properties
Changes
[hide diffs]

Modified src/admin.c from [3d7573884c] to [8499f27819].

@@ -108,10 +108,10 @@
   }
   admin_prepare_submenu();
   style_header("Admin");
   @ <h2>Links:</h2>
   @ <ul>
-  @ <li><a href='%s(g.zBaseURL)/admin/setup'>Fossil WWW Setup</a></li>
+  @ <li><a href='%s(g.zBaseURL)/setup'>Fossil WWW Setup</a></li>
   @ <li><a href='%s(g.zBaseURL)/admin/sql'>Run SQL queries</a></li>
   @ </ul>
   style_footer();
 }

Modified src/db.c from [2755f169fc] to [1ccbb50ea2].

@@ -789,13 +789,15 @@
      "INSERT INTO user(login, pw, cap, info)"
      "VALUES(%Q,'','s','')", zUser
   );
   db_multi_exec(
      "INSERT INTO user(login,pw,cap,info)"
-     "   VALUES('anonymous','anonymous','hjkorw','Anon');"
+     "   VALUES('anonymous','anonymous','aghknw','Anon');"
      "INSERT INTO user(login,pw,cap,info)"
      "   VALUES('nobody','','jor','Nobody');"
+     "INSERT INTO user(login,pw,cap,info)"
+     "   VALUES('developer','','deipt','Dev');"
   );
   user_select();
 
   if (makeInitialVersion){
     blob_zero(&manifest);

Modified src/login.c from [86fb4c3fd8] to [0807191c83].

@@ -113,11 +113,11 @@
       );
       cgi_redirect(zGoto);
       return;
     }
   }
-  if( zUsername!=0 && zPasswd!=0 ){
+  if( zUsername!=0 && zPasswd!=0 && zPasswd[0]!=0 ){
     int uid = db_int(0,
         "SELECT uid FROM user"
         " WHERE login=%Q AND pw=%Q", zUsername, zPasswd);
     if( uid<=0 || strcmp(zUsername,"nobody")==0 ){
       sleep(1);
@@ -300,13 +300,15 @@
   g.userUid = uid;
   if( g.zLogin && strcmp(g.zLogin,"nobody")==0 ){
     g.zLogin = 0;
   }
   if( uid && g.zLogin ){
+    /* All logged-in users inherit privileges from "nobody" */
     zNcap = db_text("", "SELECT cap FROM user WHERE login = 'nobody'");
     login_set_capabilities(zNcap);
-    if( db_get_int("inherit-anon",0) ){
+    if( strcmp(g.zLogin, "anonymous")!=0 ){
+      /* All logged-in users inherit privileges from "anonymous" */
       zAcap = db_text("", "SELECT cap FROM user WHERE login = 'anonymous'");
       login_set_capabilities(zAcap);
     }
   }
   login_set_capabilities(zCap);
@@ -314,10 +316,11 @@
 
 /*
 ** Set the global capability flags based on a capability string.
 */
 void login_set_capabilities(const char *zCap){
+  static char *zDev = 0;
   int i;
   for(i=0; zCap[i]; i++){
     switch( zCap[i] ){
       case 's':   g.okSetup = 1;
       case 'a':   g.okAdmin = g.okRdTkt = g.okWrTkt =
@@ -343,10 +346,20 @@
       case 'n':   g.okNewTkt = 1;                               break;
       case 'w':   g.okWrTkt = g.okRdTkt = g.okNewTkt =
                   g.okApndTkt = 1;                              break;
       case 'c':   g.okApndTkt = 1;                              break;
       case 't':   g.okTktFmt = 1;                               break;
+
+      /* The "v" privileges is a little different.  It recursively
+      ** inherits all privileges of the user named "developer" */
+      case 'v': {
+        if( zDev==0 ){
+          zDev = db_text("", "SELECT cap FROM user WHERE login='developer'");
+          login_set_capabilities(zDev);
+        }
+        break;
+      }
     }
   }
 }
 
 /*
@@ -359,27 +372,35 @@
   int rc = 1;
   if( nCap<0 ) nCap = strlen(zCap);
   for(i=0; i<nCap && rc && zCap[i]; i++){
     switch( zCap[i] ){
       case 'a':  rc = g.okAdmin;     break;
+      /* case 'b': */
       case 'c':  rc = g.okApndTkt;   break;
       case 'd':  rc = g.okDelete;    break;
       case 'e':  rc = g.okRdAddr;    break;
       case 'f':  rc = g.okNewWiki;   break;
       case 'g':  rc = g.okClone;     break;
       case 'h':  rc = g.okHistory;   break;
       case 'i':  rc = g.okWrite;     break;
       case 'j':  rc = g.okRdWiki;    break;
       case 'k':  rc = g.okWrWiki;    break;
+      /* case 'l': */
       case 'm':  rc = g.okApndWiki;  break;
       case 'n':  rc = g.okNewTkt;    break;
       case 'o':  rc = g.okRead;      break;
       case 'p':  rc = g.okPassword;  break;
+      /* case 'q': */
       case 'r':  rc = g.okRdTkt;     break;
       case 's':  rc = g.okSetup;     break;
       case 't':  rc = g.okTktFmt;    break;
+      /* case 'u': */
+      /* case 'v': */
       case 'w':  rc = g.okWrTkt;     break;
+      /* case 'x': */
+      /* case 'y': */
+      /* case 'z': */
       default:   rc = 0;             break;
     }
   }
   return rc;
 }

Modified src/my_page.c from [52bd9eb48f] to [98c9467776].

@@ -27,12 +27,12 @@
 */
 #include <assert.h>
 #include "config.h"
 #include "my_page.h"
 
-/**
-Renders a logout button.
+/*
+** Renders a logout button.
 */
 static void mypage_logout_button()
 {
   if( g.zLogin ){
     @ <br clear="both"/><hr/>
@@ -43,12 +43,12 @@
     @ <input type="submit" name="out" value="Logout"/></p>
     @ </form>
   }
 }
 
-/**
-Renders a password changer.
+/*
+** Renders a password changer.
 */
 static void mypage_password_changer()
 {
   if( g.okPassword ){
     @ <br clear="both"/><hr/>
@@ -71,12 +71,12 @@
     @ </form>
   }
 
 }
 
-/**
-Default page rendered for /my.
+/*
+** Default page rendered for /my.
 */
 static void mypage_page_default()
 {
   int uid = g.userUid;
   char * sql = mprintf( "SELECT login,cap,info FROM user WHERE uid=%d",

Modified src/setup.c from [7115d9c001] to [1c7a1834ca].

@@ -152,34 +152,50 @@
   @ <li value="15"><b>Check-Out</b>: Check out versions</li>
   @ <li value="16"><b>Password</b>: Change your own password</li>
   @ <li value="18"><b>Read-Tkt</b>: View tickets</li>
   @ <li value="19"><b>Setup:</b> Setup and configure this website</li>
   @ <li value="20"><b>Tkt-Report:</b> Create new bug summary reports</li>
+  @ <li value="22"><b>Developer:</b> Inherit privileges of user "developer"</li>
   @ <li value="23"><b>Write-Tkt</b>: Edit tickets</li>
   @ </ol>
   @ </p></li>
   @
   @ <li><p>
-  @ Every user, logged in or not, has the privileges of <b>nobody</b>.
+  @ Every user, logged in or not, inherits the privileges of <b>nobody</b>.
   @ Any human can login as <b>anonymous</b> since the password is
   @ clearly displayed on the login page for them to type.  The purpose
   @ of requiring anonymous to log in is to prevent access by spiders.
+  @ Every logged-in user inherits the privileges of <b>anonymous</b>.
   @ </p></li>
   @
   @ </ol>
   @ </td></tr></table>
   style_footer();
 }
 
 /*
+** Return true if zPw is a valid password string.  A valid
+** password string is:
+**
+**  (1)  A zero-length string, or
+**  (2)  a string that contains a character other than '*'.
+*/
+static int isValidPwString(const char *zPw){
+  if( zPw==0 ) return 0;
+  if( zPw[0]==0 ) return 1;
+  while( zPw[0]=='*' ){ zPw++; }
+  return zPw[0]!=0;
+}
+
+/*
 ** WEBPAGE: /setup_uedit
 */
 void user_edit(void){
-  const char *zId, *zLogin, *zInfo, *zCap;
+  const char *zId, *zLogin, *zInfo, *zCap, *zPw;
   char *oaa, *oas, *oar, *oaw, *oan, *oai, *oaj, *oao, *oap;
   char *oak, *oad, *oac, *oaf, *oam, *oah, *oag, *oae;
-  char *oat;
+  char *oat, *oav;
   int doWrite;
   int uid;
   int higherUser = 0;  /* True if user being edited is SETUP and the */
                        /* user doing the editing is ADMIN.  Disallow editing */
 
@@ -208,12 +224,10 @@
   ** modified user record.  After writing the user record, redirect
   ** to the page that displays a list of users.
   */
   doWrite = cgi_all("login","info","pw") && !higherUser;
   if( doWrite ){
-    const char *zPw;
-    const char *zLogin;
     char zCap[50];
     int i = 0;
     int aa = P("aa")!=0;
     int ad = P("ad")!=0;
     int ae = P("ae")!=0;
@@ -230,10 +244,11 @@
     int af = P("af")!=0;
     int am = P("am")!=0;
     int ah = P("ah")!=0;
     int ag = P("ag")!=0;
     int at = P("at")!=0;
+    int av = P("av")!=0;
     if( aa ){ zCap[i++] = 'a'; }
     if( ac ){ zCap[i++] = 'c'; }
     if( ad ){ zCap[i++] = 'd'; }
     if( ae ){ zCap[i++] = 'e'; }
     if( af ){ zCap[i++] = 'f'; }
@@ -247,15 +262,16 @@
     if( ao ){ zCap[i++] = 'o'; }
     if( ap ){ zCap[i++] = 'p'; }
     if( ar ){ zCap[i++] = 'r'; }
     if( as ){ zCap[i++] = 's'; }
     if( at ){ zCap[i++] = 't'; }
+    if( av ){ zCap[i++] = 'v'; }
     if( aw ){ zCap[i++] = 'w'; }
 
     zCap[i] = 0;
     zPw = P("pw");
-    if( zPw==0 || zPw[0]==0 ){
+    if( !isValidPwString(zPw) ){
       zPw = db_text(0, "SELECT pw FROM user WHERE uid=%d", uid);
     }
     zLogin = P("login");
     if( uid>0 &&
         db_exists("SELECT 1 FROM user WHERE login=%Q AND uid!=%d", zLogin, uid)
@@ -280,16 +296,18 @@
   /* Load the existing information about the user, if any
   */
   zLogin = "";
   zInfo = "";
   zCap = "";
+  zPw = "";
   oaa = oac = oad = oae = oaf = oag = oah = oai = oaj = oak = oam =
-        oan = oao = oap = oar = oas = oat = oaw = "";
+        oan = oao = oap = oar = oas = oat = oav = oaw = "";
   if( uid ){
     zLogin = db_text("", "SELECT login FROM user WHERE uid=%d", uid);
     zInfo = db_text("", "SELECT info FROM user WHERE uid=%d", uid);
     zCap = db_text("", "SELECT cap FROM user WHERE uid=%d", uid);
+    zPw = db_text("", "SELECT pw FROM user WHERE uid=%d", uid);
     if( strchr(zCap, 'a') ) oaa = " checked";
     if( strchr(zCap, 'c') ) oac = " checked";
     if( strchr(zCap, 'd') ) oad = " checked";
     if( strchr(zCap, 'e') ) oae = " checked";
     if( strchr(zCap, 'f') ) oaf = " checked";
@@ -303,10 +321,11 @@
     if( strchr(zCap, 'o') ) oao = " checked";
     if( strchr(zCap, 'p') ) oap = " checked";
     if( strchr(zCap, 'r') ) oar = " checked";
     if( strchr(zCap, 's') ) oas = " checked";
     if( strchr(zCap, 't') ) oat = " checked";
+    if( strchr(zCap, 'v') ) oav = " checked";
     if( strchr(zCap, 'w') ) oaw = " checked";
   }
 
   /* Begin generating the page
   */
@@ -346,10 +365,11 @@
   @     <input type="checkbox" name="ae"%s(oad)>Email</input><br>
   @     <input type="checkbox" name="ap"%s(oap)>Password</input><br>
   @     <input type="checkbox" name="ai"%s(oai)>Check-In</input><br>
   @     <input type="checkbox" name="ao"%s(oao)>Check-Out</input><br>
   @     <input type="checkbox" name="ah"%s(oah)>History</input><br>
+  @     <input type="checkbox" name="av"%s(oav)>Developer</input><br>
   @     <input type="checkbox" name="ag"%s(oag)>Clone</input><br>
   @     <input type="checkbox" name="aj"%s(oaj)>Read Wiki</input><br>
   @     <input type="checkbox" name="af"%s(oaf)>New Wiki</input><br>
   @     <input type="checkbox" name="am"%s(oam)>Append Wiki</input><br>
   @     <input type="checkbox" name="ak"%s(oak)>Write Wiki</input><br>
@@ -360,21 +380,30 @@
   @     <input type="checkbox" name="at"%s(oat)>Tkt Report</input>
   @   </td>
   @ </tr>
   @ <tr>
   @   <td align="right">Password:</td>
-  @   <td><input type="password" name="pw" value=""></td>
+  if( strcmp(zLogin, "anonymous")==0 ){
+    /* User the password for "anonymous" as cleartext */
+    @   <td><input type="text" name="pw" value="%h(zPw)"></td>
+  }else if( zPw[0] ){
+    /* Obscure the password for all other users */
+    @   <td><input type="password" name="pw" value="**********"></td>
+  }else{
+    /* Show an empty password as an empty input field */
+    @   <td><input type="password" name="pw" value=""></td>
+  }
   @ </tr>
   if( !higherUser ){
     @ <tr>
     @   <td>&nbsp</td>
     @   <td><input type="submit" name="submit" value="Apply Changes">
     @ </tr>
   }
   @ </table></td></tr></table>
-  @ <p><b>Notes:</b></p>
-  @ <ol>
+  @ <h2>Privileges And Capabilities:</h2>
+  @ <ul>
   if( higherUser ){
     @ <li><p><font color="blue"><b>
     @ User %h(zLogin) has Setup privileges and you only have Admin privileges
     @ so you are not permitted to make changes to %h(zLogin).
     @ </b></font></p></li>
@@ -402,10 +431,15 @@
   @ user "nobody" to avoid problems with spiders trying to walk every
   @ historical version of every baseline and file.
   @ </p></li>
   @
   @ <li><p>
+  @ The <b>Developer</b> privilege causes all privileges of the user
+  @ named "developer" to be inherited by this user.
+  @ </p></li>
+  @
+  @ <li><p>
   @ The <b>Check-in</b> privilege allows remote users to "push".
   @ The <b>Check-out</b> privilege allows remote users to "pull".
   @ The <b>Clone</b> privilege allows remote users to "clone".
   @ </li><p>
   @
@@ -418,39 +452,58 @@
   @ ticket report formats.
   @ </p></li>
   @
   @ <li><p>
   @ Users with the <b>Password</b> privilege are allowed to change their
-  @ own password.  Recommended ON for most users but OFF for "anonynmous"
-  @ and "nobody".
+  @ own password.  Recommended ON for most users but OFF for special
+  @ users "developer, "anonynmous", and "nobody".
   @ </p></li>
   @
   @ <li><p>
   @ The <b>EMail</b> privilege allows the display of sensitive information
   @ such as the email address of users and contact information on tickets.
   @ Recommended OFF for "anonymous" and for "nobody".
   @ </p></li>
   @
   @ <li><p>
+  @ Login is prohibited if the password is an empty string.
+  @ </p></li>
+  @ </ul>
+  @
+  @ <h2>Special Logins</h2>
+  @
+  @ <ul>
+  @ <li><p>
   @ No login is required for user "<b>nobody</b>".  The capabilities
-  @ of this user are available to anyone without supplying a username or
-  @ password.  To disable nobody access, make sure there is no user
-  @ with an ID of <b>nobody</b> or that the nobody user has no
-  @ capabilities enabled.  The password for nobody is ignore.  To
-  @ avoid problems with spiders overloading the server, it is suggested
-  @ that the 'h' (History) capability be turned off for user nobody.
+  @ of the <b>nobody</b> user are inherited by all users, regardless of
+  @ whether or not they are logged in.  To disable universal access
+  @ to the repository, make sure no user named "<b>nobody</b>" exists or
+  @ that the <b>nobody</b> user has no capabilities enabled.
+  @ The password for <b>nobody</b> is ignore.  To avoid problems with
+  @ spiders overloading the server, it is recommended
+  @ that the 'h' (History) capability be turned off for the <b>nobody</b>
+  @ user.
   @ </p></li>
   @
   @ <li><p>
   @ Login is required for user "<b>anonymous</b>" but the password
   @ is displayed on the login screen beside the password entry box
   @ so anybody who can read should be able to login as anonymous.
   @ On the other hand, spiders and web-crawlers will typically not
   @ be able to login.  Set the capabilities of the anonymous user
   @ to things that you want any human to be able to do, but not any
-  @ spider.
+  @ spider.  Every other logged-in user inherits the privileges of
+  @ <b>anonymous</b>.
   @ </p></li>
+  @
+  @ <li><p>
+  @ The "<b>developer</b>" user is intended as a template for trusted users
+  @ with check-in privileges.  When adding new trusted users, simply
+  @ select the <b>Developer</b> privilege to cause the new user to inherit
+  @ all privileges of the "developer" user.
+  @ </li></p>
+  @ </ul>
   @ </form>
   style_footer();
 }