1 /* zxidpool.c - Attribute handling
2 * Copyright (c) 2010-2011 Sampo Kellomaki (sampo@iki.fi), All Rights Reserved.
3 * Copyright (c) 2007-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: zxidpool.c,v 1.7 2009-11-24 23:53:40 sampo Exp $
10 *
11 * 4.9.2009, forked from zxidsimp.c --Sampo
12 * 1.2.2010, added ses_to methods --Sampo
13 * 21.5.2010, added local attribute authority and local EPRs feature --Sampo
14 */
15
16 #include "platform.h"
17
18 #include <memory.h>
19 #include <string.h>
20 #include <errno.h>
21
22 #include "errmac.h"
23 #include "zx.h"
24 #include "zxid.h"
25 #include "zxidpriv.h"
26 #include "zxidutil.h"
27 #include "zxidconf.h"
28 #include "c/zx-sa-data.h"
29
30 /*(i) Convert attributes from (session) pool to LDIF entry, applying OUTMAP.
31 * This is used by zxid_simple() SSO successful code to generate return
32 * value, but can also be used later to regenerate the LDIF
33 * given the pool. See zxid_ses_to_pool() for how to create the pool.
34 *
35 * N.B. More complete documentation is available in <<link: zxid-simple.pd>> (*** fixme) */
36
37 /* Called by: */
zxid_pool_to_ldif(zxid_conf * cf,struct zxid_attr * pool)38 static struct zx_str* zxid_pool_to_ldif(zxid_conf* cf, struct zxid_attr* pool)
39 {
40 char* p;
41 char* name;
42 char* idpnid = 0;
43 char* affid = 0;
44 int len = 0, name_len;
45 struct zxid_map* map;
46 struct zxid_attr* at;
47 struct zxid_attr* av;
48 struct zx_str* ss;
49
50 /* Length computation pass */
51
52 for (at = pool; at; at = at->n) {
53 map = zxid_find_map(cf->outmap, at->name);
54 if (map) {
55 if (map->rule == ZXID_MAP_RULE_DEL) {
56 D("attribute(%s) filtered out by del rule in OUTMAP", at->name);
57 continue;
58 }
59 at->map_val = zxid_map_val(cf, 0, 0, map, at->name, at->val);
60 if (map->dst && *map->dst && map->src && map->src[0] != '*') {
61 name_len = strlen(map->dst);
62 } else {
63 name_len = strlen(at->name);
64 }
65 len += name_len + sizeof(": \n")-1 + at->map_val->len;
66 DD("len1=%d", len);
67
68 for (av = at->nv; av; av = av->n) {
69 av->map_val = zxid_map_val(cf, 0, 0, map, at->name, av->val);
70 len += name_len + sizeof(": \n")-1 + av->map_val->len;
71 DD("len2=%d", len);
72 }
73 } else {
74 name_len = strlen(at->name);
75 len += name_len + sizeof(": \n")-1 + (at->val?strlen(at->val):0);
76 DD("len3=%d name_len=%d name(%s)", len, name_len, at->name);
77 for (av = at->nv; av; av = av->n) {
78 len += name_len + sizeof(": \n")-1 + (av->val?strlen(av->val):0);
79 DD("len4=%d", len);
80 }
81 }
82
83 if (!strcmp(at->name, "idpnid")) idpnid = at->val;
84 else if (!strcmp(at->name, "affid")) affid = at->val;
85 }
86 len += sizeof("dn: idpnid=,affid=\n")-1 + (idpnid?strlen(idpnid):0) + (affid?strlen(affid):0);
87 DD("lenFin=%d", p-ss->s);
88
89 /* Attribute rendering pass */
90
91 ss = zx_new_len_str(cf->ctx, len);
92 p = ss->s;
93
94 memcpy(p, "dn: idpnid=", sizeof("dn: idpnid=")-1);
95 p += sizeof("dn: idpnid=")-1;
96 if (idpnid) {
97 strcpy(p, idpnid);
98 p += strlen(idpnid);
99 }
100 memcpy(p, ",affid=", sizeof(",affid=")-1);
101 p += sizeof(",affid=")-1;
102 if (affid) {
103 strcpy(p, affid);
104 p += strlen(affid);
105 }
106 *p++ = '\n';
107
108 DD("len 0=%d", ((int)(p-ss->s)));
109
110 for (at = pool; at; at = at->n) {
111 map = zxid_find_map(cf->outmap, at->name);
112 if (map) {
113 if (map->rule == ZXID_MAP_RULE_DEL)
114 continue;
115 if (map->dst && *map->dst && map->src && map->src[0] != '*') {
116 name = map->dst;
117 } else {
118 name = at->name;
119 }
120
121 name_len = strlen(name);
122 strcpy(p, name);
123 p += name_len;
124 *p++ = ':';
125 *p++ = ' ';
126 memcpy(p, at->map_val->s, at->map_val->len);
127 p += at->map_val->len;
128 *p++ = '\n';
129
130 DD("len 1=%d", ((int)(p-ss->s)));
131
132 for (av = at->nv; av; av = av->n) {
133 strcpy(p, name);
134 p += name_len;
135 *p++ = ':';
136 *p++ = ' ';
137 memcpy(p, av->map_val->s, av->map_val->len);
138 p += av->map_val->len;
139 *p++ = '\n';
140
141 DD("len 2=%d", (int)(p-ss->s));
142 }
143
144
145 } else {
146 name_len = strlen(at->name);
147 strcpy(p, at->name);
148 p += name_len;
149 *p++ = ':';
150 *p++ = ' ';
151 if (at->val) {
152 strcpy(p, at->val);
153 p += strlen(at->val);
154 }
155 *p++ = '\n';
156
157 DD("len 3=%d name_len=%d name(%s)", (int)(p-ss->s), name_len, at->name);
158
159 for (av = at->nv; av; av = av->n) {
160 strcpy(p, at->name);
161 p += name_len;
162 *p++ = ':';
163 *p++ = ' ';
164 if (at->val) {
165 strcpy(p, av->val);
166 p += strlen(av->val);
167 }
168 *p++ = '\n';
169
170 D("len 4=%d", (int)(p-ss->s));
171 }
172
173 }
174 }
175 DD("len Fin=%d", (int)(p-ss->s));
176
177 ASSERTOPP(p, ==, ss->s+len);
178 return ss;
179 }
180
181 /*(-) Length computation of JSON string */
182
183 /* Called by: zxid_pool_to_json x9 */
zxid_json_strlen(char * js)184 static int zxid_json_strlen(char* js)
185 {
186 int res = 0;
187 for (; *js; ++js, ++res) {
188 int c = *(unsigned char*)js;
189 if (c < ' ') {
190 if ((c == '\n') || (c == '\r') || (c == '\t') ||
191 (c == '\b') || (c == '\f')) {
192 /* \X */
193 res++;
194 } else {
195 /* \uXXXX */
196 res += 5;
197 }
198 } else if ((c == '\'') || (c == '\"') || (c == '\\')) {
199 /* \X */
200 res++;
201 } else if ((c == 0xe2) && (((unsigned char*)js)[1] == 0x80) &&
202 ((((unsigned char*)js)[2] & 0xfe) == 0xa8)) {
203 /* Some java-script based JSON decoders don't like
204 * unescaped \u2028 and \u2029. */
205 /* \uXXXX */
206 res += 5;
207 js += 2;
208 }
209 }
210 return res;
211 }
212
213 /*(-) Copy JSON string */
214
215 /* Called by: zxid_pool_to_json x8 */
zxid_json_strcpy(char * dest,char * js)216 static char* zxid_json_strcpy(char* dest, char* js)
217 {
218 for (; *js; ++js) {
219 int c = *(unsigned char*)js;
220 if (c < ' ') {
221 /* Control character. */
222 *dest++ = '\\';
223 if (c == '\n') c = 'n';
224 else if (c == '\r') c = 'r';
225 else if (c == '\t') c = 't';
226 else if (c == '\b') c = 'b';
227 else if (c == '\f') c = 'f';
228 else {
229 /* \uXXXX */
230 sprintf(dest, "u%04x", c);
231 dest += 5;
232 continue;
233 }
234 } else if ((c == '\'') || (c == '\"') || (c == '\\')) {
235 /* \X */
236 *dest++ = '\\';
237 } else if ((c == 0xe2) && (((unsigned char*)js)[1] == 0x80) &&
238 ((((unsigned char*)js)[2] & 0xfe) == 0xa8)) {
239 /* Some java-script based JSON decoders don't like
240 * unescaped \u2028 and \u2029. */
241 /* \uXXXX */
242 sprintf(dest, "\\u%04x", 0x2028 | (js[2] & 1));
243 js += 2;
244 dest += 6;
245 continue;
246 }
247 *dest++ = c;
248 }
249 return dest;
250 }
251
252 /*() Convert attributes from (session) pool to JSON, applying OUTMAP. */
253
254 /* Called by: zxid_ses_to_json */
zxid_pool_to_json(zxid_conf * cf,struct zxid_attr * pool)255 static struct zx_str* zxid_pool_to_json(zxid_conf* cf, struct zxid_attr* pool)
256 {
257 char* p;
258 char* name;
259 int len = sizeof("{")-1, name_len;
260 struct zxid_map* map;
261 struct zxid_attr* at;
262 struct zxid_attr* av;
263 struct zx_str* ss;
264
265 /* Length computation pass */
266
267 for (at = pool; at; at = at->n) {
268 map = zxid_find_map(cf->outmap, at->name);
269 if (map) {
270 if (map->rule == ZXID_MAP_RULE_DEL) {
271 D("attribute(%s) filtered out by del rule in OUTMAP", at->name);
272 continue;
273 }
274 at->map_val = zxid_map_val(cf, 0, 0, map, at->name, at->val);
275 if (map->dst && *map->dst && map->src && map->src[0] != '*') {
276 name_len = zxid_json_strlen(map->dst);
277 } else {
278 name_len = zxid_json_strlen(at->name);
279 }
280
281 if (at->nv) { /* Multivalue requires array */
282 len += name_len + sizeof("\"\":[\"\"],")-1 +
283 zxid_json_strlen(at->map_val->s);
284 for (av = at->nv; av; av = av->n) {
285 av->map_val = zxid_map_val(cf, 0, 0, map, at->name, av->val);
286 len += name_len + sizeof(",\"\"")-1 +
287 zxid_json_strlen(at->map_val->s);
288 }
289 } else {
290 len += name_len + sizeof("\"\":\"\",")-1 +
291 zxid_json_strlen(at->map_val->s);
292 }
293 } else {
294 name_len = zxid_json_strlen(at->name);
295 if (at->nv) { /* Multivalue requires array */
296 len += name_len + sizeof("\"\":[\"\"],")-1 +
297 (at->val?zxid_json_strlen(at->val):0);
298 for (av = at->nv; av; av = av->n)
299 len += name_len + sizeof(",\"\"")-1 +
300 (av->val?zxid_json_strlen(av->val):0);
301 } else {
302 len += name_len + sizeof("\"\":\"\",")-1 +
303 (at->val?zxid_json_strlen(at->val):0);
304 }
305 }
306 }
307
308 /* Attribute rendering pass */
309
310 ss = zx_new_len_str(cf->ctx, len);
311 p = ss->s;
312 *p++ = '{';
313
314 for (at = pool; at; at = at->n) {
315 map = zxid_find_map(cf->outmap, at->name);
316 if (map) {
317 if (map->rule == ZXID_MAP_RULE_DEL)
318 continue;
319 if (map->dst && *map->dst && map->src && map->src[0] != '*') {
320 name = map->dst;
321 } else {
322 name = at->name;
323 }
324
325 *p++ = '"';
326 p = zxid_json_strcpy(p, name);
327 p += strlen(name);
328 *p++ = '"';
329 *p++ = ':';
330 if (at->nv) {
331 *p++ = '[';
332 *p++ = '"';
333 p = zxid_json_strcpy(p, at->map_val->s);
334 *p++ = '"';
335 for (av = at->nv; av; av = av->n) {
336 *p++ = ',';
337 *p++ = '"';
338 p = zxid_json_strcpy(p, av->map_val->s);
339 *p++ = '"';
340 }
341 *p++ = ']';
342 } else {
343 *p++ = '"';
344 p = zxid_json_strcpy(p, at->map_val->s);
345 *p++ = '"';
346 }
347
348 } else {
349 *p++ = '"';
350 p = zxid_json_strcpy(p, at->name);
351 *p++ = '"';
352 *p++ = ':';
353 if (at->nv) {
354 *p++ = '[';
355 *p++ = '"';
356 if (at->val) {
357 p = zxid_json_strcpy(p, at->val);
358 }
359 *p++ = '"';
360 for (av = at->nv; av; av = av->n) {
361 *p++ = ',';
362 *p++ = '"';
363 if (at->val) {
364 p = zxid_json_strcpy(p, av->val);
365 }
366 *p++ = '"';
367 }
368 *p++ = ']';
369 } else {
370 *p++ = '"';
371 if (at->val) {
372 p = zxid_json_strcpy(p, at->val);
373 }
374 *p++ = '"';
375 }
376 }
377 *p++ = ',';
378 }
379 p[-1] = '}'; /* Overwrites last comma */
380 ASSERTOPP(p, ==, ss->s+len);
381 return ss;
382 }
383
384 /*() Convert attributes from (session) pool to query string, applying OUTMAP.
385 * *** Need to check multivalue handling. Now all values are simply blurted
386 * out as separate name=value pairs.
387 * *** Need to figure out how to distinguish query string return from
388 * other returns, like redirect. Perhaps arrange dn field always first? */
389
390 /* Called by: zxid_ses_to_qs */
zxid_pool_to_qs(zxid_conf * cf,struct zxid_attr * pool)391 static struct zx_str* zxid_pool_to_qs(zxid_conf* cf, struct zxid_attr* pool)
392 {
393 char* p;
394 char* name;
395 int len = sizeof("dn=QS1&")-1, name_len;
396 struct zxid_map* map;
397 struct zxid_attr* at;
398 struct zxid_attr* av;
399 struct zx_str* ss;
400
401 /* Length computation pass */
402
403 for (at = pool; at; at = at->n) {
404 map = zxid_find_map(cf->outmap, at->name);
405 if (map) {
406 if (map->rule == ZXID_MAP_RULE_DEL) {
407 D("attribute(%s) filtered out by del rule in OUTMAP", at->name);
408 continue;
409 }
410 at->map_val = zxid_map_val(cf, 0, 0, map, at->name, at->val);
411 if (map->dst && *map->dst && map->src && map->src[0] != '*') {
412 name_len = strlen(map->dst);
413 } else {
414 name_len = strlen(at->name);
415 }
416 len += name_len + sizeof("=&")-1 + zx_url_encode_len(at->map_val->len,at->map_val->s)-1;
417 for (av = at->nv; av; av = av->n) {
418 av->map_val = zxid_map_val(cf, 0, 0, map, at->name, av->val);
419 len += name_len + sizeof("=&")-1 + zx_url_encode_len(av->map_val->len,av->map_val->s)-1;
420 }
421 D("len=%d name_len=%d %s", len, name_len, at->name);
422 } else {
423 name_len = strlen(at->name);
424 len += name_len + sizeof("=&")-1 + (at->val?zx_url_encode_len(strlen(at->val),at->val)-1:0);
425 D("len=%d name_len=%d %s (nomap) url_enc_len=%d", len, name_len, at->name, (at->val?zx_url_encode_len(strlen(at->val),at->val)-1:0));
426 for (av = at->nv; av; av = av->n)
427 len += name_len + sizeof("=&")-1 + (av->val?zx_url_encode_len(strlen(av->val),av->val)-1:0);
428 }
429 }
430
431 /* Attribute rendering pass */
432
433 DD("HERE %d", 0);
434
435 ss = zx_new_len_str(cf->ctx, len);
436 p = ss->s;
437 memcpy(p, "dn=QS1&", sizeof("dn=QS1&")-1);
438 p += sizeof("dn=QS1&")-1;
439
440 for (at = pool; at; at = at->n) {
441 map = zxid_find_map(cf->outmap, at->name);
442 if (map) {
443 if (map->rule == ZXID_MAP_RULE_DEL)
444 continue;
445 if (map->dst && *map->dst && map->src && map->src[0] != '*') {
446 name = map->dst;
447 } else {
448 name = at->name;
449 }
450
451 name_len = strlen(name);
452 strcpy(p, name);
453 p += name_len;
454 *p++ = '=';
455 p = zx_url_encode_raw(at->map_val->len, at->map_val->s, p);
456 *p++ = '&';
457
458 for (av = at->nv; av; av = av->n) {
459 strcpy(p, name);
460 p += name_len;
461 *p++ = '=';
462 p = zx_url_encode_raw(av->map_val->len, av->map_val->s, p);
463 *p++ = '&';
464 }
465 } else {
466 name_len = strlen(at->name);
467 strcpy(p, at->name);
468 p += name_len;
469 *p++ = '=';
470 if (at->val)
471 p = zx_url_encode_raw(strlen(at->val), at->val, p);
472 *p++ = '&';
473
474 for (av = at->nv; av; av = av->n) {
475 strcpy(p, at->name);
476 p += name_len;
477 *p++ = '=';
478 if (at->val)
479 p = zx_url_encode_raw(strlen(av->val), av->val, p);
480 *p++ = '&';
481 }
482 }
483 }
484 D("p=%p == %p ss=%p len=%d", p, ss->s+len, ss->s, len);
485 DD("p(%.*s)", len, ss->s);
486 ASSERTOPP(p, ==, ss->s+len);
487 *p = 0; /* Zap last & */
488 return ss;
489 }
490
491 /*() Convert attributes from session to LDIF, applying OUTMAP. */
492
493 /* Called by: */
zxid_ses_to_ldif(zxid_conf * cf,zxid_ses * ses)494 struct zx_str* zxid_ses_to_ldif(zxid_conf* cf, zxid_ses* ses) {
495 return zxid_pool_to_ldif(cf, ses?ses->at:0);
496 }
497
498 /*() Convert attributes from session to JSON, applying OUTMAP. */
499
500 /* Called by: zxid_simple_ab_pep */
zxid_ses_to_json(zxid_conf * cf,zxid_ses * ses)501 struct zx_str* zxid_ses_to_json(zxid_conf* cf, zxid_ses* ses) {
502 return zxid_pool_to_json(cf, ses?ses->at:0);
503 }
504
505 /*() Convert attributes from session to query string, applying OUTMAP. */
506
507 /* Called by: zxid_simple_ab_pep */
zxid_ses_to_qs(zxid_conf * cf,zxid_ses * ses)508 struct zx_str* zxid_ses_to_qs(zxid_conf* cf, zxid_ses* ses) {
509 return zxid_pool_to_qs(cf, ses?ses->at:0);
510 }
511
512 /*() Add values to session attribute pool, applying NEED, WANT, and INMAP */
513
514 /* Called by: zxid_add_a7n_at_to_pool x2 */
zxid_add_at_vals(zxid_conf * cf,zxid_ses * ses,struct zx_sa_Attribute_s * at,char * name,struct zx_str * issuer)515 static int zxid_add_at_vals(zxid_conf* cf, zxid_ses* ses, struct zx_sa_Attribute_s* at, char* name, struct zx_str* issuer)
516 {
517 struct zx_str* ss;
518 struct zxid_map* map;
519 struct zx_sa_AttributeValue_s* av;
520 struct zxid_attr* ses_at;
521
522 /* Attribute must be needed or wanted */
523
524 if (!zxid_is_needed(cf->need, name) && !zxid_is_needed(cf->want, name)) {
525 D("attribute(%s) neither needed nor wanted", name);
526 return 0;
527 }
528
529 map = zxid_find_map(cf->inmap, name);
530 if (map && map->rule == ZXID_MAP_RULE_DEL) {
531 D("attribute(%s) filtered out by del rule in INMAP", name);
532 return 0;
533 }
534
535 /* Locate existing session pool attribute by name or mapped name, or create
536 * empty one if needed. N.B. The value is not assigned here yet. */
537
538 if (map && map->dst && *map->dst && map->src && map->src[0] != '*') {
539 ses_at = zxid_find_at(ses->at, map->dst);
540 if (!ses_at)
541 ses->at = ses_at = zxid_new_at(cf, ses->at, strlen(map->dst), map->dst, 0, 0, "mappd");
542 } else {
543 ses_at = zxid_find_at(ses->at, name);
544 if (!ses_at)
545 ses->at = ses_at = zxid_new_at(cf, ses->at, strlen(name), name, 0, 0, "as is");
546 }
547 ses_at->orig = at;
548 ses_at->issuer = issuer;
549
550 for (av = at->AttributeValue;
551 av;
552 av = (struct zx_sa_AttributeValue_s*)ZX_NEXT(av)) {
553 if (av->gg.g.tok != zx_sa_AttributeValue_ELEM)
554 continue;
555 DD(" adding value: %p", ZX_GET_CONTENT(av));
556 if (av->EndpointReference || av->ResourceOffering)
557 continue; /* Skip bootstraps. They are handled elsewhere, see zxid_snarf_eprs_from_ses(). */
558 if (ZX_GET_CONTENT(av)) {
559 ss = zxid_map_val_ss(cf, ses, 0, map, ses_at->name, ZX_GET_CONTENT(av));
560 if (ses_at->val) {
561 D(" multival(%.*s)", ss->len, ss->s);
562 ses->at->nv = zxid_new_at(cf, ses_at->nv, 0, 0, ss->len, ss->s, "multival");
563 } else {
564 D(" 1st val(%.*s)", ss->len, ss->s);
565 COPYVAL(ses_at->val, ss->s, ss->s+ss->len);
566 }
567 }
568 }
569 // *** check that value is not null, add empty string
570 return 1;
571 }
572
573 /*() Add Attribute Statements of an Assertion to session attribute pool, applying NEED, WANT, and INMAP */
574
575 /* Called by: zxid_ses_to_pool */
zxid_add_a7n_at_to_pool(zxid_conf * cf,zxid_ses * ses,zxid_a7n * a7n)576 static void zxid_add_a7n_at_to_pool(zxid_conf* cf, zxid_ses* ses, zxid_a7n* a7n)
577 {
578 struct zx_sa_Attribute_s* at;
579 struct zx_sa_AttributeStatement_s* as;
580 if (!a7n)
581 return;
582
583 for (as = a7n->AttributeStatement;
584 as;
585 as = (struct zx_sa_AttributeStatement_s*)ZX_NEXT(as)) {
586 if (as->gg.g.tok != zx_sa_AttributeStatement_ELEM)
587 continue;
588 for (at = as->Attribute;
589 at;
590 at = (struct zx_sa_Attribute_s*)ZX_NEXT(at)) {
591 if (at->gg.g.tok != zx_sa_Attribute_ELEM)
592 continue;
593 if (at->Name)
594 zxid_add_at_vals(cf, ses, at, zx_str_to_c(cf->ctx, &at->Name->g), ZX_GET_CONTENT(a7n->Issuer));
595 if (at->FriendlyName)
596 zxid_add_at_vals(cf, ses, at, zx_str_to_c(cf->ctx, &at->FriendlyName->g), ZX_GET_CONTENT(a7n->Issuer));
597 }
598 }
599 }
600
601 /*() Add simple attribute to session's attribute pool, applying NEED, WANT, and INMAP.
602 * Replaces zxid_add_attr_to_pool() */
603
604 /* Called by: chkuid, zxid_add_action_from_body_child, zxid_add_ldif_at2ses, zxid_add_qs2ses, zxid_mini_httpd_sso, zxid_ses_to_pool x26, zxid_simple_ab_pep x2 */
zxid_add_attr_to_ses(zxid_conf * cf,zxid_ses * ses,char * at_name,struct zx_str * val)605 void zxid_add_attr_to_ses(zxid_conf* cf, zxid_ses* ses, char* at_name, struct zx_str* val)
606 {
607 struct zxid_map* map;
608 if (!val)
609 val = zx_dup_str(cf->ctx, "-");
610
611 if (zxid_is_needed(cf->need, at_name) || zxid_is_needed(cf->want, at_name)) {
612 map = zxid_find_map(cf->inmap, at_name);
613 if (map && map->rule == ZXID_MAP_RULE_DEL) {
614 D("attribute(%s) filtered out by del rule in INMAP", at_name);
615 } else {
616 if (map && map->dst && *map->dst && map->src && map->src[0] != '*') {
617 ses->at = zxid_new_at(cf, ses->at, strlen(map->dst), map->dst, val->len, val->s, "mappd2");
618 } else {
619 ses->at = zxid_new_at(cf, ses->at, strlen(at_name), at_name, val->len, val->s, "as is2");
620 }
621 }
622 } else {
623 D("attribute(%s) neither needed nor wanted", at_name);
624 }
625 }
626
627 /*() Parse LDIF format and insert attributes to linked list. Return new head of the list.
628 * *** illegal input causes corrupt pointer. For example query string input causes corruption. */
629
630 /* Called by: zxid_ses_to_pool x3 */
zxid_add_ldif_at2ses(zxid_conf * cf,zxid_ses * ses,const char * prefix,char * p,char * lk)631 static void zxid_add_ldif_at2ses(zxid_conf* cf, zxid_ses* ses, const char* prefix, char* p, char* lk)
632 {
633 char* name;
634 char* val;
635 char* nbuf;
636 char name_buf[ZXID_MAX_USER];
637 int len;
638 if (prefix) {
639 strncpy(name_buf, prefix, sizeof(name_buf)-1);
640 nbuf = name_buf + MIN(strlen(prefix), sizeof(name_buf)-1);
641 } else
642 nbuf = name_buf;
643
644 for (; p; ++p) {
645 name = p;
646 p = strstr(p, ": ");
647 if (!p)
648 break;
649 len = MIN(p-name, sizeof(name_buf)-(nbuf-name_buf)-1);
650 memcpy(nbuf, name, len);
651 nbuf[len]=0;
652
653 val = p+2;
654 p = strchr(val, '\n'); /* *** parsing LDIF is fragile if values are multiline */
655 len = p?(p-val):strlen(val);
656 D("%s: ATTR(%s)=(%.*s)", lk, name_buf, len, val);
657 zxid_add_attr_to_ses(cf, ses, name_buf, zx_dup_len_str(cf->ctx, len, val));
658 }
659 }
660
661 /*() Copy user's local EPRs to his current session.
662 * This function implements a feature where user can have at
663 * some site some long term EPRs (with long term credential). When SSO
664 * is made, these EPRs are copied to user's session's EPR
665 * cache and thus made available. The persistent user EPRs could
666 * be used to implement stuff like subscriptions.
667 *
668 * The ".all" user's EPRs provide a mechanism to add to all users of
669 * a given SP some EPR. Naturally such EPR can not have per user
670 * or short time credential. This can have security implications.
671 *
672 * cf:: Config object for cf->cpath, and for memory allocation
673 * ses:: Session object. ses->sid is used to determine desitmation directory.
674 * path:: Path to the user directory (in /var/zxid/user/<sha1_safe_base64(idpnid)>/)
675 */
676
677 /* Called by: zxid_ses_to_pool x3 */
zxid_cp_usr_eprs2ses(zxid_conf * cf,zxid_ses * ses,struct zx_str * path)678 static void zxid_cp_usr_eprs2ses(zxid_conf* cf, zxid_ses* ses, struct zx_str* path)
679 {
680 char bs_dir[ZXID_MAX_BUF];
681 char ses_path[ZXID_MAX_BUF];
682 DIR* dir;
683 struct dirent * de;
684 if (!ses->sid || !*ses->sid || !path)
685 return; /* No valid session. Nothing to do. */
686
687 snprintf(bs_dir, sizeof(bs_dir), "%.*s/.bs", path->len, path->s);
688 bs_dir[sizeof(bs_dir)-1] = 0; /* must terminate manually as on win32 nul is not guaranteed */
689 dir = opendir(bs_dir);
690 if (!dir) {
691 D("Local bootstrap dir(%s) does not exist", bs_dir);
692 return;
693 }
694 while (de = readdir(dir)) {
695 if (ONE_OF_2(de->d_name[0], '.', 0)) /* skip . and .. and .foo */
696 continue;
697
698 snprintf(bs_dir, sizeof(bs_dir), "%.*s/.bs/%s", path->len, path->s, de->d_name);
699 bs_dir[sizeof(bs_dir)-1] = 0; /* must terminate manually as on win32 nul is not guaranteed */
700 snprintf(ses_path, sizeof(ses_path), "%.*s" ZXID_SES_DIR "%s/%s", path->len, path->s, ses->sid, de->d_name);
701 ses_path[sizeof(ses_path)-1] = 0; /* must term manually as on win32 nul is not guaranteed */
702 copy_file(bs_dir, ses_path, "EPRS2ses", 1);
703 }
704 closedir(dir);
705 }
706
707 /*(i) Process attributes from the AttributeStatements of the session's
708 * SSO Assertion and insert them to the session's attribute pool. NEED, WANT, and INMAP
709 * are applied. The pool is suitable for use by PEP or eventually
710 * rendering to LDIF (or JSON). This function also implements
711 * local attribute authority. */
712
713 /* Called by: zxid_as_call_ses, zxid_az_base_cf, zxid_az_cf, zxid_fetch_ses, zxid_simple_ab_pep, zxid_wsc_valid_re_env, zxid_wsp_validate_env */
zxid_ses_to_pool(zxid_conf * cf,zxid_ses * ses)714 void zxid_ses_to_pool(zxid_conf* cf, zxid_ses* ses)
715 {
716 char* src;
717 char* dst;
718 char* lim;
719 struct zx_str* issuer = 0;
720 struct zx_str* affid;
721 struct zx_str* nid;
722 struct zx_str* tgtissuer = 0;
723 struct zx_str* tgtaffid;
724 struct zx_str* tgtnid;
725 struct zx_str* accr;
726 struct zx_str* path;
727 struct zx_sa_AuthnStatement_s* as;
728 struct zx_sa_Assertion_s* a7n;
729 struct zx_sa_Assertion_s* tgta7n;
730 char* buf;
731 char sha1_name[28];
732
733 D_INDENT("ses2pool: ");
734 zxid_get_ses_sso_a7n(cf, ses);
735 a7n = ses->a7n;
736 D("adding a7n %p to pool", a7n);
737 zxid_add_a7n_at_to_pool(cf, ses, a7n);
738
739 /* Format some pseudo attributes that describe the SSO */
740
741 if (a7n) {
742 zxid_add_attr_to_ses(cf, ses, "ssoa7n", zx_easy_enc_elem_opt(cf, &a7n->gg));
743 issuer = ZX_GET_CONTENT(a7n->Issuer);
744 }
745 zxid_add_attr_to_ses(cf, ses, "issuer", issuer);
746 zxid_add_attr_to_ses(cf, ses, "ssoa7npath",zx_dup_str(cf->ctx, STRNULLCHK(ses->sso_a7n_path)));
747
748 affid = ses->nameid&&ses->nameid->NameQualifier?&ses->nameid->NameQualifier->g:0;
749 nid = ZX_GET_CONTENT(ses->nameid);
750 zxid_add_attr_to_ses(cf, ses, "affid", affid);
751 zxid_add_attr_to_ses(cf, ses, "idpnid", nid);
752 zxid_add_attr_to_ses(cf, ses, "nidfmt", zx_dup_str(cf->ctx, ses->nidfmt?"P":"T"));
753 if (nid) {
754 zxid_user_sha1_name(cf, affid, nid, sha1_name);
755 path = zx_strf(cf->ctx, "%s" ZXID_USER_DIR "%s", cf->cpath, sha1_name);
756 zxid_add_attr_to_ses(cf, ses, "localpath", path);
757 buf = read_all_alloc(cf->ctx, "splocal_user_at", 0, 0, "%.*s/.bs/.at", path->len, path->s);
758 if (buf) {
759 zxid_add_ldif_at2ses(cf, ses, "local_", buf, "splocal_user_at");
760 ZX_FREE(cf->ctx, buf);
761 }
762 zxid_cp_usr_eprs2ses(cf, ses, path);
763 }
764
765 /* Format pseudo attrs that describe the target, defaulting to the SSO identity. */
766
767 if (ses->tgta7n)
768 tgta7n = ses->tgta7n;
769 else
770 tgta7n = a7n;
771 if (tgta7n) {
772 zxid_add_attr_to_ses(cf, ses, "tgta7n", zx_easy_enc_elem_opt(cf, &a7n->gg));
773 tgtissuer = ZX_GET_CONTENT(tgta7n->Issuer);
774 }
775 if (tgtissuer)
776 zxid_add_attr_to_ses(cf, ses, "tgtissuer", tgtissuer);
777 zxid_add_attr_to_ses(cf, ses, "tgta7npath",zx_dup_str(cf->ctx, STRNULLCHK(ses->tgt_a7n_path)));
778
779 tgtaffid = ses->tgtnameid&&ses->tgtnameid->NameQualifier?&ses->tgtnameid->NameQualifier->g:0;
780 tgtnid = ZX_GET_CONTENT(ses->tgtnameid);
781 if (!tgtissuer) tgtissuer = issuer; /* Default: requestor is the target */
782 if (!tgtaffid) tgtaffid = affid;
783 if (!tgtnid) tgtnid = nid;
784 zxid_add_attr_to_ses(cf, ses, "tgtaffid", tgtaffid);
785 zxid_add_attr_to_ses(cf, ses, "tgtnid", tgtnid);
786 zxid_add_attr_to_ses(cf, ses, "tgtfmt", zx_dup_str(cf->ctx, ses->tgtfmt?"P":"T"));
787 if (tgtnid) {
788 zxid_user_sha1_name(cf, tgtaffid, tgtnid, sha1_name);
789 path = zx_strf(cf->ctx, "%s" ZXID_USER_DIR "%s", cf->cpath, sha1_name);
790 zxid_add_attr_to_ses(cf, ses, "tgtpath", path);
791 buf = read_all_alloc(cf->ctx, "sptgt_user_at", 0, 0, "%.*s/.bs/.at", path->len, path->s);
792 if (buf) {
793 zxid_add_ldif_at2ses(cf, ses, "tgt_", buf, "sptgt_user_at");
794 ZX_FREE(cf->ctx, buf);
795 }
796 zxid_cp_usr_eprs2ses(cf, ses, path);
797 }
798
799 accr = a7n&&(as = a7n->AuthnStatement)&&as->AuthnContext?ZX_GET_CONTENT(as->AuthnContext->AuthnContextClassRef):0;
800 //accr = a7n&&a7n->AuthnStatement&&a7n->AuthnStatement->AuthnContext&&a7n->AuthnStatement->AuthnContext->AuthnContextClassRef&&a7n->AuthnStatement->AuthnContext->AuthnContextClassRef->content&&a7n->AuthnStatement->AuthnContext->AuthnContextClassRef->content?a7n->AuthnStatement->AuthnContext->AuthnContextClassRef->content:0;
801 zxid_add_attr_to_ses(cf, ses, "authnctxlevel", accr);
802
803 buf = read_all_alloc(cf->ctx, "splocal.all", 0,0, "%s" ZXID_USER_DIR ".all/.bs/.at" , cf->cpath);
804 if (buf) {
805 zxid_add_ldif_at2ses(cf, ses, 0, buf, "splocal.all");
806 ZX_FREE(cf->ctx, buf);
807 }
808 path = zx_strf(cf->ctx, "%s" ZXID_USER_DIR ".all", cf->cpath);
809 zxid_cp_usr_eprs2ses(cf, ses, path);
810
811 zxid_add_attr_to_ses(cf, ses, "eid", zxid_my_ent_id(cf));
812 zxid_add_attr_to_ses(cf, ses, "sigres", zx_strf(cf->ctx, "%x", ses->sigres));
813 zxid_add_attr_to_ses(cf, ses, "ssores", zx_strf(cf->ctx, "%x", ses->ssores));
814 if (ses->sid && *ses->sid) {
815 zxid_add_attr_to_ses(cf, ses, "sesid", zx_dup_str(cf->ctx, STRNULLCHK(ses->sid)));
816 zxid_add_attr_to_ses(cf, ses, "sespath", zx_strf(cf->ctx, "%s" ZXID_SES_DIR "%s", cf->cpath, STRNULLCHK(ses->sid)));
817 }
818 zxid_add_attr_to_ses(cf, ses, "sesix", zx_dup_str(cf->ctx, STRNULLCHK(ses->sesix)));
819 zxid_add_attr_to_ses(cf, ses, "setcookie", zx_dup_str(cf->ctx, STRNULLCHK(ses->setcookie)));
820 zxid_add_attr_to_ses(cf, ses, "setptmcookie",zx_dup_str(cf->ctx,STRNULLCHK(ses->setptmcookie)));
821 if (ses->cookie && ses->cookie[0])
822 zxid_add_attr_to_ses(cf, ses, "cookie", zx_dup_str(cf->ctx, ses->cookie));
823 zxid_add_attr_to_ses(cf, ses, "msgid", ses->wsp_msgid);
824
825 zxid_add_attr_to_ses(cf, ses, "rs", zx_dup_str(cf->ctx, STRNULLCHK(ses->rs)));
826 src = dst = ses->at->val;
827 lim = ses->at->val + strlen(ses->at->val);
828 URL_DECODE(dst, src, lim);
829 *dst = 0;
830 D("RelayState(%s)", ses->at->val);
831 D_DEDENT("ses2pool: ");
832 }
833
834 /*(i) Add Attributes from Querty String to Session attribute pool
835 * The qs argument is parsed according to the CGI Query String rules (string
836 * is modifed to insert nul terminations and URL decoded in place)
837 * and the attributes are added to the session. If apply_map is 1, the
838 * INMAP configuration is applied. While this may seem a hassle, it
839 * allows for specification of the values as safe_base64, etc. If values
840 * are to be added verbatim, just specify 0 (all other values reserved).
841 * The input argument qs gets modified in-situ due to URL decoding and
842 * nul termination. Make sure to duplicate any string constant before calling.
843 * Returns 1 on success, 0 on failure (return value often not checked). */
844
845 /* Called by: zxid_az_base_cf_ses, zxid_az_cf_ses, zxid_query_ctlpt_pdp x2 */
zxid_add_qs2ses(zxid_conf * cf,zxid_ses * ses,char * qs,int apply_map)846 int zxid_add_qs2ses(zxid_conf* cf, zxid_ses* ses, char* qs, int apply_map)
847 {
848 char* n;
849 char* v;
850 if (!qs || !ses)
851 return 0;
852
853 D("qs(%s) len=%d", qs, (int)strlen(qs));
854 while (qs && *qs) {
855 qs = zxid_qs_nv_scan(qs, &n, &v, 1);
856 if (!n)
857 n = "NULL_NAM_ERR";
858
859 if (apply_map) {
860 D("map %s=%s", n,v);
861 zxid_add_attr_to_ses(cf, ses, n, zx_dup_str(cf->ctx, v));
862 } else {
863 D("asis %s=%s", n,v);
864 ses->at = zxid_new_at(cf, ses->at, strlen(n), n, strlen(v), v, "as is3");
865 }
866 }
867 return 1;
868 }
869
870 /*(i) Given session object (see zxid_simple_cf_ses() or zxid_fetch_ses()),
871 * return n'th value (ix=0 is first) of given attribute, if any, from the
872 * session common attribute pool. If apply_map is 0, the value is returned
873 * as is. If it is 1 then OUTMAP is applied (the
874 * attribute name is in the internal namespace). Other apply_map values
875 * are reserved. */
876
877 /* Called by: */
zxid_get_at(zxid_conf * cf,zxid_ses * ses,char * atname,int ix,int apply_map)878 struct zx_str* zxid_get_at(zxid_conf* cf, zxid_ses* ses, char* atname, int ix, int apply_map)
879 {
880 struct zxid_attr* at;
881 struct zxid_attr* av;
882 if (!cf || !ses || !atname) {
883 ERR("Missing args cf=%p ses=%p atname=%p", cf, ses, atname);
884 return 0;
885 }
886 for (at = ses->at; at; at = at->n) {
887 if (!strcmp(at->name, atname)) {
888 for (av = at; av && ix; --ix, av = av->nv) ;
889 if (av) {
890 if (apply_map) {
891 return zx_dup_str(cf->ctx, at->val); /* *** */
892 } else
893 return zx_dup_str(cf->ctx, at->val);
894 }
895 }
896 }
897 return 0;
898 }
899
900 /* EOF -- zxidpool.c */
901