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); }
static const char *xml_meta_attr_value(ACL_XML_ATTR *attr, const char *data) { int ch; SKIP_SPACE(data); if (*data == 0) return data; if (IS_QUOTE(*data)) attr->quote = *data++; while ((ch = *data) != 0) { if (attr->backslash) { ACL_VSTRING_ADDCH(attr->value, ch); attr->backslash = 0; } else if (ch == '\\') { if (attr->part_word) { ACL_VSTRING_ADDCH(attr->value, ch); attr->part_word = 0; } else attr->backslash = 1; } else if (attr->quote) { if (ch == attr->quote) { data++; break; } ACL_VSTRING_ADDCH(attr->value, ch); } else if (IS_SPACE(ch)) { data++; break; } else { ACL_VSTRING_ADDCH(attr->value, ch); if ((attr->node->xml->flag & ACL_XML_FLAG_PART_WORD)) { if (attr->part_word) attr->part_word = 0; else if (ch < 0) attr->part_word = 1; } } data++; } ACL_VSTRING_TERMINATE(attr->value); return data; }
static void acl_token_name_walk(const ACL_TOKEN *token, void *arg) { ACL_VSTRING *buf = (ACL_VSTRING*) arg; ACL_VSTRING *name = acl_vstring_alloc(256); acl_token_name(token, name); if (LEN(buf) > 0) ACL_VSTRING_ADDCH(buf, ';'); acl_vstring_strcat(buf, STR(name)); acl_vstring_free(name); }
static void strip_address(ACL_VSTRING *vp, ssize_t start, TOK822 *addr) { ACL_VSTRING *tmp; /* * Emit plain <address>. Discard any comments or phrases. */ ACL_VSTRING_TERMINATE(vp); acl_msg_warn("stripping too many comments from address: %.100s...", acl_vstring_str(vp) + start); //acl_printable(vstring_str(vp) + start, '?')); //zsx acl_vstring_truncate(vp, start); ACL_VSTRING_ADDCH(vp, '<'); if (addr) { tmp = acl_vstring_alloc(100); tok822_internalize(tmp, addr, TOK822_STR_TERM); quote_822_local_flags(vp, acl_vstring_str(tmp), QUOTE_FLAG_8BITCLEAN | QUOTE_FLAG_APPEND); acl_vstring_free(tmp); } ACL_VSTRING_ADDCH(vp, '>'); }
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 const char *xml_parse_right_lt(ACL_XML *xml, const char *data) { ACL_XML_NODE *node; SKIP_SPACE(data); if (*data == 0) return (NULL); if (*data == '/') { xml->curr_node->status = ACL_XML_S_RTAG; data++; return (data); } else if ((xml->curr_node->flag & ACL_XML_F_LEAF)) { ACL_VSTRING_ADDCH(xml->curr_node->text, '<'); ACL_VSTRING_ADDCH(xml->curr_node->text, *data); ACL_VSTRING_TERMINATE(xml->curr_node->text); xml->curr_node->status = ACL_XML_S_TXT; data++; return (data); } /* 说明遇到了当前结点的子结点 */ /* 重新设置当前结点状态,以便于其可以找到 "</" */ xml->curr_node->status = ACL_XML_S_TXT; /* 创建新的子结点,并将其加入至当前结点的子结点集合中 */ node = acl_xml_node_alloc(xml); acl_xml_node_add_child(xml->curr_node, node); node->depth = xml->curr_node->depth + 1; if (node->depth > xml->depth) xml->depth = node->depth; xml->curr_node = node; xml->curr_node->status = ACL_XML_S_LLT; return (data); }
static const char *xml_parse_meta_tag(ACL_XML *xml, const char *data) { int ch; while ((ch = *data) != 0) { data++; if (IS_SPACE(ch)) { xml->curr_node->status = ACL_XML_S_MTXT; break; } ACL_VSTRING_ADDCH(xml->curr_node->ltag, ch); } ACL_VSTRING_TERMINATE(xml->curr_node->ltag); return (data); }
static const char *xml_parse_attr(ACL_XML *xml, const char *data) { int ch; ACL_XML_ATTR *attr = xml->curr_node->curr_attr; if (attr == NULL || LEN(attr->name) == 0) { SKIP_SPACE(data); /* 略过 ' ', '\t' */ if (*data == 0) return (NULL); SKIP_WHILE(*data == '=', data); if (*data == 0) return (NULL); } if (*data == '>') { xml->curr_node->status = ACL_XML_S_LGT; xml_parse_check_self_closed(xml); xml->curr_node->curr_attr = NULL; data++; return (data); } xml->curr_node->last_ch = *data; if (*data == '/') { data++; return (data); } if (attr == NULL) { attr = acl_xml_attr_alloc(xml->curr_node); xml->curr_node->curr_attr = attr; } while ((ch = *data) != 0) { xml->curr_node->last_ch = ch; if (ch == '=') { xml->curr_node->status = ACL_XML_S_AVAL; data++; break; } if (!IS_SPACE(ch)) ACL_VSTRING_ADDCH(attr->name, ch); data++; } ACL_VSTRING_TERMINATE(attr->name); return (data); }
static const char *xml_meta_attr_name(ACL_XML_ATTR *attr, const char *data) { int ch; while ((ch = *data) != 0) { if (ch == '=') { data++; ACL_VSTRING_TERMINATE(attr->name); break; } if (!IS_SPACE(ch)) ACL_VSTRING_ADDCH(attr->name, ch); data++; } return data; }
int acl_xml_encode(const char *in, ACL_VSTRING *out) { int n = 0; while (*in) { if (__charmap[(unsigned char)(*in)] != NULL) { acl_vstring_strcat(out, __charmap[(unsigned char)(*in)]); n++; } else ACL_VSTRING_ADDCH(out, (*in)); in++; } ACL_VSTRING_TERMINATE(out); return (n); }
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); }
static const char *xml_parse_text(ACL_XML *xml, const char *data) { int ch; if (LEN(xml->curr_node->text) == 0) { SKIP_SPACE(data); if (*data == 0) return (NULL); } while ((ch = *data) != 0) { if (ch == '<') { xml->curr_node->status = ACL_XML_S_RLT; data++; break; } ACL_VSTRING_ADDCH(xml->curr_node->text, ch); data++; } ACL_VSTRING_TERMINATE(xml->curr_node->text); if (xml->curr_node->status != ACL_XML_S_RLT) return (data); if ((xml->curr_node->flag & ACL_XML_F_SELF_CL)) { /* 如果该标签是自关闭类型,则应使父结点直接跳至右边 '/' 处理位置, * 同时使本结点跳至右边 '>' 处理位置 */ ACL_XML_NODE *parent = acl_xml_node_parent(xml->curr_node); if (parent != xml->root) parent->status = ACL_XML_S_RLT; xml->curr_node->status = ACL_XML_S_RGT; } if (LEN(xml->curr_node->text) == 0) return (data); return (data); }
int acl_xml_encode(const char *in, ACL_VSTRING *out) { const unsigned char *ptr = (const unsigned char*) in; int n = 0; size_t len = strlen(in); len += len / 2; ACL_VSTRING_SPACE(out, (int) len); while (*ptr) { if (__charmap[*ptr] != NULL) { acl_vstring_strcat(out, __charmap[*ptr]); n++; } else { ACL_VSTRING_ADDCH(out, *ptr); } ptr++; } ACL_VSTRING_TERMINATE(out); return n; }
static const char *xml_parse_meta_comment(ACL_XML *xml, const char *data) { int ch; if (LEN(xml->curr_node->text) == 0) { SKIP_SPACE(data); } while ((ch = *data) != 0) { if (xml->curr_node->quote) { if (ch == xml->curr_node->quote) { xml->curr_node->quote = 0; } else { ACL_VSTRING_ADDCH(xml->curr_node->text, ch); } } else if (IS_QUOTE(ch)) { if (xml->curr_node->quote == 0) { xml->curr_node->quote = ch; } else { ACL_VSTRING_ADDCH(xml->curr_node->text, ch); } } else if (ch == '<') { xml->curr_node->nlt++; ACL_VSTRING_ADDCH(xml->curr_node->text, ch); } else if (ch == '>') { if (xml->curr_node->nlt == 0) { if (xml->curr_node->meta[0] == '-' && xml->curr_node->meta[1] == '-') { data++; xml->curr_node->status = ACL_XML_S_MEND; break; } } xml->curr_node->nlt--; ACL_VSTRING_ADDCH(xml->curr_node->text, ch); } else if (xml->curr_node->nlt > 0) { ACL_VSTRING_ADDCH(xml->curr_node->text, ch); } else if (ch == '-') { if (xml->curr_node->meta[0] != '-') { xml->curr_node->meta[0] = '-'; } else if (xml->curr_node->meta[1] != '-') { xml->curr_node->meta[1] = '-'; } } else { if (xml->curr_node->meta[0] == '-') { ACL_VSTRING_ADDCH(xml->curr_node->text, '-'); xml->curr_node->meta[0] = 0; } if (xml->curr_node->meta[1] == '-') { ACL_VSTRING_ADDCH(xml->curr_node->text, '-'); xml->curr_node->meta[1] = 0; } ACL_VSTRING_ADDCH(xml->curr_node->text, ch); } data++; } ACL_VSTRING_TERMINATE(xml->curr_node->text); return (data); }
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); }
static const char *xml_parse_attr_val(ACL_XML *xml, const char *data) { int ch; ACL_XML_ATTR *attr = xml->curr_node->curr_attr; if (LEN(attr->value) == 0 && !attr->quote) { SKIP_SPACE(data); if (IS_QUOTE(*data)) { attr->quote = *data++; } if (*data == 0) { return (NULL); } } while ((ch = *data) != 0) { if (attr->backslash) { ACL_VSTRING_ADDCH(attr->value, ch); xml->curr_node->last_ch = ch; attr->backslash = 0; } else if (ch == '\\') { if (attr->part_word) { ACL_VSTRING_ADDCH(attr->value, ch); attr->part_word = 0; } else attr->backslash = 1; } else if (attr->quote) { if (ch == attr->quote) { xml->curr_node->status = ACL_XML_S_ATTR; xml->curr_node->last_ch = ch; data++; break; } ACL_VSTRING_ADDCH(attr->value, ch); xml->curr_node->last_ch = ch; } else if (ch == '>') { xml->curr_node->status = ACL_XML_S_LGT; xml_parse_check_self_closed(xml); data++; break; } else if (IS_SPACE(ch)) { xml->curr_node->status = ACL_XML_S_ATTR; xml->curr_node->last_ch = ch; data++; break; } else { ACL_VSTRING_ADDCH(attr->value, ch); xml->curr_node->last_ch = ch; if ((xml->flag & ACL_XML_FLAG_PART_WORD)) { /* 处理半个汉字的情形 */ if (attr->part_word) attr->part_word = 0; else if (ch < 0) attr->part_word = 1; } } data++; } ACL_VSTRING_TERMINATE(attr->value); if (xml->curr_node->status != ACL_XML_S_AVAL) { /* 将该标签ID号映射至哈希表中,以便于快速查询 */ if (IS_ID(STR(attr->name)) && LEN(attr->value) > 0) { const char *ptr = STR(attr->value); /* 防止重复ID被插入现象 */ if (acl_htable_find(xml->id_table, ptr) == NULL) { acl_htable_enter(xml->id_table, ptr, attr); /* 只有当该属性被加入哈希表后才会赋于结点的 id */ xml->curr_node->id = attr->value; } } /* 必须将该结点的当前属性对象置空,以便于继续解析时 * 可以创建新的属性对象 */ xml->curr_node->curr_attr = NULL; } return (data); }
static void thread_write_fn(void *arg) { char *id = (char*) arg; char key[256], buf[256]; ACL_VSTRING *value = acl_vstring_alloc(__value_size); time_t begin, last, now; DICT_POOL_DB *db; int i, n, j; KEY *key_array; key_array = (KEY*) acl_mycalloc(__max, sizeof(KEY)); n = __value_size; acl_vstring_sprintf(value, "%u:", (unsigned) acl_pthread_self()); n -= LEN(value); for (i = 0; i < n; i++) ACL_VSTRING_ADDCH(value, 'v'); ACL_VSTRING_TERMINATE(value); time(&begin); last = begin; for (j = 0, i = __begin; i < __begin + __max; i++) { snprintf(buf, sizeof(buf), "%s:%s:%d", __key_pre, id, i); #if 0 MDString(buf, key, sizeof(key)); #else acl_uint64 k = acl_hash_crc64(buf, strlen(buf)); snprintf(key, sizeof(key), "%llu", k); #endif key_array[j++].key = acl_mystrdup(key); } if (__max <= 100) { printf("before sort\n"); for (i = 0; i < __max; i++) { printf("key[%d]: %s\n", i, key_array[i].key); } } if (__sort) qsort(key_array, __max, sizeof(KEY), cmp_fn); if (__max <= 100) { printf("after sort\n"); for (i = 0; i < __max; i++) { printf("key[%d]: %s\n", i, key_array[i].key); } } for (i = 0; i < __max; i++) { char *ptr; size_t size; db = dict_pool_db(__dict_pool, key_array[i].key, strlen(key_array[i].key)); dict_pool_db_lock(db); ptr = dict_pool_db_get(db, key_array[i].key, strlen(key_array[i].key), &size); if (ptr != NULL) { printf("key: %s exist now, size: %d\n", key_array[i].key, (int) size); acl_myfree(ptr); } dict_pool_db_set(db, key_array[i].key, strlen(key_array[i].key), STR(value), LEN(value)); ptr = dict_pool_db_get(db, key_array[i].key, strlen(key_array[i].key), &size); if (ptr == NULL) { printf("key: %s not add into db\n", key_array[i].key); } else acl_myfree(ptr); dict_pool_db_unlock(db); if (i > 0 && i % __report_base == 0) { time(&now); printf("thread %u add one, i=%d, time=%ld, key=%s\r\n", (unsigned) acl_pthread_self(), i, now - last, key_array[i].key); last = now; } LOCK; __nwrite++; UNLOCK; } for (i = 0; i < __max; i++) { acl_myfree(key_array[i].key); } acl_myfree(key_array); acl_vstring_free(value); acl_myfree(id); printf("thread %u add over, i=%d, time=%ld\r\n", (unsigned) acl_pthread_self(), i, time(NULL) - begin); }
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); }
int mac_parse(const char *value, MAC_PARSE_FN action, char *context) { const char *myname = "mac_parse"; ACL_VSTRING *buf = acl_vstring_alloc(1); /* result buffer */ const char *vp; /* value pointer */ const char *pp; /* open_paren pointer */ const char *ep; /* string end pointer */ static char open_paren[] = "({"; static char close_paren[] = ")}"; int level; int status = 0; #define SKIP(start, var, cond) \ for (var = start; *var && (cond); var++); acl_debug(DEBUG_MAC, 2) ("%s: %s", myname, value); for (vp = value; *vp;) { if (*vp != '$') { /* ordinary character */ ACL_VSTRING_ADDCH(buf, *vp); vp += 1; } else if (vp[1] == '$') { /* $$ becomes $ */ ACL_VSTRING_ADDCH(buf, *vp); vp += 2; } else { /* found bare $ */ if (ACL_VSTRING_LEN(buf) > 0) MAC_PARSE_ACTION(status, MAC_PARSE_LITERAL, buf, context); vp += 1; pp = open_paren; if (*vp == *pp || *vp == *++pp) { /* ${x} or $(x) */ level = 1; vp += 1; for (ep = vp; level > 0; ep++) { if (*ep == 0) { acl_msg_warn("truncated macro reference: \"%s\"", value); status |= MAC_PARSE_ERROR; break; } if (*ep == *pp) level++; if (*ep == close_paren[pp - open_paren]) level--; } if (status & MAC_PARSE_ERROR) break; acl_vstring_strncat(buf, vp, level > 0 ? ep - vp : ep - vp - 1); vp = ep; } else { /* plain $x */ SKIP(vp, ep, ACL_ISALNUM(*ep) || *ep == '_'); acl_vstring_strncat(buf, vp, ep - vp); vp = ep; } if (ACL_VSTRING_LEN(buf) == 0) { status |= MAC_PARSE_ERROR; acl_msg_warn("empty macro name: \"%s\"", value); break; } MAC_PARSE_ACTION(status, MAC_PARSE_EXPR, buf, context); } } if (ACL_VSTRING_LEN(buf) > 0 && (status & MAC_PARSE_ERROR) == 0) MAC_PARSE_ACTION(status, MAC_PARSE_LITERAL, buf, context); /* * Cleanup. */ acl_vstring_free(buf); return (status); }
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 }
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 *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); }