[BZ #4381]
[glibc.git] / nis / nss_nisplus / nisplus-rpc.c
blob711c6bc2732150547c29a100da7c253c9dfb4138
1 /* Copyright (C) 1997, 1998, 2001, 2002, 2003, 2005, 2006, 2007
2 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
4 Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1997.
6 The GNU C Library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
11 The GNU C Library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public
17 License along with the GNU C Library; if not, write to the Free
18 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
19 02111-1307 USA. */
21 #include <atomic.h>
22 #include <ctype.h>
23 #include <errno.h>
24 #include <nss.h>
25 #include <string.h>
26 #include <rpc/netdb.h>
27 #include <rpcsvc/nis.h>
28 #include <bits/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)
45 static int
46 _nss_nisplus_parse_rpcent (nis_result *result, struct rpcent *rpc,
47 char *buffer, size_t buflen, int *errnop)
49 char *first_unused = buffer;
50 size_t room_left = buflen;
51 unsigned int i;
52 char *line;
55 if (result == NULL)
56 return 0;
58 if ((result->status != NIS_SUCCESS && result->status != NIS_S_SUCCESS)
59 || __type_of (NIS_RES_OBJECT (result)) != NIS_ENTRY_OBJ
60 || strcmp (NIS_RES_OBJECT (result)[0].EN_data.en_type, "rpc_tbl") != 0
61 || NIS_RES_OBJECT (result)[0].EN_data.en_cols.en_cols_len < 3)
62 return 0;
64 if (NISENTRYLEN (0, 0, result) >= room_left)
66 no_more_room:
67 *errnop = ERANGE;
68 return -1;
70 strncpy (first_unused, NISENTRYVAL (0, 0, result),
71 NISENTRYLEN (0, 0, result));
72 first_unused[NISENTRYLEN (0, 0, result)] = '\0';
73 rpc->r_name = first_unused;
74 size_t len = strlen (first_unused) + 1;
75 room_left -= len;
76 first_unused += len;
78 rpc->r_number = atoi (NISENTRYVAL (0, 2, result));
80 /* XXX Rewrite at some point to allocate the array first and then
81 copy the strings. It wasteful to first concatenate the strings
82 to just split them again later. */
83 line = first_unused;
84 for (i = 0; i < NIS_RES_NUMOBJ (result); ++i)
86 if (strcmp (NISENTRYVAL (i, 1, result), rpc->r_name) != 0)
88 if (NISENTRYLEN (i, 1, result) + 2 > room_left)
89 goto no_more_room;
90 *first_unused++ = ' ';
91 first_unused = __stpncpy (first_unused, NISENTRYVAL (i, 1, result),
92 NISENTRYLEN (i, 1, result));
93 room_left -= NISENTRYLEN (i, 1, result) + 1;
96 *first_unused++ = '\0';
98 /* Adjust the pointer so it is aligned for
99 storing pointers. */
100 size_t adjust = ((__alignof__ (char *)
101 - (first_unused - (char *) 0) % __alignof__ (char *))
102 % __alignof__ (char *));
103 if (room_left < adjust + sizeof (char *))
104 goto no_more_room;
105 first_unused += adjust;
106 room_left -= adjust;
107 rpc->r_aliases = (char **) first_unused;
109 /* For the terminating NULL pointer. */
110 room_left -= sizeof (char *);
112 i = 0;
113 while (*line != '\0')
115 /* Skip leading blanks. */
116 while (isspace (*line))
117 ++line;
119 if (*line == '\0')
120 break;
122 if (room_left < sizeof (char *))
123 goto no_more_room;
125 room_left -= sizeof (char *);
126 rpc->r_aliases[i++] = line;
128 while (*line != '\0' && *line != ' ')
129 ++line;
131 if (*line == ' ')
132 *line++ = '\0';
134 rpc->r_aliases[i] = NULL;
136 return 1;
140 static enum nss_status
141 _nss_create_tablename (int *errnop)
143 if (tablename_val == NULL)
145 const char *local_dir = nis_local_directory ();
146 size_t local_dir_len = strlen (local_dir);
147 static const char prefix[] = "rpc.org_dir.";
149 char *p = malloc (sizeof (prefix) + local_dir_len);
150 if (p == NULL)
152 *errnop = errno;
153 return NSS_STATUS_TRYAGAIN;
156 memcpy (__stpcpy (p, prefix), local_dir, local_dir_len + 1);
158 tablename_len = sizeof (prefix) - 1 + local_dir_len;
160 atomic_write_barrier ();
162 tablename_val = p;
165 return NSS_STATUS_SUCCESS;
169 enum nss_status
170 _nss_nisplus_setrpcent (int stayopen)
172 enum nss_status status = NSS_STATUS_SUCCESS;
174 __libc_lock_lock (lock);
176 if (result != NULL)
178 nis_freeresult (result);
179 result = NULL;
182 if (tablename_val == NULL)
184 int err;
185 status = _nss_create_tablename (&err);
188 __libc_lock_unlock (lock);
190 return status;
193 enum nss_status
194 _nss_nisplus_endrpcent (void)
196 __libc_lock_lock (lock);
198 if (result != NULL)
200 nis_freeresult (result);
201 result = NULL;
204 __libc_lock_unlock (lock);
206 return NSS_STATUS_SUCCESS;
209 static enum nss_status
210 internal_nisplus_getrpcent_r (struct rpcent *rpc, char *buffer,
211 size_t buflen, int *errnop)
213 int parse_res;
215 /* Get the next entry until we found a correct one. */
218 nis_result *saved_res;
220 if (result == NULL)
222 saved_res = NULL;
223 if (tablename_val == NULL)
225 enum nss_status status = _nss_create_tablename (errnop);
227 if (status != NSS_STATUS_SUCCESS)
228 return status;
231 result = nis_first_entry (tablename_val);
232 if (result == NULL)
234 *errnop = errno;
235 return NSS_STATUS_TRYAGAIN;
237 if (niserr2nss (result->status) != NSS_STATUS_SUCCESS)
238 return niserr2nss (result->status);
240 else
242 saved_res = result;
243 result = nis_next_entry (tablename_val, &result->cookie);
244 if (result == NULL)
246 *errnop = errno;
247 return NSS_STATUS_TRYAGAIN;
249 if (niserr2nss (result->status) != NSS_STATUS_SUCCESS)
251 nis_freeresult (saved_res);
252 return niserr2nss (result->status);
256 parse_res = _nss_nisplus_parse_rpcent (result, rpc, buffer,
257 buflen, errnop);
258 if (parse_res == -1)
260 nis_freeresult (result);
261 result = saved_res;
262 *errnop = ERANGE;
263 return NSS_STATUS_TRYAGAIN;
265 else
267 if (saved_res)
268 nis_freeresult (saved_res);
271 while (!parse_res);
273 return NSS_STATUS_SUCCESS;
276 enum nss_status
277 _nss_nisplus_getrpcent_r (struct rpcent *result, char *buffer,
278 size_t buflen, int *errnop)
280 int status;
282 __libc_lock_lock (lock);
284 status = internal_nisplus_getrpcent_r (result, buffer, buflen, errnop);
286 __libc_lock_unlock (lock);
288 return status;
291 enum nss_status
292 _nss_nisplus_getrpcbyname_r (const char *name, struct rpcent *rpc,
293 char *buffer, size_t buflen, int *errnop)
295 int parse_res;
297 if (tablename_val == NULL)
299 __libc_lock_lock (lock);
301 enum nss_status status = _nss_create_tablename (errnop);
303 __libc_lock_unlock (lock);
305 if (status != NSS_STATUS_SUCCESS)
306 return status;
309 if (name == NULL)
310 return NSS_STATUS_NOTFOUND;
312 char buf[strlen (name) + 10 + tablename_len];
313 int olderr = errno;
315 /* Search at first in the alias list, and use the correct name
316 for the next search */
317 snprintf (buf, sizeof (buf), "[name=%s],%s", name, tablename_val);
318 nis_result *result = nis_list (buf, FOLLOW_PATH | FOLLOW_LINKS | USE_DGRAM,
319 NULL, NULL);
321 if (result != NULL)
323 char *bufptr = buf;
325 /* If we did not find it, try it as original name. But if the
326 database is correct, we should find it in the first case, too */
327 if ((result->status != NIS_SUCCESS
328 && result->status != NIS_S_SUCCESS)
329 || __type_of (result->objects.objects_val) != NIS_ENTRY_OBJ
330 || strcmp (result->objects.objects_val->EN_data.en_type,
331 "rpc_tbl") != 0
332 || result->objects.objects_val->EN_data.en_cols.en_cols_len < 3)
333 snprintf (buf, sizeof (buf), "[cname=%s],%s", name, tablename_val);
334 else
336 /* We need to allocate a new buffer since there is no
337 guarantee the returned name has a length limit. */
338 const char *entryval = NISENTRYVAL (0, 0, result);
339 size_t buflen = strlen (entryval) + 10 + tablename_len;
340 bufptr = alloca (buflen);
341 snprintf (bufptr, buflen, "[cname=%s],%s",
342 entryval, tablename_val);
345 nis_freeresult (result);
346 result = nis_list (bufptr, FOLLOW_PATH | FOLLOW_LINKS | USE_DGRAM,
347 NULL, NULL);
350 if (result == NULL)
352 *errnop = ENOMEM;
353 return NSS_STATUS_TRYAGAIN;
356 if (__builtin_expect (niserr2nss (result->status) != NSS_STATUS_SUCCESS, 0))
358 enum nss_status status = niserr2nss (result->status);
360 __set_errno (olderr);
362 nis_freeresult (result);
363 return status;
366 parse_res = _nss_nisplus_parse_rpcent (result, rpc, buffer, buflen,
367 errnop);
369 nis_freeresult (result);
371 if (parse_res < 1)
373 if (parse_res == -1)
375 *errnop = ERANGE;
376 return NSS_STATUS_TRYAGAIN;
379 __set_errno (olderr);
380 return NSS_STATUS_NOTFOUND;
383 return NSS_STATUS_SUCCESS;
386 enum nss_status
387 _nss_nisplus_getrpcbynumber_r (const int number, struct rpcent *rpc,
388 char *buffer, size_t buflen, int *errnop)
390 if (tablename_val == NULL)
392 __libc_lock_lock (lock);
394 enum nss_status status = _nss_create_tablename (errnop);
396 __libc_lock_unlock (lock);
398 if (status != NSS_STATUS_SUCCESS)
399 return status;
402 char buf[12 + 3 * sizeof (number) + tablename_len];
403 int olderr = errno;
405 snprintf (buf, sizeof (buf), "[number=%d],%s", number, tablename_val);
407 nis_result *result = nis_list (buf, FOLLOW_LINKS | FOLLOW_PATH | USE_DGRAM,
408 NULL, NULL);
410 if (result == NULL)
412 *errnop = ENOMEM;
413 return NSS_STATUS_TRYAGAIN;
416 if (__builtin_expect (niserr2nss (result->status) != NSS_STATUS_SUCCESS, 0))
418 enum nss_status status = niserr2nss (result->status);
420 __set_errno (olderr);
422 nis_freeresult (result);
423 return status;
426 int parse_res = _nss_nisplus_parse_rpcent (result, rpc, buffer, buflen,
427 errnop);
429 nis_freeresult (result);
431 if (parse_res < 1)
433 if (parse_res == -1)
435 *errnop = ERANGE;
436 return NSS_STATUS_TRYAGAIN;
438 else
440 __set_errno (olderr);
441 return NSS_STATUS_NOTFOUND;
445 return NSS_STATUS_SUCCESS;