packaging: add license files to all sub components
[platform/upstream/linaro-glibc.git] / nis / nis_callback.c
1 /* Copyright (C) 1997-2014 Free Software Foundation, Inc.
2    This file is part of the GNU C Library.
3    Contributed by Thorsten Kukuk <kukuk@suse.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 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.
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    Lesser General Public License for more details.
14
15    You should have received a copy of the GNU Lesser General Public
16    License along with the GNU C Library; if not, see
17    <http://www.gnu.org/licenses/>.  */
18
19 #include <errno.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <unistd.h>
23 #include <libintl.h>
24 #include <rpc/rpc.h>
25 #include <rpc/pmap_clnt.h>
26 #include <string.h>
27 #include <memory.h>
28 #include <syslog.h>
29 #include <sys/poll.h>
30 #include <sys/socket.h>
31 #include <netinet/in.h>
32 #include <arpa/inet.h>
33 #include <rpc/key_prot.h>
34 #include <rpcsvc/nis.h>
35 #include <rpcsvc/nis_callback.h>
36 #include <bits/libc-lock.h>
37
38 #include "nis_xdr.h"
39 #include "nis_intern.h"
40
41 /* Sorry, we are not able to make this threadsafe. Stupid. But some
42    functions doesn't send us a nis_result obj, so we don't have a
43    cookie. Maybe we could use keys for threads ? Have to learn more
44    about pthreads -- kukuk@vt.uni-paderborn.de */
45
46 static nis_cb *data;
47
48 __libc_lock_define_initialized (static, callback)
49
50
51 #if 0
52 static char *
53 __nis_getpkey(const char *sname)
54 {
55   char buf[(strlen (sname) + 1) * 2 + 40];
56   char pkey[HEXKEYBYTES + 1];
57   char *cp, *domain;
58   nis_result *res;
59   unsigned int len = 0;
60
61   domain = strchr (sname, '.');
62   if (domain == NULL)
63     return NULL;
64
65   /* Remove prefixing dot */
66   ++domain;
67
68   cp = stpcpy (buf, "[cname=");
69   cp = stpcpy (cp, sname);
70   cp = stpcpy (cp, ",auth_type=DES],cred.org_dir.");
71   cp = stpcpy (cp, domain);
72
73   res = nis_list (buf, USE_DGRAM|NO_AUTHINFO|FOLLOW_LINKS|FOLLOW_PATH,
74                   NULL, NULL);
75
76   if (res == NULL)
77     return NULL;
78
79   if (NIS_RES_STATUS (res) != NIS_SUCCESS)
80     {
81       nis_freeresult (res);
82       return NULL;
83     }
84
85   len = ENTRY_LEN(NIS_RES_OBJECT(res), 3);
86   strncpy (pkey, ENTRY_VAL(NIS_RES_OBJECT(res), 3), len);
87   pkey[len] = '\0';
88   cp = strchr (pkey, ':');
89   if (cp != NULL)
90     *cp = '\0';
91
92   nis_freeresult (res);
93
94   return strdup (pkey);
95 }
96 #endif
97
98 static void
99 cb_prog_1 (struct svc_req *rqstp, SVCXPRT *transp)
100 {
101   union
102     {
103       cback_data cbproc_receive_1_arg;
104       nis_error cbproc_error_1_arg;
105     }
106   argument;
107   char *result;
108   xdrproc_t xdr_argument, xdr_result;
109   bool_t bool_result;
110
111   switch (rqstp->rq_proc)
112     {
113     case NULLPROC:
114       svc_sendreply (transp, (xdrproc_t) xdr_void, (char *) NULL);
115       return;
116
117     case CBPROC_RECEIVE:
118       {
119         unsigned int i;
120
121         xdr_argument = (xdrproc_t) xdr_cback_data;
122         xdr_result = (xdrproc_t) xdr_bool;
123         memset (&argument, 0, sizeof (argument));
124         if (!svc_getargs (transp, xdr_argument, (caddr_t) & argument))
125           {
126             svcerr_decode (transp);
127             return;
128           }
129         bool_result = FALSE;
130         for (i = 0; i < argument.cbproc_receive_1_arg.entries.entries_len; ++i)
131           {
132 #define cbproc_entry(a) argument.cbproc_receive_1_arg.entries.entries_val[a]
133             char name[strlen (cbproc_entry(i)->zo_name) +
134                       strlen (cbproc_entry(i)->zo_domain) + 3];
135             char *cp;
136
137             cp = stpcpy (name, cbproc_entry(i)->zo_name);
138             *cp++ = '.';
139             cp = stpcpy (cp, cbproc_entry(i)->zo_domain);
140
141             if ((data->callback) (name, cbproc_entry(i), data->userdata))
142               {
143                 bool_result = TRUE;
144                 data->nomore = 1;
145                 data->result = NIS_SUCCESS;
146                 break;
147               }
148           }
149         result = (char *) &bool_result;
150       }
151       break;
152     case CBPROC_FINISH:
153       xdr_argument = (xdrproc_t) xdr_void;
154       xdr_result = (xdrproc_t) xdr_void;
155       memset (&argument, 0, sizeof (argument));
156       if (!svc_getargs (transp, xdr_argument, (caddr_t) & argument))
157         {
158           svcerr_decode (transp);
159           return;
160         }
161       data->nomore = 1;
162       data->result = NIS_SUCCESS;
163       bool_result = TRUE;       /* to make gcc happy, not necessary */
164       result = (char *) &bool_result;
165       break;
166     case CBPROC_ERROR:
167       xdr_argument = (xdrproc_t) _xdr_nis_error;
168       xdr_result = (xdrproc_t) xdr_void;
169       memset (&argument, 0, sizeof (argument));
170       if (!svc_getargs (transp, xdr_argument, (caddr_t) & argument))
171         {
172           svcerr_decode (transp);
173           return;
174         }
175       data->nomore = 1;
176       data->result = argument.cbproc_error_1_arg;
177       bool_result = TRUE;       /* to make gcc happy, not necessary */
178       result = (char *) &bool_result;
179       break;
180     default:
181       svcerr_noproc (transp);
182       return;
183     }
184   if (result != NULL && !svc_sendreply (transp, xdr_result, result))
185     svcerr_systemerr (transp);
186   if (!svc_freeargs (transp, xdr_argument, (caddr_t) & argument))
187     {
188       fputs (_ ("unable to free arguments"), stderr);
189       exit (1);
190     }
191   return;
192 }
193
194 static nis_error
195 internal_nis_do_callback (struct dir_binding *bptr, netobj *cookie,
196                           struct nis_cb *cb)
197 {
198   struct timeval TIMEOUT = {25, 0};
199   bool_t cb_is_running;
200
201   data = cb;
202
203   for (;;)
204     {
205       struct pollfd my_pollfd[svc_max_pollfd];
206       int i;
207
208       if (svc_max_pollfd == 0 && svc_pollfd == NULL)
209         return NIS_CBERROR;
210
211       for (i = 0; i < svc_max_pollfd; ++i)
212         {
213           my_pollfd[i].fd = svc_pollfd[i].fd;
214           my_pollfd[i].events = svc_pollfd[i].events;
215           my_pollfd[i].revents = 0;
216         }
217
218       switch (i = TEMP_FAILURE_RETRY (__poll (my_pollfd, svc_max_pollfd,
219                                               25*1000)))
220         {
221         case -1:
222           return NIS_CBERROR;
223         case 0:
224           /* See if callback 'thread' in the server is still alive. */
225           cb_is_running = FALSE;
226           if (clnt_call (bptr->clnt, NIS_CALLBACK, (xdrproc_t) xdr_netobj,
227                          (caddr_t) cookie, (xdrproc_t) xdr_bool,
228                          (caddr_t) &cb_is_running, TIMEOUT) != RPC_SUCCESS)
229             cb_is_running = FALSE;
230
231           if (cb_is_running == FALSE)
232             {
233               syslog (LOG_ERR, "NIS+: callback timed out");
234               return NIS_CBERROR;
235             }
236           break;
237         default:
238           svc_getreq_poll (my_pollfd, i);
239           if (data->nomore)
240             return data->result;
241         }
242     }
243 }
244
245 nis_error
246 __nis_do_callback (struct dir_binding *bptr, netobj *cookie,
247                    struct nis_cb *cb)
248 {
249   nis_error result;
250
251   __libc_lock_lock (callback);
252
253   result = internal_nis_do_callback (bptr, cookie, cb);
254
255   __libc_lock_unlock (callback);
256
257   return result;
258 }
259
260 struct nis_cb *
261 __nis_create_callback (int (*callback) (const_nis_name, const nis_object *,
262                                         const void *),
263                        const void *userdata, unsigned int flags)
264 {
265   struct nis_cb *cb;
266   int sock = RPC_ANYSOCK;
267   struct sockaddr_in sin;
268   socklen_t len = sizeof (struct sockaddr_in);
269   unsigned short port;
270   int nomsg = 0;
271
272   cb = (struct nis_cb *) calloc (1,
273                                  sizeof (struct nis_cb) + sizeof (nis_server));
274   if (__glibc_unlikely (cb == NULL))
275     goto failed;
276   cb->serv = (nis_server *) (cb + 1);
277   cb->serv->name = strdup (nis_local_principal ());
278   if (__glibc_unlikely (cb->serv->name == NULL))
279     goto failed;
280   cb->serv->ep.ep_val = (endpoint *) calloc (2, sizeof (endpoint));
281   if (__glibc_unlikely (cb->serv->ep.ep_val == NULL))
282     goto failed;
283   cb->serv->ep.ep_len = 1;
284   cb->serv->ep.ep_val[0].family = strdup ("inet");
285   if (__glibc_unlikely (cb->serv->ep.ep_val[0].family == NULL))
286     goto failed;
287   cb->callback = callback;
288   cb->userdata = userdata;
289
290   if ((flags & NO_AUTHINFO) || !key_secretkey_is_set ())
291     {
292       cb->serv->key_type = NIS_PK_NONE;
293       cb->serv->pkey.n_bytes = NULL;
294       cb->serv->pkey.n_len = 0;
295     }
296   else
297     {
298 #if 0
299       if ((cb->serv->pkey.n_bytes = __nis_getpkey (cb->serv->name)) == NULL)
300         {
301           cb->serv->pkey.n_len = 0;
302           cb->serv->key_type = NIS_PK_NONE;
303         }
304       else
305         {
306           cb->serv->key_type = NIS_PK_DH;
307           cb->serv->pkey.n_len = strlen(cb->serv->pkey.n_bytes);
308         }
309 #else
310       cb->serv->pkey.n_len =0;
311       cb->serv->pkey.n_bytes = NULL;
312       cb->serv->key_type = NIS_PK_NONE;
313 #endif
314     }
315
316   cb->serv->ep.ep_val[0].proto = strdup ((flags & USE_DGRAM) ? "udp" : "tcp");
317   if (__glibc_unlikely (cb->serv->ep.ep_val[0].proto == NULL))
318     goto failed;
319   cb->xprt = ((flags & USE_DGRAM)
320               ? svcudp_bufcreate (sock, 100, 8192)
321               : svctcp_create (sock, 100, 8192));
322   if (cb->xprt == NULL)
323     {
324       nomsg = 1;
325       goto failed;
326     }
327   cb->sock = cb->xprt->xp_sock;
328   if (!svc_register (cb->xprt, CB_PROG, CB_VERS, cb_prog_1, 0))
329     {
330       xprt_unregister (cb->xprt);
331       svc_destroy (cb->xprt);
332       xdr_free ((xdrproc_t) _xdr_nis_server, (char *) cb->serv);
333       free (cb);
334       syslog (LOG_ERR, "NIS+: failed to register callback dispatcher");
335       return NULL;
336     }
337
338   if (getsockname (cb->sock, (struct sockaddr *) &sin, &len) == -1)
339     {
340       xprt_unregister (cb->xprt);
341       svc_destroy (cb->xprt);
342       xdr_free ((xdrproc_t) _xdr_nis_server, (char *) cb->serv);
343       free (cb);
344       syslog (LOG_ERR, "NIS+: failed to read local socket info");
345       return NULL;
346     }
347   port = ntohs (sin.sin_port);
348   get_myaddress (&sin);
349
350   if (asprintf (&cb->serv->ep.ep_val[0].uaddr, "%s.%d.%d",
351                 inet_ntoa (sin.sin_addr), (port & 0xFF00) >> 8, port & 0x00FF)
352       < 0)
353     goto failed;
354
355   return cb;
356
357  failed:
358   if (cb)
359     {
360       if (cb->xprt)
361         svc_destroy (cb->xprt);
362       xdr_free ((xdrproc_t) _xdr_nis_server, (char *) cb->serv);
363       free (cb);
364     }
365   if (!nomsg)
366     syslog (LOG_ERR, "NIS+: out of memory allocating callback");
367   return NULL;
368 }
369
370 nis_error
371 __nis_destroy_callback (struct nis_cb *cb)
372 {
373   xprt_unregister (cb->xprt);
374   svc_destroy (cb->xprt);
375   close (cb->sock);
376   xdr_free ((xdrproc_t) _xdr_nis_server, (char *) cb->serv);
377   free (cb);
378
379   return NIS_SUCCESS;
380 }