📄 authorize.c
字号:
/* * $Id: authorize.c,v 1.5.2.1 2005/07/20 17:11:50 andrei Exp $ * * Digest Authentication - Diameter support * * Copyright (C) 2001-2003 FhG Fokus * * This file is part of ser, a free SIP server. * * ser 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 * * For a license to use the ser software under conditions * other than those described here, or to purchase support for this * software, please contact iptel.org by e-mail at the following addresses: * info@iptel.org * * ser 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: * ------- * 2003-09-11: updated to new build_lump_rpl() interface (bogdan) * 2003-11-11: build_lump_rpl() removed, add_lump_rpl() has flags (bogdan) */#include <stdio.h>#include <stdlib.h>#include <string.h>#include <sys/types.h>#include <sys/socket.h>#include <netinet/in.h>#include <netdb.h> #include <string.h>/* memory management */#include "../../mem/mem.h"#include "../../mem/shm_mem.h"/* printing messages, dealing with strings and other utils */#include "../../dprint.h"#include "../../str.h"#include "../../ut.h"/* digest parser headers */#include "../../parser/digest/digest.h"#include "../../parser/parse_uri.h"#include "../../parser/parse_from.h"#include "../../parser/parse_to.h"/* necessary when dealing with lumps */#include "../../data_lump_rpl.h"/* headers defined by this module */#include "diameter_msg.h"#include "auth_diameter.h"#include "defs.h"#include "authorize.h"#include "tcp_comm.h"/* Extract URI depending on the request from To or From header */int get_uri(struct sip_msg* m, str** uri){ if ((REQ_LINE(m).method.len == 8) && (memcmp(REQ_LINE(m).method.s, "REGISTER", 8) == 0)) { /* REGISTER */ if (!m->to && ((parse_headers(m, HDR_TO, 0) == -1)|| (!m->to))) { LOG(L_ERR, M_NAME":get_uri(): To header field not found or " "malformed\n"); /* it was a REGISTER and an error appeared when parsing TO header*/ return -1; } *uri = &(get_to(m)->uri); } else { if (parse_from_header(m) == -1) { LOG(L_ERR, M_NAME":get_uri(): Error while parsing FROM header\n"); /* an error appeared when parsing FROM header */ return -1; } *uri = &(get_from(m)->uri); } /* success */ return 0;}/* Return parsed To or From host part of the parsed uri (that is realm) */int get_realm(struct sip_msg* m, int hftype, struct sip_uri* u){ str uri; /* extracting the uri */ if ((REQ_LINE(m).method.len==8) && !memcmp(REQ_LINE(m).method.s, "REGISTER", 8) && (hftype == HDR_AUTHORIZATION) ) { /* REGISTER */ if (!m->to && ((parse_headers(m, HDR_TO, 0) == -1) || (!m->to))) { LOG(L_ERR, M_NAME":get_realm(): Error while parsing TO header\n"); /* signal the error */ return -1; } /* Body of To header field is parsed automatically */ uri = get_to(m)->uri; } else { if (parse_from_header(m)<0) { LOG(L_ERR, M_NAME":get_realm(): Error while parsing FROM header\n"); /* signal the error */ return -1; } uri = get_from(m)->uri; } /* parsing the uri */ if (parse_uri(uri.s, uri.len, u) < 0) { LOG(L_ERR, M_NAME":get_realm(): Error while parsing URI\n"); return -1; } /* everything was OK */ return 0;}/* Find credentials with given realm in a SIP message header */int find_credentials(struct sip_msg* _m, str* _realm, int _hftype, struct hdr_field** _h){ struct hdr_field** hook, *ptr, *prev; int res; str* r; switch(_hftype) { case HDR_AUTHORIZATION: hook = &(_m->authorization); break; case HDR_PROXYAUTH: hook = &(_m->proxy_auth); break; default: hook = &(_m->authorization); break; } /* If the credentials haven't been parsed yet, do it now */ if (*hook == 0) if (parse_headers(_m, _hftype, 0) == -1) { LOG(L_ERR, M_NAME":find_credentials(): Error while parsing headers\n"); return -1; } ptr = *hook; /* Iterate through the credentials of the message to find credentials with given realm */ while(ptr) { res = parse_credentials(ptr); if (res < 0) { LOG(L_ERR, M_NAME":find_credentials(): Error while parsing " "credentials\n"); return (res == -1) ? -2 : -3; } else if (res == 0) { r = &(((auth_body_t*)(ptr->parsed))->digest.realm); if (r->len == _realm->len) { if (!strncasecmp(_realm->s, r->s, r->len)) { *_h = ptr; return 0; } } } prev = ptr; if (parse_headers(_m, _hftype, 1) == -1) { LOG(L_ERR, M_NAME":find_credentials(): Error while parsing" " headers\n"); return -4; } else { if (prev != _m->last_header) { if (_m->last_header->type == _hftype) ptr = _m->last_header; else break; } else break; } } /* Credentials with given realm not found */ return 1;}auth_result_t pre_auth(struct sip_msg* _m, str* _realm, int _hftype, struct hdr_field** _h){ int ret; struct sip_uri uri; if ((_m->REQ_METHOD == METHOD_ACK) || (_m->REQ_METHOD == METHOD_CANCEL)) return AUTHORIZED; /* if no realm supplied, find out now */ if (_realm==0 || _realm->len == 0) { if (get_realm(_m, _hftype, &uri) < 0) { LOG(L_ERR, M_NAME":pre_auth(): Error while extracting realm\n"); if (send_resp(_m, 400, MESSAGE_400, 0, 0) == -1) { LOG(L_ERR, M_NAME":pre_auth(): Error while sending 400 reply\n"); } return ERROR; } *_realm = uri.host; } ret = find_credentials(_m, _realm, _hftype, _h); if (ret < 0) { LOG(L_ERR, M_NAME":pre_auth(): Error while looking for credentials\n"); if (send_resp(_m, (ret == -2) ? 500 : 400, (ret == -2) ? MESSAGE_500 : MESSAGE_400, 0, 0) == -1) { LOG(L_ERR, M_NAME":pre_auth(): Error while sending 400 reply\n"); } return ERROR; } else if (ret > 0) { LOG(L_ERR, M_NAME":pre_auth(): Credentials with given realm not " "found\n"); return NO_CREDENTIALS; } return DO_AUTHORIZATION;}/* Authorize digest credentials */int authorize(struct sip_msg* msg, str* realm, int hftype){ auth_result_t ret; struct hdr_field* h; auth_body_t* cred = NULL; str* uri; struct sip_uri puri; str domain; domain = *realm; /* see what is to do after a first look at the message */ ret = pre_auth(msg, &domain, hftype, &h); switch(ret) { case ERROR: return 0; case AUTHORIZED: return 1; case NO_CREDENTIALS: cred = NULL; break; case DO_AUTHORIZATION: cred = (auth_body_t*)h->parsed; break; } if (get_uri(msg, &uri) < 0) { LOG(L_ERR, M_NAME":authorize(): From/To URI not found\n"); return -1; } if (parse_uri(uri->s, uri->len, &puri) < 0) { LOG(L_ERR, M_NAME":authorize(): Error while parsing From/To URI\n"); return -1; }// user.s = (char *)pkg_malloc(puri.user.len);// un_escape(&(puri.user), &user); /* parse the ruri, if not yet */ if(msg->parsed_uri_ok==0 && parse_sip_msg_uri(msg)<0) { LOG(L_ERR,M_NAME":authorize(): ERROR while parsing the Request-URI\n"); return -1; } /* preliminary check */ if(cred) { if (puri.host.len != cred->digest.realm.len) { DBG(M_NAME":authorize(): Credentials realm and URI host do not " "match\n"); return -1; } if (strncasecmp(puri.host.s, cred->digest.realm.s, puri.host.len) != 0) { DBG(M_NAME":authorize(): Credentials realm and URI host do not " "match\n"); return -1; } } if( diameter_authorize(cred?h:NULL, &msg->first_line.u.request.method, puri, msg->parsed_uri, msg->id, rb) != 1) { send_resp(msg, 500, "Internal Server Error", NULL, 0); return -1; } if( srv_response(msg, rb, hftype) != 1 ) return -1; mark_authorized_cred(msg, h); return 1;}/* * This function creates and submits diameter authentication request as per * draft-srinivas-aaa-basic-digest-00.txt. * Service type of the request is Authenticate-Only. * Returns: * 1 - success * -1 - error * */int diameter_authorize(struct hdr_field* hdr, str* p_method, struct sip_uri uri, struct sip_uri ruri, unsigned int m_id, rd_buf_t* rb){ str method, user_name; AAAMessage *req; AAA_AVP *avp, *position; int name_flag, port_flag; dig_cred_t* cred; unsigned int tmp; user_name.s=0; /* fixes gcc 4.0 warning */ if ( !p_method ) { LOG(L_ERR, M_NAME":diameter_authorize(): Invalid parameter value\n"); return -1;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -