1 | /* Copyright (C) 1997-2017 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 | <http://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 | } |
376 | |