/* Editor Settings: expandtabs and use 4 spaces for indentation
* ex: set softtabstop=4 tabstop=8 expandtab shiftwidth=4: *
* -*- mode: c, c-basic-offset: 4 -*- */
/*
* Copyright Likewise Software 2004-2008
* All rights reserved.
*
* 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, see
* .
*
* LIKEWISE SOFTWARE MAKES THIS SOFTWARE AVAILABLE UNDER OTHER LICENSING
* TERMS AS WELL. IF YOU HAVE ENTERED INTO A SEPARATE LICENSE AGREEMENT
* WITH LIKEWISE SOFTWARE, THEN YOU MAY ELECT TO USE THE SOFTWARE UNDER THE
* TERMS OF THAT SOFTWARE LICENSE AGREEMENT INSTEAD OF THE TERMS OF THE GNU
* GENERAL PUBLIC LICENSE, NOTWITHSTANDING THE ABOVE NOTICE. IF YOU
* HAVE QUESTIONS, OR WISH TO REQUEST A COPY OF THE ALTERNATE LICENSING
* TERMS OFFERED BY LIKEWISE SOFTWARE, PLEASE CONTACT LIKEWISE SOFTWARE AT
* license@likewisesoftware.com
*/
/*
* Copyright (C) Likewise Software. All rights reserved.
*
* Module Name:
*
* main.c
*
* Abstract:
*
* Likewise Security and Authentication Subsystem (LSASS)
*
* Service Entry API
*
* Authors: Krishna Ganugapati (krishnag@likewisesoftware.com)
* Sriram Nambakam (snambakam@likewisesoftware.com)
* Kyle Stemen (kstemen@likewisesoftware.com)
*/
#include "config.h"
#include "lsassd.h"
#include "lwnet.h"
#include "lw/base.h"
#include "lwdscache.h"
#include "eventlog.h"
#include "lsasrvutils.h"
/* Needed for dcethread_fork() */
#include
#ifdef ENABLE_STATIC_PROVIDERS
#ifdef ENABLE_AD
extern DWORD LsaInitializeProvider_ActiveDirectory(PCSTR*, PLSA_PROVIDER_FUNCTION_TABLE_2*);
#endif
#ifdef ENABLE_LOCAL
extern DWORD LsaInitializeProvider_Local(PCSTR*, PLSA_PROVIDER_FUNCTION_TABLE_2*);
#endif
static LSA_STATIC_PROVIDER gStaticProviders[] =
{
#ifdef ENABLE_AD
{ "lsa-activedirectory-provider", LsaInitializeProvider_ActiveDirectory },
#endif
#ifdef ENABLE_LOCAL
{ "lsa-local-provider", LsaInitializeProvider_Local },
#endif
{ 0 }
};
#endif // ENABLE_STATIC_PROVIDERS
#ifdef ENABLE_PIDFILE
static
VOID
LsaSrvCreatePIDFile(
VOID
);
static
pid_t
LsaSrvGetPidFromPidFile(
VOID
);
static
VOID
LsaSrvRemovePidFile(
VOID
);
#endif
int
lsassd_main(
int argc,
char* argv[]
)
{
DWORD dwError = 0;
PCSTR pszSmNotify = NULL;
int notifyFd = -1;
char notifyCode = 0;
int ret = 0;
// Register a signal handler for program crashes such that it prints out a
// backtrace.
dwError = LsaSrvRegisterCrashHandler();
BAIL_ON_LSA_ERROR(dwError);
dwError = LsaSrvSetDefaults();
BAIL_ON_LSA_ERROR(dwError);
dwError = LsaSrvParseArgs(argc,
argv,
&gServerInfo);
BAIL_ON_LSA_ERROR(dwError);
dwError = LsaInitLogging_r(
LsaGetProgramName(argv[0]),
gServerInfo.logTarget,
gServerInfo.maxAllowedLogLevel,
gServerInfo.szLogFilePath);
BAIL_ON_LSA_ERROR(dwError);
LSA_LOG_VERBOSE("Logging started");
dwError = LsaInitTracing_r();
BAIL_ON_LSA_ERROR(dwError);
if (atexit(LsaSrvExitHandler) < 0) {
dwError = errno;
BAIL_ON_LSA_ERROR(dwError);
}
if (LsaSrvShouldStartAsDaemon()) {
dwError = LsaSrvStartAsDaemon();
BAIL_ON_LSA_ERROR(dwError);
}
// Ignore any errors returned by this function.
LsaSrvRaiseMaxFiles(1024);
dwError = LWNetExtendEnvironmentForKrb5Affinity(TRUE);
BAIL_ON_LSA_ERROR(dwError);
dwError = LsaBlockSelectedSignals();
BAIL_ON_LSA_ERROR(dwError);
// Test system to see if dependent configuration tasks are completed prior to starting our process.
dwError = LsaSrvStartupPreCheck();
BAIL_ON_LSA_ERROR(dwError);
#ifdef ENABLE_PIDFILE
LsaSrvCreatePIDFile();
#endif
dwError = LwDsCacheAddPidException(getpid());
if (dwError == LW_ERROR_FAILED_STARTUP_PREREQUISITE_CHECK)
{
LSA_LOG_ERROR("Could not register process pid (%d) with Mac DirectoryService Cache plugin", (int) getpid());
BAIL_ON_LSA_ERROR(dwError);
}
dwError = LsaSrvInitialize();
BAIL_ON_LSA_ERROR(dwError);
//dwError = LsaSrvStartListenThread(&listenerThreadId, &pListenerThreadId);
dwError = LsaSrvStartListenThread();
BAIL_ON_LSA_ERROR(dwError);
dwError = NtlmSrvStartListenThread();
BAIL_ON_LSA_ERROR(dwError);
if ((pszSmNotify = getenv("LIKEWISE_SM_NOTIFY")) != NULL)
{
notifyFd = atoi(pszSmNotify);
do
{
ret = write(notifyFd, ¬ifyCode, sizeof(notifyCode));
} while(ret != sizeof(notifyCode) && errno == EINTR);
if (ret < 0)
{
LSA_LOG_ERROR("Could not notify service manager: %s (%i)", strerror(errno), errno);
dwError = LwMapErrnoToLwError(errno);
BAIL_ON_LSA_ERROR(dwError);
}
close(notifyFd);
}
LsaSrvLogProcessStartedEvent();
// Handle signals, blocking until we are supposed to exit.
dwError = LsaSrvHandleSignals();
BAIL_ON_LSA_ERROR(dwError);
cleanup:
LSA_LOG_VERBOSE("Lsa main cleaning up");
LsaSrvStopProcess();
LsaSrvStopListenThread();
LwDsCacheRemovePidException(getpid());
NtlmSrvStopListenThread();
LsaSrvApiShutdown();
LwIoShutdown();
NtlmClientIpcShutdown();
LSA_LOG_INFO("LSA Service exiting...");
LsaSrvSetProcessExitCode(dwError);
LsaShutdownLogging_r();
LsaShutdownTracing_r();
#ifdef ENABLE_PIDFILE
LsaSrvRemovePidFile();
#endif
return dwError;
error:
LSA_LOG_ERROR("LSA Process exiting due to error [Code:%d]", dwError);
LsaSrvLogProcessFailureEvent(dwError);
goto cleanup;
}
DWORD
LsaSrvStartupPreCheck(
VOID
)
{
DWORD dwError = 0;
PSTR pszHostname = NULL;
int iter = 0;
#ifdef __LWI_DARWIN__
// Make sure that the local hostname has been setup by the system
for (iter = 0; iter < STARTUP_PRE_CHECK_WAIT; iter++)
{
LW_SAFE_FREE_STRING(pszHostname);
dwError = LsaDnsGetHostInfo(&pszHostname);
BAIL_ON_LSA_ERROR(dwError);
if (!strcasecmp(pszHostname, "localhost"))
{
sleep(10);
}
else
{
/* Hostname now looks correct */
LSA_LOG_INFO("LSA Process start up check for hostname complete [hostname:%s]", pszHostname);
break;
}
}
if (iter >= STARTUP_PRE_CHECK_WAIT)
{
dwError = LW_ERROR_FAILED_STARTUP_PREREQUISITE_CHECK;
LSA_LOG_ERROR("LSA start up pre-check failed to get updated hostname after %d seconds of waiting [Code:%d]",
STARTUP_PRE_CHECK_WAIT*10,
dwError);
BAIL_ON_LSA_ERROR(dwError);
}
#endif
for (iter = 0; iter < STARTUP_NETLOGON_WAIT; iter++)
{
dwError = LsaSrvVerifyNetLogonStatus();
if (dwError)
{
sleep(1);
}
else
{
/* NetLogon is responsive */
LSA_LOG_INFO("LSA Process start up check for NetLogon complete");
break;
}
}
if (iter >= STARTUP_NETLOGON_WAIT)
{
dwError = LW_ERROR_FAILED_STARTUP_PREREQUISITE_CHECK;
LSA_LOG_ERROR("LSA start up pre-check failed to be able to use NetLogonD after %d seconds of waiting [Code:%d]",
STARTUP_NETLOGON_WAIT,
dwError);
BAIL_ON_LSA_ERROR(dwError);
}
for (iter = 0; iter < STARTUP_LWIO_WAIT; iter++)
{
dwError = LsaSrvVerifyLwIoStatus();
if (dwError)
{
sleep(1);
}
else
{
/* LwIo is responsive */
LSA_LOG_INFO("LSA Process start up check for LwIo complete");
break;
}
}
if (iter >= STARTUP_LWIO_WAIT)
{
dwError = LW_ERROR_FAILED_STARTUP_PREREQUISITE_CHECK;
LSA_LOG_ERROR("LSA start up pre-check failed to be able to use LwIoD after %d seconds of waiting [Code:%d]",
STARTUP_LWIO_WAIT,
dwError);
BAIL_ON_LSA_ERROR(dwError);
}
#if defined (__LWI_DARWIN_)
// Now that we are running, we need to flush the DirectoryService process of any negative cache entries
dwError = LsaSrvFlushSystemCache();
BAIL_ON_LSA_ERROR(dwError);
#endif
cleanup:
LW_SAFE_FREE_STRING(pszHostname);
return dwError;
error:
LSA_LOG_ERROR("LSA Process exiting due to error checking hostname at startup [Code:%d]", dwError);
goto cleanup;
}
DWORD
LsaSrvVerifyNetLogonStatus(
VOID
)
{
DWORD dwError = 0;
PSTR pszDomain = NULL;
dwError = LWNetGetCurrentDomain(&pszDomain);
LSA_LOG_INFO("LsaSrvVerifyNetLogonStatus call to LWNet API returned %d", dwError);
BAIL_ON_LSA_ERROR(dwError);
cleanup:
if (pszDomain)
{
LWNetFreeString(pszDomain);
}
return dwError;
error:
if (dwError == ERROR_NOT_JOINED)
{
dwError = 0;
}
goto cleanup;
}
DWORD
LsaSrvVerifyLwIoStatus(
VOID
)
{
DWORD dwError = 0;
PLWIO_LOG_INFO pLogInfo = NULL;
PIO_CONTEXT pContext = NULL;
dwError = LwIoOpenContext(&pContext);
LSA_LOG_INFO("LsaSrvVerifyLwIoStatus call to LwIo API returned %d", dwError);
BAIL_ON_LSA_ERROR(dwError);
dwError = LwIoGetLogInfo(
(HANDLE) pContext,
&pLogInfo);
LSA_LOG_INFO("LsaSrvVerifyLwIoStatus call to LwIo API returned %d", dwError);
BAIL_ON_LSA_ERROR(dwError);
cleanup:
if (pLogInfo)
{
LwIoFreeLogInfo(pLogInfo);
}
if (pContext != NULL)
{
LwIoCloseContext(pContext);
}
return dwError;
error:
goto cleanup;
}
DWORD
LsaSrvRaiseMaxFiles(
DWORD dwMaxFiles
)
{
DWORD dwError = 0;
struct rlimit maxFiles = {0};
BOOLEAN bRaised = FALSE;
if (getrlimit(RLIMIT_NOFILE, &maxFiles) < 0)
{
dwError = LwMapErrnoToLwError(errno);
BAIL_ON_LSA_ERROR(dwError);
}
if (maxFiles.rlim_cur < dwMaxFiles)
{
LSA_LOG_INFO("Raising soft max fd limit from %d to %d",
maxFiles.rlim_cur,
dwMaxFiles);
maxFiles.rlim_cur = dwMaxFiles;
bRaised = TRUE;
}
if (maxFiles.rlim_max < dwMaxFiles)
{
LSA_LOG_INFO("Raising hard max fd limit from %d to %d",
maxFiles.rlim_max,
dwMaxFiles);
maxFiles.rlim_max = dwMaxFiles;
bRaised = TRUE;
}
if (bRaised)
{
if (setrlimit(RLIMIT_NOFILE, &maxFiles) < 0)
{
LSA_LOG_ERROR("Raising max fd limit failed");
dwError = LwMapErrnoToLwError(errno);
BAIL_ON_LSA_ERROR(dwError);
}
}
cleanup:
return dwError;
error:
goto cleanup;
}
DWORD
LsaSrvSetDefaults(
VOID
)
{
DWORD dwError = 0;
gpServerInfo->maxAllowedLogLevel = LSA_LOG_LEVEL_ERROR;
*(gpServerInfo->szLogFilePath) = '\0';
strcpy(gpServerInfo->szCachePath, CACHEDIR);
strcpy(gpServerInfo->szPrefixPath, PREFIXDIR);
setlocale(LC_ALL, "");
return (dwError);
}
DWORD
LsaSrvParseArgs(
int argc,
PSTR argv[],
PLSASERVERINFO pLsaServerInfo
)
{
typedef enum {
PARSE_MODE_OPEN = 0,
PARSE_MODE_LOGFILE,
PARSE_MODE_LOGLEVEL
} ParseMode;
DWORD dwError = 0;
ParseMode parseMode = PARSE_MODE_OPEN;
int iArg = 1;
PSTR pArg = NULL;
BOOLEAN bLogTargetSet = FALSE;
do {
pArg = argv[iArg++];
if (pArg == NULL || *pArg == '\0') {
break;
}
switch(parseMode) {
case PARSE_MODE_OPEN:
{
if (strcmp(pArg, "--logfile") == 0) {
parseMode = PARSE_MODE_LOGFILE;
}
else if ((strcmp(pArg, "--help") == 0) ||
(strcmp(pArg, "-h") == 0)) {
ShowUsage(LsaGetProgramName(argv[0]));
exit(0);
}
else if (strcmp(pArg, "--start-as-daemon") == 0) {
pLsaServerInfo->dwStartAsDaemon = 1;
// If other arguments set before this set the log target
// don't over-ride that setting
if (!bLogTargetSet)
{
pLsaServerInfo->logTarget = LSA_LOG_TARGET_SYSLOG;
}
}
else if (strcmp(pArg, "--syslog") == 0)
{
bLogTargetSet = TRUE;
pLsaServerInfo->logTarget = LSA_LOG_TARGET_SYSLOG;
}
else if (strcmp(pArg, "--loglevel") == 0) {
parseMode = PARSE_MODE_LOGLEVEL;
} else {
LSA_LOG_ERROR("Unrecognized command line option [%s]",
pArg);
ShowUsage(LsaGetProgramName(argv[0]));
exit(1);
}
break;
}
case PARSE_MODE_LOGFILE:
{
strcpy(pLsaServerInfo->szLogFilePath, pArg);
LwStripWhitespace(pLsaServerInfo->szLogFilePath, TRUE, TRUE);
if (!strcmp(pLsaServerInfo->szLogFilePath, "."))
{
pLsaServerInfo->logTarget = LSA_LOG_TARGET_CONSOLE;
}
else
{
pLsaServerInfo->logTarget = LSA_LOG_TARGET_FILE;
}
bLogTargetSet = TRUE;
parseMode = PARSE_MODE_OPEN;
break;
}
case PARSE_MODE_LOGLEVEL:
{
if (!strcasecmp(pArg, "error")) {
pLsaServerInfo->maxAllowedLogLevel = LSA_LOG_LEVEL_ERROR;
} else if (!strcasecmp(pArg, "warning")) {
pLsaServerInfo->maxAllowedLogLevel = LSA_LOG_LEVEL_WARNING;
} else if (!strcasecmp(pArg, "info")) {
pLsaServerInfo->maxAllowedLogLevel = LSA_LOG_LEVEL_INFO;
} else if (!strcasecmp(pArg, "verbose")) {
pLsaServerInfo->maxAllowedLogLevel = LSA_LOG_LEVEL_VERBOSE;
} else if (!strcasecmp(pArg, "debug")) {
pLsaServerInfo->maxAllowedLogLevel = LSA_LOG_LEVEL_DEBUG;
} else if (!strcasecmp(pArg, "trace")) {
pLsaServerInfo->maxAllowedLogLevel = LSA_LOG_LEVEL_TRACE;
} else {
LSA_LOG_ERROR("Error: Invalid log level [%s]", pArg);
ShowUsage(LsaGetProgramName(argv[0]));
exit(1);
}
parseMode = PARSE_MODE_OPEN;
break;
}
}
} while (iArg < argc);
if (pLsaServerInfo->dwStartAsDaemon)
{
if (pLsaServerInfo->logTarget == LSA_LOG_TARGET_CONSOLE)
{
LSA_LOG_ERROR("%s", "Error: Cannot log to console when executing as a daemon");
dwError = LW_ERROR_INVALID_PARAMETER;
BAIL_ON_LSA_ERROR(dwError);
}
}
else
{
if (!bLogTargetSet)
{
pLsaServerInfo->logTarget = LSA_LOG_TARGET_CONSOLE;
}
}
error:
return dwError;
}
PSTR
LsaGetProgramName(
PSTR pszFullProgramPath
)
{
if (pszFullProgramPath == NULL || *pszFullProgramPath == '\0') {
return NULL;
}
// start from end of the string
PSTR pszNameStart = pszFullProgramPath + strlen(pszFullProgramPath);
do {
if (*(pszNameStart - 1) == '/') {
break;
}
pszNameStart--;
} while (pszNameStart != pszFullProgramPath);
return pszNameStart;
}
VOID
ShowUsage(
PCSTR pszProgramName
)
{
printf("Usage: %s [--start-as-daemon]\n"
" [--logfile logFilePath]\n"
" [--syslog]\n"
" [--loglevel {error, warning, info, verbose, debug, trace}]\n", pszProgramName);
}
VOID
LsaSrvExitHandler(
VOID
)
{
DWORD dwError = 0;
DWORD dwExitCode = 0;
CHAR szErrCodeFilePath[PATH_MAX+1];
PSTR pszCachePath = NULL;
BOOLEAN bFileExists = 0;
FILE* fp = NULL;
dwError = LsaSrvGetCachePath(&pszCachePath);
BAIL_ON_LSA_ERROR(dwError);
sprintf(szErrCodeFilePath, "%s/lsasd.err", pszCachePath);
dwError = LsaCheckFileExists(szErrCodeFilePath, &bFileExists);
BAIL_ON_LSA_ERROR(dwError);
if (bFileExists) {
dwError = LsaRemoveFile(szErrCodeFilePath);
BAIL_ON_LSA_ERROR(dwError);
}
dwError = LsaSrvGetProcessExitCode(&dwExitCode);
BAIL_ON_LSA_ERROR(dwError);
LsaSrvLogProcessStoppedEvent(dwExitCode);
if (dwExitCode) {
fp = fopen(szErrCodeFilePath, "w");
if (fp == NULL) {
dwError = errno;
BAIL_ON_LSA_ERROR(dwError);
}
fprintf(fp, "%d\n", dwExitCode);
}
error:
LW_SAFE_FREE_STRING(pszCachePath);
if (fp != NULL) {
fclose(fp);
}
}
DWORD
LsaSrvInitialize(
VOID
)
{
DWORD dwError = 0;
dwError = LsaInitCacheFolders();
BAIL_ON_LSA_ERROR(dwError);
#ifdef ENABLE_STATIC_PROVIDERS
dwError = LsaSrvApiInit(gStaticProviders);
#else
dwError = LsaSrvApiInit(NULL);
#endif
BAIL_ON_LSA_ERROR(dwError);
cleanup:
return dwError;
error:
goto cleanup;
}
DWORD
LsaInitCacheFolders(
VOID
)
{
DWORD dwError = 0;
PSTR pszCachePath = NULL;
BOOLEAN bExists = FALSE;
dwError = LsaSrvGetCachePath(&pszCachePath);
BAIL_ON_LSA_ERROR(dwError);
dwError = LsaCheckDirectoryExists(
pszCachePath,
&bExists);
BAIL_ON_LSA_ERROR(dwError);
if (!bExists) {
mode_t cacheDirMode = S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH;
dwError = LsaCreateDirectory(pszCachePath, cacheDirMode);
BAIL_ON_LSA_ERROR(dwError);
}
cleanup:
LW_SAFE_FREE_STRING(pszCachePath);
return dwError;
error:
goto cleanup;
}
BOOLEAN
LsaSrvShouldStartAsDaemon(
VOID
)
{
BOOLEAN bResult = FALSE;
BOOLEAN bInLock = FALSE;
LSA_LOCK_SERVERINFO(bInLock);
bResult = (gpServerInfo->dwStartAsDaemon != 0);
LSA_UNLOCK_SERVERINFO(bInLock);
return bResult;
}
DWORD
LsaSrvStartAsDaemon(
VOID
)
{
DWORD dwError = 0;
pid_t pid;
int fd = 0;
int iFd = 0;
/* Use dcethread_fork() rather than fork() because we link with DCE/RPC */
if ((pid = dcethread_fork()) != 0) {
// Parent terminates
exit (0);
}
// Let the first child be a session leader
setsid();
// Ignore SIGHUP, because when the first child terminates
// it would be a session leader, and thus all processes in
// its session would receive the SIGHUP signal. By ignoring
// this signal, we are ensuring that our second child will
// ignore this signal and will continue execution.
dwError = LsaSrvIgnoreSIGHUP();
BAIL_ON_LSA_ERROR(dwError);
// Spawn a second child
if ((pid = fork()) != 0) {
// Let the first child terminate
// This will ensure that the second child cannot be a session leader
// Therefore, the second child cannot hold a controlling terminal
exit(0);
}
// This is the second child executing
dwError = chdir("/");
BAIL_ON_LSA_ERROR(dwError);
// Clear our file mode creation mask
umask(0);
for (iFd = 0; iFd < 3; iFd++)
close(iFd);
for (iFd = 0; iFd < 3; iFd++) {
fd = open("/dev/null", O_RDWR, 0);
if (fd < 0) {
fd = open("/dev/null", O_WRONLY, 0);
}
if (fd < 0) {
exit(1);
}
if (fd != iFd) {
exit(1);
}
}
return (dwError);
error:
return (dwError);
}
DWORD
LsaSrvGetProcessExitCode(
PDWORD pdwExitCode
)
{
DWORD dwError = 0;
BOOLEAN bInLock = FALSE;
LSA_LOCK_SERVERINFO(bInLock);
*pdwExitCode = gpServerInfo->dwExitCode;
LSA_UNLOCK_SERVERINFO(bInLock);
return dwError;
}
VOID
LsaSrvSetProcessExitCode(
DWORD dwExitCode
)
{
BOOLEAN bInLock = FALSE;
LSA_LOCK_SERVERINFO(bInLock);
gpServerInfo->dwExitCode = dwExitCode;
LSA_UNLOCK_SERVERINFO(bInLock);
}
DWORD
LsaSrvGetCachePath(
PSTR* ppszPath
)
{
DWORD dwError = 0;
PSTR pszPath = NULL;
BOOLEAN bInLock = FALSE;
LSA_LOCK_SERVERINFO(bInLock);
if (LW_IS_NULL_OR_EMPTY_STR(gpServerInfo->szCachePath)) {
dwError = LW_ERROR_INVALID_CACHE_PATH;
BAIL_ON_LSA_ERROR(dwError);
}
dwError = LwAllocateString(gpServerInfo->szCachePath, &pszPath);
BAIL_ON_LSA_ERROR(dwError);
*ppszPath = pszPath;
cleanup:
LSA_UNLOCK_SERVERINFO(bInLock);
return dwError;
error:
LW_SAFE_FREE_STRING(pszPath);
*ppszPath = NULL;
goto cleanup;
}
DWORD
LsaSrvGetPrefixPath(
PSTR* ppszPath
)
{
DWORD dwError = 0;
PSTR pszPath = NULL;
BOOLEAN bInLock = FALSE;
LSA_LOCK_SERVERINFO(bInLock);
if (LW_IS_NULL_OR_EMPTY_STR(gpServerInfo->szPrefixPath)) {
dwError = LW_ERROR_INVALID_PREFIX_PATH;
BAIL_ON_LSA_ERROR(dwError);
}
dwError = LwAllocateString(gpServerInfo->szPrefixPath, &pszPath);
BAIL_ON_LSA_ERROR(dwError);
*ppszPath = pszPath;
cleanup:
LSA_UNLOCK_SERVERINFO(bInLock);
return dwError;
error:
LW_SAFE_FREE_STRING(pszPath);
*ppszPath = NULL;
goto cleanup;
}
#ifdef ENABLE_PIDFILE
VOID
LsaSrvCreatePIDFile(
VOID
)
{
int result = -1;
pid_t pid;
char contents[PID_FILE_CONTENTS_SIZE];
size_t len;
int fd = -1;
pid = LsaSrvGetPidFromPidFile();
if (pid > 0) {
fprintf(stderr, "Daemon already running as %d\n", (int) pid);
result = -1;
goto error;
}
fd = open(PID_FILE, O_CREAT | O_WRONLY | O_EXCL, 0644);
if (fd < 0) {
fprintf(stderr, "Could not create pid file: %s\n", strerror(errno));
result = 1;
goto error;
}
pid = getpid();
snprintf(contents, sizeof(contents)-1, "%d\n", (int) pid);
contents[sizeof(contents)-1] = 0;
len = strlen(contents);
result = (int) write(fd, contents, len);
if ( result != (int) len ) {
fprintf(stderr, "Could not write to pid file: %s\n", strerror(errno));
result = -1;
goto error;
}
result = 0;
error:
if (fd != -1) {
close(fd);
}
if (result < 0) {
exit(1);
}
}
static
pid_t
LsaSrvGetPidFromPidFile(
VOID
)
{
pid_t pid = 0;
int fd = -1;
int result;
char contents[PID_FILE_CONTENTS_SIZE];
fd = open(PID_FILE, O_RDONLY, 0644);
if (fd < 0) {
goto error;
}
result = read(fd, contents, sizeof(contents)-1);
if (result <= 0) {
goto error;
}
contents[result-1] = 0;
result = atoi(contents);
if (result <= 0) {
result = -1;
goto error;
}
pid = (pid_t) result;
result = kill(pid, 0);
if (result != 0 || errno == ESRCH) {
unlink(PID_FILE);
pid = 0;
}
error:
if (fd != -1) {
close(fd);
}
return pid;
}
static
VOID
LsaSrvRemovePidFile(
VOID
)
{
if (LsaSrvGetPidFromPidFile() == getpid())
{
unlink(PID_FILE);
}
}
#endif
DWORD
LsaBlockSelectedSignals(
VOID
)
{
DWORD dwError = 0;
sigset_t default_signal_mask;
sigset_t old_signal_mask;
sigemptyset(&default_signal_mask);
sigaddset(&default_signal_mask, SIGINT);
sigaddset(&default_signal_mask, SIGTERM);
sigaddset(&default_signal_mask, SIGHUP);
sigaddset(&default_signal_mask, SIGQUIT);
sigaddset(&default_signal_mask, SIGPIPE);
dwError = pthread_sigmask(SIG_BLOCK, &default_signal_mask, &old_signal_mask);
BAIL_ON_LSA_ERROR(dwError);
cleanup:
return dwError;
error:
goto cleanup;
}
BOOLEAN
LsaSrvShouldProcessExit(
VOID
)
{
BOOLEAN bExit = FALSE;
BOOLEAN bInLock = FALSE;
LSA_LOCK_SERVERINFO(bInLock);
bExit = gpServerInfo->bProcessShouldExit;
LSA_UNLOCK_SERVERINFO(bInLock);
return bExit;
}
VOID
LsaSrvSetProcessToExit(
BOOLEAN bExit
)
{
BOOLEAN bInLock = FALSE;
LSA_LOCK_SERVERINFO(bInLock);
gpServerInfo->bProcessShouldExit = bExit;
LSA_UNLOCK_SERVERINFO(bInLock);
}
VOID
LsaSrvLogProcessStartedEvent(
VOID
)
{
DWORD dwError = 0;
PSTR pszDescription = NULL;
dwError = LwAllocateStringPrintf(
&pszDescription,
"The Likewise authentication service was started.");
BAIL_ON_LSA_ERROR(dwError);
LsaSrvLogServiceSuccessEvent(
LSASS_EVENT_INFO_SERVICE_STARTED,
SERVICE_EVENT_CATEGORY,
pszDescription,
NULL);
cleanup:
LW_SAFE_FREE_STRING(pszDescription);
return;
error:
goto cleanup;
}
VOID
LsaSrvLogProcessStoppedEvent(
DWORD dwExitCode
)
{
DWORD dwError = 0;
PSTR pszDescription = NULL;
PSTR pszData = NULL;
dwError = LwAllocateStringPrintf(
&pszDescription,
"The Likewise authentication service was stopped");
BAIL_ON_LSA_ERROR(dwError);
dwError = LsaGetErrorMessageForLoggingEvent(
dwExitCode,
&pszData);
BAIL_ON_LSA_ERROR(dwError);
if (dwExitCode)
{
LsaSrvLogServiceFailureEvent(
LSASS_EVENT_ERROR_SERVICE_STOPPED,
SERVICE_EVENT_CATEGORY,
pszDescription,
pszData);
}
else
{
LsaSrvLogServiceSuccessEvent(
LSASS_EVENT_INFO_SERVICE_STOPPED,
SERVICE_EVENT_CATEGORY,
pszDescription,
pszData);
}
cleanup:
LW_SAFE_FREE_STRING(pszDescription);
LW_SAFE_FREE_STRING(pszData);
return;
error:
goto cleanup;
}
VOID
LsaSrvLogProcessFailureEvent(
DWORD dwErrCode
)
{
DWORD dwError = 0;
PSTR pszDescription = NULL;
PSTR pszData = NULL;
dwError = LwAllocateStringPrintf(
&pszDescription,
"The Likewise authentication service stopped running due to an error");
BAIL_ON_LSA_ERROR(dwError);
dwError = LsaGetErrorMessageForLoggingEvent(
dwErrCode,
&pszData);
BAIL_ON_LSA_ERROR(dwError);
LsaSrvLogServiceFailureEvent(
LSASS_EVENT_ERROR_SERVICE_START_FAILURE,
SERVICE_EVENT_CATEGORY,
pszDescription,
pszData);
cleanup:
LW_SAFE_FREE_STRING(pszDescription);
LW_SAFE_FREE_STRING(pszData);
return;
error:
goto cleanup;
}