Extend NSS test suite
[platform/upstream/glibc.git] / nss / nss_test1.c
1 /* Template generic NSS service provider.  See nss_test.h for usage.
2    Copyright (C) 2017 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    <http://www.gnu.org/licenses/>.  */
18
19 #include <errno.h>
20 #include <nss.h>
21 #include <pthread.h>
22 #include <string.h>
23 #include <stdio.h>
24 #include <alloc_buffer.h>
25
26
27 /* We need to be able to handle NULLs "properly" within the testsuite,
28    to test known bad data.  */
29 #define alloc_buffer_maybe_copy_string(b,s) s ? alloc_buffer_copy_string (b, s) : NULL;
30
31 /* This file is the master template.  Other instances of this test
32    module should define NAME(x) to have their name instead of "test1",
33    then include this file.
34 */
35 #define NAME_(x,n) _nss_##n##_##x
36 #ifndef NAME
37 #define NAME(x) NAME_(x,test1)
38 #endif
39 #define NAMESTR__(x) #x
40 #define NAMESTR_(x) NAMESTR__(x)
41 #define NAMESTR(x) NAMESTR_(NAME(x))
42
43 #include "nss_test.h"
44
45 /* -------------------------------------------------- */
46 /* Default Data.  */
47
48 static struct passwd default_pwd_data[] =
49   {
50 #define PWD(u) \
51     { .pw_name = (char *) "name" #u, .pw_passwd = (char *) "*", .pw_uid = u,  \
52       .pw_gid = 100, .pw_gecos = (char *) "*", .pw_dir = (char *) "*",        \
53       .pw_shell = (char *) "*" }
54     PWD (30),
55     PWD (100),
56     PWD (200),
57     PWD (60),
58     PWD (20000)
59   };
60 #define default_npwd_data (sizeof (pwd_data) / sizeof (pwd_data[0]))
61
62 static struct passwd *pwd_data = default_pwd_data;
63 static int npwd_data = default_npwd_data;
64
65 static struct group *grp_data = NULL;
66 static int ngrp_data = 0;
67
68 /* This function will get called, and once per session, look back into
69    the test case's executable for an init hook function, and call
70    it.  */
71
72 static int initted = 0;
73 static void
74 init(void)
75 {
76   test_tables t;
77   int i;
78
79   if (initted)
80     return;
81   if (NAME(init_hook))
82     {
83       memset (&t, 0, sizeof(t));
84       NAME(init_hook)(&t);
85
86       if (t.pwd_table)
87         {
88           pwd_data = t.pwd_table;
89           for (i=0; ! PWD_ISLAST(& pwd_data[i]); i++)
90             ;
91           npwd_data = i;
92         }
93
94       if (t.grp_table)
95         {
96           grp_data = t.grp_table;
97           for (i=0; ! GRP_ISLAST(& grp_data[i]); i++)
98             ;
99           ngrp_data = i;
100         }
101     }
102   initted = 1;
103 }
104
105 /* -------------------------------------------------- */
106 /* Password handling.  */
107
108 static size_t pwd_iter;
109 #define CURPWD pwd_data[pwd_iter]
110
111 static pthread_mutex_t pwd_lock = PTHREAD_MUTEX_INITIALIZER;
112
113 enum nss_status
114 NAME(setpwent) (int stayopen)
115 {
116   init();
117   pwd_iter = 0;
118   return NSS_STATUS_SUCCESS;
119 }
120
121
122 enum nss_status
123 NAME(endpwent) (void)
124 {
125   init();
126   return NSS_STATUS_SUCCESS;
127 }
128
129 static enum nss_status
130 copy_passwd (struct passwd *result, struct passwd *local,
131             char *buffer, size_t buflen, int *errnop)
132 {
133   struct alloc_buffer buf = alloc_buffer_create (buffer, buflen);
134
135   result->pw_name = alloc_buffer_maybe_copy_string (&buf, local->pw_name);
136   result->pw_passwd = alloc_buffer_maybe_copy_string (&buf, local->pw_passwd);
137   result->pw_uid = local->pw_uid;
138   result->pw_gid = local->pw_gid;
139   result->pw_gecos = alloc_buffer_maybe_copy_string (&buf, local->pw_gecos);
140   result->pw_dir = alloc_buffer_maybe_copy_string (&buf, local->pw_dir);
141   result->pw_shell = alloc_buffer_maybe_copy_string (&buf, local->pw_shell);
142
143   if (alloc_buffer_has_failed (&buf))
144     {
145       *errnop = ERANGE;
146       return NSS_STATUS_TRYAGAIN;
147     }
148
149   return NSS_STATUS_SUCCESS;
150 }
151
152 enum nss_status
153 NAME(getpwent_r) (struct passwd *result, char *buffer, size_t buflen,
154                        int *errnop)
155 {
156   int res = NSS_STATUS_SUCCESS;
157
158   init();
159   pthread_mutex_lock (&pwd_lock);
160
161   if (pwd_iter >= npwd_data)
162     res = NSS_STATUS_NOTFOUND;
163   else
164     {
165       res = copy_passwd (result, &CURPWD, buffer, buflen, errnop);
166       ++pwd_iter;
167     }
168
169   pthread_mutex_unlock (&pwd_lock);
170
171   return res;
172 }
173
174
175 enum nss_status
176 NAME(getpwuid_r) (uid_t uid, struct passwd *result, char *buffer,
177                        size_t buflen, int *errnop)
178 {
179   init();
180   for (size_t idx = 0; idx < npwd_data; ++idx)
181     if (pwd_data[idx].pw_uid == uid)
182       return copy_passwd (result, &pwd_data[idx], buffer, buflen, errnop);
183
184   return NSS_STATUS_NOTFOUND;
185 }
186
187
188 enum nss_status
189 NAME(getpwnam_r) (const char *name, struct passwd *result, char *buffer,
190                        size_t buflen, int *errnop)
191 {
192   init();
193   for (size_t idx = 0; idx < npwd_data; ++idx)
194     if (strcmp (pwd_data[idx].pw_name, name) == 0)
195       return copy_passwd (result, &pwd_data[idx], buffer, buflen, errnop);
196
197   return NSS_STATUS_NOTFOUND;
198 }
199
200 /* -------------------------------------------------- */
201 /* Group handling.  */
202
203 static size_t grp_iter;
204 #define CURGRP grp_data[grp_iter]
205
206 static pthread_mutex_t grp_lock = PTHREAD_MUTEX_INITIALIZER;
207
208 enum nss_status
209 NAME(setgrent) (int stayopen)
210 {
211   init();
212   grp_iter = 0;
213   return NSS_STATUS_SUCCESS;
214 }
215
216
217 enum nss_status
218 NAME(endgrent) (void)
219 {
220   init();
221   return NSS_STATUS_SUCCESS;
222 }
223
224 static enum nss_status
225 copy_group (struct group *result, struct group *local,
226             char *buffer, size_t buflen, int *errnop)
227 {
228   struct alloc_buffer buf = alloc_buffer_create (buffer, buflen);
229   char **memlist;
230   int i;
231
232   if (local->gr_mem)
233     {
234       i = 0;
235       while (local->gr_mem[i])
236         ++i;
237
238       memlist = alloc_buffer_alloc_array (&buf, char *, i + 1);
239
240       if (memlist) {
241         for (i = 0; local->gr_mem[i]; ++i)
242           memlist[i] = alloc_buffer_maybe_copy_string (&buf, local->gr_mem[i]);
243         memlist[i] = NULL;
244       }
245
246       result->gr_mem = memlist;
247     }
248   else
249     result->gr_mem = NULL;
250
251   result->gr_name = alloc_buffer_maybe_copy_string (&buf, local->gr_name);
252   result->gr_passwd = alloc_buffer_maybe_copy_string (&buf, local->gr_passwd);
253   result->gr_gid = local->gr_gid;
254
255   if (alloc_buffer_has_failed (&buf))
256     {
257       *errnop = ERANGE;
258       return NSS_STATUS_TRYAGAIN;
259     }
260
261   return NSS_STATUS_SUCCESS;
262 }
263
264
265 enum nss_status
266 NAME(getgrent_r) (struct group *result, char *buffer, size_t buflen,
267                        int *errnop)
268 {
269   int res = NSS_STATUS_SUCCESS;
270
271   init();
272   pthread_mutex_lock (&grp_lock);
273
274   if (grp_iter >= ngrp_data)
275     res = NSS_STATUS_NOTFOUND;
276   else
277     {
278       res = copy_group (result, &CURGRP, buffer, buflen, errnop);
279       ++grp_iter;
280     }
281
282   pthread_mutex_unlock (&pwd_lock);
283
284   return res;
285 }
286
287
288 enum nss_status
289 NAME(getgrgid_r) (gid_t gid, struct group *result, char *buffer,
290                   size_t buflen, int *errnop)
291 {
292   init();
293   for (size_t idx = 0; idx < ngrp_data; ++idx)
294     if (grp_data[idx].gr_gid == gid)
295       return copy_group (result, &grp_data[idx], buffer, buflen, errnop);
296
297   return NSS_STATUS_NOTFOUND;
298 }
299
300
301 enum nss_status
302 NAME(getgrnam_r) (const char *name, struct group *result, char *buffer,
303                        size_t buflen, int *errnop)
304 {
305   init();
306   for (size_t idx = 0; idx < ngrp_data; ++idx)
307     if (strcmp (pwd_data[idx].pw_name, name) == 0)
308       {
309         return copy_group (result, &grp_data[idx], buffer, buflen, errnop);
310       }
311
312   return NSS_STATUS_NOTFOUND;
313 }