Thread: Re: [PATCHES] Users/Groups -> Roles
* Tom Lane (tgl@sss.pgh.pa.us) wrote: > Stephen Frost <sfrost@snowman.net> writes: > > Attached please find files and patches associated with moving from the > > User/Group system currently in place to Roles, as discussed > > previously. > > I have cleaned this up a bit and committed it. I normally wouldn't > commit an incomplete patch, but this change is blocking Alvaro's work > on dependencies for shared objects, so I felt it was best to get the > catalog changes in now. That will let Alvaro work on dependencies > while I sort out the unfinished bits of roles, which I intend to do > over the next day or so. Great, glad to hear it. I hope you got a chance to look over the open items in the 'milestones' file. I'd really like to see the grammar be fixed to match SQL spec for GRANT ROLE/REVOKE ROLE. I think an approach to take there might be to try and get GrantRoleStmt and GrantStmt to use the same productions at the end of the line if possible or something along those lines. Also, I've been looking through the diff between my tree and what you committed to CVS and had a couple comments (just my 2c: I think it would have been alot easier using SVN to see exaclty what was different from my patch vs. other changes since my last CVS up): First, sorry about the gratuitous name changes, it helped me find every place I needed to look at the code and think aboutif it needed to be changed in some way (ie: Int32GetDatum -> ObjectIdGetDatum, etc). I had planned on changing someof them back to minimize the patch but kind of ran out of time. Second, looks like I missed fixing an owner check in pg_proc.c Current CVS has, line 269: if (GetUserId() != oldproc->proowner&& !superuser()) Which is not a sufficient owner check. This should by fixed by doing a proper pg_proc_ownercheck,ie: if (!pg_proc_ownercheck(HeapTupleGetOid(oldtup), GetUserId())) Third, I feel it's incorrect to only allow superuser() to change ownership of objects under a role-based system. Usersmust be able to create objects owned by a role they're in (as opposed to owned only by themselves). Without this thereis no way for a given role to allow other roles to perform owner-level actions on objects which they create. The pointof adding roles was to allow owner-level actions on objects to more than a single user or the superuser. Requiringthe superuser to get involved with every table creation defeats much of the point. This should really be possibleeither by explicitly changing the ownership of an object using ALTER ... OWNER, or by a SET ROLE followed by CREATETABLE, etc. SET ROLE is defined by the SQL specification, though we don't support it specifically yet (shouldn'tbe too difficult to add now though). Certainly if we accept that SET ROLE should be supported and that objectsthen created should be owned by the role set in SET ROLE we should be willing to support non-superusers doing ALTER... OWNER given that they could effectively do the same thing via SET ROLE (though with much more difficulty, whichhas no appreciable gain). Fourth, not that I use it, but, it looks like my changes to src/interfaces/ecpg/preproc/preproc.y were lost. Not sure ifthat was intentional or not (I wouldn't think so... I do wish ecpg could just be the differences necessary for ecpg andbe based off the main parser somehow, but that'd be a rather large change). Oh, and in that same boat, src/tools/pgindent/pgindentalso appears to not have gotten the changes that I made. > Many thanks for your work on this! Happy to have helped though frustrated that you seem to have removed the part that I was originally looking for. I don'tfeel that's justification for having it (I feel I've addressed that above) but it certainly would have been nice tobe aware of that earlier and perhaps to have discussed the issues around it a bit more before being so close to the featurefreeze (I know, alot my fault, but there it is). Thanks, Stephen
Stephen Frost <sfrost@snowman.net> writes: > Also, I've been looking through the diff between my tree and what you > committed to CVS and had a couple comments > First, sorry about the gratuitous name changes, it helped me find > every place I needed to look at the code and think about if it needed > to be changed in some way (ie: Int32GetDatum -> ObjectIdGetDatum, > etc). I had planned on changing some of them back to minimize the > patch but kind of ran out of time. No problem, I figured that was why you'd done it, but changing them back helped me to understand the patch also ;-) > Second, looks like I missed fixing an owner check in pg_proc.c Got it. I was wondering if there were more --- might be worth checking all the superuser() calls. > Third, I feel it's incorrect to only allow superuser() to change > ownership of objects under a role-based system. I took that out because it struck me as a likely security hole; we don't allow non-superuser users to give away objects now, and we shouldn't allow non-superuser roles to do so either. Moreover the tests you had were inconsistent (not same test everyplace). > Users must be able to > create objects owned by a role they're in (as opposed to owned only > by themselves). This is what SET SESSION AUTHORIZATION/SET ROLE is for, no? You set the auth to a role you are allowed to be in, then create the object. I do notice that we don't have this yet, but it's surely a required piece of the puzzle. > Fourth, not that I use it, but, it looks like my changes to > src/interfaces/ecpg/preproc/preproc.y were lost. Not sure if that was > intentional or not Yeah, it was. I leave it to Michael Meskes to sync ecpg with the main parser; on the occasions where I've tried to do it for him, things didn't work out well. > I do wish ecpg could just > be the differences necessary for ecpg and be based off the main parser > somehow, Me too, but I haven't seen a way yet. > src/tools/pgindent/pgindent also appears to not have gotten the > changes that I made. That's an automatically generated list; there's no need to edit it. regards, tom lane
Stephen Frost <sfrost@snowman.net> writes: > The code I had for this was: > if (!pg_class_ownercheck(tuple,GetUserId()) || > !is_role_member(newowner,GetUserId())) > That needs a check for superuser though because while the test will pass > on the 'pg_class_ownercheck' side, it won't on the 'is_role_member' side Um, right, that was another problem I had with it --- at one point the regression tests were failing because the superuser wasn't allowed to reassign object ownership ... I'm still fairly concerned about the security implications of letting ordinary users reassign object ownership. The fact that SET ROLE would let you *create* an object with ownership X is a long way away from saying that you should be allowed to change an *existing* object to have ownership X. This is particularly so if you are a member of a couple of different roles with different memberships: you will be able to cause objects to become effectively owned by certain other people, or make them stop being effectively owned by those people. I don't have a clear trouble case in mind at the moment, but this sure sounds like the stuff of routine security-hole reports. (Altering the ownership of a SECURITY DEFINER function, in particular, sounds like a great path for a cracker to pursue.) > One place I recall seeing one and not being sure if it should be a new > *_ownercheck() function or not was in the 2PC patch- twophase.c, line > 380: This one I think we can leave... regards, tom lane
* Tom Lane (tgl@sss.pgh.pa.us) wrote: > Stephen Frost <sfrost@snowman.net> writes: > > Second, looks like I missed fixing an owner check in pg_proc.c > > Got it. I was wondering if there were more --- might be worth checking > all the superuser() calls. Yeah, let's come up with a decision about what exactly we should allow and then perhaps I can go through all of the superuser() calls and see what needs fixing up. > > Third, I feel it's incorrect to only allow superuser() to change > > ownership of objects under a role-based system. > > I took that out because it struck me as a likely security hole; we don't > allow non-superuser users to give away objects now, and we shouldn't > allow non-superuser roles to do so either. Moreover the tests you had > were inconsistent (not same test everyplace). Sorry about them being inconsistent, I didn't intend for them to be. I went through a couple of iterations of them trying to do the check the 'right' way. Thinking back on it, even the checks I ended up with were wrong (in the superuser case), though I think they were closer. Basically my thought was to allow the same thing you could do w/ SET ROLE, etc: If you are the owner of the object to be changed (following the normal owner checking rules) AND would still be considered the owner of the object *after* the change, then you can change the ownership. The code I had for this was: if (!pg_class_ownercheck(tuple,GetUserId()) || !is_role_member(newowner,GetUserId())) That needs a check for superuser though because while the test will pass on the 'pg_class_ownercheck' side, it won't on the 'is_role_member' side (currently anyway, I suppose a superuser could be considered to be in any role, so we could change is_role_member to always return true for superusers, that'd probably make pg_group look ugly though, either way): if (!superuser() && !(pg_class_ownercheck(tupe,GetUserId()) && is_role_member(newowner,GetUserId()))) I think that's the correct check and can be done the same way for pretty much all of the objects. Were there other security concerns you had? I'd be happy to look through the superuser() checks in commands/ and develop a patch following what I described above, as well as looking for other cases where we should be using the *_ownercheck() functions. One place I recall seeing one and not being sure if it should be a new *_ownercheck() function or not was in the 2PC patch- twophase.c, line 380: if (user != gxact->owner && !superuser_arg(user)) Wasn't sure if that made sense to have *_ownercheck, or, even if we added one for it, if it made sense to check is_member_of_role() for prepared transactions. I don't think SQL has anything to say about it, anyone know what other DBs do here? > > Users must be able to > > create objects owned by a role they're in (as opposed to owned only > > by themselves). > > This is what SET SESSION AUTHORIZATION/SET ROLE is for, no? You set the > auth to a role you are allowed to be in, then create the object. I do > notice that we don't have this yet, but it's surely a required piece of > the puzzle. (Technically I think SET SESSION AUTHORIZATION is different from SET ROLE, but anyway) Right, that's another way to do it (as I mentioned), and that lets you do ownership changes, but they're much more painful: CONNECT AS joe; CREATE TABLE abc as SELECT name,avg(a),sum(b) FROM reallybigtable; -- Whoops, I meant for abc to be owned by role C so sally can add her -- column to it later, or vacuum/analyze it, whatever GRANT SELECT ON abc TO C; -- Might not be necessary ALTER TABLE abc RENAME TO abc_temp; SET ROLE C; CREATE TABLE abc AS SELECT * FROM abc_temp; -- Could be big :( SET ROLE NONE; -- Might be just 'SET ROLE;'? Gotta check the spec DROP TABLE abc_temp; I don't really see the point in making users go through all of these hoops to do an ownership change. In the end, it's the same result near as I can tell... > Yeah, it was. I leave it to Michael Meskes to sync ecpg with the main > parser; on the occasions where I've tried to do it for him, things > didn't work out well. Ah, ok. > > src/tools/pgindent/pgindent also appears to not have gotten the > > changes that I made. > > That's an automatically generated list; there's no need to edit it. Hah, silly me. Thanks, Stephen
* Tom Lane (tgl@sss.pgh.pa.us) wrote: > Stephen Frost <sfrost@snowman.net> writes: > > That needs a check for superuser though because while the test will pass > > on the 'pg_class_ownercheck' side, it won't on the 'is_role_member' side > > Um, right, that was another problem I had with it --- at one point the > regression tests were failing because the superuser wasn't allowed to > reassign object ownership ... Yeah, sorry about that. > I'm still fairly concerned about the security implications of letting > ordinary users reassign object ownership. The fact that SET ROLE would > let you *create* an object with ownership X is a long way away from > saying that you should be allowed to change an *existing* object to have > ownership X. This is particularly so if you are a member of a couple of > different roles with different memberships: you will be able to cause > objects to become effectively owned by certain other people, or make > them stop being effectively owned by those people. I don't have a clear > trouble case in mind at the moment, but this sure sounds like the stuff > of routine security-hole reports. (Altering the ownership of a SECURITY > DEFINER function, in particular, sounds like a great path for a cracker > to pursue.) SET ROLE also lets you *drop* an object owned by that role. Or alter it. Or CREATE OR REPLACE FUNCTION ... I can understand your concern. The specific use case I'm thinking about is where a user creates an object, does some work on it, and then wants to change its ownership to be owned by a role which that user is in. I find myself doing that a fair bit (as superuser atm). One thing I don't like about limiting it to that is that you then can't go back without the whole drop/create business or getting an admin. This also isn't stuff that couldn't be done through other means, even in the SECURITY DEFINER function case, you just need to drop, set role, create. Having a role with members be able to own objects isn't meant to replace the privileges system and I don't expect people to try to use it to. I can perhaps see a special case for SECURITY DEFINER functions but if we're going to special case them I'd think we'd need to make them only be creatable/modifiable at all by superusers or add another flag to the role to allow that. Thanks, Stephen
On Tue, Jun 28, 2005 at 14:45:06 -0400, Stephen Frost <sfrost@snowman.net> wrote: > > If you are the owner of the object to be changed (following the normal > owner checking rules) AND would still be considered the owner of the > object *after* the change, then you can change the ownership. That still isn't a good idea, because the new owner may not have had access to create the object you just gave to them. Or you may not have had access to drop the object you just gave away. That is going to be a security hole.
On Tue, Jun 28, 2005 at 14:52:07 -0500, Bruno Wolff III <bruno@wolff.to> wrote: > On Tue, Jun 28, 2005 at 14:45:06 -0400, > Stephen Frost <sfrost@snowman.net> wrote: > > > > If you are the owner of the object to be changed (following the normal > > owner checking rules) AND would still be considered the owner of the > > object *after* the change, then you can change the ownership. > > That still isn't a good idea, because the new owner may not have had > access to create the object you just gave to them. Or you may not have > had access to drop the object you just gave away. That is going to > be a security hole. Thinking about it some more, drops wouldn't be an issue since the owner can always drop objects. Creating objects in particular schemas or databases is not something that all roles may be able to do.
* Bruno Wolff III (bruno@wolff.to) wrote: > On Tue, Jun 28, 2005 at 14:45:06 -0400, > Stephen Frost <sfrost@snowman.net> wrote: > > > > If you are the owner of the object to be changed (following the normal > > owner checking rules) AND would still be considered the owner of the > > object *after* the change, then you can change the ownership. > > That still isn't a good idea, because the new owner may not have had > access to create the object you just gave to them. Or you may not have > had access to drop the object you just gave away. That is going to > be a security hole. If you're considered the owner of an object then you have access to drop it already. You have to be a member of the role to which you're changing the ownership. That role not having permission to create the object in place is an interesting question. That's an issue for SET ROLE too, to some extent I think, do you still have your role's permissions after you've SET ROLE to another role? If not then you'd have to grant CREATE on the schema to the role in order to create objects owned by that role, and I don't think that's necessairly something you'd want to do. Thanks, Stephen
Stephen Frost wrote: > I can perhaps see a special case for SECURITY DEFINER functions but if > we're going to special case them I'd think we'd need to make them only > be creatable/modifiable at all by superusers or add another flag to the > role to allow that. I agree that owner changes of SECURITY DEFINER functions seem dangerous. I would follow Stephen's idea that SECURITY DEFINER functions should only be creatable/modifiable by superusers. This would be similar to unix, where setting the suid/sgid bits is usually only allowed to root. Best Regards, Michael Paesold
Stephen Frost wrote: > If you're considered the owner of an object then you have access to drop > it already. You have to be a member of the role to which you're > changing the ownership. That role not having permission to create the > object in place is an interesting question. That's an issue for SET > ROLE too, to some extent I think, do you still have your role's > permissions after you've SET ROLE to another role? For me this would be the "natural" way how SET ROLE would behave. This is unix'ism again, but using setuid to become another user, you loose the privileges of the old user context. Therefore SET ROLE should not inherit privileges from the other role. This seems to be the safes approach. Nevertheless, what does the standard say? > If not then you'd > have to grant CREATE on the schema to the role in order to create > objects owned by that role, and I don't think that's necessairly > something you'd want to do. Right, that's an issue. But since the new role will be the *owner* of the object, it *should* really have create-privileges in that schema. So the above way seems to be correct anyway. Best Regards, Michael Paesold
* Bruno Wolff III (bruno@wolff.to) wrote: > Thinking about it some more, drops wouldn't be an issue since the owner > can always drop objects. Right. > Creating objects in particular schemas or databases is not something that > all roles may be able to do. Yeah, I'm not entirely sure what I think about this issue. If you're not allowed to change ownership of objects and SET ROLE drops your regular ROLE's privileges then the role which owns the object originally (and which you're required to be in) must have had create access to that schema at some point. I can see requiring the role that's changing the ownership to have create access to the schema in which the object that's being changed is in. Thanks, Stephen
* Michael Paesold (mpaesold@gmx.at) wrote: > Stephen Frost wrote: > >If you're considered the owner of an object then you have access to drop > >it already. You have to be a member of the role to which you're > >changing the ownership. That role not having permission to create the > >object in place is an interesting question. That's an issue for SET > >ROLE too, to some extent I think, do you still have your role's > >permissions after you've SET ROLE to another role? > > For me this would be the "natural" way how SET ROLE would behave. This is > unix'ism again, but using setuid to become another user, you loose the > privileges of the old user context. > Therefore SET ROLE should not inherit privileges from the other role. This > seems to be the safes approach. > > Nevertheless, what does the standard say? Hmm, it says there's a stack and that the thing on top is what's currently used, so it sounds like it would drop the privs too, but imv it's not entirely clear. > >If not then you'd > >have to grant CREATE on the schema to the role in order to create > >objects owned by that role, and I don't think that's necessairly > >something you'd want to do. > > Right, that's an issue. But since the new role will be the *owner* of the > object, it *should* really have create-privileges in that schema. So the > above way seems to be correct anyway. I'm not entirely sure that you'd necessairly want the role to have create privileges on the schema even when it owns things in the schema but the more I think about it that doesn't seem all that unreasonable either. I don't think it'd be very difficult to add such a check to the ALTER OWNER code too though. In general, and perhaps as a unix'ism to some extent, I don't particularly like having to su to people. To get all the other permissions which the role has you don't have to 'su' currently, and personally I like that and think that's correct for a role-based environment (unlike unix where you have users and groups). Thanks, Stephen
Stephen Frost <sfrost@snowman.net> writes: > * Bruno Wolff III (bruno@wolff.to) wrote: >> Creating objects in particular schemas or databases is not something that >> all roles may be able to do. > Yeah, I'm not entirely sure what I think about this issue. We have a precedent, which is that RENAME checks for create rights. If you want to lean on the argument that this is just a shortcut for dropping the object and then recreating it somewhere else, then you need (a) the right to drop the object --- which is inherent in being the old owner, and (b) the right to create the new object, which means that (b1) you can become the role you wish to have owning the object, and (b2) *as that role* you would have the rights needed to create the object. Stephen's original analysis covers (a) and (b1) but not (b2). With (b2) I'd agree that it's just a useful shortcut. I don't see a need to treat SECURITY DEFINER functions as superuser-only. We've had that facility since 7.3 or so and no one has complained that it's too dangerous. regards, tom lane
* Tom Lane (tgl@sss.pgh.pa.us) wrote: > Stephen Frost <sfrost@snowman.net> writes: > > * Bruno Wolff III (bruno@wolff.to) wrote: > >> Creating objects in particular schemas or databases is not something that > >> all roles may be able to do. > > > Yeah, I'm not entirely sure what I think about this issue. > > We have a precedent, which is that RENAME checks for create rights. Ah, ok. Precedent is good. > If you want to lean on the argument that this is just a shortcut for > dropping the object and then recreating it somewhere else, then you > need (a) the right to drop the object --- which is inherent in being > the old owner, and (b) the right to create the new object, which means > that (b1) you can become the role you wish to have owning the object, > and (b2) *as that role* you would have the rights needed to create the > object. > > Stephen's original analysis covers (a) and (b1) but not (b2). With (b2) > I'd agree that it's just a useful shortcut. Right. Ok, I'll develop a patch which covers (a), (b1) and (b2). I'll also go through all of the superuser() calls in src/backend/commands/ and check for other places we may need *_ownercheck calls. I expect to have the patch done either tonight or tommorow. Thanks, Stephen
I notice that AddRoleMems/DelRoleMems assume that ADMIN OPTION is not inherited indirectly; that is it must be granted directly to you. This seems wrong; SQL99 has under <privileges> 19) B has the WITH ADMIN OPTION on a role if a role authorization descriptor identifies the role as grantedto B WITH ADMIN OPTION or a role authorization descriptor identifies it as granted WITH ADMINOPTION to another applicable role for B. and in the Access Rules for <grant role statement> 1) Every role identified by <role granted> shall be contained in the applicable roles for A and the correspondingrole authorization descriptors shall specify WITH ADMIN OPTION. I can't see any support in the spec for the idea that WITH ADMIN OPTION doesn't flow through role memberships in the same way as ordinary membership; can you quote someplace that implies this? regards, tom lane
* Tom Lane (tgl@sss.pgh.pa.us) wrote: > I notice that AddRoleMems/DelRoleMems assume that ADMIN OPTION is not > inherited indirectly; that is it must be granted directly to you. > This seems wrong; SQL99 has under <privileges> > > 19) B has the WITH ADMIN OPTION on a role if a role authorization > descriptor identifies the role as granted to B WITH ADMIN OPTION > or a role authorization descriptor identifies it as granted WITH > ADMIN OPTION to another applicable role for B. > > and in the Access Rules for <grant role statement> > > 1) Every role identified by <role granted> shall be contained > in the applicable roles for A and the corresponding role > authorization descriptors shall specify WITH ADMIN OPTION. > > I can't see any support in the spec for the idea that WITH ADMIN OPTION > doesn't flow through role memberships in the same way as ordinary > membership; can you quote someplace that implies this? Hrm, no, sorry, I just interpreted the 'Access Rules' line for <grant role statement> differently. That is to say: 1) Every role identified by <role granted> shall be contained (Alright, all the roles which you're granting, right) in the applicable roles for A and the corresponding role (A must be in all the roles which are being granted) authorization descriptors shall specify WITH ADMIN OPTION. (the grants to A for those rules specify ADMIN OPTION) This came across to me as meaning "there must exist an authorization descriptor such that the granted-role equals <role granted>, the grantee is A and WITH ADMIN OPTION is set". That could only be true if the grant was done explicitly. Reading from 19 above (which I don't recall seeing before, or at least not reading very carefully) I think you're right. Either way is fine with me. Thanks, Stephen