static int verify_parse_entry(char *buf, int *status, long *probed, long *updated, char **text) { char *probed_text; char *updated_text; if ((probed_text = split_at(buf, ':')) != 0 && (updated_text = split_at(probed_text, ':')) != 0 && (*text = split_at(updated_text, ':')) != 0 && alldig(buf) && alldig(probed_text) && alldig(updated_text)) { *probed = atol(probed_text); *updated = atol(updated_text); *status = atoi(buf); /* * Coverity 200604: the code incorrectly tested (probed || updated), * so that the sanity check never detected all-zero time stamps. Such * records are never written. If we read a record with all-zero time * stamps, then something is badly broken. */ if ((*status == DEL_RCPT_STAT_OK || *status == DEL_RCPT_STAT_DEFER || *status == DEL_RCPT_STAT_BOUNCE || *status == DEL_RCPT_STAT_TODO) && (*probed || *updated)) return (0); } msg_warn("bad address verify table entry: %.100s", buf); return (-1); }
int main(){ char * num1 ; char * num2 ; num1 = readInput(1); num2 = readInput(2); printf("\nConverted to int:%d",convert_to_int(num1)); printf("\nConverted to char:%s",convert_to_char(convert_to_int(num1))); printf("\nMax:%d",max(num1,num2,10)); printf("\nSplit at 0-3:%s",split_at(num1,0,3)); printf("\nSplit at 3-5:%s",split_at(num1,3,strlen(num1))); printf("\nKaratsuba:%d",karatSuba(num1,num2)); return 0 ; }
static int find_transport_entry(TRANSPORT_INFO *tp, const char *key, const char *rcpt_domain, int flags, VSTRING *channel, VSTRING *nexthop) { char *saved_value; const char *host; const char *value; #define FOUND 1 #define NOTFOUND 0 /* * Look up an entry with extreme prejudice. * * XXX Should report lookup failure status to caller instead of aborting. */ if ((value = maps_find(tp->transport_path, key, flags)) == 0) return (NOTFOUND); /* * It would be great if we could specify a recipient address in the * lookup result. Unfortunately, we cannot simply run the result through * a parser that recognizes "transport:user@domain" because the lookup * result can have arbitrary content (especially in the case of the error * mailer). */ else { saved_value = mystrdup(value); host = split_at(saved_value, ':'); update_entry(saved_value, host ? host : "", rcpt_domain, channel, nexthop); myfree(saved_value); return (FOUND); } }
static void banners_option(char *value, struct request_info *request) { char path[MAXPATHLEN]; char ibuf[BUFSIZ]; char obuf[2 * BUFSIZ]; struct stat st; int ch; FILE *fp; (void)snprintf(path, sizeof path, "%s/%s", value, eval_daemon(request)); if ((fp = fopen(path, "r")) != 0) { while ((ch = fgetc(fp)) == 0) write(request->fd, "", 1); ungetc(ch, fp); while (fgets(ibuf, sizeof(ibuf) - 2, fp)) { if (split_at(ibuf, '\n')) strcat(ibuf, "\r\n"); /* XXX strcat is safe */ percent_x(obuf, sizeof(obuf), ibuf, request); write(request->fd, obuf, strlen(obuf)); } fclose(fp); } else if (stat(value, &st) < 0) { tcpd_warn("%s: %m", value); } }
int smtp_sasl_passwd_lookup(SMTP_SESSION *session) { const char *myname = "smtp_sasl_passwd_lookup"; SMTP_STATE *state = session->state; const char *value; char *passwd; /* * Sanity check. */ if (smtp_sasl_passwd_map == 0) msg_panic("%s: passwd map not initialized", myname); /* * Look up the per-server password information. Try the hostname first, * then try the destination. * * XXX Instead of using nexthop (the intended destination) we use dest * (either the intended destination, or a fall-back destination). * * XXX SASL authentication currently depends on the host/domain but not on * the TCP port. If the port is not :25, we should append it to the table * lookup key. Code for this was briefly introduced into 2.2 snapshots, * but didn't canonicalize the TCP port, and did not append the port to * the MX hostname. */ smtp_sasl_passwd_map->error = 0; if (((state->misc_flags & SMTP_MISC_FLAG_USE_LMTP) == 0 && var_smtp_sender_auth && state->request->sender[0] && (value = mail_addr_find(smtp_sasl_passwd_map, state->request->sender, (char **) 0)) != 0) || (smtp_sasl_passwd_map->error == 0 && (value = maps_find(smtp_sasl_passwd_map, session->host, 0)) != 0) || (smtp_sasl_passwd_map->error == 0 && (value = maps_find(smtp_sasl_passwd_map, session->dest, 0)) != 0)) { if (session->sasl_username) myfree(session->sasl_username); session->sasl_username = mystrdup(value); passwd = split_at(session->sasl_username, ':'); if (session->sasl_passwd) myfree(session->sasl_passwd); session->sasl_passwd = mystrdup(passwd ? passwd : ""); if (msg_verbose) msg_info("%s: host `%s' user `%s' pass `%s'", myname, session->host, session->sasl_username, session->sasl_passwd); return (1); } else if (smtp_sasl_passwd_map->error) { msg_warn("%s: %s lookup error", state->request->queue_id, smtp_sasl_passwd_map->title); vstream_longjmp(session->stream, SMTP_ERR_DATA); } else { if (msg_verbose) msg_info("%s: no auth info found (sender=`%s', host=`%s')", myname, state->request->sender, session->host); return (0); } }
static void xsasl_dovecot_parse_reply_args(XSASL_DOVECOT_SERVER *server, char *line, VSTRING *reply, int success) { char *next; if (server->username) { myfree(server->username); server->username = 0; } /* * Note: TAB is part of the Dovecot protocol and must not appear in * legitimate Dovecot usernames, otherwise the protocol would break. */ for (; line != NULL; line = next) { next = split_at(line, '\t'); if (strncmp(line, "user="******"reason=", 7) == 0) { if (!success) { printable(line + 7, '?'); vstring_strcpy(reply, line + 7); } } } }
void VG_(bindRangeMap) ( RangeMap* rm, UWord key_min, UWord key_max, UWord val ) { vg_assert(key_min <= key_max); split_at(rm, key_min); if (key_max < UWORD_MAX) split_at(rm, key_max + 1); Word iMin, iMax, i; iMin = find(rm, key_min); iMax = find(rm, key_max); for (i = iMin; i <= iMax; i++) { Range* rng = VG_(indexXA)(rm->ranges, i); rng->val = val; } preen(rm); }
int main(int argc, char **argv) { char *transport; char *endpoint; char *path; int server_sock; int client_fd; if (argc < 3 || (endpoint = split_at(transport = argv[1], ':')) == 0 || *endpoint == 0 || *transport == 0) msg_fatal("usage: %s transport:endpoint file...", argv[0]); if (strcmp(transport, "stream") == 0) { server_sock = stream_connect(endpoint, BLOCKING, 0); } else { msg_fatal("invalid transport name: %s", transport); } if (server_sock < 0) msg_fatal("connect %s:%s: %m", transport, endpoint); argv += 2; while ((path = *argv++) != 0) { if ((client_fd = open(path, O_RDONLY, 0)) < 0) msg_fatal("open %s: %m", path); msg_info("path=%s client_fd=%d", path, client_fd); if (stream_send_fd(server_sock, client_fd) < 0) msg_fatal("send file descriptor: %m"); if (close(client_fd) != 0) msg_fatal("close(%d): %m", client_fd); } exit(0); }
static void postmap_body(void *ptr, int unused_rec_type, const char *keybuf, ssize_t unused_len, off_t unused_offset) { POSTMAP_KEY_STATE *state = (POSTMAP_KEY_STATE *) ptr; DICT **dicts = state->dicts; char **maps = state->maps; int map_count = state->map_count; int dict_flags = state->dict_flags; const char *map_name; const char *value; int n; for (n = 0; n < map_count; n++) { if (dicts[n] == 0) dicts[n] = ((map_name = split_at(maps[n], ':')) != 0 ? dict_open3(maps[n], map_name, O_RDONLY, dict_flags) : dict_open3(var_db_type, maps[n], O_RDONLY, dict_flags)); if ((value = dict_get(dicts[n], keybuf)) != 0) { if (*value == 0) { msg_warn("table %s:%s: key %s: empty string result is not allowed", dicts[n]->type, dicts[n]->name, keybuf); msg_warn("table %s:%s should return NO RESULT in case of NOT FOUND", dicts[n]->type, dicts[n]->name); } vstream_printf("%s %s\n", keybuf, value); state->found = 1; break; } if (dicts[n]->error) msg_fatal("table %s:%s: query error: %m", dicts[n]->type, dicts[n]->name); } }
char *split_addr(char *localpart, int delimiter) { int len; /* * Don't split these, regardless of what the delimiter is. */ if (strcasecmp(localpart, MAIL_ADDR_POSTMASTER) == 0) return (0); if (strcasecmp(localpart, MAIL_ADDR_MAIL_DAEMON) == 0) return (0); if (strcasecmp(localpart, var_double_bounce_sender) == 0) return (0); /* * Backwards compatibility: don't split owner-foo or foo-request. */ if (delimiter == '-' && var_ownreq_special != 0) { if (strncasecmp(localpart, "owner-", 6) == 0) return (0); if ((len = strlen(localpart) - 8) > 0 && strcasecmp(localpart + len, "-request") == 0) return (0); } /* * Safe to split this address. Do not split the address if the result * would have a null localpart. */ return (delimiter == *localpart ? 0 : split_at(localpart, delimiter)); }
void register_dbms_parameters(const char *param_value, const char *(flag_parameter) (const char *, int, PC_MASTER_ENT *), PC_MASTER_ENT *local_scope) { const PC_DBMS_INFO *dp; char *bufp; char *db_type; char *prefix; static VSTRING *buffer = 0; static VSTRING *candidate = 0; const char **cpp; /* * XXX This does not examine both sides of conditional macro expansion, * and may expand the "wrong" conditional macros. This is the best we can * do for legacy database configuration support. */ if (buffer == 0) buffer = vstring_alloc(100); bufp = expand_parameter_value(buffer, SHOW_EVAL, param_value, local_scope); /* * Naive parsing. We don't really know if the parameter specifies free * text or a list of databases. */ while ((db_type = mystrtok(&bufp, " ,\t\r\n")) != 0) { /* * Skip over "proxy:" maptypes, to emulate the proxymap(8) server's * behavior when opening a local database configuration file. */ while ((prefix = split_at(db_type, ':')) != 0 && strcmp(db_type, DICT_TYPE_PROXY) == 0) db_type = prefix; /* * Look for database:prefix where the prefix is not a pathname and * the database is a known type. Synthesize candidate parameter names * from the user-defined prefix and from the database-defined suffix * list, and see if those parameters have a "name=value" entry in the * local or global namespace. */ if (prefix != 0 && *prefix != '/' && *prefix != '.') { for (dp = dbms_info; dp->db_type != 0; dp++) { if (strcmp(db_type, dp->db_type) == 0) { for (cpp = dp->db_suffixes; *cpp; cpp++) { vstring_sprintf(candidate ? candidate : (candidate = vstring_alloc(30)), "%s_%s", prefix, *cpp); flag_parameter(STR(candidate), PC_PARAM_FLAG_DBMS | PC_PARAM_FLAG_USER, local_scope); } break; } } } } }
static void severity_option(char *value, struct request_info *request) { char *level = split_at(value, '.'); allow_severity = deny_severity = level ? severity_map(log_fac, value) | severity_map(log_sev, level) : severity_map(log_sev, value); }
static const char *mail_version_worker(MAIL_VERSION *mp, char *cp) { char *major_field; char *minor_field; char *patch_field; /* * Program name. */ if ((mp->program = mystrtok(&cp, "-")) == 0) return ("no program name"); /* * Major, minor, patchlevel. If this is a stable release, then we ignore * text after the patchlevel, in case there are vendor extensions. */ if ((major_field = mystrtok(&cp, "-")) == 0) return ("missing major version"); if ((minor_field = split_at(major_field, '.')) == 0) return ("missing minor version"); if ((mp->major = mail_version_int(major_field)) < 0) return ("bad major version"); patch_field = split_at(minor_field, '.'); if ((mp->minor = mail_version_int(minor_field)) < 0) return ("bad minor version"); if (patch_field == 0) mp->patch = -1; else if ((mp->patch = mail_version_int(patch_field)) < 0) return ("bad patchlevel"); /* * Experimental release. If this is not a stable release, we take * everything to the end of the string. */ if (patch_field != 0) mp->snapshot = 0; else if ((mp->snapshot = mystrtok(&cp, "")) == 0) return ("missing snapshot field"); return (0); }
static int postmap_deletes(VSTREAM *in, char **maps, const int map_count, int dict_flags) { int found = 0; VSTRING *keybuf = vstring_alloc(100); DICT **dicts; const char *map_name; int n; int open_flags; /* * Sanity check. */ if (map_count <= 0) msg_panic("postmap_deletes: bad map count"); /* * Open maps ahead of time. */ dicts = (DICT **) mymalloc(sizeof(*dicts) * map_count); for (n = 0; n < map_count; n++) { map_name = split_at(maps[n], ':'); if (map_name && strcmp(maps[n], DICT_TYPE_PROXY) == 0) open_flags = O_RDWR | O_CREAT; /* XXX */ else open_flags = O_RDWR; dicts[n] = (map_name != 0 ? dict_open3(maps[n], map_name, open_flags, dict_flags) : dict_open3(var_db_type, maps[n], open_flags, dict_flags)); } /* * Perform all requests. */ while (vstring_get_nonl(keybuf, in) != VSTREAM_EOF) { for (n = 0; n < map_count; n++) { found |= (dict_del(dicts[n], STR(keybuf)) == 0); if (dicts[n]->error) msg_fatal("table %s:%s: delete error: %m", dicts[n]->type, dicts[n]->name); } } /* * Cleanup. */ for (n = 0; n < map_count; n++) if (dicts[n]) dict_close(dicts[n]); myfree((void *) dicts); vstring_free(keybuf); return (found); }
int karatSuba( char * num1, char * num2 ){ int n1,n2 ; n1 = convert_to_int(num1); n2 = convert_to_int(num2); if ( n1 < 10 || n2 < 10 ){ return n1*n2 ; } int m = max(num1,num2,10)/2; // high1, low1 = split_at(num1,m2); char * high1 = split_at(num1,0,m); char * low1 = split_at(num1,m,strlen(num1)); // high2, low2 = split_at(num2,m2); char * high2 = split_at(num2,0,m); char * low2 = split_at(num2,m,strlen(num2)); int z0 = karatSuba(low1,low2); int z1 = karatSuba(convert_to_char(convert_to_int(low1)+convert_to_int(high1)),(convert_to_char(convert_to_int(low2)+convert_to_int(high2)))); int z2 = karatSuba(high1,high2); return (z2*pow(10,2*m))+((z1-z2-z0)*pow(10,m))+z0; }
DICT *dict_open(const char *dict_spec, int open_flags, int dict_flags) { char *saved_dict_spec = mystrdup(dict_spec); char *dict_name; DICT *dict; if ((dict_name = split_at(saved_dict_spec, ':')) == 0) msg_fatal("open dictionary: expecting \"type:name\" form instead of \"%s\"", dict_spec); dict = dict_open3(saved_dict_spec, dict_name, open_flags, dict_flags); myfree(saved_dict_spec); return (dict); }
static void user_option(char *value, struct request_info *request) { struct passwd *pwd, pws; char *group; char pwbuf[1024]; if ((group = split_at(value, '.')) != 0) group_option(group, request); (void)getpwnam_r(value, &pws, pwbuf, sizeof(pwbuf), &pwd); if (pwd == NULL) tcpd_jump("unknown user: \"%s\"", value); if (dry_run == 0 && setuid(pwd->pw_uid)) tcpd_jump("setuid(%s): %m", value); }
int main(int argc, char **argv) { VSTRING *reply; int ch; char *rule; char *addr; msg_vstream_init(argv[0], VSTREAM_ERR); mail_conf_read(); msg_info("using config files in %s", var_config_dir); if (chdir(var_queue_dir) < 0) msg_fatal("chdir %s: %m", var_queue_dir); while ((ch = GETOPT(argc, argv, "v")) > 0) { switch (ch) { case 'v': msg_verbose++; break; default: usage(argv[0]); } } reply = vstring_alloc(1); if (argc > optind) { for (;;) { if ((rule = argv[optind++]) == 0) break; if ((addr = argv[optind++]) == 0) usage(argv[0]); rewrite(rule, addr, reply); } } else { VSTRING *buffer = vstring_alloc(1); while (vstring_fgets_nonl(buffer, VSTREAM_IN)) { if ((addr = split_at(STR(buffer), ' ')) == 0 || *(rule = STR(buffer)) == 0) usage(argv[0]); rewrite(rule, addr, reply); } vstring_free(buffer); } vstring_free(reply); exit(0); }
static int xsasl_dovecot_parse_reply(XSASL_DOVECOT_SERVER *server, char **line) { char *id; if (*line == NULL) { msg_warn("SASL: Protocol error"); return -1; } id = *line; *line = split_at(*line, '\t'); if (strtoul(id, NULL, 0) != server->last_request_id) { /* reply to another request, shouldn't really happen.. */ return -1; } return 0; }
const char *host_port(char *buf, char **host, char *def_host, char **port, char *def_service) { char *cp = buf; /* * [host]:port, [host]:, [host]. */ if (*cp == '[') { *host = ++cp; if ((cp = split_at(cp, ']')) == 0) return ("missing \"]\""); if (*cp && *cp++ != ':') return ("garbage after \"]\""); *port = *cp ? cp : def_service; } /* * host:port, host:, host, :port, port. */ else { if ((cp = split_at_right(buf, ':')) != 0) { *host = *buf ? buf : def_host; *port = *cp ? cp : def_service; } else { *host = def_host ? def_host : (*buf ? buf : 0); *port = def_service ? def_service : (*buf ? buf : 0); } } if (*host == 0) return ("missing host information"); if (*port == 0) return ("missing service information"); /* * Final sanity checks. We're still sloppy, allowing bare numerical * network addresses instead of requiring proper [ipaddress] forms. */ if (*host != def_host && !valid_hostname(*host, DONT_GRIPE) && !valid_hostaddr(*host, DONT_GRIPE)) return ("valid hostname or network address required"); if (*port != def_service && ISDIGIT(**port) && !alldig(*port)) return ("garbage after numerical service"); return (0); }
static int match_parse_mask(const char *pattern, unsigned long *net_bits, unsigned int *mask_shift) { char *saved_pattern; char *mask; #define BITS_PER_ADDR 32 saved_pattern = mystrdup(pattern); if ((mask = split_at(saved_pattern, '/')) != 0) { if (!alldig(mask) || (*mask_shift = atoi(mask)) > BITS_PER_ADDR || (*net_bits = inet_addr(saved_pattern)) == INADDR_NONE) { msg_fatal("bad net/mask pattern: %s", pattern); } } myfree(saved_pattern); return (mask != 0); }
static int xsasl_dovecot_handle_reply(XSASL_DOVECOT_SERVER *server, VSTRING *reply) { const char *myname = "xsasl_dovecot_handle_reply"; char *line, *cmd; /* XXX Encapsulate for logging. */ while (vstring_get_nonl(server->sasl_line, server->impl->sasl_stream) != VSTREAM_EOF) { line = vstring_str(server->sasl_line); if (msg_verbose) msg_info("%s: auth reply: %s", myname, line); cmd = line; line = split_at(line, '\t'); if (strcmp(cmd, "OK") == 0) { if (xsasl_dovecot_parse_reply(server, &line) == 0) { /* authentication successful */ xsasl_dovecot_parse_reply_args(server, line, reply, 1); return XSASL_AUTH_DONE; } } else if (strcmp(cmd, "CONT") == 0) { if (xsasl_dovecot_parse_reply(server, &line) == 0) { vstring_strcpy(reply, line); return XSASL_AUTH_MORE; } } else if (strcmp(cmd, "FAIL") == 0) { if (xsasl_dovecot_parse_reply(server, &line) == 0) { /* authentication failure */ xsasl_dovecot_parse_reply_args(server, line, reply, 0); return XSASL_AUTH_FAIL; } } else { /* ignore */ } } vstring_strcpy(reply, "Connection lost to authentication server"); return XSASL_AUTH_TEMP; }
static double split(int a, int b) { enum class ca, cb; ca = classify(a); cb = classify(b); if (ca == cb) return 0.5; if (ca > cb) return 1.0-split(b, a); switch (ca) { case good: switch (cb) { case average: return split_at(333, a, b); case bad: return split_at(500, a, b); case remote: return split_at(999, a, b); default: abort(); } case average: switch (cb) { case bad: return split_at(666, a, b); case remote: return split_at(999, a, b); default: abort(); } case bad: switch (cb) { case remote: return split_at(1000, a, b); default: abort(); } default: abort(); } }
static void output_header(void *context, int header_class, const HEADER_OPTS *header_info, VSTRING *buf, off_t offset) { SM_STATE *state = (SM_STATE *) context; TOK822 *tree; TOK822 **addr_list; TOK822 **tpp; ARGV *rcpt; char *start; char *line; char *next_line; ssize_t len; /* * Parse the header line, and save copies of recipient addresses in the * appropriate place. */ if (header_class == MIME_HDR_PRIMARY && header_info && (header_info->flags & HDR_OPT_RECIP) && (header_info->flags & HDR_OPT_EXTRACT) && (state->resent == 0 || (header_info->flags & HDR_OPT_RR))) { if (header_info->flags & HDR_OPT_RR) { rcpt = state->resent_recip; if (state->resent == 0) state->resent = 1; } else rcpt = state->recipients; tree = tok822_parse(STR(buf) + strlen(header_info->name) + 1); addr_list = tok822_grep(tree, TOK822_ADDR); for (tpp = addr_list; *tpp; tpp++) { tok822_internalize(state->temp, tpp[0]->head, TOK822_STR_DEFL); argv_add(rcpt, STR(state->temp), (char *) 0); } myfree((void *) addr_list); tok822_free_tree(tree); } /* * Pipe the unmodified message header through the header line folding * routine, and ensure that long lines are chopped appropriately. */ for (line = start = STR(buf); line; line = next_line) { next_line = split_at(line, '\n'); len = next_line ? next_line - line - 1 : strlen(line); do { if (len > var_line_limit) { output_text(context, REC_TYPE_CONT, line, var_line_limit, offset); line += var_line_limit; len -= var_line_limit; offset += var_line_limit; } else { output_text(context, REC_TYPE_NORM, line, len, offset); offset += len; break; } } while (len > 0); offset += 1; } }
static inline karatsuba(num *a,num *b,num *c){ /* * a=[hi1:lo1] * b=[h2:lo2] * a=hi1*B^m2+lo1 * b=hi2*B^m2+lo2 * a*b=(hi1*hi2)B^(2*m2)+ (l1h2+l2h1) B^m2+lo1*lo2 */ if(a->n<2){ mul1_(b,a->a[0],c); return; } if(b->n<2){ mul1_(a,b->a[0],c); return; } /* printf("%d %d\n",a->n,b->n); printNum(a); printNum(b); printf("case #3\n");*/ int m=max2(a->n,b->n); int m2=m/2; //printf("m2=%d\n",m2); num hi1,lo1,hi2,lo2,z0,z1,z2,t1,t2,lh1,lh2; split_at(a,m2,&hi1,&lo1); split_at(b,m2,&hi2,&lo2); /*puts("--- hi1 ---"); printNum(&hi1); puts("--- lo1 ---"); printNum(&lo1); puts("--- hi2 ---"); printNum(&hi2); puts("--- lo2 ---"); printNum(&lo2); */ add_(&lo1,&hi1,&lh1); add_(&lo2,&hi2,&lh2); karatsuba(&lh1,&lh2,&z1); karatsuba(&lo1,&lo2,&z0); karatsuba(&hi1,&hi2,&z2); /*puts(" z0 z1 z2 "); printNum(&z0); printNum(&z1); printNum(&z2); */ add_(&z0,&z2,&t1); //t1=z0+z2 sub_(&z1,&t1,&t2);//t2=z1-t1 //puts("t2= "); //printNum(&t2); shift_left(&z2,2*m2);//z2*B^2*m2 shift_left(&t2,m2); //t2*B^m2 //printNum(&z2); //printNum(&t2); //printNum(&z0); add_(&z0,&z2,c); //printNum(c); add_(c,&t2,c); rm0(c); //printNum(c); }
VSTRING *cidr_match_parse(CIDR_MATCH *ip, char *pattern, VSTRING *why) { const char *myname = "cidr_match_parse"; char *mask_search; char *mask; MAI_HOSTADDR_STR hostaddr; unsigned char *np; unsigned char *mp; /* * Strip [] from [addr/len] or [addr]/len, destroying the pattern. CIDR * maps don't need [] to eliminate syntax ambiguity, but matchlists need * it. While stripping [], figure out where we should start looking for * /mask information. */ if (*pattern == '[') { pattern++; if ((mask_search = split_at(pattern, ']')) == 0) { vstring_sprintf(why ? why : (why = vstring_alloc(20)), "missing ']' character after \"[%s\"", pattern); return (why); } else if (*mask_search != '/') { if (*mask_search != 0) { vstring_sprintf(why ? why : (why = vstring_alloc(20)), "garbage after \"[%s]\"", pattern); return (why); } mask_search = pattern; } } else mask_search = pattern; /* * Parse the pattern into network and mask, destroying the pattern. */ if ((mask = split_at(mask_search, '/')) != 0) { ip->addr_family = CIDR_MATCH_ADDR_FAMILY(pattern); ip->addr_bit_count = CIDR_MATCH_ADDR_BIT_COUNT(ip->addr_family); ip->addr_byte_count = CIDR_MATCH_ADDR_BYTE_COUNT(ip->addr_family); if (!alldig(mask) || (ip->mask_shift = atoi(mask)) > ip->addr_bit_count || inet_pton(ip->addr_family, pattern, ip->net_bytes) != 1) { vstring_sprintf(why ? why : (why = vstring_alloc(20)), "bad net/mask pattern: \"%s/%s\"", pattern, mask); return (why); } if (ip->mask_shift > 0) { /* Allow for bytes > 8. */ memset(ip->mask_bytes, ~0U, ip->addr_byte_count); mask_addr(ip->mask_bytes, ip->addr_byte_count, ip->mask_shift); } else memset(ip->mask_bytes, 0, ip->addr_byte_count); /* * Sanity check: all host address bits must be zero. */ for (np = ip->net_bytes, mp = ip->mask_bytes; np < ip->net_bytes + ip->addr_byte_count; np++, mp++) { if (*np & ~(*mp)) { mask_addr(ip->net_bytes, ip->addr_byte_count, ip->mask_shift); if (inet_ntop(ip->addr_family, ip->net_bytes, hostaddr.buf, sizeof(hostaddr.buf)) == 0) msg_fatal("inet_ntop: %m"); vstring_sprintf(why ? why : (why = vstring_alloc(20)), "non-null host address bits in \"%s/%s\", " "perhaps you should use \"%s/%d\" instead", pattern, mask, hostaddr.buf, ip->mask_shift); return (why); } } } /* * No /mask specified. Treat a bare network address as /allbits. */ else { ip->addr_family = CIDR_MATCH_ADDR_FAMILY(pattern); ip->addr_bit_count = CIDR_MATCH_ADDR_BIT_COUNT(ip->addr_family); ip->addr_byte_count = CIDR_MATCH_ADDR_BYTE_COUNT(ip->addr_family); if (inet_pton(ip->addr_family, pattern, ip->net_bytes) != 1) { vstring_sprintf(why ? why : (why = vstring_alloc(20)), "bad address pattern: \"%s\"", pattern); return (why); } ip->mask_shift = ip->addr_bit_count; /* Allow for bytes > 8. */ memset(ip->mask_bytes, ~0U, ip->addr_byte_count); } /* * Wrap up the result. */ ip->next = 0; return (0); }
static void psc_dnsbl_add_site(const char *site) { const char *myname = "psc_dnsbl_add_site"; char *saved_site = mystrdup(site); VSTRING *byte_codes = 0; PSC_DNSBL_HEAD *head; PSC_DNSBL_SITE *new_site; char junk; const char *weight_text; char *pattern_text; int weight; HTABLE_INFO *ht; char *parse_err; /* * Parse the required DNSBL domain name, the optional reply filter and * the optional reply weight factor. */ #define DO_GRIPE 1 /* Negative weight means whitelist. */ if ((weight_text = split_at(saved_site, '*')) != 0) { if (sscanf(weight_text, "%d%c", &weight, &junk) != 1) msg_fatal("bad DNSBL weight factor \"%s\" in \"%s\"", weight_text, site); } else { weight = 1; } /* Reply filter. */ if ((pattern_text = split_at(saved_site, '=')) != 0) { byte_codes = vstring_alloc(100); if ((parse_err = ip_match_parse(byte_codes, pattern_text)) != 0) msg_fatal("bad DNSBL filter syntax: %s", parse_err); } if (valid_hostname(saved_site, DO_GRIPE) == 0) msg_fatal("bad DNSBL domain name \"%s\" in \"%s\"", saved_site, site); if (msg_verbose > 1) msg_info("%s: \"%s\" -> domain=\"%s\" pattern=\"%s\" weight=%d", myname, site, saved_site, pattern_text ? pattern_text : "null", weight); /* * Look up or create the (filter, weight) list head for this DNSBL domain * name. */ if ((head = (PSC_DNSBL_HEAD *) htable_find(dnsbl_site_cache, saved_site)) == 0) { head = (PSC_DNSBL_HEAD *) mymalloc(sizeof(*head)); ht = htable_enter(dnsbl_site_cache, saved_site, (void *) head); /* Translate the DNSBL name into a safe name if available. */ if (psc_dnsbl_reply == 0 || (head->safe_dnsbl = dict_get(psc_dnsbl_reply, saved_site)) == 0) head->safe_dnsbl = ht->key; if (psc_dnsbl_reply && psc_dnsbl_reply->error) msg_fatal("%s:%s lookup error", psc_dnsbl_reply->type, psc_dnsbl_reply->name); head->first = 0; } /* * Append the new (filter, weight) node to the list for this DNSBL domain * name. */ new_site = (PSC_DNSBL_SITE *) mymalloc(sizeof(*new_site)); new_site->filter = (pattern_text ? mystrdup(pattern_text) : 0); new_site->byte_codes = (byte_codes ? ip_match_save(byte_codes) : 0); new_site->weight = weight; new_site->next = head->first; head->first = new_site; myfree(saved_site); if (byte_codes) vstring_free(byte_codes); }
const char *smtpd_milter_eval(const char *name, void *ptr) { SMTPD_STATE *state = (SMTPD_STATE *) ptr; const RESOLVE_REPLY *reply; char *cp; /* * On-the-fly initialization. */ if (state->expand_buf == 0) state->expand_buf = vstring_alloc(10); /* * Canonicalize the name. */ if (*name != '{') { /* } */ vstring_sprintf(state->expand_buf, "{%s}", name); name = STR(state->expand_buf); } /* * System macros. */ if (strcmp(name, S8_MAC_DAEMON_NAME) == 0) return (var_milt_daemon_name); if (strcmp(name, S8_MAC_V) == 0) return (var_milt_v); /* * Connect macros. */ if (strcmp(name, S8_MAC__) == 0) { vstring_sprintf(state->expand_buf, "%s [%s]", state->reverse_name, state->addr); if (strcasecmp(state->name, state->reverse_name) != 0) vstring_strcat(state->expand_buf, " (may be forged)"); return (STR(state->expand_buf)); } if (strcmp(name, S8_MAC_J) == 0) return (var_myhostname); if (strcmp(name, S8_MAC_CLIENT_ADDR) == 0) return (state->rfc_addr); if (strcmp(name, S8_MAC_CLIENT_PORT) == 0) return (strcmp(state->port, CLIENT_PORT_UNKNOWN) ? state->port : "0"); if (strcmp(name, S8_MAC_CLIENT_CONN) == 0) { vstring_sprintf(state->expand_buf, "%d", state->conn_count); return (STR(state->expand_buf)); } if (strcmp(name, S8_MAC_CLIENT_NAME) == 0) return (state->name); if (strcmp(name, S8_MAC_CLIENT_PTR) == 0) return (state->reverse_name); if (strcmp(name, S8_MAC_CLIENT_RES) == 0) return (state->name_status == SMTPD_PEER_CODE_OK ? "OK" : state->name_status == SMTPD_PEER_CODE_FORGED ? "FORGED" : state->name_status == SMTPD_PEER_CODE_TEMP ? "TEMP" : "FAIL"); /* * HELO macros. */ #ifdef USE_TLS #define IF_ENCRYPTED(x) (state->tls_context ? (x) : 0) #define IF_TRUSTED(x) (TLS_CERT_IS_TRUSTED(state->tls_context) ? (x) : 0) if (strcmp(name, S8_MAC_TLS_VERSION) == 0) return (IF_ENCRYPTED(state->tls_context->protocol)); if (strcmp(name, S8_MAC_CIPHER) == 0) return (IF_ENCRYPTED(state->tls_context->cipher_name)); if (strcmp(name, S8_MAC_CIPHER_BITS) == 0) { if (state->tls_context == 0) return (0); vstring_sprintf(state->expand_buf, "%d", IF_ENCRYPTED(state->tls_context->cipher_usebits)); return (STR(state->expand_buf)); } if (strcmp(name, S8_MAC_CERT_SUBJECT) == 0) return (IF_TRUSTED(state->tls_context->peer_CN)); if (strcmp(name, S8_MAC_CERT_ISSUER) == 0) return (IF_TRUSTED(state->tls_context->issuer_CN)); #endif /* * MAIL FROM macros. */ #define IF_SASL_ENABLED(s) (smtpd_sasl_is_active(state) && (s) ? (s) : 0) if (strcmp(name, S8_MAC_I) == 0) return (state->queue_id); #ifdef USE_SASL_AUTH if (strcmp(name, S8_MAC_AUTH_TYPE) == 0) return (IF_SASL_ENABLED(state->sasl_method)); if (strcmp(name, S8_MAC_AUTH_AUTHEN) == 0) return (IF_SASL_ENABLED(state->sasl_username)); if (strcmp(name, S8_MAC_AUTH_AUTHOR) == 0) return (IF_SASL_ENABLED(state->sasl_sender)); #endif if (strcmp(name, S8_MAC_MAIL_ADDR) == 0) { if (state->sender == 0) return (0); if (state->sender[0] == 0) return (""); reply = smtpd_resolve_addr(state->sender); /* Sendmail 8.13 does not externalize the null string. */ if (STR(reply->recipient)[0]) quote_821_local(state->expand_buf, STR(reply->recipient)); else vstring_strcpy(state->expand_buf, STR(reply->recipient)); return (STR(state->expand_buf)); } if (strcmp(name, S8_MAC_MAIL_HOST) == 0) { if (state->sender == 0) return (0); reply = smtpd_resolve_addr(state->sender); return (STR(reply->nexthop)); } if (strcmp(name, S8_MAC_MAIL_MAILER) == 0) { if (state->sender == 0) return (0); reply = smtpd_resolve_addr(state->sender); return (STR(reply->transport)); } /* * RCPT TO macros. */ if (strcmp(name, S8_MAC_RCPT_ADDR) == 0) { if (state->recipient == 0) return (0); if (state->recipient[0] == 0) return (""); if (state->milter_reject_text) { /* 554 5.7.1 <*****@*****.**>: Relay access denied */ vstring_strcpy(state->expand_buf, state->milter_reject_text + 4); cp = split_at(STR(state->expand_buf), ' '); return (cp ? split_at(cp, ' ') : cp); } reply = smtpd_resolve_addr(state->recipient); /* Sendmail 8.13 does not externalize the null string. */ if (STR(reply->recipient)[0]) quote_821_local(state->expand_buf, STR(reply->recipient)); else vstring_strcpy(state->expand_buf, STR(reply->recipient)); return (STR(state->expand_buf)); } if (strcmp(name, S8_MAC_RCPT_HOST) == 0) { if (state->recipient == 0) return (0); if (state->milter_reject_text) { /* 554 5.7.1 <*****@*****.**>: Relay access denied */ vstring_strcpy(state->expand_buf, state->milter_reject_text + 4); (void) split_at(STR(state->expand_buf), ' '); return (STR(state->expand_buf)); } reply = smtpd_resolve_addr(state->recipient); return (STR(reply->nexthop)); } if (strcmp(name, S8_MAC_RCPT_MAILER) == 0) { if (state->recipient == 0) return (0); if (state->milter_reject_text) return (S8_RCPT_MAILER_ERROR); reply = smtpd_resolve_addr(state->recipient); return (STR(reply->transport)); } return (0); }
void smtpd_peer_init(SMTPD_STATE *state) { const char *myname = "smtpd_peer_init"; SOCKADDR_SIZE sa_length; struct sockaddr *sa; INET_PROTO_INFO *proto_info = inet_proto_info(); sa = (struct sockaddr *) & (state->sockaddr); sa_length = sizeof(state->sockaddr); /* * Look up the peer address information. * * XXX If we make local endpoint (getsockname) information available to * Milter applications as {if_name} and {if_addr}, then we also must be * able to provide this via the XCLIENT command for Milter testing. * * XXX If we make local or remote port information available to policy * servers or Milter applications, then we must also make this testable * with the XCLIENT command, otherwise there will be confusion. * * XXX If we make local or remote port information available via logging, * then we must also support these attributes with the XFORWARD command. * * XXX If support were to be added for Milter applications in down-stream * MTAs, then consistency demands that we propagate a lot of Sendmail * macro information via the XFORWARD command. Otherwise we could end up * with a very confusing situation. */ if (getpeername(vstream_fileno(state->client), sa, &sa_length) >= 0) { errno = 0; } /* * If peer went away, give up. */ if (errno != 0 && errno != ENOTSOCK) { state->name = mystrdup(CLIENT_NAME_UNKNOWN); state->reverse_name = mystrdup(CLIENT_NAME_UNKNOWN); state->addr = mystrdup(CLIENT_ADDR_UNKNOWN); state->rfc_addr = mystrdup(CLIENT_ADDR_UNKNOWN); state->addr_family = AF_UNSPEC; state->name_status = SMTPD_PEER_CODE_PERM; state->reverse_name_status = SMTPD_PEER_CODE_PERM; state->port = mystrdup(CLIENT_PORT_UNKNOWN); } /* * Convert the client address to printable address and hostname. * * XXX If we're given an IPv6 (or IPv4) connection from, e.g., inetd, while * Postfix IPv6 (or IPv4) support is turned off, don't (skip to the final * else clause, pretend the origin is localhost[127.0.0.1], and become an * open relay). */ else if (errno == 0 && (sa->sa_family == AF_INET #ifdef AF_INET6 || sa->sa_family == AF_INET6 #endif )) { MAI_HOSTNAME_STR client_name; MAI_HOSTADDR_STR client_addr; MAI_SERVPORT_STR client_port; int aierr; char *colonp; /* * Sanity check: we can't use sockets that we're not configured for. */ if (strchr((char *) proto_info->sa_family_list, sa->sa_family) == 0) msg_fatal("cannot handle socket type %s with \"%s = %s\"", #ifdef AF_INET6 sa->sa_family == AF_INET6 ? "AF_INET6" : #endif sa->sa_family == AF_INET ? "AF_INET" : "other", VAR_INET_PROTOCOLS, var_inet_protocols); /* * Sorry, but there are some things that we just cannot do while * connected to the network. */ if (geteuid() != var_owner_uid || getuid() != var_owner_uid) { msg_error("incorrect SMTP server privileges: uid=%lu euid=%lu", (unsigned long) getuid(), (unsigned long) geteuid()); msg_fatal("the Postfix SMTP server must run with $%s privileges", VAR_MAIL_OWNER); } /* * Convert the client address to printable form. */ if ((aierr = sockaddr_to_hostaddr(sa, sa_length, &client_addr, &client_port, 0)) != 0) msg_fatal("%s: cannot convert client address/port to string: %s", myname, MAI_STRERROR(aierr)); state->port = mystrdup(client_port.buf); /* * XXX Strip off the IPv6 datalink suffix to avoid false alarms with * strict address syntax checks. */ #ifdef HAS_IPV6 (void) split_at(client_addr.buf, '%'); #endif /* * We convert IPv4-in-IPv6 address to 'true' IPv4 address early on, * but only if IPv4 support is enabled (why would anyone want to turn * it off)? With IPv4 support enabled we have no need for the IPv6 * form in logging, hostname verification and access checks. */ #ifdef HAS_IPV6 if (sa->sa_family == AF_INET6) { if (strchr((char *) proto_info->sa_family_list, AF_INET) != 0 && IN6_IS_ADDR_V4MAPPED(&SOCK_ADDR_IN6_ADDR(sa)) && (colonp = strrchr(client_addr.buf, ':')) != 0) { struct addrinfo *res0; if (msg_verbose > 1) msg_info("%s: rewriting V4-mapped address \"%s\" to \"%s\"", myname, client_addr.buf, colonp + 1); state->addr = mystrdup(colonp + 1); state->rfc_addr = mystrdup(colonp + 1); state->addr_family = AF_INET; aierr = hostaddr_to_sockaddr(state->addr, (char *) 0, 0, &res0); if (aierr) msg_fatal("%s: cannot convert %s from string to binary: %s", myname, state->addr, MAI_STRERROR(aierr)); sa_length = res0->ai_addrlen; if (sa_length > sizeof(state->sockaddr)) sa_length = sizeof(state->sockaddr); memcpy((char *) sa, res0->ai_addr, sa_length); freeaddrinfo(res0); /* 200412 */ } /* * Following RFC 2821 section 4.1.3, an IPv6 address literal gets * a prefix of 'IPv6:'. We do this consistently for all IPv6 * addresses that that appear in headers or envelopes. The fact * that valid_mailhost_addr() enforces the form helps of course. * We use the form without IPV6: prefix when doing access * control, or when accessing the connection cache. */ else { state->addr = mystrdup(client_addr.buf); state->rfc_addr = concatenate(IPV6_COL, client_addr.buf, (char *) 0); state->addr_family = sa->sa_family; } } /* * An IPv4 address is in dotted quad decimal form. */ else #endif { state->addr = mystrdup(client_addr.buf); state->rfc_addr = mystrdup(client_addr.buf); state->addr_family = sa->sa_family; } /* * Look up and sanity check the client hostname. * * It is unsafe to allow numeric hostnames, especially because there * exists pressure to turn off the name->addr double check. In that * case an attacker could trivally bypass access restrictions. * * sockaddr_to_hostname() already rejects malformed or numeric names. */ #define TEMP_AI_ERROR(e) \ ((e) == EAI_AGAIN || (e) == EAI_MEMORY || (e) == EAI_SYSTEM) #define REJECT_PEER_NAME(state, code) { \ myfree(state->name); \ state->name = mystrdup(CLIENT_NAME_UNKNOWN); \ state->name_status = code; \ } if (var_smtpd_peername_lookup == 0) { state->name = mystrdup(CLIENT_NAME_UNKNOWN); state->reverse_name = mystrdup(CLIENT_NAME_UNKNOWN); state->name_status = SMTPD_PEER_CODE_PERM; state->reverse_name_status = SMTPD_PEER_CODE_PERM; } else if ((aierr = sockaddr_to_hostname(sa, sa_length, &client_name, (MAI_SERVNAME_STR *) 0, 0)) != 0) { state->name = mystrdup(CLIENT_NAME_UNKNOWN); state->reverse_name = mystrdup(CLIENT_NAME_UNKNOWN); state->name_status = (TEMP_AI_ERROR(aierr) ? SMTPD_PEER_CODE_TEMP : SMTPD_PEER_CODE_PERM); state->reverse_name_status = (TEMP_AI_ERROR(aierr) ? SMTPD_PEER_CODE_TEMP : SMTPD_PEER_CODE_PERM); } else { struct addrinfo *res0; struct addrinfo *res; state->name = mystrdup(client_name.buf); state->reverse_name = mystrdup(client_name.buf); state->name_status = SMTPD_PEER_CODE_OK; state->reverse_name_status = SMTPD_PEER_CODE_OK; /* * Reject the hostname if it does not list the peer address. * Without further validation or qualification, such information * must not be allowed to enter the audit trail, as people would * draw false conclusions. */ aierr = hostname_to_sockaddr_pf(state->name, state->addr_family, (char *) 0, 0, &res0); if (aierr) { msg_warn("%s: hostname %s verification failed: %s", state->addr, state->name, MAI_STRERROR(aierr)); REJECT_PEER_NAME(state, (TEMP_AI_ERROR(aierr) ? SMTPD_PEER_CODE_TEMP : SMTPD_PEER_CODE_FORGED)); } else { for (res = res0; /* void */ ; res = res->ai_next) { if (res == 0) { msg_warn("%s: address not listed for hostname %s", state->addr, state->name); REJECT_PEER_NAME(state, SMTPD_PEER_CODE_FORGED); break; } if (strchr((char *) proto_info->sa_family_list, res->ai_family) == 0) { msg_info("skipping address family %d for host %s", res->ai_family, state->name); continue; } if (sock_addr_cmp_addr(res->ai_addr, sa) == 0) break; /* keep peer name */ } freeaddrinfo(res0); } } } /* * If it's not Internet, assume the client is local, and avoid using the * naming service because that can hang when the machine is disconnected. */ else { state->name = mystrdup("localhost"); state->reverse_name = mystrdup("localhost"); state->addr = mystrdup("127.0.0.1"); /* XXX bogus. */ state->rfc_addr = mystrdup("127.0.0.1");/* XXX bogus. */ state->addr_family = AF_UNSPEC; state->name_status = SMTPD_PEER_CODE_OK; state->reverse_name_status = SMTPD_PEER_CODE_OK; state->port = mystrdup("0"); /* XXX bogus. */ } /* * Do the name[addr]:port formatting for pretty reports. */ state->namaddr = SMTPD_BUILD_NAMADDRPORT(state->name, state->addr, state->port); }
static void get_service_attr(SPAWN_ATTR *attr, char *service, char **argv) { const char *myname = "get_service_attr"; struct passwd *pwd; struct group *grp; char *user; /* user name */ char *group; /* group name */ /* * Initialize. */ user = 0; group = 0; attr->argv = 0; /* * Figure out the command time limit for this transport. */ attr->time_limit = get_mail_conf_time2(service, _MAXTIME, var_command_maxtime, 's', 1, 0); /* * Iterate over the command-line attribute list. */ for ( /* void */ ; *argv != 0; argv++) { /* * user=username[:groupname] */ if (strncasecmp("user="******"user="******"user="******"unknown user name: %s", user); attr->uid = pwd->pw_uid; if (group != 0) { if ((grp = getgrnam(group)) == 0) msg_fatal("unknown group name: %s", group); attr->gid = grp->gr_gid; } else { attr->gid = pwd->pw_gid; } } /* * argv=command... */ else if (strncasecmp("argv=", *argv, sizeof("argv=") - 1) == 0) { *argv += sizeof("argv=") - 1; /* XXX clobbers argv */ attr->argv = argv; break; } /* * Bad. */ else msg_fatal("unknown attribute name: %s", *argv); } /* * Sanity checks. Verify that every member has an acceptable value. */ if (user == 0) msg_fatal("missing user= attribute"); if (attr->argv == 0) msg_fatal("missing argv= attribute"); if (attr->uid == 0) msg_fatal("request to deliver as root"); if (attr->uid == var_owner_uid) msg_fatal("request to deliver as mail system owner"); if (attr->gid == 0) msg_fatal("request to use privileged group id %ld", (long) attr->gid); if (attr->gid == var_owner_gid) msg_fatal("request to use mail system owner group id %ld", (long) attr->gid); if (attr->uid == (uid_t) (-1)) msg_fatal("user must not have user ID -1"); if (attr->gid == (gid_t) (-1)) msg_fatal("user must not have group ID -1"); /* * Give the poor tester a clue of what is going on. */ if (msg_verbose) msg_info("%s: uid %ld, gid %ld; time %d", myname, (long) attr->uid, (long) attr->gid, attr->time_limit); }