1 /* zxidconf.c  -  Handwritten functions for parsing ZXID configuration file
2  * Copyright (c) 2012-2016 Synergetics (sampo@synergetics.be), All Rights Reserved.
3  * Copyright (c) 2009-2011 Sampo Kellomaki (sampo@iki.fi), All Rights Reserved.
4  * Copyright (c) 2006-2009 Symlabs (symlabs@symlabs.com), All Rights Reserved.
5  * Author: Sampo Kellomaki (sampo@iki.fi)
6  * This is confidential unpublished proprietary source code of the author.
7  * NO WARRANTY, not even implied warranties. Contains trade secrets.
8  * Distribution prohibited unless authorized in writing.
9  * Licensed under Apache License 2.0, see file COPYING.
10  * $Id: zxidconf.c,v 1.51 2010-01-08 02:10:09 sampo Exp $
11  *
12  * 12.8.2006, created --Sampo
13  * 16.1.2007, split from zxidlib.c --Sampo
14  * 27.3.2007, lazy reading of certificates --Sampo
15  * 22.2.2008, added path_supplied feature --Sampo
16  * 7.10.2008, added documentation --Sampo
17  * 29.8.2009, added Auto-Cert feature a.k.a. zxid_mk_self_signed_cert() --Sampo
18  * 4.9.2009,  added NEED, WANT, INMAP, PEPMAP, OUTMAP, and ATTRSRC --Sampo
19  * 15.11.2009, added SHOW_CONF (o=d) option --Sampo
20  * 7.1.2010,  added WSC and WSP signing options --Sampo
21  * 12.2.2010, added pthread locking --Sampo
22  * 31.5.2010, added 4 web service call PEPs --Sampo
23  * 21.4.2011, fixed DSA key reading and reading unqualified keys --Sampo
24  * 3.12.2011, added VPATH feature --Sampo
25  * 10.12.2011, added VURL and BUTTON_URL, deleted ORG_URL except for legacy check --Sampo
26  * 17.8.2012, added audit bus configuration --Sampo
27  * 16.2.2013, added WD option --Sampo
28  * 21.6.2013, added wsp_pat --Sampo
29  * 20.11.2013, added %d expansion for VURL, added ECHO for debug prints --Sampo
30  * 29.11.2013, added INCLUDE feature --Sampo
31  * 4.12.2013,  changed URL to BURL --Sampo
32  * 11.4.2015,  added UNIX_GRP_AZ_MAP --Sampo
33  * 18.12.2015, applied patch from soconnor, perceptyx, including detection of
34  *             signature algorithm from certificate. --Sampo
35  * 8.1.2016,   added configuration options for signature and digest algorithms --Sampo
36  */
37 
38 #include "platform.h"  /* needed on Win32 for pthread_mutex_lock() et al. */
39 
40 #include <malloc.h>
41 #include <memory.h>
42 #include <string.h>
43 #include <stdlib.h>
44 #include <sys/types.h>
45 #include <grp.h>
46 #ifdef USE_CURL
47 #include <curl/curl.h>
48 #endif
49 
50 #include "errmac.h"
51 #include "zx.h"
52 #include "zxid.h"
53 #include "zxidutil.h"
54 #include "zxidconf.h"
55 #include "zxidpriv.h"
56 #include "c/zxidvers.h"
57 
58 /* ============== Configuration ============== */
59 /* Eventually configuration will be read from some file, but for
60  * now, we settle for compilation time configuration, see zxidconf.h */
61 
62 #ifdef USE_OPENSSL
63 
64 #include <openssl/rand.h>
65 #include <openssl/x509.h>
66 #include <openssl/rsa.h>
67 
68 #if 0
69 /*(-) Compute raw SHA1 digest hash over contents of a file.
70  *
71  * cf:: ZXID configuration object, used for deteminin path prefix and for memory allocation
72  * name:: Name of the file (under hierarchy defined by PATH configuration option)
73  * sha1:: A sha1 buffer which should be exactly 20 bytes (160 bits) long. The
74  *     buffer will be modified in place by this function. */
75 
76 /* Called by:  zxid_init_conf */
77 void zxid_sha1_file(zxid_conf* cf, char* name, char* sha1)
78 {
79   int gotall;
80   char* buf;
81   ZERO(sha1, 20);
82   buf = read_all_alloc(cf->ctx, "sha1_file", 1, &gotall, "%s%s", cf->cpath, name);
83   if (!buf)
84     return;
85   SHA1(buf, gotall, sha1);
86   ZX_FREE(cf->ctx, buf);
87 }
88 #endif
89 
zxid_extract_cert_pem(char * buf,char * name)90 char* zxid_extract_cert_pem(char* buf, char* name)
91 {
92   char* p;
93   char* e;
94   p = strstr(buf, PEM_CERT_START);
95   if (!p) {
96     ERR("No certificate found in file(%s)\n", name);
97     return 0;
98   }
99   p += sizeof(PEM_CERT_START) - 1;
100   if (*p == 0xd) ++p;
101   if (*p != 0xa) return 0;
102   ++p;
103 
104   e = strstr(buf, PEM_CERT_END);
105   if (!e) return 0;
106   *e = 0;
107   return p;
108 }
109 
110 /*() Extract a certificate as base64 textr from PEM encoded file. */
111 
zxid_read_cert_pem(zxid_conf * cf,char * name,int siz,char * buf)112 char* zxid_read_cert_pem(zxid_conf* cf, char* name, int siz, char* buf)
113 {
114   int got = read_all(siz, buf, "read_cert", 1, "%s" ZXID_PEM_DIR "%s", cf->cpath, name);
115   if (!got && cf->auto_cert)
116     zxid_mk_self_sig_cert(cf, siz, buf, "read_cert", name);
117   return zxid_extract_cert_pem(buf, name);
118 }
119 
120 
121 /*() Extract a certificate from PEM encoded string. */
122 
123 /* Called by:  opt, test_mode, zxid_read_cert */
zxid_extract_cert(char * buf,char * name)124 X509* zxid_extract_cert(char* buf, char* name)
125 {
126   X509* x = 0;  /* Forces d2i_X509() to alloc the memory. */
127   char* p;
128   char* e;
129   p = zxid_extract_cert_pem(buf, name);
130   if (!p)
131     return 0;
132   e = unbase64_raw(p, p+strlen(p), p, zx_std_index_64);
133   OpenSSL_add_all_algorithms();
134   if (!d2i_X509(&x, (const unsigned char**)&p /* *** compile warning */, e-p) || !x) {
135     ERR("DER decoding of X509 certificate failed.\n%d", 0);
136     return 0;
137   }
138   return x;
139 }
140 
141 /*() Extract a certificate from PEM encoded file. */
142 
143 /* Called by:  hi_new_shuffler, zxid_idp_sso_desc x2, zxid_init_conf x3, zxid_lazy_load_sign_cert_and_pkey, zxid_sp_sso_desc x2, zxlog_write_line */
zxid_read_cert(zxid_conf * cf,char * name)144 X509* zxid_read_cert(zxid_conf* cf, char* name)
145 {
146   X509* x = 0;  /* Forces d2i_X509() to alloc the memory. */
147   char buf[8192];
148   char* p;
149   char* e;
150   p = zxid_read_cert_pem(cf, name, sizeof(buf), buf);
151   if (!p)
152     return 0;
153   OpenSSL_add_all_algorithms();
154   e = unbase64_raw(p, p+strlen(p), p, zx_std_index_64);
155   if (!d2i_X509(&x, (const unsigned char**)&p /* *** compile warning */, e-p) || !x) {
156     ERR("DER decoding of X509 certificate failed.\n%d", 0);
157     return 0;
158   }
159   return x;
160 }
161 
162 /*() Extract a private key from PEM encoded string.
163  * *** This function needs to expand to handle DSA and EC */
164 
165 /* Called by: */
zxid_extract_private_key(char * buf,char * name)166 EVP_PKEY* zxid_extract_private_key(char* buf, char* name)
167 {
168   char* p;
169   char* e;
170   int typ;
171   EVP_PKEY* pk = 0;  /* Forces d2i_PrivateKey() to alloc the memory. */
172   OpenSSL_add_all_algorithms();
173 
174   if (p = strstr(buf, PEM_RSA_PRIV_KEY_START)) {
175     typ = EVP_PKEY_RSA;
176     e = PEM_RSA_PRIV_KEY_END;
177     p += sizeof(PEM_RSA_PRIV_KEY_START) - 1;
178   } else if (p = strstr(buf, PEM_DSA_PRIV_KEY_START)) {
179     typ = EVP_PKEY_DSA;
180     e = PEM_DSA_PRIV_KEY_END;
181     p += sizeof(PEM_DSA_PRIV_KEY_START) - 1;
182   } else if (p = strstr(buf, PEM_PRIV_KEY_START)) {  /* Not official format, but sometimes seen. */
183     typ = EVP_PKEY_RSA;
184     e = PEM_PRIV_KEY_END;
185     p += sizeof(PEM_PRIV_KEY_START) - 1;
186   } else {
187     ERR("No private key found in file(%s). Looking for separator (%s) or (%s).\npem data(%s)", name, PEM_RSA_PRIV_KEY_START, PEM_DSA_PRIV_KEY_START, buf);
188     return 0;
189   }
190   if (*p == 0xd) ++p;
191   if (*p != 0xa) {
192     ERR("Bad privkey missing newline ch(0x%x) at %ld (%.*s) of buf(%s)", *p, (long)(p-buf), 5, p-2, buf);
193     return 0;
194   }
195   ++p;
196 
197   e = strstr(buf, e);
198   if (!e) {
199     ERR("End marker not found, typ=%d", typ);
200     return 0;
201   }
202 
203   zx_report_openssl_err("extract_private_key0"); /* *** seems something leaves errors on stack */
204   p = unbase64_raw(p, e, buf, zx_std_index_64);
205   if (!d2i_PrivateKey(typ, &pk, (const unsigned char**)&buf, p-buf) || !pk) {
206     zx_report_openssl_err("extract_private_key"); /* *** seems d2i can leave errors on stack */
207     ERR("DER decoding of private key failed.\n%d", 0);
208     return 0;
209   }
210   zx_report_openssl_err("extract_private_key2"); /* *** seems d2i can leave errors on stack */
211   return pk; /* RSA* rsa = EVP_PKEY_get1_RSA(pk); */
212 }
213 
214 /*() Extract a private key from PEM encoded file. */
215 
216 /* Called by:  hi_new_shuffler, test_ibm_cert_problem x2, test_ibm_cert_problem_enc_dec x2, zxbus_mint_receipt x2, zxenc_privkey_dec, zxid_init_conf x3, zxid_lazy_load_sign_cert_and_pkey, zxlog_write_line x2 */
zxid_read_private_key(zxid_conf * cf,char * name)217 EVP_PKEY* zxid_read_private_key(zxid_conf* cf, char* name)
218 {
219   char buf[8192];
220   int got = read_all(sizeof(buf),buf,"read_private_key",1, "%s" ZXID_PEM_DIR "%s", cf->cpath, name);
221   if (!got && cf->auto_cert)
222     zxid_mk_self_sig_cert(cf, sizeof(buf), buf, "read_private_key", name);
223   return zxid_extract_private_key(buf, name);
224 }
225 
226 /*() Lazy load signing certificate and private key. This reads them from disk
227  * if needed. If they do not exist and auto_cert is enabled, they will be
228  * generated on disk and then read. Once read from disk, they will be cached in
229  * memory.
230  *
231  * > N.B. If the cert does not yet exist, write access to disk will be needed.
232  * > If it already exists, read access is sufficient. Thus it is more secure
233  * > to pregenerate the certificate and then set the permissions so that
234  * > the process can read it, but can not alter it.
235  *
236  * cf:: Configuration object
237  * cert:: result parameter. If non null, the certificate will be extracted
238  *     from file and pointer to the X509 data structure will be deposited
239  *     to place pointed by this parameter. If null, certificate is neither
240  *     extracted nor returned. The data structure should be freed by the
241  *     caller.
242  * pkey:: result parameter. Must be specified. The private key data structure
243  *     is extracted from the file and returned using this parameter. The
244  *     data structure should be freed by the caller.
245  * logkey:: Free form string describing why the cert and private key are
246  *     being requested. Used for logging and debugging.
247  * return:: Returns 1 on success and 0 on failure.
248  */
249 
250 /* Called by:  zxid_anoint_a7n, zxid_anoint_sso_resp, zxid_az_soap x3, zxid_idp_soap_dispatch x2, zxid_idp_sso, zxid_mk_art_deref, zxid_mk_at_cert, zxid_saml2_post_enc, zxid_saml2_redir_enc, zxid_sp_mni_soap, zxid_sp_slo_soap, zxid_sp_soap_dispatch x7, zxid_ssos_anreq, zxid_wsf_sign */
zxid_lazy_load_sign_cert_and_pkey(zxid_conf * cf,X509 ** cert,EVP_PKEY ** pkey,const char * logkey)251 int zxid_lazy_load_sign_cert_and_pkey(zxid_conf* cf, X509** cert, EVP_PKEY** pkey, const char* logkey)
252 {
253   LOCK(cf->mx, logkey);
254   if (cert) {
255     if (!(*cert = cf->sign_cert)) // Lazy load cert and private key
256       *cert = cf->sign_cert = zxid_read_cert(cf, "sign-nopw-cert.pem");
257   }
258   if (!(*pkey = cf->sign_pkey))
259     *pkey = cf->sign_pkey = zxid_read_private_key(cf, "sign-nopw-cert.pem");
260   UNLOCK(cf->mx, logkey);
261   if (cert && !*cert || !*pkey)
262     return 0;
263   return 1;
264 }
265 
266 #endif  /* USE_OPENSSL */
267 
268 /*() Set obscure options of ZX and ZXID layers. Used to set debug options.
269  * Generally setting these options is not supported, but this function
270  * exists to avoid uncontrolled access to global variables. At least this
271  * way the unsupported activity will happen in one controlled place where
272  * it can be ignored, if need to be. You have been warned. */
273 
274 /* Called by:  main, zxid_fed_mgmt_cf, zxid_idp_list_cf_cgi, zxid_simple_cf_ses */
zxid_set_opt(zxid_conf * cf,int which,int val)275 int zxid_set_opt(zxid_conf* cf, int which, int val)
276 {
277   switch (which) {
278   case 1: errmac_debug = val; INFO("errmac_debug=%d",val); return val;
279   case 5: exit(val);  /* This is typically used to force __gcov_flush() */
280   case 6: zxid_set_opt_cstr(cf, 6, "/var/zxid/log/log.dbg"); return 0;
281 #ifdef M_CHECK_ACTION  /* glibc specific */
282   case 7: mallopt(M_CHECK_ACTION, val); return 0;  /* val==3 enables cores on bad free() */
283 #endif
284   default: ERR("zxid_set_opt: this version " ZXID_REL " does not support which=%d val=%d (ignored)", which, val);
285   }
286   return -1;
287 }
288 
289 /*() Set obscure options of ZX and ZXID layers. Used to set debug options.
290  * Generally setting these options is not supported, but this function
291  * exists to avoid uncontrolled access to global variables. At least this
292  * way the unsupported activity will happen in one controlled place where
293  * it can be ignored, if need to be. You have been warned. */
294 
295 /* Called by:  zxid_parse_conf_raw, zxid_set_opt */
zxid_set_opt_cstr(zxid_conf * cf,int which,char * val)296 char* zxid_set_opt_cstr(zxid_conf* cf, int which, char* val)
297 {
298   char buf[PATH_MAX];
299   switch (which) {
300   case 2: strncpy(errmac_instance, val, sizeof(errmac_instance)); return errmac_instance;
301   case 3: D_INDENT(val); return errmac_indent;
302   case 4: D_DEDENT(val); return errmac_indent;
303   case 6:
304     D("Forwarding debug output to file(%s) cwd(%s)", STRNULLCHK(val), getcwd(buf, sizeof(buf)));
305     errmac_debug_log = fopen(val, "a");
306     if (!errmac_debug_log) {
307       perror("zxid_set_opt_cstr: failed to open new log file");
308       fprintf(stderr, "zxid_set_opt_cstr: failed to open new log file(%s), euid=%d egid=%d cwd(%s)", STRNULLCHK(val), geteuid(), getegid(), getcwd(buf, sizeof(buf)));
309       exit(1);
310     }
311     INFO("zxid_set_opt_cstr: opened new log file(%s), rel=" ZXID_REL " euid=%d egid=%d cwd(%s)", STRNULLCHK(val), geteuid(), getegid(), getcwd(buf, sizeof(buf)));
312     return "";
313   default: ERR("zxid_set_opt_cstr: this version " ZXID_REL " does not support which=%d val(%s) (ignored)", which, STRNULLCHK(val));
314   }
315   return 0;
316 }
317 
318 /*() Set the BURL configuration variable.  Special accessor function to
319  * manipulate BURL config option. Manipulating this option is common in
320  * virtual hosting situations - hence this convenience function.  You
321  * could use zxid_parse_conf() instead to manipulate BURL and some other
322  * options. */
323 
324 /* Called by:  main x2, zxidwspcgi_main */
zxid_url_set(zxid_conf * cf,const char * burl)325 void zxid_url_set(zxid_conf* cf, const char* burl)
326 {
327   if (!cf || !burl) {
328     ERR("NULL pointer as cf or url argument cf=%p url=%p", cf, burl);
329     return;
330   }
331   D("Setting url(%s)", burl);
332   cf->burl = zx_dup_cstr(cf->ctx, burl);
333 }
334 
335 /* ================== Attribute Broker Config ================*/
336 
337 #define IS_RULE(rule, val) (!memcmp((rule), (val), sizeof(val)-1) && (rule)[sizeof(val)-1] == '$')
338 
339 /*() Create new (common pool) attribute and add it to a linked list */
340 
341 /* Called by:  zxid_add_at_vals x3, zxid_add_attr_to_ses x2, zxid_add_qs2ses, zxid_load_atsrc, zxid_load_need */
zxid_new_at(zxid_conf * cf,struct zxid_attr * at,int name_len,char * name,int val_len,char * val,char * lk)342 struct zxid_attr* zxid_new_at(zxid_conf* cf, struct zxid_attr* at, int name_len, char* name, int val_len, char* val, char* lk)
343 {
344   struct zxid_attr* aa = ZX_ZALLOC(cf->ctx, struct zxid_attr);
345   aa->n = at;
346   at = aa;
347   COPYVAL(at->name, name, name+name_len);
348   if (val)
349     COPYVAL(at->val, val, val+val_len);
350   D("%s:\tATTR(%.*s)=(%.*s)", lk, name_len, name, MIN(val_len, 80), STRNULLCHK(val));
351   return aa;
352 }
353 
354 /*() Reverse of zxid_new_at(). */
355 
356 /* Called by:  zxid_free_atsrc, zxid_free_need */
zxid_free_at(struct zxid_conf * cf,struct zxid_attr * attr)357 void zxid_free_at(struct zxid_conf *cf, struct zxid_attr *attr)
358 {
359   while (attr) {
360     struct zxid_attr *next = attr->n;
361     ZX_FREE(cf->ctx, attr->name);
362     if (attr->val) ZX_FREE(cf->ctx, attr->val);
363     ZX_FREE(cf->ctx, attr);
364     attr = next;
365   }
366 }
367 
368 /*() Parse need specification and add it to linked list
369  * A,B$usage$retention$oblig$ext;A,B$usage$retention$oblig$ext;...
370  */
371 
372 /* Called by:  zxid_init_conf x2, zxid_parse_conf_raw x2 */
zxid_load_need(zxid_conf * cf,struct zxid_need * need,char * v)373 struct zxid_need* zxid_load_need(zxid_conf* cf, struct zxid_need* need, char* v)
374 {
375   char* attrs;
376   char* usage;
377   char* retent;
378   char* oblig;
379   char* ext;
380   char* p = v;
381   char* a;
382   int len;
383   struct zxid_need* nn;
384 
385   while (p && *p) {
386     attrs = p;
387     p = strchr(p, '$');
388     if (!p) {
389       ERR("Malformed NEED or WANT directive: attribute list at pos %d", ((int)(p-v)));
390       return need;
391     }
392 
393     usage = ++p;
394     p = strchr(p, '$');
395     if (!p) {
396       ERR("Malformed NEED or WANT directive: usage missing at pos %d", ((int)(p-v)));
397       return need;
398     }
399 
400     retent = ++p;
401     p = strchr(p, '$');
402     if (!p) {
403       ERR("Malformed NEED or WANT directive: retention missing at pos %d", ((int)(p-v)));
404       return need;
405     }
406 
407     oblig = ++p;
408     p = strchr(p, '$');
409     if (!p) {
410       ERR("Malformed NEED or WANT directive: obligations missing at pos %d", ((int)(p-v)));
411       return need;
412     }
413 
414     ext = ++p;
415     p = strchr(p, ';');  /* Stanza ends in separator ; or end of string nul */
416     if (!p)
417       p = ext + strlen(ext);
418 
419     if (IS_RULE(usage, "reset")) {
420       INFO("Reset need %p", need);
421       zxid_free_need(cf, need);
422       need = 0;
423       if (!*p) break;
424       ++p;
425       continue;
426     }
427 
428     nn = ZX_ZALLOC(cf->ctx, struct zxid_need);
429     nn->n = need;
430     need = nn;
431 
432     COPYVAL(nn->usage,  usage,  retent-1);
433     COPYVAL(nn->retent, retent, oblig-1);
434     COPYVAL(nn->oblig,  oblig,  ext-1);
435     COPYVAL(nn->ext,    ext,    p);
436 
437     DD("need attrs(%.*s) usage(%s) retent(%s) oblig(%s) ext(%s)", usage-attrs-1, attrs, nn->usage, nn->retent, nn->oblig, nn->ext);
438 
439     for (a = attrs; ; a += len+1) {
440       len = strcspn(a, ",$");
441       nn->at = zxid_new_at(cf, nn->at, len, a, 0,0, "need/want");
442       if (a[len] == '$')
443 	break;
444     }
445     if (!*p) break;
446     ++p;
447   }
448 
449   return need;
450 }
451 
452 /*() Reverse of zxid_load_need(). */
453 
454 /* Called by:  zxid_free_conf x2, zxid_load_need */
zxid_free_need(struct zxid_conf * cf,struct zxid_need * need)455 void zxid_free_need(struct zxid_conf *cf, struct zxid_need *need)
456 {
457   while (need) {
458     struct zxid_need *next = need->n;
459     ZX_FREE(cf->ctx, need->usage);
460     ZX_FREE(cf->ctx, need->retent);
461     ZX_FREE(cf->ctx, need->oblig);
462     ZX_FREE(cf->ctx, need->ext);
463     zxid_free_at(cf, need->at);
464     ZX_FREE(cf->ctx, need);
465     need = next;
466   }
467 }
468 
469 /*() Parse map specification and add it to linked list
470  * srcns$A$rule$b$ext;src$A$rule$b$ext;...
471  * The list ends up being built in reverse order, which at runtime
472  * causes last stanzas to be evaluated first and first match is used.
473  * Thus you should place most specific rules last and most generic rules first.
474  * See also: zxid_find_map() and zxid_map_val()
475  */
476 
477 /* Called by:  zxid_init_conf x7, zxid_mk_usr_a7n_to_sp, zxid_parse_conf_raw x7, zxid_read_map */
zxid_load_map(zxid_conf * cf,struct zxid_map * map,char * v)478 struct zxid_map* zxid_load_map(zxid_conf* cf, struct zxid_map* map, char* v)
479 {
480   char* ns;
481   char* A;
482   char* rule;
483   char* b;
484   char* ext;
485   char* p = v;
486   int len;
487   struct zxid_map* mm;
488 
489   DD("v(%s)", v);
490 
491   while (p && *p) {
492     ns = p;
493     p = strchr(p, '$');
494     if (!p) {
495       ERR("Malformed MAP directive: source namespace missing at pos %d", ((int)(p-v)));
496       return map;
497     }
498 
499     A = ++p;
500     p = strchr(p, '$');
501     if (!p) {
502       ERR("Malformed MAP directive: source attribute name missing at pos %d", ((int)(p-v)));
503       return map;
504     }
505 
506     rule = ++p;
507     p = strchr(p, '$');
508     if (!p) {
509       ERR("Malformed MAP directive: rule missing at pos %d", ((int)(p-v)));
510       return map;
511     }
512 
513     b = ++p;
514     p = strchr(p, '$');
515     if (!p) {
516       ERR("Malformed MAP directive: destination attribute name missing at pos %d", ((int)(p-v)));
517       return map;
518     }
519 
520     ext = ++p;
521     len = strcspn(p, ";\n");  /* Stanza ends in separator ; or end of string nul */
522     p = ext + len;
523 
524     if (IS_RULE(rule, "reset")) {
525       INFO("Reset map %p", map);
526       for (; map; map = mm) {
527 	mm = map->n;
528 	ZX_FREE(cf->ctx, map);
529       }
530       if (!*p) break;
531       ++p;
532       continue;
533     }
534 
535     mm = ZX_ZALLOC(cf->ctx, struct zxid_map);
536     mm->n = map;
537     map = mm;
538 
539     if (IS_RULE(rule, "") || IS_RULE(rule, "rename")) { mm->rule = ZXID_MAP_RULE_RENAME; }
540     else if (IS_RULE(rule, "del"))           { mm->rule = ZXID_MAP_RULE_DEL; }
541     else if (IS_RULE(rule, "feidedec"))      { mm->rule = ZXID_MAP_RULE_FEIDEDEC; }
542     else if (IS_RULE(rule, "feideenc"))      { mm->rule = ZXID_MAP_RULE_FEIDEENC; }
543     else if (IS_RULE(rule, "unsb64-inf"))    { mm->rule = ZXID_MAP_RULE_UNSB64_INF; }
544     else if (IS_RULE(rule, "def-sb64"))      { mm->rule = ZXID_MAP_RULE_DEF_SB64; }
545     else if (IS_RULE(rule, "unsb64"))        { mm->rule = ZXID_MAP_RULE_UNSB64; }
546     else if (IS_RULE(rule, "sb64"))          { mm->rule = ZXID_MAP_RULE_SB64; }
547 
548     else if (IS_RULE(rule, "a7n"))           { mm->rule = ZXID_MAP_RULE_WRAP_A7N; }
549     else if (IS_RULE(rule, "a7n-feideenc"))  { mm->rule = ZXID_MAP_RULE_WRAP_A7N | ZXID_MAP_RULE_FEIDEENC; }
550     else if (IS_RULE(rule, "a7n-def-sb64"))  { mm->rule = ZXID_MAP_RULE_WRAP_A7N | ZXID_MAP_RULE_DEF_SB64; }
551     else if (IS_RULE(rule, "a7n-sb64"))      { mm->rule = ZXID_MAP_RULE_WRAP_A7N | ZXID_MAP_RULE_SB64; }
552 
553     else if (IS_RULE(rule, "x509"))          { mm->rule = ZXID_MAP_RULE_WRAP_X509; }
554     else if (IS_RULE(rule, "x509-feideenc")) { mm->rule = ZXID_MAP_RULE_WRAP_X509 | ZXID_MAP_RULE_FEIDEENC; }
555     else if (IS_RULE(rule, "x509-def-sb64")) { mm->rule = ZXID_MAP_RULE_WRAP_X509 | ZXID_MAP_RULE_DEF_SB64; }
556     else if (IS_RULE(rule, "x509-sb64"))     { mm->rule = ZXID_MAP_RULE_WRAP_X509 | ZXID_MAP_RULE_SB64; }
557 
558     else if (IS_RULE(rule, "file"))          { mm->rule = ZXID_MAP_RULE_WRAP_FILE; }
559     else if (IS_RULE(rule, "file-feideenc")) { mm->rule = ZXID_MAP_RULE_WRAP_FILE | ZXID_MAP_RULE_FEIDEENC; }
560     else if (IS_RULE(rule, "file-def-sb64")) { mm->rule = ZXID_MAP_RULE_WRAP_FILE | ZXID_MAP_RULE_DEF_SB64; }
561     else if (IS_RULE(rule, "file-sb64"))     { mm->rule = ZXID_MAP_RULE_WRAP_FILE | ZXID_MAP_RULE_SB64; }
562 
563     else {
564       ERR("Unknown map rule(%.*s) at col %d of (%s)", ((int)(b-rule)), rule, ((int)(rule-v)), v);
565       //ERR("sizeof(rename)=%d cmp=%d c(%c)", sizeof("rename"), memcmp(rule, "rename", sizeof("rename")-1), rule[sizeof("rename")]);
566     }
567 
568     COPYVAL(mm->ns,  ns,  A-1);
569     COPYVAL(mm->src, A,   rule-1);
570     COPYVAL(mm->dst, b,   ext-1);
571     COPYVAL(mm->ext, ext, p);
572 
573     DD("map ns(%s) src(%s) rule=%d dst(%s) ext(%s)", mm->ns, mm->src, mm->rule, mm->dst, mm->ext);
574     if (!*p || *p == '\n') break;
575     ++p;
576   }
577 
578   return map;
579 }
580 
581 /*() Parse unix_grp_az_map specification and add it to linked list
582  * srcns$A$rule$b$ext;src$A$rule$b$ext;...
583  * The list ends up being built in reverse order, which at runtime
584  * causes last stanzas to be evaluated first and first match is used.
585  * Thus you should place most specific rules last and most generic rules first.
586  * See also: zxid_find_map() and zxid_map_val()
587  */
588 
589 /* Called by:  zxid_init_conf x7, zxid_mk_usr_a7n_to_sp, zxid_parse_conf_raw x7, zxid_read_map */
zxid_load_unix_grp_az_map(zxid_conf * cf,struct zxid_map * map,char * v)590 struct zxid_map* zxid_load_unix_grp_az_map(zxid_conf* cf, struct zxid_map* map, char* v)
591 {
592   char* ns;
593   char* A;
594   char* val;
595   char* group;
596   char* ext;
597   char* p = v;
598   int len, n_grps, i;
599   struct zxid_map* mm;
600   struct group* grp;
601   gid_t* gids;
602 
603   DD("v(%s)", v);
604 
605   n_grps = getgroups(0,0);
606   gids = ZX_ALLOC(cf->ctx, (n_grps+1)*sizeof(gid_t));
607   getgroups(n_grps, gids);
608   gids[n_grps] = getegid();  /* getgroups(2) is not guaranteed to return egid */
609 
610   while (p && *p) {
611     ns = p;
612     p = strchr(p, '$');
613     if (!p) {
614       ERR("Malformed UNIX_GRP_AZ_MAP directive: source namespace missing at pos %d", ((int)(p-v)));
615       return map;
616     }
617 
618     A = ++p;
619     p = strchr(p, '$');
620     if (!p) {
621       ERR("Malformed UNIX_GRP_AZ_MAP directive: source attribute name missing at pos %d", ((int)(p-v)));
622       return map;
623     }
624 
625     val = ++p;
626     p = strchr(p, '$');
627     if (!p) {
628       ERR("Malformed UNIX_GRP_AZ_MAP directive: value missing at pos %d", ((int)(p-v)));
629       return map;
630     }
631 
632     group = ++p;
633     p = strchr(p, '$');
634     if (!p) {
635       ERR("Malformed UNIX_GRP_AZ_MAP directive: unix group name missing at pos %d", ((int)(p-v)));
636       return map;
637     }
638 
639     ext = ++p;
640     len = strcspn(p, ";\n");  /* Stanza ends in separator ; or end of string nul */
641     p = ext + len;
642 
643     mm = ZX_ZALLOC(cf->ctx, struct zxid_map);
644     mm->n = map;
645     map = mm;
646 
647     COPYVAL(mm->ns,  ns,  A-1);
648     COPYVAL(mm->src, A,   val-1);
649     COPYVAL(mm->dst, val, group-1);
650     COPYVAL(mm->ext, ext, p);
651 
652     *(ext-1) = 0;
653     grp = getgrnam(group);
654     *(ext-1) = '$';
655     if (grp) {
656       for (i = 0; i <= n_grps; ++i)
657 	if (grp->gr_gid == gids[i])
658 	  goto have_group;
659       ERR("UNIX_GRP_AZ_MAP: The current process does not belong to unix group name %s at pos %d (Config Error: see /etc/group for listing of groups)", group, ((int)(p-v)));
660       return map;
661     have_group:
662       mm->rule = grp->gr_gid;
663     } else {
664       ERR("UNIX_GRP_AZ_MAP: unix group name %s does not exist at pos %d (Config Error: see /etc/group for listing of groups)", group, ((int)(p-v)));
665       return map;
666     }
667 
668     DD("map ns(%s) A(%s) val(%s) gid=%d ext(%s)", mm->ns, mm->src, mm->dst, mm->rule, mm->ext);
669     if (!*p || *p == '\n') break;
670     ++p;
671   }
672 
673   ZX_FREE(cf->ctx, gids);
674   return map;
675 }
676 
677 /*() Reverse of zxid_load_map(). */
678 
679 /* Called by:  zxid_free_conf x7 */
zxid_free_map(struct zxid_conf * cf,struct zxid_map * map)680 void zxid_free_map(struct zxid_conf *cf, struct zxid_map *map)
681 {
682   while (map) {
683     struct zxid_map *next = map->n;
684     ZX_FREE(cf->ctx, map->ns);
685     ZX_FREE(cf->ctx, map->src);
686     ZX_FREE(cf->ctx, map->dst);
687     ZX_FREE(cf->ctx, map->ext);
688     ZX_FREE(cf->ctx, map);
689     map = next;
690   }
691 }
692 
693 /*() Parse comma separated strings (nul terminated) and add to linked list */
694 
695 /* Called by:  zxid_init_conf x4, zxid_load_obl_list, zxid_parse_conf_raw x4 */
zxid_load_cstr_list(zxid_conf * cf,struct zxid_cstr_list * l,char * p)696 struct zxid_cstr_list* zxid_load_cstr_list(zxid_conf* cf, struct zxid_cstr_list* l, char* p)
697 {
698   char* q;
699   struct zxid_cstr_list* cs;
700 
701   for (; p && *p; (void)(*p && ++p)) {
702     q = p;
703     p = strchr(p, ',');
704     if (!p)
705       p = q + strlen(q);
706     cs = ZX_ZALLOC(cf->ctx, struct zxid_cstr_list);
707     cs->n = l;
708     l = cs;
709     COPYVAL(cs->s, q, p);
710   }
711   return l;
712 }
713 
714 /*() Free list nodes and strings of zxid_cstr_list. */
715 
716 /* Called by:  zxid_free_conf x4, zxid_free_obl_list */
zxid_free_cstr_list(struct zxid_conf * cf,struct zxid_cstr_list * l)717 void zxid_free_cstr_list(struct zxid_conf* cf, struct zxid_cstr_list* l)
718 {
719   while (l) {
720     struct zxid_cstr_list* next = l->n;
721     ZX_FREE(cf->ctx, l->s);
722     ZX_FREE(cf->ctx, l);
723     l = next;
724   }
725 }
726 
727 // *** print obl_list
728 
729 /*() Parse and construct an obligations list with multiple values as cstr_list.
730  * The input string obl will be modified in place and used for long term reference,
731  * so do not pass a constant string or something that will be freed immadiately. */
732 
733 /* Called by:  zxid_eval_sol1, zxid_parse_conf_raw x2 */
zxid_load_obl_list(zxid_conf * cf,struct zxid_obl_list * ol,char * obl)734 struct zxid_obl_list* zxid_load_obl_list(zxid_conf* cf, struct zxid_obl_list* ol, char* obl)
735 {
736   struct zxid_obl_list* ob;
737   char *val, *name;
738   DD("obl(%s) len=%d", STRNULLCHK(obl), obl?strlen(obl):-1);
739   if (!obl)
740     return 0;
741   while (obl && *obl) {
742     obl = zxid_qs_nv_scan(obl, &name, &val, 1);
743     if (!name)
744       name = "NULL_NAM_ERRO";
745     if (!strcmp(name, "reset")) {
746       ol = 0;
747       continue;
748     }
749     ob = ZX_ZALLOC(cf->ctx, struct zxid_obl_list);
750     ob->name = name;
751     ob->vals = zxid_load_cstr_list(cf, 0, val);
752     ob->n = ol;
753     ol = ob;
754     D("ALLOC OBL(%s) %p", ol->name, ol);
755   }
756   return ol;
757 }
758 
759 /*() Free list nodes and strings of zxid_obl_list. */
760 
761 /* Called by:  zxid_eval_sol1 x2 */
zxid_free_obl_list(struct zxid_conf * cf,struct zxid_obl_list * ol)762 void zxid_free_obl_list(struct zxid_conf* cf, struct zxid_obl_list* ol)
763 {
764   //return; /* *** LEAK temporary fix 20130319 --Sampo */
765   while (ol) {
766     struct zxid_obl_list* next = ol->n;
767     zxid_free_cstr_list(cf, ol->vals);
768     /* ZX_FREE(cf->ctx, ol->name); BAD IDEA: the name comes from external static storage */
769     D("FREE OBL(%s) %p", ol->name, ol);
770     ZX_FREE(cf->ctx, ol);
771     ol = next;
772   }
773 }
774 
775 /*() Parse comma separated bus_urls and add to linked list */
776 
777 /* Called by:  zxid_init_conf, zxid_parse_conf_raw */
zxid_load_bus_url(zxid_conf * cf,struct zxid_bus_url * bu_root,char * p)778 struct zxid_bus_url* zxid_load_bus_url(zxid_conf* cf, struct zxid_bus_url* bu_root, char* p)
779 {
780   char* q;
781   struct zxid_bus_url* bu;
782 
783   for (; p && *p; (void)(*p && ++p)) {
784     q = p;
785     p = strchr(p, ',');
786     if (!p)
787       p = q + strlen(q);
788     bu = ZX_ZALLOC(cf->ctx, struct zxid_bus_url);
789     bu->n = bu_root;
790     bu_root = bu;
791     COPYVAL(bu->s, q, p);
792     COPYVAL(bu->eid, q, p);  /* *** convention is that contact URL and eid are the same?!? */
793   }
794   return bu_root;
795 }
796 
797 /*() Reverse of zxid_load_bus_url(). */
798 
799 /* Called by:  zxid_free_conf */
zxid_free_bus_url(struct zxid_conf * cf,struct zxid_bus_url * bu)800 void zxid_free_bus_url(struct zxid_conf* cf, struct zxid_bus_url* bu)
801 {
802   struct zxid_bus_url* next;
803   while (bu) {
804     next = bu->n;
805     ZX_FREE(cf->ctx, bu->s);
806     ZX_FREE(cf->ctx, bu->eid);
807     ZX_FREE(cf->ctx, bu);
808     bu = next;
809   }
810 }
811 
812 /*() Parse ATTRSRC specification and add it to linked list
813  *   namespace$A,B$weight$accessparamURL$AAPMLref$otherLim$ext;namespace$A,B$weight$accessparamURL$AAPMLref$otherLim$ext;...
814  */
815 
816 /* Called by:  zxid_init_conf, zxid_parse_conf_raw */
zxid_load_atsrc(zxid_conf * cf,struct zxid_atsrc * atsrc,char * v)817 struct zxid_atsrc* zxid_load_atsrc(zxid_conf* cf, struct zxid_atsrc* atsrc, char* v)
818 {
819   char* ns;
820   char* attrs;
821   char* weight;
822   char* url;
823   char* aapml;
824   char* otherlim;
825   char* ext;
826   char* p = v;
827   char* a;
828   int len;
829   struct zxid_atsrc* as;
830 
831   while (p && *p) {
832     ns = p;
833     p = strchr(p, '$');
834     if (!p) {
835       ERR("Malformed ATSRC directive: namespace missing at pos %d", ((int)(p-v)));
836       return atsrc;
837     }
838 
839     attrs = ++p;
840     p = strchr(p, '$');
841     if (!p) {
842       ERR("Malformed ATSRC directive: attribute list missing at pos %d", ((int)(p-v)));
843       return atsrc;
844     }
845 
846     weight = ++p;
847     p = strchr(p, '$');
848     if (!p) {
849       ERR("Malformed ATSRC directive: weight missing at pos %d", ((int)(p-v)));
850       return atsrc;
851     }
852 
853     url = ++p;
854     p = strchr(p, '$');
855     if (!p) {
856       ERR("Malformed ATSRC directive: url missing at pos %d", ((int)(p-v)));
857       return atsrc;
858     }
859 
860     aapml = ++p;
861     p = strchr(p, '$');
862     if (!p) {
863       ERR("Malformed ATSRC directive: aapml ref missing at pos %d", ((int)(p-v)));
864       return atsrc;
865     }
866 
867     otherlim = ++p;
868     p = strchr(p, '$');
869     if (!p) {
870       ERR("Malformed ATSRC directive: otherlim missing at pos %d", ((int)(p-v)));
871       return atsrc;
872     }
873 
874     ext = ++p;
875     p = strchr(p, ';');  /* Stanza ends in separator ; or end of string nul */
876     if (!p)
877       p = ext + strlen(ext);
878 
879     if (IS_RULE(url, "reset")) {
880       INFO("Reset atsrc %p", atsrc);
881       zxid_free_atsrc(cf, atsrc);
882       atsrc = NULL;
883       if (!*p) break;
884       ++p;
885       continue;
886     }
887 
888     as = ZX_ZALLOC(cf->ctx, struct zxid_atsrc);
889     as->n = atsrc;
890     atsrc = as;
891 
892     COPYVAL(as->ns,       ns,        attrs-1);
893     COPYVAL(as->weight,   weight,    url-1);
894     COPYVAL(as->url,      url,       aapml-1);
895     COPYVAL(as->aapml,    aapml,     otherlim-1);
896     COPYVAL(as->otherlim, otherlim,  ext-1);
897     COPYVAL(as->ext,      ext,       p);
898 
899     D("atsrc ns(%s) attrs(%.*s) weight(%s) url(%s) aapml(%s) otherlim(%s) ext(%s)", as->ns, ((int)(weight-attrs-1)), attrs, as->weight, as->url, as->aapml, as->otherlim, as->ext);
900 
901     for (a = attrs; ; a += len+1) {
902       len = strcspn(a, ",$");
903       as->at = zxid_new_at(cf, as->at, len, a, 0,0, "atsrc");
904       if (a[len] == '$')
905 	break;
906     }
907     if (!*p) break;
908     ++p;
909   }
910 
911   return atsrc;
912 }
913 
914 /*() Reverse of zxid_load_atsrc(). */
915 
916 /* Called by:  zxid_free_conf, zxid_load_atsrc */
zxid_free_atsrc(struct zxid_conf * cf,struct zxid_atsrc * src)917 void zxid_free_atsrc(struct zxid_conf *cf, struct zxid_atsrc *src)
918 {
919   while (src) {
920     struct zxid_atsrc *next = src->n;
921     zxid_free_at(cf, src->at);
922     ZX_FREE(cf->ctx, src->ns);
923     ZX_FREE(cf->ctx, src->weight);
924     ZX_FREE(cf->ctx, src->url);
925     ZX_FREE(cf->ctx, src->aapml);
926     ZX_FREE(cf->ctx, src->otherlim);
927     ZX_FREE(cf->ctx, src->ext);
928     ZX_FREE(cf->ctx, src);
929     src = next;
930   }
931 }
932 
933 /*() Check whether attribute is in a (needed or wanted) list. Just a linear
934  * scan as it is simple and good enough for handful of attributes. */
935 
936 /* Called by:  zxid_add_at_vals x2, zxid_add_attr_to_ses x2 */
zxid_is_needed(struct zxid_need * need,const char * name)937 struct zxid_need* zxid_is_needed(struct zxid_need* need, const char* name)
938 {
939   struct zxid_attr* at;
940   if (!name || !*name)
941     return 0;
942   for (; need; need = need->n)
943     for (at = need->at; at; at = at->n)
944       if (at->name[0] == '*' && !at->name[1]   /* Wild card */
945 	  || !strcmp(at->name, name)) /* Match! */
946 	return need;
947   return 0;
948 }
949 
950 /*() Check whether attribute is in a (needed or wanted) list. Just a linear
951  * scan as it is simple and good enough for handful of attributes.
952  * The list ends up being built in reverse order, which at runtime
953  * causes last stanzas to be evaluated first and first match is used.
954  * Thus you should place most specific rules last and most generic rules first.
955  * See also: zxid_load_map() and zxid_map_val() */
956 
957 /* Called by:  pool2apache, zxid_add_at_vals, zxid_add_attr_to_ses, zxid_add_mapped_attr x2, zxid_pepmap_extract, zxid_pool2env, zxid_pool_to_json x2, zxid_pool_to_ldif x2, zxid_pool_to_qs x2 */
zxid_find_map(struct zxid_map * map,const char * name)958 struct zxid_map* zxid_find_map(struct zxid_map* map, const char* name)
959 {
960   if (!name || !*name)
961     return 0;
962   for (; map; map = map->n) {
963     DD("HERE src(%s)", STRNULLCHKNULL(map->src));
964     if (map->src[0] == '*' && !map->src[1] /* Wild card (only sensible for del and data xform) */
965 	|| !strcmp(map->src, name)) /* Match! */
966       return map;
967   }
968   return 0;
969 }
970 
971 /*() Check whether name is in the list. Used for Local PDP white and black lists. */
972 
973 /* Called by:  zxid_eval_sol1, zxid_localpdp x4 */
zxid_find_cstr_list(struct zxid_cstr_list * cs,const char * name)974 struct zxid_cstr_list* zxid_find_cstr_list(struct zxid_cstr_list* cs, const char* name)
975 {
976   if (!name || !*name)
977     return 0;
978   for (; cs; cs = cs->n)
979     if (cs->s[0] == '*' && !cs->s[1] /* Wild card */
980 	|| !strcmp(cs->s, name))     /* Match! */
981       return cs;
982   return 0;
983 }
984 
985 /*() Chech whether any of multivalues of an attribute is on the list. */
986 
zxid_find_at_multival_on_cstr_list(struct zxid_cstr_list * cs,struct zxid_attr * at)987 struct zxid_cstr_list* zxid_find_at_multival_on_cstr_list(struct zxid_cstr_list* cs, struct zxid_attr* at)
988 {
989   struct zxid_cstr_list* ret;
990   for (; at; at = at->nv)
991     if ((ret = zxid_find_cstr_list(cs, at->val)))
992       return ret;
993   return 0;
994 }
995 
996 /*() Check whether name is in the obligations list. */
997 
998 /* Called by:  zxid_eval_sol1 */
zxid_find_obl_list(struct zxid_obl_list * obl,const char * name)999 struct zxid_obl_list* zxid_find_obl_list(struct zxid_obl_list* obl, const char* name)
1000 {
1001   if (!name || !*name)
1002     return 0;
1003   for (; obl; obl = obl->n)
1004     if (obl->name[0] == '*' && !obl->name[1] /* Wild card */
1005 	|| !strcmp(obl->name, name))     /* Match! */
1006       return obl;
1007   return 0;
1008 }
1009 
1010 /*() Check whether attribute is in pool. */
1011 
1012 /* Called by:  zxid_localpdp x2 */
zxid_find_at(struct zxid_attr * pool,const char * name)1013 struct zxid_attr* zxid_find_at(struct zxid_attr* pool, const char* name)
1014 {
1015   if (!name || !*name)
1016     return 0;
1017   for (; pool; pool = pool->n)
1018     if (!strcmp(pool->name, name))     /* Match! */
1019       return pool;
1020   return 0;
1021 }
1022 
1023 /*() Check that the user, who is logged into session, maps to group.
1024  * This is used by UNIX_GRP_AZ_MAP to check that filesystem
1025  * permissions allow user to access a file (existence of g+r and
1026  * user mapping to the correct group).
1027  *
1028  * return:: 0=deny, 1=permit */
1029 
zxid_unix_grp_az_check(zxid_conf * cf,zxid_ses * ses,int gid)1030 int zxid_unix_grp_az_check(zxid_conf* cf, zxid_ses* ses, int gid)
1031 {
1032   struct zxid_map* grp_map = 0;
1033   struct zxid_attr* at = 0;
1034 
1035   if (!cf || !ses) {
1036     ERR("missing argument cf=%p", cf);
1037     return 0;
1038   }
1039   if (!ses->nid || !ses->nid[0]) {
1040     INFO("user not logged in ses->nid=%p", ses->nid);
1041     return 0;
1042   }
1043   for (grp_map = cf->unix_grp_az_map; grp_map; grp_map = grp_map->n) {
1044     if (grp_map->rule != gid)
1045       continue;
1046 
1047     /* If affiliation filter is specified, check it. */
1048     if (grp_map->ns && strcmp(grp_map->ns, "") /* none of the wild card cases */
1049 	&& strcmp(grp_map->ns, "*") && strcmp(grp_map->ns, "**")) {
1050       at = zxid_find_at(ses->at, "affid");
1051       if (!at || !zx_match(grp_map->ns, at->val /*ses->nameid->NameQualifier*/))
1052 	continue;
1053     }
1054 
1055     /* If attribute filter is specified, check it. */
1056     if (grp_map->src && strcmp(grp_map->src, "") /* none of the wild card cases */
1057 	&& strcmp(grp_map->src, "*") && strcmp(grp_map->src, "**")) {
1058       at = zxid_find_at(ses->at, grp_map->src);
1059       if (!at || !zx_match(grp_map->dst, at->val /*ses->nameid->NameQualifier*/))
1060 	continue;
1061     }
1062     D("%s=%s maps to gid=%d", STRNULLCHKD(grp_map?grp_map->src:0), STRNULLCHKD(at?at->val:0), gid);
1063     return 1;
1064   }
1065   INFO("user does not map to gid=%d", gid);
1066   return 0;
1067 }
1068 
1069 /*() Given URL, return a newly allocated string corresponding
1070  * to the domain name part of the URL. Used to grab fedusername_suffix
1071  * from the url config option. */
1072 
1073 /* Called by:  zxid_parse_conf_raw */
zxid_grab_domain_name(zxid_conf * cf,const char * url)1074 char* zxid_grab_domain_name(zxid_conf* cf, const char* url)
1075 {
1076   char* dom;
1077   char* p;
1078   int len;
1079   if (!url || !*url)
1080     return 0;
1081   dom = strchr(url, ':');
1082   if (!dom || dom[1] != '/' || dom[2] != '/')
1083     return 0;
1084   dom += 3;
1085   /* After shipping https:// scan for domain name allowable characters. */
1086   len = strspn(dom, ".abcdefghijklmnopqrstuvwxyz0123456789-ABCDEFGHIJKLMNOPQRSTUVWXYZ");
1087   p = ZX_ALLOC(cf->ctx, len+1);
1088   memcpy(p, dom, len);
1089   p[len] = 0;
1090   return p;
1091 }
1092 
1093 struct zx_lock zxid_ent_cache_mx;
1094 int zxid_ent_cache_mx_init = 0;
1095 
1096 /*(i) Initialize configuration object, which must have already been
1097  * allocated, to factory defaults (i.e. compiled in defaults, see
1098  * zxidconf.h). Config file is not read.
1099  *
1100  * cf:: Pointer to previously allocated configuration object
1101  * path:: Since this configuration option is so fundamental, it can
1102  *     be supplied directly as argument. However, unlike zxid_new_conf()
1103  *     this does not cause the config file to be read.
1104  * return:: 0 on success (currently, 2008, this function can not
1105  *     fail - thus it is common to ignore the return value)
1106  *
1107  * N.B. This function does NOT initialize the ZX context object although
1108  * it is a field of this object. You MUST separately initialize
1109  * the ZX context object, e.g. using zx_reset_ctx() or zx_init_ctx(),
1110  * before you can use ZXID configuration object in any memory allocation prone
1111  * activity (which is nearly every function in this API).
1112  */
1113 
1114 /* Called by:  zxid_conf_to_cf_len, zxid_init_conf_ctx */
zxid_init_conf(zxid_conf * cf,const char * zxid_path)1115 int zxid_init_conf(zxid_conf* cf, const char* zxid_path)
1116 {
1117   DD("Initconf with path(%s)", zxid_path);
1118   cf->magic = ZXID_CONF_MAGIC;
1119   cf->cpath_len = zxid_path ? strlen(zxid_path) : 0;
1120   cf->cpath = ZX_ALLOC(cf->ctx, cf->cpath_len+1);
1121   memcpy(cf->cpath, zxid_path, cf->cpath_len);
1122   cf->cpath[cf->cpath_len] = 0;
1123   cf->nice_name     = ZXID_NICE_NAME;
1124   cf->button_url    = ZXID_BUTTON_URL;
1125   cf->pref_button_size = ZXID_PREF_BUTTON_SIZE;
1126   cf->org_name      = ZXID_ORG_NAME;
1127   cf->locality      = ZXID_LOCALITY;
1128   cf->state         = ZXID_STATE;
1129   cf->country       = ZXID_COUNTRY;
1130   cf->contact_org   = ZXID_CONTACT_ORG;
1131   cf->contact_name  = ZXID_CONTACT_NAME;
1132   cf->contact_email = ZXID_CONTACT_EMAIL;
1133   cf->contact_tel   = ZXID_CONTACT_TEL;
1134   /* NB: Typically allocated by zxid_grab_domain_name(). */
1135   COPYVAL(cf->fedusername_suffix, ZXID_FEDUSERNAME_SUFFIX,
1136 	  ZXID_FEDUSERNAME_SUFFIX + strlen(ZXID_FEDUSERNAME_SUFFIX));
1137   cf->burl = ZXID_BURL;
1138   cf->non_standard_entityid = ZXID_NON_STANDARD_ENTITYID;
1139   cf->redirect_hack_imposed_url = ZXID_REDIRECT_HACK_IMPOSED_URL;
1140   cf->redirect_hack_zxid_url = ZXID_REDIRECT_HACK_ZXID_URL;
1141   cf->defaultqs     = ZXID_DEFAULTQS;
1142   cf->wsp_pat       = ZXID_WSP_PAT;
1143   cf->uma_pat       = ZXID_UMA_PAT;
1144   cf->sso_pat       = ZXID_SSO_PAT;
1145   cf->cdc_url       = ZXID_CDC_URL;
1146   cf->cdc_choice    = ZXID_CDC_CHOICE;
1147   cf->authn_req_sign = ZXID_AUTHN_REQ_SIGN;
1148   cf->want_sso_a7n_signed = ZXID_WANT_SSO_A7N_SIGNED;
1149   cf->want_authn_req_signed = ZXID_WANT_AUTHN_REQ_SIGNED;
1150   cf->sso_soap_sign = ZXID_SSO_SOAP_SIGN;
1151   cf->sso_soap_resp_sign = ZXID_SSO_SOAP_RESP_SIGN;
1152   cf->sso_sign      = ZXID_SSO_SIGN;
1153   cf->wsc_sign      = ZXID_WSC_SIGN;
1154   cf->wsp_sign      = ZXID_WSP_SIGN;
1155   cf->oaz_jwt_sigenc_alg = ZXID_OAZ_JWT_SIGENC_ALG;
1156   cf->wspcgicmd     = ZXID_WSPCGICMD;
1157   cf->nameid_enc    = ZXID_NAMEID_ENC;
1158   cf->post_a7n_enc  = ZXID_POST_A7N_ENC;
1159   cf->canon_inopt   = ZXID_CANON_INOPT;
1160   if (cf->ctx) cf->ctx->canon_inopt = cf->canon_inopt;
1161   cf->enc_tail_opt  = ZXID_ENC_TAIL_OPT;
1162   cf->enckey_opt    = ZXID_ENCKEY_OPT;
1163   cf->valid_opt     = ZXID_VALID_OPT;
1164   cf->idpatopt      = ZXID_IDPATOPT;
1165   cf->idp_list_meth = ZXID_IDP_LIST_METH;
1166   cf->di_allow_create = ZXID_DI_ALLOW_CREATE;
1167   cf->di_nid_fmt    = ZXID_DI_NID_FMT;
1168   cf->di_a7n_enc    = ZXID_DI_A7N_ENC;
1169   cf->bootstrap_level = ZXID_BOOTSTRAP_LEVEL;
1170   cf->show_conf     = ZXID_SHOW_CONF;
1171 #ifdef USE_OPENSSL
1172   if (zxid_path) {
1173 #if 0
1174     /* DO NOT ENABLE! The certificates and keys are read "just in time" if and when needed. */
1175     cf->sign_cert = zxid_read_cert(cf, "sign-nopw-cert.pem");
1176     cf->sign_pkey = zxid_read_private_key(cf, "sign-nopw-cert.pem");
1177     cf->enc_cert = zxid_read_cert(cf, "enc-nopw-cert.pem");
1178     cf->enc_pkey = zxid_read_private_key(cf, "enc-nopw-cert.pem");
1179     cf->log_sign_pkey = zxid_read_private_key(cf, "logsign-nopw-cert.pem");
1180     cf->log_enc_cert = zxid_read_cert(cf, "logenc-nopw-cert.pem");
1181     zxid_sha1_file(cf, "pem/logenc.key", cf->log_symkey);
1182 #endif
1183   }
1184 #else
1185   ERR("This copy of zxid was compiled to NOT use OpenSSL. Reading certificate and private key is not supported. Signing and signature verification are not supported either. Add -DUSE_OPENSSL and recompile. %d", 0);
1186 #endif
1187   cf->md_fetch = ZXID_MD_FETCH;
1188   cf->md_populate_cache = ZXID_MD_POPULATE_CACHE;
1189   cf->md_cache_first    = ZXID_MD_CACHE_FIRST;
1190   cf->md_cache_last     = ZXID_MD_CACHE_LAST;
1191   cf->md_authority      = ZXID_MD_AUTHORITY;
1192   cf->load_cot_cache    = ZXID_LOAD_COT_CACHE;
1193   cf->auto_cert         = ZXID_AUTO_CERT;
1194   cf->ses_arch_dir      = ZXID_SES_ARCH_DIR;
1195   cf->ses_cookie_name   = ZXID_SES_COOKIE_NAME;
1196   cf->ptm_cookie_name   = ZXID_PTM_COOKIE_NAME;
1197   cf->user_local        = ZXID_USER_LOCAL;
1198   cf->idp_ena           = ZXID_IDP_ENA;
1199   cf->idp_pxy_ena       = ZXID_IDP_PXY_ENA;
1200   cf->imps_ena          = ZXID_IMPS_ENA;
1201   cf->as_ena            = ZXID_AS_ENA;
1202   cf->md_authority_ena  = ZXID_MD_AUTHORITY_ENA;
1203   cf->backwards_compat_ena  = ZXID_BACKWARDS_COMPAT_ENA;
1204   cf->pdp_ena           = ZXID_PDP_ENA;
1205   cf->cpn_ena           = ZXID_CPN_ENA;
1206   cf->az_opt            = ZXID_AZ_OPT;
1207   cf->az_fail_mode      = ZXID_AZ_FAIL_MODE;
1208 
1209   cf->loguser = ZXID_LOGUSER;
1210   cf->log_level = ZXLOG_LEVEL;
1211   cf->log_err = ZXLOG_ERR;      /* Log enables and signing and encryption flags (if USE_OPENSSL) */
1212   cf->log_act = ZXLOG_ACT;
1213   cf->log_issue_a7n  = ZXLOG_ISSUE_A7N;
1214   cf->log_issue_msg  = ZXLOG_ISSUE_MSG;
1215   cf->log_rely_a7n   = ZXLOG_RELY_A7N;
1216   cf->log_rely_msg   = ZXLOG_RELY_MSG;
1217   cf->log_err_in_act = ZXLOG_ERR_IN_ACT;
1218   cf->log_act_in_err = ZXLOG_ACT_IN_ERR;
1219   cf->log_sigfail_is_err = ZXLOG_SIGFAIL_IS_ERR;
1220   cf->bus_rcpt       = ZXBUS_RCPT;
1221   cf->bus_url        = zxid_load_bus_url(cf, 0, ZXID_BUS_URL);
1222   cf->bus_pw         = ZXID_BUS_PW;
1223 
1224   cf->sig_fatal      = ZXID_SIG_FATAL;
1225   cf->nosig_fatal    = ZXID_NOSIG_FATAL;
1226   cf->msg_sig_ok     = ZXID_MSG_SIG_OK;
1227   cf->timeout_fatal  = ZXID_TIMEOUT_FATAL;
1228   cf->audience_fatal = ZXID_AUDIENCE_FATAL;
1229   cf->dup_a7n_fatal  = ZXID_DUP_A7N_FATAL;
1230   cf->dup_msg_fatal  = ZXID_DUP_MSG_FATAL;
1231   cf->relto_fatal    = ZXID_RELTO_FATAL;
1232   cf->wsp_nosig_fatal = ZXID_WSP_NOSIG_FATAL;
1233   cf->notimestamp_fatal = ZXID_NOTIMESTAMP_FATAL;
1234   cf->anon_ok        = ZXID_ANON_OK;
1235   cf->optional_login_pat = ZXID_OPTIONAL_LOGIN_PAT;
1236   cf->required_authnctx = ZXID_REQUIRED_AUTHNCTX;	/* NB: NULL. */
1237   cf->issue_authnctx = zxid_load_cstr_list(cf, 0, ZXID_ISSUE_AUTHNCTX);
1238   cf->idp_pref_acs_binding = ZXID_IDP_PREF_ACS_BINDING;
1239   cf->mandatory_attr = ZXID_MANDATORY_ATTR;
1240 
1241   cf->before_slop    = ZXID_BEFORE_SLOP;
1242   cf->after_slop     = ZXID_AFTER_SLOP;
1243   cf->timeskew       = ZXID_TIMESKEW;
1244   cf->a7nttl         = ZXID_A7NTTL;
1245   cf->pdp_url        = ZXID_PDP_URL;
1246   cf->pdp_call_url   = ZXID_PDP_CALL_URL;
1247   cf->xasp_vers      = ZXID_XASP_VERS;
1248   cf->trustpdp_url   = ZXID_TRUSTPDP_URL;
1249 
1250   cf->need           = zxid_load_need(cf, 0, ZXID_NEED);
1251   cf->want           = zxid_load_need(cf, 0, ZXID_WANT);
1252   cf->attrsrc        = zxid_load_atsrc(cf, 0, ZXID_ATTRSRC);
1253   cf->inmap          = zxid_load_map(cf, 0, ZXID_INMAP);
1254   cf->outmap         = zxid_load_map(cf, 0, ZXID_OUTMAP);
1255   cf->pepmap         = zxid_load_map(cf, 0, ZXID_PEPMAP);
1256   cf->pepmap_rqout   = zxid_load_map(cf, 0, ZXID_PEPMAP_RQOUT);
1257   cf->pepmap_rqin    = zxid_load_map(cf, 0, ZXID_PEPMAP_RQIN);
1258   cf->pepmap_rsout   = zxid_load_map(cf, 0, ZXID_PEPMAP_RSOUT);
1259   cf->pepmap_rsin    = zxid_load_map(cf, 0, ZXID_PEPMAP_RSIN);
1260 
1261   cf->localpdp_role_permit    = zxid_load_cstr_list(cf, 0, ZXID_LOCALPDP_ROLE_PERMIT);
1262   cf->localpdp_role_deny      = zxid_load_cstr_list(cf, 0, ZXID_LOCALPDP_ROLE_DENY);
1263   cf->localpdp_idpnid_permit  = zxid_load_cstr_list(cf, 0, ZXID_LOCALPDP_IDPNID_PERMIT);
1264   cf->localpdp_idpnid_deny    = zxid_load_cstr_list(cf, 0, ZXID_LOCALPDP_IDPNID_DENY);
1265 
1266   cf->wsc_localpdp_obl_pledge = ZXID_WSC_LOCALPDP_OBL_PLEDGE;
1267   cf->wsp_localpdp_obl_req    = ZXID_WSP_LOCALPDP_OBL_REQ;
1268   cf->wsp_localpdp_obl_emit   = ZXID_WSP_LOCALPDP_OBL_EMIT;
1269   cf->wsc_localpdp_obl_accept = ZXID_WSC_LOCALPDP_OBL_ACCEPT;
1270 
1271   cf->unix_grp_az_map   = zxid_load_unix_grp_az_map(cf, 0, ZXID_UNIX_GRP_AZ_MAP);
1272 
1273   cf->redir_to_content  = ZXID_REDIR_TO_CONTENT;
1274   cf->remote_user_ena   = ZXID_REMOTE_USER_ENA;
1275   cf->max_soap_retry    = ZXID_MAX_SOAP_RETRY;
1276   cf->mod_saml_attr_prefix  = ZXID_MOD_SAML_ATTR_PREFIX;
1277   cf->wsc_soap_content_type = ZXID_WSC_SOAP_CONTENT_TYPE;
1278   cf->wsc_to_hdr        = ZXID_WSC_TO_HDR;
1279   cf->wsc_replyto_hdr   = ZXID_WSC_REPLYTO_HDR;
1280   cf->wsc_action_hdr    = ZXID_WSC_ACTION_HDR;
1281   cf->soap_action_hdr   = ZXID_SOAP_ACTION_HDR;
1282 
1283   cf->bare_url_entityid = ZXID_BARE_URL_ENTITYID;
1284   cf->show_tech         = ZXID_SHOW_TECH;
1285   cf->wd                = ZXID_WD;
1286   cf->idp_sel_page      = ZXID_IDP_SEL_PAGE;
1287   cf->idp_sel_templ_file= ZXID_IDP_SEL_TEMPL_FILE;
1288   cf->idp_sel_templ     = ZXID_IDP_SEL_TEMPL;
1289 #if 0
1290   cf->idp_sel_start     = ZXID_IDP_SEL_START;
1291   cf->idp_sel_new_idp   = ZXID_IDP_SEL_NEW_IDP;
1292   cf->idp_sel_our_eid   = ZXID_IDP_SEL_OUR_EID;
1293   cf->idp_sel_tech_user = ZXID_IDP_SEL_TECH_USER;
1294   cf->idp_sel_tech_site = ZXID_IDP_SEL_TECH_SITE;
1295   cf->idp_sel_footer    = ZXID_IDP_SEL_FOOTER;
1296   cf->idp_sel_end       = ZXID_IDP_SEL_END;
1297 #endif
1298 
1299   cf->an_page           = ZXID_AN_PAGE;
1300   cf->an_templ_file     = ZXID_AN_TEMPL_FILE;
1301   cf->an_templ          = ZXID_AN_TEMPL;
1302 
1303   cf->post_templ_file   = ZXID_POST_TEMPL_FILE;
1304   cf->post_templ        = ZXID_POST_TEMPL;
1305 
1306   cf->err_page          = ZXID_ERR_PAGE;
1307   cf->err_templ_file    = ZXID_ERR_TEMPL_FILE;
1308   cf->err_templ         = ZXID_ERR_TEMPL;
1309 
1310   cf->new_user_page     = ZXID_NEW_USER_PAGE;
1311   cf->recover_passwd    = ZXID_RECOVER_PASSWD;
1312   cf->atsel_page        = ZXID_ATSEL_PAGE;
1313 
1314   cf->mgmt_start        = ZXID_MGMT_START;
1315   cf->mgmt_logout       = ZXID_MGMT_LOGOUT;
1316   cf->mgmt_defed        = ZXID_MGMT_DEFED;
1317   cf->mgmt_footer       = ZXID_MGMT_FOOTER;
1318   cf->mgmt_end          = ZXID_MGMT_END;
1319 
1320   cf->xmldsig_sig_meth  = ZXID_XMLDSIG_SIG_METH;
1321   cf->xmldsig_digest_algo = ZXID_XMLDSIG_DIGEST_ALGO;
1322   cf->samlsig_digest_algo = ZXID_SAMLSIG_DIGEST_ALGO;
1323   cf->blobsig_digest_algo = ZXID_BLOBSIG_DIGEST_ALGO;
1324 
1325   LOCK_INIT(cf->mx);
1326   LOCK_INIT(cf->curl_mx);
1327   if (!zxid_ent_cache_mx_init) {
1328     LOCK_INIT(zxid_ent_cache_mx);
1329     zxid_ent_cache_mx_init = 1;
1330   }
1331 
1332 #if 1
1333   DD("path(%.*s) cf->magic=%x", cf->cpath_len, cf->cpath, cf->magic);
1334 #else
1335   fprintf(stderr, "t %9s:%-3d %-16s %s d " "path(%.*s) cf->magic=%x" "\n",
1336 	  __FILE__, __LINE__, __FUNCTION__, ERRMAC_INSTANCE, cf->cpath_len, cf->cpath, cf->magic);
1337   fflush(stderr);
1338 #endif
1339   return 0;
1340 }
1341 
1342 /*() Reverse of zxid_init_conf() and zxid_parse_conf_raw(). */
1343 
1344 /* Called by: */
zxid_free_conf(zxid_conf * cf)1345 void zxid_free_conf(zxid_conf *cf)
1346 {
1347   zxid_free_need(cf, cf->need);
1348   zxid_free_need(cf, cf->want);
1349   zxid_free_atsrc(cf, cf->attrsrc);
1350   zxid_free_bus_url(cf, cf->bus_url);
1351   zxid_free_map(cf, cf->inmap);
1352   zxid_free_map(cf, cf->outmap);
1353   zxid_free_map(cf, cf->pepmap);
1354   zxid_free_map(cf, cf->pepmap_rqout);
1355   zxid_free_map(cf, cf->pepmap_rqin);
1356   zxid_free_map(cf, cf->pepmap_rsout);
1357   zxid_free_map(cf, cf->pepmap_rsin);
1358   zxid_free_cstr_list(cf, cf->localpdp_role_permit);
1359   zxid_free_cstr_list(cf, cf->localpdp_role_deny);
1360   zxid_free_cstr_list(cf, cf->localpdp_idpnid_permit);
1361   zxid_free_cstr_list(cf, cf->localpdp_idpnid_deny);
1362   zxid_free_cstr_list(cf, cf->issue_authnctx);
1363   zxid_free_map(cf, cf->unix_grp_az_map);
1364   if (cf->required_authnctx) {
1365     ZX_FREE(cf->ctx, cf->required_authnctx);
1366   }
1367   if (cf->fedusername_suffix) {
1368     ZX_FREE(cf->ctx, cf->fedusername_suffix);
1369   }
1370   if (cf->cpath) {
1371     ZX_FREE(cf->ctx, cf->cpath);
1372   }
1373 }
1374 
1375 /*() Reset the doubly linked seen list and unknown_ns list to empty.
1376  * This is "light" version of zx_reset_ctx() that can be called
1377  * safely from inside lock. */
1378 
1379 /* Called by:  sig_validate, zx_prepare_dec_ctx, zx_reset_ctx, zxid_sp_sso_finalize */
zx_reset_ns_ctx(struct zx_ctx * ctx)1380 void zx_reset_ns_ctx(struct zx_ctx* ctx)
1381 {
1382   ctx->guard_seen_n.seen_n = &ctx->guard_seen_p;
1383   ctx->guard_seen_p.seen_p = &ctx->guard_seen_n;
1384   ctx->unknown_ns = 0;
1385 }
1386 
1387 /*() Reset the seen doubly linked list to empty and initialize memory
1388  * allocation related function pointers to system malloc(3). Without
1389  * such initialization, any memory allocation activity as well as
1390  * any XML parsing activity is doomed to segmentation fault. */
1391 
1392 /* Called by:  dirconf, main x3, zx_init_ctx, zxid_az, zxid_az_base, zxid_simple_len */
zx_reset_ctx(struct zx_ctx * ctx)1393 void zx_reset_ctx(struct zx_ctx* ctx)
1394 {
1395   ZERO(ctx, sizeof(struct zx_ctx));
1396   LOCK_INIT(ctx->mx);
1397   ctx->malloc_func = &malloc;
1398   ctx->realloc_func = &realloc;
1399   ctx->free_func = &free;
1400   zx_reset_ns_ctx(ctx);
1401 }
1402 
1403 /*() Allocate new ZX object and initialize it in standard
1404  * way, i.e. use malloc(3) for memory allocation. */
1405 
1406 /* Called by:  zxid_conf_to_cf_len, zxid_init_conf_ctx */
zx_init_ctx()1407 struct zx_ctx* zx_init_ctx()
1408 {
1409   struct zx_ctx* ctx;
1410   ctx = malloc(sizeof(struct zx_ctx));
1411   D("malloc %p size=%d", ctx, (int)sizeof(struct zx_ctx));
1412   if (!ctx) {
1413     ERR("out-of-memory in ctx alloc sizeof=%d", (int)sizeof(struct zx_ctx));
1414     return 0;
1415   }
1416   zx_reset_ctx(ctx);
1417   return ctx;
1418 }
1419 
1420 /*() Reverse of zx_init_ctx().
1421  * N.B. As of now (20111210) does not free the dependency structures. This
1422  * may be added in future. */
1423 
1424 /* Called by: */
zx_free_ctx(struct zx_ctx * ctx)1425 void zx_free_ctx(struct zx_ctx* ctx)
1426 {
1427   free(ctx);
1428 }
1429 
1430 /*() Minimal initialization of
1431  * the context is performed. Certificate and key operations as well as
1432  * CURL initialization are omitted. However the zx_ctx is installed so
1433  * that memory allocation against the context should work.
1434  * Supplying zxid_path merely initializes the PATH config option,
1435  * but does not cause configuration file to be read.
1436  *
1437  * Just initializes the config object to factory defaults (see zxidconf.h).
1438  * Previous content of the config object is lost. */
1439 
1440 /* Called by:  zxid_conf_to_cf_len, zxid_new_conf */
zxid_init_conf_ctx(zxid_conf * cf,const char * zxid_path)1441 zxid_conf* zxid_init_conf_ctx(zxid_conf* cf, const char* zxid_path)
1442 {
1443 #if 0
1444   fprintf(stderr, "Waiting 60 secs for gdb attach...\n");
1445   sleep(60);
1446 #endif
1447   cf->ctx = zx_init_ctx();
1448   if (!cf->ctx)
1449     return 0;
1450   zxid_init_conf(cf, zxid_path);
1451 #ifdef USE_CURL
1452   if (zxid_path) {
1453     cf->curl = curl_easy_init();
1454     if (!cf->curl) {
1455       ERR("Failed to initialize libcurl %d",0);
1456       exit(2);
1457     }
1458   }
1459 #endif
1460   return cf;
1461 }
1462 
1463 /*() Allocate conf object and initialize it with default config (config file is not read).
1464  * See zxid_new_conf_to_cf() for a more complete solution.
1465  * Just initializes the config object to factory defaults (see zxidconf.h).
1466  * Previous content of the config object is lost. */
1467 
1468 /* Called by:  attribute_sort_test, covimp_test, main x4, so_enc_dec, test_ibm_cert_problem, test_ibm_cert_problem_enc_dec, test_mode, timegm_test, timegm_tester, x509_test */
zxid_new_conf(const char * zxid_path)1469 zxid_conf* zxid_new_conf(const char* zxid_path)
1470 {
1471   /* *** unholy malloc()s: should use our own allocator! */
1472   zxid_conf* cf = malloc(sizeof(zxid_conf));
1473   if (!cf) {
1474     ERR("out-of-memory %d", (int)sizeof(zxid_conf));
1475     exit(1);
1476   }
1477   return zxid_init_conf_ctx(cf, zxid_path);
1478 }
1479 
1480 /* ======================= CONF PARSING ======================== */
1481 
1482 #if defined(ZXID_CONF_FILE) || defined(ZXID_CONF_FLAG)
1483 
1484 #define SCAN_INT(v, lval) sscanf(v,"%i",&i); lval=i /* Safe for char, too. Decimal or hex 0x */
1485 
1486 /*(-) Helper to evaluate a new PATH. check_file_exists helps to implement
1487  * the sematic where PATH is not changed unless corresponding zxid.conf
1488  * is found. This is used by VPATH. */
1489 
1490 /* Called by:  zxid_parse_conf_raw, zxid_parse_vpath */
zxid_parse_conf_path_raw(zxid_conf * cf,const char * v,int check_file_exists)1491 static void zxid_parse_conf_path_raw(zxid_conf* cf, const char* v, int check_file_exists)
1492 {
1493   int len;
1494   char *buf;
1495 
1496   /* N.B: The buffer read here leaks on purpose as conf parsing takes references inside it. */
1497   buf = read_all_alloc(cf->ctx, "-parse_conf_raw", 1, &len, "%s" ZXID_CONF_FILE, v);
1498   if (!buf || !len)
1499     buf = read_all_alloc(cf->ctx, "-parse_conf_raw", 1, &len, "%szxid.conf", v);
1500   if (buf && len) {
1501     cf->cpath = (char*)v;
1502     cf->cpath_len = strlen(v);
1503     ++cf->cpath_supplied;   /* Record level of recursion so we can avoid infinite recursion. */
1504     if (len)
1505       zxid_parse_conf_raw(cf, len, buf);  /* Recurse */
1506     --cf->cpath_supplied;
1507   } else if (!check_file_exists) {
1508     cf->cpath = (char*)v;   /* Set PATH anyway. */
1509     cf->cpath_len = strlen(v);
1510   }
1511 }
1512 
1513 /*(-) Helper to parse an include file. check_file_exists helps to implement
1514  * the sematic where PATH is not changed unless corresponding zxid.conf
1515  * is found. This is used by VPATH. */
1516 
1517 /* Called by:  zxid_parse_conf_raw */
zxid_parse_inc(zxid_conf * cf,const char * inc_file,int check_file_exists)1518 static void zxid_parse_inc(zxid_conf* cf, const char* inc_file, int check_file_exists)
1519 {
1520   int len;
1521   char *buf;
1522 
1523   /* N.B: The buffer read here leaks on purpose as conf parsing takes references inside it. */
1524   buf = read_all_alloc(cf->ctx, "-parse_inc", 1, &len, "%s", inc_file);
1525   if (buf && len) {
1526     ++cf->cpath_supplied;   /* Record level of recursion so we can avoid infinite recursion. */
1527     if (len)
1528       zxid_parse_conf_raw(cf, len, buf);  /* Recurse */
1529     --cf->cpath_supplied;
1530   } else if (check_file_exists) {
1531     ERR("Mandatory configuration include file(%s) not found. Aborting.", inc_file);
1532     DIE_ACTION(errno);
1533   } else {
1534     ERR("Optional configuration include file(%s) not found. Ignored.", inc_file);
1535   }
1536 }
1537 
1538 int zxid_suppress_vpath_warning = 30;
1539 
1540 /*() Helper to evaluate environment variables for VPATH and VURL.
1541  * squash_type: 0=VPATH, 1=VURL
1542  * Squashing conversts everything to lowercase and anything
1543  * not understood to underscore ("_"). In case of VURL squash,
1544  * URL characters [/:?&=] are left intact. */
1545 
1546 /* Called by:  zxid_expand_percent x4 */
zxid_eval_squash_env(char * vorig,const char * exp,char * env_hdr,char * out,char * lim,int squash_type)1547 static int zxid_eval_squash_env(char* vorig, const char* exp, char* env_hdr, char* out, char* lim, int squash_type)
1548 {
1549   int len;
1550   char* val = getenv(env_hdr);
1551   if (!val) {
1552     if (--zxid_suppress_vpath_warning > 0) ERR("VPATH or VURL(%s) %s expansion specified, but env(%s) not defined?!? Violation of CGI spec? SERVER_SOFTWARE(%s)", vorig, exp, env_hdr, STRNULLCHKQ(getenv("SERVER_SOFTWARE")));
1553     return 0;
1554   }
1555   len = strlen(val);
1556   if (out + len > lim) {
1557     ERR("TOO LONG: VPATH or VURL(%s) %s expansion specified env(%s) val(%s) does not fit, missing %ld bytes. SERVER_SOFTWARE(%s)", vorig, exp, env_hdr, val, (long)(lim - (out + len)), STRNULLCHKQ(getenv("SERVER_SOFTWARE")));
1558     return 0;
1559   }
1560 
1561   /* Squash suspicious */
1562 
1563   for (; *val; ++val, ++out)
1564     if (!squash_type && IN_RANGE(*val, 'A', 'Z')) {
1565       *out = *val - ('A' - 'a');  /* lowercase host names */
1566     } else if (IN_RANGE(*val, 'a', 'z') || IN_RANGE(*val, '0', '9') || ONE_OF_2(*val, '.', '-')) {
1567       *out = *val;
1568     } else if (squash_type == 1 && ONE_OF_5(*val, '/', ':', '?', '&', '=')) {
1569       *out = *val;
1570     } else {
1571       *out = '_';
1572     }
1573   return len;
1574 }
1575 
1576 /*() Expand percent expansions as found in VPATH and VURL
1577  * squash_type: 0=VPATH, 1=VURL.
1578  * See CGI specification for environment variables such as
1579  *   %h expands to HTTP_HOST (from Host header, e.g. Host: sp.foo.bar or Host: sp.foo.bar:8443)
1580  *   %s expands to SCRIPT_NAME
1581  *   %d expands to directory portion of SCRIPT_NAME
1582  */
1583 
1584 /* Called by:  zxid_parse_vpath, zxid_parse_vurl */
zxid_expand_percent(char * vorig,char * out,char * lim,int squash_type)1585 static char* zxid_expand_percent(char* vorig, char* out, char* lim, int squash_type)
1586 {
1587   int len;
1588   char* x;
1589   char* p;
1590   char* val;
1591   --lim;
1592   for (p = vorig; *p && out < lim; ++p) {
1593     if (*p != '%') {
1594       *out++ = *p;
1595       continue;
1596     }
1597     switch (*++p) {
1598     case 'a':
1599       val = getenv("SERVER_PORT");
1600       if (!val)
1601 	val = "";
1602       if (!memcmp(val, "80", MIN(strlen(val), 2)) || !memcmp(val, "88", MIN(strlen(val), 2)))
1603 	x = squash_type?"http://":"http_";
1604       else
1605 	x = squash_type?"https://":"https_";
1606       if (out + strlen(x) >= lim)
1607 	goto toobig;
1608       strcpy(out, x);
1609       out += strlen(out);
1610       break;
1611     case 'h': out += zxid_eval_squash_env(vorig, "%h", "HTTP_HOST", out, lim, squash_type); break;
1612     case 'P':
1613       val = getenv("SERVER_PORT");
1614       if (!val)
1615 	val = "";
1616       if (!strcmp(val, "443") || !strcmp(val, "80"))
1617 	break;     /* omit default ports */
1618       if (out >= lim)
1619 	goto toobig;
1620       *out++ = ':';  /* colon in front of port, e.g. :8080 */
1621       /* fall thru */
1622     case 'p': out += zxid_eval_squash_env(vorig,"%p", "SERVER_PORT", out, lim, squash_type); break;
1623     case 's': out += zxid_eval_squash_env(vorig,"%s", "SCRIPT_NAME", out, lim, squash_type); break;
1624     case 'd':
1625       len = zxid_eval_squash_env(vorig, "%d", "SCRIPT_NAME", out, lim, squash_type);
1626       for (out += len; len && out[-1] != '/'; --out, --len) ;
1627       break;
1628     case '%': *out++ = '%';  break;
1629     default:
1630       ERR("VPATH or VURL(%s): Syntactically wrong percent expansion character(%c) 0x%x, ignored", vorig, p[-1], p[-1]);
1631     }
1632   }
1633   *out = 0;
1634   return out;
1635  toobig:
1636   ERR("VPATH or VURL(%s) extrapolation does not fit in buffer", vorig);
1637   *out = 0;
1638   return out;
1639 }
1640 
1641 /*(-) Convert, in place, $ to & as needed for WSC_LOCALPDP_PLEDGE */
1642 
1643 /* Called by:  zxid_parse_conf_raw x2 */
zxid_dollar_to_amp(char * p)1644 static char* zxid_dollar_to_amp(char* p)
1645 {
1646   char* ret = p;
1647   for (p = strchr(p, '$'); p; p = strchr(p, '$'))
1648     *p = '&';
1649   return ret;
1650 }
1651 
1652 /*() Parse VPATH (virtual host) related config file.
1653  * If the file VPATHzxid.conf does not exist (note that the specified
1654  * VPATH usually ends in a slash ("/")), the PATH is not changed.
1655  * Effectively unconfigured VPATHs are handled by the default PATH. */
1656 
1657 /* Called by:  zxid_parse_conf_raw */
zxid_parse_vpath(zxid_conf * cf,char * vpath)1658 static int zxid_parse_vpath(zxid_conf* cf, char* vpath)
1659 {
1660   char newpath[PATH_MAX];
1661   char *np, *lim;
1662 
1663   DD("VPATH inside file(%.*s) %d new(%s)", cf->cpath_len, cf->cpath, cf->cpath_supplied, vpath);
1664   if (cf->cpath_supplied && !memcmp(cf->cpath, vpath, cf->cpath_len)
1665       || cf->cpath_supplied > ZXID_PATH_MAX_RECURS_EXPAND_DEPTH) {
1666     D("Skipping VPATH inside file(%.*s) path_supplied=%d", cf->cpath_len, cf->cpath, cf->cpath_supplied);
1667     return 0;
1668   }
1669 
1670   /* Check for relative path and prepend PATH if needed. */
1671 
1672   np = newpath;
1673   lim = newpath + sizeof(newpath);
1674 
1675   if (*vpath != '/') {
1676     if (cf->cpath_len > lim-np) {
1677       ERR("TOO LONG: CPATH(%.*s) len=%d does not fit in vpath buffer size=%ld", cf->cpath_len, cf->cpath, cf->cpath_len, (long)(lim-np));
1678       return 0;
1679     }
1680     memcpy(np, cf->cpath, cf->cpath_len);
1681     np +=  cf->cpath_len;
1682   }
1683 
1684   zxid_expand_percent(vpath, np, lim, 0);
1685   if (--zxid_suppress_vpath_warning > 0) {
1686     INFO("VPATH(%s) alters CPATH(%s) to new CPATH(%s)", vpath, cf->cpath, newpath);
1687   }
1688   zxid_parse_conf_path_raw(cf, zx_dup_cstr(cf->ctx, newpath), 1);
1689   return 1;
1690 }
1691 
1692 /*() Parse VURL (virtual host) to URL */
1693 
1694 /* Called by:  zxid_parse_conf_raw */
zxid_parse_vurl(zxid_conf * cf,char * vurl)1695 static int zxid_parse_vurl(zxid_conf* cf, char* vurl)
1696 {
1697   char newurl[PATH_MAX];
1698   zxid_expand_percent(vurl, newurl, newurl + sizeof(newurl), 1);
1699   if (--zxid_suppress_vpath_warning > 0) {
1700     INFO("VURL(%s) alters BURL(%s) to new BURL(%s)", vurl, cf->burl, newurl);
1701   }
1702   cf->burl = zx_dup_cstr(cf->ctx, newurl);
1703   return 1;
1704 }
1705 
1706 /*(i) Parse partial configuration specifications, such as may occur
1707  * on command line or in a configuration file.
1708  *
1709  * Generally you should
1710  * call first zxid_new_conf(), or at least zxid_init_conf(), and
1711  * then call this function to apply modifications over the defaults.
1712  * The configuration options are named after the config options
1713  * that appear in zxidconf.h, except that prefix ZXID_ is removed.
1714  *
1715  * N.B. The qs memory must come from static or permanently allocated
1716  * source as direct pointers to inside it will be taken. The memory
1717  * will be modified to add nul terminations. Do not use stack based
1718  * memory like local variable (unless local of main()).
1719  * Do consider strdup() or similar before calling this function.
1720  *
1721  * cf:: Previously allocated and initialized ZXID configuration object
1722  * qs_len:: Query String length. -1 means nul terminated C string
1723  * qs:: Configuration data in extended CGI Query String format. "extended"
1724  *     means newline can be used as separator, in addition to ampersand ("&")
1725  *     This argument is modified in place, changing separators to nul string
1726  *     terminations and performing URL decoding.
1727  * return:: -1 on failure, 0 on success */
1728 
1729 /* Called by:  zxid_conf_to_cf_len x4, zxid_parse_conf, zxid_parse_conf_path_raw */
zxid_parse_conf_raw(zxid_conf * cf,int qs_len,char * qs)1730 int zxid_parse_conf_raw(zxid_conf* cf, int qs_len, char* qs)
1731 {
1732   int i;
1733   int lineno;
1734   char *p, *n, *v;
1735   if (qs_len != -1 && qs[qs_len]) {  /* *** access one past end of buffer */
1736     ERR("LIMITATION: The configuration strings MUST be nul terminated (even when length is supplied explicitly). qs_len=%d qs(%.*s)", qs_len, qs_len, qs);
1737     return -1;
1738   }
1739   for (lineno = 1; qs && *qs; ++lineno) {
1740     qs = zxid_qs_nv_scan(qs, &n, &v, 1);
1741     if (!n) {
1742       if (!qs)
1743 	break;
1744       n = "NULL_NAME_ERR";
1745     }
1746 
1747     if (!strcmp(n, ZXID_PATH_OPT))       goto path;
1748 
1749     switch (n[0]) {
1750     case 'A':  /* AUTHN_REQ_SIGN, ACT, AUDIENCE_FATAL, AFTER_SLOP */
1751       if (!strcmp(n, "AUTO_CERT"))       { SCAN_INT(v, cf->auto_cert); break; }
1752       if (!strcmp(n, "AUTHN_REQ_SIGN"))  { SCAN_INT(v, cf->authn_req_sign); break; }
1753       if (!strcmp(n, "ACT"))             { SCAN_INT(v, cf->log_act); break; }
1754       if (!strcmp(n, "ACT_IN_ERR"))      { SCAN_INT(v, cf->log_err_in_act); break; }
1755       if (!strcmp(n, "AUDIENCE_FATAL"))  { SCAN_INT(v, cf->audience_fatal); break; }
1756       if (!strcmp(n, "AFTER_SLOP"))      { SCAN_INT(v, cf->after_slop); break; }
1757       if (!strcmp(n, "ANON_OK"))         { cf->anon_ok = v; D("anon_ok(%s)", cf->anon_ok); break; }
1758       if (!strcmp(n, "AN_PAGE"))         { cf->an_page = v; break; }
1759       if (!strcmp(n, "AN_TEMPL_FILE"))   { cf->an_templ_file = v; break; }
1760       if (!strcmp(n, "AN_TEMPL"))        { cf->an_templ = v; break; }
1761       if (!strcmp(n, "ATSEL_PAGE"))      { cf->atsel_page = v; break; }
1762       if (!strcmp(n, "ATTRSRC"))     { cf->attrsrc = zxid_load_atsrc(cf, cf->attrsrc, v); break; }
1763       if (!strcmp(n, "A7NTTL"))          { SCAN_INT(v, cf->a7nttl); break; }
1764       if (!strcmp(n, "AS_ENA"))          { SCAN_INT(v, cf->as_ena); break; }
1765       if (!strcmp(n, "AZ_OPT"))          { SCAN_INT(v, cf->az_opt); break; }
1766       if (!strcmp(n, "AZ_FAIL_MODE"))    { SCAN_INT(v, cf->az_fail_mode); break; }
1767       goto badcf;
1768     case 'B':  /* BEFORE_SLOP */
1769       if (!strcmp(n, "BURL"))            { cf->burl = v; cf->fedusername_suffix = zxid_grab_domain_name(cf, cf->burl); break; }
1770       if (!strcmp(n, "BEFORE_SLOP"))       { SCAN_INT(v, cf->before_slop); break; }
1771       if (!strcmp(n, "BOOTSTRAP_LEVEL"))   { SCAN_INT(v, cf->bootstrap_level); break; }
1772       if (!strcmp(n, "BARE_URL_ENTITYID")) { SCAN_INT(v, cf->bare_url_entityid); break; }
1773       if (!strcmp(n, "BUTTON_URL"))        {
1774 	if (!strstr(v, "saml2_icon_468x60") && !strstr(v, "saml2_icon_150x60") && !strstr(v, "saml2_icon_16x16"))
1775 	  ERR("BUTTON_URL has to specify button image and the image filename MUST contain substring \"saml2_icon\" in it (see symlabs-saml-displayname-2008.pdf submitted to OASIS SSTC). Furthermore, this substring must specify the size, which must be one of 468x60, 150x60, or 16x16. Acceptable substrings are are \"saml2_icon_468x60\", \"saml2_icon_150x60\", \"saml2_icon_16x16\", e.g. \"https://your-domain.com/your-brand-saml2_icon_150x60.png\". Current value(%s) may be used despite this error. Only last acceptable specification of BUTTON_URL will be used. (conf line %d", v, lineno);
1776 	if (!cf->button_url || strstr(v, cf->pref_button_size)) /* Pref overrides previous. */
1777 	  cf->button_url = v;
1778 	break;
1779       }
1780       if (!strcmp(n, "BUS_URL"))         { cf->bus_url = zxid_load_bus_url(cf, cf->bus_url, v);   break; }
1781       if (!strcmp(n, "BUS_PW"))          { cf->bus_pw = v; break; }
1782       if (!strcmp(n, "BACKWARDS_COMPAT_ENA")) { SCAN_INT(v, cf->backwards_compat_ena); break; }
1783       if (!strcmp(n, "BLOBSIG_DIGEST_ALGO")) { cf->blobsig_digest_algo = v; break; }
1784       goto badcf;
1785     case 'C':  /* CDC_URL, CDC_CHOICE */
1786       if (!strcmp(n, "CPATH"))           goto path;
1787       if (!strcmp(n, "CDC_URL"))         { cf->cdc_url = v; break; }
1788       if (!strcmp(n, "CDC_CHOICE"))      { SCAN_INT(v, cf->cdc_choice); break; }
1789       if (!strcmp(n, "CONTACT_ORG"))     { cf->contact_org = v; break; }
1790       if (!strcmp(n, "CONTACT_NAME"))    { cf->contact_name = v; break; }
1791       if (!strcmp(n, "CONTACT_EMAIL"))   { cf->contact_email = v; break; }
1792       if (!strcmp(n, "CONTACT_TEL"))     { cf->contact_tel = v; break; }
1793       if (!strcmp(n, "COUNTRY"))         { cf->country = v; break; }
1794       if (!strcmp(n, "CANON_INOPT"))     { SCAN_INT(v, cf->canon_inopt); if (cf->ctx) cf->ctx->canon_inopt = cf->canon_inopt; break; }
1795       if (!strcmp(n, "CPN_ENA"))         { SCAN_INT(v, cf->cpn_ena); break; }
1796       goto badcf;
1797     case 'D':  /* DUP_A7N_FATAL, DUP_MSG_FATAL */
1798       if (!strcmp(n, "DEFAULTQS"))       { cf->defaultqs = v; break; }
1799       if (!strcmp(n, "DUP_A7N_FATAL"))   { SCAN_INT(v, cf->dup_a7n_fatal); break; }
1800       if (!strcmp(n, "DUP_MSG_FATAL"))   { SCAN_INT(v, cf->dup_msg_fatal); break; }
1801       if (!strcmp(n, "DI_ALLOW_CREATE")) { cf->di_allow_create = *v; break; }
1802       if (!strcmp(n, "DI_NID_FMT"))      { SCAN_INT(v, cf->di_nid_fmt); break; }
1803       if (!strcmp(n, "DI_A7N_ENC"))      { SCAN_INT(v, cf->di_a7n_enc); break; }
1804       if (!strcmp(n, "DEBUG"))           { SCAN_INT(v, errmac_debug); INFO("errmac_debug:%d", errmac_debug); break; }
1805       if (!strcmp(n, "DEBUG_LOG"))       { zxid_set_opt_cstr(cf, 6, v); break; }
1806       if (!strcmp(n, "D"))               { D("D=%s (conf line %d)", v, lineno); break; }
1807       if (!strcmp(n, "DIE"))             { ERR("DIE=%s (conf line %d)", v, lineno); DIE_ACTION(1); break; }
1808       goto badcf;
1809     case 'E':  /* ERR, ERR_IN_ACT */
1810       if (!strcmp(n, "ERR"))             { SCAN_INT(v, cf->log_err); break; }
1811       if (!strcmp(n, "ERR_IN_ACT"))      { SCAN_INT(v, cf->log_err_in_act); break; }
1812       if (!strcmp(n, "ENC_TAIL_OPT"))    { SCAN_INT(v, cf->enc_tail_opt); break; }
1813       if (!strcmp(n, "ENCKEY_OPT"))      { SCAN_INT(v, cf->enckey_opt); break; }
1814       if (!strcmp(n, "ERR_PAGE"))        { cf->err_page = v; break; }
1815       if (!strcmp(n, "ERR_TEMPL_FILE"))  { cf->err_templ_file = v; break; }
1816       if (!strcmp(n, "ERR_TEMPL"))       { cf->err_templ = v; break; }
1817       if (!strcmp(n, "ECHO"))            { INFO("ECHO=%s (conf line %d)", v, lineno); break; }
1818       goto badcf;
1819     case 'F':
1820       if (!strcmp(n, "FEDUSERNAME_SUFFIX")) { cf->fedusername_suffix = v; break; }
1821       goto badcf;
1822     case 'I':  /* ISSUE_A7N, ISSUE_MSG */
1823       if (!strcmp(n, "ISSUE_A7N"))       { SCAN_INT(v, cf->log_issue_a7n); break; }
1824       if (!strcmp(n, "ISSUE_MSG"))       { SCAN_INT(v, cf->log_issue_msg); break; }
1825       if (!strcmp(n, "ISSUE_AUTHNCTX"))  { cf->issue_authnctx = zxid_load_cstr_list(cf, cf->issue_authnctx, v); break; }
1826 #if 0
1827       if (!strcmp(n, "IDP_SEL_START"))   { cf->idp_sel_start = v; break; }
1828       if (!strcmp(n, "IDP_SEL_NEW_IDP")) { cf->idp_sel_new_idp = v; break; }
1829       if (!strcmp(n, "IDP_SEL_OUR_EID")) { cf->idp_sel_our_eid = v; break; }
1830       if (!strcmp(n, "IDP_SEL_TECH_USER")) { cf->idp_sel_tech_user =v; break; }
1831       if (!strcmp(n, "IDP_SEL_TECH_SITE")) { cf->idp_sel_tech_site =v; break; }
1832       if (!strcmp(n, "IDP_SEL_FOOTER"))  { cf->idp_sel_footer = v; break; }
1833       if (!strcmp(n, "IDP_SEL_END"))     { cf->idp_sel_end = v; break; }
1834 #endif
1835       if (!strcmp(n, "IDP_SEL_PAGE"))    { cf->idp_sel_page = v; break; }
1836       if (!strcmp(n, "IDP_SEL_TEMPL_FILE")) { cf->idp_sel_templ_file = v; break; }
1837       if (!strcmp(n, "IDP_SEL_TEMPL"))   { cf->idp_sel_templ = v; break; }
1838       if (!strcmp(n, "IDP_ENA"))         { SCAN_INT(v, cf->idp_ena); break; }
1839       if (!strcmp(n, "IDP_PXY_ENA"))     { SCAN_INT(v, cf->idp_pxy_ena); break; }
1840       if (!strcmp(n, "IMPS_ENA"))        { SCAN_INT(v, cf->imps_ena); break; }
1841       if (!strcmp(n, "IDP_PREF_ACS_BINDING")) { cf->idp_pref_acs_binding = v; break; }
1842       if (!strcmp(n, "IDPATOPT"))        { SCAN_INT(v, cf->idpatopt); break; }
1843       if (!strcmp(n, "IDP_LIST_METH"))   { SCAN_INT(v, cf->idp_list_meth); break; }
1844       if (!strcmp(n, "INMAP"))           { cf->inmap = zxid_load_map(cf, cf->inmap, v); break; }
1845       if (!strcmp(n, "INFO"))            { INFO("INFO=%s (conf line %d)", v, lineno); break; }
1846       if (!strcmp(n, "INCLUDE"))         { zxid_parse_inc(cf, v, 1); break; }
1847       goto badcf;
1848     case 'L':  /* LEVEL (log level) */
1849       if (!strcmp(n, "LEVEL"))     { SCAN_INT(v, cf->log_level); break; }
1850       if (!strcmp(n, "LOGUSER"))   { SCAN_INT(v, cf->loguser); break; }
1851       if (!strcmp(n, "LOCALPDP_ROLE_PERMIT"))   { cf->localpdp_role_permit   = zxid_load_cstr_list(cf, cf->localpdp_role_permit, v);   break; }
1852       if (!strcmp(n, "LOCALPDP_ROLE_DENY"))     { cf->localpdp_role_deny     = zxid_load_cstr_list(cf, cf->localpdp_role_deny, v);     break; }
1853       if (!strcmp(n, "LOCALPDP_IDPNID_PERMIT")) { cf->localpdp_idpnid_permit = zxid_load_cstr_list(cf, cf->localpdp_idpnid_permit, v); break; }
1854       if (!strcmp(n, "LOCALPDP_IDPNID_DENY"))   { cf->localpdp_idpnid_deny   = zxid_load_cstr_list(cf, cf->localpdp_idpnid_deny, v);   break; }
1855       if (!strcmp(n, "LOAD_COT_CACHE"))  { cf->load_cot_cache = v; break; }
1856       if (!strcmp(n, "LOCALITY"))        { cf->locality = v; break; }
1857       goto badcf;
1858     case 'M':  /* MD_FETCH, MD_POPULATE_CACHE, MD_CACHE_FIRST, MD_CACHE_LAST */
1859       if (!strcmp(n, "MANDATORY_ATTR"))    { cf->mandatory_attr = v; break; }
1860       if (!strcmp(n, "MD_FETCH"))          { SCAN_INT(v, cf->md_fetch); break; }
1861       if (!strcmp(n, "MD_POPULATE_CACHE")) { SCAN_INT(v, cf->md_populate_cache); break; }
1862       if (!strcmp(n, "MD_CACHE_FIRST"))    { SCAN_INT(v, cf->md_cache_first); break; }
1863       if (!strcmp(n, "MD_CACHE_LAST"))     { SCAN_INT(v, cf->md_cache_last); break; }
1864       if (!strcmp(n, "MD_AUTHORITY_ENA"))  { SCAN_INT(v, cf->md_authority_ena); break; }
1865       if (!strcmp(n, "MD_AUTHORITY")) { cf->md_authority = v; break; }
1866       if (!strcmp(n, "MGMT_START"))   { cf->mgmt_start = v; break; }
1867       if (!strcmp(n, "MGMT_LOGOUT"))  { cf->mgmt_logout = v; break; }
1868       if (!strcmp(n, "MGMT_DEFED"))   { cf->mgmt_defed = v; break; }
1869       if (!strcmp(n, "MGMT_FOOTER"))  { cf->mgmt_footer = v; break; }
1870       if (!strcmp(n, "MGMT_END"))     { cf->mgmt_end = v; break; }
1871       if (!strcmp(n, "MSG_SIG_OK"))   { SCAN_INT(v, cf->msg_sig_ok); break; }
1872       if (!strcmp(n, "MAX_SOAP_RETRY"))        { SCAN_INT(v, cf->max_soap_retry); break; }
1873       if (!strcmp(n, "MOD_SAML_ATTR_PREFIX"))  { cf->mod_saml_attr_prefix = v; break; }
1874 
1875       goto badcf;
1876     case 'N':  /* NAMEID_ENC, NICE_NAME, NOSIG_FATAL */
1877       if (!strcmp(n, "NAMEID_ENC"))     { SCAN_INT(v, cf->nameid_enc); break; }
1878       if (!strcmp(n, "NICE_NAME"))      { cf->nice_name = v; break; }
1879       if (!strcmp(n, "NON_STANDARD_ENTITYID")) { cf->non_standard_entityid = v; D("NON_STANDARD_ENTITYID set(%s)", v); break; }
1880       if (!strcmp(n, "NOSIG_FATAL"))    { SCAN_INT(v, cf->nosig_fatal); break; }
1881       if (!strcmp(n, "NOTIMESTAMP_FATAL")) { SCAN_INT(v, cf->notimestamp_fatal); break; }
1882       if (!strcmp(n, "NEED"))           { cf->need = zxid_load_need(cf, cf->need, v); break; }
1883       if (!strcmp(n, "NEW_USER_PAGE"))  { cf->new_user_page = v; break; }
1884       goto badcf;
1885     case 'O':  /* OUTMAP */
1886       if (!strcmp(n, "OUTMAP"))         { cf->outmap = zxid_load_map(cf, cf->outmap, v); break; }
1887       if (!strcmp(n, "ORG_NAME"))       { cf->org_name = v; break; }
1888       if (!strcmp(n, "ORG_URL"))        {
1889 	ERR("Discontinued configuration option ORG_URL supplied. This option has been deleted. Use BUTTON_URL instead, but note that the URL has to specify button image instead of home page (the image filename MUST contain substring \"saml2_icon\" in it). Current value(%s) (conf line %d)", v, lineno);
1890 	cf->button_url = v;
1891 	break;
1892       }
1893       if (!strcmp(n, "OAZ_JWT_SIGENC_ALG")) { cf->oaz_jwt_sigenc_alg = *v; break; }
1894       if (!strcmp(n, "OPT_INCLUDE"))    { zxid_parse_inc(cf, v, 0); break; }
1895       if (!strcmp(n, "OPTIONAL_LOGIN_PAT")) { cf->optional_login_pat = v; D("optional_login_pat(%s)", cf->optional_login_pat); break; }
1896       goto badcf;
1897     case 'P':  /* PATH (e.g. /var/zxid) */
1898       DD("PATH maybe n(%s)=v(%s)", n, v);
1899       if (!strcmp(n, "PATH")) {
1900     path:
1901 	DD("CPATH inside file(%.*s) %d new(%s)", cf->cpath_len, cf->cpath, cf->cpath_supplied, v);
1902 	if (cf->cpath_supplied && !memcmp(cf->cpath, v, cf->cpath_len)
1903 	    || cf->cpath_supplied > ZXID_PATH_MAX_RECURS_EXPAND_DEPTH) {
1904 	  D("Skipping CPATH inside file(%.*s) cpath_supplied=%d", cf->cpath_len, cf->cpath, cf->cpath_supplied);
1905 	  break;
1906 	}
1907 	zxid_parse_conf_path_raw(cf, v, 0);
1908 	break;
1909       }
1910       if (!strcmp(n, "PDP_ENA"))        { SCAN_INT(v, cf->pdp_ena); break; }
1911       if (!strcmp(n, "PDP_URL"))        { cf->pdp_url = v; break; }
1912       if (!strcmp(n, "PDP_CALL_URL"))   { cf->pdp_call_url = v; break; }
1913       if (!strcmp(n, "PEPMAP"))         { cf->pepmap = zxid_load_map(cf, cf->pepmap, v); break; }
1914       if (!strcmp(n, "PEPMAP_RQOUT"))   { cf->pepmap_rqout = zxid_load_map(cf, cf->pepmap_rqout, v); break; }
1915       if (!strcmp(n, "PEPMAP_RQIN"))    { cf->pepmap_rqin  = zxid_load_map(cf, cf->pepmap_rqin,  v); break; }
1916       if (!strcmp(n, "PEPMAP_RSOUT"))   { cf->pepmap_rsout = zxid_load_map(cf, cf->pepmap_rsout, v); break; }
1917       if (!strcmp(n, "PEPMAP_RSIN"))    { cf->pepmap_rsin  = zxid_load_map(cf, cf->pepmap_rsin,  v); break; }
1918       if (!strcmp(n, "POST_A7N_ENC"))   { SCAN_INT(v, cf->post_a7n_enc); break; }
1919       if (!strcmp(n, "POST_TEMPL_FILE"))   { cf->post_templ_file = v; break; }
1920       if (!strcmp(n, "POST_TEMPL"))        { cf->post_templ = v; break; }
1921       if (!strcmp(n, "PREF_BUTTON_SIZE"))        {
1922 	if (!strstr(v, "468x60") && !strstr(v, "150x60") && !strstr(v, "16x16"))
1923 	  ERR("PREF_BUTTON_SIZE should specify one of the standard button image sizes, such as 468x60, 150x60, or 16x16 (and the image filename MUST contain substring \"saml2_icon\" in it, see symlabs-saml-displayname-2008.pdf submitted to OASIS SSTC). Current value(%s) is used despite this error. (conf line %d", v, lineno);
1924 	cf->pref_button_size = v;
1925 	break;
1926       }
1927       if (!strcmp(n, "PTM_COOKIE_NAME")) { cf->ptm_cookie_name = (!v[0] || v[0]=='0' && !v[1]) ? 0 : v; break; }
1928       if (!strcmp(n, "PRAGMA"))          { D("PRAGMA(%s)", v); break; }
1929       goto badcf;
1930     case 'R':  /* RELY_A7N, RELY_MSG */
1931       if (!strcmp(n, "REDIRECT_HACK_IMPOSED_URL")) { cf->redirect_hack_imposed_url = v; break; }
1932       if (!strcmp(n, "REDIRECT_HACK_ZXID_URL")) {
1933 	cf->redirect_hack_zxid_url = v;
1934 	p = strchr(v, '?');
1935 	if (p) {
1936 	  *p = 0;
1937 	  cf->redirect_hack_zxid_qs = p+1;
1938 	}
1939 	break;
1940       }
1941       if (!strcmp(n, "REDIR_TO_CONTENT"))  { SCAN_INT(v, cf->redir_to_content); break; }
1942       if (!strcmp(n, "REMOTE_USER_ENA"))   { SCAN_INT(v, cf->remote_user_ena); break; }
1943       if (!strcmp(n, "RELY_A7N"))          { SCAN_INT(v, cf->log_rely_a7n); break; }
1944       if (!strcmp(n, "RELY_MSG"))          { SCAN_INT(v, cf->log_rely_msg); break; }
1945       if (!strcmp(n, "REQUIRED_AUTHNCTX")) {
1946 	/* Count how many */
1947         for (i=2, p=v; *p; ++p)
1948 	  if (*p == '$')
1949 	    ++i;
1950 	cf->required_authnctx = zx_zalloc(cf->ctx, sizeof(char*) * i);
1951 	/* Populate array with strings, stomping the separator char $ to nul termination. */
1952         for (i=0, p=v; *p; ++i) {
1953 	  cf->required_authnctx[i] = p;
1954 	  p = strchr(p, '$');
1955 	  if (!p)
1956 	    break;
1957 	  *p++ = 0;
1958 	}
1959 	break;
1960       }
1961       if (!strcmp(n, "RECOVER_PASSWD")) { cf->recover_passwd = v; break; }
1962       if (!strcmp(n, "RELTO_FATAL"))    { SCAN_INT(v, cf->relto_fatal); break; }
1963       if (!strcmp(n, "RCPT"))           { SCAN_INT(v, cf->bus_rcpt); break; }
1964       if (!strcmp(n, "REM"))            { /* no-op */ break; }
1965       goto badcf;
1966     case 'S':  /* SES_ARCH_DIR, SIGFAIL_IS_ERR, SIG_FATAL */
1967       if (!strcmp(n, "SES_ARCH_DIR"))   { cf->ses_arch_dir = (!v[0] || v[0]=='0' && !v[1]) ? 0 : v; break; }
1968       if (!strcmp(n, "SES_COOKIE_NAME")) { cf->ses_cookie_name = (!v[0] || v[0]=='0' && !v[1]) ? 0 : v; break; }
1969       if (!strcmp(n, "SIGFAIL_IS_ERR")) { SCAN_INT(v, cf->log_sigfail_is_err); break; }
1970       if (!strcmp(n, "SIG_FATAL"))      { SCAN_INT(v, cf->sig_fatal); break; }
1971       if (!strcmp(n, "SSO_SIGN"))       { SCAN_INT(v, cf->sso_sign); break; }
1972       if (!strcmp(n, "SSO_SOAP_SIGN"))  { SCAN_INT(v, cf->sso_soap_sign); break; }
1973       if (!strcmp(n, "SSO_SOAP_RESP_SIGN"))  { SCAN_INT(v, cf->sso_soap_resp_sign); break; }
1974       if (!strcmp(n, "SHOW_CONF"))      { SCAN_INT(v, cf->show_conf); break; }
1975       if (!strcmp(n, "SHOW_TECH"))      { SCAN_INT(v, cf->show_tech); break; }
1976       if (!strcmp(n, "STATE"))          { cf->state = v; break; }
1977       if (!strcmp(n, "SSO_PAT"))        { cf->sso_pat = v; break; }
1978       if (!strcmp(n, "SOAP_ACTION_HDR")) { cf->soap_action_hdr = v; break; }
1979       if (!strcmp(n, "SAMLSIG_DIGEST_ALGO")) { cf->samlsig_digest_algo = v; break; }
1980       goto badcf;
1981     case 'T':  /* TIMEOUT_FATAL */
1982       if (!strcmp(n, "TIMEOUT_FATAL"))  { SCAN_INT(v, cf->timeout_fatal); break; }
1983       if (!strcmp(n, "TIMESKEW"))       { SCAN_INT(v, cf->timeskew); break; }
1984       if (!strcmp(n, "TRUSTPDP_URL"))   { cf->trustpdp_url = v; break; }
1985       goto badcf;
1986     case 'U':  /* URL, USER_LOCAL */
1987       if (!strcmp(n, "URL"))            { cf->burl = v; cf->fedusername_suffix = zxid_grab_domain_name(cf, cf->burl); break; }
1988       if (!strcmp(n, "USER_LOCAL"))     { SCAN_INT(v, cf->user_local); break; }
1989       if (!strcmp(n, "UMA_PAT"))        { cf->uma_pat = v; break; }
1990       if (!strcmp(n, "UNIX_GRP_AZ_MAP")) { cf->unix_grp_az_map = zxid_load_unix_grp_az_map(cf, cf->unix_grp_az_map, v); break; }
1991       goto badcf;
1992     case 'V':  /* VALID_OPT */
1993       if (!strcmp(n, "VALID_OPT"))      { SCAN_INT(v, cf->valid_opt); break; }
1994       if (!strcmp(n, "VPATH"))          { zxid_parse_vpath(cf, v); break; }
1995       if (!strcmp(n, "VURL"))           { zxid_parse_vurl(cf, v); break; }
1996       goto badcf;
1997     case 'W':  /* WANT_SSO_A7N_SIGNED */
1998       if (!strcmp(n, "WANT"))           { cf->want = zxid_load_need(cf, cf->want, v); break; }
1999       if (!strcmp(n, "WANT_SSO_A7N_SIGNED"))   { SCAN_INT(v, cf->want_sso_a7n_signed); break; }
2000       if (!strcmp(n, "WANT_AUTHN_REQ_SIGNED")) { SCAN_INT(v, cf->want_authn_req_signed); break; }
2001       if (!strcmp(n, "WSC_SIGN"))       { SCAN_INT(v, cf->wsc_sign); break; }
2002       if (!strcmp(n, "WSP_SIGN"))       { SCAN_INT(v, cf->wsp_sign); break; }
2003       if (!strcmp(n, "WSPCGICMD"))      { cf->wspcgicmd = v; break; }
2004       if (!strcmp(n, "WSP_NOSIG_FATAL")) { SCAN_INT(v, cf->wsp_nosig_fatal); break; }
2005       if (!strcmp(n, "WSC_LOCALPDP_OBL_PLEDGE"))  { cf->wsc_localpdp_obl_pledge = zxid_dollar_to_amp(v);   break; }
2006       if (!strcmp(n, "WSP_LOCALPDP_OBL_REQ"))     { cf->wsp_localpdp_obl_req    = zxid_load_obl_list(cf, cf->wsp_localpdp_obl_req, v);   break; }
2007       if (!strcmp(n, "WSP_LOCALPDP_OBL_EMIT"))    { cf->wsp_localpdp_obl_emit   = zxid_dollar_to_amp(v);   break; }
2008       if (!strcmp(n, "WSC_LOCALPDP_OBL_ACCEPT"))  { cf->wsc_localpdp_obl_accept = zxid_load_obl_list(cf, cf->wsc_localpdp_obl_accept, v);   break; }
2009       if (!strcmp(n, "WD"))             { cf->wd = v; chdir(v); break; }
2010       if (!strcmp(n, "WSP_PAT"))        { cf->wsp_pat = v; break; }
2011       if (!strcmp(n, "WSC_SOAP_CONTENT_TYPE")) { cf->wsc_soap_content_type = v; break; }
2012       if (!strcmp(n, "WSC_TO_HDR"))     { cf->wsc_to_hdr = v; break; }
2013       if (!strcmp(n, "WSC_REPLYTO_HDR")) { cf->wsc_replyto_hdr = v; break; }
2014       if (!strcmp(n, "WSC_ACTION_HDR")) { cf->wsc_action_hdr = v; break; }
2015       if (!strcmp(n, "WARN"))           { WARN("WARN=%s (conf line %d)", v, lineno); break; }
2016       goto badcf;
2017     case 'X':  /* XASP_VERS */
2018       if (!strcmp(n, "XASP_VERS"))      { cf->xasp_vers = v; break; }
2019       if (!strcmp(n, "XMLDSIG_SIG_METH")) { cf->xmldsig_sig_meth = v; break; }
2020       if (!strcmp(n, "XMLDSIG_DIGEST_ALGO")) { cf->xmldsig_digest_algo = v; break; }
2021       goto badcf;
2022     default:
2023     badcf:
2024       ERR("Unknown config option(%s) val(%s), ignored (conf line %d)", n, v, lineno);
2025       zxlog(cf, 0, 0, 0, 0, 0, 0, 0, "N", "S", "BADCF", n, 0);
2026     }
2027   }
2028   return 0;
2029 }
2030 
2031 /*() Wrapper with initial error checking for zxid_parse_conf_raw(), which see. */
2032 
2033 /* Called by:  opt x13, set_zxid_conf */
zxid_parse_conf(zxid_conf * cf,char * qs)2034 int zxid_parse_conf(zxid_conf* cf, char* qs)
2035 {
2036   if (!cf || !qs)
2037     return -1;
2038   return zxid_parse_conf_raw(cf, strlen(qs), qs);
2039 }
2040 
2041 #endif
2042 
2043 /*() Pretty print need or want chain.
2044  * *** leaks some ss and need nodes */
2045 
2046 /* Called by:  zxid_show_conf x2 */
zxid_show_need(zxid_conf * cf,struct zxid_need * np)2047 static struct zx_str* zxid_show_need(zxid_conf* cf, struct zxid_need* np)
2048 {
2049   struct zxid_attr* ap;
2050   struct zx_str* ss;
2051   struct zx_str* need = zx_dup_str(cf->ctx, "");
2052   for (; np; np = np->n) {
2053     ss = zx_dup_str(cf->ctx, "");
2054     for (ap = np->at; ap; ap = ap->n) {
2055       ss = zx_strf(cf->ctx, "%s,%.*s", STRNULLCHK(ap->name), ss->len, ss->s);
2056     }
2057     if (ss->len) {  /* chop off last comma separator */
2058       ss->len -= 1;
2059       ss->s[ss->len] = 0;
2060     }
2061     need = zx_strf(cf->ctx, "  attrs(%s)\n    usage(%s)\n    retent(%s)\n    oblig(%s)\n    ext(%s)$\n%.*s",
2062 		   ss->s, STRNULLCHK(np->usage), STRNULLCHK(np->retent),
2063 		   STRNULLCHK(np->oblig), STRNULLCHK(np->ext),
2064 		   need->len, need->s);
2065     ZX_FREE(cf->ctx, ss);
2066   }
2067   if (need->len) {  /* chop off last dollar separator */
2068     need->len -= 2;
2069     need->s[need->len] = 0;
2070   }
2071   return need;
2072 }
2073 
2074 /*() Pretty print map chain. */
2075 
2076 /* Called by:  zxid_show_conf x7 */
zxid_show_map(zxid_conf * cf,struct zxid_map * mp)2077 static struct zx_str* zxid_show_map(zxid_conf* cf, struct zxid_map* mp)
2078 {
2079   struct zx_str* inmap = zx_dup_str(cf->ctx, "");
2080   for (; mp; mp = mp->n) {
2081     inmap = zx_strf(cf->ctx, "  rule=%d$ ns(%s)$ src(%s)$ dst(%s)$ ext(%s);\n%.*s", mp->rule, STRNULLCHK(mp->ns), STRNULLCHK(mp->src), STRNULLCHK(mp->dst), STRNULLCHK(mp->ext), inmap->len, inmap->s);
2082   }
2083   if (inmap->len) {  /* chop off last semicolon separator */
2084     inmap->len -= 2;
2085     inmap->s[inmap->len] = 0;
2086   }
2087   return inmap;
2088 }
2089 
2090 
2091 /*() Pretty print cstr list as used in local PDP. */
2092 
2093 /* Called by:  zxid_show_conf x4 */
zxid_show_cstr_list(zxid_conf * cf,struct zxid_cstr_list * cp)2094 static struct zx_str* zxid_show_cstr_list(zxid_conf* cf, struct zxid_cstr_list* cp)
2095 {
2096   struct zx_str* ss = zx_dup_str(cf->ctx, "");
2097   for (; cp; cp = cp->n) {
2098     ss = zx_strf(cf->ctx, "  %s,\n%.*s", STRNULLCHK(cp->s), ss->len, ss->s);
2099   }
2100   if (ss->len) {  /* chop off last comma separator */
2101     ss->len -= 2;
2102     ss->s[ss->len] = 0;
2103   }
2104   return ss;
2105 }
2106 
2107 /*() Pretty print bus_url list. */
2108 
2109 /* Called by:  zxid_show_conf */
zxid_show_bus_url(zxid_conf * cf,struct zxid_bus_url * cp)2110 static struct zx_str* zxid_show_bus_url(zxid_conf* cf, struct zxid_bus_url* cp)
2111 {
2112   struct zx_str* ss = zx_dup_str(cf->ctx, "");
2113   for (; cp; cp = cp->n) {
2114     ss = zx_strf(cf->ctx, "  %s,\n%.*s", STRNULLCHK(cp->s), ss->len, ss->s);
2115   }
2116   if (ss->len) {  /* chop off last comma separator */
2117     ss->len -= 2;
2118     ss->s[ss->len] = 0;
2119   }
2120   return ss;
2121 }
2122 
2123 /*() Generate our SP CARML and return it as a string. */
2124 
2125 /* Called by:  opt x5, zxid_simple_show_conf */
zxid_show_conf(zxid_conf * cf)2126 struct zx_str* zxid_show_conf(zxid_conf* cf)
2127 {
2128   char* eid;
2129   char* p;
2130   struct zxid_attr* ap;
2131   struct zxid_atsrc* sp;
2132   struct zx_str* ss;
2133   struct zx_str* required_authnctx;
2134   struct zx_str* need;
2135   struct zx_str* want;
2136   struct zx_str* attrsrc;
2137   struct zx_str* bus_url;
2138   struct zx_str* inmap;
2139   struct zx_str* outmap;
2140   struct zx_str* pepmap;
2141   struct zx_str* pepmap_rqout;
2142   struct zx_str* pepmap_rqin;
2143   struct zx_str* pepmap_rsout;
2144   struct zx_str* pepmap_rsin;
2145   struct zx_str* localpdp_role_permit;
2146   struct zx_str* localpdp_role_deny;
2147   struct zx_str* localpdp_idpnid_permit;
2148   struct zx_str* localpdp_idpnid_deny;
2149   struct zx_str* issue_authnctx;
2150   struct zx_str* unix_grp_az_map;
2151   if (cf->log_level>0)
2152     zxlog(cf, 0, 0, 0, 0, 0, 0, 0, "N", "W", "MYCONF", 0, 0);
2153 
2154   if (!cf->show_conf) {
2155     return zx_strf(cf->ctx, "<title>Conf dump disabled</title><body bgcolor=white>Conf viewing disabled using SHOW_CONF=0 option.");
2156   }
2157 
2158   /* N.B. The following way of "concatenating" strings leaks memory of the intermediate
2159    * results. We can't be bothered as the o=d is just a debug page. */
2160 
2161   required_authnctx = zx_dup_str(cf->ctx, "");
2162   for (p = cf->required_authnctx ? *cf->required_authnctx:0; p; ++p) {
2163     required_authnctx = zx_strf(cf->ctx, "  %s$\n%.*s", p, required_authnctx->len, required_authnctx->s);
2164   }
2165   if (required_authnctx->len) {  /* chop off last dollar separator */
2166     required_authnctx->len -= 2;
2167     required_authnctx->s[required_authnctx->len] = 0;
2168   }
2169 
2170   need = zxid_show_need(cf, cf->need);
2171   want = zxid_show_need(cf, cf->want);
2172 
2173   attrsrc = zx_dup_str(cf->ctx, "");
2174   for (sp = cf->attrsrc; sp; sp = sp->n) {
2175     ss = zx_dup_str(cf->ctx, "");
2176     for (ap = sp->at; ap; ap = ap->n) {
2177       ss = zx_strf(cf->ctx, "%s,%.*s", STRNULLCHK(ap->name), ss->len, ss->s);
2178     }
2179     if (ss->len) {  /* chop off last dollar separator */
2180       ss->len -= 1;
2181       ss->s[ss->len] = 0;
2182     }
2183     attrsrc = zx_strf(cf->ctx, "  attrs(%s)\n    ns(%s)\n    weight(%s)\n    burl(%s)\n    aapml(%s)\n    otherlim(%s)\n    ext(%s)$\n%.*s", ss->s, STRNULLCHK(sp->ns), STRNULLCHK(sp->weight), STRNULLCHK(sp->url), STRNULLCHK(sp->aapml), STRNULLCHK(sp->otherlim), STRNULLCHK(sp->ext),
2184 		   attrsrc->len, attrsrc->s);
2185   }
2186   if (attrsrc->len) {  /* chop off last dollar separator */
2187     attrsrc->len -= 2;
2188     attrsrc->s[attrsrc->len] = 0;
2189   }
2190 
2191   bus_url = zxid_show_bus_url(cf, cf->bus_url);
2192 
2193   inmap = zxid_show_map(cf, cf->inmap);
2194   outmap = zxid_show_map(cf, cf->outmap);
2195   pepmap = zxid_show_map(cf, cf->pepmap);
2196   pepmap_rqout = zxid_show_map(cf, cf->pepmap_rqout);
2197   pepmap_rqin  = zxid_show_map(cf, cf->pepmap_rqin);
2198   pepmap_rsout = zxid_show_map(cf, cf->pepmap_rsout);
2199   pepmap_rsin  = zxid_show_map(cf, cf->pepmap_rsin);
2200 
2201   localpdp_role_permit   = zxid_show_cstr_list(cf, cf->localpdp_role_permit);
2202   localpdp_role_deny     = zxid_show_cstr_list(cf, cf->localpdp_role_deny);
2203   localpdp_idpnid_permit = zxid_show_cstr_list(cf, cf->localpdp_idpnid_permit);
2204   localpdp_idpnid_deny   = zxid_show_cstr_list(cf, cf->localpdp_idpnid_deny);
2205 
2206   issue_authnctx = zxid_show_cstr_list(cf, cf->issue_authnctx);
2207 
2208   unix_grp_az_map = zxid_show_map(cf, cf->unix_grp_az_map);
2209 
2210   eid = zxid_my_ent_id_cstr(cf);
2211 
2212   return zx_strf(cf->ctx,
2213 "<title>Conf for %s</title><body bgcolor=white><h1>Conf for %s</h1>"
2214 "<p>Please see config file in %s" ZXID_CONF_FILE ", and documentation in zxid-conf.pd and zxidconf.h\n"
2215 "<p>[ <a href=\"?o=B\">Metadata</a> | <a href=\"?o=c\">CARML</a> | <a href=\"?o=d\">This Conf Dump</a> ]\n"
2216 "<p>Version: R" ZXID_REL " (" ZXID_COMPILE_DATE ")\n"
2217 
2218 "<pre>"
2219 "DEBUG=0x%x\n"
2220 "CPATH=%s\n"
2221 "BURL=%s\n"
2222 "AFFILIATION=%s\n"
2223 "NICE_NAME=%s\n"
2224 "BUTTON_URL=%s\n"
2225 "PREF_BUTTON_SIZE=%s\n"
2226 "ORG_NAME=%s\n"
2227 "LOCALITY=%s\n"
2228 "STATE=%s\n"
2229 "COUNTRY=%s\n"
2230 "CONTACT_ORG=%s\n"
2231 "CONTACT_NAME=%s\n"
2232 "CONTACT_EMAIL=%s\n"
2233 "CONTACT_TEL=%s\n"
2234 "FEDUSERNAME_SUFFIX=%s\n"
2235 "#ZXID_CONF_FILE_ENA=%d (compile)\n"
2236 "#ZXID_CONF_FLAG=%d (compile)\n"
2237 "NON_STANDARD_ENTITYID=%s\n"
2238 "REDIRECT_HACK_IMPOSED_URL=%s\n"
2239 "REDIRECT_HACK_ZXID_URL=%s\n"
2240 "REDIRECT_HACK_ZXID_QS=%s\n"
2241 "DEFAULTQS=%s\n"
2242 "WSP_PAT=%s\n"
2243 "UMA_PAT=%s\n"
2244 "SSO_PAT=%s\n"
2245 "WSC_SOAP_CONTENT_TYPE=%s\n"
2246 "WSC_TO_HDR=%s\n"
2247 "WSC_REPLYTO_HDR=%s\n"
2248 "WSC_ACTION_HDR=%s\n"
2249 "SOAP_ACTION_HDR=%s\n"
2250 "CDC_URL=%s\n"
2251 "CDC_CHOICE=%d\n"
2252 
2253 "LOAD_COT_CACHE=%s\n"
2254 "MD_FETCH=%d\n"
2255 "MD_POPULATE_CACHE=%d\n"
2256 "MD_CACHE_FIRST=%d\n"
2257 "MD_CACHE_LAST=%d\n"
2258 "MD_AUTHORITY=%s\n"
2259 
2260 "AUTO_CERT=%d\n"
2261 "AUTHN_REQ_SIGN=%d\n"
2262 "WANT_AUTHN_REQ_SIGNED=%d\n"
2263 "WANT_SSO_A7N_SIGNED=%d\n"
2264 "SSO_SOAP_SIGN=%d\n"
2265 "SSO_SOAP_RESP_SIGN=%d\n"
2266 "SSO_SIGN=%x\n"
2267 "WSC_SIGN=%x\n"
2268 "WSP_SIGN=%x\n"
2269 "OAZ_JWT_SIGENC_ALG=%c\n"
2270 "WSPCGICMD=%s\n"
2271 "NAMEID_ENC=%x\n"
2272 "POST_A7N_ENC=%d\n"
2273 "CANON_INOPT=%x\n"
2274 "ENC_TAIL_OPT=%x\n"
2275 "ENCKEY_OPT=%d\n"
2276 "VALID_OPT=0x%x\n"
2277 "IDPATOPT=%d\n"
2278 "DI_ALLOW_CREATE=%d\n"
2279 "DI_NID_FMT=%d\n"
2280 "DI_A7N_ENC=%d\n"
2281 "BOOTSTRAP_LEVEL=%d\n"
2282 "SHOW_CONF=%x\n"
2283 "#ZXID_ID_BITS=%d (compile)\n"
2284 "#ZXID_ID_MAX_BITS=%d (compile)\n"
2285 "#ZXID_TRUE_RAND=%d (compile)\n"
2286 "SES_ARCH_DIR=%s\n"
2287 "SES_COOKIE_NAME=%s\n"
2288 "PTM_COOKIE_NAME=%s\n"
2289 "IPPORT=%s\n"
2290 "USER_LOCAL=%d\n"
2291 "IDP_ENA=%d\n"
2292 "IDP_PXY_ENA=%d\n"
2293 "IMPS_ENA=%d\n"
2294 "AS_ENA=%d\n"
2295 "MD_AUTHORITY_ENA=%d\n"
2296 "BACKWARDS_COMPAT_ENA=%d\n"
2297 "PDP_ENA=%d\n"
2298 "CPN_ENA=%d\n"
2299 "AZ_OPT=%d\n"
2300 "AZ_FAIL_MODE=%d\n"
2301 "#ZXID_MAX_BUF=%d (compile)\n"
2302 
2303 /* *** should these be prefixed by LOG? */
2304 "LOG_ERR=%d\n"
2305 "LOG_ACT=%d\n"
2306 "LOG_ISSUE_A7N=%d\n"
2307 "LOG_ISSUE_MSG=%d\n"
2308 "LOG_RELY_A7N=%d\n"
2309 "LOG_RELY_MSG=%d\n"
2310 "LOG_ERR_IN_ACT=%d\n"
2311 "LOG_ACT_IN_ERR=%d\n"
2312 "LOG_SIGFAIL_IS_ERR=%d\n"
2313 "LOG_LEVEL=%d\n"
2314 "LOGUSER=%d\n"
2315 
2316 "SIG_FATAL=%d\n"
2317 "NOSIG_FATAL=%d\n"
2318 "MSG_SIG_OK=%d\n"
2319 "TIMEOUT_FATAL=%d\n"
2320 "AUDIENCE_FATAL=%d\n"
2321 "DUP_A7N_FATAL=%d\n"
2322 "DUP_MSG_FATAL=%d\n"
2323 "RELTO_FATAL=%d\n"
2324 "WSP_NOSIG_FATAL=%d\n"
2325 "NOTIMESTAMP_FATAL=%d\n"
2326 "REDIR_TO_CONTENT=%d\n"
2327 "REMOTE_USER_ENA=%d\n"
2328 "MAX_SOAP_RETRY=%d\n"
2329 
2330 "BEFORE_SLOP=%d\n"
2331 "AFTER_SLOP=%d\n"
2332 "TIMESKEW=%d\n"
2333 "A7NTTL=%d\n"
2334 
2335 "ANON_OK=%s\n"
2336 "OPTIONAL_LOGIN_PAT=%s\n"
2337 "ISSUE_AUTHNCTX=%s\n"
2338 "IDP_PREF_ACS_BINDING=%s\n"
2339 "MANDATORY_ATTR=%s\n"
2340 "PDP_URL=%s\n"
2341 "PDP_CALL_URL=%s\n"
2342 "XASP_VERS=%s\n"
2343 "TRUSTPDP_URL=%s\n"
2344 "MOD_SAML_ATTR_PREFIX=%s\n"
2345 "BARE_URL_ENTITYID=%d\n"
2346 "SHOW_TECH=%d\n"
2347 "WD=%s\n"
2348 
2349 "XMLDSIG_SIG_METH=%s\n"
2350 "XMLDSIG_DIGEST_ALGO=%s\n"
2351 "SAMLSIG_DIGEST_ALGO=%s\n"
2352 "BLOBSIG_DIGEST_ALGO=%s\n"
2353 
2354 "IDP_LIST_METH=%d\n"
2355 "IDP_SEL_PAGE=%s\n"
2356 "IDP_SEL_TEMPL_FILE=%s\n"
2357 "</pre>"
2358 "<textarea cols=100 rows=20>"
2359 "IDP_SEL_TEMPL=%s\n"
2360 #if 0
2361 "IDP_SEL_START=%s\n"
2362 "IDP_SEL_NEW_IDP=%s\n"
2363 "IDP_SEL_OUR_EID=%s\n"
2364 "IDP_SEL_TECH_USER=%s\n"
2365 "IDP_SEL_TECH_SITE=%s\n"
2366 "IDP_SEL_FOOTER=%s\n"
2367 "IDP_SEL_END=%s\n"
2368 #endif
2369 "</textarea><pre>\n"
2370 
2371 "AN_PAGE=%s\n"
2372 "AN_TEMPL_FILE=%s\n"
2373 "</pre><textarea cols=100 rows=20>"
2374 "AN_TEMPL=%s\n"
2375 "</textarea><pre>\n"
2376 
2377 "POST_TEMPL_FILE=%s\n"
2378 "</pre><textarea cols=100 rows=7>"
2379 "POST_TEMPL=%s\n"
2380 "</textarea><pre>\n"
2381 
2382 "ERR_PAGE=%s\n"
2383 "ERR_TEMPL_FILE=%s\n"
2384 "</pre><textarea cols=100 rows=7>"
2385 "ERR_TEMPL=%s\n"
2386 "</textarea><pre>\n"
2387 
2388 "NEW_USER_PAGE=%s\n"
2389 "RECOVER_PASSWD=%s\n"
2390 "ATSEL_PAGE=%s\n"
2391 
2392 "</pre><textarea cols=100 rows=15>"
2393 "MGMT_START=%s\n"
2394 "MGMT_LOGOUT=%s\n"
2395 "MGMT_DEFED=%s\n"
2396 "MGMT_FOOTER=%s\n"
2397 "MGMT_END=%s\n"
2398 "</textarea>"
2399 
2400 "<pre>\n"
2401 "DBG=%s\n"
2402 
2403 "REQUIRED_AUTHN_CTX=\n%s\n"
2404 "NEED=\n%s\n"
2405 "WANT=\n%s\n"
2406 "ATTRSRC=\n%s\n"
2407 "BUS_URL=\n%s\n"
2408 "BUS_PW=%s\n"
2409 "RCPT=%d\n"
2410 "INMAP=\n%s\n"
2411 "OUTMAP=\n%s\n"
2412 "PEPMAP=\n%s\n"
2413 "PEPMAP_RQOUT=\n%s\n"
2414 "PEPMAP_RQIN=\n%s\n"
2415 "PEPMAP_RSOUT=\n%s\n"
2416 "PEPMAP_RSIN=\n%s\n"
2417 "LOCALPDP_ROLE_PERMIT=\n%s\n"
2418 "LOCALPDP_ROLE_DENY=\n%s\n"
2419 "LOCALPDP_IDPNID_PERMIT=\n%s\n"
2420 "LOCALPDP_IDPNID_DENY=\n%s\n"
2421 "WSC_LOCALPDP_OBL_PLEDGE=%s\n"
2422 //"WSP_LOCALPDP_OBL_REQ=%s\n"
2423 "WSP_LOCALPDP_OBL_EMIT=%s\n"
2424 //"WSC_LOCALPDP_OBL_ACCEPT=%s\n"
2425 "UNIX_GRP_AZ_MAP=\n%s\n"
2426 "</pre>",
2427 		 cf->burl, eid,
2428 		 cf->cpath,
2429 
2430 		 errmac_debug,
2431 		 cf->cpath,
2432 		 cf->burl,
2433 		 STRNULLCHK(cf->affiliation),
2434 		 STRNULLCHK(cf->nice_name),
2435 		 STRNULLCHK(cf->button_url),
2436 		 STRNULLCHK(cf->pref_button_size),
2437 		 STRNULLCHK(cf->org_name),
2438 		 STRNULLCHK(cf->locality),
2439 		 STRNULLCHK(cf->state),
2440 		 STRNULLCHK(cf->country),
2441 		 STRNULLCHK(cf->contact_org),
2442 		 STRNULLCHK(cf->contact_name),
2443 		 STRNULLCHK(cf->contact_email),
2444 		 STRNULLCHK(cf->contact_tel),
2445 		 STRNULLCHK(cf->fedusername_suffix),
2446 		 ZXID_CONF_FILE_ENA,
2447 		 ZXID_CONF_FLAG,
2448 		 STRNULLCHK(cf->non_standard_entityid),
2449 		 STRNULLCHK(cf->redirect_hack_imposed_url),
2450 		 STRNULLCHK(cf->redirect_hack_zxid_url),
2451 		 STRNULLCHK(cf->redirect_hack_zxid_qs),
2452 		 STRNULLCHK(cf->defaultqs),
2453 		 STRNULLCHK(cf->wsp_pat),
2454 		 STRNULLCHK(cf->uma_pat),
2455 		 STRNULLCHK(cf->sso_pat),
2456 		 STRNULLCHK(cf->wsc_soap_content_type),
2457 		 STRNULLCHK(cf->wsc_to_hdr),
2458 		 STRNULLCHK(cf->wsc_replyto_hdr),
2459 		 STRNULLCHK(cf->wsc_action_hdr),
2460 		 STRNULLCHK(cf->soap_action_hdr),
2461 		 STRNULLCHK(cf->cdc_url),
2462 		 cf->cdc_choice,
2463 
2464 		 STRNULLCHK(cf->load_cot_cache),
2465 		 cf->md_fetch,
2466 		 cf->md_populate_cache,
2467 		 cf->md_cache_first,
2468 		 cf->md_cache_last,
2469 		 STRNULLCHK(cf->md_authority),
2470 
2471 		 cf->auto_cert,
2472 		 cf->authn_req_sign,
2473 		 cf->want_authn_req_signed,
2474 		 cf->want_sso_a7n_signed,
2475 		 cf->sso_soap_sign,
2476 		 cf->sso_soap_resp_sign,
2477 		 cf->sso_sign,
2478 		 cf->wsc_sign,
2479 		 cf->wsp_sign,
2480 		 cf->oaz_jwt_sigenc_alg,
2481 		 cf->wspcgicmd,
2482 		 cf->nameid_enc,
2483 		 cf->post_a7n_enc,
2484 		 cf->canon_inopt,
2485 		 cf->enc_tail_opt,
2486 		 cf->enckey_opt,
2487 		 cf->valid_opt,
2488 		 cf->idpatopt,
2489 		 cf->di_allow_create,
2490 		 cf->di_nid_fmt,
2491 		 cf->di_a7n_enc,
2492 		 cf->bootstrap_level,
2493 		 cf->show_conf,
2494 		 ZXID_ID_BITS,
2495 		 ZXID_ID_MAX_BITS,
2496 		 ZXID_TRUE_RAND,
2497 		 STRNULLCHK(cf->ses_arch_dir),
2498 		 STRNULLCHK(cf->ses_cookie_name),
2499 		 STRNULLCHK(cf->ptm_cookie_name),
2500 		 STRNULLCHK(cf->ipport),
2501 		 cf->user_local,
2502 		 cf->idp_ena,
2503 		 cf->idp_pxy_ena,
2504 		 cf->imps_ena,
2505 		 cf->as_ena,
2506 		 cf->md_authority_ena,
2507 		 cf->backwards_compat_ena,
2508 		 cf->pdp_ena,
2509 		 cf->cpn_ena,
2510 		 cf->az_opt,
2511 		 cf->az_fail_mode,
2512 		 ZXID_MAX_BUF,
2513 
2514 		 cf->log_err,
2515 		 cf->log_act,
2516 		 cf->log_issue_a7n,
2517 		 cf->log_issue_msg,
2518 		 cf->log_rely_a7n,
2519 		 cf->log_rely_msg,
2520 		 cf->log_err_in_act,
2521 		 cf->log_act_in_err,
2522 		 cf->log_sigfail_is_err,
2523 		 cf->log_level,
2524 		 cf->loguser,
2525 
2526 		 cf->sig_fatal,
2527 		 cf->nosig_fatal,
2528 		 cf->msg_sig_ok,
2529 		 cf->timeout_fatal,
2530 		 cf->audience_fatal,
2531 		 cf->dup_a7n_fatal,
2532 		 cf->dup_msg_fatal,
2533 		 cf->relto_fatal,
2534 		 cf->wsp_nosig_fatal,
2535 		 cf->notimestamp_fatal,
2536 		 cf->redir_to_content,
2537 		 cf->remote_user_ena,
2538 		 cf->max_soap_retry,
2539 
2540 		 cf->before_slop,
2541 		 cf->after_slop,
2542 		 cf->timeskew,
2543 		 cf->a7nttl,
2544 
2545 		 STRNULLCHK(cf->anon_ok),
2546 		 STRNULLCHK(cf->optional_login_pat),
2547 		 issue_authnctx->s,
2548 		 STRNULLCHK(cf->idp_pref_acs_binding),
2549 		 STRNULLCHK(cf->mandatory_attr),
2550 		 STRNULLCHK(cf->pdp_url),
2551 		 STRNULLCHK(cf->pdp_call_url),
2552 		 STRNULLCHK(cf->xasp_vers),
2553 		 STRNULLCHK(cf->trustpdp_url),
2554 		 STRNULLCHK(cf->mod_saml_attr_prefix),
2555 		 cf->bare_url_entityid,
2556 		 cf->show_tech,
2557 		 STRNULLCHK(cf->wd),
2558 		 STRNULLCHK(cf->xmldsig_sig_meth),
2559 		 STRNULLCHK(cf->xmldsig_digest_algo),
2560 		 STRNULLCHK(cf->samlsig_digest_algo),
2561 		 STRNULLCHK(cf->blobsig_digest_algo),
2562 
2563 		 cf->idp_list_meth,
2564 		 STRNULLCHK(cf->idp_sel_page),
2565 		 STRNULLCHK(cf->idp_sel_templ_file),
2566 		 STRNULLCHK(cf->idp_sel_templ),
2567 #if 0
2568 		 STRNULLCHK(cf->idp_sel_start),
2569 		 STRNULLCHK(cf->idp_sel_new_idp),
2570 		 STRNULLCHK(cf->idp_sel_our_eid),
2571 		 STRNULLCHK(cf->idp_sel_tech_user),
2572 		 STRNULLCHK(cf->idp_sel_tech_site),
2573 		 STRNULLCHK(cf->idp_sel_footer),
2574 		 STRNULLCHK(cf->idp_sel_end),
2575 #endif
2576 		 STRNULLCHK(cf->an_page),
2577 		 STRNULLCHK(cf->an_templ_file),
2578 		 STRNULLCHK(cf->an_templ),
2579 
2580 		 STRNULLCHK(cf->post_templ_file),
2581 		 STRNULLCHK(cf->post_templ),
2582 
2583 		 STRNULLCHK(cf->err_page),
2584 		 STRNULLCHK(cf->err_templ_file),
2585 		 STRNULLCHK(cf->err_templ),
2586 
2587 		 STRNULLCHK(cf->new_user_page),
2588 		 STRNULLCHK(cf->recover_passwd),
2589 		 STRNULLCHK(cf->atsel_page),
2590 
2591 		 STRNULLCHK(cf->mgmt_start),
2592 		 STRNULLCHK(cf->mgmt_logout),
2593 		 STRNULLCHK(cf->mgmt_defed),
2594 		 STRNULLCHK(cf->mgmt_footer),
2595 		 STRNULLCHK(cf->mgmt_end),
2596 
2597 		 STRNULLCHK(cf->dbg),
2598 
2599 		 required_authnctx->s,
2600 		 need->s,
2601 		 want->s,
2602 		 attrsrc->s,
2603 		 bus_url->s,
2604 		 STRNULLCHK(cf->bus_pw),
2605 		 cf->bus_rcpt,
2606 		 inmap->s,
2607 		 outmap->s,
2608 		 pepmap->s,
2609 		 pepmap_rqout->s,
2610 		 pepmap_rqin->s,
2611 		 pepmap_rsout->s,
2612 		 pepmap_rsin->s,
2613 		 localpdp_role_permit->s,
2614 		 localpdp_role_deny->s,
2615 		 localpdp_idpnid_permit->s,
2616 		 localpdp_idpnid_deny->s,
2617 		 STRNULLCHK(cf->wsc_localpdp_obl_pledge),
2618 		 //STRNULLCHK(cf->wsp_localpdp_obl_req),
2619 		 STRNULLCHK(cf->wsp_localpdp_obl_emit),
2620 		 //STRNULLCHK(cf->wsc_localpdp_obl_accept)
2621 		 unix_grp_az_map->s //,
2622 	 );
2623 }
2624 
2625 /* EOF  --  zxidconf.c */
2626