To avoid confusion in case of an authenticator side handshake_state
structure and eapol_sm structure, rename own_ie to supplicant_ie and
ap_ie to authenticator_ie. Also rename
handshake_state_set_{own,ap}_{rsn,wpa} and fix when we call
handshake_state_setup_own_ciphers. As a result
handshake_state_set_authenticator, if needed, should be called before
handshake_state_set_{own,ap}_{rsn,wpa}.
After EAPOL logic was moved to eapol.c a check was added to
ap_associate_sta_cb to bitwise compare the AP's RSNE to the RSNE
received in the (Re)Association frame. There is as far as I know no
reason for them to be the same (although they are in our autotest) and
if there was a reason we'd rather validate the (Re)Association RSNE
immediately when received. We also must set different RSNEs as the
"own" (supplicant) and "ap" RSNEs in the handshake_state for validation
of step 2/4 in eapol.c (fixes wpa_supplicant's and MS Windows
connections being rejected)
Make sure we interrupt eapol traffic (4-way handshake) if we receive a
Disassociation from station. Actually do this in ap_del_station because
it's called from both ap_disassoc_cb and ap_success_assoc_resp_cb and
seems to make sense in both cases.
On one hand when we're called with HANDSHAKE_EVENT_FAILED or
HANDSHAKE_EVENT_SETTING_KEYS_FAILED the eapol_sm will be freed in
eapol.c, fix a double-free by setting it to NULL before ap_free_sta
is called.
On the other hand make sure we call eapol_sm_free before setting
sta->sm to NULL in ap_drop_rsna to avoid potential leak and avoid
the eapol_sm continuing to use the handshake_state we freed.
timespec_compare wanted to receive network_info structures as arguments
to compare connected_time timestamps but in one instance we were passing
actual timespec structures. Add a new function to compare plain timespec
values and switch the names for readability.
==7330== 112 bytes in 1 blocks are still reachable in loss record 1 of 1
==7330== at 0x4C2CF8F: malloc (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
==7330== by 0x14CF7D: l_malloc (util.c:62)
==7330== by 0x152A25: l_io_new (io.c:172)
==7330== by 0x16B217: l_fswatch_init (fswatch.c:171)
==7330== by 0x16B217: l_fswatch_new (fswatch.c:198)
==7330== by 0x13B9D9: known_networks_init (knownnetworks.c:401)
==7330== by 0x110020: main (main.c:439)
There was somewhat overlapping functionality in the device_watch
infrastructure as well as the netdev_event_watch. This commit combines
the two into a single watch based on the netdev object and cleans up the
various interface additions / removals.
With this commit the interfaces are created when the netdev/device is
switched to Powered=True state AND when the netdev iftype is also in the
correct state for that interface. If the device is brought down, then
all interfaces except the .Device interface are removed.
This will make it easy to implement Device.Mode property properly since
most nl80211 devices need to be brought into Powered=False state prior
to switching the iftype.
The way that netdev_set_linkmode_and_operstate was used resulted in
potential crashes when the netdev was destroyed. This is because netdev
was given as data to l_netlink_send and could be destroyed between the
time of the call and the callback. Since the result of calls to
netdev_set_linkmode_and_operstate is inconsequential, it isn't really
worthwhile tracking these calls in order to cancel them.
This patch simplies the handling of these rtnl calls, makes sure that
netdev isn't passed as user data and rewrites the
netdev_set_linkmode_and_operstate signature to be more consistent with
rtnl_set_powered.
Since all netdevs share the rtnl l_netlink object, it was possible for
netdevs to be destroyed with outstanding commands still executing on the
rtnl object. This can lead to crashes and other nasty situations.
This patch makes sure that Powered requests are always tracked via
set_powered_cmd_id and the request is canceled when netdev is destroyed.
This also implies that netdev_set_powered can now return an -EBUSY error
in case a request is already outstanding.
SAE is meant to work in a peer-to-peer fashion where neither side acts
as a dedicated authenticator or supplicant. This was not the case with
the current code. The handshake state authenticator address was hard
coded as the destination address for all packets, which will not work
when mesh comes into play. This also made unit testing the full SAE
procedure with two sae_sm's impossible.
This patch adds a peer address element to sae_sm which is filled with
either aa/spa based on the value of handshake->authenticator
This removes the authenticator bit in eapol_sm as well as unifies
eapol_register_authenticator and eapol_register. Taking advantage
of the handshake state authenticator bit we no longer have a need
for 2 separate register functions.
ap, and adhoc were also updated to set the authenticator bit in
the handshake and only use eapol_register to register their sm's.
netdev was updated to use the authenticator bit when choosing the
correct key address for adhoc.
Both SAE and adhoc can benefit from knowing whether the handshake state
is an authenticator or a supplicant. It will allow both to easily
obtain the remote address rather than sorting out if aa/spa match the
devices own address.
The send confirm counter is incremented before calling sae_send_confirm
in all cases, but the function itself was also incrementing sc after
sending the packet. This isn't critical to the successful execution of
SAE as the AP just uses the sc value in the packet but it did violate
the 802.11 spec.
In order to plug SAE into the existing connect mechanism the actual
CMD_CONNECT message is never sent, rather sae_register takes care
of sending out CMD_AUTHENTICATE. This required some shuffling of
code in order to handle both eapol and sae. In the case of non-SAE
authentication everything behaves as it did before. When using SAE
an sae_sm is created when a connection is attempted but the eapol_sm
is not. After SAE succeeds it will start association and then create
the eapol_sm and start the 4-way handshake.
This change also adds the handshake SAE events to device and
initializes SAE in main.
SAE (Simultaneous Authentication of Equals) takes place during
authentication, and followed by EAPoL/4-way handshake. This
module handles the entire SAE commit/confirm exchange. This was
done similar to eapol.
SAE begins when sae_register is called. At this point a commit
message will be created and sent out which kicks off the SAE
authentication procedure.
The commit/confirm exchange is very similar to EAP-PWD, so all
the ecc utility functions could be re-used as-is. A few new ecc
utility functions were added to conform to the 80211 'blinding'
technique for computing the password element.
For an SAE network, the raw passphrase is required. For this reason,
known network psk files should now always contain a 'Passphrase' entry.
If a psk file is found without a Passphrase entry the agent will be asked
for the Passphrase before connecting. This will update the legacy psk
file with the Passphrase entry.
Due to the quirk in how storage_network_sync implements file writing,
iwd was generating unnecessary KnownNetwork removal events (and
preventing certain test cases from passing successfully)
storage_network_sync tries to perform atomic writes by writing to a
temporary storage location first, unlinking the existing file and
renaming the tmp file as the original.
This generates a set of inotify events which confuses the current
implementation.
The previous change did not consider the case of the PSK being written
for the very first time. In this case storage_network_open would return
NULL and an empty file would be written.
Change this so that if storage_network_open fails, then the current
network settings are written to disk and not a temporary.
Reload the network settings from disk before calling
storage_network_sync in network_sync_psk to avoid potentially
overwriting changes made to the storage by user since the connection
attempt started. This won't account for all situations but it
covers some of them and doesn't cost us much.
Our logic would set CONTROL_PORT_OVER_NL80211 even in cases where
CONTROL_PORT wasn't used (e.g. for open networks). While the kernel
ignored this attribute in this case, it is nicer to set this only if
CONTROL_PORT is intended to be used.
SAE will require some of the same CMD_ASSOCIATE building code that
FT currently uses. This breaks out the common code from FT into
netdev_build_cmd_associate_common.
This also required passing in the akm suite in case the key description
version was zero. In the zero case the akm must be checked. For now this
only supports the SAE akm.
Update the known networks list and network properties on file creations,
removals and modifications. We watch for these filesystem events using
ell's fswatch and react accordingly.
This makes testEAP-PEAP-GTC pass for me by re-adding the check for the
GTC-Secret setting which was replaced with the check for the secrets
list in 3d2285ec7e.
eap_append_secret now takes a new cache_policy parameter which can be
used by the EAP method to signal that the value received from the agent
is to never be cached, i.e. each value can only be used once. The
parameter value should be EAP_CACHE_NEVER for this and we use this in
value EAP-GTC where the secret tokens are one time use. The
EAP_CACHE_TEMPORARY value is used in other methods, it preserves the
default behaviour where a secret can be cached for as long as the
network stays in range (this is the current implementation more than a
design choice I believe, I didn't go for a more specific enum name as
this may still change I suppose).
SAE generates the PMKID during the authentication process, rather than
generating it on-the-fly using the PMK. For this reason SAE needs to be
able to set the PMKID once its generated. A new flag was also added
(has_pmkid) which signifies if the PMKID was set or if it should be
generated.
SAE needs access to the raw passphrase, not the PSK which network
saves. This changes saves the passphrase in network and handshake
objects, as well as adds getters to both objects so SAE can retrieve
the passphrase.
This fixes improper cleanup when ofono leaves the bus after a simauth
instance has been cleaned up. The problem was that the plugin
exit was being called after the simauth module, causing there to
be stale simauth instances that were no longer valid. Now plugins
cleanup before simauth.
This fix fixes the print seen when iwd exits:
"Auth provider queue was not empty on exit!"
Make the network_storage_* functions uniformly accept an enum value
instead of a string so that he conversion to string doesn't need to
happen in all callers.
Now, EAP-GTC behaves similar to MSCHAPv2 where check_settings allows
for missing EAP-Identity and GTC-Secret fields. Either or both can be
missing and the agent will request the missing fields.
Add ObjectManager objects with properties for each Known Network so that
signals are emitted for creation or removal of a Known Network and a
Property Changed is emitted on LastConnectedTime change. Remove the
ListKnownNetworks method from the old KnownNetworks interface.
Note this breaks clients that used the known networks interface.
Drop the corresponding network_info field, function and D-Bus property.
The last seen times didn't seem useful but if a client needs them it can
probably implement the same logic with the information already available
through DBus.
If the sm object (or the handshake object) is NULL, don't call the
corresponding function.
0 0x7fb6cd37da80 in /lib64/libc.so.6
1 0x414764 in eapol_sm_destroy() at eapol.c:673
2 0x42e402 in ap_sta_free() at ap.c:97
3 0x439dbe in l_queue_clear() at /home/parallels/wrk/iwd/ell/queue.c:109
4 0x439e09 in l_queue_destroy() at /home/parallels/wrk/iwd/ell/queue.c:83
5 0x42e4bf in ap_reset() at ap.c:132
6 0x42e519 in ap_free() at ap.c:147
7 0x447456 in interface_instance_free() at /home/parallels/wrk/iwd/ell/dbus-service.c:513
8 0x449be0 in _dbus_object_tree_remove_interface() at /home/parallels/wrk/iwd/ell/dbus-service.c:1595
9 0x449ced in _dbus_object_tree_object_destroy() at /home/parallels/wrk/iwd/ell/dbus-service.c:787
10 0x40fb8c in device_free() at device.c:2717
11 0x405cdb in netdev_free() at netdev.c:605
12 0x439dbe in l_queue_clear() at /home/parallels/wrk/iwd/ell/queue.c:109
13 0x439e09 in l_queue_destroy() at /home/parallels/wrk/iwd/ell/queue.c:83
14 0x40aac2 in netdev_shutdown() at netdev.c:4483
15 0x403b75 in iwd_shutdown() at main.c:80
16 0x43d9f3 in signal_callback() at /home/parallels/wrk/iwd/ell/signal.c:83
17 0x43d4ee in l_main_iterate() at /home/parallels/wrk/iwd/ell/main.c:376
18 0x43d5ac in l_main_run() at /home/parallels/wrk/iwd/ell/main.c:419
19 0x40379b in main() at main.c:454
20 0x7fb6cd36788a in /lib64/libc.so.6
Until now network.c managed the list of network_info structs including
for known networks and networks that are seen in at least one device's
scan results, with the is_known flag to distinguish known networks.
Each time the list was processed though the code was either interested
in one subset of networks or the other. Split the list into a Known
Networks list and the list of other networks seen in scans. Move all
code related to Known Networks to knownnetworks.c, this simplifies
network.h. It also gets rid of network_info_get_known which actually
returned the list of all network_infos (not just for known networks),
which logically should have been private to network.c. Update device.c
and scan.c to use functions specific to Known Networks instead of
filtering the lists by the is_known flag.
This will also allow knownnetworks.c to export DBus objects and/or
properties for the Known Networks information because it now knows when
Known Networks are added, removed or modified by IWD.
The return value from network_connected is not checked and even if one
of the storage operations fails the function should probably continue
so only print a message on error.
If the device mode it toggled from 'ap' back to 'station' without actually
starting the access point ap_free attempts to zero out the psk, which
causes a crash because it had never been allocated (Start() never was
called). Since ap->psk is actually never used this was removed. Also added
a memset to zero out the pmk on cleanup.
This is the crash observed:
++++++++ backtrace ++++++++
0 0x7f6ffe978a80 in /lib64/libc.so.6
1 0x7f6ffe9d6766 in /lib64/libc.so.6
2 0x42dd51 in memset() at /usr/include/bits/string3.h:90
3 0x42ddd9 in ap_free() at src/ap.c:144
4 0x445ec6 in interface_instance_free() at ell/dbus-service.c:513
5 0x448650 in _dbus_object_tree_remove_interface() at ell/dbus-service.c:1595
6 0x40d980 in device_set_mode_sta() at src/device.c:2113
7 0x447d4c in properties_set() at ell/dbus-service.c:1861
8 0x448a33 in _dbus_object_tree_dispatch() at ell/dbus-service.c:1691
9 0x442587 in message_read_handler() at ell/dbus.c:285
10 0x43cac9 in io_callback() at ell/io.c:123
11 0x43bf5e in l_main_iterate() at ell/main.c:376
12 0x43c01c in l_main_run() at ell/main.c:419
13 0x40379d in main() at src/main.c:460
14 0x7f6ffe96288a in /lib64/libc.so.6
+++++++++++++++++++++++++++