/* * $Id: auth_hdr.c 2072 2007-04-25 11:28:24Z bogdan_iancu $ * * Copyright (C) 2005 Voice Sistem SRL * * This file is part of openser, a free SIP server. * * UAC OpenSER-module is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * UAC OpenSER-module is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * History: * --------- * 2005-01-31 first version (ramona) */ #include "string.h" #include "ctype.h" #include "../../dprint.h" #include "../../str.h" #include "../../mem/mem.h" #include "auth_hdr.h" #include "auth.h" #define AUTHENTICATE_MD5 (1<<0) #define AUTHENTICATE_MD5SESS (1<<1) #define AUTHENTICATE_STALE (1<<2) #define AUTHENTICATE_DIGEST_S "Digest" #define AUTHENTICATE_DIGEST_LEN (sizeof(AUTHENTICATE_DIGEST_S)-1) #define LOWER1B(_n) \ ((_n)|0x20) #define LOWER4B(_n) \ ((_n)|0x20202020) #define GET4B(_p) \ ((*(_p)<<24) + (*(_p+1)<<16) + (*(_p+2)<<8) + *(_p+3)) #define GET3B(_p) \ ((*(_p)<<24) + (*(_p+1)<<16) + (*(_p+2)<<8) + 0xff) #define CASE_5B(_hex4,_c5, _new_state, _quoted) \ case _hex4: \ if (p+5s==0 || *body->s==0 ) { LOG(L_ERR,"ERROR:uac:parse_authenticate_body: empty body\n"); goto error; } memset( auth, 0, sizeof(struct authenticate_body)); p = body->s; end = body->s + body->len; /* parse the "digest" */ while (p=end ) goto parse_error; if (strncmp(p,AUTHENTICATE_DIGEST_S,AUTHENTICATE_DIGEST_LEN)!=0) goto parse_error; p += AUTHENTICATE_DIGEST_LEN; if (!isspace((int)*p)) goto parse_error; p++; while (p=\"%.*s\" state=%d\n", name.len,name.s,val.len,val.s,state); /* process the AVP */ switch (state) { case QOP_STATE: /* TODO - add qop support */ LOG(L_NOTICE,"NOTICE:uac:parse_authenticate_body: no qop " "support for the moment :-( -> ignoring\n"); break; case REALM_STATE: auth->realm = val; break; case NONCE_STATE: auth->nonce = val; break; case DOMAIN_STATE: auth->domain = val; break; case OPAQUE_STATE: auth->opaque = val; break; case ALGORITHM_STATE: if (val.len==3) { if ( LOWER4B(GET3B(val.s))==0x6d6435ff) /*MD5*/ auth->flags |= AUTHENTICATE_MD5; } else { LOG(L_ERR,"ERROR:uac:parse_authenticate_body: " "unsupported algorithm \"%.*s\"\n",val.len,val.s); goto error; } break; case STALE_STATE: if (val.len==4 && LOWER4B(GET4B(val.s))==0x74727565) /*true*/ { auth->flags |= AUTHENTICATE_STALE; } else if ( !(val.len==5 && val.s[4]=='e' && LOWER4B(GET4B(val.s))==0x66616c73) ) { LOG(L_ERR,"ERROR:uac:parse_authenticate_body: " "unsupported stale value \"%.*s\"\n",val.len,val.s); goto error; } break; default: break; } } /* some checkings */ if (auth->nonce.s==0 || auth->realm.s==0) { LOG(L_ERR,"ERROR:uac:parse_authenticate_body: realm or " "nonce missing\n"); goto error; } return 0; parse_error: LOG(L_ERR,"ERROR:uac:parse_authenticate_body: parse error in <%.*s> " "around %ld\n", body->len, body->s, (long)(p-body->s)); error: return -1; } #define AUTHORIZATION_HDR_START "Authorization: Digest " #define AUTHORIZATION_HDR_START_LEN (sizeof(AUTHORIZATION_HDR_START)-1) #define PROXY_AUTHORIZATION_HDR_START "Proxy-Authorization: Digest " #define PROXY_AUTHORIZATION_HDR_START_LEN \ (sizeof(PROXY_AUTHORIZATION_HDR_START)-1) #define USERNAME_FIELD_S "username=\"" #define USERNAME_FIELD_LEN (sizeof(USERNAME_FIELD_S)-1) #define REALM_FIELD_S "realm=\"" #define REALM_FIELD_LEN (sizeof(REALM_FIELD_S)-1) #define NONCE_FIELD_S "nonce=\"" #define NONCE_FIELD_LEN (sizeof(NONCE_FIELD_S)-1) #define URI_FIELD_S "uri=\"" #define URI_FIELD_LEN (sizeof(URI_FIELD_S)-1) #define OPAQUE_FIELD_S "opaque=\"" #define OPAQUE_FIELD_LEN (sizeof(OPAQUE_FIELD_S)-1) #define RESPONSE_FIELD_S "response=\"" #define RESPONSE_FIELD_LEN (sizeof(RESPONSE_FIELD_S)-1) #define ALGORITHM_FIELD_S "algorithm=\"MD5\"" #define ALGORITHM_FIELD_LEN (sizeof(ALGORITHM_FIELD_S)-1) #define FIELD_SEPARATOR_S "\", " #define FIELD_SEPARATOR_LEN (sizeof(FIELD_SEPARATOR_S)-1) #define add_string( _p, _s, _l) \ do {\ memcpy( _p, _s, _l);\ _p += _l; \ }while(0) str* build_authorization_hdr(int code, str *uri, struct uac_credential *crd, struct authenticate_body *auth, char *response) { static str hdr; char *p; int len; int response_len; response_len = strlen(response); /* compile then len */ len = (code==401? AUTHORIZATION_HDR_START_LEN:PROXY_AUTHORIZATION_HDR_START_LEN) + USERNAME_FIELD_LEN + crd->user.len + FIELD_SEPARATOR_LEN + REALM_FIELD_LEN + crd->realm.len + FIELD_SEPARATOR_LEN + NONCE_FIELD_LEN + auth->nonce.len + FIELD_SEPARATOR_LEN + URI_FIELD_LEN + uri->len + FIELD_SEPARATOR_LEN + (auth->opaque.len? (OPAQUE_FIELD_LEN + auth->opaque.len + FIELD_SEPARATOR_LEN):0) + RESPONSE_FIELD_LEN + response_len + FIELD_SEPARATOR_LEN + ALGORITHM_FIELD_LEN + CRLF_LEN; hdr.s = (char*)pkg_malloc( len + 1); if (hdr.s==0) { LOG(L_ERR,"ERROR:uac:build_authorization_hdr: no more mem\n"); goto error; } p = hdr.s; /* header start */ if (code==401) { add_string( p, AUTHORIZATION_HDR_START USERNAME_FIELD_S, AUTHORIZATION_HDR_START_LEN+USERNAME_FIELD_LEN); } else { add_string( p, PROXY_AUTHORIZATION_HDR_START USERNAME_FIELD_S, PROXY_AUTHORIZATION_HDR_START_LEN+USERNAME_FIELD_LEN); } /* username */ add_string( p, crd->user.s, crd->user.len); /* REALM */ add_string( p, FIELD_SEPARATOR_S REALM_FIELD_S, FIELD_SEPARATOR_LEN+REALM_FIELD_LEN); add_string( p, crd->realm.s, crd->realm.len); /* NONCE */ add_string( p, FIELD_SEPARATOR_S NONCE_FIELD_S, FIELD_SEPARATOR_LEN+NONCE_FIELD_LEN); add_string( p, auth->nonce.s, auth->nonce.len); /* URI */ add_string( p, FIELD_SEPARATOR_S URI_FIELD_S, FIELD_SEPARATOR_LEN+URI_FIELD_LEN); add_string( p, uri->s, uri->len); /* OPAQUE */ if (auth->opaque.len ) { add_string( p, FIELD_SEPARATOR_S OPAQUE_FIELD_S, FIELD_SEPARATOR_LEN+OPAQUE_FIELD_LEN); add_string( p, auth->opaque.s, auth->opaque.len); } /* RESPONSE */ add_string( p, FIELD_SEPARATOR_S RESPONSE_FIELD_S, FIELD_SEPARATOR_LEN+RESPONSE_FIELD_LEN); add_string( p, response, response_len); /* ALGORITHM */ add_string( p, FIELD_SEPARATOR_S ALGORITHM_FIELD_S CRLF, FIELD_SEPARATOR_LEN+ALGORITHM_FIELD_LEN+CRLF_LEN); hdr.len = p - hdr.s; if (hdr.len!=len) { LOG(L_CRIT,"BUG:uac:build_authorization_hdr: bad buffer computation " "(%d<>%d)\n",len,hdr.len); pkg_free( hdr.s ); goto error; } DBG("DEBUG:uac:build_authorization_hdr: hdr is <%.*s>\n", hdr.len,hdr.s); return &hdr; error: return 0; }