ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/cvsroot/ermyth/modules/saslserv/crypt.C
Revision: 1.8
Committed: Sat Sep 22 14:27:30 2007 UTC (19 years 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

# User Rev Content
1 pippijn 1.7 /**
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 pippijn 1.4 * Copyright © 2006 Atheme Development Group
10 pippijn 1.2 * Rights to this code are as documented in doc/pod/license.pod.
11 pippijn 1.1 *
12 pippijn 1.8 * $Id: crypt.C,v 1.7 2007-09-16 18:54:44 pippijn Exp $
13 pippijn 1.1 */
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 pippijn 1.4 #include <ermyth/crypto.h>
24     #include <ermyth/module.h>
25 pippijn 1.1 #include <account/myuser.h>
26 pippijn 1.8 #include <util/random.h>
27     #include <util/md5.h>
28 pippijn 1.4 #include <sasl.h>
29 pippijn 1.1
30 pippijn 1.8 static char const rcsid[] = "$Id: crypt.C,v 1.7 2007-09-16 18:54:44 pippijn Exp $";
31 pippijn 1.1
32 pippijn 1.8 REGISTER_MODULE ("saslserv/crypt", false, "The Ermyth Team <http://ermyth.xinutec.org>");
33 pippijn 1.1
34 pippijn 1.4 E list_t sasl_mechanisms;
35     static node_t *mnode;
36 pippijn 1.1 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 pippijn 1.4 static sasl_mechanism_t mech ("CRYPT", &mech_start, &mech_step, &mech_finish);
40 pippijn 1.1
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 pippijn 1.4 bool
50     _modinit (module *m)
51 pippijn 1.1 {
52     mnode = node_create ();
53 pippijn 1.4 node_add (&mech, mnode, &sasl_mechanisms);
54    
55     return true;
56 pippijn 1.1 }
57    
58     void
59     _moddeinit ()
60     {
61 pippijn 1.4 node_del (mnode, &sasl_mechanisms);
62 pippijn 1.1 }
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 pippijn 1.4 p->mechdata = new crypt_status;
81 pippijn 1.1 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 pippijn 1.4 s->server_data[i] = (unsigned char) (gen_rand32 () % 256);
88 pippijn 1.1
89     /* Send data to client */
90 pippijn 1.6 *out = salloc<char> (16);
91 pippijn 1.1 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 pippijn 1.5 if (!(mu = myuser_t::find (user)))
119 pippijn 1.1 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 pippijn 1.6 *out = salloc<char> (2);
129 pippijn 1.1 memcpy (*out, mu->pass, 2);
130     }
131     else if (*(mu->pass) == '$') /* FreeBSD MD5 type */
132     {
133     *out_len = strlen (mu->pass) - 22;
134 pippijn 1.6 *out = salloc<char> (*out_len);
135 pippijn 1.1 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 pippijn 1.4 s->password = (unsigned char *) strdup (crypt (mu->pass, crypto::gen_salt ()));
143 pippijn 1.1 *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 pippijn 1.4 sfree (s->password);
178     sfree (p->mechdata);
179 pippijn 1.1 }
180     }