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

📄 auth_module.c

📁 Sofia SIP is an open-source SIP User-Agent library, compliant with the IETF RFC3261 specification.
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * 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_module.c * @brief Authentication verification module * * The authentication module provides server or proxy-side authentication * verification for network elements like registrars, presence servers, and * proxies. * * @author Pekka Pessi <Pekka.Pessi@nokia.com>. * * @date Created: Wed Apr 11 15:14:03 2001 ppessi */#include "config.h"#include <stddef.h>#include <stdlib.h>#include <string.h>#include <stdio.h>#include <assert.h>#include <sys/types.h>#include <sys/stat.h>#include <unistd.h>#include <sofia-sip/auth_digest.h>#include "iptsec_debug.h"#if HAVE_FUNC#elif HAVE_FUNCTION#define __func__ __FUNCTION__#elsestatic char const __func__[] = "auth_mod";#endif#include <sofia-sip/su_debug.h>#include <sofia-sip/su_wait.h>#include <sofia-sip/su_alloc.h>#include <sofia-sip/su_tagarg.h>#include <sofia-sip/base64.h>#include <sofia-sip/su_md5.h>#include <sofia-sip/msg_parser.h>#include <sofia-sip/msg_date.h>#include "sofia-sip/auth_module.h"#include "sofia-sip/auth_plugin.h"#define APW_HASH(apw) ((apw)->apw_index)char const auth_internal_server_error[] = "Internal server error";static void auth_call_scheme_destructor(void *);static void auth_md5_hmac_key(auth_mod_t *am);HTABLE_PROTOS_WITH(auth_htable, aht, auth_passwd_t, usize_t, unsigned);HTABLE_BODIES_WITH(auth_htable, aht, auth_passwd_t, APW_HASH, 		   usize_t, unsigned);/**Allocate an authentication module instance. * * The function auth_mod_alloc() allocates an authentication module object. * */auth_mod_t *auth_mod_alloc(auth_scheme_t *scheme,			   tag_type_t tag, tag_value_t value, ...){  auth_mod_t *am = NULL;  if ((am = su_home_new(scheme->asch_size))) {    am->am_scheme = scheme;    su_home_destructor(am->am_home, auth_call_scheme_destructor);  }  return am;}/**Initialize an authentication module instance. * * The function auth_mod_init_default() initializes an authentication module * object used to authenticate the requests. * * @param am * @param base * @param root * @param tag,value,... tagged argument list * * @TAGS * AUTHTAG_REALM(), AUTHTAG_OPAQUE(), AUTHTAG_DB(), AUTHTAG_QOP(), * AUTHTAG_ALGORITHM(), AUTHTAG_EXPIRES(), AUTHTAG_NEXT_EXPIRES(), * AUTHTAG_BLACKLIST(), AUTHTAG_FORBIDDEN(), AUTHTAG_ANONYMOUS(), * AUTHTAG_FAKE(), AUTHTAG_ALLOW(), AUTHTAG_REMOTE(), and * AUTHTAG_MASTER_KEY(). * * @return 0 if successful * @return -1 upon an error */int auth_init_default(auth_mod_t *am,		      auth_scheme_t *base,		      su_root_t *root,		      tag_type_t tag, tag_value_t value, ...){  int retval = 0;  ta_list ta;  char const *realm = NULL, *opaque = NULL, *db = NULL, *allows = NULL;  char const *qop = NULL, *algorithm = NULL;  unsigned expires = 60 * 60, next_expires = 5 * 60;  unsigned max_ncount = 0;  unsigned blacklist = 5;  int forbidden = 0;  int anonymous = 0;  int fake = 0;  url_string_t const *remote = NULL;  char const *master_key = "fish";  char *s;  ta_start(ta, tag, value);  /* Authentication stuff */  tl_gets(ta_args(ta),	  AUTHTAG_REALM_REF(realm),	  AUTHTAG_OPAQUE_REF(opaque),	  AUTHTAG_DB_REF(db),	  AUTHTAG_QOP_REF(qop),	  AUTHTAG_ALGORITHM_REF(algorithm),	  AUTHTAG_EXPIRES_REF(expires),	  AUTHTAG_NEXT_EXPIRES_REF(next_expires),	  AUTHTAG_MAX_NCOUNT_REF(max_ncount),	  AUTHTAG_BLACKLIST_REF(blacklist),	  AUTHTAG_FORBIDDEN_REF(forbidden),	  AUTHTAG_ANONYMOUS_REF(anonymous),	  AUTHTAG_FAKE_REF(fake),	  AUTHTAG_ALLOW_REF(allows),	  AUTHTAG_REMOTE_REF(remote),	  AUTHTAG_MASTER_KEY_REF(master_key),	  TAG_NULL());  if (!realm) realm = "*";  if (!allows) allows = "ACK, BYE, CANCEL";  am->am_realm = su_strdup(am->am_home, realm);  am->am_opaque = su_strdup(am->am_home, opaque);  am->am_db = su_strdup(am->am_home, db);  s = su_strdup(am->am_home, allows);  if (s)    msg_commalist_d(am->am_home, &s, &am->am_allow, NULL);  am->am_expires = expires;  am->am_next_exp = next_expires;  am->am_max_ncount = max_ncount;  am->am_blacklist = blacklist;  am->am_forbidden = forbidden;  am->am_anonymous = anonymous;  am->am_fake = fake;  am->am_remote = url_hdup(am->am_home, (url_t *)remote);  am->am_algorithm = algorithm ? su_strdup(am->am_home, algorithm) : "MD5";  am->am_nextnonce = !algorithm || strcasecmp(algorithm, "MD5") == 0;  if (next_expires == 0)    am->am_nextnonce = 0;  am->am_qop = su_strdup(am->am_home, qop);  if (master_key) {    su_md5_t md5[1];    su_md5_init(md5);    su_md5_strupdate(md5, master_key);    su_md5_strupdate(md5, "70P 53KR37");    su_md5_digest(md5, am->am_master_key);  }  auth_md5_hmac_key(am);  /* Make sure that we have something     that can be used to identify credentials */  if (am->am_opaque && strcmp(am->am_opaque, "*") == 0) {#ifndef HOST_NAME_MAX#define HOST_NAME_MAX 255#endif    char hostname[HOST_NAME_MAX + 1];    su_md5_t md5[1];    uint8_t hmac[6];    gethostname(hostname, sizeof hostname);    auth_md5_hmac_init(am, md5);    su_md5_strupdate(md5, hostname);    su_md5_update(md5, ":", 1);    if (am->am_remote)      url_update(md5, am->am_remote);    auth_md5_hmac_digest(am, md5, hmac, sizeof hmac);    base64_e(hostname, sizeof hostname, hmac, sizeof hmac);    am->am_opaque = su_strdup(am->am_home, hostname);    if (!am->am_opaque) {      retval = -1;      SU_DEBUG_1(("%s: cannot create unique identifier\n", __func__));    }  }  if (retval < 0)    ;  else if (db) {    retval = auth_readdb(am);    if (retval == -1) {      int err = errno;      SU_DEBUG_1(("auth-module: %s: %s\n", am->am_db, strerror(err)));      errno = err;    }  }  else {    retval = auth_htable_resize(am->am_home, am->am_users, 0);  }  ta_end(ta);  return retval;}/** Destroy (a reference to) an authentication module. */void auth_mod_destroy(auth_mod_t *am){  su_home_unref(am->am_home);}/** Call scheme-specific destructor function. */static void auth_call_scheme_destructor(void *arg){  auth_mod_t *am = arg;  am->am_scheme->asch_destroy(am);}/** Do-nothing destroy function. * * The auth_destroy_default() is the default member function called by * auth_mod_destroy(). */void auth_destroy_default(auth_mod_t *am){}/** Create a new reference to authentication module. */auth_mod_t *auth_mod_ref(auth_mod_t *am){  return (auth_mod_t *)su_home_ref(am->am_home);}/** Destroy a reference to an authentication module. */void auth_mod_unref(auth_mod_t *am){  su_home_unref(am->am_home);}/** Get authenticatin module name. @NEW_1_12_4. */char const *auth_mod_name(auth_mod_t *am){  return am ? am->am_scheme->asch_method : "<nil>";}/** Initialize a auth_status_t stucture. * * @retval NULL upon an error * @relates auth_status_t */auth_status_t *auth_status_init(void *p, isize_t size){  return auth_status_init_with(p, size, 500, auth_internal_server_error);}/** Initialize a auth_status_t stucture. * * @retval NULL upon an error * @relates auth_status_t */auth_status_t *auth_status_init_with(void *p,				     isize_t size,				     int status,				     char const *phrase){  auth_status_t *as;  if (!p || size < (sizeof *as))    return NULL;  if (size > INT_MAX) size = INT_MAX;  as = memset(p, 0, size);  as->as_home->suh_size = (int)size;  /* su_home_init(as->as_home); */  as->as_status = status, as->as_phrase = phrase;  return as;}/** Allocate a new auth_status_t structure. @relates auth_status_t */auth_status_t *auth_status_new(su_home_t *home){  auth_status_t *as = su_home_clone(home, (sizeof *as));  if (as) {    as->as_status = 500;    as->as_phrase = auth_internal_server_error;  }  return as;}/** Create a new reference to an auth_status_t structure. * @relates auth_status_t */auth_status_t *auth_status_ref(auth_status_t *as){  return (auth_status_t *)su_home_ref(as->as_home);}/** Destroy (a reference to) an auth_status_t structure. @relates auth_status_t */void auth_status_unref(auth_status_t *as){  su_home_unref(as->as_home);}/** Authenticate user. * * The function auth_mod_method() invokes scheme-specific authentication * operation where the user's credentials are checked using scheme-specific * method. The authentication result along with an optional challenge header * is stored in the @a as structure. * * @param am           pointer to authentication module object [in] * @param as           pointer to authentication status structure [in/out] * @param credentials  pointer to a header with user's credentials [in] * @param ach          pointer to a structure describing challenge [in] * * The @a ach structure defines what kind of response and challenge header * is returned to the user. For example, a server authentication is * implemented with 401 response code and phrase along with WWW-Authenticate * header template in the @a ach structure. * * The auth_mod_method() returns the authentication result in the * #auth_mod_t @a as structure. The @a as->as_status describes the result * as follows: * - <i>as->as_status == 0</i> authentication is successful * - <i>as->as_status == 100</i> authentication is pending * - <i>as->as_status >= 400</i> authentication fails, *   return as_status as an error code to client * * When the authentication is left pending, the client must set the * as_callback pointer in @a as structure to an appropriate callback * function. The callback is invoked when the authentication is completed, * either successfully or with an error. * * Note that the authentication module may generate a new challenge each * time authentication is used (e.g., Digest using MD5 algorithm). Such a * challenge header is stored in the @a as->as_response return-value field. * * @note The authentication plugin may use the given reference to @a as, @a * credentials and @a ach structures until the asynchronous authentication * completes. Therefore, they should not be allocated from stack unless * application uses strictly synchronous authentication schemes only (Basic * and Digest). * * @note This function should be called auth_mod_check(). */void auth_mod_verify(auth_mod_t *am,		     auth_status_t *as,		     msg_auth_t *credentials,		     auth_challenger_t const *ach){  char const *wildcard, *host;  if (!am || !as || !ach)    return;  wildcard = strchr(am->am_realm, '*');  host = as->as_domain;  /* Initialize per-request realm */  if (as->as_realm)    ;  else if (!wildcard) {    as->as_realm = am->am_realm;  }  else if (!host) {    return;			/* Internal error */  }  else if (strcmp(am->am_realm, "*") == 0) {    as->as_realm = host;  }  else {    /* Replace * with hostpart */    as->as_realm = su_sprintf(as->as_home, "%.*s%s%s",			      (int)(wildcard - am->am_realm), am->am_realm,			      host,			      wildcard + 1);  }  am->am_scheme->asch_check(am, as, credentials, ach);}/** Make a challenge header. * * This function invokes plugin-specific member function generating a * challenge header. Client uses the challenge header contents when * prompting the user for a username and password then generates its * credential header using the parameters given in the challenge header. * * @param am pointer to authentication module object * @param as pointer to authentication status structure (return-value) * @param ach pointer to a structure describing challenge * * The auth_mod_challenge() returns the challenge header, appropriate * response code and reason phrase in the #auth_status_t structure. The * auth_mod_challenge() is currently always synchronous function. */void auth_mod_challenge(auth_mod_t *am,			auth_status_t *as,			auth_challenger_t const *ach){  if (am && as && ach)    am->am_scheme->asch_challenge(am, as, ach);}/** Cancel asynchronous authentication. * * The auth_mod_cancel() function cancels a pending authentication. * Application can reclaim the authentication status, credential and * challenger objects by using auth_mod_cancel(). */void auth_mod_cancel(auth_mod_t *am, auth_status_t *as){  if (am && as)    am->am_scheme->asch_cancel(am, as);}/** Do-nothing cancel function. * * The auth_cancel_default() is the default member function called by * auth_mod_cancel(). */void auth_cancel_default(auth_mod_t *am, auth_status_t *as){}/* ====================================================================== *//* Basic authentication scheme */static void auth_method_basic_x(auth_mod_t *am,				auth_status_t *as,				msg_auth_t *au,				auth_challenger_t const *ach);auth_scheme_t auth_scheme_basic[1] =  {{      "Basic",			/* asch_method */      sizeof (auth_mod_t),	/* asch_size */      auth_init_default,	/* asch_init */      auth_method_basic_x, 	/* asch_check */      auth_challenge_basic,	/* asch_challenge */      auth_cancel_default,	/* asch_cancel */      auth_destroy_default	/* asch_destroy */  }};/**Authenticate a request with @b Basic authentication. * * This function reads user database before authentication, if needed. */staticvoid auth_method_basic_x(auth_mod_t *am,			 auth_status_t *as,			 msg_auth_t *au,			 auth_challenger_t const *ach){  if (am) {    auth_readdb_if_needed(am);    auth_method_basic(am, as, au, ach);  }}/** Authenticate a request with @b Basic authentication scheme. * */void auth_method_basic(auth_mod_t *am,

⌨️ 快捷键说明

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