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