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