Back to home page

Nginx displayed by LXR

Source navigation ]
Diff markup ]
Identifier search ]
general search ]
 
 
Version: nginx-1.13.12 ]​[ nginx-1.12.2 ]​

0001 
0002 /*
0003  * Copyright (C) Igor Sysoev
0004  * Copyright (C) Nginx, Inc.
0005  */
0006 
0007 
0008 #include <ngx_config.h>
0009 #include <ngx_core.h>
0010 #include <ngx_http.h>
0011 #include <ngx_crypt.h>
0012 
0013 
0014 #define NGX_HTTP_AUTH_BUF_SIZE  2048
0015 
0016 
0017 typedef struct {
0018     ngx_http_complex_value_t  *realm;
0019     ngx_http_complex_value_t   user_file;
0020 } ngx_http_auth_basic_loc_conf_t;
0021 
0022 
0023 static ngx_int_t ngx_http_auth_basic_handler(ngx_http_request_t *r);
0024 static ngx_int_t ngx_http_auth_basic_crypt_handler(ngx_http_request_t *r,
0025     ngx_str_t *passwd, ngx_str_t *realm);
0026 static ngx_int_t ngx_http_auth_basic_set_realm(ngx_http_request_t *r,
0027     ngx_str_t *realm);
0028 static void ngx_http_auth_basic_close(ngx_file_t *file);
0029 static void *ngx_http_auth_basic_create_loc_conf(ngx_conf_t *cf);
0030 static char *ngx_http_auth_basic_merge_loc_conf(ngx_conf_t *cf,
0031     void *parent, void *child);
0032 static ngx_int_t ngx_http_auth_basic_init(ngx_conf_t *cf);
0033 static char *ngx_http_auth_basic_user_file(ngx_conf_t *cf, ngx_command_t *cmd,
0034     void *conf);
0035 
0036 
0037 static ngx_command_t  ngx_http_auth_basic_commands[] = {
0038 
0039     { ngx_string("auth_basic"),
0040       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LMT_CONF
0041                         |NGX_CONF_TAKE1,
0042       ngx_http_set_complex_value_slot,
0043       NGX_HTTP_LOC_CONF_OFFSET,
0044       offsetof(ngx_http_auth_basic_loc_conf_t, realm),
0045       NULL },
0046 
0047     { ngx_string("auth_basic_user_file"),
0048       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LMT_CONF
0049                         |NGX_CONF_TAKE1,
0050       ngx_http_auth_basic_user_file,
0051       NGX_HTTP_LOC_CONF_OFFSET,
0052       offsetof(ngx_http_auth_basic_loc_conf_t, user_file),
0053       NULL },
0054 
0055       ngx_null_command
0056 };
0057 
0058 
0059 static ngx_http_module_t  ngx_http_auth_basic_module_ctx = {
0060     NULL,                                  /* preconfiguration */
0061     ngx_http_auth_basic_init,              /* postconfiguration */
0062 
0063     NULL,                                  /* create main configuration */
0064     NULL,                                  /* init main configuration */
0065 
0066     NULL,                                  /* create server configuration */
0067     NULL,                                  /* merge server configuration */
0068 
0069     ngx_http_auth_basic_create_loc_conf,   /* create location configuration */
0070     ngx_http_auth_basic_merge_loc_conf     /* merge location configuration */
0071 };
0072 
0073 
0074 ngx_module_t  ngx_http_auth_basic_module = {
0075     NGX_MODULE_V1,
0076     &ngx_http_auth_basic_module_ctx,       /* module context */
0077     ngx_http_auth_basic_commands,          /* module directives */
0078     NGX_HTTP_MODULE,                       /* module type */
0079     NULL,                                  /* init master */
0080     NULL,                                  /* init module */
0081     NULL,                                  /* init process */
0082     NULL,                                  /* init thread */
0083     NULL,                                  /* exit thread */
0084     NULL,                                  /* exit process */
0085     NULL,                                  /* exit master */
0086     NGX_MODULE_V1_PADDING
0087 };
0088 
0089 
0090 static ngx_int_t
0091 ngx_http_auth_basic_handler(ngx_http_request_t *r)
0092 {
0093     off_t                            offset;
0094     ssize_t                          n;
0095     ngx_fd_t                         fd;
0096     ngx_int_t                        rc;
0097     ngx_err_t                        err;
0098     ngx_str_t                        pwd, realm, user_file;
0099     ngx_uint_t                       i, level, login, left, passwd;
0100     ngx_file_t                       file;
0101     ngx_http_auth_basic_loc_conf_t  *alcf;
0102     u_char                           buf[NGX_HTTP_AUTH_BUF_SIZE];
0103     enum {
0104         sw_login,
0105         sw_passwd,
0106         sw_skip
0107     } state;
0108 
0109     alcf = ngx_http_get_module_loc_conf(r, ngx_http_auth_basic_module);
0110 
0111     if (alcf->realm == NULL || alcf->user_file.value.data == NULL) {
0112         return NGX_DECLINED;
0113     }
0114 
0115     if (ngx_http_complex_value(r, alcf->realm, &realm) != NGX_OK) {
0116         return NGX_ERROR;
0117     }
0118 
0119     if (realm.len == 3 && ngx_strncmp(realm.data, "off", 3) == 0) {
0120         return NGX_DECLINED;
0121     }
0122 
0123     rc = ngx_http_auth_basic_user(r);
0124 
0125     if (rc == NGX_DECLINED) {
0126 
0127         ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
0128                       "no user/password was provided for basic authentication");
0129 
0130         return ngx_http_auth_basic_set_realm(r, &realm);
0131     }
0132 
0133     if (rc == NGX_ERROR) {
0134         return NGX_HTTP_INTERNAL_SERVER_ERROR;
0135     }
0136 
0137     if (ngx_http_complex_value(r, &alcf->user_file, &user_file) != NGX_OK) {
0138         return NGX_ERROR;
0139     }
0140 
0141     fd = ngx_open_file(user_file.data, NGX_FILE_RDONLY, NGX_FILE_OPEN, 0);
0142 
0143     if (fd == NGX_INVALID_FILE) {
0144         err = ngx_errno;
0145 
0146         if (err == NGX_ENOENT) {
0147             level = NGX_LOG_ERR;
0148             rc = NGX_HTTP_FORBIDDEN;
0149 
0150         } else {
0151             level = NGX_LOG_CRIT;
0152             rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
0153         }
0154 
0155         ngx_log_error(level, r->connection->log, err,
0156                       ngx_open_file_n " \"%s\" failed", user_file.data);
0157 
0158         return rc;
0159     }
0160 
0161     ngx_memzero(&file, sizeof(ngx_file_t));
0162 
0163     file.fd = fd;
0164     file.name = user_file;
0165     file.log = r->connection->log;
0166 
0167     state = sw_login;
0168     passwd = 0;
0169     login = 0;
0170     left = 0;
0171     offset = 0;
0172 
0173     for ( ;; ) {
0174         i = left;
0175 
0176         n = ngx_read_file(&file, buf + left, NGX_HTTP_AUTH_BUF_SIZE - left,
0177                           offset);
0178 
0179         if (n == NGX_ERROR) {
0180             ngx_http_auth_basic_close(&file);
0181             return NGX_HTTP_INTERNAL_SERVER_ERROR;
0182         }
0183 
0184         if (n == 0) {
0185             break;
0186         }
0187 
0188         for (i = left; i < left + n; i++) {
0189             switch (state) {
0190 
0191             case sw_login:
0192                 if (login == 0) {
0193 
0194                     if (buf[i] == '#' || buf[i] == CR) {
0195                         state = sw_skip;
0196                         break;
0197                     }
0198 
0199                     if (buf[i] == LF) {
0200                         break;
0201                     }
0202                 }
0203 
0204                 if (buf[i] != r->headers_in.user.data[login]) {
0205                     state = sw_skip;
0206                     break;
0207                 }
0208 
0209                 if (login == r->headers_in.user.len) {
0210                     state = sw_passwd;
0211                     passwd = i + 1;
0212                 }
0213 
0214                 login++;
0215 
0216                 break;
0217 
0218             case sw_passwd:
0219                 if (buf[i] == LF || buf[i] == CR || buf[i] == ':') {
0220                     buf[i] = '\0';
0221 
0222                     ngx_http_auth_basic_close(&file);
0223 
0224                     pwd.len = i - passwd;
0225                     pwd.data = &buf[passwd];
0226 
0227                     return ngx_http_auth_basic_crypt_handler(r, &pwd, &realm);
0228                 }
0229 
0230                 break;
0231 
0232             case sw_skip:
0233                 if (buf[i] == LF) {
0234                     state = sw_login;
0235                     login = 0;
0236                 }
0237 
0238                 break;
0239             }
0240         }
0241 
0242         if (state == sw_passwd) {
0243             left = left + n - passwd;
0244             ngx_memmove(buf, &buf[passwd], left);
0245             passwd = 0;
0246 
0247         } else {
0248             left = 0;
0249         }
0250 
0251         offset += n;
0252     }
0253 
0254     ngx_http_auth_basic_close(&file);
0255 
0256     if (state == sw_passwd) {
0257         pwd.len = i - passwd;
0258         pwd.data = ngx_pnalloc(r->pool, pwd.len + 1);
0259         if (pwd.data == NULL) {
0260             return NGX_HTTP_INTERNAL_SERVER_ERROR;
0261         }
0262 
0263         ngx_cpystrn(pwd.data, &buf[passwd], pwd.len + 1);
0264 
0265         return ngx_http_auth_basic_crypt_handler(r, &pwd, &realm);
0266     }
0267 
0268     ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
0269                   "user \"%V\" was not found in \"%s\"",
0270                   &r->headers_in.user, user_file.data);
0271 
0272     return ngx_http_auth_basic_set_realm(r, &realm);
0273 }
0274 
0275 
0276 static ngx_int_t
0277 ngx_http_auth_basic_crypt_handler(ngx_http_request_t *r, ngx_str_t *passwd,
0278     ngx_str_t *realm)
0279 {
0280     ngx_int_t   rc;
0281     u_char     *encrypted;
0282 
0283     rc = ngx_crypt(r->pool, r->headers_in.passwd.data, passwd->data,
0284                    &encrypted);
0285 
0286     ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
0287                    "rc: %i user: \"%V\" salt: \"%s\"",
0288                    rc, &r->headers_in.user, passwd->data);
0289 
0290     if (rc != NGX_OK) {
0291         return NGX_HTTP_INTERNAL_SERVER_ERROR;
0292     }
0293 
0294     if (ngx_strcmp(encrypted, passwd->data) == 0) {
0295         return NGX_OK;
0296     }
0297 
0298     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
0299                    "encrypted: \"%s\"", encrypted);
0300 
0301     ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
0302                   "user \"%V\": password mismatch",
0303                   &r->headers_in.user);
0304 
0305     return ngx_http_auth_basic_set_realm(r, realm);
0306 }
0307 
0308 
0309 static ngx_int_t
0310 ngx_http_auth_basic_set_realm(ngx_http_request_t *r, ngx_str_t *realm)
0311 {
0312     size_t   len;
0313     u_char  *basic, *p;
0314 
0315     r->headers_out.www_authenticate = ngx_list_push(&r->headers_out.headers);
0316     if (r->headers_out.www_authenticate == NULL) {
0317         return NGX_HTTP_INTERNAL_SERVER_ERROR;
0318     }
0319 
0320     len = sizeof("Basic realm=\"\"") - 1 + realm->len;
0321 
0322     basic = ngx_pnalloc(r->pool, len);
0323     if (basic == NULL) {
0324         r->headers_out.www_authenticate->hash = 0;
0325         r->headers_out.www_authenticate = NULL;
0326         return NGX_HTTP_INTERNAL_SERVER_ERROR;
0327     }
0328 
0329     p = ngx_cpymem(basic, "Basic realm=\"", sizeof("Basic realm=\"") - 1);
0330     p = ngx_cpymem(p, realm->data, realm->len);
0331     *p = '"';
0332 
0333     r->headers_out.www_authenticate->hash = 1;
0334     ngx_str_set(&r->headers_out.www_authenticate->key, "WWW-Authenticate");
0335     r->headers_out.www_authenticate->value.data = basic;
0336     r->headers_out.www_authenticate->value.len = len;
0337 
0338     return NGX_HTTP_UNAUTHORIZED;
0339 }
0340 
0341 static void
0342 ngx_http_auth_basic_close(ngx_file_t *file)
0343 {
0344     if (ngx_close_file(file->fd) == NGX_FILE_ERROR) {
0345         ngx_log_error(NGX_LOG_ALERT, file->log, ngx_errno,
0346                       ngx_close_file_n " \"%s\" failed", file->name.data);
0347     }
0348 }
0349 
0350 
0351 static void *
0352 ngx_http_auth_basic_create_loc_conf(ngx_conf_t *cf)
0353 {
0354     ngx_http_auth_basic_loc_conf_t  *conf;
0355 
0356     conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_auth_basic_loc_conf_t));
0357     if (conf == NULL) {
0358         return NULL;
0359     }
0360 
0361     return conf;
0362 }
0363 
0364 
0365 static char *
0366 ngx_http_auth_basic_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
0367 {
0368     ngx_http_auth_basic_loc_conf_t  *prev = parent;
0369     ngx_http_auth_basic_loc_conf_t  *conf = child;
0370 
0371     if (conf->realm == NULL) {
0372         conf->realm = prev->realm;
0373     }
0374 
0375     if (conf->user_file.value.data == NULL) {
0376         conf->user_file = prev->user_file;
0377     }
0378 
0379     return NGX_CONF_OK;
0380 }
0381 
0382 
0383 static ngx_int_t
0384 ngx_http_auth_basic_init(ngx_conf_t *cf)
0385 {
0386     ngx_http_handler_pt        *h;
0387     ngx_http_core_main_conf_t  *cmcf;
0388 
0389     cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);
0390 
0391     h = ngx_array_push(&cmcf->phases[NGX_HTTP_ACCESS_PHASE].handlers);
0392     if (h == NULL) {
0393         return NGX_ERROR;
0394     }
0395 
0396     *h = ngx_http_auth_basic_handler;
0397 
0398     return NGX_OK;
0399 }
0400 
0401 
0402 static char *
0403 ngx_http_auth_basic_user_file(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
0404 {
0405     ngx_http_auth_basic_loc_conf_t *alcf = conf;
0406 
0407     ngx_str_t                         *value;
0408     ngx_http_compile_complex_value_t   ccv;
0409 
0410     if (alcf->user_file.value.data) {
0411         return "is duplicate";
0412     }
0413 
0414     value = cf->args->elts;
0415 
0416     ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
0417 
0418     ccv.cf = cf;
0419     ccv.value = &value[1];
0420     ccv.complex_value = &alcf->user_file;
0421     ccv.zero = 1;
0422     ccv.conf_prefix = 1;
0423 
0424     if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
0425         return NGX_CONF_ERROR;
0426     }
0427 
0428     return NGX_CONF_OK;
0429 }