/* * Copyright (c) 1996-2007, OpenFWTK Development Group * All rights reserved. See LICENSE. */ static char RcsId[] = ""; #include #include #include #include #include "firewall.h" #include "auth.h" #include "firewall.h" #include "firewall2.h" #include "auth.h" #include "authdb.h" #ifdef AUTHPROTO_SECURID #define SECURID_MAX_SEED_LEN 100 /* NOTE!!! SECURID_MAX_SEED_LEN * SECURID_MAX_TOK_NUM * SECURID_MAX_TOK_LEN * should not be greater AUTH_PROTO_BUF_LEN (500 bytes currently) */ #define SECURID_MAX_TOK_NUM 40 #define SECURID_MAX_TOK_LEN 10 typedef struct { char seed[SECURID_MAX_SEED_LEN]; char used_toks[SECURID_MAX_TOK_NUM][SECURID_MAX_TOK_LEN]; } t_securid_db; /* * Copyright (C) 2002 e_costin@yahoo.com * */ #ifdef _MSC_VER #pragma intrinsic (_lrotr, _lrotl) #else /* GCC or CC */ #define __int64 long long #define __forceinline __inline__ #define _lrotr(x, n) ((((unsigned long)(x)) >> ((int) ((n) & 31))) | (((unsigned long)(x)) << ((int) ((-(n)) & 31)))) #define _lrotl(x, n) ((((unsigned long)(x)) << ((int) ((n) & 31))) | (((unsigned long)(x)) >> ((int) ((-(n)) & 31)))) #endif #include #include #include #include #include #include #include #include #include #include #include #define PAM_SM_AUTH #define PAM_SM_ACCOUNT #define ror32(x, n) _lrotr (x, n) #define rol32(x, n) _lrotl (x, n) #define bswap32(x) (rol32 ((unsigned long)(x), 8) & 0x00ff00ff | ror32 ((unsigned long)(x), 8) & 0xff00ff00) static __forceinline unsigned char ror8 (const unsigned char x, const int n) { return (x >> (n & 7)) | (x << ((-n) & 7)); } static __forceinline unsigned __int64 rol64 (const unsigned __int64 x, const int n) { return (x << (n & 63)) | (x >> ((-n) & 63)); } static __forceinline unsigned __int64 bswap64 (const unsigned __int64 x) { unsigned long a = (unsigned long) x, b = (unsigned long) (x >> 32); return (((unsigned __int64) bswap32 (a)) << 32) | bswap32(b); } typedef union _OCTET { unsigned __int64 Q[1]; unsigned long D[2]; unsigned short W[4]; unsigned char B[8]; } OCTET; static __forceinline unsigned __int64 rol64_bitstring (const unsigned __int64 x, int n) { OCTET out, in; in.Q[0] = x; if((n&63) == 0) { out.Q[0] = in.Q[0]; } else { out.D[0] = htonl((unsigned long)((unsigned __int64)ntohl(in.D[!((n&63)<=32)]) << (((n-1) & 31) + 1) | (unsigned long)ntohl(in.D[ (n&63)<=32 ]) >> ((-n) & 31))); out.D[1] = htonl((unsigned long)((unsigned __int64)ntohl(in.D[ (n&63)<=32 ]) << (((n-1) & 31) + 1) | (unsigned long)ntohl(in.D[!((n&63)<=32)]) >> ((-n) & 31))); } return out.Q[0]; } static int ctrl = 0; void securid_expand_key_to_4_bit_per_byte (const OCTET source, char *target) { int i; for (i = 0; i < 8; i++) { target[i*2 ] = source.B[i] >> 4; target[i*2+1] = source.B[i] & 0x0F; } } void securid_expand_data_to_1_bit_per_byte (const OCTET source, char *target) { int i, j, k; for (i = 0, k = 0; i < 8; i++) for (j = 7; j >= 0; j--) target[k++] = (source.B[i] >> j) & 1; } void securid_reassemble_64_bit_from_64_byte (const unsigned char *source, OCTET *target) { int i = 0, j, k = 0; for (target->Q[0] = 0; i < 8; i++) for (j = 7; j >= 0; j--) target->B[i] |= source[k++] << j; } void securid_permute_data (OCTET *data, const OCTET key) { unsigned char bit_data[128]; unsigned char hex_key[16]; unsigned long i, k, b, m, bit; unsigned char j; unsigned char *hkw, *permuted_bit; memset (bit_data, 0, sizeof (bit_data)); securid_expand_data_to_1_bit_per_byte (*data, bit_data); securid_expand_key_to_4_bit_per_byte (key, hex_key); for (bit = 32, hkw = hex_key, m = 0; bit <= 32; hkw += 8, bit -= 32) { permuted_bit = bit_data + 64 + bit; for (k = 0, b = 28; k < 8; k++, b -= 4) { for (j = hkw[k]; j; j--) { bit_data[(bit + b + m + 4) & 0x3F] = bit_data[m]; m = (m + 1) & 0x3F; } for (i = 0; i < 4; i++) { permuted_bit[b + i] |= bit_data[(bit + b + m + i) & 0x3F]; } } } securid_reassemble_64_bit_from_64_byte (bit_data + 64, data); } void securid_do_4_rounds (OCTET *data, OCTET *key) { unsigned char round, i, j; unsigned char t; for (round = 0; round < 4; round++) { for (i = 0; i < 8; i++) { for (j = 0; j < 8; j++) { if ((((key->B[i] >> (j ^ 7)) ^ (data->B[0] >> 7)) & 1) != 0) { t = data->B[4]; data->B[4] = 100 - data->B[0]; data->B[0] = t; } else { data->B[0] = (unsigned char) (ror8 ((unsigned char) (ror8 (data->B[0], 1) - 1), 1) - 1) ^ data->B[4]; } /* #ifdef I_AM_LITTLE_ENDIAN data->Q[0] = bswap64 (rol64 (bswap64 (data->Q[0]), 1)); #else data->Q[0] = rol64 (data->Q[0], 1); #endif */ data->Q[0] = rol64_bitstring (data->Q[0], 1); } } key->Q[0] ^= data->Q[0]; } } void securid_convert_to_decimal (OCTET *data, const OCTET key) { unsigned long i; unsigned char c, hi, lo; c = (key.B[7] & 0x0F) % 5; for (i = 0; i < 8; i++) { hi = data->B[i] >> 4; lo = data->B[i] & 0x0F; c = (c + (key.B[i] >> 4)) % 5; if (hi > 9) data->B[i] = ((hi = (hi - (c + 1) * 2) % 10) << 4) | lo; c = (c + (key.B[i] & 0x0F)) % 5; if (lo > 9) data->B[i] = (lo = ((lo - (c + 1) * 2) % 10)) | (hi << 4); } } void securid_hash_data (OCTET *data, OCTET key, unsigned char convert_to_decimal) { securid_permute_data (data, key); securid_do_4_rounds (data, &key); securid_permute_data (data, key); if (convert_to_decimal) securid_convert_to_decimal (data, key); } void securid_hash_time (unsigned long time, OCTET *hash, OCTET key) { hash->B[0] = (unsigned char) (time >> 16); hash->B[1] = (unsigned char) (time >> 8); hash->B[2] = (unsigned char) time; hash->B[3] = (unsigned char) time; hash->B[4] = (unsigned char) (time >> 16); hash->B[5] = (unsigned char) (time >> 8); hash->B[6] = (unsigned char) time; hash->B[7] = (unsigned char) time; securid_hash_data (hash, key, 1); } /* * * Looks up an user name in a database and checks the password * * return values: * 1 = user not found * 0 = Auth OK * -1 = password incorrect * -2 = system error * password file = /etc/securid.pass * used codes file = /etc/securid.codes */ static int user_lookup(const char *user, const char *pass, Auth *ap) { int found, i; signed long /* j, k,*/ tt; OCTET key, hi, hj; FILE *fi, *fs; char *m, *p, *serv, s[46], inkey[17], inkey1[9], inkey2[9], tmp_cod[20], serial[10], okey[17]; t_securid_db *securid_db; int tok_num; // unsigned __int64 key64; unsigned long my_time = 1079609897l; char buf[1000]; /* Reread the s/key record NOW and leave DB (and open) */ /* * Obtain an exclusive lock on the DB file so the same password * cannot be used twice to get in to the system. */ if(auth_dbgetu_forupdate(user, ap) || !ap->authproto_rec.active) { auth_dbclose(); return(1); } securid_db = (t_securid_db *)ap->authproto_rec.buf; /* #ifdef I_AM_LITTLE_ENDIAN for (i = 0 ; i < 8; i++) inkey1[i] = securid_db->seed[i]; inkey1[8] = '\00'; for (i = 0 ; i < 8; i++) inkey2[i] = securid_db->seed[i+8]; inkey2[8] = '\00'; key.D[0] = strtoul (inkey2, &m, 16); key.D[1] = strtoul (inkey1, &m, 16); #else for (i = 0; i < 8; i++) { okey[2*i] = securid_db->seed[15-2*i-1]; okey[2*i+1] = securid_db->seed[15-2*i]; } okey[16] = '\00'; key.Q[0] = strtoull (okey, &m, 16); #endif */ for (i = 0 ; i < 8; i++) inkey1[i] = securid_db->seed[i]; inkey1[8] = '\00'; for (i = 0 ; i < 8; i++) inkey2[i] = securid_db->seed[i+8]; inkey2[8] = '\00'; key.D[1] = htonl(strtoul (inkey2, &m, 16)); key.D[0] = htonl(strtoul (inkey1, &m, 16)); key.Q[0] = bswap64(key.Q[0]); for(tok_num=0; tok_num < SECURID_MAX_TOK_NUM && securid_db->used_toks[tok_num][0] != '\0'; tok_num++) { if (strncmp(securid_db->used_toks[tok_num],pass,6) == 0) /* the token used before */ { auth_dbclose(); return 1; } } if(tok_num >= SECURID_MAX_TOK_NUM) { sosay(0, "list of used tokens is full"); auth_dbclose(); /* Unlock DB file and close it */ return(1); } /* #ifdef I_AM_LITTLE_ENDIAN hj.D[0] = strtoul (pass, &m, 16); #else hj.D[0] = bswap32(strtoul (pass, &m, 16)); #endif */ hj.D[0] = bswap32(htonl(strtoul (pass, &m, 16))); found = 0; tt = (time (NULL) / 60 - 0x806880) * 2; // (t & -4) for 60 sec periods, (t & -8) for 120 sec periods, etc. securid_hash_time (((tt-4) & -4), &hi, key); if ((hi.B[3] == hj.B[2]) && (hi.B[4] == hj.B[1]) && (hi.B[5] == hj.B[0])) found = 1; securid_hash_time ((tt & -4), &hi, key); if ((hi.B[0] == hj.B[2]) && (hi.B[1] == hj.B[1]) && (hi.B[2] == hj.B[0])) found = 1; if ((hi.B[3] == hj.B[2]) && (hi.B[4] == hj.B[1]) && (hi.B[5] == hj.B[0])) found = 1; securid_hash_time (((tt+4) & -4), &hi, key); if ((hi.B[0] == hj.B[2]) && (hi.B[1] == hj.B[1]) && (hi.B[2] == hj.B[0])) found = 1; if (found == 1) { strncpy(securid_db->used_toks[tok_num], pass, SECURID_MAX_TOK_LEN); if(tok_num < SECURID_MAX_TOK_NUM - 1) securid_db->used_toks[tok_num + 1][0] = '\0'; if(auth_dbputu(user,ap)) { sosay(0, "database error"); auth_dbclose(); /* Unlock DB file and close it */ return(1); } auth_dbclose(); /* ok */ return 0; } auth_dbclose(); /* wrong token */ return(1); } int secichallng(user,buf,bs) char *user; char *buf; int bs; { return(0); } int seciverify(user,pass,ap,rbuf) char *user; char *pass; Auth *ap; char *rbuf; { int ret_val; strlcpy(rbuf,"Permission Denied.",MAXSTR); // if(!challenged) // return(1); ret_val = user_lookup(user, pass, ap); if(ret_val == 0) strlcpy(rbuf,"ok",MAXSTR); return(ret_val); } seciset(user,pass,ap,rbuf) char *user; char *pass; Auth *ap; char *rbuf; { int status; Cfg *cfp; char *sdhost = NULL; t_securid_db *securid_db; if((pass == (char *)0) || (*pass == '\0') { strlcpy(rbuf,"NULL passwords not permitted for SecurID.",MAXSTR); return(1); } if(ap == NULL) { strlcpy(rbuf,"Database error.",MAXSTR); return(1); } securid_db = (t_securid_db *)ap->authproto_rec.buf; if(!ap->authproto_rec.active || strncmp(securid_db->seed, pass, SECURID_MAX_TOK_LEN)) { securid_db->used_toks[0][0] = '\0'; /* clean out the used tok list if the seed has changed */ } strncpy(securid_db->seed, pass, SECURID_MAX_SEED_LEN); ap->authproto_rec.active = 1; if(auth_dbputu(user,ap)) { sosay(0, "database error"); return(1); } snprintf(rbuf,MAXSTR,"SecurID seed for %s is %s",user, pass); return(0); } #endif