|
|
df3356 |
From 05d657339a80405900f8a066e41f08c121755cbf Mon Sep 17 00:00:00 2001
|
|
|
df3356 |
From: Stef Walter <stefw@redhat.com>
|
|
|
df3356 |
Date: Fri, 3 Jan 2014 16:37:12 +0100
|
|
|
df3356 |
Subject: [PATCH] sssd: Use safe printf when formatting full_name_format
|
|
|
df3356 |
strings
|
|
|
df3356 |
|
|
|
df3356 |
Since sssd.conf uses such printf formats in its code, and it's
|
|
|
df3356 |
completely bogus to be passing user provided input to printf
|
|
|
df3356 |
directly...
|
|
|
df3356 |
---
|
|
|
df3356 |
service/Makefile.am | 1 +
|
|
|
df3356 |
service/realm-sssd.c | 52 ++++---
|
|
|
df3356 |
service/safe-printf.c | 348 +++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
df3356 |
service/safe-printf.h | 45 ++++++
|
|
|
df3356 |
tests/Makefile.am | 6 +
|
|
|
df3356 |
tests/test-safe-printf.c | 238 ++++++++++++++++++++++++++++++++
|
|
|
df3356 |
7 files changed, 662 insertions(+), 29 deletions(-)
|
|
|
df3356 |
create mode 100644 service/safe-printf.c
|
|
|
df3356 |
create mode 100644 service/safe-printf.h
|
|
|
df3356 |
create mode 100644 tests/test-safe-printf.c
|
|
|
df3356 |
|
|
|
df3356 |
diff --git a/service/Makefile.am b/service/Makefile.am
|
|
|
df3356 |
index 37743a7..603ccbe 100644
|
|
|
df3356 |
--- a/service/Makefile.am
|
|
|
df3356 |
+++ b/service/Makefile.am
|
|
|
df3356 |
@@ -59,6 +59,7 @@ realmd_SOURCES = \
|
|
|
df3356 |
realm-sssd-config.c realm-sssd-config.h \
|
|
|
df3356 |
realm-sssd-ipa.c realm-sssd-ipa.h \
|
|
|
df3356 |
realm-usleep-async.c realm-usleep-async.h \
|
|
|
df3356 |
+ safe-printf.c safe-printf.h \
|
|
|
df3356 |
$(NULL)
|
|
|
df3356 |
|
|
|
df3356 |
realmd_CFLAGS = \
|
|
|
df3356 |
diff --git a/service/realm-sssd.c b/service/realm-sssd.c
|
|
|
df3356 |
index b904514..a4863d4 100644
|
|
|
df3356 |
--- a/service/realm-sssd.c
|
|
|
df3356 |
+++ b/service/realm-sssd.c
|
|
|
df3356 |
@@ -25,6 +25,7 @@
|
|
|
df3356 |
#include "realm-service.h"
|
|
|
df3356 |
#include "realm-sssd.h"
|
|
|
df3356 |
#include "realm-sssd-config.h"
|
|
|
df3356 |
+#include "safe-printf.h"
|
|
|
df3356 |
|
|
|
df3356 |
#include <glib/gstdio.h>
|
|
|
df3356 |
#include <glib/gi18n.h>
|
|
|
df3356 |
@@ -315,38 +316,13 @@ update_domain (RealmSssd *self)
|
|
|
df3356 |
g_free (domain);
|
|
|
df3356 |
}
|
|
|
df3356 |
|
|
|
df3356 |
-static gchar *
|
|
|
df3356 |
-build_login_format (const gchar *format,
|
|
|
df3356 |
- ...) G_GNUC_PRINTF (1, 2);
|
|
|
df3356 |
-
|
|
|
df3356 |
-static gchar *
|
|
|
df3356 |
-build_login_format (const gchar *format,
|
|
|
df3356 |
- ...)
|
|
|
df3356 |
-{
|
|
|
df3356 |
- gchar *result;
|
|
|
df3356 |
- va_list va;
|
|
|
df3356 |
-
|
|
|
df3356 |
- /* This function exists mostly to get around gcc warnings */
|
|
|
df3356 |
-
|
|
|
df3356 |
- if (format == NULL)
|
|
|
df3356 |
- format = "%1$s@%2$s";
|
|
|
df3356 |
-
|
|
|
df3356 |
- va_start (va, format);
|
|
|
df3356 |
- result = g_strdup_vprintf (format, va);
|
|
|
df3356 |
- va_end (va);
|
|
|
df3356 |
-
|
|
|
df3356 |
- return result;
|
|
|
df3356 |
-}
|
|
|
df3356 |
-
|
|
|
df3356 |
-#pragma GCC diagnostic push
|
|
|
df3356 |
-#pragma GCC diagnostic ignored "-Wformat-nonliteral"
|
|
|
df3356 |
-
|
|
|
df3356 |
static void
|
|
|
df3356 |
update_login_formats (RealmSssd *self)
|
|
|
df3356 |
{
|
|
|
df3356 |
RealmKerberos *kerberos = REALM_KERBEROS (self);
|
|
|
df3356 |
gchar *login_formats[2] = { NULL, NULL };
|
|
|
df3356 |
gchar *format = NULL;
|
|
|
df3356 |
+ gchar *domain_name;
|
|
|
df3356 |
gboolean qualify;
|
|
|
df3356 |
|
|
|
df3356 |
if (self->pv->section == NULL) {
|
|
|
df3356 |
@@ -366,10 +342,28 @@ update_login_formats (RealmSssd *self)
|
|
|
df3356 |
/* Setup the login formats */
|
|
|
df3356 |
format = realm_ini_config_get (self->pv->config, self->pv->section, "full_name_format");
|
|
|
df3356 |
|
|
|
df3356 |
- /* Here we place a '%s' in the place of the user in the format */
|
|
|
df3356 |
- login_formats[0] = build_login_format (format, "%U", self->pv->domain);
|
|
|
df3356 |
- realm_kerberos_set_login_formats (kerberos, (const gchar **)login_formats);
|
|
|
df3356 |
+ /* The full domain name */
|
|
|
df3356 |
+ domain_name = calc_domain (self);
|
|
|
df3356 |
+
|
|
|
df3356 |
+ /*
|
|
|
df3356 |
+ * In theory we should be discovering the short name or flat name as sssd
|
|
|
df3356 |
+ * calls it. We configured it as the sssd.conf 'domains' name, so we just
|
|
|
df3356 |
+ * use that. Eventually we want to have a way to query sssd for that.
|
|
|
df3356 |
+ */
|
|
|
df3356 |
+
|
|
|
df3356 |
+ /*
|
|
|
df3356 |
+ * Here we place a '%U' in the place of the user in the format, and
|
|
|
df3356 |
+ * fill in the domain appropriately. sssd uses snprintf for this, which
|
|
|
df3356 |
+ * is risky and very compex to do right with positional arguments.
|
|
|
df3356 |
+ *
|
|
|
df3356 |
+ * We only replace the arguments documented in sssd.conf, as well as
|
|
|
df3356 |
+ * other non-field printf replacements.
|
|
|
df3356 |
+ */
|
|
|
df3356 |
+
|
|
|
df3356 |
+ if (safe_asprintf (login_formats, format, "%U", domain_name ? domain_name : "", self->pv->domain, NULL) >= 0)
|
|
|
df3356 |
+ realm_kerberos_set_login_formats (kerberos, (const gchar **)login_formats);
|
|
|
df3356 |
g_free (login_formats[0]);
|
|
|
df3356 |
+ g_free (domain_name);
|
|
|
df3356 |
g_free (format);
|
|
|
df3356 |
}
|
|
|
df3356 |
|
|
|
df3356 |
diff --git a/service/safe-printf.c b/service/safe-printf.c
|
|
|
df3356 |
new file mode 100644
|
|
|
df3356 |
index 0000000..069c915
|
|
|
df3356 |
--- /dev/null
|
|
|
df3356 |
+++ b/service/safe-printf.c
|
|
|
df3356 |
@@ -0,0 +1,348 @@
|
|
|
df3356 |
+/* realmd -- Realm configuration service
|
|
|
df3356 |
+ *
|
|
|
df3356 |
+ * Copyright 2013 Red Hat Inc
|
|
|
df3356 |
+ *
|
|
|
df3356 |
+ * This program is free software: you can redistribute it and/or modify
|
|
|
df3356 |
+ * it under the terms of the GNU Lesser General Public License as published
|
|
|
df3356 |
+ * by the Free Software Foundation; either version 2 of the licence or (at
|
|
|
df3356 |
+ * your option) any later version.
|
|
|
df3356 |
+ *
|
|
|
df3356 |
+ * See the included COPYING file for more information.
|
|
|
df3356 |
+ *
|
|
|
df3356 |
+ * Author: Stef Walter <stefw@redhat.com>
|
|
|
df3356 |
+ */
|
|
|
df3356 |
+
|
|
|
df3356 |
+#include "config.h"
|
|
|
df3356 |
+
|
|
|
df3356 |
+#include "safe-printf.h"
|
|
|
df3356 |
+
|
|
|
df3356 |
+#include <stdarg.h>
|
|
|
df3356 |
+#include <string.h>
|
|
|
df3356 |
+
|
|
|
df3356 |
+#ifndef MIN
|
|
|
df3356 |
+#define MIN(a, b) (((a) < (b)) ? (a) : (b))
|
|
|
df3356 |
+#endif
|
|
|
df3356 |
+
|
|
|
df3356 |
+#ifndef MAX
|
|
|
df3356 |
+#define MAX(a, b) (((a) > (b)) ? (a) : (b))
|
|
|
df3356 |
+#endif
|
|
|
df3356 |
+
|
|
|
df3356 |
+static void
|
|
|
df3356 |
+safe_padding (int count,
|
|
|
df3356 |
+ int *total,
|
|
|
df3356 |
+ void (* callback) (void *, const char *, size_t),
|
|
|
df3356 |
+ void *data)
|
|
|
df3356 |
+{
|
|
|
df3356 |
+ char eight[] = " ";
|
|
|
df3356 |
+ int num;
|
|
|
df3356 |
+
|
|
|
df3356 |
+ while (count > 0) {
|
|
|
df3356 |
+ num = MIN (count, 8);
|
|
|
df3356 |
+ callback (data, eight, num);
|
|
|
df3356 |
+ count -= num;
|
|
|
df3356 |
+ *total += num;
|
|
|
df3356 |
+ }
|
|
|
df3356 |
+}
|
|
|
df3356 |
+
|
|
|
df3356 |
+static void
|
|
|
df3356 |
+dummy_callback (void *data,
|
|
|
df3356 |
+ const char *piece,
|
|
|
df3356 |
+ size_t len)
|
|
|
df3356 |
+{
|
|
|
df3356 |
+
|
|
|
df3356 |
+}
|
|
|
df3356 |
+
|
|
|
df3356 |
+int
|
|
|
df3356 |
+safe_printf_cb (void (* callback) (void *, const char *, size_t),
|
|
|
df3356 |
+ void *data,
|
|
|
df3356 |
+ const char *format,
|
|
|
df3356 |
+ const char * const args[],
|
|
|
df3356 |
+ int num_args)
|
|
|
df3356 |
+{
|
|
|
df3356 |
+ int at_arg = 0;
|
|
|
df3356 |
+ const char *cp;
|
|
|
df3356 |
+ int precision;
|
|
|
df3356 |
+ int width;
|
|
|
df3356 |
+ int len;
|
|
|
df3356 |
+ const char *value;
|
|
|
df3356 |
+ int total;
|
|
|
df3356 |
+ int left;
|
|
|
df3356 |
+
|
|
|
df3356 |
+ if (!callback)
|
|
|
df3356 |
+ callback = dummy_callback;
|
|
|
df3356 |
+
|
|
|
df3356 |
+ total = 0;
|
|
|
df3356 |
+ cp = format;
|
|
|
df3356 |
+
|
|
|
df3356 |
+ while (*cp) {
|
|
|
df3356 |
+
|
|
|
df3356 |
+ /* Piece of raw string */
|
|
|
df3356 |
+ if (*cp != '%') {
|
|
|
df3356 |
+ len = strcspn (cp, "%");
|
|
|
df3356 |
+ callback (data, cp, len);
|
|
|
df3356 |
+ total += len;
|
|
|
df3356 |
+ cp += len;
|
|
|
df3356 |
+ continue;
|
|
|
df3356 |
+ }
|
|
|
df3356 |
+
|
|
|
df3356 |
+ cp++;
|
|
|
df3356 |
+
|
|
|
df3356 |
+ /* An literal percent sign? */
|
|
|
df3356 |
+ if (*cp == '%') {
|
|
|
df3356 |
+ callback (data, "%", 1);
|
|
|
df3356 |
+ total++;
|
|
|
df3356 |
+ cp++;
|
|
|
df3356 |
+ continue;
|
|
|
df3356 |
+ }
|
|
|
df3356 |
+
|
|
|
df3356 |
+ value = NULL;
|
|
|
df3356 |
+ left = 0;
|
|
|
df3356 |
+ precision = -1;
|
|
|
df3356 |
+ width = -1;
|
|
|
df3356 |
+
|
|
|
df3356 |
+ /* Test for positional argument. */
|
|
|
df3356 |
+ if (*cp >= '0' && *cp <= '9') {
|
|
|
df3356 |
+ /* Look-ahead parsing, otherwise skipped */
|
|
|
df3356 |
+ if (cp[strspn (cp, "0123456789")] == '$') {
|
|
|
df3356 |
+ unsigned int n = 0;
|
|
|
df3356 |
+ for (; *cp >= '0' && *cp <= '9'; cp++)
|
|
|
df3356 |
+ n = 10 * n + (*cp - '0');
|
|
|
df3356 |
+ /* Positional argument 0 is invalid. */
|
|
|
df3356 |
+ if (n == 0)
|
|
|
df3356 |
+ return -1;
|
|
|
df3356 |
+ /* Positional argument N too high */
|
|
|
df3356 |
+ if (n > num_args)
|
|
|
df3356 |
+ return -1;
|
|
|
df3356 |
+ value = args[n - 1];
|
|
|
df3356 |
+ cp++; /* $ */
|
|
|
df3356 |
+ }
|
|
|
df3356 |
+ }
|
|
|
df3356 |
+
|
|
|
df3356 |
+ /* Read the supported flags. */
|
|
|
df3356 |
+ for (; ; cp++) {
|
|
|
df3356 |
+ if (*cp == '-')
|
|
|
df3356 |
+ left = 1;
|
|
|
df3356 |
+ /* Supported but ignored */
|
|
|
df3356 |
+ else if (*cp != ' ')
|
|
|
df3356 |
+ break;
|
|
|
df3356 |
+ }
|
|
|
df3356 |
+
|
|
|
df3356 |
+ /* Parse the width. */
|
|
|
df3356 |
+ if (*cp >= '0' && *cp <= '9') {
|
|
|
df3356 |
+ width = 0;
|
|
|
df3356 |
+ for (; *cp >= '0' && *cp <= '9'; cp++)
|
|
|
df3356 |
+ width = 10 * width + (*cp - '0');
|
|
|
df3356 |
+ }
|
|
|
df3356 |
+
|
|
|
df3356 |
+ /* Parse the precision. */
|
|
|
df3356 |
+ if (*cp == '.') {
|
|
|
df3356 |
+ precision = 0;
|
|
|
df3356 |
+ for (cp++; *cp >= '0' && *cp <= '9'; cp++)
|
|
|
df3356 |
+ precision = 10 * precision + (*cp - '0');
|
|
|
df3356 |
+ }
|
|
|
df3356 |
+
|
|
|
df3356 |
+ /* Read the conversion character. */
|
|
|
df3356 |
+ switch (*cp++) {
|
|
|
df3356 |
+ case 's':
|
|
|
df3356 |
+ /* Non-positional argument */
|
|
|
df3356 |
+ if (value == NULL) {
|
|
|
df3356 |
+ /* Too many arguments used */
|
|
|
df3356 |
+ if (at_arg == num_args)
|
|
|
df3356 |
+ return -1;
|
|
|
df3356 |
+ value = args[at_arg++];
|
|
|
df3356 |
+ }
|
|
|
df3356 |
+ break;
|
|
|
df3356 |
+
|
|
|
df3356 |
+ /* No other conversion characters are supported */
|
|
|
df3356 |
+ default:
|
|
|
df3356 |
+ return -1;
|
|
|
df3356 |
+ }
|
|
|
df3356 |
+
|
|
|
df3356 |
+ /* How many characters are we printing? */
|
|
|
df3356 |
+ len = strlen (value);
|
|
|
df3356 |
+ if (precision >= 0)
|
|
|
df3356 |
+ len = MIN (precision, len);
|
|
|
df3356 |
+
|
|
|
df3356 |
+ /* Do we need padding? */
|
|
|
df3356 |
+ safe_padding (left ? 0 : width - len, &total, callback, data);
|
|
|
df3356 |
+
|
|
|
df3356 |
+ /* The actual data */;
|
|
|
df3356 |
+ callback (data, value, len);
|
|
|
df3356 |
+ total += len;
|
|
|
df3356 |
+
|
|
|
df3356 |
+ /* Do we need padding? */
|
|
|
df3356 |
+ safe_padding (left ? width - len : 0, &total, callback, data);
|
|
|
df3356 |
+ }
|
|
|
df3356 |
+
|
|
|
df3356 |
+ return total;
|
|
|
df3356 |
+}
|
|
|
df3356 |
+
|
|
|
df3356 |
+struct sprintf_ctx {
|
|
|
df3356 |
+ char *data;
|
|
|
df3356 |
+ size_t length;
|
|
|
df3356 |
+ size_t alloc;
|
|
|
df3356 |
+};
|
|
|
df3356 |
+
|
|
|
df3356 |
+static void
|
|
|
df3356 |
+asprintf_callback (void *data,
|
|
|
df3356 |
+ const char *piece,
|
|
|
df3356 |
+ size_t length)
|
|
|
df3356 |
+{
|
|
|
df3356 |
+ struct sprintf_ctx *cx = data;
|
|
|
df3356 |
+ void *mem;
|
|
|
df3356 |
+
|
|
|
df3356 |
+ if (!cx->data)
|
|
|
df3356 |
+ return;
|
|
|
df3356 |
+
|
|
|
df3356 |
+ /* Reallocate if necessary */
|
|
|
df3356 |
+ if (cx->length + length + 1 > cx->alloc) {
|
|
|
df3356 |
+ cx->alloc += MAX (length + 1, 1024);
|
|
|
df3356 |
+ mem = realloc (cx->data, cx->alloc);
|
|
|
df3356 |
+ if (mem == NULL) {
|
|
|
df3356 |
+ free (cx->data);
|
|
|
df3356 |
+ cx->data = NULL;
|
|
|
df3356 |
+ return;
|
|
|
df3356 |
+ }
|
|
|
df3356 |
+ cx->data = mem;
|
|
|
df3356 |
+ }
|
|
|
df3356 |
+
|
|
|
df3356 |
+ memcpy (cx->data + cx->length, piece, length);
|
|
|
df3356 |
+ cx->length += length;
|
|
|
df3356 |
+ cx->data[cx->length] = 0;
|
|
|
df3356 |
+}
|
|
|
df3356 |
+
|
|
|
df3356 |
+static const char **
|
|
|
df3356 |
+valist_to_args (va_list va,
|
|
|
df3356 |
+ int *num_args)
|
|
|
df3356 |
+{
|
|
|
df3356 |
+ int alo_args;
|
|
|
df3356 |
+ const char **args;
|
|
|
df3356 |
+ const char *arg;
|
|
|
df3356 |
+ void *mem;
|
|
|
df3356 |
+
|
|
|
df3356 |
+ *num_args = alo_args = 0;
|
|
|
df3356 |
+ args = NULL;
|
|
|
df3356 |
+
|
|
|
df3356 |
+ for (;;) {
|
|
|
df3356 |
+ arg = va_arg (va, const char *);
|
|
|
df3356 |
+ if (arg == NULL)
|
|
|
df3356 |
+ break;
|
|
|
df3356 |
+ if (*num_args == alo_args) {
|
|
|
df3356 |
+ alo_args += 8;
|
|
|
df3356 |
+ mem = realloc (args, sizeof (const char *) * alo_args);
|
|
|
df3356 |
+ if (!mem) {
|
|
|
df3356 |
+ free (args);
|
|
|
df3356 |
+ return NULL;
|
|
|
df3356 |
+ }
|
|
|
df3356 |
+ args = mem;
|
|
|
df3356 |
+ }
|
|
|
df3356 |
+ args[(*num_args)++] = arg;
|
|
|
df3356 |
+ }
|
|
|
df3356 |
+
|
|
|
df3356 |
+ return args;
|
|
|
df3356 |
+}
|
|
|
df3356 |
+
|
|
|
df3356 |
+int
|
|
|
df3356 |
+safe_asprintf (char **strp,
|
|
|
df3356 |
+ const char *format,
|
|
|
df3356 |
+ ...)
|
|
|
df3356 |
+{
|
|
|
df3356 |
+ struct sprintf_ctx cx;
|
|
|
df3356 |
+ const char **args;
|
|
|
df3356 |
+ int num_args;
|
|
|
df3356 |
+ va_list va;
|
|
|
df3356 |
+ int ret;
|
|
|
df3356 |
+ int i;
|
|
|
df3356 |
+
|
|
|
df3356 |
+ va_start (va, format);
|
|
|
df3356 |
+ args = valist_to_args (va, &num_args);
|
|
|
df3356 |
+ va_end (va);
|
|
|
df3356 |
+
|
|
|
df3356 |
+ if (args == NULL)
|
|
|
df3356 |
+ return -1;
|
|
|
df3356 |
+
|
|
|
df3356 |
+ /* Preallocate a pretty good guess */
|
|
|
df3356 |
+ cx.alloc = strlen (format) + 1;
|
|
|
df3356 |
+ for (i = 0; i < num_args; i++)
|
|
|
df3356 |
+ cx.alloc += strlen (args[i]);
|
|
|
df3356 |
+
|
|
|
df3356 |
+ cx.data = malloc (cx.alloc);
|
|
|
df3356 |
+ if (!cx.data) {
|
|
|
df3356 |
+ free (args);
|
|
|
df3356 |
+ return -1;
|
|
|
df3356 |
+ }
|
|
|
df3356 |
+
|
|
|
df3356 |
+ cx.data[0] = '\0';
|
|
|
df3356 |
+ cx.length = 0;
|
|
|
df3356 |
+
|
|
|
df3356 |
+ ret = safe_printf_cb (asprintf_callback, &cx, format, args, num_args);
|
|
|
df3356 |
+ if (cx.data == NULL)
|
|
|
df3356 |
+ ret = -1;
|
|
|
df3356 |
+ if (ret < 0)
|
|
|
df3356 |
+ free (cx.data);
|
|
|
df3356 |
+ else
|
|
|
df3356 |
+ *strp = cx.data;
|
|
|
df3356 |
+
|
|
|
df3356 |
+ free (args);
|
|
|
df3356 |
+ return ret;
|
|
|
df3356 |
+}
|
|
|
df3356 |
+
|
|
|
df3356 |
+static void
|
|
|
df3356 |
+snprintf_callback (void *data,
|
|
|
df3356 |
+ const char *piece,
|
|
|
df3356 |
+ size_t length)
|
|
|
df3356 |
+{
|
|
|
df3356 |
+ struct sprintf_ctx *cx = data;
|
|
|
df3356 |
+
|
|
|
df3356 |
+ /* Don't copy if too much data */
|
|
|
df3356 |
+ if (cx->length > cx->alloc)
|
|
|
df3356 |
+ length = 0;
|
|
|
df3356 |
+ else if (cx->length + length > cx->alloc)
|
|
|
df3356 |
+ length = cx->alloc - cx->length;
|
|
|
df3356 |
+ else
|
|
|
df3356 |
+ length = length;
|
|
|
df3356 |
+
|
|
|
df3356 |
+ if (length > 0)
|
|
|
df3356 |
+ memcpy (cx->data + cx->length, piece, length);
|
|
|
df3356 |
+
|
|
|
df3356 |
+ /* Null termination happens later */
|
|
|
df3356 |
+ cx->length += length;
|
|
|
df3356 |
+}
|
|
|
df3356 |
+
|
|
|
df3356 |
+int
|
|
|
df3356 |
+safe_snprintf (char *str,
|
|
|
df3356 |
+ size_t len,
|
|
|
df3356 |
+ const char *format,
|
|
|
df3356 |
+ ...)
|
|
|
df3356 |
+{
|
|
|
df3356 |
+ struct sprintf_ctx cx;
|
|
|
df3356 |
+ int num_args;
|
|
|
df3356 |
+ va_list va;
|
|
|
df3356 |
+ const char **args;
|
|
|
df3356 |
+ int ret;
|
|
|
df3356 |
+
|
|
|
df3356 |
+ cx.data = str;
|
|
|
df3356 |
+ cx.length = 0;
|
|
|
df3356 |
+ cx.alloc = len;
|
|
|
df3356 |
+
|
|
|
df3356 |
+ va_start (va, format);
|
|
|
df3356 |
+ args = valist_to_args (va, &num_args);
|
|
|
df3356 |
+ va_end (va);
|
|
|
df3356 |
+
|
|
|
df3356 |
+ if (args == NULL)
|
|
|
df3356 |
+ return -1;
|
|
|
df3356 |
+
|
|
|
df3356 |
+ if (len)
|
|
|
df3356 |
+ cx.data[0] = '\0';
|
|
|
df3356 |
+
|
|
|
df3356 |
+ ret = safe_printf_cb (snprintf_callback, &cx, format, args, num_args);
|
|
|
df3356 |
+ if (ret < 0)
|
|
|
df3356 |
+ return ret;
|
|
|
df3356 |
+
|
|
|
df3356 |
+ /* Null terminate appropriately */
|
|
|
df3356 |
+ if (len > 0)
|
|
|
df3356 |
+ cx.data[MIN(cx.length, len - 1)] = '\0';
|
|
|
df3356 |
+
|
|
|
df3356 |
+ free (args);
|
|
|
df3356 |
+ return ret;
|
|
|
df3356 |
+}
|
|
|
df3356 |
diff --git a/service/safe-printf.h b/service/safe-printf.h
|
|
|
df3356 |
new file mode 100644
|
|
|
df3356 |
index 0000000..8881b91
|
|
|
df3356 |
--- /dev/null
|
|
|
df3356 |
+++ b/service/safe-printf.h
|
|
|
df3356 |
@@ -0,0 +1,45 @@
|
|
|
df3356 |
+/* realmd -- Realm configuration service
|
|
|
df3356 |
+ *
|
|
|
df3356 |
+ * Copyright 2013 Red Hat Inc
|
|
|
df3356 |
+ *
|
|
|
df3356 |
+ * This program is free software: you can redistribute it and/or modify
|
|
|
df3356 |
+ * it under the terms of the GNU Lesser General Public License as published
|
|
|
df3356 |
+ * by the Free Software Foundation; either version 2 of the licence or (at
|
|
|
df3356 |
+ * your option) any later version.
|
|
|
df3356 |
+ *
|
|
|
df3356 |
+ * See the included COPYING file for more information.
|
|
|
df3356 |
+ *
|
|
|
df3356 |
+ * Author: Stef Walter <stefw@redhat.com>
|
|
|
df3356 |
+ */
|
|
|
df3356 |
+
|
|
|
df3356 |
+#include "config.h"
|
|
|
df3356 |
+
|
|
|
df3356 |
+#ifndef __SAFE_PRINTF_H__
|
|
|
df3356 |
+#define __SAFE_PRINTF_H__
|
|
|
df3356 |
+
|
|
|
df3356 |
+#include <stdlib.h>
|
|
|
df3356 |
+
|
|
|
df3356 |
+#ifndef GNUC_NULL_TERMINATED
|
|
|
df3356 |
+#if __GNUC__ >= 4
|
|
|
df3356 |
+#define GNUC_NULL_TERMINATED __attribute__((__sentinel__))
|
|
|
df3356 |
+#else
|
|
|
df3356 |
+#define GNUC_NULL_TERMINATED
|
|
|
df3356 |
+#endif
|
|
|
df3356 |
+#endif
|
|
|
df3356 |
+
|
|
|
df3356 |
+int safe_asprintf (char **strp,
|
|
|
df3356 |
+ const char *format,
|
|
|
df3356 |
+ ...) GNUC_NULL_TERMINATED;
|
|
|
df3356 |
+
|
|
|
df3356 |
+int safe_snprintf (char *str,
|
|
|
df3356 |
+ size_t len,
|
|
|
df3356 |
+ const char *format,
|
|
|
df3356 |
+ ...) GNUC_NULL_TERMINATED;
|
|
|
df3356 |
+
|
|
|
df3356 |
+int safe_printf_cb (void (* callback) (void *data, const char *piece, size_t len),
|
|
|
df3356 |
+ void *data,
|
|
|
df3356 |
+ const char *format,
|
|
|
df3356 |
+ const char * const args[],
|
|
|
df3356 |
+ int num_args);
|
|
|
df3356 |
+
|
|
|
df3356 |
+#endif /* __SAFE_PRINTF_H__ */
|
|
|
df3356 |
diff --git a/tests/Makefile.am b/tests/Makefile.am
|
|
|
df3356 |
index f6d400b..d26c762 100644
|
|
|
df3356 |
--- a/tests/Makefile.am
|
|
|
df3356 |
+++ b/tests/Makefile.am
|
|
|
df3356 |
@@ -17,6 +17,7 @@ LDADD = \
|
|
|
df3356 |
TEST_PROGS = \
|
|
|
df3356 |
test-ini-config \
|
|
|
df3356 |
test-sssd-config \
|
|
|
df3356 |
+ test-safe-printf \
|
|
|
df3356 |
test-login-name \
|
|
|
df3356 |
test-samba-ou-format \
|
|
|
df3356 |
test-settings \
|
|
|
df3356 |
@@ -43,6 +44,11 @@ test_sssd_config_SOURCES = \
|
|
|
df3356 |
$(top_srcdir)/service/realm-settings.c \
|
|
|
df3356 |
$(NULL)
|
|
|
df3356 |
|
|
|
df3356 |
+test_safe_printf_SOURCES = \
|
|
|
df3356 |
+ test-safe-printf.c \
|
|
|
df3356 |
+ $(top_srcdir)/service/safe-printf.c \
|
|
|
df3356 |
+ $(NULL)
|
|
|
df3356 |
+
|
|
|
df3356 |
test_login_name_SOURCES = \
|
|
|
df3356 |
test-login-name.c \
|
|
|
df3356 |
$(top_srcdir)/service/realm-login-name.c \
|
|
|
df3356 |
diff --git a/tests/test-safe-printf.c b/tests/test-safe-printf.c
|
|
|
df3356 |
new file mode 100644
|
|
|
df3356 |
index 0000000..fa337ac
|
|
|
df3356 |
--- /dev/null
|
|
|
df3356 |
+++ b/tests/test-safe-printf.c
|
|
|
df3356 |
@@ -0,0 +1,238 @@
|
|
|
df3356 |
+/* realmd -- Realm configuration service
|
|
|
df3356 |
+ *
|
|
|
df3356 |
+ * Copyright 2012 Red Hat Inc
|
|
|
df3356 |
+ *
|
|
|
df3356 |
+ * This program is free software: you can redistribute it and/or modify
|
|
|
df3356 |
+ * it under the terms of the GNU Lesser General Public License as published
|
|
|
df3356 |
+ * by the Free Software Foundation; either version 2 of the licence or (at
|
|
|
df3356 |
+ * your option) any later version.
|
|
|
df3356 |
+ *
|
|
|
df3356 |
+ * See the included COPYING file for more information.
|
|
|
df3356 |
+ *
|
|
|
df3356 |
+ * Author: Stef Walter <stefw@gnome.org>
|
|
|
df3356 |
+ */
|
|
|
df3356 |
+
|
|
|
df3356 |
+#include "config.h"
|
|
|
df3356 |
+
|
|
|
df3356 |
+#include "service/safe-printf.h"
|
|
|
df3356 |
+
|
|
|
df3356 |
+#include <glib.h>
|
|
|
df3356 |
+
|
|
|
df3356 |
+#include <string.h>
|
|
|
df3356 |
+
|
|
|
df3356 |
+typedef struct {
|
|
|
df3356 |
+ const gchar *format;
|
|
|
df3356 |
+ const gchar *args[8];
|
|
|
df3356 |
+ const gchar *result;
|
|
|
df3356 |
+} Fixture;
|
|
|
df3356 |
+
|
|
|
df3356 |
+static void
|
|
|
df3356 |
+callback (void *data,
|
|
|
df3356 |
+ const char *piece,
|
|
|
df3356 |
+ size_t len)
|
|
|
df3356 |
+{
|
|
|
df3356 |
+ g_string_append_len (data, piece, len);
|
|
|
df3356 |
+}
|
|
|
df3356 |
+
|
|
|
df3356 |
+static void
|
|
|
df3356 |
+test_safe_printf (gconstpointer user_data)
|
|
|
df3356 |
+{
|
|
|
df3356 |
+ const Fixture *fixture = user_data;
|
|
|
df3356 |
+ GString *out;
|
|
|
df3356 |
+ int num_args;
|
|
|
df3356 |
+ int ret;
|
|
|
df3356 |
+
|
|
|
df3356 |
+ for (num_args = 0; fixture->args[num_args] != NULL; )
|
|
|
df3356 |
+ num_args++;
|
|
|
df3356 |
+
|
|
|
df3356 |
+ out = g_string_new ("");
|
|
|
df3356 |
+ ret = safe_printf_cb (callback, out, fixture->format, (const gchar **)fixture->args, num_args);
|
|
|
df3356 |
+ if (fixture->result) {
|
|
|
df3356 |
+ g_assert_cmpint (ret, >=, 0);
|
|
|
df3356 |
+ g_assert_cmpstr (out->str, ==, fixture->result);
|
|
|
df3356 |
+ g_assert_cmpint (ret, ==, out->len);
|
|
|
df3356 |
+ } else {
|
|
|
df3356 |
+ g_assert_cmpint (ret, <, 0);
|
|
|
df3356 |
+ }
|
|
|
df3356 |
+
|
|
|
df3356 |
+ g_string_free (out, TRUE);
|
|
|
df3356 |
+}
|
|
|
df3356 |
+
|
|
|
df3356 |
+static const Fixture fixtures[] = {
|
|
|
df3356 |
+ {
|
|
|
df3356 |
+ /* Just a bog standard string */
|
|
|
df3356 |
+ "%s", { "blah", NULL, },
|
|
|
df3356 |
+ "blah"
|
|
|
df3356 |
+ },
|
|
|
df3356 |
+ {
|
|
|
df3356 |
+ /* Empty to print */
|
|
|
df3356 |
+ "%s", { "", NULL, },
|
|
|
df3356 |
+ ""
|
|
|
df3356 |
+ },
|
|
|
df3356 |
+ {
|
|
|
df3356 |
+ /* Nothing to print */
|
|
|
df3356 |
+ "", { "blah", NULL, },
|
|
|
df3356 |
+ ""
|
|
|
df3356 |
+ },
|
|
|
df3356 |
+ {
|
|
|
df3356 |
+ /* Width right aligned */
|
|
|
df3356 |
+ "%8s", { "blah", NULL, },
|
|
|
df3356 |
+ " blah"
|
|
|
df3356 |
+ },
|
|
|
df3356 |
+ {
|
|
|
df3356 |
+ /* Width left aligned */
|
|
|
df3356 |
+ "whoop %-8s doo", { "dee", NULL, },
|
|
|
df3356 |
+ "whoop dee doo"
|
|
|
df3356 |
+ },
|
|
|
df3356 |
+ {
|
|
|
df3356 |
+ /* Width space aligned (ignored) */
|
|
|
df3356 |
+ "whoop % 8s doo", { "dee", NULL, },
|
|
|
df3356 |
+ "whoop dee doo"
|
|
|
df3356 |
+ },
|
|
|
df3356 |
+ {
|
|
|
df3356 |
+ /* Width left space aligned (ignored) */
|
|
|
df3356 |
+ "whoop % -8s doo", { "dee", NULL, },
|
|
|
df3356 |
+ "whoop dee doo"
|
|
|
df3356 |
+ },
|
|
|
df3356 |
+ {
|
|
|
df3356 |
+ /* Precision 1 digit */
|
|
|
df3356 |
+ "whoop %.3s doo", { "deedle-dee", NULL, },
|
|
|
df3356 |
+ "whoop dee doo"
|
|
|
df3356 |
+ },
|
|
|
df3356 |
+ {
|
|
|
df3356 |
+ /* Precision, N digits */
|
|
|
df3356 |
+ "whoop %.10s doo", { "deedle-dee-deedle-do-deedle-dum", NULL, },
|
|
|
df3356 |
+ "whoop deedle-dee doo"
|
|
|
df3356 |
+ },
|
|
|
df3356 |
+ {
|
|
|
df3356 |
+ /* Precision, zero digits */
|
|
|
df3356 |
+ "whoop %.s doo", { "deedle", NULL, },
|
|
|
df3356 |
+ "whoop doo"
|
|
|
df3356 |
+ },
|
|
|
df3356 |
+ {
|
|
|
df3356 |
+ /* Multiple simple arguments */
|
|
|
df3356 |
+ "space %s %s", { "man", "dances", NULL, },
|
|
|
df3356 |
+ "space man dances"
|
|
|
df3356 |
+ },
|
|
|
df3356 |
+ {
|
|
|
df3356 |
+ /* Literal percent */
|
|
|
df3356 |
+ "100%% of space folk dance", { NULL, },
|
|
|
df3356 |
+ "100% of space folk dance"
|
|
|
df3356 |
+ },
|
|
|
df3356 |
+ {
|
|
|
df3356 |
+ /* Multiple simple arguments */
|
|
|
df3356 |
+ "space %2$s %1$s", { "dances", "man", NULL, },
|
|
|
df3356 |
+ "space man dances"
|
|
|
df3356 |
+ },
|
|
|
df3356 |
+ {
|
|
|
df3356 |
+ /* Skipping an argument (not supported by standard printf) */
|
|
|
df3356 |
+ "space %2$s dances", { "dances", "man", NULL, },
|
|
|
df3356 |
+ "space man dances"
|
|
|
df3356 |
+ },
|
|
|
df3356 |
+
|
|
|
df3356 |
+ /* Failures start here */
|
|
|
df3356 |
+
|
|
|
df3356 |
+ {
|
|
|
df3356 |
+ /* Unsupported conversion */
|
|
|
df3356 |
+ "%x", { "blah", NULL, },
|
|
|
df3356 |
+ NULL
|
|
|
df3356 |
+ },
|
|
|
df3356 |
+ {
|
|
|
df3356 |
+ /* Bad positional argument */
|
|
|
df3356 |
+ "space %55$s dances", { "dances", "man", NULL, },
|
|
|
df3356 |
+ NULL
|
|
|
df3356 |
+ },
|
|
|
df3356 |
+ {
|
|
|
df3356 |
+ /* Zero positional argument */
|
|
|
df3356 |
+ "space %0$s dances", { "dances", "man", NULL, },
|
|
|
df3356 |
+ NULL
|
|
|
df3356 |
+ },
|
|
|
df3356 |
+ {
|
|
|
df3356 |
+ /* Too many args used */
|
|
|
df3356 |
+ "%s %s dances", { "space", NULL, },
|
|
|
df3356 |
+ NULL
|
|
|
df3356 |
+ },
|
|
|
df3356 |
+
|
|
|
df3356 |
+};
|
|
|
df3356 |
+
|
|
|
df3356 |
+static void
|
|
|
df3356 |
+test_safe_snprintf (void)
|
|
|
df3356 |
+{
|
|
|
df3356 |
+ char buffer[8];
|
|
|
df3356 |
+ int ret;
|
|
|
df3356 |
+
|
|
|
df3356 |
+ ret = safe_snprintf (buffer, 8, "%s", "space", "man", NULL);
|
|
|
df3356 |
+ g_assert_cmpint (ret, ==, 5);
|
|
|
df3356 |
+ g_assert_cmpstr (buffer, ==, "space");
|
|
|
df3356 |
+
|
|
|
df3356 |
+ ret = safe_snprintf (buffer, 8, "", "space", "man", NULL);
|
|
|
df3356 |
+ g_assert_cmpint (ret, ==, 0);
|
|
|
df3356 |
+ g_assert_cmpstr (buffer, ==, "");
|
|
|
df3356 |
+
|
|
|
df3356 |
+ ret = safe_snprintf (buffer, 8, "the %s %s dances away", "space", "man", NULL);
|
|
|
df3356 |
+ g_assert_cmpint (ret, ==, 25);
|
|
|
df3356 |
+ g_assert_cmpstr (buffer, ==, "the spa");
|
|
|
df3356 |
+
|
|
|
df3356 |
+ ret = safe_snprintf (buffer, 8, "%5$s", NULL);
|
|
|
df3356 |
+ g_assert_cmpint (ret, <, 0);
|
|
|
df3356 |
+}
|
|
|
df3356 |
+
|
|
|
df3356 |
+static void
|
|
|
df3356 |
+test_safe_asprintf (void)
|
|
|
df3356 |
+{
|
|
|
df3356 |
+ char *buffer;
|
|
|
df3356 |
+ int ret;
|
|
|
df3356 |
+
|
|
|
df3356 |
+ ret = safe_asprintf (&buffer, "%s", "space", "man", NULL);
|
|
|
df3356 |
+ g_assert_cmpint (ret, ==, 5);
|
|
|
df3356 |
+ g_assert_cmpstr (buffer, ==, "space");
|
|
|
df3356 |
+ free (buffer);
|
|
|
df3356 |
+
|
|
|
df3356 |
+ ret = safe_asprintf (&buffer, "", "space", "man", NULL);
|
|
|
df3356 |
+ g_assert_cmpint (ret, ==, 0);
|
|
|
df3356 |
+ g_assert_cmpstr (buffer, ==, "");
|
|
|
df3356 |
+ free (buffer);
|
|
|
df3356 |
+
|
|
|
df3356 |
+ ret = safe_asprintf (&buffer, "the %s %s dances away", "space", "man", NULL);
|
|
|
df3356 |
+ g_assert_cmpint (ret, ==, 25);
|
|
|
df3356 |
+ g_assert_cmpstr (buffer, ==, "the space man dances away");
|
|
|
df3356 |
+ free (buffer);
|
|
|
df3356 |
+
|
|
|
df3356 |
+ ret = safe_asprintf (&buffer, "%1$s %1$s %1$s %1$s %1$s %1$s", "space man", NULL);
|
|
|
df3356 |
+ g_assert_cmpint (ret, ==, 59);
|
|
|
df3356 |
+ g_assert_cmpstr (buffer, ==, "space man space man space man space man space man space man");
|
|
|
df3356 |
+ free (buffer);
|
|
|
df3356 |
+
|
|
|
df3356 |
+ ret = safe_asprintf (&buffer, "%5$s", NULL);
|
|
|
df3356 |
+ g_assert_cmpint (ret, <, 0);
|
|
|
df3356 |
+}
|
|
|
df3356 |
+
|
|
|
df3356 |
+int
|
|
|
df3356 |
+main (int argc,
|
|
|
df3356 |
+ char **argv)
|
|
|
df3356 |
+{
|
|
|
df3356 |
+ gchar *escaped;
|
|
|
df3356 |
+ gchar *name;
|
|
|
df3356 |
+ gint i;
|
|
|
df3356 |
+
|
|
|
df3356 |
+ g_test_init (&argc, &argv, NULL);
|
|
|
df3356 |
+ g_set_prgname ("test-safe-printf");
|
|
|
df3356 |
+
|
|
|
df3356 |
+ for (i = 0; i < G_N_ELEMENTS (fixtures); i++) {
|
|
|
df3356 |
+ if (g_str_equal (fixtures[i].format, ""))
|
|
|
df3356 |
+ escaped = g_strdup ("_empty_");
|
|
|
df3356 |
+ else
|
|
|
df3356 |
+ escaped = g_strdup (fixtures[i].format);
|
|
|
df3356 |
+ g_strdelimit (escaped, " =\\/", '_');
|
|
|
df3356 |
+ name = g_strdup_printf ("/realmd/safe-printf/%s", escaped);
|
|
|
df3356 |
+ g_free (escaped);
|
|
|
df3356 |
+
|
|
|
df3356 |
+ g_test_add_data_func (name, fixtures + i, test_safe_printf);
|
|
|
df3356 |
+ g_free (name);
|
|
|
df3356 |
+ }
|
|
|
df3356 |
+
|
|
|
df3356 |
+ g_test_add_func ("/realmd/safe-snprintf", test_safe_snprintf);
|
|
|
df3356 |
+ g_test_add_func ("/realmd/safe-asprintf", test_safe_asprintf);
|
|
|
df3356 |
+
|
|
|
df3356 |
+ return g_test_run ();
|
|
|
df3356 |
+}
|
|
|
df3356 |
--
|
|
|
df3356 |
1.8.4.2
|
|
|
df3356 |
|