auth-process.c revision 54a6d29d96e243cd5c84892384c18c9830359ada
/* 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 "restrict-access.h"
#include "restrict-process-size.h"
#include "auth-process.h"
#include <stdlib.h>
#include <unistd.h>
#include <pwd.h>
#include <syslog.h>
#define MAX_INBUF_SIZE \
(sizeof(struct auth_master_reply) + AUTH_MASTER_MAX_REPLY_DATA_SIZE)
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 auth_master_reply auth_reply;
struct hash_table *requests;
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);
struct auth_master_reply *reply,
const unsigned char *data)
{
void *context;
i_error("Auth process %s sent unrequested reply with tag %u",
return TRUE;
}
/* make sure the reply looks OK */
nul_pos = 0;
data = (const unsigned char *) "";
} else {
}
i_error("Auth process %s sent invalid reply",
return FALSE;
}
/* fix the request so that all the values point to \0 terminated
strings */
return TRUE;
}
{
struct auth_master_request req;
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, "
}
return;
}
}
static void auth_process_input(void *context)
{
struct auth_process *p = context;
const unsigned char *data;
switch (i_stream_read(p->input)) {
case 0:
return;
case -1:
/* disconnected */
return;
case -2:
/* buffer full */
i_error("BUG: Auth process %s sent us more than %d "
return;
}
if (!p->initialized) {
if (data[0] != 'O') {
i_fatal("Auth process sent invalid initialization "
"notification");
}
p->initialized = TRUE;
}
for (;;) {
if (!p->in_auth_reply) {
if (size < sizeof(p->auth_reply))
break;
p->in_auth_reply = TRUE;
}
break;
/* reply is now read */
break;
}
p->in_auth_reply = FALSE;
}
}
static struct auth_process *
{
struct auth_process *p;
sizeof(struct auth_master_request)*100,
FALSE);
group->process_count++;
return p;
}
{
}
static void auth_process_destroy(struct auth_process *p)
{
struct auth_process **pos;
i_error("Auth process died too early - shutting down");
}
if (*pos == p) {
break;
}
}
p->group->process_count--;
hash_destroy(p->requests);
i_stream_unref(p->input);
o_stream_unref(p->output);
i_error("close(auth) failed: %m");
i_free(p);
}
{
int fd[2], i;
/* create communication to process with a socket pair */
i_error("socketpair() failed: %m");
return -1;
}
if (pid < 0) {
i_error("fork() failed: %m");
return -1;
}
if (pid != 0) {
/* master */
return pid;
}
/* move master communication handle to 0 */
i_fatal("login: dup2(0) failed: %m");
leave stderr alone, we might want to use it for logging. */
i_fatal("login: dup2(1) failed: %m");
/* move login communication handle to 3. do it last so we can be
sure it's not closed afterwards. */
i_fatal("login: dup2() failed: %m");
}
for (i = 0; i <= 3; i++)
fd_close_on_exec(i, FALSE);
/* setup access environment */
/* set other environment */
env_put("USE_CYRUS_SASL=1");
env_put("VERBOSE=1");
/* make sure we don't leak syslog fd, but do it last so that
any errors above will be logged */
closelog();
/* hide the path, it's ugly */
else
argv[0]++;
return -1;
}
{
struct auth_process_group *group;
struct auth_process *p;
return p;
}
}
return NULL;
}
{
struct auth_process_group *group;
const char *path;
/* create socket for listening auth requests from login */
/* set correct permissions */
i_fatal("login: chown(%s, %s, %s) failed: %m",
}
}
{
struct auth_process *next;
}
}
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)
{
}