int acl_xml_decode(const char *in, ACL_VSTRING *out) { int n = 0, len = (int) strlen(in); const char *ptr = in, *pre; const ACL_TOKEN *token; const XML_SPEC *spec; ACL_VSTRING_SPACE(out, len); acl_pthread_once(&__token_once, xml_decode_init); if (__token_tree == NULL) acl_msg_fatal("__token_tree null"); while (*ptr != 0) { pre = ptr; token = acl_token_tree_match(__token_tree, &ptr, NULL, NULL); if (token == NULL) { pre = markup_unescape(pre, out); len = (int) (ptr - pre); if (len > 0) acl_vstring_memcat(out, pre, len); break; } spec = (const XML_SPEC*) token->ctx; acl_assert(spec != NULL); len = (int) (ptr - pre - spec->len); if (len > 0) acl_vstring_memcat(out, pre, len); acl_vstring_strcat(out, spec->str); n++; } ACL_VSTRING_TERMINATE(out); return n; }
HTTP_HDR_REQ *http_hdr_req_create(const char *url, const char *method, const char *version) { const char *myname = "http_hdr_req_create"; HTTP_HDR_REQ *hdr_req; ACL_VSTRING *req_line = acl_vstring_alloc(256); HTTP_HDR_ENTRY *entry; const char *ptr; static char *__user_agent = "Mozilla/5.0 (Windows; U; Windows NT 5.0" "; zh-CN; rv:1.9.0.3) Gecko/2008092417 ACL/3.0.6"; if (url == NULL || *url == 0) { acl_msg_error("%s(%d): url invalid", myname, __LINE__); return NULL; } if (method == NULL || *method == 0) { acl_msg_error("%s(%d): method invalid", myname, __LINE__); return NULL; } if (version == NULL || *version == 0) { acl_msg_error("%s(%d): version invalid", myname, __LINE__); return NULL; } acl_vstring_strcpy(req_line, method); acl_vstring_strcat(req_line, " "); if (strncasecmp(url, "http://", sizeof("http://") - 1) == 0) url += sizeof("http://") - 1; else if (strncasecmp(url, "https://", sizeof("https://") - 1) == 0) url += sizeof("https://") -1; ptr = strchr(url, '/'); if (ptr) acl_vstring_strcat(req_line, ptr); else { ACL_VSTRING_ADDCH(req_line, '/'); ACL_VSTRING_TERMINATE(req_line); } acl_vstring_strcat(req_line, " "); acl_vstring_strcat(req_line, version); entry = http_hdr_entry_new(acl_vstring_str(req_line)); acl_vstring_free(req_line); if (entry == NULL) { acl_msg_error("%s(%d): http_hdr_entry_new return null for (%s)", myname, __LINE__, acl_vstring_str(req_line)); return NULL; } hdr_req = http_hdr_req_new(); http_hdr_append_entry(&hdr_req->hdr, entry); hdr_req->flag |= (HTTP_HDR_REQ_FLAG_PARSE_PARAMS | HTTP_HDR_REQ_FLAG_PARSE_COOKIE); if (http_hdr_req_line_parse(hdr_req) < 0) { http_hdr_req_free(hdr_req); return NULL; } hdr_req->host[0] = 0; __get_host_from_url(hdr_req->host, sizeof(hdr_req->host), url); if (hdr_req->host[0] != 0) http_hdr_put_str(&hdr_req->hdr, "Host", hdr_req->host); http_hdr_put_str(&hdr_req->hdr, "Connection", "Close"); http_hdr_put_str(&hdr_req->hdr, "User-Agent", __user_agent); return hdr_req; }
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); }
static void test61(void) { ACL_VSTRING* buf; buf = acl_vstring_alloc(256); acl_vstring_strcpy(buf, "hello world!"); acl_vstring_strcat(buf, "hello world!"); acl_vstring_strcat(buf, "hello world!"); acl_vstring_strcat(buf, "hello world!"); acl_vstring_strcat(buf, "hello world!"); acl_vstring_strcat(buf, "hello world!"); acl_vstring_strcat(buf, "hello world!"); acl_vstring_strcat(buf, "hello world!"); acl_vstring_strcat(buf, "hello world!"); acl_vstring_strcat(buf, "hello world!"); acl_vstring_strcat(buf, "hello world!"); acl_vstring_strcat(buf, "hello world!"); acl_vstring_strcat(buf, "hello world!"); acl_vstring_strcat(buf, "hello world!"); acl_vstring_strcat(buf, "hello world!"); acl_vstring_strcat(buf, "hello world!"); acl_vstring_strcat(buf, "hello world!"); acl_vstring_strcat(buf, "hello world!"); acl_vstring_strcat(buf, "hello world!"); acl_vstring_strcat(buf, "hello world!"); acl_vstring_strcat(buf, "hello world!"); acl_vstring_strcat(buf, "hello world!"); acl_vstring_strcat(buf, "hello world!"); acl_vstring_strcat(buf, "hello world!"); acl_vstring_strcat(buf, "hello world!"); acl_vstring_strcat(buf, "hello world!"); acl_vstring_strcat(buf, "hello world!"); acl_vstring_strcat(buf, "hello world!"); acl_vstring_strcat(buf, "hello world!"); acl_vstring_strcat(buf, "hello world!"); acl_vstring_strcat(buf, "hello world!"); acl_vstring_strcat(buf, "hello world!"); acl_vstring_strcat(buf, "hello world!"); acl_vstring_strcat(buf, "hello world!"); acl_vstring_strcat(buf, "hello world!"); acl_vstring_free(buf); }
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 }
static void get_url(const char *method, const char *url, const char *proxy, const char *dump) { /* 创建 HTTP 请求头 */ HTTP_HDR_REQ *hdr_req = http_hdr_req_create(url, method, "HTTP/1.1"); ACL_VSTREAM *stream; ACL_VSTRING *buf = acl_vstring_alloc(256); HTTP_HDR_RES *hdr_res; HTTP_RES *res; ACL_FILE *fp = NULL; const char *ptr; int ret; /* 输出 HTTP 请求头内容 */ http_hdr_print(&hdr_req->hdr, "---request hdr---"); /* 如果设定代理服务器,则连接代理服务器地址, * 否则使用 HTTP 请求头里指定的地址 */ if (*proxy) acl_vstring_strcpy(buf, proxy); else acl_vstring_strcpy(buf, http_hdr_req_host(hdr_req)); /* 获得远程 HTTP 服务器的连接地址 */ ptr = acl_vstring_memchr(buf, ':'); if (ptr == NULL) acl_vstring_strcat(buf, ":80"); else { int port; ptr++; port = atoi(ptr); if (port <= 0 || port >= 65535) { printf("http server's addr(%s) invalid\n", acl_vstring_str(buf)); acl_vstring_free(buf); http_hdr_req_free(hdr_req); return; } } /* 连接远程 http 服务器 */ stream = acl_vstream_connect(acl_vstring_str(buf) /* 服务器地址 */, ACL_BLOCKING /* 采用阻塞方式 */, 10 /* 连接超时时间为 10 秒 */, 10 /* 网络 IO 操作超时时间为 10 秒 */, 4096 /* stream 流缓冲区大小为 4096 字节 */); if (stream == NULL) { printf("connect addr(%s) error(%s)\n", acl_vstring_str(buf), acl_last_serror()); acl_vstring_free(buf); http_hdr_req_free(hdr_req); return; } /* 构建 HTTP 请求头数据 */ http_hdr_build_request(hdr_req, buf); /* 向 HTTP 服务器发送请求 */ ret = acl_vstream_writen(stream, acl_vstring_str(buf), ACL_VSTRING_LEN(buf)); if (ret == ACL_VSTREAM_EOF) { printf("write to server error(%s)\n", acl_last_serror()); acl_vstream_close(stream); acl_vstring_free(buf); http_hdr_req_free(hdr_req); return; } /* 创建一个 HTTP 响应头对象 */ hdr_res = http_hdr_res_new(); /* 读取 HTTP 服务器响应头*/ ret = http_hdr_res_get_sync(hdr_res, stream, 10 /* IO 超时时间为 10 秒 */); if (ret < 0) { printf("get http reply header error(%s)\n", acl_last_serror()); http_hdr_res_free(hdr_res); acl_vstream_close(stream); acl_vstring_free(buf); http_hdr_req_free(hdr_req); return; } if (http_hdr_res_parse(hdr_res) < 0) { printf("parse http reply header error\n"); http_hdr_print(&hdr_res->hdr, "--- reply http header ---"); http_hdr_res_free(hdr_res); acl_vstream_close(stream); acl_vstring_free(buf); http_hdr_req_free(hdr_req); return; } /* 如果需要转储至磁盘则需要先打开文件 */ if (dump != NULL) { fp = acl_fopen(dump, "w+"); if (fp == NULL) printf("open file(%s) error(%s)\n", dump, acl_last_serror()); } /* 如果 HTTP 响应没有数据体则仅输出 HTTP 响应头即可 */ if (hdr_res->hdr.content_length == 0 || (hdr_res->hdr.content_length == -1 && !hdr_res->hdr.chunked && hdr_res->reply_status > 300 && hdr_res->reply_status < 400)) { if (fp) http_hdr_fprint(ACL_FSTREAM(fp), &hdr_res->hdr, "--- reply http header ---"); else http_hdr_fprint(ACL_VSTREAM_OUT, &hdr_res->hdr, "--- reply http header ---"); http_hdr_res_free(hdr_res); acl_vstream_close(stream); acl_vstring_free(buf); http_hdr_req_free(hdr_req); return; } /* 输出 HTTP 响应头 */ http_hdr_print(&hdr_res->hdr, "--- reply http header ---"); /* 创建 HTTP 响应体对象 */ res = http_res_new(hdr_res); /* 如果有数据体则开始读取 HTTP 响应数据体部分 */ while (1) { http_off_t n; char buf2[4096]; n = http_res_body_get_sync(res, stream, buf2, sizeof(buf2) - 1); if (n <= 0) break; if (fp) { if (acl_fwrite(buf2, (size_t) n, 1, fp) == (size_t) EOF) { printf("write to dump file(%s) error(%s)\n", dump, acl_last_serror()); break; } } else { buf2[n] = 0; printf("%s", buf2); } } if (fp) acl_fclose(fp); http_res_free(res); /* 释放 HTTP 响应对象, hdr_res 会在此函数内部自动被释放 */ acl_vstream_close(stream); /* 关闭网络流 */ acl_vstring_free(buf); /* 释放内存区 */ http_hdr_req_free(hdr_req); /* 释放 HTTP 请求头对象 */ }
static int mac_expand_callback(int type, ACL_VSTRING *buf, char *ptr) { MAC_EXP *mc = (MAC_EXP *) ptr; int lookup_mode; const char *text; char *cp, *pp = NULL; int ch; ssize_t len; size_t size; /* * Sanity check. */ if (mc->level++ > 100) { acl_msg_warn("unreasonable macro call nesting: \"%s\"", acl_vstring_str(buf)); mc->status |= MAC_PARSE_ERROR; } if (mc->status & MAC_PARSE_ERROR) return (mc->status); /* * $Name etc. reference. * * In order to support expansion of lookup results, we must save the lookup * result. We use the input buffer since it will not be needed anymore. */ if (type == MAC_PARSE_EXPR) { /* * Look for the ? or : delimiter. In case of a syntax error, return * without doing damage, and issue a warning instead. */ for (cp = acl_vstring_str(buf); /* void */ ; cp++) { if ((ch = *cp) == 0) { lookup_mode = MAC_EXP_MODE_USE; break; } if (ch == '?' || ch == ':') { *cp++ = 0; lookup_mode = MAC_EXP_MODE_TEST; break; } if (!ACL_ISALNUM(ch) && ch != '_') { acl_msg_warn("macro name syntax error: \"%s\"", acl_vstring_str(buf)); mc->status |= MAC_PARSE_ERROR; return (mc->status); } } /* * Look up the named parameter. */ text = mc->lookup(acl_vstring_str(buf), lookup_mode, mc->context, &pp, &size); /* * Perform the requested substitution. */ switch (ch) { case '?': if (text != 0 && *text != 0) mac_parse(cp, mac_expand_callback, (char *) mc); break; case ':': if (text == 0 || *text == 0) mac_parse(cp, mac_expand_callback, (char *) mc); break; default: if (text == 0) { mc->status |= MAC_PARSE_UNDEF; } else if (*text == 0) { /* void */ ; } else if (mc->flags & MAC_EXP_FLAG_RECURSE) { acl_vstring_strcpy(buf, text); mac_parse(acl_vstring_str(buf), mac_expand_callback, (char *) mc); } else { len = (int) ACL_VSTRING_LEN(mc->result); acl_vstring_strcat(mc->result, text); if (mc->filter) { cp = acl_vstring_str(mc->result) + len; while (*(cp += strspn(cp, mc->filter))) *cp++ = '_'; } } break; } } /* * Literal text. */ else { acl_vstring_strcat(mc->result, acl_vstring_str(buf)); } mc->level--; if (pp) free(pp); return (mc->status); }