/* $Id$ */
/*
* Copyright (c) 2006 Nicholas Marriott <nicholas.marriott@gmail.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <paths.h>
#include <string.h>
#include <unistd.h>
#include "fdm.h"
#include "deliver.h"
#include "match.h"
void parent_fetch_error(struct child *, struct msg *);
void parent_fetch_action(struct child *, struct children *,
struct deliver_ctx *, struct msg *);
void parent_fetch_cmd(struct child *, struct children *, struct mail_ctx *,
struct msg *);
int
parent_fetch(struct child *child, struct msg *msg, struct msgbuf *msgbuf)
{
struct child_fetch_data *data = child->data;
struct children *children = data->children;
struct deliver_ctx *dctx;
struct mail_ctx *mctx;
struct mail *m;
switch (msg->type) {
case MSG_ACTION:
if (msgbuf->buf == NULL || msgbuf->len == 0)
fatalx("bad tags");
m = xcalloc(1, sizeof *m);
if (mail_receive(m, msg, 0) != 0) {
log_warn("parent: can't receive mail");
parent_fetch_error(child, msg);
break;
}
m->tags = msgbuf->buf;
dctx = xcalloc(1, sizeof *dctx);
dctx->account = msg->data.account;
dctx->mail = m;
parent_fetch_action(child, children, dctx, msg);
break;
case MSG_COMMAND:
if (msgbuf->buf == NULL || msgbuf->len == 0)
fatalx("bad tags");
m = xcalloc(1, sizeof *m);
if (mail_receive(m, msg, 0) != 0) {
log_warn("parent: can't receive mail");
parent_fetch_error(child, msg);
break;
}
m->tags = msgbuf->buf;
mctx = xcalloc(1, sizeof *mctx);
mctx->account = msg->data.account;
mctx->mail = m;
parent_fetch_cmd(child, children, mctx, msg);
break;
case MSG_DONE:
fatalx("unexpected message");
case MSG_EXIT:
return (-1);
}
return (0);
}
void
parent_fetch_error(struct child *child, struct msg *msg)
{
msg->type = MSG_DONE;
msg->data.error = DELIVER_FAILURE;
if (privsep_send(child->io, msg, NULL) != 0)
fatalx("privsep_send error");
}
void
parent_fetch_action(struct child *child, struct children *children,
struct deliver_ctx *dctx, struct msg *msg)
{
struct actitem *ti = msg->data.actitem;
struct mail *m = dctx->mail;
struct mail *md = &dctx->wr_mail;
struct child_deliver_data *data;
uid_t uid = msg->data.uid;
gid_t gid = msg->data.gid;
memset(md, 0, sizeof *md);
/*
* If writing back, open a new mail now and set its ownership so it
* can be accessed by the child.
*/
if (ti->deliver->type == DELIVER_WRBACK) {
if (mail_open(md, IO_BLOCKSIZE) != 0) {
log_warn("parent: failed to create mail");
parent_fetch_error(child, msg);
return;
}
if (geteuid() == 0 &&
shm_owner(&md->shm, conf.child_uid, conf.child_gid) != 0) {
mail_destroy(md);
log_warn("parent: failed to set mail ownership");
parent_fetch_error(child, msg);
return;
}
md->decision = m->decision;
}
data = xmalloc(sizeof *data);
data->child = child;
data->msgid = msg->id;
data->account = dctx->account;
data->hook = child_deliver_action_hook;
data->actitem = ti;
data->dctx = dctx;
data->mail = m;
data->name = "deliver";
data->uid = uid;
data->gid = gid;
child = child_start(
children, uid, gid, child_deliver, parent_deliver, data, child);
log_debug3("parent: deliver "
"child %ld started (uid %lu)", (long) child->pid, (u_long) uid);
}
void
parent_fetch_cmd(struct child *child, struct children *children,
struct mail_ctx *mctx, struct msg *msg)
{
struct mail *m = mctx->mail;
struct child_deliver_data *data;
uid_t uid = msg->data.uid;
gid_t gid = msg->data.gid;
data = xmalloc(sizeof *data);
data->child = child;
data->msgid = msg->id;
data->account = mctx->account;
data->hook = child_deliver_cmd_hook;
data->mctx = mctx;
data->cmddata = msg->data.cmddata;
data->mail = m;
data->name = "command";
data->uid = uid;
data->gid = gid;
child = child_start(
children, uid, gid, child_deliver, parent_deliver, data, child);
log_debug3("parent: command "
"child %ld started (uid %lu)", (long) child->pid, (u_long) uid);
}