int main(int unused_argc, char **unused_argv) { VSTRING *extension = vstring_alloc(1); VSTRING *buf = vstring_alloc(1); ARGV *argv; char **cpp; mail_conf_read(); if (chdir(var_queue_dir) < 0) msg_fatal("chdir %s: %m", var_queue_dir); vstream_printf("extension: (CR for none): "); vstream_fflush(VSTREAM_OUT); if (vstring_get_nonl(extension, VSTREAM_IN) == VSTREAM_EOF) exit(0); vstream_printf("print strings to be translated, one per line\n"); vstream_fflush(VSTREAM_OUT); while (vstring_get_nonl(buf, VSTREAM_IN) != VSTREAM_EOF) { argv = mail_addr_crunch(STR(buf), VSTRING_LEN(extension) ? STR(extension) : 0); for (cpp = argv->argv; *cpp; cpp++) vstream_printf(" %s\n", *cpp); vstream_fflush(VSTREAM_OUT); } return (0); }
int main(int unused_argc, char **unused_argv) { VSTRING *buf = vstring_alloc(100); VSTRING *result = vstring_alloc(100); char *cp; char *name; char *value; HTABLE *table; int stat; while (!vstream_feof(VSTREAM_IN)) { table = htable_create(0); /* * Read a block of definitions, terminated with an empty line. */ while (vstring_get_nonl(buf, VSTREAM_IN) != VSTREAM_EOF) { vstream_printf("<< %s\n", vstring_str(buf)); vstream_fflush(VSTREAM_OUT); if (VSTRING_LEN(buf) == 0) break; cp = vstring_str(buf); name = mystrtok(&cp, " \t\r\n="); value = mystrtok(&cp, " \t\r\n="); htable_enter(table, name, value ? mystrdup(value) : 0); } /* * Read a block of patterns, terminated with an empty line or EOF. */ while (vstring_get_nonl(buf, VSTREAM_IN) != VSTREAM_EOF) { vstream_printf("<< %s\n", vstring_str(buf)); vstream_fflush(VSTREAM_OUT); if (VSTRING_LEN(buf) == 0) break; cp = vstring_str(buf); VSTRING_RESET(result); stat = mac_expand(result, vstring_str(buf), MAC_EXP_FLAG_NONE, (char *) 0, lookup, (char *) table); vstream_printf("stat=%d result=%s\n", stat, vstring_str(result)); vstream_fflush(VSTREAM_OUT); } htable_free(table, myfree); vstream_printf("\n"); } /* * Clean up. */ vstring_free(buf); vstring_free(result); exit(0); }
int main(int unused_argc, char **unused_argv) { VSTRING *vp = vstring_alloc(10); int tok_argc; POP3D_TOKEN *tok_argv; int i; for (;;) { if (isatty(STDIN_FILENO)) vstream_printf("enter POP3D command: "); vstream_fflush(VSTREAM_OUT); if (vstring_get_nonl(vp, VSTREAM_IN) == VSTREAM_EOF) break; if (*vstring_str(vp) == '#') continue; if (!isatty(STDIN_FILENO)) vstream_printf("%s\n", vstring_str(vp)); tok_argc = pop3d_token(vstring_str(vp), &tok_argv); for (i = 0; i < tok_argc; i++) { vstream_printf("Token type: %s\n", tok_argv[i].tokval == POP3D_TOK_OTHER ? "other" : tok_argv[i].tokval == POP3D_TOK_ERROR ? "error" : "unknown"); vstream_printf("Token value: %s\n", tok_argv[i].strval); } } exit(0); }
int main(int unused_argc, char **unused_argv) { VSTRING *buf = vstring_alloc(100); char *junk; unsigned long ulval; int base; char ch; unsigned long ulval2; #ifdef MISSING_STRTOUL #define strtoul strtol #endif while (vstring_get_nonl(buf, VSTREAM_IN) != VSTREAM_EOF) { ch = 0; if (sscanf(STR(buf), "%lu %d%c", &ulval, &base, &ch) != 2 || ch) { msg_warn("bad input %s", STR(buf)); } else { (void) safe_ultostr(buf, ulval, base, 5, '0'); vstream_printf("%lu = %s\n", ulval, STR(buf)); ulval2 = safe_strtoul(STR(buf), &junk, base); if (*junk || (ulval2 == ULONG_MAX && errno == ERANGE)) msg_warn("%s: %m", STR(buf)); if (ulval2 != ulval) msg_warn("%lu != %lu", ulval2, ulval); } vstream_fflush(VSTREAM_OUT); } vstring_free(buf); return (0); }
int main(int argc, char **argv) { VSTRING *in = vstring_alloc(10); VSTRING *out = vstring_alloc(10); double tval; int sec; int usec; int sig_dig; int max_dig; while (vstring_get_nonl(in, VSTREAM_IN) > 0) { vstream_printf(">> %s\n", vstring_str(in)); if (vstring_str(in)[0] == 0 || vstring_str(in)[0] == '#') continue; if (sscanf(vstring_str(in), "%lf %d %d", &tval, &sig_dig, &max_dig) != 3) msg_fatal("bad input: %s", vstring_str(in)); sec = (int) tval; /* raw seconds */ usec = (tval - sec) * MILLION; /* raw microseconds */ VSTRING_RESET(out); format_tv(out, sec, usec, sig_dig, max_dig); vstream_printf("%s\n", vstring_str(out)); vstream_fflush(VSTREAM_OUT); } vstring_free(in); vstring_free(out); return (0); }
static void log_stream(int level, VSTREAM *fp) { VSTRING *buf = vstring_alloc(100); while (vstring_get_nonl(buf, fp) != VSTREAM_EOF) msg_text(level, vstring_str(buf)); vstring_free(buf); }
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 main(void) { VSTRING *buf = vstring_alloc(1); while (vstring_get_nonl(buf, VSTREAM_IN) != VSTREAM_EOF) { vstream_printf("%c", (LEN(buf) && !valid_utf8_string(STR(buf), LEN(buf))) ? '!' : ' '); vstream_fwrite(VSTREAM_OUT, STR(buf), LEN(buf)); vstream_printf("\n"); } vstream_fflush(VSTREAM_OUT); vstring_free(buf); exit(0); }
int main(void) { VSTRING *buf = vstring_alloc(100); SERVER_ACL *argv; int ret; int have_tty = isatty(0); char *bufp; char *cmd; char *value; const NAME_CODE acl_map[] = { SERVER_ACL_NAME_ERROR, SERVER_ACL_ACT_ERROR, SERVER_ACL_NAME_PERMIT, SERVER_ACL_ACT_PERMIT, SERVER_ACL_NAME_REJECT, SERVER_ACL_ACT_REJECT, SERVER_ACL_NAME_DUNNO, SERVER_ACL_ACT_DUNNO, 0, }; #define VAR_SERVER_ACL "server_acl" while (vstring_get_nonl(buf, VSTREAM_IN) != VSTREAM_EOF) { bufp = STR(buf); if (have_tty == 0) { vstream_printf("> %s\n", bufp); vstream_fflush(VSTREAM_OUT); } if (*bufp == '#') continue; if ((cmd = mystrtok(&bufp, " =")) == 0 || STREQ(cmd, "?")) { vstream_printf("usage: %s=value|%s=value|address=value\n", VAR_MYNETWORKS, VAR_SERVER_ACL); } else if ((value = mystrtok(&bufp, " =")) == 0) { vstream_printf("missing value\n"); } else if (STREQ(cmd, VAR_MYNETWORKS)) { UPDATE_VAR(var_mynetworks, value); } else if (STREQ(cmd, VAR_SERVER_ACL)) { UPDATE_VAR(var_server_acl, value); } else if (STREQ(cmd, "address")) { server_acl_pre_jail_init(var_mynetworks, VAR_SERVER_ACL); argv = server_acl_parse(var_server_acl, VAR_SERVER_ACL); ret = server_acl_eval(value, argv, VAR_SERVER_ACL); argv_free(argv); vstream_printf("%s: %s\n", value, str_name_code(acl_map, ret)); } else { vstream_printf("unknown command: \"%s\"\n", cmd); } vstream_fflush(VSTREAM_OUT); } vstring_free(buf); exit(0); }
int main(int argc, char **argv) { VSTRING *buf = vstring_alloc(10); char *dir; char *base; while (vstring_get_nonl(buf, VSTREAM_IN) > 0) { dir = sane_dirname((VSTRING *) 0, STR(buf)); base = sane_basename((VSTRING *) 0, STR(buf)); vstream_printf("input=\"%s\" dir=\"%s\" base=\"%s\"\n", STR(buf), dir, base); } vstream_fflush(VSTREAM_OUT); vstring_free(buf); return (0); }
static int get_buffer(VSTRING *buf, VSTREAM *fp, int interactive) { int status; if (interactive) { vstream_printf("> "); vstream_fflush(VSTREAM_OUT); } if ((status = vstring_get_nonl(buf, fp)) != VSTREAM_EOF) { if (!interactive) { vstream_printf(">>> %s\n", STR(buf)); vstream_fflush(VSTREAM_OUT); } } return (status); }
int main(int unused_argc, char **unused_argv) { int mask_bits; VSTRING *buf = vstring_alloc(1); const char *mask_string; while (vstring_get_nonl(buf, VSTREAM_IN) != VSTREAM_EOF) { mask_bits = ehlo_mask(vstring_str(buf)); mask_string = str_ehlo_mask(mask_bits); vstream_printf("%s -> 0x%x -> %s\n", vstring_str(buf), mask_bits, mask_string); vstream_fflush(VSTREAM_OUT); } vstring_free(buf); exit(0); }
int main(int argc, char **argv) { static const NAME_MASK demo_table[] = { "zero", 1 << 0, "one", 1 << 1, "two", 1 << 2, "three", 1 << 3, 0, 0, }; static const NAME_MASK feature_table[] = { "DEFAULT", NAME_MASK_DEFAULT, "FATAL", NAME_MASK_FATAL, "ANY_CASE", NAME_MASK_ANY_CASE, "RETURN", NAME_MASK_RETURN, "COMMA", NAME_MASK_COMMA, "PIPE", NAME_MASK_PIPE, "NUMBER", NAME_MASK_NUMBER, "WARN", NAME_MASK_WARN, "IGNORE", NAME_MASK_IGNORE, 0, }; int in_feature_mask; int out_feature_mask; int demo_mask; const char *demo_str; VSTRING *out_buf = vstring_alloc(1); VSTRING *in_buf = vstring_alloc(1); if (argc != 3) msg_fatal("usage: %s in-feature-mask out-feature-mask", argv[0]); in_feature_mask = name_mask(argv[1], feature_table, argv[1]); out_feature_mask = name_mask(argv[2], feature_table, argv[2]); while (vstring_get_nonl(in_buf, VSTREAM_IN) != VSTREAM_EOF) { demo_mask = name_mask_opt("name", demo_table, STR(in_buf), in_feature_mask); demo_str = str_name_mask_opt(out_buf, "mask", demo_table, demo_mask, out_feature_mask); vstream_printf("%s -> 0x%x -> %s\n", STR(in_buf), demo_mask, demo_str ? demo_str : "(null)"); vstream_fflush(VSTREAM_OUT); } vstring_free(in_buf); vstring_free(out_buf); exit(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; }
int main(int argc, char **argv) { VSTRING *inbuf = vstring_alloc(100); VSTRING *result = vstring_alloc(100); char *bufp; char *cmd; char *target; char *junk; mail_conf_read(); while (vstring_get_nonl(inbuf, VSTREAM_IN) != VSTREAM_EOF) { bufp = STR(inbuf); if (!isatty(0)) { vstream_printf("> %s\n", bufp); vstream_fflush(VSTREAM_OUT); } if (*bufp == '#') continue; if ((cmd = mystrtok(&bufp, " \t")) == 0) { vstream_printf("usage: file path|map maptype:mapname\n"); vstream_fflush(VSTREAM_OUT); continue; } target = mystrtok(&bufp, " \t"); junk = mystrtok(&bufp, " \t"); if (strcmp(cmd, "file") == 0 && target && !junk) { data_redirect_file(result, target); vstream_printf("%s -> %s\n", target, STR(result)); } else if (strcmp(cmd, "map") == 0 && target && !junk) { data_redirect_map(result, target); vstream_printf("%s -> %s\n", target, STR(result)); } else { vstream_printf("usage: file path|map maptype:mapname\n"); } vstream_fflush(VSTREAM_OUT); } vstring_free(inbuf); return (0); }
static char *read_param_from_file(const char *path) { VSTRING *why = vstring_alloc(100); VSTRING *buf = vstring_alloc(100); VSTREAM *fp; char *bp; char *result; /* * Ugly macros to make complex expressions less unreadable. */ #define SKIP(start, var, cond) do { \ for (var = start; *var && (cond); var++) \ /* void */; \ } while (0) #define TRIM(s) do { \ char *p; \ for (p = (s) + strlen(s); p > (s) && ISSPACE(p[-1]); p--) \ /* void */; \ *p = 0; \ } while (0) fp = safe_open(path, O_RDONLY, 0, (struct stat *) 0, -1, -1, why); if (fp == 0) msg_fatal("%s: %s", path, vstring_str(why)); vstring_get_nonl(buf, fp); if (vstream_ferror(fp)) /* FIX 20070501 */ msg_fatal("%s: read error: %m", path); vstream_fclose(fp); SKIP(vstring_str(buf), bp, ISSPACE(*bp)); TRIM(bp); result = mystrdup(bp); vstring_free(why); vstring_free(buf); return (result); }
int main(int argc, char **argv) { ADDR_MATCH_LIST *list; char *addr; int ch; msg_vstream_init(argv[0], VSTREAM_ERR); while ((ch = GETOPT(argc, argv, "v")) > 0) { switch (ch) { case 'v': msg_verbose++; break; default: usage(argv[0]); } } if (argc != optind + 2) usage(argv[0]); list = addr_match_list_init(MATCH_FLAG_PARENT | MATCH_FLAG_RETURN, argv[optind]); addr = argv[optind + 1]; if (strcmp(addr, "-") == 0) { VSTRING *buf = vstring_alloc(100); while (vstring_get_nonl(buf, VSTREAM_IN) != VSTREAM_EOF) vstream_printf("%s: %s\n", vstring_str(buf), addr_match_list_match(list, vstring_str(buf)) ? "YES" : list->error == 0 ? "NO" : "ERROR"); vstring_free(buf); } else { vstream_printf("%s: %s\n", addr, addr_match_list_match(list, addr) > 0 ? "YES" : list->error == 0 ? "NO" : "ERROR"); } vstream_fflush(VSTREAM_OUT); addr_match_list_free(list); return (0); }
static int postalias_queries(VSTREAM *in, char **maps, const int map_count, const int dict_flags) { int found = 0; VSTRING *keybuf = vstring_alloc(100); DICT **dicts; const char *map_name; const char *value; int n; /* * Sanity check. */ if (map_count <= 0) msg_panic("postalias_queries: bad map count"); /* * Prepare to open maps lazily. */ dicts = (DICT **) mymalloc(sizeof(*dicts) * map_count); for (n = 0; n < map_count; n++) dicts[n] = 0; /* * Perform all queries. Open maps on the fly, to avoid opening unecessary * maps. */ while (vstring_get_nonl(keybuf, in) != VSTREAM_EOF) { 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], STR(keybuf))) != 0) { if (*value == 0) { msg_warn("table %s:%s: key %s: empty string result is not allowed", dicts[n]->type, dicts[n]->name, STR(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", STR(keybuf), value); found = 1; break; } if (dicts[n]->error) msg_fatal("table %s:%s: query error: %m", dicts[n]->type, dicts[n]->name); } } if (found) vstream_fflush(VSTREAM_OUT); /* * Cleanup. */ for (n = 0; n < map_count; n++) if (dicts[n]) dict_close(dicts[n]); myfree((void *) dicts); vstring_free(keybuf); return (found); }
int main(int argc, char **argv) { SESSION *session; char *host; char *port; char *path; int path_len; int sessions = 1; int ch; int i; char *buf; const char *parse_err; struct addrinfo *res; int aierr; const char *protocols = INET_PROTO_NAME_ALL; INET_PROTO_INFO *proto_info; char *message_file = 0; /* * Fingerprint executables and core dumps. */ MAIL_VERSION_STAMP_ALLOCATE; signal(SIGPIPE, SIG_IGN); msg_vstream_init(argv[0], VSTREAM_ERR); /* * Parse JCL. */ while ((ch = GETOPT(argc, argv, "46AcC:df:F:l:Lm:M:Nor:R:s:S:t:T:vw:")) > 0) { switch (ch) { case '4': protocols = INET_PROTO_NAME_IPV4; break; case '6': protocols = INET_PROTO_NAME_IPV6; break; case 'A': allow_reject = 1; break; case 'c': count++; break; case 'C': if ((connect_count = atoi(optarg)) <= 0) msg_fatal("bad connection count: %s", optarg); break; case 'd': disconnect = 0; break; case 'f': sender = optarg; break; case 'F': if (message_file == 0 && message_length > 0) msg_fatal("-l option cannot be used with -F"); message_file = optarg; break; case 'l': if (message_file != 0) msg_fatal("-l option cannot be used with -F"); if ((message_length = atoi(optarg)) <= 0) msg_fatal("bad message length: %s", optarg); break; case 'L': talk_lmtp = 1; break; case 'm': if ((message_count = atoi(optarg)) <= 0) msg_fatal("bad message count: %s", optarg); break; case 'M': if (*optarg == '[') { if (!valid_mailhost_literal(optarg, DO_GRIPE)) msg_fatal("bad address literal: %s", optarg); } else { if (!valid_hostname(optarg, DO_GRIPE)) msg_fatal("bad hostname: %s", optarg); } var_myhostname = optarg; break; case 'N': number_rcpts = 1; break; case 'o': send_helo_first = 0; send_headers = 0; break; case 'r': if ((recipients = atoi(optarg)) <= 0) msg_fatal("bad recipient count: %s", optarg); break; case 'R': if (fixed_delay > 0) msg_fatal("do not use -w and -R options at the same time"); if ((random_delay = atoi(optarg)) <= 0) msg_fatal("bad random delay: %s", optarg); break; case 's': if ((sessions = atoi(optarg)) <= 0) msg_fatal("bad session count: %s", optarg); break; case 'S': subject = optarg; break; case 't': recipient = optarg; break; case 'T': if ((inet_windowsize = atoi(optarg)) <= 0) msg_fatal("bad TCP window size: %s", optarg); break; case 'v': msg_verbose++; break; case 'w': if (random_delay > 0) msg_fatal("do not use -w and -R options at the same time"); if ((fixed_delay = atoi(optarg)) <= 0) msg_fatal("bad fixed delay: %s", optarg); break; default: usage(argv[0]); } } if (argc - optind != 1) usage(argv[0]); if (random_delay > 0) srand(getpid()); /* * Initialize the message content, SMTP encoded. smtp_fputs() will append * another \r\n but we don't care. */ if (message_file != 0) { VSTREAM *fp; VSTRING *buf = vstring_alloc(100); VSTRING *msg = vstring_alloc(100); if ((fp = vstream_fopen(message_file, O_RDONLY, 0)) == 0) msg_fatal("open %s: %m", message_file); while (vstring_get_nonl(buf, fp) != VSTREAM_EOF) { if (*vstring_str(buf) == '.') VSTRING_ADDCH(msg, '.'); vstring_memcat(msg, vstring_str(buf), VSTRING_LEN(buf)); vstring_memcat(msg, "\r\n", 2); } if (vstream_ferror(fp)) msg_fatal("read %s: %m", message_file); vstream_fclose(fp); vstring_free(buf); message_length = VSTRING_LEN(msg); message_data = vstring_export(msg); send_headers = 0; } else if (message_length > 0) { message_data = mymalloc(message_length); memset(message_data, 'X', message_length); for (i = 80; i < message_length; i += 80) { message_data[i - 80] = "0123456789"[(i / 80) % 10]; message_data[i - 2] = '\r'; message_data[i - 1] = '\n'; } } /* * Translate endpoint address to internal form. */ proto_info = inet_proto_init("protocols", protocols); if (strncmp(argv[optind], "unix:", 5) == 0) { path = argv[optind] + 5; path_len = strlen(path); if (path_len >= (int) sizeof(sun.sun_path)) msg_fatal("unix-domain name too long: %s", path); memset((char *) &sun, 0, sizeof(sun)); sun.sun_family = AF_UNIX; #ifdef HAS_SUN_LEN sun.sun_len = path_len + 1; #endif memcpy(sun.sun_path, path, path_len); sa = (struct sockaddr *) & sun; sa_length = sizeof(sun); } else { if (strncmp(argv[optind], "inet:", 5) == 0) argv[optind] += 5; buf = mystrdup(argv[optind]); if ((parse_err = host_port(buf, &host, (char *) 0, &port, "smtp")) != 0) msg_fatal("%s: %s", argv[optind], parse_err); if ((aierr = hostname_to_sockaddr(host, port, SOCK_STREAM, &res)) != 0) msg_fatal("%s: %s", argv[optind], MAI_STRERROR(aierr)); myfree(buf); sa = (struct sockaddr *) & ss; if (res->ai_addrlen > sizeof(ss)) msg_fatal("address length %d > buffer length %d", (int) res->ai_addrlen, (int) sizeof(ss)); memcpy((char *) sa, res->ai_addr, res->ai_addrlen); sa_length = res->ai_addrlen; #ifdef HAS_SA_LEN sa->sa_len = sa_length; #endif freeaddrinfo(res); } /* * Make sure the SMTP server cannot run us out of memory by sending * never-ending lines of text. */ if (buffer == 0) { buffer = vstring_alloc(100); vstring_ctl(buffer, VSTRING_CTL_MAXLEN, (ssize_t) var_line_limit, 0); } /* * Make sure we have sender and recipient addresses. */ if (var_myhostname == 0) var_myhostname = get_hostname(); if (sender == 0 || recipient == 0) { vstring_sprintf(buffer, "foo@%s", var_myhostname); defaddr = mystrdup(vstring_str(buffer)); if (sender == 0) sender = defaddr; if (recipient == 0) recipient = defaddr; } /* * Start sessions. */ while (sessions-- > 0) { session = (SESSION *) mymalloc(sizeof(*session)); session->stream = 0; session->xfer_count = 0; session->connect_count = connect_count; session->next = 0; session_count++; startup(session); } for (;;) { event_loop(-1); if (session_count <= 0 && message_count <= 0) { if (count) { VSTREAM_PUTC('\n', VSTREAM_OUT); vstream_fflush(VSTREAM_OUT); } exit(0); } } }
static int flush_send_path(const char *path, int how) { const char *myname = "flush_send_path"; VSTRING *queue_id; VSTRING *queue_file; VSTREAM *log; struct utimbuf tbuf; static char qmgr_flush_trigger[] = { QMGR_REQ_FLUSH_DEAD, /* flush dead site/transport cache */ }; static char qmgr_scan_trigger[] = { QMGR_REQ_SCAN_INCOMING, /* scan incoming queue */ }; HTABLE *dup_filter; int count; /* * Sanity check. */ if (!mail_queue_id_ok(path)) return (FLUSH_STAT_BAD); /* * Open the logfile. If the file does not exist, then there is no queued * mail for this destination. */ if ((log = mail_queue_open(MAIL_QUEUE_FLUSH, path, O_RDWR, 0600)) == 0) { if (errno != ENOENT) msg_fatal("%s: open fast flush logfile %s: %m", myname, path); return (FLUSH_STAT_OK); } /* * We must lock the logfile, so that we don't lose information when it is * truncated. Unfortunately, this means that the file can be locked for a * significant amount of time. If things really get stuck the Postfix * watchdog will take care of it. */ if (myflock(vstream_fileno(log), INTERNAL_LOCK, MYFLOCK_OP_EXCLUSIVE) < 0) msg_fatal("%s: lock fast flush logfile %s: %m", myname, path); /* * With the UNTHROTTLE_BEFORE strategy, we ask the queue manager to * unthrottle all transports and queues before we move a deferred queue * file to the incoming queue. This minimizes a race condition where the * queue manager seizes a queue file before it knows that we want to * flush that message. * * This reduces the race condition time window to a very small amount (the * flush server does not really know when the queue manager reads its * command fifo). But there is a worse race, where the queue manager * moves a deferred queue file to the active queue before we have a * chance to expedite its delivery. */ if (how & UNTHROTTLE_BEFORE) mail_trigger(MAIL_CLASS_PUBLIC, var_queue_service, qmgr_flush_trigger, sizeof(qmgr_flush_trigger)); /* * This is the part that dominates running time: schedule the listed * queue files for delivery by updating their file time stamps and by * moving them from the deferred queue to the incoming queue. This should * take no more than a couple seconds under normal conditions. Filter out * duplicate queue file names to avoid hammering the file system, with * some finite limit on the amount of memory that we are willing to * sacrifice for duplicate filtering. Graceful degradation. * * By moving selected queue files from the deferred queue to the incoming * queue we optimize for the case where most deferred mail is for other * sites. If that assumption does not hold, i.e. all deferred mail is for * the same site, then doing a "fast flush" will cost more disk I/O than * a "slow flush" that delivers the entire deferred queue. This penalty * is only temporary - it will go away after we unite the active queue * and the incoming queue. */ queue_id = vstring_alloc(10); queue_file = vstring_alloc(10); dup_filter = htable_create(10); tbuf.actime = tbuf.modtime = event_time(); for (count = 0; vstring_get_nonl(queue_id, log) != VSTREAM_EOF; count++) { if (!mail_queue_id_ok(STR(queue_id))) { msg_warn("bad queue id \"%.30s...\" in fast flush logfile %s", STR(queue_id), path); continue; } if (dup_filter->used >= FLUSH_DUP_FILTER_SIZE || htable_find(dup_filter, STR(queue_id)) == 0) { if (msg_verbose) msg_info("%s: logfile %s: update queue file %s time stamps", myname, path, STR(queue_id)); if (dup_filter->used <= FLUSH_DUP_FILTER_SIZE) htable_enter(dup_filter, STR(queue_id), 0); count += flush_one_file(STR(queue_id), queue_file, &tbuf, how); } else { if (msg_verbose) msg_info("%s: logfile %s: skip queue file %s as duplicate", myname, path, STR(queue_file)); } } htable_free(dup_filter, (void (*) (void *)) 0); vstring_free(queue_file); vstring_free(queue_id); /* * Truncate the fast flush log. */ if (count > 0 && ftruncate(vstream_fileno(log), (off_t) 0) < 0) msg_fatal("%s: truncate fast flush logfile %s: %m", myname, path); /* * Workaround for noatime mounts. Use futimes() if available. */ (void) utimes(VSTREAM_PATH(log), (struct timeval *) 0); /* * Request delivery and clean up. */ if (myflock(vstream_fileno(log), INTERNAL_LOCK, MYFLOCK_OP_NONE) < 0) msg_fatal("%s: unlock fast flush logfile %s: %m", myname, path); if (vstream_fclose(log) != 0) msg_warn("%s: read fast flush logfile %s: %m", myname, path); if (count > 0) { if (msg_verbose) msg_info("%s: requesting delivery for logfile %s", myname, path); mail_trigger(MAIL_CLASS_PUBLIC, var_queue_service, qmgr_scan_trigger, sizeof(qmgr_scan_trigger)); } return (FLUSH_STAT_OK); }
static int postmap_queries(VSTREAM *in, char **maps, const int map_count, const int postmap_flags, const int dict_flags) { int found = 0; VSTRING *keybuf = vstring_alloc(100); DICT **dicts; const char *map_name; const char *value; int n; /* * Sanity check. */ if (map_count <= 0) msg_panic("postmap_queries: bad map count"); /* * Prepare to open maps lazily. */ dicts = (DICT **) mymalloc(sizeof(*dicts) * map_count); for (n = 0; n < map_count; n++) dicts[n] = 0; /* * Perform all queries. Open maps on the fly, to avoid opening unecessary * maps. */ if ((postmap_flags & POSTMAP_FLAG_HB_KEY) == 0) { while (vstring_get_nonl(keybuf, in) != VSTREAM_EOF) { 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], STR(keybuf))) != 0) { if (*value == 0) { msg_warn("table %s:%s: key %s: empty string result is not allowed", dicts[n]->type, dicts[n]->name, STR(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", STR(keybuf), value); found = 1; break; } if (dicts[n]->error) msg_fatal("table %s:%s: query error: %m", dicts[n]->type, dicts[n]->name); } } } else { POSTMAP_KEY_STATE key_state; MIME_STATE *mime_state; int mime_errs = 0; /* * Bundle up the request and instantiate a MIME parsing engine. */ key_state.dicts = dicts; key_state.maps = maps; key_state.map_count = map_count; key_state.dict_flags = dict_flags; key_state.header_done = 0; key_state.found = 0; mime_state = mime_state_alloc((postmap_flags & POSTMAP_FLAG_MIME_KEY) ? 0 : MIME_OPT_DISABLE_MIME, (postmap_flags & POSTMAP_FLAG_HEADER_KEY) ? postmap_header : (MIME_STATE_HEAD_OUT) 0, (postmap_flags & POSTMAP_FLAG_FULL_KEY) ? (MIME_STATE_ANY_END) 0 : postmap_head_end, (postmap_flags & POSTMAP_FLAG_BODY_KEY) ? postmap_body : (MIME_STATE_BODY_OUT) 0, (MIME_STATE_ANY_END) 0, (MIME_STATE_ERR_PRINT) 0, (void *) &key_state); /* * Process the input message. */ while (vstring_get_nonl(keybuf, in) != VSTREAM_EOF && key_state.header_done == 0 && mime_errs == 0) mime_errs = mime_state_update(mime_state, REC_TYPE_NORM, STR(keybuf), LEN(keybuf)); /* * Flush the MIME engine output buffer and tidy up loose ends. */ if (mime_errs == 0) mime_errs = mime_state_update(mime_state, REC_TYPE_END, "", 0); if (mime_errs) msg_fatal("message format error: %s", mime_state_detail(mime_errs)->text); mime_state_free(mime_state); found = key_state.found; } if (found) vstream_fflush(VSTREAM_OUT); /* * Cleanup. */ for (n = 0; n < map_count; n++) if (dicts[n]) dict_close(dicts[n]); myfree((void *) dicts); vstring_free(keybuf); return (found); }
static int xsasl_dovecot_server_connect(XSASL_DOVECOT_SERVER_IMPL *xp) { const char *myname = "xsasl_dovecot_server_connect"; VSTRING *line_str; VSTREAM *sasl_stream; char *line, *cmd, *mech_name; unsigned int major_version, minor_version; int fd, success; int sec_props; const char *path; if (msg_verbose) msg_info("%s: Connecting", myname); /* * Not documented, but necessary for testing. */ path = xp->socket_path; if (strncmp(path, "inet:", 5) == 0) { fd = inet_connect(path + 5, BLOCKING, AUTH_TIMEOUT); } else { if (strncmp(path, "unix:", 5) == 0) path += 5; fd = unix_connect(path, BLOCKING, AUTH_TIMEOUT); } if (fd < 0) { msg_warn("SASL: Connect to %s failed: %m", xp->socket_path); return (-1); } sasl_stream = vstream_fdopen(fd, O_RDWR); vstream_control(sasl_stream, VSTREAM_CTL_PATH, xp->socket_path, VSTREAM_CTL_TIMEOUT, AUTH_TIMEOUT, VSTREAM_CTL_END); /* XXX Encapsulate for logging. */ vstream_fprintf(sasl_stream, "VERSION\t%u\t%u\n" "CPID\t%u\n", AUTH_PROTOCOL_MAJOR_VERSION, AUTH_PROTOCOL_MINOR_VERSION, (unsigned int) getpid()); if (vstream_fflush(sasl_stream) == VSTREAM_EOF) { msg_warn("SASL: Couldn't send handshake: %m"); return (-1); } success = 0; line_str = vstring_alloc(256); /* XXX Encapsulate for logging. */ while (vstring_get_nonl(line_str, sasl_stream) != VSTREAM_EOF) { line = vstring_str(line_str); if (msg_verbose) msg_info("%s: auth reply: %s", myname, line); cmd = line; line = split_at(line, '\t'); if (strcmp(cmd, "VERSION") == 0) { if (sscanf(line, "%u\t%u", &major_version, &minor_version) != 2) { msg_warn("SASL: Protocol version error"); break; } if (major_version != AUTH_PROTOCOL_MAJOR_VERSION) { /* Major version is different from ours. */ msg_warn("SASL: Protocol version mismatch (%d vs. %d)", major_version, AUTH_PROTOCOL_MAJOR_VERSION); break; } } else if (strcmp(cmd, "MECH") == 0 && line != NULL) { mech_name = line; line = split_at(line, '\t'); if (line != 0) { sec_props = name_mask_delim_opt(myname, xsasl_dovecot_serv_sec_props, line, "\t", NAME_MASK_ANY_CASE | NAME_MASK_IGNORE); if ((sec_props & SEC_PROPS_PRIVATE) != 0) continue; } else sec_props = 0; xsasl_dovecot_server_mech_append(&xp->mechanism_list, mech_name, sec_props); } else if (strcmp(cmd, "DONE") == 0) { /* Handshake finished. */ success = 1; break; } else { /* ignore any unknown commands */ } } vstring_free(line_str); if (!success) { /* handshake failed */ (void) vstream_fclose(sasl_stream); return (-1); } xp->sasl_stream = sasl_stream; return (0); }
static int xsasl_dovecot_server_connect(XSASL_DOVECOT_SERVER_IMPL *xp) { const char *myname = "xsasl_dovecot_server_connect"; VSTRING *line_str; VSTREAM *sasl_stream; char *line, *cmd, *mech_name; unsigned int major_version, minor_version; int fd, success, have_mech_line; int sec_props; const char *path; if (msg_verbose) msg_info("%s: Connecting", myname); /* * Not documented, but necessary for testing. */ path = xp->socket_path; if (strncmp(path, "inet:", 5) == 0) { fd = inet_connect(path + 5, BLOCKING, AUTH_TIMEOUT); } else { if (strncmp(path, "unix:", 5) == 0) path += 5; fd = unix_connect(path, BLOCKING, AUTH_TIMEOUT); } if (fd < 0) { msg_warn("SASL: Connect to %s failed: %m", xp->socket_path); return (-1); } sasl_stream = vstream_fdopen(fd, O_RDWR); vstream_control(sasl_stream, CA_VSTREAM_CTL_PATH(xp->socket_path), CA_VSTREAM_CTL_TIMEOUT(AUTH_TIMEOUT), CA_VSTREAM_CTL_END); /* XXX Encapsulate for logging. */ vstream_fprintf(sasl_stream, "VERSION\t%u\t%u\n" "CPID\t%u\n", AUTH_PROTOCOL_MAJOR_VERSION, AUTH_PROTOCOL_MINOR_VERSION, (unsigned int) getpid()); if (vstream_fflush(sasl_stream) == VSTREAM_EOF) { msg_warn("SASL: Couldn't send handshake: %m"); return (-1); } success = 0; have_mech_line = 0; line_str = vstring_alloc(256); /* XXX Encapsulate for logging. */ while (vstring_get_nonl(line_str, sasl_stream) != VSTREAM_EOF) { line = vstring_str(line_str); if (msg_verbose) msg_info("%s: auth reply: %s", myname, line); cmd = line; line = split_at(line, '\t'); if (strcmp(cmd, "VERSION") == 0) { if (sscanf(line, "%u\t%u", &major_version, &minor_version) != 2) { msg_warn("SASL: Protocol version error"); break; } if (major_version != AUTH_PROTOCOL_MAJOR_VERSION) { /* Major version is different from ours. */ msg_warn("SASL: Protocol version mismatch (%d vs. %d)", major_version, AUTH_PROTOCOL_MAJOR_VERSION); break; } } else if (strcmp(cmd, "MECH") == 0 && line != NULL) { mech_name = line; have_mech_line = 1; line = split_at(line, '\t'); if (line != 0) { sec_props = name_mask_delim_opt(myname, xsasl_dovecot_serv_sec_props, line, "\t", NAME_MASK_ANY_CASE | NAME_MASK_IGNORE); if ((sec_props & SEC_PROPS_PRIVATE) != 0) continue; } else sec_props = 0; xsasl_dovecot_server_mech_append(&xp->mechanism_list, mech_name, sec_props); } else if (strcmp(cmd, "SPID") == 0) { /* * Unfortunately the auth protocol handshake wasn't designed well * to differentiate between auth-client/userdb/master. * auth-userdb and auth-master send VERSION + SPID lines only and * nothing afterwards, while auth-client sends VERSION + MECH + * SPID + CUID + more. The simplest way that we can determine if * we've connected to the correct socket is to see if MECH line * exists or not (alternatively we'd have to have a small timeout * after SPID to see if CUID is sent or not). */ if (!have_mech_line) { msg_warn("SASL: Connected to wrong auth socket (auth-master instead of auth-client)"); break; } } else if (strcmp(cmd, "DONE") == 0) { /* Handshake finished. */ success = 1; break; } else { /* ignore any unknown commands */ } } vstring_free(line_str); if (!success) { /* handshake failed */ (void) vstream_fclose(sasl_stream); return (-1); } xp->sasl_stream = sasl_stream; return (0); }
void dict_open_dlinfo(const char *path) { char *myname="dict_open_dlinfo"; VSTREAM *conf_fp=vstream_fopen(path,O_RDONLY,0); VSTRING *buf = vstring_alloc(100); char *cp; ARGV *argv; MVECT vector; int nelm=0; int linenum=0; dict_dlinfo=(DLINFO*)mvect_alloc(&vector,sizeof(DLINFO),3,NULL,NULL); if (!conf_fp) { msg_warn("%s: cannot open %s. No dynamic maps will be allowed.", myname, path); } else { while (vstring_get_nonl(buf,conf_fp) != VSTREAM_EOF) { cp = vstring_str(buf); linenum++; if (*cp == '#' || *cp == '\0') continue; argv = argv_split(cp, " \t"); if (argv->argc != 3 && argv->argc != 4) { msg_fatal("%s: Expected \"pattern .so-name open-function [mkmap-function]\" at line %d", myname, linenum); } if (STREQ(argv->argv[0],"*")) { msg_warn("%s: wildcard dynamic map entry no longer supported.", myname); continue; } if (argv->argv[1][0] != '/') { msg_fatal("%s: .so name must begin with a \"/\" at line %d", myname, linenum); } if (nelm >= vector.nelm) { dict_dlinfo=(DLINFO*)mvect_realloc(&vector,vector.nelm+3); } dict_dlinfo[nelm].pattern = mystrdup(argv->argv[0]); dict_dlinfo[nelm].soname = mystrdup(argv->argv[1]); dict_dlinfo[nelm].openfunc = mystrdup(argv->argv[2]); if (argv->argc==4) dict_dlinfo[nelm].mkmapfunc = mystrdup(argv->argv[3]); else dict_dlinfo[nelm].mkmapfunc = NULL; nelm++; argv_free(argv); } } if (nelm >= vector.nelm) { dict_dlinfo=(DLINFO*)mvect_realloc(&vector,vector.nelm+1); } dict_dlinfo[nelm].pattern = NULL; dict_dlinfo[nelm].soname = NULL; dict_dlinfo[nelm].openfunc = NULL; dict_dlinfo[nelm].mkmapfunc = NULL; if (conf_fp) vstream_fclose(conf_fp); vstring_free(buf); }
BOUNCE_LOG *bounce_log_read(BOUNCE_LOG *bp) { char *recipient; char *text; char *cp; int state; /* * Our trivial logfile parser state machine. */ #define START 0 /* still searching */ #define FOUND 1 /* in logfile entry */ /* * Initialize. */ state = START; bp->recipient = "(unavailable)"; bp->orig_rcpt = 0; bp->rcpt_offset = 0; bp->dsn_status = "(unavailable)"; bp->dsn_action = "(unavailable)"; bp->text = "(unavailable)"; /* * Support mixed logfile formats to make transitions easier. The same * file can start with old-style records and end with new-style records. * With backwards compatibility, we even have old format followed by new * format within the same logfile entry! */ while ((vstring_get_nonl(bp->buf, bp->fp) != VSTREAM_EOF)) { /* * Logfile entries are separated by blank lines. Even the old ad-hoc * logfile format has a blank line after the last record. This means * we can safely use blank lines to detect the start and end of * logfile entries. */ if (STR(bp->buf)[0] == 0) { if (state == FOUND) return (bp); state = START; continue; } /* * Sanitize. XXX This needs to be done more carefully with new-style * logfile entries. */ cp = printable(STR(bp->buf), '?'); if (state == START) state = FOUND; /* * New style logfile entries are in "name = value" format. */ if (ISALNUM(*cp)) { const char *err; char *name; char *value; /* * Split into name and value. */ if ((err = split_nameval(cp, &name, &value)) != 0) { msg_warn("%s: malformed record: %s", VSTREAM_PATH(bp->fp), err); continue; } /* * Save attribute value. */ if (STREQ(name, MAIL_ATTR_RECIP)) { bp->recipient = STR(vstring_strcpy(bp->rcpt_buf, *value ? value : "(MAILER-DAEMON)")); } else if (STREQ(name, MAIL_ATTR_ORCPT)) { bp->orig_rcpt = STR(vstring_strcpy(bp->orcp_buf, *value ? value : "(MAILER-DAEMON)")); } else if (STREQ(name, MAIL_ATTR_OFFSET)) { bp->rcpt_offset = atol(value); } else if (STREQ(name, MAIL_ATTR_STATUS)) { bp->dsn_status = STR(vstring_strcpy(bp->status_buf, value)); } else if (STREQ(name, MAIL_ATTR_ACTION)) { bp->dsn_action = STR(vstring_strcpy(bp->action_buf, value)); } else if (STREQ(name, MAIL_ATTR_WHY)) { bp->text = STR(vstring_strcpy(bp->text_buf, value)); } else { msg_warn("%s: unknown attribute name: %s, ignored", VSTREAM_PATH(bp->fp), name); } continue; } /* * Old-style logfile record. Find the recipient address. */ if (*cp != '<') { msg_warn("%s: malformed record: %.30s...", VSTREAM_PATH(bp->fp), cp); continue; } recipient = cp + 1; if ((cp = strstr(recipient, ">: ")) == 0) { msg_warn("%s: malformed record: %.30s...", VSTREAM_PATH(bp->fp), cp); continue; } *cp = 0; vstring_strcpy(bp->rcpt_buf, *recipient ? recipient : "(MAILER-DAEMON)"); bp->recipient = STR(bp->rcpt_buf); /* * Find the text that explains why mail was not deliverable. */ text = cp + 2; while (*text && ISSPACE(*text)) text++; vstring_strcpy(bp->text_buf, text); bp->text = STR(bp->text_buf); /* * Add compatibility status and action info, to make up for data that * was not stored in old-style bounce logfiles. */ bp->dsn_status = bp->compat_status; bp->dsn_action = bp->compat_action; } return (0); }