Branch data Line data Source code
1 : : /* zxiddi.c - Discovery Server
2 : : * Copyright (c) 2010 Sampo Kellomaki (sampo@iki.fi), All Rights Reserved.
3 : : * Copyright (c) 2009 Symlabs (symlabs@symlabs.com), All Rights Reserved.
4 : : * Author: Sampo Kellomaki (sampo@iki.fi)
5 : : * This is confidential unpublished proprietary source code of the author.
6 : : * NO WARRANTY, not even implied warranties. Contains trade secrets.
7 : : * Distribution prohibited unless authorized in writing.
8 : : * Licensed under Apache License 2.0, see file COPYING.
9 : : * $Id: zxiddi.c,v 1.2 2009-11-24 23:53:40 sampo Exp $
10 : : *
11 : : * 15.11.2009, created --Sampo
12 : : *
13 : : * See also zxidepr.c for discovery client code.
14 : : *
15 : : * zxcot -e http://idp.tas3.pt:8081/zxididp?o=S 'Discovery Svc' \
16 : : * http://idp.tas3.pt:8081/zxididp?o=B urn:liberty:disco:2006-08 \
17 : : * | zxcot -bs /var/zxid/idpdimd
18 : : */
19 : :
20 : : #include "platform.h" /* for dirent.h */
21 : : #include "errmac.h"
22 : : #include "zxid.h"
23 : : #include "zxidpriv.h"
24 : : #include "zxidutil.h"
25 : : #include "zxidconf.h"
26 : : #include "saml2.h"
27 : : #include "wsf.h"
28 : : #include "c/zx-const.h"
29 : : #include "c/zx-ns.h"
30 : : #include "c/zx-data.h"
31 : :
32 : : /*() Recover end user's identity: uid at IdP. This is actually done via "self federation"
33 : : * that was created when token for accessing discovery was issued.
34 : : * Returns 1 on success, 0 on failure. */
35 : :
36 : : /* Called by: zxid_di_query, zxid_imreq, zxid_ps_addent_invite, zxid_ps_resolv_id, zxid_ssos_anreq */
37 : : int zxid_idp_map_nid2uid(zxid_conf* cf, int len, char* uid, zxid_nid* nameid, struct zx_lu_Status_s** stp)
38 : 18 : {
39 : : struct zx_str* affil;
40 : : char sp_name_buf[1024];
41 [ - + ]: 18 : if (!nameid) {
42 : 0 : ERR("Missing nameid %d",0);
43 : 0 : return 0;
44 : : }
45 : :
46 [ + - ]: 18 : affil = nameid->SPNameQualifier ? &nameid->SPNameQualifier->g : zxid_my_ent_id(cf);
47 : 18 : zxid_nice_sha1(cf, sp_name_buf, sizeof(sp_name_buf), affil, affil, 7);
48 [ + - + - : 18 : len = read_all(len-1, uid, "idp_map_nid2uid", 1, "%s" ZXID_NID_DIR "%s/%.*s", cf->path, sp_name_buf, ZX_GET_CONTENT_LEN(nameid), ZX_GET_CONTENT_S(nameid));
+ - + - +
- + - ]
49 [ - + ]: 18 : if (!len) {
50 [ # # # # : 0 : ERR("Can not find reverse mapping for SP,SHA1(%s) nid(%.*s)", sp_name_buf, ZX_GET_CONTENT_LEN(nameid), ZX_GET_CONTENT_S(nameid));
# # # # #
# # # ]
51 [ # # ]: 0 : if (stp)
52 : 0 : *stp = zxid_mk_lu_Status(cf, 0, "Fail", 0, 0, 0);
53 : 0 : return 0;
54 : : }
55 : 18 : return 1;
56 : : }
57 : :
58 : : /*() Server side Discovery Service Query processing. See also zxid_gen_bootstraps() */
59 : :
60 : : /* Called by: zxid_sp_soap_dispatch */
61 : : struct zx_di_QueryResponse_s* zxid_di_query(zxid_conf* cf,zxid_ses* ses,struct zx_di_Query_s* req)
62 : 17 : {
63 : : struct zx_di_RequestedService_s* rs;
64 : 17 : struct zx_di_QueryResponse_s* resp = zx_NEW_di_QueryResponse(cf->ctx,0);
65 : : struct zx_root_s* r;
66 : 17 : int len, epr_len, match, n_discovered = 0;
67 : : char logop[8];
68 : : char uid[ZXID_MAX_USER];
69 : : char mdpath[ZXID_MAX_BUF];
70 : : char path[ZXID_MAX_BUF];
71 : : char* epr_buf;
72 : : DIR* dir;
73 : : struct dirent* de;
74 : : struct zx_elem_s* el;
75 : 17 : struct zx_a_Metadata_s* md = 0;
76 : : struct zx_str* ss;
77 : : struct zx_str* tt;
78 : 17 : struct zx_str* addr = 0;
79 : 17 : zxid_epr* epr = 0;
80 : 17 : D_INDENT("di_query: ");
81 : 17 : ses->uid = uid;
82 : :
83 [ - + ]: 17 : if (!zxid_idp_map_nid2uid(cf, sizeof(uid), uid, ses->tgtnameid, &resp->Status)) {
84 : 0 : D_DEDENT("di_query: ");
85 : 0 : return resp;
86 : : }
87 : 17 : name_from_path(mdpath, sizeof(mdpath), "%sdimd", cf->path);
88 : :
89 : : /* Work through all requests */
90 : :
91 : 17 : for (rs = req->RequestedService;
92 [ + + + - ]: 51 : rs && rs->gg.g.tok == zx_di_RequestedService_ELEM;
93 : 17 : rs = (struct zx_di_RequestedService_s*)ZX_NEXT(rs)) {
94 : :
95 : : /* Look for all entities providing service */
96 : :
97 [ + - + - : 17 : if (ZX_SIMPLE_ELEM_CHK(rs->ServiceType)) {
+ - + - +
- + - ]
98 : : /* *** proper handling of discovering simultaneously multiple service types? */
99 : : } else {
100 [ # # # # ]: 0 : D("%d: No specific service type given. Looking for all. %p", n_discovered, rs->ServiceType);
101 : 0 : len = 0;
102 : 0 : path[0] = 0;
103 : : }
104 : :
105 [ + - - + ]: 17 : D("%d: Looking for service metadata in dir(%s)", n_discovered, mdpath);
106 : 17 : dir = opendir(mdpath);
107 [ - + ]: 17 : if (!dir) {
108 : 0 : perror("opendir to find service metadata");
109 : 0 : ERR("Opening service metadata directory failed path(%s)", mdpath);
110 : 0 : resp->Status = zxid_mk_lu_Status(cf, &resp->gg, "Fail", 0, 0, 0);
111 : 0 : D_DEDENT("di_query: ");
112 : 0 : return resp;
113 : : }
114 : :
115 : : /* Work through all available providers, filtering out insuitable ones. */
116 : :
117 [ + + ]: 323 : while (de = readdir(dir)) {
118 [ + - - + ]: 289 : D("%d: Considering file(%s)", n_discovered, de->d_name);
119 : :
120 [ + - ]: 289 : if (de->d_name[strlen(de->d_name)-1] == '~') /* Ignore backups from hand edited EPRs. */
121 : 0 : continue;
122 : :
123 : : /* Filter file name by service type */
124 : :
125 : 289 : for (el = rs->ServiceType;
126 [ + - + + ]: 594 : el && el->g.tok == zx_di_ServiceType_ELEM;
127 : 16 : el = (struct zx_elem_s*)el->g.n) {
128 [ + - + - : 289 : ss = ZX_GET_CONTENT(el);
+ - ]
129 [ + - + - ]: 289 : if (!ss || !ss->len)
130 : : continue;
131 : 289 : len = MIN(ss->len, sizeof(path)-1);
132 : 289 : memcpy(path, ss->s, len);
133 : 289 : path[len] = 0;
134 : 289 : zxid_fold_svc(path, len);
135 [ + + - + ]: 289 : if (memcmp(de->d_name, path, len) || de->d_name[len] != ',') {
136 [ + - - + ]: 273 : D("%d: rejected due to prefix(%s) file(%s)", n_discovered, path, de->d_name);
137 : 273 : goto next_file;
138 : : }
139 : : }
140 : :
141 : : /* Probable enough, read and parse EPR so we can continue examination. */
142 : :
143 : 16 : epr_buf = read_all_alloc(cf->ctx, "find_svcmd", 1, &epr_len, "%s/%s", mdpath, de->d_name);
144 [ - + ]: 16 : if (!epr_buf)
145 : 0 : continue;
146 : :
147 : 16 : r = zx_dec_zx_root(cf->ctx, epr_len, epr_buf, "diq epr");
148 [ - + ]: 16 : if (!r) {
149 : 0 : ERR("Failed to XML parse epr_buf(%.*s) file(%s)", epr_len, epr_buf, de->d_name);
150 : 0 : ZX_FREE(cf->ctx, epr_buf);
151 : 0 : continue;
152 : : }
153 : : /* *** add ID-WSF 1.1 handling */
154 : 16 : epr = r->EndpointReference;
155 : 16 : ZX_FREE(cf->ctx, r);
156 [ + - - + ]: 16 : if (!epr || !epr->Metadata) {
157 : 0 : ERR("No EPR or missing <Metadata>. epr_buf(%.*s) file(%s)", epr_len, epr_buf, de->d_name);
158 : 0 : ZX_FREE(cf->ctx, epr_buf);
159 : 0 : continue;
160 : : }
161 [ + - + - : 16 : if (!ZX_SIMPLE_ELEM_CHK(epr->Address)) {
+ - + - +
- - + ]
162 : 0 : ERR("EPR missing <Address>. epr_buf(%.*s) file(%s)", epr_len, epr_buf, de->d_name);
163 : 0 : ZX_FREE(cf->ctx, epr_buf);
164 : 0 : continue;
165 : : }
166 [ + - + - : 16 : addr = ZX_GET_CONTENT(epr->Address);
+ - ]
167 : 16 : md = epr->Metadata;
168 : :
169 : : /* Filter by service type */
170 : :
171 : 16 : match = 1;
172 : 16 : for (el = rs->ServiceType;
173 [ + - + - ]: 32 : el && el->g.tok == zx_di_ServiceType_ELEM;
174 : 0 : el = (struct zx_elem_s*)el->g.n) {
175 [ + - + - : 16 : ss = ZX_GET_CONTENT(el);
+ - ]
176 [ + - + - ]: 16 : if (!ss || !ss->len)
177 : : continue;
178 : 16 : match = 0;
179 [ + - + - : 16 : tt = ZX_GET_CONTENT(md->ServiceType);
+ - ]
180 [ + - - + ]: 16 : if (!tt || !tt->len) {
181 : 0 : INFO("EPR missing ServiceType. Rejected. epr_buf(%.*s) file(%s)", epr_len, epr_buf, de->d_name);
182 : 0 : ZX_FREE(cf->ctx, epr_buf);
183 : 0 : goto next_file;
184 : : }
185 [ + - - + ]: 16 : if (ss->len != tt->len || memcmp(ss->s, tt->s, ss->len)) {
186 [ # # # # ]: 0 : D("%d: Internal svctype(%.*s) does not match desired(%.*s)", n_discovered, tt->len, tt->s, ss->len, ss->s);
187 : 0 : continue;
188 : : }
189 [ + - - + ]: 16 : D("%d: ServiceType matches. file(%s)", n_discovered, de->d_name);
190 : 16 : match = 1;
191 : 16 : break;
192 : : }
193 [ - + ]: 16 : if (!match) {
194 [ # # # # ]: 0 : D("%d: Rejected due to ServiceType. file(%s)", n_discovered, de->d_name);
195 : 0 : ZX_FREE(cf->ctx, epr_buf);
196 : 0 : goto next_file;
197 : : }
198 : :
199 : : /* Filter by provider id */
200 : :
201 : 16 : for (el = rs->ProviderID;
202 [ + + + - ]: 32 : el && el->g.tok == zx_di_ProviderID_ELEM;
203 : 0 : el = (struct zx_elem_s*)el->g.n) {
204 [ + - + - : 1 : ss = ZX_GET_CONTENT(el);
+ - ]
205 [ + - + - ]: 1 : if (!ss || !ss->len)
206 : : continue;
207 : 1 : match = 0;
208 [ + - + - : 1 : tt = ZX_GET_CONTENT(md->ProviderID);
+ - ]
209 [ + - - + ]: 1 : if (!tt || !tt->len) {
210 : 0 : INFO("EPR missing ProviderID. epr_buf(%.*s) file(%s)", epr_len, epr_buf, de->d_name);
211 : 0 : break;
212 : : }
213 [ + - - + ]: 1 : if (ss->len != tt->len || memcmp(ss->s, tt->s, ss->len)) {
214 [ # # # # ]: 0 : D("%d: ProviderID(%.*s) does not match desired(%.*s)", n_discovered, tt->len, tt->s, ss->len, ss->s);
215 : 0 : continue;
216 : : }
217 [ + - - + ]: 1 : D("%d: ProviderID matches. file(%s)", n_discovered, de->d_name);
218 : 1 : match = 1;
219 : 1 : break;
220 : : }
221 : : #if 1
222 : : /* TAS3 extension: allow matching by the Address (URL) as well */
223 [ - + ]: 16 : if (!match) {
224 : 0 : for (el = rs->ProviderID;
225 [ # # # # ]: 0 : el && el->g.tok == zx_di_ProviderID_ELEM;
226 : 0 : el = (struct zx_elem_s*)el->g.n) {
227 [ # # # # : 0 : ss = ZX_GET_CONTENT(el);
# # ]
228 [ # # # # ]: 0 : if (!ss || !ss->len)
229 : : continue;
230 : 0 : match = 0;
231 [ # # # # ]: 0 : if (ss->len != addr->len || memcmp(ss->s, addr->s, ss->len)) {
232 [ # # # # ]: 0 : D("%d: Address(%.*s) does not match desired(%.*s)", n_discovered, addr->len, addr->s, ss->len, ss->s);
233 : 0 : continue;
234 : : }
235 [ # # # # ]: 0 : D("%d: Address matches. file(%s)", n_discovered, de->d_name);
236 : 0 : match = 1;
237 : 0 : break;
238 : : }
239 : : }
240 : : #endif
241 [ - + ]: 16 : if (!match) {
242 [ # # # # ]: 0 : D("%d: Rejected due to ProviderID. file(%s)", n_discovered, de->d_name);
243 : 0 : ZX_FREE(cf->ctx, epr_buf);
244 : 0 : goto next_file;
245 : : }
246 : :
247 : : /* *** Check Options */
248 : :
249 : : /* *** Check Framework */
250 : :
251 : : /* *** Check Action */
252 : :
253 : : #if 0
254 : : /* Call Trust and Privacy Negotiation (TrustBuilder), Andreas. */
255 : : systemf("./tpn-client.sh %s %s %s", idpnid, "urn:idhrxml:cv:update", host);
256 : : #endif
257 : 16 : ++n_discovered;
258 [ + - - + ]: 16 : D("%d: DISCOVERED EPR url(%.*s)", n_discovered, addr->len, addr->s);
259 [ - + ]: 16 : if (!zxid_add_fed_tok2epr(cf, ses, epr, 1, logop)) {
260 : 0 : ZX_FREE(cf->ctx, epr_buf);
261 : 0 : goto next_file;
262 : : }
263 : :
264 : 16 : zx_add_kid(&resp->gg, &epr->gg);
265 [ + - ]: 16 : if (!resp->EndpointReference)
266 : 16 : resp->EndpointReference = epr;
267 : :
268 : 16 : zxlogwsp(cf, ses, "K", logop, uid, 0);
269 : :
270 [ - + # # : 16 : if (rs->resultsType && rs->resultsType->g.s
# # # # ]
271 : : && (!memcmp(rs->resultsType->g.s, "only-one", rs->resultsType->g.len)
272 : : || !memcmp(rs->resultsType->g.s, "best", rs->resultsType->g.len))) {
273 [ # # # # ]: 0 : D("only-one or best requested (%.*s)", rs->resultsType->g.len, rs->resultsType->g.s);
274 : 0 : break;
275 : : }
276 : :
277 : 306 : next_file:
278 : : continue;
279 : : }
280 : :
281 : 17 : closedir(dir);
282 : : }
283 [ + - + - : 17 : ss = ZX_GET_CONTENT(req->RequestedService->ServiceType);
+ - ]
284 [ + - + - : 17 : D("TOTAL discovered %d svctype(%.*s)", n_discovered, ss?ss->len:0, ss?ss->s:"");
+ - - + ]
285 [ + - + - ]: 17 : zxlogwsp(cf, ses, "K", "DIOK", 0, "%.*s n=%d", ss?ss->len:1, ss?ss->s:"-", n_discovered);
286 : 17 : resp->Status = zxid_mk_lu_Status(cf, &resp->gg, "OK", 0, 0, 0); /* last is first */
287 : 17 : D_DEDENT("di_query: ");
288 : 17 : return resp;
289 : : }
290 : :
291 : : /* EOF -- zxiddi.c */
|