1 /* 2 * Copyright (c) 1995, 1996 3 * Bill Paul <wpaul@ctr.columbia.edu>. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by Bill Paul. 16 * 4. Neither the name of the author nor the names of any co-contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 * 32 * $Id: yppasswdd_main.c,v 1.10 1996/02/24 21:41:15 wpaul Exp $ 33 */ 34 35 #include "yppasswd.h" 36 #include <stdio.h> 37 #include <sys/types.h> 38 #include <stdlib.h> /* getenv, exit */ 39 #include <unistd.h> 40 #include <string.h> 41 #include <sys/param.h> 42 #include <rpc/pmap_clnt.h> /* for pmap_unset */ 43 #include <string.h> /* strcmp */ 44 #include <signal.h> 45 #include <fcntl.h> 46 #include <sys/ioctl.h> 47 #include <sys/stat.h> 48 #include <sys/ttycom.h> /* TIOCNOTTY */ 49 #ifdef __cplusplus 50 #include <sysent.h> /* getdtablesize, open */ 51 #endif /* __cplusplus */ 52 #include <memory.h> 53 #include <sys/socket.h> 54 #include <netinet/in.h> 55 #include <syslog.h> 56 #include <err.h> 57 #include <errno.h> 58 #include <rpcsvc/yp.h> 59 struct dom_binding {}; 60 #include <rpcsvc/ypclnt.h> 61 #include "yppasswdd_extern.h" 62 #include "yppasswd_comm.h" 63 #include "ypxfr_extern.h" 64 65 #ifndef SIG_PF 66 #define SIG_PF void(*)(int) 67 #endif 68 69 #ifdef DEBUG 70 #define RPC_SVC_FG 71 #endif 72 73 #define _RPCSVC_CLOSEDOWN 120 74 #ifndef lint 75 static const char rcsid[] = "$Id: yppasswdd_main.c,v 1.10 1996/02/24 21:41:15 wpaul Exp $"; 76 #endif /* not lint */ 77 int _rpcpmstart = 0; /* Started by a port monitor ? */ 78 static int _rpcfdtype; 79 /* Whether Stream or Datagram ? */ 80 /* States a server can be in wrt request */ 81 82 #define _IDLE 0 83 #define _SERVED 1 84 #define _SERVING 2 85 86 extern int _rpcsvcstate; /* Set when a request is serviced */ 87 char *progname = "rpc.yppasswdd"; 88 char *passfile_default = "/var/yp/master.passwd"; 89 char *passfile; 90 char *yppasswd_domain = NULL; 91 int no_chsh = 0; 92 int no_chfn = 0; 93 int allow_additions = 0; 94 int multidomain = 0; 95 int verbose = 0; 96 int resvport = 1; 97 char *yp_dir = "/var/yp/"; 98 int yp_sock; 99 100 101 static void 102 my_svc_run() 103 { 104 #ifdef FD_SETSIZE 105 fd_set readfds; 106 #else 107 int readfds; 108 #endif /* def FD_SETSIZE */ 109 extern int errno; 110 111 for (;;) { 112 113 114 #ifdef FD_SETSIZE 115 readfds = svc_fdset; 116 #else 117 readfds = svc_fds; 118 #endif /* def FD_SETSIZE */ 119 FD_SET(yp_sock, &readfds); 120 121 switch (select(_rpc_dtablesize(), &readfds, (fd_set *)0, (fd_set *)0, 122 (struct timeval *)0)) { 123 case -1: 124 if (errno == EINTR) { 125 continue; 126 } 127 perror("svc_run: - select failed"); 128 return; 129 case 0: 130 continue; 131 default: 132 if (FD_ISSET(yp_sock, &readfds)) { 133 do_master(); 134 FD_CLR(yp_sock, &readfds); 135 } 136 svc_getreqset(&readfds); 137 } 138 } 139 } 140 141 static void terminate(sig) 142 int sig; 143 { 144 svc_unregister(YPPASSWDPROG, YPPASSWDVERS); 145 close(yp_sock); 146 unlink(sockname); 147 exit(0); 148 } 149 150 static void reload(sig) 151 int sig; 152 { 153 load_securenets(); 154 } 155 156 static void 157 closedown(int sig) 158 { 159 if (_rpcsvcstate == _IDLE) { 160 extern fd_set svc_fdset; 161 static int size; 162 int i, openfd; 163 164 if (_rpcfdtype == SOCK_DGRAM) { 165 close(yp_sock); 166 unlink(sockname); 167 exit(0); 168 } 169 if (size == 0) { 170 size = getdtablesize(); 171 } 172 for (i = 0, openfd = 0; i < size && openfd < 2; i++) 173 if (FD_ISSET(i, &svc_fdset)) 174 openfd++; 175 if (openfd <= 1) { 176 close(yp_sock); 177 unlink(sockname); 178 exit(0); 179 } 180 } 181 if (_rpcsvcstate == _SERVED) 182 _rpcsvcstate = _IDLE; 183 184 (void) signal(SIGALRM, (SIG_PF) closedown); 185 (void) alarm(_RPCSVC_CLOSEDOWN/2); 186 } 187 188 static void usage() 189 { 190 fprintf(stderr, "Usage: %s [-t master.passwd file] [-d domain] \ 191 [-p path] [-s] [-f] [-m] [-a] [-v] [-u] [-h]\n", 192 progname); 193 exit(1); 194 } 195 196 main(argc, argv) 197 int argc; 198 char *argv[]; 199 { 200 register SVCXPRT *transp = NULL; 201 int sock; 202 int proto = 0; 203 struct sockaddr_in saddr; 204 int asize = sizeof (saddr); 205 int ch; 206 int rval; 207 char *mastername; 208 char myname[MAXHOSTNAMELEN + 2]; 209 extern int errno; 210 extern int debug; 211 212 debug = 1; 213 214 while ((ch = getopt(argc, argv, "t:d:p:sfamvh")) != EOF) { 215 switch(ch) { 216 case 't': 217 passfile_default = optarg; 218 break; 219 case 'd': 220 yppasswd_domain = optarg; 221 break; 222 case 's': 223 no_chsh++; 224 break; 225 case 'f': 226 no_chfn++; 227 break; 228 case 'p': 229 yp_dir = optarg; 230 break; 231 case 'a': 232 allow_additions++; 233 break; 234 case 'm': 235 multidomain++; 236 break; 237 case 'v': 238 verbose++; 239 break; 240 case 'u': 241 resvport = 0; 242 break; 243 default: 244 case 'h': 245 usage(); 246 break; 247 } 248 } 249 250 if (yppasswd_domain == NULL) { 251 if (yp_get_default_domain(&yppasswd_domain)) { 252 yp_error("no domain specified and system domain \ 253 name isn't set -- aborting"); 254 usage(); 255 } 256 } 257 258 load_securenets(); 259 260 if (getrpcport("localhost", YPPROG, YPVERS, IPPROTO_UDP) <= 0) { 261 yp_error("this host is not an NIS server -- aborting"); 262 exit(1); 263 } 264 265 if ((mastername = ypxfr_get_master(yppasswd_domain, "passwd.byname", 266 "localhost",0)) == NULL) { 267 yp_error("can't get name of NIS master server"); 268 exit(1); 269 } 270 271 if (gethostname((char *)&myname, sizeof(myname)) == -1) { 272 yp_error("can't get local hostname: %s", strerror(errno)); 273 exit(1); 274 } 275 276 if (strncmp(mastername, (char *)&myname, sizeof(myname))) { 277 yp_error("this host is not an NIS master server -- aborting"); 278 exit(1); 279 } 280 281 debug = 0; 282 283 if (getsockname(0, (struct sockaddr *)&saddr, &asize) == 0) { 284 int ssize = sizeof (int); 285 286 if (saddr.sin_family != AF_INET) 287 exit(1); 288 if (getsockopt(0, SOL_SOCKET, SO_TYPE, 289 (char *)&_rpcfdtype, &ssize) == -1) 290 exit(1); 291 sock = 0; 292 _rpcpmstart = 1; 293 proto = 0; 294 openlog(progname, LOG_PID, LOG_DAEMON); 295 } else { 296 #ifndef RPC_SVC_FG 297 int size; 298 int pid, i; 299 300 pid = fork(); 301 if (pid < 0) { 302 perror("cannot fork"); 303 exit(1); 304 } 305 if (pid) 306 exit(0); 307 size = getdtablesize(); 308 for (i = 0; i < size; i++) 309 (void) close(i); 310 i = open("/dev/console", 2); 311 (void) dup2(i, 1); 312 (void) dup2(i, 2); 313 i = open("/dev/tty", 2); 314 if (i >= 0) { 315 (void) ioctl(i, TIOCNOTTY, (char *)NULL); 316 (void) close(i); 317 } 318 openlog(progname, LOG_PID, LOG_DAEMON); 319 #endif 320 sock = RPC_ANYSOCK; 321 (void) pmap_unset(YPPASSWDPROG, YPPASSWDVERS); 322 } 323 324 if ((_rpcfdtype == 0) || (_rpcfdtype == SOCK_DGRAM)) { 325 transp = svcudp_create(sock); 326 if (transp == NULL) { 327 yp_error("cannot create udp service."); 328 exit(1); 329 } 330 if (!_rpcpmstart) 331 proto = IPPROTO_UDP; 332 if (!svc_register(transp, YPPASSWDPROG, YPPASSWDVERS, yppasswdprog_1, proto)) { 333 yp_error("unable to register (YPPASSWDPROG, YPPASSWDVERS, udp)."); 334 exit(1); 335 } 336 } 337 338 if ((_rpcfdtype == 0) || (_rpcfdtype == SOCK_STREAM)) { 339 transp = svctcp_create(sock, 0, 0); 340 if (transp == NULL) { 341 yp_error("cannot create tcp service."); 342 exit(1); 343 } 344 if (!_rpcpmstart) 345 proto = IPPROTO_TCP; 346 if (!svc_register(transp, YPPASSWDPROG, YPPASSWDVERS, yppasswdprog_1, proto)) { 347 yp_error("unable to register (YPPASSWDPROG, YPPASSWDVERS, tcp)."); 348 exit(1); 349 } 350 } 351 352 if (transp == (SVCXPRT *)NULL) { 353 yp_error("could not create a handle"); 354 exit(1); 355 } 356 if (_rpcpmstart) { 357 (void) signal(SIGALRM, (SIG_PF) closedown); 358 (void) alarm(_RPCSVC_CLOSEDOWN/2); 359 } 360 /* set up resource limits and block signals */ 361 pw_init(); 362 363 /* except SIGCHLD, which we need to catch */ 364 install_reaper(1); 365 signal(SIGTERM, (SIG_PF) terminate); 366 367 signal(SIGHUP, (SIG_PF) reload); 368 369 unlink(sockname); 370 yp_sock = makeservsock(); 371 if (chmod(sockname, 0)) 372 err(1, "chmod of %s failed", sockname); 373 374 my_svc_run(); 375 yp_error("svc_run returned"); 376 exit(1); 377 /* NOTREACHED */ 378 } 379