Blame src/include/k5-platform.h

Packit fd8b60
/* -*- mode: c; indent-tabs-mode: nil -*- */
Packit fd8b60
/* include/k5-platform.h */
Packit fd8b60
/*
Packit fd8b60
 * Copyright 2003, 2004, 2005, 2007, 2008, 2009 Massachusetts Institute of Technology.
Packit fd8b60
 * All Rights Reserved.
Packit fd8b60
 *
Packit fd8b60
 * Export of this software from the United States of America may
Packit fd8b60
 *   require a specific license from the United States Government.
Packit fd8b60
 *   It is the responsibility of any person or organization contemplating
Packit fd8b60
 *   export to obtain such a license before exporting.
Packit fd8b60
 *
Packit fd8b60
 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
Packit fd8b60
 * distribute this software and its documentation for any purpose and
Packit fd8b60
 * without fee is hereby granted, provided that the above copyright
Packit fd8b60
 * notice appear in all copies and that both that copyright notice and
Packit fd8b60
 * this permission notice appear in supporting documentation, and that
Packit fd8b60
 * the name of M.I.T. not be used in advertising or publicity pertaining
Packit fd8b60
 * to distribution of the software without specific, written prior
Packit fd8b60
 * permission.  Furthermore if you modify this software you must label
Packit fd8b60
 * your software as modified software and not distribute it in such a
Packit fd8b60
 * fashion that it might be confused with the original M.I.T. software.
Packit fd8b60
 * M.I.T. makes no representations about the suitability of
Packit fd8b60
 * this software for any purpose.  It is provided "as is" without express
Packit fd8b60
 * or implied warranty.
Packit fd8b60
 */
Packit fd8b60
Packit fd8b60
/*
Packit fd8b60
 * Some platform-dependent definitions to sync up the C support level.
Packit fd8b60
 * Some to a C99-ish level, some related utility code.
Packit fd8b60
 *
Packit fd8b60
 * Currently:
Packit fd8b60
 * + [u]int{8,16,32}_t types
Packit fd8b60
 * + 64-bit types and load/store code
Packit fd8b60
 * + SIZE_MAX
Packit fd8b60
 * + shared library init/fini hooks
Packit fd8b60
 * + consistent getpwnam/getpwuid interfaces
Packit fd8b60
 * + va_copy fudged if not provided
Packit fd8b60
 * + strlcpy/strlcat
Packit fd8b60
 * + fnmatch
Packit fd8b60
 * + [v]asprintf
Packit fd8b60
 * + strerror_r
Packit fd8b60
 * + mkstemp
Packit fd8b60
 * + zap (support function and macro)
Packit fd8b60
 * + constant time memory comparison
Packit fd8b60
 * + path manipulation
Packit fd8b60
 * + _, N_, dgettext, bindtextdomain (for localization)
Packit fd8b60
 * + getopt_long
Packit fd8b60
 * + secure_getenv
Packit fd8b60
 * + fetching filenames from a directory
Packit fd8b60
 */
Packit fd8b60
Packit fd8b60
#ifndef K5_PLATFORM_H
Packit fd8b60
#define K5_PLATFORM_H
Packit fd8b60
Packit fd8b60
#include "autoconf.h"
Packit fd8b60
#include <assert.h>
Packit fd8b60
#include <string.h>
Packit fd8b60
#include <stdarg.h>
Packit fd8b60
#include <stdint.h>
Packit fd8b60
#include <limits.h>
Packit fd8b60
#include <stdlib.h>
Packit fd8b60
#include <stdio.h>
Packit fd8b60
#include <fcntl.h>
Packit fd8b60
#include <errno.h>
Packit fd8b60
#ifdef HAVE_FNMATCH_H
Packit fd8b60
#include <fnmatch.h>
Packit fd8b60
#endif
Packit fd8b60
Packit fd8b60
#ifdef HAVE_UNISTD_H
Packit fd8b60
#include <unistd.h>
Packit fd8b60
#endif
Packit fd8b60
Packit fd8b60
#ifdef _WIN32
Packit fd8b60
#define CAN_COPY_VA_LIST
Packit fd8b60
#endif
Packit fd8b60
Packit fd8b60
/* This attribute prevents unused function warnings in gcc and clang. */
Packit fd8b60
#ifdef __GNUC__
Packit fd8b60
#define UNUSED __attribute__((__unused__))
Packit fd8b60
#else
Packit fd8b60
#define UNUSED
Packit fd8b60
#endif
Packit fd8b60
Packit fd8b60
#if defined(macintosh) || (defined(__MACH__) && defined(__APPLE__))
Packit fd8b60
#include <TargetConditionals.h>
Packit fd8b60
#endif
Packit fd8b60
Packit fd8b60
/* Initialization and finalization function support for libraries.
Packit fd8b60
Packit fd8b60
   At top level, before the functions are defined or even declared:
Packit fd8b60
   MAKE_INIT_FUNCTION(init_fn);
Packit fd8b60
   MAKE_FINI_FUNCTION(fini_fn);
Packit fd8b60
   Then:
Packit fd8b60
   int init_fn(void) { ... }
Packit fd8b60
   void fini_fn(void) { if (INITIALIZER_RAN(init_fn)) ... }
Packit fd8b60
   In code, in the same file:
Packit fd8b60
   err = CALL_INIT_FUNCTION(init_fn);
Packit fd8b60
Packit fd8b60
   To trigger or verify the initializer invocation from another file,
Packit fd8b60
   a helper function must be created.
Packit fd8b60
Packit fd8b60
   This model handles both the load-time execution (Windows) and
Packit fd8b60
   delayed execution (pthread_once) approaches, and should be able to
Packit fd8b60
   guarantee in both cases that the init function is run once, in one
Packit fd8b60
   thread, before other stuff in the library is done; furthermore, the
Packit fd8b60
   finalization code should only run if the initialization code did.
Packit fd8b60
   (Maybe I could've made the "if INITIALIZER_RAN" test implicit, via
Packit fd8b60
   another function hidden in macros, but this is hairy enough
Packit fd8b60
   already.)
Packit fd8b60
Packit fd8b60
   The init_fn and fini_fn names should be chosen such that any
Packit fd8b60
   exported names staring with those names, and optionally followed by
Packit fd8b60
   additional characters, fits in with any namespace constraints on
Packit fd8b60
   the library in question.
Packit fd8b60
Packit fd8b60
Packit fd8b60
   There's also PROGRAM_EXITING() currently always defined as zero.
Packit fd8b60
   If there's some trivial way to find out if the fini function is
Packit fd8b60
   being called because the program that the library is linked into is
Packit fd8b60
   exiting, we can just skip all the work because the resources are
Packit fd8b60
   about to be freed up anyways.  Generally this is likely to be the
Packit fd8b60
   same as distinguishing whether the library was loaded dynamically
Packit fd8b60
   while the program was running, or loaded as part of program
Packit fd8b60
   startup.  On most platforms, I don't think we can distinguish these
Packit fd8b60
   cases easily, and it's probably not worth expending any significant
Packit fd8b60
   effort.  (Note in particular that atexit() won't do, because if the
Packit fd8b60
   library is explicitly loaded and unloaded, it would have to be able
Packit fd8b60
   to deregister the atexit callback function.  Also, the system limit
Packit fd8b60
   on atexit callbacks may be small.)
Packit fd8b60
Packit fd8b60
Packit fd8b60
   Implementation outline:
Packit fd8b60
Packit fd8b60
   Windows: MAKE_FINI_FUNCTION creates a symbol with a magic name that
Packit fd8b60
   is sought at library build time, and code is added to invoke the
Packit fd8b60
   function when the library is unloaded.  MAKE_INIT_FUNCTION does
Packit fd8b60
   likewise, but the function is invoked when the library is loaded,
Packit fd8b60
   and an extra variable is declared to hold an error code and a "yes
Packit fd8b60
   the initializer ran" flag.  CALL_INIT_FUNCTION blows up if the flag
Packit fd8b60
   isn't set, otherwise returns the error code.
Packit fd8b60
Packit fd8b60
   UNIX: MAKE_INIT_FUNCTION creates and initializes a variable with a
Packit fd8b60
   name derived from the function name, containing a k5_once_t
Packit fd8b60
   (pthread_once_t or int), an error code, and a pointer to the
Packit fd8b60
   function.  The function itself is declared static, but the
Packit fd8b60
   associated variable has external linkage.  CALL_INIT_FUNCTION
Packit fd8b60
   ensures thath the function is called exactly once (pthread_once or
Packit fd8b60
   just check the flag) and returns the stored error code (or the
Packit fd8b60
   pthread_once error).
Packit fd8b60
Packit fd8b60
   (That's the basic idea.  With some debugging assert() calls and
Packit fd8b60
   such, it's a bit more complicated.  And we also need to handle
Packit fd8b60
   doing the pthread test at run time on systems where that works, so
Packit fd8b60
   we use the k5_once_t stuff instead.)
Packit fd8b60
Packit fd8b60
   UNIX, with compiler support: MAKE_FINI_FUNCTION declares the
Packit fd8b60
   function as a destructor, and the run time linker support or
Packit fd8b60
   whatever will cause it to be invoked when the library is unloaded,
Packit fd8b60
   the program ends, etc.
Packit fd8b60
Packit fd8b60
   UNIX, with linker support: MAKE_FINI_FUNCTION creates a symbol with
Packit fd8b60
   a magic name that is sought at library build time, and linker
Packit fd8b60
   options are used to mark it as a finalization function for the
Packit fd8b60
   library.  The symbol must be exported.
Packit fd8b60
Packit fd8b60
   UNIX, no library finalization support: The finalization function
Packit fd8b60
   never runs, and we leak memory.  Tough.
Packit fd8b60
Packit fd8b60
   DELAY_INITIALIZER will be defined by the configure script if we
Packit fd8b60
   want to use k5_once instead of load-time initialization.  That'll
Packit fd8b60
   be the preferred method on most systems except Windows, where we
Packit fd8b60
   have to initialize some mutexes.
Packit fd8b60
Packit fd8b60
Packit fd8b60
Packit fd8b60
Packit fd8b60
   For maximum flexibility in defining the macros, the function name
Packit fd8b60
   parameter should be a simple name, not even a macro defined as
Packit fd8b60
   another name.  The function should have a unique name, and should
Packit fd8b60
   conform to whatever namespace is used by the library in question.
Packit fd8b60
   (We do have export lists, but (1) they're not used for all
Packit fd8b60
   platforms, and (2) they're not used for static libraries.)
Packit fd8b60
Packit fd8b60
   If the macro expansion needs the function to have been declared, it
Packit fd8b60
   must include a declaration.  If it is not necessary for the symbol
Packit fd8b60
   name to be exported from the object file, the macro should declare
Packit fd8b60
   it as "static".  Hence the signature must exactly match "void
Packit fd8b60
   foo(void)".  (ANSI C allows a static declaration followed by a
Packit fd8b60
   non-static one; the result is internal linkage.)  The macro
Packit fd8b60
   expansion has to come before the function, because gcc apparently
Packit fd8b60
   won't act on "__attribute__((constructor))" if it comes after the
Packit fd8b60
   function definition.
Packit fd8b60
Packit fd8b60
   This is going to be compiler- and environment-specific, and may
Packit fd8b60
   require some support at library build time, and/or "asm"
Packit fd8b60
   statements.  But through macro expansion and auxiliary functions,
Packit fd8b60
   we should be able to handle most things except #pragma.
Packit fd8b60
Packit fd8b60
   It's okay for this code to require that the library be built
Packit fd8b60
   with the same compiler and compiler options throughout, but
Packit fd8b60
   we shouldn't require that the library and application use the
Packit fd8b60
   same compiler.
Packit fd8b60
Packit fd8b60
   For static libraries, we don't really care about cleanup too much,
Packit fd8b60
   since it's all memory handling and mutex allocation which will all
Packit fd8b60
   be cleaned up when the program exits.  Thus, it's okay if gcc-built
Packit fd8b60
   static libraries don't play nicely with cc-built executables when
Packit fd8b60
   it comes to static constructors, just as long as it doesn't cause
Packit fd8b60
   linking to fail.
Packit fd8b60
Packit fd8b60
   For dynamic libraries on UNIX, we'll use pthread_once-type support
Packit fd8b60
   to do delayed initialization, so if finalization can't be made to
Packit fd8b60
   work, we'll only have memory leaks in a load/use/unload cycle.  If
Packit fd8b60
   anyone (like, say, the OS vendor) complains about this, they can
Packit fd8b60
   tell us how to get a shared library finalization function invoked
Packit fd8b60
   automatically.
Packit fd8b60
Packit fd8b60
   Currently there's --disable-delayed-initialization for preventing
Packit fd8b60
   the initialization from being delayed on UNIX, but that's mainly
Packit fd8b60
   just for testing the linker options for initialization, and will
Packit fd8b60
   probably be removed at some point.  */
Packit fd8b60
Packit fd8b60
/* Helper macros.  */
Packit fd8b60
Packit fd8b60
# define JOIN__2_2(A,B) A ## _ ## _ ## B
Packit fd8b60
# define JOIN__2(A,B) JOIN__2_2(A,B)
Packit fd8b60
Packit fd8b60
/* XXX Should test USE_LINKER_INIT_OPTION early, and if it's set,
Packit fd8b60
   always provide a function by the expected name, even if we're
Packit fd8b60
   delaying initialization.  */
Packit fd8b60
Packit fd8b60
#if defined(DELAY_INITIALIZER)
Packit fd8b60
Packit fd8b60
/* Run the initialization code during program execution, at the latest
Packit fd8b60
   possible moment.  This means multiple threads may be active.  */
Packit fd8b60
# include "k5-thread.h"
Packit fd8b60
typedef struct { k5_once_t once; int error, did_run; void (*fn)(void); } k5_init_t;
Packit fd8b60
# ifdef USE_LINKER_INIT_OPTION
Packit fd8b60
#  define MAYBE_DUMMY_INIT(NAME)                \
Packit fd8b60
        void JOIN__2(NAME, auxinit) () { }
Packit fd8b60
# else
Packit fd8b60
#  define MAYBE_DUMMY_INIT(NAME)
Packit fd8b60
# endif
Packit fd8b60
# ifdef __GNUC__
Packit fd8b60
/* Do it in macro form so we get the file/line of the invocation if
Packit fd8b60
   the assertion fails.  */
Packit fd8b60
#  define k5_call_init_function(I)                                      \
Packit fd8b60
        (__extension__ ({                                               \
Packit fd8b60
                k5_init_t *k5int_i = (I);                               \
Packit fd8b60
                int k5int_err = k5_once(&k5int_i->once, k5int_i->fn);   \
Packit fd8b60
                (k5int_err                                              \
Packit fd8b60
                 ? k5int_err                                            \
Packit fd8b60
                 : (assert(k5int_i->did_run != 0), k5int_i->error));    \
Packit fd8b60
            }))
Packit fd8b60
#  define MAYBE_DEFINE_CALLINIT_FUNCTION
Packit fd8b60
# else
Packit fd8b60
#  define MAYBE_DEFINE_CALLINIT_FUNCTION                        \
Packit fd8b60
        static inline int k5_call_init_function(k5_init_t *i)   \
Packit fd8b60
        {                                                       \
Packit fd8b60
            int err;                                            \
Packit fd8b60
            err = k5_once(&i->once, i->fn);                     \
Packit fd8b60
            if (err)                                            \
Packit fd8b60
                return err;                                     \
Packit fd8b60
            assert (i->did_run != 0);                           \
Packit fd8b60
            return i->error;                                    \
Packit fd8b60
        }
Packit fd8b60
# endif
Packit fd8b60
# define MAKE_INIT_FUNCTION(NAME)                               \
Packit fd8b60
        static int NAME(void);                                  \
Packit fd8b60
        MAYBE_DUMMY_INIT(NAME)                                  \
Packit fd8b60
        /* forward declaration for use in initializer */        \
Packit fd8b60
        static void JOIN__2(NAME, aux) (void);                  \
Packit fd8b60
        static k5_init_t JOIN__2(NAME, once) =                  \
Packit fd8b60
                { K5_ONCE_INIT, 0, 0, JOIN__2(NAME, aux) };     \
Packit fd8b60
        MAYBE_DEFINE_CALLINIT_FUNCTION                          \
Packit fd8b60
        static void JOIN__2(NAME, aux) (void)                   \
Packit fd8b60
        {                                                       \
Packit fd8b60
            JOIN__2(NAME, once).did_run = 1;                    \
Packit fd8b60
            JOIN__2(NAME, once).error = NAME();                 \
Packit fd8b60
        }                                                       \
Packit fd8b60
        /* so ';' following macro use won't get error */        \
Packit fd8b60
        static int NAME(void)
Packit fd8b60
# define CALL_INIT_FUNCTION(NAME)       \
Packit fd8b60
        k5_call_init_function(& JOIN__2(NAME, once))
Packit fd8b60
/* This should be called in finalization only, so we shouldn't have
Packit fd8b60
   multiple active threads mucking around in our library at this
Packit fd8b60
   point.  So ignore the once_t object and just look at the flag.
Packit fd8b60
Packit fd8b60
   XXX Could we have problems with memory coherence between processors
Packit fd8b60
   if we don't invoke mutex/once routines?  Probably not, the
Packit fd8b60
   application code should already be coordinating things such that
Packit fd8b60
   the library code is not in use by this point, and memory
Packit fd8b60
   synchronization will be needed there.  */
Packit fd8b60
# define INITIALIZER_RAN(NAME)  \
Packit fd8b60
        (JOIN__2(NAME, once).did_run && JOIN__2(NAME, once).error == 0)
Packit fd8b60
Packit fd8b60
# define PROGRAM_EXITING()              (0)
Packit fd8b60
Packit fd8b60
#elif defined(__GNUC__) && !defined(_WIN32) && defined(CONSTRUCTOR_ATTR_WORKS)
Packit fd8b60
Packit fd8b60
/* Run initializer at load time, via GCC/C++ hook magic.  */
Packit fd8b60
Packit fd8b60
# ifdef USE_LINKER_INIT_OPTION
Packit fd8b60
     /* Both gcc and linker option??  Favor gcc.  */
Packit fd8b60
#  define MAYBE_DUMMY_INIT(NAME)                \
Packit fd8b60
        void JOIN__2(NAME, auxinit) () { }
Packit fd8b60
# else
Packit fd8b60
#  define MAYBE_DUMMY_INIT(NAME)
Packit fd8b60
# endif
Packit fd8b60
Packit fd8b60
typedef struct { int error; unsigned char did_run; } k5_init_t;
Packit fd8b60
# define MAKE_INIT_FUNCTION(NAME)               \
Packit fd8b60
        MAYBE_DUMMY_INIT(NAME)                  \
Packit fd8b60
        static k5_init_t JOIN__2(NAME, ran)     \
Packit fd8b60
                = { 0, 2 };                     \
Packit fd8b60
        static void JOIN__2(NAME, aux)(void)    \
Packit fd8b60
            __attribute__((constructor));       \
Packit fd8b60
        static int NAME(void);                  \
Packit fd8b60
        static void JOIN__2(NAME, aux)(void)    \
Packit fd8b60
        {                                       \
Packit fd8b60
            JOIN__2(NAME, ran).error = NAME();  \
Packit fd8b60
            JOIN__2(NAME, ran).did_run = 3;     \
Packit fd8b60
        }                                       \
Packit fd8b60
        static int NAME(void)
Packit fd8b60
# define CALL_INIT_FUNCTION(NAME)               \
Packit fd8b60
        (JOIN__2(NAME, ran).did_run == 3        \
Packit fd8b60
         ? JOIN__2(NAME, ran).error             \
Packit fd8b60
         : (abort(),0))
Packit fd8b60
# define INITIALIZER_RAN(NAME)  (JOIN__2(NAME,ran).did_run == 3 && JOIN__2(NAME, ran).error == 0)
Packit fd8b60
Packit fd8b60
# define PROGRAM_EXITING()              (0)
Packit fd8b60
Packit fd8b60
#elif defined(USE_LINKER_INIT_OPTION) || defined(_WIN32)
Packit fd8b60
Packit fd8b60
/* Run initializer at load time, via linker magic, or in the
Packit fd8b60
   case of WIN32, win_glue.c hard-coded knowledge.  */
Packit fd8b60
typedef struct { int error; unsigned char did_run; } k5_init_t;
Packit fd8b60
# define MAKE_INIT_FUNCTION(NAME)               \
Packit fd8b60
        static k5_init_t JOIN__2(NAME, ran)     \
Packit fd8b60
                = { 0, 2 };                     \
Packit fd8b60
        static int NAME(void);                  \
Packit fd8b60
        void JOIN__2(NAME, auxinit)()           \
Packit fd8b60
        {                                       \
Packit fd8b60
            JOIN__2(NAME, ran).error = NAME();  \
Packit fd8b60
            JOIN__2(NAME, ran).did_run = 3;     \
Packit fd8b60
        }                                       \
Packit fd8b60
        static int NAME(void)
Packit fd8b60
# define CALL_INIT_FUNCTION(NAME)               \
Packit fd8b60
        (JOIN__2(NAME, ran).did_run == 3        \
Packit fd8b60
         ? JOIN__2(NAME, ran).error             \
Packit fd8b60
         : (abort(),0))
Packit fd8b60
# define INITIALIZER_RAN(NAME)  \
Packit fd8b60
        (JOIN__2(NAME, ran).error == 0)
Packit fd8b60
Packit fd8b60
# define PROGRAM_EXITING()              (0)
Packit fd8b60
Packit fd8b60
#else
Packit fd8b60
Packit fd8b60
# error "Don't know how to do load-time initializers for this configuration."
Packit fd8b60
Packit fd8b60
# define PROGRAM_EXITING()              (0)
Packit fd8b60
Packit fd8b60
#endif
Packit fd8b60
Packit fd8b60
Packit fd8b60
Packit fd8b60
#if defined(USE_LINKER_FINI_OPTION) || defined(_WIN32)
Packit fd8b60
/* If we're told the linker option will be used, it doesn't really
Packit fd8b60
   matter what compiler we're using.  Do it the same way
Packit fd8b60
   regardless.  */
Packit fd8b60
Packit fd8b60
# ifdef __hpux
Packit fd8b60
Packit fd8b60
     /* On HP-UX, we need this auxiliary function.  At dynamic load or
Packit fd8b60
        unload time (but *not* program startup and termination for
Packit fd8b60
        link-time specified libraries), the linker-indicated function
Packit fd8b60
        is called with a handle on the library and a flag indicating
Packit fd8b60
        whether it's being loaded or unloaded.
Packit fd8b60
Packit fd8b60
        The "real" fini function doesn't need to be exported, so
Packit fd8b60
        declare it static.
Packit fd8b60
Packit fd8b60
        As usual, the final declaration is just for syntactic
Packit fd8b60
        convenience, so the top-level invocation of this macro can be
Packit fd8b60
        followed by a semicolon.  */
Packit fd8b60
Packit fd8b60
#  include <dl.h>
Packit fd8b60
#  define MAKE_FINI_FUNCTION(NAME)                                          \
Packit fd8b60
        static void NAME(void);                                             \
Packit fd8b60
        void JOIN__2(NAME, auxfini)(shl_t, int); /* silence gcc warnings */ \
Packit fd8b60
        void JOIN__2(NAME, auxfini)(shl_t h, int l) { if (!l) NAME(); }     \
Packit fd8b60
        static void NAME(void)
Packit fd8b60
Packit fd8b60
# else /* not hpux */
Packit fd8b60
Packit fd8b60
#  define MAKE_FINI_FUNCTION(NAME)      \
Packit fd8b60
        void NAME(void)
Packit fd8b60
Packit fd8b60
# endif
Packit fd8b60
Packit fd8b60
#elif !defined(SHARED)
Packit fd8b60
Packit fd8b60
/*
Packit fd8b60
 * In this case, we just don't care about finalization.  The code will still
Packit fd8b60
 * define the function, but we won't do anything with it.
Packit fd8b60
 */
Packit fd8b60
# define MAKE_FINI_FUNCTION(NAME)               \
Packit fd8b60
        static void NAME(void) UNUSED
Packit fd8b60
Packit fd8b60
#elif defined(__GNUC__) && defined(DESTRUCTOR_ATTR_WORKS)
Packit fd8b60
/* If we're using gcc, if the C++ support works, the compiler should
Packit fd8b60
   build executables and shared libraries that support the use of
Packit fd8b60
   static constructors and destructors.  The C compiler supports a
Packit fd8b60
   function attribute that makes use of the same facility as C++.
Packit fd8b60
Packit fd8b60
   XXX How do we know if the C++ support actually works?  */
Packit fd8b60
# define MAKE_FINI_FUNCTION(NAME)       \
Packit fd8b60
        static void NAME(void) __attribute__((destructor))
Packit fd8b60
Packit fd8b60
#else
Packit fd8b60
Packit fd8b60
# error "Don't know how to do unload-time finalization for this configuration."
Packit fd8b60
Packit fd8b60
#endif
Packit fd8b60
Packit fd8b60
#ifndef SIZE_MAX
Packit fd8b60
# define SIZE_MAX ((size_t)((size_t)0 - 1))
Packit fd8b60
#endif
Packit fd8b60
Packit fd8b60
#ifdef _WIN32
Packit fd8b60
# define SSIZE_MAX ((ssize_t)(SIZE_MAX/2))
Packit fd8b60
#endif
Packit fd8b60
Packit fd8b60
/* Read and write integer values as (unaligned) octet strings in
Packit fd8b60
   specific byte orders.  Add per-platform optimizations as
Packit fd8b60
   needed.  */
Packit fd8b60
Packit fd8b60
#if HAVE_ENDIAN_H
Packit fd8b60
# include <endian.h>
Packit fd8b60
#elif HAVE_MACHINE_ENDIAN_H
Packit fd8b60
# include <machine/endian.h>
Packit fd8b60
#endif
Packit fd8b60
/* Check for BIG/LITTLE_ENDIAN macros.  If exactly one is defined, use
Packit fd8b60
   it.  If both are defined, then BYTE_ORDER should be defined and
Packit fd8b60
   match one of them.  Try those symbols, then try again with an
Packit fd8b60
   underscore prefix.  */
Packit fd8b60
#if defined(BIG_ENDIAN) && defined(LITTLE_ENDIAN)
Packit fd8b60
# if BYTE_ORDER == BIG_ENDIAN
Packit fd8b60
#  define K5_BE
Packit fd8b60
# endif
Packit fd8b60
# if BYTE_ORDER == LITTLE_ENDIAN
Packit fd8b60
#  define K5_LE
Packit fd8b60
# endif
Packit fd8b60
#elif defined(BIG_ENDIAN)
Packit fd8b60
# define K5_BE
Packit fd8b60
#elif defined(LITTLE_ENDIAN)
Packit fd8b60
# define K5_LE
Packit fd8b60
#elif defined(_BIG_ENDIAN) && defined(_LITTLE_ENDIAN)
Packit fd8b60
# if _BYTE_ORDER == _BIG_ENDIAN
Packit fd8b60
#  define K5_BE
Packit fd8b60
# endif
Packit fd8b60
# if _BYTE_ORDER == _LITTLE_ENDIAN
Packit fd8b60
#  define K5_LE
Packit fd8b60
# endif
Packit fd8b60
#elif defined(_BIG_ENDIAN)
Packit fd8b60
# define K5_BE
Packit fd8b60
#elif defined(_LITTLE_ENDIAN)
Packit fd8b60
# define K5_LE
Packit fd8b60
#elif defined(__BIG_ENDIAN__) && !defined(__LITTLE_ENDIAN__)
Packit fd8b60
# define K5_BE
Packit fd8b60
#elif defined(__LITTLE_ENDIAN__) && !defined(__BIG_ENDIAN__)
Packit fd8b60
# define K5_LE
Packit fd8b60
#endif
Packit fd8b60
#if !defined(K5_BE) && !defined(K5_LE)
Packit fd8b60
/* Look for some architectures we know about.
Packit fd8b60
Packit fd8b60
   MIPS can use either byte order, but the preprocessor tells us which
Packit fd8b60
   mode we're compiling for.  The GCC config files indicate that
Packit fd8b60
   variants of Alpha and IA64 might be out there with both byte
Packit fd8b60
   orders, but until we encounter the "wrong" ones in the real world,
Packit fd8b60
   just go with the default (unless there are cpp predefines to help
Packit fd8b60
   us there too).
Packit fd8b60
Packit fd8b60
   As far as I know, only PDP11 and ARM (which we don't handle here)
Packit fd8b60
   have strange byte orders where an 8-byte value isn't laid out as
Packit fd8b60
   either 12345678 or 87654321.  */
Packit fd8b60
# if defined(__i386__) || defined(_MIPSEL) || defined(__alpha__) || (defined(__ia64__) && !defined(__hpux))
Packit fd8b60
#  define K5_LE
Packit fd8b60
# endif
Packit fd8b60
# if defined(__hppa__) || defined(__rs6000__) || defined(__sparc__) || defined(_MIPSEB) || defined(__m68k__) || defined(__sparc64__) || defined(__ppc__) || defined(__ppc64__) || (defined(__hpux) && defined(__ia64__))
Packit fd8b60
#  define K5_BE
Packit fd8b60
# endif
Packit fd8b60
#endif
Packit fd8b60
#if defined(K5_BE) && defined(K5_LE)
Packit fd8b60
# error "oops, check the byte order macros"
Packit fd8b60
#endif
Packit fd8b60
Packit fd8b60
/* Optimize for GCC on platforms with known byte orders.
Packit fd8b60
Packit fd8b60
   GCC's packed structures can be written to with any alignment; the
Packit fd8b60
   compiler will use byte operations, unaligned-word operations, or
Packit fd8b60
   normal memory ops as appropriate for the architecture.
Packit fd8b60
Packit fd8b60
   This assumes the availability of uint##_t types, which should work
Packit fd8b60
   on most of our platforms except Windows, where we're not using
Packit fd8b60
   GCC.  */
Packit fd8b60
#ifdef __GNUC__
Packit fd8b60
# define PUT(SIZE,PTR,VAL)      (((struct { uint##SIZE##_t i; } __attribute__((packed)) *)(PTR))->i = (VAL))
Packit fd8b60
# define GET(SIZE,PTR)          (((const struct { uint##SIZE##_t i; } __attribute__((packed)) *)(PTR))->i)
Packit fd8b60
# define PUTSWAPPED(SIZE,PTR,VAL)       PUT(SIZE,PTR,SWAP##SIZE(VAL))
Packit fd8b60
# define GETSWAPPED(SIZE,PTR)           SWAP##SIZE(GET(SIZE,PTR))
Packit fd8b60
#endif
Packit fd8b60
/* To do: Define SWAP16, SWAP32, SWAP64 macros to byte-swap values
Packit fd8b60
   with the indicated numbers of bits.
Packit fd8b60
Packit fd8b60
   Linux: byteswap.h, bswap_16 etc.
Packit fd8b60
   Solaris 10: none
Packit fd8b60
   macOS: machine/endian.h or byte_order.h, NXSwap{Short,Int,LongLong}
Packit fd8b60
   NetBSD: sys/bswap.h, bswap16 etc.  */
Packit fd8b60
Packit fd8b60
#if defined(HAVE_BYTESWAP_H) && defined(HAVE_BSWAP_16)
Packit fd8b60
# include <byteswap.h>
Packit fd8b60
# define SWAP16                 bswap_16
Packit fd8b60
# define SWAP32                 bswap_32
Packit fd8b60
# ifdef HAVE_BSWAP_64
Packit fd8b60
#  define SWAP64                bswap_64
Packit fd8b60
# endif
Packit fd8b60
#elif TARGET_OS_MAC
Packit fd8b60
# include <architecture/byte_order.h>
Packit fd8b60
# define SWAP16                k5_swap16
Packit fd8b60
static inline unsigned int k5_swap16 (unsigned int x) {
Packit fd8b60
    x &= 0xffff;
Packit fd8b60
    return (x >> 8) | ((x & 0xff) << 8);
Packit fd8b60
}
Packit fd8b60
# define SWAP32                 OSSwapInt32
Packit fd8b60
# define SWAP64                 OSSwapInt64
Packit fd8b60
#elif defined(HAVE_SYS_BSWAP_H)
Packit fd8b60
/* XXX NetBSD/x86 5.0.1 defines bswap16 and bswap32 as inline
Packit fd8b60
   functions only, so autoconf doesn't pick up on their existence.
Packit fd8b60
   So, no feature macro test for them here.  The 64-bit version isn't
Packit fd8b60
   inline at all, though, for whatever reason.  */
Packit fd8b60
# include <sys/bswap.h>
Packit fd8b60
# define SWAP16                 bswap16
Packit fd8b60
# define SWAP32                 bswap32
Packit fd8b60
/* However, bswap64 causes lots of warnings about 'long long'
Packit fd8b60
   constants; probably only on 32-bit platforms.  */
Packit fd8b60
# if LONG_MAX > 0x7fffffffL
Packit fd8b60
#  define SWAP64                bswap64
Packit fd8b60
# endif
Packit fd8b60
#endif
Packit fd8b60
Packit fd8b60
/* Note that on Windows at least this file can be included from C++
Packit fd8b60
   source, so casts *from* void* are required.  */
Packit fd8b60
static inline void
Packit fd8b60
store_16_be (unsigned int val, void *vp)
Packit fd8b60
{
Packit fd8b60
    unsigned char *p = (unsigned char *) vp;
Packit fd8b60
#if defined(__GNUC__) && defined(K5_BE) && !defined(__cplusplus)
Packit fd8b60
    PUT(16,p,val);
Packit fd8b60
#elif defined(__GNUC__) && defined(K5_LE) && defined(SWAP16) && !defined(__cplusplus)
Packit fd8b60
    PUTSWAPPED(16,p,val);
Packit fd8b60
#else
Packit fd8b60
    p[0] = (val >>  8) & 0xff;
Packit fd8b60
    p[1] = (val      ) & 0xff;
Packit fd8b60
#endif
Packit fd8b60
}
Packit fd8b60
static inline void
Packit fd8b60
store_32_be (unsigned int val, void *vp)
Packit fd8b60
{
Packit fd8b60
    unsigned char *p = (unsigned char *) vp;
Packit fd8b60
#if defined(__GNUC__) && defined(K5_BE) && !defined(__cplusplus)
Packit fd8b60
    PUT(32,p,val);
Packit fd8b60
#elif defined(__GNUC__) && defined(K5_LE) && defined(SWAP32) && !defined(__cplusplus)
Packit fd8b60
    PUTSWAPPED(32,p,val);
Packit fd8b60
#else
Packit fd8b60
    p[0] = (val >> 24) & 0xff;
Packit fd8b60
    p[1] = (val >> 16) & 0xff;
Packit fd8b60
    p[2] = (val >>  8) & 0xff;
Packit fd8b60
    p[3] = (val      ) & 0xff;
Packit fd8b60
#endif
Packit fd8b60
}
Packit fd8b60
static inline void
Packit fd8b60
store_64_be (uint64_t val, void *vp)
Packit fd8b60
{
Packit fd8b60
    unsigned char *p = (unsigned char *) vp;
Packit fd8b60
#if defined(__GNUC__) && defined(K5_BE) && !defined(__cplusplus)
Packit fd8b60
    PUT(64,p,val);
Packit fd8b60
#elif defined(__GNUC__) && defined(K5_LE) && defined(SWAP64) && !defined(__cplusplus)
Packit fd8b60
    PUTSWAPPED(64,p,val);
Packit fd8b60
#else
Packit fd8b60
    p[0] = (unsigned char)((val >> 56) & 0xff);
Packit fd8b60
    p[1] = (unsigned char)((val >> 48) & 0xff);
Packit fd8b60
    p[2] = (unsigned char)((val >> 40) & 0xff);
Packit fd8b60
    p[3] = (unsigned char)((val >> 32) & 0xff);
Packit fd8b60
    p[4] = (unsigned char)((val >> 24) & 0xff);
Packit fd8b60
    p[5] = (unsigned char)((val >> 16) & 0xff);
Packit fd8b60
    p[6] = (unsigned char)((val >>  8) & 0xff);
Packit fd8b60
    p[7] = (unsigned char)((val      ) & 0xff);
Packit fd8b60
#endif
Packit fd8b60
}
Packit fd8b60
static inline unsigned short
Packit fd8b60
load_16_be (const void *cvp)
Packit fd8b60
{
Packit fd8b60
    const unsigned char *p = (const unsigned char *) cvp;
Packit fd8b60
#if defined(__GNUC__) && defined(K5_BE) && !defined(__cplusplus)
Packit fd8b60
    return GET(16,p);
Packit fd8b60
#elif defined(__GNUC__) && defined(K5_LE) && defined(SWAP16) && !defined(__cplusplus)
Packit fd8b60
    return GETSWAPPED(16,p);
Packit fd8b60
#else
Packit fd8b60
    return (p[1] | (p[0] << 8));
Packit fd8b60
#endif
Packit fd8b60
}
Packit fd8b60
static inline unsigned int
Packit fd8b60
load_32_be (const void *cvp)
Packit fd8b60
{
Packit fd8b60
    const unsigned char *p = (const unsigned char *) cvp;
Packit fd8b60
#if defined(__GNUC__) && defined(K5_BE) && !defined(__cplusplus)
Packit fd8b60
    return GET(32,p);
Packit fd8b60
#elif defined(__GNUC__) && defined(K5_LE) && defined(SWAP32) && !defined(__cplusplus)
Packit fd8b60
    return GETSWAPPED(32,p);
Packit fd8b60
#else
Packit fd8b60
    return (p[3] | (p[2] << 8)
Packit fd8b60
            | ((uint32_t) p[1] << 16)
Packit fd8b60
            | ((uint32_t) p[0] << 24));
Packit fd8b60
#endif
Packit fd8b60
}
Packit fd8b60
static inline uint64_t
Packit fd8b60
load_64_be (const void *cvp)
Packit fd8b60
{
Packit fd8b60
    const unsigned char *p = (const unsigned char *) cvp;
Packit fd8b60
#if defined(__GNUC__) && defined(K5_BE) && !defined(__cplusplus)
Packit fd8b60
    return GET(64,p);
Packit fd8b60
#elif defined(__GNUC__) && defined(K5_LE) && defined(SWAP64) && !defined(__cplusplus)
Packit fd8b60
    return GETSWAPPED(64,p);
Packit fd8b60
#else
Packit fd8b60
    return ((uint64_t)load_32_be(p) << 32) | load_32_be(p+4);
Packit fd8b60
#endif
Packit fd8b60
}
Packit fd8b60
static inline void
Packit fd8b60
store_16_le (unsigned int val, void *vp)
Packit fd8b60
{
Packit fd8b60
    unsigned char *p = (unsigned char *) vp;
Packit fd8b60
#if defined(__GNUC__) && defined(K5_LE) && !defined(__cplusplus)
Packit fd8b60
    PUT(16,p,val);
Packit fd8b60
#elif defined(__GNUC__) && defined(K5_BE) && defined(SWAP16) && !defined(__cplusplus)
Packit fd8b60
    PUTSWAPPED(16,p,val);
Packit fd8b60
#else
Packit fd8b60
    p[1] = (val >>  8) & 0xff;
Packit fd8b60
    p[0] = (val      ) & 0xff;
Packit fd8b60
#endif
Packit fd8b60
}
Packit fd8b60
static inline void
Packit fd8b60
store_32_le (unsigned int val, void *vp)
Packit fd8b60
{
Packit fd8b60
    unsigned char *p = (unsigned char *) vp;
Packit fd8b60
#if defined(__GNUC__) && defined(K5_LE) && !defined(__cplusplus)
Packit fd8b60
    PUT(32,p,val);
Packit fd8b60
#elif defined(__GNUC__) && defined(K5_BE) && defined(SWAP32) && !defined(__cplusplus)
Packit fd8b60
    PUTSWAPPED(32,p,val);
Packit fd8b60
#else
Packit fd8b60
    p[3] = (val >> 24) & 0xff;
Packit fd8b60
    p[2] = (val >> 16) & 0xff;
Packit fd8b60
    p[1] = (val >>  8) & 0xff;
Packit fd8b60
    p[0] = (val      ) & 0xff;
Packit fd8b60
#endif
Packit fd8b60
}
Packit fd8b60
static inline void
Packit fd8b60
store_64_le (uint64_t val, void *vp)
Packit fd8b60
{
Packit fd8b60
    unsigned char *p = (unsigned char *) vp;
Packit fd8b60
#if defined(__GNUC__) && defined(K5_LE) && !defined(__cplusplus)
Packit fd8b60
    PUT(64,p,val);
Packit fd8b60
#elif defined(__GNUC__) && defined(K5_BE) && defined(SWAP64) && !defined(__cplusplus)
Packit fd8b60
    PUTSWAPPED(64,p,val);
Packit fd8b60
#else
Packit fd8b60
    p[7] = (unsigned char)((val >> 56) & 0xff);
Packit fd8b60
    p[6] = (unsigned char)((val >> 48) & 0xff);
Packit fd8b60
    p[5] = (unsigned char)((val >> 40) & 0xff);
Packit fd8b60
    p[4] = (unsigned char)((val >> 32) & 0xff);
Packit fd8b60
    p[3] = (unsigned char)((val >> 24) & 0xff);
Packit fd8b60
    p[2] = (unsigned char)((val >> 16) & 0xff);
Packit fd8b60
    p[1] = (unsigned char)((val >>  8) & 0xff);
Packit fd8b60
    p[0] = (unsigned char)((val      ) & 0xff);
Packit fd8b60
#endif
Packit fd8b60
}
Packit fd8b60
static inline unsigned short
Packit fd8b60
load_16_le (const void *cvp)
Packit fd8b60
{
Packit fd8b60
    const unsigned char *p = (const unsigned char *) cvp;
Packit fd8b60
#if defined(__GNUC__) && defined(K5_LE) && !defined(__cplusplus)
Packit fd8b60
    return GET(16,p);
Packit fd8b60
#elif defined(__GNUC__) && defined(K5_BE) && defined(SWAP16) && !defined(__cplusplus)
Packit fd8b60
    return GETSWAPPED(16,p);
Packit fd8b60
#else
Packit fd8b60
    return (p[0] | (p[1] << 8));
Packit fd8b60
#endif
Packit fd8b60
}
Packit fd8b60
static inline unsigned int
Packit fd8b60
load_32_le (const void *cvp)
Packit fd8b60
{
Packit fd8b60
    const unsigned char *p = (const unsigned char *) cvp;
Packit fd8b60
#if defined(__GNUC__) && defined(K5_LE) && !defined(__cplusplus)
Packit fd8b60
    return GET(32,p);
Packit fd8b60
#elif defined(__GNUC__) && defined(K5_BE) && defined(SWAP32) && !defined(__cplusplus)
Packit fd8b60
    return GETSWAPPED(32,p);
Packit fd8b60
#else
Packit fd8b60
    return (p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24));
Packit fd8b60
#endif
Packit fd8b60
}
Packit fd8b60
static inline uint64_t
Packit fd8b60
load_64_le (const void *cvp)
Packit fd8b60
{
Packit fd8b60
    const unsigned char *p = (const unsigned char *) cvp;
Packit fd8b60
#if defined(__GNUC__) && defined(K5_LE) && !defined(__cplusplus)
Packit fd8b60
    return GET(64,p);
Packit fd8b60
#elif defined(__GNUC__) && defined(K5_BE) && defined(SWAP64) && !defined(__cplusplus)
Packit fd8b60
    return GETSWAPPED(64,p);
Packit fd8b60
#else
Packit fd8b60
    return ((uint64_t)load_32_le(p+4) << 32) | load_32_le(p);
Packit fd8b60
#endif
Packit fd8b60
}
Packit fd8b60
Packit fd8b60
#define UINT16_TYPE uint16_t
Packit fd8b60
#define UINT32_TYPE uint32_t
Packit fd8b60
Packit fd8b60
static inline void
Packit fd8b60
store_16_n (unsigned int val, void *vp)
Packit fd8b60
{
Packit fd8b60
    UINT16_TYPE n = val;
Packit fd8b60
    memcpy(vp, &n, 2);
Packit fd8b60
}
Packit fd8b60
static inline void
Packit fd8b60
store_32_n (unsigned int val, void *vp)
Packit fd8b60
{
Packit fd8b60
    UINT32_TYPE n = val;
Packit fd8b60
    memcpy(vp, &n, 4);
Packit fd8b60
}
Packit fd8b60
static inline void
Packit fd8b60
store_64_n (uint64_t val, void *vp)
Packit fd8b60
{
Packit fd8b60
    uint64_t n = val;
Packit fd8b60
    memcpy(vp, &n, 8);
Packit fd8b60
}
Packit fd8b60
static inline unsigned short
Packit fd8b60
load_16_n (const void *p)
Packit fd8b60
{
Packit fd8b60
    UINT16_TYPE n;
Packit fd8b60
    memcpy(&n, p, 2);
Packit fd8b60
    return n;
Packit fd8b60
}
Packit fd8b60
static inline unsigned int
Packit fd8b60
load_32_n (const void *p)
Packit fd8b60
{
Packit fd8b60
    UINT32_TYPE n;
Packit fd8b60
    memcpy(&n, p, 4);
Packit fd8b60
    return n;
Packit fd8b60
}
Packit fd8b60
static inline uint64_t
Packit fd8b60
load_64_n (const void *p)
Packit fd8b60
{
Packit fd8b60
    uint64_t n;
Packit fd8b60
    memcpy(&n, p, 8);
Packit fd8b60
    return n;
Packit fd8b60
}
Packit fd8b60
#undef UINT16_TYPE
Packit fd8b60
#undef UINT32_TYPE
Packit fd8b60
Packit fd8b60
/* Assume for simplicity that these swaps are identical.  */
Packit fd8b60
static inline uint64_t
Packit fd8b60
k5_htonll (uint64_t val)
Packit fd8b60
{
Packit fd8b60
#ifdef K5_BE
Packit fd8b60
    return val;
Packit fd8b60
#elif defined K5_LE && defined SWAP64
Packit fd8b60
    return SWAP64 (val);
Packit fd8b60
#else
Packit fd8b60
    return load_64_be ((unsigned char *)&val;;
Packit fd8b60
#endif
Packit fd8b60
}
Packit fd8b60
static inline uint64_t
Packit fd8b60
k5_ntohll (uint64_t val)
Packit fd8b60
{
Packit fd8b60
    return k5_htonll (val);
Packit fd8b60
}
Packit fd8b60
Packit fd8b60
/* Make the interfaces to getpwnam and getpwuid consistent.
Packit fd8b60
   Model the wrappers on the POSIX thread-safe versions, but
Packit fd8b60
   use the unsafe system versions if the safe ones don't exist
Packit fd8b60
   or we can't figure out their interfaces.  */
Packit fd8b60
Packit fd8b60
/* int k5_getpwnam_r(const char *, blah blah) */
Packit fd8b60
#ifdef HAVE_GETPWNAM_R
Packit fd8b60
# ifndef GETPWNAM_R_4_ARGS
Packit fd8b60
/* POSIX */
Packit fd8b60
#  define k5_getpwnam_r(NAME, REC, BUF, BUFSIZE, OUT)   \
Packit fd8b60
        (getpwnam_r(NAME,REC,BUF,BUFSIZE,OUT) == 0      \
Packit fd8b60
         ? (*(OUT) == NULL ? -1 : 0) : -1)
Packit fd8b60
# else
Packit fd8b60
/* POSIX drafts? */
Packit fd8b60
#  ifdef GETPWNAM_R_RETURNS_INT
Packit fd8b60
#   define k5_getpwnam_r(NAME, REC, BUF, BUFSIZE, OUT)  \
Packit fd8b60
        (getpwnam_r(NAME,REC,BUF,BUFSIZE) == 0          \
Packit fd8b60
         ? (*(OUT) = REC, 0)                            \
Packit fd8b60
         : (*(OUT) = NULL, -1))
Packit fd8b60
#  else
Packit fd8b60
#   define k5_getpwnam_r(NAME, REC, BUF, BUFSIZE, OUT)  \
Packit fd8b60
        (*(OUT) = getpwnam_r(NAME,REC,BUF,BUFSIZE), *(OUT) == NULL ? -1 : 0)
Packit fd8b60
#  endif
Packit fd8b60
# endif
Packit fd8b60
#else /* no getpwnam_r, or can't figure out #args or return type */
Packit fd8b60
/* Will get warnings about unused variables.  */
Packit fd8b60
# define k5_getpwnam_r(NAME, REC, BUF, BUFSIZE, OUT) \
Packit fd8b60
        (*(OUT) = getpwnam(NAME), *(OUT) == NULL ? -1 : 0)
Packit fd8b60
#endif
Packit fd8b60
Packit fd8b60
/* int k5_getpwuid_r(uid_t, blah blah) */
Packit fd8b60
#ifdef HAVE_GETPWUID_R
Packit fd8b60
# ifndef GETPWUID_R_4_ARGS
Packit fd8b60
/* POSIX */
Packit fd8b60
#  define k5_getpwuid_r(UID, REC, BUF, BUFSIZE, OUT)    \
Packit fd8b60
        (getpwuid_r(UID,REC,BUF,BUFSIZE,OUT) == 0       \
Packit fd8b60
         ? (*(OUT) == NULL ? -1 : 0) : -1)
Packit fd8b60
# else
Packit fd8b60
/* POSIX drafts?  Yes, I mean to test GETPWNAM... here.  Less junk to
Packit fd8b60
   do at configure time.  */
Packit fd8b60
#  ifdef GETPWNAM_R_RETURNS_INT
Packit fd8b60
#   define k5_getpwuid_r(UID, REC, BUF, BUFSIZE, OUT)   \
Packit fd8b60
        (getpwuid_r(UID,REC,BUF,BUFSIZE) == 0           \
Packit fd8b60
         ? (*(OUT) = REC, 0)                            \
Packit fd8b60
         : (*(OUT) = NULL, -1))
Packit fd8b60
#  else
Packit fd8b60
#   define k5_getpwuid_r(UID, REC, BUF, BUFSIZE, OUT)  \
Packit fd8b60
        (*(OUT) = getpwuid_r(UID,REC,BUF,BUFSIZE), *(OUT) == NULL ? -1 : 0)
Packit fd8b60
#  endif
Packit fd8b60
# endif
Packit fd8b60
#else /* no getpwuid_r, or can't figure out #args or return type */
Packit fd8b60
/* Will get warnings about unused variables.  */
Packit fd8b60
# define k5_getpwuid_r(UID, REC, BUF, BUFSIZE, OUT) \
Packit fd8b60
        (*(OUT) = getpwuid(UID), *(OUT) == NULL ? -1 : 0)
Packit fd8b60
#endif
Packit fd8b60
Packit fd8b60
/* Ensure, if possible, that the indicated file descriptor won't be
Packit fd8b60
   kept open if we exec another process (e.g., launching a ccapi
Packit fd8b60
   server).  If we don't know how to do it... well, just go about our
Packit fd8b60
   business.  Probably most callers won't check the return status
Packit fd8b60
   anyways.  */
Packit fd8b60
Packit fd8b60
/* Macros make the Sun compiler happier, and all variants of this do a
Packit fd8b60
   single evaluation of the argument, and fcntl and fileno should
Packit fd8b60
   produce reasonable error messages on type mismatches, on any system
Packit fd8b60
   with F_SETFD.  */
Packit fd8b60
#ifdef F_SETFD
Packit fd8b60
# ifdef FD_CLOEXEC
Packit fd8b60
#  define set_cloexec_fd(FD)    ((void)fcntl((FD), F_SETFD, FD_CLOEXEC))
Packit fd8b60
# else
Packit fd8b60
#  define set_cloexec_fd(FD)    ((void)fcntl((FD), F_SETFD, 1))
Packit fd8b60
# endif
Packit fd8b60
#else
Packit fd8b60
# define set_cloexec_fd(FD)     ((void)(FD))
Packit fd8b60
#endif
Packit fd8b60
#define set_cloexec_file(F)     set_cloexec_fd(fileno(F))
Packit fd8b60
Packit fd8b60
/* Since the original ANSI C spec left it undefined whether or
Packit fd8b60
   how you could copy around a va_list, C 99 added va_copy.
Packit fd8b60
   For old implementations, let's do our best to fake it.
Packit fd8b60
Packit fd8b60
   XXX Doesn't yet handle implementations with __va_copy (early draft)
Packit fd8b60
   or GCC's __builtin_va_copy.  */
Packit fd8b60
#if defined(HAS_VA_COPY) || defined(va_copy)
Packit fd8b60
/* Do nothing.  */
Packit fd8b60
#elif defined(CAN_COPY_VA_LIST)
Packit fd8b60
#define va_copy(dest, src)      ((dest) = (src))
Packit fd8b60
#else
Packit fd8b60
/* Assume array type, but still simply copyable.
Packit fd8b60
Packit fd8b60
   There is, theoretically, the possibility that va_start will
Packit fd8b60
   allocate some storage pointed to by the va_list, and in that case
Packit fd8b60
   we'll just lose.  If anyone cares, we could try to devise a test
Packit fd8b60
   for that case.  */
Packit fd8b60
#define va_copy(dest, src)      memcpy(dest, src, sizeof(va_list))
Packit fd8b60
#endif
Packit fd8b60
Packit fd8b60
/* Provide strlcpy/strlcat interfaces. */
Packit fd8b60
#ifndef HAVE_STRLCPY
Packit fd8b60
#define strlcpy krb5int_strlcpy
Packit fd8b60
#define strlcat krb5int_strlcat
Packit fd8b60
extern size_t krb5int_strlcpy(char *dst, const char *src, size_t siz);
Packit fd8b60
extern size_t krb5int_strlcat(char *dst, const char *src, size_t siz);
Packit fd8b60
#endif
Packit fd8b60
Packit fd8b60
/* Provide fnmatch interface. */
Packit fd8b60
#ifndef HAVE_FNMATCH
Packit fd8b60
#define fnmatch k5_fnmatch
Packit fd8b60
int k5_fnmatch(const char *pattern, const char *string, int flags);
Packit fd8b60
#define FNM_NOMATCH     1       /* Match failed. */
Packit fd8b60
#define FNM_NOSYS       2       /* Function not implemented. */
Packit fd8b60
#define FNM_NORES       3       /* Out of resources */
Packit fd8b60
#define FNM_NOESCAPE    0x01    /* Disable backslash escaping. */
Packit fd8b60
#define FNM_PATHNAME    0x02    /* Slash must be matched by slash. */
Packit fd8b60
#define FNM_PERIOD      0x04    /* Period must be matched by period. */
Packit fd8b60
#define FNM_CASEFOLD    0x08    /* Pattern is matched case-insensitive */
Packit fd8b60
#define FNM_LEADING_DIR 0x10    /* Ignore /<tail> after Imatch. */
Packit fd8b60
#endif
Packit fd8b60
Packit fd8b60
/* Provide [v]asprintf interfaces.  */
Packit fd8b60
#ifndef HAVE_VSNPRINTF
Packit fd8b60
#ifdef _WIN32
Packit fd8b60
static inline int
Packit fd8b60
vsnprintf(char *str, size_t size, const char *format, va_list args)
Packit fd8b60
{
Packit fd8b60
    va_list args_copy;
Packit fd8b60
    int length;
Packit fd8b60
Packit fd8b60
    va_copy(args_copy, args);
Packit fd8b60
    length = _vscprintf(format, args_copy);
Packit fd8b60
    va_end(args_copy);
Packit fd8b60
    if (size > 0) {
Packit fd8b60
        _vsnprintf(str, size, format, args);
Packit fd8b60
        str[size - 1] = '\0';
Packit fd8b60
    }
Packit fd8b60
    return length;
Packit fd8b60
}
Packit fd8b60
static inline int
Packit fd8b60
snprintf(char *str, size_t size, const char *format, ...)
Packit fd8b60
{
Packit fd8b60
    va_list args;
Packit fd8b60
    int n;
Packit fd8b60
Packit fd8b60
    va_start(args, format);
Packit fd8b60
    n = vsnprintf(str, size, format, args);
Packit fd8b60
    va_end(args);
Packit fd8b60
    return n;
Packit fd8b60
}
Packit fd8b60
#else /* not win32 */
Packit fd8b60
#error We need an implementation of vsnprintf.
Packit fd8b60
#endif /* win32? */
Packit fd8b60
#endif /* no vsnprintf */
Packit fd8b60
Packit fd8b60
#ifndef HAVE_VASPRINTF
Packit fd8b60
Packit fd8b60
extern int krb5int_vasprintf(char **, const char *, va_list)
Packit fd8b60
#if !defined(__cplusplus) && (__GNUC__ > 2)
Packit fd8b60
    __attribute__((__format__(__printf__, 2, 0)))
Packit fd8b60
#endif
Packit fd8b60
    ;
Packit fd8b60
extern int krb5int_asprintf(char **, const char *, ...)
Packit fd8b60
#if !defined(__cplusplus) && (__GNUC__ > 2)
Packit fd8b60
    __attribute__((__format__(__printf__, 2, 3)))
Packit fd8b60
#endif
Packit fd8b60
    ;
Packit fd8b60
Packit fd8b60
#define vasprintf krb5int_vasprintf
Packit fd8b60
/* Assume HAVE_ASPRINTF iff HAVE_VASPRINTF.  */
Packit fd8b60
#define asprintf krb5int_asprintf
Packit fd8b60
Packit fd8b60
#elif defined(NEED_VASPRINTF_PROTO)
Packit fd8b60
Packit fd8b60
extern int vasprintf(char **, const char *, va_list)
Packit fd8b60
#if !defined(__cplusplus) && (__GNUC__ > 2)
Packit fd8b60
    __attribute__((__format__(__printf__, 2, 0)))
Packit fd8b60
#endif
Packit fd8b60
    ;
Packit fd8b60
extern int asprintf(char **, const char *, ...)
Packit fd8b60
#if !defined(__cplusplus) && (__GNUC__ > 2)
Packit fd8b60
    __attribute__((__format__(__printf__, 2, 3)))
Packit fd8b60
#endif
Packit fd8b60
    ;
Packit fd8b60
Packit fd8b60
#endif /* have vasprintf and prototype? */
Packit fd8b60
Packit fd8b60
/* Return true if the snprintf return value RESULT reflects a buffer
Packit fd8b60
   overflow for the buffer size SIZE.
Packit fd8b60
Packit fd8b60
   We cast the result to unsigned int for two reasons.  First, old
Packit fd8b60
   implementations of snprintf (such as the one in Solaris 9 and
Packit fd8b60
   prior) return -1 on a buffer overflow.  Casting the result to -1
Packit fd8b60
   will convert that value to UINT_MAX, which should compare larger
Packit fd8b60
   than any reasonable buffer size.  Second, comparing signed and
Packit fd8b60
   unsigned integers will generate warnings with some compilers, and
Packit fd8b60
   can have unpredictable results, particularly when the relative
Packit fd8b60
   widths of the types is not known (size_t may be the same width as
Packit fd8b60
   int or larger).
Packit fd8b60
*/
Packit fd8b60
#define SNPRINTF_OVERFLOW(result, size) \
Packit fd8b60
    ((unsigned int)(result) >= (size_t)(size))
Packit fd8b60
Packit fd8b60
#if defined(_WIN32) || !defined(HAVE_STRERROR_R) || defined(STRERROR_R_CHAR_P)
Packit fd8b60
#define strerror_r k5_strerror_r
Packit fd8b60
#endif
Packit fd8b60
extern int k5_strerror_r(int errnum, char *buf, size_t buflen);
Packit fd8b60
Packit fd8b60
#ifndef HAVE_MKSTEMP
Packit fd8b60
extern int krb5int_mkstemp(char *);
Packit fd8b60
#define mkstemp krb5int_mkstemp
Packit fd8b60
#endif
Packit fd8b60
Packit fd8b60
#ifndef HAVE_GETTIMEOFDAY
Packit fd8b60
extern int krb5int_gettimeofday(struct timeval *tp, void *ignore);
Packit fd8b60
#define gettimeofday krb5int_gettimeofday
Packit fd8b60
#endif
Packit fd8b60
Packit fd8b60
/*
Packit fd8b60
 * Attempt to zero memory in a way that compilers won't optimize out.
Packit fd8b60
 *
Packit fd8b60
 * This mechanism should work even for heap storage about to be freed,
Packit fd8b60
 * or automatic storage right before we return from a function.
Packit fd8b60
 *
Packit fd8b60
 * Then, even if we leak uninitialized memory someplace, or UNIX
Packit fd8b60
 * "core" files get created with world-read access, some of the most
Packit fd8b60
 * sensitive data in the process memory will already be safely wiped.
Packit fd8b60
 *
Packit fd8b60
 * We're not going so far -- yet -- as to try to protect key data that
Packit fd8b60
 * may have been written into swap space....
Packit fd8b60
 */
Packit fd8b60
#ifdef _WIN32
Packit fd8b60
# define zap(ptr, len) SecureZeroMemory(ptr, len)
Packit fd8b60
#elif defined(__STDC_LIB_EXT1__)
Packit fd8b60
/*
Packit fd8b60
 * Use memset_s() which cannot be optimized out.  Avoid memset_s(NULL, 0, 0, 0)
Packit fd8b60
 * which would cause a runtime constraint violation.
Packit fd8b60
 */
Packit fd8b60
static inline void zap(void *ptr, size_t len)
Packit fd8b60
{
Packit fd8b60
    if (len > 0)
Packit fd8b60
        memset_s(ptr, len, 0, len);
Packit fd8b60
}
Packit fd8b60
#elif defined(HAVE_EXPLICIT_BZERO)
Packit fd8b60
# define zap(ptr, len) explicit_bzero(ptr, len)
Packit fd8b60
#elif defined(HAVE_EXPLICIT_MEMSET)
Packit fd8b60
# define zap(ptr, len) explicit_memset(ptr, 0, len)
Packit fd8b60
#elif defined(__GNUC__) || defined(__clang__)
Packit fd8b60
/*
Packit fd8b60
 * Use an asm statement which declares a memory clobber to force the memset to
Packit fd8b60
 * be carried out.  Avoid memset(NULL, 0, 0) which has undefined behavior.
Packit fd8b60
 */
Packit fd8b60
static inline void zap(void *ptr, size_t len)
Packit fd8b60
{
Packit fd8b60
    if (len > 0)
Packit fd8b60
        memset(ptr, 0, len);
Packit fd8b60
    __asm__ __volatile__("" : : "g" (ptr) : "memory");
Packit fd8b60
}
Packit fd8b60
#else
Packit fd8b60
/*
Packit fd8b60
 * Use a function from libkrb5support to defeat inlining unless link-time
Packit fd8b60
 * optimization is used.  The function uses a volatile pointer, which prevents
Packit fd8b60
 * current compilers from optimizing out the memset.
Packit fd8b60
 */
Packit fd8b60
# define zap(ptr, len) krb5int_zap(ptr, len)
Packit fd8b60
#endif
Packit fd8b60
Packit fd8b60
extern void krb5int_zap(void *ptr, size_t len);
Packit fd8b60
Packit fd8b60
/*
Packit fd8b60
 * Return 0 if the n-byte memory regions p1 and p2 are equal, and nonzero if
Packit fd8b60
 * they are not.  The function is intended to take the same amount of time
Packit fd8b60
 * regardless of how many bytes of p1 and p2 are equal.
Packit fd8b60
 */
Packit fd8b60
int k5_bcmp(const void *p1, const void *p2, size_t n);
Packit fd8b60
Packit fd8b60
/*
Packit fd8b60
 * Split a path into parent directory and basename.  Either output parameter
Packit fd8b60
 * may be NULL if the caller doesn't need it.  parent_out will be empty if path
Packit fd8b60
 * has no basename.  basename_out will be empty if path ends with a path
Packit fd8b60
 * separator.  Returns 0 on success or ENOMEM on allocation failure.
Packit fd8b60
 */
Packit fd8b60
long k5_path_split(const char *path, char **parent_out, char **basename_out);
Packit fd8b60
Packit fd8b60
/*
Packit fd8b60
 * Compose two path components, inserting the platform-appropriate path
Packit fd8b60
 * separator if needed.  If path2 is an absolute path, path1 will be discarded
Packit fd8b60
 * and path_out will be a copy of path2.  Returns 0 on success or ENOMEM on
Packit fd8b60
 * allocation failure.
Packit fd8b60
 */
Packit fd8b60
long k5_path_join(const char *path1, const char *path2, char **path_out);
Packit fd8b60
Packit fd8b60
/* Return 1 if path is absolute, 0 if it is relative. */
Packit fd8b60
int k5_path_isabs(const char *path);
Packit fd8b60
Packit fd8b60
/*
Packit fd8b60
 * Localization macros.  If we have gettext, define _ appropriately for
Packit fd8b60
 * translating a string.  If we do not have gettext, define _ and
Packit fd8b60
 * bindtextdomain as no-ops.  N_ is always a no-op; it marks a string for
Packit fd8b60
 * extraction to pot files but does not translate it.
Packit fd8b60
 */
Packit fd8b60
#ifdef ENABLE_NLS
Packit fd8b60
#include <libintl.h>
Packit fd8b60
#define KRB5_TEXTDOMAIN "mit-krb5"
Packit fd8b60
#define _(s) dgettext(KRB5_TEXTDOMAIN, s)
Packit fd8b60
#else
Packit fd8b60
#define _(s) s
Packit fd8b60
#define dgettext(d, m) m
Packit fd8b60
#define ngettext(m1, m2, n) (((n) == 1) ? m1 : m2)
Packit fd8b60
#define bindtextdomain(p, d)
Packit fd8b60
#endif
Packit fd8b60
#define N_(s) s
Packit fd8b60
Packit fd8b60
#if !defined(HAVE_GETOPT) || !defined(HAVE_UNISTD_H)
Packit fd8b60
/* Data objects imported from DLLs must be declared as such on Windows. */
Packit fd8b60
#if defined(_WIN32) && !defined(K5_GETOPT_C)
Packit fd8b60
#define K5_GETOPT_DECL __declspec(dllimport)
Packit fd8b60
#else
Packit fd8b60
#define K5_GETOPT_DECL
Packit fd8b60
#endif
Packit fd8b60
K5_GETOPT_DECL extern int k5_opterr;
Packit fd8b60
K5_GETOPT_DECL extern int k5_optind;
Packit fd8b60
K5_GETOPT_DECL extern int k5_optopt;
Packit fd8b60
K5_GETOPT_DECL extern char *k5_optarg;
Packit fd8b60
#define opterr k5_opterr
Packit fd8b60
#define optind k5_optind
Packit fd8b60
#define optopt k5_optopt
Packit fd8b60
#define optarg k5_optarg
Packit fd8b60
Packit fd8b60
extern int k5_getopt(int nargc, char * const nargv[], const char *ostr);
Packit fd8b60
#define getopt k5_getopt
Packit fd8b60
#endif /* HAVE_GETOPT */
Packit fd8b60
Packit fd8b60
#ifdef HAVE_GETOPT_LONG
Packit fd8b60
#include <getopt.h>
Packit fd8b60
#else
Packit fd8b60
Packit fd8b60
struct option
Packit fd8b60
{
Packit fd8b60
  const char *name;
Packit fd8b60
  int has_arg;
Packit fd8b60
  int *flag;
Packit fd8b60
  int val;
Packit fd8b60
};
Packit fd8b60
Packit fd8b60
#define no_argument       0
Packit fd8b60
#define required_argument 1
Packit fd8b60
#define optional_argument 2
Packit fd8b60
Packit fd8b60
extern int k5_getopt_long(int nargc, char **nargv, char *options,
Packit fd8b60
                          struct option *long_options, int *index);
Packit fd8b60
#define getopt_long k5_getopt_long
Packit fd8b60
#endif /* HAVE_GETOPT_LONG */
Packit fd8b60
Packit fd8b60
#if defined(_WIN32)
Packit fd8b60
/* On Windows there is never a need to ignore the process environment. */
Packit fd8b60
#define secure_getenv getenv
Packit fd8b60
#elif !defined(HAVE_SECURE_GETENV)
Packit fd8b60
#define secure_getenv k5_secure_getenv
Packit fd8b60
extern char *k5_secure_getenv(const char *name);
Packit fd8b60
#endif
Packit fd8b60
Packit fd8b60
/* Set *fnames_out to a null-terminated list of filenames within dirname,
Packit fd8b60
 * sorted according to strcmp().  Return 0 on success, or ENOENT/ENOMEM. */
Packit fd8b60
int k5_dir_filenames(const char *dirname, char ***fnames_out);
Packit fd8b60
void k5_free_filenames(char **fnames);
Packit fd8b60
Packit fd8b60
#endif /* K5_PLATFORM_H */