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  | }