#include <talloc.h>
static uint32_t instance_count = 0;
+static fr_dict_t const *dict_freeradius; /*internal dictionary for server*/
+extern fr_dict_autoload_t rlm_imap_dict[];
+fr_dict_autoload_t rlm_imap_dict[] = {
+ { .out = &dict_freeradius, .proto = "freeradius" },
+ { NULL }
+};
/** Initialise global curl options
*
* libcurl is meant to performa reference counting, but still seems to
#ifdef WITH_TLS
fr_openssl_free();
#endif
-
curl_global_cleanup();
}
+
+int fr_curl_easy_tls_init (fr_curl_io_request_t *randle, fr_curl_tls_t *conf)
+{
+ REQUEST *request = randle->request;
+
+ if (conf->tls_certificate_file) FR_CURL_SET_OPTION(CURLOPT_SSLCERT, conf->tls_certificate_file);
+ if (conf->tls_private_key_file) FR_CURL_SET_OPTION(CURLOPT_SSLKEY, conf->tls_private_key_file);
+ if (conf->tls_private_key_password) FR_CURL_SET_OPTION(CURLOPT_KEYPASSWD, conf->tls_private_key_password);
+ if (conf->tls_ca_file) FR_CURL_SET_OPTION(CURLOPT_CAINFO, conf->tls_ca_file);
+ if (conf->tls_ca_issuer_file) FR_CURL_SET_OPTION(CURLOPT_ISSUERCERT, conf->tls_ca_issuer_file);
+ if (conf->tls_ca_path) FR_CURL_SET_OPTION(CURLOPT_CAPATH, conf->tls_ca_path);
+ if (conf->tls_random_file) FR_CURL_SET_OPTION(CURLOPT_RANDOM_FILE, conf->tls_random_file);
+
+ FR_CURL_SET_OPTION(CURLOPT_SSL_VERIFYPEER, (conf->tls_check_cert == true) ? 1L : 0L);
+ FR_CURL_SET_OPTION(CURLOPT_SSL_VERIFYHOST, (conf->tls_check_cert_cn == true) ? 2L : 0L);
+
+ return 0;
+error:
+ return -1;
+}
+
+int fr_curl_response_certinfo(REQUEST *request, fr_curl_io_request_t *randle)
+{
+ CURL *candle = randle->candle;
+ CURLcode ret;
+ int i;
+ char buffer[265];
+ char *p , *q, *attr = buffer;
+ fr_cursor_t cursor, list;
+ VALUE_PAIR *cert_vps = NULL;
+ /*
+ * Examples and documentation show cert_info being
+ * a struct curl_certinfo *, but CPP checks require
+ * it to be a struct curl_slist *.
+ *
+ * https://curl.haxx.se/libcurl/c/certinfo.html
+ */
+ union {
+ struct curl_slist *to_info;
+ struct curl_certinfo *to_certinfo;
+ } ptr;
+ ptr.to_info = NULL;
+
+ fr_cursor_init(&list, &request->packet->vps);
+
+ ret = curl_easy_getinfo(candle, CURLINFO_CERTINFO, &ptr.to_info);
+ if (ret != CURLE_OK) {
+ REDEBUG("Getting certificate info failed: %i - %s", ret, curl_easy_strerror(ret));
+
+ return -1;
+ }
+
+ attr += strlcpy(attr, "TLS-Cert-", sizeof(buffer));
+
+ RDEBUG2("Chain has %i certificate(s)", ptr.to_certinfo->num_of_certs);
+ for (i = 0; i < ptr.to_certinfo->num_of_certs; i++) {
+ struct curl_slist *cert_attrs;
+
+ RDEBUG2("Processing certificate %i",i);
+ fr_cursor_init(&cursor, &cert_vps);
+
+ for (cert_attrs = ptr.to_certinfo->certinfo[i];
+ cert_attrs;
+ cert_attrs = cert_attrs->next) {
+ VALUE_PAIR *vp;
+ fr_dict_attr_t const *da;
+
+ q = strchr(cert_attrs->data, ':');
+ if (!q) {
+ RWDEBUG("Malformed certinfo from libcurl: %s", cert_attrs->data);
+ continue;
+ }
+
+ strlcpy(attr, cert_attrs->data, (q - cert_attrs->data) + 1);
+ for (p = attr; *p != '\0'; p++) if (*p == ' ') *p = '-';
+
+ da = fr_dict_attr_by_name(dict_freeradius, buffer);
+ if (!da) {
+ RDEBUG3("Skipping %s += '%s'", buffer, q + 1);
+ RDEBUG3("If this value is required, define attribute \"%s\"", buffer);
+ continue;
+ }
+ MEM(vp = fr_pair_afrom_da(request->packet, da));
+ fr_pair_value_from_str(vp, q + 1, -1, '\0', true);
+
+ fr_cursor_append(&cursor, vp);
+ }
+ /*
+ * Add a copy of the cert_vps to session state.
+ *
+ * Both PVS studio and Coverity detect the condition
+ * below as logically dead code unless we explicitly
+ * set cert_vps. This is because they're too dumb
+ * to realise that the cursor argument passed to
+ * tls_session_pairs_from_x509_cert contains a
+ * reference to cert_vps.
+ */
+ cert_vps = fr_cursor_current(&cursor);
+ if (cert_vps) {
+ /*
+ * Print out all the pairs we have so far
+ */
+ log_request_pair_list(L_DBG_LVL_2, request, cert_vps, NULL);
+ fr_cursor_merge(&list, &cursor);
+ cert_vps = NULL;
+ }
+ }
+ return 0;
+}
+
+CONF_PARSER fr_curl_tls_config[] = {
+ { FR_CONF_OFFSET("ca_file", FR_TYPE_FILE_INPUT, fr_curl_tls_t, tls_ca_file) },
+ { FR_CONF_OFFSET("ca_issuer_file", FR_TYPE_FILE_INPUT, fr_curl_tls_t, tls_ca_issuer_file) },
+ { FR_CONF_OFFSET("ca_path", FR_TYPE_FILE_INPUT, fr_curl_tls_t, tls_ca_path) },
+ { FR_CONF_OFFSET("certificate_file", FR_TYPE_FILE_INPUT, fr_curl_tls_t, tls_certificate_file) },
+ { FR_CONF_OFFSET("private_key_file", FR_TYPE_FILE_INPUT, fr_curl_tls_t, tls_private_key_file) },
+ { FR_CONF_OFFSET("private_key_password", FR_TYPE_STRING | FR_TYPE_SECRET, fr_curl_tls_t, tls_private_key_password) },
+ { FR_CONF_OFFSET("random_file", FR_TYPE_STRING, fr_curl_tls_t, tls_random_file) },
+ { FR_CONF_OFFSET("check_cert", FR_TYPE_BOOL, fr_curl_tls_t, tls_check_cert), .dflt = "yes" },
+ { FR_CONF_OFFSET("check_cert_cn", FR_TYPE_BOOL, fr_curl_tls_t, tls_check_cert_cn), .dflt = "yes" },
+ { FR_CONF_OFFSET("extract_cert_attrs", FR_TYPE_BOOL, fr_curl_tls_t, tls_extract_cert_attrs), .dflt = "no" },
+ CONF_PARSER_TERMINATOR
+};
#include <curl/curl.h>
#include <freeradius-devel/server/request.h>
#include <freeradius-devel/util/event.h>
+#include <freeradius-devel/server/module.h>
+
+DIAG_OPTIONAL
+DIAG_OFF(disabled-macro-expansion)
+#define FR_CURL_SET_OPTION(_x, _y)\
+do {\
+ int _ret;\
+ if ((_ret = curl_easy_setopt(randle->candle, _x, _y)) != CURLE_OK) {\
+ char const *_option;\
+ _option = STRINGIFY(_x);\
+ ROPTIONAL(RERROR, ERROR, "Failed setting curl option %s: %s (%i)", _option, curl_easy_strerror(_ret), _ret);\
+ goto error;\
+ }\
+} while (0)
/** Uctx data for timer and I/O functions
*
void *uctx; //!< Private data for the module using the API.
} fr_curl_io_request_t;
+typedef struct {
+ char const *tls_certificate_file;
+ char const *tls_private_key_file;
+ char const *tls_private_key_password;
+ char const *tls_ca_file;
+ char const *tls_ca_issuer_file;
+ char const *tls_ca_path;
+ char const *tls_random_file;
+ bool tls_check_cert;
+ bool tls_check_cert_cn;
+ bool tls_extract_cert_attrs;
+} fr_curl_tls_t;
+
+extern CONF_PARSER fr_curl_tls_config[];
+
int fr_curl_io_request_enqueue(fr_curl_handle_t *mhandle,
REQUEST *request, fr_curl_io_request_t *creq);
void fr_curl_free(void);
+int fr_curl_response_certinfo(REQUEST *request, fr_curl_io_request_t *randle);
+
+int fr_curl_easy_tls_init (fr_curl_io_request_t *randle, fr_curl_tls_t *conf);
+
#ifdef __cplusplus
}
#endif