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 *
IceAuthFileName(void)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
IceLockAuthFile(const char * file_name,int retries,int timeout,long dead)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 = 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
213 void
IceUnlockAuthFile(const char * file_name)214 IceUnlockAuthFile (
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
236 IceAuthFileEntry *
IceReadAuthFileEntry(FILE * auth_file)237 IceReadAuthFileEntry (
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
287 void
IceFreeAuthFileEntry(IceAuthFileEntry * auth)288 IceFreeAuthFileEntry (
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
305 Status
IceWriteAuthFileEntry(FILE * auth_file,IceAuthFileEntry * auth)306 IceWriteAuthFileEntry (
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
333 IceAuthFileEntry *
IceGetAuthFileEntry(const char * protocol_name,const char * network_id,const char * auth_name)334 IceGetAuthFileEntry (
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
379 static Status
read_short(FILE * file,unsigned short * shortp)380 read_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
392 static Status
read_string(FILE * file,char ** stringp)393 read_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
424 static Status
read_counted_string(FILE * file,unsigned short * countp,char ** stringp)425 read_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
458 static Status
write_short(FILE * file,unsigned short s)459 write_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
473 static Status
write_string(FILE * file,const char * string)474 write_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
485 static Status
write_counted_string(FILE * file,unsigned short count,const char * string)486 write_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