blob: c8c2c61832999bac3d1358b28577e2256cb93605 [file]
/* Copyright 2019 greenbytes GmbH (https://www.greenbytes.de)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdio.h>
#include <stdlib.h>
#include <apr_lib.h>
#include <apr_buckets.h>
#include <apr_getopt.h>
#include <apr_hash.h>
#include <apr_strings.h>
#include "md.h"
#include "md_json.h"
#include "md_http.h"
#include "md_log.h"
#include "md_reg.h"
#include "md_store.h"
#include "md_util.h"
#include "md_cmd.h"
#include "md_cmd_store.h"
/**************************************************************************************************/
/* command: store add */
static apr_status_t cmd_add(md_cmd_ctx *ctx, const md_cmd_t *cmd)
{
md_t *md, *nmd;
apr_status_t rv;
(void)cmd;
md = md_create(ctx->p, md_cmd_gather_args(ctx, 0));
if (md->domains->nelts == 0) {
return APR_EINVAL;
}
md->ca_urls = NULL;
if (ctx->ca_url) {
md->ca_urls = apr_array_make(ctx->p, 3, sizeof(const char*));
APR_ARRAY_PUSH(md->ca_urls, const char*) = ctx->ca_url;
}
md->ca_proto = "ACME";
rv = md_save(ctx->store, ctx->p, MD_SG_DOMAINS, md, 1);
if (APR_SUCCESS == rv) {
md_load(ctx->store, MD_SG_DOMAINS, md->name, &nmd, ctx->p);
md_cmd_print_md(ctx, nmd);
}
return rv;
}
static md_cmd_t AddCmd = {
"add", MD_CTX_STORE,
NULL, cmd_add, MD_NoOptions, NULL,
"add dns [dns2...]",
"add a new managed domain 'dns' with all the additional domain names",
};
/**************************************************************************************************/
/* command: store remove */
static apr_status_t cmd_remove(md_cmd_ctx *ctx, const md_cmd_t *cmd)
{
const char *name;
apr_status_t rv;
int i;
if (ctx->argc <= 0) {
return usage(cmd, "needs at least one name");
}
for (i = 0; i < ctx->argc; ++i) {
name = ctx->argv[i];
rv = md_remove(ctx->store, ctx->p,
MD_SG_DOMAINS, name, md_cmd_ctx_has_option(ctx, "force"));
if (APR_SUCCESS != rv) {
md_log_perror(MD_LOG_MARK, MD_LOG_ERR, rv, ctx->p, "removing md %s", name);
break;
}
}
return rv;
}
static apr_status_t opts_remove(md_cmd_ctx *ctx, int option, const char *optarg)
{
(void)optarg;
switch (option) {
case 'f':
md_cmd_ctx_set_option(ctx, "force", "1");
break;
default:
return APR_EINVAL;
}
return APR_SUCCESS;
}
static apr_getopt_option_t RemoveOptions [] = {
{ "force", 'f', 0, "force removal, be silent about missing domains"},
{ NULL , 0, 0, NULL }
};
static md_cmd_t RemoveCmd = {
"remove", MD_CTX_STORE,
opts_remove, cmd_remove,
RemoveOptions, NULL,
"remove [options] name [name...]",
"remove the managed domains <name> from the store",
};
/**************************************************************************************************/
/* command: store list */
static int list_md(void *baton, md_store_t *store, md_t *md, apr_pool_t *ptemp)
{
(void)store;
(void)ptemp;
md_cmd_print_md(baton, md);
return 1;
}
static apr_status_t cmd_list(md_cmd_ctx *ctx, const md_cmd_t *cmd)
{
(void)cmd;
return md_store_md_iter(list_md, ctx, ctx->store, ctx->p, MD_SG_DOMAINS, "*");
}
static md_cmd_t ListCmd = {
"list", MD_CTX_STORE,
NULL, cmd_list, MD_NoOptions, NULL,
"list",
"list all managed domains in the store"
};
/**************************************************************************************************/
/* command: store update */
static apr_status_t cmd_update(md_cmd_ctx *ctx, const md_cmd_t *cmd)
{
const char *name;
md_t *md;
apr_status_t rv;
int changed;
if (ctx->argc <= 0) {
return usage(cmd, "needs md name");
}
name = ctx->argv[0];
rv = md_load(ctx->store, MD_SG_DOMAINS, name, &md, ctx->p);
if (APR_ENOENT == rv) {
md_log_perror(MD_LOG_MARK, MD_LOG_INFO, 0, ctx->p, "%s: not found", name);
return rv;
}
else if (APR_SUCCESS != rv) {
md_log_perror(MD_LOG_MARK, MD_LOG_ERR, rv, ctx->p, "loading store");
return rv;
}
/* update what */
changed = 0;
if (ctx->argc > 1) {
const char *aspect = ctx->argv[1];
if (!strcmp("domains", aspect)) {
md->domains = md_cmd_gather_args(ctx, 2);
if (apr_is_empty_array(md->domains)) {
fprintf(stderr, "update domains needs at least 1 domain name as parameter\n");
return APR_EGENERAL;
}
changed = 1;
}
else {
fprintf(stderr, "unknown update aspect: %s\n", aspect);
return APR_ENOTIMPL;
}
}
if (ctx->ca_url && (md->ca_urls == NULL
|| md->ca_urls->nelts != 1
|| strcmp(ctx->ca_url, APR_ARRAY_IDX(md->ca_urls, 0, const char*)))) {
md->ca_urls = apr_array_make(ctx->p, 3, sizeof(const char*));
APR_ARRAY_PUSH(md->ca_urls, const char*) = ctx->ca_url;
changed = 1;
}
if (changed) {
rv = md_save(ctx->store, ctx->p, MD_SG_DOMAINS, md, 0);
}
else {
md_log_perror(MD_LOG_MARK, MD_LOG_INFO, 0, ctx->p, "no changes necessary");
}
if (APR_SUCCESS == rv) {
rv = md_load(ctx->store, MD_SG_DOMAINS, name, &md, ctx->p);
md_cmd_print_md(ctx, md);
}
return rv;
}
static md_cmd_t UpdateCmd = {
"update", MD_CTX_STORE,
NULL, cmd_update, MD_NoOptions, NULL,
"update <name>",
"update the managed domain <name> in the store"
};
/**************************************************************************************************/
/* command: store */
static const md_cmd_t *StoreSubCmds[] = {
&AddCmd,
&RemoveCmd,
&ListCmd,
&UpdateCmd,
NULL
};
md_cmd_t MD_StoreCmd = {
"store", MD_CTX_STORE,
NULL, NULL, MD_NoOptions, StoreSubCmds,
"store cmd [opts] [args]",
"manipulate the MD store",
};