not quite so much needs to be delayed to the init() function
[personal-kdebase.git] / workspace / kdm / backend / auth.c
bloba7bb55bd6b94c72084bda43b396f4d052de7eab2
1 /*
3 Copyright 1988, 1998 The Open Group
4 Copyright 2000-2004 Oswald Buddenhagen <ossi@kde.org>
6 Permission to use, copy, modify, distribute, and sell this software and its
7 documentation for any purpose is hereby granted without fee, provided that
8 the above copyright notice appear in all copies and that both that
9 copyright notice and this permission notice appear in supporting
10 documentation.
12 The above copyright notice and this permission notice shall be included
13 in all copies or substantial portions of the Software.
15 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
16 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18 IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
19 OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
20 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
21 OTHER DEALINGS IN THE SOFTWARE.
23 Except as contained in this notice, the name of a copyright holder shall
24 not be used in advertising or otherwise to promote the sale, use or
25 other dealings in this Software without prior written authorization
26 from the copyright holder.
31 * xdm - display manager daemon
32 * Author: Keith Packard, MIT X Consortium
34 * maintain the authorization generation daemon
37 #include "dm.h"
38 #include "dm_auth.h"
39 #include "dm_error.h"
41 #include <sys/stat.h>
42 #include <fcntl.h>
43 #include <stdlib.h>
44 #ifdef __OpenBSD__
45 #include <pwd.h>
46 #endif
48 #include <sys/ioctl.h>
50 #include "dm_socket.h"
51 #ifdef DNETCONN
52 # include <netdnet/dnetdb.h>
53 #endif
55 #if (defined(_POSIX_SOURCE) && !defined(_AIX) && !defined(__QNX__)) || defined(__hpux) || defined(__svr4__) /* XXX */
56 # define NEED_UTSNAME
57 # include <sys/utsname.h>
58 #endif
60 #ifdef __GNU__
61 # include <netdb.h>
62 # undef SIOCGIFCONF
63 #else /* __GNU__ */
64 # include <net/if.h>
65 # ifdef __svr4__
66 # include <netdb.h>
67 # include <sys/sockio.h>
68 # include <sys/stropts.h>
69 # endif
70 # ifdef __EMX__
71 # define link rename
72 # define chown(a,b,c)
73 # include <io.h>
74 # endif
75 #endif /* __GNU__ */
77 #include <X11/Xlib.h>
79 struct AuthProtocol {
80 unsigned short name_length;
81 const char *name;
82 void (*InitAuth)( unsigned short len, const char *name );
83 Xauth *(*GetAuth)( unsigned short len, const char *name );
84 #ifdef XDMCP
85 void (*GetXdmcpAuth)( struct protoDisplay *pdpy,
86 unsigned short authorizationNameLen,
87 const char *authorizationName );
88 #endif
89 int inited;
92 #ifdef XDMCP
93 # define xdmcpauth(arg) , arg
94 #else
95 # define xdmcpauth(arg)
96 #endif
98 static struct AuthProtocol authProtocols[] = {
99 { (unsigned short)18, "MIT-MAGIC-COOKIE-1",
100 mitInitAuth, mitGetAuth xdmcpauth(NULL), False
102 #ifdef HASXDMAUTH
103 { (unsigned short)19, "XDM-AUTHORIZATION-1",
104 xdmInitAuth, xdmGetAuth xdmcpauth(xdmGetXdmcpAuth), False
106 #endif
107 #ifdef SECURE_RPC
108 { (unsigned short)9, "SUN-DES-1",
109 secureRPCInitAuth, secureRPCGetAuth xdmcpauth(NULL), False
111 #endif
112 #ifdef K5AUTH
113 { (unsigned short)14, "MIT-KERBEROS-5",
114 krb5InitAuth, krb5GetAuth xdmcpauth(NULL), False
116 #endif
119 static struct AuthProtocol *
120 findProtocol( unsigned short name_length, const char *name )
122 unsigned i;
124 for (i = 0; i < as(authProtocols); i++)
125 if (authProtocols[i].name_length == name_length &&
126 memcmp( authProtocols[i].name, name, name_length ) == 0)
128 return &authProtocols[i];
130 return (struct AuthProtocol *)0;
134 validAuthorization( unsigned short name_length, const char *name )
136 if (findProtocol( name_length, name ))
137 return True;
138 return False;
141 static Xauth *
142 generateAuthorization( unsigned short name_length, const char *name )
144 struct AuthProtocol *a;
145 Xauth *auth = 0;
147 debug( "generateAuthorization %s\n", name );
148 if ((a = findProtocol( name_length, name ))) {
149 if (!a->inited) {
150 (*a->InitAuth)( name_length, name );
151 a->inited = True;
153 auth = (*a->GetAuth)( name_length, name );
154 if (auth) {
155 debug( "got %p (%d %.*s) %02[*hhx\n", auth,
156 auth->name_length, auth->name_length, auth->name,
157 auth->data_length, auth->data );
158 } else
159 debug( "got (null)\n" );
160 } else
161 debug( "unknown authorization %s\n", name );
162 return auth;
165 #ifdef XDMCP
167 void
168 setProtoDisplayAuthorization( struct protoDisplay *pdpy,
169 unsigned short authorizationNameLen,
170 const char *authorizationName )
172 struct AuthProtocol *a;
173 Xauth *auth;
175 a = findProtocol( authorizationNameLen, authorizationName );
176 pdpy->xdmcpAuthorization = pdpy->fileAuthorization = 0;
177 if (a) {
178 if (!a->inited) {
179 (*a->InitAuth)( authorizationNameLen, authorizationName );
180 a->inited = True;
182 if (a->GetXdmcpAuth) {
183 (*a->GetXdmcpAuth)( pdpy, authorizationNameLen, authorizationName );
184 auth = pdpy->xdmcpAuthorization;
185 } else {
186 auth = (*a->GetAuth)( authorizationNameLen, authorizationName );
187 pdpy->fileAuthorization = auth;
188 pdpy->xdmcpAuthorization = 0;
190 if (auth)
191 debug( "got %p (%d %.*s)\n", auth,
192 auth->name_length, auth->name_length, auth->name );
193 else
194 debug( "got (null)\n" );
198 #endif /* XDMCP */
200 void
201 cleanUpFileName( const char *src, char *dst, int len )
203 while (*src) {
204 if (--len <= 0)
205 break;
206 switch (*src & 0x7f) {
207 case '/':
208 *dst++ = '_';
209 break;
210 case '-':
211 *dst++ = '.';
212 break;
213 default:
214 *dst++ = (*src & 0x7f);
216 ++src;
218 *dst = '\0';
222 static FILE *
223 fdOpenW( int fd )
225 FILE *f;
227 if (fd >= 0) {
228 if ((f = fdopen( fd, "w" )))
229 return f;
230 close( fd );
232 return 0;
236 #define NAMELEN 255
238 static FILE *
239 makeServerAuthFile( struct display *d )
241 FILE *f;
242 #ifndef HAVE_MKSTEMP
243 int r;
244 #endif
245 char cleanname[NAMELEN], nambuf[NAMELEN+128];
248 * Some paranoid, but still not sufficient (DoS was still possible)
249 * checks used to be here. I removed all this stuff because
250 * a) authDir is supposed to be /var/run/xauth (=safe) or similar and
251 * b) even if it's not (say, /tmp), we create files safely (hopefully).
253 if (mkdir( authDir, 0755 ) < 0 && errno != EEXIST)
254 return 0;
255 cleanUpFileName( d->name, cleanname, NAMELEN - 8 );
256 #ifdef HAVE_MKSTEMP
257 sprintf( nambuf, "%s/A%s-XXXXXX", authDir, cleanname );
258 if ((f = fdOpenW( mkstemp( nambuf ) ))) {
259 strDup( &d->authFile, nambuf );
260 return f;
262 #else
263 for (r = 0; r < 100; r++) {
264 sprintf( nambuf, "%s/A%s-XXXXXX", authDir, cleanname );
265 (void)mktemp( nambuf );
266 if ((f = fdOpenW( open( nambuf, O_WRONLY | O_CREAT | O_EXCL, 0600 ) ))) {
267 strDup( &d->authFile, nambuf );
268 return f;
271 #endif
272 return 0;
276 saveServerAuthorizations( struct display *d, Xauth **auths, int count )
278 FILE *auth_file;
279 int i;
280 #ifdef __OpenBSD__
281 struct passwd *x11;
282 #endif
284 if (!d->authFile && d->clientAuthFile && *d->clientAuthFile)
285 strDup( &d->authFile, d->clientAuthFile );
286 if (d->authFile) {
287 if (!(auth_file = fdOpenW( creat( d->authFile, 0600 ) ))) {
288 logError( "Cannot open X server authorization file %s\n", d->authFile );
289 free( d->authFile );
290 d->authFile = NULL;
291 return False;
293 } else {
294 if (!(auth_file = makeServerAuthFile( d ))) {
295 logError( "Cannot create X server authorization file\n" );
296 return False;
299 #ifdef __OpenBSD__
300 /* Give read capability to group _x11 */
301 if (!(x11 = getpwnam( "_x11" )))
302 logError( "Cannot find _x11 user\n" );
303 else
304 fchown( fileno( auth_file ), x11->pw_uid, x11->pw_gid );
305 endpwent();
306 #endif
307 debug( "file: %s auth: %p\n", d->authFile, auths );
308 for (i = 0; i < count; i++) {
310 * User-based auths may not have data until
311 * a user logs in. In which case don't write
312 * to the auth file so xrdb and setup programs don't fail.
314 if (auths[i]->data_length > 0)
315 if (!XauWriteAuth( auth_file, auths[i] ) ||
316 fflush( auth_file ) == EOF)
318 fclose( auth_file );
319 logError( "Cannot write X server authorization file %s\n",
320 d->authFile );
321 free( d->authFile );
322 d->authFile = NULL;
323 return False;
326 fclose( auth_file );
327 return True;
330 void
331 setLocalAuthorization( struct display *d )
333 Xauth *auth, **auths;
334 int i, j;
336 if (d->authorizations)
338 for (i = 0; i < d->authNum; i++)
339 XauDisposeAuth( d->authorizations[i] );
340 free( (char *)d->authorizations );
341 d->authorizations = (Xauth **)NULL;
342 d->authNum = 0;
344 debug( "setLocalAuthorization %s, auths %[s\n", d->name, d->authNames );
345 if (!d->authNames)
346 return;
347 for (i = 0; d->authNames[i]; i++)
349 d->authNameNum = i;
350 if (d->authNameLens)
351 free( (char *)d->authNameLens );
352 d->authNameLens = (unsigned short *)Malloc( d->authNameNum * sizeof(unsigned short) );
353 if (!d->authNameLens)
354 return;
355 for (i = 0; i < d->authNameNum; i++)
356 d->authNameLens[i] = strlen( d->authNames[i] );
357 auths = (Xauth **)Malloc( d->authNameNum * sizeof(Xauth *) );
358 if (!auths)
359 return;
360 j = 0;
361 for (i = 0; i < d->authNameNum; i++) {
362 auth = generateAuthorization( d->authNameLens[i], d->authNames[i] );
363 if (auth)
364 auths[j++] = auth;
366 if (saveServerAuthorizations( d, auths, j )) {
367 d->authorizations = auths;
368 d->authNum = j;
369 } else {
370 for (i = 0; i < j; i++)
371 XauDisposeAuth( auths[i] );
372 free( (char *)auths );
377 * Set the authorization to use for xdm's initial connection
378 * to the X server. Cannot use user-based authorizations
379 * because no one has logged in yet, so we don't have any
380 * user credentials.
381 * Well, actually we could use SUN-DES-1 because we tell the server
382 * to allow root in. This is bogus and should be fixed.
384 void
385 setAuthorization( struct display *d )
387 register Xauth **auth = d->authorizations;
388 int i;
390 for (i = 0; i < d->authNum; i++) {
391 if (auth[i]->name_length == 9 &&
392 memcmp( auth[i]->name, "SUN-DES-1", 9 ) == 0)
393 continue;
394 if (auth[i]->name_length == 14 &&
395 memcmp( auth[i]->name, "MIT-KERBEROS-5", 14 ) == 0)
396 continue;
397 XSetAuthorization( auth[i]->name, (int)auth[i]->name_length,
398 auth[i]->data, (int)auth[i]->data_length );
402 static int
403 openFiles( const char *name, char *new_name, FILE **oldp, FILE **newp )
405 strcat( strcpy( new_name, name ), "-n" );
406 if (!(*newp =
407 fdOpenW( creat( new_name, 0600 ) ))) {
408 debug( "cannot open new file %s\n", new_name );
409 return False;
411 *oldp = fopen( name, "r" );
412 debug( "opens succeeded %s %s\n", name, new_name );
413 return True;
416 struct addrList {
417 struct addrList *next;
418 unsigned short family, address_length, number_length;
419 char data[1];
422 static struct addrList *addrs;
424 static void
425 initAddrs( void )
427 addrs = 0;
430 static void
431 doneAddrs( void )
433 struct addrList *a, *n;
434 for (a = addrs; a; a = n) {
435 n = a->next;
436 free( a );
440 static void
441 saveEntry( Xauth *auth )
443 struct addrList *new;
445 if (!(new = Malloc( offsetof(struct addrList, data) +
446 auth->address_length + auth->number_length )))
447 return;
448 new->address_length = auth->address_length;
449 new->number_length = auth->number_length;
450 memcpy( new->data, auth->address, (int)auth->address_length );
451 memcpy( new->data + (int)auth->address_length,
452 auth->number, (int)auth->number_length );
453 new->family = auth->family;
454 new->next = addrs;
455 addrs = new;
458 static int
459 checkEntry( Xauth *auth )
461 struct addrList *a;
463 for (a = addrs; a; a = a->next)
464 if (a->family == auth->family &&
465 a->address_length == auth->address_length &&
466 !memcmp( a->data, auth->address, auth->address_length ) &&
467 a->number_length == auth->number_length &&
468 !memcmp( a->data + a->address_length,
469 auth->number, auth->number_length ))
470 return True;
471 return False;
474 static void
475 writeAuth( FILE *file, Xauth *auth, int *ok )
477 if (debugLevel & DEBUG_AUTH) /* normally too verbose */
478 debug( "writeAuth: doWrite = %d\n"
479 "family: %d\n"
480 "addr: %02[*:hhx\n"
481 "number: %02[*:hhx\n"
482 "name: %02[*:hhx\n"
483 "data: %02[*:hhx\n",
484 ok, auth->family,
485 auth->address_length, auth->address,
486 auth->number_length, auth->number,
487 auth->name_length, auth->name,
488 auth->data_length, auth->data );
489 if (ok && !XauWriteAuth( file, auth ))
490 *ok = False;
493 static void
494 writeAddr( int family, int addr_length, CARD8 *addr,
495 FILE *file, Xauth *auth, int *ok )
497 auth->family = (unsigned short)family;
498 auth->address_length = addr_length;
499 auth->address = (char *)addr;
500 debug( "writeAddr: writing and saving an entry\n" );
501 writeAuth( file, auth, ok );
502 if (!checkEntry( auth ))
503 saveEntry( auth );
506 static void
507 defineLocal( FILE *file, Xauth *auth, int *ok )
509 #if !defined(NEED_UTSNAME) || defined(__hpux)
510 char displayname[100];
511 #endif
512 #ifdef NEED_UTSNAME
513 struct utsname name;
514 #endif
516 /* stolen from xinit.c */
518 /* Make sure this produces the same string as _XGetHostname in lib/X/XlibInt.c.
519 * Otherwise, Xau will not be able to find your cookies in the Xauthority file.
521 * Note: POSIX says that the ``nodename'' member of utsname does _not_ have
522 * to have sufficient information for interfacing to the network,
523 * and so, you may be better off using gethostname (if it exists).
526 #ifdef NEED_UTSNAME
528 /* hpux:
529 * Why not use gethostname()? Well, at least on my system, I've had to
530 * make an ugly kernel patch to get a name longer than 8 characters, and
531 * uname() lets me access to the whole string (it smashes release, you
532 * see), whereas gethostname() kindly truncates it for me.
534 uname( &name );
535 writeAddr( FamilyLocal, strlen( name.nodename ), (CARD8 *)name.nodename,
536 file, auth, ok );
537 #endif
539 #if !defined(NEED_UTSNAME) || defined(__hpux)
540 /* _AIX:
541 * In _AIX, _POSIX_SOURCE is defined, but uname gives only first
542 * field of hostname. Thus, we use gethostname instead.
546 * For HP-UX, HP's Xlib expects a fully-qualified domain name, which
547 * is achieved by using gethostname(). For compatibility, we must
548 * also still create the entry using uname() above.
550 displayname[0] = 0;
551 if (!gethostname( displayname, sizeof(displayname) ))
552 displayname[sizeof(displayname) - 1] = 0;
554 # ifdef NEED_UTSNAME
556 * If gethostname and uname both returned the same name,
557 * do not write a duplicate entry.
559 if (strcmp( displayname, name.nodename ))
560 # endif
561 writeAddr( FamilyLocal, strlen( displayname ), (CARD8 *)displayname,
562 file, auth, ok );
563 #endif
566 #ifdef SYSV_SIOCGIFCONF
568 /* Deal with different SIOCGIFCONF ioctl semantics on SYSV, SVR4 */
571 ifioctl( int fd, int cmd, char *arg )
573 struct strioctl ioc;
574 int ret;
576 bzero( (char *)&ioc, sizeof(ioc) );
577 ioc.ic_cmd = cmd;
578 ioc.ic_timout = 0;
579 if (cmd == SIOCGIFCONF) {
580 ioc.ic_len = ((struct ifconf *)arg)->ifc_len;
581 ioc.ic_dp = ((struct ifconf *)arg)->ifc_buf;
582 } else {
583 ioc.ic_len = sizeof(struct ifreq);
584 ioc.ic_dp = arg;
586 ret = ioctl( fd, I_STR, (char *)&ioc );
587 if (ret >= 0 && cmd == SIOCGIFCONF)
588 ((struct ifconf *)arg)->ifc_len = ioc.ic_len;
589 return (ret);
592 #endif /* SYSV_SIOCGIFCONF */
594 #ifdef HAVE_GETIFADDRS
595 # include <ifaddrs.h>
597 static void
598 defineSelf( FILE *file, Xauth *auth, int *ok )
600 struct ifaddrs *ifap, *ifr;
601 CARD8 *addr;
602 int family, len;
604 if (getifaddrs( &ifap ) < 0)
605 return;
606 for (ifr = ifap; ifr; ifr = ifr->ifa_next) {
607 if (!ifr->ifa_addr)
608 continue;
609 family = convertAddr( (char *)(ifr->ifa_addr), &len, &addr );
610 if (family == -1 || family == FamilyLocal)
611 continue;
613 * don't write out 'localhost' entries, as
614 * they may conflict with other local entries.
615 * defineLocal will always be called to add
616 * the local entry anyway, so this one can
617 * be tossed.
619 if (family == FamilyInternet &&
620 addr[0] == 127 && addr[1] == 0 && addr[2] == 0 && addr[3] == 1)
622 debug( "Skipping localhost address\n" );
623 continue;
625 # if defined(IPv6) && defined(AF_INET6)
626 if (family == FamilyInternet6) {
627 if (IN6_IS_ADDR_LOOPBACK( ((struct in6_addr *)addr) )) {
628 debug( "Skipping IPv6 localhost address\n" );
629 continue;
631 /* Also skip XDM-AUTHORIZATION-1 */
632 if (auth->name_length == 19 &&
633 !memcmp( auth->name, "XDM-AUTHORIZATION-1", 19 )) {
634 debug( "Skipping IPv6 XDM-AUTHORIZATION-1\n" );
635 continue;
638 # endif
639 writeAddr( family, len, addr, file, auth, ok );
641 freeifaddrs( ifap );
643 #else /* GETIFADDRS */
645 #if defined(STREAMSCONN) && !defined(SYSV_SIOCGIFCONF) && !defined(WINTCP)
647 #include <tiuser.h>
649 /* Define this host for access control. Find all the hosts the OS knows about
650 * for this fd and add them to the selfhosts list.
651 * TLI version, written without sufficient documentation.
653 static void
654 defineSelf( int fd, FILE *file, Xauth *auth, int *ok )
656 struct netbuf netb;
657 char addrret[1024]; /* easier than t_alloc */
659 netb.maxlen = sizeof(addrret);
660 netb.buf = addrret;
661 if (t_getname( fd, &netb, LOCALNAME ) == -1)
662 t_error( "t_getname" );
663 /* what a kludge */
664 writeAddr( FamilyInternet, 4, (CARD8 *)netb.buf+4, file, auth, ok );
667 #else
669 #ifdef WINTCP /* NCR with Wollongong TCP */
671 #include <stropts.h>
672 #include <tiuser.h>
674 #include <sys/stream.h>
675 #include <net/if.h>
676 #include <netinet/ip.h>
677 #include <netinet/ip_var.h>
678 #include <netinet/in.h>
679 #include <netinet/in_var.h>
681 static void
682 defineSelf( int fd, FILE *file, Xauth *auth, int *ok )
685 * The Wollongong drivers used by NCR SVR4/MP-RAS don't understand the
686 * socket IO calls that most other drivers seem to like. Because of
687 * this, this routine must be special cased for NCR. Eventually,
688 * this will be cleared up.
691 struct ipb ifnet;
692 struct in_ifaddr ifaddr;
693 struct strioctl str;
694 int len, ipfd;
696 if ((ipfd = open( "/dev/ip", O_RDWR, 0 )) < 0) {
697 logError( "Trouble getting interface configuration\n" );
698 return;
701 /* Indicate that we want to start at the beginning */
702 ifnet.ib_next = (struct ipb *)1;
704 while (ifnet.ib_next) {
705 str.ic_cmd = IPIOC_GETIPB;
706 str.ic_timout = 0;
707 str.ic_len = sizeof(struct ipb);
708 str.ic_dp = (char *)&ifnet;
710 if (ioctl( ipfd, (int)I_STR, (char *)&str ) < 0) {
711 close( ipfd );
712 logError( "Trouble getting interface configuration\n" );
713 return;
716 ifaddr.ia_next = (struct in_ifaddr *)ifnet.if_addrlist;
717 str.ic_cmd = IPIOC_GETINADDR;
718 str.ic_timout = 0;
719 str.ic_len = sizeof(struct in_ifaddr);
720 str.ic_dp = (char *)&ifaddr;
722 if (ioctl( ipfd, (int)I_STR, (char *)&str ) < 0) {
723 close( ipfd );
724 logError( "Trouble getting interface configuration\n" );
725 return;
729 * Ignore the 127.0.0.1 entry.
731 if (IA_SIN( &ifaddr )->sin_addr.s_addr == htonl( 0x7f000001 ))
732 continue;
734 writeAddr( FamilyInternet, 4, (CARD8 *)&(IA_SIN( &ifaddr )->sin_addr),
735 file, auth, ok );
738 close( ipfd );
741 #else /* WINTCP */
743 /* Solaris provides an extended interface SIOCGLIFCONF. Other systems
744 * may have this as well, but the code has only been tested on Solaris
745 * so far, so we only enable it there. Other platforms may be added as
746 * needed.
748 * Test for Solaris commented out -- TSI @ UQV 2003.06.13
750 #ifdef SIOCGLIFCONF
751 /* #if defined(sun) */
752 # define USE_SIOCGLIFCONF
753 /* #endif */
754 #endif
756 #if defined(SIOCGIFCONF) || defined (USE_SIOCGLIFCONF)
758 #if !defined(SYSV_SIOCGIFCONF) || defined(USE_SIOCGLIFCONF)
759 # define ifioctl ioctl
760 #endif
762 #ifdef USE_SIOCGLIFCONF
763 # define ifr_type struct lifreq
764 #else
765 # define ifr_type struct ifreq
766 #endif
768 /* Handle variable length ifreq in BNR2 and later */
769 #ifdef VARIABLE_IFREQ
770 # define ifr_size(p) (sizeof(struct ifreq) + \
771 (p->ifr_addr.sa_len > sizeof(p->ifr_addr) ? \
772 p->ifr_addr.sa_len - sizeof(p->ifr_addr) : 0))
773 #else
774 # define ifr_size(p) (sizeof(ifr_type))
775 #endif
777 #ifdef USE_SIOCGLIFCONF
778 # define IFC_IOCTL_REQ SIOCGLIFCONF
779 # define IFC_REQ(ifc) ifc.lifc_req
780 # define IFC_LEN(ifc) ifc.lifc_len
781 # define IFR_ADDR(ifr) ifr->lifr_addr
782 # define IFR_NAME(ifr) ifr->lifr_name
783 #else
784 # define IFC_IOCTL_REQ SIOCGIFCONF
785 # define IFC_REQ(ifc) ifc.ifc_req
786 # define IFC_LEN(ifc) ifc.ifc_len
787 # define IFR_ADDR(ifr) ifr->ifr_addr
788 # define IFR_NAME(ifr) ifr->ifr_name
789 #endif
791 /* Define this host for access control. Find all the hosts the OS knows about
792 * for this fd and add them to the selfhosts list.
794 static void
795 defineSelf( int fd, FILE *file, Xauth *auth, int *ok )
797 char buf[2048], *cp, *cplim;
798 int len;
799 CARD8 *addr;
800 int family;
801 ifr_type *ifr;
802 #ifdef USE_SIOCGLIFCONF
803 int n;
804 void * bufptr = buf;
805 size_t buflen = sizeof(buf);
806 struct lifconf ifc;
807 # ifdef SIOCGLIFNUM
808 struct lifnum ifn;
809 # endif
810 #else
811 struct ifconf ifc;
812 #endif
814 #if defined(SIOCGLIFNUM) && defined(SIOCGLIFCONF)
815 ifn.lifn_family = AF_UNSPEC;
816 ifn.lifn_flags = 0;
817 if (ioctl( fd, (int)SIOCGLIFNUM, (char *)&ifn ) < 0)
818 logError( "Failed getting interface count\n" );
819 if (buflen < (ifn.lifn_count * sizeof(struct lifreq))) {
820 buflen = ifn.lifn_count * sizeof(struct lifreq);
821 bufptr = Malloc( buflen );
823 #endif
825 #ifdef USE_SIOCGLIFCONF
826 ifc.lifc_family = AF_UNSPEC;
827 ifc.lifc_flags = 0;
828 ifc.lifc_len = buflen;
829 ifc.lifc_buf = bufptr;
830 #else
831 ifc.ifc_len = sizeof(buf);
832 ifc.ifc_buf = buf;
833 #endif
834 if (ifioctl (fd, IFC_IOCTL_REQ, (char *)&ifc) < 0) {
835 logError( "Trouble getting network interface configuration\n" );
836 #if defined(SIOCGLIFNUM) && defined(SIOCGLIFCONF)
837 if (bufptr != buf)
838 free( bufptr );
839 #endif
840 return;
843 cplim = (char *)IFC_REQ( ifc ) + IFC_LEN( ifc );
845 for (cp = (char *)IFC_REQ( ifc ); cp < cplim; cp += ifr_size (ifr)) {
846 ifr = (ifr_type *) cp;
847 #ifdef DNETCONN
849 * this is ugly but SIOCGIFCONF returns decnet addresses in
850 * a different form from other decnet calls
852 if (IFR_ADDR( ifr ).sa_family == AF_DECnet) {
853 len = sizeof(struct dn_naddr);
854 addr = (CARD8 *)IFR_ADDR( ifr ).sa_data;
855 family = FamilyDECnet;
856 } else
857 #endif
859 family = convertAddr( (char *)&IFR_ADDR( ifr ), &len, &addr );
860 if (family < 0)
861 continue;
863 if (len == 0) {
864 debug( "skipping zero length address\n" );
865 continue;
868 * don't write out 'localhost' entries, as
869 * they may conflict with other local entries.
870 * defineLocal will always be called to add
871 * the local entry anyway, so this one can
872 * be tossed.
874 if (family == FamilyInternet &&
875 addr[0] == 127 && addr[1] == 0 &&
876 addr[2] == 0 && addr[3] == 1)
878 debug( "skipping localhost address\n" );
879 continue;
881 #if defined(IPv6) && defined(AF_INET6)
882 if (family == FamilyInternet6) {
883 if (IN6_IS_ADDR_LOOPBACK( ((struct in6_addr *)addr) )) {
884 debug( "Skipping IPv6 localhost address\n" );
885 continue;
887 /* Also skip XDM-AUTHORIZATION-1 */
888 if (auth->name_length == 19 &&
889 !memcmp( auth->name, "XDM-AUTHORIZATION-1", 19 )) {
890 debug( "Skipping IPv6 XDM-AUTHORIZATION-1\n" );
891 continue;
894 #endif
896 debug( "defineSelf: write network address, length %d\n", len );
897 writeAddr( family, len, addr, file, auth, ok );
899 #if defined(SIOCGLIFNUM) && defined(SIOCGLIFCONF)
900 if (bufptr != buf)
901 free( bufptr );
902 #endif
905 #else /* SIOCGIFCONF */
907 /* Define this host for access control. Find all the hosts the OS knows about
908 * for this fd and add them to the selfhosts list.
910 static void
911 defineSelf( int fd, int file, int auth, int *ok )
913 int len;
914 CARD8 *addr;
915 int family;
917 struct utsname name;
918 register struct hostent *hp;
920 union {
921 struct sockaddr sa;
922 struct sockaddr_in in;
923 } saddr;
925 struct sockaddr_in *inetaddr;
927 /* hpux:
928 * Why not use gethostname()? Well, at least on my system, I've had to
929 * make an ugly kernel patch to get a name longer than 8 characters, and
930 * uname() lets me access to the whole string (it smashes release, you
931 * see), whereas gethostname() kindly truncates it for me.
933 uname( &name );
934 if ((hp = gethostbyname( name.nodename ))) {
935 saddr.sa.sa_family = hp->h_addrtype;
936 inetaddr = (struct sockaddr_in *)(&(saddr.sa));
937 memmove( (char *)&(inetaddr->sin_addr), (char *)hp->h_addr,
938 (int)hp->h_length );
939 if ((family = convertAddr( &(saddr.sa), &len, &addr )) >= 0)
940 writeAddr( FamilyInternet, sizeof(inetaddr->sin_addr),
941 (CARD8 *)(&inetaddr->sin_addr), file, auth, ok );
945 #endif /* SIOCGIFCONF else */
946 #endif /* WINTCP else */
947 #endif /* STREAMSCONN && !SYSV_SIOCGIFCONF else */
948 #endif /* HAVE_GETIFADDRS */
950 static void
951 setAuthNumber( Xauth *auth, const char *name )
953 char *colon;
954 char *dot;
956 debug( "setAuthNumber %s\n", name );
957 colon = strrchr( name, ':' );
958 if (colon) {
959 ++colon;
960 dot = strchr( colon, '.' );
961 if (dot)
962 auth->number_length = dot - colon;
963 else
964 auth->number_length = strlen( colon );
965 if (!strNDup( &auth->number, colon, auth->number_length ))
966 auth->number_length = 0;
967 debug( "setAuthNumber: %s\n", auth->number );
971 static void
972 writeLocalAuth( FILE *file, Xauth *auth, const char *name, int *ok )
974 #if defined(STREAMSCONN) || !defined(HAVE_GETIFADDRS)
975 int fd;
976 #endif
978 debug( "writeLocalAuth: %s %.*s\n", name, auth->name_length, auth->name );
979 setAuthNumber( auth, name );
980 # ifdef STREAMSCONN
981 fd = t_open( "/dev/tcp", O_RDWR, 0 );
982 t_bind( fd, NULL, NULL );
983 defineSelf( fd, file, auth, ok );
984 t_unbind( fd );
985 t_close( fd );
986 # elif defined(HAVE_GETIFADDRS)
987 defineSelf( file, auth, ok );
988 # else
989 # ifdef TCPCONN
990 # if defined(IPv6) && defined(AF_INET6)
991 fd = socket( AF_INET6, SOCK_STREAM, 0 );
992 if (fd < 0)
993 # endif
994 fd = socket( AF_INET, SOCK_STREAM, 0 );
995 defineSelf( fd, file, auth, ok );
996 close( fd );
997 # endif
998 # ifdef DNETCONN
999 fd = socket( AF_DECnet, SOCK_STREAM, 0 );
1000 defineSelf( fd, file, auth, ok );
1001 close( fd );
1002 # endif
1003 # endif /* HAVE_GETIFADDRS */
1004 defineLocal( file, auth, ok );
1007 #ifdef XDMCP
1010 * Call convertAddr(), and if it returns an IPv4 localhost, convert it
1011 * to a local display name. Meets the _XTransconvertAddress's localhost
1012 * hack.
1015 static int
1016 convertAuthAddr( char *saddr, int *len, CARD8 **addr )
1018 int ret = convertAddr( saddr, len, addr );
1019 if (ret == FamilyInternet &&
1020 ((struct in_addr *)*addr)->s_addr == htonl( 0x7F000001L ))
1021 ret = FamilyLocal;
1022 return ret;
1025 static void
1026 writeRemoteAuth( FILE *file, Xauth *auth, XdmcpNetaddr peer, int peerlen,
1027 const char *name, int *ok )
1029 int family = FamilyLocal;
1030 CARD8 *addr;
1032 debug( "writeRemoteAuth: %s %.*s\n", name, auth->name_length, auth->name );
1033 if (!peer || peerlen < 2)
1034 return;
1035 setAuthNumber( auth, name );
1036 family = convertAuthAddr( peer, &peerlen, &addr );
1037 debug( "writeRemoteAuth: family %d\n", family );
1038 if (family != FamilyLocal) {
1039 debug( "writeRemoteAuth: %d, %02[*:hhx\n",
1040 family, peerlen, addr );
1041 writeAddr( family, peerlen, addr, file, auth, ok );
1042 } else
1043 writeLocalAuth( file, auth, name, ok );
1046 #endif /* XDMCP */
1048 #define NBSIZE 1024
1050 static void
1051 startUserAuth( char *buf, char *nbuf, FILE **old, FILE **new )
1053 const char *home;
1054 int lockStatus;
1056 initAddrs();
1057 *new = 0;
1058 if ((home = getEnv( userEnviron, "HOME" )) && strlen( home ) < NBSIZE - 12) {
1059 sprintf( buf, "%s/.Xauthority", home );
1060 debug( "XauLockAuth %s\n", buf );
1061 lockStatus = XauLockAuth( buf, 1, 2, 10 );
1062 debug( "lock is %d\n", lockStatus );
1063 if (lockStatus == LOCK_SUCCESS)
1064 if (!openFiles( buf, nbuf, old, new ))
1065 XauUnlockAuth( buf );
1067 if (!*new)
1068 logWarn( "Cannot update authorization file in home dir %s\n", home );
1071 static int
1072 endUserAuth( FILE *old, FILE *new, const char *nname, int ok )
1074 Xauth *entry;
1075 struct stat statb;
1077 if (old) {
1078 if (fstat( fileno( old ), &statb ) != -1)
1079 chmod( nname, (int)(statb.st_mode & 0777) );
1080 /*SUPPRESS 560*/
1081 while ((entry = XauReadAuth( old ))) {
1082 if (!checkEntry( entry )) {
1083 debug( "writing an entry\n" );
1084 writeAuth( new, entry, &ok );
1086 XauDisposeAuth( entry );
1088 fclose( old );
1090 if (fclose( new ) == EOF)
1091 ok = False;
1092 doneAddrs();
1093 return ok;
1096 static void
1097 undoUserAuth( const char *name, const char *new_name )
1099 logWarn( "Cannot save user authorization in home dir\n" );
1100 unlink( new_name );
1101 XauUnlockAuth( name );
1104 static char *
1105 moveUserAuth( const char *name, char *new_name, char *envname )
1107 if (unlink( name ))
1108 debug( "unlink %s failed\n", name );
1109 if (link( new_name, name )) {
1110 debug( "link failed %s %s\n", new_name, name );
1111 logError( "Cannot move user authorization into place\n" );
1112 envname = new_name;
1113 } else {
1114 debug( "new authorization moved into place\n" );
1115 unlink( new_name );
1117 XauUnlockAuth( name );
1118 return envname;
1121 void
1122 setUserAuthorization( struct display *d )
1124 FILE *old, *new;
1125 char *name;
1126 char *envname;
1127 Xauth **auths;
1128 int i, ok;
1129 int magicCookie;
1130 int data_len;
1131 char name_buf[NBSIZE], new_name[NBSIZE + 2];
1133 debug( "setUserAuthorization\n" );
1134 auths = d->authorizations;
1135 if (auths) {
1136 if (d->forceUserAuthDir)
1137 goto fallback;
1138 startUserAuth( name_buf, new_name, &old, &new );
1139 if (new) {
1140 envname = 0;
1141 name = name_buf;
1142 } else {
1143 /* 'old' is uninitialized here */
1144 fallback:
1146 if (strlen( d->userAuthDir ) >= NBSIZE - 13)
1147 return;
1149 * Note, that we don't lock the auth file here, as it's
1150 * temporary - we can assume, that we are the only ones
1151 * knowing about this file anyway.
1153 #ifdef HAVE_MKSTEMP
1154 sprintf( name_buf, "%s/.XauthXXXXXX", d->userAuthDir );
1155 new = fdOpenW( mkstemp( name_buf ) );
1156 #else
1157 for (i = 0; i < 100; i++) {
1158 sprintf( name_buf, "%s/.XauthXXXXXX", d->userAuthDir );
1159 (void)mktemp( name_buf );
1160 if ((new =
1161 fdOpenW( open( name_buf, O_WRONLY | O_CREAT | O_EXCL,
1162 0600 ) )))
1163 break;
1165 #endif
1166 if (!new) {
1167 logError( "Cannot create authorization file in %s\n",
1168 d->userAuthDir );
1169 return;
1171 name = 0;
1172 envname = name_buf;
1173 old = 0;
1175 ok = True;
1176 debug( "%d authorization protocols for %s\n", d->authNum, d->name );
1178 * Write MIT-MAGIC-COOKIE-1 authorization first, so that
1179 * R4 clients which only knew that, and used the first
1180 * matching entry will continue to function
1182 magicCookie = -1;
1183 for (i = 0; i < d->authNum; i++) {
1184 if (auths[i]->name_length == 18 &&
1185 !memcmp( auths[i]->name, "MIT-MAGIC-COOKIE-1", 18 ))
1187 magicCookie = i;
1188 if ((d->displayType & d_location) == dLocal)
1189 writeLocalAuth( new, auths[i], d->name, &ok );
1190 #ifdef XDMCP
1191 else
1192 writeRemoteAuth( new, auths[i], (XdmcpNetaddr)d->peer.data,
1193 d->peer.length, d->name, &ok );
1194 #endif
1195 break;
1198 /* now write other authorizations */
1199 for (i = 0; i < d->authNum; i++) {
1200 if (i != magicCookie) {
1201 data_len = auths[i]->data_length;
1202 /* client will just use default Kerberos cache, so don't
1203 * even write cache info into the authority file.
1205 if (auths[i]->name_length == 14 &&
1206 !strncmp( auths[i]->name, "MIT-KERBEROS-5", 14 ))
1207 auths[i]->data_length = 0;
1208 if ((d->displayType & d_location) == dLocal)
1209 writeLocalAuth( new, auths[i], d->name, &ok );
1210 #ifdef XDMCP
1211 else
1212 writeRemoteAuth( new, auths[i], (XdmcpNetaddr)d->peer.data,
1213 d->peer.length, d->name, &ok );
1214 #endif
1215 auths[i]->data_length = data_len;
1218 if (!endUserAuth( old, new, new_name, ok )) {
1219 if (!name) {
1220 logError( "Cannot save user authorization\n" );
1221 return;
1223 undoUserAuth( name, new_name );
1224 initAddrs();
1225 goto fallback;
1227 if (name)
1228 envname = moveUserAuth( name, new_name, envname );
1229 if (envname) {
1230 userEnviron = setEnv( userEnviron, "XAUTHORITY", envname );
1231 systemEnviron = setEnv( systemEnviron, "XAUTHORITY", envname );
1233 /* a chown() used to be here, but this code runs as user anyway */
1235 debug( "done setUserAuthorization\n" );
1238 void
1239 removeUserAuthorization( struct display *d )
1241 Xauth **auths;
1242 FILE *old, *new;
1243 int i;
1244 char name[NBSIZE], new_name[NBSIZE + 2];
1246 if (!(auths = d->authorizations))
1247 return;
1248 debug( "removeUserAuthorization\n" );
1249 startUserAuth( name, new_name, &old, &new );
1250 if (new) {
1251 for (i = 0; i < d->authNum; i++) {
1252 if ((d->displayType & d_location) == dLocal)
1253 writeLocalAuth( new, auths[i], d->name, 0 );
1254 #ifdef XDMCP
1255 else
1256 writeRemoteAuth( new, auths[i], (XdmcpNetaddr)d->peer.data,
1257 d->peer.length, d->name, 0 );
1258 #endif
1260 if (endUserAuth( old, new, new_name, True ))
1261 (void)moveUserAuth( name, new_name, 0 );
1262 else
1263 undoUserAuth( name, new_name );
1265 debug( "done removeUserAuthorization\n" );