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; }
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); } } }
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 */ }
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; } }
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; }