/** * This function is called when username or password are requested from user. * This function is called in main thread as async request from dbus. * @param mount_op mount operation * @param message message to show to user * @param default_user preffered user * @param default_domain domain name * @param flags what type of information is required * @param user_data nsIChannel */ static void mount_operation_ask_password (GMountOperation *mount_op, const char *message, const char *default_user, const char *default_domain, GAskPasswordFlags flags, gpointer user_data) { nsIChannel *channel = (nsIChannel *) user_data; if (!channel) { g_mount_operation_reply(mount_op, G_MOUNT_OPERATION_ABORTED); return; } // We can't handle request for domain if (flags & G_ASK_PASSWORD_NEED_DOMAIN) { g_mount_operation_reply(mount_op, G_MOUNT_OPERATION_ABORTED); return; } nsCOMPtr<nsIAuthPrompt> prompt; NS_QueryNotificationCallbacks(channel, prompt); // If no auth prompt, then give up. We could failover to using the // WindowWatcher service, but that might defeat a consumer's purposeful // attempt to disable authentication (for whatever reason). if (!prompt) { g_mount_operation_reply(mount_op, G_MOUNT_OPERATION_ABORTED); return; } // Parse out the host and port... nsCOMPtr<nsIURI> uri; channel->GetURI(getter_AddRefs(uri)); if (!uri) { g_mount_operation_reply(mount_op, G_MOUNT_OPERATION_ABORTED); return; } nsAutoCString scheme, hostPort; uri->GetScheme(scheme); uri->GetHostPort(hostPort); // It doesn't make sense for either of these strings to be empty. What kind // of funky URI is this? if (scheme.IsEmpty() || hostPort.IsEmpty()) { g_mount_operation_reply(mount_op, G_MOUNT_OPERATION_ABORTED); return; } // Construct the single signon key. Altering the value of this key will // cause people's remembered passwords to be forgotten. Think carefully // before changing the way this key is constructed. nsAutoString key, realm; NS_ConvertUTF8toUTF16 dispHost(scheme); dispHost.AppendLiteral("://"); dispHost.Append(NS_ConvertUTF8toUTF16(hostPort)); key = dispHost; if (*default_domain != '\0') { // We assume the realm string is ASCII. That might be a bogus assumption, // but we have no idea what encoding GnomeVFS is using, so for now we'll // limit ourselves to ISO-Latin-1. XXX What is a better solution? realm.Append('"'); realm.Append(NS_ConvertASCIItoUTF16(default_domain)); realm.Append('"'); key.Append(' '); key.Append(realm); } // Construct the message string... // // We use Necko's string bundle here. This code really should be encapsulated // behind some Necko API, after all this code is based closely on the code in // nsHttpChannel.cpp. nsCOMPtr<nsIStringBundleService> bundleSvc = do_GetService(NS_STRINGBUNDLE_CONTRACTID); if (!bundleSvc) { g_mount_operation_reply(mount_op, G_MOUNT_OPERATION_ABORTED); return; } nsCOMPtr<nsIStringBundle> bundle; bundleSvc->CreateBundle("chrome://global/locale/commonDialogs.properties", getter_AddRefs(bundle)); if (!bundle) { g_mount_operation_reply(mount_op, G_MOUNT_OPERATION_ABORTED); return; } nsAutoString nsmessage; if (flags & G_ASK_PASSWORD_NEED_PASSWORD) { if (flags & G_ASK_PASSWORD_NEED_USERNAME) { if (!realm.IsEmpty()) { const char16_t *strings[] = { realm.get(), dispHost.get() }; bundle->FormatStringFromName(MOZ_UTF16("EnterLoginForRealm2"), strings, 2, getter_Copies(nsmessage)); } else { const char16_t *strings[] = { dispHost.get() }; bundle->FormatStringFromName(MOZ_UTF16("EnterUserPasswordFor2"), strings, 1, getter_Copies(nsmessage)); } } else { NS_ConvertUTF8toUTF16 userName(default_user); const char16_t *strings[] = { userName.get(), dispHost.get() }; bundle->FormatStringFromName(MOZ_UTF16("EnterPasswordFor"), strings, 2, getter_Copies(nsmessage)); } } else { g_warning("Unknown mount operation request (flags: %x)", flags); } if (nsmessage.IsEmpty()) { g_mount_operation_reply(mount_op, G_MOUNT_OPERATION_ABORTED); return; } // Prompt the user... nsresult rv; bool retval = false; char16_t *user = nullptr, *pass = nullptr; if (default_user) { // user will be freed by PromptUsernameAndPassword user = ToNewUnicode(NS_ConvertUTF8toUTF16(default_user)); } if (flags & G_ASK_PASSWORD_NEED_USERNAME) { rv = prompt->PromptUsernameAndPassword(nullptr, nsmessage.get(), key.get(), nsIAuthPrompt::SAVE_PASSWORD_PERMANENTLY, &user, &pass, &retval); } else { rv = prompt->PromptPassword(nullptr, nsmessage.get(), key.get(), nsIAuthPrompt::SAVE_PASSWORD_PERMANENTLY, &pass, &retval); } if (NS_FAILED(rv) || !retval) { // was || user == '\0' || pass == '\0' g_mount_operation_reply(mount_op, G_MOUNT_OPERATION_ABORTED); free(user); free(pass); return; } /* GIO should accept UTF8 */ g_mount_operation_set_username(mount_op, NS_ConvertUTF16toUTF8(user).get()); g_mount_operation_set_password(mount_op, NS_ConvertUTF16toUTF8(pass).get()); free(user); free(pass); g_mount_operation_reply(mount_op, G_MOUNT_OPERATION_HANDLED); }
static void ProxiedAuthCallback(gconstpointer in, gsize in_size, gpointer out, gsize out_size, gpointer callback_data) { GnomeVFSModuleCallbackAuthenticationIn *authIn = (GnomeVFSModuleCallbackAuthenticationIn *) in; GnomeVFSModuleCallbackAuthenticationOut *authOut = (GnomeVFSModuleCallbackAuthenticationOut *) out; LOG(("gnomevfs: ProxiedAuthCallback [uri=%s]\n", authIn->uri)); // Without a channel, we have no way of getting a prompter. nsIChannel *channel = (nsIChannel *) callback_data; if (!channel) return; nsCOMPtr<nsIAuthPrompt> prompt; NS_QueryNotificationCallbacks(channel, prompt); // If no auth prompt, then give up. We could failover to using the // WindowWatcher service, but that might defeat a consumer's purposeful // attempt to disable authentication (for whatever reason). if (!prompt) return; // Parse out the host and port... nsCOMPtr<nsIURI> uri; channel->GetURI(getter_AddRefs(uri)); if (!uri) return; #ifdef DEBUG { // // Make sure authIn->uri is consistent with the channel's URI. // // XXX This check is probably not IDN safe, and it might incorrectly // fire as a result of escaping differences. It's unclear what // kind of transforms GnomeVFS might have applied to the URI spec // that we originally gave to it. In spite of the likelihood of // false hits, this check is probably still valuable. // nsAutoCString spec; uri->GetSpec(spec); int uriLen = strlen(authIn->uri); if (!StringHead(spec, uriLen).Equals(nsDependentCString(authIn->uri, uriLen))) { LOG(("gnomevfs: [spec=%s authIn->uri=%s]\n", spec.get(), authIn->uri)); NS_ERROR("URI mismatch"); } } #endif nsAutoCString scheme, hostPort; uri->GetScheme(scheme); uri->GetHostPort(hostPort); // It doesn't make sense for either of these strings to be empty. What kind // of funky URI is this? if (scheme.IsEmpty() || hostPort.IsEmpty()) return; // Construct the single signon key. Altering the value of this key will // cause people's remembered passwords to be forgotten. Think carefully // before changing the way this key is constructed. nsAutoString key, realm; NS_ConvertUTF8toUTF16 dispHost(scheme); dispHost.AppendLiteral("://"); dispHost.Append(NS_ConvertUTF8toUTF16(hostPort)); key = dispHost; if (authIn->realm) { // We assume the realm string is ASCII. That might be a bogus assumption, // but we have no idea what encoding GnomeVFS is using, so for now we'll // limit ourselves to ISO-Latin-1. XXX What is a better solution? realm.Append('"'); realm.Append(NS_ConvertASCIItoUTF16(authIn->realm)); realm.Append('"'); key.Append(' '); key.Append(realm); } // Construct the message string... // // We use Necko's string bundle here. This code really should be encapsulated // behind some Necko API, after all this code is based closely on the code in // nsHttpChannel.cpp. nsCOMPtr<nsIStringBundleService> bundleSvc = do_GetService(NS_STRINGBUNDLE_CONTRACTID); if (!bundleSvc) return; nsCOMPtr<nsIStringBundle> bundle; bundleSvc->CreateBundle("chrome://global/locale/commonDialogs.properties", getter_AddRefs(bundle)); if (!bundle) return; nsString message; if (!realm.IsEmpty()) { const char16_t *strings[] = { realm.get(), dispHost.get() }; bundle->FormatStringFromName(MOZ_UTF16("EnterUserPasswordForRealm"), strings, 2, getter_Copies(message)); } else { const char16_t *strings[] = { dispHost.get() }; bundle->FormatStringFromName(MOZ_UTF16("EnterUserPasswordFor"), strings, 1, getter_Copies(message)); } if (message.IsEmpty()) return; // Prompt the user... nsresult rv; bool retval = false; char16_t *user = nullptr, *pass = nullptr; rv = prompt->PromptUsernameAndPassword(nullptr, message.get(), key.get(), nsIAuthPrompt::SAVE_PASSWORD_PERMANENTLY, &user, &pass, &retval); if (NS_FAILED(rv)) return; if (!retval || !user || !pass) return; // XXX We need to convert the UTF-16 username and password from our dialog to // strings that GnomeVFS can understand. It's unclear what encoding GnomeVFS // expects, so for now we assume 7-bit ASCII. Hopefully, we can get a better // solution at some point. // One copy is never enough... authOut->username = g_strdup(NS_LossyConvertUTF16toASCII(user).get()); authOut->password = g_strdup(NS_LossyConvertUTF16toASCII(pass).get()); nsMemory::Free(user); nsMemory::Free(pass); }