Splitted the non-java project into client and server projects in order

to be able to deliver the client component onto distributions targeting
desktops without having to deliver the server components. This commit is
for the resulting client project.
This commit is contained in:
Juan Carlos Luciani
2006-11-13 05:20:43 +00:00
parent 2cc21a344c
commit 2c8668479c
110 changed files with 19988 additions and 0 deletions

View File

@@ -0,0 +1,126 @@
#######################################################################
#
# Copyright (C) 2006 Novell, Inc.
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public
# License as published by the Free Software Foundation; either
# version 2 of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public
# License along with this program; if not, write to the Free
# Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
# Author: Juan Carlos Luciani <jluciani@novell.com>
#
#######################################################################
if DEBUG
TARGET_CFG = Debug
CFLAGS += -v -w
DEFINES = -DDBG
else
TARGET_CFG = Release
DEFINES = -DNDEBUG
endif
SUBDIRS =
DIST_SUBDIRS =
ROOT = ../..
LIBDIR = $(ROOT)/$(LIB)
# handle Mono secondary dependencies
export MONO_PATH := $(MONO_PATH)
PLATFORMINDEPENDENTSOURCEDIR = ..
PLATFORMDEPENDENTSOURCEDIR = .
MODULE_NAME = libcasa_c_authtoken
MODULE_EXT = so
CFILES = ../authmech.c \
../authmsg.c \
../authpolicy.c \
../cache.c \
../config.c \
../engine.c \
../getpolicymsg.c \
../gettokenmsg.c \
../util.c \
../invalidcert.c \
rpc.c \
platform.c
CSFILES_CSC :=
INCLUDES = -I. -I.. -I../../include
RESOURCES =
if LIB64
DEFINES += -D_LIB64
endif
CFLAGS += -Wno-format-extra-args -fno-strict-aliasing $(INCLUDES) $(DEFINES)
LIBS = -lpthread -ldl -lexpat -lcurl -lidn -lssl -lcrypto -lz -lmicasa
LDFLAGS = -Bsymbolic -shared -Wl,-soname=$(MODULE_NAME).$(MODULE_EXT) -L$(ROOT)/lib/$(TARGET_CFG)
OBJDIR = ./$(TARGET_CFG)/$(LIB)
OBJS = $(addprefix $(OBJDIR)/, $(CFILES:%.c=%.o))
EXTRA_DIST = $(CFILES) *.h
CUR_DIR := $(shell pwd)
all: $(OBJDIR)/$(MODULE_NAME).$(MODULE_EXT)
#
# Pattern based rules.
#
vpath %.c $(PLATFORMDEPENDENTSOURCEDIR) $(PLATFORMINDEPENDENTSOURCEDIR)
vpath %.cpp $(PLATFORMDEPENDENTSOURCEDIR) $(PLATFORMINDEPENDENTSOURCEDIR)
$(OBJDIR)/%.o: %.c
$(CC) -c $(CFLAGS) -o $@ $<
$(OBJDIR)/%.o: %.cpp
$(CC) -c $(CFLAGS) -o $@ $<
$(OBJDIR)/$(MODULE_NAME).$(MODULE_EXT): $(OBJDIR) $(OBJS)
@echo [======== Linking $@ ========]
$(LINK) -o $@ $(LDFLAGS) $(OBJS) $(LIBS)
cp -f $(OBJDIR)/$(MODULE_NAME).$(MODULE_EXT) $(LIBDIR)/$(TARGET_CFG)/$(MODULE_NAME).$(MODULE_EXT)
$(OBJDIR):
[ -d $(OBJDIR) ] || mkdir -p $(OBJDIR)
[ -d $(LIBDIR) ] || mkdir -p $(LIBDIR)
[ -d $(LIBDIR)/$(TARGET_CFG) ] || mkdir -p $(LIBDIR)/$(TARGET_CFG)
install-exec-local: $(OBJDIR)/$(MODULE_NAME).$(MODULE_EXT)
$(mkinstalldirs) $(DESTDIR)$(libdir)
$(INSTALL_PROGRAM) $(OBJDIR)/$(MODULE_NAME).$(MODULE_EXT) $(DESTDIR)$(libdir)/
uninstall-local:
cd $(DESTDIR)$(libdir); rm -f $(OBJDIR)/$(MODULE_NAME).$(MODULE_EXT)
rmdir $(DESTDIR)$(libdir)
#installcheck-local: install
# $(mkinstalldirs) $(DESTDIR)$(libdir)
# $(INSTALL_PROGRAM) $(DESTDIR)$(libdir)
# cd $(DESTDIR)$(libdir); $(MONO)
clean-local:
if [ -d $(TARGET_CFG) ]; then rm -rf $(TARGET_CFG); fi
distclean-local:
maintainer-clean-local:
rm -f Makefile.in

View File

@@ -0,0 +1,831 @@
/***********************************************************************
*
* Copyright (C) 2006 Novell, Inc. All Rights Reserved.
*
* 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 Lesser 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, Novell, Inc.
*
* To contact Novell about this file by physical or electronic mail,
* you may find current contact information at www.novell.com.
*
* Author: Juan Carlos Luciani <jluciani@novell.com>
*
***********************************************************************/
//===[ Include files ]=====================================================
#include "internal.h"
//===[ Type definitions ]==================================================
//
// Normalized Host Name Cache Entry definition
//
typedef struct _NormalizedHostNameCacheEntry
{
LIST_ENTRY listEntry;
char *pHostName;
char *pNormalizedHostName;
int buffLengthRequired;
} NormalizedHostNameCacheEntry, *PNormalizedHostNameCacheEntry;
//===[ Type definitions for Local_sem ]====================================
//
// Notes: Most of the code for this definitions and the Local_sem_xxxx
// functions was copied with minor modifications from W. Richard
// Stevens book: UNIX Network Programming, Interprocess
// Communications (Printed in 1999).
//
// You may ask, why not just use Posix Named Semaphores? The answer
// is that I wish that I could but I can not tolerate that they are
// not released when the process that holds them terminates abnormally.
//
union semun /* define union for semctl() */
{
int val;
struct semid_ds *buf;
unsigned short *array;
};
typedef struct
{
int sem_semid; /* the System V semaphore ID */
int sem_magic; /* magic number if open */
} Local_sem_t;
#ifndef SEM_R
#define SEM_R 0400
#endif
#ifndef SEM_A
#define SEM_A 0200
#endif
#define SVSEM_MODE (SEM_R | SEM_A | SEM_R>>3 | SEM_R>>6)
#define SEM_MAGIC 0x45678923
#define SEM_FAILED ((Local_sem_t *)(-1)) /* avoid compiler warnings */
#ifndef SEMVMX
#define SEMVMX 32767 /* historical System V max value for sem */
#endif
#define MAX_OPEN_SEM_TRIES 10 /* for waiting for initialization */
//===[ Function prototypes ]===============================================
//===[ Global variables ]==================================================
// Normalized host name cache variables
static
LIST_ENTRY normalizedHostNameCacheListHead;
static
pthread_mutex_t g_hNormalizedHostNameCacheMutex = PTHREAD_MUTEX_INITIALIZER;
// Client configuration file folder
char clientConfigFolder[] = "/etc/CASA/authtoken/client";
// Authentication mechanism configuration file folder
char mechConfigFolder[] = "/etc/CASA/authtoken/client/mechanisms";
// Module Synchronization mutex
pthread_mutex_t g_hModuleMutex = PTHREAD_MUTEX_INITIALIZER;
// Path separator
char pathCharString[] = "/";
// Milliseconds per System Tick
static
long g_milliSecondsPerTicks = 0;
// Named Semaphore for user variables
static
char g_userNamedSemName[256];
static
Local_sem_t *g_userNamedSem = SEM_FAILED;
static
bool g_userNamedSemAcquired = false;
//++=======================================================================
Local_sem_t*
Local_sem_open(const char *pathname, int oflag, ... )
//
// Arguments:
//
// Returns:
//
// Abstract:
//
// Notes: Most of the code for this routine was copied with minor
// modifications from W. Richard Stevens book: UNIX Network
// Programming, Interprocess Communications (Printed in 1999).
//
// L2
//=======================================================================--
{
int i, fd, semflag, semid, save_errno;
key_t key;
mode_t mode;
va_list ap;
Local_sem_t *sem;
union semun arg;
unsigned int value;
struct semid_ds seminfo;
struct sembuf initop;
/* 4no mode for sem_open() w/out O_CREAT; guess */
semflag = SVSEM_MODE;
semid = -1;
if (oflag & O_CREAT) {
va_start(ap, oflag); /* init ap to final named argument */
mode = va_arg(ap, mode_t);
value = va_arg(ap, unsigned int);
va_end(ap);
/* 4convert to key that will identify System V semaphore */
if ( (fd = open(pathname, oflag, mode)) == -1)
return(SEM_FAILED);
close(fd);
if ( (key = ftok(pathname, 0)) == (key_t) -1)
return(SEM_FAILED);
semflag = IPC_CREAT | (mode & 0777);
if (oflag & O_EXCL)
semflag |= IPC_EXCL;
/* 4create the System V semaphore with IPC_EXCL */
if ( (semid = semget(key, 1, semflag | IPC_EXCL)) >= 0) {
/* 4success, we're the first so initialize to 0 */
arg.val = 0;
if (semctl(semid, 0, SETVAL, arg) == -1)
goto err;
/* 4then increment by value to set sem_otime nonzero */
if (value > SEMVMX) {
errno = EINVAL;
goto err;
}
initop.sem_num = 0;
initop.sem_op = value;
initop.sem_flg = 0;
if (semop(semid, &initop, 1) == -1)
goto err;
goto finish;
} else if (errno != EEXIST || (semflag & IPC_EXCL) != 0)
goto err;
/* else fall through */
}
/*
* (O_CREAT not secified) or
* (O_CREAT without O_EXCL and semaphore already exists).
* Must open semaphore and make certain it has been initialized.
*/
if ( (key = ftok(pathname, 0)) == (key_t) -1)
goto err;
if ( (semid = semget(key, 0, semflag)) == -1)
goto err;
arg.buf = &seminfo;
for (i = 0; i < MAX_OPEN_SEM_TRIES; i++) {
if (semctl(semid, 0, IPC_STAT, arg) == -1)
goto err;
if (arg.buf->sem_otime != 0)
goto finish;
sleep(1);
}
errno = ETIMEDOUT;
err:
save_errno = errno; /* don't let semctl() change errno */
if (semid != -1)
semctl(semid, 0, IPC_RMID);
errno = save_errno;
return(SEM_FAILED);
finish:
if ( (sem = malloc(sizeof(Local_sem_t))) == NULL)
goto err;
sem->sem_semid = semid;
sem->sem_magic = SEM_MAGIC;
return(sem);
}
//++=======================================================================
int
Local_sem_wait(Local_sem_t *sem)
//
// Arguments:
//
// Returns:
//
// Abstract:
//
// Notes: Most of the code for this routine was copied with minor
// modifications from W. Richard Stevens book: UNIX Network
// Programming, Interprocess Communications (Printed in 1999).
//
// L2
//=======================================================================--
{
struct sembuf op;
if (sem->sem_magic != SEM_MAGIC) {
errno = EINVAL;
return(-1);
}
op.sem_num = 0;
op.sem_op = -1;
//op.sem_flg = 0;
op.sem_flg = SEM_UNDO; // Deviation from Richard's to allow cleanup in case of abnormal termination.
if (semop(sem->sem_semid, &op, 1) < 0)
return(-1);
return(0);
}
//++=======================================================================
int
Local_sem_post(Local_sem_t *sem)
//
// Arguments:
//
// Returns:
//
// Abstract:
//
// Notes: Most of the code for this routine was copied with minor
// modifications from W. Richard Stevens book: UNIX Network
// Programming, Interprocess Communications (Printed in 1999).
//
// L2
//=======================================================================--
{
struct sembuf op;
if (sem->sem_magic != SEM_MAGIC) {
errno = EINVAL;
return(-1);
}
op.sem_num = 0;
op.sem_op = 1;
op.sem_flg = 0;
if (semop(sem->sem_semid, &op, 1) < 0)
return(-1);
return(0);
}
//++=======================================================================
int
Local_sem_close(Local_sem_t *sem)
//
// Arguments:
//
// Returns:
//
// Abstract:
//
// Notes: Most of the code for this routine was copied with minor
// modifications from W. Richard Stevens book: UNIX Network
// Programming, Interprocess Communications (Printed in 1999).
//
// L2
//=======================================================================--
{
if (sem->sem_magic != SEM_MAGIC) {
errno = EINVAL;
return(-1);
}
sem->sem_magic = 0; /* just in case */
free(sem);
return(0);
}
//++=======================================================================
DWORD
GetTickCount(void)
//
// Arguments:
//
// Returns:
//
// Abstract:
//
// Notes:
//
// L2
//=======================================================================--
{
struct tms tm;
DWORD tickCount;
DbgTrace(2, "-GetTickCount- Start\n", 0);
// Determine milliseconds per tick if we have not done already
if (g_milliSecondsPerTicks == 0)
{
long ticksPerSecond;
ticksPerSecond = sysconf(_SC_CLK_TCK);
DbgTrace(3, "-GetTickCount- TicksPerSec = %0lX\n", ticksPerSecond);
g_milliSecondsPerTicks = 1000 / ticksPerSecond;
}
// Determine the tickCount as milliseconds
tickCount = g_milliSecondsPerTicks * times(&tm);
DbgTrace(2, "-GetTickCount- End, retValue = %0lX\n", tickCount);
return tickCount;
}
//++=======================================================================
CasaStatus
CreateUserMutex(
HANDLE *phMutex
)
//
// Arguments:
//
// Returns:
//
// Abstract:
//
// Notes:
//
// L2
//=======================================================================--
{
CasaStatus retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR,
CASA_FACILITY_AUTHTOKEN,
CASA_STATUS_UNSUCCESSFUL);
DbgTrace(1, "-CreateUserMutex- Start\n", 0);
// We use Named Semaphores to provide this functionality. The semaphore names are
// linked to the user via its uid.
if (sprintf(g_userNamedSemName, "/var/lib/CASA/authtoken/semuser_%d", geteuid()) != -1)
{
// Create or open semaphore to be only used by the effective user
g_userNamedSem = Local_sem_open((const char*) g_userNamedSemName, O_RDWR | O_CREAT, 0600, 1);
if (g_userNamedSem == SEM_FAILED)
{
DbgTrace(0, "-CreateUserMutex- Error opening named semaphore, errno = %d\n", errno);
}
else
{
// Success
retStatus = CASA_STATUS_SUCCESS;
}
}
else
{
DbgTrace(0, "-CreateUserMutex- sprintf failed, error = %d\n", errno);
}
DbgTrace(1, "-CreateUserMutex- End, retStatus\n", retStatus);
return retStatus;
}
//++=======================================================================
void
AcquireUserMutex(
HANDLE hMutex
)
//
// Arguments:
//
// Returns:
//
// Abstract:
//
// Notes:
//
// L2
//=======================================================================--
{
DbgTrace(2, "-AcquireUserMutex- Start\n", 0);
// Wait on the named semaphore
if (Local_sem_wait(g_userNamedSem) != 0)
{
DbgTrace(0, "-AcquireUserMutex- Error returned by sem_wait(), errno = %d\n", errno);
}
// The user semaphore has been acquired
g_userNamedSemAcquired = true;
DbgTrace(2, "-AcquireUserMutex- End\n", 0);
}
//++=======================================================================
void
ReleaseUserMutex(
HANDLE hMutex
)
//
// Arguments:
//
// Returns:
//
// Abstract:
//
// Notes:
//
// L2
//=======================================================================--
{
DbgTrace(2, "-ReleaseUserMutex- Start\n", 0);
// The user semaphore is no longer acquired
g_userNamedSemAcquired = false;
// Post on the named semaphore
if (Local_sem_post(g_userNamedSem) != 0)
{
DbgTrace(0, "-ReleaseUserMutex- Error returned by sem_post(), errno = %d\n", errno);
}
DbgTrace(2, "-ReleaseUserMutex- End\n", 0);
}
//++=======================================================================
void
DestroyUserMutex(
HANDLE hMutex
)
//
// Arguments:
//
// Returns:
//
// Abstract:
//
// Notes:
//
// L2
//=======================================================================--
{
DbgTrace(2, "-DestroyUserMutex- Start\n", 0);
// Do not do anything if the named semaphore is invalid
if (g_userNamedSem != SEM_FAILED)
{
// Close the named semaphore. Note that we want user semaphores to
// hang around, therefore we will not unlink them. This is per-design as
// is not a resource leak. If someone has an issue with this, then it can
// be solved by installing a cron job that cleans up the semaphores for
// deleted users.
if (Local_sem_close(g_userNamedSem) != 0)
{
DbgTrace(0, "-DestroyUserMutex- Error returned by sem_close(), errno = %d\n", errno);
}
// Forget about the semaphore
g_userNamedSem = SEM_FAILED;
}
DbgTrace(2, "-DestroyUserMutex- End\n", 0);
}
//++=======================================================================
LIB_HANDLE
OpenLibrary(
IN char *pFileName)
//
// Arguments:
//
// Returns:
//
// Abstract:
//
// Notes:
//
// L2
//=======================================================================--
{
LIB_HANDLE libHandle;
DbgTrace(1, "-OpenLibrary- Start\n", 0);
libHandle = dlopen(pFileName, RTLD_LAZY);
if (libHandle == NULL)
{
DbgTrace(0, "-OpenLibrary- Not able to load library, error = %s\n", dlerror());
}
DbgTrace(1, "-OpenLibrary- End, handle = %0lX\n", (long) libHandle);
return libHandle;
}
//++=======================================================================
void
CloseLibrary(
IN LIB_HANDLE libHandle)
//
// Arguments:
//
// Returns:
//
// Abstract:
//
// Notes:
//
// L2
//=======================================================================--
{
DbgTrace(1, "-CloseLibrary- Start\n", 0);
dlclose(libHandle);
DbgTrace(1, "-CloseLibrary- End\n", 0);
}
//++=======================================================================
void*
GetFunctionPtr(
IN LIB_HANDLE libHandle,
IN char *pFunctionName)
//
// Arguments:
//
// Returns:
//
// Abstract:
//
// Notes:
//
// L2
//=======================================================================--
{
void *pFuncPtr;
DbgTrace(1, "-GetFunctionPtr- Start\n", 0);
pFuncPtr = dlsym(libHandle, pFunctionName);
if (pFuncPtr == NULL)
{
DbgTrace(0, "-GetFunctionPtr- Not able to obtain func ptr, error = %s\n", dlerror());
}
DbgTrace(1, "-GetFunctionPtr- End, pFuncPtr = %0lX\n", (long) pFuncPtr);
return pFuncPtr;
}
//++=======================================================================
char*
NormalizeHostName(
IN const char *pHostName)
//
// Arguments:
//
// Returns:
//
// Abstract:
//
// Notes:
//
// L2
//=======================================================================--
{
char *pNormalizedName = NULL;
LIST_ENTRY *pListEntry;
NormalizedHostNameCacheEntry *pEntry = NULL;
DbgTrace(1, "-NormalizeHostName- Start\n", 0);
// Obtain our synchronization mutex
pthread_mutex_lock(&g_hNormalizedHostNameCacheMutex);
// First try to find an entry in the normalized host name cache
// for the host name provided.
pListEntry = normalizedHostNameCacheListHead.Flink;
while (pListEntry != &normalizedHostNameCacheListHead)
{
// Get pointer to the entry
pEntry = CONTAINING_RECORD(pListEntry, NormalizedHostNameCacheEntry, listEntry);
// Check if the entry is for the host name
if (strcmp(pHostName, pEntry->pHostName) == 0)
{
// This entry corresponds to the given host name
break;
}
else
{
// The entry does not correspond to the given host name
pEntry = NULL;
}
// Advance to the next entry
pListEntry = pListEntry->Flink;
}
// Check if we found an entry in our cache for the given host name
if (pEntry)
{
// Entry found, obtain the normalized name from it.
pNormalizedName = (char*) malloc(pEntry->buffLengthRequired);
if (pNormalizedName)
{
// Copy the normalized name onto the allocated buffer
strcpy(pNormalizedName, pEntry->pNormalizedHostName);
}
else
{
DbgTrace(0, "-NormalizeHostName- Buffer allocation error\n", 0);
}
}
else
{
// An entry was not found in our cache, create one.
pEntry = (NormalizedHostNameCacheEntry*) malloc(sizeof(NormalizedHostNameCacheEntry));
if (pEntry)
{
// Zero the entry
memset(pEntry, 0, sizeof(*pEntry));
// Allocate a buffer to hold the host name in the entry
pEntry->pHostName = (char*) malloc(strlen(pHostName) + 1);
if (pEntry->pHostName)
{
struct hostent *pLookupResult;
struct sockaddr_in sockAddr = {0};
// Copy the host name given into the allocated buffer
strcpy(pEntry->pHostName, pHostName);
// Now try to resolve the normalized name
pLookupResult = gethostbyname(pHostName);
if (pLookupResult && pLookupResult->h_addrtype == AF_INET)
{
char dnsHostName[NI_MAXHOST];
// Set up a sockaddr structure
sockAddr.sin_family = AF_INET;
sockAddr.sin_addr.s_addr = *((int*) pLookupResult->h_addr_list[0]);
// Now try to resolve the name using DNS
if (getnameinfo((const struct sockaddr*) &sockAddr,
sizeof(sockAddr),
dnsHostName,
sizeof(dnsHostName),
NULL,
0,
NI_NAMEREQD) == 0)
{
// We resolved the address to a DNS name, use it as the normalized name.
pEntry->buffLengthRequired = (int) strlen(dnsHostName) + 1;
pEntry->pNormalizedHostName = (char*) malloc(pEntry->buffLengthRequired);
if (pEntry->pNormalizedHostName)
{
// Copy the dns name
strcpy(pEntry->pNormalizedHostName, dnsHostName);
}
else
{
DbgTrace(0, "-NormalizeHostName- Buffer allocation error\n", 0);
}
}
else
{
DbgTrace(0, "-NormalizeHostName- getnameInfo failed, error %d\n", errno);
// Not able to resolve the name in DNS, just use the host name as
// the normalized name.
pEntry->buffLengthRequired = (int) strlen(pHostName) + 1;
pEntry->pNormalizedHostName = (char*) malloc(pEntry->buffLengthRequired);
if (pEntry->pNormalizedHostName)
{
// Copy the host name
strcpy(pEntry->pNormalizedHostName, pHostName);
}
else
{
DbgTrace(0, "-NormalizeHostName- Buffer allocation error\n", 0);
}
}
}
else
{
DbgTrace(0, "-NormalizeHostName- Name resolution failed, error = %d\n", errno);
}
}
else
{
DbgTrace(0, "-NormalizeHostName- Buffer allocation error\n", 0);
// Free the space allocated for the entry
free(pEntry);
}
// Proceed based on whether or not we normalized the name
if (pEntry->pNormalizedHostName)
{
// The name was normalized, save the entry in our cache.
InsertHeadList(&normalizedHostNameCacheListHead, &pEntry->listEntry);
// Return the normalized name present in the entry
pNormalizedName = (char*) malloc(pEntry->buffLengthRequired);
if (pNormalizedName)
{
// Copy the normalized name onto the allocated buffer
strcpy(pNormalizedName, pEntry->pNormalizedHostName);
}
else
{
DbgTrace(0, "-NormalizeHostName- Buffer allocation error\n", 0);
}
}
else
{
// The host name was not normalized, free allocated resources.
if (pEntry->pHostName)
free(pEntry->pHostName);
free(pEntry);
}
}
else
{
DbgTrace(0, "-NormalizeHostName- Buffer allocation error\n", 0);
}
}
// Release our synchronization mutex
pthread_mutex_unlock(&g_hNormalizedHostNameCacheMutex);
DbgTrace(1, "-NormalizeHostName- End, pNormalizedName = %0lX\n", (long) pNormalizedName);
return pNormalizedName;
}
//++=======================================================================
CasaStatus
InitializeHostNameNormalization(void)
//
// Arguments:
//
// Returns:
//
// Abstract:
//
// Notes:
//
// L2
//=======================================================================--
{
CasaStatus retStatus = CASA_STATUS_SUCCESS;
DbgTrace(1, "-InitializeHostNameNormalization- Start\n", 0);
// Initialize the cache list head
InitializeListHead(&normalizedHostNameCacheListHead);
DbgTrace(1, "-InitializeHostNameNormalization- End, retStatus = %08X\n", retStatus);
return retStatus;
}
//++=======================================================================
//++=======================================================================
//++=======================================================================

View File

@@ -0,0 +1,130 @@
/***********************************************************************
*
* Copyright (C) 2006 Novell, Inc. All Rights Reserved.
*
* 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 Lesser 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, Novell, Inc.
*
* To contact Novell about this file by physical or electronic mail,
* you may find current contact information at www.novell.com.
*
* Author: Juan Carlos Luciani <jluciani@novell.com>
*
***********************************************************************/
#define _GNU_SOURCE
//===[ Include files ]=====================================================
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <syslog.h>
#include <pthread.h>
#include <string.h>
#include <ctype.h>
#include <errno.h>
#include <dlfcn.h>
#include <unistd.h>
#include <sys/times.h>
#include <fcntl.h>
#include <netdb.h>
#include <curl/curl.h>
#include <stdarg.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
//===[ Type definitions ]==================================================
#ifndef CONTAINING_RECORD
#define CONTAINING_RECORD(address, type, field) ((type *)( \
(char*)(address) - \
(char*)(&((type *)0)->field)))
#endif
//
// DbgTrace macro define
//
#define DbgTrace(LEVEL, X, Y) { \
char printBuff[256]; \
if (LEVEL == 0 || DebugLevel >= LEVEL) \
{ \
_snprintf(printBuff, sizeof(printBuff), X, Y); \
fprintf(stderr, "CASA_AuthToken %s", printBuff); \
} \
}
/*#define DbgTrace(LEVEL, X, Y) { \
if (LEVEL == 0 || DebugLevel >= LEVEL) \
{ \
openlog("CASA_AuthToken", LOG_CONS | LOG_NOWAIT | LOG_ODELAY, LOG_USER); \
syslog(LOG_USER | LOG_INFO, X, Y); \
closelog(); \
} \
}*/
//
// Rpc Session definition
//
typedef struct _RpcSession
{
CURL *hCurl;
char *pPartialHttpUrl;
int partialHttpUrlLen;
char *pPartialHttpsUrl;
int partialHttpsUrlLen;
struct curl_slist *headers;
char *pRecvData;
int recvDataLen;
} RpcSession, *PRpcSession;
//
// Other definitions
//
#define HANDLE void*
#define LIB_HANDLE void*
#define DWORD unsigned long
#define AcquireModuleMutex pthread_mutex_lock(&g_hModuleMutex)
#define ReleaseModuleMutex pthread_mutex_unlock(&g_hModuleMutex)
//
// Deal with function name mapping issues
//
#define _snprintf snprintf
#define stricmp strcasecmp
//===[ Inlines functions ]===============================================
//===[ Function prototypes ]===============================================
//===[ Global externals ]==================================================
//===[ External prototypes ]===============================================
extern
DWORD
GetTickCount(void);
//===[ External data ]=====================================================
extern pthread_mutex_t g_hModuleMutex;
//=========================================================================

View File

@@ -0,0 +1,566 @@
/***********************************************************************
*
* Copyright (C) 2006 Novell, Inc. All Rights Reserved.
*
* 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 Lesser 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, Novell, Inc.
*
* To contact Novell about this file by physical or electronic mail,
* you may find current contact information at www.novell.com.
*
* Author: Juan Carlos Luciani <jluciani@novell.com>
*
***********************************************************************/
//===[ Include files ]=====================================================
#include "internal.h"
//===[ Type definitions ]==================================================
#define MAX_RPC_RETRIES 3
//===[ Function prototypes ]===============================================
//===[ Global variables ]==================================================
//++=======================================================================
size_t
CurlWriteCallback(
IN void *pData,
IN size_t dataItemSz,
IN size_t numDataItems,
IN RpcSession *pSession)
//
// Arguments:
//
// Returns:
//
// Abstract:
//
// Notes:
//
// L2
//=======================================================================--
{
size_t dataConsumed = numDataItems;
DbgTrace(1, "-CurlWriteCallback- Start\n", 0);
// Consume the data by keeping a copy of the data. Note that we may have
// already consumed some data in which case we need to allocate a new
// buffer big enough to hold all of it.
if (pSession->pRecvData == NULL)
{
// We have not yet consumed receive data for the current Rpc
pSession->pRecvData = (char*) malloc(numDataItems * dataItemSz);
if (pSession->pRecvData)
{
// Consume the data
memcpy(pSession->pRecvData, pData, numDataItems * dataItemSz);
pSession->recvDataLen = numDataItems * dataItemSz;
}
else
{
DbgTrace(0, "-CurlWriteCallback- Buffer allocation error\n", 0);
dataConsumed = CURLE_WRITE_ERROR; // To abort RPC
}
}
else
{
// We have already consumed receive data for the current Rpc, append the new data to it.
char *pNewRecvDataBuf = (char*) malloc(pSession->recvDataLen + (numDataItems * dataItemSz));
if (pNewRecvDataBuf)
{
memcpy(pNewRecvDataBuf, pSession->pRecvData, pSession->recvDataLen);
memcpy(pNewRecvDataBuf + pSession->recvDataLen, pData, numDataItems * dataItemSz);
pSession->recvDataLen += numDataItems * dataItemSz;
free(pSession->pRecvData);
pSession->pRecvData = pNewRecvDataBuf;
}
else
{
DbgTrace(0, "-CurlWriteCallback- Buffer allocation error\n", 0);
dataConsumed = CURLE_WRITE_ERROR; // To abort RPC
// Forget about already consumed data
free(pSession->pRecvData);
pSession->pRecvData = NULL;
}
}
DbgTrace(1, "-CurlWriteCallback- End\n", 0);
return dataConsumed;
}
//++=======================================================================
RpcSession*
OpenRpcSession(
IN const char *pHostName,
IN const uint16_t hostPort)
//
// Arguments:
//
// Returns:
//
// Abstract:
//
// Notes:
//
// L2
//=======================================================================--
{
RpcSession *pSession = NULL;
char *pPartialHttpUrl = NULL;
char *pPartialHttpsUrl = NULL;
int hostNameLen = strlen(pHostName);
DbgTrace(1, "-OpenRpcSession- Start\n", 0);
// Build the partial URL strings that may be used with this session.
pPartialHttpUrl = (char*) malloc(7 /*"http://"*/ + hostNameLen + 34 /*":XXXX/CasaAuthTokenSvc/Rpc?method="*/ + 1 /*NULL Terminator*/);
pPartialHttpsUrl = (char*) malloc(8 /*"https://"*/ + hostNameLen + 34 /*":XXXX/CasaAuthTokenSvc/Rpc?method="*/ + 1 /*NULL Terminator*/);
if (pPartialHttpUrl && pPartialHttpsUrl)
{
sprintf(pPartialHttpUrl, "http://%s:%d/CasaAuthTokenSvc/Rpc?method=", pHostName, hostPort);
sprintf(pPartialHttpsUrl, "https://%s:%d/CasaAuthTokenSvc/Rpc?method=", pHostName, hostPort);
// Allocate space for the session
pSession = (RpcSession*) malloc(sizeof(*pSession));
if (pSession)
{
// Zero the session structure
memset(pSession, 0, sizeof(*pSession));
// Get a curl handle
pSession->hCurl = curl_easy_init();
if (pSession->hCurl != NULL)
{
CURLcode result;
bool setOptError = false;
// Set necessary options on the handle
if ((result = curl_easy_setopt(pSession->hCurl, CURLOPT_NOSIGNAL, 0)) != CURLE_OK)
{
DbgTrace(0, "-OpenRpcSession- Error setting CURLOPT_NOSIGNAL, code = %d\n", result);
setOptError = true;
}
if ((result = curl_easy_setopt(pSession->hCurl, CURLOPT_USERAGENT, "CASA Client/1.0")) != CURLE_OK)
{
DbgTrace(0, "-OpenRpcSession- Error setting CURLOPT_USERAGENT, code = %d\n", result);
setOptError = true;
}
if ((result = curl_easy_setopt(pSession->hCurl, CURLOPT_POST, 1)) != CURLE_OK)
{
DbgTrace(0, "-OpenRpcSession- Error setting CURLOPT_POST, code = %d\n", result);
setOptError = true;
}
pSession->headers = curl_slist_append(pSession->headers, "Content-Type: text/html");
pSession->headers = curl_slist_append(pSession->headers, "Expect:");
if ((result = curl_easy_setopt(pSession->hCurl, CURLOPT_HTTPHEADER, pSession->headers)) != CURLE_OK)
{
DbgTrace(0, "-OpenRpcSession- Error setting CURLOPT_HTTPHEADER, code = %d\n", result);
setOptError = true;
}
if ((result = curl_easy_setopt(pSession->hCurl, CURLOPT_WRITEFUNCTION, CurlWriteCallback)) != CURLE_OK)
{
DbgTrace(0, "-OpenRpcSession- Error setting CURLOPT_WRITEFUNCTION, code = %d\n", result);
setOptError = true;
}
if ((result = curl_easy_setopt(pSession->hCurl, CURLOPT_WRITEDATA, pSession)) != CURLE_OK)
{
DbgTrace(0, "-OpenRpcSession- Error setting CURLOPT_WRITEDATA, code = %d\n", result);
setOptError = true;
}
// Now check if we succeded
if (setOptError == false)
{
// Success, finish setting up the session object.
pSession->pPartialHttpUrl = pPartialHttpUrl;
pSession->partialHttpUrlLen = strlen(pPartialHttpUrl);
pSession->pPartialHttpsUrl = pPartialHttpsUrl;
pSession->partialHttpsUrlLen = strlen(pPartialHttpsUrl);
// Forget about the partial URL buffers so that they do not get deleted below
pPartialHttpUrl = NULL;
pPartialHttpsUrl = NULL;
}
else
{
// Failed to set a needed curl option
if (pSession->headers)
curl_slist_free_all(pSession->headers);
curl_easy_cleanup(pSession->hCurl);
free(pSession);
pSession = NULL;
}
}
else
{
DbgTrace(0, "-OpenRpcSession- Error creating curl handle\n", 0);
free(pSession);
pSession = NULL;
}
}
else
{
DbgTrace(0, "-OpenRpcSession- Failed to allocate buffer for rpc session\n", 0);
}
}
else
{
DbgTrace(0, "-OpenRpcSession- Failed to allocate buffer for URL\n", 0);
}
// Free buffers not utilized
if (pPartialHttpUrl)
free(pPartialHttpUrl);
if (pPartialHttpsUrl)
free(pPartialHttpsUrl);
DbgTrace(2, "-OpenRpcSession- End, pSession = %0lX\n", (long) pSession);
return pSession;
}
//++=======================================================================
void
CloseRpcSession(
IN RpcSession *pSession)
//
// Arguments:
//
// Returns:
//
// Abstract:
//
// Notes:
//
// L2
//=======================================================================--
{
DbgTrace(1, "-CloseRpcSession- Start\n", 0);
// Free any HTTP headers associated with the session
if (pSession->headers)
curl_slist_free_all(pSession->headers);
// Close the curl handle associated with this session
curl_easy_cleanup(pSession->hCurl);
// Free the space allocated for the session
if (pSession->pRecvData)
free(pSession->pRecvData);
free(pSession->pPartialHttpUrl);
free(pSession->pPartialHttpsUrl);
free(pSession);
DbgTrace(1, "-CloseRpcSession- End\n", 0);
}
//++=======================================================================
static
CasaStatus
InternalRpc(
IN RpcSession *pSession,
IN char *pMethod,
IN long flags,
IN char *pRequestData,
INOUT char **ppResponseData,
INOUT int *pResponseDataLen)
//
// Arguments:
//
// Returns:
//
// Abstract:
//
// Notes:
//
// L2
//=======================================================================--
{
#define CASA_STATUS_INVALID_SERVER_CERTIFICATE CASA_STATUS_UNSUCCESSFUL // temporary until casa_status.h is updated
CasaStatus retStatus;
char *pPartialUrl;
int partialUrlLen;
char *pUrl;
CURLcode curlResult;
DbgTrace(1, "-InternalRpc- Start\n", 0);
// Initialize output parameters
*ppResponseData = NULL;
*pResponseDataLen = 0;
// Setup the URL using the input parameters
if (flags & SECURE_RPC_FLAG)
{
pPartialUrl = pSession->pPartialHttpsUrl;
partialUrlLen = pSession->partialHttpsUrlLen;
// Check if we need to ignore invalid CERTS
if (flags & ALLOW_INVALID_CERTS_RPC_FLAG)
{
if ((curlResult = curl_easy_setopt(pSession->hCurl, CURLOPT_SSL_VERIFYPEER, 0)) != CURLE_OK)
{
DbgTrace(0, "-InternalRpc- Error setting CURLOPT_SSL_VERIFYPEER, code = %d\n", curlResult);
}
if ((curlResult = curl_easy_setopt(pSession->hCurl, CURLOPT_SSL_VERIFYHOST, 0)) != CURLE_OK)
{
DbgTrace(0, "-InternalRpc- Error setting CURLOPT_SSL_VERIFYHOST, code = %d\n", curlResult);
}
}
else
{
if ((curlResult = curl_easy_setopt(pSession->hCurl, CURLOPT_SSL_VERIFYPEER, 1)) != CURLE_OK)
{
DbgTrace(0, "-InternalRpc- Error setting CURLOPT_SSL_VERIFYPEER, code = %d\n", curlResult);
}
if ((curlResult = curl_easy_setopt(pSession->hCurl, CURLOPT_SSL_VERIFYHOST, 2)) != CURLE_OK)
{
DbgTrace(0, "-InternalRpc- Error setting CURLOPT_SSL_VERIFYHOST, code = %d\n", curlResult);
}
}
}
else
{
pPartialUrl = pSession->pPartialHttpUrl;
partialUrlLen = pSession->partialHttpUrlLen;
}
pUrl = (char*) malloc(partialUrlLen + strlen(pMethod) + 1);
if (pUrl)
{
strcpy(pUrl, pPartialUrl);
strcat(pUrl, pMethod);
// Tell curl about the URL
curlResult = curl_easy_setopt(pSession->hCurl, CURLOPT_URL, pUrl);
if (curlResult == CURLE_OK)
{
// Tell curl about our post data
curlResult = curl_easy_setopt(pSession->hCurl, CURLOPT_POSTFIELDS, pRequestData);
if (curlResult == CURLE_OK)
{
// Tell curl about our post data len
curlResult = curl_easy_setopt(pSession->hCurl, CURLOPT_POSTFIELDSIZE, strlen(pRequestData));
if (curlResult == CURLE_OK)
{
// Now do the HTTP request
curlResult = curl_easy_perform(pSession->hCurl);
if (curlResult == CURLE_OK)
{
// Get the HTTP Response code
long httpCompStatus;
curlResult = curl_easy_getinfo(pSession->hCurl, CURLINFO_RESPONSE_CODE, &httpCompStatus);
if (curlResult == CURLE_OK)
{
// Verify that the HTTP request was successfully completed by the server
if (httpCompStatus == 200)
{
// Success, return the response data to the caller.
retStatus = CASA_STATUS_SUCCESS;
*ppResponseData = pSession->pRecvData;
*pResponseDataLen = pSession->recvDataLen;;
// Forget about the response data buffer to keep from freeing it.
pSession->pRecvData = NULL;
}
else
{
DbgTrace(0, "-InternalRpc- HTTP request did not complete successfully, status = %ld\n", httpCompStatus);
retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR,
CASA_FACILITY_AUTHTOKEN,
CASA_STATUS_UNSUCCESSFUL);
}
}
else
{
DbgTrace(0, "-OpenRpcSession- Curl get info failed, code = %d\n", curlResult);
retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR,
CASA_FACILITY_AUTHTOKEN,
CASA_STATUS_UNSUCCESSFUL);
}
}
else
{
DbgTrace(0, "-OpenRpcSession- Curl perform failed, code = %d\n", curlResult);
retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR,
CASA_FACILITY_AUTHTOKEN,
CASA_STATUS_UNSUCCESSFUL);
}
// Make sure that we never exit with a recv data buffer hanging off the session
if (pSession->pRecvData)
{
free(pSession->pRecvData);
pSession->pRecvData = NULL;
}
}
else
{
DbgTrace(0, "-OpenRpcSession- Error setting CURLOPT_POSTFIELDSIZE, code = %d\n", curlResult);
retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR,
CASA_FACILITY_AUTHTOKEN,
CASA_STATUS_UNSUCCESSFUL);
}
}
else
{
DbgTrace(0, "-OpenRpcSession- Error setting CURLOPT_POSTFIELDS, code = %d\n", curlResult);
retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR,
CASA_FACILITY_AUTHTOKEN,
CASA_STATUS_UNSUCCESSFUL);
}
}
else
{
DbgTrace(0, "-OpenRpcSession- Error setting CURLOPT_URL, code = %d\n", curlResult);
retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR,
CASA_FACILITY_AUTHTOKEN,
CASA_STATUS_UNSUCCESSFUL);
}
// Free the buffer used to hold the URL
free(pUrl);
}
else
{
DbgTrace(0, "-InternalRpc- Buffer allocation failure\n", 0);
retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR,
CASA_FACILITY_AUTHTOKEN,
CASA_STATUS_INSUFFICIENT_RESOURCES);
}
DbgTrace(1, "-InternalRpc- End, retStatus = %d\n", retStatus);
return retStatus;
}
//++=======================================================================
CasaStatus
Rpc(
IN RpcSession *pSession,
IN char *pMethod,
IN long flags,
IN char *pRequestData,
INOUT char **ppResponseData,
INOUT int *pResponseDataLen)
//
// Arguments:
//
// Returns:
//
// Abstract:
//
// Notes:
//
// L2
//=======================================================================--
{
CasaStatus retStatus;
int retries = 0;
DbgTrace(1, "-Rpc- Start\n", 0);
// Retry the RPC as needed
do
{
// Issue the RPC
retStatus = InternalRpc(pSession,
pMethod,
flags,
pRequestData,
ppResponseData,
pResponseDataLen);
// Account for this try
retries ++;
} while (CasaStatusCode(retStatus) == CASA_STATUS_AUTH_SERVER_UNAVAILABLE
&& retries < MAX_RPC_RETRIES);
DbgTrace(1, "-Rpc- End, retStatus = %d\n", retStatus);
return retStatus;
}
//++=======================================================================
CasaStatus
InitializeRpc(void)
//
// Arguments:
//
// Returns:
//
// Abstract:
//
// Notes:
//
// L2
//=======================================================================--
{
CasaStatus retStatus;
DbgTrace(1, "-InitializeRpc- Start\n", 0);
// Perform libcurl initializatoin
CURLcode curlStatus = curl_global_init(CURL_GLOBAL_SSL);
if (curlStatus != 0)
{
DbgTrace(0, "-InitializeRpc- Error initializing libcurl, curlStatus = %08X\n", curlStatus);
retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR,
CASA_FACILITY_AUTHTOKEN,
CASA_STATUS_UNSUCCESSFUL);
}
else
{
// Success
retStatus = CASA_STATUS_SUCCESS;
}
DbgTrace(1, "-InitializeRpc- End, retStatus = %08X\n", retStatus);
return retStatus;
}
//++=======================================================================
//++=======================================================================
//++=======================================================================