diff options
author | Kaleb Keithley <kaleb@freedesktop.org> | 2003-11-14 15:54:53 +0000 |
---|---|---|
committer | Kaleb Keithley <kaleb@freedesktop.org> | 2003-11-14 15:54:53 +0000 |
commit | df3e1beed5bbb631975127133464b7e24fc38497 (patch) | |
tree | 6291fb1c51fb790c2f236249b5f44eb9bedfdc7b |
R6.6 is the Xorg base-lineXORG-MAIN
-rw-r--r-- | Chooser.ad | 44 | ||||
-rw-r--r-- | access.c | 748 | ||||
-rw-r--r-- | auth.c | 1278 | ||||
-rw-r--r-- | choose.c | 508 | ||||
-rw-r--r-- | chooser.c | 1005 | ||||
-rw-r--r-- | config/GiveConsole | 10 | ||||
-rw-r--r-- | config/README | 11 | ||||
-rw-r--r-- | config/TakeConsole | 7 | ||||
-rw-r--r-- | config/Xaccess | 68 | ||||
-rw-r--r-- | config/Xservers.fs | 11 | ||||
-rw-r--r-- | config/Xservers.ws.cpp | 13 | ||||
-rw-r--r-- | config/Xsetup_0 | 3 | ||||
-rw-r--r-- | config/xdm-config.cpp | 19 | ||||
-rw-r--r-- | daemon.c | 146 | ||||
-rw-r--r-- | dm.c | 855 | ||||
-rw-r--r-- | dm.h | 360 | ||||
-rw-r--r-- | dpylist.c | 274 | ||||
-rw-r--r-- | error.c | 195 | ||||
-rw-r--r-- | file.c | 258 | ||||
-rw-r--r-- | genauth.c | 228 | ||||
-rw-r--r-- | greet.h | 187 | ||||
-rw-r--r-- | greeter/Login.c | 904 | ||||
-rw-r--r-- | greeter/Login.h | 106 | ||||
-rw-r--r-- | greeter/LoginP.h | 96 | ||||
-rw-r--r-- | greeter/greet.c | 410 | ||||
-rw-r--r-- | greeter/verify.c | 173 | ||||
-rw-r--r-- | krb5auth.c | 266 | ||||
-rw-r--r-- | mitauth.c | 91 | ||||
-rw-r--r-- | netaddr.c | 242 | ||||
-rw-r--r-- | policy.c | 162 | ||||
-rw-r--r-- | protodpy.c | 173 | ||||
-rw-r--r-- | reset.c | 116 | ||||
-rw-r--r-- | resource.c | 472 | ||||
-rw-r--r-- | rpcauth.c | 88 | ||||
-rw-r--r-- | server.c | 419 | ||||
-rw-r--r-- | session.c | 878 | ||||
-rw-r--r-- | socket.c | 123 | ||||
-rw-r--r-- | streams.c | 147 | ||||
-rw-r--r-- | util.c | 263 | ||||
-rw-r--r-- | xdm.man.cpp | 1258 | ||||
-rw-r--r-- | xdmauth.c | 301 | ||||
-rw-r--r-- | xdmcp.c | 1226 | ||||
-rw-r--r-- | xdmshell.c | 222 |
43 files changed, 14364 insertions, 0 deletions
diff --git a/Chooser.ad b/Chooser.ad new file mode 100644 index 0000000..4dc4c74 --- /dev/null +++ b/Chooser.ad @@ -0,0 +1,44 @@ +*ShapeStyle: Oval +*cursor: left_ptr +*allowShellResize: true +*label.label: XDMCP Host Menu +*label.borderWidth: 0 +*label.skipAdjust: true +*paned*showGrip: false +!*viewport.horizDistance: 20 +!*viewport.height: 200 +*viewport.width: 400 +*viewport.height: 50 +*viewport.allowVert: true +*viewport.fromVert: label +*viewport.resizeable: true +*viewport.allowResize: true + +*list.translations: #override \ + <BtnDown>: Set() CheckWilling() \n\ + <BtnUp>(2): Accept() +*list.defaultColumns: 1 +*list.forceFolumns: true + +*box.skipAdjust: true +*cancel.fromHoriz: viewport +*cancel.fromVert: label +*cancel.vertDistance: 100 +*cancel.bottom: ChainBottom +*cancel.top: ChainBottom +*cancel.left: ChainRight +*cancel.right: ChainRight + +*accept.fromHoriz: viewport +*accept.fromVert: cancel +*accept.bottom: ChainBottom +*accept.top: ChainBottom +*accept.left: ChainRight +*accept.right: ChainRight + +*cancel.translations: #override \ + <BtnUp>: Cancel() unset() +*accept.translations: #override \ + <BtnUp>: Accept() unset() +*ping.translations: #override \ + <BtnUp>: Ping() unset() diff --git a/access.c b/access.c new file mode 100644 index 0000000..2328ba6 --- /dev/null +++ b/access.c @@ -0,0 +1,748 @@ +/* + * $Xorg: access.c,v 1.5 2001/02/09 02:05:40 xorgcvs Exp $ + * +Copyright 1990, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + * + * Author: Keith Packard, MIT X Consortium + */ + +/* + * Access control for XDMCP - keep a database of allowable display addresses + * and (potentially) a list of hosts to send ForwardQuery packets to + */ + +# include "dm.h" + +#ifdef XDMCP + +# include <X11/Xos.h> +# include <X11/Xdmcp.h> +# include <X11/X.h> +# include <stdio.h> +# include <ctype.h> +# include <netinet/in.h> +# include <netdb.h> +# include <sys/socket.h> + +#define ALIAS_CHARACTER '%' +#define NEGATE_CHARACTER '!' +#define CHOOSER_STRING "CHOOSER" +#define BROADCAST_STRING "BROADCAST" + +#define HOST_ALIAS 0 +#define HOST_ADDRESS 1 +#define HOST_BROADCAST 2 +#define HOST_CHOOSER 3 + +typedef struct _hostEntry { + struct _hostEntry *next; + int type; + union _hostOrAlias { + char *aliasName; + ARRAY8 hostAddress; + } entry; +} HostEntry; + +#define DISPLAY_ALIAS 0 +#define DISPLAY_PATTERN 1 +#define DISPLAY_ADDRESS 2 + +typedef struct _displayEntry { + struct _displayEntry *next; + int type; + int notAllowed; + int chooser; + union _displayType { + char *aliasName; + char *displayPattern; + struct _display { + ARRAY8 clientAddress; + CARD16 connectionType; + } displayAddress; + } entry; + HostEntry *hosts; +} DisplayEntry; + +static DisplayEntry *database; + +static ARRAY8 localAddress; + +ARRAY8Ptr +getLocalAddress () +{ + static int haveLocalAddress; + + if (!haveLocalAddress) + { + struct hostent *hostent; + + hostent = gethostbyname (localHostname()); + XdmcpAllocARRAY8 (&localAddress, hostent->h_length); + memmove( localAddress.data, hostent->h_addr, hostent->h_length); + } + return &localAddress; +} + +static void +FreeHostEntry (h) + HostEntry *h; +{ + switch (h->type) { + case HOST_ALIAS: + free (h->entry.aliasName); + break; + case HOST_ADDRESS: + XdmcpDisposeARRAY8 (&h->entry.hostAddress); + break; + case HOST_CHOOSER: + break; + } + free ((char *) h); +} + +static void +FreeDisplayEntry (d) + DisplayEntry *d; +{ + HostEntry *h, *next; + switch (d->type) { + case DISPLAY_ALIAS: + free (d->entry.aliasName); + break; + case DISPLAY_PATTERN: + free (d->entry.displayPattern); + break; + case DISPLAY_ADDRESS: + XdmcpDisposeARRAY8 (&d->entry.displayAddress); + break; + } + for (h = d->hosts; h; h = next) { + next = h->next; + FreeHostEntry (h); + } + free ((char *) d); +} + +static void +FreeAccessDatabase () +{ + DisplayEntry *d, *next; + + for (d = database; d; d = next) + { + next = d->next; + FreeDisplayEntry (d); + } + database = 0; +} + +#define WORD_LEN 256 +static char wordBuffer[WORD_LEN]; +static int nextIsEOF; + +static char * +ReadWord (file, EOFatEOL) + FILE *file; + int EOFatEOL; +{ + int c; + char *wordp; + int quoted; + + wordp = wordBuffer; + if (nextIsEOF) + { + nextIsEOF = FALSE; + return NULL; + } + quoted = FALSE; + for (;;) { + c = getc (file); + switch (c) { + case '#': + if (quoted) + { + *wordp++ = c; + break; + } + while ((c = getc (file)) != EOF && c != '\n') + ; + case '\n': + case EOF: + if (c == EOF || (EOFatEOL && !quoted)) + { + ungetc (c, file); + if (wordp == wordBuffer) + return NULL; + *wordp = '\0'; + nextIsEOF = TRUE; + return wordBuffer; + } + case ' ': + case '\t': + if (wordp != wordBuffer) + { + ungetc (c, file); + *wordp = '\0'; + return wordBuffer; + } + break; + case '\\': + if (!quoted) + { + quoted = TRUE; + continue; + } + default: + *wordp++ = c; + break; + } + quoted = FALSE; + } +} + +static HostEntry * +ReadHostEntry (file) + FILE *file; +{ + char *hostOrAlias; + HostEntry *h; + struct hostent *hostent; + +tryagain: + hostOrAlias = ReadWord (file, TRUE); + if (!hostOrAlias) + return NULL; + h = (HostEntry *) malloc (sizeof (DisplayEntry)); + if (*hostOrAlias == ALIAS_CHARACTER) + { + h->type = HOST_ALIAS; + h->entry.aliasName = malloc (strlen (hostOrAlias) + 1); + if (!h->entry.aliasName) { + free ((char *) h); + return NULL; + } + strcpy (h->entry.aliasName, hostOrAlias); + } + else if (!strcmp (hostOrAlias, CHOOSER_STRING)) + { + h->type = HOST_CHOOSER; + } + else if (!strcmp (hostOrAlias, BROADCAST_STRING)) + { + h->type = HOST_BROADCAST; + } + else + { + h->type = HOST_ADDRESS; + hostent = gethostbyname (hostOrAlias); + if (!hostent) + { + Debug ("No such host %s\n", hostOrAlias); + LogError ("Access file \"%s\", host \"%s\" not found\n", accessFile, hostOrAlias); + free ((char *) h); + goto tryagain; + } + if (!XdmcpAllocARRAY8 (&h->entry.hostAddress, hostent->h_length)) + { + LogOutOfMem ("ReadHostEntry\n"); + free ((char *) h); + return NULL; + } + memmove( h->entry.hostAddress.data, hostent->h_addr, hostent->h_length); + } + return h; +} + +static int +HasGlobCharacters (s) + char *s; +{ + for (;;) + switch (*s++) { + case '?': + case '*': + return 1; + case '\0': + return 0; + } +} + +static DisplayEntry * +ReadDisplayEntry (file) + FILE *file; +{ + char *displayOrAlias; + DisplayEntry *d; + struct _display *display; + HostEntry *h, **prev; + struct hostent *hostent; + + displayOrAlias = ReadWord (file, FALSE); + if (!displayOrAlias) + return NULL; + d = (DisplayEntry *) malloc (sizeof (DisplayEntry)); + d->notAllowed = 0; + d->chooser = 0; + if (*displayOrAlias == ALIAS_CHARACTER) + { + d->type = DISPLAY_ALIAS; + d->entry.aliasName = malloc (strlen (displayOrAlias) + 1); + if (!d->entry.aliasName) + { + free ((char *) d); + return NULL; + } + strcpy (d->entry.aliasName, displayOrAlias); + } + else + { + if (*displayOrAlias == NEGATE_CHARACTER) + { + d->notAllowed = 1; + ++displayOrAlias; + } + if (HasGlobCharacters (displayOrAlias)) + { + d->type = DISPLAY_PATTERN; + d->entry.displayPattern = malloc (strlen (displayOrAlias) + 1); + if (!d->entry.displayPattern) + { + free ((char *) d); + return NULL; + } + strcpy (d->entry.displayPattern, displayOrAlias); + } + else + { + if ((hostent = gethostbyname (displayOrAlias)) == NULL) + { + LogError ("Access file %s, display %s unknown\n", accessFile, displayOrAlias); + free ((char *) d); + return NULL; + } + d->type = DISPLAY_ADDRESS; + display = &d->entry.displayAddress; + if (!XdmcpAllocARRAY8 (&display->clientAddress, hostent->h_length)) + { + free ((char *) d); + return NULL; + } + memmove( display->clientAddress.data, hostent->h_addr, hostent->h_length); + switch (hostent->h_addrtype) + { +#ifdef AF_UNIX + case AF_UNIX: + display->connectionType = FamilyLocal; + break; +#endif +#ifdef AF_INET + case AF_INET: + display->connectionType = FamilyInternet; + break; +#endif +#ifdef AF_DECnet + case AF_DECnet: + display->connectionType = FamilyDECnet; + break; +#endif + default: + display->connectionType = FamilyLocal; + break; + } + } + } + prev = &d->hosts; + while ((h = ReadHostEntry (file))) + { + if (h->type == HOST_CHOOSER) + { + FreeHostEntry (h); + d->chooser = 1; + } else { + *prev = h; + prev = &h->next; + } + } + *prev = NULL; + return d; +} + +static +ReadAccessDatabase (file) + FILE *file; +{ + DisplayEntry *d, **prev; + + prev = &database; + while ((d = ReadDisplayEntry (file))) + { + *prev = d; + prev = &d->next; + } + *prev = NULL; +} + +ScanAccessDatabase () +{ + FILE *datafile; + + FreeAccessDatabase (); + if (*accessFile) + { + datafile = fopen (accessFile, "r"); + if (!datafile) + { + LogError ("Cannot open access control file %s, no XDMCP reqeusts will be granted\n", accessFile); + return 0; + } + ReadAccessDatabase (datafile); + fclose (datafile); + } + return 1; +} + +/* + * calls the given function for each valid indirect entry. Returns TRUE if + * the local host exists on any of the lists, else FALSE + */ + +#define MAX_DEPTH 32 + +static int indirectAlias (); + +static int +scanHostlist (h, clientAddress, connectionType, function, closure, depth, broadcast) + HostEntry *h; + ARRAY8Ptr clientAddress; + CARD16 connectionType; + int (*function)(); + char *closure; + int depth; + int broadcast; +{ + int haveLocalhost = 0; + + for (; h; h = h->next) + { + switch (h->type) { + case HOST_ALIAS: + if (indirectAlias (h->entry.aliasName, clientAddress, + connectionType, function, closure, depth, + broadcast)) + haveLocalhost = 1; + break; + case HOST_ADDRESS: + if (XdmcpARRAY8Equal (getLocalAddress(), &h->entry.hostAddress)) + haveLocalhost = 1; + else if (function) + (*function) (connectionType, &h->entry.hostAddress, closure); + break; + case HOST_BROADCAST: + if (broadcast) + { + ARRAY8 temp; + + if (function) + { + temp.data = (BYTE *) BROADCAST_STRING; + temp.length = strlen ((char *)temp.data); + (*function) (connectionType, &temp, closure); + } + } + break; + } + } + return haveLocalhost; +} + +/* Returns non-0 iff string is matched by pattern. Does case folding. + */ +static int +patternMatch (string, pattern) + char *string, *pattern; +{ + int p, s; + + if (!string) + string = ""; + + for (;;) + { + s = *string++; + switch (p = *pattern++) { + case '*': + if (!*pattern) + return 1; + for (string--; *string; string++) + if (patternMatch (string, pattern)) + return 1; + return 0; + case '?': + if (s == '\0') + return 0; + break; + case '\0': + return s == '\0'; + case '\\': + p = *pattern++; + /* fall through */ + default: + if (isupper(p)) p = tolower(p); + if (isupper(s)) s = tolower(s); + if (p != s) + return 0; + } + } +} + +static int +indirectAlias (alias, clientAddress, connectionType, function, closure, depth, + broadcast) + char *alias; + ARRAY8Ptr clientAddress; + CARD16 connectionType; + int (*function)(); + char *closure; + int depth; + int broadcast; +{ + DisplayEntry *d; + int haveLocalhost = 0; + + if (depth == MAX_DEPTH) + return 0; + for (d = database; d; d = d->next) + { + if (d->type != DISPLAY_ALIAS || !patternMatch (alias, d->entry.aliasName)) + continue; + if (scanHostlist (d->hosts, clientAddress, connectionType, + function, closure, depth + 1, broadcast)) + { + haveLocalhost = 1; + } + } + return haveLocalhost; +} + +ARRAY8Ptr IndirectChoice (); + +int ForEachMatchingIndirectHost (clientAddress, connectionType, function, closure) + ARRAY8Ptr clientAddress; + CARD16 connectionType; + int (*function)(); + char *closure; +{ + int haveLocalhost = 0; + DisplayEntry *d; + char *clientName = NULL, *NetworkAddressToHostname (); + + for (d = database; d; d = d->next) + { + switch (d->type) { + case DISPLAY_ALIAS: + continue; + case DISPLAY_PATTERN: + if (!clientName) + clientName = NetworkAddressToHostname (connectionType, + clientAddress); + if (!patternMatch (clientName, d->entry.displayPattern)) + continue; + break; + case DISPLAY_ADDRESS: + if (d->entry.displayAddress.connectionType != connectionType || + !XdmcpARRAY8Equal (&d->entry.displayAddress.clientAddress, + clientAddress)) + { + continue; + } + break; + } + if (!d->hosts) + continue; + if (d->notAllowed) + break; + if (d->chooser) + { + ARRAY8Ptr choice; + + choice = IndirectChoice (clientAddress, connectionType); + if (!choice || XdmcpARRAY8Equal (getLocalAddress(), choice)) + haveLocalhost = 1; + else + (*function) (connectionType, choice, closure); + } + else if (scanHostlist (d->hosts, clientAddress, connectionType, + function, closure, 0, FALSE)) + { + haveLocalhost = 1; + } + break; + } + if (clientName) + free (clientName); + return haveLocalhost; +} + +int UseChooser (clientAddress, connectionType) + ARRAY8Ptr clientAddress; + CARD16 connectionType; +{ + DisplayEntry *d; + char *clientName = NULL, *NetworkAddressToHostname (); + + for (d = database; d; d = d->next) + { + switch (d->type) { + case DISPLAY_ALIAS: + continue; + case DISPLAY_PATTERN: + if (!clientName) + clientName = NetworkAddressToHostname (connectionType, + clientAddress); + if (!patternMatch (clientName, d->entry.displayPattern)) + continue; + break; + case DISPLAY_ADDRESS: + if (d->entry.displayAddress.connectionType != connectionType || + !XdmcpARRAY8Equal (&d->entry.displayAddress.clientAddress, + clientAddress)) + { + continue; + } + break; + } + if (!d->hosts) + continue; + if (d->notAllowed) + break; + if (d->chooser && !IndirectChoice (clientAddress, connectionType)) { + if (clientName) + free (clientName); + return 1; + } + break; + } + if (clientName) + free (clientName); + return 0; +} + +void ForEachChooserHost (clientAddress, connectionType, function, closure) + ARRAY8Ptr clientAddress; + CARD16 connectionType; + int (*function)(); + char *closure; +{ + int haveLocalhost = 0; + DisplayEntry *d; + char *clientName = NULL, *NetworkAddressToHostname (); + + for (d = database; d; d = d->next) + { + switch (d->type) { + case DISPLAY_ALIAS: + continue; + case DISPLAY_PATTERN: + if (!clientName) + clientName = NetworkAddressToHostname (connectionType, + clientAddress); + if (!patternMatch (clientName, d->entry.displayPattern)) + continue; + break; + case DISPLAY_ADDRESS: + if (d->entry.displayAddress.connectionType != connectionType || + !XdmcpARRAY8Equal (&d->entry.displayAddress.clientAddress, + clientAddress)) + { + continue; + } + break; + } + if (!d->hosts) + continue; + if (d->notAllowed) + break; + if (!d->chooser) + break; + if (scanHostlist (d->hosts, clientAddress, connectionType, + function, closure, 0, TRUE)) + { + haveLocalhost = 1; + } + break; + } + if (clientName) + free (clientName); + if (haveLocalhost) + (*function) (connectionType, getLocalAddress(), closure); +} + +/* + * returns TRUE if the given client is acceptable to the local host. The + * given display client is acceptable if it occurs without a host list. + */ + +int AcceptableDisplayAddress (clientAddress, connectionType, type) + ARRAY8Ptr clientAddress; + CARD16 connectionType; + xdmOpCode type; +{ + DisplayEntry *d; + char *clientName = NULL, *NetworkAddressToHostname (); + + if (!*accessFile) + return 1; + if (type == INDIRECT_QUERY) + return 1; + for (d = database; d; d = d->next) + { + if (d->hosts) + continue; + switch (d->type) { + case DISPLAY_ALIAS: + continue; + case DISPLAY_PATTERN: + if (!clientName) + clientName = NetworkAddressToHostname (connectionType, + clientAddress); + if (!patternMatch (clientName, d->entry.displayPattern)) + continue; + break; + case DISPLAY_ADDRESS: + if (d->entry.displayAddress.connectionType != connectionType || + !XdmcpARRAY8Equal (&d->entry.displayAddress.clientAddress, + clientAddress)) + { + continue; + } + break; + } + break; + } + if (clientName) + free (clientName); + return (d != 0) && (d->notAllowed == 0); +} + +#endif /* XDMCP */ @@ -0,0 +1,1278 @@ +/* $Xorg: auth.c,v 1.5 2001/02/09 02:05:40 xorgcvs Exp $ */ +/* + +Copyright 1988, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall +not be used in advertising or otherwise to promote the sale, use or +other dealings in this Software without prior written authorization +from The Open Group. + +*/ + +/* + * xdm - display manager daemon + * Author: Keith Packard, MIT X Consortium + * + * auth.c + * + * maintain the authorization generation daemon + */ + +#include "dm.h" +#include <X11/X.h> +#include <sys/types.h> +#include <sys/stat.h> + +#include <errno.h> +#ifdef X_NOT_STDC_ENV +extern int errno; +#endif + +#include <sys/socket.h> +#ifndef ESIX +# include <sys/ioctl.h> +#endif /* !ESIX */ + +#ifdef TCPCONN +# include <netinet/in.h> +#endif +#ifdef DNETCONN +# include <netdnet/dn.h> +# include <netdnet/dnetdb.h> +#endif + +#if (defined(_POSIX_SOURCE) && !defined(AIXV3)) || defined(hpux) || defined(USG) || defined(SVR4) +#define NEED_UTSNAME +#include <sys/utsname.h> +#endif + +#if defined(SYSV) && defined(SYSV386) +# include <sys/stream.h> +# ifdef ISC +# include <sys/sioctl.h> +# endif /* ISC */ +# ifdef ESIX +# include <lan/net_ioctl.h> +# endif /* ESIX */ +#endif /* SYSV386 */ + +#ifdef SVR4 +# include <netdb.h> +# include <sys/sockio.h> +#ifdef USL +# include <sys/stropts.h> +#endif +#endif +#ifdef __convex__ +# include <sync/queue.h> +# include <sync/sema.h> +#endif +#include <net/if.h> + +extern int MitInitAuth (); +extern Xauth *MitGetAuth (); + +#ifdef HASXDMAUTH +extern int XdmInitAuth (); +extern Xauth *XdmGetAuth (); +#ifdef XDMCP +extern void XdmGetXdmcpAuth (); +#else +#define XdmGetXdmcpAuth NULL +#endif +#endif + +#ifdef SECURE_RPC +extern int SecureRPCInitAuth (); +extern Xauth *SecureRPCGetAuth (); +#endif + +#ifdef K5AUTH +extern int Krb5InitAuth (); +extern Xauth *Krb5GetAuth (); +#endif + +struct AuthProtocol { + unsigned short name_length; + char *name; + int (*InitAuth)(); + Xauth *(*GetAuth)(); + void (*GetXdmcpAuth)(); + int inited; +}; + +static struct AuthProtocol AuthProtocols[] = { +{ (unsigned short) 18, "MIT-MAGIC-COOKIE-1", + MitInitAuth, MitGetAuth, NULL +}, +#ifdef HASXDMAUTH +{ (unsigned short) 19, "XDM-AUTHORIZATION-1", + XdmInitAuth, XdmGetAuth, XdmGetXdmcpAuth, +}, +#endif +#ifdef SECURE_RPC +{ (unsigned short) 9, "SUN-DES-1", + SecureRPCInitAuth, SecureRPCGetAuth, NULL, +}, +#endif +#ifdef K5AUTH +{ (unsigned short) 14, "MIT-KERBEROS-5", + Krb5InitAuth, Krb5GetAuth, NULL, +}, +#endif +}; + +#define NUM_AUTHORIZATION (sizeof (AuthProtocols) / sizeof (AuthProtocols[0])) + +static struct AuthProtocol * +findProtocol (name_length, name) + unsigned short name_length; + char *name; +{ + int i; + + for (i = 0; i < NUM_AUTHORIZATION; i++) + if (AuthProtocols[i].name_length == name_length && + memcmp(AuthProtocols[i].name, name, name_length) == 0) + { + return &AuthProtocols[i]; + } + return (struct AuthProtocol *) 0; +} + +ValidAuthorization (name_length, name) + unsigned short name_length; + char *name; +{ + if (findProtocol (name_length, name)) + return TRUE; + return FALSE; +} + +static Xauth * +GenerateAuthorization (name_length, name) +unsigned short name_length; +char *name; +{ + struct AuthProtocol *a; + Xauth *auth = 0; + int i; + + Debug ("GenerateAuthorization %*.*s\n", + name_length, name_length, name); + a = findProtocol (name_length, name); + if (a) + { + if (!a->inited) + { + (*a->InitAuth) (name_length, name); + a->inited = TRUE; + } + auth = (*a->GetAuth) (name_length, name); + if (auth) + { + Debug ("Got 0x%x (%d %*.*s) ", auth, + auth->name_length, auth->name_length, + auth->name_length, auth->name); + for (i = 0; i < (int)auth->data_length; i++) + Debug (" %02x", auth->data[i] & 0xff); + Debug ("\n"); + } + else + Debug ("Got (null)\n"); + } + else + { + Debug ("Unknown authorization %*.*s\n", name_length, name_length, name); + } + return auth; +} + +#ifdef XDMCP + +SetProtoDisplayAuthorization (pdpy, + authorizationNameLen, authorizationName) + struct protoDisplay *pdpy; + unsigned short authorizationNameLen; + char *authorizationName; +{ + struct AuthProtocol *a; + Xauth *auth; + + a = findProtocol (authorizationNameLen, authorizationName); + pdpy->xdmcpAuthorization = pdpy->fileAuthorization = 0; + if (a) + { + if (!a->inited) + { + (*a->InitAuth) (authorizationNameLen, authorizationName); + a->inited = TRUE; + } + if (a->GetXdmcpAuth) + { + (*a->GetXdmcpAuth) (pdpy, authorizationNameLen, authorizationName); + auth = pdpy->xdmcpAuthorization; + } + else + { + auth = (*a->GetAuth) (authorizationNameLen, authorizationName); + pdpy->fileAuthorization = auth; + pdpy->xdmcpAuthorization = 0; + } + if (auth) + Debug ("Got 0x%x (%d %*.*s)\n", auth, + auth->name_length, auth->name_length, + auth->name_length, auth->name); + else + Debug ("Got (null)\n"); + } +} + +#endif /* XDMCP */ + +void +CleanUpFileName (src, dst, len) + char *src, *dst; + int len; +{ + while (*src) { + if (--len <= 0) + break; + switch (*src & 0x7f) + { + case '/': + *dst++ = '_'; + break; + case '-': + *dst++ = '.'; + break; + default: + *dst++ = (*src & 0x7f); + } + ++src; + } + *dst = '\0'; +} + +static char authdir1[] = "authdir"; +static char authdir2[] = "authfiles"; + +static +MakeServerAuthFile (d) + struct display *d; +{ + int len; +#ifdef SYSV +#define NAMELEN 14 +#else +#define NAMELEN 255 +#endif + char cleanname[NAMELEN]; + int r; + struct stat statb; + + if (d->clientAuthFile && *d->clientAuthFile) + len = strlen (d->clientAuthFile) + 1; + else + { + CleanUpFileName (d->name, cleanname, NAMELEN - 8); + len = strlen (authDir) + strlen (authdir1) + strlen (authdir2) + + strlen (cleanname) + 14; + } + if (d->authFile) + free (d->authFile); + d->authFile = malloc ((unsigned) len); + if (!d->authFile) + return FALSE; + if (d->clientAuthFile && *d->clientAuthFile) + strcpy (d->authFile, d->clientAuthFile); + else + { + sprintf (d->authFile, "%s/%s", authDir, authdir1); + r = stat(d->authFile, &statb); + if (r == 0) { + if (statb.st_uid != 0) + (void) chown(d->authFile, 0, statb.st_gid); + if ((statb.st_mode & 0077) != 0) + (void) chmod(d->authFile, statb.st_mode & 0700); + } else { + if (errno == ENOENT) + r = mkdir(d->authFile, 0700); + if (r < 0) { + free (d->authFile); + d->authFile = NULL; + return FALSE; + } + } + sprintf (d->authFile, "%s/%s/%s", authDir, authdir1, authdir2); + r = mkdir(d->authFile, 0700); + if (r < 0 && errno != EEXIST) { + free (d->authFile); + d->authFile = NULL; + return FALSE; + } + sprintf (d->authFile, "%s/%s/%s/A%s-XXXXXX", + authDir, authdir1, authdir2, cleanname); + (void) mktemp (d->authFile); + } + return TRUE; +} + +SaveServerAuthorizations (d, auths, count) + struct display *d; + Xauth **auths; + int count; +{ + FILE *auth_file; + int mask; + int ret; + int i; + + mask = umask (0077); + if (!d->authFile && !MakeServerAuthFile (d)) + return FALSE; + (void) unlink (d->authFile); + auth_file = fopen (d->authFile, "w"); + umask (mask); + if (!auth_file) { + Debug ("Can't creat auth file %s\n", d->authFile); + LogError ("Cannot open server authorization file %s\n", d->authFile); + free (d->authFile); + d->authFile = NULL; + ret = FALSE; + } + else + { + Debug ("File: %s auth: %x\n", d->authFile, auths); + ret = TRUE; + for (i = 0; i < count; i++) + { + /* + * User-based auths may not have data until + * a user logs in. In which case don't write + * to the auth file so xrdb and setup programs don't fail. + */ + if (auths[i]->data_length > 0) + if (!XauWriteAuth (auth_file, auths[i]) || + fflush (auth_file) == EOF) + { + LogError ("Cannot write server authorization file %s\n", + d->authFile); + ret = FALSE; + free (d->authFile); + d->authFile = NULL; + } + } + fclose (auth_file); + } + return ret; +} + +void +SetLocalAuthorization (d) + struct display *d; +{ + Xauth *auth, **auths; + int i, j; + + if (d->authorizations) + { + for (i = 0; i < d->authNum; i++) + XauDisposeAuth (d->authorizations[i]); + free ((char *) d->authorizations); + d->authorizations = (Xauth **) NULL; + d->authNum = 0; + } + if (!d->authNames) + return; + for (i = 0; d->authNames[i]; i++) + ; + d->authNameNum = i; + if (d->authNameLens) + free ((char *) d->authNameLens); + d->authNameLens = (unsigned short *) malloc + (d->authNameNum * sizeof (unsigned short)); + if (!d->authNameLens) + return; + for (i = 0; i < d->authNameNum; i++) + d->authNameLens[i] = strlen (d->authNames[i]); + auths = (Xauth **) malloc (d->authNameNum * sizeof (Xauth *)); + if (!auths) + return; + j = 0; + for (i = 0; i < d->authNameNum; i++) + { + auth = GenerateAuthorization (d->authNameLens[i], d->authNames[i]); + if (auth) + auths[j++] = auth; + } + if (SaveServerAuthorizations (d, auths, j)) + { + d->authorizations = auths; + d->authNum = j; + } + else + { + for (i = 0; i < j; i++) + XauDisposeAuth (auths[i]); + free ((char *) auths); + } +} + +/* + * Set the authorization to use for xdm's initial connection + * to the X server. Cannot use user-based authorizations + * because no one has logged in yet, so we don't have any + * user credentials. + * Well, actually we could use SUN-DES-1 because we tell the server + * to allow root in. This is bogus and should be fixed. + */ +SetAuthorization (d) + struct display *d; +{ + register Xauth **auth = d->authorizations; + int i; + + for (i = 0; i < d->authNum; i++) + { + if (auth[i]->name_length == 9 && + memcmp(auth[i]->name, "SUN-DES-1", 9) == 0) + continue; + if (auth[i]->name_length == 14 && + memcmp(auth[i]->name, "MIT-KERBEROS-5", 14) == 0) + continue; + XSetAuthorization (auth[i]->name, (int) auth[i]->name_length, + auth[i]->data, (int) auth[i]->data_length); + } +} + +static +openFiles (name, new_name, oldp, newp) +char *name, *new_name; +FILE **oldp, **newp; +{ + int mask; + + strcpy (new_name, name); + strcat (new_name, "-n"); + mask = umask (0077); + (void) unlink (new_name); + *newp = fopen (new_name, "w"); + (void) umask (mask); + if (!*newp) { + Debug ("can't open new file %s\n", new_name); + return 0; + } + *oldp = fopen (name, "r"); + Debug ("opens succeeded %s %s\n", name, new_name); + return 1; +} + +static +binaryEqual (a, b, len) +char *a, *b; +unsigned short len; +{ + while (len-- > 0) + if (*a++ != *b++) + return 0; + return 1; +} + +static +dumpBytes (len, data) +unsigned short len; +char *data; +{ + unsigned short i; + + Debug ("%d: ", len); + for (i = 0; i < len; i++) + Debug ("%02x ", data[i] & 0377); + Debug ("\n"); +} + +static +dumpAuth (auth) + Xauth *auth; +{ + Debug ("family: %d\n", auth->family); + Debug ("addr: "); + dumpBytes (auth->address_length, auth->address); + Debug ("number: "); + dumpBytes (auth->number_length, auth->number); + Debug ("name: "); + dumpBytes (auth->name_length, auth->name); + Debug ("data: "); + dumpBytes (auth->data_length, auth->data); +} + +struct addrList { + unsigned short family; + unsigned short address_length; + char *address; + unsigned short number_length; + char *number; + unsigned short name_length; + char *name; + struct addrList *next; +}; + +static struct addrList *addrs; + +static +initAddrs () +{ + addrs = 0; +} + +static +doneAddrs () +{ + struct addrList *a, *n; + for (a = addrs; a; a = n) { + n = a->next; + if (a->address) + free (a->address); + if (a->number) + free (a->number); + free ((char *) a); + } +} + +static checkEntry (); + +static void +saveEntry (auth) + Xauth *auth; +{ + struct addrList *new; + + new = (struct addrList *) malloc (sizeof (struct addrList)); + if (!new) { + LogOutOfMem ("saveEntry"); + return; + } + if ((new->address_length = auth->address_length) > 0) { + new->address = malloc (auth->address_length); + if (!new->address) { + LogOutOfMem ("saveEntry"); + free ((char *) new); + return; + } + memmove( new->address, auth->address, (int) auth->address_length); + } else + new->address = 0; + if ((new->number_length = auth->number_length) > 0) { + new->number = malloc (auth->number_length); + if (!new->number) { + LogOutOfMem ("saveEntry"); + free (new->address); + free ((char *) new); + return; + } + memmove( new->number, auth->number, (int) auth->number_length); + } else + new->number = 0; + if ((new->name_length = auth->name_length) > 0) { + new->name = malloc (auth->name_length); + if (!new->name) { + LogOutOfMem ("saveEntry"); + free (new->number); + free (new->address); + free ((char *) new); + return; + } + memmove( new->name, auth->name, (int) auth->name_length); + } else + new->name = 0; + new->family = auth->family; + new->next = addrs; + addrs = new; +} + +static +checkEntry (auth) + Xauth *auth; +{ + struct addrList *a; + + for (a = addrs; a; a = a->next) { + if (a->family == auth->family && + a->address_length == auth->address_length && + binaryEqual (a->address, auth->address, auth->address_length) && + a->number_length == auth->number_length && + binaryEqual (a->number, auth->number, auth->number_length) && + a->name_length == auth->name_length && + binaryEqual (a->name, auth->name, auth->name_length)) + { + return 1; + } + } + return 0; +} + +static int doWrite; + +static +writeAuth (file, auth) + FILE *file; + Xauth *auth; +{ + if (debugLevel >= 15) { /* normally too verbose */ + Debug ("writeAuth: doWrite = %d\n", doWrite); + dumpAuth (auth); /* does Debug only */ + } + if (doWrite) + XauWriteAuth (file, auth); +} + +static +writeAddr (family, addr_length, addr, file, auth) + int family; + int addr_length; + char *addr; + FILE *file; + Xauth *auth; +{ + auth->family = (unsigned short) family; + auth->address_length = addr_length; + auth->address = addr; + Debug ("writeAddr: writing and saving an entry\n"); + writeAuth (file, auth); + saveEntry (auth); +} + +static +DefineLocal (file, auth) + FILE *file; + Xauth *auth; +{ + char displayname[100]; + char tmp_displayname[100]; + + strcpy(tmp_displayname, ""); + + /* stolen from xinit.c */ + +/* Make sure this produces the same string as _XGetHostname in lib/X/XlibInt.c. + * Otherwise, Xau will not be able to find your cookies in the Xauthority file. + * + * Note: POSIX says that the ``nodename'' member of utsname does _not_ have + * to have sufficient information for interfacing to the network, + * and so, you may be better off using gethostname (if it exists). + */ + +#ifdef NEED_UTSNAME + + /* hpux: + * Why not use gethostname()? Well, at least on my system, I've had to + * make an ugly kernel patch to get a name longer than 8 characters, and + * uname() lets me access to the whole string (it smashes release, you + * see), whereas gethostname() kindly truncates it for me. + */ + { + struct utsname name; + + uname(&name); + strcpy(displayname, name.nodename); + } + writeAddr (FamilyLocal, strlen (displayname), displayname, file, auth); + + strcpy(tmp_displayname, displayname); +#endif + +#if (!defined(NEED_UTSNAME) || defined (hpux)) + /* AIXV3: + * In AIXV3, _POSIX_SOURCE is defined, but uname gives only first + * field of hostname. Thus, we use gethostname instead. + */ + + /* + * For HP-UX, HP's Xlib expects a fully-qualified domain name, which + * is achieved by using gethostname(). For compatability, we must + * also still create the entry using uname() above. + */ + gethostname(displayname, sizeof(displayname)); + + /* + * If gethostname and uname both returned the same name, + * do not write a duplicate entry. + */ + if (strcmp (displayname, tmp_displayname)) + writeAddr (FamilyLocal, strlen (displayname), displayname, + file, auth); +#endif +} + +#ifdef USL +/* Deal with different SIOCGIFCONF ioctl semantics on UnixWare */ +static int +ifioctl (fd, cmd, arg) + int fd; + int cmd; + char *arg; +{ + struct strioctl ioc; + int ret; + + bzero((char *) &ioc, sizeof(ioc)); + ioc.ic_cmd = cmd; + ioc.ic_timout = 0; + if (cmd == SIOCGIFCONF) + { + ioc.ic_len = ((struct ifconf *) arg)->ifc_len; + ioc.ic_dp = ((struct ifconf *) arg)->ifc_buf; + } + else + { + ioc.ic_len = sizeof(struct ifreq); + ioc.ic_dp = arg; + } + ret = ioctl(fd, I_STR, (char *) &ioc); + if (ret >= 0 && cmd == SIOCGIFCONF) + ((struct ifconf *) arg)->ifc_len = ioc.ic_len; + return(ret); +} +#endif /* USL */ + + +#ifdef WINTCP /* NCR with Wollongong TCP */ + +#include <sys/un.h> +#include <stropts.h> +#include <tiuser.h> + +#include <sys/stream.h> +#include <net/if.h> +#include <netinet/ip.h> +#include <netinet/ip_var.h> +#include <netinet/in.h> +#include <netinet/in_var.h> + +static +DefineSelf (fd, file, auth) + int fd; + FILE *file; + Xauth *auth; +{ + /* + * The Wolongong drivers used by NCR SVR4/MP-RAS don't understand the + * socket IO calls that most other drivers seem to like. Because of + * this, this routine must be special cased for NCR. Eventually, + * this will be cleared up. + */ + + struct ipb ifnet; + struct in_ifaddr ifaddr; + struct strioctl str; + unsigned char *addr; + int family, len, ipfd; + + if ((ipfd = open ("/dev/ip", O_RDWR, 0 )) < 0) + LogError ("Getting interface configuration"); + + /* Indicate that we want to start at the begining */ + ifnet.ib_next = (struct ipb *) 1; + + while (ifnet.ib_next) + { + str.ic_cmd = IPIOC_GETIPB; + str.ic_timout = 0; + str.ic_len = sizeof (struct ipb); + str.ic_dp = (char *) &ifnet; + + if (ioctl (ipfd, (int) I_STR, (char *) &str) < 0) + { + close (ipfd); + LogError ("Getting interface configuration"); + } + + ifaddr.ia_next = (struct in_ifaddr *) ifnet.if_addrlist; + str.ic_cmd = IPIOC_GETINADDR; + str.ic_timout = 0; + str.ic_len = sizeof (struct in_ifaddr); + str.ic_dp = (char *) &ifaddr; + + if (ioctl (ipfd, (int) I_STR, (char *) &str) < 0) + { + close (ipfd); + LogError ("Getting interface configuration"); + } + + /* + * Ignore the 127.0.0.1 entry. + */ + if (IA_SIN(&ifaddr)->sin_addr.s_addr == htonl(0x7f000001) ) + continue; + + writeAddr (FamilyInternet, 4, (char *)&(IA_SIN(&ifaddr)->sin_addr), file, auth); + + } + close(ipfd); + +} + +#else /* WINTCP */ + +#ifdef SIOCGIFCONF + +/* Define this host for access control. Find all the hosts the OS knows about + * for this fd and add them to the selfhosts list. + */ +static +DefineSelf (fd, file, auth) + int fd; + FILE *file; + Xauth *auth; +{ + char buf[2048]; + struct ifconf ifc; + register int n; + int len; + char *addr; + int family; + register struct ifreq *ifr; + + ifc.ifc_len = sizeof (buf); + ifc.ifc_buf = buf; + +#ifdef USL + if (ifioctl (fd, SIOCGIFCONF, (char *) &ifc) < 0) +#else + if (ioctl (fd, SIOCGIFCONF, (char *) &ifc) < 0) +#endif + LogError ("Trouble getting network interface configuration"); + for (ifr = ifc.ifc_req +#ifdef BSD44SOCKETS + ; (char *)ifr < ifc.ifc_buf + ifc.ifc_len; + ifr = (struct ifreq *)((char *)ifr + sizeof (struct ifreq) + + (ifr->ifr_addr.sa_len > sizeof (ifr->ifr_addr) ? + ifr->ifr_addr.sa_len - sizeof (ifr->ifr_addr) : 0)) +#else + , n = ifc.ifc_len / sizeof (struct ifreq); --n >= 0; ifr++ +#endif + ) + { +#ifdef DNETCONN + /* + * this is ugly but SIOCGIFCONF returns decnet addresses in + * a different form from other decnet calls + */ + if (ifr->ifr_addr.sa_family == AF_DECnet) { + len = sizeof (struct dn_naddr); + addr = (char *)ifr->ifr_addr.sa_data; + family = FamilyDECnet; + } else +#endif + { + if (ConvertAddr (&ifr->ifr_addr, &len, &addr) < 0) + continue; + if (len == 0) + { + Debug ("Skipping zero length address\n"); + continue; + } + /* + * don't write out 'localhost' entries, as + * they may conflict with other local entries. + * DefineLocal will always be called to add + * the local entry anyway, so this one can + * be tossed. + */ + if (len == 4 && + addr[0] == 127 && addr[1] == 0 && + addr[2] == 0 && addr[3] == 1) + { + Debug ("Skipping localhost address\n"); + continue; + } + family = FamilyInternet; + } + Debug ("DefineSelf: write network address, length %d\n", len); + writeAddr (family, len, addr, file, auth); + } +} + +#else /* SIOCGIFCONF */ + +/* Define this host for access control. Find all the hosts the OS knows about + * for this fd and add them to the selfhosts list. + */ +static +DefineSelf (fd, file, auth) + int fd; +{ + register int n; + int len; + caddr_t addr; + int family; + + struct utsname name; + register struct hostent *hp; + + union { + struct sockaddr sa; + struct sockaddr_in in; + } saddr; + + struct sockaddr_in *inetaddr; + + /* hpux: + * Why not use gethostname()? Well, at least on my system, I've had to + * make an ugly kernel patch to get a name longer than 8 characters, and + * uname() lets me access to the whole string (it smashes release, you + * see), whereas gethostname() kindly truncates it for me. + */ + uname(&name); + hp = gethostbyname (name.nodename); + if (hp != NULL) { + saddr.sa.sa_family = hp->h_addrtype; + inetaddr = (struct sockaddr_in *) (&(saddr.sa)); + memmove( (char *) &(inetaddr->sin_addr), (char *) hp->h_addr, (int) hp->h_length); + family = ConvertAddr ( &(saddr.sa), &len, &addr); + if ( family >= 0) { + writeAddr (FamilyInternet, sizeof (inetaddr->sin_addr), + (char *) (&inetaddr->sin_addr), file, auth); + } + } +} + +#endif /* SIOCGIFCONF else */ + +#endif /* WINTCP */ + + +static +setAuthNumber (auth, name) + Xauth *auth; + char *name; +{ + char *colon; + char *dot, *number; + + Debug ("setAuthNumber %s\n", name); + colon = strrchr(name, ':'); + if (colon) { + ++colon; + dot = strchr(colon, '.'); + if (dot) + auth->number_length = dot - colon; + else + auth->number_length = strlen (colon); + number = malloc (auth->number_length + 1); + if (number) { + strncpy (number, colon, auth->number_length); + number[auth->number_length] = '\0'; + } else { + LogOutOfMem ("setAuthNumber"); + auth->number_length = 0; + } + auth->number = number; + Debug ("setAuthNumber: %s\n", number); + } +} + +static +writeLocalAuth (file, auth, name) + FILE *file; + Xauth *auth; + char *name; +{ + int fd; + + Debug ("writeLocalAuth: %s %.*s\n", name, auth->name_length, auth->name); + setAuthNumber (auth, name); +#ifdef STREAMSCONN + fd = t_open ("/dev/tcp", O_RDWR, 0); + t_bind(fd, NULL, NULL); + DefineSelf (fd, file, auth); + t_unbind (fd); + t_close (fd); +#endif +#ifdef TCPCONN + fd = socket (AF_INET, SOCK_STREAM, 0); + DefineSelf (fd, file, auth); + close (fd); +#endif +#ifdef DNETCONN + fd = socket (AF_DECnet, SOCK_STREAM, 0); + DefineSelf (fd, file, auth); + close (fd); +#endif + DefineLocal (file, auth); +} + +#ifdef XDMCP + +static void +writeRemoteAuth (file, auth, peer, peerlen, name) + FILE *file; + Xauth *auth; + XdmcpNetaddr peer; + int peerlen; + char *name; +{ + int family = FamilyLocal; + char *addr; + + Debug ("writeRemoteAuth: %s %.*s\n", name, auth->name_length, auth->name); + if (!peer || peerlen < 2) + return; + setAuthNumber (auth, name); + family = ConvertAddr (peer, &peerlen, &addr); + Debug ("writeRemoteAuth: family %d\n", family); + if (family != FamilyLocal) + { + Debug ("writeRemoteAuth: %d, %d, %x\n", + family, peerlen, *(int *)addr); + writeAddr (family, peerlen, addr, file, auth); + } + else + { + writeLocalAuth (file, auth, name); + } +} + +#endif /* XDMCP */ + +void +SetUserAuthorization (d, verify) + struct display *d; + struct verify_info *verify; +{ + FILE *old, *new; + char home_name[1024], backup_name[1024], new_name[1024]; + char *name; + char *home; + char *envname = 0; + int lockStatus; + Xauth *entry, **auths; + int setenv; + char **setEnv (), *getEnv (); + struct stat statb; + int i; + int magicCookie; + int data_len; + + Debug ("SetUserAuthorization\n"); + auths = d->authorizations; + if (auths) { + home = getEnv (verify->userEnviron, "HOME"); + lockStatus = LOCK_ERROR; + if (home) { + strcpy (home_name, home); + if (home[strlen(home) - 1] != '/') + strcat (home_name, "/"); + strcat (home_name, ".Xauthority"); + Debug ("XauLockAuth %s\n", home_name); + lockStatus = XauLockAuth (home_name, 1, 2, 10); + Debug ("Lock is %d\n", lockStatus); + if (lockStatus == LOCK_SUCCESS) { + if (openFiles (home_name, new_name, &old, &new)) { + name = home_name; + setenv = 0; + } else { + Debug ("openFiles failed\n"); + XauUnlockAuth (home_name); + lockStatus = LOCK_ERROR; + } + } + } + if (lockStatus != LOCK_SUCCESS) { + sprintf (backup_name, "%s/.XauthXXXXXX", d->userAuthDir); + (void) mktemp (backup_name); + lockStatus = XauLockAuth (backup_name, 1, 2, 10); + Debug ("backup lock is %d\n", lockStatus); + if (lockStatus == LOCK_SUCCESS) { + if (openFiles (backup_name, new_name, &old, &new)) { + name = backup_name; + setenv = 1; + } else { + XauUnlockAuth (backup_name); + lockStatus = LOCK_ERROR; + } + } + } + if (lockStatus != LOCK_SUCCESS) { + Debug ("can't lock auth file %s or backup %s\n", + home_name, backup_name); + LogError ("can't lock authorization file %s or backup %s\n", + home_name, backup_name); + return; + } + initAddrs (); + doWrite = 1; + Debug ("%d authorization protocols for %s\n", d->authNum, d->name); + /* + * Write MIT-MAGIC-COOKIE-1 authorization first, so that + * R4 clients which only knew that, and used the first + * matching entry will continue to function + */ + magicCookie = -1; + for (i = 0; i < d->authNum; i++) + { + if (auths[i]->name_length == 18 && + !strncmp (auths[i]->name, "MIT-MAGIC-COOKIE-1", 18)) + { + magicCookie = i; + if (d->displayType.location == Local) + writeLocalAuth (new, auths[i], d->name); +#ifdef XDMCP + else + writeRemoteAuth (new, auths[i], d->peer, d->peerlen, d->name); +#endif + break; + } + } + /* now write other authorizations */ + for (i = 0; i < d->authNum; i++) + { + if (i != magicCookie) + { + data_len = auths[i]->data_length; + /* client will just use default Kerberos cache, so don't + * even write cache info into the authority file. + */ + if (auths[i]->name_length == 14 && + !strncmp (auths[i]->name, "MIT-KERBEROS-5", 14)) + auths[i]->data_length = 0; + if (d->displayType.location == Local) + writeLocalAuth (new, auths[i], d->name); +#ifdef XDMCP + else + writeRemoteAuth (new, auths[i], d->peer, d->peerlen, d->name); +#endif + auths[i]->data_length = data_len; + } + } + if (old) { + if (fstat (fileno (old), &statb) != -1) + chmod (new_name, (int) (statb.st_mode & 0777)); + /*SUPPRESS 560*/ + while ((entry = XauReadAuth (old))) { + if (!checkEntry (entry)) + { + Debug ("Writing an entry\n"); + writeAuth (new, entry); + } + XauDisposeAuth (entry); + } + fclose (old); + } + doneAddrs (); + fclose (new); + if (unlink (name) == -1) + Debug ("unlink %s failed\n", name); + envname = name; + if (link (new_name, name) == -1) { + Debug ("link failed %s %s\n", new_name, name); + LogError ("Can't move authorization into place\n"); + setenv = 1; + envname = new_name; + } else { + Debug ("new is in place, go for it!\n"); + unlink (new_name); + } + if (setenv) { + verify->userEnviron = setEnv (verify->userEnviron, + "XAUTHORITY", envname); + verify->systemEnviron = setEnv (verify->systemEnviron, + "XAUTHORITY", envname); + } + XauUnlockAuth (name); + if (envname) + chown (envname, verify->uid, verify->gid); + } + Debug ("done SetUserAuthorization\n"); +} + +void +RemoveUserAuthorization (d, verify) + struct display *d; + struct verify_info *verify; +{ + char *home; + Xauth **auths, *entry; + char name[1024], new_name[1024]; + int lockStatus; + FILE *old, *new; + struct stat statb; + int i; + char *getEnv (); + + if (!(auths = d->authorizations)) + return; + home = getEnv (verify->userEnviron, "HOME"); + if (!home) + return; + Debug ("RemoveUserAuthorization\n"); + strcpy (name, home); + if (home[strlen(home) - 1] != '/') + strcat (name, "/"); + strcat (name, ".Xauthority"); + Debug ("XauLockAuth %s\n", name); + lockStatus = XauLockAuth (name, 1, 2, 10); + Debug ("Lock is %d\n", lockStatus); + if (lockStatus != LOCK_SUCCESS) + return; + if (openFiles (name, new_name, &old, &new)) + { + initAddrs (); + doWrite = 0; + for (i = 0; i < d->authNum; i++) + { + if (d->displayType.location == Local) + writeLocalAuth (new, auths[i], d->name); +#ifdef XDMCP + else + writeRemoteAuth (new, auths[i], d->peer, d->peerlen, d->name); +#endif + } + doWrite = 1; + if (old) { + if (fstat (fileno (old), &statb) != -1) + chmod (new_name, (int) (statb.st_mode & 0777)); + /*SUPPRESS 560*/ + while ((entry = XauReadAuth (old))) { + if (!checkEntry (entry)) + { + Debug ("Writing an entry\n"); + writeAuth (new, entry); + } + XauDisposeAuth (entry); + } + fclose (old); + } + doneAddrs (); + fclose (new); + if (unlink (name) == -1) + Debug ("unlink %s failed\n", name); + if (link (new_name, name) == -1) { + Debug ("link failed %s %s\n", new_name, name); + LogError ("Can't move authorization into place\n"); + } else { + Debug ("new is in place, go for it!\n"); + unlink (new_name); + } + } + XauUnlockAuth (name); +} diff --git a/choose.c b/choose.c new file mode 100644 index 0000000..1e88be7 --- /dev/null +++ b/choose.c @@ -0,0 +1,508 @@ +/* + * $Xorg: choose.c,v 1.5 2001/02/09 02:05:40 xorgcvs Exp $ + * +Copyright 1990, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + * + * Author: Keith Packard, MIT X Consortium + */ + +/* + * choose.c + * + * xdm interface to chooser program + */ + +#include "dm.h" + +#ifdef XDMCP + +#include <X11/X.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <sys/un.h> +#include <ctype.h> +#include <errno.h> +#if defined(STREAMSCONN) +# include <tiuser.h> +#endif + +#ifdef X_NOT_STDC_ENV +extern int errno; +#define Time_t long +extern Time_t time (); +#else +#include <time.h> +#define Time_t time_t +#endif + +static +FormatBytes (data, length, buf, buflen) + unsigned char *data; + int length; + char *buf; + int buflen; +{ + int i; + static char HexChars[] = "0123456789abcdef"; + + if (buflen < length * 2 + 1) + return 0; + for (i = 0; i < length; i++) + { + *buf++ = HexChars[(data[i] >> 4) & 0xf]; + *buf++ = HexChars[(data[i]) & 0xf]; + } + *buf++ = '\0'; + return 1; +} + +static +FormatARRAY8 (a, buf, buflen) + ARRAY8Ptr a; + char *buf; + int buflen; +{ + return FormatBytes (a->data, a->length, buf, buflen); +} + +/* Converts an Internet address in ARRAY8 format to a string in + familiar dotted address notation, e.g., "18.24.0.11" + Returns 1 if successful, 0 if not. + */ +static int +ARRAY8ToDottedDecimal (a, buf, buflen) + ARRAY8Ptr a; + char *buf; + int buflen; +{ + if (a->length != 4 || buflen < 20) + return 0; + sprintf(buf, "%d.%d.%d.%d", + a->data[0], a->data[1], a->data[2], a->data[3]); + return 1; +} + +typedef struct _IndirectUsers { + struct _IndirectUsers *next; + ARRAY8 client; + CARD16 connectionType; +} IndirectUsersRec, *IndirectUsersPtr; + +static IndirectUsersPtr indirectUsers; + +RememberIndirectClient (clientAddress, connectionType) + ARRAY8Ptr clientAddress; + CARD16 connectionType; +{ + IndirectUsersPtr i; + + for (i = indirectUsers; i; i = i->next) + if (XdmcpARRAY8Equal (clientAddress, &i->client) && + connectionType == i->connectionType) + return 1; + i = (IndirectUsersPtr) malloc (sizeof (IndirectUsersRec)); + if (!XdmcpCopyARRAY8 (clientAddress, &i->client)) + { + free ((char *) i); + return 0; + } + i->connectionType = connectionType; + i->next = indirectUsers; + indirectUsers = i; + return 1; +} + +ForgetIndirectClient (clientAddress, connectionType) + ARRAY8Ptr clientAddress; + CARD16 connectionType; +{ + IndirectUsersPtr i, prev; + + prev = 0; + for (i = indirectUsers; i; i = i->next) + { + if (XdmcpARRAY8Equal (clientAddress, &i->client) && + connectionType == i->connectionType) + { + if (prev) + prev->next = i->next; + else + indirectUsers = i->next; + XdmcpDisposeARRAY8 (&i->client); + free ((char *) i); + break; + } + prev = i; + } +} + +IsIndirectClient (clientAddress, connectionType) + ARRAY8Ptr clientAddress; + CARD16 connectionType; +{ + IndirectUsersPtr i; + + for (i = indirectUsers; i; i = i->next) + if (XdmcpARRAY8Equal (clientAddress, &i->client) && + connectionType == i->connectionType) + return 1; + return 0; +} + +extern char *NetaddrPort(); + +static +FormatChooserArgument (buf, len) + char *buf; + int len; +{ + unsigned char addr_buf[1024]; + int addr_len = sizeof (addr_buf); + unsigned char result_buf[1024]; + int result_len = 0; + int netfamily; + + if (GetChooserAddr (addr_buf, &addr_len) == -1) + { + LogError ("Cannot get return address for chooser socket\n"); + Debug ("Cannot get chooser socket address\n"); + return 0; + } + netfamily = NetaddrFamily((XdmcpNetaddr)addr_buf); + switch (netfamily) { + case AF_INET: + { + char *port; + int portlen; + ARRAY8Ptr localAddress, getLocalAddress (); + + port = NetaddrPort((XdmcpNetaddr)addr_buf, &portlen); + result_buf[0] = netfamily >> 8; + result_buf[1] = netfamily & 0xFF; + result_buf[2] = port[0]; + result_buf[3] = port[1]; + localAddress = getLocalAddress (); + memmove( (char *)result_buf+4, (char *)localAddress->data, 4); + result_len = 8; + } + break; +#ifdef AF_DECnet + case AF_DECnet: + break; +#endif + default: + Debug ("Chooser family %d isn't known\n", netfamily); + return 0; + } + + return FormatBytes (result_buf, result_len, buf, len); +} + +typedef struct _Choices { + struct _Choices *next; + ARRAY8 client; + CARD16 connectionType; + ARRAY8 choice; + Time_t time; +} ChoiceRec, *ChoicePtr; + +static ChoicePtr choices; + +ARRAY8Ptr +IndirectChoice (clientAddress, connectionType) + ARRAY8Ptr clientAddress; + CARD16 connectionType; +{ + ChoicePtr c, next, prev; + Time_t now; + + now = time ((Time_t*)0); + prev = 0; + for (c = choices; c; c = next) + { + next = c->next; + Debug ("Choice checking timeout: %d >? %d\n", now - c->time, choiceTimeout); + if (now - c->time > (Time_t)choiceTimeout) + { + Debug ("Timeout choice %d > %d\n", now - c->time, choiceTimeout); + if (prev) + prev->next = next; + else + choices = next; + XdmcpDisposeARRAY8 (&c->client); + XdmcpDisposeARRAY8 (&c->choice); + free ((char *) c); + } + else + { + if (XdmcpARRAY8Equal (clientAddress, &c->client) && + connectionType == c->connectionType) + return &c->choice; + prev = c; + } + } + return 0; +} + +static int +RegisterIndirectChoice (clientAddress, connectionType, choice) + ARRAY8Ptr clientAddress, choice; + CARD16 connectionType; +{ + ChoicePtr c; + int insert; + int found = 0; + + Debug ("Got indirect choice back\n"); + for (c = choices; c; c = c->next) { + if (XdmcpARRAY8Equal (clientAddress, &c->client) && + connectionType == c->connectionType) { + found = 1; + break; + } + } + if (!found) + return 0; + + insert = 0; + if (!c) + { + c = (ChoicePtr) malloc (sizeof (ChoiceRec)); + insert = 1; + if (!c) + return 0; + c->connectionType = connectionType; + if (!XdmcpCopyARRAY8 (clientAddress, &c->client)) + { + free ((char *) c); + return 0; + } + } + else + { + XdmcpDisposeARRAY8 (&c->choice); + } + if (!XdmcpCopyARRAY8 (choice, &c->choice)) + { + XdmcpDisposeARRAY8 (&c->client); + free ((char *) c); + return 0; + } + if (insert) + { + c->next = choices; + choices = c; + } + c->time = time (0); + return 1; +} + +#ifdef notdef +static +RemoveIndirectChoice (clientAddress, connectionType) + ARRAY8Ptr clientAddress; + CARD16 connectionType; +{ + ChoicePtr c, prev; + + prev = 0; + for (c = choices; c; c = c->next) + { + if (XdmcpARRAY8Equal (clientAddress, &c->client) && + connectionType == c->connectionType) + { + if (prev) + prev->next = c->next; + else + choices = c->next; + XdmcpDisposeARRAY8 (&c->client); + XdmcpDisposeARRAY8 (&c->choice); + free ((char *) c); + return; + } + prev = c; + } +} +#endif + +/*ARGSUSED*/ +static +AddChooserHost (connectionType, addr, closure) + CARD16 connectionType; + ARRAY8Ptr addr; + char *closure; +{ + char ***argp, **parseArgs(); + char hostbuf[1024]; + + argp = (char ***) closure; + if (addr->length == strlen ("BROADCAST") && + !strncmp ((char *)addr->data, "BROADCAST", addr->length)) + { + *argp = parseArgs (*argp, "BROADCAST"); + } + else if (ARRAY8ToDottedDecimal (addr, hostbuf, sizeof (hostbuf))) + { + *argp = parseArgs (*argp, hostbuf); + } +} + +ProcessChooserSocket (fd) + int fd; +{ + int client_fd; + char buf[1024]; + int len; + XdmcpBuffer buffer; + ARRAY8 clientAddress; + CARD16 connectionType; + ARRAY8 choice; +#if defined(STREAMSCONN) + struct t_call *call; + int flags=0; +#endif + + Debug ("Process chooser socket\n"); + len = sizeof (buf); +#if defined(STREAMSCONN) + call = (struct t_call *)t_alloc( fd, T_CALL, T_ALL ); + if( call == NULL ) + { + t_error( "ProcessChooserSocket: t_alloc failed" ); + LogError ("Cannot setup to listen on chooser connection\n"); + return; + } + if( t_listen( fd, call ) < 0 ) + { + t_error( "ProcessChooserSocket: t_listen failed" ); + t_free( (char *)call, T_CALL ); + LogError ("Cannot listen on chooser connection\n"); + return; + } + client_fd = t_open ("/dev/tcp", O_RDWR, NULL); + if (client_fd == -1) + { + t_error( "ProcessChooserSocket: t_open failed" ); + t_free( (char *)call, T_CALL ); + LogError ("Cannot open new chooser connection\n"); + return; + } + if( t_bind( client_fd, NULL, NULL ) < 0 ) + { + t_error( "ProcessChooserSocket: t_bind failed" ); + t_free( (char *)call, T_CALL ); + LogError ("Cannot bind new chooser connection\n"); + t_close (client_fd); + return; + } + if( t_accept (fd, client_fd, call) < 0 ) + { + t_error( "ProcessChooserSocket: t_accept failed" ); + LogError ("Cannot accept chooser connection\n"); + t_free( (char *)call, T_CALL ); + t_unbind (client_fd); + t_close (client_fd); + return; + } +#else + client_fd = accept (fd, (struct sockaddr *)buf, &len); + if (client_fd == -1) + { + LogError ("Cannot accept chooser connection\n"); + return; + } +#endif + Debug ("Accepted %d\n", client_fd); + +#if defined(STREAMSCONN) + len = t_rcv (client_fd, buf, sizeof (buf),&flags); +#else + len = read (client_fd, buf, sizeof (buf)); +#endif + Debug ("Read returns %d\n", len); + if (len > 0) + { + buffer.data = (BYTE *) buf; + buffer.size = sizeof (buf); + buffer.count = len; + buffer.pointer = 0; + clientAddress.data = 0; + clientAddress.length = 0; + choice.data = 0; + choice.length = 0; + if (XdmcpReadARRAY8 (&buffer, &clientAddress) && + XdmcpReadCARD16 (&buffer, &connectionType) && + XdmcpReadARRAY8 (&buffer, &choice)) + { + Debug ("Read from chooser succesfully\n"); + if (!RegisterIndirectChoice (&clientAddress, connectionType, &choice)) + Debug ("Invalid chooser reply\n"); + } + XdmcpDisposeARRAY8 (&clientAddress); + XdmcpDisposeARRAY8 (&choice); + } + else + { + LogError ("Choice response read error: %s\n", strerror(errno)); + } + +#if defined(STREAMSCONN) + t_unbind (client_fd); + t_free( (char *)call, T_CALL ); + t_close (client_fd); +#else + close (client_fd); +#endif +} + +RunChooser (d) + struct display *d; +{ + char **args, **parseArgs(), **systemEnv(); + char buf[1024]; + char **env; + + Debug ("RunChooser %s\n", d->name); + SetTitle (d->name, "chooser", (char *) 0); + LoadXloginResources (d); + args = parseArgs ((char **) 0, d->chooser); + strcpy (buf, "-xdmaddress "); + if (FormatChooserArgument (buf + strlen (buf), sizeof (buf) - strlen (buf))) + args = parseArgs (args, buf); + strcpy (buf, "-clientaddress "); + if (FormatARRAY8 (&d->clientAddr, buf + strlen (buf), sizeof (buf) - strlen (buf))) + args = parseArgs (args, buf); + sprintf (buf, "-connectionType %d", d->connectionType); + args = parseArgs (args, buf); + ForEachChooserHost (&d->clientAddr, d->connectionType, AddChooserHost, + (char *) &args); + env = systemEnv (d, (char *) 0, (char *) 0); + Debug ("Running %s\n", args[0]); + execute (args, env); + Debug ("Couldn't run %s\n", args[0]); + LogError ("Cannot execute %s\n", args[0]); + exit (REMANAGE_DISPLAY); +} + +#endif /* XDMCP */ diff --git a/chooser.c b/chooser.c new file mode 100644 index 0000000..3724691 --- /dev/null +++ b/chooser.c @@ -0,0 +1,1005 @@ +/* + * $Xorg: chooser.c,v 1.4 2001/02/09 02:05:40 xorgcvs Exp $ + * +Copyright 1990, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + * + * Author: Keith Packard, MIT X Consortium + */ + +/* + * Chooser - display a menu of names and let the user select one + */ + +/* + * Layout: + * + * +--------------------------------------------------+ + * | +------------------+ | + * | | Label | | + * | +------------------+ | + * | +-+--------------+ | + * | |^| name-1 | | + * | ||| name-2 | | + * | |v| name-3 | | + * | | | name-4 | | + * | | | name-5 | | + * | | | name-6 | | + * | +----------------+ | + * | cancel accept ping | + * +--------------------------------------------------+ + */ + +#include <X11/Intrinsic.h> +#include <X11/StringDefs.h> +#include <X11/Xatom.h> + +#include <X11/Xaw/Paned.h> +#include <X11/Xaw/Label.h> +#include <X11/Xaw/Viewport.h> +#include <X11/Xaw/List.h> +#include <X11/Xaw/Box.h> +#include <X11/Xaw/Command.h> + +#include "dm.h" + +#include <X11/Xdmcp.h> + +#include <sys/types.h> +#include <stdio.h> +#include <ctype.h> + +#ifdef SVR4 +#include <sys/sockio.h> +#endif +#include <sys/socket.h> +#include <netinet/in.h> +#include <sys/ioctl.h> +#ifdef STREAMSCONN +#ifdef WINTCP /* NCR with Wollongong TCP */ +#include <netinet/ip.h> +#endif +#include <stropts.h> +#include <tiuser.h> +#include <netconfig.h> +#include <netdir.h> +#endif + +#ifdef XKB +#include <X11/extensions/XKBbells.h> +#endif + +#define BROADCAST_HOSTNAME "BROADCAST" + +#ifndef ishexdigit +#define ishexdigit(c) (isdigit(c) || 'a' <= (c) && (c) <= 'f') +#endif + +#ifdef hpux +# include <sys/utsname.h> +# ifdef HAS_IFREQ +# include <net/if.h> +# endif +#else +#ifdef __convex__ +# include <sync/queue.h> +# include <sync/sema.h> +#endif +# include <net/if.h> +#endif /* hpux */ + +#include <netdb.h> + +Widget toplevel, label, viewport, paned, list, box, cancel, acceptit, ping; + +static void CvtStringToARRAY8(); + +static struct _app_resources { + ARRAY8Ptr xdmAddress; + ARRAY8Ptr clientAddress; + int connectionType; +} app_resources; + +#define offset(field) XtOffsetOf(struct _app_resources, field) + +#define XtRARRAY8 "ARRAY8" + +static XtResource resources[] = { + {"xdmAddress", "XdmAddress", XtRARRAY8, sizeof (ARRAY8Ptr), + offset (xdmAddress), XtRString, NULL }, + {"clientAddress", "ClientAddress", XtRARRAY8, sizeof (ARRAY8Ptr), + offset (clientAddress), XtRString, NULL }, + {"connectionType", "ConnectionType", XtRInt, sizeof (int), + offset (connectionType), XtRImmediate, (XtPointer) 0 } +}; +#undef offset + +static XrmOptionDescRec options[] = { + "-xdmaddress", "*xdmAddress", XrmoptionSepArg, NULL, + "-clientaddress", "*clientAddress", XrmoptionSepArg, NULL, + "-connectionType", "*connectionType", XrmoptionSepArg, NULL, +}; + +typedef struct _hostAddr { + struct _hostAddr *next; + struct sockaddr *addr; + int addrlen; + xdmOpCode type; +} HostAddr; + +static HostAddr *hostAddrdb; + +typedef struct _hostName { + struct _hostName *next; + char *fullname; + int willing; + ARRAY8 hostname, status; + CARD16 connectionType; + ARRAY8 hostaddr; +} HostName; + +static HostName *hostNamedb; + +static int socketFD; + +static int pingTry; + +#define PING_INTERVAL 2000 +#define TRIES 3 + +static XdmcpBuffer directBuffer, broadcastBuffer; +static XdmcpBuffer buffer; + +/* ARGSUSED */ +static void +PingHosts (closure, id) + XtPointer closure; + XtIntervalId *id; +{ + HostAddr *hosts; + + for (hosts = hostAddrdb; hosts; hosts = hosts->next) + { + if (hosts->type == QUERY) + XdmcpFlush (socketFD, &directBuffer, hosts->addr, hosts->addrlen); + else + XdmcpFlush (socketFD, &broadcastBuffer, hosts->addr, hosts->addrlen); + } + if (++pingTry < TRIES) + XtAddTimeOut (PING_INTERVAL, PingHosts, (XtPointer) 0); +} + +char **NameTable; +int NameTableSize; + +static int +HostnameCompare (a, b) +#ifdef __STDC__ + const void *a, *b; +#else + char *a, *b; +#endif +{ + return strcmp (*(char **)a, *(char **)b); +} + +static void +RebuildTable (size) + int size; +{ + char **newTable = 0; + HostName *names; + int i; + + if (size) + { + newTable = (char **) malloc (size * sizeof (char *)); + if (!newTable) + return; + for (names = hostNamedb, i = 0; names; names = names->next, i++) + newTable[i] = names->fullname; + qsort (newTable, size, sizeof (char *), HostnameCompare); + } + XawListChange (list, newTable, size, 0, TRUE); + if (NameTable) + free ((char *) NameTable); + NameTable = newTable; + NameTableSize = size; +} + +static int +AddHostname (hostname, status, addr, willing) + ARRAY8Ptr hostname, status; + struct sockaddr *addr; + int willing; +{ + HostName *new, **names, *name; + ARRAY8 hostAddr; + CARD16 connectionType; + int fulllen; + + switch (addr->sa_family) + { + case AF_INET: + hostAddr.data = (CARD8 *) &((struct sockaddr_in *) addr)->sin_addr; + hostAddr.length = 4; + connectionType = FamilyInternet; + break; + default: + hostAddr.data = (CARD8 *) ""; + hostAddr.length = 0; + connectionType = FamilyLocal; + break; + } + for (names = &hostNamedb; *names; names = & (*names)->next) + { + name = *names; + if (connectionType == name->connectionType && + XdmcpARRAY8Equal (&hostAddr, &name->hostaddr)) + { + if (XdmcpARRAY8Equal (status, &name->status)) + { + return 0; + } + break; + } + } + if (!*names) + { + new = (HostName *) malloc (sizeof (HostName)); + if (!new) + return 0; + if (hostname->length) + { + switch (addr->sa_family) + { + case AF_INET: + { + struct hostent *hostent; + char *host; + + hostent = gethostbyaddr ((char *)hostAddr.data, hostAddr.length, AF_INET); + if (hostent) + { + XdmcpDisposeARRAY8 (hostname); + host = hostent->h_name; + XdmcpAllocARRAY8 (hostname, strlen (host)); + memmove( hostname->data, host, hostname->length); + } + } + } + } + if (!XdmcpAllocARRAY8 (&new->hostaddr, hostAddr.length)) + { + free ((char *) new->fullname); + free ((char *) new); + return 0; + } + memmove( new->hostaddr.data, hostAddr.data, hostAddr.length); + new->connectionType = connectionType; + new->hostname = *hostname; + + *names = new; + new->next = 0; + NameTableSize++; + } + else + { + new = *names; + free (new->fullname); + XdmcpDisposeARRAY8 (&new->status); + XdmcpDisposeARRAY8 (hostname); + } + new->willing = willing; + new->status = *status; + + hostname = &new->hostname; + fulllen = hostname->length; + if (fulllen < 30) + fulllen = 30; + new->fullname = malloc (fulllen + status->length + 10); + if (!new->fullname) + { + new->fullname = "Unknown"; + } + else + { + sprintf (new->fullname, "%-30.*s %*.*s", + hostname->length, hostname->data, + status->length, status->length, status->data); + } + RebuildTable (NameTableSize); + return 1; +} + +static void +DisposeHostname (host) + HostName *host; +{ + XdmcpDisposeARRAY8 (&host->hostname); + XdmcpDisposeARRAY8 (&host->hostaddr); + XdmcpDisposeARRAY8 (&host->status); + free ((char *) host->fullname); + free ((char *) host); +} + +static void +RemoveHostname (host) + HostName *host; +{ + HostName **prev, *hosts; + + prev = &hostNamedb;; + for (hosts = hostNamedb; hosts; hosts = hosts->next) + { + if (hosts == host) + break; + prev = &hosts->next; + } + if (!hosts) + return; + *prev = host->next; + DisposeHostname (host); + NameTableSize--; + RebuildTable (NameTableSize); +} + +static void +EmptyHostnames () +{ + HostName *hosts, *next; + + for (hosts = hostNamedb; hosts; hosts = next) + { + next = hosts->next; + DisposeHostname (hosts); + } + NameTableSize = 0; + hostNamedb = 0; + RebuildTable (NameTableSize); +} + +/* ARGSUSED */ +static void +ReceivePacket (closure, source, id) + XtPointer closure; + int *source; + XtInputId *id; +{ + XdmcpHeader header; + ARRAY8 authenticationName; + ARRAY8 hostname; + ARRAY8 status; + int saveHostname = 0; + struct sockaddr addr; + int addrlen; + + addrlen = sizeof (addr); + if (!XdmcpFill (socketFD, &buffer, &addr, &addrlen)) + return; + if (!XdmcpReadHeader (&buffer, &header)) + return; + if (header.version != XDM_PROTOCOL_VERSION) + return; + hostname.data = 0; + status.data = 0; + authenticationName.data = 0; + switch (header.opcode) { + case WILLING: + if (XdmcpReadARRAY8 (&buffer, &authenticationName) && + XdmcpReadARRAY8 (&buffer, &hostname) && + XdmcpReadARRAY8 (&buffer, &status)) + { + if (header.length == 6 + authenticationName.length + + hostname.length + status.length) + { + if (AddHostname (&hostname, &status, &addr, header.opcode == (int) WILLING)) + saveHostname = 1; + } + } + XdmcpDisposeARRAY8 (&authenticationName); + break; + case UNWILLING: + if (XdmcpReadARRAY8 (&buffer, &hostname) && + XdmcpReadARRAY8 (&buffer, &status)) + { + if (header.length == 4 + hostname.length + status.length) + { + if (AddHostname (&hostname, &status, &addr, header.opcode == (int) WILLING)) + saveHostname = 1; + + } + } + break; + default: + break; + } + if (!saveHostname) + { + XdmcpDisposeARRAY8 (&hostname); + XdmcpDisposeARRAY8 (&status); + } +} + +static void +RegisterHostaddr (addr, len, type) + struct sockaddr *addr; + int len; + xdmOpCode type; +{ + HostAddr *host, **prev; + + host = (HostAddr *) malloc (sizeof (HostAddr)); + if (!host) + return; + host->addr = (struct sockaddr *) malloc (len); + if (!host->addr) + { + free ((char *) host); + return; + } + memmove( (char *) host->addr, (char *) addr, len); + host->addrlen = len; + host->type = type; + for (prev = &hostAddrdb; *prev; prev = &(*prev)->next) + ; + *prev = host; + host->next = NULL; +} + +/* + * Register the address for this host. + * Called with each of the names on the command line. + * The special name "BROADCAST" looks up all the broadcast + * addresses on the local host. + */ + +static void +RegisterHostname (name) + char *name; +{ + struct hostent *hostent; + struct sockaddr_in in_addr; + struct ifconf ifc; + register struct ifreq *ifr; + struct sockaddr broad_addr; + char buf[2048]; + int n; + + if (!strcmp (name, BROADCAST_HOSTNAME)) + { +#ifdef WINTCP /* NCR with Wollongong TCP */ + int ipfd; + struct ifconf *ifcp; + struct strioctl ioc; + + ifcp = (struct ifconf *)buf; + ifcp->ifc_buf = buf+4; + ifcp->ifc_len = sizeof (buf) - 4; + + if ((ipfd=open( "/dev/ip", O_RDONLY )) < 0 ) + { + t_error( "RegisterHostname() t_open(/dev/ip) failed" ); + return; + } + + ioc.ic_cmd = IPIOC_GETIFCONF; + ioc.ic_timout = 60; + ioc.ic_len = sizeof( buf ); + ioc.ic_dp = (char *)ifcp; + + if (ioctl (ipfd, (int) I_STR, (char *) &ioc) < 0) + { + perror( "RegisterHostname() ioctl(I_STR(IPIOC_GETIFCONF)) failed" ); + close( ipfd ); + return; + } + + for (ifr = ifcp->ifc_req, +n = ifcp->ifc_len / sizeof (struct ifreq); + --n >= 0; + ifr++) +#else /* WINTCP */ + ifc.ifc_len = sizeof (buf); + ifc.ifc_buf = buf; + if (ioctl (socketFD, (int) SIOCGIFCONF, (char *) &ifc) < 0) + return; + for (ifr = ifc.ifc_req +#ifdef BSD44SOCKETS + ; (char *)ifr < ifc.ifc_buf + ifc.ifc_len; + ifr = (struct ifreq *)((char *)ifr + sizeof (struct ifreq) + + (ifr->ifr_addr.sa_len > sizeof (ifr->ifr_addr) ? + ifr->ifr_addr.sa_len - sizeof (ifr->ifr_addr) : 0)) +#else + , n = ifc.ifc_len / sizeof (struct ifreq); --n >= 0; ifr++ +#endif + ) +#endif /* WINTCP */ + { + if (ifr->ifr_addr.sa_family != AF_INET) + continue; + + broad_addr = ifr->ifr_addr; + ((struct sockaddr_in *) &broad_addr)->sin_addr.s_addr = + htonl (INADDR_BROADCAST); +#ifdef SIOCGIFBRDADDR + { + struct ifreq broad_req; + + broad_req = *ifr; +#ifdef WINTCP /* NCR with Wollongong TCP */ + ioc.ic_cmd = IPIOC_GETIFFLAGS; + ioc.ic_timout = 0; + ioc.ic_len = sizeof( broad_req ); + ioc.ic_dp = (char *)&broad_req; + + if (ioctl (ipfd, I_STR, (char *) &ioc) != -1 && +#else /* WINTCP */ + if (ioctl (socketFD, SIOCGIFFLAGS, (char *) &broad_req) != -1 && +#endif /* WINTCP */ + (broad_req.ifr_flags & IFF_BROADCAST) && + (broad_req.ifr_flags & IFF_UP) + ) + { + broad_req = *ifr; +#ifdef WINTCP /* NCR with Wollongong TCP */ + ioc.ic_cmd = IPIOC_GETIFBRDADDR; + ioc.ic_timout = 0; + ioc.ic_len = sizeof( broad_req ); + ioc.ic_dp = (char *)&broad_req; + + if (ioctl (ipfd, I_STR, (char *) &ioc) != -1) +#else /* WINTCP */ + if (ioctl (socketFD, SIOCGIFBRDADDR, &broad_req) != -1) +#endif /* WINTCP */ + broad_addr = broad_req.ifr_addr; + else + continue; + } + else + continue; + } +#endif + in_addr = *((struct sockaddr_in *) &broad_addr); + in_addr.sin_port = htons (XDM_UDP_PORT); +#ifdef BSD44SOCKETS + in_addr.sin_len = sizeof(in_addr); +#endif + RegisterHostaddr ((struct sockaddr *)&in_addr, sizeof (in_addr), + BROADCAST_QUERY); + } + } + else + { + + /* address as hex string, e.g., "12180022" (depreciated) */ + if (strlen(name) == 8 && + FromHex(name, (char *)&in_addr.sin_addr, strlen(name)) == 0) + { + in_addr.sin_family = AF_INET; + } + /* Per RFC 1123, check first for IP address in dotted-decimal form */ + else if ((in_addr.sin_addr.s_addr = inet_addr(name)) != -1) + in_addr.sin_family = AF_INET; + else + { + hostent = gethostbyname (name); + if (!hostent) + return; + if (hostent->h_addrtype != AF_INET || hostent->h_length != 4) + return; + in_addr.sin_family = hostent->h_addrtype; + memmove( &in_addr.sin_addr, hostent->h_addr, 4); + } + in_addr.sin_port = htons (XDM_UDP_PORT); +#ifdef BSD44SOCKETS + in_addr.sin_len = sizeof(in_addr); +#endif + RegisterHostaddr ((struct sockaddr *)&in_addr, sizeof (in_addr), + QUERY); + } +} + +static ARRAYofARRAY8 AuthenticationNames; + +static void +RegisterAuthenticationName (name, namelen) + char *name; + int namelen; +{ + ARRAY8Ptr authName; + if (!XdmcpReallocARRAYofARRAY8 (&AuthenticationNames, + AuthenticationNames.length + 1)) + return; + authName = &AuthenticationNames.data[AuthenticationNames.length-1]; + if (!XdmcpAllocARRAY8 (authName, namelen)) + return; + memmove( authName->data, name, namelen); +} + +int +InitXDMCP (argv) + char **argv; +{ + int soopts = 1; + XdmcpHeader header; + int i; + + header.version = XDM_PROTOCOL_VERSION; + header.opcode = (CARD16) BROADCAST_QUERY; + header.length = 1; + for (i = 0; i < (int)AuthenticationNames.length; i++) + header.length += 2 + AuthenticationNames.data[i].length; + XdmcpWriteHeader (&broadcastBuffer, &header); + XdmcpWriteARRAYofARRAY8 (&broadcastBuffer, &AuthenticationNames); + + header.version = XDM_PROTOCOL_VERSION; + header.opcode = (CARD16) QUERY; + header.length = 1; + for (i = 0; i < (int)AuthenticationNames.length; i++) + header.length += 2 + AuthenticationNames.data[i].length; + XdmcpWriteHeader (&directBuffer, &header); + XdmcpWriteARRAYofARRAY8 (&directBuffer, &AuthenticationNames); +#if defined(STREAMSCONN) + if ((socketFD = t_open ("/dev/udp", O_RDWR, 0)) < 0) + return 0; + if (t_bind( socketFD, NULL, NULL ) < 0) { + t_close(socketFD); + return 0; + } + + /* + * This part of the code looks contrived. It will actually fit in nicely + * when the CLTS part of Xtrans is implemented. + */ + { + struct netconfig *nconf; + + if( (nconf=getnetconfigent("udp")) == NULL ) { + t_unbind(socketFD); + t_close(socketFD); + return 0; + } + + if( netdir_options(nconf, ND_SET_BROADCAST, socketFD, NULL) ) { + freenetconfigent(nconf); + t_unbind(socketFD); + t_close(socketFD); + return 0; + } + + freenetconfigent(nconf); + } +#else + if ((socketFD = socket (AF_INET, SOCK_DGRAM, 0)) < 0) + return 0; +#endif +#ifdef SO_BROADCAST + soopts = 1; + if (setsockopt (socketFD, SOL_SOCKET, SO_BROADCAST, (char *)&soopts, sizeof (soopts)) < 0) + perror ("setsockopt"); +#endif + + XtAddInput (socketFD, (XtPointer) XtInputReadMask, ReceivePacket, + (XtPointer) 0); + while (*argv) + { + RegisterHostname (*argv); + ++argv; + } + pingTry = 0; + PingHosts ((XtPointer)NULL, (XtIntervalId *)NULL); + return 1; +} + +static void +Choose (h) + HostName *h; +{ + if (app_resources.xdmAddress) + { + struct sockaddr_in in_addr; + struct sockaddr *addr; + int family; + int len; + int fd; + char buf[1024]; + XdmcpBuffer buffer; + char *xdm; +#if defined(STREAMSCONN) + struct t_call call, rcv; +#endif + + xdm = (char *) app_resources.xdmAddress->data; + family = (xdm[0] << 8) + xdm[1]; + switch (family) { + case AF_INET: +#ifdef BSD44SOCKETS + in_addr.sin_len = sizeof(in_addr); +#endif + in_addr.sin_family = family; + memmove( &in_addr.sin_port, xdm + 2, 2); + memmove( &in_addr.sin_addr, xdm + 4, 4); + addr = (struct sockaddr *) &in_addr; + len = sizeof (in_addr); + break; + } +#if defined(STREAMSCONN) + if ((fd = t_open ("/dev/tcp", O_RDWR, NULL)) == -1) + { + fprintf (stderr, "Cannot create response endpoint\n"); + fflush(stderr); + exit (REMANAGE_DISPLAY); + } + if (t_bind (fd, NULL, NULL) == -1) + { + fprintf (stderr, "Cannot bind response endpoint\n"); + fflush(stderr); + t_close (fd); + exit (REMANAGE_DISPLAY); + } + call.addr.buf=(char *)addr; + call.addr.len=len; + call.addr.maxlen=len; + call.opt.len=0; + call.opt.maxlen=0; + call.udata.len=0; + call.udata.maxlen=0; + if (t_connect (fd, &call, NULL) == -1) + { + t_error ("Cannot connect to xdm\n"); + fflush(stderr); + t_unbind (fd); + t_close (fd); + exit (REMANAGE_DISPLAY); + } +#else + if ((fd = socket (family, SOCK_STREAM, 0)) == -1) + { + fprintf (stderr, "Cannot create response socket\n"); + exit (REMANAGE_DISPLAY); + } + if (connect (fd, addr, len) == -1) + { + fprintf (stderr, "Cannot connect to xdm\n"); + exit (REMANAGE_DISPLAY); + } +#endif + buffer.data = (BYTE *) buf; + buffer.size = sizeof (buf); + buffer.pointer = 0; + buffer.count = 0; + XdmcpWriteARRAY8 (&buffer, app_resources.clientAddress); + XdmcpWriteCARD16 (&buffer, (CARD16) app_resources.connectionType); + XdmcpWriteARRAY8 (&buffer, &h->hostaddr); +#if defined(STREAMSCONN) + if( t_snd (fd, (char *)buffer.data, buffer.pointer, 0) < 0 ) + { + fprintf (stderr, "Cannot send to xdm\n"); + fflush(stderr); + t_unbind (fd); + t_close (fd); + exit (REMANAGE_DISPLAY); + } + sleep(5); /* Hack because sometimes the connection gets + closed before the data arrives on the other end. */ + t_snddis (fd,NULL); + t_unbind (fd); + t_close (fd); +#else + write (fd, (char *)buffer.data, buffer.pointer); + close (fd); +#endif + } + else + { + int i; + + printf ("%u\n", h->connectionType); + for (i = 0; i < (int)h->hostaddr.length; i++) + printf ("%u%s", h->hostaddr.data[i], + i == h->hostaddr.length - 1 ? "\n" : " "); + } +} + +/* ARGSUSED */ +static void +DoAccept (w, event, params, num_params) + Widget w; + XEvent *event; + String *params; + Cardinal *num_params; +{ + XawListReturnStruct *r; + HostName *h; + + r = XawListShowCurrent (list); + if (r->list_index == XAW_LIST_NONE) +#ifdef XKB + XkbStdBell(XtDisplay(toplevel),XtWindow(w),0,XkbBI_MinorError); +#else + XBell (XtDisplay (toplevel), 0); +#endif + else + { + for (h = hostNamedb; h; h = h->next) + if (!strcmp (r->string, h->fullname)) + { + Choose (h); + } + exit (OBEYSESS_DISPLAY); + } +} + +/* ARGSUSED */ +static void +DoCheckWilling (w, event, params, num_params) + Widget w; + XEvent *event; + String *params; + Cardinal *num_params; +{ + XawListReturnStruct *r; + HostName *h; + + r = XawListShowCurrent (list); + if (r->list_index == XAW_LIST_NONE) + return; + for (h = hostNamedb; h; h = h->next) + if (!strcmp (r->string, h->fullname)) + if (!h->willing) + XawListUnhighlight (list); +} + +/* ARGSUSED */ +static void +DoCancel (w, event, params, num_params) + Widget w; + XEvent *event; + String *params; + Cardinal *num_params; +{ + exit (OBEYSESS_DISPLAY); +} + +/* ARGSUSED */ +static void +DoPing (w, event, params, num_params) + Widget w; + XEvent *event; + String *params; + Cardinal *num_params; +{ + EmptyHostnames (); + pingTry = 0; + PingHosts ((XtPointer)NULL, (XtIntervalId *)NULL); +} + +static XtActionsRec app_actions[] = { + "Accept", DoAccept, + "Cancel", DoCancel, + "CheckWilling", DoCheckWilling, + "Ping", DoPing, +}; + +main (argc, argv) + int argc; + char **argv; +{ + Arg position[3]; + Dimension width, height; + Position x, y; + + toplevel = XtInitialize (argv[0], "Chooser", options, XtNumber(options), &argc, argv); + + XtAddConverter(XtRString, XtRARRAY8, CvtStringToARRAY8, NULL, 0); + + XtGetApplicationResources (toplevel, (XtPointer) &app_resources, resources, + XtNumber (resources), NULL, (Cardinal) 0); + + XtAddActions (app_actions, XtNumber (app_actions)); + paned = XtCreateManagedWidget ("paned", panedWidgetClass, toplevel, NULL, 0); + label = XtCreateManagedWidget ("label", labelWidgetClass, paned, NULL, 0); + viewport = XtCreateManagedWidget ("viewport", viewportWidgetClass, paned, NULL, 0); + list = XtCreateManagedWidget ("list", listWidgetClass, viewport, NULL, 0); + box = XtCreateManagedWidget ("box", boxWidgetClass, paned, NULL, 0); + cancel = XtCreateManagedWidget ("cancel", commandWidgetClass, box, NULL, 0); + acceptit = XtCreateManagedWidget ("accept", commandWidgetClass, box, NULL, 0); + ping = XtCreateManagedWidget ("ping", commandWidgetClass, box, NULL, 0); + + /* + * center ourselves on the screen + */ + XtSetMappedWhenManaged(toplevel, FALSE); + XtRealizeWidget (toplevel); + + XtSetArg (position[0], XtNwidth, &width); + XtSetArg (position[1], XtNheight, &height); + XtGetValues (toplevel, position, (Cardinal) 2); + x = (Position)(WidthOfScreen (XtScreen (toplevel)) - width) / 2; + y = (Position)(HeightOfScreen (XtScreen (toplevel)) - height) / 3; + XtSetArg (position[0], XtNx, x); + XtSetArg (position[1], XtNy, y); + XtSetValues (toplevel, position, (Cardinal) 2); + + /* + * Run + */ + XtMapWidget(toplevel); + InitXDMCP (argv + 1); + XtMainLoop (); + exit(0); + /*NOTREACHED*/ +} + +/* Converts the hex string s of length len into the byte array d. + Returns 0 if s was a legal hex string, 1 otherwise. + */ +int +FromHex (s, d, len) + char *s, *d; + int len; +{ + int t; + int ret = len&1; /* odd-length hex strings are illegal */ + while (len >= 2) + { +#define HexChar(c) ('0' <= (c) && (c) <= '9' ? (c) - '0' : (c) - 'a' + 10) + + if (!ishexdigit(*s)) + ret = 1; + t = HexChar (*s) << 4; + s++; + if (!ishexdigit(*s)) + ret = 1; + t += HexChar (*s); + s++; + *d++ = t; + len -= 2; + } + return ret; +} + +/*ARGSUSED*/ +static void +CvtStringToARRAY8 (args, num_args, fromVal, toVal) + XrmValuePtr args; + Cardinal *num_args; + XrmValuePtr fromVal; + XrmValuePtr toVal; +{ + static ARRAY8Ptr dest; + char *s; + int len; + + dest = (ARRAY8Ptr) XtMalloc (sizeof (ARRAY8)); + len = fromVal->size; + s = (char *) fromVal->addr; + if (!XdmcpAllocARRAY8 (dest, len >> 1)) + XtStringConversionWarning ((char *) fromVal->addr, XtRARRAY8); + else + { + FromHex (s, (char *) dest->data, len); + } + toVal->addr = (caddr_t) &dest; + toVal->size = sizeof (ARRAY8Ptr); +} diff --git a/config/GiveConsole b/config/GiveConsole new file mode 100644 index 0000000..ab2dee5 --- /dev/null +++ b/config/GiveConsole @@ -0,0 +1,10 @@ +#!/bin/sh +# Assign ownership of the console to the invoking user +# $Xorg: GiveConsole,v 1.3 2000/08/17 19:54:17 cpqbld Exp $ +# +# By convention, both xconsole and xterm -C check that the +# console is owned by the invoking user and is readable before attaching +# the console output. This way a random user can invoke xterm -C without +# causing serious grief. +# +chown $USER /dev/console diff --git a/config/README b/config/README new file mode 100644 index 0000000..4d49f91 --- /dev/null +++ b/config/README @@ -0,0 +1,11 @@ +$Xorg: README,v 1.3 2000/08/17 19:54:17 cpqbld Exp $ + +Xdm Sample Configuration + +This directory contains a collection of files which describe a sample +configuration of xdm. Choose between the sample Xservers.* files; copy the +appropriate one to "$(XDMDIR)/Xservers" along with the other +files in this directory. + +Only a few of the many configuration parameters which xdm can be tuned with +are set in this sample, read the xdm manual page for a complete description. diff --git a/config/TakeConsole b/config/TakeConsole new file mode 100644 index 0000000..005c5e0 --- /dev/null +++ b/config/TakeConsole @@ -0,0 +1,7 @@ +#!/bin/sh +# Reassign ownership of the console to root, this should disallow +# assignment of console output to any random users's xterm +# $Xorg: TakeConsole,v 1.3 2000/08/17 19:54:17 cpqbld Exp $ +# +chmod 622 /dev/console +chown root /dev/console diff --git a/config/Xaccess b/config/Xaccess new file mode 100644 index 0000000..b41c4c3 --- /dev/null +++ b/config/Xaccess @@ -0,0 +1,68 @@ +# $Xorg: Xaccess,v 1.3 2000/08/17 19:54:17 cpqbld Exp $ +# +# Access control file for XDMCP connections +# +# To control Direct and Broadcast access: +# +# pattern +# +# To control Indirect queries: +# +# pattern list of hostnames and/or macros ... +# +# To use the chooser: +# +# pattern CHOOSER BROADCAST +# +# or +# +# pattern CHOOSER list of hostnames and/or macros ... +# +# To define macros: +# +# %name list of hosts ... +# +# The first form tells xdm which displays to respond to itself. +# The second form tells xdm to forward indirect queries from hosts matching +# the specified pattern to the indicated list of hosts. +# The third form tells xdm to handle indirect queries using the chooser; +# the chooser is directed to send its own queries out via the broadcast +# address and display the results on the terminal. +# The fourth form is similar to the third, except instead of using the +# broadcast address, it sends DirectQuerys to each of the hosts in the list +# +# In all cases, xdm uses the first entry which matches the terminal; +# for IndirectQuery messages only entries with right hand sides can +# match, for Direct and Broadcast Query messages, only entries without +# right hand sides can match. +# + +* #any host can get a login window + +# +# To hardwire a specific terminal to a specific host, you can +# leave the terminal sending indirect queries to this host, and +# use an entry of the form: +# + +#terminal-a host-a + + +# +# The nicest way to run the chooser is to just ask it to broadcast +# requests to the network - that way new hosts show up automatically. +# Sometimes, however, the chooser can't figure out how to broadcast, +# so this may not work in all environments. +# + +* CHOOSER BROADCAST #any indirect host can get a chooser + +# +# If you'd prefer to configure the set of hosts each terminal sees, +# then just uncomment these lines (and comment the CHOOSER line above) +# and edit the %hostlist line as appropriate +# + +#%hostlist host-a host-b + +#* CHOOSER %hostlist # diff --git a/config/Xservers.fs b/config/Xservers.fs new file mode 100644 index 0000000..5c1c900 --- /dev/null +++ b/config/Xservers.fs @@ -0,0 +1,11 @@ +# $Xorg: Xservers.fs,v 1.3 2000/08/17 19:54:17 cpqbld Exp $ +# +# Xservers file, fileserver prototype (any machine without a display) +# +# Put X terminals which don't support XDMCP in this file; you will +# want to leave those terminals on and connected to the network, else +# xdm will have a tougher time managing them. +# +# Each line should look like: +# +# XterminalName:0 foreign diff --git a/config/Xservers.ws.cpp b/config/Xservers.ws.cpp new file mode 100644 index 0000000..6153daf --- /dev/null +++ b/config/Xservers.ws.cpp @@ -0,0 +1,13 @@ +XCOMM $Xorg: Xserv.ws.cpp,v 1.3 2000/08/17 19:54:17 cpqbld Exp $ +XCOMM +XCOMM Xservers file, workstation prototype +XCOMM +XCOMM This file should contain an entry to start the server on the +XCOMM local display; if you have more than one display (not screen), +XCOMM you can add entries to the list (one per line). If you also +XCOMM have some X terminals connected which do not support XDMCP, +XCOMM you can add them here as well. Each X terminal line should +XCOMM look like: +XCOMM XTerminalName:0 foreign +XCOMM +:0 local BINDIR/X diff --git a/config/Xsetup_0 b/config/Xsetup_0 new file mode 100644 index 0000000..8e30694 --- /dev/null +++ b/config/Xsetup_0 @@ -0,0 +1,3 @@ +#!/bin/sh +# $Xorg: Xsetup_0,v 1.3 2000/08/17 19:54:17 cpqbld Exp $ +xconsole -geometry 480x130-0-0 -daemon -notify -verbose -fn fixed -exitOnFail diff --git a/config/xdm-config.cpp b/config/xdm-config.cpp new file mode 100644 index 0000000..0f81104 --- /dev/null +++ b/config/xdm-config.cpp @@ -0,0 +1,19 @@ +! $Xorg: xdm-conf.cpp,v 1.3 2000/08/17 19:54:17 cpqbld Exp $ +DisplayManager.errorLogFile: XDMDIR/xdm-errors +DisplayManager.pidFile: XDMDIR/xdm-pid +DisplayManager.keyFile: XDMDIR/xdm-keys +DisplayManager.servers: XDMDIR/Xservers +DisplayManager.accessFile: XDMDIR/Xaccess +! All displays should use authorization, but we cannot be sure +! X terminals will be configured that way, so by default +! use authorization only for local displays :0, :1, etc. +DisplayManager._0.authorize: true +DisplayManager._1.authorize: true +! The following three resources set up display :0 as the console. +DisplayManager._0.setup: XDMDIR/Xsetup_0 +DisplayManager._0.startup: XDMDIR/GiveConsole +DisplayManager._0.reset: XDMDIR/TakeConsole +! +DisplayManager*resources: XDMDIR/Xresources +DisplayManager*session: XDMDIR/Xsession +DisplayManager*authComplain: false diff --git a/daemon.c b/daemon.c new file mode 100644 index 0000000..937240c --- /dev/null +++ b/daemon.c @@ -0,0 +1,146 @@ +/* $Xorg: daemon.c,v 1.4 2001/02/09 02:05:40 xorgcvs Exp $ */ +/* + +Copyright 1988, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall +not be used in advertising or otherwise to promote the sale, use or +other dealings in this Software without prior written authorization +from The Open Group. + +*/ + +/* + * xdm - display manager daemon + * Author: Keith Packard, MIT X Consortium + */ + +#include <X11/Xos.h> + +#if defined(SVR4) || defined(USG) +#include <termios.h> +#else +#include <sys/ioctl.h> +#endif +#if defined(__osf__) || defined(linux) +#define setpgrp setpgid +#endif +#ifdef hpux +#include <sys/ptyio.h> +#endif +#include <errno.h> +#ifdef X_NOT_STDC_ENV +extern int errno; +#endif +#include <sys/types.h> +#ifdef X_NOT_POSIX +#define Pid_t int +#else +#define Pid_t pid_t +#endif + +extern void exit (); + +BecomeOrphan () +{ + Pid_t child_id; + int stat; + + /* + * fork so that the process goes into the background automatically. Also + * has a nice side effect of having the child process get inherited by + * init (pid 1). + * Separate the child into its own process group before the parent + * exits. This eliminates the possibility that the child might get + * killed when the init script that's running xdm exits. + */ + + child_id = fork(); + switch (child_id) { + case 0: + /* child */ + break; + case -1: + /* error */ + LogError("daemon fork failed, errno = %d\n", errno); + break; + + default: + /* parent */ + +#if defined(SVR4) + stat = setpgid(child_id, child_id); + /* This gets error EPERM. Why? */ +#else +#if defined(SYSV) + stat = 0; /* don't know how to set child's process group */ +#else + stat = setpgrp(child_id, child_id); + if (stat != 0) + LogError("setting process grp for daemon failed, errno = %d\n", + errno); +#endif +#endif + exit (0); + } +} + +BecomeDaemon () +{ + register int i; + + /* + * Close standard file descriptors and get rid of controlling tty + */ + +#if defined(SYSV) || defined(SVR4) + setpgrp (); +#else + setpgrp (0, getpid()); +#endif + + close (0); + close (1); + close (2); + +#if !((defined(SYSV) || defined(SVR4)) && defined(i386)) + if ((i = open ("/dev/tty", O_RDWR)) >= 0) { /* did open succeed? */ +#if defined(USG) && defined(TCCLRCTTY) + int zero = 0; + (void) ioctl (i, TCCLRCTTY, &zero); +#else +#if (defined(SYSV) || defined(SVR4)) && defined(TIOCTTY) + int zero = 0; + (void) ioctl (i, TIOCTTY, &zero); +#else + (void) ioctl (i, TIOCNOTTY, (char *) 0); /* detach, BSD style */ +#endif +#endif + (void) close (i); + } +#endif /* !i386 */ + + /* + * Set up the standard file descriptors. + */ + (void) open ("/", O_RDONLY); /* root inode already in core */ + (void) dup2 (0, 1); + (void) dup2 (0, 2); +} @@ -0,0 +1,855 @@ +/* $Xorg: dm.c,v 1.5 2001/02/09 02:05:40 xorgcvs Exp $ */ +/* + +Copyright 1988, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall +not be used in advertising or otherwise to promote the sale, use or +other dealings in this Software without prior written authorization +from The Open Group. + +*/ + +/* + * xdm - display manager daemon + * Author: Keith Packard, MIT X Consortium + * + * display manager + */ + +# include "dm.h" + +# include <stdio.h> +#ifdef X_POSIX_C_SOURCE +#define _POSIX_C_SOURCE X_POSIX_C_SOURCE +#include <signal.h> +#undef _POSIX_C_SOURCE +#else +#if defined(X_NOT_POSIX) || defined(_POSIX_SOURCE) +#include <signal.h> +#else +#define _POSIX_SOURCE +#include <signal.h> +#undef _POSIX_SOURCE +#endif +#endif + +#ifndef sigmask +#define sigmask(m) (1 << ((m - 1))) +#endif + +# include <sys/stat.h> +# include <errno.h> +# include <X11/Xfuncproto.h> +#if NeedVarargsPrototypes +# include <stdarg.h> +# define Va_start(a,b) va_start(a,b) +#else +# include <varargs.h> +# define Va_start(a,b) va_start(a) +#endif + +#ifndef F_TLOCK +#ifndef X_NOT_POSIX +# include <unistd.h> +#endif +#endif + +#ifdef X_NOT_STDC_ENV +extern int errno; +#endif + + +#ifdef SVR4 +extern FILE *fdopen(); +#endif + +static void RescanServers (); +static void ScanServers (); +int Rescan; +static long ServersModTime, ConfigModTime, AccessFileModTime; +static SIGVAL StopAll (), RescanNotify (); +void StopDisplay (); +static void RestartDisplay (); +static void StartDisplays (); + +int nofork_session = 0; + +#ifndef NOXDMTITLE +static char *Title; +static int TitleLen; +#endif + +#ifndef UNRELIABLE_SIGNALS +static SIGVAL ChildNotify (); +#endif + +static int parent_pid = -1; /* PID of parent xdm process */ + +main (argc, argv) +int argc; +char **argv; +{ + int oldpid, oldumask; + char cmdbuf[1024]; + + /* make sure at least world write access is disabled */ + if (((oldumask = umask(022)) & 002) == 002) + (void) umask (oldumask); +#ifndef NOXDMTITLE + Title = argv[0]; + TitleLen = (argv[argc - 1] + strlen(argv[argc - 1])) - Title; +#endif + + /* + * Step 1 - load configuration parameters + */ + InitResources (argc, argv); + SetConfigFileTime (); + LoadDMResources (); + /* + * Only allow root to run in non-debug mode to avoid problems + */ + if (debugLevel == 0 && getuid() != 0) + { + fprintf (stderr, "Only root wants to run %s\n", argv[0]); + exit (1); + } + if (debugLevel == 0 && daemonMode) + BecomeOrphan (); + if (debugLevel >= 10) + nofork_session = 1; + if (debugLevel == 0 && daemonMode) + BecomeDaemon (); + /* SUPPRESS 560 */ + if ((oldpid = StorePid ())) + { + if (oldpid == -1) + LogError ("Can't create/lock pid file %s\n", pidFile); + else + LogError ("Can't lock pid file %s, another xdm is running (pid %d)\n", + pidFile, oldpid); + exit (1); + } + if (debugLevel == 0) + InitErrorLog (); + + if (nofork_session == 0) { + /* Clean up any old Authorization files */ + sprintf(cmdbuf, "/bin/rm -f %s/authdir/authfiles/A*", authDir); + system(cmdbuf); + } + +#ifdef XDMCP + init_session_id (); + CreateWellKnownSockets (); +#else + Debug ("xdm: not compiled for XDMCP\n"); +#endif + parent_pid = getpid (); + (void) Signal (SIGTERM, StopAll); + (void) Signal (SIGINT, StopAll); + /* + * Step 2 - Read /etc/Xservers and set up + * the socket. + * + * Keep a sub-daemon running + * for each entry + */ + SetAccessFileTime (); +#ifdef XDMCP + ScanAccessDatabase (); +#endif + ScanServers (); + StartDisplays (); + (void) Signal (SIGHUP, RescanNotify); +#ifndef UNRELIABLE_SIGNALS + (void) Signal (SIGCHLD, ChildNotify); +#endif + while ( +#ifdef XDMCP + AnyWellKnownSockets() || +#endif + AnyDisplaysLeft ()) + { + if (Rescan) + { + RescanServers (); + Rescan = 0; + } +#if defined(UNRELIABLE_SIGNALS) || !defined(XDMCP) + WaitForChild (); +#else + WaitForSomething (); +#endif + } + Debug ("Nothing left to do, exiting\n"); + exit(0); + /*NOTREACHED*/ +} + +/* ARGSUSED */ +static SIGVAL +RescanNotify (n) + int n; +{ + Debug ("Caught SIGHUP\n"); + Rescan = 1; +#ifdef SIGNALS_RESET_WHEN_CAUGHT + (void) Signal (SIGHUP, RescanNotify); +#endif +} + +static void +ScanServers () +{ + char lineBuf[10240]; + int len; + FILE *serversFile; + struct stat statb; + static DisplayType acceptableTypes[] = + { { Local, Permanent, FromFile }, + { Foreign, Permanent, FromFile }, + }; + +#define NumTypes (sizeof (acceptableTypes) / sizeof (acceptableTypes[0])) + + if (servers[0] == '/') + { + serversFile = fopen (servers, "r"); + if (serversFile == NULL) + { + LogError ("cannot access servers file %s\n", servers); + return; + } + if (ServersModTime == 0) + { + fstat (fileno (serversFile), &statb); + ServersModTime = statb.st_mtime; + } + while (fgets (lineBuf, sizeof (lineBuf)-1, serversFile)) + { + len = strlen (lineBuf); + if (lineBuf[len-1] == '\n') + lineBuf[len-1] = '\0'; + ParseDisplay (lineBuf, acceptableTypes, NumTypes); + } + fclose (serversFile); + } + else + { + ParseDisplay (servers, acceptableTypes, NumTypes); + } +} + +static void +MarkDisplay (d) +struct display *d; +{ + d->state = MissingEntry; +} + +static void +RescanServers () +{ + Debug ("rescanning servers\n"); + LogInfo ("Rescanning both config and servers files\n"); + ForEachDisplay (MarkDisplay); + SetConfigFileTime (); + ReinitResources (); + LoadDMResources (); + ScanServers (); + SetAccessFileTime (); +#ifdef XDMCP + ScanAccessDatabase (); +#endif + StartDisplays (); +} + +SetConfigFileTime () +{ + struct stat statb; + + if (stat (config, &statb) != -1) + ConfigModTime = statb.st_mtime; +} + +SetAccessFileTime () +{ + struct stat statb; + + if (stat (accessFile, &statb) != -1) + AccessFileModTime = statb.st_mtime; +} + +static +RescanIfMod () +{ + struct stat statb; + + if (config && stat (config, &statb) != -1) + { + if (statb.st_mtime != ConfigModTime) + { + Debug ("Config file %s has changed, rereading\n", config); + LogInfo ("Rereading configuration file %s\n", config); + ConfigModTime = statb.st_mtime; + ReinitResources (); + LoadDMResources (); + } + } + if (servers[0] == '/' && stat(servers, &statb) != -1) + { + if (statb.st_mtime != ServersModTime) + { + Debug ("Servers file %s has changed, rescanning\n", servers); + LogInfo ("Rereading servers file %s\n", servers); + ServersModTime = statb.st_mtime; + ForEachDisplay (MarkDisplay); + ScanServers (); + } + } +#ifdef XDMCP + if (accessFile && accessFile[0] && stat (accessFile, &statb) != -1) + { + if (statb.st_mtime != AccessFileModTime) + { + Debug ("Access file %s has changed, rereading\n", accessFile); + LogInfo ("Rereading access file %s\n", accessFile); + AccessFileModTime = statb.st_mtime; + ScanAccessDatabase (); + } + } +#endif +} + +/* + * catch a SIGTERM, kill all displays and exit + */ + +/* ARGSUSED */ +static SIGVAL +StopAll (n) + int n; +{ + if (parent_pid != getpid()) + { + /* + * We are a child xdm process that was killed by the + * master xdm before we were able to return from fork() + * and remove this signal handler. + * + * See defect XWSog08655 for more information. + */ + Debug ("Child xdm caught SIGTERM before it remove that signal.\n"); + (void) Signal (n, SIG_DFL); + TerminateProcess (getpid(), SIGTERM); + return; + } + Debug ("Shutting down entire manager\n"); +#ifdef XDMCP + DestroyWellKnownSockets (); +#endif + ForEachDisplay (StopDisplay); +#ifdef SIGNALS_RESET_WHEN_CAUGHT + /* to avoid another one from killing us unceremoniously */ + (void) Signal (SIGTERM, StopAll); + (void) Signal (SIGINT, StopAll); +#endif +} + +/* + * notice that a child has died and may need another + * sub-daemon started + */ + +int ChildReady; + +#ifndef UNRELIABLE_SIGNALS +/* ARGSUSED */ +static SIGVAL +ChildNotify (n) + int n; +{ + ChildReady = 1; +} +#endif + +WaitForChild () +{ + int pid; + struct display *d; + waitType status; +#ifndef X_NOT_POSIX + sigset_t mask, omask; +#else + int omask; +#endif + +#ifdef UNRELIABLE_SIGNALS + /* XXX classic System V signal race condition here with RescanNotify */ + if ((pid = wait (&status)) != -1) +#else +#ifndef X_NOT_POSIX + sigemptyset(&mask); + sigaddset(&mask, SIGCHLD); + sigaddset(&mask, SIGHUP); + sigprocmask(SIG_BLOCK, &mask, &omask); +#else + omask = sigblock (sigmask (SIGCHLD) | sigmask (SIGHUP)); +#endif + Debug ("signals blocked, mask was 0x%x\n", omask); + if (!ChildReady && !Rescan) +#ifndef X_NOT_POSIX + sigsuspend(&omask); +#else + sigpause (omask); +#endif + ChildReady = 0; +#ifndef X_NOT_POSIX + sigprocmask(SIG_SETMASK, &omask, (sigset_t *)NULL); +#else + sigsetmask (omask); +#endif +#ifndef X_NOT_POSIX + while ((pid = waitpid (-1, &status, WNOHANG)) > 0) +#else + while ((pid = wait3 (&status, WNOHANG, (struct rusage *) 0)) > 0) +#endif +#endif + { + Debug ("Manager wait returns pid: %d sig %d core %d code %d\n", + pid, waitSig(status), waitCore(status), waitCode(status)); + if (autoRescan) + RescanIfMod (); + /* SUPPRESS 560 */ + if ((d = FindDisplayByPid (pid))) { + d->pid = -1; + switch (waitVal (status)) { + case UNMANAGE_DISPLAY: + Debug ("Display exited with UNMANAGE_DISPLAY\n"); + StopDisplay (d); + break; + case OBEYSESS_DISPLAY: + d->startTries = 0; + Debug ("Display exited with OBEYSESS_DISPLAY\n"); + if (d->displayType.lifetime != Permanent || + d->status == zombie) + StopDisplay (d); + else + RestartDisplay (d, FALSE); + break; + default: + Debug ("Display exited with unknown status %d\n", waitVal(status)); + LogError ("Unknown session exit code %d from process %d\n", + waitVal (status), pid); + StopDisplay (d); + break; + case OPENFAILED_DISPLAY: + Debug ("Display exited with OPENFAILED_DISPLAY, try %d of %d\n", + d->startTries, d->startAttempts); + LogError ("Display %s cannot be opened\n", d->name); + /* + * no display connection was ever made, tell the + * terminal that the open attempt failed + */ +#ifdef XDMCP + if (d->displayType.origin == FromXDMCP) + SendFailed (d, "Cannot open display"); +#endif + if (d->displayType.origin == FromXDMCP || + d->status == zombie || + ++d->startTries >= d->startAttempts) + { + LogError ("Display %s is being disabled\n", d->name); + StopDisplay (d); + } + else + { + RestartDisplay (d, TRUE); + } + break; + case RESERVER_DISPLAY: + d->startTries = 0; + Debug ("Display exited with RESERVER_DISPLAY\n"); + if (d->displayType.origin == FromXDMCP || d->status == zombie) + StopDisplay(d); + else + RestartDisplay (d, TRUE); + break; + case waitCompose (SIGTERM,0,0): + d->startTries = 0; + Debug ("Display exited on SIGTERM\n"); + if (d->displayType.origin == FromXDMCP || d->status == zombie) + StopDisplay(d); + else + RestartDisplay (d, TRUE); + break; + case REMANAGE_DISPLAY: + d->startTries = 0; + Debug ("Display exited with REMANAGE_DISPLAY\n"); + /* + * XDMCP will restart the session if the display + * requests it + */ + if (d->displayType.origin == FromXDMCP || d->status == zombie) + StopDisplay(d); + else + RestartDisplay (d, FALSE); + break; + } + } + /* SUPPRESS 560 */ + else if ((d = FindDisplayByServerPid (pid))) + { + d->serverPid = -1; + switch (d->status) + { + case zombie: + Debug ("Zombie server reaped, removing display %s\n", d->name); + RemoveDisplay (d); + break; + case phoenix: + Debug ("Phoenix server arises, restarting display %s\n", d->name); + d->status = notRunning; + break; + case running: + Debug ("Server for display %s terminated unexpectedly, status %d\n", d->name, waitVal (status)); + LogError ("Server for display %s terminated unexpectedly: %d\n", d->name, waitVal (status)); + if (d->pid != -1) + { + Debug ("Terminating session pid %d\n", d->pid); + TerminateProcess (d->pid, SIGTERM); + } + break; + case notRunning: + Debug ("Server exited for notRunning session on display %s\n", d->name); + break; + } + } + else + { + Debug ("Unknown child termination, status %d\n", waitVal (status)); + } + } + StartDisplays (); +} + +static void +CheckDisplayStatus (d) +struct display *d; +{ + if (d->displayType.origin == FromFile) + { + switch (d->state) { + case MissingEntry: + StopDisplay (d); + break; + case NewEntry: + d->state = OldEntry; + case OldEntry: + if (d->status == notRunning) + StartDisplay (d); + break; + } + } +} + +static void +StartDisplays () +{ + ForEachDisplay (CheckDisplayStatus); +} + +void +StartDisplay (d) +struct display *d; +{ + int pid; + + Debug ("StartDisplay %s\n", d->name); + LoadServerResources (d); + if (d->displayType.location == Local) + { + /* don't bother pinging local displays; we'll + * certainly notice when they exit + */ + d->pingInterval = 0; + if (d->authorize) + { + Debug ("SetLocalAuthorization %s, auth %s\n", + d->name, d->authNames[0]); + SetLocalAuthorization (d); + /* + * reset the server after writing the authorization information + * to make it read the file (for compatibility with old + * servers which read auth file only on reset instead of + * at first connection) + */ + if (d->serverPid != -1 && d->resetForAuth && d->resetSignal) + kill (d->serverPid, d->resetSignal); + } + if (d->serverPid == -1 && !StartServer (d)) + { + LogError ("Server for display %s can't be started, session disabled\n", d->name); + RemoveDisplay (d); + return; + } + } + else + { + /* this will only happen when using XDMCP */ + if (d->authorizations) + SaveServerAuthorizations (d, d->authorizations, d->authNum); + } + if (!nofork_session) + pid = fork (); + else + pid = 0; + switch (pid) + { + case 0: + if (!nofork_session) { + CleanUpChild (); + (void) Signal (SIGPIPE, SIG_IGN); + } + LoadSessionResources (d); + SetAuthorization (d); + if (!WaitForServer (d)) + exit (OPENFAILED_DISPLAY); +#ifdef XDMCP + if (d->useChooser) + RunChooser (d); + else +#endif + ManageSession (d); + exit (REMANAGE_DISPLAY); + case -1: + break; + default: + Debug ("pid: %d\n", pid); + d->pid = pid; + d->status = running; + break; + } +} + +TerminateProcess (pid, signal) +{ + kill (pid, signal); +#ifdef SIGCONT + kill (pid, SIGCONT); +#endif +} + +/* + * transition from running to zombie or deleted + */ + +void +StopDisplay (d) + struct display *d; +{ + if (d->serverPid != -1) + d->status = zombie; /* be careful about race conditions */ + if (d->pid != -1) + TerminateProcess (d->pid, SIGTERM); + if (d->serverPid != -1) + TerminateProcess (d->serverPid, d->termSignal); + else + RemoveDisplay (d); +} + +/* + * transition from running to phoenix or notRunning + */ + +static void +RestartDisplay (d, forceReserver) + struct display *d; + int forceReserver; +{ + if (d->serverPid != -1 && (forceReserver || d->terminateServer)) + { + TerminateProcess (d->serverPid, d->termSignal); + d->status = phoenix; + } + else + { + d->status = notRunning; + } +} + +static FD_TYPE CloseMask; +static int max; + +RegisterCloseOnFork (fd) +int fd; +{ + FD_SET (fd, &CloseMask); + if (fd > max) + max = fd; +} + +ClearCloseOnFork (fd) +int fd; +{ + FD_CLR (fd, &CloseMask); + if (fd == max) { + while (--fd >= 0) + if (FD_ISSET (fd, &CloseMask)) + break; + max = fd; + } +} + +CloseOnFork () +{ + int fd; + + for (fd = 0; fd <= max; fd++) + if (FD_ISSET (fd, &CloseMask)) + close (fd); + FD_ZERO (&CloseMask); + max = 0; +} + +static int pidFd; +static FILE *pidFilePtr; + +StorePid () +{ + int oldpid; + + if (pidFile[0] != '\0') { + pidFd = open (pidFile, 2); + if (pidFd == -1 && errno == ENOENT) + pidFd = open (pidFile, O_RDWR|O_CREAT, 0666); + if (pidFd == -1 || !(pidFilePtr = fdopen (pidFd, "r+"))) + { + LogError ("process-id file %s cannot be opened\n", + pidFile); + return -1; + } + if (fscanf (pidFilePtr, "%d\n", &oldpid) != 1) + oldpid = -1; + fseek (pidFilePtr, 0l, 0); + if (lockPidFile) + { +#ifdef F_SETLK +#ifndef SEEK_SET +#define SEEK_SET 0 +#endif + struct flock lock_data; + lock_data.l_type = F_WRLCK; + lock_data.l_whence = SEEK_SET; + lock_data.l_start = lock_data.l_len = 0; + if (fcntl(pidFd, F_SETLK, &lock_data) == -1) + { + if (errno == EAGAIN) + return oldpid; + else + return -1; + } +#else +#ifdef LOCK_EX + if (flock (pidFd, LOCK_EX|LOCK_NB) == -1) + { + if (errno == EWOULDBLOCK) + return oldpid; + else + return -1; + } +#else + if (lockf (pidFd, F_TLOCK, 0) == -1) + { + if (errno == EACCES) + return oldpid; + else + return -1; + } +#endif +#endif + } + fprintf (pidFilePtr, "%5d\n", getpid ()); + (void) fflush (pidFilePtr); + RegisterCloseOnFork (pidFd); + } + return 0; +} + +UnlockPidFile () +{ + if (lockPidFile) +#ifdef F_SETLK + { + struct flock lock_data; + lock_data.l_type = F_UNLCK; + lock_data.l_whence = SEEK_SET; + lock_data.l_start = lock_data.l_len = 0; + (void) fcntl(pidFd, F_SETLK, &lock_data); + } +#else +#ifdef F_ULOCK + lockf (pidFd, F_ULOCK, 0); +#else + flock (pidFd, LOCK_UN); +#endif +#endif + close (pidFd); + fclose (pidFilePtr); +} + +#if NeedVarargsPrototypes +SetTitle (char *name, ...) +#else +/*VARARGS*/ +SetTitle (name, va_alist) +char *name; +va_dcl +#endif +{ +#ifndef NOXDMTITLE + char *p = Title; + int left = TitleLen; + char *s; + va_list args; + + Va_start(args,name); + *p++ = '-'; + --left; + s = name; + while (s) + { + while (*s && left > 0) + { + *p++ = *s++; + left--; + } + s = va_arg (args, char *); + } + while (left > 0) + { + *p++ = ' '; + --left; + } + va_end(args); +#endif +} @@ -0,0 +1,360 @@ +/* $Xorg: dm.h,v 1.4 2001/02/09 02:05:40 xorgcvs Exp $ */ +/* + +Copyright 1988, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall +not be used in advertising or otherwise to promote the sale, use or +other dealings in this Software without prior written authorization +from The Open Group. + +*/ + +/* + * xdm - display manager daemon + * Author: Keith Packard, MIT X Consortium + * + * dm.h + * + * public interfaces for greet/verify functionality + */ + +#include <X11/Xos.h> +#include <X11/Xfuncs.h> +#include <X11/Xmd.h> +#include <X11/Xauth.h> + +#if defined(X_POSIX_C_SOURCE) +#define _POSIX_C_SOURCE X_POSIX_C_SOURCE +#include <setjmp.h> +#include <limits.h> +#undef _POSIX_C_SOURCE +#elif defined(X_NOT_POSIX) || defined(_POSIX_SOURCE) +#include <setjmp.h> +#include <limits.h> +#else +#define _POSIX_SOURCE +#include <setjmp.h> +#include <limits.h> +#undef _POSIX_SOURCE +#endif + +/* If XDMCP symbol defined, compile to run XDMCP protocol */ + +#define XDMCP + +#ifdef XDMCP +#include <X11/Xdmcp.h> +#endif + +#ifdef pegasus +#undef dirty /* Some bozo put a macro called dirty in sys/param.h */ +#endif /* pegasus */ + +#ifndef X_NOT_POSIX +#ifdef _POSIX_SOURCE +#include <sys/wait.h> +#else +#define _POSIX_SOURCE +#include <sys/wait.h> +#undef _POSIX_SOURCE +#endif +# define waitCode(w) (WIFEXITED(w) ? WEXITSTATUS(w) : 0) +# define waitSig(w) (WIFSIGNALED(w) ? WTERMSIG(w) : 0) +# define waitCore(w) 0 /* not in POSIX. so what? */ +typedef int waitType; +#else /* X_NOT_POSIX */ +#ifdef SYSV +# define waitCode(w) (((w) >> 8) & 0x7f) +# define waitSig(w) ((w) & 0xff) +# define waitCore(w) (((w) >> 15) & 0x01) +typedef int waitType; +#else /* SYSV */ +# include <sys/wait.h> +# define waitCode(w) ((w).w_T.w_Retcode) +# define waitSig(w) ((w).w_T.w_Termsig) +# define waitCore(w) ((w).w_T.w_Coredump) +typedef union wait waitType; +#endif +#endif /* X_NOT_POSIX */ + +# define waitCompose(sig,core,code) ((sig) * 256 + (core) * 128 + (code)) +# define waitVal(w) waitCompose(waitSig(w), waitCore(w), waitCode(w)) + +typedef enum displayStatus { running, notRunning, zombie, phoenix } DisplayStatus; + +#ifndef FD_ZERO +typedef struct my_fd_set { int fds_bits[1]; } my_fd_set; +# define FD_ZERO(fdp) bzero ((fdp), sizeof (*(fdp))) +# define FD_SET(f,fdp) ((fdp)->fds_bits[(f) / (sizeof (int) * 8)] |= (1 << ((f) % (sizeof (int) * 8)))) +# define FD_CLR(f,fdp) ((fdp)->fds_bits[(f) / (sizeof (int) * 8)] &= ~(1 << ((f) % (sizeof (int) * 8)))) +# define FD_ISSET(f,fdp) ((fdp)->fds_bits[(f) / (sizeof (int) * 8)] & (1 << ((f) % (sizeof (int) * 8)))) +# define FD_TYPE my_fd_set +#else +# define FD_TYPE fd_set +#endif + +/* + * local - server runs on local host + * foreign - server runs on remote host + * permanent - session restarted when it exits + * transient - session not restarted when it exits + * fromFile - started via entry in servers file + * fromXDMCP - started with XDMCP + */ + +typedef struct displayType { + unsigned int location:1; + unsigned int lifetime:1; + unsigned int origin:1; +} DisplayType; + +# define Local 1 +# define Foreign 0 + +# define Permanent 1 +# define Transient 0 + +# define FromFile 1 +# define FromXDMCP 0 + +extern DisplayType parseDisplayType (); + +typedef enum fileState { NewEntry, OldEntry, MissingEntry } FileState; + +struct display { + struct display *next; + /* Xservers file / XDMCP information */ + char *name; /* DISPLAY name */ + char *class; /* display class (may be NULL) */ + DisplayType displayType; /* method to handle with */ + char **argv; /* program name and arguments */ + + /* display state */ + DisplayStatus status; /* current status */ + int pid; /* process id of child */ + int serverPid; /* process id of server (-1 if none) */ + FileState state; /* state during HUP processing */ + int startTries; /* current start try */ + +#ifdef XDMCP + /* XDMCP state */ + CARD32 sessionID; /* ID of active session */ + XdmcpNetaddr peer; /* display peer address */ + int peerlen; /* length of peer address */ + XdmcpNetaddr from; /* XDMCP port of display */ + int fromlen; + CARD16 displayNumber; + int useChooser; /* Run the chooser for this display */ + ARRAY8 clientAddr; /* for chooser picking */ + CARD16 connectionType; /* ... */ +#endif + /* server management resources */ + int serverAttempts; /* number of attempts at running X */ + int openDelay; /* open delay time */ + int openRepeat; /* open attempts to make */ + int openTimeout; /* abort open attempt timeout */ + int startAttempts; /* number of attempts at starting */ + int pingInterval; /* interval between XSync */ + int pingTimeout; /* timeout for XSync */ + int terminateServer;/* restart for each session */ + int grabServer; /* keep server grabbed for Login */ + int grabTimeout; /* time to wait for grab */ + int resetSignal; /* signal to reset server */ + int termSignal; /* signal to terminate server */ + int resetForAuth; /* server reads auth file at reset */ + char *keymaps; /* binary compat with DEC */ + char *greeterLib; /* greeter shared library name */ + + /* session resources */ + char *resources; /* resource file */ + char *xrdb; /* xrdb program */ + char *setup; /* Xsetup program */ + char *startup; /* Xstartup program */ + char *reset; /* Xreset program */ + char *session; /* Xsession program */ + char *userPath; /* path set for session */ + char *systemPath; /* path set for startup/reset */ + char *systemShell; /* interpreter for startup/reset */ + char *failsafeClient;/* a client to start when the session fails */ + char *chooser; /* chooser program */ + + /* authorization resources */ + int authorize; /* enable authorization */ + char **authNames; /* authorization protocol names */ + unsigned short *authNameLens; /* authorization protocol name lens */ + char *clientAuthFile;/* client specified auth file */ + char *userAuthDir; /* backup directory for tickets */ + int authComplain; /* complain when no auth for XDMCP */ + + /* information potentially derived from resources */ + int authNameNum; /* number of protocol names */ + Xauth **authorizations;/* authorization data */ + int authNum; /* number of authorizations */ + char *authFile; /* file to store authorization in */ + + int version; /* to keep dynamic greeter clued in */ + /* add new fields only after here. And preferably at the end. */ +}; + +#ifdef XDMCP + +#define PROTO_TIMEOUT (30 * 60) /* 30 minutes should be long enough */ + +struct protoDisplay { + struct protoDisplay *next; + XdmcpNetaddr address; /* UDP address */ + int addrlen; /* UDP address length */ + unsigned long date; /* creation date */ + CARD16 displayNumber; + CARD16 connectionType; + ARRAY8 connectionAddress; + CARD32 sessionID; + Xauth *fileAuthorization; + Xauth *xdmcpAuthorization; + ARRAY8 authenticationName; + ARRAY8 authenticationData; + XdmAuthKeyRec key; +}; +#endif /* XDMCP */ + +struct greet_info { + char *name; /* user name */ + char *password; /* user password */ + char *string; /* random string */ + char *passwd; /* binary compat with DEC */ + int version; /* for dynamic greeter to see */ + /* add new fields below this line, and preferably at the end */ +}; + +/* setgroups is not covered by POSIX, arg type varies */ +#if defined(SYSV) || defined(SVR4) || defined(__osf__) || defined(linux) +#define GID_T gid_t +#else +#define GID_T int +#endif + +struct verify_info { + int uid; /* user id */ + int gid; /* group id */ + char **argv; /* arguments to session */ + char **userEnviron; /* environment for session */ + char **systemEnviron;/* environment for startup/reset */ + int version; /* for dynamic greeter to see */ + /* add new fields below this line, and preferably at the end */ +}; + +/* display manager exit status definitions */ + +# define OBEYSESS_DISPLAY 0 /* obey multipleSessions resource */ +# define REMANAGE_DISPLAY 1 /* force remanage */ +# define UNMANAGE_DISPLAY 2 /* force deletion */ +# define RESERVER_DISPLAY 3 /* force server termination */ +# define OPENFAILED_DISPLAY 4 /* XOpenDisplay failed, retry */ + +#ifndef TRUE +#define TRUE 1 +#define FALSE 0 +#endif + +extern char *config; + +extern char *servers; +extern int request_port; +extern int debugLevel; +extern char *errorLogFile; +extern int daemonMode; +extern char *pidFile; +extern int lockPidFile; +extern char *authDir; +extern int autoRescan; +extern int removeDomainname; +extern char *keyFile; +extern char *accessFile; +extern char **exportList; +extern char *randomFile; +extern char *greeterLib; +extern int choiceTimeout; /* chooser choice timeout */ + +extern struct display *FindDisplayByName (), + *FindDisplayBySessionID (), + *FindDisplayByAddress (), + *FindDisplayByPid (), + *FindDisplayByServerPid (), + *NewDisplay (); + +extern struct protoDisplay *FindProtoDisplay (), + *NewProtoDisplay (); + +extern char *localHostname (); + +/* in xdmcp.c */ +extern void init_session_id(); +extern void registerHostname(); + +/* in dm.c */ +extern void StartDisplay(); + +/* in session.c */ +extern void execute(); + +/* in auth.c */ +extern void SetLocalAuthorization(); +extern void SetUserAuthorization(); +extern void RemoveUserAuthorization(); +extern void CleanUpFileName(); + +/* in protodpy.c */ +extern void DisposeProtoDisplay(); + +/* + * CloseOnFork flags + */ + +# define CLOSE_ALWAYS 0 +# define LEAVE_FOR_DISPLAY 1 + +#ifndef X_NOT_STDC_ENV +#include <stdlib.h> +#else +char *malloc(), *realloc(); +#endif + +#if defined(X_NOT_POSIX) && defined(SIGNALRETURNSINT) +#define SIGVAL int +#else +#define SIGVAL void +#endif + +#ifdef X_NOT_POSIX +#ifdef SYSV +#define SIGNALS_RESET_WHEN_CAUGHT +#define UNRELIABLE_SIGNALS +#endif +#define Setjmp(e) setjmp(e) +#define Longjmp(e,v) longjmp(e,v) +#define Jmp_buf jmp_buf +#else +#define Setjmp(e) sigsetjmp(e,1) +#define Longjmp(e,v) siglongjmp(e,v) +#define Jmp_buf sigjmp_buf +#endif + +SIGVAL (*Signal())(); diff --git a/dpylist.c b/dpylist.c new file mode 100644 index 0000000..6dcaafa --- /dev/null +++ b/dpylist.c @@ -0,0 +1,274 @@ +/* $Xorg: dpylist.c,v 1.4 2001/02/09 02:05:40 xorgcvs Exp $ */ +/* + +Copyright 1988, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall +not be used in advertising or otherwise to promote the sale, use or +other dealings in this Software without prior written authorization +from The Open Group. + +*/ + +/* + * xdm - display manager daemon + * Author: Keith Packard, MIT X Consortium + * + * a simple linked list of known displays + */ + +# include "dm.h" + +static struct display *displays; + +AnyDisplaysLeft () +{ + return displays != (struct display *) 0; +} + +ForEachDisplay (f) + void (*f)(); +{ + struct display *d, *next; + + for (d = displays; d; d = next) { + next = d->next; + (*f) (d); + } +} + +struct display * +FindDisplayByName (name) +char *name; +{ + struct display *d; + + for (d = displays; d; d = d->next) + if (!strcmp (name, d->name)) + return d; + return 0; +} + +struct display * +FindDisplayByPid (pid) +int pid; +{ + struct display *d; + + for (d = displays; d; d = d->next) + if (pid == d->pid) + return d; + return 0; +} + +struct display * +FindDisplayByServerPid (serverPid) +int serverPid; +{ + struct display *d; + + for (d = displays; d; d = d->next) + if (serverPid == d->serverPid) + return d; + return 0; +} + +#ifdef XDMCP + +struct display * +FindDisplayBySessionID (sessionID) + CARD32 sessionID; +{ + struct display *d; + + for (d = displays; d; d = d->next) + if (sessionID == d->sessionID) + return d; + return 0; +} + +struct display * +FindDisplayByAddress (addr, addrlen, displayNumber) + XdmcpNetaddr addr; + int addrlen; + CARD16 displayNumber; +{ + struct display *d; + + for (d = displays; d; d = d->next) + if (d->displayType.origin == FromXDMCP && + d->displayNumber == displayNumber && + addressEqual (d->from, d->fromlen, addr, addrlen)) + { + return d; + } + return 0; +} + +#endif /* XDMCP */ + +#define IfFree(x) if (x) free ((char *) x) + +RemoveDisplay (old) +struct display *old; +{ + struct display *d, *p; + char **x; + int i; + + p = 0; + for (d = displays; d; d = d->next) { + if (d == old) { + if (p) + p->next = d->next; + else + displays = d->next; + IfFree (d->name); + IfFree (d->class); + for (x = d->argv; x && *x; x++) + IfFree (*x); + IfFree (d->argv); + IfFree (d->resources); + IfFree (d->xrdb); + IfFree (d->setup); + IfFree (d->startup); + IfFree (d->reset); + IfFree (d->session); + IfFree (d->userPath); + IfFree (d->systemPath); + IfFree (d->systemShell); + IfFree (d->failsafeClient); + IfFree (d->chooser); + if (d->authorizations) + { + for (i = 0; i < d->authNum; i++) + XauDisposeAuth (d->authorizations[i]); + free ((char *) d->authorizations); + } + IfFree (d->clientAuthFile); + if (d->authFile) + (void) unlink (d->authFile); + IfFree (d->authFile); + IfFree (d->userAuthDir); + for (x = d->authNames; x && *x; x++) + IfFree (*x); + IfFree (d->authNames); + IfFree (d->authNameLens); +#ifdef XDMCP + IfFree (d->peer); + IfFree (d->from); + XdmcpDisposeARRAY8 (&d->clientAddr); +#endif + free ((char *) d); + break; + } + p = d; + } +} + +struct display * +NewDisplay (name, class) +char *name; +char *class; +{ + struct display *d; + + d = (struct display *) malloc (sizeof (struct display)); + if (!d) { + LogOutOfMem ("NewDisplay"); + return 0; + } + d->next = displays; + d->name = malloc ((unsigned) (strlen (name) + 1)); + if (!d->name) { + LogOutOfMem ("NewDisplay"); + free ((char *) d); + return 0; + } + strcpy (d->name, name); + if (class) + { + d->class = malloc ((unsigned) (strlen (class) + 1)); + if (!d->class) { + LogOutOfMem ("NewDisplay"); + free (d->name); + free ((char *) d); + return 0; + } + strcpy (d->class, class); + } + else + { + d->class = (char *) 0; + } + /* initialize every field to avoid possible problems */ + d->argv = 0; + d->status = notRunning; + d->pid = -1; + d->serverPid = -1; + d->state = NewEntry; + d->resources = NULL; + d->xrdb = NULL; + d->setup = NULL; + d->startup = NULL; + d->reset = NULL; + d->session = NULL; + d->userPath = NULL; + d->systemPath = NULL; + d->systemShell = NULL; + d->failsafeClient = NULL; + d->chooser = NULL; + d->authorize = FALSE; + d->authorizations = NULL; + d->authNum = 0; + d->authNameNum = 0; + d->clientAuthFile = NULL; + d->authFile = NULL; + d->userAuthDir = NULL; + d->authNames = NULL; + d->authNameLens = NULL; + d->authComplain = 1; + d->openDelay = 0; + d->openRepeat = 0; + d->openTimeout = 0; + d->startAttempts = 0; + d->startTries = 0; + d->terminateServer = 0; + d->grabTimeout = 0; +#ifdef XDMCP + d->sessionID = 0; + d->peer = 0; + d->peerlen = 0; + d->from = 0; + d->fromlen = 0; + d->displayNumber = 0; + d->useChooser = 0; + d->clientAddr.data = NULL; + d->clientAddr.length = 0; + d->connectionType = 0; +#endif + d->version = 1; /* registered with The Open Group */ + displays = d; + return d; +} + + + + @@ -0,0 +1,195 @@ +/* $Xorg: error.c,v 1.4 2001/02/09 02:05:40 xorgcvs Exp $ */ +/* + +Copyright 1988, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall +not be used in advertising or otherwise to promote the sale, use or +other dealings in this Software without prior written authorization +from The Open Group. + +*/ + +/* + * xdm - display manager daemon + * Author: Keith Packard, MIT X Consortium + * + * error.c + * + * Log display manager errors to a file as + * we generally do not have a terminal to talk to + */ + +# include "dm.h" +# include <stdio.h> +#if NeedVarargsPrototypes +# include <stdarg.h> +#else +/* this type needs to be big enough to contain int or pointer */ +typedef long Fmtarg_t; +#endif + +/*VARARGS1*/ +LogInfo( +#if NeedVarargsPrototypes + char * fmt, ...) +#else + fmt, arg1, arg2, arg3, arg4, arg5, arg6) + char *fmt; + Fmtarg_t arg1, arg2, arg3, arg4, arg5, arg6; +#endif +{ + fprintf (stderr, "xdm info (pid %d): ", getpid()); +#if NeedVarargsPrototypes + { + va_list args; + va_start(args, fmt); + vfprintf (stderr, fmt, args); + va_end(args); + } +#else + fprintf (stderr, fmt, arg1, arg2, arg3, arg4, arg5, arg6); +#endif + fflush (stderr); +} + +/*VARARGS1*/ +LogError ( +#if NeedVarargsPrototypes + char * fmt, ...) +#else + fmt, arg1, arg2, arg3, arg4, arg5, arg6) + char *fmt; + Fmtarg_t arg1, arg2, arg3, arg4, arg5, arg6; +#endif +{ + fprintf (stderr, "xdm error (pid %d): ", getpid()); +#if NeedVarargsPrototypes + { + va_list args; + va_start(args, fmt); + vfprintf (stderr, fmt, args); + va_end(args); + } +#else + fprintf (stderr, fmt, arg1, arg2, arg3, arg4, arg5, arg6); +#endif + fflush (stderr); +} + +/*VARARGS1*/ +LogPanic ( +#if NeedVarargsPrototypes + char * fmt, ...) +#else + fmt, arg1, arg2, arg3, arg4, arg5, arg6) + char *fmt; + Fmtarg_t arg1, arg2, arg3, arg4, arg5, arg6; +#endif +{ + fprintf (stderr, "xdm panic (pid %d): ", getpid()); +#if NeedVarargsPrototypes + { + va_list args; + va_start(args, fmt); + vfprintf (stderr, fmt, args); + va_end(args); + } +#else + fprintf (fmt, arg1, arg2, arg3, arg4, arg5, arg6); +#endif + fflush (stderr); + exit (1); +} + +/*VARARGS1*/ +LogOutOfMem ( +#if NeedVarargsPrototypes + char * fmt, ...) +#else + fmt, arg1, arg2, arg3, arg4, arg5, arg6) + char *fmt; + Fmtarg_t arg1, arg2, arg3, arg4, arg5, arg6; +#endif +{ + fprintf (stderr, "xdm: out of memory in routine "); +#if NeedVarargsPrototypes + { + va_list args; + va_start(args, fmt); + vfprintf (stderr, fmt, args); + va_end(args); + } +#else + fprintf (stderr, fmt, arg1, arg2, arg3, arg4, arg5, arg6); +#endif + fflush (stderr); +} + +Panic (mesg) +char *mesg; +{ + int i; + + i = creat ("/dev/console", 0666); + write (i, "panic: ", 7); + write (i, mesg, strlen (mesg)); + exit (1); +} + + +/*VARARGS1*/ +Debug ( +#if NeedVarargsPrototypes + char * fmt, ...) +#else + fmt, arg1, arg2, arg3, arg4, arg5, arg6) + char *fmt; + Fmtarg_t arg1, arg2, arg3, arg4, arg5, arg6; +#endif +{ + if (debugLevel > 0) + { +#if NeedVarargsPrototypes + va_list args; + va_start(args, fmt); + vprintf (fmt, args); + va_end(args); +#else + printf (fmt, arg1, arg2, arg3, arg4, arg5, arg6); +#endif + fflush (stdout); + } +} + +InitErrorLog () +{ + int i; + if (errorLogFile[0]) { + i = creat (errorLogFile, 0666); + if (i != -1) { + if (i != 2) { + dup2 (i, 2); + close (i); + } + } else + LogError ("Cannot open errorLogFile %s\n", errorLogFile); + } +} @@ -0,0 +1,258 @@ +/* $Xorg: file.c,v 1.5 2001/02/09 02:05:40 xorgcvs Exp $ */ +/* + +Copyright 1988, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall +not be used in advertising or otherwise to promote the sale, use or +other dealings in this Software without prior written authorization +from The Open Group. + +*/ + +/* + * xdm - display manager daemon + * Author: Keith Packard, MIT X Consortium + * + * file.c + */ + +# include "dm.h" +# include <ctype.h> + +DisplayTypeMatch (d1, d2) +DisplayType d1, d2; +{ + return d1.location == d2.location && + d1.lifetime == d2.lifetime && + d1.origin == d2.origin; +} + +static void +freeArgs (args) + char **args; +{ + char **a; + + for (a = args; *a; a++) + free (*a); + free ((char *) args); +} + +static char ** +splitIntoWords (s) + char *s; +{ + char **args, **newargs; + char *wordStart; + int nargs; + + args = 0; + nargs = 0; + while (*s) + { + while (*s && isspace (*s)) + ++s; + if (!*s || *s == '#') + break; + wordStart = s; + while (*s && *s != '#' && !isspace (*s)) + ++s; + if (!args) + { + args = (char **) malloc (2 * sizeof (char *)); + if (!args) + return NULL; + } + else + { + newargs = (char **) realloc ((char *) args, + (nargs+2)*sizeof (char *)); + if (!newargs) + { + freeArgs (args); + return NULL; + } + args = newargs; + } + args[nargs] = malloc (s - wordStart + 1); + if (!args[nargs]) + { + freeArgs (args); + return NULL; + } + strncpy (args[nargs], wordStart, s - wordStart); + args[nargs][s-wordStart] = '\0'; + ++nargs; + args[nargs] = NULL; + } + return args; +} + +static char ** +copyArgs (args) + char **args; +{ + char **a, **new, **n; + + for (a = args; *a; a++) + /* SUPPRESS 530 */ + ; + new = (char **) malloc ((a - args + 1) * sizeof (char *)); + if (!new) + return NULL; + n = new; + a = args; + /* SUPPRESS 560 */ + while ((*n++ = *a++)) + /* SUPPRESS 530 */ + ; + return new; +} + +freeSomeArgs (args, n) + char **args; + int n; +{ + char **a; + + a = args; + while (n--) + free (*a++); + free ((char *) args); +} + +ParseDisplay (source, acceptableTypes, numAcceptable) +char *source; +DisplayType *acceptableTypes; +int numAcceptable; +{ + char **args, **argv, **a; + char *name, *class, *type; + struct display *d; + int usedDefault; + DisplayType displayType; + + args = splitIntoWords (source); + if (!args) + return; + if (!args[0]) + { + LogError ("Missing display name in servers file\n"); + freeArgs (args); + return; + } + name = args[0]; + if (!args[1]) + { + LogError ("Missing display type for %s\n", args[0]); + freeArgs (args); + return; + } + displayType = parseDisplayType (args[1], &usedDefault); + class = NULL; + type = args[1]; + argv = args + 2; + /* + * extended syntax; if the second argument doesn't + * exactly match a legal display type and the third + * argument does, use the second argument as the + * display class string + */ + if (usedDefault && args[2]) + { + displayType = parseDisplayType (args[2], &usedDefault); + if (!usedDefault) + { + class = args[1]; + type = args[2]; + argv = args + 3; + } + } + while (numAcceptable) + { + if (DisplayTypeMatch (*acceptableTypes, displayType)) + break; + --numAcceptable; + ++acceptableTypes; + } + if (!numAcceptable) + { + LogError ("Unacceptable display type %s for display %s\n", + type, name); + } + d = FindDisplayByName (name); + if (d) + { + d->state = OldEntry; + if (class && strcmp (d->class, class)) + { + char *newclass; + + newclass = malloc ((unsigned) (strlen (class) + 1)); + if (newclass) + { + free (d->class); + strcpy (newclass, class); + d->class = newclass; + } + } + Debug ("Found existing display: %s %s %s", d->name, d->class , type); + freeArgs (d->argv); + } + else + { + d = NewDisplay (name, class); + Debug ("Found new display: %s %s %s", + d->name, d->class ? d->class : "", type); + } + d->displayType = displayType; + d->argv = copyArgs (argv); + for (a = d->argv; a && *a; a++) + Debug (" %s", *a); + Debug ("\n"); + freeSomeArgs (args, argv - args); +} + +static struct displayMatch { + char *name; + DisplayType type; +} displayTypes[] = { + "local", { Local, Permanent, FromFile }, + "foreign", { Foreign, Permanent, FromFile }, + 0, { Local, Permanent, FromFile }, +}; + +DisplayType +parseDisplayType (string, usedDefault) + char *string; + int *usedDefault; +{ + struct displayMatch *d; + + for (d = displayTypes; d->name; d++) + if (!strcmp (d->name, string)) + { + *usedDefault = 0; + return d->type; + } + *usedDefault = 1; + return d->type; +} diff --git a/genauth.c b/genauth.c new file mode 100644 index 0000000..a4f8ced --- /dev/null +++ b/genauth.c @@ -0,0 +1,228 @@ +/* $Xorg: genauth.c,v 1.5 2001/02/09 02:05:40 xorgcvs Exp $ */ +/* + +Copyright 1988, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall +not be used in advertising or otherwise to promote the sale, use or +other dealings in this Software without prior written authorization +from The Open Group. + +*/ + +/* + * xdm - display manager daemon + * Author: Keith Packard, MIT X Consortium + */ + +# include <X11/Xauth.h> +# include <X11/Xos.h> +# include "dm.h" + +#include <errno.h> + +#ifdef X_NOT_STDC_ENV +#define Time_t long +extern Time_t time (); +extern int errno; +#else +#include <time.h> +#define Time_t time_t +#endif + +static unsigned char key[8]; + +#ifdef HASXDMAUTH + +typedef unsigned char auth_cblock[8]; /* block size */ + +typedef struct auth_ks_struct { auth_cblock _; } auth_wrapper_schedule[16]; + +extern void _XdmcpWrapperToOddParity(); + +static +longtochars (l, c) + long l; + unsigned char *c; +{ + c[0] = (l >> 24) & 0xff; + c[1] = (l >> 16) & 0xff; + c[2] = (l >> 8) & 0xff; + c[3] = l & 0xff; +} + +#endif + +# define FILE_LIMIT 1024 /* no more than this many buffers */ + +static int +sumFile (name, sum) +char *name; +long sum[2]; +{ + long buf[1024*2]; + int cnt; + int fd; + int loops; + int reads; + int i; + int ret_status = 0; + + fd = open (name, 0); + if (fd < 0) { + LogError("Cannot open randomFile \"%s\", errno = %d\n", name, errno); + return 0; + } +#ifdef FRAGILE_DEV_MEM + if (strcmp(name, "/dev/mem") == 0) lseek (fd, (off_t) 0x100000, SEEK_SET); +#endif + reads = FILE_LIMIT; + sum[0] = 0; + sum[1] = 0; + while ((cnt = read (fd, (char *) buf, sizeof (buf))) > 0 && --reads > 0) { + loops = cnt / (2 * sizeof (long)); + for (i = 0; i < loops; i+= 2) { + sum[0] += buf[i]; + sum[1] += buf[i+1]; + ret_status = 1; + } + } + if (cnt < 0) + LogError("Cannot read randomFile \"%s\", errno = %d\n", name, errno); + close (fd); + return ret_status; +} + +#ifdef HASXDMAUTH + +static +InitXdmcpWrapper () +{ + long sum[2]; + unsigned char tmpkey[8]; + + if (!sumFile (randomFile, sum)) { + sum[0] = time ((Time_t *) 0); + sum[1] = time ((Time_t *) 0); + } + longtochars (sum[0], tmpkey+0); + longtochars (sum[1], tmpkey+4); + tmpkey[0] = 0; + _XdmcpWrapperToOddParity (tmpkey, key); +} + +#endif + +#ifndef HASXDMAUTH +/* A random number generator that is more unpredictable + than that shipped with some systems. + This code is taken from the C standard. */ + +static unsigned long int next = 1; + +static int +xdm_rand() +{ + next = next * 1103515245 + 12345; + return (unsigned int)(next/65536) % 32768; +} + +static void +xdm_srand(seed) + unsigned int seed; +{ + next = seed; +} +#endif /* no HASXDMAUTH */ + +GenerateAuthData (auth, len) +char *auth; +int len; +{ + long ldata[2]; + +#ifdef ITIMER_REAL + { + struct timeval now; + + X_GETTIMEOFDAY (&now); + ldata[0] = now.tv_usec; + ldata[1] = now.tv_sec; + } +#else + { + long time (); + + ldata[0] = time ((long *) 0); + ldata[1] = getpid (); + } +#endif +#ifdef HASXDMAUTH + { + int bit; + int i; + auth_wrapper_schedule schedule; + unsigned char data[8]; + static int xdmcpAuthInited; + + longtochars (ldata[0], data+0); + longtochars (ldata[1], data+4); + if (!xdmcpAuthInited) + { + InitXdmcpWrapper (); + xdmcpAuthInited = 1; + } + _XdmcpAuthSetup (key, schedule); + for (i = 0; i < len; i++) { + auth[i] = 0; + for (bit = 1; bit < 256; bit <<= 1) { + _XdmcpAuthDoIt (data, data, schedule, 1); + if (data[0] + data[1] & 0x4) + auth[i] |= bit; + } + } + } +#else + { + int seed; + int value; + int i; + static long localkey[2] = {0,0}; + + if ( (localkey[0] == 0) && (localkey[1] == 0) ) { + if (!sumFile (randomFile, localkey)) { + localkey[0] = 1; /* To keep from continually calling sumFile() */ + } + } + + seed = (ldata[0]+localkey[0]) + ((ldata[1]+localkey[1]) << 16); + xdm_srand (seed); + for (i = 0; i < len; i++) + { + value = xdm_rand (); + auth[i] = (value & 0xff00) >> 8; + } + value = len; + if (value > sizeof (key)) + value = sizeof (key); + memmove( (char *) key, auth, value); + } +#endif +} @@ -0,0 +1,187 @@ +/* $Xorg: greet.h,v 1.4 2001/02/09 02:05:40 xorgcvs Exp $ */ +/* + +Copyright 1994, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall +not be used in advertising or otherwise to promote the sale, use or +other dealings in this Software without prior written authorization +from The Open Group. + +*/ + +/* + * greet.h - interface to xdm's dynamically-loadable modular greeter + */ + +#include <X11/Xlib.h> + +struct dlfuncs { + int (*_PingServer)(); + int (*_SessionPingFailed)(); + int (*_Debug)(); + int (*_RegisterCloseOnFork)(); + int (*_SecureDisplay)(); + int (*_UnsecureDisplay)(); + int (*_ClearCloseOnFork)(); + int (*_SetupDisplay)(); + int (*_LogError)(); + int (*_SessionExit)(); + int (*_DeleteXloginResources)(); + int (*_source)(); + char **(*_defaultEnv)(); + char **(*_setEnv)(); + char **(*_parseArgs)(); + int (*_printEnv)(); + char **(*_systemEnv)(); + int (*_LogOutOfMem)(); + void (*_setgrent)(); /* no longer used */ + struct group *(*_getgrent)(); /* no longer used */ + void (*_endgrent)(); /* no longer used */ +#ifdef USESHADOW + struct spwd *(*_getspnam)(); + void (*_endspent)(); +#endif + struct passwd *(*_getpwnam)(); + char *(*_crypt)(); +}; + +/* + * Return values for GreetUser(); + * Values must be explictly defined because the greet library + * may come from a different vendor. + * Negative values indicate an error. + */ +typedef enum { + Greet_Session_Over = 0, /* session managed and over */ + Greet_Success = 1, /* greet succeeded, session not managed */ + Greet_Failure = -1 /* greet failed */ +} greet_user_rtn; + +/* + * GreetUser can either handle the user's session or allow xdm to do it. + * The return or exit status of GreetUser indicates to xdm whether it + * should start a session. + * + * GreetUser is passed the xdm struct display pointer, a pointer to a + * Display, and pointers to greet and verify structs. If it expectes xdm + * to run the session, it fills in the Display pointer and the fields + * of the greet and verify structs. + * + * The verify struct includes the uid, gid, arguments to run the session, + * environment for the session, and environment for startup/reset. + * + * The greet struct includes the user's name and password but these are + * really only needed if xdm is compiled with a user-based authorization + * option such as SECURE_RPC or K5AUTH. + */ + +extern greet_user_rtn GreetUser( +#if NeedFunctionPrototypes + struct display *d, + Display **dpy, + struct verify_info *verify, + struct greet_info *greet, + struct dlfuncs *dlfcns +#endif +); + +typedef greet_user_rtn (*GreetUserProc)( +#if NeedFunctionPrototypes + struct display *, + Display **, + struct verify_info *, + struct greet_info *, + struct dlfuncs *dlfcns +#endif +); + +#ifdef GREET_LIB +/* + * The greeter uses some symbols from the main xdm executable. Since some + * dynamic linkers are broken, we need to fix things up so that the symbols + * are referenced indirectly through function pointers. The definitions + * here, are used to hold the pointers to the functions in the main xdm + * executable. The pointers are filled in when the GreetUser function is + * called, with the pointer values passed as a paramter. + */ + +extern int (*__xdm_PingServer)(); +extern int (*__xdm_SessionPingFailed)(); +extern int (*__xdm_Debug)(); +extern int (*__xdm_RegisterCloseOnFork)(); +extern int (*__xdm_SecureDisplay)(); +extern int (*__xdm_UnsecureDisplay)(); +extern int (*__xdm_ClearCloseOnFork)(); +extern int (*__xdm_SetupDisplay)(); +extern int (*__xdm_LogError)(); +extern int (*__xdm_SessionExit)(); +extern int (*__xdm_DeleteXloginResources)(); +extern int (*__xdm_source)(); +extern char **(*__xdm_defaultEnv)(); +extern char **(*__xdm_setEnv)(); +extern char **(*__xdm_parseArgs)(); +extern int (*__xdm_printEnv)(); +extern char **(*__xdm_systemEnv)(); +extern int (*__xdm_LogOutOfMem)(); +extern void (*__xdm_setgrent)(); +extern struct group *(*__xdm_getgrent)(); +extern void (*__xdm_endgrent)(); +#ifdef USESHADOW +extern struct spwd *(*__xdm_getspnam)(); +extern void (*__xdm_endspent)(); +#endif +extern struct passwd *(*__xdm_getpwnam)(); +extern char *(*__xdm_crypt)(); + +/* + * Force the shared library to call through the function pointer + * initialized during the initial call into the library. + */ + +#define PingServer (*__xdm_PingServer) +#define SessionPingFailed (*__xdm_SessionPingFailed) +#define Debug (*__xdm_Debug) +#define RegisterCloseOnFork (*__xdm_RegisterCloseOnFork) +#define SecureDisplay (*__xdm_SecureDisplay) +#define UnsecureDisplay (*__xdm_UnsecureDisplay) +#define ClearCloseOnFork (*__xdm_ClearCloseOnFork) +#define SetupDisplay (*__xdm_SetupDisplay) +#define LogError (*__xdm_LogError) +#define SessionExit (*__xdm_SessionExit) +#define DeleteXloginResources (*__xdm_DeleteXloginResources) +#define source (*__xdm_source) +#define defaultEnv (*__xdm_defaultEnv) +#define setEnv (*__xdm_setEnv) +#define parseArgs (*__xdm_parseArgs) +#define printEnv (*__xdm_printEnv) +#define systemEnv (*__xdm_systemEnv) +#define LogOutOfMem (*__xdm_LogOutOfMem) +#define setgrent (*__xdm_setgrent) +#define getgrent (*__xdm_getgrent) +#define endgrent (*__xdm_endgrent) +#ifdef USESHADOW +#define getspnam (*__xdm_getspnam) +#define endspent (*__xdm_endspent) +#endif +#define getpwnam (*__xdm_getpwnam) +#define crypt (*__xdm_crypt) + +#endif /* GREET_LIB */ diff --git a/greeter/Login.c b/greeter/Login.c new file mode 100644 index 0000000..7650774 --- /dev/null +++ b/greeter/Login.c @@ -0,0 +1,904 @@ +/* $Xorg: Login.c,v 1.4 2001/02/09 02:05:41 xorgcvs Exp $ */ +/* + +Copyright 1988, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall +not be used in advertising or otherwise to promote the sale, use or +other dealings in this Software without prior written authorization +from The Open Group. + +*/ + +/* + * xdm - display manager daemon + * Author: Keith Packard, MIT X Consortium + * + * Login.c + */ + +# include <X11/IntrinsicP.h> +# include <X11/StringDefs.h> +# include <X11/keysym.h> +# include <X11/Xfuncs.h> + +# include <stdio.h> + +# include "dm.h" +# include "greet.h" +# include "LoginP.h" + +#define offset(field) XtOffsetOf(LoginRec, login.field) +#define goffset(field) XtOffsetOf(WidgetRec, core.field) + +static XtResource resources[] = { + {XtNwidth, XtCWidth, XtRDimension, sizeof(Dimension), + goffset(width), XtRImmediate, (XtPointer) 0}, + {XtNheight, XtCHeight, XtRDimension, sizeof(Dimension), + goffset(height), XtRImmediate, (XtPointer) 0}, + {XtNx, XtCX, XtRPosition, sizeof (Position), + goffset(x), XtRImmediate, (XtPointer) -1}, + {XtNy, XtCY, XtRPosition, sizeof (Position), + goffset(y), XtRImmediate, (XtPointer) -1}, + {XtNforeground, XtCForeground, XtRPixel, sizeof(Pixel), + offset(textpixel), XtRString, XtDefaultForeground}, + {XtNpromptColor, XtCForeground, XtRPixel, sizeof(Pixel), + offset(promptpixel), XtRString, XtDefaultForeground}, + {XtNgreetColor, XtCForeground, XtRPixel, sizeof(Pixel), + offset(greetpixel), XtRString, XtDefaultForeground}, + {XtNfailColor, XtCForeground, XtRPixel, sizeof (Pixel), + offset(failpixel), XtRString, XtDefaultForeground}, + {XtNfont, XtCFont, XtRFontStruct, sizeof (XFontStruct *), + offset (font), XtRString, "*-new century schoolbook-medium-r-normal-*-180-*"}, + {XtNpromptFont, XtCFont, XtRFontStruct, sizeof (XFontStruct *), + offset (promptFont), XtRString, "*-new century schoolbook-bold-r-normal-*-180-*"}, + {XtNgreetFont, XtCFont, XtRFontStruct, sizeof (XFontStruct *), + offset (greetFont), XtRString, "*-new century schoolbook-bold-i-normal-*-240-*"}, + {XtNfailFont, XtCFont, XtRFontStruct, sizeof (XFontStruct *), + offset (failFont), XtRString, "*-new century schoolbook-bold-r-normal-*-180-*"}, + {XtNgreeting, XtCGreeting, XtRString, sizeof (char *), + offset(greeting), XtRString, "X Window System"}, + {XtNunsecureGreeting, XtCGreeting, XtRString, sizeof (char *), + offset(unsecure_greet), XtRString, "This is an unsecure session"}, + {XtNnamePrompt, XtCNamePrompt, XtRString, sizeof (char *), + offset(namePrompt), XtRString, "Login: "}, + {XtNpasswdPrompt, XtCPasswdPrompt, XtRString, sizeof (char *), + offset(passwdPrompt), XtRString, "Password: "}, + {XtNfail, XtCFail, XtRString, sizeof (char *), + offset(fail), XtRString, "Login incorrect"}, + {XtNfailTimeout, XtCFailTimeout, XtRInt, sizeof (int), + offset(failTimeout), XtRImmediate, (XtPointer) 10}, + {XtNnotifyDone, XtCCallback, XtRFunction, sizeof (XtPointer), + offset(notify_done), XtRFunction, (XtPointer) 0}, + {XtNsessionArgument, XtCSessionArgument, XtRString, sizeof (char *), + offset(sessionArg), XtRString, (XtPointer) 0 }, + {XtNsecureSession, XtCSecureSession, XtRBoolean, sizeof (Boolean), + offset(secure_session), XtRImmediate, False }, + {XtNallowAccess, XtCAllowAccess, XtRBoolean, sizeof (Boolean), + offset(allow_access), XtRImmediate, False } +}; + +#undef offset +#undef goffset + +# define TEXT_X_INC(w) ((w)->login.font->max_bounds.width) +# define TEXT_Y_INC(w) ((w)->login.font->max_bounds.ascent +\ + (w)->login.font->max_bounds.descent) +# define PROMPT_X_INC(w) ((w)->login.promptFont->max_bounds.width) +# define PROMPT_Y_INC(w) ((w)->login.promptFont->max_bounds.ascent +\ + (w)->login.promptFont->max_bounds.descent) +# define GREET_X_INC(w) ((w)->login.greetFont->max_bounds.width) +# define GREET_Y_INC(w) ((w)->login.greetFont->max_bounds.ascent +\ + (w)->login.greetFont->max_bounds.descent) +# define FAIL_X_INC(w) ((w)->login.failFont->max_bounds.width) +# define FAIL_Y_INC(w) ((w)->login.failFont->max_bounds.ascent +\ + (w)->login.failFont->max_bounds.descent) + +# define Y_INC(w) max (TEXT_Y_INC(w), PROMPT_Y_INC(w)) + +# define LOGIN_PROMPT_W(w) (XTextWidth (w->login.promptFont,\ + w->login.namePrompt,\ + strlen (w->login.namePrompt))) +# define PASS_PROMPT_W(w) (XTextWidth (w->login.promptFont,\ + w->login.passwdPrompt,\ + strlen (w->login.passwdPrompt))) +# define PROMPT_W(w) (max(LOGIN_PROMPT_W(w), PASS_PROMPT_W(w))) +# define GREETING(w) ((w)->login.secure_session && !(w)->login.allow_access ?\ + (w)->login.greeting : (w)->login.unsecure_greet) +# define GREET_X(w) ((int)(w->core.width - XTextWidth (w->login.greetFont,\ + GREETING(w), strlen (GREETING(w)))) / 2) +# define GREET_Y(w) (GREETING(w)[0] ? 2 * GREET_Y_INC (w) : 0) +# define GREET_W(w) (max (XTextWidth (w->login.greetFont,\ + w->login.greeting, strlen (w->login.greeting)), \ + XTextWidth (w->login.greetFont,\ + w->login.unsecure_greet, strlen (w->login.unsecure_greet)))) +# define LOGIN_X(w) (2 * PROMPT_X_INC(w)) +# define LOGIN_Y(w) (GREET_Y(w) + GREET_Y_INC(w) +\ + w->login.greetFont->max_bounds.ascent + Y_INC(w)) +# define LOGIN_W(w) (w->core.width - 6 * TEXT_X_INC(w)) +# define LOGIN_H(w) (3 * Y_INC(w) / 2) +# define LOGIN_TEXT_X(w)(LOGIN_X(w) + PROMPT_W(w)) +# define PASS_X(w) (LOGIN_X(w)) +# define PASS_Y(w) (LOGIN_Y(w) + 8 * Y_INC(w) / 5) +# define PASS_W(w) (LOGIN_W(w)) +# define PASS_H(w) (LOGIN_H(w)) +# define PASS_TEXT_X(w) (PASS_X(w) + PROMPT_W(w)) +# define FAIL_X(w) ((int)(w->core.width - XTextWidth (w->login.failFont,\ + w->login.fail, strlen (w->login.fail))) / 2) +# define FAIL_Y(w) (PASS_Y(w) + 2 * FAIL_Y_INC (w) +\ + w->login.failFont->max_bounds.ascent) +# define FAIL_W(w) (XTextWidth (w->login.failFont,\ + w->login.fail, strlen (w->login.fail))) + +# define PAD_X(w) (2 * (LOGIN_X(w) + max (GREET_X_INC(w), FAIL_X_INC(w)))) + +# define PAD_Y(w) (max (max (Y_INC(w), GREET_Y_INC(w)),\ + FAIL_Y_INC(w))) + +static void Initialize(), Realize(), Destroy(), Redisplay(); +static Boolean SetValues(); +static void draw_it (); + +static int max (a,b) { return a > b ? a : b; } + +static void +EraseName (w, cursor) + LoginWidget w; + int cursor; +{ + int x; + + x = LOGIN_TEXT_X (w); + if (cursor > 0) + x += XTextWidth (w->login.font, w->login.data.name, cursor); + XDrawString (XtDisplay(w), XtWindow (w), w->login.bgGC, x, LOGIN_Y(w), + w->login.data.name + cursor, strlen (w->login.data.name + cursor)); +} + +static void +DrawName (w, cursor) + LoginWidget w; + int cursor; +{ + int x; + + x = LOGIN_TEXT_X (w); + if (cursor > 0) + x += XTextWidth (w->login.font, w->login.data.name, cursor); + XDrawString (XtDisplay(w), XtWindow (w), w->login.textGC, x, LOGIN_Y(w), + w->login.data.name + cursor, strlen (w->login.data.name + cursor)); +} + +static void +realizeCursor (w, gc) + LoginWidget w; + GC gc; +{ + int x, y; + int height, width; + + switch (w->login.state) { + case GET_NAME: + x = LOGIN_TEXT_X (w); + y = LOGIN_Y (w); + height = w->login.font->max_bounds.ascent + w->login.font->max_bounds.descent; + width = 1; + if (w->login.cursor > 0) + x += XTextWidth (w->login.font, w->login.data.name, w->login.cursor); + break; + case GET_PASSWD: + x = PASS_TEXT_X (w); + y = PASS_Y (w); + height = w->login.font->max_bounds.ascent + w->login.font->max_bounds.descent; + width = 1; + break; + default: + return; + } + XFillRectangle (XtDisplay (w), XtWindow (w), gc, + x, y - w->login.font->max_bounds.ascent, width, height); +} + +static void +EraseFail (w) + LoginWidget w; +{ + int x = FAIL_X(w); + int y = FAIL_Y(w); + + XSetForeground (XtDisplay (w), w->login.failGC, + w->core.background_pixel); + XDrawString (XtDisplay (w), XtWindow (w), w->login.failGC, + x, y, + w->login.fail, strlen (w->login.fail)); + w->login.failUp = 0; + XSetForeground (XtDisplay (w), w->login.failGC, + w->login.failpixel); +} + +static void +XorCursor (w) + LoginWidget w; +{ + realizeCursor (w, w->login.xorGC); +} + +static void +RemoveFail (w) + LoginWidget w; +{ + if (w->login.failUp) + EraseFail (w); +} + +static void +EraseCursor (w) + LoginWidget (w); +{ + realizeCursor (w, w->login.bgGC); +} + +/*ARGSUSED*/ +void failTimeout (client_data, id) + XtPointer client_data; + XtIntervalId * id; +{ + LoginWidget w = (LoginWidget)client_data; + + Debug ("failTimeout\n"); + EraseFail (w); +} + +DrawFail (ctx) + Widget ctx; +{ + LoginWidget w; + + w = (LoginWidget) ctx; + XorCursor (w); + ResetLogin (w); + XorCursor (w); + w->login.failUp = 1; + RedrawFail (w); + if (w->login.failTimeout > 0) { + Debug ("failTimeout: %d\n", w->login.failTimeout); + XtAppAddTimeOut(XtWidgetToApplicationContext ((Widget)w), + w->login.failTimeout * 1000, + failTimeout, (XtPointer) w); + } +} + +RedrawFail (w) + LoginWidget w; +{ + int x = FAIL_X(w); + int y = FAIL_Y(w); + + if (w->login.failUp) + XDrawString (XtDisplay (w), XtWindow (w), w->login.failGC, + x, y, + w->login.fail, strlen (w->login.fail)); +} + +static void +draw_it (w) + LoginWidget w; +{ + EraseCursor (w); + if (GREETING(w)[0]) + XDrawString (XtDisplay (w), XtWindow (w), w->login.greetGC, + GREET_X(w), GREET_Y(w), + GREETING(w), strlen (GREETING(w))); + XDrawString (XtDisplay (w), XtWindow (w), w->login.promptGC, + LOGIN_X(w), LOGIN_Y(w), + w->login.namePrompt, strlen (w->login.namePrompt)); + XDrawString (XtDisplay (w), XtWindow (w), w->login.promptGC, + PASS_X(w), PASS_Y(w), + w->login.passwdPrompt, strlen (w->login.passwdPrompt)); + RedrawFail (w); + DrawName (w, 0); + XorCursor (w); + /* + * The GrabKeyboard here is needed only because of + * a bug in the R3 server -- the keyboard is grabbed on + * the root window, and the server won't dispatch events + * to the focus window unless the focus window is a ancestor + * of the grab window. Bug in server already found and fixed, + * compatibility until at least R4. + */ + if (XGrabKeyboard (XtDisplay (w), XtWindow (w), False, GrabModeAsync, + GrabModeAsync, CurrentTime) != GrabSuccess) + { + XSetInputFocus (XtDisplay (w), XtWindow (w), + RevertToPointerRoot, CurrentTime); + } +} + +/*ARGSUSED*/ +static void +DeleteBackwardChar (ctxw, event, params, num_params) + Widget ctxw; + XEvent *event; + String *params; + Cardinal *num_params; +{ + LoginWidget ctx = (LoginWidget)ctxw; + + XorCursor (ctx); + RemoveFail (ctx); + if (ctx->login.cursor > 0) { + ctx->login.cursor--; + switch (ctx->login.state) { + case GET_NAME: + EraseName (ctx, ctx->login.cursor); + strcpy (ctx->login.data.name + ctx->login.cursor, + ctx->login.data.name + ctx->login.cursor + 1); + DrawName (ctx, ctx->login.cursor); + break; + case GET_PASSWD: + strcpy (ctx->login.data.passwd + ctx->login.cursor, + ctx->login.data.passwd + ctx->login.cursor + 1); + break; + } + } + XorCursor (ctx); +} + +/*ARGSUSED*/ +static void +DeleteForwardChar (ctxw, event, params, num_params) + Widget ctxw; + XEvent *event; + String *params; + Cardinal *num_params; +{ + LoginWidget ctx = (LoginWidget)ctxw; + + XorCursor (ctx); + RemoveFail (ctx); + switch (ctx->login.state) { + case GET_NAME: + if (ctx->login.cursor < (int)strlen (ctx->login.data.name)) { + EraseName (ctx, ctx->login.cursor); + strcpy (ctx->login.data.name + ctx->login.cursor, + ctx->login.data.name + ctx->login.cursor + 1); + DrawName (ctx, ctx->login.cursor); + } + break; + case GET_PASSWD: + if (ctx->login.cursor < (int)strlen (ctx->login.data.passwd)) { + strcpy (ctx->login.data.passwd + ctx->login.cursor, + ctx->login.data.passwd + ctx->login.cursor + 1); + } + break; + } + XorCursor (ctx); +} + +/*ARGSUSED*/ +static void +MoveBackwardChar (ctxw, event, params, num_params) + Widget ctxw; + XEvent *event; + String *params; + Cardinal *num_params; +{ + LoginWidget ctx = (LoginWidget)ctxw; + + XorCursor (ctx); + RemoveFail (ctx); + if (ctx->login.cursor > 0) + ctx->login.cursor--; + XorCursor (ctx); +} + +/*ARGSUSED*/ +static void +MoveForwardChar (ctxw, event, params, num_params) + Widget ctxw; + XEvent *event; + String *params; + Cardinal *num_params; +{ + LoginWidget ctx = (LoginWidget)ctxw; + + XorCursor (ctx); + RemoveFail (ctx); + switch (ctx->login.state) { + case GET_NAME: + if (ctx->login.cursor < (int)strlen(ctx->login.data.name)) + ++ctx->login.cursor; + break; + case GET_PASSWD: + if (ctx->login.cursor < (int)strlen(ctx->login.data.passwd)) + ++ctx->login.cursor; + break; + } + XorCursor (ctx); +} + +/*ARGSUSED*/ +static void +MoveToBegining (ctxw, event, params, num_params) + Widget ctxw; + XEvent *event; + String *params; + Cardinal *num_params; +{ + LoginWidget ctx = (LoginWidget)ctxw; + + XorCursor (ctx); + RemoveFail (ctx); + ctx->login.cursor = 0; + XorCursor (ctx); +} + +/*ARGSUSED*/ +static void +MoveToEnd (ctxw, event, params, num_params) + Widget ctxw; + XEvent *event; + String *params; + Cardinal *num_params; +{ + LoginWidget ctx = (LoginWidget)ctxw; + + XorCursor (ctx); + RemoveFail (ctx); + switch (ctx->login.state) { + case GET_NAME: + ctx->login.cursor = strlen (ctx->login.data.name); + break; + case GET_PASSWD: + ctx->login.cursor = strlen (ctx->login.data.passwd); + break; + } + XorCursor (ctx); +} + +/*ARGSUSED*/ +static void +EraseToEndOfLine (ctxw, event, params, num_params) + Widget ctxw; + XEvent *event; + String *params; + Cardinal *num_params; +{ + LoginWidget ctx = (LoginWidget)ctxw; + + XorCursor (ctx); + RemoveFail (ctx); + switch (ctx->login.state) { + case GET_NAME: + EraseName (ctx, ctx->login.cursor); + ctx->login.data.name[ctx->login.cursor] = '\0'; + break; + case GET_PASSWD: + ctx->login.data.passwd[ctx->login.cursor] = '\0'; + break; + } + XorCursor (ctx); +} + +/*ARGSUSED*/ +static void +EraseLine (ctxw, event, params, num_params) + Widget ctxw; + XEvent *event; + String *params; + Cardinal *num_params; +{ + MoveToBegining (ctxw, event, params, num_params); + EraseToEndOfLine (ctxw, event, params, num_params); +} + +/*ARGSUSED*/ +static void +FinishField (ctxw, event, params, num_params) + Widget ctxw; + XEvent *event; + String *params; + Cardinal *num_params; +{ + LoginWidget ctx = (LoginWidget)ctxw; + + XorCursor (ctx); + RemoveFail (ctx); + switch (ctx->login.state) { + case GET_NAME: + ctx->login.state = GET_PASSWD; + ctx->login.cursor = 0; + break; + case GET_PASSWD: + ctx->login.state = DONE; + ctx->login.cursor = 0; + (*ctx->login.notify_done) (ctx, &ctx->login.data, NOTIFY_OK); + break; + } + XorCursor (ctx); +} + +/*ARGSUSED*/ +static void +AllowAccess (ctxw, event, params, num_params) + Widget ctxw; + XEvent *event; + String *params; + Cardinal *num_params; +{ + LoginWidget ctx = (LoginWidget)ctxw; + Arg arglist[1]; + Boolean allow; + + RemoveFail (ctx); + XtSetArg (arglist[0], XtNallowAccess, (char *) &allow); + XtGetValues ((Widget) ctx, arglist, 1); + XtSetArg (arglist[0], XtNallowAccess, !allow); + XtSetValues ((Widget) ctx, arglist, 1); +} + +/*ARGSUSED*/ +static void +SetSessionArgument (ctxw, event, params, num_params) + Widget ctxw; + XEvent *event; + String *params; + Cardinal *num_params; +{ + LoginWidget ctx = (LoginWidget)ctxw; + + RemoveFail (ctx); + if (ctx->login.sessionArg) + XtFree (ctx->login.sessionArg); + ctx->login.sessionArg = 0; + if (*num_params > 0) { + ctx->login.sessionArg = XtMalloc (strlen (params[0]) + 1); + if (ctx->login.sessionArg) + strcpy (ctx->login.sessionArg, params[0]); + else + LogOutOfMem ("set session argument"); + } +} + +/*ARGSUSED*/ +static void +RestartSession (ctxw, event, params, num_params) + Widget ctxw; + XEvent *event; + String *params; + Cardinal *num_params; +{ + LoginWidget ctx = (LoginWidget)ctxw; + + XorCursor (ctx); + RemoveFail (ctx); + ctx->login.state = DONE; + ctx->login.cursor = 0; + (*ctx->login.notify_done) (ctx, &ctx->login.data, NOTIFY_RESTART); + XorCursor (ctx); +} + +/*ARGSUSED*/ +static void +AbortSession (ctxw, event, params, num_params) + Widget ctxw; + XEvent *event; + String *params; + Cardinal *num_params; +{ + LoginWidget ctx = (LoginWidget)ctxw; + + XorCursor (ctx); + RemoveFail (ctx); + ctx->login.state = DONE; + ctx->login.cursor = 0; + (*ctx->login.notify_done) (ctx, &ctx->login.data, NOTIFY_ABORT); + XorCursor (ctx); +} + +/*ARGSUSED*/ +static void +AbortDisplay (ctxw, event, params, num_params) + Widget ctxw; + XEvent *event; + String *params; + Cardinal *num_params; +{ + LoginWidget ctx = (LoginWidget)ctxw; + + XorCursor (ctx); + RemoveFail (ctx); + ctx->login.state = DONE; + ctx->login.cursor = 0; + (*ctx->login.notify_done) (ctx, &ctx->login.data, NOTIFY_ABORT_DISPLAY); + XorCursor (ctx); +} + +ResetLogin (w) + LoginWidget w; +{ + EraseName (w, 0); + w->login.cursor = 0; + w->login.data.name[0] = '\0'; + w->login.data.passwd[0] = '\0'; + w->login.state = GET_NAME; +} + +/* ARGSUSED */ +static void +InsertChar (ctxw, event, params, num_params) + Widget ctxw; + XEvent *event; + String *params; + Cardinal *num_params; +{ + LoginWidget ctx = (LoginWidget)ctxw; + + char strbuf[128]; + int len; + + len = XLookupString (&event->xkey, strbuf, sizeof (strbuf), 0, 0); + strbuf[len] = '\0'; + switch (ctx->login.state) { + case GET_NAME: + if (len + (int)strlen(ctx->login.data.name) >= NAME_LEN - 1) + len = NAME_LEN - strlen(ctx->login.data.name) - 2; + case GET_PASSWD: + if (len + (int)strlen(ctx->login.data.passwd) >= NAME_LEN - 1) + len = NAME_LEN - strlen(ctx->login.data.passwd) - 2; + } + if (len == 0) + return; + XorCursor (ctx); + RemoveFail (ctx); + switch (ctx->login.state) { + case GET_NAME: + EraseName (ctx, ctx->login.cursor); + memmove( ctx->login.data.name + ctx->login.cursor + len, + ctx->login.data.name + ctx->login.cursor, + strlen (ctx->login.data.name + ctx->login.cursor) + 1); + memmove( ctx->login.data.name + ctx->login.cursor, strbuf, len); + DrawName (ctx, ctx->login.cursor); + ctx->login.cursor += len; + break; + case GET_PASSWD: + memmove( ctx->login.data.passwd + ctx->login.cursor + len, + ctx->login.data.passwd + ctx->login.cursor, + strlen (ctx->login.data.passwd + ctx->login.cursor) + 1); + memmove( ctx->login.data.passwd + ctx->login.cursor, strbuf, len); + ctx->login.cursor += len; + break; + } + XorCursor (ctx); +} + +/* ARGSUSED */ +static void Initialize (greq, gnew, args, num_args) + Widget greq, gnew; + ArgList args; + Cardinal *num_args; +{ + LoginWidget w = (LoginWidget)gnew; + XtGCMask valuemask, xvaluemask; + XGCValues myXGCV; + Arg position[2]; + Position x, y; + + myXGCV.foreground = w->login.textpixel; + myXGCV.background = w->core.background_pixel; + valuemask = GCForeground | GCBackground; + if (w->login.font) { + myXGCV.font = w->login.font->fid; + valuemask |= GCFont; + } + w->login.textGC = XtGetGC(gnew, valuemask, &myXGCV); + myXGCV.foreground = w->core.background_pixel; + w->login.bgGC = XtGetGC(gnew, valuemask, &myXGCV); + + myXGCV.foreground = w->login.textpixel ^ w->core.background_pixel; + myXGCV.function = GXxor; + xvaluemask = valuemask | GCFunction; + w->login.xorGC = XtGetGC (gnew, xvaluemask, &myXGCV); + + /* + * Note that the second argument is a GCid -- QueryFont accepts a GCid and + * returns the curently contained font. + */ + + if (w->login.font == NULL) + w->login.font = XQueryFont (XtDisplay (w), + XGContextFromGC (XDefaultGCOfScreen (XtScreen (w)))); + + xvaluemask = valuemask; + if (w->login.promptFont == NULL) + w->login.promptFont = w->login.font; + else + xvaluemask |= GCFont; + + myXGCV.foreground = w->login.promptpixel; + myXGCV.font = w->login.promptFont->fid; + w->login.promptGC = XtGetGC (gnew, xvaluemask, &myXGCV); + + xvaluemask = valuemask; + if (w->login.greetFont == NULL) + w->login.greetFont = w->login.font; + else + xvaluemask |= GCFont; + + myXGCV.foreground = w->login.greetpixel; + myXGCV.font = w->login.greetFont->fid; + w->login.greetGC = XtGetGC (gnew, xvaluemask, &myXGCV); + + xvaluemask = valuemask; + if (w->login.failFont == NULL) + w->login.failFont = w->login.font; + else + xvaluemask |= GCFont; + + myXGCV.foreground = w->login.failpixel; + myXGCV.font = w->login.failFont->fid; + w->login.failGC = XtGetGC (gnew, xvaluemask, &myXGCV); + + w->login.data.name[0] = '\0'; + w->login.data.passwd[0] = '\0'; + w->login.state = GET_NAME; + w->login.cursor = 0; + w->login.failUp = 0; + if (w->core.width == 0) + w->core.width = max (GREET_W(w), FAIL_W(w)) + PAD_X(w); + if (w->core.height == 0) { + int fy = FAIL_Y(w); + int pady = PAD_Y(w); + + w->core.height = fy + pady; /* for stupid compilers */ + } + if ((x = w->core.x) == -1) + x = (int)(XWidthOfScreen (XtScreen (w)) - w->core.width) / 2; + if ((y = w->core.y) == -1) + y = (int)(XHeightOfScreen (XtScreen (w)) - w->core.height) / 3; + XtSetArg (position[0], XtNx, x); + XtSetArg (position[1], XtNy, y); + XtSetValues (XtParent (w), position, (Cardinal) 2); +} + + +static void Realize (gw, valueMask, attrs) + Widget gw; + XtValueMask *valueMask; + XSetWindowAttributes *attrs; +{ + XtCreateWindow( gw, (unsigned)InputOutput, (Visual *)CopyFromParent, + *valueMask, attrs ); +} + +static void Destroy (gw) + Widget gw; +{ + LoginWidget w = (LoginWidget)gw; + bzero (w->login.data.name, NAME_LEN); + bzero (w->login.data.passwd, NAME_LEN); + XtReleaseGC(gw, w->login.textGC); + XtReleaseGC(gw, w->login.bgGC); + XtReleaseGC(gw, w->login.xorGC); + XtReleaseGC(gw, w->login.promptGC); + XtReleaseGC(gw, w->login.greetGC); + XtReleaseGC(gw, w->login.failGC); +} + +/* ARGSUSED */ +static void Redisplay(gw, event, region) + Widget gw; + XEvent *event; + Region region; +{ + draw_it ((LoginWidget) gw); +} + +/*ARGSUSED*/ +static Boolean SetValues (current, request, new, args, num_args) + Widget current, request, new; + ArgList args; + Cardinal *num_args; +{ + LoginWidget currentL, newL; + + currentL = (LoginWidget) current; + newL = (LoginWidget) new; + if (GREETING (currentL) != GREETING (newL)) + return True; + return False; +} + +char defaultLoginTranslations [] = +"\ +Ctrl<Key>H: delete-previous-character() \n\ +Ctrl<Key>D: delete-character() \n\ +Ctrl<Key>B: move-backward-character() \n\ +Ctrl<Key>F: move-forward-character() \n\ +Ctrl<Key>A: move-to-begining() \n\ +Ctrl<Key>E: move-to-end() \n\ +Ctrl<Key>K: erase-to-end-of-line() \n\ +Ctrl<Key>U: erase-line() \n\ +Ctrl<Key>X: erase-line() \n\ +Ctrl<Key>C: restart-session() \n\ +Ctrl<Key>\\\\: abort-session() \n\ +:Ctrl<Key>plus: allow-all-access() \n\ +<Key>BackSpace: delete-previous-character() \n\ +<Key>Delete: delete-previous-character() \n\ +<Key>Return: finish-field() \n\ +<Key>: insert-char() \ +"; + +XtActionsRec loginActionsTable [] = { + {"delete-previous-character", DeleteBackwardChar}, + {"delete-character", DeleteForwardChar}, + {"move-backward-character", MoveBackwardChar}, + {"move-forward-character", MoveForwardChar}, + {"move-to-begining", MoveToBegining}, + {"move-to-end", MoveToEnd}, + {"erase-to-end-of-line", EraseToEndOfLine}, + {"erase-line", EraseLine}, + {"finish-field", FinishField}, + {"abort-session", AbortSession}, + {"abort-display", AbortDisplay}, + {"restart-session", RestartSession}, + {"insert-char", InsertChar}, + {"set-session-argument", SetSessionArgument}, + {"allow-all-access", AllowAccess}, +}; + +LoginClassRec loginClassRec = { + { /* core fields */ + /* superclass */ &widgetClassRec, + /* class_name */ "Login", + /* size */ sizeof(LoginRec), + /* class_initialize */ NULL, + /* class_part_initialize */ NULL, + /* class_inited */ FALSE, + /* initialize */ Initialize, + /* initialize_hook */ NULL, + /* realize */ Realize, + /* actions */ loginActionsTable, + /* num_actions */ XtNumber (loginActionsTable), + /* resources */ resources, + /* num_resources */ XtNumber(resources), + /* xrm_class */ NULLQUARK, + /* compress_motion */ TRUE, + /* compress_exposure */ TRUE, + /* compress_enterleave */ TRUE, + /* visible_interest */ FALSE, + /* destroy */ Destroy, + /* resize */ NULL, + /* expose */ Redisplay, + /* set_values */ SetValues, + /* set_values_hook */ NULL, + /* set_values_almost */ NULL, + /* get_values_hook */ NULL, + /* accept_focus */ NULL, + /* version */ XtVersion, + /* callback_private */ NULL, + /* tm_table */ defaultLoginTranslations, + /* query_geometry */ XtInheritQueryGeometry, + /* display_accelerator */ XtInheritDisplayAccelerator, + /* extension */ NULL + } +}; + +WidgetClass loginWidgetClass = (WidgetClass) &loginClassRec; diff --git a/greeter/Login.h b/greeter/Login.h new file mode 100644 index 0000000..d2b88f4 --- /dev/null +++ b/greeter/Login.h @@ -0,0 +1,106 @@ +/* $Xorg: Login.h,v 1.4 2001/02/09 02:05:41 xorgcvs Exp $ */ +/* + +Copyright 1988, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall +not be used in advertising or otherwise to promote the sale, use or +other dealings in this Software without prior written authorization +from The Open Group. + +*/ + +/* + * xdm - display manager daemon + * Author: Keith Packard, MIT X Consortium + */ + + +#ifndef _XtLogin_h +#define _XtLogin_h + +/*********************************************************************** + * + * Login Widget + * + ***********************************************************************/ + +/* Parameters: + + Name Class RepType Default Value + ---- ----- ------- ------------- + background Background pixel White + border BorderColor pixel Black + borderWidth BorderWidth int 1 + foreground Foreground Pixel Black + height Height int 120 + mappedWhenManaged MappedWhenManaged Boolean True + width Width int 120 + x Position int 0 + y Position int 0 + +*/ + +# define XtNgreeting "greeting" +# define XtNunsecureGreeting "unsecureGreeting" +# define XtNnamePrompt "namePrompt" +# define XtNpasswdPrompt "passwdPrompt" +# define XtNfail "fail" +# define XtNnotifyDone "notifyDone" +# define XtNpromptColor "promptColor" +# define XtNgreetColor "greetColor" +# define XtNfailColor "failColor" +# define XtNpromptFont "promptFont" +# define XtNgreetFont "greetFont" +# define XtNfailFont "failFont" +# define XtNfailTimeout "failTimeout" +# define XtNsessionArgument "sessionArgument" +# define XtNsecureSession "secureSession" +# define XtNallowAccess "allowAccess" + +# define XtCGreeting "Greeting" +# define XtCNamePrompt "NamePrompt" +# define XtCPasswdPrompt "PasswdPrompt" +# define XtCFail "Fail" +# define XtCFailTimeout "FailTimeout" +# define XtCSessionArgument "SessionArgument" +# define XtCSecureSession "SecureSession" +# define XtCAllowAccess "AllowAccess" + +/* notifyDone interface definition */ + +#define NAME_LEN 32 + +typedef struct _LoginData { + char name[NAME_LEN], passwd[NAME_LEN]; +} LoginData; + +# define NOTIFY_OK 0 +# define NOTIFY_ABORT 1 +# define NOTIFY_RESTART 2 +# define NOTIFY_ABORT_DISPLAY 3 + +typedef struct _LoginRec *LoginWidget; /* completely defined in LoginPrivate.h */ +typedef struct _LoginClassRec *LoginWidgetClass; /* completely defined in LoginPrivate.h */ + +extern WidgetClass loginWidgetClass; + +#endif /* _XtLogin_h */ +/* DON'T ADD STUFF AFTER THIS #endif */ diff --git a/greeter/LoginP.h b/greeter/LoginP.h new file mode 100644 index 0000000..8a8f467 --- /dev/null +++ b/greeter/LoginP.h @@ -0,0 +1,96 @@ +/* $Xorg: LoginP.h,v 1.4 2001/02/09 02:05:41 xorgcvs Exp $ */ +/* + +Copyright 1988, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall +not be used in advertising or otherwise to promote the sale, use or +other dealings in this Software without prior written authorization +from The Open Group. + +*/ + +/* + * xdm - display manager daemon + * Author: Keith Packard, MIT X Consortium + */ + +#ifndef _LoginP_h +#define _LoginP_h + +#include "Login.h" +#include <X11/CoreP.h> + +#define GET_NAME 0 +#define GET_PASSWD 1 +#define DONE 2 + +/* New fields for the login widget instance record */ +typedef struct { + Pixel textpixel; /* foreground pixel */ + Pixel promptpixel; /* prompt pixel */ + Pixel greetpixel; /* greeting pixel */ + Pixel failpixel; /* failure pixel */ + GC textGC; /* pointer to GraphicsContext */ + GC bgGC; /* pointer to GraphicsContext */ + GC xorGC; /* pointer to GraphicsContext */ + GC promptGC; + GC greetGC; + GC failGC; + char *greeting; /* greeting */ + char *unsecure_greet;/* message displayed when insecure */ + char *namePrompt; /* name prompt */ + char *passwdPrompt; /* password prompt */ + char *fail; /* failure message */ + XFontStruct *font; /* font for text */ + XFontStruct *promptFont; /* font for prompts */ + XFontStruct *greetFont; /* font for greeting */ + XFontStruct *failFont; /* font for failure message */ + int state; /* state */ + int cursor; /* current cursor position */ + int failUp; /* failure message displayed */ + LoginData data; /* name/passwd */ + char *sessionArg; /* argument passed to session */ + void (*notify_done)();/* proc to call when done */ + int failTimeout; /* seconds til drop fail msg */ + XtIntervalId interval_id; /* drop fail message note */ + Boolean secure_session; /* session is secured */ + Boolean allow_access; /* disable access control on login */ + } LoginPart; + +/* Full instance record declaration */ +typedef struct _LoginRec { + CorePart core; + LoginPart login; + } LoginRec; + +/* New fields for the Login widget class record */ +typedef struct {int dummy;} LoginClassPart; + +/* Full class record declaration. */ +typedef struct _LoginClassRec { + CoreClassPart core_class; + LoginClassPart login_class; + } LoginClassRec; + +/* Class pointer. */ +extern LoginClassRec loginClassRec; + +#endif /* _LoginP_h */ diff --git a/greeter/greet.c b/greeter/greet.c new file mode 100644 index 0000000..93c64a6 --- /dev/null +++ b/greeter/greet.c @@ -0,0 +1,410 @@ +/* $Xorg: greet.c,v 1.4 2001/02/09 02:05:41 xorgcvs Exp $ */ +/* + +Copyright 1988, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall +not be used in advertising or otherwise to promote the sale, use or +other dealings in this Software without prior written authorization +from The Open Group. + +*/ + +/* + * xdm - display manager daemon + * Author: Keith Packard, X Consortium + * + * widget to get username/password + * + */ + +#include <X11/Intrinsic.h> +#include <X11/StringDefs.h> +#include <X11/Shell.h> +#include <X11/XKBlib.h> + +#include "dm.h" +#include "greet.h" +#include "Login.h" + +#if GREET_LIB +/* + * Function pointers filled in by the initial call ito the library + */ + +int (*__xdm_PingServer)() = NULL; +int (*__xdm_SessionPingFailed)() = NULL; +int (*__xdm_Debug)() = NULL; +int (*__xdm_RegisterCloseOnFork)() = NULL; +int (*__xdm_SecureDisplay)() = NULL; +int (*__xdm_UnsecureDisplay)() = NULL; +int (*__xdm_ClearCloseOnFork)() = NULL; +int (*__xdm_SetupDisplay)() = NULL; +int (*__xdm_LogError)() = NULL; +int (*__xdm_SessionExit)() = NULL; +int (*__xdm_DeleteXloginResources)() = NULL; +int (*__xdm_source)() = NULL; +char **(*__xdm_defaultEnv)() = NULL; +char **(*__xdm_setEnv)() = NULL; +char **(*__xdm_parseArgs)() = NULL; +int (*__xdm_printEnv)() = NULL; +char **(*__xdm_systemEnv)() = NULL; +int (*__xdm_LogOutOfMem)() = NULL; +void (*__xdm_setgrent)() = NULL; +struct group *(*__xdm_getgrent)() = NULL; +void (*__xdm_endgrent)() = NULL; +#ifdef USESHADOW +struct spwd *(*__xdm_getspnam)() = NULL; +void (*__xdm_endspent)() = NULL; +#endif +struct passwd *(*__xdm_getpwnam)() = NULL; +char *(*__xdm_crypt)() = NULL; + +#endif + +#ifdef SECURE_RPC +#include <rpc/rpc.h> +#include <rpc/key_prot.h> +#endif + +#ifdef K5AUTH +#include <krb5/krb5.h> +#endif + +extern Display *dpy; + +static int done, code; +static char name[128], password[128]; +static Widget toplevel; +static Widget login; +static XtAppContext context; +static XtIntervalId pingTimeout; + +/*ARGSUSED*/ +static void +GreetPingServer (closure, intervalId) + XtPointer closure; + XtIntervalId *intervalId; +{ + struct display *d; + + d = (struct display *) closure; + if (!PingServer (d, XtDisplay (toplevel))) + SessionPingFailed (d); + pingTimeout = XtAppAddTimeOut (context, d->pingInterval * 60 * 1000, + GreetPingServer, (closure)); +} + +/*ARGSUSED*/ +static void +GreetDone (w, data, status) + Widget w; + LoginData *data; + int status; +{ + Debug ("GreetDone: %s, (password is %d long)\n", + data->name, strlen (data->passwd)); + switch (status) { + case NOTIFY_OK: + strcpy (name, data->name); + strcpy (password, data->passwd); + bzero (data->passwd, NAME_LEN); + code = 0; + done = 1; + break; + case NOTIFY_ABORT: + Debug ("RESERVER_DISPLAY\n"); + code = RESERVER_DISPLAY; + done = 1; + break; + case NOTIFY_RESTART: + Debug ("REMANAGE_DISPLAY\n"); + code = REMANAGE_DISPLAY; + done = 1; + break; + case NOTIFY_ABORT_DISPLAY: + Debug ("UNMANAGE_DISPLAY\n"); + code = UNMANAGE_DISPLAY; + done = 1; + break; + } +} + +static Display * +InitGreet (d) + struct display *d; +{ + Arg arglist[10]; + int i; + static int argc; + Screen *scrn; + static char *argv[] = { "xlogin", 0 }; + Display *dpy; + + Debug ("greet %s\n", d->name); + argc = 1; + XtToolkitInitialize (); + context = XtCreateApplicationContext(); + dpy = XtOpenDisplay (context, d->name, "xlogin", "Xlogin", 0,0, + &argc, argv); + + if (!dpy) + return 0; + + { + int opcode, evbase, errbase, majret, minret; + unsigned int value = XkbPCF_GrabsUseXKBStateMask; + if (XkbQueryExtension (dpy, &opcode, &evbase, &errbase, &majret, &minret)) { + if (XkbSetPerClientControls (dpy, XkbPCF_GrabsUseXKBStateMask, &value)) + LogError ("%s\n", "SetPerClientControls failed"); + } + } + + RegisterCloseOnFork (ConnectionNumber (dpy)); + + SecureDisplay (d, dpy); + + i = 0; + scrn = XDefaultScreenOfDisplay(dpy); + XtSetArg(arglist[i], XtNscreen, scrn); i++; + XtSetArg(arglist[i], XtNargc, argc); i++; + XtSetArg(arglist[i], XtNargv, argv); i++; + + toplevel = XtAppCreateShell ((String) NULL, "Xlogin", + applicationShellWidgetClass, dpy, arglist, i); + + i = 0; + XtSetArg (arglist[i], XtNnotifyDone, (XtPointer)GreetDone); i++; + if (!d->authorize || d->authorizations || !d->authComplain) + { + XtSetArg (arglist[i], XtNsecureSession, True); i++; + } + login = XtCreateManagedWidget ("login", loginWidgetClass, toplevel, + arglist, i); + XtRealizeWidget (toplevel); + + XWarpPointer(dpy, None, XRootWindowOfScreen (scrn), + 0, 0, 0, 0, + XWidthOfScreen(scrn) / 2, + XHeightOfScreen(scrn) / 2); + + if (d->pingInterval) + { + pingTimeout = XtAppAddTimeOut (context, d->pingInterval * 60 * 1000, + GreetPingServer, (XtPointer) d); + } + return dpy; +} + +static +CloseGreet (d) + struct display *d; +{ + Boolean allow; + Arg arglist[1]; + Display *dpy = XtDisplay(toplevel); + + if (pingTimeout) + { + XtRemoveTimeOut (pingTimeout); + pingTimeout = 0; + } + UnsecureDisplay (d, dpy); + XtSetArg (arglist[0], XtNallowAccess, (char *) &allow); + XtGetValues (login, arglist, 1); + if (allow) + { + Debug ("Disabling access control\n"); + XSetAccessControl (dpy, DisableAccess); + } + XtDestroyWidget (toplevel); + ClearCloseOnFork (XConnectionNumber (dpy)); + XCloseDisplay (dpy); + Debug ("Greet connection closed\n"); +} + +static int +Greet (d, greet) + struct display *d; + struct greet_info *greet; +{ + XEvent event; + Arg arglist[1]; + + XtSetArg (arglist[0], XtNallowAccess, False); + XtSetValues (login, arglist, 1); + + Debug ("dispatching %s\n", d->name); + done = 0; + while (!done) { + XtAppNextEvent (context, &event); + XtDispatchEvent (&event); + } + XFlush (XtDisplay (toplevel)); + Debug ("Done dispatch %s\n", d->name); + if (code == 0) + { + greet->name = name; + greet->password = password; + XtSetArg (arglist[0], XtNsessionArgument, (char *) &(greet->string)); + XtGetValues (login, arglist, 1); + Debug ("sessionArgument: %s\n", greet->string ? greet->string : "<NULL>"); + } + return code; +} + + +static void +FailedLogin (d, greet) + struct display *d; + struct greet_info *greet; +{ + DrawFail (login); + bzero (greet->name, strlen(greet->name)); + bzero (greet->password, strlen(greet->password)); +} + + +greet_user_rtn GreetUser(d, dpy, verify, greet, dlfuncs) + struct display *d; + Display ** dpy; + struct verify_info *verify; + struct greet_info *greet; + struct dlfuncs *dlfuncs; +{ + int i; + +#ifdef GREET_LIB +/* + * These must be set before they are used. + */ + __xdm_PingServer = dlfuncs->_PingServer; + __xdm_SessionPingFailed = dlfuncs->_SessionPingFailed; + __xdm_Debug = dlfuncs->_Debug; + __xdm_RegisterCloseOnFork = dlfuncs->_RegisterCloseOnFork; + __xdm_SecureDisplay = dlfuncs->_SecureDisplay; + __xdm_UnsecureDisplay = dlfuncs->_UnsecureDisplay; + __xdm_ClearCloseOnFork = dlfuncs->_ClearCloseOnFork; + __xdm_SetupDisplay = dlfuncs->_SetupDisplay; + __xdm_LogError = dlfuncs->_LogError; + __xdm_SessionExit = dlfuncs->_SessionExit; + __xdm_DeleteXloginResources = dlfuncs->_DeleteXloginResources; + __xdm_source = dlfuncs->_source; + __xdm_defaultEnv = dlfuncs->_defaultEnv; + __xdm_setEnv = dlfuncs->_setEnv; + __xdm_parseArgs = dlfuncs->_parseArgs; + __xdm_printEnv = dlfuncs->_printEnv; + __xdm_systemEnv = dlfuncs->_systemEnv; + __xdm_LogOutOfMem = dlfuncs->_LogOutOfMem; + __xdm_setgrent = dlfuncs->_setgrent; + __xdm_getgrent = dlfuncs->_getgrent; + __xdm_endgrent = dlfuncs->_endgrent; +#ifdef USESHADOW + __xdm_getspnam = dlfuncs->_getspnam; + __xdm_endspent = dlfuncs->_endspent; +#endif + __xdm_getpwnam = dlfuncs->_getpwnam; + __xdm_crypt = dlfuncs->_crypt; +#endif + + *dpy = InitGreet (d); + /* + * Run the setup script - note this usually will not work when + * the server is grabbed, so we don't even bother trying. + */ + if (!d->grabServer) + SetupDisplay (d); + if (!*dpy) { + LogError ("Cannot reopen display %s for greet window\n", d->name); + exit (RESERVER_DISPLAY); + } + for (;;) { + /* + * Greet user, requesting name/password + */ + code = Greet (d, greet); + if (code != 0) + { + CloseGreet (d); + SessionExit (d, code, FALSE); + } + /* + * Verify user + */ + if (Verify (d, greet, verify)) + break; + else + FailedLogin (d, greet); + } + DeleteXloginResources (d, *dpy); + CloseGreet (d); + Debug ("Greet loop finished\n"); + /* + * Run system-wide initialization file + */ + if (source (verify->systemEnviron, d->startup) != 0) + { + Debug ("Startup program %s exited with non-zero status\n", + d->startup); + SessionExit (d, OBEYSESS_DISPLAY, FALSE); + } + /* + * for user-based authorization schemes, + * add the user to the server's allowed "hosts" list. + */ + for (i = 0; i < d->authNum; i++) + { +#ifdef SECURE_RPC + if (d->authorizations[i]->name_length == 9 && + memcmp(d->authorizations[i]->name, "SUN-DES-1", 9) == 0) + { + XHostAddress addr; + char netname[MAXNETNAMELEN+1]; + char domainname[MAXNETNAMELEN+1]; + + getdomainname(domainname, sizeof domainname); + user2netname (netname, verify->uid, domainname); + addr.family = FamilyNetname; + addr.length = strlen (netname); + addr.address = netname; + XAddHost (*dpy, &addr); + } +#endif +#ifdef K5AUTH + if (d->authorizations[i]->name_length == 14 && + memcmp(d->authorizations[i]->name, "MIT-KERBEROS-5", 14) == 0) + { + /* 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. + */ + extern Xauth *Krb5GetAuthFor(); + + XauDisposeAuth (d->authorizations[i]); + d->authorizations[i] = + Krb5GetAuthFor(14, "MIT-KERBEROS-5", d->name); + SaveServerAuthorizations (d, d->authorizations, d->authNum); + } +#endif + } + + return Greet_Success; +} diff --git a/greeter/verify.c b/greeter/verify.c new file mode 100644 index 0000000..52b8138 --- /dev/null +++ b/greeter/verify.c @@ -0,0 +1,173 @@ +/* $Xorg: verify.c,v 1.4 2001/02/09 02:05:41 xorgcvs Exp $ */ +/* + +Copyright 1988, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall +not be used in advertising or otherwise to promote the sale, use or +other dealings in this Software without prior written authorization +from The Open Group. + +*/ + +/* + * xdm - display manager daemon + * Author: Keith Packard, MIT X Consortium + * + * verify.c + * + * typical unix verification routine. + */ + +# include "dm.h" +# include <pwd.h> +#ifdef USESHADOW +# include <shadow.h> +# include <errno.h> +#ifdef X_NOT_STDC_ENV +extern int errno; +#endif +#endif + +# include "greet.h" + +#ifdef X_NOT_STDC_ENV +char *getenv(); +#endif + +static char *envvars[] = { + "TZ", /* SYSV and SVR4, but never hurts */ +#if defined(sony) && !defined(SYSTYPE_SYSV) && !defined(_SYSTYPE_SYSV) + "bootdev", + "boothowto", + "cputype", + "ioptype", + "machine", + "model", + "CONSDEVTYPE", + "SYS_LANGUAGE", + "SYS_CODE", +#endif +#if (defined(SVR4) || defined(SYSV)) && defined(i386) && !defined(sun) + "XLOCAL", +#endif + NULL +}; + +static char ** +userEnv (d, useSystemPath, user, home, shell) +struct display *d; +int useSystemPath; +char *user, *home, *shell; +{ + char **env; + char **envvar; + char *str; + extern char **defaultEnv (), **setEnv (); + + env = defaultEnv (); + env = setEnv (env, "DISPLAY", d->name); + env = setEnv (env, "HOME", home); + env = setEnv (env, "LOGNAME", user); /* POSIX, System V */ + env = setEnv (env, "USER", user); /* BSD */ + env = setEnv (env, "PATH", useSystemPath ? d->systemPath : d->userPath); + env = setEnv (env, "SHELL", shell); + for (envvar = envvars; *envvar; envvar++) + { + str = getenv(*envvar); + if (str) + env = setEnv (env, *envvar, str); + } + return env; +} + +int +Verify (d, greet, verify) +struct display *d; +struct greet_info *greet; +struct verify_info *verify; +{ + struct passwd *p; +#ifdef USESHADOW + struct spwd *sp; +#endif + char *user_pass; +#if !defined(SVR4) || !defined(GREET_LIB) /* shared lib decls handle this */ + char *crypt (); + char **systemEnv (), **parseArgs (); +#endif + char *shell, *home; + char **argv; + + Debug ("Verify %s ...\n", greet->name); + p = getpwnam (greet->name); + if (!p || strlen (greet->name) == 0) { + Debug ("getpwnam() failed.\n"); + bzero(greet->password, strlen(greet->password)); + return 0; + } else { + user_pass = p->pw_passwd; + } +#ifdef USESHADOW + errno = 0; + sp = getspnam(greet->name); + if (sp == NULL) { + Debug ("getspnam() failed, errno=%d. Are you root?\n", errno); + } else { + user_pass = sp->sp_pwdp; + } + endspent(); +#endif +#if defined(ultrix) || defined(__ultrix__) + if (authenticate_user(p, greet->password, NULL) < 0) +#else + if (strcmp (crypt (greet->password, user_pass), user_pass)) +#endif + { + Debug ("password verify failed\n"); + bzero(greet->password, strlen(greet->password)); + return 0; + } + Debug ("verify succeeded\n"); + bzero(user_pass, strlen(user_pass)); /* in case shadow password */ + /* The password is passed to StartClient() for use by user-based + authorization schemes. It is zeroed there. */ + verify->uid = p->pw_uid; + verify->gid = p->pw_gid; + home = p->pw_dir; + shell = p->pw_shell; + argv = 0; + if (d->session) + argv = parseArgs (argv, d->session); + if (greet->string) + argv = parseArgs (argv, greet->string); + if (!argv) + argv = parseArgs (argv, "xsession"); + verify->argv = argv; + verify->userEnviron = userEnv (d, p->pw_uid == 0, + greet->name, home, shell); + Debug ("user environment:\n"); + printEnv (verify->userEnviron); + verify->systemEnviron = systemEnv (d, greet->name, home); + Debug ("system environment:\n"); + printEnv (verify->systemEnviron); + Debug ("end of environments\n"); + return 1; +} diff --git a/krb5auth.c b/krb5auth.c new file mode 100644 index 0000000..5451430 --- /dev/null +++ b/krb5auth.c @@ -0,0 +1,266 @@ +/* $Xorg: krb5auth.c,v 1.4 2001/02/09 02:05:40 xorgcvs Exp $ */ +/* + +Copyright 1994, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall +not be used in advertising or otherwise to promote the sale, use or +other dealings in this Software without prior written authorization +from The Open Group. + +*/ + +/* + * xdm - display manager daemon + * Author: Stephen Gildea, The Open Group + */ + +/* + * krb5auth + * + * generate Kerberos Version 5 authorization records + */ + +#include "dm.h" +#include <sys/types.h> +#include <sys/stat.h> +#include <krb5/krb5.h> +#include <krb5/kdb.h> /* for TGTNAME */ + +/*ARGSUSED*/ +Krb5InitAuth (name_len, name) + unsigned short name_len; + char *name; +{ + krb5_init_ets(); /* initialize error_message() tables */ +} + +/* + * Returns malloc'ed string that is the credentials cache name. + * name should be freed by caller. + */ +char * +Krb5CCacheName(dname) + char *dname; +{ + char *name; + char *tmpdir; + + tmpdir = getenv("TMPDIR"); + if (!tmpdir) + tmpdir = "/tmp"; + name = malloc(strlen(tmpdir) + strlen(dname) + 20); + if (!name) + return NULL; + sprintf(name, "FILE:%s/K5C", tmpdir); + CleanUpFileName(dname, name+strlen(name), strlen(dname)+1); + return name; +} + +krb5_error_code +Krb5DisplayCCache(dname, ccache_return) + char *dname; + krb5_ccache *ccache_return; +{ + krb5_error_code code; + char *name; + + name = Krb5CCacheName(dname); + if (!name) + return ENOMEM; + Debug("resolving Kerberos cache %s\n", name); + code = krb5_cc_resolve(name, ccache_return); + free(name); + return code; +} + +Xauth * +Krb5GetAuthFor(namelen, name, dname) + unsigned short namelen; + char *name; + char *dname; +{ + Xauth *new; + char *filename; + struct stat statbuf; + + new = (Xauth *) malloc (sizeof *new); + if (!new) + return (Xauth *) 0; + new->family = FamilyWild; + new->address_length = 0; + new->address = 0; + new->number_length = 0; + new->number = 0; + + if (dname) + { + filename = Krb5CCacheName(dname); + new->data = (char *) malloc (3 + strlen(filename) + 1); + if (!new->data) + { + free (filename); + free ((char *) new); + return (Xauth *) 0; + } + strcpy(new->data, "UU:"); + strcat(new->data, filename); + free (filename); + new->data_length = strlen(new->data); + } + else + { + new->data = NULL; + new->data_length = 0; + } + + new->name = (char *) malloc (namelen); + if (!new->name) + { + free ((char *) new->data); + free ((char *) new); + return (Xauth *) 0; + } + memmove( new->name, name, namelen); + new->name_length = namelen; + return new; +} + + +Xauth * +Krb5GetAuth (namelen, name) + unsigned short namelen; + char *name; +{ + return Krb5GetAuthFor(namelen, name, NULL); +} + +int preauth_search_list[] = { + 0, + KRB5_PADATA_ENC_TIMESTAMP, + -1 + }; + +/* + * Krb5Init - lifted from kinit.c + * Get TGT. + * Returns 0 if successful, 1 if not. + */ +int +Krb5Init(name, passwd, d) + char *name; + char *passwd; + struct display *d; /* k5_ccache filled in if successful */ +{ + krb5_ccache ccache; + krb5_error_code code; + krb5_principal me; + krb5_creds my_creds; + krb5_principal server; + krb5_address **my_addresses; + krb5_timestamp now; + int i; + + if (code = Krb5DisplayCCache(d->name, &ccache)) { + LogError("%s while getting Krb5 ccache for \"%s\"\n", + error_message(code), d->name); + return 1; + } + + if (code = krb5_parse_name (name, &me)) { + LogError("%s while parsing Krb5 name \"%s\"\n", + error_message(code), name); + return 1; + } + + code = krb5_cc_initialize (ccache, me); + if (code != 0) { + LogError("%s while initializing Krb5 cache \"%s\"\n", + error_message(code), krb5_cc_default_name()); + return 1; + } + + memset((char *)&my_creds, 0, sizeof(my_creds)); + + my_creds.client = me; + + if (code = krb5_build_principal_ext(&server, + krb5_princ_realm(me)->length, + krb5_princ_realm(me)->data, + 6, "krbtgt", + krb5_princ_realm(me)->length, + krb5_princ_realm(me)->data, + 0)) { + LogError("%s while building Krb5 TGT server name\n", + error_message(code)); + return 1; + } + + my_creds.server = server; + + code = krb5_os_localaddr(&my_addresses); + if (code != 0) { + LogError("%s while getting my address for Krb5\n", + error_message(code)); + return 1; + } + if (code = krb5_timeofday(&now)) { + LogError("%s while getting time of day for Krb5\n", + error_message(code)); + return 1; + } + my_creds.times.starttime = 0; /* start timer when request + gets to KDC */ + my_creds.times.endtime = now + 60*60*8; /* 8 hours */ + my_creds.times.renew_till = 0; + + for (i = 0; preauth_search_list[i] >= 0; i++) { + code = krb5_get_in_tkt_with_password(0, my_addresses, + preauth_search_list[i], + ETYPE_DES_CBC_CRC, + KEYTYPE_DES, + passwd, + ccache, + &my_creds, 0); + if (code != KRB5KDC_PREAUTH_FAILED && + code != KRB5KRB_ERR_GENERIC) + break; + } + + krb5_free_principal(server); + krb5_free_addresses(my_addresses); + + if (code) { + char *my_name = NULL; + int code2 = krb5_unparse_name(me, &my_name); + if (code == KRB5KRB_AP_ERR_BAD_INTEGRITY) { + LogError ("password incorrect for Krb5 principal \"%s\"\n", + code2 ? name : my_name); + } + else + LogError("%s while getting initial Krb5 credentials for \"%s\"\n", + error_message(code), code2 ? name : my_name); + if (my_name) + free (my_name); + return 1; + } + krb5_cc_close(ccache); + return 0; +} diff --git a/mitauth.c b/mitauth.c new file mode 100644 index 0000000..1eee630 --- /dev/null +++ b/mitauth.c @@ -0,0 +1,91 @@ +/* $Xorg: mitauth.c,v 1.4 2001/02/09 02:05:40 xorgcvs Exp $ */ +/* + +Copyright 1988, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall +not be used in advertising or otherwise to promote the sale, use or +other dealings in this Software without prior written authorization +from The Open Group. + +*/ + +/* + * xdm - display manager daemon + * Author: Keith Packard, MIT X Consortium + * + * mitauth + * + * generate authorization keys + * for MIT-MAGIC-COOKIE-1 type authorization + */ + +# include <X11/Xos.h> +# include "dm.h" + +# define AUTH_DATA_LEN 16 /* bytes of authorization data */ +static char auth_name[256]; +static int auth_name_len; + +MitInitAuth (name_len, name) + unsigned short name_len; + char *name; +{ + if (name_len > 256) + name_len = 256; + auth_name_len = name_len; + memmove( auth_name, name, name_len); +} + +Xauth * +MitGetAuth (namelen, name) + unsigned short namelen; + char *name; +{ + Xauth *new; + new = (Xauth *) malloc (sizeof (Xauth)); + + if (!new) + return (Xauth *) 0; + new->family = FamilyWild; + new->address_length = 0; + new->address = 0; + new->number_length = 0; + new->number = 0; + + new->data = (char *) malloc (AUTH_DATA_LEN); + if (!new->data) + { + free ((char *) new); + return (Xauth *) 0; + } + new->name = (char *) malloc (namelen); + if (!new->name) + { + free ((char *) new->data); + free ((char *) new); + return (Xauth *) 0; + } + memmove( (char *)new->name, name, namelen); + new->name_length = namelen; + GenerateAuthData (new->data, AUTH_DATA_LEN); + new->data_length = AUTH_DATA_LEN; + return new; +} diff --git a/netaddr.c b/netaddr.c new file mode 100644 index 0000000..7053780 --- /dev/null +++ b/netaddr.c @@ -0,0 +1,242 @@ +/* $Xorg: netaddr.c,v 1.4 2001/02/09 02:05:40 xorgcvs Exp $ */ +/* + +Copyright 1991, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall +not be used in advertising or otherwise to promote the sale, use or +other dealings in this Software without prior written authorization +from The Open Group. + +*/ + +/* + * xdm - X display manager + * + * netaddr.c - Interpretation of XdmcpNetaddr object. + */ + +#include "dm.h" + +#include <X11/X.h> /* FamilyInternet, etc. */ + +#ifdef XDMCP + +#include <sys/socket.h> /* struct sockaddr */ +#include <netinet/in.h> /* struct sockaddr_in */ + +#ifdef UNIXCONN +#include <sys/un.h> /* struct sockaddr_un */ +#endif +#ifdef DNETCONN +#include <netdnet/dn.h> /* struct sockaddr_dn */ +#endif + +/* given an XdmcpNetaddr, returns the socket protocol family used, + e.g., AF_INET */ + +int NetaddrFamily(netaddrp) + XdmcpNetaddr netaddrp; +{ +#ifdef STREAMSCONN + short family = *(short *)netaddrp; + return family; +#else + return ((struct sockaddr *)netaddrp)->sa_family; +#endif +} + + +/* given an XdmcpNetaddr, returns a pointer to the TCP/UDP port used + and sets *lenp to the length of the address + or 0 if not using TCP or UDP. */ + +char * NetaddrPort(netaddrp, lenp) + XdmcpNetaddr netaddrp; + int *lenp; /* return */ +{ +#ifdef STREAMSCONN + *lenp = 2; + return netaddrp+2; +#else + switch (NetaddrFamily(netaddrp)) + { + case AF_INET: + *lenp = 2; + return (char *)&(((struct sockaddr_in *)netaddrp)->sin_port); + default: + *lenp = 0; + return NULL; + } +#endif +} + + +/* given an XdmcpNetaddr, returns a pointer to the network address + and sets *lenp to the length of the address */ + +char * NetaddrAddress(netaddrp, lenp) + XdmcpNetaddr netaddrp; + int *lenp; /* return */ +{ +#ifdef STREAMSCONN + *lenp = 4; + return netaddrp+4; +#else + switch (NetaddrFamily(netaddrp)) { +#ifdef UNIXCONN + case AF_UNIX: + *lenp = strlen(((struct sockaddr_un *)netaddrp)->sun_path); + return (char *) (((struct sockaddr_un *)netaddrp)->sun_path); +#endif +#ifdef TCPCONN + case AF_INET: + *lenp = sizeof (struct in_addr); + return (char *) &(((struct sockaddr_in *)netaddrp)->sin_addr); +#endif +#ifdef DNETCONN + case AF_DECnet: + *lenp = sizeof (struct dn_naddr); + return (char *) &(((struct sockaddr_dn *)netaddrp)->sdn_add); +#endif +#ifdef AF_CHAOS + case AF_CHAOS: +#endif + default: + *lenp = 0; + return NULL; + } +#endif /* STREAMSCONN else */ +} + + +/* given an XdmcpNetaddr, sets *addr to the network address used and + sets *len to the number of bytes in addr. + Returns the X protocol family used, e.g., FamilyInternet */ + +int ConvertAddr (saddr, len, addr) + XdmcpNetaddr saddr; + int *len; /* return */ + char **addr; /* return */ +{ + int retval; + + if (len == NULL) + return -1; + *addr = NetaddrAddress(saddr, len); +#ifdef STREAMSCONN + /* kludge */ + if (NetaddrFamily(saddr) == 2) + retval = FamilyInternet; +#else + switch (NetaddrFamily(saddr)) + { +#ifdef AF_UNSPEC + case AF_UNSPEC: + retval = FamilyLocal; + break; +#endif +#ifdef AF_UNIX +#ifndef hpux + case AF_UNIX: + retval = FamilyLocal; + break; +#endif +#endif +#ifdef TCPCONN + case AF_INET: + retval = FamilyInternet; + break; +#endif +#ifdef DNETCONN + case AF_DECnet: + retval = FamilyDECnet; + break; +#endif +#ifdef AF_CHAOS + case AF_CHAOS: + retval = FamilyChaos; + break; +#endif + default: + retval = -1; + break; + } +#endif /* STREAMSCONN else */ + Debug ("ConvertAddr returning %d for family %d\n", retval, + NetaddrFamily(saddr)); + return retval; +} + +addressEqual (a1, len1, a2, len2) + XdmcpNetaddr a1, a2; + int len1, len2; +{ + int partlen1, partlen2; + char *part1, *part2; + + if (len1 != len2) + { + return FALSE; + } + if (NetaddrFamily(a1) != NetaddrFamily(a2)) + { + return FALSE; + } + part1 = NetaddrPort(a1, &partlen1); + part2 = NetaddrPort(a2, &partlen2); + if (partlen1 != partlen2 || memcmp(part1, part2, partlen1) != 0) + { + return FALSE; + } + part1 = NetaddrAddress(a1, &partlen1); + part2 = NetaddrAddress(a2, &partlen2); + if (partlen1 != partlen2 || memcmp(part1, part2, partlen1) != 0) + { + return FALSE; + } + return TRUE; +} + +#ifdef DEBUG +/*ARGSUSED*/ +PrintSockAddr (a, len) /* Debugging routine */ + struct sockaddr *a; + int len; +{ + unsigned char *t, *p; + + Debug ("family %d, ", a->sa_family); + switch (a->sa_family) { +#ifdef AF_INET + case AF_INET: + + p = (unsigned char *) &((struct sockaddr_in *) a)->sin_port; + t = (unsigned char *) &((struct sockaddr_in *) a)->sin_addr; + + Debug ("port %d, host %d.%d.%d.%d\n", + (p[0] << 8) + p[1], t[0], t[1], t[2], t[3]); + break; + } +#endif +} +#endif + +#endif /* XDMCP */ diff --git a/policy.c b/policy.c new file mode 100644 index 0000000..3cffa90 --- /dev/null +++ b/policy.c @@ -0,0 +1,162 @@ +/* $Xorg: policy.c,v 1.4 2001/02/09 02:05:40 xorgcvs Exp $ */ +/* + +Copyright 1988, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall +not be used in advertising or otherwise to promote the sale, use or +other dealings in this Software without prior written authorization +from The Open Group. + +*/ + +/* + * xdm - display manager daemon + * Author: Keith Packard, MIT X Consortium + * + * policy.c. Implement site-dependent policy for XDMCP connections + */ + +# include "dm.h" + +#ifdef XDMCP + +# include <X11/X.h> +# include <sys/socket.h> +#ifdef AF_INET +# include <netinet/in.h> +#endif + +static ARRAY8 noAuthentication = { (CARD16) 0, (CARD8Ptr) 0 }; + +typedef struct _XdmAuth { + ARRAY8 authentication; + ARRAY8 authorization; +} XdmAuthRec, *XdmAuthPtr; + +static XdmAuthRec auth[] = { +#ifdef HASXDMAUTH +{ {(CARD16) 20, (CARD8 *) "XDM-AUTHENTICATION-1"}, + {(CARD16) 19, (CARD8 *) "XDM-AUTHORIZATION-1"}, +}, +#endif +{ {(CARD16) 0, (CARD8 *) 0}, + {(CARD16) 0, (CARD8 *) 0}, +} +}; + +#define NumAuth (sizeof auth / sizeof auth[0]) + +ARRAY8Ptr +ChooseAuthentication (authenticationNames) + ARRAYofARRAY8Ptr authenticationNames; +{ + int i, j; + + for (i = 0; i < (int)authenticationNames->length; i++) + for (j = 0; j < NumAuth; j++) + if (XdmcpARRAY8Equal (&authenticationNames->data[i], + &auth[j].authentication)) + return &authenticationNames->data[i]; + return &noAuthentication; +} + +CheckAuthentication (pdpy, displayID, name, data) + struct protoDisplay *pdpy; + ARRAY8Ptr displayID, name, data; +{ +#ifdef HASXDMAUTH + if (name->length && !strncmp ((char *)name->data, "XDM-AUTHENTICATION-1", 20)) + return XdmCheckAuthentication (pdpy, displayID, name, data); +#endif + return TRUE; +} + +int +SelectAuthorizationTypeIndex (authenticationName, authorizationNames) + ARRAY8Ptr authenticationName; + ARRAYofARRAY8Ptr authorizationNames; +{ + int i, j; + + for (j = 0; j < NumAuth; j++) + if (XdmcpARRAY8Equal (authenticationName, + &auth[j].authentication)) + break; + if (j < NumAuth) + { + for (i = 0; i < (int)authorizationNames->length; i++) + if (XdmcpARRAY8Equal (&authorizationNames->data[i], + &auth[j].authorization)) + return i; + } + for (i = 0; i < (int)authorizationNames->length; i++) + if (ValidAuthorization (authorizationNames->data[i].length, + (char *) authorizationNames->data[i].data)) + return i; + return -1; +} + +/*ARGSUSED*/ +int +Willing (addr, connectionType, authenticationName, status, type) + ARRAY8Ptr addr; + CARD16 connectionType; + ARRAY8Ptr authenticationName; + ARRAY8Ptr status; + xdmOpCode type; +{ + char statusBuf[256]; + int ret; + + ret = AcceptableDisplayAddress (addr, connectionType, type); + if (!ret) + sprintf (statusBuf, "Display not authorized to connect"); + else + sprintf (statusBuf, "Willing to manage"); + status->length = strlen (statusBuf); + status->data = (CARD8Ptr) malloc (status->length); + if (!status->data) + status->length = 0; + else + memmove( status->data, statusBuf, status->length); + return ret; +} + +/*ARGSUSED*/ +ARRAY8Ptr +Accept (from, fromlen, displayNumber) + struct sockaddr *from; + int fromlen; + CARD16 displayNumber; +{ + return 0; +} + +/*ARGSUSED*/ +int +SelectConnectionTypeIndex (connectionTypes, connectionAddresses) + ARRAY16Ptr connectionTypes; + ARRAYofARRAY8Ptr connectionAddresses; +{ + return 0; +} + +#endif /* XDMCP */ diff --git a/protodpy.c b/protodpy.c new file mode 100644 index 0000000..4672f77 --- /dev/null +++ b/protodpy.c @@ -0,0 +1,173 @@ +/* + * $Xorg: protodpy.c,v 1.4 2001/02/09 02:05:40 xorgcvs Exp $ + * +Copyright 1989, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + * + * Author: Keith Packard, MIT X Consortium + */ + +/* + * protodpy.c + * + * manage a collection of proto-displays. These are displays for + * which sessionID's have been generated, but no session has been + * started. + */ + +#include "dm.h" + +#ifdef XDMCP + +#include <sys/types.h> +#ifdef X_NOT_STDC_ENV +#define Time_t long +extern Time_t time (); +#else +#include <time.h> +#define Time_t time_t +#endif + +static struct protoDisplay *protoDisplays; + +#ifdef DEBUG +static +PrintProtoDisplay (pdpy) + struct protoDisplay *pdpy; +{ + Debug ("ProtoDisplay 0x%x\n", pdpy); + Debug ("\taddress: "); + PrintSockAddr (pdpy->address, pdpy->addrlen); + Debug ("\tdate %d (%d from now)\n", pdpy->date, time(0) - pdpy->date); + Debug ("\tdisplay Number %d\n", pdpy->displayNumber); + Debug ("\tsessionID %d\n", pdpy->sessionID); +} +#endif + +struct protoDisplay * +FindProtoDisplay (address, addrlen, displayNumber) + XdmcpNetaddr address; + int addrlen; + CARD16 displayNumber; +{ + struct protoDisplay *pdpy; + + Debug ("FindProtoDisplay\n"); + for (pdpy = protoDisplays; pdpy; pdpy=pdpy->next) + { + if (pdpy->displayNumber == displayNumber && + addressEqual (address, addrlen, pdpy->address, pdpy->addrlen)) + { + return pdpy; + } + } + return (struct protoDisplay *) 0; +} + +static +TimeoutProtoDisplays (now) + Time_t now; +{ + struct protoDisplay *pdpy, *next; + + for (pdpy = protoDisplays; pdpy; pdpy = next) + { + next = pdpy->next; + if (pdpy->date < now - PROTO_TIMEOUT) + DisposeProtoDisplay (pdpy); + } +} + +struct protoDisplay * +NewProtoDisplay (address, addrlen, displayNumber, + connectionType, connectionAddress, sessionID) + XdmcpNetaddr address; + int addrlen; + CARD16 displayNumber; + CARD16 connectionType; + ARRAY8Ptr connectionAddress; + CARD32 sessionID; +{ + struct protoDisplay *pdpy; + Time_t date; + + Debug ("NewProtoDisplay\n"); + time (&date); + TimeoutProtoDisplays (date); + pdpy = (struct protoDisplay *) malloc (sizeof *pdpy); + if (!pdpy) + return NULL; + pdpy->address = (XdmcpNetaddr) malloc (addrlen); + if (!pdpy->address) + { + free ((char *) pdpy); + return NULL; + } + pdpy->addrlen = addrlen; + memmove( pdpy->address, address, addrlen); + pdpy->displayNumber = displayNumber; + pdpy->connectionType = connectionType; + pdpy->date = date; + if (!XdmcpCopyARRAY8 (connectionAddress, &pdpy->connectionAddress)) + { + free ((char *) pdpy->address); + free ((char *) pdpy); + return NULL; + } + pdpy->sessionID = sessionID; + pdpy->fileAuthorization = (Xauth *) NULL; + pdpy->xdmcpAuthorization = (Xauth *) NULL; + pdpy->next = protoDisplays; + protoDisplays = pdpy; + return pdpy; +} + +void +DisposeProtoDisplay (pdpy) + struct protoDisplay *pdpy; +{ + struct protoDisplay *p, *prev; + + prev = 0; + for (p = protoDisplays; p; p=p->next) + { + if (p == pdpy) + break; + prev = p; + } + if (!p) + return; + if (prev) + prev->next = pdpy->next; + else + protoDisplays = pdpy->next; + bzero(&pdpy->key, sizeof(pdpy->key)); + if (pdpy->fileAuthorization) + XauDisposeAuth (pdpy->fileAuthorization); + if (pdpy->xdmcpAuthorization) + XauDisposeAuth (pdpy->xdmcpAuthorization); + XdmcpDisposeARRAY8 (&pdpy->connectionAddress); + free ((char *) pdpy->address); + free ((char *) pdpy); +} + +#endif /* XDMCP */ @@ -0,0 +1,116 @@ +/* $Xorg: reset.c,v 1.4 2001/02/09 02:05:40 xorgcvs Exp $ */ +/* + +Copyright 1988, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall +not be used in advertising or otherwise to promote the sale, use or +other dealings in this Software without prior written authorization +from The Open Group. + +*/ + +/* + * xdm - display manager daemon + * Author: Keith Packard, MIT X Consortium + * + * pseudoReset -- pretend to reset the server by killing all clients + * with windows. It will reset the server most of the time, unless + * a client remains connected with no windows. + */ + +# include "dm.h" +# include <X11/Xlib.h> +# include <signal.h> + +/*ARGSUSED*/ +static int +ignoreErrors (dpy, event) +Display *dpy; +XErrorEvent *event; +{ + Debug ("ignoring error\n"); +} + +/* + * this is mostly bogus -- but quite useful. I wish the protocol + * had some way of enumerating and identifying clients, that way + * this code wouldn't have to be this kludgy. + */ + +static +killWindows (dpy, window) +Display *dpy; +Window window; +{ + Window root, parent, *children; + int child; + unsigned int nchildren = 0; + + while (XQueryTree (dpy, window, &root, &parent, &children, &nchildren) + && nchildren > 0) + { + for (child = 0; child < nchildren; child++) { + Debug ("XKillClient 0x%x\n", children[child]); + XKillClient (dpy, children[child]); + } + XFree ((char *)children); + } +} + +static Jmp_buf resetJmp; + +/* ARGSUSED */ +static SIGVAL +abortReset (n) + int n; +{ + Longjmp (resetJmp, 1); +} + +/* + * this display connection better not have any windows... + */ + +pseudoReset (dpy) +Display *dpy; +{ + Window root; + int screen; + + if (Setjmp (resetJmp)) { + LogError ("pseudoReset timeout\n"); + } else { + (void) Signal (SIGALRM, abortReset); + (void) alarm (30); + XSetErrorHandler (ignoreErrors); + for (screen = 0; screen < ScreenCount (dpy); screen++) { + Debug ("pseudoReset screen %d\n", screen); + root = RootWindow (dpy, screen); + killWindows (dpy, root); + } + Debug ("before XSync\n"); + XSync (dpy, False); + (void) alarm (0); + } + Signal (SIGALRM, SIG_DFL); + XSetErrorHandler ((int (*)()) 0); + Debug ("pseudoReset done\n"); +} diff --git a/resource.c b/resource.c new file mode 100644 index 0000000..5745ae6 --- /dev/null +++ b/resource.c @@ -0,0 +1,472 @@ +/* $Xorg: resource.c,v 1.4 2001/02/09 02:05:40 xorgcvs Exp $ */ +/* + +Copyright 1988, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall +not be used in advertising or otherwise to promote the sale, use or +other dealings in this Software without prior written authorization +from The Open Group. + +*/ + +/* + * xdm - display manager daemon + * Author: Keith Packard, MIT X Consortium + * + * resource.c + */ + +# include "dm.h" +# include <X11/Intrinsic.h> +# include <X11/Xmu/CharSet.h> + +char *config; + +char *servers; +int request_port; +int debugLevel; +char *errorLogFile; +int daemonMode; +char *pidFile; +int lockPidFile; +char *authDir; +int autoRescan; +int removeDomainname; +char *keyFile; +char *accessFile; +char **exportList; +char *randomFile; +char *greeterLib; +int choiceTimeout; /* chooser choice timeout */ + +# define DM_STRING 0 +# define DM_INT 1 +# define DM_BOOL 2 +# define DM_ARGV 3 + +/* + * the following constants are supposed to be set in the makefile from + * parameters set util/imake.includes/site.def (or *.macros in that directory + * if it is server-specific). DO NOT CHANGE THESE DEFINITIONS! + */ +#ifndef DEF_SERVER_LINE +#define DEF_SERVER_LINE ":0 local /usr/bin/X11/X :0" +#endif +#ifndef XRDB_PROGRAM +#define XRDB_PROGRAM "/usr/bin/X11/xrdb" +#endif +#ifndef DEF_SESSION +#define DEF_SESSION "/usr/bin/X11/xterm -ls" +#endif +#ifndef DEF_USER_PATH +#define DEF_USER_PATH ":/bin:/usr/bin:/usr/bin/X11:/usr/ucb" +#endif +#ifndef DEF_SYSTEM_PATH +#define DEF_SYSTEM_PATH "/etc:/bin:/usr/bin:/usr/bin/X11:/usr/ucb" +#endif +#ifndef DEF_SYSTEM_SHELL +#define DEF_SYSTEM_SHELL "/bin/sh" +#endif +#ifndef DEF_FAILSAFE_CLIENT +#define DEF_FAILSAFE_CLIENT "/usr/bin/X11/xterm" +#endif +#ifndef DEF_XDM_CONFIG +#define DEF_XDM_CONFIG "/usr/lib/X11/xdm/xdm-config" +#endif +#ifndef DEF_CHOOSER +#define DEF_CHOOSER "/usr/lib/X11/xdm/chooser" +#endif +#ifndef DEF_AUTH_NAME +#ifdef HASXDMAUTH +#define DEF_AUTH_NAME "XDM-AUTHORIZATION-1 MIT-MAGIC-COOKIE-1" +#else +#define DEF_AUTH_NAME "MIT-MAGIC-COOKIE-1" +#endif +#endif +#ifndef DEF_AUTH_DIR +#define DEF_AUTH_DIR "/usr/lib/X11/xdm" +#endif +#ifndef DEF_USER_AUTH_DIR +#define DEF_USER_AUTH_DIR "/tmp" +#endif +#ifndef DEF_KEY_FILE +#define DEF_KEY_FILE "" +#endif +#ifndef DEF_ACCESS_FILE +#define DEF_ACCESS_FILE "" +#endif +#ifndef DEF_RANDOM_FILE +#define DEF_RANDOM_FILE "/dev/mem" +#endif +#ifndef DEF_GREETER_LIB +#define DEF_GREETER_LIB "/X11/lib/X11/xdm/libXdmGreet.so" +#endif + +#define DEF_UDP_PORT "177" /* registered XDMCP port, dont change */ + +struct dmResources { + char *name, *class; + int type; + char **dm_value; + char *default_value; +} DmResources[] = { +"servers", "Servers", DM_STRING, &servers, + DEF_SERVER_LINE, +"requestPort", "RequestPort", DM_INT, (char **) &request_port, + DEF_UDP_PORT, +"debugLevel", "DebugLevel", DM_INT, (char **) &debugLevel, + "0", +"errorLogFile", "ErrorLogFile", DM_STRING, &errorLogFile, + "", +"daemonMode", "DaemonMode", DM_BOOL, (char **) &daemonMode, + "true", +"pidFile", "PidFile", DM_STRING, &pidFile, + "", +"lockPidFile", "LockPidFile", DM_BOOL, (char **) &lockPidFile, + "true", +"authDir", "authDir", DM_STRING, &authDir, + DEF_AUTH_DIR, +"autoRescan", "AutoRescan", DM_BOOL, (char **) &autoRescan, + "true", +"removeDomainname","RemoveDomainname",DM_BOOL, (char **) &removeDomainname, + "true", +"keyFile", "KeyFile", DM_STRING, &keyFile, + DEF_KEY_FILE, +"accessFile", "AccessFile", DM_STRING, &accessFile, + DEF_ACCESS_FILE, +"exportList", "ExportList", DM_ARGV, (char **) &exportList, + "", +"randomFile", "RandomFile", DM_STRING, &randomFile, + DEF_RANDOM_FILE, +"greeterLib", "GreeterLib", DM_STRING, &greeterLib, + DEF_GREETER_LIB, +"choiceTimeout","ChoiceTimeout",DM_INT, (char **) &choiceTimeout, + "15", +}; + +# define NUM_DM_RESOURCES (sizeof DmResources / sizeof DmResources[0]) + +# define boffset(f) XtOffsetOf(struct display, f) + +struct displayResource { + char *name, *class; + int type; + int offset; + char *default_value; +}; + +/* resources for managing the server */ + +struct displayResource serverResources[] = { +"serverAttempts","ServerAttempts",DM_INT, boffset(serverAttempts), + "1", +"openDelay", "OpenDelay", DM_INT, boffset(openDelay), + "15", +"openRepeat", "OpenRepeat", DM_INT, boffset(openRepeat), + "5", +"openTimeout", "OpenTimeout", DM_INT, boffset(openTimeout), + "30", +"startAttempts","StartAttempts",DM_INT, boffset(startAttempts), + "4", +"pingInterval", "PingInterval", DM_INT, boffset(pingInterval), + "5", +"pingTimeout", "PingTimeout", DM_INT, boffset(pingTimeout), + "5", +"terminateServer","TerminateServer",DM_BOOL, boffset(terminateServer), + "false", +"grabServer", "GrabServer", DM_BOOL, boffset(grabServer), + "false", +"grabTimeout", "GrabTimeout", DM_INT, boffset(grabTimeout), + "3", +"resetSignal", "Signal", DM_INT, boffset(resetSignal), + "1", /* SIGHUP */ +"termSignal", "Signal", DM_INT, boffset(termSignal), + "15", /* SIGTERM */ +"resetForAuth", "ResetForAuth", DM_BOOL, boffset(resetForAuth), + "false", +"authorize", "Authorize", DM_BOOL, boffset(authorize), + "true", +"authComplain", "AuthComplain", DM_BOOL, boffset(authComplain), + "true", +"authName", "AuthName", DM_ARGV, boffset(authNames), + DEF_AUTH_NAME, +"authFile", "AuthFile", DM_STRING, boffset(clientAuthFile), + "", +}; + +# define NUM_SERVER_RESOURCES (sizeof serverResources/\ + sizeof serverResources[0]) + +/* resources which control the session behaviour */ + +struct displayResource sessionResources[] = { +"resources", "Resources", DM_STRING, boffset(resources), + "", +"xrdb", "Xrdb", DM_STRING, boffset(xrdb), + XRDB_PROGRAM, +"setup", "Setup", DM_STRING, boffset(setup), + "", +"startup", "Startup", DM_STRING, boffset(startup), + "", +"reset", "Reset", DM_STRING, boffset(reset), + "", +"session", "Session", DM_STRING, boffset(session), + DEF_SESSION, +"userPath", "Path", DM_STRING, boffset(userPath), + DEF_USER_PATH, +"systemPath", "Path", DM_STRING, boffset(systemPath), + DEF_SYSTEM_PATH, +"systemShell", "Shell", DM_STRING, boffset(systemShell), + DEF_SYSTEM_SHELL, +"failsafeClient","FailsafeClient", DM_STRING, boffset(failsafeClient), + DEF_FAILSAFE_CLIENT, +"userAuthDir", "UserAuthDir", DM_STRING, boffset(userAuthDir), + DEF_USER_AUTH_DIR, +"chooser", "Chooser", DM_STRING, boffset(chooser), + DEF_CHOOSER, +}; + +# define NUM_SESSION_RESOURCES (sizeof sessionResources/\ + sizeof sessionResources[0]) + +XrmDatabase DmResourceDB; + +GetResource (name, class, valueType, valuep, default_value) + char *name, *class; + int valueType; + char **valuep; + char *default_value; +{ + char *type; + XrmValue value; + char *string, *new_string; + char str_buf[50]; + int len; + extern char **parseArgs(); + + if (DmResourceDB && XrmGetResource (DmResourceDB, + name, class, + &type, &value)) + { + string = value.addr; + len = value.size; + } + else + { + string = default_value; + len = strlen (string); + } + + Debug ("%s/%s value %*.*s\n", name, class, len, len, string); + + if (valueType == DM_STRING && *valuep) + { + if (strlen (*valuep) == len && !strncmp (*valuep, string, len)) + return; + else + free (*valuep); + } + + switch (valueType) { + case DM_STRING: + new_string = malloc ((unsigned) (len+1)); + if (!new_string) { + LogOutOfMem ("GetResource"); + return; + } + strncpy (new_string, string, len); + new_string[len] = '\0'; + *(valuep) = new_string; + break; + case DM_INT: + strncpy (str_buf, string, sizeof (str_buf)); + str_buf[sizeof (str_buf)-1] = '\0'; + *((int *) valuep) = atoi (str_buf); + break; + case DM_BOOL: + strncpy (str_buf, string, sizeof (str_buf)); + str_buf[sizeof (str_buf)-1] = '\0'; + XmuCopyISOLatin1Lowered (str_buf, str_buf); + if (!strcmp (str_buf, "true") || + !strcmp (str_buf, "on") || + !strcmp (str_buf, "yes")) + *((int *) valuep) = 1; + else if (!strcmp (str_buf, "false") || + !strcmp (str_buf, "off") || + !strcmp (str_buf, "no")) + *((int *) valuep) = 0; + break; + case DM_ARGV: + freeArgs (*(char ***) valuep); + *((char ***) valuep) = parseArgs ((char **) 0, string); + break; + } +} + +XrmOptionDescRec configTable [] = { +{"-server", NULL, XrmoptionSkipArg, (caddr_t) NULL }, +{"-udpPort", NULL, XrmoptionSkipArg, (caddr_t) NULL }, +{"-error", NULL, XrmoptionSkipArg, (caddr_t) NULL }, +{"-resources", NULL, XrmoptionSkipArg, (caddr_t) NULL }, +{"-session", NULL, XrmoptionSkipArg, (caddr_t) NULL }, +{"-debug", NULL, XrmoptionSkipArg, (caddr_t) NULL }, +{"-xrm", NULL, XrmoptionSkipArg, (caddr_t) NULL }, +{"-config", ".configFile", XrmoptionSepArg, (caddr_t) NULL } +}; + +XrmOptionDescRec optionTable [] = { +{"-server", ".servers", XrmoptionSepArg, (caddr_t) NULL }, +{"-udpPort", ".requestPort", XrmoptionSepArg, (caddr_t) NULL }, +{"-error", ".errorLogFile", XrmoptionSepArg, (caddr_t) NULL }, +{"-resources", "*resources", XrmoptionSepArg, (caddr_t) NULL }, +{"-session", "*session", XrmoptionSepArg, (caddr_t) NULL }, +{"-debug", "*debugLevel", XrmoptionSepArg, (caddr_t) NULL }, +{"-xrm", NULL, XrmoptionResArg, (caddr_t) NULL }, +{"-daemon", ".daemonMode", XrmoptionNoArg, "true" }, +{"-nodaemon", ".daemonMode", XrmoptionNoArg, "false" } +}; + +static int originalArgc; +static char **originalArgv; + +InitResources (argc, argv) +int argc; +char **argv; +{ + XrmInitialize (); + originalArgc = argc; + originalArgv = argv; + ReinitResources (); +} + +ReinitResources () +{ + int argc; + char **a; + char **argv; + XrmDatabase newDB; + + argv = (char **) malloc ((originalArgc + 1) * sizeof (char *)); + if (!argv) + LogPanic ("no space for argument realloc\n"); + for (argc = 0; argc < originalArgc; argc++) + argv[argc] = originalArgv[argc]; + argv[argc] = 0; + if (DmResourceDB) + XrmDestroyDatabase (DmResourceDB); + DmResourceDB = XrmGetStringDatabase (""); + /* pre-parse the command line to get the -config option, if any */ + XrmParseCommand (&DmResourceDB, configTable, + sizeof (configTable) / sizeof (configTable[0]), + "DisplayManager", &argc, argv); + GetResource ("DisplayManager.configFile", "DisplayManager.ConfigFile", + DM_STRING, &config, DEF_XDM_CONFIG); + newDB = XrmGetFileDatabase ( config ); + if (newDB) + { + if (DmResourceDB) + XrmDestroyDatabase (DmResourceDB); + DmResourceDB = newDB; + } + else if (argc != originalArgc) + LogError ("Can't open configuration file %s\n", config ); + XrmParseCommand (&DmResourceDB, optionTable, + sizeof (optionTable) / sizeof (optionTable[0]), + "DisplayManager", &argc, argv); + if (argc > 1) + { + LogError ("extra arguments on command line:"); + for (a = argv + 1; *a; a++) + LogError (" \"%s\"", *a); + LogError ("\n"); + } + free (argv); +} + +LoadDMResources () +{ + int i; + char name[1024], class[1024]; + + for (i = 0; i < NUM_DM_RESOURCES; i++) { + sprintf (name, "DisplayManager.%s", DmResources[i].name); + sprintf (class, "DisplayManager.%s", DmResources[i].class); + GetResource (name, class, DmResources[i].type, + (char **) DmResources[i].dm_value, + DmResources[i].default_value); + } +} + +static +CleanUpName (src, dst, len) +char *src, *dst; +int len; +{ + while (*src) { + if (--len <= 0) + break; + switch (*src) + { + case ':': + case '.': + *dst++ = '_'; + break; + default: + *dst++ = *src; + } + ++src; + } + *dst = '\0'; +} + +LoadDisplayResources (d, resources, numResources) + struct display *d; + struct displayResource *resources; + int numResources; +{ + int i; + char name[1024], class[1024]; + char dpyName[512], dpyClass[512]; + + CleanUpName (d->name, dpyName, sizeof (dpyName)); + CleanUpName (d->class ? d->class : d->name, dpyClass, sizeof (dpyClass)); + for (i = 0; i < numResources; i++) { + sprintf (name, "DisplayManager.%s.%s", + dpyName, resources[i].name); + sprintf (class, "DisplayManager.%s.%s", + dpyClass, resources[i].class); + GetResource (name, class, resources[i].type, + (char **) (((char *) d) + resources[i].offset), + resources[i].default_value); + } +} + +LoadServerResources (d) + struct display *d; +{ + LoadDisplayResources (d, serverResources, NUM_SERVER_RESOURCES); +} + +LoadSessionResources (d) + struct display *d; +{ + LoadDisplayResources (d, sessionResources, NUM_SESSION_RESOURCES); +} diff --git a/rpcauth.c b/rpcauth.c new file mode 100644 index 0000000..7c94652 --- /dev/null +++ b/rpcauth.c @@ -0,0 +1,88 @@ +/* $Xorg: rpcauth.c,v 1.4 2001/02/09 02:05:40 xorgcvs Exp $ */ +/* + +Copyright 1988, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall +not be used in advertising or otherwise to promote the sale, use or +other dealings in this Software without prior written authorization +from The Open Group. + +*/ + +/* + * xdm - display manager daemon + * Author: Keith Packard, MIT X Consortium + * + * rpcauth + * + * generate SecureRPC authorization records + */ + +# include <X11/Xos.h> +# include <rpc/rpc.h> +# include <rpc/key_prot.h> +# include "dm.h" + +/*ARGSUSED*/ +SecureRPCInitAuth (name_len, name) + unsigned short name_len; + char *name; +{ +} + +Xauth * +SecureRPCGetAuth (namelen, name) + unsigned short namelen; + char *name; +{ + char key[MAXNETNAMELEN+1]; + Xauth *new; + + new = (Xauth *) malloc (sizeof *new); + if (!new) + return (Xauth *) 0; + new->family = FamilyWild; + new->address_length = 0; + new->address = 0; + new->number_length = 0; + new->number = 0; + + getnetname (key); + Debug ("System netname %s\n", key); + new->data_length = strlen(key); + new->data = (char *) malloc (new->data_length); + if (!new->data) + { + free ((char *) new); + return (Xauth *) 0; + } + new->name = (char *) malloc (namelen); + if (!new->name) + { + free ((char *) new->data); + free ((char *) new); + return (Xauth *) 0; + } + memmove( new->name, name, namelen); + new->name_length = namelen; + memmove( new->data, key, new->data_length); + return new; +} diff --git a/server.c b/server.c new file mode 100644 index 0000000..76c17d7 --- /dev/null +++ b/server.c @@ -0,0 +1,419 @@ +/* $Xorg: server.c,v 1.5 2001/02/09 02:05:40 xorgcvs Exp $ */ +/* + +Copyright 1988, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall +not be used in advertising or otherwise to promote the sale, use or +other dealings in this Software without prior written authorization +from The Open Group. + +*/ + +/* + * xdm - display manager daemon + * Author: Keith Packard, MIT X Consortium + * + * server.c - manage the X server + */ + +# include "dm.h" +# include <X11/Xlib.h> +# include <X11/Xos.h> +# include <stdio.h> +# include <signal.h> +# include <errno.h> +# include <sys/socket.h> + +static receivedUsr1; + +#ifdef X_NOT_STDC_ENV +extern int errno; +#endif + +static serverPause (); + +static Display *dpy; + +/* ARGSUSED */ +static SIGVAL +CatchUsr1 (n) + int n; +{ +#ifdef SIGNALS_RESET_WHEN_CAUGHT + (void) Signal (SIGUSR1, CatchUsr1); +#endif + Debug ("display manager caught SIGUSR1\n"); + ++receivedUsr1; +} + +char *_SysErrorMsg (n) + int n; +{ + char *s = strerror(n); + return (s ? s : "unknown error"); +} + +StartServerOnce (d) +struct display *d; +{ + char **f; + char **argv; + char arg[1024]; + char **parseArgs (); + int pid; + + Debug ("StartServer for %s\n", d->name); + receivedUsr1 = 0; + (void) Signal (SIGUSR1, CatchUsr1); + argv = d->argv; + switch (pid = fork ()) { + case 0: + CleanUpChild (); + if (d->authFile) { + sprintf (arg, "-auth %s", d->authFile); + argv = parseArgs (argv, arg); + } + if (!argv) { + LogError ("StartServer: no arguments\n"); + sleep ((unsigned) d->openDelay); + exit (UNMANAGE_DISPLAY); + } + for (f = argv; *f; f++) + Debug ("'%s' ", *f); + Debug ("\n"); + /* + * give the server SIGUSR1 ignored, + * it will notice that and send SIGUSR1 + * when ready + */ + (void) Signal (SIGUSR1, SIG_IGN); + (void) execv (argv[0], argv); + LogError ("server %s cannot be executed\n", + argv[0]); + sleep ((unsigned) d->openDelay); + exit (REMANAGE_DISPLAY); + case -1: + LogError ("fork failed, sleeping\n"); + return 0; + default: + break; + } + Debug ("Server Started %d\n", pid); + d->serverPid = pid; + if (serverPause ((unsigned) d->openDelay, pid)) + return FALSE; + return TRUE; +} + +StartServer (d) +struct display *d; +{ + int i; + int ret = FALSE; + + i = 0; + while (d->serverAttempts == 0 || i < d->serverAttempts) + { + if ((ret = StartServerOnce (d)) == TRUE) + break; + sleep (d->openDelay); + i++; + } + return ret; +} + +/* + * sleep for t seconds, return 1 if the server is dead when + * the sleep finishes, 0 else + */ + +static Jmp_buf pauseAbort; +static int serverPauseRet; + +/* ARGSUSED */ +static SIGVAL +serverPauseAbort (n) + int n; +{ + Longjmp (pauseAbort, 1); +} + +/* ARGSUSED */ +static SIGVAL +serverPauseUsr1 (n) + int n; +{ + Debug ("display manager paused til SIGUSR1\n"); + ++receivedUsr1; + Longjmp (pauseAbort, 1); +} + +static +serverPause (t, serverPid) +unsigned t; +int serverPid; +{ + int pid; + + serverPauseRet = 0; + if (!Setjmp (pauseAbort)) { + (void) Signal (SIGALRM, serverPauseAbort); + (void) Signal (SIGUSR1, serverPauseUsr1); +#ifdef SYSV + if (receivedUsr1) + (void) alarm ((unsigned) 1); + else + (void) alarm (t); +#else + if (!receivedUsr1) + (void) alarm (t); + else + Debug ("Already received USR1\n"); +#endif + for (;;) { +#if defined(SYSV) && defined(X_NOT_POSIX) + pid = wait ((waitType *) 0); +#else + if (!receivedUsr1) + pid = wait ((waitType *) 0); + else +#ifndef X_NOT_POSIX + pid = waitpid (-1, (int *) 0, WNOHANG); +#else + pid = wait3 ((waitType *) 0, WNOHANG, + (struct rusage *) 0); +#endif /* X_NOT_POSIX */ +#endif /* SYSV */ + if (pid == serverPid || + pid == -1 && errno == ECHILD) + { + Debug ("Server dead\n"); + serverPauseRet = 1; + break; + } +#if !defined(SYSV) || !defined(X_NOT_POSIX) + if (pid == 0) { + Debug ("Server alive and kicking\n"); + break; + } +#endif + } + } + (void) alarm ((unsigned) 0); + (void) Signal (SIGALRM, SIG_DFL); + (void) Signal (SIGUSR1, CatchUsr1); + if (serverPauseRet) { + Debug ("Server died\n"); + LogError ("server unexpectedly died\n"); + } + return serverPauseRet; +} + + +/* + * this code is complicated by some TCP failings. On + * many systems, the connect will occasionally hang forever, + * this trouble is avoided by setting up a timeout to Longjmp + * out of the connect (possibly leaving piles of garbage around + * inside Xlib) and give up, terminating the server. + */ + +static Jmp_buf openAbort; + +/* ARGSUSED */ +static SIGVAL +abortOpen (n) + int n; +{ + Longjmp (openAbort, 1); +} + +#ifdef XDMCP + +#ifdef STREAMSCONN +#include <tiuser.h> +#endif + +static +GetRemoteAddress (d, fd) + struct display *d; + int fd; +{ + char buf[512]; + int len = sizeof (buf); +#ifdef STREAMSCONN + struct netbuf netb; +#endif + + if (d->peer) + free ((char *) d->peer); +#ifdef STREAMSCONN + netb.maxlen = sizeof(buf); + netb.buf = buf; + t_getname(fd, &netb, REMOTENAME); + len = 8; + /* lucky for us, t_getname returns something that looks like a sockaddr */ +#else + getpeername (fd, (struct sockaddr *) buf, &len); +#endif + d->peerlen = 0; + if (len) + { + d->peer = (XdmcpNetaddr) malloc (len); + if (d->peer) + { + memmove( (char *) d->peer, buf, len); + d->peerlen = len; + } + } + Debug ("Got remote address %s %d\n", d->name, d->peerlen); +} + +#endif /* XDMCP */ + +static int +openErrorHandler (dpy) + Display *dpy; +{ + LogError ("IO Error in XOpenDisplay\n"); + exit (OPENFAILED_DISPLAY); +} + +int +WaitForServer (d) + struct display *d; +{ + int i; + + for (i = 0; i < (d->openRepeat > 0 ? d->openRepeat : 1); i++) { + (void) Signal (SIGALRM, abortOpen); + (void) alarm ((unsigned) d->openTimeout); + if (!Setjmp (openAbort)) { + Debug ("Before XOpenDisplay(%s)\n", d->name); + errno = 0; + (void) XSetIOErrorHandler (openErrorHandler); + dpy = XOpenDisplay (d->name); +#ifdef STREAMSCONN + { + /* For some reason, the next XOpenDisplay we do is + going to fail, so we might as well get that out + of the way. There is something broken here. */ + Display *bogusDpy = XOpenDisplay (d->name); + Debug ("bogus XOpenDisplay %s\n", + bogusDpy ? "succeeded" : "failed"); + if (bogusDpy) XCloseDisplay(bogusDpy); /* just in case */ + } +#endif + (void) alarm ((unsigned) 0); + (void) Signal (SIGALRM, SIG_DFL); + (void) XSetIOErrorHandler ((int (*)()) 0); + Debug ("After XOpenDisplay(%s)\n", d->name); + if (dpy) { +#ifdef XDMCP + if (d->displayType.location == Foreign) + GetRemoteAddress (d, ConnectionNumber (dpy)); +#endif + RegisterCloseOnFork (ConnectionNumber (dpy)); + (void) fcntl (ConnectionNumber (dpy), F_SETFD, 0); + return 1; + } else { + Debug ("OpenDisplay failed %d (%s) on \"%s\"\n", + errno, _SysErrorMsg (errno), d->name); + } + Debug ("waiting for server to start %d\n", i); + sleep ((unsigned) d->openDelay); + } else { + Debug ("hung in open, aborting\n"); + LogError ("Hung in XOpenDisplay(%s), aborting\n", d->name); + (void) Signal (SIGALRM, SIG_DFL); + break; + } + } + Debug ("giving up on server\n"); + LogError ("server open failed for %s, giving up\n", d->name); + return 0; +} + +ResetServer (d) + struct display *d; +{ + if (dpy && d->displayType.origin != FromXDMCP) + pseudoReset (dpy); +} + +static Jmp_buf pingTime; + +static void +PingLost () +{ + Longjmp (pingTime, 1); +} + +/* ARGSUSED */ +static int +PingLostIOErr (dpy) + Display *dpy; +{ + PingLost(); +} + +/* ARGSUSED */ +static SIGVAL +PingLostSig (n) + int n; +{ + PingLost(); +} + +PingServer (d, alternateDpy) + struct display *d; + Display *alternateDpy; +{ + int (*oldError)(); + SIGVAL (*oldSig)(); + int oldAlarm; + + if (!alternateDpy) + alternateDpy = dpy; + oldError = XSetIOErrorHandler (PingLostIOErr); + oldAlarm = alarm (0); + oldSig = Signal (SIGALRM, PingLostSig); + (void) alarm (d->pingTimeout * 60); + if (!Setjmp (pingTime)) + { + Debug ("Ping server\n"); + XSync (alternateDpy, 0); + } + else + { + Debug ("Server dead\n"); + (void) alarm (0); + (void) Signal (SIGALRM, SIG_DFL); + XSetIOErrorHandler (oldError); + return 0; + } + (void) alarm (0); + (void) Signal (SIGALRM, oldSig); + (void) alarm (oldAlarm); + Debug ("Server alive\n"); + XSetIOErrorHandler (oldError); + return 1; +} diff --git a/session.c b/session.c new file mode 100644 index 0000000..9eae405 --- /dev/null +++ b/session.c @@ -0,0 +1,878 @@ +/* $Xorg: session.c,v 1.8 2001/02/09 02:05:40 xorgcvs Exp $ */ +/* + +Copyright 1988, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall +not be used in advertising or otherwise to promote the sale, use or +other dealings in this Software without prior written authorization +from The Open Group. + +*/ + +/* + * xdm - display manager daemon + * Author: Keith Packard, MIT X Consortium + * + * session.c + */ + +#include "dm.h" +#include "greet.h" +#include <X11/Xlib.h> +#include <signal.h> +#include <X11/Xatom.h> +#include <errno.h> +#include <stdio.h> +#include <ctype.h> +#ifdef AIXV3 +# include <usersec.h> +#endif +#ifdef SECURE_RPC +# include <rpc/rpc.h> +# include <rpc/key_prot.h> +#endif +#ifdef K5AUTH +# include <krb5/krb5.h> +#endif + +#ifndef GREET_USER_STATIC +#include <dlfcn.h> +#ifndef RTLD_NOW +#define RTLD_NOW 1 +#endif +#endif + +#ifdef CSRG_BASED +#include <sys/param.h> +#ifdef HAS_SETUSERCONTEXT +#include <login_cap.h> +#include <pwd.h> +#endif +#endif + +extern int PingServer(); +extern int SessionPingFailed(); +extern int Debug(); +extern int RegisterCloseOnFork(); +extern int SecureDisplay(); +extern int UnsecureDisplay(); +extern int ClearCloseOnFork(); +extern int SetupDisplay(); +extern int LogError(); +extern int SessionExit(); +extern int DeleteXloginResources(); +extern int source(); +extern char **defaultEnv(); +extern char **setEnv(); +extern char **parseArgs(); +extern int printEnv(); +extern char **systemEnv(); +extern int LogOutOfMem(); +extern void setgrent(); +extern struct group *getgrent(); +extern void endgrent(); +#ifdef USESHADOW +extern struct spwd *getspnam(); +extern void endspent(); +#endif +extern struct passwd *getpwnam(); +extern char *crypt(); + +static struct dlfuncs dlfuncs = { + PingServer, + SessionPingFailed, + Debug, + RegisterCloseOnFork, + SecureDisplay, + UnsecureDisplay, + ClearCloseOnFork, + SetupDisplay, + LogError, + SessionExit, + DeleteXloginResources, + source, + defaultEnv, + setEnv, + parseArgs, + printEnv, + systemEnv, + LogOutOfMem, + setgrent, + getgrent, + endgrent, +#ifdef USESHADOW + getspnam, + endspent, +#endif + getpwnam, + crypt, + }; + +#ifdef X_NOT_STDC_ENV +extern int errno; +#endif + +static Bool StartClient(); + +static int clientPid; +static struct greet_info greet; +static struct verify_info verify; + +static Jmp_buf abortSession; + +/* ARGSUSED */ +static SIGVAL +catchTerm (n) + int n; +{ + Longjmp (abortSession, 1); +} + +static Jmp_buf pingTime; + +/* ARGSUSED */ +static SIGVAL +catchAlrm (n) + int n; +{ + Longjmp (pingTime, 1); +} + +static Jmp_buf tenaciousClient; + +/* ARGSUSED */ +static SIGVAL +waitAbort (n) + int n; +{ + Longjmp (tenaciousClient, 1); +} + +#if defined(_POSIX_SOURCE) || defined(SYSV) || defined(SVR4) +#define killpg(pgrp, sig) kill(-(pgrp), sig) +#endif + +static void +AbortClient (pid) + int pid; +{ + int sig = SIGTERM; +#ifdef __STDC__ + volatile int i; +#else + int i; +#endif + int retId; + for (i = 0; i < 4; i++) { + if (killpg (pid, sig) == -1) { + switch (errno) { + case EPERM: + LogError ("xdm can't kill client\n"); + case EINVAL: + case ESRCH: + return; + } + } + if (!Setjmp (tenaciousClient)) { + (void) Signal (SIGALRM, waitAbort); + (void) alarm ((unsigned) 10); + retId = wait ((waitType *) 0); + (void) alarm ((unsigned) 0); + (void) Signal (SIGALRM, SIG_DFL); + if (retId == pid) + break; + } else + (void) Signal (SIGALRM, SIG_DFL); + sig = SIGKILL; + } +} + +SessionPingFailed (d) + struct display *d; +{ + if (clientPid > 1) + { + AbortClient (clientPid); + source (verify.systemEnviron, d->reset); + } + SessionExit (d, RESERVER_DISPLAY, TRUE); +} + +/* + * We need our own error handlers because we can't be sure what exit code Xlib + * will use, and our Xlib does exit(1) which matches REMANAGE_DISPLAY, which + * can cause a race condition leaving the display wedged. We need to use + * RESERVER_DISPLAY for IO errors, to ensure that the manager waits for the + * server to terminate. For other X errors, we should give up. + */ + +/*ARGSUSED*/ +static +IOErrorHandler (dpy) + Display *dpy; +{ + LogError("fatal IO error %d (%s)\n", errno, _SysErrorMsg(errno)); + exit(RESERVER_DISPLAY); +} + +static int +ErrorHandler(dpy, event) + Display *dpy; + XErrorEvent *event; +{ + LogError("X error\n"); + if (XmuPrintDefaultErrorMessage (dpy, event, stderr) == 0) return 0; + exit(UNMANAGE_DISPLAY); + /*NOTREACHED*/ +} + +ManageSession (d) +struct display *d; +{ + int pid; + Display *dpy; + greet_user_rtn greet_stat; + static GreetUserProc greet_user_proc = NULL; +#ifndef GREET_USER_STATIC + void *greet_lib_handle; +#endif + + Debug ("ManageSession %s\n", d->name); + (void)XSetIOErrorHandler(IOErrorHandler); + (void)XSetErrorHandler(ErrorHandler); + SetTitle(d->name, (char *) 0); + /* + * Load system default Resources + */ + LoadXloginResources (d); + +#ifdef GREET_USER_STATIC + greet_user_proc = GreetUser; +#else + Debug("ManageSession: loading greeter library %s\n", greeterLib); + greet_lib_handle = dlopen(greeterLib, RTLD_NOW); + if (greet_lib_handle != NULL) + greet_user_proc = (GreetUserProc)dlsym(greet_lib_handle, "GreetUser"); + if (greet_user_proc == NULL) + { + LogError("%s while loading %s\n", dlerror(), greeterLib); + exit(UNMANAGE_DISPLAY); + } +#endif + + /* tell the possibly dynamically loaded greeter function + * what data structure formats to expect. + * These version numbers are registered with The Open Group. */ + verify.version = 1; + greet.version = 1; + greet_stat = (*greet_user_proc)(d, &dpy, &verify, &greet, &dlfuncs); + + if (greet_stat == Greet_Success) + { + clientPid = 0; + if (!Setjmp (abortSession)) { + (void) Signal (SIGTERM, catchTerm); + /* + * Start the clients, changing uid/groups + * setting up environment and running the session + */ + if (StartClient (&verify, d, &clientPid, greet.name, greet.password)) { + Debug ("Client Started\n"); + +#ifndef GREET_USER_STATIC + /* Save memory; close library */ + dlclose(greet_lib_handle); +#endif + + /* + * Wait for session to end, + */ + for (;;) { + if (d->pingInterval) + { + if (!Setjmp (pingTime)) + { + (void) Signal (SIGALRM, catchAlrm); + (void) alarm (d->pingInterval * 60); + pid = wait ((waitType *) 0); + (void) alarm (0); + } + else + { + (void) alarm (0); + if (!PingServer (d, (Display *) NULL)) + SessionPingFailed (d); + } + } + else + { + pid = wait ((waitType *) 0); + } + if (pid == clientPid) + break; + } + } else { + LogError ("session start failed\n"); + } + } else { + /* + * when terminating the session, nuke + * the child and then run the reset script + */ + AbortClient (clientPid); + } + } + /* + * run system-wide reset file + */ + Debug ("Source reset program %s\n", d->reset); + source (verify.systemEnviron, d->reset); + SessionExit (d, OBEYSESS_DISPLAY, TRUE); +} + +LoadXloginResources (d) +struct display *d; +{ + char **args, **parseArgs(); + char **env = 0, **setEnv(), **systemEnv(); + + if (d->resources[0] && access (d->resources, 4) == 0) { + env = systemEnv (d, (char *) 0, (char *) 0); + args = parseArgs ((char **) 0, d->xrdb); + args = parseArgs (args, d->resources); + Debug ("Loading resource file: %s\n", d->resources); + (void) runAndWait (args, env); + freeArgs (args); + freeEnv (env); + } +} + +SetupDisplay (d) +struct display *d; +{ + char **env = 0, **setEnv(), **systemEnv(); + + if (d->setup && d->setup[0]) + { + env = systemEnv (d, (char *) 0, (char *) 0); + (void) source (env, d->setup); + freeEnv (env); + } +} + +/*ARGSUSED*/ +DeleteXloginResources (d, dpy) +struct display *d; +Display *dpy; +{ + int i; + Atom prop = XInternAtom(dpy, "SCREEN_RESOURCES", True); + + XDeleteProperty(dpy, RootWindow (dpy, 0), XA_RESOURCE_MANAGER); + if (prop) { + for (i = ScreenCount(dpy); --i >= 0; ) + XDeleteProperty(dpy, RootWindow (dpy, i), prop); + } +} + +static Jmp_buf syncJump; + +/* ARGSUSED */ +static SIGVAL +syncTimeout (n) + int n; +{ + Longjmp (syncJump, 1); +} + +SecureDisplay (d, dpy) +struct display *d; +Display *dpy; +{ + Debug ("SecureDisplay %s\n", d->name); + (void) Signal (SIGALRM, syncTimeout); + if (Setjmp (syncJump)) { + LogError ("WARNING: display %s could not be secured\n", + d->name); + SessionExit (d, RESERVER_DISPLAY, FALSE); + } + (void) alarm ((unsigned) d->grabTimeout); + Debug ("Before XGrabServer %s\n", d->name); + XGrabServer (dpy); + if (XGrabKeyboard (dpy, DefaultRootWindow (dpy), True, GrabModeAsync, + GrabModeAsync, CurrentTime) != GrabSuccess) + { + (void) alarm (0); + (void) Signal (SIGALRM, SIG_DFL); + LogError ("WARNING: keyboard on display %s could not be secured\n", + d->name); + SessionExit (d, RESERVER_DISPLAY, FALSE); + } + Debug ("XGrabKeyboard succeeded %s\n", d->name); + (void) alarm (0); + (void) Signal (SIGALRM, SIG_DFL); + pseudoReset (dpy); + if (!d->grabServer) + { + XUngrabServer (dpy); + XSync (dpy, 0); + } + Debug ("done secure %s\n", d->name); +} + +UnsecureDisplay (d, dpy) +struct display *d; +Display *dpy; +{ + Debug ("Unsecure display %s\n", d->name); + if (d->grabServer) + { + XUngrabServer (dpy); + XSync (dpy, 0); + } +} + +SessionExit (d, status, removeAuth) + struct display *d; +{ + /* make sure the server gets reset after the session is over */ + if (d->serverPid >= 2 && d->resetSignal) + kill (d->serverPid, d->resetSignal); + else + ResetServer (d); + if (removeAuth) + { + setgid (verify.gid); + setuid (verify.uid); + RemoveUserAuthorization (d, &verify); +#ifdef K5AUTH + /* do like "kdestroy" program */ + { + krb5_error_code code; + krb5_ccache ccache; + + code = Krb5DisplayCCache(d->name, &ccache); + if (code) + LogError("%s while getting Krb5 ccache to destroy\n", + error_message(code)); + else { + code = krb5_cc_destroy(ccache); + if (code) { + if (code == KRB5_FCC_NOFILE) { + Debug ("No Kerberos ccache file found to destroy\n"); + } else + LogError("%s while destroying Krb5 credentials cache\n", + error_message(code)); + } else + Debug ("Kerberos ccache destroyed\n"); + krb5_cc_close(ccache); + } + } +#endif /* K5AUTH */ + } + Debug ("Display %s exiting with status %d\n", d->name, status); + exit (status); +} + +static Bool +StartClient (verify, d, pidp, name, passwd) + struct verify_info *verify; + struct display *d; + int *pidp; + char *name; + char *passwd; +{ + char **f, *home, *getEnv (); + char *failsafeArgv[2]; + int pid; +#ifdef HAS_SETUSERCONTEXT + struct passwd* pwd; +#endif + + if (verify->argv) { + Debug ("StartSession %s: ", verify->argv[0]); + for (f = verify->argv; *f; f++) + Debug ("%s ", *f); + Debug ("; "); + } + if (verify->userEnviron) { + for (f = verify->userEnviron; *f; f++) + Debug ("%s ", *f); + Debug ("\n"); + } + switch (pid = fork ()) { + case 0: + CleanUpChild (); + + /* Do system-dependent login setup here */ + +#ifndef AIXV3 +#ifndef HAS_SETUSERCONTEXT + if (setgid(verify->gid) < 0) + { + LogError("setgid %d (user \"%s\") failed, errno=%d\n", + verify->gid, name, errno); + return (0); + } +#if (BSD >= 199103) + if (setlogin(name) < 0) + { + LogError("setlogin for \"%s\" failed, errno=%d", name, errno); + return(0); + } +#endif + if (initgroups(name, verify->gid) < 0) + { + LogError("initgroups for \"%s\" failed, errno=%d\n", name, errno); + return (0); + } + if (setuid(verify->uid) < 0) + { + LogError("setuid %d (user \"%s\") failed, errno=%d\n", + verify->uid, name, errno); + return (0); + } +#else /* HAS_SETUSERCONTEXT */ + /* + * Set the user's credentials: uid, gid, groups, + * environment variables, resource limits, and umask. + */ + pwd = getpwnam(name); + if (pwd) + { + if (setusercontext(NULL, pwd, pwd->pw_uid, LOGIN_SETALL) < 0) + { + LogError("setusercontext for \"%s\" failed, errno=%d\n", name, + errno); + return (0); + } + endpwent(); + } + else + { + LogError("getpwnam for \"%s\" failed, errno=%d\n", name, errno); + return (0); + } +#endif /* HAS_SETUSERCONTEXT */ +#else /* AIXV3 */ + /* + * Set the user's credentials: uid, gid, groups, + * audit classes, user limits, and umask. + */ + if (setpcred(name, NULL) == -1) + { + LogError("setpcred for \"%s\" failed, errno=%d\n", name, errno); + return (0); + } +#endif /* AIXV3 */ + + /* + * for user-based authorization schemes, + * use the password to get the user's credentials. + */ +#ifdef SECURE_RPC + /* do like "keylogin" program */ + { + char netname[MAXNETNAMELEN+1], secretkey[HEXKEYBYTES+1]; + int nameret, keyret; + int len; + int key_set_ok = 0; + + nameret = getnetname (netname); + Debug ("User netname: %s\n", netname); + len = strlen (passwd); + if (len > 8) + bzero (passwd + 8, len - 8); + keyret = getsecretkey(netname,secretkey,passwd); + Debug ("getsecretkey returns %d, key length %d\n", + keyret, strlen (secretkey)); + /* 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 : name); + } + } + if (!key_set_ok) + { + /* remove SUN-DES-1 from authorizations list */ + int i, j; + for (i = 0; i < d->authNum; i++) + { + if (d->authorizations[i]->name_length == 9 && + memcmp(d->authorizations[i]->name, "SUN-DES-1", 9) == 0) + { + for (j = i+1; j < d->authNum; j++) + d->authorizations[j-1] = d->authorizations[j]; + d->authNum--; + break; + } + } + } + bzero(secretkey, strlen(secretkey)); + } +#endif +#ifdef K5AUTH + /* do like "kinit" program */ + { + int i, j; + int result; + extern char *Krb5CCacheName(); + + result = Krb5Init(name, passwd, d); + if (result == 0) { + /* point session clients at the Kerberos credentials cache */ + verify->userEnviron = + setEnv(verify->userEnviron, + "KRB5CCNAME", Krb5CCacheName(d->name)); + } else { + for (i = 0; i < d->authNum; i++) + { + if (d->authorizations[i]->name_length == 14 && + memcmp(d->authorizations[i]->name, "MIT-KERBEROS-5", 14) == 0) + { + /* remove Kerberos from authorizations list */ + for (j = i+1; j < d->authNum; j++) + d->authorizations[j-1] = d->authorizations[j]; + d->authNum--; + break; + } + } + } + } +#endif /* K5AUTH */ + bzero(passwd, strlen(passwd)); + SetUserAuthorization (d, verify); + home = getEnv (verify->userEnviron, "HOME"); + if (home) + if (chdir (home) == -1) { + LogError ("user \"%s\": cannot chdir to home \"%s\" (err %d), using \"/\"\n", + getEnv (verify->userEnviron, "USER"), home, errno); + chdir ("/"); + verify->userEnviron = setEnv(verify->userEnviron, "HOME", "/"); + } + if (verify->argv) { + Debug ("executing session %s\n", verify->argv[0]); + execute (verify->argv, verify->userEnviron); + LogError ("Session \"%s\" execution failed (err %d)\n", verify->argv[0], errno); + } else { + LogError ("Session has no command/arguments\n"); + } + failsafeArgv[0] = d->failsafeClient; + failsafeArgv[1] = 0; + execute (failsafeArgv, verify->userEnviron); + exit (1); + case -1: + bzero(passwd, strlen(passwd)); + Debug ("StartSession, fork failed\n"); + LogError ("can't start session on \"%s\", fork failed, errno=%d\n", + d->name, errno); + return 0; + default: + bzero(passwd, strlen(passwd)); + Debug ("StartSession, fork succeeded %d\n", pid); + *pidp = pid; + return 1; + } +} + +int +source (environ, file) +char **environ; +char *file; +{ + char **args, *args_safe[2]; + extern char **parseArgs (); + int ret; + + if (file && file[0]) { + Debug ("source %s\n", file); + args = parseArgs ((char **) 0, file); + if (!args) + { + args = args_safe; + args[0] = file; + args[1] = NULL; + } + ret = runAndWait (args, environ); + freeArgs (args); + return ret; + } + return 0; +} + +int +runAndWait (args, environ) + char **args; + char **environ; +{ + int pid; + waitType result; + + switch (pid = fork ()) { + case 0: + CleanUpChild (); + execute (args, environ); + LogError ("can't execute \"%s\" (err %d)\n", args[0], errno); + exit (1); + case -1: + Debug ("fork failed\n"); + LogError ("can't fork to execute \"%s\" (err %d)\n", args[0], errno); + return 1; + default: + while (wait (&result) != pid) + /* SUPPRESS 530 */ + ; + break; + } + return waitVal (result); +} + +void +execute (argv, environ) + char **argv; + char **environ; +{ + /* give /dev/null as stdin */ + (void) close (0); + open ("/dev/null", 0); + /* make stdout follow stderr to the log file */ + dup2 (2,1); + execve (argv[0], argv, environ); + /* + * In case this is a shell script which hasn't been + * made executable (or this is a SYSV box), do + * a reasonable thing + */ + if (errno != ENOENT) { + char program[1024], *e, *p, *optarg; + FILE *f; + char **newargv, **av; + int argc; + + /* + * emulate BSD kernel behaviour -- read + * the first line; check if it starts + * with "#!", in which case it uses + * the rest of the line as the name of + * program to run. Else use "/bin/sh". + */ + f = fopen (argv[0], "r"); + if (!f) + return; + if (fgets (program, sizeof (program) - 1, f) == NULL) + { + fclose (f); + return; + } + fclose (f); + e = program + strlen (program) - 1; + if (*e == '\n') + *e = '\0'; + if (!strncmp (program, "#!", 2)) { + p = program + 2; + while (*p && isspace (*p)) + ++p; + optarg = p; + while (*optarg && !isspace (*optarg)) + ++optarg; + if (*optarg) { + *optarg = '\0'; + do + ++optarg; + while (*optarg && isspace (*optarg)); + } else + optarg = 0; + } else { + p = "/bin/sh"; + optarg = 0; + } + Debug ("Shell script execution: %s (optarg %s)\n", + p, optarg ? optarg : "(null)"); + for (av = argv, argc = 0; *av; av++, argc++) + /* SUPPRESS 530 */ + ; + newargv = (char **) malloc ((argc + (optarg ? 3 : 2)) * sizeof (char *)); + if (!newargv) + return; + av = newargv; + *av++ = p; + if (optarg) + *av++ = optarg; + /* SUPPRESS 560 */ + while ((*av++ = *argv++)) + /* SUPPRESS 530 */ + ; + execve (newargv[0], newargv, environ); + } +} + +extern char **setEnv (); + +char ** +defaultEnv () +{ + char **env, **exp, *value; + + env = 0; + for (exp = exportList; exp && *exp; ++exp) + { + value = getenv (*exp); + if (value) + env = setEnv (env, *exp, value); + } + return env; +} + +char ** +systemEnv (d, user, home) +struct display *d; +char *user, *home; +{ + char **env; + + env = defaultEnv (); + env = setEnv (env, "DISPLAY", d->name); + if (home) + env = setEnv (env, "HOME", home); + if (user) + { + env = setEnv (env, "USER", user); + env = setEnv (env, "LOGNAME", user); + } + env = setEnv (env, "PATH", d->systemPath); + env = setEnv (env, "SHELL", d->systemShell); + if (d->authFile) + env = setEnv (env, "XAUTHORITY", d->authFile); + return env; +} diff --git a/socket.c b/socket.c new file mode 100644 index 0000000..47b0c79 --- /dev/null +++ b/socket.c @@ -0,0 +1,123 @@ +/* $Xorg: socket.c,v 1.4 2001/02/09 02:05:40 xorgcvs Exp $ */ +/* + +Copyright 1988, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall +not be used in advertising or otherwise to promote the sale, use or +other dealings in this Software without prior written authorization +from The Open Group. + +*/ + +/* + * xdm - display manager daemon + * Author: Keith Packard, MIT X Consortium + * + * socket.c - Support for BSD sockets + */ + +#include "dm.h" + +#ifdef XDMCP +#ifndef STREAMSCONN + +#include <errno.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <sys/un.h> +#include <netdb.h> + +#ifdef X_NOT_STDC_ENV +extern int errno; +#endif + + +extern int xdmcpFd; +extern int chooserFd; + +extern FD_TYPE WellKnownSocketsMask; +extern int WellKnownSocketsMax; + +CreateWellKnownSockets () +{ + struct sockaddr_in sock_addr; + char *name, *localHostname(); + + if (request_port == 0) + return; + Debug ("creating socket %d\n", request_port); + xdmcpFd = socket (AF_INET, SOCK_DGRAM, 0); + if (xdmcpFd == -1) { + LogError ("XDMCP socket creation failed, errno %d\n", errno); + return; + } + name = localHostname (); + registerHostname (name, strlen (name)); + RegisterCloseOnFork (xdmcpFd); + /* zero out the entire structure; this avoids 4.4 incompatibilities */ + bzero ((char *) &sock_addr, sizeof (sock_addr)); +#ifdef BSD44SOCKETS + sock_addr.sin_len = sizeof(sock_addr); +#endif + sock_addr.sin_family = AF_INET; + sock_addr.sin_port = htons ((short) request_port); + sock_addr.sin_addr.s_addr = htonl (INADDR_ANY); + if (bind (xdmcpFd, (struct sockaddr *)&sock_addr, sizeof (sock_addr)) == -1) + { + LogError ("error %d binding socket address %d\n", errno, request_port); + close (xdmcpFd); + xdmcpFd = -1; + return; + } + WellKnownSocketsMax = xdmcpFd; + FD_SET (xdmcpFd, &WellKnownSocketsMask); + + chooserFd = socket (AF_INET, SOCK_STREAM, 0); + Debug ("Created chooser socket %d\n", chooserFd); + if (chooserFd == -1) + { + LogError ("chooser socket creation failed, errno %d\n", errno); + return; + } + listen (chooserFd, 5); + if (chooserFd > WellKnownSocketsMax) + WellKnownSocketsMax = chooserFd; + FD_SET (chooserFd, &WellKnownSocketsMask); +} + +GetChooserAddr (addr, lenp) + char *addr; + int *lenp; +{ + struct sockaddr_in in_addr; + int len; + + len = sizeof in_addr; + if (getsockname (chooserFd, (struct sockaddr *)&in_addr, &len) < 0) + return -1; + Debug ("Chooser socket port: %d\n", ntohs(in_addr.sin_port)); + memmove( addr, (char *) &in_addr, len); + *lenp = len; + return 0; +} + +#endif /* !STREAMSCONN */ +#endif /* XDMCP */ diff --git a/streams.c b/streams.c new file mode 100644 index 0000000..585fe90 --- /dev/null +++ b/streams.c @@ -0,0 +1,147 @@ +/* $Xorg: streams.c,v 1.4 2001/02/09 02:05:40 xorgcvs Exp $ */ +/* + +Copyright 1988, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall +not be used in advertising or otherwise to promote the sale, use or +other dealings in this Software without prior written authorization +from The Open Group. + +*/ + +/* + * xdm - display manager daemon + * Author: Keith Packard, MIT X Consortium + * + * streams.c - Support for STREAMS + */ + +#include "dm.h" + +#ifdef XDMCP +#ifdef STREAMSCONN + +#include <fcntl.h> +#include <tiuser.h> +#include <netconfig.h> +#include <netdir.h> + +extern int xdmcpFd; +extern int chooserFd; + +extern FD_TYPE WellKnownSocketsMask; +extern int WellKnownSocketsMax; + +CreateWellKnownSockets () +{ + struct t_bind bind_addr; + struct netconfig *nconf; + struct nd_hostserv service; + struct nd_addrlist *servaddrs; + char *name, *localHostname(); + char bindbuf[15]; + int it; + + if (request_port == 0) + return; + Debug ("creating UDP stream %d\n", request_port); + + nconf = getnetconfigent("udp"); + if (!nconf) { + t_error("getnetconfigent udp"); + return; + } + + xdmcpFd = t_open(nconf->nc_device, O_RDWR, NULL); + if (xdmcpFd == -1) { + LogError ("XDMCP stream creation failed\n"); + t_error ("CreateWellKnownSockets(xdmcpFd): t_open failed"); + return; + } + name = localHostname (); + registerHostname (name, strlen (name)); + RegisterCloseOnFork (xdmcpFd); + + service.h_host = HOST_SELF; + sprintf(bindbuf, "%d", request_port); + service.h_serv = bindbuf; + netdir_getbyname(nconf, &service, &servaddrs); + freenetconfigent(nconf); + + bind_addr.qlen = 5; + bind_addr.addr.buf = servaddrs->n_addrs[0].buf; + bind_addr.addr.len = servaddrs->n_addrs[0].len; + bind_addr.addr.maxlen = servaddrs->n_addrs[0].len; + it = t_bind(xdmcpFd, &bind_addr, &bind_addr); + netdir_free((char *)servaddrs, ND_ADDRLIST); + if (it < 0) + { + LogError ("error binding STREAMS address %d\n", request_port); + t_error("CreateWellKNowSocket(xdmcpFd): t_bind failed"); + t_close (xdmcpFd); + xdmcpFd = -1; + return; + } + WellKnownSocketsMax = xdmcpFd; + FD_SET (xdmcpFd, &WellKnownSocketsMask); + + chooserFd = t_open ("/dev/tcp", O_RDWR, NULL); + Debug ("Created chooser fd %d\n", chooserFd); + if (chooserFd == -1) + { + LogError ("chooser stream creation failed\n"); + t_error("CreateWellKnowSockets(chooserFd): t_open failed"); + return; + } + bind_addr.qlen = 5; + bind_addr.addr.len = 0; + bind_addr.addr.maxlen = 0; + if( t_bind( chooserFd, &bind_addr, NULL ) < 0 ) + { + t_error("CreateWellKnowSockets(chooserFd): t_bind failed"); + } + + if (chooserFd > WellKnownSocketsMax) + WellKnownSocketsMax = chooserFd; + FD_SET (chooserFd, &WellKnownSocketsMask); +} + +GetChooserAddr (addr, lenp) + char *addr; /* return */ + int *lenp; /* size of addr, returned as amt used */ +{ + struct netbuf nbuf; + int retval; + + nbuf.buf = addr; + nbuf.len = *lenp; + nbuf.maxlen = *lenp; + retval = t_getname (chooserFd, &nbuf, LOCALNAME); + if (retval < 0) { + if (debugLevel > 0) + t_error("t_getname on chooser fd"); + } + *lenp = nbuf.len; + return retval; +} + +#endif /* STREAMSCONN */ +#endif /* XDMCP */ @@ -0,0 +1,263 @@ +/* $Xorg: util.c,v 1.4 2001/02/09 02:05:41 xorgcvs Exp $ */ +/* + +Copyright 1989, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall +not be used in advertising or otherwise to promote the sale, use or +other dealings in this Software without prior written authorization +from The Open Group. + +*/ + +/* + * xdm - display manager daemon + * Author: Keith Packard, MIT X Consortium + * + * util.c + * + * various utility routines + */ + +# include "dm.h" +#ifdef X_POSIX_C_SOURCE +#define _POSIX_C_SOURCE X_POSIX_C_SOURCE +#include <signal.h> +#undef _POSIX_C_SOURCE +#else +#if defined(X_NOT_POSIX) || defined(_POSIX_SOURCE) +#include <signal.h> +#else +#define _POSIX_SOURCE +#include <signal.h> +#undef _POSIX_SOURCE +#endif +#endif +#if defined(__osf__) || defined(linux) +#define setpgrp setpgid +#endif + +printEnv (e) +char **e; +{ + while (*e) + Debug ("%s\n", *e++); +} + +static char * +makeEnv (name, value) +char *name; +char *value; +{ + char *result; + + result = malloc ((unsigned) (strlen (name) + strlen (value) + 2)); + if (!result) { + LogOutOfMem ("makeEnv"); + return 0; + } + sprintf (result, "%s=%s", name, value); + return result; +} + +char * +getEnv (e, name) + char **e; + char *name; +{ + int l = strlen (name); + + if (!e) return 0; + + while (*e) { + if ((int)strlen (*e) > l && !strncmp (*e, name, l) && + (*e)[l] == '=') + return (*e) + l + 1; + ++e; + } + return 0; +} + +char ** +setEnv (e, name, value) + char **e; + char *name; + char *value; +{ + char **new, **old; + char *newe; + int envsize; + int l; + + l = strlen (name); + newe = makeEnv (name, value); + if (!newe) { + LogOutOfMem ("setEnv"); + return e; + } + if (e) { + for (old = e; *old; old++) + if ((int)strlen (*old) > l && !strncmp (*old, name, l) && (*old)[l] == '=') + break; + if (*old) { + free (*old); + *old = newe; + return e; + } + envsize = old - e; + new = (char **) realloc ((char *) e, + (unsigned) ((envsize + 2) * sizeof (char *))); + } else { + envsize = 0; + new = (char **) malloc (2 * sizeof (char *)); + } + if (!new) { + LogOutOfMem ("setEnv"); + free (newe); + return e; + } + new[envsize] = newe; + new[envsize+1] = 0; + return new; +} + +freeEnv (env) + char **env; +{ + char **e; + + if (env) + { + for (e = env; *e; e++) + free (*e); + free (env); + } +} + +# define isblank(c) ((c) == ' ' || c == '\t') + +char ** +parseArgs (argv, string) +char **argv; +char *string; +{ + char *word; + char *save; + int i; + + i = 0; + while (argv && argv[i]) + ++i; + if (!argv) { + argv = (char **) malloc (sizeof (char *)); + if (!argv) { + LogOutOfMem ("parseArgs"); + return 0; + } + } + word = string; + for (;;) { + if (!*string || isblank (*string)) { + if (word != string) { + argv = (char **) realloc ((char *) argv, + (unsigned) ((i + 2) * sizeof (char *))); + save = malloc ((unsigned) (string - word + 1)); + if (!argv || !save) { + LogOutOfMem ("parseArgs"); + if (argv) + free ((char *) argv); + if (save) + free (save); + return 0; + } + argv[i] = strncpy (save, word, string-word); + argv[i][string-word] = '\0'; + i++; + } + if (!*string) + break; + word = string + 1; + } + ++string; + } + argv[i] = 0; + return argv; +} + +freeArgs (argv) + char **argv; +{ + char **a; + + if (!argv) + return; + + for (a = argv; *a; a++) + free (*a); + free ((char *) argv); +} + +CleanUpChild () +{ +#if defined(SYSV) || defined(SVR4) + setpgrp (); +#else + setpgrp (0, getpid ()); + sigsetmask (0); +#endif +#ifdef SIGCHLD + (void) Signal (SIGCHLD, SIG_DFL); +#endif + (void) Signal (SIGTERM, SIG_DFL); + (void) Signal (SIGPIPE, SIG_DFL); + (void) Signal (SIGALRM, SIG_DFL); + (void) Signal (SIGHUP, SIG_DFL); + CloseOnFork (); +} + +static char localHostbuf[256]; +static int gotLocalHostname; + +char * +localHostname () +{ + if (!gotLocalHostname) + { + XmuGetHostname (localHostbuf, sizeof (localHostbuf) - 1); + gotLocalHostname = 1; + } + return localHostbuf; +} + +SIGVAL (*Signal (sig, handler))() + int sig; + SIGVAL (*handler)(); +{ +#ifndef X_NOT_POSIX + struct sigaction sigact, osigact; + sigact.sa_handler = handler; + sigemptyset(&sigact.sa_mask); + sigact.sa_flags = 0; + sigaction(sig, &sigact, &osigact); + return osigact.sa_handler; +#else + return signal(sig, handler); +#endif +} diff --git a/xdm.man.cpp b/xdm.man.cpp new file mode 100644 index 0000000..45f8a90 --- /dev/null +++ b/xdm.man.cpp @@ -0,0 +1,1258 @@ +.\" $Xorg: xdm.man,v 1.4 2001/02/09 02:05:41 xorgcvs Exp $ +.\" Copyright 1988, 1994, 1998 The Open Group +.\" +.\" Permission to use, copy, modify, distribute, and sell this software and its +.\" documentation for any purpose is hereby granted without fee, provided that +.\" the above copyright notice appear in all copies and that both that +.\" copyright notice and this permission notice appear in supporting +.\" documentation. +.\" +.\" The above copyright notice and this permission notice shall be included +.\" in all copies or substantial portions of the Software. +.\" +.\" THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +.\" OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +.\" MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +.\" IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR +.\" OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +.\" ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +.\" OTHER DEALINGS IN THE SOFTWARE. +.\" +.\" Except as contained in this notice, the name of The Open Group shall +.\" not be used in advertising or otherwise to promote the sale, use or +.\" other dealings in this Software without prior written authorization +.\" from The Open Group. +.TH XDM 1 "Release 6.4" "X Version 11" +.SH NAME +xdm \- X Display Manager with support for XDMCP, host chooser +.SH SYNOPSIS +.B xdm +[ +.B \-config +.I configuration_file +] [ +.B \-nodaemon +] [ +.B \-debug +.I debug_level +] [ +.B \-error +.I error_log_file +] [ +.B \-resources +.I resource_file +] [ +.B \-server +.I server_entry +] [ +.B \-session +.I session_program +] +.SH DESCRIPTION +.I Xdm +manages a collection of X displays, which may be on the local host +or remote servers. The design of +.I xdm +was guided by the needs of X terminals as well as The Open Group standard +XDMCP, the \fIX Display Manager Control Protocol\fP. +.I Xdm +provides services similar to those provided by \fIinit\fP, \fIgetty\fP +and \fIlogin\fP on character terminals: prompting for login name and password, +authenticating the user, and running a ``session.'' +.PP +A ``session'' is defined by the lifetime of a particular process; in the +traditional character-based terminal world, it is the user's login shell. +In the +.I xdm +context, it is an arbitrary session manager. This is because in a windowing +environment, a user's login shell process does not necessarily have any +terminal-like interface with which to connect. +When a real session manager is not available, a window manager or terminal +emulator is typically used as the ``session manager,'' meaning that +termination of this process terminates the user's session. +.PP +When the session is terminated, \fIxdm\fP +resets the X server and (optionally) restarts the whole process. +.PP +When \fIxdm\fP receives an Indirect query via XDMCP, it can run a +\fIchooser\fP process to +perform an XDMCP BroadcastQuery (or an XDMCP Query to specified hosts) +on behalf of the display and +offer a menu of possible hosts that offer XDMCP display management. +This feature is useful with X terminals that do not offer a host +menu themselves. +.PP +Because +.I xdm +provides the first interface that users will see, it is designed to be +simple to use and easy to customize to the needs of a particular site. +.I Xdm +has many options, most of which have reasonable defaults. Browse through the +various sections of this manual, +picking and choosing the things you want to change. +Pay particular attention to the +.B "Session Program" +section, which will describe how to +set up the style of session desired. +.SH "OVERVIEW" +\fIxdm\fP is highly configurable, and most of its behavior can be +controlled by resource files and shell scripts. The names of these +files themselves are resources read from the file \fIxdm-config\fP or +the file named by the \fB\-config\fP option. +.PP +\fIxdm\fP offers display management two different ways. It can manage +X servers running on the local machine and specified in +\fIXservers\fP, and it can manage remote X servers (typically X +terminals) using XDMCP (the XDM Control Protocol) +as specified in the \fIXaccess\fP file. +.PP +The resources of the X clients run by \fIxdm\fP outside the user's +session, including \fIxdm\fP's own login window, can be +affected by setting resources in the \fIXresources\fP file. +.PP +For X terminals that do not offer a menu of hosts to get display +management from, \fIxdm\fP can collect willing hosts and run the +\fIchooser\fP program to offer the user a menu. +For X displays attached to a host, this step is typically not used, as +the local host does the display management. +.PP +After resetting the X server, \fIxdm\fP runs the \fIXsetup\fP script +to assist in setting up the screen the user sees along with the +\fIxlogin\fP widget. +.PP +The \fIxlogin\fP widget, which \fIxdm\fP presents, +offers the familiar login and password prompts. +.PP +After the user logs in, \fIxdm\fP runs the \fIXstartup\fP script as +root. +.PP +Then \fIxdm\fP runs the \fIXsession\fP script as the user. This +system session file may do some additional startup and typically runs +the \fI.xsession\fP script in the user's home directory. +When the \fIXsession\fP script exits, the session is over. +.PP +At the end of the session, the \fIXreset\fP script is run to clean up, +the X server is reset, and the cycle starts over. +.PP +The file \fI/usr/X11R6/lib/X11/xdm/xdm-errors\fP will contain error +messages from +.I xdm +and anything output to stderr by \fIXsetup, Xstartup, Xsession\fP +or \fIXreset\fP. +When you have trouble getting +.I xdm +working, check this file to see if +.I xdm +has any clues to the trouble. +.SH OPTIONS +.PP +All of these options, except \fB\-config\fP itself, +specify values that can also be specified in the configuration file +as resources. +.IP "\fB\-config\fP \fIconfiguration_file\fP" +Names the configuration file, which specifies resources to control +the behavior of +.I xdm. +.I <XRoot>/lib/X11/xdm/xdm-config +is the default. +See the section \fBConfiguration File\fP. +.IP "\fB\-nodaemon\fP" +Specifies ``false'' as the value for the \fBDisplayManager.daemonMode\fP +resource. +This suppresses the normal daemon behavior, which is for +.I xdm +to close all file descriptors, disassociate itself from +the controlling terminal, and put +itself in the background when it first starts up. +.IP "\fB\-debug\fP \fIdebug_level\fP" +Specifies the numeric value for the \fBDisplayManager.debugLevel\fP +resource. A non-zero value causes +.I xdm +to print lots of debugging statements to the terminal; it also disables the +\fBDisplayManager.daemonMode\fP resource, forcing +.I xdm +to run synchronously. To interpret these debugging messages, a copy +of the source code for +.I xdm +is almost a necessity. No attempt has been +made to rationalize or standardize the output. +.IP "\fB\-error\fP \fIerror_log_file\fP" +Specifies the value for the \fBDisplayManager.errorLogFile\fP resource. +This file contains errors from +.I xdm +as well as anything written to stderr by the various scripts and programs +run during the progress of the session. +.IP "\fB\-resources\fP \fIresource_file\fP" +Specifies the value for the \fBDisplayManager*resources\fP resource. This file +is loaded using +.I xrdb +to specify configuration parameters for the +authentication widget. +.IP "\fB\-server\fP \fIserver_entry\fP" +Specifies the value for the \fBDisplayManager.servers\fP resource. +See the section +.B "Local Server Specification" +for a description of this resource. +.IP "\fB\-udpPort\fP \fIport_number\fP" +Specifies the value for the \fBDisplayManager.requestPort\fP resource. This +sets the port-number which +.I xdm +will monitor for XDMCP requests. As XDMCP +uses the registered well-known UDP port 177, this resource should +not be changed except for debugging. +.IP "\fB\-session\fP \fIsession_program\fP" +Specifies the value for the \fBDisplayManager*session\fP resource. This +indicates the program to run as the session after the user has logged in. +.IP "\fB\-xrm\fP \fIresource_specification\fP" +Allows an arbitrary resource to be specified, as in most +X Toolkit applications. +.SH RESOURCES +At many stages the actions of +.I xdm +can be controlled through the use of its configuration file, which is in the +X resource format. +Some resources modify the behavior of +.I xdm +on all displays, +while others modify its behavior on a single display. Where actions relate +to a specific display, +the display name is inserted into the resource name between +``DisplayManager'' and the final resource name segment. +.PP +For local displays, the resource name and class are as read from the +\fIXservers\fP file. +.PP +For remote displays, the resource name is what the network address of +the display resolves to. See the \fBremoveDomain\fP resource. The +name must match exactly; \fIxdm\fP is not aware of +all the network aliases that might reach a given display. +If the name resolve fails, the address is +used. The resource class is as sent by the display in the XDMCP +Manage request. +.PP +Because the resource +manager uses colons to separate the name of the resource from its value and +dots to separate resource name parts, +.I xdm +substitutes underscores for both dots and colons when generating the resource +name. +For example, \fBDisplayManager.expo_x_org_0.startup\fP is the name of the +resource which defines the startup shell file for the ``expo.x.org:0'' display. +.\" +.IP "\fBDisplayManager.servers\fP" +This resource either specifies a file name full of server entries, one per +line (if the value starts with a slash), or a single server entry. +See the section \fBLocal Server Specification\fP for the details. +.IP "\fBDisplayManager.requestPort\fP" +This indicates the UDP port number which +.I xdm +uses to listen for incoming XDMCP requests. Unless you need to debug the +system, leave this with its default value of 177. +.IP "\fBDisplayManager.errorLogFile\fP" +Error output is normally directed at the system console. To redirect it, +set this resource to a file name. A method to send these messages to +.I syslog +should be developed for systems which support it; however, the +wide variety of interfaces precludes any system-independent +implementation. This file also contains any output directed to stderr +by the \fIXsetup, Xstartup, Xsession\fP and \fIXreset\fP files, +so it will contain descriptions +of problems in those scripts as well. +.IP "\fBDisplayManager.debugLevel\fP" +If the integer value of this resource is greater than zero, +reams of +debugging information will be printed. It also disables daemon mode, which +would redirect the information into the bit-bucket, and +allows non-root users to run +.I xdm, +which would normally not be useful. +.IP "\fBDisplayManager.daemonMode\fP" +Normally, +.I xdm +attempts to make itself into a daemon process unassociated with any terminal. +This is +accomplished by forking and leaving the parent process to exit, then closing +file descriptors and releasing the controlling terminal. In some +environments this is not desired (in particular, when debugging). Setting +this resource to ``false'' will disable this feature. +.IP "\fBDisplayManager.pidFile\fP" +The filename specified will be created to contain an ASCII +representation of the process-id of the main +.I xdm +process. +.I Xdm +also uses file locking on this file +to attempt to eliminate multiple daemons running on +the same machine, which would cause quite a bit of havoc. +.IP "\fBDisplayManager.lockPidFile\fP" +This is the resource which controls whether +.I xdm +uses file locking to keep multiple display managers from running amok. +On System V, this +uses the \fIlockf\fP library call, while on BSD it uses \fIflock.\fP +.IP "\fBDisplayManager.authDir\fP" +This names a directory under which +.I xdm +stores authorization files while initializing the session. The +default value is \fI<XRoot>/lib/X11/xdm.\fP +Can be overridden for specific displays by +DisplayManager.\fIDISPLAY\fP.authFile. +.IP \fBDisplayManager.autoRescan\fP +This boolean controls whether +.I xdm +rescans the configuration, servers, access control and authentication keys +files after a session terminates and the files have changed. By default it +is ``true.'' You can force +.I xdm +to reread these files by sending a SIGHUP to the main process. +.IP "\fBDisplayManager.removeDomainname\fP" +When computing the display name for XDMCP clients, the name resolver will +typically create a fully qualified host name for the terminal. As this is +sometimes confusing, +.I xdm +will remove the domain name portion of the host name if it is the same as the +domain name of the local host when this variable is set. By default the +value is ``true.'' +.IP "\fBDisplayManager.keyFile\fP" +XDM-AUTHENTICATION-1 style XDMCP authentication requires that a private key +be shared between +.I xdm +and the terminal. This resource specifies the file containing those +values. Each entry in the file consists of a display name and the shared +key. By default, +.I xdm +does not include support for XDM-AUTHENTICATION-1, as it requires DES which +is not generally distributable because of United States export restrictions. +.IP \fBDisplayManager.accessFile\fP +To prevent unauthorized XDMCP service and to allow forwarding of XDMCP +IndirectQuery requests, this file contains a database of hostnames which are +either allowed direct access to this machine, or have a list of hosts to +which queries should be forwarded to. The format of this file is described +in the section +.B "XDMCP Access Control." +.IP \fBDisplayManager.exportList\fP +A list of additional environment variables, separated by white space, +to pass on to the \fIXsetup\fP, +\fIXstartup\fP, \fIXsession\fP, and \fIXreset\fP programs. +.IP \fBDisplayManager.randomFile\fP +A file to checksum to generate the seed of authorization keys. +This should be a file that changes frequently. +The default is \fI/dev/mem\fP. +.IP \fBDisplayManager.greeterLib\fP +On systems that support a dynamically-loadable greeter library, the +name of the library. Default is \fI<XRoot>/lib/X11/xdm/libXdmGreet.so\fP. +.IP \fBDisplayManager.choiceTimeout\fP +Number of seconds to wait for display to respond after user has +selected a host from the chooser. If the display sends an XDMCP +IndirectQuery within this time, the request is forwarded to the chosen +host. Otherwise, it is assumed to be from a new session and the +chooser is offered again. +Default is 15. +.\" +.IP "\fBDisplayManager.\fP\fIDISPLAY\fP\fB.resources\fP" +This resource specifies the name of the file to be loaded by \fIxrdb\fP +as the resource database onto the root window of screen 0 of the display. +The \fIXsetup\fP program, the Login widget, and \fIchooser\fP will use +the resources set in this file. +This resource data base is loaded just before the authentication procedure +is started, so it can control the appearance of the login window. See the +section +.B "Authentication Widget," +which describes the various +resources that are appropriate to place in this file. +There is no default value for this resource, but +\fI<XRoot>/lib/X11/xdm/Xresources\fP +is the conventional name. +.IP "\fBDisplayManager.\fP\fIDISPLAY\fP\fB.chooser\fP" +Specifies the program run to offer a host menu for Indirect queries +redirected to the special host name CHOOSER. +\fI<XRoot>/lib/X11/xdm/chooser\fP is the default. +See the sections \fBXDMCP Access Control\fP and \fBChooser\fP. +.IP "\fBDisplayManager.\fP\fIDISPLAY\fP\fB.xrdb\fP" +Specifies the program used to load the resources. By default, +.I xdm +uses \fI<XRoot>/bin/xrdb\fP. +.IP "\fBDisplayManager.\fP\fIDISPLAY\fP\fB.cpp\fP" +This specifies the name of the C preprocessor which is used by \fIxrdb\fP. +.IP "\fBDisplayManager.\fP\fIDISPLAY\fP\fB.setup\fP" +This specifies a program which is run (as root) before offering the +Login window. This may be used to change the appearance of the screen +around the Login window or to put up other windows (e.g., you may want +to run \fIxconsole\fP here). +By default, no program is run. The conventional name for a +file used here is \fIXsetup\fP. +See the section \fBSetup Program.\fP +.IP "\fBDisplayManager.\fP\fIDISPLAY\fP\fB.startup\fP" +This specifies a program which is run (as root) after the authentication +process succeeds. By default, no program is run. The conventional name for a +file used here is \fIXstartup\fP. +See the section \fBStartup Program.\fP +.IP "\fBDisplayManager.\fP\fIDISPLAY\fP\fB.session\fP" +This specifies the session to be executed (not running as root). +By default, \fI<XRoot>/bin/xterm\fP is +run. The conventional name is \fIXsession\fP. +See the section +.B "Session Program." +.IP "\fBDisplayManager.\fP\fIDISPLAY\fP\fB.reset\fP" +This specifies a program which is run (as root) after the session terminates. +By default, no program is run. +The conventional name is \fIXreset\fP. +See the section +.B "Reset Program." +.IP "\fBDisplayManager.\fP\fIDISPLAY\fP\fB.openDelay\fP" +.IP "\fBDisplayManager.\fP\fIDISPLAY\fP\fB.openRepeat\fP" +.IP "\fBDisplayManager.\fP\fIDISPLAY\fP\fB.openTimeout\fP" +.IP "\fBDisplayManager.\fP\fIDISPLAY\fP\fB.startAttempts\fP" +These numeric resources control the behavior of +.I xdm +when attempting to open intransigent servers. \fBopenDelay\fP is +the length of the +pause (in seconds) between successive attempts, \fBopenRepeat\fP is the +number of attempts to make, \fBopenTimeout\fP is the amount of time +to wait while actually +attempting the open (i.e., the maximum time spent in the +.IR connect (2) +system call) and \fBstartAttempts\fP is the number of times this entire process +is done before giving up on the server. After \fBopenRepeat\fP attempts have been made, +or if \fBopenTimeout\fP seconds elapse in any particular attempt, +.I xdm +terminates and restarts the server, attempting to connect again. +This +process is repeated \fBstartAttempts\fP times, at which point the display is +declared dead and disabled. Although +this behavior may seem arbitrary, it has been empirically developed and +works quite well on most systems. The default values are +5 for \fBopenDelay\fP, 5 for \fBopenRepeat\fP, 30 for \fBopenTimeout\fP and +4 for \fBstartAttempts\fP. +.IP "\fBDisplayManager.\fP\fIDISPLAY\fP\fB.pingInterval\fP" +.IP "\fBDisplayManager.\fP\fIDISPLAY\fP\fB.pingTimeout\fP" +To discover when remote displays disappear, +.I xdm +occasionally pings them, using an X connection and \fIXSync\fP +calls. \fBpingInterval\fP specifies the time (in minutes) between each +ping attempt, \fBpingTimeout\fP specifies the maximum amount of time (in +minutes) to wait for the terminal to respond to the request. If the +terminal does not respond, the session is declared dead and terminated. By +default, both are set to 5 minutes. If you frequently use X terminals which +can become isolated from the managing host, you may wish to increase this +value. The only worry is that sessions will continue to exist after the +terminal has been accidentally disabled. +.I xdm +will not ping local displays. Although it would seem harmless, it is +unpleasant when the workstation session is terminated as a result of the +server hanging for NFS service and not responding to the ping. +.IP "\fBDisplayManager.\fP\fIDISPLAY\fP\fB.terminateServer\fP" +This boolean resource specifies whether the X server should be terminated +when a session terminates (instead of resetting it). This option can be +used when the server tends to grow without bound over time, in order to limit +the amount of time the server is run. The default value is ``false.'' +.IP "\fBDisplayManager.\fP\fIDISPLAY\fP\fB.userPath\fP" +.I Xdm +sets the PATH environment variable for the session to this value. It should +be a colon separated list of directories; see +.IR sh (1) +for a full description. +``:/bin:/usr/bin:/usr/X11R6/bin:/usr/ucb'' +is a common setting. +The default value can be specified at build time in the X system +configuration file with DefaultUserPath. +.IP "\fBDisplayManager.\fP\fIDISPLAY\fP\fB.systemPath\fP" +.I Xdm +sets the PATH environment variable for the startup and reset scripts to the +value of this resource. The default for this resource is specified +at build time by the DefaultSystemPath entry in the system configuration file; +``/etc:/bin:/usr/bin:/usr/X11R6/bin:/usr/ucb'' is a common choice. +Note the absence of ``.'' from this entry. This is a good practice to +follow for root; it avoids many common Trojan Horse system penetration +schemes. +.IP "\fBDisplayManager.\fP\fIDISPLAY\fP\fB.systemShell\fP" +.I Xdm +sets the SHELL environment variable for the startup and reset scripts to the +value of this resource. It is \fI/bin/sh\fP by default. +.IP "\fBDisplayManager.\fP\fIDISPLAY\fP\fB.failsafeClient\fP" +If the default session fails to execute, +.I xdm +will fall back to this program. This program is executed with no +arguments, but executes using the same environment variables as +the session would have had (see the section \fBSession Program\fP). +By default, \fI<XRoot>/bin/xterm\fP is used. +.IP "\fBDisplayManager.\fP\fIDISPLAY\fP\fB.grabServer\fP" +.IP "\fBDisplayManager.\fP\fIDISPLAY\fP\fB.grabTimeout\fP" +To improve security, +.I xdm +grabs the server and keyboard while reading the login name and password. +The +\fBgrabServer\fP resource specifies if the server should be held for the +duration of the name/password reading. When ``false,'' the server is ungrabbed +after the keyboard grab succeeds, otherwise the server is grabbed until just +before the session begins. The default is ``false.'' +The \fBgrabTimeout\fP resource specifies the maximum time +.I xdm +will wait for the grab to succeed. The grab may fail if some other +client has the server grabbed, or possibly if the network latencies +are very high. This resource has a default value of 3 seconds; you +should be cautious when raising it, as a user can be spoofed by a +look-alike window on the display. If the grab fails, +.I xdm +kills and restarts the server (if possible) and the session. +.IP "\fBDisplayManager.\fP\fIDISPLAY\fP\fB.authorize\fP" +.IP "\fBDisplayManager.\fP\fIDISPLAY\fP\fB.authName\fP" +\fBauthorize\fP is a boolean resource which controls whether +.I xdm +generates and uses authorization for the local server connections. If +authorization is used, \fBauthName\fP is a list +of authorization mechanisms to use, separated by white space. +XDMCP connections dynamically specify which +authorization mechanisms are supported, so +\fBauthName\fP is ignored in this case. When \fBauthorize\fP is set for a +display and authorization is not available, the user is informed by having a +different message displayed in the login widget. By default, \fBauthorize\fP +is ``true.'' \fBauthName\fP is ``MIT-MAGIC-COOKIE-1,'' or, if +XDM-AUTHORIZATION-1 is available, ``XDM-AUTHORIZATION-1\0MIT-MAGIC-COOKIE-1.'' +.IP \fBDisplayManager.\fP\fIDISPLAY\fP\fB.authFile\fP +This file is used to communicate the authorization data from +.I xdm +to the server, using the \fB\-auth\fP server command line option. +It should be +kept in a directory which is not world-writable as it could easily be +removed, disabling the authorization mechanism in the server. +If not specified, a name is generated from DisplayManager.authDir and +the name of the display. +.IP "\fBDisplayManager.\fP\fIDISPLAY\fP\fB.authComplain\fP" +If set to ``false,'' disables the use of the \fBunsecureGreeting\fP +in the login window. +See the section \fBAuthentication Widget.\fP +The default is ``true.'' +.IP "\fBDisplayManager.\fP\fIDISPLAY\fP\fB.resetSignal\fP" +The number of the signal \fIxdm\fP sends to reset the server. +See the section \fBControlling the Server.\fP +The default is 1 (SIGHUP). +.IP "\fBDisplayManager.\fP\fIDISPLAY\fP\fB.termSignal\fP" +The number of the signal \fIxdm\fP sends to terminate the server. +See the section \fBControlling the Server.\fP +The default is 15 (SIGTERM). +.IP "\fBDisplayManager.\fP\fIDISPLAY\fP\fB.resetForAuth\fP" +The original implementation of authorization in the sample server reread the +authorization file at server reset time, instead of when checking the +initial connection. As +.I xdm +generates the authorization information just before connecting to the +display, an old server would not get up-to-date authorization information. +This resource causes +.I xdm +to send SIGHUP to the server after setting up the file, causing an +additional server reset to occur, during which time the new authorization +information will be read. +The default is ``false,'' which will work for all MIT servers. +.IP "\fBDisplayManager.\fP\fIDISPLAY\fP\fB.userAuthDir\fP" +When +.I xdm +is unable to write to the usual user authorization file ($HOME/.Xauthority), +it creates a unique file name in this directory and points the environment +variable XAUTHORITY at the created file. It uses \fI/tmp\fP by default. +.SH "CONFIGURATION FILE" +First, the +.I xdm +configuration file should be set up. +Make a directory (usually \fI<XRoot>/lib/X11/xdm\fP, where <XRoot> +refers to the root of the X11 install tree) to contain all of the relevant +files. In the examples that follow, we use /usr/X11R6 as the value of +<XRoot>. +.LP +Here is a reasonable configuration file, which could be +named \fIxdm-config\fP: +.nf + +.ta .5i 4i + + DisplayManager.servers: /usr/X11R6/lib/X11/xdm/Xservers + DisplayManager.errorLogFile: /usr/X11R6/lib/X11/xdm/xdm-errors + DisplayManager*resources: /usr/X11R6/lib/X11/xdm/Xresources + DisplayManager*startup: /usr/X11R6/lib/X11/xdm/Xstartup + DisplayManager*session: /usr/X11R6/lib/X11/xdm/Xsession + DisplayManager.pidFile: /usr/X11R6/lib/X11/xdm/xdm-pid + DisplayManager._0.authorize: true + DisplayManager*authorize: false + +.fi +.PP +Note that this file mostly contains references to other files. Note also +that some of the resources are specified with ``*'' separating the +components. These resources can be made unique for each different display, +by replacing the ``*'' with the display-name, but normally this is not very +useful. See the \fBResources\fP section for a complete discussion. +.SH "XDMCP ACCESS CONTROL" +.PP +The database file specified by the \fBDisplayManager.accessFile\fP provides +information which +.I xdm +uses to control access from displays requesting XDMCP service. This file +contains three types of entries: entries which control the response to +Direct and Broadcast queries, entries which control the response to +Indirect queries, and macro definitions. +.PP +The format of the Direct entries is simple, either a host name or a +pattern, which is distinguished from a host name by the inclusion of +one or more meta characters (`*' matches any sequence of 0 or more +characters, and `?' matches any single character) which are compared against +the host name of the display device. +If the entry is a host name, all comparisons are done using +network addresses, so any name which converts to the correct network address +may be used. +For patterns, only canonical host names are used +in the comparison, so ensure that you do not attempt to match +aliases. +Preceding either a host name or a pattern with a `!' character +causes hosts which +match that entry to be excluded. +.PP +An Indirect entry also contains a host name or pattern, +but follows it with a list of +host names or macros to which indirect queries should be sent. +.PP +A macro definition contains a macro name and a list of host names and +other macros that +the macro expands to. To distinguish macros from hostnames, macro +names start with a `%' character. Macros may be nested. +.PP +Indirect entries +may also specify to have \fIxdm\fP run \fIchooser\fP to offer a menu +of hosts to connect to. See the section \fBChooser\fP. +.PP +When checking access for a particular display host, each entry is scanned in +turn and the first matching entry determines the response. Direct and +Broadcast +entries are ignored when scanning for an Indirect entry and vice-versa. +.PP +Blank lines are ignored, `#' is treated as a comment +delimiter causing the rest of that line to be ignored, +and `\e\fInewline\fP' +causes the newline to be ignored, allowing indirect host lists to span +multiple lines. +.PP +Here is an example Xaccess file: +.LP +.ta 2i 4i +.nf +# +# Xaccess \- XDMCP access control file +# + +# +# Direct/Broadcast query entries +# + +!xtra.lcs.mit.edu # disallow direct/broadcast service for xtra +bambi.ogi.edu # allow access from this particular display +*.lcs.mit.edu # allow access from any display in LCS + +# +# Indirect query entries +# + +%HOSTS expo.lcs.mit.edu xenon.lcs.mit.edu \\ + excess.lcs.mit.edu kanga.lcs.mit.edu + +extract.lcs.mit.edu xenon.lcs.mit.edu #force extract to contact xenon +!xtra.lcs.mit.edu dummy #disallow indirect access +*.lcs.mit.edu %HOSTS #all others get to choose +.fi +.SH CHOOSER +.PP +For X terminals that do not offer a host menu for use with Broadcast +or Indirect queries, the \fIchooser\fP program can do this for them. +In the \fIXaccess\fP file, specify ``CHOOSER'' as the first entry in +the Indirect host list. \fIChooser\fP will send a Query request to +each of the remaining host names in the list and offer a menu of all +the hosts that respond. +.PP +The list may consist of the word ``BROADCAST,'' in which case +\fIchooser\fP will send a Broadcast instead, again offering a menu of +all hosts that respond. Note that on some operating systems, UDP +packets cannot be broadcast, so this feature will not work. +.PP +Example \fIXaccess\fP file using \fIchooser\fP: + +.nf +extract.lcs.mit.edu CHOOSER %HOSTS #offer a menu of these hosts +xtra.lcs.mit.edu CHOOSER BROADCAST #offer a menu of all hosts +.fi +.PP +The program to use for \fIchooser\fP is specified by the +\fBDisplayManager.\fP\fIDISPLAY\fP\fB.chooser\fP resource. For more +flexibility at this step, the chooser could be a shell script. +\fIChooser\fP is the session manager here; it is run instead of a +child \fIxdm\fP to manage the display. +.PP +Resources for this program +can be put into the file named by +\fBDisplayManager.\fP\fIDISPLAY\fP\fB.resources\fP. +.PP +When the user selects a host, \fIchooser\fP prints the host chosen, +which is read by the parent \fIxdm\fP, and exits. +\fIxdm\fP closes its connection to the X server, and the server resets +and sends another \fBIndirect\fP XDMCP request. +\fIxdm\fP remembers the user's choice (for +\fBDisplayManager.choiceTimeout\fP seconds) and forwards the request +to the chosen host, which starts a session on that display. +.\" +.SH "LOCAL SERVER SPECIFICATION" +.PP +The resource \fBDisplayManager.servers\fP gives a server specification +or, if the values starts with a slash (/), the name of a file +containing server specifications, one per line. +.PP +Each specification +indicates a display which should constantly be managed and which is +not using XDMCP. +This method is used typically for local servers only. If the resource +or the file named by the resource is empty, \fIxdm\fP will offer XDMCP +service only. +.PP +Each specification consists of at least three parts: a display +name, a display class, a display type, and (for local servers) a command +line to start the server. A typical entry for local display number 0 would +be: +.nf + + :0 Digital-QV local /usr/X11R6/bin/X :0 + +.fi +The display types are: +.ta 1i +.nf + +local local display: \fIxdm\fP must run the server +foreign remote display: \fIxdm\fP opens an X connection to a running server + +.fi +.PP +The display name must be something that can be passed in the \fB\-display\fP +option to an X program. This string is used to generate the display-specific +resource names, so be careful to match the +names (e.g., use ``:0 Sun-CG3 local /usr/X11R6/bin/X :0'' instead of +``localhost:0 Sun-CG3 local /usr/X11R6/bin/X :0'' +if your other resources are specified as +``DisplayManager._0.session''). The display class portion is also used in the +display-specific resources, as the class of the resource. This is +useful if you have a large collection of similar displays (such as a corral of +X terminals) and would like to set resources for groups of them. When using +XDMCP, the display is required to specify the display class, so the manual +for your particular X terminal should document the display class +string for your device. If it doesn't, you can run +.I xdm +in debug mode and +look at the resource strings which it generates for that device, which will +include the class string. +.PP +When \fIxdm\fP starts a session, it sets up authorization data for the +server. For local servers, \fIxdm\fP passes +``\fB\-auth\fP \fIfilename\fP'' on the server's command line to point +it at its authorization data. +For XDMCP servers, \fIxdm\fP passes the +authorization data to the server via the \fBAccept\fP XDMCP request. +.SH RESOURCES FILE +The \fIXresources\fP file is +loaded onto the display as a resource database using +.I xrdb. +As the authentication +widget reads this database before starting up, it usually contains +parameters for that widget: +.nf +.ta .5i 1i + + xlogin*login.translations: #override\\ + Ctrl<Key>R: abort-display()\\n\\ + <Key>F1: set-session-argument(failsafe) finish-field()\\n\\ + <Key>Return: set-session-argument() finish-field() + xlogin*borderWidth: 3 + xlogin*greeting: CLIENTHOST + #ifdef COLOR + xlogin*greetColor: CadetBlue + xlogin*failColor: red + #endif + +.fi +.PP +Please note the translations entry; it specifies +a few new translations for the widget which allow users to escape from the +default session (and avoid troubles that may occur in it). Note that if +#override is not specified, the default translations are removed and replaced +by the new value, not a very useful result as some of the default translations +are quite useful (such as ``<Key>: insert-char ()'' which responds to normal +typing). +.PP +This file may also contain resources for the setup program and \fIchooser\fP. +.SH "SETUP PROGRAM" +The \fIXsetup\fP file is run after +the server is reset, but before the Login window is offered. +The file is typically a shell script. +It is run as root, so should be careful about security. +This is the place to change the root background or bring up other +windows that should appear on the screen along with the Login widget. +.PP +In addition to any specified by \fBDisplayManager.exportList\fP, +the following environment variables are passed: +.nf +.ta .5i 2i + + DISPLAY the associated display name + PATH the value of \fBDisplayManager.\fP\fIDISPLAY\fP\fB.systemPath\fP + SHELL the value of \fBDisplayManager.\fP\fIDISPLAY\fP\fB.systemShell\fP + XAUTHORITY may be set to an authority file +.fi +.PP +Note that since \fIxdm\fP grabs the keyboard, any other windows will not be +able to receive keyboard input. They will be able to interact with +the mouse, however; beware of potential security holes here. +If \fBDisplayManager.\fP\fIDISPLAY\fP\fB.grabServer\fP is set, +\fIXsetup\fP will not be able to connect +to the display at all. +Resources for this program +can be put into the file named by +\fBDisplayManager.\fP\fIDISPLAY\fP\fB.resources\fP. +.PP +Here is a sample \fIXsetup\fP script: +.nf + + #!/bin/sh + # Xsetup_0 \- setup script for one workstation + xcmsdb < /usr/X11R6/lib/monitors/alex.0 + xconsole\0\-geometry\0480x130\-0\-0\0\-notify\0\-verbose\0\-exitOnFail & + +.fi +.SH "AUTHENTICATION WIDGET" +The authentication widget reads a name/password pair +from the keyboard. Nearly every imaginable +parameter can be controlled with a resource. Resources for this widget +should be put into the file named by +\fBDisplayManager.\fP\fIDISPLAY\fP\fB.resources\fP. All of these have reasonable +default values, so it is not necessary to specify any of them. +.IP "\fBxlogin.Login.width, xlogin.Login.height, xlogin.Login.x, xlogin.Login.y\fP" +The geometry of the Login widget is normally computed automatically. If you +wish to position it elsewhere, specify each of these resources. +.IP "\fBxlogin.Login.foreground\fP" +The color used to display the typed-in user name. +.IP "\fBxlogin.Login.font\fP" +The font used to display the typed-in user name. +.IP "\fBxlogin.Login.greeting\fP" +A string which identifies this window. +The default is ``X Window System.'' +.IP "\fBxlogin.Login.unsecureGreeting\fP" +When X authorization is requested in the configuration file for this +display and none is in use, this greeting replaces the standard +greeting. The default is ``This is an unsecure session'' +.IP "\fBxlogin.Login.greetFont\fP" +The font used to display the greeting. +.IP "\fBxlogin.Login.greetColor\fP" +The color used to display the greeting. +.IP "\fBxlogin.Login.namePrompt\fP" +The string displayed to prompt for a user name. +.I Xrdb +strips trailing white space from resource values, so to add spaces at +the end of the prompt (usually a nice thing), add spaces escaped with +backslashes. The default is ``Login: '' +.IP "\fBxlogin.Login.passwdPrompt\fP" +The string displayed to prompt for a password. +The default is ``Password: '' +.IP "\fBxlogin.Login.promptFont\fP" +The font used to display both prompts. +.IP "\fBxlogin.Login.promptColor\fP" +The color used to display both prompts. +.IP "\fBxlogin.Login.fail\fP" +A message which is displayed when the authentication fails. +The default is ``Login incorrect'' +.IP "\fBxlogin.Login.failFont\fP" +The font used to display the failure message. +.IP "\fBxlogin.Login.failColor\fP" +The color used to display the failure message. +.IP "\fBxlogin.Login.failTimeout\fP" +The number of seconds that the failure message is displayed. +The default is 30. +.IP "\fBxlogin.Login.translations\fP" +This specifies the translations used for the login widget. Refer to the X +Toolkit documentation for a complete discussion on translations. The default +translation table is: +.nf +.ta .5i 2i + + Ctrl<Key>H: delete-previous-character() \\n\\ + Ctrl<Key>D: delete-character() \\n\\ + Ctrl<Key>B: move-backward-character() \\n\\ + Ctrl<Key>F: move-forward-character() \\n\\ + Ctrl<Key>A: move-to-begining() \\n\\ + Ctrl<Key>E: move-to-end() \\n\\ + Ctrl<Key>K: erase-to-end-of-line() \\n\\ + Ctrl<Key>U: erase-line() \\n\\ + Ctrl<Key>X: erase-line() \\n\\ + Ctrl<Key>C: restart-session() \\n\\ + Ctrl<Key>\\\\: abort-session() \\n\\ + <Key>BackSpace: delete-previous-character() \\n\\ + <Key>Delete: delete-previous-character() \\n\\ + <Key>Return: finish-field() \\n\\ + <Key>: insert-char() \\ + +.fi +.PP +The actions which are supported by the widget are: +.IP "delete-previous-character" +Erases the character before the cursor. +.IP "delete-character" +Erases the character after the cursor. +.IP "move-backward-character" +Moves the cursor backward. +.IP "move-forward-character" +Moves the cursor forward. +.IP "move-to-begining" +(Apologies about the spelling error.) +Moves the cursor to the beginning of the editable text. +.IP "move-to-end" +Moves the cursor to the end of the editable text. +.IP "erase-to-end-of-line" +Erases all text after the cursor. +.IP "erase-line" +Erases the entire text. +.IP "finish-field" +If the cursor is in the name field, proceeds to the password field; if the +cursor is in the password field, checks the current name/password pair. If +the name/password pair is valid, \fIxdm\fP +starts the session. Otherwise the failure message is displayed and +the user is prompted again. +.IP "abort-session" +Terminates and restarts the server. +.IP "abort-display" +Terminates the server, disabling it. This action +is not accessible in the default configuration. +There are various reasons to stop \fIxdm\fP on a system console, such as +when shutting the system down, when using \fIxdmshell\fP, +to start another type of server, or to generally access the console. +Sending \fIxdm\fP a SIGHUP will restart the display. See the section +\fBControlling XDM\fP. +.IP "restart-session" +Resets the X server and starts a new session. This can be used when +the resources have been changed and you want to test them or when +the screen has been overwritten with system messages. +.IP "insert-char" +Inserts the character typed. +.IP "set-session-argument" +Specifies a single word argument which is passed to the session at startup. +See the section \fBSession Program\fP. +.IP "allow-all-access" +Disables access control in the server. This can be used when +the .Xauthority file cannot be created by +.I xdm. +Be very careful using this; +it might be better to disconnect the machine from the network +before doing this. +.SH "STARTUP PROGRAM" +.PP +The \fIXstartup\fP program is run as +root when the user logs in. +It is typically a shell script. +Since it is run as root, \fIXstartup\fP should be +very careful about security. This is the place to put commands which add +entries to \fI/etc/utmp\fP +(the \fIsessreg\fP program may be useful here), +mount users' home directories from file servers, +or abort the session if logins are not +allowed. +.PP +In addition to any specified by \fBDisplayManager.exportList\fP, +the following environment variables are passed: +.nf +.ta .5i 2i + + DISPLAY the associated display name + HOME the initial working directory of the user + LOGNAME the user name + USER the user name + PATH the value of \fBDisplayManager.\fP\fIDISPLAY\fP\fB.systemPath\fP + SHELL the value of \fBDisplayManager.\fP\fIDISPLAY\fP\fB.systemShell\fP + XAUTHORITY may be set to an authority file + +.fi +.PP +No arguments are passed to the script. +.I Xdm +waits until this script exits before starting the user session. If the +exit value of this script is non-zero, +.I xdm +discontinues the session and starts another authentication +cycle. +.PP +The sample \fIXstartup\fP file shown here prevents login while the +file \fI/etc/nologin\fP +exists. +Thus this is not a complete example, but +simply a demonstration of the available functionality. +.PP +Here is a sample \fIXstartup\fP script: +.nf +.ta .5i 1i + + #!/bin/sh + # + # Xstartup + # + # This program is run as root after the user is verified + # + if [ \-f /etc/nologin ]; then + xmessage\0\-file /etc/nologin\0\-timeout 30\0\-center + exit 1 + fi + sessreg\0\-a\0\-l $DISPLAY\0\-x /usr/X11R6/lib/xdm/Xservers $LOGNAME + /usr/X11R6/lib/xdm/GiveConsole + exit 0 +.fi +.SH "SESSION PROGRAM" +.PP +The \fIXsession\fP program is the command which is run as the user's session. +It is run with +the permissions of the authorized user. +.PP +In addition to any specified by \fBDisplayManager.exportList\fP, +the following environment variables are passed: +.nf +.ta .5i 2i + + DISPLAY the associated display name + HOME the initial working directory of the user + LOGNAME the user name + USER the user name + PATH the value of \fBDisplayManager.\fP\fIDISPLAY\fP\fB.userPath\fP + SHELL the user's default shell (from \fIgetpwnam\fP) + XAUTHORITY may be set to a non-standard authority file + KRB5CCNAME may be set to a Kerberos credentials cache name + +.fi +.PP +At most installations, \fIXsession\fP should look in $HOME for +a file \fI\.xsession,\fP +which contains commands that each user would like to use as a session. +\fIXsession\fP should also +implement a system default session if no user-specified session exists. +See the section \fBTypical Usage\fP. +.PP +An argument may be passed to this program from the authentication widget +using the `set-session-argument' action. This can be used to select +different styles of session. One good use of this feature is to allow +the user to escape from the ordinary session when it fails. This +allows users to repair their own \fI.xsession\fP if it fails, +without requiring administrative intervention. +The example following +demonstrates this feature. +.PP +This example recognizes +the special +``failsafe'' mode, specified in the translations +in the \fIXresources\fP file, to provide an escape +from the ordinary session. It also requires that the .xsession file +be executable so we don't have to guess what shell it wants to use. +.nf +.ta .5i 1i 1.5i + + #!/bin/sh + # + # Xsession + # + # This is the program that is run as the client + # for the display manager. + + case $# in + 1) + case $1 in + failsafe) + exec xterm \-geometry 80x24\-0\-0 + ;; + esac + esac + + startup=$HOME/.xsession + resources=$HOME/.Xresources + + if [ \-f "$startup" ]; then + exec "$startup" + else + if [ \-f "$resources" ]; then + xrdb \-load "$resources" + fi + twm & + xman \-geometry +10\-10 & + exec xterm \-geometry 80x24+10+10 \-ls + fi + +.fi +.PP +The user's \fI.xsession\fP file might look something like this +example. Don't forget that the file must have execute permission. +.nf + #! /bin/csh + # no \-f in the previous line so .cshrc gets run to set $PATH + twm & + xrdb \-merge "$HOME/.Xresources" + emacs \-geometry +0+50 & + xbiff \-geometry \-430+5 & + xterm \-geometry \-0+50 -ls +.fi +.SH "RESET PROGRAM" +.PP +Symmetrical with \fIXstartup\fP, +the \fIXreset\fP script is run after the user session has +terminated. Run as root, it should contain commands that undo +the effects of commands in \fIXstartup,\fP removing entries +from \fI/etc/utmp\fP +or unmounting directories from file servers. The environment +variables that were passed to \fIXstartup\fP are also +passed to \fIXreset\fP. +.PP +A sample \fIXreset\fP script: +.nf +.ta .5i 1i + #!/bin/sh + # + # Xreset + # + # This program is run as root after the session ends + # + sessreg\0\-d\0\-l $DISPLAY\0\-x /usr/X11R6/lib/xdm/Xservers $LOGNAME + /usr/X11R6/lib/xdm/TakeConsole + exit 0 +.fi +.SH "CONTROLLING THE SERVER" +.I Xdm +controls local servers using POSIX signals. SIGHUP is expected to reset the +server, closing all client connections and performing other cleanup +duties. SIGTERM is expected to terminate the server. +If these signals do not perform the expected actions, +the resources \fBDisplayManager.\fP\fIDISPLAY\fP\fB.resetSignal\fP and +\fBDisplayManager.\fP\fIDISPLAY\fP\fB.termSignal\fP can specify alternate signals. +.PP +To control remote terminals not using XDMCP, +.I xdm +searches the window hierarchy on the display and uses the protocol request +KillClient in an attempt to clean up the terminal for the next session. This +may not actually kill all of the clients, as only those which have created +windows will be noticed. XDMCP provides a more sure mechanism; when +.I xdm +closes its initial connection, the session is over and the terminal is +required to close all other connections. +.SH "CONTROLLING XDM" +.PP +.I Xdm +responds to two signals: SIGHUP and SIGTERM. When sent a SIGHUP, +.I xdm +rereads the configuration file, the access control file, and the servers +file. For the servers file, it notices if entries have been added or +removed. If a new entry has been added, +.I xdm +starts a session on the associated display. Entries which have been removed +are disabled immediately, meaning that any session in progress will be +terminated without notice and no new session will be started. +.PP +When sent a SIGTERM, +.I xdm +terminates all sessions in progress and exits. This can be used when +shutting down the system. +.PP +.I Xdm +attempts to mark its various sub-processes for +.IR ps (1) +by editing the +command line argument list in place. Because +.I xdm +can't allocate additional +space for this task, it is useful to start +.I xdm +with a reasonably long +command line (using the full path name should be enough). +Each process which is +servicing a display is marked \fB\-\fP\fIdisplay.\fP +.SH "ADDITIONAL LOCAL DISPLAYS" +.PP +To add an additional local display, add a line for it to the +\fIXservers\fP file. +(See the section \fBLocal Server Specification\fP.) +.PP +Examine the display-specific resources in \fIxdm-config\fP +(e.g., \fBDisplayManager._0.authorize\fP) +and consider which of them should be copied for the new display. +The default \fIxdm-config\fP has all the appropriate lines for +displays \fB:0\fP and \fB:1\fP. +.SH "OTHER POSSIBILITIES" +.PP +You can use \fIxdm\fP +to run a single session at a time, using the 4.3 \fIinit\fP +options or other suitable daemon by specifying the server on the command +line: +.nf +.ta .5i + + xdm \-server ":0 SUN-3/60CG4 local /usr/X11R6/bin/X :0" + +.fi +.PP +Or, you might have a file server and a collection of X terminals. The +configuration for this is identical to the sample above, +except the \fIXservers\fP file would look like +.nf +.ta .5i + + extol:0 VISUAL-19 foreign + exalt:0 NCD-19 foreign + explode:0 NCR-TOWERVIEW3000 foreign + +.fi +.PP +This directs +.I xdm +to manage sessions on all three of these terminals. See the section +\fBControlling Xdm\fP for a description of using signals to enable +and disable these terminals in a manner reminiscent of +.IR init (8). +.SH LIMITATIONS +One thing that +.I xdm +isn't very good at doing is coexisting with other window systems. To use +multiple window systems on the same hardware, you'll probably be more +interested in +.I xinit. +.SH FILES +.TP 20 +.I <XRoot>/lib/X11/xdm/xdm-config +the default configuration file +.TP 20 +.I $HOME/.Xauthority +user authorization file where \fIxdm\fP stores keys for clients to read +.TP 20 +.I <XRoot>/lib/X11/xdm/chooser +the default chooser +.TP 20 +.I <XRoot>/bin/xrdb +the default resource database loader +.TP 20 +.I <XRoot>/bin/X +the default server +.TP 20 +.I <XRoot>/bin/xterm +the default session program and failsafe client +.TP 20 +.I <XRoot>/lib/X11/xdm/A<display>\-<suffix> +the default place for authorization files +.TP 20 +.I /tmp/K5C<display> +Kerberos credentials cache +.LP +Note: <XRoot> refers to the root of the X11 install tree. +.SH "SEE ALSO" +.IR X (1), +.IR xinit (1), +.IR xauth (1), +.IR Xsecurity (1), +.IR sessreg (1), +.IR Xserver (1), +.\" .IR chooser (1), \" except that there isn't a manual for it yet +.\" .IR xdmshell (1), \" except that there isn't a manual for it yet +.br +.I "X Display Manager Control Protocol" +.SH AUTHOR +Keith Packard, MIT X Consortium diff --git a/xdmauth.c b/xdmauth.c new file mode 100644 index 0000000..cd4d221 --- /dev/null +++ b/xdmauth.c @@ -0,0 +1,301 @@ +/* $Xorg: xdmauth.c,v 1.4 2001/02/09 02:05:41 xorgcvs Exp $ */ +/* + +Copyright 1988, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall +not be used in advertising or otherwise to promote the sale, use or +other dealings in this Software without prior written authorization +from The Open Group. + +*/ + +/* + * xdm - display manager daemon + * Author: Keith Packard, MIT X Consortium + * + * xdmauth + * + * generate authorization data for XDM-AUTHORIZATION-1 as per XDMCP spec + */ + +#include "dm.h" + +#ifdef HASXDMAUTH + +static char auth_name[256]; +static int auth_name_len; + +XdmPrintDataHex (s, a, l) + char *s; + char *a; + int l; +{ + int i; + + Debug ("%s", s); + for (i = 0; i < l; i++) + Debug (" %02x", a[i] & 0xff); + Debug ("\n"); +} + +#ifdef notdef /* not used */ +XdmPrintKey (s, k) + char *s; + XdmAuthKeyRec *k; +{ + XdmPrintDataHex (s, (char *) k->data, 8); +} +#endif + +#ifdef XDMCP +XdmPrintArray8Hex (s, a) + char *s; + ARRAY8Ptr a; +{ + XdmPrintDataHex (s, (char *) a->data, a->length); +} +#endif + +XdmInitAuth (name_len, name) + unsigned short name_len; + char *name; +{ + if (name_len > 256) + name_len = 256; + auth_name_len = name_len; + memmove( auth_name, name, name_len); +} + +/* + * Generate authorization for XDM-AUTHORIZATION-1 + * + * When being used with XDMCP, 8 bytes are generated for the session key + * (sigma), as the random number (rho) is already shared between xdm and + * the server. Otherwise, we'll prepend a random number to pass in the file + * between xdm and the server (16 bytes total) + */ + +Xauth * +XdmGetAuthHelper (namelen, name, includeRho) + unsigned short namelen; + char *name; + int includeRho; +{ + Xauth *new; + new = (Xauth *) malloc (sizeof (Xauth)); + + if (!new) + return (Xauth *) 0; + new->family = FamilyWild; + new->address_length = 0; + new->address = 0; + new->number_length = 0; + new->number = 0; + if (includeRho) + new->data_length = 16; + else + new->data_length = 8; + + new->data = (char *) malloc (new->data_length); + if (!new->data) + { + free ((char *) new); + return (Xauth *) 0; + } + new->name = (char *) malloc (namelen); + if (!new->name) + { + free ((char *) new->data); + free ((char *) new); + return (Xauth *) 0; + } + memmove( (char *)new->name, name, namelen); + new->name_length = namelen; + GenerateAuthData ((char *)new->data, new->data_length); + /* + * set the first byte of the session key to zero as it + * is a DES key and only uses 56 bits + */ + ((char *)new->data)[new->data_length - 8] = '\0'; + XdmPrintDataHex ("Local server auth", (char *)new->data, new->data_length); + return new; +} + +Xauth * +XdmGetAuth (namelen, name) + unsigned short namelen; + char *name; +{ + return XdmGetAuthHelper (namelen, name, TRUE); +} + +#ifdef XDMCP + +void +XdmGetXdmcpAuth (pdpy,authorizationNameLen, authorizationName) + struct protoDisplay *pdpy; + unsigned short authorizationNameLen; + char *authorizationName; +{ + Xauth *fileauth, *xdmcpauth; + + if (pdpy->fileAuthorization && pdpy->xdmcpAuthorization) + return; + xdmcpauth = XdmGetAuthHelper (authorizationNameLen, authorizationName, FALSE); + if (!xdmcpauth) + return; + fileauth = (Xauth *) malloc (sizeof (Xauth)); + if (!fileauth) + { + XauDisposeAuth(xdmcpauth); + return; + } + /* build the file auth from the XDMCP auth */ + *fileauth = *xdmcpauth; + fileauth->name = malloc (xdmcpauth->name_length); + fileauth->data = malloc (16); + fileauth->data_length = 16; + if (!fileauth->name || !fileauth->data) + { + XauDisposeAuth (xdmcpauth); + if (fileauth->name) + free ((char *) fileauth->name); + if (fileauth->data) + free ((char *) fileauth->data); + free ((char *) fileauth); + return; + } + /* + * for the file authorization, prepend the random number (rho) + * which is simply the number we've been passing back and + * forth via XDMCP + */ + memmove( fileauth->name, xdmcpauth->name, xdmcpauth->name_length); + memmove( fileauth->data, pdpy->authenticationData.data, 8); + memmove( fileauth->data + 8, xdmcpauth->data, 8); + XdmPrintDataHex ("Accept packet auth", xdmcpauth->data, xdmcpauth->data_length); + XdmPrintDataHex ("Auth file auth", fileauth->data, fileauth->data_length); + /* encrypt the session key for its trip back to the server */ + XdmcpWrap (xdmcpauth->data, &pdpy->key, xdmcpauth->data, 8); + pdpy->fileAuthorization = fileauth; + pdpy->xdmcpAuthorization = xdmcpauth; +} + +#define atox(c) ('0' <= c && c <= '9' ? c - '0' : \ + 'a' <= c && c <= 'f' ? c - 'a' + 10 : \ + 'A' <= c && c <= 'F' ? c - 'A' + 10 : -1) + +static +HexToBinary (key) + char *key; +{ + char *out, *in; + int top, bottom; + + in = key + 2; + out= key; + while (in[0] && in[1]) + { + top = atox(in[0]); + if (top == -1) + return 0; + bottom = atox(in[1]); + if (bottom == -1) + return 0; + *out++ = (top << 4) | bottom; + in += 2; + } + if (in[0]) + return 0; + *out++ = '\0'; + return 1; +} + +/* + * Search the Keys file for the entry matching this display. This + * routine accepts either plain ascii strings for keys, or hex-encoded numbers + */ + +XdmGetKey (pdpy, displayID) + struct protoDisplay *pdpy; + ARRAY8Ptr displayID; +{ + FILE *keys; + char line[1024], id[1024], key[1024]; + int keylen; + + Debug ("Lookup key for %*.*s\n", displayID->length, displayID->length, displayID->data); + keys = fopen (keyFile, "r"); + if (!keys) + return FALSE; + while (fgets (line, sizeof (line) - 1, keys)) + { + if (line[0] == '#' || sscanf (line, "%s %s", id, key) != 2) + continue; + bzero(line, sizeof(line)); + Debug ("Key entry for \"%s\" %d bytes\n", id, strlen(key)); + if (strlen (id) == displayID->length && + !strncmp (id, (char *)displayID->data, displayID->length)) + { + if (!strncmp (key, "0x", 2) || !strncmp (key, "0X", 2)) + if (!HexToBinary (key)) + break; + keylen = strlen (key); + while (keylen < 7) + key[keylen++] = '\0'; + pdpy->key.data[0] = '\0'; + memmove( pdpy->key.data + 1, key, 7); + bzero(key, sizeof(key)); + fclose (keys); + return TRUE; + } + } + bzero(line, sizeof(line)); + bzero(key, sizeof(key)); + fclose (keys); + return FALSE; +} + +/*ARGSUSED*/ +XdmCheckAuthentication (pdpy, displayID, authenticationName, authenticationData) + struct protoDisplay *pdpy; + ARRAY8Ptr displayID, authenticationName, authenticationData; +{ + XdmAuthKeyPtr incoming; + + if (!XdmGetKey (pdpy, displayID)) + return FALSE; + if (authenticationData->length != 8) + return FALSE; + XdmcpUnwrap (authenticationData->data, &pdpy->key, + authenticationData->data, 8); + XdmPrintArray8Hex ("Request packet auth", authenticationData); + if (!XdmcpCopyARRAY8(authenticationData, &pdpy->authenticationData)) + return FALSE; + incoming = (XdmAuthKeyPtr) authenticationData->data; + XdmcpIncrementKey (incoming); + XdmcpWrap (authenticationData->data, &pdpy->key, + authenticationData->data, 8); + return TRUE; +} + +#endif /* XDMCP */ +#endif /* HASXDMAUTH (covering the entire file) */ @@ -0,0 +1,1226 @@ +/* $Xorg: xdmcp.c,v 1.4 2001/02/09 02:05:41 xorgcvs Exp $ */ +/* + +Copyright 1988, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall +not be used in advertising or otherwise to promote the sale, use or +other dealings in this Software without prior written authorization +from The Open Group. + +*/ + +/* + * xdm - display manager daemon + * Author: Keith Packard, MIT X Consortium + * + * xdmcp.c - Support for XDMCP + */ + +# include "dm.h" + +#ifdef XDMCP + +# include <X11/X.h> +# include <X11/Xfuncs.h> +# include <sys/types.h> +# include <ctype.h> + +#include <sys/socket.h> +#include <netinet/in.h> +#include <sys/un.h> +#include <netdb.h> + +#ifdef X_NOT_STDC_ENV +#define Time_t long +extern Time_t time (); +#else +#include <time.h> +#define Time_t time_t +#endif + +#define getString(name,len) ((name = malloc (len + 1)) ? 1 : 0) + +/* + * interface to policy routines + */ + +extern ARRAY8Ptr ChooseAuthentication (); +extern int Willing (); +extern ARRAY8Ptr Accept (); +extern int SelectConnectionTypeIndex (); + +int xdmcpFd = -1; +int chooserFd = -1; + +FD_TYPE WellKnownSocketsMask; +int WellKnownSocketsMax; + +#define pS(s) ((s) ? ((char *) (s)) : "empty string") + +DestroyWellKnownSockets () +{ + if (xdmcpFd != -1) + { + close (xdmcpFd); + xdmcpFd = -1; + } + if (chooserFd != -1) + { + close (chooserFd); + chooserFd = -1; + } +} + +AnyWellKnownSockets () +{ + return xdmcpFd != -1 || chooserFd != -1; +} + +static XdmcpBuffer buffer; + +/*ARGSUSED*/ +static void +sendForward (connectionType, address, closure) + CARD16 connectionType; + ARRAY8Ptr address; + char *closure; +{ +#ifdef AF_INET + struct sockaddr_in in_addr; +#endif +#ifdef AF_DECnet +#endif + struct sockaddr *addr; + int addrlen; + + switch (connectionType) + { +#ifdef AF_INET + case FamilyInternet: + addr = (struct sockaddr *) &in_addr; + bzero ((char *) &in_addr, sizeof (in_addr)); +#ifdef BSD44SOCKETS + in_addr.sin_len = sizeof(in_addr); +#endif + in_addr.sin_family = AF_INET; + in_addr.sin_port = htons ((short) XDM_UDP_PORT); + if (address->length != 4) + return; + memmove( (char *) &in_addr.sin_addr, address->data, address->length); + addrlen = sizeof (struct sockaddr_in); + break; +#endif +#ifdef AF_DECnet + case FamilyDECnet: +#endif + default: + return; + } + XdmcpFlush (xdmcpFd, &buffer, addr, addrlen); +} + +extern char *NetaddrAddress(); +extern char *NetaddrPort(); + +static void +ClientAddress (from, addr, port, type) + struct sockaddr *from; + ARRAY8Ptr addr, port; /* return */ + CARD16 *type; /* return */ +{ + int length, family; + char *data; + + data = NetaddrPort(from, &length); + XdmcpAllocARRAY8 (port, length); + memmove( port->data, data, length); + port->length = length; + + family = ConvertAddr(from, &length, &data); + XdmcpAllocARRAY8 (addr, length); + memmove( addr->data, data, length); + addr->length = length; + + *type = family; +} + +static void +all_query_respond (from, fromlen, authenticationNames, type) + struct sockaddr *from; + int fromlen; + ARRAYofARRAY8Ptr authenticationNames; + xdmOpCode type; +{ + ARRAY8Ptr authenticationName; + ARRAY8 status; + ARRAY8 addr; + CARD16 connectionType; + int family; + int length; + + family = ConvertAddr(from, &length, &(addr.data)); + addr.length = length; /* convert int to short */ + Debug ("all_query_respond: conntype=%d, addr=%lx, len=%d\n", + family, *(addr.data), addr.length); + if (family < 0) + return; + connectionType = family; + + if (type == INDIRECT_QUERY) + RememberIndirectClient (&addr, connectionType); + else + ForgetIndirectClient (&addr, connectionType); + + authenticationName = ChooseAuthentication (authenticationNames); + if (Willing (&addr, connectionType, authenticationName, &status, type)) + send_willing (from, fromlen, authenticationName, &status); + else + if (type == QUERY) + send_unwilling (from, fromlen, authenticationName, &status); + XdmcpDisposeARRAY8 (&status); +} + +static void +indirect_respond (from, fromlen, length) + struct sockaddr *from; + int fromlen; + int length; +{ + ARRAYofARRAY8 queryAuthenticationNames; + ARRAY8 clientAddress; + ARRAY8 clientPort; + CARD16 connectionType; + int expectedLen; + int i; + XdmcpHeader header; + int localHostAsWell; + + Debug ("Indirect respond %d\n", length); + if (!XdmcpReadARRAYofARRAY8 (&buffer, &queryAuthenticationNames)) + return; + expectedLen = 1; + for (i = 0; i < (int)queryAuthenticationNames.length; i++) + expectedLen += 2 + queryAuthenticationNames.data[i].length; + if (length == expectedLen) + { + ClientAddress (from, &clientAddress, &clientPort, &connectionType); + /* + * set up the forward query packet + */ + header.version = XDM_PROTOCOL_VERSION; + header.opcode = (CARD16) FORWARD_QUERY; + header.length = 0; + header.length += 2 + clientAddress.length; + header.length += 2 + clientPort.length; + header.length += 1; + for (i = 0; i < (int)queryAuthenticationNames.length; i++) + header.length += 2 + queryAuthenticationNames.data[i].length; + XdmcpWriteHeader (&buffer, &header); + XdmcpWriteARRAY8 (&buffer, &clientAddress); + XdmcpWriteARRAY8 (&buffer, &clientPort); + XdmcpWriteARRAYofARRAY8 (&buffer, &queryAuthenticationNames); + + localHostAsWell = ForEachMatchingIndirectHost (&clientAddress, connectionType, sendForward, (char *) 0); + + XdmcpDisposeARRAY8 (&clientAddress); + XdmcpDisposeARRAY8 (&clientPort); + if (localHostAsWell) + all_query_respond (from, fromlen, &queryAuthenticationNames, + INDIRECT_QUERY); + } + else + { + Debug ("Indirect length error got %d expect %d\n", length, expectedLen); + } + XdmcpDisposeARRAYofARRAY8 (&queryAuthenticationNames); +} + +static void +ProcessRequestSocket () +{ + XdmcpHeader header; + struct sockaddr_in addr; + int addrlen = sizeof addr; + + Debug ("ProcessRequestSocket\n"); + bzero ((char *) &addr, sizeof (addr)); + if (!XdmcpFill (xdmcpFd, &buffer, &addr, &addrlen)) { + Debug ("XdmcpFill failed\n"); + return; + } + if (!XdmcpReadHeader (&buffer, &header)) { + Debug ("XdmcpReadHeader failed\n"); + return; + } + if (header.version != XDM_PROTOCOL_VERSION) { + Debug ("XDMCP header version read was %d, expected %d\n", + header.version, XDM_PROTOCOL_VERSION); + return; + } + Debug ("header: %d %d %d\n", header.version, header.opcode, header.length); + switch (header.opcode) + { + case BROADCAST_QUERY: + broadcast_respond (&addr, addrlen, header.length); + break; + case QUERY: + query_respond (&addr, addrlen, header.length); + break; + case INDIRECT_QUERY: + indirect_respond (&addr, addrlen, header.length); + break; + case FORWARD_QUERY: + forward_respond (&addr, addrlen, header.length); + break; + case REQUEST: + request_respond (&addr, addrlen, header.length); + break; + case MANAGE: + manage (&addr, addrlen, header.length); + break; + case KEEPALIVE: + send_alive (&addr, addrlen, header.length); + break; + } +} + +WaitForSomething () +{ + FD_TYPE reads; + int nready; + extern int Rescan, ChildReady; + + Debug ("WaitForSomething\n"); + if (AnyWellKnownSockets () && !ChildReady) { + reads = WellKnownSocketsMask; + nready = select (WellKnownSocketsMax + 1, &reads, 0, 0, 0); + Debug ("select returns %d. Rescan: %d ChildReady: %d\n", + nready, Rescan, ChildReady); + if (nready > 0) + { + if (xdmcpFd >= 0 && FD_ISSET (xdmcpFd, &reads)) + ProcessRequestSocket (); + if (chooserFd >= 0 && FD_ISSET (chooserFd, &reads)) + ProcessChooserSocket (chooserFd); + } + if (ChildReady) + { + WaitForChild (); + } + } else + WaitForChild (); +} + +/* + * respond to a request on the UDP socket. + */ + +static ARRAY8 Hostname; + +void +registerHostname (name, namelen) + char *name; + int namelen; +{ + int i; + + if (!XdmcpReallocARRAY8 (&Hostname, namelen)) + return; + for (i = 0; i < namelen; i++) + Hostname.data[i] = name[i]; +} + +static void +direct_query_respond (from, fromlen, length, type) + struct sockaddr *from; + int fromlen; + int length; + xdmOpCode type; +{ + ARRAYofARRAY8 queryAuthenticationNames; + int expectedLen; + int i; + + if (!XdmcpReadARRAYofARRAY8 (&buffer, &queryAuthenticationNames)) + return; + expectedLen = 1; + for (i = 0; i < (int)queryAuthenticationNames.length; i++) + expectedLen += 2 + queryAuthenticationNames.data[i].length; + if (length == expectedLen) + all_query_respond (from, fromlen, &queryAuthenticationNames, type); + XdmcpDisposeARRAYofARRAY8 (&queryAuthenticationNames); +} + +query_respond (from, fromlen, length) + struct sockaddr *from; + int fromlen; + int length; +{ + Debug ("Query respond %d\n", length); + direct_query_respond (from, fromlen, length, QUERY); +} + +broadcast_respond (from, fromlen, length) + struct sockaddr *from; + int fromlen; + int length; +{ + direct_query_respond (from, fromlen, length, BROADCAST_QUERY); +} + +/* computes an X display name */ + +static char * +NetworkAddressToName(connectionType, connectionAddress, displayNumber) + CARD16 connectionType; + ARRAY8Ptr connectionAddress; + CARD16 displayNumber; +{ + switch (connectionType) + { + case FamilyInternet: + { + CARD8 *data; + struct hostent *hostent; + char *name; + char *localhost, *localHostname(); + + data = connectionAddress->data; + hostent = gethostbyaddr ((char *)data, + connectionAddress->length, AF_INET); + + localhost = localHostname (); + + /* + * protect against bogus host names + */ + if (hostent && hostent->h_name && hostent->h_name[0] + && (hostent->h_name[0] != '.')) + { + if (!strcmp (localhost, hostent->h_name)) + { + if (!getString (name, 10)) + return 0; + sprintf (name, ":%d", displayNumber); + } + else + { + if (removeDomainname) + { + char *localDot, *remoteDot; + + /* check for a common domain name. This + * could reduce names by recognising common + * super-domain names as well, but I don't think + * this is as useful, and will confuse more + * people + */ + if ((localDot = strchr(localhost, '.')) && + (remoteDot = strchr(hostent->h_name, '.'))) + { + /* smash the name in place; it won't + * be needed later. + */ + if (!strcmp (localDot+1, remoteDot+1)) + *remoteDot = '\0'; + } + } + + if (!getString (name, strlen (hostent->h_name) + 10)) + return 0; + sprintf (name, "%s:%d", hostent->h_name, displayNumber); + } + } + else + { + if (!getString (name, 25)) + return 0; + sprintf(name, "%d.%d.%d.%d:%d", + data[0], data[1], data[2], data[3], displayNumber); + } + return name; + } +#ifdef DNET + case FamilyDECnet: + return NULL; +#endif /* DNET */ + default: + return NULL; + } +} + +/*ARGSUSED*/ +forward_respond (from, fromlen, length) + struct sockaddr *from; + int fromlen; + int length; +{ + ARRAY8 clientAddress; + ARRAY8 clientPort; + ARRAYofARRAY8 authenticationNames; + struct sockaddr *client; + int clientlen; + int expectedLen; + int i; + + Debug ("Forward respond %d\n", length); + clientAddress.length = 0; + clientAddress.data = 0; + clientPort.length = 0; + clientPort.data = 0; + authenticationNames.length = 0; + authenticationNames.data = 0; + if (XdmcpReadARRAY8 (&buffer, &clientAddress) && + XdmcpReadARRAY8 (&buffer, &clientPort) && + XdmcpReadARRAYofARRAY8 (&buffer, &authenticationNames)) + { + expectedLen = 0; + expectedLen += 2 + clientAddress.length; + expectedLen += 2 + clientPort.length; + expectedLen += 1; /* authenticationNames */ + for (i = 0; i < (int)authenticationNames.length; i++) + expectedLen += 2 + authenticationNames.data[i].length; + if (length == expectedLen) + { + int j; + + j = 0; + for (i = 0; i < (int)clientPort.length; i++) + j = j * 256 + clientPort.data[i]; + Debug ("Forward client address (port %d)", j); + for (i = 0; i < (int)clientAddress.length; i++) + Debug (" %d", clientAddress.data[i]); + Debug ("\n"); + switch (from->sa_family) + { +#ifdef AF_INET + case AF_INET: + { + struct sockaddr_in in_addr; + + if (clientAddress.length != 4 || + clientPort.length != 2) + { + goto badAddress; + } + bzero ((char *) &in_addr, sizeof (in_addr)); +#ifdef BSD44SOCKETS + in_addr.sin_len = sizeof(in_addr); +#endif + in_addr.sin_family = AF_INET; + memmove( &in_addr.sin_addr, clientAddress.data, 4); + memmove( (char *) &in_addr.sin_port, clientPort.data, 2); + client = (struct sockaddr *) &in_addr; + clientlen = sizeof (in_addr); + all_query_respond (client, clientlen, &authenticationNames, + FORWARD_QUERY); + } + break; +#endif +#ifdef AF_UNIX + case AF_UNIX: + { + struct sockaddr_un un_addr; + + if (clientAddress.length >= sizeof (un_addr.sun_path)) + goto badAddress; + bzero ((char *) &un_addr, sizeof (un_addr)); + un_addr.sun_family = AF_UNIX; + memmove( un_addr.sun_path, clientAddress.data, clientAddress.length); + un_addr.sun_path[clientAddress.length] = '\0'; + client = (struct sockaddr *) &un_addr; +#ifdef BSD44SOCKETS + un_addr.sun_len = strlen(un_addr.sun_path); + clientlen = SUN_LEN(&un_addr); +#else + clientlen = sizeof (un_addr); +#endif + all_query_respond (client, clientlen, &authenticationNames, + FORWARD_QUERY); + } + break; +#endif +#ifdef AF_CHAOS + case AF_CHAOS: + goto badAddress; +#endif +#ifdef AF_DECnet + case AF_DECnet: + goto badAddress; +#endif + } + } + else + { + Debug ("Forward length error got %d expect %d\n", length, expectedLen); + } + } +badAddress: + XdmcpDisposeARRAY8 (&clientAddress); + XdmcpDisposeARRAY8 (&clientPort); + XdmcpDisposeARRAYofARRAY8 (&authenticationNames); +} + +send_willing (from, fromlen, authenticationName, status) + struct sockaddr *from; + int fromlen; + ARRAY8Ptr authenticationName; + ARRAY8Ptr status; +{ + XdmcpHeader header; + + Debug ("Send willing %*.*s %*.*s\n", authenticationName->length, + authenticationName->length, + pS(authenticationName->data), + status->length, + status->length, + pS(status->data)); + header.version = XDM_PROTOCOL_VERSION; + header.opcode = (CARD16) WILLING; + header.length = 6 + authenticationName->length + + Hostname.length + status->length; + XdmcpWriteHeader (&buffer, &header); + XdmcpWriteARRAY8 (&buffer, authenticationName); + XdmcpWriteARRAY8 (&buffer, &Hostname); + XdmcpWriteARRAY8 (&buffer, status); + XdmcpFlush (xdmcpFd, &buffer, from, fromlen); +} + +send_unwilling (from, fromlen, authenticationName, status) + struct sockaddr *from; + int fromlen; + ARRAY8Ptr authenticationName; + ARRAY8Ptr status; +{ + XdmcpHeader header; + + Debug ("Send unwilling %*.*s %*.*s\n", authenticationName->length, + authenticationName->length, + pS(authenticationName->data), + status->length, + status->length, + pS(status->data)); + header.version = XDM_PROTOCOL_VERSION; + header.opcode = (CARD16) UNWILLING; + header.length = 4 + Hostname.length + status->length; + XdmcpWriteHeader (&buffer, &header); + XdmcpWriteARRAY8 (&buffer, &Hostname); + XdmcpWriteARRAY8 (&buffer, status); + XdmcpFlush (xdmcpFd, &buffer, from, fromlen); +} + +static unsigned long globalSessionID; + +#define NextSessionID() (++globalSessionID) + +void init_session_id() +{ + /* Set randomly so we are unlikely to reuse id's from a previous + * incarnation so we don't say "Alive" to those displays. + * Start with low digits 0 to make debugging easier. + */ + globalSessionID = (time((Time_t)0)&0x7fff) * 16000; +} + +static ARRAY8 outOfMemory = { (CARD16) 13, (CARD8Ptr) "Out of memory" }; +static ARRAY8 noValidAddr = { (CARD16) 16, (CARD8Ptr) "No valid address" }; +static ARRAY8 noValidAuth = { (CARD16) 22, (CARD8Ptr) "No valid authorization" }; +static ARRAY8 noAuthentic = { (CARD16) 29, (CARD8Ptr) "XDM has no authentication key" }; + +request_respond (from, fromlen, length) + struct sockaddr *from; + int fromlen; + int length; +{ + CARD16 displayNumber; + ARRAY16 connectionTypes; + ARRAYofARRAY8 connectionAddresses; + ARRAY8 authenticationName; + ARRAY8 authenticationData; + ARRAYofARRAY8 authorizationNames; + ARRAY8 manufacturerDisplayID; + ARRAY8Ptr reason; + int expectlen; + int i, j; + struct protoDisplay *pdpy; + ARRAY8 authorizationName, authorizationData; + ARRAY8Ptr connectionAddress; + + Debug ("Request respond %d\n", length); + connectionTypes.data = 0; + connectionAddresses.data = 0; + authenticationName.data = 0; + authenticationData.data = 0; + authorizationNames.data = 0; + authorizationName.length = 0; + authorizationData.length = 0; + manufacturerDisplayID.data = 0; + if (XdmcpReadCARD16 (&buffer, &displayNumber) && + XdmcpReadARRAY16 (&buffer, &connectionTypes) && + XdmcpReadARRAYofARRAY8 (&buffer, &connectionAddresses) && + XdmcpReadARRAY8 (&buffer, &authenticationName) && + XdmcpReadARRAY8 (&buffer, &authenticationData) && + XdmcpReadARRAYofARRAY8 (&buffer, &authorizationNames) && + XdmcpReadARRAY8 (&buffer, &manufacturerDisplayID)) + { + expectlen = 0; + expectlen += 2; /* displayNumber */ + expectlen += 1 + 2*connectionTypes.length; /* connectionTypes */ + expectlen += 1; /* connectionAddresses */ + for (i = 0; i < (int)connectionAddresses.length; i++) + expectlen += 2 + connectionAddresses.data[i].length; + expectlen += 2 + authenticationName.length; /* authenticationName */ + expectlen += 2 + authenticationData.length; /* authenticationData */ + expectlen += 1; /* authoriationNames */ + for (i = 0; i < (int)authorizationNames.length; i++) + expectlen += 2 + authorizationNames.data[i].length; + expectlen += 2 + manufacturerDisplayID.length; /* displayID */ + if (expectlen != length) + { + Debug ("Request length error got %d expect %d\n", length, expectlen); + goto abort; + } + if (connectionTypes.length == 0 || + connectionAddresses.length != connectionTypes.length) + { + reason = &noValidAddr; + pdpy = 0; + goto decline; + } + pdpy = FindProtoDisplay (from, fromlen, displayNumber); + if (!pdpy) { + + /* Check this Display against the Manager's policy */ + reason = Accept (from, fromlen, displayNumber); + if (reason) + goto decline; + + /* Check the Display's stream services against Manager's policy */ + i = SelectConnectionTypeIndex (&connectionTypes, + &connectionAddresses); + if (i < 0) { + reason = &noValidAddr; + goto decline; + } + + /* The Manager considers this a new session */ + connectionAddress = &connectionAddresses.data[i]; + pdpy = NewProtoDisplay (from, fromlen, displayNumber, + connectionTypes.data[i], connectionAddress, + NextSessionID()); + Debug ("NewProtoDisplay 0x%x\n", pdpy); + if (!pdpy) { + reason = &outOfMemory; + goto decline; + } + } + if (authorizationNames.length == 0) + j = 0; + else + j = SelectAuthorizationTypeIndex (&authenticationName, + &authorizationNames); + if (j < 0) + { + reason = &noValidAuth; + goto decline; + } + if (!CheckAuthentication (pdpy, + &manufacturerDisplayID, + &authenticationName, + &authenticationData)) + { + reason = &noAuthentic; + goto decline; + } + if (j < (int)authorizationNames.length) + { + Xauth *auth; + SetProtoDisplayAuthorization (pdpy, + (unsigned short) authorizationNames.data[j].length, + (char *) authorizationNames.data[j].data); + auth = pdpy->xdmcpAuthorization; + if (!auth) + auth = pdpy->fileAuthorization; + if (auth) + { + authorizationName.length = auth->name_length; + authorizationName.data = (CARD8Ptr) auth->name; + authorizationData.length = auth->data_length; + authorizationData.data = (CARD8Ptr) auth->data; + } + } + if (pdpy) + { + send_accept (from, fromlen, pdpy->sessionID, + &authenticationName, + &authenticationData, + &authorizationName, + &authorizationData); + } + else + { +decline: ; + send_decline (from, fromlen, &authenticationName, + &authenticationData, + reason); + if (pdpy) + DisposeProtoDisplay (pdpy); + } + } +abort: + XdmcpDisposeARRAY16 (&connectionTypes); + XdmcpDisposeARRAYofARRAY8 (&connectionAddresses); + XdmcpDisposeARRAY8 (&authenticationName); + XdmcpDisposeARRAY8 (&authenticationData); + XdmcpDisposeARRAYofARRAY8 (&authorizationNames); + XdmcpDisposeARRAY8 (&manufacturerDisplayID); +} + +send_accept (to, tolen, sessionID, + authenticationName, authenticationData, + authorizationName, authorizationData) + struct sockaddr *to; + int tolen; + CARD32 sessionID; + ARRAY8Ptr authenticationName, authenticationData; + ARRAY8Ptr authorizationName, authorizationData; +{ + XdmcpHeader header; + + Debug ("Accept Session ID %d\n", sessionID); + header.version = XDM_PROTOCOL_VERSION; + header.opcode = (CARD16) ACCEPT; + header.length = 4; /* session ID */ + header.length += 2 + authenticationName->length; + header.length += 2 + authenticationData->length; + header.length += 2 + authorizationName->length; + header.length += 2 + authorizationData->length; + XdmcpWriteHeader (&buffer, &header); + XdmcpWriteCARD32 (&buffer, sessionID); + XdmcpWriteARRAY8 (&buffer, authenticationName); + XdmcpWriteARRAY8 (&buffer, authenticationData); + XdmcpWriteARRAY8 (&buffer, authorizationName); + XdmcpWriteARRAY8 (&buffer, authorizationData); + XdmcpFlush (xdmcpFd, &buffer, to, tolen); +} + +send_decline (to, tolen, authenticationName, authenticationData, status) + struct sockaddr *to; + int tolen; + ARRAY8Ptr authenticationName, authenticationData; + ARRAY8Ptr status; +{ + XdmcpHeader header; + + Debug ("Decline %*.*s\n", status->length, status->length, pS(status->data)); + header.version = XDM_PROTOCOL_VERSION; + header.opcode = (CARD16) DECLINE; + header.length = 0; + header.length += 2 + status->length; + header.length += 2 + authenticationName->length; + header.length += 2 + authenticationData->length; + XdmcpWriteHeader (&buffer, &header); + XdmcpWriteARRAY8 (&buffer, status); + XdmcpWriteARRAY8 (&buffer, authenticationName); + XdmcpWriteARRAY8 (&buffer, authenticationData); + XdmcpFlush (xdmcpFd, &buffer, to, tolen); +} + +manage (from, fromlen, length) + struct sockaddr *from; + int fromlen; + int length; +{ + CARD32 sessionID; + CARD16 displayNumber; + ARRAY8 displayClass; + int expectlen; + struct protoDisplay *pdpy; + struct display *d; + char *name = NULL; + char *class = NULL; + XdmcpNetaddr from_save; + ARRAY8 clientAddress, clientPort; + CARD16 connectionType; + + Debug ("Manage %d\n", length); + displayClass.data = 0; + displayClass.length = 0; + if (XdmcpReadCARD32 (&buffer, &sessionID) && + XdmcpReadCARD16 (&buffer, &displayNumber) && + XdmcpReadARRAY8 (&buffer, &displayClass)) + { + expectlen = 4 + /* session ID */ + 2 + /* displayNumber */ + 2 + displayClass.length; /* displayClass */ + if (expectlen != length) + { + Debug ("Manage length error got %d expect %d\n", length, expectlen); + goto abort; + } + pdpy = FindProtoDisplay (from, fromlen, displayNumber); + Debug ("Manage Session ID %d, pdpy 0x%x\n", sessionID, pdpy); + if (!pdpy || pdpy->sessionID != sessionID) + { + /* + * We may have already started a session for this display + * but it hasn't seen the response in the form of an + * XOpenDisplay() yet. So check if it is in the list of active + * displays, and if so check that the session id's match. + * If all this is true, then we have a duplicate request that + * can be ignored. + */ + if (!pdpy + && (d = FindDisplayByAddress(from, fromlen, displayNumber)) + && d->sessionID == sessionID) { + Debug("manage: got duplicate pkt, ignoring\n"); + goto abort; + } + Debug ("Session ID %d refused\n", sessionID); + if (pdpy) + Debug ("Existing Session ID %d\n", pdpy->sessionID); + send_refuse (from, fromlen, sessionID); + } + else + { + name = NetworkAddressToName (pdpy->connectionType, + &pdpy->connectionAddress, + pdpy->displayNumber); + Debug ("Computed display name: %s\n", name); + if (!name) + { + send_failed (from, fromlen, "(no name)", sessionID, "out of memory"); + goto abort; + } + d = FindDisplayByName (name); + if (d) + { + extern void StopDisplay (); + + Debug ("Terminating active session for %s\n", d->name); + StopDisplay (d); + } + class = malloc (displayClass.length + 1); + if (!class) + { + send_failed (from, fromlen, name, sessionID, "out of memory"); + goto abort; + } + if (displayClass.length) + { + memmove( class, displayClass.data, displayClass.length); + class[displayClass.length] = '\0'; + } + else + { + free ((char *) class); + class = (char *) NULL; + } + from_save = (XdmcpNetaddr) malloc (fromlen); + if (!from_save) + { + send_failed (from, fromlen, name, sessionID, "out of memory"); + goto abort; + } + memmove( from_save, from, fromlen); + d = NewDisplay (name, class); + if (!d) + { + free ((char *) from_save); + send_failed (from, fromlen, name, sessionID, "out of memory"); + goto abort; + } + d->displayType.location = Foreign; + d->displayType.lifetime = Transient; + d->displayType.origin = FromXDMCP; + d->sessionID = pdpy->sessionID; + d->from = from_save; + d->fromlen = fromlen; + d->displayNumber = pdpy->displayNumber; + ClientAddress (from, &clientAddress, &clientPort, &connectionType); + d->useChooser = 0; + if (IsIndirectClient (&clientAddress, connectionType)) + { + Debug ("IsIndirectClient\n"); + ForgetIndirectClient (&clientAddress, connectionType); + if (UseChooser (&clientAddress, connectionType)) + { + d->useChooser = 1; + Debug ("Use chooser for %s\n", d->name); + } + } + d->clientAddr = clientAddress; + d->connectionType = connectionType; + XdmcpDisposeARRAY8 (&clientPort); + if (pdpy->fileAuthorization) + { + d->authorizations = (Xauth **) malloc (sizeof (Xauth *)); + if (!d->authorizations) + { + free ((char *) from_save); + free ((char *) d); + send_failed (from, fromlen, name, sessionID, "out of memory"); + goto abort; + } + d->authorizations[0] = pdpy->fileAuthorization; + d->authNum = 1; + pdpy->fileAuthorization = 0; + } + DisposeProtoDisplay (pdpy); + Debug ("Starting display %s,%s\n", d->name, d->class); + StartDisplay (d); + } + } +abort: + XdmcpDisposeARRAY8 (&displayClass); + if (name) free ((char*) name); + if (class) free ((char*) class); +} + +SendFailed (d, reason) + struct display *d; + char *reason; +{ + Debug ("Display start failed, sending Failed\n"); + send_failed (d->from, d->fromlen, d->name, d->sessionID, reason); +} + +send_failed (from, fromlen, name, sessionID, reason) + struct sockaddr *from; + int fromlen; + char *name; + CARD32 sessionID; + char *reason; +{ + static char buf[256]; + XdmcpHeader header; + ARRAY8 status; + + sprintf (buf, "Session %d failed for display %s: %s", + sessionID, name, reason); + Debug ("Send failed %d %s\n", sessionID, buf); + status.length = strlen (buf); + status.data = (CARD8Ptr) buf; + header.version = XDM_PROTOCOL_VERSION; + header.opcode = (CARD16) FAILED; + header.length = 6 + status.length; + XdmcpWriteHeader (&buffer, &header); + XdmcpWriteCARD32 (&buffer, sessionID); + XdmcpWriteARRAY8 (&buffer, &status); + XdmcpFlush (xdmcpFd, &buffer, from, fromlen); +} + +send_refuse (from, fromlen, sessionID) + struct sockaddr *from; + int fromlen; + CARD32 sessionID; +{ + XdmcpHeader header; + + Debug ("Send refuse %d\n", sessionID); + header.version = XDM_PROTOCOL_VERSION; + header.opcode = (CARD16) REFUSE; + header.length = 4; + XdmcpWriteHeader (&buffer, &header); + XdmcpWriteCARD32 (&buffer, sessionID); + XdmcpFlush (xdmcpFd, &buffer, from, fromlen); +} + +send_alive (from, fromlen, length) + struct sockaddr *from; + int fromlen; + int length; +{ + CARD32 sessionID; + CARD16 displayNumber; + struct display *d; + XdmcpHeader header; + CARD8 sendRunning; + CARD32 sendSessionID; + + Debug ("Send alive\n"); + if (XdmcpReadCARD16 (&buffer, &displayNumber) && + XdmcpReadCARD32 (&buffer, &sessionID)) + { + if (length == 6) + { + d = FindDisplayBySessionID (sessionID); + if (!d) { + d = FindDisplayByAddress (from, fromlen, displayNumber); + } + sendRunning = 0; + sendSessionID = 0; + if (d && d->status == running) + { + if (d->sessionID == sessionID) + sendRunning = 1; + sendSessionID = d->sessionID; + } + header.version = XDM_PROTOCOL_VERSION; + header.opcode = (CARD16) ALIVE; + header.length = 5; + Debug ("alive: %d %d\n", sendRunning, sendSessionID); + XdmcpWriteHeader (&buffer, &header); + XdmcpWriteCARD8 (&buffer, sendRunning); + XdmcpWriteCARD32 (&buffer, sendSessionID); + XdmcpFlush (xdmcpFd, &buffer, from, fromlen); + } + } +} + +char * +NetworkAddressToHostname (connectionType, connectionAddress) + CARD16 connectionType; + ARRAY8Ptr connectionAddress; +{ + char *name = 0; + + switch (connectionType) + { + case FamilyInternet: + { + struct hostent *hostent; + char dotted[20]; + char *local_name; + + hostent = gethostbyaddr ((char *)connectionAddress->data, + connectionAddress->length, AF_INET); + + if (hostent) + local_name = hostent->h_name; + else { + /* can't get name, so use emergency fallback */ + sprintf(dotted, "%d.%d.%d.%d", + connectionAddress->data[0], + connectionAddress->data[1], + connectionAddress->data[2], + connectionAddress->data[3]); + local_name = dotted; + LogError ("Cannot convert Internet address %s to host name\n", + dotted); + } + if (!getString (name, strlen (local_name))) + break; + strcpy (name, local_name); + break; + } +#ifdef DNET + case FamilyDECnet: + break; +#endif /* DNET */ + default: + break; + } + return name; +} + +static +HostnameToNetworkAddress (name, connectionType, connectionAddress) +char *name; +CARD16 connectionType; +ARRAY8Ptr connectionAddress; +{ + switch (connectionType) + { + case FamilyInternet: + { + struct hostent *hostent; + + hostent = gethostbyname (name); + if (!hostent) + return FALSE; + if (!XdmcpAllocARRAY8 (connectionAddress, hostent->h_length)) + return FALSE; + memmove( connectionAddress->data, hostent->h_addr, hostent->h_length); + return TRUE; + } +#ifdef DNET + case FamilyDECnet: + return FALSE; +#endif + } + return FALSE; +} + +/* + * converts a display name into a network address, using + * the same rules as XOpenDisplay (algorithm cribbed from there) + */ + +static +NameToNetworkAddress(name, connectionTypep, connectionAddress, displayNumber) +char *name; +CARD16Ptr connectionTypep; +ARRAY8Ptr connectionAddress; +CARD16Ptr displayNumber; +{ + char *colon, *display_number; + char hostname[1024]; + int dnet = FALSE; + CARD16 number; + CARD16 connectionType; + + colon = strchr(name, ':'); + if (!colon) + return FALSE; + if (colon != name) + { + if (colon - name > sizeof (hostname)) + return FALSE; + strncpy (hostname, name, colon - name); + hostname[colon - name] = '\0'; + } + else + { + strcpy (hostname, localHostname ()); + } + if (colon[1] == ':') + { + dnet = TRUE; + colon++; + } +#ifndef DNETCONN + if (dnet) + return FALSE; +#endif + display_number = colon + 1; + while (*display_number && *display_number != '.') + { + if (!isascii (*display_number) || !isdigit(*display_number)) + return FALSE; + } + if (display_number == colon + 1) + return FALSE; + number = atoi (colon + 1); +#ifdef DNETCONN + if (dnet) + connectionType = FamilyDECnet; + else +#endif + connectionType = FamilyInternet; + if (!HostnameToNetworkAddress (hostname, connectionType, connectionAddress)) + return FALSE; + *displayNumber = number; + *connectionTypep = connectionType; + return TRUE; +} + +#endif /* XDMCP */ diff --git a/xdmshell.c b/xdmshell.c new file mode 100644 index 0000000..166e689 --- /dev/null +++ b/xdmshell.c @@ -0,0 +1,222 @@ +/* $Xorg: xdmshell.c,v 1.4 2001/02/09 02:05:41 xorgcvs Exp $ */ +/* + * xdmshell - simple program for running xdm from login + * + * +Copyright 1988, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + * * + * Author: Jim Fulton, MIT X Consortium + * + * This program should probably be setuid to root. On the macII, it must be + * run from the console so that getty doesn't get confused about zero-length + * reads. + * + * WARNING: Make sure that you tailor your Xresources file to have a + * way of invoking the abort-display() action. Otherwise, you won't be able + * bring down X when you are finished. + */ + +#include <stdio.h> +#include "dm.h" +#include <errno.h> +#ifdef X_NOT_STDC_ENV +extern int errno; +#endif + +#ifdef macII +#define ON_CONSOLE_ONLY +#endif + +#ifdef ON_CONSOLE_ONLY +#include <sys/ioctl.h> +#endif + +#ifndef BINDIR +#define BINDIR "/usr/bin/X11" +#endif + +/* + * HP-UX does have vfork, but A/UX doesn't + */ +#ifndef HAS_VFORK +#define vfork() fork() +#endif + +char *ProgramName; + +static char *SysErrorMsg (n) + int n; +{ + char *s = strerror(n); + return (s ? s : "unknown error"); +} + + +static int exec_args (filename, args) + char *filename; + char **args; +{ + int pid; + waitType status; + + if (!filename) return -1; + + if (filename[0] != '/') { + fprintf (stderr, + "%s: attempt to execute program with relative pathname: %s\n", + ProgramName, filename); + return -1; + } + + if (access (filename, X_OK) != 0) return -1; + + switch (pid = vfork ()) { + case -1: /* error */ + return -1; + case 0: /* child */ + execv (filename, args); + _exit (1); + /* NOTREACHED */ + default: /* parent */ + while (wait (&status) != pid) ; + } + return waitCode (status); +} + +static int exec_one_arg (filename, arg) + char *filename; + char *arg; +{ + char *argv[3]; + + argv[0] = filename; + argv[1] = arg; + argv[2] = NULL; + return exec_args (filename, argv); +} + +main (argc, argv) + int argc; + char *argv[]; +{ + int ttyfd; + char cmdbuf[256]; + char *args[10]; +#ifdef ON_CONSOLE_ONLY + int consfd; + int ttypgrp, conspgrp; + char *ttyName; + extern char *ttyname(); +#endif + + ProgramName = argv[0]; + + if (argc > 1) { + fprintf (stderr, "usage: %s\r\n", ProgramName); + exit (1); + } + + ttyfd = open ("/dev/tty", O_RDWR, 0); + if (ttyfd < 3) { /* stdin = 0, stdout = 1, stderr = 2 */ + fprintf (stderr, + "%s: must be run directly from the console.\r\n", + ProgramName); + exit (1); + } +#ifdef ON_CONSOLE_ONLY + if (ioctl (ttyfd, TIOCGPGRP, (char *)&ttypgrp) != 0) { + fprintf (stderr, "%s: unable to get process group of /dev/tty\r\n", + ProgramName); + (void) close (ttyfd); + exit (1); + } +#endif + (void) close (ttyfd); + +#ifdef ON_CONSOLE_ONLY + ttyName = ttyname (0); + if (!ttyName || strcmp (ttyName, "/dev/console") != 0) { + fprintf (stderr, "%s: must login on /dev/console instead of %s\r\n", + ProgramName, ttyName ? ttyName : "non-terminal device"); + exit (1); + } + + consfd = open ("/dev/console", O_RDWR, 0); + if (consfd < 3) { /* stdin = 0, stdout = 1, stderr = 2 */ + fprintf (stderr, "%s: unable to open /dev/console\r\n", + ProgramName); + exit (1); + } + + if (ioctl (consfd, TIOCGPGRP, (char *)&conspgrp) != 0) { + fprintf (stderr, + "%s: unable to get process group of /dev/console\r\n", + ProgramName); + (void) close (consfd); + exit (1); + } + (void) close (consfd); + + if (ttypgrp != conspgrp) { + fprintf (stderr, "%s: must be run from /dev/console\r\n", + ProgramName); + exit (1); + } +#endif + + /* make xdm run in a non-setuid environment */ + setuid (geteuid()); + + /* + * exec /usr/bin/X11/xdm -nodaemon -udpPort 0 + */ + strcpy (cmdbuf, BINDIR); + strcat (cmdbuf, "/xdm"); + args[0] = cmdbuf; + args[1] = "-nodaemon"; + args[2] = "-udpPort"; + args[3] = "0"; + args[4] = NULL; + if (exec_args (cmdbuf, args) == -1) { + fprintf (stderr, "%s: unable to execute %s (error %d, %s)\r\n", + ProgramName, cmdbuf, errno, SysErrorMsg(errno)); + exit (1); + } + +#ifdef macII + strcpy (cmdbuf, BINDIR); + strcat (cmdbuf, "/Xrepair"); + (void) exec_one_arg (cmdbuf, NULL); + (void) exec_one_arg ("/usr/bin/screenrestore", NULL); +#endif + +#ifdef sun + strcpy (cmdbuf, BINDIR); + strcat (cmdbuf, "/kbd_mode"); + (void) exec_one_arg (cmdbuf, "-a"); +#endif + + exit (0); + /*NOTREACHED*/ +} + |