LCOV - code coverage report
Current view: top level - zxid - zxidcgi.c (source / functions) Hit Total Coverage
Test: ZXID Code Coverage Lines: 130 145 89.7 %
Date: 2010-12-19 Functions: 3 3 100.0 %
Branches: 171 277 61.7 %

           Branch data     Line data    Source code
       1                 :            : /* zxidcgi.c  -  Handwritten functions for parsing SP specific CGI options
       2                 :            :  * Copyright (c) 2010 Sampo Kellomaki (sampo@iki.fi), All Rights Reserved.
       3                 :            :  * Copyright (c) 2006-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: zxidcgi.c,v 1.33 2010-01-08 02:10:09 sampo Exp $
      10                 :            :  *
      11                 :            :  * 12.8.2006, created --Sampo
      12                 :            :  * 16.1.2007, split from zxidlib.c --Sampo
      13                 :            :  * 12.10.2007, added cookie scanning --Sampo
      14                 :            :  * 7.10.2008, added documentation --Sampo
      15                 :            :  *
      16                 :            :  * See also: http://hoohoo.ncsa.uiuc.edu/cgi/interface.html (CGI specification)
      17                 :            :  */
      18                 :            : 
      19                 :            : #include <memory.h>
      20                 :            : #include <string.h>
      21                 :            : #include "errmac.h"
      22                 :            : #include "zxid.h"
      23                 :            : #include "zxidconf.h"
      24                 :            : 
      25                 :            : /* ============== CGI Parsing ============== */
      26                 :            : 
      27                 :            : /*(i) Parse query string or form POST and detect parameters relevant for ZXID.
      28                 :            :  * N.B. This CGI parsing is very specific for needs of ZXID. It is not generic.
      29                 :            :  *
      30                 :            :  * cgi:: Already allocated CGI structure where results of this function
      31                 :            :  *     are deposited. Note that this structure is not cleared. Thus it is
      32                 :            :  *     possible to call zxid_parse_cgi() multiple times to accumulate
      33                 :            :  *     results from multiple sources, e.g. foirst for query string, and then
      34                 :            :  *     for form POST.
      35                 :            :  * qs:: CGI formatted input. Usually query string or form POST content.
      36                 :            :  * return:: 0 on success. Other values reserved. Usually return value is
      37                 :            :  *     ignored as there really is no way for this function to fail. Unrecognized
      38                 :            :  *     CGI arguments are simply ignored with assumption that some other processing
      39                 :            :  *     layer will pick them up - hence no need to flag error. */
      40                 :            : 
      41                 :            : /* Called by:  chkuid x3, main x4, zxid_decode_ssoreq, zxid_new_cgi, zxid_simple_cf_ses x3 */
      42                 :            : int zxid_parse_cgi(zxid_cgi* cgi, char* qs)
      43                 :        203 : {
      44                 :            :   char *p, *n, *v, *val, *name;
      45                 :            :   DD("qs(%s) len=%d", STRNULLCHK(qs), qs?strlen(qs):-1);
      46         [ -  + ]:        203 :   if (!qs)
      47                 :          0 :     return 0;
      48   [ +  -  +  + ]:        752 :   while (qs && *qs) {
      49         [ +  + ]:        346 :     for (; *qs == '&'; ++qs) ;                  /* Skip over & or && */
      50         [ +  - ]:        346 :     if (!*qs) break;
      51                 :            :     
      52                 :        346 :     qs = strchr(name = qs, '=');                /* Scan name (until '=') */
      53         [ +  - ]:        346 :     if (!qs) break;
      54         [ +  + ]:        346 :     if (qs == name) {                           /* Key was an empty string: skip it */
      55                 :          1 :       qs = strchr(qs, '&');                     /* Scan value (until '&') *** or '?' */
      56                 :          1 :       continue;
      57                 :            :     }
      58   [ +  -  -  + ]:        345 :     for (; name < qs && *name <= ' '; ++name) ; /* Skip over initial whitespace before name */
      59                 :        345 :     n = p = name;
      60   [ +  +  +  -  :        345 :     URL_DECODE(p, name, qs);
          +  -  -  +  #  
          #  #  #  #  #  
          #  #  +  -  +  
          -  +  -  -  +  
          #  #  #  #  +  
          -  +  -  +  -  
          -  +  -  +  +  
                      + ]
      61                 :        345 :     *p = 0;                                     /* Nul-term n (name) */
      62                 :            :     
      63   [ +  +  +  + ]:        345 :     for (val = ++qs; *qs && *qs != '&'; ++qs) ; /* Skip over = and scan value (until '&') */
      64                 :        345 :     v = p = val;
      65                 :            :     /* SAMLRequest and Response MUST NOT be URL decoded as the URL encoding
      66                 :            :      * is needed for redirect binding signature validation. See also unbase64_raw()
      67                 :            :      * for how these fields are URL decoded at later stage. */
      68   [ +  +  +  +  :        648 :     if (n[0] != 'S' && n[0] != 'R'
          +  +  +  +  +  
             +  +  +  +  
                      + ]
      69                 :            :         || strcmp(n, "SAMLRequest") && strcmp(n, "SAMLResponse")
      70                 :            :         && strcmp(n, "SigAlg") && strcmp(n, "Signature") && strcmp(n, "RelayState"))
      71   [ +  +  +  -  :        303 :       URL_DECODE(p, val, qs);
          +  -  -  +  #  
          #  #  #  #  #  
          #  #  +  -  +  
          +  +  -  -  +  
          #  #  #  #  +  
          -  +  -  +  -  
          +  +  +  +  +  
                      + ]
      72                 :            :     else
      73                 :         42 :       p = qs;
      74                 :            : 
      75         [ +  + ]:        345 :     if (*qs)
      76                 :        142 :       ++qs;
      77                 :        345 :     *p = 0;                                     /* Nul-term v (value) */
      78                 :            :     
      79   [ +  +  +  +  :        345 :     switch (n[0]) {
          +  +  +  +  +  
             +  +  +  +  
                      - ]
      80                 :            :     case 'o':
      81         [ +  + ]:        180 :       if (!n[1]) { cgi->op = v[0];    break; }
      82         [ +  + ]:          2 :       if (n[1] = 'k' && !n[2]) { cgi->ok = v;  break; }  /* ok button */
      83                 :          1 :       goto unknown;
      84                 :            :     case 's':
      85         [ +  - ]:          8 :       if (!n[1]) { cgi->sid = v; break; }
      86                 :          0 :       goto unknown;
      87                 :            :     case 'c':
      88         [ +  - ]:          1 :       if (!n[1]) { cgi->cdc = v; break; }
      89                 :          0 :       goto unknown;
      90                 :            :       /* The following two entity IDs, combined with various login buttons
      91                 :            :        * aim at supporting may different user interface layouts. You need to
      92                 :            :        * understand how they interact to avoid undesired conflicts. */
      93                 :            :     case 'e':  /* EntityID field (manual entry). Overrides 'd'. */
      94         [ +  - ]:          6 :       if (!n[1]) {
      95                 :          6 : set_eid:
      96         [ +  + ]:          6 :         if (v[0]) cgi->eid = v;
      97                 :            :         DD("v(%s) v0=0x%02x v=%p cgi->eid=%p cgi=%p", v, v[0], v, cgi->eid, cgi);
      98                 :          6 :         break;
      99                 :            :       }
     100                 :          0 :       goto unknown;
     101                 :            :     case 'd':  /* EntityID popup or radio box */
     102         [ +  - ]:          1 :       if (!n[1]) {
     103   [ +  -  +  - ]:          1 :         if (cgi->eid && cgi->eid[0]) {
     104   [ -  +  #  # ]:          1 :           D("EID already set v(%s) v0=0x%02x v=%p cgi->eid=%p cgi=%p", v, v[0], v, cgi->eid, cgi);
     105                 :          1 :           break;
     106                 :            :         }
     107                 :          0 :         goto set_eid;
     108                 :            :       }
     109                 :          0 :       goto unknown;
     110                 :            :     case 'l':
     111                 :            :       /* Login button names are like lP<eid>, where "l" is literal ell, P is
     112                 :            :        * protocol profile designator, and <eid> is Entity ID of the IdP.
     113                 :            :        * N.B. If eid is omitted from button name, it may be provided using
     114                 :            :        * d or e fields (see above). */
     115                 :          8 :       cgi->pr_ix = n[1];
     116         [ +  + ]:          8 :       if (n[2])
     117                 :          7 :         cgi->eid = n+2;
     118                 :          8 :       cgi->op = 'L';
     119   [ +  +  -  + ]:          8 :       D("cgi: login eid(%s)", cgi->eid);
     120                 :          8 :       break;
     121                 :            :     case 'i':
     122         [ +  - ]:          1 :       if (!strcmp(n, "inv")) {
     123                 :          1 :         cgi->inv = v;
     124                 :          1 :         break;
     125                 :            :       }
     126                 :            :       /* IdP and protocol index selection popup values are like P<eid>
     127                 :            :        * N.B. If eid is omitted from button name, it may be provided using
     128                 :            :        * d or e fields (see above). This effectively allows i to be just
     129                 :            :        * a protocol selection popup. */
     130                 :          0 :       cgi->pr_ix = v[0];
     131         [ #  # ]:          0 :       if (v[1])
     132                 :          0 :         cgi->eid = v+1;
     133                 :          0 :       break;
     134                 :            :     case 'f':  /* flags and (hidden) fields found in typical SP login form */
     135   [ +  -  +  - ]:         67 :       if (!n[1] || n[2]) goto unknown;
     136   [ +  +  +  +  :         67 :       switch (n[1]) {
          +  +  +  +  +  
                +  +  - ]
     137   [ +  -  -  + ]:          7 :       case 'a': cgi->authn_ctx = v;       D("authn_ctx=%s", cgi->authn_ctx); break;
     138   [ +  -  -  + ]:          7 :       case 'c': cgi->allow_create = v[0]; D("allow_create=%c", cgi->allow_create); break;
     139   [ +  -  -  + ]:          7 :       case 'f': cgi->force_authn = v[0];  D("force_authn=%c", cgi->force_authn); break;
     140                 :          1 :       case 'g': cgi->get_complete = v;    break;
     141                 :          1 :       case 'h': cgi->pxy_count = v;       break;
     142                 :            :         /*case 'i': cgi->idp_list = v;        break;*/
     143                 :          7 :       case 'm': cgi->matching_rule = v;   break;
     144   [ +  -  -  + ]:          7 :       case 'n': cgi->nid_fmt = v;         D("nid_fmt=%s", cgi->nid_fmt); break;
     145   [ +  -  -  + ]:          7 :       case 'p': cgi->ispassive = v[0];    D("ispassive=%c", cgi->ispassive); break;
     146                 :          7 :       case 'q': cgi->affil = v;           break;
     147                 :          9 :       case 'r': cgi->rs = v;              break;
     148                 :          7 :       case 'y': cgi->consent = v;         break;
     149                 :            :       }
     150                 :         67 :       break;
     151                 :            :     case 'g':
     152   [ +  -  +  - ]:         15 :       if (!n[1] || n[2]) goto unknown;
     153   [ +  +  +  + ]:         15 :       switch (n[1]) {
     154                 :            :       case 'l':
     155                 :            :       case 'r':
     156                 :            :       case 's':
     157                 :            :       case 't':
     158                 :         12 :       case 'u': cgi->op = n[1];           break;
     159                 :          1 :       case 'n': cgi->newnym = v;          break;
     160                 :          1 :       case 'e': cgi->enc_hint = v[0];     break;
     161                 :            :       }
     162                 :         15 :       break;
     163                 :            :     case 'a':
     164         [ +  - ]:         13 :       if (!n[1]) goto unknown;
     165   [ +  +  +  +  :         13 :       switch (n[1]) {
             +  +  +  - ]
     166         [ +  - ]:          2 :       case 'l': if (n[3]) goto unknown;  cgi->op = n[2];           break;
     167   [ +  -  +  +  :          4 :       case 'u': if (n[2]) goto unknown;  if (v[0] || !cgi->uid) cgi->uid = v; break;
                   +  - ]
     168         [ +  - ]:          2 :       case 'p': if (n[2]) goto unknown;  cgi->pw = v;              break;
     169         [ +  - ]:          2 :       case 'r': if (n[2]) goto unknown;  cgi->ssoreq = v;          break;
     170         [ +  - ]:          1 :       case 'n': if (n[2]) goto unknown;  cgi->op = 'N';            break;
     171         [ +  - ]:          1 :       case 'w': if (n[2]) goto unknown;  cgi->op = 'W';            break;
     172         [ +  - ]:          1 :       case 't': if (n[2]) goto unknown;  cgi->atselafter = 1;      break;
     173                 :            :       }
     174                 :         13 :       break;
     175                 :            :     case 'z':
     176         [ +  - ]:          2 :       switch (n[1]) {
     177                 :            :       case 'x':
     178      [ +  -  - ]:          2 :         switch (n[2]) {
     179                 :          2 :         case 'a': cgi->zxapp = v;         break;
     180                 :          0 :         case 'r': cgi->zxrfr = v;         break;
     181                 :            :         }
     182                 :            :         break;
     183                 :            :       }
     184                 :          2 :       break;
     185                 :            :     case 'R':
     186         [ +  - ]:          6 :       if (!strcmp(n, "RelayState")) {
     187                 :          6 :         cgi->rs = v;
     188                 :          6 :         break;
     189                 :            :       }
     190                 :          0 :       break;
     191                 :            :     case 'S':
     192         [ +  + ]:         37 :       if (!strcmp(n, "SAMLart")) {
     193                 :          1 :         cgi->saml_art = v;
     194                 :          1 :         cgi->op = 'A';
     195                 :          1 :         break;
     196                 :            :       }
     197         [ +  + ]:         36 :       if (!strcmp(n, "SAMLResponse")) {
     198                 :          8 :         cgi->saml_resp = v;
     199                 :          8 :         cgi->op = 'P';
     200                 :          8 :         break;
     201                 :            :       }
     202         [ +  + ]:         28 :       if (!strcmp(n, "SAMLRequest")) {
     203                 :          8 :         cgi->saml_req = v;
     204   [ +  -  +  +  :          8 :         if (!ONE_OF_3(cgi->op, 'p', 'F', 'R'))  /* Avoid redundant sigvfy and processing for IdP */
                   +  - ]
     205                 :          2 :           cgi->op = 'Q';
     206                 :          8 :         break;
     207                 :            :       }
     208         [ +  + ]:         20 :       if (!strcmp(n, "SigAlg")) {
     209                 :         10 :         cgi->sigalg = v;
     210                 :         10 :         break;
     211                 :            :       }
     212         [ +  - ]:         10 :       if (!strcmp(n, "Signature")) {
     213                 :         10 :         cgi->sig = v;
     214                 :         10 :         break;
     215                 :            :       }
     216                 :            :       /* fall thru */
     217                 :          1 :     unknown:
     218   [ -  +  #  # ]:          1 :     default:  D("Unknown CGI field(%s) val(%s)", n, v);
     219                 :            :     }
     220                 :            :   }
     221                 :            :   DD("END cgi=%p cgi->eid=%p (%s) op(%c) magic=%x", cgi, cgi->eid, cgi->eid, cgi->op, cgi->magic);
     222                 :        203 :   return 0;
     223                 :            : }
     224                 :            : 
     225                 :            : /* Called by:  covimp_test */
     226                 :            : zxid_cgi* zxid_new_cgi(zxid_conf* cf, char* qs)
     227                 :          1 : {
     228                 :          1 :   zxid_cgi* cgi = ZX_ZALLOC(cf->ctx, zxid_cgi);
     229                 :          1 :   cgi->magic = ZXID_CGI_MAGIC;
     230         [ +  - ]:          1 :   if (qs) {
     231                 :            :     char* qqs;
     232                 :          1 :     int len = strlen(qs);
     233                 :          1 :     qqs = ZX_ALLOC(cf->ctx, len+1);
     234                 :          1 :     memcpy(qqs, qs, len);
     235                 :          1 :     qqs[len] = 0;
     236                 :          1 :     zxid_parse_cgi(cgi, qqs);
     237                 :            :   }
     238                 :          1 :   return cgi;
     239                 :            : }
     240                 :            : 
     241                 :            : /*() Try to extract session ID from a cookie. The extracted value, if any,
     242                 :            :  * will be deposited in cgi->sid. If no session ID is found, then cgi->sid
     243                 :            :  * is not modified. The name of the cookie is determined by configuration
     244                 :            :  * option ~SES_COOKIE_NAME~ (see zxidconf.h).
     245                 :            :  *
     246                 :            :  * return:: none, but cgi->sid is modified
     247                 :            :  *
     248                 :            :  * For original Netscape cookie spec see: http://curl.haxx.se/rfc/cookie_spec.html (Oct2007)
     249                 :            :  *
     250                 :            :  * *Example*
     251                 :            :  *
     252                 :            :  *    ONE_COOKIE=aaa; ZXIDSES=S12cvd324; SOME_OTHER_COOKIE=...
     253                 :            :  */
     254                 :            : 
     255                 :            : /* Called by:  chkuid, zxid_simple_cf_ses */
     256                 :            : void zxid_get_sid_from_cookie(zxid_conf* cf, zxid_cgi* cgi, const char* cookie)
     257                 :         52 : {
     258                 :            :   char* q;
     259                 :            :   int len;
     260         [ +  + ]:         52 :   if (!cookie)
     261                 :         38 :     return;
     262                 :         14 :   len = strlen(cf->ses_cookie_name);
     263                 :         14 :   for (cookie = strstr(cookie, cf->ses_cookie_name);
     264         [ +  - ]:         28 :        cookie;
     265                 :          0 :        cookie = strstr(cookie + 1, cf->ses_cookie_name))
     266         [ +  - ]:         14 :     if (cookie[len] == '=') {
     267                 :         14 :       cookie += len + 1;
     268         [ -  + ]:         14 :       if (*cookie == '"')
     269                 :          0 :         ++cookie;
     270                 :         14 :       q = strchr(cookie, ';');
     271         [ -  + ]:         14 :       len = q ? (q-cookie) : strlen(cookie);
     272         [ -  + ]:         14 :       if (cookie[len-1] == '"')
     273                 :          0 :         --len;
     274                 :         14 :       cgi->sid = ZX_ALLOC(cf->ctx, len + 1);
     275                 :         14 :       memcpy(cgi->sid, cookie, len);
     276                 :         14 :       cgi->sid[len] = 0;
     277                 :         14 :       return;
     278                 :            :     }
     279                 :            : }
     280                 :            : 
     281                 :            : /* EOF  --  zxidcgi.c */

Generated by: LCOV version 1.9