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