2 * IRC - Internet Relay Chat, ircd/ircd_crypt.c
3 * Copyright (C) 2002 hikari
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 1, or (at your option)
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 * This is a new look crypto API for ircu, it can handle different
24 * password formats by the grace of the standard magic tokens at the
25 * begining of the password e.g. $1 for MD5, $2 for Blowfish, etc.
27 * Currently crypt routines are implemented for: the native crypt()
28 * function, Salted MD5 and a plain text mechanism which should only
29 * be used for testing. I intend to add Blowish, 3DES and possibly
30 * SHA1 support as well at some point, but I'll need to check the
31 * possible problems that'll cause with stupid crypto laws.
33 * It's also designed to be "ready" for the modularisation of ircu, so
34 * someone get round to doing it, because I'm not doing it ;)
36 * The plan for Stage B is to semi-modularise the authentication
37 * mechanism to allow authentication against some other sources than
38 * the conf file (whatever takes someones fancy, kerberos, ldap, sql, etc).
40 * -- blessed be, hikari.
44 #include "ircd_crypt.h"
45 #include "ircd_alloc.h"
46 #include "ircd_features.h"
47 #include "ircd_string.h"
50 /* while we're not modular, we need their init functions */
51 #include "ircd_crypt_native.h"
52 #include "ircd_crypt_plain.h"
53 #include "ircd_crypt_smd5.h"
60 crypt_mechs_t* crypt_mechs_root;
63 * add a crypt mechanism to the list
65 int ircd_crypt_register_mech(crypt_mech_t* mechanism)
67 crypt_mechs_t* crypt_mech;
69 Debug((DEBUG_INFO, "ircd_crypt_register_mech: resistering mechanism: %s", mechanism->shortname));
71 /* try to allocate some memory for the new mechanism */
72 if ((crypt_mech = (crypt_mechs_t*)MyMalloc(sizeof(crypt_mechs_t))) == NULL)
74 /* aww poot, we couldn't get any memory, scream a little then back out */
75 Debug((DEBUG_MALLOC, "ircd_crypt_register_mech: could not allocate memory for %s", mechanism->shortname));
79 /* ok, we have memory, initialise it */
80 memset(crypt_mech, 0, sizeof(crypt_mechs_t));
83 crypt_mech->mech = mechanism;
84 crypt_mech->next = crypt_mech->prev = NULL;
86 /* first of all, is there anything there already? */
87 if(crypt_mechs_root->next == NULL)
89 /* nope, just add ourself */
90 crypt_mechs_root->next = crypt_mechs_root->prev = crypt_mech;
92 /* nice and simple, put ourself at the end */
93 crypt_mech->prev = crypt_mechs_root->prev;
94 crypt_mech->next = NULL;
95 crypt_mechs_root->prev = crypt_mech->prev->next = crypt_mech;
99 Debug((DEBUG_INFO, "ircd_crypt_register_mech: resistered mechanism: %s, crypt_function is at 0x%X.", crypt_mech->mech->shortname, &crypt_mech->mech->crypt_function));
100 Debug((DEBUG_INFO, "ircd_crypt_register_mech: %s: %s", crypt_mech->mech->shortname, crypt_mech->mech->description));
105 * remove a crypt mechanism from the list
107 int ircd_crypt_unregister_mech(crypt_mech_t* mechanism)
114 * this is now a wrapper function which attempts to establish the password
115 * format and funnel it off to the correct handler function.
117 const char* ircd_crypt(const char* key, const char* salt)
119 char *hashed_pass = NULL;
120 const char *temp_hashed_pass, *mysalt;
121 crypt_mechs_t* crypt_mech;
124 assert(NULL != salt);
126 Debug((DEBUG_DEBUG, "ircd_crypt: key is %s", key));
127 Debug((DEBUG_DEBUG, "ircd_crypt: salt is %s", salt));
129 crypt_mech = crypt_mechs_root->next;
131 /* by examining the first n characters of a password string we
132 * can discover what kind of password it is. hopefully. */
135 if (strlen(salt) < crypt_mech->mech->crypt_token_size)
137 /* try the next mechanism instead */
138 Debug((DEBUG_DEBUG, "ircd_crypt: salt is too short, will try next mech at 0x%X", crypt_mech->next));
139 crypt_mech = crypt_mech->next;
143 Debug((DEBUG_DEBUG, "ircd_crypt: comparing %s with %s",
144 salt, crypt_mech->mech->crypt_token));
146 if(0 == ircd_strncmp(crypt_mech->mech->crypt_token, salt, crypt_mech->mech->crypt_token_size))
148 Debug((DEBUG_DEBUG, "ircd_crypt: type is %s",
149 crypt_mech->mech->shortname));
151 /* before we send this all off to the crypt_function, we need to remove
154 /* make sure we won't end up with a password comprised entirely of
156 if(strlen(salt) < crypt_mech->mech->crypt_token_size + 1)
159 mysalt = salt + crypt_mech->mech->crypt_token_size;
161 if(NULL == (temp_hashed_pass = crypt_mech->mech->crypt_function(key, mysalt)))
164 Debug((DEBUG_DEBUG, "ircd_crypt: untagged pass is %s", temp_hashed_pass));
166 /* ok, now we need to prefix the password we just got back
167 with the right tag */
168 if(NULL == (hashed_pass = (char *)MyMalloc(sizeof(char)*strlen(temp_hashed_pass) + crypt_mech->mech->crypt_token_size + 1)))
170 Debug((DEBUG_MALLOC, "ircd_crypt: unable to allocate memory for temp_hashed_pass"));
173 memset(hashed_pass, 0, sizeof(char)*strlen(temp_hashed_pass)
174 +crypt_mech->mech->crypt_token_size + 1);
175 ircd_strncpy(hashed_pass, crypt_mech->mech->crypt_token,
176 crypt_mech->mech->crypt_token_size);
177 ircd_strncpy(hashed_pass + crypt_mech->mech->crypt_token_size, temp_hashed_pass, strlen(temp_hashed_pass));
178 Debug((DEBUG_DEBUG, "ircd_crypt: tagged pass is %s", hashed_pass));
180 Debug((DEBUG_DEBUG, "ircd_crypt: will try next mechansim at 0x%X",
182 crypt_mech = crypt_mech->next;
188 /* try to use native crypt for an old-style (untagged) password */
189 if (strlen(salt) > 2)
191 temp_hashed_pass = (char*)ircd_crypt_native(key, salt);
192 if (!ircd_strcmp(temp_hashed_pass, salt))
193 return strdup(temp_hashed_pass);
200 * some basic init, when we're modular this will be our entry
203 void ircd_crypt_init(void)
206 if((crypt_mechs_root = MyMalloc(sizeof(crypt_mechs_t))) == NULL)
208 /* awooga - can't allocate memory for the root structure */
209 Debug((DEBUG_MALLOC, "init_crypt: Could not allocate memory for crypt_mechs_root"));
213 crypt_mechs_root->mech = NULL;
214 crypt_mechs_root->next = crypt_mechs_root->prev = NULL;
216 /* temporary kludge until we're modular. manualy call the
217 register funtions for crypt mechanisms */
218 ircd_register_crypt_smd5();
219 ircd_register_crypt_plain();
220 ircd_register_crypt_native();