From 2838810cd5b1589fc7323d2664032948744fa6ef Mon Sep 17 00:00:00 2001 From: rob Date: Mon, 12 Apr 2021 20:11:51 +0100 Subject: [PATCH] Add Support for ThemeSpecPath, FasCustomParametersList, FasCustomVariablesList, FasCustomImagesList Signed-off-by: rob --- src/conf.c | 150 +++++++++++++++++++++++++++++++++++++++++- src/conf.h | 138 +++++++++++++++++++++----------------- src/http_microhttpd.c | 17 +++-- src/main.c | 37 +++++++++++ 4 files changed, 275 insertions(+), 67 deletions(-) diff --git a/src/conf.c b/src/conf.c index e873435..8bd2eb1 100644 --- a/src/conf.c +++ b/src/conf.c @@ -84,6 +84,7 @@ typedef enum { oFasURL, oFasSSL, oLoginOptionEnabled, + oThemeSpecPath, oAllowLegacySplash, oUseOutdatedMHD, oUnescapeCallbackEnabled, @@ -121,7 +122,9 @@ typedef enum { oPreAuth, oWalledGardenFqdnList, oWalledGardenPortList, - oFasCustomParametersList + oFasCustomParametersList, + oFasCustomVariablesList, + oFasCustomImagesList } OpCodes; /** @internal @@ -150,6 +153,7 @@ static const struct { { "fasurl", oFasURL }, { "fasssl", oFasSSL }, { "login_option_enabled", oLoginOptionEnabled }, + { "themespec_path", oThemeSpecPath }, { "allow_legacy_splash", oAllowLegacySplash }, { "use_outdated_mhd", oUseOutdatedMHD }, { "unescape_callback_enabled", oUnescapeCallbackEnabled }, @@ -188,6 +192,8 @@ static const struct { { "walledgarden_fqdn_list", oWalledGardenFqdnList }, { "walledgarden_port_list", oWalledGardenPortList }, { "fas_custom_parameters_list", oFasCustomParametersList }, + { "fas_custom_variables_list", oFasCustomVariablesList }, + { "fas_custom_images_list", oFasCustomImagesList }, { NULL, oBadOption }, }; @@ -236,6 +242,7 @@ config_init(void) config.fas_port = DEFAULT_FASPORT; config.fas_key = safe_strdup(DEFAULT_FASKEY); config.login_option_enabled = DEFAULT_LOGIN_OPTION_ENABLED; + config.themespec_path = NULL; config.allow_legacy_splash = DEFAULT_ALLOW_LEGACY_SPLASH; config.use_outdated_mhd = DEFAULT_USE_OUTDATED_MHD; config.unescape_callback_enabled = DEFAULT_UNESCAPE_CALLBACK_ENABLED; @@ -246,6 +253,8 @@ config_init(void) config.fas_ssl = NULL; config.fas_hid = NULL; config.custom_params = NULL; + config.custom_vars = NULL; + config.custom_images = NULL; config.fas_path = DEFAULT_FASPATH; config.webroot = safe_strdup(DEFAULT_WEBROOT); config.splashpage = safe_strdup(DEFAULT_SPLASHPAGE); @@ -824,6 +833,15 @@ config_read(const char *filename) exit(1); } break; + case oThemeSpecPath: + config.themespec_path = safe_strdup(p1); + if (!((stat(p1, &sb) == 0) && S_ISREG(sb.st_mode) && (sb.st_mode & S_IXUSR))) { + debug(LOG_ERR, "ThemeSpec program does not exist or is not executeable: %s", p1); + debug(LOG_ERR, "Exiting..."); + exit(1); + } + debug(LOG_NOTICE, "Added ThemeSpec [%s]", p1); + break; case oAllowLegacySplash: if (sscanf(p1, "%d", &config.allow_legacy_splash) < 1) { debug(LOG_ERR, "Bad arg %s to option %s on line %d in %s", p1, s, linenum, filename); @@ -904,6 +922,12 @@ config_read(const char *filename) case oFasCustomParametersList: parse_fas_custom_parameters_list(p1); break; + case oFasCustomVariablesList: + parse_fas_custom_variables_list(p1); + break; + case oFasCustomImagesList: + parse_fas_custom_images_list(p1); + break; case oMACmechanism: if (!strcasecmp("allow", p1)) { config.macmechanism = MAC_ALLOW; @@ -1167,6 +1191,40 @@ int add_to_fas_custom_parameters_list(const char possibleparam[]) return 0; } +int add_to_fas_custom_variables_list(const char possiblevar[]) +{ + char var[128]; + t_FASVAR *p = NULL; + + sscanf(possiblevar, "%s", var); + + // Add Variable to head of list + p = safe_malloc(sizeof(t_FASVAR)); + p->fasvar = safe_strdup(var); + p->next = config.fas_custom_variables_list; + + config.fas_custom_variables_list = p; + debug(LOG_NOTICE, "Added Custom Variable [%s]", possiblevar); + return 0; +} + +int add_to_fas_custom_images_list(const char possibleimage[]) +{ + char image[128]; + t_FASIMG *p = NULL; + + sscanf(possibleimage, "%s", image); + + // Add Image to head of list + p = safe_malloc(sizeof(t_FASIMG)); + p->fasimg = safe_strdup(image); + p->next = config.fas_custom_images_list; + + config.fas_custom_images_list = p; + debug(LOG_NOTICE, "Added Custom Image [%s]", possibleimage); + return 0; +} + int add_to_trusted_mac_list(const char possiblemac[]) { char mac[18]; @@ -1614,7 +1672,7 @@ void parse_fas_custom_parameters_list(const char ptr[]) debug(LOG_DEBUG, "[%s] is the urlencoded Custom FAS Parameter", possibleparam_urlencoded); safe_asprintf(&cmd, - "echo \"%s\" | awk -F'%s' 'NF==2 && $1!=\"\" && $2!=\"\" {printf \"%s\",$0}'", + "echo \"%s\" | awk -F'%s' 'NF>1 && $1!=\"\" && $2!=\"\" {printf \"%s\",$0}'", possibleparam_urlencoded, CUSTOM_SEPARATOR, FORMAT_SPECIFIER @@ -1633,6 +1691,94 @@ void parse_fas_custom_parameters_list(const char ptr[]) } } +/* Given a pointer to a comma or whitespace delimited sequence of + * Custom FAS Variables, add each parameter to config.fas_custom_variables_list + */ +void parse_fas_custom_variables_list(const char ptr[]) +{ + char *ptrcopy = NULL; + char *possiblevar = NULL; + char msg[128] = {0}; + char *cmd = NULL; + char possiblevar_urlencoded[256] = {0}; + + debug(LOG_INFO, "Parsing list [%s] for Custom FAS Variables", ptr); + + // strsep modifies original, so let's make a copy + ptrcopy = safe_strdup(ptr); + + while ((possiblevar = strsep(&ptrcopy, ", \t"))) { + if (strlen(possiblevar) > 0) { + + // URL encode Variable before parsing + memset(possiblevar_urlencoded, 0, sizeof(possiblevar_urlencoded)); + uh_urlencode(possiblevar_urlencoded, sizeof(possiblevar_urlencoded), possiblevar, strlen(possiblevar)); + debug(LOG_DEBUG, "[%s] is the urlencoded Custom FAS Variable", possiblevar_urlencoded); + + safe_asprintf(&cmd, + "echo \"%s\" | awk -F'%s' 'NF>1 && $1!=\"\" && $2!=\"\" {printf \"%s\",$0}'", + possiblevar_urlencoded, + CUSTOM_SEPARATOR, + FORMAT_SPECIFIER + ); + debug(LOG_DEBUG, "Parse command [%s]", cmd); + memset(msg, 0, sizeof(msg)); + execute_ret_url_encoded(msg, sizeof(msg) - 1, cmd); + free(cmd); + if (strcmp(msg, possiblevar_urlencoded) == 0) { + debug(LOG_INFO, "Adding variable [%s] [%s]", possiblevar, msg); + add_to_fas_custom_variables_list(possiblevar); + } else { + debug(LOG_WARNING, "Invalid Custom Variable [%s] [%s] - skipping", possiblevar, msg); + } + } + } +} + +/* Given a pointer to a comma or whitespace delimited sequence of + * Custom FAS Images, add each image to config.fas_custom_images_list + */ +void parse_fas_custom_images_list(const char ptr[]) +{ + char *ptrcopy = NULL; + char *possibleimage = NULL; + char msg[128] = {0}; + char *cmd = NULL; + char possibleimage_urlencoded[256] = {0}; + + debug(LOG_INFO, "Parsing list [%s] for Custom FAS Images", ptr); + + // strsep modifies original, so let's make a copy + ptrcopy = safe_strdup(ptr); + + while ((possibleimage = strsep(&ptrcopy, ", \t"))) { + if (strlen(possibleimage) > 0) { + + // URL encode Image before parsing + memset(possibleimage_urlencoded, 0, sizeof(possibleimage_urlencoded)); + uh_urlencode(possibleimage_urlencoded, sizeof(possibleimage_urlencoded), possibleimage, strlen(possibleimage)); + debug(LOG_DEBUG, "[%s] is the urlencoded Custom FAS Image", possibleimage_urlencoded); + + safe_asprintf(&cmd, + "echo \"%s\" | awk -F'%s' 'NF>1 && $1!=\"\" && $2!=\"\" {printf \"%s\",$0}'", + possibleimage_urlencoded, + CUSTOM_SEPARATOR, + FORMAT_SPECIFIER + ); + debug(LOG_DEBUG, "Parse command [%s]", cmd); + memset(msg, 0, sizeof(msg)); + execute_ret_url_encoded(msg, sizeof(msg) - 1, cmd); + free(cmd); + if (strcmp(msg, possibleimage_urlencoded) == 0) { + debug(LOG_INFO, "Adding image [%s] [%s]", possibleimage, msg); + add_to_fas_custom_images_list(possibleimage); + } else { + debug(LOG_WARNING, "Invalid Custom Image [%s] [%s] - skipping", possibleimage, msg); + } + } + } +} + /** Set the debug log level. See syslog.h * Return 0 on success. diff --git a/src/conf.h b/src/conf.h index 7f337d4..55cad4f 100644 --- a/src/conf.h +++ b/src/conf.h @@ -153,74 +153,92 @@ typedef struct _FASPARAM_t { struct _FASPARAM_t *next; } t_FASPARAM; +// Custom FAS Variables +typedef struct _FASVAR_t { + char *fasvar; + struct _FASVAR_t *next; +} t_FASVAR; + +// Custom FAS Images +typedef struct _FASIMG_t { + char *fasimg; + struct _FASIMG_t *next; +} t_FASIMG; + + // Configuration structure typedef struct { - char configfile[255]; //@brief name of the config file - char *ndsctl_sock; //@brief ndsctl path to socket - char *internal_sock; //@brief internal path to socket - int daemon; //@brief if daemon > 0, use daemon mode + char configfile[255]; //@brief name of the config file + char *ndsctl_sock; //@brief ndsctl path to socket + char *internal_sock; //@brief internal path to socket + int daemon; //@brief if daemon > 0, use daemon mode int debuglevel; //@brief Debug information verbosity int maxclients; //@brief Maximum number of clients allowed - char *gw_name; //@brief Name of the gateway; e.g. its SSID or a unique identifier for use in a remote FAS - char *http_encoded_gw_name; //@brief http encoded name of the gateway, used as a templated variable in splash.htm - char *url_encoded_gw_name; //@brief url encoded name of the gateway used as variable in Preauth - char *gw_interface; //@brief Interface we will manage - char *gw_iprange; //@brief IP range on gw_interface we will manage - char *gw_ip; //@brief Internal IP (v4 or v6) for our web server - char *gw_address; //@brief Internal IP with port for our web server - char *gw_mac; //@brief MAC address of the interface we manage - char *gw_fqdn; //@brief FQDN of the client status page - unsigned int gw_port; //@brief Port the webserver will run on - unsigned int fas_port; //@brief Port the fas server will run on - int login_option_enabled; //@brief Use default PreAuth Login script - int allow_legacy_splash; //@brief Allow use of legacy html splash page - int use_outdated_mhd; //@brief Use outdated libmicrohttpd - int unescape_callback_enabled; //@brief Enable external MHD unescape callback script + char *gw_name; //@brief Name of the gateway; e.g. its SSID or a unique identifier for use in a remote FAS + char *http_encoded_gw_name; //@brief http encoded name of the gateway, used as a templated variable in splash.htm + char *url_encoded_gw_name; //@brief url encoded name of the gateway used as variable in Preauth + char *gw_interface; //@brief Interface we will manage + char *gw_iprange; //@brief IP range on gw_interface we will manage + char *gw_ip; //@brief Internal IP (v4 or v6) for our web server + char *gw_address; //@brief Internal IP with port for our web server + char *gw_mac; //@brief MAC address of the interface we manage + char *gw_fqdn; //@brief FQDN of the client status page + unsigned int gw_port; //@brief Port the webserver will run on + unsigned int fas_port; //@brief Port the fas server will run on + int login_option_enabled; //@brief Use default PreAuth Login script + int allow_legacy_splash; //@brief Allow use of legacy html splash page + int use_outdated_mhd; //@brief Use outdated libmicrohttpd + int unescape_callback_enabled; //@brief Enable external MHD unescape callback script int fas_secure_enabled; //@brief Enable Secure FAS char *fas_path; //@brief Path to forward authentication page of FAS - char *fas_key; //@brief AES key for FAS - char *fas_remoteip; //@brief IP addess of a remote FAS - char *fas_remotefqdn; //@brief FQDN of a remote FAS - char *fas_url; //@brief URL of a remote FAS - char *fas_ssl; //@brief SSL provider for FAS - char *fas_hid; //@brief Hash provider for FAS - char *webroot; //@brief Directory containing splash pages, etc. - char *splashpage; //@brief Name of main splash page - char *statuspage; //@brief Name of info status page - char *redirectURL; //@brief URL to direct client to after authentication - char *authdir; //@brief Notional relative dir for authentication URL - char *denydir; //@brief Notional relative dir for denial URL - char *preauthdir; //@brief Notional relative dir for preauth URL - int session_timeout; //@brief Minutes of the default session length - int preauth_idle_timeout; //@brief Minutes a preauthenticated client will be kept in the system - int auth_idle_timeout; //@brief Minutes an authenticated client will be kept in the system - int checkinterval; //@brief Period the the client timeout check thread will run, in seconds - int set_mss; //@brief boolean, whether to set mss - int mss_value; //@brief int, mss value; <= 0 clamp to pmtu - int traffic_control; //@brief boolean, whether to do tc - int rate_check_window; //@brief window size in multiples of checkinterval for rate check moving average - unsigned long long int download_rate; //@brief Download rate, kb/s - unsigned long long int upload_rate; //@brief Upload rate, kb/s - unsigned long long int download_quota; //@brief Download quota, kB - unsigned long long int upload_quota; //@brief Upload quota, kB + char *fas_key; //@brief AES key for FAS + char *fas_remoteip; //@brief IP addess of a remote FAS + char *fas_remotefqdn; //@brief FQDN of a remote FAS + char *fas_url; //@brief URL of a remote FAS + char *fas_ssl; //@brief SSL provider for FAS + char *fas_hid; //@brief Hash provider for FAS + char *themespec_path; //@brief Path to the ThemeSpec file to use for login_option_enabled = 3 + char *webroot; //@brief Directory containing splash pages, etc. + char *splashpage; //@brief Name of main splash page + char *statuspage; //@brief Name of info status page + char *redirectURL; //@brief URL to direct client to after authentication + char *authdir; //@brief Notional relative dir for authentication URL + char *denydir; //@brief Notional relative dir for denial URL + char *preauthdir; //@brief Notional relative dir for preauth URL + int session_timeout; //@brief Minutes of the default session length + int preauth_idle_timeout; //@brief Minutes a preauthenticated client will be kept in the system + int auth_idle_timeout; //@brief Minutes an authenticated client will be kept in the system + int checkinterval; //@brief Period the the client timeout check thread will run, in seconds + int set_mss; //@brief boolean, whether to set mss + int mss_value; //@brief int, mss value; <= 0 clamp to pmtu + int traffic_control; //@brief boolean, whether to do tc + int rate_check_window; //@brief window size in multiples of checkinterval for rate check moving average + unsigned long long int download_rate; //@brief Download rate, kb/s + unsigned long long int upload_rate; //@brief Upload rate, kb/s + unsigned long long int download_quota; //@brief Download quota, kB + unsigned long long int upload_quota; //@brief Upload quota, kB int upload_ifb; //@brief Number of IFB handling upload int log_syslog; //@brief boolean, whether to log to syslog - int syslog_facility; //@brief facility to use when using syslog for logging - int macmechanism; //@brief mechanism wrt MAC addrs - t_firewall_ruleset *rulesets; //@brief firewall rules - t_MAC *trustedmaclist; //@brief list of trusted macs - t_MAC *blockedmaclist; //@brief list of blocked macs - t_MAC *allowedmaclist; //@brief list of allowed macs - t_WGP *walledgarden_port_list; //@brief list of Walled Garden Ports - t_WGFQDN *walledgarden_fqdn_list; //@brief list of Walled Garden FQDNs + int syslog_facility; //@brief facility to use when using syslog for logging + int macmechanism; //@brief mechanism wrt MAC addrs + t_firewall_ruleset *rulesets; //@brief firewall rules + t_MAC *trustedmaclist; //@brief list of trusted macs + t_MAC *blockedmaclist; //@brief list of blocked macs + t_MAC *allowedmaclist; //@brief list of allowed macs + t_WGP *walledgarden_port_list; //@brief list of Walled Garden Ports + t_WGFQDN *walledgarden_fqdn_list; //@brief list of Walled Garden FQDNs t_FASPARAM *fas_custom_parameters_list; //@brief list of Custom FAS parameters - char *custom_params; //@brief FAS custom parameter string - unsigned int fw_mark_authenticated; //@brief iptables mark for authenticated packets - unsigned int fw_mark_blocked; //@brief iptables mark for blocked packets - unsigned int fw_mark_trusted; //@brief iptables mark for trusted packets - int ip6; //@brief enable IPv6 - char *binauth; //@brief external authentication program - char *preauth; //@brief external preauthentication program + t_FASVAR *fas_custom_variables_list; //@brief list of Custom FAS variables + t_FASIMG *fas_custom_images_list; //@brief list of Custom FAS images + char *custom_params; //@brief FAS custom parameter string + char *custom_vars; //@brief FAS custom variable string + char *custom_images; //@brief FAS custom image string + unsigned int fw_mark_authenticated; //@brief iptables mark for authenticated packets + unsigned int fw_mark_blocked; //@brief iptables mark for blocked packets + unsigned int fw_mark_trusted; //@brief iptables mark for trusted packets + int ip6; //@brief enable IPv6 + char *binauth; //@brief external authentication program + char *preauth; //@brief external preauthentication program } s_config; // @brief Get the current gateway configuration @@ -259,6 +277,8 @@ void parse_allowed_mac_list(const char[]); void parse_walledgarden_fqdn_list(const char[]); void parse_walledgarden_port_list(const char[]); void parse_fas_custom_parameters_list(const char[]); +void parse_fas_custom_variables_list(const char[]); +void parse_fas_custom_images_list(const char[]); int is_blocked_mac(const char *mac); int is_allowed_mac(const char *mac); diff --git a/src/http_microhttpd.c b/src/http_microhttpd.c index 3097e8a..5040abb 100644 --- a/src/http_microhttpd.c +++ b/src/http_microhttpd.c @@ -1103,7 +1103,7 @@ static char *construct_querystring(t_client *client, char *originurl, char *quer debug(LOG_INFO, "clientif: [%s] url_encoded_gw_name: [%s]", clientif, config->url_encoded_gw_name); snprintf(query_str, QUERYMAXLEN, - "clientip=%s%sclientmac=%s%sgatewayname=%s%sversion=%s%shid=%s%sgatewayaddress=%s%sgatewaymac=%s%sauthdir=%s%soriginurl=%s%sclientif=%s%s%s", + "clientip=%s%sclientmac=%s%sgatewayname=%s%sversion=%s%shid=%s%sgatewayaddress=%s%sgatewaymac=%s%sauthdir=%s%soriginurl=%s%sclientif=%s%sthemespec=%s%s%s%s%s", client->ip, QUERYSEPARATOR, client->mac, QUERYSEPARATOR, config->url_encoded_gw_name, QUERYSEPARATOR, @@ -1113,9 +1113,11 @@ static char *construct_querystring(t_client *client, char *originurl, char *quer config->gw_mac, QUERYSEPARATOR, config->authdir, QUERYSEPARATOR, originurl, QUERYSEPARATOR, - clientif, - QUERYSEPARATOR, - config->custom_params + clientif, QUERYSEPARATOR, + config->themespec_path, QUERYSEPARATOR, + config->custom_params, + config->custom_vars, + config->custom_images ); b64_encode(query_str_b64, sizeof(query_str_b64), query_str, strlen(query_str)); @@ -1139,7 +1141,7 @@ static char *construct_querystring(t_client *client, char *originurl, char *quer get_client_interface(clientif, sizeof(clientif), client->mac); debug(LOG_INFO, "clientif: [%s]", clientif); snprintf(querystr, QUERYMAXLEN, - "clientip=%s%sclientmac=%s%sgatewayname=%s%sversion=%s%shid=%s%sgatewayaddress=%s%sgatewaymac=%s%sauthdir=%s%soriginurl=%s%sclientif=%s%s%s", + "clientip=%s%sclientmac=%s%sgatewayname=%s%sversion=%s%shid=%s%sgatewayaddress=%s%sgatewaymac=%s%sauthdir=%s%soriginurl=%s%sclientif=%s%sthemespec=%s%s%s%s%s", client->ip, QUERYSEPARATOR, client->mac, QUERYSEPARATOR, config->url_encoded_gw_name, QUERYSEPARATOR, @@ -1150,7 +1152,10 @@ static char *construct_querystring(t_client *client, char *originurl, char *quer config->authdir, QUERYSEPARATOR, originurl, QUERYSEPARATOR, clientif, QUERYSEPARATOR, - config->custom_params + config->themespec_path, QUERYSEPARATOR, + config->custom_params, + config->custom_vars, + config->custom_images ); } else { diff --git a/src/main.c b/src/main.c index 9f0c8c9..a33672c 100644 --- a/src/main.c +++ b/src/main.c @@ -347,6 +347,43 @@ setup_from_config(void) debug(LOG_DEBUG, "Custom FAS parameter string [%s]", config->custom_params); } + // Setup custom FAS variables if configured + char fasvar[512] = {0}; + t_FASVAR *fas_fasvar; + if (config->fas_custom_parameters_list) { + for (fas_fasvar = config->fas_custom_variables_list; fas_fasvar != NULL; fas_fasvar = fas_fasvar->next) { + + // Make sure we don't have a buffer overflow + if ((sizeof(fasvar) - strlen(fasvar)) > (strlen(fas_fasvar->fasvar) + 4)) { + strcat(fasvar, fas_fasvar->fasvar); + strcat(fasvar, QUERYSEPARATOR); + } else { + break; + } + } + config->custom_vars = safe_strdup(fasvar); + debug(LOG_DEBUG, "Custom FAS variables string [%s]", config->custom_vars); + } + + // Setup custom FAS images if configured + char fasimage[512] = {0}; + t_FASIMG *fas_fasimage; + if (config->fas_custom_images_list) { + for (fas_fasimage = config->fas_custom_images_list; fas_fasimage != NULL; fas_fasimage = fas_fasimage->next) { + + // Make sure we don't have a buffer overflow + if ((sizeof(fasimage) - strlen(fasimage)) > (strlen(fas_fasimage->fasimg) + 4)) { + strcat(fasimage, fas_fasimage->fasimg); + strcat(fasimage, QUERYSEPARATOR); + } else { + break; + } + } + config->custom_images = safe_strdup(fasimage); + debug(LOG_DEBUG, "Custom FAS images string [%s]", config->custom_images); + } + + if (config->gw_fqdn || config->walledgarden_fqdn_list) { // For Client status Page - configure the hosts file if (config->gw_fqdn) {