/*
 * CDE - Common Desktop Environment
 *
 * Copyright (c) 1993-2012, The Open Group. All rights reserved.
 *
 * These libraries and programs are free software; you can
 * redistribute them and/or modify them under the terms of the GNU
 * Lesser General Public License as published by the Free Software
 * Foundation; either version 2 of the License, or (at your option)
 * any later version.
 *
 * These libraries and programs are distributed in the hope that
 * they will be useful, but WITHOUT ANY WARRANTY; without even the
 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
 * PURPOSE. See the GNU Lesser General Public License for more
 * details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with these libraries and programs; if not, write
 * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
 * Floor, Boston, MA 02110-1301 USA
 */
//%%  (c) Copyright 1993, 1994 Hewlett-Packard Company			
//%%  (c) Copyright 1993, 1994 International Business Machines Corp.	
//%%  (c) Copyright 1993, 1994 Sun Microsystems, Inc.			
//%%  (c) Copyright 1993, 1994 Novell, Inc. 				
//%%  $XConsortium: tt_audit.C /main/13 1996/11/20 11:07:12 drk $ 			 				
/* %W 93/08/15
 *
 * tt_audit.cc
 *
 * Copyright (c) 1990 by Sun Microsystems, Inc.
 */
#include <unistd.h>
#include <fcntl.h>
#include "Tt/tt_c.h"
#include "util/tt_trace.h"
#include "util/tt_global_env.h"
#include "util/tt_audit.h"
#include "util/tt_port.h"
#include "util/tt_enumname.h"
#include "api/c/api_handle.h"
#include "mp/mp_c_mp.h"
#include "mp/mp_c_message.h"
#include "mp/mp_pattern.h"

extern _Tt_c_mp		*_tt_c_mp;

extern Tt_status	_tt_pointer_error(void *);

void	*_tt_error_pointer(Tt_status s);

// max length of a propename
#define TT_SPEC_PROPNAME_MAX_LEN         64

// This func does cascaded error checking, checking for some NULL
// pointers, and starts tracing. See _Tt_trace for parsing of argskey.
//
// Note carefully: in the loop which parses the args for error
// checking, the code relys on previous iterations having set
// certain variables, for example, the context slotname checking
// code relies on the msg variable having been set by a previous
// loop iteration.  All this in the name of coding efficiency.
//
Tt_status _Tt_audit::
entry(const char *argskey, _Tt_entry_pt func, ...)
{
	va_list			ap;
	char			c, *cp;
    const char *preview;
	int			num_args = strlen(argskey);
	Tt_message 		m;
	_Tt_c_message_ptr       msg;
	Tt_pattern		p;
        _Tt_pattern_ptr		pat;
#ifdef OPT_XTHREADS
	static xmutex_rec	mutex = XMUTEX_INITIALIZER;
#endif

	va_start(ap, func);
	_Tt_trace::entry(argskey, func, ap);

	// Increment the number of API calls made in this process.
#ifdef OPT_XTHREADS
	// Serialize the check for _tt_global
	xmutex_lock(&mutex);
#endif
	if (! _tt_global) {
		_tt_global = new _Tt_global();
	}
#ifdef OPT_XTHREADS
	xmutex_unlock(&mutex);
#endif

	_tt_global->grab_mutex();
	_tt_global->event_counter++;

	// init checking (formerly INITCHECK, PTR_INITCHECK, etc.
	switch (func) {
		case TT_DEFAULT_PTYPE:
		case TT_DEFAULT_PTYPE_SET:
		case TT_DEFAULT_FILE:
		case TT_DEFAULT_FILE_SET:
		case TT_DEFAULT_SESSION:
		case TT_DEFAULT_PROCID:
		case TT_DEFAULT_PROCID_SET:
		case TT_FILE_JOIN:
		case TT_FILE_QUIT:
		case TT_FILE_DESTROY:
		case TT_FILE_MOVE:
		case TT_FILE_COPY:
		case TT_FILE_OBJECTS_QUERY:
		case TT_MESSAGE_PRINT:
		case TT_MESSAGE_CREATE:
		case TT_MESSAGE_CREATE_SUPER:
		case TT_MESSAGE_DESTROY:
		case TT_MESSAGE_SEND:
		case TT_MESSAGE_SEND_ON_EXIT:
		case TT_MESSAGE_RECEIVE:
		case TT_MESSAGE_CALLBACK_ADD:
		case TT_MESSAGE_REJECT:
		case TT_MESSAGE_REPLY:
		case TT_MESSAGE_FAIL:
		case TT_MESSAGE_ACCEPT:
		case TT_MESSAGE_PATTERN:
		case TT_MESSAGE_USER:
		case TT_MESSAGE_USER_SET:
		case TT_MESSAGE_ARG_ADD:
		case TT_MESSAGE_BARG_ADD:
		case TT_MESSAGE_ARG_BVAL:
		case TT_MESSAGE_ARG_BVAL_SET:
		case TT_MESSAGE_ARG_IVAL:
		case TT_MESSAGE_ARG_IVAL_SET:
		case TT_MESSAGE_ARG_MODE:
		case TT_MESSAGE_ARG_TYPE:
		case TT_MESSAGE_ARG_VAL:
		case TT_MESSAGE_ARG_VAL_SET:
		case TT_MESSAGE_ARGS_COUNT:
		case TT_MESSAGE_XARG_ADD:
		case TT_MESSAGE_ARG_XVAL:
		case TT_MESSAGE_ARG_XVAL_SET:
		case TT_MESSAGE_CONTEXT_XVAL:
		case TT_MESSAGE_XCONTEXT_SET:
		case TT_MESSAGE_CONTEXT_VAL:
		case TT_MESSAGE_CONTEXT_IVAL:
		case TT_MESSAGE_CONTEXT_BVAL:
		case TT_MESSAGE_CONTEXT_SET:
		case TT_MESSAGE_ICONTEXT_SET:
		case TT_MESSAGE_BCONTEXT_SET:
		case TT_MESSAGE_CONTEXTS_COUNT:
		case TT_MESSAGE_CONTEXT_SLOTNAME:
		case TT_MESSAGE_CLASS_SET:
		case TT_MESSAGE_FILE:
		case TT_MESSAGE_FILE_SET:
		case TT_MESSAGE_OBJECT:
		case TT_MESSAGE_OBJECT_SET:
		case TT_MESSAGE_ID:
		case TT_MESSAGE_OP:
		case TT_MESSAGE_OP_SET:
		case TT_MESSAGE_OPNUM:
		case TT_MESSAGE_OTYPE:
		case TT_MESSAGE_OTYPE_SET:
		case TT_MESSAGE_ADDRESS:
		case TT_MESSAGE_ADDRESS_SET:
		case TT_MESSAGE_HANDLER:
		case TT_MESSAGE_HANDLER_SET:
		case TT_MESSAGE_HANDLER_PTYPE:
		case TT_MESSAGE_HANDLER_PTYPE_SET:
		case TT_MESSAGE_DISPOSITION:
		case TT_MESSAGE_DISPOSITION_SET:
		case TT_MESSAGE_SCOPE:
		case TT_MESSAGE_SCOPE_SET:
		case TT_MESSAGE_SENDER:
		case TT_MESSAGE_SENDER_PTYPE:
		case TT_MESSAGE_SENDER_PTYPE_SET:
		case TT_MESSAGE_SESSION:
		case TT_MESSAGE_SESSION_SET:
		case TT_MESSAGE_STATE:
		case TT_MESSAGE_STATUS_STRING:
		case TT_MESSAGE_STATUS_STRING_SET:
		case TT_MESSAGE_STATUS:
		case TT_MESSAGE_STATUS_SET:
		case TT_CLOSE:
		case TT_SESSION_JOIN:
		case TT_SESSION_QUIT:
		case TT_FD:
		case TT_PNOTICE_CREATE:
		case TT_PREQUEST_CREATE:
		case TT_ONOTICE_CREATE:
		case TT_OREQUEST_CREATE:
		case TT_PTYPE_OPNUM_CALLBACK_ADD:
		case TT_OTYPE_OPNUM_CALLBACK_ADD:
		case TT_SESSION_PROP_COUNT:
		case TT_SESSION_PROP:
		case TT_SESSION_PROP_ADD:
		case TT_SESSION_PROP_SET:
		case TT_SESSION_BPROP:
		case TT_SESSION_BPROP_ADD:
		case TT_SESSION_BPROP_SET:
		case TT_SESSION_PROPNAME:
		case TT_SESSION_PROPNAMES_COUNT:
		case TT_SPEC_BPROP:
		case TT_SPEC_BPROP_ADD:
		case TT_SPEC_BPROP_SET:
		case TT_SPEC_CREATE:
		case TT_SPEC_DESTROY:
		case TT_SPEC_FILE:
		case TT_SPEC_MOVE:
		case TT_SPEC_TYPE_SET:
		case TT_SPEC_PROP:
		case TT_SPEC_TYPE:
		case TT_SPEC_PROP_ADD:
		case TT_SPEC_PROP_COUNT:
		case TT_SPEC_PROP_SET:
		case TT_SPEC_PROPNAME:
		case TT_SPEC_PROPNAMES_COUNT:
		case TT_SPEC_WRITE:
		case TT_OBJID_EQUAL:
		case TT_OBJID_OBJKEY:
		case TT_PATTERN_PRINT:
		case TT_PATTERN_CREATE:
		case TT_PATTERN_DESTROY:
		case TT_PATTERN_REGISTER:
		case TT_PATTERN_UNREGISTER:
		case TT_PATTERN_CONTEXT_ADD:
		case TT_PATTERN_ICONTEXT_ADD:
		case TT_PATTERN_XCONTEXT_ADD:
		case TT_PATTERN_BCONTEXT_ADD:
		case TT_PTYPE_DECLARE:
		case TT_PTYPE_UNDECLARE:
		case TT_PTYPE_EXISTS:
		case TT_SESSION_TYPES_LOAD:
		case TT_CONTEXT_JOIN:
		case TT_ICONTEXT_JOIN:
		case TT_BCONTEXT_JOIN:
		case TT_CONTEXT_QUIT:
		case TT_ICONTEXT_QUIT:
		case TT_BCONTEXT_QUIT:
		case TT_XCONTEXT_JOIN:
		case TT_XCONTEXT_QUIT:
		case TT_OTYPE_DERIVEDS_COUNT:
		case TT_OTYPE_BASE:
		case TT_OTYPE_DERIVED:
		case TT_OTYPE_IS_DERIVED:
		case TT_OTYPE_OSIG_COUNT:
		case TT_OTYPE_HSIG_COUNT:
		case TT_OTYPE_OSIG_OP:
		case TT_OTYPE_HSIG_OP:
		case TT_OTYPE_OSIG_ARGS_COUNT:
		case TT_OTYPE_HSIG_ARGS_COUNT:
		case TT_OTYPE_OSIG_ARG_MODE:
		case TT_OTYPE_HSIG_ARG_MODE:
		case TT_OTYPE_OSIG_ARG_TYPE:
		case TT_OTYPE_HSIG_ARG_TYPE:
			if (!_tt_mp || !_tt_c_mp) {
				va_end(ap);
				return TT_ERR_NOMP;
			}
			if (_tt_c_mp && !_tt_c_mp->default_c_procid().c_pointer()) {
				va_end(ap);
				return TT_ERR_PROCID;
			}
		break;

		case TT_INITIAL_SESSION:
		case TT_PATTERN_CALLBACK_ADD:
		case TT_PATTERN_USER:
		case TT_PATTERN_USER_SET:
		case TT_PATTERN_CATEGORY:
		case TT_PATTERN_CATEGORY_SET:
		case TT_PATTERN_ARG_ADD:
		case TT_PATTERN_BARG_ADD:
		case TT_PATTERN_IARG_ADD:
		case TT_PATTERN_XARG_ADD:
		case TT_PATTERN_CLASS_ADD:
		case TT_PATTERN_FILE_ADD:
		case TT_PATTERN_OBJECT_ADD:
		case TT_PATTERN_OP_ADD:
		case TT_PATTERN_OPNUM_ADD:
		case TT_PATTERN_OTYPE_ADD:
		case TT_PATTERN_ADDRESS_ADD:
		case TT_PATTERN_DISPOSITION_ADD:
		case TT_PATTERN_SCOPE_ADD:
		case TT_PATTERN_SENDER_ADD:
		case TT_PATTERN_SENDER_PTYPE_ADD:
		case TT_PATTERN_SESSION_ADD:
		case TT_PATTERN_STATE_ADD:
			if (! _tt_mp) {
				va_end(ap);
				return(TT_ERR_NOMP);
			}
		break;
	}

	va_start(ap, func);

	// paramater checking for NULL & cascaded errors, over-long
	// propnames, etc.
	preview = argskey;
	while (num_args--) {
		switch (c = *preview++) {
			case VTYPE:
			case CHAR_PTR:
			case OBJID:
			case PROPNAME: {
				cp = va_arg(ap, char*);

				if ((cp == NULL) && (c != CHAR_PTR)) {
					va_end(ap);
					switch(func) {
					    case TT_SESSION_TYPES_LOAD:
						return TT_ERR_FILE;
					    case TT_MESSAGE_HANDLER_SET:
						return TT_ERR_PROCID;
					    default:
						return TT_ERR_POINTER;
					}
				}

				if (c == PROPNAME) {
					if (strlen(cp) > TT_SPEC_PROPNAME_MAX_LEN) {
						va_end(ap);
						return TT_ERR_PROPNAME;
					}
				}
			} break;

			case SESSION:
				cp = va_arg(ap, char*);

				if (cp == NULL) {
					va_end(ap);
					return TT_ERR_SESSION;
				}

				if (_tt_pointer_error(cp) != TT_OK) {
					va_end(ap);
					return TT_ERR_POINTER;
                                }
			break;

			case STRICT_VOID_PTR:
			case STRICT_CHAR_PTR:
				cp = va_arg(ap, char*);

				if (cp == NULL) {
					va_end(ap);
					if  (func == TT_SPEC_CREATE) {
						return TT_ERR_PATH;
					} else {
						return TT_ERR_POINTER;
					}
				}

				if (_tt_pointer_error(cp) != TT_OK) {
					va_end(ap);
					return TT_ERR_POINTER;
				}
			break;

			case STRICT_PAT_PTR:

				p = va_arg(ap, Tt_pattern);

				if (p == NULL) {
					va_end(ap);
					return TT_ERR_POINTER;
				}

				if (_tt_pointer_error(p) != TT_OK) {
					va_end(ap);
					return TT_ERR_POINTER;
				}

				switch (func) {
					case TT_PATTERN_PRINT:
					case TT_PATTERN_DESTROY:
					case TT_PATTERN_REGISTER:
					case TT_PATTERN_UNREGISTER:
					case TT_PATTERN_CATEGORY:
					case TT_PATTERN_CATEGORY_SET:
					case TT_PATTERN_ARG_ADD:
					case TT_PATTERN_BARG_ADD:
					case TT_PATTERN_IARG_ADD:
					case TT_PATTERN_XARG_ADD:
					case TT_PATTERN_CONTEXT_ADD:
					case TT_PATTERN_ICONTEXT_ADD:
					case TT_PATTERN_XCONTEXT_ADD:
					case TT_PATTERN_BCONTEXT_ADD:
					case TT_PATTERN_CLASS_ADD:
					case TT_PATTERN_FILE_ADD:
					case TT_PATTERN_OBJECT_ADD:
					case TT_PATTERN_OP_ADD:
					case TT_PATTERN_OPNUM_ADD:
					case TT_PATTERN_OTYPE_ADD:
					case TT_PATTERN_ADDRESS_ADD:
					case TT_PATTERN_DISPOSITION_ADD:
					case TT_PATTERN_SCOPE_ADD:
					case TT_PATTERN_SENDER_ADD:
					case TT_PATTERN_SENDER_PTYPE_ADD:
					case TT_PATTERN_SESSION_ADD:
					case TT_PATTERN_STATE_ADD:
					    pat = _tt_htab->lookup_pat(p);
				     
					    if (pat.is_null()) {
						    va_end(ap);
						    return TT_ERR_POINTER;
					    }
					break;
				}
			break;

			case STRICT_MESG_PTR: {

				m = va_arg(ap, Tt_message);

				if (m == NULL) {
					va_end(ap);
					return TT_ERR_POINTER;
				}

				if (_tt_pointer_error(m) != TT_OK) {
					va_end(ap);
					return TT_ERR_POINTER;
				}

				// checking specific to certain API calls
				switch (func) {
					case TT_MESSAGE_PRINT:
					case TT_MESSAGE_CREATE_SUPER:
					case TT_MESSAGE_DESTROY:
					case TT_MESSAGE_SEND:
					case TT_MESSAGE_SEND_ON_EXIT:
					case TT_MESSAGE_REJECT:
					case TT_MESSAGE_REPLY:
					case TT_MESSAGE_FAIL:
					case TT_MESSAGE_ACCEPT:
					case TT_MESSAGE_PATTERN:
					case TT_MESSAGE_ARG_ADD:
					case TT_MESSAGE_BARG_ADD:
					case TT_MESSAGE_ARG_BVAL:
					case TT_MESSAGE_ARG_BVAL_SET:
					case TT_MESSAGE_IARG_ADD:
					case TT_MESSAGE_ARG_IVAL:
					case TT_MESSAGE_ARG_IVAL_SET:
					case TT_MESSAGE_ARG_MODE:
					case TT_MESSAGE_ARG_TYPE:
					case TT_MESSAGE_ARG_VAL:
					case TT_MESSAGE_ARG_VAL_SET:
					case TT_MESSAGE_ARGS_COUNT:
					case TT_MESSAGE_XARG_ADD:
					case TT_MESSAGE_ARG_XVAL:
					case TT_MESSAGE_ARG_XVAL_SET:
					case TT_MESSAGE_XCONTEXT_SET:
					case TT_MESSAGE_CONTEXT_IVAL:
					case TT_MESSAGE_CONTEXT_VAL:
					case TT_MESSAGE_CONTEXT_XVAL:
					case TT_MESSAGE_CONTEXT_BVAL:
					case TT_MESSAGE_CONTEXT_SET:
					case TT_MESSAGE_ICONTEXT_SET:
					case TT_MESSAGE_BCONTEXT_SET:
					case TT_MESSAGE_CONTEXTS_COUNT:
					case TT_MESSAGE_CONTEXT_SLOTNAME:
					case TT_MESSAGE_CLASS:
					case TT_MESSAGE_CLASS_SET:
					case TT_MESSAGE_FILE:
					case TT_MESSAGE_FILE_SET:
					case TT_MESSAGE_OBJECT:
					case TT_MESSAGE_OBJECT_SET:
					case TT_MESSAGE_ID:
					case TT_MESSAGE_OP:
					case TT_MESSAGE_OP_SET:
					case TT_MESSAGE_OPNUM:
					case TT_MESSAGE_OTYPE:
					case TT_MESSAGE_OTYPE_SET:
					case TT_MESSAGE_ADDRESS:
					case TT_MESSAGE_ADDRESS_SET:
					case TT_MESSAGE_HANDLER:
					case TT_MESSAGE_HANDLER_SET:
					case TT_MESSAGE_HANDLER_PTYPE:
					case TT_MESSAGE_HANDLER_PTYPE_SET:
					case TT_MESSAGE_DISPOSITION:
					case TT_MESSAGE_DISPOSITION_SET:
					case TT_MESSAGE_SCOPE:
					case TT_MESSAGE_SCOPE_SET:
					case TT_MESSAGE_SENDER:
					case TT_MESSAGE_SENDER_PTYPE:
					case TT_MESSAGE_SENDER_PTYPE_SET:
					case TT_MESSAGE_SESSION:
					case TT_MESSAGE_SESSION_SET:
					case TT_MESSAGE_STATE:
					case TT_MESSAGE_STATUS_STRING:
					case TT_MESSAGE_STATUS_STRING_SET:
					case TT_MESSAGE_STATUS:
					case TT_MESSAGE_STATUS_SET:
						msg = _tt_htab->lookup_msg(m);

						if (msg.is_null()) {
							va_end(ap);
							return TT_ERR_POINTER;
						}

					break;
				}

			} break;

			// this is an index for a particular argument
			// We have a separate case for this in order to
			// factor out the test below.
			case ARG_INTEGER: {
				int arg_index;
				_Tt_arg_list_ptr        msg_args(msg->args());

                                arg_index = va_arg(ap, int);

				if (func == TT_MESSAGE_ARG_BVAL		||
				    func == TT_MESSAGE_ARG_BVAL_SET	||
				    func == TT_MESSAGE_ARG_IVAL		||
				    func == TT_MESSAGE_ARG_IVAL_SET	||
				    func == TT_MESSAGE_ARG_MODE		||
				    func == TT_MESSAGE_ARG_TYPE		||
				    func == TT_MESSAGE_ARG_VAL		||
				    func == TT_MESSAGE_ARG_VAL_SET	||
				    func == TT_MESSAGE_ARG_XVAL		||
				    func == TT_MESSAGE_ARG_XVAL_SET) {

				    if (arg_index < 0 || msg_args.is_null() ||
					 msg_args->count() <= arg_index) {
					    va_end(ap);
					    return TT_ERR_NUM;
				    }
				} else {
					_tt_syslog(0, LOG_ERR,
						   "_Tt_audit::entry(): ARG_INTEGER: func==%s",
						   _tt_enumname(func));
					va_end(ap);
					return TT_ERR_INTERNAL;
				}
			} break;

			case STRICT_SLOTNAME:
			case SLOTNAME: {
				char *slotname;

				slotname = va_arg(ap, char *);

				if (slotname == NULL) {
					va_end(ap);
					return TT_ERR_SLOTNAME;
				}

				if (c == STRICT_SLOTNAME) {
					if (_tt_pointer_error(slotname) != TT_OK) {
						va_end(ap);
						return _tt_pointer_error(slotname);
					}

					// if the slotname is the first
					// arg, as a STRICT_SLOTNAME implies,
					// then there won't have been a
					// message passed previously, so
					// don't check for it below.
					va_end(ap);
					return TT_OK;
				}

				switch (func) {
					case TT_MESSAGE_CONTEXT_SET:
					case TT_MESSAGE_BCONTEXT_SET:
					case TT_MESSAGE_ICONTEXT_SET:
					case TT_MESSAGE_XCONTEXT_SET:
					// context may not have been
					// created yet.
					break;

					default: {
						_Tt_msg_context_ptr cntxt;

						cntxt = msg->context(slotname);
						if (cntxt.is_null()) {
							va_end(ap);
							return TT_ERR_SLOTNAME;
						}
					} break;
				}
			} break;


			case MESG_PTR: {
				Tt_message msg;

				msg = va_arg(ap, Tt_message);

				if (msg == NULL) {
					va_end(ap);
					return TT_ERR_POINTER;
				}
			} break;

			case BYTES_WITH_LEN:
			case VOID_PTR:
#ifdef __ppc
				cp = (char *) va_arg(ap, void *);
#else
				(void) va_arg(ap, void *);
#endif
			break;

			case VOID:
#ifdef __ppc
				cp = (char *) va_arg(ap, void *);
#else
				(void) va_arg(ap, void *);
#endif
			break;

			case INTEGER:
			case AUDIT_STATUS:
			case ADDRESS:
			case DISPOSITION:
		        case STATE:
		        case FEATURE:
			case CLASS:
			case CATEGORY:
			case MODE:
			case SCOPE:
			case BYTES_LENGTH:
#ifdef __ppc
                                int  junk_int;
				junk_int = va_arg(ap, int);
#else
				(void) va_arg(ap, int);
#endif
			break;

			default:
				_tt_syslog( 0, LOG_ERR,
					    "_Tt_audit::entry(): argskey=='%c'",
					    c );
				va_end(ap);
				return TT_ERR_INTERNAL;
			// NOTREACHED
			// break;
		}
	}
	va_end(ap);

	return TT_OK;
}
