static void out_cb(void *context, int rec_type, const char *buf, ssize_t len, off_t offset) { const HBC_TEST_CONTEXT *dp = (HBC_TEST_CONTEXT *) context; vstream_fwrite(dp->fp, buf, len); VSTREAM_PUTC('\n', dp->fp); vstream_fflush(dp->fp); }
void netstring_put(VSTREAM *stream, const char *data, ssize_t len) { const char *myname = "netstring_put"; if (msg_verbose > 1) msg_info("%s: write netstring len %ld data %.*s", myname, (long) len, (int) (len < 30 ? len : 30), data); vstream_fprintf(stream, "%ld:", (long) len); vstream_fwrite(stream, data, len); VSTREAM_PUTC(',', stream); }
int main(int unused_argc, char **unused_argv) { VSTRING *in = vstring_alloc(10); VSTRING *out = vstring_alloc(10); while (vstring_fgets_nonl(in, VSTREAM_IN)) { unescape(out, vstring_str(in)); vstream_fwrite(VSTREAM_OUT, vstring_str(out), VSTRING_LEN(out)); } vstream_fflush(VSTREAM_OUT); exit(0); }
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(int argc, char **argv) { VSTRING *in = vstring_alloc(10); VSTRING *out = vstring_alloc(10); int un_escape = 1; if (argc > 2 || (argc > 1 && (un_escape = strcmp(argv[1], "-e"))) != 0) msg_fatal("usage: %s [-e (escape)]", argv[0]); if (un_escape) { while (vstring_fgets_nonl(in, VSTREAM_IN)) { unescape(out, vstring_str(in)); vstream_fwrite(VSTREAM_OUT, vstring_str(out), VSTRING_LEN(out)); } } else { while (vstring_fgets(in, VSTREAM_IN)) { escape(out, vstring_str(in), VSTRING_LEN(in)); vstream_fwrite(VSTREAM_OUT, vstring_str(out), VSTRING_LEN(out)); } } vstream_fflush(VSTREAM_OUT); exit(0); }
int memcache_fwrite(VSTREAM *stream, const char *cp, ssize_t todo) { /* * Sanity check. */ if (todo < 0) msg_panic("memcache_fwrite: negative todo %ld", (long) todo); /* * Do the I/O. */ if (msg_verbose) msg_info("%s write: %.*s", VSTREAM_PATH(stream), (int) todo, cp); if (vstream_fwrite(stream, cp, todo) != todo || vstream_fputs("\r\n", stream) == VSTREAM_EOF) return (-1); else return (0); }
main(int unused_argc, char **unused_argv) { VSTRING *raw = vstring_alloc(BUFLEN); VSTRING *hex = vstring_alloc(100); int len; while ((len = read_buf(VSTREAM_IN, raw)) > 0) { hex_quote(hex, STR(raw)); if (hex_unquote(raw, STR(hex)) == 0) msg_fatal("bad input: %.100s", STR(hex)); if (LEN(raw) != len) msg_fatal("len %d != raw len %d", len, LEN(raw)); if (vstream_fwrite(VSTREAM_OUT, STR(raw), LEN(raw)) != LEN(raw)) msg_fatal("write error: %m"); } vstream_fflush(VSTREAM_OUT); vstring_free(raw); vstring_free(hex); return (0); }
int main(int unused_argc, char **unused_argv) { VSTRING *unquoted = vstring_alloc(BUFLEN); VSTRING *quoted = vstring_alloc(100); ssize_t len; while ((len = read_buf(VSTREAM_IN, unquoted)) > 0) { xtext_quote(quoted, STR(unquoted), "+="); if (xtext_unquote(unquoted, STR(quoted)) == 0) msg_fatal("bad input: %.100s", STR(quoted)); if (LEN(unquoted) != len) msg_fatal("len %ld != unquoted len %ld", (long) len, (long) LEN(unquoted)); if (vstream_fwrite(VSTREAM_OUT, STR(unquoted), LEN(unquoted)) != LEN(unquoted)) msg_fatal("write error: %m"); } vstream_fflush(VSTREAM_OUT); vstring_free(unquoted); vstring_free(quoted); return (0); }
void smtp_fwrite(const char *cp, int todo, VSTREAM *stream) { unsigned err; if (todo < 0) msg_panic("smtp_fwrite: negative todo %d", todo); /* * Do the I/O, protected against timeout. */ smtp_timeout_reset(stream); err = (vstream_fwrite(stream, cp, todo) != todo); smtp_timeout_detect(stream); /* * See if there was a problem. */ if (err != 0) { if (msg_verbose) msg_info("smtp_fwrite: EOF"); vstream_longjmp(stream, SMTP_ERR_EOF); } }
static void show_queue(void) { const char *errstr; char buf[VSTREAM_BUFSIZE]; VSTREAM *showq; int n; uid_t uid = getuid(); if (uid != 0 && uid != var_owner_uid && (errstr = check_user_acl_byuid(VAR_SHOWQ_ACL, var_showq_acl, uid)) != 0) msg_fatal_status(EX_NOPERM, "User %s(%ld) is not allowed to view the mail queue", errstr, (long) uid); /* * Connect to the show queue service. Terminate silently when piping into * a program that terminates early. */ if ((showq = mail_connect(MAIL_CLASS_PUBLIC, var_showq_service, BLOCKING)) != 0) { while ((n = vstream_fread(showq, buf, sizeof(buf))) > 0) { if (vstream_fwrite(VSTREAM_OUT, buf, n) != n || vstream_fflush(VSTREAM_OUT) != 0) { if (errno == EPIPE) break; msg_fatal("write error: %m"); } } if (vstream_fclose(showq) && errno != EPIPE) msg_warn("close: %m"); } /* * Don't assume that the mail system is down when the user has * insufficient permission to access the showq socket. */ else if (errno == EACCES) { msg_fatal_status(EX_SOFTWARE, "Connect to the %s %s service: %m", var_mail_name, var_showq_service); } /* * When the mail system is down, the superuser can still access the queue * directly. Just run the showq program in stand-alone mode. */ else if (geteuid() == 0) { ARGV *argv; int stat; msg_warn("Mail system is down -- accessing queue directly"); argv = argv_alloc(6); argv_add(argv, var_showq_service, "-u", "-S", (char *) 0); for (n = 0; n < msg_verbose; n++) argv_add(argv, "-v", (char *) 0); argv_terminate(argv); stat = mail_run_foreground(var_daemon_dir, argv->argv); argv_free(argv); if (stat != 0) msg_fatal_status(stat < 0 ? EX_OSERR : EX_SOFTWARE, "Error running %s/%s", var_daemon_dir, argv->argv[0]); } /* * When the mail system is down, unprivileged users are stuck, because by * design the mail system contains no set_uid programs. The only way for * an unprivileged user to cross protection boundaries is to talk to the * showq daemon. */ else { msg_fatal_status(EX_UNAVAILABLE, "Queue report unavailable - mail system is down"); } }
static void postcat(VSTREAM *fp, VSTRING *buffer, int flags) { int prev_type = 0; int rec_type; struct timeval tv; time_t time; int ch; off_t offset; const char *error_text; char *attr_name; char *attr_value; int rec_flags = (msg_verbose ? REC_FLAG_NONE : REC_FLAG_DEFAULT); int state; /* state machine, input type */ int do_print; /* state machine, output control */ long data_offset; /* state machine, read optimization */ long data_size; /* state machine, read optimization */ #define TEXT_RECORD(rec_type) \ (rec_type == REC_TYPE_CONT || rec_type == REC_TYPE_NORM) /* * See if this is a plausible file. */ if ((ch = VSTREAM_GETC(fp)) != VSTREAM_EOF) { if (!strchr(REC_TYPE_ENVELOPE, ch)) { msg_warn("%s: input is not a valid queue file", VSTREAM_PATH(fp)); return; } vstream_ungetc(fp, ch); } /* * Other preliminaries. */ if (flags & PC_FLAG_PRINT_ENV) vstream_printf("*** ENVELOPE RECORDS %s ***\n", VSTREAM_PATH(fp)); state = PC_STATE_ENV; do_print = (flags & PC_FLAG_PRINT_ENV); data_offset = data_size = -1; /* * Now look at the rest. */ for (;;) { if (flags & PC_FLAG_PRINT_OFFSET) offset = vstream_ftell(fp); rec_type = rec_get_raw(fp, buffer, 0, rec_flags); if (rec_type == REC_TYPE_ERROR) msg_fatal("record read error"); if (rec_type == REC_TYPE_EOF) break; /* * First inspect records that have side effects on the (envelope, * header, body) state machine or on the record reading order. * * XXX Comments marked "Optimization:" identify subtle code that will * likely need to be revised when the queue file organization is * changed. */ #define PRINT_MARKER(flags, fp, offset, type, text) do { \ if ((flags) & PC_FLAG_PRINT_OFFSET) \ vstream_printf("%9lu ", (unsigned long) (offset)); \ if (flags & PC_FLAG_PRINT_RTYPE_DEC) \ vstream_printf("%3d ", (type)); \ vstream_printf("*** %s %s ***\n", (text), VSTREAM_PATH(fp)); \ vstream_fflush(VSTREAM_OUT); \ } while (0) #define PRINT_RECORD(flags, offset, type, value) do { \ if ((flags) & PC_FLAG_PRINT_OFFSET) \ vstream_printf("%9lu ", (unsigned long) (offset)); \ if (flags & PC_FLAG_PRINT_RTYPE_DEC) \ vstream_printf("%3d ", (type)); \ vstream_printf("%s: %s\n", rec_type_name(rec_type), (value)); \ vstream_fflush(VSTREAM_OUT); \ } while (0) if (TEXT_RECORD(rec_type)) { /* This is wrong when the message starts with whitespace. */ if (state == PC_STATE_HEADER && (flags & (PC_MASK_PRINT_TEXT)) && prev_type != REC_TYPE_CONT && TEXT_RECORD(rec_type) && !(is_header(STR(buffer)) || IS_SPACE_TAB(STR(buffer)[0]))) { /* Update the state machine. */ state = PC_STATE_BODY; do_print = (flags & PC_FLAG_PRINT_BODY); /* Optimization: terminate if nothing left to print. */ if (do_print == 0 && (flags & PC_FLAG_PRINT_ENV) == 0) break; /* Optimization: skip to extracted segment marker. */ if (do_print == 0 && (flags & PC_FLAG_PRINT_ENV) && data_offset >= 0 && data_size >= 0 && vstream_fseek(fp, data_offset + data_size, SEEK_SET) < 0) msg_fatal("seek error: %m"); } /* Optional output happens further down below. */ } else if (rec_type == REC_TYPE_MESG) { /* Sanity check. */ if (state != PC_STATE_ENV) msg_warn("%s: out-of-order message content marker", VSTREAM_PATH(fp)); /* Optional output. */ if (flags & PC_FLAG_PRINT_ENV) PRINT_MARKER(flags, fp, offset, rec_type, "MESSAGE CONTENTS"); /* Optimization: skip to extracted segment marker. */ if ((flags & PC_MASK_PRINT_TEXT) == 0 && data_offset >= 0 && data_size >= 0 && vstream_fseek(fp, data_offset + data_size, SEEK_SET) < 0) msg_fatal("seek error: %m"); /* Update the state machine, even when skipping. */ state = PC_STATE_HEADER; do_print = (flags & PC_FLAG_PRINT_HEADER); continue; } else if (rec_type == REC_TYPE_XTRA) { /* Sanity check. */ if (state != PC_STATE_HEADER && state != PC_STATE_BODY) msg_warn("%s: out-of-order extracted segment marker", VSTREAM_PATH(fp)); /* Optional output (terminate preceding header/body line). */ if (do_print && prev_type == REC_TYPE_CONT) VSTREAM_PUTCHAR('\n'); if (flags & PC_FLAG_PRINT_ENV) PRINT_MARKER(flags, fp, offset, rec_type, "HEADER EXTRACTED"); /* Update the state machine. */ state = PC_STATE_ENV; do_print = (flags & PC_FLAG_PRINT_ENV); /* Optimization: terminate if nothing left to print. */ if (do_print == 0) break; continue; } else if (rec_type == REC_TYPE_END) { /* Sanity check. */ if (state != PC_STATE_ENV) msg_warn("%s: out-of-order message end marker", VSTREAM_PATH(fp)); /* Optional output. */ if (flags & PC_FLAG_PRINT_ENV) PRINT_MARKER(flags, fp, offset, rec_type, "MESSAGE FILE END"); /* Terminate the state machine. */ break; } else if (rec_type == REC_TYPE_PTR) { /* Optional output. */ /* This record type is exposed only with '-v'. */ if (do_print) PRINT_RECORD(flags, offset, rec_type, STR(buffer)); /* Skip to the pointer's target record. */ if (rec_goto(fp, STR(buffer)) == REC_TYPE_ERROR) msg_fatal("bad pointer record, or input is not seekable"); continue; } else if (rec_type == REC_TYPE_SIZE) { /* Optional output (here before we update the state machine). */ if (do_print) PRINT_RECORD(flags, offset, rec_type, STR(buffer)); /* Read the message size/offset for the state machine optimizer. */ if (data_size >= 0 || data_offset >= 0) { msg_warn("file contains multiple size records"); } else { if (sscanf(STR(buffer), "%ld %ld", &data_size, &data_offset) != 2 || data_offset <= 0 || data_size <= 0) msg_fatal("invalid size record: %.100s", STR(buffer)); /* Optimization: skip to the message header. */ if ((flags & PC_FLAG_PRINT_ENV) == 0) { if (vstream_fseek(fp, data_offset, SEEK_SET) < 0) msg_fatal("seek error: %m"); /* Update the state machine. */ state = PC_STATE_HEADER; do_print = (flags & PC_FLAG_PRINT_HEADER); } } continue; } /* * Don't inspect side-effect-free records that aren't printed. */ if (do_print == 0) continue; if (flags & PC_FLAG_PRINT_OFFSET) vstream_printf("%9lu ", (unsigned long) offset); if (flags & PC_FLAG_PRINT_RTYPE_DEC) vstream_printf("%3d ", rec_type); switch (rec_type) { case REC_TYPE_TIME: REC_TYPE_TIME_SCAN(STR(buffer), tv); time = tv.tv_sec; vstream_printf("%s: %s", rec_type_name(rec_type), asctime(localtime(&time))); break; case REC_TYPE_WARN: REC_TYPE_WARN_SCAN(STR(buffer), time); vstream_printf("%s: %s", rec_type_name(rec_type), asctime(localtime(&time))); break; case REC_TYPE_CONT: /* REC_TYPE_FILT collision */ if (state == PC_STATE_ENV) vstream_printf("%s: ", rec_type_name(rec_type)); else if (msg_verbose) vstream_printf("unterminated_text: "); vstream_fwrite(VSTREAM_OUT, STR(buffer), LEN(buffer)); if (state == PC_STATE_ENV || msg_verbose || (flags & PC_FLAG_PRINT_OFFSET) != 0) { rec_type = 0; VSTREAM_PUTCHAR('\n'); } break; case REC_TYPE_NORM: if (msg_verbose) vstream_printf("%s: ", rec_type_name(rec_type)); vstream_fwrite(VSTREAM_OUT, STR(buffer), LEN(buffer)); VSTREAM_PUTCHAR('\n'); break; case REC_TYPE_DTXT: /* This record type is exposed only with '-v'. */ vstream_printf("%s: ", rec_type_name(rec_type)); vstream_fwrite(VSTREAM_OUT, STR(buffer), LEN(buffer)); VSTREAM_PUTCHAR('\n'); break; case REC_TYPE_ATTR: error_text = split_nameval(STR(buffer), &attr_name, &attr_value); if (error_text != 0) { msg_warn("%s: malformed attribute: %s: %.100s", VSTREAM_PATH(fp), error_text, STR(buffer)); break; } if (strcmp(attr_name, MAIL_ATTR_CREATE_TIME) == 0) { time = atol(attr_value); vstream_printf("%s: %s", MAIL_ATTR_CREATE_TIME, asctime(localtime(&time))); } else { vstream_printf("%s: %s=%s\n", rec_type_name(rec_type), attr_name, attr_value); } break; default: vstream_printf("%s: %s\n", rec_type_name(rec_type), STR(buffer)); break; } prev_type = rec_type; /* * In case the next record is broken. */ vstream_fflush(VSTREAM_OUT); } }
int attr_vprint0(VSTREAM *fp, int flags, va_list ap) { const char *myname = "attr_print0"; int attr_type; char *attr_name; unsigned int_val; unsigned long long_val; char *str_val; HTABLE_INFO **ht_info_list; HTABLE_INFO **ht; ssize_t len_val; static VSTRING *base64_buf; ATTR_PRINT_SLAVE_FN print_fn; void *print_arg; /* * Sanity check. */ if (flags & ~ATTR_FLAG_ALL) msg_panic("%s: bad flags: 0x%x", myname, flags); /* * Iterate over all (type, name, value) triples, and produce output on * the fly. */ while ((attr_type = va_arg(ap, int)) != ATTR_TYPE_END) { switch (attr_type) { case ATTR_TYPE_INT: attr_name = va_arg(ap, char *); vstream_fwrite(fp, attr_name, strlen(attr_name) + 1); int_val = va_arg(ap, int); vstream_fprintf(fp, "%u", (unsigned) int_val); VSTREAM_PUTC('\0', fp); if (msg_verbose) msg_info("send attr %s = %u", attr_name, int_val); break; case ATTR_TYPE_LONG: attr_name = va_arg(ap, char *); vstream_fwrite(fp, attr_name, strlen(attr_name) + 1); long_val = va_arg(ap, unsigned long); vstream_fprintf(fp, "%lu", (unsigned long) long_val); VSTREAM_PUTC('\0', fp); if (msg_verbose) msg_info("send attr %s = %lu", attr_name, long_val); break; case ATTR_TYPE_STR: attr_name = va_arg(ap, char *); vstream_fwrite(fp, attr_name, strlen(attr_name) + 1); str_val = va_arg(ap, char *); vstream_fwrite(fp, str_val, strlen(str_val) + 1); if (msg_verbose) msg_info("send attr %s = %s", attr_name, str_val); break; case ATTR_TYPE_DATA: attr_name = va_arg(ap, char *); vstream_fwrite(fp, attr_name, strlen(attr_name) + 1); len_val = va_arg(ap, ssize_t); str_val = va_arg(ap, char *); if (base64_buf == 0) base64_buf = vstring_alloc(10); base64_encode(base64_buf, str_val, len_val); vstream_fwrite(fp, STR(base64_buf), LEN(base64_buf) + 1); if (msg_verbose) msg_info("send attr %s = [data %ld bytes]", attr_name, (long) len_val); break; case ATTR_TYPE_FUNC: print_fn = va_arg(ap, ATTR_PRINT_SLAVE_FN); print_arg = va_arg(ap, void *); print_fn(attr_print0, fp, flags | ATTR_FLAG_MORE, print_arg); break; case ATTR_TYPE_HASH: ht_info_list = htable_list(va_arg(ap, HTABLE *)); for (ht = ht_info_list; *ht; ht++) { vstream_fwrite(fp, ht[0]->key, strlen(ht[0]->key) + 1); vstream_fwrite(fp, ht[0]->value, strlen(ht[0]->value) + 1); if (msg_verbose) msg_info("send attr name %s value %s", ht[0]->key, (char *) ht[0]->value); } myfree((void *) ht_info_list); break; default: msg_panic("%s: unknown type code: %d", myname, attr_type); } } if ((flags & ATTR_FLAG_MORE) == 0) VSTREAM_PUTC('\0', fp); return (vstream_ferror(fp)); }