/* Called by: smtp_decode_req */ static int smtp_ehlo(struct hi_thr* hit, struct hi_io* io, struct hi_pdu* req) { char* p = req->m; char* lim = req->ap; if (lim - p < 7) { /* too little, need more for "EHLO s\n" */ req->need = 7 - (lim - p); return 0; } p[0] = toupper(p[0]); p[1] = toupper(p[1]); p[2] = toupper(p[2]); p[3] = toupper(p[3]); if (memcmp(p, "EHLO ", 5) && memcmp(req->m, "HELO ", 5)) goto bad; p += 5; for (; p < lim && !ONE_OF_2(*p, '\r', '\n'); ++p) ; CRLF_CHECK(p, lim, req); hi_sendf(hit, io, 0, 0, "250-%s\r\n250-PIPELINING\r\n250 8-BIT MIME\r\n", SMTP_EHLO_CLI); io->pair = hi_prototab[HIPROTO_SIS].specs->conns; hi_prototab[HIPROTO_SIS].specs->conns->pair = io; /* But there could be multiple? */ #if 0 /* We do this nowdays during setup */ sis_send_bind(hit, io->pair, SAP_ID_HMTP, 0, 0x0200); /* 0x0200 == nonarq, no repeats */ #endif io->ad.smtp.state = SMTP_MAIN; req->need = (p - req->m) + 5; req->ad.smtp.skip_ehlo = req->scan = p; D("EHLO ok req(%p)", req); return 0; bad: ERR("Bad SMTP PDU. fd(%x)", io->fd); return HI_CONN_CLOSE; }
/* Called by: zxcot_main */ static int zxid_lscot(zxid_conf* cf, int col_swap, const char* dcot) { int got, ret; char* p; DIR* dir; struct dirent* de; dir = opendir(dcot); if (!dir) { perror("opendir for /var/zxid/cot (or other if configured) for loading cot cache"); D("failed path(%s)", dcot); got = strlen(dcot); p = ZX_ALLOC(cf->ctx, got+1); memcpy(p, dcot, got-1); p[got-1] = 0; /* chop off / */ got = zxid_lscot_line(cf, col_swap, p, ""); ZX_FREE(cf->ctx, p); return got; } while (de = readdir(dir)) { if (de->d_name[0] == '.' || de->d_name[strlen(de->d_name)-1] == '~') continue; ret = zxid_lscot_line(cf, col_swap, dcot, de->d_name); if (!ONE_OF_2(ret, 0, 2)) return ret; } return 0; }
/* Called by: smtp_decode_resp */ static int smtp_resp_wait_221_goodbye(struct hi_thr* hit, struct hi_io* io, struct hi_pdu* resp) { char* p = resp->scan; char* lim = resp->ap; int n = lim - p; if (n < 6) { /* 250 m\n or 250-m\n */ resp->need = (6 - n) + (p - resp->m); /* what we have plus what we need */ return 0; } if (!THREE_IN_ROW(p, '2', '2', '1')) /* 221 goodbye */ goto bad; switch (n = p[3]) { case ' ': case '-': for (p+=4; p < lim && !ONE_OF_2(*p, '\r', '\n'); ++p) ; CRLF_CHECK(p, lim, resp); resp->scan = p; break; default: goto bad; } if (n == ' ') { D("221 bye seen resp(%p)", resp); io->ad.smtp.state = SMTP_INIT; return HI_CONN_CLOSE; } resp->need = 6 + p - resp->m; /* Prime the pump for next response */ return 0; bad: D("SMTP server sent bad response(%.*s)", n, p); return HI_CONN_CLOSE; }
/* Called by: hi_shuffle */ struct hi_qel* hi_todo_consume(struct hi_thr* hit) { struct hi_io* io; struct hi_qel* qe; LOCK(hit->shf->todo_mut, "todo_cons"); D("LOCK todo_mut.thr=%lx (cond_wait)", (long)hit->shf->todo_mut.thr); deque_again: while (!hit->shf->todo_consume && hit->shf->poll_tok.proto == HIPROTO_POLL_OFF) /* Empty? */ ERRMAC_COND_WAIT(&hit->shf->todo_cond, hit->shf->todo_mut, "todo-cons"); /* Block until work */ D("Out of cond_wait todo_mut.thr=%lx", (long)hit->shf->todo_mut.thr); if (!hit->shf->todo_consume) { ASSERT(hit->shf->poll_tok.proto); force_poll: hit->shf->poll_tok.proto = HIPROTO_POLL_OFF; D("UNLK cons-poll todo_mut.thr=%lx", (long)hit->shf->todo_mut.thr); UNLOCK(hit->shf->todo_mut, "todo_cons-poll"); return &hit->shf->poll_tok; } qe = hi_todo_consume_queue_inlock(hit->shf); if (!ONE_OF_2(qe->kind, HI_TCP_S, HI_TCP_C)) { D("cons qe_%p kind(%s) intodo=%x todo_mut.thr=%lx", qe, QEL_KIND(qe->kind), qe->intodo, (long)hit->shf->todo_mut.thr); UNLOCK(hit->shf->todo_mut, "todo_cons"); return qe; } io = (struct hi_io*)qe; LOCK(io->qel.mut, "n_thr-inc"); ASSERT(!hit->cur_io); if (io->n_thr == HI_IO_N_THR_END_POLL) { /* Special close end game, see hi_close() */ io->n_thr = HI_IO_N_THR_END_GAME; hi_todo_produce_queue_inlock(hit->shf, qe); /* Put it back: try again later */ UNLOCK(io->qel.mut, "n_thr-poll"); goto force_poll; } if (io->n_thr == HI_IO_N_THR_END_GAME) { hit->cur_io = io; hit->cur_n_close = io->n_close; UNLOCK(io->qel.mut, "n_thr-end"); hi_close(hit, io, "cons-end"); goto deque_again; } if (io->fd & 0x80000000) { D("cons-ign-closed: LK&UNLK io(%x)->qel.thr=%lx n_thr=%d r/w=%d/%d ev=%d intodo=%x", io->fd, (long)io->qel.mut.thr, io->n_thr, io->reading, io->writing, io->events, io->qel.intodo); /* Let it be consumed so that r/w will fail and hi_close() is called to clean up. */ } ++io->n_thr; /* Increase two counts: once for write, and once for read, decrease for intodo ending. Net is +1. */ hit->cur_io = io; hit->cur_n_close = io->n_close; D("cons: LK&UNLK io(%x)->qel.thr=%lx n_thr=%d r/w=%d/%d ev=%x intodo=%x", io->fd, (long)io->qel.mut.thr, io->n_thr, io->reading, io->writing, io->events, io->qel.intodo); UNLOCK(io->qel.mut, "n_thr-inc"); D("UNLK todo_mut.thr=%lx", (long)hit->shf->todo_mut.thr); UNLOCK(hit->shf->todo_mut, "todo_cons-tcp"); return qe; }
/* Called by: smtp_decode_req */ static int smtp_data(struct hi_thr* hit, struct hi_io* io, struct hi_pdu* req) { char* p = req->scan; char* lim = req->ap; switch (io->ad.smtp.state) { case SMTP_MORE0: break; case SMTP_MORE1: goto look_for_dot; case SMTP_MORE2: default: NEVERNEVER("impossible SMTP state %d", io->ad.smtp.state); } while (lim - p >= 3) { /* \n.\n */ for (; *p != '\n' && lim - p >= 3; ++p) ; /* \n.\n */ if (lim - p < 3) break; ++p; look_for_dot: if (p[0] == '.' && ONE_OF_2(p[1], '\r', '\n')) { ++p; if (*p == '\r') { ++p; if (p == lim) break; if (*p != '\n') continue; /* this happens a lot */ } ++p; /* *p was '\n' */ /* End of message, hurrah! */ D("End-of-message seen req(%p)", req); hmtp_send(hit, io->pair, p - req->m, req->m, 6, "QUIT\r\n"); #if 1 io->ad.smtp.state = SMTP_WAIT; req->need = 0; /* Hold it until we get response from SIS layer. */ #else hi_sendf(hit, io, 0, 0, "250 sent\r\n"); /* *** hold this off? */ req->need = (p - req->m) + 5; /* *** not clear how second message could be sent. Perhaps we need second scan pointer? */ #endif req->scan = p; return 0; } } /* *** need to handle mail larger than U_PDU case */ req->need = 3 - (lim - p); req->scan = p-1; D("more data needed req(%p) need=%d", req, req->need); return 0; bad: ERR("Bad SMTP PDU. fd(%x)", io->fd); return HI_CONN_CLOSE; }
/* Called by: hi_accept, hi_accept_book, hi_close, hi_in_out, hi_poll x3, hi_send0, stomp_msg_deliver, zxbus_sched_new_delivery, zxbus_sched_pending_delivery */ void hi_todo_produce(struct hi_thr* hit, struct hi_qel* qe, const char* lk, int from_poll) { struct hi_io* io; LOCK(hit->shf->todo_mut, "todo_prod"); D("%s: LOCK todo_mut.thr=%lx", lk, (long)hit->shf->todo_mut.thr); if (qe->intodo == HI_INTODO_INTODO) { if (ONE_OF_2(qe->kind, HI_TCP_S, HI_TCP_C)) { io = ((struct hi_io*)qe); D("%s: prod already in todo(%x) n_thr=%d r/w=%d/%d ev=%x", lk, io->fd, io->n_thr, io->reading, io->writing, io->events); if (io->fd & 0x80000000) D("%s: prod-closed fd(%x) intodo! n_thr=%d r/w=%d/%d ev=%x intodo=%x", lk, io->fd, io->n_thr, io->reading, io->writing, io->events, io->qel.intodo); } else { D("%s: prod already in todo qe_%p kind(%s)", lk, qe, QEL_KIND(qe->kind)); } goto out; } if (!ONE_OF_2(qe->kind, HI_TCP_S, HI_TCP_C)) { D("%s: prod qe(%p) kind(%s)", lk, qe, QEL_KIND(qe->kind)); goto produce; } io = (struct hi_io*)qe; LOCK(io->qel.mut, "n_thr-inc-todo"); if (from_poll) { /* Detect already closed (or even end game) io, see hi_close(). Note that * this detection only needs to apply to produce from poll. */ if (io->n_thr == HI_IO_N_THR_END_POLL || io->fd & 0x80000000) { D("%s: prod(%x)-ign LK&UNLK n_c/t=%d/%d r/w=%d/%d ev=%x", lk, io->fd, io->n_close, io->n_thr, io->reading, io->writing, io->events); UNLOCK(io->qel.mut, "n_thr-inc-ign"); goto out; } ASSERTOPI(io->n_thr, >=, 0); ++io->n_thr; /* Should have been done already by caller, but for poll optimize lock. */ } else { if (io->n_thr != HI_IO_N_THR_END_POLL) {
/* Called by: stomp_msg_deliver, zxbus_subscribe */ struct hi_ch* zxbus_find_ch(struct hiios* shf, int len, const char* dest) { int n; struct hi_ch* ch; if (len == -1) len = strlen(dest); else if (len == -2) len = strchr(dest, '\n') - dest; for (n = shf->max_chs, ch = shf->chs; n; --n, ++ch) { if (!ch->dest) break; if (!memcmp(ch->dest, dest, len) && ONE_OF_2(dest[len],'\n','\0')) { D("found ch(%s)", ch->dest); return ch; } } D("channel(%.*s) not found", len, dest); return 0; }
/* Called by: zx_password_authn */ static int zx_pw_chk(const char* uid, const char* pw_buf, const char* passw, int fd_hint) { unsigned char pw_hash[120]; /* *** Add here support for other authentication backends */ DD("io(%x) pw_buf (%s) len=%d", fd_hint, pw_buf, strlen(pw_buf)); if (!memcmp(pw_buf, "$1$", sizeof("$1$")-1)) { /* MD5 hashed password */ zx_md5_crypt(passw, (char*)pw_buf, (char*)pw_hash); D("io(%x) pw_hash(%s)", fd_hint, pw_hash); if (strcmp((char*)pw_buf, (char*)pw_hash)) { ERR("Bad password. uid(%s)", uid); D("md5 pw(%s) .pw(%s) pw_hash(%s)", passw, pw_buf, pw_hash); return 0; } #ifdef USE_OPENSSL } else if (!memcmp(pw_buf, "$c$", sizeof("$c$")-1)) { /* DES fcrypt hashed password */ DES_fcrypt(passw, (char*)pw_buf+3, (char*)pw_hash); D("io(%x) pw_hash(%s)", fd_hint, pw_hash); if (strcmp((char*)pw_buf+3, (char*)pw_hash)) { ERR("Bad password for uid(%s)", uid); D("crypt pw(%s) .pw(%s) pw_hash(%s)", passw, pw_buf, pw_hash); return 0; } #endif } else if (ONE_OF_2(pw_buf[0], '$', '_')) { /* Unsupported hash */ ERR("Unsupported password hash. uid(%s)", uid); D("io(%x) pw(%s) .pw(%s)", fd_hint, passw, pw_buf); return 0; } else { /* Plaintext password (no hash) */ if (strcmp((char*)pw_buf, passw)) { ERR("Bad password. uid(%s)", uid); D("io(%x) pw(%s) .pw(%s)", fd_hint, passw, pw_buf); return 0; } } INFO("Login(%x) OK acnt(%s)", fd_hint, uid); return 2; }
/* Called by: smtp_decode_resp */ static int smtp_resp_wait_250_msg_sent(struct hi_thr* hit, struct hi_io* io, struct hi_pdu* resp) { char* p = resp->scan; char* lim = resp->ap; int n = lim - p; if (n < 6) { /* 250 m\n or 250-m\n */ resp->need = (6 - n) + (p - resp->m); /* what we have plus what we need */ return 0; } if (!THREE_IN_ROW(p, '2', '5', '0')) /* 250 message sent */ goto bad; switch (n = p[3]) { case ' ': case '-': for (p+=4; p < lim && !ONE_OF_2(*p, '\r', '\n'); ++p) ; CRLF_CHECK(p, lim, resp); resp->scan = p; break; default: goto bad; } if (n == ' ') { /* *** should we attempt to skip the 220 greeting? */ D("250 after data 354 seen resp(%p)", resp); hmtp_send(hit, io->pair, p-resp->m, resp->m, 13, "221 goodbye\r\n"); hi_sendf(hit, io, 0, 0, "QUIT\r\n"); /* One message per connection! */ io->ad.smtp.state = SMTP_QUIT; } resp->need = 6 + p - resp->m; /* Prime the pump for next response */ return 0; bad: D("SMTP server sent bad response(%.*s)", n, p); if (io->pair) hmtp_send(hit, io->pair, resp->need, resp->m, 0, 0); return HI_CONN_CLOSE; }
/* Called by: smtp_decode_resp */ static int smtp_resp_wait_220_greet(struct hi_thr* hit, struct hi_io* io, struct hi_pdu* resp) { char* p = resp->scan; char* lim = resp->ap; int n = lim - p; if (n < 6) { /* 220 m\n or 220-m\n */ resp->need = (6 - n) + (p - resp->m); /* what we have plus what we need */ return 0; } if (!THREE_IN_ROW(p, '2', '2', '0')) /* 220 greet */ goto bad; switch (n = p[3]) { case ' ': case '-': for (p+=4; p < lim && !ONE_OF_2(*p, '\r', '\n'); ++p) ; CRLF_CHECK(p, lim, resp); resp->scan = p; break; default: goto bad; } if (n == ' ') { D("220 greet seen resp(%p)", resp); hi_sendf(hit, io, 0, 0, "EHLO %s\r\n", SMTP_GREET_DOMAIN); io->ad.smtp.state = SMTP_RDY; } resp->need = 6 + p - resp->m; /* Prime the pump for next response */ return 0; bad: D("SMTP server sent bad response(%.*s)", n, p); if (io->pair) hmtp_send(hit, io->pair, resp->need, resp->m, 0, 0); return HI_CONN_CLOSE; }
/* Called by: smtp_decode_resp */ static int smtp_resp_wait_354_from_data(struct hi_thr* hit, struct hi_io* io, struct hi_pdu* resp) { char* p = resp->scan; char* lim = resp->ap; int next_state, n = lim - p; if (n < 6) { /* 250 m\n or 250-m\n */ resp->need = (6 - n) + (p - resp->m); /* what we have plus what we need */ return 0; } if (THREE_IN_ROW(p, '3', '5', '4')) { /* 354 enter mail */ next_state = SMTP_SENT; } else if (THREE_IN_ROW(p, '2', '5', '0')) { next_state = io->ad.smtp.state; } else goto bad; switch (n = p[3]) { case ' ': case '-': for (p+=4; p < lim && !ONE_OF_2(*p, '\r', '\n'); ++p) ; CRLF_CHECK(p, lim, resp); resp->scan = p; break; default: goto bad; } if (n == ' ' && next_state == SMTP_SENT) { if (io->ad.smtp.uni_ind_hmtp) { /* Send payload immediately */ /* io->ad.smtp.uni_ind_hmtp is the sis unidata_ind primitive contaning HMTP request */ char* payload; char* q = io->ad.smtp.uni_ind_hmtp->scan; char* qlim = io->ad.smtp.uni_ind_hmtp->ap; struct hi_pdu* pdu = hi_pdu_alloc(hit, "smtp_wait_354"); payload = q; --q; /* Take the new line from preceding DATA to avoid special case later */ /* Make sure QUIT is NOT sent (we will send one ourselves, eventually). Scan for message * terminating "\r\n.\r\n". Its also possible we will not see message terminator. That * means the message is so big it takes several SIS primitives to transmit. */ for (; q+2 < qlim; ++q) { if (q[0] == '\n' && q[1] == '.' && ONE_OF_2(q[2], '\r', '\n')) { if (q[2] == '\r' && ((q+3 >= qlim) || q[3] != '\n')) continue; q += (q[2] == '\r') ? 4 : 3; break; } } D("354 for DATA seen resp(%p), sending %d bytes", resp, (int)(q-payload)); hi_send1(hit, io, 0, 0, pdu, q-payload, payload); io->ad.smtp.state = SMTP_SENT; /* *** if hmtp / smtp message was not complete, arrange further SIS layer * I/O to be forwarded into the smtp connection. Similarily, if the * hmtp message has not arrived yet at all, it should be forwarded * as soon as it does arrive. */ } else { NEVER("smtp client io is missing is unidata_ind_hmtp? %p", io->pair); return HI_CONN_CLOSE; } } resp->need = 6 + p - resp->m; /* Prime the pump for next response */ return 0; bad: D("SMTP server sent bad response(%.*s)", n, p); if (io->pair) hmtp_send(hit, io->pair, resp->need, resp->m, 0, 0); return HI_CONN_CLOSE; badhmtp: D("Bad HMTP PDU from SIS layer %d", 0); if (io->pair) hmtp_send(hit, io->pair, 9, "500 Bad\r\n", 0, 0); return HI_CONN_CLOSE; }
/* Called by: smtp_decode_resp */ static int smtp_resp_wait_250_from_ehlo(struct hi_thr* hit, struct hi_io* io, struct hi_pdu* resp) { char* p = resp->scan; char* lim = resp->ap; int n = lim - p; if (n < 6) { /* 250 m\n or 250-m\n */ resp->need = (6 - n) + (p - resp->m); /* what we have plus what we need */ return 0; } if (!THREE_IN_ROW(p, '2', '5', '0')) goto bad; switch (n = p[3]) { case ' ': case '-': for (p+=4; p < lim && !ONE_OF_2(*p, '\r', '\n'); ++p) ; CRLF_CHECK(p, lim, resp); resp->scan = p; break; default: goto bad; } if (n == ' ') { if (io->ad.smtp.uni_ind_hmtp) { /* Send payload immediately */ /* io->ad.smtp.uni_ind_hmtp is the sis unidata_ind primitive contaning HMTP request */ char* payload; char* q = io->ad.smtp.uni_ind_hmtp->scan; char* qlim = io->ad.smtp.uni_ind_hmtp->ap; struct hi_pdu* pdu = hi_pdu_alloc(hit, "smtp_wait_250"); if (qlim-q < 25) /* *** should determine this number better */ goto badhmtp; /* Skip EHLO if any */ q[0] = toupper(q[0]); q[1] = toupper(q[1]); q[2] = toupper(q[2]); q[3] = toupper(q[3]); if (memcmp(q, "EHLO ", 5)) goto badhmtp; for (q+=5; q < qlim && !ONE_OF_2(*q, '\r', '\n'); ++q) ; if (q == qlim) goto badhmtp; if (*q == '\r') { ++q; if (q == qlim || *q != '\n') goto badhmtp; } ++q; if (q == qlim) goto badhmtp; payload = q; /* Scan till end of DATA command. We can not send the actual data before 354 response * to DATA command, for which we wait in SEND state. */ for (; q+6 < qlim; ++q) { if (q[0] == '\n' && ONE_OF_2(q[1], 'D', 'd') && ONE_OF_2(q[2], 'A', 'a') && ONE_OF_2(q[3], 'T', 't') && ONE_OF_2(q[4], 'A', 'a') && ONE_OF_2(q[5], '\r', '\n') ) { if (q[5] == '\r' && ((q+7 >= qlim) || q[6] != '\n')) continue; q += (q[5] == '\r') ? 7 : 6; break; } } D("250 for EHLO seen resp(%p)", resp); io->ad.smtp.uni_ind_hmtp->scan = q; hi_send1(hit, io, 0, 0, pdu, q-payload, payload); io->ad.smtp.state = SMTP_SEND; /* *** if hmtp / smtp message was not complete, arrange further SIS layer * I/O to be forwarded into the smtp connection. Similarily, if the * hmtp message has not arrived yet at all, it should be forwarded * as soon as it does arrive. */ } else { NEVER("smtp client io is missing is unidata_ind_hmtp? %p", io->pair); return HI_CONN_CLOSE; } } resp->need = 6 + p - resp->m; /* Prime the pump for next response */ return 0; bad: D("SMTP server sent bad response(%.*s)", n, p); if (io->pair) hmtp_send(hit, io->pair, resp->need, resp->m, 0, 0); return HI_CONN_CLOSE; badhmtp: D("Bad HMTP PDU from SIS layer %d", 0); if (io->pair) hmtp_send(hit, io->pair, 9, "500 Bad\r\n", 0, 0); return HI_CONN_CLOSE; }
/* Called by: */ int zxumacall_main(int argc, char** argv, char** env) { int siz, got, n; char* p; struct zx_str* ss; zxid_ses* ses; zxid_entity* idp_meta; zxid_epr* epr; strncpy(errmac_instance, CC_CYNY("\tzxuma"), sizeof(errmac_instance)); cf = zxid_new_conf_to_cf(0); opt(&argc, &argv, &env); if (dynclireg) { zxumacall_dynclireg_client(cf); return 0; } if (rsrc_name) { if (!client_secret) zxumacall_dynclireg_client(cf); zxumacall_rsrcreg_client(cf); return 0; } if (sid) { D("Existing session sesid(%s)", sid); ses = zxid_fetch_ses(cf, sid); if (!ses) { ERR("Session not found or error in session sesid(%s)", sid); return 1; } } else { D("Obtain session from authentication service(%s)", idp); idp_meta = zxid_get_ent(cf, idp); if (!idp_meta) { ERR("IdP metadata not found and could not be fetched. idp(%s)", idp); return 1; } for (p = user; !ONE_OF_2(*p, ':', 0); ++p) ; if (*p) *p++ = 0; ses = zxid_as_call(cf, idp_meta, user, p); if (!ses) { ERR("Login using Authentication Service failed idp(%s)", idp); return 1; } INFO("Logged in. NameID(%s) Session in %s" ZXID_SES_DIR "%s", ses->nid, cf->cpath, ses->sid); } if (listses) return zxid_print_session(cf, ses); if (im_to) { D("ID-WSF Map to identity at eid(%s)", im_to); zxid_map_identity_token(cf, ses, im_to, 0); //printf("%.*s\n", ZX_GET_CONTENT_LEN(nameid), ZX_GET_CONTENT_S(nameid)); return 0; } if (nidmap_to) { D("SAML Map to identity at eid(%s)", nidmap_to); zxid_nidmap_identity_token(cf, ses, nidmap_to, 0); //printf("%.*s\n", ZX_GET_CONTENT_LEN(nameid), ZX_GET_CONTENT_S(nameid)); return 0; } if (di_only) { D("Discover only. svctype(%s), dindex=%d", STRNULLCHK(svc), din); epr = zxid_get_epr(cf, ses, svc, url, di, 0 /*action*/, din); if (!epr) { ERR("Discovery failed to find any epr of service type(%s)", STRNULLCHK(svc)); return 3; } for (din = 1; ;++din) { epr = zxid_get_epr(cf, ses, svc, url, di, 0 /*action*/, din); if (!epr) break; printf("%d. Found epr for service type(%s)\n", din, STRNULLCHK(svc)); ss = zxid_get_epr_desc(cf, epr); printf(" Description: %.*s\n", ss?ss->len:0, ss?ss->s:""); ss = zxid_get_epr_address(cf, epr); printf(" EPURL: %.*s\n", ss?ss->len:0, ss?ss->s:""); ss = zxid_get_epr_entid(cf, epr); printf(" EntityID: %.*s\n", ss?ss->len:0, ss?ss->s:""); } return 0; } if (svc) { D("Call service svctype(%s)", svc); if (!bdy) { if (verbose) fprintf(stderr, "Reading SOAP request body from stdin...\n"); siz = 4096; p = bdy = ZX_ALLOC(cf->ctx, siz); while (1) { n = read_all_fd(fdstdin, p, siz+bdy-p-1, &got); if (n == -1) { perror("reading SOAP req from stdin"); break; } p += got; if (got < siz+bdy-p-1) break; siz += 60*1024; REALLOCN(bdy, siz); } *p = 0; } if (dryrun) { if (verbose) fprintf(stderr, "Dryrun. Call aborted.\n"); return 0; } if (verbose) fprintf(stderr, "Calling...\n"); ss = zxid_call(cf, ses, svc, url, di, az, bdy); if (!ss || !ss->s) { ERR("Call failed %p", ss); return 2; } if (verbose) fprintf(stderr, "Done. Call returned %d bytes.\n", ss->len); if (out_fmt) { p = zxid_extract_body(cf, ss->s); printf("%s", p); } else printf("%.*s", ss->len, ss->s); } else if (az) { D("Call Az(%s)", az); if (dryrun) { if (verbose) fprintf(stderr, "Dryrun. zxid_az() aborted.\n"); return 0; } if (zxid_az_cf_ses(cf, az, ses)) { if (verbose) fprintf(stderr, "Permit.\n"); return 0; } else { if (verbose) fprintf(stderr, "Deny.\n"); return 1; } } else { D("Neither service type (-t) nor -az supplied. Performed only authentication. %d",0); if (verbose) fprintf(stderr, "Authentication only.\n"); } return 0; }