1 /*
2    Unix SMB/CIFS implementation.
3 
4    local testing of the nss wrapper
5 
6    Copyright (C) Guenther Deschner 2009-2010
7 
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 3 of the License, or
11    (at your option) any later version.
12 
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17 
18    You should have received a copy of the GNU General Public License
19    along with this program.  If not, see <http://www.gnu.org/licenses/>.
20 */
21 
22 #include "includes.h"
23 
24 #include "torture/torture.h"
25 #include "torture/local/proto.h"
26 #include "lib/replace/system/passwd.h"
27 
copy_passwd(struct torture_context * tctx,const struct passwd * pwd,struct passwd * p)28 static bool copy_passwd(struct torture_context *tctx,
29 			const struct passwd *pwd,
30 			struct passwd *p)
31 {
32 	p->pw_name	= talloc_strdup(tctx, pwd->pw_name);
33 	torture_assert(tctx, (p->pw_name != NULL || pwd->pw_name == NULL), __location__);
34 	p->pw_passwd	= talloc_strdup(tctx, pwd->pw_passwd);
35 	torture_assert(tctx, (p->pw_passwd != NULL || pwd->pw_passwd == NULL), __location__);
36 	p->pw_uid	= pwd->pw_uid;
37 	p->pw_gid	= pwd->pw_gid;
38 	p->pw_gecos	= talloc_strdup(tctx, pwd->pw_gecos);
39 	torture_assert(tctx, (p->pw_gecos != NULL || pwd->pw_gecos == NULL), __location__);
40 	p->pw_dir	= talloc_strdup(tctx, pwd->pw_dir);
41 	torture_assert(tctx, (p->pw_dir != NULL || pwd->pw_dir == NULL), __location__);
42 	p->pw_shell	= talloc_strdup(tctx, pwd->pw_shell);
43 	torture_assert(tctx, (p->pw_shell != NULL || pwd->pw_shell == NULL), __location__);
44 
45 	return true;
46 }
47 
print_passwd(struct passwd * pwd)48 static void print_passwd(struct passwd *pwd)
49 {
50 	printf("%s:%s:%lu:%lu:%s:%s:%s\n",
51 	       pwd->pw_name,
52 	       pwd->pw_passwd,
53 	       (unsigned long)pwd->pw_uid,
54 	       (unsigned long)pwd->pw_gid,
55 	       pwd->pw_gecos,
56 	       pwd->pw_dir,
57 	       pwd->pw_shell);
58 }
59 
60 
test_getpwnam(struct torture_context * tctx,const char * name,struct passwd * pwd_p)61 static bool test_getpwnam(struct torture_context *tctx,
62 			  const char *name,
63 			  struct passwd *pwd_p)
64 {
65 	struct passwd *pwd;
66 	int ret;
67 
68 	torture_comment(tctx, "Testing getpwnam: %s\n", name);
69 
70 	errno = 0;
71 	pwd = getpwnam(name);
72 	ret = errno;
73 	torture_assert(tctx, (pwd != NULL), talloc_asprintf(tctx,
74 		       "getpwnam(%s) failed - %d - %s",
75 		       name, ret, strerror(ret)));
76 
77 	if (pwd_p != NULL) {
78 		torture_assert(tctx, copy_passwd(tctx, pwd, pwd_p), __location__);
79 	}
80 
81 	return true;
82 }
83 
test_getpwnam_r(struct torture_context * tctx,const char * name,struct passwd * pwd_p)84 static bool test_getpwnam_r(struct torture_context *tctx,
85 			    const char *name,
86 			    struct passwd *pwd_p)
87 {
88 	struct passwd pwd, *pwdp;
89 	char buffer[4096];
90 	int ret;
91 
92 	torture_comment(tctx, "Testing getpwnam_r: %s\n", name);
93 
94 	ret = getpwnam_r(name, &pwd, buffer, sizeof(buffer), &pwdp);
95 	torture_assert(tctx, ret == 0, talloc_asprintf(tctx,
96 		       "getpwnam_r(%s) failed - %d - %s",
97 		       name, ret, strerror(ret)));
98 
99 	print_passwd(&pwd);
100 
101 	if (pwd_p != NULL) {
102 		torture_assert(tctx, copy_passwd(tctx, &pwd, pwd_p), __location__);
103 	}
104 
105 	return true;
106 }
107 
test_getpwuid(struct torture_context * tctx,uid_t uid,struct passwd * pwd_p)108 static bool test_getpwuid(struct torture_context *tctx,
109 			  uid_t uid,
110 			  struct passwd *pwd_p)
111 {
112 	struct passwd *pwd;
113 	int ret;
114 
115 	torture_comment(tctx, "Testing getpwuid: %lu\n", (unsigned long)uid);
116 
117 	errno = 0;
118 	pwd = getpwuid(uid);
119 	ret = errno;
120 	torture_assert(tctx, (pwd != NULL), talloc_asprintf(tctx,
121 		       "getpwuid(%lu) failed - %d - %s",
122 		       (unsigned long)uid, ret, strerror(ret)));
123 
124 	print_passwd(pwd);
125 
126 	if (pwd_p != NULL) {
127 		torture_assert(tctx, copy_passwd(tctx, pwd, pwd_p), __location__);
128 	}
129 
130 	return true;
131 }
132 
test_getpwuid_r(struct torture_context * tctx,uid_t uid,struct passwd * pwd_p)133 static bool test_getpwuid_r(struct torture_context *tctx,
134 			    uid_t uid,
135 			    struct passwd *pwd_p)
136 {
137 	struct passwd pwd, *pwdp;
138 	char buffer[4096];
139 	int ret;
140 
141 	torture_comment(tctx, "Testing getpwuid_r: %lu\n", (unsigned long)uid);
142 
143 	ret = getpwuid_r(uid, &pwd, buffer, sizeof(buffer), &pwdp);
144 	torture_assert(tctx, ret == 0, talloc_asprintf(tctx,
145 		       "getpwuid_r(%lu) failed - %d - %s",
146 		       (unsigned long)uid, ret, strerror(ret)));
147 
148 	print_passwd(&pwd);
149 
150 	if (pwd_p != NULL) {
151 		torture_assert(tctx, copy_passwd(tctx, &pwd, pwd_p), __location__);
152 	}
153 
154 	return true;
155 }
156 
157 
copy_group(struct torture_context * tctx,const struct group * grp,struct group * g)158 static bool copy_group(struct torture_context *tctx,
159 		       const struct group *grp,
160 		       struct group *g)
161 {
162 	int i;
163 
164 	g->gr_name	= talloc_strdup(tctx, grp->gr_name);
165 	torture_assert(tctx, (g->gr_name != NULL || grp->gr_name == NULL), __location__);
166 	g->gr_passwd	= talloc_strdup(tctx, grp->gr_passwd);
167 	torture_assert(tctx, (g->gr_passwd != NULL || grp->gr_passwd == NULL), __location__);
168 	g->gr_gid	= grp->gr_gid;
169 	g->gr_mem	= NULL;
170 
171 	for (i=0; grp->gr_mem && grp->gr_mem[i]; i++) {
172 		g->gr_mem = talloc_realloc(tctx, g->gr_mem, char *, i + 2);
173 		torture_assert(tctx, (g->gr_mem != NULL), __location__);
174 		g->gr_mem[i] = talloc_strdup(g->gr_mem, grp->gr_mem[i]);
175 		torture_assert(tctx, (g->gr_mem[i] != NULL), __location__);
176 		g->gr_mem[i+1] = NULL;
177 	}
178 
179 	return true;
180 }
181 
print_group(struct group * grp)182 static void print_group(struct group *grp)
183 {
184 	int i;
185 	printf("%s:%s:%lu:",
186 	       grp->gr_name,
187 	       grp->gr_passwd,
188 	       (unsigned long)grp->gr_gid);
189 
190 	if ((grp->gr_mem == NULL) || !grp->gr_mem[0]) {
191 		printf("\n");
192 		return;
193 	}
194 
195 	for (i=0; grp->gr_mem[i+1]; i++) {
196 		printf("%s,", grp->gr_mem[i]);
197 	}
198 	printf("%s\n", grp->gr_mem[i]);
199 }
200 
test_getgrnam(struct torture_context * tctx,const char * name,struct group * grp_p)201 static bool test_getgrnam(struct torture_context *tctx,
202 			  const char *name,
203 			  struct group *grp_p)
204 {
205 	struct group *grp;
206 	int ret;
207 
208 	torture_comment(tctx, "Testing getgrnam: %s\n", name);
209 
210 	errno = 0;
211 	grp = getgrnam(name);
212 	ret = errno;
213 	torture_assert(tctx, (grp != NULL), talloc_asprintf(tctx,
214 		       "getgrnam(%s) failed - %d - %s",
215 		       name, ret, strerror(ret)));
216 
217 	print_group(grp);
218 
219 	if (grp_p != NULL) {
220 		torture_assert(tctx, copy_group(tctx, grp, grp_p), __location__);
221 	}
222 
223 	return true;
224 }
225 
test_getgrnam_r(struct torture_context * tctx,const char * name,struct group * grp_p)226 static bool test_getgrnam_r(struct torture_context *tctx,
227 			    const char *name,
228 			    struct group *grp_p)
229 {
230 	struct group grp, *grpp;
231 	char buffer[4096];
232 	int ret;
233 
234 	torture_comment(tctx, "Testing getgrnam_r: %s\n", name);
235 
236 	ret = getgrnam_r(name, &grp, buffer, sizeof(buffer), &grpp);
237 	torture_assert(tctx, ret == 0, talloc_asprintf(tctx,
238 		       "getgrnam_r(%s) failed - %d - %s",
239 		       name, ret, strerror(ret)));
240 
241 	print_group(&grp);
242 
243 	if (grp_p != NULL) {
244 		torture_assert(tctx, copy_group(tctx, &grp, grp_p), __location__);
245 	}
246 
247 	return true;
248 }
249 
250 
test_getgrgid(struct torture_context * tctx,gid_t gid,struct group * grp_p)251 static bool test_getgrgid(struct torture_context *tctx,
252 			  gid_t gid,
253 			  struct group *grp_p)
254 {
255 	struct group *grp;
256 	int ret;
257 
258 	torture_comment(tctx, "Testing getgrgid: %lu\n", (unsigned long)gid);
259 
260 	errno = 0;
261 	grp = getgrgid(gid);
262 	ret = errno;
263 	torture_assert(tctx, (grp != NULL), talloc_asprintf(tctx,
264 		       "getgrgid(%lu) failed - %d - %s",
265 		       (unsigned long)gid, ret, strerror(ret)));
266 
267 	print_group(grp);
268 
269 	if (grp_p != NULL) {
270 		torture_assert(tctx, copy_group(tctx, grp, grp_p), __location__);
271 	}
272 
273 	return true;
274 }
275 
test_getgrgid_r(struct torture_context * tctx,gid_t gid,struct group * grp_p)276 static bool test_getgrgid_r(struct torture_context *tctx,
277 			    gid_t gid,
278 			    struct group *grp_p)
279 {
280 	struct group grp, *grpp;
281 	char buffer[4096];
282 	int ret;
283 
284 	torture_comment(tctx, "Testing getgrgid_r: %lu\n", (unsigned long)gid);
285 
286 	ret = getgrgid_r(gid, &grp, buffer, sizeof(buffer), &grpp);
287 	torture_assert(tctx, ret == 0, talloc_asprintf(tctx,
288 		       "getgrgid_r(%lu) failed - %d - %s",
289 		       (unsigned long)gid, ret, strerror(ret)));
290 
291 	print_group(&grp);
292 
293 	if (grp_p != NULL) {
294 		torture_assert(tctx, copy_group(tctx, &grp, grp_p), __location__);
295 	}
296 
297 	return true;
298 }
299 
test_enum_passwd(struct torture_context * tctx,struct passwd ** pwd_array_p,size_t * num_pwd_p)300 static bool test_enum_passwd(struct torture_context *tctx,
301 			     struct passwd **pwd_array_p,
302 			     size_t *num_pwd_p)
303 {
304 	struct passwd *pwd;
305 	struct passwd *pwd_array = NULL;
306 	size_t num_pwd = 0;
307 
308 	torture_comment(tctx, "Testing setpwent\n");
309 	setpwent();
310 
311 	while ((pwd = getpwent()) != NULL) {
312 		torture_comment(tctx, "Testing getpwent\n");
313 
314 		print_passwd(pwd);
315 		if (pwd_array_p && num_pwd_p) {
316 			pwd_array = talloc_realloc(tctx, pwd_array, struct passwd, num_pwd+1);
317 			torture_assert(tctx, pwd_array, "out of memory");
318 			copy_passwd(tctx, pwd, &pwd_array[num_pwd]);
319 			num_pwd++;
320 		}
321 	}
322 
323 	torture_comment(tctx, "Testing endpwent\n");
324 	endpwent();
325 
326 	if (pwd_array_p) {
327 		*pwd_array_p = pwd_array;
328 	}
329 	if (num_pwd_p) {
330 		*num_pwd_p = num_pwd;
331 	}
332 
333 	return true;
334 }
335 
test_enum_r_passwd(struct torture_context * tctx,struct passwd ** pwd_array_p,size_t * num_pwd_p)336 static bool test_enum_r_passwd(struct torture_context *tctx,
337 			       struct passwd **pwd_array_p,
338 			       size_t *num_pwd_p)
339 {
340 	struct passwd pwd, *pwdp;
341 	struct passwd *pwd_array = NULL;
342 	size_t num_pwd = 0;
343 	char buffer[4096];
344 	int ret;
345 
346 	torture_comment(tctx, "Testing setpwent\n");
347 	setpwent();
348 
349 #ifdef HAVE_GETPWENT_R /* getpwent_r not supported on macOS */
350 	while (1) {
351 		torture_comment(tctx, "Testing getpwent_r\n");
352 
353 #ifdef SOLARIS_GETPWENT_R
354 		ret = getpwent_r(&pwd, buffer, sizeof(buffer));
355 #else /* SOLARIS_GETPWENT_R */
356 		ret = getpwent_r(&pwd, buffer, sizeof(buffer), &pwdp);
357 #endif /* SOLARIS_GETPWENT_R */
358 		if (ret != 0) {
359 			if (ret != ENOENT) {
360 				torture_comment(tctx, "got %d return code\n", ret);
361 			}
362 			break;
363 		}
364 		print_passwd(&pwd);
365 		if (pwd_array_p && num_pwd_p) {
366 			pwd_array = talloc_realloc(tctx, pwd_array, struct passwd, num_pwd+1);
367 			torture_assert(tctx, pwd_array, "out of memory");
368 			copy_passwd(tctx, &pwd, &pwd_array[num_pwd]);
369 			num_pwd++;
370 		}
371 	}
372 #endif /* getpwent_r not supported on macOS */
373 
374 	torture_comment(tctx, "Testing endpwent\n");
375 	endpwent();
376 
377 	if (pwd_array_p) {
378 		*pwd_array_p = pwd_array;
379 	}
380 	if (num_pwd_p) {
381 		*num_pwd_p = num_pwd;
382 	}
383 
384 	return true;
385 }
386 
torture_assert_passwd_equal(struct torture_context * tctx,const struct passwd * p1,const struct passwd * p2,const char * comment)387 static bool torture_assert_passwd_equal(struct torture_context *tctx,
388 					const struct passwd *p1,
389 					const struct passwd *p2,
390 					const char *comment)
391 {
392 	torture_assert_str_equal(tctx, p1->pw_name, p2->pw_name, comment);
393 	torture_assert_str_equal(tctx, p1->pw_passwd, p2->pw_passwd, comment);
394 	torture_assert_int_equal(tctx, p1->pw_uid, p2->pw_uid, comment);
395 	torture_assert_int_equal(tctx, p1->pw_gid, p2->pw_gid, comment);
396 	torture_assert_str_equal(tctx, p1->pw_gecos, p2->pw_gecos, comment);
397 	torture_assert_str_equal(tctx, p1->pw_dir, p2->pw_dir, comment);
398 	torture_assert_str_equal(tctx, p1->pw_shell, p2->pw_shell, comment);
399 
400 	return true;
401 }
402 
test_passwd(struct torture_context * tctx)403 static bool test_passwd(struct torture_context *tctx)
404 {
405 	int i;
406 	struct passwd *pwd, pwd1, pwd2;
407 	size_t num_pwd;
408 
409 	torture_assert(tctx, test_enum_passwd(tctx, &pwd, &num_pwd),
410 					      "failed to enumerate passwd");
411 
412 	for (i=0; i < num_pwd; i++) {
413 		torture_assert(tctx, test_getpwnam(tctx, pwd[i].pw_name, &pwd1),
414 			"failed to call getpwnam for enumerated user");
415 		torture_assert(tctx, torture_assert_passwd_equal(tctx, &pwd[i], &pwd1,
416 			"getpwent and getpwnam gave different results"),
417 			__location__);
418 		torture_assert(tctx, test_getpwuid(tctx, pwd[i].pw_uid, &pwd2),
419 			"failed to call getpwuid for enumerated user");
420 		torture_assert(tctx, torture_assert_passwd_equal(tctx, &pwd[i], &pwd2,
421 			"getpwent and getpwuid gave different results"),
422 			__location__);
423 		torture_assert(tctx, torture_assert_passwd_equal(tctx, &pwd1, &pwd2,
424 			"getpwnam and getpwuid gave different results"),
425 			__location__);
426 	}
427 
428 	return true;
429 }
430 
test_passwd_r(struct torture_context * tctx)431 static bool test_passwd_r(struct torture_context *tctx)
432 {
433 	int i;
434 	struct passwd *pwd, pwd1, pwd2;
435 	size_t num_pwd;
436 
437 	torture_assert(tctx, test_enum_r_passwd(tctx, &pwd, &num_pwd),
438 						"failed to enumerate passwd");
439 
440 	for (i=0; i < num_pwd; i++) {
441 		torture_assert(tctx, test_getpwnam_r(tctx, pwd[i].pw_name, &pwd1),
442 			"failed to call getpwnam_r for enumerated user");
443 		torture_assert(tctx, torture_assert_passwd_equal(tctx, &pwd[i], &pwd1,
444 			"getpwent_r and getpwnam_r gave different results"),
445 			__location__);
446 		torture_assert(tctx, test_getpwuid_r(tctx, pwd[i].pw_uid, &pwd2),
447 			"failed to call getpwuid_r for enumerated user");
448 		torture_assert(tctx, torture_assert_passwd_equal(tctx, &pwd[i], &pwd2,
449 			"getpwent_r and getpwuid_r gave different results"),
450 			__location__);
451 		torture_assert(tctx, torture_assert_passwd_equal(tctx, &pwd1, &pwd2,
452 			"getpwnam_r and getpwuid_r gave different results"),
453 			__location__);
454 	}
455 
456 	return true;
457 }
458 
test_passwd_r_cross(struct torture_context * tctx)459 static bool test_passwd_r_cross(struct torture_context *tctx)
460 {
461 	int i;
462 	struct passwd *pwd, pwd1, pwd2, pwd3, pwd4;
463 	size_t num_pwd;
464 
465 	torture_assert(tctx, test_enum_r_passwd(tctx, &pwd, &num_pwd),
466 						"failed to enumerate passwd");
467 
468 	for (i=0; i < num_pwd; i++) {
469 		torture_assert(tctx, test_getpwnam_r(tctx, pwd[i].pw_name, &pwd1),
470 			"failed to call getpwnam_r for enumerated user");
471 		torture_assert(tctx, torture_assert_passwd_equal(tctx, &pwd[i], &pwd1,
472 			"getpwent_r and getpwnam_r gave different results"),
473 			__location__);
474 		torture_assert(tctx, test_getpwuid_r(tctx, pwd[i].pw_uid, &pwd2),
475 			"failed to call getpwuid_r for enumerated user");
476 		torture_assert(tctx, torture_assert_passwd_equal(tctx, &pwd[i], &pwd2,
477 			"getpwent_r and getpwuid_r gave different results"),
478 			__location__);
479 		torture_assert(tctx, torture_assert_passwd_equal(tctx, &pwd1, &pwd2,
480 			"getpwnam_r and getpwuid_r gave different results"),
481 			__location__);
482 		torture_assert(tctx, test_getpwnam(tctx, pwd[i].pw_name, &pwd3),
483 			"failed to call getpwnam for enumerated user");
484 		torture_assert(tctx, torture_assert_passwd_equal(tctx, &pwd[i], &pwd3,
485 			"getpwent_r and getpwnam gave different results"),
486 			__location__);
487 		torture_assert(tctx, test_getpwuid(tctx, pwd[i].pw_uid, &pwd4),
488 			"failed to call getpwuid for enumerated user");
489 		torture_assert(tctx, torture_assert_passwd_equal(tctx, &pwd[i], &pwd4,
490 			"getpwent_r and getpwuid gave different results"),
491 			__location__);
492 		torture_assert(tctx, torture_assert_passwd_equal(tctx, &pwd3, &pwd4,
493 			"getpwnam and getpwuid gave different results"),
494 			__location__);
495 	}
496 
497 	return true;
498 }
499 
test_enum_group(struct torture_context * tctx,struct group ** grp_array_p,size_t * num_grp_p)500 static bool test_enum_group(struct torture_context *tctx,
501 			    struct group **grp_array_p,
502 			    size_t *num_grp_p)
503 {
504 	struct group *grp;
505 	struct group *grp_array = NULL;
506 	size_t num_grp = 0;
507 
508 	torture_comment(tctx, "Testing setgrent\n");
509 	setgrent();
510 
511 	while ((grp = getgrent()) != NULL) {
512 		torture_comment(tctx, "Testing getgrent\n");
513 
514 		print_group(grp);
515 		if (grp_array_p && num_grp_p) {
516 			grp_array = talloc_realloc(tctx, grp_array, struct group, num_grp+1);
517 			torture_assert(tctx, grp_array, "out of memory");
518 			copy_group(tctx, grp, &grp_array[num_grp]);
519 			num_grp++;
520 		}
521 	}
522 
523 	torture_comment(tctx, "Testing endgrent\n");
524 	endgrent();
525 
526 	if (grp_array_p) {
527 		*grp_array_p = grp_array;
528 	}
529 	if (num_grp_p) {
530 		*num_grp_p = num_grp;
531 	}
532 
533 	return true;
534 }
535 
test_enum_r_group(struct torture_context * tctx,struct group ** grp_array_p,size_t * num_grp_p)536 static bool test_enum_r_group(struct torture_context *tctx,
537 			      struct group **grp_array_p,
538 			      size_t *num_grp_p)
539 {
540 	struct group grp, *grpp;
541 	struct group *grp_array = NULL;
542 	size_t num_grp = 0;
543 	char buffer[4096];
544 	int ret;
545 
546 	torture_comment(tctx, "Testing setgrent\n");
547 	setgrent();
548 
549 #ifdef HAVE_GETGRENT_R /* getgrent_r not supported on macOS */
550 	while (1) {
551 		torture_comment(tctx, "Testing getgrent_r\n");
552 
553 #ifdef SOLARIS_GETGRENT_R
554 		ret = getgrent_r(&grp, buffer, sizeof(buffer));
555 #else /* SOLARIS_GETGRENT_R */
556 		ret = getgrent_r(&grp, buffer, sizeof(buffer), &grpp);
557 #endif /* SOLARIS_GETGRENT_R */
558 		if (ret != 0) {
559 			if (ret != ENOENT) {
560 				torture_comment(tctx, "got %d return code\n", ret);
561 			}
562 			break;
563 		}
564 		print_group(&grp);
565 		if (grp_array_p && num_grp_p) {
566 			grp_array = talloc_realloc(tctx, grp_array, struct group, num_grp+1);
567 			torture_assert(tctx, grp_array, "out of memory");
568 			copy_group(tctx, &grp, &grp_array[num_grp]);
569 			num_grp++;
570 		}
571 	}
572 #endif /* getgrent_r not supported on macOS */
573 
574 	torture_comment(tctx, "Testing endgrent\n");
575 	endgrent();
576 
577 	if (grp_array_p) {
578 		*grp_array_p = grp_array;
579 	}
580 	if (num_grp_p) {
581 		*num_grp_p = num_grp;
582 	}
583 
584 	return true;
585 }
586 
torture_assert_group_equal(struct torture_context * tctx,const struct group * g1,const struct group * g2,const char * comment)587 static bool torture_assert_group_equal(struct torture_context *tctx,
588 				       const struct group *g1,
589 				       const struct group *g2,
590 				       const char *comment)
591 {
592 	int i;
593 	torture_assert_str_equal(tctx, g1->gr_name, g2->gr_name, comment);
594 	torture_assert_str_equal(tctx, g1->gr_passwd, g2->gr_passwd, comment);
595 	torture_assert_int_equal(tctx, g1->gr_gid, g2->gr_gid, comment);
596 	torture_assert(tctx, !(g1->gr_mem && !g2->gr_mem), __location__);
597 	torture_assert(tctx, !(!g1->gr_mem && g2->gr_mem), __location__);
598 	if (!g1->gr_mem && !g2->gr_mem) {
599 		return true;
600 	}
601 	for (i=0; g1->gr_mem[i] && g2->gr_mem[i]; i++) {
602 		torture_assert_str_equal(tctx, g1->gr_mem[i], g2->gr_mem[i], comment);
603 	}
604 
605 	return true;
606 }
607 
test_group(struct torture_context * tctx)608 static bool test_group(struct torture_context *tctx)
609 {
610 	int i;
611 	struct group *grp, grp1, grp2;
612 	size_t num_grp;
613 
614 	torture_assert(tctx, test_enum_group(tctx, &grp, &num_grp),
615 					     "failed to enumerate group");
616 
617 	for (i=0; i < num_grp; i++) {
618 		torture_assert(tctx, test_getgrnam(tctx, grp[i].gr_name, &grp1),
619 			"failed to call getgrnam for enumerated user");
620 		torture_assert(tctx, torture_assert_group_equal(tctx, &grp[i], &grp1,
621 			"getgrent and getgrnam gave different results"),
622 			__location__);
623 		torture_assert(tctx, test_getgrgid(tctx, grp[i].gr_gid, &grp2),
624 			"failed to call getgrgid for enumerated user");
625 		torture_assert(tctx, torture_assert_group_equal(tctx, &grp[i], &grp2,
626 			"getgrent and getgrgid gave different results"),
627 			__location__);
628 		torture_assert(tctx, torture_assert_group_equal(tctx, &grp1, &grp2,
629 			"getgrnam and getgrgid gave different results"),
630 			__location__);
631 	}
632 
633 	return true;
634 }
635 
test_group_r(struct torture_context * tctx)636 static bool test_group_r(struct torture_context *tctx)
637 {
638 	int i;
639 	struct group *grp, grp1, grp2;
640 	size_t num_grp;
641 
642 	torture_assert(tctx, test_enum_r_group(tctx, &grp, &num_grp),
643 					       "failed to enumerate group");
644 
645 	for (i=0; i < num_grp; i++) {
646 		torture_assert(tctx, test_getgrnam_r(tctx, grp[i].gr_name, &grp1),
647 			"failed to call getgrnam_r for enumerated user");
648 		torture_assert(tctx, torture_assert_group_equal(tctx, &grp[i], &grp1,
649 			"getgrent_r and getgrnam_r gave different results"),
650 			__location__);
651 		torture_assert(tctx, test_getgrgid_r(tctx, grp[i].gr_gid, &grp2),
652 			"failed to call getgrgid_r for enumerated user");
653 		torture_assert(tctx, torture_assert_group_equal(tctx, &grp[i], &grp2,
654 			"getgrent_r and getgrgid_r gave different results"),
655 			__location__);
656 		torture_assert(tctx, torture_assert_group_equal(tctx, &grp1, &grp2,
657 			"getgrnam_r and getgrgid_r gave different results"),
658 			__location__);
659 	}
660 
661 	return true;
662 }
663 
test_group_r_cross(struct torture_context * tctx)664 static bool test_group_r_cross(struct torture_context *tctx)
665 {
666 	int i;
667 	struct group *grp, grp1, grp2, grp3, grp4;
668 	size_t num_grp;
669 
670 	torture_assert(tctx, test_enum_r_group(tctx, &grp, &num_grp),
671 					       "failed to enumerate group");
672 
673 	for (i=0; i < num_grp; i++) {
674 		torture_assert(tctx, test_getgrnam_r(tctx, grp[i].gr_name, &grp1),
675 			"failed to call getgrnam_r for enumerated user");
676 		torture_assert(tctx, torture_assert_group_equal(tctx, &grp[i], &grp1,
677 			"getgrent_r and getgrnam_r gave different results"),
678 			__location__);
679 		torture_assert(tctx, test_getgrgid_r(tctx, grp[i].gr_gid, &grp2),
680 			"failed to call getgrgid_r for enumerated user");
681 		torture_assert(tctx, torture_assert_group_equal(tctx, &grp[i], &grp2,
682 			"getgrent_r and getgrgid_r gave different results"),
683 			__location__);
684 		torture_assert(tctx, torture_assert_group_equal(tctx, &grp1, &grp2,
685 			"getgrnam_r and getgrgid_r gave different results"),
686 			__location__);
687 		torture_assert(tctx, test_getgrnam(tctx, grp[i].gr_name, &grp3),
688 			"failed to call getgrnam for enumerated user");
689 		torture_assert(tctx, torture_assert_group_equal(tctx, &grp[i], &grp3,
690 			"getgrent_r and getgrnam gave different results"),
691 			__location__);
692 		torture_assert(tctx, test_getgrgid(tctx, grp[i].gr_gid, &grp4),
693 			"failed to call getgrgid for enumerated user");
694 		torture_assert(tctx, torture_assert_group_equal(tctx, &grp[i], &grp4,
695 			"getgrent_r and getgrgid gave different results"),
696 			__location__);
697 		torture_assert(tctx, torture_assert_group_equal(tctx, &grp3, &grp4,
698 			"getgrnam and getgrgid gave different results"),
699 			__location__);
700 	}
701 
702 	return true;
703 }
704 
705 #ifdef HAVE_GETGROUPLIST
test_getgrouplist(struct torture_context * tctx,const char * user,gid_t gid,gid_t ** gids_p,int * num_gids_p)706 static bool test_getgrouplist(struct torture_context *tctx,
707 			      const char *user,
708 			      gid_t gid,
709 			      gid_t **gids_p,
710 			      int *num_gids_p)
711 {
712 	int ret;
713 	int num_groups = 0;
714 	gid_t *groups = NULL;
715 
716 	torture_comment(tctx, "Testing getgrouplist: %s\n", user);
717 
718 	ret = getgrouplist(user, gid, NULL, &num_groups);
719 	if (ret == -1 || num_groups != 0) {
720 
721 		groups = talloc_array(tctx, gid_t, num_groups);
722 		torture_assert(tctx, groups, "out of memory\n");
723 
724 		ret = getgrouplist(user, gid, groups, &num_groups);
725 	}
726 
727 	torture_assert(tctx, (ret != -1), "failed to call getgrouplist");
728 
729 	torture_comment(tctx, "%s is member in %d groups\n", user, num_groups);
730 
731 	if (gids_p) {
732 		*gids_p = groups;
733 	}
734 	if (num_gids_p) {
735 		*num_gids_p = num_groups;
736 	}
737 
738 	return true;
739 }
740 #endif /* HAVE_GETGROUPLIST */
741 
test_user_in_group(struct torture_context * tctx,const struct passwd * pwd,const struct group * grp)742 static bool test_user_in_group(struct torture_context *tctx,
743 			       const struct passwd *pwd,
744 			       const struct group *grp)
745 {
746 	int i;
747 
748 	for (i=0; grp->gr_mem && grp->gr_mem[i] != NULL; i++) {
749 		if (strequal(grp->gr_mem[i], pwd->pw_name)) {
750 			return true;
751 		}
752 	}
753 
754 	return false;
755 }
756 
test_membership_user(struct torture_context * tctx,const struct passwd * pwd,struct group * grp_array,size_t num_grp)757 static bool test_membership_user(struct torture_context *tctx,
758 				 const struct passwd *pwd,
759 				 struct group *grp_array,
760 				 size_t num_grp)
761 {
762 	int num_user_groups = 0;
763 	int num_user_groups_from_enum = 0;
764 	gid_t *user_groups = NULL;
765 	int g, i;
766 	bool primary_group_had_user_member = false;
767 
768 #ifdef HAVE_GETGROUPLIST
769 	torture_assert(tctx, test_getgrouplist(tctx,
770 					       pwd->pw_name,
771 					       pwd->pw_gid,
772 					       &user_groups,
773 					       &num_user_groups),
774 					       "failed to test getgrouplist");
775 #endif /* HAVE_GETGROUPLIST */
776 
777 	for (g=0; g < num_user_groups; g++) {
778 		torture_assert(tctx, test_getgrgid(tctx, user_groups[g], NULL),
779 			"failed to find the group the user is a member of");
780 	}
781 
782 
783 	for (i=0; i < num_grp; i++) {
784 
785 		struct group grp = grp_array[i];
786 
787 		if (test_user_in_group(tctx, pwd, &grp)) {
788 
789 			struct group current_grp;
790 			num_user_groups_from_enum++;
791 
792 			torture_assert(tctx, test_getgrnam(tctx, grp.gr_name, &current_grp),
793 					"failed to find the group the user is a member of");
794 
795 			if (current_grp.gr_gid == pwd->pw_gid) {
796 				torture_comment(tctx, "primary group %s of user %s lists user as member\n",
797 						current_grp.gr_name,
798 						pwd->pw_name);
799 				primary_group_had_user_member = true;
800 			}
801 
802 			continue;
803 		}
804 	}
805 
806 	if (!primary_group_had_user_member) {
807 		num_user_groups_from_enum++;
808 	}
809 
810 	torture_assert_int_equal(tctx, num_user_groups, num_user_groups_from_enum,
811 		"getgrouplist and real inspection of grouplist gave different results\n");
812 
813 	return true;
814 }
815 
test_membership(struct torture_context * tctx)816 static bool test_membership(struct torture_context *tctx)
817 {
818 	const char *old_pwd = getenv("NSS_WRAPPER_PASSWD");
819 	const char *old_group = getenv("NSS_WRAPPER_GROUP");
820 	struct passwd *pwd;
821 	size_t num_pwd;
822 	struct group *grp;
823 	size_t num_grp;
824 	int i;
825 
826 	if (!old_pwd || !old_group) {
827 		torture_comment(tctx, "ENV NSS_WRAPPER_PASSWD or NSS_WRAPPER_GROUP not set\n");
828 		torture_skip(tctx, "nothing to test\n");
829 	}
830 
831 	torture_assert(tctx, test_enum_passwd(tctx, &pwd, &num_pwd),
832 					      "failed to enumerate passwd");
833 	torture_assert(tctx, test_enum_group(tctx, &grp, &num_grp),
834 					     "failed to enumerate group");
835 
836 	for (i=0; i < num_pwd; i++) {
837 
838 		torture_assert(tctx, test_membership_user(tctx, &pwd[i], grp, num_grp),
839 			"failed to test membership for user");
840 
841 	}
842 
843 	return true;
844 }
845 
test_enumeration(struct torture_context * tctx)846 static bool test_enumeration(struct torture_context *tctx)
847 {
848 	const char *old_pwd = getenv("NSS_WRAPPER_PASSWD");
849 	const char *old_group = getenv("NSS_WRAPPER_GROUP");
850 
851 	if (!old_pwd || !old_group) {
852 		torture_comment(tctx, "ENV NSS_WRAPPER_PASSWD or NSS_WRAPPER_GROUP not set\n");
853 		torture_skip(tctx, "nothing to test\n");
854 	}
855 
856 	torture_assert(tctx, test_passwd(tctx),
857 			"failed to test users");
858 	torture_assert(tctx, test_group(tctx),
859 			"failed to test groups");
860 
861 	return true;
862 }
863 
test_reentrant_enumeration(struct torture_context * tctx)864 static bool test_reentrant_enumeration(struct torture_context *tctx)
865 {
866 	const char *old_pwd = getenv("NSS_WRAPPER_PASSWD");
867 	const char *old_group = getenv("NSS_WRAPPER_GROUP");
868 
869 	if (!old_pwd || !old_group) {
870 		torture_comment(tctx, "ENV NSS_WRAPPER_PASSWD or NSS_WRAPPER_GROUP not set\n");
871 		torture_skip(tctx, "nothing to test\n");
872 	}
873 
874 	torture_comment(tctx, "Testing re-entrant calls\n");
875 
876 	torture_assert(tctx, test_passwd_r(tctx),
877 			"failed to test users");
878 	torture_assert(tctx, test_group_r(tctx),
879 			"failed to test groups");
880 
881 	return true;
882 }
883 
test_reentrant_enumeration_crosschecks(struct torture_context * tctx)884 static bool test_reentrant_enumeration_crosschecks(struct torture_context *tctx)
885 {
886 	const char *old_pwd = getenv("NSS_WRAPPER_PASSWD");
887 	const char *old_group = getenv("NSS_WRAPPER_GROUP");
888 
889 	if (!old_pwd || !old_group) {
890 		torture_comment(tctx, "ENV NSS_WRAPPER_PASSWD or NSS_WRAPPER_GROUP not set\n");
891 		torture_skip(tctx, "nothing to test\n");
892 	}
893 
894 	torture_comment(tctx, "Testing re-entrant calls with cross checks\n");
895 
896 	torture_assert(tctx, test_passwd_r_cross(tctx),
897 			"failed to test users");
898 	torture_assert(tctx, test_group_r_cross(tctx),
899 			"failed to test groups");
900 
901 	return true;
902 }
903 
test_passwd_duplicates(struct torture_context * tctx)904 static bool test_passwd_duplicates(struct torture_context *tctx)
905 {
906 	size_t i, d;
907 	struct passwd *pwd;
908 	size_t num_pwd;
909 	int duplicates = 0;
910 
911 	torture_assert(tctx, test_enum_passwd(tctx, &pwd, &num_pwd),
912 	    "failed to enumerate passwd");
913 
914 	for (i=0; i < num_pwd; i++) {
915 		const char *current_name = pwd[i].pw_name;
916 		for (d=0; d < num_pwd; d++) {
917 			const char *dup_name = pwd[d].pw_name;
918 			if (d == i) {
919 				continue;
920 			}
921 			if (!strequal(current_name, dup_name)) {
922 				continue;
923 			}
924 
925 			torture_warning(tctx, "found duplicate names:");
926 			print_passwd(&pwd[d]);
927 			print_passwd(&pwd[i]);
928 			duplicates++;
929 		}
930 	}
931 
932 	if (duplicates) {
933 		torture_fail(tctx, talloc_asprintf(tctx, "found %d duplicate names", duplicates));
934 	}
935 
936 	return true;
937 }
938 
test_group_duplicates(struct torture_context * tctx)939 static bool test_group_duplicates(struct torture_context *tctx)
940 {
941 	size_t i, d;
942 	struct group *grp;
943 	size_t num_grp;
944 	int duplicates = 0;
945 
946 	torture_assert(tctx, test_enum_group(tctx, &grp, &num_grp),
947 		"failed to enumerate group");
948 
949 	for (i=0; i < num_grp; i++) {
950 		const char *current_name = grp[i].gr_name;
951 		for (d=0; d < num_grp; d++) {
952 			const char *dup_name = grp[d].gr_name;
953 			if (d == i) {
954 				continue;
955 			}
956 			if (!strequal(current_name, dup_name)) {
957 				continue;
958 			}
959 
960 			torture_warning(tctx, "found duplicate names:");
961 			print_group(&grp[d]);
962 			print_group(&grp[i]);
963 			duplicates++;
964 		}
965 	}
966 
967 	if (duplicates) {
968 		torture_fail(tctx, talloc_asprintf(tctx, "found %d duplicate names", duplicates));
969 	}
970 
971 	return true;
972 }
973 
974 
test_duplicates(struct torture_context * tctx)975 static bool test_duplicates(struct torture_context *tctx)
976 {
977 	const char *old_pwd = getenv("NSS_WRAPPER_PASSWD");
978 	const char *old_group = getenv("NSS_WRAPPER_GROUP");
979 
980 	if (!old_pwd || !old_group) {
981 		torture_comment(tctx, "ENV NSS_WRAPPER_PASSWD or NSS_WRAPPER_GROUP not set\n");
982 		torture_skip(tctx, "nothing to test\n");
983 	}
984 
985 	torture_assert(tctx, test_passwd_duplicates(tctx),
986 			"failed to test users");
987 	torture_assert(tctx, test_group_duplicates(tctx),
988 			"failed to test groups");
989 
990 	return true;
991 }
992 
993 
torture_local_nss(TALLOC_CTX * mem_ctx)994 struct torture_suite *torture_local_nss(TALLOC_CTX *mem_ctx)
995 {
996 	struct torture_suite *suite = torture_suite_create(mem_ctx, "nss");
997 
998 	torture_suite_add_simple_test(suite, "enumeration", test_enumeration);
999 	torture_suite_add_simple_test(suite, "reentrant enumeration", test_reentrant_enumeration);
1000 	torture_suite_add_simple_test(suite, "reentrant enumeration crosschecks", test_reentrant_enumeration_crosschecks);
1001 	torture_suite_add_simple_test(suite, "membership", test_membership);
1002 	torture_suite_add_simple_test(suite, "duplicates", test_duplicates);
1003 
1004 	return suite;
1005 }
1006