📄 auth_module.c
字号:
auth_status_t *as, msg_auth_t *au, auth_challenger_t const *ach){ char *userpass, buffer[128]; size_t n, upsize; char *pass; auth_passwd_t *apw; if (!as->as_realm) return; userpass = buffer, upsize = sizeof buffer; for (au = auth_mod_credentials(au, "Basic", NULL); au; au = auth_mod_credentials(au->au_next, "Basic", NULL)) { if (!au->au_params) continue; n = base64_d(userpass, upsize - 1, au->au_params[0]); if (n < 0 || n >= INT_MAX) continue; if (n >= upsize) { void *b = realloc(userpass == buffer ? NULL : userpass, upsize = n + 1); if (b == NULL) break; base64_d(userpass = b, upsize - 1, au->au_params[0]); } userpass[n] = 0; if (!(pass = strchr(userpass, ':'))) continue; *pass++ = '\0'; SU_DEBUG_5(("auth_method_basic: %s => %s:%s\n", au->au_params[0], userpass, pass)); if (!(apw = auth_mod_getpass(am, userpass, as->as_realm))) continue; if (strcmp(apw->apw_pass, pass)) continue; as->as_user = apw->apw_user; as->as_anonymous = apw == am->am_anon_user; as->as_ident = apw->apw_ident; as->as_match = (msg_header_t *)au; as->as_status = 0; /* Successful authentication! */ break; } if (userpass != buffer) free(userpass); if (au) return; if (auth_allow_check(am, as)) auth_challenge_basic(am, as, ach);}/** Construct a challenge header for @b Basic authentication scheme. */void auth_challenge_basic(auth_mod_t *am, auth_status_t *as, auth_challenger_t const *ach){ as->as_status = ach->ach_status; as->as_phrase = ach->ach_phrase; as->as_response = msg_header_format(as->as_home, ach->ach_header, "Basic realm=\"%s\"", as->as_realm);}/* ====================================================================== *//* Digest authentication scheme */static void auth_method_digest_x(auth_mod_t *am, auth_status_t *as, msg_auth_t *au, auth_challenger_t const *ach);auth_scheme_t auth_scheme_digest[1] = {{ "Digest", /* asch_method */ sizeof (auth_mod_t), /* asch_size */ auth_init_default, /* asch_init */ auth_method_digest_x, /* asch_check */ auth_challenge_digest, /* asch_challenge */ auth_cancel_default, /* asch_cancel */ auth_destroy_default /* asch_destroy */ }};struct nonce { msg_time_t issued; uint32_t count; uint16_t nextnonce; uint8_t digest[6];};#define AUTH_DIGEST_NONCE_LEN (BASE64_MINSIZE(sizeof (struct nonce)) + 1)/** Authenticate a request with @b Digest authentication scheme. * * This function reads user database before authentication, if needed. */staticvoid auth_method_digest_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_digest(am, as, au, ach); }}/** Authenticate a request with @b Digest authentication scheme. */void auth_method_digest(auth_mod_t *am, auth_status_t *as, msg_auth_t *au, auth_challenger_t const *ach){ as->as_allow = as->as_allow || auth_allow_check(am, as) == 0; if (as->as_realm) au = auth_digest_credentials(au, as->as_realm, am->am_opaque); else au = NULL; if (as->as_allow) { SU_DEBUG_5(("%s: allow unauthenticated %s\n", __func__, as->as_method)); as->as_status = 0, as->as_phrase = NULL; as->as_match = (msg_header_t *)au; return; } if (au) { auth_response_t ar[1] = {{ sizeof(ar) }}; auth_digest_response_get(as->as_home, ar, au->au_params); as->as_match = (msg_header_t *)au; auth_check_digest(am, as, ar, ach); } else { /* There was no matching credentials, send challenge */ SU_DEBUG_5(("%s: no credentials matched\n", __func__)); auth_challenge_digest(am, as, ach); }}/** Verify digest authentication */void auth_check_digest(auth_mod_t *am, auth_status_t *as, auth_response_t *ar, auth_challenger_t const *ach){ char const *a1; auth_hexmd5_t a1buf, response; auth_passwd_t *apw; char const *phrase; msg_time_t now = msg_now(); if (am == NULL || as == NULL || ar == NULL || ach == NULL) { if (as) { as->as_status = 500, as->as_phrase = "Internal Server Error"; as->as_response = NULL; } return; } phrase = "Bad authorization";#define PA "Authorization missing " if ((!ar->ar_username && (phrase = PA "username")) || (!ar->ar_nonce && (phrase = PA "nonce")) || (!ar->ar_uri && (phrase = PA "URI")) || (!ar->ar_response && (phrase = PA "response")) || /* (!ar->ar_opaque && (phrase = PA "opaque")) || */ /* Check for qop */ (ar->ar_qop && ((ar->ar_auth && strcasecmp(ar->ar_qop, "auth") && strcasecmp(ar->ar_qop, "\"auth\"")) || (ar->ar_auth_int && strcasecmp(ar->ar_qop, "auth-int") && strcasecmp(ar->ar_qop, "\"auth-int\""))) && (phrase = PA "has invalid qop"))) { assert(phrase); SU_DEBUG_5(("auth_method_digest: 400 %s\n", phrase)); as->as_status = 400, as->as_phrase = phrase; as->as_response = NULL; return; } if (as->as_nonce_issued == 0 /* Already validated nonce */ && auth_validate_digest_nonce(am, as, ar, now) < 0) { as->as_blacklist = am->am_blacklist; auth_challenge_digest(am, as, ach); return; } if (as->as_stale) { auth_challenge_digest(am, as, ach); return; } apw = auth_mod_getpass(am, ar->ar_username, ar->ar_realm); if (apw && apw->apw_hash) a1 = apw->apw_hash; else if (apw && apw->apw_pass) auth_digest_a1(ar, a1buf, apw->apw_pass), a1 = a1buf; else auth_digest_a1(ar, a1buf, "xyzzy"), a1 = a1buf, apw = NULL; if (ar->ar_md5sess) auth_digest_a1sess(ar, a1buf, a1), a1 = a1buf; auth_digest_response(ar, response, a1, as->as_method, as->as_body, as->as_bodylen); if (!apw || strcmp(response, ar->ar_response)) { if (am->am_forbidden) { as->as_status = 403, as->as_phrase = "Forbidden"; as->as_response = NULL; as->as_blacklist = am->am_blacklist; } else { auth_challenge_digest(am, as, ach); as->as_blacklist = am->am_blacklist; } SU_DEBUG_5(("auth_method_digest: response did not match\n")); return; } assert(apw); as->as_user = apw->apw_user; as->as_anonymous = apw == am->am_anon_user; as->as_ident = apw->apw_ident; if (am->am_nextnonce || am->am_mutual) auth_info_digest(am, as, ach); if (am->am_challenge) auth_challenge_digest(am, as, ach); SU_DEBUG_7(("auth_method_digest: successful authentication\n")); as->as_status = 0; /* Successful authentication! */ as->as_phrase = "";}/** Construct a challenge header for @b Digest authentication scheme. */void auth_challenge_digest(auth_mod_t *am, auth_status_t *as, auth_challenger_t const *ach){ char const *u, *d; char nonce[AUTH_DIGEST_NONCE_LEN]; auth_generate_digest_nonce(am, nonce, sizeof nonce, 0, msg_now()); u = as->as_uri; d = as->as_pdomain; as->as_response = msg_header_format(as->as_home, ach->ach_header, "Digest" " realm=\"%s\"," "%s%s%s" "%s%s%s" " nonce=\"%s\"," "%s%s%s" "%s" /* stale */ " algorithm=%s" "%s%s%s", as->as_realm, u ? " uri=\"" : "", u ? u : "", u ? "\"," : "", d ? " domain=\"" : "", d ? d : "", d ? "\"," : "", nonce, am->am_opaque ? " opaque=\"" : "", am->am_opaque ? am->am_opaque : "", am->am_opaque ? "\"," : "", as->as_stale ? " stale=true," : "", am->am_algorithm, am->am_qop ? ", qop=\"" : "", am->am_qop ? am->am_qop : "", am->am_qop ? "\"" : ""); if (!as->as_response) as->as_status = 500, as->as_phrase = auth_internal_server_error; else as->as_status = ach->ach_status, as->as_phrase = ach->ach_phrase;}/** Construct a info header for @b Digest authentication scheme. */void auth_info_digest(auth_mod_t *am, auth_status_t *as, auth_challenger_t const *ach){ if (!ach->ach_info) return; if (am->am_nextnonce) { char nonce[AUTH_DIGEST_NONCE_LEN]; auth_generate_digest_nonce(am, nonce, sizeof nonce, 1, msg_now()); as->as_info = msg_header_format(as->as_home, ach->ach_info, "nextnonce=\"%s\"", nonce); }}/* ====================================================================== *//* Password database */su_inline voidauth_htable_append_local(auth_htable_t *pr, auth_passwd_t *apw);/** Get an passwd entry for user. */auth_passwd_t *auth_mod_getpass(auth_mod_t *am, char const *user, char const *realm){ auth_passwd_t *apw, **slot; unsigned hash; if (am == NULL || user == NULL) return NULL; hash = msg_hash_string(user); for (slot = auth_htable_hash(am->am_users, hash); (apw = *slot); slot = auth_htable_next(am->am_users, slot)) { if (hash != apw->apw_index) continue; if (strcmp(user, apw->apw_user)) continue; if (realm && apw->apw_realm[0] && strcmp(realm, apw->apw_realm)) continue; break; /* Found it */ } return apw;}/** Add a password entry. */auth_passwd_t *auth_mod_addpass(auth_mod_t *am, char const *user, char const *realm){ auth_passwd_t *apw, **slot; unsigned index; if (am == NULL || user == NULL) return NULL; index = msg_hash_string(user); for (slot = auth_htable_hash(am->am_users, index); (apw = *slot); slot = auth_htable_next(am->am_users, slot)) { if (index != apw->apw_index) continue; if (strcmp(user, apw->apw_user)) continue; if (realm && strcmp(realm, apw->apw_realm)) continue; break; /* Found it */ } if (realm == NULL) realm = ""; if (!apw) { size_t ulen = strlen(user) + 1, rlen = strlen(realm) + 1; size_t size = sizeof *apw + ulen + rlen; apw = su_alloc(am->am_home, size); if (apw) { memset(apw, 0, sizeof *apw); apw->apw_index = index; apw->apw_user = memcpy((char *)(apw + 1), user, ulen); apw->apw_realm = memcpy((char *)apw->apw_user + ulen, realm, rlen); if (!auth_htable_is_full(am->am_users)) { *slot = apw, am->am_users->aht_used++; } else { if (auth_htable_resize(am->am_home, am->am_users, 0) < 0) su_free(am->am_home, apw), apw = NULL; else auth_htable_append(am->am_users, apw); } } } return apw;}static ssize_t readfile(su_home_t *, FILE *, void **contents, int add_trailing_lf);static int auth_readdb_internal(auth_mod_t *am, int always);/** Read authentication database */int auth_readdb(auth_mod_t *am){ return auth_readdb_internal(am, 1);}/** Read authentication database only when needed */int auth_readdb_if_needed(auth_mod_t *am){ struct stat st[1]; if (!am->am_stat || !am->am_db) return 0; if (stat(am->am_db, st) != -1 && st->st_dev == am->am_stat->st_dev && st->st_ino == am->am_stat->st_ino && st->st_size == am->am_stat->st_size && memcmp(&st->st_mtime, &am->am_stat->st_mtime, (sizeof st->st_mtime)) == 0) /* Nothing has changed or passwd file is removed */ return 0; return auth_readdb_internal(am, 0);}#if HAVE_FLOCK#include <sys/file.h>#endif/* This is just a magic value */#define auth_apw_local ((void *)(intptr_t)auth_readdb_internal)/** Read authentication database */staticint auth_readdb_internal(auth_mod_t *am, int always){ FILE *f; char *data, *s; size_t len, i, n, N; auth_passwd_t *apw; if (!am->am_stat) am->am_stat = su_zalloc(am->am_home, sizeof (*am->am_stat)); f = fopen(am->am_db, "rb"); if (f) { void *buffer = NULL; auth_passwd_t *fresh = NULL;#if HAVE_FLOCK int locked; /* Obtain shared lock on the database file */ if (flock(fileno(f), LOCK_SH | (always ? 0 : LOCK_NB)) == 0) { locked = 1; } else { locked = 0; if (errno == ENOLCK) { ; } else if (errno == EWOULDBLOCK) { SU_DEBUG_3(("auth(%s): user file \"%s\" is busy, trying again later\n", am->am_scheme->asch_method, am->am_db)); fclose(f); return always ? -1 : 0; } else { SU_DEBUG_3(("auth(%s): flock(\"%s\"): %s (%u)\n", am->am_scheme->asch_method, am->am_db, strerror(errno), errno)); fclose(f); return always ? -1 : 0; } }#endif if (am->am_stat) stat(am->am_db, am->am_stat); /* too bad if this fails */ len = readfile(am->am_home, f, &buffer, 1);#if HAVE_FLOCK /* Release shared lock on the database file */ if (locked && flock(fileno(f), LOCK_UN) == -1) { SU_DEBUG_0(("auth(%s): un-flock(\"%s\"): %s (%u)\n", am->am_scheme->asch_method, am->am_db, strerror(errno), errno)); fclose(f); return -1; }#endif fclose(f); if (len < 0) return -1; /* Count number of entries in new buffer */ for (i = am->am_anonymous, s = data = buffer; s < data + len; s += n + strspn(s + n, "\r\n")) { n = strcspn(s, "\r\n"); if (*s != '#' && *s != '\n' && *s != '\r') i++; } N = i, i = 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -