--- loki_setup/CHANGES 2004-11-20 07:43:42.000000000 -0600 +++ loki_setup.zinx/CHANGES 2005-03-16 16:56:46.400205504 -0600 @@ -1,4 +1,6 @@ Current: +Christopher Lais (Id Software) - Wed Mar 16 08:09:59 CST 2005 + * Fix handling of invalid password in xsu Ryan C. Gordon (icculus.org) - Sat Nov 20 08:42:16 EST 2004 * Minor carbon_ui tweaks and corrections to update function. Ludwig Nussel - Wed Nov 10 14:21:21 PST 2004 --- loki_setup/xsu.c 2003-07-02 14:40:39.000000000 -0500 +++ loki_setup.zinx/xsu.c 2005-03-16 16:36:17.752988272 -0600 @@ -37,6 +37,7 @@ #include "xsu.h" static int term = -1; +static int term_status = 0; static gint exec_su_failed (gpointer user_data) @@ -79,22 +80,25 @@ if ( sig == SIGCHLD && term > 0 ) { int status; pid_t pid = wait(&status); + + close(term); term = -1; + term_status = status; + if ( WIFEXITED(status) ) { #ifdef DEBUG fprintf(stderr,"Child %d returned\n", pid); #endif - gtk_exit(WEXITSTATUS(status)); + /* This is handled at the end of xsu_process */ + return; } else if ( WIFSIGNALED(status) ) { #ifdef DEBUG fprintf(stderr,"Xsu: subprocess %d has died from signal %d\n", pid, WTERMSIG(status)); #endif gtk_exit(EXIT_ERROR); + } else { + fprintf(stderr, "Xsu: got SIGCHLD from %d for unknown reason (%08x)\n", pid, status); + gtk_exit(EXIT_ERROR); } - close(term); term = -1; - - while (gtk_events_pending ()) - gtk_main_iteration (); - gtk_main_quit (); } } @@ -135,22 +139,27 @@ gchar *buffer; char *argv[6], c; fd_set fds; - struct timeval delay = { 0, 10*1000 }; /* 10 ms wait */ + struct timeval delay; #ifdef DEBUG printf("void xsu_perform()\n"); #endif + gtk_widget_hide (gtk_xsu_window); + + if (password == NULL) + return; + /* 0.2.1 * Minor security fix. Password would remain in memory if we don't clean the password textbox. */ - gtk_entry_set_text(GTK_ENTRY(gtk_password_textbox),""); - gtk_widget_hide (gtk_xsu_window); - - if (password == NULL) - return; + password_return = g_strdup_printf ("%s\n", password); + /* Technically, we aren't supposed to modify this, but it should + usually be OK because we're explicitly clearing it afterwards. */ + memset (password, 0, strlen (password)); + gtk_entry_set_text(GTK_ENTRY(gtk_password_textbox),""); /* xsu 0.2.1 * Option to set the DISPLAY environment @@ -177,6 +186,9 @@ argv[2] = "-c"; argv[3] = buffer; argv[4] = NULL; +#ifdef DEBUG + fprintf(stderr, "%s %s -c %s\n", su_command, username, buffer); +#endif term = exec_program(su_command, argv); /* We are not a gnome-application anymore but under control of su */ @@ -231,33 +243,65 @@ fprintf(stderr, "Got it!\n"); #endif - /* Discard any remaining characters on stdin */ - for(;;) { + /* Slurp up any extra characters immediately after the password prompt, + because su might clear the buffer after we send the password if we + don't. */ + for (;;) { FD_ZERO(&fds); FD_SET(term, &fds); - if ( select(term+1, &fds, NULL, NULL, &delay) ) { - if ( read(term, &c, 1) <= 0 ) - break; + + delay.tv_sec = 0; + delay.tv_usec = 10*1000; /* 10 ms wait */ + + if (select(term+1, &fds, NULL, NULL, &delay) > 0) { + if (read(term, &c, 1) < 0) + break; } else break; } - password_return = g_strdup_printf ("%s\n", password); #ifdef DEBUG fprintf(stderr,"Sending password\n"); #endif /* 0.2.2 * Minor security fix, clear the password from memory */ - memset (password, 0, strlen (password)); if ( write(term, password_return, strlen(password_return)) < 0 ) { perror("write"); } + memset (password_return, 0, strlen (password_return)); g_free (password_return); password_return = NULL; - g_free (password); password = NULL; - //gtk_main(); + /* Eat up any output, and wait for a SIGCHLD saying su exited */ + while (term >= 0) { + FD_ZERO(&fds); + FD_SET(term, &fds); + + delay.tv_sec = 0; + delay.tv_usec = 10*1000; /* 10 ms wait */ + + if ( select(term+1, &fds, NULL, NULL, &delay) > 0 ) { + read(term, &c, 1); +#ifdef DEBUG + fprintf(stderr, "read from pty: %02x\n", c); +#endif + } + + while (gtk_events_pending ()) + gtk_main_iteration (); + } + + if (WIFEXITED(term_status) && WEXITSTATUS(term_status)) { + /* su failed, so ask for the password again */ +#ifdef DEBUG + fprintf(stderr, "returning control to gtk\n"); +#endif + gtk_widget_show (gtk_xsu_window); + } else { + /* Exit normally */ + gtk_main_quit(); + } }