/** * crypt.C: CRYPT mechanism provider * * Copyright © 2007 Pippijn van Steenhoven / The Ermyth Team * Rights to this code are as documented in COPYING. * * * Portions of this file were derived from sources bearing the following license: * Copyright © 2006 Atheme Development Group * Rights to this code are as documented in doc/pod/license.pod. * * $Id: crypt.C,v 1.8 2007/09/22 14:27:30 pippijn Exp $ */ /******************************* 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" #include #include #include #include #include #include static char const rcsid[] = "$Id: crypt.C,v 1.8 2007/09/22 14:27:30 pippijn Exp $"; REGISTER_MODULE ("saslserv/crypt", false, "The Ermyth Team "); E list_t sasl_mechanisms; static 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); static 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; }; bool _modinit (module *m) { mnode = node_create (); node_add (&mech, mnode, &sasl_mechanisms); return true; } void _moddeinit () { node_del (mnode, &sasl_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 = new 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) (gen_rand32 () % 256); /* Send data to client */ *out = salloc (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_t::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 = salloc (2); memcpy (*out, mu->pass, 2); } else if (*(mu->pass) == '$') /* FreeBSD MD5 type */ { *out_len = strlen (mu->pass) - 22; *out = salloc (*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, crypto::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 */ { MD5Context ctx; char hash[16]; if (len != 16) return ASASL_FAIL; MD5Init (&ctx); MD5Update (&ctx, s->server_data, 16); MD5Update (&ctx, s->client_data, 16); MD5Update (&ctx, s->password, strlen ((char *) s->password)); MD5Final ((unsigned char *) hash, &ctx); 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; sfree (s->password); sfree (p->mechdata); } }