#include "config.h" #include #include #include #include #include #ifdef HAVE_CRYPT_H #include #endif #ifdef HAVE_RPCSVC_CRYPT_H #include #endif #include "libstr.h" #include "liblist.h" #include "libmd5.h" #include "httpauth.h" #include "log.h" /* If a required_group_file exist, is a user in the right group? */ bool group_oke(t_session *session, char *user, t_charlist *group) { bool retval; FILE *gfp; char *pwfile, line[257], *item, *rest; int len; if ((user == NULL) || (group->size == 0)) { return true; } if (session->host->groupfile == NULL) { return false; } pwfile = file_in_chroot(session, session->host->groupfile); if ((gfp = fopen_neighbour(pwfile, "r", session->file_on_disk)) == NULL) { log_file_error(session, session->host->groupfile, "groupfile not found"); return false; } retval = false; line[256] = '\0'; while (fgets(line, 256, gfp) != NULL) { if (split_string(line, &item, &rest, ':') == 0) { if (in_charlist(item, group)) { if ((len = strlen(rest)) == 0) { continue; } if ((rest[len] == '\n') || (rest[len] == '\r')) { rest[len] = '\0'; } do { split_string(rest, &item, &rest, ' '); if (strcmp(user, item) == 0) { retval = true; break; } } while (rest != NULL); } } if (retval == true) { break; } } fclose(gfp); return retval; } /* Read a password from a file */ static char *get_password(t_session *session, char *username) { char *pwfile, line[257], *result = NULL, *sep; FILE *pfp; pwfile = file_in_chroot(session, session->host->passwordfile); if ((pfp = fopen_neighbour(pwfile, "r", session->file_on_disk)) != NULL) { line[256] = '\0'; while ((sep = fgets(line, 256, pfp)) != NULL) { while ((*sep != ':') && (*sep != '\0')) { sep++; } if (*sep == ':') { *(sep++) = '\0'; if (strcmp(line, username) == 0) { result = sep; while ((*sep != '\n') && (*sep != '\r') && (*sep != ':') && (*sep != '\0')) { sep++; } if (*sep != '\0') { *sep = '\0'; result = strdup(result); } else { result = NULL; } break; } } } fclose(pfp); } else { log_file_error(session, session->host->passwordfile, "passwordfile not found"); } return result; } /* Basic HTTP authentication. */ static bool basic_http_authentication(t_session *session, char *auth_str) { bool retval = false; char *auth_user, *auth_passwd, *passwd, *encrypted, salt[3]; if ((auth_user = strdup(auth_str)) == NULL) { return false; } if (decode_base64(auth_user)) { auth_passwd = auth_user; while ((*auth_passwd != ':') && (auth_passwd != '\0')) { auth_passwd++; } if (*auth_passwd == ':') { *(auth_passwd++) = '\0'; if ((passwd = get_password(session, auth_user)) != NULL) { if (group_oke(session, auth_user, &(session->host->required_group))) { salt[0] = *passwd; salt[1] = *(passwd + 1); salt[2] = '\0'; encrypted = crypt(auth_passwd, salt); /* Password match? */ if (strcmp(encrypted, passwd) == 0) { retval = ((session->remote_user = strdup(auth_user)) != NULL); } } free(passwd); } } } free(auth_user); return retval; } static char *unquoted(char *str) { int len; if (str != NULL) { len = strlen(str); if (len > 0) { if (*str == '\"') { str++; len--; } if (str[len - 1] == '\"') { str[len - 1] = '\0'; } } } return str; } /* Digest HTTP authentication. */ static bool digest_http_authentication(t_session *session, char *auth_str) { bool retval = false, quote_found; char *key, *value, *rest, *empty = "", *passwd, A1[33], A2[33], result[33]; char *username = empty, *realm = empty, *nonce = empty, *uri = empty, *qop = empty, *nc = empty, *cnonce = empty, *algoritm = empty, *response = empty, *opaque = empty; key = rest = auth_str; while (*key != '\0') { quote_found = false; while (*rest != '\0') { if (*rest == '"') { if (quote_found) { if (*(rest + 1) == ',') { rest++; *(rest++) = '\0'; break; } else if (*(rest + 1) == '\0') { rest++; break; } else { return false; } } quote_found = true; } else if ((*rest == ',') && (quote_found == false)) { *(rest++) = '\0'; break; } rest++; } if (split_string(key, &key, &value, '=') != -1) { if (strcmp(key, "username") == 0) { username = unquoted(value); } else if (strcmp(key, "realm") == 0) { realm = unquoted(value); } else if (strcmp(key, "nonce") == 0) { nonce = unquoted(value); } else if (strcmp(key, "uri") == 0) { uri = unquoted(value); } else if (strcmp(key, "qop") == 0) { qop = unquoted(value); } else if (strcmp(key, "nc") == 0) { nc = unquoted(value); } else if (strcmp(key, "cnonce") == 0) { cnonce = unquoted(value); } else if (strcmp(key, "algoritm") == 0) { algoritm = unquoted(value); } else if (strcmp(key, "response") == 0) { response = unquoted(value); } else if (strcmp(key, "opaque") == 0) { opaque = unquoted(value); } } key = rest; } if (session->vars != NULL) { if (strncmp(session->uri, uri, session->uri_len) != 0) { return false; } else if (*(uri + session->uri_len) != '?') { return false; } else if (strcmp(session->vars, uri + session->uri_len + 1) != 0) { return false; } } else if (strcmp(session->uri, uri) != 0) { return false; } if ((passwd = get_password(session, username)) != NULL) { if (group_oke(session, username, &(session->host->required_group))) do { /* Calculate A1 */ if ((value = (char*)malloc(strlen(username) + strlen(realm) + strlen(passwd) + 3)) == NULL) { break; } sprintf(value, "%s:%s:%s", username, realm, passwd); md5_hash(value, strlen(value), A1); free(value); /* Calculate A2 */ if ((value = (char*)malloc(strlen(session->method) + strlen(uri) + 2)) == NULL) { break; } sprintf(value, "%s:%s", session->method, uri); md5_hash(value, strlen(value), A2); free(value); /* Calculate response */ if ((value = (char*)malloc(strlen(A1) + strlen(nonce) + strlen(A2) + 6)) == NULL) { break; } sprintf(value, "%s:%s:%s", A1, nonce, A2); md5_hash(value, strlen(value), result); free(value); /* Password match? */ if (strcmp(result, response) == 0) { retval = ((session->remote_user = strdup(username)) != NULL); } } while (false); free(passwd); } return retval; } /* Check if the file is protected by an .hiawatha file with passwordfile setting. */ bool http_authentication_oke(t_session *session, bool on_pwdfile_missing) { char *auth_str; bool result = false; if (session->host->passwordfile == NULL) { return on_pwdfile_missing; } else if ((auth_str = get_headerfield("Authorization:", session->headerfields)) != NULL) { auth_str = strdup(auth_str); if ((strncmp(auth_str, "Basic ", 6) == 0) && (session->host->auth_method == basic)) { result = basic_http_authentication(session, auth_str + 6); } else if ((strncmp(auth_str, "Digest ", 7) == 0) && (session->host->auth_method == digest)) { result = digest_http_authentication(session, auth_str + 7); } free(auth_str); } return result; }