/* ipwps_credentials.c - IPWPS Credentials module */ /* * Copyright (c) 2009 Wind River Systems, Inc. * * The right to copy, distribute, modify, or otherwise make use * of this software may be licensed only pursuant to the terms * of an applicable Wind River license agreement. * */ /* modification history -------------------- 01a,28Apr09,mry Created */ /* DESCRIPTION: * =========== * Implements the IPWPS Credential configuration/auto-generation. */ /* **************************************************************************** * 1 DESCRIPTION **************************************************************************** */ /* **************************************************************************** * 2 CONFIGURATION **************************************************************************** */ #include "ipwps_config.h" /* **************************************************************************** * 3 INCLUDE FILES **************************************************************************** */ #define IPCOM_USE_CLIB_PROTO #include #include #include #include #include #include #include #include "ipwps_core.h" #include "ipwps_credentials.h" #include "ipwps_debug.h" /* **************************************************************************** * 4 DEFINES **************************************************************************** */ /* **************************************************************************** * 5 TYPES **************************************************************************** */ typedef struct Ipwps_credential_sysvar_list_st { char *sysvar_netidx; char *sysvar_ssid; char *sysvar_auth; char *sysvar_encr; char *sysvar_keyidx; char *sysvar_netkey; char *sysvar_8021x; char *sysvar_eapid; char *sysvar_eaptype; } Ipwps_credential_sysvar_list; /* **************************************************************************** * 6 EXTERN PROTOTYPES **************************************************************************** */ extern IP_GLOBAL Ip_err ipwps_parse_hex_sysvar(char *sysvar, Ip_u8 *val, Ip_u16 size); /* **************************************************************************** * 7 LOCAL PROTOTYPES **************************************************************************** */ /* * **************************************************************************** * 8 DATA **************************************************************************** */ /* **************************************************************************** * 9 STATIC FUNCTIONS **************************************************************************** */ IP_STATIC IP_CONST char *ipwps_credentials_method_name(Ipwps_credential_method cred_method); IP_STATIC Ip_err ipwps_credentials_set_method(Ipwps_ctx* ctx, Ipwps_credential_method cred_method); IP_STATIC Ip_err ipwps_credentials_auto_new(Ipwps_ctx* ctx); IP_STATIC Ip_err ipwps_credentials_default_set(Ipwps_ctx* ctx); IP_STATIC Ip_err ipwps_credentials_interact_add(Ipwps_ctx* ctx, Ip_u16 setid); IP_STATIC Ip_err ipwps_credentials_delete(Ipwps_ctx* ctx, Ip_u16 setid); IP_STATIC Ip_err ipwps_credentials_duplicate_builtin_reg(Ipwps_ctx* ctx); IP_STATIC Ip_err ipwps_credentials_duplicate_set(Ipwps_ctx* ctx, Ip_u16 to_setid, Ip_u16 from_setid); IP_STATIC Ipwps_credential_set *ipwps_credentials_get_cred_ptr(Ipwps_ctx* ctx, Ip_u16 setid); IP_STATIC Ip_err ipwps_credentials_generate_new(Ipwps_ctx* ctx, Ipwps_credential_set *cred); IP_STATIC Ip_err ipwps_credentials_default_retrieve(Ipwps_ctx* ctx, Ipwps_credential_set *cred); IP_STATIC Ip_err ipwps_credentials_interact_retrieve(Ipwps_ctx* ctx, Ipwps_credential_set *cred); IP_STATIC Ip_err ipwps_credentials_retrieve_from_sysvars(Ipwps_credential_set *cred, Ipwps_credential_sysvar_list *syslist); IP_STATIC Ip_err ipwps_credentials_verify_allhex(IP_CONST char *string); IP_STATIC Ip_err ipwps_credentials_verify_allascii(IP_CONST char *string); IP_STATIC Ip_err ipwps_credentials_verify_netkey(IP_CONST char *netkey); IP_GLOBAL Ip_err ipwps_credentials_gen_random_ascii(char *buf, Ip_u16 size); IP_GLOBAL Ip_err ipwps_credentials_gen_random_hex(char *buf, Ip_u16 size); IP_GLOBAL Ip_err ipwps_credentials_notify_register(Ipwps_ctx* ctx, Ipwps_credentials_notify_fn notify_fn); IP_GLOBAL Ip_err ipwps_credentials_notify_deregister(Ipwps_ctx* ctx, Ipwps_credentials_notify_fn notify_fn); IP_STATIC void ipwps_credentials_notify(Ipwps_ctx* ctx, Ip_u16 setid, Ipwps_credential_notify_type ntype); /* **************************************************************************** * 10 GLOBAL FUNCTIONS **************************************************************************** */ IP_GLOBAL Ip_err ipwps_credentials_add_set(Ipwps_ctx* ctx, Ip_u16 setid, Ipwps_credential_set *from_cred); IP_GLOBAL void ipwps_credentials_remove_set(Ipwps_ctx* ctx, Ip_u16 setid); /* *=========================================================================== * ipwps_credentials_init *=========================================================================== * Description: * Parameters: * Returns: * */ IP_GLOBAL Ip_err ipwps_credentials_init(Ipwps_ctx* ctx) { char method[IPWPS_CREDENTIALS_CONFIG_METHOD_STRLEN]; Ip_size_t len; Ipwps_credential_method cred_method; Ip_err rc = IPCOM_SUCCESS; ip_assert(ctx); if (ctx->public.daemon_status < IPWPSD_STATUS_CONFIGURED) { IPCOM_LOG2(CRIT, "ipwps_credentials_init :: Error! Invalid daemon state %s (%d)", ipwps_daemon_status(&ctx->public), ctx->public.daemon_status); return IPCOM_ERR_FAILED; } /* Just delete the enrollee credentials when reinitializing */ ipcom_memset(&ctx->credentials.enrollee_credentials, 0, sizeof(Ipwps_credential_set)); ctx->credentials.num_enrollee_creds = 0; len = sizeof(method); if (!ipcom_sysvar_get(IPWPS_SYSVAR_CREDENTIAL_METHOD, method, &len)) { /* This is a valid thing to have. If the sysvar is missing, it means the credentials module was not selected. * We will return a success and let other apps that depend on this complain if they need it. * This is acceptable if the device is running an Enrollee only. */ ipcom_strncpy(ctx->public.coop_info.credentials_config_method, ipwps_credentials_method_name(IPWPS_CERDENTIAL_METHOD_NOTSET), IPWPS_CREDENTIALS_CONFIG_METHOD_STRLEN); IPCOM_LOG1(INFO, "Failed to get %s sysvar. Credentials Module is disabled.", IPWPS_SYSVAR_CREDENTIAL_METHOD); return IPCOM_SUCCESS; } if (ipcom_strcmp(method, IPWPS_CRED_CONFIG_METHOD_AUTO) == 0) { cred_method = IPWPS_CERDENTIAL_METHOD_AUTO; } else if (ipcom_strcmp(method, IPWPS_CRED_CONFIG_METHOD_DEFAULT) == 0) { cred_method = IPWPS_CERDENTIAL_METHOD_DEFAULT; } else if (ipcom_strcmp(method, IPWPS_CRED_CONFIG_METHOD_INTERACT) == 0) { cred_method = IPWPS_CERDENTIAL_METHOD_INTERACTIVE; } else { IPCOM_LOG2(ERR, "ipwps_credentials_init :: Invalid config method \"%s\" specified in sysvar %s.", method, IPWPS_SYSVAR_CREDENTIAL_METHOD); return IPCOM_ERR_FAILED; } if (ipwps_credentials_set_method(ctx, cred_method) != IPCOM_SUCCESS) { return IPCOM_ERR_FAILED; } /* In case we are init in auto mode, we need to gen a new set of credentials */ if ((cred_method == IPWPS_CERDENTIAL_METHOD_AUTO) && !ctx->credentials.ap_credentials.valid) rc = ipwps_credentials_auto_new(ctx); return rc; } /* *=========================================================================== * ipwps_credentials_shutdown *=========================================================================== * Description: * Parameters: * Returns: * */ IP_GLOBAL Ip_err ipwps_credentials_shutdown(Ipwps_ctx* ctx) { ip_assert(ctx); /* Leave AP and registrar credentials alone */ ipcom_memset(&ctx->credentials.enrollee_credentials, 0, sizeof(ctx->credentials.enrollee_credentials)); ctx->credentials.num_enrollee_creds =0; ipcom_memset(ctx->credential_notify_fn, 0, IPWPS_MAX_CREDENTIAL_NOTIFY_FNS*sizeof(void *)); return IPCOM_SUCCESS; } /* *=========================================================================== * ipwps_credentials_shutdown *=========================================================================== * Description: * Parameters: * Returns: * */ IP_GLOBAL Ip_err ipwps_credentials_clear(Ipwps_ctx* ctx) { ip_assert(ctx); ipcom_memset(&ctx->credentials, 0, sizeof(ctx->credentials)); return IPCOM_SUCCESS; } /* *=========================================================================== * ipwps_credentials_handle_event *=========================================================================== * Description: * Parameters: * Returns: * */ IP_GLOBAL Ip_err ipwps_credentials_handle_event(Ipwps_ctx* ctx) { Ip_err rc = IPCOM_ERR_FAILED; Ipwps_event_msg *rcv_event_msg = IPWPS_CTX_RCVD_EVENT_MSG(ctx); Ipwps_credential_method cred_method; Ip_u16 cred_setno; ip_assert(ctx); if (ctx->event != IPWPS_IPD_EVENT_WPSAPI) { IPCOM_LOG1(ERR, "ipwps_credentials_handle_event :: Error! Unsupported event (%d)", ctx->event); rc = IPCOM_ERR_NOT_SUPPORTED; goto cred_resp; } if (ctx->rcvd_ipd_msg.wps_msg_type.wpsapi != IPWPS_MSG_TYPE_WPSAPI_CREDENTIAL_EVENT) { IPCOM_LOG1(ERR, "ipwps_credentials_handle_event :: Received WPSAPI event with UNEXPECTED wps_msg_type %d.", ctx->rcvd_ipd_msg.wps_msg_type); rc = IPCOM_ERR_FAILED; goto cred_resp; } switch (rcv_event_msg->event_type.credential_event) { case IPWPS_CREDENTIAL_EVENT_SETMETHOD: if (!rcv_event_msg->event_data.valid) { IPCOM_LOG0(ERR, "Ipwps_pin_handle_event :: Invalid event data"); rc = IPCOM_ERR_FAILED; goto cred_resp; } cred_method = rcv_event_msg->event_data.u.credential_method; #ifdef IPWPS_DEBUG_CEREDENTIALS IPCOM_LOG2(DEBUG2, "ipwps_credentials_handle_event :: Received IPWPS_CREDENTIAL_EVENT_SETMETHOD event with cred_method %d (%s)", cred_method, ipwps_credentials_method_name(cred_method)); #endif rc = ipwps_credentials_set_method(ctx, cred_method); break; case IPWPS_CREDENTIAL_EVENT_ADDCRED: if (!rcv_event_msg->event_data.valid) { IPCOM_LOG0(ERR, "Ipwps_pin_handle_event :: Invalid event data"); rc = IPCOM_ERR_FAILED; goto cred_resp; } cred_setno = rcv_event_msg->event_data.u.credential_setno; #ifdef IPWPS_DEBUG_CEREDENTIALS IPCOM_LOG1(DEBUG2, "ipwps_credentials_handle_event :: Received IPWPS_CREDENTIAL_EVENT_ADDCRED event with cred_setno %d", cred_setno); #endif rc = ipwps_credentials_interact_add(ctx, cred_setno); break; case IPWPS_CREDENTIAL_EVENT_DELCRED: if (!rcv_event_msg->event_data.valid) { IPCOM_LOG0(ERR, "Ipwps_pin_handle_event :: Invalid event data"); rc = IPCOM_ERR_FAILED; goto cred_resp; } cred_setno = rcv_event_msg->event_data.u.credential_setno; #ifdef IPWPS_DEBUG_CEREDENTIALS IPCOM_LOG1(DEBUG2, "ipwps_credentials_handle_event :: Received IPWPS_CREDENTIAL_EVENT_DELCRED event with cred_setno %d", cred_setno); #endif rc = ipwps_credentials_delete(ctx, cred_setno); break; case IPWPS_CREDENTIAL_EVENT_NEWCRED: #ifdef IPWPS_DEBUG_CEREDENTIALS IPCOM_LOG0(DEBUG2, "ipwps_credentials_handle_event :: Received IPWPS_CREDENTIAL_EVENT_NEWCRED event"); #endif rc = ipwps_credentials_auto_new(ctx); break; default: IPCOM_LOG1(ERR, "ipwps_credentials_handle_event :: Invalid Credential event %d", rcv_event_msg->event_type.credential_event); rc = IPCOM_ERR_FAILED; break; } cred_resp: IPWPS_PREPARE_RESPONSE_MSG(ctx, rc); ipwps_send_response_msg(ctx); return rc; } /* *=========================================================================== * ipwps_credentials_set_method *=========================================================================== * Description: Set a credential method. In case of "default" method, the * AP credentials, and if applicable 1st built-in registrar credential set, * are overwritten. * Parameters: * Returns: * */ IP_STATIC Ip_err ipwps_credentials_set_method(Ipwps_ctx* ctx, Ipwps_credential_method cred_method) { Ip_err rc = IPCOM_SUCCESS; IP_CONST char *method; ip_assert(ctx); method = ipwps_credentials_method_name(cred_method); switch (cred_method) { case IPWPS_CERDENTIAL_METHOD_AUTO: case IPWPS_CERDENTIAL_METHOD_DEFAULT: case IPWPS_CERDENTIAL_METHOD_INTERACTIVE: break; default: IPCOM_LOG1(ERR, "ipwps_credentials_set_method :: Invalid cred_method %d", cred_method); return IPCOM_ERR_FAILED; } /* Add sysvar so that when we reconfig, it is enabled again */ IPWPS_SYSVARSET(IPWPS_SYSVAR_CREDENTIAL_METHOD, method, IPCOM_ERR_FAILED); ipcom_strncpy(ctx->public.coop_info.credentials_config_method, method, IPWPS_CREDENTIALS_CONFIG_METHOD_STRLEN); ctx->public.coop_info.cred_method = cred_method; ctx->public.wps_credentials_module.enabled = IP_TRUE; ctx->public.wps_credentials_module.status = IPWPSD_MODULE_STATUS_READY; if (cred_method == IPWPS_CERDENTIAL_METHOD_DEFAULT) rc = ipwps_credentials_default_set(ctx); return rc; } /* *=========================================================================== * ipwps_credentials_auto_new *=========================================================================== * Description: Auto-generate a new credential set. * The AP credentials, and if applicable 1st built-in registrar credential set, * are overwritten. * Parameters: * Returns: * */ IP_STATIC Ip_err ipwps_credentials_auto_new(Ipwps_ctx* ctx) { Ipwps_credential_set cred; #ifdef IPWPS_DEBUG_CEREDENTIALS IPCOM_LOG0(DEBUG2, "ipwps_credentials_auto_new :: called."); #endif ip_assert(ctx); if (ctx->public.coop_info.cred_method != IPWPS_CERDENTIAL_METHOD_AUTO) { IPCOM_LOG2(ERR, "Auto-generating new credentials is only supported for \"%s\" method (current method = \"%s\").", IPWPS_CRED_CONFIG_METHOD_AUTO, ctx->public.coop_info.credentials_config_method); return IPCOM_ERR_NOT_SUPPORTED; } /* Auto gen new credentials for cred */ if (ipwps_credentials_generate_new(ctx, &cred) != IPCOM_SUCCESS) { IPCOM_LOG0(ERR, "ipwps_credentials_interact_add :: Failed to geherate new Credentials"); return IPCOM_ERR_FAILED; } cred.valid = IP_TRUE; if (ipwps_credentials_add_set(ctx, IPWPS_CREDENTIAL_AP_SETID, &cred) != IPCOM_SUCCESS) { IPCOM_LOG0(ERR, "ipwps_credentials_auto_new :: Failed to add new AP credential set"); return IPCOM_ERR_FAILED; } return ipwps_credentials_duplicate_builtin_reg(ctx); } /* *=========================================================================== * ipwps_credentials_default_set *=========================================================================== * Description: Add the default AP credential set. * The AP credentials, and if applicable 1st built-in registrar credential set, * are overwritten. * Parameters: * Returns: * */ IP_STATIC Ip_err ipwps_credentials_default_set(Ipwps_ctx* ctx) { Ipwps_credential_set cred; #ifdef IPWPS_DEBUG_CEREDENTIALS IPCOM_LOG0(DEBUG2, "ipwps_credentials_default_set :: called."); #endif ip_assert(ctx); if (ctx->public.coop_info.cred_method != IPWPS_CERDENTIAL_METHOD_DEFAULT) { IPCOM_LOG2(ERR, "Resetting default credentials is only supported for \"%s\" method (current method = \"%s\").", IPWPS_CRED_CONFIG_METHOD_DEFAULT, ctx->public.coop_info.credentials_config_method); return IPCOM_ERR_NOT_SUPPORTED; } /* Verify syvars and copy values into cred */ if (ipwps_credentials_default_retrieve(ctx, &cred) != IPCOM_SUCCESS) { IPCOM_LOG0(ERR, "ipwps_credentials_interact_add :: Failed to set default Credentials"); return IPCOM_ERR_FAILED; } cred.valid = IP_TRUE; if (ipwps_credentials_add_set(ctx, IPWPS_CREDENTIAL_AP_SETID, &cred) != IPCOM_SUCCESS) { IPCOM_LOG0(ERR, "ipwps_credentials_default_set :: Failed to add new AP credential set"); return IPCOM_ERR_FAILED; } return ipwps_credentials_duplicate_builtin_reg(ctx); } /* *=========================================================================== * ipwps_credentials_interact_add *=========================================================================== * Description: Add the specified interactive credential set. * If the specified credential set already exists and is valid, this call * will fail. * Parameters: * Returns: * */ IP_STATIC Ip_err ipwps_credentials_interact_add(Ipwps_ctx* ctx, Ip_u16 setid) { Ipwps_credential_set cred; #ifdef IPWPS_DEBUG_CEREDENTIALS IPCOM_LOG1(DEBUG2, "ipwps_credentials_interact_add :: called (setid = %d).", setid); #endif ip_assert(ctx); if (setid > IPWPS_NUM_CEDENTIALS_MAX) { IPCOM_LOG2(ERR, "ipwps_credentials_interact_add :: setid = %d exceeds maximum %d", setid, IPWPS_NUM_CEDENTIALS_MAX); return IPCOM_ERR_FAILED; } if (ctx->public.coop_info.cred_method != IPWPS_CERDENTIAL_METHOD_INTERACTIVE) { IPCOM_LOG2(ERR, "Adding credentials is only supported for \"%s\" method (current method = \"%s\").", IPWPS_CRED_CONFIG_METHOD_INTERACT, ctx->public.coop_info.credentials_config_method); return IPCOM_ERR_NOT_SUPPORTED; } if (ipwps_credentials_get_cred_ptr(ctx, setid)->valid) { IPCOM_LOG1(ERR, "ipwps_credentials_interact_add :: credential set #%d already exists. Please delete before adding.", setid); return IPCOM_ERR_ALREADY_INSTALLED; } /* Verify sysvars and copy values into cred */ if (ipwps_credentials_interact_retrieve(ctx, &cred) != IPCOM_SUCCESS) { IPCOM_LOG1(ERR, "ipwps_credentials_interact_add :: Failed to add Credentials for setid = %d", setid); return IPCOM_ERR_FAILED; } cred.valid = IP_TRUE; if (ipwps_credentials_add_set(ctx, setid, &cred) != IPCOM_SUCCESS) { IPCOM_LOG1(ERR, "ipwps_credentials_interact_add :: Failed to add credential set %d", setid); return IPCOM_ERR_FAILED; } if (setid == IPWPS_CREDENTIAL_AP_SETID) { ipwps_credentials_duplicate_builtin_reg(ctx); } return IPCOM_SUCCESS; } /* *=========================================================================== * ipwps_credentials_delete *=========================================================================== * Description: Delete the specified credential set. * Parameters: * Returns: * */ IP_STATIC Ip_err ipwps_credentials_delete(Ipwps_ctx* ctx, Ip_u16 setid) { #ifdef IPWPS_DEBUG_CEREDENTIALS IPCOM_LOG1(DEBUG2, "ipwps_credentials_delete :: called (setid = %d).", setid); #endif ip_assert(ctx); if (setid > IPWPS_NUM_CEDENTIALS_MAX) { IPCOM_LOG2(ERR, "ipwps_credentials_delete :: setid = %d exceeds maximum %d", setid, IPWPS_NUM_CEDENTIALS_MAX); return IPCOM_ERR_FAILED; } ipwps_credentials_remove_set(ctx, setid); return IPCOM_SUCCESS; } /* *=========================================================================== * *=========================================================================== * Description: Create a duplicate of the AP credentials into the 1st registrar * credential set if built-in registrar is available, otherwise do nothing. * This will overwrite the existing set in case of a built-in registrar. * Parameters: * Returns: * */ IP_STATIC Ip_err ipwps_credentials_duplicate_builtin_reg(Ipwps_ctx* ctx) { if ((ctx->public.coop_info.wps_role != IPWPS_ROLE_AP_WITH_BUILTIN_REGISTRAR) #ifdef IPWPS_DEBUG && (ctx->public.coop_info.wps_role != IPWPS_ROLE_TESTAPP) #endif ) return IPCOM_SUCCESS; return ipwps_credentials_duplicate_set(ctx, IPWPS_CREDENTIAL_BULTIN_REG_SETID, IPWPS_CREDENTIAL_AP_SETID); } /* *=========================================================================== * ipwps_credentials_get_cred_ptr *=========================================================================== * Description: * Parameters: * Returns: * */ IP_STATIC Ipwps_credential_set *ipwps_credentials_get_cred_ptr(Ipwps_ctx* ctx, Ip_u16 setid) { Ipwps_credential_set *cred = IP_NULL; ip_assert(ctx); ip_assert(setid <= IPWPS_NUM_CEDENTIALS_MAX); if (setid == IPWPS_CREDENTIAL_AP_SETID) { cred = &ctx->credentials.ap_credentials; } else { cred = &ctx->credentials.registrar_credentials[setid-1]; } return cred; } /* *=========================================================================== * ipwps_credentials_notify_register *=========================================================================== * Description: * Parameters: * Returns: * */ IP_GLOBAL Ip_err ipwps_credentials_notify_register(Ipwps_ctx* ctx, Ipwps_credentials_notify_fn notify_fn) { int i; ip_assert(ctx); for (i=0; i < IPWPS_MAX_CREDENTIAL_NOTIFY_FNS; i++) { if (ctx->credential_notify_fn[i] == IP_NULL) { ctx->credential_notify_fn[i] = (void *)notify_fn; break; } } if (i == IPWPS_MAX_CREDENTIAL_NOTIFY_FNS) { IPCOM_LOG1(ERR, "ipwps_credentials_notify_register :: Failed to add notify_fn 0x%x", notify_fn); return IPCOM_ERR_FAILED; } return IPCOM_SUCCESS; } /* *=========================================================================== * ipwps_credentials_notify_deregister *=========================================================================== * Description: * Parameters: * Returns: * */ IP_GLOBAL Ip_err ipwps_credentials_notify_deregister(Ipwps_ctx* ctx, Ipwps_credentials_notify_fn notify_fn) { int i; ip_assert(ctx); for (i=0; i < IPWPS_MAX_CREDENTIAL_NOTIFY_FNS; i++) { if (ctx->credential_notify_fn[i] == notify_fn) { ctx->credential_notify_fn[i] = IP_NULL; break; } } if (i == IPWPS_MAX_CREDENTIAL_NOTIFY_FNS) { IPCOM_LOG1(ERR, "ipwps_credentials_notify_deregister :: Failed to find notify_fn 0x%x", notify_fn); return IPCOM_ERR_FAILED; } return IPCOM_SUCCESS; } /* *=========================================================================== * ipwps_credentials_notify *=========================================================================== * Description: * Parameters: * Returns: * */ IP_STATIC void ipwps_credentials_notify(Ipwps_ctx* ctx, Ip_u16 setid, Ipwps_credential_notify_type ntype) { int i; ip_assert(ctx); for (i=0; i < IPWPS_MAX_CREDENTIAL_NOTIFY_FNS; i++) { Ipwps_credentials_notify_fn notify_fn = (Ipwps_credentials_notify_fn)ctx->credential_notify_fn[i]; if (notify_fn) notify_fn(ctx, setid, ntype); } } /* *=========================================================================== * ipwps_credentials_mark_registrar_cred *=========================================================================== * Description: Set/reset the "donotoffer" flag for the specified ap/registrar * credential * Parameters: * Returns: * */ IP_GLOBAL Ip_err ipwps_credentials_mark_registrar_cred(Ipwps_ctx* ctx, Ip_u16 cred_set, Ip_bool donotoffer) { Ipwps_credential_set *cred; ip_assert(ctx); if (cred_set >= IPWPS_NUM_CEDENTIALS_MAX) return IPCOM_ERR_INVALID_ARG; cred = ipwps_credentials_get_cred_ptr(ctx, cred_set+1); if (!cred) { return IPCOM_ERR_FAILED; } cred->donotoffer = donotoffer; return IPCOM_SUCCESS; } /* *=========================================================================== * ipwps_credentials_unmark_all_registrar_creds *=========================================================================== * Description: Reset the "donotoffer" flag for all ap/registrar credentials * Parameters: * Returns: * */ IP_GLOBAL Ip_err ipwps_credentials_unmark_all_registrar_creds(Ipwps_ctx* ctx) { int set_id; for (set_id = 0; set_id donotoffer = IP_FALSE; } return IPCOM_SUCCESS; } /* *=========================================================================== * ipwps_credentials_add_set *=========================================================================== * Description: * Parameters: * Returns: * */ IP_GLOBAL Ip_err ipwps_credentials_add_set(Ipwps_ctx* ctx, Ip_u16 setid, Ipwps_credential_set *from_cred) { Ipwps_credential_set *to_cred; ip_assert(ctx); ip_assert(setid <= IPWPS_NUM_CEDENTIALS_MAX); ip_assert(from_cred); if (!from_cred->valid) { IPCOM_LOG1(ERR, "ipwps_credentials_add_set :: Invalid credential to add to setid %d", setid); return IPCOM_ERR_FAILED; } to_cred = ipwps_credentials_get_cred_ptr(ctx, setid); ip_assert(to_cred); /* Remove before re-adding */ if (to_cred->valid) ipwps_credentials_remove_set(ctx, setid); if (setid == IPWPS_CREDENTIAL_AP_SETID) { ctx->credentials.ap_creds = IP_TRUE; } else { ctx->credentials.num_registrar_creds++; ip_assert(ctx->credentials.num_registrar_creds <= IPWPS_NUM_CEDENTIALS_MAX); } ipcom_memcpy(to_cred, from_cred, sizeof(Ipwps_credential_set)); to_cred->valid = IP_TRUE; /* redundant */ /* Notify any registered apps */ ipwps_credentials_notify(ctx, setid, IPWPS_CREDENTIAL_ADD); return IPCOM_SUCCESS; } /* *=========================================================================== * ipwps_credentials_remove_set *=========================================================================== * Description: * Parameters: * Returns: * */ IP_GLOBAL void ipwps_credentials_remove_set(Ipwps_ctx* ctx, Ip_u16 setid) { Ipwps_credential_set *cred; ip_assert(ctx); ip_assert(setid <= IPWPS_NUM_CEDENTIALS_MAX); cred = ipwps_credentials_get_cred_ptr(ctx, setid); ip_assert(cred); if (setid == IPWPS_CREDENTIAL_AP_SETID) { ctx->credentials.ap_creds = IP_FALSE; } else { if (!cred->valid) return; ip_assert(ctx->credentials.num_registrar_creds); ctx->credentials.num_registrar_creds--; } ipcom_memset(cred, 0, sizeof(Ipwps_credential_set)); /* Notify any registered apps */ ipwps_credentials_notify(ctx, setid, IPWPS_CREDENTIAL_DELETE); } /* *=========================================================================== * ipwps_credentials_duplicate_set *=========================================================================== * Description: * Parameters: * Returns: * */ IP_STATIC Ip_err ipwps_credentials_duplicate_set(Ipwps_ctx* ctx, Ip_u16 to_setid, Ip_u16 from_setid) { Ipwps_credential_set *from_cred; ip_assert(ctx); from_cred = ipwps_credentials_get_cred_ptr(ctx, from_setid); ip_assert(from_cred); if (!from_cred->valid) { IPCOM_LOG1(ERR, "ipwps_credentials_duplicate_set :: Invalid credential set %d", from_setid); return IPCOM_ERR_FAILED; } return ipwps_credentials_add_set(ctx, to_setid, from_cred); } /* *=========================================================================== * ipwps_credentials_generate_new *=========================================================================== * Description: Generate a new credential set based on strongest capability * (as retrieved from the driver) and randomly provide a passphrase/PSK * and SSID if one is not set. * Parameters: * Returns: * */ IP_STATIC Ip_err ipwps_credentials_generate_new(Ipwps_ctx* ctx, Ipwps_credential_set *cred) { char *sysvar; Ip_size_t len; Ip_u16 auth_cap, encr_cap; Ip_u32 netidx; ip_assert(ctx); ip_assert(cred); ipcom_memset(cred, 0 , sizeof(Ipwps_credential_set)); sysvar = IPWPS_SYSVAR_CREDENTIAL_AUTO_NETINDEX; netidx = ipcom_sysvar_get_as_int(sysvar, IPWPS_NETINDEX_DEFAULT); if ((netidx < IPWPS_NETINDEX_MIN) || (netidx > IPWPS_NETINDEX_MAX)) { cred->network_idx = IPWPS_NETINDEX_DEFAULT; } else { cred->network_idx = netidx; } sysvar = IPWPS_SYSVAR_CREDENTIAL_AUTO_SSID; len = sizeof(cred->ssid); if (ipcom_sysvar_get(sysvar, cred->ssid, &len)) { if (ipwps_credentials_verify_allascii(cred->ssid) != IPCOM_SUCCESS) { IPCOM_LOG0(ERR, "ipwps_credentials_generate_new :: Invalid auto SSID value"); return IPCOM_ERR_FAILED; } } if (ipcom_strlen(cred->ssid) == 0) { /* Auto-gen an SSID */ ipcom_memset(cred->ssid, 0, sizeof(cred->ssid)); ipwps_credentials_gen_random_ascii(cred->ssid, IPWPS_SSID_MAXLEN); } auth_cap = ctx->public.cap_info.auth_types; encr_cap = ctx->public.cap_info.encr_types; /* Always choose the highest supported capability */ if (auth_cap & IPWPS_AUTH_TYPE_WPA2PSK) { cred->auth_type = IPWPS_AUTH_TYPE_WPA2PSK; } else if (auth_cap & IPWPS_AUTH_TYPE_WPAPSK) { cred->auth_type = IPWPS_AUTH_TYPE_WPAPSK; } else if (auth_cap & IPWPS_AUTH_TYPE_OPEN) { return IPCOM_SUCCESS; /* We can only support open mode in this case, so we are done */ } else { IPCOM_LOG0(ERR, "ipwps_credentials_generate_new :: Authentication capabilities donnot allow auto credential support"); return IPCOM_ERR_FAILED; } if (encr_cap & IPWPS_ENCRYPT_TYPE_AES) { cred->encr_type = IPWPS_ENCRYPT_TYPE_AES; } else if (encr_cap & IPWPS_ENCRYPT_TYPE_TKIP) { cred->encr_type = IPWPS_ENCRYPT_TYPE_TKIP; } else { IPCOM_LOG0(ERR, "ipwps_credentials_generate_new :: Encryption capabilities donnot allow auto credential support"); return IPCOM_ERR_FAILED; } sysvar = IPWPS_SYSVAR_CREDENTIAL_AUTO_KEYLEN; cred->netkey_size = ipcom_sysvar_get_as_int(sysvar, IPWPS_PROTO_NETWORK_KEY_MAXLEN); if ((cred->netkey_size >= IPWPS_PASSPHRASE_MINLEN) && (cred->netkey_size < IPWPS_PROTO_NETWORK_KEY_MAXLEN)) { /* Auto-gen a random Passphrase */ ipcom_memset(cred->netkey, 0, sizeof(cred->netkey)); ipwps_credentials_gen_random_ascii((char *)cred->netkey, cred->netkey_size); } else { /* Auto-gen random PSK */ cred->netkey_size = IPWPS_PROTO_NETWORK_KEY_MAXLEN; /* This is to fix invalid sizes */ if (ipwps_credentials_gen_random_hex((char *)cred->netkey, cred->netkey_size)!= IPCOM_SUCCESS){ IPCOM_LOG0(ERR, "ipwps_credentials_generate_new :: Failed to gen random hex key"); return IPCOM_ERR_FAILED; } } cred->netkey_idx = IPWPS_KEYINDEX_DEFAULT; return IPCOM_SUCCESS; } /* *=========================================================================== * ipwps_credentials_default_retrieve *=========================================================================== * Description: * Parameters: * Returns: * */ IP_STATIC Ip_err ipwps_credentials_default_retrieve(Ipwps_ctx* ctx, Ipwps_credential_set *cred) { Ipwps_credential_sysvar_list syslist = { IPWPS_SYSVAR_CREDENTIAL_DEF_NETINDEX, IPWPS_SYSVAR_CREDENTIAL_DEF_SSID, IPWPS_SYSVAR_CREDENTIAL_DEF_AUTH, IPWPS_SYSVAR_CREDENTIAL_DEF_ENCR, IPWPS_SYSVAR_CREDENTIAL_DEF_KEYINDEX, IPWPS_SYSVAR_CREDENTIAL_DEF_KEY, IPWPS_SYSVAR_CREDENTIAL_DEF_8021X, IPWPS_SYSVAR_CREDENTIAL_DEF_EAP_ID, IPWPS_SYSVAR_CREDENTIAL_DEF_EAP_TYPE }; return ipwps_credentials_retrieve_from_sysvars(cred, &syslist); } /* *=========================================================================== * ipwps_credentials_interact_retrieve *=========================================================================== * Description: * Parameters: * Returns: * */ IP_STATIC Ip_err ipwps_credentials_interact_retrieve(Ipwps_ctx* ctx, Ipwps_credential_set *cred) { Ipwps_credential_sysvar_list syslist = { IPWPS_SYSVAR_CREDENTIAL_NETINDEX, IPWPS_SYSVAR_CREDENTIAL_SSID, IPWPS_SYSVAR_CREDENTIAL_AUTH, IPWPS_SYSVAR_CREDENTIAL_ENCR, IPWPS_SYSVAR_CREDENTIAL_KEYINDEX, IPWPS_SYSVAR_CREDENTIAL_KEY, IPWPS_SYSVAR_CREDENTIAL_8021X, IPWPS_SYSVAR_CREDENTIAL_EAP_ID, IPWPS_SYSVAR_CREDENTIAL_EAP_TYPE }; return ipwps_credentials_retrieve_from_sysvars(cred, &syslist); } /* *=========================================================================== * ipwps_credentials_interact_retrieve *=========================================================================== * Description: * Parameters: * Returns: * */ IP_STATIC Ip_err ipwps_credentials_retrieve_from_sysvars(Ipwps_credential_set *cred, Ipwps_credential_sysvar_list *syslist) { char *sysvar; Ip_size_t len; char keyval[IPWPS_PROTO_NETWORK_KEY_MAXLEN+1]; char authval[32]; char encrval[32]; ip_assert(cred); ip_assert(syslist); ipcom_memset(cred, 0 , sizeof(Ipwps_credential_set)); cred->network_idx = ipcom_sysvar_get_as_int(syslist->sysvar_netidx, IPWPS_NETINDEX_DEFAULT); sysvar = syslist->sysvar_ssid; len = sizeof(cred->ssid); if (!ipcom_sysvar_get(sysvar, cred->ssid, &len)) { IPCOM_LOG1(ERR, "Failed to get %s sysvar", sysvar); return IPCOM_ERR_FAILED; } if (ipwps_credentials_verify_allascii(cred->ssid) != IPCOM_SUCCESS) { #ifdef IPWPS_DEBUG_CEREDENTIALS IPCOM_LOG0(ERR, "ipwps_credentials_interact_retrieve :: ssid value not all ascii"); #endif return IPCOM_ERR_FAILED; } sysvar = syslist->sysvar_auth; len = sizeof(authval); if (!ipcom_sysvar_get(sysvar, authval, &len)) { IPCOM_LOG1(ERR, "Failed to get %s sysvar", sysvar); return IPCOM_ERR_FAILED; } if (ipcom_strcmp(authval, IPWPS_CRED_AUTH_OPEN) == 0) { cred->auth_type = IPWPS_AUTH_TYPE_OPEN; cred->encr_type = IPWPS_ENCRYPT_TYPE_NONE; /* We're done, all other sysvars are redundant */ return IPCOM_SUCCESS; } else if ((ipcom_strcmp(authval, IPWPS_CRED_AUTH_WPA) != 0) && (ipcom_strcmp(authval, IPWPS_CRED_AUTH_WPA2) != 0) && (ipcom_strcmp(authval, IPWPS_CRED_AUTH_ALL) != 0)) { #ifdef IPWPS_DEBUG_CEREDENTIALS IPCOM_LOG1(ERR, "ipwps_credentials_interact_retrieve :: Invalid auth value: \"%s\"", authval); #endif return IPCOM_ERR_FAILED; } sysvar = syslist->sysvar_encr; len = sizeof(encrval); if (!ipcom_sysvar_get(sysvar, encrval, &len)) { IPCOM_LOG1(ERR, "Failed to get %s sysvar", sysvar); return IPCOM_ERR_FAILED; } if (ipcom_strcmp(encrval,IPWPS_CRED_ENCR_TKIP) == 0) { cred->encr_type = IPWPS_ENCRYPT_TYPE_TKIP; } else if (ipcom_strcmp(encrval, IPWPS_CRED_ENCR_AES) == 0) { cred->encr_type = IPWPS_ENCRYPT_TYPE_AES; } else if (ipcom_strcmp(encrval,IPWPS_CRED_ENCR_ALL) == 0) { cred->encr_type = IPWPS_ENCRYPT_TYPE_TKIP |IPWPS_ENCRYPT_TYPE_AES; } else { #ifdef IPWPS_DEBUG_CEREDENTIALS IPCOM_LOG1(ERR, "ipwps_credentials_interact_retrieve :: Invalid encr value: \"%s\"", encrval); #endif return IPCOM_ERR_FAILED; } cred->enabled_8021x = ipcom_sysvar_get_as_int(syslist->sysvar_8021x, 0); if (cred->enabled_8021x) { sysvar = syslist->sysvar_eapid; len = sizeof(cred->eap_id); if (!ipcom_sysvar_get(sysvar, cred->eap_id, &len)) { IPCOM_LOG1(ERR, "Failed to get %s sysvar", sysvar); return IPCOM_ERR_FAILED; } sysvar = syslist->sysvar_eaptype; len = 1; /* try simple eap type 1st */ if (ipwps_parse_hex_sysvar(sysvar, cred->eap_type, len) != IPCOM_SUCCESS) { len = sizeof(cred->eap_type); /* must be extended eap type */ if (ipwps_parse_hex_sysvar(sysvar, cred->eap_type, len) != IPCOM_SUCCESS) { return IPCOM_ERR_FAILED; } } if (ipcom_strcmp(authval, IPWPS_CRED_AUTH_WPA) == 0) { cred->auth_type = IPWPS_AUTH_TYPE_WPA; } else if (ipcom_strcmp(authval, IPWPS_CRED_AUTH_WPA2) == 0) { cred->auth_type = IPWPS_AUTH_TYPE_WPA2; } else if (ipcom_strcmp(authval, IPWPS_CRED_AUTH_ALL) == 0) { cred->auth_type = IPWPS_AUTH_TYPE_WPA | IPWPS_AUTH_TYPE_WPA2; } } else { sysvar = syslist->sysvar_netkey; len = sizeof(keyval); if (!ipcom_sysvar_get(sysvar, keyval, &len)) { IPCOM_LOG1(ERR, "Failed to get %s sysvar", sysvar); return IPCOM_ERR_FAILED; } if (ipwps_credentials_verify_netkey(keyval) != IPCOM_SUCCESS) { #ifdef IPWPS_DEBUG_CEREDENTIALS IPCOM_LOG1(ERR, "%s sysvar contains invalid passphrase or PSK value.", sysvar); #endif return IPCOM_ERR_FAILED; } cred->netkey_size = strlen(keyval); ipcom_memcpy(cred->netkey, keyval, cred->netkey_size); cred->netkey_idx = ipcom_sysvar_get_as_int(syslist->sysvar_keyidx, IPWPS_KEYINDEX_DEFAULT); if (ipcom_strcmp(authval, IPWPS_CRED_AUTH_WPA) == 0) { cred->auth_type = IPWPS_AUTH_TYPE_WPAPSK; } else if (ipcom_strcmp(authval, IPWPS_CRED_AUTH_WPA2) == 0) { cred->auth_type = IPWPS_AUTH_TYPE_WPA2PSK; } else if (ipcom_strcmp(authval, IPWPS_CRED_AUTH_ALL) == 0) { cred->auth_type = IPWPS_AUTH_TYPE_WPAPSK | IPWPS_AUTH_TYPE_WPA2PSK; } } return IPCOM_SUCCESS; } /* *=========================================================================== * ipwps_credentials_verify_netkey *=========================================================================== * Description: Verify proper passphrase of PSK length and format. * Parameters: * Returns: * */ IP_STATIC Ip_err ipwps_credentials_verify_netkey(IP_CONST char *netkey) { Ip_u16 size; if (!netkey) { #ifdef IPWPS_DEBUG_CEREDENTIALS IPCOM_LOG0(ERR, "ipwps_credentials_verify_netkey :: NULL netkey"); #endif return IPCOM_ERR_FAILED; } size = strlen(netkey); if (size == IPWPS_PROTO_NETWORK_KEY_MAXLEN) { if (ipwps_credentials_verify_allhex(netkey) != IPCOM_SUCCESS) { #ifdef IPWPS_DEBUG_CEREDENTIALS IPCOM_LOG1(ERR, "ipwps_credentials_verify_netkey :: netkey PSK value not all hex: \"%s\"", netkey); #endif return IPCOM_ERR_FAILED; } } else if ((size >= IPWPS_PASSPHRASE_MINLEN) && (size < IPWPS_PROTO_NETWORK_KEY_MAXLEN)) { if (ipwps_credentials_verify_allascii(netkey) != IPCOM_SUCCESS) { #ifdef IPWPS_DEBUG_CEREDENTIALS IPCOM_LOG0(ERR, "ipwps_credentials_verify_netkey :: netkey passphrase value not all ascii"); #endif return IPCOM_ERR_FAILED; } } else { #ifdef IPWPS_DEBUG_CEREDENTIALS IPCOM_LOG1(ERR, "ipwps_credentials_verify_netkey :: Invalid netkey length %d", size); #endif return IPCOM_ERR_FAILED; } return IPCOM_SUCCESS; } /* *=========================================================================== * ipwps_credentials_verify_allhex *=========================================================================== * Description: * Parameters: * Returns: * */ IP_STATIC Ip_err ipwps_credentials_verify_allhex(IP_CONST char *string) { Ip_u16 size, i; ip_assert(string); size = strlen(string); for (i = 0; i < size; i++) { if (!ipcom_isxdigit(string[i])) return IPCOM_ERR_FAILED; } return IPCOM_SUCCESS; } /* *=========================================================================== * ipwps_credentials_verify_allascii *=========================================================================== * Description: * Parameters: * Returns: * */ IP_STATIC Ip_err ipwps_credentials_verify_allascii(IP_CONST char *string) { Ip_u16 size, i; ip_assert(string); size = strlen(string); for (i = 0; i < size; i++) { if (!ipcom_isascii(string[i])) return IPCOM_ERR_FAILED; } return IPCOM_SUCCESS; } /* *=========================================================================== * ipwps_credentials_random_ascii *=========================================================================== * Description: Generate a specified number of random printable ascii characters. * NOTE that the buffer will not be NULL terminated by this routine. It is * the callers responsibility to do so. * Parameters: * Returns: */ IP_GLOBAL Ip_err ipwps_credentials_gen_random_ascii(char *buf, Ip_u16 size) { IP_CONST char first_printable_ascii = 0x20, last_printable_ascii = 0x7E; Ip_u32 num_printable_ascii = last_printable_ascii - first_printable_ascii +1; Ip_u32 i, j, randval, printable_ascii_randval; char *tempbuf; Ip_bool acceptable; char excluded_chars[] = {'\'', '\"', '`', '\'', '\\'}; /* Exclude chars that cause problem in shell data entry */ #ifdef IPWPS_CRED_TEST_RANDOM_ASCII_RANGE char seq_char = last_printable_ascii; #endif ip_assert(buf); tempbuf = ipcom_calloc(1, size+1); if (!tempbuf) return IPCOM_ERR_FAILED; for (i = 0; i < size; i++) { acceptable = IP_FALSE; while (!acceptable) { #ifdef IPWPS_CRED_TEST_RANDOM_ASCII_RANGE printable_ascii_randval = seq_char--; if (seq_char < first_printable_ascii) seq_char = last_printable_ascii; #else randval = ipcom_rand(); printable_ascii_randval = last_printable_ascii - (randval%num_printable_ascii); #endif acceptable = IP_TRUE; for (j = 0; j < sizeof(excluded_chars); j ++) { if (printable_ascii_randval == excluded_chars[j]) { acceptable = IP_FALSE; break; } } /* Avoid space as the last char as that is confusing */ if ((i == (size-1)) && (printable_ascii_randval == ' ')) acceptable = IP_FALSE; } ipcom_sprintf(&tempbuf[i], "%c", printable_ascii_randval); } ipcom_memcpy(buf, tempbuf, size); ipcom_free(tempbuf); return IPCOM_SUCCESS; } /* *=========================================================================== * ipwps_credentials_gen_random_hex *=========================================================================== * Description: Generate a specified number of random hex characters. * Parameters: * Returns: */ IP_GLOBAL Ip_err ipwps_credentials_gen_random_hex(char *buf, Ip_u16 size) { Ip_u16 i, max = (size/8)*8+8+1; char *tempbuf; Ip_u32 randval; ip_assert(buf); tempbuf = ipcom_calloc(1, max); if (!tempbuf) return IPCOM_ERR_FAILED; i = 0; while (i < size) { randval = ipcom_rand(); ipcom_sprintf(&tempbuf[i], "%.8x", randval); i+=8; } ipcom_memcpy(buf, tempbuf, size); ipcom_free(tempbuf); return IPCOM_SUCCESS; } #ifdef IPWPS_DEBUG /* *=========================================================================== * ipwps_credentials_test_rand_hex *=========================================================================== * Description: * Parameters: * Returns: */ IP_GLOBAL void ipwps_credentials_test_rand_hex(void) { char buf[64]; int size,j; for (size = 1; size <= sizeof(buf); size++) { ipcom_printf("buf[%d]: ", size); ipcom_memset(buf, 0, sizeof(buf)); ipwps_credentials_gen_random_hex(buf, size); for (j = 0; j < size; j++) ipcom_printf("%c", buf[j]); ipcom_printf("\n"); } } /* *=========================================================================== * ipwps_credentials_test_rand_ascii *=========================================================================== * Description: * Parameters: * Returns: */ IP_GLOBAL void ipwps_credentials_test_rand_ascii(void) { char buf[128]; int size; /* leave at least 1 byte for the NULL char */ for (size = 1; size < sizeof(buf); size++) { ipcom_memset(buf, 0, sizeof(buf)); ipwps_credentials_gen_random_ascii(buf, size); ipcom_printf("buf[%d]: %s\n", size, buf); } } #endif /* *=========================================================================== * ipwps_credentials_method_name *=========================================================================== * Description: * Parameters: * Returns: */ IP_STATIC IP_CONST char *ipwps_credentials_method_name(Ipwps_credential_method cred_method) { IP_CONST char *name = "INVALID"; switch (cred_method) { case IPWPS_CERDENTIAL_METHOD_AUTO: name = IPWPS_CRED_CONFIG_METHOD_AUTO; break; case IPWPS_CERDENTIAL_METHOD_DEFAULT: name = IPWPS_CRED_CONFIG_METHOD_DEFAULT; break; case IPWPS_CERDENTIAL_METHOD_INTERACTIVE: name = IPWPS_CRED_CONFIG_METHOD_INTERACT; break; case IPWPS_CERDENTIAL_METHOD_NOTSET: name = "NOT SET"; break; } return name; }