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