#167 Use JSON-RPC for the IPA CA and deprecate XMLRPC in all clients
Merged 3 years ago by rcritten. Opened 3 years ago by rcritten.
rcritten/certmonger ipajson  into  master

file modified
+12
@@ -29,6 +29,18 @@ 

  local-archive:

  	$(MAKE) archive ORIGIN=$(ARCHIVEOUTDIR)

  

+ local-srpm:

+ 	repo=`pwd`; \

+ 	tmpdir=`mktemp -d /tmp/make_archive_XXXXXX`; \

+ 	if test -d "$$tmpdir" ; then \

+ 		git clone . $$tmpdir;\

+ 		cd $$tmpdir;\

+ 		./make-srpm.sh;\

+ 		cp -v $(distdir)-*.src.rpm $(ARCHIVEOUTDIR)/;\

+ 		chmod -R u+rw $$tmpdir;\

+ 		rm -fr $$tmpdir;\

+ 	fi

+ 

  srpm:

  	repo=`pwd`; \

  	tmpdir=`mktemp -d /tmp/make_archive_XXXXXX`; \

file modified
+22 -2
@@ -24,6 +24,8 @@ 

  %global sysvinitdir %{_initrddir}

  %endif

  

+ %bcond_with xmlrpc

+ 

  Name:		certmonger

  Version:	0.79.11

  Release:	1%{?dist}
@@ -33,10 +35,11 @@ 

  License:	GPLv3+

  URL:		http://pagure.io/certmonger/

  Source0:	http://releases.pagure.org/certmonger/certmonger-%{version}.tar.gz

- #Source1:	http://releases.pagure.org/certmonger/certmonger-%{version}.tar.gz.sig

+ #Source1:	http://releases.pagure.org/certmonger/certmonger-%%{version}.tar.gz.sig

  BuildRoot:	%(mktemp -ud %{_tmppath}/%{name}-%{version}-%{release}-XXXXXX)

  

  BuildRequires:	openldap-devel

+ BuildRequires:	krb5-devel

  BuildRequires:	dbus-devel, nspr-devel, nss-devel, openssl-devel, libidn2-devel

  BuildRequires:	autoconf, automake, gcc, gettext-devel

  %if 0%{?fedora} >= 12 || 0%{?rhel} >= 6
@@ -50,7 +53,11 @@ 

  %else

  BuildRequires:	curl-devel

  %endif

- BuildRequires:	libxml2-devel, xmlrpc-c-devel

+ BuildRequires:	libxml2-devel

+ %if %{with xmlrpc}

+ BuildRequires:	xmlrpc-c-devel

+ %endif

+ BuildRequires:	jansson-devel

  %if 0%{?rhel} && 0%{?rhel} < 6

  BuildRequires:	bind-libbind-devel

  BuildRequires:	mktemp
@@ -132,10 +139,17 @@ 

  	--enable-tmpfiles \

  %endif

  	--with-homedir=/run/certmonger \

+ %if %{with xmlrpc}

+ 	--with-xmlrpc \

+ %endif

  	--with-tmpdir=/run/certmonger --enable-pie --enable-now

+ %if %{with xmlrpc}

  # For some reason, some versions of xmlrpc-c-config in Fedora and RHEL just

  # tell us about libxmlrpc_client, but we need more.  Work around.

  make %{?_smp_mflags} XMLRPC_LIBS="-lxmlrpc_client -lxmlrpc_util -lxmlrpc"

+ %else

+ make %{?_smp_mflags}

+ %endif

  

  %install

  rm -rf $RPM_BUILD_ROOT
@@ -154,6 +168,12 @@ 

  if test $1 -eq 1 ; then

  	%{_bindir}/dbus-send --system --type=method_call --dest=org.freedesktop.DBus / org.freedesktop.DBus.ReloadConfig 2>&1 || :

  fi

+ %if %{without xmlrpc}

+ # remove any existing certmaster CA configuration

+ if test $1 -gt 1 ; then

+     %{_bindir}/getcert remove-ca -c certmaster 2>&1 || :

+ fi

+ %endif

  %if %{systemd}

  if test $1 -eq 1 ; then

  	/bin/systemctl daemon-reload >/dev/null 2>&1 || :

file modified
+37 -23
@@ -278,29 +278,42 @@ 

  	CPPFLAGS="$savedCPPFLAGS"

  	LDFLAGS="$savedLDFLAGS"

  

- 	dnl PKG_CHECK_MODULES(XMLRPC,xmlrpc_client) # Not provided in upstream versions.

- 	savedCFLAGS="$CFLAGS"

- 	CFLAGS=

- 	AC_ARG_VAR(XMLRPC_C_CONFIG,[the full path of the xmlrpc-c-config command])

- 	AC_PATH_PROG(XMLRPC_C_CONFIG,[xmlrpc-c-config],,[$PATH$PATH_SEPARATOR/usr/xmlrpc/bin$PATH_SEPARATOR/usr/xmlrpc-c/bin])

- 	if test -z "$XMLRPC_C_CONFIG" ; then

- 		AC_MSG_ERROR(xmlrpc-c-config not found)

- 	fi

- 	AC_MSG_CHECKING(for XMLRPC CFLAGS)

- 	XMLRPC_CFLAGS="`${XMLRPC_C_CONFIG} client --cflags` `${XMLRPC_C_CONFIG} --cflags`"

- 	AC_MSG_RESULT([$XMLRPC_CFLAGS])

- 	AC_SUBST(XMLRPC_CFLAGS)

- 	AC_MSG_CHECKING(for XMLRPC LIBS)

- 	XMLRPC_LIBS="`${XMLRPC_C_CONFIG} client --libs` `${XMLRPC_C_CONFIG} --libs`"

- 	AC_MSG_RESULT([$XMLRPC_LIBS])

- 	AC_SUBST(XMLRPC_LIBS)

- 	CFLAGS="$CFLAGS $XMLRPC_CFLAGS"

- 	AC_CHECK_MEMBERS(struct xmlrpc_curl_xportparms.gssapi_delegation,,,

- 			 [

- 			 #include <xmlrpc-c/client.h>

- 			 #include <xmlrpc-c/transport.h>

- 			 ])

- 	CFLAGS="$savedCFLAGS"

+ 	PKG_CHECK_MODULES(JANSSON,jansson)

+ 	have_jansson=true

+ 

+ 	AC_ARG_WITH([xmlrpc],

+ 		[AC_HELP_STRING([--with-xmlrpc], [Enable XML-RPC support])],

+ 		[with_xmlrpc=${with_xmlrpc}],

+ 		[with_xmlrpc=no])

+ 	AS_IF([test x"$with_xmlrpc" = xyes], [AC_DEFINE([WITH_XMLRPC], [1],

+ 		[include XMLRPC support])])

+ 	AM_CONDITIONAL(WITH_XMLRPC,test x"$with_xmlrpc" = xyes)

+ 

+ 	AS_IF([test x"$with_xmlrpc" = xyes], [

+ 		dnl PKG_CHECK_MODULES(XMLRPC,xmlrpc_client) # Not provided in upstream versions.

+ 		savedCFLAGS="$CFLAGS"

+ 		CFLAGS=

+ 		AC_ARG_VAR(XMLRPC_C_CONFIG,[the full path of the xmlrpc-c-config command])

+ 		AC_PATH_PROG(XMLRPC_C_CONFIG,[xmlrpc-c-config],,[$PATH$PATH_SEPARATOR/usr/xmlrpc/bin$PATH_SEPARATOR/usr/xmlrpc-c/bin])

+ 		if test -z "$XMLRPC_C_CONFIG" ; then

+ 			AC_MSG_ERROR(xmlrpc-c-config not found)

+ 		fi

+ 		AC_MSG_CHECKING(for XMLRPC CFLAGS)

+ 		XMLRPC_CFLAGS="`${XMLRPC_C_CONFIG} client --cflags` `${XMLRPC_C_CONFIG} --cflags`"

+ 		AC_MSG_RESULT([$XMLRPC_CFLAGS])

+ 		AC_SUBST(XMLRPC_CFLAGS)

+ 		AC_MSG_CHECKING(for XMLRPC LIBS)

+ 		XMLRPC_LIBS="`${XMLRPC_C_CONFIG} client --libs` `${XMLRPC_C_CONFIG} --libs`"

+ 		AC_MSG_RESULT([$XMLRPC_LIBS])

+ 		AC_SUBST(XMLRPC_LIBS)

+ 		CFLAGS="$CFLAGS $XMLRPC_CFLAGS"

+ 		AC_CHECK_MEMBERS(struct xmlrpc_curl_xportparms.gssapi_delegation,,,

+ 				 [

+ 				 #include <xmlrpc-c/client.h>

+ 				 #include <xmlrpc-c/transport.h>

+ 				 ])

+ 		CFLAGS="$savedCFLAGS"

+ 	])

  

  	savedCFLAGS="$CFLAGS"

  	savedCPPFLAGS="$CPPFLAGS"
@@ -863,6 +876,7 @@ 

  	AM_CONDITIONAL(HAVE_EC,false)

  	AM_CONDITIONAL(WITH_IPA,false)

  	AM_CONDITIONAL(WITH_CERTMASTER,false)

+ 	AM_CONDITIONAL(WITH_XMLRPC,false)

  	AM_CONDITIONAL(WITH_LOCAL,false)

  	AM_CONDITIONAL(HAVE_UUID,false)

  fi

file modified
+25 -8
@@ -11,15 +11,17 @@ 

  endif

  man_MANS = certmonger.8 getcert.1 getcert-request.1 getcert-list.1 \

  	   getcert-list-cas.1 getcert-start-tracking.1 getcert-stop-tracking.1 \

- 	   selfsign-getcert.1 ipa-getcert.1 certmaster-getcert.1 \

+ 	   selfsign-getcert.1 ipa-getcert.1 \

  	   getcert-resubmit.1 certmonger-ipa-submit.8 \

- 	   certmonger-certmaster-submit.8 \

  	   certmonger-dogtag-ipa-renew-agent-submit.8 certmonger.conf.5 \

  	   getcert-refresh.1 getcert-refresh-ca.1 local-getcert.1 \

  	   certmonger-local-submit.8 getcert-status.1 \

  	   certmonger-dogtag-submit.8 certmonger-scep-submit.8 \

  	   getcert-add-ca.1 getcert-add-scep-ca.1 getcert-modify-ca.1 \

  	   getcert-remove-ca.1 getcert-rekey.1

+ if WITH_XMLRPC

+ man_MANS += certmaster-getcert.1 certmonger-certmaster-submit.8

+ endif

  pkgsysconfdir = $(sysconfdir)/$(PACKAGE)

  pkgsysconf_DATA = certmonger.conf

  EXTRA_PROGRAMS =
@@ -105,8 +107,6 @@ 

  	submit-sn.c \

  	submit-u.c \

  	submit-u.h \

- 	submit-x.c \

- 	submit-x.h \

  	subproc.c \

  	subproc.h \

  	tdbus.c \
@@ -121,6 +121,11 @@ 

  	util-m.h \

  	util-n.c \

  	util-n.h

+ if WITH_XMLRPC

+ libcm_a_SOURCES += \

+ 	submit-x.c \

+ 	submit-x.h

+ endif

  libcm_o_a_SOURCES =

  if HAVE_OPENSSL

  libcm_o_a_SOURCES += \
@@ -158,11 +163,13 @@ 

  ipa_getcert_LDADD = $(getcert_LDADD)

  endif

  if WITH_IPA

+ if WITH_XMLRPC

  bin_PROGRAMS += certmaster-getcert

  certmaster_getcert_CFLAGS = $(getcert_CFLAGS)

  certmaster_getcert_SOURCES = certmaster-getcert.c tm.c tm.h

  certmaster_getcert_LDADD = $(getcert_LDADD)

  endif

+ endif

  bin_PROGRAMS += selfsign-getcert

  selfsign_getcert_CFLAGS = $(getcert_CFLAGS)

  selfsign_getcert_SOURCES = selfsign-getcert.c tm.c tm.h
@@ -181,21 +188,28 @@ 

  certmonger_session_LDADD = libcm.a \

  		   $(OPENSSL_LIBS) $(CERTMONGER_LIBS) $(KRB5_LIBS) $(IDN_LIBS) \

  		   $(GMP_LIBS) $(UUID_LIBS) $(POPT_LIBS) $(LTLIBICONV) $(LDAP_LIBS)

- noinst_PROGRAMS = tdbusm-check serial-check nl-check submit-x toklist

+ noinst_PROGRAMS = tdbusm-check serial-check nl-check toklist

+ if WITH_XMLRPC

+ noinst_PROGRAMS += submit-x

+ endif

  tdbusm_check_SOURCES = tdbusm-check.c tm.c tm.h

  tdbusm_check_LDADD = libcm.a $(CERTMONGER_LIBS) $(POPT_LIBS) $(LDAP_LIBS)

  serial_check_LDADD = libcm.a $(CERTMONGER_LIBS) $(LTLIBICONV) $(LDAP_LIBS)

  nl_check_LDADD = libcm.a $(CERTMONGER_LIBS) $(LDAP_LIBS)

+ if WITH_XMLRPC

  submit_x_CFLAGS = $(AM_CFLAGS) $(NSS_CFLAGS) -DCM_SUBMIT_X_MAIN

  submit_x_SOURCES = submit-x.c submit-x.h submit-u.c submit-u.h log.c log.h \

  	tm.c tm.h

  submit_x_LDADD = $(XMLRPC_LIBS) $(KRB5_LIBS) $(TALLOC_LIBS) \

  		 $(GMP_LIBS) $(UUID_LIBS) $(POPT_LIBS)

+ endif

  toklist_CFLAGS = $(AM_CFLAGS) $(NSS_CFLAGS)

  toklist_LDADD = $(NSS_LIBS) $(POPT_LIBS)

  if WITH_CERTMASTER

+ if WITH_XMLRPC

  pkglibexec_PROGRAMS += certmaster-submit

  endif

+ endif

  if WITH_IPA

  pkglibexec_PROGRAMS += ipa-submit

  endif
@@ -205,19 +219,22 @@ 

  pkglibexec_PROGRAMS += scep-submit

  endif

  noinst_PROGRAMS += submit-h submit-d

- ipa_submit_CFLAGS = $(AM_CFLAGS) $(NSS_CFLAGS)

+ ipa_submit_CFLAGS = $(AM_CFLAGS) $(NSS_CFLAGS) $(CURL_CFLAGS) $(JANSSON_CFLAGS)

  ipa_submit_SOURCES = ipa.c srvloc.c srvloc.h store.h store-gen.c \

- 		submit-x.c submit-x.h submit-u.c submit-u.h \

+ 		submit-h.c submit-h.h submit-u.c submit-u.h \

  		submit-e.h util.c util.h log.c log.h tm.c tm.h

  ipa_submit_LDADD = $(XMLRPC_LIBS) $(LDAP_LIBS) $(KRB5_LIBS) $(TALLOC_LIBS) \

  		   $(GMP_LIBS) $(IDN_LIBS) $(OPENSSL_LIBS) $(UUID_LIBS) \

- 		   $(RESOLV_LIBS) $(LTLIBICONV) $(POPT_LIBS)

+ 		   $(RESOLV_LIBS) $(LTLIBICONV) $(POPT_LIBS) $(CURL_LIBS) \

+ 		   $(JANSSON_LIBS)

+ if WITH_XMLRPC

  certmaster_submit_CFLAGS = $(AM_CFLAGS) $(NSS_CFLAGS)

  certmaster_submit_SOURCES = certmaster.c submit-x.c submit-x.h \

  		submit-e.h submit-u.c submit-u.h util.c util.h log.c log.h \

  		tm.c tm.h

  certmaster_submit_LDADD = $(XMLRPC_LIBS) $(KRB5_LIBS) $(TALLOC_LIBS) \

  			  $(GMP_LIBS) $(UUID_LIBS) $(LTLIBICONV) $(POPT_LIBS)

+ endif

  dogtag_ipa_renew_agent_submit_CFLAGS = $(AM_CFLAGS) $(XML_CFLAGS) \

  				       $(NSS_CFLAGS) $(CURL_CFLAGS) \

  				       -DDOGTAG_IPA_RENEW_AGENT=1

file modified
+1 -1
@@ -691,7 +691,7 @@ 

  	/* Submit the form(s). */

  	hctx = NULL;

  	while (url != NULL) {

- 		hctx = cm_submit_h_init(ctx, method, url, params, NULL, NULL,

+ 		hctx = cm_submit_h_init(ctx, method, url, params, NULL, NULL, NULL,

  					cainfo, capath, sslcert, sslkey, sslpin,

  					cm_submit_h_negotiate_off,

  					cm_submit_h_delegate_off,

file modified
+461 -85
@@ -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 @@ 

  }

  

  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 @@ 

  	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 @@ 

  	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 @@ 

  		 "(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 @@ 

  					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 @@ 

  				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 @@ 

  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 @@ 

  			}

  			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 @@ 

  		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 @@ 

  			}

  			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 @@ 

  	       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 @@ 

  				}

  				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 @@ 

  		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 @@ 

  	ldap_msgfree(lresult);

  	free(realm);

  	free(kerr);

+ 	if (ld) {

+ 		ldap_unbind_ext(ld, NULL, NULL);

+ 	}

  	return CM_SUBMIT_STATUS_ISSUED;

  }

  
@@ -600,7 +957,8 @@ 

  	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 @@ 

  		{"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 @@ 

  	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 @@ 

  							      "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 @@ 

  			}

  		}

  	}

+ 	free(ipaconfig);

  	csr = NULL;

  	memset(uri, '\0', sizeof(uri));

  	memset(ldn, '\0', sizeof(ldn));
@@ -787,16 +1153,25 @@ 

  		    (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 @@ 

  	/* 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 @@ 

  		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) {

file modified
+3 -3
@@ -496,7 +496,7 @@ 

  	}

  

  	/* Submit the first request. */

- 	hctx = cm_submit_h_init(ctx, "GET", url, params, NULL, NULL,

+ 	hctx = cm_submit_h_init(ctx, "GET", url, params, NULL, NULL, NULL,

  				cainfo, NULL, NULL, NULL, NULL,

  				cm_submit_h_negotiate_off,

  				cm_submit_h_delegate_off,
@@ -593,7 +593,7 @@ 

  	}

  	/* Submit a second HTTP request if we have one to make. */

  	if (params2 != NULL) {

- 		hctx = cm_submit_h_init(ctx, "GET", url, params2, NULL, NULL,

+ 		hctx = cm_submit_h_init(ctx, "GET", url, params2, NULL, NULL, NULL,

  					NULL, NULL, NULL, NULL, NULL,

  					cm_submit_h_negotiate_off,

  					cm_submit_h_delegate_off,
@@ -794,7 +794,7 @@ 

  						 OP_GET_CA_CERT

  						 "&message=%d", i++);

  			hctx = cm_submit_h_init(ctx, "GET", url, params,

- 						NULL, NULL, NULL, NULL,

+ 						NULL, NULL, NULL, NULL, NULL,

  						NULL, NULL, NULL,

  						cm_submit_h_negotiate_off,

  						cm_submit_h_delegate_off,

file modified
+2
@@ -2650,6 +2650,7 @@ 

  			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 @@ 

  			j++;

  		}

  #endif

+ #endif

  #ifdef WITH_IPA

  		/* Make sure we get at least 1 dogtag-ipa-renew-agent entry. */

  		for (k = 0; k < j; k++) {

file modified
+1 -1
@@ -1188,7 +1188,7 @@ 

  		fprintf(stderr, "url = \"%s%s%s\"\n", uri,

  		        params ? "?" : "", params ? params : "");

  	}

- 	hctx = cm_submit_h_init(ctx, method, uri, params, NULL, NULL,

+ 	hctx = cm_submit_h_init(ctx, method, uri, params, NULL, NULL, NULL,

  				cainfo, capath, sslcert, sslkey, sslpin,

  				cm_submit_h_negotiate_off,

  				cm_submit_h_delegate_off,

file modified
+15 -5
@@ -51,7 +51,7 @@ 

  struct cm_submit_h_context {

  	int ret;

  	long response_code;

- 	char *method, *uri, *args, *accept, *ctype, *cainfo, *capath, *result;

+ 	char *method, *uri, *args, *accept, *ctype, *referer, *cainfo, *capath, *result;

  	int result_length;

  	char *sslcert, *sslkey, *sslpass;

  	enum cm_submit_h_opt_negotiate negotiate;
@@ -66,7 +66,7 @@ 

  cm_submit_h_init(void *parent,

  		 const char *method, const char *uri, const char *args,

  		 const char *content_type, const char *accept,

- 		 const char *cainfo, const char *capath,

+ 		 const char *referer, const char *cainfo, const char *capath,

  		 const char *sslcert, const char *sslkey, const char *sslpass,

  		 enum cm_submit_h_opt_negotiate neg,

  		 enum cm_submit_h_opt_delegate del,
@@ -84,6 +84,7 @@ 

  		ctx->ctype = content_type ?

  			     talloc_strdup(ctx, content_type) :

  			     NULL;

+ 		ctx->referer = referer ? talloc_strdup(ctx, referer) : NULL;

  		ctx->accept = accept ? talloc_strdup(ctx, accept) : NULL;

  		ctx->cainfo = cainfo ? talloc_strdup(ctx, cainfo) : NULL;

  		ctx->capath = capath ? talloc_strdup(ctx, capath) : NULL;
@@ -180,10 +181,11 @@ 

  			}

  		}

  		if (ctx->negotiate == cm_submit_h_negotiate_on) {

- #if defined(CURLOPT_HTTPAUTH) && defined(CURLAUTH_GSSNEGOTIATE)

+ #if defined(CURLAUTH_NEGOTIATE)

  			curl_easy_setopt(ctx->curl,

  					 CURLOPT_HTTPAUTH,

- 					 CURLAUTH_GSSNEGOTIATE);

+ 					 CURLAUTH_NEGOTIATE);

+ 			curl_easy_setopt(ctx->curl, CURLOPT_USERPWD, ":");

  #else

  			cm_log(-1,

  			       "warning: libcurl doesn't appear to support "
@@ -243,6 +245,14 @@ 

  							    header);

  			}

  		}

+ 		if (ctx->referer != NULL) {

+ 			header = talloc_asprintf(ctx, "Referer: %s",

+ 						 ctx->referer);

+ 			if (header != NULL) {

+ 				headers = curl_slist_append(headers,

+ 							    header);

+ 			}

+ 		}

  		curl_easy_setopt(ctx->curl, CURLOPT_HTTPHEADER, headers);

  		curl_easy_setopt(ctx->curl, CURLOPT_WRITEFUNCTION,

  				 append_result);
@@ -415,7 +425,7 @@ 

  	}

  

  	ctx = cm_submit_h_init(NULL, method, url, poptGetArg(pctx),

- 			       ctype, accept,

+ 			       ctype, accept, NULL,

  			       cainfo, capath, sslcert, sslkey, sslpass,

  			       negotiate, negotiate_delegate,

  			       clientauth, cm_submit_h_env_modify_on,

file modified
+1
@@ -45,6 +45,7 @@ 

  					     const char *args,

  					     const char *content_type,

  					     const char *accept,

+ 					     const char *referer,

  					     const char *cainfo,

  					     const char *capath,

  					     const char *sslcert,

file modified
+6 -124
@@ -34,10 +34,6 @@ 

  	is-default: no

  	ca-type: EXTERNAL

  	helper-location: $libexecdir/ipa-submit

- CA 'certmaster':

- 	is-default: no

- 	ca-type: EXTERNAL

- 	helper-location: $libexecdir/certmaster-submit

  CA 'dogtag-ipa-renew-agent':

  	is-default: no

  	ca-type: EXTERNAL
@@ -45,8 +41,8 @@ 

  

  [[ API ]]

  [ simpleprop.py ]

- /org/fedorahosted/certmonger/cas/CA6

- /org/fedorahosted/certmonger/cas/CA6

+ /org/fedorahosted/certmonger/cas/CA5

+ /org/fedorahosted/certmonger/cas/CA5

  : -> : -k admin@localhost -> :

  0 -> 1 -> 0

  [ walk.py ]
@@ -182,7 +178,7 @@ 

  OK

  

  [ /org/fedorahosted/certmonger: org.fedorahosted.certmonger.get_known_cas ]

- dbus.Array([dbus.ObjectPath('/org/fedorahosted/certmonger/cas/CA1'), dbus.ObjectPath('/org/fedorahosted/certmonger/cas/CA2'), dbus.ObjectPath('/org/fedorahosted/certmonger/cas/CA3'), dbus.ObjectPath('/org/fedorahosted/certmonger/cas/CA4'), dbus.ObjectPath('/org/fedorahosted/certmonger/cas/CA5')], signature=dbus.Signature('o'))

+ dbus.Array([dbus.ObjectPath('/org/fedorahosted/certmonger/cas/CA1'), dbus.ObjectPath('/org/fedorahosted/certmonger/cas/CA2'), dbus.ObjectPath('/org/fedorahosted/certmonger/cas/CA3'), dbus.ObjectPath('/org/fedorahosted/certmonger/cas/CA4')], signature=dbus.Signature('o'))

  

  [ /org/fedorahosted/certmonger: org.fedorahosted.certmonger.get_requests ]

  dbus.Array([dbus.ObjectPath('/org/fedorahosted/certmonger/requests/Request2')], signature=dbus.Signature('o'))
@@ -508,7 +504,6 @@ 

   <node name="CA2"/>

   <node name="CA3"/>

   <node name="CA4"/>

-  <node name="CA5"/>

  </node>

  

  [ /org/fedorahosted/certmonger/cas/CA1: org.freedesktop.DBus.Introspectable.Introspect ]
@@ -942,10 +937,10 @@ 

  </node>

  

  [ /org/fedorahosted/certmonger/cas/CA4: org.fedorahosted.certmonger.ca.get_config_file_path ]

- $tmpdir/cas/20180327134236-2

+ $tmpdir/cas/20180327134236-3

  

  [ /org/fedorahosted/certmonger/cas/CA4: org.fedorahosted.certmonger.ca.get_nickname ]

- certmaster

+ dogtag-ipa-renew-agent

  

  [ /org/fedorahosted/certmonger/cas/CA4: org.fedorahosted.certmonger.ca.get_is_default ]

  0
@@ -957,7 +952,7 @@ 

  None

  

  [ /org/fedorahosted/certmonger/cas/CA4: org.fedorahosted.certmonger.ca.get_location ]

- $libexecdir/certmaster-submit

+ $libexecdir/dogtag-ipa-renew-agent-submit

  

  [ /org/fedorahosted/certmonger/cas/CA4: org.fedorahosted.certmonger.ca.get_issuer_names ]

  dbus.Array([], signature=dbus.Signature('s'))
@@ -965,116 +960,3 @@ 

  [ /org/fedorahosted/certmonger/cas/CA4: org.fedorahosted.certmonger.ca.refresh ]

  1

  

- [ /org/fedorahosted/certmonger/cas/CA5: org.freedesktop.DBus.Introspectable.Introspect ]

- <!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"

- "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">

- 

- <node name="/org/fedorahosted/certmonger/cas/CA5">

-  <interface name="org.freedesktop.DBus.Introspectable">

-   <method name="Introspect">

-    <arg name="xml_data" type="s" direction="out"/>

-   </method>

-  </interface>

-  <interface name="org.freedesktop.DBus.Properties">

-   <method name="Get">

-    <arg name="interface_name" type="s" direction="in"/>

-    <arg name="property_name" type="s" direction="in"/>

-    <arg name="value" type="v" direction="out"/>

-   </method>

-   <method name="Set">

-    <arg name="interface_name" type="s" direction="in"/>

-    <arg name="property_name" type="s" direction="in"/>

-    <arg name="value" type="v" direction="in"/>

-   </method>

-   <method name="GetAll">

-    <arg name="interface_name" type="s" direction="in"/>

-    <arg name="props" type="a{sv}" direction="out"/>

-   </method>

-   <signal name="PropertiesChanged">

-    <arg name="interface_name" type="s"/>

-    <arg name="changed_properties" type="a{sv}"/>

-    <arg name="invalidated_properties" type="as"/>

-   </signal>

-  </interface>

-  <interface name="org.fedorahosted.certmonger.ca">

-   <method name="get_config_file_path">

-    <arg name="path" type="s" direction="out"/>

-   </method>

-   <method name="get_nickname">

-    <arg name="nickname" type="s" direction="out"/>

-   </method>

-   <property name="nickname" type="s" access="read"/>

-   <property name="aka" type="s" access="read"/>

-   <method name="get_is_default">

-    <arg name="default" type="b" direction="out"/>

-   </method>

-   <property name="is-default" type="b" access="readwrite"/>

-   <method name="get_type">

-    <arg name="type" type="s" direction="out"/>

-   </method>

-   <method name="get_serial">

-    <arg name="serial_hex" type="s" direction="out"/>

-   </method>

-   <method name="get_location">

-    <arg name="path" type="s" direction="out"/>

-   </method>

-   <property name="external-helper" type="s" access="readwrite"/>

-   <method name="get_issuer_names">

-    <arg name="names" type="as" direction="out"/>

-   </method>

-   <method name="refresh">

-    <arg name="working" type="b" direction="out"/>

-   </method>

-   <property name="ca-error" type="s" access="read"/>

-   <property name="issuer-names" type="as" access="read"/>

-   <property name="root-certs" type="a(ss)" access="read"/>

-   <property name="root-other-certs" type="a(ss)" access="read"/>

-   <property name="other-certs" type="a(ss)" access="read"/>

-   <property name="required-enroll-attributes" type="as" access="read"/>

-   <property name="required-renew-attributes" type="as" access="read"/>

-   <property name="supported-profiles" type="as" access="read"/>

-   <property name="default-profile" type="s" access="read"/>

-   <property name="root-cert-files" type="as" access="readwrite"/>

-   <property name="root-other-cert-files" type="as" access="readwrite"/>

-   <property name="other-cert-files" type="as" access="readwrite"/>

-   <property name="root-cert-nssdbs" type="as" access="readwrite"/>

-   <property name="root-other-cert-nssdbs" type="as" access="readwrite"/>

-   <property name="other-cert-nssdbs" type="as" access="readwrite"/>

-   <property name="ca-presave-command" type="s" access="read"/>

-   <property name="ca-presave-uid" type="s" access="read"/>

-   <property name="ca-postsave-command" type="s" access="read"/>

-   <property name="ca-postsave-uid" type="s" access="read"/>

-   <property name="scep-cipher" type="s" access="readwrite"/>

-   <property name="scep-digest" type="s" access="readwrite"/>

-   <property name="scep-ca-identifier" type="s" access="readwrite"/>

-   <property name="scep-ca-capabilities" type="as" access="read"/>

-   <property name="scep-ra-cert" type="s" access="read"/>

-   <property name="scep-ca-cert" type="s" access="read"/>

-   <property name="scep-other-certs" type="s" access="read"/>

-  </interface>

- </node>

- 

- [ /org/fedorahosted/certmonger/cas/CA5: org.fedorahosted.certmonger.ca.get_config_file_path ]

- $tmpdir/cas/20180327134236-3

- 

- [ /org/fedorahosted/certmonger/cas/CA5: org.fedorahosted.certmonger.ca.get_nickname ]

- dogtag-ipa-renew-agent

- 

- [ /org/fedorahosted/certmonger/cas/CA5: org.fedorahosted.certmonger.ca.get_is_default ]

- 0

- 

- [ /org/fedorahosted/certmonger/cas/CA5: org.fedorahosted.certmonger.ca.get_type ]

- EXTERNAL

- 

- [ /org/fedorahosted/certmonger/cas/CA5: org.fedorahosted.certmonger.ca.get_serial ]

- None

- 

- [ /org/fedorahosted/certmonger/cas/CA5: org.fedorahosted.certmonger.ca.get_location ]

- $libexecdir/dogtag-ipa-renew-agent-submit

- 

- [ /org/fedorahosted/certmonger/cas/CA5: org.fedorahosted.certmonger.ca.get_issuer_names ]

- dbus.Array([], signature=dbus.Signature('s'))

- 

- [ /org/fedorahosted/certmonger/cas/CA5: org.fedorahosted.certmonger.ca.refresh ]

- 1

- 

IPA switched to a JSON-RPC API a few years ago. Stop using the legacy XML-RPC interface and use JSON instead.

Also make XML-RPC an optional requirement, disabled by default. This will disable certmaster support.

@abbra @frenaud I realize you are most likely unfamiliar with certmonger code but if you have time I'd appreciate a second set of eyes on this.

I made a build with these changes and the child KILL patch at https://copr.fedorainfracloud.org/coprs/rcritten/certmonger/

Instead of strcpy() and snprintf() below, please use krb5_build_principal_ext() or krb5_build_principal() from libkrb5. They differ in that one accepts explicit length and char-data pairs and the other one accepts null-terminated strings.

Actually, krb5_get_init_creds_keytab works just fine with tgs being NULL, that would be an equivalent of what you are doing with tgs above. It means that the whole code that generates tgs can be removed and tgs in this call can be replaced with NULL.

The use of talloc structures here is backwards to what it was designed for.
Please create a temporary context before doing a referrer thing above. Then allocate the referrer off that context and supply the context to cm_submit_h_init().
Finally, you'd only need to clean up the context, not individual elements, so no need to do talloc_free(referer); or talloc_free(hctx);.

One more thing is that you pass referer as 7th argument to cm_submit_h_init() and twice passing application/json to content_type and accept. However, 7th argument is cainfo and there is also cainfo passed in. Looks like it is an error?

(A comment around cm_submit_h_init() signature should be ignored, it is due to how pagure displays the diff.

Hi @rcritten

  • After an upgrade to your copr version, the CA helper "certmaster" is still displayed with getcert list-cas. A %triggerin scriptlet may be added to certmonger.spec in order to delete the CA helper definition from /var/lib/certmonger/cas

  • if I call getcert resubmit -i <id> with one of the IPA certs tracked by the IPA helper, I get an error in /var/log/httpd/error_log:

ipa: INFO: [jsonserver_kerb] host/master.domain.com@DOMAIN.COM: cert_request(None, principal='krbtgt/DOMAIN.COM@DOMAIN.COM', add=True): OptionError
ipa: INFO: exception OptionError caught when converting options: Unknown option: profile

and the journal displays:

certmonger[381314]: 2020-08-26 14:06:39 [381314] Running enrollment helper "/usr/libexec/certmonger/ipa-server-guard".
ipa-submit[381315]: JSON-RPC error: 3005: Unknown option: profile
ipa-submit[381315]: JSON-RPC error: 911: Missing or invalid HTTP Referer, Referer: https://master.domain.com/ipa/json

4 new commits added

  • Switch IPA calls to use the JSON-RPC endpoint instead of XMLRPC
  • Add Referer header option to the submit-h API
  • Make xmlrpc optional in the certmonger spec file, disable certmaster
  • Require jansson for IPA RPC calls, make xmlrpc optional
3 years ago

Dropped the tgs part.

Generate a talloc context and pass that to cm_submit_h_init().

The argument ordering looks ok to me.

I fixed the profile option (to profile_id)

And remove the certmaster CA in %post if xmlrpc isn't enabled.

I've submitted another copr build with the related fixes included.

Hi @rcritten
Tested with your copr repo:

  • the upgrade now properly removes certmaster CA helper
  • could not reproduce any more the renewal lock issue
  • getcert resubmit -i <id> now passes profile_id, the renewal is working

I will let @abbra review the code in depth but the PR is working as expected.

rebased onto 44ed8826b13b3787322a042dc4b7d0e0df5e3164

3 years ago

@ftweedal you have some experience with certmonger. If you have a chance, can you take a peek?

@rcritten sure, I will review it tomorrow (wednesday).

This doesn't look right (note the extra '+' in front of endif).

A couple of fixes are needed to get the srpm generation working:

diff --git a/certmonger.spec b/certmonger.spec
index 9d8f2ccb..2ccad7e6 100644
--- a/certmonger.spec
+++ b/certmonger.spec
@@ -172,7 +172,7 @@ fi
 if test $1 -gt 1 ; then
     %{_bindir}/getcert remove-ca -c certmaster 2>&1 || :
 fi
-+%endif
+%endif
 %if %{systemd}
 if test $1 -eq 1 ; then
        /bin/systemctl daemon-reload >/dev/null 2>&1 || :
diff --git a/configure.ac b/configure.ac
index 14991244..f2964856 100644
--- a/configure.ac
+++ b/configure.ac
@@ -876,6 +876,7 @@ else
        AM_CONDITIONAL(HAVE_EC,false)
        AM_CONDITIONAL(WITH_IPA,false)
        AM_CONDITIONAL(WITH_CERTMASTER,false)
+       AM_CONDITIONAL(WITH_XMLRPC,false)
        AM_CONDITIONAL(WITH_LOCAL,false)
        AM_CONDITIONAL(HAVE_UUID,false)
 fi

Also, an older commit (removal of DSA tests) broke some stuff. I made a separate PR to fix that: https://pagure.io/certmonger/pull-request/169 .

And the produced SRPM fails to build - haven't yet investigated but here's the COPR build: https://copr.fedorainfracloud.org/coprs/ftweedal/certmonger-jsonrpc/build/1663049/ .

It failed due to a missing BuildRequires: krb5-devel

Clearly I don't normally test the srpm target. I think I have it worked out. The current target pulls a fresh pull from upstream and not from the local directory to actually test out changes. I'll add a new target.

I also forgot to disable certmaster in the tests (it is included in the CA counts, for example).

I may just kill certmaster altogether in the tests and not try to do some acrobatics to support with and without, we'll see.

rebased onto 1de7c2e

3 years ago

I merged the dangling test targets patch, thanks.

I killed certmaster in the 028-dbus test so make check will pass.

I added a patch that adds a new target, local-srpm, to build from the current tree rather than from master. I took the output from 'make local-srpm' and ran it through mock and it built successfully.

@rcritten it's not for this PR, but the way SRPMs are built is yuck. Like... clone the origin, then clone it again, then do the stuff. It can be cleaned up a lot. I cannot think of any use case for the current srpm target to clone from origin.

Would also be nice to have a check for dirty working tree and abort with warning - based on how the srpm gets built, that's usually a mistake. I've been bitten several times making the SRPM, building, installing, testing, then realising the changes I wanted to test were not even included >_<

So I think: git diff --quiet to ensure no modified files, then git read-tree followed by git-checkout-index to a temp dir. (You can override the git index file and working dir with environment variables; see https://github.com/frasertweedale/dotfiles/blob/master/.gitconfig#L91-L103 for example).

@rcritten build works for me now. I installed IPA and did a getcert resubmit on the HTTP cert. I haven't done thorough testing, but I see in the diff that profile_id and cacn (issuer identifier) are being passed. Looks good from my POV.

Re: the srpm target yeah, I never understood its purpose which is why I hadn't tested with it. In the end it did prove to be useful since it discovered a typo and missing BR in the sample spec file.

I'm honestly not sure how much effort i want to put into supporting it.

I think this works well enough to merge into master and do additional live testing in Fedora via the FreeIPA CI system.

Pull-Request has been merged by rcritten

3 years ago