auth-process.c revision ae08adadadc5ad6a6629442b7b01785864cbfa36
/* Copyright (C) 2002 Timo Sirainen */
#include "common.h"
#include "ioloop.h"
#include "env-util.h"
#include "fd-close-on-exec.h"
#include "network.h"
#include "istream.h"
#include "ostream.h"
#include "str.h"
#include "restrict-access.h"
#include "restrict-process-size.h"
#include "auth-process.h"
#include "../auth/auth-master-interface.h"
#include "log.h"
#include <stdlib.h>
#include <unistd.h>
#include <pwd.h>
#include <syslog.h>
#define MAX_INBUF_SIZE 8192
#define MAX_OUTBUF_SIZE 65536
struct auth_process_group {
struct auth_process_group *next;
int listen_fd;
struct auth_settings *set;
unsigned int process_count;
struct auth_process *processes;
};
struct auth_process {
struct auth_process *next;
struct auth_process_group *group;
int fd;
struct hash_table *requests;
unsigned int private_listener:1;
unsigned int external:1;
unsigned int version_received:1;
unsigned int initialized:1;
unsigned int in_auth_reply:1;
};
static unsigned int auth_tag;
static struct auth_process_group *process_groups;
static void auth_process_destroy(struct auth_process *p);
{
t_push();
if (ret >= 0) {
/* FIXME: well .. I'm not sure if it'd be better to
just block here. I don't think this condition should
happen often, so this could mean that the auth
process is stuck. Or that the computer is just
too heavily loaded. Possibility to block infinitely
is annoying though, so for now don't do it. */
i_warning("Auth process %s transmit buffer full, "
}
} else {
}
t_pop();
}
static int
{
void *context;
const char *const *list;
unsigned int id;
/* <id> <userid> [..] */
i_error("BUG: Auth process %s sent corrupted USER line",
return FALSE;
}
i_error("BUG: Auth process %s sent unrequested reply with ID "
return FALSE;
}
return TRUE;
}
static int
{
void *context;
unsigned int id;
i_error("BUG: Auth process %s sent unrequested reply with ID "
return FALSE;
}
return TRUE;
}
static int
{
unsigned int pid;
if (process->initialized) {
i_error("BUG: Authentication server re-handshaking");
return FALSE;
}
if (pid == 0) {
i_error("BUG: Authentication server said it's PID 0");
return FALSE;
}
i_error("BUG: Authentication server sent invalid SPID "
return FALSE;
}
return TRUE;
}
static int
{
void *context;
const char *error;
unsigned int id;
error++;
i_error("BUG: Auth process %s sent unrequested reply with ID "
return FALSE;
}
return TRUE;
}
static void auth_process_input(void *context)
{
const char *line;
int ret;
case 0:
return;
case -1:
/* disconnected */
return;
case -2:
/* buffer full */
i_error("BUG: Auth process %s sent us more than %d "
(int)MAX_INBUF_SIZE);
return;
}
if (!process->version_received) {
return;
/* make sure the major version matches */
i_error("Auth process %s not compatible with master "
"process (mixed old and new binaries?)",
return;
}
}
t_push();
else
t_pop();
if (!ret) {
break;
}
}
}
static struct auth_process *
{
struct auth_process *p;
const char *handshake;
if (pid != 0)
FALSE);
p->private_listener = TRUE;
group->process_count++;
return p;
}
static void auth_process_destroy(struct auth_process *p)
{
struct hash_iterate_context *iter;
const char *path;
struct auth_process **pos;
i_error("Auth process died too early - shutting down");
}
if (*pos == p) {
break;
}
}
p->group->process_count--;
if (p->private_listener) {
NULL);
}
hash_destroy(p->requests);
i_stream_unref(p->input);
o_stream_unref(p->output);
i_error("close(auth) failed: %m");
i_free(p);
}
static void
{
return;
}
const char *path)
{
struct auth_process *auth;
int fd;
if (fd == -1) {
return -1;
}
return 0;
}
{
const char *path;
int fd;
NULL);
if (fd < 0)
/* set correct permissions */
i_fatal("login: chown(%s, %s, %s) failed: %m",
}
return fd;
}
{
struct auth_socket_settings *as;
/* see if this is a connect socket */
/* create communication to process with a socket pair */
i_error("socketpair() failed: %m");
return -1;
}
if (log_fd < 0)
pid = -1;
else {
if (pid < 0)
i_error("fork() failed: %m");
}
if (pid < 0) {
return -1;
}
if (pid != 0) {
/* master */
return 0;
}
/* move master communication handle to 0 */
i_fatal("dup2(stdin) failed: %m");
i_fatal("dup2(stdout) failed: %m");
i_fatal("dup2(stderr) failed: %m");
/* move login communication handle to 3. do it last so we can be
sure it's not closed afterwards. */
if (listen_fd != 3) {
i_fatal("dup2() failed: %m");
}
for (i = 0; i <= 3; i++)
fd_close_on_exec(i, FALSE);
/* setup access environment */
0, 0, NULL);
/* set other environment */
continue;
}
env_put("VERBOSE=1");
env_put("VERBOSE_DEBUG=1");
env_put("SSL_REQUIRE_CLIENT_CERT=1");
/* make sure we don't leak syslog fd, but do it last so that
any errors above will be logged */
closelog();
return -1;
}
{
struct auth_process_group *group;
struct auth_process *p;
return p;
}
}
return NULL;
}
{
struct auth_process_group *group;
return;
/* If we keep long running login processes, we want them to use
all the auth processes in round robin. this means we have to create
separate socket for all of them. So, group->listen_fd is only
used with login_process_per_connection. */
else
}
{
struct auth_process *next;
const char *path;
}
}
}
void auth_processes_destroy_all(void)
{
struct auth_process_group *next;
while (process_groups != NULL) {
}
}
{
struct auth_settings *auth_set;
}
}
static void
{
struct auth_process_group *group;
unsigned int count;
if (process_groups == NULL) {
/* first time here, create the groups */
}
(void)create_auth_process(group);
}
}
void auth_processes_init(void)
{
}
void auth_processes_deinit(void)
{
}