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