1 diff --git a/capplets/about-me/mate-about-me-password.c b/capplets/about-me/mate-about-me-password.c
2 index abac117..5a82566 100644
3 --- a/capplets/about-me/mate-about-me-password.c
4 +++ b/capplets/about-me/mate-about-me-password.c
9 +/* This is needed to get ptmx-related functions in GLIBC */
10 +#ifndef _XOPEN_SOURCE
11 +#define _XOPEN_SOURCE 600
14 +/* This is needed to get pipe2() in GLIBC */
17 /* Are all of these needed? */
18 #include <gdk/gdkkeysyms.h>
24 +#include <sys/stat.h>
29 +#define PASSWD "/usr/bin/passwd"
30 +#define PTMX "/dev/ptmx"
33 +#define PTY_MAX_NAME 20
36 #include <sys/types.h>
37 @@ -85,6 +103,9 @@ typedef struct {
38 /* Buffer size for backend output */
41 +/* Bufffer size for backend error messages */
42 +#define ERRBUFSIZE 1024
47 @@ -170,85 +191,178 @@ static gboolean
48 spawn_passwd (PasswordDialog *pdialog, GError **error)
52 - gint my_stdin, my_stdout, my_stderr;
53 + int pid, pty_m, err_pipe[2];
54 + char slave_name[PTY_MAX_NAME];
57 - argv[0] = "/usr/bin/passwd"; /* Is it safe to rely on a hard-coded path? */
58 + argv[0] = PASSWD; /* Is it safe to rely on a hard-coded path? */
61 - envp[0] = NULL; /* If we pass an empty array as the environment,
62 - * will the childs environment be empty, and the
63 - * locales set to the C default? From the manual:
64 - * "If envp is NULL, the child inherits its
65 - * parent'senvironment."
66 - * If I'm wrong here, we somehow have to set
70 - if (!g_spawn_async_with_pipes (NULL, /* Working directory */
71 - argv, /* Argument vector */
72 - envp, /* Environment */
73 - G_SPAWN_DO_NOT_REAP_CHILD, /* Flags */
74 - NULL, /* Child setup */
75 - NULL, /* Data to child setup */
76 - &pdialog->backend_pid, /* PID */
77 - &my_stdin, /* Stdin */
78 - &my_stdout, /* Stdout */
79 - &my_stderr, /* Stderr */
80 - error)) { /* GError */
82 - /* An error occurred */
83 - free_passwd_resources (pdialog);
85 + pty_m = open(PTMX, O_RDWR|O_NOCTTY);
87 + name = ptsname(pty_m);
88 + if (name && (strlen(name) < PTY_MAX_NAME)) {
89 + strncpy(slave_name, name, PTY_MAX_NAME);
93 + PASSDLG_ERROR_BACKEND,
94 + _("Couldn't get slave_name of pty"));
101 + PASSDLG_ERROR_BACKEND,
102 + _("Couldn't open pseudo-tty"));
107 - if (dup2 (my_stderr, my_stdout) == -1) {
109 + if (grantpt(pty_m) < 0) {
112 - PASSDLG_ERROR_BACKEND,
117 - stop_passwd (pdialog);
120 + PASSDLG_ERROR_BACKEND,
121 + _("Couldn't set permission on slave device: %s"),
127 - /* Open IO Channels */
128 - pdialog->backend_stdin = g_io_channel_unix_new (my_stdin);
129 - pdialog->backend_stdout = g_io_channel_unix_new (my_stdout);
131 - /* Set raw encoding */
132 - /* Set nonblocking mode */
133 - if (g_io_channel_set_encoding (pdialog->backend_stdin, NULL, error) != G_IO_STATUS_NORMAL ||
134 - g_io_channel_set_encoding (pdialog->backend_stdout, NULL, error) != G_IO_STATUS_NORMAL ||
135 - g_io_channel_set_flags (pdialog->backend_stdin, G_IO_FLAG_NONBLOCK, error) != G_IO_STATUS_NORMAL ||
136 - g_io_channel_set_flags (pdialog->backend_stdout, G_IO_FLAG_NONBLOCK, error) != G_IO_STATUS_NORMAL ) {
137 + if (unlockpt(pty_m) < 0) {
138 + g_set_error (error,
140 + PASSDLG_ERROR_BACKEND,
141 + _("Couldn't unlock slave device: %s"),
148 - stop_passwd (pdialog);
149 + if (pipe2(err_pipe, O_CLOEXEC) < 0) {
150 + g_set_error (error,
152 + PASSDLG_ERROR_BACKEND,
153 + _("Couldn't create error reporting pipe: %s"),
163 + char buf[ERRBUFSIZE];
164 + close(err_pipe[0]);
167 + if (setsid() < 0) {
168 + len = snprintf(buf, ERRBUFSIZE, _("Couldn't create new process group: %s"), strerror(errno));
169 + write(err_pipe[1], buf, (len>ERRBUFSIZE) ? ERRBUFSIZE : len );
173 - /* Turn off buffering */
174 - g_io_channel_set_buffered (pdialog->backend_stdin, FALSE);
175 - g_io_channel_set_buffered (pdialog->backend_stdout, FALSE);
176 + /* Now we are a session leader, on System V first open tty will become controlling tty */
177 + pty_s = open(slave_name, O_RDWR);
179 - /* Add IO Channel watcher */
180 - pdialog->backend_stdout_watch_id = g_io_add_watch (pdialog->backend_stdout,
181 - G_IO_IN | G_IO_PRI,
182 - (GIOFunc) io_watch_stdout, pdialog);
184 + len = snprintf(buf, ERRBUFSIZE, _("Couldn't open slave terminal device: %s"), strerror(errno));
185 + write(err_pipe[1], buf, (len>ERRBUFSIZE) ? ERRBUFSIZE : len );
189 +#if defined(TIOCSCTTY) && !defined(__sun)
190 + /* BSD systems need to set controlling tty explicitly. Solaris/illumos can export
191 + TIOCSCTTY when __EXTENSIONS__ are defined, but doesn't need this. */
192 + if (ioctl(pty_s,TIOCSCTTY, NULL) < 0) {
194 + len=snprintf(buf, ERRBUFSIZE, _("Couldn't establish controlling terminal: %s"), strerror(errno));
195 + write(err_pipe[1], buf, (len>ERRBUFSIZE) ? ERRBUFSIZE : len );
200 + /* Set stdin, stdout, stderr to our tty */
205 + execvp(argv[0], argv);
209 + len=snprintf(buf, ERRBUFSIZE, _("Couldn't exec passwd: %s"), strerror(errno));
210 + write(err_pipe[1], buf, (len>ERRBUFSIZE) ? ERRBUFSIZE : len );
212 + } else if (pid > 0) {
214 + char buf[ERRBUFSIZE];
217 + close(err_pipe[1]);
218 + /* Wait for child to run exec() and read possible error message */
219 + while (pos < ERRBUFSIZE - 1 && ((rb=read(err_pipe[0], &buf[pos], ERRBUFSIZE-1-pos)) > 0)) {
222 + close(err_pipe[0]);
224 + /* There were messages in err_pipe */
226 + g_set_error (error,
228 + PASSDLG_ERROR_BACKEND,
231 + stop_passwd(pdialog);
235 + /* Open IO Channels */
236 + pdialog->backend_stdin = g_io_channel_unix_new (pty_m);
237 + /* g_io_channel_shutdown(pdialog->backend_stdin) will close associated file descriptor (pty_m),
238 + but this will generate warning on g_io_channel_shutdown(pdialog->backend_stdout).
239 + To avoid it, dup() file descriptor */
240 + pdialog->backend_stdout = g_io_channel_unix_new (dup(pty_m));
241 + pdialog->backend_pid = pid;
243 + /* Set raw encoding */
244 + /* Set nonblocking mode */
245 + if (g_io_channel_set_encoding (pdialog->backend_stdin, NULL, error) != G_IO_STATUS_NORMAL ||
246 + g_io_channel_set_encoding (pdialog->backend_stdout, NULL, error) != G_IO_STATUS_NORMAL ||
247 + g_io_channel_set_flags (pdialog->backend_stdin, G_IO_FLAG_NONBLOCK, error) != G_IO_STATUS_NORMAL ||
248 + g_io_channel_set_flags (pdialog->backend_stdout, G_IO_FLAG_NONBLOCK, error) != G_IO_STATUS_NORMAL ) {
251 + stop_passwd (pdialog);
255 - /* Add child watcher */
256 - pdialog->backend_child_watch_id = g_child_watch_add (pdialog->backend_pid, (GChildWatchFunc) child_watch_cb, pdialog);
257 + /* Turn off buffering */
258 + g_io_channel_set_buffered (pdialog->backend_stdin, FALSE);
259 + g_io_channel_set_buffered (pdialog->backend_stdout, FALSE);
262 + /* Add IO Channel watcher */
263 + pdialog->backend_stdout_watch_id = g_io_add_watch (pdialog->backend_stdout,
264 + G_IO_IN | G_IO_PRI,
265 + (GIOFunc) io_watch_stdout, pdialog);
267 + /* Add child watcher */
268 + pdialog->backend_child_watch_id = g_child_watch_add (pdialog->backend_pid, (GChildWatchFunc) child_watch_cb, pdialog);
278 + PASSDLG_ERROR_BACKEND,
279 + _("Couldn't fork: %s"),
286 /* Stop passwd backend */
287 @@ -822,7 +936,7 @@ passdlg_spawn_passwd (PasswordDialog *pdialog)
289 /* translators: Unable to launch <program>: <error message> */
290 details = g_strdup_printf (_("Unable to launch %s: %s"),
291 - "/usr/bin/passwd", error->message);
292 + PASSWD, error->message);
294 passdlg_error_dialog (GTK_WINDOW (parent),
295 _("Unable to launch backend"),