Beispiel #1
0
int
main(int argc, char **argv)
{
	extern char *optarg;
	char *proxystr = NULL;
	char *proxyhost, *proxyport;
	int rc, err_code;
	int sval;
	int sockfd;
	int pipefd = -1;
	int sleeptime = 0;
	boolean_t quit = B_FALSE;
	struct addrinfo hints;
	struct addrinfo *ai = NULL;
	sigset_t main_ss;

	while ((rc = getopt(argc, argv, "s:")) != -1) {
		switch (rc) {
		case 's':
			proxystr = optarg;
			break;
		case ':':
			(void) fprintf(stderr, "Option -%c requires operand\n",
			    optopt);
			usage();
			break;
		case '?':
			(void) fprintf(stderr, "Unrecognized option -%c\n",
			    optopt);
			usage();
			break;
		default:
			break;
		}
	}

	if (proxystr == NULL) {
		usage();
	}

	proxyhost = strtok(proxystr, ":");
	if (proxyhost == NULL) {
		(void) fprintf(stderr,
		    "host must be of format hostname:port\n");
		usage();
	}
	proxyport = strtok(NULL, ":");
	if (proxyport == NULL) {
		(void) fprintf(stderr,
		    "host must be of format hostname:port\n");
		usage();
	}

	(void) signal(SIGPIPE, SIG_IGN);

	if (daemonize_start() < 0) {
		(void) fprintf(stderr, "Unable to start daemon\n");
		exit(EXIT_FAILURE);
	}

	/*
	 * Before doing anything else, check to see if it's possible to reach
	 * the proxyd.  If not, sit in a loop waiting for a period of time.
	 * If the proxyd doesn't come on-line after waiting, return an error
	 * code that tells smf to enter this service into maintenance mode.
	 */
	while ((rc = zp_ping_proxy()) < -1) {
		(void) sleep(SLEEP_INTERVAL);
		sleeptime += SLEEP_INTERVAL;
		if (sleeptime >= SLEEP_DURATION)
			break;
	}

	if (rc == -2) {
		/* never successfully reached proxy */
		(void) fprintf(stderr, "Timed out trying to reach proxy\n");
		exit(SMF_EXIT_ERR_FATAL);
	} else if (rc == -1) {
		/* got some other error */
		exit(EXIT_FAILURE);
	}

	(void) memset(&hints, 0, sizeof (struct addrinfo));
	hints.ai_flags = AI_ALL;
	hints.ai_family = PF_UNSPEC;
	hints.ai_socktype = SOCK_STREAM;

	if ((err_code = getaddrinfo(proxyhost, proxyport, &hints, &ai))
	    != 0) {
		(void) fprintf(stderr, "Unable to perform name lookup\n");
		(void) fprintf(stderr, "%s: %s\n", proxyhost,
		    gai_strerror(err_code));
		exit(EXIT_FAILURE);
	}

	if ((sockfd = socket(ai->ai_family, SOCK_STREAM, 0)) < 0) {
		perror("socket");
		exit(EXIT_FAILURE);
	}

	sval = 1;
	if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (char *)&sval,
	    sizeof (sval)) < 0) {
		perror("setsocketopt");
		exit(EXIT_FAILURE);
	}

	if (bind(sockfd, (struct sockaddr *)ai->ai_addr, ai->ai_addrlen) < 0) {
		if (errno != EADDRINUSE) {
			perror("bind");
			exit(EXIT_FAILURE);
		}
		/*
		 * If the socket is in use, call zoneproxyd and
		 * ask it to un-register the current socket.  Then
		 * try again.
		 */

		if (zp_unregister_zone() < 0) {
			exit(EXIT_FAILURE);
		}

		if (bind(sockfd, (struct sockaddr *)ai->ai_addr,
		    ai->ai_addrlen) < 0) {
			perror("bind");
			exit(EXIT_FAILURE);
		}

	}

	if (listen(sockfd, 5) < 0) {
		perror("listen");
		exit(EXIT_FAILURE);
	}

	if (zp_register_socket(sockfd, &pipefd) < 0) {
		exit(EXIT_FAILURE);
	}

	/*
	 * At this point, the proxyd has a copy of the socket and will answer
	 * all incoming connection requests.  Close our refernce to the socket
	 * here.
	 */
	(void) close(sockfd);
	freeaddrinfo(ai);

	daemonize_ready(0);

	(void) sigfillset(&main_ss);

	if (thr_sigsetmask(SIG_BLOCK, &main_ss, NULL) < 0) {
		perror("thr_sigsetmask");
		exit(EXIT_FAILURE);
	}

	/* create signal handling thread */
	if (thr_create(NULL, 0, (void *(*)(void *))s_handler, NULL,
	    THR_BOUND, NULL) < 0) {
		perror("thr_create");
		exit(EXIT_FAILURE);
	}

	drop_privs();

	/* Wait for signal to quit */
	while (quit == B_FALSE) {
		struct pollfd pfd[1];
		boolean_t unexpected = B_FALSE;
		char value;

		/*
		 * Pipe to proxyd notfies client when to quit.  If the proxy
		 * writes a byte to the pipe, or the pipe is closed
		 * unexpectedly, POLLIN will be true, telling us to exit.
		 */
		pfd[0].fd = pipefd;
		pfd[0].events = POLLIN;

		if (poll(pfd, 1, INFTIM) < 0) {
			if (errno == EINTR) {
				continue;
			}
			perror("poll");
			exit(EXIT_FAILURE);
		}

		if (pfd[0].revents & POLLIN) {
			rc = read(pipefd, &value, 1);
			if (rc < 0) {
				perror("read");
				exit(EXIT_FAILURE);
			}
			quit = B_TRUE;
			if (rc == 0)
				unexpected = B_TRUE;
		} else if (pfd[0].revents & (POLLERR | POLLHUP | POLLNVAL)) {
			quit = B_TRUE;
			unexpected = B_TRUE;
		}

		if (quit && unexpected) {
			exit(EXIT_DAEMON_TERM);
		}

	}

	return (0);
}
Beispiel #2
0
/* the main program... */
int main(int argc, char *argv[])
{
  int i;
  sigset_t signalmask, oldmask;
#ifdef HAVE_PTHREAD_TIMEDJOIN_NP
  struct timespec ts;
#endif /* HAVE_PTHREAD_TIMEDJOIN_NP */
  /* block all these signals so our worker threads won't handle them */
  sigemptyset(&signalmask);
  sigaddset(&signalmask, SIGHUP);
  sigaddset(&signalmask, SIGINT);
  sigaddset(&signalmask, SIGQUIT);
  sigaddset(&signalmask, SIGABRT);
  sigaddset(&signalmask, SIGPIPE);
  sigaddset(&signalmask, SIGTERM);
  sigaddset(&signalmask, SIGUSR1);
  sigaddset(&signalmask, SIGUSR2);
  pthread_sigmask(SIG_BLOCK, &signalmask, &oldmask);
  /* close all file descriptors (except stdin/out/err) */
  daemonize_closefds();
  /* parse the command line */
  parse_cmdline(argc, argv);
  /* clean the environment */
#ifdef HAVE_CLEARENV
  if (clearenv() || putenv("HOME=/") || putenv("TMPDIR=/tmp") ||
      putenv("LDAPNOINIT=1"))
  {
    log_log(LOG_ERR, "clearing environment failed");
    exit(EXIT_FAILURE);
  }
#else /* not HAVE_CLEARENV */
  /* this is a bit ugly */
  environ = sane_environment;
#endif /* not HAVE_CLEARENV */
  /* disable the nss_ldap module for this process */
  disable_nss_ldap();
  /* set LDAP log level */
  if (myldap_set_debuglevel(nslcd_debugging) != LDAP_SUCCESS)
    exit(EXIT_FAILURE);
  /* read configuration file */
  cfg_init(NSLCD_CONF_PATH);
  /* set default mode for pidfile and socket */
  (void)umask((mode_t)0022);
  /* see if someone already locked the pidfile
     if --check option was given exit TRUE if daemon runs
     (pidfile locked), FALSE otherwise */
  if (nslcd_checkonly)
  {
    if (is_locked(NSLCD_PIDFILE))
    {
      log_log(LOG_DEBUG, "pidfile (%s) is locked", NSLCD_PIDFILE);
      exit(EXIT_SUCCESS);
    }
    else
    {
      log_log(LOG_DEBUG, "pidfile (%s) is not locked", NSLCD_PIDFILE);
      exit(EXIT_FAILURE);
    }
  }
  /* change directory */
  if (chdir("/") != 0)
  {
    log_log(LOG_ERR, "chdir failed: %s", strerror(errno));
    exit(EXIT_FAILURE);
  }
  /* normal check for pidfile locked */
  if (is_locked(NSLCD_PIDFILE))
  {
    log_log(LOG_ERR, "nslcd may already be active, cannot acquire lock (%s): %s",
            NSLCD_PIDFILE, strerror(errno));
    exit(EXIT_FAILURE);
  }
  /* daemonize */
  if ((!nslcd_debugging) && (!nslcd_nofork))
  {
    errno = 0;
    if (daemonize_daemon() != 0)
    {
      log_log(LOG_ERR, "unable to daemonize: %s", strerror(errno));
      exit(EXIT_FAILURE);
    }
  }
  /* intilialize logging */
  if (!nslcd_debugging)
  {
    daemonize_redirect_stdio();
    log_startlogging();
  }
  /* write pidfile */
  create_pidfile(NSLCD_PIDFILE);
  /* log start */
  log_log(LOG_INFO, "version %s starting", VERSION);
  /* install handler to close stuff off on exit and log notice */
  if (atexit(exithandler))
  {
    log_log(LOG_ERR, "atexit() failed: %s", strerror(errno));
    daemonize_ready(EXIT_FAILURE, "atexit() failed\n");
    exit(EXIT_FAILURE);
  }
  adjust_oom_score();
  /* create socket */
  nslcd_serversocket = create_socket(NSLCD_SOCKET);
  /* start subprocess to do invalidating if reconnect_invalidate is set */
  for (i = 0; i < LM_NONE; i++)
    if (nslcd_cfg->reconnect_invalidate[i])
      break;
  if (i < LM_NONE)
    invalidator_start();
  /* change nslcd group and supplemental groups */
  if ((nslcd_cfg->gid != NOGID) && (nslcd_cfg->uidname != NULL))
  {
#ifdef HAVE_INITGROUPS
    /* load supplementary groups */
    if (initgroups(nslcd_cfg->uidname, nslcd_cfg->gid) < 0)
      log_log(LOG_WARNING, "cannot initgroups(\"%s\",%lu) (ignored): %s",
              nslcd_cfg->uidname, (unsigned long int)nslcd_cfg->gid, strerror(errno));
    else
      log_log(LOG_DEBUG, "initgroups(\"%s\",%lu) done",
              nslcd_cfg->uidname, (unsigned long int)nslcd_cfg->gid);
#else /* not HAVE_INITGROUPS */
#ifdef HAVE_SETGROUPS
    /* just drop all supplemental groups */
    if (setgroups(0, NULL) < 0)
      log_log(LOG_WARNING, "cannot setgroups(0,NULL) (ignored): %s",
              strerror(errno));
    else
      log_log(LOG_DEBUG, "setgroups(0,NULL) done");
#else /* not HAVE_SETGROUPS */
    log_log(LOG_DEBUG, "neither initgroups() or setgroups() available");
#endif /* not HAVE_SETGROUPS */
#endif /* not HAVE_INITGROUPS */
  }
  /* change to nslcd gid */
  if (nslcd_cfg->gid != NOGID)
  {
    if (setgid(nslcd_cfg->gid) != 0)
    {
      log_log(LOG_ERR, "cannot setgid(%lu): %s",
              (unsigned long int)nslcd_cfg->gid, strerror(errno));
      daemonize_ready(EXIT_FAILURE, "cannot setgid()\n");
      exit(EXIT_FAILURE);
    }
    log_log(LOG_DEBUG, "setgid(%lu) done", (unsigned long int)nslcd_cfg->gid);
  }
  /* change to nslcd uid */
  if (nslcd_cfg->uid != NOUID)
  {
    if (setuid(nslcd_cfg->uid) != 0)
    {
      log_log(LOG_ERR, "cannot setuid(%lu): %s",
              (unsigned long int)nslcd_cfg->uid, strerror(errno));
      daemonize_ready(EXIT_FAILURE, "cannot setuid()\n");
      exit(EXIT_FAILURE);
    }
    log_log(LOG_DEBUG, "setuid(%lu) done", (unsigned long int)nslcd_cfg->uid);
  }
  /* start worker threads */
  log_log(LOG_INFO, "accepting connections");
  nslcd_threads = (pthread_t *)malloc(nslcd_cfg->threads * sizeof(pthread_t));
  if (nslcd_threads == NULL)
  {
    log_log(LOG_CRIT, "main(): malloc() failed to allocate memory");
    daemonize_ready(EXIT_FAILURE, "malloc() failed to allocate memory\n");
    exit(EXIT_FAILURE);
  }
  for (i = 0; i < nslcd_cfg->threads; i++)
  {
    if (pthread_create(&nslcd_threads[i], NULL, worker, NULL))
    {
      log_log(LOG_ERR, "unable to start worker thread %d: %s",
              i, strerror(errno));
      daemonize_ready(EXIT_FAILURE, "unable to start worker thread\n");
      exit(EXIT_FAILURE);
    }
  }
  /* install signal handlers for some signals */
  install_sighandler(SIGHUP, sig_handler);
  install_sighandler(SIGINT, sig_handler);
  install_sighandler(SIGQUIT, sig_handler);
  install_sighandler(SIGABRT, sig_handler);
  install_sighandler(SIGPIPE, SIG_IGN);
  install_sighandler(SIGTERM, sig_handler);
  install_sighandler(SIGUSR1, sig_handler);
  install_sighandler(SIGUSR2, SIG_IGN);
  /* signal the starting process to exit because we can provide services now */
  daemonize_ready(EXIT_SUCCESS, NULL);
  /* enable receiving of signals */
  pthread_sigmask(SIG_SETMASK, &oldmask, NULL);
  /* wait until we received a signal */
  while ((nslcd_receivedsignal == 0) || (nslcd_receivedsignal == SIGUSR1))
  {
    sleep(INT_MAX); /* sleep as long as we can or until we receive a signal */
    if (nslcd_receivedsignal == SIGUSR1)
    {
      log_log(LOG_INFO, "caught signal %s (%d), refresh retries",
              signame(nslcd_receivedsignal), nslcd_receivedsignal);
      myldap_immediate_reconnect();
      nslcd_receivedsignal = 0;
    }
  }
  /* print something about received signal */
  log_log(LOG_INFO, "caught signal %s (%d), shutting down",
          signame(nslcd_receivedsignal), nslcd_receivedsignal);
  /* cancel all running threads */
  for (i = 0; i < nslcd_cfg->threads; i++)
    if (pthread_cancel(nslcd_threads[i]))
      log_log(LOG_WARNING, "failed to stop thread %d (ignored): %s",
              i, strerror(errno));
  /* close server socket to trigger failures in threads waiting on accept() */
  close(nslcd_serversocket);
  nslcd_serversocket = -1;
  /* if we can, wait a few seconds for the threads to finish */
#ifdef HAVE_PTHREAD_TIMEDJOIN_NP
  ts.tv_sec = time(NULL) + 3;
  ts.tv_nsec = 0;
#endif /* HAVE_PTHREAD_TIMEDJOIN_NP */
  for (i = 0; i < nslcd_cfg->threads; i++)
  {
#ifdef HAVE_PTHREAD_TIMEDJOIN_NP
    pthread_timedjoin_np(nslcd_threads[i], NULL, &ts);
#endif /* HAVE_PTHREAD_TIMEDJOIN_NP */
    if (pthread_kill(nslcd_threads[i], 0) == 0)
      log_log(LOG_ERR, "thread %d is still running, shutting down anyway", i);
  }
  /* we're done */
  return EXIT_FAILURE;
}