/*
 * nasd_security_dr.h
 *
 * Put the Security in NASD drive
 */
/*
 * Copyright (c) of Carnegie Mellon University, 1997,1998,1999.
 *
 * Permission to reproduce, use, and prepare derivative works of
 * this software for internal use is granted provided the copyright
 * and "No Warranty" statements are included with all reproductions
 * and derivative works. This software may also be redistributed
 * without charge provided that the copyright and "No Warranty"
 * statements are included in all redistributions.
 *
 * NO WARRANTY. THIS SOFTWARE IS FURNISHED ON AN "AS IS" BASIS.
 * CARNEGIE MELLON UNIVERSITY MAKES NO WARRANTIES OF ANY KIND, EITHER
 * EXPRESSED OR IMPLIED AS TO THE MATTER INCLUDING, BUT NOT LIMITED
 * TO: WARRANTY OF FITNESS FOR PURPOSE OR MERCHANTABILITY, EXCLUSIVITY
 * OF RESULTS OR RESULTS OBTAINED FROM USE OF THIS SOFTWARE. CARNEGIE
 * MELLON UNIVERSITY DOES NOT MAKE ANY WARRANTY OF ANY KIND WITH RESPECT
 * TO FREEDOM FROM PATENT, TRADEMARK, OR COPYRIGHT INFRINGEMENT.
 */


#ifndef _NASD_SECURITY_DR_H_
#define _NASD_SECURITY_DR_H_ 

#include <nasd/nasd_options.h>
#include <nasd/nasd_drive_options.h>
#include <nasd/nasd_types.h>
#include <nasd/nasd_security.h>
#include <nasd/nasd_itypes.h>
#include <nasd/nasd_cache.h>

typedef struct nasd_sec_kc_q_s		nasd_sec_kc_q_t;
typedef struct nasd_sec_kc_ent_s	nasd_sec_kc_ent_t;

struct nasd_sec_kc_ent_s {
  nasd_capability_t capability;
  nasd_key_t op_key;
  nasd_key_t integrity_key;
  nasd_key_t privacy_key;
  nasd_sec_kc_ent_t *cnext;
  nasd_sec_kc_ent_t *cprev;
  nasd_sec_kc_ent_t *lnext;
  nasd_sec_kc_ent_t *lprev;
  nasd_sec_kc_ent_t *fnext;
  nasd_sec_kc_ent_t *fprev;
};

struct nasd_sec_kc_q_s {
  nasd_sec_kc_ent_t head;
  int size;
};

extern nasd_sec_kc_q_t nasd_sec_kc_lru;
extern nasd_sec_kc_q_t nasd_sec_kc_free;
extern nasd_sec_kc_q_t *nasd_sec_kc_bucket_ents;
extern int nasd_sec_kc_buckets;
extern int nasd_sec_kc_size;
NASD_DECLARE_EXTERN_MUTEX(nasd_sec_kc_lock)

#define NASD_KC_CACHESIZE_DEFAULT	1024
#define NASD_KC_BUCKETS_DEFAULT		127
#define NASD_KC_BUCKET(_nid_)		NASD_ABS((int)((_nid_)%nasd_sec_kc_buckets))

/* here we shamelessly steal the queue-manipulation macros from the ODC. */
#define NASD_KCQ_INS(_q_,_ent_,_nxt_,_prv_)	NASD_ODC_Q_INS_NOLOCK(_q_,_ent_,_nxt_,_prv_)
#define NASD_KCQ_DEQ(_ent_,_nxt_,_prv_)	NASD_ODC_Q_DEQ_NOLOCK(_ent_,_nxt_,_prv_)
#define NASD_KCQ_DEQ_TAIL(_q_,_ent_,_nxt_,_prv_)	NASD_ODC_Q_DEQ_TAIL_NOLOCK(_q_,_ent_,_nxt_,_prv_)
#define NASD_KCQ_SIZE(_q_)		((_q_)->size)

#define NASD_KC_LOCK()			NASD_LOCK_MUTEX(nasd_sec_kc_lock)
#define NASD_KC_UNLOCK()		NASD_UNLOCK_MUTEX(nasd_sec_kc_lock)

nasd_status_t nasd_unpack_args(nasd_security_param_otw_t sec_param_otw,
			       nasd_capability_otw_t capability_otw,
			       nasd_digest_nonce_otw_t digest_otw,
			       void *args_otw,
			       int args_otw_len,
			       nasd_security_param_t *sec_param,
			       nasd_capability_t *capability,
			       void *args,
			       void (*unmarshall_fn)(),
			       nasd_iv_t icv,
			       nasd_key_t op_key,
			       nasd_key_t integrity_key,
			       nasd_key_t privacy_key,
			       nasd_security_context_t *context);
nasd_status_t nasd_sec_get_capability_keys(nasd_security_param_t *sec_param,
					   nasd_capability_t *capability,
					   nasd_capability_otw_t capability_otw,
					   nasd_byte_t *op_key,
					   nasd_byte_t *integrity_key,
					   nasd_byte_t *privacy_key);
nasd_status_t nasd_sec_verify_args(nasd_security_param_t *sec_param,
				   nasd_capability_t *capability,
				   nasd_digest_nonce_otw_t digest_otw,
				   nasd_digest_nonce_t *digest,
				   void *args_otw,
				   int args_otw_len,
				   nasd_key_t op_key,
				   nasd_key_t integrity_key,
				   nasd_security_context_t *context);
void nasd_pack_res(nasd_security_param_t *sec_param,
		   void *res,
		   void *res_otw,
		   int res_otw_len,
		   nasd_digest_nonce_otw_t digest_otw,
		   void (*marshall_fn)(),
		   nasd_iv_t icv,
		   nasd_key_t op_key,
		   nasd_key_t integrity_key,
		   nasd_key_t privacy_key,
		   nasd_security_context_t *context);

nasd_status_t nasd_sec_init(void);
nasd_status_t nasd_sec_kc_lookup(nasd_capability_t *capability,
				 nasd_sec_kc_ent_t *ke);
nasd_status_t nasd_sec_kc_insert(nasd_capability_t *capability,
				 nasd_byte_t *op_key,
				 nasd_byte_t *integrity_key,
				 nasd_byte_t *privacy_key);
void nasd_sec_kc_invalidate(nasd_identifier_t identifier);
nasd_status_t nasd_sec_kc_init(nasd_shutdown_list_t *sl);
void nasd_sec_kc_q_init(nasd_sec_kc_q_t *kq);

#if NASD_SECURE_RPCS_ENABLE > 0
/* Generic security-check macros. */
#define NASD_SEC_INVALID_PART(_sec_param_) \
	(NASD_OD_INVALID_PART(&PART((_sec_param_).partnum)))

#define NASD_SEC_CAP_INCORRECT_PART(_cap_, _pn_) \
	((_cap_).partnum != (_pn_))

#define NASD_SEC_CAP_INCORRECT_NI(_cap_, _ni_) \
	((_cap_).ni != (_ni_))

#define NASD_SEC_PART_PROTECTION(_sec_param_, _pn_) \
	(((_sec_param_).actual_protection & PART(_pn_).min_protection) != PART(_pn_).min_protection)

/* We only check the capability if NASD_INTEGRITY_ARGS is set.
   Otherwise there is no point since we have no guarantee that the
   capability is authentic. */
#define NASD_SEC_GENERIC_OBJECT_OP(_sec_param_, _cap_, _args_, _rc_, _rights_) { \
	if(NASD_SEC_INVALID_PART(_sec_param_)) _rc_ = NASD_BAD_PARTITION; \
	else if(NASD_SEC_PART_PROTECTION(_sec_param_, (_args_).in_partnum)) _rc_ = NASD_PART_PROTECTION; \
	else if(NASD_SEC_IS_CAPABILITY((_sec_param_).type) && ((_sec_param_).actual_protection & NASD_INTEGRITY_ARGS)) { \
		if(!((_cap_).rights & _rights_)) _rc_ = NASD_INSUFFICIENT_PERM; \
		else if(NASD_SEC_CAP_INCORRECT_PART(_cap_, (_args_).in_partnum)) _rc_ = NASD_WRONG_PARTITION; \
		else if(NASD_SEC_CAP_INCORRECT_NI(_cap_, (_args_).in_identifier)) _rc_ = NASD_WRONG_NI; \
	} \
	}

#define NASD_SEC_GENERIC_SMPL_OP(_sec_param_, _cap_, _args_, _rc_, _rights_) { \
	nasd_nodenum_t _n; \
	int _is_control = 0; \
	if(nasd_od_decompose_control((_args_).in_identifier, &_n) == NASD_SUCCESS) \
		_is_control = 1; \
	if(_is_control && (_n == NASD_CTRL_TRACE_INFO || _n == NASD_CTRL_TRACE_DATA)) { \
		if((_sec_param_).type < NASD_DRIVE_KEY) _rc_ = NASD_INSUFFICIENT_PERM; \
	} else if(NASD_SEC_INVALID_PART(_sec_param_) && !(_is_control && _n == NASD_CTRL_DRIVE_INFO)) _rc_ = NASD_BAD_PARTITION; \
	else if(NASD_SEC_PART_PROTECTION(_sec_param_, (_args_).in_partnum)) _rc_ = NASD_PART_PROTECTION; \
	else if(NASD_SEC_IS_CAPABILITY((_sec_param_).type) && ((_sec_param_).actual_protection & NASD_INTEGRITY_ARGS)) { \
		if(!((_cap_).rights & _rights_)) _rc_ = NASD_INSUFFICIENT_PERM; \
		else if(NASD_SEC_CAP_INCORRECT_PART(_cap_, (_args_).in_partnum)) _rc_ = NASD_WRONG_PARTITION; \
		else if(NASD_SEC_CAP_INCORRECT_NI(_cap_, (_args_).in_identifier)) _rc_ = NASD_WRONG_NI; \
		else if((_cap_).region_start != 0 || (_cap_).region_end != 0) { \
			if((_cap_).region_start > (_args_).in_offset) _rc_ = NASD_REQUEST_OUTSIDE_RANGE; \
			else if((_cap_).region_end < (_args_).in_offset + (_args_).in_len) _rc_ = NASD_REQUEST_OUTSIDE_RANGE; \
		} \
	} \
	}

/* Per-RPC security policy macros.  The idea is that the RPC-specific server
   stub can call the appropriate macro once it has the security parameter,
   capability, and arguments unpacked.  The macro places its result
   in _rc_ if a security violation is detected, otherwise _rc_ is left
   untouched. */
#define NASD_SEC_POLICY_PART_CREAT(_sec_param_, _cap_, _args_, _rc_) { \
	if((_sec_param_).type != NASD_DRIVE_KEY) _rc_ = NASD_BAD_KEYTYPE; \
	}

#define NASD_SEC_POLICY_CREATE(_sec_param_, _cap_, _args_, _rc_) { \
	if(NASD_SEC_INVALID_PART(_sec_param_)) _rc_ = NASD_BAD_PARTITION; \
	else if(NASD_SEC_IS_CAPABILITY((_sec_param_).type)) _rc_ = NASD_BAD_KEYTYPE; \
	else if((_sec_param_).partnum != (_args_).in_partnum) _rc_ = NASD_WRONG_PARTITION; \
	else if(NASD_SEC_PART_PROTECTION(_sec_param_, (_args_).in_partnum)) _rc_ = NASD_PART_PROTECTION; \
	}

#define NASD_SEC_POLICY_GETATTR(_sec_param_, _cap_, _args_, _rc_) \
	NASD_SEC_GENERIC_OBJECT_OP(_sec_param_, _cap_, _args_, _rc_, NASD_ACCESS_RIGHTS_GETATTR)

#define NASD_SEC_POLICY_SETATTR(_sec_param_, _cap_, _args_, _rc_) \
	NASD_SEC_GENERIC_OBJECT_OP(_sec_param_, _cap_, _args_, _rc_, NASD_ACCESS_RIGHTS_SETATTR)

#define NASD_SEC_POLICY_FLUSH_OBJ(_sec_param_, _cap_, _args_, _rc_) \
	NASD_SEC_GENERIC_OBJECT_OP(_sec_param_, _cap_, _args_, _rc_, NASD_ACCESS_RIGHTS_FLUSH)

#define NASD_SEC_POLICY_REMOVE(_sec_param_, _cap_, _args_, _rc_) \
	NASD_SEC_GENERIC_OBJECT_OP(_sec_param_, _cap_, _args_, _rc_, NASD_ACCESS_RIGHTS_REMOVE)

#define NASD_SEC_POLICY_EJECT_OBJ(_sec_param_, _cap_, _args_, _rc_) \
	NASD_SEC_GENERIC_OBJECT_OP(_sec_param_, _cap_, _args_, _rc_, NASD_ACCESS_RIGHTS_EJECT)

#define NASD_SEC_POLICY_READ_SIMPLE(_sec_param_, _cap_, _args_, _rc_) \
	NASD_SEC_GENERIC_SMPL_OP(_sec_param_, _cap_, _args_, _rc_, NASD_ACCESS_RIGHTS_READ)

#define NASD_SEC_POLICY_TREAD_SIMPLE(_sec_param_, _cap_, _args_, _rc_) \
	NASD_SEC_GENERIC_SMPL_OP(_sec_param_, _cap_, _args_, _rc_, NASD_ACCESS_RIGHTS_READ)

#define NASD_SEC_POLICY_WRITE_SIMPLE(_sec_param_, _cap_, _args_, _rc_) \
	NASD_SEC_GENERIC_SMPL_OP(_sec_param_, _cap_, _args_, _rc_, NASD_ACCESS_RIGHTS_WRITE)

/* CHANGE_KEY security policy: remove NASD_PRIVACY_ARGS from the following line
   if you don't care about a client changing a key without encrypting it. */
#define NASD_SEC_POLICY_CHANGE_KEY(_sec_param_, _cap_, _args_, _rc_) { \
	if(((_sec_param_).actual_protection & (NASD_INTEGRITY_ARGS | NASD_PRIVACY_ARGS)) != \
	   (NASD_INTEGRITY_ARGS | NASD_PRIVACY_ARGS)) _rc_ = NASD_WEAK_COOKIE; \
	else if(NASD_SEC_IS_CAPABILITY((_sec_param_).type)) _rc_ = NASD_BAD_KEYTYPE; \
	else if((_args_).in_type == NASD_MASTER_KEY) _rc_ = NASD_IMMUTABLE_KEY; \
	else if(((_args_).in_type == NASD_DRIVE_KEY || (_args_).in_type == NASD_PARTITION_KEY) && \
		((_sec_param_).type <= (_args_).in_type)) _rc_ = NASD_INSUFFICIENT_PERM; \
	else if(((_args_).in_type == NASD_RED_KEY || (_args_).in_type == NASD_BLACK_KEY) && \
		((_sec_param_).type <= NASD_RED_KEY)) _rc_ = NASD_INSUFFICIENT_PERM; \
	}

/* Not sure how these should fit into the NASD security model, so no
   security policies for them. */
#define NASD_SEC_POLICY_STRT_IREAD(_sec_param_, _cap_, _args_, _rc_)
#define NASD_SEC_POLICY_STOP_IREAD(_sec_param_, _cap_, _args_, _rc_)

#define NASD_SEC_POLICY_RSHUTDOWN(_sec_param_, _cap_, _args_, _rc_) { \
	if((_sec_param_).type != NASD_DRIVE_KEY) _rc_ = NASD_BAD_KEYTYPE; \
	}
#else /* NASD_SECURE_RPCS_ENABLE > 0 */
#define NASD_SEC_POLICY_PART_CREAT(_sec_param_, _cap_, _args_, _rc_)
#define NASD_SEC_POLICY_CREATE(_sec_param_, _cap_, _args_, _rc_)
#define NASD_SEC_POLICY_GETATTR(_sec_param_, _cap_, _args_, _rc_) 
#define NASD_SEC_POLICY_SETATTR(_sec_param_, _cap_, _args_, _rc_)
#define NASD_SEC_POLICY_FLUSH_OBJ(_sec_param_, _cap_, _args_, _rc_)
#define NASD_SEC_POLICY_REMOVE(_sec_param_, _cap_, _args_, _rc_)
#define NASD_SEC_POLICY_EJECT_OBJ(_sec_param_, _cap_, _args_, _rc_)
#define NASD_SEC_POLICY_READ_SIMPLE(_sec_param_, _cap_, _args_, _rc_)
#define NASD_SEC_POLICY_TREAD_SIMPLE(_sec_param_, _cap_, _args_, _rc_)
#define NASD_SEC_POLICY_WRITE_SIMPLE(_sec_param_, _cap_, _args_, _rc_)
#define NASD_SEC_POLICY_CHANGE_KEY(_sec_param_, _cap_, _args_, _rc_)
#define NASD_SEC_POLICY_STRT_IREAD(_sec_param_, _cap_, _args_, _rc_)
#define NASD_SEC_POLICY_STOP_IREAD(_sec_param_, _cap_, _args_, _rc_)
#define NASD_SEC_POLICY_RSHUTDOWN(_sec_param_, _cap_, _args_, _rc_)
#endif /* NASD_SECURE_RPCS_ENABLE > 0 */

#endif /* !_NASD_SECURITY_DR_H_ */
