/src/cfg_client.c
C | 411 lines | 245 code | 80 blank | 86 comment | 58 complexity | a1bb961da9a0c5b9d7291bec4c97c54d MD5 | raw file
Possible License(s): GPL-2.0
- /***************************************************************************
- * *
- * 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. *
- * *
- ***************************************************************************/
- #define __CFG_CLIENT_C
- #ifdef CFG_CLIENT
- #define LOGGERNAME "cfg_client"
- #include <stdio.h>
- #ifdef HAVE_STDLIB_H
- #include <stdlib.h>
- #endif /* HAVE_STDLIB_H */
- #ifdef HAVE_STRING_H
- #include <string.h>
- #endif /* HAVE_STRING_H */
- #ifdef HAVE_SYS_SOCKET_H
- #include <sys/socket.h>
- #endif /* HAVE_SYS_SOCKET_H */
- #ifdef HAVE_SYS_TYPES_H
- #include <sys/types.h>
- #endif /* HAVE_SYS_TYPES_H */
- #ifdef HAVE_NETINET_IN_H
- #include <netinet/in.h>
- #endif /* HAVE_NETINET_IN_H */
- #include <linux/ipsec.h>
- #ifdef HAVE_ARPA_INET
- #include <arpa/inet.h>
- #endif /* HAVE_ARPA_INET */
- #ifdef HAVE_UNISTD_H
- #include <unistd.h>
- #endif /* HAVE_UNISTD_H */
- #include <sys/wait.h>
- #include <glib.h>
- #include <gmodule.h>
- #include "logging.h"
- #include "netlib.h"
- #include "auth.h"
- #include "cfg.h"
- #include "cfg_client.h"
- #define MAX_ENVLINE_LEN 256
- #define MAX_IPBUF_SIZE 80
- /**
- * Put variable into environemnt
- *
- * \return This function does not return
- *
- * In case of an error, exit() is called since we assume that we run
- * from fork()-ed process.
- */
- void newenv(char *c)
- {
- LOG_DEBUG("New env item '%s'", c);
- if (putenv(g_strdup(c)) < 0) {
- LOG_PERROR(LOG_PRIORITY_FATAL);
- exit(EXIT_FAILURE);
- }
- }
- /**
- * Execute script to update network parameters received from responder
- *
- * @param argv Script to execute, along with additional parameters
- * @param cfg Configuration data
- * @param id ID used to represent client to VPN gateway
- * @param vpngw IP address of the VIP gateway (either IPv4 or IPv6)
- * @param interface Interface through which we established connection
- *
- * \return 0 if execution was successful, -1 otherwise
- */
- int cfg_client_exec_script(gchar **argv, struct cfg *cfg, struct id *id,
- struct netaddr *vpngw, gchar *interface)
- {
- GSList *c;
- pid_t pid;
- char buf[MAX_ENVLINE_LEN];
- char ipbuf[MAX_IPBUF_SIZE];
- char *p;
- pid_t status;
- gint retval;
- LOG_FUNC_START(1);
- retval = -1;
- pid = fork();
- if (pid < 0) {
- LOG_PERROR(LOG_PRIORITY_ERROR);
- goto out;
- }
- if (!pid) {
- /*
- * Child process should prepare environment and
- * execute startup script.
- */
- strcpy(buf, IKEV2_CLIENT_ENV_ID);
- strcat(buf, "=");
- p = id_id2str(id);
- strcat(buf, p);
- g_free(p);
- newenv(buf);
- if (vpngw) {
- if (netaddr_get_family(vpngw) == AF_INET)
- strcpy(buf, IKEV2_CLIENT_ENV_VPN_IP4_ADDR);
- else
- strcpy(buf, IKEV2_CLIENT_ENV_VPN_IP6_ADDR);
- strcat(buf, "=");
- netaddr_ip2str(vpngw, ipbuf, MAX_IPBUF_SIZE);
- strcat(buf, ipbuf);
- newenv(buf);
- }
- strcpy(buf, IKEV2_CLIENT_ENV_IF);
- strcat(buf, "=");
- strcat(buf, interface);
- newenv(buf);
- if (cfg->flags & OPTION_F4_ADDR) {
- /*
- * If there are IPv4 addresses put them into
- * environemnt variable
- */
- strcpy(buf, IKEV2_CLIENT_ENV_ADDR4);
- strcat(buf, "=");
- for (c = cfg->netaddrs; c; c = c->next) {
- if (netaddr_get_family(c->data) == AF_INET) {
- netaddr_ip2str(c->data, ipbuf,
- MAX_IPBUF_SIZE);
- strcat(buf, ipbuf);
- strcat(buf, " ");
- }
- }
- if (strlen(buf) > sizeof(IKEV2_CLIENT_ENV_ADDR4) + 1)
- newenv(buf);
- if (cfg->expiry4) {
- snprintf(buf, MAX_ENVLINE_LEN, "%s=%u",
- IKEV2_CLIENT_ENV_EXPIRES4,
- cfg->expiry4);
- newenv(buf);
- }
- }
- if (cfg->flags & OPTION_F4_NETMASK) {
- /*
- * If there are IPv4 addresses put them into
- * environemnt variable
- */
- strcpy(buf, IKEV2_CLIENT_ENV_NETMASK4);
- strcat(buf, "=");
- inet_ntop(AF_INET, (struct in_addr *)&cfg->netmask,
- buf + strlen(buf), MAX_ENVLINE_LEN - strlen(buf));
- if (strlen(buf) > sizeof(IKEV2_CLIENT_ENV_NETMASK4) + 1)
- newenv(buf);
- }
- if (cfg->flags & OPTION_F4_SUBNETS) {
- /*
- * If there are IPv4 addresses put them into
- * environemnt variable
- */
- strcpy(buf, IKEV2_CLIENT_ENV_SUBNETS4);
- strcat(buf, "=");
- for (c = cfg->subnets; c; c = c->next) {
- if (netaddr_get_family(c->data) == AF_INET) {
- netaddr_net2str(c->data, ipbuf,
- MAX_IPBUF_SIZE);
- strcat(buf, ipbuf);
- strcat(buf, " ");
- }
- }
- if (strlen(buf) > sizeof(IKEV2_CLIENT_ENV_SUBNETS4) + 1)
- newenv(buf);
- }
- if (cfg->flags & OPTION_F6_ADDR) {
- /*
- * If there are IPv4 addresses put them into
- * environemnt variable
- */
- strcpy(buf, IKEV2_CLIENT_ENV_ADDR6);
- strcat(buf, "=");
- for (c = cfg->netaddrs; c; c = c->next) {
- if (netaddr_get_family(c->data) == AF_INET6) {
- netaddr_ip2str(c->data, ipbuf,
- MAX_IPBUF_SIZE);
- strcat(buf, ipbuf);
- strcat(buf, " ");
- }
- }
- if (strlen(buf) > sizeof(IKEV2_CLIENT_ENV_ADDR6) + 1)
- newenv(buf);
- if (cfg->expiry6) {
- snprintf(buf, MAX_ENVLINE_LEN, "%s=%u",
- IKEV2_CLIENT_ENV_EXPIRES6,
- cfg->expiry6);
- newenv(buf);
- }
- }
- if (cfg->flags & OPTION_F6_SUBNETS) {
- /*
- * If there are IPv4 addresses put them into
- * environemnt variable
- */
- strcpy(buf, IKEV2_CLIENT_ENV_SUBNETS6);
- strcat(buf, "=");
- for (c = cfg->subnets; c; c = c->next) {
- if (netaddr_get_family(c->data) == AF_INET6) {
- netaddr_ip2str(c->data, ipbuf,
- MAX_IPBUF_SIZE);
- strcat(buf, ipbuf);
- strcat(buf, " ");
- }
- }
- if (strlen(buf) > sizeof(IKEV2_CLIENT_ENV_SUBNETS6) + 1)
- newenv(buf);
- }
- if (cfg->flags & OPTION_F4_DNS) {
- /*
- * If there are IPv4 addresses put them into
- * environemnt variable
- */
- strcpy(buf, IKEV2_CLIENT_ENV_DNS4);
- strcat(buf, "=");
- for (c = cfg->dns; c; c = c->next) {
- if (netaddr_get_family(c->data) == AF_INET) {
- netaddr_ip2str(c->data, ipbuf,
- MAX_IPBUF_SIZE);
- strcat(buf, ipbuf);
- strcat(buf, " ");
- }
- }
- if (strlen(buf) > sizeof(IKEV2_CLIENT_ENV_DNS4) + 1)
- newenv(buf);
- }
- if (cfg->flags & OPTION_F6_DNS) {
- /*
- * If there are IPv4 addresses put them into
- * environemnt variable
- */
- strcpy(buf, IKEV2_CLIENT_ENV_DNS6);
- strcat(buf, "=");
- for (c = cfg->dns; c; c = c->next) {
- if (netaddr_get_family(c->data) == AF_INET6) {
- netaddr_ip2str(c->data, ipbuf,
- MAX_IPBUF_SIZE);
- strcat(buf, ipbuf);
- strcat(buf, " ");
- }
- }
- if (strlen(buf) > sizeof(IKEV2_CLIENT_ENV_DNS6) + 1)
- newenv(buf);
- }
- if (cfg->flags & OPTION_F4_NBNS) {
- /*
- * If there are IPv4 addresses put them into
- * environemnt variable
- */
- strcpy(buf, IKEV2_CLIENT_ENV_NBNS);
- strcat(buf, "=");
- for (c = cfg->nbns; c; c = c->next) {
- if (netaddr_get_family(c->data) == AF_INET) {
- netaddr_ip2str(c->data, ipbuf,
- MAX_IPBUF_SIZE);
- strcat(buf, ipbuf);
- strcat(buf, " ");
- }
- }
- if (strlen(buf) > sizeof(IKEV2_CLIENT_ENV_NBNS) + 1)
- newenv(buf);
- }
- if (cfg->flags & OPTION_F4_DHCP) {
- /*
- * If there are IPv4 addresses put them into
- * environemnt variable
- */
- strcpy(buf, IKEV2_CLIENT_ENV_DHCP4);
- strcat(buf, "=");
- for (c = cfg->dhcp; c; c = c->next) {
- if (netaddr_get_family(c->data) == AF_INET) {
- netaddr_ip2str(c->data, ipbuf,
- MAX_IPBUF_SIZE);
- strcat(buf, ipbuf);
- strcat(buf, " ");
- }
- }
- if (strlen(buf) > sizeof(IKEV2_CLIENT_ENV_DHCP4) + 1)
- newenv(buf);
- }
- if (cfg->flags & OPTION_F6_DHCP) {
- /*
- * If there are IPv4 addresses put them into
- * environemnt variable
- */
- strcpy(buf, IKEV2_CLIENT_ENV_DHCP6);
- strcat(buf, "=");
- for (c = cfg->dhcp; c; c = c->next) {
- if (netaddr_get_family(c->data) == AF_INET6) {
- netaddr_ip2str(c->data, ipbuf,
- MAX_IPBUF_SIZE);
- strcat(buf, ipbuf);
- strcat(buf, " ");
- }
- }
- if (strlen(buf) > sizeof(IKEV2_CLIENT_ENV_DHCP6) + 1)
- newenv(buf);
- }
- execv(argv[0], argv);
- /*
- * If we reached this part then there was error in the
- * previous function.
- */
- LOG_PERROR(LOG_PRIORITY_ERROR);
- exit(1);
- }
- /*
- * Parent process should wait for the child process
- * and monitor return value...
- *
- * There is a potential DoS here. If the script never
- * returns then the IKEv2 will block!
- */
- wait(&status);
- /**
- * Check that script exited via exit call and that it
- * returned zero. This signals successful script run.
- */
- if (!WIFEXITED(status))
- LOG_ERROR("Script %s prematurely ended!", argv[0]);
- else if (WEXITSTATUS(status))
- LOG_ERROR("Script %s returned exit code %d",
- argv[0], WEXITSTATUS(status));
- else
- retval = 0;
- out:
- LOG_FUNC_END(1);
- return retval;
- }
- #endif /* CFG_CLIENT */