Fossil SCM

clean up error handling and permissions for various /json/user/save cases.

stephan 2012-03-17 14:59 trunk
Commit d2bb7aeaa6590afa674ab00ea4b0ec43c88795e6
1 file changed +47 -37
+47 -37
--- src/json_user.c
+++ src/json_user.c
@@ -24,20 +24,15 @@
2424
#endif
2525
2626
static cson_value * json_user_get();
2727
static cson_value * json_user_list();
2828
static cson_value * json_user_save();
29
-#if 0
30
-static cson_value * json_user_create();
31
-
32
-#endif
3329
3430
/*
3531
** Mapping of /json/user/XXX commands/paths to callbacks.
3632
*/
3733
static const JsonPageDef JsonPageDefs_User[] = {
38
-{"create", json_page_nyi, 0},
3934
{"save", json_user_save, 0},
4035
{"get", json_user_get, 0},
4136
{"list", json_user_list, 0},
4237
/* Last entry MUST have a NULL name. */
4338
{NULL,NULL,0}
@@ -52,11 +47,11 @@
5247
return json_page_dispatch_helper(&JsonPageDefs_User[0]);
5348
}
5449
5550
5651
/*
57
-** Impl of /json/user/list. Requires admin rights.
52
+** Impl of /json/user/list. Requires admin/setup rights.
5853
*/
5954
static cson_value * json_user_list(){
6055
cson_value * payV = NULL;
6156
Stmt q;
6257
if(!g.perm.Admin && !g.perm.Setup){
@@ -102,11 +97,11 @@
10297
db_finalize(&q);
10398
return u;
10499
}
105100
106101
/*
107
-** Identical to _load_user_by_name(), but expects a user ID. Returns
102
+** Identical to json_load_user_by_name(), but expects a user ID. Returns
108103
** NULL if no user found with that ID.
109104
*/
110105
static cson_value * json_load_user_by_id(int uid){
111106
cson_value * u = NULL;
112107
Stmt q;
@@ -125,11 +120,11 @@
125120
return u;
126121
}
127122
128123
129124
/*
130
-** Impl of /json/user/get. Requires admin rights.
125
+** Impl of /json/user/get. Requires admin or setup rights.
131126
*/
132127
static cson_value * json_user_get(){
133128
cson_value * payV = NULL;
134129
char const * pUser = NULL;
135130
if(!g.perm.Admin && !g.perm.Setup){
@@ -165,16 +160,16 @@
165160
** are not included in pUser.
166161
**
167162
** If uid is specified then name may refer to a _new_ name
168163
** for a user, otherwise the name must refer to an existing user.
169164
** If uid=-1 then the name must be specified and a new user is
170
-** created (failes if one already exists).
165
+** created (fails if one already exists).
171166
**
172167
** If uid is not set, this function might modify pUser to contain the
173168
** db-found (or inserted) user ID.
174169
**
175
-** On error g.json's error state is set one of the FSL_JSON_E_xxx
170
+** On error g.json's error state is set and one of the FSL_JSON_E_xxx
176171
** values from FossilJsonCodes is returned.
177172
**
178173
** On success the db record for the given user is updated.
179174
**
180175
** Requires either Admin, Setup, or Password access. Non-admin/setup
@@ -218,18 +213,21 @@
218213
}
219214
zName = zNameFree;
220215
}else if(-1==uid){
221216
/* try to create a new user */
222217
if(!g.perm.Admin && !g.perm.Setup){
223
- return json_set_err(FSL_JSON_E_DENIED,
224
- "Requires 'a' or 's' privileges.");
218
+ json_set_err(FSL_JSON_E_DENIED,
219
+ "Requires 'a' or 's' privileges.");
220
+ goto error;
225221
}else if(!zName || !*zName){
226
- return json_set_err(FSL_JSON_E_MISSING_ARGS,
227
- "No name specified for new user.");
222
+ json_set_err(FSL_JSON_E_MISSING_ARGS,
223
+ "No name specified for new user.");
224
+ goto error;
228225
}else if( db_exists("SELECT 1 FROM user WHERE login=%Q", zName) ){
229
- return json_set_err(FSL_JSON_E_RESOURCE_ALREADY_EXISTS,
230
- "User %s already exists.", zName);
226
+ json_set_err(FSL_JSON_E_RESOURCE_ALREADY_EXISTS,
227
+ "User %s already exists.", zName);
228
+ goto error;
231229
}else{
232230
Stmt ins = empty_Stmt;
233231
db_prepare(&ins, "INSERT INTO user (login) VALUES(%Q)",zName);
234232
db_step( &ins );
235233
db_finalize(&ins);
@@ -239,12 +237,13 @@
239237
cson_object_set( pUser, "uid", cson_value_new_integer(uid) );
240238
}
241239
}else{
242240
uid = db_int(0,"SELECT uid FROM user WHERE login=%Q", zName);
243241
if(uid<=0){
244
- return json_set_err(FSL_JSON_E_RESOURCE_NOT_FOUND,
245
- "No login found for user [%s].", zName);
242
+ json_set_err(FSL_JSON_E_RESOURCE_NOT_FOUND,
243
+ "No login found for user [%s].", zName);
244
+ goto error;
246245
}
247246
cson_object_set( pUser, "uid", cson_value_new_integer(uid) );
248247
}
249248
250249
/* Maintenance note: all error-returns from here on out should go
@@ -254,10 +253,11 @@
254253
if(uid != g.userUid){
255254
if(!g.perm.Admin && !g.perm.Setup){
256255
json_set_err(FSL_JSON_E_DENIED,
257256
"Changing another user's data requires "
258257
"'a' or 's' privileges.");
258
+ goto error;
259259
}
260260
}
261261
/* check if the target uid currently has setup rights. */
262262
tgtHadSetup = db_int(0,"SELECT 1 FROM user where uid=%d"
263263
" AND cap GLOB '*s*'", uid);
@@ -265,13 +265,14 @@
265265
if((tgtHasSetup || tgtHadSetup) && !g.perm.Setup){
266266
/*
267267
Do not allow a non-setup user to set or remove setup
268268
privileges. setup.c uses similar logic.
269269
*/
270
- return json_set_err(FSL_JSON_E_DENIED,
271
- "Modifying 's' users/privileges requires "
272
- "'s' privileges.");
270
+ json_set_err(FSL_JSON_E_DENIED,
271
+ "Modifying 's' users/privileges requires "
272
+ "'s' privileges.");
273
+ goto error;
273274
}
274275
/*
275276
Potential todo: do not allow a setup user to remove 's' from
276277
himself, to avoid locking himself out?
277278
*/
@@ -297,34 +298,43 @@
297298
blob_appendf(&sql, ", login=%Q", zNameNew);
298299
++gotFields;
299300
}
300301
}
301302
302
- if( zCap ){
303
+ if( zCap && *zCap ){
304
+ if(!g.perm.Admin || !g.perm.Setup){
305
+ /* we "could" arguably silently ignore cap in this case. */
306
+ json_set_err(FSL_JSON_E_DENIED,
307
+ "Changing capabilities requires 'a' or 's' privileges.");
308
+ goto error;
309
+ }
303310
blob_appendf(&sql, ", cap=%Q", zCap);
304311
++gotFields;
305312
}
306
-#define TRY_LOGIN_GROUP 0 /* login group support is not yet implemented. */
313
+
307314
if( zPW && *zPW ){
308315
if(!g.perm.Admin && !g.perm.Setup && !g.perm.Password){
309
- return json_set_err( FSL_JSON_E_DENIED,
310
- "Password change requires 'a', 's', "
311
- "or 'p' permissions.");
312
- }
316
+ json_set_err( FSL_JSON_E_DENIED,
317
+ "Password change requires 'a', 's', "
318
+ "or 'p' permissions.");
319
+ goto error;
320
+ }else{
321
+#define TRY_LOGIN_GROUP 0 /* login group support is not yet implemented. */
313322
#if !TRY_LOGIN_GROUP
314
- char * zPWHash = NULL;
315
- ++gotFields;
316
- zPWHash = sha1_shared_secret(zPW, zNameNew ? zNameNew : zName, NULL);
317
- blob_appendf(&sql, ", pw=%Q", zPWHash);
318
- free(zPWHash);
323
+ char * zPWHash = NULL;
324
+ ++gotFields;
325
+ zPWHash = sha1_shared_secret(zPW, zNameNew ? zNameNew : zName, NULL);
326
+ blob_appendf(&sql, ", pw=%Q", zPWHash);
327
+ free(zPWHash);
319328
#else
320
- ++gotFields;
321
- blob_appendf(&sql, ", pw=coalesce(shared_secret(%Q,%Q,"
322
- "(SELECT value FROM config WHERE name='project-code')))",
323
- zPW, zNameNew ? zNameNew : zName);
324
- /* shared_secret() func is undefined? */
329
+ ++gotFields;
330
+ blob_appendf(&sql, ", pw=coalesce(shared_secret(%Q,%Q,"
331
+ "(SELECT value FROM config WHERE name='project-code')))",
332
+ zPW, zNameNew ? zNameNew : zName);
333
+ /* shared_secret() func is undefined? */
325334
#endif
335
+ }
326336
}
327337
328338
if( zInfo ){
329339
blob_appendf(&sql, ", info=%Q", zInfo);
330340
++gotFields;
331341
--- src/json_user.c
+++ src/json_user.c
@@ -24,20 +24,15 @@
24 #endif
25
26 static cson_value * json_user_get();
27 static cson_value * json_user_list();
28 static cson_value * json_user_save();
29 #if 0
30 static cson_value * json_user_create();
31
32 #endif
33
34 /*
35 ** Mapping of /json/user/XXX commands/paths to callbacks.
36 */
37 static const JsonPageDef JsonPageDefs_User[] = {
38 {"create", json_page_nyi, 0},
39 {"save", json_user_save, 0},
40 {"get", json_user_get, 0},
41 {"list", json_user_list, 0},
42 /* Last entry MUST have a NULL name. */
43 {NULL,NULL,0}
@@ -52,11 +47,11 @@
52 return json_page_dispatch_helper(&JsonPageDefs_User[0]);
53 }
54
55
56 /*
57 ** Impl of /json/user/list. Requires admin rights.
58 */
59 static cson_value * json_user_list(){
60 cson_value * payV = NULL;
61 Stmt q;
62 if(!g.perm.Admin && !g.perm.Setup){
@@ -102,11 +97,11 @@
102 db_finalize(&q);
103 return u;
104 }
105
106 /*
107 ** Identical to _load_user_by_name(), but expects a user ID. Returns
108 ** NULL if no user found with that ID.
109 */
110 static cson_value * json_load_user_by_id(int uid){
111 cson_value * u = NULL;
112 Stmt q;
@@ -125,11 +120,11 @@
125 return u;
126 }
127
128
129 /*
130 ** Impl of /json/user/get. Requires admin rights.
131 */
132 static cson_value * json_user_get(){
133 cson_value * payV = NULL;
134 char const * pUser = NULL;
135 if(!g.perm.Admin && !g.perm.Setup){
@@ -165,16 +160,16 @@
165 ** are not included in pUser.
166 **
167 ** If uid is specified then name may refer to a _new_ name
168 ** for a user, otherwise the name must refer to an existing user.
169 ** If uid=-1 then the name must be specified and a new user is
170 ** created (failes if one already exists).
171 **
172 ** If uid is not set, this function might modify pUser to contain the
173 ** db-found (or inserted) user ID.
174 **
175 ** On error g.json's error state is set one of the FSL_JSON_E_xxx
176 ** values from FossilJsonCodes is returned.
177 **
178 ** On success the db record for the given user is updated.
179 **
180 ** Requires either Admin, Setup, or Password access. Non-admin/setup
@@ -218,18 +213,21 @@
218 }
219 zName = zNameFree;
220 }else if(-1==uid){
221 /* try to create a new user */
222 if(!g.perm.Admin && !g.perm.Setup){
223 return json_set_err(FSL_JSON_E_DENIED,
224 "Requires 'a' or 's' privileges.");
 
225 }else if(!zName || !*zName){
226 return json_set_err(FSL_JSON_E_MISSING_ARGS,
227 "No name specified for new user.");
 
228 }else if( db_exists("SELECT 1 FROM user WHERE login=%Q", zName) ){
229 return json_set_err(FSL_JSON_E_RESOURCE_ALREADY_EXISTS,
230 "User %s already exists.", zName);
 
231 }else{
232 Stmt ins = empty_Stmt;
233 db_prepare(&ins, "INSERT INTO user (login) VALUES(%Q)",zName);
234 db_step( &ins );
235 db_finalize(&ins);
@@ -239,12 +237,13 @@
239 cson_object_set( pUser, "uid", cson_value_new_integer(uid) );
240 }
241 }else{
242 uid = db_int(0,"SELECT uid FROM user WHERE login=%Q", zName);
243 if(uid<=0){
244 return json_set_err(FSL_JSON_E_RESOURCE_NOT_FOUND,
245 "No login found for user [%s].", zName);
 
246 }
247 cson_object_set( pUser, "uid", cson_value_new_integer(uid) );
248 }
249
250 /* Maintenance note: all error-returns from here on out should go
@@ -254,10 +253,11 @@
254 if(uid != g.userUid){
255 if(!g.perm.Admin && !g.perm.Setup){
256 json_set_err(FSL_JSON_E_DENIED,
257 "Changing another user's data requires "
258 "'a' or 's' privileges.");
 
259 }
260 }
261 /* check if the target uid currently has setup rights. */
262 tgtHadSetup = db_int(0,"SELECT 1 FROM user where uid=%d"
263 " AND cap GLOB '*s*'", uid);
@@ -265,13 +265,14 @@
265 if((tgtHasSetup || tgtHadSetup) && !g.perm.Setup){
266 /*
267 Do not allow a non-setup user to set or remove setup
268 privileges. setup.c uses similar logic.
269 */
270 return json_set_err(FSL_JSON_E_DENIED,
271 "Modifying 's' users/privileges requires "
272 "'s' privileges.");
 
273 }
274 /*
275 Potential todo: do not allow a setup user to remove 's' from
276 himself, to avoid locking himself out?
277 */
@@ -297,34 +298,43 @@
297 blob_appendf(&sql, ", login=%Q", zNameNew);
298 ++gotFields;
299 }
300 }
301
302 if( zCap ){
 
 
 
 
 
 
303 blob_appendf(&sql, ", cap=%Q", zCap);
304 ++gotFields;
305 }
306 #define TRY_LOGIN_GROUP 0 /* login group support is not yet implemented. */
307 if( zPW && *zPW ){
308 if(!g.perm.Admin && !g.perm.Setup && !g.perm.Password){
309 return json_set_err( FSL_JSON_E_DENIED,
310 "Password change requires 'a', 's', "
311 "or 'p' permissions.");
312 }
 
 
313 #if !TRY_LOGIN_GROUP
314 char * zPWHash = NULL;
315 ++gotFields;
316 zPWHash = sha1_shared_secret(zPW, zNameNew ? zNameNew : zName, NULL);
317 blob_appendf(&sql, ", pw=%Q", zPWHash);
318 free(zPWHash);
319 #else
320 ++gotFields;
321 blob_appendf(&sql, ", pw=coalesce(shared_secret(%Q,%Q,"
322 "(SELECT value FROM config WHERE name='project-code')))",
323 zPW, zNameNew ? zNameNew : zName);
324 /* shared_secret() func is undefined? */
325 #endif
 
326 }
327
328 if( zInfo ){
329 blob_appendf(&sql, ", info=%Q", zInfo);
330 ++gotFields;
331
--- src/json_user.c
+++ src/json_user.c
@@ -24,20 +24,15 @@
24 #endif
25
26 static cson_value * json_user_get();
27 static cson_value * json_user_list();
28 static cson_value * json_user_save();
 
 
 
 
29
30 /*
31 ** Mapping of /json/user/XXX commands/paths to callbacks.
32 */
33 static const JsonPageDef JsonPageDefs_User[] = {
 
34 {"save", json_user_save, 0},
35 {"get", json_user_get, 0},
36 {"list", json_user_list, 0},
37 /* Last entry MUST have a NULL name. */
38 {NULL,NULL,0}
@@ -52,11 +47,11 @@
47 return json_page_dispatch_helper(&JsonPageDefs_User[0]);
48 }
49
50
51 /*
52 ** Impl of /json/user/list. Requires admin/setup rights.
53 */
54 static cson_value * json_user_list(){
55 cson_value * payV = NULL;
56 Stmt q;
57 if(!g.perm.Admin && !g.perm.Setup){
@@ -102,11 +97,11 @@
97 db_finalize(&q);
98 return u;
99 }
100
101 /*
102 ** Identical to json_load_user_by_name(), but expects a user ID. Returns
103 ** NULL if no user found with that ID.
104 */
105 static cson_value * json_load_user_by_id(int uid){
106 cson_value * u = NULL;
107 Stmt q;
@@ -125,11 +120,11 @@
120 return u;
121 }
122
123
124 /*
125 ** Impl of /json/user/get. Requires admin or setup rights.
126 */
127 static cson_value * json_user_get(){
128 cson_value * payV = NULL;
129 char const * pUser = NULL;
130 if(!g.perm.Admin && !g.perm.Setup){
@@ -165,16 +160,16 @@
160 ** are not included in pUser.
161 **
162 ** If uid is specified then name may refer to a _new_ name
163 ** for a user, otherwise the name must refer to an existing user.
164 ** If uid=-1 then the name must be specified and a new user is
165 ** created (fails if one already exists).
166 **
167 ** If uid is not set, this function might modify pUser to contain the
168 ** db-found (or inserted) user ID.
169 **
170 ** On error g.json's error state is set and one of the FSL_JSON_E_xxx
171 ** values from FossilJsonCodes is returned.
172 **
173 ** On success the db record for the given user is updated.
174 **
175 ** Requires either Admin, Setup, or Password access. Non-admin/setup
@@ -218,18 +213,21 @@
213 }
214 zName = zNameFree;
215 }else if(-1==uid){
216 /* try to create a new user */
217 if(!g.perm.Admin && !g.perm.Setup){
218 json_set_err(FSL_JSON_E_DENIED,
219 "Requires 'a' or 's' privileges.");
220 goto error;
221 }else if(!zName || !*zName){
222 json_set_err(FSL_JSON_E_MISSING_ARGS,
223 "No name specified for new user.");
224 goto error;
225 }else if( db_exists("SELECT 1 FROM user WHERE login=%Q", zName) ){
226 json_set_err(FSL_JSON_E_RESOURCE_ALREADY_EXISTS,
227 "User %s already exists.", zName);
228 goto error;
229 }else{
230 Stmt ins = empty_Stmt;
231 db_prepare(&ins, "INSERT INTO user (login) VALUES(%Q)",zName);
232 db_step( &ins );
233 db_finalize(&ins);
@@ -239,12 +237,13 @@
237 cson_object_set( pUser, "uid", cson_value_new_integer(uid) );
238 }
239 }else{
240 uid = db_int(0,"SELECT uid FROM user WHERE login=%Q", zName);
241 if(uid<=0){
242 json_set_err(FSL_JSON_E_RESOURCE_NOT_FOUND,
243 "No login found for user [%s].", zName);
244 goto error;
245 }
246 cson_object_set( pUser, "uid", cson_value_new_integer(uid) );
247 }
248
249 /* Maintenance note: all error-returns from here on out should go
@@ -254,10 +253,11 @@
253 if(uid != g.userUid){
254 if(!g.perm.Admin && !g.perm.Setup){
255 json_set_err(FSL_JSON_E_DENIED,
256 "Changing another user's data requires "
257 "'a' or 's' privileges.");
258 goto error;
259 }
260 }
261 /* check if the target uid currently has setup rights. */
262 tgtHadSetup = db_int(0,"SELECT 1 FROM user where uid=%d"
263 " AND cap GLOB '*s*'", uid);
@@ -265,13 +265,14 @@
265 if((tgtHasSetup || tgtHadSetup) && !g.perm.Setup){
266 /*
267 Do not allow a non-setup user to set or remove setup
268 privileges. setup.c uses similar logic.
269 */
270 json_set_err(FSL_JSON_E_DENIED,
271 "Modifying 's' users/privileges requires "
272 "'s' privileges.");
273 goto error;
274 }
275 /*
276 Potential todo: do not allow a setup user to remove 's' from
277 himself, to avoid locking himself out?
278 */
@@ -297,34 +298,43 @@
298 blob_appendf(&sql, ", login=%Q", zNameNew);
299 ++gotFields;
300 }
301 }
302
303 if( zCap && *zCap ){
304 if(!g.perm.Admin || !g.perm.Setup){
305 /* we "could" arguably silently ignore cap in this case. */
306 json_set_err(FSL_JSON_E_DENIED,
307 "Changing capabilities requires 'a' or 's' privileges.");
308 goto error;
309 }
310 blob_appendf(&sql, ", cap=%Q", zCap);
311 ++gotFields;
312 }
313
314 if( zPW && *zPW ){
315 if(!g.perm.Admin && !g.perm.Setup && !g.perm.Password){
316 json_set_err( FSL_JSON_E_DENIED,
317 "Password change requires 'a', 's', "
318 "or 'p' permissions.");
319 goto error;
320 }else{
321 #define TRY_LOGIN_GROUP 0 /* login group support is not yet implemented. */
322 #if !TRY_LOGIN_GROUP
323 char * zPWHash = NULL;
324 ++gotFields;
325 zPWHash = sha1_shared_secret(zPW, zNameNew ? zNameNew : zName, NULL);
326 blob_appendf(&sql, ", pw=%Q", zPWHash);
327 free(zPWHash);
328 #else
329 ++gotFields;
330 blob_appendf(&sql, ", pw=coalesce(shared_secret(%Q,%Q,"
331 "(SELECT value FROM config WHERE name='project-code')))",
332 zPW, zNameNew ? zNameNew : zName);
333 /* shared_secret() func is undefined? */
334 #endif
335 }
336 }
337
338 if( zInfo ){
339 blob_appendf(&sql, ", info=%Q", zInfo);
340 ++gotFields;
341

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button