authutil.c revision a3129944
1/******************************************************************************
2
3
4Copyright 1993, 1998  The Open Group
5
6Permission to use, copy, modify, distribute, and sell this software and its
7documentation for any purpose is hereby granted without fee, provided that
8the above copyright notice appear in all copies and that both that
9copyright notice and this permission notice appear in supporting
10documentation.
11
12The above copyright notice and this permission notice shall be included in
13all copies or substantial portions of the Software.
14
15THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
18OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
19AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
22Except as contained in this notice, the name of The Open Group shall not be
23used in advertising or otherwise to promote the sale, use or other dealings
24in this Software without prior written authorization from The Open Group.
25
26Author: 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
45extern unsigned	sleep ();
46#else
47#define link rename
48#endif
49#endif
50
51static Status read_short (FILE *file, unsigned short *shortp);
52static Status read_string (FILE *file, char **stringp);
53static Status read_counted_string (FILE *file, unsigned short *countp, char **stringp);
54static Status write_short (FILE *file, unsigned short s);
55static Status write_string (FILE *file, const char *string);
56static 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
66char *
67IceAuthFileName (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
139int
140IceLockAuthFile (
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 = creat (creat_name, 0666);
179
180	    if (creat_fd == -1)
181	    {
182		if (errno != EACCES)
183		    return (IceAuthLockError);
184	    }
185	    else
186		close (creat_fd);
187	}
188
189	if (creat_fd != -1)
190	{
191	    if (link (creat_name, link_name) != -1)
192		return (IceAuthLockSuccess);
193
194	    if (errno == ENOENT)
195	    {
196		creat_fd = -1;	/* force re-creat next time around */
197		continue;
198	    }
199
200	    if (errno != EEXIST)
201		return (IceAuthLockError);
202	}
203
204	sleep ((unsigned) timeout);
205	--retries;
206    }
207
208    return (IceAuthLockTimeout);
209}
210
211
212
213void
214IceUnlockAuthFile (
215	const char	*file_name
216)
217{
218#ifndef WIN32
219    char	creat_name[1025];
220#endif
221    char	link_name[1025];
222
223    if ((int) strlen (file_name) > 1022)
224	return;
225
226#ifndef WIN32
227    snprintf (creat_name, sizeof(creat_name), "%s-c", file_name);
228    unlink (creat_name);
229#endif
230    snprintf (link_name, sizeof(link_name), "%s-l", file_name);
231    unlink (link_name);
232}
233
234
235
236IceAuthFileEntry *
237IceReadAuthFileEntry (
238	FILE	*auth_file
239)
240{
241    IceAuthFileEntry   	local;
242    IceAuthFileEntry   	*ret;
243
244    local.protocol_name = NULL;
245    local.protocol_data = NULL;
246    local.network_id = NULL;
247    local.auth_name = NULL;
248    local.auth_data = NULL;
249
250    if (!read_string (auth_file, &local.protocol_name))
251	return (NULL);
252
253    if (!read_counted_string (auth_file,
254	&local.protocol_data_length, &local.protocol_data))
255	goto bad;
256
257    if (!read_string (auth_file, &local.network_id))
258	goto bad;
259
260    if (!read_string (auth_file, &local.auth_name))
261	goto bad;
262
263    if (!read_counted_string (auth_file,
264	&local.auth_data_length, &local.auth_data))
265	goto bad;
266
267    if (!(ret = malloc (sizeof (IceAuthFileEntry))))
268	goto bad;
269
270    *ret = local;
271
272    return (ret);
273
274 bad:
275
276    free (local.protocol_name);
277    free (local.protocol_data);
278    free (local.network_id);
279    free (local.auth_name);
280    free (local.auth_data);
281
282    return (NULL);
283}
284
285
286
287void
288IceFreeAuthFileEntry (
289	IceAuthFileEntry	*auth
290)
291{
292    if (auth)
293    {
294	free (auth->protocol_name);
295	free (auth->protocol_data);
296	free (auth->network_id);
297	free (auth->auth_name);
298	free (auth->auth_data);
299	free (auth);
300    }
301}
302
303
304
305Status
306IceWriteAuthFileEntry (
307	FILE			*auth_file,
308	IceAuthFileEntry	*auth
309)
310{
311    if (!write_string (auth_file, auth->protocol_name))
312	return (0);
313
314    if (!write_counted_string (auth_file,
315	auth->protocol_data_length, auth->protocol_data))
316	return (0);
317
318    if (!write_string (auth_file, auth->network_id))
319	return (0);
320
321    if (!write_string (auth_file, auth->auth_name))
322	return (0);
323
324    if (!write_counted_string (auth_file,
325	auth->auth_data_length, auth->auth_data))
326	return (0);
327
328    return (1);
329}
330
331
332
333IceAuthFileEntry *
334IceGetAuthFileEntry (
335	const char	*protocol_name,
336	const char	*network_id,
337	const char	*auth_name
338)
339{
340    FILE    		*auth_file;
341    char    		*filename;
342    IceAuthFileEntry    *entry;
343
344    if (!(filename = IceAuthFileName ()))
345	return (NULL);
346
347    if (access (filename, R_OK) != 0)		/* checks REAL id */
348	return (NULL);
349
350    if (!(auth_file = fopen (filename, "rb")))
351	return (NULL);
352
353    for (;;)
354    {
355	if (!(entry = IceReadAuthFileEntry (auth_file)))
356	    break;
357
358	if (strcmp (protocol_name, entry->protocol_name) == 0 &&
359	    strcmp (network_id, entry->network_id) == 0 &&
360            strcmp (auth_name, entry->auth_name) == 0)
361	{
362	    break;
363	}
364
365	IceFreeAuthFileEntry (entry);
366    }
367
368    fclose (auth_file);
369
370    return (entry);
371}
372
373
374
375/*
376 * local routines
377 */
378
379static Status
380read_short (FILE *file, unsigned short *shortp)
381{
382    unsigned char   file_short[2];
383
384    if (fread (file_short, sizeof (file_short), 1, file) != 1)
385	return (0);
386
387    *shortp = file_short[0] * 256 + file_short[1];
388    return (1);
389}
390
391
392static Status
393read_string (FILE *file, char **stringp)
394
395{
396    unsigned short  len;
397    char	    *data;
398
399    if (!read_short (file, &len))
400	return (0);
401
402    data = malloc ((unsigned) len + 1);
403
404    if (!data)
405	    return (0);
406
407    if (len != 0)
408    {
409	if (fread (data, sizeof (char), len, file) != len)
410	{
411	    free (data);
412	    return (0);
413	}
414
415    }
416    data[len] = '\0';
417
418    *stringp = data;
419
420    return (1);
421}
422
423
424static Status
425read_counted_string (FILE *file, unsigned short	*countp, char **stringp)
426{
427    unsigned short  len;
428    char	    *data;
429
430    if (!read_short (file, &len))
431	return (0);
432
433    if (len == 0)
434    {
435	data = NULL;
436    }
437    else
438    {
439    	data = malloc ((unsigned) len);
440
441    	if (!data)
442	    return (0);
443
444	if (fread (data, sizeof (char), len, file) != len)
445	{
446	    free (data);
447	    return (0);
448    	}
449    }
450
451    *stringp = data;
452    *countp = len;
453
454    return (1);
455}
456
457
458static Status
459write_short (FILE *file, unsigned short s)
460{
461    unsigned char   file_short[2];
462
463    file_short[0] = (s & (unsigned) 0xff00) >> 8;
464    file_short[1] = s & 0xff;
465
466    if (fwrite (file_short, sizeof (file_short), 1, file) != 1)
467	return (0);
468
469    return (1);
470}
471
472
473static Status
474write_string (FILE *file, const char *string)
475{
476    size_t count = strlen (string);
477
478    if (count > USHRT_MAX)
479	return (0);
480
481    return write_counted_string (file, (unsigned short) count, string);
482}
483
484
485static Status
486write_counted_string (FILE *file, unsigned short count, const char *string)
487{
488    if (!write_short (file, count))
489	return (0);
490
491    if (fwrite (string, sizeof (char), count, file) != count)
492	return (0);
493
494    return (1);
495}
496