@@ -408,13 +408,13 @@ scrub_abbrs(struct state *sp)
408
408
* 1 if the time zone has changed
409
409
*/
410
410
static int
411
- tzfile_changed (const char * name )
411
+ tzfile_changed (const char * name , int fd )
412
412
{
413
413
static char old_name [PATH_MAX ];
414
414
static struct stat old_sb ;
415
415
struct stat sb ;
416
416
417
- if (stat ( name , & sb ) != 0 )
417
+ if (_fstat ( fd , & sb ) != 0 )
418
418
return -1 ;
419
419
420
420
if (strcmp (name , old_name ) != 0 ) {
@@ -446,8 +446,10 @@ union input_buffer {
446
446
+ 4 * TZ_MAX_TIMES ];
447
447
};
448
448
449
+ #ifndef __FreeBSD__
449
450
/* TZDIR with a trailing '/' rather than a trailing '\0'. */
450
451
static char const tzdirslash [sizeof TZDIR ] = TZDIR "/" ;
452
+ #endif /* !__FreeBSD__ */
451
453
452
454
/* Local storage needed for 'tzloadbody'. */
453
455
union local_storage {
@@ -460,13 +462,15 @@ union local_storage {
460
462
struct state st ;
461
463
} u ;
462
464
465
+ #ifndef __FreeBSD__
463
466
/* The name of the file to be opened. Ideally this would have no
464
467
size limits, to support arbitrarily long Zone names.
465
468
Limiting Zone names to 1024 bytes should suffice for practical use.
466
469
However, there is no need for this to be smaller than struct
467
470
file_analysis as that struct is allocated anyway, as the other
468
471
union member. */
469
472
char fullname [max (sizeof (struct file_analysis ), sizeof tzdirslash + 1024 )];
473
+ #endif /* !__FreeBSD__ */
470
474
};
471
475
472
476
/* Load tz data from the file named NAME into *SP. Read extended
@@ -480,7 +484,11 @@ tzloadbody(char const *name, struct state *sp, bool doextend,
480
484
register int fid ;
481
485
register int stored ;
482
486
register ssize_t nread ;
487
+ #ifdef __FreeBSD__
488
+ int serrno ;
489
+ #else /* !__FreeBSD__ */
483
490
register bool doaccess ;
491
+ #endif /* !__FreeBSD__ */
484
492
register union input_buffer * up = & lsp -> u .u ;
485
493
register int tzheadsize = sizeof (struct tzhead );
486
494
@@ -494,6 +502,7 @@ tzloadbody(char const *name, struct state *sp, bool doextend,
494
502
495
503
if (name [0 ] == ':' )
496
504
++ name ;
505
+ #ifndef __FreeBSD__
497
506
#ifdef SUPPRESS_TZDIR
498
507
/* Do not prepend TZDIR. This is intended for specialized
499
508
applications only, due to its security implications. */
@@ -502,9 +511,7 @@ tzloadbody(char const *name, struct state *sp, bool doextend,
502
511
doaccess = name [0 ] == '/' ;
503
512
#endif
504
513
if (!doaccess ) {
505
- #ifndef __FreeBSD__
506
514
char const * dot ;
507
- #endif /* !__FreeBSD__ */
508
515
if (sizeof lsp -> fullname - sizeof tzdirslash <= strlen (name ))
509
516
return ENAMETOOLONG ;
510
517
@@ -514,7 +521,6 @@ tzloadbody(char const *name, struct state *sp, bool doextend,
514
521
memcpy (lsp -> fullname , tzdirslash , sizeof tzdirslash );
515
522
strcpy (lsp -> fullname + sizeof tzdirslash , name );
516
523
517
- #ifndef __FreeBSD__
518
524
/* Set doaccess if NAME contains a ".." file name
519
525
component, as such a name could read a file outside
520
526
the TZDIR virtual subtree. */
@@ -524,35 +530,49 @@ tzloadbody(char const *name, struct state *sp, bool doextend,
524
530
doaccess = true;
525
531
break ;
526
532
}
527
- #endif /* !__FreeBSD__ */
528
533
529
534
name = lsp -> fullname ;
530
535
}
531
- #ifndef __FreeBSD__
532
536
if (doaccess && access (name , R_OK ) != 0 )
533
537
return errno ;
534
- #endif /* !__FreeBSD__ */
535
- #ifdef DETECT_TZ_CHANGES
536
- if (doextend ) {
537
- /*
538
- * Detect if the timezone file has changed. Check
539
- * 'doextend' to ignore TZDEFRULES; the tzfile_changed()
540
- * function can only keep state for a single file.
541
- */
542
- switch (tzfile_changed (name )) {
543
- case -1 :
544
- return errno ;
545
- case 0 :
546
- return 0 ;
547
- case 1 :
548
- break ;
549
- }
550
- }
551
- #endif /* DETECT_TZ_CHANGES */
538
+ #else /* __FreeBSD__ */
539
+ if (issetugid ()) {
540
+ const char * relname = name ;
541
+ if (strncmp (relname , TZDIR "/" , strlen (TZDIR ) + 1 ) == 0 )
542
+ relname += strlen (TZDIR ) + 1 ;
543
+ int dd = _open (TZDIR , O_DIRECTORY | O_RDONLY );
544
+ if (dd < 0 )
545
+ return errno ;
546
+ fid = _openat (dd , relname , O_RDONLY | O_BINARY , AT_RESOLVE_BENEATH );
547
+ serrno = errno ;
548
+ _close (dd );
549
+ errno = serrno ;
550
+ } else
551
+ #endif
552
552
fid = _open (name , O_RDONLY | O_BINARY );
553
553
if (fid < 0 )
554
554
return errno ;
555
555
556
+ #ifdef DETECT_TZ_CHANGES
557
+ if (doextend ) {
558
+ /*
559
+ * Detect if the timezone file has changed. Check 'doextend' to
560
+ * ignore TZDEFRULES; the tzfile_changed() function can only
561
+ * keep state for a single file.
562
+ */
563
+ switch (tzfile_changed (name , fid )) {
564
+ case -1 :
565
+ serrno = errno ;
566
+ _close (fid );
567
+ return serrno ;
568
+ case 0 :
569
+ _close (fid );
570
+ return 0 ;
571
+ case 1 :
572
+ break ;
573
+ }
574
+ }
575
+ #endif /* DETECT_TZ_CHANGES */
556
576
nread = _read (fid , up -> buf , sizeof up -> buf );
557
577
if (nread < tzheadsize ) {
558
578
int err = nread < 0 ? errno : EINVAL ;
0 commit comments