upload tizen2.0 source
[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,%p)\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);
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                 free (*addrp);
201                 *addrp = NULL;
202             }
203             if (!*addrp)
204                 *addrp = malloc (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                 free (*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     const 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 = malloc (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 = malloc (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 _X_UNUSED)
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 = malloc (strlen (ciptr->transptr->TransName) + strlen (addr) + 2);
422     strcpy (hostname, ciptr->transptr->TransName);
423     strcat (hostname, "/");
424     if (addr)
425         strcat (hostname, addr);
426
427     return (hostname);
428 }
429
430 #endif /* ICE_t */
431
432
433 #if defined(WIN32) && defined(TCPCONN)
434 int
435 TRANS(WSAStartup) (void)
436 {
437     static WSADATA wsadata;
438
439     prmsg (2,"WSAStartup()\n");
440
441     if (!wsadata.wVersion && WSAStartup(MAKEWORD(2,2), &wsadata))
442         return 1;
443     return 0;
444 }
445 #endif
446
447 #include <ctype.h>
448
449 static int
450 is_numeric (const char *str)
451 {
452     int i;
453
454     for (i = 0; i < (int) strlen (str); i++)
455         if (!isdigit (str[i]))
456             return (0);
457
458     return (1);
459 }
460
461 #ifdef TRANS_SERVER
462 #include <sys/types.h>
463 #include <sys/stat.h>
464 #include <errno.h>
465
466 #if !defined(S_IFLNK) && !defined(S_ISLNK)
467 #undef lstat
468 #define lstat(a,b) stat(a,b)
469 #endif
470
471 #define FAIL_IF_NOMODE  1
472 #define FAIL_IF_NOT_ROOT 2
473 #define WARN_NO_ACCESS 4
474
475 /*
476  * We make the assumption that when the 'sticky' (t) bit is requested
477  * it's not save if the directory has non-root ownership or the sticky
478  * bit cannot be set and fail.
479  */
480 static int
481 trans_mkdir(const char *path, int mode)
482 {
483     struct stat buf;
484
485     if (lstat(path, &buf) != 0) {
486         if (errno != ENOENT) {
487             prmsg(1, "mkdir: ERROR: (l)stat failed for %s (%d)\n",
488                   path, errno);
489             return -1;
490         }
491         /* Dir doesn't exist. Try to create it */
492
493 #if !defined(WIN32) && !defined(__CYGWIN__)
494         /*
495          * 'sticky' bit requested: assume application makes
496          * certain security implications. If effective user ID
497          * is != 0: fail as we may not be able to meet them.
498          */
499         if (geteuid() != 0) {
500             if (mode & 01000) {
501                 prmsg(1, "mkdir: ERROR: euid != 0,"
502                       "directory %s will not be created.\n",
503                       path);
504 #ifdef FAIL_HARD
505                 return -1;
506 #endif
507             } else {
508                 prmsg(1, "mkdir: Cannot create %s with root ownership\n",
509                       path);
510             }
511         }
512 #endif
513
514 #ifndef WIN32
515         if (mkdir(path, mode) == 0) {
516             if (chmod(path, mode)) {
517                 prmsg(1, "mkdir: ERROR: Mode of %s should be set to %04o\n",
518                       path, mode);
519 #ifdef FAIL_HARD
520                 return -1;
521 #endif
522             }
523 #else
524         if (mkdir(path) == 0) {
525 #endif
526         } else {
527             prmsg(1, "mkdir: ERROR: Cannot create %s\n",
528                   path);
529             return -1;
530         }
531
532         return 0;
533
534     } else {
535         if (S_ISDIR(buf.st_mode)) {
536             int updateOwner = 0;
537             int updateMode = 0;
538             int updatedOwner = 0;
539             int updatedMode = 0;
540             int status = 0;
541             /* Check if the directory's ownership is OK. */
542             if (buf.st_uid != 0)
543                 updateOwner = 1;
544
545             /*
546              * Check if the directory's mode is OK.  An exact match isn't
547              * required, just a mode that isn't more permissive than the
548              * one requested.
549              */
550             if ((~mode) & 0077 & buf.st_mode)
551                 updateMode = 1;
552
553             /*
554              * If the directory is not writeable not everybody may
555              * be able to create sockets. Therefore warn if mode
556              * cannot be fixed.
557              */
558             if ((~buf.st_mode) & 0022 & mode) {
559                 updateMode = 1;
560                 status |= WARN_NO_ACCESS;
561             }
562
563             /*
564              * If 'sticky' bit is requested fail if owner isn't root
565              * as we assume the caller makes certain security implications
566              */
567             if (mode & 01000) {
568                 status |= FAIL_IF_NOT_ROOT;
569                 if (!(buf.st_mode & 01000)) {
570                     status |= FAIL_IF_NOMODE;
571                     updateMode = 1;
572                 }
573             }
574
575 #ifdef HAS_FCHOWN
576             /*
577              * If fchown(2) and fchmod(2) are available, try to correct the
578              * directory's owner and mode.  Otherwise it isn't safe to attempt
579              * to do this.
580              */
581             if (updateMode || updateOwner) {
582                 int fd = -1;
583                 struct stat fbuf;
584                 if ((fd = open(path, O_RDONLY)) != -1) {
585                     if (fstat(fd, &fbuf) == -1) {
586                         prmsg(1, "mkdir: ERROR: fstat failed for %s (%d)\n",
587                               path, errno);
588                         close(fd);
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);
600                         close(fd);
601                         return -1;
602                     }
603                     if (updateOwner && fchown(fd, 0, 0) == 0)
604                         updatedOwner = 1;
605                     if (updateMode && fchmod(fd, mode) == 0)
606                         updatedMode = 1;
607                     close(fd);
608                 }
609             }
610 #endif
611
612             if (updateOwner && !updatedOwner) {
613 #ifdef FAIL_HARD
614                 if (status & FAIL_IF_NOT_ROOT) {
615                     prmsg(1, "mkdir: ERROR: Owner of %s must be set to root\n",
616                           path);
617                     return -1;
618                 }
619 #endif
620 #if !defined(__APPLE_CC__) && !defined(__CYGWIN__)
621                 prmsg(1, "mkdir: Owner of %s should be set to root\n",
622                       path);
623 #endif
624             }
625
626             if (updateMode && !updatedMode) {
627 #ifdef FAIL_HARD
628                 if (status & FAIL_IF_NOMODE) {
629                     prmsg(1, "mkdir: ERROR: Mode of %s must be set to %04o\n",
630                           path, mode);
631                     return -1;
632                 }
633 #endif
634                 prmsg(1, "mkdir: Mode of %s should be set to %04o\n",
635                       path, mode);
636                 if (status & WARN_NO_ACCESS) {
637                     prmsg(1, "mkdir: this may cause subsequent errors\n");
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 */