├── .gitignore ├── src ├── config ├── sasl_header_parser.h ├── http_auth_header_parser.h ├── http_auth_header_parser.peg ├── sc_map.h ├── sc_map.c ├── ngx_http_auth_sasl_module.c └── http_auth_header_parser.c ├── debug.conf ├── Makefile ├── LICENSE └── README.org /.gitignore: -------------------------------------------------------------------------------- 1 | root/ 2 | *.core 3 | -------------------------------------------------------------------------------- /src/config: -------------------------------------------------------------------------------- 1 | ngx_addon_name=ngx_http_auth_sasl_module 2 | HTTP_MODULES="$HTTP_MODULES ngx_http_auth_sasl_module" 3 | NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_addon_dir/ngx_http_auth_sasl_module.c $ngx_addon_dir/http_auth_header_parser.c $ngx_addon_dir/sc_map.c" 4 | CORE_LIBS="$CORE_LIBS -lsasl2" 5 | 6 | -------------------------------------------------------------------------------- /debug.conf: -------------------------------------------------------------------------------- 1 | error_log logs/error.log debug; 2 | events { } 3 | http { 4 | auth_sasl localhost; 5 | sasl_realm localhost; 6 | sasl_mechanisms "OPAQUE"; 7 | sasl_db_path /usr/local/etc/sasldb2; 8 | 9 | add_header X-SASL-SECURE $sasl_secure; 10 | add_header X-REMOTE-USER $sasl_user; 11 | add_header X-SASL-REALM $sasl_realm; 12 | add_header X-SASL-MECH $sasl_mech; 13 | 14 | server { 15 | listen *:8090; 16 | root .; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/sasl_header_parser.h: -------------------------------------------------------------------------------- 1 | #ifndef sasl_header_parser_h 2 | #define sasl_header_parser_h 3 | 4 | #include 5 | 6 | typedef struct { 7 | const char *realm; 8 | size_t realm_len; 9 | const char *mech; 10 | size_t mech_len; 11 | unsigned long s2s; 12 | const char *c2s; 13 | size_t c2s_len; 14 | const char *s2c; 15 | size_t *s2c_len; 16 | const char* input; 17 | size_t input_len; 18 | size_t input_ptr; 19 | } sasl_header_fields_t; 20 | 21 | 22 | void parse_header(sasl_header_fields_t *auxil, const unsigned char* header, const size_t header_len); 23 | 24 | #endif // sasl_header_parser_h 25 | -------------------------------------------------------------------------------- /src/http_auth_header_parser.h: -------------------------------------------------------------------------------- 1 | /* A packrat parser generated by PackCC 1.8.0 */ 2 | 3 | #ifndef PCC_INCLUDED_HTTP_AUTH_HEADER_PARSER_H 4 | #define PCC_INCLUDED_HTTP_AUTH_HEADER_PARSER_H 5 | 6 | #line 10 "http_auth_header_parser.peg" 7 | #include "sasl_header_parser.h" 8 | #line 8 "http_auth_header_parser.h" 9 | #ifdef __cplusplus 10 | extern "C" { 11 | #endif 12 | 13 | typedef struct sasl_header_context_tag sasl_header_context_t; 14 | 15 | sasl_header_context_t *sasl_header_create(sasl_header_fields_t*auxil); 16 | int sasl_header_parse(sasl_header_context_t *ctx, int *ret); 17 | void sasl_header_destroy(sasl_header_context_t *ctx); 18 | 19 | #ifdef __cplusplus 20 | } 21 | #endif 22 | 23 | #endif /* !PCC_INCLUDED_HTTP_AUTH_HEADER_PARSER_H */ 24 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | default: build 2 | 3 | NGINX_ROOT = ../nginx 4 | 5 | .PHONY: clean configure build start stop test curl 6 | 7 | src/http_auth_header_parser.c: src/http_auth_header_parser.peg 8 | cd src; ../../packcc/build/gcc/debug/bin/packcc -a -l http_auth_header_parser.peg 9 | 10 | clean: 11 | if [ -e $(NGINX_ROOT)/Makefile ]; then \ 12 | $(MAKE) -C $(NGINX_ROOT) clean; \ 13 | fi 14 | rm -rf root nginx.core 15 | 16 | configure: stop 17 | cd $(NGINX_ROOT) && CFLAGS="-Wno-error=cast-function-type -O0 -g" ./configure --with-debug --add-module=${CURDIR}/src 18 | 19 | build: stop src/http_auth_header_parser.c 20 | $(MAKE) -C $(NGINX_ROOT) build 21 | 22 | root: 23 | mkdir -p root/logs 24 | 25 | root/debug.conf: root debug.conf 26 | cp ${CURDIR}/debug.conf root/debug.conf 27 | 28 | root/logs: root 29 | mkdir -p root/logs 30 | 31 | start: build root/logs root/debug.conf 32 | rm -f root/logs/error.log 33 | $(NGINX_ROOT)/objs/nginx -p ${CURDIR}/root -c debug.conf 34 | 35 | stop: 36 | if [ -e ${CURDIR}/root/logs/nginx.pid ]; then \ 37 | if [ -x $(NGINX_ROOT)/objs/nginx ]; then \ 38 | $(NGINX_ROOT)/objs/nginx -s stop -p ${CURDIR}/root -c debug.conf; \ 39 | fi ; \ 40 | fi 41 | 42 | test: start curl stop 43 | 44 | curl: 45 | python3 ../../sasl/http_sasl.py 46 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 20229, Stefan Marsiske 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions 6 | are met: 7 | 8 | 1. Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | 11 | 2. Redistributions in binary form must reproduce the above copyright 12 | notice, this list of conditions and the following disclaimer in 13 | the documentation and/or other materials provided with the 14 | distribution. 15 | 16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 | HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | 28 | 29 | # SPDX-License-Identifier: BSD-2-Clause 30 | # SPDX-FileCopyrightText: Stefan Marsiske 31 | # 32 | -------------------------------------------------------------------------------- /src/http_auth_header_parser.peg: -------------------------------------------------------------------------------- 1 | %prefix "sasl_header" 2 | 3 | # packcc -l sasl_header.peg && gcc -o sasl_header sasl_header.c && ./sasl_header 4 | # outputs 5 | # c2s : vqIkiXo9hh740PGdOKSXYkNIfPNwQxx028LBjVVxHRcAAQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eH2iFbpPZ0yQ051VgeZtfYS2Tsam8EryENhhSfagov994cwBzAA== 6 | # realm: localhost 7 | # mech: OPAQUE 8 | 9 | %header { 10 | #include "sasl_header_parser.h" 11 | } 12 | 13 | %source { 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | #define PCC_GETCHAR(auxil) next_chr(auxil) 20 | 21 | static int next_chr(sasl_header_fields_t *auxil) { 22 | if(auxil->input_ptr < auxil->input_len) { 23 | return auxil->input[auxil->input_ptr++]; 24 | } 25 | return EOF; 26 | } 27 | 28 | } 29 | 30 | %auxil "sasl_header_fields_t*" 31 | 32 | header <- [Ss][Aa][Ss][Ll] assertion (',' assertion )* 33 | 34 | assertion <- _ (msg/mech/realm) _ 35 | 36 | # s2c is not needed in a server 37 | # msg <- s2s / s2c / c2s 38 | msg <- s2s / c2s 39 | s2s <- "s2s" _ '=' _ '"' < [0-9a-fA-F]+ > '"' { 40 | errno = 0; 41 | long tmp = strtoul($1,NULL,16); 42 | if (errno == 0) auxil->s2s = tmp; 43 | } 44 | # s2c <- "s2c" _ '=' _ '"' < base64string > '"' { 45 | # auxil->s2c = auxil->input + $1s; 46 | # auxil->s2c_len = $1e - $1s; 47 | #} 48 | c2s <- "c2s" _ '=' _ '"' < base64string > '"' { 49 | auxil->c2s = auxil->input + $1s; 50 | auxil->c2s_len = $1e - $1s; 51 | } 52 | 53 | mech <- [Mm][Ee][Cc][Hh] _ '=' _ '"' < mechstring > '"' { 54 | auxil->mech = auxil->input + $1s; 55 | auxil->mech_len = $1e - $1s; 56 | } 57 | realm <- [Rr][Ee][Aa][Ll][Mm] _ '=' _ '"' < realmstring > '"' { 58 | auxil->realm = auxil->input + $1s; 59 | auxil->realm_len = $1e - $1s; 60 | } 61 | 62 | realmstring <- [^"\\]* 63 | mechstring <- [A-Z0-9-_][A-Z0-9-_]?[A-Z0-9-_]?[A-Z0-9-_]?[A-Z0-9-_]?[A-Z0-9-_]?[A-Z0-9-_]?[A-Z0-9-_]?[A-Z0-9-_]?[A-Z0-9-_]?[A-Z0-9-_]?[A-Z0-9-_]?[A-Z0-9-_]?[A-Z0-9-_]?[A-Z0-9-_]?[A-Z0-9-_]?[A-Z0-9-_]?[A-Z0-9-_]?[A-Z0-9-_]?[A-Z0-9-_]? 64 | base64string <- [a-zA-Z0-9-._~+/]*'='* 65 | _ <- [ \t]* 66 | 67 | 68 | %% 69 | 70 | void parse_header(sasl_header_fields_t *auxil, const unsigned char* header, const size_t header_len) { 71 | auxil->input = (const char*) header; 72 | auxil->input_len = header_len; 73 | sasl_header_context_t *ctx = sasl_header_create(auxil); 74 | while (sasl_header_parse(ctx, NULL)); 75 | sasl_header_destroy(ctx); 76 | } 77 | 78 | #ifdef TEST 79 | int main(void) { 80 | sasl_header_fields_t parsed={0}; 81 | const char header[]="SASL c2s=\"vqIkiXo9hh740PGdOKSXYkNIfPNwQxx028LBjVVxHRcAAQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eH2iFbpPZ0yQ051VgeZtfYS2Tsam8EryENhhSfagov994cwBzAA==\",realm=\"localhost\",mech=\"OPAQUE\""; 82 | parse_header(&parsed, header, strlen(header)); 83 | 84 | if(parsed.mech) printf("mech: %s\n", parsed.mech); 85 | if(parsed.realm) printf("realm: %s\n", parsed.realm); 86 | if(parsed.s2s) printf("s2s: %ld\n", parsed.s2s); 87 | if(parsed.s2c) printf("s2c: %s\n", parsed.s2c); 88 | if(parsed.c2s) printf("c2s: %s\n", parsed.c2s); 89 | 90 | return 0; 91 | } 92 | #endif -------------------------------------------------------------------------------- /README.org: -------------------------------------------------------------------------------- 1 | * NGINX HTTP SASL authentication module 2 | 3 | This is experimental. 4 | 5 | It implements this RFC draft: 6 | https://datatracker.ietf.org/doc/html/draft-vanrein-httpauth-sasl 7 | 8 | ** Dependencies 9 | If you want to build this, it expects an nginx source tree in '../nginx' 10 | 11 | You also need https://github.com/arithy/packcc in '../packcc/' if you change 12 | 'src/http_auth_header_parser.peg'. 13 | 14 | ** Deployment 15 | 16 | you can test with this script: 17 | https://github.com/stef/libopaque/blob/master/sasl/http_sasl.py if you 18 | have also the opaque mechanism installed from the libopaque 19 | repo. Otherwise adapt the script to use a different mechanism. 20 | 21 | In any case the Makefile explains it all, or has pointers to more 22 | information. 23 | 24 | ** Limitations 25 | 26 | One possible limitation is that SASL is(/can be) stateful, and the 27 | state is currently kept in a worker process. If different worker 28 | processes handle the different steps of the same authentication flow 29 | then the state will be a problem, as it is currently not shared 30 | between worker processes. Sadly the state used by cyrus sasl contains 31 | all kind of pointers, especially function pointers (which should be 32 | the same, but this is depending also on the SASL mech probably) and 33 | thus using shared memory to share the contexts could lead to problems. 34 | 35 | Even more of a limitation is if the SASL auth is terminated at servers 36 | behind a load balancer, the SASL state must be known by the backend 37 | server, otherwise it will not succeed, thus a load balancer must make 38 | sure that the same backend server is used for the whole of a SASL auth 39 | execution. 40 | 41 | ** Variables 42 | 43 | This module setst the following nginx variables: 44 | 45 | *** sasl_secure 46 | Is only "yes" (without the quotes) when a client is authenticated to 47 | the current resource. It never has another value; it is simply 48 | undefined when not secured by SASL 49 | 50 | *** sasl_realm 51 | Is the realm for which the secure exchange succeeded. A realm is not 52 | always used, because sites only need it when there are more than one 53 | in the same name space. When undefined in the SASL flow, this variable 54 | will not be set. 55 | 56 | *** sasl_user 57 | Is the client identity as confirmed through SASL authentication. Its 58 | content is formatted like an email address, and includes a domain 59 | name. That domain need not be related to the web server; it is 60 | possible for a web server to welcome foreign clients. 61 | 62 | *** sasl_mech 63 | Indicates the mechanism used, and is one of the standardised SASL 64 | mechanism names. It may be used to detect the level of security. 65 | 66 | ** Config 67 | 68 | A minimal example config with verbose logging: 69 | 70 | #+BEGIN_EXAMPLE 71 | error_log logs/error.log debug; 72 | events { } 73 | http { 74 | auth_sasl localhost; 75 | sasl_realm localhost; 76 | sasl_mechanisms "OPAQUE"; 77 | sasl_db_path /usr/local/etc/sasldb2; 78 | 79 | add_header X-SASL-SECURE $sasl_secure; 80 | add_header X-REMOTE-USER $sasl_user; 81 | add_header X-SASL-REALM $sasl_realm; 82 | add_header X-SASL-MECH $sasl_mech; 83 | 84 | server { 85 | listen *:8090; 86 | root .; 87 | } 88 | } 89 | #+END_EXAMPLE 90 | 91 | ** Credits 92 | 93 | This project was funded through the NGI0 PET Fund, a fund established 94 | by NLnet with financial support from the European Commission's Next 95 | Generation Internet programme, under the aegis of DG Communications 96 | Networks, Content and Technology under grant agreement No 825310. 97 | -------------------------------------------------------------------------------- /src/sc_map.h: -------------------------------------------------------------------------------- 1 | /* 2 | * BSD-3-Clause 3 | * 4 | * Copyright 2021 Ozan Tezcan 5 | * All rights reserved. 6 | * 7 | * Redistribution and use in source and binary forms, with or without 8 | * modification, are permitted provided that the following conditions are met: 9 | * 10 | * 1. Redistributions of source code must retain the above copyright notice, 11 | * this list of conditions and the following disclaimer. 12 | * 2. Redistributions in binary form must reproduce the above copyright notice, 13 | * this list of conditions and the following disclaimer in the documentation 14 | * and/or other materials provided with the distribution. 15 | * 3. Neither the name of the copyright holder nor the names of its contributors 16 | * may be used to endorse or promote products derived from this software 17 | * without specific prior written permission. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 23 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 24 | * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 25 | * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 | * POSSIBILITY OF SUCH DAMAGE. 30 | */ 31 | 32 | #ifndef SC_MAP_H 33 | #define SC_MAP_H 34 | 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | 41 | #define SC_MAP_VERSION "2.0.0" 42 | 43 | #ifdef SC_HAVE_CONFIG_H 44 | #include "config.h" 45 | #else 46 | #define sc_map_calloc calloc 47 | #define sc_map_free free 48 | #endif 49 | 50 | #define sc_map_dec_strkey(name, K, V) \ 51 | struct sc_map_item_##name { \ 52 | K key; \ 53 | V value; \ 54 | uint32_t hash; \ 55 | }; \ 56 | \ 57 | sc_map_of(name, K, V) 58 | 59 | #define sc_map_dec_scalar(name, K, V) \ 60 | struct sc_map_item_##name { \ 61 | K key; \ 62 | V value; \ 63 | }; \ 64 | \ 65 | sc_map_of(name, K, V) 66 | 67 | #define sc_map_of(name, K, V) \ 68 | struct sc_map_##name { \ 69 | struct sc_map_item_##name *mem; \ 70 | uint32_t cap; \ 71 | uint32_t size; \ 72 | uint32_t load_fac; \ 73 | uint32_t remap; \ 74 | bool used; \ 75 | bool oom; \ 76 | bool found; \ 77 | }; \ 78 | \ 79 | /** \ 80 | * Create map \ 81 | * \ 82 | * @param map map \ 83 | * @param cap initial capacity, zero is accepted \ 84 | * @param load_factor must be >25 and <95. Pass 0 for default value. \ 85 | * @return 'true' on success, \ 86 | * 'false' on out of memory or if 'load_factor' value is \ 87 | * invalid. \ 88 | */ \ 89 | bool sc_map_init_##name(struct sc_map_##name *map, uint32_t cap, \ 90 | uint32_t load_factor); \ 91 | \ 92 | /** \ 93 | * Destroy map. \ 94 | * \ 95 | * @param map map \ 96 | */ \ 97 | void sc_map_term_##name(struct sc_map_##name *map); \ 98 | \ 99 | /** \ 100 | * Get map element count \ 101 | * \ 102 | * @param map map \ 103 | * @return element count \ 104 | */ \ 105 | uint32_t sc_map_size_##name(struct sc_map_##name *map); \ 106 | \ 107 | /** \ 108 | * Clear map \ 109 | * \ 110 | * @param map map \ 111 | */ \ 112 | void sc_map_clear_##name(struct sc_map_##name *map); \ 113 | \ 114 | /** \ 115 | * Put element to the map \ 116 | * \ 117 | * struct sc_map_str map; \ 118 | * sc_map_put_str(&map, "key", "value"); \ 119 | * \ 120 | * @param map map \ 121 | * @param K key \ 122 | * @param V value \ 123 | * @return previous value if exists \ 124 | * call sc_map_found() to see if returned value if valid. \ 125 | */ \ 126 | V sc_map_put_##name(struct sc_map_##name *map, K key, V val); \ 127 | \ 128 | /** \ 129 | * Get element \ 130 | * \ 131 | * @param map map \ 132 | * @param K key \ \ 133 | * @return current value if exists. \ 134 | * call sc_map_found() to see if returned value if valid. \ 135 | */ \ 136 | /** NOLINTNEXTLINE */ \ 137 | V sc_map_get_##name(struct sc_map_##name *map, K key); \ 138 | \ 139 | /** \ 140 | * Delete element \ 141 | * \ 142 | * @param map map \ 143 | * @param K key \ 144 | * @return current value if exists. \ 145 | * call sc_map_found() to see if returned value if valid. \ 146 | */ \ 147 | /** NOLINTNEXTLINE */ \ 148 | V sc_map_del_##name(struct sc_map_##name *map, K key); 149 | 150 | /** 151 | * @param map map 152 | * @return - if put operation overrides a value, returns true 153 | * - if get operation finds the key, returns true 154 | * - if del operation deletes a key, returns true 155 | */ 156 | #define sc_map_found(map) ((map)->found) 157 | 158 | /** 159 | * @param map map 160 | * @return true if put operation failed with out of memory 161 | */ 162 | #define sc_map_oom(map) ((map)->oom) 163 | 164 | /** 165 | * Foreach loop 166 | * 167 | * char *key, *value; 168 | * struct sc_map_str map; 169 | * 170 | * sc_map_foreach(&map, key, value) { 171 | * printf("key = %s, value = %s \n"); 172 | * } 173 | */ 174 | #define sc_map_foreach(map, K, V) \ 175 | for (int64_t __i = -1, __b = 0; __i < (map)->cap; __i++) \ 176 | for ((V) = (map)->mem[__i].value, (K) = (map)->mem[__i].key, \ 177 | __b = 1; \ 178 | __b && ((__i == -1 && (map)->used) || (K) != 0); __b = 0) 179 | 180 | /** 181 | * Foreach loop for keys 182 | * 183 | * char *key; 184 | * struct sc_map_str map; 185 | * 186 | * sc_map_foreach_key(&map, key) { 187 | * printf("key = %s \n"); 188 | * } 189 | */ 190 | #define sc_map_foreach_key(map, K) \ 191 | for (int64_t __i = -1, __b = 0; __i < (map)->cap; __i++) \ 192 | for ((K) = (map)->mem[__i].key, __b = 1; \ 193 | __b && ((__i == -1 && (map)->used) || (K) != 0); __b = 0) 194 | 195 | /** 196 | * Foreach loop for values 197 | * 198 | * char *value; 199 | * struct sc_map_str map; 200 | * 201 | * sc_map_foreach_value(&map, value) { 202 | * printf("value = %s \n"); 203 | * } 204 | */ 205 | #define sc_map_foreach_value(map, V) \ 206 | for (int64_t __i = -1, __b = 0; __i < (map)->cap; __i++) \ 207 | for ((V) = (map)->mem[__i].value, __b = 1; \ 208 | __b && \ 209 | ((__i == -1 && (map)->used) || (map)->mem[__i].key != 0); \ 210 | __b = 0) 211 | 212 | // clang-format off 213 | 214 | // name key type value type 215 | sc_map_dec_scalar(32, uint32_t, uint32_t) 216 | sc_map_dec_scalar(64, uint64_t, uint64_t) 217 | sc_map_dec_scalar(64v, uint64_t, void *) 218 | sc_map_dec_scalar(64s, uint64_t, const char *) 219 | sc_map_dec_strkey(str, const char *, const char *) 220 | sc_map_dec_strkey(sv, const char *, void*) 221 | sc_map_dec_strkey(s64, const char *, uint64_t) 222 | 223 | // clang-format on 224 | 225 | #endif 226 | -------------------------------------------------------------------------------- /src/sc_map.c: -------------------------------------------------------------------------------- 1 | /* 2 | * BSD-3-Clause 3 | * 4 | * Copyright 2021 Ozan Tezcan 5 | * All rights reserved. 6 | * 7 | * Redistribution and use in source and binary forms, with or without 8 | * modification, are permitted provided that the following conditions are met: 9 | * 10 | * 1. Redistributions of source code must retain the above copyright notice, 11 | * this list of conditions and the following disclaimer. 12 | * 2. Redistributions in binary form must reproduce the above copyright notice, 13 | * this list of conditions and the following disclaimer in the documentation 14 | * and/or other materials provided with the distribution. 15 | * 3. Neither the name of the copyright holder nor the names of its contributors 16 | * may be used to endorse or promote products derived from this software 17 | * without specific prior written permission. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 23 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 24 | * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 25 | * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 | * POSSIBILITY OF SUCH DAMAGE. 30 | */ 31 | 32 | #include "sc_map.h" 33 | 34 | #include 35 | 36 | #ifndef SC_MAP_MAX 37 | #define SC_MAP_MAX UINT32_MAX 38 | #endif 39 | 40 | #define sc_map_def_strkey(name, K, V, cmp, hash_fn) \ 41 | bool sc_map_cmp_##name(struct sc_map_item_##name *t, K key, \ 42 | uint32_t hash) \ 43 | { \ 44 | return t->hash == hash && cmp(t->key, key); \ 45 | } \ 46 | \ 47 | void sc_map_assign_##name(struct sc_map_item_##name *t, K key, \ 48 | V value, uint32_t hash) \ 49 | { \ 50 | t->key = key; \ 51 | t->value = value; \ 52 | t->hash = hash; \ 53 | } \ 54 | \ 55 | uint32_t sc_map_hashof_##name(struct sc_map_item_##name *t) \ 56 | { \ 57 | return t->hash; \ 58 | } \ 59 | \ 60 | sc_map_def(name, K, V, cmp, hash_fn) 61 | 62 | #define sc_map_def_scalar(name, K, V, cmp, hash_fn) \ 63 | bool sc_map_cmp_##name(struct sc_map_item_##name *t, K key, \ 64 | uint32_t hash) \ 65 | { \ 66 | (void) hash; \ 67 | return cmp(t->key, key); \ 68 | } \ 69 | \ 70 | void sc_map_assign_##name(struct sc_map_item_##name *t, K key, \ 71 | V value, uint32_t hash) \ 72 | { \ 73 | (void) hash; \ 74 | t->key = key; \ 75 | t->value = value; \ 76 | } \ 77 | \ 78 | uint32_t sc_map_hashof_##name(struct sc_map_item_##name *t) \ 79 | { \ 80 | return hash_fn(t->key); \ 81 | } \ 82 | \ 83 | sc_map_def(name, K, V, cmp, hash_fn) 84 | 85 | #define sc_map_def(name, K, V, cmp, hash_fn) \ 86 | \ 87 | static const struct sc_map_item_##name empty_items_##name[2]; \ 88 | \ 89 | static const struct sc_map_##name sc_map_empty_##name = { \ 90 | .cap = 1, \ 91 | .mem = (struct sc_map_item_##name *) &empty_items_##name[1]}; \ 92 | \ 93 | static void *sc_map_alloc_##name(uint32_t *cap, uint32_t factor) \ 94 | { \ 95 | uint32_t v = *cap; \ 96 | struct sc_map_item_##name *t; \ 97 | \ 98 | if (*cap > SC_MAP_MAX / factor) { \ 99 | return NULL; \ 100 | } \ 101 | \ 102 | /* Find next power of two */ \ 103 | v = v < 8 ? 8 : (v * factor); \ 104 | v--; \ 105 | for (uint32_t i = 1; i < sizeof(v) * 8; i *= 2) { \ 106 | v |= v >> i; \ 107 | } \ 108 | v++; \ 109 | \ 110 | *cap = v; \ 111 | t = sc_map_calloc(sizeof(*t), v + 1); \ 112 | return t ? &t[1] : NULL; \ 113 | } \ 114 | \ 115 | bool sc_map_init_##name(struct sc_map_##name *m, uint32_t cap, \ 116 | uint32_t load_fac) \ 117 | { \ 118 | void *t; \ 119 | uint32_t f = (load_fac == 0) ? 75 : load_fac; \ 120 | \ 121 | if (f > 95 || f < 25) { \ 122 | return false; \ 123 | } \ 124 | \ 125 | if (cap == 0) { \ 126 | *m = sc_map_empty_##name; \ 127 | m->load_fac = f; \ 128 | return true; \ 129 | } \ 130 | \ 131 | t = sc_map_alloc_##name(&cap, 1); \ 132 | if (t == NULL) { \ 133 | return false; \ 134 | } \ 135 | \ 136 | m->mem = t; \ 137 | m->size = 0; \ 138 | m->used = false; \ 139 | m->cap = cap; \ 140 | m->load_fac = f; \ 141 | m->remap = (uint32_t) (m->cap * ((double) m->load_fac / 100)); \ 142 | \ 143 | return true; \ 144 | } \ 145 | \ 146 | void sc_map_term_##name(struct sc_map_##name *m) \ 147 | { \ 148 | if (m->mem != sc_map_empty_##name.mem) { \ 149 | sc_map_free(&m->mem[-1]); \ 150 | *m = sc_map_empty_##name; \ 151 | } \ 152 | } \ 153 | \ 154 | uint32_t sc_map_size_##name(struct sc_map_##name *m) \ 155 | { \ 156 | return m->size; \ 157 | } \ 158 | \ 159 | void sc_map_clear_##name(struct sc_map_##name *m) \ 160 | { \ 161 | if (m->size > 0) { \ 162 | for (uint32_t i = 0; i < m->cap; i++) { \ 163 | m->mem[i].key = 0; \ 164 | } \ 165 | \ 166 | m->used = false; \ 167 | m->size = 0; \ 168 | } \ 169 | } \ 170 | \ 171 | static bool sc_map_remap_##name(struct sc_map_##name *m) \ 172 | { \ 173 | uint32_t pos, cap, mod; \ 174 | struct sc_map_item_##name *new; \ 175 | \ 176 | if (m->size < m->remap) { \ 177 | return true; \ 178 | } \ 179 | \ 180 | cap = m->cap; \ 181 | new = sc_map_alloc_##name(&cap, 2); \ 182 | if (new == NULL) { \ 183 | return false; \ 184 | } \ 185 | \ 186 | mod = cap - 1; \ 187 | \ 188 | for (uint32_t i = 0; i < m->cap; i++) { \ 189 | if (m->mem[i].key != 0) { \ 190 | pos = sc_map_hashof_##name(&m->mem[i]) & mod; \ 191 | \ 192 | while (true) { \ 193 | if (new[pos].key == 0) { \ 194 | new[pos] = m->mem[i]; \ 195 | break; \ 196 | } \ 197 | \ 198 | pos = (pos + 1) & (mod); \ 199 | } \ 200 | } \ 201 | } \ 202 | \ 203 | if (m->mem != sc_map_empty_##name.mem) { \ 204 | new[-1] = m->mem[-1]; \ 205 | sc_map_free(&m->mem[-1]); \ 206 | } \ 207 | \ 208 | m->mem = new; \ 209 | m->cap = cap; \ 210 | m->remap = (uint32_t) (m->cap * ((double) m->load_fac / 100)); \ 211 | \ 212 | return true; \ 213 | } \ 214 | \ 215 | V sc_map_put_##name(struct sc_map_##name *m, K key, V value) \ 216 | { \ 217 | V ret; \ 218 | uint32_t pos, mod, h; \ 219 | \ 220 | m->oom = false; \ 221 | \ 222 | if (!sc_map_remap_##name(m)) { \ 223 | m->oom = true; \ 224 | return 0; \ 225 | } \ 226 | \ 227 | if (key == 0) { \ 228 | ret = (m->used) ? m->mem[-1].value : 0; \ 229 | m->found = m->used; \ 230 | m->size += !m->used; \ 231 | m->used = true; \ 232 | m->mem[-1].value = value; \ 233 | \ 234 | return ret; \ 235 | } \ 236 | \ 237 | mod = m->cap - 1; \ 238 | h = hash_fn(key); \ 239 | pos = h & (mod); \ 240 | \ 241 | while (true) { \ 242 | if (m->mem[pos].key == 0) { \ 243 | m->size++; \ 244 | } else if (!sc_map_cmp_##name(&m->mem[pos], key, h)) { \ 245 | pos = (pos + 1) & (mod); \ 246 | continue; \ 247 | } \ 248 | \ 249 | m->found = m->mem[pos].key != 0; \ 250 | ret = m->found ? m->mem[pos].value : 0; \ 251 | sc_map_assign_##name(&m->mem[pos], key, value, h); \ 252 | \ 253 | return ret; \ 254 | } \ 255 | } \ 256 | \ 257 | /** NOLINTNEXTLINE */ \ 258 | V sc_map_get_##name(struct sc_map_##name *m, K key) \ 259 | { \ 260 | const uint32_t mod = m->cap - 1; \ 261 | uint32_t h, pos; \ 262 | \ 263 | if (key == 0) { \ 264 | m->found = m->used; \ 265 | return m->used ? m->mem[-1].value : 0; \ 266 | } \ 267 | \ 268 | h = hash_fn(key); \ 269 | pos = h & mod; \ 270 | \ 271 | while (true) { \ 272 | if (m->mem[pos].key == 0) { \ 273 | m->found = false; \ 274 | return 0; \ 275 | } else if (!sc_map_cmp_##name(&m->mem[pos], key, h)) { \ 276 | pos = (pos + 1) & (mod); \ 277 | continue; \ 278 | } \ 279 | \ 280 | m->found = true; \ 281 | return m->mem[pos].value; \ 282 | } \ 283 | } \ 284 | \ 285 | /** NOLINTNEXTLINE */ \ 286 | V sc_map_del_##name(struct sc_map_##name *m, K key) \ 287 | { \ 288 | const uint32_t mod = m->cap - 1; \ 289 | uint32_t pos, prev, it, p, h; \ 290 | V ret; \ 291 | \ 292 | if (key == 0) { \ 293 | m->found = m->used; \ 294 | m->size -= m->used; \ 295 | m->used = false; \ 296 | \ 297 | return m->found ? m->mem[-1].value : 0; \ 298 | } \ 299 | \ 300 | h = hash_fn(key); \ 301 | pos = h & (mod); \ 302 | \ 303 | while (true) { \ 304 | if (m->mem[pos].key == 0) { \ 305 | m->found = false; \ 306 | return 0; \ 307 | } else if (!sc_map_cmp_##name(&m->mem[pos], key, h)) { \ 308 | pos = (pos + 1) & (mod); \ 309 | continue; \ 310 | } \ 311 | \ 312 | m->found = true; \ 313 | ret = m->mem[pos].value; \ 314 | \ 315 | m->size--; \ 316 | m->mem[pos].key = 0; \ 317 | prev = pos; \ 318 | it = pos; \ 319 | \ 320 | while (true) { \ 321 | it = (it + 1) & (mod); \ 322 | if (m->mem[it].key == 0) { \ 323 | break; \ 324 | } \ 325 | \ 326 | p = sc_map_hashof_##name(&m->mem[it]) & (mod); \ 327 | \ 328 | if ((p > it && (p <= prev || it >= prev)) || \ 329 | (p <= prev && it >= prev)) { \ 330 | \ 331 | m->mem[prev] = m->mem[it]; \ 332 | m->mem[it].key = 0; \ 333 | prev = it; \ 334 | } \ 335 | } \ 336 | \ 337 | return ret; \ 338 | } \ 339 | } 340 | 341 | static uint32_t sc_map_hash_32(uint32_t a) 342 | { 343 | return a; 344 | } 345 | 346 | static uint32_t sc_map_hash_64(uint64_t a) 347 | { 348 | return ((uint32_t) a) ^ (uint32_t) (a >> 32u); 349 | } 350 | 351 | // clang-format off 352 | uint32_t murmurhash(const char *key) 353 | { 354 | const uint64_t m = UINT64_C(0xc6a4a7935bd1e995); 355 | const size_t len = strlen(key); 356 | const unsigned char* p = (const unsigned char*) key; 357 | const unsigned char *end = p + (len & ~(uint64_t) 0x7); 358 | uint64_t h = (len * m); 359 | 360 | while (p != end) { 361 | uint64_t k; 362 | memcpy(&k, p, sizeof(k)); 363 | 364 | k *= m; 365 | k ^= k >> 47u; 366 | k *= m; 367 | 368 | h ^= k; 369 | h *= m; 370 | p += 8; 371 | } 372 | 373 | switch (len & 7u) { 374 | case 7: h ^= (uint64_t) p[6] << 48ul; // fall through 375 | case 6: h ^= (uint64_t) p[5] << 40ul; // fall through 376 | case 5: h ^= (uint64_t) p[4] << 32ul; // fall through 377 | case 4: h ^= (uint64_t) p[3] << 24ul; // fall through 378 | case 3: h ^= (uint64_t) p[2] << 16ul; // fall through 379 | case 2: h ^= (uint64_t) p[1] << 8ul; // fall through 380 | case 1: h ^= (uint64_t) p[0]; // fall through 381 | h *= m; 382 | default: 383 | break; 384 | }; 385 | 386 | h ^= h >> 47u; 387 | h *= m; 388 | h ^= h >> 47u; 389 | 390 | return (uint32_t) h; 391 | } 392 | 393 | #define sc_map_eq(a, b) ((a) == (b)) 394 | #define sc_map_streq(a, b) (!strcmp(a, b)) 395 | 396 | // name, key type, value type, cmp hash 397 | sc_map_def_scalar(32, uint32_t, uint32_t, sc_map_eq, sc_map_hash_32) 398 | sc_map_def_scalar(64, uint64_t, uint64_t, sc_map_eq, sc_map_hash_64) 399 | sc_map_def_scalar(64v, uint64_t, void *, sc_map_eq, sc_map_hash_64) 400 | sc_map_def_scalar(64s, uint64_t, const char *, sc_map_eq, sc_map_hash_64) 401 | sc_map_def_strkey(str, const char *, const char *, sc_map_streq, murmurhash) 402 | sc_map_def_strkey(sv, const char *, void *, sc_map_streq, murmurhash) 403 | sc_map_def_strkey(s64, const char *, uint64_t, sc_map_streq, murmurhash) 404 | 405 | // clang-format on 406 | -------------------------------------------------------------------------------- /src/ngx_http_auth_sasl_module.c: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2022 Stefan Marsiske 3 | * 4 | * Based on 'ngx_http_auth_basic_module.c' by Igor Sysoev and 5 | * 'ngx_http_auth_pam_module.c' by Sergio Talens-Oliag. 6 | * 7 | */ 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include "sasl_header_parser.h" 16 | #include "sc_map.h" 17 | 18 | /* 19 | * Our per-location configuration. 20 | */ 21 | typedef struct { 22 | ngx_str_t realm; 23 | ngx_str_t service_name; 24 | ngx_str_t sasl_realm; 25 | ngx_str_t mechs; 26 | ngx_str_t db_path; 27 | //ngx_shm_zone_t *shm_zone; 28 | struct sc_map_64v *conns; 29 | sasl_callback_t *callbacks; 30 | } ngx_http_auth_sasl_loc_conf_t; 31 | 32 | typedef struct { 33 | ngx_int_t secure; 34 | ngx_int_t mech; 35 | ngx_int_t user; 36 | } ngx_http_auth_sasl_var_index_t; 37 | 38 | static ngx_http_auth_sasl_var_index_t ngx_http_sasl_var_index; 39 | 40 | //static ngx_str_t shm_name = ngx_string("sasl_contexts"); 41 | 42 | #define NGX_SASL_SEC_BUF_SIZE (2048) 43 | #define NGX_SASL_HTTP_SERVICE_NAME "HTTP" 44 | 45 | static ngx_str_t ngx_http_auth_sasl_secure_var = ngx_string("sasl_secure"); 46 | static ngx_str_t ngx_http_auth_sasl_mech_var = ngx_string("sasl_mech"); 47 | static ngx_str_t ngx_http_auth_sasl_realm_var = ngx_string("sasl_realm"); 48 | static ngx_str_t ngx_http_auth_sasl_user_var = ngx_string("sasl_user"); 49 | static ngx_str_t ngx_http_auth_sasl_yes = ngx_string("yes"); 50 | 51 | /* 52 | * The public interface of this module. 53 | */ 54 | ngx_module_t ngx_http_auth_sasl_module; 55 | 56 | static int http_auth_sasl_getopt(void *context, const char *plugin_name, 57 | const char *option, 58 | const char **result, unsigned *len) { 59 | ngx_http_auth_sasl_loc_conf_t *dconf = (ngx_http_auth_sasl_loc_conf_t *) context; 60 | if (dconf) { 61 | if (!strcmp(option, "sasldb_path")) { 62 | if (dconf->db_path.data) { 63 | *result = (char*) dconf->db_path.data; 64 | if (len) { 65 | *len = (unsigned) dconf->db_path.len; 66 | } 67 | } 68 | } else if (!strcmp(option, "mech_list")) { 69 | if (dconf->mechs.data) { 70 | *result = (char*) dconf->mechs.data; 71 | if (len) { 72 | *len = (unsigned) dconf->mechs.len; 73 | } 74 | } 75 | } 76 | return SASL_OK; 77 | } 78 | return SASL_FAIL; 79 | } 80 | 81 | static const sasl_callback_t callbacks[] = { 82 | { 83 | SASL_CB_GETOPT, (sasl_callback_ft) http_auth_sasl_getopt, NULL 84 | }, { 85 | SASL_CB_LIST_END, NULL, NULL 86 | } 87 | }; 88 | 89 | /* ======================================================================================== 90 | * Access Handler 91 | * ======================================================================================== */ 92 | 93 | /* 94 | * Sends a WWW-Authenticate header with realm name 95 | * and returns HTTP 401 Authorization Required status. 96 | */ 97 | static ngx_int_t 98 | ngx_http_auth_sasl_unauthorized(ngx_http_request_t *r, const ngx_http_auth_sasl_loc_conf_t *lcf) 99 | { 100 | u_char *processed; 101 | u_char *p; 102 | size_t len; 103 | static const char PREFIX[] = "SASL realm=\""; 104 | static const char MECH[] = "\",mech=\""; 105 | static const u_char HEADER_NAME[] = "WWW-Authenticate"; 106 | static const size_t HEADER_NAME_LEN = sizeof(HEADER_NAME) - 1; 107 | static const size_t PREFIX_LEN = sizeof(PREFIX) - 1; 108 | static const size_t MECH_LEN = sizeof(MECH) - 1; 109 | 110 | r->headers_out.www_authenticate = ngx_list_push(&r->headers_out.headers); 111 | if (r->headers_out.www_authenticate == NULL) { 112 | return NGX_HTTP_INTERNAL_SERVER_ERROR; 113 | } 114 | 115 | r->headers_out.www_authenticate->hash = 1; 116 | r->headers_out.www_authenticate->key.len = (size_t) HEADER_NAME_LEN; 117 | r->headers_out.www_authenticate->key.data = (u_char*) HEADER_NAME; 118 | 119 | /* WWW-Authenticate: SASL s2s="",realm="SASL http auth test",mech="OPAQUE" */ 120 | 121 | len = PREFIX_LEN + lcf->realm.len + MECH_LEN + lcf->mechs.len + 1; 122 | 123 | processed = ngx_palloc(r->pool, len); 124 | if (processed == NULL) { 125 | return NGX_ERROR; 126 | } 127 | 128 | p = ngx_cpymem(processed, PREFIX, PREFIX_LEN); 129 | p = ngx_cpymem(p, lcf->realm.data, lcf->realm.len); 130 | p = ngx_cpymem(p, MECH, MECH_LEN); 131 | p = ngx_cpymem(p, lcf->mechs.data, lcf->mechs.len); 132 | *p = '"'; 133 | 134 | r->headers_out.www_authenticate->value.data = processed; 135 | r->headers_out.www_authenticate->value.len = len; 136 | 137 | return NGX_HTTP_UNAUTHORIZED; 138 | } 139 | 140 | static ngx_int_t ngx_http_auth_sasl_set_var(ngx_http_request_t *r, 141 | const ngx_uint_t index, 142 | ngx_str_t *val) { 143 | ngx_log_error(NGX_LOG_DEBUG, r->connection->log, 0, 144 | "setting variable idx(%d): %s", index, val->data); 145 | ngx_http_variable_value_t *v; 146 | // copying behavior from 147 | // https://github.com/nginx-shib/nginx-http-shibboleth/blob/fffdfb8f7c298dc97f4a1b04fb96f4b87ddd6105/ngx_http_shibboleth_module.c#L468= 148 | v = &r->variables[index]; 149 | if(NULL == v) { 150 | return NGX_ERROR; 151 | } 152 | 153 | v->valid = 1; 154 | v->not_found = 0; 155 | v->no_cacheable = 1; 156 | v->len = val->len; 157 | v->data = val->data; 158 | 159 | return NGX_OK; 160 | } 161 | 162 | static ngx_int_t 163 | ngx_http_auth_sasl_handler(ngx_http_request_t *r) { 164 | 165 | sasl_conn_t *conn = NULL; 166 | ngx_http_auth_sasl_loc_conf_t *lcf; 167 | 168 | ngx_log_error(NGX_LOG_DEBUG, r->connection->log, 0, "SASL HANDLER"); 169 | 170 | lcf = ngx_http_get_module_loc_conf(r, ngx_http_auth_sasl_module); 171 | 172 | if (lcf->realm.len == 0) { 173 | /* SASL authentication is not enabled at this location. */ 174 | return NGX_OK; 175 | } 176 | 177 | ngx_log_error(NGX_LOG_DEBUG, r->connection->log, 0, 178 | "SASL HANDLER REALM: %s", lcf->realm.data); 179 | 180 | if(r->headers_in.authorization) { 181 | int result; 182 | int result2; 183 | char buf[NGX_SASL_SEC_BUF_SIZE]; 184 | long id=0; 185 | unsigned clientinlen = 0; 186 | unsigned serveroutlen = 0; 187 | unsigned len; 188 | const char *clientin = NULL; 189 | const char *serverout; 190 | sasl_header_fields_t parsed={0}; 191 | 192 | ngx_log_error(NGX_LOG_DEBUG, r->connection->log, 0, 193 | "Authorize Header: %s", r->headers_in.authorization->value.data); 194 | 195 | // parse auth line 196 | parse_header(&parsed, 197 | r->headers_in.authorization->value.data, 198 | r->headers_in.authorization->value.len); 199 | 200 | if(parsed.c2s) { 201 | if (SASL_OK == sasl_decode64(parsed.c2s, parsed.c2s_len, 202 | buf, NGX_SASL_SEC_BUF_SIZE, &clientinlen)) { 203 | ngx_log_error(NGX_LOG_DEBUG, r->connection->log, 0, "decoded c2s"); 204 | clientin = buf; 205 | } 206 | } 207 | 208 | if(parsed.mech) { 209 | result = sasl_server_new(NGX_SASL_HTTP_SERVICE_NAME, 210 | NULL, /* my fully qualified domain name; 211 | NULL says use gethostname() */ 212 | (char*)lcf->realm.data, /* The user realm used for password 213 | lookups; NULL means default to serverFQDN 214 | Note: This does not affect Kerberos */ 215 | NULL, NULL, /* IP Address information strings */ 216 | lcf->callbacks, /* Callbacks supported only for this connection */ 217 | SASL_SUCCESS_DATA, /* security flags (security layers are enabled 218 | using security properties, separately) */ 219 | &conn); 220 | ngx_log_error(NGX_LOG_DEBUG, r->connection->log, 0, 221 | "new sasl_server: %d", result); 222 | if(SASL_OK == result) { 223 | do { 224 | id = ngx_random(); 225 | if(id==0) continue; // never allow 0 id 226 | (void) sc_map_get_64v(lcf->conns, id); 227 | } while(sc_map_found(lcf->conns)); 228 | sc_map_put_64v(lcf->conns, id, conn); 229 | char mech[parsed.mech_len+1]; 230 | ngx_memcpy(mech,parsed.mech,parsed.mech_len); 231 | mech[parsed.mech_len]=0; 232 | result = sasl_server_start(conn, mech, 233 | clientin, clientinlen, 234 | &serverout, &serveroutlen); 235 | ngx_log_error(NGX_LOG_DEBUG, r->connection->log, 0, 236 | "starting sasl_server: %d", result); 237 | } 238 | } else { 239 | ngx_log_error(NGX_LOG_DEBUG, r->connection->log, 0, "loading sasl_server"); 240 | conn = sc_map_get_64v(lcf->conns, parsed.s2s); 241 | if (!sc_map_found(lcf->conns)) { 242 | if(r->headers_out.www_authenticate) { 243 | const unsigned int vallen = strlen("SASL s2c=\"\",s2s=\"\"") + 16; 244 | unsigned char val[vallen], *p; 245 | 246 | p = ngx_snprintf(val, vallen, "SASL s2c=\"\",s2s=\"%p\"", parsed.s2s); 247 | if(vallen != (p - val)) { 248 | return NGX_HTTP_INTERNAL_SERVER_ERROR; 249 | } 250 | if(ngx_memcmp(val, r->headers_out.www_authenticate->value.data, vallen)==0) { 251 | return NGX_OK; 252 | } 253 | } 254 | ngx_log_error(NGX_LOG_DEBUG, r->connection->log, 0, 255 | "sasl context not found, restarting auth dance"); 256 | return NGX_HTTP_UNAUTHORIZED; 257 | } 258 | result = sasl_server_step(conn, clientin, clientinlen, &serverout, &serveroutlen); 259 | ngx_log_error(NGX_LOG_DEBUG, r->connection->log, 0, 260 | "stepping sasl_server: %d", result); 261 | id = parsed.s2s; 262 | } 263 | 264 | if (result != SASL_OK && result != SASL_CONTINUE) { 265 | ngx_log_error(NGX_LOG_DEBUG, r->connection->log, 0, 266 | "ERROR starting SASL negotiation: %s", 267 | sasl_errstring(result, NULL, NULL)); 268 | return NGX_HTTP_UNAUTHORIZED; 269 | } 270 | 271 | result2 = sasl_encode64(serverout, serveroutlen, buf, NGX_SASL_SEC_BUF_SIZE, &len); 272 | if (result2 == SASL_OK) { 273 | unsigned char *val, *p; 274 | const unsigned int vallen = strlen("SASL s2c=\"\",s2s=\"\"") + len + 16; 275 | static const u_char HEADER_NAME[] = "WWW-Authenticate"; 276 | static const size_t HEADER_NAME_LEN = sizeof(HEADER_NAME) - 1; 277 | 278 | // todo? apachemod does: 279 | //r->err_headers_out, 280 | // (PROXYREQ_PROXY == r->proxyreq) ? "Proxy-Authenticate" : "WWW-Authenticate", 281 | // apr_psprintf(r->pool, "SASL s2c=\"%s\",s2s=\"%s\"", buf, s2s) 282 | 283 | val = ngx_palloc(r->pool, vallen); 284 | if (NULL == val) { 285 | return NGX_ERROR; 286 | } 287 | p = ngx_snprintf(val, vallen, "SASL s2c=\"%s\",s2s=\"%p\"", buf, id); 288 | if(vallen != (p - val)) { 289 | return NGX_HTTP_INTERNAL_SERVER_ERROR; 290 | } 291 | 292 | r->headers_out.www_authenticate = ngx_list_push(&r->headers_out.headers); 293 | if (r->headers_out.www_authenticate == NULL) { 294 | return NGX_HTTP_INTERNAL_SERVER_ERROR; 295 | } 296 | r->headers_out.www_authenticate->hash = 1; 297 | r->headers_out.www_authenticate->key.len = (size_t) HEADER_NAME_LEN; 298 | r->headers_out.www_authenticate->key.data = (u_char*) HEADER_NAME; 299 | r->headers_out.www_authenticate->value.data = val; 300 | r->headers_out.www_authenticate->value.len = vallen; 301 | ngx_log_error(NGX_LOG_DEBUG, r->connection->log, 0, "sasl header set"); 302 | 303 | if (result == SASL_OK) { 304 | /* successfully authenticated */ 305 | ngx_log_error(NGX_LOG_DEBUG, r->connection->log, 0, "sasl_ok"); 306 | 307 | /* set variable: sasl_user */ 308 | ngx_str_t user; 309 | char *user_p; 310 | if (sasl_getprop(conn, SASL_USERNAME, (const void**) &user_p) != SASL_OK) { 311 | ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "failed to query SASL_USERNAME"); 312 | return NGX_HTTP_INTERNAL_SERVER_ERROR; 313 | } 314 | user.len = ngx_strlen(user_p); 315 | user.data = ngx_palloc(r->pool, user.len); 316 | if (user.data == NULL) { 317 | return NGX_ERROR; 318 | } 319 | ngx_memcpy(user.data, user_p, user.len); 320 | if(NGX_OK!=ngx_http_auth_sasl_set_var(r,ngx_http_sasl_var_index.user, &user)) { 321 | ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "failed to set variable: user"); 322 | return NGX_HTTP_INTERNAL_SERVER_ERROR; 323 | }; 324 | 325 | /* set variable: sasl_secure */ 326 | if(NGX_OK!=ngx_http_auth_sasl_set_var(r,ngx_http_sasl_var_index.secure, 327 | &ngx_http_auth_sasl_yes)) { 328 | ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "failed to set variable: secure"); 329 | return NGX_HTTP_INTERNAL_SERVER_ERROR; 330 | }; 331 | 332 | /* set variable: sasl_mech */ 333 | ngx_str_t mech; 334 | char *mech_p; 335 | if (sasl_getprop(conn, SASL_MECHNAME, (const void**) &mech_p) != SASL_OK) { 336 | ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, 337 | "failed to query SASL_MECHNAME"); 338 | return NGX_HTTP_INTERNAL_SERVER_ERROR; 339 | } 340 | mech.len = ngx_strlen(mech_p); 341 | mech.data = ngx_palloc(r->pool, mech.len); 342 | if (mech.data == NULL) { 343 | return NGX_ERROR; 344 | } 345 | ngx_memcpy(mech.data, mech_p, mech.len); 346 | if(NGX_OK!=ngx_http_auth_sasl_set_var(r,ngx_http_sasl_var_index.mech, &mech)) { 347 | ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "failed to set variable: mech"); 348 | return NGX_HTTP_INTERNAL_SERVER_ERROR; 349 | }; 350 | 351 | /* remove cyrus sasl connection for hash table ... */ 352 | (void) sc_map_del_64v(lcf->conns, id); 353 | if (!sc_map_found(lcf->conns)) { 354 | return NGX_HTTP_INTERNAL_SERVER_ERROR; 355 | } 356 | ///* ... and dispose it */ 357 | sasl_dispose(&conn); 358 | return NGX_OK; 359 | } 360 | } 361 | //sc_map_term_64v(&map); 362 | 363 | //if(NGX_OK != rc) { 364 | // return NGX_ERROR; 365 | //} 366 | ngx_log_error(NGX_LOG_DEBUG, r->connection->log, 0, "sasl returning 401"); 367 | return NGX_HTTP_UNAUTHORIZED; 368 | } 369 | 370 | // no authorize header 371 | return ngx_http_auth_sasl_unauthorized(r, lcf); 372 | } 373 | 374 | /* Variables */ 375 | static ngx_int_t ngx_http_auth_sasl_get_realm_var (ngx_http_request_t *r, 376 | ngx_http_variable_value_t *v, 377 | uintptr_t data) { 378 | u_char *p; 379 | ngx_http_auth_sasl_loc_conf_t *lcf; 380 | lcf = ngx_http_get_module_loc_conf(r, ngx_http_auth_sasl_module); 381 | 382 | p = ngx_pnalloc(r->pool, lcf->sasl_realm.len); 383 | if (p == NULL) { 384 | return NGX_ERROR; 385 | } 386 | 387 | v->len = lcf->sasl_realm.len; 388 | v->valid = 1; 389 | v->no_cacheable = 1; 390 | v->not_found = 0; 391 | v->data = lcf->sasl_realm.data; 392 | 393 | return NGX_OK; 394 | } 395 | 396 | static ngx_int_t ngx_http_auth_sasl_variable(ngx_http_request_t *r, 397 | ngx_http_variable_value_t *v, uintptr_t data) { 398 | ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, 399 | "get http auth sasl variable"); 400 | //v->not_found = 0; 401 | return NGX_OK; 402 | } 403 | 404 | 405 | /* 406 | static ngx_int_t 407 | ngx_http_aut_sasl_shm_init(ngx_shm_zone_t *shm_zone, void *data) 408 | { 409 | ngx_slab_pool_t *shpool; 410 | 411 | if (data) { 412 | shm_zone->data = data; 413 | return NGX_OK; 414 | } 415 | 416 | shpool = (ngx_slab_pool_t *) shm_zone->shm.addr; 417 | 418 | nconn = ngx_slab_alloc(shpool, 4); 419 | if (nconn == NULL) { 420 | return NGX_ERROR; 421 | } 422 | 423 | *nconn = 0; 424 | 425 | shm_zone->data = nconn; 426 | 427 | return NGX_OK; 428 | } 429 | */ 430 | 431 | 432 | /* ======================================================================================== 433 | * Configuration 434 | * ======================================================================================== */ 435 | 436 | static ngx_int_t ngx_http_auth_sasl_add_var(ngx_conf_t * cf, ngx_str_t *key, ngx_int_t *idx) { 437 | ngx_http_variable_t *v; 438 | ngx_int_t n; 439 | v = ngx_http_add_variable(cf, key, 0); 440 | if (v == NULL) { 441 | ngx_conf_log_error(NGX_LOG_ERR, cf, 0, "failed to add variable %s", key->data); 442 | return NGX_ERROR; 443 | } 444 | v->get_handler=ngx_http_auth_sasl_variable; 445 | n = ngx_http_get_variable_index(cf, key); 446 | if (n == NGX_ERROR) { 447 | ngx_conf_log_error(NGX_LOG_ERR, cf, 0, "failed to get variable index %s", key->data); 448 | return NGX_ERROR; 449 | } 450 | *idx = n; 451 | //ngx_conf_log_error(NGX_LOG_DEBUG, cf, 0, "%s idx=%d", key->data, n); 452 | 453 | return NGX_OK; 454 | } 455 | 456 | static ngx_int_t ngx_http_auth_sasl_preconf(ngx_conf_t * cf) { 457 | ngx_http_variable_t *v; 458 | ngx_conf_log_error(NGX_LOG_DEBUG, cf, 0, "sasl_preconf()"); 459 | 460 | v = ngx_http_add_variable(cf, &ngx_http_auth_sasl_realm_var, 0); 461 | if (v == NULL) { 462 | ngx_conf_log_error(NGX_LOG_ERR, cf, 0, "failed to add variable sasl_realm"); 463 | return NGX_ERROR; 464 | } 465 | v->get_handler=ngx_http_auth_sasl_get_realm_var; 466 | 467 | if(NGX_ERROR==ngx_http_auth_sasl_add_var(cf,&ngx_http_auth_sasl_secure_var, 468 | &ngx_http_sasl_var_index.secure)) { 469 | return NGX_ERROR; 470 | } 471 | 472 | if(NGX_ERROR==ngx_http_auth_sasl_add_var(cf,&ngx_http_auth_sasl_mech_var, 473 | &ngx_http_sasl_var_index.mech)) { 474 | return NGX_ERROR; 475 | } 476 | 477 | if(NGX_ERROR==ngx_http_auth_sasl_add_var(cf,&ngx_http_auth_sasl_user_var, 478 | &ngx_http_sasl_var_index.user)) { 479 | return NGX_ERROR; 480 | } 481 | 482 | return NGX_OK; 483 | } 484 | 485 | /* 486 | * Registers our request access phase handler. 487 | */ 488 | static ngx_int_t 489 | ngx_http_auth_sasl_init(ngx_conf_t *cf) 490 | { 491 | int result; 492 | ngx_http_handler_pt *h; 493 | ngx_http_core_main_conf_t *cmcf; 494 | 495 | cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module); 496 | 497 | h = ngx_array_push(&cmcf->phases[NGX_HTTP_ACCESS_PHASE].handlers); 498 | if (h == NULL) { 499 | return NGX_ERROR; 500 | } 501 | 502 | *h = ngx_http_auth_sasl_handler; 503 | 504 | // initialize sasl_server 505 | result = sasl_server_init(NULL, NULL); 506 | if (result != SASL_OK) { 507 | return NGX_ERROR; 508 | } 509 | ngx_conf_log_error(NGX_LOG_DEBUG, cf, 0, "sasl_server_init succeeded"); 510 | 511 | #ifdef DEBUG_SASL 512 | const char **mechlist = sasl_global_listmech(); 513 | char *mech; 514 | while ((mech = (char*) *mechlist++) != NULL) { 515 | ngx_conf_log_error(NGX_LOG_DEBUG, cf, 0, "mech: %s", mech); 516 | } 517 | #endif 518 | // todo 519 | //lmcf->shm_zone = ngx_shared_memory_add(cf, &shm_name, ngx_pagesize * 2, 520 | // &ngx_http_auth_sasl_module); 521 | //if (lmcf->shm_zone == NULL) { 522 | // return NGX_ERROR; 523 | //} 524 | 525 | //lmcf->shm_zone->init = ngx_rtmp_limit_shm_init; 526 | 527 | return NGX_OK; 528 | } 529 | 530 | /* 531 | * Creates an instance of per-location configuration. 532 | */ 533 | static void * 534 | ngx_http_auth_sasl_create_loc_conf(ngx_conf_t *cf) 535 | { 536 | sasl_callback_t *sasl_callbacks; 537 | ngx_http_auth_sasl_loc_conf_t *conf; 538 | 539 | conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_auth_sasl_loc_conf_t)); 540 | if (conf == NULL) { 541 | return NGX_CONF_ERROR; 542 | } 543 | 544 | conf->conns = ngx_pcalloc(cf->pool, sizeof(struct sc_map_64v)); 545 | sc_map_init_64v(conf->conns, 0, 0); 546 | 547 | sasl_callbacks = ngx_pcalloc(cf->pool, sizeof(callbacks)); 548 | if (sasl_callbacks == NULL) { 549 | return NGX_CONF_ERROR; 550 | } 551 | ngx_memcpy(sasl_callbacks, callbacks, sizeof(callbacks)); 552 | sasl_callbacks[0].context = conf; 553 | 554 | conf->callbacks = sasl_callbacks; 555 | 556 | return conf; 557 | } 558 | 559 | /* 560 | * Overrides inherited configuration. 561 | */ 562 | static char * 563 | ngx_http_auth_sasl_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) 564 | { 565 | ngx_http_auth_sasl_loc_conf_t *prev = parent; 566 | ngx_http_auth_sasl_loc_conf_t *conf = child; 567 | 568 | if (conf->realm.data == NULL) { 569 | conf->realm = prev->realm; 570 | } 571 | 572 | if (conf->sasl_realm.data == NULL) { 573 | conf->sasl_realm = prev->sasl_realm; 574 | } 575 | 576 | if (conf->mechs.data == NULL) { 577 | conf->mechs = prev->mechs; 578 | } 579 | 580 | if (conf->db_path.data == NULL) { 581 | conf->db_path = prev->db_path; 582 | } 583 | 584 | return NGX_CONF_OK; 585 | } 586 | 587 | /* 588 | * If the realm name equals "off", the value is discarded, and 589 | * SASL authentication is disabled at this location. 590 | */ 591 | static char * 592 | ngx_http_auth_sasl_post_handler(ngx_conf_t *cf, void *post, void *data) 593 | { 594 | ngx_str_t *realm = data; 595 | 596 | if (ngx_strcmp(realm->data, "off") == 0) { 597 | realm->len = 0; 598 | realm->data = (u_char *) ""; 599 | } 600 | 601 | return NGX_CONF_OK; 602 | } 603 | 604 | 605 | static ngx_conf_post_t ngx_http_auth_sasl_post = { 606 | ngx_http_auth_sasl_post_handler /* post_handler */ 607 | }; 608 | 609 | static ngx_command_t ngx_http_auth_sasl_commands[] = { 610 | 611 | /* auth_sasl off | ; */ 612 | { 613 | ngx_string("auth_sasl"), /* name */ 614 | NGX_HTTP_MAIN_CONF | /* allow in main config */ 615 | NGX_HTTP_SRV_CONF | /* allow in server block */ 616 | NGX_HTTP_LOC_CONF | /* allow in location block */ 617 | NGX_HTTP_LMT_CONF | /* allow in limit_except block */ 618 | NGX_CONF_TAKE1, /* take one argument */ 619 | ngx_conf_set_str_slot, /* set string value */ 620 | NGX_HTTP_LOC_CONF_OFFSET, /* configuration to set */ 621 | offsetof(ngx_http_auth_sasl_loc_conf_t, realm), /* field to set */ 622 | &ngx_http_auth_sasl_post /* config post processing */ 623 | }, 624 | { 625 | ngx_string("sasl_realm"), 626 | NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LMT_CONF|NGX_CONF_TAKE1, 627 | ngx_conf_set_str_slot, 628 | NGX_HTTP_LOC_CONF_OFFSET, 629 | offsetof(ngx_http_auth_sasl_loc_conf_t, sasl_realm), 630 | NULL 631 | }, 632 | { 633 | ngx_string("sasl_mechanisms"), 634 | NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LMT_CONF|NGX_CONF_TAKE1, 635 | ngx_conf_set_str_slot, 636 | NGX_HTTP_LOC_CONF_OFFSET, 637 | offsetof(ngx_http_auth_sasl_loc_conf_t, mechs), 638 | NULL 639 | }, 640 | { 641 | ngx_string("sasl_db_path"), 642 | NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LMT_CONF|NGX_CONF_TAKE1, 643 | ngx_conf_set_str_slot, 644 | NGX_HTTP_LOC_CONF_OFFSET, 645 | offsetof(ngx_http_auth_sasl_loc_conf_t, db_path), 646 | NULL 647 | }, 648 | ngx_null_command 649 | }; 650 | 651 | 652 | /* ======================================================================================== 653 | * Module Interface 654 | * ======================================================================================== */ 655 | 656 | static ngx_http_module_t ngx_http_auth_sasl_module_ctx = { 657 | ngx_http_auth_sasl_preconf, /* preconfiguration */ 658 | ngx_http_auth_sasl_init, /* postconfiguration */ 659 | 660 | NULL, /* create main configuration */ 661 | NULL, /* init main configuration */ 662 | 663 | NULL, /* create server configuration */ 664 | NULL, /* merge server configuration */ 665 | 666 | ngx_http_auth_sasl_create_loc_conf, /* create location configuration */ 667 | ngx_http_auth_sasl_merge_loc_conf /* merge location configuration */ 668 | }; 669 | 670 | ngx_module_t ngx_http_auth_sasl_module = { 671 | NGX_MODULE_V1, 672 | &ngx_http_auth_sasl_module_ctx, /* module context */ 673 | ngx_http_auth_sasl_commands, /* module directives */ 674 | NGX_HTTP_MODULE, /* module type */ 675 | NULL, /* init master */ 676 | NULL, /* init module */ 677 | NULL, /* init process */ 678 | NULL, /* init thread */ 679 | NULL, /* exit thread */ 680 | NULL, /* exit process */ 681 | NULL, /* exit master */ 682 | NGX_MODULE_V1_PADDING 683 | }; 684 | -------------------------------------------------------------------------------- /src/http_auth_header_parser.c: -------------------------------------------------------------------------------- 1 | /* A packrat parser generated by PackCC 1.8.0 */ 2 | 3 | #ifdef _MSC_VER 4 | #undef _CRT_SECURE_NO_WARNINGS 5 | #define _CRT_SECURE_NO_WARNINGS 6 | #endif /* _MSC_VER */ 7 | #include 8 | #include 9 | #include 10 | 11 | #ifndef _MSC_VER 12 | #if defined __GNUC__ && defined _WIN32 /* MinGW */ 13 | #ifndef PCC_USE_SYSTEM_STRNLEN 14 | #define strnlen(str, maxlen) pcc_strnlen(str, maxlen) 15 | static size_t pcc_strnlen(const char *str, size_t maxlen) { 16 | size_t i; 17 | for (i = 0; i < maxlen && str[i]; i++); 18 | return i; 19 | } 20 | #endif /* !PCC_USE_SYSTEM_STRNLEN */ 21 | #endif /* defined __GNUC__ && defined _WIN32 */ 22 | #endif /* !_MSC_VER */ 23 | 24 | #include "http_auth_header_parser.h" 25 | 26 | #line 14 "http_auth_header_parser.peg" 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | #define PCC_GETCHAR(auxil) next_chr(auxil) 33 | 34 | static int next_chr(sasl_header_fields_t *auxil) { 35 | if(auxil->input_ptr < auxil->input_len) { 36 | return auxil->input[auxil->input_ptr++]; 37 | } 38 | return EOF; 39 | } 40 | #line 40 "http_auth_header_parser.c" 41 | #if !defined __has_attribute || defined _MSC_VER 42 | #define __attribute__(x) 43 | #endif 44 | 45 | #ifdef _MSC_VER 46 | #define MARK_FUNC_AS_USED __pragma(warning(suppress:4505)) 47 | #else 48 | #define MARK_FUNC_AS_USED __attribute__((__unused__)) 49 | #endif 50 | 51 | #ifndef PCC_BUFFER_MIN_SIZE 52 | #define PCC_BUFFER_MIN_SIZE 256 53 | #endif /* !PCC_BUFFER_MIN_SIZE */ 54 | 55 | #ifndef PCC_ARRAY_MIN_SIZE 56 | #define PCC_ARRAY_MIN_SIZE 2 57 | #endif /* !PCC_ARRAY_MIN_SIZE */ 58 | 59 | #ifndef PCC_POOL_MIN_SIZE 60 | #define PCC_POOL_MIN_SIZE 65536 61 | #endif /* !PCC_POOL_MIN_SIZE */ 62 | 63 | #define PCC_DBG_EVALUATE 0 64 | #define PCC_DBG_MATCH 1 65 | #define PCC_DBG_NOMATCH 2 66 | 67 | #define PCC_VOID_VALUE (~(size_t)0) 68 | 69 | typedef enum pcc_bool_tag { 70 | PCC_FALSE = 0, 71 | PCC_TRUE 72 | } pcc_bool_t; 73 | 74 | typedef struct pcc_char_array_tag { 75 | char *buf; 76 | size_t max; 77 | size_t len; 78 | } pcc_char_array_t; 79 | 80 | typedef struct pcc_range_tag { 81 | size_t start; 82 | size_t end; 83 | } pcc_range_t; 84 | 85 | typedef int pcc_value_t; 86 | 87 | typedef sasl_header_fields_t*pcc_auxil_t; 88 | 89 | typedef sasl_header_context_t pcc_context_t; 90 | 91 | typedef struct pcc_value_table_tag { 92 | pcc_value_t *buf; 93 | size_t max; 94 | size_t len; 95 | } pcc_value_table_t; 96 | 97 | typedef struct pcc_value_refer_table_tag { 98 | pcc_value_t **buf; 99 | size_t max; 100 | size_t len; 101 | } pcc_value_refer_table_t; 102 | 103 | typedef struct pcc_capture_tag { 104 | pcc_range_t range; 105 | char *string; /* mutable */ 106 | } pcc_capture_t; 107 | 108 | typedef struct pcc_capture_table_tag { 109 | pcc_capture_t *buf; 110 | size_t max; 111 | size_t len; 112 | } pcc_capture_table_t; 113 | 114 | typedef struct pcc_capture_const_table_tag { 115 | const pcc_capture_t **buf; 116 | size_t max; 117 | size_t len; 118 | } pcc_capture_const_table_t; 119 | 120 | typedef struct pcc_thunk_tag pcc_thunk_t; 121 | typedef struct pcc_thunk_array_tag pcc_thunk_array_t; 122 | 123 | typedef void (*pcc_action_t)(pcc_context_t *, pcc_thunk_t *, pcc_value_t *); 124 | 125 | typedef enum pcc_thunk_type_tag { 126 | PCC_THUNK_LEAF, 127 | PCC_THUNK_NODE 128 | } pcc_thunk_type_t; 129 | 130 | typedef struct pcc_thunk_leaf_tag { 131 | pcc_value_refer_table_t values; 132 | pcc_capture_const_table_t capts; 133 | pcc_capture_t capt0; 134 | pcc_action_t action; 135 | } pcc_thunk_leaf_t; 136 | 137 | typedef struct pcc_thunk_node_tag { 138 | const pcc_thunk_array_t *thunks; /* just a reference */ 139 | pcc_value_t *value; /* just a reference */ 140 | } pcc_thunk_node_t; 141 | 142 | typedef union pcc_thunk_data_tag { 143 | pcc_thunk_leaf_t leaf; 144 | pcc_thunk_node_t node; 145 | } pcc_thunk_data_t; 146 | 147 | struct pcc_thunk_tag { 148 | pcc_thunk_type_t type; 149 | pcc_thunk_data_t data; 150 | }; 151 | 152 | struct pcc_thunk_array_tag { 153 | pcc_thunk_t **buf; 154 | size_t max; 155 | size_t len; 156 | }; 157 | 158 | typedef struct pcc_thunk_chunk_tag { 159 | pcc_value_table_t values; 160 | pcc_capture_table_t capts; 161 | pcc_thunk_array_t thunks; 162 | size_t pos; /* the starting position in the character buffer */ 163 | } pcc_thunk_chunk_t; 164 | 165 | typedef struct pcc_lr_entry_tag pcc_lr_entry_t; 166 | 167 | typedef enum pcc_lr_answer_type_tag { 168 | PCC_LR_ANSWER_LR, 169 | PCC_LR_ANSWER_CHUNK 170 | } pcc_lr_answer_type_t; 171 | 172 | typedef union pcc_lr_answer_data_tag { 173 | pcc_lr_entry_t *lr; 174 | pcc_thunk_chunk_t *chunk; 175 | } pcc_lr_answer_data_t; 176 | 177 | typedef struct pcc_lr_answer_tag pcc_lr_answer_t; 178 | 179 | struct pcc_lr_answer_tag { 180 | pcc_lr_answer_type_t type; 181 | pcc_lr_answer_data_t data; 182 | size_t pos; /* the absolute position in the input */ 183 | pcc_lr_answer_t *hold; 184 | }; 185 | 186 | typedef pcc_thunk_chunk_t *(*pcc_rule_t)(pcc_context_t *); 187 | 188 | typedef struct pcc_rule_set_tag { 189 | pcc_rule_t *buf; 190 | size_t max; 191 | size_t len; 192 | } pcc_rule_set_t; 193 | 194 | typedef struct pcc_lr_head_tag pcc_lr_head_t; 195 | 196 | struct pcc_lr_head_tag { 197 | pcc_rule_t rule; 198 | pcc_rule_set_t invol; 199 | pcc_rule_set_t eval; 200 | pcc_lr_head_t *hold; 201 | }; 202 | 203 | typedef struct pcc_lr_memo_tag { 204 | pcc_rule_t rule; 205 | pcc_lr_answer_t *answer; 206 | } pcc_lr_memo_t; 207 | 208 | typedef struct pcc_lr_memo_map_tag { 209 | pcc_lr_memo_t *buf; 210 | size_t max; 211 | size_t len; 212 | } pcc_lr_memo_map_t; 213 | 214 | typedef struct pcc_lr_table_entry_tag { 215 | pcc_lr_head_t *head; /* just a reference */ 216 | pcc_lr_memo_map_t memos; 217 | pcc_lr_answer_t *hold_a; 218 | pcc_lr_head_t *hold_h; 219 | } pcc_lr_table_entry_t; 220 | 221 | typedef struct pcc_lr_table_tag { 222 | pcc_lr_table_entry_t **buf; 223 | size_t max; 224 | size_t len; 225 | size_t ofs; 226 | } pcc_lr_table_t; 227 | 228 | struct pcc_lr_entry_tag { 229 | pcc_rule_t rule; 230 | pcc_thunk_chunk_t *seed; /* just a reference */ 231 | pcc_lr_head_t *head; /* just a reference */ 232 | }; 233 | 234 | typedef struct pcc_lr_stack_tag { 235 | pcc_lr_entry_t **buf; 236 | size_t max; 237 | size_t len; 238 | } pcc_lr_stack_t; 239 | 240 | typedef struct pcc_memory_entry_tag pcc_memory_entry_t; 241 | typedef struct pcc_memory_pool_tag pcc_memory_pool_t; 242 | 243 | struct pcc_memory_entry_tag { 244 | pcc_memory_entry_t *next; 245 | }; 246 | 247 | struct pcc_memory_pool_tag { 248 | pcc_memory_pool_t *next; 249 | size_t allocated; 250 | size_t unused; 251 | }; 252 | 253 | typedef struct pcc_memory_recycler_tag { 254 | pcc_memory_pool_t *pool_list; 255 | pcc_memory_entry_t *entry_list; 256 | size_t element_size; 257 | } pcc_memory_recycler_t; 258 | 259 | struct sasl_header_context_tag { 260 | size_t pos; /* the position in the input of the first character currently buffered */ 261 | size_t cur; /* the current parsing position in the character buffer */ 262 | size_t level; 263 | pcc_char_array_t buffer; 264 | pcc_lr_table_t lrtable; 265 | pcc_lr_stack_t lrstack; 266 | pcc_thunk_array_t thunks; 267 | pcc_auxil_t auxil; 268 | pcc_memory_recycler_t thunk_chunk_recycler; 269 | pcc_memory_recycler_t lr_head_recycler; 270 | pcc_memory_recycler_t lr_answer_recycler; 271 | }; 272 | 273 | #ifndef PCC_ERROR 274 | #define PCC_ERROR(auxil) pcc_error() 275 | MARK_FUNC_AS_USED 276 | static void pcc_error(void) { 277 | fprintf(stderr, "Syntax error\n"); 278 | exit(1); 279 | } 280 | #endif /* !PCC_ERROR */ 281 | 282 | #ifndef PCC_GETCHAR 283 | #define PCC_GETCHAR(auxil) getchar() 284 | #endif /* !PCC_GETCHAR */ 285 | 286 | #ifndef PCC_MALLOC 287 | #define PCC_MALLOC(auxil, size) pcc_malloc_e(size) 288 | static void *pcc_malloc_e(size_t size) { 289 | void *const p = malloc(size); 290 | if (p == NULL) { 291 | fprintf(stderr, "Out of memory\n"); 292 | exit(1); 293 | } 294 | return p; 295 | } 296 | #endif /* !PCC_MALLOC */ 297 | 298 | #ifndef PCC_REALLOC 299 | #define PCC_REALLOC(auxil, ptr, size) pcc_realloc_e(ptr, size) 300 | static void *pcc_realloc_e(void *ptr, size_t size) { 301 | void *const p = realloc(ptr, size); 302 | if (p == NULL) { 303 | fprintf(stderr, "Out of memory\n"); 304 | exit(1); 305 | } 306 | return p; 307 | } 308 | #endif /* !PCC_REALLOC */ 309 | 310 | #ifndef PCC_FREE 311 | #define PCC_FREE(auxil, ptr) free(ptr) 312 | #endif /* !PCC_FREE */ 313 | 314 | #ifndef PCC_DEBUG 315 | #define PCC_DEBUG(auxil, event, rule, level, pos, buffer, length) ((void)0) 316 | #endif /* !PCC_DEBUG */ 317 | 318 | static char *pcc_strndup_e(pcc_auxil_t auxil, const char *str, size_t len) { 319 | const size_t m = strnlen(str, len); 320 | char *const s = (char *)PCC_MALLOC(auxil, m + 1); 321 | memcpy(s, str, m); 322 | s[m] = '\0'; 323 | return s; 324 | } 325 | 326 | static void pcc_char_array__init(pcc_auxil_t auxil, pcc_char_array_t *array) { 327 | array->len = 0; 328 | array->max = 0; 329 | array->buf = NULL; 330 | } 331 | 332 | static void pcc_char_array__add(pcc_auxil_t auxil, pcc_char_array_t *array, char ch) { 333 | if (array->max <= array->len) { 334 | const size_t n = array->len + 1; 335 | size_t m = array->max; 336 | if (m == 0) m = PCC_BUFFER_MIN_SIZE; 337 | while (m < n && m != 0) m <<= 1; 338 | if (m == 0) m = n; 339 | array->buf = (char *)PCC_REALLOC(auxil, array->buf, m); 340 | array->max = m; 341 | } 342 | array->buf[array->len++] = ch; 343 | } 344 | 345 | static void pcc_char_array__term(pcc_auxil_t auxil, pcc_char_array_t *array) { 346 | PCC_FREE(auxil, array->buf); 347 | } 348 | 349 | static void pcc_value_table__init(pcc_auxil_t auxil, pcc_value_table_t *table) { 350 | table->len = 0; 351 | table->max = 0; 352 | table->buf = NULL; 353 | } 354 | 355 | MARK_FUNC_AS_USED 356 | static void pcc_value_table__resize(pcc_auxil_t auxil, pcc_value_table_t *table, size_t len) { 357 | if (table->max < len) { 358 | size_t m = table->max; 359 | if (m == 0) m = PCC_ARRAY_MIN_SIZE; 360 | while (m < len && m != 0) m <<= 1; 361 | if (m == 0) m = len; 362 | table->buf = (pcc_value_t *)PCC_REALLOC(auxil, table->buf, sizeof(pcc_value_t) * m); 363 | table->max = m; 364 | } 365 | table->len = len; 366 | } 367 | 368 | MARK_FUNC_AS_USED 369 | static void pcc_value_table__clear(pcc_auxil_t auxil, pcc_value_table_t *table) { 370 | memset(table->buf, 0, sizeof(pcc_value_t) * table->len); 371 | } 372 | 373 | static void pcc_value_table__term(pcc_auxil_t auxil, pcc_value_table_t *table) { 374 | PCC_FREE(auxil, table->buf); 375 | } 376 | 377 | static void pcc_value_refer_table__init(pcc_auxil_t auxil, pcc_value_refer_table_t *table) { 378 | table->len = 0; 379 | table->max = 0; 380 | table->buf = NULL; 381 | } 382 | 383 | static void pcc_value_refer_table__resize(pcc_auxil_t auxil, pcc_value_refer_table_t *table, size_t len) { 384 | size_t i; 385 | if (table->max < len) { 386 | size_t m = table->max; 387 | if (m == 0) m = PCC_ARRAY_MIN_SIZE; 388 | while (m < len && m != 0) m <<= 1; 389 | if (m == 0) m = len; 390 | table->buf = (pcc_value_t **)PCC_REALLOC(auxil, table->buf, sizeof(pcc_value_t *) * m); 391 | table->max = m; 392 | } 393 | for (i = table->len; i < len; i++) table->buf[i] = NULL; 394 | table->len = len; 395 | } 396 | 397 | static void pcc_value_refer_table__term(pcc_auxil_t auxil, pcc_value_refer_table_t *table) { 398 | PCC_FREE(auxil, table->buf); 399 | } 400 | 401 | static void pcc_capture_table__init(pcc_auxil_t auxil, pcc_capture_table_t *table) { 402 | table->len = 0; 403 | table->max = 0; 404 | table->buf = NULL; 405 | } 406 | 407 | MARK_FUNC_AS_USED 408 | static void pcc_capture_table__resize(pcc_auxil_t auxil, pcc_capture_table_t *table, size_t len) { 409 | size_t i; 410 | for (i = len; i < table->len; i++) PCC_FREE(auxil, table->buf[i].string); 411 | if (table->max < len) { 412 | size_t m = table->max; 413 | if (m == 0) m = PCC_ARRAY_MIN_SIZE; 414 | while (m < len && m != 0) m <<= 1; 415 | if (m == 0) m = len; 416 | table->buf = (pcc_capture_t *)PCC_REALLOC(auxil, table->buf, sizeof(pcc_capture_t) * m); 417 | table->max = m; 418 | } 419 | for (i = table->len; i < len; i++) { 420 | table->buf[i].range.start = 0; 421 | table->buf[i].range.end = 0; 422 | table->buf[i].string = NULL; 423 | } 424 | table->len = len; 425 | } 426 | 427 | static void pcc_capture_table__term(pcc_auxil_t auxil, pcc_capture_table_t *table) { 428 | while (table->len > 0) { 429 | table->len--; 430 | PCC_FREE(auxil, table->buf[table->len].string); 431 | } 432 | PCC_FREE(auxil, table->buf); 433 | } 434 | 435 | static void pcc_capture_const_table__init(pcc_auxil_t auxil, pcc_capture_const_table_t *table) { 436 | table->len = 0; 437 | table->max = 0; 438 | table->buf = NULL; 439 | } 440 | 441 | static void pcc_capture_const_table__resize(pcc_auxil_t auxil, pcc_capture_const_table_t *table, size_t len) { 442 | size_t i; 443 | if (table->max < len) { 444 | size_t m = table->max; 445 | if (m == 0) m = PCC_ARRAY_MIN_SIZE; 446 | while (m < len && m != 0) m <<= 1; 447 | if (m == 0) m = len; 448 | table->buf = (const pcc_capture_t **)PCC_REALLOC(auxil, (pcc_capture_t **)table->buf, sizeof(const pcc_capture_t *) * m); 449 | table->max = m; 450 | } 451 | for (i = table->len; i < len; i++) table->buf[i] = NULL; 452 | table->len = len; 453 | } 454 | 455 | static void pcc_capture_const_table__term(pcc_auxil_t auxil, pcc_capture_const_table_t *table) { 456 | PCC_FREE(auxil, (void *)table->buf); 457 | } 458 | 459 | MARK_FUNC_AS_USED 460 | static pcc_thunk_t *pcc_thunk__create_leaf(pcc_auxil_t auxil, pcc_action_t action, size_t valuec, size_t captc) { 461 | pcc_thunk_t *const thunk = (pcc_thunk_t *)PCC_MALLOC(auxil, sizeof(pcc_thunk_t)); 462 | thunk->type = PCC_THUNK_LEAF; 463 | pcc_value_refer_table__init(auxil, &thunk->data.leaf.values); 464 | pcc_value_refer_table__resize(auxil, &thunk->data.leaf.values, valuec); 465 | pcc_capture_const_table__init(auxil, &thunk->data.leaf.capts); 466 | pcc_capture_const_table__resize(auxil, &thunk->data.leaf.capts, captc); 467 | thunk->data.leaf.capt0.range.start = 0; 468 | thunk->data.leaf.capt0.range.end = 0; 469 | thunk->data.leaf.capt0.string = NULL; 470 | thunk->data.leaf.action = action; 471 | return thunk; 472 | } 473 | 474 | static pcc_thunk_t *pcc_thunk__create_node(pcc_auxil_t auxil, const pcc_thunk_array_t *thunks, pcc_value_t *value) { 475 | pcc_thunk_t *const thunk = (pcc_thunk_t *)PCC_MALLOC(auxil, sizeof(pcc_thunk_t)); 476 | thunk->type = PCC_THUNK_NODE; 477 | thunk->data.node.thunks = thunks; 478 | thunk->data.node.value = value; 479 | return thunk; 480 | } 481 | 482 | static void pcc_thunk__destroy(pcc_auxil_t auxil, pcc_thunk_t *thunk) { 483 | if (thunk == NULL) return; 484 | switch (thunk->type) { 485 | case PCC_THUNK_LEAF: 486 | PCC_FREE(auxil, thunk->data.leaf.capt0.string); 487 | pcc_capture_const_table__term(auxil, &thunk->data.leaf.capts); 488 | pcc_value_refer_table__term(auxil, &thunk->data.leaf.values); 489 | break; 490 | case PCC_THUNK_NODE: 491 | break; 492 | default: /* unknown */ 493 | break; 494 | } 495 | PCC_FREE(auxil, thunk); 496 | } 497 | 498 | static void pcc_thunk_array__init(pcc_auxil_t auxil, pcc_thunk_array_t *array) { 499 | array->len = 0; 500 | array->max = 0; 501 | array->buf = NULL; 502 | } 503 | 504 | static void pcc_thunk_array__add(pcc_auxil_t auxil, pcc_thunk_array_t *array, pcc_thunk_t *thunk) { 505 | if (array->max <= array->len) { 506 | const size_t n = array->len + 1; 507 | size_t m = array->max; 508 | if (m == 0) m = PCC_ARRAY_MIN_SIZE; 509 | while (m < n && m != 0) m <<= 1; 510 | if (m == 0) m = n; 511 | array->buf = (pcc_thunk_t **)PCC_REALLOC(auxil, array->buf, sizeof(pcc_thunk_t *) * m); 512 | array->max = m; 513 | } 514 | array->buf[array->len++] = thunk; 515 | } 516 | 517 | static void pcc_thunk_array__revert(pcc_auxil_t auxil, pcc_thunk_array_t *array, size_t len) { 518 | while (array->len > len) { 519 | array->len--; 520 | pcc_thunk__destroy(auxil, array->buf[array->len]); 521 | } 522 | } 523 | 524 | static void pcc_thunk_array__term(pcc_auxil_t auxil, pcc_thunk_array_t *array) { 525 | while (array->len > 0) { 526 | array->len--; 527 | pcc_thunk__destroy(auxil, array->buf[array->len]); 528 | } 529 | PCC_FREE(auxil, array->buf); 530 | } 531 | 532 | static void pcc_memory_recycler__init(pcc_auxil_t auxil, pcc_memory_recycler_t *recycler, size_t element_size) { 533 | recycler->pool_list = NULL; 534 | recycler->entry_list = NULL; 535 | recycler->element_size = element_size; 536 | } 537 | 538 | static void *pcc_memory_recycler__supply(pcc_auxil_t auxil, pcc_memory_recycler_t *recycler) { 539 | if (recycler->entry_list) { 540 | pcc_memory_entry_t *const tmp = recycler->entry_list; 541 | recycler->entry_list = tmp->next; 542 | return tmp; 543 | } 544 | if (!recycler->pool_list || recycler->pool_list->unused == 0) { 545 | size_t size = PCC_POOL_MIN_SIZE; 546 | if (recycler->pool_list) { 547 | size = recycler->pool_list->allocated << 1; 548 | if (size == 0) size = recycler->pool_list->allocated; 549 | } 550 | { 551 | pcc_memory_pool_t *const pool = (pcc_memory_pool_t *)PCC_MALLOC( 552 | auxil, sizeof(pcc_memory_pool_t) + recycler->element_size * size 553 | ); 554 | pool->allocated = size; 555 | pool->unused = size; 556 | pool->next = recycler->pool_list; 557 | recycler->pool_list = pool; 558 | } 559 | } 560 | recycler->pool_list->unused--; 561 | return (char *)recycler->pool_list + sizeof(pcc_memory_pool_t) + recycler->element_size * recycler->pool_list->unused; 562 | } 563 | 564 | static void pcc_memory_recycler__recycle(pcc_auxil_t auxil, pcc_memory_recycler_t *recycler, void *ptr) { 565 | pcc_memory_entry_t *const tmp = (pcc_memory_entry_t *)ptr; 566 | tmp->next = recycler->entry_list; 567 | recycler->entry_list = tmp; 568 | } 569 | 570 | static void pcc_memory_recycler__term(pcc_auxil_t auxil, pcc_memory_recycler_t *recycler) { 571 | while (recycler->pool_list) { 572 | pcc_memory_pool_t *const tmp = recycler->pool_list; 573 | recycler->pool_list = tmp->next; 574 | PCC_FREE(auxil, tmp); 575 | } 576 | } 577 | 578 | MARK_FUNC_AS_USED 579 | static pcc_thunk_chunk_t *pcc_thunk_chunk__create(pcc_context_t *ctx) { 580 | pcc_thunk_chunk_t *const chunk = (pcc_thunk_chunk_t *)pcc_memory_recycler__supply(ctx->auxil, &ctx->thunk_chunk_recycler); 581 | pcc_value_table__init(ctx->auxil, &chunk->values); 582 | pcc_capture_table__init(ctx->auxil, &chunk->capts); 583 | pcc_thunk_array__init(ctx->auxil, &chunk->thunks); 584 | chunk->pos = 0; 585 | return chunk; 586 | } 587 | 588 | static void pcc_thunk_chunk__destroy(pcc_context_t *ctx, pcc_thunk_chunk_t *chunk) { 589 | if (chunk == NULL) return; 590 | pcc_thunk_array__term(ctx->auxil, &chunk->thunks); 591 | pcc_capture_table__term(ctx->auxil, &chunk->capts); 592 | pcc_value_table__term(ctx->auxil, &chunk->values); 593 | pcc_memory_recycler__recycle(ctx->auxil, &ctx->thunk_chunk_recycler, chunk); 594 | } 595 | 596 | static void pcc_rule_set__init(pcc_auxil_t auxil, pcc_rule_set_t *set) { 597 | set->len = 0; 598 | set->max = 0; 599 | set->buf = NULL; 600 | } 601 | 602 | static size_t pcc_rule_set__index(pcc_auxil_t auxil, const pcc_rule_set_t *set, pcc_rule_t rule) { 603 | size_t i; 604 | for (i = 0; i < set->len; i++) { 605 | if (set->buf[i] == rule) return i; 606 | } 607 | return PCC_VOID_VALUE; 608 | } 609 | 610 | static pcc_bool_t pcc_rule_set__add(pcc_auxil_t auxil, pcc_rule_set_t *set, pcc_rule_t rule) { 611 | const size_t i = pcc_rule_set__index(auxil, set, rule); 612 | if (i != PCC_VOID_VALUE) return PCC_FALSE; 613 | if (set->max <= set->len) { 614 | const size_t n = set->len + 1; 615 | size_t m = set->max; 616 | if (m == 0) m = PCC_ARRAY_MIN_SIZE; 617 | while (m < n && m != 0) m <<= 1; 618 | if (m == 0) m = n; 619 | set->buf = (pcc_rule_t *)PCC_REALLOC(auxil, set->buf, sizeof(pcc_rule_t) * m); 620 | set->max = m; 621 | } 622 | set->buf[set->len++] = rule; 623 | return PCC_TRUE; 624 | } 625 | 626 | static pcc_bool_t pcc_rule_set__remove(pcc_auxil_t auxil, pcc_rule_set_t *set, pcc_rule_t rule) { 627 | const size_t i = pcc_rule_set__index(auxil, set, rule); 628 | if (i == PCC_VOID_VALUE) return PCC_FALSE; 629 | memmove(set->buf + i, set->buf + (i + 1), sizeof(pcc_rule_t) * (set->len - (i + 1))); 630 | return PCC_TRUE; 631 | } 632 | 633 | static void pcc_rule_set__clear(pcc_auxil_t auxil, pcc_rule_set_t *set) { 634 | set->len = 0; 635 | } 636 | 637 | static void pcc_rule_set__copy(pcc_auxil_t auxil, pcc_rule_set_t *set, const pcc_rule_set_t *src) { 638 | size_t i; 639 | pcc_rule_set__clear(auxil, set); 640 | for (i = 0; i < src->len; i++) { 641 | pcc_rule_set__add(auxil, set, src->buf[i]); 642 | } 643 | } 644 | 645 | static void pcc_rule_set__term(pcc_auxil_t auxil, pcc_rule_set_t *set) { 646 | PCC_FREE(auxil, set->buf); 647 | } 648 | 649 | static pcc_lr_head_t *pcc_lr_head__create(pcc_context_t *ctx, pcc_rule_t rule) { 650 | pcc_lr_head_t *const head = (pcc_lr_head_t *)pcc_memory_recycler__supply(ctx->auxil, &ctx->lr_head_recycler); 651 | head->rule = rule; 652 | pcc_rule_set__init(ctx->auxil, &head->invol); 653 | pcc_rule_set__init(ctx->auxil, &head->eval); 654 | head->hold = NULL; 655 | return head; 656 | } 657 | 658 | static void pcc_lr_head__destroy(pcc_context_t *ctx, pcc_lr_head_t *head) { 659 | if (head == NULL) return; 660 | pcc_lr_head__destroy(ctx, head->hold); 661 | pcc_rule_set__term(ctx->auxil, &head->eval); 662 | pcc_rule_set__term(ctx->auxil, &head->invol); 663 | pcc_memory_recycler__recycle(ctx->auxil, &ctx->lr_head_recycler, head); 664 | } 665 | 666 | static void pcc_lr_entry__destroy(pcc_auxil_t auxil, pcc_lr_entry_t *lr); 667 | 668 | static pcc_lr_answer_t *pcc_lr_answer__create(pcc_context_t *ctx, pcc_lr_answer_type_t type, size_t pos) { 669 | pcc_lr_answer_t *answer = (pcc_lr_answer_t *)pcc_memory_recycler__supply(ctx->auxil, &ctx->lr_answer_recycler); 670 | answer->type = type; 671 | answer->pos = pos; 672 | answer->hold = NULL; 673 | switch (answer->type) { 674 | case PCC_LR_ANSWER_LR: 675 | answer->data.lr = NULL; 676 | break; 677 | case PCC_LR_ANSWER_CHUNK: 678 | answer->data.chunk = NULL; 679 | break; 680 | default: /* unknown */ 681 | PCC_FREE(ctx->auxil, answer); 682 | answer = NULL; 683 | } 684 | return answer; 685 | } 686 | 687 | static void pcc_lr_answer__set_chunk(pcc_context_t *ctx, pcc_lr_answer_t *answer, pcc_thunk_chunk_t *chunk) { 688 | pcc_lr_answer_t *const a = pcc_lr_answer__create(ctx, answer->type, answer->pos); 689 | switch (answer->type) { 690 | case PCC_LR_ANSWER_LR: 691 | a->data.lr = answer->data.lr; 692 | break; 693 | case PCC_LR_ANSWER_CHUNK: 694 | a->data.chunk = answer->data.chunk; 695 | break; 696 | default: /* unknown */ 697 | break; 698 | } 699 | a->hold = answer->hold; 700 | answer->hold = a; 701 | answer->type = PCC_LR_ANSWER_CHUNK; 702 | answer->data.chunk = chunk; 703 | } 704 | 705 | static void pcc_lr_answer__destroy(pcc_context_t *ctx, pcc_lr_answer_t *answer) { 706 | while (answer != NULL) { 707 | pcc_lr_answer_t *const a = answer->hold; 708 | switch (answer->type) { 709 | case PCC_LR_ANSWER_LR: 710 | pcc_lr_entry__destroy(ctx->auxil, answer->data.lr); 711 | break; 712 | case PCC_LR_ANSWER_CHUNK: 713 | pcc_thunk_chunk__destroy(ctx, answer->data.chunk); 714 | break; 715 | default: /* unknown */ 716 | break; 717 | } 718 | pcc_memory_recycler__recycle(ctx->auxil, &ctx->lr_answer_recycler, answer); 719 | answer = a; 720 | } 721 | } 722 | 723 | static void pcc_lr_memo_map__init(pcc_auxil_t auxil, pcc_lr_memo_map_t *map) { 724 | map->len = 0; 725 | map->max = 0; 726 | map->buf = NULL; 727 | } 728 | 729 | static size_t pcc_lr_memo_map__index(pcc_context_t *ctx, pcc_lr_memo_map_t *map, pcc_rule_t rule) { 730 | size_t i; 731 | for (i = 0; i < map->len; i++) { 732 | if (map->buf[i].rule == rule) return i; 733 | } 734 | return PCC_VOID_VALUE; 735 | } 736 | 737 | static void pcc_lr_memo_map__put(pcc_context_t *ctx, pcc_lr_memo_map_t *map, pcc_rule_t rule, pcc_lr_answer_t *answer) { 738 | const size_t i = pcc_lr_memo_map__index(ctx, map, rule); 739 | if (i != PCC_VOID_VALUE) { 740 | pcc_lr_answer__destroy(ctx, map->buf[i].answer); 741 | map->buf[i].answer = answer; 742 | } 743 | else { 744 | if (map->max <= map->len) { 745 | const size_t n = map->len + 1; 746 | size_t m = map->max; 747 | if (m == 0) m = PCC_ARRAY_MIN_SIZE; 748 | while (m < n && m != 0) m <<= 1; 749 | if (m == 0) m = n; 750 | map->buf = (pcc_lr_memo_t *)PCC_REALLOC(ctx->auxil, map->buf, sizeof(pcc_lr_memo_t) * m); 751 | map->max = m; 752 | } 753 | map->buf[map->len].rule = rule; 754 | map->buf[map->len].answer = answer; 755 | map->len++; 756 | } 757 | } 758 | 759 | static pcc_lr_answer_t *pcc_lr_memo_map__get(pcc_context_t *ctx, pcc_lr_memo_map_t *map, pcc_rule_t rule) { 760 | const size_t i = pcc_lr_memo_map__index(ctx, map, rule); 761 | return (i != PCC_VOID_VALUE) ? map->buf[i].answer : NULL; 762 | } 763 | 764 | static void pcc_lr_memo_map__term(pcc_context_t *ctx, pcc_lr_memo_map_t *map) { 765 | while (map->len > 0) { 766 | map->len--; 767 | pcc_lr_answer__destroy(ctx, map->buf[map->len].answer); 768 | } 769 | PCC_FREE(ctx->auxil, map->buf); 770 | } 771 | 772 | static pcc_lr_table_entry_t *pcc_lr_table_entry__create(pcc_context_t *ctx) { 773 | pcc_lr_table_entry_t *const entry = (pcc_lr_table_entry_t *)PCC_MALLOC(ctx->auxil, sizeof(pcc_lr_table_entry_t)); 774 | entry->head = NULL; 775 | pcc_lr_memo_map__init(ctx->auxil, &entry->memos); 776 | entry->hold_a = NULL; 777 | entry->hold_h = NULL; 778 | return entry; 779 | } 780 | 781 | static void pcc_lr_table_entry__destroy(pcc_context_t *ctx, pcc_lr_table_entry_t *entry) { 782 | if (entry == NULL) return; 783 | pcc_lr_head__destroy(ctx, entry->hold_h); 784 | pcc_lr_answer__destroy(ctx, entry->hold_a); 785 | pcc_lr_memo_map__term(ctx, &entry->memos); 786 | PCC_FREE(ctx->auxil, entry); 787 | } 788 | 789 | static void pcc_lr_table__init(pcc_auxil_t auxil, pcc_lr_table_t *table) { 790 | table->ofs = 0; 791 | table->len = 0; 792 | table->max = 0; 793 | table->buf = NULL; 794 | } 795 | 796 | static void pcc_lr_table__resize(pcc_context_t *ctx, pcc_lr_table_t *table, size_t len) { 797 | size_t i; 798 | for (i = len; i < table->len; i++) pcc_lr_table_entry__destroy(ctx, table->buf[i]); 799 | if (table->max < len) { 800 | size_t m = table->max; 801 | if (m == 0) m = PCC_ARRAY_MIN_SIZE; 802 | while (m < len && m != 0) m <<= 1; 803 | if (m == 0) m = len; 804 | table->buf = (pcc_lr_table_entry_t **)PCC_REALLOC(ctx->auxil, table->buf, sizeof(pcc_lr_table_entry_t *) * m); 805 | table->max = m; 806 | } 807 | for (i = table->len; i < len; i++) table->buf[i] = NULL; 808 | table->len = len; 809 | } 810 | 811 | static void pcc_lr_table__set_head(pcc_context_t *ctx, pcc_lr_table_t *table, size_t index, pcc_lr_head_t *head) { 812 | index += table->ofs; 813 | if (index >= table->len) pcc_lr_table__resize(ctx, table, index + 1); 814 | if (table->buf[index] == NULL) table->buf[index] = pcc_lr_table_entry__create(ctx); 815 | table->buf[index]->head = head; 816 | } 817 | 818 | static void pcc_lr_table__hold_head(pcc_context_t *ctx, pcc_lr_table_t *table, size_t index, pcc_lr_head_t *head) { 819 | index += table->ofs; 820 | if (index >= table->len) pcc_lr_table__resize(ctx, table, index + 1); 821 | if (table->buf[index] == NULL) table->buf[index] = pcc_lr_table_entry__create(ctx); 822 | head->hold = table->buf[index]->hold_h; 823 | table->buf[index]->hold_h = head; 824 | } 825 | 826 | static void pcc_lr_table__set_answer(pcc_context_t *ctx, pcc_lr_table_t *table, size_t index, pcc_rule_t rule, pcc_lr_answer_t *answer) { 827 | index += table->ofs; 828 | if (index >= table->len) pcc_lr_table__resize(ctx, table, index + 1); 829 | if (table->buf[index] == NULL) table->buf[index] = pcc_lr_table_entry__create(ctx); 830 | pcc_lr_memo_map__put(ctx, &table->buf[index]->memos, rule, answer); 831 | } 832 | 833 | static void pcc_lr_table__hold_answer(pcc_context_t *ctx, pcc_lr_table_t *table, size_t index, pcc_lr_answer_t *answer) { 834 | index += table->ofs; 835 | if (index >= table->len) pcc_lr_table__resize(ctx, table, index + 1); 836 | if (table->buf[index] == NULL) table->buf[index] = pcc_lr_table_entry__create(ctx); 837 | answer->hold = table->buf[index]->hold_a; 838 | table->buf[index]->hold_a = answer; 839 | } 840 | 841 | static pcc_lr_head_t *pcc_lr_table__get_head(pcc_context_t *ctx, pcc_lr_table_t *table, size_t index) { 842 | index += table->ofs; 843 | if (index >= table->len || table->buf[index] == NULL) return NULL; 844 | return table->buf[index]->head; 845 | } 846 | 847 | static pcc_lr_answer_t *pcc_lr_table__get_answer(pcc_context_t *ctx, pcc_lr_table_t *table, size_t index, pcc_rule_t rule) { 848 | index += table->ofs; 849 | if (index >= table->len || table->buf[index] == NULL) return NULL; 850 | return pcc_lr_memo_map__get(ctx, &table->buf[index]->memos, rule); 851 | } 852 | 853 | static void pcc_lr_table__shift(pcc_context_t *ctx, pcc_lr_table_t *table, size_t count) { 854 | size_t i; 855 | if (count > table->len - table->ofs) count = table->len - table->ofs; 856 | for (i = 0; i < count; i++) pcc_lr_table_entry__destroy(ctx, table->buf[table->ofs++]); 857 | if (table->ofs > (table->max >> 1)) { 858 | memmove(table->buf, table->buf + table->ofs, sizeof(pcc_lr_table_entry_t *) * (table->len - table->ofs)); 859 | table->len -= table->ofs; 860 | table->ofs = 0; 861 | } 862 | } 863 | 864 | static void pcc_lr_table__term(pcc_context_t *ctx, pcc_lr_table_t *table) { 865 | while (table->len > table->ofs) { 866 | table->len--; 867 | pcc_lr_table_entry__destroy(ctx, table->buf[table->len]); 868 | } 869 | PCC_FREE(ctx->auxil, table->buf); 870 | } 871 | 872 | static pcc_lr_entry_t *pcc_lr_entry__create(pcc_auxil_t auxil, pcc_rule_t rule) { 873 | pcc_lr_entry_t *const lr = (pcc_lr_entry_t *)PCC_MALLOC(auxil, sizeof(pcc_lr_entry_t)); 874 | lr->rule = rule; 875 | lr->seed = NULL; 876 | lr->head = NULL; 877 | return lr; 878 | } 879 | 880 | static void pcc_lr_entry__destroy(pcc_auxil_t auxil, pcc_lr_entry_t *lr) { 881 | PCC_FREE(auxil, lr); 882 | } 883 | 884 | static void pcc_lr_stack__init(pcc_auxil_t auxil, pcc_lr_stack_t *stack) { 885 | stack->len = 0; 886 | stack->max = 0; 887 | stack->buf = NULL; 888 | } 889 | 890 | static void pcc_lr_stack__push(pcc_auxil_t auxil, pcc_lr_stack_t *stack, pcc_lr_entry_t *lr) { 891 | if (stack->max <= stack->len) { 892 | const size_t n = stack->len + 1; 893 | size_t m = stack->max; 894 | if (m == 0) m = PCC_ARRAY_MIN_SIZE; 895 | while (m < n && m != 0) m <<= 1; 896 | if (m == 0) m = n; 897 | stack->buf = (pcc_lr_entry_t **)PCC_REALLOC(auxil, stack->buf, sizeof(pcc_lr_entry_t *) * m); 898 | stack->max = m; 899 | } 900 | stack->buf[stack->len++] = lr; 901 | } 902 | 903 | static pcc_lr_entry_t *pcc_lr_stack__pop(pcc_auxil_t auxil, pcc_lr_stack_t *stack) { 904 | return stack->buf[--stack->len]; 905 | } 906 | 907 | static void pcc_lr_stack__term(pcc_auxil_t auxil, pcc_lr_stack_t *stack) { 908 | PCC_FREE(auxil, stack->buf); 909 | } 910 | 911 | static pcc_context_t *pcc_context__create(pcc_auxil_t auxil) { 912 | pcc_context_t *const ctx = (pcc_context_t *)PCC_MALLOC(auxil, sizeof(pcc_context_t)); 913 | ctx->pos = 0; 914 | ctx->cur = 0; 915 | ctx->level = 0; 916 | pcc_char_array__init(auxil, &ctx->buffer); 917 | pcc_lr_table__init(auxil, &ctx->lrtable); 918 | pcc_lr_stack__init(auxil, &ctx->lrstack); 919 | pcc_thunk_array__init(auxil, &ctx->thunks); 920 | pcc_memory_recycler__init(auxil, &ctx->thunk_chunk_recycler, sizeof(pcc_thunk_chunk_t)); 921 | pcc_memory_recycler__init(auxil, &ctx->lr_head_recycler, sizeof(pcc_lr_head_t)); 922 | pcc_memory_recycler__init(auxil, &ctx->lr_answer_recycler, sizeof(pcc_lr_answer_t)); 923 | ctx->auxil = auxil; 924 | return ctx; 925 | } 926 | 927 | static void pcc_context__destroy(pcc_context_t *ctx) { 928 | if (ctx == NULL) return; 929 | pcc_thunk_array__term(ctx->auxil, &ctx->thunks); 930 | pcc_lr_stack__term(ctx->auxil, &ctx->lrstack); 931 | pcc_lr_table__term(ctx, &ctx->lrtable); 932 | pcc_char_array__term(ctx->auxil, &ctx->buffer); 933 | pcc_memory_recycler__term(ctx->auxil, &ctx->thunk_chunk_recycler); 934 | pcc_memory_recycler__term(ctx->auxil, &ctx->lr_head_recycler); 935 | pcc_memory_recycler__term(ctx->auxil, &ctx->lr_answer_recycler); 936 | PCC_FREE(ctx->auxil, ctx); 937 | } 938 | 939 | static size_t pcc_refill_buffer(pcc_context_t *ctx, size_t num) { 940 | if (ctx->buffer.len >= ctx->cur + num) return ctx->buffer.len - ctx->cur; 941 | while (ctx->buffer.len < ctx->cur + num) { 942 | const int c = PCC_GETCHAR(ctx->auxil); 943 | if (c < 0) break; 944 | pcc_char_array__add(ctx->auxil, &ctx->buffer, (char)c); 945 | } 946 | return ctx->buffer.len - ctx->cur; 947 | } 948 | 949 | MARK_FUNC_AS_USED 950 | static void pcc_commit_buffer(pcc_context_t *ctx) { 951 | memmove(ctx->buffer.buf, ctx->buffer.buf + ctx->cur, ctx->buffer.len - ctx->cur); 952 | ctx->buffer.len -= ctx->cur; 953 | ctx->pos += ctx->cur; 954 | pcc_lr_table__shift(ctx, &ctx->lrtable, ctx->cur); 955 | ctx->cur = 0; 956 | } 957 | 958 | MARK_FUNC_AS_USED 959 | static const char *pcc_get_capture_string(pcc_context_t *ctx, const pcc_capture_t *capt) { 960 | if (capt->string == NULL) 961 | ((pcc_capture_t *)capt)->string = 962 | pcc_strndup_e(ctx->auxil, ctx->buffer.buf + capt->range.start, capt->range.end - capt->range.start); 963 | return capt->string; 964 | } 965 | 966 | MARK_FUNC_AS_USED 967 | static pcc_bool_t pcc_apply_rule(pcc_context_t *ctx, pcc_rule_t rule, pcc_thunk_array_t *thunks, pcc_value_t *value) { 968 | static pcc_value_t null; 969 | pcc_thunk_chunk_t *c = NULL; 970 | const size_t p = ctx->pos + ctx->cur; 971 | pcc_bool_t b = PCC_TRUE; 972 | pcc_lr_answer_t *a = pcc_lr_table__get_answer(ctx, &ctx->lrtable, p, rule); 973 | pcc_lr_head_t *h = pcc_lr_table__get_head(ctx, &ctx->lrtable, p); 974 | if (h != NULL) { 975 | if (a == NULL && rule != h->rule && pcc_rule_set__index(ctx->auxil, &h->invol, rule) == PCC_VOID_VALUE) { 976 | b = PCC_FALSE; 977 | c = NULL; 978 | } 979 | else if (pcc_rule_set__remove(ctx->auxil, &h->eval, rule)) { 980 | b = PCC_FALSE; 981 | c = rule(ctx); 982 | a = pcc_lr_answer__create(ctx, PCC_LR_ANSWER_CHUNK, ctx->pos + ctx->cur); 983 | a->data.chunk = c; 984 | pcc_lr_table__hold_answer(ctx, &ctx->lrtable, p, a); 985 | } 986 | } 987 | if (b) { 988 | if (a != NULL) { 989 | ctx->cur = a->pos - ctx->pos; 990 | switch (a->type) { 991 | case PCC_LR_ANSWER_LR: 992 | if (a->data.lr->head == NULL) { 993 | a->data.lr->head = pcc_lr_head__create(ctx, rule); 994 | pcc_lr_table__hold_head(ctx, &ctx->lrtable, p, a->data.lr->head); 995 | } 996 | { 997 | size_t i = ctx->lrstack.len; 998 | while (i > 0) { 999 | i--; 1000 | if (ctx->lrstack.buf[i]->head == a->data.lr->head) break; 1001 | ctx->lrstack.buf[i]->head = a->data.lr->head; 1002 | pcc_rule_set__add(ctx->auxil, &a->data.lr->head->invol, ctx->lrstack.buf[i]->rule); 1003 | } 1004 | } 1005 | c = a->data.lr->seed; 1006 | break; 1007 | case PCC_LR_ANSWER_CHUNK: 1008 | c = a->data.chunk; 1009 | break; 1010 | default: /* unknown */ 1011 | break; 1012 | } 1013 | } 1014 | else { 1015 | pcc_lr_entry_t *const e = pcc_lr_entry__create(ctx->auxil, rule); 1016 | pcc_lr_stack__push(ctx->auxil, &ctx->lrstack, e); 1017 | a = pcc_lr_answer__create(ctx, PCC_LR_ANSWER_LR, p); 1018 | a->data.lr = e; 1019 | pcc_lr_table__set_answer(ctx, &ctx->lrtable, p, rule, a); 1020 | c = rule(ctx); 1021 | pcc_lr_stack__pop(ctx->auxil, &ctx->lrstack); 1022 | a->pos = ctx->pos + ctx->cur; 1023 | if (e->head == NULL) { 1024 | pcc_lr_answer__set_chunk(ctx, a, c); 1025 | } 1026 | else { 1027 | e->seed = c; 1028 | h = a->data.lr->head; 1029 | if (h->rule != rule) { 1030 | c = a->data.lr->seed; 1031 | a = pcc_lr_answer__create(ctx, PCC_LR_ANSWER_CHUNK, ctx->pos + ctx->cur); 1032 | a->data.chunk = c; 1033 | pcc_lr_table__hold_answer(ctx, &ctx->lrtable, p, a); 1034 | } 1035 | else { 1036 | pcc_lr_answer__set_chunk(ctx, a, a->data.lr->seed); 1037 | if (a->data.chunk == NULL) { 1038 | c = NULL; 1039 | } 1040 | else { 1041 | pcc_lr_table__set_head(ctx, &ctx->lrtable, p, h); 1042 | for (;;) { 1043 | ctx->cur = p - ctx->pos; 1044 | pcc_rule_set__copy(ctx->auxil, &h->eval, &h->invol); 1045 | c = rule(ctx); 1046 | if (c == NULL || ctx->pos + ctx->cur <= a->pos) break; 1047 | pcc_lr_answer__set_chunk(ctx, a, c); 1048 | a->pos = ctx->pos + ctx->cur; 1049 | } 1050 | pcc_thunk_chunk__destroy(ctx, c); 1051 | pcc_lr_table__set_head(ctx, &ctx->lrtable, p, NULL); 1052 | ctx->cur = a->pos - ctx->pos; 1053 | c = a->data.chunk; 1054 | } 1055 | } 1056 | } 1057 | } 1058 | } 1059 | if (c == NULL) return PCC_FALSE; 1060 | if (value == NULL) value = &null; 1061 | memset(value, 0, sizeof(pcc_value_t)); /* in case */ 1062 | pcc_thunk_array__add(ctx->auxil, thunks, pcc_thunk__create_node(ctx->auxil, &c->thunks, value)); 1063 | return PCC_TRUE; 1064 | } 1065 | 1066 | MARK_FUNC_AS_USED 1067 | static void pcc_do_action(pcc_context_t *ctx, const pcc_thunk_array_t *thunks, pcc_value_t *value) { 1068 | size_t i; 1069 | for (i = 0; i < thunks->len; i++) { 1070 | pcc_thunk_t *const thunk = thunks->buf[i]; 1071 | switch (thunk->type) { 1072 | case PCC_THUNK_LEAF: 1073 | thunk->data.leaf.action(ctx, thunk, value); 1074 | break; 1075 | case PCC_THUNK_NODE: 1076 | pcc_do_action(ctx, thunk->data.node.thunks, thunk->data.node.value); 1077 | break; 1078 | default: /* unknown */ 1079 | break; 1080 | } 1081 | } 1082 | } 1083 | 1084 | static void pcc_action_s2s_0(sasl_header_context_t *__pcc_ctx, pcc_thunk_t *__pcc_in, pcc_value_t *__pcc_out) { 1085 | #define auxil (__pcc_ctx->auxil) 1086 | #define __ (*__pcc_out) 1087 | #define _0 pcc_get_capture_string(__pcc_ctx, &__pcc_in->data.leaf.capt0) 1088 | #define _0s ((const size_t)(__pcc_ctx->pos + __pcc_in->data.leaf.capt0.range.start)) 1089 | #define _0e ((const size_t)(__pcc_ctx->pos + __pcc_in->data.leaf.capt0.range.end)) 1090 | #define _1 pcc_get_capture_string(__pcc_ctx, __pcc_in->data.leaf.capts.buf[0]) 1091 | #define _1s ((const size_t)(__pcc_ctx->pos + __pcc_in->data.leaf.capts.buf[0]->range.start)) 1092 | #define _1e ((const size_t)(__pcc_ctx->pos + __pcc_in->data.leaf.capts.buf[0]->range.end)) 1093 | #line 40 "http_auth_header_parser.peg" 1094 | errno = 0; 1095 | long tmp = strtoul(_1,NULL,16); 1096 | if (errno == 0) auxil->s2s = tmp; 1097 | #line 1097 "http_auth_header_parser.c" 1098 | #undef _1e 1099 | #undef _1s 1100 | #undef _1 1101 | #undef _0e 1102 | #undef _0s 1103 | #undef _0 1104 | #undef __ 1105 | #undef auxil 1106 | } 1107 | 1108 | static void pcc_action_c2s_0(sasl_header_context_t *__pcc_ctx, pcc_thunk_t *__pcc_in, pcc_value_t *__pcc_out) { 1109 | #define auxil (__pcc_ctx->auxil) 1110 | #define __ (*__pcc_out) 1111 | #define _0 pcc_get_capture_string(__pcc_ctx, &__pcc_in->data.leaf.capt0) 1112 | #define _0s ((const size_t)(__pcc_ctx->pos + __pcc_in->data.leaf.capt0.range.start)) 1113 | #define _0e ((const size_t)(__pcc_ctx->pos + __pcc_in->data.leaf.capt0.range.end)) 1114 | #define _1 pcc_get_capture_string(__pcc_ctx, __pcc_in->data.leaf.capts.buf[0]) 1115 | #define _1s ((const size_t)(__pcc_ctx->pos + __pcc_in->data.leaf.capts.buf[0]->range.start)) 1116 | #define _1e ((const size_t)(__pcc_ctx->pos + __pcc_in->data.leaf.capts.buf[0]->range.end)) 1117 | #line 49 "http_auth_header_parser.peg" 1118 | auxil->c2s = auxil->input + _1s; 1119 | auxil->c2s_len = _1e - _1s; 1120 | #line 1120 "http_auth_header_parser.c" 1121 | #undef _1e 1122 | #undef _1s 1123 | #undef _1 1124 | #undef _0e 1125 | #undef _0s 1126 | #undef _0 1127 | #undef __ 1128 | #undef auxil 1129 | } 1130 | 1131 | static void pcc_action_mech_0(sasl_header_context_t *__pcc_ctx, pcc_thunk_t *__pcc_in, pcc_value_t *__pcc_out) { 1132 | #define auxil (__pcc_ctx->auxil) 1133 | #define __ (*__pcc_out) 1134 | #define _0 pcc_get_capture_string(__pcc_ctx, &__pcc_in->data.leaf.capt0) 1135 | #define _0s ((const size_t)(__pcc_ctx->pos + __pcc_in->data.leaf.capt0.range.start)) 1136 | #define _0e ((const size_t)(__pcc_ctx->pos + __pcc_in->data.leaf.capt0.range.end)) 1137 | #define _1 pcc_get_capture_string(__pcc_ctx, __pcc_in->data.leaf.capts.buf[0]) 1138 | #define _1s ((const size_t)(__pcc_ctx->pos + __pcc_in->data.leaf.capts.buf[0]->range.start)) 1139 | #define _1e ((const size_t)(__pcc_ctx->pos + __pcc_in->data.leaf.capts.buf[0]->range.end)) 1140 | #line 54 "http_auth_header_parser.peg" 1141 | auxil->mech = auxil->input + _1s; 1142 | auxil->mech_len = _1e - _1s; 1143 | #line 1143 "http_auth_header_parser.c" 1144 | #undef _1e 1145 | #undef _1s 1146 | #undef _1 1147 | #undef _0e 1148 | #undef _0s 1149 | #undef _0 1150 | #undef __ 1151 | #undef auxil 1152 | } 1153 | 1154 | static void pcc_action_realm_0(sasl_header_context_t *__pcc_ctx, pcc_thunk_t *__pcc_in, pcc_value_t *__pcc_out) { 1155 | #define auxil (__pcc_ctx->auxil) 1156 | #define __ (*__pcc_out) 1157 | #define _0 pcc_get_capture_string(__pcc_ctx, &__pcc_in->data.leaf.capt0) 1158 | #define _0s ((const size_t)(__pcc_ctx->pos + __pcc_in->data.leaf.capt0.range.start)) 1159 | #define _0e ((const size_t)(__pcc_ctx->pos + __pcc_in->data.leaf.capt0.range.end)) 1160 | #define _1 pcc_get_capture_string(__pcc_ctx, __pcc_in->data.leaf.capts.buf[0]) 1161 | #define _1s ((const size_t)(__pcc_ctx->pos + __pcc_in->data.leaf.capts.buf[0]->range.start)) 1162 | #define _1e ((const size_t)(__pcc_ctx->pos + __pcc_in->data.leaf.capts.buf[0]->range.end)) 1163 | #line 58 "http_auth_header_parser.peg" 1164 | auxil->realm = auxil->input + _1s; 1165 | auxil->realm_len = _1e - _1s; 1166 | #line 1166 "http_auth_header_parser.c" 1167 | #undef _1e 1168 | #undef _1s 1169 | #undef _1 1170 | #undef _0e 1171 | #undef _0s 1172 | #undef _0 1173 | #undef __ 1174 | #undef auxil 1175 | } 1176 | 1177 | static pcc_thunk_chunk_t *pcc_evaluate_rule_header(pcc_context_t *ctx); 1178 | static pcc_thunk_chunk_t *pcc_evaluate_rule_assertion(pcc_context_t *ctx); 1179 | static pcc_thunk_chunk_t *pcc_evaluate_rule_msg(pcc_context_t *ctx); 1180 | static pcc_thunk_chunk_t *pcc_evaluate_rule_s2s(pcc_context_t *ctx); 1181 | static pcc_thunk_chunk_t *pcc_evaluate_rule_c2s(pcc_context_t *ctx); 1182 | static pcc_thunk_chunk_t *pcc_evaluate_rule_mech(pcc_context_t *ctx); 1183 | static pcc_thunk_chunk_t *pcc_evaluate_rule_realm(pcc_context_t *ctx); 1184 | static pcc_thunk_chunk_t *pcc_evaluate_rule_realmstring(pcc_context_t *ctx); 1185 | static pcc_thunk_chunk_t *pcc_evaluate_rule_mechstring(pcc_context_t *ctx); 1186 | static pcc_thunk_chunk_t *pcc_evaluate_rule_base64string(pcc_context_t *ctx); 1187 | static pcc_thunk_chunk_t *pcc_evaluate_rule__(pcc_context_t *ctx); 1188 | 1189 | static pcc_thunk_chunk_t *pcc_evaluate_rule_header(pcc_context_t *ctx) { 1190 | pcc_thunk_chunk_t *const chunk = pcc_thunk_chunk__create(ctx); 1191 | chunk->pos = ctx->cur; 1192 | PCC_DEBUG(ctx->auxil, PCC_DBG_EVALUATE, "header", ctx->level, chunk->pos, (ctx->buffer.buf + chunk->pos), (ctx->buffer.len - chunk->pos)); 1193 | ctx->level++; 1194 | pcc_value_table__resize(ctx->auxil, &chunk->values, 0); 1195 | pcc_capture_table__resize(ctx->auxil, &chunk->capts, 0); 1196 | { 1197 | char c; 1198 | if (pcc_refill_buffer(ctx, 1) < 1) goto L0000; 1199 | c = ctx->buffer.buf[ctx->cur]; 1200 | if (!( 1201 | c == 'S' || 1202 | c == 's' 1203 | )) goto L0000; 1204 | ctx->cur++; 1205 | } 1206 | { 1207 | char c; 1208 | if (pcc_refill_buffer(ctx, 1) < 1) goto L0000; 1209 | c = ctx->buffer.buf[ctx->cur]; 1210 | if (!( 1211 | c == 'A' || 1212 | c == 'a' 1213 | )) goto L0000; 1214 | ctx->cur++; 1215 | } 1216 | { 1217 | char c; 1218 | if (pcc_refill_buffer(ctx, 1) < 1) goto L0000; 1219 | c = ctx->buffer.buf[ctx->cur]; 1220 | if (!( 1221 | c == 'S' || 1222 | c == 's' 1223 | )) goto L0000; 1224 | ctx->cur++; 1225 | } 1226 | { 1227 | char c; 1228 | if (pcc_refill_buffer(ctx, 1) < 1) goto L0000; 1229 | c = ctx->buffer.buf[ctx->cur]; 1230 | if (!( 1231 | c == 'L' || 1232 | c == 'l' 1233 | )) goto L0000; 1234 | ctx->cur++; 1235 | } 1236 | if (!pcc_apply_rule(ctx, pcc_evaluate_rule_assertion, &chunk->thunks, NULL)) goto L0000; 1237 | { 1238 | int i; 1239 | for (i = 0;; i++) { 1240 | const size_t p = ctx->cur; 1241 | const size_t n = chunk->thunks.len; 1242 | if ( 1243 | pcc_refill_buffer(ctx, 1) < 1 || 1244 | ctx->buffer.buf[ctx->cur] != ',' 1245 | ) goto L0001; 1246 | ctx->cur++; 1247 | if (!pcc_apply_rule(ctx, pcc_evaluate_rule_assertion, &chunk->thunks, NULL)) goto L0001; 1248 | if (ctx->cur == p) break; 1249 | continue; 1250 | L0001:; 1251 | ctx->cur = p; 1252 | pcc_thunk_array__revert(ctx->auxil, &chunk->thunks, n); 1253 | break; 1254 | } 1255 | } 1256 | ctx->level--; 1257 | PCC_DEBUG(ctx->auxil, PCC_DBG_MATCH, "header", ctx->level, chunk->pos, (ctx->buffer.buf + chunk->pos), (ctx->cur - chunk->pos)); 1258 | return chunk; 1259 | L0000:; 1260 | ctx->level--; 1261 | PCC_DEBUG(ctx->auxil, PCC_DBG_NOMATCH, "header", ctx->level, chunk->pos, (ctx->buffer.buf + chunk->pos), (ctx->cur - chunk->pos)); 1262 | pcc_thunk_chunk__destroy(ctx, chunk); 1263 | return NULL; 1264 | } 1265 | 1266 | static pcc_thunk_chunk_t *pcc_evaluate_rule_assertion(pcc_context_t *ctx) { 1267 | pcc_thunk_chunk_t *const chunk = pcc_thunk_chunk__create(ctx); 1268 | chunk->pos = ctx->cur; 1269 | PCC_DEBUG(ctx->auxil, PCC_DBG_EVALUATE, "assertion", ctx->level, chunk->pos, (ctx->buffer.buf + chunk->pos), (ctx->buffer.len - chunk->pos)); 1270 | ctx->level++; 1271 | pcc_value_table__resize(ctx->auxil, &chunk->values, 0); 1272 | pcc_capture_table__resize(ctx->auxil, &chunk->capts, 0); 1273 | if (!pcc_apply_rule(ctx, pcc_evaluate_rule__, &chunk->thunks, NULL)) goto L0000; 1274 | { 1275 | const size_t p = ctx->cur; 1276 | const size_t n = chunk->thunks.len; 1277 | if (!pcc_apply_rule(ctx, pcc_evaluate_rule_msg, &chunk->thunks, NULL)) goto L0002; 1278 | goto L0001; 1279 | L0002:; 1280 | ctx->cur = p; 1281 | pcc_thunk_array__revert(ctx->auxil, &chunk->thunks, n); 1282 | if (!pcc_apply_rule(ctx, pcc_evaluate_rule_mech, &chunk->thunks, NULL)) goto L0003; 1283 | goto L0001; 1284 | L0003:; 1285 | ctx->cur = p; 1286 | pcc_thunk_array__revert(ctx->auxil, &chunk->thunks, n); 1287 | if (!pcc_apply_rule(ctx, pcc_evaluate_rule_realm, &chunk->thunks, NULL)) goto L0004; 1288 | goto L0001; 1289 | L0004:; 1290 | ctx->cur = p; 1291 | pcc_thunk_array__revert(ctx->auxil, &chunk->thunks, n); 1292 | goto L0000; 1293 | L0001:; 1294 | } 1295 | if (!pcc_apply_rule(ctx, pcc_evaluate_rule__, &chunk->thunks, NULL)) goto L0000; 1296 | ctx->level--; 1297 | PCC_DEBUG(ctx->auxil, PCC_DBG_MATCH, "assertion", ctx->level, chunk->pos, (ctx->buffer.buf + chunk->pos), (ctx->cur - chunk->pos)); 1298 | return chunk; 1299 | L0000:; 1300 | ctx->level--; 1301 | PCC_DEBUG(ctx->auxil, PCC_DBG_NOMATCH, "assertion", ctx->level, chunk->pos, (ctx->buffer.buf + chunk->pos), (ctx->cur - chunk->pos)); 1302 | pcc_thunk_chunk__destroy(ctx, chunk); 1303 | return NULL; 1304 | } 1305 | 1306 | static pcc_thunk_chunk_t *pcc_evaluate_rule_msg(pcc_context_t *ctx) { 1307 | pcc_thunk_chunk_t *const chunk = pcc_thunk_chunk__create(ctx); 1308 | chunk->pos = ctx->cur; 1309 | PCC_DEBUG(ctx->auxil, PCC_DBG_EVALUATE, "msg", ctx->level, chunk->pos, (ctx->buffer.buf + chunk->pos), (ctx->buffer.len - chunk->pos)); 1310 | ctx->level++; 1311 | pcc_value_table__resize(ctx->auxil, &chunk->values, 0); 1312 | pcc_capture_table__resize(ctx->auxil, &chunk->capts, 0); 1313 | { 1314 | const size_t p = ctx->cur; 1315 | const size_t n = chunk->thunks.len; 1316 | if (!pcc_apply_rule(ctx, pcc_evaluate_rule_s2s, &chunk->thunks, NULL)) goto L0002; 1317 | goto L0001; 1318 | L0002:; 1319 | ctx->cur = p; 1320 | pcc_thunk_array__revert(ctx->auxil, &chunk->thunks, n); 1321 | if (!pcc_apply_rule(ctx, pcc_evaluate_rule_c2s, &chunk->thunks, NULL)) goto L0003; 1322 | goto L0001; 1323 | L0003:; 1324 | ctx->cur = p; 1325 | pcc_thunk_array__revert(ctx->auxil, &chunk->thunks, n); 1326 | goto L0000; 1327 | L0001:; 1328 | } 1329 | ctx->level--; 1330 | PCC_DEBUG(ctx->auxil, PCC_DBG_MATCH, "msg", ctx->level, chunk->pos, (ctx->buffer.buf + chunk->pos), (ctx->cur - chunk->pos)); 1331 | return chunk; 1332 | L0000:; 1333 | ctx->level--; 1334 | PCC_DEBUG(ctx->auxil, PCC_DBG_NOMATCH, "msg", ctx->level, chunk->pos, (ctx->buffer.buf + chunk->pos), (ctx->cur - chunk->pos)); 1335 | pcc_thunk_chunk__destroy(ctx, chunk); 1336 | return NULL; 1337 | } 1338 | 1339 | static pcc_thunk_chunk_t *pcc_evaluate_rule_s2s(pcc_context_t *ctx) { 1340 | pcc_thunk_chunk_t *const chunk = pcc_thunk_chunk__create(ctx); 1341 | chunk->pos = ctx->cur; 1342 | PCC_DEBUG(ctx->auxil, PCC_DBG_EVALUATE, "s2s", ctx->level, chunk->pos, (ctx->buffer.buf + chunk->pos), (ctx->buffer.len - chunk->pos)); 1343 | ctx->level++; 1344 | pcc_value_table__resize(ctx->auxil, &chunk->values, 0); 1345 | pcc_capture_table__resize(ctx->auxil, &chunk->capts, 1); 1346 | if ( 1347 | pcc_refill_buffer(ctx, 3) < 3 || 1348 | (ctx->buffer.buf + ctx->cur)[0] != 's' || 1349 | (ctx->buffer.buf + ctx->cur)[1] != '2' || 1350 | (ctx->buffer.buf + ctx->cur)[2] != 's' 1351 | ) goto L0000; 1352 | ctx->cur += 3; 1353 | if (!pcc_apply_rule(ctx, pcc_evaluate_rule__, &chunk->thunks, NULL)) goto L0000; 1354 | if ( 1355 | pcc_refill_buffer(ctx, 1) < 1 || 1356 | ctx->buffer.buf[ctx->cur] != '=' 1357 | ) goto L0000; 1358 | ctx->cur++; 1359 | if (!pcc_apply_rule(ctx, pcc_evaluate_rule__, &chunk->thunks, NULL)) goto L0000; 1360 | if ( 1361 | pcc_refill_buffer(ctx, 1) < 1 || 1362 | ctx->buffer.buf[ctx->cur] != '\"' 1363 | ) goto L0000; 1364 | ctx->cur++; 1365 | { 1366 | const size_t p = ctx->cur; 1367 | size_t q; 1368 | { 1369 | const size_t p0 = ctx->cur; 1370 | const size_t n0 = chunk->thunks.len; 1371 | int i; 1372 | for (i = 0;; i++) { 1373 | const size_t p = ctx->cur; 1374 | const size_t n = chunk->thunks.len; 1375 | { 1376 | char c; 1377 | if (pcc_refill_buffer(ctx, 1) < 1) goto L0001; 1378 | c = ctx->buffer.buf[ctx->cur]; 1379 | if (!( 1380 | (c >= '0' && c <= '9') || 1381 | (c >= 'a' && c <= 'f') || 1382 | (c >= 'A' && c <= 'F') 1383 | )) goto L0001; 1384 | ctx->cur++; 1385 | } 1386 | if (ctx->cur == p) break; 1387 | continue; 1388 | L0001:; 1389 | ctx->cur = p; 1390 | pcc_thunk_array__revert(ctx->auxil, &chunk->thunks, n); 1391 | break; 1392 | } 1393 | if (i < 1) { 1394 | ctx->cur = p0; 1395 | pcc_thunk_array__revert(ctx->auxil, &chunk->thunks, n0); 1396 | goto L0000; 1397 | } 1398 | } 1399 | q = ctx->cur; 1400 | chunk->capts.buf[0].range.start = p; 1401 | chunk->capts.buf[0].range.end = q; 1402 | } 1403 | if ( 1404 | pcc_refill_buffer(ctx, 1) < 1 || 1405 | ctx->buffer.buf[ctx->cur] != '\"' 1406 | ) goto L0000; 1407 | ctx->cur++; 1408 | { 1409 | pcc_thunk_t *const thunk = pcc_thunk__create_leaf(ctx->auxil, pcc_action_s2s_0, 0, 1); 1410 | thunk->data.leaf.capts.buf[0] = &(chunk->capts.buf[0]); 1411 | thunk->data.leaf.capt0.range.start = chunk->pos; 1412 | thunk->data.leaf.capt0.range.end = ctx->cur; 1413 | pcc_thunk_array__add(ctx->auxil, &chunk->thunks, thunk); 1414 | } 1415 | ctx->level--; 1416 | PCC_DEBUG(ctx->auxil, PCC_DBG_MATCH, "s2s", ctx->level, chunk->pos, (ctx->buffer.buf + chunk->pos), (ctx->cur - chunk->pos)); 1417 | return chunk; 1418 | L0000:; 1419 | ctx->level--; 1420 | PCC_DEBUG(ctx->auxil, PCC_DBG_NOMATCH, "s2s", ctx->level, chunk->pos, (ctx->buffer.buf + chunk->pos), (ctx->cur - chunk->pos)); 1421 | pcc_thunk_chunk__destroy(ctx, chunk); 1422 | return NULL; 1423 | } 1424 | 1425 | static pcc_thunk_chunk_t *pcc_evaluate_rule_c2s(pcc_context_t *ctx) { 1426 | pcc_thunk_chunk_t *const chunk = pcc_thunk_chunk__create(ctx); 1427 | chunk->pos = ctx->cur; 1428 | PCC_DEBUG(ctx->auxil, PCC_DBG_EVALUATE, "c2s", ctx->level, chunk->pos, (ctx->buffer.buf + chunk->pos), (ctx->buffer.len - chunk->pos)); 1429 | ctx->level++; 1430 | pcc_value_table__resize(ctx->auxil, &chunk->values, 0); 1431 | pcc_capture_table__resize(ctx->auxil, &chunk->capts, 1); 1432 | if ( 1433 | pcc_refill_buffer(ctx, 3) < 3 || 1434 | (ctx->buffer.buf + ctx->cur)[0] != 'c' || 1435 | (ctx->buffer.buf + ctx->cur)[1] != '2' || 1436 | (ctx->buffer.buf + ctx->cur)[2] != 's' 1437 | ) goto L0000; 1438 | ctx->cur += 3; 1439 | if (!pcc_apply_rule(ctx, pcc_evaluate_rule__, &chunk->thunks, NULL)) goto L0000; 1440 | if ( 1441 | pcc_refill_buffer(ctx, 1) < 1 || 1442 | ctx->buffer.buf[ctx->cur] != '=' 1443 | ) goto L0000; 1444 | ctx->cur++; 1445 | if (!pcc_apply_rule(ctx, pcc_evaluate_rule__, &chunk->thunks, NULL)) goto L0000; 1446 | if ( 1447 | pcc_refill_buffer(ctx, 1) < 1 || 1448 | ctx->buffer.buf[ctx->cur] != '\"' 1449 | ) goto L0000; 1450 | ctx->cur++; 1451 | { 1452 | const size_t p = ctx->cur; 1453 | size_t q; 1454 | if (!pcc_apply_rule(ctx, pcc_evaluate_rule_base64string, &chunk->thunks, NULL)) goto L0000; 1455 | q = ctx->cur; 1456 | chunk->capts.buf[0].range.start = p; 1457 | chunk->capts.buf[0].range.end = q; 1458 | } 1459 | if ( 1460 | pcc_refill_buffer(ctx, 1) < 1 || 1461 | ctx->buffer.buf[ctx->cur] != '\"' 1462 | ) goto L0000; 1463 | ctx->cur++; 1464 | { 1465 | pcc_thunk_t *const thunk = pcc_thunk__create_leaf(ctx->auxil, pcc_action_c2s_0, 0, 1); 1466 | thunk->data.leaf.capts.buf[0] = &(chunk->capts.buf[0]); 1467 | thunk->data.leaf.capt0.range.start = chunk->pos; 1468 | thunk->data.leaf.capt0.range.end = ctx->cur; 1469 | pcc_thunk_array__add(ctx->auxil, &chunk->thunks, thunk); 1470 | } 1471 | ctx->level--; 1472 | PCC_DEBUG(ctx->auxil, PCC_DBG_MATCH, "c2s", ctx->level, chunk->pos, (ctx->buffer.buf + chunk->pos), (ctx->cur - chunk->pos)); 1473 | return chunk; 1474 | L0000:; 1475 | ctx->level--; 1476 | PCC_DEBUG(ctx->auxil, PCC_DBG_NOMATCH, "c2s", ctx->level, chunk->pos, (ctx->buffer.buf + chunk->pos), (ctx->cur - chunk->pos)); 1477 | pcc_thunk_chunk__destroy(ctx, chunk); 1478 | return NULL; 1479 | } 1480 | 1481 | static pcc_thunk_chunk_t *pcc_evaluate_rule_mech(pcc_context_t *ctx) { 1482 | pcc_thunk_chunk_t *const chunk = pcc_thunk_chunk__create(ctx); 1483 | chunk->pos = ctx->cur; 1484 | PCC_DEBUG(ctx->auxil, PCC_DBG_EVALUATE, "mech", ctx->level, chunk->pos, (ctx->buffer.buf + chunk->pos), (ctx->buffer.len - chunk->pos)); 1485 | ctx->level++; 1486 | pcc_value_table__resize(ctx->auxil, &chunk->values, 0); 1487 | pcc_capture_table__resize(ctx->auxil, &chunk->capts, 1); 1488 | { 1489 | char c; 1490 | if (pcc_refill_buffer(ctx, 1) < 1) goto L0000; 1491 | c = ctx->buffer.buf[ctx->cur]; 1492 | if (!( 1493 | c == 'M' || 1494 | c == 'm' 1495 | )) goto L0000; 1496 | ctx->cur++; 1497 | } 1498 | { 1499 | char c; 1500 | if (pcc_refill_buffer(ctx, 1) < 1) goto L0000; 1501 | c = ctx->buffer.buf[ctx->cur]; 1502 | if (!( 1503 | c == 'E' || 1504 | c == 'e' 1505 | )) goto L0000; 1506 | ctx->cur++; 1507 | } 1508 | { 1509 | char c; 1510 | if (pcc_refill_buffer(ctx, 1) < 1) goto L0000; 1511 | c = ctx->buffer.buf[ctx->cur]; 1512 | if (!( 1513 | c == 'C' || 1514 | c == 'c' 1515 | )) goto L0000; 1516 | ctx->cur++; 1517 | } 1518 | { 1519 | char c; 1520 | if (pcc_refill_buffer(ctx, 1) < 1) goto L0000; 1521 | c = ctx->buffer.buf[ctx->cur]; 1522 | if (!( 1523 | c == 'H' || 1524 | c == 'h' 1525 | )) goto L0000; 1526 | ctx->cur++; 1527 | } 1528 | if (!pcc_apply_rule(ctx, pcc_evaluate_rule__, &chunk->thunks, NULL)) goto L0000; 1529 | if ( 1530 | pcc_refill_buffer(ctx, 1) < 1 || 1531 | ctx->buffer.buf[ctx->cur] != '=' 1532 | ) goto L0000; 1533 | ctx->cur++; 1534 | if (!pcc_apply_rule(ctx, pcc_evaluate_rule__, &chunk->thunks, NULL)) goto L0000; 1535 | if ( 1536 | pcc_refill_buffer(ctx, 1) < 1 || 1537 | ctx->buffer.buf[ctx->cur] != '\"' 1538 | ) goto L0000; 1539 | ctx->cur++; 1540 | { 1541 | const size_t p = ctx->cur; 1542 | size_t q; 1543 | if (!pcc_apply_rule(ctx, pcc_evaluate_rule_mechstring, &chunk->thunks, NULL)) goto L0000; 1544 | q = ctx->cur; 1545 | chunk->capts.buf[0].range.start = p; 1546 | chunk->capts.buf[0].range.end = q; 1547 | } 1548 | if ( 1549 | pcc_refill_buffer(ctx, 1) < 1 || 1550 | ctx->buffer.buf[ctx->cur] != '\"' 1551 | ) goto L0000; 1552 | ctx->cur++; 1553 | { 1554 | pcc_thunk_t *const thunk = pcc_thunk__create_leaf(ctx->auxil, pcc_action_mech_0, 0, 1); 1555 | thunk->data.leaf.capts.buf[0] = &(chunk->capts.buf[0]); 1556 | thunk->data.leaf.capt0.range.start = chunk->pos; 1557 | thunk->data.leaf.capt0.range.end = ctx->cur; 1558 | pcc_thunk_array__add(ctx->auxil, &chunk->thunks, thunk); 1559 | } 1560 | ctx->level--; 1561 | PCC_DEBUG(ctx->auxil, PCC_DBG_MATCH, "mech", ctx->level, chunk->pos, (ctx->buffer.buf + chunk->pos), (ctx->cur - chunk->pos)); 1562 | return chunk; 1563 | L0000:; 1564 | ctx->level--; 1565 | PCC_DEBUG(ctx->auxil, PCC_DBG_NOMATCH, "mech", ctx->level, chunk->pos, (ctx->buffer.buf + chunk->pos), (ctx->cur - chunk->pos)); 1566 | pcc_thunk_chunk__destroy(ctx, chunk); 1567 | return NULL; 1568 | } 1569 | 1570 | static pcc_thunk_chunk_t *pcc_evaluate_rule_realm(pcc_context_t *ctx) { 1571 | pcc_thunk_chunk_t *const chunk = pcc_thunk_chunk__create(ctx); 1572 | chunk->pos = ctx->cur; 1573 | PCC_DEBUG(ctx->auxil, PCC_DBG_EVALUATE, "realm", ctx->level, chunk->pos, (ctx->buffer.buf + chunk->pos), (ctx->buffer.len - chunk->pos)); 1574 | ctx->level++; 1575 | pcc_value_table__resize(ctx->auxil, &chunk->values, 0); 1576 | pcc_capture_table__resize(ctx->auxil, &chunk->capts, 1); 1577 | { 1578 | char c; 1579 | if (pcc_refill_buffer(ctx, 1) < 1) goto L0000; 1580 | c = ctx->buffer.buf[ctx->cur]; 1581 | if (!( 1582 | c == 'R' || 1583 | c == 'r' 1584 | )) goto L0000; 1585 | ctx->cur++; 1586 | } 1587 | { 1588 | char c; 1589 | if (pcc_refill_buffer(ctx, 1) < 1) goto L0000; 1590 | c = ctx->buffer.buf[ctx->cur]; 1591 | if (!( 1592 | c == 'E' || 1593 | c == 'e' 1594 | )) goto L0000; 1595 | ctx->cur++; 1596 | } 1597 | { 1598 | char c; 1599 | if (pcc_refill_buffer(ctx, 1) < 1) goto L0000; 1600 | c = ctx->buffer.buf[ctx->cur]; 1601 | if (!( 1602 | c == 'A' || 1603 | c == 'a' 1604 | )) goto L0000; 1605 | ctx->cur++; 1606 | } 1607 | { 1608 | char c; 1609 | if (pcc_refill_buffer(ctx, 1) < 1) goto L0000; 1610 | c = ctx->buffer.buf[ctx->cur]; 1611 | if (!( 1612 | c == 'L' || 1613 | c == 'l' 1614 | )) goto L0000; 1615 | ctx->cur++; 1616 | } 1617 | { 1618 | char c; 1619 | if (pcc_refill_buffer(ctx, 1) < 1) goto L0000; 1620 | c = ctx->buffer.buf[ctx->cur]; 1621 | if (!( 1622 | c == 'M' || 1623 | c == 'm' 1624 | )) goto L0000; 1625 | ctx->cur++; 1626 | } 1627 | if (!pcc_apply_rule(ctx, pcc_evaluate_rule__, &chunk->thunks, NULL)) goto L0000; 1628 | if ( 1629 | pcc_refill_buffer(ctx, 1) < 1 || 1630 | ctx->buffer.buf[ctx->cur] != '=' 1631 | ) goto L0000; 1632 | ctx->cur++; 1633 | if (!pcc_apply_rule(ctx, pcc_evaluate_rule__, &chunk->thunks, NULL)) goto L0000; 1634 | if ( 1635 | pcc_refill_buffer(ctx, 1) < 1 || 1636 | ctx->buffer.buf[ctx->cur] != '\"' 1637 | ) goto L0000; 1638 | ctx->cur++; 1639 | { 1640 | const size_t p = ctx->cur; 1641 | size_t q; 1642 | if (!pcc_apply_rule(ctx, pcc_evaluate_rule_realmstring, &chunk->thunks, NULL)) goto L0000; 1643 | q = ctx->cur; 1644 | chunk->capts.buf[0].range.start = p; 1645 | chunk->capts.buf[0].range.end = q; 1646 | } 1647 | if ( 1648 | pcc_refill_buffer(ctx, 1) < 1 || 1649 | ctx->buffer.buf[ctx->cur] != '\"' 1650 | ) goto L0000; 1651 | ctx->cur++; 1652 | { 1653 | pcc_thunk_t *const thunk = pcc_thunk__create_leaf(ctx->auxil, pcc_action_realm_0, 0, 1); 1654 | thunk->data.leaf.capts.buf[0] = &(chunk->capts.buf[0]); 1655 | thunk->data.leaf.capt0.range.start = chunk->pos; 1656 | thunk->data.leaf.capt0.range.end = ctx->cur; 1657 | pcc_thunk_array__add(ctx->auxil, &chunk->thunks, thunk); 1658 | } 1659 | ctx->level--; 1660 | PCC_DEBUG(ctx->auxil, PCC_DBG_MATCH, "realm", ctx->level, chunk->pos, (ctx->buffer.buf + chunk->pos), (ctx->cur - chunk->pos)); 1661 | return chunk; 1662 | L0000:; 1663 | ctx->level--; 1664 | PCC_DEBUG(ctx->auxil, PCC_DBG_NOMATCH, "realm", ctx->level, chunk->pos, (ctx->buffer.buf + chunk->pos), (ctx->cur - chunk->pos)); 1665 | pcc_thunk_chunk__destroy(ctx, chunk); 1666 | return NULL; 1667 | } 1668 | 1669 | static pcc_thunk_chunk_t *pcc_evaluate_rule_realmstring(pcc_context_t *ctx) { 1670 | pcc_thunk_chunk_t *const chunk = pcc_thunk_chunk__create(ctx); 1671 | chunk->pos = ctx->cur; 1672 | PCC_DEBUG(ctx->auxil, PCC_DBG_EVALUATE, "realmstring", ctx->level, chunk->pos, (ctx->buffer.buf + chunk->pos), (ctx->buffer.len - chunk->pos)); 1673 | ctx->level++; 1674 | pcc_value_table__resize(ctx->auxil, &chunk->values, 0); 1675 | pcc_capture_table__resize(ctx->auxil, &chunk->capts, 0); 1676 | { 1677 | int i; 1678 | for (i = 0;; i++) { 1679 | const size_t p = ctx->cur; 1680 | const size_t n = chunk->thunks.len; 1681 | { 1682 | char c; 1683 | if (pcc_refill_buffer(ctx, 1) < 1) goto L0001; 1684 | c = ctx->buffer.buf[ctx->cur]; 1685 | if ( 1686 | c == '\"' || 1687 | c == '\\' 1688 | ) goto L0001; 1689 | ctx->cur++; 1690 | } 1691 | if (ctx->cur == p) break; 1692 | continue; 1693 | L0001:; 1694 | ctx->cur = p; 1695 | pcc_thunk_array__revert(ctx->auxil, &chunk->thunks, n); 1696 | break; 1697 | } 1698 | } 1699 | ctx->level--; 1700 | PCC_DEBUG(ctx->auxil, PCC_DBG_MATCH, "realmstring", ctx->level, chunk->pos, (ctx->buffer.buf + chunk->pos), (ctx->cur - chunk->pos)); 1701 | return chunk; 1702 | } 1703 | 1704 | static pcc_thunk_chunk_t *pcc_evaluate_rule_mechstring(pcc_context_t *ctx) { 1705 | pcc_thunk_chunk_t *const chunk = pcc_thunk_chunk__create(ctx); 1706 | chunk->pos = ctx->cur; 1707 | PCC_DEBUG(ctx->auxil, PCC_DBG_EVALUATE, "mechstring", ctx->level, chunk->pos, (ctx->buffer.buf + chunk->pos), (ctx->buffer.len - chunk->pos)); 1708 | ctx->level++; 1709 | pcc_value_table__resize(ctx->auxil, &chunk->values, 0); 1710 | pcc_capture_table__resize(ctx->auxil, &chunk->capts, 0); 1711 | { 1712 | char c; 1713 | if (pcc_refill_buffer(ctx, 1) < 1) goto L0000; 1714 | c = ctx->buffer.buf[ctx->cur]; 1715 | if (!( 1716 | (c >= 'A' && c <= 'Z') || 1717 | (c >= '0' && c <= '9') || 1718 | c == '-' || 1719 | c == '_' 1720 | )) goto L0000; 1721 | ctx->cur++; 1722 | } 1723 | { 1724 | const size_t p = ctx->cur; 1725 | const size_t n = chunk->thunks.len; 1726 | { 1727 | char c; 1728 | if (pcc_refill_buffer(ctx, 1) < 1) goto L0001; 1729 | c = ctx->buffer.buf[ctx->cur]; 1730 | if (!( 1731 | (c >= 'A' && c <= 'Z') || 1732 | (c >= '0' && c <= '9') || 1733 | c == '-' || 1734 | c == '_' 1735 | )) goto L0001; 1736 | ctx->cur++; 1737 | } 1738 | goto L0002; 1739 | L0001:; 1740 | ctx->cur = p; 1741 | pcc_thunk_array__revert(ctx->auxil, &chunk->thunks, n); 1742 | L0002:; 1743 | } 1744 | { 1745 | const size_t p = ctx->cur; 1746 | const size_t n = chunk->thunks.len; 1747 | { 1748 | char c; 1749 | if (pcc_refill_buffer(ctx, 1) < 1) goto L0003; 1750 | c = ctx->buffer.buf[ctx->cur]; 1751 | if (!( 1752 | (c >= 'A' && c <= 'Z') || 1753 | (c >= '0' && c <= '9') || 1754 | c == '-' || 1755 | c == '_' 1756 | )) goto L0003; 1757 | ctx->cur++; 1758 | } 1759 | goto L0004; 1760 | L0003:; 1761 | ctx->cur = p; 1762 | pcc_thunk_array__revert(ctx->auxil, &chunk->thunks, n); 1763 | L0004:; 1764 | } 1765 | { 1766 | const size_t p = ctx->cur; 1767 | const size_t n = chunk->thunks.len; 1768 | { 1769 | char c; 1770 | if (pcc_refill_buffer(ctx, 1) < 1) goto L0005; 1771 | c = ctx->buffer.buf[ctx->cur]; 1772 | if (!( 1773 | (c >= 'A' && c <= 'Z') || 1774 | (c >= '0' && c <= '9') || 1775 | c == '-' || 1776 | c == '_' 1777 | )) goto L0005; 1778 | ctx->cur++; 1779 | } 1780 | goto L0006; 1781 | L0005:; 1782 | ctx->cur = p; 1783 | pcc_thunk_array__revert(ctx->auxil, &chunk->thunks, n); 1784 | L0006:; 1785 | } 1786 | { 1787 | const size_t p = ctx->cur; 1788 | const size_t n = chunk->thunks.len; 1789 | { 1790 | char c; 1791 | if (pcc_refill_buffer(ctx, 1) < 1) goto L0007; 1792 | c = ctx->buffer.buf[ctx->cur]; 1793 | if (!( 1794 | (c >= 'A' && c <= 'Z') || 1795 | (c >= '0' && c <= '9') || 1796 | c == '-' || 1797 | c == '_' 1798 | )) goto L0007; 1799 | ctx->cur++; 1800 | } 1801 | goto L0008; 1802 | L0007:; 1803 | ctx->cur = p; 1804 | pcc_thunk_array__revert(ctx->auxil, &chunk->thunks, n); 1805 | L0008:; 1806 | } 1807 | { 1808 | const size_t p = ctx->cur; 1809 | const size_t n = chunk->thunks.len; 1810 | { 1811 | char c; 1812 | if (pcc_refill_buffer(ctx, 1) < 1) goto L0009; 1813 | c = ctx->buffer.buf[ctx->cur]; 1814 | if (!( 1815 | (c >= 'A' && c <= 'Z') || 1816 | (c >= '0' && c <= '9') || 1817 | c == '-' || 1818 | c == '_' 1819 | )) goto L0009; 1820 | ctx->cur++; 1821 | } 1822 | goto L0010; 1823 | L0009:; 1824 | ctx->cur = p; 1825 | pcc_thunk_array__revert(ctx->auxil, &chunk->thunks, n); 1826 | L0010:; 1827 | } 1828 | { 1829 | const size_t p = ctx->cur; 1830 | const size_t n = chunk->thunks.len; 1831 | { 1832 | char c; 1833 | if (pcc_refill_buffer(ctx, 1) < 1) goto L0011; 1834 | c = ctx->buffer.buf[ctx->cur]; 1835 | if (!( 1836 | (c >= 'A' && c <= 'Z') || 1837 | (c >= '0' && c <= '9') || 1838 | c == '-' || 1839 | c == '_' 1840 | )) goto L0011; 1841 | ctx->cur++; 1842 | } 1843 | goto L0012; 1844 | L0011:; 1845 | ctx->cur = p; 1846 | pcc_thunk_array__revert(ctx->auxil, &chunk->thunks, n); 1847 | L0012:; 1848 | } 1849 | { 1850 | const size_t p = ctx->cur; 1851 | const size_t n = chunk->thunks.len; 1852 | { 1853 | char c; 1854 | if (pcc_refill_buffer(ctx, 1) < 1) goto L0013; 1855 | c = ctx->buffer.buf[ctx->cur]; 1856 | if (!( 1857 | (c >= 'A' && c <= 'Z') || 1858 | (c >= '0' && c <= '9') || 1859 | c == '-' || 1860 | c == '_' 1861 | )) goto L0013; 1862 | ctx->cur++; 1863 | } 1864 | goto L0014; 1865 | L0013:; 1866 | ctx->cur = p; 1867 | pcc_thunk_array__revert(ctx->auxil, &chunk->thunks, n); 1868 | L0014:; 1869 | } 1870 | { 1871 | const size_t p = ctx->cur; 1872 | const size_t n = chunk->thunks.len; 1873 | { 1874 | char c; 1875 | if (pcc_refill_buffer(ctx, 1) < 1) goto L0015; 1876 | c = ctx->buffer.buf[ctx->cur]; 1877 | if (!( 1878 | (c >= 'A' && c <= 'Z') || 1879 | (c >= '0' && c <= '9') || 1880 | c == '-' || 1881 | c == '_' 1882 | )) goto L0015; 1883 | ctx->cur++; 1884 | } 1885 | goto L0016; 1886 | L0015:; 1887 | ctx->cur = p; 1888 | pcc_thunk_array__revert(ctx->auxil, &chunk->thunks, n); 1889 | L0016:; 1890 | } 1891 | { 1892 | const size_t p = ctx->cur; 1893 | const size_t n = chunk->thunks.len; 1894 | { 1895 | char c; 1896 | if (pcc_refill_buffer(ctx, 1) < 1) goto L0017; 1897 | c = ctx->buffer.buf[ctx->cur]; 1898 | if (!( 1899 | (c >= 'A' && c <= 'Z') || 1900 | (c >= '0' && c <= '9') || 1901 | c == '-' || 1902 | c == '_' 1903 | )) goto L0017; 1904 | ctx->cur++; 1905 | } 1906 | goto L0018; 1907 | L0017:; 1908 | ctx->cur = p; 1909 | pcc_thunk_array__revert(ctx->auxil, &chunk->thunks, n); 1910 | L0018:; 1911 | } 1912 | { 1913 | const size_t p = ctx->cur; 1914 | const size_t n = chunk->thunks.len; 1915 | { 1916 | char c; 1917 | if (pcc_refill_buffer(ctx, 1) < 1) goto L0019; 1918 | c = ctx->buffer.buf[ctx->cur]; 1919 | if (!( 1920 | (c >= 'A' && c <= 'Z') || 1921 | (c >= '0' && c <= '9') || 1922 | c == '-' || 1923 | c == '_' 1924 | )) goto L0019; 1925 | ctx->cur++; 1926 | } 1927 | goto L0020; 1928 | L0019:; 1929 | ctx->cur = p; 1930 | pcc_thunk_array__revert(ctx->auxil, &chunk->thunks, n); 1931 | L0020:; 1932 | } 1933 | { 1934 | const size_t p = ctx->cur; 1935 | const size_t n = chunk->thunks.len; 1936 | { 1937 | char c; 1938 | if (pcc_refill_buffer(ctx, 1) < 1) goto L0021; 1939 | c = ctx->buffer.buf[ctx->cur]; 1940 | if (!( 1941 | (c >= 'A' && c <= 'Z') || 1942 | (c >= '0' && c <= '9') || 1943 | c == '-' || 1944 | c == '_' 1945 | )) goto L0021; 1946 | ctx->cur++; 1947 | } 1948 | goto L0022; 1949 | L0021:; 1950 | ctx->cur = p; 1951 | pcc_thunk_array__revert(ctx->auxil, &chunk->thunks, n); 1952 | L0022:; 1953 | } 1954 | { 1955 | const size_t p = ctx->cur; 1956 | const size_t n = chunk->thunks.len; 1957 | { 1958 | char c; 1959 | if (pcc_refill_buffer(ctx, 1) < 1) goto L0023; 1960 | c = ctx->buffer.buf[ctx->cur]; 1961 | if (!( 1962 | (c >= 'A' && c <= 'Z') || 1963 | (c >= '0' && c <= '9') || 1964 | c == '-' || 1965 | c == '_' 1966 | )) goto L0023; 1967 | ctx->cur++; 1968 | } 1969 | goto L0024; 1970 | L0023:; 1971 | ctx->cur = p; 1972 | pcc_thunk_array__revert(ctx->auxil, &chunk->thunks, n); 1973 | L0024:; 1974 | } 1975 | { 1976 | const size_t p = ctx->cur; 1977 | const size_t n = chunk->thunks.len; 1978 | { 1979 | char c; 1980 | if (pcc_refill_buffer(ctx, 1) < 1) goto L0025; 1981 | c = ctx->buffer.buf[ctx->cur]; 1982 | if (!( 1983 | (c >= 'A' && c <= 'Z') || 1984 | (c >= '0' && c <= '9') || 1985 | c == '-' || 1986 | c == '_' 1987 | )) goto L0025; 1988 | ctx->cur++; 1989 | } 1990 | goto L0026; 1991 | L0025:; 1992 | ctx->cur = p; 1993 | pcc_thunk_array__revert(ctx->auxil, &chunk->thunks, n); 1994 | L0026:; 1995 | } 1996 | { 1997 | const size_t p = ctx->cur; 1998 | const size_t n = chunk->thunks.len; 1999 | { 2000 | char c; 2001 | if (pcc_refill_buffer(ctx, 1) < 1) goto L0027; 2002 | c = ctx->buffer.buf[ctx->cur]; 2003 | if (!( 2004 | (c >= 'A' && c <= 'Z') || 2005 | (c >= '0' && c <= '9') || 2006 | c == '-' || 2007 | c == '_' 2008 | )) goto L0027; 2009 | ctx->cur++; 2010 | } 2011 | goto L0028; 2012 | L0027:; 2013 | ctx->cur = p; 2014 | pcc_thunk_array__revert(ctx->auxil, &chunk->thunks, n); 2015 | L0028:; 2016 | } 2017 | { 2018 | const size_t p = ctx->cur; 2019 | const size_t n = chunk->thunks.len; 2020 | { 2021 | char c; 2022 | if (pcc_refill_buffer(ctx, 1) < 1) goto L0029; 2023 | c = ctx->buffer.buf[ctx->cur]; 2024 | if (!( 2025 | (c >= 'A' && c <= 'Z') || 2026 | (c >= '0' && c <= '9') || 2027 | c == '-' || 2028 | c == '_' 2029 | )) goto L0029; 2030 | ctx->cur++; 2031 | } 2032 | goto L0030; 2033 | L0029:; 2034 | ctx->cur = p; 2035 | pcc_thunk_array__revert(ctx->auxil, &chunk->thunks, n); 2036 | L0030:; 2037 | } 2038 | { 2039 | const size_t p = ctx->cur; 2040 | const size_t n = chunk->thunks.len; 2041 | { 2042 | char c; 2043 | if (pcc_refill_buffer(ctx, 1) < 1) goto L0031; 2044 | c = ctx->buffer.buf[ctx->cur]; 2045 | if (!( 2046 | (c >= 'A' && c <= 'Z') || 2047 | (c >= '0' && c <= '9') || 2048 | c == '-' || 2049 | c == '_' 2050 | )) goto L0031; 2051 | ctx->cur++; 2052 | } 2053 | goto L0032; 2054 | L0031:; 2055 | ctx->cur = p; 2056 | pcc_thunk_array__revert(ctx->auxil, &chunk->thunks, n); 2057 | L0032:; 2058 | } 2059 | { 2060 | const size_t p = ctx->cur; 2061 | const size_t n = chunk->thunks.len; 2062 | { 2063 | char c; 2064 | if (pcc_refill_buffer(ctx, 1) < 1) goto L0033; 2065 | c = ctx->buffer.buf[ctx->cur]; 2066 | if (!( 2067 | (c >= 'A' && c <= 'Z') || 2068 | (c >= '0' && c <= '9') || 2069 | c == '-' || 2070 | c == '_' 2071 | )) goto L0033; 2072 | ctx->cur++; 2073 | } 2074 | goto L0034; 2075 | L0033:; 2076 | ctx->cur = p; 2077 | pcc_thunk_array__revert(ctx->auxil, &chunk->thunks, n); 2078 | L0034:; 2079 | } 2080 | { 2081 | const size_t p = ctx->cur; 2082 | const size_t n = chunk->thunks.len; 2083 | { 2084 | char c; 2085 | if (pcc_refill_buffer(ctx, 1) < 1) goto L0035; 2086 | c = ctx->buffer.buf[ctx->cur]; 2087 | if (!( 2088 | (c >= 'A' && c <= 'Z') || 2089 | (c >= '0' && c <= '9') || 2090 | c == '-' || 2091 | c == '_' 2092 | )) goto L0035; 2093 | ctx->cur++; 2094 | } 2095 | goto L0036; 2096 | L0035:; 2097 | ctx->cur = p; 2098 | pcc_thunk_array__revert(ctx->auxil, &chunk->thunks, n); 2099 | L0036:; 2100 | } 2101 | { 2102 | const size_t p = ctx->cur; 2103 | const size_t n = chunk->thunks.len; 2104 | { 2105 | char c; 2106 | if (pcc_refill_buffer(ctx, 1) < 1) goto L0037; 2107 | c = ctx->buffer.buf[ctx->cur]; 2108 | if (!( 2109 | (c >= 'A' && c <= 'Z') || 2110 | (c >= '0' && c <= '9') || 2111 | c == '-' || 2112 | c == '_' 2113 | )) goto L0037; 2114 | ctx->cur++; 2115 | } 2116 | goto L0038; 2117 | L0037:; 2118 | ctx->cur = p; 2119 | pcc_thunk_array__revert(ctx->auxil, &chunk->thunks, n); 2120 | L0038:; 2121 | } 2122 | ctx->level--; 2123 | PCC_DEBUG(ctx->auxil, PCC_DBG_MATCH, "mechstring", ctx->level, chunk->pos, (ctx->buffer.buf + chunk->pos), (ctx->cur - chunk->pos)); 2124 | return chunk; 2125 | L0000:; 2126 | ctx->level--; 2127 | PCC_DEBUG(ctx->auxil, PCC_DBG_NOMATCH, "mechstring", ctx->level, chunk->pos, (ctx->buffer.buf + chunk->pos), (ctx->cur - chunk->pos)); 2128 | pcc_thunk_chunk__destroy(ctx, chunk); 2129 | return NULL; 2130 | } 2131 | 2132 | static pcc_thunk_chunk_t *pcc_evaluate_rule_base64string(pcc_context_t *ctx) { 2133 | pcc_thunk_chunk_t *const chunk = pcc_thunk_chunk__create(ctx); 2134 | chunk->pos = ctx->cur; 2135 | PCC_DEBUG(ctx->auxil, PCC_DBG_EVALUATE, "base64string", ctx->level, chunk->pos, (ctx->buffer.buf + chunk->pos), (ctx->buffer.len - chunk->pos)); 2136 | ctx->level++; 2137 | pcc_value_table__resize(ctx->auxil, &chunk->values, 0); 2138 | pcc_capture_table__resize(ctx->auxil, &chunk->capts, 0); 2139 | { 2140 | int i; 2141 | for (i = 0;; i++) { 2142 | const size_t p = ctx->cur; 2143 | const size_t n = chunk->thunks.len; 2144 | { 2145 | char c; 2146 | if (pcc_refill_buffer(ctx, 1) < 1) goto L0001; 2147 | c = ctx->buffer.buf[ctx->cur]; 2148 | if (!( 2149 | (c >= 'a' && c <= 'z') || 2150 | (c >= 'A' && c <= 'Z') || 2151 | (c >= '0' && c <= '9') || 2152 | c == '-' || 2153 | c == '.' || 2154 | c == '_' || 2155 | c == '~' || 2156 | c == '+' || 2157 | c == '/' 2158 | )) goto L0001; 2159 | ctx->cur++; 2160 | } 2161 | if (ctx->cur == p) break; 2162 | continue; 2163 | L0001:; 2164 | ctx->cur = p; 2165 | pcc_thunk_array__revert(ctx->auxil, &chunk->thunks, n); 2166 | break; 2167 | } 2168 | } 2169 | { 2170 | int i; 2171 | for (i = 0;; i++) { 2172 | const size_t p = ctx->cur; 2173 | const size_t n = chunk->thunks.len; 2174 | if ( 2175 | pcc_refill_buffer(ctx, 1) < 1 || 2176 | ctx->buffer.buf[ctx->cur] != '=' 2177 | ) goto L0002; 2178 | ctx->cur++; 2179 | if (ctx->cur == p) break; 2180 | continue; 2181 | L0002:; 2182 | ctx->cur = p; 2183 | pcc_thunk_array__revert(ctx->auxil, &chunk->thunks, n); 2184 | break; 2185 | } 2186 | } 2187 | ctx->level--; 2188 | PCC_DEBUG(ctx->auxil, PCC_DBG_MATCH, "base64string", ctx->level, chunk->pos, (ctx->buffer.buf + chunk->pos), (ctx->cur - chunk->pos)); 2189 | return chunk; 2190 | } 2191 | 2192 | static pcc_thunk_chunk_t *pcc_evaluate_rule__(pcc_context_t *ctx) { 2193 | pcc_thunk_chunk_t *const chunk = pcc_thunk_chunk__create(ctx); 2194 | chunk->pos = ctx->cur; 2195 | PCC_DEBUG(ctx->auxil, PCC_DBG_EVALUATE, "_", ctx->level, chunk->pos, (ctx->buffer.buf + chunk->pos), (ctx->buffer.len - chunk->pos)); 2196 | ctx->level++; 2197 | pcc_value_table__resize(ctx->auxil, &chunk->values, 0); 2198 | pcc_capture_table__resize(ctx->auxil, &chunk->capts, 0); 2199 | { 2200 | int i; 2201 | for (i = 0;; i++) { 2202 | const size_t p = ctx->cur; 2203 | const size_t n = chunk->thunks.len; 2204 | { 2205 | char c; 2206 | if (pcc_refill_buffer(ctx, 1) < 1) goto L0001; 2207 | c = ctx->buffer.buf[ctx->cur]; 2208 | if (!( 2209 | c == ' ' || 2210 | c == '\t' 2211 | )) goto L0001; 2212 | ctx->cur++; 2213 | } 2214 | if (ctx->cur == p) break; 2215 | continue; 2216 | L0001:; 2217 | ctx->cur = p; 2218 | pcc_thunk_array__revert(ctx->auxil, &chunk->thunks, n); 2219 | break; 2220 | } 2221 | } 2222 | ctx->level--; 2223 | PCC_DEBUG(ctx->auxil, PCC_DBG_MATCH, "_", ctx->level, chunk->pos, (ctx->buffer.buf + chunk->pos), (ctx->cur - chunk->pos)); 2224 | return chunk; 2225 | } 2226 | 2227 | sasl_header_context_t *sasl_header_create(sasl_header_fields_t*auxil) { 2228 | return pcc_context__create(auxil); 2229 | } 2230 | 2231 | int sasl_header_parse(sasl_header_context_t *ctx, int *ret) { 2232 | if (pcc_apply_rule(ctx, pcc_evaluate_rule_header, &ctx->thunks, ret)) 2233 | pcc_do_action(ctx, &ctx->thunks, ret); 2234 | else 2235 | PCC_ERROR(ctx->auxil); 2236 | pcc_commit_buffer(ctx); 2237 | pcc_thunk_array__revert(ctx->auxil, &ctx->thunks, 0); 2238 | return pcc_refill_buffer(ctx, 1) >= 1; 2239 | } 2240 | 2241 | void sasl_header_destroy(sasl_header_context_t *ctx) { 2242 | pcc_context__destroy(ctx); 2243 | } 2244 | 2245 | #line 69 "http_auth_header_parser.peg" 2246 | 2247 | void parse_header(sasl_header_fields_t *auxil, const unsigned char* header, const size_t header_len) { 2248 | auxil->input = (const char*) header; 2249 | auxil->input_len = header_len; 2250 | sasl_header_context_t *ctx = sasl_header_create(auxil); 2251 | while (sasl_header_parse(ctx, NULL)); 2252 | sasl_header_destroy(ctx); 2253 | } 2254 | 2255 | #ifdef TEST 2256 | int main(void) { 2257 | sasl_header_fields_t parsed={0}; 2258 | const char header[]="SASL c2s=\"vqIkiXo9hh740PGdOKSXYkNIfPNwQxx028LBjVVxHRcAAQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eH2iFbpPZ0yQ051VgeZtfYS2Tsam8EryENhhSfagov994cwBzAA==\",realm=\"localhost\",mech=\"OPAQUE\""; 2259 | parse_header(&parsed, header, strlen(header)); 2260 | 2261 | if(parsed.mech) printf("mech: %s\n", parsed.mech); 2262 | if(parsed.realm) printf("realm: %s\n", parsed.realm); 2263 | if(parsed.s2s) printf("s2s: %ld\n", parsed.s2s); 2264 | if(parsed.s2c) printf("s2c: %s\n", parsed.s2c); 2265 | if(parsed.c2s) printf("c2s: %s\n", parsed.c2s); 2266 | 2267 | return 0; 2268 | } 2269 | #endif --------------------------------------------------------------------------------