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