SQLite

Check-in [c8171ecd0d]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Further ideas on user authentication. Not yet working code.
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | user-auth
Files: files | file ages | folders
SHA1: c8171ecd0d6f097c9e95d5f6643bae8d67f44750
User & Date: drh 2014-09-10 17:34:28.937
Context
2014-09-10
19:01
Add the ".user" shell command and implement the sqlite3_user_add() routine. Incremental check-in. The code compiles but does not work. (check-in: a0455f9deb user: drh tags: user-auth)
17:34
Further ideas on user authentication. Not yet working code. (check-in: c8171ecd0d user: drh tags: user-auth)
2014-09-09
14:47
Non-working preliminary implementation attempts on user authentication. (check-in: 8440f093ba user: drh tags: user-auth)
Changes
Side-by-Side Diff Ignore Whitespace Patch
Changes to ext/userauth/userauth.c.
18
19
20
21
22
23
24

25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59



60
61

62
63
64
65
66
67

68
69
70
71
72
73
74

75
76
77
78
79
80




81
82
83

84
85
86

87




88
89
90
91
92
93
94
95



96
97



98
99
100
101














102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119

120
121
122
123

124
125
126
127
128
129
130
131
132
133
134
135
136
137















138
139


140
141

142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161

162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179



180
181
182
183
184
185
186
187
188
189
190
191
192
193

194
195
196
197
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45


46

47
48
49
50
51
52
53
54
55
56

57
58
59
60

61
62
63




64
65
66

67

68

69

70
71
72


73
74
75
76
77
78

79
80
81

82
83
84
85
86
87
88
89
90
91
92



93
94
95
96

97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134

135
136

137

138














139
140
141
142
143
144
145
146
147
148
149
150
151
152
153


154
155
156

157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176

177

178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216







+




















-
-

-










-
+
+
+

-
+


-
-
-
-
+


-

-

-
+
-



-
-
+
+
+
+


-
+


-
+

+
+
+
+





-
-
-
+
+
+

-
+
+
+




+
+
+
+
+
+
+
+
+
+
+
+
+
+

















-
+

-

-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
+
+

-
+



















-
+
-

















+
+
+














+




**
** To compile with the user-authentication feature, append this file to
** end of an SQLite amalgamation, then add the SQLITE_USER_AUTHENTICATION
** compile-time option.  See the user-auth.txt file in the same source
** directory as this file for additional information.
*/
#ifdef SQLITE_USER_AUTHENTICATION
#include "sqliteInt.h"

/*
** Prepare an SQL statement for use by the user authentication logic.
** Return a pointer to the prepared statement on success.  Return a
** NULL pointer if there is an error of any kind.
*/
static sqlite3_stmt *sqlite3UserAuthPrepare(
  sqlite3 *db,
  const char *zFormat,
  ...
){
  sqlite3_stmt *pStmt;
  char *zSql;
  int rc;
  va_list ap;

  va_start(ap, zFormat);
  zSql = sqlite3_vmprintf(zFormat, ap);
  va_end(ap);
  if( zSql==0 ) return 0;
  savedFlags = db->auth.authFlags;
  db->auth.authFlags |= UAUTH_Ovrd;
  rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0);
  db->auth.authFlags = savedFlags;
  sqlite3_free(zSql);
  if( rc ){
    sqlite3_finalize(pStmt);
    pStmt = 0;
  }
  return pStmt;
}

/*
** Check to see if database zDb has a "sqlite_user" table and if it does
** whether that table can authenticate zUser with nPw,zPw.  
** whether that table can authenticate zUser with nPw,zPw.  Write one of
** the UAUTH_* user authorization level codes into *peAuth and return a
** result code.
*/
static int sqlite3UserAuthCheckLogin(
static int userAuthCheckLogin(
  sqlite3 *db,               /* The database connection to check */
  const char *zDb,           /* Name of specific database to check */
  const char *zUser,         /* User name */
  int nPw,                   /* Size of password in bytes */
  const char *zPw,           /* Password */
  int *pbOk                  /* OUT: write boolean result here */
  u8 *peAuth                 /* OUT: One of UAUTH_* constants */
){
  sqlite3_stmt *pStmt;
  char *zSql;
  int rc;
  int iResult;

  *pbOk = 0;
  *peAuth = UAUTH_Unknown;
  iResult = 0;
  pStmt = sqlite3UserAuthPrepare(db, 
              "SELECT 1 FROM \"%w\".sqlite_master "
              " WHERE name='sqlite_user' AND type='table'", zDb);
  if( pStmt==0 ) return SQLITE_NOMEM;
  rc = sqlite3_step(pStmt):
  if( pStmt==0 ){
    return SQLITE_NOMEM;
  }
  rc = sqlite3_step(pStmt);
  sqlite3_finalize(pStmt);
  if( rc==SQLITE_DONE ){
    *pbOk = 1;
    *peAuth = UAUTH_Admin;  /* No sqlite_user table.  Everybody is admin. */
    return SQLITE_OK;
  }
  if( rc!=SQLITE_OK ){
  if( rc!=SQLITE_ROW ){
    return rc;
  }
  if( db->auth.zAuthUser==0 ){
    *peAuth = UAUTH_Fail;
    return SQLITE_OK;
  }
  pStmt = sqlite3UserAuthPrepare(db,
            "SELECT pw=sqlite_crypt(?1,pw), isAdmin FROM \"%w\".sqlite_user"
            " WHERE uname=?2", zDb);
  if( pStmt==0 ) return SQLITE_NOMEM;
  sqlite3_bind_blob(pStmt, 1, zPw, nPw, SQLITE_STATIC);
  sqlite3_bind_text(pStmt, 2, zUser, -1, SQLITE_STATIC);
  rc = sqlite_step(pStmt);
  sqlite3_bind_blob(pStmt, 1, db->auth.zAuthPW, db->auth.nAuthPW,SQLITE_STATIC);
  sqlite3_bind_text(pStmt, 2, db->auth.zAuthUser, -1, SQLITE_STATIC);
  rc = sqlite3_step(pStmt);
  if( rc==SQLITE_ROW && sqlite3_column_int(pStmt,0) ){
    *pbOk = sqlite3_column_int(pStmt, 1);
    *peAuth = sqlite3_column_int(pStmt, 1) + UAUTH_User;
  }else{
    *peAuth = UAUTH_Fail;
  }
  sqlite3_finalize(pStmt);
  return rc;
}
int sqlite3UserAuthCheckLogin(
  sqlite3 *db,               /* The database connection to check */
  const char *zDb,           /* Name of specific database to check */
  u8 *peAuth                 /* OUT: One of UAUTH_* constants */
){
  int rc;
  u8 savedAuthLevel;
  savedAuthLevel = db->auth.authLevel;
  db->auth.authLevel = UAUTH_Admin;
  rc = userAuthCheckLogin(db, zDb, peAuth);
  db->auth.authLevel = savedAuthLevel;
  return rc;
}


/*
** If a database contains the SQLITE_USER table, then the
** sqlite3_user_authenticate() interface must be invoked with an
** appropriate username and password prior to enable read and write
** access to the database.
**
** Return SQLITE_OK on success or SQLITE_ERROR if the username/password
** combination is incorrect or unknown.
**
** If the SQLITE_USER table is not present in the database file, then
** this interface is a harmless no-op returnning SQLITE_OK.
*/
int sqlite3_user_authenticate(
  sqlite3 *db,           /* The database connection */
  const char *zUsername, /* Username */
  int nPW,               /* Number of bytes in aPW[] */
  const void *aPW        /* Password or credentials */
  const char *zPW        /* Password or credentials */
){
  int bOk = 0;
  int rc;

  u8 authLevel = UAUTH_Fail;
  rc = sqlite3UserAuthCheckLogin(db, zUsername, nPw, zPw, &bOk);
  if( bOk ){
    db->auth.authFlags = bOk==2 ? UAUTH_Auth|UAUTH_Admin : UAUTH_Auth;
    sqlite3_free(db->auth.zAuthUser);
    db->auth.zAuthUser = sqlite3_malloc("%s", zUsername);
    sqlite3_free(db->auth.zPw);
    db->auth.zPw = sqlite3_malloc( nPw+1 );
    if( db->auth.zPw ){
      memcpy(db->auth.zPw,zPw,nPw);
      db->auth.nPw = nPw;
      rc = SQLITE_OK;
    }else{
      rc = SQLITE_NOMEM;
    }
  db->auth.authLevel = UAUTH_Unknown;
  sqlite3_free(db->auth.zAuthUser);
  sqlite3_free(db->auth.zAuthPW);
  memset(&db->auth, 0, sizeof(db->auth));
  db->auth.zAuthUser = sqlite3_mprintf("%s", zUsername);
  if( db->auth.zAuthUser==0 ) return SQLITE_NOMEM;
  db->auth.zAuthPW = sqlite3_malloc( nPW+1 );
  if( db->auth.zAuthPW==0 ) return SQLITE_NOMEM;
  memcpy(db->auth.zAuthPW,zPW,nPW);
  db->auth.nAuthPW = nPW;
  rc = sqlite3UserAuthCheckLogin(db, "main", &authLevel);
  db->auth.authLevel = authLevel;
  if( rc ){
    return rc;           /* OOM error, I/O error, etc. */
  }
  }else{
    db->auth.authFlags = 0;
  if( authLevel<UAUTH_User ){
    return SQLITE_AUTH;  /* Incorrect username and/or password */
  }
  return rc;
  return SQLITE_OK;      /* Successful login */
}

/*
** The sqlite3_user_add() interface can be used (by an admin user only)
** to create a new user.  When called on a no-authentication-required
** database, this routine converts the database into an authentication-
** required database, automatically makes the added user an
** administrator, and logs in the current connection as that user.
** The sqlite3_user_add() interface only works for the "main" database, not
** for any ATTACH-ed databases.  Any call to sqlite3_user_add() by a
** non-admin user results in an error.
*/
int sqlite3_user_add(
  sqlite3 *db,           /* Database connection */
  const char *zUsername, /* Username to be added */
  int isAdmin,           /* True to give new user admin privilege */
  int nPW,               /* Number of bytes in aPW[] */
  const void *aPW        /* Password or credentials */
){
  if( !DbIsAdmin(db) ) return SQLITE_ERROR;
  if( db->auth.authLevel<UAUTH_Admin ) return SQLITE_ERROR;
  
  return SQLITE_OK;
}

/*
** The sqlite3_user_change() interface can be used to change a users
** login credentials or admin privilege.  Any user can change their own
** login credentials.  Only an admin user can change another users login
** credentials or admin privilege setting.  No user may change their own 
** admin privilege setting.
*/
int sqlite3_user_change(
  sqlite3 *db,           /* Database connection */
  const char *zUsername, /* Username to change */
  int isAdmin,           /* Modified admin privilege for the user */
  int nPW,               /* Number of bytes in aPW[] */
  const void *aPW        /* Modified password or credentials */
){
  if( db->auth.authLevel<UAUTH_User ) return SQLITE_ERROR;
  if( strcmp(db->auth.zAuthUser, zUsername)!=0
       && db->auth.authLevel<UAUTH_Admin ) return SQLITE_ERROR;
  return SQLITE_OK;
}

/*
** The sqlite3_user_delete() interface can be used (by an admin user only)
** to delete a user.  The currently logged-in user cannot be deleted,
** which guarantees that there is always an admin user and hence that
** the database cannot be converted into a no-authentication-required
** database.
*/
int sqlite3_user_delete(
  sqlite3 *db,           /* Database connection */
  const char *zUsername  /* Username to remove */
){
  if( db->auth.authLevel<UAUTH_Admin ) return SQLITE_ERROR;
  return SQLITE_OK;
}

#endif /* SQLITE_USER_AUTHENTICATION */
Changes to main.mk.
63
64
65
66
67
68
69
70

71
72
73
74
75
76
77
63
64
65
66
67
68
69

70
71
72
73
74
75
76
77







-
+







         main.o malloc.o mem0.o mem1.o mem2.o mem3.o mem5.o \
         memjournal.o \
         mutex.o mutex_noop.o mutex_unix.o mutex_w32.o \
         notify.o opcodes.o os.o os_unix.o os_win.o \
         pager.o pcache.o pcache1.o pragma.o prepare.o printf.o \
         random.o resolve.o rowset.o rtree.o select.o status.o \
         table.o threads.o tokenize.o trigger.o \
         update.o util.o vacuum.o \
         update.o userauth.o util.o vacuum.o \
         vdbeapi.o vdbeaux.o vdbeblob.o vdbemem.o vdbesort.o \
	 vdbetrace.o wal.o walker.o where.o utf.o vtab.o



# All of the source code files.
#
210
211
212
213
214
215
216
217



218
219
220
221
222
223
224
210
211
212
213
214
215
216

217
218
219
220
221
222
223
224
225
226







-
+
+
+







SRC += \
  $(TOP)/ext/icu/sqliteicu.h \
  $(TOP)/ext/icu/icu.c
SRC += \
  $(TOP)/ext/rtree/sqlite3rtree.h \
  $(TOP)/ext/rtree/rtree.h \
  $(TOP)/ext/rtree/rtree.c

SRC += \
  $(TOP)/ext/userauth/userauth.c \
  $(TOP)/ext/userauth/userauth.h

# Generated source code files
#
SRC += \
  keywordhash.h \
  opcodes.c \
  opcodes.h \
373
374
375
376
377
378
379


380
381
382
383
384
385
386
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390







+
+







  $(TOP)/ext/fts3/fts3Int.h \
  $(TOP)/ext/fts3/fts3_hash.h \
  $(TOP)/ext/fts3/fts3_tokenizer.h
EXTHDR += \
  $(TOP)/ext/rtree/rtree.h
EXTHDR += \
  $(TOP)/ext/icu/sqliteicu.h
EXTHDR += \
  $(TOP)/ext/userauth/userauth.h

# This is the default Makefile target.  The objects listed here
# are what get build when you type just "make" with no arguments.
#
all:	sqlite3.h libsqlite3.a sqlite3$(EXE)

libsqlite3.a:	$(LIBOBJ)
553
554
555
556
557
558
559



560
561
562
563
564
565
566
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573







+
+
+







	$(TCCX) -DSQLITE_CORE -c $(TOP)/ext/fts3/fts3_unicode2.c

fts3_write.o:	$(TOP)/ext/fts3/fts3_write.c $(HDR) $(EXTHDR)
	$(TCCX) -DSQLITE_CORE -c $(TOP)/ext/fts3/fts3_write.c

rtree.o:	$(TOP)/ext/rtree/rtree.c $(HDR) $(EXTHDR)
	$(TCCX) -DSQLITE_CORE -c $(TOP)/ext/rtree/rtree.c

userauth.o:	$(TOP)/ext/userauth/userauth.c $(HDR) $(EXTHDR)
	$(TCCX) -DSQLITE_CORE -c $(TOP)/ext/userauth/userauth.c


# Rules for building test programs and for running tests
#
tclsqlite3:	$(TOP)/src/tclsqlite.c libsqlite3.a
	$(TCCX) $(TCL_FLAGS) -DTCLSH=1 -o tclsqlite3 \
		$(TOP)/src/tclsqlite.c libsqlite3.a $(LIBTCL) $(THREADLIB)
Changes to src/build.c.
298
299
300
301
302
303
304
305



306
307
308
309
310
311
312
298
299
300
301
302
303
304

305
306
307
308
309
310
311
312
313
314







-
+
+
+







  int i;
  assert( zName!=0 );
  /* All mutexes are required for schema access.  Make sure we hold them. */
  assert( zDatabase!=0 || sqlite3BtreeHoldsAllMutexes(db) );
#if SQLITE_USER_AUTHENTICATION
  /* Only the admin user is allowed to know that the sqlite_user table
  ** exists */
  if( DbIsAdmin(db)==0 && sqlite3UserAuthTable(zName)!=0 ) return 0;
  if( db->auth.authLevel<UAUTH_Admin && sqlite3UserAuthTable(zName)!=0 ){
    return 0;
  }
#endif
  for(i=OMIT_TEMPDB; i<db->nDb; i++){
    int j = (i<2) ? i^1 : i;   /* Search TEMP before MAIN */
    if( zDatabase!=0 && sqlite3StrICmp(zDatabase, db->aDb[j].zName) ) continue;
    assert( sqlite3SchemaMutexHeld(db, j, 0) );
    p = sqlite3HashFind(&db->aDb[j].pSchema->tblHash, zName);
    if( p ) break;
344
345
346
347
348
349
350






351
352
353
354
355
356
357
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365







+
+
+
+
+
+







    if( zDbase ){
      sqlite3ErrorMsg(pParse, "%s: %s.%s", zMsg, zDbase, zName);
    }else{
      sqlite3ErrorMsg(pParse, "%s: %s", zMsg, zName);
    }
    pParse->checkSchema = 1;
  }
#if SQLITE_USER_AUTHENICATION
  else if( pParse->db->auth.authLevel<UAUTH_User ){
    sqlite3ErrorMsg(pParse, "user not authenticated");
    p = 0;
  }
#endif
  return p;
}

/*
** Locate the table identified by *p.
**
** This is a wrapper around sqlite3LocateTable(). The difference between
Changes to src/main.c.
2566
2567
2568
2569
2570
2571
2572
2573
2574
2575
2576
2577
2578
2579
2580
2581
2582
2583
2566
2567
2568
2569
2570
2571
2572




2573
2574
2575
2576
2577
2578
2579







-
-
-
-







    }
    sqlite3Error(db, rc);
    goto opendb_out;
  }
  db->aDb[0].pSchema = sqlite3SchemaGet(db, db->aDb[0].pBt);
  db->aDb[1].pSchema = sqlite3SchemaGet(db, 0);

#if SQLITE_USER_AUTHENTICATION
  db->auth.authFlags = UAUTH_Auth|UAUTH_Admin;
#endif

  /* The default safety_level for the main database is 'full'; for the temp
  ** database it is 'NONE'. This matches the pager layer defaults.  
  */
  db->aDb[0].zName = "main";
  db->aDb[0].safety_level = 3;
  db->aDb[1].zName = "temp";
  db->aDb[1].safety_level = 1;
Changes to src/pragma.c.
1394
1395
1396
1397
1398
1399
1400
1401

1402
1403
1404
1405
1406
1407
1408
1394
1395
1396
1397
1398
1399
1400

1401
1402
1403
1404
1405
1406
1407
1408







-
+







      int mask = aPragmaNames[mid].iArg;    /* Mask of bits to set or clear. */
      if( db->autoCommit==0 ){
        /* Foreign key support may not be enabled or disabled while not
        ** in auto-commit mode.  */
        mask &= ~(SQLITE_ForeignKeys);
      }
#if SQLITE_USER_AUTHENTICATION
      if( !DbIsAdmin(db) ){
      if( db->auth.authLevel<UAUTH_Admin ){
        /* Do not allow non-admin users to modify the schema arbitrarily */
        mask &= ~(SQLITE_WriteSchema);
      }
#endif

      if( sqlite3GetBoolean(zRight, 0) ){
        db->flags |= mask;
Changes to src/prepare.c.
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
202
203
204
205
206
207
208



209
210
211
212
213
214
215







-
-
-







    rc = initData.rc;
    goto error_out;
  }
  pTab = sqlite3FindTable(db, zMasterName, db->aDb[iDb].zName);
  if( ALWAYS(pTab) ){
    pTab->tabFlags |= TF_Readonly;
  }
#if SQLITE_USER_AUTHENTICATION
  db->auth.authFlags = UAUTH_Auth|UAUTH_Admin;
#endif

  /* Create a cursor to hold the database open
  */
  pDb = &db->aDb[iDb];
  if( pDb->pBt==0 ){
    if( !OMIT_TEMPDB && ALWAYS(iDb==1) ){
      DbSetProperty(db, 1, DB_SchemaLoaded);
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
357
358
359
360
361
362
363








364
365
366
367
368
369
370







-
-
-
-
-
-
-
-







    ** of the schema was loaded before the error occurred. The primary
    ** purpose of this is to allow access to the sqlite_master table
    ** even when its contents have been corrupted.
    */
    DbSetProperty(db, iDb, DB_SchemaLoaded);
    rc = SQLITE_OK;
  }
#if SQLITE_USER_AUTHENTICATION
  if( rc==SQLITE_OK && iDb!=1 ){
    if( sqlite3FindTable(db, "sqlite_user", db->aDb[iDb].zName)!=0 ){
      db->auth.authFlags = UAUTH_AuthReqd;
    }
  }
#endif


  /* Jump here for an error that occurs after successfully allocating
  ** curMain and calling sqlite3BtreeEnter(). For an error that occurs
  ** before that point, jump to error_out.
  */
initone_error_out:
  if( openedTransaction ){
416
417
418
419
420
421
422
423
424


425
426
427
428
429
430
431
405
406
407
408
409
410
411


412
413
414
415
416
417
418
419
420







-
-
+
+







  }

  /* Once all the other databases have been initialized, load the schema
  ** for the TEMP database. This is loaded last, as the TEMP database
  ** schema may contain references to objects in other databases.
  */
#ifndef SQLITE_OMIT_TEMPDB
  if( rc==SQLITE_OK && ALWAYS(db->nDb>1)
                    && !DbHasProperty(db, 1, DB_SchemaLoaded) ){
  assert( db->nDb>1 );
  if( rc==SQLITE_OK && !DbHasProperty(db, 1, DB_SchemaLoaded) ){
    rc = sqlite3InitOne(db, 1, pzErrMsg);
    if( rc ){
      sqlite3ResetOneSchema(db, 1);
    }
  }
#endif

721
722
723
724
725
726
727














728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736











737
738
739
740
741
742
743







+
+
+
+
+
+
+
+
+
+
+
+
+
+






-
-
-
-
-
-
-
-
-
-
-







  int rc;
  assert( ppStmt!=0 );
  *ppStmt = 0;
  if( !sqlite3SafetyCheckOk(db) ){
    return SQLITE_MISUSE_BKPT;
  }
  sqlite3_mutex_enter(db->mutex);
#if SQLITE_USER_AUTHENTICATION
  if( db->auth.authLevel<UAUTH_User ){
    if( db->auth.authLevel==UAUTH_Unknown ){
      u8 authLevel = UAUTH_Fail;
      sqlite3UserAuthCheckLogin(db, "main", &authLevel);
      db->auth.authLevel = authLevel;
    }
    if( db->auth.authLevel<UAUTH_User ){
      sqlite3ErrorWithMsg(db, SQLITE_ERROR, "user not authenticated");
      sqlite3_mutex_leave(db->mutex);
      return SQLITE_ERROR;
    }
  }
#endif
  sqlite3BtreeEnterAll(db);
  rc = sqlite3Prepare(db, zSql, nBytes, saveSqlFlag, pOld, ppStmt, pzTail);
  if( rc==SQLITE_SCHEMA ){
    sqlite3_finalize(*ppStmt);
    rc = sqlite3Prepare(db, zSql, nBytes, saveSqlFlag, pOld, ppStmt, pzTail);
  }
#if SQLITE_USER_AUTHENTICATION
  assert( rc==SQLITE_OK || *ppStmt==0 );
printf("rc=%d init=%d auth=%d sql=[%.50s]\n", rc, db->init.busy, db->auth.authFlags, zSql);
fflush(stdout);
  if( rc==SQLITE_OK && !DbIsAuth(db) && db->init.busy==0 ){
    sqlite3_finalize(*ppStmt);
    *ppStmt = 0;
    sqlite3ErrorWithMsg(db, SQLITE_ERROR, "user not authenticated");
    rc = SQLITE_ERROR;
  }
#endif
  sqlite3BtreeLeaveAll(db);
  sqlite3_mutex_leave(db->mutex);
  assert( rc==SQLITE_OK || *ppStmt==0 );
  return rc;
}

/*
Changes to src/sqliteInt.h.
991
992
993
994
995
996
997
998

999
1000
1001
1002
1003
1004
1005
1006
1007




1008
1009

1010
1011
1012
1013
1014
1015

1016
1017
1018
1019
1020
1021
1022
991
992
993
994
995
996
997

998
999
1000
1001
1002
1003




1004
1005
1006
1007


1008



1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019







-
+





-
-
-
-
+
+
+
+
-
-
+
-
-
-



+







#ifdef SQLITE_USER_AUTHENTICATION
/*
** Information held in the "sqlite3" database connection object and used
** to manage user authentication.
*/
typedef struct sqlite3_userauth sqlite3_userauth;
struct sqlite3_userauth {
  u8 authFlags;                 /* Status flags for user authentication */
  u8 authLevel;                 /* Current authentication level */
  int nAuthPW;                  /* Size of the zAuthPW in bytes */
  char *zAuthPW;                /* Password used to authenticate */
  char *zAuthUser;              /* User name used to authenticate */
};

/* Allowed values for sqlite3_userauth.authFlags */
#define UAUTH_Ovrd        0x01  /* Do not enforce access restrictions */
#define UAUTH_Auth        0x02  /* True if the user has authenticated */
#define UAUTH_Admin       0x04  /* True if the user is an administrator */
/* Allowed values for sqlite3_userauth.authLevel */
#define UAUTH_Unknown     0     /* Authentication not yet checked */
#define UAUTH_Fail        1     /* User authentication failed */
#define UAUTH_User        2     /* Authenticated as a normal user */
#define UAUTH_AuthReqd    0x08  /* True if main has an sqlite_user table */

#define UAUTH_Admin       3     /* Authenticated as an administrator */
/* Macros for accessing sqlite3.auth.authFlags */
#define DbIsAuth(D)       (((D)->auth.authFlags&UAUTH_Auth)!=0)
#define DbIsAdmin(D)      (((D)->auth.authFlags&UAUTH_Admin)!=0)

/* Functions used only by user authorization logic */
int sqlite3UserAuthTable(const char*);
int sqlite3UserAuthCheckLogin(sqlite3*,const char*,u8*);

#endif /* SQLITE_USER_AUTHENTICATION */


/*
** Each database connection is an instance of the following structure.
*/