+ talloc_steal(mem_ctx, apcs);
+ *rc=TR_CFG_SUCCESS;
+
+ cleanup:
+ talloc_free(tmp_ctx);
+ return apcs;
+}
+
+static TR_NAME *tr_cfg_parse_name(TALLOC_CTX *mem_ctx, json_t *jname, TR_CFG_RC *rc)
+{
+ TR_NAME *name=NULL;
+ *rc=TR_CFG_ERROR;
+
+ if ((jname==NULL) || (!json_is_string(jname))) {
+ tr_err("tr_cfg_parse_name: name missing or not a string");
+ *rc=TR_CFG_BAD_PARAMS;
+ name=NULL;
+ } else {
+ name=tr_new_name(json_string_value(jname));
+ if (name==NULL) {
+ tr_err("tr_cfg_parse_name: could not allocate name");
+ *rc=TR_CFG_NOMEM;
+ } else {
+ *rc=TR_CFG_SUCCESS;
+ }
+ }
+ return name;
+}
+
+static int tr_cfg_parse_shared_config(json_t *jsc, TR_CFG_RC *rc)
+{
+ const char *shared=NULL;
+ *rc=TR_CFG_SUCCESS;
+
+ if ((jsc==NULL) ||
+ (!json_is_string(jsc)) ||
+ (NULL==(shared=json_string_value(jsc)))) {
+ *rc=TR_CFG_BAD_PARAMS;
+ return -1;
+ }
+
+ if (0==strcmp(shared, "no"))
+ return 0;
+ else if (0==strcmp(shared, "yes"))
+ return 1;
+
+ /* any other value is an error */
+ tr_debug("tr_cfg_parse_shared_config: invalid shared_config value \"%s\" (should be \"yes\" or \"no\")",
+ shared);
+ *rc=TR_CFG_NOPARSE;
+ return -1;
+}
+
+static TR_REALM_ORIGIN tr_cfg_realm_origin(json_t *jrealm)
+{
+ json_t *jremote=json_object_get(jrealm, "remote");
+ const char *s=NULL;
+
+ if (jremote==NULL)
+ return TR_REALM_LOCAL;
+ if (!json_is_string(jremote)) {
+ tr_warning("tr_cfg_realm_origin: \"remote\" is not a string, assuming this is a local realm.");
+ return TR_REALM_LOCAL;
+ }
+ s=json_string_value(jremote);
+ if (strcasecmp(s, "yes")==0)
+ return TR_REALM_REMOTE_INCOMPLETE;
+ else if (strcasecmp(s, "no")!=0)
+ tr_warning("tr_cfg_realm_origin: \"remote\" is neither 'yes' nor 'no', assuming this is a local realm.");
+
+ return TR_REALM_LOCAL;
+}
+
+/* Parse the identity provider object from a realm and fill in the given TR_IDP_REALM. */
+static TR_CFG_RC tr_cfg_parse_idp(TR_IDP_REALM *idp, json_t *jidp)
+{
+ TALLOC_CTX *tmp_ctx=talloc_new(NULL);
+ TR_APC *apcs=NULL;
+ TR_AAA_SERVER *aaa=NULL;
+ TR_CFG_RC rc=TR_CFG_ERROR;
+
+ if (jidp==NULL)
+ goto cleanup;
+
+ idp->shared_config=tr_cfg_parse_shared_config(json_object_get(jidp, "shared_config"), &rc);
+ if (rc!=TR_CFG_SUCCESS) {
+ tr_err("tr_cfg_parse_idp: missing or malformed shared_config specification");
+ rc=TR_CFG_NOPARSE;
+ goto cleanup;
+ }
+
+ apcs=tr_cfg_parse_apcs(tmp_ctx, json_object_get(jidp, "apcs"), &rc);
+ if ((rc!=TR_CFG_SUCCESS) || (apcs==NULL)) {
+ tr_err("tr_cfg_parse_idp: unable to parse APC");
+ rc=TR_CFG_NOPARSE;
+ goto cleanup;
+ }
+
+ aaa=tr_cfg_parse_aaa_servers(idp, json_object_get(jidp, "aaa_servers"), &rc);
+ if (rc!=TR_CFG_SUCCESS) {
+ tr_err("tr_cfg_parse_idp: unable to parse AAA servers");
+ rc=TR_CFG_NOPARSE;
+ goto cleanup;
+ }
+
+ tr_debug("tr_cfg_parse_idp: APC=\"%.*s\"",
+ apcs->id->len,
+ apcs->id->buf);
+
+ /* done, fill in the idp structures */
+ idp->apcs=apcs;
+ talloc_steal(idp, apcs);
+ idp->aaa_servers=aaa;
+ rc=TR_CFG_SUCCESS;
+
+cleanup:
+ if (rc!=TR_CFG_SUCCESS) {
+ if (apcs!=NULL)
+ tr_apc_free(apcs);
+ if (aaa!=NULL)
+ tr_aaa_server_free(aaa);
+ }
+
+ talloc_free(tmp_ctx);
+ return rc;
+}
+
+/* parses idp realm */
+static TR_IDP_REALM *tr_cfg_parse_one_idp_realm(TALLOC_CTX *mem_ctx, json_t *jrealm, TR_CFG_RC *rc)
+{
+ TALLOC_CTX *tmp_ctx=talloc_new(NULL);
+ TR_IDP_REALM *realm=NULL;
+ TR_CFG_RC call_rc=TR_CFG_ERROR;
+
+ *rc=TR_CFG_ERROR; /* default to error if not set */
+
+ if ((!jrealm) || (!rc)) {
+ tr_err("tr_cfg_parse_one_idp_realm: Bad parameters.");
+ if (rc)
+ *rc=TR_CFG_BAD_PARAMS;
+ goto cleanup;
+ }
+
+ if (NULL==(realm=tr_idp_realm_new(tmp_ctx))) {
+ tr_err("tr_cfg_parse_one_idp_realm: could not allocate idp realm.");
+ *rc=TR_CFG_NOMEM;
+ goto cleanup;
+ }
+
+ realm->origin=tr_cfg_realm_origin(jrealm);
+ if (realm->origin!=TR_REALM_LOCAL) {
+ tr_debug("tr_cfg_parse_one_idp_realm: realm is remote, should not have full IdP info.");
+ *rc=TR_CFG_NOPARSE;
+ goto cleanup;
+ }
+
+ /* must have a name */
+ realm->realm_id=tr_cfg_parse_name(realm,
+ json_object_get(jrealm, "realm"),
+ &call_rc);
+ if ((call_rc!=TR_CFG_SUCCESS) || (realm->realm_id==NULL)) {
+ tr_err("tr_cfg_parse_one_idp_realm: could not parse realm name");
+ *rc=TR_CFG_NOPARSE;
+ goto cleanup;
+ }
+ tr_debug("tr_cfg_parse_one_idp_realm: realm_id=\"%.*s\"",
+ realm->realm_id->len,
+ realm->realm_id->buf);
+
+ call_rc=tr_cfg_parse_idp(realm, json_object_get(jrealm, "identity_provider"));
+ if (call_rc!=TR_CFG_SUCCESS) {
+ tr_err("tr_cfg_parse_one_idp_realm: could not parse identity_provider.");
+ *rc=TR_CFG_NOPARSE;
+ goto cleanup;
+ }
+
+ *rc=TR_CFG_SUCCESS;
+
+cleanup:
+ if (*rc==TR_CFG_SUCCESS)
+ talloc_steal(mem_ctx, realm);
+ else {
+ talloc_free(realm);
+ realm=NULL;
+ }
+
+ talloc_free(tmp_ctx);
+ return realm;
+}
+
+ /* Determine whether the realm is an IDP realm */
+static int tr_cfg_is_idp_realm(json_t *jrealm)
+{
+ /* If a realm spec contains an identity_provider, it's an IDP realm. */
+ if (NULL != json_object_get(jrealm, "identity_provider"))
+ return 1;
+ else
+ return 0;
+}
+
+static TR_IDP_REALM *tr_cfg_parse_one_remote_realm(TALLOC_CTX *mem_ctx, json_t *jrealm, TR_CFG_RC *rc)
+{
+ TALLOC_CTX *tmp_ctx=talloc_new(NULL);
+ TR_IDP_REALM *realm=talloc(mem_ctx, TR_IDP_REALM);
+
+ *rc=TR_CFG_ERROR; /* default to error if not set */
+
+ if ((!jrealm) || (!rc)) {
+ tr_err("tr_cfg_parse_one_remote_realm: Bad parameters.");
+ if (rc)
+ *rc=TR_CFG_BAD_PARAMS;
+ goto cleanup;
+ }
+
+ if (NULL==(realm=tr_idp_realm_new(tmp_ctx))) {
+ tr_err("tr_cfg_parse_one_remote_realm: could not allocate idp realm.");
+ *rc=TR_CFG_NOMEM;
+ goto cleanup;
+ }
+
+ /* must have a name */
+ realm->realm_id=tr_cfg_parse_name(realm,
+ json_object_get(jrealm, "realm"),
+ rc);
+ if ((*rc!=TR_CFG_SUCCESS) || (realm->realm_id==NULL)) {
+ tr_err("tr_cfg_parse_one_remote_realm: could not parse realm name");
+ *rc=TR_CFG_NOPARSE;
+ goto cleanup;
+ }
+ tr_debug("tr_cfg_parse_one_remote_realm: realm_id=\"%.*s\"",
+ realm->realm_id->len,
+ realm->realm_id->buf);
+
+ realm->origin=tr_cfg_realm_origin(jrealm);
+ *rc=TR_CFG_SUCCESS;
+
+cleanup:
+ if (*rc==TR_CFG_SUCCESS)
+ talloc_steal(mem_ctx, realm);
+ else {
+ talloc_free(realm);
+ realm=NULL;
+ }
+
+ talloc_free(tmp_ctx);
+ return realm;
+}
+
+static int tr_cfg_is_remote_realm(json_t *jrealm)
+{
+ return (tr_cfg_realm_origin(jrealm)!=TR_REALM_LOCAL);
+}
+
+/* Parse any idp realms in the j_realms object. Ignores other realm types. */
+static TR_IDP_REALM *tr_cfg_parse_idp_realms(TALLOC_CTX *mem_ctx, json_t *jrealms, TR_CFG_RC *rc)
+{
+ TALLOC_CTX *tmp_ctx=talloc_new(NULL);
+ TR_IDP_REALM *realms=NULL;
+ TR_IDP_REALM *new_realm=NULL;
+ json_t *this_jrealm=NULL;
+ int ii=0;
+
+ *rc=TR_CFG_ERROR;
+ if ((jrealms==NULL) || (!json_is_array(jrealms))) {
+ tr_err("tr_cfg_parse_idp_realms: realms not an array");
+ *rc=TR_CFG_BAD_PARAMS;
+ goto cleanup;
+ }
+
+ for (ii=0; ii<json_array_size(jrealms); ii++) {
+ this_jrealm=json_array_get(jrealms, ii);
+ if (tr_cfg_is_idp_realm(this_jrealm)) {
+ new_realm=tr_cfg_parse_one_idp_realm(tmp_ctx, this_jrealm, rc);
+ if ((*rc)!=TR_CFG_SUCCESS) {
+ tr_err("tr_cfg_parse_idp_realms: error decoding realm entry %d", ii+1);
+ *rc=TR_CFG_NOPARSE;
+ goto cleanup;
+ }
+ tr_idp_realm_add(realms, new_realm);
+ } else if (tr_cfg_is_remote_realm(this_jrealm)) {
+ new_realm=tr_cfg_parse_one_remote_realm(tmp_ctx, this_jrealm, rc);
+ if ((*rc)!=TR_CFG_SUCCESS) {
+ tr_err("tr_cfg_parse_idp_realms: error decoding remote realm entry %d", ii+1);
+ *rc=TR_CFG_NOPARSE;
+ goto cleanup;
+ }
+ tr_idp_realm_add(realms, new_realm);
+ }
+ }
+
+ *rc=TR_CFG_SUCCESS;
+ talloc_steal(mem_ctx, realms);
+
+cleanup:
+ talloc_free(tmp_ctx);
+ return realms;
+}
+
+static TR_GSS_NAMES *tr_cfg_parse_gss_names(TALLOC_CTX *mem_ctx, json_t *jgss_names, TR_CFG_RC *rc)
+{
+ TALLOC_CTX *tmp_ctx=talloc_new(NULL);
+ TR_GSS_NAMES *gn=NULL;
+ json_t *jname=NULL;
+ int ii=0;
+ TR_NAME *name=NULL;
+
+ if ((rc==NULL) || (jgss_names==NULL)) {
+ tr_err("tr_cfg_parse_gss_names: Bad parameters.");
+ *rc=TR_CFG_BAD_PARAMS;
+
+ }
+
+ if (!json_is_array(jgss_names)) {
+ tr_err("tr_cfg_parse_gss_names: gss_names not an array.");
+ *rc=TR_CFG_NOPARSE;
+ goto cleanup;
+ }
+
+ gn=tr_gss_names_new(tmp_ctx);
+ for (ii=0; ii<json_array_size(jgss_names); ii++) {
+ jname=json_array_get(jgss_names, ii);
+ if (!json_is_string(jname)) {
+ tr_err("tr_cfg_parse_gss_names: Encountered non-string gss name.");
+ *rc=TR_CFG_NOPARSE;
+ goto cleanup;
+ }
+
+ name=tr_new_name(json_string_value(jname));
+ if (name==NULL) {
+ tr_err("tr_cfg_parse_gss_names: Out of memory allocating gss name.");
+ *rc=TR_CFG_NOMEM;
+ goto cleanup;
+ }
+
+ if (tr_gss_names_add(gn, name)!=0) {
+ tr_free_name(name);
+ tr_err("tr_cfg_parse_gss_names: Unable to add gss name to RP client.");
+ *rc=TR_CFG_ERROR;
+ goto cleanup;
+ }
+ }
+
+ talloc_steal(mem_ctx, gn);
+ *rc=TR_CFG_SUCCESS;
+
+ cleanup:
+ talloc_free(tmp_ctx);
+ if ((*rc!=TR_CFG_SUCCESS) && (gn!=NULL))
+ gn=NULL;
+ return gn;
+}
+
+/* default filter accepts realm and *.realm */
+static TR_FILTER_SET *tr_cfg_default_filters(TALLOC_CTX *mem_ctx, TR_NAME *realm, TR_CFG_RC *rc)
+{
+ TALLOC_CTX *tmp_ctx=talloc_new(NULL);
+ TR_FILTER *filt=NULL;
+ TR_FILTER_SET *filt_set=NULL;
+ TR_CONSTRAINT *cons=NULL;
+ TR_NAME *name=NULL;
+ TR_NAME *n_prefix=tr_new_name("*.");
+ TR_NAME *n_rp_realm_1=tr_new_name("rp_realm");
+ TR_NAME *n_rp_realm_2=tr_new_name("rp_realm");
+ TR_NAME *n_domain=tr_new_name("domain");
+ TR_NAME *n_realm=tr_new_name("realm");
+
+
+ if ((realm==NULL) || (rc==NULL)) {
+ tr_debug("tr_cfg_default_filters: invalid arguments.");
+ if (rc!=NULL)
+ *rc=TR_CFG_BAD_PARAMS;
+ goto cleanup;
+ }
+
+ if ((n_prefix==NULL) ||
+ (n_rp_realm_1==NULL) ||
+ (n_rp_realm_2==NULL) ||
+ (n_domain==NULL) ||
+ (n_realm==NULL)) {
+ tr_debug("tr_cfg_default_filters: unable to allocate names.");
+ *rc=TR_CFG_NOMEM;
+ goto cleanup;
+ }
+
+ filt=tr_filter_new(tmp_ctx);
+ if (filt==NULL) {
+ tr_debug("tr_cfg_default_filters: could not allocate filter.");
+ *rc=TR_CFG_NOMEM;
+ goto cleanup;
+ }
+ tr_filter_set_type(filt, TR_FILTER_TYPE_TID_INBOUND);
+ filt->lines[0]=tr_fline_new(filt);
+ if (filt->lines[0]==NULL) {
+ tr_debug("tr_cfg_default_filters: could not allocate filter line.");
+ *rc=TR_CFG_NOMEM;
+ goto cleanup;
+ }
+
+ filt->lines[0]->action=TR_FILTER_ACTION_ACCEPT;
+ filt->lines[0]->specs[0]=tr_fspec_new(filt->lines[0]);
+ filt->lines[0]->specs[0]->field=n_rp_realm_1;
+ n_rp_realm_1=NULL; /* we don't own this name any more */
+
+ name=tr_dup_name(realm);
+ if (name==NULL) {
+ tr_debug("tr_cfg_default_filters: could not allocate realm name.");
+ *rc=TR_CFG_NOMEM;
+ goto cleanup;
+ }
+ tr_fspec_add_match(filt->lines[0]->specs[0], name);
+ name=NULL; /* we no longer own the name */
+
+ /* now do the wildcard name */
+ filt->lines[0]->specs[1]=tr_fspec_new(filt->lines[0]);
+ filt->lines[0]->specs[1]->field=n_rp_realm_2;
+ n_rp_realm_2=NULL; /* we don't own this name any more */
+
+ if (NULL==(name=tr_name_cat(n_prefix, realm))) {
+ tr_debug("tr_cfg_default_filters: could not allocate wildcard realm name.");
+ *rc=TR_CFG_NOMEM;
+ goto cleanup;
+ }
+
+ tr_fspec_add_match(filt->lines[0]->specs[1], name);
+ name=NULL; /* we no longer own the name */
+
+ /* domain constraint */
+ if (NULL==(cons=tr_constraint_new(filt->lines[0]))) {
+ tr_debug("tr_cfg_default_filters: could not allocate domain constraint.");
+ *rc=TR_CFG_NOMEM;
+ goto cleanup;
+ }
+
+ cons->type=n_domain;
+ n_domain=NULL; /* belongs to the constraint now */
+ name=tr_dup_name(realm);
+ if (name==NULL) {
+ tr_debug("tr_cfg_default_filters: could not allocate realm name for domain constraint.");
+ *rc=TR_CFG_NOMEM;
+ goto cleanup;
+ }
+ cons->matches[0]=name;
+ name=tr_name_cat(n_prefix, realm);
+ if (name==NULL) {
+ tr_debug("tr_cfg_default_filters: could not allocate wildcard realm name for domain constraint.");
+ *rc=TR_CFG_NOMEM;
+ goto cleanup;
+ }
+ cons->matches[1]=name;
+ name=NULL;
+ filt->lines[0]->domain_cons=cons;
+
+
+ /* realm constraint */
+ if (NULL==(cons=tr_constraint_new(filt->lines[0]))) {
+ tr_debug("tr_cfg_default_filters: could not allocate realm constraint.");
+ *rc=TR_CFG_NOMEM;
+ goto cleanup;
+ }
+
+ cons->type=n_realm;
+ n_realm=NULL; /* belongs to the constraint now */
+ name=tr_dup_name(realm);
+ if (name==NULL) {
+ tr_debug("tr_cfg_default_filters: could not allocate realm name for realm constraint.");
+ *rc=TR_CFG_NOMEM;
+ goto cleanup;
+ }
+ cons->matches[0]=name;
+ name=tr_name_cat(n_prefix, realm);
+ if (name==NULL) {
+ tr_debug("tr_cfg_default_filters: could not allocate wildcard realm name for realm constraint.");
+ *rc=TR_CFG_NOMEM;
+ goto cleanup;
+ }
+ cons->matches[1]=name;
+ name=NULL;
+ filt->lines[0]->realm_cons=cons;
+
+ /* put the filter in a set */
+ filt_set=tr_filter_set_new(tmp_ctx);
+ if ((filt_set==NULL)||(0!=tr_filter_set_add(filt_set, filt))) {
+ tr_debug("tr_cfg_default_filters: could not allocate filter set.");
+ *rc=TR_CFG_NOMEM;
+ goto cleanup;
+ }
+ talloc_steal(mem_ctx, filt_set);
+
+cleanup:
+ talloc_free(tmp_ctx);
+
+ if (*rc!=TR_CFG_SUCCESS)
+ filt=NULL;
+
+ if (n_prefix!=NULL)
+ tr_free_name(n_prefix);
+ if (n_rp_realm_1!=NULL)
+ tr_free_name(n_rp_realm_1);
+ if (n_rp_realm_2!=NULL)
+ tr_free_name(n_rp_realm_2);
+ if (n_realm!=NULL)
+ tr_free_name(n_realm);
+ if (n_domain!=NULL)
+ tr_free_name(n_domain);
+ if (name!=NULL)
+ tr_free_name(name);
+
+ return filt_set;
+}
+
+/* parses rp client */
+static TR_RP_CLIENT *tr_cfg_parse_one_rp_client(TALLOC_CTX *mem_ctx, json_t *jrealm, TR_CFG_RC *rc)
+{
+ TALLOC_CTX *tmp_ctx=talloc_new(NULL);
+ TR_RP_CLIENT *client=NULL;
+ TR_CFG_RC call_rc=TR_CFG_ERROR;
+ TR_FILTER_SET *new_filts=NULL;
+ TR_NAME *realm=NULL;
+ json_t *jfilt=NULL;
+ json_t *jrealm_id=NULL;
+
+ *rc=TR_CFG_ERROR; /* default to error if not set */
+
+ if ((!jrealm) || (!rc)) {
+ tr_err("tr_cfg_parse_one_rp_client: Bad parameters.");
+ if (rc)
+ *rc=TR_CFG_BAD_PARAMS;
+ goto cleanup;
+ }
+
+ if ((NULL==(jrealm_id=json_object_get(jrealm, "realm"))) || (!json_is_string(jrealm_id))) {
+ tr_debug("tr_cfg_parse_one_rp_client: no realm ID found.");
+ *rc=TR_CFG_BAD_PARAMS;
+ goto cleanup;
+ }
+
+ tr_debug("tr_cfg_parse_one_rp_client: realm_id=\"%s\"", json_string_value(jrealm_id));
+ realm=tr_new_name(json_string_value(jrealm_id));
+ if (realm==NULL) {
+ tr_err("tr_cfg_parse_one_rp_client: could not allocate realm ID.");
+ *rc=TR_CFG_NOMEM;
+ goto cleanup;
+ }
+
+ if (NULL==(client=tr_rp_client_new(tmp_ctx))) {
+ tr_err("tr_cfg_parse_one_rp_client: could not allocate rp client.");
+ *rc=TR_CFG_NOMEM;
+ goto cleanup;