Esempio n. 1
0
int testDAD_init_suite() {
    char *macdata[] = {
        "ec:ac:24:70:4c:f6", "EC:AC:24:70:4C:F7",
        "Ec:aC:24:70:4c:F8", "38:45:63:f6:8e:83",
        "f7:d5:9c:38:8f:db", "bf:de:9e:0e:6e:eb",
        "b6:f5:bf:ff:c2:32", "83:23:3d:f2:17:31",
        "26:3e:f2:4e:0d:ff", "d4:fc:84:dc:81:a9",
        NULL
    };
    char *ipdata[] = {
        "ffe5:1838:afd7:2472:b3e7:3ae6:a228:12b4", "0E51:A030:C113:3838:C080:DD09:4D6C:189D",
        "9af2:2354:ecd1:f412:b9e3:648C:519D:DDDF", "69df:0c97:aaff:ef86:7cc0:ede5:2a7b:6cc0",
        "4605:da5a:9f0f:8a36:f63a:e40a:1614:0554", "6956:2caa:6abf:f6b2:3c57:a99c:d88d:ff7d",
        "4a7d:e4d7:54ea:48ed:8467:6b59:3670:a941", "1d24:c623:219a:0aa1:7628:51ce:870a:898f",
        "5e0f:1e4b:e619:d99f:dd65:caf1:12a5:01fc", "8693:39c0:36de:d326:cb63:a585:c63e:2f04",
        NULL
    };
    char *ipstr = "5338:41ab:64f7:a598:39b6:e0f8:5a6e:5ec8";
    IP_t ip;
    int i;
    time_t ts = 1234567890;
    
    ip_parse(&ip, ipstr);

    for (i = 0; i < EXAMPLE_LEN; i++) {
        host_set(&h[i], mac_parse(NULL, macdata[i]), ip_parse(NULL, ipdata[i]), ts++);
    }
    for (i = 0; i < EXAMPLE_LEN; i++) {
        host_set(&g[i], mac_parse(NULL, macdata[i]), &ip, ts++);
    }
    return 0;
}
Esempio n. 2
0
int     mac_expand(VSTRING *result, const char *pattern, int flags,
		           const char *filter,
		           MAC_EXP_LOOKUP_FN lookup, char *context)
{
    MAC_EXP mc;
    int     status;

    /*
     * Bundle up the request and do the substitutions.
     */
    mc.result = result;
    mc.flags = flags;
    mc.filter = filter;
    mc.lookup = lookup;
    mc.context = context;
    mc.status = 0;
    mc.level = 0;
    if ((flags & (MAC_EXP_FLAG_APPEND | MAC_EXP_FLAG_SCAN)) == 0)
	VSTRING_RESET(result);
    status = mac_parse(pattern, mac_expand_callback, (char *) &mc);
    if ((flags & MAC_EXP_FLAG_SCAN) == 0)
	VSTRING_TERMINATE(result);

    return (status);
}
Esempio n. 3
0
int     main(int unused_argc, char **unused_argv)
{
    VSTRING *buf = vstring_alloc(1);

    while (vstring_fgets_nonl(buf, VSTREAM_IN)) {
	mac_parse(vstring_str(buf), mac_parse_print, (char *) 0);
	vstream_fflush(VSTREAM_OUT);
    }
    vstring_free(buf);
    return (0);
}
Esempio n. 4
0
static int mac_expand_callback(int type, VSTRING *buf, char *ptr)
{
    char   *myname = "mac_expand_callback";
    MAC_EXP *mc = (MAC_EXP *) ptr;
    int     lookup_mode;
    const char *text;
    char   *cp;
    int     ch;
    int     len;

    /*
     * Sanity check.
     */
    if (mc->level++ > 100) {
	msg_warn("unreasonable macro call nesting: \"%s\"", vstring_str(buf));
	mc->status |= MAC_PARSE_ERROR;
    }
    if (mc->status & MAC_PARSE_ERROR)
	return (mc->status);

    /*
     * $Name etc. reference.
     */
    if (type == MAC_PARSE_VARNAME) {

	/*
	 * Look for the ? or : delimiter. In case of a syntax error, return
	 * without doing damage, and issue a warning instead.
	 */
	for (cp = vstring_str(buf); /* void */ ; cp++) {
	    if ((ch = *cp) == 0) {
		lookup_mode = MAC_EXP_MODE_USE;
		break;
	    }
	    if (ch == '?' || ch == ':') {
		*cp++ = 0;
		lookup_mode = MAC_EXP_MODE_TEST;
		break;
	    }
	    if (!ISALNUM(ch) && ch != '_') {
		msg_warn("macro name syntax error: \"%s\"", vstring_str(buf));
		mc->status |= MAC_PARSE_ERROR;
		return (mc->status);
	    }
	}

	/*
	 * Look up the named parameter.
	 */
	text = mc->lookup(vstring_str(buf), lookup_mode, mc->context);

	/*
	 * Perform the requested substitution.
	 */
	switch (ch) {
	case '?':
	    if (text != 0 && *text != 0)
		mac_parse(cp, mac_expand_callback, (char *) mc);
	    break;
	case ':':
	    if (text == 0 || *text == 0)
		mac_parse(cp, mac_expand_callback, (char *) mc);
	    break;
	default:
	    if (text == 0) {
		mc->status |= MAC_PARSE_UNDEF;
	    } else if (*text == 0) {
		 /* void */ ;
	    } else if (mc->flags & MAC_EXP_FLAG_RECURSE) {
		mac_parse(text, mac_expand_callback, (char *) mc);
	    } else {
		len = VSTRING_LEN(mc->result);
		vstring_strcat(mc->result, text);
		if (mc->filter) {
		    cp = vstring_str(mc->result) + len;
		    while (*(cp += strspn(cp, mc->filter)))
			*cp++ = '_';
		}
	    }
	    break;
	}
    }

    /*
     * Literal text.
     */
    else {
	text = vstring_str(buf);
	vstring_strcat(mc->result, text);
    }

    /*
     * Give the poor tester a clue of what is going on.
     */
    if (msg_verbose)
	msg_info("%s: %s = %s", myname, vstring_str(buf),
		 text ? text : "(undef)");

    mc->level--;

    return (mc->status);
}
Esempio n. 5
0
static int mac_expand_callback(int type, VSTRING *buf, char *ptr)
{
    MAC_EXP *mc = (MAC_EXP *) ptr;
    int     lookup_mode;
    const char *text;
    char   *cp;
    int     ch;
    ssize_t len;

    /*
     * Sanity check.
     */
    if (mc->level++ > 100) {
	msg_warn("unreasonable macro call nesting: \"%s\"", vstring_str(buf));
	mc->status |= MAC_PARSE_ERROR;
    }
    if (mc->status & MAC_PARSE_ERROR)
	return (mc->status);

    /*
     * $Name etc. reference.
     * 
     * In order to support expansion of lookup results, we must save the lookup
     * result. We use the input buffer since it will not be needed anymore.
     */
    if (type == MAC_PARSE_EXPR) {

	/*
	 * Look for the ? or : delimiter. In case of a syntax error, return
	 * without doing damage, and issue a warning instead.
	 */
	for (cp = vstring_str(buf); /* void */ ; cp++) {
	    if ((ch = *cp) == 0) {
		lookup_mode = MAC_EXP_MODE_USE;
		break;
	    }
	    if (ch == '?' || ch == ':') {
		*cp++ = 0;
		lookup_mode = MAC_EXP_MODE_TEST;
		break;
	    }
	    if (!ISALNUM(ch) && ch != '_') {
		msg_warn("macro name syntax error: \"%s\"", vstring_str(buf));
		mc->status |= MAC_PARSE_ERROR;
		return (mc->status);
	    }
	}

	/*
	 * Look up the named parameter.
	 */
	text = mc->lookup(vstring_str(buf), lookup_mode, mc->context);

	/*
	 * Perform the requested substitution.
	 */
	switch (ch) {
	case '?':
	    if ((text != 0 && *text != 0) || (mc->flags & MAC_EXP_FLAG_SCAN))
		mac_parse(cp, mac_expand_callback, (char *) mc);
	    break;
	case ':':
	    if (text == 0 || *text == 0 || (mc->flags & MAC_EXP_FLAG_SCAN))
		mac_parse(cp, mac_expand_callback, (char *) mc);
	    break;
	default:
	    if (text == 0) {
		mc->status |= MAC_PARSE_UNDEF;
	    } else if (*text == 0 || (mc->flags & MAC_EXP_FLAG_SCAN)) {
		 /* void */ ;
	    } else if (mc->flags & MAC_EXP_FLAG_RECURSE) {
		vstring_strcpy(buf, text);
		mac_parse(vstring_str(buf), mac_expand_callback, (char *) mc);
	    } else {
		len = VSTRING_LEN(mc->result);
		vstring_strcat(mc->result, text);
		if (mc->filter) {
		    cp = vstring_str(mc->result) + len;
		    while (*(cp += strspn(cp, mc->filter)))
			*cp++ = '_';
		}
	    }
	    break;
	}
    }

    /*
     * Literal text.
     */
    else if ((mc->flags & MAC_EXP_FLAG_SCAN) == 0) {
	vstring_strcat(mc->result, vstring_str(buf));
    }

    mc->level--;

    return (mc->status);
}
Esempio n. 6
0
static DICT_PCRE_RULE *dict_pcre_parse_rule(const char *mapname, int lineno,
					            char *line, int nesting,
					            int dict_flags)
{
    char   *p;
    int     actual_sub;

    p = line;

    /*
     * An ordinary match rule takes one pattern and replacement text.
     */
    if (!ISALNUM(*p)) {
	DICT_PCRE_REGEXP regexp;
	DICT_PCRE_ENGINE engine;
	DICT_PCRE_PRESCAN_CONTEXT prescan_context;
	DICT_PCRE_MATCH_RULE *match_rule;

	/*
	 * Get the pattern string and options.
	 */
	if (dict_pcre_get_pattern(mapname, lineno, &p, &regexp) == 0)
	    return (0);

	/*
	 * Get the replacement text.
	 */
	while (*p && ISSPACE(*p))
	    ++p;
	if (!*p)
	    msg_warn("%s, line %d: no replacement text: using empty string",
		     mapname, lineno);

	/*
	 * Sanity check the $number instances in the replacement text.
	 */
	prescan_context.mapname = mapname;
	prescan_context.lineno = lineno;
	prescan_context.max_sub = 0;
	prescan_context.literal = 0;

	/*
	 * The optimizer will eliminate code duplication and/or dead code.
	 */
#define CREATE_MATCHOP_ERROR_RETURN(rval) do { \
	if (prescan_context.literal) \
	    myfree(prescan_context.literal); \
	return (rval); \
    } while (0)

	if (mac_parse(p, dict_pcre_prescan, (char *) &prescan_context)
	    & MAC_PARSE_ERROR) {
	    msg_warn("pcre map %s, line %d: bad replacement syntax: "
		     "skipping this rule", mapname, lineno);
	    CREATE_MATCHOP_ERROR_RETURN(0);
	}

	/*
	 * Substring replacement not possible with negative regexps.
	 */
	if (prescan_context.max_sub > 0 && regexp.match == 0) {
	    msg_warn("pcre map %s, line %d: $number found in negative match "
		   "replacement text: skipping this rule", mapname, lineno);
	    CREATE_MATCHOP_ERROR_RETURN(0);
	}
	if (prescan_context.max_sub > 0 && (dict_flags & DICT_FLAG_NO_REGSUB)) {
	    msg_warn("pcre map %s, line %d: "
		     "regular expression substitution is not allowed: "
		     "skipping this rule", mapname, lineno);
	    CREATE_MATCHOP_ERROR_RETURN(0);
	}

	/*
	 * Compile the pattern.
	 */
	if (dict_pcre_compile(mapname, lineno, &regexp, &engine) == 0)
	    CREATE_MATCHOP_ERROR_RETURN(0);
#ifdef PCRE_INFO_CAPTURECOUNT
	if (pcre_fullinfo(engine.pattern, engine.hints,
			  PCRE_INFO_CAPTURECOUNT,
			  (void *) &actual_sub) != 0)
	    msg_panic("pcre map %s, line %d: pcre_fullinfo failed",
		      mapname, lineno);
	if (prescan_context.max_sub > actual_sub) {
	    msg_warn("pcre map %s, line %d: out of range replacement index \"%d\": "
		     "skipping this rule", mapname, lineno,
		     (int) prescan_context.max_sub);
	    if (engine.pattern)
		myfree((char *) engine.pattern);
	    if (engine.hints)
		myfree((char *) engine.hints);
	    CREATE_MATCHOP_ERROR_RETURN(0);
	}
#endif

	/*
	 * Save the result.
	 */
	match_rule = (DICT_PCRE_MATCH_RULE *)
	    dict_pcre_rule_alloc(DICT_PCRE_OP_MATCH, nesting, lineno,
				 sizeof(DICT_PCRE_MATCH_RULE));
	match_rule->match = regexp.match;
	match_rule->max_sub = prescan_context.max_sub;
	if (prescan_context.literal)
	    match_rule->replacement = prescan_context.literal;
	else
	    match_rule->replacement = mystrdup(p);
	match_rule->pattern = engine.pattern;
	match_rule->hints = engine.hints;
	return ((DICT_PCRE_RULE *) match_rule);
    }

    /*
     * The IF operator takes one pattern but no replacement text.
     */
    else if (strncasecmp(p, "IF", 2) == 0 && !ISALNUM(p[2])) {
	DICT_PCRE_REGEXP regexp;
	DICT_PCRE_ENGINE engine;
	DICT_PCRE_IF_RULE *if_rule;

	p += 2;

	/*
	 * Get the pattern.
	 */
	while (*p && ISSPACE(*p))
	    p++;
	if (!dict_pcre_get_pattern(mapname, lineno, &p, &regexp))
	    return (0);

	/*
	 * Warn about out-of-place text.
	 */
	while (*p && ISSPACE(*p))
	    ++p;
	if (*p) {
	    msg_warn("pcre map %s, line %d: ignoring extra text after "
		     "IF statement: \"%s\"", mapname, lineno, p);
	    msg_warn("pcre map %s, line %d: do not prepend whitespace"
		     " to statements between IF and ENDIF", mapname, lineno);
	}

	/*
	 * Compile the pattern.
	 */
	if (dict_pcre_compile(mapname, lineno, &regexp, &engine) == 0)
	    return (0);

	/*
	 * Save the result.
	 */
	if_rule = (DICT_PCRE_IF_RULE *)
	    dict_pcre_rule_alloc(DICT_PCRE_OP_IF, nesting, lineno,
				 sizeof(DICT_PCRE_IF_RULE));
	if_rule->match = regexp.match;
	if_rule->pattern = engine.pattern;
	if_rule->hints = engine.hints;
	return ((DICT_PCRE_RULE *) if_rule);
    }

    /*
     * The ENDIF operator takes no patterns and no replacement text.
     */
    else if (strncasecmp(p, "ENDIF", 5) == 0 && !ISALNUM(p[5])) {
	DICT_PCRE_RULE *rule;

	p += 5;

	/*
	 * Warn about out-of-place ENDIFs.
	 */
	if (nesting == 0) {
	    msg_warn("pcre map %s, line %d: ignoring ENDIF without matching IF",
		     mapname, lineno);
	    return (0);
	}

	/*
	 * Warn about out-of-place text.
	 */
	while (*p && ISSPACE(*p))
	    ++p;
	if (*p)
	    msg_warn("pcre map %s, line %d: ignoring extra text after ENDIF",
		     mapname, lineno);

	/*
	 * Save the result.
	 */
	rule = dict_pcre_rule_alloc(DICT_PCRE_OP_ENDIF, nesting, lineno,
				    sizeof(DICT_PCRE_RULE));
	return (rule);
    }

    /*
     * Unrecognized input.
     */
    else {
	msg_warn("pcre map %s, line %d: ignoring unrecognized request",
		 mapname, lineno);
	return (0);
    }
}
Esempio n. 7
0
static const char *dict_pcre_lookup(DICT *dict, const char *lookup_string)
{
    DICT_PCRE *dict_pcre = (DICT_PCRE *) dict;
    DICT_PCRE_RULE *rule;
    DICT_PCRE_IF_RULE *if_rule;
    DICT_PCRE_MATCH_RULE *match_rule;
    int     lookup_len = strlen(lookup_string);
    DICT_PCRE_EXPAND_CONTEXT ctxt;
    int     nesting = 0;

    dict->error = 0;

    if (msg_verbose)
	msg_info("dict_pcre_lookup: %s: %s", dict->name, lookup_string);

    /*
     * Optionally fold the key.
     */
    if (dict->flags & DICT_FLAG_FOLD_MUL) {
	if (dict->fold_buf == 0)
	    dict->fold_buf = vstring_alloc(10);
	vstring_strcpy(dict->fold_buf, lookup_string);
	lookup_string = lowercase(vstring_str(dict->fold_buf));
    }
    for (rule = dict_pcre->head; rule; rule = rule->next) {

	/*
	 * Skip rules inside failed IF/ENDIF.
	 */
	if (nesting < rule->nesting)
	    continue;

	switch (rule->op) {

	    /*
	     * Search for a matching expression.
	     */
	case DICT_PCRE_OP_MATCH:
	    match_rule = (DICT_PCRE_MATCH_RULE *) rule;
	    ctxt.matches = pcre_exec(match_rule->pattern, match_rule->hints,
				     lookup_string, lookup_len,
				     NULL_STARTOFFSET, NULL_EXEC_OPTIONS,
				     ctxt.offsets, PCRE_MAX_CAPTURE * 3);

	    if (ctxt.matches > 0) {
		if (!match_rule->match)
		    continue;			/* Negative rule matched */
	    } else if (ctxt.matches == PCRE_ERROR_NOMATCH) {
		if (match_rule->match)
		    continue;			/* Positive rule did not
						 * match */
	    } else {
		dict_pcre_exec_error(dict->name, rule->lineno, ctxt.matches);
		continue;			/* pcre_exec failed */
	    }

	    /*
	     * Skip $number substitutions when the replacement text contains
	     * no $number strings, as learned during the compile time
	     * pre-scan. The pre-scan already replaced $$ by $.
	     */
	    if (match_rule->max_sub == 0)
		return match_rule->replacement;

	    /*
	     * We've got a match. Perform substitution on replacement string.
	     */
	    if (dict_pcre->expansion_buf == 0)
		dict_pcre->expansion_buf = vstring_alloc(10);
	    VSTRING_RESET(dict_pcre->expansion_buf);
	    ctxt.dict_pcre = dict_pcre;
	    ctxt.match_rule = match_rule;
	    ctxt.lookup_string = lookup_string;

	    if (mac_parse(match_rule->replacement, dict_pcre_expand,
			  (char *) &ctxt) & MAC_PARSE_ERROR)
		msg_fatal("pcre map %s, line %d: bad replacement syntax",
			  dict->name, rule->lineno);

	    VSTRING_TERMINATE(dict_pcre->expansion_buf);
	    return (vstring_str(dict_pcre->expansion_buf));

	    /*
	     * Conditional. XXX We provide space for matched substring info
	     * because PCRE uses part of it as workspace for backtracking.
	     * PCRE will allocate memory if it runs out of backtracking
	     * storage.
	     */
	case DICT_PCRE_OP_IF:
	    if_rule = (DICT_PCRE_IF_RULE *) rule;
	    ctxt.matches = pcre_exec(if_rule->pattern, if_rule->hints,
				     lookup_string, lookup_len,
				     NULL_STARTOFFSET, NULL_EXEC_OPTIONS,
				     ctxt.offsets, PCRE_MAX_CAPTURE * 3);

	    if (ctxt.matches > 0) {
		if (!if_rule->match)
		    continue;			/* Negative rule matched */
	    } else if (ctxt.matches == PCRE_ERROR_NOMATCH) {
		if (if_rule->match)
		    continue;			/* Positive rule did not
						 * match */
	    } else {
		dict_pcre_exec_error(dict->name, rule->lineno, ctxt.matches);
		continue;			/* pcre_exec failed */
	    }
	    nesting++;
	    continue;

	    /*
	     * ENDIF after successful IF.
	     */
	case DICT_PCRE_OP_ENDIF:
	    nesting--;
	    continue;

	default:
	    msg_panic("dict_pcre_lookup: impossible operation %d", rule->op);
	}
    }
    return (0);
}
Esempio n. 8
0
static ARGV *expand_argv(const char *service, char **argv,
			         RECIPIENT_LIST *rcpt_list, int flags)
{
    VSTRING *buf = vstring_alloc(100);
    ARGV   *result;
    char  **cpp;
    PIPE_STATE state;
    int     i;
    char   *ext;
    char   *dom;

    /*
     * This appears to be simple operation (replace $name by its expansion).
     * However, it becomes complex because a command-line argument that
     * references $recipient must expand to as many command-line arguments as
     * there are recipients (that's wat programs called by sendmail expect).
     * So we parse each command-line argument, and depending on what we find,
     * we either expand the argument just once, or we expand it once for each
     * recipient. In either case we end up parsing the command-line argument
     * twice. The amount of CPU time wasted will be negligible.
     * 
     * Note: we can't use recursive macro expansion here, because recursion
     * would screw up mail addresses that contain $ characters.
     */
#define NO	0
#define EARLY_RETURN(x) { argv_free(result); vstring_free(buf); return (x); }

    result = argv_alloc(1);
    for (cpp = argv; *cpp; cpp++) {
	state.service = service;
	state.expand_flag = 0;
	if (mac_parse(*cpp, parse_callback, (char *) &state) & MAC_PARSE_ERROR)
	    EARLY_RETURN(0);
	if (state.expand_flag == 0) {		/* no $recipient etc. */
	    argv_add(result, dict_eval(PIPE_DICT_TABLE, *cpp, NO), ARGV_END);
	} else {				/* contains $recipient etc. */
	    for (i = 0; i < rcpt_list->len; i++) {

		/*
		 * This argument contains $recipient.
		 */
		if (state.expand_flag & PIPE_FLAG_RCPT) {
		    morph_recipient(buf, rcpt_list->info[i].address, flags);
		    dict_update(PIPE_DICT_TABLE, PIPE_DICT_RCPT, STR(buf));
		}

		/*
		 * This argument contains $original_recipient.
		 */
		if (state.expand_flag & PIPE_FLAG_ORIG_RCPT) {
		    morph_recipient(buf, rcpt_list->info[i].orig_addr, flags);
		    dict_update(PIPE_DICT_TABLE, PIPE_DICT_ORIG_RCPT, STR(buf));
		}

		/*
		 * This argument contains $user. Extract the plain user name.
		 * Either anything to the left of the extension delimiter or,
		 * in absence of the latter, anything to the left of the
		 * rightmost @.
		 * 
		 * Beware: if the user name is blank (e.g. +user@host), the
		 * argument is suppressed. This is necessary to allow for
		 * cyrus bulletin-board (global mailbox) delivery. XXX But,
		 * skipping empty user parts will also prevent other
		 * expansions of this specific command-line argument.
		 */
		if (state.expand_flag & PIPE_FLAG_USER) {
		    morph_recipient(buf, rcpt_list->info[i].address,
				    flags & PIPE_OPT_FOLD_ALL);
		    if (split_at_right(STR(buf), '@') == 0)
			msg_warn("no @ in recipient address: %s",
				 rcpt_list->info[i].address);
		    if (*var_rcpt_delim)
			split_addr(STR(buf), var_rcpt_delim);
		    if (*STR(buf) == 0)
			continue;
		    dict_update(PIPE_DICT_TABLE, PIPE_DICT_USER, STR(buf));
		}

		/*
		 * This argument contains $extension. Extract the recipient
		 * extension: anything between the leftmost extension
		 * delimiter and the rightmost @. The extension may be blank.
		 */
		if (state.expand_flag & PIPE_FLAG_EXTENSION) {
		    morph_recipient(buf, rcpt_list->info[i].address,
				    flags & PIPE_OPT_FOLD_ALL);
		    if (split_at_right(STR(buf), '@') == 0)
			msg_warn("no @ in recipient address: %s",
				 rcpt_list->info[i].address);
		    if (*var_rcpt_delim == 0
			|| (ext = split_addr(STR(buf), var_rcpt_delim)) == 0)
			ext = "";		/* insert null arg */
		    dict_update(PIPE_DICT_TABLE, PIPE_DICT_EXTENSION, ext);
		}

		/*
		 * This argument contains $mailbox. Extract the mailbox name:
		 * anything to the left of the rightmost @.
		 */
		if (state.expand_flag & PIPE_FLAG_MAILBOX) {
		    morph_recipient(buf, rcpt_list->info[i].address,
				    flags & PIPE_OPT_FOLD_ALL);
		    if (split_at_right(STR(buf), '@') == 0)
			msg_warn("no @ in recipient address: %s",
				 rcpt_list->info[i].address);
		    dict_update(PIPE_DICT_TABLE, PIPE_DICT_MAILBOX, STR(buf));
		}

		/*
		 * This argument contains $domain. Extract the domain name:
		 * anything to the right of the rightmost @.
		 */
		if (state.expand_flag & PIPE_FLAG_DOMAIN) {
		    morph_recipient(buf, rcpt_list->info[i].address,
				    flags & PIPE_OPT_FOLD_ALL);
		    dom = split_at_right(STR(buf), '@');
		    if (dom == 0) {
			msg_warn("no @ in recipient address: %s",
				 rcpt_list->info[i].address);
			dom = "";		/* insert null arg */
		    }
		    dict_update(PIPE_DICT_TABLE, PIPE_DICT_DOMAIN, dom);
		}

		/*
		 * Done.
		 */
		argv_add(result, dict_eval(PIPE_DICT_TABLE, *cpp, NO), ARGV_END);
	    }
	}
    }
    argv_terminate(result);
    vstring_free(buf);
    return (result);
}
Esempio n. 9
0
static int mac_expand_callback(int type, VSTRING *buf, void *ptr)
{
    static const char myname[] = "mac_expand_callback";
    MAC_EXP_CONTEXT *mc = (MAC_EXP_CONTEXT *) ptr;
    int     lookup_mode;
    const char *lookup;
    char   *cp;
    int     ch;
    ssize_t res_len;
    ssize_t tmp_len;
    const char *res_iftrue;
    const char *res_iffalse;

    /*
     * Sanity check.
     */
    if (mc->level++ > 100)
	mac_exp_parse_error(mc, "unreasonable macro call nesting: \"%s\"",
			    vstring_str(buf));
    if (mc->status & MAC_PARSE_ERROR)
	return (mc->status);

    /*
     * Named parameter or relational expression. In case of a syntax error,
     * return without doing damage, and issue a warning instead.
     */
    if (type == MAC_PARSE_EXPR) {

	cp = vstring_str(buf);

	/*
	 * Relational expression. If recursion is disabled, perform only one
	 * level of $name expansion.
	 */
	if (MAC_EXP_FIND_LEFT_CURLY(tmp_len, cp)) {
	    if (mac_exp_parse_relational(mc, &lookup, &cp) != 0)
		return (mc->status);

	    /*
	     * Look for the ? or : operator.
	     */
	    if ((ch = *cp) != 0) {
		if (ch != '?' && ch != ':')
		    MAC_EXP_ERR_RETURN(mc, "\"?\" or \":\" expected at: "
				       "\"...}>>>%.20s\"", cp);
		cp++;
	    }
	}

	/*
	 * Named parameter.
	 */
	else {

	    /*
	     * Look for the ? or : operator. In case of a syntax error,
	     * return without doing damage, and issue a warning instead.
	     */
	    for ( /* void */ ; /* void */ ; cp++) {
		if ((ch = *cp) == 0) {
		    lookup_mode = MAC_EXP_MODE_USE;
		    break;
		}
		if (ch == '?' || ch == ':') {
		    *cp++ = 0;
		    lookup_mode = MAC_EXP_MODE_TEST;
		    break;
		}
		if (!ISALNUM(ch) && ch != '_') {
		    MAC_EXP_ERR_RETURN(mc, "attribute name syntax error at: "
				       "\"...%.*s>>>%.20s\"",
				       (int) (cp - vstring_str(buf)),
				       vstring_str(buf), cp);
		}
	    }

	    /*
	     * Look up the named parameter. Todo: allow the lookup function
	     * to specify if the result is safe for $name expanson.
	     */
	    lookup = mc->lookup(vstring_str(buf), lookup_mode, mc->context);
	}

	/*
	 * Return the requested result. After parsing the result operand
	 * following ?, we fall through to parse the result operand following
	 * :. This is necessary with the ternary ?: operator: first, with
	 * MAC_EXP_FLAG_SCAN to parse both result operands with mac_parse(),
	 * and second, to find garbage after any result operand. Without
	 * MAC_EXP_FLAG_SCAN the content of only one of the ?: result
	 * operands will be parsed with mac_parse(); syntax errors in the
	 * other operand will be missed.
	 */
	switch (ch) {
	case '?':
	    if (MAC_EXP_FIND_LEFT_CURLY(tmp_len, cp)) {
		if ((res_iftrue = mac_exp_extract_curly_payload(mc, &cp)) == 0)
		    return (mc->status);
	    } else {
		res_iftrue = cp;
		cp = "";			/* no left-over text */
	    }
	    if ((lookup != 0 && *lookup != 0) || (mc->flags & MAC_EXP_FLAG_SCAN))
		mc->status |= mac_parse(res_iftrue, mac_expand_callback,
					(void *) mc);
	    if (*cp == 0)			/* end of input, OK */
		break;
	    if (*cp != ':')			/* garbage */
		MAC_EXP_ERR_RETURN(mc, "\":\" expected at: "
				   "\"...%s}>>>%.20s\"", res_iftrue, cp);
	    cp += 1;
	    /* FALLTHROUGH: do not remove, see comment above. */
	case ':':
	    if (MAC_EXP_FIND_LEFT_CURLY(tmp_len, cp)) {
		if ((res_iffalse = mac_exp_extract_curly_payload(mc, &cp)) == 0)
		    return (mc->status);
	    } else {
		res_iffalse = cp;
		cp = "";			/* no left-over text */
	    }
	    if (lookup == 0 || *lookup == 0 || (mc->flags & MAC_EXP_FLAG_SCAN))
		mc->status |= mac_parse(res_iffalse, mac_expand_callback,
					(void *) mc);
	    if (*cp != 0)			/* garbage */
		MAC_EXP_ERR_RETURN(mc, "unexpected input at: "
				   "\"...%s}>>>%.20s\"", res_iffalse, cp);
	    break;
	case 0:
	    if (lookup == 0) {
		mc->status |= MAC_PARSE_UNDEF;
	    } else if (*lookup == 0 || (mc->flags & MAC_EXP_FLAG_SCAN)) {
		 /* void */ ;
	    } else if (mc->flags & MAC_EXP_FLAG_RECURSE) {
		vstring_strcpy(buf, lookup);
		mc->status |= mac_parse(vstring_str(buf), mac_expand_callback,
					(void *) mc);
	    } else {
		res_len = VSTRING_LEN(mc->result);
		vstring_strcat(mc->result, lookup);
		if (mc->flags & MAC_EXP_FLAG_PRINTABLE) {
		    printable(vstring_str(mc->result) + res_len, '_');
		} else if (mc->filter) {
		    cp = vstring_str(mc->result) + res_len;
		    while (*(cp += strspn(cp, mc->filter)))
			*cp++ = '_';
		}
	    }
	    break;
	default:
	    msg_panic("%s: unknown operator code %d", myname, ch);
	}
    }

    /*
     * Literal text.
     */
    else if ((mc->flags & MAC_EXP_FLAG_SCAN) == 0) {
	vstring_strcat(mc->result, vstring_str(buf));
    }
    mc->level--;

    return (mc->status);
}
Esempio n. 10
0
int nmrp_do(struct nmrpd_args *args)
{
	struct nmrp_pkt tx, rx;
	uint8_t *src, dest[6];
	uint16_t len, region;
	char *filename;
	time_t beg;
	int i, status, ulreqs, expect, upload_ok, autoip;
	struct ethsock *sock;
	uint32_t intf_addr;
	void (*sigh_orig)(int);
	struct {
		struct in_addr addr;
		struct in_addr mask;
	} PACKED ipconf;

	if (args->op != NMRP_UPLOAD_FW) {
		fprintf(stderr, "Operation not implemented.\n");
		return 1;
	}

	if (!mac_parse(args->mac, dest)) {
		fprintf(stderr, "Invalid MAC address '%s'.\n", args->mac);
		return 1;
	}

	if ((ipconf.mask.s_addr = inet_addr(args->ipmask)) == INADDR_NONE) {
		fprintf(stderr, "Invalid subnet mask '%s'.\n", args->ipmask);
		return 1;
	}

	if (!args->ipaddr) {
		autoip = true;
		/* The MAC of the device that was used to test this utility starts
		 * with a4:2b:8c, hence 164 (0xa4) and 183 (0x2b + 0x8c)
		 */
		args->ipaddr = "10.164.183.252";

		if (!args->ipaddr_intf) {
			args->ipaddr_intf = "10.164.183.253";
		}
	} else if (args->ipaddr_intf) {
		autoip = true;
	} else {
		autoip = false;
	}

	if ((ipconf.addr.s_addr = inet_addr(args->ipaddr)) == INADDR_NONE) {
		fprintf(stderr, "Invalid IP address '%s'.\n", args->ipaddr);
		return 1;
	}

	if (args->ipaddr_intf && (intf_addr = inet_addr(args->ipaddr_intf)) == INADDR_NONE) {
		fprintf(stderr, "Invalid IP address '%s'.\n", args->ipaddr_intf);
		return 1;
	}

	if (args->file_local && strcmp(args->file_local, "-") && access(args->file_local, R_OK) == -1) {
		fprintf(stderr, "Error accessing file '%s'.\n", args->file_local);
		return 1;
	}

	if (args->file_remote) {
		if (!tftp_is_valid_filename(args->file_remote)) {
			fprintf(stderr, "Invalid remote filename '%s'.\n",
					args->file_remote);
			return 1;
		}
	}

	if (args->region) {
		region = htons(to_region_code(args->region));
		if (!region) {
			fprintf(stderr, "Invalid region code '%s'.\n", args->region);
			return 1;
		}
	} else {
		region = 0;
	}

	status = 1;

	sock = ethsock_create(args->intf, ETH_P_NMRP);
	if (!sock) {
		return 1;
	}

	gsock = sock;
	garp = 0;
	sigh_orig = signal(SIGINT, sigh);

	if (!autoip) {
		status = is_valid_ip(sock, &ipconf.addr, &ipconf.mask);
		if (status <= 0) {
			if (!status) {
				fprintf(stderr, "Address %s/%s cannot be used on interface %s.\n",
						args->ipaddr, args->ipmask, args->intf);
			}
			goto out;
		}
	} else {
		if (verbosity) {
			printf("Adding %s to interface %s.\n", args->ipaddr_intf, args->intf);
		}

		if (ethsock_ip_add(sock, intf_addr, ipconf.mask.s_addr, &gundo) != 0) {
			goto out;
		}
	}

	if (ethsock_set_timeout(sock, args->rx_timeout)) {
		goto out;
	}

	src = ethsock_get_hwaddr(sock);
	if (!src) {
		goto out;
	}

	memcpy(tx.eh.ether_shost, src, 6);
	memcpy(tx.eh.ether_dhost, dest, 6);
	tx.eh.ether_type = htons(ETH_P_NMRP);

	msg_init(&tx.msg, NMRP_C_ADVERTISE);
	msg_opt_add(&tx.msg, NMRP_O_MAGIC_NO, "NTGR", 4);
	msg_hton(&tx.msg);

	i = 0;
	upload_ok = 0;
	beg = time(NULL);

	while (1) {
		printf("\rAdvertising NMRP server on %s ... %c",
				args->intf, spinner[i]);
		fflush(stdout);
		i = (i + 1) & 3;

		if (pkt_send(sock, &tx) < 0) {
			perror("sendto");
			goto out;
		}

		status = pkt_recv(sock, &rx);
		if (status == 0 && memcmp(rx.eh.ether_dhost, src, 6) == 0) {
			break;
		} else if (status == 1) {
			goto out;
		} else {
			if ((time(NULL) - beg) >= 60) {
				printf("\nNo response after 60 seconds. Bailing out.\n");
				goto out;
			}
		}
	}

	printf("\n");

	expect = NMRP_C_CONF_REQ;
	ulreqs = 0;

	do {
		if (expect != NMRP_C_NONE && rx.msg.code != expect) {
			fprintf(stderr, "Received %s while waiting for %s!\n",
					msg_code_str(rx.msg.code), msg_code_str(expect));
		}

		msg_init(&tx.msg, NMRP_C_NONE);

		status = 1;

		switch (rx.msg.code) {
			case NMRP_C_ADVERTISE:
				printf("Received NMRP advertisement from %s.\n",
						mac_to_str(rx.eh.ether_shost));
				status = 1;
				goto out;
			case NMRP_C_CONF_REQ:
				tx.msg.code = NMRP_C_CONF_ACK;

				msg_opt_add(&tx.msg, NMRP_O_DEV_IP, &ipconf, 8);
				msg_opt_add(&tx.msg, NMRP_O_FW_UP, NULL, 0);

#ifdef NMRPFLASH_SET_REGION
				if (region) {
					msg_opt_add(&tx.msg, NMRP_O_DEV_REGION, &region, 2);
				}
#endif

				expect = NMRP_C_TFTP_UL_REQ;

				printf("Received configuration request from %s.\n",
						mac_to_str(rx.eh.ether_shost));

				memcpy(tx.eh.ether_dhost, rx.eh.ether_shost, 6);

				printf("Sending configuration: ip %s, mask %s.\n",
						args->ipaddr, args->ipmask);

				memcpy(arpmac, rx.eh.ether_shost, 6);
				memcpy(&arpip, &ipconf.addr, sizeof(ipconf.addr));

				if (ethsock_arp_add(sock, arpmac, &arpip) != 0) {
					goto out;
				}

				garp = 1;

				break;
			case NMRP_C_TFTP_UL_REQ:
				if (!upload_ok) {
					if (++ulreqs > 5) {
						printf("Bailing out after %d upload requests.\n",
								ulreqs);
						tx.msg.code = NMRP_C_CLOSE_REQ;
						break;
					}
				} else {
					if (verbosity) {
						printf("Ignoring extra upload request.\n");
					}
					ethsock_set_timeout(sock, args->ul_timeout);
					tx.msg.code = NMRP_C_KEEP_ALIVE_REQ;
					break;
				}

				len = 0;
				filename = msg_opt_data(&rx.msg, NMRP_O_FILE_NAME, &len);
				if (filename) {
					if (!args->file_remote) {
						args->file_remote = filename;
					}
					printf("Received upload request: filename '%.*s'.\n",
							len, filename);
				} else if (!args->file_remote) {
					args->file_remote = args->file_local;
					printf("Received upload request with empty filename.\n");
				}

				status = 0;

				if (args->tftpcmd) {
					printf("Executing '%s' ... \n", args->tftpcmd);
					setenv("IP", inet_ntoa(ipconf.addr), 1);
					setenv("MAC", mac_to_str(rx.eh.ether_shost), 1);
					setenv("NETMASK", inet_ntoa(ipconf.mask), 1);
					status = system(args->tftpcmd);
				}

				if (!status && args->file_local) {
					if (!autoip) {
						status = is_valid_ip(sock, &ipconf.addr, &ipconf.mask);
						if (status < 0) {
							goto out;
						} else if (!status) {
							printf("IP address of %s has changed. Please assign a "
									"static ip to the interface.\n", args->intf);
							tx.msg.code = NMRP_C_CLOSE_REQ;
							break;
						}
					}

					if (verbosity) {
						printf("Using remote filename '%s'.\n",
								args->file_remote);
					}

					if (!strcmp(args->file_local, "-")) {
						printf("Uploading from stdin ... ");
					} else {
						printf("Uploading %s ... ", leafname(args->file_local));
					}
					fflush(stdout);
					status = tftp_put(args);
				}

				if (!status) {
					printf("OK\nWaiting for remote to respond.\n");
					upload_ok = 1;
					ethsock_set_timeout(sock, args->ul_timeout);
					tx.msg.code = NMRP_C_KEEP_ALIVE_REQ;
					expect = NMRP_C_NONE;
				} else if (status == -2) {
					expect = NMRP_C_TFTP_UL_REQ;
				} else {
					goto out;
				}

				break;
			case NMRP_C_KEEP_ALIVE_REQ:
				tx.msg.code = NMRP_C_KEEP_ALIVE_ACK;
				ethsock_set_timeout(sock, args->ul_timeout);
				printf("Received keep-alive request.\n");
				break;
			case NMRP_C_CLOSE_REQ:
				tx.msg.code = NMRP_C_CLOSE_ACK;
				break;
			case NMRP_C_CLOSE_ACK:
				status = 0;
				goto out;
			default:
				fprintf(stderr, "Unknown message code 0x%02x!\n",
						rx.msg.code);
				msg_dump(&rx.msg, 0);
		}

		if (tx.msg.code != NMRP_C_NONE) {
			msg_hton(&tx.msg);

			if (pkt_send(sock, &tx) < 0) {
				perror("sendto");
				goto out;
			}

			if (tx.msg.code == NMRP_C_CLOSE_REQ) {
				goto out;
			}
		}

		if (rx.msg.code == NMRP_C_CLOSE_REQ) {
			printf("Remote finished. Closing connection.\n");
			break;
		}

		status = pkt_recv(sock, &rx);
		if (status) {
			if (status == 2) {
				fprintf(stderr, "Timeout while waiting for %s.\n",
						msg_code_str(expect));
			}
			goto out;
		}

		ethsock_set_timeout(sock, args->rx_timeout);

	} while (1);

	status = 0;

	if (ulreqs) {
		printf("Reboot your device now.\n");
	} else {
		printf("No upload request received.\n");
	}

out:
	signal(SIGINT, sigh_orig);
	gsock = NULL;
	ethsock_arp_del(sock, arpmac, &arpip);
	ethsock_ip_del(sock, &gundo);
	ethsock_close(sock);
	return status;
}