/* ****************************************************************************** * INTERPEAK SOURCE FILE * * Document no: @(#) $Name: VXWORKS_ITER40_2019102207 $ $RCSfile: ipcom_auth.c,v $ $Revision: 1.41.10.4 $ * $Source: /home/interpeak/CVSRoot/ipcom/src/ipcom_auth.c,v $ * $Author: jren $ * $State: Exp $ $Locker: $ * * INTERPEAK_COPYRIGHT_STRING * Design and implementation by Lennart Bang ****************************************************************************** */ /* **************************************************************************** * 1 DESCRIPTION **************************************************************************** */ /* **************************************************************************** * 2 CONFIGURATION **************************************************************************** */ #ifndef IPCOM_KERNEL #define IPCOM_KERNEL #endif #include "ipcom_config.h" #ifdef IP_PORT_OSE5 #include "sysparam.h" #endif /* **************************************************************************** * 3 INCLUDE FILES **************************************************************************** */ #define IPCOM_USE_CLIB_PROTO #include "ipcom_clib.h" #include "ipcom_auth.h" #include "ipcom_err.h" #include "ipcom_list.h" #include "ipcom_syslog.h" #include "ipcom_os.h" #include "ipcom_shell.h" #ifdef IPMCRYPTO #include #include #define IPCOM_AUTH_USE_HASH #endif #ifdef IPCRYPTO #include "ipcrypto_config.h" #include #include #define IPCOM_AUTH_USE_HASH #endif /* **************************************************************************** * 4 DEFINES **************************************************************************** */ #define IPCOM_SYSLOG_PRIORITY IPCOM_SYSLOG_IPCOM_PRIORITY #define IPCOM_SYSLOG_FACILITY IPCOM_LOG_IPCOM /* **************************************************************************** * 5 TYPES **************************************************************************** */ /* *=========================================================================== * Ipcom_auth_user *=========================================================================== */ typedef struct Ipcom_auth_user_struct { Ipcom_list list; char* username; char* password; Ip_uid_t userid; Ip_bool pwdhash; /* Cleartext or hashed password */ char salt[IPCOM_AUTH_SALT_LENGTH_MAX]; int salt_len; } Ipcom_auth_user; /* *=========================================================================== * Global ipcom_auth data *=========================================================================== * Internal global Ipcom_auth data. */ typedef struct Ipcom_auth_data_struct { Ipcom_mutex mutex; Ipcom_list users_head; } Ipcom_auth_data; /* **************************************************************************** * 6 EXTERN PROTOTYPES **************************************************************************** */ IP_PUBLIC int ipcom_cmd_user(int argc, char **argv); /* **************************************************************************** * 7 LOCAL PROTOTYPES **************************************************************************** */ IP_STATIC Ip_err ipcom_auth_init(void *unused); IP_PUBLIC Ip_err ipcom_auth_old_and_unsecure_hash_rtn(const char *password, const char *salt, Ip_size_t salt_len, char *buf); #ifdef IPCOM_AUTH_USE_HASH IP_STATIC Ip_err (*ipcom_auth_hash_rtn)(const char *password, const char *salt, Ip_size_t salt_len, char *buf) = IP_NULL; #endif IP_STATIC Ip_err ipcom_auth_userid_get(Ip_uid_t *userid); /* **************************************************************************** * 8 DATA **************************************************************************** */ /* *=========================================================================== * Global ipcom_auth data *=========================================================================== */ IP_STATIC Ipcom_auth_data ipcom_auth; IP_STATIC Ipcom_once_t ipcom_auth_once = IPCOM_ONCE_INIT; #ifdef IPCOM_AUTH_USE_HASH IP_STATIC Ip_err ipcom_auth_decode(const Ip_u8* in, int inl, Ip_u8* out, int* outl); #endif /* **************************************************************************** * 9 STATIC FUNCTIONS **************************************************************************** */ /* *=========================================================================== * ipcom_auth_userid_get *=========================================================================== * Description: Get next available userid * Parameters: * Returns: * */ IP_STATIC Ip_err ipcom_auth_userid_get(Ip_uid_t *userid) { Ipcom_auth_user *user; Ip_uid_t userid_tmp; Ip_err err = IPCOM_SUCCESS; Ip_bool flag; /* Find next available userid */ for (userid_tmp = 0; (userid_tmp < ipcom_auth.users_head.size) && (userid_tmp < (Ip_uid_t)(~0)); userid_tmp++) { flag = IP_FALSE; for (user = IPCOM_LIST_FIRST(&ipcom_auth.users_head); user; user = IPCOM_LIST_NEXT(&user->list)) { if(userid_tmp == user->userid) { flag = IP_TRUE; /* Userid is in use */ break; } } if (flag == IP_FALSE) break; /* Userid is not in use */ } *userid = userid_tmp; if (*userid == (Ip_uid_t)(~0)) err = IPCOM_ERR_FAILED; return err; } #ifdef IPCOM_AUTH_USE_HASH /* *=========================================================================== * ipcom_auth_decode *=========================================================================== * Description: Decode base64 encoded string * Parameters: * Returns: * */ IP_STATIC Ip_err ipcom_auth_decode(const Ip_u8* in, int inl, Ip_u8* out, int* outl) { EVP_ENCODE_CTX ctx; int i, outl_tmp = 0; EVP_DecodeInit(&ctx); i = EVP_DecodeUpdate(&ctx, out, outl, in, inl); outl_tmp = *outl + outl_tmp; if (i < 0) return IPCOM_ERR_FAILED; i = EVP_DecodeFinal(&ctx, out + outl_tmp, outl); if (i < 0) return IPCOM_ERR_FAILED; outl_tmp = *outl + outl_tmp; *outl = outl_tmp; return IPCOM_SUCCESS; } #endif /* IPCOM_AUTH_USE_HASH */ /* *=========================================================================== * ipcom_auth_init *=========================================================================== * Description: * Parameters: * Returns: * */ IP_STATIC Ip_err ipcom_auth_init(void *unused) { Ip_err retval; (void)unused; ipcom_memset(&ipcom_auth, 0, sizeof(Ipcom_auth_data)); ipcom_list_init(&ipcom_auth.users_head); retval = ipcom_mutex_create(&ipcom_auth.mutex); ip_assert(retval == IPCOM_SUCCESS); if (retval != IPCOM_SUCCESS) return retval; return IPCOM_SUCCESS; } /* **************************************************************************** * 10 GLOBAL FUNCTIONS **************************************************************************** */ /* **************************************************************************** * 11 PUBLIC FUNCTIONS **************************************************************************** */ /* *=========================================================================== * ipcom_auth_useradd *=========================================================================== * Description: Add IPCOM user with a cleartext password. * Parameters: * Returns: * */ IP_PUBLIC Ip_err ipcom_auth_useradd(const char *username, const char *password, Ip_uid_t userid) { /* Cleartext password */ return ipcom_auth_useradd_hash(username, password, userid, IP_FALSE, ""); } /* *=========================================================================== * ipcom_auth_useradd_hash *=========================================================================== * Description: Add IPCOM user with a hashed or cleartext password * Parameters: * Returns: * */ IP_PUBLIC Ip_err ipcom_auth_useradd_hash(const char *username, const char *password, Ip_uid_t userid, Ip_bool hash, const char *salt) { Ipcom_auth_user *user = IP_NULL; Ip_err err; #ifdef IPCOM_AUTH_USE_HASH Ip_u8 hash_buf[IPCOM_AUTH_PASSWORD_MAX]; int salt_len; #else IPCOM_UNUSED_ARG(salt); #endif err = ipcom_once(&ipcom_auth_once, ipcom_auth_init, IP_NULL); if (err != IPCOM_SUCCESS) return err; if (!username || ipcom_strlen(username) >= IPCOM_AUTH_USERNAME_MAX || !password || ipcom_strlen(password) >= IPCOM_AUTH_PASSWORD_MAX) return IPCOM_ERR_INVALID_ARG; ipcom_mutex_lock(ipcom_auth.mutex); /* Get a userid if not provided */ if (userid == (Ip_uid_t) (~0u)) { if ((err = ipcom_auth_userid_get(&userid)) != IPCOM_SUCCESS) goto leave; } /* Check for duplicate. */ for (user = IPCOM_LIST_FIRST(&ipcom_auth.users_head); user; user = IPCOM_LIST_NEXT(&user->list)) if (ipcom_strcmp(username, user->username) == 0 || user->userid == userid) { err = IPCOM_ERR_DUPLICATE; user = IP_NULL; goto leave; } /* Create new user. */ user = ipcom_calloc(1, sizeof(Ipcom_auth_user)); if (user == IP_NULL) { err = IPCOM_ERR_NO_MEMORY; goto leave; } /* Init user. */ user->pwdhash = hash; /* Hashed or cleartext */ user->userid = userid; user->username = ipcom_strdup(username); user->password = ipcom_strdup(password); if (user->username == IP_NULL || user->password == IP_NULL) { err = IPCOM_ERR_NO_MEMORY; goto leave; } if (hash == IP_TRUE) { #ifdef IPCOM_AUTH_USE_HASH /* Decode the SALT */ if (salt) { if ((ipcom_auth_decode((Ip_u8*)salt, (int)ipcom_strlen(salt), hash_buf, &salt_len) != IPCOM_SUCCESS) || (salt_len > IPCOM_AUTH_SALT_LENGTH_MAX)) { err = IPCOM_ERR_FAILED; goto leave; } ipcom_memcpy(user->salt, hash_buf, salt_len); user->salt_len = salt_len; } #else err = IPCOM_ERR_NOT_SUPPORTED; goto leave; #endif /* IPCOM_AUTH_USE_HASH */ } ipcom_list_insert_last(&ipcom_auth.users_head, &user->list); leave: if (err != IPCOM_SUCCESS) { if (user) { if (user->username) ipcom_free(user->username); if (user->password) ipcom_free(user->password); ipcom_free(user); } } ipcom_mutex_unlock(ipcom_auth.mutex); return err; /*lint !e429 Custodial pointer 'user' has not been freed or returned */ } /* *=========================================================================== * ipcom_auth_userdel *=========================================================================== * Description: Delete IPCOM user. * Parameters: * Returns: * */ IP_PUBLIC Ip_err ipcom_auth_userdel(const char *username) { Ipcom_auth_user *user; Ip_err err; err = ipcom_once(&ipcom_auth_once, ipcom_auth_init, IP_NULL); if (err != IPCOM_SUCCESS) return err; ip_assert(username); ipcom_mutex_lock(ipcom_auth.mutex); /* Find user */ for (user = IPCOM_LIST_FIRST(&ipcom_auth.users_head); user; user = IPCOM_LIST_NEXT(&user->list)) if (ipcom_strcmp(username, user->username) == 0) break; if (user == IP_NULL) { err = IPCOM_ERR_NOT_FOUND; goto leave; } ipcom_free(user->username); ipcom_free(user->password); /* Remove and free user. */ ipcom_list_remove(&user->list); ipcom_free(user); leave: ipcom_mutex_unlock(ipcom_auth.mutex); return err; } /* *=========================================================================== * ipcom_auth_userget *=========================================================================== * Description: * Parameters: * Returns: * */ IP_PUBLIC Ip_err ipcom_auth_userget(const char *username, Ipcom_auth_userinfo *userinfo) { Ipcom_auth_user *user; Ip_err err; err = ipcom_once(&ipcom_auth_once, ipcom_auth_init, IP_NULL); if (err != IPCOM_SUCCESS) return err; ip_assert(username); ipcom_mutex_lock(ipcom_auth.mutex); #ifdef IP_PORT_OSE5 { char user[IPCOM_AUTH_USERNAME_MAX]; char password[IPCOM_AUTH_PASSWORD_MAX]; if (sysparam_readattr_string("login", "username", user, sizeof(user)) == 0 && sysparam_readattr_string("login", "password", password, sizeof(password)) == 0 && ipcom_strcmp(user, username) == 0) { if (userinfo) { ipcom_memset(userinfo, 0, sizeof(Ipcom_auth_userinfo)); ipcom_strcpy(userinfo->username, username); ipcom_strcpy(userinfo->password, password); userinfo->pwdhash = IP_FALSE;/* Cleartext */ } goto leave; } } #endif /* IP_PORT_OSE5 */ /* Find user */ for (user = IPCOM_LIST_FIRST(&ipcom_auth.users_head); user; user = IPCOM_LIST_NEXT(&user->list)) if (ipcom_strcmp(username, user->username) == 0) break; if (user == IP_NULL) { err = IPCOM_ERR_NOT_FOUND; goto leave; } /* Copy over info. */ if (userinfo) { ipcom_memset(userinfo, 0, sizeof(Ipcom_auth_userinfo)); ipcom_strncpy(userinfo->username, user->username, IPCOM_AUTH_USERNAME_MAX - 1); if(user->pwdhash == IP_TRUE) { ipcom_strncpy(userinfo->password, user->password, IPCOM_AUTH_PASSWORD_MAX - 1); ipcom_memcpy(userinfo->salt, user->salt, user->salt_len); userinfo->salt_len = user->salt_len; } else ipcom_strncpy(userinfo->password, user->password, IPCOM_AUTH_PASSWORD_MAX - 1); userinfo->userid = user->userid; userinfo->pwdhash = user->pwdhash; } leave: ipcom_mutex_unlock(ipcom_auth.mutex); return err; } /* *=========================================================================== * ipcom_auth_userlist *=========================================================================== * Description: List users * Parameters: * Returns: * */ IP_PUBLIC Ip_err ipcom_auth_userlist(Ip_uid_t *userid, Ipcom_auth_userinfo *userinfo) { Ipcom_auth_user *user; Ip_err err; if (userid == IP_NULL) return IPCOM_ERR_INVALID_ARG; if (userinfo) ipcom_memset(userinfo, 0, sizeof(Ipcom_auth_userinfo)); err = ipcom_once(&ipcom_auth_once, ipcom_auth_init, IP_NULL); if (err != IPCOM_SUCCESS) return IP_NULL; ipcom_mutex_lock(ipcom_auth.mutex); /* Find user */ for (user = IPCOM_LIST_FIRST(&ipcom_auth.users_head); user; user = IPCOM_LIST_NEXT(&user->list)) if (*userid == user->userid) break; /* No user found, return first user's userid. */ if (user == IP_NULL) { user = IPCOM_LIST_FIRST(&ipcom_auth.users_head); *userid = user ? user->userid : ~0u; err = IPCOM_ERR_NOT_FOUND; goto leave; } /* Copy over userinfo. */ if (userinfo) { ipcom_strncpy(userinfo->username, user->username, sizeof(userinfo->username)); ipcom_strncpy(userinfo->password, user->password, sizeof(userinfo->password)); ip_assert(userinfo->username[sizeof(userinfo->username)-1] == 0); ip_assert(userinfo->password[sizeof(userinfo->password)-1] == 0); userinfo->userid = user->userid; userinfo->pwdhash = user->pwdhash; } /* Next user's userid. */ user = IPCOM_LIST_NEXT(&user->list); *userid = user ? user->userid : ~0u; leave: ipcom_mutex_unlock(ipcom_auth.mutex); return err; } #ifdef IPCOM_AUTH_USE_HASH /* *=========================================================================== * ipcom_auth_hash_rtn_install *=========================================================================== * Description: Install hash routine * Parameters: * Returns: * */ IP_PUBLIC Ip_err ipcom_auth_hash_rtn_install(Ipcom_auth_hash_hook hash_rtn, Ip_size_t digest) { Ip_err err = IPCOM_SUCCESS; IPCOM_UNUSED_ARG(digest); err = ipcom_once(&ipcom_auth_once, ipcom_auth_init, IP_NULL); if (err != IPCOM_SUCCESS) return err; ipcom_mutex_lock(ipcom_auth.mutex); ipcom_auth_hash_rtn = hash_rtn; ipcom_mutex_unlock(ipcom_auth.mutex); return err; } /* *=========================================================================== * ipcom_auth_hash *=========================================================================== * Description: Hash passwords * Parameters: password - the input unhashed password string * salt - buffer to pass the salt, IPCOM_AUTH_SALT_LENGTH bytes * buf - buffer of length IPCOM_AUTH_PASSWORD_MAX in which * to store the hashed password string * Returns: */ IP_PUBLIC Ip_err ipcom_auth_hash(const char *password, const char *salt, Ip_size_t salt_len, char *buf) { if (ipcom_auth_hash_rtn == IP_NULL) return ipcom_auth_default_hash_rtn(password, salt, salt_len, buf); else if((*ipcom_auth_hash_rtn) (password, salt, salt_len, buf) != IPCOM_SUCCESS) return (IPCOM_ERR_FAILED); return (IPCOM_SUCCESS); } /* *=========================================================================== * ipcom_auth_default_hash_rtn *=========================================================================== * Description: Default hash routine * Parameters: * Returns: * */ IP_PUBLIC Ip_err ipcom_auth_default_hash_rtn(const char *password, const char *salt, Ip_size_t salt_len, char *buf) { char buf1[IPCOM_AUTH_PASSWORD_MAX]; EVP_ENCODE_CTX ctx; int outl; int i; unsigned char* unsigned_buf = (unsigned char*)buf; /* Store salt + password in buffer */ if (salt_len > IPCOM_AUTH_SALT_LENGTH_MAX || (salt_len+ipcom_strlen(password)+1 > IPCOM_AUTH_PASSWORD_MAX-1)) return IPCOM_ERR_INVALID_ARG; ipcom_memcpy(buf1, salt, salt_len); ipcom_strcpy(&buf1[salt_len], password); /* Hash buffer */ SHA256((unsigned char*)buf1, salt_len+ipcom_strlen(password), unsigned_buf); /* Base64 encode hash */ EVP_EncodeInit(&ctx); EVP_EncodeUpdate(&ctx, unsigned_buf, &outl, unsigned_buf, 32); EVP_EncodeFinal(&ctx, unsigned_buf+outl, &outl); /* Remove terminating line feed */ for (i=(int)(ipcom_strlen((char*)unsigned_buf)-1); i>0 && unsigned_buf[i]=='\n';i--) unsigned_buf[i] = 0; return IPCOM_SUCCESS; } /* *=========================================================================== * ipcom_auth_hash_get *=========================================================================== * Description: Obsolete function. Only kept in order to simplify the upgrade * process. loginLib.c has a dependency to this function and we * do not want to make changes that require an update to * loginLib.c * Parameters: * Returns: * */ IP_PUBLIC Ip_err ipcom_auth_hash_get(Ip_size_t *digest) { *digest = SHA256_DIGEST_LENGTH; return IPCOM_SUCCESS; } /* *=========================================================================== * ipcom_auth_old_and_unsecure_hash_rtn *=========================================================================== * Description: * Parameters: * Returns: * */ IP_PUBLIC Ip_err ipcom_auth_old_and_unsecure_hash_rtn(const char *password, const char *salt, Ip_size_t salt_len, char *buf) { int ix; Ip_u32 magic = 31695317; Ip_u32 passwdInt = 0; IPCOM_UNUSED_ARG(salt); IPCOM_UNUSED_ARG(salt_len); if (ipcom_strlen(password) < 8 || ipcom_strlen(password) > 40) { return (IPCOM_ERR_FAILED); } for (ix = 0; ix < ipcom_strlen(password); ix++) /* Sum the string */ passwdInt += (password[ix]) * (ix+1) ^ (ix+1); ipcom_sprintf (buf, "%u", (long) (passwdInt * magic)); /* Convert integer to string */ /* Make encrypted passwd printable */ for (ix = 0; ix < ipcom_strlen (buf); ix++) { if (buf[ix] < '3') buf[ix] = (char)(buf[ix] + '!'); /* Arbitrary */ if (buf[ix] < '7') buf[ix] = (char)(buf[ix] + '/'); /* Arbitrary */ if (buf[ix] < '9') buf[ix] = (char)(buf[ix] + 'B'); /* Arbitrary */ } return (IPCOM_SUCCESS); } #endif /* IPCOM_AUTH_USE_HASH */ /* **************************************************************************** * END OF FILE **************************************************************************** */