diff --git a/auth_token/PAM/Makefile b/auth_token/PAM/Makefile new file mode 100644 index 00000000..0f24a1e4 --- /dev/null +++ b/auth_token/PAM/Makefile @@ -0,0 +1,20 @@ +# +# configure environment +# +TARGET = pam_casaauthtok +include global.mak +include defaults.$(PLAT) +include rules.mak + +BIN_NAME = $(TARGET)$(xtra).$(BIN) +LIB_NAME = $(TARGET)$(xtra).$(LIB) + +# +# target object and source files +# +include objs.$(PLAT) + +# +# targets +# +include target.cl diff --git a/auth_token/PAM/link.lux b/auth_token/PAM/link.lux new file mode 100644 index 00000000..9d73ec0f --- /dev/null +++ b/auth_token/PAM/link.lux @@ -0,0 +1,10 @@ +LINK = $(CC) \ + -Wl,-Bsymbolic \ + -shared \ + -Wl,--version-script=$(TARGET)_$(PLAT).exp \ + -Wl,-rpath -Wl,/usr/$(ARCH_LlB) \ + -L/usr/$(ARCH_LIB) -lpthread -lc -lpam -lcasa_auth_token\ + -Wl,-soname -Wl,$(TARGET).so \ + -o $(LIBDIR)$(XTRA)/$(TARGET).so \ + -L$(LIBDIR)$(XTRA) \ + $(OBJDIR)*.$(O) diff --git a/auth_token/PAM/objs.lux b/auth_token/PAM/objs.lux new file mode 100644 index 00000000..f9a53ff5 --- /dev/null +++ b/auth_token/PAM/objs.lux @@ -0,0 +1,3 @@ +OBJS=\ + pam_authtoken.$(O) + diff --git a/auth_token/PAM/pam_authtoken.c b/auth_token/PAM/pam_authtoken.c new file mode 100644 index 00000000..db152936 --- /dev/null +++ b/auth_token/PAM/pam_authtoken.c @@ -0,0 +1,321 @@ +/*********************************************************************** + * File: pam_authtoken.c + * Author: Juan Carlos Luciani (jluciani@novell.com) + * + * Abstract: Implements the CASA Authentication Token PAM Module. + * + * Copyright (C) 2005 Novell, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; version 2.1 + * of the License. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * To contact Novell about this file by physical or electronic mail, + * you may find current contact information at www.novell.com. + ***********************************************************************/ + +#define _GNU_SOURCE + +#include + +#ifndef LINUX +#include +#endif + +#define PAM_SM_AUTH +#define PAM_SM_ACCOUNT +#define PAM_SM_PASSWORD +#define PAM_SM_SESSION + +#include +#include + +#include + + +/* ************************************************************************ + * LogError() + * + * Logs error to syslog. + * + * ************************************************************************/ +static void +LogError(char *pFormatStr, ... ) +{ + va_list args; + +// openlog("pam_authtoken", LOG_CONS | LOG_NOWAIT | LOG_ODELAY, LOG_USER); + va_start(args, pFormatStr); + +// vsyslog(LOG_USER | LOG_INFO, pFormatStr, args); + printf(pFormatStr, args); + + va_end(args); +// closelog(); +} + + +/* ************************************************************************ + * pam_sm_authenticate() + * + * Service provider implementation for pam_authenticate(). + * + * This is a PAM authentication management function. + * + * We are going to validate the credentials using the CASA Authentication + * Token Credential APIs. + * + * ************************************************************************/ +PAM_EXTERN int +pam_sm_authenticate(pam_handle_t *pamh, + int flags, + int argc, + const char **argv) +{ + int retStatus; + CasaStatus casaStatus; + char *pServicename = NULL; + char *pUsername = NULL; + char *pAuthToken = NULL; + + + // Get the servicename. + if (pam_get_item(pamh, PAM_SERVICE, (void*) &pServicename) == PAM_SUCCESS + && pServicename != NULL) + { + // We got the service name, now obtain the username. + // Note that we are not calling pam_get_user() because we + // assume that the service has set it before calling PAM_Authenticate. + if (pam_get_item(pamh, PAM_USER, (void*) &pUsername) == PAM_SUCCESS + && pUsername != NULL) + { + struct pam_response *responses = NULL; + + // We got the username, now obtain the authentication token. + if (pam_get_item(pamh, PAM_AUTHTOK, (void*) &pAuthToken) != PAM_SUCCESS + || pAuthToken == NULL) + { + struct pam_conv *pConv; + + // The authentication token has not been set, try to obtain it from the + // application through the use of the conversation function. + if (pam_get_item(pamh, PAM_CONV, (void*) &pConv) == PAM_SUCCESS) + { + struct pam_message msg; + struct pam_message *messages = &msg; + + // Obtained the conversation structure, now query the conversation + // function for the authentication token. + msg.msg_style = PAM_PROMPT_ECHO_OFF; + if (pConv->conv(1, + (const struct pam_message **) &messages, + &responses, + pConv->appdata_ptr) == PAM_SUCCESS) + { + // Check if we have a successful response + if (responses[0].resp_retcode == PAM_SUCCESS + && responses[0].resp) + { + // Set the authentication token with PAM + if (pam_set_item(pamh, PAM_AUTHTOK, responses[0].resp) == PAM_SUCCESS) + { + // Use the buffer returned by the caller as the authentication token + pAuthToken = responses[0].resp; + } + else + { + LogError("Unable to set the authentication token"); + } + } + else + { + LogError("Response error"); + } + } + else + { + LogError("Conversation function error"); + } + } + else + { + LogError("Unable to obtain conversation structure"); + } + } + + // Check if we suuceeded at obtaining the authentication token + if (pAuthToken) + { + // We got all of the information that we need, now validate the credentials. + casaStatus = ValidateAuthTokenCredentials(pServicename, + pUsername, + strlen(pUsername), + pAuthToken, + strlen(pAuthToken)); + if (CASA_SUCCESS(casaStatus)) + { + // Authentication succeded + retStatus = PAM_SUCCESS; + } + else + { + LogError("Service %s failed to authenticate %s with status = %08X", pServicename, pUsername, casaStatus); + retStatus = PAM_AUTH_ERR; + } + } + else + { + LogError("Unable to obtain authentication token"); + retStatus = PAM_CRED_INSUFFICIENT; + } + + // Free conversation function response buffers if necessary + if (responses) + { + if (responses[0].resp) + free(responses[0].resp); + free(responses); + } + } + else + { + LogError("Unable to obtain username"); + retStatus = PAM_CRED_INSUFFICIENT; + } + } + else + { + LogError("Unable to obtain servicename"); + retStatus = PAM_SYSTEM_ERR; + } + + return retStatus; +} + + +/* ************************************************************************ + * pam_sm_setcred() + * + * Service provider implementation for pam_setcred(). + * + * This is a PAM authentication management function. + * + * This function is here just for completedness and to protect against + * PAM misconfiguration. + * + * ************************************************************************/ +PAM_EXTERN int +pam_sm_setcred(pam_handle_t *pamh, + int flags, + int argc, + const char **argv) +{ + return PAM_SUCCESS; +} + + +/* ************************************************************************ + * pam_sm_acct_mgmt() + * + * Service provider implementation for pam_acct_mgmt(). + * + * This is a PAM account management function. + * + * This function is here just for completedness and to protect against + * PAM misconfiguration. + * + * ************************************************************************/ +PAM_EXTERN int +pam_sm_acct_mgmt(pam_handle_t *pamh, + int flags, + int argc, + const char **argv) +{ + return PAM_SUCCESS; +} + + +/* ************************************************************************ + * pam_sm_chauthtok() + * + * Service provider implementation for pam_chauthtok(). + * + * This is a PAM password management function. + * + * This function is here just for completedness and to protect against + * PAM misconfiguration. + * + * ************************************************************************/ +PAM_EXTERN int +pam_sm_chauthtok(pam_handle_t *pamh, + int flags, + int argc, + const char **argv) +{ + return PAM_SUCCESS; +} + + +/* ************************************************************************ + * pam_sm_open_session() + * + * Service provider implementation for pam_open_session(). + * + * This is a PAM session management function. + * + * This function is here just for completedness and to protect against + * PAM misconfiguration. + * + * ************************************************************************/ +PAM_EXTERN int pam_sm_open_session(pam_handle_t *pamh, + int flags, + int argc, + const char **argv) +{ + return PAM_SUCCESS; +} + + +/* ************************************************************************ + * pam_sm_close_session() + * + * Service provider implementation for pam_close_session(). + * + * This is a PAM session management function. + * + * This function is here just for completedness and to protect against + * PAM misconfiguration. + * + * ************************************************************************/ +PAM_EXTERN int pam_sm_close_session(pam_handle_t *pamh, + int flags, + int argc, + const char **argv) +{ + return PAM_SUCCESS; +} + + +/* static module data */ +#ifdef PAM_STATIC +struct pam_module _pam_pwcapture_modstruct = { + "pam_pwcapture", + pam_sm_authenticate, + pam_sm_setcred, + pam_sm_acct_mgmt, + pam_sm_chauthtok, + pam_sm_open_session, + pam_sm_close_session +}; +#endif + diff --git a/auth_token/PAM/pam_casaauthtok_lux.exp b/auth_token/PAM/pam_casaauthtok_lux.exp new file mode 100644 index 00000000..ea0c3ff6 --- /dev/null +++ b/auth_token/PAM/pam_casaauthtok_lux.exp @@ -0,0 +1,11 @@ +VER_1.0 +{ + global: + pam_sm_authenticate; + pam_sm_setcred; + pam_sm_acct_mgmt; + pam_sm_open_session; + pam_sm_close_session; + local: + *; +}; diff --git a/auth_token/auth_token_int.h b/auth_token/auth_token_int.h new file mode 100644 index 00000000..eb802ab6 --- /dev/null +++ b/auth_token/auth_token_int.h @@ -0,0 +1,304 @@ +/*********************************************************************** + * File: auth_token_int.h + * Author: Juan Carlos Luciani (jluciani@novell.com) + * + * Abstract: Defines the interface between the authentication token + * module and its providers. + * + * Copyright (C) 2005 Novell, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; version 2.1 + * of the License. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * To contact Novell about this file by physical or electronic mail, + * you may find current contact information at www.novell.com. + ***********************************************************************/ + +#ifndef _AUTH_TOKEN_INT_H_ +#define _AUTH_TOKEN_INT_H_ + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" +{ +#endif + +//===[ Include files ]===================================================== + +#include +#include + +//===[ Type definitions ]================================================== + +//===[ Function prototypes ]=============================================== + +//===[ Global variables ]================================================== + +/************************************************************************** +*************************************************************************** +** ** +** Definitions common to all interfaces ** +** ** +*************************************************************************** +**************************************************************************/ + + +//++======================================================================= +typedef +int +(SSCS_CALL *PFN_AddReference)( + IN const void *pIfInstance); +// +// Arguments: +// pIfInstance - +// Pointer to interface object. +// +// Returns: +// Interface reference count. +// +// Description: +// Increases interface reference count. +//=======================================================================-- + + +//++======================================================================= +typedef +void +(SSCS_CALL *PFN_ReleaseReference)( + IN const void *pIfInstance); +// +// Arguments: +// pIfInstance - +// Pointer to interface object. +// +// Returns: +// Nothing. +// +// Description: +// Decreases interface reference count. The interface is deallocated if +// the reference count becomes zero. +//=======================================================================-- + + + +/************************************************************************** +*************************************************************************** +** ** +** Configuration Object Interface Definitions ** +** ** +*************************************************************************** +**************************************************************************/ + + +//++======================================================================= +typedef +char* +(SSCS_CALL *PFN_GetEntryValue)( + IN const void *pIfInstance, + IN const char *pKeyName); +// +// Arguments: +// pIfInstance - +// Pointer to interface object. +// +// pKeyName - +// Pointer to NULL terminated string that contains the +// name of the key whose value is being requested. +// +// Returns: +// Pointer to NULL terminated string with value being requested or NULL. +// +// Description: +// Gets value associated with a key for the configuration object. +//=======================================================================-- + + +// +// Config Interface Object +// +typedef struct _ConfigIf +{ + PFN_AddReference addReference; + PFN_ReleaseReference releaseReference; + PFN_GetEntryValue getEntryValue; + +} ConfigIf, *PConfigIf; + + + +/************************************************************************** +*************************************************************************** +** ** +** Authentication Token Interface Definitions ** +** ** +*************************************************************************** +**************************************************************************/ + + +//++======================================================================= +typedef +CasaStatus +(SSCS_CALL *PFN_GetAuthTokenCredentials)( + IN const void *pIfInstance, + IN const ConfigIf *pServiceConfigIf, + INOUT const char *pUserNameBuf, + INOUT int *pUserNameBufLen, + INOUT const char *pTokenBuf, + INOUT int *pTokenBufLen); +// +// Arguments: +// pIfInstance - +// Pointer to interface object. +// +// pServiceConfigIf - +// Pointer to service config object to which the client is trying to +// authenticate. +// +// pUserNameBuf - +// Pointer to buffer that will receive a string with the +// username that should used when authenticating to the +// service. The length of this buffer is specified by the +// pUserNameBufLen parameter. Note that the string +// returned will be NULL terminated. +// +// pUserNameBufLen - +// Pointer to integer that contains the length of the +// buffer pointed at by pUserNameBuf. Upon return of the +// function, the integer will contain the actual length +// of the username string (including the NULL terminator) +// if the function successfully completes or the buffer +// length required if the function fails because the buffer +// pointed at by either pUserNameBuf or pTokenBuf is not +// large enough. +// +// pTokenBuf - +// Pointer to buffer that will receive the authentication +// token. The length of this buffer is specified by the +// pTokenBufLen parameter. Note that the the authentication +// token will be in the form of a NULL terminated string. +// +// pTokenBufLen - +// Pointer to integer that contains the length of the +// buffer pointed at by pTokenBuf. Upon return of the +// function, the integer will contain the actual length +// of the authentication token if the function successfully +// completes or the buffer length required if the function +// fails because the buffer pointed at by either pUserNameBuf +// or pTokenBuf is not large enough. Please note that the +// authentication token +// +// Returns: +// Casa Status +// +// Description: +// Get authentication token credentials to authenticate user to specified +// service. +//=======================================================================-- + + +//++======================================================================= +typedef +CasaStatus +(SSCS_CALL *PFN_ValidateAuthTokenCredentials)( + IN const void *pIfInstance, + IN const ConfigIf *pServiceConfigIf, + IN const char *pUserName, + IN const int userNameLen, + IN const char *pTokenBuf, + IN const int tokenBufLen); +// +// Arguments: +// pIfInstance - +// Pointer to interface object. +// +// pServiceConfigIf - +// Pointer to service config object to which the client is trying to +// authenticate. +// +// pUserName - +// Pointer to string with the username that is being +// authenticated to the service. The length of the name +// is specified by the pUserNameLen parameter. Note that +// the string does not need to be NULL terminated. +// +// userNameLen - +// Length of the user name contained within the buffer +// pointed at by pUserNameBuf (Does not include the NULL +// terminator). If this parameter is set to -1 then the +// function assumes that the username string is NULL +// terminated. +// +// pTokenBuf - +// Pointer to buffer that will receive the authentication +// token. The length of this buffer is specified by the +// pTokenBufLen parameter. Note that the the authentication +// token will be in the form of a NULL terminated string. +// +// tokenBufLen - +// Length of the data contained within the buffer pointed +// at by pTokenBuf. +// +// Returns: +// Casa status. +// +// Description: +// Validates authentication token credentials. +// +//=======================================================================-- + + +// +// AuthToken Interface Object +// +typedef struct _AuthTokenIf +{ + PFN_AddReference addReference; + PFN_ReleaseReference releaseReference; + PFN_GetAuthTokenCredentials getAuthTokenCredentials; + PFN_ValidateAuthTokenCredentials validateAuthTokenCredentials; + +} AuthTokenIf, *PAuthTokenIf; + + +//++======================================================================= +typedef +CasaStatus +(SSCS_CALL *PFN_GetAuthTokenIfRtn)( + IN const ConfigIf *pModuleConfigIf, + INOUT AuthTokenIf **ppAuthTokenIf); +// +// Arguments: +// pModuleConfigIf - +// Pointer to configuration interface instance for the module. +// +// ppAuthTokenIf - +// Pointer to variable that will receive pointer to AuthTokenIf +// instance. +// +// Returns: +// Casa Status +// +// Description: +// Gets authentication token interface instance. +//=======================================================================-- + +#define GET_AUTH_TOKEN_INTERFACE_RTN_SYMBOL "GetAuthTokenInterface" +#define GET_AUTH_TOKEN_INTERFACE_RTN GetAuthTokenInterface + + +#if defined(__cplusplus) || defined(c_plusplus) +} +#endif // #if defined(__cplusplus) || defined(c_plusplus) + +#endif // #ifndef _AUTH_TOKEN_INT_H_ + diff --git a/auth_token/casa_status.h b/auth_token/casa_status.h new file mode 100644 index 00000000..e8e9f695 --- /dev/null +++ b/auth_token/casa_status.h @@ -0,0 +1,204 @@ +/*********************************************************************** + * File: casa_status.h + * + * Abstract: Defines the statuses used within CASA. + * + * Copyright (C) 2005 Novell, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; version 2.1 + * of the License. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * To contact Novell about this file by physical or electronic mail, + * you may find current contact information at www.novell.com. + ***********************************************************************/ + +#ifndef _CASA_STATUS_H_ +#define _CASA_STATUS_H_ + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" +{ +#endif + +//===[ Header files specific to this module ]============================== + +#include + +//===[ External data ]============================== + +//===[ External prototypes ]============================== + +//===[ Type definitions ]============================== + +// +// CasaStatus type +// +// +// The layed out of status values is as follows: +// +// 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 +// 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 +// +---+-+-+-+---------------------+-------------------------------+ +// |Sev|r|r|r| Facility | Code | +// +---+-+-+-+---------------------+-------------------------------+ +// +// where +// +// Sev - is the severity code +// +// 00 - Success +// 01 - Informational +// 10 - Warning +// 11 - Error +// +// r - is a reserved bit for internal use +// +// Facility - is the facility code +// +// Code - is the facility's status code +// +typedef uint32_t CasaStatus; + + +//===[ Manifest constants ]============================== + +// +// Define severity codes to be used with CasaStatusBuild macro +// + +#define CASA_SEVERITY_SUCCESS 0x0 +#define CASA_SEVERITY_INFORMATIONAL 0x1 +#define CASA_SEVERITY_WARNING 0x2 +#define CASA_SEVERITY_ERROR 0x3 + +// +// Define the facility codes +// +// Facility codes will start at 0x800 and then work backwards +// in an effort to avoid conflict with other system components. +// + +#define CASA_FACILITY_AUTHTOKEN 0x7FF +#define CASA_FACILITY_KRB5TOKEN 0x7FE + +// +// Codes above FACILITY_SPECIFIC are component specific status codes. +// Facility specific status codes are defined in the facilities' header file. +// + +#define FACILITY_SPECIFIC 0x00001000 + +// +// Codes below FACILITY_SPECIFIC are common status codes shared by all components. +// + +#define CASA_STATUS_SUCCESS ((CasaStatus)0x00000000) // Call completed successfully +#define CASA_STATUS_UNSUCCESSFUL ((CasaStatus)0x00000001) // Call completed unsuccessfully +#define CASA_STATUS_INVALID_HANDLE ((CasaStatus)0x00000002) // An invalid handle was specified +#define CASA_STATUS_INVALID_PARAMETER ((CasaStatus)0x00000003) // An invalid parameter to function was specified +#define CASA_STATUS_INSUFFICIENT_RESOURCES ((CasaStatus)0x00000004) +#define CASA_STATUS_ACCESS_DENIED ((CasaStatus)0x00000005) // Caller does not have required access rights for operation +#define CASA_STATUS_BUFFER_OVERFLOW ((CasaStatus)0x00000006) // The data was too large to fit into the specified buffer +#define CASA_STATUS_NO_DATA ((CasaStatus)0x00000007) +#define CASA_STATUS_NO_MORE_ENTRIES ((CasaStatus)0x00000008) // No more entries to enumerate +#define CASA_STATUS_TIMEOUT ((CasaStatus)0x00000009) // Timed out waiting on resource +#define CASA_STATUS_OBJECT_NOT_FOUND ((CasaStatus)0x0000000A) +#define CASA_STATUS_CANCELLED ((CasaStatus)0x0000000B) // Request cancelled +#define CASA_STATUS_NOT_IMPLEMENTED ((CasaStatus)0x0000000C) +#define CASA_STATUS_PENDING ((CasaStatus)0x0000000D) // The request is being processed +#define CASA_STATUS_INVALID_STATE ((CasaStatus)0x0000000E) +#define CASA_STATUS_INVALID_REQUEST ((CasaStatus)0x0000000F) +#define CASA_STATUS_ALREADY_REGISTERED ((CasaStatus)0x00000010) +#define CASA_STATUS_ABORTED ((CasaStatus)0x00000011) +#define CASA_STATUS_REQUEST_NOT_FOUND ((CasaStatus)0x00000012) // Unable to cancel request because it was not found +#define CASA_STATUS_OBJECT_ALREADY_EXISTS ((CasaStatus)0x00000013) // The object being created already exists. +#define CASA_STATUS_UNSUPPORTED_PROTOCOL ((CasaStatus)0x00000014) // The object is only accessable through a unsupported protocol. +#define CASA_STATUS_REJECTED ((CasaStatus)0x00000015) +#define CASA_STATUS_ACCESS_VIOLATION ((CasaStatus)0x00000016) +#define CASA_STATUS_NOT_SUPPORTED ((CasaStatus)0x00000017) +#define CASA_STATUS_NO_PROVIDERS ((CasaStatus)0x00000018) // No providers are available. +#define CASA_STATUS_CONFLICT ((CasaStatus)0x00000019) +#define CASA_STATUS_INSUFFICIENT_STORAGE ((CasaStatus)0x0000001A) +#define CASA_STATUS_AUTHENTICATION_FAILURE ((CasaStatus)0x0000001B) +#define CASA_STATUS_CONFIGURATION_ERROR ((CasaStatus)0x0000001C) +#define CASA_STATUS_LIBRARY_LOAD_FAILURE ((CasaStatus)0x0000001D) + +//===[ Macro definitions ]============================== + +// +// Macro for building status error codes +// + +#define CasaStatusBuild(severity, facility, errorcode) \ + ((CasaStatus)(((severity) << 30) | ((facility) << 16) | (errorcode))) + +// +// Macro for retrieving the facility +// + +#define CasaStatusFacility(status) \ + ((CasaStatus)(((CasaStatus)(status) >> 16) & (CasaStatus)0x07FF)) + +// +// Macro for retrieving severity +// + +#define CasaStatusSeverity(status) \ + ((CasaStatus)(((CasaStatus)(status)) >> 30)) + +// +// Macro for retrieving status code +// + +#define CasaStatusCode(status) \ + ((CasaStatus)((CasaStatus)(status) & (CasaStatus)0x0000FFFF)) + +// +// Macro for checking status code for success +// + +#define CASA_SUCCESS(status) \ + ((CasaStatus)(status) >> 30 != CASA_SEVERITY_ERROR) + +// +// Macro for checking status code for information +// + +#define CASA_INFORMATION(status) \ + ((CasaStatus)(status) >> 30 == CASA_SEVERITY_INFORMATIONAL) + +// +// Macro for checking status code for warning +// + +#define CASA_WARNING(status) \ + ((CasaStatus)(status) >> 30 == CASA_SEVERITY_WARNING) + +// +// Macro for checking status code for error +// + +#define CASA_ERROR(status) \ + ((CasaStatus)(status) >> 30 == CASA_SEVERITY_ERROR) + + +//===[ Function Prototypes ]============================== + +//===[ Global Variables ]============================== + +#endif // _CASA_STATUS_H_ + +//========================================================================= +//========================================================================= +// casa_status.h diff --git a/auth_token/krb5_token/linux/Makefile b/auth_token/krb5_token/linux/Makefile new file mode 100644 index 00000000..64268518 --- /dev/null +++ b/auth_token/krb5_token/linux/Makefile @@ -0,0 +1,20 @@ +# +# configure environment +# +TARGET = casa_krb5_token +include global.mak +include defaults.$(PLAT) +include rules.mak + +BIN_NAME = $(TARGET)$(xtra).$(BIN) +LIB_NAME = $(TARGET)$(xtra).$(LIB) + +# +# target object and source files +# +include objs.$(PLAT) + +# +# targets +# +include target.cl diff --git a/auth_token/krb5_token/linux/casa_krb5_token_lux.exp b/auth_token/krb5_token/linux/casa_krb5_token_lux.exp new file mode 100644 index 00000000..9280a1fd --- /dev/null +++ b/auth_token/krb5_token/linux/casa_krb5_token_lux.exp @@ -0,0 +1,7 @@ +VER_1.0 +{ + global: + GetAuthTokenInterface; + local: + *; +}; diff --git a/auth_token/krb5_token/linux/get.c b/auth_token/krb5_token/linux/get.c new file mode 100644 index 00000000..a41df87e --- /dev/null +++ b/auth_token/krb5_token/linux/get.c @@ -0,0 +1,314 @@ +/*********************************************************************** + * File: get.c + * Author: Juan Carlos Luciani (jluciani@novell.com) + * + * Abstract: Implements the GetAuthTokenCredentials functionality + * for the Kerberos system over GSS-API. + * + * Copyright (C) 2005 Novell, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; version 2.1 + * of the License. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * To contact Novell about this file by physical or electronic mail, + * you may find current contact information at www.novell.com. + ***********************************************************************/ + +//===[ Include files ]===================================================== + +#include "internal.h" + +//===[ Type definitions ]================================================== + +//===[ Function prototypes ]=============================================== + +//===[ Global variables ]================================================== + + +//++======================================================================= +CasaStatus SSCS_CALL +Krb5AuthTokenIf_GetAuthTokenCredentials( + IN const void *pIfInstance, + IN const ConfigIf *pServiceConfigIf, + INOUT const char *pUserNameBuf, + INOUT int *pUserNameBufLen, + INOUT const char *pTokenBuf, + INOUT int *pTokenBufLen) +// +// Arguments: +// pIfInstance - +// Pointer to interface object. +// +// pServiceConfigIf - +// Pointer to service config object to which the client is trying to +// authenticate. +// +// pUserNameBuf - +// Pointer to buffer that will receive a string with the +// username that should used when authenticating to the +// service. The length of this buffer is specified by the +// pUserNameBufLen parameter. Note that the string +// returned will be NULL terminated. +// +// pUserNameBufLen - +// Pointer to integer that contains the length of the +// buffer pointed at by pUserNameBuf. Upon return of the +// function, the integer will contain the actual length +// of the username string (including the NULL terminator) +// if the function successfully completes or the buffer +// length required if the function fails because the buffer +// pointed at by either pUserNameBuf or pTokenBuf is not +// large enough. +// +// pTokenBuf - +// Pointer to buffer that will receive the authentication +// token. The length of this buffer is specified by the +// pTokenBufLen parameter. Note that the the authentication +// token will be in the form of a NULL terminated string. +// +// pTokenBufLen - +// Pointer to integer that contains the length of the +// buffer pointed at by pTokenBuf. Upon return of the +// function, the integer will contain the actual length +// of the authentication token if the function successfully +// completes or the buffer length required if the function +// fails because the buffer pointed at by either pUserNameBuf +// or pTokenBuf is not large enough. +// +// Returns: +// Casa Status +// +// Description: +// Get authentication token credentials to authenticate user to specified +// service. +// +// L2 +//=======================================================================-- +{ + CasaStatus retStatus; + OM_uint32 gssMajStat; + OM_uint32 gssMinStat; + char *pKrbServiceName; + + + DbgTrace(1, "krb5_token -Krb5AuthTokenIf_GetAuthTokenCredentials- Start\n", 0); + + // Validate input parameters + if (pIfInstance == NULL + || pServiceConfigIf == NULL + || pUserNameBufLen == NULL + || (pUserNameBuf == NULL && *pUserNameBufLen != 0) + || pTokenBufLen == NULL + || (pTokenBuf == NULL && *pTokenBufLen != 0)) + { + DbgTrace(0, "krb5_token -Krb5AuthTokenIf_GetAuthTokenCredentials- Invalid input parameter\n", 0); + + retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, + CASA_FACILITY_KRB5TOKEN, + CASA_STATUS_INVALID_PARAMETER); + goto exit; + } + + // Map service name to Krb Service Principal Name + pKrbServiceName = pServiceConfigIf->getEntryValue(pServiceConfigIf, "KerberosPrincipal"); + if (pKrbServiceName) + { + gss_buffer_desc gssBuffer; + gss_name_t gssServiceName; + + // Import the service principal name into something that + // GSS-API can understand based on its form. + gssBuffer.value = (void*) pKrbServiceName; + gssBuffer.length = strlen(pKrbServiceName) + 1; + if (strchr(pKrbServiceName, '@') != NULL) + { + // The name is of the form "servicename@hostname" + gssMajStat = gss_import_name(&gssMinStat, + &gssBuffer, + (gss_OID) GSS_C_NT_HOSTBASED_SERVICE, + &gssServiceName); + } + else + { + // The name is of the form "servicename" + gssMajStat = gss_import_name(&gssMinStat, + &gssBuffer, + (gss_OID) GSS_C_NT_USER_NAME, + &gssServiceName); + } + + // Proceed based on the result of the name import operation + if (gssMajStat == GSS_S_COMPLETE) + { + // Establish a context + gss_ctx_id_t gssContext = GSS_C_NO_CONTEXT; + gss_buffer_desc gssSendToken = {0}; + OM_uint32 gssRetFlags; + gssMajStat = gss_init_sec_context(&gssMinStat, + GSS_C_NO_CREDENTIAL, + &gssContext, + gssServiceName, + g_mechOid, + 0, // Flags + 0, + NULL, // no channel bindings + GSS_C_NO_BUFFER, // no token from peer + NULL, // ignore mech type + &gssSendToken, + &gssRetFlags, + NULL); // ignore time rec + + // Proceed based on the result of the gss_init_sec_context operation + if (gssMajStat == GSS_S_COMPLETE + && gssSendToken.length != 0) + { + // Now get the username + gss_name_t gssClient; + gssMajStat = gss_inquire_context(&gssMinStat, + gssContext, + &gssClient, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL); + if (gssMajStat == GSS_S_COMPLETE) + { + gss_buffer_desc gssDisplayName; + gss_OID gssNameType; + gssMajStat = gss_display_name(&gssMinStat, gssClient, &gssDisplayName, &gssNameType); + if (gssMajStat == GSS_S_COMPLETE) + { + char *pEncodedToken; + int encodedTokenLen; + + // Base64 encode the token + retStatus = EncodeData(gssSendToken.value, + gssSendToken.length, + &pEncodedToken, + &encodedTokenLen); + if (CASA_SUCCESS(retStatus)) + { + // Verify that the caller provided buffers that are big enough + if (gssDisplayName.length > *pUserNameBufLen + || encodedTokenLen > *pTokenBufLen) + { + // At least one of the supplied buffers is not big enough + DbgTrace(1, "krb5_token -Krb5AuthTokenIf_GetAuthTokenCredentials- Insufficient buffer space provided\n", 0); + + retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, + CASA_FACILITY_KRB5TOKEN, + CASA_STATUS_BUFFER_OVERFLOW); + } + else + { + // The buffers provided are large enough, copy the data and return the actual sizes. + memcpy((void*) pUserNameBuf, gssDisplayName.value, gssDisplayName.length + 1); + memcpy((void*) pTokenBuf, pEncodedToken, encodedTokenLen +1); + + // Success + retStatus = CASA_STATUS_SUCCESS; + } + + // Return the actual sizes or the sizes required + *pUserNameBufLen = gssDisplayName.length + 1; + *pTokenBufLen = encodedTokenLen; + + // Free the buffer containing the encoded token + free(pEncodedToken); + } + else + { + DbgTrace(1, "krb5_token -Krb5AuthTokenIf_GetAuthTokenCredentials- Encoding failed\n", 0); + } + + // Release the buffer associated with the client display name + gss_release_buffer(&gssMinStat, &gssDisplayName); + } + else + { + DbgTrace(0, "krb5_token -Krb5AuthTokenIf_GetAuthTokenCredentials- Error obtaining display name\n", 0); + LogGssStatuses("obtaining display name", gssMajStat, gssMinStat); + + retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, + CASA_FACILITY_KRB5TOKEN, + CASA_STATUS_UNSUCCESSFUL); + } + } + else + { + DbgTrace(0, "krb5_token -Krb5AuthTokenIf_GetAuthTokenCredentials- Error inquiring context\n", 0); + LogGssStatuses("inquiring context", gssMajStat, gssMinStat); + + retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, + CASA_FACILITY_KRB5TOKEN, + CASA_STATUS_UNSUCCESSFUL); + } + } + else + { + DbgTrace(0, "krb5_token -Krb5AuthTokenIf_GetAuthTokenCredentials- Error initing sec context\n", 0); + LogGssStatuses("initializing context", gssMajStat, gssMinStat); + + retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, + CASA_FACILITY_KRB5TOKEN, + CASA_STATUS_UNSUCCESSFUL); + } + + // Release send token buffer if necessary + if (gssSendToken.length != 0) + gss_release_buffer(&gssMinStat, &gssSendToken); + + + // Free context if necessary + if (gssContext != GSS_C_NO_CONTEXT) + gss_delete_sec_context(&gssMinStat, &gssContext, GSS_C_NO_BUFFER); + + // Release the buffer associated with the service name + gss_release_name(&gssMinStat, &gssServiceName); + } + else + { + DbgTrace(0, "krb5_token -Krb5AuthTokenIf_GetAuthTokenCredentials- Error importing service name\n", 0); + LogGssStatuses("importing service name", gssMajStat, gssMinStat); + + retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, + CASA_FACILITY_KRB5TOKEN, + CASA_STATUS_OBJECT_NOT_FOUND); + } + + // Free the krb service principal name + free(pKrbServiceName); + } + else + { + DbgTrace(0, "krb5_token -Krb5AuthTokenIf_GetAuthTokenCredentials- No Kerberos principal name configured\n", 0); + retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, + CASA_FACILITY_KRB5TOKEN, + CASA_STATUS_CONFIGURATION_ERROR); + } + +exit: + + DbgTrace(1, "krb5_token -Krb5AuthTokenIf_GetAuthTokenCredentials- End, retStatus = %08X\n", retStatus); + + return retStatus; +} + + +//++======================================================================= +//++======================================================================= +//++======================================================================= + diff --git a/auth_token/krb5_token/linux/interface.c b/auth_token/krb5_token/linux/interface.c new file mode 100644 index 00000000..8878213c --- /dev/null +++ b/auth_token/krb5_token/linux/interface.c @@ -0,0 +1,218 @@ +/*********************************************************************** + * File: interface.c + * Author: Juan Carlos Luciani (jluciani@novell.com) + * + * Abstract: Implements the AuthTokenIf for the module. + * + * Copyright (C) 2005 Novell, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; version 2.1 + * of the License. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * To contact Novell about this file by physical or electronic mail, + * you may find current contact information at www.novell.com. + ***********************************************************************/ + +//===[ Include files ]===================================================== + +#include "internal.h" + +//===[ Type definitions ]================================================== + +// +// Authentication Token Interface instance data +// +typedef struct _AuthTokenIfInstance +{ + int refCount; + AuthTokenIf authTokenIf; + +} AuthTokenIfInstance, *PAuthTokenIfInstance; + +//===[ Function prototypes ]=============================================== + +//===[ Global variables ]================================================== + +// AuthTokenIf synchronization mutex and variables +static +pthread_mutex_t g_authTokenIfMutex = PTHREAD_MUTEX_INITIALIZER; + +static +int g_numAuthTokenIfObjs = 0; + + + +//++======================================================================= +int SSCS_CALL +Krb5AuthTokenIf_AddReference( + IN const void *pIfInstance) +// +// Arguments: +// pIfInstance - +// Pointer to interface object. +// +// Returns: +// Interface reference count. +// +// Description: +// Increases interface reference count. +// +// L2 +//=======================================================================-- +{ + int refCount; + AuthTokenIfInstance *pAuthTokenIfInstance = CONTAINING_RECORD(pIfInstance, AuthTokenIfInstance, authTokenIf); + + DbgTrace(2, "krb5_token -Krb5AuthTokenIf_AddReference- Start\n", 0); + + // Increment the reference count on the object + pthread_mutex_lock(&g_authTokenIfMutex); + pAuthTokenIfInstance->refCount ++; + refCount = pAuthTokenIfInstance->refCount; + pthread_mutex_unlock(&g_authTokenIfMutex); + + DbgTrace(2, "krb5_token -Krb5AuthTokenIf_AddReference- End, refCount = %08X\n", refCount); + + return refCount; +} + + +//++======================================================================= +void SSCS_CALL +Krb5AuthTokenIf_ReleaseReference( + IN const void *pIfInstance) +// +// Arguments: +// pIfInstance - +// Pointer to interface object. +// +// Returns: +// Nothing. +// +// Description: +// Decreases interface reference count. The interface is deallocated if +// the reference count becomes zero. +// +// L2 +//=======================================================================-- +{ + bool freeObj = false; + AuthTokenIfInstance *pAuthTokenIfInstance = CONTAINING_RECORD(pIfInstance, AuthTokenIfInstance, authTokenIf); + + DbgTrace(2, "krb5_token -Krb5AuthTokenIf_ReleaseReference- Start\n", 0); + + // Decrement the reference count on the object and determine if it needs to + // be released. + pthread_mutex_lock(&g_authTokenIfMutex); + pAuthTokenIfInstance->refCount --; + if (pAuthTokenIfInstance->refCount == 0) + { + // The object needs to be released, forget about it. + freeObj = true; + g_numAuthTokenIfObjs --; + } + pthread_mutex_unlock(&g_authTokenIfMutex); + + // Free object if necessary + if (freeObj) + free(pAuthTokenIfInstance); + + DbgTrace(2, "krb5_token -Krb5AuthTokenIf_ReleaseReference- End\n", 0); +} + + +//++======================================================================= +CasaStatus SSCS_CALL +GET_AUTH_TOKEN_INTERFACE_RTN( + IN const ConfigIf *pModuleConfigIf, + INOUT AuthTokenIf **ppAuthTokenIf) +// +// Arguments: +// pModuleConfigIf - +// Pointer to configuration interface instance for the module. +// +// ppAuthTokenIf - +// Pointer to variable that will receive pointer to AuthTokenIf +// instance. +// +// Returns: +// Casa Status +// +// Description: +// Gets authentication token interface instance. +// +// L2 +//=======================================================================-- +{ + CasaStatus retStatus; + AuthTokenIfInstance *pAuthTokenIfInstance; + + + DbgTrace(1, "krb5_token -GetAuthTokenInterface- Start\n", 0); + + // Validate input parameters + if (pModuleConfigIf == NULL + || ppAuthTokenIf == NULL) + { + DbgTrace(0, "krb5_token -GetAuthTokenInterface- Invalid input parameter\n", 0); + + retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, + CASA_FACILITY_KRB5TOKEN, + CASA_STATUS_INVALID_PARAMETER); + goto exit; + } + + // Allocate space for the interface instance + pAuthTokenIfInstance = malloc(sizeof(*pAuthTokenIfInstance)); + if (pAuthTokenIfInstance) + { + // Initialize the interface instance data + pAuthTokenIfInstance->refCount = 1; + pAuthTokenIfInstance->authTokenIf.addReference = Krb5AuthTokenIf_AddReference; + pAuthTokenIfInstance->authTokenIf.releaseReference = Krb5AuthTokenIf_ReleaseReference; + pAuthTokenIfInstance->authTokenIf.getAuthTokenCredentials = Krb5AuthTokenIf_GetAuthTokenCredentials; + pAuthTokenIfInstance->authTokenIf.validateAuthTokenCredentials = Krb5AuthTokenIf_ValidateAuthTokenCredentials; + + // Keep track of this object + pthread_mutex_lock(&g_authTokenIfMutex); + g_numAuthTokenIfObjs ++; + pthread_mutex_unlock(&g_authTokenIfMutex); + + // Return the interface to the caller + *ppAuthTokenIf = &pAuthTokenIfInstance->authTokenIf; + + // Success + retStatus = CASA_STATUS_SUCCESS; + } + else + { + DbgTrace(0, "krb5_token -GetAuthTokenInterface- Buffer allocation failure\n", 0); + + retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, + CASA_FACILITY_KRB5TOKEN, + CASA_STATUS_INSUFFICIENT_RESOURCES); + } + +exit: + + DbgTrace(1, "krb5_token -GetAuthTokenInterface- End, retStatus = %08X\n", retStatus); + + return retStatus; +} + + +//++======================================================================= +//++======================================================================= +//++======================================================================= + diff --git a/auth_token/krb5_token/linux/internal.h b/auth_token/krb5_token/linux/internal.h new file mode 100644 index 00000000..980e0b30 --- /dev/null +++ b/auth_token/krb5_token/linux/internal.h @@ -0,0 +1,113 @@ +/*********************************************************************** + * File: internal.h + * Author: Juan Carlos Luciani (jluciani@novell.com) + * + * Abstract: Defines or includes the definitions necessary for the + * module. + * + * Copyright (C) 2005 Novell, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; version 2.1 + * of the License. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * To contact Novell about this file by physical or electronic mail, + * you may find current contact information at www.novell.com. + ***********************************************************************/ + +//===[ Include files ]===================================================== + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +//===[ Type definitions ]================================================== + +#define CONTAINING_RECORD(address, type, field) ((type *)( \ + (char*)(address) - \ + (char*)(&((type *)0)->field))) + +// +// DbgTrace macro define +// +#define DbgTrace(LEVEL, X, Y) { \ + if (LEVEL == 0) \ + printf(X, Y); \ + else if (DebugLevel >= LEVEL) \ + printf(X, Y); \ +} + +//===[ Inlines functions ]=============================================== + +//===[ Function prototypes ]=============================================== + +//===[ Global variables ]================================================== + +//===[ Global externals ]================================================== + +extern int DebugLevel; + +extern gss_OID g_mechOid; + +//===[ External prototypes ]=============================================== + +extern void +LogGssStatuses( + IN char *operation, + IN OM_uint32 majorGssStatus, + IN OM_uint32 minorGssStatus); + +extern CasaStatus +EncodeData( + IN const void *pData, + IN const int32_t dataLen, + INOUT char **ppEncodedData, + INOUT int32_t *pEncodedDataLen); + +extern CasaStatus +DecodeData( + IN const char *pEncodedData, + IN const int32_t encodedDataLen, + INOUT void **ppData, + INOUT int32_t *pDataLen); + +extern CasaStatus CSAPI +Krb5AuthTokenIf_GetAuthTokenCredentials( + IN const void *pIfInstance, + IN const ConfigIf *pServiceConfigIf, + INOUT const char *pUserNameBuf, + INOUT int *pUserNameBufLen, + INOUT const char *pTokenBuf, + INOUT int *pTokenBufLen); + +extern CasaStatus CSAPI +Krb5AuthTokenIf_ValidateAuthTokenCredentials( + IN const void *pIfInstance, + IN const ConfigIf *pServiceConfigIf, + IN const char *pUserName, + IN const int userNameLen, + IN const char *pTokenBuf, + IN const int tokenBufLen); + + +//========================================================================= + diff --git a/auth_token/krb5_token/linux/link.lux b/auth_token/krb5_token/linux/link.lux new file mode 100644 index 00000000..20459938 --- /dev/null +++ b/auth_token/krb5_token/linux/link.lux @@ -0,0 +1,10 @@ +LINK = $(CC) \ + -Wl,-Bsymbolic \ + -shared \ + -Wl,--version-script=$(TARGET)_$(PLAT).exp \ + -Wl,-rpath -Wl,/usr/$(ARCH_LlB) \ + -L/usr/$(ARCH_LIB) -lpthread -lc -lgssapi \ + -Wl,-soname -Wl,$(TARGET).so \ + -o $(LIBDIR)$(XTRA)/$(TARGET).so \ + -L$(LIBDIR)$(XTRA) \ + $(OBJDIR)*.$(O) diff --git a/auth_token/krb5_token/linux/objs.lux b/auth_token/krb5_token/linux/objs.lux new file mode 100644 index 00000000..cd5668f8 --- /dev/null +++ b/auth_token/krb5_token/linux/objs.lux @@ -0,0 +1,6 @@ +OBJS=\ + util.$(O) \ + get.$(O) \ + verify.$(O) \ + interface.$(O) + diff --git a/auth_token/krb5_token/linux/util.c b/auth_token/krb5_token/linux/util.c new file mode 100644 index 00000000..557d8adc --- /dev/null +++ b/auth_token/krb5_token/linux/util.c @@ -0,0 +1,383 @@ +/*********************************************************************** + * File: util.c + * Author: Juan Carlos Luciani (jluciani@novell.com) + * + * Abstract: Implements common utility functions for the library. + * + * Copyright (C) 2005 Novell, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; version 2.1 + * of the License. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * To contact Novell about this file by physical or electronic mail, + * you may find current contact information at www.novell.com. + ***********************************************************************/ + +//===[ Include files ]===================================================== + +#include "internal.h" +#include + +//===[ Type definitions ]================================================== + +//===[ Function prototypes ]=============================================== + +//===[ Global variables ]================================================== + +// Debug Level +int DebugLevel = 1; + +// Mechanism OID +gss_OID g_mechOid = GSS_C_NULL_OID; + +// Tables for Base64 encoding and decoding +static const int8_t g_Base64[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + +static const uint8_t g_Expand64[256] = +{ + /* ASCII table */ + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 62, 64, 64, 64, 63, + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 64, 64, 64, 64, 64, 64, + 64, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 64, 64, 64, 64, 64, + 64, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64 +}; + + +/* ************************************************************************ + * LogError() + * + * Log error to system log. + * + * ************************************************************************/ +//static void +//LogError(char *pFormatStr, ... ) +//{ +// va_list args; +// +// openlog("CASA", LOG_CONS | LOG_NOWAIT | LOG_ODELAY, LOG_USER); +// va_start(args, pFormatStr); +// vsyslog(LOG_USER | LOG_INFO, pFormatStr, args); +// va_end(args); +// closelog(); +//} + + +//++======================================================================= +void +LogGssStatuses( + IN char *operation, + IN OM_uint32 majorGssStatus, + IN OM_uint32 minorGssStatus) +// +// Arguments: +// +// Returns: +// +// Description: +// +// L2 +//=======================================================================-- +{ + OM_uint32 gssMajStat; + OM_uint32 gssMinStat; + gss_buffer_desc msg = GSS_C_EMPTY_BUFFER; + OM_uint32 gssMsgCtx; + + // Trace the messages associated with the major status + gssMsgCtx = 0; + while (1) + { + gssMajStat = gss_display_status(&gssMinStat, + majorGssStatus, + GSS_C_GSS_CODE, + g_mechOid, + &gssMsgCtx, + &msg); + if (gssMajStat != GSS_S_COMPLETE) + { + DbgTrace(0, "krb5_token -LogGssStatuses- Error obtaining display status\n", 0); + break; + } + + // Trace this message + DbgTrace(0, "krb5_token -LogGssStatuses- GSS-API error %s: ", operation); + DbgTrace(0, "%s\n", (char *)msg.value); + + if (msg.length != 0) + gss_release_buffer(&gssMinStat, &msg); + + if (!gssMsgCtx) + break; + } + + // Trace the messages associated with the minor status + gssMsgCtx = 0; + while (1) + { + gssMajStat = gss_display_status(&gssMinStat, + minorGssStatus, + GSS_C_MECH_CODE, + g_mechOid, + &gssMsgCtx, + &msg); + if (gssMajStat != GSS_S_COMPLETE) + { + DbgTrace(0, "krb5_token -LogGssStatuses- Error obtaining display status\n", 0); + break; + } + + // Trace this message + DbgTrace(0, "krb5_token -LogGssStatuses- GSS-API error %s: ", operation); + DbgTrace(0, "%s\n", (char *)msg.value); + + if (msg.length != 0) + gss_release_buffer(&gssMinStat, &msg); + + if (!gssMsgCtx) + break; + } +} + + +//++======================================================================= +CasaStatus +EncodeData( + IN const void *pData, + IN const int32_t dataLen, + INOUT char **ppEncodedData, + INOUT int32_t *pEncodedDataLen) +// +// Arguments: +// +// Returns: +// +// Description: +// +// L2 +//=======================================================================-- +{ + CasaStatus retStatus; + int encodedSize; + char *pBuffer; + + + DbgTrace(3, "krb5_token -EncodeData- Start\n", 0); + + // Determine the encoded size and allocate a buffer to hold the encoded data + encodedSize = ((dataLen * 4 + 2) / 3) - (dataLen % 3 ) + 4; + *ppEncodedData = malloc(encodedSize); + if (*ppEncodedData) + { + uint8_t *pOut, *pIn; + int i; + + // Setup pointers to move through the buffers + pIn = (uint8_t*) pData; + pOut = (uint8_t*) *ppEncodedData; + + // Perform the encoding + for (i = 0; i < dataLen - 2; i += 3) + { + *pOut++ = g_Base64[(pIn[i] >> 2) & 0x3F]; + *pOut++ = g_Base64[((pIn[i] & 0x3) << 4) | + ((int32_t)(pIn[i + 1] & 0xF0) >> 4)]; + *pOut++ = g_Base64[((pIn[i + 1] & 0xF) << 2) | + ((int32_t)(pIn[i + 2] & 0xC0) >> 6)]; + *pOut++ = g_Base64[pIn[i + 2] & 0x3F]; + } + if (i < dataLen) + { + *pOut++ = g_Base64[(pIn[i] >> 2) & 0x3F]; + if (i == (dataLen - 1)) + { + *pOut++ = g_Base64[((pIn[i] & 0x3) << 4)]; + *pOut++ = '='; + } + else + { + *pOut++ = g_Base64[((pIn[i] & 0x3) << 4) | + ((int32_t)(pIn[i + 1] & 0xF0) >> 4)]; + *pOut++ = g_Base64[((pIn[i + 1] & 0xF) << 2)]; + } + *pOut++ = '='; + } + *pOut++ = '\0'; + + // Return the encoded data length + *pEncodedDataLen = (int32_t)(pOut - (uint8_t*)*ppEncodedData); + + // Success + retStatus = CASA_STATUS_SUCCESS; + } + else + { + DbgTrace(0, "krb5_token -EncodeData- Buffer allocation failure\n", 0); + + retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, + CASA_FACILITY_KRB5TOKEN, + CASA_STATUS_INSUFFICIENT_RESOURCES); + } + + DbgTrace(3, "krb5_token -EncodeData- End, retStatus = %08X\n", retStatus); + + return retStatus; +} + + +//++======================================================================= +CasaStatus +DecodeData( + IN const char *pEncodedData, + IN const int32_t encodedDataLen, // Does not include NULL terminator + INOUT void **ppData, + INOUT int32_t *pDataLen) +// +// Arguments: +// +// Returns: +// +// Description: +// +// L2 +//=======================================================================-- +{ + CasaStatus retStatus; + int i, j; + int decodedSize; + + DbgTrace(3, "krb5_token -DecodeData- Start\n", 0); + + // Determine the decoded size + for (i = 0, j = 0; i < encodedDataLen; i++) + if (g_Expand64[((uint8_t*) pEncodedData)[i]] < 64) + j++; + decodedSize = (j * 3 + 3) / 4; + + // Allocate buffer to hold the decoded data + *ppData = malloc(decodedSize); + if (*ppData) + { + bool endReached = false; + uint8_t c0, c1, c2, c3; + uint8_t *p, *q; + + // Initialize parameters that will be used during the decode operation + c0 = c1 = c2 = c3 = 0; + p = (uint8_t*) pEncodedData; + q = (uint8_t*) *ppData; + + // Decode the data + // + // Loop through the data, piecing back information. Any newlines, and/or + // carriage returns need to be skipped. + while (j > 4) + { + while ((64 == g_Expand64[*p]) && (('\n' == *p) || ('\r' == *p))) + p++; + if (64 == g_Expand64[*p]) + { + endReached = true; + break; + } + c0 = *(p++); + + while ((64 == g_Expand64[*p]) && (('\n' == *p) || ('\r' == *p))) + p++; + if (64 == g_Expand64[*p]) + { + *(q++) = (uint8_t)(g_Expand64[c0] << 2); + j--; + endReached = true; + break; + } + c1 = *(p++); + + while ((64 == g_Expand64[*p]) && (('\n' == *p) || ('\r' == *p))) + p++; + if (64 == g_Expand64[*p]) + { + *(q++) = (uint8_t)(g_Expand64[c0] << 2 | g_Expand64[c1] >> 4); + *(q++) = (uint8_t)(g_Expand64[c1] << 4); + j -= 2; + endReached = true; + break; + } + c2 = *(p++); + + while ((64 == g_Expand64[*p]) && (('\n' == *p) || ('\r' == *p))) + p++; + if (64 == g_Expand64[*p]) + { + *(q++) = (uint8_t)(g_Expand64[c0] << 2 | g_Expand64[c1] >> 4); + *(q++) = (uint8_t)(g_Expand64[c1] << 4 | g_Expand64[c2] >> 2); + *(q++) = (uint8_t)(g_Expand64[c2] << 6); + j -= 3; + endReached = true; + break; + } + c3 = *(p++); + + *(q++) = (uint8_t)(g_Expand64[c0] << 2 | g_Expand64[c1] >> 4); + *(q++) = (uint8_t)(g_Expand64[c1] << 4 | g_Expand64[c2] >> 2); + *(q++) = (uint8_t)(g_Expand64[c2] << 6 | g_Expand64[c3]); + j -= 4; + } + if (!endReached) + { + if (j > 1) + *(q++) = (uint8_t)(g_Expand64[*p] << 2 | g_Expand64[p[1]] >> 4); + if (j > 2) + *(q++) = (uint8_t)(g_Expand64[p[1]] << 4 | g_Expand64[p[2]] >> 2); + if (j > 3) + *(q++) = (uint8_t)(g_Expand64[p[2]] << 6 | g_Expand64[p[3]]); + } + + // Return the length of the decoded data + *pDataLen = (int32_t)(q - (uint8_t*)*ppData); + + // Success + retStatus = CASA_STATUS_SUCCESS; + } + else + { + DbgTrace(0, "krb5_token -DecodeData- Buffer allocation failure\n", 0); + + retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, + CASA_FACILITY_KRB5TOKEN, + CASA_STATUS_INSUFFICIENT_RESOURCES); + } + + DbgTrace(3, "krb5_token -DecodeData- End, retStatus = %08X\n", retStatus); + + return retStatus; +} + + +//++======================================================================= +//++======================================================================= +//++======================================================================= + diff --git a/auth_token/krb5_token/linux/verify.c b/auth_token/krb5_token/linux/verify.c new file mode 100644 index 00000000..15dbc041 --- /dev/null +++ b/auth_token/krb5_token/linux/verify.c @@ -0,0 +1,510 @@ +/*********************************************************************** + * File: verify.c + * Author: Juan Carlos Luciani (jluciani@novell.com) + * + * Abstract: Implements the VerifyAuthTokenCredentials functionality + * for the Kerberos system over GSS-API. + * + * Copyright (C) 2005 Novell, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; version 2.1 + * of the License. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * To contact Novell about this file by physical or electronic mail, + * you may find current contact information at www.novell.com. + ***********************************************************************/ + +//===[ Include files ]===================================================== + +#include "internal.h" + +//===[ Type definitions ]================================================== + +typedef struct _CacheCred +{ + LIST_ENTRY listEntry; + char *pName; + int32_t nameLen; + int32_t refCount; + gss_cred_id_t gssCred; + +} CacheCred; + +//===[ Function prototypes ]=============================================== + +//===[ Global variables ]================================================== + +// Server Credential List and syncronizing mutex +static +LIST_ENTRY g_serverCredListHead = {&g_serverCredListHead, &g_serverCredListHead}; + +static +pthread_mutex_t g_serverCredMutex = PTHREAD_MUTEX_INITIALIZER; + + +//++======================================================================= +static +CasaStatus +GetServiceCredentials( + IN const ConfigIf *pServiceConfigIf, + INOUT gss_cred_id_t **ppServerCreds) +// +// Arguments: +// +// Returns: +// +// Abstract: +// +// Notes: +// +// L2 +//=======================================================================-- +{ + CasaStatus retStatus; + gss_OID_set_desc mechOidSet; + gss_OID_set desiredMechs; + gss_name_t gssServiceName; + OM_uint32 gssMajStat; + OM_uint32 gssMinStat; + gss_buffer_desc gssBuffer; + char *pKrbServiceName; + + + DbgTrace(2, "krb5_token -GetServiceCredentials- Start\n", 0); + + // Obtain the Krb Service Principal Name configured for the service + pKrbServiceName = pServiceConfigIf->getEntryValue(pServiceConfigIf, "KerberosPrincipal"); + if (pKrbServiceName) + { + LIST_ENTRY *pListEntry; + CacheCred *pCacheCred = NULL; + int32_t krbServiceNameLen = strlen(pKrbServiceName); + + // Gain exclusive access to our server credential cache + pthread_mutex_lock(&g_serverCredMutex); + + // Look if we already have the credentials in our cash + pListEntry = g_serverCredListHead.Flink; + while (pListEntry != &g_serverCredListHead) + { + // Get pointer to the current entry + pCacheCred = CONTAINING_RECORD(pListEntry, CacheCred, listEntry); + + // Check if this is the credential that we need + if (pCacheCred->nameLen == krbServiceNameLen + && memcmp(pKrbServiceName, pCacheCred->pName, krbServiceNameLen) == 0) + { + // This is the credential that we need, stop looking. + break; + } + else + { + // This is not the credential that we are looking for + pCacheCred = NULL; + } + + // Advance to the next entry + pListEntry = pListEntry->Flink; + } + + // Proceed based on whether or not a credential was found + if (pCacheCred) + { + // Credential found in the cache, increment its reference count + // and return it to the caller. + pCacheCred->refCount ++; + *ppServerCreds = &pCacheCred->gssCred; + + // Success + retStatus = CASA_STATUS_SUCCESS; + } + else + { + // Needed credential not found in the cache, create a cache entry. + pCacheCred = malloc(sizeof(*pCacheCred)); + if (pCacheCred) + { + // Initialize the refCount on the entry + pCacheCred->refCount = 0; + + // Allocate buffer to contain the service name within the cache entry + pCacheCred->pName = malloc(krbServiceNameLen + 1); + if (pCacheCred->pName) + { + // Save the service name within the entry + strcpy(pCacheCred->pName, pKrbServiceName); + pCacheCred->nameLen = krbServiceNameLen; + + // Determine the desired mechanism + if (g_mechOid != GSS_C_NULL_OID) + { + desiredMechs = &mechOidSet; + mechOidSet.count = 1; + mechOidSet.elements = g_mechOid; + } + else + { + desiredMechs = GSS_C_NULL_OID_SET; + } + + // Import the service name into something that GSS-API can understand + // based on its format. + gssBuffer.value = pKrbServiceName; + gssBuffer.length = krbServiceNameLen + 1; + if (strchr(pKrbServiceName, '@') != NULL) + { + // The name is of the form "servicename@hostname" + gssMajStat = gss_import_name(&gssMinStat, + &gssBuffer, + (gss_OID) GSS_C_NT_HOSTBASED_SERVICE, + &gssServiceName); + } + else + { + // The name is of the form "servicename" + gssMajStat = gss_import_name(&gssMinStat, + &gssBuffer, + (gss_OID) GSS_C_NT_USER_NAME, + &gssServiceName); + } + if (gssMajStat == GSS_S_COMPLETE) + { + // Now attempt to acquire the credentials + gssMajStat = gss_acquire_cred(&gssMinStat, + gssServiceName, + 0, + desiredMechs, + GSS_C_ACCEPT, + &pCacheCred->gssCred, + NULL, + NULL); + if (gssMajStat == GSS_S_COMPLETE) + { + // Success + retStatus = CASA_STATUS_SUCCESS; + } + else + { + DbgTrace(0, "krb5_token -GetServiceCredentials- Error acquiring service credential\n", 0); + LogGssStatuses("acquiring credential", gssMajStat, gssMinStat); + + retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, + CASA_FACILITY_KRB5TOKEN, + CASA_STATUS_CONFIGURATION_ERROR); + } + + // Release the imported name + gss_release_name(&gssMinStat, &gssServiceName); + } + else + { + DbgTrace(0, "krb5_token -GetServiceCredentials- Error importing service name\n", 0); + LogGssStatuses("importing service name", gssMajStat, gssMinStat); + + retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, + CASA_FACILITY_KRB5TOKEN, + CASA_STATUS_OBJECT_NOT_FOUND); + } + + // Check if we were successful at obtaining the credentials + if (CASA_SUCCESS(retStatus)) + { + // Insert the entry in the cache, increment its reference count, + // and return it to the caller. + InsertTailList(&g_serverCredListHead, &pCacheCred->listEntry); + pCacheCred->refCount ++; + *ppServerCreds = &pCacheCred->gssCred; + } + else + { + // Failed, free the allocated buffers + free(pCacheCred->pName); + free(pCacheCred); + } + } + else + { + DbgTrace(0, "krb5_token -GetServiceCredentials- Unable to allocate buffer\n", 0); + + // Free buffer allocated for cache entry + free(pCacheCred); + + retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, + CASA_FACILITY_KRB5TOKEN, + CASA_STATUS_INSUFFICIENT_RESOURCES); + } + } + else + { + DbgTrace(0, "krb5_token -GetServiceCredentials- Unable to allocate buffer\n", 0); + + retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, + CASA_FACILITY_KRB5TOKEN, + CASA_STATUS_INSUFFICIENT_RESOURCES); + } + } + + // Release exclusive access to our server credential cache + pthread_mutex_unlock(&g_serverCredMutex); + + // Free the krb service principal name + free(pKrbServiceName); + } + else + { + DbgTrace(0, "krb5_token -GetServiceCredentials- No Kerberos principal name configured\n", 0); + retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, + CASA_FACILITY_KRB5TOKEN, + CASA_STATUS_CONFIGURATION_ERROR); + } + + DbgTrace(2, "krb5_token -GetServiceCredentials- End, retStatus = %08X\n", retStatus); + + return retStatus; +} + + +//++======================================================================= +static +void +ReleaseServiceCredentials( + IN gss_cred_id_t *pServerCreds) +// +// Arguments: +// +// Returns: +// +// Abstract: +// +// Notes: +// +// L2 +//=======================================================================-- +{ + CacheCred *pCacheCred = CONTAINING_RECORD(pServerCreds, CacheCred, gssCred); + + DbgTrace(2, "krb5_token -ReleaseServiceCredentials- Start\n", 0); + + // Gain exclusive access to our server credential cache + pthread_mutex_lock(&g_serverCredMutex); + + // Decrement the reference count on the entry + pCacheCred->refCount --; + + // Release exclusive access to our server credential cache + pthread_mutex_unlock(&g_serverCredMutex); + + DbgTrace(2, "krb5_token -ReleaseServiceCredentials- End\n", 0); +} + + +//++======================================================================= +CasaStatus SSCS_CALL +Krb5AuthTokenIf_ValidateAuthTokenCredentials( + IN const void *pIfInstance, + IN const ConfigIf *pServiceConfigIf, + IN const char *pUserName, + IN const int userNameLen, + IN const char *pTokenBuf, + IN const int tokenBufLen) +// +// Arguments: +// pIfInstance - +// Pointer to interface object. +// +// pServiceConfigIf - +// Pointer to service config object to which the client is trying to +// authenticate. +// +// pUserName - +// Pointer to string with the username that is being +// authenticated to the service. The length of the name +// is specified by the pUserNameLen parameter. Note that +// the string does not need to be NULL terminated. +// +// userNameLen - +// Length of the user name contained within the buffer +// pointed at by pUserNameBuf (Does not include the NULL +// terminator). If this parameter is set to -1 then the +// function assumes that the username string is NULL +// terminated. +// +// pTokenBuf - +// Pointer to buffer that will receive the authentication +// token. The length of this buffer is specified by the +// pTokenBufLen parameter. Note that the the authentication +// token will be in the form of a NULL terminated string. +// +// tokenBufLen - +// Length of the data contained within the buffer pointed +// at by pTokenBuf. (Does not include the NULL +// terminator). If this parameter is set to -1 then the +// function assumes that the username string is NULL +// terminated. +// +// Returns: +// Casa status. +// +// Description: +// Validates authentication token credentials. +// +// L2 +//=======================================================================-- +{ + CasaStatus retStatus; + gss_cred_id_t *pServerCreds; + + + DbgTrace(1, "krb5_token -Krb5AuthTokenIf_ValidateAuthTokenCredentials- Start\n", 0); + + // Validate input parameters + if (pIfInstance == NULL + || pServiceConfigIf == NULL + || pUserName == NULL + || userNameLen == 0 + || pTokenBuf == NULL + || tokenBufLen == 0) + { + DbgTrace(0, "krb5_token -Krb5AuthTokenIf_ValidateAuthTokenCredentials- Invalid input parameter\n", 0); + + retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, + CASA_FACILITY_KRB5TOKEN, + CASA_STATUS_INVALID_PARAMETER); + goto exit; + } + + // Get server credentials + retStatus = GetServiceCredentials(pServiceConfigIf, &pServerCreds); + if (CASA_SUCCESS(retStatus)) + { + gss_buffer_desc gssRecvToken; + + // Server credentials obtained, now decode the incoming token. + retStatus = DecodeData(pTokenBuf, + /*pTokenBuf[tokenBufLen] == '\0' ? tokenBufLen - 1 : tokenBufLen,*/ tokenBufLen + 1, + &gssRecvToken.value, + (int32_t*) &gssRecvToken.length); + if (CASA_SUCCESS(retStatus)) + { + OM_uint32 gssMajStat; + OM_uint32 gssMinStat; + gss_ctx_id_t gssContext = GSS_C_NO_CONTEXT; + gss_buffer_desc gssSendToken = {0}; + OM_uint32 gssRetFlags; + gss_name_t gssClient; + gss_OID gssDoid; + + // Process token received from client + gssMajStat = gss_accept_sec_context(&gssMinStat, + &gssContext, + *pServerCreds, + &gssRecvToken, + GSS_C_NO_CHANNEL_BINDINGS, + &gssClient, + &gssDoid, + &gssSendToken, + &gssRetFlags, + NULL, + NULL); + if (gssMajStat == GSS_S_COMPLETE) + { + gss_buffer_desc gssDisplayName; + gss_OID gssNameType; + gssMajStat = gss_display_name(&gssMinStat, gssClient, &gssDisplayName, &gssNameType); + if (gssMajStat == GSS_S_COMPLETE) + { + int actualUserNameLen; + + // Determine the name of the user name provided by the caller + if (userNameLen == -1) + actualUserNameLen = strlen(pUserName); + else + actualUserNameLen = userNameLen; + + // Verify that the user names match + if (actualUserNameLen == gssDisplayName.length + && strncmp(pUserName, gssDisplayName.value, actualUserNameLen) == 0) + { + // The names match, credentials validated. + retStatus = CASA_STATUS_SUCCESS; + } + else + { + DbgTrace(0, "krb5_token -Krb5AuthTokenIf_ValidateAuthTokenCredentials- The user names do not match\n", 0); + retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, + CASA_FACILITY_KRB5TOKEN, + CASA_STATUS_AUTHENTICATION_FAILURE); + } + + // Free the client display name + gss_release_buffer(&gssMinStat, &gssDisplayName); + } + else + { + DbgTrace(0, "krb5_token -Krb5AuthTokenIf_ValidateAuthTokenCredentials- Error obtaining display name\n", 0); + LogGssStatuses("obtaining display name", gssMajStat, gssMinStat); + + retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, + CASA_FACILITY_KRB5TOKEN, + CASA_STATUS_UNSUCCESSFUL); + } + } + else + { + DbgTrace(1, "krb5_token -Krb5AuthTokenIf_ValidateAuthTokenCredentials- gss_accept_sec_context error\n", 0); + LogGssStatuses("accepting sec context", gssMajStat, gssMinStat); + + retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, + CASA_FACILITY_KRB5TOKEN, + CASA_STATUS_AUTHENTICATION_FAILURE); + } + + // Free send token if necessary + if (gssSendToken.length != 0) + { + DbgTrace(0, "krb5_token -Krb5AuthTokenIf_ValidateAuthTokenCredentials- Un-expected send token returned by gss_accept_sec_context\n", 0); + gss_release_buffer(&gssMinStat, &gssSendToken); + } + + // Free context if necessary + if (gssContext != GSS_C_NO_CONTEXT) + gss_delete_sec_context(&gssMinStat, &gssContext, GSS_C_NO_BUFFER); + + // Free the buffer associated with the token + free(gssRecvToken.value); + } + else + { + DbgTrace(0, "krb5_token -Krb5AuthTokenIf_ValidateAuthTokenCredentials- Token decode failure\n", 0); + } + + ReleaseServiceCredentials(pServerCreds); + } + else + { + DbgTrace(0, "krb5_token -Krb5AuthTokenIf_ValidateAuthTokenCredentials- Failed to get the server credentials\n", 0); + } + +exit: + + DbgTrace(1, "krb5_token -Krb5AuthTokenIf_ValidateAuthTokenCredentials- End, retStatus = %08X\n", retStatus); + + return retStatus; +} + + +//++======================================================================= +//++======================================================================= +//++======================================================================= + diff --git a/auth_token/linux/Makefile b/auth_token/linux/Makefile new file mode 100644 index 00000000..0a90ba28 --- /dev/null +++ b/auth_token/linux/Makefile @@ -0,0 +1,20 @@ +# +# configure environment +# +TARGET = libcasa_auth_token +include global.mak +include defaults.$(PLAT) +include rules.mak + +BIN_NAME = $(TARGET)$(xtra).$(BIN) +LIB_NAME = $(TARGET)$(xtra).$(LIB) + +# +# target object and source files +# +include objs.$(PLAT) + +# +# targets +# +include target.cl diff --git a/auth_token/linux/auth_token.c b/auth_token/linux/auth_token.c new file mode 100644 index 00000000..b8404e3b --- /dev/null +++ b/auth_token/linux/auth_token.c @@ -0,0 +1,546 @@ +/*********************************************************************** + * File: auth_token.c + * Author: Juan Carlos Luciani (jluciani@novell.com) + * + * Abstract: Implements the CASA Authentication Token credentials API. + * + * Copyright (C) 2005 Novell, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; version 2.1 + * of the License. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * To contact Novell about this file by physical or electronic mail, + * you may find current contact information at www.novell.com. + ***********************************************************************/ + +//===[ Include files ]===================================================== + +#include "internal.h" + +//===[ Type definitions ]================================================== + +// +// AuthModule definition +// +typedef struct _AuthModule +{ + LIST_ENTRY listEntry; + char *pAuthTypeName; + int authTypeNameLen; + void *libHandle; + AuthTokenIf *pAuthTokenIf; + +} AuthModule, *PAuthModule; + +//===[ Function prototypes ]=============================================== + +//===[ Global variables ]================================================== + +// Debug Level +int DebugLevel = 1; + +// AuthModule List and syncronizing mutex +static +LIST_ENTRY g_authModuleListHead = {&g_authModuleListHead, &g_authModuleListHead}; + +static +pthread_mutex_t g_authModuleMutex = PTHREAD_MUTEX_INITIALIZER; + + +//++======================================================================= +static +CasaStatus +GetAuthTokenInterface( + IN const char *pAuthTypeName, + INOUT AuthTokenIf **ppAuthTokenIf) +// +// Arguments: +// +// Returns: +// +// Abstract: +// +// Notes: +// +// Environment: +// +// L2 +//=======================================================================-- +{ + CasaStatus retStatus; + ConfigIf *pModuleConfigIf; + + + DbgTrace(2, "auth_token -GetAuthTokenInterface- Start\n", 0); + + // Get the configuration for the module + retStatus = GetConfigInterface("/etc/opt/novell/CASA/authtoken.d/modules.d", + pAuthTypeName, + &pModuleConfigIf); + if (CASA_SUCCESS(retStatus) + && CasaStatusCode(retStatus) != CASA_STATUS_OBJECT_NOT_FOUND) + { + LIST_ENTRY *pListEntry; + AuthModule *pAuthModule = NULL; + int32_t authTypeNameLen = strlen(pAuthTypeName); + + // Gain exclusive access to our mutex + pthread_mutex_lock(&g_authModuleMutex); + + // Look if we already have the module in our list + pListEntry = g_authModuleListHead.Flink; + while (pListEntry != &g_authModuleListHead) + { + // Get pointer to the current entry + pAuthModule = CONTAINING_RECORD(pListEntry, AuthModule, listEntry); + + // Check if this is the module that we need + if (pAuthModule->authTypeNameLen == authTypeNameLen + && memcmp(pAuthTypeName, pAuthModule->pAuthTypeName, authTypeNameLen) == 0) + { + // This is the module that we need, stop looking. + break; + } + else + { + // This is not the module that we are looking for + pAuthModule = NULL; + } + + // Advance to the next entry + pListEntry = pListEntry->Flink; + } + + // Proceed based on whether or not a module was found + if (pAuthModule) + { + // Module found in our list, provide the caller with its AuthTokenIf + // instance after we have incremented its reference count. + pAuthModule->pAuthTokenIf->addReference(pAuthModule->pAuthTokenIf); + *ppAuthTokenIf = pAuthModule->pAuthTokenIf; + + // Success + retStatus = CASA_STATUS_SUCCESS; + } + else + { + // Needed module not found in our list, create an entry. + pAuthModule = malloc(sizeof(*pAuthModule)); + if (pAuthModule) + { + // Allocate buffer to contain the authentication type name within the module entry + pAuthModule->pAuthTypeName = malloc(authTypeNameLen + 1); + if (pAuthModule->pAuthTypeName) + { + char *pLibraryName; + + // Initialize the library handle field + pAuthModule->libHandle = NULL; + + // Save the auth type name within the entry + strcpy(pAuthModule->pAuthTypeName, pAuthTypeName); + pAuthModule->authTypeNameLen = authTypeNameLen; + + // Obtain the name of the library that we must load + pLibraryName = pModuleConfigIf->getEntryValue(pModuleConfigIf, "LibraryName"); + if (pLibraryName) + { + // Load the library + pAuthModule->libHandle = dlopen(pLibraryName, RTLD_LAZY); + if (pAuthModule->libHandle) + { + PFN_GetAuthTokenIfRtn pGetAuthTokenIfRtn; + + // Library has been loaded, now get a pointer to its GetAuthTokenInterface routine + pGetAuthTokenIfRtn = dlsym(pAuthModule->libHandle, GET_AUTH_TOKEN_INTERFACE_RTN_SYMBOL); + if (pGetAuthTokenIfRtn) + { + // Now, obtain the modules AuthTokenIf. + retStatus = (pGetAuthTokenIfRtn)(pModuleConfigIf, &pAuthModule->pAuthTokenIf); + } + else + { + DbgTrace(0, "auth_token -GetAuthTokenInterface- dlsym error = %s\n", dlerror()); + retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, + CASA_FACILITY_AUTHTOKEN, + CASA_STATUS_LIBRARY_LOAD_FAILURE); + } + } + else + { + DbgTrace(0, "auth_token -GetAuthTokenInterface- dlopen error = %s\n", dlerror()); + retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, + CASA_FACILITY_AUTHTOKEN, + CASA_STATUS_UNSUCCESSFUL); + } + + // Free the buffer holding the library name + free(pLibraryName); + } + else + { + DbgTrace(0, "auth_token -GetAuthTokenInterface- Library name not configured\n", 0); + retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, + CASA_FACILITY_AUTHTOKEN, + CASA_STATUS_CONFIGURATION_ERROR); + } + + // Check if we were successful at obtaining the AuthTokenIf instance for the + // module. + if (CASA_SUCCESS(retStatus)) + { + // Insert the entry in the list, provide the caller with its AuthTokenIf + // instance after we have incremented its reference count. + InsertTailList(&g_authModuleListHead, &pAuthModule->listEntry); + pAuthModule->pAuthTokenIf->addReference(pAuthModule->pAuthTokenIf); + *ppAuthTokenIf = pAuthModule->pAuthTokenIf; + } + else + { + // Failed, free resources. + free(pAuthModule->pAuthTypeName); + if (pAuthModule->libHandle) + dlclose(pAuthModule->libHandle); + free(pAuthModule); + } + } + else + { + DbgTrace(0, "auth_token -GetAuthTokenInterface- Unable to allocate buffer\n", 0); + + // Free buffer allocated for entry + free(pAuthModule); + + retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, + CASA_FACILITY_AUTHTOKEN, + CASA_STATUS_INSUFFICIENT_RESOURCES); + } + } + else + { + DbgTrace(0, "auth_token -GetAuthTokenInterface- Unable to allocate buffer\n", 0); + retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, + CASA_FACILITY_AUTHTOKEN, + CASA_STATUS_INSUFFICIENT_RESOURCES); + } + } + + // Release exclusive access to our mutex + pthread_mutex_unlock(&g_authModuleMutex); + + // Release config interface instance + pModuleConfigIf->releaseReference(pModuleConfigIf); + } + else + { + DbgTrace(0, "auth_token -GetAuthTokenInterface- Unable to obtain config interface\n", 0); + retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, + CASA_FACILITY_AUTHTOKEN, + CASA_STATUS_CONFIGURATION_ERROR); + } + + DbgTrace(2, "auth_token -GetAuthTokenInterface- End, retStatus = %08X\n", retStatus); + + return retStatus; +} + + +//++======================================================================= +CasaStatus SSCS_CALL +GetAuthTokenCredentials( + IN const char *pServiceName, + INOUT const char *pUserNameBuf, + INOUT int *pUserNameBufLen, + INOUT const char *pTokenBuf, + INOUT int *pTokenBufLen) +// +// Arguments: +// pServiceName - +// Pointer to NULL terminated string that contains the +// name of the service to which the client is trying to +// authenticate. +// +// pUserNameBuf - +// Pointer to buffer that will receive a string with the +// username that should used when authenticating to the +// service. The length of this buffer is specified by the +// pUserNameBufLen parameter. Note that the string +// returned will be NULL terminated. +// +// pUserNameBufLen - +// Pointer to integer that contains the length of the +// buffer pointed at by pUserNameBuf. Upon return of the +// function, the integer will contain the actual length +// of the username string (including the NULL terminator) +// if the function successfully completes or the buffer +// length required if the function fails because the buffer +// pointed at by either pUserNameBuf or pTokenBuf is not +// large enough. +// +// pTokenBuf - +// Pointer to buffer that will receive the authentication +// token. The length of this buffer is specified by the +// pTokenBufLen parameter. Note that the the authentication +// token will be in the form of a NULL terminated string. +// +// pTokenBufLen - +// Pointer to integer that contains the length of the +// buffer pointed at by pTokenBuf. Upon return of the +// function, the integer will contain the actual length +// of the authentication token if the function successfully +// completes or the buffer length required if the function +// fails because the buffer pointed at by either pUserNameBuf +// or pTokenBuf is not large enough. +// +// Returns: +// Casa Status +// +// Description: +// Get authentication token credentials to authenticate user to specified +// service. +// +// L2 +//=======================================================================-- +{ + CasaStatus retStatus; + ConfigIf *pServiceConfigIf; + AuthTokenIf *pAuthTokenIf; + + + DbgTrace(1, "auth_token -GetAuthTokenCredentials- Start\n", 0); + + // Validate input parameters + if (pServiceName == NULL + || pUserNameBufLen == NULL + || (pUserNameBuf == NULL && *pUserNameBufLen != 0) + || pTokenBufLen == NULL + || (pTokenBuf == NULL && *pTokenBufLen != 0)) + { + DbgTrace(0, "auth_token -GetAuthTokenCredentials- Invalid input parameter\n", 0); + + retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, + CASA_FACILITY_AUTHTOKEN, + CASA_STATUS_INVALID_PARAMETER); + goto exit; + } + + // Check if we have a configuration entry for the service + retStatus = GetConfigInterface("/etc/opt/novell/CASA/authtoken.d/services.d", + pServiceName, + &pServiceConfigIf); + if (CASA_SUCCESS(retStatus) + && CasaStatusCode(retStatus) != CASA_STATUS_OBJECT_NOT_FOUND) + { + char *pAuthType; + + // Obtain the configured authentication type for the service + pAuthType = pServiceConfigIf->getEntryValue(pServiceConfigIf, "AuthType"); + if (pAuthType) + { + // Obtain the appropriate token interface for the authentication type + retStatus = GetAuthTokenInterface(pAuthType, + &pAuthTokenIf); + if (CASA_SUCCESS(retStatus)) + { + // We found a provider for the service, query it for credentials. + retStatus = pAuthTokenIf->getAuthTokenCredentials(pAuthTokenIf, + pServiceConfigIf, + pUserNameBuf, + pUserNameBufLen, + pTokenBuf, + pTokenBufLen); + + // Release token interface + pAuthTokenIf->releaseReference(pAuthTokenIf); + } + else + { + // No authentication token interface available for authentication type + DbgTrace(0, "auth_token -GetAuthTokenCredentials- Failed to obtain authentication token interface\n", 0); + } + + // Free the buffer holding the authentication type string + free(pAuthType); + } + else + { + DbgTrace(0, "auth_token -GetAuthTokenCredentials- Authentication type not configured\n", 0); + retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, + CASA_FACILITY_AUTHTOKEN, + CASA_STATUS_CONFIGURATION_ERROR); + } + + // Release service config interface + pServiceConfigIf->releaseReference(pServiceConfigIf); + } + else + { + // We are not providing authentication services for the service + DbgTrace(1, "auth_token -GetAuthTokenCredentials- Service not configured\n", 0); + } + +exit: + + DbgTrace(1, "auth_token -GetAuthTokenCredentials- End, retStatus = %08X\n", retStatus); + + return retStatus; +} + + +//++======================================================================= +CasaStatus SSCS_CALL +ValidateAuthTokenCredentials( + IN const char *pServiceName, + IN const char *pUserName, + IN const int userNameLen, + IN const char *pTokenBuf, + IN const int tokenBufLen) +// +// Arguments: +// pServiceName - +// Pointer to NULL terminated string that contains the +// name of the service to which the client is trying to +// authenticate. +// +// pUserName - +// Pointer to string with the username that is being +// authenticated to the service. The length of the name +// is specified by the pUserNameLen parameter. Note that +// the string does not need to be NULL terminated. +// +// userNameLen - +// Length of the user name contained within the buffer +// pointed at by pUserNameBuf (Does not include the NULL +// terminator). If this parameter is set to -1 then the +// function assumes that the username string is NULL +// terminated. +// +// pTokenBuf - +// Pointer to buffer that will receive the authentication +// token. The length of this buffer is specified by the +// pTokenBufLen parameter. Note that the the authentication +// token will be in the form of a NULL terminated string. +// +// tokenBufLen - +// Length of the data contained within the buffer pointed +// at by pTokenBuf. +// +// Returns: +// Casa status. +// +// Description: +// Validates authentication token credentials. +// +// L2 +//=======================================================================-- +{ + CasaStatus retStatus; + ConfigIf *pServiceConfigIf; + AuthTokenIf *pAuthTokenIf; + + + DbgTrace(1, "auth_token -ValidateAuthTokenCredentials- Start\n", 0); + + // Validate input parameters + if (pServiceName == NULL + || pUserName == NULL + || userNameLen == 0 + || pTokenBuf == NULL + || tokenBufLen == 0) + { + DbgTrace(0, "auth_token -ValidateAuthTokenCredentials- Invalid input parameter\n", 0); + + retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, + CASA_FACILITY_AUTHTOKEN, + CASA_STATUS_INVALID_PARAMETER); + goto exit; + } + + // Check if we have a configuration entry for the service + retStatus = GetConfigInterface("/etc/opt/novell/CASA/authtoken.d/services.d", + pServiceName, + &pServiceConfigIf); + if (CASA_SUCCESS(retStatus)) + { + // Check if the configuration entry was not found + if (CasaStatusCode(retStatus) != CASA_STATUS_OBJECT_NOT_FOUND) + { + char *pAuthType; + + // Obtain the configured authentication type for the service + pAuthType = pServiceConfigIf->getEntryValue(pServiceConfigIf, "AuthType"); + if (pAuthType) + { + // Obtain the appropriate token interface for the authentication type + retStatus = GetAuthTokenInterface(pAuthType, + &pAuthTokenIf); + if (CASA_SUCCESS(retStatus)) + { + // We found a provider for the service, validate the credentials. + retStatus = pAuthTokenIf->validateAuthTokenCredentials(pAuthTokenIf, + pServiceConfigIf, + pUserName, + userNameLen, + pTokenBuf, + tokenBufLen); + + // Release token interface + pAuthTokenIf->releaseReference(pAuthTokenIf); + } + else + { + // No authentication token interface available for authentication type + DbgTrace(0, "auth_token -ValidateAuthTokenCredentials- Failed to obtain authentication token interface\n", 0); + } + + // Free the buffer holding the authentication type string + free(pAuthType); + } + else + { + DbgTrace(0, "auth_token -ValidateAuthTokenCredentials- Authentication type not configured\n", 0); + retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, + CASA_FACILITY_AUTHTOKEN, + CASA_STATUS_CONFIGURATION_ERROR); + } + + // Release service config interface + pServiceConfigIf->releaseReference(pServiceConfigIf); + } + else + { + // We need to return an error + DbgTrace(0, "auth_token -ValidateAuthTokenCredentials- Service not configured\n", 0); + retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, + CASA_FACILITY_AUTHTOKEN, + CASA_STATUS_CONFIGURATION_ERROR); + } + } + else + { + DbgTrace(0, "auth_token -ValidateAuthTokenCredentials- Error obtaining service configuration\n", 0); + } + +exit: + + DbgTrace(1, "auth_token -ValidateAuthTokenCredentials- End, retStatus = %08X\n", retStatus); + + return retStatus; +} + + +//++======================================================================= +//++======================================================================= +//++======================================================================= + diff --git a/auth_token/linux/config.c b/auth_token/linux/config.c new file mode 100644 index 00000000..5f340f1f --- /dev/null +++ b/auth_token/linux/config.c @@ -0,0 +1,700 @@ +/*********************************************************************** + * File: config.c + * Author: Juan Carlos Luciani (jluciani@novell.com) + * + * Abstract: Implements the Configuration Interface. + * + * Copyright (C) 2005 Novell, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; version 2.1 + * of the License. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * To contact Novell about this file by physical or electronic mail, + * you may find current contact information at www.novell.com. + ***********************************************************************/ + +//===[ Include files ]===================================================== + +#include "internal.h" + +//===[ Type definitions ]================================================== + +// +// Config Key object +// +typedef struct _ConfigKey +{ + LIST_ENTRY listEntry; + char *pKeyName; + int keyNameLen; + char *pValue; + int valueLen; + +} ConfigKey, *pConfigKey; + +// +// Config Interface instance data +// +typedef struct _ConfigIfInstance +{ + LIST_ENTRY listEntry; + int refCount; + char *pConfigFolder; + int configFolderLen; + char *pConfigName; + int configNameLen; + LIST_ENTRY configKeyListHead; + ConfigIf configIf; + +} ConfigIfInstance, *PConfigIfInstance; + +//===[ Function prototypes ]=============================================== + +//===[ Global variables ]================================================== + +// ConfigIf synchronization mutex and variables +static +pthread_mutex_t g_configIfMutex = PTHREAD_MUTEX_INITIALIZER; + +static +LIST_ENTRY g_configIfListHead = {&g_configIfListHead, &g_configIfListHead}; + +static +int g_numConfigIfObjs = 0; + + +//++======================================================================= +static void +RemoveWhiteSpaceFromTheEnd( + IN const char *pInString) +// +// Arguments: +// +// Returns: +// +// Abstract: +// +// Notes: +// +// L2 +//=======================================================================-- +{ + char *pLineEnd = (char*) pInString + strlen(pInString) - 1; + + + DbgTrace(3, "auth_token -RemoveWhiteSpaceFromTheEnd- Start\n", 0); + + while (pLineEnd != pInString) + { + if (*pLineEnd == '\n' + || *pLineEnd == ' ' + || *pLineEnd == '\t') + { + // Strike this character + *pLineEnd = '\0'; + pLineEnd --; + } + else + { + // Found a non-white character + break; + } + } + + DbgTrace(3, "auth_token -RemoveWhiteSpaceFromTheEnd- End\n", 0); +} + + +//++======================================================================= +static char* +SkipWhiteSpace( + IN const char *pInString) +// +// Arguments: +// +// Returns: +// +// Abstract: +// +// Notes: +// +// L2 +//=======================================================================-- +{ + char *pOutString = (char*) pInString; + + DbgTrace(3, "auth_token -SkipWhiteSpace- Start\n", 0); + + while (*pOutString != '\0') + { + if (*pOutString == '\n' + || *pOutString == ' ' + || *pOutString == '\t') + { + // Skip this character + pOutString ++; + } + else + { + // Found a non-white character + break; + } + } + + DbgTrace(3, "auth_token -SkipWhiteSpace- End\n", 0); + + return pOutString; +} + + +//++======================================================================= +static char* +SkipNonWhiteSpace( + IN const char *pInString) +// +// Arguments: +// +// Returns: +// +// Abstract: +// +// Notes: +// +// L2 +//=======================================================================-- +{ + char *pOutString; + + DbgTrace(3, "auth_token -SkipNonWhiteSpace- Start\n", 0); + + while (*pOutString != '\0') + { + if (*pOutString == '\n' + || *pOutString == ' ' + || *pOutString == '\t') + { + // Found a white character + break; + } + else + { + // Skip this character + pOutString ++; + } + } + + DbgTrace(3, "auth_token -SkipNonWhiteSpace- End\n", 0); + + return pOutString; +} + + +//++======================================================================= +static void +LowerCaseString( + IN char *pDestString, + IN const char *pSrcString) +// +// Arguments: +// +// Returns: +// +// Abstract: +// +// Notes: +// +// L2 +//=======================================================================-- +{ + int i; + + DbgTrace(3, "auth_token -LowerCaseString- Start\n", 0); + + // Copy the string as lower case + for (i = 0; pSrcString[i] != '\0'; i++) + { + if (isalpha(pSrcString[i])) + pDestString[i] = tolower(pSrcString[i]); + else + pDestString[i] = pSrcString[i]; + } + + // Null terminate the destination string + pDestString[i] = '\0'; + + DbgTrace(3, "auth_token -LowerCaseString- End\n", 0); +} + + +//++======================================================================= +int SSCS_CALL +ConfigIf_AddReference( + IN const void *pIfInstance) +// +// Arguments: +// pIfInstance - +// Pointer to interface object. +// +// Returns: +// Interface reference count. +// +// Description: +// Increases interface reference count. +// +// L2 +//=======================================================================-- +{ + int refCount; + ConfigIfInstance *pConfigIfInstance = CONTAINING_RECORD(pIfInstance, ConfigIfInstance, configIf); + + DbgTrace(2, "auth_token -ConfigIf_AddReference- Start\n", 0); + + // Increment the reference count on the object + pthread_mutex_lock(&g_configIfMutex); + pConfigIfInstance->refCount ++; + refCount = pConfigIfInstance->refCount; + pthread_mutex_unlock(&g_configIfMutex); + + DbgTrace(2, "auth_token -ConfigIf_AddReference- End, refCount = %08X\n", refCount); + + return refCount; +} + + +//++======================================================================= +void SSCS_CALL +ConfigIf_ReleaseReference( + IN const void *pIfInstance) +// +// Arguments: +// pIfInstance - +// Pointer to interface object. +// +// Returns: +// Nothing. +// +// Description: +// Decreases interface reference count. The interface is deallocated if +// the reference count becomes zero. +// +// L2 +//=======================================================================-- +{ + bool freeObj = false; + ConfigIfInstance *pConfigIfInstance = CONTAINING_RECORD(pIfInstance, ConfigIfInstance, configIf); + + DbgTrace(2, "auth_token -ConfigIf_ReleaseReference- Start\n", 0); + + // Decrement the reference count on the object and determine if it needs to + // be released. + pthread_mutex_lock(&g_configIfMutex); + pConfigIfInstance->refCount --; + if (pConfigIfInstance->refCount == 0) + { + // The object needs to be released, forget about it. + freeObj = true; + g_numConfigIfObjs --; + RemoveEntryList(&pConfigIfInstance->listEntry); + } + pthread_mutex_unlock(&g_configIfMutex); + + // Free object if necessary + if (freeObj) + { + // Free all of the config key objects associated with this configuration + // interface instance. + while (!IsListEmpty(&pConfigIfInstance->configKeyListHead)) + { + LIST_ENTRY *pListEntry; + ConfigKey *pConfigKey; + + // Get reference to entry at the head of the list + pListEntry = pConfigIfInstance->configKeyListHead.Flink; + pConfigKey = CONTAINING_RECORD(pListEntry, ConfigKey, listEntry); + + // Free the buffers associated with the ConfigKey + free(pConfigKey->pKeyName); + free(pConfigKey->pValue); + + // Remove the entry from the list + RemoveEntryList(&pConfigKey->listEntry); + + // Finish freeing the ConfigKey + free(pConfigKey); + } + + // Free the rest of the buffers associated with the interface instance data + free(pConfigIfInstance->pConfigFolder); + free(pConfigIfInstance->pConfigName); + free(pConfigIfInstance); + } + + DbgTrace(2, "auth_token -ConfigIf_ReleaseReference- End\n", 0); +} + + +//++======================================================================= +char* SSCS_CALL +ConfigIf__GetEntryValue( + IN const void *pIfInstance, + IN const char *pKeyName) +// +// Arguments: +// pIfInstance - +// Pointer to interface object. +// +// pKeyName - +// Pointer to NULL terminated string that contains the +// name of the key whose value is being requested. +// +// Returns: +// Pointer to NULL terminated string with value being requested or NULL. +// +// Description: +// Gets value associated with a key for the configuration object. +// +// L2 +//=======================================================================-- +{ + ConfigIfInstance *pConfigIfInstance = CONTAINING_RECORD(pIfInstance, ConfigIfInstance, configIf); + char *pValue = NULL; + LIST_ENTRY *pListEntry; + ConfigKey *pConfigKey; + int keyNameLen = strlen(pKeyName); + char *pKeyNameLowercase; + + DbgTrace(2, "auth_token -ConfigIf_GetEntryValue- Start\n", 0); + + // Allocate enough space to hold lower case version of the key name + pKeyNameLowercase = malloc(keyNameLen); + if (pKeyNameLowercase) + { + // Lower case the key name + LowerCaseString(pKeyNameLowercase, pKeyName); + + // Try to find matching ConfigKey + pListEntry = pConfigIfInstance->configKeyListHead.Flink; + while (pListEntry != &pConfigIfInstance->configKeyListHead) + { + // Get pointer to the current entry + pConfigKey = CONTAINING_RECORD(pListEntry, ConfigKey, listEntry); + + // Check if we have a match + if (pConfigKey->keyNameLen == keyNameLen + && memcmp(pKeyNameLowercase, pConfigKey->pKeyName, keyNameLen) == 0) + { + // We found it, return its value. + pValue = malloc(pConfigKey->valueLen + 1); + if (pValue) + { + strcpy(pValue, pConfigKey->pValue); + } + else + { + DbgTrace(0, "auth_token -ConfigIf_GetEntryValue- Buffer allocation failure\n", 0); + } + break; + } + + // Advance to the next entry + pListEntry = pListEntry->Flink; + } + + // Free the lower case version of the key name + free(pKeyNameLowercase); + } + else + { + DbgTrace(0, "auth_token -ConfigIf_GetEntryValue- Buffer allocation failure\n", 0); + } + + DbgTrace(2, "auth_token -ConfigIf_GetEntryValue- End, pValue = %08X\n", pValue); + + return pValue; +} + + + +//++======================================================================= +CasaStatus SSCS_CALL +GetConfigInterface( + IN const char *pConfigFolder, + IN const char *pConfigName, + INOUT ConfigIf **ppConfigIf) +// +// Arguments: +// pConfigFolder - +// Pointer to NULL terminated string that contains the name of +// the folder containing the configuration file. +// +// pConfigName - +// Pointer to NULL terminated string containing the name of the +// configuration entry. +// +// ppConfigIf - +// Pointer to variable that will receive pointer to ConfigIf +// instance. +// +// Returns: +// Casa Status +// +// Description: +// Get configuration interface to specified configuration entry. +// +// L2 +//=======================================================================-- +{ + int configFolderLen = strlen(pConfigFolder); + int configNameLen = strlen(pConfigName); + ConfigIfInstance *pConfigIfInstance; + LIST_ENTRY *pListEntry; + CasaStatus retStatus = CasaStatusBuild(CASA_SEVERITY_INFORMATIONAL, + CASA_FACILITY_AUTHTOKEN, + CASA_STATUS_OBJECT_NOT_FOUND); + + DbgTrace(2, "auth_token -GetConfigInterface- Start\n", 0); + + // Obtain exclusive access to our mutex + pthread_mutex_lock(&g_configIfMutex); + + // Check if we already have an entry in our list for the configuration + pListEntry = g_configIfListHead.Flink; + while (pListEntry != &g_configIfListHead) + { + // Get pointer to the current entry + pConfigIfInstance = CONTAINING_RECORD(pListEntry, ConfigIfInstance, listEntry); + + // Check if we have a match + if (pConfigIfInstance->configFolderLen == configFolderLen + && pConfigIfInstance->configNameLen == configNameLen + && memcmp(pConfigFolder, pConfigIfInstance->pConfigFolder, configFolderLen) == 0 + && memcmp(pConfigName, pConfigIfInstance->pConfigName, configNameLen) == 0) + { + // We found it, return the ConfigIf associated with the instance data + // after incrementing its reference count. + pConfigIfInstance->refCount ++; + *ppConfigIf = &pConfigIfInstance->configIf; + + // Success + retStatus = CASA_STATUS_SUCCESS; + break; + } + + // Advance to the next entry + pListEntry = pListEntry->Flink; + } + + // Proceed to create interface instance data for the configuration if none was found + if (retStatus != CASA_STATUS_SUCCESS) + { + char *pFilePath; + + // Build a string containing the configuration file path + pFilePath = malloc(configFolderLen + 1 + configNameLen + sizeof(".conf")); + if (pFilePath) + { + FILE *pConfigFile; + + strcpy(pFilePath, pConfigFolder); + strcat(pFilePath, "/"); + strcat(pFilePath, pConfigName); + strcat(pFilePath, ".conf"); + + // Open the configuration file for reading + pConfigFile = fopen(pFilePath, "r"); + if (pConfigFile) + { + // Opened the file, create a ConfigIfInstance object for it. + pConfigIfInstance = malloc(sizeof(*pConfigIfInstance)); + if (pConfigIfInstance) + { + // Initialize the list head within the instance data + InitializeListHead(&pConfigIfInstance->configKeyListHead); + + // Initialize the ConfigIf within the instance data + pConfigIfInstance->configIf.addReference = ConfigIf_AddReference; + pConfigIfInstance->configIf.releaseReference = ConfigIf_ReleaseReference; + pConfigIfInstance->configIf.getEntryValue = ConfigIf__GetEntryValue; + + // Save the ConfigFolder and ConfigName information within the instance data + pConfigIfInstance->pConfigFolder = malloc(configFolderLen + 1); + if (pConfigIfInstance->pConfigFolder) + { + strcpy(pConfigIfInstance->pConfigFolder, pConfigFolder); + pConfigIfInstance->configFolderLen = configFolderLen; + + pConfigIfInstance->pConfigName = malloc(configNameLen + 1); + if (pConfigIfInstance->pConfigName) + { + strcpy(pConfigIfInstance->pConfigName, pConfigName); + pConfigIfInstance->configNameLen = configNameLen; + + // Add the instance data into our list and bump up its reference count + // since we did that. + InsertTailList(&g_configIfListHead, &pConfigIfInstance->listEntry); + pConfigIfInstance->refCount = 1; + + // At this point we want to return success to the caller even if we + // experience a read error. + retStatus = CASA_STATUS_SUCCESS; + + // Return the ConfigIf associated with the instance data after + // incrementing its reference count. + pConfigIfInstance->refCount ++; + *ppConfigIf = &pConfigIfInstance->configIf; + + // Now update the instance data with the information present in the file + if (fseek(pConfigFile, 0, SEEK_SET) == 0) + { + char line[512]; + + while (fgets(line, sizeof(line), pConfigFile) != NULL) + { + int lineLength; + + RemoveWhiteSpaceFromTheEnd(line); + + lineLength = strlen(line); + if (lineLength != 0) + { + char *pKey; + char *pKeyEnd; + char *pValue; + int keyLen, valueLen; + ConfigKey *pConfigKey; + + // Attempt to find the key + pKey = SkipWhiteSpace(line); + + // Make sure that we are not dealing with an empty line or a comment + if (*pKey == '\0' || *pKey == '#') + continue; + + // Go past the key + pKeyEnd = SkipNonWhiteSpace(pKey); + + // Protect against a malformed line + if (*pKeyEnd == '\0') + { + DbgTrace(0, "auth_token -GetConfigInterface- Key found without value\n", 0); + continue; + } + + // Attempt to find the value + pValue = SkipWhiteSpace(pKeyEnd); + + // Protect against a malformed line + if (*pValue == '\0') + { + DbgTrace(0, "auth_token -GetConfigInterface- Key found without value\n", 0); + continue; + } + + // Delineate the key + *pKeyEnd = '\0'; + + // Create a ConfigKey object for this key/value pair + pConfigKey = malloc(sizeof(*pConfigKey)); + if (pConfigKey) + { + pConfigKey->keyNameLen = strlen(pKey); + pConfigKey->pKeyName = malloc(pConfigKey->keyNameLen + 1); + if (pConfigKey->pKeyName) + { + // Save the key name in lower case + LowerCaseString(pConfigKey->pKeyName, pKey); + + pConfigKey->valueLen = strlen(pValue); + pConfigKey->pValue = malloc(pConfigKey->valueLen + 1); + if (pConfigKey->pValue) + { + strcpy(pConfigKey->pValue, pValue); + + // The entry is ready, now associate it with the instance data. + InsertTailList(&pConfigIfInstance->configKeyListHead, &pConfigKey->listEntry); + } + else + { + DbgTrace(0, "auth_token -GetConfigInterface- Buffer allocation failure\n", 0); + free(pConfigKey->pKeyName); + free(pConfigKey); + } + } + else + { + DbgTrace(0, "auth_token -GetConfigInterface- Buffer allocation failure\n", 0); + free(pConfigKey); + } + } + else + { + DbgTrace(0, "auth_token -GetConfigInterface- Buffer allocation failure\n", 0); + } + } + } + } + else + { + DbgTrace(0, "auth_token -GetConfigInterface- File seek error, errno = %d\n", errno); + } + } + else + { + DbgTrace(0, "auth_token -GetConfigInterface- Buffer allocation failure\n", 0); + + // Free the buffers associated with the instance data + free(pConfigIfInstance->pConfigFolder); + free(pConfigIfInstance); + } + } + else + { + DbgTrace(0, "auth_token -GetConfigInterface- Buffer allocation failure\n", 0); + + // Free the buffer allocated for the instance data + free(pConfigIfInstance); + } + } + else + { + DbgTrace(0, "auth_token -GetConfigInterface- Buffer allocation failure\n", 0); + } + + // Close the file + fclose(pConfigFile); + } + else + { + DbgTrace(1, "auth_token -GetConfigInterface- Unable to open config file, errno = %d\n", errno); + } + } + else + { + DbgTrace(0, "auth_token -GetConfigInterface- Buffer allocation error\n", 0); + } + } + + // Release exclusive access to our mutex + pthread_mutex_unlock(&g_configIfMutex); + + DbgTrace(2, "auth_token -GetConfigInterface- End, retStatus = %08X\n", retStatus); + + return retStatus; +} + + +//++======================================================================= +//++======================================================================= +//++======================================================================= + diff --git a/auth_token/linux/internal.h b/auth_token/linux/internal.h new file mode 100644 index 00000000..d46d62d2 --- /dev/null +++ b/auth_token/linux/internal.h @@ -0,0 +1,81 @@ +/*********************************************************************** + * File: internal.h + * Author: Juan Carlos Luciani (jluciani@novell.com) + * + * Abstract: Defines or includes the definitions necessary for the + * module. + * + * Copyright (C) 2005 Novell, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; version 2.1 + * of the License. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * To contact Novell about this file by physical or electronic mail, + * you may find current contact information at www.novell.com. + ***********************************************************************/ + +//===[ Include files ]===================================================== + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +//===[ Type definitions ]================================================== + +#define CONTAINING_RECORD(address, type, field) ((type *)( \ + (char*)(address) - \ + (char*)(&((type *)0)->field))) + +// +// DbgTrace macro define +// +#define DbgTrace(LEVEL, X, Y) { \ + if (LEVEL == 0) \ + printf(X, Y); \ + else if (DebugLevel >= LEVEL) \ + printf(X, Y); \ +} + +//===[ Inlines functions ]=============================================== + +//===[ Function prototypes ]=============================================== + +//===[ Global variables ]================================================== + +//===[ Global externals ]================================================== + +extern int DebugLevel; + +//===[ External prototypes ]=============================================== + +extern +CasaStatus CSAPI +GetConfigInterface( + IN const char *pFolder, + IN const char *pConfigName, + INOUT ConfigIf **ppConfigIf); + + +//========================================================================= + diff --git a/auth_token/linux/libcasa_auth_token_lux.exp b/auth_token/linux/libcasa_auth_token_lux.exp new file mode 100644 index 00000000..27d4f630 --- /dev/null +++ b/auth_token/linux/libcasa_auth_token_lux.exp @@ -0,0 +1,8 @@ +VER_1.0 +{ + global: + GetAuthTokenCredentials; + ValidateAuthTokenCredentials; + local: + *; +}; diff --git a/auth_token/linux/link.lux b/auth_token/linux/link.lux new file mode 100644 index 00000000..bc81f42f --- /dev/null +++ b/auth_token/linux/link.lux @@ -0,0 +1,10 @@ +LINK = $(CC) \ + -Wl,-Bsymbolic \ + -shared \ + -Wl,--version-script=$(TARGET)_$(PLAT).exp \ + -Wl,-rpath -Wl,/usr/$(ARCH_LlB) \ + -L/usr/$(ARCH_LIB) -lpthread -lc -ldl \ + -Wl,-soname -Wl,$(TARGET).so \ + -o $(LIBDIR)$(XTRA)/$(TARGET).so \ + -L$(LIBDIR)$(XTRA) \ + $(OBJDIR)*.$(O) diff --git a/auth_token/linux/objs.lux b/auth_token/linux/objs.lux new file mode 100644 index 00000000..d0d1e815 --- /dev/null +++ b/auth_token/linux/objs.lux @@ -0,0 +1,4 @@ +OBJS=\ + auth_token.$(O) \ + config.$(O) + diff --git a/auth_token/list_entry.h b/auth_token/list_entry.h new file mode 100644 index 00000000..2ecfbcd5 --- /dev/null +++ b/auth_token/list_entry.h @@ -0,0 +1,191 @@ +/*********************************************************************** + * File: internal.h + * Author: Juan Carlos Luciani (jluciani@novell.com) + * + * Abstract: Defines the LIST_ENTRY type and the inlines necessary + * to manage queues and lists which make use of it. + * + * Copyright (C) 2005 Novell, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; version 2.1 + * of the License. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * To contact Novell about this file by physical or electronic mail, + * you may find current contact information at www.novell.com. + ***********************************************************************/ + +#ifndef _LIST_ENTRY_H_ +#define _LIST_ENTRY_H_ + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" +{ +#endif + +//===[ Include files ]===================================================== + +#include + +//===[ Type definitions ]================================================== + +#ifndef CSAPI +#if defined(WIN32) +#define CSAPI __stdcall +#else +#define CSAPI +#endif +#endif + +#ifndef IN +#define IN +#endif + +#ifndef OUT +#define OUT +#endif + +#ifndef INOUT +#define INOUT +#endif + +// +// LIST_ENTRY Type +// Doubly linked list structure +// +typedef struct _LIST_ENTRY +{ + struct _LIST_ENTRY * volatile Flink; + struct _LIST_ENTRY * volatile Blink; +} LIST_ENTRY, *PLIST_ENTRY; + + +//===[ Inlines functions ]=============================================== + +// +// Inline functions for operating on LIST_ENTRY double-linked lists +// + +__inline static void InitializeListHead( + IN PLIST_ENTRY pListEntry ) +{ + pListEntry->Flink = pListEntry->Blink = pListEntry; +} + +__inline static void InsertEntryAfter( + IN PLIST_ENTRY pListEntry, + IN PLIST_ENTRY pAfterEntry ) +{ + pListEntry->Flink = pAfterEntry->Flink; + pListEntry->Blink = pAfterEntry; + pListEntry->Flink->Blink = pAfterEntry->Flink = pListEntry; +} + +__inline static void InsertEntryBefore( + IN PLIST_ENTRY pListEntry, + IN PLIST_ENTRY pBeforeEntry ) +{ + pListEntry->Flink = pBeforeEntry; + pListEntry->Blink = pBeforeEntry->Blink; + pListEntry->Blink->Flink = pBeforeEntry->Blink = pListEntry; +} + +__inline static void InsertHeadList( + IN PLIST_ENTRY pListHead, + IN PLIST_ENTRY pListEntry ) +{ + pListEntry->Blink = pListHead; + pListEntry->Flink = pListHead->Flink; + pListEntry->Flink->Blink = pListHead->Flink = pListEntry; +} + +__inline static void InsertTailList( + IN PLIST_ENTRY pListHead, + IN PLIST_ENTRY pListEntry ) +{ + pListEntry->Flink = pListHead; + pListEntry->Blink = pListHead->Blink; + pListEntry->Blink->Flink = pListHead->Blink = pListEntry; +} + +__inline static bool IsListEmpty( + IN PLIST_ENTRY pListHead ) +{ + bool rc = false; + if(pListHead->Flink == pListHead) + rc = true; + return(rc); +} + +__inline static void RemoveEntryList( + IN PLIST_ENTRY pListEntry ) +{ + pListEntry->Flink->Blink = pListEntry->Blink; + pListEntry->Blink->Flink = pListEntry->Flink; + pListEntry->Flink = pListEntry->Blink = (PLIST_ENTRY) 0xbaadf00d; +} + +__inline static PLIST_ENTRY RemoveHeadList( + IN PLIST_ENTRY pListHead ) +{ + PLIST_ENTRY Entry = (PLIST_ENTRY)0; + if(pListHead->Flink != pListHead) + { + Entry = pListHead->Flink; + RemoveEntryList(Entry); + } + return(Entry); +} + +__inline static PLIST_ENTRY RemoveTailList( + IN PLIST_ENTRY pListHead ) +{ + PLIST_ENTRY Entry= (PLIST_ENTRY)0; + if(pListHead->Blink != pListHead) + { + Entry = pListHead->Blink; + RemoveEntryList(Entry); + } + return(Entry); +} + +__inline static PLIST_ENTRY GetFirstListEntry( + IN PLIST_ENTRY pList) +{ + PLIST_ENTRY Entry = (PLIST_ENTRY)0; + if(pList != pList->Flink) + Entry = pList->Flink; + return(Entry); +} + +__inline static PLIST_ENTRY GetNextListEntry( + IN PLIST_ENTRY pList, + IN PLIST_ENTRY pEntry) +{ + PLIST_ENTRY Entry = (PLIST_ENTRY)0; + if(pList != pEntry->Flink) + Entry = pEntry->Flink; + return(Entry); +} + + +//========================================================================= + + +#if defined(__cplusplus) || defined(c_plusplus) +} +#endif // #if defined(__cplusplus) || defined(c_plusplus) + +#endif // #ifndef _LIST_ENTRY_H_ + + diff --git a/auth_token/test/linux/krb-test-service b/auth_token/test/linux/krb-test-service new file mode 100644 index 00000000..cf79c39f --- /dev/null +++ b/auth_token/test/linux/krb-test-service @@ -0,0 +1,6 @@ +#%PAM-1.0 +auth required pam_casaauthtok.so +account required pam_casaauthtok.so +password required pam_casaauthtok.so +session required pam_casaauthtok.so + diff --git a/auth_token/test/linux/make-test-pam.sh b/auth_token/test/linux/make-test-pam.sh new file mode 100755 index 00000000..054e585a --- /dev/null +++ b/auth_token/test/linux/make-test-pam.sh @@ -0,0 +1,2 @@ +#!/bin/bash +gcc -o test-pam test-pam.c -g -I"../.." -I"../../../include" -DN_PLAT_UNIX -L"../../../lib/lux/dbg" -lpam -lcasa_auth_token diff --git a/auth_token/test/linux/make-test.sh b/auth_token/test/linux/make-test.sh new file mode 100755 index 00000000..424aa10e --- /dev/null +++ b/auth_token/test/linux/make-test.sh @@ -0,0 +1,2 @@ +#!/bin/bash +gcc -o test test.c -I"../.." -I"../../../include" -DN_PLAT_UNIX -g -L"../../../lib/lux/dbg" -lcasa_auth_token diff --git a/auth_token/test/linux/test-pam.c b/auth_token/test/linux/test-pam.c new file mode 100644 index 00000000..d365496a --- /dev/null +++ b/auth_token/test/linux/test-pam.c @@ -0,0 +1,321 @@ +//++======================================================================= +// File Name: test.c +// Version: v1.00 +// Author: Juan Carlos Luciani v1.0 +// +// Abstract: This module tests the authentication token infrastructure. +// +// Notes: +// +// Revision History: +// +// +// (C) Unpublished Copyright of Novell, Inc. All Rights Reserved. +// +// No part of this file may be duplicated, revised, translated, localized, +// or modified in any manner or compiled, linked or uploaded or downloaded +// to or from any computer system without the prior written consent of +// Novell, Inc. +//=======================================================================-- + + + +//===[ Include files ]===================================================== + +#include +#include +#include +#include +#include +#include +#include + +#include + +//===[ Type definitions ]================================================== + +typedef struct _AppUserData +{ + char *pUserName; + char *pAuthToken; + +} AppUserData, *PAppUserData; + +// +// DbgTrace macro define +// +#define DbgTrace(LEVEL, X, Y) { \ + if (LEVEL == 0) \ + printf(X, Y); \ + else if (DebugLevel >= LEVEL) \ + printf(X, Y); \ +} + + +//===[ Function prototypes ]=============================================== + +//===[ Global variables ]================================================== + +// Usage string +char usage[] = "\ntest: usage: [-p ConnectPort] [-D DebugLevel]\n"; + +// Debug Level +int DebugLevel = 3; + +//++======================================================================= +int +Converse(int num_msg, + const struct pam_message **msg, + struct pam_response **resp, + void *appdata_ptr) +// +// Arguments: +// +// Returns: +// +// Abstract: +// +// Notes: +// +// Environment: +// +//=======================================================================-- +{ + int retStatus = PAM_SUCCESS; + int replies = 0; + struct pam_response *reply = NULL; + AppUserData *pAppUserData = (PAppUserData) appdata_ptr; + + // Initialize output parameters + *resp = NULL; + + // Check input parameters + if (num_msg <= 0 || appdata_ptr == NULL) + return PAM_CONV_ERR; + + // Allocate enough space for the replies + reply = malloc(sizeof(struct pam_response) * num_msg); + if (!reply) + return PAM_CONV_ERR; + + // Zero the reply buffer + memset(reply, 0, sizeof(struct pam_response) * num_msg); + + for (replies = 0; + replies < num_msg && retStatus == PAM_SUCCESS; + replies++) + { + switch (msg[replies]->msg_style) + { + case PAM_PROMPT_ECHO_ON: + + // The caller wants the username + reply[replies].resp_retcode = PAM_SUCCESS; + reply[replies].resp = malloc(strlen(pAppUserData->pUserName) + 1); + if (reply[replies].resp) + strcpy(reply[replies].resp, pAppUserData->pUserName); + else + { + DbgTrace(0, "Converse- Buffer allocation failure\n", 0); + retStatus = PAM_CONV_ERR; + } + break; + + case PAM_PROMPT_ECHO_OFF: + + // The caller wants the authentication token + reply[replies].resp_retcode = PAM_SUCCESS; + reply[replies].resp = malloc(strlen(pAppUserData->pAuthToken) + 1); + if (reply[replies].resp) + strcpy(reply[replies].resp, pAppUserData->pAuthToken); + else + { + DbgTrace(0, "Converse- Buffer allocation failure\n", 0); + retStatus = PAM_CONV_ERR; + } + break; + + case PAM_TEXT_INFO: + case PAM_ERROR_MSG: + + // Just return success + reply[replies].resp_retcode = PAM_SUCCESS; + reply[replies].resp = NULL; + break; + + default: + + // Un-expected + retStatus = PAM_CONV_ERR; + } + } + + // Proceed based on the status + if (retStatus == PAM_SUCCESS) + { + *resp = reply; + } + else + { + // Free buffers allocated for the reply + for (replies = 0; + replies < num_msg && retStatus == PAM_SUCCESS; + replies++) + { + if (reply[replies].resp != NULL) + free(reply[replies].resp); + } + free(reply); + } + + return retStatus; +} + + +//++======================================================================= +void +ExecuteTests(void) +// +// Arguments: +// +// Returns: +// +// Abstract: +// +// Notes: +// +// Environment: +// +//=======================================================================-- +{ + CasaStatus status; + char userName[100]; + int userNameBufLen = sizeof(userName); + char token[1000]; + int tokenBufLen = sizeof(token); + + DbgTrace(1, "ExecuteTests- Start\n", 0); + + status = GetAuthTokenCredentials("krb-test-service", + userName, + &userNameBufLen, + token, + &tokenBufLen); + if (CASA_SUCCESS(status) + && CasaStatusCode(status) != CASA_STATUS_OBJECT_NOT_FOUND) + { + AppUserData appUserData = {userName, token}; + struct pam_conv conv = {Converse, &appUserData}; + pam_handle_t *pamh; + int pam_status; + + // We obtained authentication token credentials to authenticate + // to the service, now verify the credentials using PAM_Authenticate.. + printf("userName = %s\n", userName); + printf("userNameBufLen = %d\n", userNameBufLen); + printf("token = %s\n", token); + printf("tokenBufLen = %d\n", tokenBufLen); + + // Open a PAM Handle + pam_status = pam_start("krb-test-service", userName, &conv, &pamh); + if (pam_status == PAM_SUCCESS) + { + // Now authenticate the user + pam_status = pam_authenticate(pamh, PAM_DISALLOW_NULL_AUTHTOK); + if (pam_status == PAM_SUCCESS) + { + DbgTrace(1, "ExecuteTests- pam_authenticate success\n", 0); + } + else + { + DbgTrace(0, "ExecuteTests- pam_authenticate failure, error = %s\n", pam_strerror(pamh, pam_status)); + } + + // Close the PAM Handle + pam_end(pamh, pam_status | PAM_DATA_SILENT); + } + else + { + DbgTrace(0, "ExecuteTests- pam_start failure, status = %08X\n", pam_status); + } + } + else + { + DbgTrace(0, "ExecuteTests- GetAuthTokenCredentials failure, status = %08X\n", status); + } + + DbgTrace(1, "ExecuteTests- End\n", 0); +} + + +//++======================================================================= +int +main( + int argc, + char* argv[]) +// +// Arguments: +// +// Returns: +// +// Abstract: +// +// Notes: +// +// L2 +//=======================================================================-- +{ + int optionsSpecified = 0; + bool doneScanning = false; + bool invalidOption = false; + int option; + + printf("**** auth-token-test ****\n"); + + // Scan through the options specified + while (!doneScanning) + { + opterr = 0; + option = getopt(argc, argv, "D"); + + // Proceed based on the result + switch (option) + { + case 'D': + // Set the debug level + DebugLevel = atoi(optarg); + optionsSpecified++; + break; + + case '?': + // Invalid option detected + doneScanning = true; + invalidOption = true; + break; + + default: + // Done scanning + doneScanning = true; + break; + } + } + + // Do some sanity checking + if (!invalidOption) + { + int i; + + for (i = 0; i < 1; i++) + ExecuteTests(); + } + else + { + // Invalid option detected or the user failed to + // specify the listening port number. + printf(usage, argv[0]); + } + + return 0; + +} /*-- main() --*/ + diff --git a/auth_token/test/linux/test.c b/auth_token/test/linux/test.c new file mode 100644 index 00000000..b0496a23 --- /dev/null +++ b/auth_token/test/linux/test.c @@ -0,0 +1,187 @@ +//++======================================================================= +// File Name: test.c +// Version: v1.00 +// Author: Juan Carlos Luciani v1.0 +// +// Abstract: This module tests the authentication token infrastructure. +// +// Notes: +// +// Revision History: +// +// +// (C) Unpublished Copyright of Novell, Inc. All Rights Reserved. +// +// No part of this file may be duplicated, revised, translated, localized, +// or modified in any manner or compiled, linked or uploaded or downloaded +// to or from any computer system without the prior written consent of +// Novell, Inc. +//=======================================================================-- + + + +//===[ Include files ]===================================================== + +#include +#include +#include +#include +#include + +#include + +//===[ Type definitions ]================================================== + +// +// DbgTrace macro define +// +#define DbgTrace(LEVEL, X, Y) { \ + if (LEVEL == 0) \ + printf(X, Y); \ + else if (DebugLevel >= LEVEL) \ + printf(X, Y); \ +} + + +//===[ Function prototypes ]=============================================== + +//===[ Global variables ]================================================== + +// Usage string +char usage[] = "\ntest: usage: [-p ConnectPort] [-D DebugLevel]\n"; + +// Debug Level +int DebugLevel = 3; + + +//++======================================================================= +void +ExecuteTests(void) +// +// Arguments: +// +// Returns: +// +// Abstract: +// +// Notes: +// +// Environment: +// +//=======================================================================-- +{ + CasaStatus status; + char userName[100]; + int userNameBufLen = sizeof(userName); + char token[1000]; + int tokenBufLen = sizeof(token); + + DbgTrace(1, "ExecuteTests- Start\n", 0); + + status = GetAuthTokenCredentials("krb-test-service", + userName, + &userNameBufLen, + token, + &tokenBufLen); + if (CASA_SUCCESS(status) + && CasaStatusCode(status) != CASA_STATUS_OBJECT_NOT_FOUND) + { + // We obtained authentication token credentials to authenticate + // to the service, now verify them. + printf("userName = %s\n", userName); + printf("userNameBufLen = %d\n", userNameBufLen); + printf("tokenBufLen = %d\n", tokenBufLen); + status = ValidateAuthTokenCredentials("krb-test-service", + userName, + strlen(userName), + token, + strlen(token)); + if (CASA_SUCCESS(status)) + { + DbgTrace(1, "ExecuteTests- ValidateAuthTokenCredentials success\n", 0); + } + else + { + DbgTrace(0, "ExecuteTests- ValidateAuthTokenCredentials failure, status = %08X\n", status); + } + } + else + { + DbgTrace(0, "ExecuteTests- GetAuthTokenCredentials failure, status = %08X\n", status); + } + + DbgTrace(1, "ExecuteTests- End\n", 0); +} + + +//++======================================================================= +int +main( + int argc, + char* argv[]) +// +// Arguments: +// +// Returns: +// +// Abstract: +// +// Notes: +// +// L2 +//=======================================================================-- +{ + int optionsSpecified = 0; + bool doneScanning = false; + bool invalidOption = false; + int option; + + printf("**** auth-token-test ****\n"); + + // Scan through the options specified + while (!doneScanning) + { + opterr = 0; + option = getopt(argc, argv, "D"); + + // Proceed based on the result + switch (option) + { + case 'D': + // Set the debug level + DebugLevel = atoi(optarg); + optionsSpecified++; + break; + + case '?': + // Invalid option detected + doneScanning = true; + invalidOption = true; + break; + + default: + // Done scanning + doneScanning = true; + break; + } + } + + // Do some sanity checking + if (!invalidOption) + { + int i; + + for (i = 0; i < 1; i++) + ExecuteTests(); + } + else + { + // Invalid option detected or the user failed to + // specify the listening port number. + printf(usage, argv[0]); + } + + return 0; + +} /*-- main() --*/ +