summaryrefslogtreecommitdiffstats
path: root/gnulib-tests/test-userspec.c
diff options
context:
space:
mode:
Diffstat (limited to 'gnulib-tests/test-userspec.c')
-rw-r--r--gnulib-tests/test-userspec.c223
1 files changed, 223 insertions, 0 deletions
diff --git a/gnulib-tests/test-userspec.c b/gnulib-tests/test-userspec.c
new file mode 100644
index 0000000..330eb1e
--- /dev/null
+++ b/gnulib-tests/test-userspec.c
@@ -0,0 +1,223 @@
+/* Test userspec.c
+ Copyright (C) 2009-2023 Free Software Foundation, Inc.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <https://www.gnu.org/licenses/>. */
+
+/* Written by Jim Meyering. */
+
+#include <config.h>
+
+#include "userspec.h"
+
+#include <stdio.h>
+#include <assert.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <pwd.h>
+#include <grp.h>
+
+#include "xalloc.h"
+
+#define ARRAY_CARDINALITY(Array) (sizeof (Array) / sizeof *(Array))
+
+struct test
+{
+ char in[100];
+ uid_t uid;
+ gid_t gid;
+ const char *user_name;
+ const char *group_name;
+ const char *result;
+};
+
+static struct test T[] =
+ {
+ { "", -1, -1, "", "", NULL},
+ { ":", -1, -1, "", "", NULL},
+ { "+0:+0", 0, 0, "", "", NULL},
+ { "+0:+0", 0, 0, "", "", NULL},
+ { ":+1", -1, 1, "", "", NULL},
+ { "+1", 1, -1, "", "", NULL},
+ { ":+0", -1, 0, "", "", NULL},
+ { "+22:+42", 22, 42, "", "", NULL},
+ /* (uint32_t)-1 should be invalid everywhere */
+ { "+4294967295:+4294967295", 0, 0, NULL, NULL, "invalid user"},
+ /* likewise, but with only the group being invalid */
+ { "+0:+4294967295", 0, 0, NULL, NULL, "invalid group"},
+ { ":+4294967295", 0, 0, NULL, NULL, "invalid group"},
+ /* and only the user being invalid */
+ { "+4294967295:+0", 0, 0, NULL, NULL, "invalid user"},
+ /* and using 2^32 */
+ { "+4294967296:+4294967296", 0, 0, NULL, NULL, "invalid user"},
+ { "+0:+4294967296", 0, 0, NULL, NULL, "invalid group"},
+ { ":+4294967296", 0, 0, NULL, NULL, "invalid group"},
+ { "+4294967296:+0", 0, 0, NULL, NULL, "invalid user"},
+ /* numeric user and no group is invalid */
+ { "+4294967295:", 0, 0, NULL, NULL, "invalid spec"},
+ { "+4294967296:", 0, 0, NULL, NULL, "invalid spec"},
+ { "+1:", 0, 0, NULL, NULL, "invalid spec"},
+ { "+0:", 0, 0, NULL, NULL, "invalid spec"},
+
+ /* "username:" must expand to UID:GID where GID is username's login group */
+ /* Add an entry like the following to the table, if possible.
+ { "U_NAME:", UID,GID, U_NAME, G_NAME, NULL}, */
+ { "" /* placeholder */, -1, -1, "", "", NULL},
+ };
+
+#define STREQ(a, b) (strcmp (a, b) == 0)
+
+static char const *
+maybe_null (char const *s)
+{
+ return s ? s : "NULL";
+}
+
+static bool
+same_diag (char const *s, char const *t)
+{
+ if (s == NULL && t == NULL)
+ return true;
+ if (s == NULL || t == NULL)
+ return false;
+ return STREQ (s, t);
+}
+
+int
+main (void)
+{
+ unsigned int i;
+ int fail = 0;
+
+ /* Find a UID that has both a user name and login group name,
+ but skip UID 0. */
+ {
+ uid_t uid;
+ for (uid = 1200; 0 < uid; uid--)
+ {
+ struct group *gr;
+ struct passwd *pw = getpwuid (uid);
+ unsigned int j;
+ size_t len;
+ if (!pw || !pw->pw_name || !(gr = getgrgid (pw->pw_gid)) || !gr->gr_name)
+ continue;
+ j = ARRAY_CARDINALITY (T) - 1;
+ len = strlen (pw->pw_name);
+ if (sizeof T[j].in - 2 < len)
+ continue;
+
+ /* Store "username:" in T[j].in. */
+ memcpy(T[j].in, pw->pw_name, len);
+ strcpy(T[j].in + len, ":");
+
+ T[j].uid = uid;
+ T[j].gid = gr->gr_gid;
+ T[j].user_name = xstrdup (pw->pw_name);
+ T[j].group_name = xstrdup (gr->gr_name);
+ T[j].result = NULL;
+ break;
+ }
+ }
+
+ char *user_name = NULL;
+ char *group_name = NULL;
+
+ for (i = 0; i < ARRAY_CARDINALITY (T); i++)
+ {
+ uid_t uid = (uid_t) -1;
+ gid_t gid = (gid_t) -1;
+ free (user_name);
+ free (group_name);
+ char const *diag = parse_user_spec (T[i].in, &uid, &gid,
+ &user_name, &group_name);
+ if (!same_diag (diag, T[i].result))
+ {
+ printf ("%s return value mismatch: got %s, expected %s\n",
+ T[i].in, maybe_null (diag), maybe_null (T[i].result));
+ fail = 1;
+ continue;
+ }
+
+ if (diag)
+ continue;
+
+ if (uid != T[i].uid || gid != T[i].gid)
+ {
+ printf ("%s mismatch (-: expected uid,gid; +:actual)\n"
+ "-%3lu,%3lu\n+%3lu,%3lu\n",
+ T[i].in,
+ (unsigned long int) T[i].uid,
+ (unsigned long int) T[i].gid,
+ (unsigned long int) uid,
+ (unsigned long int) gid);
+ fail = 1;
+ }
+
+ if (T[i].result)
+ {
+ /* Expected a non-NULL result diagnostic, yet got NULL. */
+ diag = "NULL";
+ printf ("%s diagnostic mismatch (-: expected diagnostic; +:actual)\n"
+ "-%s\n+%s\n", T[i].in, T[i].result, diag);
+ fail = 1;
+ }
+ else
+ {
+ /* Should get the same result, but with a warning, if replacing
+ ':' with '.'. */
+ char *colon = strchr (T[i].in, ':');
+ if (colon)
+ {
+ *colon = '.';
+ uid_t uid2 = -1;
+ gid_t gid2 = -1;
+ char *user_name2 = NULL;
+ char *group_name2 = NULL;
+ bool warn;
+ if (! (parse_user_spec_warn (T[i].in, &uid2, &gid2,
+ &user_name2, &group_name2, &warn)
+ && warn))
+ printf ("%s did not warn\n", T[i].in);
+ else if (! (uid == uid2 && gid == gid2
+ && !!user_name == !!user_name2
+ && (!user_name || STREQ (user_name, user_name2))
+ && !!group_name == !!group_name2
+ && (!group_name || STREQ (group_name, group_name2))))
+ printf ("%s treated differently than with colon\n", T[i].in);
+
+ free (user_name2);
+ free (group_name2);
+ }
+ }
+ }
+
+ /* Ensure NULL parameters are ignored. */
+ {
+ uid_t uid = (uid_t) -1;
+ char const *diag = parse_user_spec ("", &uid, NULL, NULL, NULL);
+ if (diag)
+ {
+ printf ("unexpected error: %s\n", diag);
+ fail = 1;
+ }
+ }
+
+ return fail;
+}
+
+/*
+Local Variables:
+indent-tabs-mode: nil
+End:
+*/