Exemplo n.º 1
0
int
mdm_get_current_vt (void)
{
#if defined (MDM_USE_SYS_VT)
	struct vt_stat s;
#elif defined (MDM_USE_CONSIO_VT)
	int vtno;
#endif
	int fd;

	do {
		errno = 0;
		fd = open (MDMCONSOLEDEVICE,
			   O_WRONLY
#ifdef O_NOCTTY
			   |O_NOCTTY
#endif
			   , 0);
	} while G_UNLIKELY (errno == EINTR);
	if (fd < 0)
		return -1;
#if defined (MDM_USE_SYS_VT)
	ioctl (fd, VT_GETSTATE, &s);

	VE_IGNORE_EINTR (close (fd));

	/* debug */
	/*
	printf ("current_Active %d\n", (int)s.v_active);
	*/

	return s.v_active;
#elif defined (MDM_USE_CONSIO_VT)
	if (ioctl (fd, VT_GETACTIVE, &vtno) == -1) {
		VE_IGNORE_EINTR (close (fd));
		return -1;
	}

VE_IGNORE_EINTR (close (fd));

	/* debug */
	/*
	printf ("current_Active %d\n", vtno);
	*/

	return vtno;
#endif
}
Exemplo n.º 2
0
void
mdm_save_customlist_data (const gchar *file,
			  const gchar *key,
			  const gchar *id)
{
	GKeyFile *cfg;

	mdm_debug ("Saving custom configuration data to file=%s, key=%s",
		file, key);
	cfg = mdm_common_config_load (file, NULL);
	if (cfg == NULL) {
		gint fd = -1;
                mdm_debug ("creating file: %s", file);
		VE_IGNORE_EINTR (fd = g_open (file,
			O_CREAT | O_TRUNC | O_RDWR, 0644));

		if (fd < 0)
			return;

		write (fd, "\n", 2);
		close (fd);
		cfg = mdm_common_config_load (file, NULL);
		if (cfg == NULL) {
			return;
		}
	}

	g_key_file_set_string (cfg, "GreeterInfo", key, ve_sure_string (id));
	mdm_common_config_save (cfg, file, NULL);
	g_key_file_free (cfg);
}
Exemplo n.º 3
0
/* change to an existing vt */
void
mdm_change_vt (int vt)
{
	int fd;
	int rc;
	if (vt < 0)
		return;

	do {
		errno = 0;
		fd = open (MDMCONSOLEDEVICE,
			   O_WRONLY
#ifdef O_NOCTTY
			   |O_NOCTTY
#endif
			   , 0);
	} while G_UNLIKELY (errno == EINTR);
	if (fd < 0)
		return;

	rc = ioctl (fd, VT_ACTIVATE, vt);
	rc = ioctl (fd, VT_WAITACTIVE, vt);

	VE_IGNORE_EINTR (close (fd));
}
Exemplo n.º 4
0
static int 
get_free_vt_sys (int *vtfd)
{
	int fd, fdv;
	int vtno;
	unsigned short vtmask;
	struct vt_stat vtstat;

	*vtfd = -1;

	do {
		errno = 0;
		fd = open (MDMCONSOLEDEVICE,
			   O_WRONLY
#ifdef O_NOCTTY
			   |O_NOCTTY
#endif
			   , 0);
	} while G_UNLIKELY (errno == EINTR);
	if (fd < 0)
		return -1;

	if (ioctl (fd, VT_GETSTATE, &vtstat) < 0) {
		VE_IGNORE_EINTR (close (fd));
		return -1;
	}

	for (vtno = mdm_daemon_config_get_value_int (MDM_KEY_FIRST_VT), vtmask = 1 << vtno;
			vtstat.v_state & vtmask; vtno++, vtmask <<= 1);
	if (!vtmask) {
		VE_IGNORE_EINTR (close (fd));
		return -1;
	}

	fdv = open_vt (vtno);
	if (fdv < 0) {
		VE_IGNORE_EINTR (close (fd));
		return -1;
	}
	*vtfd = fdv;
	return vtno;
}
Exemplo n.º 5
0
void
mdmcomm_comm_bulk_stop (void)
{
	/* Close the connection */
	if (comm_fd > 0) {
		do_command (comm_fd, MDM_SUP_CLOSE, FALSE);
		VE_IGNORE_EINTR (close (comm_fd));
	}
	comm_fd  = 0;
	num_cmds = 0;
	bulk_acs = FALSE;
}
Exemplo n.º 6
0
/* This just gets a cookie of MIT-MAGIC-COOKIE-1 type */
char *
mdmcomm_get_a_cookie (gboolean binary)
{
	FILE *fp;
	char *number;
	char *cookie = NULL;
	Xauth *xau;

	VE_IGNORE_EINTR (fp = fopen (XauFileName (), "r"));
	if (fp == NULL) {
		return NULL;
	}

	number = get_dispnum ();

	cookie = NULL;

	while ((xau = XauReadAuth (fp)) != NULL) {
		/* Just find the FIRST magic cookie, that's what mdm uses */
		if (xau->number_length != strlen (number) ||
		    strncmp (xau->number, number, xau->number_length) != 0 ||
		    /* mdm sends MIT-MAGIC-COOKIE-1 cookies of length 16,
		     * so just do those */
		    xau->data_length != 16 ||
		    xau->name_length != strlen ("MIT-MAGIC-COOKIE-1") ||
		    strncmp (xau->name, "MIT-MAGIC-COOKIE-1",
			     xau->name_length) != 0) {
			XauDisposeAuth (xau);
			continue;
		}

		if (binary) {
			cookie = g_new0 (char, 16);
			memcpy (cookie, xau->data, 16);
		} else {
			int i;
			GString *str;

			str = g_string_new (NULL);

			for (i = 0; i < xau->data_length; i++) {
				g_string_append_printf
					(str, "%02x",
					 (guint)(guchar)xau->data[i]);
			}
			cookie = g_string_free (str, FALSE);
		}

		XauDisposeAuth (xau);

		break;
	}
Exemplo n.º 7
0
static char *
mdmcomm_call_mdm_real (const char *command,
		       const char *auth_cookie,
		       const char *min_version,
		       int tries,
		       int try_start)
{
	char *ret;

	/*
         * If already sent the max number of commands, close the connection
         * and reopen.  Subtract 1 to allow the "CLOSE" to get through.
         */
	if (num_cmds == (MDM_SUP_MAX_MESSAGES - 1)) {
		mdm_common_debug ("  Closing and reopening connection.");
		do_command (comm_fd, MDM_SUP_CLOSE, FALSE);
		VE_IGNORE_EINTR (close (comm_fd));
		comm_fd  = 0;
		num_cmds = 0;
	}

	if (tries <= 0) {
		if ( !quiet)
			mdm_common_debug ("  Command failed %d times, aborting.", try_start);
		return NULL;
	}

	if (!quiet && tries != try_start) {
		mdm_common_debug ("  Trying failed command again.  Try %d of %d.",
				  (try_start - tries + 1), try_start);
	}

	if (comm_fd <= 0) {
		struct sockaddr_un addr;
		strcpy (addr.sun_path, MDM_SUP_SOCKET);
		addr.sun_family = AF_UNIX;
		comm_fd = socket (AF_UNIX, SOCK_STREAM, 0);
		if (comm_fd < 0) {
			if ( !quiet)
				mdm_common_debug ("  Failed to open socket");

			return mdmcomm_call_mdm_real (command, auth_cookie, min_version, tries - 1, try_start);
		}

		if (connect (comm_fd, (struct sockaddr *)&addr, sizeof (addr)) < 0) {


			/*
			 * If there is a failure on connect, there are probably
                         * other clients fighting for the connection, so sleep
                         * for 1 second before retry to avoid failing over and
                         * over in a tight loop.
                         *
                         * Only do this if allow_sleep is true.  allow_sleep
                         * will get set to FALSE if the first call to this 
                         * function fails all retries.
			 */
			if (allow_sleep == TRUE) {

				did_sleep_on_failure = TRUE;

				/*
				 * Only actualy sleep if we are going to try
				 * again.
				 */
				if (tries > 1) {
					if ( !quiet)
						mdm_common_debug ("  Failed to connect to socket, sleep 1 second and retry");
					sleep (1);
				}
			} else {
				if ( !quiet)
					mdm_common_debug ("  Failed to connect to socket, not sleeping");
			}
			VE_IGNORE_EINTR (close (comm_fd));
			comm_fd = 0;
			return mdmcomm_call_mdm_real (command, auth_cookie,
						      min_version, tries - 1, try_start);
		}

		/*
                 * If we get this far, then even if we did sleep in the past,
		 * we did get a connection, so no need to prevent future
		 * sleeps if required.
                 */
		allow_sleep          = TRUE;
                did_sleep_on_failure = FALSE;

		/* Version check first - only check first time */
		ret = do_command (comm_fd, MDM_SUP_VERSION, TRUE);
		if (ret == NULL) {
			if ( !quiet)
				mdm_common_debug ("  Version check failed");
			VE_IGNORE_EINTR (close (comm_fd));
			comm_fd = 0;
			return mdmcomm_call_mdm_real (command, auth_cookie,
						      min_version, tries - 1, try_start);
		}
		if (strncmp (ret, "MDM ", strlen ("MDM ")) != 0) {
			if ( !quiet)
				mdm_common_debug ("  Version check failed, bad name");

			g_free (ret);
			do_command (comm_fd, MDM_SUP_CLOSE, FALSE);
			VE_IGNORE_EINTR (close (comm_fd));
			comm_fd = 0;
			return NULL;
		}
		if ( ! version_ok_p (&ret[4], min_version)) {
			if ( !quiet)
				mdm_common_debug ("  Version check failed, bad version");
			g_free (ret);
			do_command (comm_fd, MDM_SUP_CLOSE, FALSE);
			VE_IGNORE_EINTR (close (comm_fd));
			comm_fd = 0;
			return NULL;
		}
		g_free (ret);
	}

	/* require authentication */
	if (auth_cookie != NULL)  {
		char *auth_cmd = g_strdup_printf
			(MDM_SUP_AUTH_LOCAL " %s", auth_cookie);
		ret = do_command (comm_fd, auth_cmd, TRUE);
		g_free (auth_cmd);
		if (ret == NULL) {
			VE_IGNORE_EINTR (close (comm_fd));
			comm_fd = 0;
			return mdmcomm_call_mdm_real (command, auth_cookie,
						      min_version, tries - 1, try_start);
		}
		/* not auth'ed */
		if (strcmp (ve_sure_string (ret), "OK") != 0) {
			if ( !quiet)
				mdm_common_debug ("  Error, auth check failed");
			do_command (comm_fd, MDM_SUP_CLOSE, FALSE);
			VE_IGNORE_EINTR (close (comm_fd));
			comm_fd = 0;
			/* returns the error */
			return ret;
		}
		g_free (ret);
	}

	ret = do_command (comm_fd, command, TRUE);
	if (ret == NULL) {
		VE_IGNORE_EINTR (close (comm_fd));
		comm_fd = 0;
		return mdmcomm_call_mdm_real (command, auth_cookie,
					      min_version, tries - 1, try_start);
	}

	/*
	 * We want to leave the connection open if bulk_acs is set to
	 * true, so clients can read as much config data in one 
	 * sockets connection when it is set.  This requires that
	 * MDM client programs ensure that they call the bulk_start
	 * and bulk_stop functions around blocks of code that
	 * need to read data in bulk.  If a client reads config data
	 * outside of the bulk_start/stop functions, then this
	 * will just negatively affect performance since an additional
	 * socket will be opened to read that config data.
	 */
	if (bulk_acs == FALSE) {
		do_command (comm_fd, MDM_SUP_CLOSE, FALSE);
		VE_IGNORE_EINTR (close (comm_fd));
		comm_fd = 0;
	}

	return ret;
}
Exemplo n.º 8
0
GList *
mdm_lang_read_locale_file (const char *locale_file)
{
	FILE *langlist;
	char curline[256];
	GList *langs = NULL;
	GHashTable *dupcheck;
	Language *language;
	gboolean clean;
	char *getsret;
	char *p;

	if (locale_file == NULL)
		return NULL;

	VE_IGNORE_EINTR (langlist = fopen (locale_file, "r"));

	if (langlist == NULL)
		return NULL;

	mdm_lang_init ();

	dupcheck = g_hash_table_new (g_str_hash, g_str_equal);

	for (;;) {
		char *name;
		char *lang;
		char **lang_list;
		int i;

		VE_IGNORE_EINTR (getsret = fgets (curline, sizeof (curline), langlist));
		if (getsret == NULL)
			break;

		if (curline[0] <= ' ' ||
		    curline[0] == '#')
			continue;

		name = strtok (curline, " \t\r\n");
		if (name == NULL)
			continue;

		lang = strtok (NULL, " \t\r\n");
		if (lang == NULL)
			continue;

		lang_list = g_strsplit (lang, ",", -1);
		if (lang_list == NULL)
			continue;

		lang = NULL;
		for (i = 0; lang_list[i] != NULL; i++) {
			if (ve_locale_exists (lang_list[i])) {
				lang = lang_list[i];
				break;
			}
		}
		if (lang == NULL ||
		    g_hash_table_lookup (dupcheck, lang) != NULL) {
			g_strfreev (lang_list);
			continue;
		}
		language = find_lang (lang, &clean);

		if (language != NULL) {
			language->found++;
		} else {
			language = g_new0 (Language, 1);
			language->found = 1;
			/* add a space before an open bracket to match
			   the style used in the internal list.
			   e.g. change "English(India)" to "English (India)" */
			p = strchr (name, '(');
			if (p != NULL && p > name && *(p-1) != ' ') {
			  *p = 0;
			  language->name= g_strconcat (name, " (", p+1, NULL);
			} else
			  language->name = g_strdup (name);
 			/* only store the "lang_country" part of the locale code, so that we notice
 			 * if there is more than one encoding of this language. See bug 132629. */
			p = strchr (lang, '.');
 			if (p == NULL)
 			  p = strchr (lang, '@');
 			if (p != NULL)
 			  language->code = g_strndup (lang, (p - lang));
 			else
 			  language->code = g_strdup (lang);
			language->untranslated = NULL;
			g_hash_table_insert (lang_names,
					     language->code,
					     language);
		}

		langs = g_list_prepend (langs, g_strdup (lang));
		g_hash_table_insert (dupcheck, g_strdup (lang),
				     GINT_TO_POINTER (1));

		g_strfreev (lang_list);
	}

	g_hash_table_foreach (dupcheck, (GHFunc) g_free, NULL);
	g_hash_table_destroy (dupcheck);

	langs = g_list_sort (langs, lang_collate);

	VE_IGNORE_EINTR (fclose (langlist));

	return langs;
}
Exemplo n.º 9
0
static int
get_free_vt_consio (int *vtfd)
{
	int fd, fdv;
	int vtno;
	GList *to_close_vts = NULL, *li;

	*vtfd = -1;

	do {
		errno = 0;
		fd = open (MDMCONSOLEDEVICE,
			   O_WRONLY
#ifdef O_NOCTTY
			   |O_NOCTTY
#endif
			   , 0);
	} while G_UNLIKELY (errno == EINTR);
	if (fd < 0)
		return -1;

	if ((ioctl (fd, VT_OPENQRY, &vtno) < 0) || (vtno == -1)) {
		VE_IGNORE_EINTR (close (fd));
		return -1;
	}

	fdv = open_vt (vtno);
	if (fdv < 0) {
		VE_IGNORE_EINTR (close (fd));
		return -1;
	}

	while (vtno < mdm_daemon_config_get_value_int (MDM_KEY_FIRST_VT)) {
		int oldvt = vtno;
		to_close_vts = g_list_prepend (to_close_vts,
					       GINT_TO_POINTER (fdv));

		if (ioctl (fd, VT_OPENQRY, &vtno) == -1) {
			vtno = -1;
			goto cleanup;
		}

		if (oldvt == vtno) {
			vtno = -1;
			goto cleanup;
		}

		fdv = open_vt (vtno);
		if (fdv < 0) {
			vtno = -1;
			goto cleanup;
		}
	}

	*vtfd = fdv;

cleanup:
	for (li = to_close_vts; li != NULL; li = li->next) {
		VE_IGNORE_EINTR (close (GPOINTER_TO_INT (li->data)));
	}
	return vtno;
}
Exemplo n.º 10
0
void
mdm_display_dispose (MdmDisplay *d)
{

    if (d == NULL)
	return;

    /* paranoia */
    if (unixconn != NULL)
            mdm_kill_subconnections_with_display (unixconn, d);

    if (d->socket_conn != NULL) {
	    MdmConnection *conn = d->socket_conn;
	    d->socket_conn = NULL;
	    mdm_connection_set_close_notify (conn, NULL, NULL);
    }

    if (d->slave_notify_fd >= 0) {
	    VE_IGNORE_EINTR (close (d->slave_notify_fd));
	    d->slave_notify_fd = -1;
    }

    if (d->master_notify_fd >= 0) {
	    VE_IGNORE_EINTR (close (d->master_notify_fd));
	    d->master_notify_fd = -1;
    }

    mdm_daemon_config_display_list_remove (d);

    d->dispstat = DISPLAY_DEAD;
    d->type = -1;

    count_session_limits ();

    if (d->name) {
	mdm_debug ("mdm_display_dispose: Disposing %s", d->name);
	g_free (d->name);
	d->name = NULL;
    }
    
    g_free (d->chosen_hostname);
    d->chosen_hostname = NULL;

    g_free (d->hostname);
    d->hostname = NULL;

    g_free (d->windowpath);
    d->windowpath = NULL;

    g_free (d->addrs);
    d->addrs = NULL;
    d->addr_count = 0;

    g_free (d->authfile);
    d->authfile = NULL;

    g_free (d->authfile_mdm);
    d->authfile_mdm = NULL; 

    if (d->auths) {
	    mdm_auth_free_auth_list (d->auths);
	    d->auths = NULL;
    }

    if (d->local_auths) {
	    mdm_auth_free_auth_list (d->local_auths);
	    d->local_auths = NULL;
    }

    g_free (d->userauth);
    d->userauth = NULL;

    g_free (d->windowpath);
    d->windowpath = NULL;

    g_free (d->command);
    d->command = NULL;

    g_free (d->device_name);
    d->device_name = NULL;

    g_free (d->cookie);
    d->cookie = NULL;

    g_free (d->bcookie);
    d->bcookie = NULL;
    
    d->indirect_id = 0;   
   
    g_free (d->login);
    d->login = NULL;

    g_free (d->preset_user);
    d->preset_user = NULL;

    g_free (d->xsession_errors_filename);
    d->xsession_errors_filename = NULL;

    if (d->session_output_fd >= 0) {
	    VE_IGNORE_EINTR (close (d->session_output_fd));
	    d->session_output_fd = -1;
    }

    if (d->xsession_errors_fd >= 0) {
	    VE_IGNORE_EINTR (close (d->xsession_errors_fd));
	    d->xsession_errors_fd = -1;
    }

    g_free (d->chooser_last_line);
    d->chooser_last_line = NULL;

    if (d->chooser_output_fd >= 0) {
	    VE_IGNORE_EINTR (close (d->chooser_output_fd));
	    d->chooser_output_fd = -1;
    }

    g_free (d->theme_name);
    d->theme_name = NULL;

    g_free (d->xserver_session_args);
    d->xserver_session_args = NULL;

    g_free (d);
}
Exemplo n.º 11
0
gboolean 
mdm_display_manage (MdmDisplay *d)
{
    pid_t pid;
    int fds[2];

    if (!d) 
	return FALSE;

    mdm_debug ("mdm_display_manage: Managing %s", d->name);

    if (pipe (fds) < 0) {
	    mdm_error ("mdm_display_manage: Cannot create pipe");
    }

    if ( ! mdm_display_check_loop (d))
	    return FALSE;

    if (d->slavepid != 0)
	    mdm_debug ("mdm_display_manage: Old slave pid is %d", (int)d->slavepid);

    /* If we have an old slave process hanging around, kill it */
    /* This shouldn't be a normal code path however, so it doesn't matter
     * that we are hanging */
    whack_old_slave (d, FALSE /* kill_connection */);

    /* Ensure that /tmp/.ICE-unix and /tmp/.X11-unix exist and have the
     * correct permissions */
    mdm_ensure_sanity ();

    d->managetime = time (NULL);

    mdm_debug ("Forking slave process");

    /* Fork slave process */
    pid = d->slavepid = fork ();

    switch (pid) {

    case 0:

	setpgid (0, 0);

	/* Make the slave it's own leader.  This 1) makes killing -pid of
	 * the daemon work more sanely because the daemon can whack the
	 * slave much better itself */
	setsid ();

	/* In the child setup empty mask and set all signals to
	 * default values, we'll make them more fun later */
	mdm_unset_signals ();

	d->slavepid = getpid ();
	
	mdm_connection_close (pipeconn);
	pipeconn = NULL;
	mdm_connection_close (unixconn);
	unixconn = NULL;

	mdm_log_shutdown ();

	/* Debian changes */
#if 0
	/* upstream version */
-	/* Close everything */
-	mdm_close_all_descriptors (0 /* from */, fds[0] /* except */, slave_fifo_pipe_fd /* except2 */);
#endif
	/* Close stdin/stdout/stderr.  Leave others, as pam modules may have them open */
	VE_IGNORE_EINTR (close (0));
	VE_IGNORE_EINTR (close (1));
	VE_IGNORE_EINTR (close (2));
	/* End of Debian changes */

	/* No error checking here - if it's messed the best response
         * is to ignore & try to continue */
	mdm_open_dev_null (O_RDONLY); /* open stdin - fd 0 */
	mdm_open_dev_null (O_RDWR); /* open stdout - fd 1 */
	mdm_open_dev_null (O_RDWR); /* open stderr - fd 2 */

	mdm_log_init ();

	d->slave_notify_fd = fds[0];

	fcntl (d->slave_notify_fd, F_SETFL, fcntl (d->slave_notify_fd, F_GETFL) | O_NONBLOCK);

	mdm_slave_start (d);
	/* should never retern */

	/* yaikes, how did we ever get here? */
	mdm_server_stop (d);
	_exit (DISPLAY_REMANAGE);

	break;

    case -1:
	d->slavepid = 0;
	mdm_error ("mdm_display_manage: Failed forking MDM slave process for %s", d->name);

	return FALSE;

    default:
	mdm_debug ("mdm_display_manage: Forked slave: %d", (int)pid);
	d->master_notify_fd = fds[1];
	VE_IGNORE_EINTR (close (fds[0]));
	break;
    }

    /* invalidate chosen hostname */
    g_free (d->chosen_hostname);
    d->chosen_hostname = NULL;

    /* use_chooser can only be temporary, if you want it permanent you set it
       up in the server definition with "chooser=true" and it will get set up
       during server command line resolution */
    d->use_chooser = FALSE;

    if (SERVER_IS_LOCAL (d)) {
	    d->dispstat = DISPLAY_ALIVE;
    }

    /* reset sleep to 1, to sleep just in case (avoids X server races) */
    d->sleep_before_run = 1;

    return TRUE;
}
Exemplo n.º 12
0
static void
whack_old_slave (MdmDisplay *d, gboolean kill_connection)
{
    time_t t = time (NULL);
    gboolean waitsleep = TRUE;

    if (kill_connection) {
	    /* This should never happen, but just in case */
	    if (d->socket_conn != NULL) {
		    MdmConnection *conn = d->socket_conn;
		    d->socket_conn = NULL;
		    mdm_connection_set_close_notify (conn, NULL, NULL);
	    }
    }

    if (d->master_notify_fd >= 0) {
	    VE_IGNORE_EINTR (close (d->master_notify_fd));
	    d->master_notify_fd = -1;
    }

    /* if we have DISPLAY_DEAD set, then this has already been killed */
    if (d->dispstat == DISPLAY_DEAD)
	    waitsleep = FALSE;

    /* Kill slave */
    if (d->slavepid > 1 &&
	(d->dispstat == DISPLAY_DEAD || kill (d->slavepid, SIGTERM) == 0)) {
	    int exitstatus;
	    int ret;
wait_again:
		
	    if (waitsleep) {
		    /* wait for some signal, yes this is a race */
		    mdm_debug ("mdm whack_old_slave: sleeping for 10 seconds");
		    sleep (10);
		  }
	    waitsleep = TRUE;
	    errno = 0;
	    ret = waitpid (d->slavepid, &exitstatus, WNOHANG);
	    if (ret <= 0) {
		    /* rekill the slave to tell it to
		       hurry up and die if we're getting
		       killed ourselves */
		    if ((mdm_daemon_config_signal_terminthup_was_notified ()) ||
			(t + 10 <= time (NULL))) {
			    mdm_debug ("whack_old_slave: GOT ANOTHER SIGTERM (or it was 10 secs already), killing slave again with SIGKILL");
			    t = time (NULL);
			    kill (d->slavepid, SIGKILL);
			    goto wait_again;
		    } else if (ret < 0 && errno == EINTR) {
			    goto wait_again;
		    }
	    }

	    if (WIFSIGNALED (exitstatus)) {
		    mdm_debug ("whack_old_slave: Slave crashed (signal %d), killing its children",
			       (int)WTERMSIG (exitstatus));

		    if (d->sesspid > 1)
			    kill (-(d->sesspid), SIGTERM);
		    d->sesspid = 0;
		    if (d->greetpid > 1)
			    kill (-(d->greetpid), SIGTERM);
		    d->greetpid = 0;
		    if (d->chooserpid > 1)
			    kill (-(d->chooserpid), SIGTERM);
		    d->chooserpid = 0;
		    if (d->servpid > 1)
			    kill (d->servpid, SIGTERM);
		    d->servpid = 0;
	    }
    }
    d->slavepid = 0;
}