]> granicus.if.org Git - apache/blob - modules/lua/lua_passwd.c
Enable to build mod_lua against Lua 5.3.
[apache] / modules / lua / lua_passwd.c
1 /* Licensed to the Apache Software Foundation (ASF) under one or more
2  * contributor license agreements.  See the NOTICE file distributed with
3  * this work for additional information regarding copyright ownership.
4  * The ASF licenses this file to You under the Apache License, Version 2.0
5  * (the "License"); you may not use this file except in compliance with
6  * the License.  You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include "lua_passwd.h"
18 #include "apr_strings.h"
19 #include "apr_errno.h"
20
21 #if APR_HAVE_STDIO_H
22 #include <stdio.h>
23 #endif
24
25 #include "apr_md5.h"
26 #include "apr_sha1.h"
27
28 #if APR_HAVE_TIME_H
29 #include <time.h>
30 #endif
31 #if APR_HAVE_CRYPT_H
32 #include <crypt.h>
33 #endif
34 #if APR_HAVE_STDLIB_H
35 #include <stdlib.h>
36 #endif
37 #if APR_HAVE_STRING_H
38 #include <string.h>
39 #endif
40 #if APR_HAVE_UNISTD_H
41 #include <unistd.h>
42 #endif
43 #if APR_HAVE_IO_H
44 #include <io.h>
45 #endif
46
47 static int generate_salt(char *s, size_t size, const char **errstr,
48                          apr_pool_t *pool)
49 {
50     unsigned char rnd[32];
51     static const char itoa64[] =
52         "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
53     apr_size_t n;
54     unsigned int val = 0, bits = 0;
55     apr_status_t rv;
56
57     n = (size * 6 + 7)/8;
58     if (n > sizeof(rnd)) {
59         *errstr = apr_psprintf(pool, "generate_salt(): BUG: Buffer too small");
60         return ERR_RANDOM;
61     }
62     rv = apr_generate_random_bytes(rnd, n);
63     if (rv) {
64         *errstr = apr_psprintf(pool, "Unable to generate random bytes: %pm",
65                                &rv);
66         return ERR_RANDOM;
67     }
68     n = 0;
69     while (size > 0) {
70         if (bits < 6) {
71             val |= (rnd[n++] << bits);
72             bits += 8;
73         }
74         *s++ = itoa64[val & 0x3f];
75         size--;
76         val >>= 6;
77         bits -= 6;
78    }
79    *s = '\0';
80    return 0;
81 }
82
83 /*
84  * Make a password record from the given information.  A zero return
85  * indicates success; on failure, ctx->errstr points to the error message.
86  */
87 int mk_password_hash(passwd_ctx *ctx)
88 {
89     char *pw;
90     char salt[16];
91     apr_status_t rv;
92     int ret = 0;
93 #if CRYPT_ALGO_SUPPORTED
94     char *cbuf;
95 #endif
96
97     pw = ctx->passwd;
98     switch (ctx->alg) {
99     case ALG_APSHA:
100         /* XXX out >= 28 + strlen(sha1) chars - fixed len SHA */
101         apr_sha1_base64(pw, strlen(pw), ctx->out);
102         break;
103
104     case ALG_APMD5:
105         ret = generate_salt(salt, 8, &ctx->errstr, ctx->pool);
106         if (ret != 0) {
107             ret = ERR_GENERAL;
108             break;
109         }
110         rv = apr_md5_encode(pw, salt, ctx->out, ctx->out_len);
111         if (rv != APR_SUCCESS) {
112             ctx->errstr = apr_psprintf(ctx->pool,
113                                        "could not encode password: %pm", &rv);
114             ret = ERR_GENERAL;
115         }
116         break;
117
118 #if CRYPT_ALGO_SUPPORTED
119     case ALG_CRYPT:
120         ret = generate_salt(salt, 8, &ctx->errstr, ctx->pool);
121         if (ret != 0)
122             break;
123         cbuf = crypt(pw, salt);
124         if (cbuf == NULL) {
125             rv = APR_FROM_OS_ERROR(errno);
126             ctx->errstr = apr_psprintf(ctx->pool, "crypt() failed: %pm", &rv);
127             ret = ERR_PWMISMATCH;
128             break;
129         }
130
131         apr_cpystrn(ctx->out, cbuf, ctx->out_len - 1);
132         if (strlen(pw) > 8) {
133             char *truncpw = apr_pstrdup(ctx->pool, pw);
134             truncpw[8] = '\0';
135             if (!strcmp(ctx->out, crypt(truncpw, salt))) {
136                 ctx->errstr = apr_psprintf(ctx->pool,
137                                            "Warning: Password truncated to 8 "
138                                            "characters by CRYPT algorithm.");
139             }
140             memset(truncpw, '\0', strlen(pw));
141         }
142         break;
143 #endif /* CRYPT_ALGO_SUPPORTED */
144
145 #if BCRYPT_ALGO_SUPPORTED
146     case ALG_BCRYPT:
147         rv = apr_generate_random_bytes((unsigned char*)salt, 16);
148         if (rv != APR_SUCCESS) {
149             ctx->errstr = apr_psprintf(ctx->pool, "Unable to generate random "
150                                        "bytes: %pm", &rv);
151             ret = ERR_RANDOM;
152             break;
153         }
154
155         if (ctx->cost == 0)
156             ctx->cost = BCRYPT_DEFAULT_COST;
157         rv = apr_bcrypt_encode(pw, ctx->cost, (unsigned char*)salt, 16,
158                                ctx->out, ctx->out_len);
159         if (rv != APR_SUCCESS) {
160             ctx->errstr = apr_psprintf(ctx->pool, "Unable to encode with "
161                                        "bcrypt: %pm", &rv);
162             ret = ERR_PWMISMATCH;
163             break;
164         }
165         break;
166 #endif /* BCRYPT_ALGO_SUPPORTED */
167
168     default:
169         ctx->errstr = apr_psprintf(ctx->pool,
170                                   "mk_password_hash(): unsupported algorithm %d",
171                                   ctx->alg);
172         ret = ERR_GENERAL;
173     }
174     memset(pw, '\0', strlen(pw));
175     return ret;
176 }
177
178