/
password.c
158 lines (127 loc) · 4.57 KB
/
password.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
#include "redismodule.h"
#include <string.h>
#include "ow-crypt.h"
#define SHA512_SALT "$2y$10"
static char *do_crypt(const char *password, char *output, int output_len)
{
char salt[16];
char tmp[64];
char *setting;
FILE *fp = fopen("/dev/urandom","r");
if (!fp) return NULL;
if (fread(salt, sizeof(salt), 1, fp) != 1) {
fclose(fp);
return NULL;
}
fclose(fp);
memset(tmp, 0, sizeof(tmp));
if (!(setting = crypt_gensalt_rn("$2y$", 0, salt, sizeof(salt),
tmp, sizeof(tmp))))
return NULL;
memset(output, 0, output_len);
return crypt_rn(password, setting, output, output_len);
}
static int cmd_password_set(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
RedisModuleCallReply *reply;
size_t len;
char crypt_buf[64];
char *hash;
if (argc != 3) {
RedisModule_WrongArity(ctx);
return REDISMODULE_OK;
}
hash = do_crypt(RedisModule_StringPtrLen(argv[2], &len), crypt_buf, sizeof(crypt_buf));
if (!hash) {
RedisModule_ReplyWithError(ctx, "ERR hash error");
return REDISMODULE_ERR;
}
reply = RedisModule_Call(ctx, "SET", "sc!", argv[1], hash);
RedisModule_ReplyWithCallReply(ctx, reply);
return REDISMODULE_OK;
}
static int cmd_password_hset(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
RedisModuleCallReply *reply;
size_t len;
char crypt_buf[64];
char *hash;
if (argc != 4) {
RedisModule_WrongArity(ctx);
return REDISMODULE_OK;
}
hash = do_crypt(RedisModule_StringPtrLen(argv[3], &len), crypt_buf, sizeof(crypt_buf));
if (!hash) {
RedisModule_ReplyWithError(ctx, "ERR hash error");
return REDISMODULE_ERR;
}
reply = RedisModule_Call(ctx, "HSET", "ssc!", argv[1], argv[2], hash);
RedisModule_ReplyWithCallReply(ctx, reply);
return REDISMODULE_OK;
}
static void validate(RedisModuleCtx *ctx, RedisModuleCallReply *reply, RedisModuleString *password)
{
const char *reply_str;
size_t reply_len;
const char *pass;
size_t pass_len;
const char *crypt_pass;
size_t crypt_pass_len;
char crypt_buf[64];
if (RedisModule_CallReplyType(reply) == REDISMODULE_REPLY_NULL) {
RedisModule_ReplyWithLongLong(ctx, 0);
return;
}
if (RedisModule_CallReplyType(reply) != REDISMODULE_REPLY_STRING) {
RedisModule_ReplyWithError(ctx, "WRONGTYPE Operation against a key holding the wrong kind of value");
return;
}
reply_str = RedisModule_CallReplyStringPtr(reply, &reply_len);
pass = RedisModule_StringPtrLen(password, &pass_len);
crypt_pass = crypt_rn(pass, reply_str, crypt_buf, sizeof(crypt_buf));
if (!crypt_pass) {
RedisModule_ReplyWithError(ctx, "ERR hash error");
return;
}
crypt_pass_len = strlen(crypt_pass);
if (crypt_pass_len == reply_len && !memcmp(reply_str, crypt_pass, crypt_pass_len)) {
RedisModule_ReplyWithLongLong(ctx, 1);
} else {
RedisModule_ReplyWithLongLong(ctx, 0);
}
}
static int cmd_password_check(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
RedisModuleCallReply *reply;
if (argc != 3) {
RedisModule_WrongArity(ctx);
return REDISMODULE_OK;
}
reply = RedisModule_Call(ctx, "GET", "s", argv[1]);
validate(ctx, reply, argv[2]);
return REDISMODULE_OK;
}
static int cmd_password_hcheck(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
RedisModuleCallReply *reply;
if (argc != 4) {
RedisModule_WrongArity(ctx);
return REDISMODULE_OK;
}
reply = RedisModule_Call(ctx, "HGET", "ss", argv[1], argv[2]);
validate(ctx, reply, argv[3]);
return REDISMODULE_OK;
}
int RedisModule_OnLoad(RedisModuleCtx *ctx) {
if (RedisModule_Init(ctx, "password", 1, REDISMODULE_APIVER_1) == REDISMODULE_ERR)
return REDISMODULE_ERR;
if (RedisModule_CreateCommand(ctx, "password.set", cmd_password_set,
"no-monitor fast", 1, 1, 1) == REDISMODULE_ERR)
return REDISMODULE_ERR;
if (RedisModule_CreateCommand(ctx, "password.hset", cmd_password_hset,
"no-monitor fast", 1, 1, 1) == REDISMODULE_ERR)
return REDISMODULE_ERR;
if (RedisModule_CreateCommand(ctx, "password.check", cmd_password_check,
"no-monitor fast", 1, 1, 1) == REDISMODULE_ERR)
return REDISMODULE_ERR;
if (RedisModule_CreateCommand(ctx, "password.hcheck", cmd_password_hcheck,
"no-monitor fast", 1, 1, 1) == REDISMODULE_ERR)
return REDISMODULE_ERR;
return REDISMODULE_OK;
}