]> git.ipfire.org Git - thirdparty/glibc.git/blob - nis/nss_nisplus/nisplus-rpc.c
* nis/nss_nisplus/nisplus-rpc.c (_nss_nisplus_parse_rpcent):
[thirdparty/glibc.git] / nis / nss_nisplus / nisplus-rpc.c
1 /* Copyright (C) 1997, 1998, 2001, 2002, 2003, 2005, 2006
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.
5
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.
10
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.
15
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. */
20
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>
29
30 #include "nss-nisplus.h"
31
32 __libc_lock_define_initialized (static, lock)
33
34 static nis_result *result;
35 static nis_name tablename_val;
36 static u_long tablename_len;
37
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)
40
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)
43
44
45 static int
46 _nss_nisplus_parse_rpcent (nis_result *result, struct rpcent *rpc,
47 char *buffer, size_t buflen, int *errnop)
48 {
49 char *first_unused = buffer;
50 size_t room_left = buflen;
51 unsigned int i;
52 char *line;
53
54
55 if (result == NULL)
56 return 0;
57
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;
63
64 if (NISENTRYLEN (0, 0, result) >= room_left)
65 {
66 no_more_room:
67 *errnop = ERANGE;
68 return -1;
69 }
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;
77
78 rpc->r_number = atoi (NISENTRYVAL (0, 2, result));
79
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)
85 {
86 if (strcmp (NISENTRYVAL (i, 1, result), rpc->r_name) != 0)
87 {
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;
94 }
95 }
96 *first_unused++ = '\0';
97
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;
108
109 /* For the terminating NULL pointer. */
110 room_left -= sizeof (char *);
111
112 i = 0;
113 while (*line != '\0')
114 {
115 /* Skip leading blanks. */
116 while (isspace (*line))
117 ++line;
118
119 if (*line == '\0')
120 break;
121
122 if (room_left < sizeof (char *))
123 goto no_more_room;
124
125 room_left -= sizeof (char *);
126 rpc->r_aliases[i++] = line;
127
128 while (*line != '\0' && *line != ' ')
129 ++line;
130
131 if (*line == ' ')
132 *line++ = '\0';
133 }
134 rpc->r_aliases[i] = NULL;
135
136 return 1;
137 }
138
139
140 static enum nss_status
141 _nss_create_tablename (int *errnop)
142 {
143 if (tablename_val == NULL)
144 {
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.";
148
149 char *p = malloc (sizeof (prefix) + local_dir_len);
150 if (p == NULL)
151 {
152 *errnop = errno;
153 return NSS_STATUS_TRYAGAIN;
154 }
155
156 memcpy (__stpcpy (p, prefix), local_dir, local_dir_len + 1);
157
158 tablename_len = sizeof (prefix) - 1 + local_dir_len;
159
160 atomic_write_barrier ();
161
162 tablename_val = p;
163 }
164
165 return NSS_STATUS_SUCCESS;
166 }
167
168
169 enum nss_status
170 _nss_nisplus_setrpcent (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_endrpcent (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_getrpcent_r (struct rpcent *rpc, char *buffer,
211 size_t buflen, int *errnop)
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 if (tablename_val == NULL)
224 {
225 enum nss_status status = _nss_create_tablename (errnop);
226
227 if (status != NSS_STATUS_SUCCESS)
228 return status;
229 }
230
231 result = nis_first_entry (tablename_val);
232 if (niserr2nss (result->status) != NSS_STATUS_SUCCESS)
233 return niserr2nss (result->status);
234 }
235 else
236 {
237 saved_res = result;
238 result = nis_next_entry (tablename_val, &result->cookie);
239 if (niserr2nss (result->status) != NSS_STATUS_SUCCESS)
240 {
241 nis_freeresult (saved_res);
242 return niserr2nss (result->status);
243 }
244 }
245
246 parse_res = _nss_nisplus_parse_rpcent (result, rpc, buffer,
247 buflen, errnop);
248 if (parse_res == -1)
249 {
250 nis_freeresult (result);
251 result = saved_res;
252 *errnop = ERANGE;
253 return NSS_STATUS_TRYAGAIN;
254 }
255 else
256 {
257 if (saved_res)
258 nis_freeresult (saved_res);
259 }
260 }
261 while (!parse_res);
262
263 return NSS_STATUS_SUCCESS;
264 }
265
266 enum nss_status
267 _nss_nisplus_getrpcent_r (struct rpcent *result, char *buffer,
268 size_t buflen, int *errnop)
269 {
270 int status;
271
272 __libc_lock_lock (lock);
273
274 status = internal_nisplus_getrpcent_r (result, buffer, buflen, errnop);
275
276 __libc_lock_unlock (lock);
277
278 return status;
279 }
280
281 enum nss_status
282 _nss_nisplus_getrpcbyname_r (const char *name, struct rpcent *rpc,
283 char *buffer, size_t buflen, int *errnop)
284 {
285 int parse_res;
286
287 if (tablename_val == NULL)
288 {
289 __libc_lock_lock (lock);
290
291 enum nss_status status = _nss_create_tablename (errnop);
292
293 __libc_lock_unlock (lock);
294
295 if (status != NSS_STATUS_SUCCESS)
296 return status;
297 }
298
299 if (name == NULL)
300 return NSS_STATUS_NOTFOUND;
301
302 char buf[strlen (name) + 10 + tablename_len];
303 int olderr = errno;
304
305 /* Search at first in the alias list, and use the correct name
306 for the next search */
307 snprintf (buf, sizeof (buf), "[name=%s],%s", name, tablename_val);
308 nis_result *result = nis_list (buf, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL);
309
310 if (result != NULL)
311 {
312 char *bufptr = buf;
313
314 /* If we did not find it, try it as original name. But if the
315 database is correct, we should find it in the first case, too */
316 if ((result->status != NIS_SUCCESS
317 && result->status != NIS_S_SUCCESS)
318 || __type_of (result->objects.objects_val) != NIS_ENTRY_OBJ
319 || strcmp (result->objects.objects_val->EN_data.en_type,
320 "rpc_tbl") != 0
321 || result->objects.objects_val->EN_data.en_cols.en_cols_len < 3)
322 snprintf (buf, sizeof (buf), "[cname=%s],%s", name, tablename_val);
323 else
324 {
325 /* We need to allocate a new buffer since there is no
326 guarantee the returned name has a length limit. */
327 const char *entryval = NISENTRYVAL (0, 0, result);
328 size_t buflen = strlen (entryval) + 10 + tablename_len;
329 bufptr = alloca (buflen);
330 snprintf (bufptr, buflen, "[cname=%s],%s",
331 entryval, tablename_val);
332 }
333
334 nis_freeresult (result);
335 result = nis_list (bufptr, FOLLOW_PATH | FOLLOW_LINKS , NULL, NULL);
336 }
337
338 if (result == NULL)
339 {
340 *errnop = ENOMEM;
341 return NSS_STATUS_TRYAGAIN;
342 }
343
344 if (__builtin_expect (niserr2nss (result->status) != NSS_STATUS_SUCCESS, 0))
345 {
346 enum nss_status status = niserr2nss (result->status);
347
348 __set_errno (olderr);
349
350 nis_freeresult (result);
351 return status;
352 }
353
354 parse_res = _nss_nisplus_parse_rpcent (result, rpc, buffer, buflen,
355 errnop);
356
357 nis_freeresult (result);
358
359 if (parse_res < 1)
360 {
361 if (parse_res == -1)
362 {
363 *errnop = ERANGE;
364 return NSS_STATUS_TRYAGAIN;
365 }
366
367 __set_errno (olderr);
368 return NSS_STATUS_NOTFOUND;
369 }
370
371 return NSS_STATUS_SUCCESS;
372 }
373
374 enum nss_status
375 _nss_nisplus_getrpcbynumber_r (const int number, struct rpcent *rpc,
376 char *buffer, size_t buflen, int *errnop)
377 {
378 if (tablename_val == NULL)
379 {
380 __libc_lock_lock (lock);
381
382 enum nss_status status = _nss_create_tablename (errnop);
383
384 __libc_lock_unlock (lock);
385
386 if (status != NSS_STATUS_SUCCESS)
387 return status;
388 }
389
390 char buf[12 + 3 * sizeof (number) + tablename_len];
391 int olderr = errno;
392
393 snprintf (buf, sizeof (buf), "[number=%d],%s", number, tablename_val);
394
395 nis_result *result = nis_list (buf, FOLLOW_LINKS | FOLLOW_PATH, NULL, NULL);
396
397 if (result == NULL)
398 {
399 *errnop = ENOMEM;
400 return NSS_STATUS_TRYAGAIN;
401 }
402
403 if (__builtin_expect (niserr2nss (result->status) != NSS_STATUS_SUCCESS, 0))
404 {
405 enum nss_status status = niserr2nss (result->status);
406
407 __set_errno (olderr);
408
409 nis_freeresult (result);
410 return status;
411 }
412
413 int parse_res = _nss_nisplus_parse_rpcent (result, rpc, buffer, buflen,
414 errnop);
415
416 nis_freeresult (result);
417
418 if (parse_res < 1)
419 {
420 if (parse_res == -1)
421 {
422 *errnop = ERANGE;
423 return NSS_STATUS_TRYAGAIN;
424 }
425 else
426 {
427 __set_errno (olderr);
428 return NSS_STATUS_NOTFOUND;
429 }
430 }
431
432 return NSS_STATUS_SUCCESS;
433 }