certmonger/0008-Switch-IPA-calls-to-us...

839 lines
24 KiB
Diff

From fdc2851233f532eb78363784712c597c63e1c4c1 Mon Sep 17 00:00:00 2001
From: Rob Crittenden <rcritten@redhat.com>
Date: Thu, 20 Aug 2020 16:57:38 -0400
Subject: [PATCH 08/11] Switch IPA calls to use the JSON-RPC endpoint instead
of XMLRPC
IPA has provided a JSON-RPC interface for many years now and has
long term plans to drop support for XMLRPC.
---
src/ipa.c | 546 ++++++++++++++++++++++++++++++++++++++--------
src/store-files.c | 2 +
2 files changed, 463 insertions(+), 85 deletions(-)
diff --git a/src/ipa.c b/src/ipa.c
index e4295826..8c089e68 100644
--- a/src/ipa.c
+++ b/src/ipa.c
@@ -33,8 +33,7 @@
#include <talloc.h>
-#include <xmlrpc-c/client.h>
-#include <xmlrpc-c/transport.h>
+#include <jansson.h>
#include <ldap.h>
#include <krb5.h>
@@ -46,7 +45,7 @@
#include "store.h"
#include "submit-e.h"
#include "submit-u.h"
-#include "submit-x.h"
+#include "submit-h.h"
#include "util.h"
#ifdef ENABLE_NLS
@@ -56,6 +55,229 @@
#define _(_text) (_text)
#endif
+static char *
+get_error_message(krb5_context ctx, krb5_error_code kcode)
+{
+ const char *ret;
+#ifdef HAVE_KRB5_GET_ERROR_MESSAGE
+ ret = ctx ? krb5_get_error_message(ctx, kcode) : NULL;
+ if (ret == NULL) {
+ ret = error_message(kcode);
+ }
+#else
+ ret = error_message(kcode);
+#endif
+ return strdup(ret);
+}
+
+char *
+cm_submit_ccache_realm(char **msg)
+{
+ krb5_context ctx;
+ krb5_ccache ccache;
+ krb5_principal princ;
+ krb5_error_code kret;
+ krb5_data *data;
+ char *ret;
+
+ if (msg != NULL) {
+ *msg = NULL;
+ }
+
+ kret = krb5_init_context(&ctx);
+ if (kret != 0) {
+ fprintf(stderr, "Error initializing Kerberos: %s.\n",
+ ret = get_error_message(ctx, kret));
+ if (msg != NULL) {
+ *msg = ret;
+ } else {
+ free(ret);
+ }
+ return NULL;
+ }
+ kret = krb5_cc_default(ctx, &ccache);
+ if (kret != 0) {
+ fprintf(stderr, "Error resolving default ccache: %s.\n",
+ ret = get_error_message(ctx, kret));
+ if (msg != NULL) {
+ *msg = ret;
+ } else {
+ free(ret);
+ }
+ return NULL;
+ }
+ kret = krb5_cc_get_principal(ctx, ccache, &princ);
+ if (kret != 0) {
+ fprintf(stderr, "Error reading default principal: %s.\n",
+ ret = get_error_message(ctx, kret));
+ if (msg != NULL) {
+ *msg = ret;
+ } else {
+ free(ret);
+ }
+ return NULL;
+ }
+ data = krb5_princ_realm(ctx, princ);
+ if (data == NULL) {
+ fprintf(stderr, "Error retrieving principal realm.\n");
+ if (msg != NULL) {
+ *msg = "Error retrieving principal realm.\n";
+ }
+ return NULL;
+ }
+ ret = malloc(data->length + 1);
+ if (ret == NULL) {
+ fprintf(stderr, "Out of memory for principal realm.\n");
+ if (msg != NULL) {
+ *msg = "Out of memory for principal realm.\n";
+ }
+ return NULL;
+ }
+ memcpy(ret, data->data, data->length);
+ ret[data->length] = '\0';
+ return ret;
+}
+
+krb5_error_code
+cm_submit_make_ccache(const char *ktname, const char *principal, char **msg)
+{
+ krb5_context ctx;
+ krb5_keytab keytab;
+ krb5_ccache ccache;
+ krb5_creds creds;
+ krb5_principal princ;
+ krb5_error_code kret;
+ krb5_get_init_creds_opt gicopts, *gicoptsp;
+ char *ret;
+
+ if (msg != NULL) {
+ *msg = NULL;
+ }
+
+ kret = krb5_init_context(&ctx);
+ if (kret != 0) {
+ ret = get_error_message(ctx, kret);
+ fprintf(stderr, "Error initializing Kerberos: %s.\n", ret);
+ if (msg != NULL) {
+ *msg = ret;
+ } else {
+ free(ret);
+ }
+ return kret;
+ }
+ if (ktname != NULL) {
+ kret = krb5_kt_resolve(ctx, ktname, &keytab);
+ } else {
+ kret = krb5_kt_default(ctx, &keytab);
+ }
+ if (kret != 0) {
+ fprintf(stderr, "Error resolving keytab: %s.\n",
+ ret = get_error_message(ctx, kret));
+ if (msg != NULL) {
+ *msg = ret;
+ } else {
+ free(ret);
+ }
+ return kret;
+ }
+ princ = NULL;
+ if (principal != NULL) {
+ kret = krb5_parse_name(ctx, principal, &princ);
+ if (kret != 0) {
+ fprintf(stderr, "Error parsing \"%s\": %s.\n",
+ principal, ret = get_error_message(ctx, kret));
+ if (msg != NULL) {
+ *msg = ret;
+ } else {
+ free(ret);
+ }
+ return kret;
+ }
+ } else {
+ kret = krb5_sname_to_principal(ctx, NULL, NULL,
+ KRB5_NT_SRV_HST, &princ);
+ if (kret != 0) {
+ fprintf(stderr, "Error building client name: %s.\n",
+ ret = get_error_message(ctx, kret));
+ if (msg != NULL) {
+ *msg = ret;
+ } else {
+ free(ret);
+ }
+ return kret;
+ }
+ }
+ memset(&creds, 0, sizeof(creds));
+#ifdef HAVE_KRB5_GET_INIT_CREDS_OPT_ALLOC
+ memset(&gicopts, 0, sizeof(gicopts));
+ gicoptsp = NULL;
+ kret = krb5_get_init_creds_opt_alloc(ctx, &gicoptsp);
+ if (kret != 0) {
+ fprintf(stderr, "Internal error: %s.\n",
+ ret = get_error_message(ctx, kret));
+ if (msg != NULL) {
+ *msg = ret;
+ } else {
+ free(ret);
+ }
+ return kret;
+ }
+#else
+ krb5_get_init_creds_opt_init(&gicopts);
+ gicoptsp = &gicopts;
+#endif
+ krb5_get_init_creds_opt_set_forwardable(gicoptsp, 1);
+ kret = krb5_get_init_creds_keytab(ctx, &creds, princ, keytab,
+ 0, NULL, gicoptsp);
+#ifdef HAVE_KRB5_GET_INIT_CREDS_OPT_ALLOC
+ krb5_get_init_creds_opt_free(ctx, gicoptsp);
+#endif
+ if (kret != 0) {
+ fprintf(stderr, "Error obtaining initial credentials: %s.\n",
+ ret = get_error_message(ctx, kret));
+ if (msg != NULL) {
+ *msg = ret;
+ } else {
+ free(ret);
+ }
+ return kret;
+ }
+ ccache = NULL;
+ kret = krb5_cc_resolve(ctx, "MEMORY:" PACKAGE_NAME "_submit",
+ &ccache);
+ if (kret == 0) {
+ kret = krb5_cc_initialize(ctx, ccache, creds.client);
+ }
+ if (kret != 0) {
+ fprintf(stderr, "Error initializing credential cache: %s.\n",
+ ret = get_error_message(ctx, kret));
+ if (msg != NULL) {
+ *msg = ret;
+ } else {
+ free(ret);
+ }
+ return kret;
+ }
+ kret = krb5_cc_store_cred(ctx, ccache, &creds);
+ if (kret != 0) {
+ fprintf(stderr,
+ "Error storing creds in credential cache: %s.\n",
+ ret = get_error_message(ctx, kret));
+ if (msg != NULL) {
+ *msg = ret;
+ } else {
+ free(ret);
+ }
+ return kret;
+ }
+ krb5_cc_close(ctx, ccache);
+ krb5_kt_close(ctx, keytab);
+ krb5_free_principal(ctx, princ);
+ krb5_free_context(ctx);
+ putenv("KRB5CCNAME=MEMORY:" PACKAGE_NAME "_submit");
+ return 0;
+}
+
static int
interact(LDAP *ld, unsigned flags, void *defaults, void *sasl_interact)
{
@@ -200,7 +422,7 @@ cm_find_default_naming_context(LDAP *ld, char **basedn)
}
static int
-cm_locate_xmlrpc_service(const char *server,
+cm_locate_jsonrpc_service(const char *server,
int ldap_uri_cmd, const char *ldap_uri,
const char *host,
const char *domain,
@@ -213,10 +435,13 @@ cm_locate_xmlrpc_service(const char *server,
LDAPDN rdn;
struct berval *lbv;
char *lattrs[2] = {"cn", NULL};
- const char *relativedn = "cn=masters,cn=ipa,cn=etc", *dn;
+ const char *relativedn = "cn=masters,cn=ipa,cn=etc";
+ char *dn;
char ldn[LINE_MAX], lfilter[LINE_MAX], uri[LINE_MAX] = "", **list;
int i, j, rc, n;
unsigned int flags;
+ int rval = 0;
+ int alloc_basedn = 0;
*uris = NULL;
@@ -231,14 +456,16 @@ cm_locate_xmlrpc_service(const char *server,
if (basedn == NULL) {
i = cm_find_default_naming_context(ld, &basedn);
if (i != 0) {
- free(basedn);
- return i;
+ rval = i;
+ goto done;
}
+ alloc_basedn = 1;
}
if (basedn == NULL) {
printf(_("Unable to determine base DN of "
"domain information on IPA server.\n"));
- return CM_SUBMIT_STATUS_UNCONFIGURED;
+ rval = CM_SUBMIT_STATUS_UNCONFIGURED;
+ goto done;
}
/* Now look up the names of the master CAs. */
snprintf(lfilter, sizeof(lfilter),
@@ -248,26 +475,31 @@ cm_locate_xmlrpc_service(const char *server,
"(ipaConfigString=enabledService)"
")", service);
snprintf(ldn, sizeof(ldn), "%s,%s", relativedn, basedn);
- free(basedn);
+ if (alloc_basedn) {
+ free(basedn);
+ }
rc = ldap_search_ext_s(ld, ldn, LDAP_SCOPE_SUBTREE,
lfilter, lattrs, 0, NULL, NULL, NULL,
LDAP_NO_LIMIT, &lresult);
if (rc != LDAP_SUCCESS) {
fprintf(stderr, "Error searching '%s': %s.\n",
ldn, ldap_err2string(rc));
- return CM_SUBMIT_STATUS_UNCONFIGURED;
+ rval = CM_SUBMIT_STATUS_UNCONFIGURED;
+ goto done;
}
/* Read their parents' for "cn" values. */
n = ldap_count_entries(ld, lresult);
if (n == 0) {
fprintf(stderr, "No CA masters found.\n");
ldap_msgfree(lresult);
- return CM_SUBMIT_STATUS_UNCONFIGURED;
+ rval = CM_SUBMIT_STATUS_UNCONFIGURED;
+ goto done;
}
list = talloc_array_ptrtype(NULL, list, n + 2);
if (list == NULL) {
fprintf(stderr, "Out of memory.\n");
- return CM_SUBMIT_STATUS_UNCONFIGURED;
+ rval = CM_SUBMIT_STATUS_UNCONFIGURED;
+ goto done;
}
i = 0;
for (lmsg = ldap_first_entry(ld, lresult);
@@ -314,7 +546,7 @@ cm_locate_xmlrpc_service(const char *server,
switch (flags & 0x0f) {
case LDAP_AVA_STRING:
list[i] = talloc_asprintf(list,
- "https://%.*s/ipa/xml",
+ "https://%.*s/ipa/json",
(int) lbv->bv_len,
lbv->bv_val);
if (list[i] != NULL) {
@@ -328,15 +560,67 @@ cm_locate_xmlrpc_service(const char *server,
ldap_dnfree(rdn);
}
}
+ ldap_memfree(dn);
}
ldap_msgfree(lresult);
if (i == 0) {
free(list);
- return CM_SUBMIT_STATUS_UNCONFIGURED;
+ rval = CM_SUBMIT_STATUS_UNCONFIGURED;
+ goto done;
}
list[i] = NULL;
*uris = list;
- return CM_SUBMIT_STATUS_ISSUED;
+ rval = CM_SUBMIT_STATUS_ISSUED;
+
+done:
+ if (ld) {
+ ldap_unbind_ext(ld, NULL, NULL);
+ }
+
+ return rval;
+}
+
+/*
+ * Parse the JSON response from the IPA server.
+ *
+ * It will return one of three types of values:
+ *
+ * < 0 is failure to parse JSON output
+ * 0 is success, no errors were found
+ * > 0 is the IPA API error code
+ */
+static int
+parse_json_result(const char *result, char **error_message) {
+ json_error_t j_error;
+
+ json_t *j_root = NULL;
+ json_t *j_error_obj = NULL;
+
+ int error_code = 0;
+
+ j_root = json_loads(result, 0, &j_error);
+ if (!j_root) {
+ cm_log(0, "Parsing JSON-RPC response failed: %s\n", j_error.text);
+ return -1;
+ }
+
+ j_error_obj = json_object_get(j_root, "error");
+ if (!j_error_obj || json_is_null(j_error_obj)) {
+ json_decref(j_root);
+ return 0; // no errors
+ }
+
+ if (json_unpack_ex(j_error_obj, &j_error, 0, "{s:i, s:s}",
+ "code", &error_code,
+ "message", error_message) != 0) {
+ cm_log(0, "Failed extracting error from JSON-RPC response: %s\n", j_error.text);
+ json_decref(j_root);
+ return -1;
+ }
+
+ cm_log(0, "JSON-RPC error: %d: %s\n", error_code, *error_message);
+ json_decref(j_root);
+ return error_code;
}
/* Make an XML-RPC request to the "cert_request" method. */
@@ -344,63 +628,98 @@ static int
submit_or_poll_uri(const char *uri, const char *cainfo, const char *capath,
const char *uid, const char *pwd, const char *csr,
const char *reqprinc, const char *profile,
- const char *issuer)
+ const char *issuer, int verbose)
{
- struct cm_submit_x_context *ctx;
- const char *args[2];
+ void *ctx;
+ struct cm_submit_h_context *hctx;
char *s, *p;
int i;
+ json_t *json_req = NULL;
+ json_error_t j_error;
+ const char *results = NULL;
+ char *json_str = NULL;
+ char *error_message = NULL;
+ char *referer = NULL;
+ int rval = 0;
+ json_t *j_root = NULL;
+ json_t *j_result_outer = NULL;
+ json_t *j_result = NULL;
+ json_t *j_cert = NULL;
+ const char *certificate = NULL;
if ((uri == NULL) || (strlen(uri) == 0)) {
return CM_SUBMIT_STATUS_UNCONFIGURED;
}
- /* Prepare to make an XML-RPC request. */
+ ctx = talloc_new(NULL);
+
+ referer = talloc_asprintf(ctx, "%s", uri);
+
+ /* Prepare to make a JSON-RPC request. */
submit:
- if ((uid != NULL) && (pwd != NULL) &&
- (strlen(uid) > 0) && (strlen(pwd) > 0)) {
- ctx = cm_submit_x_init(NULL, uri, "cert_request",
- cainfo, capath, uid, pwd,
- cm_submit_x_negotiate_off,
- cm_submit_x_delegate_off);;
- } else {
- ctx = cm_submit_x_init(NULL, uri, "cert_request",
- cainfo, capath, NULL, NULL,
- cm_submit_x_negotiate_on,
- cm_submit_x_delegate_on);
+ json_req = json_pack_ex(&j_error, 0,
+ "{s:s, s:[[s], {s:s, s:s*, s:s*, s:b}]}",
+ "method", "cert_request",
+ "params",
+ csr,
+ "principal", reqprinc,
+ "profile_id", profile,
+ "cacn", issuer,
+ "add", 1);
+ if (!json_req) {
+ cm_log(0, "json_pack_ex() failed: %s\n", j_error.text);
+ return CM_SUBMIT_STATUS_UNCONFIGURED;
}
- if (ctx == NULL) {
- fprintf(stderr, "Error setting up for XMLRPC to %s on "
- "the client.\n", uri);
- printf(_("Error setting up for XMLRPC on the client.\n"));
+ json_str = json_dumps(json_req, 0);
+ json_decref(json_req);
+ if (!json_str) {
+ cm_log(0, "json_dumps() failed\n");
return CM_SUBMIT_STATUS_UNCONFIGURED;
}
- /* Add the CSR contents as the sole unnamed argument. */
- args[0] = csr;
- args[1] = NULL;
- cm_submit_x_add_arg_as(ctx, args);
- /* Add the principal name named argument. */
- cm_submit_x_add_named_arg_s(ctx, "principal", reqprinc);
- /* Add the requested profile name named argument. */
- if (profile != NULL) {
- cm_submit_x_add_named_arg_s(ctx, "profile_id", profile);
- }
- /* Add the requested CA issuer named argument. */
- if (issuer != NULL) {
- cm_submit_x_add_named_arg_s(ctx, "cacn", issuer);
+ hctx = cm_submit_h_init(ctx, "POST", uri, json_str,
+ "application/json", "application/json",
+ referer, cainfo, capath,
+ NULL, NULL, NULL,
+ cm_submit_h_negotiate_on,
+ cm_submit_h_delegate_off,
+ cm_submit_h_clientauth_off,
+ cm_submit_h_env_modify_off,
+ verbose > 1 ?
+ cm_submit_h_curl_verbose_on :
+ cm_submit_h_curl_verbose_off);
+ free(json_str);
+
+ if (hctx == NULL) {
+ fprintf(stderr, "Error setting up JSON-RPC to %s on "
+ "the client.\n", uri);
+ printf(_("Error setting up for JSON-RPC on the client.\n"));
+ rval = CM_SUBMIT_STATUS_UNCONFIGURED;
+ goto cleanup;
}
- /* Tell the server to add entries for a principal if one
- * doesn't exist yet. */
- cm_submit_x_add_named_arg_b(ctx, "add", 1);
/* Submit the request. */
fprintf(stderr, "Submitting request to \"%s\".\n", uri);
- cm_submit_x_run(ctx);
+ cm_submit_h_run(hctx);
/* Check the results. */
- if (cm_submit_x_faulted(ctx) == 0) {
- i = cm_submit_x_fault_code(ctx);
+
+ results = cm_submit_h_results(hctx, NULL);
+ cm_log(1, "%s\n", results);
+ if (cm_submit_h_response_code(hctx) != 200) {
+ cm_log(0, "JSON-RPC call failed with HTTP status code: %d\n",
+ cm_submit_h_response_code(hctx));
+ cm_log(0, "code = %d, code_text = \"%s\"\n",
+ cm_submit_h_result_code(hctx), cm_submit_h_result_code_text(hctx));
+ rval = CM_SUBMIT_STATUS_UNREACHABLE;
+ goto cleanup;
+ }
+ i = parse_json_result(results, &error_message);
+ if (i < 0) {
+ rval = CM_SUBMIT_STATUS_UNREACHABLE;
+ goto cleanup;
+ }
+ if (i > 0) {
/* Interpret the error. See errors.py to get the
* classifications. */
switch (i / 1000) {
@@ -424,8 +743,9 @@ submit:
}
printf("Server at %s denied our request, "
"giving up: %d (%s).\n", uri, i,
- cm_submit_x_fault_text(ctx));
- return CM_SUBMIT_STATUS_REJECTED;
+ error_message);
+ rval = CM_SUBMIT_STATUS_REJECTED;
+ goto cleanup;
break;
case 1: /* authentication error - transient? */
case 4: /* execution error - transient? */
@@ -433,22 +753,51 @@ submit:
default:
printf("Server at %s failed request, "
"will retry: %d (%s).\n", uri, i,
- cm_submit_x_fault_text(ctx));
- return CM_SUBMIT_STATUS_UNREACHABLE;
+ error_message);
+ rval = CM_SUBMIT_STATUS_UNREACHABLE;
+ goto cleanup;
break;
}
- } else
- if (cm_submit_x_has_results(ctx) == 0) {
- if (cm_submit_x_get_named_s(ctx, "certificate",
- &s) == 0) {
+ } else {
+ j_root = json_loads(results, 0, &j_error);
+ if (!j_root) {
+ cm_log(0, "Parsing JSON-RPC response failed: %s\n", j_error.text);
+ rval = CM_SUBMIT_STATUS_UNREACHABLE;
+ goto cleanup;
+ }
+
+ j_result_outer = json_object_get(j_root, "result");
+ if (!j_result_outer) {
+ cm_log(0, "Parsing JSON-RPC response failed, no outer result\n");
+ rval = CM_SUBMIT_STATUS_UNREACHABLE;
+ goto cleanup;
+ }
+
+ j_result = json_object_get(j_result_outer, "result");
+ if (!j_result) {
+ cm_log(0, "Parsing JSON-RPC response failed, no inner result\n");
+ rval = CM_SUBMIT_STATUS_UNREACHABLE;
+ goto cleanup;
+ }
+
+ j_cert = json_object_get(j_result, "certificate");
+ if (!j_cert) {
+ cm_log(0, "Parsing JSON-RPC response failed, no certificate\n");
+ rval = CM_SUBMIT_STATUS_UNREACHABLE;
+ goto cleanup;
+ }
+ certificate = json_string_value(j_cert);
+
+ if (certificate) {
/* If we got a certificate, we're probably
* okay. */
- fprintf(stderr, "Certificate: \"%s\"\n", s);
- s = cm_submit_u_base64_from_text(s);
+ fprintf(stderr, "Certificate: \"%s\"\n", certificate);
+ s = cm_submit_u_base64_from_text(certificate);
if (s == NULL) {
printf("Out of memory parsing server "
"response, will retry.\n");
- return CM_SUBMIT_STATUS_UNREACHABLE;
+ rval = CM_SUBMIT_STATUS_UNREACHABLE;
+ goto cleanup;
}
p = cm_submit_u_pem_from_base64("CERTIFICATE",
FALSE, s);
@@ -457,15 +806,19 @@ submit:
}
free(s);
free(p);
- return CM_SUBMIT_STATUS_ISSUED;
+ rval = CM_SUBMIT_STATUS_ISSUED;
+ goto cleanup;
} else {
- return CM_SUBMIT_STATUS_REJECTED;
+ rval = CM_SUBMIT_STATUS_REJECTED;
}
- } else {
- /* No useful response, no fault. Try again, from
- * scratch, later. */
- return CM_SUBMIT_STATUS_UNREACHABLE;
}
+
+cleanup:
+ json_decref(j_root);
+ cm_submit_h_cleanup(hctx);
+ talloc_free(ctx);
+
+ return rval;
}
static int
@@ -473,16 +826,17 @@ submit_or_poll(const char *uri, const char *cainfo, const char *capath,
const char *server, int ldap_uri_cmd, const char *ldap_uri,
const char *host, const char *domain, char *basedn,
const char *uid, const char *pwd, const char *csr,
- const char *reqprinc, const char *profile, const char *issuer)
+ const char *reqprinc, const char *profile, const char *issuer,
+ int verbose)
{
int i, u;
char **uris;
i = submit_or_poll_uri(uri, cainfo, capath, uid, pwd, csr, reqprinc,
- profile, issuer);
+ profile, issuer, verbose);
if ((i == CM_SUBMIT_STATUS_UNREACHABLE) ||
(i == CM_SUBMIT_STATUS_UNCONFIGURED)) {
- u = cm_locate_xmlrpc_service(server, ldap_uri_cmd, ldap_uri,
+ u = cm_locate_jsonrpc_service(server, ldap_uri_cmd, ldap_uri,
host, domain, basedn, "CA", &uris);
if ((u == 0) && (uris != NULL)) {
for (u = 0; uris[u] != NULL; u++) {
@@ -491,7 +845,7 @@ submit_or_poll(const char *uri, const char *cainfo, const char *capath,
}
i = submit_or_poll_uri(uris[u], cainfo, capath,
uid, pwd, csr, reqprinc,
- profile, issuer);
+ profile, issuer, verbose);
if ((i != CM_SUBMIT_STATUS_UNREACHABLE) &&
(i != CM_SUBMIT_STATUS_UNCONFIGURED)) {
talloc_free(uris);
@@ -562,7 +916,7 @@ fetch_roots(const char *server, int ldap_uri_cmd, const char *ldap_uri,
return CM_SUBMIT_STATUS_ISSUED;
}
/* Read our realm name from our ccache. */
- realm = cm_submit_x_ccache_realm(&kerr);
+ realm = cm_submit_ccache_realm(&kerr);
/* Read all of the certificates. */
for (lmsg = ldap_first_entry(ld, lresult);
lmsg != NULL;
@@ -588,6 +942,9 @@ fetch_roots(const char *server, int ldap_uri_cmd, const char *ldap_uri,
ldap_msgfree(lresult);
free(realm);
free(kerr);
+ if (ld) {
+ ldap_unbind_ext(ld, NULL, NULL);
+ }
return CM_SUBMIT_STATUS_ISSUED;
}
@@ -600,7 +957,8 @@ main(int argc, const char **argv)
char *csr, *p, uri[LINE_MAX], *reqprinc = NULL, *ipaconfig, *kerr;
char *uid = NULL, *pwd = NULL, *pwdfile = NULL;
const char *xmlrpc_uri = NULL, *ldap_uri = NULL, *server = NULL, *csrfile;
- int xmlrpc_uri_cmd = 0, ldap_uri_cmd = 0, verbose = 0;
+ const char *jsonrpc_uri = NULL;
+ int jsonrpc_uri_cmd = 0, ldap_uri_cmd = 0, verbose = 0;
const char *mode = CM_OP_SUBMIT;
char ldn[LINE_MAX], *basedn = NULL, *profile = NULL, *issuer = NULL;
krb5_error_code kret;
@@ -609,6 +967,7 @@ main(int argc, const char **argv)
{"host", 'h', POPT_ARG_STRING, &host, 0, "IPA server hostname", "HOSTNAME"},
{"domain", 'd', POPT_ARG_STRING, &domain, 0, "IPA domain name", "NAME"},
{"xmlrpc-url", 'H', POPT_ARG_STRING, NULL, 'H', "IPA XMLRPC service location", "URL"},
+ {"jsonrpc-url", 'J', POPT_ARG_STRING, NULL, 'J', "IPA JSON-RPC service location", "URL"},
{"ldap-url", 'L', POPT_ARG_STRING, NULL, 'L', "IPA LDAP service location", "URL"},
{"capath", 'C', POPT_ARG_STRING, &capath, 0, NULL, "DIRECTORY"},
{"cafile", 'c', POPT_ARG_STRING, &cainfo, 0, NULL, "FILENAME"},
@@ -659,9 +1018,10 @@ main(int argc, const char **argv)
poptSetOtherOptionHelp(pctx, "[options] [csrfile]");
while ((c = poptGetNextOpt(pctx)) > 0) {
switch (c) {
- case 'H':
- xmlrpc_uri = poptGetOptArg(pctx);
- xmlrpc_uri_cmd++;
+ case 'H': /* XMLRPC URI kept for backwards compatibility */
+ case 'J':
+ jsonrpc_uri = poptGetOptArg(pctx);
+ jsonrpc_uri_cmd++;
break;
case 'L':
ldap_uri = poptGetOptArg(pctx);
@@ -724,6 +1084,11 @@ main(int argc, const char **argv)
"global",
"xmlrpc_uri");
}
+ if (jsonrpc_uri == NULL) {
+ jsonrpc_uri = get_config_entry(ipaconfig,
+ "global",
+ "jsonrpc_uri");
+ }
if (ldap_uri == NULL) {
/* Preferred, but likely to only be set on a
* server. */
@@ -756,6 +1121,7 @@ main(int argc, const char **argv)
}
}
}
+ free(ipaconfig);
csr = NULL;
memset(uri, '\0', sizeof(uri));
memset(ldn, '\0', sizeof(ldn));
@@ -787,16 +1153,25 @@ main(int argc, const char **argv)
(getenv(CM_SUBMIT_ISSUER_ENV) != NULL)) {
issuer = strdup(getenv(CM_SUBMIT_ISSUER_ENV));
}
- if ((server != NULL) && !xmlrpc_uri_cmd) {
+ if ((server != NULL) && !jsonrpc_uri_cmd) {
snprintf(uri, sizeof(uri),
- "https://%s/ipa/xml", server);
+ "https://%s/ipa/json", server);
+ } else
+ if (jsonrpc_uri != NULL) {
+ snprintf(uri, sizeof(uri), "%s", jsonrpc_uri);
} else
if (xmlrpc_uri != NULL) {
- snprintf(uri, sizeof(uri), "%s", xmlrpc_uri);
+ /* strip off the trailing xml and replace with json */
+ if ((strlen(xmlrpc_uri) + 1) > sizeof(uri)) {
+ printf(_("xmlrpc_uri is longer than %ld.\n"), sizeof(uri) - 2);
+ return CM_SUBMIT_STATUS_UNCONFIGURED;
+ }
+ snprintf(uri, strlen(xmlrpc_uri) - 2, "%s", xmlrpc_uri);
+ strcat(uri, "json");
} else
if (host != NULL) {
snprintf(uri, sizeof(uri),
- "https://%s/ipa/xml", host);
+ "https://%s/ipa/json", host);
}
/* Read the CSR from the environment, or from the file named on
@@ -891,7 +1266,7 @@ main(int argc, const char **argv)
/* Setup a ccache unless we're told to use the default one. */
kerr = NULL;
if (make_keytab_ccache &&
- ((kret = cm_submit_x_make_ccache(ktname, kpname, &kerr)) != 0)) {
+ ((kret = cm_submit_make_ccache(ktname, kpname, &kerr)) != 0)) {
fprintf(stderr, "Error setting up ccache at the client: %s.\n",
kerr);
if (ktname == NULL) {
@@ -939,11 +1314,12 @@ main(int argc, const char **argv)
ret = submit_or_poll(uri, cainfo, capath, server,
ldap_uri_cmd, ldap_uri, host, domain,
basedn, uid, pwd, csr, reqprinc, profile,
- issuer);
+ issuer, verbose);
free(csr);
free(profile);
free(issuer);
free(reqprinc);
+ free(basedn);
return ret;
} else
if (strcasecmp(mode, CM_OP_FETCH_ROOTS) == 0) {
diff --git a/src/store-files.c b/src/store-files.c
index 4c3b2232..85ac692e 100644
--- a/src/store-files.c
+++ b/src/store-files.c
@@ -2650,6 +2650,7 @@ cm_store_get_all_cas(void *parent)
j++;
}
#endif
+#ifdef WITH_XMLRPC
#ifdef WITH_CERTMASTER
/* Make sure we get at least one certmaster entry. */
for (k = 0; k < j; k++) {
@@ -2670,6 +2671,7 @@ cm_store_get_all_cas(void *parent)
j++;
}
#endif
+#endif
#ifdef WITH_IPA
/* Make sure we get at least 1 dogtag-ipa-renew-agent entry. */
for (k = 0; k < j; k++) {
--
2.25.4