Home | History | Annotate | Line # | Download | only in src
      1 /******************************************************************************
      2 
      3 
      4 Copyright 1993, 1998  The Open Group
      5 
      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.
     11 
     12 The above copyright notice and this permission notice shall be included in
     13 all copies or substantial portions of the Software.
     14 
     15 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     16 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     17 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
     18 OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
     19 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
     20 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
     21 
     22 Except as contained in this notice, the name of The Open Group shall not be
     23 used in advertising or otherwise to promote the sale, use or other dealings
     24 in this Software without prior written authorization from The Open Group.
     25 
     26 Author: Ralph Mor, X Consortium
     27 ******************************************************************************/
     28 
     29 #ifdef HAVE_CONFIG_H
     30 #include <config.h>
     31 #endif
     32 #include <X11/ICE/ICElib.h>
     33 #include "ICElibint.h"
     34 #include <X11/ICE/ICEutil.h>
     35 #include <X11/Xos.h>
     36 #include <sys/stat.h>
     37 #include <errno.h>
     38 #include <limits.h>
     39 
     40 #include <time.h>
     41 #ifndef X_NOT_POSIX
     42 #include <unistd.h>
     43 #else
     44 #ifndef WIN32
     45 extern unsigned	sleep ();
     46 #else
     47 #define link rename
     48 #endif
     49 #endif
     50 
     51 static Status read_short (FILE *file, unsigned short *shortp);
     52 static Status read_string (FILE *file, char **stringp);
     53 static Status read_counted_string (FILE *file, unsigned short *countp, char **stringp);
     54 static Status write_short (FILE *file, unsigned short s);
     55 static Status write_string (FILE *file, const char *string);
     56 static Status write_counted_string (FILE *file, unsigned short count, const char *string);
     57 
     58 
     59 
     60 /*
     61  * The following routines are for manipulating the .ICEauthority file
     62  * These are utility functions - they are not part of the standard
     63  * ICE library specification.
     64  */
     65 
     66 char *
     67 IceAuthFileName (void)
     68 {
     69     const char  *ICEauthority_name = ".ICEauthority";
     70     char    	*name;
     71     static char	*buf;
     72     static size_t bsize;
     73     size_t    	size;
     74 #ifdef WIN32
     75 #ifndef PATH_MAX
     76 #define PATH_MAX 512
     77 #endif
     78     char    	dir[PATH_MAX];
     79 #endif
     80 
     81     if ((name = getenv ("ICEAUTHORITY")))
     82 	return (name);
     83 
     84     /* If it's in the XDG_RUNTIME_DIR, don't use a dotfile */
     85     if ((name = getenv ("XDG_RUNTIME_DIR")))
     86 	ICEauthority_name++;
     87 
     88     if (!name || !name[0])
     89 	name = getenv ("HOME");
     90 
     91     if (!name || !name[0])
     92     {
     93 #ifdef WIN32
     94     register char *ptr1;
     95     register char *ptr2;
     96     int len1 = 0, len2 = 0;
     97 
     98     if ((ptr1 = getenv("HOMEDRIVE")) && (ptr2 = getenv("HOMEDIR"))) {
     99 	len1 = strlen (ptr1);
    100 	len2 = strlen (ptr2);
    101     } else if ((ptr2 = getenv("USERNAME"))) {
    102 	len1 = strlen (ptr1 = "/users/");
    103 	len2 = strlen (ptr2);
    104     }
    105     if ((len1 + len2 + 1) < PATH_MAX) {
    106 	snprintf (dir, sizeof(dir), "%s%s", ptr1, (ptr2) ? ptr2 : "");
    107 	name = dir;
    108     }
    109     if (!name || !name[0])
    110 #endif
    111 	return (NULL);
    112     }
    113 
    114     /* Special case for "/".  We will add our own '/' later. */
    115     if (name[1] == '\0')
    116 	name++;
    117 
    118     size = strlen (name) + 1 + strlen (ICEauthority_name) + 1;
    119 
    120     if (size > bsize)
    121     {
    122 
    123 	free (buf);
    124 	buf = malloc (size);
    125 	if (!buf) {
    126 	    bsize = 0;
    127 	    return (NULL);
    128 	}
    129 	bsize = size;
    130     }
    131 
    132     snprintf (buf, bsize, "%s/%s", name, ICEauthority_name);
    133 
    134     return (buf);
    135 }
    136 
    137 
    138 
    139 int
    140 IceLockAuthFile (
    141 	const char *file_name,
    142 	int	retries,
    143 	int	timeout,
    144 	long	dead
    145 )
    146 {
    147     char	creat_name[1025], link_name[1025];
    148     struct stat	statb;
    149     time_t	now;
    150     int		creat_fd = -1;
    151 
    152     if ((int) strlen (file_name) > 1022)
    153 	return (IceAuthLockError);
    154 
    155     snprintf (creat_name, sizeof(creat_name), "%s-c", file_name);
    156     snprintf (link_name, sizeof(link_name), "%s-l", file_name);
    157 
    158     if (stat (creat_name, &statb) != -1)
    159     {
    160 	now = time ((time_t *) 0);
    161 
    162 	/*
    163 	 * NFS may cause ctime to be before now, special
    164 	 * case a 0 deadtime to force lock removal
    165 	 */
    166 
    167 	if (dead == 0 || now - statb.st_ctime > dead)
    168 	{
    169 	    unlink (creat_name);
    170 	    unlink (link_name);
    171 	}
    172     }
    173 
    174     while (retries > 0)
    175     {
    176 	if (creat_fd == -1)
    177 	{
    178 	    creat_fd = open (creat_name,
    179                              O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC, 0666);
    180 
    181 	    if (creat_fd == -1)
    182 	    {
    183 		if (errno != EACCES)
    184 		    return (IceAuthLockError);
    185 	    }
    186 	    else
    187 		close (creat_fd);
    188 	}
    189 
    190 	if (creat_fd != -1)
    191 	{
    192 	    if (link (creat_name, link_name) != -1)
    193 		return (IceAuthLockSuccess);
    194 
    195 	    if (errno == ENOENT)
    196 	    {
    197 		creat_fd = -1;	/* force re-creat next time around */
    198 		continue;
    199 	    }
    200 
    201 	    if (errno != EEXIST)
    202 		return (IceAuthLockError);
    203 	}
    204 
    205 	sleep ((unsigned) timeout);
    206 	--retries;
    207     }
    208 
    209     return (IceAuthLockTimeout);
    210 }
    211 
    212 
    213 
    214 void
    215 IceUnlockAuthFile (
    216 	const char	*file_name
    217 )
    218 {
    219 #ifndef WIN32
    220     char	creat_name[1025];
    221 #endif
    222     char	link_name[1025];
    223 
    224     if ((int) strlen (file_name) > 1022)
    225 	return;
    226 
    227 #ifndef WIN32
    228     snprintf (creat_name, sizeof(creat_name), "%s-c", file_name);
    229     unlink (creat_name);
    230 #endif
    231     snprintf (link_name, sizeof(link_name), "%s-l", file_name);
    232     unlink (link_name);
    233 }
    234 
    235 
    236 
    237 IceAuthFileEntry *
    238 IceReadAuthFileEntry (
    239 	FILE	*auth_file
    240 )
    241 {
    242     IceAuthFileEntry   	local;
    243     IceAuthFileEntry   	*ret;
    244 
    245     local.protocol_name = NULL;
    246     local.protocol_data = NULL;
    247     local.network_id = NULL;
    248     local.auth_name = NULL;
    249     local.auth_data = NULL;
    250 
    251     if (!read_string (auth_file, &local.protocol_name))
    252 	return (NULL);
    253 
    254     if (!read_counted_string (auth_file,
    255 	&local.protocol_data_length, &local.protocol_data))
    256 	goto bad;
    257 
    258     if (!read_string (auth_file, &local.network_id))
    259 	goto bad;
    260 
    261     if (!read_string (auth_file, &local.auth_name))
    262 	goto bad;
    263 
    264     if (!read_counted_string (auth_file,
    265 	&local.auth_data_length, &local.auth_data))
    266 	goto bad;
    267 
    268     if (!(ret = malloc (sizeof (IceAuthFileEntry))))
    269 	goto bad;
    270 
    271     *ret = local;
    272 
    273     return (ret);
    274 
    275  bad:
    276 
    277     free (local.protocol_name);
    278     free (local.protocol_data);
    279     free (local.network_id);
    280     free (local.auth_name);
    281     free (local.auth_data);
    282 
    283     return (NULL);
    284 }
    285 
    286 
    287 
    288 void
    289 IceFreeAuthFileEntry (
    290 	IceAuthFileEntry	*auth
    291 )
    292 {
    293     if (auth)
    294     {
    295 	free (auth->protocol_name);
    296 	free (auth->protocol_data);
    297 	free (auth->network_id);
    298 	free (auth->auth_name);
    299 	free (auth->auth_data);
    300 	free (auth);
    301     }
    302 }
    303 
    304 
    305 
    306 Status
    307 IceWriteAuthFileEntry (
    308 	FILE			*auth_file,
    309 	IceAuthFileEntry	*auth
    310 )
    311 {
    312     if (!write_string (auth_file, auth->protocol_name))
    313 	return (0);
    314 
    315     if (!write_counted_string (auth_file,
    316 	auth->protocol_data_length, auth->protocol_data))
    317 	return (0);
    318 
    319     if (!write_string (auth_file, auth->network_id))
    320 	return (0);
    321 
    322     if (!write_string (auth_file, auth->auth_name))
    323 	return (0);
    324 
    325     if (!write_counted_string (auth_file,
    326 	auth->auth_data_length, auth->auth_data))
    327 	return (0);
    328 
    329     return (1);
    330 }
    331 
    332 
    333 
    334 IceAuthFileEntry *
    335 IceGetAuthFileEntry (
    336 	const char	*protocol_name,
    337 	const char	*network_id,
    338 	const char	*auth_name
    339 )
    340 {
    341     FILE    		*auth_file;
    342     char    		*filename;
    343     IceAuthFileEntry    *entry;
    344 
    345     if (!(filename = IceAuthFileName ()))
    346 	return (NULL);
    347 
    348     if (access (filename, R_OK) != 0)		/* checks REAL id */
    349 	return (NULL);
    350 
    351     if (!(auth_file = fopen (filename, "rb" FOPEN_CLOEXEC)))
    352 	return (NULL);
    353 
    354     for (;;)
    355     {
    356 	if (!(entry = IceReadAuthFileEntry (auth_file)))
    357 	    break;
    358 
    359 	if (strcmp (protocol_name, entry->protocol_name) == 0 &&
    360 	    strcmp (network_id, entry->network_id) == 0 &&
    361             strcmp (auth_name, entry->auth_name) == 0)
    362 	{
    363 	    break;
    364 	}
    365 
    366 	IceFreeAuthFileEntry (entry);
    367     }
    368 
    369     fclose (auth_file);
    370 
    371     return (entry);
    372 }
    373 
    374 
    375 
    376 /*
    377  * local routines
    378  */
    379 
    380 static Status
    381 read_short (FILE *file, unsigned short *shortp)
    382 {
    383     unsigned char   file_short[2];
    384 
    385     if (fread (file_short, sizeof (file_short), 1, file) != 1)
    386 	return (0);
    387 
    388     *shortp = file_short[0] * 256 + file_short[1];
    389     return (1);
    390 }
    391 
    392 
    393 static Status
    394 read_string (FILE *file, char **stringp)
    395 
    396 {
    397     unsigned short  len;
    398     char	    *data;
    399 
    400     if (!read_short (file, &len))
    401 	return (0);
    402 
    403     data = malloc ((unsigned) len + 1);
    404 
    405     if (!data)
    406 	    return (0);
    407 
    408     if (len != 0)
    409     {
    410 	if (fread (data, sizeof (char), len, file) != len)
    411 	{
    412 	    free (data);
    413 	    return (0);
    414 	}
    415 
    416     }
    417     data[len] = '\0';
    418 
    419     *stringp = data;
    420 
    421     return (1);
    422 }
    423 
    424 
    425 static Status
    426 read_counted_string (FILE *file, unsigned short	*countp, char **stringp)
    427 {
    428     unsigned short  len;
    429     char	    *data;
    430 
    431     if (!read_short (file, &len))
    432 	return (0);
    433 
    434     if (len == 0)
    435     {
    436 	data = NULL;
    437     }
    438     else
    439     {
    440     	data = malloc ((unsigned) len);
    441 
    442     	if (!data)
    443 	    return (0);
    444 
    445 	if (fread (data, sizeof (char), len, file) != len)
    446 	{
    447 	    free (data);
    448 	    return (0);
    449     	}
    450     }
    451 
    452     *stringp = data;
    453     *countp = len;
    454 
    455     return (1);
    456 }
    457 
    458 
    459 static Status
    460 write_short (FILE *file, unsigned short s)
    461 {
    462     unsigned char   file_short[2];
    463 
    464     file_short[0] = (s & (unsigned) 0xff00) >> 8;
    465     file_short[1] = s & 0xff;
    466 
    467     if (fwrite (file_short, sizeof (file_short), 1, file) != 1)
    468 	return (0);
    469 
    470     return (1);
    471 }
    472 
    473 
    474 static Status
    475 write_string (FILE *file, const char *string)
    476 {
    477     size_t count = strlen (string);
    478 
    479     if (count > USHRT_MAX)
    480 	return (0);
    481 
    482     return write_counted_string (file, (unsigned short) count, string);
    483 }
    484 
    485 
    486 static Status
    487 write_counted_string (FILE *file, unsigned short count, const char *string)
    488 {
    489     if (!write_short (file, count))
    490 	return (0);
    491 
    492     if ((count > 0) &&
    493         (fwrite (string, sizeof (char), count, file) != count))
    494 	return (0);
    495 
    496     return (1);
    497 }
    498