LCOV - code coverage report
Current view: top level - zxid - zxidsimp.c (source / functions) Hit Total Coverage
Test: ZXID Code Coverage Lines: 418 667 62.7 %
Date: 2010-12-19 Functions: 26 35 74.3 %
Branches: 384 923 41.6 %

           Branch data     Line data    Source code
       1                 :            : /* zxidsimp.c  -  Handwritten zxid_simple() API
       2                 :            :  * Copyright (c) 2009-2010 Sampo Kellomaki (sampo@iki.fi), All Rights Reserved.
       3                 :            :  * Copyright (c) 2007-2009 Symlabs (symlabs@symlabs.com), All Rights Reserved.
       4                 :            :  * Author: Sampo Kellomaki (sampo@iki.fi)
       5                 :            :  * This is confidential unpublished proprietary source code of the author.
       6                 :            :  * NO WARRANTY, not even implied warranties. Contains trade secrets.
       7                 :            :  * Distribution prohibited unless authorized in writing.
       8                 :            :  * Licensed under Apache License 2.0, see file COPYING.
       9                 :            :  * $Id: zxidsimp.c,v 1.64 2010-01-08 02:10:09 sampo Exp $
      10                 :            :  *
      11                 :            :  * 17.1.2007, created --Sampo
      12                 :            :  * 2.2.2007,  improved the LDIF return --Sampo
      13                 :            :  * 9.3.2008,  refactored the logged in and need login cases to subroutines --Sampo
      14                 :            :  * 7.10.2008, added documentation --Sampo
      15                 :            :  * 4.9.2009,  added attribute broker and PEP functionality --Sampo
      16                 :            :  * 31.5.2010, moved local PEP and attribute broker functionality to zxidpep.c --Sampo
      17                 :            :  * 7.9.2010,  tweaked the az requests to separate ses az from resource az --Sampo
      18                 :            :  * 22.9.2010, added People Service invitation resolution --Sampo
      19                 :            :  *
      20                 :            :  * Login button abbreviations
      21                 :            :  * A2 = SAML 2.0 Artifact Profile
      22                 :            :  * P2 = SAML 2.0 POST Profile
      23                 :            :  * S2 = SAML 2.0 POST Simple Sign
      24                 :            :  * A12 = Liberty ID-FF 1.2 Artifact Profile
      25                 :            :  * P12 = Liberty ID-FF 1.2 POST Profile
      26                 :            :  * A1 = Bare SAML 1.x Artifact Profile
      27                 :            :  * P1 = Base SAML 1.x POST Profile
      28                 :            :  * A0 = WS-Federation Artifact Profile
      29                 :            :  * P0 = WS-Federation POST Profile
      30                 :            :  */
      31                 :            : 
      32                 :            : #include "platform.h"  /* needed on Win32 for pthread_mutex_lock() et al. */
      33                 :            : 
      34                 :            : #include <memory.h>
      35                 :            : #include <string.h>
      36                 :            : 
      37                 :            : #include "errmac.h"
      38                 :            : #include "zx.h"
      39                 :            : #include "zxid.h"
      40                 :            : #include "zxidpriv.h"
      41                 :            : #include "zxidutil.h"
      42                 :            : #include "zxidconf.h"
      43                 :            : #include "c/zxidvers.h"
      44                 :            : #include "c/zx-md-data.h"
      45                 :            : 
      46                 :            : /*() Convert configuration string ~conf~ to configuration object ~cf~. See zxid_conf_to_cf() */
      47                 :            : 
      48                 :            : /* Called by:  dirconf, main x2, zxid_az, zxid_az_base, zxid_fed_mgmt_len, zxid_idp_list_len, zxid_idp_select_len, zxid_new_conf_to_cf, zxid_simple_len */
      49                 :            : int zxid_conf_to_cf_len(zxid_conf* cf, int conf_len, const char* conf)
      50                 :        262 : {
      51                 :            : #if 1
      52         [ +  + ]:        262 :   if (!cf->ctx) {
      53                 :         71 :     cf->ctx = zx_init_ctx();
      54         [ -  + ]:         71 :     if (!cf->ctx) {
      55                 :          0 :       ERR("Failed to alloc zx_ctx %d",0);
      56                 :          0 :       exit(2);
      57                 :            :     }
      58                 :            :   }
      59                 :        262 :   zxid_init_conf(cf, ZXID_PATH);
      60                 :            : #ifdef USE_CURL
      61   [ -  +  #  # ]:        262 :   LOCK(cf->curl_mx, "curl init");
      62                 :        262 :   cf->curl = curl_easy_init();
      63         [ -  + ]:        262 :   if (!cf->curl) {
      64                 :          0 :     ERR("Failed to initialize libcurl %d",0);
      65   [ #  #  #  # ]:          0 :     UNLOCK(cf->curl_mx, "curl init");
      66                 :          0 :     exit(2);
      67                 :            :   }
      68   [ -  +  #  # ]:        262 :   UNLOCK(cf->curl_mx, "curl init");
      69                 :            : #endif
      70                 :            : #else
      71                 :            :   zxid_init_conf_ctx(cf, ZXID_PATH /* N.B. Often this is overridden. */);
      72                 :            : #endif
      73                 :            : #if defined(ZXID_CONF_FILE) || defined(ZXID_CONF_FLAG)
      74                 :            :   {
      75                 :            :     char* buf;
      76                 :            :     char* cc;
      77   [ +  -  +  + ]:        262 :     int len, clen = conf_len == -1 && conf ? strlen(conf) : conf_len;
      78                 :            : 
      79   [ +  +  -  +  :        262 :     if (!conf || conf_len < 5 || memcmp(conf, "PATH=", 5)) {
                   #  # ]
      80                 :            :       /* No conf, or conf does not start by PATH: read from file default values */
      81                 :        262 :       buf = read_all_alloc(cf->ctx, "-conf_to_cf", 1, &len, "%szxid.conf", cf->path);
      82   [ +  -  +  - ]:        262 :       if (buf && len)
      83                 :        262 :         zxid_parse_conf_raw(cf, len, buf);
      84                 :            :     }
      85                 :            :     
      86   [ +  +  +  - ]:        262 :     if (conf && conf_len) {
      87                 :            :       /* Copy the conf string because we are going to modify it in place. */
      88                 :        197 :       cc = ZX_ALLOC(cf->ctx, clen+1);
      89                 :        197 :       memcpy(cc, conf, clen);
      90                 :        197 :       cc[clen] = 0;
      91                 :        197 :       zxid_parse_conf_raw(cf, clen, cc);
      92                 :            :     }
      93                 :            :   }
      94                 :            : #endif
      95                 :        262 :   return 0;
      96                 :            : }
      97                 :            : 
      98                 :            : /*() Create new ZXID configuration object given configuration string and
      99                 :            :  * possibly configuration file.
     100                 :            :  *
     101                 :            :  * zxid_new_conf_to_cf() parses first the default config file, then the string (i.e. string
     102                 :            :  * can override config file). However, if the string contains PATH specification,
     103                 :            :  * then the config file is reread from (presumably new) location and overrides
     104                 :            :  * eariler config.
     105                 :            :  *
     106                 :            :  * conf::   Configuration string
     107                 :            :  * return:: Configuration object */
     108                 :            : 
     109                 :            : /* Called by:  main x6, opt x2, zxcall_main, zxcot_main, zxidwspcgi_main x2 */
     110                 :            : zxid_conf* zxid_new_conf_to_cf(const char* conf)
     111                 :         71 : {
     112                 :         71 :   zxid_conf* cf = malloc(sizeof(zxid_conf));  /* *** direct use of malloc */
     113   [ +  +  -  + ]:         71 :   D("malloc %p size=%d", cf, sizeof(zxid_conf));
     114         [ -  + ]:         71 :   if (!cf) {
     115                 :          0 :     ERR("out-of-memory %d", sizeof(zxid_conf));
     116                 :          0 :     exit(1); /* *** perhaps too severe! */
     117                 :            :   }
     118                 :         71 :   cf = ZERO(cf, sizeof(zxid_conf));
     119                 :         71 :   zxid_conf_to_cf_len(cf, -1, conf);
     120                 :         71 :   return cf;
     121                 :            : }
     122                 :            : 
     123                 :            : /* ------------ zxid_fed_mgmt() ------------ */
     124                 :            : 
     125                 :            : /*(i) Generate Single Logout button and possibly other federation management
     126                 :            :  * buttons for use in logged in state of the app HTML GUI.
     127                 :            :  *
     128                 :            :  * Either outputs the management screen to stdout or returns string of HTML (at specified
     129                 :            :  * automation level). If res_len is supplied, the string length is returned in res_len.
     130                 :            :  * Otherwise you can just run strlen() on return value.
     131                 :            :  *
     132                 :            :  * N.B. More complete documentation is available in <<link: zxid-simple.pd>> (*** fixme) */
     133                 :            : 
     134                 :            : /* Called by:  zxid_fed_mgmt_len, zxid_simple_ses_active_cf */
     135                 :            : char* zxid_fed_mgmt_cf(zxid_conf* cf, int* res_len, int sid_len, char* sid, int auto_flags)
     136                 :          3 : {
     137                 :            :   char* res;
     138                 :            :   struct zx_str* ss;
     139                 :            :   struct zx_str* ss2;
     140   [ +  -  +  - ]:          3 :   int slen = sid_len == -1 && sid ? strlen(sid) : sid_len;
     141         [ +  - ]:          3 :   if (auto_flags & ZXID_AUTO_DEBUG) zxid_set_opt(cf, 1, 1);
     142                 :            : 
     143         [ +  - ]:          3 :   if (cf->log_level>1)
     144         [ +  - ]:          3 :     zxlog(cf, 0, 0, 0, 0, 0, 0, 0, "N", "W", "MGMT", 0, "sid(%.*s)", sid_len, STRNULLCHK(sid));
     145                 :            :   
     146   [ +  -  +  - ]:          6 :   if ((auto_flags & ZXID_AUTO_FORMT) && (auto_flags & ZXID_AUTO_FORMF))
     147   [ -  +  +  - ]:          3 :     ss = zx_strf(cf->ctx,
     148                 :            :                  "%s"
     149                 :            : #ifdef ZXID_USE_POST
     150                 :            :                  "<form method=post action=\"%s?o=P\">\n"
     151                 :            : #else
     152                 :            :                  "<form method=get action=\"%s\">\n"
     153                 :            : #endif
     154                 :            :                  "<input type=hidden name=s value=\"%.*s\">\n"
     155                 :            :                  "%s%s\n"
     156                 :            :                  "</form>%s%s%s%s",
     157                 :            :                  cf->mgmt_start,
     158                 :            :                  cf->url,
     159                 :            :                  slen, STRNULLCHK(sid),
     160                 :            :                  cf->mgmt_logout, cf->mgmt_defed,
     161                 :            :                  cf->mgmt_footer, zxid_version_str(), STRNULLCHK(cf->dbg), cf->mgmt_end);
     162         [ #  # ]:          0 :   else if (auto_flags & ZXID_AUTO_FORMT)
     163         [ #  # ]:          0 :     ss = zx_strf(cf->ctx,
     164                 :            : #ifdef ZXID_USE_POST
     165                 :            :                  "<form method=post action=\"%s?o=P\">\n"
     166                 :            : #else
     167                 :            :                  "<form method=get action=\"%s\">\n"
     168                 :            : #endif
     169                 :            :                  "<input type=hidden name=s value=\"%.*s\">"
     170                 :            :                  "%s%s\n"
     171                 :            :                  "</form>",
     172                 :            :                  cf->url,
     173                 :            :                  slen, STRNULLCHK(sid),
     174                 :            :                  cf->mgmt_logout, cf->mgmt_defed);
     175         [ #  # ]:          0 :   else if (auto_flags & ZXID_AUTO_FORMF)
     176         [ #  # ]:          0 :     ss = zx_strf(cf->ctx,
     177                 :            :                  "<input type=hidden name=s value=\"%.*s\">"
     178                 :            :                  "%s%s\n",
     179                 :            :                  slen, STRNULLCHK(sid),
     180                 :            :                  cf->mgmt_logout, cf->mgmt_defed);
     181                 :            :   else
     182                 :          0 :     ss = zx_dup_str(cf->ctx, "");
     183                 :            : 
     184                 :            : #if 0
     185                 :            :   printf("COOKIE: foo\r\n");
     186                 :            :   if (qs) printf("QS(%s)\n", qs);
     187                 :            :   if (got>0) printf("GOT(%.*s)\n", got, buf);
     188                 :            :   if (cgi->err) printf("<p><font color=red><i>%s</i></font></p>\n", cgi->err);
     189                 :            :   if (cgi->msg) printf("<p><i>%s</i></p>\n", cgi->msg);
     190                 :            :   printf("User:<input name=user> PW:<input name=pw type=password>");
     191                 :            :   printf("<input name=login value=\" Login \" type=submit>");
     192                 :            :   printf("<h3>Technical options (typically hidden fields on production site)</h3>\n");
     193                 :            :   printf("sid(%s) nid(%s) <a href=\"zxid?s=%s\">Reload</a>", ses->sid, ses->nid, ses->sid);
     194                 :            :   if (cgi->dbg) printf("<p><form><textarea cols=100 row=10>%s</textarea></form>\n", cgi->dbg);
     195                 :            : #endif
     196                 :            : 
     197   [ +  -  -  + ]:          3 :   if (auto_flags & ZXID_AUTO_MGMTC && auto_flags & ZXID_AUTO_MGMTH) {  /* Both H&C: CGI */
     198                 :          0 :     printf("Content-Type: text/html" CRLF "Content-Length: %d" CRLF2 "%.*s",
     199                 :            :            ss->len, ss->len, ss->s);
     200                 :          0 :     zx_str_free(cf->ctx, ss);
     201                 :          0 :     return 0;
     202                 :            :   }
     203                 :            : 
     204         [ +  - ]:          3 :   if (auto_flags & (ZXID_AUTO_MGMTC | ZXID_AUTO_MGMTH)) {
     205         [ -  + ]:          3 :     if (auto_flags & ZXID_AUTO_MGMTH) {  /* H only: return both H and C */
     206   [ #  #  #  # ]:          0 :       D("With headers 0x%x", auto_flags);
     207                 :          0 :       ss2 = zx_strf(cf->ctx, "Content-Type: text/html" CRLF "Content-Length: %d" CRLF2 "%.*s",
     208                 :            :                     ss->len, ss->len, ss->s);
     209                 :          0 :       zx_str_free(cf->ctx, ss);
     210                 :            :     } else {
     211   [ +  -  -  + ]:          3 :       D("No headers 0x%x", auto_flags);
     212                 :          3 :       ss2 = ss;       /* C only */
     213                 :            :     }
     214                 :          3 :     res = ss2->s;
     215                 :            :     DD("res(%s)", res);
     216         [ -  + ]:          3 :     if (res_len)
     217                 :          0 :       *res_len = ss2->len;
     218                 :          3 :     ZX_FREE(cf->ctx, ss2);
     219                 :          3 :     return res;
     220                 :            :   }
     221   [ #  #  #  # ]:          0 :   D("m(%.*s)", ss->len, ss->s);
     222                 :          0 :   zx_str_free(cf->ctx, ss);
     223         [ #  # ]:          0 :   if (res_len)
     224                 :          0 :     *res_len = 1;
     225                 :          0 :   return zx_dup_cstr(cf->ctx, "m");   /* Neither H nor C */
     226                 :            : }
     227                 :            : 
     228                 :            : /* Called by:  zxid_fed_mgmt */
     229                 :          0 : char* zxid_fed_mgmt_len(int conf_len, char* conf, int* res_len, char* sid, int auto_flags) {
     230                 :            :   zxid_conf cf;
     231                 :          0 :   zxid_conf_to_cf_len(&cf, conf_len, conf);
     232                 :          0 :   return zxid_fed_mgmt_cf(&cf, 0, -1, sid, auto_flags);
     233                 :            : }
     234                 :            : 
     235                 :            : /* Called by: */
     236                 :          0 : char* zxid_fed_mgmt(char* conf, char* sid, int auto_flags) {
     237                 :          0 :   return zxid_fed_mgmt_len(-1, conf, 0, sid, auto_flags);
     238                 :            : }
     239                 :            : 
     240                 :            : /* ------------ zxid_an_page() ------------ */
     241                 :            : 
     242                 :            : #define BBMATCH(k, key, lim) (sizeof(k)-1 == (lim)-(key) && !memcmp((k), (key), sizeof(k)-1))
     243                 :            : 
     244                 :            : /*() Bang-bang expansions (!!VAR) understood in the templates. */
     245                 :            : 
     246                 :            : /* Called by:  zxid_template_page_cf */
     247                 :            : static char* zxid_map_bangbang(zxid_conf* cf, zxid_cgi* cgi, const char* key, const char* lim, int auto_flags)
     248                 :        381 : {
     249                 :            :   char* s;
     250                 :            :   struct zx_str* ss;
     251                 :            :   
     252   [ +  +  +  +  :        381 :   switch (*key) {
          +  +  +  +  +  
                   +  - ]
     253                 :            :   case 'A':
     254   [ +  -  +  - ]:         20 :     if (BBMATCH("ACTION_URL", key, lim)) return cgi->action_url;
     255                 :          0 :     break;
     256                 :            :   case 'D':
     257   [ +  -  +  - ]:         46 :     if (BBMATCH("DBG", key, lim)) return cgi->dbg;
     258                 :          0 :     break;
     259                 :            :   case 'E':
     260   [ +  -  +  + ]:         96 :     if (BBMATCH("EID", key, lim)) {
     261                 :         50 :       ss = zxid_my_ent_id(cf);
     262                 :         50 :       s = ss->s; ZX_FREE(cf->ctx, ss);
     263                 :         50 :       return s;
     264                 :            :     }
     265   [ +  -  +  - ]:         46 :     if (BBMATCH("ERR", key, lim)) return cgi->err;
     266                 :          0 :     break;
     267                 :            :   case 'I':
     268   [ +  -  +  - ]:         20 :     if (BBMATCH("IDP_LIST", key, lim)) return zxid_idp_list_cf_cgi(cf, cgi, 0, auto_flags);
     269                 :          0 :     break;
     270                 :            :   case 'M':
     271   [ +  -  +  - ]:         46 :     if (BBMATCH("MSG", key, lim)) return cgi->msg;
     272                 :          0 :     break;
     273                 :            :   case 'U':
     274   [ +  -  +  - ]:         26 :     if (BBMATCH("URL", key, lim)) return cf->url;
     275                 :          0 :     break;
     276                 :            :   case 'R':
     277   [ +  -  +  - ]:         25 :     if (BBMATCH("RS", key, lim)) return cgi->rs;
     278                 :          0 :     break;
     279                 :            :   case 'S':
     280   [ +  +  +  - ]:         65 :     if (BBMATCH("SIG", key, lim)) return cgi->sig;
     281   [ +  +  +  + ]:         60 :     if (BBMATCH("SP_EID", key, lim)) return cgi->sp_eid;
     282   [ +  +  +  - ]:         50 :     if (BBMATCH("SP_DPY_NAME", key, lim)) return cgi->sp_dpy_name;
     283   [ +  +  +  - ]:         45 :     if (BBMATCH("SSOREQ", key, lim)) return cgi->ssoreq;
     284   [ +  +  +  - ]:         40 :     if (BBMATCH("SAML_ART", key, lim)) return cgi->saml_art;
     285   [ +  -  +  - ]:         20 :     if (BBMATCH("SAML_RESP", key, lim)) return cgi->saml_resp;
     286                 :          0 :     break;
     287                 :            :   case 'V':
     288   [ +  -  +  - ]:         31 :     if (BBMATCH("VERSION", key, lim)) return zxid_version_str();
     289                 :          0 :     break;
     290                 :            :   case 'Z':
     291   [ +  -  +  - ]:          6 :     if (BBMATCH("ZXAPP", key, lim)) return cgi->zxapp;
     292                 :            :     break;
     293                 :            :   }
     294   [ #  #  #  # ]:          0 :   D("Unmatched bangbang key(%.*s), taken as empty.", lim-key, key);
     295                 :          0 :   return 0;
     296                 :            : }
     297                 :            : 
     298                 :            : /*() Expand a template. Only selected !!VAR expansions supported. No IFs or loops. */
     299                 :            : 
     300                 :            : /* Called by:  zxid_idp_select_zxstr_cf_cgi, zxid_saml2_post_enc, zxid_simple_idp_show_an, zxid_simple_show_err */
     301                 :            : struct zx_str* zxid_template_page_cf(zxid_conf* cf, zxid_cgi* cgi, const char* templ_path, const char* default_templ, int size_hint, int auto_flags)
     302                 :         31 : {
     303                 :            :   char buf[8192];
     304                 :            :   const char* templ;
     305                 :            :   const char* tp;
     306                 :            :   const char* tq;
     307                 :            :   char* pp;
     308                 :            :   struct zx_str* ss;
     309                 :         31 :   int len, got = read_all(sizeof(buf)-1, buf, "templ", 1, "%s", templ_path);
     310         [ -  + ]:         31 :   if (got <= 0) {
     311   [ #  #  #  # ]:          0 :     D("Template at path(%s) not found. Using default template.", templ_path);
     312                 :          0 :     templ = default_templ;
     313         [ -  + ]:         31 :   } else if (got == sizeof(buf)-1) {
     314                 :          0 :     ERR("Template at path(%s) does not fit in buffer of %d. Using default template.", templ_path, sizeof(buf)-1);
     315                 :          0 :     templ = default_templ;
     316                 :            :   } else
     317                 :         31 :     templ = buf;
     318                 :            :   while (1) {  /* Try rendering, iterate if expansion is needed. */
     319                 :         46 :     tp = templ;
     320                 :         46 :     ss = zx_new_len_str(cf->ctx, strlen(tp) + size_hint);
     321   [ +  +  +  - ]:      45508 :     for (pp = ss->s; *tp && pp < ss->s + ss->len; ) {
     322   [ +  +  +  +  :      45431 :       if (tp[0] == '!' && tp[1] == '!' && AZaz_(tp[2])) {
          +  -  +  -  -  
             +  #  #  #  
                      # ]
     323   [ +  +  +  +  :        381 :         for (tq = tp+=2; AZaz_(*tp); ++tp) ;
          +  -  -  +  #  
                      # ]
     324                 :        381 :         tq = zxid_map_bangbang(cf, cgi, tq, tp, auto_flags);
     325   [ +  +  +  + ]:        381 :         if (!tq || !*tq)
     326                 :            :           continue;
     327                 :        212 :         len = strlen(tq);
     328         [ +  + ]:        212 :         if (pp + len >= ss->s + ss->len) {
     329                 :         15 :           pp += len;
     330                 :         15 :           break;
     331                 :            :         }
     332                 :        197 :         memcpy(pp, tq, len);
     333                 :        197 :         pp += len;
     334                 :        197 :         continue;
     335                 :            :       }
     336                 :      45050 :       *pp++ = *tp++;
     337                 :            :     }
     338         [ +  + ]:         46 :     if (pp >= ss->s + ss->len) {
     339                 :         15 :       INFO("Expansion of template too big. Does not fit in %d. Expanding.", ss->len);
     340                 :         15 :       size_hint += size_hint;  /* Double it */
     341                 :            :       continue;
     342                 :            :     }
     343                 :            :     break;
     344                 :         15 :   }
     345                 :         31 :   *pp = 0;
     346                 :         31 :   ss->len = pp - ss->s;
     347                 :         31 :   return ss;
     348                 :            : }
     349                 :            : 
     350                 :            : /* ------------ zxid_idp_list() ------------ */
     351                 :            : 
     352                 :            : /*(i) Generate IdP selection buttons (Login buttons) for the IdPs that are
     353                 :            :  * members of our Circle of Trust (CoT). This can be used as component for
     354                 :            :  * developing your application specific (HTML) login screen.
     355                 :            :  *
     356                 :            :  * N.B. More complete documentation is available in <<link: zxid-simple.pd>> (*** fixme) */
     357                 :            : 
     358                 :            : /* Called by:  zxid_idp_list_cf, zxid_idp_select_zxstr_cf_cgi, zxid_map_bangbang */
     359                 :            : char* zxid_idp_list_cf_cgi(zxid_conf* cf, zxid_cgi* cgi, int* res_len, int auto_flags)
     360                 :         20 : {
     361                 :            :   int i;
     362                 :            :   char* s;
     363                 :            :   char mark[32];
     364                 :            :   struct zx_str* ss;
     365                 :            :   struct zx_str* dd;
     366                 :            :   zxid_entity* idp;
     367                 :            :   zxid_entity* idp_cdc;
     368         [ +  - ]:         20 :   if (auto_flags & ZXID_AUTO_DEBUG) zxid_set_opt(cf, 1, 1);
     369                 :         20 :   idp = zxid_load_cot_cache(cf);
     370         [ -  + ]:         20 :   if (!idp) {
     371   [ #  #  #  # ]:          0 :     D("No IdP's found %p", res_len);
     372         [ #  # ]:          0 :     if (res_len)
     373                 :          0 :       *res_len = 0;
     374                 :          0 :     return "";
     375                 :            :   }
     376                 :            :   
     377   [ +  -  +  - ]:         40 :   if ((auto_flags & ZXID_AUTO_FORMT) && (auto_flags & ZXID_AUTO_FORMF))
     378                 :         20 :     ss = zx_dup_str(cf->ctx, "<h3>Login Using Known IdP</h3>\n");
     379                 :            :   else
     380                 :          0 :     ss = zx_dup_str(cf->ctx, "");
     381                 :            : 
     382         [ -  + ]:         20 :   if (cf->idp_list_meth == ZXID_IDP_LIST_POPUP) {
     383                 :          0 :     dd = zx_strf(cf->ctx, "%.*s<select name=d>\n", ss->len, ss->s);
     384                 :          0 :     zx_str_free(cf->ctx, ss);
     385                 :          0 :     ss = dd;
     386                 :            :   }
     387                 :            : 
     388   [ +  -  -  + ]:         20 :   D("Starting IdP list processing... %p", idp);
     389         [ +  + ]:        409 :   for (; idp; idp = idp->n) {
     390         [ +  + ]:        389 :     if (!idp->ed->IDPSSODescriptor)
     391                 :        125 :       continue;
     392                 :            :     
     393                 :        264 :     mark[0] = 0;
     394         [ +  - ]:        264 :     if (cgi) {    /* Was IdP recommended in IdP list supplied via CDC? See zxid_cdc_check() */
     395                 :        264 :       for (idp_cdc = cgi->idp_list, i=1;
     396   [ -  +  #  # ]:        528 :            idp_cdc && idp_cdc != idp;
     397                 :          0 :            idp_cdc = idp_cdc->n_cdc, ++i);
     398   [ -  +  #  #  :        264 :       if (cf->cdc_choice == ZXID_CDC_CHOICE_UI_ONLY_CDC && cgi->idp_list && !idp_cdc)
                   #  # ]
     399                 :          0 :         continue;
     400         [ -  + ]:        264 :       if (idp_cdc) {
     401                 :          0 :         snprintf(mark, sizeof(mark), " CDC %d", i);
     402                 :          0 :         mark[sizeof(mark)-1] = 0;
     403                 :            :       }
     404                 :            :     }
     405                 :            : 
     406      [ -  -  + ]:        264 :     switch (cf->idp_list_meth) {
     407                 :            :     default:
     408                 :          0 :       ERR("Unsupported IDP_LIST_METH=%d, reverting to popup.", cf->idp_list_meth);
     409                 :          0 :       cf->idp_list_meth = ZXID_IDP_LIST_POPUP;
     410                 :            :       /* fall thru */
     411                 :            :     case ZXID_IDP_LIST_POPUP:
     412         [ #  # ]:          0 :       dd = zx_strf(cf->ctx, "%.*s"
     413                 :            :                    "<option value=\"%s\"> %s (%s) %s\n",
     414                 :            :                    ss->len, ss->s, idp->eid, STRNULLCHK(idp->dpy_name), idp->eid, mark);
     415                 :          0 :       break;
     416                 :            :     case ZXID_IDP_LIST_BUTTON:
     417         [ -  + ]:        264 :       if (cf->show_tech) {
     418   [ #  #  #  #  :          0 :         dd = zx_strf(cf->ctx, "%.*s"
             #  #  #  # ]
     419                 :            :                      "<input type=submit name=\"l0%s\" value=\" Login with %s (%s)\">\n"
     420                 :            :                      "<input type=submit name=\"l1%s\" value=\" Login with %s (%s) (A2) \">\n"
     421                 :            :                      "<input type=submit name=\"l2%s\" value=\" Login with %s (%s) (P2) \">\n"
     422                 :            :                      "<input type=submit name=\"l5%s\" value=\" Login with %s (%s) (S2) \">%s<br>\n",
     423                 :            :                      ss->len, ss->s,
     424                 :            :                      idp->eid, STRNULLCHK(idp->dpy_name), idp->eid,
     425                 :            :                      idp->eid, STRNULLCHK(idp->dpy_name), idp->eid,
     426                 :            :                      idp->eid, STRNULLCHK(idp->dpy_name), idp->eid,
     427                 :            :                      idp->eid, STRNULLCHK(idp->dpy_name), idp->eid,
     428                 :            :                      mark);
     429                 :            :       } else {
     430         [ +  + ]:        264 :         dd = zx_strf(cf->ctx, "%.*s"
     431                 :            :                      "<input type=submit name=\"l0%s\" value=\" Login with %s (%s) \">%s<br>\n",
     432                 :            :                      ss->len, ss->s, idp->eid, STRNULLCHK(idp->dpy_name), idp->eid, mark);
     433                 :            :       }
     434                 :            :       break;
     435                 :            :     }
     436                 :        264 :     zx_str_free(cf->ctx, ss);
     437                 :        264 :     ss = dd;
     438                 :            :   }
     439         [ -  + ]:         20 :   if (cf->idp_list_meth == ZXID_IDP_LIST_POPUP) {
     440         [ #  # ]:          0 :     if (cf->show_tech) {
     441                 :          0 :       dd = zx_strf(cf->ctx, "%.*s</select>"
     442                 :            :                    "<input type=submit name=\"l0\" value=\" Login \">\n"
     443                 :            :                    "<input type=submit name=\"l1\" value=\" Login (A2) \">\n"
     444                 :            :                    "<input type=submit name=\"l2\" value=\" Login (P2) \">\n"
     445                 :            :                    "<input type=submit name=\"l5\" value=\" Login (S2) \"><br>\n",
     446                 :            :                    ss->len, ss->s);
     447                 :            :     } else {
     448                 :          0 :       dd = zx_strf(cf->ctx, "%.*s</select>"
     449                 :            :                    "<input type=submit name=\"l0\" value=\" Login \"><br>\n",
     450                 :            :                    ss->len, ss->s);
     451                 :            :     }
     452                 :          0 :     zx_str_free(cf->ctx, ss);
     453                 :          0 :     ss = dd;
     454                 :            :   }
     455                 :            : 
     456                 :         20 :   s = ss->s;
     457   [ +  -  -  + ]:         20 :   D("IdP list(%s)", s);
     458         [ -  + ]:         20 :   if (res_len)
     459                 :          0 :     *res_len = ss->len;
     460                 :         20 :   ZX_FREE(cf->ctx, ss);
     461                 :         20 :   return s;
     462                 :            : }
     463                 :            : 
     464                 :            : /* Called by:  zxid_idp_list_len */
     465                 :          0 : char* zxid_idp_list_cf(zxid_conf* cf, int* res_len, int auto_flags) {
     466                 :          0 :   return zxid_idp_list_cf_cgi(cf, 0, res_len, auto_flags);
     467                 :            : }
     468                 :            : 
     469                 :            : /* Called by:  zxid_idp_list */
     470                 :          0 : char* zxid_idp_list_len(int conf_len, char* conf, int* res_len, int auto_flags) {
     471                 :            :   zxid_conf cf;
     472                 :          0 :   zxid_conf_to_cf_len(&cf, conf_len, conf);
     473                 :          0 :   return zxid_idp_list_cf(&cf, 0, auto_flags);
     474                 :            : }
     475                 :            : 
     476                 :            : /* Called by: */
     477                 :          0 : char* zxid_idp_list(char* conf, int auto_flags) {
     478                 :          0 :   return zxid_idp_list_len(-1, conf, 0, auto_flags);
     479                 :            : }
     480                 :            : 
     481                 :            : #define FLDCHK(x,y) (x && x->y ? x->y : "")
     482                 :            : 
     483                 :            : /*(i) Render entire IdP selection screen. You may use this code, possibly adjusted
     484                 :            :  * by some configuration options (see zxidconf.h), or you may choose to develop
     485                 :            :  * your own IdP selection screen from scratch.
     486                 :            :  *
     487                 :            :  * N.B. More complete documentation is available in <<link: zxid-simple.pd>> (*** fixme) */
     488                 :            : 
     489                 :            : /* Called by:  zxid_idp_select_zxstr_cf, zxid_simple_show_idp_sel */
     490                 :            : struct zx_str* zxid_idp_select_zxstr_cf_cgi(zxid_conf* cf, zxid_cgi* cgi, int auto_flags)
     491                 :         20 : {
     492                 :         20 :   struct zx_str* eid=0;
     493                 :            :   struct zx_str* ss;
     494                 :            : 
     495   [ +  -  +  -  :         20 :   D("HERE %p e(%s) m(%s) d(%s)", eid, FLDCHK(cgi, err), FLDCHK(cgi, msg), FLDCHK(cgi, dbg));
          -  +  +  -  +  
          +  +  -  +  +  
                   -  + ]
     496         [ +  - ]:         20 :   if (cf->log_level>1)
     497                 :         20 :     zxlog(cf, 0,0,0,0,0,0,0, "N", "W", "IDPSEL", 0, 0);
     498                 :            : 
     499                 :            : #if 1
     500                 :         20 :   ss = zxid_template_page_cf(cf, cgi, cf->idp_sel_templ_file, cf->idp_sel_templ, 4096, auto_flags);
     501                 :            : #else
     502                 :            :   if (cf->idp_sel_our_eid && cf->idp_sel_our_eid[0])
     503                 :            :     eid = zxid_my_ent_id(cf);
     504                 :            :   char* idp_list = zxid_idp_list_cf_cgi(cf, cgi, 0, auto_flags);
     505                 :            :   if ((auto_flags & ZXID_AUTO_FORMT) && (auto_flags & ZXID_AUTO_FORMF)) {
     506                 :            :     DD("HERE %p", cgi->idp_list);
     507                 :            :     ss = zx_strf(cf->ctx,
     508                 :            :                  "%s"
     509                 :            : #ifdef ZXID_USE_POST
     510                 :            :                  "<form method=post action=\"%s?o=P\">\n"
     511                 :            : #else
     512                 :            :                  "<form method=get action=\"%s\">\n"
     513                 :            : #endif
     514                 :            :                  "<font color=red>%s</font><font color=green>%s</font><font color=white>%s</font>"
     515                 :            :                  "%s"
     516                 :            :                  "%s<a href=\"%.*s\">%.*s</a><br>"
     517                 :            :                  "%s"    /* IdP List */
     518                 :            :                  "%s%s"
     519                 :            :                  "<input type=hidden name=fr value=\"%s\">\n"
     520                 :            :                  "</form>%s%s%s",
     521                 :            :                  cf->idp_sel_start,
     522                 :            :                  cf->url,
     523                 :            :                  FLDCHK(cgi, err), FLDCHK(cgi, msg), FLDCHK(cgi, dbg),
     524                 :            :                  cf->idp_sel_new_idp,
     525                 :            :                  cf->idp_sel_our_eid, eid?eid->len:0, eid?eid->s:"", eid?eid->len:0, eid?eid->s:"",
     526                 :            :                  idp_list,
     527                 :            :                  cf->idp_sel_tech_user, cf->idp_sel_tech_site,
     528                 :            :                  FLDCHK(cgi, rs),
     529                 :            :                  cf->idp_sel_footer, zxid_version_str(), cf->idp_sel_end);
     530                 :            :     DD("HERE(%d) ss(%.*s)", ss->len, ss->len, ss->s);
     531                 :            :   } else if (auto_flags & ZXID_AUTO_FORMT) {
     532                 :            :     ss = zx_strf(cf->ctx,
     533                 :            : #ifdef ZXID_USE_POST
     534                 :            :                  "<form method=post action=\"%s?o=P\">\n"
     535                 :            : #else
     536                 :            :                  "<form method=get action=\"%s\">\n"
     537                 :            : #endif
     538                 :            :                  "<font color=red>%s</font><font color=green>%s</font><font color=white>%s</font>"
     539                 :            :                  "%s"
     540                 :            :                  "%s<a href=\"%.*s\">%.*s</a><br>"
     541                 :            :                  "%s"    /* IdP List */
     542                 :            :                  "%s%s"
     543                 :            :                  "<input type=hidden name=fr value=\"%s\">\n"
     544                 :            :                  "</form>",
     545                 :            :                  cf->url,
     546                 :            :                  FLDCHK(cgi, err), FLDCHK(cgi, msg), FLDCHK(cgi, dbg),
     547                 :            :                  cf->idp_sel_new_idp,
     548                 :            :                  cf->idp_sel_our_eid, eid?eid->len:0, eid?eid->s:"", eid?eid->len:0, eid?eid->s:"",
     549                 :            :                  idp_list,
     550                 :            :                  cf->idp_sel_tech_user, cf->idp_sel_tech_site,
     551                 :            :                  FLDCHK(cgi, rs));
     552                 :            :   } else if (auto_flags & ZXID_AUTO_FORMF) {
     553                 :            :     ss = zx_strf(cf->ctx,
     554                 :            :                  "<font color=red>%s</font><font color=green>%s</font><font color=white>%s</font>"
     555                 :            :                  "%s"
     556                 :            :                  "%s<a href=\"%.*s\">%.*s</a><br>"
     557                 :            :                  "%s"    /* IdP List */
     558                 :            :                  "%s%s"
     559                 :            :                  "<input type=hidden name=fr value=\"%s\">\n",
     560                 :            :                  FLDCHK(cgi, err), FLDCHK(cgi, msg), FLDCHK(cgi, dbg),
     561                 :            :                  cf->idp_sel_new_idp,
     562                 :            :                  cf->idp_sel_our_eid, eid?eid->len:0, eid?eid->s:"", eid?eid->len:0, eid?eid->s:"",
     563                 :            :                  idp_list,
     564                 :            :                  cf->idp_sel_tech_user, cf->idp_sel_tech_site,
     565                 :            :                  FLDCHK(cgi, rs));
     566                 :            :   } else
     567                 :            :     ss = zx_dup_str(cf->ctx, "");
     568                 :            : #endif
     569                 :            : #if 0
     570                 :            :   if (cgi.err) printf("<p><font color=red><i>%s</i></font></p>\n", cgi.err);
     571                 :            :   if (cgi.msg) printf("<p><i>%s</i></p>\n", cgi.msg);
     572                 :            :   printf("User:<input name=user> PW:<input name=pw type=password>");
     573                 :            :   printf("<input name=login value=\" Login \" type=submit>");
     574                 :            :   printf("<h3>Login Using IdP Discovered from Common Domain Cookie (CDC)</h3>\n");
     575                 :            :   printf("RelayState: <input name=fr value=\"rs123\"><br>\n");
     576                 :            :   if (cgi.dbg) printf("<p><form><textarea cols=100 row=10>%s</textarea></form>\n", cgi.dbg);
     577                 :            : #endif
     578                 :         20 :   return ss;
     579                 :            : }
     580                 :            : 
     581                 :            : /* Called by:  zxid_idp_select_cf */
     582                 :          0 : struct zx_str* zxid_idp_select_zxstr_cf(zxid_conf* cf, int auto_flags) {
     583                 :          0 :   return zxid_idp_select_zxstr_cf_cgi(cf, 0, auto_flags);
     584                 :            : }
     585                 :            : 
     586                 :            : /* Called by:  zxid_idp_select_len */
     587                 :          0 : char* zxid_idp_select_cf(zxid_conf* cf, int* res_len, int auto_flags) {
     588                 :            :   char* s;
     589                 :          0 :   struct zx_str* ss = zxid_idp_select_zxstr_cf(cf, auto_flags);
     590                 :          0 :   s = ss->s;
     591         [ #  # ]:          0 :   if (res_len)
     592                 :          0 :     *res_len = ss->len;
     593                 :          0 :   ZX_FREE(cf->ctx, ss);
     594                 :          0 :   return s;
     595                 :            : }
     596                 :            : 
     597                 :            : /* Called by:  zxid_idp_select */
     598                 :          0 : char* zxid_idp_select_len(int conf_len, char* conf, int* res_len, int auto_flags) {
     599                 :            :   zxid_conf cf;
     600                 :          0 :   zxid_conf_to_cf_len(&cf, conf_len, conf);
     601                 :          0 :   return zxid_idp_select_cf(&cf, 0, auto_flags);
     602                 :            : }
     603                 :            : 
     604                 :            : /* Called by: */
     605                 :          0 : char* zxid_idp_select(char* conf, int auto_flags) {
     606                 :          0 :   return zxid_idp_select_len(-1, conf, 0, auto_flags);
     607                 :            : }
     608                 :            : 
     609                 :            : /* ------------ zxid_simple() ------------ */
     610                 :            : 
     611                 :            : /*() Deal with the various methods of shipping the page, including CGI stdout, or
     612                 :            :  * as string with or without headers, as indicated by the auto_flag. The
     613                 :            :  * page is in ss. */
     614                 :            : 
     615                 :            : /* Called by:  zxid_simple_idp_show_an, zxid_simple_show_carml, zxid_simple_show_conf, zxid_simple_show_err, zxid_simple_show_idp_sel, zxid_simple_show_meta */
     616                 :            : static char* zxid_simple_show_page(zxid_conf* cf, struct zx_str* ss, int c_mask, int h_mask, char* rets, char* cont_type, int* res_len, int auto_flags)
     617                 :         32 : {
     618                 :            :   char* res;
     619                 :            :   struct zx_str* ss2;
     620   [ +  -  +  + ]:         32 :   if (auto_flags & c_mask && auto_flags & h_mask) {  /* Both H&C: CGI */
     621   [ +  -  -  + ]:         27 :     D("CGI %x", auto_flags);
     622                 :         27 :     printf("Content-Type: %s" CRLF "Content-Length: %d" CRLF2 "%.*s",
     623                 :            :            cont_type, ss->len, ss->len, ss->s);
     624         [ +  - ]:         27 :     if (auto_flags & ZXID_AUTO_EXIT)
     625                 :         27 :       exit(0);
     626                 :          0 :     zx_str_free(cf->ctx, ss);
     627         [ #  # ]:          0 :     if (res_len)
     628                 :          0 :       *res_len = 1;
     629                 :          0 :     return zx_dup_cstr(cf->ctx, "n");
     630                 :            :   }
     631                 :            :   
     632         [ +  - ]:          5 :   if (auto_flags & (c_mask | h_mask)) {
     633         [ -  + ]:          5 :     if (auto_flags & h_mask) {  /* H only: return both H and C */
     634   [ #  #  #  # ]:          0 :       D("With headers %x", auto_flags);
     635                 :          0 :       ss2 = zx_strf(cf->ctx, "Content-Type: %s" CRLF "Content-Length: %d" CRLF2 "%.*s",
     636                 :            :                     cont_type, ss->len, ss->len, ss->s);
     637                 :          0 :       zx_str_free(cf->ctx, ss);
     638                 :            :     } else {
     639   [ +  -  -  + ]:          5 :       D("No headers %x", auto_flags);
     640                 :          5 :       ss2 = ss;       /* C only */
     641                 :            :     }
     642                 :          5 :     res = ss2->s;
     643                 :            :     DD("res(%s)", res);
     644         [ -  + ]:          5 :     if (res_len)
     645                 :          0 :       *res_len = ss2->len;
     646                 :          5 :     ZX_FREE(cf->ctx, ss2);
     647                 :          5 :     return res;
     648                 :            :   }
     649                 :            :   /* Do not output anything (both c and h 0). Effectively the generated page is thrown away. */
     650   [ #  #  #  #  :          0 :   D("e(%.*s) cm=%x hm=%x af=%x rets(%s)", ss?ss->len:-1, ss?ss->s:"", c_mask, h_mask, auto_flags, rets);
             #  #  #  # ]
     651         [ #  # ]:          0 :   if (ss)
     652                 :          0 :     zx_str_free(cf->ctx, ss);
     653         [ #  # ]:          0 :   if (res_len)
     654                 :          0 :     *res_len = 1;
     655                 :          0 :   return zx_dup_cstr(cf->ctx, rets);   /* Neither H nor C */
     656                 :            : }
     657                 :            : 
     658                 :            : /*() Helper function to redirect according to auto flags. */
     659                 :            : 
     660                 :            : /* Called by:  zxid_simple_idp_an_ok_do_rest, zxid_simple_idp_new_user, zxid_simple_idp_recover_password, zxid_simple_idp_show_an, zxid_simple_show_err, zxid_simple_show_idp_sel */
     661                 :            : static char* zxid_simple_redir_page(zxid_conf* cf, char* redir, char* rs, int* res_len, int auto_flags)
     662                 :          2 : {
     663                 :            :   char* res;
     664                 :            :   struct zx_str* ss;
     665   [ +  -  -  + ]:          2 :   D("cf=%p redir(%s)", cf, redir);
     666         [ +  - ]:          2 :   if (auto_flags & ZXID_AUTO_REDIR) {
     667         [ +  - ]:          2 :     printf("Location: %s?%s" CRLF2, redir, STRNULLCHK(rs));
     668         [ +  - ]:          2 :     if (auto_flags & ZXID_AUTO_EXIT)
     669                 :          2 :       exit(0);
     670         [ #  # ]:          0 :     if (res_len)
     671                 :          0 :       *res_len = 1;
     672                 :          0 :     return zx_dup_cstr(cf->ctx, "n");
     673                 :            :   }
     674         [ #  # ]:          0 :   ss = zx_strf(cf->ctx, "Location: %s?%s" CRLF2, redir, STRNULLCHK(rs));
     675         [ #  # ]:          0 :   if (res_len)
     676                 :          0 :     *res_len = ss->len;
     677                 :          0 :   res = ss->s;
     678                 :          0 :   ZX_FREE(cf->ctx, ss);
     679                 :          0 :   return res;
     680                 :            : }
     681                 :            : 
     682                 :            : /*() Show IdP selection or login screen.
     683                 :            :  *
     684                 :            :  * N.B. More complete documentation is available in <<link: zxid-simple.pd>> (*** fixme) */
     685                 :            : 
     686                 :            : /* Called by:  zxid_ps_accept_invite, zxid_ps_finalize_invite, zxid_simple_no_ses_cf, zxid_simple_ses_active_cf x5 */
     687                 :            : char* zxid_simple_show_idp_sel(zxid_conf* cf, zxid_cgi* cgi, int* res_len, int auto_flags)
     688                 :         20 : {
     689                 :            :   struct zx_str* ss;
     690   [ +  -  -  + ]:         20 :   D("cf=%p cgi=%p", cf, cgi);
     691   [ -  +  #  # ]:         20 :   if (cf->idp_sel_page && cf->idp_sel_page[0]) {
     692   [ #  #  #  #  :          0 :     D("idp_sel_page(%s) rs(%s)", cf->idp_sel_page, STRNULLCHK(cgi->rs));
                   #  # ]
     693                 :          0 :     return zxid_simple_redir_page(cf, cf->idp_sel_page, cgi->rs, res_len, auto_flags);
     694                 :            :   }
     695         [ +  - ]:         20 :   ss = auto_flags & (ZXID_AUTO_LOGINC | ZXID_AUTO_LOGINH)
     696                 :            :     ? zxid_idp_select_zxstr_cf_cgi(cf, cgi, auto_flags)
     697                 :            :     : 0;
     698                 :            :   DD("idp_select: ret(%s)", ss?ss->len:1, ss?ss->s:"?");
     699                 :         20 :   return zxid_simple_show_page(cf, ss, ZXID_AUTO_LOGINC, ZXID_AUTO_LOGINH,
     700                 :            :                                "e", "text/html", res_len, auto_flags);
     701                 :            : }
     702                 :            : 
     703                 :            : 
     704                 :            : /*() Emit metadata. Corresponds to "o=B" query string.
     705                 :            :  *
     706                 :            :  * N.B. More complete documentation is available in <<link: zxid-simple.pd>> (*** fixme) */
     707                 :            : 
     708                 :            : /* Called by:  zxid_simple_no_ses_cf x2, zxid_simple_ses_active_cf x2 */
     709                 :            : static char* zxid_simple_show_meta(zxid_conf* cf, zxid_cgi* cgi, int* res_len, int auto_flags)
     710                 :          4 : {
     711                 :          4 :   struct zx_str* meta = zxid_sp_meta(cf, cgi);
     712                 :          4 :   return zxid_simple_show_page(cf, meta, ZXID_AUTO_METAC, ZXID_AUTO_METAH,
     713                 :            :                                "b", "text/xml", res_len, auto_flags);
     714                 :            : }
     715                 :            : 
     716                 :            : /*() Emit CARML declaration for SP. Corresponds to "o=c" query string. */
     717                 :            : 
     718                 :            : /* Called by:  zxid_simple_no_ses_cf, zxid_simple_ses_active_cf */
     719                 :            : static char* zxid_simple_show_carml(zxid_conf* cf, zxid_cgi* cgi, int* res_len, int auto_flags)
     720                 :          1 : {
     721                 :          1 :   struct zx_str* carml = zxid_sp_carml(cf);
     722                 :          1 :   return zxid_simple_show_page(cf, carml, ZXID_AUTO_METAC, ZXID_AUTO_METAH,
     723                 :            :                                "c", "text/xml", res_len, auto_flags);
     724                 :            : }
     725                 :            : 
     726                 :            : /*() Dump internal info and configuration. Corresponds to "o=d" query string. */
     727                 :            : 
     728                 :            : /* Called by:  zxid_simple_no_ses_cf, zxid_simple_ses_active_cf */
     729                 :            : static char* zxid_simple_show_conf(zxid_conf* cf, zxid_cgi* cgi, int* res_len, int auto_flags)
     730                 :          1 : {
     731                 :          1 :   struct zx_str* ss = zxid_show_conf(cf);
     732                 :          1 :   return zxid_simple_show_page(cf, ss, ZXID_AUTO_METAC, ZXID_AUTO_METAH,
     733                 :            :                                "d", "text/html", res_len, auto_flags);
     734                 :            : }
     735                 :            : 
     736                 :            : /*() Show Error screen. */
     737                 :            : 
     738                 :            : /* Called by:  zxid_ps_accept_invite x4, zxid_ps_finalize_invite x4 */
     739                 :            : char* zxid_simple_show_err(zxid_conf* cf, zxid_cgi* cgi, int* res_len, int auto_flags)
     740                 :          1 : {
     741                 :            :   char* p;
     742                 :            :   struct zx_str* ss;
     743                 :            : 
     744         [ +  - ]:          1 :   if (cf->log_level>1)
     745                 :          1 :     zxlog(cf, 0, 0, 0, 0, 0, 0, 0, "N", "W", "ERR", 0, "");
     746                 :            : 
     747   [ -  +  #  # ]:          1 :   if (cf->err_page && cf->err_page[0]) {
     748   [ #  #  #  #  :          0 :     ss = zx_strf(cf->ctx, "zxrfr=F%s%s%s%s&zxidpurl=%s",
          #  #  #  #  #  
                #  #  # ]
     749                 :            :                  cgi->zxapp && cgi->zxapp[0] ? "&zxapp=" : "", cgi->zxapp ? cgi->zxapp : "",
     750                 :            :                  cgi->err && cgi->err[0] ? "&err=" : "", cgi->err ? cgi->err : "",
     751                 :            :                  cf->url);
     752                 :          0 :     p = ss->s;
     753                 :          0 :     ZX_FREE(cf->ctx, ss);
     754   [ #  #  #  # ]:          0 :     D("err_page(%s) p(%s)", cf->err_page, p);
     755                 :          0 :     return zxid_simple_redir_page(cf, cf->err_page, p, res_len, auto_flags);
     756                 :            :   }
     757                 :            :     
     758                 :          1 :   ss = zxid_template_page_cf(cf, cgi, cf->err_templ_file, cf->err_templ, 4096, auto_flags);
     759                 :          1 :   return zxid_simple_show_page(cf, ss, ZXID_AUTO_LOGINC, ZXID_AUTO_LOGINH,
     760                 :            :                                "g", "text/html", res_len, auto_flags);
     761                 :            : }
     762                 :            : 
     763                 :            : /* ----------- IdP Screens ----------- */
     764                 :            : 
     765                 :            : /*() Decode ssoreq (ar=), i.e. the preserved original AuthnReq */
     766                 :            : 
     767                 :            : /* Called by:  zxid_simple_idp_pw_authn, zxid_simple_idp_show_an */
     768                 :            : static int zxid_decode_ssoreq(zxid_conf* cf, zxid_cgi* cgi)
     769                 :          2 : {
     770                 :            :   int len;
     771                 :            :   char* buf;
     772                 :            :   char* p;
     773   [ +  -  +  + ]:          2 :   if (!cgi->ssoreq || !cgi->ssoreq[0])
     774                 :          1 :     return 1;
     775   [ +  -  -  + ]:          1 :   D("ssoreq(%s)", cgi->ssoreq);
     776                 :          1 :   len = strlen(cgi->ssoreq);
     777                 :          1 :   buf = ZX_ALLOC(cf->ctx, SIMPLE_BASE64_PESSIMISTIC_DECODE_LEN(len));
     778                 :          1 :   p = unbase64_raw(cgi->ssoreq, cgi->ssoreq + len, buf, zx_std_index_64);
     779                 :          1 :   p = zx_zlib_raw_inflate(0, p-buf, buf, &len);
     780                 :          1 :   ZX_FREE(cf->ctx, buf);
     781         [ +  - ]:          1 :   if (!p)
     782                 :          1 :     return 0;
     783                 :          0 :   p[len] = 0;
     784                 :          0 :   cgi->op = 0;
     785   [ #  #  #  # ]:          0 :   D("ar/ssoreq decoded(%s)", p);
     786                 :          0 :   zxid_parse_cgi(cgi, p);  /* cgi->op will be Q due to SAMLRequest inside ssoreq */
     787                 :          0 :   cgi->op = 'F';
     788                 :          0 :   return 1;
     789                 :            : }
     790                 :            : 
     791                 :            : /*() Process IdP side after successful authentication. If IdP was
     792                 :            :  * invoked with AuthnReq (in SAMLRequest) then op=='F' as set
     793                 :            :  * in zxid_simple_idp_pw_authn() which will trigger the rest of the
     794                 :            :  * SSO protocol in zxid_simple_ses_active_cf(). Otherwise just
     795                 :            :  * show the IdP management screen. */
     796                 :            : 
     797                 :            : /* Called by:  zxid_simple_idp_pw_authn, zxid_simple_idp_show_an */
     798                 :            : static char* zxid_simple_idp_an_ok_do_rest(zxid_conf* cf, zxid_cgi* cgi, zxid_ses* ses, int* res_len, int auto_flags)
     799                 :          2 : {
     800                 :            :   struct zx_str* ss;
     801                 :            :   char* p;
     802                 :            :   DD("idp do_rest %p", ses);
     803   [ +  -  -  + ]:          2 :   if (cf->atsel_page && cgi->atselafter) { /* *** More sophisticated criteria needed. */
     804   [ #  #  #  #  :          0 :     ss = zx_strf(cf->ctx, "ar=%s&s=%s&zxrfr=F%s%s%s%s&zxidpurl=%s",
          #  #  #  #  #  
                #  #  # ]
     805                 :            :                  cgi->ssoreq, cgi->sid,
     806                 :            :                  cgi->zxapp && cgi->zxapp[0] ? "&zxapp=" : "", cgi->zxapp ? cgi->zxapp : "",
     807                 :            :                  cgi->err && cgi->err[0] ? "&err=" : "", cgi->err ? cgi->err : "",
     808                 :            :                  cf->url);
     809                 :          0 :     p = ss->s;
     810                 :          0 :     ZX_FREE(cf->ctx, ss);
     811   [ #  #  #  # ]:          0 :     D("atsel_page(%s) redir(%s)", cf->atsel_page, p);
     812                 :          0 :     return zxid_simple_redir_page(cf, cf->atsel_page, p, res_len, auto_flags);
     813                 :            :   }
     814                 :          2 :   return zxid_simple_ses_active_cf(cf, cgi, ses, res_len, auto_flags);
     815                 :            : }
     816                 :            : 
     817                 :            : /*() Show Authentication screen. Generally this will be in response to
     818                 :            :  * the SP having sent user via redirect to o=F carrying AuthnRequest encoded
     819                 :            :  * in SAMLRequest query string parameter, per SAML redirect binding
     820                 :            :  * [SAML2bind].  We must preserve SAMLRequest as hidden field, ar, in the
     821                 :            :  * page for later processing once the authentication step has been
     822                 :            :  * taken care of. It will also be passed on the query string to
     823                 :            :  * external authentication page if any was configured with AN_PAGE
     824                 :            :  * directive.
     825                 :            :  *
     826                 :            :  * N.B. More complete documentation is available in <<link: zxid-simple.pd>> (*** fixme) */
     827                 :            : 
     828                 :            : /* Called by:  zxid_simple_idp_new_user, zxid_simple_idp_pw_authn, zxid_simple_idp_recover_password, zxid_simple_no_ses_cf */
     829                 :            : static char* zxid_simple_idp_show_an(zxid_conf* cf, zxid_cgi* cgi, int* res_len, int auto_flags)
     830                 :          6 : {
     831                 :            :   int zlen, len;
     832                 :            :   char* zbuf;
     833                 :          6 :   char* b64 = 0;
     834                 :            :   char* p;
     835                 :            :   char* ar;
     836                 :            :   struct zx_sa_Issuer_s* issuer;
     837                 :            :   zxid_entity* meta;
     838                 :            :   struct zx_root_s* r;
     839                 :            :   struct zx_str* ss;
     840                 :            :   zxid_ses sess;
     841                 :          6 :   ZERO(&sess, sizeof(sess));
     842   [ +  -  -  + ]:          6 :   D("cf=%p cgi=%p", cf, cgi);
     843                 :            :   
     844                 :            :   DD("z saml_req(%s) rs(%s) sigalg(%s) sig(%s)", cgi->saml_req, cgi->rs, cgi->sigalg, cgi->sig);  
     845   [ +  +  +  - ]:          6 :   if (cgi->uid && zxid_pw_authn(cf, cgi, &sess)) {  /* Try login, just in case. */
     846                 :          1 :     return zxid_simple_idp_an_ok_do_rest(cf, cgi, &sess, res_len, auto_flags);
     847                 :            :   }
     848         [ +  + ]:          5 :   if (cgi->saml_req) {
     849                 :            :     DD("zz saml_req(%s) rs(%s) sigalg(%s) sig(%s)", cgi->saml_req, cgi->rs, cgi->sigalg, cgi->sig);  
     850   [ +  -  +  -  :          1 :     ss = zx_strf(cf->ctx, "SAMLRequest=%s%s%s&SigAlg=%s&Signature=%s",
          -  +  -  +  #  
                #  +  - ]
     851                 :            :                  STRNULLCHK(cgi->saml_req),
     852                 :            :                  cgi->rs && cgi->rs[0] ? "&RelayState=" : "", cgi->rs ? cgi->rs : "",
     853                 :            :                  STRNULLCHK(cgi->sigalg),
     854                 :            :                  STRNULLCHK(cgi->sig));
     855   [ +  -  -  + ]:          1 :     D("z input(%.*s) len=%d", ss->len, ss->s, ss->len);
     856                 :          1 :     zbuf = zx_zlib_raw_deflate(cf->ctx, ss->len, ss->s, &zlen);
     857         [ -  + ]:          1 :     if (!zbuf)
     858                 :          0 :       return 0;
     859                 :            :     
     860                 :          1 :     len = SIMPLE_BASE64_LEN(zlen);
     861                 :            :     DD("zbuf(%.*s) zlen=%d len=%d", zlen, zbuf, zlen, len);
     862                 :          1 :     b64 = ZX_ALLOC(cf->ctx, len+1);
     863                 :          1 :     p = base64_fancy_raw(zbuf, zlen, b64, safe_basis_64, 1<<31, 0, 0, '=');
     864                 :          1 :     *p = 0;
     865                 :          1 :     zx_str_free(cf->ctx, ss);
     866                 :          1 :     cgi->ssoreq = b64;
     867                 :            :   }
     868                 :            :   
     869   [ -  +  #  # ]:          5 :   if (cf->an_page && cf->an_page[0]) {
     870   [ #  #  #  #  :          0 :     ss = zx_strf(cf->ctx, "ar=%s&zxrfr=F%s%s%s%s&zxidpurl=%s",
          #  #  #  #  #  
                #  #  # ]
     871                 :            :                  cgi->ssoreq,
     872                 :            :                  cgi->zxapp && cgi->zxapp[0] ? "&zxapp=" : "", cgi->zxapp ? cgi->zxapp : "",
     873                 :            :                  cgi->err && cgi->err[0] ? "&err=" : "", cgi->err ? cgi->err : "",
     874                 :            :                  cf->url);
     875         [ #  # ]:          0 :     if (b64)
     876                 :          0 :       ZX_FREE(cf->ctx, b64);
     877                 :          0 :     ar = ss->s;
     878                 :          0 :     ZX_FREE(cf->ctx, ss);
     879   [ #  #  #  # ]:          0 :     D("an_page(%s) ar(%s)", cf->an_page, ar);
     880                 :          0 :     return zxid_simple_redir_page(cf, cf->an_page, ar, res_len, auto_flags);
     881                 :            :   }
     882                 :            :   
     883         [ +  - ]:          5 :   if (cf->log_level>1)
     884                 :          5 :     zxlog(cf, 0, 0, 0, 0, 0, 0, 0, "N", "W", "AUTHN", 0, "");
     885                 :            :   
     886                 :            :   /* Attempt to provisorily decode the request and fetch metadata of the SP so we
     887                 :            :    * can detect trouble early on and provide some assuring knowledge to the user. */
     888                 :            :   
     889   [ +  +  -  + ]:          5 :   if (!cgi->saml_req && cgi->ssoreq) {
     890                 :          0 :     zxid_decode_ssoreq(cf, cgi);
     891                 :            :   }
     892                 :            :   
     893                 :          5 :   r = zxid_decode_redir_or_post(cf, cgi, &sess, 0x2);
     894         [ +  + ]:          5 :   if (r) {
     895                 :          1 :     issuer = zxid_extract_issuer(cf, cgi, &sess, r);
     896   [ +  -  +  -  :          2 :     if (ZX_SIMPLE_ELEM_CHK(issuer)) {
          +  -  +  -  +  
                -  +  - ]
     897   [ +  -  +  -  :          1 :       meta = zxid_get_ent_ss(cf, ZX_GET_CONTENT(issuer));
                   +  - ]
     898         [ +  - ]:          1 :       if (meta) {
     899                 :          1 :         cgi->sp_eid = meta->eid;
     900                 :          1 :         cgi->sp_dpy_name = meta->dpy_name;
     901                 :            :       } else {
     902   [ #  #  #  #  :          0 :         ERR("Unable to find metadata for Issuer(%.*s) in AnReq Redir", ZX_GET_CONTENT_LEN(issuer), ZX_GET_CONTENT_S(issuer));
          #  #  #  #  #  
                #  #  # ]
     903                 :          0 :         cgi->err = "Issuer unknown - metadata exchange may be needed (AnReq).";
     904                 :          0 :         cgi->sp_dpy_name = "--SP description unavailable--";
     905   [ #  #  #  #  :          0 :         cgi->sp_eid = zx_str_to_c(cf->ctx, ZX_GET_CONTENT(issuer));
                   #  # ]
     906                 :            :       }
     907                 :            :     } else {
     908                 :          0 :       cgi->err = "Issuer could not be determined from Authentication Request.";
     909                 :          0 :       cgi->sp_eid = "";
     910                 :          0 :       cgi->sp_dpy_name = "--No SP could be determined--";
     911                 :            :     }
     912                 :            :   } else {
     913                 :          4 :       cgi->err = "Malformed or nonexistant Authentication Request";
     914                 :          4 :       cgi->sp_eid = "";
     915                 :          4 :       cgi->sp_dpy_name = "--No SP could be determined--";
     916                 :            :   }
     917                 :            :   
     918                 :          5 :   ss = zxid_template_page_cf(cf, cgi, cf->an_templ_file, cf->an_templ, 4096, auto_flags);
     919         [ +  + ]:          5 :   if (b64)
     920                 :          1 :     ZX_FREE(cf->ctx, b64);
     921                 :            :   DD("an_page: ret(%s)", ss?ss->len:1, ss?ss->s:"?");
     922                 :          5 :   return zxid_simple_show_page(cf, ss, ZXID_AUTO_LOGINC, ZXID_AUTO_LOGINH,
     923                 :            :                                "a", "text/html", res_len, auto_flags);
     924                 :            : }
     925                 :            : 
     926                 :            : /*() Process password authentication form and, if ssoreq (ar=) is present
     927                 :            :  * (see zxid_simple_idp_show_an() for how it is embedded to hidden
     928                 :            :  * form field), proceed to federated SSO. If login fails, redisplay
     929                 :            :  * the authentication page.
     930                 :            :  *
     931                 :            :  * N.B. More complete documentation is available in <<link: zxid-simple.pd>> (*** fixme) */
     932                 :            : 
     933                 :            : /* Called by:  zxid_simple_no_ses_cf */
     934                 :            : static char* zxid_simple_idp_pw_authn(zxid_conf* cf, zxid_cgi* cgi, int* res_len, int auto_flags)
     935                 :          2 : {
     936                 :            :   zxid_ses sess;
     937   [ +  -  -  + ]:          2 :   D("cf=%p cgi=%p", cf, cgi);
     938                 :            :  
     939         [ +  + ]:          2 :   if (!zxid_decode_ssoreq(cf, cgi))
     940                 :          1 :     goto err;
     941                 :            : 
     942                 :          1 :   ZERO(&sess, sizeof(sess));
     943         [ +  - ]:          1 :   if (zxid_pw_authn(cf, cgi, &sess))
     944                 :          1 :     return zxid_simple_idp_an_ok_do_rest(cf, cgi, &sess, res_len, auto_flags);
     945                 :            : 
     946   [ #  #  #  #  :          0 :   D("PW Login failed uid(%s) pw(%s) err(%s)", STRNULLCHK(cgi->uid), STRNULLCHK(cgi->pw), STRNULLCHK(cgi->err));
          #  #  #  #  #  
                      # ]
     947                 :          1 :  err:
     948                 :          1 :   return zxid_simple_idp_show_an(cf, cgi, res_len, auto_flags);
     949                 :            : }
     950                 :            : 
     951                 :            : /*() Redirect user to new user creation page. */
     952                 :            : 
     953                 :            : /* Called by:  zxid_simple_no_ses_cf */
     954                 :            : static char* zxid_simple_idp_new_user(zxid_conf* cf, zxid_cgi* cgi, int* res_len, int auto_flags)
     955                 :          1 : {
     956                 :            :   char* p;
     957                 :            :   struct zx_str* ss;
     958   [ +  -  -  + ]:          1 :   D("cf=%p cgi=%p", cf, cgi);
     959                 :            : 
     960                 :            :   // ***
     961                 :            : 
     962   [ +  -  +  - ]:          1 :   if (cf->new_user_page && cf->new_user_page[0]) {
     963   [ -  +  -  +  :          1 :     ss = zx_strf(cf->ctx, "ar=%s&zxrfr=F%s%s%s%s&zxidpurl=%s",
          #  #  -  +  -  
                +  #  # ]
     964                 :            :                  cgi->ssoreq,
     965                 :            :                  cgi->zxapp && cgi->zxapp[0] ? "&zxapp=" : "", cgi->zxapp ? cgi->zxapp : "",
     966                 :            :                  cgi->err && cgi->err[0] ? "&err=" : "", cgi->err ? cgi->err : "",
     967                 :            :                  cf->url);
     968                 :          1 :     p = ss->s;
     969                 :          1 :     ZX_FREE(cf->ctx, ss);
     970   [ +  -  -  + ]:          1 :     D("new_user_page(%s) redir(%s)", cf->new_user_page, p);
     971                 :          1 :     return zxid_simple_redir_page(cf, cf->new_user_page, p, res_len, auto_flags);
     972                 :            :   }
     973                 :            : 
     974                 :          0 :   ERR("No new user page URL defined. (IdP config problem, or IdP intentionally does not support online new user creation. See NEW_USER_PAGE config option.) %d", 0);
     975                 :          0 :   cgi->err = "No new user page URL defined. (IdP config problem, or IdP intentionally does not support online new user creation.)";
     976                 :            :   
     977                 :          0 :   return zxid_simple_idp_show_an(cf, cgi, res_len, auto_flags);
     978                 :            : }
     979                 :            : 
     980                 :            : /*() Redirect user to recover password page. */
     981                 :            : 
     982                 :            : /* Called by:  zxid_simple_no_ses_cf */
     983                 :            : static char* zxid_simple_idp_recover_password(zxid_conf* cf, zxid_cgi* cgi, int* res_len, int auto_flags)
     984                 :          1 : {
     985                 :            :   char* p;
     986                 :            :   struct zx_str* ss;
     987   [ +  -  -  + ]:          1 :   D("cf=%p cgi=%p", cf, cgi);
     988                 :            : 
     989                 :            :   // ***
     990                 :            : 
     991   [ +  -  +  - ]:          1 :   if (cf->recover_passwd && cf->recover_passwd[0]) {
     992   [ -  +  -  +  :          1 :     ss = zx_strf(cf->ctx, "ar=%s&zxrfr=F%s%s%s%s&zxidpurl=%s",
          #  #  -  +  -  
                +  #  # ]
     993                 :            :                  cgi->ssoreq,
     994                 :            :                  cgi->zxapp && cgi->zxapp[0] ? "&zxapp=" : "", cgi->zxapp ? cgi->zxapp : "",
     995                 :            :                  cgi->err && cgi->err[0] ? "&err=" : "", cgi->err ? cgi->err : "",
     996                 :            :                  cf->url);
     997                 :          1 :     p = ss->s;
     998                 :          1 :     ZX_FREE(cf->ctx, ss);
     999   [ +  -  -  + ]:          1 :     D("recover_passwd(%s) redir(%s)", cf->recover_passwd, p);
    1000                 :          1 :     return zxid_simple_redir_page(cf, cf->recover_passwd, p, res_len, auto_flags);
    1001                 :            :   }
    1002                 :            : 
    1003                 :          0 :   ERR("No password recover page URL defined. (IdP config problem, or IdP intentionally does not support online password recovery. See RECOVER_PASSWD config option.) %d", 0);
    1004                 :          0 :   cgi->err = "No password recover page URL defined. (IdP config problem, or IdP intentionally does not support online password recovery.)";
    1005                 :            :   
    1006                 :          0 :   return zxid_simple_idp_show_an(cf, cgi, res_len, auto_flags);
    1007                 :            : }
    1008                 :            : 
    1009                 :            : /* ===== Main Control Logic for Session Active and Session Inactive Cases ===== */
    1010                 :            : 
    1011                 :            : /*() Subroutine of zxid_simple_cf() for the session active case.
    1012                 :            :  *
    1013                 :            :  * NULL return means the "not logged in" processing is needed, see zxid_simple_no_ses_cf()
    1014                 :            :  *
    1015                 :            :  * N.B. More complete documentation is available in <<link: zxid-simple.pd>> (*** fixme) */
    1016                 :            : 
    1017                 :            : /* Called by:  chkuid x2, zxid_simple_cf_ses, zxid_simple_idp_an_ok_do_rest */
    1018                 :            : char* zxid_simple_ses_active_cf(zxid_conf* cf, zxid_cgi* cgi, zxid_ses* ses, int* res_len, int auto_flags)
    1019                 :         16 : {
    1020                 :            :   struct zx_str* accr;
    1021                 :            :   char* p;
    1022                 :         16 :   char* res = 0;
    1023                 :            :   struct zx_str* ss;
    1024                 :            :   
    1025   [ +  -  +  -  :         16 :   if (!cf || !cgi || !ses) {
                   -  + ]
    1026                 :          0 :     ERR("FATAL: NULL pointer. You MUST supply configuration(%p), cgi(%p), and session(%p) objects (programming error)", cf, cgi, ses);
    1027         [ #  # ]:          0 :     NEVERNEVER("Bad args %p", cf);
    1028                 :            :   }
    1029                 :            :   
    1030                 :            :   /* OPs (the o= CGI field. Not to be confused with first letter of zxid_simple() return value)
    1031                 :            :    * l = local logout (form gl)
    1032                 :            :    * r = SLO redir    (form gr)
    1033                 :            :    * s = SLO soap     (form gs)
    1034                 :            :    * t = nireg redir  (form gt)
    1035                 :            :    * u = nireg soap   (form gu)
    1036                 :            :    * v = Az soap      (form gv)
    1037                 :            :    * c = CARML for the SP
    1038                 :            :    * d = Dump internal data, including config; debug screen
    1039                 :            :    * m = Show management screen
    1040                 :            :    * n = Just check session (used for checking session for protected content pages)
    1041                 :            :    * p = Password Login (IdP form submit alp= with au= and ap=)
    1042                 :            :    * P = POST response. HTTP POST in general
    1043                 :            :    * Q = POST request
    1044                 :            :    * R = POST request to IdP
    1045                 :            :    * S = SOAP (POST) request
    1046                 :            :    * B = Metadata
    1047                 :            :    *
    1048                 :            :    * M = CDC redirect and LECP detect
    1049                 :            :    * C = CDC reader
    1050                 :            :    * E = Normal "Entry" page (e.g. after CDC read)
    1051                 :            :    * L = Start SSO (submit of E)
    1052                 :            :    * A = Artifact processing
    1053                 :            :    * N = New User, during IdP Login (form an)
    1054                 :            :    * W = Recover password,  during IdP Login (form aw)
    1055                 :            :    * D = Delegation / Invitation acceptance user interface, the idp selection
    1056                 :            :    * G = Delegation / Invitation finalization after SSO (via RelayState)
    1057                 :            :    *
    1058                 :            :    * I = used for IdP ???
    1059                 :            :    * K = used?
    1060                 :            :    * F = IdP: Return SSO A7N after successful An; no ses case, generate IdP ui
    1061                 :            :    *
    1062                 :            :    * Still available: GHJORTUVWXYZabcdefghijkoqwxyz
    1063                 :            :    */
    1064                 :            :   
    1065         [ -  + ]:         16 :   if (cgi->enc_hint)
    1066                 :          0 :     cf->nameid_enc = cgi->enc_hint != '0';
    1067   [ +  -  -  + ]:         16 :   D("op(%c) session(%s) active", cgi->op, cgi->sid);
    1068                 :            :   DD("session(%s) active op(%c) saml_req(%s)", cgi->sid, cgi->op, STRNULLCHK(cgi->saml_req));
    1069   [ +  +  -  -  :         16 :   switch (cgi->op) {
          -  +  -  +  -  
          -  -  +  -  -  
             -  -  +  + ]
    1070                 :            :   case 'l':
    1071         [ +  - ]:          3 :     if (cf->log_level>0)
    1072   [ -  +  #  #  :          3 :       zxlog(cf, 0,0,0,0,0,0, ZX_GET_CONTENT(ses->nameid), "N", "W", "LOCLO", ses->sid,0);
                   #  # ]
    1073                 :          3 :     zxid_del_ses(cf, ses);
    1074                 :          3 :     cgi->msg = "Local logout Ok. Session terminated.";
    1075                 :          3 :     return zxid_simple_show_idp_sel(cf, cgi, res_len, auto_flags);
    1076                 :            :   case 'r':
    1077                 :          2 :     ss = zxid_sp_slo_redir(cf, cgi, ses);
    1078                 :          2 :     zxid_del_ses(cf, ses);
    1079                 :          2 :     goto redir_ok;
    1080                 :            :   case 's':
    1081                 :          0 :     zxid_sp_slo_soap(cf, cgi, ses);
    1082                 :          0 :     zxid_del_ses(cf, ses);
    1083                 :          0 :     cgi->msg = "SP Initiated logout (SOAP). Session terminated.";
    1084                 :          0 :     return zxid_simple_show_idp_sel(cf, cgi, res_len, auto_flags);
    1085                 :            :   case 't':
    1086                 :          0 :     ss = zxid_sp_mni_redir(cf, cgi, ses, zx_ref_str(cf->ctx, cgi->newnym));
    1087                 :          0 :     goto redir_ok;
    1088                 :            :   case 'u':
    1089                 :          0 :     zxid_sp_mni_soap(cf, cgi, ses, zx_ref_str(cf->ctx, cgi->newnym));
    1090                 :          0 :     cgi->msg = "SP Initiated defederation (SOAP).";
    1091                 :          0 :     break;     /* Defederation does not have to mean SLO */
    1092                 :            :   case 'v':    /* N.B. This is just testing facility. The result is ignored. */
    1093         [ -  + ]:          1 :     zxid_pep_az_soap_pepmap(cf, cgi, ses, cf->pdp_call_url?cf->pdp_call_url:cf->pdp_url, cf->pepmap);
    1094                 :          1 :     cgi->msg = "PEP-to-PDP Authorization call (SOAP).";
    1095                 :          1 :     break;     /* Defederation does not have to mean SLO */
    1096                 :            :   case 'm':
    1097                 :          0 :     res = zxid_fed_mgmt_cf(cf, res_len, -1, cgi->sid, auto_flags);
    1098         [ #  # ]:          0 :     if (auto_flags & ZXID_AUTO_EXIT)
    1099                 :          0 :       exit(0);
    1100                 :          0 :     return res;
    1101                 :            :   case 'P':    /* POST Profile Responses */
    1102                 :            :   case 'I':
    1103                 :            :   case 'K':
    1104                 :            :   case 'Q':    /* POST Profile Requests */
    1105   [ +  -  +  -  :          2 :     D("saml_req(%s) rs(%s) sigalg(%s) sig(%s)", STRNULLCHK(cgi->saml_req), STRNULLCHK(cgi->rs), STRNULLCHK(cgi->sigalg), STRNULLCHK(cgi->sig));
          +  -  -  +  +  
                -  -  + ]
    1106                 :          2 :     ss = zxid_sp_dispatch(cf, cgi, ses);
    1107   [ -  +  -  - ]:          2 :     switch (ss->s[0]) {
    1108                 :          0 :     case 'K': return zxid_simple_show_idp_sel(cf, cgi, res_len, auto_flags);
    1109                 :          2 :     case 'L': goto redir_ok;
    1110                 :          0 :     case 'I': goto idp;
    1111                 :            :     }
    1112   [ #  #  #  # ]:          0 :     D("Q ss(%.*s) (fall thru)", ss->len, ss->s);
    1113                 :          0 :     break;
    1114                 :            : 
    1115                 :            :      /*  Delegation / Invitation URL clicked. */
    1116                 :          0 :   case 'D':  return zxid_ps_accept_invite(cf, cgi, ses, res_len, auto_flags);
    1117                 :          0 :   case 'G':  return zxid_ps_finalize_invite(cf, cgi, ses, res_len, auto_flags);
    1118                 :            : 
    1119                 :            :   case 'R':
    1120                 :          0 :     cgi->op = 'F';
    1121                 :            :     /* Fall thru */
    1122                 :            :   case 'F': /*  IdP: Return SSO A7N after successful An; no ses case, generate IdP ui */
    1123                 :          5 :   idp:
    1124                 :          5 :     ss = zxid_idp_dispatch(cf, cgi, ses, 1);  /* N.B. The original request is in cgi->saml_req */
    1125      [ -  +  - ]:          5 :     switch (ss->s[0]) {
    1126                 :          0 :     case 'K': return zxid_simple_show_idp_sel(cf, cgi, res_len, auto_flags);
    1127                 :            :     case 'C': /* Content-type:  -- i.e. ship page or XML out */
    1128                 :            :     case 'L':
    1129                 :          9 :   redir_ok:
    1130         [ +  + ]:          9 :       if (auto_flags & ZXID_AUTO_REDIR) {
    1131                 :          8 :         printf("%.*s", ss->len, ss->s);
    1132                 :          8 :         zx_str_free(cf->ctx, ss);
    1133                 :          8 :         fflush(stdout);
    1134                 :          8 :         goto cgi_exit;
    1135                 :            :       } else
    1136                 :          1 :         goto res_zx_str;
    1137                 :            :     }
    1138   [ #  #  #  # ]:          0 :     D("idp err(%.*s) (fall thru)", ss->len, ss->s);
    1139                 :            :     /* *** */
    1140                 :          0 :     break;
    1141                 :          0 :   case 'c': return zxid_simple_show_carml(cf, cgi, res_len, auto_flags);
    1142                 :          0 :   case 'd': return zxid_simple_show_conf(cf, cgi, res_len, auto_flags);
    1143                 :          0 :   case 'B': return zxid_simple_show_meta(cf, cgi, res_len, auto_flags);
    1144                 :          0 :   case 'n': break;
    1145                 :          2 :   case 'p': break;
    1146                 :            :   default:
    1147         [ -  + ]:          1 :     if (cf->bare_url_entityid)
    1148                 :          0 :       return zxid_simple_show_meta(cf, cgi, res_len, auto_flags);
    1149                 :            :   }
    1150         [ -  + ]:          4 :   if (cf->required_authnctx) {
    1151                 :          0 :     zxid_get_ses_sso_a7n(cf, ses);
    1152   [ #  #  #  #  :          0 :     accr = ses->a7n&&ses->a7n->AuthnStatement&&ses->a7n->AuthnStatement->AuthnContext
          #  #  #  #  #  
                #  #  # ]
    1153                 :            :       ?ZX_GET_CONTENT(ses->a7n->AuthnStatement->AuthnContext->AuthnContextClassRef):0;
    1154                 :            : 
    1155         [ #  # ]:          0 :     if (accr)
    1156         [ #  # ]:          0 :       for (p = cf->required_authnctx[0]; p; ++p)
    1157   [ #  #  #  # ]:          0 :         if (!memcmp(accr->s, p, accr->len) && !p[accr->len])
    1158                 :          0 :           goto ok;
    1159                 :            :     
    1160                 :            :     /* *** arrange same session to be used after step-up authentication. */
    1161                 :            :     
    1162   [ #  #  #  #  :          0 :     D("Required AuthnCtx not satisfied by (%.*s). Step-up authentication needed.", accr&&accr->len?accr->len:1, accr&&accr->len?accr->s:"-");
          #  #  #  #  #  
                #  #  # ]
    1163                 :          0 :     cgi->msg = "Step-up authentication requested.";
    1164                 :          0 :     return zxid_simple_show_idp_sel(cf, cgi, res_len, auto_flags);
    1165                 :          0 :   ok:
    1166   [ #  #  #  # ]:          0 :     D("Required AuthnCtx satisfied(%s)", p);
    1167                 :            :   }
    1168                 :            : 
    1169                 :            :   /* Already successful Single Sign-On case starts here */
    1170                 :          4 :   ses->rs = cgi->rs;
    1171                 :          4 :   return zxid_simple_ab_pep(cf, ses, res_len, auto_flags);
    1172                 :            :   
    1173                 :          8 : cgi_exit:
    1174         [ +  - ]:          8 :   if (auto_flags & ZXID_AUTO_EXIT)
    1175                 :          8 :     exit(0);
    1176                 :          0 :   res = zx_dup_cstr(cf->ctx, "n");
    1177         [ #  # ]:          0 :   if (res_len)
    1178                 :          0 :     *res_len = 1;
    1179                 :          0 :   return res;
    1180                 :            : 
    1181                 :          1 : res_zx_str:
    1182                 :          1 :   res = ss->s;
    1183         [ -  + ]:          1 :   if (res_len)
    1184                 :          0 :     *res_len = ss->len;
    1185                 :          1 :   ZX_FREE(cf->ctx, ss);
    1186                 :          1 :   return res;
    1187                 :            : }
    1188                 :            : 
    1189                 :            : /*() Subroutine of zxid_simple_cf() for the no session detected/active case.
    1190                 :            :  *
    1191                 :            :  * N.B. More complete documentation is available in <<link: zxid-simple.pd>> (*** fixme) */
    1192                 :            : 
    1193                 :            : /* Called by:  chkuid, zxid_simple_cf_ses */
    1194                 :            : char* zxid_simple_no_ses_cf(zxid_conf* cf, zxid_cgi* cgi, zxid_ses* ses, int* res_len, int auto_flags)
    1195                 :         45 : {
    1196                 :         45 :   char* res = 0;
    1197                 :            :   struct zx_str* ss;
    1198                 :            :   
    1199   [ +  -  +  -  :         45 :   if (!cf || !cgi || !ses) {
                   -  + ]
    1200                 :          0 :     ERR("FATAL: NULL pointer. You MUST supply configuration(%p), cgi(%p), and session(%p) objects (programming error)", cf, cgi, ses);
    1201                 :          0 :     exit(1);
    1202                 :            :   }
    1203                 :            : 
    1204   [ +  +  +  +  :         45 :   switch (cgi->op) {
          +  +  +  +  +  
          +  +  +  +  +  
                   +  + ]
    1205                 :            :   case 'M':  /* Invoke LECP or redirect to CDC reader. */
    1206                 :          2 :     ss = zxid_lecp_check(cf, cgi);
    1207   [ +  -  -  +  :          2 :     D("LECP check: ss(%.*s)", ss?ss->len:1, ss?ss->s:"?");
             -  +  -  + ]
    1208         [ -  + ]:          2 :     if (ss) {
    1209         [ #  # ]:          0 :       if (auto_flags & ZXID_AUTO_REDIR) {
    1210                 :          0 :         printf("%.*s", ss->len, ss->s);
    1211                 :          0 :         zx_str_free(cf->ctx, ss);
    1212                 :          0 :         goto cgi_exit;
    1213                 :            :       } else
    1214                 :          0 :         goto res_zx_str;
    1215                 :            :     } else {
    1216         [ +  - ]:          2 :       if (auto_flags & ZXID_AUTO_REDIR) {
    1217                 :          2 :         printf("Location: %s?o=C" CRLF2, cf->cdc_url);
    1218                 :          2 :         goto cgi_exit;
    1219                 :            :       } else {
    1220                 :          0 :         ss = zx_strf(cf->ctx, "Location: %s?o=C" CRLF2, cf->cdc_url);
    1221                 :          0 :         goto res_zx_str;
    1222                 :            :       }
    1223                 :            :     }
    1224                 :            :   case 'C':  /* CDC Read: Common Domain Cookie Reader */
    1225                 :          1 :     zxid_cdc_read(cf, cgi);
    1226                 :          1 :     goto cgi_exit;
    1227                 :            :   case 'E':  /* Return from CDC read, or start here to by-pass CDC read. */
    1228                 :          5 :     ss = zxid_lecp_check(cf, cgi);  /* use o=E&fc=1&fn=p  to set allow create true */
    1229   [ +  -  -  +  :          5 :     D("LECP check: ss(%.*s)", ss?ss->len:1, ss?ss->s:"?");
             -  +  -  + ]
    1230         [ -  + ]:          5 :     if (ss) {
    1231         [ #  # ]:          0 :       if (auto_flags & ZXID_AUTO_REDIR) {
    1232                 :          0 :         printf("%.*s", ss->len, ss->s);
    1233                 :          0 :         zx_str_free(cf->ctx, ss);
    1234                 :          0 :         goto cgi_exit;
    1235                 :            :       } else
    1236                 :          0 :         goto res_zx_str;
    1237                 :            :     }
    1238         [ -  + ]:          5 :     if (zxid_cdc_check(cf, cgi))
    1239                 :          0 :       return 0;
    1240   [ +  -  -  + ]:          5 :     D("NOT CDC %d", 0);
    1241                 :          5 :     break;
    1242                 :            :   case 'L':
    1243         [ +  + ]:          6 :     if (auto_flags & ZXID_AUTO_REDIR) {
    1244         [ +  + ]:          3 :       if (zxid_start_sso(cf, cgi))
    1245                 :          2 :         goto cgi_exit;
    1246                 :            :     } else {
    1247         [ +  - ]:          3 :       if ((ss = zxid_start_sso_location(cf, cgi)))
    1248                 :          3 :         goto res_zx_str;
    1249                 :            :     }
    1250                 :          1 :     break;
    1251                 :            :   case 'A':
    1252   [ +  -  -  + ]:          1 :     D("Process artifact(%s) pid=%d", cgi->saml_art, getpid());
    1253      [ -  -  + ]:          1 :     switch (zxid_sp_deref_art(cf, cgi, ses)) {
    1254                 :          0 :     case ZXID_REDIR_OK: ERR("*** Odd, redirect on artifact deref. %d", 0); break;
    1255                 :            :     case ZXID_SSO_OK:
    1256                 :          4 : show_protected_content_setcookie:
    1257   [ +  -  -  + ]:          4 :       D("show_protected_content_setcookie: (%s)", cf->ses_cookie_name);
    1258   [ +  -  +  - ]:          4 :       if (cf->ses_cookie_name && *cf->ses_cookie_name) {
    1259   [ +  -  -  + ]:          4 :         ses->setcookie = zx_alloc_sprintf(cf->ctx, 0, "%s=%s; path=/%s",
    1260                 :            :                                           cf->ses_cookie_name, ses->sid,
    1261                 :            :                                           ONE_OF_2(cf->url[4], 's', 'S')?"; secure":"");
    1262                 :          4 :         ses->cookie = zx_alloc_sprintf(cf->ctx, 0, "$Version=1; %s=%s",
    1263                 :            :                                        cf->ses_cookie_name, ses->sid);
    1264                 :            :       }
    1265                 :          4 :       ses->rs = cgi->rs;
    1266                 :          4 :       return zxid_simple_ab_pep(cf, ses, res_len, auto_flags);
    1267                 :            :     }
    1268                 :          1 :     break;
    1269                 :            :   case 'P':    /* POST Profile Responses */
    1270                 :            :   case 'I':
    1271                 :            :   case 'K':
    1272                 :            :   case 'Q':    /* POST Profile Requests */
    1273                 :            :     DD("PRE saml_req(%s) saml_resp(%s) rs(%s) sigalg(%s) sig(%s)", STRNULLCHK(cgi->saml_req),  STRNULLCHK(cgi->saml_resp), cgi->rs, cgi->sigalg, cgi->sig);
    1274                 :          8 :     ss = zxid_sp_dispatch(cf, cgi, ses);
    1275   [ +  -  -  + ]:          8 :     D("POST dispatch_loc(%s)", ss->s);
    1276   [ +  -  -  -  :          8 :     switch (ss->s[0]) {
                      + ]
    1277                 :          4 :     case 'O': goto show_protected_content_setcookie;
    1278                 :          0 :     case 'M': return zxid_simple_ab_pep(cf, ses, res_len, auto_flags); /* Mgmt screen case */
    1279                 :            :     case 'L':  /* Location */
    1280         [ #  # ]:          0 :       if (auto_flags & ZXID_AUTO_REDIR) {
    1281                 :          0 :         printf("%.*s", ss->len, ss->s);
    1282                 :          0 :         zx_str_free(cf->ctx, ss);
    1283                 :          0 :         fflush(stdout);
    1284                 :          0 :         goto cgi_exit;
    1285                 :            :       } else
    1286                 :          0 :         goto res_zx_str;
    1287                 :          0 :     case 'I': goto idp;
    1288                 :            :     }
    1289   [ +  -  -  + ]:          4 :     D("Q err (fall thru) %d", 0);
    1290                 :          4 :     break;
    1291                 :          1 :   case 'c':    return zxid_simple_show_carml(cf, cgi, res_len, auto_flags);
    1292                 :          1 :   case 'd':    return zxid_simple_show_conf(cf, cgi, res_len, auto_flags);
    1293                 :          4 :   case 'B':    return zxid_simple_show_meta(cf, cgi, res_len, auto_flags);
    1294                 :            :   case 'D': /*  Delegation / Inviatation URL clicked. */
    1295                 :          1 :      return zxid_ps_accept_invite(cf, cgi, ses, res_len, auto_flags);
    1296                 :            :   case 'R':
    1297                 :          1 :     cgi->op = 'F';
    1298                 :            :     /* Fall thru */
    1299                 :            :   case 'F':
    1300                 :          5 : idp:           return zxid_simple_idp_show_an(cf, cgi, res_len, auto_flags);
    1301                 :          2 :   case 'p':    return zxid_simple_idp_pw_authn(cf, cgi, res_len, auto_flags);
    1302                 :          1 :   case 'N':    return zxid_simple_idp_new_user(cf, cgi, res_len, auto_flags);
    1303                 :          1 :   case 'W':    return zxid_simple_idp_recover_password(cf, cgi, res_len, auto_flags);
    1304                 :            :   default:
    1305         [ -  + ]:          6 :     if (cf->bare_url_entityid)
    1306                 :          0 :       return zxid_simple_show_meta(cf, cgi, res_len, auto_flags);
    1307   [ +  -  -  + ]:          6 :     D("unknown op(%c)", cgi->op);
    1308                 :            :   }
    1309                 :         17 :   return zxid_simple_show_idp_sel(cf, cgi, res_len, auto_flags);
    1310                 :            : 
    1311                 :          5 : cgi_exit:
    1312         [ +  - ]:          5 :   if (auto_flags & ZXID_AUTO_EXIT)
    1313                 :          5 :     exit(0);
    1314                 :          0 :   res = zx_dup_cstr(cf->ctx, "n");
    1315         [ #  # ]:          0 :   if (res_len)
    1316                 :          0 :     *res_len = 1;
    1317                 :          0 :   return res;
    1318                 :            : 
    1319                 :          3 : res_zx_str:
    1320                 :          3 :   res = ss->s;
    1321         [ -  + ]:          3 :   if (res_len)
    1322                 :          0 :     *res_len = ss->len;
    1323                 :          3 :   ZX_FREE(cf->ctx, ss);
    1324                 :          3 :   return res;
    1325                 :            : }
    1326                 :            : 
    1327                 :            : /*(i) Simple handler that assumes the configuration has already been read in.
    1328                 :            :  * The memory for result is grabbed from ZX_ALLOC(), usually malloc(3)
    1329                 :            :  * and is "given" away to the caller, i.e. caller must free it. The
    1330                 :            :  * return value is LDIF (or JSON or query string, if configured)
    1331                 :            :  * of attributes in success case.
    1332                 :            :  * res_len, if non-null, will receive the length of the response.
    1333                 :            :  *
    1334                 :            :  * The major advantage of zxid_simple_cf_ses() is that the session stays
    1335                 :            :  * as binary object and does not need to be recreated / reparsed from
    1336                 :            :  * filesystem representation. The object can be directly used for PEP
    1337                 :            :  * calls (but see inline PEP call enabled by PDPURL) and WSC.
    1338                 :            :  *
    1339                 :            :  * cf:: Configuration object
    1340                 :            :  * qs_len:: Length of the query string. -1 = use strlen()
    1341                 :            :  * qs:: Query string (or POST content)
    1342                 :            :  * ses:: Session object
    1343                 :            :  * res_len:: Result parameter. If non-null, will be set to the length of the returned string
    1344                 :            :  * auto_flags:: Automation flags, see zxid-simple.pd for documentation
    1345                 :            :  * return:: String representing protocol action or SSO attributes
    1346                 :            :  *
    1347                 :            :  * N.B. More complete documentation is available in <<link: zxid-simple.pd>> (*** fixme) */
    1348                 :            : 
    1349                 :            : /* Called by:  zxid_simple_cf */
    1350                 :            : char* zxid_simple_cf_ses(zxid_conf* cf, int qs_len, char* qs, zxid_ses* ses, int* res_len, int auto_flags)
    1351                 :        196 : {
    1352                 :            :   int got, ret;
    1353                 :            :   char* remote_addr;
    1354                 :            :   char* cont_len;
    1355                 :        196 :   char* buf = 0;
    1356                 :        196 :   char* res = 0;
    1357                 :            :   zxid_cgi cgi;
    1358                 :        196 :   ZERO(&cgi, sizeof(cgi));
    1359                 :            :   
    1360   [ +  -  -  + ]:        196 :   if (!cf || !ses) {
    1361                 :          0 :     ERR("NULL pointer. You MUST supply configuration object %p and session object %p (programming error). auto_flags=%x", cf, ses, auto_flags);
    1362                 :          0 :     exit(1);
    1363                 :            :   }
    1364                 :            :   
    1365                 :            :   /*fprintf(stderr, "qs(%s) arg, autoflags=%x\n", qs, auto_flags);*/
    1366         [ +  - ]:        196 :   if (auto_flags & ZXID_AUTO_DEBUG) zxid_set_opt(cf, 1, 1);
    1367   [ -  +  #  # ]:        196 :   LOCK(cf->mx, "simple ipport");
    1368         [ +  - ]:        196 :   if (!cf->ipport) {
    1369                 :        196 :     remote_addr = getenv("REMOTE_ADDR");
    1370         [ +  + ]:        196 :     if (remote_addr) {
    1371                 :        166 :       ses->ipport = ZX_ALLOC(cf->ctx, strlen(remote_addr) + 6 + 1); /* :12345 */
    1372                 :        166 :       sprintf(ses->ipport, "%s:-", remote_addr);
    1373                 :        166 :       cf->ipport = ses->ipport;
    1374                 :            :     }
    1375                 :            :   }
    1376   [ -  +  #  # ]:        196 :   UNLOCK(cf->mx, "simple ipport");
    1377                 :            :   
    1378         [ +  + ]:        196 :   if (!qs) {
    1379                 :        183 :     qs = getenv("QUERY_STRING");
    1380         [ +  - ]:        183 :     if (qs) {
    1381   [ +  -  +  -  :        183 :       D("QUERY_STRING(%s) %s", STRNULLCHK(qs), ZXID_REL);
                   -  + ]
    1382                 :        183 :       zxid_parse_cgi(&cgi, qs);
    1383   [ +  +  +  +  :        192 :       if (ONE_OF_3(cgi.op, 'P', 'R', 'S')) {
                   +  + ]
    1384                 :        146 :         cont_len = getenv("CONTENT_LENGTH");
    1385         [ +  + ]:        146 :         if (cont_len) {
    1386                 :        143 :           sscanf(cont_len, "%d", &got);
    1387   [ +  -  -  + ]:        143 :           D("o=%c cont_len=%s got=%d rel=%s", cgi.op, cont_len, got, ZXID_REL);
    1388                 :        143 :           buf = ZX_ALLOC(cf->ctx, got);
    1389         [ -  + ]:        143 :           if (!buf) {
    1390                 :          0 :             ERR("out of memory len=%d", got);
    1391                 :          0 :             exit(1);
    1392                 :            :           }
    1393         [ -  + ]:        143 :           if (read_all_fd(0, buf, got, &got) == -1) {
    1394                 :          0 :             perror("Trouble reading post content.");
    1395                 :            :           } else {
    1396                 :        143 :             buf[got] = 0;
    1397                 :            :             DD("POST(%s) got=%d cont_len(%s)", buf, got, cont_len);
    1398                 :        143 :             D_XML_BLOB(cf, "POST", got, buf);
    1399         [ +  + ]:        143 :             if (buf[0] == '<') goto sp_soap;  /* No BOM and looks like XML */
    1400         [ -  + ]:          6 :             if (buf[2] == '<') {              /* UTF-16 BOM and looks like XML */
    1401                 :          0 :               got-=2; buf+=2;
    1402                 :          0 :               ERR("UTF-16 NOT SUPPORTED %x%x", buf[0], buf[1]);
    1403                 :          0 :               goto sp_soap;
    1404                 :            :             }
    1405         [ -  + ]:          6 :             if (buf[3] == '<') {              /* UTF-8 BOM and looks XML */
    1406                 :          0 :               got-=3; buf+=3;
    1407                 :        137 :             sp_soap:
    1408                 :            :               /* *** TODO: SOAP response should not be sent internally unless there is auto */
    1409                 :        137 :               ret = zxid_sp_soap_parse(cf, &cgi, ses, got, buf);
    1410   [ +  -  -  + ]:        137 :               D("POST soap parse returned %d (0=fail, 1=ok, 2=redir, 3=sso ok)", ret);
    1411         [ -  + ]:        137 :               if (ret == ZXID_SSO_OK)
    1412                 :          0 :                 return zxid_simple_ab_pep(cf, ses, res_len, auto_flags);
    1413   [ -  +  #  # ]:        137 :               if (auto_flags & ZXID_AUTO_SOAPC || auto_flags & ZXID_AUTO_SOAPH) {
    1414         [ +  - ]:        137 :                 if (auto_flags & ZXID_AUTO_EXIT)
    1415                 :        137 :                   exit(0);
    1416                 :          0 :                 res = zx_dup_cstr(cf->ctx, "n");
    1417         [ #  # ]:          0 :                 if (res_len)
    1418                 :          0 :                   *res_len = 1;
    1419                 :          0 :                 goto done;
    1420                 :            :               }
    1421         [ #  # ]:          0 :               res = zx_dup_cstr(cf->ctx, ret ? "n" : "*** SOAP error (enable debug if you want to see why)"); 
    1422         [ #  # ]:          0 :               if (res_len)
    1423                 :          0 :                 *res_len = strlen(res);
    1424                 :          0 :               goto done;
    1425                 :            :             }
    1426                 :          6 :             zxid_parse_cgi(&cgi, buf);
    1427                 :            :           }
    1428                 :            :         } else {
    1429   [ +  -  -  + ]:          3 :           D("o=%c post, but no CONTENT_LENGTH rel=%s", cgi.op, ZXID_REL);
    1430                 :            :         }
    1431                 :            :       } else {
    1432   [ +  -  -  + ]:         37 :         D("o=%c other rel=%s", cgi.op, ZXID_REL);
    1433                 :            :       }
    1434                 :            :     }
    1435                 :            :   } else {
    1436         [ +  + ]:         13 :     if (qs_len == -1)
    1437                 :         12 :       qs_len = strlen(qs);
    1438         [ -  + ]:         13 :     if (qs[qs_len]) {   /* *** reads one past end of buffer */
    1439                 :          0 :       ERR("IMPLEMENTATION LIMIT: Query String MUST be nul terminated len=%d", qs_len);
    1440                 :          0 :       exit(1);
    1441                 :            :     }
    1442   [ +  -  +  -  :         13 :     D("QUERY_STRING(%s) %s", STRNULLCHK(qs), ZXID_REL);
                   -  + ]
    1443                 :         13 :     zxid_parse_cgi(&cgi, qs);
    1444                 :            :   }
    1445   [ +  +  +  - ]:         59 :   if (!cgi.op && !cf->bare_url_entityid)
    1446                 :          1 :     cgi.op = 'M';  /* By default, if no ses, check CDC and offer SSO */
    1447                 :            : 
    1448   [ +  +  +  -  :         59 :   if (!cgi.sid && cf->ses_cookie_name && *cf->ses_cookie_name)
                   +  - ]
    1449                 :         52 :     zxid_get_sid_from_cookie(cf, &cgi, getenv("HTTP_COOKIE"));
    1450                 :            : 
    1451         [ +  + ]:         59 :   if (cgi.sid) {
    1452         [ +  + ]:         21 :       if (!zxid_get_ses(cf, ses, cgi.sid)) {
    1453   [ +  -  -  + ]:          7 :         D("No session(%s) active op(%c)", cgi.sid, cgi.op);
    1454                 :            :       } else
    1455         [ +  - ]:         14 :         if (res = zxid_simple_ses_active_cf(cf, &cgi, ses, res_len, auto_flags))
    1456                 :          4 :           goto done;
    1457                 :            :   }
    1458                 :            : 
    1459                 :         45 :   ZERO(ses, sizeof(zxid_ses));   /* No session yet! Process login form */
    1460                 :         45 :   res = zxid_simple_no_ses_cf(cf, &cgi, ses, res_len, auto_flags);
    1461                 :            : 
    1462                 :         17 : done:
    1463         [ +  + ]:         17 :   if (buf)
    1464                 :          1 :     ZX_FREE(cf->ctx, buf);
    1465                 :         17 :   return res;
    1466                 :            : }
    1467                 :            : 
    1468                 :            : /*() Allocate simple session and then call simple handler. Strings
    1469                 :            :  * are length + pointer (no C string nul termination needed).
    1470                 :            :  * A wrapper for zxid_simple_cf().
    1471                 :            :  *
    1472                 :            :  * cf:: Configuration object
    1473                 :            :  * qs_len:: Length of the query string. -1 = use strlen()
    1474                 :            :  * qs:: Query string (or POST content)
    1475                 :            :  * res_len:: Result parameter. If non-null, will be set to the length of the returned string
    1476                 :            :  * auto_flags:: Automation flags, see zxid-simple.pd for documentation
    1477                 :            :  * return:: String representing protocol action or SSO attributes
    1478                 :            :  *
    1479                 :            :  * N.B. More complete documentation is available in <<link: zxid-simple.pd>> (*** fixme) */
    1480                 :            : 
    1481                 :            : /* Called by:  main x3, zxid_simple_len, zxidwspcgi_main */
    1482                 :            : char* zxid_simple_cf(zxid_conf* cf, int qs_len, char* qs, int* res_len, int auto_flags)
    1483                 :        196 : {
    1484                 :            :   zxid_ses ses;
    1485                 :        196 :   ZERO(&ses, sizeof(ses));
    1486                 :        196 :   return zxid_simple_cf_ses(cf, qs_len, qs, &ses, res_len, auto_flags);
    1487                 :            : }
    1488                 :            : 
    1489                 :            : /*() Process simple configuration and then call simple handler. Strings
    1490                 :            :  * are length + pointer (no C string nul termination needed).
    1491                 :            :  * a wrapper for zxid_simple_cf().
    1492                 :            :  *
    1493                 :            :  * N.B. More complete documentation is available in <<link: zxid-simple.pd>> (*** fixme) */
    1494                 :            : 
    1495                 :            : /* Called by:  zxid_simple */
    1496                 :            : char* zxid_simple_len(int conf_len, char* conf, int qs_len, char* qs, int* res_len, int auto_flags)
    1497                 :        183 : {
    1498                 :            :   struct zx_ctx ctx;
    1499                 :            :   zxid_conf cf;
    1500                 :        183 :   zx_reset_ctx(&ctx);
    1501                 :        183 :   ZERO(&cf, sizeof(cf));
    1502                 :        183 :   cf.ctx = &ctx;
    1503                 :        183 :   zxid_conf_to_cf_len(&cf, conf_len, conf);
    1504                 :        183 :   return zxid_simple_cf(&cf, qs_len, qs, res_len, auto_flags);
    1505                 :            : }
    1506                 :            : 
    1507                 :            : /*() Main simple interface. C string nul termination is assumed. Really just
    1508                 :            :  * a wrapper for zxid_simple_cf().
    1509                 :            :  *
    1510                 :            :  * N.B. More complete documentation is available in <<link: zxid-simple.pd>> (*** fixme) */
    1511                 :            : 
    1512                 :            : /* Called by:  main x4 */
    1513                 :            : char* zxid_simple(char* conf, char* qs, int auto_flags)
    1514                 :        183 : {
    1515                 :        183 :   return zxid_simple_len(-1, conf, -1, qs, 0, auto_flags);
    1516                 :            : }
    1517                 :            : 
    1518                 :            : /* EOF  --  zxidsimp.c */

Generated by: LCOV version 1.9