a92f1445f46f6baf99233da854e804e7e27729f0
[kopensolaris-gnu/glibc.git] / nis / nis_call.c
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
29 static struct timeval TIMEOUT = {25, 0};
30 static int const MAXTRIES = 3;
31
32 static unsigned long
33 inetstr2int (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
56 static 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;
63
64   memset (&clnt_saddr, '\0', sizeof clnt_saddr);
65   clnt_saddr.sin_family = AF_INET;
66   for (i = 0; i < server->ep.ep_len; i++)
67     {
68       if (strcmp (server->ep.ep_val[i].family,"loopback") == 0)
69         {
70           if (server->ep.ep_val[i].uaddr[i] == '-')
71             clnt_saddr.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
72           else
73             if (strcmp (server->ep.ep_val[i].proto,"udp") == 0)
74               {
75                 if ((flags & USE_DGRAM) == USE_DGRAM)
76                   clnt_saddr.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
77                 else
78                   continue;
79               }
80             else
81               if (strcmp (server->ep.ep_val[i].proto,"tcp") == 0)
82                 {
83                   if ((flags & USE_DGRAM) == USE_DGRAM)
84                     continue;
85                   else
86                     clnt_saddr.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
87                 }
88         }
89       else
90         if (strcmp (server->ep.ep_val[i].family,"inet") == 0)
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
96               if (strcmp (server->ep.ep_val[i].proto,"udp") == 0)
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
105                 if (strcmp (server->ep.ep_val[i].proto,"tcp") == 0)
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;
116
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);
124
125       if (client == NULL)
126         continue;
127       if (clnt_call (client, 0, (xdrproc_t) xdr_void, NULL,
128                      (xdrproc_t) xdr_void, NULL, TIMEOUT) != RPC_SUCCESS)
129         {
130           clnt_destroy (client);
131           continue;
132         }
133
134       if ((flags & NO_AUTHINFO) != NO_AUTHINFO)
135         {
136 #if defined(HAVE_SECURE_RPC)
137           if (server->key_type == NIS_PK_DH && getenv ("NO_SECURE_RPC") == NULL)
138             {
139               char netname[MAXNETNAMELEN+1];
140               char *p;
141
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
153 #endif
154             client->cl_auth = authunix_create_default ();
155         }
156       return client;
157     }
158
159   return NULL;
160 }
161
162 nis_error
163 __do_niscall (const nis_server *serv, int serv_len, u_long prog,
164               xdrproc_t xargs, caddr_t req, xdrproc_t xres, caddr_t resp,
165               u_long flags)
166 {
167   CLIENT *clnt;
168   directory_obj *dir = NULL;
169   const nis_server *server;
170   int try, result;
171   unsigned int server_len;
172
173   if (serv == NULL || serv_len == 0)
174     {
175       dir = readColdStartFile ();
176       if (dir == NULL) /* No /var/nis/NIS_COLD_START -> no NIS+ installed */
177         return NIS_UNAVAIL;
178       server = dir->do_servers.do_servers_val;
179       server_len = dir->do_servers.do_servers_len;
180     }
181   else
182     {
183       server = serv;
184       server_len = serv_len;
185     }
186
187   if (((flags & MASTER_ONLY) == MASTER_ONLY) && server_len > 1)
188     server_len = 1; /* The first entry is the master */
189
190   try = 0;
191   result = NIS_NAMEUNREACHABLE;
192
193   while (try < MAXTRIES && result != RPC_SUCCESS)
194     {
195       unsigned int i;
196
197       if ((flags & HARD_LOOKUP) == 0)
198         ++try;
199
200       for (i = 0; i < server_len; i++)
201         {
202           if ((clnt = __nis_dobind (&server[i], flags)) == NULL)
203             continue;
204
205           result = clnt_call (clnt, prog, xargs, req, xres, resp, TIMEOUT);
206
207           if (result != RPC_SUCCESS)
208             {
209               clnt_perror (clnt, "do_niscall: clnt_call");
210               clnt_destroy (clnt);
211               result = NIS_RPCERROR;
212             }
213           else
214             clnt_destroy (clnt);
215         }
216     }
217
218   if (dir != NULL)
219     nis_free_directory (dir);
220   return result;
221 }