Fossil SCM
/json/user/save now requires 's' privilege in order to set/remove the 's' privilege or edit another user who currently has the 's' privilege, to somewhat more closely mimic the HTML interface's behaviour.
Commit
029870831aeb0e28a1489f19882a7bad4360936d
Parent
fca6c46cd99534f…
1 file changed
+24
-14
+24
-14
| --- src/json_user.c | ||
| +++ src/json_user.c | ||
| @@ -175,16 +175,13 @@ | ||
| 175 | 175 | ** values from FossilJsonCodes is returned. |
| 176 | 176 | ** |
| 177 | 177 | ** On success the db record for the given user is updated. |
| 178 | 178 | ** |
| 179 | 179 | ** Requires either Admin, Setup, or Password access. Non-admin/setup |
| 180 | -** users can only change their own information. | |
| 181 | -** | |
| 182 | -** TODOs: | |
| 183 | -** | |
| 184 | -** - Admin non-Setup users cannot change the information for Setup | |
| 185 | -** users. | |
| 180 | +** users can only change their own information. Non-setup users may | |
| 181 | +** not modify the 's' permission. Admin users without setup | |
| 182 | +** permissions may not edit any other user who has the 's' permission. | |
| 186 | 183 | ** |
| 187 | 184 | */ |
| 188 | 185 | int json_user_update_from_json( cson_object * pUser ){ |
| 189 | 186 | #define CSTR(X) cson_string_cstr(cson_value_get_string( cson_object_get(pUser, X ) )) |
| 190 | 187 | char const * zName = CSTR("name"); |
| @@ -195,10 +192,12 @@ | ||
| 195 | 192 | char const * zPW = CSTR("password"); |
| 196 | 193 | cson_value const * forceLogout = cson_object_get(pUser, "forceLogout"); |
| 197 | 194 | int gotFields = 0; |
| 198 | 195 | #undef CSTR |
| 199 | 196 | cson_int_t uid = cson_value_get_integer( cson_object_get(pUser, "uid") ); |
| 197 | + char const tgtHasSetup = zCap && (NULL!=strchr(zCap, 's')); | |
| 198 | + char tgtHadSetup = 0; | |
| 200 | 199 | Blob sql = empty_blob; |
| 201 | 200 | Stmt q = empty_Stmt; |
| 202 | 201 | |
| 203 | 202 | if(!g.perm.Admin && !g.perm.Setup && !g.perm.Password){ |
| 204 | 203 | return json_set_err( FSL_JSON_E_DENIED, |
| @@ -219,11 +218,11 @@ | ||
| 219 | 218 | }else if(-1==uid){ |
| 220 | 219 | /* try to create a new user */ |
| 221 | 220 | if(!g.perm.Admin && !g.perm.Setup){ |
| 222 | 221 | return json_set_err(FSL_JSON_E_DENIED, |
| 223 | 222 | "Requires 'a' or 's' privileges."); |
| 224 | - } else if(!zName || !*zName){ | |
| 223 | + }else if(!zName || !*zName){ | |
| 225 | 224 | return json_set_err(FSL_JSON_E_MISSING_ARGS, |
| 226 | 225 | "No name specified for new user."); |
| 227 | 226 | }else if( db_exists("SELECT 1 FROM user WHERE login=%Q", zName) ){ |
| 228 | 227 | return json_set_err(FSL_JSON_E_RESOURCE_ALREADY_EXISTS, |
| 229 | 228 | "User %s already exists.", zName); |
| @@ -249,23 +248,34 @@ | ||
| 249 | 248 | /* Maintenance note: all error-returns from here on out should go |
| 250 | 249 | via 'goto error' in order to clean up. |
| 251 | 250 | */ |
| 252 | 251 | |
| 253 | 252 | if(uid != g.userUid){ |
| 254 | - /* | |
| 255 | - TODO: do not allow an admin user to modify a setup user | |
| 256 | - unless the admin is also a setup user. setup.c uses | |
| 257 | - that logic. There is a corner case for a NEW Setup user | |
| 258 | - which the admin is just installing. Hmm. | |
| 259 | - */ | |
| 260 | 253 | if(!g.perm.Admin && !g.perm.Setup){ |
| 261 | 254 | json_set_err(FSL_JSON_E_DENIED, |
| 262 | 255 | "Changing another user's data requires " |
| 263 | 256 | "'a' or 's' privileges."); |
| 264 | 257 | } |
| 265 | 258 | } |
| 266 | - | |
| 259 | + /* check if the target uid currently has setup rights. */ | |
| 260 | + tgtHadSetup = db_int(0,"SELECT 1 FROM user where uid=%d" | |
| 261 | + " AND cap GLOB '*s*'", uid); | |
| 262 | + | |
| 263 | + if((tgtHasSetup || tgtHadSetup) && !g.perm.Setup){ | |
| 264 | + /* | |
| 265 | + Do not allow a non-setup user to set or remove setup | |
| 266 | + privileges. setup.c uses similar logic. | |
| 267 | + */ | |
| 268 | + return json_set_err(FSL_JSON_E_DENIED, | |
| 269 | + "Modifying 's' users/privileges requires " | |
| 270 | + "'s' privileges."); | |
| 271 | + } | |
| 272 | + /* | |
| 273 | + Potential todo: do not allow a setup user to remove 's' from | |
| 274 | + himself, to avoid locking himself out? | |
| 275 | + */ | |
| 276 | + | |
| 267 | 277 | blob_append(&sql, "UPDATE USER SET",-1 ); |
| 268 | 278 | blob_append(&sql, " mtime=cast(strftime('%s') AS INTEGER)", -1); |
| 269 | 279 | |
| 270 | 280 | if((uid>0) && zNameNew){ |
| 271 | 281 | /* Check for name change... */ |
| 272 | 282 |
| --- src/json_user.c | |
| +++ src/json_user.c | |
| @@ -175,16 +175,13 @@ | |
| 175 | ** values from FossilJsonCodes is returned. |
| 176 | ** |
| 177 | ** On success the db record for the given user is updated. |
| 178 | ** |
| 179 | ** Requires either Admin, Setup, or Password access. Non-admin/setup |
| 180 | ** users can only change their own information. |
| 181 | ** |
| 182 | ** TODOs: |
| 183 | ** |
| 184 | ** - Admin non-Setup users cannot change the information for Setup |
| 185 | ** users. |
| 186 | ** |
| 187 | */ |
| 188 | int json_user_update_from_json( cson_object * pUser ){ |
| 189 | #define CSTR(X) cson_string_cstr(cson_value_get_string( cson_object_get(pUser, X ) )) |
| 190 | char const * zName = CSTR("name"); |
| @@ -195,10 +192,12 @@ | |
| 195 | char const * zPW = CSTR("password"); |
| 196 | cson_value const * forceLogout = cson_object_get(pUser, "forceLogout"); |
| 197 | int gotFields = 0; |
| 198 | #undef CSTR |
| 199 | cson_int_t uid = cson_value_get_integer( cson_object_get(pUser, "uid") ); |
| 200 | Blob sql = empty_blob; |
| 201 | Stmt q = empty_Stmt; |
| 202 | |
| 203 | if(!g.perm.Admin && !g.perm.Setup && !g.perm.Password){ |
| 204 | return json_set_err( FSL_JSON_E_DENIED, |
| @@ -219,11 +218,11 @@ | |
| 219 | }else if(-1==uid){ |
| 220 | /* try to create a new user */ |
| 221 | if(!g.perm.Admin && !g.perm.Setup){ |
| 222 | return json_set_err(FSL_JSON_E_DENIED, |
| 223 | "Requires 'a' or 's' privileges."); |
| 224 | } else if(!zName || !*zName){ |
| 225 | return json_set_err(FSL_JSON_E_MISSING_ARGS, |
| 226 | "No name specified for new user."); |
| 227 | }else if( db_exists("SELECT 1 FROM user WHERE login=%Q", zName) ){ |
| 228 | return json_set_err(FSL_JSON_E_RESOURCE_ALREADY_EXISTS, |
| 229 | "User %s already exists.", zName); |
| @@ -249,23 +248,34 @@ | |
| 249 | /* Maintenance note: all error-returns from here on out should go |
| 250 | via 'goto error' in order to clean up. |
| 251 | */ |
| 252 | |
| 253 | if(uid != g.userUid){ |
| 254 | /* |
| 255 | TODO: do not allow an admin user to modify a setup user |
| 256 | unless the admin is also a setup user. setup.c uses |
| 257 | that logic. There is a corner case for a NEW Setup user |
| 258 | which the admin is just installing. Hmm. |
| 259 | */ |
| 260 | if(!g.perm.Admin && !g.perm.Setup){ |
| 261 | json_set_err(FSL_JSON_E_DENIED, |
| 262 | "Changing another user's data requires " |
| 263 | "'a' or 's' privileges."); |
| 264 | } |
| 265 | } |
| 266 | |
| 267 | blob_append(&sql, "UPDATE USER SET",-1 ); |
| 268 | blob_append(&sql, " mtime=cast(strftime('%s') AS INTEGER)", -1); |
| 269 | |
| 270 | if((uid>0) && zNameNew){ |
| 271 | /* Check for name change... */ |
| 272 |
| --- src/json_user.c | |
| +++ src/json_user.c | |
| @@ -175,16 +175,13 @@ | |
| 175 | ** values from FossilJsonCodes is returned. |
| 176 | ** |
| 177 | ** On success the db record for the given user is updated. |
| 178 | ** |
| 179 | ** Requires either Admin, Setup, or Password access. Non-admin/setup |
| 180 | ** users can only change their own information. Non-setup users may |
| 181 | ** not modify the 's' permission. Admin users without setup |
| 182 | ** permissions may not edit any other user who has the 's' permission. |
| 183 | ** |
| 184 | */ |
| 185 | int json_user_update_from_json( cson_object * pUser ){ |
| 186 | #define CSTR(X) cson_string_cstr(cson_value_get_string( cson_object_get(pUser, X ) )) |
| 187 | char const * zName = CSTR("name"); |
| @@ -195,10 +192,12 @@ | |
| 192 | char const * zPW = CSTR("password"); |
| 193 | cson_value const * forceLogout = cson_object_get(pUser, "forceLogout"); |
| 194 | int gotFields = 0; |
| 195 | #undef CSTR |
| 196 | cson_int_t uid = cson_value_get_integer( cson_object_get(pUser, "uid") ); |
| 197 | char const tgtHasSetup = zCap && (NULL!=strchr(zCap, 's')); |
| 198 | char tgtHadSetup = 0; |
| 199 | Blob sql = empty_blob; |
| 200 | Stmt q = empty_Stmt; |
| 201 | |
| 202 | if(!g.perm.Admin && !g.perm.Setup && !g.perm.Password){ |
| 203 | return json_set_err( FSL_JSON_E_DENIED, |
| @@ -219,11 +218,11 @@ | |
| 218 | }else if(-1==uid){ |
| 219 | /* try to create a new user */ |
| 220 | if(!g.perm.Admin && !g.perm.Setup){ |
| 221 | return json_set_err(FSL_JSON_E_DENIED, |
| 222 | "Requires 'a' or 's' privileges."); |
| 223 | }else if(!zName || !*zName){ |
| 224 | return json_set_err(FSL_JSON_E_MISSING_ARGS, |
| 225 | "No name specified for new user."); |
| 226 | }else if( db_exists("SELECT 1 FROM user WHERE login=%Q", zName) ){ |
| 227 | return json_set_err(FSL_JSON_E_RESOURCE_ALREADY_EXISTS, |
| 228 | "User %s already exists.", zName); |
| @@ -249,23 +248,34 @@ | |
| 248 | /* Maintenance note: all error-returns from here on out should go |
| 249 | via 'goto error' in order to clean up. |
| 250 | */ |
| 251 | |
| 252 | if(uid != g.userUid){ |
| 253 | if(!g.perm.Admin && !g.perm.Setup){ |
| 254 | json_set_err(FSL_JSON_E_DENIED, |
| 255 | "Changing another user's data requires " |
| 256 | "'a' or 's' privileges."); |
| 257 | } |
| 258 | } |
| 259 | /* check if the target uid currently has setup rights. */ |
| 260 | tgtHadSetup = db_int(0,"SELECT 1 FROM user where uid=%d" |
| 261 | " AND cap GLOB '*s*'", uid); |
| 262 | |
| 263 | if((tgtHasSetup || tgtHadSetup) && !g.perm.Setup){ |
| 264 | /* |
| 265 | Do not allow a non-setup user to set or remove setup |
| 266 | privileges. setup.c uses similar logic. |
| 267 | */ |
| 268 | return json_set_err(FSL_JSON_E_DENIED, |
| 269 | "Modifying 's' users/privileges requires " |
| 270 | "'s' privileges."); |
| 271 | } |
| 272 | /* |
| 273 | Potential todo: do not allow a setup user to remove 's' from |
| 274 | himself, to avoid locking himself out? |
| 275 | */ |
| 276 | |
| 277 | blob_append(&sql, "UPDATE USER SET",-1 ); |
| 278 | blob_append(&sql, " mtime=cast(strftime('%s') AS INTEGER)", -1); |
| 279 | |
| 280 | if((uid>0) && zNameNew){ |
| 281 | /* Check for name change... */ |
| 282 |