]> git.ipfire.org Git - thirdparty/glibc.git/blame - nis/nis_call.c
Update.
[thirdparty/glibc.git] / nis / nis_call.c
CommitLineData
e61abf83
UD
1/* Copyright (C) 1997 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 Library General Public License as
7 published by the Free Software Foundation; either version 2 of the
8 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 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public
16 License along with the GNU C Library; see the file COPYING.LIB. If not,
17 write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA. */
19
20#include <string.h>
21#include <rpc/rpc.h>
22#include <rpc/auth.h>
23#include <rpcsvc/nis.h>
24#include <sys/socket.h>
25#include <netinet/in.h>
26#include <arpa/inet.h>
27#include "nis_intern.h"
28
29static struct timeval TIMEOUT = {25, 0};
30static int const MAXTRIES = 3;
31
32static unsigned long
33inetstr2int (const char *str)
34{
35 char buffer[strlen (str) + 3];
36 size_t buflen;
37 size_t i, j;
38
39 buflen = stpcpy (buffer, str) - buffer;
40
41 j = 0;
42 for (i = 0; i < buflen; ++i)
43 if (buffer[i] == '.')
44 {
45 ++j;
46 if (j == 4)
47 {
48 buffer[i] = '\0';
49 break;
50 }
51 }
52
53 return inet_addr (buffer);
54}
55
56static CLIENT *
57__nis_dobind (const nis_server *server, u_long flags)
58{
59 struct sockaddr_in clnt_saddr;
60 int clnt_sock;
61 size_t i;
62 CLIENT *client = NULL;
e61abf83 63
26dee9c4
UD
64 memset (&clnt_saddr, '\0', sizeof clnt_saddr);
65 clnt_saddr.sin_family = AF_INET;
e61abf83
UD
66 for (i = 0; i < server->ep.ep_len; i++)
67 {
714a562f 68 if (strcmp (server->ep.ep_val[i].family, "loopback") == 0)
e61abf83
UD
69 {
70 if (server->ep.ep_val[i].uaddr[i] == '-')
71 clnt_saddr.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
72 else
714a562f 73 if (strcmp (server->ep.ep_val[i].proto, "udp") == 0)
e61abf83
UD
74 {
75 if ((flags & USE_DGRAM) == USE_DGRAM)
76 clnt_saddr.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
77 else
78 continue;
79 }
26dee9c4 80 else
714a562f 81 if (strcmp (server->ep.ep_val[i].proto, "tcp") == 0)
26dee9c4
UD
82 {
83 if ((flags & USE_DGRAM) == USE_DGRAM)
84 continue;
85 else
86 clnt_saddr.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
87 }
e61abf83
UD
88 }
89 else
714a562f 90 if (strcmp (server->ep.ep_val[i].family, "inet") == 0)
e61abf83
UD
91 {
92 if (server->ep.ep_val[i].uaddr[i] == '-')
93 clnt_saddr.sin_addr.s_addr =
94 inetstr2int (server->ep.ep_val[i].uaddr);
95 else
714a562f 96 if (strcmp (server->ep.ep_val[i].proto, "udp") == 0)
e61abf83
UD
97 {
98 if ((flags & USE_DGRAM) == USE_DGRAM)
99 clnt_saddr.sin_addr.s_addr =
100 inetstr2int (server->ep.ep_val[i].uaddr);
101 else
102 continue;
103 }
104 else
714a562f 105 if (strcmp (server->ep.ep_val[i].proto, "tcp") == 0)
e61abf83
UD
106 {
107 if ((flags & USE_DGRAM) == USE_DGRAM)
108 continue;
109 else
110 clnt_saddr.sin_addr.s_addr =
111 inetstr2int (server->ep.ep_val[i].uaddr);
112 }
113 }
114 else
115 continue;
7799b7b3 116
e61abf83
UD
117 clnt_sock = RPC_ANYSOCK;
118 if ((flags & USE_DGRAM) == USE_DGRAM)
119 client = clntudp_create (&clnt_saddr, NIS_PROG, NIS_VERSION,
120 TIMEOUT, &clnt_sock);
121 else
122 client = clnttcp_create (&clnt_saddr, NIS_PROG, NIS_VERSION,
123 &clnt_sock, 0, 0);
7799b7b3 124
e61abf83
UD
125 if (client == NULL)
126 continue;
e61abf83 127 if (clnt_call (client, 0, (xdrproc_t) xdr_void, NULL,
26dee9c4 128 (xdrproc_t) xdr_void, NULL, TIMEOUT) != RPC_SUCCESS)
e61abf83
UD
129 {
130 clnt_destroy (client);
131 continue;
132 }
26dee9c4 133
e61abf83 134 if ((flags & NO_AUTHINFO) != NO_AUTHINFO)
26dee9c4
UD
135 {
136#if defined(HAVE_SECURE_RPC)
51702635 137 if (server->key_type == NIS_PK_DH && getenv ("NO_SECURE_RPC") == NULL)
26dee9c4
UD
138 {
139 char netname[MAXNETNAMELEN+1];
140 char *p;
7799b7b3 141
26dee9c4
UD
142 p = stpcpy (netname, "unix.");
143 strncpy (p, server->name,MAXNETNAMELEN-5);
144 netname[MAXNETNAMELEN] = '\0';
145 p = strchr (netname, '.');
146 *p = '@';
147 client->cl_auth =
148 authdes_pk_create (netname, &server->pkey, 300, NULL, NULL);
149 if (!client->cl_auth)
150 client->cl_auth = authunix_create_default ();
151 }
152 else
e61abf83 153#endif
26dee9c4
UD
154 client->cl_auth = authunix_create_default ();
155 }
e61abf83
UD
156 return client;
157 }
7799b7b3 158
e61abf83
UD
159 return NULL;
160}
161
162nis_error
43b0e40f
UD
163__do_niscall2 (const nis_server *server, u_int server_len, u_long prog,
164 xdrproc_t xargs, caddr_t req, xdrproc_t xres, caddr_t resp,
165 u_long flags)
e61abf83
UD
166{
167 CLIENT *clnt;
7799b7b3 168 int try, result;
e61abf83 169
43b0e40f
UD
170 try = 0;
171 result = NIS_NAMEUNREACHABLE;
e61abf83 172
26dee9c4
UD
173 if (((flags & MASTER_ONLY) == MASTER_ONLY) && server_len > 1)
174 server_len = 1; /* The first entry is the master */
175
e61abf83
UD
176 while (try < MAXTRIES && result != RPC_SUCCESS)
177 {
178 unsigned int i;
7799b7b3 179
26dee9c4
UD
180 if ((flags & HARD_LOOKUP) == 0)
181 ++try;
7799b7b3 182
e61abf83
UD
183 for (i = 0; i < server_len; i++)
184 {
185 if ((clnt = __nis_dobind (&server[i], flags)) == NULL)
186 continue;
187
188 result = clnt_call (clnt, prog, xargs, req, xres, resp, TIMEOUT);
189
190 if (result != RPC_SUCCESS)
191 {
26dee9c4 192 clnt_perror (clnt, "do_niscall: clnt_call");
e61abf83
UD
193 clnt_destroy (clnt);
194 result = NIS_RPCERROR;
195 }
196 else
197 clnt_destroy (clnt);
198 }
199 }
200
43b0e40f
UD
201 return result;
202}
203
204static directory_obj *
205dir_lookup (const_nis_name name, nis_server *serv, u_long flags)
206{
207 CLIENT *clnt;
208 int try, result;
209 nis_result *res;
210 struct ns_request req;
211 directory_obj *dir;
212
213 res = calloc (1, sizeof (nis_result));
214 req.ns_name = (char *)name;
215 req.ns_object.ns_object_len = 0;
216 req.ns_object.ns_object_val = NULL;
217 try = 0;
218 result = NIS_NAMEUNREACHABLE;
219
220 while (try < MAXTRIES && result != RPC_SUCCESS)
221 {
222 if ((clnt = __nis_dobind (serv, flags)) == NULL)
223 continue;
224
225 result = clnt_call (clnt, NIS_LOOKUP, (xdrproc_t) xdr_ns_request,
226 (caddr_t) &req, (xdrproc_t) xdr_nis_result,
227 (caddr_t) res, TIMEOUT);
228
229 if (result != RPC_SUCCESS)
230 {
231 clnt_perror (clnt, "do_niscall: clnt_call");
232 clnt_destroy (clnt);
233 result = NIS_RPCERROR;
234 }
235 else
236 clnt_destroy (clnt);
237 }
238 if (result != RPC_SUCCESS || res->status != NIS_SUCCESS)
239 return NULL;
240
241 dir = nis_clone_directory (&res->objects.objects_val->DI_data, NULL);
242 nis_freeresult (res);
243
244 return dir;
245}
246
247static directory_obj *
248rec_dirsearch (const_nis_name name, directory_obj *dir, u_long flags)
249{
250 char domain [strlen (name) + 3];
251
252 nis_domain_of_r (name, domain, sizeof (domain));
253 if (strncmp (domain, "org_dir.", 8) == 0)
254 {
255 char tmp[strlen (name) + 3];
256
257 nis_domain_of_r (domain, tmp, sizeof (tmp));
258 strcpy (domain, tmp);
259 }
260 else
261 if (strncmp (domain, "groups_dir.", 11) == 0)
262 {
263 char tmp[strlen (name) + 3];
264
265 nis_domain_of_r (domain, tmp, sizeof (tmp));
266 strcpy (domain, tmp);
267 }
268 else
269 {
270 /* We have no grous_dir or org_dir, so try the complete name */
271 strcpy (domain, name);
272 }
273
274 switch (nis_dir_cmp (domain, dir->do_name))
275 {
276 case SAME_NAME:
277 return dir;
278 case NOT_SEQUENTIAL:
279 /* NOT_SEQUENTIAL means, go one up and try it there ! */
280 case HIGHER_NAME:
281 { /* We need data from a parent domain */
282 directory_obj *obj;
283 char ndomain [strlen (name) + 3];
284
285 nis_domain_of_r (dir->do_name, ndomain, sizeof (ndomain));
286
287 /* The root server of our domain is a replica of the parent
288 domain ! (Now I understand why a root server must be a
289 replica of the parent domain) */
290 obj = dir_lookup (ndomain, dir->do_servers.do_servers_val,
291 flags);
292 if (obj != NULL)
293 {
294 /* We have found a NIS+ server serving ndomain, now
295 let us search for "name" */
296 nis_free_directory (dir);
297 return rec_dirsearch (name, obj, flags);
298 }
299 else
300 {
301 /* Ups, very bad. Are we already the root server ? */
302 nis_free_directory (dir);
303 return NULL;
304 }
305 }
306 break;
307 case LOWER_NAME:
308 {
309 directory_obj *obj;
310 char leaf [strlen (name) + 3];
311 char ndomain [strlen (name) + 3];
312 u_int i;
714a562f 313 char *cp;
43b0e40f
UD
314
315 do
316 {
317 if (strlen (domain) == 0)
318 {
319 nis_free_directory (dir);
320 return NULL;
321 }
322 nis_leaf_of_r (domain, leaf, sizeof (leaf));
323 nis_domain_of_r (domain, ndomain, sizeof (ndomain));
324 strcpy (domain, ndomain);
325 }
326 while (nis_dir_cmp (domain, dir->do_name) != SAME_NAME);
714a562f
UD
327 cp = strchr (leaf, '\0');
328 *cp++ = '.';
329 strcpy (cp, domain);
43b0e40f
UD
330
331 for (i = 0; i < dir->do_servers.do_servers_len; ++i)
332 {
333 obj = dir_lookup (leaf, &dir->do_servers.do_servers_val[i],
334 flags);
335 if (obj != NULL)
336 {
337 /* We have found a NIS+ server serving ndomain, now
338 let us search for "name" */
339 nis_free_directory (dir);
340 return rec_dirsearch (name, obj, flags);
341 }
342 }
343 }
344 break;
345 case BAD_NAME:
346 nis_free_directory (dir);
347 return NULL;
348 }
349 nis_free_directory (dir);
350 return NULL;
351}
352
353nis_error
354__do_niscall (const_nis_name name, u_long prog, xdrproc_t xargs,
355 caddr_t req, xdrproc_t xres, caddr_t resp, u_long flags)
356{
357 nis_error result;
358 directory_obj *dir = NULL;
359 const nis_server *server;
360 u_int server_len;
361
362
363 dir = readColdStartFile ();
364 if (dir == NULL) /* No /var/nis/NIS_COLD_START -> no NIS+ installed */
365 return NIS_UNAVAIL;
366
367 if (name != NULL)
368 {
369 dir = rec_dirsearch (name, dir, flags);
370 if (dir == NULL)
371 {
372 if (nis_dir_cmp (nis_local_directory(), name) == NOT_SEQUENTIAL)
373 return NIS_NAMEUNREACHABLE;
374 else
375 return NIS_NOTFOUND;
376 }
377 }
378 server = dir->do_servers.do_servers_val;
379 server_len = dir->do_servers.do_servers_len;
380
381 if (((flags & MASTER_ONLY) == MASTER_ONLY) && server_len > 1)
382 server_len = 1; /* The first entry is the master */
383
384 result = __do_niscall2 (server, server_len, prog, xargs, req, xres,
385 resp, flags);
e61abf83
UD
386 if (dir != NULL)
387 nis_free_directory (dir);
43b0e40f 388
e61abf83
UD
389 return result;
390}