File Annotation
Not logged in
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** Copyright (c) 2006 D. Richard Hipp
dbda8d6ce9 2007-07-21       drh: **
dbda8d6ce9 2007-07-21       drh: ** This program is free software; you can redistribute it and/or
dbda8d6ce9 2007-07-21       drh: ** modify it under the terms of the GNU General Public
dbda8d6ce9 2007-07-21       drh: ** License version 2 as published by the Free Software Foundation.
dbda8d6ce9 2007-07-21       drh: **
dbda8d6ce9 2007-07-21       drh: ** This program is distributed in the hope that it will be useful,
dbda8d6ce9 2007-07-21       drh: ** but WITHOUT ANY WARRANTY; without even the implied warranty of
dbda8d6ce9 2007-07-21       drh: ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
dbda8d6ce9 2007-07-21       drh: ** General Public License for more details.
dbda8d6ce9 2007-07-21       drh: **
dbda8d6ce9 2007-07-21       drh: ** You should have received a copy of the GNU General Public
dbda8d6ce9 2007-07-21       drh: ** License along with this library; if not, write to the
dbda8d6ce9 2007-07-21       drh: ** Free Software Foundation, Inc., 59 Temple Place - Suite 330,
dbda8d6ce9 2007-07-21       drh: ** Boston, MA  02111-1307, USA.
dbda8d6ce9 2007-07-21       drh: **
dbda8d6ce9 2007-07-21       drh: ** Author contact information:
dbda8d6ce9 2007-07-21       drh: **   drh@hwaci.com
dbda8d6ce9 2007-07-21       drh: **   http://www.hwaci.com/drh/
dbda8d6ce9 2007-07-21       drh: **
dbda8d6ce9 2007-07-21       drh: *******************************************************************************
dbda8d6ce9 2007-07-21       drh: **
dbda8d6ce9 2007-07-21       drh: ** Commands and procedures used for creating, processing, editing, and
dbda8d6ce9 2007-07-21       drh: ** querying information about users.
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: #include "config.h"
dbda8d6ce9 2007-07-21       drh: #include "user.h"
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** Strip leading and trailing space from a string and add the string
dbda8d6ce9 2007-07-21       drh: ** onto the end of a blob.
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: static void strip_string(Blob *pBlob, char *z){
dbda8d6ce9 2007-07-21       drh:   int i;
dbda8d6ce9 2007-07-21       drh:   blob_reset(pBlob);
dbda8d6ce9 2007-07-21       drh:   while( isspace(*z) ){ z++; }
dbda8d6ce9 2007-07-21       drh:   for(i=0; z[i]; i++){
dbda8d6ce9 2007-07-21       drh:     if( z[i]=='\r' || z[i]=='\n' ){
dbda8d6ce9 2007-07-21       drh:        while( i>0 && isspace(z[i-1]) ){ i--; }
dbda8d6ce9 2007-07-21       drh:        z[i] = 0;
dbda8d6ce9 2007-07-21       drh:        break;
dbda8d6ce9 2007-07-21       drh:     }
dbda8d6ce9 2007-07-21       drh:     if( z[i]<' ' ) z[i] = ' ';
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh:   blob_append(pBlob, z, -1);
dbda8d6ce9 2007-07-21       drh: }
dbda8d6ce9 2007-07-21       drh: 
83c876b447 2007-09-21 anonymous: #ifdef __MINGW32__
83c876b447 2007-09-21 anonymous: /*
83c876b447 2007-09-21 anonymous: ** getpass for Windows
83c876b447 2007-09-21 anonymous: */
83c876b447 2007-09-21 anonymous: static char *getpass(const char *prompt){
83c876b447 2007-09-21 anonymous:   static char pwd[64];
83c876b447 2007-09-21 anonymous:   size_t i;
83c876b447 2007-09-21 anonymous: 
83c876b447 2007-09-21 anonymous:   fputs(prompt,stderr);
83c876b447 2007-09-21 anonymous:   fflush(stderr);
83c876b447 2007-09-21 anonymous:   for(i=0; i<sizeof(pwd)-1; ++i){
83c876b447 2007-09-21 anonymous:     pwd[i] = _getch();
83c876b447 2007-09-21 anonymous:     if(pwd[i]=='\r' || pwd[i]=='\n'){
83c876b447 2007-09-21 anonymous:       break;
83c876b447 2007-09-21 anonymous:     }
83c876b447 2007-09-21 anonymous:     /* BS or DEL */
83c876b447 2007-09-21 anonymous:     else if(i>0 && (pwd[i]==8 || pwd[i]==127)){
83c876b447 2007-09-21 anonymous:       i -= 2;
83c876b447 2007-09-21 anonymous:       continue;
83c876b447 2007-09-21 anonymous:     }
83c876b447 2007-09-21 anonymous:     /* CTRL-C */
83c876b447 2007-09-21 anonymous:     else if(pwd[i]==3) {
83c876b447 2007-09-21 anonymous:       i=0;
83c876b447 2007-09-21 anonymous:       break;
83c876b447 2007-09-21 anonymous:     }
83c876b447 2007-09-21 anonymous:     /* ESC */
83c876b447 2007-09-21 anonymous:     else if(pwd[i]==27){
83c876b447 2007-09-21 anonymous:       i=0;
83c876b447 2007-09-21 anonymous:       break;
83c876b447 2007-09-21 anonymous:     }
83c876b447 2007-09-21 anonymous:     else{
83c876b447 2007-09-21 anonymous:       fputc('*',stderr);
83c876b447 2007-09-21 anonymous:     }
83c876b447 2007-09-21 anonymous:   }
83c876b447 2007-09-21 anonymous:   pwd[i]='\0';
83c876b447 2007-09-21 anonymous:   fputs("\n", stderr);
83c876b447 2007-09-21 anonymous:   return pwd;
83c876b447 2007-09-21 anonymous: }
83c876b447 2007-09-21 anonymous: #endif
83c876b447 2007-09-21 anonymous: 
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** Do a single prompt for a passphrase.  Store the results in the blob.
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: static void prompt_for_passphrase(const char *zPrompt, Blob *pPassphrase){
dbda8d6ce9 2007-07-21       drh:   char *z = getpass(zPrompt);
dbda8d6ce9 2007-07-21       drh:   strip_string(pPassphrase, z);
dbda8d6ce9 2007-07-21       drh: }
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
e621b6dbe3 2007-07-30       drh: ** Prompt the user for a password.  Store the result in the pPassphrase
e621b6dbe3 2007-07-30       drh: ** blob.
dbda8d6ce9 2007-07-21       drh: **
dbda8d6ce9 2007-07-21       drh: ** Behavior is controlled by the verify parameter:
dbda8d6ce9 2007-07-21       drh: **
dbda8d6ce9 2007-07-21       drh: **     0     Just ask once.
dbda8d6ce9 2007-07-21       drh: **
dbda8d6ce9 2007-07-21       drh: **     1     If the first answer is a non-empty string, ask for
dbda8d6ce9 2007-07-21       drh: **           verification.  Repeat if the two strings do not match.
dbda8d6ce9 2007-07-21       drh: **
dbda8d6ce9 2007-07-21       drh: **     2     Ask twice, repeat if the strings do not match.
dbda8d6ce9 2007-07-21       drh: */
e621b6dbe3 2007-07-30       drh: void prompt_for_password(
e621b6dbe3 2007-07-30       drh:   const char *zPrompt,
e621b6dbe3 2007-07-30       drh:   Blob *pPassphrase,
e621b6dbe3 2007-07-30       drh:   int verify
e621b6dbe3 2007-07-30       drh: ){
dbda8d6ce9 2007-07-21       drh:   Blob secondTry;
dbda8d6ce9 2007-07-21       drh:   blob_zero(pPassphrase);
dbda8d6ce9 2007-07-21       drh:   blob_zero(&secondTry);
dbda8d6ce9 2007-07-21       drh:   while(1){
dbda8d6ce9 2007-07-21       drh:     prompt_for_passphrase(zPrompt, pPassphrase);
dbda8d6ce9 2007-07-21       drh:     if( verify==0 ) break;
dbda8d6ce9 2007-07-21       drh:     if( verify==1 && blob_size(pPassphrase)==0 ) break;
dbda8d6ce9 2007-07-21       drh:     prompt_for_passphrase("Again: ", &secondTry);
dbda8d6ce9 2007-07-21       drh:     if( blob_compare(pPassphrase, &secondTry) ){
dbda8d6ce9 2007-07-21       drh:       printf("Passphrases do not match.  Try again...\n");
dbda8d6ce9 2007-07-21       drh:     }else{
dbda8d6ce9 2007-07-21       drh:       break;
dbda8d6ce9 2007-07-21       drh:     }
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh:   blob_reset(&secondTry);
dbda8d6ce9 2007-07-21       drh: }
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** Prompt the user to enter a single line of text.
dbda8d6ce9 2007-07-21       drh: */
e37451d9c2 2007-08-01       drh: void prompt_user(const char *zPrompt, Blob *pIn){
dbda8d6ce9 2007-07-21       drh:   char *z;
dbda8d6ce9 2007-07-21       drh:   char zLine[1000];
dbda8d6ce9 2007-07-21       drh:   blob_zero(pIn);
dbda8d6ce9 2007-07-21       drh:   printf("%s", zPrompt);
dbda8d6ce9 2007-07-21       drh:   fflush(stdout);
dbda8d6ce9 2007-07-21       drh:   z = fgets(zLine, sizeof(zLine), stdin);
dbda8d6ce9 2007-07-21       drh:   if( z ){
dbda8d6ce9 2007-07-21       drh:     strip_string(pIn, z);
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh: }
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** COMMAND:  user
dbda8d6ce9 2007-07-21       drh: **
6607844a01 2007-08-18       drh: ** Usage: %fossil user SUBCOMMAND ...  ?-R|--repository FILE?
6607844a01 2007-08-18       drh: **
6607844a01 2007-08-18       drh: ** Run various subcommands on users of the open repository or of
6607844a01 2007-08-18       drh: ** the repository identified by the -R or --repository option.
6607844a01 2007-08-18       drh: **
6607844a01 2007-08-18       drh: **    %fossil user capabilities USERNAME ?STRING?
6607844a01 2007-08-18       drh: **
6607844a01 2007-08-18       drh: **        Query or set the capabilities for user USERNAME
6607844a01 2007-08-18       drh: **
6607844a01 2007-08-18       drh: **    %fossil user default ?USERNAME?
6607844a01 2007-08-18       drh: **
6607844a01 2007-08-18       drh: **        Query or set the default user.  The default user is the
6607844a01 2007-08-18       drh: **        user for command-line interaction.
6607844a01 2007-08-18       drh: **
6607844a01 2007-08-18       drh: **    %fossil user list
6607844a01 2007-08-18       drh: **
6607844a01 2007-08-18       drh: **        List all users known to the repository
6607844a01 2007-08-18       drh: **
6607844a01 2007-08-18       drh: **    %fossil user new
6607844a01 2007-08-18       drh: **
6607844a01 2007-08-18       drh: **        Create a new user in the repository.  Users can never be
6607844a01 2007-08-18       drh: **        deleted.  They can be denied all access but they must continue
6607844a01 2007-08-18       drh: **        to exist in the database.
6607844a01 2007-08-18       drh: **
6607844a01 2007-08-18       drh: **    %fossil user password USERNAME
6607844a01 2007-08-18       drh: **
6607844a01 2007-08-18       drh: **        Change the web access password for a user.
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: void user_cmd(void){
916b6e4b3b 2007-07-21       drh:   int n;
dbda8d6ce9 2007-07-21       drh:   db_find_and_open_repository();
dbda8d6ce9 2007-07-21       drh:   if( g.argc<3 ){
916b6e4b3b 2007-07-21       drh:     usage("capabilities|default|list|new|password ...");
916b6e4b3b 2007-07-21       drh:   }
916b6e4b3b 2007-07-21       drh:   n = strlen(g.argv[2]);
916b6e4b3b 2007-07-21       drh:   if( n>=2 && strncmp(g.argv[2],"new",n)==0 ){
dbda8d6ce9 2007-07-21       drh:     Blob passwd, login, contact;
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:     prompt_user("login: ", &login);
dbda8d6ce9 2007-07-21       drh:     prompt_user("contact-info: ", &contact);
e621b6dbe3 2007-07-30       drh:     prompt_for_password("password: ", &passwd, 1);
dbda8d6ce9 2007-07-21       drh:     db_multi_exec(
dbda8d6ce9 2007-07-21       drh:       "INSERT INTO user(login,pw,cap,info)"
dbda8d6ce9 2007-07-21       drh:       "VALUES(%B,%B,'jnor',%B)",
dbda8d6ce9 2007-07-21       drh:       &login, &passwd, &contact
dbda8d6ce9 2007-07-21       drh:     );
916b6e4b3b 2007-07-21       drh:   }else if( n>=2 && strncmp(g.argv[2],"default",n)==0 ){
dbda8d6ce9 2007-07-21       drh:     user_select();
dbda8d6ce9 2007-07-21       drh:     if( g.argc==3 ){
dbda8d6ce9 2007-07-21       drh:       printf("%s\n", g.zLogin);
dbda8d6ce9 2007-07-21       drh:     }else if( g.localOpen ){
dbda8d6ce9 2007-07-21       drh:       db_lset("default-user", g.zLogin);
dbda8d6ce9 2007-07-21       drh:     }else{
dbda8d6ce9 2007-07-21       drh:       db_set("default-user", g.zLogin);
dbda8d6ce9 2007-07-21       drh:     }
916b6e4b3b 2007-07-21       drh:   }else if( n>=2 && strncmp(g.argv[2],"list",n)==0 ){
dbda8d6ce9 2007-07-21       drh:     Stmt q;
dbda8d6ce9 2007-07-21       drh:     db_prepare(&q, "SELECT login, info FROM user ORDER BY login");
dbda8d6ce9 2007-07-21       drh:     while( db_step(&q)==SQLITE_ROW ){
dbda8d6ce9 2007-07-21       drh:       printf("%-12s %s\n", db_column_text(&q, 0), db_column_text(&q, 1));
dbda8d6ce9 2007-07-21       drh:     }
dbda8d6ce9 2007-07-21       drh:     db_finalize(&q);
916b6e4b3b 2007-07-21       drh:   }else if( n>=2 && strncmp(g.argv[2],"password",2)==0 ){
dbda8d6ce9 2007-07-21       drh:     char *zPrompt;
dbda8d6ce9 2007-07-21       drh:     int uid;
dbda8d6ce9 2007-07-21       drh:     Blob pw;
df3d6cbff5 2007-09-24  mjanssen:     if( g.argc!=4 ) usage("password USERNAME");
dbda8d6ce9 2007-07-21       drh:     uid = db_int(0, "SELECT uid FROM user WHERE login=%Q", g.argv[3]);
dbda8d6ce9 2007-07-21       drh:     if( uid==0 ){
dbda8d6ce9 2007-07-21       drh:       fossil_fatal("no such user: %s", g.argv[3]);
dbda8d6ce9 2007-07-21       drh:     }
dbda8d6ce9 2007-07-21       drh:     zPrompt = mprintf("new passwd for %s: ", g.argv[3]);
e621b6dbe3 2007-07-30       drh:     prompt_for_password(zPrompt, &pw, 1);
dbda8d6ce9 2007-07-21       drh:     if( blob_size(&pw)==0 ){
dbda8d6ce9 2007-07-21       drh:       printf("password unchanged\n");
dbda8d6ce9 2007-07-21       drh:     }else{
dbda8d6ce9 2007-07-21       drh:       db_multi_exec("UPDATE user SET pw=%B WHERE uid=%d", &pw, uid);
dbda8d6ce9 2007-07-21       drh:     }
916b6e4b3b 2007-07-21       drh:   }else if( n>=2 && strncmp(g.argv[2],"capabilities",2)==0 ){
916b6e4b3b 2007-07-21       drh:     int uid;
916b6e4b3b 2007-07-21       drh:     if( g.argc!=4 && g.argc!=5 ){
916b6e4b3b 2007-07-21       drh:       usage("user capabilities USERNAME ?PERMISSIONS?");
916b6e4b3b 2007-07-21       drh:     }
916b6e4b3b 2007-07-21       drh:     uid = db_int(0, "SELECT uid FROM user WHERE login=%Q", g.argv[3]);
916b6e4b3b 2007-07-21       drh:     if( uid==0 ){
916b6e4b3b 2007-07-21       drh:       fossil_fatal("no such user: %s", g.argv[3]);
916b6e4b3b 2007-07-21       drh:     }
916b6e4b3b 2007-07-21       drh:     if( g.argc==5 ){
916b6e4b3b 2007-07-21       drh:       db_multi_exec(
916b6e4b3b 2007-07-21       drh:         "UPDATE user SET cap=%Q WHERE uid=%d", g.argv[4],
916b6e4b3b 2007-07-21       drh:         uid
916b6e4b3b 2007-07-21       drh:       );
916b6e4b3b 2007-07-21       drh:     }
916b6e4b3b 2007-07-21       drh:     printf("%s\n", db_text(0, "SELECT cap FROM user WHERE uid=%d", uid));
dbda8d6ce9 2007-07-21       drh:   }else{
dbda8d6ce9 2007-07-21       drh:     fossil_panic("user subcommand should be one of: "
916b6e4b3b 2007-07-21       drh:                  "capabilities default list new password");
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh: }
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** Attempt to set the user to zLogin
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: static int attempt_user(const char *zLogin){
dbda8d6ce9 2007-07-21       drh:   int uid;
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:   if( zLogin==0 ){
dbda8d6ce9 2007-07-21       drh:     return 0;
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh:   uid = db_int(0, "SELECT uid FROM user WHERE login=%Q", zLogin);
dbda8d6ce9 2007-07-21       drh:   if( uid ){
dbda8d6ce9 2007-07-21       drh:     g.userUid = uid;
dbda8d6ce9 2007-07-21       drh:     g.zLogin = mprintf("%s", zLogin);
dbda8d6ce9 2007-07-21       drh:     return 1;
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh:   return 0;
dbda8d6ce9 2007-07-21       drh: }
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** Figure out what user is at the controls.
dbda8d6ce9 2007-07-21       drh: **
dbda8d6ce9 2007-07-21       drh: **   (1)  Use the --user and -U command-line options.
dbda8d6ce9 2007-07-21       drh: **
dbda8d6ce9 2007-07-21       drh: **   (2)  If the local database is open, check in VVAR.
dbda8d6ce9 2007-07-21       drh: **
dbda8d6ce9 2007-07-21       drh: **   (3)  Check the default user in the repository
dbda8d6ce9 2007-07-21       drh: **
dbda8d6ce9 2007-07-21       drh: **   (4)  Try the USER environment variable.
dbda8d6ce9 2007-07-21       drh: **
dbda8d6ce9 2007-07-21       drh: **   (5)  Use the first user in the USER table.
dbda8d6ce9 2007-07-21       drh: **
dbda8d6ce9 2007-07-21       drh: ** The user name is stored in g.zLogin.  The uid is in g.userUid.
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: void user_select(void){
dbda8d6ce9 2007-07-21       drh:   Stmt s;
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:   if( g.userUid ) return;
dbda8d6ce9 2007-07-21       drh:   if( attempt_user(g.zLogin) ) return;
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:   if( g.localOpen && attempt_user(db_lget("default-user",0)) ) return;
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:   if( attempt_user(db_get("default-user", 0)) ) return;
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:   if( attempt_user(getenv("USER")) ) return;
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:   db_prepare(&s, "SELECT uid, login FROM user WHERE login<>'anonymous'");
dbda8d6ce9 2007-07-21       drh:   if( db_step(&s)==SQLITE_ROW ){
dbda8d6ce9 2007-07-21       drh:     g.userUid = db_column_int(&s, 0);
dbda8d6ce9 2007-07-21       drh:     g.zLogin = mprintf("%s", db_column_text(&s, 1));
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh:   db_finalize(&s);
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:   if( g.userUid==0 ){
dbda8d6ce9 2007-07-21       drh:     db_prepare(&s, "SELECT uid, login FROM user");
dbda8d6ce9 2007-07-21       drh:     if( db_step(&s)==SQLITE_ROW ){
dbda8d6ce9 2007-07-21       drh:       g.userUid = db_column_int(&s, 0);
dbda8d6ce9 2007-07-21       drh:       g.zLogin = mprintf("%s", db_column_text(&s, 1));
dbda8d6ce9 2007-07-21       drh:     }
dbda8d6ce9 2007-07-21       drh:     db_finalize(&s);
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:   if( g.userUid==0 ){
dbda8d6ce9 2007-07-21       drh:     db_multi_exec(
dbda8d6ce9 2007-07-21       drh:       "INSERT INTO user(login, pw, cap, info)"
dbda8d6ce9 2007-07-21       drh:       "VALUES('anonymous', '', '', '')"
dbda8d6ce9 2007-07-21       drh:     );
dbda8d6ce9 2007-07-21       drh:     g.userUid = db_last_insert_rowid();
dbda8d6ce9 2007-07-21       drh:     g.zLogin = "anonymous";
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh: }