ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/ermyth/modules/saslserv/crypt.C
Revision: 1.8
Committed: Sat Sep 22 14:27:30 2007 UTC (16 years, 8 months ago) by pippijn
Content type: text/plain
Branch: MAIN
CVS Tags: HEAD
Changes since 1.7: +5 -4 lines
Log Message:
split up ermyth into ermyth-modules, libermyth (currently just ermyth-util) and ermyth-core

File Contents

# Content
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 }