/*  Copyright (c) 2002, 2003, 2006 The Regents of the University of Michigan.
 *  All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions
 *  are met:
 *
 *  1. Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *  2. Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 *  3. Neither the name of the University nor the names of its
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 *  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
 *  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 *  DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 *  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
 *  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */


#ifndef LIBACL_NFS4_H
#define LIBACL_NFS4_H 1

#include <sys/types.h>
#include <pwd.h>
#include <grp.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/queue.h>
#include <sys/errno.h>
#include <string.h>
#include "nfs4.h"

/* flags'/perms' corresponding display characters */
#define TYPE_ALLOW			'A'
#define TYPE_DENY 			'D'
#define TYPE_AUDIT			'U'
#define TYPE_ALARM			'L'

#define FLAG_FILE_INHERIT		'f'
#define FLAG_DIR_INHERIT		'd'
#define FLAG_NO_PROPAGATE_INHERIT	'n'
#define FLAG_INHERIT_ONLY		'i'
#define FLAG_SUCCESSFUL_ACCESS		'S'
#define FLAG_FAILED_ACCESS		'F'
#define FLAG_GROUP			'g'
#define FLAG_INHERITED			'I'

#define PERM_READ_DATA			'r'
#define PERM_WRITE_DATA			'w'
#define PERM_APPEND_DATA		'a'

#define PERM_LIST_DIR			PERM_READ_DATA
#define PERM_CREATE_FILE		PERM_WRITE_DATA
#define PERM_CREATE_SUBDIR		PERM_APPEND_DATA
#define PERM_DELETE_CHILD		'D'

#define PERM_DELETE			'd'
#define PERM_EXECUTE			'x'
#define PERM_READ_ATTR			't'
#define PERM_WRITE_ATTR			'T'
#define PERM_READ_NAMED_ATTR		'n'
#define PERM_WRITE_NAMED_ATTR		'N'
#define PERM_READ_ACL			'c'
#define PERM_WRITE_ACL			'C'
#define PERM_WRITE_OWNER		'o'
#define PERM_SYNCHRONIZE		'y'

#define PERM_GENERIC_READ		'R'
#define PERM_GENERIC_WRITE		'W'
#define PERM_GENERIC_EXECUTE		'X'

/* mode bit translations: */
#define NFS4_READ_MODE NFS4_ACE_READ_DATA
#define NFS4_WRITE_MODE (NFS4_ACE_WRITE_DATA \
		| NFS4_ACE_APPEND_DATA | NFS4_ACE_DELETE_CHILD)
#define NFS4_EXECUTE_MODE NFS4_ACE_EXECUTE
#define NFS4_ANYONE_MODE (NFS4_ACE_READ_ATTRIBUTES | NFS4_ACE_READ_ACL | \
		NFS4_ACE_SYNCHRONIZE)
#define NFS4_OWNER_MODE (NFS4_ACE_WRITE_ATTRIBUTES | NFS4_ACE_WRITE_ACL)

/* flags used to simulate posix default ACLs */
#define NFS4_INHERITANCE_FLAGS (NFS4_ACE_FILE_INHERIT_ACE \
		| NFS4_ACE_DIRECTORY_INHERIT_ACE | NFS4_ACE_INHERIT_ONLY_ACE)

/*
 * NFS4_MAX_ACESIZE -- the number of bytes in the string representation we
 * read in (not the same as on-the-wire, which is also not the same as how
 * NFSD actually stores the ACEs).
 *
 * Note that right now NFSD tolerates at most 170 ACEs, regardless of size,
 * and linux in general tolerates at most 64KB xattrs.
 *
 * :     3 of these
 * type  1
 * flag  7 (total number of flag characters)
 * who   NFS4_MAX_PRINCIPALSIZE  (user:128, domain:256, '@':1, NULL:1)
 * mask  14 (total number of dir + common mask characters)
 *
 * which equals 410.  let's try that for now.
 */
#define NFS4_MAX_ACESIZE	(3 + 1 + 7 + NFS4_MAX_PRINCIPALSIZE + 14)

/*
 * NFS4_MAX_ACLSIZE -- the number of bytes in the string representation
 * of a whole ACL, regardless of the number of ACEs; used to set buffer
 * sizes.  since linux limits xattrs to 64KB anyway, we don't have to
 * worry about/can't really handle huge ACLs.  while the string
 * representation doesn't directly compare to the xattr size, this
 * is probably a reasonable guess.
 */
#define NFS4_MAX_ACLSIZE	(65536)


/* NFS4 acl xattr name */
#define ACL_NFS4_XATTR "system.nfs4_acl"
#define DACL_NFS4_XATTR "system.nfs4_dacl"
#define SACL_NFS4_XATTR "system.nfs4_sacl"

/* Macro for finding empty tailqs */
#define TAILQ_IS_EMPTY(head) (head.tqh_first == NULL)

/* Flags to pass certain properties around */
#define NFS4_ACL_NOFLAGS			0x00
#define NFS4_ACL_ISFILE				0x00
#define NFS4_ACL_ISDIR				0x01
#define NFS4_ACL_OWNER				0x02
#define NFS4_ACL_REQUEST_DEFAULT	0x04
#define NFS4_ACL_RAW				0x01

#define NFS4_XDR_MOD				4

typedef u_int32_t u32;

enum acl_type {
	ACL_TYPE_ACL,
	ACL_TYPE_DACL,
	ACL_TYPE_SACL
};

enum {	ACL_NFS4_NOT_USED = 0,
		ACL_NFS4_USED
};

struct ace_container {
	struct nfs4_ace *ace;
	TAILQ_ENTRY(ace_container) l_ace;
};

TAILQ_HEAD(ace_container_list_head, ace_container);

/**** Public functions ****/

extern struct nfs4_acl *	nfs4_getacl(const char *path);
extern struct nfs4_acl *	nfs4_getdacl(const char *path);
extern struct nfs4_acl *	nfs4_getsacl(const char *path);
extern int			nfs4_setacl(const char *path, struct nfs4_acl *acl);
extern int			nfs4_setdacl(const char *path, struct nfs4_acl *acl);
extern int			nfs4_setsacl(const char *path, struct nfs4_acl *acl);

/** Manipulation functions **/
extern int			acl_nfs4_set_who(struct nfs4_ace*, int, char*);
extern struct nfs4_acl *	acl_nfs4_copy_acl(struct nfs4_acl *);
extern struct nfs4_acl *	acl_nfs4_xattr_load(char *, int, u32);
extern struct nfs4_acl *	acl_nfs41_xattr_load(char *, int, u32, enum acl_type);
extern int			acl_nfs4_xattr_pack(struct nfs4_acl *, char**);
extern int			acl_nfs41_xattr_pack(struct nfs4_acl *, char**, enum acl_type);
extern int			acl_nfs4_xattr_size(struct nfs4_acl *);

extern void			nfs4_free_acl(struct nfs4_acl *);
extern int			nfs4_set_acl(struct nfs4_acl *acl, const char *path);
extern int			nfs4_remove_ace(struct nfs4_acl *acl, struct nfs4_ace *ace);
extern int			nfs4_remove_ace_at(struct nfs4_acl *acl, unsigned int index);
extern int			nfs4_insert_ace_at(struct nfs4_acl *acl, struct nfs4_ace *ace, unsigned int index);
#define nfs4_prepend_ace(acl, ace)  nfs4_insert_ace_at(acl, ace, 0)
#define nfs4_append_ace(acl, ace)   nfs4_insert_ace_at(acl, ace, acl->naces)
extern struct nfs4_ace *	nfs4_new_ace(int is_directory, u32 type, u32 flag, u32 access_mask, int whotype, char* who);
extern struct nfs4_acl *	nfs4_new_acl(u32);

extern int 			nfs4_insert_file_aces(struct nfs4_acl *acl, FILE* fd, unsigned int index);
extern int 			nfs4_insert_string_aces(struct nfs4_acl *acl, const char *acl_spec, unsigned int index);
extern int			nfs4_replace_ace(struct nfs4_acl *acl, struct nfs4_ace *old_ace, struct nfs4_ace *new_ace);
extern int			nfs4_replace_ace_spec(struct nfs4_acl *acl, char *from_ace_spec, char *to_ace_spec);
extern int			nfs4_remove_file_aces(struct nfs4_acl *acl, FILE *fd);
extern int			nfs4_remove_string_aces(struct nfs4_acl *acl, char *string);


/** Conversion functions **/
extern struct nfs4_ace * 	nfs4_ace_from_string(char *ace_spec, int is_dir);
extern struct nfs4_acl * 	nfs4_acl_for_path(const char *path);
extern char *			nfs4_acl_spec_from_file(FILE *f);


/** Access Functions **/
extern int			acl_nfs4_get_who(struct nfs4_ace*, int*, char**);
extern int			acl_nfs4_get_whotype(char*);

extern struct nfs4_ace *	nfs4_get_first_ace(struct nfs4_acl *);
extern struct nfs4_ace *	nfs4_get_next_ace(struct nfs4_ace **);
extern struct nfs4_ace *	nfs4_get_ace_at(struct nfs4_acl *, unsigned int index);


/** Display Functions **/
extern void			nfs4_print_acl(FILE *fp, struct nfs4_acl *acl);
extern int			nfs4_print_ace(FILE *fp, struct nfs4_ace *ace, u32 isdir);
extern int			nfs4_print_ace_verbose(struct nfs4_ace * ace, u32 isdir);
extern char*			nfs4_get_ace_type(struct nfs4_ace*, char*, int);
extern char*			nfs4_get_ace_flags(struct nfs4_ace*, char*);
extern char*			nfs4_get_ace_access(struct nfs4_ace*, char*, int);


/** misc **/
extern int 			nfs4_ace_cmp(struct nfs4_ace *lhs, struct nfs4_ace *rhs);
extern unsigned long		strtoul_reals(char *s, int base);
#endif
