Conditional compilation for UNIX specific libraries

Add TLS configuration parsing
This commit is contained in:
Ahmed Yarub Hani Al Nuaimi
2021-09-04 12:49:02 -03:00
parent fb28bbfc34
commit 00c9cedf59
11 changed files with 221 additions and 119 deletions

View File

@@ -10,7 +10,9 @@ extern "C" {
#include <malloc.h>
#include <stdio.h>
#include <errno.h>
#ifndef _WIN32
#include <unistd.h>
#endif
#include <pthread.h>
#include <apiClient.h>
#include <CoreV1API.h>

View File

@@ -0,0 +1,5 @@
find_package(OpenSSL REQUIRED)
find_package(ZLIB REQUIRED)
find_package(yaml CONFIG REQUIRED)
include("${CMAKE_CURRENT_LIST_DIR}/@pkgName@Targets.cmake")

View File

@@ -1,7 +1,9 @@
#include "authn_plugin.h"
#include <stdio.h>
#include <stdlib.h>
#ifndef _WIN32
#include <dlfcn.h>
#endif
#include <errno.h>
#define PLUGIN_NAME_TEMPLATE "libkubernetes_%s.so"
@@ -15,6 +17,7 @@ authn_plugin_t *create_authn_plugin(const char *name)
{
static char fname[] = "create_authn_plugin()";
#ifndef _WIN32
authn_plugin_t *plugin = calloc(1, sizeof(authn_plugin_t));
if (!plugin) {
fprintf(stderr, "%s: Cannot allocate memory for plugin library %s.[%s]\n", fname, name, strerror(errno));
@@ -51,10 +54,13 @@ authn_plugin_t *create_authn_plugin(const char *name)
return plugin;
error:
error:
free_authn_plugin(plugin);
plugin = NULL;
return plugin;
#else
return NULL;
#endif
}
void free_authn_plugin(authn_plugin_t * plugin)
@@ -64,7 +70,9 @@ void free_authn_plugin(authn_plugin_t * plugin)
}
if (plugin->dlhandler) {
#ifndef _WIN32
dlclose(plugin->dlhandler);
#endif
plugin->dlhandler = NULL;
}

View File

@@ -28,7 +28,12 @@ int kube_exec_and_get_result(ExecCredential_t * exec_credential, const kubeconfi
for (int i = 0; i < exec->envs_count; i++) {
keyValuePair_t *pair = exec->envs[i];
if (pair && pair->key && pair->value) {
#ifndef _WIN32
rc = setenv(pair->key, (char *) (pair->value), 1); /* 1 means to overwrite the existing environment variable */
#else
rc = _putenv_s(pair->key, (char *) (pair->value));
#endif
if (0 != rc) {
fprintf(stderr, "%s: Cannot set environment variable %s=%s.[%s]\n", fname, pair->key, (char *) (pair->value), strerror(errno));
return -1;
@@ -61,7 +66,11 @@ int kube_exec_and_get_result(ExecCredential_t * exec_credential, const kubeconfi
char *result_string = NULL;
FILE *fp = NULL;
#ifndef _WIN32
fp = popen(command_string, "r"); /* r means read from stdout */
#else
fp = _popen(command_string, "r"); /* r means read from stdout */
#endif
if (fp) {
result_string = calloc(1, KUBECONFIG_EXEC_RESULT_BUFFER_SIZE);
if (!result_string) {
@@ -81,7 +90,11 @@ int kube_exec_and_get_result(ExecCredential_t * exec_credential, const kubeconfi
strncat(result_string, string_buf, strlen(string_buf));
memset(string_buf, 0, sizeof(string_buf));
}
#ifndef _WIN32
pclose(fp);
#else
_pclose(fp);
#endif
} else {
fprintf(stderr, "%s: Cannot open pipe to run command.[%s]\n", fname, strerror(errno));
return -1;
@@ -89,7 +102,7 @@ int kube_exec_and_get_result(ExecCredential_t * exec_credential, const kubeconfi
rc = kubeyaml_parse_exec_crendential(exec_credential, result_string);
end:
end:
if (result_string) {
free(result_string);
}

View File

@@ -1,6 +1,8 @@
#define _GNU_SOURCE
#include <stdlib.h>
#ifndef _WIN32
#include <unistd.h>
#endif
#include <sys/stat.h>
#include <errno.h>
#include "incluster_config.h"
@@ -24,15 +26,15 @@ static int checkServiceAccountFile(const char *fileName)
struct stat info;
if (-1 == stat(fileName, &info)) {
switch (errno) {
case ENOENT:
fprintf(stderr, "%s: The file %s does not exist.[%s]\n", fname, fileName, strerror(errno));
return -1;
case EACCES:
fprintf(stderr, "%s: No permission to read the file %s.[%s]\n", fname, fileName, strerror(errno));
return -1;
default:
fprintf(stderr, "%s: Cannot retrieve the information of file %s.[%s]\n", fname, fileName, strerror(errno));
return -1;
case ENOENT:
fprintf(stderr, "%s: The file %s does not exist.[%s]\n", fname, fileName, strerror(errno));
return -1;
case EACCES:
fprintf(stderr, "%s: No permission to read the file %s.[%s]\n", fname, fileName, strerror(errno));
return -1;
default:
fprintf(stderr, "%s: Cannot retrieve the information of file %s.[%s]\n", fname, fileName, strerror(errno));
return -1;
}
}
@@ -43,13 +45,21 @@ static int setBasePathInCluster(char **pBasePath)
{
static char fname[] = "setBasePathInCluster()";
#ifndef _WIN32
const char *service_host_env = secure_getenv(SERVICE_HOST_ENV_NAME);
#else
const char *service_host_env = getenv(SERVICE_HOST_ENV_NAME);
#endif
if (!service_host_env) {
fprintf(stderr, "%s: Cannot retrieve the kubernetes service host inside a pod by the env %s.\n", fname, SERVICE_HOST_ENV_NAME);
return -1;
}
#ifndef _WIN32
const char *service_port_env = secure_getenv(SERVICE_PORT_ENV_NAME);
#else
const char *service_port_env = getenv(SERVICE_PORT_ENV_NAME);
#endif
if (!service_port_env) {
fprintf(stderr, "%s: Cannot retrieve the kubernetes service port inside a pod by the env %s.\n", fname, SERVICE_PORT_ENV_NAME);
return -1;

View File

@@ -1,7 +1,11 @@
#define _GNU_SOURCE
#include <stdlib.h>
#include <errno.h>
#ifndef _WIN32
#include <unistd.h>
#include <libgen.h>
#endif
#include <string.h>
#include <libgen.h>
#include <stdbool.h>
@@ -13,7 +17,12 @@
#include "authn_plugin/authn_plugin.h"
#define ENV_KUBECONFIG "KUBECONFIG"
#ifndef _WIN32
#define ENV_HOME "HOME"
#else
#define ENV_HOME "USERPROFILE"
#endif
#define KUBE_CONFIG_DEFAULT_LOCATION "%s/.kube/config"
static int setBasePath(char **pBasePath, char *basePath)
@@ -41,10 +50,10 @@ static int setSslConfig(sslConfig_t ** pSslConfig, const kubeconfig_property_t *
if (user->client_key_data) {
client_key_file = kubeconfig_mk_cert_key_tempfile(user->client_key_data);
}
insecure_skip_tls_verify = user->insecure_skip_tls_verify;
}
if (cluster) {
insecure_skip_tls_verify = cluster->insecure_skip_tls_verify;
if ((0 == insecure_skip_tls_verify) && (cluster->certificate_authority_data)) {
ca_file = kubeconfig_mk_cert_key_tempfile(cluster->certificate_authority_data);
}
@@ -99,11 +108,19 @@ static char *getWorkingConfigFile(const char *configFileNamePassedIn)
if (configFileNamePassedIn) {
configFileName = strdup(configFileNamePassedIn);
} else {
#ifndef _WIN32
kubeconfig_env = secure_getenv(ENV_KUBECONFIG);
#else
kubeconfig_env = getenv(ENV_KUBECONFIG);
#endif
if (kubeconfig_env) {
configFileName = strdup(kubeconfig_env);
} else {
#ifndef _WIN32
homedir_env = secure_getenv(ENV_HOME);
#else
homedir_env = getenv(ENV_HOME);
#endif
if (homedir_env) {
int configFileNameSize = strlen(homedir_env) + strlen(KUBE_CONFIG_DEFAULT_LOCATION) + 1;
configFileName = calloc(configFileNameSize, sizeof(char));
@@ -167,7 +184,7 @@ static int kubeconfig_exec(kubeconfig_property_t * current_user)
goto end;
}
end:
end:
exec_credential_free(exec_output);
exec_output = NULL;
return rc;
@@ -184,13 +201,30 @@ static int kubeconfig_update_exec_command_path(kubeconfig_property_t * exec, con
char *kube_config_file_copy = NULL;
char *original_command = NULL;
#ifndef _WIN32
if ('/' != exec->command[0]) { // relative path e.g. "./bin/" or "bin/"
#else
if (':' != exec->command[1]) { // relative path e.g. ".\bin\" or "bin\"
#endif
kube_config_file_copy = strdup(kube_config_file);
if (NULL == kube_config_file_copy) {
fprintf(stderr, "%s: Cannot allocate memory for temp kube config file name.[%s]\n", fname, strerror(errno));
return -1;
}
#ifndef _WIN32
const char *kube_config_dirname = dirname(kube_config_file_copy);
#else
char drive[_MAX_DRIVE];
char dir[_MAX_DIR];
char fname[_MAX_FNAME];
char ext[_MAX_EXT];
_splitpath(kube_config_file_copy, drive, dir, fname, ext);
const char *kube_config_dirname;
_makepath(kube_config_dirname, drive, dir, NULL, NULL);
#endif
original_command = exec->command;
int new_command_length = strlen(kube_config_dirname) + strlen("/") + strlen(original_command) + 1 /* 1 for the terminal of string */ ;
exec->command = calloc(1, new_command_length);
@@ -334,7 +368,7 @@ int load_kube_config(char **pBasePath, sslConfig_t ** pSslConfig, list_t ** pApi
}
}
if (current_cluster || current_user) {
if (current_cluster) {
rc = setSslConfig(pSslConfig, current_cluster, current_user);
if (0 != rc) {
fprintf(stderr, "%s: Cannot set the SSL Configuration for the client.\n", fname);

View File

@@ -7,113 +7,113 @@
extern "C" {
#endif
typedef enum ExecCredential_type_t {
EXEC_CREDENTIAL_TYPE_TOKEN = 1,
EXEC_CREDENTIAL_TYPE_CLIENT_CERT
} ExecCredential_type_t;
typedef enum ExecCredential_type_t {
EXEC_CREDENTIAL_TYPE_TOKEN = 1,
EXEC_CREDENTIAL_TYPE_CLIENT_CERT
} ExecCredential_type_t;
typedef struct ExecCredential_status_t {
ExecCredential_type_t type;
union {
struct {
char *token;
};
struct {
char *clientCertificateData;
char *clientKeyData;
};
typedef struct ExecCredential_status_t {
ExecCredential_type_t type;
union {
struct {
char *token;
};
} ExecCredential_status_t;
typedef struct ExecCredential_t {
char *apiVersion;
char *kind;
ExecCredential_status_t *status;
} ExecCredential_t;
typedef enum kubeconfig_property_type_t {
KUBECONFIG_PROPERTY_TYPE_CONTEXT = 1,
KUBECONFIG_PROPERTY_TYPE_CLUSTER,
KUBECONFIG_PROPERTY_TYPE_USER,
KUBECONFIG_PROPERTY_TYPE_USER_EXEC,
KUBECONFIG_PROPERTY_TYPE_USER_AUTH_PROVIDER
} kubeconfig_property_type_t;
typedef struct kubeconfig_property_t {
kubeconfig_property_type_t type;
char *name;
union {
struct { /* context */
char *cluster;
char *namespace;
char *user;
};
struct { /* cluster */
char *server;
char *certificate_authority_data;
};
struct { /* user */
char *token;
char *client_certificate_data;
char *client_key_data;
struct kubeconfig_property_t *auth_provider;
struct kubeconfig_property_t *exec;
int insecure_skip_tls_verify;
char *username;
char *password;
};
struct { /* user exec */
char *command;
char *apiVersion;
keyValuePair_t **envs;
int envs_count;
char **args;
int args_count;
};
struct { /* user auth provider */
char *access_token;
char *client_id;
char *client_secret;
char *cmd_path;
char *expires_on;
char *expiry;
char *id_token;
char *idp_certificate_authority;
char *idp_certificate_authority_data;
char *idp_issuer_url;
char *refresh_token;
};
struct {
char *clientCertificateData;
char *clientKeyData;
};
} kubeconfig_property_t;
};
} ExecCredential_status_t;
typedef struct kubeconfig_t {
char *fileName;
char *apiVersion;
char *preferences;
char *kind;
char *current_context;
kubeconfig_property_t **contexts;
int contexts_count;
kubeconfig_property_t **clusters;
int clusters_count;
kubeconfig_property_t **users;
int users_count;
} kubeconfig_t;
typedef struct ExecCredential_t {
char *apiVersion;
char *kind;
ExecCredential_status_t *status;
} ExecCredential_t;
ExecCredential_t *exec_credential_create();
void exec_credential_free(ExecCredential_t *);
typedef enum kubeconfig_property_type_t {
KUBECONFIG_PROPERTY_TYPE_CONTEXT = 1,
KUBECONFIG_PROPERTY_TYPE_CLUSTER,
KUBECONFIG_PROPERTY_TYPE_USER,
KUBECONFIG_PROPERTY_TYPE_USER_EXEC,
KUBECONFIG_PROPERTY_TYPE_USER_AUTH_PROVIDER
} kubeconfig_property_type_t;
ExecCredential_status_t *exec_credential_status_create();
void exec_credential_status_free(ExecCredential_status_t *);
typedef struct kubeconfig_property_t {
kubeconfig_property_type_t type;
char *name;
union {
struct { /* context */
char *cluster;
char *namespace;
char *user;
};
struct { /* cluster */
char *server;
char *certificate_authority_data;
int insecure_skip_tls_verify;
};
struct { /* user */
char *token;
char *client_certificate_data;
char *client_key_data;
struct kubeconfig_property_t *auth_provider;
struct kubeconfig_property_t *exec;
char *username;
char *password;
};
struct { /* user exec */
char *command;
char *apiVersion;
keyValuePair_t **envs;
int envs_count;
char **args;
int args_count;
};
struct { /* user auth provider */
char *access_token;
char *client_id;
char *client_secret;
char *cmd_path;
char *expires_on;
char *expiry;
char *id_token;
char *idp_certificate_authority;
char *idp_certificate_authority_data;
char *idp_issuer_url;
char *refresh_token;
};
};
} kubeconfig_property_t;
kubeconfig_property_t *kubeconfig_property_create(kubeconfig_property_type_t type);
void kubeconfig_property_free(kubeconfig_property_t * property);
typedef struct kubeconfig_t {
char *fileName;
char *apiVersion;
char *preferences;
char *kind;
char *current_context;
kubeconfig_property_t **contexts;
int contexts_count;
kubeconfig_property_t **clusters;
int clusters_count;
kubeconfig_property_t **users;
int users_count;
} kubeconfig_t;
kubeconfig_property_t **kubeconfig_properties_create(int contexts_count, kubeconfig_property_type_t type);
void kubeconfig_properties_free(kubeconfig_property_t ** properties, int properties_count);
ExecCredential_t *exec_credential_create();
void exec_credential_free(ExecCredential_t *);
kubeconfig_t *kubeconfig_create();
void kubeconfig_free(kubeconfig_t * kubeconfig);
ExecCredential_status_t *exec_credential_status_create();
void exec_credential_status_free(ExecCredential_status_t *);
kubeconfig_property_t *kubeconfig_property_create(kubeconfig_property_type_t type);
void kubeconfig_property_free(kubeconfig_property_t * property);
kubeconfig_property_t **kubeconfig_properties_create(int contexts_count, kubeconfig_property_type_t type);
void kubeconfig_properties_free(kubeconfig_property_t ** properties, int properties_count);
kubeconfig_t *kubeconfig_create();
void kubeconfig_free(kubeconfig_t * kubeconfig);
#ifdef __cplusplus
}

View File

@@ -3,7 +3,14 @@
#include <stdbool.h>
#include <string.h>
#include <stdlib.h>
#ifndef _WIN32
#include <unistd.h>
#define KUBE_CONFIG_TEMPFILE_NAME_TEMPLATE "/tmp/kubeconfig-XXXXXX"
#else
#include <io.h>
#include <fcntl.h>
#define KUBE_CONFIG_TEMPFILE_NAME_TEMPLATE "%s\\kubeconfig-XXXXXX"
#endif
#include "../include/apiClient.h"
#define KUBE_CONFIG_TEMPFILE_NAME_TEMPLATE "/tmp/kubeconfig-XXXXXX"
@@ -39,21 +46,33 @@ char *kubeconfig_mk_cert_key_tempfile(const char *data)
cert_key_data_bytes = strlen(cert_key_data);
}
#ifndef _WIN32
char tempfile_name_template[] = KUBE_CONFIG_TEMPFILE_NAME_TEMPLATE;
int fd = mkstemp(tempfile_name_template);
#else
char *tempdir_env = getenv("TEMP");
int tmpFileNameSize = strlen(tempdir_env) + strlen(KUBE_CONFIG_TEMPFILE_NAME_TEMPLATE) + 1;
char *tempfile_name_template = calloc(tmpFileNameSize, sizeof(char));
snprintf(tempfile_name_template, tmpFileNameSize, KUBE_CONFIG_TEMPFILE_NAME_TEMPLATE, tempdir_env);
char *filename = _mktemp(tempfile_name_template);
int fd = _sopen( filename, O_CREAT|O_WRONLY, _SH_DENYWR );
#endif
if (-1 == fd) {
fprintf(stderr, "%s: Creating temp file for kubeconfig failed with error [%s]\n", fname, strerror(errno));
free(tempfile_name_template);
return NULL;
}
int rc = write(fd, cert_key_data, cert_key_data_bytes);
close(fd);
int rc = _write(fd, cert_key_data, cert_key_data_bytes);
_close(fd);
if (true == is_data_base64_encoded && cert_key_data) {
free((char *) cert_key_data); // cast "const char *" to "char *"
free((char *) cert_key_data); // cast "const char *" to "char *"
cert_key_data = NULL;
}
if (-1 == rc) {
fprintf(stderr, "%s: Writing temp file failed with error [%s]\n", fname, strerror(errno));
free(tempfile_name_template);
return NULL;
}

View File

@@ -44,6 +44,7 @@ mapping :: = MAPPING - START(node node) * MAPPING - END
#define KEY_USER_AUTH_PROVIDER_CONFIG_IDP_ISSUE_URL "idp-issuer-url"
#define KEY_USER_AUTH_PROVIDER_CONFIG_REFRESH_TOKEN "refresh-token"
#define KEY_CERTIFICATE_AUTHORITY_DATA "certificate-authority-data"
#define KEY_INSECURE_SKIP_TLS_VERIFY "insecure-skip-tls-verify"
#define KEY_SERVER "server"
#define KEY_CLIENT_CERTIFICATE_DATA "client-certificate-data"
#define KEY_CLIENT_KEY_DATA "client-key-data"
@@ -186,6 +187,8 @@ static int parse_kubeconfig_yaml_property_mapping(kubeconfig_property_t * proper
property->certificate_authority_data = strdup(value->data.scalar.value);
} else if (0 == strcmp(key->data.scalar.value, KEY_SERVER)) {
property->server = strdup(value->data.scalar.value);
} else if (0 == strcmp(key->data.scalar.value, KEY_INSECURE_SKIP_TLS_VERIFY)) {
property->insecure_skip_tls_verify = (0 == strcmp(value->data.scalar.value, "true")); //libyaml fails to parse true, but it can parse "true"!
}
} else if (KUBECONFIG_PROPERTY_TYPE_USER == property->type) {
if (0 == strcmp(key->data.scalar.value, KEY_CLIENT_CERTIFICATE_DATA)) {

View File

@@ -7,6 +7,9 @@
extern "C" {
#endif
#undef stdin
#undef stdout
int kube_exec(wsclient_t * wsc, const char *namespace_, const char *pod_name, const char *container_name, int stdin, int stdout, int tty, const char *command);
#ifdef __cplusplus

View File

@@ -2,7 +2,9 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifndef _WIN32
#include <unistd.h>
#endif
#include <fcntl.h>
#include <stdbool.h>
@@ -143,7 +145,7 @@ static void connect_client(lws_sorted_usec_list_t * sul)
i.host = i.address;
i.origin = i.address;
i.ssl_connection = wsc->ssl_config ? LCCSCF_USE_SSL : 0;
//i.protocol = pro;
//i.local_protocol_name = "websocket-client";
i.pwsi = &wsc->wsi;
@@ -186,8 +188,8 @@ static int callback_wsclient(struct lws *wsi, enum lws_callback_reasons reason,
lwsl_user("%s: The first char of data received is not STDOUT.\n", __func__);
return 0;
}
/*
* The first character of data received from
/*
* The first character of data received from
* the kubernets API server is "STDOUT",
* we ignore it
*/
@@ -271,11 +273,13 @@ static void read_from_stdin(wsclient_t * wsc)
char wsc_attach_stdin_buffer[WSC_ATTACH_STDIN_BUFFER_SIZE];
memset(wsc_attach_stdin_buffer, 0, sizeof(wsc_attach_stdin_buffer));
#ifndef _WIN32
int flag, newflag;
flag = fcntl(STDIN_FILENO, F_GETFL);
newflag = flag | O_NONBLOCK;
fcntl(STDIN_FILENO, F_SETFL, newflag);
fgets(wsc_attach_stdin_buffer, sizeof(wsc_attach_stdin_buffer) - 1, stdin);
#endif
if (wsc_attach_stdin_buffer && strlen(wsc_attach_stdin_buffer) > 0) {
wsc->data_to_send_len = strlen(wsc_attach_stdin_buffer) + 1 /* TTY_STDIN_NUMBER */ ;
@@ -283,8 +287,9 @@ static void read_from_stdin(wsclient_t * wsc)
wsc->data_to_send[LWS_PRE] = TTY_STDIN_NUMBER;
strncpy(wsc->data_to_send + LWS_PRE + 1, wsc_attach_stdin_buffer, strlen(wsc_attach_stdin_buffer));
}
#ifndef _WIN32
fcntl(STDIN_FILENO, F_SETFL, flag);
#endif
}
int wsclient_run(wsclient_t * wsc, wsc_mode_t mode)