The following code is a listing of the acl.c program.
/***************************************************************
* *
* COPYRIGHT (C) SIEMENS NIXDORF INFORMATIONSSYSTEME AG 1991 *
* ALL RIGHTS RESERVED *
* *
***************************************************************/
/*
*
* This sample program displays the access permissions (ACL) on each
* entry in the directory for a specific user. The permissions are
* presented in a form similiar to the UNIX file permissions.
* In addition, each entry is flagged as either a master
* or a shadow copy.
*
* The distinguished name of the user performing the check is:
*
* /C=de/O=sni/OU=ap/CN=norbert
*
* The results are presented in the following format :
*
* [ABCD] <entry's distinguished name>
*
* A: 'm' master copy
* 's' shadow copy
*
* B: 'r' read access to public attributes
* 'w' write access to public attributes
* '-' no access to public attributes
*
* C: 'r' read access to standard attributes
* 'w' write access to standard attributes
* '-' no access to standard attributes
*
* D: 'r' read access to sensitive attributes
* 'w' write access to sensitive attributes
* '-' no access to sensitive attributes
*
* For example, the following result means that the entry '/C=de/O=sni'
* is a master copy and that the requesting user
* (/C=de/O=sni/OU=ap/CN=norbert) has write access to its public
* attributes, read access to its standard
* attributes and no access to its sensitive attributes.
*
* [mwr-] /C=de/O=sni
*
* The program requires that the specific user perform an authenticated
* bind to the directory. In order to achieve this the user's
* credentials must already exist in the directory.
* Therefore the following tree of 6 entries is added to the directory
* each time the program runs, and removed again afterwards.
*
* O C=de
* | (objectClass=Country,
* | ACL=(mod-pub: *
* | read-std:*
* | mod-std: *
* | read-sen:*
* | mod-sen: *))
* |
* |
* O O=sni
* | (objectClass=Organization,
* | ACL=(mod-pub: /C=de/O=sni/OU=ap/*
* | read-std:/C=de/O=sni/OU=ap/CN=stefanie
* | mod-std: /C=de/O=sni/OU=ap/CN=stefanie
* | read-sen:/C=de/O=sni/OU=ap/CN=stefanie
* | mod-sen: /C=de/O=sni/OU=ap/CN=stefanie))
* |
* O OU=ap
* | (objectClass=OrganizationalUnit,
* | ACL=(mod-pub: /C=de/O=sni/OU=ap/*
* | read-std:/C=de/O=sni/OU=ap/CN=stefanie
* | mod-std: /C=de/O=sni/OU=ap/CN=stefanie
* | read-sen:/C=de/O=sni/OU=ap/CN=stefanie
* | mod-sen: /C=de/O=sni/OU=ap/CN=stefanie))
* |
* |
* +-------+-------+
* | | |
* | | O CN=ingrid
* | | (objectClass=OrganizationalPerson,
* | | ACL=(mod-pub: /C=de/O=sni/OU=ap/*
* | | read-std:/C=de/O=sni/OU=ap/*
* | | mod-std: /C=de/O=sni/OU=ap/CN=stefanie
* | | read-sen:/C=de/O=sni/OU=ap/*
* | | mod-sen: /C=de/O=sni/OU=ap/CN=stefanie),
* | | surname="Schmid",
* | | telephone="+49 89 636 0",
* | | userPassword="secret")
* | |
* | O CN=norbert
* | (objectClass=OrganizationalPerson,
* | ACL=(mod-pub: /C=de/O=sni/OU=ap/*
* | read-std:/C=de/O=sni/OU=ap/*
* | mod-std: /C=de/O=sni/OU=ap/CN=stefanie
* | read-sen:/C=de/O=sni/OU=ap/*
* | mod-sen: /C=de/O=sni/OU=ap/CN=stefanie),
* | surname="Schmid",
* | telephone="+49 89 636 0",
* | userPassword="secret")
* |
* O CN=stefanie
* (objectClass=OrganizationalPerson,
* ACL=(mod-pub: /C=de/O=sni/OU=ap/*
* read-std:/C=de/O=sni/OU=ap/*
* mod-std: /C=de/O=sni/OU=ap/CN=stefanie
* read-sen:/C=de/O=sni/OU=ap/*
* mod-sen: /C=de/O=sni/OU=ap/CN=stefanie),
* surname="Schmid",
* telephone="+49 89 636 0",
* userPassword="secret")
*
*
*/
#ifdef THREADSAFE
#include <pthread.h>
#endif
#include <xom.h>
#include <xds.h>
#include <xdsbdcp.h>
#include <xdsgds.h>
#include <xdscds.h>
#include "acl.h" /* static initialization of data structures. */
void
main(
int argc,
char *argv[]
)
{
OM_workspace workspace; /* workspace for objects */
OM_private_object session; /* Session object. */
OM_private_object bound_session; /* Holds the Session object which */
/* is returned by ds_bind() */
OM_private_object context; /* Context object. */
OM_private_object result; /* Holds the search result object. */
OM_sint invoke_id; /* Integer for the invoke id */
/* returned by ds_search(). */
/* (this parameter must be present */
/* even though it is ignored). */
OM_type sinfo_list[] = { DS_SEARCH_INFO, 0 };
OM_type entry_list[] = { DS_ENTRIES, 0 };
/* Lists of types to be extracted */
OM_public_object sinfo; /* Search-Info object from result. */
OM_public_object entry; /* Entry object from search info. */
OM_value_position total_num; /* Number of descriptors returned. */
OM_return_code rc; /* XOM function return code. */
register int i;
char user_name[MAX_DN_LEN];
/* Holds requestor's name. */
char entry_string[MAX_DN_LEN + 7] = "[?r??] ";
/* Holds entry details. */
/* Step 3 (see acl.h program code for Steps 1 and 2)
*
* Initialise a directory workspace for use by XOM.
*/
if ((workspace = ds_initialize()) == (OM_workspace)0)
printf("ds_initialize() error\n");
/* Step 4
*
* Negotiate the use of the BDCP and GDS packages.
*/
if (ds_version(features, workspace) != DS_SUCCESS)
printf("ds_version() error\n");
/* Step 5
*
* Add a fixed tree of entries to the directory in order to permit
* an authenticated bind by: /C=de/O=sni/OU=ap/CN=norbert
*/
if (! add_tree(workspace))
printf("add_tree() error\n");
/* Step 6
*
* Create a default session object.
*/
if ((rc = om_create(DSX_C_GDS_SESSION,OM_TRUE,workspace,&session))
!= OM_SUCCESS)
printf("om_create() error %d\n", rc);
/* Step 7
*
* Alter the default session object to include the following
* credentials: requestor: /C=de/O=sni/OU=ap/CN=norbert
* password: "secret"
* authentication mechanism: simple
*/
if ((rc = om_put(session, OM_REPLACE_ALL, credentials, 0 ,0, 0))
!= OM_SUCCESS)
printf("om_put() error %d\n", rc);
/* Step 8
*
* Bind with credentials to the default GDS server. The returned
* session object is stored in the private object variable
* bound_session and is used for all further XDS function calls.
*/
if (ds_bind(session, workspace, &bound_session) != DS_SUCCESS)
printf("ds_bind() error\n");
/* Step 9
*
* Create a default context object.
*/
if ((rc = om_create(DSX_C_GDS_CONTEXT,OM_TRUE,workspace,&context))
!= OM_SUCCESS)
printf("om_create() error %d\n", rc);
/*
* Alter the default context object to include 'shadow' entries.
*/
if ((rc = om_put(context, OM_REPLACE_ALL, use_copy, 0 ,0, 0))
!= OM_SUCCESS)
printf("om_put() error %d\n", rc);
/* Step 10
*
* Search the whole subtree below root. The filter selects
* entries with an object-class attribute. The selection
* extracts the ACL attribute from each selected entry.
* The results are returned in the private object 'result'.
*
* NOTE: Since every entry contains an object-class attribute the
* filter performs no function other than to demonstrate how
* filters may be used.
*/
if (ds_search(bound_session, context, dn_root, DS_WHOLE_SUBTREE,
filter, OM_FALSE, selection_acl, &result, &invoke_id)
!= DS_SUCCESS)
printf("ds_search() error\n");
/* Step 11
*
* Close the connection to the GDS server.
*/
if (ds_unbind(bound_session) != DS_SUCCESS)
printf("ds_unbind() error\n");
/* Step 12
*
* Remove the user's credentials from the directory.
*/
if (! remove_tree(workspace, session))
printf("remove_tree() error\n");
/* Step 13
*
* Extract components from the search result by means of om_get().
*/
if ((rc = om_get(result,
OM_EXCLUDE_ALL_BUT_THESE_TYPES + OM_EXCLUDE_SUBOBJECTS,
sinfo_list, OM_FALSE, 0, 0, &sinfo, &total_num))
!= OM_SUCCESS)
printf("om_get(Search-Result) error %d\n", rc);
if ((rc = om_get(sinfo->value.object.object,
OM_EXCLUDE_ALL_BUT_THESE_TYPES + OM_EXCLUDE_SUBOBJECTS,
entry_list, OM_FALSE, 0, 0, &entry, &total_num))
!= OM_SUCCESS)
printf("om_get(Search-Info) error %d\n", rc);
/*
* Convert the requestor's distinguished name to string format.
*/
if (! xds_name_to_string(dn_norbert, user_name))
printf("xds_name_to_string() error\n");
printf("User: %s\nTotal: %d\n", user_name, total_num);
/* Step 14
*
* Examine each entry and print the entry details.
*/
for (i = 0; i < total_num; i++) {
if (process_entry_info((entry+i)->value.object.object,
entry_string, user_name))
printf("%s\n", entry_string);
}
/* Step 15
*
* Close the directory workspace.
*/
if (ds_shutdown(workspace) != DS_SUCCESS)
printf("ds_shutdown() error\n");
}
/*
* Add the tree of entries described above.
*/
int
add_tree(
OM_workspace workspace
)
{
OM_private_object session; /* Holds the Session object which */
/* is returned by ds_bind() */
OM_sint invoke_id; /* Integer for the invoke id */
int error = 0;
/* Bind (without credentials) to the default GDS server. */
if (ds_bind(DS_DEFAULT_SESSION, workspace, &session) != DS_SUCCESS)
error++;
/* Add entries to the GDS server. */
ds_add_entry(session, DS_DEFAULT_CONTEXT, dn_de, alist_C,
&invoke_id);
if (ds_add_entry(session, DS_DEFAULT_CONTEXT, dn_sni, alist_O,
&invoke_id) != DS_SUCCESS)
error++;
if (ds_add_entry(session, DS_DEFAULT_CONTEXT, dn_ap, alist_OU,
&invoke_id) != DS_SUCCESS)
error++;
if (ds_add_entry(session, DS_DEFAULT_CONTEXT, dn_stefanie, alist_OP,
&invoke_id) != DS_SUCCESS)
error++;
if (ds_add_entry(session, DS_DEFAULT_CONTEXT, dn_norbert, alist_OP,
&invoke_id) != DS_SUCCESS)
error++;
if (ds_add_entry(session, DS_DEFAULT_CONTEXT, dn_ingrid, alist_OP,
&invoke_id) != DS_SUCCESS)
error++;
/* Close the connection to the GDS server. */
if (ds_unbind(session) != DS_SUCCESS)
error++;
return (error?0:1);
}
/*
* Remove the tree of entries described above.
*/
int
remove_tree(
OM_workspace workspace,
OM_private_object session
)
{
OM_private_object bound_session; /* Holds Session object which */
/* is returned by ds_bind() */
OM_sint invoke_id; /* Integer for the invoke id */
int error = 0;
/* Bind (with credentials) to the default GDS server. */
if (ds_bind(session, workspace, &bound_session) != DS_SUCCESS)
error++;
/* Remove entries from the GDS server. */
if (ds_remove_entry(bound_session, DS_DEFAULT_CONTEXT, dn_ingrid,
&invoke_id) != DS_SUCCESS)
error++;
if (ds_remove_entry(bound_session, DS_DEFAULT_CONTEXT, dn_stefanie,
&invoke_id) != DS_SUCCESS)
error++;
if (ds_remove_entry(bound_session, DS_DEFAULT_CONTEXT, dn_norbert,
&invoke_id) != DS_SUCCESS)
error++;
if (ds_remove_entry(bound_session, DS_DEFAULT_CONTEXT, dn_ap,
&invoke_id) != DS_SUCCESS)
error++;
if (ds_remove_entry(bound_session, DS_DEFAULT_CONTEXT, dn_sni,
&invoke_id) != DS_SUCCESS)
error++;
ds_remove_entry(bound_session, DS_DEFAULT_CONTEXT, dn_de,
&invoke_id);
/* Close the connection to the GDS server. */
if (ds_unbind(bound_session) != DS_SUCCESS)
error++;
return (error?0:1);
}
/*
* Convert a distinguished name in XDS format (OM_descriptor
* lists) to string format.
*/
int
xds_name_to_string(
OM_public_object name, /* Xds distinguished name. */
char *string /* String distinguished name. */
)
{
register OM_object dn = name;
register OM_object rdn;
register OM_object ava;
register char *sp = string;
int error = 0;
while ((dn->type != OM_NO_MORE_TYPES) && (! error)) {
if ((dn->type == DS_RDNS) &&
((dn->syntax & OM_S_SYNTAX) == OM_S_OBJECT)) {
rdn = dn->value.object.object;
while ((rdn->type != OM_NO_MORE_TYPES) && (! error)) {
if ((rdn->type == DS_AVAS) &&
((rdn->syntax & OM_S_SYNTAX) == OM_S_OBJECT)) {
ava = rdn->value.object.object;
while ((ava->type != OM_NO_MORE_TYPES) &&
(! error)) {
if ((ava->type == DS_ATTRIBUTE_TYPE) &&
((ava->syntax & OM_S_SYNTAX) ==
OM_S_OBJECT_IDENTIFIER_STRING)) {
*sp++ = '/';
if (strncmp(ava->value.string.elements,
DS_A_COUNTRY_NAME.elements,
ava->value.string.length) == 0)
*sp++ = 'C';
else if (strncmp(ava->value.string.elements,
DS_A_ORG_NAME.elements,
ava->value.string.length) == 0)
*sp++ = 'O';
else if (strncmp(ava->value.string.elements,
DS_A_ORG_UNIT_NAME.elements,
ava->value.string.length) == 0)
*sp++ = 'O', *sp++ = 'U';
else if (strncmp(ava->value.string.elements,
DS_A_COMMON_NAME.elements,
ava->value.string.length) == 0)
*sp++ = 'C', *sp++ = 'N';
else if (strncmp(ava->value.string.elements,
DS_A_LOCALITY_NAME.elements,
ava->value.string.length) == 0)
*sp++ = 'L';
else if (strncmp(ava->value.string.elements,
DSX_TYPELESS_RDN.elements,
ava->value.string.length) != 0) {
error++;
continue;
}
if (*(sp-1) != '/'); /* no '=' if typeless*/
*sp++ = '=';
}
if (ava->type == DS_ATTRIBUTE_VALUES) {
switch(ava->syntax & OM_S_SYNTAX) {
case OM_S_PRINTABLE_STRING :
case OM_S_TELETEX_STRING :
strncpy(sp, ava->value.string.elements,
ava->value.string.length);
sp += ava->value.string.length;
break;
default:
error++;
continue;
}
}
ava++;
}
}
rdn++;
}
}
dn++;
}
*sp = '\0';
return (error?0:1);
}
/*
* Extract information about an entry from the Entry-Info object:
* whether the entry is a master-copy, its ACL permissions and
* its distinguished name.
* Build up a string based on this information.
*/
int
process_entry_info(
OM_private_object entry,
char *entry_string,
char *user_name
)
{
OM_return_code rc; /* Return code from XOM function. */
OM_public_object ei_attrs; /* Components from Entry-Info. */
OM_public_object attr; /* Directory attribute. */
OM_public_object acl; /* ACL attribute value. */
OM_public_object acl_item; /* ACL item component. */
OM_value_position total_attrs; /* Number of attributes returned. */
register int i;
register int interp;
register int error = 0;
register int found_acl = 0;
static OM_type ei_attr_list[] = { DS_FROM_ENTRY,
DS_OBJECT_NAME,
DS_ATTRIBUTES,
0 };
/* Attributes to be extracted. */
/*
* Extract three attributes from each Entry-Info object.
*/
if ((rc = om_get(entry, OM_EXCLUDE_ALL_BUT_THESE_TYPES,
ei_attr_list, OM_FALSE, 0, 0, &ei_attrs, &total_attrs))
!= OM_SUCCESS) {
error++;
printf("om_get(Entry-Info) error %d\n", rc);
}
for (i = 0; ((i < total_attrs) && (! error)); i++, ei_attrs++) {
/*
* Determine if current entry is a master-copy or a shadow-copy.
*/
if ((ei_attrs->type == DS_FROM_ENTRY) &&
((ei_attrs->syntax & OM_S_SYNTAX) == OM_S_BOOLEAN))
if (ei_attrs->value.boolean == OM_TRUE)
entry_string[1] = 'm';
else if (ei_attrs->value.boolean == OM_FALSE)
entry_string[1] = 's';
else
entry_string[1] = '?';
if ((ei_attrs->type == DS_ATTRIBUTES) &&
((ei_attrs->syntax & OM_S_SYNTAX) == OM_S_OBJECT)) {
attr = ei_attrs->value.object.object;
while ((attr->type != OM_NO_MORE_TYPES) && (! error)) {
/*
* Check that the attribute is an ACL attribute.
*/
if ((attr->type == DS_ATTRIBUTE_TYPE) &&
((attr->syntax & OM_S_SYNTAX) ==
OM_S_OBJECT_IDENTIFIER_STRING)) {
if (strncmp(attr->value.string.elements,
DSX_A_ACL.elements,
attr->value.string.length) == 0)
found_acl++;
}
/*
* Examine the ACL. Check each permission for
* the current user.
*/
if ((found_acl) &&
(attr->type == DS_ATTRIBUTE_VALUES) &&
((attr->syntax & OM_S_SYNTAX) == OM_S_OBJECT)) {
acl = attr->value.object.object;
entry_string[2] = 'r';
entry_string[3] = '-';
entry_string[4] = '-';
while (acl->type != OM_NO_MORE_TYPES) {
if ((acl->syntax & OM_S_SYNTAX) == OM_S_OBJECT)
acl_item = acl->value.object.object;
switch (acl->type) {
case OM_CLASS:
break;
case DSX_MODIFY_PUBLIC:
if (permitted_access(user_name, acl_item))
entry_string[2] = 'w';
break;
case DSX_READ_STANDARD:
if (permitted_access(user_name, acl_item))
entry_string[3] = 'r';
break;
case DSX_MODIFY_STANDARD:
if (permitted_access(user_name, acl_item))
entry_string[3] = 'w';
break;
case DSX_READ_SENSITIVE:
if (permitted_access(user_name, acl_item))
entry_string[4] = 'r';
break;
case DSX_MODIFY_SENSITIVE:
if (permitted_access(user_name, acl_item))
entry_string[4] = 'w';
break;
}
acl++;
}
}
attr++;
}
}
/*
* Convert the entry's distinguished name to a string format.
*/
if ((ei_attrs->type == DS_OBJECT_NAME) &&
((ei_attrs->syntax & OM_S_SYNTAX) == OM_S_OBJECT))
if (! xds_name_to_string(ei_attrs->value.object.object,
&entry_string[7])) {
error++;
printf("xds_name_to_string() error\n");
}
}
return (error?0:1);
}
/*
* Check if a user is permitted access based on the ACL supplied.
*
*/
int
permitted_access(
char *user_name,
OM_public_object acl_item
)
{
char acl_name[MAX_DN_LEN];
int interpretation;
int acl_present = 0;
int access = 0;
int acl_name_length;
while (acl_item->type != OM_NO_MORE_TYPES) {
switch (acl_item->type) {
case OM_CLASS:
break;
case DSX_INTERPRETATION:
interpretation = acl_item->value.boolean;
break;
case DSX_USER:
xds_name_to_string(acl_item->value.object.object, acl_name);
if (interpretation == DSX_SINGLE_OBJECT) {
if (strcmp(acl_name, user_name) == 0)
access = 1;
}
else if (interpretation == DSX_ROOT_OF_SUBTREE) {
if ((acl_name_length = strlen(acl_name)) == 0)
access = 1;
else if (strncmp(acl_name,user_name,
acl_name_length) == 0)
access = 1;
}
break;
}
acl_item++;
}
return (access);
}