175b9cbf4274693512b4a361af752004053a1941
[platform/upstream/glibc.git] / nis / nss_nisplus / nisplus-parser.c
1 /* Copyright (C) 1997-2020 Free Software Foundation, Inc.
2    This file is part of the GNU C Library.
3    Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1997.
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 <pwd.h>
20 #include <ctype.h>
21 #include <errno.h>
22 #include <string.h>
23 #include <rpcsvc/nis.h>
24
25 #include "nisplus-parser.h"
26
27 #define NISENTRYVAL(idx, col, res) \
28         (NIS_RES_OBJECT (res)[idx].EN_data.en_cols.en_cols_val[col].ec_value.ec_value_val)
29
30 #define NISENTRYLEN(idx, col, res) \
31         (NIS_RES_OBJECT (res)[idx].EN_data.en_cols.en_cols_val[col].ec_value.ec_value_len)
32
33 #define NISOBJVAL(col, obj) \
34   ((obj)->EN_data.en_cols.en_cols_val[col].ec_value.ec_value_val)
35
36 #define NISOBJLEN(col, obj) \
37   ((obj)->EN_data.en_cols.en_cols_val[col].ec_value.ec_value_len)
38
39
40 int
41 _nss_nisplus_parse_pwent (nis_result *result, struct passwd *pw,
42                           char *buffer, size_t buflen, int *errnop)
43 {
44   if ((result->status != NIS_SUCCESS && result->status != NIS_S_SUCCESS)
45       || NIS_RES_NUMOBJ (result) != 1
46       || __type_of (NIS_RES_OBJECT (result)) != NIS_ENTRY_OBJ
47       || strcmp (NIS_RES_OBJECT (result)->EN_data.en_type, "passwd_tbl") != 0
48       || NIS_RES_OBJECT (result)->EN_data.en_cols.en_cols_len < 7)
49     return 0;
50
51   nis_object *obj = NIS_RES_OBJECT (result);
52   char *first_unused = buffer;
53   size_t room_left = buflen;
54   size_t len;
55
56   if (NISOBJLEN (0, obj) >= room_left)
57     {
58       /* The line is too long for our buffer.  */
59     no_more_room:
60       *errnop = ERANGE;
61       return -1;
62     }
63
64   strncpy (first_unused, NISOBJVAL (0, obj), NISOBJLEN (0, obj));
65   first_unused[NISOBJLEN (0, obj)] = '\0';
66   len = strlen (first_unused);
67   if (len == 0) /* No name ? Should never happen, database is corrupt */
68     return 0;
69   pw->pw_name = first_unused;
70   room_left -= len + 1;
71   first_unused += len + 1;
72
73   if (NISOBJLEN (1, obj) >= room_left)
74     goto no_more_room;
75
76   strncpy (first_unused, NISOBJVAL (1, obj), NISOBJLEN (1, obj));
77   first_unused[NISOBJLEN (1, obj)] = '\0';
78   pw->pw_passwd = first_unused;
79   len = strlen (first_unused);
80   room_left -= len + 1;
81   first_unused += len + 1;
82
83   char *numstr = NISOBJVAL (2, obj);
84   len = NISOBJLEN (2, obj);
85   if (len == 0 || numstr[len - 1] != '\0')
86     {
87       if (len >= room_left)
88         goto no_more_room;
89
90       strncpy (first_unused, numstr, len);
91       first_unused[len] = '\0';
92       numstr = first_unused;
93     }
94   if (numstr[0] == '\0')
95     /* If we don't have a uid, it's an invalid shadow entry.  */
96     return 0;
97   pw->pw_uid = strtoul (numstr, NULL, 10);
98
99   numstr = NISOBJVAL (3, obj);
100   len = NISOBJLEN (3, obj);
101   if (len == 0 || numstr[len - 1] != '\0')
102     {
103       if (len >= room_left)
104         goto no_more_room;
105
106       strncpy (first_unused, numstr, len);
107       first_unused[len] = '\0';
108       numstr = first_unused;
109     }
110   if (numstr[0] == '\0')
111     /* If we don't have a gid, it's an invalid shadow entry.  */
112     return 0;
113   pw->pw_gid = strtoul (numstr, NULL, 10);
114
115   if (NISOBJLEN(4, obj) >= room_left)
116     goto no_more_room;
117
118   strncpy (first_unused, NISOBJVAL (4, obj), NISOBJLEN (4, obj));
119   first_unused[NISOBJLEN (4, obj)] = '\0';
120   pw->pw_gecos = first_unused;
121   len = strlen (first_unused);
122   room_left -= len + 1;
123   first_unused += len + 1;
124
125   if (NISOBJLEN (5, obj) >= room_left)
126     goto no_more_room;
127
128   strncpy (first_unused, NISOBJVAL (5, obj), NISOBJLEN (5, obj));
129   first_unused[NISOBJLEN (5, obj)] = '\0';
130   pw->pw_dir = first_unused;
131   len = strlen (first_unused);
132   room_left -= len + 1;
133   first_unused += len + 1;
134
135   if (NISOBJLEN (6, obj) >= room_left)
136     goto no_more_room;
137
138   strncpy (first_unused, NISOBJVAL (6, obj), NISOBJLEN (6, obj));
139   first_unused[NISOBJLEN (6, obj)] = '\0';
140   pw->pw_shell = first_unused;
141   len = strlen (first_unused);
142   room_left -= len + 1;
143   first_unused += len + 1;
144
145   return 1;
146 }
147
148
149 int
150 _nss_nisplus_parse_grent (nis_result *result, struct group *gr,
151                           char *buffer, size_t buflen, int *errnop)
152 {
153   if ((result->status != NIS_SUCCESS && result->status != NIS_S_SUCCESS)
154       || __type_of(NIS_RES_OBJECT (result)) != NIS_ENTRY_OBJ
155       || strcmp (NIS_RES_OBJECT (result)[0].EN_data.en_type, "group_tbl") != 0
156       || NIS_RES_OBJECT (result)[0].EN_data.en_cols.en_cols_len < 4)
157     return 0;
158
159   nis_object *obj = NIS_RES_OBJECT (result);
160   char *first_unused = buffer;
161   size_t room_left = buflen;
162   char *line;
163   int count;
164   size_t len;
165
166   if (NISOBJLEN (0, obj) >= room_left)
167     {
168       /* The line is too long for our buffer.  */
169     no_more_room:
170       *errnop = ERANGE;
171       return -1;
172     }
173
174   strncpy (first_unused, NISOBJVAL (0, obj), NISOBJLEN (0, obj));
175   first_unused[NISOBJLEN (0, obj)] = '\0';
176   len = strlen (first_unused);
177   if (len == 0) /* group table is corrupt */
178     return 0;
179   gr->gr_name = first_unused;
180   room_left -= len + 1;
181   first_unused += len + 1;
182
183   if (NISOBJLEN (1, obj) >= room_left)
184     goto no_more_room;
185
186   strncpy (first_unused, NISOBJVAL (1, obj), NISOBJLEN (1, obj));
187   first_unused[NISOBJLEN (1, obj)] = '\0';
188   gr->gr_passwd = first_unused;
189   len = strlen (first_unused);
190   room_left -= len + 1;
191   first_unused += len + 1;
192
193   char *numstr = NISOBJVAL (2, obj);
194   len = NISOBJLEN (2, obj);
195   if (len == 0 || numstr[len - 1] != '\0')
196     {
197       if (len >= room_left)
198         goto no_more_room;
199
200       strncpy (first_unused, numstr, len);
201       first_unused[len] = '\0';
202       numstr = first_unused;
203     }
204   if (numstr[0] == '\0')
205     /* We should always have a gid.  */
206     return 0;
207   gr->gr_gid = strtoul (numstr, NULL, 10);
208
209   if (NISOBJLEN (3, obj) >= room_left)
210     goto no_more_room;
211
212   strncpy (first_unused, NISOBJVAL (3, obj), NISOBJLEN (3, obj));
213   first_unused[NISOBJLEN (3, obj)] = '\0';
214   line = first_unused;
215   len = strlen (line);
216   room_left -= len + 1;
217   first_unused += len + 1;
218   /* Adjust the pointer so it is aligned for
219      storing pointers.  */
220   size_t adjust = ((__alignof__ (char *)
221                     - (first_unused - (char *) 0) % __alignof__ (char *))
222                    % __alignof__ (char *));
223   if (room_left < adjust)
224     goto no_more_room;
225   first_unused += adjust;
226   room_left -= adjust;
227   gr->gr_mem = (char **) first_unused;
228
229   count = 0;
230   while (*line != '\0')
231     {
232       /* Skip leading blanks.  */
233       while (isspace (*line))
234         ++line;
235
236       if (*line == '\0')
237         break;
238
239       if (room_left < sizeof (char *))
240         goto no_more_room;
241       room_left -= sizeof (char *);
242       gr->gr_mem[count++] = line;
243
244       while (*line != '\0' && *line != ',' && !isspace (*line))
245         ++line;
246
247       if (*line == ',' || isspace (*line))
248         {
249           int is = isspace (*line);
250
251           *line++ = '\0';
252           if (is)
253             while (*line != '\0' && (*line == ',' || isspace (*line)))
254               ++line;
255         }
256     }
257   if (room_left < sizeof (char *))
258     goto no_more_room;
259   room_left -= sizeof (char *);
260   gr->gr_mem[count] = NULL;
261
262   return 1;
263 }
264
265
266 int
267 _nss_nisplus_parse_spent (nis_result *result, struct spwd *sp,
268                           char *buffer, size_t buflen, int *errnop)
269 {
270   char *first_unused = buffer;
271   size_t room_left = buflen;
272   size_t len;
273
274   if (result == NULL)
275     return 0;
276
277   if ((result->status != NIS_SUCCESS && result->status != NIS_S_SUCCESS)
278       || NIS_RES_NUMOBJ (result) != 1
279       || __type_of(NIS_RES_OBJECT (result)) != NIS_ENTRY_OBJ
280       || strcmp (NIS_RES_OBJECT (result)->EN_data.en_type, "passwd_tbl") != 0
281       || NIS_RES_OBJECT (result)->EN_data.en_cols.en_cols_len < 8)
282     return 0;
283
284   if (NISENTRYLEN (0, 0, result) >= room_left)
285     {
286       /* The line is too long for our buffer.  */
287     no_more_room:
288       *errnop = ERANGE;
289       return -1;
290     }
291
292   strncpy (first_unused, NISENTRYVAL (0, 0, result),
293            NISENTRYLEN (0, 0, result));
294   first_unused[NISENTRYLEN (0, 0, result)] = '\0';
295   len = strlen (first_unused);
296   if (len == 0)
297     return 0;
298   sp->sp_namp = first_unused;
299   room_left -= len + 1;
300   first_unused += len + 1;
301
302   if (NISENTRYLEN (0, 1, result) >= room_left)
303     goto no_more_room;
304
305   strncpy (first_unused, NISENTRYVAL (0, 1, result),
306            NISENTRYLEN (0, 1, result));
307   first_unused[NISENTRYLEN (0, 1, result)] = '\0';
308   sp->sp_pwdp = first_unused;
309   len = strlen (first_unused);
310   room_left -= len + 1;
311   first_unused += len + 1;
312
313   sp->sp_lstchg = sp->sp_min = sp->sp_max = sp->sp_warn = sp->sp_inact =
314     sp->sp_expire = -1;
315   sp->sp_flag = ~0ul;
316
317   if (NISENTRYLEN (0, 7, result) > 0)
318     {
319       char *line = NISENTRYVAL (0, 7, result);
320       char *cp = strchr (line, ':');
321       if (cp == NULL)
322         return 1;
323       *cp++ = '\0';
324       if (*line)
325         sp->sp_lstchg = atol (line);
326
327       line = cp;
328       cp = strchr (line, ':');
329       if (cp == NULL)
330         return 1;
331       *cp++ = '\0';
332       if (*line)
333         sp->sp_min = atol (line);
334
335       line = cp;
336       cp = strchr (line, ':');
337       if (cp == NULL)
338         return 1;
339       *cp++ = '\0';
340       if (*line)
341         sp->sp_max = atol (line);
342
343       line = cp;
344       cp = strchr (line, ':');
345       if (cp == NULL)
346         return 1;
347       *cp++ = '\0';
348       if (*line)
349         sp->sp_warn = atol (line);
350
351       line = cp;
352       cp = strchr (line, ':');
353       if (cp == NULL)
354         return 1;
355       *cp++ = '\0';
356       if (*line)
357         sp->sp_inact = atol (line);
358
359       line = cp;
360       cp = strchr (line, ':');
361       if (cp == NULL)
362         return 1;
363       *cp++ = '\0';
364       if (*line)
365         sp->sp_expire = atol (line);
366
367       line = cp;
368       if (line == NULL)
369         return 1;
370       if (*line)
371         sp->sp_flag = atol (line);
372     }
373
374   return 1;
375 }