예제 #1
0
int
XAddHosts (
    register Display *dpy,
    XHostAddress *hosts,
    int n)
{
    register int i;
    for (i = 0; i < n; i++) {
	(void) XAddHost(dpy, &hosts[i]);
      }
    return 1;
}
예제 #2
0
파일: dm.c 프로젝트: mit-athena/dm
int main(int argc, char **argv)
{
  char *consoletty, *p;
  char **dmargv, **xargv, **consoleargv = NULL, **loginargv;
  char xpidf[256], line[16], buf[256];
  fd_set readfds;
  int pgrp, file, tries, count, redir = TRUE;
  char dpyacl[40];
  Display *dpy;
  XHostAddress *hosts, localhost;
  int nhosts, dpynum = 0;
  struct stat hostsinfo;
  Bool state;
  time_t now, last_console_failure = 0;
  struct sigaction sigact;
  sigset_t mask;
#if defined(SRIOCSREDIR) || defined(TIOCCONS)
  int on;
#endif
  int fd;
  int conspipe[2];
  XIOErrorHandler xioerror_handler;

  sigemptyset(&sigact.sa_mask);
  sigact.sa_flags = 0;
  (void) sigemptyset(&sig_zero);

  /* Create a localhost entity for access control purposes. */
  localhost.family = FamilyLocalHost;
  localhost.length = 0;
  localhost.address = "";

/*
 * Note about setting environment variables in dm:
 *
 *   All environment variables passed to dm and set in dm are
 *   subsequently passed to any children of dm. This is usually
 *   true of processes that exec in children, so that's not a
 *   big surprise.
 *
 *   However, xlogin is one of the children dm forks, and it goes
 *   to lengths to ensure that the environments of users logging in
 *   are ISOLATED from xlogin's own environment. Therefore, do not
 *   expect that setting an environment variable here will reach the
 *   user unless you have gone to lengths to make sure that xlogin
 *   passes it on. Put another way, if you set a new environment
 *   variable here, consider whether or not it should be seen by the
 *   user. If it should, go modify verify.c as well. Consider also
 *   whether the variable should be seen _only_ by the user. If so,
 *   make the change only in xlogin, and not here.
 *
 *   As an added complication, xlogin _does_ pass environment variables
 *   on to the pre-login options. Therefore, if you set an environment
 *   variable that should _not_ be seen, you must filter it in xlogin.c.
 *
 *   Confused? Too bad. I'm in a nasty, if verbose, mood this year.
 *
 * General summary:
 *
 *   If you add an environment variable here there are three likely
 *   possibilities:
 *
 *     1. It's for the user only, not needed by any of dm's children.
 *        --> Don't set it here. Set it in verify.c for users and in
 *        --> xlogin.c for the pre-login options, if appropriate.
 *
 *     2. It's for dm and its children only, and _should not_ be seen
 *        by the user or pre-login options.
 *        --> You must filter the option from the pre-login options
 *        --> in xlogin.c. No changes to verify.c are required.
 *
 *     3. It's for dm and the user and the pre-login options.
 *        --> You must pass the option explicitly to the user in
 *        --> verify.c. No changes to xlogin.c are required.
 *
 *                                                   --- cfields
 */
#ifdef notdef
  putenv("LD_LIBRARY_PATH=/usr/openwin/lib");
  putenv("OPENWINHOME=/usr/openwin");
#endif

  if (argc < 2)
    {
      fprintf(stderr, "dm: first argument must be configuration file\n");
      sleep(60);
      exit(1);
    }

  conf = argv[1];

  if (argc != 4 && (argc != 5 || strcmp(argv[3], "-noconsole")))
    {
      fprintf(stderr,
	      "usage: %s configfile logintty [-noconsole] consoletty\n",
	      argv[0]);
      console_login(conf, NULL);
    }
  if (argc == 5)
    redir = FALSE;

  /* parse argument lists */
  /* ignore argv[2] */
  consoletty = argv[argc - 1];
#ifdef SOLARIS
  /* On Solaris, use the console tty name for the utmp line field,
   * as the Solaris finger requires an actual device name there.
   * Elsewhere, we will use the display name (see below).
   */
  utmp_line = consoletty;
#endif

  openlog("dm", 0, LOG_USER);

  /* We use options from the config file rather than taking
   * them from the command line because the current command
   * line form is gross (why???), and I don't see a good way
   * to extend it without making things grosser or breaking
   * backwards compatibility. So, we take a line from the
   * config file and use real parsing.
   */
  p = getconf(conf, "dm");
  if (p != NULL)
    {
      dmargv = parseargs(p, NULL, NULL, NULL);
      while (*dmargv)
	{
	  if (!strcmp(*dmargv, "-display"))
	    {
	      dmargv++;
	      if (*dmargv)
		{
		  dpynum = atoi(*(dmargv) + 1);
		  dmargv++;
		}
	    }
	  else
	    dmargv++;
	}
    }

  p = getconf(conf, "X");
  if (p == NULL)
    console_login(conf, "\ndm: Can't find X command line\n");
  xargv = parseargs(p, NULL, NULL, NULL);

  p = getconf(conf, "console");
  if (p == NULL)
    console_login(conf, "\ndm: Can't find console command line\n");

  /* We will pass the read side of the pipe created below to console
   * on descriptor 3.
   */
  consoleargv = parseargs(p, "-inputfd", "3", NULL);

  /* Signal Setup */
  sigact.sa_handler = SIG_IGN;
  sigaction(SIGTSTP, &sigact, NULL);
  sigaction(SIGTTIN, &sigact, NULL);
  sigaction(SIGTTOU, &sigact, NULL);
  /* so that X pipe errors don't nuke us */
  sigaction(SIGPIPE, &sigact, NULL);
  sigact.sa_handler = shutdown;
  sigaction(SIGFPE, &sigact, NULL);
  sigact.sa_handler = die;
  sigaction(SIGHUP, &sigact, NULL);
  sigaction(SIGINT, &sigact, NULL);
  sigaction(SIGTERM, &sigact, NULL);
  sigact.sa_handler = child;
  sigaction(SIGCHLD, &sigact, NULL);
  sigact.sa_handler = catchalarm;
  sigaction(SIGALRM, &sigact, NULL);

  strcpy(line, "/dev/");
  strcat(line, consoletty);

  fd = open(line, O_RDWR);
  if (fd == -1)
    {
      syslog(LOG_ERR, "Cannot open %s: %m", line);
      /* This probably won't work, but it seems to be the appropriate
	 punt location. */
      console_login(conf, "Cannot open tty.\n");
    }

  if (login_tty(fd) == -1)
    syslog(LOG_ERR, "Cannot set the console as a login terminal (%s)",
	   strerror(errno));
  else
    {
      /* Set the console characteristics so we don't lose later */
      setpgid(0, pgrp = getpid());	/* Reset the tty pgrp  */
      if (tcsetpgrp(0, pgrp) == -1)
	syslog(LOG_ERR, "tcsetpgrp failed for console terminal (%s)",
	       strerror(errno));
    }

  /* save our pid file */
  writepid(dmpidf, getpid());

  /* Fire up X */
  xpid = 0;
  for (tries = 0; tries < 3; tries++)
    {
      syslog(LOG_DEBUG, "Starting X, try #%d", tries + 1);
      x_running = STARTUP;
      sigact.sa_handler = xready;
      sigaction(SIGUSR1, &sigact, NULL);
      switch (fork_and_store(&xpid))
	{
	case 0:
	  if (fcntl(2, F_SETFD, 1) == -1)
	    close(2);
	  (void) sigprocmask(SIG_SETMASK, &sig_zero, (sigset_t *) 0);

	  /* ignoring SIGUSR1 will cause the server to send us a SIGUSR1
	   * when it is ready to accept connections
	   */
	  sigact.sa_handler = SIG_IGN;
	  sigaction(SIGUSR1, &sigact, NULL);
	  p = *xargv;
	  *xargv = "X";
	  execv(p, xargv);
	  fprintf(stderr, "dm: X server failed exec: %s\n", strerror(errno));
	  _exit(1);
	case -1:
	  fprintf(stderr, "dm: Unable to fork to start X server: %s\n",
		  strerror(errno));
	  break;
	default:
	  sprintf(xpidf, xpids, dpynum);
	  writepid(xpidf, xpid);

	  if (x_running == STARTUP)
	    {
	      alarm(X_START_WAIT);
	      alarm_running = RUNNING;
	      sigsuspend(&sig_zero);
	    }
	  if (x_running != RUNNING)
	    {
	      syslog(LOG_DEBUG, "X failed to start; alarm_running=%d",
		     alarm_running);
	      if (alarm_running == NONEXISTENT)
		fprintf(stderr, "dm: Unable to start X\n");
	      else
		fprintf(stderr, "dm: X failed to become ready\n");

	      /* If X wouldn't run, it could be that an existing X
	       * process hasn't shut down.  Wait X_STOP_WAIT seconds
	       * for that to happen.
	       */
	      x_stop_wait();
	    }
	  sigact.sa_handler = SIG_IGN;
	  sigaction(SIGUSR1, &sigact, NULL);
	}
      if (x_running == RUNNING)
	break;
    }
  alarm(0);
  if (x_running != RUNNING)
    {
      syslog(LOG_DEBUG, "Giving up on starting X.");
      console_login(conf, "\nUnable to start X, doing console login "
		    "instead.\n");
    }

  /* Tighten up security a little bit. Remove all hosts from X's
   * access control list, assuming /etc/X0.hosts does not exist or
   * has zero length. If it does exist with nonzero length, this
   * behavior is not wanted. The desired effect of removing all hosts
   * is that only connections from the Unix domain socket will be
   * allowed.       

   * More secure code using Xau also exists, but there wasn't
   * time to completely flesh it out and resolve a couple of
   * issues. This code is probably good enough, but we'll see.
   * Maybe next time. 

   * This code has the added benefit of leaving an X display
   * connection open, owned by dm. This provides a less-hacky
   * solution to the config_console problem, where if config_console
   * is the first program run on user login, it causes the only
   * X app running at the time, console, to exit, thus resetting
   * the X server. Thus this code also allows the removal of the
   * hack in xlogin that attempts to solve the same problem, but
   * fails on the RS/6000 for reasons unexplored.

   * P.S. Don't run this code under Solaris 2.2- (2.3 is safe).
   * Removing all hosts from the acl on that server results in
   * no connections, not even from the Unix domain socket, being
   * allowed. --- cfields
   */

  sprintf(dpyacl, xhosts, dpynum);
  sprintf(dpyname, ":%d", dpynum);

#ifndef SOLARIS
  /* Use the display name for the utmp line field, except on Solaris. */
  utmp_line = dpyname;
#endif

  /* Put in our own error handler, open the display, then reset the handler. */
  xioerror_handler = XSetIOErrorHandler(handle_xioerror);
  dpy = XOpenDisplay(dpyname);
  XSetIOErrorHandler(xioerror_handler);

  if (dpy != NULL && (stat(dpyacl, &hostsinfo) || hostsinfo.st_size == 0))
    {
      hosts = XListHosts(dpy, &nhosts, &state);
      if (hosts != NULL)
	{
	  XRemoveHosts(dpy, hosts, nhosts);
	  XFree(hosts);
	}
      XAddHost(dpy, &localhost);
      XFlush(dpy);
    }
  /* else if (dpy == NULL)
   *   Could've sworn the X server was running now.
   *   Follow the original code path. No need introducing new bugs
   *   to this hairy code, just preserve the old behavior as though
   *   this code had never been added.
   */

  /* set up the console pty */
  if (openpty(&console_master_fd, &console_slave_fd, NULL, NULL, NULL) == -1)
    console_login(conf, "Cannot allocate pseudo-terminal\n");

  if (redir)
    {
      /* Redirect /dev/console output to the pty slave. */
#ifdef SRIOCSREDIR
      on = open("/dev/console", O_RDONLY);
      if (on >= 0)
	{
	  ioctl(on, SRIOCSREDIR, console_slave_fd);
	  close(on);
	}
#else
#ifdef TIOCCONS
      on = 1;
      ioctl(console_slave_fd, TIOCCONS, &on);
#endif
#endif
    }

  /* Set up the console pipe. */
  if (pipe(conspipe) == -1)
    console_login(conf, "Cannot create pipe for console\n");

  /* start up console */
  start_console(console_master_fd, conspipe[0], consoleargv);

  /* Set up to invoke xlogin. */
  p = getconf(conf, "login");
  if (p == NULL)
    console_login(conf, "\ndm: Can't find login command line\n");
  loginargv = parseargs(p, "-line", utmp_line, NULL);

  /* Fire up the X login */
  for (tries = 0; tries < 3; tries++)
    {
      syslog(LOG_DEBUG, "Starting xlogin, try #%d", tries + 1);
      login_running = STARTUP;
      sigact.sa_handler = loginready;
      sigaction(SIGUSR1, &sigact, NULL);
      switch (fork_and_store(&loginpid))
	{
	case 0:
	  max_fd = sysconf(_SC_OPEN_MAX);
	  for (file = 3; file < max_fd; file++)
	    {
	      if (file != conspipe[1])
		close(file);
	    }

	  setsid();
	  
	  file = open("/dev/null", O_RDONLY);
	  if (file >= 0)
	    {
	      dup2(file, 0);
	      if (file != 0)
		close(file);
	    }
	  
	  file = conspipe[1];
	  if (file == -1)
	    file = open("/dev/null", O_WRONLY);
	  if (file >= 0)
	    {
	      if (file != 1)
		dup2(file, 1);
	      if (file != 2)
		dup2(file, 2);
	      if (file != 1 && file != 2)
		close(file);
	    }

	  (void) sigprocmask(SIG_SETMASK, &sig_zero, (sigset_t *) 0);
	  /* ignoring SIGUSR1 will cause xlogin to send us a SIGUSR1
	   * when it is ready
	   */
	  sigact.sa_handler = SIG_IGN;
	  sigaction(SIGUSR1, &sigact, NULL);
	  /* dm ignores sigpipe; because of this, all of the children (ie, */
	  /* the entire session) inherit this unless we fix it now */
	  sigact.sa_handler = SIG_DFL;
	  sigaction(SIGPIPE, &sigact, NULL);
	  execv(loginargv[0], loginargv);
	  fprintf(stderr, "dm: X login failed exec: %s\n", strerror(errno));
	  _exit(1);
	case -1:
	  fprintf(stderr, "dm: Unable to fork to start X login: %s\n",
		  strerror(errno));
	  break;
	default:
	  alarm(LOGIN_START_WAIT);
	  alarm_running = RUNNING;
	  while (login_running == STARTUP && alarm_running == RUNNING)
	    sigsuspend(&sig_zero);
	  if (login_running != RUNNING)
	    {
	      syslog(LOG_DEBUG, "xlogin failed to start; alarm_running=%d",
		     alarm_running);
	      kill(loginpid, SIGKILL);
	      if (alarm_running != NONEXISTENT)
		fprintf(stderr, "dm: Unable to start Xlogin\n");
	      else
		fprintf(stderr, "dm: Xlogin failed to become ready\n");
	    }
	}
      if (login_running == RUNNING)
	break;
    }
  sigact.sa_handler = SIG_IGN;
  sigaction(SIGUSR1, &sigact, NULL);
  alarm(0);
  if (login_running != RUNNING)
    {
      syslog(LOG_DEBUG, "Giving up on starting xlogin.");
      console_login(conf, "\nUnable to start xlogin, doing console login "
		    "instead.\n");
    }

  /* main loop.  Wait for SIGCHLD, waking up every minute anyway. */
  (void) sigemptyset(&sig_cur);
  (void) sigaddset(&sig_cur, SIGCHLD);
  (void) sigprocmask(SIG_BLOCK, &sig_cur, NULL);
  while (1)
    {
      /* Wait for something to hapen */
      if (console_failed)
	{
	  /* if no console is running, we must copy bits from the console
	   * (master side of pty) to the real console to appear as black
	   * bar messages.
	   */
	  FD_ZERO(&readfds);
	  FD_SET(console_master_fd, &readfds);
	  (void) sigprocmask(SIG_SETMASK, &sig_zero, &mask);
	  count = select(console_master_fd + 1, &readfds, NULL, NULL, NULL);
	  (void) sigprocmask(SIG_BLOCK, &mask, NULL);
	  if (count > 0 && FD_ISSET(console_master_fd, &readfds))
	    {
	      file = read(console_master_fd, buf, sizeof(buf));
	      if (file != -1)
		write(1, buf, file);
	    }
	}
      else
	{
	  alarm(60);
	  sigsuspend(&sig_zero);
	}

      if (login_running == STARTUP)
	{
	  (void) sigprocmask(SIG_SETMASK, &sig_zero, NULL);
	  console_login(conf, "\nConsole login requested.\n");
	}
      if (console_running == FAILED)
	{
	  console_running = NONEXISTENT;
	  time(&now);
	  if (now - last_console_failure <= 3)
	    {
	      /* Give up on console.  Set the console characteristics so
	       * we don't lose later. */
	      syslog(LOG_ERR, "Giving up on the console");
	      setpgid(0, pgrp = getpid());	/* Reset the tty pgrp */
	      tcsetpgrp(0, pgrp);
	      console_failed = TRUE;
	    }
	  else
	    last_console_failure = now;
	}
      if (console_running == NONEXISTENT && !console_failed)
	start_console(console_master_fd, conspipe[0], consoleargv);
      if (login_running == NONEXISTENT || x_running == NONEXISTENT)
	{
	  syslog(LOG_DEBUG, "login_running=%d, x_running=%d, quitting",
		 login_running, x_running);
	  (void) sigprocmask(SIG_SETMASK, &sig_zero, NULL);
	  cleanup(utmp_line);
	  _exit(0);
	}
    }
}
예제 #3
0
파일: xhost.c 프로젝트: aosm/X11
static int 
change_host(Display *dpy, char *name, Bool add)
{
    XHostAddress ha;
    char *lname;
    int namelen, i, family = FamilyWild;
#ifdef K5AUTH
    krb5_principal princ;
    krb5_data kbuf;
#endif
#ifdef NEEDSOCKETS
#ifndef AMTCPCONN
    static struct in_addr addr;	/* so we can point at it */
#if defined(IPv6) && defined(AF_INET6)
    static struct in6_addr addr6; /* so we can point at it */
#else
    struct hostent *hp;
#endif
#else
    static ipaddr_t addr;
#endif
#endif
    char *cp;
#ifdef DNETCONN
    struct dn_naddr *dnaddrp;
    struct nodeent *np;
    static struct dn_naddr dnaddr;
#endif				/* DNETCONN */
    static char *add_msg = "being added to access control list";
    static char *remove_msg = "being removed from access control list";

    namelen = strlen(name);
    if ((lname = (char *)malloc(namelen+1)) == NULL) {
	fprintf (stderr, "%s: malloc bombed in change_host\n", ProgramName);
	exit (1);
    }
    for (i = 0; i < namelen; i++) {
	lname[i] = tolower(name[i]);
    }
    lname[namelen] = '\0';
    if (!strncmp("inet:", lname, 5)) {
#if defined(TCPCONN) || defined(STREAMSCONN) || defined(AMTCPCONN)
	family = FamilyInternet;
	name += 5;
#else
	fprintf (stderr, "%s: not compiled for TCP/IP\n", ProgramName);
	return 0;
#endif
    }
    else if (!strncmp("inet6:", lname, 6)) {
#if (defined(TCPCONN) || defined(STREAMSCONN)) && \
    defined(IPv6) && defined(AF_INET6)
	family = FamilyInternet6;
	name += 6;
#else
	fprintf (stderr, "%s: not compiled for IPv6\n", ProgramName);
	return 0;
#endif
    }
    else if (!strncmp("dnet:", lname, 5)) {
#ifdef DNETCONN
	family = FamilyDECnet;
	name += 5;
#else
	fprintf (stderr, "%s: not compiled for DECnet\n", ProgramName);
	return 0;
#endif
    }
    else if (!strncmp("nis:", lname, 4)) {
#ifdef SECURE_RPC
	family = FamilyNetname;
	name += 4;
#else
	fprintf (stderr, "%s: not compiled for Secure RPC\n", ProgramName);
	return 0;
#endif
    }
    else if (!strncmp("krb:", lname, 4)) {
#ifdef K5AUTH
	family = FamilyKrb5Principal;
	name +=4;
#else
	fprintf (stderr, "%s: not compiled for Kerberos 5\n", ProgramName);
	return 0;
#endif
    }
    else if (!strncmp("local:", lname, 6)) {
	family = FamilyLocalHost;
    }
    if (family == FamilyWild && (cp = strchr(lname, ':'))) {
	*cp = '\0';
	fprintf (stderr, "%s: unknown address family \"%s\"\n",
		 ProgramName, lname);
	return 0;
    }
    free(lname);

#ifdef DNETCONN
    if (family == FamilyDECnet ||
	(cp = strchr(name, ':')) && (*(cp + 1) == ':') &&
	!(*cp = '\0')) {
	ha.family = FamilyDECnet;
	if (dnaddrp = dnet_addr(name)) {
	    dnaddr = *dnaddrp;
	} else {
	    if ((np = getnodebyname (name)) == NULL) {
		fprintf (stderr, "%s:  unable to get node name for \"%s::\"\n",
			 ProgramName, name);
		return 0;
	    }
	    dnaddr.a_len = np->n_length;
	    memmove( dnaddr.a_addr, np->n_addr, np->n_length);
	}
	ha.length = sizeof(struct dn_naddr);
	ha.address = (char *)&dnaddr;
	if (add) {
	    XAddHost (dpy, &ha);
	    printf ("%s:: %s\n", name, add_msg);
	} else {
	    XRemoveHost (dpy, &ha);
	    printf ("%s:: %s\n", name, remove_msg);
	}
	return 1;
    }
#endif				/* DNETCONN */
#ifdef K5AUTH
    if (family == FamilyKrb5Principal) {
	krb5_error_code retval;

	retval = krb5_parse_name(name, &princ);
	if (retval) {
	    krb5_init_ets();	/* init krb errs for error_message() */
	    fprintf(stderr, "%s: cannot parse Kerberos name: %s\n",
		    ProgramName, error_message(retval));
	    return 0;
	}
	XauKrb5Encode(princ, &kbuf);
	ha.length = kbuf.length;
	ha.address = kbuf.data;
	ha.family = family;
	if (add)
	    XAddHost(dpy, &ha);
	else
	    XRemoveHost(dpy, &ha);
	krb5_free_principal(princ);
	free(kbuf.data);
	printf( "%s %s\n", name, add ? add_msg : remove_msg);
	return 1;
    }
#endif
    if (family == FamilyLocalHost) {
	ha.length = 0;
	ha.address = "";
	ha.family = family;
	if (add)
	    XAddHost(dpy, &ha);
	else
	    XRemoveHost(dpy, &ha);
	printf( "non-network local connections %s\n", add ? add_msg : remove_msg);
	return 1;
    }
    /*
     * If it has an '@', it's a netname
     */
    if ((family == FamilyNetname && (cp = strchr(name, '@'))) ||
	(cp = strchr(name, '@'))) {
        char *netname = name;
#ifdef SECURE_RPC
	static char username[MAXNETNAMELEN];

	if (!cp[1]) {
	    struct passwd *pwd;
	    static char domainname[128];

	    *cp = '\0';
	    pwd = getpwnam(name);
	    if (!pwd) {
		fprintf(stderr, "no such user \"%s\"\n", name);
		return 0;
	    }
	    getdomainname(domainname, sizeof(domainname));
	    if (!user2netname(username, pwd->pw_uid, domainname)) {
		fprintf(stderr, "failed to get netname for \"%s\"\n", name);
		return 0;
	    }
	    netname = username;
	}
#endif
	ha.family = FamilyNetname;
	ha.length = strlen(netname);
	ha.address = netname;
	if (add)
	    XAddHost (dpy, &ha);
	else
	    XRemoveHost (dpy, &ha);
	if (netname != name)
	    printf ("%s@ (%s) %s\n", name, netname, add ? add_msg : remove_msg);
	else
	    printf ("%s %s\n", netname, add ? add_msg : remove_msg);
        return 1;
    }
#ifdef NEEDSOCKETS
    /*
     * First see if inet_addr() can grok the name; if so, then use it.
     */
#ifndef AMTCPCONN
    if (((family == FamilyWild) || (family == FamilyInternet)) &&
	((addr.s_addr = inet_addr(name)) != -1)) {
#else
    if (((family == FamilyWild) || (family == FamilyInternet)) &&
	((addr = inet_addr(name)) != -1)) {
#endif
	ha.family = FamilyInternet;
	ha.length = 4;		/* but for Cray would be sizeof(addr.s_addr) */
	ha.address = (char *)&addr; /* but for Cray would be &addr.s_addr */
	if (add) {
	    XAddHost (dpy, &ha);
	    printf ("%s %s\n", name, add_msg);
	} else {
	    XRemoveHost (dpy, &ha);
	    printf ("%s %s\n", name, remove_msg);
	}
	return 1;
    } 
#if defined(IPv6) && defined(AF_INET6)
    /*
     * Check to see if inet_pton() can grok it as an IPv6 address
     */
    else if (((family == FamilyWild) || (family == FamilyInternet6)) &&
	     (inet_pton(AF_INET6, name, &addr6.s6_addr) == 1)) {
	ha.family = FamilyInternet6;
	ha.length = sizeof(addr6.s6_addr);		
	ha.address = (char *) &addr6.s6_addr; 
	if (add) {
	    XAddHost (dpy, &ha);
	    printf ("%s %s\n", name, add_msg);
	} else {
	    XRemoveHost (dpy, &ha);
	    printf ("%s %s\n", name, remove_msg);
	}
	return 1;
    } else {
    /*
     * Is it in the namespace?  
     *
     * If no family was specified, use both Internet v4 & v6 addresses.
     * Otherwise, use only addresses matching specified family.
     */
	struct addrinfo *addresses;
	struct addrinfo *a;
	Bool didit = False;

	if (getaddrinfo(name, NULL, NULL, &addresses) != 0)
	    return 0;

	for (a = addresses; a != NULL; a = a->ai_next) {
	    if ( ((a->ai_family == AF_INET) && (family != FamilyInternet6))
	      || ((a->ai_family == AF_INET6) && (family != FamilyInternet)) ) {
		char ad[INET6_ADDRSTRLEN];
		ha.family = XFamily(a->ai_family);
		if (a->ai_family == AF_INET6) {
		    ha.address = (char *)
		      &((struct sockaddr_in6 *) a->ai_addr)->sin6_addr;
		    ha.length = 
		      sizeof (((struct sockaddr_in6 *) a->ai_addr)->sin6_addr);
		} else {
		    ha.address = (char *)
		      &((struct sockaddr_in *) a->ai_addr)->sin_addr;
		    ha.length = 
		      sizeof (((struct sockaddr_in *) a->ai_addr)->sin_addr);
		}
		inet_ntop(a->ai_family, ha.address, ad, sizeof(ad));
	/* printf("Family: %d\nLength: %d\n", a->ai_family, ha.length); */
		/* printf("Address: %s\n", ad); */

		if (add) {
		    XAddHost (dpy, &ha);
		} else {
		    XRemoveHost (dpy, &ha);
		}
		didit = True;
	    }
	}
	if (didit == True) {
	    printf ("%s %s\n", name, add ? add_msg : remove_msg);
	} else {
	    const char *familyMsg = "";

	    if (family == FamilyInternet6) {
		familyMsg = "inet6 ";
	    } else if (family == FamilyInternet) {
		familyMsg = "inet ";
	    }

	    fprintf(stderr, "%s: unable to get %saddress for \"%s\"\n",
		ProgramName, familyMsg, name);
	}
	freeaddrinfo(addresses);
	return 1;
    }
#else /* !IPv6 */
    /*
     * Is it in the namespace?
     */
    else if (((hp = gethostbyname(name)) == (struct hostent *)NULL)
	     || hp->h_addrtype != AF_INET) {
	return 0;
    } else {
	ha.family = XFamily(hp->h_addrtype);
	ha.length = hp->h_length;
#ifdef h_addr			/* new 4.3bsd version of gethostent */
    {
	char **list;

	/* iterate over the hosts */
	for (list = hp->h_addr_list; *list; list++) {
	    ha.address = *list;
	    if (add) {
		XAddHost (dpy, &ha);
	    } else {
		XRemoveHost (dpy, &ha);
	    }
	}
    }
#else
	ha.address = hp->h_addr;
	if (add) {
	    XAddHost (dpy, &ha);
	} else {
	    XRemoveHost (dpy, &ha);
	}
#endif
	printf ("%s %s\n", name, add ? add_msg : remove_msg);
	return 1;
    }
#endif /* IPv6 */
#else /* NEEDSOCKETS */
    return 0;
#endif /* NEEDSOCKETS */
}
예제 #4
0
main()
{
      Window w2;

      Display *dpy = XOpenDisplay(NIL);
      assert(dpy);
      Screen *scr = DefaultScreenOfDisplay(dpy);

      // CreateWindow

      Window w = XCreateWindow(dpy, RootWindowOfScreen(scr), 10, 100, 200, 300, 0, CopyFromParent,
			       CopyFromParent, CopyFromParent,
			       0, NIL);

      XDestroyWindow(dpy, w);

      // CreateWindow with arguments

      XSetWindowAttributes swa;
      swa.background_pixel = WhitePixelOfScreen(scr);
      swa.bit_gravity = NorthWestGravity;
      swa.border_pixel = BlackPixelOfScreen(scr);
      swa.colormap = DefaultColormapOfScreen(scr);
      swa.cursor = None;
      swa.win_gravity = NorthGravity;

      w = XCreateWindow(dpy, RootWindowOfScreen(scr), 10, 100, 200, 300, 0, CopyFromParent,
			CopyFromParent, CopyFromParent,
			CWBackPixel | CWBitGravity | CWBorderPixel | CWColormap | CWCursor | CWWinGravity, 
			&swa);
      
      // CreateWindow with other arguments

      XDestroyWindow(dpy, w);

      Pixmap pixmap = XCreatePixmap(dpy, RootWindowOfScreen(scr), 45, 25, DefaultDepthOfScreen(scr));
      assert(pixmap);

      swa.background_pixmap = pixmap;
      swa.border_pixmap = pixmap;

      w = XCreateWindow(dpy, RootWindowOfScreen(scr), 10, 100, 200, 300, 0, CopyFromParent,
			CopyFromParent, CopyFromParent,
			CWBackPixmap | CWBorderPixmap,
			&swa);
      
      // ChangeWindowAttributes

      swa.backing_planes = 0x1;
      swa.backing_pixel = WhitePixelOfScreen(scr);
      swa.save_under = True;
      swa.event_mask = KeyPressMask | KeyReleaseMask;
      swa.do_not_propagate_mask = ButtonPressMask | Button4MotionMask;
      swa.override_redirect = False;
      XChangeWindowAttributes(dpy, w, CWBackingPlanes | CWBackingPixel | CWSaveUnder | CWEventMask
			      | CWDontPropagate | CWOverrideRedirect, &swa);

      // GetWindowAttributes

      XWindowAttributes wa;
      Status success = XGetWindowAttributes(dpy, w, &wa);

      // DestroyWindow (done)

      // DestroySubwindows

      w2 = XCreateWindow(dpy, w, 20, 30, 40, 50, 3, CopyFromParent, CopyFromParent, CopyFromParent, 0, NIL);
      XDestroySubwindows(dpy, w);

      // ChangeSaveSet

//        Display *dpy2 = XOpenDisplay(NIL);
//        assert(dpy2);
//        XAddToSaveSet(dpy2, w);
//        XCloseDisplay(dpy2);

      // ReparentWindow

      w2 = XCreateWindow(dpy, RootWindowOfScreen(scr), 20, 30, 40, 50, 3, 
			 CopyFromParent, CopyFromParent, CopyFromParent, 0, NIL);
      XReparentWindow(dpy, w2, w, 10, 5);

      // MapWindow

      XMapWindow(dpy, w);

      // MapSubwindows
      
      XMapSubwindows(dpy, w);

      // UnmapWindow
      
      XUnmapWindow(dpy, w);

      // UnmapSubwindows

      XMapWindow(dpy, w);
      XUnmapSubwindows(dpy, w2);
      XMapSubwindows(dpy, w);

      // ConfigureWindow

      Window w3 = XCreateWindow(dpy, w, 10, 50, 100, 10, 2,
			 CopyFromParent, CopyFromParent, CopyFromParent, 0, NIL);

      XMapWindow(dpy, w3);

      XWindowChanges wc;
      wc.x = -5;
      wc.y = -10;
      wc.width = 50;
      wc.height = 40;
      wc.border_width = 7;
      wc.sibling = w2;
      wc.stack_mode = Opposite;
      XConfigureWindow(dpy, w3, 
		       CWX | CWY | CWWidth | CWHeight | CWBorderWidth | CWSibling | CWStackMode, 
		       &wc);

      // CirculateWindow

      XCirculateSubwindows(dpy, w, RaiseLowest);

      // GetGeometry

      Window root;
      int x, y;
      unsigned width, height, border_width, depth;
      XGetGeometry(dpy, w, &root, &x, &y, &width, &height, &border_width, &depth);

      // QueryTree

      Window parent;
      Window *children;
      unsigned nchildren;
      success = XQueryTree(dpy, w, &root, &parent, &children, &nchildren);
      XFree(children);

      // InternAtom

      Atom a = XInternAtom(dpy, "WM_PROTOCOLS", True);

      // GetAtomName

      char *string = XGetAtomName(dpy, XA_PRIMARY);
      XFree(string);

      // ChangeProperty

      XStoreName(dpy, w, "test window");

      // DeleteProperty

      XDeleteProperty(dpy, w, XA_WM_NAME);

      // GetProperty
      // TODO

      // ListProperties

      int num_prop;
      Atom *list = XListProperties(dpy, w, &num_prop);
      XFree(list);

      // SetSelectionOwner

      XSetSelectionOwner(dpy, XA_PRIMARY, w, 12000);
      XSetSelectionOwner(dpy, XA_SECONDARY, w, CurrentTime);

      // GetSelectionOwner

      Window wx = XGetSelectionOwner(dpy, XA_PRIMARY);

      // ConvertSelection

      XConvertSelection(dpy, XA_SECONDARY, XA_CURSOR, XA_POINT, w, CurrentTime);

      // SendEvent

      // GrabPointer

      std::cerr << "Grabbing" << std::endl;
      int res = XGrabPointer(dpy, w, False, Button5MotionMask | PointerMotionHintMask,
			     GrabModeSync, GrabModeAsync, w, None, CurrentTime);
      XSync(dpy, False);
//      sleep(5);

      // UngrabPointer

      std::cerr << "Ungrabbing" << std::endl;
      XUngrabPointer(dpy, CurrentTime);

      // GrabButton

      XGrabButton(dpy, 3, ShiftMask | ControlMask, w, False, PointerMotionHintMask | Button2MotionMask, 
		  GrabModeAsync, GrabModeSync, None, None);
		  
      XGrabButton(dpy, 2, AnyModifier, w, False, PointerMotionHintMask | Button2MotionMask, 
		  GrabModeAsync, GrabModeSync, None, None);
		  
      // UngrabButton

      XUngrabButton(dpy, 2, LockMask, w);

      // ChangeActivePointerGrab

      XChangeActivePointerGrab(dpy, ButtonPressMask, None, CurrentTime);

      // GrabKeyboard

      XGrabKeyboard(dpy, w, True, GrabModeSync, GrabModeSync, 12000);

      // UngrabKeyboard

      XUngrabKeyboard(dpy, 13000);

      // GrabKey

      XGrabKey(dpy, XKeysymToKeycode(dpy, XK_Tab), ShiftMask | Mod3Mask, w, True, GrabModeSync,
	       GrabModeSync);

      // UngrabKey

      XUngrabKey(dpy, AnyKey, AnyModifier, w);

      // AllowEvents

      XAllowEvents(dpy, AsyncPointer, 14000);

      // GrabServer

      XGrabServer(dpy);

      // UngrabServer

      XUngrabServer(dpy);

      // QueryPointer

      Window child;
      int root_x, root_y, win_x, win_y;
      unsigned mask;
      Bool bres = XQueryPointer(dpy, w, &root, &child, &root_x, &root_y, &win_x, &win_y, &mask);

      // GetMotionEvents

      int nevents;
      XGetMotionEvents(dpy, w, 15000, 16000, &nevents);

      // TranslateCoordinates

      int dest_x, dest_y;

      XTranslateCoordinates(dpy, w, w2, 10, 20, &dest_x, &dest_y, &child);

      // WarpPointer

      XWarpPointer(dpy, w, w2, 0, 0, 100, 100, 20, 30);

      // SetInputFocus

      XSetInputFocus(dpy,w, RevertToPointerRoot, 17000);
      XSetInputFocus(dpy, PointerRoot, RevertToPointerRoot, 17000);

      // GetInputFocus

      Window focus;
      int revert_to;
      XGetInputFocus(dpy, &focus, &revert_to);

      // QueryKeymap

      char keys_return[32];
      XQueryKeymap(dpy, keys_return);

      // OpenFont

      Font fid = XLoadFont(dpy, "cursor");

      // CloseFont

      XUnloadFont(dpy, fid);

      // QueryFont

      XFontStruct *fs = XLoadQueryFont(dpy, "cursor");
      assert(fs);

      // QueryTextExtents

      int direction, font_ascent, font_descent;
      XCharStruct overall;
      XQueryTextExtents(dpy, fs -> fid, "toto", 4, &direction, &font_ascent, &font_descent, &overall);
      XQueryTextExtents(dpy, fs -> fid, "odd__length", 11, &direction, &font_ascent, &font_descent, &overall);

      XChar2b c2bs;
      c2bs.byte1 = '$';
      c2bs.byte2 = 'B';
      XQueryTextExtents16(dpy, fs -> fid, &c2bs, 1, &direction, &font_ascent, &font_descent, &overall);

      XQueryTextExtents(dpy, fs -> fid, longString, strlen(longString), &direction, &font_ascent, 
			&font_descent, &overall);

      // ListFonts

      int actual_count;
      char **fontList = XListFonts(dpy, "*", 100, &actual_count);
      XFree((char *)fontList);

      // ListFontsWithInfo

      int count;
      XFontStruct *info;
      char **names = XListFontsWithInfo(dpy, "*", 100, &count, &info);
      XFreeFontInfo(names, info, count);

      // SetFontPath
      // GetFontPath

      int npaths;
      char **charList = XGetFontPath(dpy, &npaths);

      char **charList2 = new char *[npaths + 1];
      memcpy(charList2, charList, npaths * sizeof(char *));
      charList2[npaths] = charList2[0];

      XSetFontPath(dpy, charList2, npaths + 1);
      XSetFontPath(dpy, charList, npaths); // Reset to some reasonnable value

      XFreeFontPath(charList);
      delete [] charList2;

      // CreatePixmap

      Pixmap pix2 = XCreatePixmap(dpy, w, 100, 200, DefaultDepthOfScreen(scr));

      // FreePixmap

      XFreePixmap(dpy, pix2);

      // CreateGC

      Pixmap bitmap = XCreateBitmapFromData(dpy, RootWindowOfScreen(scr), 
					    "\000\000\001\000\000\001\000\000\001\377\377\377", 3, 4);

      XGCValues gcv;
      gcv.function = GXand;
      gcv.plane_mask = 0x1;
      gcv.foreground = WhitePixelOfScreen(scr);
      gcv.background = BlackPixelOfScreen(scr);
      gcv.line_width = 2;
      gcv.line_style = LineDoubleDash;
      gcv.cap_style = CapProjecting;
      gcv.join_style = JoinRound;
      gcv.fill_style = FillStippled;
      gcv.fill_rule = EvenOddRule;
      gcv.arc_mode = ArcPieSlice;
      gcv.tile = pixmap;
      gcv.stipple = bitmap;
      gcv.ts_x_origin = 3;
      gcv.ts_y_origin = 4;
      gcv.font = fs -> fid;
      gcv.subwindow_mode = ClipByChildren;
      gcv.graphics_exposures = True;
      gcv.clip_x_origin = 5;
      gcv.clip_y_origin = 6;
      gcv.clip_mask = bitmap;
      gcv.dash_offset = 1;
      gcv.dashes = 0xc2;
      
      GC gc = XCreateGC(dpy, w, 
			  GCFunction | GCPlaneMask | GCForeground | GCBackground | GCLineWidth
			| GCLineStyle | GCCapStyle | GCJoinStyle | GCFillStyle | GCFillRule | GCTile
			| GCStipple | GCTileStipXOrigin | GCTileStipYOrigin | GCFont | GCSubwindowMode
			| GCGraphicsExposures | GCClipXOrigin | GCClipYOrigin | GCClipMask | GCDashOffset
			| GCDashList | GCArcMode,
			&gcv);

      // ChangeGC

      gcv.function = GXandReverse;

      // Only a few of these should appear, since the values are cached on the client side by the Xlib.

      XChangeGC(dpy, gc, GCFunction | GCLineStyle | GCStipple | GCGraphicsExposures | GCDashList, &gcv);

      // CopyGC
      
      GC gc2 = XCreateGC(dpy, w, 0, NIL);
      XCopyGC(dpy, gc, GCFunction | GCLineStyle | GCStipple | GCGraphicsExposures | GCDashList, gc2);

      // SetDashes

      XSetDashes(dpy, gc, 3, "\001\377\001", 3);

      // SetClipRectangles

      XRectangle rectangles[] = { { 10, 20, 30, 40 }, { 100, 200, 5, 3 }, { -5, 1, 12, 24 } };
      XSetClipRectangles(dpy, gc, 12, 9, rectangles, SIZEOF(rectangles), Unsorted);

      // FreeGC

	    // done already

      // ClearArea

      XClearArea(dpy, w, 30, 10, 10, 100, False);

      // CopyArea

      XCopyArea(dpy, w, pixmap, gc, 0, 0, 100, 100, 10, 10);

      // CopyPlane

      // This won't work if the Screen doesn't have at least 3 planes
      XCopyPlane(dpy, pixmap, w, gc, 20, 10, 40, 30, 0, 0, 0x4);

      // PolyPoint

      XDrawPoint(dpy, w, gc, 1, 2);

      XPoint points[] = { { 3, 4 }, { 5, 6 } };
      XDrawPoints(dpy, w, gc, points, SIZEOF(points), CoordModeOrigin);

      // PolyLine

      XDrawLines(dpy, w, gc, points, SIZEOF(points), CoordModePrevious);

      // PolySegment

      XSegment segments[] = { { 7, 8, 9, 10 }, { 11, 12, 13, 14 }, { 15, 16, 17, 18 } };
      XDrawSegments(dpy, w, gc, segments, SIZEOF(segments));

      // PolyRectangle

      XDrawRectangles(dpy, w, gc, rectangles, SIZEOF(rectangles));

      // PolyArc

      XArc arcs[] = { { 10, 20, 30, 40, 50, 60 }, { -70, 80, 90, 100, 110, 120 }, 
		      { 10, 20, 30, 40, 50, -30 } };

      XDrawArcs(dpy, w, gc, arcs, SIZEOF(arcs));

      // FillPoly

      XFillPolygon(dpy, w, gc, points, SIZEOF(points), Convex, CoordModePrevious);

      // PolyFillRectangle
      
      XFillRectangles(dpy, w, gc, rectangles, SIZEOF(rectangles));

      // PolyFillArc
      
      XFillArcs(dpy, w, gc, arcs, SIZEOF(arcs));

      // PutImage
      // GetImage

      XImage *image = XGetImage(dpy, w, 10, 20, 40, 30, AllPlanes, ZPixmap);
      XPutImage(dpy, w, gc, image, 0, 0, 50, 60, 40, 30);
      XSync(dpy, False); // Make the next request starts at the beginning of a packet

      // PolyText8
      XTextItem textItems[3];
      textItems[0].chars = "toto";
      textItems[0].nchars = strlen(textItems[0].chars);
      textItems[0].delta = -3;
      textItems[0].font = fs->fid;
      textItems[1].chars = "titi";
      textItems[1].nchars = strlen(textItems[1].chars);
      textItems[1].delta = 3;
      textItems[1].font = None;
      textItems[2].chars = "tutu";
      textItems[2].nchars = strlen(textItems[2].chars);
      textItems[2].delta = 0;
      textItems[2].font = fs->fid;

      XDrawText(dpy, w, gc, 10, 10, textItems, 3);


      XTextItem textItems2[3];
      textItems2[0].chars = "totox";
      textItems2[0].nchars = strlen(textItems2[0].chars);
      textItems2[0].delta = -3;
      textItems2[0].font = fs->fid;
      textItems2[1].chars = "titi";
      textItems2[1].nchars = strlen(textItems2[1].chars);
      textItems2[1].delta = 3;
      textItems2[1].font = None;
      textItems2[2].chars = "tutu";
      textItems2[2].nchars = strlen(textItems2[2].chars);
      textItems2[2].delta = 0;
      textItems2[2].font = fs->fid;

      XDrawText(dpy, w, gc, 10, 10, textItems2, 3);

      // PolyText16

      XChar2b c2b2[] = { 0, 't', 0, 'x' };

      XTextItem16 items16[] = { { &c2bs, 1, -5, None }, { NULL, 0, 0, None }, { c2b2, 2, 0, fs -> fid } };
      XDrawText16(dpy, w, gc, 10, 0, items16, SIZEOF(items16));

      // ImageText8

      XDrawImageString(dpy, w, gc, 10, 10, "toto", 4);

      // ImageText16

      XDrawImageString16(dpy, w, gc, 10, 10, &c2bs, 1);
      XDrawImageString16(dpy, w, gc, 10, 20, c2b2, 2);

      // CreateColormap
      // Don't forget to tell the kids how it was when we had only 8 bits per pixel.

      Colormap colormap = XCreateColormap(dpy, w, DefaultVisualOfScreen(scr), None);

      // FreeColormap

      XFreeColormap(dpy, colormap);
      colormap = XCreateColormap(dpy, w, DefaultVisualOfScreen(scr), None);

      // CopyColormapAndFree

      Colormap colormap2 = XCopyColormapAndFree(dpy, colormap);

      // InstallColormap

      XInstallColormap(dpy, colormap2);

      // UninstallColormap

      XUninstallColormap(dpy, colormap2);

      // ListInstalledColormaps

      int num;
      Colormap *colormapList = XListInstalledColormaps(dpy, w, &num);

      // AllocColor

      XColor screen;
      screen.red = 0;
      screen.green = 32767;
      screen.blue = 65535;
      screen.flags = DoRed | DoGreen | DoBlue;
      success = XAllocColor(dpy, colormap, &screen);

      // AllocNamedColor

      XColor screen2, exact;
      success = XAllocNamedColor(dpy, colormap, "Wheat", &screen2, &exact);

      // AllocColorCells

      unsigned long plane_masks, pixels;
      success = XAllocColorCells(dpy, colormap, False, &plane_masks, 1, &pixels, 1);

      // AllocColorPlanes

      unsigned long rmask, gmask, bmask;
      success = XAllocColorPlanes(dpy, colormap, False, &pixels, 1, 0, 0, 0, &rmask, &gmask, &bmask);

      // FreeColors

      unsigned long pixels2[2] = { screen.pixel, screen2.pixel };
      XFreeColors(dpy, colormap, pixels2, 2, 0);

      // StoreColors

      success = XAllocColorCells(dpy, colormap, False, NIL, 0, pixels2, 2);

      // On many contemporary (that is, year 2000) video cards, you can't allocate read / write cells
      // I want my requests to be sent, however.
      if (!success) {
	    XSetErrorHandler(errorHandler);
      }

      XColor colors[2];
      colors[0] = screen;  colors[0].pixel = pixels2[0];
      colors[1] = screen2; colors[1].pixel = pixels2[1];
      XStoreColors(dpy, colormap, colors, 2);

      // StoreNamedColor

      XStoreNamedColor(dpy, colormap, "Wheat", colors[0].pixel, DoBlue);

      XSync(dpy, False);
      XSetErrorHandler(NIL); // Restore the default handler

      // QueryColors

      screen2.pixel = WhitePixelOfScreen(scr);
      XQueryColor(dpy, colormap, &screen2);

      // LookupColor

      success = XLookupColor(dpy, colormap, "DarkCyan", &exact, &screen);

      // CreateCursor

      Cursor cursor = XCreatePixmapCursor(dpy, pixmap, None, &exact, colors, 10, 10);

      // CreateGlyphCursor
      
      Cursor cursor2 = XCreateGlyphCursor(dpy, fs -> fid, fs -> fid, 'X', 0, &exact, colors);

      // FreeCursor
      
      XFreeCursor(dpy, cursor2);

      // RecolorCursor

      XRecolorCursor(dpy, cursor, colors, &exact);

      // QueryBestSize

      success = XQueryBestSize(dpy, CursorShape, RootWindowOfScreen(scr), 100, 20, &width, &height);

      // QueryExtension

      int major_opcode, first_event, first_error;
      XQueryExtension(dpy, "toto", &major_opcode, &first_event, &first_error);

      // ListExtensions

      int nextensions;
      char **extensionList = XListExtensions(dpy, &nextensions);
      for(char **p = extensionList; nextensions; nextensions--, p++) std::cout << *p << std::endl;
      XFree(extensionList);

      // ChangeKeyboardMapping
      // GetKeyboardMapping

      int min_keycodes, max_keycodes;
      XDisplayKeycodes(dpy, &min_keycodes, &max_keycodes);

      int keysyms_per_keycode;
      KeySym *keysyms = XGetKeyboardMapping(dpy, min_keycodes, max_keycodes - min_keycodes + 1,
					    &keysyms_per_keycode);
      XChangeKeyboardMapping(dpy, min_keycodes, keysyms_per_keycode, keysyms, 
			     max_keycodes - min_keycodes + 1);

      // ChangeKeyboardControl
      // GetKeyboardControl

      XKeyboardState keyboardState;
      XGetKeyboardControl(dpy, &keyboardState);

      XKeyboardControl keyboardValues;
      keyboardValues.key_click_percent = keyboardState.key_click_percent;
      keyboardValues.bell_percent = keyboardState.bell_percent;
      keyboardValues.bell_pitch = keyboardState.bell_pitch;
      keyboardValues.bell_duration = keyboardState.bell_duration;
      keyboardValues.led = 1;
      keyboardValues.led_mode = LedModeOn;
      keyboardValues.key = min_keycodes;
      keyboardValues.auto_repeat_mode = AutoRepeatModeDefault;
      XChangeKeyboardControl(dpy, 
			       KBKeyClickPercent | KBBellPercent | KBBellPitch | KBBellDuration
			     | KBLed | KBLedMode | KBKey | KBAutoRepeatMode,
			     &keyboardValues);

      // Bell

      XBell(dpy, 90);

      // ChangePointerControl
      // GetPointerControl

      int accel_numerator, accel_denominator, threshold;
      XGetPointerControl(dpy, &accel_numerator, &accel_denominator, &threshold);

      XChangePointerControl(dpy, True, True, accel_numerator, accel_denominator, threshold);

      // SetScreenSaver
      // GetScreenSaver

      int timeout, interval, prefer_blanking, allow_exposures;
      XGetScreenSaver(dpy, &timeout, &interval, &prefer_blanking, &allow_exposures);
      XSetScreenSaver(dpy, timeout, interval, prefer_blanking, allow_exposures);

      // ChangeHosts
      // ListHosts

      int nhosts;
      Bool state;
      XHostAddress *hostList = XListHosts(dpy, &nhosts, &state);

      XHostAddress host;
      host.family = FamilyInternet;
      host.length = 4;
      host.address = "\001\002\003\004";
      XAddHost(dpy, &host);

      // SetAccessControl

      XSetAccessControl(dpy, EnableAccess);

      // SetCloseDownMode

      XSetCloseDownMode(dpy, RetainTemporary);

      // KillClient

      XKillClient(dpy, AllTemporary);

      // RotateProperties

      Atom properties[] = { XInternAtom(dpy, "CUT_BUFFER0", False), 
			    XInternAtom(dpy, "CUT_BUFFER1", False),
			    XInternAtom(dpy, "CUT_BUFFER2", False) };
      XRotateWindowProperties(dpy, RootWindowOfScreen(scr), properties, SIZEOF(properties), -1);

      // ForceScreenSaver

      XForceScreenSaver(dpy, ScreenSaverReset);

      // SetPointerMapping
      // GetPointerMapping

      unsigned char map[64];
      int map_length = XGetPointerMapping(dpy, map, 64);
      XSetPointerMapping(dpy, map, map_length);

      // SetModifierMapping
      // GetModifierMapping

      XModifierKeymap *modmap = XGetModifierMapping(dpy);
      XSetModifierMapping(dpy, modmap);

      // NoOperation

      XNoOp(dpy);

      for(;;) {
	    XEvent e;
	    XNextEvent(dpy, &e);
	    std::cout << "Got an event of type " << e.type << std::endl;
      }
}
예제 #5
0
int
startClient( volatile int *pid )
{
	const char *home, *sessargs, *desksess;
	char **env, *xma;
	char **argv, *fname, *str;
#ifdef USE_PAM
	char ** volatile pam_env;
# ifndef HAVE_PAM_GETENVLIST
	char **saved_env;
# endif
	int pretc;
#else
# ifdef _AIX
	char *msg;
	char **theenv;
	extern char **newenv; /* from libs.a, this is set up by setpenv */
# endif
#endif
#ifdef HAVE_SETUSERCONTEXT
	extern char **environ;
#endif
	char *failsafeArgv[2];
	char *buf, *buf2;
	int i;

	if (strCmp( dmrcuser, curuser )) {
		if (curdmrc) { free( curdmrc ); curdmrc = 0; }
		if (dmrcuser) { free( dmrcuser ); dmrcuser = 0; }
	}

#if defined(USE_PAM) || defined(_AIX)
	if (!(p = getpwnam( curuser ))) {
		logError( "getpwnam(%s) failed.\n", curuser );
	  pError:
		displayStr( V_MSG_ERR, 0 );
		return 0;
	}
#endif

#ifndef USE_PAM
# ifdef _AIX
	msg = NULL;
	loginsuccess( curuser, hostname, tty, &msg );
	if (msg) {
		debug( "loginsuccess() - %s\n", msg );
		free( (void *)msg );
	}
# else /* _AIX */
#  if defined(KERBEROS) && defined(AFS)
	if (krbtkfile[0] != '\0') {
		if (k_hasafs()) {
			int fail = 0;
			if (k_setpag() == -1) {
				logError( "setpag() for %s failed\n", curuser );
				fail = 1;
			}
			if ((ret = k_afsklog( NULL, NULL )) != KSUCCESS) {
				logError( "AFS Warning: %s\n", krb_get_err_text( ret ) );
				fail = 1;
			}
			if (fail)
				displayMsg( V_MSG_ERR,
				            "Warning: Problems during Kerberos4/AFS setup." );
		}
	}
#  endif /* KERBEROS && AFS */
# endif /* _AIX */
#endif	/* !PAM */

	curuid = p->pw_uid;
	curgid = p->pw_gid;

	env = baseEnv( curuser );
	xma = 0;
	strApp( &xma, "method=", curtype, (char *)0 );
	if (td_setup)
		strApp( &xma, ",auto", (char *)0 );
	if (xma) {
		env = setEnv( env, "XDM_MANAGED", xma );
		free( xma );
	}
	if (td->autoLock && cursource == PWSRC_AUTOLOGIN)
		env = setEnv( env, "DESKTOP_LOCKED", "true" );
	env = setEnv( env, "PATH", curuid ? td->userPath : td->systemPath );
	env = setEnv( env, "SHELL", p->pw_shell );
	env = setEnv( env, "HOME", p->pw_dir );
#if !defined(USE_PAM) && !defined(_AIX) && defined(KERBEROS)
	if (krbtkfile[0] != '\0')
		env = setEnv( env, "KRBTKFILE", krbtkfile );
#endif
	userEnviron = inheritEnv( env, envvars );
	env = systemEnv( curuser );
	systemEnviron = setEnv( env, "HOME", p->pw_dir );
	debug( "user environment:\n%[|''>'\n's"
	       "system environment:\n%[|''>'\n's"
	       "end of environments\n",
	       userEnviron,
	       systemEnviron );

	/*
	 * for user-based authorization schemes,
	 * add the user to the server's allowed "hosts" list.
	 */
	for (i = 0; i < td->authNum; i++) {
#ifdef SECURE_RPC
		if (td->authorizations[i]->name_length == 9 &&
		    !memcmp( td->authorizations[i]->name, "SUN-DES-1", 9 ))
		{
			XHostAddress addr;
			char netname[MAXNETNAMELEN+1];
			char domainname[MAXNETNAMELEN+1];

			getdomainname( domainname, sizeof(domainname) );
			user2netname( netname, curuid, domainname );
			addr.family = FamilyNetname;
			addr.length = strlen( netname );
			addr.address = netname;
			XAddHost( dpy, &addr );
		}
#endif
#ifdef K5AUTH
		if (td->authorizations[i]->name_length == 14 &&
		    !memcmp( td->authorizations[i]->name, "MIT-KERBEROS-5", 14 ))
		{
			/* Update server's auth file with user-specific info.
			 * Don't need to AddHost because X server will do that
			 * automatically when it reads the cache we are about
			 * to point it at.
			 */
			XauDisposeAuth( td->authorizations[i] );
			td->authorizations[i] =
				krb5GetAuthFor( 14, "MIT-KERBEROS-5", td->name );
			saveServerAuthorizations( td, td->authorizations, td->authNum );
		}
#endif
	}

	if (*dmrcDir)
		mergeSessionArgs( TRUE );

	debug( "now starting the session\n" );

#ifdef USE_PAM

# ifdef HAVE_SETUSERCONTEXT
	if (setusercontext( lc, p, p->pw_uid, LOGIN_SETGROUP )) {
		logError( "setusercontext(groups) for %s failed: %m\n",
		          curuser );
		goto pError;
	}
# else
	if (!setGid( curuser, curgid ))
		goto pError;
# endif

# ifndef HAVE_PAM_GETENVLIST
	if (!(pam_env = initStrArr( 0 ))) {
		resetGids();
		goto pError;
	}
	saved_env = environ;
	environ = pam_env;
# endif
	removeCreds = 1; /* set it first - i don't trust PAM's rollback */
	pretc = pam_setcred( pamh, 0 );
	reInitErrorLog();
# ifndef HAVE_PAM_GETENVLIST
	pam_env = environ;
	environ = saved_env;
# endif
# ifdef HAVE_INITGROUPS
	/* This seems to be a strange place for it, but do it:
	   - after the initial groups are set
	   - after pam_setcred might have set something, even in the error case
	   - before pam_setcred(DELETE_CRED) might need it
	 */
	if (!saveGids())
		goto pError;
# endif
	if (pretc != PAM_SUCCESS) {
		logError( "pam_setcred() for %s failed: %s\n",
		          curuser, pam_strerror( pamh, pretc ) );
		resetGids();
		return 0;
	}

	removeSession = 1; /* set it first - same as above */
	pretc = pam_open_session( pamh, 0 );
	reInitErrorLog();
	if (pretc != PAM_SUCCESS) {
		logError( "pam_open_session() for %s failed: %s\n",
		          curuser, pam_strerror( pamh, pretc ) );
		resetGids();
		return 0;
	}

	/* we don't want sessreg and the startup/reset scripts run with user
	   credentials. unfortunately, we can reset only the gids. */
	resetGids();

# define D_LOGIN_SETGROUP LOGIN_SETGROUP
#else /* USE_PAM */
# define D_LOGIN_SETGROUP 0
#endif /* USE_PAM */

	removeAuth = 1;
	chownCtrl( &td->ctrl, curuid );
	endpwent();
#if !defined(USE_PAM) && defined(USESHADOW) && !defined(_AIX)
	endspent();
#endif
	ctltalk.pipe = &ctlpipe;
	ASPrintf( &buf, "sub-daemon for display %s", td->name );
	ASPrintf( &buf2, "client for display %s", td->name );
	switch (gFork( &ctlpipe, buf, buf2, 0, 0, mstrtalk.pipe, pid )) {
	case 0:

		gCloseOnExec( ctltalk.pipe );
		if (Setjmp( ctltalk.errjmp ))
			exit( 1 );

		gCloseOnExec( mstrtalk.pipe );
		if (Setjmp( mstrtalk.errjmp ))
			goto cError;

#ifndef NOXDMTITLE
		setproctitle( "%s'", td->name );
#endif
		strApp( &prog, " '", (char *)0 );
		reInitErrorLog();

		setsid();

		sessreg( td, getpid(), curuser, curuid );

		/* We do this here, as we want to have the session as parent. */
		switch (source( systemEnviron, td->startup, td_setup )) {
		case 0:
			break;
		case wcCompose( 0, 0, 127 ):
			goto cError;
		default: /* Explicit failure => message already displayed. */
			logError( "Startup script returned non-zero exit code\n" );
			exit( 1 );
		}

	/* Memory leaks are ok here as we exec() soon. */

#if defined(USE_PAM) || !defined(_AIX)

# ifdef USE_PAM
		/* pass in environment variables set by libpam and modules it called */
#  ifdef HAVE_PAM_GETENVLIST
		pam_env = pam_getenvlist( pamh );
		reInitErrorLog();
#  endif
		if (pam_env)
			for (; *pam_env; pam_env++)
				userEnviron = putEnv( *pam_env, userEnviron );
# endif

# ifdef HAVE_SETLOGIN
		if (setlogin( curuser ) < 0) {
			logError( "setlogin for %s failed: %m\n", curuser );
			goto cError;
		}
#  define D_LOGIN_SETLOGIN LOGIN_SETLOGIN
# else
#  define D_LOGIN_SETLOGIN 0
# endif

# if defined(USE_PAM) && defined(HAVE_INITGROUPS)
		if (!restoreGids())
			goto cError;
# endif

# ifndef HAVE_SETUSERCONTEXT

#  ifdef USE_PAM
		if (!setUid( curuser, curuid ))
			goto cError;
#  else
		if (!setUser( curuser, curuid, curgid ))
			goto cError;
#  endif

# else /* !HAVE_SETUSERCONTEXT */

		/*
		 * Destroy environment.
		 * We need to do this before setusercontext() because that may
		 * set or reset some environment variables.
		 */
		if (!(environ = initStrArr( 0 )))
			goto cError;

		/*
		 * Set the user's credentials: uid, gid, groups,
		 * environment variables, resource limits, and umask.
		 */
		if (setusercontext( lc, p, p->pw_uid,
		        LOGIN_SETALL & ~(D_LOGIN_SETGROUP|D_LOGIN_SETLOGIN) ) < 0)
		{
			logError( "setusercontext for %s failed: %m\n", curuser );
			goto cError;
		}

		for (i = 0; environ[i]; i++)
			userEnviron = putEnv( environ[i], userEnviron );

# endif /* !HAVE_SETUSERCONTEXT */

#else /* PAM || !_AIX */
		/*
		 * Set the user's credentials: uid, gid, groups,
		 * audit classes, user limits, and umask.
		 */
		if (setpcred( curuser, NULL ) == -1) {
			logError( "setpcred for %s failed: %m\n", curuser );
			goto cError;
		}

		/*
		 * Set the users process environment. Store protected variables and
		 * obtain updated user environment list. This call will initialize
		 * global 'newenv'.
		 */
		if (setpenv( curuser, PENV_INIT | PENV_ARGV | PENV_NOEXEC,
		             userEnviron, NULL ) != 0)
		{
			logError( "Cannot set %s's process environment\n", curuser );
			goto cError;
		}
		userEnviron = newenv;

#endif /* _AIX */

		/*
		 * for user-based authorization schemes,
		 * use the password to get the user's credentials.
		 */
#ifdef SECURE_RPC
		/* do like "keylogin" program */
		if (!curpass[0])
			logInfo( "No password for NIS provided.\n" );
		else {
			char netname[MAXNETNAMELEN+1], secretkey[HEXKEYBYTES+1];
			int nameret, keyret;
			int len;
			int key_set_ok = 0;
			struct key_netstarg netst;

			nameret = getnetname( netname );
			debug( "user netname: %s\n", netname );
			len = strlen( curpass );
			if (len > 8)
				bzero( curpass + 8, len - 8 );
			keyret = getsecretkey( netname, secretkey, curpass );
			debug( "getsecretkey returns %d, key length %d\n",
			       keyret, strlen( secretkey ) );
			netst.st_netname = netname;
			memcpy( netst.st_priv_key, secretkey, HEXKEYBYTES );
			memset( netst.st_pub_key, 0, HEXKEYBYTES );
			if (key_setnet( &netst ) < 0)
				debug( "Could not set secret key.\n" );
			/* is there a key, and do we have the right password? */
			if (keyret == 1) {
				if (*secretkey) {
					keyret = key_setsecret( secretkey );
					debug( "key_setsecret returns %d\n", keyret );
					if (keyret == -1)
						logError( "Failed to set NIS secret key\n" );
					else
						key_set_ok = 1;
				} else {
					/* found a key, but couldn't interpret it */
					logError( "Password incorrect for NIS principal %s\n",
					          nameret ? netname : curuser );
				}
			}
			if (!key_set_ok)
				nukeAuth( 9, "SUN-DES-1" );
			bzero( secretkey, strlen( secretkey ) );
		}
#endif
#ifdef K5AUTH
		/* do like "kinit" program */
		if (!curpass[0])
			logInfo( "No password for Kerberos5 provided.\n" );
		else
			if ((str = krb5Init( curuser, curpass, td->name )))
				userEnviron = setEnv( userEnviron, "KRB5CCNAME", str );
			else
				nukeAuth( 14, "MIT-KERBEROS-5" );
#endif /* K5AUTH */
		if (td->autoReLogin) {
			gSet( &mstrtalk );
			gSendInt( D_ReLogin );
			gSendStr( curuser );
			gSendStr( curpass );
			gSendStr( newdmrc );
		}
		if (curpass)
			bzero( curpass, strlen( curpass ) );
		setUserAuthorization( td );
		home = getEnv( userEnviron, "HOME" );
		if (home && chdir( home ) < 0) {
			logError( "Cannot chdir to %s's home %s: %m\n", curuser, home );
			sendStr( V_MSG_ERR, "Cannot enter home directory. Using /.\n" );
			chdir( "/" );
			userEnviron = setEnv( userEnviron, "HOME", "/" );
			home = 0;
		}
		if (home || td->clientLogFile[0] == '/') {
			if (!createClientLog( td->clientLogFile )) {
				logWarn( "Session log file according to %s cannot be created: %m\n",
				         td->clientLogFile );
				goto tmperr;
			}
		} else {
		  tmperr:
			if (!createClientLog( td->clientLogFallback ))
				logError( "Fallback session log file according to %s cannot be created: %m\n",
				          td->clientLogFallback );
			/* Could inform the user, but I guess this is only confusing. */
		}
		if (!*dmrcDir)
			mergeSessionArgs( home != 0 );
		if (!(desksess = iniEntry( curdmrc, "Desktop", "Session", 0 )))
			desksess = "failsafe"; /* only due to OOM */
		gSet( &mstrtalk );
		gSendInt( D_User );
		gSendInt( curuid );
		gSendStr( curuser );
		gSendStr( desksess );
		close( mstrtalk.pipe->fd.w );
		userEnviron = setEnv( userEnviron, "DESKTOP_SESSION", desksess );
		for (i = 0; td->sessionsDirs[i]; i++) {
			fname = 0;
			if (strApp( &fname, td->sessionsDirs[i], "/", desksess, ".desktop", (char *)0 )) {
				if ((str = iniLoad( fname ))) {
					if (!strCmp( iniEntry( str, "Desktop Entry", "Hidden", 0 ), "true" ) ||
					    !(sessargs = iniEntry( str, "Desktop Entry", "Exec", 0 )))
						sessargs = "";
					free( str );
					free( fname );
					goto gotit;
				}
				free( fname );
			}
		}
		if (!strcmp( desksess, "failsafe" ) ||
		    !strcmp( desksess, "default" ) ||
		    !strcmp( desksess, "custom" ))
			sessargs = desksess;
		else
			sessargs = "";
	  gotit:
		if (!(argv = parseArgs( (char **)0, td->session )) ||
		    !(argv = addStrArr( argv, sessargs, -1 )))
			exit( 1 );
		if (argv[0] && *argv[0]) {
			debug( "executing session %\"[s\n", argv );
			execute( argv, userEnviron );
			logError( "Session %\"s execution failed: %m\n", argv[0] );
		} else
			logError( "Session has no command/arguments\n" );
		failsafeArgv[0] = td->failsafeClient;
		failsafeArgv[1] = 0;
		execute( failsafeArgv, userEnviron );
		logError( "Failsafe client %\"s execution failed: %m\n",
		          failsafeArgv[0] );
	  cError:
		sendStr( V_MSG_ERR, 0 );
		exit( 1 );
	case -1:
		free( buf );
		return 0;
	}
	debug( "StartSession, fork succeeded %d\n", *pid );
	free( buf );

	gSet( &ctltalk );
	if (!Setjmp( ctltalk.errjmp ))
		while (gRecvCmd( &i )) {
			buf = gRecvStr();
			displayStr( i, buf );
			free( buf );
			gSet( &ctltalk );
			gSendInt( 0 );
		}
	gClosen( ctltalk.pipe );
	finishGreet();

	return 1;
}