1 |
/** |
2 |
* crypt.C: CRYPT mechanism provider |
3 |
* |
4 |
* Copyright © 2007 Pippijn van Steenhoven / The Ermyth Team |
5 |
* Rights to this code are as documented in COPYING. |
6 |
* |
7 |
* |
8 |
* Portions of this file were derived from sources bearing the following license: |
9 |
* Copyright © 2006 Atheme Development Group |
10 |
* Rights to this code are as documented in doc/pod/license.pod. |
11 |
* |
12 |
* $Id: crypt.C,v 1.7 2007-09-16 18:54:44 pippijn Exp $ |
13 |
*/ |
14 |
|
15 |
/******************************* WARNING ****************************************** |
16 |
* This mechanism presents a vulnerability that allows any user to be logged in * |
17 |
* providing their crytped password is known. This allows attackers with a stolen * |
18 |
* DB or crypted password to instantly log in using only the crypted password and * |
19 |
* without cracking or brute-forcing. If you use this, guard your DB closely! * |
20 |
**********************************************************************************/ |
21 |
|
22 |
#include "atheme.h" |
23 |
#include <ermyth/crypto.h> |
24 |
#include <ermyth/module.h> |
25 |
#include <account/myuser.h> |
26 |
#include <util/random.h> |
27 |
#include <util/md5.h> |
28 |
#include <sasl.h> |
29 |
|
30 |
static char const rcsid[] = "$Id: crypt.C,v 1.7 2007-09-16 18:54:44 pippijn Exp $"; |
31 |
|
32 |
REGISTER_MODULE ("saslserv/crypt", false, "The Ermyth Team <http://ermyth.xinutec.org>"); |
33 |
|
34 |
E list_t sasl_mechanisms; |
35 |
static node_t *mnode; |
36 |
static int mech_start (sasl_session_t *p, char **out, int *out_len); |
37 |
static int mech_step (sasl_session_t *p, char *message, int len, char **out, int *out_len); |
38 |
static void mech_finish (sasl_session_t *p); |
39 |
static sasl_mechanism_t mech ("CRYPT", &mech_start, &mech_step, &mech_finish); |
40 |
|
41 |
struct crypt_status |
42 |
{ |
43 |
unsigned char client_data[16]; |
44 |
unsigned char server_data[16]; |
45 |
unsigned char *password; |
46 |
unsigned char stage; |
47 |
}; |
48 |
|
49 |
bool |
50 |
_modinit (module *m) |
51 |
{ |
52 |
mnode = node_create (); |
53 |
node_add (&mech, mnode, &sasl_mechanisms); |
54 |
|
55 |
return true; |
56 |
} |
57 |
|
58 |
void |
59 |
_moddeinit () |
60 |
{ |
61 |
node_del (mnode, &sasl_mechanisms); |
62 |
} |
63 |
|
64 |
/* Protocol synopsis; |
65 |
* S -> C: 16 random bytes |
66 |
* C -> S: 16 random bytes(different from server's random bytes) + username |
67 |
* S -> C: salt from user's pass(possibly generated on the spot) |
68 |
* C -> S: raw MD5 of (server's data + client's data + crypted pass) |
69 |
* |
70 |
* WARNING: this allows the client to log in given just the encrypted password |
71 |
*/ |
72 |
|
73 |
static int |
74 |
mech_start (sasl_session_t *p, char **out, int *out_len) |
75 |
{ |
76 |
struct crypt_status *s; |
77 |
int i; |
78 |
|
79 |
/* Allocate session structure for our crap */ |
80 |
p->mechdata = new crypt_status; |
81 |
s = (struct crypt_status *) p->mechdata; |
82 |
s->stage = 0; |
83 |
s->password = NULL; |
84 |
|
85 |
/* Generate server's random data */ |
86 |
for (i = 0; i < 16; i++) |
87 |
s->server_data[i] = (unsigned char) (gen_rand32 () % 256); |
88 |
|
89 |
/* Send data to client */ |
90 |
*out = salloc<char> (16); |
91 |
memcpy (*out, s->server_data, 16); |
92 |
*out_len = 16; |
93 |
|
94 |
return ASASL_MORE; |
95 |
} |
96 |
|
97 |
static int |
98 |
mech_step (sasl_session_t *p, char *message, int len, char **out, int *out_len) |
99 |
{ |
100 |
struct crypt_status *s = (struct crypt_status *) p->mechdata; |
101 |
myuser_t *mu; |
102 |
s->stage++; |
103 |
|
104 |
if (s->stage == 1) /* C -> S: username + 16 bytes random data */ |
105 |
{ |
106 |
char user[64]; |
107 |
|
108 |
if (len < 17) |
109 |
return ASASL_FAIL; |
110 |
|
111 |
/* Store client's random data & skip to username */ |
112 |
memcpy (s->client_data, message, 16); |
113 |
message += 16; |
114 |
len -= 16; |
115 |
|
116 |
/* Sanitize and check if user exists */ |
117 |
strlcpy (user, message, len > 63 ? 64 : len + 1); |
118 |
if (!(mu = myuser_t::find (user))) |
119 |
return ASASL_FAIL; |
120 |
p->username = strdup (user); |
121 |
|
122 |
/* Send salt from password to client, generating one if necessary */ |
123 |
if (mu->flags & MU_CRYPTPASS) |
124 |
{ |
125 |
if (strlen (mu->pass) == 13) /* original DES type */ |
126 |
{ |
127 |
*out_len = 2; |
128 |
*out = salloc<char> (2); |
129 |
memcpy (*out, mu->pass, 2); |
130 |
} |
131 |
else if (*(mu->pass) == '$') /* FreeBSD MD5 type */ |
132 |
{ |
133 |
*out_len = strlen (mu->pass) - 22; |
134 |
*out = salloc<char> (*out_len); |
135 |
memcpy (*out, mu->pass, *out_len); |
136 |
(*out)[(*out_len) - 1] = '$'; |
137 |
} |
138 |
s->password = (unsigned char *) strdup (mu->pass); |
139 |
} |
140 |
else |
141 |
{ |
142 |
s->password = (unsigned char *) strdup (crypt (mu->pass, crypto::gen_salt ())); |
143 |
*out_len = 10; |
144 |
*out = strdup ((char *) s->password); |
145 |
} |
146 |
return ASASL_MORE; |
147 |
} |
148 |
else if (s->stage == 2) /* C -> S: raw MD5 of server random data + client random data + crypted password */ |
149 |
{ |
150 |
MD5Context ctx; |
151 |
char hash[16]; |
152 |
|
153 |
if (len != 16) |
154 |
return ASASL_FAIL; |
155 |
|
156 |
MD5Init (&ctx); |
157 |
MD5Update (&ctx, s->server_data, 16); |
158 |
MD5Update (&ctx, s->client_data, 16); |
159 |
MD5Update (&ctx, s->password, strlen ((char *) s->password)); |
160 |
MD5Final ((unsigned char *) hash, &ctx); |
161 |
|
162 |
if (!memcmp (message, hash, 16)) |
163 |
return ASASL_DONE; |
164 |
else |
165 |
return ASASL_FAIL; |
166 |
} |
167 |
else /* wtf? */ |
168 |
return ASASL_FAIL; |
169 |
} |
170 |
|
171 |
static void |
172 |
mech_finish (sasl_session_t *p) |
173 |
{ |
174 |
if (p->mechdata) |
175 |
{ |
176 |
struct crypt_status *s = (struct crypt_status *) p->mechdata; |
177 |
sfree (s->password); |
178 |
sfree (p->mechdata); |
179 |
} |
180 |
} |