auth_hdr.c

Go to the documentation of this file.
00001 /*
00002  * $Id: auth_hdr.c 4585 2008-08-06 08:20:30Z klaus_darilion $
00003  *
00004  * Copyright (C) 2005 Voice Sistem SRL
00005  *
00006  * This file is part of Kamailio, a free SIP server.
00007  *
00008  * UAC Kamailio-module is free software; you can redistribute it and/or
00009  * modify it under the terms of the GNU General Public License
00010  * as published by the Free Software Foundation; either version 2
00011  * of the License, or (at your option) any later version.
00012  *
00013  * UAC Kamailio-module is distributed in the hope that it will be useful,
00014  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016  * GNU General Public License for more details.
00017  *
00018  * You should have received a copy of the GNU General Public License
00019  * along with this program; if not, write to the Free Software
00020  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00021  *
00022  *
00023  * History:
00024  * ---------
00025  *  2005-01-31  first version (ramona)
00026  */
00027 
00028 
00029 #include "string.h"
00030 #include "ctype.h"
00031 
00032 #include "../../dprint.h"
00033 #include "../../str.h"
00034 #include "../../mem/mem.h"
00035 
00036 #include "auth_hdr.h"
00037 #include "auth.h"
00038 
00039 
00040 #define AUTHENTICATE_MD5         (1<<0)
00041 #define AUTHENTICATE_MD5SESS     (1<<1)
00042 #define AUTHENTICATE_STALE       (1<<2)
00043 
00044 #define AUTHENTICATE_DIGEST_S    "Digest"
00045 #define AUTHENTICATE_DIGEST_LEN  (sizeof(AUTHENTICATE_DIGEST_S)-1)
00046 
00047 #define LOWER1B(_n) \
00048    ((_n)|0x20)
00049 #define LOWER4B(_n) \
00050    ((_n)|0x20202020)
00051 #define GET4B(_p) \
00052    ((*(_p)<<24) + (*(_p+1)<<16) + (*(_p+2)<<8) + *(_p+3))
00053 #define GET3B(_p) \
00054    ((*(_p)<<24) + (*(_p+1)<<16) + (*(_p+2)<<8) + 0xff)
00055 
00056 #define CASE_5B(_hex4,_c5, _new_state, _quoted) \
00057    case _hex4: \
00058       if (p+5<end && LOWER1B(*(p+4))==_c5 ) \
00059       { \
00060          p+=5; \
00061          state = _new_state; \
00062          quoted_val = _quoted; \
00063       } else { \
00064          p+=4; \
00065       } \
00066       break;
00067 
00068 #define CASE_6B(_hex4,_c5,_c6, _new_state, _quoted) \
00069    case _hex4: \
00070       if (p+6<end && LOWER1B(*(p+4))==_c5 && LOWER1B(*(p+5))==_c6) \
00071       { \
00072          p+=6; \
00073          state = _new_state; \
00074          quoted_val = _quoted; \
00075       } else { \
00076          p+=4; \
00077       } \
00078       break;
00079 
00080 #define OTHER_STATE      0
00081 #define QOP_STATE        1
00082 #define REALM_STATE      2
00083 #define NONCE_STATE      3
00084 #define STALE_STATE      4
00085 #define DOMAIN_STATE     5
00086 #define OPAQUE_STATE     6
00087 #define ALGORITHM_STATE  7
00088 
00089 
00090 
00091 int parse_authenticate_body( str *body, struct authenticate_body *auth)
00092 {
00093    char *p;
00094    char *end;
00095    int  n;
00096    int state;
00097    str name;
00098    str val;
00099    int quoted_val;
00100 
00101    if (body->s==0 || *body->s==0 )
00102    {
00103       LM_ERR("empty body\n");
00104       goto error;
00105    }
00106 
00107    memset( auth, 0, sizeof(struct authenticate_body));
00108    p = body->s;
00109    end = body->s + body->len;
00110 
00111    /* parse the "digest" */
00112    while (p<end && isspace((int)*p)) p++;
00113    if (p+AUTHENTICATE_DIGEST_LEN>=end )
00114       goto parse_error;
00115    if (strncmp(p,AUTHENTICATE_DIGEST_S,AUTHENTICATE_DIGEST_LEN)!=0)
00116       goto parse_error;
00117    p += AUTHENTICATE_DIGEST_LEN;
00118    if (!isspace((int)*p))
00119       goto parse_error;
00120    p++;
00121    while (p<end && isspace((int)*p)) p++;
00122    if (p==end)
00123       goto parse_error;
00124 
00125    while (p<end)
00126    {
00127       state = OTHER_STATE;
00128       quoted_val = 0;
00129       /* get name */
00130       name.s = p;
00131       if (p+4<end)
00132       {
00133          n = LOWER4B( GET4B(p) );
00134          switch(n)
00135          {
00136             CASE_5B( 0x7265616c, 'm', REALM_STATE, 1); /*realm*/
00137             CASE_5B( 0x6e6f6e63, 'e', NONCE_STATE, 1); /*nonce*/
00138             CASE_5B( 0x7374616c, 'e', STALE_STATE, 0); /*stale*/
00139             CASE_6B( 0x646f6d62, 'i', 'n', DOMAIN_STATE, 1); /*domain*/
00140             CASE_6B( 0x6f706171, 'u', 'e', OPAQUE_STATE, 1); /*opaque*/
00141             case 0x616c676f: /*algo*/
00142                if (p+9<end && LOWER4B(GET4B(p+4))==0x72697468
00143                   && LOWER1B(*(p+8))=='m' )
00144                {
00145                   p+=9;
00146                   state = ALGORITHM_STATE;
00147                } else {
00148                   p+=4;
00149                }
00150                break;
00151             default:
00152                if ((n|0xff)==0x716f70ff) /*qop*/
00153                {
00154                   state = QOP_STATE;
00155                   p+=3;
00156                }
00157          }
00158       } else if (p+3<end) {
00159          n = LOWER4B( GET3B(p) );
00160          if (n==0x716f70ff) /*qop*/
00161          {
00162             p+=3;
00163             state = QOP_STATE;
00164          }
00165       }
00166 
00167       /* parse to the "=" */
00168       for( n=0 ; p<end&&!isspace((int)*p)&&*p!='=' ; n++,p++  );
00169       if (p==end)
00170          goto parse_error;
00171       if (n!=0)
00172          state = OTHER_STATE;
00173       name.len = p-name.s;
00174       /* get the '=' */
00175       while (p<end && isspace((int)*p)) p++;
00176       if (p==end || *p!='=')
00177          goto parse_error;
00178       p++;
00179       /* get the value (quoted or not) */
00180       while (p<end && isspace((int)*p)) p++;
00181       if (p+1>=end || (quoted_val && *p!='\"'))
00182          goto parse_error;
00183       if (!quoted_val && *p=='\"')
00184          quoted_val = 1;
00185       if (quoted_val)
00186       {
00187          val.s = ++p;
00188          while (p<end && *p!='\"')
00189             p++;
00190          if (p==end)
00191             goto error;
00192       } else {
00193          val.s = p;
00194          while (p<end && !isspace((int)*p) && *p!=',')
00195             p++;
00196       }
00197       val.len = p - val.s;
00198       if (val.len==0)
00199          val.s = 0;
00200       /* consume the closing '"' if quoted */
00201       p += quoted_val;
00202       while (p<end && isspace((int)*p)) p++;
00203       if (p<end && *p==',')
00204       {
00205          p++;
00206          while (p<end && isspace((int)*p)) p++;
00207       }
00208 
00209       LM_DBG("<%.*s>=\"%.*s\" state=%d\n",
00210          name.len,name.s,val.len,val.s,state);
00211 
00212       /* process the AVP */
00213       switch (state)
00214       {
00215          case QOP_STATE:
00216             auth->qop = val;
00217             if(val.len>=4 && !strncmp(val.s, "auth", 4))
00218                auth->flags |= QOP_AUTH;
00219             break;
00220          case REALM_STATE:
00221             auth->realm = val;
00222             break;
00223          case NONCE_STATE:
00224             auth->nonce = val;
00225             break;
00226          case DOMAIN_STATE:
00227             auth->domain = val;
00228             break;
00229          case OPAQUE_STATE:
00230             auth->opaque = val;
00231             break;
00232          case ALGORITHM_STATE:
00233             if (val.len==3)
00234             {
00235                if ( LOWER4B(GET3B(val.s))==0x6d6435ff) /*MD5*/
00236                   auth->flags |= AUTHENTICATE_MD5;
00237             } else {
00238                LM_ERR("unsupported algorithm \"%.*s\"\n",val.len,val.s);
00239                goto error;
00240             }
00241             break;
00242          case STALE_STATE:
00243             if (val.len==4 && LOWER4B(GET4B(val.s))==0x74727565) /*true*/
00244             {
00245                   auth->flags |= AUTHENTICATE_STALE;
00246             } else if ( !(val.len==5 && LOWER1B(val.s[4])=='e' && 
00247                LOWER4B(GET4B(val.s))==0x66616c73) )
00248             {
00249                LM_ERR("unsupported stale value \"%.*s\"\n",val.len,val.s);
00250                goto error;
00251             }
00252             break;
00253          default:
00254             break;
00255       }
00256    }
00257 
00258    /* some checkings */
00259    if (auth->nonce.s==0 || auth->realm.s==0)
00260    {
00261       LM_ERR("realm or nonce missing\n");
00262       goto error;
00263    }
00264 
00265    return 0;
00266 parse_error:
00267       LM_ERR("parse error in <%.*s> around %ld\n", body->len, body->s, (long)(p-body->s));
00268 error:
00269    return -1;
00270 }
00271 
00272 
00273 #define AUTHORIZATION_HDR_START       "Authorization: Digest "
00274 #define AUTHORIZATION_HDR_START_LEN   (sizeof(AUTHORIZATION_HDR_START)-1)
00275 
00276 #define PROXY_AUTHORIZATION_HDR_START      "Proxy-Authorization: Digest "
00277 #define PROXY_AUTHORIZATION_HDR_START_LEN  \
00278    (sizeof(PROXY_AUTHORIZATION_HDR_START)-1)
00279 
00280 #define USERNAME_FIELD_S         "username=\""
00281 #define USERNAME_FIELD_LEN       (sizeof(USERNAME_FIELD_S)-1)
00282 #define REALM_FIELD_S            "realm=\""
00283 #define REALM_FIELD_LEN          (sizeof(REALM_FIELD_S)-1)
00284 #define NONCE_FIELD_S            "nonce=\""
00285 #define NONCE_FIELD_LEN          (sizeof(NONCE_FIELD_S)-1)
00286 #define URI_FIELD_S              "uri=\""
00287 #define URI_FIELD_LEN            (sizeof(URI_FIELD_S)-1)
00288 #define OPAQUE_FIELD_S           "opaque=\""
00289 #define OPAQUE_FIELD_LEN         (sizeof(OPAQUE_FIELD_S)-1)
00290 #define RESPONSE_FIELD_S         "response=\""
00291 #define RESPONSE_FIELD_LEN       (sizeof(RESPONSE_FIELD_S)-1)
00292 #define ALGORITHM_FIELD_S        "algorithm=MD5"
00293 #define ALGORITHM_FIELD_LEN       (sizeof(ALGORITHM_FIELD_S)-1)
00294 #define FIELD_SEPARATOR_S        "\", "
00295 #define FIELD_SEPARATOR_LEN      (sizeof(FIELD_SEPARATOR_S)-1)
00296 #define FIELD_SEPARATOR_UQ_S     ", "
00297 #define FIELD_SEPARATOR_UQ_LEN   (sizeof(FIELD_SEPARATOR_UQ_S)-1)
00298 
00299 #define QOP_FIELD_S              "qop="
00300 #define QOP_FIELD_LEN            (sizeof(QOP_FIELD_S)-1)
00301 #define NC_FIELD_S               "nc="
00302 #define NC_FIELD_LEN             (sizeof(NC_FIELD_S)-1)
00303 #define CNONCE_FIELD_S           "cnonce=\""
00304 #define CNONCE_FIELD_LEN         (sizeof(CNONCE_FIELD_S)-1)
00305 
00306 #define add_string( _p, _s, _l) \
00307    do {\
00308       memcpy( _p, _s, _l);\
00309       _p += _l; \
00310    }while(0)
00311 
00312 
00313 str* build_authorization_hdr(int code, str *uri, 
00314       struct uac_credential *crd, struct authenticate_body *auth,
00315       char *response)
00316 {
00317    static str hdr;
00318    char *p;
00319    int len;
00320    int response_len;
00321 
00322    response_len = strlen(response);
00323 
00324    /* compile then len */
00325    len = (code==401?
00326       AUTHORIZATION_HDR_START_LEN:PROXY_AUTHORIZATION_HDR_START_LEN) +
00327       USERNAME_FIELD_LEN + crd->user.len + FIELD_SEPARATOR_LEN +
00328       REALM_FIELD_LEN + crd->realm.len + FIELD_SEPARATOR_LEN +
00329       NONCE_FIELD_LEN + auth->nonce.len + FIELD_SEPARATOR_LEN +
00330       URI_FIELD_LEN + uri->len + FIELD_SEPARATOR_LEN +
00331       (auth->opaque.len?
00332          (OPAQUE_FIELD_LEN + auth->opaque.len + FIELD_SEPARATOR_LEN):0) +
00333       RESPONSE_FIELD_LEN + response_len + FIELD_SEPARATOR_LEN +
00334       ALGORITHM_FIELD_LEN + CRLF_LEN;
00335    if((auth->flags&QOP_AUTH) || (auth->flags&QOP_AUTH_INT))
00336       len += QOP_FIELD_LEN + 4 /*auth*/ + FIELD_SEPARATOR_UQ_LEN +
00337             NC_FIELD_LEN + auth->nc->len + FIELD_SEPARATOR_UQ_LEN +
00338             CNONCE_FIELD_LEN + auth->cnonce->len + FIELD_SEPARATOR_LEN;
00339 
00340    hdr.s = (char*)pkg_malloc( len + 1);
00341    if (hdr.s==0)
00342    {
00343       LM_ERR("no more pkg mem\n");
00344       goto error;
00345    }
00346 
00347    p = hdr.s;
00348    /* header start */
00349    if (code==401)
00350    {
00351       add_string( p, AUTHORIZATION_HDR_START USERNAME_FIELD_S,
00352          AUTHORIZATION_HDR_START_LEN+USERNAME_FIELD_LEN);
00353    } else {
00354       add_string( p, PROXY_AUTHORIZATION_HDR_START USERNAME_FIELD_S,
00355          PROXY_AUTHORIZATION_HDR_START_LEN+USERNAME_FIELD_LEN);
00356    }
00357    /* username */
00358    add_string( p, crd->user.s, crd->user.len);
00359    /* REALM */
00360    add_string( p, FIELD_SEPARATOR_S REALM_FIELD_S,
00361       FIELD_SEPARATOR_LEN+REALM_FIELD_LEN);
00362    add_string( p, crd->realm.s, crd->realm.len);
00363    /* NONCE */
00364    add_string( p, FIELD_SEPARATOR_S NONCE_FIELD_S, 
00365       FIELD_SEPARATOR_LEN+NONCE_FIELD_LEN);
00366    add_string( p, auth->nonce.s, auth->nonce.len);
00367    /* URI */
00368    add_string( p, FIELD_SEPARATOR_S URI_FIELD_S,
00369       FIELD_SEPARATOR_LEN+URI_FIELD_LEN);
00370    add_string( p, uri->s, uri->len);
00371    /* OPAQUE */
00372    if (auth->opaque.len )
00373    {
00374       add_string( p, FIELD_SEPARATOR_S OPAQUE_FIELD_S, 
00375          FIELD_SEPARATOR_LEN+OPAQUE_FIELD_LEN);
00376       add_string( p, auth->opaque.s, auth->opaque.len);
00377    }
00378    if((auth->flags&QOP_AUTH) || (auth->flags&QOP_AUTH_INT))
00379    {
00380       add_string( p, FIELD_SEPARATOR_S QOP_FIELD_S, 
00381          FIELD_SEPARATOR_LEN+QOP_FIELD_LEN);
00382       add_string( p, "auth", 4);
00383       add_string( p, FIELD_SEPARATOR_UQ_S NC_FIELD_S, 
00384          FIELD_SEPARATOR_UQ_LEN+NC_FIELD_LEN);
00385       add_string( p, auth->nc->s, auth->nc->len);
00386       add_string( p, FIELD_SEPARATOR_UQ_S CNONCE_FIELD_S, 
00387          FIELD_SEPARATOR_UQ_LEN+CNONCE_FIELD_LEN);
00388       add_string( p, auth->cnonce->s, auth->cnonce->len);
00389    }
00390    /* RESPONSE */
00391    add_string( p, FIELD_SEPARATOR_S RESPONSE_FIELD_S,
00392       FIELD_SEPARATOR_LEN+RESPONSE_FIELD_LEN);
00393    add_string( p, response, response_len);
00394    /* ALGORITHM */
00395    add_string( p, FIELD_SEPARATOR_S ALGORITHM_FIELD_S CRLF,
00396       FIELD_SEPARATOR_LEN+ALGORITHM_FIELD_LEN+CRLF_LEN);
00397 
00398    hdr.len = p - hdr.s;
00399 
00400    if (hdr.len!=len)
00401    {
00402       LM_CRIT("BUG: bad buffer computation "
00403          "(%d<>%d)\n",len,hdr.len);
00404       pkg_free( hdr.s );
00405       goto error;
00406    }
00407 
00408    LM_DBG("hdr is <%.*s>\n",
00409       hdr.len,hdr.s);
00410 
00411    return &hdr;
00412 error:
00413    return 0;
00414 }
00415 

Generated on Thu May 17 12:00:25 2012 for Kamailio - The Open Source SIP Server by  doxygen 1.5.6