~ubuntu-branches/ubuntu/gutsy/nginx/gutsy

« back to all changes in this revision

Viewing changes to src/http/modules/ngx_http_auth_basic_module.c

  • Committer: Bazaar Package Importer
  • Author(s): Jose Parrella
  • Date: 2006-11-12 18:31:24 UTC
  • Revision ID: james.westby@ubuntu.com-20061112183124-xmd3o5aulb1qqyjl
Tags: upstream-0.4.12
ImportĀ upstreamĀ versionĀ 0.4.12

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
 
 
2
/*
 
3
 * Copyright (C) Igor Sysoev
 
4
 */
 
5
 
 
6
 
 
7
#include <ngx_config.h>
 
8
#include <ngx_core.h>
 
9
#include <ngx_http.h>
 
10
 
 
11
 
 
12
#define NGX_HTTP_AUTH_BUF_SIZE  2048
 
13
 
 
14
 
 
15
typedef struct {
 
16
    ngx_str_t  passwd;
 
17
} ngx_http_auth_basic_ctx_t;
 
18
 
 
19
 
 
20
typedef struct {
 
21
    ngx_str_t  realm;
 
22
    ngx_str_t  user_file;
 
23
} ngx_http_auth_basic_loc_conf_t;
 
24
 
 
25
 
 
26
static ngx_int_t ngx_http_auth_basic_handler(ngx_http_request_t *r);
 
27
static ngx_int_t ngx_http_auth_basic_crypt_handler(ngx_http_request_t *r,
 
28
    ngx_http_auth_basic_ctx_t *ctx, ngx_str_t *passwd, ngx_str_t *realm);
 
29
static ngx_int_t ngx_http_auth_basic_set_realm(ngx_http_request_t *r,
 
30
    ngx_str_t *realm);
 
31
static void ngx_http_auth_basic_close(ngx_file_t *file);
 
32
static void *ngx_http_auth_basic_create_loc_conf(ngx_conf_t *cf);
 
33
static char *ngx_http_auth_basic_merge_loc_conf(ngx_conf_t *cf,
 
34
    void *parent, void *child);
 
35
static ngx_int_t ngx_http_auth_basic_init(ngx_conf_t *cf);
 
36
static char *ngx_http_auth_basic(ngx_conf_t *cf, void *post, void *data);
 
37
 
 
38
 
 
39
static ngx_conf_post_handler_pt  ngx_http_auth_basic_p = ngx_http_auth_basic;
 
40
 
 
41
static ngx_command_t  ngx_http_auth_basic_commands[] = {
 
42
 
 
43
    { ngx_string("auth_basic"),
 
44
      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LMT_CONF
 
45
                        |NGX_CONF_TAKE1,
 
46
      ngx_conf_set_str_slot,
 
47
      NGX_HTTP_LOC_CONF_OFFSET,
 
48
      offsetof(ngx_http_auth_basic_loc_conf_t, realm),
 
49
      &ngx_http_auth_basic_p },
 
50
 
 
51
    { ngx_string("auth_basic_user_file"),
 
52
      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LMT_CONF
 
53
                        |NGX_CONF_TAKE1,
 
54
      ngx_conf_set_str_slot,
 
55
      NGX_HTTP_LOC_CONF_OFFSET,
 
56
      offsetof(ngx_http_auth_basic_loc_conf_t, user_file),
 
57
      NULL },
 
58
 
 
59
      ngx_null_command
 
60
};
 
61
 
 
62
 
 
63
static ngx_http_module_t  ngx_http_auth_basic_module_ctx = {
 
64
    NULL,                                  /* preconfiguration */
 
65
    ngx_http_auth_basic_init,              /* postconfiguration */
 
66
 
 
67
    NULL,                                  /* create main configuration */
 
68
    NULL,                                  /* init main configuration */
 
69
 
 
70
    NULL,                                  /* create server configuration */
 
71
    NULL,                                  /* merge server configuration */
 
72
 
 
73
    ngx_http_auth_basic_create_loc_conf,   /* create location configuration */
 
74
    ngx_http_auth_basic_merge_loc_conf     /* merge location configuration */
 
75
};
 
76
 
 
77
 
 
78
ngx_module_t  ngx_http_auth_basic_module = {
 
79
    NGX_MODULE_V1,
 
80
    &ngx_http_auth_basic_module_ctx,       /* module context */
 
81
    ngx_http_auth_basic_commands,          /* module directives */
 
82
    NGX_HTTP_MODULE,                       /* module type */
 
83
    NULL,                                  /* init master */
 
84
    NULL,                                  /* init module */
 
85
    NULL,                                  /* init process */
 
86
    NULL,                                  /* init thread */
 
87
    NULL,                                  /* exit thread */
 
88
    NULL,                                  /* exit process */
 
89
    NULL,                                  /* exit master */
 
90
    NGX_MODULE_V1_PADDING
 
91
};
 
92
 
 
93
 
 
94
static ngx_int_t
 
95
ngx_http_auth_basic_handler(ngx_http_request_t *r)
 
96
{
 
97
    off_t                            offset;
 
98
    ssize_t                          n;
 
99
    ngx_fd_t                         fd;
 
100
    ngx_int_t                        rc;
 
101
    ngx_str_t                        pwd;
 
102
    ngx_uint_t                       i, login, left, passwd;
 
103
    ngx_file_t                       file;
 
104
    ngx_http_auth_basic_ctx_t       *ctx;
 
105
    ngx_http_auth_basic_loc_conf_t  *alcf;
 
106
    u_char                           buf[NGX_HTTP_AUTH_BUF_SIZE];
 
107
    enum {
 
108
        sw_login,
 
109
        sw_passwd,
 
110
        sw_skip
 
111
    } state;
 
112
 
 
113
    alcf = ngx_http_get_module_loc_conf(r, ngx_http_auth_basic_module);
 
114
 
 
115
    if (alcf->realm.len == 0 || alcf->user_file.len == 0) {
 
116
        return NGX_OK;
 
117
    }
 
118
 
 
119
    ctx = ngx_http_get_module_ctx(r, ngx_http_auth_basic_module);
 
120
 
 
121
    if (ctx) {
 
122
        return ngx_http_auth_basic_crypt_handler(r, ctx, &ctx->passwd,
 
123
                                                 &alcf->realm);
 
124
    }
 
125
 
 
126
    rc = ngx_http_auth_basic_user(r);
 
127
 
 
128
    if (rc == NGX_DECLINED) {
 
129
        return ngx_http_auth_basic_set_realm(r, &alcf->realm);
 
130
    }
 
131
 
 
132
    if (rc == NGX_ERROR) {
 
133
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
 
134
    }
 
135
 
 
136
    fd = ngx_open_file(alcf->user_file.data, NGX_FILE_RDONLY, NGX_FILE_OPEN);
 
137
 
 
138
    if (fd == NGX_INVALID_FILE) {
 
139
        ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno,
 
140
                      ngx_open_file_n " \"%s\" failed", alcf->user_file.data);
 
141
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
 
142
    }
 
143
 
 
144
    ngx_memzero(&file, sizeof(ngx_file_t));
 
145
 
 
146
    file.fd = fd;
 
147
    file.name = alcf->user_file;
 
148
    file.log = r->connection->log;
 
149
 
 
150
    state = sw_login;
 
151
    passwd = 0;
 
152
    login = 0;
 
153
    left = 0;
 
154
    offset = 0;
 
155
 
 
156
    for ( ;; ) {
 
157
        n = ngx_read_file(&file, buf + left, NGX_HTTP_AUTH_BUF_SIZE - left,
 
158
                          offset);
 
159
 
 
160
        if (n == NGX_ERROR) {
 
161
            ngx_http_auth_basic_close(&file);
 
162
            return NGX_HTTP_INTERNAL_SERVER_ERROR;
 
163
        }
 
164
 
 
165
        if (n == 0) {
 
166
            break;
 
167
        }
 
168
 
 
169
        for (i = left; i < left + n; i++) {
 
170
            switch (state) {
 
171
 
 
172
            case sw_login:
 
173
                if (login == 0 && buf[i] == '#') {
 
174
                    state = sw_skip;
 
175
                    break;
 
176
                }
 
177
 
 
178
                if (buf[i] != r->headers_in.user.data[login]) {
 
179
                    state = sw_skip;
 
180
                    break;
 
181
                }
 
182
 
 
183
                if (login == r->headers_in.user.len) {
 
184
                    state = sw_passwd;
 
185
                    passwd = i + 1;
 
186
                }
 
187
 
 
188
                login++;
 
189
 
 
190
                break;
 
191
 
 
192
            case sw_passwd:
 
193
                if (buf[i] == LF || buf[i] == CR || buf[i] == ':') {
 
194
                    buf[i] = '\0';
 
195
 
 
196
                    ngx_http_auth_basic_close(&file);
 
197
 
 
198
                    pwd.len = i - passwd;
 
199
                    pwd.data = &buf[passwd];
 
200
 
 
201
                    return ngx_http_auth_basic_crypt_handler(r, NULL, &pwd,
 
202
                                                             &alcf->realm);
 
203
                }
 
204
 
 
205
                break;
 
206
 
 
207
            case sw_skip:
 
208
                if (buf[i] == LF) {
 
209
                    state = sw_login;
 
210
                    login = 0;
 
211
                }
 
212
 
 
213
                break;
 
214
            }
 
215
        }
 
216
 
 
217
        if (state == sw_passwd) {
 
218
            left = left + n - passwd;
 
219
            ngx_memcpy(buf, &buf[passwd], left);
 
220
            passwd = 0;
 
221
 
 
222
        } else {
 
223
            left = 0;
 
224
        }
 
225
 
 
226
        offset += n;
 
227
    }
 
228
 
 
229
    ngx_http_auth_basic_close(&file);
 
230
 
 
231
    return ngx_http_auth_basic_set_realm(r, &alcf->realm);
 
232
}
 
233
 
 
234
 
 
235
static ngx_int_t
 
236
ngx_http_auth_basic_crypt_handler(ngx_http_request_t *r,
 
237
    ngx_http_auth_basic_ctx_t *ctx, ngx_str_t *passwd, ngx_str_t *realm)
 
238
{
 
239
    ngx_int_t   rc;
 
240
    u_char     *encrypted;
 
241
 
 
242
    rc = ngx_crypt(r->pool, r->headers_in.passwd.data, passwd->data,
 
243
                   &encrypted);
 
244
 
 
245
    ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
 
246
                  "rc: %d user: \"%V\" salt: \"%s\"",
 
247
                  rc, &r->headers_in.user, passwd->data);
 
248
 
 
249
    if (rc == NGX_OK) {
 
250
        if (ngx_strcmp(encrypted, passwd->data) == 0) {
 
251
            return NGX_OK;
 
252
        }
 
253
 
 
254
        ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
 
255
                       "encrypted: \"%s\"", encrypted);
 
256
 
 
257
        return ngx_http_auth_basic_set_realm(r, realm);
 
258
    }
 
259
 
 
260
    if (rc == NGX_ERROR) {
 
261
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
 
262
    }
 
263
 
 
264
    /* rc == NGX_AGAIN */
 
265
 
 
266
    if (ctx == NULL) {
 
267
        ctx = ngx_palloc(r->pool, sizeof(ngx_http_auth_basic_ctx_t));
 
268
        if (ctx == NULL) {
 
269
            return NGX_HTTP_INTERNAL_SERVER_ERROR;
 
270
        }
 
271
 
 
272
        ngx_http_set_ctx(r, ctx, ngx_http_auth_basic_module);
 
273
 
 
274
        ctx->passwd.len = passwd->len;
 
275
        passwd->len++;
 
276
 
 
277
        ctx->passwd.data = ngx_pstrdup(r->pool, passwd);
 
278
        if (ctx->passwd.data == NULL) {
 
279
            return NGX_HTTP_INTERNAL_SERVER_ERROR;
 
280
        }
 
281
 
 
282
    }
 
283
 
 
284
    /* TODO: add mutex event */
 
285
 
 
286
    return rc;
 
287
}
 
288
 
 
289
 
 
290
static ngx_int_t
 
291
ngx_http_auth_basic_set_realm(ngx_http_request_t *r, ngx_str_t *realm)
 
292
{
 
293
    r->headers_out.www_authenticate = ngx_list_push(&r->headers_out.headers);
 
294
    if (r->headers_out.www_authenticate == NULL) {
 
295
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
 
296
    }
 
297
 
 
298
    r->headers_out.www_authenticate->hash = 1;
 
299
    r->headers_out.www_authenticate->key.len = sizeof("WWW-Authenticate") - 1;
 
300
    r->headers_out.www_authenticate->key.data = (u_char *) "WWW-Authenticate";
 
301
    r->headers_out.www_authenticate->value = *realm;
 
302
 
 
303
    return NGX_HTTP_UNAUTHORIZED;
 
304
}
 
305
 
 
306
static void
 
307
ngx_http_auth_basic_close(ngx_file_t *file)
 
308
{
 
309
    if (ngx_close_file(file->fd) == NGX_FILE_ERROR) {
 
310
        ngx_log_error(NGX_LOG_ALERT, file->log, ngx_errno,
 
311
                      ngx_close_file_n " \"%s\" failed", file->name.data);
 
312
    }
 
313
}
 
314
 
 
315
 
 
316
static void *
 
317
ngx_http_auth_basic_create_loc_conf(ngx_conf_t *cf)
 
318
{
 
319
    ngx_http_auth_basic_loc_conf_t  *conf;
 
320
 
 
321
    conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_auth_basic_loc_conf_t));
 
322
    if (conf == NULL) {
 
323
        return NGX_CONF_ERROR;
 
324
    }
 
325
 
 
326
    return conf;
 
327
}
 
328
 
 
329
 
 
330
static char *
 
331
ngx_http_auth_basic_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
 
332
{
 
333
    ngx_http_auth_basic_loc_conf_t  *prev = parent;
 
334
    ngx_http_auth_basic_loc_conf_t  *conf = child;
 
335
 
 
336
    if (conf->realm.data == NULL) {
 
337
        conf->realm = prev->realm;
 
338
    }
 
339
 
 
340
    if (conf->user_file.data) {
 
341
        if (ngx_conf_full_name(cf->cycle, &conf->user_file) != NGX_OK) {
 
342
            return NGX_CONF_ERROR;
 
343
        }
 
344
 
 
345
    } else {
 
346
        conf->user_file = prev->user_file;
 
347
    }
 
348
 
 
349
    return NGX_CONF_OK;
 
350
}
 
351
 
 
352
 
 
353
static ngx_int_t
 
354
ngx_http_auth_basic_init(ngx_conf_t *cf)
 
355
{
 
356
    ngx_http_handler_pt        *h;
 
357
    ngx_http_core_main_conf_t  *cmcf;
 
358
 
 
359
    cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);
 
360
 
 
361
    h = ngx_array_push(&cmcf->phases[NGX_HTTP_ACCESS_PHASE].handlers);
 
362
    if (h == NULL) {
 
363
        return NGX_ERROR;
 
364
    }
 
365
 
 
366
    *h = ngx_http_auth_basic_handler;
 
367
 
 
368
    return NGX_OK;
 
369
}
 
370
 
 
371
 
 
372
static char *
 
373
ngx_http_auth_basic(ngx_conf_t *cf, void *post, void *data)
 
374
{
 
375
    ngx_str_t  *realm = data;
 
376
 
 
377
    size_t   len;
 
378
    u_char  *basic, *p;
 
379
 
 
380
    if (ngx_strcmp(realm->data, "off") == 0) {
 
381
        realm->len = 0;
 
382
        realm->data = (u_char *) "";
 
383
 
 
384
        return NGX_CONF_OK;
 
385
    }
 
386
 
 
387
    len = sizeof("Basic realm=\"") - 1 + realm->len + 1;
 
388
 
 
389
    basic = ngx_palloc(cf->pool, len);
 
390
    if (basic == NULL) {
 
391
        return NGX_CONF_ERROR;
 
392
    }
 
393
 
 
394
    p = ngx_cpymem(basic, "Basic realm=\"", sizeof("Basic realm=\"") - 1);
 
395
    p = ngx_cpymem(p, realm->data, realm->len);
 
396
    *p = '"';
 
397
 
 
398
    realm->len = len;
 
399
    realm->data = basic;
 
400
 
 
401
    return NGX_CONF_OK;
 
402
}