⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 auth_client.c

📁 Sofia SIP is an open-source SIP User-Agent library, compliant with the IETF RFC3261 specification.
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * 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"#define SOFIA_EXTEND_AUTH_CLIENT 1#include <sofia-sip/su.h>#include <sofia-sip/su_md5.h>#include "sofia-sip/auth_common.h"#include "sofia-sip/auth_client.h"#include "sofia-sip/auth_client_plugin.h"#include <sofia-sip/msg_types.h>#include <sofia-sip/msg_header.h>#include <sofia-sip/auth_digest.h>#include <sofia-sip/base64.h>#include <sofia-sip/su_uniqueid.h>#include <sofia-sip/string0.h>#include <sofia-sip/su_debug.h>#include <stddef.h>#include <stdlib.h>#include <string.h>#include <assert.h>static auth_client_t *ca_create(su_home_t *home, 				char const *scheme,				char const *realm);static void ca_destroy(su_home_t *home, auth_client_t *ca);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_info(auth_client_t *ca,		   msg_auth_info_t const *ai,		   msg_hclass_t *credential_class);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);/** Initialize authenticators. * * The function auc_challenge() merges the challenge @a ch to the list of * authenticators @a auc_list.   * * @param[in,out] auc_list  list of authenticators to be updated * @param[in,out] home      memory home used for allocating authenticators * @param[in] ch        challenge to be processed * @param[in] crcl      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)	return -1;      if (updated == 0)	continue;		/* No match, next */      matched = 1;      if (updated > 1)	retval = 1;		/* Updated authenticator */    }    if (!matched) {      /* There was no matching authenticator, create a new one */      *cca = ca_create(home, scheme, realm);      if (ca_challenge((*cca), ch, crcl, scheme, realm) < 0) {	ca_destroy(home, *cca), *cca = NULL;	return -1;      }      retval = 1;		/* Updated authenticator */    }  }  return retval;}/** Update authentication client.  * * @retval -1 upon an error * @retval 0 when challenge did not match * @retval 1 when challenge did match but was not updated * @retval 2 when challenge did match and updated client */staticint ca_challenge(auth_client_t *ca, 		 msg_auth_t const *ch,		 msg_hclass_t *credential_class,		 char const *scheme, 		 char const *realm){  int stale = 0;  assert(ca); assert(ch);  if (!ca || !ch)    return -1;  if (strcasecmp(ca->ca_scheme, scheme))    return 0;  if (strcmp(ca->ca_realm, realm))    return 0;  if (ca->ca_credential_class &&       ca->ca_credential_class != credential_class)    return 0;  if (!ca->ca_auc)    return 1;  if (ca->ca_auc->auc_challenge)    stale = ca->ca_auc->auc_challenge(ca, ch);  if (stale < 0)    return -1;  if (!ca->ca_credential_class)    stale = 2, ca->ca_credential_class = credential_class;  return stale > 1 ? 2 : 1;}/** Store authentication info to authenticators. * * The function auc_info() feeds the authentication data from the @b * Authentication-Info header @a info to the list of authenticators @a * auc_list. * * @param[in,out] auc_list  list of authenticators to be updated * @param[in] info        info header to be processed * @param[in] credential_class      corresponding credential class * * The authentication info can be in either @AuthenticationInfo or in * @ProxyAuthenticationInfo headers. If the header is @AuthenticationInfo, * the @a credential_class should be #sip_authorization_class or * #http_authorization_class. Likewise, If the header is * @ProxyAuthenticationInfo, the @a credential_class should be * #sip_proxy_authorization_class or #http_proxy_authorization_class. * The authentication into header usually contains next nonce or mutual * authentication information. Currently, only the nextnonce parameter is * processed. * * @bug * In principle, SIP allows more than one challenge for a single request.  * For example, there can be multiple proxies that each challenge the * client. The result of storing authentication info can be quite unexpected * if there are more than one authenticator with the given type (specified * by @a credential_class). * * @retval number of challenges to updated * @retval 0 when there was no challenge to update * @retval -1 upon an error * * @NEW_1_12_5. */int auc_info(auth_client_t **auc_list,	     msg_auth_info_t const *info,	     msg_hclass_t *credential_class){  auth_client_t *ca;  int retval = 0;  /* Go through each challenge in Authenticate or Proxy-Authenticate headers */  /* Update matching authenticator */  for (ca = *auc_list; ca; ca = ca->ca_next) {    int updated = ca_info(ca, info, credential_class);    if (updated < 0)      return -1;    if (updated >= 1)      retval = 1;		/* Updated authenticator */  }  return retval;}/** Update authentication client with authentication info.  * * @retval -1 upon an error * @retval 0 when challenge did not match * @retval 1 when challenge did match but was not updated * @retval 2 when challenge did match and updated client */staticint ca_info(auth_client_t *ca, 	    msg_auth_info_t const *info,	    msg_hclass_t *credential_class){  assert(ca); assert(info);  if (!ca || !info)    return -1;  if (!ca->ca_credential_class)    return 0;  if (ca->ca_credential_class != credential_class)    return 0;  if (!ca->ca_auc      || (size_t)ca->ca_auc->auc_plugin_size <=          offsetof(auth_client_plugin_t, auc_info)      || !ca->ca_auc->auc_info)    return 0;  return ca->ca_auc->auc_info(ca, info);}/**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[in,out] auc_list  list of authenticators  * @param[in,out] home      memory home used for allocations * @param[in] data          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[in,out] auc_list  list of authenticators  * @param[in] scheme        scheme to use (NULL, if any) * @param[in] realm         realm to use (NULL, if any) * @param[in] user          username  * @param[in] pass          password *  * @retval number of updated clients * @retval 0 when no client was updated * @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){  char *new_user, *new_pass;  char *old_user, *old_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 0;  old_user = ca->ca_user, old_pass = ca->ca_pass;  if (str0cmp(user, old_user) == 0 && str0cmp(pass, old_pass) == 0)    return 0;  new_user = su_strdup(ca->ca_home, user);  new_pass = su_strdup(ca->ca_home, pass);  if (!new_user || !new_pass)    return -1;  ca->ca_user = new_user, ca->ca_pass = new_pass;  if (AUTH_CLIENT_IS_EXTENDED(ca))    ca->ca_clear = 0;  su_free(ca->ca_home, old_user);  su_free(ca->ca_home, old_pass);  return 1;}/** Copy authentication data from @a src to @a dst. * * @retval >0 if credentials were copied * @retval 0 if there was no credentials to copy * @retval <0 if an error occurred. */int auc_copy_credentials(auth_client_t **dst,			 auth_client_t const *src){  int retval = 0;  if (!dst)    return -1;  for (;*dst; dst = &(*dst)->ca_next) {    auth_client_t *d = *dst;    auth_client_t const *ca;    for (ca = src; ca; ca = ca->ca_next) {      char *u, *p;      if (!ca->ca_user || !ca->ca_pass)	continue;      if (AUTH_CLIENT_IS_EXTENDED(ca) && ca->ca_clear)	continue;      if (!ca->ca_scheme[0] || strcasecmp(ca->ca_scheme, d->ca_scheme))	continue;      if (!ca->ca_realm[0] || strcmp(ca->ca_realm, d->ca_realm))	continue;      if (!(AUTH_CLIENT_IS_EXTENDED(d) && d->ca_clear) &&	  d->ca_user && strcmp(d->ca_user, ca->ca_user) == 0 &&	  d->ca_pass && strcmp(d->ca_pass, ca->ca_pass) == 0) {	retval++;	break;      }      u = su_strdup(d->ca_home, ca->ca_user);      p = su_strdup(d->ca_home, ca->ca_pass);      if (!u || !p)	return -1;      if (d->ca_user) su_free(d->ca_home, (void *)d->ca_user);      if (d->ca_pass) su_free(d->ca_home, (void *)d->ca_pass);      d->ca_user = u, d->ca_pass = p;      if (AUTH_CLIENT_IS_EXTENDED(d))	d->ca_clear = 0;      retval++;      break;    }  }  return retval;}      	      /**Clear authentication data from the authenticator. * * The function auc_clear_credentials() is used to remove the credentials * from the authenticators. * * @param[in,out] auc_list  list of authenticators  * @param[in] scheme    scheme (if non-null, remove only matching credentials)  * @param[in] realm     realm (if non-null, remove only matching credentials) * * @retval 0 when successful * @retval -1 upon an error */int auc_clear_credentials(auth_client_t **auc_list, 			  char const *scheme,			  char const *realm){  int retval = 0;  int match;  for (; *auc_list; auc_list = &(*auc_list)->ca_next) {    auth_client_t *ca = *auc_list;    if (!AUTH_CLIENT_IS_EXTENDED(ca))      continue;    if ((scheme != NULL && strcasecmp(scheme, ca->ca_scheme)) ||	(realm != NULL && strcmp(realm, ca->ca_realm)))      continue;    match = ca->ca_auc->auc_clear(*auc_list);    if (match < 0) {      retval = -1;      break;    }    if (match)       retval++;  }  return retval;}staticint ca_clear_credentials(auth_client_t *ca){  assert(ca); assert(ca->ca_home->suh_size >= (int)(sizeof *ca));  if (!ca)    return -1;  ca->ca_clear = 1;  return 1;}/** Check if we have all required credentials. *  * @retval 1 when authorization can proceed * @retval 0 when there is not enough credentials * * @NEW_1_12_5. */int auc_has_authorization(auth_client_t **auc_list){  auth_client_t const *ca;  if (auc_list == NULL)    return 0;  /* Make sure every challenge has credentials */  for (ca = *auc_list; ca; ca = ca->ca_next) {

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -