diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c index 3d3552f45..1ccce440c 100644 --- a/wpa_supplicant/config.c +++ b/wpa_supplicant/config.c @@ -2272,6 +2272,74 @@ int wpa_config_set_cred(struct wpa_cred *cred, const char *var, } +struct wpa_cred * wpa_config_get_cred(struct wpa_config *config, int id) +{ + struct wpa_cred *cred; + + cred = config->cred; + while (cred) { + if (id == cred->id) + break; + cred = cred->next; + } + + return cred; +} + + +struct wpa_cred * wpa_config_add_cred(struct wpa_config *config) +{ + int id; + struct wpa_cred *cred, *last = NULL; + + id = -1; + cred = config->cred; + while (cred) { + if (cred->id > id) + id = cred->id; + last = cred; + cred = cred->next; + } + id++; + + cred = os_zalloc(sizeof(*cred)); + if (cred == NULL) + return NULL; + cred->id = id; + if (last) + last->next = cred; + else + config->cred = cred; + + return cred; +} + + +int wpa_config_remove_cred(struct wpa_config *config, int id) +{ + struct wpa_cred *cred, *prev = NULL; + + cred = config->cred; + while (cred) { + if (id == cred->id) + break; + prev = cred; + cred = cred->next; + } + + if (cred == NULL) + return -1; + + if (prev) + prev->next = cred->next; + else + config->cred = cred->next; + + wpa_config_free_cred(cred); + return 0; +} + + #ifndef CONFIG_NO_CONFIG_BLOBS /** * wpa_config_get_blob - Get a named configuration blob diff --git a/wpa_supplicant/config.h b/wpa_supplicant/config.h index e45b608a1..35fdc9431 100644 --- a/wpa_supplicant/config.h +++ b/wpa_supplicant/config.h @@ -547,6 +547,9 @@ void wpa_config_set_blob(struct wpa_config *config, void wpa_config_free_blob(struct wpa_config_blob *blob); int wpa_config_remove_blob(struct wpa_config *config, const char *name); +struct wpa_cred * wpa_config_get_cred(struct wpa_config *config, int id); +struct wpa_cred * wpa_config_add_cred(struct wpa_config *config); +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); diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c index 1cdb082ed..1bbdebe49 100644 --- a/wpa_supplicant/ctrl_iface.c +++ b/wpa_supplicant/ctrl_iface.c @@ -1897,6 +1897,132 @@ static int wpa_supplicant_ctrl_iface_get_network( } +static int wpa_supplicant_ctrl_iface_list_creds(struct wpa_supplicant *wpa_s, + char *buf, size_t buflen) +{ + char *pos, *end; + struct wpa_cred *cred; + int ret; + + pos = buf; + end = buf + buflen; + ret = os_snprintf(pos, end - pos, + "cred id / realm / username / domain / imsi\n"); + if (ret < 0 || ret >= end - pos) + return pos - buf; + pos += ret; + + cred = wpa_s->conf->cred; + while (cred) { + ret = os_snprintf(pos, end - pos, "%d\t%s\t%s\t%s\t%s\n", + cred->id, cred->realm ? cred->realm : "", + cred->username ? cred->username : "", + cred->domain ? cred->domain : "", + cred->imsi ? cred->imsi : ""); + if (ret < 0 || ret >= end - pos) + return pos - buf; + pos += ret; + + cred = cred->next; + } + + return pos - buf; +} + + +static int wpa_supplicant_ctrl_iface_add_cred(struct wpa_supplicant *wpa_s, + char *buf, size_t buflen) +{ + struct wpa_cred *cred; + int ret; + + wpa_printf(MSG_DEBUG, "CTRL_IFACE: ADD_CRED"); + + cred = wpa_config_add_cred(wpa_s->conf); + if (cred == NULL) + return -1; + + ret = os_snprintf(buf, buflen, "%d\n", cred->id); + if (ret < 0 || (size_t) ret >= buflen) + return -1; + return ret; +} + + +static int wpa_supplicant_ctrl_iface_remove_cred(struct wpa_supplicant *wpa_s, + char *cmd) +{ + int id; + struct wpa_cred *cred; + + /* cmd: "" or "all" */ + if (os_strcmp(cmd, "all") == 0) { + wpa_printf(MSG_DEBUG, "CTRL_IFACE: REMOVE_CRED all"); + cred = wpa_s->conf->cred; + while (cred) { + id = cred->id; + cred = cred->next; + wpa_config_remove_cred(wpa_s->conf, id); + } + return 0; + } + + id = atoi(cmd); + wpa_printf(MSG_DEBUG, "CTRL_IFACE: REMOVE_CRED id=%d", id); + + cred = wpa_config_get_cred(wpa_s->conf, id); + if (cred == NULL || + wpa_config_remove_cred(wpa_s->conf, id) < 0) { + wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find cred id=%d", + id); + return -1; + } + + return 0; +} + + +static int wpa_supplicant_ctrl_iface_set_cred(struct wpa_supplicant *wpa_s, + char *cmd) +{ + int id; + struct wpa_cred *cred; + char *name, *value; + + /* cmd: " " */ + name = os_strchr(cmd, ' '); + if (name == NULL) + return -1; + *name++ = '\0'; + + value = os_strchr(name, ' '); + if (value == NULL) + return -1; + *value++ = '\0'; + + id = atoi(cmd); + wpa_printf(MSG_DEBUG, "CTRL_IFACE: SET_CRED id=%d name='%s'", + id, name); + wpa_hexdump_ascii_key(MSG_DEBUG, "CTRL_IFACE: value", + (u8 *) value, os_strlen(value)); + + 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; + } + + if (wpa_config_set_cred(cred, name, value, 0) < 0) { + wpa_printf(MSG_DEBUG, "CTRL_IFACE: Failed to set cred " + "variable '%s'", name); + return -1; + } + + return 0; +} + + #ifndef CONFIG_NO_CONFIG_WRITE static int wpa_supplicant_ctrl_iface_save_config(struct wpa_supplicant *wpa_s) { @@ -3801,6 +3927,18 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s, } else if (os_strncmp(buf, "GET_NETWORK ", 12) == 0) { reply_len = wpa_supplicant_ctrl_iface_get_network( wpa_s, buf + 12, reply, reply_size); + } else if (os_strcmp(buf, "LIST_CREDS") == 0) { + reply_len = wpa_supplicant_ctrl_iface_list_creds( + wpa_s, reply, reply_size); + } else if (os_strcmp(buf, "ADD_CRED") == 0) { + reply_len = wpa_supplicant_ctrl_iface_add_cred( + wpa_s, reply, reply_size); + } else if (os_strncmp(buf, "REMOVE_CRED ", 12) == 0) { + if (wpa_supplicant_ctrl_iface_remove_cred(wpa_s, buf + 12)) + reply_len = -1; + } else if (os_strncmp(buf, "SET_CRED ", 9) == 0) { + if (wpa_supplicant_ctrl_iface_set_cred(wpa_s, buf + 9)) + reply_len = -1; #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 ed269b289..d28641bf8 100644 --- a/wpa_supplicant/wpa_cli.c +++ b/wpa_supplicant/wpa_cli.c @@ -1602,6 +1602,61 @@ static int wpa_cli_cmd_get_network(struct wpa_ctrl *ctrl, int argc, } +static int wpa_cli_cmd_list_creds(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_ctrl_command(ctrl, "LIST_CREDS"); +} + + +static int wpa_cli_cmd_add_cred(struct wpa_ctrl *ctrl, int argc, char *argv[]) +{ + return wpa_ctrl_command(ctrl, "ADD_CRED"); +} + + +static int wpa_cli_cmd_remove_cred(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + char cmd[32]; + int res; + + if (argc < 1) { + printf("Invalid REMOVE_CRED command: needs one argument " + "(cred id)\n"); + return -1; + } + + res = os_snprintf(cmd, sizeof(cmd), "REMOVE_CRED %s", argv[0]); + if (res < 0 || (size_t) res >= sizeof(cmd)) + return -1; + cmd[sizeof(cmd) - 1] = '\0'; + + return wpa_ctrl_command(ctrl, cmd); +} + + +static int wpa_cli_cmd_set_cred(struct wpa_ctrl *ctrl, int argc, char *argv[]) +{ + char cmd[256]; + int res; + + if (argc != 3) { + printf("Invalid SET_CRED command: needs three arguments\n" + "(cred id, variable name, and value)\n"); + return -1; + } + + res = os_snprintf(cmd, sizeof(cmd), "SET_CRED %s %s %s", + argv[0], argv[1], argv[2]); + if (res < 0 || (size_t) res >= sizeof(cmd) - 1) { + printf("Too long SET_CRED command.\n"); + return -1; + } + return wpa_ctrl_command(ctrl, cmd); +} + + static int wpa_cli_cmd_disconnect(struct wpa_ctrl *ctrl, int argc, char *argv[]) { @@ -2784,6 +2839,18 @@ static struct wpa_cli_cmd wpa_cli_commands[] = { { "get_network", wpa_cli_cmd_get_network, cli_cmd_flag_none, " = get network variables" }, + { "list_creds", wpa_cli_cmd_list_creds, + cli_cmd_flag_none, + "= list configured credentials" }, + { "add_cred", wpa_cli_cmd_add_cred, + cli_cmd_flag_none, + "= add a credential" }, + { "remove_cred", wpa_cli_cmd_remove_cred, + cli_cmd_flag_none, + " = remove a credential" }, + { "set_cred", wpa_cli_cmd_set_cred, + cli_cmd_flag_sensitive, + " = set credential variables" }, { "save_config", wpa_cli_cmd_save_config, cli_cmd_flag_none, "= save the current configuration" },