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
158
159
160
161
162
163
164
165
166
167
168
169
170
|
/*
* Copyright (c) 2006 Atheme Development Group
* Rights to this code are as documented in doc/LICENSE.
*
* CRYPT mechanism provider
*
*/
/******************************* WARNING ******************************************
* This mechanism presents a vulnerability that allows any user to be logged in *
* providing their crytped password is known. This allows attackers with a stolen *
* DB or crypted password to instantly log in using only the crypted password and *
* without cracking or brute-forcing. If you use this, guard your DB closely! *
**********************************************************************************/
#include "atheme.h"
DECLARE_MODULE_V1
(
"saslserv/crypt", false, _modinit, _moddeinit,
PACKAGE_STRING,
"Atheme Development Group <http://www.atheme.org>"
);
mowgli_list_t *mechanisms;
mowgli_node_t *mnode;
static int mech_start(sasl_session_t *p, char **out, int *out_len);
static int mech_step(sasl_session_t *p, char *message, int len, char **out, int *out_len);
static void mech_finish(sasl_session_t *p);
sasl_mechanism_t mech = {"CRYPT", &mech_start, &mech_step, &mech_finish};
struct crypt_status
{
unsigned char client_data[16];
unsigned char server_data[16];
unsigned char *password;
unsigned char stage;
};
void _modinit(module_t *m)
{
MODULE_USE_SYMBOL(mechanisms, "saslserv/main", "sasl_mechanisms");
mnode = mowgli_node_create();
mowgli_node_add(&mech, mnode, mechanisms);
}
void _moddeinit()
{
mowgli_node_delete(mnode, mechanisms);
}
/* Protocol synopsis;
* S -> C: 16 random bytes
* C -> S: 16 random bytes(different from server's random bytes) + username
* S -> C: salt from user's pass(possibly generated on the spot)
* C -> S: raw MD5 of (server's data + client's data + crypted pass)
*
* WARNING: this allows the client to log in given just the encrypted password
*/
static int mech_start(sasl_session_t *p, char **out, int *out_len)
{
struct crypt_status *s;
int i;
/* Allocate session structure for our crap */
p->mechdata = malloc(sizeof(struct crypt_status));
s = (struct crypt_status *)p->mechdata;
s->stage = 0;
s->password = NULL;
/* Generate server's random data */
for(i = 0;i < 16;i++)
s->server_data[i] = (unsigned char)(arc4random() % 256);
/* Send data to client */
*out = malloc(16);
memcpy(*out, s->server_data, 16);
*out_len = 16;
return ASASL_MORE;
}
static int mech_step(sasl_session_t *p, char *message, int len, char **out, int *out_len)
{
struct crypt_status *s = (struct crypt_status *)p->mechdata;
myuser_t *mu;
s->stage++;
if(s->stage == 1) /* C -> S: username + 16 bytes random data */
{
char user[64];
if(len < 17)
return ASASL_FAIL;
/* Store client's random data & skip to username */
memcpy(s->client_data, message, 16);
message += 16;
len -= 16;
/* Sanitize and check if user exists */
strlcpy(user, message, len > 63 ? 64 : len + 1);
if(!(mu = myuser_find(user)))
return ASASL_FAIL;
p->username = strdup(user);
/* Send salt from password to client, generating one if necessary */
if(mu->flags & MU_CRYPTPASS)
{
if(strlen(mu->pass) == 13) /* original DES type */
{
*out_len = 2;
*out = malloc(2);
memcpy(*out, mu->pass, 2);
}
else if(*(mu->pass) == '$') /* FreeBSD MD5 type */
{
*out_len = strlen(mu->pass) - 22;
*out = malloc(*out_len);
memcpy(*out, mu->pass, *out_len);
(*out)[(*out_len) - 1] = '$';
}
s->password = (unsigned char *) strdup(mu->pass);
}
else
{
s->password = (unsigned char *) strdup(crypt(mu->pass, gen_salt()));
*out_len = 10;
*out = strdup((char *)s->password);
}
return ASASL_MORE;
}
else if(s->stage == 2) /* C -> S: raw MD5 of server random data + client random data + crypted password */
{
md5_state_t ctx;
char hash[16];
if(len != 16)
return ASASL_FAIL;
md5_init(&ctx);
md5_append(&ctx, s->server_data, 16);
md5_append(&ctx, s->client_data, 16);
md5_append(&ctx, s->password, strlen((char *)s->password));
md5_finish(&ctx, (unsigned char *) hash);
if(!memcmp(message, hash, 16))
return ASASL_DONE;
else
return ASASL_FAIL;
}else /* wtf? */
return ASASL_FAIL;
}
static void mech_finish(sasl_session_t *p)
{
if(p->mechdata)
{
struct crypt_status *s = (struct crypt_status *)p->mechdata;
free(s->password);
free(p->mechdata);
}
}
/* vim:cinoptions=>s,e0,n0,f0,{0,}0,^0,=s,ps,t0,c3,+s,(2s,us,)20,*30,gs,hs
* vim:ts=8
* vim:sw=8
* vim:noexpandtab
*/
|