12b3ab265ecb5807399f1e2fd020c2deb7f3f410
[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)
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)
177         {
178           fputs (_("Error: could not find a NIS_COLD_START file\n"), stderr);
179           return NIS_UNAVAIL;
180         }
181       server = dir->do_servers.do_servers_val;
182       server_len = dir->do_servers.do_servers_len;
183     }
184   else
185     {
186       server = serv;
187       server_len = serv_len;
188     }
189
190   if (((flags & MASTER_ONLY) == MASTER_ONLY) && server_len > 1)
191     server_len = 1; /* The first entry is the master */
192
193   try = 0;
194   result = NIS_NAMEUNREACHABLE;
195
196   while (try < MAXTRIES && result != RPC_SUCCESS)
197     {
198       unsigned int i;
199
200       if ((flags & HARD_LOOKUP) == 0)
201         ++try;
202
203       for (i = 0; i < server_len; i++)
204         {
205           if ((clnt = __nis_dobind (&server[i], flags)) == NULL)
206             continue;
207
208           result = clnt_call (clnt, prog, xargs, req, xres, resp, TIMEOUT);
209
210           if (result != RPC_SUCCESS)
211             {
212               clnt_perror (clnt, "do_niscall: clnt_call");
213               clnt_destroy (clnt);
214               result = NIS_RPCERROR;
215             }
216           else
217             clnt_destroy (clnt);
218         }
219     }
220
221   if (dir != NULL)
222     nis_free_directory (dir);
223   return result;
224 }