1/*
2 *
3 * parse_displayname - utility routine for splitting up display name strings
4 *
5 *
6Copyright 1989, 1998  The Open Group
7
8Permission to use, copy, modify, distribute, and sell this software and its
9documentation for any purpose is hereby granted without fee, provided that
10the above copyright notice appear in all copies and that both that
11copyright notice and this permission notice appear in supporting
12documentation.
13
14The above copyright notice and this permission notice shall be included in
15all copies or substantial portions of the Software.
16
17THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
20OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
21AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23
24Except as contained in this notice, the name of The Open Group shall not be
25used in advertising or otherwise to promote the sale, use or other dealings
26in this Software without prior written authorization from The Open Group.
27 * *
28 * Author:  Jim Fulton, MIT X Consortium
29 */
30
31#ifdef HAVE_CONFIG_H
32#include "config.h"
33#endif
34
35#include <stdio.h>			/* for NULL */
36#include <ctype.h>			/* for isascii() and isdigit() */
37#include <X11/Xos.h>			/* for strchr() and string routines */
38#include <X11/Xlib.h>			/* for Family constants */
39#include <X11/Xauth.h>			/* for FamilyLocal */
40#include <X11/Xmu/SysUtil.h>
41
42#include <sys/stat.h>
43#include <limits.h>
44
45#if defined(UNIXCONN) || defined(LOCALCONN)
46#define UNIX_CONNECTION "unix"
47#define UNIX_CONNECTION_LENGTH 4
48#endif
49
50#include <stdlib.h>
51#include "xauth.h"
52
53/*
54 * private utility routines
55 */
56
57char *
58copystring (const char *src, int len)
59{
60    char *cp;
61
62    if (!src && len != 0) return NULL;
63    cp = malloc (len + 1);
64    if (cp) {
65	if (src) memcpy (cp, src, len);
66	cp[len] = '\0';
67    }
68    return cp;
69}
70
71
72char *
73get_local_hostname (char *buf, int maxlen)
74{
75    buf[0] = '\0';
76    (void) XmuGetHostname (buf, maxlen);
77    return (buf[0] ? buf : NULL);
78}
79
80#ifndef UNIXCONN
81static char *
82copyhostname (void)
83{
84    char buf[256];
85
86    return (get_local_hostname (buf, sizeof buf) ?
87	    copystring (buf, strlen (buf)) : NULL);
88}
89#endif
90
91/*
92 * parse_displayname - display a display string up into its component parts
93 */
94Bool
95parse_displayname (const char *displayname,
96		   int *familyp,	/* return */
97		   char **hostp,	/* return */
98		   int *dpynump,	/* return */
99		   int *scrnump,	/* return */
100		   char **restp)	/* return */
101{
102    char *ptr;				/* work variables */
103    int len;				/* work variable */
104    int family = -1;			/* value to be returned */
105    char *host = NULL;			/* must free if set and error return */
106    int dpynum = -1;			/* value to be returned */
107    int scrnum = 0;			/* value to be returned */
108    char *rest = NULL;			/* must free if set and error return */
109    Bool dnet = False;			/* if true then using DECnet */
110
111					/* check the name */
112    if (!displayname || !displayname[0]) return False;
113
114					/* must have at least :number */
115    ptr = strrchr(displayname, ':');
116    if (!ptr || !ptr[1]) return False;
117    if ((ptr != displayname) && (*(ptr - 1) == ':')) {
118	ptr--;
119	dnet = True;
120    }
121
122
123    /*
124     * get the host string; if none is given, use the most effiecient path
125     */
126
127    len = (ptr - displayname);	/* length of host name */
128    if (len == 0) {			/* choose most efficient path */
129#if defined(UNIXCONN) || defined(LOCALCONN)
130	host = copystring (UNIX_CONNECTION, UNIX_CONNECTION_LENGTH);
131	family = FamilyLocal;
132#else
133	if (dnet) {
134	    host = copystring ("0", 1);
135	    family = FamilyDECnet;
136	} else {
137	    host = copyhostname ();
138	    family = FamilyInternet;
139	}
140#endif
141    } else if (!dnet && (*displayname == '[') && (*(ptr - 1) == ']')) {
142	/* Allow RFC2732-like [<IPv6NumericAddress>]:display syntax */
143	family = FamilyInternet6;
144	host = copystring (displayname + 1, len - 2);
145    } else {
146	host = copystring (displayname, len);
147	if (dnet) {
148	    family = dnet;
149	} else {
150#if defined(UNIXCONN) || defined(LOCALCONN)
151	    if (host && strcmp (host, UNIX_CONNECTION) == 0)
152	      family = FamilyLocal;
153	    else
154#endif
155	      family = FamilyInternet;
156	}
157    }
158
159    if (!host) return False;
160
161    {
162        /*
163         * If using launchd socket, remove the screen number from the end
164         * of $DISPLAY and check if it is a path to a socket.
165         */
166        char path[PATH_MAX];
167        struct stat sbuf;
168
169#ifdef HAVE_STRLCPY
170        strlcpy(path, displayname, sizeof(path));
171#else
172        strncpy(path, displayname, sizeof(path) - 1);
173        path[sizeof(path) - 1] = '\0';
174#endif
175        if (0 == stat(path, &sbuf) && S_ISSOCK(sbuf.st_mode)) {
176            family = FamilyLocal;
177        } else {
178            char *dot = strrchr(path, '.');
179            if (dot) {
180                *dot = '\0';
181                /* screen = atoi(dot + 1); */
182                if (0 == stat(path, &sbuf) && S_ISSOCK(sbuf.st_mode)) {
183                    family = FamilyLocal;
184                }
185            }
186        }
187    }
188
189    /*
190     * get the display number; we know that there is something after the
191     * colon (or colons) from above.  note that host is now set and must
192     * be freed if there is an error.
193     */
194
195    if (dnet) ptr++;			/* skip the extra DECnet colon */
196    ptr++;				/* move to start of display num */
197    {
198	register char *cp;
199
200	for (cp = ptr; *cp && isascii(*cp) && isdigit(*cp); cp++) ;
201	len = (cp - ptr);
202					/* check present and valid follow */
203	if (len == 0 || (*cp && *cp != '.')) {
204	    free (host);
205	    return False;
206	}
207
208	dpynum = atoi (ptr);		/* it will handle num. as well */
209	ptr = cp;
210    }
211
212    /*
213     * now get screen number if given; ptr may point to nul at this point
214     */
215    if (ptr[0] == '.') {
216	register char *cp;
217
218	ptr++;
219	for (cp = ptr; *cp && isascii(*cp) && isdigit(*cp); cp++) ;
220	len = (cp - ptr);
221	if (len == 0 || (*cp && *cp != '.')) {	/* all prop name */
222	    free (host);
223	    return False;
224	}
225
226	scrnum = atoi (ptr);		/* it will handle num. as well */
227	ptr = cp;
228    }
229
230    /*
231     * and finally, get any additional stuff that might be following the
232     * the screen number; ptr must point to a period if there is anything
233     */
234
235    if (ptr[0] == '.') {
236	ptr++;
237	len = strlen (ptr);
238	if (len > 0) {
239	    rest = copystring (ptr, len);
240	    if (!rest) {
241		free (host);
242		return False;
243	    }
244	}
245    }
246
247    /*
248     * and we are done!
249     */
250
251    *familyp = family;
252    *hostp = host;
253    *dpynump = dpynum;
254    *scrnump = scrnum;
255    *restp = rest;
256    return True;
257}
258
259
260