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: */ 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 */ 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 */ 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 */ 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 */ 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: */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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: */ 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