1 /* Copyright (C) 1997,1998,1999,2000,2005,2006 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
3 Contributed by Thorsten Kukuk <kukuk@suse.de>, 1997.
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.
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.
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, write to the Free
17 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
26 #include <rpc/pmap_clnt.h>
31 #include <sys/socket.h>
32 #include <netinet/in.h>
33 #include <arpa/inet.h>
34 #include <rpc/key_prot.h>
35 #include <rpcsvc/nis.h>
36 #include <rpcsvc/nis_callback.h>
37 #include <bits/libc-lock.h>
40 #include "nis_intern.h"
42 /* Sorry, we are not able to make this threadsafe. Stupid. But some
43 functions doesn't send us a nis_result obj, so we don't have a
44 cookie. Maybe we could use keys for threads ? Have to learn more
45 about pthreads -- kukuk@vt.uni-paderborn.de */
49 __libc_lock_define_initialized (static, callback
)
54 __nis_getpkey(const char *sname
)
56 char buf
[(strlen (sname
) + 1) * 2 + 40];
57 char pkey
[HEXKEYBYTES
+ 1];
62 domain
= strchr (sname
, '.');
66 /* Remove prefixing dot */
69 cp
= stpcpy (buf
, "[cname=");
70 cp
= stpcpy (cp
, sname
);
71 cp
= stpcpy (cp
, ",auth_type=DES],cred.org_dir.");
72 cp
= stpcpy (cp
, domain
);
74 res
= nis_list (buf
, USE_DGRAM
|NO_AUTHINFO
|FOLLOW_LINKS
|FOLLOW_PATH
,
80 if (NIS_RES_STATUS (res
) != NIS_SUCCESS
)
86 len
= ENTRY_LEN(NIS_RES_OBJECT(res
), 3);
87 strncpy (pkey
, ENTRY_VAL(NIS_RES_OBJECT(res
), 3), len
);
89 cp
= strchr (pkey
, ':');
100 cb_prog_1 (struct svc_req
*rqstp
, SVCXPRT
*transp
)
104 cback_data cbproc_receive_1_arg
;
105 nis_error cbproc_error_1_arg
;
109 xdrproc_t xdr_argument
, xdr_result
;
112 switch (rqstp
->rq_proc
)
115 svc_sendreply (transp
, (xdrproc_t
) xdr_void
, (char *) NULL
);
122 xdr_argument
= (xdrproc_t
) xdr_cback_data
;
123 xdr_result
= (xdrproc_t
) xdr_bool
;
124 memset (&argument
, 0, sizeof (argument
));
125 if (!svc_getargs (transp
, xdr_argument
, (caddr_t
) & argument
))
127 svcerr_decode (transp
);
131 for (i
= 0; i
< argument
.cbproc_receive_1_arg
.entries
.entries_len
; ++i
)
133 #define cbproc_entry(a) argument.cbproc_receive_1_arg.entries.entries_val[a]
134 char name
[strlen (cbproc_entry(i
)->zo_name
) +
135 strlen (cbproc_entry(i
)->zo_domain
) + 3];
138 cp
= stpcpy (name
, cbproc_entry(i
)->zo_name
);
140 cp
= stpcpy (cp
, cbproc_entry(i
)->zo_domain
);
142 if ((data
->callback
) (name
, cbproc_entry(i
), data
->userdata
))
146 data
->result
= NIS_SUCCESS
;
150 result
= (char *) &bool_result
;
154 xdr_argument
= (xdrproc_t
) xdr_void
;
155 xdr_result
= (xdrproc_t
) xdr_void
;
156 memset (&argument
, 0, sizeof (argument
));
157 if (!svc_getargs (transp
, xdr_argument
, (caddr_t
) & argument
))
159 svcerr_decode (transp
);
163 data
->result
= NIS_SUCCESS
;
164 bool_result
= TRUE
; /* to make gcc happy, not necessary */
165 result
= (char *) &bool_result
;
168 xdr_argument
= (xdrproc_t
) _xdr_nis_error
;
169 xdr_result
= (xdrproc_t
) xdr_void
;
170 memset (&argument
, 0, sizeof (argument
));
171 if (!svc_getargs (transp
, xdr_argument
, (caddr_t
) & argument
))
173 svcerr_decode (transp
);
177 data
->result
= argument
.cbproc_error_1_arg
;
178 bool_result
= TRUE
; /* to make gcc happy, not necessary */
179 result
= (char *) &bool_result
;
182 svcerr_noproc (transp
);
185 if (result
!= NULL
&& !svc_sendreply (transp
, xdr_result
, result
))
186 svcerr_systemerr (transp
);
187 if (!svc_freeargs (transp
, xdr_argument
, (caddr_t
) & argument
))
189 fputs (_ ("unable to free arguments"), stderr
);
196 internal_nis_do_callback (struct dir_binding
*bptr
, netobj
*cookie
,
199 struct timeval TIMEOUT
= {25, 0};
200 bool_t cb_is_running
= FALSE
;
206 struct pollfd
*my_pollfd
;
209 if (svc_max_pollfd
== 0 && svc_pollfd
== NULL
)
212 my_pollfd
= malloc (sizeof (struct pollfd
) * svc_max_pollfd
);
213 if (__builtin_expect (my_pollfd
== NULL
, 0))
216 for (i
= 0; i
< svc_max_pollfd
; ++i
)
218 my_pollfd
[i
].fd
= svc_pollfd
[i
].fd
;
219 my_pollfd
[i
].events
= svc_pollfd
[i
].events
;
220 my_pollfd
[i
].revents
= 0;
223 switch (i
= __poll (my_pollfd
, svc_max_pollfd
, 25*1000))
232 /* See if callback 'thread' in the server is still alive. */
233 memset ((char *) &cb_is_running
, 0, sizeof (cb_is_running
));
234 if (clnt_call (bptr
->clnt
, NIS_CALLBACK
, (xdrproc_t
) xdr_netobj
,
235 (caddr_t
) cookie
, (xdrproc_t
) xdr_bool
,
236 (caddr_t
) & cb_is_running
, TIMEOUT
) != RPC_SUCCESS
)
237 cb_is_running
= FALSE
;
239 if (cb_is_running
== FALSE
)
241 syslog (LOG_ERR
, "NIS+: callback timed out");
246 svc_getreq_poll (my_pollfd
, i
);
255 __nis_do_callback (struct dir_binding
*bptr
, netobj
*cookie
,
260 __libc_lock_lock (callback
);
262 result
= internal_nis_do_callback (bptr
, cookie
, cb
);
264 __libc_lock_unlock (callback
);
270 __nis_create_callback (int (*callback
) (const_nis_name
, const nis_object
*,
272 const void *userdata
, unsigned int flags
)
275 int sock
= RPC_ANYSOCK
;
276 struct sockaddr_in sin
;
277 socklen_t len
= sizeof (struct sockaddr_in
);
281 cb
= (struct nis_cb
*) calloc (1,
282 sizeof (struct nis_cb
) + sizeof (nis_server
));
283 if (__builtin_expect (cb
== NULL
, 0))
285 cb
->serv
= (nis_server
*) (cb
+ 1);
286 cb
->serv
->name
= strdup (nis_local_principal ());
287 if (__builtin_expect (cb
->serv
->name
== NULL
, 0))
289 cb
->serv
->ep
.ep_val
= (endpoint
*) calloc (2, sizeof (endpoint
));
290 if (__builtin_expect (cb
->serv
->ep
.ep_val
== NULL
, 0))
292 cb
->serv
->ep
.ep_len
= 1;
293 cb
->serv
->ep
.ep_val
[0].family
= strdup ("inet");
294 if (__builtin_expect (cb
->serv
->ep
.ep_val
[0].family
== NULL
, 0))
296 cb
->callback
= callback
;
297 cb
->userdata
= userdata
;
299 if ((flags
& NO_AUTHINFO
) || !key_secretkey_is_set ())
301 cb
->serv
->key_type
= NIS_PK_NONE
;
302 cb
->serv
->pkey
.n_bytes
= NULL
;
303 cb
->serv
->pkey
.n_len
= 0;
308 if ((cb
->serv
->pkey
.n_bytes
= __nis_getpkey (cb
->serv
->name
)) == NULL
)
310 cb
->serv
->pkey
.n_len
= 0;
311 cb
->serv
->key_type
= NIS_PK_NONE
;
315 cb
->serv
->key_type
= NIS_PK_DH
;
316 cb
->serv
->pkey
.n_len
= strlen(cb
->serv
->pkey
.n_bytes
);
319 cb
->serv
->pkey
.n_len
=0;
320 cb
->serv
->pkey
.n_bytes
= NULL
;
321 cb
->serv
->key_type
= NIS_PK_NONE
;
325 cb
->serv
->ep
.ep_val
[0].proto
= strdup ((flags
& USE_DGRAM
) ? "udp" : "tcp");
326 if (__builtin_expect (cb
->serv
->ep
.ep_val
[0].proto
== NULL
, 0))
328 cb
->xprt
= ((flags
& USE_DGRAM
)
329 ? svcudp_bufcreate (sock
, 100, 8192)
330 : svctcp_create (sock
, 100, 8192));
331 if (cb
->xprt
== NULL
)
336 cb
->sock
= cb
->xprt
->xp_sock
;
337 if (!svc_register (cb
->xprt
, CB_PROG
, CB_VERS
, cb_prog_1
, 0))
339 xprt_unregister (cb
->xprt
);
340 svc_destroy (cb
->xprt
);
341 xdr_free ((xdrproc_t
) _xdr_nis_server
, (char *) cb
->serv
);
343 syslog (LOG_ERR
, "NIS+: failed to register callback dispatcher");
347 if (getsockname (cb
->sock
, (struct sockaddr
*) &sin
, &len
) == -1)
349 xprt_unregister (cb
->xprt
);
350 svc_destroy (cb
->xprt
);
351 xdr_free ((xdrproc_t
) _xdr_nis_server
, (char *) cb
->serv
);
353 syslog (LOG_ERR
, "NIS+: failed to read local socket info");
356 port
= ntohs (sin
.sin_port
);
357 get_myaddress (&sin
);
359 if (asprintf (&cb
->serv
->ep
.ep_val
[0].uaddr
, "%s.%d.%d",
360 inet_ntoa (sin
.sin_addr
), (port
& 0xFF00) >> 8, port
& 0x00FF)
370 svc_destroy (cb
->xprt
);
372 xdr_free ((xdrproc_t
) _xdr_nis_server
, (char *) cb
->serv
);
376 syslog (LOG_ERR
, "NIS+: out of memory allocating callback");
381 __nis_destroy_callback (struct nis_cb
*cb
)
383 xprt_unregister (cb
->xprt
);
384 svc_destroy (cb
->xprt
);
386 xdr_free ((xdrproc_t
) _xdr_nis_server
, (char *) cb
->serv
);