Ejemplo n.º 1
0
int main()
{
	volatile int i;

	trace_append("%s: setup FreeRTOS...\n", __func__);

	MboxQueue = xQueueCreate( 32, sizeof( unsigned int* ) );
	vSemaphoreCreateBinary(InitDoneSemaphore);
	xSemaphoreTake(InitDoneSemaphore, portMAX_DELAY);

	hw_init();

	xTaskCreate(LedFlash, "led", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY + 2, NULL);

	xTaskCreate(IpcTask, "ipc", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY + 1, NULL);
	xTaskCreate(RdaemonTask, "rdaemon", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY + 1, NULL);

	trace_append("%s: start FreeRTOS...\n", __func__);

	vTaskStartScheduler();

	/* Just sit and flash the LED quickly if we fail */

	while( 1 ) {
		for( i = 0; i < 50000; i++ );
        toggle_bit(GPIO_DATAOUT, 25);
	}
}
Ejemplo n.º 2
0
static void cleanup_trace_append(CLEANUP_STATE *state, RECIPIENT *rcpt,
				         DSN *dsn)
{
    MSG_STATS stats;

    if (cleanup_trace_path == 0) {
	cleanup_trace_path = vstring_alloc(10);
	mail_queue_path(cleanup_trace_path, MAIL_QUEUE_TRACE,
			state->queue_id);
    }
    if (trace_append(BOUNCE_FLAG_CLEAN, state->queue_id,
		     CLEANUP_MSG_STATS(&stats, state),
		     rcpt, "none", dsn) != 0) {
	msg_warn("%s: trace logfile update error", state->queue_id);
	state->errs |= CLEANUP_STAT_WRITE;
    }
}
Ejemplo n.º 3
0
void trace(unsigned int pc, unsigned int sp, unsigned int top)
{
	//unsigned int *spalign  = (unsigned int*)&_stack[0];
	//	if (pc < 0x40 || pc >=0x400) {
	/*
	 if (sp > sizeof(_stack)) {
	 printf("Access beyond end of stack 0x%08x\n",sp);
	 fflush(stdout);
	 abort();
	 }
	 */
	trace_append(pc,sp,top);
    /*
	printf("0x%07X 0x%02X 0x%08X 0x%08X 0x%08X 0x?u 0x%016x\n", pc,
		   _memory[pc], sp,
		   top,
		   bswap_32(spalign[ (( ( sp & (STACK_SIZE-1) ) >>2) + 1 )] ),
		   zpuino_get_tick_count()
		   );
           */
	//fflush(stdout);
	//	}
}
Ejemplo n.º 4
0
int     defer_append(int flags, const char *id, MSG_STATS *stats,
		             RECIPIENT *rcpt, const char *relay,
		             DSN *dsn)
{
    const char *rcpt_domain;
    DSN     my_dsn = *dsn;
    int     status;

    /*
     * Sanity check.
     */
    if (my_dsn.status[0] != '4' || !dsn_valid(my_dsn.status)) {
	msg_warn("defer_append: ignoring dsn code \"%s\"", my_dsn.status);
	my_dsn.status = "4.0.0";
    }

    /*
     * MTA-requested address verification information is stored in the verify
     * service database.
     */
    if (flags & DEL_REQ_FLAG_MTA_VRFY) {
	my_dsn.action = "undeliverable";
	status = verify_append(id, stats, rcpt, relay, &my_dsn,
			       DEL_RCPT_STAT_DEFER);
	return (status);
    }

    /*
     * User-requested address verification information is logged and mailed
     * to the requesting user.
     */
    if (flags & DEL_REQ_FLAG_USR_VRFY) {
	my_dsn.action = "undeliverable";
	status = trace_append(flags, id, stats, rcpt, relay, &my_dsn);
	return (status);
    }

    /*
     * Normal mail delivery. May also send a delivery record to the user.
     * 
     * XXX DSN We write all deferred recipients to the defer logfile regardless
     * of DSN NOTIFY options, because those options don't apply to mailq(1)
     * reports or to postmaster notifications.
     */
    else {

	/*
	 * Supply default action.
	 */
	my_dsn.action = "delayed";

	if (mail_command_client(MAIL_CLASS_PRIVATE, var_defer_service,
			   ATTR_TYPE_INT, MAIL_ATTR_NREQ, BOUNCE_CMD_APPEND,
				ATTR_TYPE_INT, MAIL_ATTR_FLAGS, flags,
				ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, id,
				ATTR_TYPE_FUNC, rcpt_print, (void *) rcpt,
				ATTR_TYPE_FUNC, dsn_print, (void *) &my_dsn,
				ATTR_TYPE_END) != 0)
	    msg_warn("%s: %s service failure", id, var_defer_service);
	log_adhoc(id, stats, rcpt, relay, &my_dsn, "deferred");

	/*
	 * Traced delivery.
	 */
	if (flags & DEL_REQ_FLAG_RECORD)
	    if (trace_append(flags, id, stats, rcpt, relay, &my_dsn) != 0)
		msg_warn("%s: %s service failure", id, var_trace_service);

	/*
	 * Notify the fast flush service. XXX Should not this belong in the
	 * bounce/defer daemon? Well, doing it here is more robust.
	 */
	if ((rcpt_domain = strrchr(rcpt->address, '@')) != 0
	    && *++rcpt_domain != 0)
	    switch (flush_add(rcpt_domain, id)) {
	    case FLUSH_STAT_OK:
	    case FLUSH_STAT_DENY:
		break;
	    default:
		msg_warn("%s: %s service failure", id, var_flush_service);
		break;
	    }
	return (-1);
    }
}
Ejemplo n.º 5
0
static void IpcTask (void * pvParameters)
{
	unsigned int msg, *local_vq_buf;
	int ret;
	struct virtqueue_buf virtq_buf;
    portTickType LastWake;

	trace_append("%s: starting task\n", __func__);

    /* Workaround
     *
     * We can't enable interrupts in U-Boot. Let's wait until Linux is booted
     * on CPU. Linux remoteproc framework sends a ping to IPU via mailbox when
     * its initialization is completed. This ping is a good indicator for IPU
     * that Linux and its remoteproc/rpmsg subsystems are up an running.
     */

    while (1) {
        msg = mailbox_read();

        if (msg == HOST_ECHO_REQUEST) {
            trace_append("%s: received echo request [0x%x] from CPU\n", __func__, msg);
            break;
        }

        trace_append("%s: host-to-m3 mailbox [0x%x]\n", __func__, msg);
        LastWake = xTaskGetTickCount();
        vTaskDelayUntil(&LastWake, 5000);
    }

	virtqueue_init();
	nvic_enable_irq(MAILBOX_IRQ);
	enable_mailbox_irq();

	trace_append("%s: start main loop\n", __func__);

	for (;;) {
		xQueueReceive(MboxQueue, &msg, portMAX_DELAY);

		switch(msg) {

		case RP_MBOX_ECHO_REQUEST :
			mailbox_send(M3_TO_HOST_MBX, RP_MBOX_ECHO_REPLY);
			break;

		case HOST_TO_M3_VRING :
			ret = virtqueue_get_avail_buf(&virtqueue_list[msg], &virtq_buf);

			/* make a local copy of the buffer */
			local_vq_buf = pvPortMalloc(RP_MSG_BUF_SIZE);
			memcpy(local_vq_buf, virtq_buf.buf_ptr, RP_MSG_BUF_SIZE);
			virtqueue_add_used_buf(&virtqueue_list[msg], virtq_buf.head);

			/* dispatch to the service queue */
			rpmsg_dispatch_msg(local_vq_buf);

			break;

		case M3_TO_HOST_VRING :
			xSemaphoreGive(InitDoneSemaphore);
			break;

        default:
	        trace_append("%s: unknown message\n", __func__);
            break;
		}
	}

	vTaskDelete(NULL);
}
Ejemplo n.º 6
0
int     deliver_alias(LOCAL_STATE state, USER_ATTR usr_attr,
		              char *name, int *statusp)
{
    const char *myname = "deliver_alias";
    const char *alias_result;
    char   *saved_alias_result;
    char   *owner;
    char  **cpp;
    uid_t   alias_uid;
    struct mypasswd *alias_pwd;
    VSTRING *canon_owner;
    DICT   *dict;
    const char *owner_rhs;		/* owner alias, RHS */
    int     alias_count;
    int     dsn_notify;
    char   *dsn_envid;
    int     dsn_ret;
    const char *dsn_orcpt;

    /*
     * Make verbose logging easier to understand.
     */
    state.level++;
    if (msg_verbose)
	MSG_LOG_STATE(myname, state);

    /*
     * DUPLICATE/LOOP ELIMINATION
     * 
     * We cannot do duplicate elimination here. Sendmail compatibility requires
     * that we allow multiple deliveries to the same alias, even recursively!
     * For example, we must deliver to mailbox any messags that are addressed
     * to the alias of a user that lists that same alias in her own .forward
     * file. Yuck! This is just an example of some really perverse semantics
     * that people will expect Postfix to implement just like sendmail.
     * 
     * We can recognize one special case: when an alias includes its own name,
     * deliver to the user instead, just like sendmail. Otherwise, we just
     * bail out when nesting reaches some unreasonable depth, and blame it on
     * a possible alias loop.
     */
    if (state.msg_attr.exp_from != 0
	&& strcasecmp(state.msg_attr.exp_from, name) == 0)
	return (NO);
    if (state.level > 100) {
	msg_warn("alias database loop for %s", name);
	dsb_simple(state.msg_attr.why, "5.4.6",
		   "alias database loop for %s", name);
	*statusp = bounce_append(BOUNCE_FLAGS(state.request),
				 BOUNCE_ATTR(state.msg_attr));
	return (YES);
    }
    state.msg_attr.exp_from = name;

    /*
     * There are a bunch of roles that we're trying to keep track of.
     * 
     * First, there's the issue of whose rights should be used when delivering
     * to "|command" or to /file/name. With alias databases, the rights are
     * those of who owns the alias, i.e. the database owner. With aliases
     * owned by root, a default user is used instead. When an alias with
     * default rights references an include file owned by an ordinary user,
     * we must use the rights of the include file owner, otherwise the
     * include file owner could take control of the default account.
     * 
     * Secondly, there's the question of who to notify of delivery problems.
     * With aliases that have an owner- alias, the latter is used to set the
     * sender and owner attributes. Otherwise, the owner attribute is reset
     * (the alias is globally visible and could be sent to by anyone).
     */
    for (cpp = alias_maps->argv->argv; *cpp; cpp++) {
	if ((dict = dict_handle(*cpp)) == 0)
	    msg_panic("%s: dictionary not found: %s", myname, *cpp);
	if ((alias_result = dict_get(dict, name)) != 0) {
	    if (msg_verbose)
		msg_info("%s: %s: %s = %s", myname, *cpp, name, alias_result);

	    /*
	     * Don't expand a verify-only request.
	     */
	    if (state.request->flags & DEL_REQ_FLAG_MTA_VRFY) {
		dsb_simple(state.msg_attr.why, "2.0.0",
			   "aliased to %s", alias_result);
		*statusp = sent(BOUNCE_FLAGS(state.request),
				SENT_ATTR(state.msg_attr));
		return (YES);
	    }

	    /*
	     * DELIVERY POLICY
	     * 
	     * Update the expansion type attribute, so we can decide if
	     * deliveries to |command and /file/name are allowed at all.
	     */
	    state.msg_attr.exp_type = EXPAND_TYPE_ALIAS;

	    /*
	     * DELIVERY RIGHTS
	     * 
	     * What rights to use for |command and /file/name deliveries? The
	     * command and file code will use default rights when the alias
	     * database is owned by root, otherwise it will use the rights of
	     * the alias database owner.
	     */
	    if ((alias_uid = dict_owner(*cpp)) == 0) {
		alias_pwd = 0;
		RESET_USER_ATTR(usr_attr, state.level);
	    } else {
		if ((alias_pwd = mypwuid(alias_uid)) == 0) {
		    msg_warn("cannot find alias database owner for %s", *cpp);
		    dsb_simple(state.msg_attr.why, "4.3.0",
			       "cannot find alias database owner");
		    *statusp = defer_append(BOUNCE_FLAGS(state.request),
					    BOUNCE_ATTR(state.msg_attr));
		    return (YES);
		}
		SET_USER_ATTR(usr_attr, alias_pwd, state.level);
	    }

	    /*
	     * WHERE TO REPORT DELIVERY PROBLEMS.
	     * 
	     * Use the owner- alias if one is specified, otherwise reset the
	     * owner attribute and use the include file ownership if we can.
	     * Save the dict_lookup() result before something clobbers it.
	     * 
	     * Don't match aliases that are based on regexps.
	     */
#define OWNER_ASSIGN(own) \
	    (own = (var_ownreq_special == 0 ? 0 : \
	    concatenate("owner-", name, (char *) 0)))

	    saved_alias_result = mystrdup(alias_result);
	    if (OWNER_ASSIGN(owner) != 0
		&& (owner_rhs = maps_find(alias_maps, owner, DICT_FLAG_NONE)) != 0) {
		canon_owner = canon_addr_internal(vstring_alloc(10),
				     var_exp_own_alias ? owner_rhs : owner);
		/* Set envelope sender and owner attribute. */
		SET_OWNER_ATTR(state.msg_attr, STR(canon_owner), state.level);
	    } else {
		canon_owner = 0;
		/* Note: this does not reset the envelope sender. */
		if (var_reset_owner_attr)
		    RESET_OWNER_ATTR(state.msg_attr, state.level);
	    }

	    /*
	     * EXTERNAL LOOP CONTROL
	     * 
	     * Set the delivered message attribute to the recipient, so that
	     * this message will list the correct forwarding address.
	     */
	    if (var_frozen_delivered == 0)
		state.msg_attr.delivered = state.msg_attr.rcpt.address;

	    /*
	     * Deliver.
	     */
	    alias_count = 0;
	    if (dict_errno != 0) {
		dsb_simple(state.msg_attr.why, "4.3.0",
			   "alias database unavailable");
		*statusp = defer_append(BOUNCE_FLAGS(state.request),
					BOUNCE_ATTR(state.msg_attr));
	    } else {

		/*
		 * XXX DSN
		 * 
		 * When delivering to a mailing list (i.e. the envelope sender
		 * is replaced) the ENVID, NOTIFY, RET, and ORCPT parameters
		 * which accompany the redistributed message MUST NOT be
		 * derived from those of the original message.
		 * 
		 * When delivering to an alias (i.e. the envelope sender is not
		 * replaced) any ENVID, RET, or ORCPT parameters are
		 * propagated to all forwarding addresses associated with
		 * that alias.  The NOTIFY parameter is propagated to the
		 * forwarding addresses, except that any SUCCESS keyword is
		 * removed.
		 */
#define DSN_SAVE_UPDATE(saved, old, new) do { \
	saved = old; \
	old = new; \
    } while (0)

		DSN_SAVE_UPDATE(dsn_notify, state.msg_attr.rcpt.dsn_notify,
				dsn_notify == DSN_NOTIFY_SUCCESS ?
				DSN_NOTIFY_NEVER :
				dsn_notify & ~DSN_NOTIFY_SUCCESS);
		if (canon_owner != 0) {
		    DSN_SAVE_UPDATE(dsn_envid, state.msg_attr.dsn_envid, "");
		    DSN_SAVE_UPDATE(dsn_ret, state.msg_attr.dsn_ret, 0);
		    DSN_SAVE_UPDATE(dsn_orcpt, state.msg_attr.rcpt.dsn_orcpt, "");
		    state.msg_attr.rcpt.orig_addr = "";
		}
		*statusp =
		    deliver_token_string(state, usr_attr, saved_alias_result,
					 &alias_count);
#if 0
		if (var_ownreq_special
		    && strncmp("owner-", state.msg_attr.sender, 6) != 0
		    && alias_count > 10)
		    msg_warn("mailing list \"%s\" needs an \"owner-%s\" alias",
			     name, name);
#endif
		if (alias_count < 1) {
		    msg_warn("no recipient in alias lookup result for %s", name);
		    dsb_simple(state.msg_attr.why, "4.3.0",
			       "alias database unavailable");
		    *statusp = defer_append(BOUNCE_FLAGS(state.request),
					    BOUNCE_ATTR(state.msg_attr));
		} else {

		    /*
		     * XXX DSN
		     * 
		     * When delivering to a mailing list (i.e. the envelope
		     * sender address is replaced) and NOTIFY=SUCCESS was
		     * specified, report a DSN of "delivered".
		     * 
		     * When delivering to an alias (i.e. the envelope sender
		     * address is not replaced) and NOTIFY=SUCCESS was
		     * specified, report a DSN of "expanded".
		     */
		    if (dsn_notify & DSN_NOTIFY_SUCCESS) {
			state.msg_attr.rcpt.dsn_notify = dsn_notify;
			if (canon_owner != 0) {
			    state.msg_attr.dsn_envid = dsn_envid;
			    state.msg_attr.dsn_ret = dsn_ret;
			    state.msg_attr.rcpt.dsn_orcpt = dsn_orcpt;
			}
			dsb_update(state.msg_attr.why, "2.0.0", canon_owner ?
				   "delivered" : "expanded",
				   DSB_SKIP_RMTA, DSB_SKIP_REPLY,
				   "alias expanded");
			(void) trace_append(BOUNCE_FLAG_NONE,
					    SENT_ATTR(state.msg_attr));
		    }
		}
	    }
	    myfree(saved_alias_result);
	    if (owner)
		myfree(owner);
	    if (canon_owner)
		vstring_free(canon_owner);
	    if (alias_pwd)
		mypwfree(alias_pwd);
	    return (YES);
	}

	/*
	 * If the alias database was inaccessible for some reason, defer
	 * further delivery for the current top-level recipient.
	 */
	if (dict_errno != 0) {
	    dsb_simple(state.msg_attr.why, "4.3.0",
		       "alias database unavailable");
	    *statusp = defer_append(BOUNCE_FLAGS(state.request),
				    BOUNCE_ATTR(state.msg_attr));
	    return (YES);
	} else {
	    if (msg_verbose)
		msg_info("%s: %s: %s not found", myname, *cpp, name);
	}
    }

    /*
     * Try delivery to a local user instead.
     */
    return (NO);
}
Ejemplo n.º 7
0
int     sent(int flags, const char *id, MSG_STATS *stats,
	             RECIPIENT *recipient, const char *relay,
	             DSN *dsn)
{
    DSN     my_dsn = *dsn;
    int     status;

    /*
     * Sanity check.
     */
    if (my_dsn.status[0] != '2' || !dsn_valid(my_dsn.status)) {
	msg_warn("sent: ignoring dsn code \"%s\"", my_dsn.status);
	my_dsn.status = "2.0.0";
    }

    /*
     * MTA-requested address verification information is stored in the verify
     * service database.
     */
    if (flags & DEL_REQ_FLAG_MTA_VRFY) {
	my_dsn.action = "deliverable";
	status = verify_append(id, stats, recipient, relay, &my_dsn,
			       DEL_RCPT_STAT_OK);
	return (status);
    }

    /*
     * User-requested address verification information is logged and mailed
     * to the requesting user.
     */
    if (flags & DEL_REQ_FLAG_USR_VRFY) {
	my_dsn.action = "deliverable";
	status = trace_append(flags, id, stats, recipient, relay, &my_dsn);
	return (status);
    }

    /*
     * Normal mail delivery. May also send a delivery record to the user.
     */
    else {
	if (my_dsn.action == 0 || my_dsn.action[0] == 0)
	    my_dsn.action = "delivered";

	if (((flags & DEL_REQ_FLAG_RECORD) == 0
	  || trace_append(flags, id, stats, recipient, relay, &my_dsn) == 0)
	    && ((recipient->dsn_notify & DSN_NOTIFY_SUCCESS) == 0
	|| trace_append(flags, id, stats, recipient, relay, &my_dsn) == 0)) {
	    log_adhoc(id, stats, recipient, relay, &my_dsn, "sent");
	    status = 0;
	} else {
	    VSTRING *junk = vstring_alloc(100);

	    vstring_sprintf(junk, "%s: %s service failed",
			    id, var_trace_service);
	    my_dsn.reason = vstring_str(junk);
	    my_dsn.status ="4.3.0";
	    status = defer_append(flags, id, stats, recipient, relay, &my_dsn);
	    vstring_free(junk);
	}
	return (status);
    }
}
Ejemplo n.º 8
0
int     deliver_dotforward(LOCAL_STATE state, USER_ATTR usr_attr, int *statusp)
{
    const char *myname = "deliver_dotforward";
    struct stat st;
    VSTRING *path;
    struct mypasswd *mypwd;
    int     fd;
    VSTREAM *fp;
    int     status;
    int     forward_found = NO;
    int     lookup_status;
    int     addr_count;
    char   *saved_forward_path;
    char   *lhs;
    char   *next;
    int     expand_status;
    int     saved_notify;

    /*
     * Make verbose logging easier to understand.
     */
    state.level++;
    if (msg_verbose)
        MSG_LOG_STATE(myname, state);

    /*
     * Skip this module if per-user forwarding is disabled.
     */
    if (*var_forward_path == 0)
        return (NO);

    /*
     * Skip non-existing users. The mailbox delivery routine will catch the
     * error.
     */
    if ((errno = mypwnam_err(state.msg_attr.user, &mypwd)) != 0) {
        msg_warn("error looking up passwd info for %s: %m",
                 state.msg_attr.user);
        dsb_simple(state.msg_attr.why, "4.0.0", "user lookup error");
        *statusp = defer_append(BOUNCE_FLAGS(state.request),
                                BOUNCE_ATTR(state.msg_attr));
        return (YES);
    }
    if (mypwd == 0)
        return (NO);

    /*
     * From here on no early returns or we have a memory leak.
     */

    /*
     * EXTERNAL LOOP CONTROL
     *
     * Set the delivered message attribute to the recipient, so that this
     * message will list the correct forwarding address.
     */
    if (var_frozen_delivered == 0)
        state.msg_attr.delivered = state.msg_attr.rcpt.address;

    /*
     * DELIVERY RIGHTS
     *
     * Do not inherit rights from the .forward file owner. Instead, use the
     * recipient's rights, and insist that the .forward file is owned by the
     * recipient. This is a small but significant difference. Use the
     * recipient's rights for all /file and |command deliveries, and pass on
     * these rights to command/file destinations in included files. When
     * these are the rights of root, the /file and |command delivery routines
     * will use unprivileged default rights instead. Better safe than sorry.
     */
    SET_USER_ATTR(usr_attr, mypwd, state.level);

    /*
     * DELIVERY POLICY
     *
     * Update the expansion type attribute so that we can decide if deliveries
     * to |command and /file/name are allowed at all.
     */
    state.msg_attr.exp_type = EXPAND_TYPE_FWD;

    /*
     * WHERE TO REPORT DELIVERY PROBLEMS
     *
     * Set the owner attribute so that 1) include files won't set the sender to
     * be this user and 2) mail forwarded to other local users will be
     * resubmitted as a new queue file.
     */
    state.msg_attr.owner = state.msg_attr.user;

    /*
     * Search the forward_path for an existing forward file.
     *
     * If unmatched extensions should never be propagated, or if a forward file
     * name includes the address extension, don't propagate the extension to
     * the recipient addresses.
     */
    status = 0;
    path = vstring_alloc(100);
    saved_forward_path = mystrdup(var_forward_path);
    next = saved_forward_path;
    lookup_status = -1;

    while ((lhs = mystrtok(&next, ", \t\r\n")) != 0) {
        expand_status = local_expand(path, lhs, &state, &usr_attr,
                                     var_fwd_exp_filter);
        if ((expand_status & (MAC_PARSE_ERROR | MAC_PARSE_UNDEF)) == 0) {
            lookup_status =
                lstat_as(STR(path), &st, usr_attr.uid, usr_attr.gid);
            if (msg_verbose)
                msg_info("%s: path %s expand_status %d look_status %d", myname,
                         STR(path), expand_status, lookup_status);
            if (lookup_status >= 0) {
                if ((expand_status & LOCAL_EXP_EXTENSION_MATCHED) != 0
                        || (local_ext_prop_mask & EXT_PROP_FORWARD) == 0)
                    state.msg_attr.unmatched = 0;
                break;
            }
        }
    }

    /*
     * Process the forward file.
     *
     * Assume that usernames do not have file system meta characters. Open the
     * .forward file as the user. Ignore files that aren't regular files,
     * files that are owned by the wrong user, or files that have world write
     * permission enabled.
     *
     * DUPLICATE/LOOP ELIMINATION
     *
     * If this user includes (an alias of) herself in her own .forward file,
     * deliver to the user instead.
     */
    if (lookup_status >= 0) {

        /*
         * Don't expand a verify-only request.
         */
        if (state.request->flags & DEL_REQ_FLAG_MTA_VRFY) {
            dsb_simple(state.msg_attr.why, "2.0.0",
                       "forward via file: %s", STR(path));
            *statusp = sent(BOUNCE_FLAGS(state.request),
                            SENT_ATTR(state.msg_attr));
            forward_found = YES;
        } else if (been_here(state.dup_filter, "forward %s", STR(path)) == 0) {
            state.msg_attr.exp_from = state.msg_attr.local;
            if (S_ISREG(st.st_mode) == 0) {
                msg_warn("file %s is not a regular file", STR(path));
            } else if (st.st_uid != 0 && st.st_uid != usr_attr.uid) {
                msg_warn("file %s has bad owner uid %ld",
                         STR(path), (long) st.st_uid);
            } else if (st.st_mode & 002) {
                msg_warn("file %s is world writable", STR(path));
            } else if ((fd = open_as(STR(path), O_RDONLY, 0, usr_attr.uid, usr_attr.gid)) < 0) {
                msg_warn("cannot open file %s: %m", STR(path));
            } else {

                /*
                 * XXX DSN. When delivering to an alias (i.e. the envelope
                 * sender address is not replaced) any ENVID, RET, or ORCPT
                 * parameters are propagated to all forwarding addresses
                 * associated with that alias.  The NOTIFY parameter is
                 * propagated to the forwarding addresses, except that any
                 * SUCCESS keyword is removed.
                 */
                close_on_exec(fd, CLOSE_ON_EXEC);
                addr_count = 0;
                fp = vstream_fdopen(fd, O_RDONLY);
                saved_notify = state.msg_attr.rcpt.dsn_notify;
                state.msg_attr.rcpt.dsn_notify =
                    (saved_notify == DSN_NOTIFY_SUCCESS ?
                     DSN_NOTIFY_NEVER : saved_notify & ~DSN_NOTIFY_SUCCESS);
                status = deliver_token_stream(state, usr_attr, fp, &addr_count);
                if (vstream_fclose(fp))
                    msg_warn("close file %s: %m", STR(path));
                if (addr_count > 0) {
                    forward_found = YES;
                    been_here(state.dup_filter, "forward-done %s", STR(path));

                    /*
                     * XXX DSN. When delivering to an alias (i.e. the
                     * envelope sender address is not replaced) and the
                     * original NOTIFY parameter for the alias contained the
                     * SUCCESS keyword, an "expanded" DSN is issued for the
                     * alias.
                     */
                    if (status == 0 && (saved_notify & DSN_NOTIFY_SUCCESS)) {
                        state.msg_attr.rcpt.dsn_notify = saved_notify;
                        dsb_update(state.msg_attr.why, "2.0.0", "expanded",
                                   DSB_SKIP_RMTA, DSB_SKIP_REPLY,
                                   "alias expanded");
                        (void) trace_append(BOUNCE_FLAG_NONE,
                                            SENT_ATTR(state.msg_attr));
                    }
                }
            }
        } else if (been_here_check(state.dup_filter, "forward-done %s", STR(path)) != 0)
            forward_found = YES;		/* else we're recursive */
    }

    /*
     * Clean up.
     */
    vstring_free(path);
    myfree(saved_forward_path);
    mypwfree(mypwd);

    *statusp = status;
    return (forward_found);
}
Ejemplo n.º 9
0
int     sent(int flags, const char *id, MSG_STATS *stats,
	             RECIPIENT *recipient, const char *relay,
	             DSN *dsn)
{
    const char *myname="sent.c Sent";
    if (msg_verbose)
 	msg_info("HU--%s Starting",myname);
    
    DSN     my_dsn = *dsn;
    DSN    *dsn_res;
    int     status;

    /*
     * Sanity check.
     */
    if (my_dsn.status[0] != '2' || !dsn_valid(my_dsn.status)) {
	msg_warn("sent: ignoring dsn code \"%s\"", my_dsn.status);
	my_dsn.status = "2.0.0";
    }

    /*
     * DSN filter (Postfix 3.0).
     */
    if (delivery_status_filter != 0
     && (dsn_res = dsn_filter_lookup(delivery_status_filter, &my_dsn)) != 0)
	my_dsn = *dsn_res;

    /*
     * MTA-requested address verification information is stored in the verify
     * service database.
     */
    if (flags & DEL_REQ_FLAG_MTA_VRFY) {
	my_dsn.action = "deliverable";
	status = verify_append(id, stats, recipient, relay, &my_dsn,
			       DEL_RCPT_STAT_OK);
	return (status);
    }

    /*
     * User-requested address verification information is logged and mailed
     * to the requesting user.
     */
    if (flags & DEL_REQ_FLAG_USR_VRFY) {
	my_dsn.action = "deliverable";
	status = trace_append(flags, id, stats, recipient, relay, &my_dsn);
	return (status);
    }

    /*
     * Normal mail delivery. May also send a delivery record to the user.
     */
    else {

	/* Readability macros: record all deliveries, or the delayed ones. */
#define REC_ALL_SENT(flags) (flags & DEL_REQ_FLAG_RECORD)
#define REC_DLY_SENT(flags, rcpt) \
	((flags & DEL_REQ_FLAG_REC_DLY_SENT) \
	&& (rcpt->dsn_notify == 0 || (rcpt->dsn_notify & DSN_NOTIFY_DELAY)))

	if (my_dsn.action == 0 || my_dsn.action[0] == 0)
	    my_dsn.action = "delivered";

	if (((REC_ALL_SENT(flags) == 0 && REC_DLY_SENT(flags, recipient) == 0)
	  || trace_append(flags, id, stats, recipient, relay, &my_dsn) == 0)
	    && ((recipient->dsn_notify & DSN_NOTIFY_SUCCESS) == 0
	|| trace_append(flags, id, stats, recipient, relay, &my_dsn) == 0)) {
	    log_adhoc(id, stats, recipient, relay, &my_dsn, "sent");
	    status = 0;
	} else {
	    VSTRING *junk = vstring_alloc(100);

	    vstring_sprintf(junk, "%s: %s service failed",
			    id, var_trace_service);
	    my_dsn.reason = vstring_str(junk);
	    my_dsn.status = "4.3.0";
	    status = defer_append(flags, id, stats, recipient, relay, &my_dsn);
	    vstring_free(junk);
	}
	return (status);
    }
}
Ejemplo n.º 10
0
int     bounce_one_intern(int flags, const char *queue, const char *id,
			          const char *encoding, const char *sender,
			          const char *dsn_envid, int dsn_ret,
			          MSG_STATS *stats, RECIPIENT *rcpt,
			          const char *relay, DSN *dsn)
{
    DSN     my_dsn = *dsn;
    int     status;

    /*
     * MTA-requested address verification information is stored in the verify
     * service database.
     */
    if (flags & DEL_REQ_FLAG_MTA_VRFY) {
	my_dsn.action = "undeliverable";
	status = verify_append(id, stats, rcpt, relay, &my_dsn,
			       DEL_RCPT_STAT_BOUNCE);
	return (status);
    }

    /*
     * User-requested address verification information is logged and mailed
     * to the requesting user.
     */
    if (flags & DEL_REQ_FLAG_USR_VRFY) {
	my_dsn.action = "undeliverable";
	status = trace_append(flags, id, stats, rcpt, relay, &my_dsn);
	return (status);
    }

    /*
     * When we're not bouncing, then use the standard multi-recipient logfile
     * based procedure.
     */
    else if (var_soft_bounce) {
	return (bounce_append_intern(flags, id, stats, rcpt, relay, &my_dsn));
    }

    /*
     * Normal mail delivery. May also send a delivery record to the user.
     * 
     * XXX DSN We send all recipients regardless of DSN NOTIFY options, because
     * those options don't apply to postmaster notifications.
     */
    else {

	/*
	 * Supply default action.
	 */
	my_dsn.action = "failed";

	if (mail_command_client(MAIL_CLASS_PRIVATE, var_bounce_service,
			      ATTR_TYPE_INT, MAIL_ATTR_NREQ, BOUNCE_CMD_ONE,
				ATTR_TYPE_INT, MAIL_ATTR_FLAGS, flags,
				ATTR_TYPE_STR, MAIL_ATTR_QUEUE, queue,
				ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, id,
				ATTR_TYPE_STR, MAIL_ATTR_ENCODING, encoding,
				ATTR_TYPE_STR, MAIL_ATTR_SENDER, sender,
			      ATTR_TYPE_STR, MAIL_ATTR_DSN_ENVID, dsn_envid,
				ATTR_TYPE_INT, MAIL_ATTR_DSN_RET, dsn_ret,
				ATTR_TYPE_FUNC, rcpt_print, (void *) rcpt,
				ATTR_TYPE_FUNC, dsn_print, (void *) &my_dsn,
				ATTR_TYPE_END) == 0
	    && ((flags & DEL_REQ_FLAG_RECORD) == 0
		|| trace_append(flags, id, stats, rcpt, relay,
				&my_dsn) == 0)) {
	    log_adhoc(id, stats, rcpt, relay, &my_dsn, "bounced");
	    status = 0;
	} else if ((flags & BOUNCE_FLAG_CLEAN) == 0) {
	    VSTRING *junk = vstring_alloc(100);

	    my_dsn.status = "4.3.0";
	    vstring_sprintf(junk, "%s or %s service failure",
			    var_bounce_service, var_trace_service);
	    my_dsn.reason = vstring_str(junk);
	    status = defer_append_intern(flags, id, stats, rcpt, relay, &my_dsn);
	    vstring_free(junk);
	} else {
	    status = -1;
	}
	return (status);
    }
}
Ejemplo n.º 11
0
int     bounce_append_intern(int flags, const char *id, MSG_STATS *stats,
			             RECIPIENT *rcpt, const char *relay,
			             DSN *dsn)
{
    DSN     my_dsn = *dsn;
    int     status;

    /*
     * MTA-requested address verification information is stored in the verify
     * service database.
     */
    if (flags & DEL_REQ_FLAG_MTA_VRFY) {
	my_dsn.action = "undeliverable";
	status = verify_append(id, stats, rcpt, relay, &my_dsn,
			       DEL_RCPT_STAT_BOUNCE);
	return (status);
    }

    /*
     * User-requested address verification information is logged and mailed
     * to the requesting user.
     */
    if (flags & DEL_REQ_FLAG_USR_VRFY) {
	my_dsn.action = "undeliverable";
	status = trace_append(flags, id, stats, rcpt, relay, &my_dsn);
	return (status);
    }

    /*
     * Normal (well almost) delivery. When we're pretending that we can't
     * bounce, don't create a defer log file when we wouldn't keep the bounce
     * log file. That's a lot of negatives in one sentence.
     */
    else if (var_soft_bounce && (flags & BOUNCE_FLAG_CLEAN)) {
	return (-1);
    }

    /*
     * Normal mail delivery. May also send a delivery record to the user.
     * 
     * XXX DSN We write all recipients to the bounce logfile regardless of DSN
     * NOTIFY options, because those options don't apply to postmaster
     * notifications.
     */
    else {
	char   *my_status = mystrdup(my_dsn.status);
	const char *log_status = var_soft_bounce ? "SOFTBOUNCE" : "bounced";

	/*
	 * Supply default action.
	 */
	my_dsn.status = my_status;
	if (var_soft_bounce) {
	    my_status[0] = '4';
	    my_dsn.action = "delayed";
	} else {
	    my_dsn.action = "failed";
	}

	if (mail_command_client(MAIL_CLASS_PRIVATE, var_soft_bounce ?
				var_defer_service : var_bounce_service,
			   ATTR_TYPE_INT, MAIL_ATTR_NREQ, BOUNCE_CMD_APPEND,
				ATTR_TYPE_INT, MAIL_ATTR_FLAGS, flags,
				ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, id,
				ATTR_TYPE_FUNC, rcpt_print, (void *) rcpt,
				ATTR_TYPE_FUNC, dsn_print, (void *) &my_dsn,
				ATTR_TYPE_END) == 0
	    && ((flags & DEL_REQ_FLAG_RECORD) == 0
		|| trace_append(flags, id, stats, rcpt, relay,
				&my_dsn) == 0)) {
	    log_adhoc(id, stats, rcpt, relay, &my_dsn, log_status);
	    status = (var_soft_bounce ? -1 : 0);
	} else if ((flags & BOUNCE_FLAG_CLEAN) == 0) {
	    VSTRING *junk = vstring_alloc(100);

	    my_dsn.status = "4.3.0";
	    vstring_sprintf(junk, "%s or %s service failure",
			    var_bounce_service, var_trace_service);
	    my_dsn.reason = vstring_str(junk);
	    status = defer_append_intern(flags, id, stats, rcpt, relay, &my_dsn);
	    vstring_free(junk);
	} else {
	    status = -1;
	}
	myfree(my_status);
	return (status);
    }
}