/*************************************************** */
/* Rule Set Based Access Control                     */
/* Author and (c) 1999-2001: Amon Ott <ao@rsbac.org> */
/* Generic List Management                           */
/* Last modified: 23/Apr/2001                        */
/*************************************************** */

/* Note: lol = list of lists, a two-level list structure */

#ifndef __RSBAC_LISTS_H
#define __RSBAC_LISTS_H

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

#define RSBAC_LIST_VERSION 3

typedef void * rsbac_list_handle_t;
typedef __u32 rsbac_list_key_t;

/* Maximum length for list (file)names */
#define RSBAC_LIST_MAX_FILENAME 15

/* Limit for max_age_in_seconds: ca. 10 years */
#define RSBAC_LIST_MAX_AGE_LIMIT (3600 * 24 * 366 * 10)

/* Maximum desc_size + data_size: Max rkmalloc size - some space for metadata */
#define RSBAC_LIST_MAX_ITEM_SIZE (RSBAC_MAX_KMALLOC - 64)

/****************************/
/* List Registration Flags: */

/* Make persistent, i.e., save to and restore from disk */
#define RSBAC_LIST_PERSIST 1

/* Ignore old list contents (still checks key, if list exists on disk) */
#define RSBAC_LIST_IGNORE_OLD 2

/* Ignore old list contents, if version upconversion is not supported
 * (no get_conv, or get_conv returned NULL) - without this flag, registration fails, if
 * list cannot be converted.
 */
#define RSBAC_LIST_IGNORE_UNSUPP_VERSION 4

/* Temporarily disallow writing list to disk, e.g. for upgrade tests */
#define RSBAC_LIST_NO_WRITE 8

/* Provide a binary backup file as /proc/rsbac-info/backup/filename */
#define RSBAC_LIST_BACKUP 16

/* Use provided default data, return it for unexisting items and
   automatically create and cleanup items with default data as necessary.
   (only items with 0 ttl (unlimited) get removed)
   (lol items with default data only get removed, if they have no subitems) */
#define RSBAC_LIST_DEF_DATA 32

/* Use provided default subitem data, return it for unexisting subitems and
   automatically create and cleanup subitems with default data as necessary.
   (only subitems with 0 ttl (unlimited) get removed) */
#define RSBAC_LIST_DEF_SUBDATA 64

/****************************/
/* Function prototypes */

/* Function to compare two descriptors, returns 0, if equal, a negative value,
 * if desc1 < desc2 and a positive value, if desc1 > desc2 (like memcmp).
 * Used for lookup and list optimization.
 * Note: Non-0 values are only used for list optimization and do not necessarily
 * imply a real order of values.
 */
typedef int rsbac_list_compare_function_t(void * desc1, void * desc2);

/* Compare function for __u32 values */
int rsbac_list_compare_u32(void * desc1, void * desc2);

/* Function to compare two datas, returns 0, if equal, and another value,
 * if not.
 * Used for lookup by data.
 * Note: list optimization is based on descriptors, so data lookup is always
 * linear search from first to last element in list order.
 */
typedef int rsbac_list_data_compare_function_t(void * data1, void * data2);

/* conversion function to upconvert old on-disk descs and datas to actual version */
/* must return 0 on success or error otherwise */
/* Attention: if old or new data_size is 0, the respective data pointer is NULL! */
typedef int rsbac_list_conv_function_t(
	void * old_desc,
	void * old_data,
	void * new_desc,
	void * new_data);

/* callback function to return an upconvert function for on-disk-version, if versions differ */
/* Note: Lists implementation does not assume anything about your version number apart
   from being of type rsbac_version_t. Use it as you like. */
typedef rsbac_list_conv_function_t * rsbac_list_get_conv_t(rsbac_version_t old_version);

/* get generic list registration version */
rsbac_version_t rsbac_list_version(void);


/* List info: This struct will be written to disk */
/*
 * list_version: a simple __u32 version number for the list. If old on-disk version is
   different, conversion is tried (depending on flags and get_conv function)
 * key: secret __u32 key, which must be the same as in on-disk version, if persistent
 * desc_size: size of the descriptor (error is returned, if list exists and value differs)
              internally reset to sizeof(__u32) for u32 call variants
 * data_size: size of data (error is returned, if list exists and value differs)
              set to 0 for sets without data
 * subdesc_size: size of the descriptor of the sublist (error is returned, if list exists
              and value differs), internally reset to sizeof(__u32) for u32 call variants
 * subdata_size: size of sublist data (error is returned, if list exists and value differs)
              set to 0 for sets without data
 * max_age: seconds until unchanged list file (no add or remove) will be purged.
   Maximum value is RSBAC_LIST_MAX_AGE_LIMIT (s.a.), use 0 for unlimited lifetime.
   (purging not yet implemented - only reused without key, please cleanup by hand)
 */
struct rsbac_list_info_t
  {
    rsbac_version_t version;
    rsbac_list_key_t key;
    __u32 desc_size;
    __u32 data_size;
    rsbac_time_t max_age; 
  };

struct rsbac_list_lol_info_t
  {
    rsbac_version_t version;
    rsbac_list_key_t key;
    __u32 desc_size;
    __u32 data_size;
    __u32 subdesc_size;
    __u32 subdata_size;
    rsbac_time_t max_age; 
  };


/* register a new list */
/*
 * If list with same name exists in memory, error -RSBAC_EEXISTS is returned.
 * If list with same name and key exists on device, it is restored depending on
   the flags.
 * If list with same name, but different key exists on disk, access is denied
   (error -EPERM).
 *
 * ds_version: for binary modules, must be RSBAC_LIST_VERSION. If version
   differs, return error.
 * handle_p: for all list accesses, an opaque handle is put into *handle_p.
 * flags: see flag values
 * compare: for lookup and list optimization, can be NULL, then
   memcmp(desc1, desc2, desc_size) is used
 * subcompare: for item lookup and optimization of sublist, can be NULL, then
   memcmp(desc1, desc2, desc_size) is used
 * get_conv: function to deliver conversion function for given version
 * get_subconv: function to deliver sublist item conversion function for given
   version
 * def_data: default data value for flag RSBAC_LIST_DEF_DATA
   (if NULL, flag is cleared)
 * def_subdata: default subdata value for flag RSBAC_LIST_DEF_SUBDATA
   (if NULL, flag is cleared)
 * name: the on-disk name, should be distinct and max. 7 or 8.2 chars
   (maxlen of RSBAC_LIST_MAX_FILENAME supported) (only used for statistics, if
   non-persistent)
 * device: the device to read list from or to save list to - use 0 for root dev
   (ignored, if non-persistent)
 */

int rsbac_list_register(
  rsbac_version_t ds_version,
  rsbac_list_handle_t *handle_p,
  struct rsbac_list_info_t info,
  u_int flags,
  rsbac_list_compare_function_t * compare,
  rsbac_list_get_conv_t * get_conv,
  void * def_data,
  char * name,
  kdev_t device);

int rsbac_list_lol_register(
  rsbac_version_t ds_version,
  rsbac_list_handle_t *handle_p,
  struct rsbac_list_lol_info_t info,
  u_int flags,
  rsbac_list_compare_function_t * compare,
  rsbac_list_compare_function_t * subcompare,
  rsbac_list_get_conv_t * get_conv,
  rsbac_list_get_conv_t * get_subconv,
  void * def_data,
  void * def_subdata,
  char * name,
  kdev_t device);

/* destroy list */
/* list is destroyed, disk file is deleted */
/* list must have been opened with register */
int rsbac_list_destroy(rsbac_list_handle_t * handle_p, rsbac_list_key_t key);

int rsbac_list_lol_destroy(rsbac_list_handle_t * handle_p, rsbac_list_key_t key);

/* detach from list */
/* list is saved (if persistent) and removed from memory. Call register for new access. */
int rsbac_list_detach(rsbac_list_handle_t * handle_p, rsbac_list_key_t key);

int rsbac_list_lol_detach(rsbac_list_handle_t * handle_p, rsbac_list_key_t key);

/* set list's no_write flag */
/* TRUE: do not write to disk, FALSE: writing allowed */
int rsbac_list_no_write
  (rsbac_list_handle_t handle, rsbac_list_key_t key, boolean no_write);

int rsbac_list_lol_no_write
  (rsbac_list_handle_t handle, rsbac_list_key_t key, boolean no_write);


/* add item */
/* if item for desc exists, the data is updated */
/* data can be NULL, if list is registered with data_size 0 (used as set) */
int rsbac_list_add(rsbac_list_handle_t handle, void * desc, void * data);

/* simple wrapper for 32Bit desc to allow using const values */
int rsbac_list_add_u32(rsbac_list_handle_t handle, __u32 desc, void * data);

/* add with time-to-live - after this time in seconds the item gets automatically removed */
/* set to 0 for unlimited (default), RSBAC_LIST_TTL_KEEP to keep previous setting */
int rsbac_list_add_ttl(
  rsbac_list_handle_t handle,
  rsbac_time_t ttl,
  void * desc,
  void * data);

int rsbac_list_add_ttl_u32(rsbac_list_handle_t handle,
                           rsbac_time_t ttl,
                           __u32 desc,
                           void * data);

/* Add list of lists sublist item, item for desc must exist */
int rsbac_list_lol_subadd(
  rsbac_list_handle_t handle,
  void * desc,
  void * subdesc,
  void * subdata);

int rsbac_list_lol_subadd_u32(rsbac_list_handle_t handle,
                              __u32 desc,
                              __u32 subdesc,
                              void * subdata);

/* add with time-to-live - after this time in seconds the item gets automatically removed */
int rsbac_list_lol_subadd_ttl(
  rsbac_list_handle_t handle,
  rsbac_time_t ttl,
  void * desc,
  void * subdesc,
  void * subdata);

int rsbac_list_lol_subadd_ttl_u32(rsbac_list_handle_t handle,
                              rsbac_time_t ttl,
                              __u32 desc,
                              __u32 subdesc,
                              void * subdata);

/* Add list of lists top level item */
int rsbac_list_lol_add(
  rsbac_list_handle_t handle,
  void * desc,
  void * data);

int rsbac_list_lol_add_u32(rsbac_list_handle_t handle, __u32 desc, void * data);

/* add with time-to-live - after this time in seconds the item gets automatically removed */
int rsbac_list_lol_add_ttl(
  rsbac_list_handle_t handle,
  rsbac_time_t ttl,
  void * desc,
  void * data);

int rsbac_list_lol_add_ttl_u32(rsbac_list_handle_t handle,
                               rsbac_time_t ttl,
                               __u32 desc,
                               void * data);


/* remove item */
int rsbac_list_remove(rsbac_list_handle_t handle, void * desc);

/* simple wrapper for 32Bit desc to allow using const values */
int rsbac_list_remove_u32(rsbac_list_handle_t handle, __u32 desc);


/* remove all items */
int rsbac_list_remove_all(rsbac_list_handle_t handle);

/* remove item from sublist - also succeeds, if item for desc or subdesc does not exist */
int rsbac_list_lol_subremove(
  rsbac_list_handle_t handle,
  void * desc,
  void * subdesc);

int rsbac_list_lol_subremove_u32(rsbac_list_handle_t handle, __u32 desc, __u32 subdesc);

/* remove same subitem from all sublists */
int rsbac_list_lol_subremove_from_all(
  rsbac_list_handle_t handle,
  void * subdesc);

int rsbac_list_lol_subremove_from_all_u32(rsbac_list_handle_t handle, __u32 subdesc);

/* remove all subitems from list */
int rsbac_list_lol_subremove_all(rsbac_list_handle_t handle, void * desc);

int rsbac_list_lol_subremove_all_u32(rsbac_list_handle_t handle, __u32 desc);

int rsbac_list_lol_remove(
  rsbac_list_handle_t handle,
  void * desc);

int rsbac_list_lol_remove_u32(rsbac_list_handle_t handle, __u32 desc);

int rsbac_list_lol_remove_all(rsbac_list_handle_t handle);


/* get item data */
/* Item data is copied - we cannot give a pointer, because item could be
 * removed */
int rsbac_list_get_data(rsbac_list_handle_t handle, void * desc, void * data);

/* simple wrapper for 32Bit desc to allow using const values */
int rsbac_list_get_data_u32(rsbac_list_handle_t handle, __u32 desc, void * data);

/* also get time-to-live - after this time in seconds the item gets automatically removed */
/* both ttl_p and data can be NULL, they are then simply not returned */
int rsbac_list_get_data_ttl(rsbac_list_handle_t handle,
                            rsbac_time_t * ttl_p,
                            void * desc,
                            void * data);

int rsbac_list_get_data_ttl_u32(rsbac_list_handle_t handle,
                                rsbac_time_t * ttl_p,
                                __u32 desc,
                                void * data);

/* get data from a subitem */
int rsbac_list_lol_get_subdata(
  rsbac_list_handle_t handle,
  void * desc,
  void * subdesc,
  void * subdata);

int rsbac_list_lol_get_subdata_u32(
  rsbac_list_handle_t handle,
  __u32 desc,
  __u32 subdesc,
  void * data);

/* also get time-to-live - after this time in seconds the item gets automatically removed */
/* both ttl_p and data can be NULL, they are then simply not returned */
int rsbac_list_lol_get_subdata_ttl(
  rsbac_list_handle_t handle,
  rsbac_time_t * ttl_p,
  void * desc,
  void * subdesc,
  void * subdata);

int rsbac_list_lol_get_subdata_ttl_u32(rsbac_list_handle_t handle,
                                   rsbac_time_t * ttl_p,
                                   __u32 desc,
                                   __u32 subdesc,
                                   void * data);


int rsbac_list_lol_get_data(rsbac_list_handle_t handle, void * desc, void * data);

int rsbac_list_lol_get_data_u32(rsbac_list_handle_t handle, __u32 desc, void * data);

/* also get time-to-live - after this time in seconds the item gets automatically removed */
/* both ttl_p and data can be NULL, they are then simply not returned */
int rsbac_list_lol_get_data_ttl(rsbac_list_handle_t handle,
                                rsbac_time_t * ttl_p,
                                void * desc,
                                void * data);

int rsbac_list_lol_get_data_ttl_u32(rsbac_list_handle_t handle,
                                    rsbac_time_t * ttl_p,
                                    __u32 desc,
                                    void * data);


/* get item desc by data */
/* Item desc is copied - we cannot give a pointer, because item could be
 * removed.
 * If no compare function is provided (NULL value), memcmp is used.
 * Note: The data value given here is always used as second parameter to the
 *       compare function, so you can use different types for storage and
 *       lookup.
 */
int rsbac_list_get_desc(rsbac_list_handle_t handle,
                        void * desc,
                        void * data,
                        rsbac_list_data_compare_function_t compare);

/* simple wrapper for 32Bit data to allow using const values */
int rsbac_list_get_desc_u32(rsbac_list_handle_t handle, void * desc, __u32 data);

/* get maximum desc (uses compare function) */
int rsbac_list_get_max_desc(rsbac_list_handle_t handle, void * desc);

/* does item exist? */
/* returns TRUE, if item exists, FALSE, if not or error */
int rsbac_list_exist(rsbac_list_handle_t handle, void * desc);

/* simple wrapper for 32Bit desc to allow using const values */
int rsbac_list_exist_u32(rsbac_list_handle_t handle, __u32 desc);

int rsbac_list_lol_subexist(
  rsbac_list_handle_t handle,
  void * desc,
  void * subdesc);

int rsbac_list_lol_subexist_u32(rsbac_list_handle_t handle, __u32 desc, __u32 subdesc);

int rsbac_list_lol_exist(
  rsbac_list_handle_t handle,
  void * desc);

int rsbac_list_lol_exist_u32(rsbac_list_handle_t handle, __u32 desc);


/* count number of elements */
/* returns number of elements or negative error code */
long rsbac_list_count(rsbac_list_handle_t handle);

long rsbac_list_lol_subcount(rsbac_list_handle_t handle, void * desc);

long rsbac_list_lol_all_subcount(rsbac_list_handle_t handle);

long rsbac_list_lol_count(rsbac_list_handle_t handle);


/* Get array of all descriptors */
/* Returns number of elements or negative error code */
/* If return value > 0, *array_p contains a pointer to a vmalloc'd array of descs,
   otherwise *array_p is set to NULL. If *array_p has been set, caller must call
   vfree(*array_p) after use! */

long rsbac_list_get_all_desc(rsbac_list_handle_t handle, void ** array_p);

long rsbac_list_lol_get_all_subdesc(rsbac_list_handle_t handle, void * desc, void ** array_p);

long rsbac_list_lol_get_all_subdesc_ttl(rsbac_list_handle_t handle,
                                        void * desc,
                                        void ** array_p,
                                        rsbac_time_t ** ttl_array_p);

long rsbac_list_lol_get_all_desc(rsbac_list_handle_t handle, void ** array_p);


/* Get array of all datas */
/* Returns number of elements or negative error code */
/* If return value > 0, *array_p contains a pointer to a vmalloc'd array of datas,
   otherwise *array_p is set to NULL. If *array_p has been set, caller must call
   vfree(*array_p) after use! */

long rsbac_list_get_all_data(rsbac_list_handle_t handle, void ** array_p);

long rsbac_list_lol_get_all_subdata(rsbac_list_handle_t handle, void * desc, void ** array_p);

long rsbac_list_lol_get_all_data(rsbac_list_handle_t handle, void ** array_p);


/* Get item size */

int rsbac_list_get_item_size(rsbac_list_handle_t handle);

int rsbac_list_lol_get_subitem_size(rsbac_list_handle_t handle);

int rsbac_list_lol_get_item_size(rsbac_list_handle_t handle);

/* Get array of all items */
/* Returns number of items or negative error code */
/* If return value > 0, *array_p contains a pointer to a vmalloc'd array of items,
   where desc and data are placed directly behind each other.
   If *array_p has been set, caller must call vfree(*array_p) after use! */

long rsbac_list_get_all_items(rsbac_list_handle_t handle, void ** array_p);

long rsbac_list_get_all_items_ttl(rsbac_list_handle_t handle,
                                  void ** array_p,
                                  rsbac_time_t ** ttl_array_p);

long rsbac_list_lol_get_all_subitems(rsbac_list_handle_t handle, void * desc, void ** array_p);

long rsbac_list_lol_get_all_subitems_ttl(rsbac_list_handle_t handle,
                                         void * desc,
                                         void ** array_p,
                                         rsbac_time_t ** ttl_array_p);

long rsbac_list_lol_get_all_items(rsbac_list_handle_t handle, void ** array_p);


#endif
/* end of lists.h */
