/**
 * Header file for eCryptfs userspace tools.
 * 
 * Copyright (C) 2004-2006 International Business Machines Corp.
 *   Author(s): Michael A. Halcrow <mahalcro@us.ibm.com>
 *
 * The structs here are shared between kernel and userspace, so if you
 * are running a 64-bit kernel, you need to compile your userspace
 * applications as 64-bit binaries.
 *
 * This program 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 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; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 * 02111-1307, USA.
 */

#ifndef ECRYTPFS_H
#define ECRYTPFS_H

#include <stdint.h>
#include <netdb.h>
#ifndef S_SPLINT_S
#include <stdio.h>
#include <syslog.h>
#endif
#include <pthread.h>
#include <unistd.h>
#ifndef S_SPLINT_S
#include <sys/types.h>
#include <linux/types.h>
#include <linux/netlink.h>
#endif
#include "decision_graph.h"

#ifndef NETLINK_ECRYPTFS
#warning NETLINK_ECRYPTFS not defined in netlink.h
#define NETLINK_ECRYPTFS 19
#endif

/* Version verification for shared data structures w/ userspace */
#ifndef ECRYPTFS_VERSION_MAJOR
#define ECRYPTFS_VERSION_MAJOR 0x00
#endif
#ifndef ECRYPTFS_VERSION_MINOR
#define ECRYPTFS_VERSION_MINOR 0x04
#endif

#ifndef ECRYPTFS_SUPPORTED_FILE_VERSION
#define ECRYPTFS_SUPPORTED_FILE_VERSION 0x02
#endif

/* These flags indicate which features are supported by the kernel
 * module; userspace tools such as the mount helper read from a sysfs
 * handle in order to determine how to behave. */
#define ECRYPTFS_VERSIONING_PASSPHRASE            0x00000001
#define ECRYPTFS_VERSIONING_PUBKEY                0x00000002
#define ECRYPTFS_VERSIONING_PLAINTEXT_PASSTHROUGH 0x00000004
#define ECRYPTFS_VERSIONING_POLICY                0x00000008
#define ECRYPTFS_VERSIONING_XATTR                 0x00000010

#define ECRYPTFS_MAX_PASSWORD_LENGTH 64
#define ECRYPTFS_MAX_PASSPHRASE_BYTES ECRYPTFS_MAX_PASSWORD_LENGTH
#define ECRYPTFS_SALT_SIZE 8
#define ECRYPTFS_SALT_SIZE_HEX (ECRYPTFS_SALT_SIZE*2)
#define ECRYPTFS_DEFAULT_SALT_HEX "0011223344556677"
/* The original signature size is only for what is stored on disk; all
 * in-memory representations are expanded hex, so it better adapted to
 * be passed around on the command line */
#define ECRYPTFS_SIG_SIZE 8
#define ECRYPTFS_SIG_SIZE_HEX (ECRYPTFS_SIG_SIZE*2)
#define ECRYPTFS_PASSWORD_SIG_SIZE ECRYPTFS_SIG_SIZE_HEX
#define ECRYPTFS_MAX_KEY_BYTES 64
#define ECRYPTFS_MAX_ENCRYPTED_KEY_BYTES 512
#define ECRYPTFS_DEFAULT_IV_BYTES 16
#define ECRYPTFS_FILE_VERSION 0x02
#define ECRYPTFS_DEFAULT_EXTENT_SIZE 4096
#define ECRPYTFS_STRING_LENGTH 128
#ifndef MAGIC_ECRYPTFS_MARKER_STR
#define MAGIC_ECRYPTFS_MARKER_STR "3c81b7f5"
#endif
#define MAX_PATH_SIZE 1024
#define MAX_NAME_SIZE 128
#define MAX_PKI_VALUE_SIZE 4096
#define ECRYPTFS_NLMSG_HELO 100
#define ECRYPTFS_NLMSG_QUIT 101
#define ECRYPTFS_NLMSG_REQUEST 102
#define ECRYPTFS_NLMSG_RESPONSE 103
#define ECRYPTFS_NETLINK_ERROR_COUNT_THRESHOLD 8
#define ECRYPTFS_MAX_PKI_NAME_BYTES 16

#ifndef SHA512_DIGEST_LENGTH
#define SHA512_DIGEST_LENGTH 64
#endif

#define PGP_DIGEST_ALGO_SHA512   10

/* TODO: Put this in configure.in, and make this ECRYPTFS_DEFAULT_PKI */
#define ECRYPTFS_PKI_OPENSSL "openssl"

#define ECRYPTFS_NOT_SALTLESS 0
#define ECRYPTFS_SALTLESS 1
#define ECRYPTFS_DEFAULT_NUM_HASH_ITERATIONS 65536

#define ECRYPTFS_TAG_64_PACKET 0x40
#define ECRYPTFS_TAG_65_PACKET 0x41
#define ECRYPTFS_TAG_66_PACKET 0x42
#define ECRYPTFS_TAG_67_PACKET 0x43

#define ecryptfs_syslog(type, fmt, arg...) \
	syslog(type, "%s: " fmt, __FUNCTION__, ## arg);

#define ECRYPTFS_MAX_NUM_CIPHERS 64
#define ECRYPTFS_ECHO_ON 1
#define ECRYPTFS_ECHO_OFF 0

/**
 * For convenience, we may need to pass around the encrypted session
 * key between kernel and userspace because the authentication token
 * may not be extractable.  For example, the TPM may not release the
 * private key, instead requiring the encrypted data and returning the
 * decrypted data.
 */
struct ecryptfs_session_key {
#define ECRYPTFS_USERSPACE_SHOULD_TRY_TO_DECRYPT 0x00000001
#define ECRYPTFS_USERSPACE_SHOULD_TRY_TO_ENCRYPT 0x00000002
#define ECRYPTFS_CONTAINS_DECRYPTED_KEY 0x00000004
#define ECRYPTFS_CONTAINS_ENCRYPTED_KEY 0x00000008
	int32_t flags;
	int32_t encrypted_key_size;
	int32_t decrypted_key_size;
	uint8_t encrypted_key[ECRYPTFS_MAX_ENCRYPTED_KEY_BYTES];
	uint8_t decrypted_key[ECRYPTFS_MAX_KEY_BYTES];
};

static const char common_salt[ECRYPTFS_SALT_SIZE] =
	{ (char)0x00, (char)0x11, (char)0x22, (char)0x33, (char)0x44,
	  (char)0x55, (char)0x66, (char)0x77 };

struct ecryptfs_password {
	int32_t password_bytes;
	int32_t hash_algo;
	int32_t hash_iterations;
	int32_t session_key_encryption_key_bytes;
#define ECRYPTFS_PERSISTENT_PASSWORD             0x01
#define ECRYPTFS_SESSION_KEY_ENCRYPTION_KEY_SET  0x02
	uint32_t flags;
	/* Iterated-hash concatenation of salt and passphrase */
	uint8_t session_key_encryption_key[ECRYPTFS_MAX_KEY_BYTES];
	uint8_t signature[ECRYPTFS_PASSWORD_SIG_SIZE + 1];
	/* Always in expanded hex */
	uint8_t salt[ECRYPTFS_SALT_SIZE];
};

struct ecryptfs_private_key {
	uint32_t key_size;
	uint32_t data_len;
	uint8_t signature[ECRYPTFS_PASSWORD_SIG_SIZE + 1];
	char pki_type[ECRYPTFS_MAX_PKI_NAME_BYTES + 1];
	uint8_t data[];
};

enum ecryptfs_token_types {ECRYPTFS_PASSWORD, ECRYPTFS_PRIVATE_KEY};

/* May be a password or a private key */
struct ecryptfs_auth_tok {
	uint16_t version; /* 8-bit major and 8-bit minor */
	uint16_t token_type;
	uint32_t flags;
	struct ecryptfs_session_key session_key;
	uint8_t reserved[32];
	union {
		struct ecryptfs_password password;
		struct ecryptfs_private_key private_key;
	} token;
}  __attribute__ ((packed));

struct ecryptfs_name_val_pair {
#define ECRYPTFS_ECHO			0x00000001
#define ECRYPTFS_MLOCK			0x00000002
#define ECRYPTFS_DEFAULT_VALUE_SET	0x00000004
	uint32_t flags;
	char *name;
	char *value;
	struct ecryptfs_name_val_pair *next;
};

void dump_auth_tok( struct ecryptfs_auth_tok *auth_tok );
extern void to_hex( char *dst, char *src, int src_size );
extern void from_hex( char *dst, char *src, int dst_size );
extern int generate_version_from_string(unsigned char *major,
					unsigned char *minor,
					char *version);

struct ecryptfs_daemon_info {
	char socket_file_full_path[MAX_PATH_SIZE];
};

struct ecryptfs_cipher_elem {
	uint8_t loaded_cipher;
	char *kernel_name;
	char *user_name;
	uint32_t bytes;
	struct ecryptfs_cipher_elem *next;
};

struct ecryptfs_netlink_message {
	uint32_t index;
	uint32_t data_len;
	uint8_t data[];
};

struct ecryptfs_pki_ops {
	int (*set_key_data)(unsigned char *private_key_data, char *sig,
			    int *length);
	int (*generate_key)(char *filename);
	int (*encrypt)(int size, char *from, char *to,
	               unsigned char *private_key_data);
	int (*decrypt)(char *from, char *to, size_t *decrypted_key_size,
		       unsigned char *private_key_data);
	int (*get_pki_data_length)(struct ecryptfs_name_val_pair *pair);
	int (*set_pki_data)(struct ecryptfs_name_val_pair *pair,
			    unsigned char *data);
	int (*get_param_subgraph_trans_node)(struct transition_node **trans,
					     uint32_t version);
};

struct ecryptfs_pki_elem {
	void *lib_handle;
	struct ecryptfs_pki_elem *next;
	char *pki_name;
	char *libname;
	struct ecryptfs_name_val_pair nvp_head;
	struct ecryptfs_pki_ops ops;
};

struct ecryptfs_ctx {
	void *ctx_mutex;
	struct ecryptfs_pki_elem pki_list_head;
	int verbosity;
	int (*get_string)(char **val, char *prompt, int echo);
	FILE *file_in;
	FILE *file_out;
};

struct cipher_str_name_map_elem {
	char *kernel_name;
	char *user_name;
	int keysize_bytes;
};

enum main_menu_enum {
	MME_NULL,
	MME_MOUNT_PASSPHRASE,
	MME_MOUNT_PUBKEY,
	MME_GEN_PUBKEY,
	MME_ABORT
};

int ecryptfs_get_version(uint32_t *version);
int ecryptfs_supports_passphrase(uint32_t version);
int ecryptfs_supports_pubkey(uint32_t version);
int ecryptfs_supports_plaintext_passthrough(uint32_t version);
int ecryptfs_supports_policy(uint32_t version);
int ecryptfs_process_decision_graph(struct ecryptfs_ctx *ctx,
                                    struct val_node **head, uint32_t version,
                                    char *opts_str);
int get_string(char *val, int len, int echo);
int get_string_stdin(char **val, char *prompt, int echo);
int stack_pop_val(struct val_node **head, void **val);
int ecryptfs_mount(char *source, char *target, unsigned long flags, char *opts);
int ecryptfs_get_current_kernel_ciphers(
	struct ecryptfs_cipher_elem *cipher_list_head);
int ecryptfs_default_cipher(struct ecryptfs_cipher_elem **default_cipher,
		 	    struct ecryptfs_cipher_elem *cipher_list_head);
int stack_push(struct val_node **head, void *val);
int ecryptfs_free_cipher_list(struct ecryptfs_cipher_elem cipher_list_head);
int ecryptfs_get_pki_list(struct ecryptfs_ctx* ctx);
int ecryptfs_parse_options(char *opts, struct ecryptfs_name_val_pair *head);
int decision_graph_mount(struct ecryptfs_ctx *ctx, struct val_node **head,
			 struct param_node *root_node,
			 struct ecryptfs_name_val_pair *nvp_head);
int add_passphrase_key_to_keyring(char *auth_tok_sig, char *passphrase,
				  char *salt);
int add_public_key_key_to_keyring(char *auth_tok_sig,
				  struct ecryptfs_pki_elem *selected_pki);
int generate_key(void);
int ecryptfs_free_pki_list(struct ecryptfs_ctx *ctx);
int create_default_dir(char *home, struct ecryptfs_pki_elem *pki);
int create_subdirectory(char *file, char *home, struct ecryptfs_pki_elem *pki);
int ecryptfs_get_loaded_ciphers(struct ecryptfs_cipher_elem *cipher_list_head);
int ecryptfs_add_crypto_modules(struct ecryptfs_cipher_elem *cipher_list_head);
int parse_packet(struct ecryptfs_ctx *ctx,
		 struct ecryptfs_netlink_message *emsg,
		 struct ecryptfs_netlink_message **reply);
int ecryptfs_find_pki(struct ecryptfs_ctx *ctx, char *pki_name,
		      struct ecryptfs_pki_elem **desired_pki);
int
generate_passphrase_sig(char *passphrase_sig, char *passphrase, char *salt,
			char *session_key_encryption_key);
int
generate_payload(struct ecryptfs_auth_tok *auth_tok, char *passphrase_sig,
		 char *salt, char *session_key_encryption_key);
int
generate_private_payload(struct ecryptfs_auth_tok *auth_tok,
			 struct ecryptfs_pki_elem *selected_pki,
			 char *passphrase_sig, int pki_data_len);
int parse_options_file(int fd, struct ecryptfs_name_val_pair *head);
int free_name_val_pairs(struct ecryptfs_name_val_pair *pair);
int ecryptfs_send_netlink(int sk_fd, struct ecryptfs_netlink_message *emsg,
			  uint16_t msg_type, uint16_t msg_flags,
			  uint32_t msg_seq);
void ecryptfs_release_netlink(int sk_fd);
int init_netlink_daemon(void);
int ecryptfs_run_netlink_daemon(int sk_fd);
int ecryptfs_init_netlink(int *sk_fd);
int ecryptfs_nvp_list_union(struct ecryptfs_name_val_pair *dst,
			    struct ecryptfs_name_val_pair *src);

#endif
