gboolean passwd_change_password (PasswdHandler *passwd_handler, const char *new_password, PasswdCallback cb, const gpointer user_data) { GError *error = NULL; passwd_handler->changing_password = TRUE; passwd_handler->new_password = new_password; passwd_handler->chpasswd_cb = cb; passwd_handler->chpasswd_cb_data = user_data; /* Stop passwd if an error occured and it is still running */ if (passwd_handler->backend_state == PASSWD_STATE_ERR) { /* Stop passwd, free resources */ stop_passwd (passwd_handler); } /* Check that the backend is still running, or that an error * has occured but it has not yet exited */ if (passwd_handler->backend_pid == -1) { /* If it is not, re-run authentication */ /* Spawn backend */ stop_passwd (passwd_handler); if (!spawn_passwd (passwd_handler, &error)) { g_warning ("%s", error->message); g_error_free (error); return FALSE; } /* Add current and new passwords to queue */ authenticate (passwd_handler); update_password (passwd_handler); } else { /* Only add new passwords to queue */ update_password (passwd_handler); } /* Pop new password through the backend. * If user has no password, popping the queue would output current * password, while 'passwd' is waiting for the new one. So wait for * io_watch_stdout() to remove current password from the queue, * and output the new one for us. */ if (passwd_handler->current_password) io_queue_pop (passwd_handler->backend_stdin_queue, passwd_handler->backend_stdin); /* Our IO watcher should now handle the rest */ return TRUE; }
/* Start backend and handle errors * If backend is already running, stop it * If an error occurs, show error dialog */ static gboolean passdlg_spawn_passwd (PasswordDialog *pdialog) { GError *error = NULL; gchar *details; /* If backend is running, stop it */ stop_passwd (pdialog); /* Spawn backend */ if (!spawn_passwd (pdialog, &error)) { GtkWidget *parent = GTK_WIDGET (gtk_builder_get_object (pdialog->ui, "change-password")); /* translators: Unable to launch <program>: <error message> */ details = g_strdup_printf (_("Unable to launch %s: %s"), "/usr/bin/passwd", error->message); passdlg_error_dialog (GTK_WINDOW (parent), _("Unable to launch backend"), _("A system error has occurred"), details); g_free (details); g_error_free (error); return FALSE; } return TRUE; }
/* Main */ void mate_about_me_password (GtkWindow *parent) { PasswordDialog *pdialog; GtkBuilder *dialog; GtkWidget *wpassdlg; gint result; gboolean response; /* Initialize dialog */ pdialog = g_new0 (PasswordDialog, 1); passdlg_init (pdialog, parent); dialog = pdialog->ui; wpassdlg = WID ("change-password"); /* Go! */ gtk_widget_show_all (wpassdlg); do { result = gtk_dialog_run (GTK_DIALOG (wpassdlg)); response = passdlg_process_response (pdialog, result); } while (response); /* Clean up */ stop_passwd (pdialog); gtk_widget_destroy (wpassdlg); g_queue_free (pdialog->backend_stdin_queue); g_object_unref (dialog); g_free (pdialog); }
void passwd_destroy (PasswdHandler *passwd_handler) { g_queue_free (passwd_handler->backend_stdin_queue); stop_passwd (passwd_handler); g_free (passwd_handler); }
/* Called when the "Change password" dialog-button is clicked * Returns: TRUE if we want to keep the dialog running, FALSE otherwise */ static gboolean passdlg_process_response (PasswordDialog *pdialog, gint response_id) { if (response_id == GTK_RESPONSE_OK) { /* Set busy as this can be a long process */ passdlg_set_busy (pdialog, TRUE); /* Stop passwd if an error occured and it is still running */ if (pdialog->backend_state == PASSWD_STATE_ERR) { /* Stop passwd, free resources */ stop_passwd (pdialog); } /* Check that the backend is still running, or that an error * hass occured but it has not yet exited */ if (pdialog->backend_pid == -1) { /* If it is not, re-run authentication */ /* Spawn backend */ if (!passdlg_spawn_passwd (pdialog)) { return TRUE; } /* Add current and new passwords to queue */ authenticate (pdialog); update_password (pdialog); } else { /* Only add new passwords to queue */ update_password (pdialog); /* Pop new password through the backend */ io_queue_pop (pdialog->backend_stdin_queue, pdialog->backend_stdin); } /* Our IO watcher should now handle the rest */ /* Keep the dialog running */ return TRUE; } return FALSE; }
void passwd_authenticate (PasswdHandler *passwd_handler, const char *current_password, PasswdCallback cb, const gpointer user_data) { GError *error = NULL; /* Don't stop if we've already started chaging password */ if (passwd_handler->changing_password) return; /* Clear data from possible previous attempts to change password */ passwd_handler->new_password = NULL; passwd_handler->chpasswd_cb = NULL; passwd_handler->chpasswd_cb_data = NULL; g_queue_foreach (passwd_handler->backend_stdin_queue, (GFunc) g_free, NULL); g_queue_clear (passwd_handler->backend_stdin_queue); passwd_handler->current_password = current_password; passwd_handler->auth_cb = cb; passwd_handler->auth_cb_data = user_data; /* Spawn backend */ stop_passwd (passwd_handler); if (!spawn_passwd (passwd_handler, &error)) { g_warning ("%s", error->message); g_error_free (error); return; } authenticate (passwd_handler); /* Our IO watcher should now handle the rest */ }
/* Spawn passwd backend * Returns: TRUE on success, FALSE otherwise and sets error appropriately */ static gboolean spawn_passwd (PasswordDialog *pdialog, GError **error) { gchar *argv[2]; gchar *envp[1]; gint my_stdin, my_stdout, my_stderr; argv[0] = "/usr/bin/passwd"; /* Is it safe to rely on a hard-coded path? */ argv[1] = NULL; envp[0] = NULL; /* If we pass an empty array as the environment, * will the childs environment be empty, and the * locales set to the C default? From the manual: * "If envp is NULL, the child inherits its * parent'senvironment." * If I'm wrong here, we somehow have to set * the locales here. */ if (!g_spawn_async_with_pipes (NULL, /* Working directory */ argv, /* Argument vector */ envp, /* Environment */ G_SPAWN_DO_NOT_REAP_CHILD, /* Flags */ NULL, /* Child setup */ NULL, /* Data to child setup */ &pdialog->backend_pid, /* PID */ &my_stdin, /* Stdin */ &my_stdout, /* Stdout */ &my_stderr, /* Stderr */ error)) { /* GError */ /* An error occured */ free_passwd_resources (pdialog); return FALSE; } /* 2>&1 */ if (dup2 (my_stderr, my_stdout) == -1) { /* Failed! */ g_set_error (error, PASSDLG_ERROR, PASSDLG_ERROR_BACKEND, strerror (errno)); /* Clean up */ stop_passwd (pdialog); return FALSE; } /* Open IO Channels */ pdialog->backend_stdin = g_io_channel_unix_new (my_stdin); pdialog->backend_stdout = g_io_channel_unix_new (my_stdout); /* Set raw encoding */ /* Set nonblocking mode */ if (g_io_channel_set_encoding (pdialog->backend_stdin, NULL, error) != G_IO_STATUS_NORMAL || g_io_channel_set_encoding (pdialog->backend_stdout, NULL, error) != G_IO_STATUS_NORMAL || g_io_channel_set_flags (pdialog->backend_stdin, G_IO_FLAG_NONBLOCK, error) != G_IO_STATUS_NORMAL || g_io_channel_set_flags (pdialog->backend_stdout, G_IO_FLAG_NONBLOCK, error) != G_IO_STATUS_NORMAL ) { /* Clean up */ stop_passwd (pdialog); return FALSE; } /* Turn off buffering */ g_io_channel_set_buffered (pdialog->backend_stdin, FALSE); g_io_channel_set_buffered (pdialog->backend_stdout, FALSE); /* Add IO Channel watcher */ pdialog->backend_stdout_watch_id = g_io_add_watch (pdialog->backend_stdout, G_IO_IN | G_IO_PRI, (GIOFunc) io_watch_stdout, pdialog); /* Add child watcher */ pdialog->backend_child_watch_id = g_child_watch_add (pdialog->backend_pid, (GChildWatchFunc) child_watch_cb, pdialog); /* Success! */ return TRUE; }
/* Spawn passwd backend * Returns: TRUE on success, FALSE otherwise and sets error appropriately */ static gboolean spawn_passwd (PasswdHandler *passwd_handler, GError **error) { gchar *argv[2]; gchar **envp; gint my_stdin, my_stdout, my_stderr; argv[0] = "/usr/bin/passwd"; /* Is it safe to rely on a hard-coded path? */ argv[1] = NULL; envp = g_get_environ (); envp = g_environ_setenv (envp, "LC_ALL", "C", TRUE); if (!g_spawn_async_with_pipes (NULL, /* Working directory */ argv, /* Argument vector */ envp, /* Environment */ G_SPAWN_DO_NOT_REAP_CHILD, /* Flags */ ignore_sigpipe, /* Child setup */ NULL, /* Data to child setup */ &passwd_handler->backend_pid, /* PID */ &my_stdin, /* Stdin */ &my_stdout, /* Stdout */ &my_stderr, /* Stderr */ error)) { /* GError */ /* An error occured */ free_passwd_resources (passwd_handler); g_strfreev (envp); return FALSE; } g_strfreev (envp); /* 2>&1 */ if (dup2 (my_stderr, my_stdout) == -1) { /* Failed! */ g_set_error_literal (error, PASSWD_ERROR, PASSWD_ERROR_BACKEND, strerror (errno)); /* Clean up */ stop_passwd (passwd_handler); return FALSE; } /* Open IO Channels */ passwd_handler->backend_stdin = g_io_channel_unix_new (my_stdin); passwd_handler->backend_stdout = g_io_channel_unix_new (my_stdout); /* Set raw encoding */ /* Set nonblocking mode */ if (g_io_channel_set_encoding (passwd_handler->backend_stdin, NULL, error) != G_IO_STATUS_NORMAL || g_io_channel_set_encoding (passwd_handler->backend_stdout, NULL, error) != G_IO_STATUS_NORMAL || g_io_channel_set_flags (passwd_handler->backend_stdin, G_IO_FLAG_NONBLOCK, error) != G_IO_STATUS_NORMAL || g_io_channel_set_flags (passwd_handler->backend_stdout, G_IO_FLAG_NONBLOCK, error) != G_IO_STATUS_NORMAL ) { /* Clean up */ stop_passwd (passwd_handler); return FALSE; } /* Turn off buffering */ g_io_channel_set_buffered (passwd_handler->backend_stdin, FALSE); g_io_channel_set_buffered (passwd_handler->backend_stdout, FALSE); /* Add IO Channel watcher */ passwd_handler->backend_stdout_watch_id = g_io_add_watch (passwd_handler->backend_stdout, G_IO_IN | G_IO_PRI, (GIOFunc) io_watch_stdout, passwd_handler); /* Add child watcher */ passwd_handler->backend_child_watch_id = g_child_watch_add (passwd_handler->backend_pid, (GChildWatchFunc) child_watch_cb, passwd_handler); /* Success! */ return TRUE; }