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

📄 auth_module.c

📁 Sofia SIP is an open-source SIP User-Agent library, compliant with the IETF RFC3261 specification.
💻 C
📖 第 1 页 / 共 3 页
字号:
    if (N > 0) {      size_t size = (N * 5 + 3) / 4;      if (auth_htable_resize(am->am_home, am->am_users, size) < 0 ||	  !(fresh = su_zalloc(am->am_home, sizeof(*fresh) * N))) {	su_free(am->am_home, buffer);	return -1;      }    }    if (am->am_anonymous) {      assert(i < N);      apw = fresh + i++;      apw->apw_index = msg_hash_string("anonymous");      apw->apw_user = "anonymous";      apw->apw_pass = "";      apw->apw_realm = "";      am->am_anon_user = apw;      if (auth_htable_is_full(am->am_users))	auth_htable_resize(am->am_home, am->am_users, 0);      auth_htable_append_local(am->am_users, apw);    }    apw = NULL;    for (data = buffer, s = data;	 s < data + len && i < N;	 s += n + strspn(s + n, "\r\n")) {      char *user, *pass, *realm, *ident;      n = strcspn(s, "\r\n");      if (*s == '#')	continue;      user = s;      s[n++] = '\0';      if (!(pass = strchr(user, ':')))	continue;      *pass++ = '\0';      if (!*pass || !*user)	continue;      if ((realm = strchr(pass, ':')))	*realm++ = '\0';      else	realm = "";      if ((ident = strchr(realm, ':')))	*ident++ = '\0';      else	ident = "";      apw = fresh + i++;      apw->apw_index = msg_hash_string(user);      apw->apw_user = user;      apw->apw_ident = ident;      /* Check for htdigest format */      if (span_hexdigit(realm) == 32 && realm[32] == '\0') {	apw->apw_realm = pass;	apw->apw_hash = realm;      } else {	apw->apw_pass = pass;	apw->apw_realm = realm;      }      if (auth_htable_is_full(am->am_users))	auth_htable_resize(am->am_home, am->am_users, 0);      auth_htable_append_local(am->am_users, apw);    }    assert(i <= N);    N = i;    /* Remove from hash those entries that were read from old passwd file */    for (i = 0; i < am->am_local_count; i++) {      if (am->am_locals[i].apw_type == auth_apw_local)	auth_htable_remove(am->am_users, &am->am_locals[i]);    }    if (am->am_locals)      su_free(am->am_home, am->am_locals); /* Free old entries */    if (am->am_buffer)      su_free(am->am_home, am->am_buffer); /* Free old passwd file contents */    SU_DEBUG_5(("auth(%s): read %u entries from \"%s\"\n",		am->am_scheme->asch_method, (unsigned)N, am->am_db));    am->am_locals = fresh;    am->am_local_count = N;    am->am_buffer = buffer;    return 0;  }  return -1;}/** Append to hash, remove existing local user */su_inline voidauth_htable_append_local(auth_htable_t *aht, auth_passwd_t *apw){  auth_passwd_t **slot;  apw->apw_type = auth_apw_local;  /* Append to hash */  for (slot = auth_htable_hash(aht, apw->apw_index);       *slot;       slot = auth_htable_next(aht, slot)) {    if (strcmp((*slot)->apw_user, apw->apw_user) == 0) {      if ((*slot)->apw_type == auth_apw_local) {	(*slot)->apw_type = NULL;	assert(aht->aht_used > 0); aht->aht_used--;	apw->apw_extended = (*slot)->apw_extended;	*slot = NULL;	break;      }      else {	/* We insert local before external entry */	auth_passwd_t *swap = apw;	apw = *slot;	*slot = swap;      }    }  }  aht->aht_used++; assert(aht->aht_used <= aht->aht_size);  *slot = apw;}staticssize_t readfile(su_home_t *home,		 FILE *f,		 void **contents,		 int add_trailing_lf){  /* Read in whole (binary!) file */  char *buffer = NULL;  long size;  size_t len;  /* Read whole file in */  if (fseek(f, 0, SEEK_END) < 0 ||      (size = ftell(f)) < 0 ||      fseek(f, 0, SEEK_SET) < 0 ||      (long)(len = (size_t)size) != size ||      size + 2 > SSIZE_MAX) {    SU_DEBUG_1(("%s: unable to determine file size (%s)\n",		__func__, strerror(errno)));    return -1;  }  if (!(buffer = su_alloc(home, len + 2)) ||      fread(buffer, 1, len, f) != len) {    SU_DEBUG_1(("%s: unable to read file (%s)\n", __func__, strerror(errno)));    if (buffer)      su_free(home, buffer);    return -1;  }  if (add_trailing_lf) {    /* Make sure that the buffer has trailing newline */    if (len == 0 || buffer[len - 1] != '\n')      buffer[len++] = '\n';  }  buffer[len] = '\0';  *contents = buffer;  return len;}/* ====================================================================== *//* Helper functions *//** Check if request method is on always-allowed list. * * @return 0 if allowed * @return 1 otherwise */int auth_allow_check(auth_mod_t *am, auth_status_t *as){  char const *method = as->as_method;  int i;  if (method && strcmp(method, "ACK") == 0) /* Hack */    return as->as_status = 0;  if (!method || !am->am_allow)    return 1;  if (am->am_allow[0] && strcmp(am->am_allow[0], "*") == 0)    return as->as_status = 0;  for (i = 0; am->am_allow[i]; i++)    if (strcmp(am->am_allow[i], method) == 0)      return as->as_status = 0;  return 1;}/** Find a credential header with matching scheme and realm. */msg_auth_t *auth_mod_credentials(msg_auth_t *auth,				 char const *scheme,				 char const *realm){  char const *arealm;  for (;auth; auth = auth->au_next) {    if (strcasecmp(auth->au_scheme, scheme))      continue;    if (!realm)      return auth;    arealm = msg_header_find_param(auth->au_common, "realm=");    if (!arealm)      continue;    if (arealm[0] == '"') {      /* Compare quoted arealm with unquoted realm */      int i, j;      for (i = 1, j = 0; arealm[i] != 0; i++, j++) {	if (arealm[i] == '"' && realm[j] == 0)	  return auth;	if (arealm[i] == '\\' && arealm[i + 1] != '\0')	  i++;	if (arealm[i] != realm[j])	  break;      }    } else {      if (strcmp(arealm, realm) == 0)	return auth;    }  }  return NULL;}/** Find a Digest credential header with matching realm and opaque. */msg_auth_t *auth_digest_credentials(msg_auth_t *auth,				    char const *realm,				    char const *opaque){  char const *arealm, *aopaque;  for (;auth; auth = auth->au_next) {    if (strcasecmp(auth->au_scheme, "Digest"))      continue;    if (realm) {      int cmp = 1;      arealm = msg_header_find_param(auth->au_common, "realm=");      if (!arealm)	continue;      if (arealm[0] == '"') {	/* Compare quoted arealm with unquoted realm */	int i, j;	for (i = 1, j = 0, cmp = 1; arealm[i] != 0; i++, j++) {	  if (arealm[i] == '"' && realm[j] == 0) {	    cmp = 0;	    break;	  }	  if (arealm[i] == '\\' && arealm[i + 1] != '\0')	    i++;	  if (arealm[i] != realm[j])	    break;	}      }      else {	cmp = strcmp(arealm, realm);      }      if (cmp)	continue;    }    if (opaque) {      int cmp = 1;      aopaque = msg_header_find_param(auth->au_common, "opaque=");      if (!aopaque)	continue;      if (aopaque[0] == '"') {	/* Compare quoted aopaque with unquoted opaque */	int i, j;	for (i = 1, j = 0, cmp = 1; aopaque[i] != 0; i++, j++) {	  if (aopaque[i] == '"' && opaque[j] == 0) {	    cmp = 0;	    break;	  }	  if (aopaque[i] == '\\' && aopaque[i + 1] != '\0')	    i++;	  if (aopaque[i] != opaque[j])	    break;	}      } else {	cmp = strcmp(aopaque, opaque);      }      if (cmp)	continue;    }    return auth;  }  return NULL;}/** Generate nonce parameter. * * @param am pointer to authentication module object * @param buffer string buffer for nonce [OUT] * @param bsize size of buffer [IN] * @param nextnonce true if this is a "nextnonce" [IN] * @param now  current time [IN] */isize_t auth_generate_digest_nonce(auth_mod_t *am,				   char buffer[],				   size_t bsize,				   int nextnonce,				   msg_time_t now){  struct nonce nonce[1] = {{ 0 }};  su_md5_t md5[1];  am->am_count += 3730029547U;	/* 3730029547 is a prime */  nonce->issued = now;  nonce->count = am->am_count;  nonce->nextnonce = nextnonce != 0;  /* Calculate HMAC of nonce data */  auth_md5_hmac_init(am, md5);  su_md5_update(md5, nonce, offsetof(struct nonce, digest));  auth_md5_hmac_digest(am, md5, nonce->digest, sizeof nonce->digest);  return base64_e(buffer, bsize, nonce, sizeof(nonce));}/** Validate nonce parameter. * * @param am   pointer to authentication module object * @param as   authentication status structure [OUT] * @param ar   decoded authentication response from client [IN] * @param now  current time [IN] */int auth_validate_digest_nonce(auth_mod_t *am,			       auth_status_t *as,			       auth_response_t *ar,			       msg_time_t now){  struct nonce nonce[1] = {{ 0 }};  su_md5_t md5[1];  uint8_t hmac[sizeof nonce->digest];  unsigned expires;  /* Check nonce */  if (!ar->ar_nonce) {    SU_DEBUG_5(("auth_method_digest: no nonce\n"));    return -1;  }  if (base64_d((void*)nonce, (sizeof nonce), ar->ar_nonce) != (sizeof nonce)) {    SU_DEBUG_5(("auth_method_digest: too short nonce\n"));    return -1;  }  /* Calculate HMAC over decoded nonce data */  auth_md5_hmac_init(am, md5);  su_md5_update(md5, nonce, offsetof(struct nonce, digest));  auth_md5_hmac_digest(am, md5, hmac, sizeof hmac);  if (memcmp(nonce->digest, hmac, sizeof nonce->digest)) {    SU_DEBUG_5(("auth_method_digest: bad nonce\n"));    return -1;  }  as->as_nonce_issued = nonce->issued;  as->as_nextnonce = nonce->nextnonce != 0;  expires = nonce->nextnonce ? am->am_next_exp : am->am_expires;  if (nonce->issued > now ||      (expires && nonce->issued + expires < now)) {    SU_DEBUG_5(("auth_method_digest: nonce expired %lu seconds ago "		"(lifetime %u)\n",		now - (nonce->issued + expires), expires));    as->as_stale = 1;  }  if (am->am_max_ncount && ar->ar_nc) {    unsigned long nc = strtoul(ar->ar_nc, NULL, 10);    if (nc == 0 || nc > am->am_max_ncount) {      SU_DEBUG_5(("auth_method_digest: nonce used %s times, max %u\n",		  ar->ar_nc, am->am_max_ncount));      as->as_stale = 1;    }  }  /* We should also check cnonce, nc... */  return 0;}/* ====================================================================== *//* HMAC routines */staticvoid auth_md5_hmac_key(auth_mod_t *am){  size_t i;  uint8_t ipad[SU_MD5_DIGEST_SIZE];  uint8_t opad[SU_MD5_DIGEST_SIZE];  assert(SU_MD5_DIGEST_SIZE == sizeof am->am_master_key);  /* Derive HMAC ipad and opad from master key */  for (i = 0; i < sizeof am->am_master_key; i++) {    ipad[i] = am->am_master_key[i] ^ 0x36;    opad[i] = am->am_master_key[i] ^ 0x5C;  }  /* Pre-calculate sum of ipad */  su_md5_init(&am->am_hmac_ipad);  su_md5_update(&am->am_hmac_ipad, ipad, sizeof ipad);  /* Pre-calculate sum of opad */  su_md5_init(&am->am_hmac_opad);  su_md5_update(&am->am_hmac_opad, opad, sizeof opad);}void auth_md5_hmac_init(auth_mod_t *am, struct su_md5_t *imd5){  *imd5 = am->am_hmac_ipad;}void auth_md5_hmac_digest(auth_mod_t *am, struct su_md5_t *imd5,			  void *hmac, size_t size){  uint8_t digest[SU_MD5_DIGEST_SIZE];  su_md5_t omd5[1];  /* inner sum */  su_md5_digest(imd5, digest);  *omd5 = am->am_hmac_opad;  su_md5_update(omd5, digest, sizeof *digest);  /* outer sum */  if (size == sizeof digest) {    su_md5_digest(omd5, hmac);  }  else {    su_md5_digest(omd5, digest);    if (size > sizeof digest) {      memset((char *)hmac + (sizeof digest), 0, size - sizeof digest);      size = sizeof digest;    }    memcpy(hmac, digest, size);  }}/* ====================================================================== *//* Compatibility interface */void auth_mod_method(auth_mod_t *am,		     auth_status_t *as,		     msg_auth_t *credentials,		     auth_challenger_t const *ach){  auth_mod_verify(am, as, credentials, ach);}void auth_mod_check_client(auth_mod_t *am,			   auth_status_t *as,			   msg_auth_t *credentials,			   auth_challenger_t const *ach){  auth_mod_verify(am, as, credentials, ach);}void auth_mod_challenge_client(auth_mod_t *am,			       auth_status_t *as,			       auth_challenger_t const *ach){  auth_mod_challenge(am, as, ach);}

⌨️ 快捷键说明

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