void vpn_died(struct connman_task *task, int exit_code, void *user_data) { struct vpn_provider *provider = user_data; struct vpn_data *data = vpn_provider_get_data(provider); int state = VPN_STATE_FAILURE; enum vpn_provider_error ret; DBG("provider %p data %p", provider, data); if (!data) goto vpn_exit; state = data->state; stop_vpn(provider); vpn_provider_set_data(provider, NULL); if (data->watch != 0) { vpn_rtnl_remove_watch(data->watch); data->watch = 0; vpn_provider_unref(provider); } vpn_exit: if (state != VPN_STATE_READY && state != VPN_STATE_DISCONNECT) { const char *name; struct vpn_driver_data *vpn_data = NULL; name = vpn_provider_get_driver_name(provider); if (name) vpn_data = g_hash_table_lookup(driver_hash, name); if (vpn_data && vpn_data->vpn_driver->error_code) ret = vpn_data->vpn_driver->error_code(provider, exit_code); else ret = VPN_PROVIDER_ERROR_UNKNOWN; vpn_provider_indicate_error(provider, ret); } else vpn_provider_set_state(provider, VPN_PROVIDER_STATE_IDLE); vpn_provider_set_index(provider, -1); if (data) { vpn_provider_unref(data->provider); g_free(data->if_name); g_free(data); } connman_task_destroy(task); }
static int oc_connect(struct vpn_provider *provider, struct connman_task *task, const char *if_name, vpn_provider_connect_cb_t cb, void *user_data) { const char *vpnhost, *vpncookie, *servercert; int err; vpnhost = vpn_provider_get_string(provider, "Host"); if (vpnhost == NULL) { connman_error("Host not set; cannot enable VPN"); return -EINVAL; } vpncookie = vpn_provider_get_string(provider, "OpenConnect.Cookie"); servercert = vpn_provider_get_string(provider, "OpenConnect.ServerCert"); if (vpncookie == NULL || servercert == NULL) { struct oc_private_data *data; data = g_try_new0(struct oc_private_data, 1); if (data == NULL) return -ENOMEM; data->provider = provider; data->task = task; data->if_name = g_strdup(if_name); data->cb = cb; data->user_data = user_data; err = request_cookie_input(provider, data); if (err != -EINPROGRESS) { vpn_provider_indicate_error(data->provider, VPN_PROVIDER_ERROR_LOGIN_FAILED); free_private_data(data); } return err; } return run_connect(provider, task, if_name, cb, user_data); }
static void request_input_cookie_reply(DBusMessage *reply, void *user_data) { struct oc_private_data *data = user_data; char *cookie = NULL, *servercert = NULL, *vpnhost = NULL; char *key; DBusMessageIter iter, dict; DBG("provider %p", data->provider); if (dbus_message_get_type(reply) == DBUS_MESSAGE_TYPE_ERROR) { goto err; } if (vpn_agent_check_reply_has_dict(reply) == FALSE) goto err; dbus_message_iter_init(reply, &iter); dbus_message_iter_recurse(&iter, &dict); while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) { DBusMessageIter entry, value; dbus_message_iter_recurse(&dict, &entry); if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_STRING) break; dbus_message_iter_get_basic(&entry, &key); if (g_str_equal(key, "OpenConnect.Cookie")) { dbus_message_iter_next(&entry); if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_VARIANT) break; dbus_message_iter_recurse(&entry, &value); if (dbus_message_iter_get_arg_type(&value) != DBUS_TYPE_STRING) break; dbus_message_iter_get_basic(&value, &cookie); vpn_provider_set_string_hide_value(data->provider, key, cookie); } else if (g_str_equal(key, "OpenConnect.ServerCert")) { dbus_message_iter_next(&entry); if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_VARIANT) break; dbus_message_iter_recurse(&entry, &value); if (dbus_message_iter_get_arg_type(&value) != DBUS_TYPE_STRING) break; dbus_message_iter_get_basic(&value, &servercert); vpn_provider_set_string(data->provider, key, servercert); } else if (g_str_equal(key, "OpenConnect.VPNHost")) { dbus_message_iter_next(&entry); if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_VARIANT) break; dbus_message_iter_recurse(&entry, &value); if (dbus_message_iter_get_arg_type(&value) != DBUS_TYPE_STRING) break; dbus_message_iter_get_basic(&value, &vpnhost); vpn_provider_set_string(data->provider, key, vpnhost); } dbus_message_iter_next(&dict); } if (cookie == NULL || servercert == NULL || vpnhost == NULL) goto err; run_connect(data->provider, data->task, data->if_name, data->cb, data->user_data); free_private_data(data); return; err: vpn_provider_indicate_error(data->provider, VPN_PROVIDER_ERROR_AUTH_FAILED); free_private_data(data); }
static DBusMessage *vpn_notify(struct connman_task *task, DBusMessage *msg, void *user_data) { struct vpn_provider *provider = user_data; struct vpn_data *data; struct vpn_driver_data *vpn_driver_data; const char *name; int state, index, err; data = vpn_provider_get_data(provider); name = vpn_provider_get_driver_name(provider); if (!name) { DBG("Cannot find VPN driver for provider %p", provider); vpn_provider_set_state(provider, VPN_PROVIDER_STATE_FAILURE); return NULL; } vpn_driver_data = g_hash_table_lookup(driver_hash, name); if (!vpn_driver_data) { DBG("Cannot find VPN driver data for name %s", name); vpn_provider_set_state(provider, VPN_PROVIDER_STATE_FAILURE); return NULL; } state = vpn_driver_data->vpn_driver->notify(msg, provider); DBG("provider %p driver %s state %d", provider, name, state); switch (state) { case VPN_STATE_CONNECT: case VPN_STATE_READY: if (data->state == VPN_STATE_READY) { /* * This is the restart case, in which case we must * just set the IP address. * * We need to remove first the old address, just * replacing the old address will not work as expected * because the old address will linger in the interface * and not disapper so the clearing is needed here. * * Also the state must change, otherwise the routes * will not be set properly. */ vpn_provider_set_state(provider, VPN_PROVIDER_STATE_CONNECT); vpn_provider_clear_address(provider, AF_INET); vpn_provider_clear_address(provider, AF_INET6); vpn_provider_change_address(provider); vpn_provider_set_state(provider, VPN_PROVIDER_STATE_READY); break; } index = vpn_provider_get_index(provider); vpn_provider_ref(provider); data->watch = vpn_rtnl_add_newlink_watch(index, vpn_newlink, provider); err = connman_inet_ifup(index); if (err < 0) { if (err == -EALREADY) /* * So the interface is up already, that is just * great. Unfortunately in this case the * newlink watch might not have been called at * all. We must manually call it here so that * the provider can go to ready state and the * routes are setup properly. */ vpn_newlink(IFF_UP, 0, provider); else DBG("Cannot take interface %d up err %d/%s", index, -err, strerror(-err)); } break; case VPN_STATE_UNKNOWN: case VPN_STATE_IDLE: case VPN_STATE_DISCONNECT: case VPN_STATE_FAILURE: vpn_provider_set_state(provider, VPN_PROVIDER_STATE_DISCONNECT); break; case VPN_STATE_AUTH_FAILURE: vpn_provider_indicate_error(provider, VPN_PROVIDER_ERROR_AUTH_FAILED); break; } return NULL; }