/**********************************************************************
* Copyright (c) 2006, 2008 IBM Corporation and others.
* All rights reserved.   This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
* $Id: user.c,v 1.8 2008/12/17 19:36:31 jwest Exp $
* 
* Contributors: 
* IBM - Initial API and implementation
**********************************************************************/

#include "user.h"

#if defined(_WIN32)
	#define strcasecmp(str1, str2) lstrcmpi(str1, str2)
#endif

BOOL vrfusrpwd(tptp_string *userid, tptp_string *password);

/** tptpAuthenticateUser ***************************************************************************
  * This function determines whether a user has access to the controller.
  *
  * @param username - the username to authenticate
  * @param password - the password to authenticate
  * @returns TRUE if the authentication is successful,
  *          FALSE otherwise.
  */
BOOL tptpAuthenticateUser(tl_state_data_t* stateData, tptp_string *username, tptp_string *password) {
	BOOL success = FALSE;

	TPTP_LOG_DEBUG_MSG1(stateData, "Verifying password for user %s", username);

	success = vrfusrpwd(username, password);

	if(success) {
		TPTP_LOG_DEBUG_MSG1(stateData, "Password verification for user %s verified succeeded.", username);
	}
	else {
		TPTP_LOG_DEBUG_MSG1(stateData, "Password verification for user %s verified failed.", username);
	}

	return success;
}

BOOL tptpUserAllowed(tl_state_data_t* stateData, tptp_string *username, tptp_string *userType, tptp_string *userList) {
	BOOL allowed = FALSE;
	tptp_string *next;

	TPTP_LOG_DEBUG_MSG1(stateData, "Checking access privilage for user %s", username);
	if(userType == NULL) {
		TPTP_LOG_DEBUG_MSG(stateData, "There is no user list. No user is allowed.");
		allowed = FALSE;
	}
	else if(0 == strcmp(userType, USER_TYPE_ALL)) {
		TPTP_LOG_DEBUG_MSG1(stateData, "User list allows everyone. User %s is granted access.", username);
		allowed = TRUE;
	}else if(0 == strcmp(userType, USER_TYPE_CUSTOM)){
		next = strtok(userList, ",");
		while(next != NULL && !allowed) {
			if(0 == strcasecmp(next, username)) {
				TPTP_LOG_DEBUG_MSG1(stateData, "User %s exists in the user list.", username);
				allowed = TRUE;
			}
			next = strtok(NULL, ",");
		}
	}


	if(allowed) {
		TPTP_LOG_DEBUG_MSG1(stateData, "User %s allowed access.", username);
	}
	else {
		TPTP_LOG_DEBUG_MSG1(stateData, "User %s denied access.", username);
	}

	return allowed;
}

/*
 * --------------------------------------------------------------------------------
 * All the platform-dependent vrfusrpwd() functions below
 * --------------------------------------------------------------------------------
 */


#if defined(_WIN32)
/*
 *	Windows/IA32 section, in-process authentication
 */
BOOL vrfusrpwd(tptp_string *userid, tptp_string *password) {
	HANDLE handle;

	return LogonUser(userid, NULL, password, LOGON32_LOGON_NETWORK, LOGON32_PROVIDER_DEFAULT, &handle);
}
#elif defined(__MVS__)
/*
 *	OS/390 section, in-process authentication. BPX.DAEMON is needed.
 */
BOOL vrfusrpwd(tptp_string *userid, tptp_string *password) {
	return __passwd(userid, password, NULL) ? FALSE : TRUE;
}
#elif defined(__OS400__)
/*
 *	OS/400 section, in-process authentication
 */
BOOL vrfusrpwd(tptp_string *userid, tptp_string *password) {
	struct error_code_t errorCode;
	char profileHandle[12];  /* profile handle, required by QSYGETPH API */
	char useridBuf[10] = "          ";

	/* In descrypted case, the password is in code page of 437 */
	errorCode.bytesProvided = 64;
	errorCode.bytesAvailable = 0;

	if(userid[0] == '*') {
		return FALSE;
	}
	else if(strlen(userid) > 10) {
		return FALSE;
	}
	else {
		int i;
		for(i = 0; i < strlen(userid); i++) {
			useridBuf[i] = toupper(userid[i]); /* change it all to upper case */
		}
	}

	QSYGETPH(useridBuf, password, profileHandle, &errorCode, strlen(password), 37); /* CCSID of password is 37 (EBCDIC) */

	if(errorCode.bytesAvailable > 0) {
		char *exc = (char*)ra_malloc(sizeof(char) * 8);
		BZERO(exc, 8);
		strncpy(exc, errorCode.exceptionID, 7);
		ra_free(exc);

		return FALSE;
	}
	else {
		return TRUE;  /* authentication successful */
	}
}
#else /* non-Windows, non-OS/400 */
/*
 * Launch a separate process to authenticate user name and password
 */
BOOL vrfusrpwd(tptp_string *userid, tptp_string *password) {
	FILE *fp;
	BOOL success = FALSE;
	char *serverHome;
	char *authCmd;
	int authLen;
	int status;
	int rc;

	struct sigaction ignoreHandler; /* Use this handler for bypassing pre-configured signal handler */
	struct sigaction oldHandler; /* Used to temporary storing the configured signal handler */

	serverHome = getCacheEnv("default", "RASERVER_HOME");
	/* Do not pass user ID and password since they will be shown by running 'ps' */
	authLen = strlen(serverHome) + 1 + strlen(BIN_DIR) + 1 + strlen(CHKPASS_CMD) + 1; /* Bug 168705 : need a null at the end for strcat() */
	authCmd = (char*)malloc(sizeof(char) * authLen);
	BZERO(authCmd, authLen);
	strcpy(authCmd, serverHome);
	strcat(authCmd, "/");
	strcat(authCmd, BIN_DIR);
	strcat(authCmd, "/");
	strcat(authCmd, CHKPASS_CMD);

	/* Disable default SIGCHLD handler since system() call doesn't work with user-supplied signal handlers */
	BZERO(&ignoreHandler, sizeof(struct sigaction));
	BZERO(&oldHandler, sizeof(struct sigaction));

	ignoreHandler.sa_handler = SIG_DFL; /* Reset to default SIGCHLD handler */
	sigaction(SIGCHLD, &ignoreHandler, &oldHandler); /* Store the previous signal handler */

	fp = popen(authCmd, "w");
	fprintf(fp, "%s\n", userid);
	fprintf(fp, "%s\n", password);
	status = pclose(fp);
	if(WIFEXITED(status)) {
		rc = WEXITSTATUS(status);
	}

	if(rc == 100) { /* 100 indicates success */
		success = TRUE;
	}
	else {
		success = FALSE;
	}

	/* Re-enable the user-specified SIGCHLD handler */
	sigaction(SIGCHLD, &oldHandler, NULL);

	free(authCmd);

	return success;
}

#endif
