The ACL library API, dce_acl_*( ), is a local interface that provides the server-side implementation of the ACL network interface. The reference pages in OSF DCE Application Development Reference describe the library routines.
The ACL library consists of the following parts:
· Initialization routines, where the server registers each ACL manager type.
· Server queries, where a server can perform various types of access checks.
· ACL object creation, where servers can create ACLs without concern for most low-level data type details.
· The rdacl_*( ) implementation and server callback, where the server maps rdacl_*( ) parameters into a specific ACL object. Two sample resolver routines are associated with this part:
- dce_acl_resolve_by_name( )
Finds an ACL's UUID, given an object's name.
- dce_acl_resolve_by_uuid( )
Finds an ACL's UUID, given an object's UUID.
Initialization Routines
An ACL manager must first define the types of the objects it manages. For example, a simple directory service would have directories and entries, and each type of object would have a different ACL manager. On a practical level, if a server has different types of objects, then the most common difference between the ACL managers is the printed representation of its permission bits. In other words, although the sec_acl_printstring_t values differ, the algorithm for evaluating permissions remains the same.
The ACL library provides a global print string that specifies the read, write, and control bits. Application developers are encouraged to use this print string whenever appropriate.
An ACL manager calls the dce_acl_register_object_type( ) routine to register an object type, once for each type of object that the server manages. The manager print string does not define any permission bits; they are set by the library to be the union of all permissions in the ACL print string.
The server must register the rdacl_*( ) interface with the RPC runtime and with the endpoint mapper. See the dce_server_register(3dce) reference page.
Server Queries
The ACL library provides several routines to automate the most common use of DCE ACLs:
· dce_acl_is_client_authorized( )
Checks whether a client's credentials are authenticated and, if so, that they grant the desired access.
· dce_acl_inq_client_permset( )
Returns the client's permissions, corresponding to an ACL.
· dce_acl_inq_client_creds( )
Returns the client's credentials.
· dce_acl_inq_permset_for_creds( )
Determines a client's complete extent of access to an object.
· dce_acl_inq_acl_from_header( )
Retrieves the UUID of an ACL from the header of an object in the backing store.
· dce_acl_inq_prin_and_group( )
Inquires the principal and the group of an RPC caller.
Creating ACL Objects
The following convenience functions may be used by an application programmer to create ACL objects in other servers or clients.
· dce_acl_copy_acl( )
Copies an ACL.
· dce_acl_obj_init( )
Initializes an ACL for an object.
· dce_acl_obj_free_entries( )
Frees space used by an ACL's entries.
· dce_acl_obj_add_user_entry( )
Adds permissions for a user ACL entry to the given ACL.
· dce_acl_obj_add_group_entry( )
Adds permissions for a group ACL entry to the given ACL.
· dce_acl_obj_add_id_entry( )
Adds permissions for an ACL entry to the given ACL.
· dce_acl_obj_add_unauth_entry( )
Adds permissions for an unauthenticated ACL entry to the given ACL.
· dce_acl_obj_add_obj_entry( )
Adds permissions for an obj ACL entry to the given ACL.
· dce_acl_obj_add_foreign_entry( )
Adds permissions for the ACL entry for a foreign user or group to the given ACL.
· dce_acl_obj_add_any_other_entry( )
Adds permissions for the any_other ACL entry to a given ACL.
RDACL Implementation and Server Callback
The ACL library makes a complete implementation of the rdacl_*( ) interface available to programmers writing servers, in a manner that is mostly transparent to the rest of the server code.
The operations in the rdacl_*( ) interface share an initial set of parameters that specify the ACL object being operated upon:
handle_t h
sec_acl_component_name_t component_name
uuid_t *manager_type
sec_acl_type_t sec_acl_type
The sec_acl_type parameter indicates whether a protection ACL, an initial default Object ACL, or an initial default Container ACL is desired. It does not appear in the access operations as it must have the value sec_acl_type_object.
In order to implement the rdacl_*( ) interface, the server must provide a resolution routine that maps these parameters into the UUID of the desired ACL object; the library includes two such routines: dce_acl_resolve_by_uuid( ) and dce_acl_resolve_by_name( ).
The resolution routine is required because servers use the namespace in different ways. Here are three examples:
· Servers that export only their binding information and manage a single object, and hence use a single ACL, do not need the resolution parameters. DTS is an example of this case.
· Servers with many objects in the namespace, with a UUID in each entry, will call rpc_binding_inq_object on the handle to obtain the object UUID. They then use this same UUID as the index of the ACL object. Many application servers will be of this type. One ACL library resolver function, dce_acl_resolve_by_uuid( ), matches this paradigm. This paradigm is not appropriate if the number of objects is immense.
· Servers with many objects will use a junction or similar architecture so that the component name (also called the residual) specifies the ACL object by name. The DCE security server is essentially of this type. Another ACL library resolver function, dce_acl_resolve_by_name( ), matches this paradigm.
The following typedef specifies the signature for a resolution routine. The first four parameters are the common rdacl_*( ) parameters mentioned previously.
typedef void (*dce_acl_resolve_func_t)(
/* [in] parameters */
handle_t h,
sec_acl_component_name_t component_name,
sec_acl_type_t sec_acl_type,
uuid_t *manager_type,
boolean32 writing,
void *resolver_arg
/* [out] parameters */
uuid_t *acl_uuid,
error_status_t *st
);
For situations in which neither of the ACL library resolver functions, dce_acl_resolve_by_uuid( ) or dce_acl_resolve_by_name( ), is appropriate, application developers must provide their own.
The following two examples illustrate the general structure of the dce_acl_resolve_by_uuid( ) API and dce_acl_resolve_by_name( ) API that are supplied in the ACL library. They may be used as paradigms for creating additional resolver routines.
The first example shows dce_acl_resolve_by_name( ).
A server has several objects and stores each in a backing store database. Part of the standard header for each object is a structure that contains the UUID of the ACL for that object. (The standard header is not intended to be an abstract type, but rather a common prolog provided to ease server development.) The resolution routine for this server retrieves the object UUID from the handle, uses that as an index into its own backing store, and uses the sec_acl_type parameter to retrieve the appropriate ACL UUID from the standard data header.
This routine needs the database handle for the server's object storage, which is specified as the resolver_arg parameter in the dce_acl_register_object_type( ) call.
#define STAT_CHECK_RET(st) { if (st != error_status_ok) return; }
dce_acl_resolve_func_t
dce_acl_resolve_by_uuid(
/* in */
handle_t h,
sec_acl_component_name_t component_name,
sec_acl_type_t sec_acl_type,
uuid_t *manager_type,
boolean32 writing,
void *resolver_arg,
/* out */
uuid_t *acl_uuid,
error_status_t *st
)
{
dce_db_handle_t db_h;
dce_db_header_t dbh;
uuid_t obj;
/* Get the object. */
rpc_binding_inq_object(h, &obj, st);
STAT_CHECK_RET(*st);
/* Get object header using the object backing store.
* The handle was passed in as the resolver_arg in the
* dce_acl_register_object_type call.
*/
db_h = (dce_db_handle_t)resolver_arg;
dce_db_std_header_fetch(db_h, &obj, &dbh, st);
STAT_CHECK_RET(*st);
/* Get the appropriate ACL based on the ACL type. */
dce_acl_inq_acl_from_header(dbh, sec_acl_type, acl_uuid, st);
STAT_CHECK_RET(*st);
}
The next example shows dce_acl_resolve_by_name( ).
A server uses the residual name to resolve an ACL object by using dce_acl_resolve_by_name( ). This routine requires a DCE database that maps names into ACL UUIDs. This backing store database must be maintained by the server application so that created objects always get a name, and that name must be a key into a database that stores the UUID identifying the object. The resolver_arg parameter given in the dce_acl_register_object_type( ) call must be a handle for that database.
#define STAT_CHECK_RET(st) { if (st != error_status_ok) return; }
dce_acl_resolve_func_t
dce_acl_resolve_by_name(
/* in */
handle_t h,
sec_acl_component_name_t component_name,
sec_acl_type_t sec_acl_type,
uuid_t *manager_type,
boolean32 writing,
void *resolver_arg,
/* out */
uuid_t *acl_uuid,
error_status_t *st
)
{
dce_db_handle_t db_h;
dce_db_header_t dbh;
/* Get object header using the object backing store.
* The handle was passed in as the resolver_arg in the
* dce_acl_register_object_type call.
*/
db_h = (dce_db_handle_t)resolver_arg;
dce_db_std_header_fetch(db_h, component_name, &dbh, st);
STAT_CHECK_RET(*st);
/* Get the appropriate ACL based on the ACL type. */
dce_acl_inq_acl_from_header(dbh, sec_acl_type, acl_uuid, st);
STAT_CHECK_RET(*st);
}