diff options
Diffstat (limited to 'portable')
-rw-r--r-- | portable/asprintf.c | 6 | ||||
-rw-r--r-- | portable/dummy.c | 3 | ||||
-rw-r--r-- | portable/krb5-extra.c | 125 | ||||
-rw-r--r-- | portable/krb5.h | 83 | ||||
-rw-r--r-- | portable/macros.h | 3 | ||||
-rw-r--r-- | portable/mkstemp.c | 87 | ||||
-rw-r--r-- | portable/setenv.c | 61 | ||||
-rw-r--r-- | portable/snprintf.c | 10 | ||||
-rw-r--r-- | portable/stdbool.h | 7 | ||||
-rw-r--r-- | portable/strlcat.c | 3 | ||||
-rw-r--r-- | portable/strlcpy.c | 3 | ||||
-rw-r--r-- | portable/system.h | 39 | ||||
-rw-r--r-- | portable/uio.h | 27 |
13 files changed, 424 insertions, 33 deletions
diff --git a/portable/asprintf.c b/portable/asprintf.c index 9cae827..4219a19 100644 --- a/portable/asprintf.c +++ b/portable/asprintf.c @@ -1,5 +1,4 @@ -/* $Id$ - * +/* * Replacement for a missing asprintf and vasprintf. * * Provides the same functionality as the standard GNU library routines @@ -19,7 +18,8 @@ #if TESTING # define asprintf test_asprintf # define vasprintf test_vasprintf -int test_asprintf(char **, const char *, ...); +int test_asprintf(char **, const char *, ...) + __attribute__((__format__(printf, 2, 3))); int test_vasprintf(char **, const char *, va_list); #endif diff --git a/portable/dummy.c b/portable/dummy.c index 66341c3..8a0d54d 100644 --- a/portable/dummy.c +++ b/portable/dummy.c @@ -1,5 +1,4 @@ -/* $Id$ - * +/* * Dummy symbol to prevent an empty library. * * On platforms that already have all of the functions that libportable would diff --git a/portable/krb5-extra.c b/portable/krb5-extra.c new file mode 100644 index 0000000..afd00e8 --- /dev/null +++ b/portable/krb5-extra.c @@ -0,0 +1,125 @@ +/* + * Portability glue functions for Kerberos. + * + * This file provides definitions of the interfaces that portable/krb5.h + * ensures exist if the function wasn't available in the Kerberos libraries. + * Everything in this file will be protected by #ifndef. If the native + * Kerberos libraries are fully capable, this file will be skipped. + * + * Written by Russ Allbery <rra@stanford.edu> + * This work is hereby placed in the public domain by its author. + */ + +#include <config.h> +#include <portable/krb5.h> +#include <portable/system.h> + +#include <errno.h> + +/* Figure out what header files to include for error reporting. */ +#if !defined(HAVE_KRB5_GET_ERROR_MESSAGE) && !defined(HAVE_KRB5_GET_ERR_TEXT) +# if !defined(HAVE_KRB5_GET_ERROR_STRING) +# if defined(HAVE_IBM_SVC_KRB5_SVC_H) +# include <ibm_svc/krb5_svc.h> +# elif defined(HAVE_ET_COM_ERR_H) +# include <et/com_err.h> +# else +# include <com_err.h> +# endif +# endif +#endif + +/* Used for unused parameters to silence gcc warnings. */ +#define UNUSED __attribute__((__unused__)) + +/* + * This string is returned for unknown error messages. We use a static + * variable so that we can be sure not to free it. + */ +static const char error_unknown[] = "unknown error"; + + +#ifndef HAVE_KRB5_GET_ERROR_MESSAGE +/* + * Given a Kerberos error code, return the corresponding error. Prefer the + * Kerberos interface if available since it will provide context-specific + * error information, whereas the error_message() call will only provide a + * fixed message. + */ +const char * +krb5_get_error_message(krb5_context ctx UNUSED, krb5_error_code code UNUSED) +{ + const char *msg = NULL; + +# if defined(HAVE_KRB5_GET_ERROR_STRING) + msg = krb5_get_error_string(ctx); +# elif defined(HAVE_KRB5_GET_ERR_TEXT) + msg = krb5_get_err_text(ctx, code); +# elif defined(HAVE_KRB5_SVC_GET_MSG) + krb5_svc_get_msg(code, (char **) &msg); +# else + msg = error_message(code); +# endif + if (msg == NULL) + return error_unknown; + else + return msg; +} +#endif /* !HAVE_KRB5_GET_ERROR_MESSAGE */ + + +#ifndef HAVE_KRB5_FREE_ERROR_MESSAGE +/* + * Free an error string if necessary. If we returned a static string, make + * sure we don't free it. + * + * This code assumes that the set of implementations that have + * krb5_free_error_message is a subset of those with krb5_get_error_message. + * If this assumption ever breaks, we may call the wrong free function. + */ +static void +krb5_free_error_message(krb5_context ctx UNUSED, const char *msg) +{ + if (msg == error_unknown) + return; +# if defined(HAVE_KRB5_GET_ERROR_STRING) + krb5_free_error_string(ctx, (char *) msg); +# elif defined(HAVE_KRB5_SVC_GET_MSG) + krb5_free_string(ctx, (char *) msg); +# endif +} +#endif /* !HAVE_KRB5_FREE_ERROR_MESSAGE */ + + +#ifndef HAVE_KRB5_GET_INIT_CREDS_OPT_ALLOC +/* + * Allocate and initialize a krb5_get_init_creds_opt struct. This code + * assumes that an all-zero bit pattern will create a NULL pointer. + */ +krb5_error_code +krb5_get_init_creds_opt_alloc(krb5_context ctx, krb5_get_init_creds_opt **opts) +{ + *opts = calloc(1, sizeof(krb5_get_init_creds_opt)); + if (*opts == NULL) + return errno; + krb5_get_init_creds_opt_init(*opts); + return 0; +} +#endif /* !HAVE_KRB5_GET_INIT_CREDS_OPT_ALLOC */ + + +#ifndef HAVE_KRB5_PRINCIPAL_GET_REALM +/* + * Return the realm of a principal as a const char *. + */ +const char * +krb5_principal_get_realm(krb5_context ctx UNUSED, krb5_const_principal princ) +{ + const krb5_data *data; + + data = krb5_princ_realm(ctx, princ); + if (data == NULL || data->data == NULL) + return NULL; + return data->data; +} +#endif /* !HAVE_KRB5_PRINCIPAL_GET_REALM */ diff --git a/portable/krb5.h b/portable/krb5.h new file mode 100644 index 0000000..d9ef283 --- /dev/null +++ b/portable/krb5.h @@ -0,0 +1,83 @@ +/* + * Portability wrapper around krb5.h. + * + * This header includes krb5.h and then adjusts for various portability + * issues, primarily between MIT Kerberos and Heimdal, so that code can be + * written to a consistent API. + * + * Unfortunately, due to the nature of the differences between MIT Kerberos + * and Heimdal, it's not possible to write code to either one of the APIs and + * adjust for the other one. In general, this header tries to make available + * the Heimdal API and fix it for MIT Kerberos, but there are places where MIT + * Kerberos requires a more specific call. For those cases, it provides the + * most specific interface. + * + * For example, MIT Kerberos has krb5_free_unparsed_name() whereas Heimdal + * prefers the generic krb5_xfree(). In this case, this header provides + * krb5_free_unparsed_name() for both APIs since it's the most specific call. + * + * Written by Russ Allbery <rra@stanford.edu> + * This work is hereby placed in the public domain by its author. + */ + +#ifndef PORTABLE_KRB5_H +#define PORTABLE_KRB5_H 1 + +#include <config.h> +#include <portable/macros.h> + +#include <krb5.h> + +BEGIN_DECLS + +/* Default to a hidden visibility for all portability functions. */ +#pragma GCC visibility push(hidden) + +/* + * krb5_{get,free}_error_message are the preferred APIs for both current MIT + * and current Heimdal, but there are tons of older APIs we may have to fall + * back on for earlier versions. + * + * This function should be called immediately after the corresponding error + * without any intervening Kerberos calls. Otherwise, the correct error + * message and supporting information may not be returned. + */ +#ifndef HAVE_KRB5_GET_ERROR_MESSAGE +const char *krb5_get_error_message(krb5_context, krb5_error_code); +#endif +#ifndef HAVE_KRB5_FREE_ERROR_MESSAGE +void krb5_free_error_message(krb5_context, const char *); +#endif + +/* + * Both current MIT and current Heimdal prefer _opt_alloc, but older versions + * of both require allocating your own struct and calling _opt_init. + */ +#ifndef HAVE_KRB5_GET_INIT_CREDS_OPT_ALLOC +krb5_error_code krb5_get_init_creds_opt_alloc(krb5_context, + krb5_get_init_creds_opt **); +#endif + +/* Heimdal-specific. */ +#ifndef HAVE_KRB5_GET_INIT_CREDS_OPT_SET_DEFAULT_FLAGS +#define krb5_get_init_creds_opt_set_default_flags(c, p, r, o) /* empty */ +#endif + +/* Heimdal: krb5_kt_free_entry, MIT: krb5_free_keytab_entry_contents. */ +#ifndef HAVE_KRB5_KT_FREE_ENTRY +# define krb5_kt_free_entry(c, e) krb5_free_keytab_entry_contents((c), (e)) +#endif + +/* + * Heimdal provides a nice function that just returns a const char *. On MIT, + * there's an accessor macro that returns the krb5_data pointer, wihch + * requires more work to get at the underlying char *. + */ +#ifndef HAVE_KRB5_PRINCIPAL_GET_REALM +const char *krb5_principal_get_realm(krb5_context, krb5_const_principal); +#endif + +/* Undo default visibility change. */ +#pragma GCC visibility pop + +#endif /* !PORTABLE_KRB5_H */ diff --git a/portable/macros.h b/portable/macros.h index dcffa59..8d5adbd 100644 --- a/portable/macros.h +++ b/portable/macros.h @@ -1,5 +1,4 @@ -/* $Id$ - * +/* * Portability macros used in include files. * * Written by Russ Allbery <rra@stanford.edu> diff --git a/portable/mkstemp.c b/portable/mkstemp.c new file mode 100644 index 0000000..dd2a485 --- /dev/null +++ b/portable/mkstemp.c @@ -0,0 +1,87 @@ +/* + * Replacement for a missing mkstemp. + * + * Provides the same functionality as the library function mkstemp for those + * systems that don't have it. + * + * Written by Russ Allbery <rra@stanford.edu> + * This work is hereby placed in the public domain by its author. + */ + +#include <config.h> +#include <portable/system.h> + +#include <errno.h> +#include <fcntl.h> +#include <sys/time.h> + +/* + * If we're running the test suite, rename mkstemp to avoid conflicts with the + * system version. #undef it first because some systems may define it to + * another name. + */ +#if TESTING +# undef mkstemp +# define mkstemp test_mkstemp +int test_mkstemp(char *); +#endif + +/* Pick the longest available integer type. */ +#if HAVE_LONG_LONG +typedef unsigned long long long_int_type; +#else +typedef unsigned long long_int_type; +#endif + +int +mkstemp(char *template) +{ + static const char letters[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; + size_t length; + char *XXXXXX; + struct timeval tv; + long_int_type randnum, working; + int i, tries, fd; + + /* + * Make sure we have a valid template and initialize p to point at the + * beginning of the template portion of the string. + */ + length = strlen(template); + if (length < 6) { + errno = EINVAL; + return -1; + } + XXXXXX = template + length - 6; + if (strcmp(XXXXXX, "XXXXXX") != 0) { + errno = EINVAL; + return -1; + } + + /* Get some more-or-less random information. */ + gettimeofday(&tv, NULL); + randnum = ((long_int_type) tv.tv_usec << 16) ^ tv.tv_sec ^ getpid(); + + /* + * Now, try to find a working file name. We try no more than TMP_MAX file + * names. + */ + for (tries = 0; tries < TMP_MAX; tries++) { + for (working = randnum, i = 0; i < 6; i++) { + XXXXXX[i] = letters[working % 62]; + working /= 62; + } + fd = open(template, O_RDWR | O_CREAT | O_EXCL, 0600); + if (fd >= 0 || (errno != EEXIST && errno != EISDIR)) + return fd; + + /* + * This is a relatively random increment. Cut off the tail end of + * tv_usec since it's often predictable. + */ + randnum += (tv.tv_usec >> 10) & 0xfff; + } + errno = EEXIST; + return -1; +} diff --git a/portable/setenv.c b/portable/setenv.c new file mode 100644 index 0000000..d66ddcd --- /dev/null +++ b/portable/setenv.c @@ -0,0 +1,61 @@ +/* + * Replacement for a missing setenv. + * + * Provides the same functionality as the standard library routine setenv for + * those platforms that don't have it. + * + * Written by Russ Allbery <rra@stanford.edu> + * This work is hereby placed in the public domain by its author. + */ + +#include <config.h> +#include <portable/system.h> + +/* + * If we're running the test suite, rename setenv to avoid conflicts with + * the system version. + */ +#if TESTING +# define setenv test_setenv +int test_setenv(const char *, const char *, int); +#endif + +int +setenv(const char *name, const char *value, int overwrite) +{ + char *envstring; + size_t size; + + if (!overwrite && getenv(name) != NULL) + return 0; + + /* + * Allocate memory for the environment string. We intentionally don't use + * concat here, or the xmalloc family of allocation routines, since the + * intention is to provide a replacement for the standard library function + * which sets errno and returns in the event of a memory allocation + * failure. + */ + size = strlen(name) + 1 + strlen(value) + 1; + envstring = malloc(size); + if (envstring == NULL) + return -1; + + /* + * Build the environment string and add it to the environment using + * putenv. Systems without putenv lose, but XPG4 requires it. + */ + strlcpy(envstring, name, size); + strlcat(envstring, "=", size); + strlcat(envstring, value, size); + return putenv(envstring); + + /* + * Note that the memory allocated is not freed. This is intentional; many + * implementations of putenv assume that the string passed to putenv will + * never be freed and don't make a copy of it. Repeated use of this + * function will therefore leak memory, since most implementations of + * putenv also don't free strings removed from the environment (due to + * being overwritten). + */ +} diff --git a/portable/snprintf.c b/portable/snprintf.c index 3c39de8..ab3121c 100644 --- a/portable/snprintf.c +++ b/portable/snprintf.c @@ -1,5 +1,4 @@ -/* $Id$ - * +/* * Replacement for a missing snprintf or vsnprintf. * * The following implementation of snprintf was taken mostly verbatim from @@ -110,13 +109,10 @@ #define VA_SHIFT(v,t) ; /* no-op for ANSI */ #define VA_END va_end(ap) -#ifdef HAVE_LONG_DOUBLE +/* Assume all compilers support long double, per Autoconf documentation. */ #define LDOUBLE long double -#else -#define LDOUBLE double -#endif -#ifdef HAVE_LONG_LONG +#ifdef HAVE_LONG_LONG_INT # define LLONG long long #else # define LLONG long diff --git a/portable/stdbool.h b/portable/stdbool.h index 61dd8a1..bfbf4c4 100644 --- a/portable/stdbool.h +++ b/portable/stdbool.h @@ -1,5 +1,4 @@ -/* $Id$ - * +/* * Portability wrapper around <stdbool.h>. * * Provides the bool and _Bool types and the true and false constants, @@ -16,7 +15,9 @@ #if HAVE_STDBOOL_H # include <stdbool.h> #else -# if !HAVE__BOOL +# if HAVE__BOOL +# define bool _Bool +# else # ifdef __cplusplus typedef bool _Bool; # elif _WIN32 diff --git a/portable/strlcat.c b/portable/strlcat.c index 4816f90..f696db3 100644 --- a/portable/strlcat.c +++ b/portable/strlcat.c @@ -1,5 +1,4 @@ -/* $Id$ - * +/* * Replacement for a missing strlcat. * * Provides the same functionality as the *BSD function strlcat, originally diff --git a/portable/strlcpy.c b/portable/strlcpy.c index d281645..596e968 100644 --- a/portable/strlcpy.c +++ b/portable/strlcpy.c @@ -1,5 +1,4 @@ -/* $Id$ - * +/* * Replacement for a missing strlcpy. * * Provides the same functionality as the *BSD function strlcpy, originally diff --git a/portable/system.h b/portable/system.h index 1408ba7..461601b 100644 --- a/portable/system.h +++ b/portable/system.h @@ -1,7 +1,9 @@ -/* $Id$ +/* + * Standard system includes and portability adjustments. * * Declarations of routines and variables in the C library. Including this - * file is the equivalent of including all of the following headers, portably: + * file is the equivalent of including all of the following headers, + * portably: * * #include <sys/types.h> * #include <stdarg.h> @@ -13,8 +15,8 @@ * #include <string.h> * #include <unistd.h> * - * Missing functions are provided via #define or prototyped if available. - * Also provides some standard #defines. + * Missing functions are provided via #define or prototyped if available from + * the portable helper library. Also provides some standard #defines. * * Written by Russ Allbery <rra@stanford.edu> * This work is hereby placed in the public domain by its author. @@ -56,13 +58,17 @@ BEGIN_DECLS +/* Default to a hidden visibility for all portability functions. */ +#pragma GCC visibility push(hidden) + /* * Provide prototypes for functions not declared in system headers. Use the - * HAVE_DECL macros for those functions that may be prototyped but - * implemented incorrectly or implemented without a prototype. + * HAVE_DECL macros for those functions that may be prototyped but implemented + * incorrectly or implemented without a prototype. */ #if !HAVE_ASPRINTF -extern int asprintf(char **, const char *, ...); +extern int asprintf(char **, const char *, ...) + __attribute__((__format__(printf, 2, 3))); extern int vasprintf(char **, const char *, va_list); #endif #if !HAVE_DECL_SNPRINTF @@ -72,6 +78,12 @@ extern int snprintf(char *, size_t, const char *, ...) #if !HAVE_DECL_VSNPRINTF extern int vsnprintf(char *, size_t, const char *, va_list); #endif +#if !HAVE_MKSTEMP +extern int mkstemp(char *); +#endif +#if !HAVE_SETENV +extern int setenv(const char *, const char *, int); +#endif #if !HAVE_STRLCAT extern size_t strlcat(char *, const char *, size_t); #endif @@ -79,6 +91,9 @@ extern size_t strlcat(char *, const char *, size_t); extern size_t strlcpy(char *, const char *, size_t); #endif +/* Undo default visibility change. */ +#pragma GCC visibility pop + END_DECLS /* Windows provides snprintf under a different name. */ @@ -91,9 +106,9 @@ END_DECLS * been defined, all the rest almost certainly have. */ #ifndef STDIN_FILENO -# define STDIN_FILENO 0 -# define STDOUT_FILENO 1 -# define STDERR_FILENO 2 +# define STDIN_FILENO 0 +# define STDOUT_FILENO 1 +# define STDERR_FILENO 2 #endif /* @@ -102,9 +117,9 @@ END_DECLS */ #ifndef va_copy # ifdef __va_copy -# define va_copy(d, s) __va_copy((d), (s)) +# define va_copy(d, s) __va_copy((d), (s)) # else -# define va_copy(d, s) memcpy(&(d), &(s), sizeof(va_list)) +# define va_copy(d, s) memcpy(&(d), &(s), sizeof(va_list)) # endif #endif diff --git a/portable/uio.h b/portable/uio.h new file mode 100644 index 0000000..3c9e840 --- /dev/null +++ b/portable/uio.h @@ -0,0 +1,27 @@ +/* + * Portability wrapper around <sys/uio.h>. + * + * Provides a definition of the iovec struct for platforms that don't have it + * (primarily Windows). Currently, the corresponding readv and writev + * functions are not provided or prototyped here. + * + * Written by Russ Allbery <rra@stanford.edu> + * This work is hereby placed in the public domain by its author. + */ + +#ifndef PORTABLE_UIO_H +#define PORTABLE_UIO_H 1 + +#include <sys/types.h> + +/* remctl.h provides its own definition of this struct on Windows. */ +#if defined(HAVE_SYS_UIO_H) +# include <sys/uio.h> +#elif !defined(REMCTL_H) +struct iovec { + void *iov_base; + size_t iov_len; +}; +#endif + +#endif /* !PORTABLE_UIO_H */ |