#include <haproxy/sample.h>
#include <haproxy/server.h>
#include <haproxy/session.h>
+#include <haproxy/ssl_ckch.h>
+#include <haproxy/ssl_sock.h>
#include <haproxy/stats-t.h>
#include <haproxy/stream.h>
#include <haproxy/stream_interface.h>
INITCALL1(STG_REGISTER, cfg_register_keywords, &cfg_kws);
+/*
+ * This function replace a ckch_store by another one, and rebuild the ckch_inst and all its dependencies.
+ * It does the sam as "cli_io_handler_commit_cert" but for lua, the major
+ * difference is that the yield in lua and for the CLI is not handled the same
+ * way.
+ */
+__LJMP static int hlua_ckch_commit_yield(lua_State *L, int status, lua_KContext ctx)
+{
+ struct ckch_inst **lua_ckchi = lua_touserdata(L, -1);
+ struct ckch_store **lua_ckchs = lua_touserdata(L, -2);
+ struct ckch_inst *ckchi = *lua_ckchi;
+ struct ckch_store *old_ckchs = lua_ckchs[0];
+ struct ckch_store *new_ckchs = lua_ckchs[1];
+ struct hlua *hlua;
+ char *err = NULL;
+ int y = 1;
+
+ hlua = hlua_gethlua(L);
+
+ /* get the first ckchi to copy */
+ if (ckchi == NULL)
+ ckchi = LIST_ELEM(old_ckchs->ckch_inst.n, typeof(ckchi), by_ckchs);
+
+ /* walk through the old ckch_inst and creates new ckch_inst using the updated ckchs */
+ list_for_each_entry_from(ckchi, &old_ckchs->ckch_inst, by_ckchs) {
+ struct ckch_inst *new_inst;
+
+ /* it takes a lot of CPU to creates SSL_CTXs, so we yield every 10 CKCH instances */
+ if (y % 10 == 0) {
+
+ *lua_ckchi = ckchi;
+
+ task_wakeup(hlua->task, TASK_WOKEN_MSG);
+ MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_ckch_commit_yield, TICK_ETERNITY, 0));
+ }
+
+ if (ckch_inst_rebuild(new_ckchs, ckchi, &new_inst, &err))
+ goto error;
+
+ /* link the new ckch_inst to the duplicate */
+ LIST_APPEND(&new_ckchs->ckch_inst, &new_inst->by_ckchs);
+ y++;
+ }
+
+ /* The generation is finished, we can insert everything */
+ ckch_store_replace(old_ckchs, new_ckchs);
+
+ lua_pop(L, 2); /* pop the lua_ckchs and ckchi */
+
+ HA_SPIN_UNLOCK(CKCH_LOCK, &ckch_lock);
+
+ return 0;
+
+error:
+ ckch_store_free(new_ckchs);
+ HA_SPIN_UNLOCK(CKCH_LOCK, &ckch_lock);
+ WILL_LJMP(luaL_error(L, "%s", err));
+ free(err);
+
+ return 0;
+}
+
+/*
+ * Replace a ckch_store <filename> in the ckchs_tree with a ckch_store created
+ * from the table in parameter.
+ *
+ * This is equivalent to "set ssl cert" + "commit ssl cert" over the CLI, which
+ * means it does not need to have a transaction since everything is done in the
+ * same function.
+ *
+ * CertCache.set{filename="", crt="", key="", sctl="", ocsp="", issuer=""}
+ *
+ */
+__LJMP static int hlua_ckch_set(lua_State *L)
+{
+ struct hlua *hlua;
+ struct ckch_inst **lua_ckchi;
+ struct ckch_store **lua_ckchs;
+ struct ckch_store *old_ckchs = NULL;
+ struct ckch_store *new_ckchs = NULL;
+ int errcode = 0;
+ char *err = NULL;
+ struct cert_exts *cert_ext = NULL;
+ char *filename;
+ struct cert_key_and_chain *ckch;
+ int ret;
+
+ if (lua_type(L, -1) != LUA_TTABLE)
+ WILL_LJMP(luaL_error(L, "'CertCache.set' needs a table as argument"));
+
+ hlua = hlua_gethlua(L);
+
+ /* FIXME: this should not return an error but should come back later */
+ if (HA_SPIN_TRYLOCK(CKCH_LOCK, &ckch_lock))
+ WILL_LJMP(luaL_error(L, "CertCache already under lock"));
+
+ ret = lua_getfield(L, -1, "filename");
+ if (ret != LUA_TSTRING) {
+ memprintf(&err, "%sNo filename specified!\n", err ? err : "");
+ errcode |= ERR_ALERT | ERR_FATAL;
+ goto end;
+ }
+ filename = (char *)lua_tostring(L, -1);
+
+
+ /* look for the filename in the tree */
+ old_ckchs = ckchs_lookup(filename);
+ if (!old_ckchs) {
+ memprintf(&err, "%sCan't replace a certificate which is not referenced by the configuration!\n", err ? err : "");
+ errcode |= ERR_ALERT | ERR_FATAL;
+ goto end;
+ }
+ /* TODO: handle extra_files_noext */
+
+ new_ckchs = ckchs_dup(old_ckchs);
+ if (!new_ckchs) {
+ memprintf(&err, "%sCannot allocate memory!\n", err ? err : "");
+ errcode |= ERR_ALERT | ERR_FATAL;
+ goto end;
+ }
+
+ ckch = new_ckchs->ckch;
+
+ /* loop on the field in the table, which have the same name as the
+ * possible extensions of files */
+ lua_pushnil(L);
+ while (lua_next(L, 1)) {
+ int i;
+ const char *field = lua_tostring(L, -2);
+ char *payload = (char *)lua_tostring(L, -1);
+
+ if (!field || strcmp(field, "filename") == 0) {
+ lua_pop(L, 1);
+ continue;
+ }
+
+ for (i = 0; field && cert_exts[i].ext != NULL; i++) {
+ if (strcmp(field, cert_exts[i].ext) == 0) {
+ cert_ext = &cert_exts[i];
+ break;
+ }
+ }
+
+ /* this is the default type, the field is not supported */
+ if (cert_ext == NULL) {
+ memprintf(&err, "%sUnsupported field '%s'\n", err ? err : "", field);
+ errcode |= ERR_ALERT | ERR_FATAL;
+ goto end;
+ }
+
+ /* appply the change on the duplicate */
+ if (cert_exts->load(filename, payload, ckch, &err) != 0) {
+ memprintf(&err, "%sCan't load the payload\n", err ? err : "");
+ errcode |= ERR_ALERT | ERR_FATAL;
+ goto end;
+ }
+ lua_pop(L, 1);
+ }
+
+ /* store the pointers on the lua stack */
+ lua_ckchs = lua_newuserdata(L, sizeof(struct ckch_store *) * 2);
+ lua_ckchs[0] = old_ckchs;
+ lua_ckchs[1] = new_ckchs;
+ lua_ckchi = lua_newuserdata(L, sizeof(struct ckch_inst *));
+ *lua_ckchi = NULL;
+
+ task_wakeup(hlua->task, TASK_WOKEN_MSG);
+ MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_ckch_commit_yield, TICK_ETERNITY, 0));
+
+end:
+ HA_SPIN_UNLOCK(CKCH_LOCK, &ckch_lock);
+
+ if (errcode & ERR_CODE) {
+ ckch_store_free(new_ckchs);
+ WILL_LJMP(luaL_error(L, "%s", err));
+ }
+ free(err);
+
+ return 0;
+}
+
/* This function can fail with an abort() due to an Lua critical error.
* We are in the initialisation process of HAProxy, this abort() is
* tolerated.
/* Set a name to the table. */
lua_setglobal(L, "Map");
+ /*
+ *
+ * Register "CertCache" class
+ *
+ */
+
+ /* Create and fill the metatable. */
+ lua_newtable(L);
+ /* Register */
+ hlua_class_function(L, "set", hlua_ckch_set);
+ lua_setglobal(L, CLASS_CERTCACHE); /* Create global object called Regex */
+
/*
*
* Register class Channel