authutil.c revision fb5e8d76
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#define Time_t time_t
42#ifndef X_NOT_POSIX
43#include <unistd.h>
44#else
45#ifndef WIN32
46extern unsigned	sleep ();
47#else
48#define link rename
49#endif
50#endif
51
52static Status read_short (FILE *file, unsigned short *shortp);
53static Status read_string (FILE *file, char **stringp);
54static Status read_counted_string (FILE *file, unsigned short *countp, char **stringp);
55static Status write_short (FILE *file, unsigned short s);
56static Status write_string (FILE *file, const char *string);
57static Status write_counted_string (FILE *file, unsigned short count, const char *string);
58
59
60
61/*
62 * The following routines are for manipulating the .ICEauthority file
63 * These are utility functions - they are not part of the standard
64 * ICE library specification.
65 */
66
67char *
68IceAuthFileName (void)
69{
70    static char slashDotICEauthority[] = "/.ICEauthority";
71    char    	*name;
72    static char	*buf;
73    static size_t bsize;
74    size_t    	size;
75#ifdef WIN32
76#ifndef PATH_MAX
77#define PATH_MAX 512
78#endif
79    char    	dir[PATH_MAX];
80#endif
81
82    if ((name = getenv ("ICEAUTHORITY")))
83	return (name);
84
85    name = getenv ("HOME");
86
87    if (!name)
88    {
89#ifdef WIN32
90    register char *ptr1;
91    register char *ptr2;
92    int len1 = 0, len2 = 0;
93
94    if ((ptr1 = getenv("HOMEDRIVE")) && (ptr2 = getenv("HOMEDIR"))) {
95	len1 = strlen (ptr1);
96	len2 = strlen (ptr2);
97    } else if ((ptr2 = getenv("USERNAME"))) {
98	len1 = strlen (ptr1 = "/users/");
99	len2 = strlen (ptr2);
100    }
101    if ((len1 + len2 + 1) < PATH_MAX) {
102	snprintf (dir, sizeof(dir), "%s%s", ptr1, (ptr2) ? ptr2 : "");
103	name = dir;
104    }
105    if (!name)
106#endif
107	return (NULL);
108    }
109
110    size = strlen (name) + strlen (&slashDotICEauthority[1]) + 2;
111
112    if (size > bsize)
113    {
114	if (buf)
115	    free (buf);
116	buf = malloc (size);
117	if (!buf)
118	    return (NULL);
119	bsize = size;
120    }
121
122    snprintf (buf, bsize, "%s%s", name,
123              slashDotICEauthority + (name[1] == '\0' ? 1 : 0));
124
125    return (buf);
126}
127
128
129
130int
131IceLockAuthFile (
132	const char *file_name,
133	int	retries,
134	int	timeout,
135	long	dead
136)
137{
138    char	creat_name[1025], link_name[1025];
139    struct stat	statb;
140    Time_t	now;
141    int		creat_fd = -1;
142
143    if ((int) strlen (file_name) > 1022)
144	return (IceAuthLockError);
145
146    snprintf (creat_name, sizeof(creat_name), "%s-c", file_name);
147    snprintf (link_name, sizeof(link_name), "%s-l", file_name);
148
149    if (stat (creat_name, &statb) != -1)
150    {
151	now = time ((Time_t *) 0);
152
153	/*
154	 * NFS may cause ctime to be before now, special
155	 * case a 0 deadtime to force lock removal
156	 */
157
158	if (dead == 0 || now - statb.st_ctime > dead)
159	{
160	    unlink (creat_name);
161	    unlink (link_name);
162	}
163    }
164
165    while (retries > 0)
166    {
167	if (creat_fd == -1)
168	{
169	    creat_fd = creat (creat_name, 0666);
170
171	    if (creat_fd == -1)
172	    {
173		if (errno != EACCES)
174		    return (IceAuthLockError);
175	    }
176	    else
177		close (creat_fd);
178	}
179
180	if (creat_fd != -1)
181	{
182	    if (link (creat_name, link_name) != -1)
183		return (IceAuthLockSuccess);
184
185	    if (errno == ENOENT)
186	    {
187		creat_fd = -1;	/* force re-creat next time around */
188		continue;
189	    }
190
191	    if (errno != EEXIST)
192		return (IceAuthLockError);
193	}
194
195	sleep ((unsigned) timeout);
196	--retries;
197    }
198
199    return (IceAuthLockTimeout);
200}
201
202
203
204void
205IceUnlockAuthFile (
206	const char	*file_name
207)
208{
209#ifndef WIN32
210    char	creat_name[1025];
211#endif
212    char	link_name[1025];
213
214    if ((int) strlen (file_name) > 1022)
215	return;
216
217#ifndef WIN32
218    snprintf (creat_name, sizeof(creat_name), "%s-c", file_name);
219    unlink (creat_name);
220#endif
221    snprintf (link_name, sizeof(link_name), "%s-l", file_name);
222    unlink (link_name);
223}
224
225
226
227IceAuthFileEntry *
228IceReadAuthFileEntry (
229	FILE	*auth_file
230)
231{
232    IceAuthFileEntry   	local;
233    IceAuthFileEntry   	*ret;
234
235    local.protocol_name = NULL;
236    local.protocol_data = NULL;
237    local.network_id = NULL;
238    local.auth_name = NULL;
239    local.auth_data = NULL;
240
241    if (!read_string (auth_file, &local.protocol_name))
242	return (NULL);
243
244    if (!read_counted_string (auth_file,
245	&local.protocol_data_length, &local.protocol_data))
246	goto bad;
247
248    if (!read_string (auth_file, &local.network_id))
249	goto bad;
250
251    if (!read_string (auth_file, &local.auth_name))
252	goto bad;
253
254    if (!read_counted_string (auth_file,
255	&local.auth_data_length, &local.auth_data))
256	goto bad;
257
258    if (!(ret = malloc (sizeof (IceAuthFileEntry))))
259	goto bad;
260
261    *ret = local;
262
263    return (ret);
264
265 bad:
266
267    if (local.protocol_name) free (local.protocol_name);
268    if (local.protocol_data) free (local.protocol_data);
269    if (local.network_id) free (local.network_id);
270    if (local.auth_name) free (local.auth_name);
271    if (local.auth_data) free (local.auth_data);
272
273    return (NULL);
274}
275
276
277
278void
279IceFreeAuthFileEntry (
280	IceAuthFileEntry	*auth
281)
282{
283    if (auth)
284    {
285	if (auth->protocol_name) free (auth->protocol_name);
286	if (auth->protocol_data) free (auth->protocol_data);
287	if (auth->network_id) free (auth->network_id);
288	if (auth->auth_name) free (auth->auth_name);
289	if (auth->auth_data) free (auth->auth_data);
290	free (auth);
291    }
292}
293
294
295
296Status
297IceWriteAuthFileEntry (
298	FILE			*auth_file,
299	IceAuthFileEntry	*auth
300)
301{
302    if (!write_string (auth_file, auth->protocol_name))
303	return (0);
304
305    if (!write_counted_string (auth_file,
306	auth->protocol_data_length, auth->protocol_data))
307	return (0);
308
309    if (!write_string (auth_file, auth->network_id))
310	return (0);
311
312    if (!write_string (auth_file, auth->auth_name))
313	return (0);
314
315    if (!write_counted_string (auth_file,
316	auth->auth_data_length, auth->auth_data))
317	return (0);
318
319    return (1);
320}
321
322
323
324IceAuthFileEntry *
325IceGetAuthFileEntry (
326	const char	*protocol_name,
327	const char	*network_id,
328	const char	*auth_name
329)
330{
331    FILE    		*auth_file;
332    char    		*filename;
333    IceAuthFileEntry    *entry;
334
335    if (!(filename = IceAuthFileName ()))
336	return (NULL);
337
338    if (access (filename, R_OK) != 0)		/* checks REAL id */
339	return (NULL);
340
341    if (!(auth_file = fopen (filename, "rb")))
342	return (NULL);
343
344    for (;;)
345    {
346	if (!(entry = IceReadAuthFileEntry (auth_file)))
347	    break;
348
349	if (strcmp (protocol_name, entry->protocol_name) == 0 &&
350	    strcmp (network_id, entry->network_id) == 0 &&
351            strcmp (auth_name, entry->auth_name) == 0)
352	{
353	    break;
354	}
355
356	IceFreeAuthFileEntry (entry);
357    }
358
359    fclose (auth_file);
360
361    return (entry);
362}
363
364
365
366/*
367 * local routines
368 */
369
370static Status
371read_short (FILE *file, unsigned short *shortp)
372{
373    unsigned char   file_short[2];
374
375    if (fread (file_short, sizeof (file_short), 1, file) != 1)
376	return (0);
377
378    *shortp = file_short[0] * 256 + file_short[1];
379    return (1);
380}
381
382
383static Status
384read_string (FILE *file, char **stringp)
385
386{
387    unsigned short  len;
388    char	    *data;
389
390    if (!read_short (file, &len))
391	return (0);
392
393    data = malloc ((unsigned) len + 1);
394
395    if (!data)
396	    return (0);
397
398    if (len != 0)
399    {
400	if (fread (data, sizeof (char), len, file) != len)
401	{
402	    free (data);
403	    return (0);
404	}
405
406    }
407    data[len] = '\0';
408
409    *stringp = data;
410
411    return (1);
412}
413
414
415static Status
416read_counted_string (FILE *file, unsigned short	*countp, char **stringp)
417{
418    unsigned short  len;
419    char	    *data;
420
421    if (!read_short (file, &len))
422	return (0);
423
424    if (len == 0)
425    {
426	data = NULL;
427    }
428    else
429    {
430    	data = malloc ((unsigned) len);
431
432    	if (!data)
433	    return (0);
434
435	if (fread (data, sizeof (char), len, file) != len)
436	{
437	    free (data);
438	    return (0);
439    	}
440    }
441
442    *stringp = data;
443    *countp = len;
444
445    return (1);
446}
447
448
449static Status
450write_short (FILE *file, unsigned short s)
451{
452    unsigned char   file_short[2];
453
454    file_short[0] = (s & (unsigned) 0xff00) >> 8;
455    file_short[1] = s & 0xff;
456
457    if (fwrite (file_short, sizeof (file_short), 1, file) != 1)
458	return (0);
459
460    return (1);
461}
462
463
464static Status
465write_string (FILE *file, const char *string)
466{
467    size_t count = strlen (string);
468
469    if (count > USHRT_MAX)
470	return (0);
471
472    return write_counted_string (file, (unsigned short) count, string);
473}
474
475
476static Status
477write_counted_string (FILE *file, unsigned short count, const char *string)
478{
479    if (!write_short (file, count))
480	return (0);
481
482    if (fwrite (string, sizeof (char), count, file) != count)
483	return (0);
484
485    return (1);
486}
487