version 1.7.4.6, 2008/11/19 01:06:20
|
version 1.8, 2007/11/28 12:44:18
|
|
|
#include <sys/wait.h> | #include <sys/wait.h> |
#include <unistd.h> | #include <unistd.h> |
#include <signal.h> | #include <signal.h> |
|
#include <grp.h> |
#include "Parent.h" | #include "Parent.h" |
#include "Log.h" | #include "Log.h" |
#include "Messages.h" | #include "Messages.h" |
|
|
#include "PasswordFile.h" | #include "PasswordFile.h" |
#include "Policy.h" | #include "Policy.h" |
#include "Macro.h" | #include "Macro.h" |
#include "FileHandle.h" |
|
| |
#if defined(PEGASUS_PAM_AUTHENTICATION) | #if defined(PEGASUS_PAM_AUTHENTICATION) |
# include "PAMAuth.h" | # include "PAMAuth.h" |
|
|
case 'w': | case 'w': |
fd = open( | fd = open( |
request.path, | request.path, |
O_WRONLY | O_TRUNC, |
O_WRONLY | O_CREAT | O_TRUNC, |
permissions); | permissions); |
break; | break; |
| |
|
|
{ | { |
fd = open( | fd = open( |
request.path, | request.path, |
O_WRONLY | O_APPEND, |
O_WRONLY | O_CREAT | O_APPEND, |
permissions); | permissions); |
break; | break; |
} | } |
} | } |
/* If the open call fails with ENOENT errno,then create the file. |
|
If the umask is set to a non default value,then the file will not |
|
get created with permissions specified in the open system call. |
|
So set the permissions for the file explicitly using fchmod. |
|
*/ |
|
if (fd == -1) | if (fd == -1) |
{ |
|
if (errno == ENOENT && (request.mode == 'w' || request.mode == 'a')) |
|
{ |
|
fd = open(request.path,O_CREAT | O_WRONLY,permissions); |
|
if (fchmod(fd,permissions) != 0) |
|
{ |
|
response.status = -1; | response.status = -1; |
close(fd); |
|
} |
|
} |
|
else |
|
{ |
|
response.status = -1; |
|
} |
|
} |
|
} | } |
while (0); | while (0); |
| |
|
|
| |
if (pipe(from) != 0) | if (pipe(from) != 0) |
{ | { |
close(to[0]); |
|
close(to[1]); |
|
status = -1; | status = -1; |
break; | break; |
} | } |
|
|
if (pid < 0) | if (pid < 0) |
{ | { |
Log(LL_SEVERE, "fork failed"); | Log(LL_SEVERE, "fork failed"); |
close(to[0]); |
|
close(to[1]); |
|
close(from[0]); |
|
close(from[1]); |
|
status = -1; | status = -1; |
break; | break; |
} | } |
|
|
| |
if (pid == 0) | if (pid == 0) |
{ | { |
char toPipeArg[32]; |
struct rlimit rlim; |
char fromPipeArg[32]; |
char arg1[32]; |
/* The user context is set here; no need to do it in cimprovagt. */ |
char arg2[32]; |
const char* setUserContextFlag = "0"; |
|
| |
/* Close unused pipe descriptors: */ | /* Close unused pipe descriptors: */ |
| |
close(to[1]); | close(to[1]); |
close(from[0]); | close(from[0]); |
| |
/* Redirect terminal I/O if required and not yet daemonized. */ |
|
|
|
if (globals.initCompletePipe != -1 && !globals.bindVerbose) |
|
{ |
|
RedirectTerminalIO(); |
|
} |
|
|
|
/* | /* |
* Close unused descriptors. Leave stdin, stdout, stderr, and the | * Close unused descriptors. Leave stdin, stdout, stderr, and the |
* child's pipe descriptors open. | * child's pipe descriptors open. |
*/ | */ |
| |
CloseUnusedDescriptors(to[0], from[1]); |
if (getrlimit(RLIMIT_NOFILE, &rlim) == 0) |
|
{ |
|
int i; |
|
|
|
for (i = 3; i < (int)rlim.rlim_cur; i++) |
|
{ |
|
if (i != to[0] && i != from[1]) |
|
close(i); |
|
} |
|
} |
| |
#if !defined(PEGASUS_DISABLE_PROV_USERCTXT) | #if !defined(PEGASUS_DISABLE_PROV_USERCTXT) |
| |
SetUserContext(request.userName, uid, gid); |
if ((int)getgid() != gid) |
|
{ |
|
if (setgid((gid_t)gid) != 0) |
|
{ |
|
Log(LL_SEVERE, "setgid(%d) failed\n", gid); |
|
_exit(1); |
|
} |
|
} |
|
|
|
if ((int)getuid() != uid) |
|
{ |
|
if (initgroups(request.userName, gid) != 0) |
|
{ |
|
Log(LL_SEVERE, "initgroups(%s, %d) failed\n", |
|
request.userName, |
|
gid); |
|
_exit(1); |
|
} |
|
|
|
if (setuid((uid_t)uid) != 0) |
|
{ |
|
Log(LL_SEVERE, "setuid(%d) failed\n", uid); |
|
_exit(1); |
|
} |
|
} |
| |
Log(LL_TRACE, "starting %s on module %s as user %s", | Log(LL_TRACE, "starting %s on module %s as user %s", |
path, request.module, request.userName); | path, request.module, request.userName); |
|
|
| |
/* Exec the CIMPROVAGT program. */ | /* Exec the CIMPROVAGT program. */ |
| |
sprintf(toPipeArg, "%d", to[0]); |
sprintf(arg1, "%d", to[0]); |
sprintf(fromPipeArg, "%d", from[1]); |
sprintf(arg2, "%d", from[1]); |
| |
Log(LL_TRACE, "execl(%s, %s, %s, %s, %s, %s, %s)\n", |
Log(LL_TRACE, "execl(%s, %s, %s, %s, %s)\n", |
path, |
path, path, arg1, arg2, request.module); |
path, |
|
setUserContextFlag, |
|
toPipeArg, |
|
fromPipeArg, |
|
request.userName, |
|
request.module); |
|
| |
/* Flawfinder: ignore */ | /* Flawfinder: ignore */ |
execl( |
execl(path, path, arg1, arg2, request.module, (char*)0); |
path, |
|
path, |
|
setUserContextFlag, |
|
toPipeArg, |
|
fromPipeArg, |
|
request.userName, |
|
request.module, |
|
(char*)0); |
|
| |
Log(LL_SEVERE, "execl(%s, %s, %s, %s, %s, %s, %s): failed\n", |
Log(LL_SEVERE, "execl(%s, %s, %s, %s, %s): failed\n", |
path, |
path, path, arg1, arg2, request.module); |
path, |
|
setUserContextFlag, |
|
toPipeArg, |
|
fromPipeArg, |
|
request.userName, |
|
request.module); |
|
_exit(1); | _exit(1); |
} | } |
|
} |
|
while (0); |
| |
/* We are the parent process. Close the child's ends of the pipes. */ |
/* Close unused pipe descriptors. */ |
| |
close(to[0]); | close(to[0]); |
close(from[1]); | close(from[1]); |
} |
|
while (0); |
|
| |
/* Send response. */ | /* Send response. */ |
| |
|
|
**============================================================================== | **============================================================================== |
*/ | */ |
| |
static void HandleDaemonizeExecutorRequest(int sock) |
static void HandleDaemonizeExecutorRequest(int sock, int bindVerbose) |
{ | { |
struct ExecutorDaemonizeExecutorResponse response; | struct ExecutorDaemonizeExecutorResponse response; |
int pid; | int pid; |
|
|
| |
Log(LL_TRACE, "HandleDaemonizeExecutorRequest()"); | Log(LL_TRACE, "HandleDaemonizeExecutorRequest()"); |
| |
if (!globals.bindVerbose) |
/* Fork (parent exits; child continues) */ |
|
/* (Ensures we are not a session leader so that setsid() will succeed.) */ |
|
|
|
pid = fork(); |
|
|
|
if (pid < 0) |
{ | { |
RedirectTerminalIO(); |
response.status = -1; |
|
Fatal(FL, "fork() failed"); |
} | } |
| |
if (globals.initCompletePipe != -1) |
if (pid > 0) |
|
_exit(0); |
|
|
|
/* Become session leader (so that our child process will not be one) */ |
|
|
|
if (setsid() < 0) |
|
{ |
|
response.status = -1; |
|
Fatal(FL, "setsid() failed"); |
|
} |
|
|
|
/* Ignore SIGHUP: */ |
|
|
|
signal(SIGHUP, SIG_IGN); |
|
|
|
/* Ignore SIGCHLD: */ |
|
|
|
signal(SIGCHLD, SIG_IGN); |
|
|
|
/* Fork again (so we are not a session leader because our parent is): */ |
|
|
|
pid = fork(); |
|
|
|
if (pid < 0) |
|
{ |
|
response.status = -1; |
|
Fatal(FL, "fork() failed"); |
|
} |
|
|
|
if (pid > 0) |
|
_exit(0); |
|
|
|
/* Catch SIGTERM: */ |
|
|
|
signal(SIGTERM, _sigHandler); |
|
|
|
if (!bindVerbose) |
{ | { |
ssize_t result; |
/* Close these file descriptors (stdin, stdout, stderr). */ |
|
|
|
close(0); |
|
close(1); |
|
close(2); |
|
|
|
/* Direct standard input, output, and error to /dev/null: */ |
| |
EXECUTOR_RESTART(write(globals.initCompletePipe, "\0", 1), result); |
open("/dev/null", O_RDONLY); |
close(globals.initCompletePipe); |
open("/dev/null", O_RDWR); |
globals.initCompletePipe = -1; |
open("/dev/null", O_RDWR); |
} | } |
| |
response.status = 0; | response.status = 0; |
|
|
} | } |
while (0); | while (0); |
| |
Log(LL_TRACE, "Basic authentication attempt: username = %s, " |
if (status != 0) |
"successful = %s", |
{ |
request.username, status == 0 ? "TRUE" : "FALSE" ); |
Log(LL_WARNING, "Basic authentication failed for username %s", |
|
request.username); |
|
} |
|
else |
|
{ |
|
Log(LL_TRACE, "Basic authentication succeeded for username %s", |
|
request.username); |
|
} |
| |
/* Send response message. */ | /* Send response message. */ |
| |
|
|
| |
#endif /* !PEGASUS_PAM_AUTHENTICATION */ | #endif /* !PEGASUS_PAM_AUTHENTICATION */ |
| |
|
if (status != 0) |
|
Log(LL_WARNING, "User validation failed on %s", request.username); |
|
|
/* Send response message. */ | /* Send response message. */ |
| |
response.status = status; | response.status = status; |
|
|
| |
/* Send response message. */ | /* Send response message. */ |
| |
if (response.status == 0) |
if (response.status != 0) |
|
{ |
|
Log(LL_WARNING, "Local authentication failed for user \"%s\"", |
|
request.user); |
|
} |
|
else |
{ | { |
Strlcpy(response.challenge, challenge, sizeof(response.challenge)); | Strlcpy(response.challenge, challenge, sizeof(response.challenge)); |
} | } |
|
|
| |
status = FinishLocalAuthentication(request.challenge, request.response); | status = FinishLocalAuthentication(request.challenge, request.response); |
| |
|
/* Log result. */ |
|
|
|
if (status != 0) |
|
{ |
|
Log(LL_WARNING, "Local authentication failed"); |
|
} |
|
|
/* Send response. */ | /* Send response. */ |
| |
response.status = status; | response.status = status; |
|
|
**============================================================================== | **============================================================================== |
*/ | */ |
| |
void Parent(int sock, int initCompletePipe, int childPid, int bindVerbose) |
void Parent(int sock, int childPid, int bindVerbose) |
{ | { |
/* Handle Ctrl-C. */ | /* Handle Ctrl-C. */ |
| |
|
|
| |
globals.childPid = childPid; | globals.childPid = childPid; |
| |
/* Save initCompletePipe; it is used at daemonization. */ |
|
|
|
globals.initCompletePipe = initCompletePipe; |
|
|
|
/* Save bindVerbose; it is used at daemonization and cimprovagt start. */ |
|
|
|
globals.bindVerbose = bindVerbose; |
|
|
|
/* Prepares socket into non-blocking I/O. */ | /* Prepares socket into non-blocking I/O. */ |
| |
SetNonBlocking(sock); | SetNonBlocking(sock); |
|
|
break; | break; |
| |
case EXECUTOR_DAEMONIZE_EXECUTOR_MESSAGE: | case EXECUTOR_DAEMONIZE_EXECUTOR_MESSAGE: |
HandleDaemonizeExecutorRequest(sock); |
HandleDaemonizeExecutorRequest(sock, bindVerbose); |
break; | break; |
| |
case EXECUTOR_RENAME_FILE_MESSAGE: | case EXECUTOR_RENAME_FILE_MESSAGE: |