Main Page | Modules | Alphabetical List | Data Structures | Directories | File List | Data Fields | Globals | Related Pages

digest.c

Go to the documentation of this file.
00001 /*
00002  * $Id: digest.c,v 1.14 2006/12/07 18:58:02 andrei Exp $
00003  *
00004  * Digest credentials parser interface
00005  *
00006  * Copyright (C) 2001-2003 FhG Fokus
00007  *
00008  * This file is part of ser, a free SIP server.
00009  *
00010  * ser 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  * For a license to use the ser software under conditions
00016  * other than those described here, or to purchase support for this
00017  * software, please contact iptel.org by e-mail at the following addresses:
00018  *    info@iptel.org
00019  *
00020  * ser is distributed in the hope that it will be useful,
00021  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00022  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00023  * GNU General Public License for more details.
00024  *
00025  * You should have received a copy of the GNU General Public License 
00026  * along with this program; if not, write to the Free Software 
00027  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00028  */
00029 
00030 
00031 #include "digest.h"
00032 #include "../../mem/mem.h"  /* pkg_malloc */
00033 #include "../../dprint.h"   /* Guess what */
00034 #include <stdio.h>          /* printf */
00035 #include <string.h>         /* strncasecmp */
00036 
00037 
00038 /*
00039  * Create and initialize a new credentials structure
00040  */
00041 static inline int new_credentials(struct hdr_field* _h)
00042 {
00043         auth_body_t* b;
00044 
00045         b = (auth_body_t*)pkg_malloc(sizeof(auth_body_t));
00046         if (b == 0) {
00047                 LOG(L_ERR, "parse_credentials(): No memory left\n");
00048                 return -1;
00049         }
00050                 
00051         init_dig_cred(&(b->digest));
00052         b->stale = 0;
00053         b->authorized = 0;
00054 
00055         _h->parsed = (void*)b;
00056 
00057         return 0;
00058 }
00059 
00060 
00061 /*
00062  * Parse digest credentials
00063  * Return value -1 means that the function was unable to allocate
00064  * memory and therefore the server should return Internal Server Error,
00065  * not Bad Request in this case !
00066  * Bad Request should be send when return value != -1
00067  */
00068 int parse_credentials(struct hdr_field* _h)
00069 {
00070         int res;
00071         void** ph_parsed;
00072 
00073         if (_h->parsed) {
00074                 return 0;  /* Already parsed */
00075         }
00076 
00077         if (new_credentials(_h) < 0) {
00078                 LOG(L_ERR, "parse_credentials(): Can't create new credentials\n");
00079                 return -1;
00080         }
00081 
00082              /* parse_digest_cred must return < -1 on error otherwise we will be
00083               * unable to distinguish if the error was caused by the server or if the
00084               * credentials are broken
00085               */
00086         res = parse_digest_cred(&(_h->body), &(((auth_body_t*)(_h->parsed))->digest));
00087         
00088         if (res != 0) {
00089                 ph_parsed=&_h->parsed;
00090                 free_credentials((auth_body_t**)ph_parsed);
00091         }
00092 
00093         return res;
00094 }
00095 
00096 
00097 /*
00098  * Free all memory
00099  */
00100 void free_credentials(auth_body_t** _b)
00101 {
00102         pkg_free(*_b);
00103         *_b = 0;
00104 }
00105 
00106 
00107 /*
00108  * Check semantics of a digest credentials structure
00109  * Make sure that all attributes needed to verify response 
00110  * string are set or at least have a default value
00111  *
00112  * The returned value is logical OR of all errors encountered
00113  * during the check, see dig_err_t type for more details 
00114  */
00115 dig_err_t check_dig_cred(dig_cred_t* _c)
00116 {
00117         dig_err_t res = E_DIG_OK;
00118 
00119              /* Username must be present */
00120         if (_c->username.user.s == 0) res |= E_DIG_USERNAME;
00121 
00122              /* Realm must be present */
00123         if (_c->realm.s == 0)  res |= E_DIG_REALM;
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                 LOG(L_ERR, "mark_authorized_cred(): Invalid header field type\n");
00206                 return -1;
00207         }
00208 
00209         if (!(f->parsed)) {
00210                 if (new_credentials(f) < 0) {
00211                         LOG(L_ERR, "mark_authorized_cred(): Error in new_credentials\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 }
00236 
00237 
00238 /*
00239  * Find credentials with given realm in a SIP message header
00240  */
00241 int find_credentials(struct sip_msg* msg, str* realm,
00242                      hdr_types_t hftype, struct hdr_field** hdr)
00243 {
00244         struct hdr_field** hook, *ptr, *prev;
00245         hdr_flags_t hdr_flags;
00246         int res;
00247         str* r;
00248 
00249              /*
00250               * Determine if we should use WWW-Authorization or
00251               * Proxy-Authorization header fields, this parameter
00252               * is set in www_authorize and proxy_authorize
00253               */
00254         switch(hftype) {
00255         case HDR_AUTHORIZATION_T: 
00256                 hook = &(msg->authorization);
00257                 hdr_flags=HDR_AUTHORIZATION_F;
00258                 break;
00259         case HDR_PROXYAUTH_T:
00260                 hook = &(msg->proxy_auth);
00261                 hdr_flags=HDR_PROXYAUTH_F;
00262                 break;
00263         default:                                
00264                 hook = &(msg->authorization);
00265                 hdr_flags=HDR_T2F(hftype);
00266                 break;
00267         }
00268 
00269              /*
00270               * If the credentials haven't been parsed yet, do it now
00271               */
00272         if (*hook == 0) {
00273                      /* No credentials parsed yet */
00274                 if (parse_headers(msg, hdr_flags, 0) == -1) {
00275                         LOG(L_ERR, "auth:find_credentials: Error while parsing headers\n");
00276                         return -1;
00277                 }
00278         }
00279 
00280         ptr = *hook;
00281 
00282              /*
00283               * Iterate through the credentials in the message and
00284               * find credentials with given realm
00285               */
00286         while(ptr) {
00287                 res = parse_credentials(ptr);
00288                 if (res < 0) {
00289                         LOG(L_ERR, "auth:find_credentials: Error while parsing credentials\n");
00290                         return (res == -1) ? -2 : -3;
00291                 } else if (res == 0) {
00292                         r = &(((auth_body_t*)(ptr->parsed))->digest.realm);
00293 
00294                         if (r->len == realm->len) {
00295                                 if (!strncasecmp(realm->s, r->s, r->len)) {
00296                                         *hdr = ptr;
00297                                         return 0;
00298                                 }
00299                         }
00300                 }
00301 
00302                 prev = ptr;
00303                 if (parse_headers(msg, hdr_flags, 1) == -1) {
00304                         LOG(L_ERR, "auth:find_credentials: Error while parsing headers\n");
00305                         return -4;
00306                 } else {
00307                         if (prev != msg->last_header) {
00308                                 if (msg->last_header->type == hftype) ptr = msg->last_header;
00309                                 else break;
00310                         } else break;
00311                 }
00312         }
00313         
00314              /*
00315               * Credentials with given realm not found
00316               */
00317         return 1;
00318 }

Generated on Tue Sep 7 04:16:12 2010 for SIPExpressRouter by  doxygen 1.3.9.1