]>
Commit | Line | Data |
---|---|---|
1 | /* | |
2 | * IRC - Internet Relay Chat, ircd/ircd_crypt.c | |
3 | * Copyright (C) 2002 hikari | |
4 | * | |
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) | |
8 | * any later version. | |
9 | * | |
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. | |
14 | * | |
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. | |
18 | * | |
19 | */ | |
20 | ||
21 | /** | |
22 | * @file | |
23 | * @brief Core password encryption routines. | |
24 | * @version $Id: ircd_crypt.c,v 1.7 2005/06/24 13:57:21 a1kmm Exp $ | |
25 | * | |
26 | * This is a new look crypto API for ircu, it can handle different | |
27 | * password formats by the grace of magic tokens at the beginning of the | |
28 | * password e.g. $SMD5 for Salted MD5, $CRYPT for native crypt(), etc. | |
29 | * | |
30 | * Currently crypt routines are implemented for: the native crypt() | |
31 | * function, Salted MD5 and a plain text mechanism which should only | |
32 | * be used for testing. I intend to add Blowfish, 3DES and possibly | |
33 | * SHA1 support as well at some point, but I'll need to check the | |
34 | * possible problems that'll cause with stupid crypto laws. | |
35 | * | |
36 | * It's also designed to be "ready" for the modularisation of ircu, so | |
37 | * someone get round to doing it, because I'm not doing it ;) | |
38 | * | |
39 | * The plan for Stage B is to semi-modularise the authentication | |
40 | * mechanism to allow authentication against some other sources than | |
41 | * the conf file (whatever takes someones fancy, kerberos, ldap, sql, etc). | |
42 | * | |
43 | * -- blessed be, hikari. | |
44 | */ | |
45 | ||
46 | #include "config.h" | |
47 | #include "ircd_crypt.h" | |
48 | #include "ircd_alloc.h" | |
49 | #include "ircd_features.h" | |
50 | #include "ircd_log.h" | |
51 | #include "ircd_string.h" | |
52 | #include "s_debug.h" | |
53 | ||
54 | /* while we're not modular, we need their init functions */ | |
55 | #include "ircd_crypt_native.h" | |
56 | #include "ircd_crypt_plain.h" | |
57 | #include "ircd_crypt_smd5.h" | |
58 | ||
59 | /* #include <assert.h> -- Now using assert in ircd_log.h */ | |
60 | #include <unistd.h> | |
61 | #include <string.h> | |
62 | ||
63 | /* evil global */ | |
64 | crypt_mechs_t* crypt_mechs_root; | |
65 | ||
66 | /** Add a crypt mechanism to the list | |
67 | * @param mechanism Pointer to the mechanism details struct | |
68 | * @return 0 on success, anything else on fail. | |
69 | * | |
70 | * This routine registers a new crypt mechanism in the loaded mechanisms list, | |
71 | * making it availabe for comparing passwords. | |
72 | */ | |
73 | int ircd_crypt_register_mech(crypt_mech_t* mechanism) | |
74 | { | |
75 | crypt_mechs_t* crypt_mech; | |
76 | ||
77 | Debug((DEBUG_INFO, "ircd_crypt_register_mech: registering mechanism: %s", mechanism->shortname)); | |
78 | ||
79 | /* try to allocate some memory for the new mechanism */ | |
80 | if ((crypt_mech = (crypt_mechs_t*)MyMalloc(sizeof(crypt_mechs_t))) == NULL) | |
81 | { | |
82 | /* aww poot, we couldn't get any memory, scream a little then back out */ | |
83 | Debug((DEBUG_MALLOC, "ircd_crypt_register_mech: could not allocate memory for %s", mechanism->shortname)); | |
84 | return -1; | |
85 | } | |
86 | ||
87 | /* ok, we have memory, initialise it */ | |
88 | memset(crypt_mech, 0, sizeof(crypt_mechs_t)); | |
89 | ||
90 | /* assign the data */ | |
91 | crypt_mech->mech = mechanism; | |
92 | crypt_mech->next = crypt_mech->prev = NULL; | |
93 | ||
94 | /* first of all, is there anything there already? */ | |
95 | if(crypt_mechs_root->next == NULL) | |
96 | { | |
97 | /* nope, just add ourself */ | |
98 | crypt_mechs_root->next = crypt_mechs_root->prev = crypt_mech; | |
99 | } else { | |
100 | /* nice and simple, put ourself at the end */ | |
101 | crypt_mech->prev = crypt_mechs_root->prev; | |
102 | crypt_mech->next = NULL; | |
103 | crypt_mechs_root->prev = crypt_mech->prev->next = crypt_mech; | |
104 | } | |
105 | ||
106 | /* we're done */ | |
107 | Debug((DEBUG_INFO, "ircd_crypt_register_mech: registered mechanism: %s, crypt_function is at 0x%X.", crypt_mech->mech->shortname, &crypt_mech->mech->crypt_function)); | |
108 | Debug((DEBUG_INFO, "ircd_crypt_register_mech: %s: %s", crypt_mech->mech->shortname, crypt_mech->mech->description)); | |
109 | return 0; | |
110 | } | |
111 | ||
112 | /** Remove a crypt mechanism from the list | |
113 | * @param mechanism Pointer to the mechanism we want to remove | |
114 | * @return 0 on success, anything else on fail. | |
115 | */ | |
116 | int ircd_crypt_unregister_mech(crypt_mech_t* mechanism) | |
117 | { | |
118 | ||
119 | return 0; | |
120 | } | |
121 | ||
122 | /** Wrapper for generating a hashed password passed on the supplied password | |
123 | * @param key Pointer to the password we want crypted | |
124 | * @param salt Pointer to the password we're comparing to (for the salt) | |
125 | * @return Pointer to the generated password (must be MyFree()'d). | |
126 | * | |
127 | * This is a wrapper function which attempts to establish the password | |
128 | * format and funnel it off to the correct mechanism handler function. The | |
129 | * returned password is compared in the oper_password_match() routine. | |
130 | */ | |
131 | char* ircd_crypt(const char* key, const char* salt) | |
132 | { | |
133 | char *hashed_pass = NULL; | |
134 | const char *temp_hashed_pass, *mysalt; | |
135 | crypt_mechs_t* crypt_mech; | |
136 | ||
137 | assert(NULL != key); | |
138 | assert(NULL != salt); | |
139 | ||
140 | Debug((DEBUG_DEBUG, "ircd_crypt: key is %s", key)); | |
141 | Debug((DEBUG_DEBUG, "ircd_crypt: salt is %s", salt)); | |
142 | ||
143 | crypt_mech = crypt_mechs_root->next; | |
144 | ||
145 | /* by examining the first n characters of a password string we | |
146 | * can discover what kind of password it is. hopefully. */ | |
147 | for (;crypt_mech;) | |
148 | { | |
149 | if (strlen(salt) < crypt_mech->mech->crypt_token_size) | |
150 | { | |
151 | /* try the next mechanism instead */ | |
152 | Debug((DEBUG_DEBUG, "ircd_crypt: salt is too short, will try next mech at 0x%X", crypt_mech->next)); | |
153 | crypt_mech = crypt_mech->next; | |
154 | continue; | |
155 | } | |
156 | ||
157 | Debug((DEBUG_DEBUG, "ircd_crypt: comparing %s with %s", | |
158 | salt, crypt_mech->mech->crypt_token)); | |
159 | ||
160 | if(0 == ircd_strncmp(crypt_mech->mech->crypt_token, salt, crypt_mech->mech->crypt_token_size)) | |
161 | { | |
162 | Debug((DEBUG_DEBUG, "ircd_crypt: type is %s", | |
163 | crypt_mech->mech->shortname)); | |
164 | ||
165 | /* before we send this all off to the crypt_function, we need to remove | |
166 | the tag from it */ | |
167 | ||
168 | /* make sure we won't end up with a password comprised entirely of | |
169 | a single \0 */ | |
170 | if(strlen(salt) < crypt_mech->mech->crypt_token_size + 1) | |
171 | return NULL; | |
172 | ||
173 | mysalt = salt + crypt_mech->mech->crypt_token_size; | |
174 | ||
175 | if(NULL == (temp_hashed_pass = crypt_mech->mech->crypt_function(key, mysalt))) | |
176 | return NULL; | |
177 | ||
178 | Debug((DEBUG_DEBUG, "ircd_crypt: untagged pass is %s", temp_hashed_pass)); | |
179 | ||
180 | /* ok, now we need to prefix the password we just got back | |
181 | with the right tag */ | |
182 | if(NULL == (hashed_pass = (char *)MyMalloc(sizeof(char)*strlen(temp_hashed_pass) + crypt_mech->mech->crypt_token_size + 1))) | |
183 | { | |
184 | Debug((DEBUG_MALLOC, "ircd_crypt: unable to allocate memory for temp_hashed_pass")); | |
185 | return NULL; | |
186 | } | |
187 | memset(hashed_pass, 0, sizeof(char)*strlen(temp_hashed_pass) | |
188 | +crypt_mech->mech->crypt_token_size + 1); | |
189 | ircd_strncpy(hashed_pass, crypt_mech->mech->crypt_token, | |
190 | crypt_mech->mech->crypt_token_size); | |
191 | ircd_strncpy(hashed_pass + crypt_mech->mech->crypt_token_size, temp_hashed_pass, strlen(temp_hashed_pass)); | |
192 | Debug((DEBUG_DEBUG, "ircd_crypt: tagged pass is %s", hashed_pass)); | |
193 | } else { | |
194 | Debug((DEBUG_DEBUG, "ircd_crypt: will try next mechanism at 0x%X", | |
195 | crypt_mech->next)); | |
196 | crypt_mech = crypt_mech->next; | |
197 | continue; | |
198 | } | |
199 | return hashed_pass; | |
200 | } | |
201 | ||
202 | /* try to use native crypt for an old-style (untagged) password */ | |
203 | if (strlen(salt) > 2) | |
204 | { | |
205 | char *s; | |
206 | temp_hashed_pass = (char*)ircd_crypt_native(key, salt); | |
207 | if (!ircd_strcmp(temp_hashed_pass, salt)) | |
208 | { | |
209 | DupString(s, temp_hashed_pass); | |
210 | return s; | |
211 | } | |
212 | } | |
213 | ||
214 | return NULL; | |
215 | } | |
216 | ||
217 | /** Some basic init. | |
218 | * This function loads initalises the crypt mechanisms linked list and | |
219 | * currently loads the default mechanisms (Salted MD5, Crypt() and PLAIN). | |
220 | * The last step is only needed while ircu is not properly modular. | |
221 | * | |
222 | * When ircu is modular this will be the entry function for the ircd_crypt | |
223 | * module. | |
224 | * | |
225 | */ | |
226 | void ircd_crypt_init(void) | |
227 | { | |
228 | ||
229 | if((crypt_mechs_root = MyMalloc(sizeof(crypt_mechs_t))) == NULL) | |
230 | { | |
231 | /* awooga - can't allocate memory for the root structure */ | |
232 | Debug((DEBUG_MALLOC, "init_crypt: Could not allocate memory for crypt_mechs_root")); | |
233 | return; | |
234 | } | |
235 | ||
236 | crypt_mechs_root->mech = NULL; | |
237 | crypt_mechs_root->next = crypt_mechs_root->prev = NULL; | |
238 | ||
239 | /* temporary kludge until we're modular. manually call the | |
240 | register functions for crypt mechanisms */ | |
241 | ircd_register_crypt_smd5(); | |
242 | ircd_register_crypt_plain(); | |
243 | ircd_register_crypt_native(); | |
244 | ||
245 | return; | |
246 | } |