/* * * Wireless daemon for Linux * * Copyright (C) 2017-2019 Intel Corporation. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include "src/iwd.h" #include "src/module.h" #include "src/watchlist.h" #include "src/simauth.h" static struct l_queue *auth_providers; struct iwd_sim_auth { const struct iwd_sim_auth_driver *driver; void *driver_data; bool aka_supported : 1; bool sim_supported : 1; char *nai; int pending; struct watchlist auth_watchers; }; struct iwd_sim_auth *iwd_sim_auth_create( const struct iwd_sim_auth_driver *driver) { struct iwd_sim_auth *auth = l_new(struct iwd_sim_auth, 1); auth->driver = driver; watchlist_init(&auth->auth_watchers, NULL); return auth; } void iwd_sim_auth_set_nai(struct iwd_sim_auth *auth, const char *nai) { auth->nai = l_strdup(nai); } void iwd_sim_auth_set_capabilities(struct iwd_sim_auth *auth, bool sim_supported, bool aka_supported) { auth->sim_supported = sim_supported; auth->aka_supported = aka_supported; } void iwd_sim_auth_set_data(struct iwd_sim_auth *auth, void *driver_data) { auth->driver_data = driver_data; } bool iwd_sim_auth_register(struct iwd_sim_auth *auth) { return l_queue_push_head(auth_providers, auth); } void *iwd_sim_auth_get_data(struct iwd_sim_auth *auth) { return auth->driver_data; } static void destroy_provider(void *data) { struct iwd_sim_auth *auth = data; if (auth->driver->remove) auth->driver->remove(auth); watchlist_destroy(&auth->auth_watchers); l_free(auth->nai); l_free(auth); } void iwd_sim_auth_remove(struct iwd_sim_auth *auth) { if (auth->driver && auth->driver->cancel_request) auth->driver->cancel_request(auth, auth->pending); WATCHLIST_NOTIFY_NO_ARGS(&auth->auth_watchers, sim_auth_unregistered_cb_t); l_queue_remove(auth_providers, auth); destroy_provider(auth); } const char *iwd_sim_auth_get_nai(struct iwd_sim_auth *auth) { return auth->nai; } struct iwd_sim_auth *iwd_sim_auth_find(bool sim, bool aka) { struct iwd_sim_auth *auth; const struct l_queue_entry *entry; for (entry = l_queue_get_entries(auth_providers); entry; entry = entry->next) { auth = entry->data; if (sim && !auth->sim_supported) continue; if (aka && !auth->aka_supported) continue; return auth; } return NULL; } unsigned int sim_auth_unregistered_watch_add(struct iwd_sim_auth *auth, sim_auth_unregistered_cb_t cb, void *data) { return watchlist_add(&auth->auth_watchers, cb, data, NULL); } void sim_auth_unregistered_watch_remove(struct iwd_sim_auth *auth, unsigned int id) { watchlist_remove(&auth->auth_watchers, id); } int sim_auth_check_milenage(struct iwd_sim_auth *auth, const uint8_t *rand, const uint8_t *autn, sim_auth_check_milenage_cb_t cb, void *data) { if (!auth->aka_supported) return -1; /* save ID in case simauth is destroyed */ auth->pending = auth->driver->check_milenage(auth, rand, autn, cb, data); return auth->pending; } int sim_auth_run_gsm(struct iwd_sim_auth *auth, const uint8_t *rands, int num_rands, sim_auth_run_gsm_cb_t cb, void *data) { if (!auth->sim_supported) return -1; /* save ID in case simauth is destroyed */ auth->pending = auth->driver->run_gsm(auth, rands, num_rands, cb, data); return auth->pending; } void sim_auth_cancel_request(struct iwd_sim_auth *auth, int id) { if (auth->driver->cancel_request) auth->driver->cancel_request(auth, id); } static int sim_auth_init(void) { auth_providers = l_queue_new(); return 0; } static void sim_auth_exit(void) { if (l_queue_length(auth_providers) > 0) l_warn("Auth provider queue was not empty on exit!"); l_queue_destroy(auth_providers, destroy_provider); } IWD_MODULE(simauth, sim_auth_init, sim_auth_exit)