1 /* Copyright (C) 1997-2018 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.
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.
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.
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/>. */
26 #include <arpa/inet.h>
27 #include <rpcsvc/nis.h>
28 #include <libc-lock.h>
30 #include "nss-nisplus.h"
32 __libc_lock_define_initialized (static, lock
)
34 static nis_result
*result
;
35 static nis_name tablename_val
;
36 static u_long tablename_len
;
38 #define NISENTRYVAL(idx, col, res) \
39 (NIS_RES_OBJECT (res)[idx].EN_data.en_cols.en_cols_val[col].ec_value.ec_value_val)
41 #define NISENTRYLEN(idx, col, res) \
42 (NIS_RES_OBJECT (res)[idx].EN_data.en_cols.en_cols_val[col].ec_value.ec_value_len)
46 _nss_nisplus_parse_netent (nis_result
*result
, struct netent
*network
,
47 char *buffer
, size_t buflen
, int *errnop
)
49 char *first_unused
= buffer
;
50 size_t room_left
= buflen
;
55 if ((result
->status
!= NIS_SUCCESS
&& result
->status
!= NIS_S_SUCCESS
)
56 || __type_of (NIS_RES_OBJECT (result
)) != NIS_ENTRY_OBJ
57 || strcmp (NIS_RES_OBJECT (result
)[0].EN_data
.en_type
,
59 || NIS_RES_OBJECT (result
)[0].EN_data
.en_cols
.en_cols_len
< 3)
62 if (NISENTRYLEN (0, 0, result
) >= room_left
)
64 /* The line is too long for our buffer. */
70 strncpy (first_unused
, NISENTRYVAL (0, 0, result
),
71 NISENTRYLEN (0, 0, result
));
72 first_unused
[NISENTRYLEN (0, 0, result
)] = '\0';
73 network
->n_name
= first_unused
;
74 size_t len
= strlen (first_unused
) + 1;
78 network
->n_addrtype
= 0;
79 network
->n_net
= inet_network (NISENTRYVAL (0, 2, result
));
81 /* XXX Rewrite at some point to allocate the array first and then
82 copy the strings. It wasteful to first concatenate the strings
83 to just split them again later. */
84 char *line
= first_unused
;
85 for (unsigned int i
= 0; i
< NIS_RES_NUMOBJ (result
); ++i
)
87 if (strcmp (NISENTRYVAL (i
, 1, result
), network
->n_name
) != 0)
89 if (NISENTRYLEN (i
, 1, result
) + 2 > room_left
)
92 *first_unused
++ = ' ';
93 first_unused
= __stpncpy (first_unused
, NISENTRYVAL (i
, 1, result
),
94 NISENTRYLEN (i
, 1, result
));
95 room_left
-= (NISENTRYLEN (i
, 1, result
) + 1);
98 *first_unused
++ = '\0';
100 /* Adjust the pointer so it is aligned for
102 size_t adjust
= ((__alignof__ (char *)
103 - (first_unused
- (char *) 0) % __alignof__ (char *))
104 % __alignof__ (char *));
105 if (room_left
< adjust
+ sizeof (char *))
107 first_unused
+= adjust
;
109 network
->n_aliases
= (char **) first_unused
;
111 /* For the terminating NULL pointer. */
112 room_left
-= sizeof (char *);
115 while (*line
!= '\0')
117 /* Skip leading blanks. */
118 while (isspace (*line
))
124 if (room_left
< sizeof (char *))
127 room_left
-= sizeof (char *);
128 network
->n_aliases
[i
++] = line
;
130 while (*line
!= '\0' && *line
!= ' ')
136 network
->n_aliases
[i
] = NULL
;
142 static enum nss_status
143 _nss_create_tablename (int *errnop
)
145 if (tablename_val
== NULL
)
147 const char *local_dir
= nis_local_directory ();
148 size_t local_dir_len
= strlen (local_dir
);
149 static const char prefix
[] = "networks.org_dir.";
151 char *p
= malloc (sizeof (prefix
) + local_dir_len
);
155 return NSS_STATUS_TRYAGAIN
;
158 memcpy (__stpcpy (p
, prefix
), local_dir
, local_dir_len
+ 1);
160 tablename_len
= sizeof (prefix
) - 1 + local_dir_len
;
162 atomic_write_barrier ();
167 return NSS_STATUS_SUCCESS
;
171 _nss_nisplus_setnetent (int stayopen
)
173 enum nss_status status
= NSS_STATUS_SUCCESS
;
175 __libc_lock_lock (lock
);
179 nis_freeresult (result
);
183 if (tablename_val
== NULL
)
186 status
= _nss_create_tablename (&err
);
189 __libc_lock_unlock (lock
);
195 _nss_nisplus_endnetent (void)
197 __libc_lock_lock (lock
);
201 nis_freeresult (result
);
205 __libc_lock_unlock (lock
);
207 return NSS_STATUS_SUCCESS
;
210 static enum nss_status
211 internal_nisplus_getnetent_r (struct netent
*network
, char *buffer
,
212 size_t buflen
, int *errnop
, int *herrnop
)
216 /* Get the next entry until we found a correct one. */
219 nis_result
*saved_res
;
225 if (tablename_val
== NULL
)
227 enum nss_status status
= _nss_create_tablename (errnop
);
229 if (status
!= NSS_STATUS_SUCCESS
)
233 result
= nis_first_entry (tablename_val
);
237 return NSS_STATUS_TRYAGAIN
;
239 if (niserr2nss (result
->status
) != NSS_STATUS_SUCCESS
)
241 int retval
= niserr2nss (result
->status
);
242 nis_freeresult (result
);
244 if (retval
== NSS_STATUS_TRYAGAIN
)
246 *herrnop
= NETDB_INTERNAL
;
257 result
= nis_next_entry (tablename_val
, &result
->cookie
);
261 return NSS_STATUS_TRYAGAIN
;
263 if (niserr2nss (result
->status
) != NSS_STATUS_SUCCESS
)
265 int retval
= niserr2nss (result
->status
);
266 nis_freeresult (result
);
268 if (retval
== NSS_STATUS_TRYAGAIN
)
270 *herrnop
= NETDB_INTERNAL
;
277 parse_res
= _nss_nisplus_parse_netent (result
, network
, buffer
,
281 *herrnop
= NETDB_INTERNAL
;
282 return NSS_STATUS_TRYAGAIN
;
288 return NSS_STATUS_SUCCESS
;
292 _nss_nisplus_getnetent_r (struct netent
*result
, char *buffer
,
293 size_t buflen
, int *errnop
, int *herrnop
)
297 __libc_lock_lock (lock
);
299 status
= internal_nisplus_getnetent_r (result
, buffer
, buflen
, errnop
,
302 __libc_lock_unlock (lock
);
308 _nss_nisplus_getnetbyname_r (const char *name
, struct netent
*network
,
309 char *buffer
, size_t buflen
, int *errnop
,
312 int parse_res
, retval
;
314 if (tablename_val
== NULL
)
316 __libc_lock_lock (lock
);
318 enum nss_status status
= _nss_create_tablename (errnop
);
320 __libc_lock_unlock (lock
);
322 if (status
!= NSS_STATUS_SUCCESS
)
329 *herrnop
= NETDB_INTERNAL
;
330 return NSS_STATUS_UNAVAIL
;
334 char buf
[strlen (name
) + 10 + tablename_len
];
337 /* Search at first in the alias list, and use the correct name
338 for the next search */
339 snprintf (buf
, sizeof (buf
), "[name=%s],%s", name
, tablename_val
);
340 result
= nis_list (buf
, FOLLOW_LINKS
| FOLLOW_PATH
| USE_DGRAM
, NULL
, NULL
);
346 /* If we do not find it, try it as original name. But if the
347 database is correct, we should find it in the first case, too */
348 if ((result
->status
!= NIS_SUCCESS
349 && result
->status
!= NIS_S_SUCCESS
)
350 || __type_of (result
->objects
.objects_val
) != NIS_ENTRY_OBJ
351 || strcmp (result
->objects
.objects_val
[0].EN_data
.en_type
,
353 || (result
->objects
.objects_val
[0].EN_data
.en_cols
.en_cols_len
355 snprintf (buf
, sizeof (buf
), "[cname=%s],%s", name
, tablename_val
);
358 /* We need to allocate a new buffer since there is no
359 guarantee the returned name has a length limit. */
360 const char *entryval
= NISENTRYVAL (0, 0, result
);
361 size_t buflen
= strlen (entryval
) + 10 + tablename_len
;
362 bufptr
= alloca (buflen
);
363 snprintf (bufptr
, buflen
, "[cname=%s],%s",
364 entryval
, tablename_val
);
367 nis_freeresult (result
);
368 result
= nis_list (bufptr
, FOLLOW_LINKS
| FOLLOW_PATH
| USE_DGRAM
,
374 __set_errno (ENOMEM
);
375 return NSS_STATUS_TRYAGAIN
;
378 retval
= niserr2nss (result
->status
);
379 if (__glibc_unlikely (retval
!= NSS_STATUS_SUCCESS
))
381 if (retval
== NSS_STATUS_TRYAGAIN
)
384 *herrnop
= NETDB_INTERNAL
;
387 __set_errno (olderr
);
388 nis_freeresult (result
);
392 parse_res
= _nss_nisplus_parse_netent (result
, network
, buffer
, buflen
,
395 nis_freeresult (result
);
398 return NSS_STATUS_SUCCESS
;
400 *herrnop
= NETDB_INTERNAL
;
404 return NSS_STATUS_TRYAGAIN
;
407 __set_errno (olderr
);
408 return NSS_STATUS_NOTFOUND
;
411 /* XXX type is ignored, SUN's NIS+ table doesn't support it */
413 _nss_nisplus_getnetbyaddr_r (uint32_t addr
, const int type
,
414 struct netent
*network
, char *buffer
,
415 size_t buflen
, int *errnop
, int *herrnop
)
417 if (tablename_val
== NULL
)
419 __libc_lock_lock (lock
);
421 enum nss_status status
= _nss_create_tablename (errnop
);
423 __libc_lock_unlock (lock
);
425 if (status
!= NSS_STATUS_SUCCESS
)
430 char buf
[27 + tablename_len
];
434 struct in_addr in
= { .s_addr
= htonl (addr
) };
435 strcpy (buf2
, inet_ntoa (in
));
436 size_t b2len
= strlen (buf2
);
440 snprintf (buf
, sizeof (buf
), "[addr=%s],%s", buf2
, tablename_val
);
441 nis_result
*result
= nis_list (buf
, EXPAND_NAME
| USE_DGRAM
,
446 __set_errno (ENOMEM
);
447 return NSS_STATUS_TRYAGAIN
;
449 enum nss_status retval
= niserr2nss (result
->status
);
450 if (__glibc_unlikely (retval
!= NSS_STATUS_SUCCESS
))
452 if (b2len
> 2 && buf2
[b2len
- 2] == '.' && buf2
[b2len
- 1] == '0')
454 /* Try again, but with trailing dot(s)
455 removed (one by one) */
456 buf2
[b2len
- 2] = '\0';
458 nis_freeresult (result
);
462 if (retval
== NSS_STATUS_TRYAGAIN
)
465 *herrnop
= NETDB_INTERNAL
;
468 __set_errno (olderr
);
469 nis_freeresult (result
);
473 int parse_res
= _nss_nisplus_parse_netent (result
, network
, buffer
,
476 nis_freeresult (result
);
479 return NSS_STATUS_SUCCESS
;
481 *herrnop
= NETDB_INTERNAL
;
485 return NSS_STATUS_TRYAGAIN
;
489 __set_errno (olderr
);
490 return NSS_STATUS_NOTFOUND
;