42f09c4d1f9a5be196680ede860e13aa78ba7bab
[framework/uifw/xorg/lib/xtrans.git] / Xtransutil.c
1 /*
2
3 Copyright 1993, 1994, 1998  The Open Group
4
5 Permission to use, copy, modify, distribute, and sell this software and its
6 documentation for any purpose is hereby granted without fee, provided that
7 the above copyright notice appear in all copies and that both that
8 copyright notice and this permission notice appear in supporting
9 documentation.
10
11 The above copyright notice and this permission notice shall be included
12 in all copies or substantial portions of the Software.
13
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17 IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 OTHER DEALINGS IN THE SOFTWARE.
21
22 Except as contained in this notice, the name of The Open Group shall
23 not be used in advertising or otherwise to promote the sale, use or
24 other dealings in this Software without prior written authorization
25 from The Open Group.
26
27  * Copyright 1993, 1994 NCR Corporation - Dayton, Ohio, USA
28  *
29  * All Rights Reserved
30  *
31  * Permission to use, copy, modify, and distribute this software and its
32  * documentation for any purpose and without fee is hereby granted, provided
33  * that the above copyright notice appear in all copies and that both that
34  * copyright notice and this permission notice appear in supporting
35  * documentation, and that the name NCR not be used in advertising
36  * or publicity pertaining to distribution of the software without specific,
37  * written prior permission.  NCR makes no representations about the
38  * suitability of this software for any purpose.  It is provided "as is"
39  * without express or implied warranty.
40  *
41  * NCRS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
42  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
43  * NO EVENT SHALL NCR BE LIABLE FOR ANY SPECIAL, INDIRECT OR
44  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
45  * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
46  * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
47  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
48  */
49
50 /*
51  * These are some utility functions created for convenience or to provide
52  * an interface that is similar to an existing interface. These are built
53  * only using the Transport Independant API, and have no knowledge of
54  * the internal implementation.
55  */
56
57 #ifdef XTHREADS
58 #include <X11/Xthreads.h>
59 #endif
60 #ifdef WIN32
61 #include <X11/Xlibint.h>
62 #include <X11/Xwinsock.h>
63 #endif
64
65 #ifdef X11_t
66
67 /*
68  * These values come from X.h and Xauth.h, and MUST match them. Some
69  * of these values are also defined by the ChangeHost protocol message.
70  */
71
72 #define FamilyInternet          0       /* IPv4 */
73 #define FamilyDECnet            1
74 #define FamilyChaos             2
75 #define FamilyInternet6         6
76 #define FamilyAmoeba            33
77 #define FamilyLocalHost         252
78 #define FamilyKrb5Principal     253
79 #define FamilyNetname           254
80 #define FamilyLocal             256
81 #define FamilyWild              65535
82
83 /*
84  * TRANS(ConvertAddress) converts a sockaddr based address to an
85  * X authorization based address. Some of this is defined as part of
86  * the ChangeHost protocol. The rest is just done in a consistent manner.
87  */
88
89 int
90 TRANS(ConvertAddress)(int *familyp, int *addrlenp, Xtransaddr **addrp)
91
92 {
93
94     PRMSG(2,"ConvertAddress(%d,%d,%x)\n",*familyp,*addrlenp,*addrp);
95
96     switch( *familyp )
97     {
98 #if defined(TCPCONN) || defined(STREAMSCONN)
99     case AF_INET:
100     {
101         /*
102          * Check for the BSD hack localhost address 127.0.0.1.
103          * In this case, we are really FamilyLocal.
104          */
105
106         struct sockaddr_in saddr;
107         int len = sizeof(saddr.sin_addr.s_addr);
108         char *cp = (char *) &saddr.sin_addr.s_addr;
109
110         memcpy (&saddr, *addrp, sizeof (struct sockaddr_in));
111
112         if ((len == 4) && (cp[0] == 127) && (cp[1] == 0) &&
113             (cp[2] == 0) && (cp[3] == 1))
114         {
115             *familyp=FamilyLocal;
116         }
117         else
118         {
119             *familyp=FamilyInternet;
120             *addrlenp=len;
121             memcpy(*addrp,&saddr.sin_addr,len);
122         }
123         break;
124     }
125
126 #if defined(IPv6) && defined(AF_INET6)
127     case AF_INET6:
128     {
129         struct sockaddr_in6 saddr6;
130
131         memcpy (&saddr6, *addrp, sizeof (struct sockaddr_in6));
132
133         if (IN6_IS_ADDR_LOOPBACK(&saddr6.sin6_addr))
134         {
135             *familyp=FamilyLocal;
136         }
137         else if (IN6_IS_ADDR_V4MAPPED(&(saddr6.sin6_addr))) {
138             char *cp = (char *) &saddr6.sin6_addr.s6_addr[12];
139
140             if ((cp[0] == 127) && (cp[1] == 0) &&
141               (cp[2] == 0) && (cp[3] == 1))
142             {
143                 *familyp=FamilyLocal;
144             }
145             else 
146             {
147                 *familyp=FamilyInternet;
148                 *addrlenp = sizeof (struct in_addr);
149                 memcpy(*addrp,cp,*addrlenp);
150             }
151         }
152         else
153         {
154             *familyp=FamilyInternet6;
155             *addrlenp=sizeof(saddr6.sin6_addr);
156             memcpy(*addrp,&saddr6.sin6_addr,sizeof(saddr6.sin6_addr));
157         }
158         break;
159     }
160 #endif /* IPv6 */
161 #endif /* defined(TCPCONN) || defined(STREAMSCONN) */
162
163
164 #if defined(UNIXCONN) || defined(LOCALCONN) 
165     case AF_UNIX:
166     {
167         *familyp=FamilyLocal;
168         break;
169     }
170 #endif /* defined(UNIXCONN) || defined(LOCALCONN) */
171
172 #if (defined(__SCO__) || defined(__UNIXWARE__)) && defined(LOCALCONN)
173     case 0:
174     {
175         *familyp=FamilyLocal;
176         break;
177     }
178 #endif
179
180     default:
181         PRMSG(1,"ConvertAddress: Unknown family type %d\n",
182               *familyp, 0,0 );
183         return -1;
184     }
185
186
187     if (*familyp == FamilyLocal)
188     {
189         /*
190          * In the case of a local connection, we need to get the
191          * host name for authentication.
192          */
193         
194         char hostnamebuf[256];
195         int len = TRANS(GetHostname) (hostnamebuf, sizeof hostnamebuf);
196
197         if (len > 0) {
198             if (*addrp && *addrlenp < (len + 1))
199             {
200                 xfree ((char *) *addrp);
201                 *addrp = NULL;
202             }
203             if (!*addrp)
204                 *addrp = (Xtransaddr *) xalloc (len + 1);
205             if (*addrp) {
206                 strcpy ((char *) *addrp, hostnamebuf);
207                 *addrlenp = len;
208             } else {
209                 *addrlenp = 0;
210             }
211         }
212         else
213         {
214             if (*addrp)
215                 xfree ((char *) *addrp);
216             *addrp = NULL;
217             *addrlenp = 0;
218         }
219     }
220
221     return 0;
222 }
223
224 #endif /* X11_t */
225
226 #ifdef ICE_t
227
228 /* Needed for _XGethostbyaddr usage in TRANS(GetPeerNetworkId) */
229 # if defined(TCPCONN) || defined(UNIXCONN)
230 #  define X_INCLUDE_NETDB_H
231 #  define XOS_USE_NO_LOCKING
232 #  include <X11/Xos_r.h>
233 # endif
234
235 #include <signal.h>
236
237 char *
238 TRANS(GetMyNetworkId) (XtransConnInfo ciptr)
239
240 {
241     int         family = ciptr->family;
242     char        *addr = ciptr->addr;
243     char        hostnamebuf[256];
244     char        *networkId = NULL;
245     char        *transName = ciptr->transptr->TransName;
246
247     if (gethostname (hostnamebuf, sizeof (hostnamebuf)) < 0)
248     {
249         return (NULL);
250     }
251
252     switch (family)
253     {
254 #if defined(UNIXCONN) || defined(STREAMSCONN) || defined(LOCALCONN) 
255     case AF_UNIX:
256     {
257         struct sockaddr_un *saddr = (struct sockaddr_un *) addr;
258         networkId = (char *) xalloc (3 + strlen (transName) +
259             strlen (hostnamebuf) + strlen (saddr->sun_path));
260         sprintf (networkId, "%s/%s:%s", transName,
261             hostnamebuf, saddr->sun_path);
262         break;
263     }
264 #endif /* defined(UNIXCONN) || defined(STREAMSCONN) || defined(LOCALCONN) */
265
266 #if defined(TCPCONN) || defined(STREAMSCONN)
267     case AF_INET:
268 #if defined(IPv6) && defined(AF_INET6)
269     case AF_INET6:
270 #endif
271     {
272         struct sockaddr_in *saddr = (struct sockaddr_in *) addr;
273 #if defined(IPv6) && defined(AF_INET6)
274         struct sockaddr_in6 *saddr6 = (struct sockaddr_in6 *) addr;
275 #endif
276         int portnum;
277         char portnumbuf[10];
278
279
280 #if defined(IPv6) && defined(AF_INET6)
281         if (family == AF_INET6)
282             portnum = ntohs (saddr6->sin6_port);
283         else
284 #endif
285             portnum = ntohs (saddr->sin_port);
286
287         snprintf (portnumbuf, sizeof(portnumbuf), "%d", portnum);
288         networkId = (char *) xalloc (3 + strlen (transName) +
289             strlen (hostnamebuf) + strlen (portnumbuf));
290         sprintf (networkId, "%s/%s:%s", transName, hostnamebuf, portnumbuf);
291         break;
292     }
293 #endif /* defined(TCPCONN) || defined(STREAMSCONN) */
294
295
296     default:
297         break;
298     }
299
300     return (networkId);
301 }
302
303 #include <setjmp.h>
304 static jmp_buf env;
305
306 #ifdef SIGALRM
307 static volatile int nameserver_timedout = 0;
308
309 static
310 #ifdef RETSIGTYPE /* set by autoconf AC_TYPE_SIGNAL */
311 RETSIGTYPE
312 #else /* Imake */
313 #ifdef SIGNALRETURNSINT
314 int
315 #else
316 void
317 #endif
318 #endif
319 nameserver_lost(int sig)
320 {
321   nameserver_timedout = 1;
322   longjmp (env, -1);
323   /* NOTREACHED */
324 #ifdef SIGNALRETURNSINT
325   return -1;                            /* for picky compilers */
326 #endif
327 }
328 #endif /* SIGALARM */
329
330
331 char *
332 TRANS(GetPeerNetworkId) (XtransConnInfo ciptr)
333
334 {
335     int         family = ciptr->family;
336     char        *peer_addr = ciptr->peeraddr;
337     char        *hostname;
338     char        addrbuf[256];
339     const char  *addr = NULL;
340
341     switch (family)
342     {
343     case AF_UNSPEC:
344 #if defined(UNIXCONN) || defined(STREAMSCONN) || defined(LOCALCONN) 
345     case AF_UNIX:
346     {
347         if (gethostname (addrbuf, sizeof (addrbuf)) == 0)
348             addr = addrbuf;
349         break;
350     }
351 #endif /* defined(UNIXCONN) || defined(STREAMSCONN) || defined(LOCALCONN) */
352
353 #if defined(TCPCONN) || defined(STREAMSCONN)
354     case AF_INET:
355 #if defined(IPv6) && defined(AF_INET6)
356     case AF_INET6:
357 #endif
358     {
359         struct sockaddr_in *saddr = (struct sockaddr_in *) peer_addr;
360 #if defined(IPv6) && defined(AF_INET6)
361         struct sockaddr_in6 *saddr6 = (struct sockaddr_in6 *) peer_addr;
362 #endif
363         char *address;
364         int addresslen;
365 #ifdef XTHREADS_NEEDS_BYNAMEPARAMS
366         _Xgethostbynameparams hparams;
367 #endif
368         struct hostent * volatile hostp = NULL;
369
370 #if defined(IPv6) && defined(AF_INET6)
371         if (family == AF_INET6)
372         {
373             address = (char *) &saddr6->sin6_addr;
374             addresslen = sizeof (saddr6->sin6_addr);
375         }
376         else
377 #endif
378         {
379             address = (char *) &saddr->sin_addr;
380             addresslen = sizeof (saddr->sin_addr);
381         }
382
383 #ifdef SIGALRM
384         /*
385          * gethostbyaddr can take a LONG time if the host does not exist.
386          * Assume that if it does not respond in NAMESERVER_TIMEOUT seconds
387          * that something is wrong and do not make the user wait.
388          * gethostbyaddr will continue after a signal, so we have to
389          * jump out of it. 
390          */
391
392         nameserver_timedout = 0;
393         signal (SIGALRM, nameserver_lost);
394         alarm (4);
395         if (setjmp(env) == 0) {
396 #endif
397             hostp = _XGethostbyaddr (address, addresslen, family, hparams);
398 #ifdef SIGALRM
399         }
400         alarm (0);
401 #endif
402         if (hostp != NULL)
403           addr = hostp->h_name;
404         else
405 #if defined(IPv6) && defined(AF_INET6)
406           addr = inet_ntop (family, address, addrbuf, sizeof (addrbuf));
407 #else
408           addr = inet_ntoa (saddr->sin_addr);
409 #endif
410         break;
411     }
412
413 #endif /* defined(TCPCONN) || defined(STREAMSCONN) */
414
415
416     default:
417         return (NULL);
418     }
419
420
421     hostname = (char *) xalloc (
422         strlen (ciptr->transptr->TransName) + strlen (addr) + 2);
423     strcpy (hostname, ciptr->transptr->TransName);
424     strcat (hostname, "/");
425     if (addr)
426         strcat (hostname, addr);
427
428     return (hostname);
429 }
430
431 #endif /* ICE_t */
432
433
434 #if defined(WIN32) && defined(TCPCONN) 
435 int
436 TRANS(WSAStartup) (void)
437 {
438     static WSADATA wsadata;
439
440     PRMSG (2,"WSAStartup()\n", 0, 0, 0);
441
442     if (!wsadata.wVersion && WSAStartup(MAKEWORD(2,2), &wsadata))
443         return 1;
444     return 0;
445 }
446 #endif
447
448 #include <ctype.h>
449
450 static int
451 is_numeric (const char *str)
452 {
453     int i;
454
455     for (i = 0; i < (int) strlen (str); i++)
456         if (!isdigit (str[i]))
457             return (0);
458
459     return (1);
460 }
461
462 #ifdef TRANS_SERVER
463 #include <sys/types.h>
464 #include <sys/stat.h>
465 #include <errno.h>
466
467 #if !defined(S_IFLNK) && !defined(S_ISLNK)
468 #undef lstat
469 #define lstat(a,b) stat(a,b)
470 #endif
471
472 #define FAIL_IF_NOMODE  1
473 #define FAIL_IF_NOT_ROOT 2
474 #define WARN_NO_ACCESS 4
475
476 /*
477  * We make the assumption that when the 'sticky' (t) bit is requested
478  * it's not save if the directory has non-root ownership or the sticky
479  * bit cannot be set and fail.
480  */
481 static int 
482 trans_mkdir(const char *path, int mode)
483 {
484     struct stat buf;
485
486     if (lstat(path, &buf) != 0) {
487         if (errno != ENOENT) {
488             PRMSG(1, "mkdir: ERROR: (l)stat failed for %s (%d)\n",
489                   path, errno, 0);
490             return -1;
491         }
492         /* Dir doesn't exist. Try to create it */
493
494 #if !defined(WIN32) && !defined(__CYGWIN__)
495         /*
496          * 'sticky' bit requested: assume application makes
497          * certain security implications. If effective user ID
498          * is != 0: fail as we may not be able to meet them.
499          */
500         if (geteuid() != 0) {
501             if (mode & 01000) {
502                 PRMSG(1, "mkdir: ERROR: euid != 0,"
503                       "directory %s will not be created.\n",
504                       path, 0, 0);          
505 #ifdef FAIL_HARD
506                 return -1;
507 #endif
508             } else {
509                 PRMSG(1, "mkdir: Cannot create %s with root ownership\n",
510                       path, 0, 0);
511             }
512         }
513 #endif
514
515 #ifndef WIN32
516         if (mkdir(path, mode) == 0) {
517             if (chmod(path, mode)) {
518                 PRMSG(1, "mkdir: ERROR: Mode of %s should be set to %04o\n",
519                       path, mode, 0);
520 #ifdef FAIL_HARD
521                 return -1;
522 #endif
523             }
524 #else
525         if (mkdir(path) == 0) {
526 #endif
527         } else {
528             PRMSG(1, "mkdir: ERROR: Cannot create %s\n",
529                   path, 0, 0);
530             return -1;
531         }
532
533         return 0;
534         
535     } else {
536         if (S_ISDIR(buf.st_mode)) {
537             int updateOwner = 0;
538             int updateMode = 0;
539             int updatedOwner = 0;
540             int updatedMode = 0;
541             int status = 0;
542             /* Check if the directory's ownership is OK. */
543             if (buf.st_uid != 0)
544                 updateOwner = 1;
545
546             /*
547              * Check if the directory's mode is OK.  An exact match isn't
548              * required, just a mode that isn't more permissive than the
549              * one requested.
550              */
551             if ((~mode) & 0077 & buf.st_mode)
552                 updateMode = 1;
553             
554             /*
555              * If the directory is not writeable not everybody may
556              * be able to create sockets. Therefore warn if mode
557              * cannot be fixed.
558              */
559             if ((~buf.st_mode) & 0022 & mode) {
560                 updateMode = 1;
561                 status |= WARN_NO_ACCESS;
562             }
563             
564             /*
565              * If 'sticky' bit is requested fail if owner isn't root
566              * as we assume the caller makes certain security implications
567              */
568             if (mode & 01000) {
569                 status |= FAIL_IF_NOT_ROOT;
570                 if (!(buf.st_mode & 01000)) {
571                     status |= FAIL_IF_NOMODE;
572                     updateMode = 1;
573                 }
574             }
575             
576 #ifdef HAS_FCHOWN
577             /*
578              * If fchown(2) and fchmod(2) are available, try to correct the
579              * directory's owner and mode.  Otherwise it isn't safe to attempt
580              * to do this.
581              */
582             if (updateMode || updateOwner) {
583                 int fd = -1;
584                 struct stat fbuf;
585                 if ((fd = open(path, O_RDONLY)) != -1) {
586                     if (fstat(fd, &fbuf) == -1) {
587                         PRMSG(1, "mkdir: ERROR: fstat failed for %s (%d)\n",
588                               path, errno, 0);
589                         return -1;
590                     }
591                     /*
592                      * Verify that we've opened the same directory as was
593                      * checked above.
594                      */
595                     if (!S_ISDIR(fbuf.st_mode) ||
596                         buf.st_dev != fbuf.st_dev ||
597                         buf.st_ino != fbuf.st_ino) {
598                         PRMSG(1, "mkdir: ERROR: inode for %s changed\n",
599                               path, 0, 0);
600                         return -1;
601                     }
602                     if (updateOwner && fchown(fd, 0, 0) == 0)
603                         updatedOwner = 1;
604                     if (updateMode && fchmod(fd, mode) == 0)
605                         updatedMode = 1;
606                     close(fd);
607                 }
608             }
609 #endif
610             
611             if (updateOwner && !updatedOwner) {
612 #ifdef FAIL_HARD
613                 if (status & FAIL_IF_NOT_ROOT) {
614                     PRMSG(1, "mkdir: ERROR: Owner of %s must be set to root\n",
615                           path, 0, 0);
616                     return -1;
617                 }
618 #endif
619 #if !defined(__APPLE_CC__) && !defined(__CYGWIN__)
620                 PRMSG(1, "mkdir: Owner of %s should be set to root\n",
621                       path, 0, 0);
622 #endif
623             }
624             
625             if (updateMode && !updatedMode) {
626 #ifdef FAIL_HARD
627                 if (status & FAIL_IF_NOMODE) {
628                     PRMSG(1, "mkdir: ERROR: Mode of %s must be set to %04o\n",
629                           path, mode, 0);
630                     return -1;
631                 }
632 #endif
633                 PRMSG(1, "mkdir: Mode of %s should be set to %04o\n",
634                       path, mode, 0);
635                 if (status & WARN_NO_ACCESS) {
636                     PRMSG(1, "mkdir: this may cause subsequent errors\n",
637                           0, 0, 0);
638                 }
639             }
640             return 0;
641         }
642         return -1;
643     }
644
645     /* In all other cases, fail */
646     return -1;
647 }
648
649 #endif /* TRANS_SERVER */