Groonga 3.0.9 Source Code Document
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
ngx_http_auth_basic_module.c
Go to the documentation of this file.
1 
2 /*
3  * Copyright (C) Igor Sysoev
4  * Copyright (C) Nginx, Inc.
5  */
6 
7 
8 #include <ngx_config.h>
9 #include <ngx_core.h>
10 #include <ngx_http.h>
11 #include <ngx_crypt.h>
12 
13 
14 #define NGX_HTTP_AUTH_BUF_SIZE 2048
15 
16 
17 typedef struct {
20 
21 
22 typedef struct {
26 
27 
28 static ngx_int_t ngx_http_auth_basic_handler(ngx_http_request_t *r);
29 static ngx_int_t ngx_http_auth_basic_crypt_handler(ngx_http_request_t *r,
30  ngx_http_auth_basic_ctx_t *ctx, ngx_str_t *passwd, ngx_str_t *realm);
31 static ngx_int_t ngx_http_auth_basic_set_realm(ngx_http_request_t *r,
32  ngx_str_t *realm);
33 static void ngx_http_auth_basic_close(ngx_file_t *file);
34 static void *ngx_http_auth_basic_create_loc_conf(ngx_conf_t *cf);
35 static char *ngx_http_auth_basic_merge_loc_conf(ngx_conf_t *cf,
36  void *parent, void *child);
37 static ngx_int_t ngx_http_auth_basic_init(ngx_conf_t *cf);
38 static char *ngx_http_auth_basic_user_file(ngx_conf_t *cf, ngx_command_t *cmd,
39  void *conf);
40 
41 
42 static ngx_command_t ngx_http_auth_basic_commands[] = {
43 
44  { ngx_string("auth_basic"),
49  offsetof(ngx_http_auth_basic_loc_conf_t, realm),
50  NULL },
51 
52  { ngx_string("auth_basic_user_file"),
55  ngx_http_auth_basic_user_file,
57  offsetof(ngx_http_auth_basic_loc_conf_t, user_file),
58  NULL },
59 
61 };
62 
63 
64 static ngx_http_module_t ngx_http_auth_basic_module_ctx = {
65  NULL, /* preconfiguration */
66  ngx_http_auth_basic_init, /* postconfiguration */
67 
68  NULL, /* create main configuration */
69  NULL, /* init main configuration */
70 
71  NULL, /* create server configuration */
72  NULL, /* merge server configuration */
73 
74  ngx_http_auth_basic_create_loc_conf, /* create location configuration */
75  ngx_http_auth_basic_merge_loc_conf /* merge location configuration */
76 };
77 
78 
81  &ngx_http_auth_basic_module_ctx, /* module context */
82  ngx_http_auth_basic_commands, /* module directives */
83  NGX_HTTP_MODULE, /* module type */
84  NULL, /* init master */
85  NULL, /* init module */
86  NULL, /* init process */
87  NULL, /* init thread */
88  NULL, /* exit thread */
89  NULL, /* exit process */
90  NULL, /* exit master */
92 };
93 
94 
95 static ngx_int_t
96 ngx_http_auth_basic_handler(ngx_http_request_t *r)
97 {
98  off_t offset;
99  ssize_t n;
100  ngx_fd_t fd;
101  ngx_int_t rc;
102  ngx_err_t err;
103  ngx_str_t pwd, realm, user_file;
104  ngx_uint_t i, level, login, left, passwd;
105  ngx_file_t file;
108  u_char buf[NGX_HTTP_AUTH_BUF_SIZE];
109  enum {
110  sw_login,
111  sw_passwd,
112  sw_skip
113  } state;
114 
115  alcf = ngx_http_get_module_loc_conf(r, ngx_http_auth_basic_module);
116 
117  if (alcf->realm == NULL || alcf->user_file.value.data == NULL) {
118  return NGX_DECLINED;
119  }
120 
121  if (ngx_http_complex_value(r, alcf->realm, &realm) != NGX_OK) {
122  return NGX_ERROR;
123  }
124 
125  if (realm.len == 3 && ngx_strncmp(realm.data, "off", 3) == 0) {
126  return NGX_DECLINED;
127  }
128 
129  ctx = ngx_http_get_module_ctx(r, ngx_http_auth_basic_module);
130 
131  if (ctx) {
132  return ngx_http_auth_basic_crypt_handler(r, ctx, &ctx->passwd,
133  &realm);
134  }
135 
136  rc = ngx_http_auth_basic_user(r);
137 
138  if (rc == NGX_DECLINED) {
139 
141  "no user/password was provided for basic authentication");
142 
143  return ngx_http_auth_basic_set_realm(r, &realm);
144  }
145 
146  if (rc == NGX_ERROR) {
148  }
149 
150  if (ngx_http_complex_value(r, &alcf->user_file, &user_file) != NGX_OK) {
151  return NGX_ERROR;
152  }
153 
154  fd = ngx_open_file(user_file.data, NGX_FILE_RDONLY, NGX_FILE_OPEN, 0);
155 
156  if (fd == NGX_INVALID_FILE) {
157  err = ngx_errno;
158 
159  if (err == NGX_ENOENT) {
160  level = NGX_LOG_ERR;
161  rc = NGX_HTTP_FORBIDDEN;
162 
163  } else {
164  level = NGX_LOG_CRIT;
166  }
167 
168  ngx_log_error(level, r->connection->log, err,
169  ngx_open_file_n " \"%s\" failed", user_file.data);
170 
171  return rc;
172  }
173 
174  ngx_memzero(&file, sizeof(ngx_file_t));
175 
176  file.fd = fd;
177  file.name = user_file;
178  file.log = r->connection->log;
179 
180  state = sw_login;
181  passwd = 0;
182  login = 0;
183  left = 0;
184  offset = 0;
185 
186  for ( ;; ) {
187  i = left;
188 
189  n = ngx_read_file(&file, buf + left, NGX_HTTP_AUTH_BUF_SIZE - left,
190  offset);
191 
192  if (n == NGX_ERROR) {
193  ngx_http_auth_basic_close(&file);
195  }
196 
197  if (n == 0) {
198  break;
199  }
200 
201  for (i = left; i < left + n; i++) {
202  switch (state) {
203 
204  case sw_login:
205  if (login == 0) {
206 
207  if (buf[i] == '#' || buf[i] == CR) {
208  state = sw_skip;
209  break;
210  }
211 
212  if (buf[i] == LF) {
213  break;
214  }
215  }
216 
217  if (buf[i] != r->headers_in.user.data[login]) {
218  state = sw_skip;
219  break;
220  }
221 
222  if (login == r->headers_in.user.len) {
223  state = sw_passwd;
224  passwd = i + 1;
225  }
226 
227  login++;
228 
229  break;
230 
231  case sw_passwd:
232  if (buf[i] == LF || buf[i] == CR || buf[i] == ':') {
233  buf[i] = '\0';
234 
235  ngx_http_auth_basic_close(&file);
236 
237  pwd.len = i - passwd;
238  pwd.data = &buf[passwd];
239 
240  return ngx_http_auth_basic_crypt_handler(r, NULL, &pwd,
241  &realm);
242  }
243 
244  break;
245 
246  case sw_skip:
247  if (buf[i] == LF) {
248  state = sw_login;
249  login = 0;
250  }
251 
252  break;
253  }
254  }
255 
256  if (state == sw_passwd) {
257  left = left + n - passwd;
258  ngx_memmove(buf, &buf[passwd], left);
259  passwd = 0;
260 
261  } else {
262  left = 0;
263  }
264 
265  offset += n;
266  }
267 
268  ngx_http_auth_basic_close(&file);
269 
270  if (state == sw_passwd) {
271  pwd.len = i - passwd;
272  pwd.data = ngx_pnalloc(r->pool, pwd.len + 1);
273  if (pwd.data == NULL) {
275  }
276 
277  ngx_cpystrn(pwd.data, &buf[passwd], pwd.len + 1);
278 
279  return ngx_http_auth_basic_crypt_handler(r, NULL, &pwd, &realm);
280  }
281 
283  "user \"%V\" was not found in \"%V\"",
284  &r->headers_in.user, &user_file);
285 
286  return ngx_http_auth_basic_set_realm(r, &realm);
287 }
288 
289 
290 static ngx_int_t
291 ngx_http_auth_basic_crypt_handler(ngx_http_request_t *r,
292  ngx_http_auth_basic_ctx_t *ctx, ngx_str_t *passwd, ngx_str_t *realm)
293 {
294  ngx_int_t rc;
295  u_char *encrypted;
296 
297  rc = ngx_crypt(r->pool, r->headers_in.passwd.data, passwd->data,
298  &encrypted);
299 
301  "rc: %d user: \"%V\" salt: \"%s\"",
302  rc, &r->headers_in.user, passwd->data);
303 
304  if (rc == NGX_OK) {
305  if (ngx_strcmp(encrypted, passwd->data) == 0) {
306  return NGX_OK;
307  }
308 
310  "encrypted: \"%s\"", encrypted);
311 
313  "user \"%V\": password mismatch",
314  &r->headers_in.user);
315 
316  return ngx_http_auth_basic_set_realm(r, realm);
317  }
318 
319  if (rc == NGX_ERROR) {
321  }
322 
323  /* rc == NGX_AGAIN */
324 
325  if (ctx == NULL) {
326  ctx = ngx_palloc(r->pool, sizeof(ngx_http_auth_basic_ctx_t));
327  if (ctx == NULL) {
329  }
330 
331  ngx_http_set_ctx(r, ctx, ngx_http_auth_basic_module);
332 
333  ctx->passwd.len = passwd->len;
334  passwd->len++;
335 
336  ctx->passwd.data = ngx_pstrdup(r->pool, passwd);
337  if (ctx->passwd.data == NULL) {
339  }
340 
341  }
342 
343  /* TODO: add mutex event */
344 
345  return rc;
346 }
347 
348 
349 static ngx_int_t
350 ngx_http_auth_basic_set_realm(ngx_http_request_t *r, ngx_str_t *realm)
351 {
352  size_t len;
353  u_char *basic, *p;
354 
356  if (r->headers_out.www_authenticate == NULL) {
358  }
359 
360  len = sizeof("Basic realm=\"\"") - 1 + realm->len;
361 
362  basic = ngx_pnalloc(r->pool, len);
363  if (basic == NULL) {
365  }
366 
367  p = ngx_cpymem(basic, "Basic realm=\"", sizeof("Basic realm=\"") - 1);
368  p = ngx_cpymem(p, realm->data, realm->len);
369  *p = '"';
370 
372  ngx_str_set(&r->headers_out.www_authenticate->key, "WWW-Authenticate");
375 
376  return NGX_HTTP_UNAUTHORIZED;
377 }
378 
379 static void
380 ngx_http_auth_basic_close(ngx_file_t *file)
381 {
382  if (ngx_close_file(file->fd) == NGX_FILE_ERROR) {
384  ngx_close_file_n " \"%s\" failed", file->name.data);
385  }
386 }
387 
388 
389 static void *
390 ngx_http_auth_basic_create_loc_conf(ngx_conf_t *cf)
391 {
393 
394  conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_auth_basic_loc_conf_t));
395  if (conf == NULL) {
396  return NULL;
397  }
398 
399  return conf;
400 }
401 
402 
403 static char *
404 ngx_http_auth_basic_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
405 {
406  ngx_http_auth_basic_loc_conf_t *prev = parent;
407  ngx_http_auth_basic_loc_conf_t *conf = child;
408 
409  if (conf->realm == NULL) {
410  conf->realm = prev->realm;
411  }
412 
413  if (conf->user_file.value.data == NULL) {
414  conf->user_file = prev->user_file;
415  }
416 
417  return NGX_CONF_OK;
418 }
419 
420 
421 static ngx_int_t
422 ngx_http_auth_basic_init(ngx_conf_t *cf)
423 {
426 
428 
430  if (h == NULL) {
431  return NGX_ERROR;
432  }
433 
434  *h = ngx_http_auth_basic_handler;
435 
436  return NGX_OK;
437 }
438 
439 
440 static char *
441 ngx_http_auth_basic_user_file(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
442 {
443  ngx_http_auth_basic_loc_conf_t *alcf = conf;
444 
445  ngx_str_t *value;
447 
448  if (alcf->user_file.value.data) {
449  return "is duplicate";
450  }
451 
452  value = cf->args->elts;
453 
455 
456  ccv.cf = cf;
457  ccv.value = &value[1];
458  ccv.complex_value = &alcf->user_file;
459  ccv.zero = 1;
460  ccv.conf_prefix = 1;
461 
462  if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
463  return NGX_CONF_ERROR;
464  }
465 
466  return NGX_CONF_OK;
467 }