Updated to fedora-glibc-20051219T1003
[glibc.git] / nis / nss_nisplus / nisplus-rpc.c
blob98baa5f7fcf721f0301c5091e858113c49c5fd2e
1 /* Copyright (C) 1997,1998,2001,2002,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.
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, write to the Free
17 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
18 02111-1307 USA. */
20 #include <atomic.h>
21 #include <ctype.h>
22 #include <errno.h>
23 #include <nss.h>
24 #include <string.h>
25 #include <rpc/netdb.h>
26 #include <rpcsvc/nis.h>
27 #include <bits/libc-lock.h>
29 #include "nss-nisplus.h"
31 __libc_lock_define_initialized (static, lock)
33 static nis_result *result;
34 static nis_name tablename_val;
35 static u_long tablename_len;
37 #define NISENTRYVAL(idx,col,res) \
38 ((res)->objects.objects_val[(idx)].EN_data.en_cols.en_cols_val[(col)].ec_value.ec_value_val)
40 #define NISENTRYLEN(idx,col,res) \
41 ((res)->objects.objects_val[(idx)].EN_data.en_cols.en_cols_val[(col)].ec_value.ec_value_len)
43 static int
44 _nss_nisplus_parse_rpcent (nis_result *result, struct rpcent *rpc,
45 char *buffer, size_t buflen, int *errnop)
47 char *first_unused = buffer;
48 size_t room_left = buflen;
49 unsigned int i;
50 char *p, *line;
53 if (result == NULL)
54 return 0;
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 "rpc_tbl") != 0
60 || result->objects.objects_val[0].EN_data.en_cols.en_cols_len < 3)
61 return 0;
63 if (NISENTRYLEN (0, 0, result) >= room_left)
65 no_more_room:
66 *errnop = ERANGE;
67 return -1;
69 strncpy (first_unused, NISENTRYVAL (0, 0, result),
70 NISENTRYLEN (0, 0, result));
71 first_unused[NISENTRYLEN (0, 0, result)] = '\0';
72 rpc->r_name = first_unused;
73 room_left -= (strlen (first_unused) + 1);
74 first_unused += strlen (first_unused) + 1;
75 rpc->r_number = atoi (NISENTRYVAL (0, 2, result));
76 p = first_unused;
78 line = p;
79 for (i = 0; i < result->objects.objects_len; ++i)
81 if (strcmp (NISENTRYVAL (i, 1, result), rpc->r_name) != 0)
83 if (NISENTRYLEN (i, 1, result) + 2 > room_left)
84 goto no_more_room;
85 *p++ = ' ';
86 p = __stpncpy (p, NISENTRYVAL (i, 1, result),
87 NISENTRYLEN (i, 1, result));
88 *p = '\0';
89 room_left -= (NISENTRYLEN (i, 1, result) + 1);
92 ++p;
93 first_unused = p;
95 /* Adjust the pointer so it is aligned for
96 storing pointers. */
97 first_unused += __alignof__ (char *) - 1;
98 first_unused -= ((first_unused - (char *) 0) % __alignof__ (char *));
99 rpc->r_aliases = (char **) first_unused;
100 if (room_left < sizeof (char *))
101 goto no_more_room;
102 room_left -= sizeof (char *);
103 rpc->r_aliases[0] = NULL;
105 i = 0;
106 while (*line != '\0')
108 /* Skip leading blanks. */
109 while (isspace (*line))
110 ++line;
112 if (*line == '\0')
113 break;
115 if (room_left < sizeof (char *))
116 goto no_more_room;
118 room_left -= sizeof (char *);
119 rpc->r_aliases[i] = line;
121 while (*line != '\0' && *line != ' ')
122 ++line;
124 if (*line == ' ')
126 *line = '\0';
127 ++line;
128 ++i;
130 else
131 rpc->r_aliases[i+1] = NULL;
134 return 1;
137 static enum nss_status
138 _nss_create_tablename (int *errnop)
140 if (tablename_val == NULL)
142 const char *local_dir = nis_local_directory ();
143 size_t local_dir_len = strlen (local_dir);
144 static const char prefix[] = "rpc.org_dir.";
146 char *p = malloc (sizeof (prefix) + local_dir_len);
147 if (tablename_val == NULL)
149 *errnop = errno;
150 return NSS_STATUS_TRYAGAIN;
153 memcpy (__stpcpy (p, prefix), local_dir, local_dir_len + 1);
155 tablename_len = sizeof (prefix) - 1 + local_dir_len;
157 atomic_write_barrier ();
159 tablename_val = p;
162 return NSS_STATUS_SUCCESS;
166 enum nss_status
167 _nss_nisplus_setrpcent (int stayopen)
169 enum nss_status status = NSS_STATUS_SUCCESS;
171 __libc_lock_lock (lock);
173 if (result != NULL)
175 nis_freeresult (result);
176 result = NULL;
179 if (tablename_val == NULL)
181 int err;
182 status = _nss_create_tablename (&err);
185 __libc_lock_unlock (lock);
187 return status;
190 enum nss_status
191 _nss_nisplus_endrpcent (void)
193 __libc_lock_lock (lock);
195 if (result != NULL)
197 nis_freeresult (result);
198 result = NULL;
201 __libc_lock_unlock (lock);
203 return NSS_STATUS_SUCCESS;
206 static enum nss_status
207 internal_nisplus_getrpcent_r (struct rpcent *rpc, char *buffer,
208 size_t buflen, int *errnop)
210 int parse_res;
212 /* Get the next entry until we found a correct one. */
215 nis_result *saved_res;
217 if (result == NULL)
219 saved_res = NULL;
220 if (tablename_val == NULL)
222 enum nss_status status = _nss_create_tablename (errnop);
224 if (status != NSS_STATUS_SUCCESS)
225 return status;
228 result = nis_first_entry (tablename_val);
229 if (niserr2nss (result->status) != NSS_STATUS_SUCCESS)
230 return niserr2nss (result->status);
232 else
234 saved_res = result;
235 result = nis_next_entry (tablename_val, &result->cookie);
236 if (niserr2nss (result->status) != NSS_STATUS_SUCCESS)
238 nis_freeresult (saved_res);
239 return niserr2nss (result->status);
243 parse_res = _nss_nisplus_parse_rpcent (result, rpc, buffer,
244 buflen, errnop);
245 if (parse_res == -1)
247 nis_freeresult (result);
248 result = saved_res;
249 *errnop = ERANGE;
250 return NSS_STATUS_TRYAGAIN;
252 else
254 if (saved_res)
255 nis_freeresult (saved_res);
258 while (!parse_res);
260 return NSS_STATUS_SUCCESS;
263 enum nss_status
264 _nss_nisplus_getrpcent_r (struct rpcent *result, char *buffer,
265 size_t buflen, int *errnop)
267 int status;
269 __libc_lock_lock (lock);
271 status = internal_nisplus_getrpcent_r (result, buffer, buflen, errnop);
273 __libc_lock_unlock (lock);
275 return status;
278 enum nss_status
279 _nss_nisplus_getrpcbyname_r (const char *name, struct rpcent *rpc,
280 char *buffer, size_t buflen, int *errnop)
282 int parse_res;
284 if (tablename_val == NULL)
286 __libc_lock_lock (lock);
288 enum nss_status status = _nss_create_tablename (errnop);
290 __libc_lock_unlock (lock);
292 if (status != NSS_STATUS_SUCCESS)
293 return status;
296 if (name == NULL)
297 return NSS_STATUS_NOTFOUND;
299 char buf[strlen (name) + 10 + tablename_len];
300 int olderr = errno;
302 /* Search at first in the alias list, and use the correct name
303 for the next search */
304 snprintf (buf, sizeof (buf), "[name=%s],%s", name, tablename_val);
305 nis_result *result = nis_list (buf, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL);
307 if (result != NULL)
309 char *bufptr = buf;
311 /* If we did not find it, try it as original name. But if the
312 database is correct, we should find it in the first case, too */
313 if ((result->status != NIS_SUCCESS
314 && result->status != NIS_S_SUCCESS)
315 || __type_of (result->objects.objects_val) != NIS_ENTRY_OBJ
316 || strcmp (result->objects.objects_val->EN_data.en_type,
317 "rpc_tbl") != 0
318 || result->objects.objects_val->EN_data.en_cols.en_cols_len < 3)
319 snprintf (buf, sizeof (buf), "[cname=%s],%s", name, tablename_val);
320 else
322 /* We need to allocate a new buffer since there is no
323 guarantee the returned name has a length limit. */
324 const char *entryval = NISENTRYVAL (0, 0, result);
325 size_t buflen = strlen (entryval) + 10 + tablename_len;
326 bufptr = alloca (buflen);
327 snprintf (bufptr, buflen, "[cname=%s],%s",
328 entryval, tablename_val);
331 nis_freeresult (result);
332 result = nis_list (bufptr, FOLLOW_PATH | FOLLOW_LINKS , NULL, NULL);
335 if (result == NULL)
337 *errnop = ENOMEM;
338 return NSS_STATUS_TRYAGAIN;
341 if (__builtin_expect (niserr2nss (result->status) != NSS_STATUS_SUCCESS, 0))
343 enum nss_status status = niserr2nss (result->status);
345 __set_errno (olderr);
347 nis_freeresult (result);
348 return status;
351 parse_res = _nss_nisplus_parse_rpcent (result, rpc, buffer, buflen,
352 errnop);
354 nis_freeresult (result);
356 if (parse_res < 1)
358 if (parse_res == -1)
360 *errnop = ERANGE;
361 return NSS_STATUS_TRYAGAIN;
364 __set_errno (olderr);
365 return NSS_STATUS_NOTFOUND;
368 return NSS_STATUS_SUCCESS;
371 enum nss_status
372 _nss_nisplus_getrpcbynumber_r (const int number, struct rpcent *rpc,
373 char *buffer, size_t buflen, int *errnop)
375 if (tablename_val == NULL)
377 __libc_lock_lock (lock);
379 enum nss_status status = _nss_create_tablename (errnop);
381 __libc_lock_unlock (lock);
383 if (status != NSS_STATUS_SUCCESS)
384 return status;
387 char buf[12 + 3 * sizeof (number) + tablename_len];
388 int olderr = errno;
390 snprintf (buf, sizeof (buf), "[number=%d],%s", number, tablename_val);
392 nis_result *result = nis_list (buf, FOLLOW_LINKS | FOLLOW_PATH, NULL, NULL);
394 if (result == NULL)
396 *errnop = ENOMEM;
397 return NSS_STATUS_TRYAGAIN;
400 if (__builtin_expect (niserr2nss (result->status) != NSS_STATUS_SUCCESS, 0))
402 enum nss_status status = niserr2nss (result->status);
404 __set_errno (olderr);
406 nis_freeresult (result);
407 return status;
410 int parse_res = _nss_nisplus_parse_rpcent (result, rpc, buffer, buflen,
411 errnop);
413 nis_freeresult (result);
415 if (parse_res < 1)
417 if (parse_res == -1)
419 *errnop = ERANGE;
420 return NSS_STATUS_TRYAGAIN;
422 else
424 __set_errno (olderr);
425 return NSS_STATUS_NOTFOUND;
429 return NSS_STATUS_SUCCESS;