]>
Commit | Line | Data |
---|---|---|
d4697bc9 | 1 | /* Copyright (C) 1997-2014 Free Software Foundation, Inc. |
e61abf83 UD |
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 | |
41bdb6e2 AJ |
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. | |
e61abf83 UD |
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 | |
41bdb6e2 | 13 | Lesser General Public License for more details. |
e61abf83 | 14 | |
41bdb6e2 | 15 | You should have received a copy of the GNU Lesser General Public |
59ba27a6 PE |
16 | License along with the GNU C Library; if not, see |
17 | <http://www.gnu.org/licenses/>. */ | |
e61abf83 | 18 | |
636e689e | 19 | #include <atomic.h> |
a334319f | 20 | #include <ctype.h> |
636e689e UD |
21 | #include <errno.h> |
22 | #include <nss.h> | |
e61abf83 | 23 | #include <string.h> |
e61abf83 UD |
24 | #include <rpc/netdb.h> |
25 | #include <rpcsvc/nis.h> | |
636e689e | 26 | #include <bits/libc-lock.h> |
e61abf83 UD |
27 | |
28 | #include "nss-nisplus.h" | |
29 | ||
30 | __libc_lock_define_initialized (static, lock) | |
31 | ||
fc9f33e3 UD |
32 | static nis_result *result; |
33 | static nis_name tablename_val; | |
34 | static u_long tablename_len; | |
e61abf83 | 35 | |
0944b9e1 UD |
36 | #define NISENTRYVAL(idx, col, res) \ |
37 | (NIS_RES_OBJECT (res)[idx].EN_data.en_cols.en_cols_val[col].ec_value.ec_value_val) | |
38 | ||
39 | #define NISENTRYLEN(idx, col, res) \ | |
40 | (NIS_RES_OBJECT (res)[idx].EN_data.en_cols.en_cols_val[col].ec_value.ec_value_len) | |
e61abf83 | 41 | |
e61abf83 UD |
42 | |
43 | static int | |
44 | _nss_nisplus_parse_rpcent (nis_result *result, struct rpcent *rpc, | |
d71b808a | 45 | char *buffer, size_t buflen, int *errnop) |
e61abf83 | 46 | { |
2d7da676 | 47 | char *first_unused = buffer; |
e61abf83 | 48 | size_t room_left = buflen; |
7799b7b3 | 49 | unsigned int i; |
0944b9e1 | 50 | char *line; |
2d7da676 | 51 | |
e61abf83 UD |
52 | |
53 | if (result == NULL) | |
26dee9c4 | 54 | return 0; |
e61abf83 | 55 | |
d71b808a | 56 | if ((result->status != NIS_SUCCESS && result->status != NIS_S_SUCCESS) |
0944b9e1 UD |
57 | || __type_of (NIS_RES_OBJECT (result)) != NIS_ENTRY_OBJ |
58 | || strcmp (NIS_RES_OBJECT (result)[0].EN_data.en_type, "rpc_tbl") != 0 | |
59 | || NIS_RES_OBJECT (result)[0].EN_data.en_cols.en_cols_len < 3) | |
26dee9c4 | 60 | return 0; |
e61abf83 | 61 | |
2d7da676 | 62 | if (NISENTRYLEN (0, 0, result) >= room_left) |
e61abf83 | 63 | { |
2d7da676 | 64 | no_more_room: |
d71b808a | 65 | *errnop = ERANGE; |
60c96635 | 66 | return -1; |
e61abf83 | 67 | } |
2d7da676 UD |
68 | strncpy (first_unused, NISENTRYVAL (0, 0, result), |
69 | NISENTRYLEN (0, 0, result)); | |
70 | first_unused[NISENTRYLEN (0, 0, result)] = '\0'; | |
71 | rpc->r_name = first_unused; | |
0944b9e1 UD |
72 | size_t len = strlen (first_unused) + 1; |
73 | room_left -= len; | |
74 | first_unused += len; | |
75 | ||
2d7da676 | 76 | rpc->r_number = atoi (NISENTRYVAL (0, 2, result)); |
2d7da676 | 77 | |
0944b9e1 UD |
78 | /* XXX Rewrite at some point to allocate the array first and then |
79 | copy the strings. It wasteful to first concatenate the strings | |
80 | to just split them again later. */ | |
81 | line = first_unused; | |
82 | for (i = 0; i < NIS_RES_NUMOBJ (result); ++i) | |
e61abf83 | 83 | { |
2d7da676 UD |
84 | if (strcmp (NISENTRYVAL (i, 1, result), rpc->r_name) != 0) |
85 | { | |
86 | if (NISENTRYLEN (i, 1, result) + 2 > room_left) | |
87 | goto no_more_room; | |
0944b9e1 UD |
88 | *first_unused++ = ' '; |
89 | first_unused = __stpncpy (first_unused, NISENTRYVAL (i, 1, result), | |
90 | NISENTRYLEN (i, 1, result)); | |
91 | room_left -= NISENTRYLEN (i, 1, result) + 1; | |
2d7da676 | 92 | } |
e61abf83 | 93 | } |
0944b9e1 | 94 | *first_unused++ = '\0'; |
2d7da676 UD |
95 | |
96 | /* Adjust the pointer so it is aligned for | |
97 | storing pointers. */ | |
0944b9e1 UD |
98 | size_t adjust = ((__alignof__ (char *) |
99 | - (first_unused - (char *) 0) % __alignof__ (char *)) | |
100 | % __alignof__ (char *)); | |
101 | if (room_left < adjust + sizeof (char *)) | |
a334319f | 102 | goto no_more_room; |
0944b9e1 UD |
103 | first_unused += adjust; |
104 | room_left -= adjust; | |
105 | rpc->r_aliases = (char **) first_unused; | |
106 | ||
107 | /* For the terminating NULL pointer. */ | |
d71b808a | 108 | room_left -= sizeof (char *); |
2d7da676 UD |
109 | |
110 | i = 0; | |
111 | while (*line != '\0') | |
e61abf83 | 112 | { |
2d7da676 UD |
113 | /* Skip leading blanks. */ |
114 | while (isspace (*line)) | |
880f421f | 115 | ++line; |
2d7da676 UD |
116 | |
117 | if (*line == '\0') | |
118 | break; | |
119 | ||
120 | if (room_left < sizeof (char *)) | |
121 | goto no_more_room; | |
122 | ||
123 | room_left -= sizeof (char *); | |
0944b9e1 | 124 | rpc->r_aliases[i++] = line; |
2d7da676 UD |
125 | |
126 | while (*line != '\0' && *line != ' ') | |
127 | ++line; | |
128 | ||
880f421f | 129 | if (*line == ' ') |
0944b9e1 | 130 | *line++ = '\0'; |
e61abf83 | 131 | } |
0944b9e1 | 132 | rpc->r_aliases[i] = NULL; |
e61abf83 | 133 | |
2d7da676 | 134 | return 1; |
e61abf83 UD |
135 | } |
136 | ||
0944b9e1 | 137 | |
2d7da676 | 138 | static enum nss_status |
d71b808a | 139 | _nss_create_tablename (int *errnop) |
2d7da676 UD |
140 | { |
141 | if (tablename_val == NULL) | |
142 | { | |
636e689e UD |
143 | const char *local_dir = nis_local_directory (); |
144 | size_t local_dir_len = strlen (local_dir); | |
145 | static const char prefix[] = "rpc.org_dir."; | |
2d7da676 | 146 | |
636e689e | 147 | char *p = malloc (sizeof (prefix) + local_dir_len); |
c8e82b4a | 148 | if (p == NULL) |
d71b808a UD |
149 | { |
150 | *errnop = errno; | |
151 | return NSS_STATUS_TRYAGAIN; | |
152 | } | |
636e689e UD |
153 | |
154 | memcpy (__stpcpy (p, prefix), local_dir, local_dir_len + 1); | |
155 | ||
156 | tablename_len = sizeof (prefix) - 1 + local_dir_len; | |
157 | ||
158 | atomic_write_barrier (); | |
159 | ||
160 | tablename_val = p; | |
2d7da676 | 161 | } |
636e689e | 162 | |
2d7da676 UD |
163 | return NSS_STATUS_SUCCESS; |
164 | } | |
165 | ||
166 | ||
e61abf83 | 167 | enum nss_status |
7d2d622a | 168 | _nss_nisplus_setrpcent (int stayopen) |
e61abf83 | 169 | { |
2d7da676 UD |
170 | enum nss_status status = NSS_STATUS_SUCCESS; |
171 | ||
e61abf83 UD |
172 | __libc_lock_lock (lock); |
173 | ||
636e689e UD |
174 | if (result != NULL) |
175 | { | |
176 | nis_freeresult (result); | |
177 | result = NULL; | |
178 | } | |
2d7da676 UD |
179 | |
180 | if (tablename_val == NULL) | |
636e689e UD |
181 | { |
182 | int err; | |
183 | status = _nss_create_tablename (&err); | |
184 | } | |
e61abf83 UD |
185 | |
186 | __libc_lock_unlock (lock); | |
187 | ||
2d7da676 | 188 | return status; |
e61abf83 UD |
189 | } |
190 | ||
191 | enum nss_status | |
192 | _nss_nisplus_endrpcent (void) | |
193 | { | |
194 | __libc_lock_lock (lock); | |
195 | ||
636e689e UD |
196 | if (result != NULL) |
197 | { | |
198 | nis_freeresult (result); | |
199 | result = NULL; | |
200 | } | |
e61abf83 UD |
201 | |
202 | __libc_lock_unlock (lock); | |
203 | ||
204 | return NSS_STATUS_SUCCESS; | |
205 | } | |
206 | ||
207 | static enum nss_status | |
208 | internal_nisplus_getrpcent_r (struct rpcent *rpc, char *buffer, | |
d71b808a | 209 | size_t buflen, int *errnop) |
e61abf83 UD |
210 | { |
211 | int parse_res; | |
212 | ||
213 | /* Get the next entry until we found a correct one. */ | |
214 | do | |
215 | { | |
60c96635 UD |
216 | nis_result *saved_res; |
217 | ||
e61abf83 UD |
218 | if (result == NULL) |
219 | { | |
60c96635 | 220 | saved_res = NULL; |
2d7da676 | 221 | if (tablename_val == NULL) |
d71b808a UD |
222 | { |
223 | enum nss_status status = _nss_create_tablename (errnop); | |
224 | ||
225 | if (status != NSS_STATUS_SUCCESS) | |
226 | return status; | |
227 | } | |
e61abf83 | 228 | |
d71b808a | 229 | result = nis_first_entry (tablename_val); |
487609e3 UD |
230 | if (result == NULL) |
231 | { | |
232 | *errnop = errno; | |
233 | return NSS_STATUS_TRYAGAIN; | |
234 | } | |
e61abf83 UD |
235 | if (niserr2nss (result->status) != NSS_STATUS_SUCCESS) |
236 | return niserr2nss (result->status); | |
237 | } | |
238 | else | |
239 | { | |
60c96635 | 240 | saved_res = result; |
636e689e | 241 | result = nis_next_entry (tablename_val, &result->cookie); |
487609e3 UD |
242 | if (result == NULL) |
243 | { | |
244 | *errnop = errno; | |
245 | return NSS_STATUS_TRYAGAIN; | |
246 | } | |
e61abf83 | 247 | if (niserr2nss (result->status) != NSS_STATUS_SUCCESS) |
60c96635 UD |
248 | { |
249 | nis_freeresult (saved_res); | |
250 | return niserr2nss (result->status); | |
251 | } | |
e61abf83 UD |
252 | } |
253 | ||
d71b808a UD |
254 | parse_res = _nss_nisplus_parse_rpcent (result, rpc, buffer, |
255 | buflen, errnop); | |
256 | if (parse_res == -1) | |
60c96635 UD |
257 | { |
258 | nis_freeresult (result); | |
259 | result = saved_res; | |
d71b808a | 260 | *errnop = ERANGE; |
60c96635 UD |
261 | return NSS_STATUS_TRYAGAIN; |
262 | } | |
263 | else | |
264 | { | |
265 | if (saved_res) | |
266 | nis_freeresult (saved_res); | |
267 | } | |
636e689e UD |
268 | } |
269 | while (!parse_res); | |
e61abf83 UD |
270 | |
271 | return NSS_STATUS_SUCCESS; | |
272 | } | |
273 | ||
274 | enum nss_status | |
275 | _nss_nisplus_getrpcent_r (struct rpcent *result, char *buffer, | |
d71b808a | 276 | size_t buflen, int *errnop) |
e61abf83 UD |
277 | { |
278 | int status; | |
279 | ||
280 | __libc_lock_lock (lock); | |
281 | ||
d71b808a | 282 | status = internal_nisplus_getrpcent_r (result, buffer, buflen, errnop); |
e61abf83 UD |
283 | |
284 | __libc_lock_unlock (lock); | |
285 | ||
286 | return status; | |
287 | } | |
288 | ||
289 | enum nss_status | |
290 | _nss_nisplus_getrpcbyname_r (const char *name, struct rpcent *rpc, | |
d71b808a | 291 | char *buffer, size_t buflen, int *errnop) |
e61abf83 UD |
292 | { |
293 | int parse_res; | |
294 | ||
2d7da676 | 295 | if (tablename_val == NULL) |
d71b808a | 296 | { |
636e689e UD |
297 | __libc_lock_lock (lock); |
298 | ||
d71b808a UD |
299 | enum nss_status status = _nss_create_tablename (errnop); |
300 | ||
636e689e UD |
301 | __libc_lock_unlock (lock); |
302 | ||
d71b808a UD |
303 | if (status != NSS_STATUS_SUCCESS) |
304 | return status; | |
305 | } | |
2d7da676 | 306 | |
e61abf83 UD |
307 | if (name == NULL) |
308 | return NSS_STATUS_NOTFOUND; | |
e61abf83 | 309 | |
636e689e UD |
310 | char buf[strlen (name) + 10 + tablename_len]; |
311 | int olderr = errno; | |
34816665 | 312 | |
636e689e UD |
313 | /* Search at first in the alias list, and use the correct name |
314 | for the next search */ | |
315 | snprintf (buf, sizeof (buf), "[name=%s],%s", name, tablename_val); | |
697d37b1 JJ |
316 | nis_result *result = nis_list (buf, FOLLOW_PATH | FOLLOW_LINKS | USE_DGRAM, |
317 | NULL, NULL); | |
e61abf83 | 318 | |
636e689e UD |
319 | if (result != NULL) |
320 | { | |
321 | char *bufptr = buf; | |
322 | ||
323 | /* If we did not find it, try it as original name. But if the | |
324 | database is correct, we should find it in the first case, too */ | |
325 | if ((result->status != NIS_SUCCESS | |
326 | && result->status != NIS_S_SUCCESS) | |
327 | || __type_of (result->objects.objects_val) != NIS_ENTRY_OBJ | |
328 | || strcmp (result->objects.objects_val->EN_data.en_type, | |
329 | "rpc_tbl") != 0 | |
330 | || result->objects.objects_val->EN_data.en_cols.en_cols_len < 3) | |
331 | snprintf (buf, sizeof (buf), "[cname=%s],%s", name, tablename_val); | |
332 | else | |
a334319f | 333 | { |
636e689e UD |
334 | /* We need to allocate a new buffer since there is no |
335 | guarantee the returned name has a length limit. */ | |
336 | const char *entryval = NISENTRYVAL (0, 0, result); | |
337 | size_t buflen = strlen (entryval) + 10 + tablename_len; | |
338 | bufptr = alloca (buflen); | |
339 | snprintf (bufptr, buflen, "[cname=%s],%s", | |
340 | entryval, tablename_val); | |
a334319f | 341 | } |
0ecb606c | 342 | |
636e689e | 343 | nis_freeresult (result); |
697d37b1 JJ |
344 | result = nis_list (bufptr, FOLLOW_PATH | FOLLOW_LINKS | USE_DGRAM, |
345 | NULL, NULL); | |
636e689e | 346 | } |
e61abf83 | 347 | |
636e689e UD |
348 | if (result == NULL) |
349 | { | |
350 | *errnop = ENOMEM; | |
351 | return NSS_STATUS_TRYAGAIN; | |
352 | } | |
e61abf83 | 353 | |
636e689e UD |
354 | if (__builtin_expect (niserr2nss (result->status) != NSS_STATUS_SUCCESS, 0)) |
355 | { | |
356 | enum nss_status status = niserr2nss (result->status); | |
357 | ||
358 | __set_errno (olderr); | |
34816665 | 359 | |
a334319f | 360 | nis_freeresult (result); |
636e689e UD |
361 | return status; |
362 | } | |
0ecb606c | 363 | |
636e689e UD |
364 | parse_res = _nss_nisplus_parse_rpcent (result, rpc, buffer, buflen, |
365 | errnop); | |
0ecb606c | 366 | |
636e689e UD |
367 | nis_freeresult (result); |
368 | ||
369 | if (parse_res < 1) | |
370 | { | |
371 | if (parse_res == -1) | |
372 | { | |
373 | *errnop = ERANGE; | |
374 | return NSS_STATUS_TRYAGAIN; | |
a334319f | 375 | } |
636e689e UD |
376 | |
377 | __set_errno (olderr); | |
378 | return NSS_STATUS_NOTFOUND; | |
e61abf83 | 379 | } |
636e689e UD |
380 | |
381 | return NSS_STATUS_SUCCESS; | |
e61abf83 UD |
382 | } |
383 | ||
384 | enum nss_status | |
385 | _nss_nisplus_getrpcbynumber_r (const int number, struct rpcent *rpc, | |
d71b808a | 386 | char *buffer, size_t buflen, int *errnop) |
e61abf83 | 387 | { |
2d7da676 | 388 | if (tablename_val == NULL) |
d71b808a | 389 | { |
636e689e UD |
390 | __libc_lock_lock (lock); |
391 | ||
d71b808a UD |
392 | enum nss_status status = _nss_create_tablename (errnop); |
393 | ||
636e689e UD |
394 | __libc_lock_unlock (lock); |
395 | ||
d71b808a UD |
396 | if (status != NSS_STATUS_SUCCESS) |
397 | return status; | |
398 | } | |
e61abf83 | 399 | |
636e689e UD |
400 | char buf[12 + 3 * sizeof (number) + tablename_len]; |
401 | int olderr = errno; | |
402 | ||
403 | snprintf (buf, sizeof (buf), "[number=%d],%s", number, tablename_val); | |
404 | ||
697d37b1 JJ |
405 | nis_result *result = nis_list (buf, FOLLOW_LINKS | FOLLOW_PATH | USE_DGRAM, |
406 | NULL, NULL); | |
636e689e UD |
407 | |
408 | if (result == NULL) | |
409 | { | |
410 | *errnop = ENOMEM; | |
411 | return NSS_STATUS_TRYAGAIN; | |
412 | } | |
413 | ||
414 | if (__builtin_expect (niserr2nss (result->status) != NSS_STATUS_SUCCESS, 0)) | |
415 | { | |
416 | enum nss_status status = niserr2nss (result->status); | |
e61abf83 | 417 | |
636e689e | 418 | __set_errno (olderr); |
e61abf83 | 419 | |
636e689e UD |
420 | nis_freeresult (result); |
421 | return status; | |
422 | } | |
e61abf83 | 423 | |
636e689e UD |
424 | int parse_res = _nss_nisplus_parse_rpcent (result, rpc, buffer, buflen, |
425 | errnop); | |
e61abf83 | 426 | |
636e689e | 427 | nis_freeresult (result); |
0ecb606c | 428 | |
636e689e UD |
429 | if (parse_res < 1) |
430 | { | |
431 | if (parse_res == -1) | |
432 | { | |
433 | *errnop = ERANGE; | |
434 | return NSS_STATUS_TRYAGAIN; | |
435 | } | |
436 | else | |
437 | { | |
438 | __set_errno (olderr); | |
439 | return NSS_STATUS_NOTFOUND; | |
440 | } | |
441 | } | |
442 | ||
443 | return NSS_STATUS_SUCCESS; | |
e61abf83 | 444 | } |