1 | /***************************************
2 | $Revision: 1.21 $
3 |
4 | Authentication utilities
5 |
6 | Status: NOT REVIEWED, TESTED
7 |
8 | Author(s): Engin Gunduz
9 |
10 | ******************/ /******************
11 | Modification History:
12 | engin (05/04/2000) Created.
13 | ******************/ /******************
14 | Copyright (c) 2000,2001,2002 RIPE NCC
15 |
16 | All Rights Reserved
17 |
18 | Permission to use, copy, modify, and distribute this software and its
19 | documentation for any purpose and without fee is hereby granted,
20 | provided that the above copyright notice appear in all copies and that
21 | both that copyright notice and this permission notice appear in
22 | supporting documentation, and that the name of the author not be
23 | used in advertising or publicity pertaining to distribution of the
24 | software without specific, written prior permission.
25 |
26 | THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
27 | ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS; IN NO EVENT SHALL
28 | AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
29 | DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
30 | AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
31 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
32 | ***************************************/
33 |
34 | #include <md5.h>
35 | #include "AU_util.h"
36 | #include "dbupdate.h"
37 | #include "crypt.h"
38 |
39 | extern int tracing;
40 | extern char *authmethods[];
41 | extern char *crypt(const char *key, const char *salt);
42 |
43 | /* AU_crypt is a wrapper around crypt(3) */
44 | char * AU_crypt(const char *key, const char *setting){
45 |
46 | return crypt(key, setting);
47 |
48 | }
49 |
50 | /* takes a list of passwords and a crypted password. If any
51 | of the passwords in the list is the plaintext of crypted
52 | text, then it immediately returns 1. Otherwise, it returns
53 | 0 */
54 | int au_check_password(char * crypted_password, GSList * password_list)
55 | {
56 | GSList * password_item = NULL;
57 |
58 | if (tracing )
59 | {
60 | printf("TRACING: au_check_password is running" );
61 | }
62 |
63 | for (password_item = password_list; password_item != NULL; password_item = g_slist_next(password_item ))
64 | {
65 | /* if the password is correct, return 1 */
66 | if (strcmp(crypt((char *)password_item->data, crypted_password), crypted_password) == 0)
67 | {
68 | if (tracing )
69 | {
70 | printf("TRACING: au_check_password returning 1\n");
71 | }
72 | return(1); /* auth OK */
73 | }
74 | }
75 | /* we couldn't find any correct password. So, return 0 */
76 | if (tracing )
77 | printf("TRACING: au_check_password returning 0\n");
78 | return(0); /* auth failed */
79 | }
80 |
81 |
82 |
83 | /* takes a list of passwords and a MD5 password. If any
84 | of the passwords in the list is the plaintext of MD5
85 | digest, then it immediately returns 1. Otherwise, it returns
86 | 0 */
87 | int au_check_MD5_password(char * MD5_password, GSList * password_list)
88 | {
89 | MD5_CTX md5ctx;
90 | unsigned char md5_value[16];
91 | int i;
92 | GSList * password_item = NULL;
93 |
94 | for (password_item = password_list; password_item != NULL; password_item = g_slist_next(password_item))
95 | {
96 | /* if the password is correct, return 1 */
97 |
98 | /* check MD5 password */
99 | MD5Init(&md5ctx);
100 | MD5Update(&md5ctx, (unsigned char *)password_item->data, (unsigned int)strlen((char *)password_item->data));
101 | MD5Final(md5_value, &md5ctx);
102 |
103 | /* md5_calc((unsigned char *)md5_value, (unsigned char *)password_item->data, (unsigned int)strlen(password_item->data)); */
104 |
105 | if (tracing )
106 | {
107 | printf("TRACING: Digest is: ");
108 | for (i = 0; i < 32; i++) printf("%02x", md5_value[i]);
109 | printf("\n");
110 | }
111 |
112 | if ( strncmp((char *)md5_value, MD5_password, 32) == 0)
113 | {
114 | if (tracing )
115 | printf("TRACING: au_check_MD5_password returning 1\n");
116 | return(1); /* auth OK */
117 | }
118 | }
119 | /* we couldn't find any correct password. So, return 0 */
120 | if (tracing )
121 | printf("TRACING: au_check_MD5_password returning 0\n");
122 | return(0); /* auth failed */
123 | }
124 |
125 |
126 |
127 | /* takes a list of plain text passwords and an MD5 crypt password. If any
128 | of the passwords in the list is the plaintext of the crypt MD5
129 | then it immediately returns 1. Otherwise, it returns 0 */
130 |
131 | int au_check_crypt_MD5_password(char * MD5_password, GSList * password_list)
132 | {
133 | int i;
134 | char *pw, *cryptpw;
135 | char *passwd;
136 | char salt[9];
137 | GSList * password_item = NULL;
138 |
139 | if (tracing )
140 | {
141 | printf("TRACING: au_check_crypt_MD5_password is running" );
142 | }
143 |
144 | /* find salt in MD5_password ($1$salt$password) */
145 | passwd = strdup(MD5_password);
146 | pw = strtok(passwd,"$"); /* points to start of string */
147 | pw = strtok(NULL,"$"); /* points to start of salt */
148 | if ( pw )
149 | {
150 | strncpy(salt, pw, 8);
151 | salt[8] = '\0';
152 | }
153 | else
154 | salt[0] = '\0';
155 | free(passwd);
156 |
157 | for (password_item = password_list; password_item != NULL; password_item = g_slist_next(password_item))
158 | {
159 | /* encrypt plain text password using the salt from the crypted password*/
160 | cryptpw = crypt_md5((const char *)password_item->data, (const char *)salt );
161 |
162 | if (tracing )
163 | {
164 | printf("TRACING: cryptpw is: [%s]\n", cryptpw );
165 | }
166 |
167 | if ( strcmp((char *)cryptpw, (char *)MD5_password) == 0)
168 | {
169 | if (tracing )
170 | printf("TRACING: au_check_crypt_MD5_password returning 1\n");
171 |
172 | return(1); /* auth OK */
173 | }
174 | }
175 | /* we couldn't find any correct password. So, return 0 */
176 | if (tracing )
177 | printf("TRACING: au_check_crypt_MD5_password returning 0\n");
178 |
179 | return(0); /* auth failed */
180 | }
181 |
182 |
183 |
184 | /* simply compares auth_pgpkeyID & mesg_pgpkeyID and
185 | returns 1 if they are the same. */
186 | int au_check_PGPkey(char * auth_pgpkeyID, /*char * mesg_pgpkeyID*/GSList * mesg_pgpkeyIDs){
187 |
188 | GSList * next = NULL;
189 |
190 | for(next = mesg_pgpkeyIDs; next != NULL; next = g_slist_next(next)){
191 | /* if auth_pgpkeyID & mesg_pgpkeyID are the same, return 1 */
192 | if(strcmp(auth_pgpkeyID, (char *)next->data) == 0){
193 | return(1);
194 | }
195 | }
196 | /* If we reached here, we couldn't find a matching keyID, so return 0 */
197 | return(0);
198 | }
199 |
200 |
201 |
202 | /* Compares the 'From' address of the message to the regular
203 | expression in the 'auth' attribute of the maintainer*/
204 | int au_check_from_address(char * regexp, char * from_address){
205 |
206 | int status;
207 | regex_t re;
208 |
209 | if(from_address == NULL){
210 | return(0);
211 | }
212 | if (regcomp(&re, regexp, REG_EXTENDED|REG_NOSUB|REG_ICASE) != 0) {
213 | //printf("DEBUG: au_check_from_address returns 0 (couldn't compile)\n");
214 | return(0); /* couldn't compile the regexp, return false */
215 | }
216 |
217 | status = regexec(&re, from_address, (size_t) 0, NULL, 0);
218 | regfree(&re);
219 | if (status != 0) {
220 | //printf("DEBUG: au_check_from_address returns 0 (regexp doesn't match)\n\t[regexp:%s][from:%s]\n",
221 | // regexp, from_address);
222 | return(0); /* failed */
223 | }
224 | /* OK, the regexp matches */
225 | //printf("DEBUG: au_check_from_address returns 1\n");
226 | return(1);
227 | }
228 |
229 |
230 | int au_is_valid_authmethod( int type )
231 | {
232 | char *authtype = NULL;
233 | int i;
234 |
235 | switch (type)
236 | {
237 | case AU_NONE: authtype = strdup("NONE");
238 | break;
239 | case AU_MAIL_FROM: authtype = strdup("MAIL-FROM");
240 | break;
241 | case AU_CRYPT_PW: authtype = strdup("CRYPT-PW");
242 | break;
243 | case AU_MD5_PW: authtype = strdup("MD5-PW");
244 | break;
245 | case AU_PGP: authtype = strdup("PGPKEY");
246 | break;
247 | default: authtype = strdup("");
248 | break;
249 | }
250 |
251 | i=0;
252 | while ( authmethods[i] != NULL )
253 | {
254 | /* check if the authtype from the mntners is in the list of valid authmethods */
255 | if ( ! strcmp(authmethods[i++], authtype) )
256 | {
257 | free(authtype);
258 | return 1;
259 | }
260 | }
261 |
262 | /* authtype is not a valid authmethod */
263 | return 0;
264 | }
265 |
266 |
267 |
268 |
269 | /* Gets a auth_vector, and credentials_struct (which is extracted
270 | from the update message) and returns 0 if all of the auth
271 | methods fail, and returns the index of the succeeding auth_struct in the auth_vector
272 | if any one of them succeeds. */
273 | int AU_authorise(GSList * auth_vector, credentials_struct credentials)
274 | {
275 | GSList *auth_item = NULL;
276 | auth_struct * temp = NULL;
277 | int result = 0;
278 |
279 | /* if the linked list contains no members, then return 1*/
280 | if (g_slist_length(auth_vector) == 0)
281 | {
282 | return(1);
283 | }
284 |
285 | for (auth_item = auth_vector; auth_item != NULL; auth_item = g_slist_next(auth_item))
286 | {
287 | temp = (auth_struct *)auth_item->data;
288 | if ( temp != NULL )
289 | {
290 | if ( au_is_valid_authmethod(temp->type) )
291 | {
292 | switch (temp->type)
293 | {
294 | case AU_NONE: return temp->index; /* NONE, immediately returns true */
295 | break;
296 | case AU_MAIL_FROM:
297 | if (au_check_from_address(temp->auth, credentials.from))
298 | {
299 | result = temp->index;
300 | }
301 | break;
302 | case AU_CRYPT_PW: if (au_check_password(temp->auth, credentials.password_list))
303 | {
304 | result = temp->index;
305 | }
306 | break;
307 | case AU_MD5_PW: if (au_check_crypt_MD5_password(temp->auth, credentials.password_list))
308 | {
309 | result = temp->index;
310 | }
311 | break;
312 | case AU_PGP: //printf("DEBUG: AU_authorise: will call au_check_PGPkey\n");
313 | //printf("DEBUG: AU_authorise: with temp->auth=[%s]\n", temp->auth);
314 | //printf("DEBUG: AU_authorise: and credentials.pgp_struct=[%s]\n", credentials.pgp_struct);
315 | if (au_check_PGPkey(temp->auth, credentials.pgp_key_list))
316 | {
317 | result = temp->index;
318 | }
319 | break;
320 | default: ;/* this mustn't happen */
321 | break;
322 | }
323 | }
324 | if (result > 0)
325 | {
326 | return(result);
327 | }
328 | }
329 | }
330 |
331 |
332 | return 0;
333 | }