amq_svc.c revision 310490
1/*
2 * Copyright (c) 1997-2014 Erez Zadok
3 * Copyright (c) 1990 Jan-Simon Pendry
4 * Copyright (c) 1990 Imperial College of Science, Technology & Medicine
5 * Copyright (c) 1990 The Regents of the University of California.
6 * All rights reserved.
7 *
8 * This code is derived from software contributed to Berkeley by
9 * Jan-Simon Pendry at Imperial College, London.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 *    notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 *    notice, this list of conditions and the following disclaimer in the
18 *    documentation and/or other materials provided with the distribution.
19 * 3. Neither the name of the University nor the names of its contributors
20 *    may be used to endorse or promote products derived from this software
21 *    without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 *
35 *
36 * File: am-utils/amd/amq_svc.c
37 *
38 */
39
40#ifdef HAVE_CONFIG_H
41# include <config.h>
42#endif /* HAVE_CONFIG_H */
43#include <am_defs.h>
44#include <amd.h>
45
46/* typedefs */
47typedef char *(*amqsvcproc_t)(voidp, struct svc_req *);
48
49#if defined(HAVE_TCPD_H) && defined(HAVE_LIBWRAP)
50# ifdef NEED_LIBWRAP_SEVERITY_VARIABLES
51/*
52 * Some systems that define libwrap already define these two variables
53 * in libwrap, while others don't: so I need to know precisely iff
54 * to define these two severity variables.
55 */
56int allow_severity=0, deny_severity=0, rfc931_timeout=0;
57# endif /* NEED_LIBWRAP_SEVERITY_VARIABLES */
58
59/*
60 * check if remote amq is authorized to access this amd.
61 * Returns: 1=allowed, 0=denied.
62 */
63static int
64amqsvc_is_client_allowed(const struct sockaddr_in *addr)
65{
66  struct request_info req;
67
68  request_init(&req, RQ_DAEMON, AMD_SERVICE_NAME, RQ_CLIENT_SIN, addr, 0);
69  sock_methods(&req);
70
71  if (hosts_access(&req))
72         return 1;
73
74  return 0;
75}
76#endif /* defined(HAVE_TCPD_H) && defined(HAVE_LIBWRAP) */
77
78
79/*
80 * Prepare the parent and child:
81 * 1) Setup IPC pipe.
82 * 2) Set signal masks.
83 * 3) Fork by calling background() so that NumChildren is updated.
84 */
85static int
86amq_fork(opaque_t argp)
87{
88#ifdef HAVE_SIGACTION
89  sigset_t new, mask;
90#else /* not HAVE_SIGACTION */
91  int mask;
92#endif /* not HAVE_SIGACTION */
93  am_node *mp;
94  pid_t pid;
95
96  mp = find_ap(*(char **) argp);
97  if (mp == NULL) {
98    errno = 0;
99    return -1;
100  }
101
102  if (pipe(mp->am_fd) == -1) {
103    mp->am_fd[0] = -1;
104    mp->am_fd[1] = -1;
105    return -1;
106  }
107
108#ifdef HAVE_SIGACTION
109  sigemptyset(&new);		/* initialize signal set we wish to block */
110  sigaddset(&new, SIGHUP);
111  sigaddset(&new, SIGINT);
112  sigaddset(&new, SIGQUIT);
113  sigaddset(&new, SIGCHLD);
114  sigprocmask(SIG_BLOCK, &new, &mask);
115#else /* not HAVE_SIGACTION */
116  mask =
117      sigmask(SIGHUP) |
118      sigmask(SIGINT) |
119      sigmask(SIGQUIT) |
120      sigmask(SIGCHLD);
121  mask = sigblock(mask);
122#endif /* not HAVE_SIGACTION */
123
124  switch ((pid = background())) {
125  case -1:	/* error */
126    dlog("amq_fork failed");
127    return -1;
128
129  case 0:	/* child */
130    close(mp->am_fd[1]);	/* close output end of pipe */
131    mp->am_fd[1] = -1;
132    return 0;
133
134  default:	/* parent */
135    close(mp->am_fd[0]);	/* close input end of pipe */
136    mp->am_fd[0] = -1;
137
138#ifdef HAVE_SIGACTION
139    sigprocmask(SIG_SETMASK, &mask, NULL);
140#else /* not HAVE_SIGACTION */
141    sigsetmask(mask);
142#endif /* not HAVE_SIGACTION */
143    return pid;
144  }
145}
146
147
148void
149amq_program_1(struct svc_req *rqstp, SVCXPRT *transp)
150{
151  union {
152    amq_string amqproc_mnttree_1_arg;
153    amq_string amqproc_umnt_1_arg;
154    amq_setopt amqproc_setopt_1_arg;
155  } argument;
156  char *result;
157  xdrproc_t xdr_argument, xdr_result;
158  amqsvcproc_t local;
159  amqsvcproc_t child;
160  amqsvcproc_t parent;
161  pid_t pid;
162
163#if defined(HAVE_TCPD_H) && defined(HAVE_LIBWRAP)
164  if (gopt.flags & CFM_USE_TCPWRAPPERS) {
165    struct sockaddr_in *remote_addr = svc_getcaller(rqstp->rq_xprt);
166    char *remote_hostname = inet_ntoa(remote_addr->sin_addr);
167
168    if (!amqsvc_is_client_allowed(remote_addr)) {
169      plog(XLOG_WARNING, "Amd denied remote amq service to %s", remote_hostname);
170      svcerr_auth(transp, AUTH_FAILED);
171      return;
172    } else {
173      dlog("Amd allowed remote amq service to %s", remote_hostname);
174    }
175  }
176#endif /* defined(HAVE_TCPD_H) && defined(HAVE_LIBWRAP) */
177
178  local = NULL;
179  child = NULL;
180  parent = NULL;
181
182  switch (rqstp->rq_proc) {
183
184  case AMQPROC_NULL:
185    xdr_argument = (xdrproc_t) xdr_void;
186    xdr_result = (xdrproc_t) xdr_void;
187    local = (amqsvcproc_t) amqproc_null_1_svc;
188    break;
189
190  case AMQPROC_MNTTREE:
191    xdr_argument = (xdrproc_t) xdr_amq_string;
192    xdr_result = (xdrproc_t) xdr_amq_mount_tree_p;
193    local = (amqsvcproc_t) amqproc_mnttree_1_svc;
194    break;
195
196  case AMQPROC_UMNT:
197    xdr_argument = (xdrproc_t) xdr_amq_string;
198    xdr_result = (xdrproc_t) xdr_void;
199    local = (amqsvcproc_t) amqproc_umnt_1_svc;
200    break;
201
202  case AMQPROC_STATS:
203    xdr_argument = (xdrproc_t) xdr_void;
204    xdr_result = (xdrproc_t) xdr_amq_mount_stats;
205    local = (amqsvcproc_t) amqproc_stats_1_svc;
206    break;
207
208  case AMQPROC_EXPORT:
209    xdr_argument = (xdrproc_t) xdr_void;
210    xdr_result = (xdrproc_t) xdr_amq_mount_tree_list;
211    local = (amqsvcproc_t) amqproc_export_1_svc;
212    break;
213
214  case AMQPROC_SETOPT:
215    xdr_argument = (xdrproc_t) xdr_amq_setopt;
216    xdr_result = (xdrproc_t) xdr_int;
217    local = (amqsvcproc_t) amqproc_setopt_1_svc;
218    break;
219
220  case AMQPROC_GETMNTFS:
221    xdr_argument = (xdrproc_t) xdr_void;
222    xdr_result = (xdrproc_t) xdr_amq_mount_info_qelem;
223    local = (amqsvcproc_t) amqproc_getmntfs_1_svc;
224    break;
225
226  case AMQPROC_GETVERS:
227    xdr_argument = (xdrproc_t) xdr_void;
228    xdr_result = (xdrproc_t) xdr_amq_string;
229    local = (amqsvcproc_t) amqproc_getvers_1_svc;
230    break;
231
232  case AMQPROC_GETPID:
233    xdr_argument = (xdrproc_t) xdr_void;
234    xdr_result = (xdrproc_t) xdr_int;
235    local = (amqsvcproc_t) amqproc_getpid_1_svc;
236    break;
237
238  case AMQPROC_PAWD:
239    xdr_argument = (xdrproc_t) xdr_amq_string;
240    xdr_result = (xdrproc_t) xdr_amq_string;
241    local = (amqsvcproc_t) amqproc_pawd_1_svc;
242    break;
243
244  case AMQPROC_SYNC_UMNT:
245    xdr_argument = (xdrproc_t) xdr_amq_string;
246    xdr_result = (xdrproc_t) xdr_amq_sync_umnt;
247    parent = (amqsvcproc_t) amqproc_sync_umnt_1_svc_parent;
248    child = (amqsvcproc_t) amqproc_sync_umnt_1_svc_child;
249    /* used if fork fails */
250    local = (amqsvcproc_t) amqproc_sync_umnt_1_svc_async;
251    break;
252
253  case AMQPROC_GETMAPINFO:
254    xdr_argument = (xdrproc_t) xdr_void;
255    xdr_result = (xdrproc_t) xdr_amq_map_info_qelem;
256    local = (amqsvcproc_t) amqproc_getmapinfo_1_svc;
257    break;
258
259  default:
260    svcerr_noproc(transp);
261    return;
262  }
263
264  memset((char *) &argument, 0, sizeof(argument));
265  if (!svc_getargs(transp,
266		   (XDRPROC_T_TYPE) xdr_argument,
267		   (SVC_IN_ARG_TYPE) & argument)) {
268    svcerr_decode(transp);
269    return;
270  }
271
272  pid = -1;
273  result = NULL;
274
275  if (child) {
276    switch ((pid = amq_fork(&argument))) {
277    case -1:	/* error */
278      break;
279
280    case 0:	/* child */
281      result = (*child) (&argument, rqstp);
282      local = NULL;
283      break;
284
285    default:	/* parent */
286      result = (*parent) (&argument, rqstp);
287      local = NULL;
288      break;
289    }
290  }
291
292  if (local)
293    result = (*local) (&argument, rqstp);
294
295  if (result != NULL && !svc_sendreply(transp,
296				       (XDRPROC_T_TYPE) xdr_result,
297				       result)) {
298    svcerr_systemerr(transp);
299  }
300
301  if (!svc_freeargs(transp,
302		    (XDRPROC_T_TYPE) xdr_argument,
303		    (SVC_IN_ARG_TYPE) & argument)) {
304    plog(XLOG_FATAL, "unable to free rpc arguments in amqprog_1");
305    going_down(1);
306  }
307
308  if (pid == 0)
309    exit(0);	/* the child is done! */
310}
311