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