553f11a8f542196fd02498006338dd33c64045c3fuankg/* Licensed to the Apache Software Foundation (ASF) under one or more
553f11a8f542196fd02498006338dd33c64045c3fuankg * contributor license agreements. See the NOTICE file distributed with
553f11a8f542196fd02498006338dd33c64045c3fuankg * this work for additional information regarding copyright ownership.
553f11a8f542196fd02498006338dd33c64045c3fuankg * The ASF licenses this file to You under the Apache License, Version 2.0
553f11a8f542196fd02498006338dd33c64045c3fuankg * (the "License"); you may not use this file except in compliance with
553f11a8f542196fd02498006338dd33c64045c3fuankg * the License. You may obtain a copy of the License at
553f11a8f542196fd02498006338dd33c64045c3fuankg *
553f11a8f542196fd02498006338dd33c64045c3fuankg * http://www.apache.org/licenses/LICENSE-2.0
553f11a8f542196fd02498006338dd33c64045c3fuankg *
553f11a8f542196fd02498006338dd33c64045c3fuankg * Unless required by applicable law or agreed to in writing, software
553f11a8f542196fd02498006338dd33c64045c3fuankg * distributed under the License is distributed on an "AS IS" BASIS,
553f11a8f542196fd02498006338dd33c64045c3fuankg * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
553f11a8f542196fd02498006338dd33c64045c3fuankg * See the License for the specific language governing permissions and
553f11a8f542196fd02498006338dd33c64045c3fuankg * limitations under the License.
553f11a8f542196fd02498006338dd33c64045c3fuankg */
553f11a8f542196fd02498006338dd33c64045c3fuankg
553f11a8f542196fd02498006338dd33c64045c3fuankg#include "lua_passwd.h"
553f11a8f542196fd02498006338dd33c64045c3fuankg#include "apr_strings.h"
553f11a8f542196fd02498006338dd33c64045c3fuankg#include "apr_errno.h"
553f11a8f542196fd02498006338dd33c64045c3fuankg
553f11a8f542196fd02498006338dd33c64045c3fuankg#if APR_HAVE_STDIO_H
553f11a8f542196fd02498006338dd33c64045c3fuankg#include <stdio.h>
553f11a8f542196fd02498006338dd33c64045c3fuankg#endif
553f11a8f542196fd02498006338dd33c64045c3fuankg
553f11a8f542196fd02498006338dd33c64045c3fuankg#include "apr_md5.h"
553f11a8f542196fd02498006338dd33c64045c3fuankg#include "apr_sha1.h"
553f11a8f542196fd02498006338dd33c64045c3fuankg
553f11a8f542196fd02498006338dd33c64045c3fuankg#if APR_HAVE_TIME_H
553f11a8f542196fd02498006338dd33c64045c3fuankg#include <time.h>
553f11a8f542196fd02498006338dd33c64045c3fuankg#endif
553f11a8f542196fd02498006338dd33c64045c3fuankg#if APR_HAVE_CRYPT_H
553f11a8f542196fd02498006338dd33c64045c3fuankg#include <crypt.h>
553f11a8f542196fd02498006338dd33c64045c3fuankg#endif
553f11a8f542196fd02498006338dd33c64045c3fuankg#if APR_HAVE_STDLIB_H
553f11a8f542196fd02498006338dd33c64045c3fuankg#include <stdlib.h>
553f11a8f542196fd02498006338dd33c64045c3fuankg#endif
553f11a8f542196fd02498006338dd33c64045c3fuankg#if APR_HAVE_STRING_H
553f11a8f542196fd02498006338dd33c64045c3fuankg#include <string.h>
553f11a8f542196fd02498006338dd33c64045c3fuankg#endif
553f11a8f542196fd02498006338dd33c64045c3fuankg#if APR_HAVE_UNISTD_H
553f11a8f542196fd02498006338dd33c64045c3fuankg#include <unistd.h>
553f11a8f542196fd02498006338dd33c64045c3fuankg#endif
553f11a8f542196fd02498006338dd33c64045c3fuankg#if APR_HAVE_IO_H
553f11a8f542196fd02498006338dd33c64045c3fuankg#include <io.h>
553f11a8f542196fd02498006338dd33c64045c3fuankg#endif
553f11a8f542196fd02498006338dd33c64045c3fuankg
553f11a8f542196fd02498006338dd33c64045c3fuankgstatic int generate_salt(char *s, size_t size, const char **errstr,
553f11a8f542196fd02498006338dd33c64045c3fuankg apr_pool_t *pool)
553f11a8f542196fd02498006338dd33c64045c3fuankg{
553f11a8f542196fd02498006338dd33c64045c3fuankg unsigned char rnd[32];
553f11a8f542196fd02498006338dd33c64045c3fuankg static const char itoa64[] =
553f11a8f542196fd02498006338dd33c64045c3fuankg "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
553f11a8f542196fd02498006338dd33c64045c3fuankg apr_size_t n;
553f11a8f542196fd02498006338dd33c64045c3fuankg unsigned int val = 0, bits = 0;
553f11a8f542196fd02498006338dd33c64045c3fuankg apr_status_t rv;
553f11a8f542196fd02498006338dd33c64045c3fuankg
553f11a8f542196fd02498006338dd33c64045c3fuankg n = (size * 6 + 7)/8;
553f11a8f542196fd02498006338dd33c64045c3fuankg if (n > sizeof(rnd)) {
553f11a8f542196fd02498006338dd33c64045c3fuankg *errstr = apr_psprintf(pool, "generate_salt(): BUG: Buffer too small");
553f11a8f542196fd02498006338dd33c64045c3fuankg return ERR_RANDOM;
553f11a8f542196fd02498006338dd33c64045c3fuankg }
553f11a8f542196fd02498006338dd33c64045c3fuankg rv = apr_generate_random_bytes(rnd, n);
553f11a8f542196fd02498006338dd33c64045c3fuankg if (rv) {
553f11a8f542196fd02498006338dd33c64045c3fuankg *errstr = apr_psprintf(pool, "Unable to generate random bytes: %pm",
553f11a8f542196fd02498006338dd33c64045c3fuankg &rv);
553f11a8f542196fd02498006338dd33c64045c3fuankg return ERR_RANDOM;
553f11a8f542196fd02498006338dd33c64045c3fuankg }
553f11a8f542196fd02498006338dd33c64045c3fuankg n = 0;
553f11a8f542196fd02498006338dd33c64045c3fuankg while (size > 0) {
553f11a8f542196fd02498006338dd33c64045c3fuankg if (bits < 6) {
553f11a8f542196fd02498006338dd33c64045c3fuankg val |= (rnd[n++] << bits);
553f11a8f542196fd02498006338dd33c64045c3fuankg bits += 8;
553f11a8f542196fd02498006338dd33c64045c3fuankg }
553f11a8f542196fd02498006338dd33c64045c3fuankg *s++ = itoa64[val & 0x3f];
553f11a8f542196fd02498006338dd33c64045c3fuankg size--;
553f11a8f542196fd02498006338dd33c64045c3fuankg val >>= 6;
553f11a8f542196fd02498006338dd33c64045c3fuankg bits -= 6;
553f11a8f542196fd02498006338dd33c64045c3fuankg }
553f11a8f542196fd02498006338dd33c64045c3fuankg *s = '\0';
553f11a8f542196fd02498006338dd33c64045c3fuankg return 0;
553f11a8f542196fd02498006338dd33c64045c3fuankg}
553f11a8f542196fd02498006338dd33c64045c3fuankg
553f11a8f542196fd02498006338dd33c64045c3fuankg/*
553f11a8f542196fd02498006338dd33c64045c3fuankg * Make a password record from the given information. A zero return
553f11a8f542196fd02498006338dd33c64045c3fuankg * indicates success; on failure, ctx->errstr points to the error message.
553f11a8f542196fd02498006338dd33c64045c3fuankg */
553f11a8f542196fd02498006338dd33c64045c3fuankgint mk_password_hash(passwd_ctx *ctx)
553f11a8f542196fd02498006338dd33c64045c3fuankg{
553f11a8f542196fd02498006338dd33c64045c3fuankg char *pw;
553f11a8f542196fd02498006338dd33c64045c3fuankg char salt[16];
553f11a8f542196fd02498006338dd33c64045c3fuankg apr_status_t rv;
553f11a8f542196fd02498006338dd33c64045c3fuankg int ret = 0;
553f11a8f542196fd02498006338dd33c64045c3fuankg#if CRYPT_ALGO_SUPPORTED
553f11a8f542196fd02498006338dd33c64045c3fuankg char *cbuf;
553f11a8f542196fd02498006338dd33c64045c3fuankg#endif
553f11a8f542196fd02498006338dd33c64045c3fuankg
553f11a8f542196fd02498006338dd33c64045c3fuankg pw = ctx->passwd;
553f11a8f542196fd02498006338dd33c64045c3fuankg switch (ctx->alg) {
553f11a8f542196fd02498006338dd33c64045c3fuankg case ALG_APSHA:
553f11a8f542196fd02498006338dd33c64045c3fuankg /* XXX out >= 28 + strlen(sha1) chars - fixed len SHA */
553f11a8f542196fd02498006338dd33c64045c3fuankg apr_sha1_base64(pw, strlen(pw), ctx->out);
553f11a8f542196fd02498006338dd33c64045c3fuankg break;
553f11a8f542196fd02498006338dd33c64045c3fuankg
553f11a8f542196fd02498006338dd33c64045c3fuankg case ALG_APMD5:
553f11a8f542196fd02498006338dd33c64045c3fuankg ret = generate_salt(salt, 8, &ctx->errstr, ctx->pool);
553f11a8f542196fd02498006338dd33c64045c3fuankg if (ret != 0) {
553f11a8f542196fd02498006338dd33c64045c3fuankg ret = ERR_GENERAL;
553f11a8f542196fd02498006338dd33c64045c3fuankg break;
553f11a8f542196fd02498006338dd33c64045c3fuankg }
553f11a8f542196fd02498006338dd33c64045c3fuankg rv = apr_md5_encode(pw, salt, ctx->out, ctx->out_len);
553f11a8f542196fd02498006338dd33c64045c3fuankg if (rv != APR_SUCCESS) {
553f11a8f542196fd02498006338dd33c64045c3fuankg ctx->errstr = apr_psprintf(ctx->pool,
553f11a8f542196fd02498006338dd33c64045c3fuankg "could not encode password: %pm", &rv);
553f11a8f542196fd02498006338dd33c64045c3fuankg ret = ERR_GENERAL;
553f11a8f542196fd02498006338dd33c64045c3fuankg }
553f11a8f542196fd02498006338dd33c64045c3fuankg break;
553f11a8f542196fd02498006338dd33c64045c3fuankg
553f11a8f542196fd02498006338dd33c64045c3fuankg#if CRYPT_ALGO_SUPPORTED
553f11a8f542196fd02498006338dd33c64045c3fuankg case ALG_CRYPT:
553f11a8f542196fd02498006338dd33c64045c3fuankg ret = generate_salt(salt, 8, &ctx->errstr, ctx->pool);
553f11a8f542196fd02498006338dd33c64045c3fuankg if (ret != 0)
553f11a8f542196fd02498006338dd33c64045c3fuankg break;
553f11a8f542196fd02498006338dd33c64045c3fuankg cbuf = crypt(pw, salt);
553f11a8f542196fd02498006338dd33c64045c3fuankg if (cbuf == NULL) {
553f11a8f542196fd02498006338dd33c64045c3fuankg rv = APR_FROM_OS_ERROR(errno);
553f11a8f542196fd02498006338dd33c64045c3fuankg ctx->errstr = apr_psprintf(ctx->pool, "crypt() failed: %pm", &rv);
553f11a8f542196fd02498006338dd33c64045c3fuankg ret = ERR_PWMISMATCH;
553f11a8f542196fd02498006338dd33c64045c3fuankg break;
553f11a8f542196fd02498006338dd33c64045c3fuankg }
553f11a8f542196fd02498006338dd33c64045c3fuankg
553f11a8f542196fd02498006338dd33c64045c3fuankg apr_cpystrn(ctx->out, cbuf, ctx->out_len - 1);
553f11a8f542196fd02498006338dd33c64045c3fuankg if (strlen(pw) > 8) {
553f11a8f542196fd02498006338dd33c64045c3fuankg char *truncpw = apr_pstrdup(ctx->pool, pw);
553f11a8f542196fd02498006338dd33c64045c3fuankg truncpw[8] = '\0';
553f11a8f542196fd02498006338dd33c64045c3fuankg if (!strcmp(ctx->out, crypt(truncpw, salt))) {
553f11a8f542196fd02498006338dd33c64045c3fuankg ctx->errstr = apr_psprintf(ctx->pool,
553f11a8f542196fd02498006338dd33c64045c3fuankg "Warning: Password truncated to 8 "
553f11a8f542196fd02498006338dd33c64045c3fuankg "characters by CRYPT algorithm.");
553f11a8f542196fd02498006338dd33c64045c3fuankg }
553f11a8f542196fd02498006338dd33c64045c3fuankg memset(truncpw, '\0', strlen(pw));
553f11a8f542196fd02498006338dd33c64045c3fuankg }
553f11a8f542196fd02498006338dd33c64045c3fuankg break;
553f11a8f542196fd02498006338dd33c64045c3fuankg#endif /* CRYPT_ALGO_SUPPORTED */
553f11a8f542196fd02498006338dd33c64045c3fuankg
553f11a8f542196fd02498006338dd33c64045c3fuankg#if BCRYPT_ALGO_SUPPORTED
553f11a8f542196fd02498006338dd33c64045c3fuankg case ALG_BCRYPT:
553f11a8f542196fd02498006338dd33c64045c3fuankg rv = apr_generate_random_bytes((unsigned char*)salt, 16);
553f11a8f542196fd02498006338dd33c64045c3fuankg if (rv != APR_SUCCESS) {
553f11a8f542196fd02498006338dd33c64045c3fuankg ctx->errstr = apr_psprintf(ctx->pool, "Unable to generate random "
553f11a8f542196fd02498006338dd33c64045c3fuankg "bytes: %pm", &rv);
553f11a8f542196fd02498006338dd33c64045c3fuankg ret = ERR_RANDOM;
553f11a8f542196fd02498006338dd33c64045c3fuankg break;
553f11a8f542196fd02498006338dd33c64045c3fuankg }
553f11a8f542196fd02498006338dd33c64045c3fuankg
553f11a8f542196fd02498006338dd33c64045c3fuankg if (ctx->cost == 0)
553f11a8f542196fd02498006338dd33c64045c3fuankg ctx->cost = BCRYPT_DEFAULT_COST;
553f11a8f542196fd02498006338dd33c64045c3fuankg rv = apr_bcrypt_encode(pw, ctx->cost, (unsigned char*)salt, 16,
553f11a8f542196fd02498006338dd33c64045c3fuankg ctx->out, ctx->out_len);
553f11a8f542196fd02498006338dd33c64045c3fuankg if (rv != APR_SUCCESS) {
553f11a8f542196fd02498006338dd33c64045c3fuankg ctx->errstr = apr_psprintf(ctx->pool, "Unable to encode with "
553f11a8f542196fd02498006338dd33c64045c3fuankg "bcrypt: %pm", &rv);
553f11a8f542196fd02498006338dd33c64045c3fuankg ret = ERR_PWMISMATCH;
553f11a8f542196fd02498006338dd33c64045c3fuankg break;
553f11a8f542196fd02498006338dd33c64045c3fuankg }
553f11a8f542196fd02498006338dd33c64045c3fuankg break;
553f11a8f542196fd02498006338dd33c64045c3fuankg#endif /* BCRYPT_ALGO_SUPPORTED */
553f11a8f542196fd02498006338dd33c64045c3fuankg
553f11a8f542196fd02498006338dd33c64045c3fuankg default:
553f11a8f542196fd02498006338dd33c64045c3fuankg ctx->errstr = apr_psprintf(ctx->pool,
e6c7108c75060e44f33554b268b528a26c9bb483fuankg "mk_password_hash(): unsupported algorithm %d",
553f11a8f542196fd02498006338dd33c64045c3fuankg ctx->alg);
e6c7108c75060e44f33554b268b528a26c9bb483fuankg ret = ERR_GENERAL;
553f11a8f542196fd02498006338dd33c64045c3fuankg }
553f11a8f542196fd02498006338dd33c64045c3fuankg memset(pw, '\0', strlen(pw));
553f11a8f542196fd02498006338dd33c64045c3fuankg return ret;
553f11a8f542196fd02498006338dd33c64045c3fuankg}
553f11a8f542196fd02498006338dd33c64045c3fuankg
553f11a8f542196fd02498006338dd33c64045c3fuankg