From bb197aadc9b8a70780d6c0d434e40a485e3b8e32 Mon Sep 17 00:00:00 2001 From: filippor Date: Mon, 29 Apr 2024 01:51:40 +0200 Subject: [PATCH 01/11] add parameter and auth by id --- Makefile.am | 2 +- src/config.c | 9 +++++++++ src/config.h | 2 ++ src/cookieRetriever.c | 32 ++++++++++++++++++++++++++++++++ src/cookieRetriever.h | 15 +++++++++++++++ src/http.c | 39 ++++++++++----------------------------- src/http.h | 29 +++++++++++++++++++++++++++++ src/main.c | 36 ++++++++++++++++++++++++++++++++---- 8 files changed, 130 insertions(+), 34 deletions(-) create mode 100644 src/cookieRetriever.c create mode 100644 src/cookieRetriever.h diff --git a/Makefile.am b/Makefile.am index 3b59e0d9..dda83c02 100644 --- a/Makefile.am +++ b/Makefile.am @@ -5,7 +5,7 @@ openfortivpn_SOURCES = src/config.c src/config.h src/hdlc.c src/hdlc.h \ src/http.c src/http.h src/io.c src/io.h src/ipv4.c \ src/ipv4.h src/log.c src/log.h src/tunnel.c \ src/tunnel.h src/main.c src/ssl.h src/xml.c \ - src/xml.h src/userinput.c src/userinput.h + src/xml.h src/userinput.c src/userinput.h src/cookieRetriever.c src/cookieRetriever.h openfortivpn_CPPFLAGS = -DSYSCONFDIR=\"$(sysconfdir)\" \ -DPPP_PATH=\"@PPP_PATH@\" \ -DNETSTAT_PATH=\"@NETSTAT_PATH@\" \ diff --git a/src/config.c b/src/config.c index 9c6d3c5d..08fd18f2 100644 --- a/src/config.c +++ b/src/config.c @@ -87,6 +87,8 @@ const struct vpn_config invalid_cfg = { .user_agent = NULL, .hostcheck = NULL, .check_virtual_desktop = NULL, + .auth_id = NULL, + .listen_port = 0 }; /* @@ -534,6 +536,13 @@ void merge_config(struct vpn_config *dst, struct vpn_config *src) free(dst->cookie); dst->cookie = src->cookie; } + if (src->auth_id != invalid_cfg.auth_id) { + free(dst->auth_id); + dst->auth_id = src->auth_id; + } + if (src->listen_port != invalid_cfg.listen_port) { + dst->listen_port = src->listen_port; + } if (src->pinentry) { free(dst->pinentry); dst->pinentry = src->pinentry; diff --git a/src/config.h b/src/config.h index eaf7f825..d0f3b814 100644 --- a/src/config.h +++ b/src/config.h @@ -90,6 +90,8 @@ struct vpn_config { char password[PASSWORD_SIZE + 1]; int password_set; char otp[OTP_SIZE + 1]; + uint16_t listen_port; + char *auth_id; char *cookie; char *otp_prompt; unsigned int otp_delay; diff --git a/src/cookieRetriever.c b/src/cookieRetriever.c new file mode 100644 index 00000000..d31944dd --- /dev/null +++ b/src/cookieRetriever.c @@ -0,0 +1,32 @@ +/* + * cookieRetriever.c + * + * Created on: 28 apr 2024 + * Author: filippor + */ +#include +#include +#include "http.h" + +#define MAX_RESPONSE_SIZE 4096 +#define MAX_COOKIES 10 + + +char* retrieve_id_with_external_browser(struct vpn_config *cfg) { + char data[512]; + char *url = data; + sprintf(url, "https://%s:%d/remote/saml/start?redirect=1", cfg->gateway_host, + cfg->gateway_port); + + if (cfg->realm[0] != '\0') { + strcat(url, "&realm="); + char *dt = url + strlen(url); + url_encode(dt, cfg->realm); + } + printf("open this address: "); + printf(url); + printf("\n"); + + return "fakke-id"; +} + diff --git a/src/cookieRetriever.h b/src/cookieRetriever.h new file mode 100644 index 00000000..3fe545f0 --- /dev/null +++ b/src/cookieRetriever.h @@ -0,0 +1,15 @@ +/* + * cookieRetriever.h + * + * Created on: 28 apr 2024 + * Author: filippor + */ + +#ifndef SRC_COOKIERETRIEVER_H_ +#define SRC_COOKIERETRIEVER_H_ +#include +#include "config.h" + +char *retrieve_id_with_external_browser(struct vpn_config *cfg ); + +#endif /* SRC_COOKIERETRIEVER_H_ */ diff --git a/src/http.c b/src/http.c index 80322894..a104d2ed 100644 --- a/src/http.c +++ b/src/http.c @@ -39,33 +39,6 @@ #define HTTP_BUFFER_SIZE 0x10000 -/* - * URL-encodes a string for HTTP requests. - * - * The dest buffer size MUST be at least strlen(str) * 3 + 1. - * - * @param[out] dest the buffer to write the URL-encoded string - * @param[in] str the input string to be escaped - */ -static void url_encode(char *dest, const char *str) -{ - while (*str != '\0') { - if (isalnum(*str) || *str == '-' || *str == '_' || - *str == '.' || *str == '~') { - *dest++ = *str; - } else { - static const char hex[] = "0123456789ABCDEF"; - - *dest++ = '%'; - *dest++ = hex[(unsigned char)*str >> 4]; - *dest++ = hex[(unsigned char)*str & 15]; - } - str++; - } - *dest = '\0'; -} - - /* * Sends data to the HTTP server. * @@ -649,8 +622,16 @@ int auth_log_in(struct tunnel *tunnel) url_encode(realm, tunnel->config->realm); tunnel->cookie[0] = '\0'; - - if (username[0] == '\0' && tunnel->config->password[0] == '\0') { + if (tunnel->config->auth_id != NULL) { + char empty_data[0]; + char urlBuf[256]; + urlBuf[0] = '\0'; + char *request_url = urlBuf; + sprintf(request_url, "/remote/saml/auth_id?id=%s", + tunnel->config->auth_id); + ret = http_request(tunnel, "GET", request_url, empty_data, &res, + &response_size); + }else if (username[0] == '\0' && tunnel->config->password[0] == '\0') { snprintf(data, sizeof(data), "cert=&nup=1"); ret = http_request(tunnel, "GET", "/remote/login", data, &res, &response_size); diff --git a/src/http.h b/src/http.h index a4a07e1b..406630f2 100644 --- a/src/http.h +++ b/src/http.h @@ -21,6 +21,7 @@ #include "tunnel.h" #include +#include #define ERR_HTTP_INVALID -1 #define ERR_HTTP_TOO_LONG -2 @@ -31,6 +32,34 @@ #define ERR_HTTP_PERMISSION -6 #define ERR_HTTP_NO_COOKIE -7 + +/* + * URL-encodes a string for HTTP requests. + * + * The dest buffer size MUST be at least strlen(str) * 3 + 1. + * + * @param[out] dest the buffer to write the URL-encoded string + * @param[in] str the input string to be escaped + */ +static void url_encode(char *dest, const char *str) +{ + while (*str != '\0') { + if (isalnum(*str) || *str == '-' || *str == '_' || + *str == '.' || *str == '~') { + *dest++ = *str; + } else { + static const char hex[] = "0123456789ABCDEF"; + + *dest++ = '%'; + *dest++ = hex[(unsigned char)*str >> 4]; + *dest++ = hex[(unsigned char)*str & 15]; + } + str++; + } + *dest = '\0'; +} + + static inline const char *err_http_str(int code) { if (code > 0) diff --git a/src/main.c b/src/main.c index c1fba334..1d36bce1 100644 --- a/src/main.c +++ b/src/main.c @@ -19,7 +19,7 @@ #include "tunnel.h" #include "userinput.h" #include "log.h" - +#include "cookieRetriever.h" #include #include @@ -225,6 +225,8 @@ int main(int argc, char *argv[]) .password = {'\0'}, .password_set = 0, .cookie = NULL, + .listen_port =0, + .auth_id = NULL, .otp = {'\0'}, .otp_prompt = NULL, .otp_delay = 0, @@ -286,6 +288,8 @@ int main(int argc, char *argv[]) {"password", required_argument, NULL, 'p'}, {"cookie", required_argument, NULL, 0}, {"cookie-on-stdin", no_argument, NULL, 0}, + {"ext-browser-saml", optional_argument,NULL,0}, + {"auth-id", required_argument,NULL,0}, {"otp", required_argument, NULL, 'o'}, {"otp-prompt", required_argument, NULL, 0}, {"otp-delay", required_argument, NULL, 0}, @@ -604,6 +608,24 @@ int main(int argc, char *argv[]) free(cookie); break; } + if (strcmp(long_options[option_index].name, + "ext-browser-saml") == 0) { + long port = 8020; + if (optarg != NULL) { + port = strtol(optarg, NULL, 0); + if (port < 1 || port > 65535) { + log_error("Specify a valid listen port or omit for parameter ext-browser-saml.\n"); + goto user_error; + } + } + cli_cfg.listen_port = (uint16_t)port; + break; + } + if (strcmp(long_options[option_index].name, "auth-id") == 0) { + free(cli_cfg.auth_id); + cli_cfg.auth_id = strdup(optarg); + break; + } goto user_error; case 'h': printf("%s%s%s%s%s%s%s", usage, summary, @@ -706,11 +728,11 @@ int main(int argc, char *argv[]) log_error("Specify a valid host:port couple.\n"); goto user_error; } - // Check username - if (cfg.username[0] == '\0' && !cfg.cookie) + // Check authentication method + if (cfg.username[0] == '\0' && !cfg.cookie && !cfg.auth_id && cfg.listen_port==0) // Need either username or cert if (cfg.user_cert == NULL) { - log_error("Specify a username.\n"); + log_error("Specify a authentication method.\n"); goto user_error; } // If username but no password given, interactively ask user @@ -732,6 +754,12 @@ int main(int argc, char *argv[]) if (cfg.otp[0] != '\0') log_debug("One-time password = \"%s\"\n", cfg.otp); + if (cfg.listen_port != 0){ + log_debug("Will listen on port \"%d\" for authentication id \n", cfg.listen_port); + free(cfg.cookie); + cfg.auth_id = retrieve_id_with_external_browser(&cfg); + } + if (geteuid() != 0) { log_error("This process was not spawned with root privileges, which are required.\n"); ret = EXIT_FAILURE; From 391f70b51682e63306dfe0a9c26ba2272dea37a4 Mon Sep 17 00:00:00 2001 From: filippor Date: Mon, 29 Apr 2024 02:54:34 +0200 Subject: [PATCH 02/11] Implement --ext-browser-saml start listening on port 8020 or parameter print a address to open in browser when id received proceed with the authemntication --- Makefile.am | 2 +- src/cookieRetriever.c | 32 -------- src/idretriever.c | 99 ++++++++++++++++++++++++ src/{cookieRetriever.h => idretriever.h} | 6 +- src/main.c | 4 +- 5 files changed, 106 insertions(+), 37 deletions(-) delete mode 100644 src/cookieRetriever.c create mode 100644 src/idretriever.c rename src/{cookieRetriever.h => idretriever.h} (66%) diff --git a/Makefile.am b/Makefile.am index dda83c02..9634e319 100644 --- a/Makefile.am +++ b/Makefile.am @@ -5,7 +5,7 @@ openfortivpn_SOURCES = src/config.c src/config.h src/hdlc.c src/hdlc.h \ src/http.c src/http.h src/io.c src/io.h src/ipv4.c \ src/ipv4.h src/log.c src/log.h src/tunnel.c \ src/tunnel.h src/main.c src/ssl.h src/xml.c \ - src/xml.h src/userinput.c src/userinput.h src/cookieRetriever.c src/cookieRetriever.h + src/xml.h src/userinput.c src/userinput.h src/idretriever.c src/idretriever.h openfortivpn_CPPFLAGS = -DSYSCONFDIR=\"$(sysconfdir)\" \ -DPPP_PATH=\"@PPP_PATH@\" \ -DNETSTAT_PATH=\"@NETSTAT_PATH@\" \ diff --git a/src/cookieRetriever.c b/src/cookieRetriever.c deleted file mode 100644 index d31944dd..00000000 --- a/src/cookieRetriever.c +++ /dev/null @@ -1,32 +0,0 @@ -/* - * cookieRetriever.c - * - * Created on: 28 apr 2024 - * Author: filippor - */ -#include -#include -#include "http.h" - -#define MAX_RESPONSE_SIZE 4096 -#define MAX_COOKIES 10 - - -char* retrieve_id_with_external_browser(struct vpn_config *cfg) { - char data[512]; - char *url = data; - sprintf(url, "https://%s:%d/remote/saml/start?redirect=1", cfg->gateway_host, - cfg->gateway_port); - - if (cfg->realm[0] != '\0') { - strcat(url, "&realm="); - char *dt = url + strlen(url); - url_encode(dt, cfg->realm); - } - printf("open this address: "); - printf(url); - printf("\n"); - - return "fakke-id"; -} - diff --git a/src/idretriever.c b/src/idretriever.c new file mode 100644 index 00000000..22210e79 --- /dev/null +++ b/src/idretriever.c @@ -0,0 +1,99 @@ +/* + * cookieRetriever.c + * + * Created on: 28 apr 2024 + * Author: filippor + */ +#include +#include +#include "log.h" +#include "http.h" +#include +#include +#include +#include + +#define MAX_REQUEST_SIZE 4096 +// Function to parse HTTP request and extract parameter "id" +char* parse_request(const char *request) { + char *id = NULL; + char *token = strtok((char*) request, " "); + while (token != NULL) { + if (strstr(token, "id=") != NULL) { + // Found "id=" parameter + id = strchr(token, '=') + 1; + break; + } + token = strtok(NULL, " "); + } + return id; +} + +char* retrieve_id_with_external_browser(struct vpn_config *cfg) { + int sockfd, newsockfd, clilen; + struct sockaddr_in serv_addr, cli_addr; + char buffer[MAX_REQUEST_SIZE]; + + // Create socket + sockfd = socket(AF_INET, SOCK_STREAM, 0); + if (sockfd < 0) { + perror("Error opening socket"); + exit(1); + } + // Initialize server address structure + bzero((char*) &serv_addr, sizeof(serv_addr)); + serv_addr.sin_family = AF_INET; + serv_addr.sin_addr.s_addr = INADDR_ANY; + serv_addr.sin_port = htons(cfg->listen_port); + + // Bind socket to address + if (bind(sockfd, (struct sockaddr*) &serv_addr, sizeof(serv_addr)) < 0) { + perror("Error on binding"); + exit(1); + } + + // Listen for incoming connections + listen(sockfd, 5); + clilen = sizeof(cli_addr); + + log_debug("Server listening on port %d to retrieve the id\n", + cfg->listen_port); + + char data[512]; + char *url = data; + sprintf(url, "https://%s:%d/remote/saml/start?redirect=1", + cfg->gateway_host, cfg->gateway_port); + + if (cfg->realm[0] != '\0') { + strcat(url, "&realm="); + char *dt = url + strlen(url); + url_encode(dt, cfg->realm); + } + log_info("open this address: %s\n", url); + + // Accept incoming connections + newsockfd = accept(sockfd, (struct sockaddr*) &cli_addr, &clilen); + if (newsockfd < 0) { + log_error("Error on accept"); + return NULL; + } + + // Read HTTP request from client + bzero(buffer, MAX_REQUEST_SIZE); + read(newsockfd, buffer, MAX_REQUEST_SIZE - 1); + log_debug("Received HTTP request:\n%s\n", buffer); + + // Parse request and extract parameter "id" + char *id = strdup(parse_request(buffer)); + if (id != NULL) { + log_debug("Extracted id: %s\n", id); + } else { + log_error("id parameter not found\n"); + } + // Close sockets + close(newsockfd); + close(sockfd); + + return id; +} + diff --git a/src/cookieRetriever.h b/src/idretriever.h similarity index 66% rename from src/cookieRetriever.h rename to src/idretriever.h index 3fe545f0..dae00ce8 100644 --- a/src/cookieRetriever.h +++ b/src/idretriever.h @@ -5,11 +5,11 @@ * Author: filippor */ -#ifndef SRC_COOKIERETRIEVER_H_ -#define SRC_COOKIERETRIEVER_H_ +#ifndef SRC_IDRETRIEVER_H_ +#define SRC_IDRETRIEVER_H_ #include #include "config.h" char *retrieve_id_with_external_browser(struct vpn_config *cfg ); -#endif /* SRC_COOKIERETRIEVER_H_ */ +#endif /* SRC_IDRETRIEVER_H_ */ diff --git a/src/main.c b/src/main.c index 1d36bce1..0e85dc2a 100644 --- a/src/main.c +++ b/src/main.c @@ -19,13 +19,13 @@ #include "tunnel.h" #include "userinput.h" #include "log.h" -#include "cookieRetriever.h" #include #include #include #include +#include "idretriever.h" #include #include #include @@ -78,6 +78,7 @@ #define usage \ "Usage: openfortivpn [[:]] [-u ] [-p ]\n" \ " [--cookie=] [--cookie-on-stdin]\n" \ +" [--ext-browser-saml[=]]"\ " [--otp=] [--otp-delay=] [--otp-prompt=]\n" \ " [--pinentry=] [--realm=]\n" \ " [--ifname=] [--set-routes=<0|1>]\n" \ @@ -117,6 +118,7 @@ PPPD_USAGE \ " -p , --password= VPN account password.\n" \ " --cookie= A valid session cookie (SVPNCOOKIE).\n" \ " --cookie-on-stdin Read the cookie (SVPNCOOKIE) from standard input.\n" \ +" --ext-browser-saml[=] Print an http address and start listen to recieve the autentication id to proceed the connection\n"\ " -o , --otp= One-Time-Password.\n" \ " --otp-prompt= Search for the OTP prompt starting with this string.\n" \ " --otp-delay= Wait seconds before sending the OTP.\n" \ From 4a48dd4b44eee2a9829e298da6f0d6670e75acf8 Mon Sep 17 00:00:00 2001 From: filippor Date: Mon, 29 Apr 2024 03:07:54 +0200 Subject: [PATCH 03/11] add response message --- src/idretriever.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/idretriever.c b/src/idretriever.c index 22210e79..aafda1e7 100644 --- a/src/idretriever.c +++ b/src/idretriever.c @@ -29,6 +29,16 @@ char* parse_request(const char *request) { return id; } +// Function to send HTTP response +void send_response(int sockfd, const char *message) { + char response[MAX_REQUEST_SIZE]; + sprintf(response, "HTTP/1.1 200 OK\r\n" + "Content-Length: %lu\r\n" + "Content-Type: text/html\r\n\r\n" + "%s", strlen(message), message); + write(sockfd, response, strlen(response)); +} + char* retrieve_id_with_external_browser(struct vpn_config *cfg) { int sockfd, newsockfd, clilen; struct sockaddr_in serv_addr, cli_addr; @@ -87,9 +97,16 @@ char* retrieve_id_with_external_browser(struct vpn_config *cfg) { char *id = strdup(parse_request(buffer)); if (id != NULL) { log_debug("Extracted id: %s\n", id); + // Send response to client + send_response(newsockfd, + "

ID retrieved. Connecting...!

"); + } else { log_error("id parameter not found\n"); + send_response(newsockfd, + "

ERROR! id not found

"); } + // Close sockets close(newsockfd); close(sockfd); From 4cdc9644018e1f68ce12bced5f63cc98e707c177 Mon Sep 17 00:00:00 2001 From: filippor Date: Mon, 29 Apr 2024 12:15:44 +0200 Subject: [PATCH 04/11] listen only from localhost expose auth-id option --- src/idretriever.c | 11 ++++++++++- src/main.c | 1 + 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/idretriever.c b/src/idretriever.c index aafda1e7..edcee8b9 100644 --- a/src/idretriever.c +++ b/src/idretriever.c @@ -50,10 +50,12 @@ char* retrieve_id_with_external_browser(struct vpn_config *cfg) { perror("Error opening socket"); exit(1); } + + // Initialize server address structure bzero((char*) &serv_addr, sizeof(serv_addr)); serv_addr.sin_family = AF_INET; - serv_addr.sin_addr.s_addr = INADDR_ANY; + serv_addr.sin_addr.s_addr = INADDR_LOOPBACK; serv_addr.sin_port = htons(cfg->listen_port); // Bind socket to address @@ -62,6 +64,13 @@ char* retrieve_id_with_external_browser(struct vpn_config *cfg) { exit(1); } + if(setsockopt(sockfd,SOL_SOCKET,SO_REUSEPORT,&(int){1},sizeof(int))<0){ + log_error("error set SO_REUSEPORT"); + } + if(setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,&(int){1},sizeof(int))<0){ + log_error("error set SO_REUSEADDR"); + } + // Listen for incoming connections listen(sockfd, 5); clilen = sizeof(cli_addr); diff --git a/src/main.c b/src/main.c index 0e85dc2a..2bd09d1c 100644 --- a/src/main.c +++ b/src/main.c @@ -119,6 +119,7 @@ PPPD_USAGE \ " --cookie= A valid session cookie (SVPNCOOKIE).\n" \ " --cookie-on-stdin Read the cookie (SVPNCOOKIE) from standard input.\n" \ " --ext-browser-saml[=] Print an http address and start listen to recieve the autentication id to proceed the connection\n"\ +" --auth-id[=] login with this id on address /remote/saml/auth_id?id=\n"\ " -o , --otp= One-Time-Password.\n" \ " --otp-prompt= Search for the OTP prompt starting with this string.\n" \ " --otp-delay= Wait seconds before sending the OTP.\n" \ From f2382c60ed301f54fa741cc9c156cbcbe70da9aa Mon Sep 17 00:00:00 2001 From: filippor Date: Mon, 29 Apr 2024 15:50:33 +0200 Subject: [PATCH 05/11] remove static url_encode --- src/http.c | 27 +++++++++++++++++++++++++++ src/http.h | 17 +---------------- src/main.c | 4 ++-- 3 files changed, 30 insertions(+), 18 deletions(-) diff --git a/src/http.c b/src/http.c index a104d2ed..aeb1e649 100644 --- a/src/http.c +++ b/src/http.c @@ -39,6 +39,33 @@ #define HTTP_BUFFER_SIZE 0x10000 +/* + * URL-encodes a string for HTTP requests. + * + * The dest buffer size MUST be at least strlen(str) * 3 + 1. + * + * @param[out] dest the buffer to write the URL-encoded string + * @param[in] str the input string to be escaped + */ +void url_encode(char *dest, const char *str) +{ + while (*str != '\0') { + if (isalnum(*str) || *str == '-' || *str == '_' || + *str == '.' || *str == '~') { + *dest++ = *str; + } else { + static const char hex[] = "0123456789ABCDEF"; + + *dest++ = '%'; + *dest++ = hex[(unsigned char)*str >> 4]; + *dest++ = hex[(unsigned char)*str & 15]; + } + str++; + } + *dest = '\0'; +} + + /* * Sends data to the HTTP server. * diff --git a/src/http.h b/src/http.h index 406630f2..58ecef66 100644 --- a/src/http.h +++ b/src/http.h @@ -41,23 +41,8 @@ * @param[out] dest the buffer to write the URL-encoded string * @param[in] str the input string to be escaped */ -static void url_encode(char *dest, const char *str) -{ - while (*str != '\0') { - if (isalnum(*str) || *str == '-' || *str == '_' || - *str == '.' || *str == '~') { - *dest++ = *str; - } else { - static const char hex[] = "0123456789ABCDEF"; +void url_encode(char *dest, const char *str); - *dest++ = '%'; - *dest++ = hex[(unsigned char)*str >> 4]; - *dest++ = hex[(unsigned char)*str & 15]; - } - str++; - } - *dest = '\0'; -} static inline const char *err_http_str(int code) diff --git a/src/main.c b/src/main.c index 2bd09d1c..8d15a5d8 100644 --- a/src/main.c +++ b/src/main.c @@ -78,7 +78,7 @@ #define usage \ "Usage: openfortivpn [[:]] [-u ] [-p ]\n" \ " [--cookie=] [--cookie-on-stdin]\n" \ -" [--ext-browser-saml[=]]"\ +" [--ext-browser-saml[=]] --auth-id= "\ " [--otp=] [--otp-delay=] [--otp-prompt=]\n" \ " [--pinentry=] [--realm=]\n" \ " [--ifname=] [--set-routes=<0|1>]\n" \ @@ -119,7 +119,7 @@ PPPD_USAGE \ " --cookie= A valid session cookie (SVPNCOOKIE).\n" \ " --cookie-on-stdin Read the cookie (SVPNCOOKIE) from standard input.\n" \ " --ext-browser-saml[=] Print an http address and start listen to recieve the autentication id to proceed the connection\n"\ -" --auth-id[=] login with this id on address /remote/saml/auth_id?id=\n"\ +" --auth-id= login with this id on address /remote/saml/auth_id?id=\n"\ " -o , --otp= One-Time-Password.\n" \ " --otp-prompt= Search for the OTP prompt starting with this string.\n" \ " --otp-delay= Wait seconds before sending the OTP.\n" \ From 9edb330ffb67c65aadc1e31cc3ac556185c701b9 Mon Sep 17 00:00:00 2001 From: filippor Date: Mon, 29 Apr 2024 17:09:51 +0200 Subject: [PATCH 06/11] restore listen on all port INADDR_ANY does not always work --- src/idretriever.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/idretriever.c b/src/idretriever.c index edcee8b9..d764bab4 100644 --- a/src/idretriever.c +++ b/src/idretriever.c @@ -55,7 +55,7 @@ char* retrieve_id_with_external_browser(struct vpn_config *cfg) { // Initialize server address structure bzero((char*) &serv_addr, sizeof(serv_addr)); serv_addr.sin_family = AF_INET; - serv_addr.sin_addr.s_addr = INADDR_LOOPBACK; + serv_addr.sin_addr.s_addr = INADDR_ANY; //sametimes INADDR_LOOPBACK does not work serv_addr.sin_port = htons(cfg->listen_port); // Bind socket to address From 3823c38a96c502457675ada9f45eaeae9d264203 Mon Sep 17 00:00:00 2001 From: filippor Date: Mon, 29 Apr 2024 19:49:54 +0200 Subject: [PATCH 07/11] more resilient request parser and fix compile warnings --- src/http.c | 9 +++----- src/http.h | 1 - src/idretriever.c | 57 ++++++++++++++++++++++++++++------------------- src/main.c | 11 ++++++--- 4 files changed, 45 insertions(+), 33 deletions(-) diff --git a/src/http.c b/src/http.c index aeb1e649..d1ad8182 100644 --- a/src/http.c +++ b/src/http.c @@ -650,13 +650,10 @@ int auth_log_in(struct tunnel *tunnel) tunnel->cookie[0] = '\0'; if (tunnel->config->auth_id != NULL) { - char empty_data[0]; - char urlBuf[256]; - urlBuf[0] = '\0'; - char *request_url = urlBuf; - sprintf(request_url, "/remote/saml/auth_id?id=%s", + char url[256]; + snprintf(url,sizeof(url), "/remote/saml/auth_id?id=%s", tunnel->config->auth_id); - ret = http_request(tunnel, "GET", request_url, empty_data, &res, + ret = http_request(tunnel, "GET", url, "", &res, &response_size); }else if (username[0] == '\0' && tunnel->config->password[0] == '\0') { snprintf(data, sizeof(data), "cert=&nup=1"); diff --git a/src/http.h b/src/http.h index 58ecef66..74641df4 100644 --- a/src/http.h +++ b/src/http.h @@ -21,7 +21,6 @@ #include "tunnel.h" #include -#include #define ERR_HTTP_INVALID -1 #define ERR_HTTP_TOO_LONG -2 diff --git a/src/idretriever.c b/src/idretriever.c index d764bab4..d8c97efd 100644 --- a/src/idretriever.c +++ b/src/idretriever.c @@ -16,17 +16,28 @@ #define MAX_REQUEST_SIZE 4096 // Function to parse HTTP request and extract parameter "id" char* parse_request(const char *request) { - char *id = NULL; - char *token = strtok((char*) request, " "); - while (token != NULL) { - if (strstr(token, "id=") != NULL) { - // Found "id=" parameter - id = strchr(token, '=') + 1; - break; + char *id_param; + char *query_start = strchr(request, '?'); + if (query_start != NULL) { + id_param = strstr(query_start, "id="); + if (id_param != NULL) { + id_param += 3; // Length of "id=" + char *id_end = strchr(id_param, '&'); + if (id_end == NULL) { + id_end = strchr(id_param, ' '); + } + if (id_end == NULL) { + id_end = strchr(id_param, '\r'); + } + if (id_end == NULL) { + id_end = id_param + strlen(id_param); // End of string + } + *id_end = '\0'; // Null-terminate the string + return id_param; + } - token = strtok(NULL, " "); } - return id; + return NULL; } // Function to send HTTP response @@ -40,22 +51,22 @@ void send_response(int sockfd, const char *message) { } char* retrieve_id_with_external_browser(struct vpn_config *cfg) { - int sockfd, newsockfd, clilen; + int sockfd, newsockfd; struct sockaddr_in serv_addr, cli_addr; + socklen_t clilen; char buffer[MAX_REQUEST_SIZE]; // Create socket sockfd = socket(AF_INET, SOCK_STREAM, 0); if (sockfd < 0) { - perror("Error opening socket"); + log_error("Error opening socket"); exit(1); } - // Initialize server address structure bzero((char*) &serv_addr, sizeof(serv_addr)); serv_addr.sin_family = AF_INET; - serv_addr.sin_addr.s_addr = INADDR_ANY; //sametimes INADDR_LOOPBACK does not work + serv_addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);; serv_addr.sin_port = htons(cfg->listen_port); // Bind socket to address @@ -64,16 +75,17 @@ char* retrieve_id_with_external_browser(struct vpn_config *cfg) { exit(1); } - if(setsockopt(sockfd,SOL_SOCKET,SO_REUSEPORT,&(int){1},sizeof(int))<0){ - log_error("error set SO_REUSEPORT"); - } - if(setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,&(int){1},sizeof(int))<0){ - log_error("error set SO_REUSEADDR"); + int opt = 1; +// if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEPORT, &opt, sizeof(int)) +// < 0) { +// log_error("error set SO_REUSEPORT"); +// } + if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0) { + log_error("Error setting SO_REUSEADDR"); } // Listen for incoming connections listen(sockfd, 5); - clilen = sizeof(cli_addr); log_debug("Server listening on port %d to retrieve the id\n", cfg->listen_port); @@ -91,11 +103,13 @@ char* retrieve_id_with_external_browser(struct vpn_config *cfg) { log_info("open this address: %s\n", url); // Accept incoming connections - newsockfd = accept(sockfd, (struct sockaddr*) &cli_addr, &clilen); + clilen = sizeof(cli_addr); + newsockfd = accept(sockfd, &cli_addr, &clilen); if (newsockfd < 0) { log_error("Error on accept"); return NULL; } + close(sockfd); // Read HTTP request from client bzero(buffer, MAX_REQUEST_SIZE); @@ -115,10 +129,7 @@ char* retrieve_id_with_external_browser(struct vpn_config *cfg) { send_response(newsockfd, "

ERROR! id not found

"); } - - // Close sockets close(newsockfd); - close(sockfd); return id; } diff --git a/src/main.c b/src/main.c index 8d15a5d8..5e95338e 100644 --- a/src/main.c +++ b/src/main.c @@ -118,7 +118,9 @@ PPPD_USAGE \ " -p , --password= VPN account password.\n" \ " --cookie= A valid session cookie (SVPNCOOKIE).\n" \ " --cookie-on-stdin Read the cookie (SVPNCOOKIE) from standard input.\n" \ -" --ext-browser-saml[=] Print an http address and start listen to recieve the autentication id to proceed the connection\n"\ +" --ext-browser-saml[=] Print an http address and start listen to recieve \n"\ +" the autentication id to proceed the connection \n"\ +" the default port if omitted is 8020\n"\ " --auth-id= login with this id on address /remote/saml/auth_id?id=\n"\ " -o , --otp= One-Time-Password.\n" \ " --otp-prompt= Search for the OTP prompt starting with this string.\n" \ @@ -617,7 +619,7 @@ int main(int argc, char *argv[]) if (optarg != NULL) { port = strtol(optarg, NULL, 0); if (port < 1 || port > 65535) { - log_error("Specify a valid listen port or omit for parameter ext-browser-saml.\n"); + log_error("Specify a valid listen port or omit for parameter ext-browser-saml\n"); goto user_error; } } @@ -758,8 +760,11 @@ int main(int argc, char *argv[]) log_debug("One-time password = \"%s\"\n", cfg.otp); if (cfg.listen_port != 0){ + if(cfg.auth_id){ + log_warn("auth-id will be ignored conflict with --ext-browser-saml"); + } log_debug("Will listen on port \"%d\" for authentication id \n", cfg.listen_port); - free(cfg.cookie); + free(cfg.auth_id); cfg.auth_id = retrieve_id_with_external_browser(&cfg); } From 65fe582c55f14746f14b0b758a3a3de0f1a34220 Mon Sep 17 00:00:00 2001 From: filippor Date: Tue, 30 Apr 2024 12:26:43 +0200 Subject: [PATCH 08/11] release port after connection --- src/config.h | 2 +- src/idretriever.c | 11 +++++------ 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/config.h b/src/config.h index d0f3b814..e6573c91 100644 --- a/src/config.h +++ b/src/config.h @@ -91,7 +91,7 @@ struct vpn_config { int password_set; char otp[OTP_SIZE + 1]; uint16_t listen_port; - char *auth_id; + char *auth_id; char *cookie; char *otp_prompt; unsigned int otp_delay; diff --git a/src/idretriever.c b/src/idretriever.c index d8c97efd..81fd1476 100644 --- a/src/idretriever.c +++ b/src/idretriever.c @@ -85,18 +85,17 @@ char* retrieve_id_with_external_browser(struct vpn_config *cfg) { } // Listen for incoming connections - listen(sockfd, 5); + listen(sockfd, 1); log_debug("Server listening on port %d to retrieve the id\n", cfg->listen_port); - char data[512]; - char *url = data; - sprintf(url, "https://%s:%d/remote/saml/start?redirect=1", + char url[512]; + snprintf(url,sizeof(url), "https://%s:%d/remote/saml/start?redirect=1", cfg->gateway_host, cfg->gateway_port); if (cfg->realm[0] != '\0') { - strcat(url, "&realm="); + strncat(url, "&realm=",sizeof(url)-1); char *dt = url + strlen(url); url_encode(dt, cfg->realm); } @@ -111,7 +110,7 @@ char* retrieve_id_with_external_browser(struct vpn_config *cfg) { } close(sockfd); - // Read HTTP request from client + // Read HTTP request from client512 bzero(buffer, MAX_REQUEST_SIZE); read(newsockfd, buffer, MAX_REQUEST_SIZE - 1); log_debug("Received HTTP request:\n%s\n", buffer); From d3ff5a6df6d3e7d12e279bc9b9c57108a75452e4 Mon Sep 17 00:00:00 2001 From: filippor Date: Tue, 30 Apr 2024 18:50:11 +0200 Subject: [PATCH 09/11] configuration file add ext-browser-saml parameter refactor --- Makefile.am | 3 +- src/config.c | 11 ++++ src/{idretriever.c => idlistener.c} | 87 +++++++++++++++-------------- src/idlistener.h | 15 +++++ src/idretriever.h | 15 ----- src/main.c | 12 ++-- 6 files changed, 80 insertions(+), 63 deletions(-) rename src/{idretriever.c => idlistener.c} (61%) create mode 100644 src/idlistener.h delete mode 100644 src/idretriever.h diff --git a/Makefile.am b/Makefile.am index 9634e319..5afafbb2 100644 --- a/Makefile.am +++ b/Makefile.am @@ -5,7 +5,8 @@ openfortivpn_SOURCES = src/config.c src/config.h src/hdlc.c src/hdlc.h \ src/http.c src/http.h src/io.c src/io.h src/ipv4.c \ src/ipv4.h src/log.c src/log.h src/tunnel.c \ src/tunnel.h src/main.c src/ssl.h src/xml.c \ - src/xml.h src/userinput.c src/userinput.h src/idretriever.c src/idretriever.h + src/xml.h src/userinput.c src/userinput.h \ + src/idlistener.c src/idlistener.h openfortivpn_CPPFLAGS = -DSYSCONFDIR=\"$(sysconfdir)\" \ -DPPP_PATH=\"@PPP_PATH@\" \ -DNETSTAT_PATH=\"@NETSTAT_PATH@\" \ diff --git a/src/config.c b/src/config.c index 08fd18f2..0523d7b6 100644 --- a/src/config.c +++ b/src/config.c @@ -468,6 +468,17 @@ int load_config(struct vpn_config *cfg, const char *filename) } else if (strcmp(key, "check-virtual-desktop") == 0) { free(cfg->check_virtual_desktop); cfg->check_virtual_desktop = strdup(val); + } else if (strcmp(key, "ext-browser-saml") == 0) { + long port = 8020; + if (val != NULL) { + port = strtol(val, NULL, 0); + if (port < 1 || port > 65535) { + log_error("Bad ext-browser-saml port in configuration file: \"%s\".\n", + val); + goto err_free; + } + } + cfg->listen_port = (uint16_t) port; } else { log_warn("Bad key in configuration file: \"%s\".\n", key); goto err_free; diff --git a/src/idretriever.c b/src/idlistener.c similarity index 61% rename from src/idretriever.c rename to src/idlistener.c index 81fd1476..0c630931 100644 --- a/src/idretriever.c +++ b/src/idlistener.c @@ -1,21 +1,46 @@ /* - * cookieRetriever.c + * Copyright (c) 2024 Filippo Rossoni * - * Created on: 28 apr 2024 - * Author: filippor + * 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 3 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, see . */ -#include -#include +#include "idlistener.h" #include "log.h" #include "http.h" +#include +#include #include #include #include #include #define MAX_REQUEST_SIZE 4096 + +static void print_url(struct vpn_config *cfg) { + char url[512]; + snprintf(url, sizeof(url), "https://%s:%d/remote/saml/start?redirect=1", + cfg->gateway_host, cfg->gateway_port); + + if (cfg->realm[0] != '\0') { + strncat(url, "&realm=", sizeof(url) - 1); + char *dt = url + strlen(url); + url_encode(dt, cfg->realm); + } + log_info("Authenticate at %s\n", url); +} + // Function to parse HTTP request and extract parameter "id" -char* parse_request(const char *request) { +static char* parse_request(const char *request) { char *id_param; char *query_start = strchr(request, '?'); if (query_start != NULL) { @@ -33,14 +58,13 @@ char* parse_request(const char *request) { id_end = id_param + strlen(id_param); // End of string } *id_end = '\0'; // Null-terminate the string - return id_param; + return strdup(id_param); } } return NULL; } -// Function to send HTTP response void send_response(int sockfd, const char *message) { char response[MAX_REQUEST_SIZE]; sprintf(response, "HTTP/1.1 200 OK\r\n" @@ -50,79 +74,60 @@ void send_response(int sockfd, const char *message) { write(sockfd, response, strlen(response)); } -char* retrieve_id_with_external_browser(struct vpn_config *cfg) { - int sockfd, newsockfd; - struct sockaddr_in serv_addr, cli_addr; - socklen_t clilen; - char buffer[MAX_REQUEST_SIZE]; - - // Create socket - sockfd = socket(AF_INET, SOCK_STREAM, 0); +char* listen_for_id(struct vpn_config *cfg) { + int sockfd = socket(AF_INET, SOCK_STREAM, 0); if (sockfd < 0) { log_error("Error opening socket"); exit(1); } - // Initialize server address structure + struct sockaddr_in serv_addr; bzero((char*) &serv_addr, sizeof(serv_addr)); serv_addr.sin_family = AF_INET; - serv_addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);; + serv_addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); serv_addr.sin_port = htons(cfg->listen_port); - // Bind socket to address if (bind(sockfd, (struct sockaddr*) &serv_addr, sizeof(serv_addr)) < 0) { perror("Error on binding"); exit(1); } int opt = 1; -// if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEPORT, &opt, sizeof(int)) -// < 0) { -// log_error("error set SO_REUSEPORT"); -// } if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0) { log_error("Error setting SO_REUSEADDR"); } + if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEPORT, &opt, sizeof(int)) < 0) { + log_error("error set SO_REUSEPORT"); + } - // Listen for incoming connections listen(sockfd, 1); - log_debug("Server listening on port %d to retrieve the id\n", cfg->listen_port); - char url[512]; - snprintf(url,sizeof(url), "https://%s:%d/remote/saml/start?redirect=1", - cfg->gateway_host, cfg->gateway_port); - - if (cfg->realm[0] != '\0') { - strncat(url, "&realm=",sizeof(url)-1); - char *dt = url + strlen(url); - url_encode(dt, cfg->realm); - } - log_info("open this address: %s\n", url); + print_url(cfg); // Accept incoming connections - clilen = sizeof(cli_addr); - newsockfd = accept(sockfd, &cli_addr, &clilen); + struct sockaddr_in cli_addr; + socklen_t clilen = sizeof(cli_addr); + int newsockfd = accept(sockfd, &cli_addr, &clilen); if (newsockfd < 0) { log_error("Error on accept"); return NULL; } close(sockfd); - // Read HTTP request from client512 + // Read HTTP request from client + char buffer[MAX_REQUEST_SIZE]; bzero(buffer, MAX_REQUEST_SIZE); read(newsockfd, buffer, MAX_REQUEST_SIZE - 1); log_debug("Received HTTP request:\n%s\n", buffer); - // Parse request and extract parameter "id" - char *id = strdup(parse_request(buffer)); + char *id = parse_request(buffer); if (id != NULL) { log_debug("Extracted id: %s\n", id); // Send response to client send_response(newsockfd, "

ID retrieved. Connecting...!

"); - } else { log_error("id parameter not found\n"); send_response(newsockfd, diff --git a/src/idlistener.h b/src/idlistener.h new file mode 100644 index 00000000..48544062 --- /dev/null +++ b/src/idlistener.h @@ -0,0 +1,15 @@ +/* + * cookieRetriever.h + * + * Created on: 28 apr 2024 + * Author: filippor + */ + +#ifndef SRC_IDLISTENER_H_ +#define SRC_IDLISTENER_H_ +#include +#include "config.h" + +char *listen_for_id(struct vpn_config *cfg ); + +#endif /* SRC_IDLISTENER_H_ */ diff --git a/src/idretriever.h b/src/idretriever.h deleted file mode 100644 index dae00ce8..00000000 --- a/src/idretriever.h +++ /dev/null @@ -1,15 +0,0 @@ -/* - * cookieRetriever.h - * - * Created on: 28 apr 2024 - * Author: filippor - */ - -#ifndef SRC_IDRETRIEVER_H_ -#define SRC_IDRETRIEVER_H_ -#include -#include "config.h" - -char *retrieve_id_with_external_browser(struct vpn_config *cfg ); - -#endif /* SRC_IDRETRIEVER_H_ */ diff --git a/src/main.c b/src/main.c index 5e95338e..e07bd061 100644 --- a/src/main.c +++ b/src/main.c @@ -18,6 +18,7 @@ #include "config.h" #include "tunnel.h" #include "userinput.h" +#include "idlistener.h" #include "log.h" #include @@ -25,7 +26,6 @@ #include #include -#include "idretriever.h" #include #include #include @@ -78,7 +78,7 @@ #define usage \ "Usage: openfortivpn [[:]] [-u ] [-p ]\n" \ " [--cookie=] [--cookie-on-stdin]\n" \ -" [--ext-browser-saml[=]] --auth-id= "\ +" [--ext-browser-saml[=]] [--auth-id=]\n" \ " [--otp=] [--otp-delay=] [--otp-prompt=]\n" \ " [--pinentry=] [--realm=]\n" \ " [--ifname=] [--set-routes=<0|1>]\n" \ @@ -119,9 +119,9 @@ PPPD_USAGE \ " --cookie= A valid session cookie (SVPNCOOKIE).\n" \ " --cookie-on-stdin Read the cookie (SVPNCOOKIE) from standard input.\n" \ " --ext-browser-saml[=] Print an http address and start listen to recieve \n"\ -" the autentication id to proceed the connection \n"\ -" the default port if omitted is 8020\n"\ -" --auth-id= login with this id on address /remote/saml/auth_id?id=\n"\ +" the autentication id to proceed the connection \n"\ +" the default port if omitted is 8020\n"\ +" --auth-id= login with this id on address /remote/saml/auth_id?id=\n"\ " -o , --otp= One-Time-Password.\n" \ " --otp-prompt= Search for the OTP prompt starting with this string.\n" \ " --otp-delay= Wait seconds before sending the OTP.\n" \ @@ -765,7 +765,7 @@ int main(int argc, char *argv[]) } log_debug("Will listen on port \"%d\" for authentication id \n", cfg.listen_port); free(cfg.auth_id); - cfg.auth_id = retrieve_id_with_external_browser(&cfg); + cfg.auth_id = listen_for_id(&cfg); } if (geteuid() != 0) { From cd371453119dd78d700584655980e9ba3206c144 Mon Sep 17 00:00:00 2001 From: Filippo Rossoni Date: Fri, 17 May 2024 17:08:46 +0200 Subject: [PATCH 10/11] set option before bind --- src/idlistener.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/idlistener.c b/src/idlistener.c index 0c630931..4e507939 100644 --- a/src/idlistener.c +++ b/src/idlistener.c @@ -82,16 +82,11 @@ char* listen_for_id(struct vpn_config *cfg) { } struct sockaddr_in serv_addr; - bzero((char*) &serv_addr, sizeof(serv_addr)); + serv_addr.sin_family = AF_INET; serv_addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); serv_addr.sin_port = htons(cfg->listen_port); - if (bind(sockfd, (struct sockaddr*) &serv_addr, sizeof(serv_addr)) < 0) { - perror("Error on binding"); - exit(1); - } - int opt = 1; if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0) { log_error("Error setting SO_REUSEADDR"); @@ -100,6 +95,13 @@ char* listen_for_id(struct vpn_config *cfg) { log_error("error set SO_REUSEPORT"); } + if (bind(sockfd, (struct sockaddr*) &serv_addr, sizeof(serv_addr)) < 0) { + perror("Error on binding"); + exit(1); + } + + + listen(sockfd, 1); log_debug("Server listening on port %d to retrieve the id\n", cfg->listen_port); From 25fec71385c8a6bf54442e9ec43a1af74af757ad Mon Sep 17 00:00:00 2001 From: FilippoR Date: Tue, 20 Aug 2024 11:17:30 +0200 Subject: [PATCH 11/11] fix merge --- src/http.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/http.c b/src/http.c index 3ae811f2..4e8f7cd5 100644 --- a/src/http.c +++ b/src/http.c @@ -674,8 +674,6 @@ int auth_log_in(struct tunnel *tunnel) ret = http_request(tunnel, "GET", url, "", &res, &response_size); }else if (username[0] == '\0' && tunnel->config->password[0] == '\0') { - snprintf(data, sizeof(data), "cert=&nup=1"); - ret = http_request(tunnel, "GET", "/remote/login", data, &res, &response_size); } else {