Enterprise • 42:50
File System Access Control Lists (ACLs) allow fine-grained management and administration of file systems and workflows. In this session you will learn about Apple's File System ACL model, Open Directory integration for more scalable group management, and available developer APIs.
Speakers: Rusty Tucker, Mike Smith
Unlisted on Apple Developer site
Transcript
This transcript was generated using Whisper, it has known transcription errors. We are working on an improved version.
The Unix permissions model has been around with us for a while now. This weekend we're kind of trying to track it down, how long we've had it. Tracked it back to 1979 in the Unix v7, and then earlier today we tracked it back to 1971. So it's been around at least as far back as that. I think now for Mac OS X it's time for us to move beyond that and to actually introduce File System Access Controls.
So today we're gonna introduce to you what we're doing in Tiger with File System Access Controls and really try and answer three deceptively simple questions. What are ACLs or ACLs as we sometimes call them? Why are we adding them to Mac OS X? But perhaps more importantly, how do ACLs affect the way that you're developing software and managing your networks? So today we're going to cover this in seven different topics. First, an overview of File System ACLs, what are the key features and benefits of them, and then present a high-level view of the File System ACL model and its capabilities. Then we'll show you how we're changing Tiger to adapt and to provide access to access controls.
And then a more detailed look at how it's being supported in the kernel. along with some specifics in how file access controls work and how the kernel calculates permissions. Then we'll show you the developer APIs that are available for you for controlling access in file systems. And then wrap up with how we've changed our group membership and adapted Mac OS X to a more flexible group membership system. So let's get started.
The purpose of File Access Control is so we can be more expressive and more flexible in how permissions are used with files. Right now the existing model, it's a bit too crude and a lot of times gets in the way of how we're trying to do our work on a daily basis.
Some of the key things that we'd like to achieve this with access control support, one, to be able to support XP clients with our servers. A lot of our customers are requiring this to be able to support their home directories and to provide workgroup services in their Microsoft networks. And we'd like to do this with Mac OS X Server.
In addition, we'd like to enable better client fit-in of the Mac OS X desktop into active directory networks so that the Mac OS X client can act as a true peer to the other machines in those networks and have full understanding of the access controls that are in use today on the servers that are on those networks.
and also to provide a foundation technology for collaborative applications so that sharing between users and different groups are easier and more secure. And finally, we'd like to be able to enable workflow applications so that the right permissions are set on documents as they go through a workflow in a somewhat automated fashion.
Conceptually an ACL is really very simple. It's simply a list of access control entries. Each one of those entries identifies a user and a set of permissions that are either granted or denied for that object. And then each ACL is then bound to a file or directory in the file system.
So for example, we can take a look at this hypothetical math assignment document and how we might be able to use ACLs to control access to it. First of all, we definitely have to be able to have so the teachers can read, write, and delete the document so they can set the assignment. Then we have a hypothetical student teacher called Ms.
Buxton who is not really ready to provide assignments or edit assignments and she's going to be given read-only access, but she's actually a member of the teacher's group since she's a student teacher. The math students will then have just read-only access to the assignments and everyone else will have no access. We'll revisit this example throughout the presentation, providing some more detail around it and actually how it would work within our system.
So we can go back to our original statement of flexibility for file system access controls, and we've got some refinements now that we can apply to that. One, we definitely want to be able to associate multiple users and groups and assign those permissions to different file system objects. As well, to provide more granular permissions, for example, the delete permission, which you cannot assign to an individual file today. And then also to support permissions inheritance, which will help enable our workflow situations. And finally, support NT compatibility of our client and server.
So now that we have our requirements, let's take a look at what the File System ACL model actually is. We can compare this to existing models that are out there today that one might draw from. First of all, we can take a look at Apple share privileges, which weren't really in ACL, but were more capable in some ways than the POSIX permissions that we have today. For example, we could have assigned a group as an owner, and permissions inheritance was implicit in the fact that you could only assign permissions to folders.
There's also Andrew File System, which is very popular for its ACLs. And it provides the same ability to have multiple users and groups, also assign permissions to folders, and introduces some new permissions such as the ability to admin and delete. The Windows NT model, for example, introduces fine-grained permissions, multiple users and groups, the ability to allow and deny permissions, as well as defining a set of rules for inheritance. Finally, there was a POSIX draft, 1003.1e, that defined an ACL model for Unix systems as a proposal.
It provided the same set of permissions that we have today, read, write, and execute, but allowed also multiple users and groups with allow-only entries and no-deny entries. Its inheritance is somewhat limited and set to a system of default permissions for new items in the directory. And this proposal has failed to gain standardization and has been since withdrawn.
So the model that we're actually going to provide in Tiger will support NT semantics, including the fine-grained permissions that are available on NT systems, as well as found in NFS v4. We'll provide for static inheritance so that you can use the NT rules of inheritance to define inheritance of permissions when items are newly created in a directory hierarchy, as well as supporting allow and deny so that you can fine-tune permissions that are given to a user based on group memberships and so on.
The interesting innovation that we're going to provide here is combining the POSIX and UNIX permissions that we have today with an ACL, which will minimize our ability to have migration impact and maximize compatibility with existing applications. Moreover, that you will be able to, on an existing volume, assign ACLs and deploy them in specific parts of the file system, certain directories, individual file objects, for example, without having to reformat the entire volume to support that. Finally, we have an API based on the POS extract that we had talked about earlier, which provides a level of extraction and flexibility to allow for future extensions.
So a number of changes that we're going to make in Tiger to support file system ACLs. First of that will be supporting ACLs from the kernel. ACLs are part of a new extended security architecture, so ACLs are fully a first-class security attribute for files. And this will require support deep in the kernel, and Mike Smith will come and explain this to us in detail later on. As part of this, we've had to revisit how we address groups in Mac OS X. So we're eliminating the existing 16-group membership limit and adding support for nested groups.
In HFS+, ACLs will be supported based on new support for extended attributes. Extended attributes are a new functionality in HFS+ in Tiger that's built on some pre-existing definitions in the specification for HFS so that it doesn't require completely reformatting the volumes to take advantage of this. The new structures and information required in the volume format can be built out transparently as you assign ACLs and extended attributes to items.
And finally, this will be available both in the Tiger client and Tiger server. Of course, changing the SMB client is another important feature for us in our ACL strategy, providing us with a good client fit-in in Microsoft networks and the ability to view users and groups from Active Directory and edit the ACLs that are in the files on NT servers.
And of course we'll also be updating AFP and the AFP client to support ACLs natively. Altogether, the changes in the kernel and file system provide us a good foundation for extended permissions in Tiger. Through the POSIX and Carbon layers, your applications will gain access to the ACL APIs so that you can change and manipulate ACLs from your software, and also providing command line tools for management of systems, including LS and Chmod, for example, to view and edit ACLs, but also in command line tools like CP, because now we need to preserve this new information when we copy files.
[Transcript missing]
With our solution, you actually end up with a full fidelity solution because the file system permissions already have the same finer-grained permissions that are found on the NT systems that it's being served to.
This is also reflected in the AFP server where we'll be showing permissions as effective permissions to Panther and earlier clients because they don't have the current capability of understanding the more fine-grained ACL permissions. But full ACL permissions will be exposed to Tiger clients. But both Samba and AFP together will work from the same basic set of permissions in the local file system, providing very unified support to both clients and the same capabilities in each platform.
Through Finder we'll be supporting editing ACLs from the desktop on both AFP, SMP, and local volumes. And of course in our server tools, providing very flexible management of ACLs in a much more fine-grained manner, including the ability for you to set presets and define your own permissions mask, making management of ACLs very efficient and easy. All in all, I think we've got a very complete and comprehensive set of changes in Tiger for ACLs. Now I'd like to introduce you Mike Smith from CoreOS Engineering.
Thanks, Rusty. So, in the next few minutes, I guess, I'll be talking about the kernel changes, the introduction of new centralized authorization infrastructure that we're calling KAUF. I'll talk a little bit about some details of the ACL format, mostly internal details for reference purposes, and we'll work through a brief example using the scenario that Rusty raised earlier, and then I'll talk a little bit about the developer API. I'm not actually going to bore you by working through the entire API detail by detail. The documentation will be available in good time, but it will go through a code sample to give you a feel for what we're actually doing.
So when we embarked on supporting ACLs, we already knew that we were going to need a centralized authorization infrastructure. The existing authorization mechanisms inside the Mac OS kernel, whilst more than adequate to the task, are relatively ad hoc authorization decisions made all over the place. There is some duplication of code, and this works okay because the model we've been working with has been relatively simple. However, ACLs and the like introduce considerable complexities, and so it's fairly important for us to reduce the amount of work that file system developers need to do, and also to just overall reduce the code bulk and replication of code.
Authorization itself inside the kernel really involves knowing three things: Who you are actually performing the action for, what you're operating on, and what the actual operation is, the specific details related to it. Kayoth provides management for credentials which are our identification, user identification. It supports processing of ACLs, provides helper functions for translation and the like. And it provides a flexible mechanism for defining actions as well as a plug-in architecture that allows third-party modules to participate in the authorization process on a per-scope basis.
We expect this to be of particular interest to folks writing virus filters, but potentially also other content filters. And the functionality is very much open-ended, so if you find yourself having a desire to control the way that access to particular resources is managed, then you can basically write a module against our API and just get involved. The consequence of all of this is that the ACLs are then fully integrated with the kernel authorization subsystem.
Again, in the vein of reducing the amount of work that individual file systems and modules need to perform, we've layered ACL implementation over the top of extended attribute support. So any file system that supports extended attributes gets ACLs for free. File systems that have their own ACL model can translate to and from our format. As we're using the Microsoft NFS v4 semantic, generally for file systems with native ACL models, these translations have already been explored and so they're well understood.
And again, as Rusty pointed out, we will continue to support POSIX ACLs. The default processing for ACLs leaves you in a situation when you're at the end of the ACL, and I'll get into that in more detail in a little bit, where you would deny the request. In our case, we will simply fall through and consider the POSIX permissions. And this gives the expected behavior. If you have a file with existing POSIX permissions and you want to add extra control to it, you can apply an ACL. The processing of the tool will behave pretty much as you expect it to.
This is a simplified overview of the way that things look now with the KL subsystem interacting with the VFS to provide the new authorization functionality. The interesting item on this particular diagram is the group membership resolver. As Rusty mentioned, we're going beyond the 16-group limit, integrating with Active Directory. It's no longer practical for us to keep a complete list of all of the groups that every credential is a member of inside the kernel, so we need an external resolution service.
I'm just going to talk briefly now about our formats. This is obviously not a comprehensive description. We'd really rather that you used our API for actually manipulating these, but understanding what's going on under the covers may help you keep up. Some terminology. Rusty's already briefly talked about access control entries. They associate an identifier of some sort with a set of permissions. Access Control List. The word list is kind of important because it's an ordered list. The processing of an ACL is dependent upon the order of the entries in the list.
The User ID and Group ID you should be familiar with already. They're the current 32-bit user and group identifiers that we've been using for some time. We're introducing a new globally unique ID which can be applied to both users and groups. This is to deal with a situation where you may have very large numbers of users or you may have groups of users that have not been maintained coherently.
So you run into the problems of either exhausting the user ID space or simply having collisions to users numbered 500, for example. The GUID is randomly generated. It's guaranteed to be unique. It operates in a 128-bit space. And so you can uniquely identify objects by their ownership even if you move them around. You have a permanent handle for them.
And the discussion is not really complete without mentioning Microsoft's security outpost. identifier, which is a structured The data item that is used with SMB operations, it performs very much the same functionality as the GUID. Microsoft chose to embed information in there rather than using an indirect reference to the information. The Kauth subsystem provides functionality for translations between all of these items. So if you have a GUID, you can get the UID, you can get the SID.
On a local file system that's using our extended attribute support, we'll be storing a GUID for the owner of the object and the access control list in the extended API as an extended attribute. Obviously, again, we would like you to use our API functions for manipulating these. You may be getting a common theme here.
One useful thing to note is that because we are tracking the owner with a GUID, it becomes possible for groups to own objects. Thank you for joining us. I'm Mike Smith, and I'm the executive director of Open Directory. Dice, again, associates an identifier with some access rights and control bits which determine whether or not those rights are granted or denied, and also some bits controlling inheritance.
More lists of stuff. These are the access permissions that we provide for controlling access to files. You can independently control reading, writing, executing of the file, deletion of individual files, obviously appending of data. And then read/write control individually over the file's basic attributes, time stamps and the like, extended attributes with the exclusion of the security information, the security information itself, and you can also grant individuals or groups the rights to change the ownership of a file.
The permissions associated with directories are very similar. Obviously, we substitute read and write with list and add file. Searching in the directory, it's possible to search within a directory for a file if you know the file's name without having to have rights to access a visitor. Pretty much parallels to the current Unix permissions. And again, the controls on rewrite of attributes and ownership.
The flags applied to an individual ACE obviously allow and deny, but the inheritance is perhaps something that's not quite so well understood. Directory objects allow you to specify ACEs which will be inherited either by child directories or by files, and also allow you to control whether those are inherited once or multiple times.
This is what Rusty was referring to as static inheritance. It effectively allows you to set up template ACLs for both files and directories created inside others. It allows you to establish permissions on objects so that an individual can create an object but may not necessarily subsequently have full access to that object. It's a real support for the workflow environment.
So I'm going to come back to Rusty's scenario here and work through a couple of brief examples. Just to recap, we have a school network. We have a group which contains all the teachers. We have a group which contains the math students. We have a student teacher, Ms. Buxton, who is part of the teachers group because she needs access to teachers-only files. But right now we don't want to grant her the ability to write to this particular math assignment.
So we rephrase this as an ACL with three ordered entries. First up, we put a denial entry which prevents Ms. Buxton from either writing or deleting that math assignment. We have a blanket allow for teachers that allows them to rewrite and delete the file, and allow for math students who actually want to read the file. And when we're processing an ACL, we process each entry in order.
In entries, ID is compared against the ID of the requester. If they're not identical or if the requester is not a member of the group called out in the entry, then we just ignore the entry. If they are a member, then we look at whether the entry is an allow or deny entry. If it's a deny entry, we take the permissions that are being requested by the operation. If any of them are denied by the entry, we stop processing at that point. alternatively, if we cumulatively accumulate all of the requested permissions from allow entries, then we allow the operation.
In this particular example, let's consider a math student who wants to open the file read-only. Perhaps they're copying it off to a private disk so they can take it home and work on it. They'll be requesting read access. We look at the first entry, Ms. Buxton, math student, not Ms. Buxton. Fine. Second entry, math student, not a teacher. Okay, ignore that one too. Third one, math student. Okay, they want read. It says they can have read. They get to read the file.
If we look at another example, Ms. Buxton is attempting to save over a copy of the math assignment, and maybe she just made a mistake. Maybe she feels that she's going to be a hacker one of these days. Who knows? She's going to want, she will have opened the file using read permissions, would have looked at the first entry, deny Ms. Buxton, okay, this applies to Ms. Buxton, but it's only denying her, write and delete, okay, so we don't block her there.
Second entry, Ms. Buxton, she's a teacher, she's allowed to read, she can read the file. Comes time to save, she wants write access. First entry, Ms. Buxton, write, denied. So you can express things with even a simple ACL like this that would not be possible with the traditional POSIX permissions, and obviously I've kept this example short because it could go on forever.
The developer API, we went around with this several times, but ultimately decided that rather than trying to introduce a great deal of new API, we would try and stay as close to the POSIX API, the existing API that you folks are familiar with already. Certainly in philosophy, obviously, we needed some extra functionality and we had a bunch more details.
We tried to avoid namespace collisions so that you don't suddenly discover that there are symbols in your application that are colliding with definitions and header files. And we've avoided exposing any data structures directly. Rather, we've preferred to stick with accessor functions in a fashion that will allow you to remain binary compatible even if we need to add extra security information.
Obviously, if your application doesn't care about access controls, I'm not quite sure why you're here right now, but your application can continue to not care. We're not really changing the basic concept of having security information associated with a file, we're just being much more eloquent about what you can express with it.
It becomes particularly important with the extra complexity that go with ACLs that applications not try to simply look at a file security information and determine from that security information whether or not something that they're going to do is going to be successful. The group membership resolution process can be time consuming.
There may also be other things going on behind the scenes. And finally, the file that you're attempting to access may actually not be on the local machine at all. It may be on a remote file server which potentially has completely different rules for evaluating whether or not you're going to have access.
So if you can at all get away with it, just go ahead and try the operation. Be prepared for it to fail. Have a good recovery, good back out scenario. But don't count on guessing ahead of time whether or not you're going to be able to process something.
Obviously, some applications do need to know. If you want feedback for a GUI application, you want to be able to gray out the icon as you mouse over it, whatever. We do provide interfaces for that. At the POSIX level you have the access function. There are other functions in Carbon. These will take ACLs into account.
They'll use the same K-auth infrastructure that's used for actual access checking. But there are scenarios in which even those aren't going to be able to give you answers. So you need to be prepared for the situation where we simply can't tell you ahead of time whether something's going to succeed. You're just going to have to be prepared to try it and deal with the situation.
So some applications do need to care. Obviously anyone who cares about security of the files they're working with, archivers and copiers that want to be accurate, that want to preserve the information that already exists in the security structures. Anyone who is providing file management functionality, whether you're a finder analogue, whether you're simply an enhanced open/closed dialog, whether you have some other way of representing files, you're going to need to be able to provide folks with the opportunity to edit security information on the files.
And so you will need to use these APIs and you'll need to come up with UI and so forth. And obviously, we're building this functionality so that you, as developers, can produce things that we never thought of. And so if you find that ACLs are relevant to something you want to do, then you'll need to use them.
Again, with this particular API, our philosophy was to try and avoid unnecessary changes to keep with the spirit of the POSIX APIs. So we've encapsulated all of the file security information into an opaque object, a thing we call the FileSecT. And this is then passed around, so stat becomes statX with an NP suffix so that you know this is not a portable call, and it returns your FileSecT. OpenX takes one instead of a ModeT. ChmodX takes a FileSec. It's the same all the way around. The ACL is part of the file security object, so the owner, the group, the POSIX mode were applicable.
We provide an API for the manipulation of the file set. Basically get set, check whether it's valid, clear it, functionality. And we provide an API for manipulating the ACL itself, which is based on the POSIX 10031E API. Obviously we needed to make some changes to cope with the differences. But since there is a good deal of established code and understanding and documentation already available for the manipulation API, we decided that was the best way to go.
So I'm going to finish up here with a brief example of creating a file with an ACL associated. In this particular case, we don't have to be the individual that is passed in as the We can go ahead and, since we're creating the file, we can basically apply whatever ACL we like. So we start off, we create an empty ACL. It's fairly straightforward. We create an entry in the ACL. At this point in time, both the ACL and the entry are blank.
And then we apply the qualifier-- we apply the qualifier, in this case the GUID, to the ACL--sorry, to the ACE. My apologies. And we'll turn this into an allow-ace because we're going to grant read-only access to the GUI that's been passed in. So we fetch the flags for the ACE, we clear them just as a proportion, and then we set the allow bit.
We get the permissions for the ACE. Again, we'll clear them as a precaution. And we'll grant the ability to read data attributes, extended attributes, and security information. And then we apply those to the ACE. And so right now we've created an ACE with one entry. Grants this particular GUID read-only access to the file.
Next we create ourselves a file security object. Since we're starting from scratch we don't have one of these from a stack call. We apply the ACL to the File Security Object, and then we can drop the ACL because we've copied it into the File Security Object. We'll turn off the POSIX permissions so that only the ACL applies to this particular file.
And then we'll create the file. As you can see, this looks just like an open call except we're passing the file security object rather than a mode in. As with the traditional open, we can actually open for any sort of access regardless of the permissions that we've associated with the file.
This actually allows us to create a file securely that we have write access to because we're copying into it or whatever, but that no one else can open for writing. We're going to clean up when we're done. So I'm going to hand this back to Rusty now. He'll talk to us a little bit about group membership.
Now we're going to talk a bit about group membership and its relation to ACLs. As we were going through the design of ACLs, it became very apparent that the existing model that we had for group membership really was not scalable enough, nor was it precise enough for the things that we wanted to do with access control.
So in Tiger, we're going to make it more scalable, more robust, eliminate the 16 group limit that we have today in Panther. And this, as you see, is with the group membership resolver and the kernel's ability to defer looking up groups until the time that it's actually necessary.
So today when you log in with a Panther system, it needs to go out onto the directory and discover all the groups to which you are a member, even if there are only 4, 5, or 16. Taking the first 16 that it finds, and those become the groups that you derive permission from. will also be supporting nested groups. The daemon will be able to expand group memberships and test membership against that, as well as provide compatibility with legacy software.
So in the directory we'll require a new group schema to support this. This new group schema is based on an authoritative list of GUIDs rather than using short names to define membership. And these GUIDs may reference either other users or other groups, which provides us the nesting capabilities and provides us for future expansion since GUIDs can really be referencing any type of object out there, including computers or things that devices we haven't really thought of yet.
Groups are also further identified by their legacy group ID and optionally the NT secure ID. This provides us with the ability to provide static translations for clients such as XP clients or a service such as the Samba service. When binding to Active Directory networks, you don't need to change the schema there. The group resolution daemon understands the schema that's present in Active Directory networks and can work with them.
So as we said before, Panther is using a 16-group array. Integra will be using a new group membership service to replace that. It provides a group expansion capabilities and performance is caching the results to these queries in both positive and negative with the time to live. Because groups and group memberships can be checked quite often, especially when going through ACLs. and then provides also the ID translation services.
So these services are going to be available to your software as well through a new API that will allow you to test membership against groups so that you don't need to parse membership lists manually. And also to provide the UID and GUID translation services or as well NTS, the SID services. The privileged processes today can edit the groups to which they are being considered a member and which are being evaluated. A new API will be available to more precisely define that within this new scheme.
All of this really opens up the possibility for a new way to manage individuals on your network using smaller groups and nested hierarchies of groups. So we can revisit the example that we have with the teachers and student teachers and redo that in a more dynamic fashion. Rather than having a single group of teachers to represent all teachers and student teachers, we'll create two separate groups. One of the staff teachers and another of just student teachers. Together these will be nested into one larger global teachers group for use where that's appropriate.
In the example that we showed, rather than having to have a deny entry specifically from Ms. Buxton for that math assignment, we can simply say student teachers have read access to this file. And then staff teachers have the necessary read, write, and delete access. What's really nice about going this way is that as roles, as people's roles change within your organization, Ms. Buxton gets promoted to, gets hired as a staff teacher. You can simply reassign her membership within the directory system and she'll automatically be obtaining new permissions in the file system where that group is, the new group membership is encountered.
So we'll kind of wrap up here with a little sneak peek at some proposed user interface to manage ACLs. First of all, within Finder's Get Info window, you can see it's very similar to what you have today. But now we have the addition of an Others listing, which is not just a single group as it is now, but another listing of both groups and users that can be assigned different permissions to this object. The idea here is to keep something that's very simple, manageable, that people can use from their own systems.
The initial view in the Tiger Server Admin Tools is very similar. It follows the same easy-to-use idea that we have in following in Finder, but also provides a more detailed view of the ACL and its associated access control entries, allowing you to edit specific information about them as to whether it's an allow or deny record, and also to be able to access preset groups of permission entries from the pop-up menu that you see here.
And those will provide customization abilities so that you can define your own sets of presets to meet the way that you're managing permissions on your network. And from there you can drill down and find more, you know, access more detailed permissions on the different objects to get to the real fine-grained permissions, control over inheritance, and so forth.
So to summarize where we are with ACLs and Tiger, providing a much more flexible way of expressing permissions on objects in the file system and reducing the arbitrary limits that we have today in the OS. Supporting compatibility with Microsoft in Microsoft networks, both the client and the server, and providing a better platform for collaboration and workflow.
With that, we're providing new information that's now exposed in the file system both in terms of ACLs and extended attributes that needs to be supported by software, specifically copy engines, archivers, and so on. Some of those changes we'll be making ourselves and some of those are going to be required by your third-party software. And finally, this may impact the way that you manage your network and hopefully we'll be able to give you enough of some information here today that you can begin planning for those changes coming up.