]> git.ipfire.org Git - thirdparty/glibc.git/blob - nis/nss_nisplus/nisplus-network.c
* nis/nss_nisplus/nisplus-service.c: Fix locking to use
[thirdparty/glibc.git] / nis / nss_nisplus / nisplus-network.c
1 /* Copyright (C) 1997,1998,2000-2003,2005 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, write to the Free
17 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
18 02111-1307 USA. */
19
20 #include <atomic.h>
21 #include <ctype.h>
22 #include <errno.h>
23 #include <netdb.h>
24 #include <nss.h>
25 #include <stdint.h>
26 #include <string.h>
27 #include <arpa/inet.h>
28 #include <rpcsvc/nis.h>
29 #include <bits/libc-lock.h>
30
31 #include "nss-nisplus.h"
32
33 __libc_lock_define_initialized (static, lock)
34
35 static nis_result *result;
36 static nis_name tablename_val;
37 static u_long tablename_len;
38
39 #define NISENTRYVAL(idx,col,res) \
40 ((res)->objects.objects_val[(idx)].EN_data.en_cols.en_cols_val[(col)].ec_value.ec_value_val)
41
42 #define NISENTRYLEN(idx,col,res) \
43 ((res)->objects.objects_val[(idx)].EN_data.en_cols.en_cols_val[(col)].ec_value.ec_value_len)
44
45
46 static int
47 _nss_nisplus_parse_netent (nis_result *result, struct netent *network,
48 char *buffer, size_t buflen, int *errnop)
49 {
50 char *first_unused = buffer;
51 size_t room_left = buflen;
52
53 if (result == NULL)
54 return 0;
55
56 if ((result->status != NIS_SUCCESS && result->status != NIS_S_SUCCESS)
57 || __type_of (result->objects.objects_val) != NIS_ENTRY_OBJ
58 || strcmp (result->objects.objects_val[0].EN_data.en_type,
59 "networks_tbl") != 0
60 || result->objects.objects_val[0].EN_data.en_cols.en_cols_len < 3)
61 return 0;
62
63 if (NISENTRYLEN (0, 0, result) >= room_left)
64 {
65 /* The line is too long for our buffer. */
66 no_more_room:
67 *errnop = ERANGE;
68 return -1;
69 }
70
71 strncpy (first_unused, NISENTRYVAL (0, 0, result),
72 NISENTRYLEN (0, 0, result));
73 first_unused[NISENTRYLEN (0, 0, result)] = '\0';
74 network->n_name = first_unused;
75 room_left -= (strlen (first_unused) +1);
76 first_unused += strlen (first_unused) +1;
77 network->n_addrtype = 0;
78 network->n_net = inet_network (NISENTRYVAL (0, 2, result));
79 char *p = first_unused;
80
81 char *line = p;
82 for (unsigned int i = 0; i < result->objects.objects_len; ++i)
83 {
84 if (strcmp (NISENTRYVAL (i, 1, result), network->n_name) != 0)
85 {
86 if (NISENTRYLEN (i, 1, result) + 2 > room_left)
87 goto no_more_room;
88
89 *p++ = ' ';
90 p = __stpncpy (p, NISENTRYVAL (i, 1, result),
91 NISENTRYLEN (i, 1, result));
92 *p = '\0';
93 room_left -= (NISENTRYLEN (i, 1, result) + 1);
94 }
95 }
96 *p++ = '\0';
97 first_unused = p;
98
99 /* Adjust the pointer so it is aligned for
100 storing pointers. */
101 first_unused += __alignof__ (char *) - 1;
102 first_unused -= ((first_unused - (char *) 0) % __alignof__ (char *));
103 network->n_aliases = (char **) first_unused;
104 if (room_left < 2 * sizeof (char *))
105 goto no_more_room;
106 room_left -= (2 * sizeof (char *));
107 network->n_aliases[0] = NULL;
108
109 unsigned int i = 0;
110 while (*line != '\0')
111 {
112 /* Skip leading blanks. */
113 while (isspace (*line))
114 ++line;
115
116 if (*line == '\0')
117 break;
118
119 if (room_left < sizeof (char *))
120 goto no_more_room;
121
122 room_left -= sizeof (char *);
123 network->n_aliases[i] = line;
124
125 while (*line != '\0' && *line != ' ')
126 ++line;
127
128 if (*line == ' ')
129 {
130 *line = '\0';
131 ++line;
132 ++i;
133 }
134 else
135 network->n_aliases[i + 1] = NULL;
136 }
137
138 return 1;
139 }
140
141 static enum nss_status
142 _nss_create_tablename (int *errnop)
143 {
144 if (tablename_val == NULL)
145 {
146 const char *local_dir = nis_local_directory ();
147 size_t local_dir_len = strlen (local_dir);
148 static const char prefix[] = "networks.org_dir.";
149
150 char *p = malloc (sizeof (prefix) + local_dir_len);
151 if (tablename_val == NULL)
152 {
153 *errnop = errno;
154 return NSS_STATUS_TRYAGAIN;
155 }
156
157 memcpy (__stpcpy (p, prefix), local_dir, local_dir_len + 1);
158
159 tablename_len = sizeof (prefix) - 1 + local_dir_len;
160
161 atomic_write_barrier ();
162
163 tablename_val = p;
164 }
165
166 return NSS_STATUS_SUCCESS;
167 }
168
169 enum nss_status
170 _nss_nisplus_setnetent (int stayopen)
171 {
172 enum nss_status status = NSS_STATUS_SUCCESS;
173
174 __libc_lock_lock (lock);
175
176 if (result != NULL)
177 {
178 nis_freeresult (result);
179 result = NULL;
180 }
181
182 if (tablename_val == NULL)
183 {
184 int err;
185 status = _nss_create_tablename (&err);
186 }
187
188 __libc_lock_unlock (lock);
189
190 return status;
191 }
192
193 enum nss_status
194 _nss_nisplus_endnetent (void)
195 {
196 __libc_lock_lock (lock);
197
198 if (result != NULL)
199 {
200 nis_freeresult (result);
201 result = NULL;
202 }
203
204 __libc_lock_unlock (lock);
205
206 return NSS_STATUS_SUCCESS;
207 }
208
209 static enum nss_status
210 internal_nisplus_getnetent_r (struct netent *network, char *buffer,
211 size_t buflen, int *errnop, int *herrnop)
212 {
213 int parse_res;
214
215 /* Get the next entry until we found a correct one. */
216 do
217 {
218 nis_result *saved_res;
219
220 if (result == NULL)
221 {
222 saved_res = NULL;
223
224 if (tablename_val == NULL)
225 {
226 enum nss_status status = _nss_create_tablename (errnop);
227
228 if (status != NSS_STATUS_SUCCESS)
229 return status;
230 }
231
232 result = nis_first_entry (tablename_val);
233 if (niserr2nss (result->status) != NSS_STATUS_SUCCESS)
234 {
235 int retval = niserr2nss (result->status);
236 nis_freeresult (result);
237 result = NULL;
238 if (retval == NSS_STATUS_TRYAGAIN)
239 {
240 *herrnop = NETDB_INTERNAL;
241 *errnop = errno;
242 return retval;
243 }
244 else
245 return retval;
246 }
247 }
248 else
249 {
250 nis_result *res = nis_next_entry (tablename_val, &result->cookie);
251 saved_res = result;
252 result = res;
253 if (niserr2nss (result->status) != NSS_STATUS_SUCCESS)
254 {
255 int retval = niserr2nss (result->status);
256 nis_freeresult (result);
257 result = saved_res;
258 if (retval == NSS_STATUS_TRYAGAIN)
259 {
260 *herrnop = NETDB_INTERNAL;
261 *errnop = errno;
262 }
263 return retval;
264 }
265 }
266
267 parse_res = _nss_nisplus_parse_netent (result, network, buffer,
268 buflen, errnop);
269 if (parse_res == -1)
270 {
271 *herrnop = NETDB_INTERNAL;
272 return NSS_STATUS_TRYAGAIN;
273 }
274
275 }
276 while (!parse_res);
277
278 return NSS_STATUS_SUCCESS;
279 }
280
281 enum nss_status
282 _nss_nisplus_getnetent_r (struct netent *result, char *buffer,
283 size_t buflen, int *errnop, int *herrnop)
284 {
285 int status;
286
287 __libc_lock_lock (lock);
288
289 status = internal_nisplus_getnetent_r (result, buffer, buflen, errnop,
290 herrnop);
291
292 __libc_lock_unlock (lock);
293
294 return status;
295 }
296
297 enum nss_status
298 _nss_nisplus_getnetbyname_r (const char *name, struct netent *network,
299 char *buffer, size_t buflen, int *errnop,
300 int *herrnop)
301 {
302 int parse_res, retval;
303
304 if (tablename_val == NULL)
305 {
306 __libc_lock_lock (lock);
307
308 enum nss_status status = _nss_create_tablename (errnop);
309
310 __libc_lock_unlock (lock);
311
312 if (status != NSS_STATUS_SUCCESS)
313 return status;
314 }
315
316 if (name == NULL)
317 {
318 *errnop = EINVAL;
319 *herrnop = NETDB_INTERNAL;
320 return NSS_STATUS_UNAVAIL;
321 }
322
323 nis_result *result;
324 char buf[strlen (name) + 10 + tablename_len];
325 int olderr = errno;
326
327 /* Search at first in the alias list, and use the correct name
328 for the next search */
329 snprintf (buf, sizeof (buf), "[name=%s],%s", name, tablename_val);
330 result = nis_list (buf, FOLLOW_LINKS | FOLLOW_PATH, NULL, NULL);
331
332 if (result != NULL)
333 {
334 char *bufptr = buf;
335
336 /* If we do not find it, try it as original name. But if the
337 database is correct, we should find it in the first case, too */
338 if ((result->status != NIS_SUCCESS
339 && result->status != NIS_S_SUCCESS)
340 || __type_of (result->objects.objects_val) != NIS_ENTRY_OBJ
341 || strcmp (result->objects.objects_val[0].EN_data.en_type,
342 "networks_tbl") != 0
343 || (result->objects.objects_val[0].EN_data.en_cols.en_cols_len
344 < 3))
345 snprintf (buf, sizeof (buf), "[cname=%s],%s", name, tablename_val);
346 else
347 {
348 /* We need to allocate a new buffer since there is no
349 guarantee the returned name has a length limit. */
350 const char *entryval = NISENTRYVAL (0, 0, result);
351 size_t buflen = strlen (entryval) + 10 + tablename_len;
352 bufptr = alloca (buflen);
353 snprintf (bufptr, buflen, "[cname=%s],%s",
354 entryval, tablename_val);
355 }
356
357 nis_freeresult (result);
358 result = nis_list (bufptr, FOLLOW_LINKS | FOLLOW_PATH, NULL, NULL);
359 }
360
361 if (result == NULL)
362 {
363 __set_errno (ENOMEM);
364 return NSS_STATUS_TRYAGAIN;
365 }
366
367 retval = niserr2nss (result->status);
368 if (__builtin_expect (retval != NSS_STATUS_SUCCESS, 0))
369 {
370 if (retval == NSS_STATUS_TRYAGAIN)
371 {
372 *errnop = errno;
373 *herrnop = NETDB_INTERNAL;
374 }
375 else
376 __set_errno (olderr);
377 nis_freeresult (result);
378 return retval;
379 }
380
381 parse_res = _nss_nisplus_parse_netent (result, network, buffer, buflen,
382 errnop);
383
384 nis_freeresult (result);
385
386 if (parse_res > 0)
387 return NSS_STATUS_SUCCESS;
388
389 *herrnop = NETDB_INTERNAL;
390 if (parse_res == -1)
391 {
392 *errnop = ERANGE;
393 return NSS_STATUS_TRYAGAIN;
394 }
395
396 __set_errno (olderr);
397 return NSS_STATUS_NOTFOUND;
398 }
399
400 /* XXX type is ignored, SUN's NIS+ table doesn't support it */
401 enum nss_status
402 _nss_nisplus_getnetbyaddr_r (uint32_t addr, const int type,
403 struct netent *network, char *buffer,
404 size_t buflen, int *errnop, int *herrnop)
405 {
406 if (tablename_val == NULL)
407 {
408 __libc_lock_lock (lock);
409
410 enum nss_status status = _nss_create_tablename (errnop);
411
412 __libc_lock_unlock (lock);
413
414 if (status != NSS_STATUS_SUCCESS)
415 return status;
416 }
417
418 {
419 int parse_res, retval;
420 nis_result *result;
421 char buf[1024 + tablename_len];
422 struct in_addr in;
423 char buf2[256];
424 int b2len;
425 int olderr = errno;
426
427 in = inet_makeaddr (addr, 0);
428 strcpy (buf2, inet_ntoa (in));
429 b2len = strlen (buf2);
430
431 while (1)
432 {
433 sprintf (buf, "[addr=%s],%s", buf2, tablename_val);
434 result = nis_list (buf, EXPAND_NAME, NULL, NULL);
435
436 if (result == NULL)
437 {
438 __set_errno (ENOMEM);
439 return NSS_STATUS_TRYAGAIN;
440 }
441 retval = niserr2nss (result->status);
442 if (retval != NSS_STATUS_SUCCESS)
443 {
444 if (buf2[b2len -2] == '.' && buf2[b2len -1] == '0')
445 {
446 /* Try again, but with trailing dot(s)
447 removed (one by one) */
448 buf2[b2len - 2] = '\0';
449 b2len -= 2;
450 continue;
451 }
452 else
453 return NSS_STATUS_NOTFOUND;
454
455 if (retval == NSS_STATUS_TRYAGAIN)
456 {
457 *errnop = errno;
458 *herrnop = NETDB_INTERNAL;
459 }
460 else
461 __set_errno (olderr);
462 nis_freeresult (result);
463 return retval;
464 }
465
466 parse_res = _nss_nisplus_parse_netent (result, network, buffer,
467 buflen, errnop);
468
469 nis_freeresult (result);
470
471 if (parse_res > 0)
472 return NSS_STATUS_SUCCESS;
473
474 *herrnop = NETDB_INTERNAL;
475 if (parse_res == -1)
476 {
477 *errnop = ERANGE;
478 return NSS_STATUS_TRYAGAIN;
479 }
480 else
481 {
482 __set_errno (olderr);
483 return NSS_STATUS_NOTFOUND;
484 }
485 }
486 }
487 }