Fossil SCM
clean up error handling and permissions for various /json/user/save cases.
Commit
d2bb7aeaa6590afa674ab00ea4b0ec43c88795e6
Parent
0d6b73f07d538c8…
1 file changed
+47
-37
+47
-37
| --- src/json_user.c | ||
| +++ src/json_user.c | ||
| @@ -24,20 +24,15 @@ | ||
| 24 | 24 | #endif |
| 25 | 25 | |
| 26 | 26 | static cson_value * json_user_get(); |
| 27 | 27 | static cson_value * json_user_list(); |
| 28 | 28 | static cson_value * json_user_save(); |
| 29 | -#if 0 | |
| 30 | -static cson_value * json_user_create(); | |
| 31 | - | |
| 32 | -#endif | |
| 33 | 29 | |
| 34 | 30 | /* |
| 35 | 31 | ** Mapping of /json/user/XXX commands/paths to callbacks. |
| 36 | 32 | */ |
| 37 | 33 | static const JsonPageDef JsonPageDefs_User[] = { |
| 38 | -{"create", json_page_nyi, 0}, | |
| 39 | 34 | {"save", json_user_save, 0}, |
| 40 | 35 | {"get", json_user_get, 0}, |
| 41 | 36 | {"list", json_user_list, 0}, |
| 42 | 37 | /* Last entry MUST have a NULL name. */ |
| 43 | 38 | {NULL,NULL,0} |
| @@ -52,11 +47,11 @@ | ||
| 52 | 47 | return json_page_dispatch_helper(&JsonPageDefs_User[0]); |
| 53 | 48 | } |
| 54 | 49 | |
| 55 | 50 | |
| 56 | 51 | /* |
| 57 | -** Impl of /json/user/list. Requires admin rights. | |
| 52 | +** Impl of /json/user/list. Requires admin/setup rights. | |
| 58 | 53 | */ |
| 59 | 54 | static cson_value * json_user_list(){ |
| 60 | 55 | cson_value * payV = NULL; |
| 61 | 56 | Stmt q; |
| 62 | 57 | if(!g.perm.Admin && !g.perm.Setup){ |
| @@ -102,11 +97,11 @@ | ||
| 102 | 97 | db_finalize(&q); |
| 103 | 98 | return u; |
| 104 | 99 | } |
| 105 | 100 | |
| 106 | 101 | /* |
| 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 | |
| 108 | 103 | ** NULL if no user found with that ID. |
| 109 | 104 | */ |
| 110 | 105 | static cson_value * json_load_user_by_id(int uid){ |
| 111 | 106 | cson_value * u = NULL; |
| 112 | 107 | Stmt q; |
| @@ -125,11 +120,11 @@ | ||
| 125 | 120 | return u; |
| 126 | 121 | } |
| 127 | 122 | |
| 128 | 123 | |
| 129 | 124 | /* |
| 130 | -** Impl of /json/user/get. Requires admin rights. | |
| 125 | +** Impl of /json/user/get. Requires admin or setup rights. | |
| 131 | 126 | */ |
| 132 | 127 | static cson_value * json_user_get(){ |
| 133 | 128 | cson_value * payV = NULL; |
| 134 | 129 | char const * pUser = NULL; |
| 135 | 130 | if(!g.perm.Admin && !g.perm.Setup){ |
| @@ -165,16 +160,16 @@ | ||
| 165 | 160 | ** are not included in pUser. |
| 166 | 161 | ** |
| 167 | 162 | ** If uid is specified then name may refer to a _new_ name |
| 168 | 163 | ** for a user, otherwise the name must refer to an existing user. |
| 169 | 164 | ** 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). | |
| 171 | 166 | ** |
| 172 | 167 | ** If uid is not set, this function might modify pUser to contain the |
| 173 | 168 | ** db-found (or inserted) user ID. |
| 174 | 169 | ** |
| 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 | |
| 176 | 171 | ** values from FossilJsonCodes is returned. |
| 177 | 172 | ** |
| 178 | 173 | ** On success the db record for the given user is updated. |
| 179 | 174 | ** |
| 180 | 175 | ** Requires either Admin, Setup, or Password access. Non-admin/setup |
| @@ -218,18 +213,21 @@ | ||
| 218 | 213 | } |
| 219 | 214 | zName = zNameFree; |
| 220 | 215 | }else if(-1==uid){ |
| 221 | 216 | /* try to create a new user */ |
| 222 | 217 | 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; | |
| 225 | 221 | }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; | |
| 228 | 225 | }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; | |
| 231 | 229 | }else{ |
| 232 | 230 | Stmt ins = empty_Stmt; |
| 233 | 231 | db_prepare(&ins, "INSERT INTO user (login) VALUES(%Q)",zName); |
| 234 | 232 | db_step( &ins ); |
| 235 | 233 | db_finalize(&ins); |
| @@ -239,12 +237,13 @@ | ||
| 239 | 237 | cson_object_set( pUser, "uid", cson_value_new_integer(uid) ); |
| 240 | 238 | } |
| 241 | 239 | }else{ |
| 242 | 240 | uid = db_int(0,"SELECT uid FROM user WHERE login=%Q", zName); |
| 243 | 241 | 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; | |
| 246 | 245 | } |
| 247 | 246 | cson_object_set( pUser, "uid", cson_value_new_integer(uid) ); |
| 248 | 247 | } |
| 249 | 248 | |
| 250 | 249 | /* Maintenance note: all error-returns from here on out should go |
| @@ -254,10 +253,11 @@ | ||
| 254 | 253 | if(uid != g.userUid){ |
| 255 | 254 | if(!g.perm.Admin && !g.perm.Setup){ |
| 256 | 255 | json_set_err(FSL_JSON_E_DENIED, |
| 257 | 256 | "Changing another user's data requires " |
| 258 | 257 | "'a' or 's' privileges."); |
| 258 | + goto error; | |
| 259 | 259 | } |
| 260 | 260 | } |
| 261 | 261 | /* check if the target uid currently has setup rights. */ |
| 262 | 262 | tgtHadSetup = db_int(0,"SELECT 1 FROM user where uid=%d" |
| 263 | 263 | " AND cap GLOB '*s*'", uid); |
| @@ -265,13 +265,14 @@ | ||
| 265 | 265 | if((tgtHasSetup || tgtHadSetup) && !g.perm.Setup){ |
| 266 | 266 | /* |
| 267 | 267 | Do not allow a non-setup user to set or remove setup |
| 268 | 268 | privileges. setup.c uses similar logic. |
| 269 | 269 | */ |
| 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; | |
| 273 | 274 | } |
| 274 | 275 | /* |
| 275 | 276 | Potential todo: do not allow a setup user to remove 's' from |
| 276 | 277 | himself, to avoid locking himself out? |
| 277 | 278 | */ |
| @@ -297,34 +298,43 @@ | ||
| 297 | 298 | blob_appendf(&sql, ", login=%Q", zNameNew); |
| 298 | 299 | ++gotFields; |
| 299 | 300 | } |
| 300 | 301 | } |
| 301 | 302 | |
| 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 | + } | |
| 303 | 310 | blob_appendf(&sql, ", cap=%Q", zCap); |
| 304 | 311 | ++gotFields; |
| 305 | 312 | } |
| 306 | -#define TRY_LOGIN_GROUP 0 /* login group support is not yet implemented. */ | |
| 313 | + | |
| 307 | 314 | if( zPW && *zPW ){ |
| 308 | 315 | 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. */ | |
| 313 | 322 | #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); | |
| 319 | 328 | #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? */ | |
| 325 | 334 | #endif |
| 335 | + } | |
| 326 | 336 | } |
| 327 | 337 | |
| 328 | 338 | if( zInfo ){ |
| 329 | 339 | blob_appendf(&sql, ", info=%Q", zInfo); |
| 330 | 340 | ++gotFields; |
| 331 | 341 |
| --- 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 |