digest.c

Go to the documentation of this file.
00001 /*
00002  * $Id: digest.c 4518 2008-07-28 15:39:28Z henningw $
00003  *
00004  * Digest credentials parser interface
00005  *
00006  * Copyright (C) 2001-2003 FhG Fokus
00007  *
00008  * This file is part of Kamailio, a free SIP server.
00009  *
00010  * Kamailio is free software; you can redistribute it and/or modify
00011  * it under the terms of the GNU General Public License as published by
00012  * the Free Software Foundation; either version 2 of the License, or
00013  * (at your option) any later version
00014  *
00015  * Kamailio is distributed in the hope that it will be useful,
00016  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00017  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018  * GNU General Public License for more details.
00019  *
00020  * You should have received a copy of the GNU General Public License 
00021  * along with this program; if not, write to the Free Software 
00022  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00023  */
00024 
00025 
00026 #include "digest.h"
00027 #include "../../mem/mem.h"  /* pkg_malloc */
00028 #include "../../dprint.h"   /* Guess what */
00029 #include <stdio.h>          /* printf */
00030 #include <string.h>         /* strncasecmp */
00031 
00032 
00033 /*
00034  * Create and initialize a new credentials structure
00035  */
00036 static inline int new_credentials(struct hdr_field* _h)
00037 {
00038    auth_body_t* b;
00039 
00040    b = (auth_body_t*)pkg_malloc(sizeof(auth_body_t));
00041    if (b == 0) {
00042       LM_ERR("no pkg memory left\n");
00043       return -1;
00044    }
00045       
00046    init_dig_cred(&(b->digest));
00047    b->stale = 0;
00048    b->authorized = 0;
00049 
00050    _h->parsed = (void*)b;
00051 
00052    return 0;
00053 }
00054 
00055 
00056 /*
00057  * Parse digest credentials
00058  * Return value -1 means that the function was unable to allocate
00059  * memory and therefore the server should return Internal Server Error,
00060  * not Bad Request in this case !
00061  * Bad Request should be send when return value != -1
00062  */
00063 int parse_credentials(struct hdr_field* _h)
00064 {
00065    int res;
00066 
00067    if (_h->parsed) {
00068       return 0;  /* Already parsed */
00069    }
00070 
00071    if (new_credentials(_h) < 0) {
00072       LM_ERR("failed to create new credentials\n");
00073       return -1;
00074    }
00075 
00076         /* parse_digest_cred must return < -1 on error otherwise we will be
00077          * unable to distinguish if the error was caused by the server or if the
00078          * credentials are broken
00079          */
00080    res = parse_digest_cred(&(_h->body), &(((auth_body_t*)(_h->parsed))->digest));
00081    
00082    if (res != 0) {
00083       free_credentials((auth_body_t**)(void*)&(_h->parsed));
00084    }
00085 
00086    return res;
00087 }
00088 
00089 
00090 /*
00091  * Free all memory
00092  */
00093 void free_credentials(auth_body_t** _b)
00094 {
00095    pkg_free(*_b);
00096    *_b = 0;
00097 }
00098 
00099 
00100 /*
00101  * Check semantics of a digest credentials structure
00102  * Make sure that all attributes needed to verify response 
00103  * string are set or at least have a default value
00104  *
00105  * The returned value is logical OR of all errors encountered
00106  * during the check, see dig_err_t type for more details 
00107  */
00108 dig_err_t check_dig_cred(dig_cred_t* _c)
00109 {
00110    dig_err_t res = E_DIG_OK;
00111 
00112         /* Username must be present */
00113    if (_c->username.user.s == 0) res |= E_DIG_USERNAME;
00114 
00115         /* Realm must be present */
00116    if (_c->realm.s == 0)  res |= E_DIG_REALM;
00117 
00118         /* If Username has domain, it must equal to Realm */
00119    if (_c->username.domain.s && 
00120        ((_c->username.domain.len != _c->realm.len) ||
00121         (strncmp(_c->username.domain.s, _c->realm.s,
00122             _c->realm.len) != 0)))
00123        res |= E_DIG_DOMAIN;
00124 
00125         /* Nonce that was used must be specified */
00126    if (_c->nonce.s == 0) res |= E_DIG_NONCE;
00127 
00128         /* URI must be specified */
00129    if (_c->uri.s == 0) res |= E_DIG_URI;
00130 
00131         /* We cannot check credentials without response */
00132    if (_c->response.s == 0) res |= E_DIG_RESPONSE;
00133 
00134         /* If QOP parameter is present, some additional
00135          * requirements must be met
00136          */
00137    if ((_c->qop.qop_parsed == QOP_AUTH) || (_c->qop.qop_parsed == QOP_AUTHINT)) {
00138            /* CNONCE must be specified */
00139       if (_c->cnonce.s == 0) res |= E_DIG_CNONCE;
00140            /* and also nonce count must be specified */
00141       if (_c->nc.s == 0) res |= E_DIG_NC;
00142    }
00143       
00144    return res; 
00145 }
00146 
00147 
00148 /*
00149  * Print credential structure content to stdout
00150  * Just for debugging
00151  */
00152 void print_cred(dig_cred_t* _c)
00153 {
00154    printf("===Digest credentials===\n");
00155    if (_c) {
00156       printf("Username\n");
00157       printf("+--whole  = \'%.*s\'\n", _c->username.whole.len, _c->username.whole.s);
00158       printf("+--user   = \'%.*s\'\n", _c->username.user.len, _c->username.user.s);
00159       printf("\\--domain = \'%.*s\'\n", _c->username.domain.len, _c->username.domain.s);
00160       printf("Realm     = \'%.*s\'\n", _c->realm.len, _c->realm.s);
00161       printf("Nonce     = \'%.*s\'\n", _c->nonce.len, _c->nonce.s);
00162       printf("URI       = \'%.*s\'\n", _c->uri.len, _c->uri.s);
00163       printf("Response  = \'%.*s\'\n", _c->response.len, _c->response.s);
00164       printf("Algorithm = \'%.*s\'\n", _c->alg.alg_str.len, _c->alg.alg_str.s);
00165       printf("\\--parsed = ");
00166 
00167       switch(_c->alg.alg_parsed) {
00168       case ALG_UNSPEC:  printf("ALG_UNSPEC\n");  break;
00169       case ALG_MD5:     printf("ALG_MD5\n");     break;
00170       case ALG_MD5SESS: printf("ALG_MD5SESS\n"); break;
00171       case ALG_OTHER:   printf("ALG_OTHER\n");   break;
00172       }
00173 
00174       printf("Cnonce    = \'%.*s\'\n", _c->cnonce.len, _c->cnonce.s);
00175       printf("Opaque    = \'%.*s\'\n", _c->opaque.len, _c->opaque.s);
00176       printf("QOP       = \'%.*s\'\n", _c->qop.qop_str.len, _c->qop.qop_str.s);
00177       printf("\\--parsed = ");
00178 
00179       switch(_c->qop.qop_parsed) {
00180       case QOP_UNSPEC:  printf("QOP_UNSPEC\n");  break;
00181       case QOP_AUTH:    printf("QOP_AUTH\n");    break;
00182       case QOP_AUTHINT: printf("QOP_AUTHINT\n"); break;
00183       case QOP_OTHER:   printf("QOP_OTHER\n");   break;
00184       }
00185       printf("NC        = \'%.*s\'\n", _c->nc.len, _c->nc.s);
00186    }
00187    printf("===/Digest credentials===\n");
00188 }
00189 
00190 
00191 /*
00192  * Mark credentials as selected so functions
00193  * following authorize know which credentials
00194  * to use if the message contained more than
00195  * one
00196  */
00197 int mark_authorized_cred(struct sip_msg* _m, struct hdr_field* _h)
00198 {
00199    struct hdr_field* f;
00200    
00201    switch(_h->type) {
00202    case HDR_AUTHORIZATION_T: f = _m->authorization; break;
00203    case HDR_PROXYAUTH_T:     f = _m->proxy_auth;    break;
00204    default:
00205       LM_ERR("invalid header field type\n");
00206       return -1;
00207    }
00208 
00209    if (!(f->parsed)) {
00210       if (new_credentials(f) < 0) {
00211          LM_ERR("new_credentials failed\n");
00212          return -1;
00213       }
00214    }
00215 
00216    ((auth_body_t*)(f->parsed))->authorized = _h;
00217 
00218    return 0;
00219 }
00220 
00221 
00222 /*
00223  * Get pointer to authorized credentials, if there are no
00224  * authorized credentials, 0 is returned
00225  */
00226 int get_authorized_cred(struct hdr_field* _f, struct hdr_field** _h)
00227 {
00228    if (_f && _f->parsed) {
00229       *_h = ((auth_body_t*)(_f->parsed))->authorized;
00230    } else {
00231       *_h = 0;
00232    }
00233    
00234    return 0;
00235 }

Generated on Tue May 22 16:00:26 2012 for Kamailio - The Open Source SIP Server by  doxygen 1.5.6