Example #1
0
File: mail.c Project: avkrotov/fdm
int
mail_receive(struct mail *m, struct msg *msg, int destroy)
{
	struct mail	*mm = &msg->data.mail;

	mm->idx = m->idx;

	mm->tags = m->tags;
	m->tags = NULL;
	mm->attach = m->attach;
	m->attach = NULL;

	mm->auxfree = m->auxfree;
	m->auxfree = NULL;
	mm->auxdata = m->auxdata;
	m->auxdata = NULL;

	if (destroy)
		mail_destroy(m);
	else
		mail_close(m);

	memcpy(m, mm, sizeof *m);
	if ((m->base = shm_reopen(&m->shm)) == NULL)
		return (-1);
	SHM_REGISTER(&m->shm);

	m->data = m->base + m->off;
	ARRAY_INIT(&m->wrapped);
	m->wrapchar = '\0';

	return (0);
}
Example #2
0
void
child_deliver_action_hook(pid_t pid, struct account *a, struct msg *msg,
    struct child_deliver_data *data, int *result)
{
	struct actitem		*ti = data->actitem;
	struct deliver_ctx	*dctx = data->dctx;
	struct mail		*m = data->mail;
	struct mail		*md = &dctx->wr_mail;

	/* Check if this is the parent. */
	if (pid != 0) {
		/* Use new mail if necessary. */
		if (ti->deliver->type != DELIVER_WRBACK) {
			xfree(dctx);
			return;
		}

		if (*result != DELIVER_SUCCESS)
			mail_destroy(md);
		else {
			mail_close(md);
			if (mail_receive(m, msg, 0) != 0) {
				log_warn("parent_deliver: can't receive mail");
				*result = DELIVER_FAILURE;
			}
		}

		xfree(dctx);
		return;
	}

	dctx->udata = xmalloc(sizeof *dctx->udata);
	dctx->udata->uid = data->uid;
	dctx->udata->gid =  data->gid;
	dctx->udata->name = xstrdup(find_tag(m->tags, "user"));
	dctx->udata->home = xstrdup(find_tag(m->tags, "home"));
	log_debug2("%s: deliver user is: %s (%lu/%lu), home is: %s", a->name,
	    dctx->udata->name, (u_long) dctx->udata->uid,
	    (u_long) dctx->udata->gid, dctx->udata->home);

	/* This is the child. do the delivery. */
	*result = ti->deliver->deliver(dctx, ti);
	if (ti->deliver->type != DELIVER_WRBACK || *result != DELIVER_SUCCESS) {
		user_free(dctx->udata);
		return;
	}
	user_free(dctx->udata);

	mail_send(md, msg);
	log_debug2("%s: using new mail, size %zu", a->name, md->size);
}
Example #3
0
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);
}
Example #4
0
/**
 * @brief	Retrieve a user's message, in response to a POP3 RETR command.
 * @note	This function will fail if a deleted message was specified by the user.
 * @param	con		the POP3 client connection issuing the command.
 * @return	This function returns no value.
 */
void pop_retr(connection_t *con) {

	uint64_t number;
	meta_message_t *meta;
	mail_message_t *message;

	if (con->pop.session_state != 1) {
		pop_invalid(con);
		return;
	}

	// Which message are we getting.
	if (!pop_num_parse(con, &number, true)) {
		con_write_bl(con, "-ERR The retrieve command requires a numeric argument.\r\n", 56);
		return;
	}

	meta_user_rlock(con->pop.user);

	// Get the message.
	if (!(meta = pop_get_message(con->pop.user->messages, number))) {
		meta_user_unlock(con->pop.user);
		con_write_bl(con, "-ERR Message not found.\r\n", 25);
		return;
	}

	// Check for deletion.
	if ((meta->status & MAIL_STATUS_HIDDEN) == MAIL_STATUS_HIDDEN) {
		meta_user_unlock(con->pop.user);
		con_write_bl(con,  "-ERR This message has been marked for deletion.\r\n", 49);
		return;
	}

	// Load the message and spit back the right number of lines.
	if (!(message = mail_load_message(meta, con->pop.user, con->server, 1))) {
		meta_user_unlock(con->pop.user);
		con_write_bl(con, "-ERR The message you requested could not be loaded into memory. It has either been "
			"deleted by another connection or is corrupted.\r\n", 131);
		return;
	}

	meta_user_unlock(con->pop.user);

	// Dot stuff the message.
	st_replace(&(message->text), PLACER("\n.", 2), PLACER("\n..", 3));

	// Tell the client to prepare for a message. The size is strictly informational.
	con_print(con, "+OK %u characters follow.\r\n", st_length_get(message->text));

	// We use raw socket IO because it is much faster when writing large amounts of data.
	con_write_st(con, message->text);

	// If the message didn't end with a line break, spit two.
	if (*(st_char_get(message->text) + st_length_get(message->text) - 1) == '\n') {
		con_write_bl(con, ".\r\n", 3);
	}
	else {
		con_write_bl(con, "\r\n.\r\n", 5);
	}

	mail_destroy(message);

	return;
}
Example #5
0
/**
 *  Create a new mail message.
 *
 *  The space pointed to by errstr should be large enough to
 *  hold MAX_MAIL_ERROR bytes. Any less than that and the error
 *  message could be truncated.
 *
 *  If errlen is 0 then no error message is written to errstr
 *  and errstr can be NULL.
 *
 *  @param  from    - who the message is from
 *  @param  to      - comma delimited list of recipients
 *  @param  cc      - comma delimited carbon copy list
 *  @param  subject - message subject
 *  @param  flags   - control flags
 *  @param  errlen  - length of the error message buffer
 *  @param  errstr  - output: error message
 *
 *  Control Flags:
 *
 *    - MAIL_ADD_NEWLINE - Add a newline after every mail message added.
 *
 *  @return
 *    - pointer to the new Mail message
 *    - NULL if:
 *        - the sendmail program could not be found
 *        - a memory allocation error occurred
 */
Mail *mail_create(
    const char  *from,
    const char  *to,
    const char  *cc,
    const char  *subject,
    int          flags,
    size_t      errlen,
    char       *errstr)
{
    Mail *mail;
    int   alloc_error;

    /* Find the sendmail program if it has not already been found */

    if (gSendMailPath[0] == '\0') {

        if (access("/usr/lib/sendmail", X_OK) == 0) {
            strcpy(gSendMailPath, "/usr/lib/sendmail");
        }
        else if (access("/usr/sbin/sendmail", X_OK) == 0) {
            strcpy(gSendMailPath, "/usr/sbin/sendmail");
        }
        else {

            snprintf(errstr, errlen,
                "Could not create mail message: '%s'\n"
                " -> sendmail program not found\n", subject);

            return((Mail *)NULL);
        }
    }

    /* Create the Mail structure */

    mail = (Mail *)calloc(1, sizeof(Mail));

    if (!mail) {

        snprintf(errstr, errlen,
            "Could not create mail message: '%s'\n"
            " -> memory allocation error\n", subject);

        return((Mail *)NULL);
    }

    alloc_error = 0;

    if (from) {

        mail->from = msngr_copy_string(from);
        if (!mail->from) {
            alloc_error = 1;
        }
    }

    if (to && !alloc_error) {

        mail->to = msngr_copy_string(to);
        if (!mail->to) {
            alloc_error = 1;
        }
    }

    if (cc && !alloc_error) {

        mail->cc = msngr_copy_string(cc);
        if (!mail->cc) {
            alloc_error = 1;
        }
    }

    if (subject && !alloc_error) {

        mail->subject = msngr_copy_string(subject);
        if (!mail->subject) {
            alloc_error = 1;
        }
    }

    if (!alloc_error) {

        mail->length   = 0;
        mail->nalloced = MAIL_BODY_GROWTH_SIZE;

        mail->body = (char *)calloc(mail->nalloced, sizeof(char));
        if (!mail->body) {
            alloc_error = 1;
        }
    }

    if (!alloc_error) {

        mail->errstr = (char *)calloc(MAX_MAIL_ERROR, sizeof(char));
        if (!mail->errstr) {
            alloc_error = 1;
        }
    }

    if (alloc_error) {

        mail_destroy(mail);

        snprintf(errstr, errlen,
            "Could not create mail message: '%s'\n"
            " -> memory allocation error\n", subject);

        return((Mail *)NULL);
    }

    mail->flags = flags;

    return(mail);
}
Example #6
0
/* Mail state. Find and read mail file. */
int
fetch_mbox_state_mail(struct account *a, struct fetch_ctx *fctx)
{
	struct fetch_mbox_data		*data = a->data;
	struct mail			*m = fctx->mail;
	struct fetch_mbox_mbox		*fmbox;
	struct fetch_mbox_mail		*aux;
	char				*line, *ptr, *lptr;
	size_t				 llen;
	int				 flushing;

	/* Find current mbox and check for EOF. */
	fmbox = ARRAY_ITEM(&data->fmboxes, data->index);
	if (data->off == fmbox->size) {
		fctx->state = fetch_mbox_state_next;
		return (FETCH_AGAIN);
	}

	/* Open the mail. */
	if (mail_open(m, IO_BLOCKSIZE) != 0) {
		log_warn("%s: failed to create mail", a->name);
		mail_destroy(m);
		return (FETCH_ERROR);
	}

	/* Create aux data. */
	aux = xmalloc(sizeof *aux);
	aux->off = data->off;
	aux->size = 0;
	aux->fmbox = fmbox;
	if (++fmbox->reference == 0)
		fatalx("reference count overflow");
	m->auxdata = aux;
	m->auxfree = fetch_mbox_free;

	/* Tag mail. */
	default_tags(&m->tags, NULL);
	add_tag(&m->tags, "mbox", "%s", xbasename(fmbox->path));
	add_tag(&m->tags, "mbox_path", "%s", xdirname(fmbox->path));
	add_tag(&m->tags, "mbox_file", "%s", fmbox->path);

	/*
	 * We start at a "From " line and include it in the mail (it can be
	 * trimmed later with minimal penalty).
	 */
	flushing = 0;
	for (;;) {
		/* Check for EOF. */
		if (data->off == fmbox->size) {
			aux->size = data->off - aux->off;
			break;
		}

		/* Locate the EOL. */
		line = fmbox->base + data->off;
		ptr = memchr(line, '\n', fmbox->size - data->off);
		if (ptr == NULL) {
			ptr = fmbox->base + fmbox->size;
			data->off = fmbox->size;
		} else
			data->off += ptr - line + 1;

		/* Check if the line is "From ". */
		if (line > fmbox->base &&
		    ptr - line >= 5 && strncmp(line, "From ", 5) == 0) {
			/* End of mail. */
			aux->size = (line - fmbox->base) - aux->off;
			break;
		}

		/* Trim >s from From. */
		if (*line == '>') {
			lptr = line;
			llen = ptr - line;
			while (*lptr == '>' && llen > 0) {
				lptr++;
				llen--;
			}

			if (llen >= 5 && strncmp(lptr, "From ", 5) == 0)
				line++;
		}

		if (flushing)
			continue;
		if (append_line(m, line, ptr - line) != 0) {
			log_warn("%s: failed to resize mail", a->name);
			mail_destroy(m);
			return (FETCH_ERROR);
		}
		if (m->size > conf.max_size)
			flushing = 1;
	}
	fmbox->total++;

	/*
	 * Check if there was a blank line between the mails and remove it if
	 * so.
	 */
	if (aux->size >= 2 &&
	    fmbox->base[aux->off + aux->size - 1] == '\n' &&
	    fmbox->base[aux->off + aux->size - 2] == '\n') {
		aux->size -= 2;
		m->size -= 2;
	}

	return (FETCH_MAIL);
}