summaryrefslogtreecommitdiff
path: root/portable
diff options
context:
space:
mode:
authorRuss Allbery <rra@stanford.edu>2010-02-21 17:45:55 -0800
committerRuss Allbery <rra@stanford.edu>2010-02-21 17:45:55 -0800
commit60210334fa3dbd5dd168199063c6ee850d750d0c (patch)
tree31e832ba6788076075d38e20ffd27ebf09430407 /portable
parente571a8eb96f42de5a114cf11ff1c3d63e5a8d301 (diff)
Imported Upstream version 0.10
Diffstat (limited to 'portable')
-rw-r--r--portable/asprintf.c6
-rw-r--r--portable/dummy.c3
-rw-r--r--portable/krb5-extra.c125
-rw-r--r--portable/krb5.h83
-rw-r--r--portable/macros.h3
-rw-r--r--portable/mkstemp.c87
-rw-r--r--portable/setenv.c61
-rw-r--r--portable/snprintf.c10
-rw-r--r--portable/stdbool.h7
-rw-r--r--portable/strlcat.c3
-rw-r--r--portable/strlcpy.c3
-rw-r--r--portable/system.h39
-rw-r--r--portable/uio.h27
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 */