📄 auth_module.c
字号:
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 + -