📄 api.c
字号:
/* * $Id: api.c,v 1.10.2.2 2005/04/26 10:14:57 janakj Exp $ * * Digest Authentication Module * * 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 */#include <string.h>#include "api.h"#include "../../dprint.h"#include "../../parser/digest/digest.h"#include "auth_mod.h"#include "nonce.h"#include "common.h"#include "rpid.h"/* * if realm determined from request, look if there are some * modification rules */void strip_realm(str* _realm){ /* no param defined -- return */ if (!realm_prefix.len) return; /* prefix longer than realm -- return */ if (realm_prefix.len > _realm->len) return; /* match ? -- if so, shorten realm -*/ if (memcmp(realm_prefix.s, _realm->s, realm_prefix.len) == 0) { _realm->s += realm_prefix.len; _realm->len -= realm_prefix.len; } return;}/* * Find credentials with given realm in a SIP message header */static inline 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; /* * Determine if we should use WWW-Authorization or * Proxy-Authorization header fields, this parameter * is set in www_authorize and proxy_authorize */ 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) { /* No credentials parsed yet */ if (parse_headers(_m, _hftype, 0) == -1) { LOG(L_ERR, "find_credentials(): Error while parsing headers\n"); return -1; } } ptr = *hook; /* * Iterate through the credentials in the message and * find credentials with given realm */ while(ptr) { res = parse_credentials(ptr); if (res < 0) { LOG(L_ERR, "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, "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;}/* * Purpose of this function is to find credentials with given realm, * do sanity check, validate credential correctness and determine if * we should really authenticate (there must be no authentication for * ACK and CANCEL */auth_result_t pre_auth(struct sip_msg* _m, str* _realm, int _hftype, struct hdr_field** _h){ int ret; auth_body_t* c; struct sip_uri uri; /* ACK and CANCEL must be always authorized, there is * no way how to challenge ACK and CANCEL cannot be * challenged because it must have the same CSeq as * the request to be canceled */ if ((_m->REQ_METHOD == METHOD_ACK) || (_m->REQ_METHOD == METHOD_CANCEL)) return AUTHORIZED; if (_realm->len == 0) { if (get_realm(_m, _hftype, &uri) < 0) { LOG(L_ERR, "pre_auth(): Error while extracting realm\n"); if (send_resp(_m, 400, MESSAGE_400, 0, 0) == -1) { LOG(L_ERR, "pre_auth(): Error while sending 400 reply\n"); } return ERROR; } *_realm = uri.host; strip_realm(_realm); } /* Try to find credentials with corresponding realm * in the message, parse them and return pointer to * parsed structure */ ret = find_credentials(_m, _realm, _hftype, _h); if (ret < 0) { LOG(L_ERR, "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, "pre_auth(): Error while sending 400 reply\n"); } return ERROR; } else if (ret > 0) { DBG("pre_auth(): Credentials with given realm not found\n"); return NOT_AUTHORIZED; } /* Pointer to the parsed credentials */ c = (auth_body_t*)((*_h)->parsed); /* Check credentials correctness here */ if (check_dig_cred(&(c->digest)) != E_DIG_OK) { LOG(L_ERR, "pre_auth(): Credentials received are not filled properly\n"); if (send_resp(_m, 400, MESSAGE_400, 0, 0) == -1) { LOG(L_ERR, "pre_auth(): Error while sending 400 reply\n"); } return ERROR; } if (check_nonce(&c->digest.nonce, &secret) != 0) { DBG("pre_auth(): Invalid nonce value received\n"); return NOT_AUTHORIZED; } return DO_AUTHORIZATION;}/* * Purpose of this function is to do post authentication steps like * marking authorized credentials and so on. */auth_result_t post_auth(struct sip_msg* _m, struct hdr_field* _h, str* _rpid){ int res = AUTHORIZED; auth_body_t* c; c = (auth_body_t*)((_h)->parsed); if (is_nonce_stale(&c->digest.nonce)) { if ((_m->REQ_METHOD == METHOD_ACK) || (_m->REQ_METHOD == METHOD_CANCEL)) { /* Method is ACK or CANCEL, we must accept stale * nonces because there is no way how to challenge * with new nonce (ACK has no response associated * and CANCEL must have the same CSeq as the request * to be canceled) */ } else { DBG("post_auth(): Response is OK, but nonce is stale\n"); c->stale = 1; res = NOT_AUTHORIZED; } } if (mark_authorized_cred(_m, _h) < 0) { LOG(L_ERR, "post_auth(): Error while marking parsed credentials\n"); if (send_resp(_m, 500, MESSAGE_500, 0, 0) == -1) { LOG(L_ERR, "post_auth(): Error while sending 500 reply\n"); } res = ERROR; } save_rpid(_rpid); return res;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -