mirror of https://github.com/Cisco-Talos/clamav
parent
cfacfb45dc
commit
2b888381b0
@ -0,0 +1,884 @@ |
||||
/*
|
||||
* Copyright (c) 2007 by Apple Computer, Inc., All Rights Reserved. |
||||
* Copyright (c) 2011 Sourcefire, Inc. |
||||
*/ |
||||
|
||||
#include <kern/assert.h> |
||||
#include <mach/mach_types.h> |
||||
#include <libkern/libkern.h> |
||||
#include <libkern/OSAtomic.h> |
||||
#include <libkern/OSMalloc.h> |
||||
#include <sys/sysctl.h> |
||||
#include <sys/kauth.h> |
||||
#include <sys/vnode.h> |
||||
|
||||
#pragma mark ***** Global Resources |
||||
/* These declarations are required to allocate memory and create locks.
|
||||
* They're created when we start and destroyed when we stop. |
||||
*/ |
||||
|
||||
static OSMallocTag gMallocTag = NULL; |
||||
static lck_grp_t * gLockGroup = NULL; |
||||
|
||||
#pragma mark ***** Vnode Utilities |
||||
/* VnodeActionInfo describes one of the action bits in the vnode scope's action
|
||||
* field. |
||||
*/ |
||||
|
||||
struct VnodeActionInfo { |
||||
kauth_action_t fMask; /* only one bit should be set */ |
||||
const char * fOpNameFile; /* descriptive name of the bit for files */ |
||||
const char * fOpNameDir; /* descriptive name of the bit for directories
|
||||
* NULL implies equivalent to fOpNameFile |
||||
*/ |
||||
}; |
||||
typedef struct VnodeActionInfo VnodeActionInfo; |
||||
|
||||
/* Some evil macros (aren't they all) to make it easier to initialise kVnodeActionInfo. */ |
||||
#define VNODE_ACTION(action) { KAUTH_VNODE_ ## action, #action, NULL } |
||||
#define VNODE_ACTION_FILEDIR(actionFile, actionDir) { KAUTH_VNODE_ ## actionFile, #actionFile, #actionDir } |
||||
|
||||
/* kVnodeActionInfo is a table of all the known action bits and their human readable names. */ |
||||
static const VnodeActionInfo kVnodeActionInfo[] = { |
||||
VNODE_ACTION_FILEDIR(READ_DATA, LIST_DIRECTORY), |
||||
VNODE_ACTION_FILEDIR(WRITE_DATA, ADD_FILE), |
||||
VNODE_ACTION_FILEDIR(EXECUTE, SEARCH), |
||||
VNODE_ACTION(DELETE), |
||||
VNODE_ACTION_FILEDIR(APPEND_DATA, ADD_SUBDIRECTORY), |
||||
VNODE_ACTION(DELETE_CHILD), |
||||
VNODE_ACTION(READ_ATTRIBUTES), |
||||
VNODE_ACTION(WRITE_ATTRIBUTES), |
||||
VNODE_ACTION(READ_EXTATTRIBUTES), |
||||
VNODE_ACTION(WRITE_EXTATTRIBUTES), |
||||
VNODE_ACTION(READ_SECURITY), |
||||
VNODE_ACTION(WRITE_SECURITY), |
||||
VNODE_ACTION(TAKE_OWNERSHIP), |
||||
VNODE_ACTION(SYNCHRONIZE), |
||||
VNODE_ACTION(LINKTARGET), |
||||
VNODE_ACTION(CHECKIMMUTABLE), |
||||
VNODE_ACTION(ACCESS), |
||||
VNODE_ACTION(NOIMMUTABLE) |
||||
}; |
||||
|
||||
#define kVnodeActionInfoCount (sizeof(kVnodeActionInfo) / sizeof(*kVnodeActionInfo)) |
||||
|
||||
static int CreateVnodeActionString( |
||||
kauth_action_t action,
|
||||
boolean_t isDir,
|
||||
char ** actionStrPtr,
|
||||
size_t * actionStrBufSizePtr |
||||
) |
||||
/* Creates a human readable description of a vnode action bitmap.
|
||||
* action is the bitmap. isDir is true if the action relates to a
|
||||
* directory, and false otherwise. This allows the action name to
|
||||
* be context sensitive (KAUTH_VNODE_EXECUTE vs KAUTH_VNODE_SEARCH). |
||||
* actionStrPtr is a place to store the allocated string pointer.
|
||||
* The caller is responsible for freeing this memory using OSFree. |
||||
* actionStrBufSizePtr is a place to store the size of the resulting
|
||||
* allocation (because the annoying kernel memory allocator requires
|
||||
* you to provide the size when you free). |
||||
*/ |
||||
{ |
||||
int err; |
||||
enum { kCalcLen, kCreateString } pass; |
||||
kauth_action_t actionsLeft; |
||||
unsigned int infoIndex; |
||||
size_t actionStrLen; |
||||
char * actionStr; |
||||
|
||||
assert( actionStrPtr != NULL); |
||||
assert(*actionStrPtr != NULL); |
||||
assert( actionStrBufSizePtr != NULL); |
||||
|
||||
err = 0; |
||||
|
||||
actionStr = NULL; |
||||
|
||||
/* A two pass algorithm. In the first pass, actionStr is NULL and we just
|
||||
* calculate actionStrLen; at the end of the first pass we actually allocate
|
||||
* actionStr. In the second pass, actionStr is not NULL and we actually
|
||||
* initialise the string in that buffer. |
||||
*/ |
||||
|
||||
for (pass = kCalcLen; pass <= kCreateString; pass++) { |
||||
actionsLeft = action; |
||||
|
||||
/* Process action bits that are described in kVnodeActionInfo. */
|
||||
infoIndex = 0; |
||||
actionStrLen = 0; |
||||
while ( (actionsLeft != 0) && (infoIndex < kVnodeActionInfoCount) ) { |
||||
if ( actionsLeft & kVnodeActionInfo[infoIndex].fMask ) { |
||||
const char * thisStr; |
||||
size_t thisStrLen; |
||||
|
||||
/* Increment the length of the action string by the action name. */
|
||||
if ( isDir && (kVnodeActionInfo[infoIndex].fOpNameDir != NULL) ) { |
||||
thisStr = kVnodeActionInfo[infoIndex].fOpNameDir; |
||||
} else { |
||||
thisStr = kVnodeActionInfo[infoIndex].fOpNameFile; |
||||
} |
||||
thisStrLen = strlen(thisStr); |
||||
|
||||
if (actionStr != NULL) { |
||||
memcpy(&actionStr[actionStrLen], thisStr, thisStrLen); |
||||
} |
||||
actionStrLen += thisStrLen; |
||||
|
||||
/* Now clear the bit in actionsLeft, indicating that we've
|
||||
* processed this one. |
||||
*/ |
||||
actionsLeft &= ~kVnodeActionInfo[infoIndex].fMask; |
||||
|
||||
/* If there's any actions left, account for the intervening "|". */ |
||||
if (actionsLeft != 0) { |
||||
if (actionStr != NULL) { |
||||
actionStr[actionStrLen] = '|'; |
||||
} |
||||
actionStrLen += 1; |
||||
} |
||||
} |
||||
infoIndex += 1; |
||||
} |
||||
|
||||
/* Now include any remaining actions as a hex number. */ |
||||
if (actionsLeft != 0) { |
||||
if (actionStr != NULL) |
||||
snprintf(&actionStr[actionStrLen], 10, "0x%08x", actionsLeft); |
||||
actionStrLen += 10; /* strlen("0x") + 8 chars of hex */ |
||||
} |
||||
|
||||
/* If we're at the end of the first pass, allocate actionStr
|
||||
* based on the size we just calculated. Remember that actionStrLen
|
||||
* is a string length, so we have to allocate an extra character to
|
||||
* account for the null terminator. If we're at the end of the
|
||||
* second pass, just place the null terminator. |
||||
*/ |
||||
if (pass == kCalcLen) { |
||||
actionStr = OSMalloc(actionStrLen + 1, gMallocTag); |
||||
if (actionStr == NULL) { |
||||
err = ENOMEM; |
||||
} |
||||
} else { |
||||
actionStr[actionStrLen] = 0; |
||||
} |
||||
|
||||
if (err != 0) { |
||||
break; |
||||
} |
||||
} |
||||
|
||||
*actionStrPtr = actionStr; |
||||
*actionStrBufSizePtr = actionStrLen + 1; |
||||
|
||||
assert( (err == 0) == (*actionStrPtr != NULL) ); |
||||
|
||||
return err; |
||||
} |
||||
|
||||
static int CreateVnodePath(vnode_t vp, char **vpPathPtr) |
||||
/* Creates a full path for a vnode. vp may be NULL, in which
|
||||
* case the returned path is NULL (that is, no memory is allocated). |
||||
* vpPathPtr is a place to store the allocated path buffer.
|
||||
* The caller is responsible for freeing this memory using OSFree
|
||||
* (the size is always MAXPATHLEN). |
||||
*/ |
||||
{ |
||||
int err; |
||||
int pathLen; |
||||
|
||||
assert( vpPathPtr != NULL); |
||||
assert(*vpPathPtr == NULL); |
||||
|
||||
err = 0; |
||||
if (vp != NULL) { |
||||
*vpPathPtr = OSMalloc(MAXPATHLEN, gMallocTag); |
||||
if (*vpPathPtr == NULL) { |
||||
err = ENOMEM; |
||||
} |
||||
if (err == 0) { |
||||
pathLen = MAXPATHLEN; |
||||
err = vn_getpath(vp, *vpPathPtr, &pathLen); |
||||
} |
||||
} |
||||
|
||||
return err; |
||||
} |
||||
|
||||
#pragma mark ***** Listener Resources |
||||
|
||||
/* Some scopes (for example KAUTH_SCOPE_VNODE) are called a /lot/. Thus,
|
||||
* it's a good idea to avoid taking mutexes in your listener if at all
|
||||
* possible. Thus, we use non-blocking synchronisation to protect the
|
||||
* global data that's accessed by our listener (gPrefix and gListenerScope).
|
||||
* Every time we enter a listener, we increment gActivationCount, and ever
|
||||
* time we leave we decrement it. When we want to change the listener, we
|
||||
* first remove the listener, then we wait for the activation count to hit,
|
||||
* then we can modify the globals protected by that activation count. |
||||
* |
||||
* IMPORTANT: |
||||
* There is still a race condition here. See RemoveListener for a description
|
||||
* of the race and why we can't fix it. |
||||
*/ |
||||
|
||||
static SInt32 gActivationCount = 0; |
||||
|
||||
static const char * gPrefix = NULL; /* points into gConfiguration, so doesn't need to be freed */ |
||||
|
||||
static char * gListenerScope = NULL; /* must be freed using OSFree */ |
||||
|
||||
static int GenericScopeListener( |
||||
kauth_cred_t credential, |
||||
void * idata, |
||||
kauth_action_t action, |
||||
uintptr_t arg0, |
||||
uintptr_t arg1, |
||||
uintptr_t arg2, |
||||
uintptr_t arg3 |
||||
) |
||||
/* A Kauth listener that's called to authorize an action in the generic
|
||||
* scope (KAUTH_SCOPE_GENERIC). See the Kauth documentation for a description
|
||||
* of the parameters. In this case, we just dump out the parameters to the
|
||||
* operation and return KAUTH_RESULT_DEFER, allowing the other listeners
|
||||
* to decide whether the operation is allowed or not. |
||||
*/ |
||||
{ |
||||
#pragma unused(idata) |
||||
#pragma unused(arg0) |
||||
#pragma unused(arg1) |
||||
#pragma unused(arg2) |
||||
#pragma unused(arg3) |
||||
|
||||
(void) OSIncrementAtomic(&gActivationCount); |
||||
|
||||
/* Tell the user about this request. */ |
||||
switch (action) { |
||||
case KAUTH_GENERIC_ISSUSER: |
||||
printf( |
||||
"scope=" KAUTH_SCOPE_GENERIC ", action=KAUTH_GENERIC_ISSUSER, actor=%ld\n",
|
||||
(long) kauth_cred_getuid(credential) |
||||
); |
||||
break; |
||||
default: |
||||
printf("ClamAuth.GenericScopeListener: Unknown action (%d).\n", action); |
||||
break; |
||||
} |
||||
|
||||
(void) OSDecrementAtomic(&gActivationCount); |
||||
|
||||
return KAUTH_RESULT_DEFER; |
||||
} |
||||
|
||||
static int ProcessScopeListener( |
||||
kauth_cred_t credential, |
||||
void * idata, |
||||
kauth_action_t action, |
||||
uintptr_t arg0, |
||||
uintptr_t arg1, |
||||
uintptr_t arg2, |
||||
uintptr_t arg3 |
||||
) |
||||
/* A Kauth listener that's called to authorize an action in the process
|
||||
* scope (KAUTH_SCOPE_PROCESS). See the Kauth documentation for a description
|
||||
* of the parameters. In this case, we just dump out the parameters to the
|
||||
* operation and return KAUTH_RESULT_DEFER, allowing the other listeners
|
||||
* to decide whether the operation is allowed or not. |
||||
*/ |
||||
{ |
||||
#pragma unused(idata) |
||||
#pragma unused(arg2) |
||||
#pragma unused(arg3) |
||||
|
||||
(void) OSIncrementAtomic(&gActivationCount); |
||||
|
||||
/* Tell the user about this request. */ |
||||
switch (action) { |
||||
case KAUTH_PROCESS_CANSIGNAL: |
||||
printf( |
||||
"scope=" KAUTH_SCOPE_PROCESS ", action=KAUTH_PROCESS_CANSIGNAL, uid=%ld, pid=%ld, target=%ld, signal=%ld\n",
|
||||
(long) kauth_cred_getuid(credential), |
||||
(long) proc_selfpid(), |
||||
(long) proc_pid((proc_t) arg0), |
||||
(long) arg1 |
||||
); |
||||
break; |
||||
case KAUTH_PROCESS_CANTRACE: |
||||
printf( |
||||
"scope=" KAUTH_SCOPE_PROCESS ", action=KAUTH_PROCESS_CANTRACE, uid=%ld, pid=%ld, target=%ld\n",
|
||||
(long) kauth_cred_getuid(credential), |
||||
(long) proc_selfpid(), |
||||
(long) proc_pid((proc_t) arg0) |
||||
); |
||||
break; |
||||
default: |
||||
printf("ClamAuth.ProcessScopeListener: Unknown action (%d).\n", action); |
||||
break; |
||||
} |
||||
|
||||
(void) OSDecrementAtomic(&gActivationCount); |
||||
|
||||
return KAUTH_RESULT_DEFER; |
||||
} |
||||
|
||||
static int VnodeScopeListener( |
||||
kauth_cred_t credential, |
||||
void * idata, |
||||
kauth_action_t action, |
||||
uintptr_t arg0, |
||||
uintptr_t arg1, |
||||
uintptr_t arg2, |
||||
uintptr_t arg3 |
||||
) |
||||
/* A Kauth listener that's called to authorize an action in the vnode scope */ |
||||
{ |
||||
#pragma unused(credential) |
||||
#pragma unused(idata) |
||||
#pragma unused(arg3) |
||||
int err; |
||||
vfs_context_t context; |
||||
vnode_t vp; |
||||
vnode_t dvp; |
||||
char * vpPath; |
||||
char * dvpPath; |
||||
boolean_t isDir; |
||||
char * actionStr; |
||||
size_t actionStrBufSize; |
||||
|
||||
actionStrBufSize = 0; |
||||
|
||||
(void) OSIncrementAtomic(&gActivationCount); |
||||
|
||||
context = (vfs_context_t) arg0; |
||||
vp = (vnode_t) arg1; |
||||
dvp = (vnode_t) arg2; |
||||
|
||||
vpPath = NULL; |
||||
dvpPath = NULL; |
||||
actionStr = NULL; |
||||
|
||||
/* Convert the vnode, if any, to a path. */ |
||||
err = CreateVnodePath(vp, &vpPath); |
||||
|
||||
/* Convert the parent directory vnode, if any, to a path. */ |
||||
if (err == 0) |
||||
err = CreateVnodePath(dvp, &dvpPath); |
||||
|
||||
/* Create actionStr as a human readable description of action. */ |
||||
if (err == 0) { |
||||
if (vp != NULL) { |
||||
isDir = ( vnode_vtype(vp) == VDIR ); |
||||
} else { |
||||
isDir = FALSE; |
||||
} |
||||
err = CreateVnodeActionString(action, isDir, &actionStr, &actionStrBufSize); |
||||
} |
||||
|
||||
/* Tell the user about this request. Note that we filter requests
|
||||
* based on gPrefix. If gPrefix is set, only requests where one
|
||||
* of the paths is prefixed by gPrefix will be printed. |
||||
*/
|
||||
if (err == 0) { |
||||
if ( (gPrefix == NULL)
|
||||
|| ( ( (vpPath != NULL) && strprefix(vpPath, gPrefix) )
|
||||
|| ( (dvpPath != NULL) && strprefix(dvpPath, gPrefix) )
|
||||
)
|
||||
) { |
||||
printf( |
||||
"scope=" KAUTH_SCOPE_VNODE ", action=%s, uid=%ld, vp=%s, dvp=%s\n",
|
||||
actionStr, |
||||
(long) kauth_cred_getuid(vfs_context_ucred(context)), |
||||
(vpPath != NULL) ? vpPath : "<null>", |
||||
(dvpPath != NULL) ? dvpPath : "<null>" |
||||
);
|
||||
} |
||||
} else { |
||||
printf("ClamAuth.VnodeScopeListener: Error %d.\n", err); |
||||
} |
||||
|
||||
/* Clean up. */ |
||||
if (actionStr != NULL) { |
||||
OSFree(actionStr, actionStrBufSize, gMallocTag); |
||||
} |
||||
if (vpPath != NULL) { |
||||
OSFree(vpPath, MAXPATHLEN, gMallocTag); |
||||
} |
||||
if (dvpPath != NULL) { |
||||
OSFree(dvpPath, MAXPATHLEN, gMallocTag); |
||||
} |
||||
|
||||
(void) OSDecrementAtomic(&gActivationCount); |
||||
|
||||
return KAUTH_RESULT_DEFER; |
||||
} |
||||
|
||||
static int FileOpScopeListener( |
||||
kauth_cred_t credential, |
||||
void * idata, |
||||
kauth_action_t action, |
||||
uintptr_t arg0, |
||||
uintptr_t arg1, |
||||
uintptr_t arg2, |
||||
uintptr_t arg3 |
||||
) |
||||
/* A Kauth listener that's called to authorize an action in the file operation */ |
||||
{ |
||||
#pragma unused(idata) |
||||
#pragma unused(arg2) |
||||
#pragma unused(arg3) |
||||
|
||||
(void) OSIncrementAtomic(&gActivationCount); |
||||
|
||||
/* Tell the user about this request. Note that we filter requests
|
||||
* based on gPrefix. If gPrefix is set, only requests there is a
|
||||
* path that's prefixed by gPrefix will be printed. |
||||
*/ |
||||
|
||||
switch (action) { |
||||
case KAUTH_FILEOP_OPEN: |
||||
if ( (gPrefix == NULL) || strprefix( (const char *) arg1, gPrefix) ) { |
||||
printf( |
||||
"scope=" KAUTH_SCOPE_FILEOP ", action=KAUTH_FILEOP_OPEN, uid=%ld, vnode=0x%lx, path=%s\n",
|
||||
(long) kauth_cred_getuid(credential), |
||||
(long) arg0, |
||||
(const char *) arg1 |
||||
); |
||||
} |
||||
break; |
||||
case KAUTH_FILEOP_EXEC: |
||||
if ( (gPrefix == NULL) || strprefix( (const char *) arg1, gPrefix) ) { |
||||
printf( |
||||
"scope=" KAUTH_SCOPE_FILEOP ", action=KAUTH_FILEOP_EXEC, uid=%ld, vnode=0x%lx, path=%s\n",
|
||||
(long) kauth_cred_getuid(credential), |
||||
(long) arg0, |
||||
(const char *) arg1 |
||||
); |
||||
} |
||||
break; |
||||
default: |
||||
printf("ClamAuth.FileOpScopeListener: Unknown action (%d).\n", action); |
||||
break; |
||||
} |
||||
|
||||
(void) OSDecrementAtomic(&gActivationCount); |
||||
|
||||
return KAUTH_RESULT_DEFER; |
||||
} |
||||
|
||||
static int UnknownScopeListener( |
||||
kauth_cred_t credential, |
||||
void * idata, |
||||
kauth_action_t action, |
||||
uintptr_t arg0, |
||||
uintptr_t arg1, |
||||
uintptr_t arg2, |
||||
uintptr_t arg3 |
||||
) |
||||
/* A Kauth listener that's called to authorize an action in any scope
|
||||
* that we don't recognise). |
||||
*/ |
||||
{ |
||||
#pragma unused(idata) |
||||
|
||||
(void) OSIncrementAtomic(&gActivationCount); |
||||
|
||||
/* Tell the user about this request. */ |
||||
printf( |
||||
"scope=%s, action=%d, uid=%ld, arg0=0x%lx, arg1=0x%lx, arg2=0x%lx, arg3=0x%lx\n",
|
||||
gListenerScope, |
||||
action, |
||||
(long) kauth_cred_getuid(credential), |
||||
(long) arg0, |
||||
(long) arg1, |
||||
(long) arg2, |
||||
(long) arg3 |
||||
); |
||||
|
||||
(void) OSDecrementAtomic(&gActivationCount); |
||||
|
||||
return KAUTH_RESULT_DEFER; |
||||
} |
||||
|
||||
#pragma mark ***** Listener Install/Remove |
||||
|
||||
/* gConfigurationLock is a mutex that protects us from two threads trying to
|
||||
* simultaneously modify the configuration. The configuration is protect in
|
||||
* N ways: |
||||
* |
||||
* o During startup, we register our sysctl OID last, so no one can start
|
||||
* modifying the configuration until everything is set up nicely. |
||||
*
|
||||
* o During normal operations, the sysctl handler (SysctlHandler) takes
|
||||
* the lock to prevent two threads from reconfiguring the system at the
|
||||
* same time. |
||||
* |
||||
* o During termination, the stop routine first removes the sysctl OID
|
||||
* and then takes the lock before it removes the listener. The first
|
||||
* act prevents any new sysctl requests coming it, the second blocks
|
||||
* until current sysctl requests are done. |
||||
* |
||||
* IMPORTANT: |
||||
* There is still a race condition here. See the stop routine for a description
|
||||
* of the race and why we can't fix it. |
||||
*/ |
||||
|
||||
static lck_mtx_t * gConfigurationLock = NULL; |
||||
|
||||
/* gListener is our handle to the installed scope listener. We need to
|
||||
* keep it around so that we can remove the listener when we're done. |
||||
*/ |
||||
|
||||
static kauth_listener_t gListener = NULL; |
||||
|
||||
static void RemoveListener(void) |
||||
/* Removes the installed scope listener, if any.
|
||||
* |
||||
* Under almost all circumstances this routine runs under the
|
||||
* gConfigurationLock. The only time that this might not be the case
|
||||
* is when the KEXT's start routine fails prior to gConfigurationLock
|
||||
* being created. |
||||
*/ |
||||
{ |
||||
/* First prevent any more threads entering our listener. */ |
||||
if (gListener != NULL) { |
||||
kauth_unlisten_scope(gListener); |
||||
gListener = NULL; |
||||
} |
||||
|
||||
/* Then wait for any threads within out listener to stop. Note that there
|
||||
* is still a race condition here; there could still be a thread executing
|
||||
* between the OSDecrementAtomic and the return from the listener function
|
||||
* (for example, FileOpScopeListener). However, there's no way to close
|
||||
* this race because of the weak concurrency guarantee for kauth_unlisten_scope. |
||||
* Moreover, the window is very small and, seeing as this only happens during
|
||||
* reconfiguration, I'm not too worried. However, I am worried enough
|
||||
* to ensure that this loop runs at least once, so we always delay the teardown
|
||||
* for at least one second waiting for the threads to drain from our
|
||||
* listener. |
||||
*/ |
||||
|
||||
do { |
||||
struct timespec oneSecond; |
||||
|
||||
oneSecond.tv_sec = 1; |
||||
oneSecond.tv_nsec = 0; |
||||
|
||||
(void) msleep(&gActivationCount, NULL, PUSER, "com_apple_dts_kext_ClamAuth.RemoveListener", &oneSecond); |
||||
} while ( gActivationCount > 0 ); |
||||
|
||||
/* gListenerScope and gPrefix are both accessed by the listener callbacks
|
||||
* without taking any form of lock. So, we don't destroy them until after
|
||||
* all the listener callbacks have drained. |
||||
*/ |
||||
|
||||
if (gListenerScope != NULL) { |
||||
OSFree(gListenerScope, strlen(gListenerScope) + 1, gMallocTag); |
||||
gListenerScope = NULL; |
||||
} |
||||
gPrefix = NULL; |
||||
} |
||||
|
||||
static void InstallListener(const char *scope, size_t scopeLen, const char *prefix) |
||||
/* Installs a listener for the specified scope. scope and scopeLen specifies
|
||||
* the scope to listen for. prefix is a parameter for the scope listener.
|
||||
* It may be NULL. |
||||
* |
||||
* prefix points into the gConfiguration global variable, so this routine
|
||||
* doesn't make a copy of it. However, it has to make a copy of scope
|
||||
* because scope can point to a place in the middle of the gConfiguration
|
||||
* variable, so there's no guarantee it's null terminated (which we need it
|
||||
* to be in order to call kauth_listen_scope. |
||||
* |
||||
* This routine always runs under the gConfigurationLock. |
||||
*/ |
||||
{ |
||||
kauth_scope_callback_t callback; |
||||
|
||||
assert(scope != NULL); |
||||
assert(scopeLen > 0); |
||||
|
||||
/* Allocate memory for the scope string. We need to keep a persistent
|
||||
* copy of this string because kauth_listen_scope doesn't make a copy of
|
||||
* its scope identifier input parameter. Normally you'd use a constant
|
||||
* string, which persists as long as the kext is loaded, but I can't do
|
||||
* that because the scope identifier is supplied by the user via sysctl. |
||||
*/ |
||||
|
||||
assert(gListenerScope == NULL); |
||||
|
||||
gListenerScope = OSMalloc(scopeLen + 1, gMallocTag); |
||||
if (gListenerScope == NULL) { |
||||
printf("ClamAuth.InstallListener: Could not allocate gListenerScope.\n"); |
||||
} else { |
||||
memcpy(gListenerScope, scope, scopeLen); |
||||
gListenerScope[scopeLen] = 0; |
||||
|
||||
/* Copy the prefix pointer over to gPrefix. */
|
||||
assert(gPrefix == NULL); |
||||
|
||||
gPrefix = prefix; |
||||
|
||||
/* Register the appropriate listener with Kauth. */ |
||||
if ( strcmp(gListenerScope, KAUTH_SCOPE_GENERIC) == 0 ) { |
||||
callback = GenericScopeListener; |
||||
} else if ( strcmp(gListenerScope, KAUTH_SCOPE_PROCESS) == 0 ) { |
||||
callback = ProcessScopeListener; |
||||
} else if ( strcmp(gListenerScope, KAUTH_SCOPE_VNODE) == 0 ) { |
||||
callback = VnodeScopeListener; |
||||
} else if ( strcmp(gListenerScope, KAUTH_SCOPE_FILEOP) == 0 ) { |
||||
callback = FileOpScopeListener; |
||||
} else { |
||||
callback = UnknownScopeListener; |
||||
} |
||||
|
||||
assert(gListener == NULL); |
||||
|
||||
gListener = kauth_listen_scope(gListenerScope, callback, NULL); |
||||
if (gListener == NULL) { |
||||
printf("ClamAuth.InstallListener: Could not create gListener.\n"); |
||||
} |
||||
} |
||||
|
||||
/* In the event of any failure, call RemoveListener which will
|
||||
* do all the right cleanup. |
||||
*/
|
||||
if ( gListenerScope == NULL || gListener == NULL ) { |
||||
RemoveListener(); |
||||
} |
||||
} |
||||
|
||||
static void ConfigureKauth(const char *configuration) |
||||
/* This routine is called by the sysctl handler when it notices
|
||||
* that the configuration has changed. It's responsible for
|
||||
* parsing the new configuration string and updating the listener. |
||||
* |
||||
* See SysctlHandler for a description of how I chose to handle the
|
||||
* failure case. |
||||
* |
||||
* This routine always runs under the gConfigurationLock. |
||||
*/ |
||||
{ |
||||
assert(configuration != NULL); |
||||
|
||||
/* Remove the existing listener. */ |
||||
RemoveListener(); |
||||
|
||||
/* Parse the configuration string and install the new listener. */ |
||||
if (strcmp(configuration, "remove") == 0) { |
||||
printf("ClamAuth.ConfigureKauth: Removed listener.\n"); |
||||
} else if ( strprefix(configuration, "add ") ) { |
||||
const char *cursor; |
||||
const char *scopeStart; |
||||
const char *scopeEnd; |
||||
const char *prefixStart; |
||||
|
||||
/* Skip the "add ". */
|
||||
cursor = configuration + strlen("add "); |
||||
|
||||
/* Work out the span of the scope. */
|
||||
scopeStart = cursor; |
||||
while ( (*cursor != ' ') && (*cursor != 0) ) { |
||||
cursor += 1; |
||||
} |
||||
scopeEnd = cursor; |
||||
|
||||
if (scopeStart == scopeEnd) { |
||||
printf("ClamAuth.ConfigureKauth: Bad configuration '%s'.\n", configuration); |
||||
} else { |
||||
|
||||
/* Look for a prefix. */ |
||||
if (*cursor == ' ') { |
||||
cursor += 1; |
||||
} |
||||
if (*cursor == 0) { |
||||
prefixStart = NULL; |
||||
} else { |
||||
prefixStart = cursor; |
||||
} |
||||
|
||||
/* Tell the user what we're doing. */
|
||||
if (prefixStart == NULL) { |
||||
printf("ClamAuth.ConfigureKauth: scope = %.*s\n", (int) (scopeEnd - scopeStart), scopeStart); |
||||
} else { |
||||
printf("ClamAuth.ConfigureKauth: scope = %.*s, prefix = %s\n", (int) (scopeEnd - scopeStart), scopeStart, prefixStart); |
||||
} |
||||
|
||||
InstallListener(scopeStart, scopeEnd - scopeStart, prefixStart); |
||||
} |
||||
} else { |
||||
printf("ClamAuth.ConfigureKauth: Bad configuration '%s'.\n", configuration); |
||||
} |
||||
} |
||||
|
||||
/* gConfiguration holds our current configuration string. It's modified by
|
||||
* SysctlHandler (well, by sysctl_handle_string which is called by SysctlHandler). |
||||
*/ |
||||
|
||||
static char gConfiguration[1024]; |
||||
|
||||
static int SysctlHandler( |
||||
struct sysctl_oid * oidp,
|
||||
void * arg1,
|
||||
int arg2,
|
||||
struct sysctl_req * req |
||||
) |
||||
/* This routine is called by the kernel when the user reads or
|
||||
* writes our sysctl variable. The arguments are standard for
|
||||
* a sysctl handler. |
||||
*/ |
||||
{ |
||||
int result; |
||||
|
||||
/* Prevent two threads trying to change our configuration at the same
|
||||
* time. |
||||
*/
|
||||
lck_mtx_lock(gConfigurationLock); |
||||
|
||||
/* Let sysctl_handle_string do all the heavy lifting of getting
|
||||
* and setting the variable. |
||||
*/
|
||||
result = sysctl_handle_string(oidp, arg1, arg2, req); |
||||
|
||||
/* On the way out, if we got no error and a new value was set,
|
||||
* do our magic. |
||||
*/
|
||||
if ( (result == 0) && (req->newptr != 0) ) { |
||||
ConfigureKauth(gConfiguration); |
||||
} |
||||
|
||||
lck_mtx_unlock(gConfigurationLock); |
||||
|
||||
return result; |
||||
} |
||||
|
||||
/* Declare our sysctl OID (that is, a variable that the user can
|
||||
* get and set using sysctl). Once this OID is registered (which
|
||||
* is done in the start routine, ClamAuth_start, below), the user
|
||||
* user can get and set our configuration variable (gConfiguration)
|
||||
* using the sysctl command line tool. |
||||
* |
||||
* We use OID using SYSCTL_OID rather than SYSCTL_STRING because
|
||||
* we want to override the hander function that's call (we want
|
||||
* SysctlHandler rather than sysctl_handle_string). |
||||
*/ |
||||
|
||||
SYSCTL_OID( |
||||
_kern, /* parent OID */ |
||||
OID_AUTO, /* sysctl number, OID_AUTO means we're only accessible by name */ |
||||
com_apple_dts_kext_ClamAuth, /* our name */ |
||||
CTLTYPE_STRING | CTLFLAG_RW | CTLFLAG_KERN, /* we're a string, more or less */ |
||||
gConfiguration, /* sysctl_handle_string gets/sets this string */ |
||||
sizeof(gConfiguration), /* and this is its maximum length */ |
||||
SysctlHandler, /* our handler */ |
||||
"A", /* because that's what SYSCTL_STRING does */ |
||||
"" /* just a comment */ |
||||
); |
||||
|
||||
/* gRegisteredOID tracks whether we've registered our OID or not. */ |
||||
|
||||
static boolean_t gRegisteredOID = FALSE; |
||||
|
||||
#pragma mark ***** Start/Stop |
||||
|
||||
/* Prototypes for our entry points */ |
||||
extern kern_return_t com_apple_dts_kext_ClamAuth_start(kmod_info_t * ki, void * d); |
||||
extern kern_return_t com_apple_dts_kext_ClamAuth_stop(kmod_info_t * ki, void * d); |
||||
|
||||
extern kern_return_t com_apple_dts_kext_ClamAuth_start(kmod_info_t * ki, void * d) |
||||
/* Called by the system to start up the kext. */ |
||||
{ |
||||
#pragma unused(ki) |
||||
#pragma unused(d) |
||||
kern_return_t err; |
||||
|
||||
|
||||
/* Allocate our global resources, needed in order to allocate memory
|
||||
* and locks throughout the rest of the program. |
||||
*/ |
||||
err = KERN_SUCCESS; |
||||
gMallocTag = OSMalloc_Tagalloc("com.apple.dts.kext.ClamAuth", OSMT_DEFAULT); |
||||
if (gMallocTag == NULL) { |
||||
err = KERN_FAILURE; |
||||
} |
||||
if (err == KERN_SUCCESS) { |
||||
gLockGroup = lck_grp_alloc_init("com.apple.dts.kext.ClamAuth", LCK_GRP_ATTR_NULL); |
||||
if (gLockGroup == NULL) { |
||||
err = KERN_FAILURE; |
||||
} |
||||
} |
||||
|
||||
/* Allocate the lock that protects our configuration. */ |
||||
if (err == KERN_SUCCESS) { |
||||
gConfigurationLock = lck_mtx_alloc_init(gLockGroup, LCK_ATTR_NULL); |
||||
if (gConfigurationLock == NULL) { |
||||
err = KERN_FAILURE; |
||||
} |
||||
} |
||||
|
||||
/* Register our sysctl handler. */
|
||||
if (err == KERN_SUCCESS) { |
||||
sysctl_register_oid(&sysctl__kern_com_apple_dts_kext_ClamAuth); |
||||
gRegisteredOID = TRUE; |
||||
} |
||||
|
||||
/* If we failed, shut everything down. */ |
||||
if (err != KERN_SUCCESS) { |
||||
printf("ClamAuth_start: Failed to initialize the driver\n"); |
||||
(void) com_apple_dts_kext_ClamAuth_stop(ki, d); |
||||
} else |
||||
printf("ClamAuth_start: ClamAV kernel driver loaded\n"); |
||||
|
||||
return err; |
||||
} |
||||
|
||||
extern kern_return_t com_apple_dts_kext_ClamAuth_stop(kmod_info_t * ki, void * d) |
||||
/* Called by the system to shut down the kext. */ |
||||
{ |
||||
#pragma unused(ki) |
||||
#pragma unused(d) |
||||
|
||||
/* Remove our sysctl handler. This prevents more threads entering the
|
||||
* handler and trying to change the configuration. There is still a
|
||||
* race condition here though. If a thread is already running in our
|
||||
* sysctl handler, there's no way to guarantee that it's done before
|
||||
* we destroy key resources (notably the gConfigurationLock mutex) that
|
||||
* it depends on. That's because sysctl_unregister_oid makes no attempt
|
||||
* to wait until all threads running inside the OID handler are done
|
||||
* before it returns. I could do stuff to minimise the risk, but there's
|
||||
* is no 100% way to close this race so I'm going to ignore it. |
||||
*/
|
||||
if (gRegisteredOID) { |
||||
sysctl_unregister_oid(&sysctl__kern_com_apple_dts_kext_ClamAuth); |
||||
gRegisteredOID = FALSE; |
||||
} |
||||
|
||||
/* Shut down the scope listen, if any. Not that we lock gConfigurationLock
|
||||
* because RemoveListener requires it to be locked. Further note that
|
||||
* we only do this if the lock has actually been allocated. If the startup
|
||||
* routine fails, we can get called with gConfigurationLock set to NULL. |
||||
*/
|
||||
if (gConfigurationLock != NULL) { |
||||
lck_mtx_lock(gConfigurationLock); |
||||
} |
||||
RemoveListener(); |
||||
if (gConfigurationLock != NULL) { |
||||
lck_mtx_unlock(gConfigurationLock); |
||||
} |
||||
|
||||
/* Clean up the configuration lock. */
|
||||
if (gConfigurationLock != NULL) { |
||||
lck_mtx_free(gConfigurationLock, gLockGroup); |
||||
gConfigurationLock = NULL; |
||||
} |
||||
|
||||
/* Clean up our global resources. */ |
||||
if (gLockGroup != NULL) { |
||||
lck_grp_free(gLockGroup); |
||||
gLockGroup = NULL; |
||||
} |
||||
if (gMallocTag != NULL) { |
||||
OSMalloc_Tagfree(gMallocTag); |
||||
gMallocTag = NULL; |
||||
} |
||||
|
||||
printf("ClamAuth_stop: ClamAV kernel driver removed\n"); |
||||
return KERN_SUCCESS; |
||||
} |
@ -0,0 +1,262 @@ |
||||
// !$*UTF8*$! |
||||
{ |
||||
archiveVersion = 1; |
||||
classes = { |
||||
}; |
||||
objectVersion = 46; |
||||
objects = { |
||||
|
||||
/* Begin PBXBuildFile section */ |
||||
52ADB27A148676E700208F0E /* LICENSE in Resources */ = {isa = PBXBuildFile; fileRef = 52ADB279148676E700208F0E /* LICENSE */; }; |
||||
52ADB28014867AF400208F0E /* ClamAuth.c in Sources */ = {isa = PBXBuildFile; fileRef = 52ADB27F14867AF400208F0E /* ClamAuth.c */; }; |
||||
/* End PBXBuildFile section */ |
||||
|
||||
/* Begin PBXFileReference section */ |
||||
32A4FEC30562C75700D090E7 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; }; |
||||
32A4FEC40562C75800D090E7 /* ClamAuth.kext */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ClamAuth.kext; sourceTree = BUILT_PRODUCTS_DIR; }; |
||||
52ADB279148676E700208F0E /* LICENSE */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = LICENSE; sourceTree = "<group>"; }; |
||||
52ADB27F14867AF400208F0E /* ClamAuth.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ClamAuth.c; sourceTree = "<group>"; }; |
||||
E4C7A4390832568C00556BCE /* Kernel.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Kernel.framework; path = /System/Library/Frameworks/Kernel.framework; sourceTree = "<absolute>"; }; |
||||
/* End PBXFileReference section */ |
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */ |
||||
32A4FEBF0562C75700D090E7 /* Frameworks */ = { |
||||
isa = PBXFrameworksBuildPhase; |
||||
buildActionMask = 2147483647; |
||||
files = ( |
||||
); |
||||
runOnlyForDeploymentPostprocessing = 0; |
||||
}; |
||||
/* End PBXFrameworksBuildPhase section */ |
||||
|
||||
/* Begin PBXGroup section */ |
||||
089C166AFE841209C02AAC07 /* KauthORama */ = { |
||||
isa = PBXGroup; |
||||
children = ( |
||||
52ADB27F14867AF400208F0E /* ClamAuth.c */, |
||||
52ADB279148676E700208F0E /* LICENSE */, |
||||
32A4FEC30562C75700D090E7 /* Info.plist */, |
||||
E4C7A4390832568C00556BCE /* Kernel.framework */, |
||||
19C28FB6FE9D52B211CA2CBB /* Products */, |
||||
); |
||||
name = KauthORama; |
||||
sourceTree = "<group>"; |
||||
}; |
||||
19C28FB6FE9D52B211CA2CBB /* Products */ = { |
||||
isa = PBXGroup; |
||||
children = ( |
||||
32A4FEC40562C75800D090E7 /* ClamAuth.kext */, |
||||
); |
||||
name = Products; |
||||
sourceTree = "<group>"; |
||||
}; |
||||
/* End PBXGroup section */ |
||||
|
||||
/* Begin PBXHeadersBuildPhase section */ |
||||
32A4FEBA0562C75700D090E7 /* Headers */ = { |
||||
isa = PBXHeadersBuildPhase; |
||||
buildActionMask = 2147483647; |
||||
files = ( |
||||
); |
||||
runOnlyForDeploymentPostprocessing = 0; |
||||
}; |
||||
/* End PBXHeadersBuildPhase section */ |
||||
|
||||
/* Begin PBXNativeTarget section */ |
||||
32A4FEB80562C75700D090E7 /* ClamAuth */ = { |
||||
isa = PBXNativeTarget; |
||||
buildConfigurationList = E40CF0E60890089400F3BED8 /* Build configuration list for PBXNativeTarget "ClamAuth" */; |
||||
buildPhases = ( |
||||
32A4FEB90562C75700D090E7 /* ShellScript */, |
||||
32A4FEBA0562C75700D090E7 /* Headers */, |
||||
32A4FEBB0562C75700D090E7 /* Resources */, |
||||
32A4FEBD0562C75700D090E7 /* Sources */, |
||||
32A4FEBF0562C75700D090E7 /* Frameworks */, |
||||
32A4FEC00562C75700D090E7 /* Rez */, |
||||
32A4FEC10562C75700D090E7 /* ShellScript */, |
||||
); |
||||
buildRules = ( |
||||
); |
||||
dependencies = ( |
||||
); |
||||
name = ClamAuth; |
||||
productInstallPath = "$(SYSTEM_LIBRARY_DIR)/Extensions"; |
||||
productName = KauthORama; |
||||
productReference = 32A4FEC40562C75800D090E7 /* ClamAuth.kext */; |
||||
productType = "com.apple.product-type.kernel-extension"; |
||||
}; |
||||
/* End PBXNativeTarget section */ |
||||
|
||||
/* Begin PBXProject section */ |
||||
089C1669FE841209C02AAC07 /* Project object */ = { |
||||
isa = PBXProject; |
||||
attributes = { |
||||
LastUpgradeCheck = 0420; |
||||
}; |
||||
buildConfigurationList = E40CF0EA0890089400F3BED8 /* Build configuration list for PBXProject "ClamAuth" */; |
||||
compatibilityVersion = "Xcode 3.2"; |
||||
developmentRegion = English; |
||||
hasScannedForEncodings = 1; |
||||
knownRegions = ( |
||||
en, |
||||
); |
||||
mainGroup = 089C166AFE841209C02AAC07 /* KauthORama */; |
||||
projectDirPath = ""; |
||||
projectRoot = ""; |
||||
targets = ( |
||||
32A4FEB80562C75700D090E7 /* ClamAuth */, |
||||
); |
||||
}; |
||||
/* End PBXProject section */ |
||||
|
||||
/* Begin PBXResourcesBuildPhase section */ |
||||
32A4FEBB0562C75700D090E7 /* Resources */ = { |
||||
isa = PBXResourcesBuildPhase; |
||||
buildActionMask = 2147483647; |
||||
files = ( |
||||
52ADB27A148676E700208F0E /* LICENSE in Resources */, |
||||
); |
||||
runOnlyForDeploymentPostprocessing = 0; |
||||
}; |
||||
/* End PBXResourcesBuildPhase section */ |
||||
|
||||
/* Begin PBXRezBuildPhase section */ |
||||
32A4FEC00562C75700D090E7 /* Rez */ = { |
||||
isa = PBXRezBuildPhase; |
||||
buildActionMask = 2147483647; |
||||
files = ( |
||||
); |
||||
runOnlyForDeploymentPostprocessing = 0; |
||||
}; |
||||
/* End PBXRezBuildPhase section */ |
||||
|
||||
/* Begin PBXShellScriptBuildPhase section */ |
||||
32A4FEB90562C75700D090E7 /* ShellScript */ = { |
||||
isa = PBXShellScriptBuildPhase; |
||||
buildActionMask = 2147483647; |
||||
files = ( |
||||
); |
||||
runOnlyForDeploymentPostprocessing = 0; |
||||
shellPath = /bin/sh; |
||||
shellScript = "script=\"${SYSTEM_DEVELOPER_DIR}/ProjectBuilder Extras/Kernel Extension Support/KEXTPreprocess\";\nif [ -x \"$script\" ]; then\n . \"$script\"\nfi"; |
||||
}; |
||||
32A4FEC10562C75700D090E7 /* ShellScript */ = { |
||||
isa = PBXShellScriptBuildPhase; |
||||
buildActionMask = 2147483647; |
||||
files = ( |
||||
); |
||||
runOnlyForDeploymentPostprocessing = 0; |
||||
shellPath = /bin/sh; |
||||
shellScript = "script=\"${SYSTEM_DEVELOPER_DIR}/ProjectBuilder Extras/Kernel Extension Support/KEXTPostprocess\";\nif [ -x \"$script\" ]; then\n . \"$script\"\nfi"; |
||||
}; |
||||
/* End PBXShellScriptBuildPhase section */ |
||||
|
||||
/* Begin PBXSourcesBuildPhase section */ |
||||
32A4FEBD0562C75700D090E7 /* Sources */ = { |
||||
isa = PBXSourcesBuildPhase; |
||||
buildActionMask = 2147483647; |
||||
files = ( |
||||
52ADB28014867AF400208F0E /* ClamAuth.c in Sources */, |
||||
); |
||||
runOnlyForDeploymentPostprocessing = 0; |
||||
}; |
||||
/* End PBXSourcesBuildPhase section */ |
||||
|
||||
/* Begin XCBuildConfiguration section */ |
||||
E40CF0E70890089400F3BED8 /* Debug */ = { |
||||
isa = XCBuildConfiguration; |
||||
buildSettings = { |
||||
INFOPLIST_FILE = Info.plist; |
||||
MODULE_NAME = com.apple.dts.kext.ClamAuth; |
||||
MODULE_START = com_apple_dts_kext_ClamAuth_start; |
||||
MODULE_STOP = com_apple_dts_kext_ClamAuth_stop; |
||||
MODULE_VERSION = 0.1; |
||||
PRODUCT_NAME = ClamAuth; |
||||
WRAPPER_EXTENSION = kext; |
||||
}; |
||||
name = Debug; |
||||
}; |
||||
E40CF0E80890089400F3BED8 /* Release */ = { |
||||
isa = XCBuildConfiguration; |
||||
buildSettings = { |
||||
INFOPLIST_FILE = Info.plist; |
||||
MODULE_NAME = com.apple.dts.kext.ClamAuth; |
||||
MODULE_START = com_apple_dts_kext_ClamAuth_start; |
||||
MODULE_STOP = com_apple_dts_kext_ClamAuth_stop; |
||||
MODULE_VERSION = 0.1; |
||||
PRODUCT_NAME = ClamAuth; |
||||
WRAPPER_EXTENSION = kext; |
||||
}; |
||||
name = Release; |
||||
}; |
||||
E40CF0EB0890089400F3BED8 /* Debug */ = { |
||||
isa = XCBuildConfiguration; |
||||
buildSettings = { |
||||
ARCHS = "$(ARCHS_STANDARD_64_BIT)"; |
||||
COPY_PHASE_STRIP = NO; |
||||
GCC_DYNAMIC_NO_PIC = NO; |
||||
GCC_GENERATE_DEBUGGING_SYMBOLS = YES; |
||||
GCC_OPTIMIZATION_LEVEL = 0; |
||||
GCC_TREAT_WARNINGS_AS_ERRORS = NO; |
||||
GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES; |
||||
GCC_WARN_MISSING_PARENTHESES = YES; |
||||
GCC_WARN_SIGN_COMPARE = YES; |
||||
GCC_WARN_UNUSED_FUNCTION = YES; |
||||
GCC_WARN_UNUSED_LABEL = YES; |
||||
GCC_WARN_UNUSED_PARAMETER = YES; |
||||
GCC_WARN_UNUSED_VALUE = YES; |
||||
GCC_WARN_UNUSED_VARIABLE = YES; |
||||
MACOSX_DEPLOYMENT_TARGET = 10.7; |
||||
SDKROOT = macosx; |
||||
WARNING_CFLAGS = "-Wall"; |
||||
}; |
||||
name = Debug; |
||||
}; |
||||
E40CF0EC0890089400F3BED8 /* Release */ = { |
||||
isa = XCBuildConfiguration; |
||||
buildSettings = { |
||||
ARCHS = "$(ARCHS_STANDARD_64_BIT)"; |
||||
COPY_PHASE_STRIP = YES; |
||||
GCC_DYNAMIC_NO_PIC = NO; |
||||
GCC_GENERATE_DEBUGGING_SYMBOLS = YES; |
||||
GCC_OPTIMIZATION_LEVEL = s; |
||||
GCC_TREAT_WARNINGS_AS_ERRORS = NO; |
||||
GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES; |
||||
GCC_WARN_MISSING_PARENTHESES = YES; |
||||
GCC_WARN_SIGN_COMPARE = YES; |
||||
GCC_WARN_UNUSED_FUNCTION = YES; |
||||
GCC_WARN_UNUSED_LABEL = YES; |
||||
GCC_WARN_UNUSED_PARAMETER = YES; |
||||
GCC_WARN_UNUSED_VALUE = YES; |
||||
GCC_WARN_UNUSED_VARIABLE = YES; |
||||
MACOSX_DEPLOYMENT_TARGET = 10.7; |
||||
SDKROOT = macosx; |
||||
WARNING_CFLAGS = "-Wall"; |
||||
}; |
||||
name = Release; |
||||
}; |
||||
/* End XCBuildConfiguration section */ |
||||
|
||||
/* Begin XCConfigurationList section */ |
||||
E40CF0E60890089400F3BED8 /* Build configuration list for PBXNativeTarget "ClamAuth" */ = { |
||||
isa = XCConfigurationList; |
||||
buildConfigurations = ( |
||||
E40CF0E70890089400F3BED8 /* Debug */, |
||||
E40CF0E80890089400F3BED8 /* Release */, |
||||
); |
||||
defaultConfigurationIsVisible = 0; |
||||
defaultConfigurationName = Debug; |
||||
}; |
||||
E40CF0EA0890089400F3BED8 /* Build configuration list for PBXProject "ClamAuth" */ = { |
||||
isa = XCConfigurationList; |
||||
buildConfigurations = ( |
||||
E40CF0EB0890089400F3BED8 /* Debug */, |
||||
E40CF0EC0890089400F3BED8 /* Release */, |
||||
); |
||||
defaultConfigurationIsVisible = 0; |
||||
defaultConfigurationName = Debug; |
||||
}; |
||||
/* End XCConfigurationList section */ |
||||
}; |
||||
rootObject = 089C1669FE841209C02AAC07 /* Project object */; |
||||
} |
@ -0,0 +1,29 @@ |
||||
<?xml version="1.0" encoding="UTF-8"?> |
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> |
||||
<plist version="1.0"> |
||||
<dict> |
||||
<key>CFBundleDevelopmentRegion</key> |
||||
<string>English</string> |
||||
<key>CFBundleExecutable</key> |
||||
<string>ClamAuth</string> |
||||
<key>CFBundleIconFile</key> |
||||
<string></string> |
||||
<key>CFBundleIdentifier</key> |
||||
<string>com.apple.dts.kext.ClamAuth</string> |
||||
<key>CFBundleInfoDictionaryVersion</key> |
||||
<string>6.0</string> |
||||
<key>CFBundlePackageType</key> |
||||
<string>KEXT</string> |
||||
<key>CFBundleSignature</key> |
||||
<string>????</string> |
||||
<key>CFBundleVersion</key> |
||||
<string>$(MODULE_VERSION)</string> |
||||
<key>OSBundleLibraries</key> |
||||
<dict> |
||||
<key>com.apple.kpi.bsd</key> |
||||
<string>8.0.0</string> |
||||
<key>com.apple.kpi.libkern</key> |
||||
<string>8.0.0</string> |
||||
</dict> |
||||
</dict> |
||||
</plist> |
@ -0,0 +1,40 @@ |
||||
Copyright (C) 2011 Sourcefire, Inc., All Rights Reserved. |
||||
|
||||
The KAuth code is based on KauthORama: |
||||
|
||||
Copyright (c) 2007 by Apple Computer, Inc., All Rights Reserved. |
||||
|
||||
Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc. |
||||
("Apple") in consideration of your agreement to the following terms, and your |
||||
use, installation, modification or redistribution of this Apple software |
||||
constitutes acceptance of these terms. If you do not agree with these terms, |
||||
please do not use, install, modify or redistribute this Apple software. |
||||
|
||||
In consideration of your agreement to abide by the following terms, and subject |
||||
to these terms, Apple grants you a personal, non-exclusive license, under Apple's |
||||
copyrights in this original Apple software (the "Apple Software"), to use, |
||||
reproduce, modify and redistribute the Apple Software, with or without |
||||
modifications, in source and/or binary forms; provided that if you redistribute |
||||
the Apple Software in its entirety and without modifications, you must retain |
||||
this notice and the following text and disclaimers in all such redistributions of |
||||
the Apple Software. Neither the name, trademarks, service marks or logos of |
||||
Apple Computer, Inc. may be used to endorse or promote products derived from the |
||||
Apple Software without specific prior written permission from Apple. Except as |
||||
expressly stated in this notice, no other rights or licenses, express or implied, |
||||
are granted by Apple herein, including but not limited to any patent rights that |
||||
may be infringed by your derivative works or by other works in which the Apple |
||||
Software may be incorporated. |
||||
|
||||
The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO |
||||
WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED |
||||
WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
||||
PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN |
||||
COMBINATION WITH YOUR PRODUCTS. |
||||
|
||||
IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR |
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE |
||||
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
||||
ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION |
||||
OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT |
||||
(INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN |
||||
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
Loading…
Reference in new issue