os/unix/ngx_user.c(h)源代码分析
本节我们主要讲述一下Linux中自带的crypt()函数,nginx采用该函数来实现自己的加密函数。
1. crypt()函数介绍
#define _XOPEN_SOURCE /* See feature_test_macros(7) */
#include <unistd.h>
char *crypt(const char *key, const char *salt);
#define _GNU_SOURCE /* See feature_test_macros(7) */
#include <crypt.h>
char *crypt_r(const char *key, const char *salt,
struct crypt_data *data);
Link with -lcrypt.
crypt()函数是一个密码加密函数。它是基于DES加密算法的一种变体来实现加密的。加密后返回一个具有13个可打印字符的字符串。
参数key
为用户输入的明文密码(最多只会处理前8个字节。如果超出部分被忽略)
参数salt
是一个两个字节的字串(字符取自[a-zA-Z0-9./],长度超过2的部分被忽略),用于扰乱该加密算法。
crypt_r()
函数是crypt()函数的可重入版本,参数crypt_data只是用于存储加密后的数据,其内部并不会分配空间。在调用前,需要将crypt_data->initialized置为0.
返回值: 函数成功时返回加密后的字符串;否则返回NULL,并设置相应的错误码
注意: 一般启用_GNU_SOURCE后,就自动的启用了_XOPEN_SOURCE,因此我们可以看到,在程序中我们并没有再去显示的开启_XOPEN_SOURCE 这个宏定义。
参看如下示例test2.c:
#define _GNU_SOURCE
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<string.h>
#include<errno.h>
int main(int argc, char *argv[])
{
if(argc != 3)
{
fprintf(stderr, "%s salt key\n", argv[0]);
return 1;
}
char *encrypted = NULL;
if((encrypted = crypt(argv[2], argv[1])) == NULL)
{
fprintf(stderr, "crypt error:%s\n", strerror(errno));
}
printf("%s encrypted:%s\n", argv[2], encrypted);
return 0;
}
编译运行:
# gcc -o test2 test2.c -lcrypt # ./test2 aa world66677 world66677 encrypted:aaElDg5KDwBQg # ./test2 aa world66688 world66688 encrypted:aaElDg5KDwBQg # ./test2 aabb world66688 world66688 encrypted:aaElDg5KDwBQg # ./test2 "\$6\$y9cP0qlmDYgBk6OZ\$" world6666 //这里也支持其他算法,请参看相应文档(这里反斜杠为转义作用) world6666 encrypted:$6$y9cP0qlmDYgBk6OZ$9Jnxb/9sqKnr4hofUO1y0T4ireWiQPuj37QYjEahjn1oRIAkWUNcuTBnipQNF6.O5U1YPMmS.1FqA7JphoEnY0
2. os/unix/ngx_user.h头文件
/*
* Copyright (C) Igor Sysoev
* Copyright (C) Nginx, Inc.
*/
#ifndef _NGX_USER_H_INCLUDED_
#define _NGX_USER_H_INCLUDED_
#include <ngx_config.h>
#include <ngx_core.h>
typedef uid_t ngx_uid_t;
typedef gid_t ngx_gid_t;
ngx_int_t ngx_libc_crypt(ngx_pool_t *pool, u_char *key, u_char *salt,
u_char **encrypted);
#endif /* _NGX_USER_H_INCLUDED_ */
这里只是声明ngx_libc_crypt()函数。
3. os/unix/ngx_user.c源文件
/*
* Copyright (C) Igor Sysoev
* Copyright (C) Nginx, Inc.
*/
#include <ngx_config.h>
#include <ngx_core.h>
/*
* Solaris has thread-safe crypt()
* Linux has crypt_r(); "struct crypt_data" is more than 128K
* FreeBSD needs the mutex to protect crypt()
*
* TODO:
* ngx_crypt_init() to init mutex
*/
#if (NGX_CRYPT)
#if (NGX_HAVE_GNU_CRYPT_R)
ngx_int_t
ngx_libc_crypt(ngx_pool_t *pool, u_char *key, u_char *salt, u_char **encrypted)
{
char *value;
size_t len;
struct crypt_data cd;
cd.initialized = 0;
#ifdef __GLIBC__
/* work around the glibc bug */
cd.current_salt[0] = ~salt[0];
#endif
value = crypt_r((char *) key, (char *) salt, &cd);
if (value) {
len = ngx_strlen(value) + 1;
*encrypted = ngx_pnalloc(pool, len);
if (*encrypted == NULL) {
return NGX_ERROR;
}
ngx_memcpy(*encrypted, value, len);
return NGX_OK;
}
ngx_log_error(NGX_LOG_CRIT, pool->log, ngx_errno, "crypt_r() failed");
return NGX_ERROR;
}
#else
ngx_int_t
ngx_libc_crypt(ngx_pool_t *pool, u_char *key, u_char *salt, u_char **encrypted)
{
char *value;
size_t len;
ngx_err_t err;
value = crypt((char *) key, (char *) salt);
if (value) {
len = ngx_strlen(value) + 1;
*encrypted = ngx_pnalloc(pool, len);
if (*encrypted == NULL) {
return NGX_ERROR;
}
ngx_memcpy(*encrypted, value, len);
return NGX_OK;
}
err = ngx_errno;
ngx_log_error(NGX_LOG_CRIT, pool->log, err, "crypt() failed");
return NGX_ERROR;
}
#endif
#endif /* NGX_CRYPT */
在ngx_auto_config.h头文件中我们有如下定义:
#ifndef NGX_CRYPT #define NGX_CRYPT 1 #endif #ifndef NGX_HAVE_GNU_CRYPT_R #define NGX_HAVE_GNU_CRYPT_R 1 #endif