Beispiel #1
0
static DICT_CIDR_ENTRY *dict_cidr_parse_rule(char *p, VSTRING *why)
{
    DICT_CIDR_ENTRY *rule;
    char   *pattern;
    char   *value;
    CIDR_MATCH cidr_info;
    MAI_HOSTADDR_STR hostaddr;

    /*
     * Split the rule into key and value. We already eliminated leading
     * whitespace, comments, empty lines or lines with whitespace only. This
     * means a null key can't happen but we will handle this anyway.
     */
    pattern = p;
    while (*p && !ISSPACE(*p))			/* Skip over key */
	p++;
    if (*p)					/* Terminate key */
	*p++ = 0;
    while (*p && ISSPACE(*p))			/* Skip whitespace */
	p++;
    value = p;
    trimblanks(value, 0)[0] = 0;		/* Trim trailing blanks */
    if (*pattern == 0) {
	vstring_sprintf(why, "no address pattern");
	return (0);
    }
    if (*value == 0) {
	vstring_sprintf(why, "no lookup result");
	return (0);
    }

    /*
     * Parse the pattern, destroying it in the process.
     */
    if (cidr_match_parse(&cidr_info, pattern, why) != 0)
	return (0);

    /*
     * Bundle up the result.
     */
    rule = (DICT_CIDR_ENTRY *) mymalloc(sizeof(DICT_CIDR_ENTRY));
    rule->cidr_info = cidr_info;
    rule->value = mystrdup(value);

    if (msg_verbose) {
	if (inet_ntop(cidr_info.addr_family, cidr_info.net_bytes,
		      hostaddr.buf, sizeof(hostaddr.buf)) == 0)
	    msg_fatal("inet_ntop: %m");
	msg_info("dict_cidr_open: add %s/%d %s",
		 hostaddr.buf, cidr_info.mask_shift, rule->value);
    }
    return (rule);
}
Beispiel #2
0
const HEADER_OPTS *header_opts_find(const char *string)
{
    const char *cp;

    if (header_hash == 0)
	header_opts_init();

    /*
     * Look up the lower-cased version of the header name.
     */
    VSTRING_RESET(header_key);
    for (cp = string; *cp != ':'; cp++) {
	if (*cp == 0)
	    msg_panic("header_opts_find: no colon in header: %.30s", string);
	VSTRING_ADDCH(header_key, TOLOWER(*cp));
    }
    vstring_truncate(header_key,
		     trimblanks(vstring_str(header_key), cp - string)
		     - vstring_str(header_key));
    VSTRING_TERMINATE(header_key);
    return ((const HEADER_OPTS *) htable_find(header_hash, vstring_str(header_key)));
}
Beispiel #3
0
DICT   *dict_thash_open(const char *path, int open_flags, int dict_flags)
{
    DICT_THASH *dict_thash;
    VSTREAM *fp = 0;
    struct stat st;
    time_t  before;
    time_t  after;
    VSTRING *line_buffer = 0;
    int     lineno;
    char   *key;
    char   *value;
    HTABLE *table;
    HTABLE_INFO *ht;

    /*
     * Let the optimizer worry about eliminating redundant code.
     */
#define DICT_THASH_OPEN_RETURN(d) { \
	DICT *__d = (d); \
	if (fp != 0) \
	    vstream_fclose(fp); \
	if (line_buffer != 0) \
	    vstring_free(line_buffer); \
	return (__d); \
    } while (0)

    /*
     * Sanity checks.
     */
    if (open_flags != O_RDONLY)
	DICT_THASH_OPEN_RETURN(dict_surrogate(DICT_TYPE_THASH, path,
					      open_flags, dict_flags,
				  "%s:%s map requires O_RDONLY access mode",
					      DICT_TYPE_THASH, path));

    /*
     * Read the flat text file into in-memory hash. Read the file again if it
     * may have changed while we were reading.
     */
    for (before = time((time_t *) 0); /* see below */ ; before = after) {
	if ((fp = vstream_fopen(path, open_flags, 0644)) == 0) {
	    DICT_THASH_OPEN_RETURN(dict_surrogate(DICT_TYPE_THASH, path,
						  open_flags, dict_flags,
					     "open database %s: %m", path));
	}
	if (line_buffer == 0)
	    line_buffer = vstring_alloc(100);
	lineno = 0;
	table = htable_create(13);
	while (readlline(line_buffer, fp, &lineno)) {

	    /*
	     * Split on the first whitespace character, then trim leading and
	     * trailing whitespace from key and value.
	     */
	    key = STR(line_buffer);
	    value = key + strcspn(key, " \t\r\n");
	    if (*value)
		*value++ = 0;
	    while (ISSPACE(*value))
		value++;
	    trimblanks(key, 0)[0] = 0;
	    trimblanks(value, 0)[0] = 0;

	    /*
	     * Enforce the "key whitespace value" format. Disallow missing
	     * keys or missing values.
	     */
	    if (*key == 0 || *value == 0) {
		msg_warn("%s, line %d: expected format: key whitespace value"
			 " -- ignoring this line", path, lineno);
		continue;
	    }
	    if (key[strlen(key) - 1] == ':')
		msg_warn("%s, line %d: record is in \"key: value\" format;"
			 " is this an alias file?", path, lineno);

	    /*
	     * Optionally fold the key.
	     */
	    if (dict_flags & DICT_FLAG_FOLD_FIX)
		lowercase(key);

	    /*
	     * Store the value under the key. Handle duplicates
	     * appropriately.
	     */
	    if ((ht = htable_locate(table, key)) != 0) {
		if (dict_flags & DICT_FLAG_DUP_IGNORE) {
		     /* void */ ;
		} else if (dict_flags & DICT_FLAG_DUP_REPLACE) {
		    myfree(ht->value);
		    ht->value = mystrdup(value);
		} else if (dict_flags & DICT_FLAG_DUP_WARN) {
		    msg_warn("%s, line %d: duplicate entry: \"%s\"",
			     path, lineno, key);
		} else {
		    msg_fatal("%s, line %d: duplicate entry: \"%s\"",
			      path, lineno, key);
		}
	    } else {
		htable_enter(table, key, mystrdup(value));
	    }
	}

	/*
	 * See if the source file is hot.
	 */
	if (fstat(vstream_fileno(fp), &st) < 0)
	    msg_fatal("fstat %s: %m", path);
	if (vstream_fclose(fp))
	    msg_fatal("read %s: %m", path);
	fp = 0;					/* DICT_THASH_OPEN_RETURN() */
	after = time((time_t *) 0);
	if (st.st_mtime < before - 1 || st.st_mtime > after)
	    break;

	/*
	 * Yes, it is hot. Discard the result and read the file again.
	 */
	htable_free(table, myfree);
	if (msg_verbose > 1)
	    msg_info("pausing to let file %s cool down", path);
	doze(300000);
    }

    /*
     * Create the in-memory table.
     */
    dict_thash = (DICT_THASH *)
	dict_alloc(DICT_TYPE_THASH, path, sizeof(*dict_thash));
    dict_thash->dict.lookup = dict_thash_lookup;
    dict_thash->dict.sequence = dict_thash_sequence;
    dict_thash->dict.close = dict_thash_close;
    dict_thash->dict.flags = dict_flags | DICT_FLAG_DUP_WARN | DICT_FLAG_FIXED;
    if (dict_flags & DICT_FLAG_FOLD_FIX)
	dict_thash->dict.fold_buf = vstring_alloc(10);
    dict_thash->info = 0;
    dict_thash->table = table;
    dict_thash->dict.owner.uid = st.st_uid;
    dict_thash->dict.owner.status = (st.st_uid != 0);

    DICT_THASH_OPEN_RETURN(DICT_DEBUG (&dict_thash->dict));
}
Beispiel #4
0
/* ARGSUSED */
int main(int argc, char **argv)
{

#ifdef LTD_STATS

    printf("mergescores: this program cannot be used with LTD_STATS\n");
    exit(1);

#else
    int fd;
    int i;
    char buf[MAXBUFFER];
    float fplanets, farmsbomb, fkills, flosses;
    float temp;
    int delta;
    int fcount = 0;
    int dupcount = 0;
    int foldcount = 0;
    char namebuf[NAME_LEN+1];

    if (argc>1) usage();
    getpath();
    fprintf(stderr, "Warning:  If you do not know how to use this program, break it now!\n");
    lstatus=(struct status *) malloc(sizeof(struct status));
    fstatus=(struct status *) malloc(sizeof(struct status));
    scanf("%10ld %10d %10d %10d %10d %10lf\n", 
	(long int *) &fstatus->time, 
	&fstatus->planets, 
	&fstatus->armsbomb, 
	&fstatus->kills, 
	&fstatus->losses,
	&fstatus->timeprod);

    fd = open(Global, O_RDONLY);
    if (fd < 0) {
	fprintf(stderr, "Cannot open the global file!\n");
	exit(0);
    }
    read(fd, (char *) lstatus, sizeof(struct status));
    close(fd);

    fprintf(stderr, "          Ticks    Planets   Armsbomb      Kills     Losses   Timeprod\n");
    fprintf(stderr, "Loc: %10ld %10d %10d %10d %10d %10lf\n", 
	(long int) lstatus->time, 
	lstatus->planets, 
	lstatus->armsbomb, 
	lstatus->kills, 
	lstatus->losses,
	lstatus->timeprod);
    fprintf(stderr, "For: %10ld %10d %10d %10d %10d %10lf\n", 
	(long int) fstatus->time, 
	fstatus->planets, 
	fstatus->armsbomb, 
	fstatus->kills, 
	fstatus->losses,
	fstatus->timeprod);

/* want factors such that (For. rating)*factor == (Local rating)
 * (to scale t-mode kills).
 *                                       foreign->timeprod * local->kills
 * therefore, factor is local/foreign == -----------------------------------
 *                                       foreign->kills    * local->timeprod 
 * (for defense, use reciprocal)
 */

    fplanets = (((float) fstatus->timeprod)*((float) lstatus->planets))/
                (((float) fstatus->planets)*((float) lstatus->timeprod));
    farmsbomb = (((float) fstatus->timeprod)*((float) lstatus->armsbomb))/
                (((float) fstatus->armsbomb)*((float) lstatus->timeprod));
    fkills = (((float) fstatus->timeprod)*((float) lstatus->kills))/
                (((float) fstatus->kills)*((float) lstatus->timeprod));
    flosses = (((float) fstatus->losses)*((float) lstatus->timeprod))/
              (((float) fstatus->timeprod)*((float) lstatus->losses));
    fprintf(stderr, "Convert Factors:%10.3f %10.3f %10.3f %10.3f\n",
	    fplanets,
	    farmsbomb,
	    fkills,
	    flosses);
    fprintf(stderr, "(foreign rating * factor) = local rating\n\n");
    
    read_lplayers();

    fd = open(PlayerFile, O_WRONLY|O_CREAT|O_TRUNC, 0600);
    if (fd < 0) {
	perror(PlayerFile);
	exit(1);
    }

    fprintf(stderr, "Processing foreign players...\n");
    while (fgets(buf, MAXBUFFER, stdin)) {
	if (strlen(buf) > 0) buf[strlen(buf)-1] = '\0';
	trimblanks2(buf+16);
	trimblanks(buf+33);
	trimblanks(buf+129);
	strcpy(play_entry.name, buf);
	fcount++;
	strcpy(play_entry.password, buf+17);
	strcpy(play_entry.stats.st_keymap, buf+34);
	sscanf(buf+130, " %d %lf %d %d %d %d %d %d %d %d %d %d %d %d %d %lf %ld %d\n",
	    &play_entry.stats.st_rank,
	    &play_entry.stats.st_maxkills,
	    &play_entry.stats.st_kills,
	    &play_entry.stats.st_losses,
	    &play_entry.stats.st_armsbomb,
	    &play_entry.stats.st_planets,
	    &play_entry.stats.st_ticks,
	    &play_entry.stats.st_tkills,
	    &play_entry.stats.st_tlosses,
	    &play_entry.stats.st_tarmsbomb,
	    &play_entry.stats.st_tplanets,
	    &play_entry.stats.st_tticks,
	    &play_entry.stats.st_sbkills,
	    &play_entry.stats.st_sblosses,
	    &play_entry.stats.st_sbticks,
	    &play_entry.stats.st_sbmaxkills,
	    &play_entry.stats.st_lastlogin,
	    &play_entry.stats.st_flags);
	temp = play_entry.stats.st_tplanets * fplanets;
	delta = temp - play_entry.stats.st_tplanets; /* increase/decrease */
	play_entry.stats.st_tplanets = temp;
	play_entry.stats.st_planets -= delta;
	if (play_entry.stats.st_planets < 0) play_entry.stats.st_planets = 0;

	temp = play_entry.stats.st_tarmsbomb * farmsbomb;
	delta = temp - play_entry.stats.st_tarmsbomb; /* increase/decrease */
	play_entry.stats.st_tarmsbomb = temp;
	play_entry.stats.st_armsbomb -= delta;
	if (play_entry.stats.st_armsbomb < 0) play_entry.stats.st_armsbomb = 0;

	temp = play_entry.stats.st_tkills * fkills;
	delta = temp - play_entry.stats.st_tkills; /* increase/decrease */
	play_entry.stats.st_tkills = temp;
	play_entry.stats.st_kills -= delta;
	if (play_entry.stats.st_kills < 0) play_entry.stats.st_kills = 0;

	temp = play_entry.stats.st_tlosses * flosses;
	delta = temp - play_entry.stats.st_tlosses; /* increase/decrease */
	play_entry.stats.st_tlosses = temp;
	play_entry.stats.st_losses -= delta;
	if (play_entry.stats.st_losses < 0) play_entry.stats.st_losses = 0;

	play_entry.stats.st_lastlogin = time(NULL);

	i = dumbsearch(&play_entry);
	switch (i) {
	  case DUP_NAME_DIFF_PASSWORD:
	    dupcount++;
	    strcpy(namebuf, play_entry.name);
	    strcat(namebuf, "_");
	    printf("%-16.16s %-16.16s %-96.96s %1d %9.2lf %7d %7d %7d %7d %7d %7d %7d %7d %7d %7d %7d %7d %7d %9.2lf %9ld %7d\n",
		   namebuf,
		   play_entry.password,
		   play_entry.stats.st_keymap,
		   play_entry.stats.st_rank,
		   play_entry.stats.st_maxkills,
		   play_entry.stats.st_kills,
		   play_entry.stats.st_losses,
		   play_entry.stats.st_armsbomb,
		   play_entry.stats.st_planets,
		   play_entry.stats.st_ticks,
		   play_entry.stats.st_tkills,
		   play_entry.stats.st_tlosses,
		   play_entry.stats.st_tarmsbomb,
		   play_entry.stats.st_tplanets,
		   play_entry.stats.st_tticks,
		   play_entry.stats.st_sbkills,
		   play_entry.stats.st_sblosses,
		   play_entry.stats.st_sbticks,
		   play_entry.stats.st_sbmaxkills,
		   play_entry.stats.st_lastlogin,
		   play_entry.stats.st_flags);
	    break;
	  case DIFF_NAME:	/* append (actually, prepend) */
	    write(fd, (char *) &play_entry, sizeof(struct statentry));
	    break;
	  default: /* fold stats together */
	    foldcount++;

	    lplayers[i]->stats.st_maxkills = MAX(lplayers[i]->stats.st_maxkills, play_entry.stats.st_maxkills);

	    lplayers[i]->stats.st_kills +=play_entry.stats.st_kills;
	    lplayers[i]->stats.st_losses += play_entry.stats.st_losses;
	    lplayers[i]->stats.st_armsbomb += play_entry.stats.st_armsbomb;
	    lplayers[i]->stats.st_planets += play_entry.stats.st_planets;
	    lplayers[i]->stats.st_ticks += play_entry.stats.st_ticks;
	    lplayers[i]->stats.st_tkills += play_entry.stats.st_tkills;
	    lplayers[i]->stats.st_tlosses += play_entry.stats.st_tlosses;
	    lplayers[i]->stats.st_tarmsbomb += play_entry.stats.st_tarmsbomb;
	    lplayers[i]->stats.st_tplanets += play_entry.stats.st_tplanets;
	    lplayers[i]->stats.st_tticks += play_entry.stats.st_tticks;
	    lplayers[i]->stats.st_sbkills += play_entry.stats.st_sbkills;
	    lplayers[i]->stats.st_sblosses += play_entry.stats.st_sblosses;
	    lplayers[i]->stats.st_sbticks += play_entry.stats.st_sbticks;

	    lplayers[i]->stats.st_lastlogin = play_entry.stats.st_lastlogin;

	    lplayers[i]->stats.st_sbmaxkills = MAX(lplayers[i]->stats.st_sbmaxkills, play_entry.stats.st_sbmaxkills);

	    lplayers[i]->stats.st_rank = MAX(lplayers[i]->stats.st_rank, play_entry.stats.st_rank);
	    
	    break;
	}			/* end switch */
    }				/* end while */

    fprintf(stderr, "Rewriting local/folded players...\n");
    for (i = 0; i < lplayercount; i++) {
	write(fd, (char *) lplayers[i], sizeof(struct statentry));
    }

    fprintf(stderr, "Done!  %d entries appended/folded (%d folded).\n",
	    fcount - dupcount , foldcount);
    fprintf(stderr, "%d entries not appended, written to stdout.\n", dupcount);
    close(fd);

#endif /* LTD_STATS */

    return 1;		/* satify lint */
}
Beispiel #5
0
DICT   *dict_pcre_open(const char *mapname, int open_flags, int dict_flags)
{
    DICT_PCRE *dict_pcre;
    VSTREAM *map_fp;
    struct stat st;
    VSTRING *line_buffer;
    DICT_PCRE_RULE *last_rule = 0;
    DICT_PCRE_RULE *rule;
    int     lineno = 0;
    int     nesting = 0;
    char   *p;

    /*
     * Sanity checks.
     */
    if (open_flags != O_RDONLY)
	return (dict_surrogate(DICT_TYPE_PCRE, mapname, open_flags, dict_flags,
			       "%s:%s map requires O_RDONLY access mode",
			       DICT_TYPE_PCRE, mapname));

    /*
     * Open the configuration file.
     */
    if ((map_fp = vstream_fopen(mapname, O_RDONLY, 0)) == 0)
	return (dict_surrogate(DICT_TYPE_PCRE, mapname, open_flags, dict_flags,
			       "open %s: %m", mapname));
    if (fstat(vstream_fileno(map_fp), &st) < 0)
	msg_fatal("fstat %s: %m", mapname);

    line_buffer = vstring_alloc(100);

    dict_pcre = (DICT_PCRE *) dict_alloc(DICT_TYPE_PCRE, mapname,
					 sizeof(*dict_pcre));
    dict_pcre->dict.lookup = dict_pcre_lookup;
    dict_pcre->dict.close = dict_pcre_close;
    dict_pcre->dict.flags = dict_flags | DICT_FLAG_PATTERN;
    if (dict_flags & DICT_FLAG_FOLD_MUL)
	dict_pcre->dict.fold_buf = vstring_alloc(10);
    dict_pcre->head = 0;
    dict_pcre->expansion_buf = 0;

    if (dict_pcre_init == 0) {
	pcre_malloc = (void *(*) (size_t)) mymalloc;
	pcre_free = (void (*) (void *)) myfree;
	dict_pcre_init = 1;
    }
    dict_pcre->dict.owner.uid = st.st_uid;
    dict_pcre->dict.owner.status = (st.st_uid != 0);

    /*
     * Parse the pcre table.
     */
    while (readlline(line_buffer, map_fp, &lineno)) {
	p = vstring_str(line_buffer);
	trimblanks(p, 0)[0] = 0;		/* Trim space at end */
	if (*p == 0)
	    continue;
	rule = dict_pcre_parse_rule(mapname, lineno, p, nesting, dict_flags);
	if (rule == 0)
	    continue;
	if (rule->op == DICT_PCRE_OP_IF) {
	    nesting++;
	} else if (rule->op == DICT_PCRE_OP_ENDIF) {
	    nesting--;
	}
	if (last_rule == 0)
	    dict_pcre->head = rule;
	else
	    last_rule->next = rule;
	last_rule = rule;
    }

    if (nesting)
	msg_warn("pcre map %s, line %d: more IFs than ENDIFs",
		 mapname, lineno);

    vstring_free(line_buffer);
    vstream_fclose(map_fp);

    return (DICT_DEBUG (&dict_pcre->dict));
}
Beispiel #6
0
static int eval_command_status(int command_status, char *service,
			          DELIVER_REQUEST *request, PIPE_ATTR *attr,
			               DSN_BUF *why)
{
    RECIPIENT *rcpt;
    int     status;
    int     result = 0;
    int     n;
    char   *saved_text;

    /*
     * Depending on the result, bounce or defer the message, and mark the
     * recipient as done where appropriate.
     */
    switch (command_status) {
    case PIPE_STAT_OK:
	/* Save the command output before dsb_update() clobbers it. */
	vstring_truncate(why->reason, trimblanks(STR(why->reason),
			      VSTRING_LEN(why->reason)) - STR(why->reason));
	if (VSTRING_LEN(why->reason) > 0) {
	    VSTRING_TERMINATE(why->reason);
	    saved_text =
		vstring_export(vstring_sprintf(
				    vstring_alloc(VSTRING_LEN(why->reason)),
					    " (%.100s)", STR(why->reason)));
	} else
	    saved_text = mystrdup("");		/* uses shared R/O storage */
	dsb_update(why, "2.0.0", (attr->flags & PIPE_OPT_FINAL_DELIVERY) ?
		   "delivered" : "relayed", DSB_SKIP_RMTA, DSB_SKIP_REPLY,
		   "delivered via %s service%s", service, saved_text);
	myfree(saved_text);
	(void) DSN_FROM_DSN_BUF(why);
	for (n = 0; n < request->rcpt_list.len; n++) {
	    rcpt = request->rcpt_list.info + n;
	    status = sent(DEL_REQ_TRACE_FLAGS(request->flags),
			  request->queue_id, &request->msg_stats, rcpt,
			  service, &why->dsn);
	    if (status == 0 && (request->flags & DEL_REQ_FLAG_SUCCESS))
		deliver_completed(request->fp, rcpt->offset);
	    result |= status;
	}
	break;
    case PIPE_STAT_BOUNCE:
    case PIPE_STAT_DEFER:
	(void) DSN_FROM_DSN_BUF(why);
	for (n = 0; n < request->rcpt_list.len; n++) {
	    rcpt = request->rcpt_list.info + n;
	    /* XXX Maybe encapsulate this with ndr_append(). */
	    status = (STR(why->status)[0] != '4' ?
		      bounce_append : defer_append)
		(DEL_REQ_TRACE_FLAGS(request->flags),
		 request->queue_id,
		 &request->msg_stats, rcpt,
		 service, &why->dsn);
	    if (status == 0)
		deliver_completed(request->fp, rcpt->offset);
	    result |= status;
	}
	break;
    case PIPE_STAT_CORRUPT:
	/* XXX DSN should we send something? */
	result |= DEL_STAT_DEFER;
	break;
    default:
	msg_panic("eval_command_status: bad status %d", command_status);
	/* NOTREACHED */
    }

    return (result);
}
Beispiel #7
0
static void postmap(char *map_type, char *path_name, int postmap_flags,
		            int open_flags, int dict_flags)
{
    VSTREAM *NOCLOBBER source_fp;
    VSTRING *line_buffer;
    MKMAP  *mkmap;
    int     lineno;
    int     last_line;
    char   *key;
    char   *value;
    struct stat st;
    mode_t  saved_mask;

    /*
     * Initialize.
     */
    line_buffer = vstring_alloc(100);
    if ((open_flags & O_TRUNC) == 0) {
	/* Incremental mode. */
	source_fp = VSTREAM_IN;
	vstream_control(source_fp, CA_VSTREAM_CTL_PATH("stdin"), CA_VSTREAM_CTL_END);
    } else {
	/* Create database. */
	if (strcmp(map_type, DICT_TYPE_PROXY) == 0)
	    msg_fatal("can't create maps via the proxy service");
	dict_flags |= DICT_FLAG_BULK_UPDATE;
	if ((source_fp = vstream_fopen(path_name, O_RDONLY, 0)) == 0)
	    msg_fatal("open %s: %m", path_name);
    }
    if (fstat(vstream_fileno(source_fp), &st) < 0)
	msg_fatal("fstat %s: %m", path_name);

    /*
     * Turn off group/other read permissions as indicated in the source file.
     */
    if ((postmap_flags & POSTMAP_FLAG_SAVE_PERM) && S_ISREG(st.st_mode))
	saved_mask = umask(022 | (~st.st_mode & 077));

    /*
     * If running as root, run as the owner of the source file, so that the
     * result shows proper ownership, and so that a bug in postmap does not
     * allow privilege escalation.
     */
    if ((postmap_flags & POSTMAP_FLAG_AS_OWNER) && getuid() == 0
	&& (st.st_uid != geteuid() || st.st_gid != getegid()))
	set_eugid(st.st_uid, st.st_gid);

    /*
     * Open the database, optionally create it when it does not exist,
     * optionally truncate it when it does exist, and lock out any
     * spectators.
     */
    mkmap = mkmap_open(map_type, path_name, open_flags, dict_flags);

    /*
     * And restore the umask, in case it matters.
     */
    if ((postmap_flags & POSTMAP_FLAG_SAVE_PERM) && S_ISREG(st.st_mode))
	umask(saved_mask);

    /*
     * Trap "exceptions" so that we can restart a bulk-mode update after a
     * recoverable error.
     */
    for (;;) {
	if (dict_isjmp(mkmap->dict) != 0
	    && dict_setjmp(mkmap->dict) != 0
	    && vstream_fseek(source_fp, SEEK_SET, 0) < 0)
	    msg_fatal("seek %s: %m", VSTREAM_PATH(source_fp));

	/*
	 * Add records to the database.
	 */
	last_line = 0;
	while (readllines(line_buffer, source_fp, &last_line, &lineno)) {

	    /*
	     * First some UTF-8 checks sans casefolding.
	     */
	    if ((mkmap->dict->flags & DICT_FLAG_UTF8_ACTIVE)
		&& !allascii(STR(line_buffer))
		&& !valid_utf8_string(STR(line_buffer), LEN(line_buffer))) {
		msg_warn("%s, line %d: non-UTF-8 input \"%s\""
			 " -- ignoring this line",
			 VSTREAM_PATH(source_fp), lineno, STR(line_buffer));
		continue;
	    }

	    /*
	     * Split on the first whitespace character, then trim leading and
	     * trailing whitespace from key and value.
	     */
	    key = STR(line_buffer);
	    value = key + strcspn(key, CHARS_SPACE);
	    if (*value)
		*value++ = 0;
	    while (ISSPACE(*value))
		value++;
	    trimblanks(key, 0)[0] = 0;
	    trimblanks(value, 0)[0] = 0;

	    /*
	     * Enforce the "key whitespace value" format. Disallow missing
	     * keys or missing values.
	     */
	    if (*key == 0 || *value == 0) {
		msg_warn("%s, line %d: expected format: key whitespace value",
			 VSTREAM_PATH(source_fp), lineno);
		continue;
	    }
	    if (key[strlen(key) - 1] == ':')
		msg_warn("%s, line %d: record is in \"key: value\" format; is this an alias file?",
			 VSTREAM_PATH(source_fp), lineno);

	    /*
	     * Store the value under a case-insensitive key.
	     */
	    mkmap_append(mkmap, key, value);
	    if (mkmap->dict->error)
		msg_fatal("table %s:%s: write error: %m",
			  mkmap->dict->type, mkmap->dict->name);
	}
	break;
    }

    /*
     * Close the mapping database, and release the lock.
     */
    mkmap_close(mkmap);

    /*
     * Cleanup. We're about to terminate, but it is a good sanity check.
     */
    vstring_free(line_buffer);
    if (source_fp != VSTREAM_IN)
	vstream_fclose(source_fp);
}
Beispiel #8
0
void    edit_parameters(int mode, int argc, char **argv)
{
    char   *path;
    EDIT_FILE *ep;
    VSTREAM *src;
    VSTREAM *dst;
    VSTRING *buf = vstring_alloc(100);
    VSTRING *key = vstring_alloc(10);
    char   *cp;
    char   *edit_key;
    char   *edit_val;
    HTABLE *table;
    struct cvalue {
	char   *value;
	int     found;
    };
    struct cvalue *cvalue;
    HTABLE_INFO **ht_info;
    HTABLE_INFO **ht;
    int     interesting;
    const char *err;

    /*
     * Store command-line parameters for quick lookup.
     */
    table = htable_create(argc);
    while ((cp = *argv++) != 0) {
	if (strchr(cp, '\n') != 0)
	    msg_fatal("-e or -# accepts no multi-line input");
	while (ISSPACE(*cp))
	    cp++;
	if (*cp == '#')
	    msg_fatal("-e or -# accepts no comment input");
	if (mode & EDIT_MAIN) {
	    if ((err = split_nameval(cp, &edit_key, &edit_val)) != 0)
		msg_fatal("%s: \"%s\"", err, cp);
	} else if (mode & COMMENT_OUT) {
	    if (*cp == 0)
		msg_fatal("-# requires non-blank parameter names");
	    if (strchr(cp, '=') != 0)
		msg_fatal("-# requires parameter names only");
	    edit_key = mystrdup(cp);
	    trimblanks(edit_key, 0);
	    edit_val = 0;
	} else {
	    msg_panic("edit_parameters: unknown mode %d", mode);
	}
	cvalue = (struct cvalue *) mymalloc(sizeof(*cvalue));
	cvalue->value = edit_val;
	cvalue->found = 0;
	htable_enter(table, edit_key, (char *) cvalue);
    }

    /*
     * Open a temp file for the result. This uses a deterministic name so we
     * don't leave behind thrash with random names.
     */
    set_config_dir();
    path = concatenate(var_config_dir, "/", MAIN_CONF_FILE, (char *) 0);
    if ((ep = edit_file_open(path, O_CREAT | O_WRONLY, 0644)) == 0)
	msg_fatal("open %s%s: %m", path, EDIT_FILE_SUFFIX);
    dst = ep->tmp_fp;

    /*
     * Open the original file for input.
     */
    if ((src = vstream_fopen(path, O_RDONLY, 0)) == 0) {
	/* OK to delete, since we control the temp file name exclusively. */
	(void) unlink(ep->tmp_path);
	msg_fatal("open %s for reading: %m", path);
    }

    /*
     * Copy original file to temp file, while replacing parameters on the
     * fly. Issue warnings for names found multiple times.
     */
#define STR(x) vstring_str(x)

    interesting = 0;
    while (vstring_get(buf, src) != VSTREAM_EOF) {
	for (cp = STR(buf); ISSPACE(*cp) /* including newline */ ; cp++)
	     /* void */ ;
	/* Copy comment, all-whitespace, or empty line. */
	if (*cp == '#' || *cp == 0) {
	    vstream_fputs(STR(buf), dst);
	}
	/* Copy, skip or replace continued text. */
	else if (cp > STR(buf)) {
	    if (interesting == 0)
		vstream_fputs(STR(buf), dst);
	    else if (mode & COMMENT_OUT)
		vstream_fprintf(dst, "#%s", STR(buf));
	}
	/* Copy or replace start of logical line. */
	else {
	    vstring_strncpy(key, cp, strcspn(cp, " \t\r\n="));
	    cvalue = (struct cvalue *) htable_find(table, STR(key));
	    if ((interesting = !!cvalue) != 0) {
		if (cvalue->found++ == 1)
		    msg_warn("%s: multiple entries for \"%s\"", path, STR(key));
		if (mode & EDIT_MAIN)
		    vstream_fprintf(dst, "%s = %s\n", STR(key), cvalue->value);
		else if (mode & COMMENT_OUT)
		    vstream_fprintf(dst, "#%s", cp);
		else
		    msg_panic("edit_parameters: unknown mode %d", mode);
	    } else {
		vstream_fputs(STR(buf), dst);
	    }
	}
    }

    /*
     * Generate new entries for parameters that were not found.
     */
    if (mode & EDIT_MAIN) {
	for (ht_info = ht = htable_list(table); *ht; ht++) {
	    cvalue = (struct cvalue *) ht[0]->value;
	    if (cvalue->found == 0)
		vstream_fprintf(dst, "%s = %s\n", ht[0]->key, cvalue->value);
	}
	myfree((char *) ht_info);
    }

    /*
     * When all is well, rename the temp file to the original one.
     */
    if (vstream_fclose(src))
	msg_fatal("read %s: %m", path);
    if (edit_file_close(ep) != 0)
	msg_fatal("close %s%s: %m", path, EDIT_FILE_SUFFIX);

    /*
     * Cleanup.
     */
    myfree(path);
    vstring_free(buf);
    vstring_free(key);
    htable_free(table, myfree);
}
Beispiel #9
0
static void postmap(char *map_type, char *path_name, int postmap_flags,
		            int open_flags, int dict_flags)
{
    VSTREAM *source_fp;
    VSTRING *line_buffer;
    MKMAP  *mkmap;
    int     lineno;
    char   *key;
    char   *value;
    struct stat st;
    mode_t  saved_mask;

    /*
     * Initialize.
     */
    line_buffer = vstring_alloc(100);
    if ((open_flags & O_TRUNC) == 0) {
	source_fp = VSTREAM_IN;
	vstream_control(source_fp, VSTREAM_CTL_PATH, "stdin", VSTREAM_CTL_END);
    } else if (strcmp(map_type, DICT_TYPE_PROXY) == 0) {
	msg_fatal("can't create maps via the proxy service");
    } else if ((source_fp = vstream_fopen(path_name, O_RDONLY, 0)) == 0) {
	msg_fatal("open %s: %m", path_name);
    }
    if (fstat(vstream_fileno(source_fp), &st) < 0)
	msg_fatal("fstat %s: %m", path_name);

    /*
     * Turn off group/other read permissions as indicated in the source file.
     */
    if ((postmap_flags & POSTMAP_FLAG_SAVE_PERM) && S_ISREG(st.st_mode))
	saved_mask = umask(022 | (~st.st_mode & 077));

    /*
     * If running as root, run as the owner of the source file, so that the
     * result shows proper ownership, and so that a bug in postmap does not
     * allow privilege escalation.
     */
    if ((postmap_flags & POSTMAP_FLAG_AS_OWNER) && getuid() == 0
	&& (st.st_uid != geteuid() || st.st_gid != getegid()))
	set_eugid(st.st_uid, st.st_gid);

    /*
     * Open the database, optionally create it when it does not exist,
     * optionally truncate it when it does exist, and lock out any
     * spectators.
     */
    mkmap = mkmap_open(map_type, path_name, open_flags, dict_flags);

    /*
     * And restore the umask, in case it matters.
     */
    if ((postmap_flags & POSTMAP_FLAG_SAVE_PERM) && S_ISREG(st.st_mode))
	umask(saved_mask);

    /*
     * Add records to the database.
     */
    lineno = 0;
    while (readlline(line_buffer, source_fp, &lineno)) {

	/*
	 * Split on the first whitespace character, then trim leading and
	 * trailing whitespace from key and value.
	 */
	key = STR(line_buffer);
	value = key + strcspn(key, " \t\r\n");
	if (*value)
	    *value++ = 0;
	while (ISSPACE(*value))
	    value++;
	trimblanks(key, 0)[0] = 0;
	trimblanks(value, 0)[0] = 0;

	/*
	 * Enforce the "key whitespace value" format. Disallow missing keys
	 * or missing values.
	 */
	if (*key == 0 || *value == 0) {
	    msg_warn("%s, line %d: expected format: key whitespace value",
		     VSTREAM_PATH(source_fp), lineno);
	    continue;
	}
	if (key[strlen(key) - 1] == ':')
	    msg_warn("%s, line %d: record is in \"key: value\" format; is this an alias file?",
		     VSTREAM_PATH(source_fp), lineno);

	/*
	 * Store the value under a case-insensitive key.
	 */
	mkmap_append(mkmap, key, value);
	if (mkmap->dict->error)
	    msg_fatal("table %s:%s: write error: %m",
		      mkmap->dict->type, mkmap->dict->name);
    }

    /*
     * Close the mapping database, and release the lock.
     */
    mkmap_close(mkmap);

    /*
     * Cleanup. We're about to terminate, but it is a good sanity check.
     */
    vstring_free(line_buffer);
    if (source_fp != VSTREAM_IN)
	vstream_fclose(source_fp);
}
Beispiel #10
0
void    pcf_edit_master(int mode, int argc, char **argv)
{
    const char *myname = "pcf_edit_master";
    char   *path;
    EDIT_FILE *ep;
    VSTREAM *src;
    VSTREAM *dst;
    VSTRING *line_buf = vstring_alloc(100);
    VSTRING *parse_buf = vstring_alloc(100);
    int     lineno;
    PCF_MASTER_ENT *new_entry;
    VSTRING *full_entry_buf = vstring_alloc(100);
    char   *cp;
    char   *pattern;
    int     service_name_type_matched;
    const char *err;
    PCF_MASTER_EDIT_REQ *edit_reqs;
    PCF_MASTER_EDIT_REQ *req;
    int     num_reqs = argc;
    const char *edit_opts = "-Me, -Fe, -Pe, -X, or -#";
    char   *service_name;
    char   *service_type;

    /*
     * Sanity check.
     */
    if (num_reqs <= 0)
	msg_panic("%s: empty argument list", myname);

    /*
     * Preprocessing: split pattern=value, then split the pattern components.
     */
    edit_reqs = (PCF_MASTER_EDIT_REQ *) mymalloc(sizeof(*edit_reqs) * num_reqs);
    for (req = edit_reqs; *argv != 0; req++, argv++) {
	req->match_count = 0;
	req->raw_text = *argv;
	cp = req->parsed_text = mystrdup(req->raw_text);
	if (strchr(cp, '\n') != 0)
	    msg_fatal("%s accept no multi-line input", edit_opts);
	while (ISSPACE(*cp))
	    cp++;
	if (*cp == '#')
	    msg_fatal("%s accept no comment input", edit_opts);
	/* Separate the pattern from the value. */
	if (mode & PCF_EDIT_CONF) {
	    if ((err = split_nameval(cp, &pattern, &req->edit_value)) != 0)
		msg_fatal("%s: \"%s\"", err, req->raw_text);
	    if ((mode & PCF_MASTER_PARAM)
	    && req->edit_value[strcspn(req->edit_value, PCF_MASTER_BLANKS)])
		msg_fatal("whitespace in parameter value: \"%s\"",
			  req->raw_text);
	} else if (mode & (PCF_COMMENT_OUT | PCF_EDIT_EXCL)) {
	    if (strchr(cp, '=') != 0)
		msg_fatal("-X or -# requires names without value");
	    pattern = cp;
	    trimblanks(pattern, 0);
	    req->edit_value = 0;
	} else {
	    msg_panic("%s: unknown mode %d", myname, mode);
	}

#define PCF_MASTER_MASK (PCF_MASTER_ENTRY | PCF_MASTER_FLD | PCF_MASTER_PARAM)

	/*
	 * Split name/type or name/type/whatever pattern into components.
	 */
	switch (mode & PCF_MASTER_MASK) {
	case PCF_MASTER_ENTRY:
	    if ((req->service_pattern =
		 pcf_parse_service_pattern(pattern, 2, 2)) == 0)
		msg_fatal("-Me, -MX or -M# requires service_name/type");
	    break;
	case PCF_MASTER_FLD:
	    if ((req->service_pattern =
		 pcf_parse_service_pattern(pattern, 3, 3)) == 0)
		msg_fatal("-Fe or -FX requires service_name/type/field_name");
	    req->field_number =
		pcf_parse_field_pattern(req->service_pattern->argv[2]);
	    if (pcf_is_magic_field_pattern(req->field_number))
		msg_fatal("-Fe does not accept wild-card field name");
	    if ((mode & PCF_EDIT_CONF)
		&& req->field_number < PCF_MASTER_FLD_CMD
	    && req->edit_value[strcspn(req->edit_value, PCF_MASTER_BLANKS)])
		msg_fatal("-Fe does not accept whitespace in non-command field");
	    break;
	case PCF_MASTER_PARAM:
	    if ((req->service_pattern =
		 pcf_parse_service_pattern(pattern, 3, 3)) == 0)
		msg_fatal("-Pe or -PX requires service_name/type/parameter");
	    req->param_pattern = req->service_pattern->argv[2];
	    if (PCF_IS_MAGIC_PARAM_PATTERN(req->param_pattern))
		msg_fatal("-Pe does not accept wild-card parameter name");
	    if ((mode & PCF_EDIT_CONF)
	    && req->edit_value[strcspn(req->edit_value, PCF_MASTER_BLANKS)])
		msg_fatal("-Pe does not accept whitespace in parameter value");
	    break;
	default:
	    msg_panic("%s: unknown edit mode %d", myname, mode);
	}
    }

    /*
     * Open a temp file for the result. This uses a deterministic name so we
     * don't leave behind thrash with random names.
     */
    pcf_set_config_dir();
    path = concatenate(var_config_dir, "/", MASTER_CONF_FILE, (char *) 0);
    if ((ep = edit_file_open(path, O_CREAT | O_WRONLY, 0644)) == 0)
	msg_fatal("open %s%s: %m", path, EDIT_FILE_SUFFIX);
    dst = ep->tmp_fp;

    /*
     * Open the original file for input.
     */
    if ((src = vstream_fopen(path, O_RDONLY, 0)) == 0) {
	/* OK to delete, since we control the temp file name exclusively. */
	(void) unlink(ep->tmp_path);
	msg_fatal("open %s for reading: %m", path);
    }

    /*
     * Copy original file to temp file, while replacing service entries on
     * the fly.
     */
    service_name_type_matched = 0;
    new_entry = 0;
    lineno = 0;
    while ((cp = pcf_next_cf_line(parse_buf, src, dst, &lineno)) != 0) {
	vstring_strcpy(line_buf, STR(parse_buf));

	/*
	 * Copy, skip or replace continued text.
	 */
	if (cp > STR(parse_buf)) {
	    if (service_name_type_matched == 0)
		vstream_fputs(STR(line_buf), dst);
	    else if (mode & PCF_COMMENT_OUT)
		vstream_fprintf(dst, "#%s", STR(line_buf));
	}

	/*
	 * Copy or replace (start of) logical line.
	 */
	else {
	    service_name_type_matched = 0;

	    /*
	     * Parse out the service name and type.
	     */
	    if ((service_name = mystrtok(&cp, PCF_MASTER_BLANKS)) == 0
		|| (service_type = mystrtok(&cp, PCF_MASTER_BLANKS)) == 0)
		msg_fatal("file %s: line %d: specify service name and type "
			  "on the same line", path, lineno);
	    if (strchr(service_name, '='))
		msg_fatal("file %s: line %d: service name syntax \"%s\" is "
			  "unsupported with %s", path, lineno, service_name,
			  edit_opts);
	    if (service_type[strcspn(service_type, "=/")] != 0)
		msg_fatal("file %s: line %d: "
			"service type syntax \"%s\" is unsupported with %s",
			  path, lineno, service_type, edit_opts);

	    /*
	     * Match each service pattern.
	     */
	    for (req = edit_reqs; req < edit_reqs + num_reqs; req++) {
		if (PCF_MATCH_SERVICE_PATTERN(req->service_pattern,
					      service_name,
					      service_type)) {
		    service_name_type_matched = 1;	/* Sticky flag */
		    req->match_count += 1;

		    /*
		     * Generate replacement master.cf entries.
		     */
		    if ((mode & PCF_EDIT_CONF)
			|| ((mode & PCF_MASTER_PARAM) && (mode & PCF_EDIT_EXCL))) {
			switch (mode & PCF_MASTER_MASK) {

			    /*
			     * Replace master.cf entry field or parameter
			     * value.
			     */
			case PCF_MASTER_FLD:
			case PCF_MASTER_PARAM:
			    if (new_entry == 0) {
				/* Gobble up any continuation lines. */
				pcf_gobble_cf_line(full_entry_buf, line_buf,
						   src, dst, &lineno);
				new_entry = (PCF_MASTER_ENT *)
				    mymalloc(sizeof(*new_entry));
				if ((err = pcf_parse_master_entry(new_entry,
						 STR(full_entry_buf))) != 0)
				    msg_fatal("file %s: line %d: %s",
					      path, lineno, err);
			    }
			    if (mode & PCF_MASTER_FLD) {
				pcf_edit_master_field(new_entry,
						      req->field_number,
						      req->edit_value);
			    } else {
				pcf_edit_master_param(new_entry, mode,
						      req->param_pattern,
						      req->edit_value);
			    }
			    break;

			    /*
			     * Replace entire master.cf entry.
			     */
			case PCF_MASTER_ENTRY:
			    if (new_entry != 0)
				pcf_free_master_entry(new_entry);
			    new_entry = (PCF_MASTER_ENT *)
				mymalloc(sizeof(*new_entry));
			    if ((err = pcf_parse_master_entry(new_entry,
						     req->edit_value)) != 0)
				msg_fatal("%s: \"%s\"", err, req->raw_text);
			    break;
			default:
			    msg_panic("%s: unknown edit mode %d", myname, mode);
			}
		    }
		}
	    }

	    /*
	     * Pass through or replace the current input line.
	     */
	    if (new_entry) {
		pcf_print_master_entry(dst, PCF_FOLD_LINE, new_entry);
		pcf_free_master_entry(new_entry);
		new_entry = 0;
	    } else if (service_name_type_matched == 0) {
		vstream_fputs(STR(line_buf), dst);
	    } else if (mode & PCF_COMMENT_OUT) {
		vstream_fprintf(dst, "#%s", STR(line_buf));
	    }
	}
    }

    /*
     * Postprocessing: when editing entire service entries, generate new
     * entries for services not found. Otherwise (editing fields or
     * parameters), "service not found" is a fatal error.
     */
    for (req = edit_reqs; req < edit_reqs + num_reqs; req++) {
	if (req->match_count == 0) {
	    if ((mode & PCF_MASTER_ENTRY) && (mode & PCF_EDIT_CONF)) {
		new_entry = (PCF_MASTER_ENT *) mymalloc(sizeof(*new_entry));
		if ((err = pcf_parse_master_entry(new_entry, req->edit_value)) != 0)
		    msg_fatal("%s: \"%s\"", err, req->raw_text);
		pcf_print_master_entry(dst, PCF_FOLD_LINE, new_entry);
		pcf_free_master_entry(new_entry);
	    } else if ((mode & PCF_MASTER_ENTRY) == 0) {
		msg_warn("unmatched service_name/type: \"%s\"", req->raw_text);
	    }
	}
    }

    /*
     * When all is well, rename the temp file to the original one.
     */
    if (vstream_fclose(src))
	msg_fatal("read %s: %m", path);
    if (edit_file_close(ep) != 0)
	msg_fatal("close %s%s: %m", path, EDIT_FILE_SUFFIX);

    /*
     * Cleanup.
     */
    myfree(path);
    vstring_free(line_buf);
    vstring_free(parse_buf);
    vstring_free(full_entry_buf);
    for (req = edit_reqs; req < edit_reqs + num_reqs; req++) {
	argv_free(req->service_pattern);
	myfree(req->parsed_text);
    }
    myfree((char *) edit_reqs);
}
Beispiel #11
0
static DICT_CIDR_ENTRY *dict_cidr_parse_rule(const char *mapname, int lineno,
					             char *p)
{
    DICT_CIDR_ENTRY *rule;
    char   *key;
    char   *value;
    char   *mask;
    int     mask_shift;
    unsigned long net_bits;
    unsigned long mask_bits;
    struct in_addr net_addr;

    /*
     * Split the rule into key and value. We already eliminated leading
     * whitespace, comments, empty lines or lines with whitespace only. This
     * means a null key can't happen but we will handle this anyway.
     */
    key = p;
    while (*p && !ISSPACE(*p))			/* Skip over key */
	p++;
    if (*p)					/* Terminate key */
	*p++ = 0;
    while (*p && ISSPACE(*p))			/* Skip whitespace */
	p++;
    value = p;
    trimblanks(value, 0)[0] = 0;		/* Trim trailing blanks */
    if (*key == 0) {
	msg_warn("cidr map %s, line %d: no address pattern: skipping this rule",
		 mapname, lineno);
	return (0);
    }
    if (*value == 0) {
	msg_warn("cidr map %s, line %d: no lookup result: skipping this rule",
		 mapname, lineno);
	return (0);
    }

    /*
     * Parse the key into network and mask, and destroy the key. Treat a bare
     * network address as /32.
     * 
     * We need explicit code for /0. The result of << is undefined when the
     * shift is greater or equal to the number of bits in the shifted
     * operand.
     */
    if ((mask = split_at(key, '/')) != 0) {
	if (!alldig(mask) || (mask_shift = atoi(mask)) > BITS_PER_ADDR
	    || (net_bits = inet_addr(key)) == INADDR_NONE) {
	    msg_warn("cidr map %s, line %d: bad net/mask pattern: \"%s/%s\": "
		     "skipping this rule", mapname, lineno, key, mask);
	    return (0);
	}
	mask_bits = mask_shift > 0 ?
	    htonl((0xffffffff) << (BITS_PER_ADDR - mask_shift)) : 0;
	if (net_bits & ~mask_bits) {
	    net_addr.s_addr = (net_bits & mask_bits);
	    msg_warn("cidr map %s, line %d: net/mask pattern \"%s/%s\" with "
		     "non-null host portion: skipping this rule",
		     mapname, lineno, key, mask);
	    msg_warn("specify \"%s/%d\" if this is really what you want",
		     inet_ntoa(net_addr), mask_shift);
	    return (0);
	}
    } else {
	if ((net_bits = inet_addr(key)) == INADDR_NONE) {
	    msg_warn("cidr map %s, line %d: bad address pattern: \"%s\": "
		     "skipping this rule", mapname, lineno, key);
	    return (0);
	}
	mask_shift = 32;
	mask_bits = htonl(0xffffffff);
    }

    /*
     * Bundle up the result.
     */
    rule = (DICT_CIDR_ENTRY *) mymalloc(sizeof(DICT_CIDR_ENTRY));
    rule->net_bits = net_bits;
    rule->mask_bits = mask_bits;
    rule->value = mystrdup(value);
    rule->next = 0;

    if (msg_verbose)
	msg_info("dict_cidr_open: %s: %lu/%d %s",
		 mapname, rule->net_bits, mask_shift, rule->value);

    return (rule);
}
Beispiel #12
0
static DICT_CIDR_ENTRY *dict_cidr_parse_rule(char *p, int lineno, int nesting,
					             VSTRING *why)
{
    DICT_CIDR_ENTRY *rule;
    char   *pattern;
    char   *value;
    CIDR_MATCH cidr_info;
    MAI_HOSTADDR_STR hostaddr;
    int     match = 1;

    /*
     * IF must be followed by a pattern.
     */
    if (strncasecmp(p, "IF", 2) == 0 && !ISALNUM(p[2])) {
	p += 2;
	for (;;) {
	    if (*p == '!')
		match = !match;
	    else if (!ISSPACE(*p))
		break;
	    p++;
	}
	if (*p == 0) {
	    vstring_sprintf(why, "no address pattern");
	    return (0);
	}
	trimblanks(p, 0)[0] = 0;		/* Trim trailing blanks */
	if (cidr_match_parse_if(&cidr_info, p, match, why) != 0)
	    return (0);
	value = "";
    }

    /*
     * ENDIF must not be followed by other text.
     */
    else if (strncasecmp(p, "ENDIF", 5) == 0 && !ISALNUM(p[5])) {
	p += 5;
	while (*p && ISSPACE(*p))		/* Skip whitespace */
	    p++;
	if (*p != 0) {
	    vstring_sprintf(why, "garbage after ENDIF");
	    return (0);
	}
	if (nesting == 0) {
	    vstring_sprintf(why, "ENDIF without IF");
	    return (0);
	}
	cidr_match_endif(&cidr_info);
	value = "";
    }

    /*
     * An address pattern.
     */
    else {

	/*
	 * Process negation operators.
	 */
	for (;;) {
	    if (*p == '!')
		match = !match;
	    else if (!ISSPACE(*p))
		break;
	    p++;
	}

	/*
	 * Split the rule into key and value. We already eliminated leading
	 * whitespace, comments, empty lines or lines with whitespace only.
	 * This means a null key can't happen but we will handle this anyway.
	 */
	pattern = p;
	while (*p && !ISSPACE(*p))		/* Skip over key */
	    p++;
	if (*p)					/* Terminate key */
	    *p++ = 0;
	while (*p && ISSPACE(*p))		/* Skip whitespace */
	    p++;
	value = p;
	trimblanks(value, 0)[0] = 0;		/* Trim trailing blanks */
	if (*pattern == 0) {
	    vstring_sprintf(why, "no address pattern");
	    return (0);
	}

	/*
	 * Parse the pattern, destroying it in the process.
	 */
	if (cidr_match_parse(&cidr_info, pattern, match, why) != 0)
	    return (0);

	if (*value == 0) {
	    vstring_sprintf(why, "no lookup result");
	    return (0);
	}
    }

    /*
     * Bundle up the result.
     */
    rule = (DICT_CIDR_ENTRY *) mymalloc(sizeof(DICT_CIDR_ENTRY));
    rule->cidr_info = cidr_info;
    rule->value = mystrdup(value);
    rule->lineno = lineno;

    if (msg_verbose) {
	if (inet_ntop(cidr_info.addr_family, cidr_info.net_bytes,
		      hostaddr.buf, sizeof(hostaddr.buf)) == 0)
	    msg_fatal("inet_ntop: %m");
	msg_info("dict_cidr_open: add %s/%d %s",
		 hostaddr.buf, cidr_info.mask_shift, rule->value);
    }
    return (rule);
}