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