static void acl_xml_node_reset(ACL_XML_NODE *node) { ACL_VSTRING_RESET(node->ltag); ACL_VSTRING_RESET(node->rtag); ACL_VSTRING_RESET(node->text); ACL_VSTRING_TERMINATE(node->ltag); ACL_VSTRING_TERMINATE(node->rtag); ACL_VSTRING_TERMINATE(node->text); node->id = NULL; if (node->attr_list) acl_array_clean(node->attr_list, (void (*)(void*)) acl_xml_attr_free); node->parent = NULL; acl_ring_init(&node->children); node->depth = 0; acl_ring_init(&node->node); node->curr_attr = NULL; node->quote = 0; node->last_ch = 0; node->nlt = 0; node->meta[0] = 0; node->flag = 0; node->status = ACL_XML_S_NXT; }
static void __hdr_reset(HTTP_HDR_REQ *hh, int clear_cookies) { hh->port = 80; hh->method[0] = 0; hh->host[0] = 0; hh->flag = 0; if (hh->url_part) { ACL_VSTRING_RESET(hh->url_part); ACL_VSTRING_TERMINATE(hh->url_part); } if (hh->url_path) { ACL_VSTRING_RESET(hh->url_path); ACL_VSTRING_TERMINATE(hh->url_path); } if (hh->url_params) { ACL_VSTRING_RESET(hh->url_params); ACL_VSTRING_TERMINATE(hh->url_params); } if (hh->file_path) { ACL_VSTRING_RESET(hh->file_path); ACL_VSTRING_TERMINATE(hh->file_path); } if (hh->params_table) acl_htable_reset(hh->params_table, __request_args_free_fn); if (clear_cookies && hh->cookies_table) acl_htable_reset(hh->cookies_table, __cookies_args_free_fn); }
static void test_buffer_gets(void) { ACL_VSTRING *buf = acl_vstring_alloc(256); const ACL_VSTRING *pbuf; const char *src; size_t i, n; unsigned char ch = (unsigned char) -1; for (i = 0; i < sizeof(string_tab) / sizeof(char*); i++) { printf("%s", string_tab[i]); } printf("------------------------------------------------------------\r\n"); for (i = 0; i < sizeof(string_tab) / sizeof(char*); i++) { src = string_tab[i]; n = strlen(src); while (1) { const char *psrc_saved = src; pbuf = acl_buffer_gets_nonl(buf, &src, n); if (pbuf) { printf("%s\n", STR(pbuf)); ACL_VSTRING_RESET(buf); n -= src - psrc_saved; if (n == 0) break; } else break; } } printf("------------------------------------------------------------\r\n"); for (i = 0; i < sizeof(string_tab) / sizeof(char*); i++) { src = string_tab[i]; n = strlen(src); while (1) { const char *psrc_saved = src; pbuf = acl_buffer_gets(buf, &src, n); if (pbuf) { printf("%s", STR(pbuf)); ACL_VSTRING_RESET(buf); n -= src - psrc_saved; if (n == 0) break; } else break; } } acl_vstring_free(buf); printf(">>>>>>>>>max ch: %d\n", ch); }
ACL_VSTRING *acl_hex_decode(ACL_VSTRING *result, const char *in, int len) { const unsigned char *cp; int count; unsigned int hex; unsigned int bin; ACL_VSTRING_RESET(result); for (cp = UCHAR_PTR(in), count = len; count > 0; cp += 2, count -= 2) { if (count < 2) return (0); hex = cp[0]; if (hex >= '0' && hex <= '9') bin = (hex - '0') << 4; else if (hex >= 'A' && hex <= 'F') bin = (hex - 'A' + 10) << 4; else if (hex >= 'a' && hex <= 'f') bin = (hex - 'a' + 10) << 4; else return (0); hex = cp[1]; if (hex >= '0' && hex <= '9') bin |= (hex - '0') ; else if (hex >= 'A' && hex <= 'F') bin |= (hex - 'A' + 10) ; else if (hex >= 'a' && hex <= 'f') bin |= (hex - 'a' + 10) ; else return (0); ACL_VSTRING_ADDCH(result, bin); } ACL_VSTRING_TERMINATE(result); return (result); }
void acl_token_name(const ACL_TOKEN *token, ACL_VSTRING *buf) { int i, n; char *ptr, *pend, ch; const ACL_TOKEN *token_iter; ACL_VSTRING_RESET(buf); token_iter = token; while (token_iter && token_iter->parent != NULL) { ACL_VSTRING_ADDCH(buf, token_iter->ch); token_iter = token_iter->parent; } ACL_VSTRING_TERMINATE(buf); pend = acl_vstring_end(buf) - 1; ptr = STR(buf); i = 0; n = (int) (pend - ptr + 1) / 2; while (i < n) { ch = *ptr; *ptr = *pend; *pend = ch; i++; ptr++; pend--; } }
static void incr_string(ACL_VSTRING *vp, int len, const char* s, int debug) { int i; printf("max: %ld, len: %ld, cnt: %ld\r\n", (long) vp->maxlen, vp->vbuf.len, vp->vbuf.cnt); for (i = 0; i < len; i++) ACL_VSTRING_ADDCH(vp, 'x'); if (s && *s) acl_vstring_sprintf_append(vp, "%s", s); else ACL_VSTRING_TERMINATE(vp); if (debug) printf("[%s]\r\n", acl_vstring_str(vp)); printf("strlen: %ld, ACL_VSTRING_LEN: %ld, max: %ld\r\n", (long) strlen(acl_vstring_str(vp)), (long) ACL_VSTRING_LEN(vp), (long) vp->maxlen); printf("Enter any key to continue ...\r\n\r\n"); getchar(); ACL_VSTRING_RESET(vp); ACL_VSTRING_TERMINATE(vp); }
static void token_tree_test(const char *tokens, const char *test_tab[]) { ACL_TOKEN *token_tree; ACL_TOKEN *token; const char *ptr, *psaved; ACL_VSTRING *buf = acl_vstring_alloc(256); int i; token_tree = acl_token_tree_create(tokens); acl_token_tree_print(token_tree); for (i = 0; test_tab[i] != NULL; i++) { ptr = psaved = test_tab[i]; token = acl_token_tree_match(token_tree, &ptr, ";", NULL); if (token) { ACL_VSTRING_RESET(buf); acl_token_name(token, buf); printf("match %s %s, token's name: %s\n", psaved, (token->flag & ACL_TOKEN_F_DENY) ? "DENY" : (token->flag & ACL_TOKEN_F_PASS ? "PASS" : "NONE"), STR(buf)); } else printf("match %s none\n", psaved); } acl_token_tree_destroy(token_tree); acl_vstring_free(buf); }
static int chunked_trailer(ACL_ASTREAM *astream, HTTP_CHAT_CTX *ctx) { HTTP_BODY_NOTIFY notify = ctx->notify.body_notify; void *arg = ctx->arg; ACL_VSTRING *sbuf; char *data; int dlen; sbuf = acl_aio_gets_peek(astream); if (sbuf == NULL) return (0); data = acl_vstring_str(sbuf); dlen = (int) ACL_VSTRING_LEN(sbuf); ACL_VSTRING_RESET(sbuf); ctx->body_len += dlen; if (strcmp(data, "\r\n") == 0 || strcmp(data, "\n") == 0) { DISABLE_READ(astream); if ((dlen = notify(HTTP_CHAT_OK, data, dlen, arg)) < 0) return (-1); return (1); } if (notify(HTTP_CHAT_CHUNK_TRAILER, data, dlen, arg) < 0) return (-1); return (0); }
int tls_scache_lookup(TLS_SCACHE *cp, char *cache_id, ACL_VSTRING *session) { char *hex_data; size_t size; /* * Logging. */ if (cp->verbose) acl_msg_info("lookup %s session id=%s", cp->cache_label, cache_id); /* * Initialize. Don't leak data. */ if (session) ACL_VSTRING_RESET(session); /* * Search the cache database. */ if ((DICT_GET(cp->db, cache_id, strlen(cache_id), &hex_data, &size)) == 0) return (0); /* * Decode entry and delete if expired or malformed. */ if (tls_scache_decode(cp, cache_id, hex_data, (int) strlen(hex_data), session) == 0) { tls_scache_delete(cp, cache_id); acl_myfree(hex_data); return (0); } else { acl_myfree(hex_data); return (1); } }
static void mime_header_line(MIME_NODE *node) { const HEADER_OPTS *header_info; size_t len = LEN(node->buffer); char *ptr = strrchr(STR(node->buffer), '\n'); if (ptr) { *ptr-- = 0; len--; if (ptr > STR(node->buffer)) { if (*ptr == '\r') { *ptr = 0; len--; } } if (len == 0) return; acl_vstring_truncate(node->buffer, len); } header_info = header_opts_find(STR(node->buffer), node->state->key_buffer); if (header_info) { if (header_info->type == HDR_CONTENT_TYPE) mime_content_type(node, header_info); else if (header_info->type == HDR_CONTENT_TRANSFER_ENCODING) mime_content_encoding(node, header_info); else if (node == node->state->root) { /* 说明邮件头 */ if ((header_info->flags & HDR_OPT_RECIP) && (header_info->flags & HDR_OPT_EXTRACT)) { /* 分析收件人地址: To, Cc, Bcc */ mail_rcpt(node, header_info); } else if ((header_info->flags & HDR_OPT_SENDER)) { /* 分析发件人地址: From, Sender, * Replyto, Returnpath */ mail_from(node, header_info); } else if ((header_info->flags & HDR_OPT_SUBJECT)) { mail_subject(node, header_info); } } else if (header_info->type == HDR_CONTENT_DISPOSITION) { mime_content_disposition(node, header_info); } } if (node->header_list) { HEADER_NV *header = header_split(STR(node->buffer)); if (header) node->header_list->push_back(node->header_list, header); } ACL_VSTRING_RESET(node->buffer); /* 清空缓冲区 */ node->last_ch = 0; node->last_lf = 0; }
void charset_conv::update_finish(acl::string* out) { #ifdef HAVE_H_ICONV if (m_pInBuf && LEN(m_pInBuf) > 0 && m_addInvalid) { out->append(STR(m_pInBuf), LEN(m_pInBuf)); ACL_VSTRING_RESET(m_pInBuf); } #endif }
static int chunked_data(ACL_ASTREAM *astream, HTTP_CHAT_CTX *ctx) { HTTP_BODY_NOTIFY notify = ctx->notify.body_notify; void *arg = ctx->arg; ACL_VSTRING *sbuf; char *data; int dlen, ret; if (ctx->chunked) { ret = (int) HTTP_LEN_ROUND(ctx); sbuf = acl_aio_readn_peek(astream, ret); } else if (ctx->hdr->content_length <= 0) { sbuf = acl_aio_read_peek(astream); } else { ret = (int) HTTP_LEN_ROUND(ctx); sbuf = acl_aio_readn_peek(astream, ret); } if (sbuf == NULL) { return (0); } data = acl_vstring_str(sbuf); dlen = (int) ACL_VSTRING_LEN(sbuf); ACL_VSTRING_RESET(sbuf); ctx->body_len += dlen; ctx->read_cnt += dlen; if (ctx->chunk_len > 0 && ctx->read_cnt >= ctx->chunk_len) { if (!ctx->chunked) { /* xxx: 禁止连续读 */ DISABLE_READ(astream); if (notify(HTTP_CHAT_OK, data, dlen, arg) < 0) return (-1); return (1); } if (notify(HTTP_CHAT_DATA, data, dlen, arg) < 0) return (-1); /* 设置标志位开始读取块数据体的分隔行数据 */ ctx->status = CHAT_S_CHUNK_SEP; return (0); } if (notify(HTTP_CHAT_DATA, data, dlen, arg) < 0) return (-1); return (0); }
ACL_VSTRING *acl_hex_encode(ACL_VSTRING *result, const char *in, int len) { const unsigned char *cp; int ch; int count; ACL_VSTRING_RESET(result); for (cp = UCHAR_PTR(in), count = len; count > 0; count--, cp++) { ch = *cp; ACL_VSTRING_ADDCH(result, acl_hex_chars[(ch >> 4) & 0xf]); ACL_VSTRING_ADDCH(result, acl_hex_chars[ch & 0xf]); } ACL_VSTRING_TERMINATE(result); return (result); }
static int hdr_can_read(ACL_ASTREAM *astream, void *context) { HTTP_CHAT_CTX *ctx = (HTTP_CHAT_CTX *) context; HTTP_HDR *hdr = ctx->hdr; HTTP_HDR_NOTIFY notify = ctx->notify.hdr_notify; void *arg = ctx->arg; ACL_VSTRING *sbuf; char *data; int dlen; int ret; while (1) { if ((ret = acl_aio_can_read(astream)) == ACL_VSTREAM_EOF) { notify(HTTP_CHAT_ERR_IO, arg); return (-1); } else if (ret == 0) { break; } sbuf = acl_aio_gets_nonl_peek(astream); if (sbuf == NULL) { break; } data = acl_vstring_str(sbuf); dlen = (int) ACL_VSTRING_LEN(sbuf); ACL_VSTRING_RESET(sbuf); ret = hdr_ready(hdr, data, dlen); switch (ret) { case HTTP_CHAT_CONTINUE: break; case HTTP_CHAT_OK: DISABLE_READ(astream); if (notify(ret, arg) < 0) { return (0); } return (0); default: DISABLE_READ(astream); (void) notify(ret, arg); return (0); } } acl_aio_enable_read(astream, hdr_can_read, ctx); return (0); }
ACL_VSTRING *escape(ACL_VSTRING *result, const char *data, ssize_t len) { int ch; ACL_VSTRING_RESET(result); while (len-- > 0) { ch = *UCHAR(data++); if (ACL_ISASCII(ch)) { if (ACL_ISPRINT(ch)) { if (ch == '\\') ACL_VSTRING_ADDCH(result, ch); ACL_VSTRING_ADDCH(result, ch); continue; } else if (ch == '\a') { /* \a -> audible bell */ acl_vstring_strcat(result, "\\a"); continue; } else if (ch == '\b') { /* \b -> backspace */ acl_vstring_strcat(result, "\\b"); continue; } else if (ch == '\f') { /* \f -> formfeed */ acl_vstring_strcat(result, "\\f"); continue; } else if (ch == '\n') { /* \n -> newline */ acl_vstring_strcat(result, "\\n"); continue; } else if (ch == '\r') { /* \r -> carriagereturn */ acl_vstring_strcat(result, "\\r"); continue; } else if (ch == '\t') { /* \t -> horizontal tab */ acl_vstring_strcat(result, "\\t"); continue; } else if (ch == '\v') { /* \v -> vertical tab */ acl_vstring_strcat(result, "\\v"); continue; } } if (ACL_ISDIGIT(*UCHAR(data))) acl_vstring_sprintf_append(result, "\\%03d", ch); else acl_vstring_sprintf_append(result, "\\%d", ch); } ACL_VSTRING_TERMINATE(result); return (result); }
ACL_VSTRING *tok822_internalize(ACL_VSTRING *vp, TOK822 *tree, int flags) { TOK822 *tp; if (flags & TOK822_STR_WIPE) ACL_VSTRING_RESET(vp); for (tp = tree; tp; tp = tp->next) { switch (tp->type) { case ',': ACL_VSTRING_ADDCH(vp, tp->type); if (flags & TOK822_STR_LINE) { ACL_VSTRING_ADDCH(vp, '\n'); continue; } break; case TOK822_ADDR: tok822_internalize(vp, tp->head, TOK822_STR_NONE); break; case TOK822_COMMENT: case TOK822_ATOM: case TOK822_QSTRING: acl_vstring_strcat(vp, acl_vstring_str(tp->vstr)); break; case TOK822_DOMLIT: ACL_VSTRING_ADDCH(vp, '['); acl_vstring_strcat(vp, acl_vstring_str(tp->vstr)); ACL_VSTRING_ADDCH(vp, ']'); break; case TOK822_STARTGRP: ACL_VSTRING_ADDCH(vp, ':'); break; default: if (tp->type >= TOK822_MINTOK) acl_msg_panic("tok822_internalize: unknown operator %d", tp->type); ACL_VSTRING_ADDCH(vp, tp->type); } if (tok822_append_space(tp)) ACL_VSTRING_ADDCH(vp, ' '); } if (flags & TOK822_STR_TERM) ACL_VSTRING_TERMINATE(vp); return (vp); }
const char *str_name_mask_opt(ACL_VSTRING *buf, const char *context, const NAME_MASK *table, int mask, int flags) { const char *myname = "name_mask"; const NAME_MASK *np; int len; static ACL_VSTRING *my_buf = 0; int delim = (flags & NAME_MASK_COMMA ? ',' : (flags & NAME_MASK_PIPE ? '|' : ' ')); if (buf == 0) { if (my_buf == 0) my_buf = acl_vstring_alloc(1); buf = my_buf; } ACL_VSTRING_RESET(buf); for (np = table; mask != 0; np++) { if (np->name == 0) { if (flags & NAME_MASK_FATAL) { acl_msg_fatal("%s: unknown %s bit in mask: 0x%x", myname, context, mask); } else if (flags & NAME_MASK_RETURN) { acl_msg_warn("%s: unknown %s bit in mask: 0x%x", myname, context, mask); return (0); } else if (flags & NAME_MASK_NUMBER) { acl_vstring_sprintf_append(buf, "0x%x%c", mask, delim); } break; } if (mask & np->mask) { mask &= ~np->mask; acl_vstring_sprintf_append(buf, "%s%c", np->name, delim); } } if ((len = (int) ACL_VSTRING_LEN(buf)) > 0) acl_vstring_truncate(buf, len - 1); ACL_VSTRING_TERMINATE(buf); return (STR(buf)); }
ACL_TOKEN *acl_token_tree_create2(const char *s, const char *sep) { const char *myname = "acl_token_tree_create"; ACL_ARGV *argv; ACL_ITER iter; unsigned int flag; ACL_TOKEN *token_tree; const ACL_TOKEN *token; ACL_VSTRING *buf; token_tree = acl_token_new(); if (s == NULL || *s == 0) return (token_tree); buf = acl_vstring_alloc(256); argv = acl_argv_split(s, sep); acl_foreach(iter, argv) { char *word = (char*) iter.ptr; char *ptr = strchr(word, '|'); flag = ACL_TOKEN_F_STOP; if (ptr) { *ptr++ = 0; if (*ptr == 'D' || *ptr == 'd') flag |= ACL_TOKEN_F_DENY; if (*ptr == 'P' || *ptr == 'p') flag |= ACL_TOKEN_F_PASS; } token = acl_token_tree_add(token_tree, word, flag, NULL); if (token == NULL) { acl_msg_info("%s(%d): word(%s) discard", myname, __LINE__, word); } else { ACL_VSTRING_RESET(buf); acl_token_name(token, buf); /* acl_msg_info("%s(%d): add word(%s) ok, token's name(%s)", myname, __LINE__, word, STR(buf)); */ } }
const char *acl_token_name1(const ACL_TOKEN *token) { static acl_pthread_key_t buf_key = (acl_pthread_key_t) ACL_TLS_OUT_OF_INDEXES; ACL_VSTRING *buf; static ACL_VSTRING *__buf_unsafe = NULL; buf = (ACL_VSTRING*) acl_pthread_tls_get(&buf_key); if (buf == NULL) { if (buf_key == (acl_pthread_key_t) ACL_TLS_OUT_OF_INDEXES) { if (__buf_unsafe == NULL) __buf_unsafe = acl_vstring_alloc(256); buf = __buf_unsafe; } else { buf = acl_vstring_alloc(256); acl_pthread_tls_set(buf_key, buf, (void (*)(void*)) acl_vstring_free); } } ACL_VSTRING_RESET(buf); acl_token_name(token, buf); return (STR(buf)); }
static int chunked_data_endl(ACL_ASTREAM *astream, HTTP_CHAT_CTX *ctx) { HTTP_BODY_NOTIFY notify = ctx->notify.body_notify; void *arg = ctx->arg; ACL_VSTRING *sbuf; char *data; int dlen; sbuf = acl_aio_gets_peek(astream); if (sbuf == NULL) return (0); data = acl_vstring_str(sbuf); dlen = (int) ACL_VSTRING_LEN(sbuf); ACL_VSTRING_RESET(sbuf); ctx->body_len += dlen; if (notify(HTTP_CHAT_CHUNK_DATA_ENDL, data, dlen, arg) < 0) return (-1); ctx->status = CHAT_S_CHUNK_HDR; return (0); }
int mac_expand(ACL_VSTRING *result, const char *pattern, int flags, const char *filter, MAC_EXP_LOOKUP_FN lookup, char *context) { MAC_EXP mc; int status; /* * Bundle up the request and do the substitutions. */ mc.result = result; mc.flags = flags; mc.filter = filter; mc.lookup = lookup; mc.context = context; mc.status = 0; mc.level = 0; ACL_VSTRING_RESET(result); status = mac_parse(pattern, mac_expand_callback, (char *) &mc); ACL_VSTRING_TERMINATE(result); return (status); }
static int hdr_gets_ready(ACL_ASTREAM *astream, void *context, char *data, int dlen) { HTTP_CHAT_CTX *ctx = (HTTP_CHAT_CTX *) context; HTTP_HDR *hdr = ctx->hdr; HTTP_HDR_NOTIFY notify = ctx->notify.hdr_notify; void *arg = ctx->arg; ACL_VSTRING *sbuf; int ret; while (1) { ret = hdr_ready(hdr, data, dlen); switch (ret) { case HTTP_CHAT_CONTINUE: break; case HTTP_CHAT_OK: acl_aio_del_read_hook(astream, hdr_gets_ready, context); if (notify(ret, arg) < 0) { return (-1); } return (0); default: acl_aio_del_read_hook(astream, hdr_gets_ready, context); (void) notify(ret, arg); return (-1); } sbuf = acl_aio_gets_nonl_peek(astream); if (sbuf == NULL) break; data = acl_vstring_str(sbuf); dlen = (int) ACL_VSTRING_LEN(sbuf); ACL_VSTRING_RESET(sbuf); } acl_aio_gets_nonl(astream); return (0); }
static int chunked_hdr(ACL_ASTREAM *astream, HTTP_CHAT_CTX *ctx) { HTTP_BODY_NOTIFY notify = ctx->notify.body_notify; void *arg = ctx->arg; ACL_VSTRING *sbuf; char *data, *ptr; int dlen; sbuf = acl_aio_gets_peek(astream); if (sbuf == NULL) return (0); data = acl_vstring_str(sbuf); dlen = (int) ACL_VSTRING_LEN(sbuf); ACL_VSTRING_RESET(sbuf); ctx->body_len += dlen; ctx->read_cnt = 0; ptr = strchr(data, ' '); if (ptr) *ptr = 0; ctx->chunk_len = strtoul(data, NULL, 16); if (ptr) *ptr = ' '; if (notify(HTTP_CHAT_CHUNK_HDR, data, dlen, arg) < 0) return (-1); if (ctx->chunk_len == 0) { ctx->status = CHAT_S_CHUNK_TAL; return (0); } ctx->status = CHAT_S_CHUNK_DAT; return (0); }
ACL_VSTRING *unescape(ACL_VSTRING *result, const char *data) { int ch; int oval; int i; #define UCHAR(cp) ((const unsigned char *) (cp)) #define ISOCTAL(ch) (ACL_ISDIGIT(ch) && (ch) != '8' && (ch) != '9') ACL_VSTRING_RESET(result); while ((ch = *UCHAR(data++)) != 0) { if (ch == '\\') { if ((ch = *UCHAR(data++)) == 0) break; switch (ch) { case 'a': /* \a -> audible bell */ ch = '\a'; break; case 'b': /* \b -> backspace */ ch = '\b'; break; case 'f': /* \f -> formfeed */ ch = '\f'; break; case 'n': /* \n -> newline */ ch = '\n'; break; case 'r': /* \r -> carriagereturn */ ch = '\r'; break; case 't': /* \t -> horizontal tab */ ch = '\t'; break; case 'v': /* \v -> vertical tab */ ch = '\v'; break; case '0': /* \nnn -> ASCII value */ case '1': case '2': case '3': case '4': case '5': case '6': case '7': for (oval = ch - '0', i = 0; i < 2 && (ch = *UCHAR(data)) != 0 && ISOCTAL(ch); i++, data++) { oval = (oval << 3) | (ch - '0'); } ch = oval; break; default: /* \any -> any */ break; } } ACL_VSTRING_ADDCH(result, ch); } ACL_VSTRING_TERMINATE(result); return (result); }
ACL_VSTRING *tok822_externalize(ACL_VSTRING *vp, TOK822 *tree, int flags) { ACL_VSTRING *tmp; TOK822 *tp; ssize_t start = 0; TOK822 *addr = 0; ssize_t addr_len = 0; /* * Guard against a Sendmail buffer overflow (CERT advisory CA-2003-07). * The problem was that Sendmail could store too much non-address text * (comments, phrases, etc.) into a static 256-byte buffer. * * When the buffer fills up, fixed Sendmail versions remove comments etc. * and reduce the information to just <$g>, which expands to <address>. * No change is made when an address expression (text separated by * commas) contains no address. This fix reportedly also protects * Sendmail systems that are still vulnerable to this problem. * * Postfix takes the same approach, grudgingly. To avoid unnecessary damage, * Postfix removes comments etc. only when the amount of non-address text * in an address expression (text separated by commas) exceeds 250 bytes. * * With Sendmail, the address part of an address expression is the * right-most <> instance in that expression. If an address expression * contains no <>, then Postfix guarantees that it contains at most one * non-comment string; that string is the address part of the address * expression, so there is no ambiguity. * * Finally, we note that stress testing shows that other code in Sendmail * 8.12.8 bluntly truncates ``text <address>'' to 256 bytes even when * this means chopping the <address> somewhere in the middle. This is a * loss of control that we're not entirely comfortable with. However, * unbalanced quotes and dangling backslash do not seem to influence the * way that Sendmail parses headers, so this is not an urgent problem. */ #define MAX_NONADDR_LENGTH 250 #define RESET_NONADDR_LENGTH { \ start = ACL_VSTRING_LEN(vp); \ addr = 0; \ addr_len = 0; \ } #define ENFORCE_NONADDR_LENGTH do { \ if (addr && (ssize_t) ACL_VSTRING_LEN(vp) - addr_len > start + MAX_NONADDR_LENGTH) \ strip_address(vp, start, addr->head); \ } while(0) if (flags & TOK822_STR_WIPE) ACL_VSTRING_RESET(vp); if (flags & TOK822_STR_TRNC) RESET_NONADDR_LENGTH; for (tp = tree; tp; tp = tp->next) { switch (tp->type) { case ',': if (flags & TOK822_STR_TRNC) ENFORCE_NONADDR_LENGTH; ACL_VSTRING_ADDCH(vp, tp->type); ACL_VSTRING_ADDCH(vp, (flags & TOK822_STR_LINE) ? '\n' : ' '); if (flags & TOK822_STR_TRNC) RESET_NONADDR_LENGTH; continue; /* * XXX In order to correctly externalize an address, it is not * sufficient to quote individual atoms. There are higher-level * rules that say when an address localpart needs to be quoted. * We wing it with the quote_822_local() routine, which ignores * the issue of atoms in the domain part that would need quoting. */ case TOK822_ADDR: addr = tp; tmp = acl_vstring_alloc(100); tok822_internalize(tmp, tp->head, TOK822_STR_TERM); addr_len = ACL_VSTRING_LEN(vp); quote_822_local_flags(vp, acl_vstring_str(tmp), QUOTE_FLAG_8BITCLEAN | QUOTE_FLAG_APPEND); addr_len = ACL_VSTRING_LEN(vp) - addr_len; acl_vstring_free(tmp); break; case TOK822_ATOM: case TOK822_COMMENT: acl_vstring_strcat(vp, acl_vstring_str(tp->vstr)); break; case TOK822_QSTRING: ACL_VSTRING_ADDCH(vp, '"'); tok822_copy_quoted(vp, acl_vstring_str(tp->vstr), "\"\\\r\n"); ACL_VSTRING_ADDCH(vp, '"'); break; case TOK822_DOMLIT: ACL_VSTRING_ADDCH(vp, '['); tok822_copy_quoted(vp, acl_vstring_str(tp->vstr), "\\\r\n"); ACL_VSTRING_ADDCH(vp, ']'); break; case TOK822_STARTGRP: ACL_VSTRING_ADDCH(vp, ':'); break; case '<': if (tp->next && tp->next->type == '>') { addr = tp; addr_len = 0; } ACL_VSTRING_ADDCH(vp, '<'); break; default: if (tp->type >= TOK822_MINTOK) acl_msg_panic("tok822_externalize: unknown operator %d", tp->type); ACL_VSTRING_ADDCH(vp, tp->type); } if (tok822_append_space(tp)) ACL_VSTRING_ADDCH(vp, ' '); } if (flags & TOK822_STR_TRNC) ENFORCE_NONADDR_LENGTH; if (flags & TOK822_STR_TERM) ACL_VSTRING_TERMINATE(vp); return (vp); }
const char *acl_getenv_list(void) { const char *myname = "acl_getenv_list"; #ifdef ACL_WINDOWS static acl_pthread_key_t buf_key = ACL_TLS_OUT_OF_INDEXES; ACL_VSTRING *buf; LPTSTR lpszVariable; LPVOID lpvEnv; int i = 0, ch = 0; buf = (ACL_VSTRING*) acl_pthread_tls_get(&buf_key); if (buf == NULL) { if (buf_key == ACL_TLS_OUT_OF_INDEXES) { acl_msg_error("%s(%d): acl_pthread_tls_get error(%s)", myname, __LINE__, acl_last_serror()); return (NULL); } buf = acl_vstring_alloc(256); acl_pthread_tls_set(buf_key, buf, (void (*)(void*)) free_vstring); } else ACL_VSTRING_RESET(buf); lpvEnv = GetEnvironmentStrings(); for (lpszVariable = (LPTSTR) lpvEnv; *lpszVariable; lpszVariable++) { if (i++ > 0) acl_vstring_strcat(buf, ", "); while (*lpszVariable) { ACL_VSTRING_ADDCH(buf, *lpszVariable++); ch = *lpszVariable; } } FreeEnvironmentStrings(lpvEnv); ACL_VSTRING_TERMINATE(buf); return (acl_vstring_str(buf)); #else static acl_pthread_key_t buf_key = (acl_pthread_key_t) ACL_TLS_OUT_OF_INDEXES; ACL_VSTRING *buf; extern char **environ; char **pptr = environ; int i = 0; buf = (ACL_VSTRING*) acl_pthread_tls_get(&buf_key); if (buf == NULL) { if (buf_key == (acl_pthread_key_t) ACL_TLS_OUT_OF_INDEXES) { acl_msg_error("%s(%d): acl_pthread_tls_get error(%s)", myname, __LINE__, acl_last_serror()); return (NULL); } buf = acl_vstring_alloc(256); acl_pthread_tls_set(buf_key, buf, (void (*)(void*)) free_vstring); } else ACL_VSTRING_RESET(buf); while (*pptr) { if (i++ > 0) acl_vstring_strcat(buf, ", "); acl_vstring_strcat(buf, *pptr); pptr++; } return (acl_vstring_str(buf)); #endif }
bool charset_conv::update(const char* in, size_t len, acl::string* out) { #ifdef HAVE_H_ICONV if (in == NULL) logger_fatal("in null"); if (out == NULL) logger_fatal("out null"); if (EQ(m_fromCharset, m_toCharset)) { out->append(in, len); return (true); } if (m_iconv == (iconv_t) -1) { logger_error("m_iconv invalid"); m_errmsg = "m_iconv invalid"; return (false); } // 去掉有些 UTF-8 文档中开始的 UTF-8 引导符 if (*m_pUtf8Pre) { while (len > 0) { if (*m_pUtf8Pre == 0x00) break; else if (*m_pUtf8Pre != *in) { // 必须使 UTF-8 前缀失效 m_pUtf8Pre = &UTF8_HEADER[3]; break; } m_pUtf8Pre++; in++; len--; } } if (len == 0) return (true); if (m_pInBuf == NULL) m_pInBuf = acl_vstring_alloc(len); if (m_pOutBuf == NULL) m_pOutBuf = acl_vstring_alloc(len); else ACL_VSTRING_SPACE(m_pOutBuf, len); // 先将输入数据进行缓冲 if (*m_pUtf8Pre && m_pUtf8Pre - UTF8_HEADER > 0) acl_vstring_memcpy(m_pInBuf, UTF8_HEADER, m_pUtf8Pre - UTF8_HEADER); acl_vstring_memcat(m_pInBuf, in, len); ACL_VSTRING_TERMINATE(m_pInBuf); char *pIn, *pOut; size_t ret, nIn, nOut; while (true) { nIn = LEN(m_pInBuf); if (nIn == 0) break; pIn = STR(m_pInBuf); pOut = STR(m_pOutBuf); nOut = SIZE(m_pOutBuf); #ifdef WIN32 # ifdef USE_WIN_ICONV ret = __iconv(m_iconv, (const char**) &pIn, &nIn, &pOut, &nOut); # else int err; ret = __iconv(m_iconv, (const char**) &pIn, &nIn, &pOut, &nOut, &err); errno = err; # endif // USE_WIN_ICONV #elif defined(ACL_SUNOS5) || defined(ACL_FREEBSD) ret = __iconv(m_iconv, (const char**) &pIn, &nIn, &pOut, &nOut); #else ret = __iconv(m_iconv, &pIn, &nIn, &pOut, &nOut); #endif if (ret != (size_t) -1) { if ((ret = SIZE(m_pOutBuf) - nOut) > 0) out->append(STR(m_pOutBuf), ret); else // xxx out->append(in, len); ACL_VSTRING_RESET(m_pInBuf); break; } else if (errno == E2BIG) { if ((ret = SIZE(m_pOutBuf) - nOut) > 0) out->append(STR(m_pOutBuf), ret); if (pIn > STR(m_pInBuf) && nIn < LEN(m_pInBuf)) acl_vstring_memmove(m_pInBuf, pIn, nIn); // 扩大内存空间 ACL_VSTRING_SPACE(m_pOutBuf, SIZE(m_pOutBuf) * 2); continue; } else if (errno == EILSEQ) { char *pNil = NULL; size_t zero = 0; // 重置状态, 似乎也没啥用处 #ifdef WIN32 # ifdef USE_WIN_ICONV __iconv(m_iconv, (const char**) &pNil, &zero, &pNil, &zero); # else __iconv(m_iconv, (const char**) &pNil, &zero, &pNil, &zero, NULL); # endif #elif defined(ACL_SUNOS5) || defined(ACL_FREEBSD) __iconv(m_iconv, (const char**) &pNil, &zero, &pNil, &zero); #else __iconv(m_iconv, &pNil, &zero, &pNil, &zero); #endif // 遇到无效的多字节序列,pIn 指向第一个无效的位置 // 先拷贝已经转换的数据 if ((ret = SIZE(m_pOutBuf) - nOut) > 0) out->append(STR(m_pOutBuf), ret); if (nIn == 0) { ACL_VSTRING_RESET(m_pInBuf); break; } acl_assert(pIn >= STR(m_pInBuf)); // 跳过无效字节 (*out) += (char)(*pIn); // 直接拷贝无效字节 nIn--; pIn++; if (nIn > 0) acl_vstring_memmove(m_pInBuf, pIn, nIn); else ACL_VSTRING_RESET(m_pInBuf); } else if (errno == EINVAL) { char *pNil = NULL; size_t zero = 0; // 重置状态, 似乎也没啥用处 #ifdef WIN32 # ifdef USE_WIN_ICONV __iconv(m_iconv, (const char**) &pNil, &zero, &pNil, &zero); # else __iconv(m_iconv, (const char**) &pNil, &zero, &pNil, &zero, NULL); # endif // USE_WIN_ICONV #elif defined(ACL_SUNOS5) || defined(ACL_FREEBSD) __iconv(m_iconv, (const char**) &pNil, &zero, &pNil, &zero); #else __iconv(m_iconv, &pNil, &zero, &pNil, &zero); #endif // 输入的多字节序列不完整,pIn 指向该不完整的位置 // 先拷贝已经转换的数据 if ((ret = SIZE(m_pOutBuf) - nOut) > 0) out->append(STR(m_pOutBuf), ret); // 移动数据,将未转换的数据移至缓冲区起始位置 if (nIn > 0) acl_vstring_memmove(m_pInBuf, pIn, nIn); else ACL_VSTRING_RESET(m_pInBuf); break; } else if (LEN(m_pInBuf) > 0) { // 如果遇到了无效的字符集,根据设置的标志位 // 决定是否直接拷贝 if (m_addInvalid) { out->append(STR(m_pInBuf), LEN(m_pInBuf)); ACL_VSTRING_RESET(m_pInBuf); } break; } else break; } return (true); #else (void) in; (void) len; (void) out; logger_error("no iconv lib"); m_errmsg = "no iconv lib"; return (false); #endif }
static int chunked_data(ACL_ASTREAM *astream, HTTP_CHAT_CTX *ctx) { HTTP_BODY_NOTIFY notify = ctx->notify.body_notify; void *arg = ctx->arg; ACL_VSTRING *sbuf = NULL; char *data; int dlen, ret; if (ctx->chunked) { ret = (int) HTTP_LEN_ROUND(ctx); sbuf = acl_aio_readn_peek(astream, ret); } else if (ctx->hdr->content_length <= 0) sbuf = acl_aio_read_peek(astream); else { ret = (int) HTTP_LEN_ROUND(ctx); if (ret <= 0) { /* 说明本次 HTTP 数据已经读完且遇到对方关闭 * 或对方发来了多余的数据,所以需要返回 -1 */ DISABLE_READ(astream); if (notify(HTTP_CHAT_OK, NULL, 0, arg) < 0) return (-1); return (-1); } else sbuf = acl_aio_readn_peek(astream, ret); } if (sbuf == NULL) return (0); data = acl_vstring_str(sbuf); dlen = (int) ACL_VSTRING_LEN(sbuf); ACL_VSTRING_RESET(sbuf); ctx->body_len += dlen; ctx->read_cnt += dlen; if (ctx->chunk_len > 0 && ctx->read_cnt >= ctx->chunk_len) { if (!ctx->chunked) { /* 如果读到完了整块数据且非 CHUNK 传输, * 则认为读完 HTTP 响应 */ /* xxx: 禁止连续读 */ DISABLE_READ(astream); if (notify(HTTP_CHAT_OK, data, dlen, arg) < 0) return (-1); return (1); } /* 对于 chunk 传输,读完本数据块 */ if (notify(HTTP_CHAT_DATA, data, dlen, arg) < 0) return (-1); /* 设置标志位开始读取块数据体的分隔行数据 */ ctx->status = CHAT_S_CHUNK_SEP; return (0); } if (notify(HTTP_CHAT_DATA, data, dlen, arg) < 0) return (-1); return (0); }
ssize_t header_token(HEADER_TOKEN *token, ssize_t token_len, ACL_VSTRING *token_buffer, const char **ptr, const char *user_specials, int user_terminator) { ssize_t comment_level; const unsigned char *cp; ssize_t len; int ch; ssize_t tok_count; ssize_t n; /* * Initialize. */ ACL_VSTRING_RESET(token_buffer); cp = CU_CHAR_PTR(*ptr); tok_count = 0; if (user_specials == 0) user_specials = LEX_822_SPECIALS; /* * Main parsing loop. * * XXX What was the reason to continue parsing when user_terminator is * specified? Perhaps this was needed at some intermediate stage of * development? */ while ((ch = *cp) != 0 && (user_terminator != 0 || tok_count < token_len)) { cp++; /* * Skip RFC 822 linear white space. */ if (IS_SPACE_TAB_CR_LF(ch)) continue; /* * Terminator. */ if (ch == user_terminator) break; /* * Skip RFC 822 comment. */ if (ch == '(') { comment_level = 1; while ((ch = *cp) != 0) { cp++; if (ch == '(') { /* comments can nest! */ comment_level++; } else if (ch == ')') { if (--comment_level == 0) break; } else if (ch == '\\') { if ((ch = *cp) == 0) break; cp++; } } continue; } /* * Copy quoted text according to RFC 822. */ if (ch == '"') { if (tok_count < token_len) { token[tok_count].u.offset = LEN(token_buffer); token[tok_count].type = HEADER_TOK_QSTRING; } while ((ch = *cp) != 0) { cp++; if (ch == '"') break; if (ch == '\n') { /* unfold */ if (tok_count < token_len) { len = LEN(token_buffer); while (len > 0 && IS_SPACE_TAB_CR_LF(STR(token_buffer)[len - 1])) len--; if (len < (ssize_t) LEN(token_buffer)) acl_vstring_truncate(token_buffer, len); } continue; } if (ch == '\\') { if (tok_count < token_len) ACL_VSTRING_ADDCH(token_buffer, ch); if (*cp == 0) break; ch = *cp; cp++; } if (tok_count < token_len) ACL_VSTRING_ADDCH(token_buffer, ch); } if (tok_count < token_len) { ACL_VSTRING_ADDCH(token_buffer, 0); tok_count++; } continue; } /* * Control, or special. */ if (strchr(user_specials, ch) || ACL_ISCNTRL(ch)) { if (tok_count < token_len) { token[tok_count].u.offset = LEN(token_buffer); token[tok_count].type = ch; ACL_VSTRING_ADDCH(token_buffer, ch); ACL_VSTRING_ADDCH(token_buffer, 0); tok_count++; } continue; } /* * Token. */ else { if (tok_count < token_len) { token[tok_count].u.offset = LEN(token_buffer); token[tok_count].type = HEADER_TOK_TOKEN; ACL_VSTRING_ADDCH(token_buffer, ch); } while ((ch = *cp) != 0 && !IS_SPACE_TAB_CR_LF(ch) && !ACL_ISCNTRL(ch) && !strchr(user_specials, ch)) { cp++; if (tok_count < token_len) ACL_VSTRING_ADDCH(token_buffer, ch); } if (tok_count < token_len) { ACL_VSTRING_ADDCH(token_buffer, 0); tok_count++; } continue; } } /* * Ignore a zero-length item after the last terminator. */ if (tok_count == 0 && ch == 0) return (-1); /* * Finalize. Fill in the string pointer array, now that the token buffer * is no longer dynamically reallocated as it grows. */ *ptr = (const char *) cp; for (n = 0; n < tok_count; n++) token[n].u.value = STR(token_buffer) + token[n].u.offset; //if (acl_msg_verbose) // acl_msg_info("header_token: %s %s %s", // tok_count > 0 ? token[0].u.value : "", // tok_count > 1 ? token[1].u.value : "", // tok_count > 2 ? token[2].u.value : ""); return (tok_count); }