1/* Test for processing of invalid group entries. [BZ #18724]
2 Copyright (C) 2015-2024 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
4
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, see
17 <https://www.gnu.org/licenses/>. */
18
19#include <errno.h>
20#include <grp.h>
21#include <stdbool.h>
22#include <stdio.h>
23#include <stdlib.h>
24#include <string.h>
25
26static bool errors;
27
28static void
29check (struct group e, const char *expected)
30{
31 char *buf;
32 size_t buf_size;
33 FILE *f = open_memstream (bufloc: &buf, sizeloc: &buf_size);
34
35 if (f == NULL)
36 {
37 printf (format: "open_memstream: %m\n");
38 errors = true;
39 return;
40 }
41
42 int ret = putgrent (p: &e, f: f);
43
44 if (expected == NULL)
45 {
46 if (ret == -1)
47 {
48 if (errno != EINVAL)
49 {
50 printf (format: "putgrent: unexpected error code: %m\n");
51 errors = true;
52 }
53 }
54 else
55 {
56 printf (format: "putgrent: unexpected success (\"%s\", \"%s\")\n",
57 e.gr_name, e.gr_passwd);
58 errors = true;
59 }
60 }
61 else
62 {
63 /* Expect success. */
64 size_t expected_length = strlen (expected);
65 if (ret == 0)
66 {
67 long written = ftell (stream: f);
68
69 if (written <= 0 || fflush (f) < 0)
70 {
71 printf (format: "stream error: %m\n");
72 errors = true;
73 }
74 else if (buf[written - 1] != '\n')
75 {
76 printf (format: "FAILED: \"%s\" without newline\n", expected);
77 errors = true;
78 }
79 else if (strncmp (buf, expected, written - 1) != 0
80 || written - 1 != expected_length)
81 {
82 buf[written - 1] = '\0';
83 printf (format: "FAILED: \"%s\" (%ld), expected \"%s\" (%zu)\n",
84 buf, written - 1, expected, expected_length);
85 errors = true;
86 }
87 }
88 else
89 {
90 printf (format: "FAILED: putgrent (expected \"%s\"): %m\n", expected);
91 errors = true;
92 }
93 }
94
95 fclose (f);
96 free (ptr: buf);
97}
98
99static int
100do_test (void)
101{
102 check (e: (struct group) {
103 .gr_name = (char *) "root",
104 },
105 expected: "root::0:");
106 check (e: (struct group) {
107 .gr_name = (char *) "root",
108 .gr_passwd = (char *) "password",
109 .gr_gid = 1234,
110 .gr_mem = (char *[2]) {(char *) "member1", NULL}
111 },
112 expected: "root:password:1234:member1");
113 check (e: (struct group) {
114 .gr_name = (char *) "root",
115 .gr_passwd = (char *) "password",
116 .gr_gid = 1234,
117 .gr_mem = (char *[3]) {(char *) "member1", (char *) "member2", NULL}
118 },
119 expected: "root:password:1234:member1,member2");
120
121 /* Bad values. */
122 {
123 static const char *const bad_strings[] = {
124 ":",
125 "\n",
126 ":bad",
127 "\nbad",
128 "b:ad",
129 "b\nad",
130 "bad:",
131 "bad\n",
132 "b:a\nd"
133 ",",
134 "\n,",
135 ":,",
136 ",bad",
137 "b,ad",
138 "bad,",
139 NULL
140 };
141 for (const char *const *bad = bad_strings; *bad != NULL; ++bad)
142 {
143 char *members[]
144 = {(char *) "first", (char *) *bad, (char *) "last", NULL};
145 if (strpbrk (*bad, ":\n") != NULL)
146 {
147 check (e: (struct group) {
148 .gr_name = (char *) *bad,
149 }, NULL);
150 check (e: (struct group) {
151 .gr_name = (char *) "root",
152 .gr_passwd = (char *) *bad,
153 }, NULL);
154 }
155 check (e: (struct group) {
156 .gr_name = (char *) "root",
157 .gr_passwd = (char *) "password",
158 .gr_mem = members,
159 }, NULL);
160 }
161 }
162
163 return errors;
164}
165
166#define TEST_FUNCTION do_test ()
167#include "../test-skeleton.c"
168

source code of glibc/nss/tst-putgrent.c