/* Called by: zxcot_main */ static int zxid_reg_svc(zxid_conf* cf, int bs_reg, int dry_run, const char* ddimd, const char* duid) { char sha1_name[28]; char path[ZXID_MAX_BUF]; int got; fdtype fd; struct zx_root_s* r; zxid_epr* epr; struct zx_str* ss; struct zx_str* tt; read_all_fd(fdstdin, buf, sizeof(buf)-1, &got); /* Read EPR */ buf[got] = 0; r = zx_dec_zx_root(cf->ctx, got, buf, "cot reg_svc"); if (!r || !r->EndpointReference) { ERR("Failed to parse <EndpointReference> buf(%.*s)", got, buf); return 1; } epr = r->EndpointReference; if (!ZX_SIMPLE_ELEM_CHK(epr->Address)) { ERR("<EndpointReference> MUST have <Address> element buf(%.*s)", got, buf); return 1; } if (!epr->Metadata) { ERR("<EndpointReference> MUST have <Metadata> element buf(%.*s)", got, buf); return 1; } if (!ZX_SIMPLE_ELEM_CHK(epr->Metadata->ProviderID)) { ERR("<EndpointReference> MUST have <Metadata> with <ProviderID> element buf(%.*s)", got, buf); return 1; } if (!epr->Metadata->ServiceType) { ERR("<EndpointReference> MUST have <ServiceType> element buf(%.*s)", got, buf); return 1; } /* *** possibly add something here and double check the required fields are available. */ ss = zx_easy_enc_elem_opt(cf, &epr->gg); if (!ss) return 2; #if 0 // *** wrong tt = ZX_GET_CONTENT(epr->Metadata->ProviderID); #else tt = ZX_GET_CONTENT(epr->Metadata->ServiceType); #endif got = MIN(tt->len, sizeof(path)-1); memcpy(path, tt?tt->s:"", got); path[got] = 0; zxid_fold_svc(path, got); sha1_safe_base64(sha1_name, ss->len, ss->s); sha1_name[27] = 0; if (verbose) fprintf(stderr, "Registering metadata in %s%s,%s\n", ddimd, path, sha1_name); if (dry_run) { if (verbose) fprintf(stderr, "Register EPR dry run. Would have written to path(%s%s,%s). " "You may also want to\n" " touch %s.all/.bs/%s,%s\n\n", ddimd, path, sha1_name, uiddir, path, sha1_name); fflush(stdin); write_all_fd(fdstdout, ss->s, ss->len); zx_str_free(cf->ctx, ss); return 0; } D("Register EPR path(%s%s,%s) in discovery metadata.", ddimd, path, sha1_name); fd = open_fd_from_path(O_CREAT | O_WRONLY | O_TRUNC, 0666, "zxcot -b", 1, "%s%s,%s", ddimd, path, sha1_name); if (fd == BADFD) { perror("open epr for registering"); ERR("Failed to open file for writing: sha1_name(%s,%s) to service registration", path, sha1_name); zx_str_free(cf->ctx, ss); return 1; } write_all_fd(fd, ss->s, ss->len); zx_str_free(cf->ctx, ss); close_file(fd, (const char*)__FUNCTION__); if (bs_reg) { if (verbose) fprintf(stderr, "Activating bootstrap %s.all/.bs/%s,%s", duid, path, sha1_name); if (!dryrun) { fd = open_fd_from_path(O_CREAT | O_WRONLY | O_TRUNC, 0666, "zxcot -bs", 1, "%s.all/.bs/%s,%s", duid, path, sha1_name); if (fd == BADFD) { perror("open epr for bootstrap activation"); ERR("Failed to open file for writing: sha1_name(%s,%s) to bootstrap activation", path, sha1_name); return 1; } write_all_fd(fd, "", 0); close_file(fd, (const char*)__FUNCTION__); } } else { D("You may also want to activate bootstrap by\n touch %s.all/.bs/%s,%s", duid, path, sha1_name); } return 0; }
/* Called by: covimp_test x3, zxid_call_epr, zxid_wsc_valid_resp */ int zxid_wsc_valid_re_env(zxid_conf* cf, zxid_ses* ses, const char* az_cred, struct zx_e_Envelope_s* env, const char* enve) { int n_refs = 0; struct zxsig_ref refs[ZXID_N_WSF_SIGNED_HEADERS]; struct timeval ourts; struct timeval srcts = {0,501000}; zxid_entity* wsc_meta; struct zx_wsse_Security_s* sec; struct zx_e_Header_s* hdr; struct zx_str* issuer; struct zx_str* logpath; struct zx_str* relto; struct zx_str ss; zxid_cgi cgi; GETTIMEOFDAY(&ourts, 0); zxid_set_fault(cf, ses, 0); zxid_set_tas3_status(cf, ses, 0); if (cf->valid_opt & ZXID_VALID_OPT_SKIP_RESP_HDR) { ERR("WARNING! Important response security validations disabled by VALID_OPT=0x%x", cf->valid_opt); return 1; } if (!env) { ERR("No <e:Envelope> found. enve(%s)", STRNULLCHK(enve)); zxid_set_fault(cf, ses, zxid_mk_fault(cf, 0, TAS3_PEP_RS_IN, "e:Server", "No SOAP Envelope found.", "IDStarMsgNotUnderstood", 0, 0, 0)); return 0; } hdr = env->Header; if (!hdr) { ERR("No <e:Header> found. %d", 0); zxid_set_fault(cf, ses, zxid_mk_fault(cf, 0, TAS3_PEP_RS_IN, "e:Server", "No SOAP Header found.", "IDStarMsgNotUnderstood", 0, 0, 0)); return 0; } if (!ZX_SIMPLE_ELEM_CHK(hdr->MessageID)) { ERR("No <a:MessageID> found. %d", 0); zxid_set_fault(cf, ses, zxid_mk_fault(cf, 0, TAS3_PEP_RS_IN, "e:Server", "No MessageID header found.", "IDStarMsgNotUnderstood", 0, 0, 0)); return 0; } relto = ZX_GET_CONTENT(hdr->RelatesTo); if (relto && relto->len) { if (ses->wsc_msgid) { if (strlen(ses->wsc_msgid) == relto->len && !memcmp(ses->wsc_msgid, relto->s, relto->len)) { D("RelatesTo check OK %d",1); } else { /* N.B. [SOAPBinding2] p.27, ll.818-822 indicates RelatesTo checking as SHOULD. */ if (cf->relto_fatal) { ERR("<a:RelatesTo> (%.*s) does not match request msgid(%s).", relto->len, relto->s, ses->wsc_msgid); zxid_set_fault(cf, ses, zxid_mk_fault(cf, 0, TAS3_PEP_RS_IN, "e:Server", "RelatesTo in response does not match request MessageID.", "InvalidRefToMsgID", 0, 0, 0)); return 0; } else { INFO("<a:RelatesTo> (%.*s) does not match request msgid(%s), but configured to ignore this error (RELTO_FATAL=0).", relto->len, relto->s, ses->wsc_msgid); } } } else { INFO("Session does not have wsc_msgid. Skipping <a:RelatesTo> check. %d",0); } } else { if (cf->relto_fatal) { ERR("No <a:RelatesTo> found. %d", 0); zxid_set_fault(cf, ses, zxid_mk_fault(cf, 0, TAS3_PEP_RS_IN, "e:Server", "No RelatesTo header found in reply.", "IDStarMsgNotUnderstood", 0, 0, 0)); return 0; } else { INFO("No <a:RelatesTo> found, but configured to ignore this (RELTO_FATAL=0). %d", 0); D("No RelTo OK enve(%s)", STRNULLCHK(enve)); } } if (!hdr->Sender || !hdr->Sender->providerID && !hdr->Sender->affiliationID) { ERR("No <b:Sender> found (or missing providerID or affiliationID). %p", hdr->Sender); zxid_set_fault(cf, ses, zxid_mk_fault(cf, 0, TAS3_PEP_RS_IN, "e:Server", "No b:Sender header found (or missing providerID or affiliationID).", "IDStarMsgNotUnderstood", 0, 0, 0)); return 0; } issuer = &hdr->Sender->providerID->g; /* Validate message signature (*** add Issuer trusted check, CA validation, etc.) */ if (!(sec = hdr->Security)) { ERR("No <wsse:Security> found. %d", 0); zxid_set_fault(cf, ses, zxid_mk_fault(cf, 0, TAS3_PEP_RS_IN, "e:Server", "No wsse:Security header found.", "IDStarMsgNotUnderstood", 0, 0, 0)); return 0; } wsc_meta = zxid_get_ent_ss(cf, issuer); if (!wsc_meta) { ses->sigres = ZXSIG_NO_SIG; if (cf->nosig_fatal) { INFO("Unable to find SAML metadata for Sender(%.*s), but configured to ignore this problem (NOSIG_FATAL=0).", issuer->len, issuer->s); } else { ERR("Unable to find SAML metadata for Sender(%.*s).", issuer->len, issuer->s); zxid_set_fault(cf, ses, zxid_mk_fault(cf, 0, TAS3_PEP_RS_IN, "e:Server", "No unable to find SAML metadata for sender.", "ProviderIDNotValid", 0, 0, 0)); return 0; } } if (!sec->Signature || !sec->Signature->SignedInfo || !sec->Signature->SignedInfo->Reference) { ses->sigres = ZXSIG_NO_SIG; if (cf->wsp_nosig_fatal) { ERR("No Security/Signature found. %p", sec->Signature); zxid_set_fault(cf, ses, zxid_mk_fault(cf, 0, TAS3_PEP_RS_IN, "e:Server", "No wsse:Security/ds:Signature found.", TAS3_STATUS_NOSIG, 0, 0, 0)); return 0; } else { INFO("No Security/Signature found, but configured to ignore this problem (WSP_NOSIG_FATAL=0). %p", sec->Signature); } } else { ZERO(refs, sizeof(refs)); n_refs = zxid_hunt_sig_parts(cf, n_refs, refs, sec->Signature->SignedInfo->Reference, hdr, env->Body); /* *** Consider adding BDY and STR */ ses->sigres = zxsig_validate(cf->ctx, wsc_meta?wsc_meta->sign_cert:0, sec->Signature, n_refs, refs); zxid_sigres_map(ses->sigres, &cgi.sigval, &cgi.sigmsg); if (cf->sig_fatal && ses->sigres) { ERR("Fail due to failed message signature sigres=%d", ses->sigres); zxid_set_fault(cf, ses, zxid_mk_fault(cf, 0, TAS3_PEP_RS_IN, "e:Server", "Message signature did not validate.", TAS3_STATUS_BADSIG, 0, 0, 0)); return 0; } } if (!zxid_timestamp_chk(cf, ses, sec->Timestamp, &ourts, &srcts, TAS3_PEP_RS_IN, "e:Server")) return 0; if (hdr->UsageDirective) { if (hdr->UsageDirective->Obligation && ZX_GET_CONTENT(hdr->UsageDirective->Obligation->AttributeAssignment)) { ses->rcvd_usagedir = zx_str_to_c(cf->ctx, ZX_GET_CONTENT(hdr->UsageDirective->Obligation->AttributeAssignment)); D("Found TAS3 UsageDirective with obligation(%s)", ses->rcvd_usagedir); } else if (ZX_GET_CONTENT(hdr->UsageDirective)) { ses->rcvd_usagedir = zx_str_to_c(cf->ctx, ZX_GET_CONTENT(hdr->UsageDirective)); D("Found unknown UsageDirective(%s)", ses->rcvd_usagedir); } else { ERR("UsageDirective empty or not understood. %p", hdr->UsageDirective->Dict); } } zxid_ses_to_pool(cf, ses); zxid_snarf_eprs_from_ses(cf, ses); /* Harvest attributes and bootstrap(s) */ if (hdr->Status && hdr->Status->code && (hdr->Status->code->g.len != 2 || hdr->Status->code->g.s[0] != 'O' || hdr->Status->code->g.s[1] != 'K')) { ERR("TAS3 or app level error code(%.*s)", hdr->Status->code->g.len, hdr->Status->code->g.s); return 0; } /* Call Rs-In PDP */ if (!zxid_query_ctlpt_pdp(cf, ses, az_cred, env, TAS3_PEP_RS_IN, "e:Client", cf->pepmap_rsin)) { return 0; } /* *** execute (or store for future execution) the obligations. */ ss.s = (char*)enve; ss.len = strlen(enve); logpath = zxlog_path(cf, issuer, ZX_GET_CONTENT(hdr->MessageID), ZXLOG_RELY_DIR, ZXLOG_MSG_KIND, 1); if (zxlog_dup_check(cf, logpath, "validate response")) { if (cf->dup_msg_fatal) { zxlog_blob(cf, cf->log_rely_msg, logpath, &ss, "validate response dup err"); zxid_set_fault(cf, ses, zxid_mk_fault(cf, 0, TAS3_PEP_RS_IN, "e:Server", "Duplicate Message.", "DuplicateMsg", 0, 0, 0)); return 0; } else { INFO("Duplicate message detected, but configured to ignore this (DUP_MSG_FATAL=0). %d",0); } } zxlog_blob(cf, cf->log_rely_msg, logpath, &ss, "validate response"); zxlog(cf, &ourts, &srcts, 0, issuer, 0, ses->a7n?&ses->a7n->ID->g:0, ZX_GET_CONTENT(ses->nameid), "N", "K", "VALID", logpath->s, 0); return 1; }