changeset 13694:3a75fed3cee2

405 Can't connect to similarly-named, encrypted wireless networks. Reviewed by: Milan Jurik <milan.jurik@xylab.cz> Reviewed by: Albert Lee <trisk@nexenta.com> Approved by: Gordon Ross <gwr@nexenta.com>
author enricop <enricop@computer.org>
date Mon, 14 May 2012 15:11:16 -0500
parents b236aca9d46b
children 2d025fa9b1e1
files usr/src/cmd/cmd-inet/lib/nwamd/door_if.c usr/src/cmd/cmd-inet/lib/nwamd/known_wlans.c usr/src/cmd/cmd-inet/lib/nwamd/ncu_phys.c usr/src/cmd/cmd-inet/usr.sbin/nwamadm/nwamadm.c
diffstat 4 files changed, 118 insertions(+), 88 deletions(-) [+]
line wrap: on
line diff
--- a/usr/src/cmd/cmd-inet/lib/nwamd/door_if.c	Mon May 14 16:03:20 2012 -0700
+++ b/usr/src/cmd/cmd-inet/lib/nwamd/door_if.c	Mon May 14 15:11:16 2012 -0500
@@ -237,7 +237,8 @@
 	    req->nwda_data.nwdad_wlan_info.nwdad_bssid);
 	return (nwamd_wlan_set_key
 	    (req->nwda_data.nwdad_wlan_info.nwdad_name,
-	    req->nwda_data.nwdad_wlan_info.nwdad_essid, NULL,
+	    req->nwda_data.nwdad_wlan_info.nwdad_essid,
+	    req->nwda_data.nwdad_wlan_info.nwdad_bssid,
 	    req->nwda_data.nwdad_wlan_info.nwdad_security_mode,
 	    req->nwda_data.nwdad_wlan_info.nwdad_keyslot,
 	    req->nwda_data.nwdad_wlan_info.nwdad_key));
--- a/usr/src/cmd/cmd-inet/lib/nwamd/known_wlans.c	Mon May 14 16:03:20 2012 -0700
+++ b/usr/src/cmd/cmd-inet/lib/nwamd/known_wlans.c	Mon May 14 15:11:16 2012 -0500
@@ -463,32 +463,6 @@
 	return (err);
 }
 
-nwam_error_t
-known_wlan_get_keyslot(const char *essid, uint_t *keyslotp)
-{
-	nwam_known_wlan_handle_t kwh = NULL;
-	nwam_value_t keyslotval = NULL;
-	uint64_t slot;
-	nwam_error_t err;
-
-	if ((err = nwam_known_wlan_read(essid, 0, &kwh)) != NWAM_SUCCESS)
-		return (err);
-	if ((err = nwam_known_wlan_get_prop_value(kwh,
-	    NWAM_KNOWN_WLAN_PROP_KEYSLOT, &keyslotval)) == NWAM_SUCCESS &&
-	    (err = nwam_value_get_uint64(keyslotval, &slot)) == NWAM_SUCCESS) {
-		*keyslotp = (uint_t)slot;
-	} else {
-		if (err == NWAM_ENTITY_NOT_FOUND)
-			err = NWAM_SUCCESS;
-		*keyslotp = 1;
-	}
-	if (keyslotval != NULL)
-		nwam_value_free(keyslotval);
-	if (kwh != NULL)
-		nwam_known_wlan_free(kwh);
-	return (err);
-}
-
 /* Performs a scan on a wifi link NCU */
 /* ARGSUSED */
 static int
--- a/usr/src/cmd/cmd-inet/lib/nwamd/ncu_phys.c	Mon May 14 16:03:20 2012 -0700
+++ b/usr/src/cmd/cmd-inet/lib/nwamd/ncu_phys.c	Mon May 14 15:11:16 2012 -0500
@@ -351,6 +351,44 @@
 }
 
 /*
+ * Callback used on each known WLAN:
+ * return 1 if a secobj, linked with an existing kwown wlan, has the same name
+ * of the secobj that is being created.
+ */
+
+static int
+find_keyname_cb(nwam_known_wlan_handle_t kwh, void *new_keyname)
+{
+	nwam_error_t err;
+	nwam_value_t old_key;
+
+	char **old_keyname;
+	uint_t num_old_keyname, i;
+
+	if ((err = nwam_known_wlan_get_prop_value(kwh,
+	    NWAM_KNOWN_WLAN_PROP_KEYNAME, &old_key)) != NWAM_SUCCESS) {
+		nlog(LOG_ERR, "find_keyname_cb: nwam_known_wlan_get_prop: %s",
+		    nwam_strerror(err));
+		return (0);
+	}
+	if ((err = nwam_value_get_string_array(old_key, &old_keyname,
+	    &num_old_keyname))
+	    != NWAM_SUCCESS) {
+		nlog(LOG_ERR, "find_keyname_cb: nwam_value_get_string: %s",
+		    nwam_strerror(err));
+		nwam_value_free(old_key);
+		return (0);
+	}
+	nwam_value_free(old_key);
+	for (i = 0; i < num_old_keyname; i++) {
+		if (strcmp(old_keyname[i], (const char *)new_keyname) == 0)
+			/* Found matching keyname so terminate walk */
+			return (1);
+	}
+	return (0);
+}
+
+/*
  * Print the key name format into the appropriate field, then convert any ":"
  * characters to ".", as ":[1-4]" is the slot indicator, which otherwise
  * would trip us up.  Invalid characters for secobj names are ignored.
@@ -403,9 +441,11 @@
 	nwamd_object_t ncu_obj;
 	nwamd_ncu_t *ncu;
 	nwamd_link_t *link;
+	int ret = 0;
 	uint8_t obj_val[DLADM_SECOBJ_VAL_MAX];
 	uint_t obj_len = sizeof (obj_val);
 	char obj_name[DLADM_SECOBJ_NAME_MAX];
+	char obj_tempname[DLADM_SECOBJ_NAME_MAX];
 	dladm_status_t status;
 	char errmsg[DLADM_STRSIZE];
 	dladm_secobj_class_t class;
@@ -419,14 +459,6 @@
 	ncu = ncu_obj->nwamd_object_data;
 	link = &ncu->ncu_link;
 
-	nlog(LOG_DEBUG, "nwamd_wlan_set_key: running for link %s", linkname);
-	/*
-	 * Name key object for this WLAN so it can be later retrieved
-	 * (name is unique for each ESSID/BSSID combination).
-	 */
-	nwamd_set_key_name(essid, bssid, obj_name, sizeof (obj_name));
-	nlog(LOG_DEBUG, "store_key: obj_name is %s", obj_name);
-
 	class = (security_mode == DLADM_WLAN_SECMODE_WEP ?
 	    DLADM_SECOBJ_CLASS_WEP : DLADM_SECOBJ_CLASS_WPA);
 	if (key_string_to_secobj_value(raw_key, obj_val, &obj_len,
@@ -436,7 +468,38 @@
 		return (NWAM_ERROR_INTERNAL);
 	}
 
-	/* we've validated the new key, so remove the old one */
+	nlog(LOG_DEBUG, "nwamd_wlan_set_key: running for link %s", linkname);
+	/*
+	 * Name key object for this WLAN so it can be later retrieved.
+	 * (bssid is appended if an object, with the same keyname,
+	 * already exists and is associated to a known wlan)
+	 */
+	nwamd_set_key_name(essid, NULL, obj_tempname, sizeof (obj_tempname));
+	(void) nwam_walk_known_wlans(find_keyname_cb, obj_tempname, 0, &ret);
+	/*
+	 * We also check if the keyval is the same. The user might want
+	 * to use the same key for more APs with the same ESSID.
+	 * This can result in a known wlan with multiple BSSIDs
+	 */
+	if (ret == 1) {
+		dladm_wlan_key_t *old_secobj = nwamd_wlan_get_key_named(
+		    obj_tempname, security_mode);
+		nlog(LOG_DEBUG, "found existing obj_name %s", obj_tempname);
+		ret = memcmp((*old_secobj).wk_val, obj_val, obj_len);
+		nwamd_set_key_name(essid, ret ? bssid : NULL, obj_name,
+		    sizeof (obj_name));
+		free(old_secobj);
+	} else {
+		nwamd_set_key_name(essid, NULL, obj_name,
+		    sizeof (obj_name));
+	}
+	nlog(LOG_DEBUG, "store_key: obj_name is %s", obj_name);
+
+	/*
+	 * We have validated the new key, so remove the old one.
+	 * This will actually delete the keyobj only if the user had set
+	 * a wrong key and is replacing it with a new one for the same AP.
+	 */
 	status = dladm_unset_secobj(dld_handle, obj_name,
 	    DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST);
 	if (status != DLADM_STATUS_OK && status != DLADM_STATUS_NOTFOUND) {
@@ -755,8 +818,7 @@
 	nwamd_object_t ncu_obj;
 	nwamd_ncu_t *ncu;
 	nwamd_link_t *link;
-	char key[DLADM_STRSIZE];
-	boolean_t found_old_key = B_FALSE, found_key = B_FALSE;
+	boolean_t found_key = B_FALSE;
 
 	if ((ncu_obj = nwamd_ncu_object_find(NWAM_NCU_TYPE_LINK, linkname))
 	    == NULL) {
@@ -799,24 +861,24 @@
 	/* does this WLAN require a key? If so go to NEED_KEY */
 	if (NEED_ENC(link->nwamd_link_wifi_security_mode)) {
 		/*
-		 * First, if a key name may have been specified for a
-		 * known WLAN.  If so, use it.  Otherwise, try both the
-		 * new nwamd key name format (ESSID) and old (ESSID/BSSID).
-		 * The user may have set the key without adding a known WLAN,
-		 * so we need to try all these options to save going to
-		 * NEED_KEY state.
+		 * nwam secobjs can have two formats: nwam-ESSID-BSSID and
+		 * nwam-ESSID. There is no reason for searching through known
+		 * wlan keynames since this is only the selection process.
 		 */
-		if (known_wlan_get_keyname(link->nwamd_link_wifi_essid,
-		    link->nwamd_link_wifi_keyname) == NWAM_SUCCESS &&
-		    (link->nwamd_link_wifi_key = nwamd_wlan_get_key_named
-		    (link->nwamd_link_wifi_keyname,
+		if ((link->nwamd_link_wifi_key = nwamd_wlan_get_key
+		    (link->nwamd_link_wifi_essid, link->nwamd_link_wifi_bssid,
 		    link->nwamd_link_wifi_security_mode)) != NULL) {
-			(void) known_wlan_get_keyslot
-			    (link->nwamd_link_wifi_essid,
-			    &link->nwamd_link_wifi_key->wk_idx);
-			nlog(LOG_DEBUG, "nwamd_wlan_select: got known WLAN "
-			    "key %s, slot %d", link->nwamd_link_wifi_keyname,
-			    link->nwamd_link_wifi_key->wk_idx);
+			/*
+			 * Found old key format,
+			 * known wlans with similar names might exist
+			 */
+			nwamd_set_key_name(link->nwamd_link_wifi_essid,
+			    link->nwamd_link_wifi_bssid,
+			    link->nwamd_link_wifi_keyname,
+			    DLADM_SECOBJ_NAME_MAX);
+			nlog(LOG_DEBUG, "nwamd_wlan_select: got old format "
+			    "WLAN key %s",
+			    link->nwamd_link_wifi_keyname);
 			found_key = B_TRUE;
 		} else if ((link->nwamd_link_wifi_key = nwamd_wlan_get_key
 		    (link->nwamd_link_wifi_essid, NULL,
@@ -827,27 +889,6 @@
 			nlog(LOG_DEBUG, "nwamd_wlan_select: got WLAN key %s",
 			    link->nwamd_link_wifi_keyname);
 			found_key = B_TRUE;
-		} else if ((link->nwamd_link_wifi_key = nwamd_wlan_get_key
-		    (link->nwamd_link_wifi_essid, link->nwamd_link_wifi_bssid,
-		    link->nwamd_link_wifi_security_mode)) != NULL) {
-			/*
-			 * Found old key format - prepare to save
-			 * it as new ESSID-only key, but don't
-			 * do it until we're released the object
-			 * lock (since nwamd_wlan_set_key()
-			 * takes the object lock).
-			 */
-			(void) strlcpy(key,
-			    (char *)link->nwamd_link_wifi_key->wk_val,
-			    link->nwamd_link_wifi_key->wk_len + 1);
-			found_old_key = B_TRUE;
-			found_key = B_TRUE;
-			nwamd_set_key_name(link->nwamd_link_wifi_essid, NULL,
-			    link->nwamd_link_wifi_keyname,
-			    DLADM_SECOBJ_NAME_MAX);
-			nlog(LOG_DEBUG, "nwamd_wlan_select: got old format "
-			    "WLAN key, converting to %s",
-			    link->nwamd_link_wifi_keyname);
 		} else {
 			nlog(LOG_ERR, "nwamd_wlan_select: could not "
 			    "find key for WLAN '%s'",
@@ -871,10 +912,6 @@
 	}
 	nwamd_object_release(ncu_obj);
 
-	if (found_old_key) {
-		(void) nwamd_wlan_set_key(linkname, essid, NULL, security_mode,
-		    1, key);
-	}
 	return (NWAM_SUCCESS);
 }
 
@@ -882,28 +919,28 @@
  * See if BSSID is in visited list of BSSIDs for known WLAN. Used for
  * strict BSSID matching (depends on wireless_strict_bssid property value).
  */
-static boolean_t
-bssid_match(nwam_known_wlan_handle_t kwh, const char *bssid)
+static int
+bssid_match(nwam_known_wlan_handle_t kwh, void *bssid)
 {
 	nwam_value_t bssidsval;
 	nwam_error_t err;
 	char **bssids;
 	uint_t nelem, i;
-	boolean_t found = B_FALSE;
+	int found = 0;
 
 	if ((err = nwam_known_wlan_get_prop_value(kwh,
 	    NWAM_KNOWN_WLAN_PROP_BSSIDS, &bssidsval)) != NWAM_SUCCESS) {
 		nlog(LOG_ERR, "bssid_match: %s", nwam_strerror(err));
-		return (B_FALSE);
+		return (0);
 	}
 	if ((err = nwam_value_get_string_array(bssidsval, &bssids, &nelem))
 	    != NWAM_SUCCESS) {
 		nwam_value_free(bssidsval);
-		return (B_FALSE);
+		return (0);
 	}
 	for (i = 0; i < nelem; i++) {
-		if (strcmp(bssid, bssids[i]) == 0) {
-			found = B_TRUE;
+		if (strcmp((const char *)bssid, bssids[i]) == 0) {
+			found = 1;
 			break;
 		}
 	}
@@ -951,7 +988,7 @@
 
 	for (i = 0; i < s->nwamd_wifi_scan_curr_num; i++) {
 		nwam_wlan_t *cur_wlan = &(s->nwamd_wifi_scan_curr[i]);
-		boolean_t b_match = bssid_match(kwh, cur_wlan->nww_bssid);
+		int b_match = bssid_match(kwh, cur_wlan->nww_bssid);
 
 		/*
 		 * We need to either match the scanned essid, or in the case
@@ -1332,6 +1369,22 @@
 			char keyname[NWAM_MAX_VALUE_LEN];
 			dladm_wlan_key_t *key = NULL;
 
+			/*
+			 * If strict_bssid is true, we start checking for
+			 * known wlans with the same BSSID.
+			 * This would prevent the selection of secobjs
+			 * that actually are referenced by different kwl
+			 * with the same ESSID.
+			 */
+			if (wireless_strict_bssid) {
+				int b_match = 0;
+				(void) nwam_walk_known_wlans(bssid_match,
+				    s.nwamd_wifi_scan_curr[i].nww_bssid, 0,
+				    &b_match);
+				if (b_match == 0)
+					continue;
+			}
+
 			if (known_wlan_get_keyname
 			    (s.nwamd_wifi_scan_curr[i].nww_essid, keyname)
 			    == NWAM_SUCCESS &&
@@ -1345,6 +1398,8 @@
 				    nww_security_mode ==
 				    DLADM_WLAN_SECMODE_WEP ?
 				    key->wk_idx : 1;
+				nlog(LOG_DEBUG, "found matching keyname for \
+				    %s", s.nwamd_wifi_scan_curr[i].nww_bssid);
 				free(key);
 			}
 		}
--- a/usr/src/cmd/cmd-inet/usr.sbin/nwamadm/nwamadm.c	Mon May 14 16:03:20 2012 -0700
+++ b/usr/src/cmd/cmd-inet/usr.sbin/nwamadm/nwamadm.c	Mon May 14 15:11:16 2012 -0500
@@ -1364,7 +1364,7 @@
 			}
 		}
 
-		err = nwam_wlan_set_key(linkname, essid, NULL, security_mode,
+		err = nwam_wlan_set_key(linkname, essid, bssid, security_mode,
 		    keyslot, key);
 		if (err != NWAM_SUCCESS)
 			die_nwamerr(err, "could not set WiFi key");