UNIXworkcode

1 /* 2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. 3 * 4 * Copyright 2026 Olaf Wintermann. All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions are met: 8 * 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 #include "sab.h" 30 31 #include "../../util/util.h" 32 #include "../../util/pblock.h" 33 34 35 int rq_match(pblock *pb, const pb_key *param, Request *rq, const char *match, const char *notmatch, int *error) { 36 if(error) { 37 *error = 0; 38 } 39 40 if(!match && !notmatch) { 41 return 1; 42 } 43 44 char *str = pblock_findkeyval(param, rq->reqpb); 45 if(!str) { 46 str = ""; 47 } 48 49 int ret = 0; 50 if(match) { 51 regex_t regex; 52 if(regcomp(&regex, match, REG_EXTENDED)) { 53 log_ereport(LOG_MISCONFIG, "sab: cannot compile regex pattern %s", match); 54 if(error) { 55 *error = 1; 56 } 57 return 0; 58 } 59 60 regmatch_t rm; 61 if(regexec(&regex, str, 1, &rm, 0) == 0) { 62 ret = 1; 63 } 64 65 regfree(&regex); 66 } else { 67 ret = 1; 68 } 69 70 71 if(notmatch) { 72 regex_t regex; 73 if(regcomp(&regex, notmatch, REG_EXTENDED)) { 74 log_ereport(LOG_MISCONFIG, "sab: cannot compile regex pattern %s", match); 75 if(error) { 76 *error = 1; 77 } 78 return 0; 79 } 80 81 regmatch_t rm; 82 if(regexec(&regex, str, 1, &rm, 0) == 0) { 83 ret = 0; 84 } 85 86 regfree(&regex); 87 } 88 89 return ret; 90 } 91 92 int sab_url_match(pblock *pb, Request *rq, int *error) { 93 char *match = pblock_findval("match", pb); 94 char *notmatch = pblock_findval("notmatch", pb); 95 return rq_match(pb, pb_key_uri, rq, match, notmatch, error); 96 } 97 98 int sab_query_match(pblock *pb, Request *rq, int *error) { 99 char *match = pblock_findval("query_match", pb); 100 char *notmatch = pblock_findval("query_notmatch", pb); 101 return rq_match(pb, pb_key_query, rq, match, notmatch, error); 102 } 103 104 // Simple detection based on a dumb cookie. If not it adds 105 // is-bot to rq->vars. 106 // 107 // Args: 108 // cookie: cookie name 109 // value: cookie value (optional) 110 // match: only apply this check if the request url matches this regex 111 // notmatch: the url should also not match this pattern 112 // query_match: only apply this check if the request query matches this regex 113 // query_notmatch: the query should also not match this pattern 114 // 115 int sab_has_cookie(pblock *pb, Session *sn, Request *rq) { 116 int error; 117 int match = sab_url_match(pb, rq, &error); 118 if(!match) { 119 return error ? REQ_ABORTED : REQ_NOACTION; 120 } 121 match = sab_query_match(pb, rq, &error); 122 if(!match) { 123 return error ? REQ_ABORTED : REQ_NOACTION; 124 } 125 126 char *cookie_name = pblock_findval("cookie", pb); 127 char *cookie_value = pblock_findval("value", pb); 128 if(!cookie_name) { 129 log_ereport(LOG_MISCONFIG, "sab-has-cookie: no cookie specified"); 130 return REQ_ABORTED; 131 } 132 133 WSBool has_cookie = FALSE; 134 char *cookie = pblock_findkeyval(pb_key_cookie, rq->headers); 135 if(cookie) { 136 char *value = util_cookie_find(cookie, cookie_name); 137 if(value) { 138 if(cookie_value) { 139 has_cookie = !strcmp(cookie_value, value); 140 } else { 141 has_cookie = TRUE; 142 } 143 } 144 } 145 146 if(!has_cookie) { 147 pblock_nvinsert("is-bot", "1", rq->vars); 148 } 149 150 return REQ_NOACTION; 151 } 152