From c880ab87eef081bc45593cb012b61b66b5503a40 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Fri, 4 Apr 2014 20:10:49 +0300 Subject: [PATCH] Interworking: Add GET_CRED ctrl_iface command "GET_CRED " can now be used to fetch credential parameters over the control interface. This does not allow passwords etc. private material to be retrieved ("*" is returned for those if the value is set regardless of the value). FAIL is returned if the requested parameter has not been set. For cred parameters that can have multiple values, newline separated list of values is returned. Signed-off-by: Jouni Malinen --- wpa_supplicant/config.c | 269 ++++++++++++++++++++++++++++++++++++ wpa_supplicant/config.h | 1 + wpa_supplicant/ctrl_iface.c | 49 +++++++ wpa_supplicant/wpa_cli.c | 15 ++ 4 files changed, 334 insertions(+) diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c index 6a4621021..74283eb75 100644 --- a/wpa_supplicant/config.c +++ b/wpa_supplicant/config.c @@ -2796,6 +2796,275 @@ int wpa_config_set_cred(struct wpa_cred *cred, const char *var, } +char * alloc_int_str(int val) +{ + char *buf; + + buf = os_malloc(20); + if (buf == NULL) + return NULL; + os_snprintf(buf, 20, "%d", val); + return buf; +} + + +char * alloc_strdup(const char *str) +{ + if (str == NULL) + return NULL; + return os_strdup(str); +} + + +char * wpa_config_get_cred_no_key(struct wpa_cred *cred, const char *var) +{ + if (os_strcmp(var, "temporary") == 0) + return alloc_int_str(cred->temporary); + + if (os_strcmp(var, "priority") == 0) + return alloc_int_str(cred->priority); + + if (os_strcmp(var, "sp_priority") == 0) + return alloc_int_str(cred->sp_priority); + + if (os_strcmp(var, "pcsc") == 0) + return alloc_int_str(cred->pcsc); + + if (os_strcmp(var, "eap") == 0) { + if (!cred->eap_method) + return NULL; + return alloc_strdup(eap_get_name(cred->eap_method[0].vendor, + cred->eap_method[0].method)); + } + + if (os_strcmp(var, "update_identifier") == 0) + return alloc_int_str(cred->update_identifier); + + if (os_strcmp(var, "min_dl_bandwidth_home") == 0) + return alloc_int_str(cred->min_dl_bandwidth_home); + + if (os_strcmp(var, "min_ul_bandwidth_home") == 0) + return alloc_int_str(cred->min_ul_bandwidth_home); + + if (os_strcmp(var, "min_dl_bandwidth_roaming") == 0) + return alloc_int_str(cred->min_dl_bandwidth_roaming); + + if (os_strcmp(var, "min_ul_bandwidth_roaming") == 0) + return alloc_int_str(cred->min_ul_bandwidth_roaming); + + if (os_strcmp(var, "max_bss_load") == 0) + return alloc_int_str(cred->max_bss_load); + + if (os_strcmp(var, "req_conn_capab") == 0) { + unsigned int i; + char *buf, *end, *pos; + int ret; + + if (!cred->num_req_conn_capab) + return NULL; + + buf = os_malloc(4000); + if (buf == NULL) + return NULL; + pos = buf; + end = pos + 4000; + for (i = 0; i < cred->num_req_conn_capab; i++) { + int *ports; + + ret = os_snprintf(pos, end - pos, "%s%u", + i > 0 ? "\n" : "", + cred->req_conn_capab_proto[i]); + if (ret < 0 || ret >= end - pos) + return buf; + pos += ret; + + ports = cred->req_conn_capab_port[i]; + if (ports) { + int j; + for (j = 0; ports[j] != -1; j++) { + ret = os_snprintf(pos, end - pos, + "%s%d", + j > 0 ? "," : ":", + ports[j]); + if (ret < 0 || ret >= end - pos) + return buf; + pos += ret; + } + } + } + + return buf; + } + + if (os_strcmp(var, "ocsp") == 0) + return alloc_int_str(cred->ocsp); + + if (os_strcmp(var, "realm") == 0) + return alloc_strdup(cred->realm); + + if (os_strcmp(var, "username") == 0) + return alloc_strdup(cred->username); + + if (os_strcmp(var, "password") == 0) { + if (!cred->password) + return NULL; + return alloc_strdup("*"); + } + + if (os_strcmp(var, "ca_cert") == 0) + return alloc_strdup(cred->ca_cert); + + if (os_strcmp(var, "client_cert") == 0) + return alloc_strdup(cred->client_cert); + + if (os_strcmp(var, "private_key") == 0) + return alloc_strdup(cred->private_key); + + if (os_strcmp(var, "private_key_passwd") == 0) { + if (!cred->private_key_passwd) + return NULL; + return alloc_strdup("*"); + } + + if (os_strcmp(var, "imsi") == 0) + return alloc_strdup(cred->imsi); + + if (os_strcmp(var, "milenage") == 0) { + if (!(cred->milenage)) + return NULL; + return alloc_strdup("*"); + } + + if (os_strcmp(var, "domain_suffix_match") == 0) + return alloc_strdup(cred->domain_suffix_match); + + if (os_strcmp(var, "domain") == 0) { + unsigned int i; + char *buf, *end, *pos; + int ret; + + if (!cred->num_domain) + return NULL; + + buf = os_malloc(4000); + if (buf == NULL) + return NULL; + pos = buf; + end = pos + 4000; + + for (i = 0; i < cred->num_domain; i++) { + ret = os_snprintf(pos, end - pos, "%s%s", + i > 0 ? "\n" : "", cred->domain[i]); + if (ret < 0 || ret >= end - pos) + return buf; + pos += ret; + } + + return buf; + } + + if (os_strcmp(var, "phase1") == 0) + return alloc_strdup(cred->phase1); + + if (os_strcmp(var, "phase2") == 0) + return alloc_strdup(cred->phase2); + + if (os_strcmp(var, "roaming_consortium") == 0) { + size_t buflen; + char *buf; + + if (!cred->roaming_consortium_len) + return NULL; + buflen = cred->roaming_consortium_len * 2 + 1; + buf = os_malloc(buflen); + if (buf == NULL) + return NULL; + wpa_snprintf_hex(buf, buflen, cred->roaming_consortium, + cred->roaming_consortium_len); + return buf; + } + + if (os_strcmp(var, "required_roaming_consortium") == 0) { + size_t buflen; + char *buf; + + if (!cred->required_roaming_consortium_len) + return NULL; + buflen = cred->required_roaming_consortium_len * 2 + 1; + buf = os_malloc(buflen); + if (buf == NULL) + return NULL; + wpa_snprintf_hex(buf, buflen, cred->required_roaming_consortium, + cred->required_roaming_consortium_len); + return buf; + } + + if (os_strcmp(var, "excluded_ssid") == 0) { + unsigned int i; + char *buf, *end, *pos; + + if (!cred->num_excluded_ssid) + return NULL; + + buf = os_malloc(4000); + if (buf == NULL) + return NULL; + pos = buf; + end = pos + 4000; + + for (i = 0; i < cred->num_excluded_ssid; i++) { + struct excluded_ssid *e; + int ret; + + e = &cred->excluded_ssid[i]; + ret = os_snprintf(pos, end - pos, "%s%s", + i > 0 ? "\n" : "", + wpa_ssid_txt(e->ssid, e->ssid_len)); + if (ret < 0 || ret >= end - pos) + return buf; + pos += ret; + } + + return buf; + } + + if (os_strcmp(var, "roaming_partner") == 0) { + unsigned int i; + char *buf, *end, *pos; + + if (!cred->num_roaming_partner) + return NULL; + + buf = os_malloc(4000); + if (buf == NULL) + return NULL; + pos = buf; + end = pos + 4000; + + for (i = 0; i < cred->num_roaming_partner; i++) { + struct roaming_partner *p; + int ret; + + p = &cred->roaming_partner[i]; + ret = os_snprintf(pos, end - pos, "%s%s,%d,%u,%s", + i > 0 ? "\n" : "", + p->fqdn, p->exact_match, p->priority, + p->country); + if (ret < 0 || ret >= end - pos) + return buf; + pos += ret; + } + + return buf; + } + + if (os_strcmp(var, "provisioning_sp") == 0) + return alloc_strdup(cred->provisioning_sp); + + return NULL; +} + + struct wpa_cred * wpa_config_get_cred(struct wpa_config *config, int id) { struct wpa_cred *cred; diff --git a/wpa_supplicant/config.h b/wpa_supplicant/config.h index de4397060..a39804949 100644 --- a/wpa_supplicant/config.h +++ b/wpa_supplicant/config.h @@ -1053,6 +1053,7 @@ int wpa_config_remove_cred(struct wpa_config *config, int id); void wpa_config_free_cred(struct wpa_cred *cred); int wpa_config_set_cred(struct wpa_cred *cred, const char *var, const char *value, int line); +char * wpa_config_get_cred_no_key(struct wpa_cred *cred, const char *var); struct wpa_config * wpa_config_alloc_empty(const char *ctrl_interface, const char *driver_param); diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c index 4a63f4a8c..65ee15e82 100644 --- a/wpa_supplicant/ctrl_iface.c +++ b/wpa_supplicant/ctrl_iface.c @@ -2811,6 +2811,51 @@ static int wpa_supplicant_ctrl_iface_set_cred(struct wpa_supplicant *wpa_s, } +static int wpa_supplicant_ctrl_iface_get_cred(struct wpa_supplicant *wpa_s, + char *cmd, char *buf, + size_t buflen) +{ + int id; + size_t res; + struct wpa_cred *cred; + char *name, *value; + + /* cmd: " " */ + name = os_strchr(cmd, ' '); + if (name == NULL) + return -1; + *name++ = '\0'; + + id = atoi(cmd); + wpa_printf(MSG_DEBUG, "CTRL_IFACE: GET_CRED id=%d name='%s'", + id, name); + + cred = wpa_config_get_cred(wpa_s->conf, id); + if (cred == NULL) { + wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find cred id=%d", + id); + return -1; + } + + value = wpa_config_get_cred_no_key(cred, name); + if (value == NULL) { + wpa_printf(MSG_DEBUG, "CTRL_IFACE: Failed to get cred variable '%s'", + name); + return -1; + } + + res = os_strlcpy(buf, value, buflen); + if (res >= buflen) { + os_free(value); + return -1; + } + + os_free(value); + + return res; +} + + #ifndef CONFIG_NO_CONFIG_WRITE static int wpa_supplicant_ctrl_iface_save_config(struct wpa_supplicant *wpa_s) { @@ -6434,6 +6479,10 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s, } else if (os_strncmp(buf, "SET_CRED ", 9) == 0) { if (wpa_supplicant_ctrl_iface_set_cred(wpa_s, buf + 9)) reply_len = -1; + } else if (os_strncmp(buf, "GET_CRED ", 9) == 0) { + reply_len = wpa_supplicant_ctrl_iface_get_cred(wpa_s, buf + 9, + reply, + reply_size); #ifndef CONFIG_NO_CONFIG_WRITE } else if (os_strcmp(buf, "SAVE_CONFIG") == 0) { if (wpa_supplicant_ctrl_iface_save_config(wpa_s)) diff --git a/wpa_supplicant/wpa_cli.c b/wpa_supplicant/wpa_cli.c index 2a9ab7fe0..83817f993 100644 --- a/wpa_supplicant/wpa_cli.c +++ b/wpa_supplicant/wpa_cli.c @@ -1474,6 +1474,18 @@ static int wpa_cli_cmd_set_cred(struct wpa_ctrl *ctrl, int argc, char *argv[]) } +static int wpa_cli_cmd_get_cred(struct wpa_ctrl *ctrl, int argc, char *argv[]) +{ + if (argc != 2) { + printf("Invalid GET_CRED command: needs two arguments\n" + "(cred id, variable name)\n"); + return -1; + } + + return wpa_cli_cmd(ctrl, "GET_CRED", 2, argc, argv); +} + + static int wpa_cli_cmd_disconnect(struct wpa_ctrl *ctrl, int argc, char *argv[]) { @@ -2594,6 +2606,9 @@ static struct wpa_cli_cmd wpa_cli_commands[] = { { "set_cred", wpa_cli_cmd_set_cred, NULL, cli_cmd_flag_sensitive, " = set credential variables" }, + { "get_cred", wpa_cli_cmd_get_cred, NULL, + cli_cmd_flag_none, + " = get credential variables" }, { "save_config", wpa_cli_cmd_save_config, NULL, cli_cmd_flag_none, "= save the current configuration" },