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.13 1996/06/23 22:24:42 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.13 1996/06/23 22:24:42 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 *yp_dir = _PATH_YP; 89 char *passfile_default = _PATH_YP "master.passwd"; 90 char *passfile; 91 char *yppasswd_domain = NULL; 92 int no_chsh = 0; 93 int no_chfn = 0; 94 int allow_additions = 0; 95 int multidomain = 0; 96 int verbose = 0; 97 int resvport = 1; 98 int inplace = 0; 99 int yp_sock; 100 101 102 static void 103 my_svc_run() 104 { 105 #ifdef FD_SETSIZE 106 fd_set readfds; 107 #else 108 int readfds; 109 #endif /* def FD_SETSIZE */ 110 extern int errno; 111 112 for (;;) { 113 114 115 #ifdef FD_SETSIZE 116 readfds = svc_fdset; 117 #else 118 readfds = svc_fds; 119 #endif /* def FD_SETSIZE */ 120 FD_SET(yp_sock, &readfds); 121 122 switch (select(_rpc_dtablesize(), &readfds, (fd_set *)0, (fd_set *)0, 123 (struct timeval *)0)) { 124 case -1: 125 if (errno == EINTR) { 126 continue; 127 } 128 perror("svc_run: - select failed"); 129 return; 130 case 0: 131 continue; 132 default: 133 if (FD_ISSET(yp_sock, &readfds)) { 134 do_master(); 135 FD_CLR(yp_sock, &readfds); 136 } 137 svc_getreqset(&readfds); 138 } 139 } 140 } 141 142 static void terminate(sig) 143 int sig; 144 { 145 svc_unregister(YPPASSWDPROG, YPPASSWDVERS); 146 close(yp_sock); 147 unlink(sockname); 148 exit(0); 149 } 150 151 static void reload(sig) 152 int sig; 153 { 154 load_securenets(); 155 } 156 157 static void 158 closedown(int sig) 159 { 160 if (_rpcsvcstate == _IDLE) { 161 extern fd_set svc_fdset; 162 static int size; 163 int i, openfd; 164 165 if (_rpcfdtype == SOCK_DGRAM) { 166 close(yp_sock); 167 unlink(sockname); 168 exit(0); 169 } 170 if (size == 0) { 171 size = getdtablesize(); 172 } 173 for (i = 0, openfd = 0; i < size && openfd < 2; i++) 174 if (FD_ISSET(i, &svc_fdset)) 175 openfd++; 176 if (openfd <= 1) { 177 close(yp_sock); 178 unlink(sockname); 179 exit(0); 180 } 181 } 182 if (_rpcsvcstate == _SERVED) 183 _rpcsvcstate = _IDLE; 184 185 (void) signal(SIGALRM, (SIG_PF) closedown); 186 (void) alarm(_RPCSVC_CLOSEDOWN/2); 187 } 188 189 static void usage() 190 { 191 fprintf(stderr, "Usage: %s [-t master.passwd file] [-d domain] \ 192 [-p path] [-s] [-f] [-m] [-i] [-a] [-v] [-u] [-h]\n", 193 progname); 194 exit(1); 195 } 196 197 main(argc, argv) 198 int argc; 199 char *argv[]; 200 { 201 register SVCXPRT *transp = NULL; 202 int sock; 203 int proto = 0; 204 struct sockaddr_in saddr; 205 int asize = sizeof (saddr); 206 int ch; 207 int rval; 208 char *mastername; 209 char myname[MAXHOSTNAMELEN + 2]; 210 extern int errno; 211 extern int debug; 212 213 debug = 1; 214 215 while ((ch = getopt(argc, argv, "t:d:p:sfamivh")) != EOF) { 216 switch(ch) { 217 case 't': 218 passfile_default = optarg; 219 break; 220 case 'd': 221 yppasswd_domain = optarg; 222 break; 223 case 's': 224 no_chsh++; 225 break; 226 case 'f': 227 no_chfn++; 228 break; 229 case 'p': 230 yp_dir = optarg; 231 break; 232 case 'a': 233 allow_additions++; 234 break; 235 case 'm': 236 multidomain++; 237 break; 238 case 'i': 239 inplace++; 240 break; 241 case 'v': 242 verbose++; 243 break; 244 case 'u': 245 resvport = 0; 246 break; 247 default: 248 case 'h': 249 usage(); 250 break; 251 } 252 } 253 254 if (yppasswd_domain == NULL) { 255 if (yp_get_default_domain(&yppasswd_domain)) { 256 yp_error("no domain specified and system domain \ 257 name isn't set -- aborting"); 258 usage(); 259 } 260 } 261 262 load_securenets(); 263 264 if (getrpcport("localhost", YPPROG, YPVERS, IPPROTO_UDP) <= 0) { 265 yp_error("this host is not an NIS server -- aborting"); 266 exit(1); 267 } 268 269 if ((mastername = ypxfr_get_master(yppasswd_domain, "passwd.byname", 270 "localhost",0)) == NULL) { 271 yp_error("can't get name of NIS master server"); 272 exit(1); 273 } 274 275 if (gethostname((char *)&myname, sizeof(myname)) == -1) { 276 yp_error("can't get local hostname: %s", strerror(errno)); 277 exit(1); 278 } 279 280 if (strncmp(mastername, (char *)&myname, sizeof(myname))) { 281 yp_error("this host is not an NIS master server -- aborting"); 282 exit(1); 283 } 284 285 debug = 0; 286 287 if (getsockname(0, (struct sockaddr *)&saddr, &asize) == 0) { 288 int ssize = sizeof (int); 289 290 if (saddr.sin_family != AF_INET) 291 exit(1); 292 if (getsockopt(0, SOL_SOCKET, SO_TYPE, 293 (char *)&_rpcfdtype, &ssize) == -1) 294 exit(1); 295 sock = 0; 296 _rpcpmstart = 1; 297 proto = 0; 298 openlog(progname, LOG_PID, LOG_DAEMON); 299 } else { 300 #ifndef RPC_SVC_FG 301 int size; 302 int pid, i; 303 304 pid = fork(); 305 if (pid < 0) { 306 perror("cannot fork"); 307 exit(1); 308 } 309 if (pid) 310 exit(0); 311 size = getdtablesize(); 312 for (i = 0; i < size; i++) 313 (void) close(i); 314 i = open("/dev/console", 2); 315 (void) dup2(i, 1); 316 (void) dup2(i, 2); 317 i = open("/dev/tty", 2); 318 if (i >= 0) { 319 (void) ioctl(i, TIOCNOTTY, (char *)NULL); 320 (void) close(i); 321 } 322 openlog(progname, LOG_PID, LOG_DAEMON); 323 #endif 324 sock = RPC_ANYSOCK; 325 (void) pmap_unset(YPPASSWDPROG, YPPASSWDVERS); 326 } 327 328 if ((_rpcfdtype == 0) || (_rpcfdtype == SOCK_DGRAM)) { 329 transp = svcudp_create(sock); 330 if (transp == NULL) { 331 yp_error("cannot create udp service."); 332 exit(1); 333 } 334 if (!_rpcpmstart) 335 proto = IPPROTO_UDP; 336 if (!svc_register(transp, YPPASSWDPROG, YPPASSWDVERS, yppasswdprog_1, proto)) { 337 yp_error("unable to register (YPPASSWDPROG, YPPASSWDVERS, udp)."); 338 exit(1); 339 } 340 } 341 342 if ((_rpcfdtype == 0) || (_rpcfdtype == SOCK_STREAM)) { 343 transp = svctcp_create(sock, 0, 0); 344 if (transp == NULL) { 345 yp_error("cannot create tcp service."); 346 exit(1); 347 } 348 if (!_rpcpmstart) 349 proto = IPPROTO_TCP; 350 if (!svc_register(transp, YPPASSWDPROG, YPPASSWDVERS, yppasswdprog_1, proto)) { 351 yp_error("unable to register (YPPASSWDPROG, YPPASSWDVERS, tcp)."); 352 exit(1); 353 } 354 } 355 356 if (transp == (SVCXPRT *)NULL) { 357 yp_error("could not create a handle"); 358 exit(1); 359 } 360 if (_rpcpmstart) { 361 (void) signal(SIGALRM, (SIG_PF) closedown); 362 (void) alarm(_RPCSVC_CLOSEDOWN/2); 363 } 364 /* set up resource limits and block signals */ 365 pw_init(); 366 367 /* except SIGCHLD, which we need to catch */ 368 install_reaper(1); 369 signal(SIGTERM, (SIG_PF) terminate); 370 371 signal(SIGHUP, (SIG_PF) reload); 372 373 unlink(sockname); 374 yp_sock = makeservsock(); 375 if (chmod(sockname, 0)) 376 err(1, "chmod of %s failed", sockname); 377 378 my_svc_run(); 379 yp_error("svc_run returned"); 380 exit(1); 381 /* NOTREACHED */ 382 } 383