krb5 commit: Add unit tests for k5_parse_host_string

Greg Hudson ghudson at mit.edu
Wed Aug 10 12:33:51 EDT 2016


https://github.com/krb5/krb5/commit/ef1e428b19aca8a692d2ca77750a5c38b3787eae
commit ef1e428b19aca8a692d2ca77750a5c38b3787eae
Author: Sarah Day <sarahday at mit.edu>
Date:   Tue Jan 19 09:50:33 2016 -0500

    Add unit tests for k5_parse_host_string
    
    Make is_string_numeric() visible outside of parse_host_string.c as
    k5_is_string_numeric() so it can be tested.  Make
    k5_parse_host_string() return an error when address begins with ':',
    for consistency with APR's apr_parse_addr_port().
    
    [ghudson at mit.edu: squashed three commits; added t_parse_host_string to
    .gitignore and clean rule; clarified commit message]

 .gitignore                             |    1 +
 src/include/k5-int.h                   |    4 +
 src/lib/krb5/krb/Makefile.in           |   16 ++-
 src/lib/krb5/krb/parse_host_string.c   |    8 +-
 src/lib/krb5/krb/t_parse_host_string.c |  251 ++++++++++++++++++++++++++++++++
 src/lib/krb5/libkrb5.exports           |    1 +
 6 files changed, 275 insertions(+), 6 deletions(-)

diff --git a/.gitignore b/.gitignore
index 3b63c98..4baf11a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -331,6 +331,7 @@ local.properties
 /src/lib/krb5/krb/t_in_ccache
 /src/lib/krb5/krb/t_kerb
 /src/lib/krb5/krb/t_pac
+/src/lib/krb5/krb/t_parse_host_string
 /src/lib/krb5/krb/t_princ
 /src/lib/krb5/krb/t_ser
 /src/lib/krb5/krb/t_vfy_increds
diff --git a/src/include/k5-int.h b/src/include/k5-int.h
index 0ed8b70..eb73fa7 100644
--- a/src/include/k5-int.h
+++ b/src/include/k5-int.h
@@ -1758,6 +1758,10 @@ krb5_encode_kdc_rep(krb5_context, krb5_msgtype, const krb5_enc_kdc_rep_part *,
                     int using_subkey, const krb5_keyblock *, krb5_kdc_rep *,
                     krb5_data ** );
 
+/* Return true if s is non-empty and composed solely of digits. */
+krb5_boolean
+k5_is_string_numeric(const char *s);
+
 krb5_error_code
 k5_parse_host_string(const char *address, int default_port, char **host_out,
                      int *port_out);
diff --git a/src/lib/krb5/krb/Makefile.in b/src/lib/krb5/krb/Makefile.in
index 7a7ae2e..0fe02a9 100644
--- a/src/lib/krb5/krb/Makefile.in
+++ b/src/lib/krb5/krb/Makefile.in
@@ -354,6 +354,7 @@ SRCS=	$(srcdir)/addr_comp.c	\
 	$(srcdir)/t_deltat.c	\
 	$(srcdir)/t_expand.c	\
 	$(srcdir)/t_pac.c	\
+	$(srcdir)/t_parse_host_string.c	\
 	$(srcdir)/t_princ.c	\
 	$(srcdir)/t_etypes.c    \
 	$(srcdir)/t_expire_warn.c \
@@ -398,6 +399,8 @@ T_PRINC_OBJS= t_princ.o parse.o unparse.o
 
 T_ETYPES_OBJS= t_etypes.o init_ctx.o etype_list.o plugin.o
 
+T_PARSE_HOST_STRING_OBJS= t_parse_host_string.o parse_host_string.o
+
 t_walk_rtree: $(T_WALK_RTREE_OBJS) $(KRB5_BASE_DEPLIBS)
 	$(CC_LINK) -o t_walk_rtree $(T_WALK_RTREE_OBJS) $(KRB5_BASE_LIBS)
 t_ad_fx_armor: t_ad_fx_armor.o
@@ -410,7 +413,7 @@ t_kerb: $(T_KERB_OBJS) $(KRB5_BASE_DEPLIBS)
 	$(CC_LINK) -o t_kerb $(T_KERB_OBJS) $(KRB5_BASE_LIBS)
 
 t_ser: $(T_SER_OBJS) $(KRB5_BASE_DEPLIBS)
-	$(CC_LINK) -o t_ser $(T_SER_OBJS) $(KRB5_BASE_LIBS) 
+	$(CC_LINK) -o t_ser $(T_SER_OBJS) $(KRB5_BASE_LIBS)
 
 t_deltat : $(T_DELTAT_OBJS) $(SUPPORT_DEPLIB)
 	$(CC_LINK) -o t_deltat $(T_DELTAT_OBJS) $(SUPPORT_LIB)
@@ -429,6 +432,10 @@ t_princ: $(T_PRINC_OBJS) $(KRB5_BASE_DEPLIBS)
 t_etypes: $(T_ETYPES_OBJS) $(KRB5_BASE_DEPLIBS)
 	$(CC_LINK) -o t_etypes $(T_ETYPES_OBJS) $(KRB5_BASE_LIBS)
 
+t_parse_host_string: $(T_PARSE_HOST_STRING_OBJS) $(KRB5_BASE_DEPLIBS)
+	$(CC_LINK) -o $@ $(T_PARSE_HOST_STRING_OBJS) $(CMOCKA_LIBS) \
+		$(KRB5_BASE_LIBS)
+
 t_expire_warn: t_expire_warn.o $(KRB5_BASE_DEPLIBS)
 	$(CC_LINK) -o $@ t_expire_warn.o $(KRB5_BASE_LIBS)
 
@@ -495,6 +502,9 @@ check-pytests: t_expire_warn t_vfy_increds
 	$(RUNPYTEST) $(srcdir)/t_vfy_increds.py $(PYTESTFLAGS)
 	$(RUNPYTEST) $(srcdir)/t_in_ccache_patypes.py $(PYTESTFLAGS)
 
+check-cmocka: t_parse_host_string
+	$(RUN_TEST) ./t_parse_host_string > /dev/null
+
 clean:
 	$(RM) $(OUTPRE)t_walk_rtree$(EXEEXT) $(OUTPRE)t_walk_rtree.$(OBJEXT) \
 		$(OUTPRE)t_kerb$(EXEEXT) $(OUTPRE)t_kerb.$(OBJEXT)	\
@@ -513,7 +523,9 @@ clean:
 	$(OUTPRE)t_vfy_increds$(EXEEXT) $(OUTPRE)t_vfy_increds.$(OBJEXT) \
 	$(OUTPRE)t_response_items$(EXEEXT) \
 	$(OUTPRE)t_response_items.$(OBJEXT) $(OUTPRE)t_sname_match$(EXEEXT) \
-	$(OUTPRE)t_sname_match.$(OBJEXT)
+	$(OUTPRE)t_sname_match.$(OBJEXT) \
+	$(OUTPRE)t_parse_host_string$(EXEEXT) \
+	$(OUTPRE)t_parse_host_string.$(OBJEXT)
 
 @libobj_frag@
 
diff --git a/src/lib/krb5/krb/parse_host_string.c b/src/lib/krb5/krb/parse_host_string.c
index 7eaa27a..2330be6 100644
--- a/src/lib/krb5/krb/parse_host_string.c
+++ b/src/lib/krb5/krb/parse_host_string.c
@@ -34,8 +34,8 @@
 #include <ctype.h>
 
 /* Return true if s is composed solely of digits. */
-static krb5_boolean
-is_string_numeric(const char *s)
+krb5_boolean
+k5_is_string_numeric(const char *s)
 {
     if (*s == '\0')
         return FALSE;
@@ -80,13 +80,13 @@ k5_parse_host_string(const char *address, int default_port, char **host_out,
     *host_out = NULL;
     *port_out = 0;
 
-    if (address == NULL || *address == '\0')
+    if (address == NULL || *address == '\0' || *address == ':')
         return EINVAL;
     if (default_port < 0 || default_port > 65535)
         return EINVAL;
 
     /* Find the bounds of the host string and the start of the port string. */
-    if (is_string_numeric(address)) {
+    if (k5_is_string_numeric(address)) {
         port = address;
     } else if (*address == '[' && (p = strchr(address, ']')) != NULL) {
         host = address + 1;
diff --git a/src/lib/krb5/krb/t_parse_host_string.c b/src/lib/krb5/krb/t_parse_host_string.c
new file mode 100644
index 0000000..76dd20f
--- /dev/null
+++ b/src/lib/krb5/krb/t_parse_host_string.c
@@ -0,0 +1,251 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/* lib/krb5/krb/t_parse_host_string.c - k5_parse_host_string() unit tests */
+/*
+ * Copyright (C) 2015 by the Massachusetts Institute of Technology.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in
+ *   the documentation and/or other materials provided with the
+ *   distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "k5-int.h"
+#include <stdarg.h>
+#include <stddef.h>
+#include <setjmp.h>
+#include <cmocka.h>
+#include <malloc.h>
+
+/* Call k5_parse_host_string() and check the result against the expected code,
+ * hostname, and port. */
+static void
+call_k5_parse_host_string(const char *host, int default_port,
+                          krb5_error_code e_code, const char *e_host,
+                          int e_port)
+{
+    krb5_error_code code;
+    char *host_out = NULL;
+    int port_out = -1;
+
+    code = k5_parse_host_string(host, default_port, &host_out, &port_out);
+
+    assert_int_equal(code, e_code);
+
+    /* Only check the port if the function was expected to be successful. */
+    if (!e_code)
+        assert_int_equal(port_out, e_port);
+
+    /* If the expected code is a failure then host_out should be NULL. */
+    if (e_code != 0 || e_host == NULL)
+        assert_null(host_out);
+    else
+        assert_string_equal(e_host, host_out);
+
+    free(host_out);
+}
+
+/* k5_parse_host_string() tests */
+
+static void
+test_named_host_only(void **state)
+{
+    call_k5_parse_host_string("test.example", 50, 0, "test.example", 50);
+}
+
+static void
+test_named_host_w_port(void **state)
+{
+    call_k5_parse_host_string("test.example:75", 0, 0, "test.example", 75);
+}
+
+static void
+test_ipv4_only(void **state)
+{
+    call_k5_parse_host_string("192.168.1.1", 100, 0, "192.168.1.1", 100);
+}
+
+static void
+test_ipv4_w_port(void **state)
+{
+    call_k5_parse_host_string("192.168.1.1:150", 0, 0, "192.168.1.1", 150);
+}
+
+static void
+test_ipv6_only(void **state)
+{
+    call_k5_parse_host_string("[BEEF:CAFE:FEED:FACE:DEAD:BEEF:DEAF:BABE]", 200,
+                              0, "BEEF:CAFE:FEED:FACE:DEAD:BEEF:DEAF:BABE",
+                              200);
+}
+
+static void
+test_ipv6_w_port(void **state)
+{
+    call_k5_parse_host_string("[BEEF:CAFE:FEED:FACE:DEAD:BEEF:DEAF:BABE]:250",
+                              0, 0, "BEEF:CAFE:FEED:FACE:DEAD:BEEF:DEAF:BABE",
+                              250);
+}
+
+static void
+test_ipv6_w_zone(void **state)
+{
+    call_k5_parse_host_string("[BEEF:CAFE:FEED:FACE:DEAD:BEEF:DEAF:BABE%eth0]",
+                              275, 0,
+                              "BEEF:CAFE:FEED:FACE:DEAD:BEEF:DEAF:BABE%eth0",
+                              275);
+}
+
+static void
+test_invalid_ipv6(void **state)
+{
+    call_k5_parse_host_string("BEEF:CAFE:FEED:FACE:DEAD:BEEF:DEAF:BABE", 1,
+                              EINVAL, NULL, 0);
+}
+
+static void
+test_no_host_port(void **state)
+{
+    call_k5_parse_host_string(":300", 0, EINVAL, NULL, 300);
+}
+
+static void
+test_port_only(void **state)
+{
+    call_k5_parse_host_string("350", 0, 0, NULL, 350);
+}
+
+static void
+test_null_host(void **state)
+{
+    call_k5_parse_host_string(NULL, 400, EINVAL, NULL, 400);
+}
+
+static void
+test_empty_host(void **state)
+{
+    call_k5_parse_host_string("", 450, EINVAL, NULL, 450);
+}
+
+static void
+test_port_out_of_range(void **state)
+{
+    call_k5_parse_host_string("70000", 1, EINVAL, NULL, 0);
+}
+
+static void
+test_port_invalid_characters(void **state)
+{
+    call_k5_parse_host_string("test.example:F101", 1, EINVAL, NULL, 0);
+}
+
+static void
+test_invalid_default_port(void **state)
+{
+    call_k5_parse_host_string("test.example", 70000, EINVAL, NULL, 0);
+}
+
+/* k5_is_string_numeric() tests */
+
+static void
+test_numeric_single_digit(void **state)
+{
+    assert_true(k5_is_string_numeric("0"));
+}
+
+static void
+test_numeric_all_digits(void **state)
+{
+    assert_true(k5_is_string_numeric("0123456789"));
+}
+
+static void
+test_numeric_alpha(void **state)
+{
+    assert_false(k5_is_string_numeric("012345F6789"));
+}
+
+static void
+test_numeric_period(void **state)
+{
+    assert_false(k5_is_string_numeric("123.456"));
+}
+
+static void
+test_numeric_negative(void **state)
+{
+    assert_false(k5_is_string_numeric("-123"));
+}
+
+static void
+test_numeric_empty(void **state)
+{
+    assert_false(k5_is_string_numeric(""));
+}
+
+static void
+test_numeric_whitespace(void **state)
+{
+    assert_false(k5_is_string_numeric("123 456"));
+}
+
+int
+main(void)
+{
+    int ret;
+
+    const struct CMUnitTest k5_parse_host_string_tests[] = {
+        cmocka_unit_test(test_named_host_only),
+        cmocka_unit_test(test_named_host_w_port),
+        cmocka_unit_test(test_ipv4_only),
+        cmocka_unit_test(test_ipv4_w_port),
+        cmocka_unit_test(test_ipv6_only),
+        cmocka_unit_test(test_ipv6_w_port),
+        cmocka_unit_test(test_ipv6_w_zone),
+        cmocka_unit_test(test_invalid_ipv6),
+        cmocka_unit_test(test_no_host_port),
+        cmocka_unit_test(test_port_only),
+        cmocka_unit_test(test_null_host),
+        cmocka_unit_test(test_empty_host),
+        cmocka_unit_test(test_port_out_of_range),
+        cmocka_unit_test(test_port_invalid_characters),
+        cmocka_unit_test(test_invalid_default_port)
+    };
+
+    const struct CMUnitTest k5_is_string_numeric_tests[] = {
+        cmocka_unit_test(test_numeric_single_digit),
+        cmocka_unit_test(test_numeric_all_digits),
+        cmocka_unit_test(test_numeric_alpha),
+        cmocka_unit_test(test_numeric_period),
+        cmocka_unit_test(test_numeric_negative),
+        cmocka_unit_test(test_numeric_empty),
+        cmocka_unit_test(test_numeric_whitespace)
+    };
+
+    ret = cmocka_run_group_tests_name("k5_parse_host_string",
+                                      k5_parse_host_string_tests, NULL, NULL);
+    ret += cmocka_run_group_tests_name("k5_is_string_numeric",
+                                       k5_is_string_numeric_tests, NULL, NULL);
+
+    return ret;
+}
diff --git a/src/lib/krb5/libkrb5.exports b/src/lib/krb5/libkrb5.exports
index e350c89..cdda32d 100644
--- a/src/lib/krb5/libkrb5.exports
+++ b/src/lib/krb5/libkrb5.exports
@@ -131,6 +131,7 @@ k5_free_secure_cookie
 k5_free_serverlist
 k5_hostrealm_free_context
 k5_init_trace
+k5_is_string_numeric
 k5_kt_get_principal
 k5_localauth_free_context
 k5_locate_kdc


More information about the cvs-krb5 mailing list