/*
 * security.h - Exports for handling security/ACLs in NTFS.  
 *              Originated from the Linux-NTFS project.
 *
 * Copyright (c) 2004      Anton Altaparmakov
 * Copyright (c) 2005-2006 Szabolcs Szakacsits
 * Copyright (c) 2007-2010 Jean-Pierre Andre
 *
 * This program/include file is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as published
 * by the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program/include file is distributed in the hope that it will be
 * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program (in the main directory of the NTFS-3G
 * distribution in the file COPYING); if not, write to the Free Software
 * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#ifndef _NTFS_SECURITY_H
#define _NTFS_SECURITY_H

#include "types.h"
#include "layout.h"
#include "inode.h"
#include "dir.h"

#ifndef POSIXACLS
#define POSIXACLS 0
#endif

typedef u16 be16;
typedef u32 be32;

#if __BYTE_ORDER == __LITTLE_ENDIAN
#define const_cpu_to_be16(x) ((((x) & 255L) << 8) + (((x) >> 8) & 255L))
#define const_cpu_to_be32(x) ((((x) & 255L) << 24) + (((x) & 0xff00L) << 8) \
			+ (((x) >> 8) & 0xff00L) + (((x) >> 24) & 255L))
#else
#define const_cpu_to_be16(x) (x)
#define const_cpu_to_be32(x) (x)
#endif

/*
 *          item in the mapping list
 */

struct MAPPING {
	struct MAPPING *next;
	int xid;		/* linux id : uid or gid */
	SID *sid;		/* Windows id : usid or gsid */
	int grcnt;		/* group count (for users only) */
	gid_t *groups;		/* groups which the user is member of */
};

/*
 *		Entry in the permissions cache
 *	Note : this cache is not organized as a generic cache
 */

struct CACHED_PERMISSIONS {
	uid_t uid;
	gid_t gid;
	le32 inh_fileid;
	le32 inh_dirid;
#if POSIXACLS
	struct POSIX_SECURITY *pxdesc;
	unsigned int pxdescsize:16;
#endif
	unsigned int mode:12;
	unsigned int valid:1;
} ;

/*
 *	Entry in the permissions cache for directories with no security_id
 */

struct CACHED_PERMISSIONS_LEGACY {
	struct CACHED_PERMISSIONS_LEGACY *next;
	struct CACHED_PERMISSIONS_LEGACY *previous;
	void *variable;
	size_t varsize;
	union ALIGNMENT payload[0];
		/* above fields must match "struct CACHED_GENERIC" */
	u64 mft_no;
	struct CACHED_PERMISSIONS perm;
} ;

/*
 *	Entry in the securid cache
 */

struct CACHED_SECURID {
	struct CACHED_SECURID *next;
	struct CACHED_SECURID *previous;
	void *variable;
	size_t varsize;
	union ALIGNMENT payload[0];
		/* above fields must match "struct CACHED_GENERIC" */
	uid_t uid;
	gid_t gid;
	unsigned int dmode;
	le32 securid;
} ;

/*
 *	Header of the security cache
 *	(has no cache structure by itself)
 */

struct CACHED_PERMISSIONS_HEADER {
	unsigned int last;
			/* statistics for permissions */
	unsigned long p_writes;
	unsigned long p_reads;
	unsigned long p_hits;
} ;

/*
 *	The whole permissions cache
 */

struct PERMISSIONS_CACHE {
	struct CACHED_PERMISSIONS_HEADER head;
	struct CACHED_PERMISSIONS *cachetable[1]; /* array of variable size */
} ;

/*
 *	Security flags values
 */

enum {
	SECURITY_DEFAULT,	/* rely on fuse for permissions checking */
	SECURITY_RAW,		/* force same ownership/permissions on files */
	SECURITY_ACL,		/* enable Posix ACLs (when compiled in) */
	SECURITY_ADDSECURIDS,	/* upgrade old security descriptors */
	SECURITY_STATICGRPS,	/* use static groups for access control */
	SECURITY_WANTED		/* a security related option was present */
} ;

/*
 *	Security context, needed by most security functions
 */

enum { MAPUSERS, MAPGROUPS, MAPCOUNT } ;

struct SECURITY_CONTEXT {
	ntfs_volume *vol;
	struct MAPPING *mapping[MAPCOUNT];
	struct PERMISSIONS_CACHE **pseccache;
	uid_t uid; /* uid of user requesting (not the mounter) */
	gid_t gid; /* gid of user requesting (not the mounter) */
	pid_t tid; /* thread id of thread requesting */
	mode_t umask; /* umask of requesting thread */
	} ;

#if POSIXACLS

/*
 *		       Posix ACL structures
 */
  
struct POSIX_ACE {
	u16 tag;
	u16 perms;
	s32 id;   
} __attribute__((__packed__));
        
struct POSIX_ACL {
	u8 version;
	u8 flags;
	u16 filler;
	struct POSIX_ACE ace[0];
} __attribute__((__packed__));

struct POSIX_SECURITY {
	mode_t mode;
	int acccnt;
	int defcnt;
	int firstdef;
	u16 tagsset;
	s32 alignment[0];
	struct POSIX_ACL acl;
} ;
        
/*
 *		Posix tags, cpu-endian 16 bits
 */
   
enum {  
	POSIX_ACL_USER_OBJ =	1,
	POSIX_ACL_USER =	2,
	POSIX_ACL_GROUP_OBJ =	4,
	POSIX_ACL_GROUP =	8,
	POSIX_ACL_MASK =	16,
	POSIX_ACL_OTHER =	32,
	POSIX_ACL_SPECIAL =	64  /* internal use only */
} ;

#define POSIX_ACL_EXTENSIONS (POSIX_ACL_USER | POSIX_ACL_GROUP | POSIX_ACL_MASK)
        
/*
 *		Posix permissions, cpu-endian 16 bits
 */
   
enum {  
	POSIX_PERM_X =		1,
	POSIX_PERM_W =		2,
	POSIX_PERM_R =		4,
	POSIX_PERM_DENIAL =	64 /* internal use only */
} ;

#define POSIX_VERSION 2

#endif

extern BOOL ntfs_guid_is_zero(const GUID *guid);
extern char *ntfs_guid_to_mbs(const GUID *guid, char *guid_str);

/**
 * ntfs_sid_is_valid - determine if a SID is valid
 * @sid:	SID for which to determine if it is valid
 *
 * Determine if the SID pointed to by @sid is valid.
 *
 * Return TRUE if it is valid and FALSE otherwise.
 */
static __inline__ BOOL ntfs_sid_is_valid(const SID *sid)
{
	if (!sid || sid->revision != SID_REVISION ||
			sid->sub_authority_count > SID_MAX_SUB_AUTHORITIES)
		return FALSE;
	return TRUE;
}

extern int ntfs_sid_to_mbs_size(const SID *sid);
extern char *ntfs_sid_to_mbs(const SID *sid, char *sid_str,
		size_t sid_str_size);
extern void ntfs_generate_guid(GUID *guid);
extern int ntfs_sd_add_everyone(ntfs_inode *ni);

extern le32 ntfs_security_hash(const SECURITY_DESCRIPTOR_RELATIVE *sd, 
			       const u32 len);

int ntfs_build_mapping(struct SECURITY_CONTEXT *scx, const char *usermap_path,
		BOOL allowdef);
int ntfs_get_owner_mode(struct SECURITY_CONTEXT *scx,
		ntfs_inode *ni, struct stat*);
int ntfs_set_mode(struct SECURITY_CONTEXT *scx, ntfs_inode *ni, mode_t mode);
BOOL ntfs_allowed_as_owner(struct SECURITY_CONTEXT *scx, ntfs_inode *ni);
int ntfs_allowed_access(struct SECURITY_CONTEXT *scx,
		ntfs_inode *ni, int accesstype);
BOOL old_ntfs_allowed_dir_access(struct SECURITY_CONTEXT *scx,
		const char *path, int accesstype);

#if POSIXACLS
le32 ntfs_alloc_securid(struct SECURITY_CONTEXT *scx,
		uid_t uid, gid_t gid, ntfs_inode *dir_ni,
		mode_t mode, BOOL isdir);
#else
le32 ntfs_alloc_securid(struct SECURITY_CONTEXT *scx,
		uid_t uid, gid_t gid, mode_t mode, BOOL isdir);
#endif
int ntfs_set_owner(struct SECURITY_CONTEXT *scx, ntfs_inode *ni,
		uid_t uid, gid_t gid);
int ntfs_set_ownmod(struct SECURITY_CONTEXT *scx,
		ntfs_inode *ni, uid_t uid, gid_t gid, mode_t mode);
#if POSIXACLS
int ntfs_set_owner_mode(struct SECURITY_CONTEXT *scx,
		ntfs_inode *ni, uid_t uid, gid_t gid,
		mode_t mode, struct POSIX_SECURITY *pxdesc);
#else
int ntfs_set_owner_mode(struct SECURITY_CONTEXT *scx,
		ntfs_inode *ni, uid_t uid, gid_t gid, mode_t mode);
#endif
le32 ntfs_inherited_id(struct SECURITY_CONTEXT *scx,
		ntfs_inode *dir_ni, BOOL fordir);
int ntfs_open_secure(ntfs_volume *vol);
void ntfs_close_secure(struct SECURITY_CONTEXT *scx);

#if POSIXACLS

int ntfs_set_inherited_posix(struct SECURITY_CONTEXT *scx,
		ntfs_inode *ni, uid_t uid, gid_t gid,
		ntfs_inode *dir_ni, mode_t mode);
int ntfs_get_posix_acl(struct SECURITY_CONTEXT *scx, ntfs_inode *ni,
			const char *name, char *value, size_t size);
int ntfs_set_posix_acl(struct SECURITY_CONTEXT *scx, ntfs_inode *ni,
			const char *name, const char *value, size_t size,
			int flags);
int ntfs_remove_posix_acl(struct SECURITY_CONTEXT *scx, ntfs_inode *ni,
			const char *name);
#endif

int ntfs_get_ntfs_acl(struct SECURITY_CONTEXT *scx, ntfs_inode *ni,
			char *value, size_t size);
int ntfs_set_ntfs_acl(struct SECURITY_CONTEXT *scx, ntfs_inode *ni,
			const char *value, size_t size, int flags); 

int ntfs_get_ntfs_attrib(ntfs_inode *ni, char *value, size_t size);
int ntfs_set_ntfs_attrib(ntfs_inode *ni,
			const char *value, size_t size,	int flags);
			

/*
 *		Security API for direct access to security descriptors
 *	based on Win32 API
 */

#define MAGIC_API 0x09042009

struct SECURITY_API {
	u32 magic;
	struct SECURITY_CONTEXT security;
	struct PERMISSIONS_CACHE *seccache;
} ;

/*
 *  The following constants are used in interfacing external programs.
 *  They are not to be stored on disk and must be defined in their
 *  native cpu representation.
 *  When disk representation (le) is needed, use SE_DACL_PRESENT, etc.
 */
enum {	OWNER_SECURITY_INFORMATION = 1,
	GROUP_SECURITY_INFORMATION = 2,
	DACL_SECURITY_INFORMATION = 4,
	SACL_SECURITY_INFORMATION = 8
} ;

int ntfs_get_file_security(struct SECURITY_API *scapi,
                const char *path, u32 selection,  
                char *buf, u32 buflen, u32 *psize);
int ntfs_set_file_security(struct SECURITY_API *scapi,
		const char *path, u32 selection, const char *attr);
int ntfs_get_file_attributes(struct SECURITY_API *scapi,
		const char *path);
BOOL ntfs_set_file_attributes(struct SECURITY_API *scapi,
		const char *path, s32 attrib);
BOOL ntfs_read_directory(struct SECURITY_API *scapi,
		const char *path, ntfs_filldir_t callback, void *context);
int ntfs_read_sds(struct SECURITY_API *scapi,
		char *buf, u32 size, u32 offset);
INDEX_ENTRY *ntfs_read_sii(struct SECURITY_API *scapi,
		INDEX_ENTRY *entry);
INDEX_ENTRY *ntfs_read_sdh(struct SECURITY_API *scapi,
		INDEX_ENTRY *entry);
struct SECURITY_API *ntfs_initialize_file_security(const char *device,
                                unsigned long flags);
BOOL ntfs_leave_file_security(struct SECURITY_API *scx);

int ntfs_get_usid(struct SECURITY_API *scapi, uid_t uid, char *buf);
int ntfs_get_gsid(struct SECURITY_API *scapi, gid_t gid, char *buf);
int ntfs_get_user(struct SECURITY_API *scapi, const SID *usid);
int ntfs_get_group(struct SECURITY_API *scapi, const SID *gsid);

#endif /* defined _NTFS_SECURITY_H */
