diff --git a/services/url_check/Makefile.am b/services/url_check/Makefile.am index 9cf7ded..e624b89 100644 --- a/services/url_check/Makefile.am +++ b/services/url_check/Makefile.am @@ -9,9 +9,9 @@ do_subst=sed -e 's%[@]SYSCONFDIR[@]%$(CONFIGDIR)%g' \ -e 's%[@]PACKAGE_STRING[@]%$(PACKAGE_STRING)%g' srv_url_check_la_LIBADD = @MODULES_LIBADD@ -srv_url_check_la_CFLAGS= +srv_url_check_la_CFLAGS= srv_url_check_la_LDFLAGS= -module -avoid-version -srv_url_check_la_SOURCES = srv_url_check.c url_check_body.c request_filter.c +srv_url_check_la_SOURCES = srv_url_check.c url_check_body.c request_filter.c htmlencode.c manpages = c-icap-mods-sguardDB.8 manpages_src = $(manpages:.8=.8.in) @@ -45,4 +45,4 @@ install-data-local: for f in $(TMPLS); do $(INSTALL) $(srcdir)/$$f $(DESTDIR)$(cicapdatadir)/templates/srv_url_check/en/; done -EXTRA_DIST= sguardDB.h url_check_body.h request_filter.h makefile.w32 srv_url_check.def srv_url_check.conf $(TMPLS) $(manpages_src) +EXTRA_DIST= sguardDB.h url_check_body.h request_filter.h makefile.w32 srv_url_check.def srv_url_check.conf htmlencode.h $(TMPLS) $(manpages_src) diff --git a/services/url_check/htmlencode.c b/services/url_check/htmlencode.c new file mode 100644 index 0000000..e30d946 --- /dev/null +++ b/services/url_check/htmlencode.c @@ -0,0 +1,126 @@ +/* + * Copyright (C) 2021 Shawn Michael + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include + +struct sz_string { + char *data; + size_t size; + size_t buffsz; +}; + +struct sz_string *double_sz_string(struct sz_string *output) { + void *voidbuff; + + voidbuff = realloc((void *)output->data, output->buffsz * 2); + if (voidbuff == NULL) { + perror("Error during realloc"); + free(output->data); + free(output); + return(NULL); + } + // Blank the new chunk of RAM + output->data = (char *)voidbuff; + output->buffsz *= 2; + + return(output); +} + +char *htmlspecialchars(char *input, size_t len) { + size_t offset = 0; + char *replacement; // Double duty as a temp var for constants and + // the return value. + int copysize = 1; + struct sz_string *output; + + if ((output = (struct sz_string *)malloc(sizeof(struct sz_string))) == NULL) { + perror("Error during initial malloc"); + return(NULL); + } + // Set minimum buffer size to 256 bytes. This prevents security errors + // later. This size *MUST* be larger than the replacement string size + // for characters. So if you change this it MUST be at least 6 for + // """ + // Excess here gets freed later with a realloc down to the correct size. + output->buffsz = 2 * len > 256 ? 2 * len : 256; + output->size = 0; + output->data = (char*)malloc(output->buffsz); + if (output->data == NULL) { + perror("Error during string malloc"); + free((void*) output); + return(NULL); + } + + for (offset = 0; offset < len; offset++) { + if (output->size > output->buffsz) { + if ((output = double_sz_string(output)) == NULL) { + perror("NULL found during double size"); + return(NULL); + } + } + + switch (input[offset]) { + case '&': + replacement = "&"; + copysize = 5; + break; + case '<': + replacement = "<"; + copysize = 4; + break; + case '>': + replacement = ">"; + copysize = 4; + break; + case '\'': + replacement = "'"; + copysize = 6; + break; + case '"': + replacement = """; + copysize = 6; + break; + default: + output->data[output->size++] = input[offset]; + continue; + } + + // Rest of loop only runs on a replacement being necessary. + if (output->size + copysize > output->buffsz) { + if ((output = double_sz_string(output)) == NULL) { + perror("Error during string malloc"); + return(NULL); + } + } + memcpy((void *)(output->data + output->size), replacement, copysize); + output->size += copysize; + } + + if ((replacement = realloc((void *)output->data, output->size + 1)) == NULL) { + // Unalbe to allocate null character + free(output->data); + } else { + replacement[output->size] = '\0'; + } + free(output); + return(replacement); +} + + diff --git a/services/url_check/htmlencode.h b/services/url_check/htmlencode.h new file mode 100644 index 0000000..f98efd7 --- /dev/null +++ b/services/url_check/htmlencode.h @@ -0,0 +1,20 @@ +/* + * Copyright (C) 2021 Shawn Michael + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + + +char *htmlspecialchars(char *input, int size); diff --git a/services/url_check/srv_url_check.c b/services/url_check/srv_url_check.c index aec2982..8086623 100644 --- a/services/url_check/srv_url_check.c +++ b/services/url_check/srv_url_check.c @@ -36,6 +36,7 @@ #endif #include "url_check_body.h" #include "request_filter.h" +#include "htmlencode.h" /*Structs for this module */ @@ -1859,43 +1860,98 @@ static struct url_check_action *select_action(const char *action) /* Formating table functions */ int fmt_srv_urlcheck_http_url(ci_request_t *req, char *buf, int len, const char *param) { - struct url_check_data *uc = ci_service_data(req); + struct url_check_data *uc; + int retval, pathsz; + char *uri; + + uc = ci_service_data(req); + pathsz = strnlen(uc->httpinf.url, 1024); + uri = htmlspecialchars(uc->httpinf.url, pathsz); /*Do notwrite more than 512 bytes*/ - return snprintf(buf, (len < 512? len:512), "%s://%s", protos[uc->httpinf.proto], uc->httpinf.url); + retval = snprintf(buf, (len < 512? len:512), "%s://%s", protos[uc->httpinf.proto], uri); + if (uri) + free(uri); + return retval; } int fmt_srv_urlcheck_host(ci_request_t *req, char *buf, int len, const char *param) { - struct url_check_data *uc = ci_service_data(req); - return snprintf(buf, len, "%s", uc->httpinf.host); + struct url_check_data *uc; + char *host; + int retval, strsz; + + uc = ci_service_data(req); + strsz = strnlen(uc->httpinf.host, 1024); + host = htmlspecialchars(uc->httpinf.host, strsz); + retval = snprintf(buf, len, "%s", host); + if (host) + free(host); + return retval; } int fmt_srv_urlcheck_matched_dbs(ci_request_t *req, char *buf, int len, const char *param) { - struct url_check_data *uc = ci_service_data(req); - return snprintf(buf, len, "%s", uc->match_info.matched_dbs); + struct url_check_data *uc; + int retval, strsz; + char *dbs; + + uc = ci_service_data(req); + strsz = strnlen(uc->httpinf.host, 1024); + dbs = htmlspecialchars(uc->match_info.matched_dbs, strsz); + retval = snprintf(buf, len, "%s", dbs); + if (dbs) + free(dbs); + return retval; } int fmt_srv_urlcheck_blocked_db(ci_request_t *req, char *buf, int len, const char *param) { - struct url_check_data *uc = ci_service_data(req); + struct url_check_data *uc; + int retval, dbsz, catsz; + char *db, *cat; + + uc = ci_service_data(req); if (uc->match_info.action < 0) return 0; - if (uc->match_info.last_subcat[0] != '\0') - return snprintf(buf, len, "%s{%s}", uc->match_info.action_db, uc->match_info.last_subcat); - else - return snprintf(buf, len, "%s", uc->match_info.action_db); + + dbsz = strnlen(uc->match_info.action_db, 256); + db = htmlspecialchars(uc->match_info.action_db, dbsz); + if (uc->match_info.last_subcat[0] != '\0') { + catsz = strnlen(uc->match_info.last_subcat, 256); + cat = htmlspecialchars(uc->match_info.last_subcat, catsz); + retval = snprintf(buf, len, "%s{%s}", db, cat); + if (cat) + free(cat); + } else { + retval = snprintf(buf, len, "%s", db); + } + if (db) + free(db); + return retval; } int fmt_srv_urlcheck_blocked_db_descr(ci_request_t *req, char *buf, int len, const char *param) { struct url_check_data *uc = ci_service_data(req); + int retval, dbsz, catsz; + char *db, *cat; + if (uc->match_info.action < 0) return 0; if (uc->match_info.action_db_descr == NULL) return fmt_srv_urlcheck_blocked_db(req, buf, len, param); - if (uc->match_info.last_subcat[0] != '\0') - return snprintf(buf, len, "%s{%s}", uc->match_info.action_db_descr, uc->match_info.last_subcat); - else - return snprintf(buf, len, "%s", uc->match_info.action_db_descr); + dbsz = strnlen(uc->match_info.action_db_descr, 256); + db = htmlspecialchars(uc->match_info.action_db_descr, dbsz); + if (uc->match_info.last_subcat[0] != '\0') { + catsz = strnlen(uc->match_info.last_subcat, 256); + cat = htmlspecialchars(uc->match_info.last_subcat, catsz); + retval = snprintf(buf, len, "%s{%s}", db, cat); + if (cat) + free(cat); + } else { + retval = snprintf(buf, len, "%s", db); + } + if (db) + free(db); + return retval; }