/************************************ */
/* Rule Set Based Access Control      */
/* Author and (c) 1999,2000: Amon Ott */
/* API: Data structures               */
/* and functions for Access           */
/* Control Information / ACL          */
/* Last modified: 12/Feb/2000         */
/************************************ */

#ifndef __RSBAC_ACL_H
#define __RSBAC_ACL_H

#include <linux/init.h>
#include <rsbac/types.h>

/***************************************************/
/*               General Prototypes                */
/***************************************************/

/* All functions return 0, if no error occurred, and a negative error code  */
/* otherwise. The error codes are defined in rsbac_error.h.                 */

/****************************************************************************/
/* Initialization, including ACI restoration for all mounted devices from   */
/* disk. After this call, all ACI is kept in memory for performance reasons,*/
/* but user and file/dir object ACI are written to disk on every change.    */

extern int rsbac_init_acl(void) __init;

/* mounting and umounting */
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)
int rsbac_mount_acl(kdev_t);
#else
int rsbac_mount_acl(kdev_t, struct dentry *);
#endif
int rsbac_umount_acl(kdev_t kdev);

/* Some information about the current status is also available */
extern int rsbac_stats_acl(void);

/* Status checking */
extern int rsbac_check_acl(int correct, int check_inode);

/* RSBAC attribute saving to disk can be triggered from outside
 * param: call lock_kernel() before writing?
 */
#if defined(CONFIG_RSBAC_ACL_MAINT) || defined(CONFIG_RSBAC_AUTO_WRITE)
extern int rsbac_write_acl(boolean);
#endif /* CONFIG_RSBAC_AUTO_WRITE */

/************************************************* */
/*               Access functions                  */
/************************************************* */

/* All these procedures handle the spinlocks to protect the targets during */
/* access.                                                                 */

/* rsbac_acl_set_acl_entry
 * Set ACL entry for given target and subject to given rights. If entry does
 * not exist, it is created, thus cutting the inheritance from default/parent.
 */

int rsbac_acl_set_acl_entry        (enum   rsbac_target_t              target,
                                    union  rsbac_target_id_t           tid,
                                    enum   rsbac_acl_subject_type_t    subj_type,
                                           rsbac_acl_subject_id_t      subj_id,
                                           rsbac_acl_rights_vector_t   rights);

/* rsbac_acl_remove_acl_entry
 * Remove ACL entry for given target and subject. This reactivates the
 * inheritance from default/parent.
 */

int rsbac_acl_remove_acl_entry     (enum   rsbac_target_t              target,
                                    union  rsbac_target_id_t           tid,
                                    enum   rsbac_acl_subject_type_t    subj_type,
                                           rsbac_acl_subject_id_t      subj_id);

/* rsbac_acl_remove_acl
 * Remove ACL for given target. For cleanup on delete.
 */

int rsbac_acl_remove_acl     (enum   rsbac_target_t              target,
                              union  rsbac_target_id_t           tid);

/* rsbac_acl_add_to_acl_entry
 * Add given rights to ACL entry for given target and subject. If entry does
 * not exist, behaviour is exactly like rsbac_acl_set_acl_entry.
 */

int rsbac_acl_add_to_acl_entry     (enum   rsbac_target_t              target,
                                    union  rsbac_target_id_t           tid,
                                    enum   rsbac_acl_subject_type_t    subj_type,
                                           rsbac_acl_subject_id_t      subj_id,
                                           rsbac_acl_rights_vector_t   rights);

/* rsbac_acl_remove_from_acl_entry
 * Remove given rights from ACL entry for given target and subject. If entry does
 * not exist, nothing happens.
 * This function does NOT remove the ACL entry, so removing all rights results in
 * NO rights for this subject/target combination!
 */

int rsbac_acl_remove_from_acl_entry(enum   rsbac_target_t              target,
                                    union  rsbac_target_id_t           tid,
                                    enum   rsbac_acl_subject_type_t    subj_type,
                                           rsbac_acl_subject_id_t      subj_id,
                                           rsbac_acl_rights_vector_t   rights);

/* rsbac_acl_set_mask
 * Set inheritance mask for given target to given rights. If item does
 * not exist, it is created.
 */

int rsbac_acl_set_mask        (enum   rsbac_target_t              target,
                               union  rsbac_target_id_t           tid,
                                      rsbac_acl_rights_vector_t   mask);

/* rsbac_acl_get_mask
 * Get inheritance mask for given target to given rights. If item does
 * not exist, default mask is returned.
 */

int rsbac_acl_get_mask        (enum   rsbac_target_t              target,
                               union  rsbac_target_id_t           tid,
                                      rsbac_acl_rights_vector_t * mask_p);

/* rsbac_acl_get_rights
 * Get effective rights from ACL entry for given target and subject.
 * If entry does not exist, inherited rights are used. If there is no parent,
 * the default rights vector for this target type is returned.
 * This function does NOT add role or group rights to user rights!
 */

int rsbac_acl_get_rights       (enum   rsbac_target_t              target,
                                union  rsbac_target_id_t           tid,
                                enum   rsbac_acl_subject_type_t    subj_type,
                                       rsbac_acl_subject_id_t      subj_id,
                                       rsbac_acl_rights_vector_t * rights_p,
                                       boolean                     inherit);

/* rsbac_acl_get_super
 * Show, whether supervisor right is set for given target and subject.
 * If supervisor right is not set, it is checked at all parents, unless
 * CONFIG_RSBAC_ACL_SUPER_FILTER is set *and* supervisor is masked out.
 */

int rsbac_acl_get_super      (enum   rsbac_target_t              target,
                                union  rsbac_target_id_t           tid,
                                enum   rsbac_acl_subject_type_t    subj_type,
                                       rsbac_acl_subject_id_t      subj_id,
                                       boolean                   * result);

/************************************************************************** */
/* The rsbac_acl_copy_fd_acl() function copies a file/dir ACL to another    */
/* file/dir ACL. The old ACL of fd2 is erased before copying.               */

int rsbac_acl_copy_fd_acl(struct rsbac_fs_file_t file1,
                          struct rsbac_fs_file_t file2);

/************************************************************************** */
/* The rsbac_acl_copy_pp_acl() function copies a process acl to another     */

int rsbac_acl_copy_pp_acl(rsbac_pid_t old_pid,
                          rsbac_pid_t new_pid);

/*************************************************
 * rsbac_acl_get_tlist
 * Get subjects from ACL entries for given target.
 */

int rsbac_acl_get_tlist       (enum   rsbac_target_t            target,
                               union  rsbac_target_id_t         tid,
                               struct rsbac_acl_entry_t         entry_array[],
                                      u_int                     maxnum);

/*************************************************
 * Group management
 */

/* add a group with new id and fill this id into *group_id_p */
int rsbac_acl_add_group(rsbac_uid_t owner, enum rsbac_acl_group_type_t type, char * name,
                        rsbac_acl_group_id_t * group_id_p);

int rsbac_acl_change_group(     rsbac_acl_group_id_t     id,
                                rsbac_uid_t              owner,
                           enum rsbac_acl_group_type_t   type,
                                char                   * name);

int rsbac_acl_remove_group(rsbac_acl_group_id_t id);

int rsbac_acl_get_group_entry(rsbac_acl_group_id_t group, struct rsbac_acl_group_entry_t * entry_p);

int rsbac_acl_list_groups(rsbac_uid_t owner,
                          boolean include_global,
                          struct rsbac_acl_group_entry_t entry_array[],
                          int maxnum);

/* check group existence */
boolean rsbac_acl_group_exist(rsbac_acl_group_id_t group);

int rsbac_acl_add_group_member(rsbac_acl_group_id_t group, rsbac_uid_t user);

int rsbac_acl_remove_group_member(rsbac_acl_group_id_t group, rsbac_uid_t user);

/* check membership */
boolean rsbac_acl_group_member(rsbac_acl_group_id_t group, rsbac_uid_t user);

/* build kmalloc'd array of all group memberships of the given user */
/* returns number of groups or negative error */
/* Attention: memory deallocation with kfree must be done by caller! */
int rsbac_acl_get_user_groups(rsbac_uid_t user, rsbac_acl_group_id_t ** group_pp);

/* Returns number of members or negative error */
int rsbac_acl_get_group_members(rsbac_acl_group_id_t group, rsbac_uid_t user_array[], int maxnum);

/*************************************************/
/* remove user from all groups and from all ACLs */
int rsbac_acl_remove_user(rsbac_uid_t user);

#endif
