Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

9957 mate-about-me can't change user password #4581

Merged
merged 11 commits into from
Nov 19, 2018
2 changes: 1 addition & 1 deletion components/desktop/mate/mate-control-center/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ include ../../../../make-rules/shared-macros.mk
COMPONENT_NAME= mate-control-center
COMPONENT_MJR_VERSION= 1.20
COMPONENT_MNR_VERSION= 3
COMPONENT_REVISION= 1
COMPONENT_REVISION= 2
COMPONENT_VERSION= $(COMPONENT_MJR_VERSION).$(COMPONENT_MNR_VERSION)
COMPONENT_PROJECT_URL= http://www.mate-desktop.org
COMPONENT_SUMMARY= MATE desktop wide preference configuration tools
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,295 @@
diff --git a/capplets/about-me/mate-about-me-password.c b/capplets/about-me/mate-about-me-password.c
index abac117..5a82566 100644
--- a/capplets/about-me/mate-about-me-password.c
+++ b/capplets/about-me/mate-about-me-password.c
@@ -27,6 +27,14 @@
# include <config.h>
#endif

+/* This is needed to get ptmx-related functions in GLIBC */
+#ifndef _XOPEN_SOURCE
+#define _XOPEN_SOURCE 600
+#endif
+
+/* This is needed to get pipe2() in GLIBC */
+#define _GNU_SOURCE
+
/* Are all of these needed? */
#include <gdk/gdkkeysyms.h>
#include <pwd.h>
@@ -35,6 +43,16 @@
#include <errno.h>
#include <string.h>
#include <sys/wait.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stropts.h>
+#include <termios.h>
+
+#define PASSWD "/usr/bin/passwd"
+#define PTMX "/dev/ptmx"
+
+/* /dev/pts/N */
+#define PTY_MAX_NAME 20

#if __sun
#include <sys/types.h>
@@ -85,6 +103,9 @@ typedef struct {
/* Buffer size for backend output */
#define BUFSIZE 64

+/* Bufffer size for backend error messages */
+#define ERRBUFSIZE 1024
+
/*
* Error handling {{
*/
@@ -170,85 +191,178 @@ static gboolean
spawn_passwd (PasswordDialog *pdialog, GError **error)
{
gchar *argv[2];
- gchar *envp[1];
- gint my_stdin, my_stdout, my_stderr;
+ int pid, pty_m, err_pipe[2];
+ char slave_name[PTY_MAX_NAME];
+ char *name;

- argv[0] = "/usr/bin/passwd"; /* Is it safe to rely on a hard-coded path? */
+ argv[0] = 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 occurred */
- free_passwd_resources (pdialog);
-
+ pty_m = open(PTMX, O_RDWR|O_NOCTTY);
+ if (pty_m > 0) {
+ name = ptsname(pty_m);
+ if (name && (strlen(name) < PTY_MAX_NAME)) {
+ strncpy(slave_name, name, PTY_MAX_NAME);
+ } else {
+ g_set_error(error,
+ PASSDLG_ERROR,
+ PASSDLG_ERROR_BACKEND,
+ _("Couldn't get slave_name of pty"));
+ close(pty_m);
+ return FALSE;
+ }
+ } else {
+ g_set_error (error,
+ PASSDLG_ERROR,
+ PASSDLG_ERROR_BACKEND,
+ _("Couldn't open pseudo-tty"));
return FALSE;
}

- /* 2>&1 */
- if (dup2 (my_stderr, my_stdout) == -1) {
- /* Failed! */
+ if (grantpt(pty_m) < 0) {
g_set_error (error,
- PASSDLG_ERROR,
- PASSDLG_ERROR_BACKEND,
- "%s",
- strerror (errno));
-
- /* Clean up */
- stop_passwd (pdialog);
-
+ PASSDLG_ERROR,
+ PASSDLG_ERROR_BACKEND,
+ _("Couldn't set permission on slave device: %s"),
+ strerror(errno));
+ close(pty_m);
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 ) {
+ if (unlockpt(pty_m) < 0) {
+ g_set_error (error,
+ PASSDLG_ERROR,
+ PASSDLG_ERROR_BACKEND,
+ _("Couldn't unlock slave device: %s"),
+ strerror(errno));
+ close(pty_m);
+ return FALSE;
+ }

- /* Clean up */
- stop_passwd (pdialog);
+ if (pipe2(err_pipe, O_CLOEXEC) < 0) {
+ g_set_error (error,
+ PASSDLG_ERROR,
+ PASSDLG_ERROR_BACKEND,
+ _("Couldn't create error reporting pipe: %s"),
+ strerror(errno));
+ close(pty_m);
return FALSE;
}
+
+ pid = fork();
+ if (pid == 0) {
+ /* Child */
+ int pty_s, len;
+ char buf[ERRBUFSIZE];
+ close(err_pipe[0]);
+
+ close(pty_m);
+ if (setsid() < 0) {
+ len = snprintf(buf, ERRBUFSIZE, _("Couldn't create new process group: %s"), strerror(errno));
+ write(err_pipe[1], buf, (len>ERRBUFSIZE) ? ERRBUFSIZE : len );
+ exit(1);
+ }

- /* Turn off buffering */
- g_io_channel_set_buffered (pdialog->backend_stdin, FALSE);
- g_io_channel_set_buffered (pdialog->backend_stdout, FALSE);
+ /* Now we are a session leader, on System V first open tty will become controlling tty */
+ pty_s = open(slave_name, O_RDWR);

- /* 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);
+ if (pty_s < 0) {
+ len = snprintf(buf, ERRBUFSIZE, _("Couldn't open slave terminal device: %s"), strerror(errno));
+ write(err_pipe[1], buf, (len>ERRBUFSIZE) ? ERRBUFSIZE : len );
+ exit(1);
+ }
+
+#if defined(TIOCSCTTY) && !defined(__sun)
+ /* BSD systems need to set controlling tty explicitly. Solaris/illumos can export
+ TIOCSCTTY when __EXTENSIONS__ are defined, but doesn't need this. */
+ if (ioctl(pty_s,TIOCSCTTY, NULL) < 0) {
+ close(pty_s);
+ len=snprintf(buf, ERRBUFSIZE, _("Couldn't establish controlling terminal: %s"), strerror(errno));
+ write(err_pipe[1], buf, (len>ERRBUFSIZE) ? ERRBUFSIZE : len );
+ exit(1);
+ }
+#endif
+
+ /* Set stdin, stdout, stderr to our tty */
+ dup2(pty_s, 0);
+ dup2(pty_s, 1);
+ dup2(pty_s, 2);
+
+ execvp(argv[0], argv);
+
+ /* Error */
+ close(pty_s);
+ len=snprintf(buf, ERRBUFSIZE, _("Couldn't exec passwd: %s"), strerror(errno));
+ write(err_pipe[1], buf, (len>ERRBUFSIZE) ? ERRBUFSIZE : len );
+ exit(1);
+ } else if (pid > 0) {
+ int rb, pos = 0;
+ char buf[ERRBUFSIZE];
+
+
+ close(err_pipe[1]);
+ /* Wait for child to run exec() and read possible error message */
+ while (pos < ERRBUFSIZE - 1 && ((rb=read(err_pipe[0], &buf[pos], ERRBUFSIZE-1-pos)) > 0)) {
+ pos += rb;
+ }
+ close(err_pipe[0]);
+ if (pos > 0) {
+ /* There were messages in err_pipe */
+ buf[pos+1] = '\0';
+ g_set_error (error,
+ PASSDLG_ERROR,
+ PASSDLG_ERROR_BACKEND,
+ buf);
+
+ stop_passwd(pdialog);
+ return FALSE;
+ }
+
+ /* Open IO Channels */
+ pdialog->backend_stdin = g_io_channel_unix_new (pty_m);
+ /* g_io_channel_shutdown(pdialog->backend_stdin) will close associated file descriptor (pty_m),
+ but this will generate warning on g_io_channel_shutdown(pdialog->backend_stdout).
+ To avoid it, dup() file descriptor */
+ pdialog->backend_stdout = g_io_channel_unix_new (dup(pty_m));
+ pdialog->backend_pid = pid;
+
+ /* 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;
+ }

- /* Add child watcher */
- pdialog->backend_child_watch_id = g_child_watch_add (pdialog->backend_pid, (GChildWatchFunc) child_watch_cb, pdialog);
+ /* Turn off buffering */
+ g_io_channel_set_buffered (pdialog->backend_stdin, FALSE);
+ g_io_channel_set_buffered (pdialog->backend_stdout, FALSE);

- /* Success! */
+ /* 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);

- return TRUE;
+ /* Success! */
+
+ return TRUE;
+ } else {
+ /* Error */
+ g_set_error(error,
+ PASSDLG_ERROR,
+ PASSDLG_ERROR_BACKEND,
+ _("Couldn't fork: %s"),
+ strerror(errno));
+ close(pty_m);
+ return FALSE;
+ }
}

/* Stop passwd backend */
@@ -822,7 +936,7 @@ passdlg_spawn_passwd (PasswordDialog *pdialog)

/* translators: Unable to launch <program>: <error message> */
details = g_strdup_printf (_("Unable to launch %s: %s"),
- "/usr/bin/passwd", error->message);
+ PASSWD, error->message);

passdlg_error_dialog (GTK_WINDOW (parent),
_("Unable to launch backend"),
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
--- mate-control-center-1.20.3/capplets/about-me/mate-about-me-password.c.~2~ 2018-11-08 15:25:28.053932491 +0000
+++ mate-control-center-1.20.3/capplets/about-me/mate-about-me-password.c 2018-11-08 15:31:15.902591210 +0000
@@ -562,6 +564,11 @@
"match",
"1 numeric or special",
"failure",
+ "must contain",
+ "must differ",
+ "are not allowed",
+ "repeating characters",
+ "history",
NULL)) {

/* What response did we get? */
@@ -586,12 +593,17 @@
g_strrstr (str->str, "longer") != NULL) {
msg = g_strdup (_("The password is too short."));
} else if (g_strrstr (str->str, "palindrome") != NULL ||
+ g_strrstr (str->str, "must contain") != NULL ||
+ g_strrstr (str->str, "are not allowed") != NULL ||
+ g_strrstr (str->str, "repeating characters") != NULL ||
+ g_strrstr (str->str, "history") != NULL ||
g_strrstr (str->str, "simpl") != NULL ||
g_strrstr (str->str, "dictionary") != NULL) {
msg = g_strdup (_("The password is too simple."));
} else if (g_strrstr (str->str, "similar") != NULL ||
g_strrstr (str->str, "different") != NULL ||
g_strrstr (str->str, "case") != NULL ||
+ g_strrstr (str->str, "must differ") != NULL ||
g_strrstr (str->str, "wrapped") != NULL) {
msg = g_strdup (_("The old and new passwords are too similar."));
} else if (g_strrstr (str->str, "1 numeric or special") != NULL) {
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
--- mate-control-center-1.20.3/capplets/about-me/mate-about-me-password.c.~4~ 2018-11-13 23:22:52.988738173 +0000
+++ mate-control-center-1.20.3/capplets/about-me/mate-about-me-password.c 2018-11-13 23:30:47.042446380 +0000
@@ -550,8 +550,10 @@
}

if (g_io_channel_read_chars (source, buf, BUFSIZE, &bytes_read, &error) != G_IO_STATUS_NORMAL) {
- g_warning ("IO Channel read error: %s", error->message);
- g_error_free (error);
+ if (error) {
+ g_warning ("IO Channel read error: %s", error->message);
+ g_error_free (error);
+ }

return TRUE;
}