auth_client.c
来自「sip协议栈」· C语言 代码 · 共 800 行 · 第 1/2 页
C
800 行
/* * This file is part of the Sofia-SIP package * * Copyright (C) 2005 Nokia Corporation. * * Contact: Pekka Pessi <pekka.pessi@nokia.com> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA * *//**@CFILE auth_client.c Authenticators for SIP client * * @author Pekka Pessi <Pekka.Pessi@nokia.com> * * @date Created: Wed Feb 14 18:32:58 2001 ppessi */#include "config.h"#include <stddef.h>#include <stdlib.h>#include <string.h>#include <assert.h>#include <sofia-sip/su.h>#include <sofia-sip/su_md5.h>#include "sofia-sip/auth_client.h"#include <sofia-sip/msg_header.h>#include <sofia-sip/auth_digest.h>#if HAVE_SOFIA_NTLM#include <sofia-sip/auth_digest.h>#endif#include <sofia-sip/base64.h>#include <sofia-sip/su_uniqueid.h>#include <sofia-sip/su_debug.h>#if HAVE_SC_CRED_H#include <sc_creds.h>#endif#if HAVE_UICC_H#include <uicc.h>#endifstruct auth_client_s { su_home_t ca_home[1]; auth_client_t*ca_next; char const *ca_scheme; char const *ca_realm; char *ca_user; char *ca_pass; msg_hclass_t *ca_credential_class; auth_challenge_t ca_ac[1]; int ca_ncount; char const *ca_cnonce; msg_header_t *(*ca_authorize)(auth_client_t *ca, su_home_t *h, char const *method, url_t const *url, msg_payload_t const *body);};static auth_client_t *ca_create(su_home_t *home);static int ca_challenge(auth_client_t *ca, msg_auth_t const *auth, msg_hclass_t *credential_class, char const *scheme, char const *realm);static int ca_credentials(auth_client_t *ca, char const *scheme, char const *realm, char const *user, char const *pass);static int ca_clear_credentials(auth_client_t *ca, char const *scheme, char const *realm);static msg_header_t *auc_basic_authorization(auth_client_t *ca, su_home_t *h, char const *method, url_t const *url, msg_payload_t const *body);static msg_header_t *auc_digest_authorization(auth_client_t *ca, su_home_t *h, char const *method, url_t const *url, msg_payload_t const *body);#if HAVE_SOFIA_NTLMstatic msg_header_t *auc_ntlm_authorization(auth_client_t *ca, su_home_t *h, char const *method, url_t const *url, msg_payload_t const *body);#endif/** Allocate a dummy auth_client_t structure. */auth_client_t *ca_create(su_home_t *home){ auth_client_t *ca; if ((ca = su_home_clone(home, sizeof(*ca)))) { ca->ca_scheme = ca->ca_realm = ""; } return ca;}void ca_destroy(su_home_t *home, auth_client_t *ca){ su_free(home, ca);}/** Initialize authenticators. * * The function auc_challenge() merges the challenge @a ch to the list of * authenticators @a auc_list. * * @param auc_list [in/out] list of authenticators to be updated * @param home [in/out] memory home used for allocating authenticators * @param ch [in] challenge to be processed * @param crcl [in] credential class * * @retval 1 when challenge was updated * @retval 0 when there was no new challenges * @retval -1 upon an error */int auc_challenge(auth_client_t **auc_list, su_home_t *home, msg_auth_t const *ch, msg_hclass_t *crcl){ auth_client_t **cca; int retval = 0; /* Go through each challenge in Authenticate or Proxy-Authenticate headers */ for (; ch; ch = ch->au_next) { char const *scheme = ch->au_scheme; char const *realm = msg_header_find_param(ch->au_common, "realm="); int matched = 0, updated; if (!scheme || !realm) continue; /* Update matching authenticator */ for (cca = auc_list; (*cca); cca = &(*cca)->ca_next) { updated = ca_challenge((*cca), ch, crcl, scheme, realm); if (updated < 0) continue; /* No match, next */ matched = 1; if (updated > 0) retval = 1; /* Updated authenticator */ } if (!matched) { /* There was no matching authenticator, create a new one */ *cca = ca_create(home); if (ca_challenge((*cca), ch, crcl, scheme, realm) != -1) { retval = 1; /* Updated authenticator */ } else { ca_destroy(home, *cca), *cca = NULL; return -1; } } } return retval;}staticint ca_challenge(auth_client_t *ca, msg_auth_t const *ch, msg_hclass_t *credential_class, char const *scheme, char const *realm){ su_home_t *home = ca->ca_home; auth_challenge_t *ac = ca->ca_ac; int existing = ca->ca_authorize != NULL; assert(ca); assert(ch); if (!ca || !ch) return -1; ca->ca_ac->ac_size = sizeof(ca->ca_ac); if (ca->ca_scheme[0] && strcmp(ca->ca_scheme, scheme)) return -1; if (ca->ca_realm[0] && strcmp(ca->ca_realm, realm)) return -1; if (strcasecmp(scheme, "Basic") == 0) { ca->ca_authorize = auc_basic_authorization; } else if (strcasecmp(scheme, "Digest") == 0) { ca->ca_authorize = auc_digest_authorization; }#if HAVE_SOFIA_NTLM else if (strcasecmp(scheme, "NTLM") == 0) { ca->ca_authorize = auc_ntlm_authorization; }#endif else return -1;#if 0 if (ca->ca_challenge_class && ca->ca_challenge_class != ch->au_common->h_class) return -1;#endif if (ca->ca_credential_class && ca->ca_credential_class != credential_class) return -1; ca->ca_credential_class = credential_class;#if 0 ca->ca_challenge = msg_header_dup(home, (msg_header_t *)ch)->sh_auth; ca->ca_challenge_class = ca->ca_challenge->au_common->h_class; ca->ca_scheme = ca->ca_challenge->au_scheme; ca->ca_realm = msg_header_find_param(ca->ca_challenge->au_common, "realm=");#else if (!ca->ca_scheme[0]) { char *d = su_strdup(home, scheme); if (!d) return -1; ca->ca_scheme = d; } if (!ca->ca_realm[0]) { char *d = su_strdup(home, realm); if (!d) return -1; ca->ca_realm = d; }#endif auth_digest_challenge_free_params(home, ac); if (auth_digest_challenge_get(home, ac, ch->au_params) < 0) return -1; /* Check that we can handle this */ if (!ac->ac_md5 && !ac->ac_md5sess) return -1; if (ac->ac_qop && !ac->ac_auth && !ac->ac_auth_int) return -1; if (ac->ac_qop && (ca->ca_cnonce == NULL || ac->ac_stale)) { su_guid_t guid[1]; char *cnonce; if (ca->ca_cnonce != NULL) /* Free the old one if we are updating after stale=true */ su_free(home, (void *)ca->ca_cnonce); su_guid_generate(guid); ca->ca_cnonce = cnonce = su_alloc(home, BASE64_SIZE(sizeof(guid)) + 1); base64_e(cnonce, BASE64_SIZE(sizeof(guid)) + 1, guid, sizeof(guid)); ca->ca_ncount = 0; } return !existing || ac->ac_stale;}/**Feed authentication data to the authenticator. * * The function auc_credentials() is used to provide the authenticators in * with authentication data (user name, secret). The authentication data * has format as follows: * * scheme:"realm":user:pass * * For instance, @c Basic:"nokia-proxy":ppessi:verysecret * * @todo The authentication data format sucks. * * @param auc_list [in/out] list of authenticators * @param home [in/out] memory home used for allocations * @param data [in] colon-separated authentication data * * @retval 0 when successful * @retval -1 upon an error */int auc_credentials(auth_client_t **auc_list, su_home_t *home, char const *data){ int retval = 0, match; char *s0, *s; char *scheme = NULL, *user = NULL, *pass = NULL, *realm = NULL; s0 = s = su_strdup(NULL, data); /* Parse authentication data */ /* Data is string like "Basic:\"agni\":user1:secret" */ if (s && (s = strchr(scheme = s, ':'))) *s++ = 0; if (s && (s = strchr(realm = s, ':'))) *s++ = 0; if (s && (s = strchr(user = s, ':'))) *s++ = 0; if (s && (s = strchr(pass = s, ':'))) *s++ = 0; if (scheme && realm && user && pass) { for (; *auc_list; auc_list = &(*auc_list)->ca_next) { match = ca_credentials(*auc_list, scheme, realm, user, pass); if (match < 0) { retval = -1; break; } if (match) retval++; } } su_free(NULL, s0); return retval;}/**Feed authentication data to the authenticator. * * The function auc_credentials() is used to provide the authenticators in * with authentication tuple (scheme, realm, user name, secret). * * scheme:"realm":user:pass * * @todo The authentication data format sucks. * * @param auc_list [in/out] list of authenticators * @param scheme [in] scheme to use (NULL, if any) * @param realm [in] realm to use (NULL, if any) * @param user [in] username * @param pass [in] password * * @retval number of matching clients * @retval 0 when no matching client was found * @retval -1 upon an error */int auc_all_credentials(auth_client_t **auc_list, char const *scheme, char const *realm, char const *user, char const *pass){ int retval = 0, match;#if HAVE_SC_CRED_H /* XXX: add */#endif if (user && pass) { for (; *auc_list; auc_list = &(*auc_list)->ca_next) { match = ca_credentials(*auc_list, scheme, realm, user, pass); if (match < 0) return -1; if (match) retval++; } } return retval;}int ca_credentials(auth_client_t *ca, char const *scheme, char const *realm, char const *user, char const *pass){ assert(ca); if (!ca || !ca->ca_scheme || !ca->ca_realm) return -1; if ((scheme != NULL && strcasecmp(scheme, ca->ca_scheme)) || (realm != NULL && strcmp(realm, ca->ca_realm))) return -1; ca->ca_user = su_strdup(ca->ca_home, user);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?