Blame nslcd/nslcd.c

Packit 6bd9ab
/*
Packit 6bd9ab
   nslcd.c - ldap local connection daemon
Packit 6bd9ab
Packit 6bd9ab
   Copyright (C) 2006 West Consulting
Packit 6bd9ab
   Copyright (C) 2006-2017 Arthur de Jong
Packit 6bd9ab
Packit 6bd9ab
   This library is free software; you can redistribute it and/or
Packit 6bd9ab
   modify it under the terms of the GNU Lesser General Public
Packit 6bd9ab
   License as published by the Free Software Foundation; either
Packit 6bd9ab
   version 2.1 of the License, or (at your option) any later version.
Packit 6bd9ab
Packit 6bd9ab
   This library is distributed in the hope that it will be useful,
Packit 6bd9ab
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 6bd9ab
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 6bd9ab
   Lesser General Public License for more details.
Packit 6bd9ab
Packit 6bd9ab
   You should have received a copy of the GNU Lesser General Public
Packit 6bd9ab
   License along with this library; if not, write to the Free Software
Packit 6bd9ab
   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
Packit 6bd9ab
   02110-1301 USA
Packit 6bd9ab
*/
Packit 6bd9ab
Packit 6bd9ab
#include "config.h"
Packit 6bd9ab
Packit 6bd9ab
#include <stdlib.h>
Packit 6bd9ab
#include <stdio.h>
Packit 6bd9ab
#include <string.h>
Packit 6bd9ab
#ifdef HAVE_STDINT_H
Packit 6bd9ab
#include <stdint.h>
Packit 6bd9ab
#endif /* HAVE_STDINT_H */
Packit 6bd9ab
#include <sys/types.h>
Packit 6bd9ab
#include <sys/param.h>
Packit 6bd9ab
#include <sys/wait.h>
Packit 6bd9ab
#ifdef HAVE_GETOPT_H
Packit 6bd9ab
#include <getopt.h>
Packit 6bd9ab
#endif /* HAVE_GETOPT_H */
Packit 6bd9ab
#include <assert.h>
Packit 6bd9ab
#include <signal.h>
Packit 6bd9ab
#include <errno.h>
Packit 6bd9ab
#include <unistd.h>
Packit 6bd9ab
#include <fcntl.h>
Packit 6bd9ab
#include <sys/stat.h>
Packit 6bd9ab
#include <sys/socket.h>
Packit 6bd9ab
#include <sys/un.h>
Packit 6bd9ab
#include <grp.h>
Packit 6bd9ab
#ifdef HAVE_NSS_H
Packit 6bd9ab
#include <nss.h>
Packit 6bd9ab
#endif /* HAVE_NSS_H */
Packit 6bd9ab
#include <pthread.h>
Packit 6bd9ab
#ifdef HAVE_PTHREAD_NP_H
Packit 6bd9ab
#include <pthread_np.h>
Packit 6bd9ab
#endif /* HAVE_PTHREAD_NP_H */
Packit 6bd9ab
#ifndef HAVE_GETOPT_LONG
Packit 6bd9ab
#include "compat/getopt_long.h"
Packit 6bd9ab
#endif /* not HAVE_GETOPT_LONG */
Packit 6bd9ab
#include <dlfcn.h>
Packit 6bd9ab
#include <libgen.h>
Packit 6bd9ab
#include <limits.h>
Packit 6bd9ab
Packit 6bd9ab
#include "nslcd.h"
Packit 6bd9ab
#include "log.h"
Packit 6bd9ab
#include "cfg.h"
Packit 6bd9ab
#include "common.h"
Packit 6bd9ab
#include "compat/attrs.h"
Packit 6bd9ab
#include "compat/getpeercred.h"
Packit 6bd9ab
#include "compat/socket.h"
Packit 6bd9ab
#include "daemonize.h"
Packit 6bd9ab
Packit 6bd9ab
/* read timeout is half a second because clients should send their request
Packit 6bd9ab
   quickly, write timeout is 60 seconds because clients could be taking some
Packit 6bd9ab
   time to process the results */
Packit 6bd9ab
#define READ_TIMEOUT 500
Packit 6bd9ab
#define WRITE_TIMEOUT 60 * 1000
Packit 6bd9ab
Packit 6bd9ab
/* buffer sizes for I/O */
Packit 6bd9ab
#define READBUFFER_MINSIZE 32
Packit 6bd9ab
#define READBUFFER_MAXSIZE 64
Packit 6bd9ab
#define WRITEBUFFER_MINSIZE 1024
Packit 6bd9ab
#define WRITEBUFFER_MAXSIZE 1 * 1024 * 1024
Packit 6bd9ab
Packit 6bd9ab
/* adjust the oom killer score */
Packit 6bd9ab
#define OOM_SCORE_ADJ_FILE "/proc/self/oom_score_adj"
Packit 6bd9ab
#define OOM_SCORE_ADJ "-1000"
Packit 6bd9ab
Packit 6bd9ab
/* flag to indicate if we are in debugging mode */
Packit 6bd9ab
static int nslcd_debugging = 0;
Packit 6bd9ab
Packit 6bd9ab
/* flag to indicate we shouldn't daemonize */
Packit 6bd9ab
static int nslcd_nofork = 0;
Packit 6bd9ab
Packit 6bd9ab
/* flag to indicate user requested the --check option */
Packit 6bd9ab
static int nslcd_checkonly = 0;
Packit 6bd9ab
Packit 6bd9ab
/* the flag to indicate that a signal was received */
Packit 6bd9ab
static volatile int nslcd_receivedsignal = 0;
Packit 6bd9ab
Packit 6bd9ab
/* the server socket used for communication */
Packit 6bd9ab
static int nslcd_serversocket = -1;
Packit 6bd9ab
Packit 6bd9ab
/* thread ids of all running threads */
Packit 6bd9ab
static pthread_t *nslcd_threads;
Packit 6bd9ab
Packit 6bd9ab
/* if we don't have clearenv() we have to do this the hard way */
Packit 6bd9ab
#ifndef HAVE_CLEARENV
Packit 6bd9ab
Packit 6bd9ab
/* the definition of the environment */
Packit 6bd9ab
extern char **environ;
Packit 6bd9ab
Packit 6bd9ab
/* the environment we want to use */
Packit 6bd9ab
static char *sane_environment[] = {
Packit 6bd9ab
  "HOME=/",
Packit 6bd9ab
  "TMPDIR=/tmp",
Packit 6bd9ab
  "LDAPNOINIT=1",
Packit 6bd9ab
  NULL
Packit 6bd9ab
};
Packit 6bd9ab
Packit 6bd9ab
#endif /* not HAVE_CLEARENV */
Packit 6bd9ab
Packit 6bd9ab
/* display version information */
Packit 6bd9ab
static void display_version(FILE *fp)
Packit 6bd9ab
{
Packit 6bd9ab
  fprintf(fp, "%s\n", PACKAGE_STRING);
Packit 6bd9ab
  fprintf(fp, "Written by Luke Howard and Arthur de Jong.\n\n");
Packit 6bd9ab
  fprintf(fp, "Copyright (C) 1997-2017 Luke Howard, Arthur de Jong and West Consulting\n"
Packit 6bd9ab
              "This is free software; see the source for copying conditions.  There is NO\n"
Packit 6bd9ab
              "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n");
Packit 6bd9ab
}
Packit 6bd9ab
Packit 6bd9ab
/* display usage information */
Packit 6bd9ab
static void display_usage(FILE *fp, const char *program_name)
Packit 6bd9ab
{
Packit 6bd9ab
  fprintf(fp, "Usage: %s [OPTION]...\n", program_name);
Packit 6bd9ab
  fprintf(fp, "Name Service LDAP connection daemon.\n");
Packit 6bd9ab
  fprintf(fp, "  -c, --check        check if the daemon already is running\n");
Packit 6bd9ab
  fprintf(fp, "  -d, --debug        don't fork and print debugging to stderr\n");
Packit 6bd9ab
  fprintf(fp, "  -n, --nofork       don't fork\n");
Packit 6bd9ab
  fprintf(fp, "      --help         display this help and exit\n");
Packit 6bd9ab
  fprintf(fp, "      --version      output version information and exit\n");
Packit 6bd9ab
  fprintf(fp, "\n" "Report bugs to <%s>.\n", PACKAGE_BUGREPORT);
Packit 6bd9ab
}
Packit 6bd9ab
Packit 6bd9ab
/* the definition of options for getopt(). see getopt(2) */
Packit 6bd9ab
static struct option const nslcd_options[] = {
Packit 6bd9ab
  {"check",   no_argument, NULL, 'c'},
Packit 6bd9ab
  {"debug",   no_argument, NULL, 'd'},
Packit 6bd9ab
  {"nofork",  no_argument, NULL, 'n'},
Packit 6bd9ab
  {"help",    no_argument, NULL, 'h'},
Packit 6bd9ab
  {"version", no_argument, NULL, 'V'},
Packit 6bd9ab
  {NULL,      0,           NULL, 0}
Packit 6bd9ab
};
Packit 6bd9ab
#define NSLCD_OPTIONSTRING "cndhV"
Packit 6bd9ab
Packit 6bd9ab
/* parse command line options and save settings in struct  */
Packit 6bd9ab
static void parse_cmdline(int argc, char *argv[])
Packit 6bd9ab
{
Packit 6bd9ab
  int optc;
Packit 6bd9ab
  while ((optc = getopt_long(argc, argv, NSLCD_OPTIONSTRING, nslcd_options, NULL)) != -1)
Packit 6bd9ab
  {
Packit 6bd9ab
    switch (optc)
Packit 6bd9ab
    {
Packit 6bd9ab
      case 'c': /* -c, --check        check if the daemon already is running */
Packit 6bd9ab
        nslcd_checkonly = 1;
Packit 6bd9ab
        break;
Packit 6bd9ab
      case 'd': /* -d, --debug        don't fork and print debugging to stderr */
Packit 6bd9ab
        nslcd_debugging++;
Packit 6bd9ab
        log_setdefaultloglevel(LOG_DEBUG);
Packit 6bd9ab
        break;
Packit 6bd9ab
      case 'n': /* -n, --nofork       don't fork */
Packit 6bd9ab
        nslcd_nofork++;
Packit 6bd9ab
        break;
Packit 6bd9ab
      case 'h': /*     --help         display this help and exit */
Packit 6bd9ab
        display_usage(stdout, argv[0]);
Packit 6bd9ab
        exit(EXIT_SUCCESS);
Packit 6bd9ab
      case 'V': /*     --version      output version information and exit */
Packit 6bd9ab
        display_version(stdout);
Packit 6bd9ab
        exit(EXIT_SUCCESS);
Packit 6bd9ab
      case ':': /* missing required parameter */
Packit 6bd9ab
      case '?': /* unknown option character or extraneous parameter */
Packit 6bd9ab
      default:
Packit 6bd9ab
        fprintf(stderr, "Try '%s --help' for more information.\n", argv[0]);
Packit 6bd9ab
        exit(EXIT_FAILURE);
Packit 6bd9ab
    }
Packit 6bd9ab
  }
Packit 6bd9ab
  /* check for remaining arguments */
Packit 6bd9ab
  if (optind < argc)
Packit 6bd9ab
  {
Packit 6bd9ab
    fprintf(stderr, "%s: unrecognized option '%s'\n", argv[0], argv[optind]);
Packit 6bd9ab
    fprintf(stderr, "Try '%s --help' for more information.\n", argv[0]);
Packit 6bd9ab
    exit(EXIT_FAILURE);
Packit 6bd9ab
  }
Packit 6bd9ab
}
Packit 6bd9ab
Packit 6bd9ab
/* signal handler for storing information on received signals */
Packit 6bd9ab
static void sig_handler(int signum)
Packit 6bd9ab
{
Packit 6bd9ab
  /* just save the signal to indicate that we're stopping */
Packit 6bd9ab
  nslcd_receivedsignal = signum;
Packit 6bd9ab
}
Packit 6bd9ab
Packit 6bd9ab
/* do some cleaning up before terminating */
Packit 6bd9ab
static void exithandler(void)
Packit 6bd9ab
{
Packit 6bd9ab
  /* close socket if it's still in use */
Packit 6bd9ab
  if (nslcd_serversocket >= 0)
Packit 6bd9ab
  {
Packit 6bd9ab
    if (close(nslcd_serversocket))
Packit 6bd9ab
      log_log(LOG_WARNING, "problem closing server socket (ignored): %s",
Packit 6bd9ab
              strerror(errno));
Packit 6bd9ab
  }
Packit 6bd9ab
  /* remove existing named socket */
Packit 6bd9ab
  if (unlink(NSLCD_SOCKET) < 0)
Packit 6bd9ab
  {
Packit 6bd9ab
    log_log(LOG_DEBUG, "unlink() of " NSLCD_SOCKET " failed (ignored): %s",
Packit 6bd9ab
            strerror(errno));
Packit 6bd9ab
  }
Packit 6bd9ab
  /* remove pidfile */
Packit 6bd9ab
  if (unlink(NSLCD_PIDFILE) < 0)
Packit 6bd9ab
  {
Packit 6bd9ab
    log_log(LOG_DEBUG, "unlink() of " NSLCD_PIDFILE " failed (ignored): %s",
Packit 6bd9ab
            strerror(errno));
Packit 6bd9ab
  }
Packit 6bd9ab
  /* log exit */
Packit 6bd9ab
  log_log(LOG_INFO, "version %s bailing out", VERSION);
Packit 6bd9ab
}
Packit 6bd9ab
Packit 6bd9ab
/* create the directory for the specified file to reside in */
Packit 6bd9ab
static void mkdirname(const char *filename)
Packit 6bd9ab
{
Packit 6bd9ab
  char *tmpname, *path;
Packit 6bd9ab
  tmpname = strdup(filename);
Packit 6bd9ab
  if (tmpname == NULL)
Packit 6bd9ab
    return;
Packit 6bd9ab
  path = dirname(tmpname);
Packit 6bd9ab
  if (mkdir(path, (mode_t)0755) == 0)
Packit 6bd9ab
  {
Packit 6bd9ab
    /* if directory was just created, set correct ownership */
Packit 6bd9ab
    if (lchown(path, nslcd_cfg->uid, nslcd_cfg->gid) < 0)
Packit 6bd9ab
      log_log(LOG_WARNING, "problem setting permissions for %s: %s",
Packit 6bd9ab
              path, strerror(errno));
Packit 6bd9ab
  }
Packit 6bd9ab
  free(tmpname);
Packit 6bd9ab
}
Packit 6bd9ab
Packit 6bd9ab
/* returns a socket ready to answer requests from the client,
Packit 6bd9ab
   exit()s on error */
Packit 6bd9ab
static int create_socket(const char *filename)
Packit 6bd9ab
{
Packit 6bd9ab
  int sock;
Packit 6bd9ab
  int i;
Packit 6bd9ab
  struct sockaddr_un addr;
Packit 6bd9ab
  /* create a socket */
Packit 6bd9ab
  if ((sock = socket(PF_UNIX, SOCK_STREAM, 0)) < 0)
Packit 6bd9ab
  {
Packit 6bd9ab
    log_log(LOG_ERR, "cannot create socket: %s", strerror(errno));
Packit 6bd9ab
    exit(EXIT_FAILURE);
Packit 6bd9ab
  }
Packit 6bd9ab
  if (sock >= (int)FD_SETSIZE)
Packit 6bd9ab
  {
Packit 6bd9ab
    log_log(LOG_ERR, "socket file descriptor number too high (%d)", sock);
Packit 6bd9ab
    exit(EXIT_FAILURE);
Packit 6bd9ab
  }
Packit 6bd9ab
  /* remove existing named socket */
Packit 6bd9ab
  if (unlink(filename) < 0)
Packit 6bd9ab
  {
Packit 6bd9ab
    log_log(LOG_DEBUG, "unlink() of %s failed (ignored): %s",
Packit 6bd9ab
            filename, strerror(errno));
Packit 6bd9ab
  }
Packit 6bd9ab
  /* do not block on accept() */
Packit 6bd9ab
  if ((i = fcntl(sock, F_GETFL, 0)) < 0)
Packit 6bd9ab
  {
Packit 6bd9ab
    log_log(LOG_ERR, "fctnl(F_GETFL) failed: %s", strerror(errno));
Packit 6bd9ab
    if (close(sock))
Packit 6bd9ab
      log_log(LOG_WARNING, "problem closing socket: %s", strerror(errno));
Packit 6bd9ab
    exit(EXIT_FAILURE);
Packit 6bd9ab
  }
Packit 6bd9ab
  if (fcntl(sock, F_SETFL, i | O_NONBLOCK) < 0)
Packit 6bd9ab
  {
Packit 6bd9ab
    log_log(LOG_ERR, "fctnl(F_SETFL,O_NONBLOCK) failed: %s", strerror(errno));
Packit 6bd9ab
    if (close(sock))
Packit 6bd9ab
      log_log(LOG_WARNING, "problem closing socket: %s", strerror(errno));
Packit 6bd9ab
    exit(EXIT_FAILURE);
Packit 6bd9ab
  }
Packit 6bd9ab
  /* create the directory if needed */
Packit 6bd9ab
  mkdirname(filename);
Packit 6bd9ab
  /* create socket address structure */
Packit 6bd9ab
  memset(&addr, 0, sizeof(struct sockaddr_un));
Packit 6bd9ab
  addr.sun_family = AF_UNIX;
Packit 6bd9ab
  strncpy(addr.sun_path, filename, sizeof(addr.sun_path));
Packit 6bd9ab
  addr.sun_path[sizeof(addr.sun_path) - 1] = '\0';
Packit 6bd9ab
  /* bind to the named socket */
Packit 6bd9ab
  if (bind(sock, (struct sockaddr *)&addr, SUN_LEN(&addr)))
Packit 6bd9ab
  {
Packit 6bd9ab
    log_log(LOG_ERR, "bind() to %s failed: %s", filename, strerror(errno));
Packit 6bd9ab
    if (close(sock))
Packit 6bd9ab
      log_log(LOG_WARNING, "problem closing socket: %s", strerror(errno));
Packit 6bd9ab
    exit(EXIT_FAILURE);
Packit 6bd9ab
  }
Packit 6bd9ab
  /* close the file descriptor on exec */
Packit 6bd9ab
  if (fcntl(sock, F_SETFD, FD_CLOEXEC) < 0)
Packit 6bd9ab
  {
Packit 6bd9ab
    log_log(LOG_ERR, "fctnl(F_SETFL,FD_CLOEXEC) on %s failed: %s",
Packit 6bd9ab
            filename, strerror(errno));
Packit 6bd9ab
    if (close(sock))
Packit 6bd9ab
      log_log(LOG_WARNING, "problem closing socket: %s", strerror(errno));
Packit 6bd9ab
    exit(EXIT_FAILURE);
Packit 6bd9ab
  }
Packit 6bd9ab
  /* set permissions of socket so anybody can do requests */
Packit 6bd9ab
  /* Note: we use chmod() here instead of fchmod() because
Packit 6bd9ab
     fchmod does not work on sockets
Packit 6bd9ab
     http://www.opengroup.org/onlinepubs/009695399/functions/fchmod.html
Packit 6bd9ab
     http://lkml.org/lkml/2005/5/16/11 */
Packit 6bd9ab
  if (chmod(filename, (mode_t)0666))
Packit 6bd9ab
  {
Packit 6bd9ab
    log_log(LOG_ERR, "chmod(0666) of %s failed: %s",
Packit 6bd9ab
            filename, strerror(errno));
Packit 6bd9ab
    if (close(sock))
Packit 6bd9ab
      log_log(LOG_WARNING, "problem closing socket: %s", strerror(errno));
Packit 6bd9ab
    exit(EXIT_FAILURE);
Packit 6bd9ab
  }
Packit 6bd9ab
  /* start listening for connections */
Packit 6bd9ab
  if (listen(sock, SOMAXCONN) < 0)
Packit 6bd9ab
  {
Packit 6bd9ab
    log_log(LOG_ERR, "listen() failed: %s", strerror(errno));
Packit 6bd9ab
    if (close(sock))
Packit 6bd9ab
      log_log(LOG_WARNING, "problem closing socket: %s", strerror(errno));
Packit 6bd9ab
    exit(EXIT_FAILURE);
Packit 6bd9ab
  }
Packit 6bd9ab
  /* we're done */
Packit 6bd9ab
  return sock;
Packit 6bd9ab
}
Packit 6bd9ab
Packit 6bd9ab
/* read the version information and action from the stream
Packit 6bd9ab
   this function returns the read action in location pointer to by action */
Packit 6bd9ab
static int read_header(TFILE *fp, int32_t *action)
Packit 6bd9ab
{
Packit 6bd9ab
  int32_t tmpint32;
Packit 6bd9ab
  int32_t protocol;
Packit 6bd9ab
  /* read the protocol version */
Packit 6bd9ab
  READ_INT32(fp, protocol);
Packit 6bd9ab
  if (protocol != (int32_t)NSLCD_VERSION)
Packit 6bd9ab
  {
Packit 6bd9ab
    log_log(LOG_DEBUG, "invalid nslcd version id: 0x%08x", (unsigned int)protocol);
Packit 6bd9ab
    return -1;
Packit 6bd9ab
  }
Packit 6bd9ab
  /* read the request type */
Packit 6bd9ab
  READ_INT32(fp, *action);
Packit 6bd9ab
  return 0;
Packit 6bd9ab
}
Packit 6bd9ab
Packit 6bd9ab
/* read a request message, returns <0 in case of errors,
Packit 6bd9ab
   this function closes the socket */
Packit 6bd9ab
static void handleconnection(int sock, MYLDAP_SESSION *session)
Packit 6bd9ab
{
Packit 6bd9ab
  TFILE *fp;
Packit 6bd9ab
  int32_t action;
Packit 6bd9ab
  uid_t uid = (uid_t)-1;
Packit 6bd9ab
  gid_t gid = (gid_t)-1;
Packit 6bd9ab
  pid_t pid = (pid_t)-1;
Packit 6bd9ab
  /* log connection */
Packit 6bd9ab
  if (getpeercred(sock, &uid, &gid, &pid))
Packit 6bd9ab
    log_log(LOG_DEBUG, "connection from unknown client: %s", strerror(errno));
Packit 6bd9ab
  else
Packit 6bd9ab
    log_log(LOG_DEBUG, "connection from pid=%lu uid=%lu gid=%lu",
Packit 6bd9ab
            (unsigned long int)pid, (unsigned long int)uid, (unsigned long int)gid);
Packit 6bd9ab
  /* create a stream object */
Packit 6bd9ab
  if ((fp = tio_fdopen(sock, READ_TIMEOUT, WRITE_TIMEOUT,
Packit 6bd9ab
                       READBUFFER_MINSIZE, READBUFFER_MAXSIZE,
Packit 6bd9ab
                       WRITEBUFFER_MINSIZE, WRITEBUFFER_MAXSIZE)) == NULL)
Packit 6bd9ab
  {
Packit 6bd9ab
    log_log(LOG_WARNING, "cannot create stream for writing: %s",
Packit 6bd9ab
            strerror(errno));
Packit 6bd9ab
    (void)close(sock);
Packit 6bd9ab
    return;
Packit 6bd9ab
  }
Packit 6bd9ab
  /* read request */
Packit 6bd9ab
  if (read_header(fp, &action))
Packit 6bd9ab
  {
Packit 6bd9ab
    (void)tio_close(fp);
Packit 6bd9ab
    return;
Packit 6bd9ab
  }
Packit 6bd9ab
  /* handle request */
Packit 6bd9ab
  switch (action)
Packit 6bd9ab
  {
Packit 6bd9ab
    case NSLCD_ACTION_CONFIG_GET:       (void)nslcd_config_get(fp, session); break;
Packit 6bd9ab
    case NSLCD_ACTION_ALIAS_BYNAME:     (void)nslcd_alias_byname(fp, session); break;
Packit 6bd9ab
    case NSLCD_ACTION_ALIAS_ALL:        (void)nslcd_alias_all(fp, session); break;
Packit 6bd9ab
    case NSLCD_ACTION_ETHER_BYNAME:     (void)nslcd_ether_byname(fp, session); break;
Packit 6bd9ab
    case NSLCD_ACTION_ETHER_BYETHER:    (void)nslcd_ether_byether(fp, session); break;
Packit 6bd9ab
    case NSLCD_ACTION_ETHER_ALL:        (void)nslcd_ether_all(fp, session); break;
Packit 6bd9ab
    case NSLCD_ACTION_GROUP_BYNAME:     (void)nslcd_group_byname(fp, session); break;
Packit 6bd9ab
    case NSLCD_ACTION_GROUP_BYGID:      (void)nslcd_group_bygid(fp, session); break;
Packit 6bd9ab
    case NSLCD_ACTION_GROUP_BYMEMBER:   (void)nslcd_group_bymember(fp, session); break;
Packit 6bd9ab
    case NSLCD_ACTION_GROUP_ALL:
Packit 6bd9ab
      if (!nslcd_cfg->nss_disable_enumeration) (void)nslcd_group_all(fp, session);
Packit 6bd9ab
      break;
Packit 6bd9ab
    case NSLCD_ACTION_HOST_BYNAME:      (void)nslcd_host_byname(fp, session); break;
Packit 6bd9ab
    case NSLCD_ACTION_HOST_BYADDR:      (void)nslcd_host_byaddr(fp, session); break;
Packit 6bd9ab
    case NSLCD_ACTION_HOST_ALL:         (void)nslcd_host_all(fp, session); break;
Packit 6bd9ab
    case NSLCD_ACTION_NETGROUP_BYNAME:  (void)nslcd_netgroup_byname(fp, session); break;
Packit 6bd9ab
    case NSLCD_ACTION_NETGROUP_ALL:     (void)nslcd_netgroup_all(fp, session); break;
Packit 6bd9ab
    case NSLCD_ACTION_NETWORK_BYNAME:   (void)nslcd_network_byname(fp, session); break;
Packit 6bd9ab
    case NSLCD_ACTION_NETWORK_BYADDR:   (void)nslcd_network_byaddr(fp, session); break;
Packit 6bd9ab
    case NSLCD_ACTION_NETWORK_ALL:      (void)nslcd_network_all(fp, session); break;
Packit 6bd9ab
    case NSLCD_ACTION_PASSWD_BYNAME:    (void)nslcd_passwd_byname(fp, session, uid); break;
Packit 6bd9ab
    case NSLCD_ACTION_PASSWD_BYUID:     (void)nslcd_passwd_byuid(fp, session, uid); break;
Packit 6bd9ab
    case NSLCD_ACTION_PASSWD_ALL:
Packit 6bd9ab
      if (!nslcd_cfg->nss_disable_enumeration) (void)nslcd_passwd_all(fp, session, uid);
Packit 6bd9ab
      break;
Packit 6bd9ab
    case NSLCD_ACTION_PROTOCOL_BYNAME:  (void)nslcd_protocol_byname(fp, session); break;
Packit 6bd9ab
    case NSLCD_ACTION_PROTOCOL_BYNUMBER:(void)nslcd_protocol_bynumber(fp, session); break;
Packit 6bd9ab
    case NSLCD_ACTION_PROTOCOL_ALL:     (void)nslcd_protocol_all(fp, session); break;
Packit 6bd9ab
    case NSLCD_ACTION_RPC_BYNAME:       (void)nslcd_rpc_byname(fp, session); break;
Packit 6bd9ab
    case NSLCD_ACTION_RPC_BYNUMBER:     (void)nslcd_rpc_bynumber(fp, session); break;
Packit 6bd9ab
    case NSLCD_ACTION_RPC_ALL:          (void)nslcd_rpc_all(fp, session); break;
Packit 6bd9ab
    case NSLCD_ACTION_SERVICE_BYNAME:   (void)nslcd_service_byname(fp, session); break;
Packit 6bd9ab
    case NSLCD_ACTION_SERVICE_BYNUMBER: (void)nslcd_service_bynumber(fp, session); break;
Packit 6bd9ab
    case NSLCD_ACTION_SERVICE_ALL:      (void)nslcd_service_all(fp, session); break;
Packit 6bd9ab
    case NSLCD_ACTION_SHADOW_BYNAME:    (void)nslcd_shadow_byname(fp, session, uid); break;
Packit 6bd9ab
    case NSLCD_ACTION_SHADOW_ALL:
Packit 6bd9ab
      if (!nslcd_cfg->nss_disable_enumeration) (void)nslcd_shadow_all(fp, session, uid);
Packit 6bd9ab
      break;
Packit 6bd9ab
    case NSLCD_ACTION_PAM_AUTHC:        (void)nslcd_pam_authc(fp, session, uid); break;
Packit 6bd9ab
    case NSLCD_ACTION_PAM_AUTHZ:        (void)nslcd_pam_authz(fp, session); break;
Packit 6bd9ab
    case NSLCD_ACTION_PAM_SESS_O:       (void)nslcd_pam_sess_o(fp, session); break;
Packit 6bd9ab
    case NSLCD_ACTION_PAM_SESS_C:       (void)nslcd_pam_sess_c(fp, session); break;
Packit 6bd9ab
    case NSLCD_ACTION_PAM_PWMOD:        (void)nslcd_pam_pwmod(fp, session, uid); break;
Packit 6bd9ab
    case NSLCD_ACTION_USERMOD:          (void)nslcd_usermod(fp, session, uid); break;
Packit 6bd9ab
    default:
Packit 6bd9ab
      log_log(LOG_WARNING, "invalid request id: 0x%08x", (unsigned int)action);
Packit 6bd9ab
      break;
Packit 6bd9ab
  }
Packit 6bd9ab
  /* we're done with the request */
Packit 6bd9ab
  myldap_session_cleanup(session);
Packit 6bd9ab
  (void)tio_close(fp);
Packit 6bd9ab
  return;
Packit 6bd9ab
}
Packit 6bd9ab
Packit 6bd9ab
/* test to see if we can lock the specified file */
Packit 6bd9ab
static int is_locked(const char *filename)
Packit 6bd9ab
{
Packit 6bd9ab
  int fd;
Packit 6bd9ab
  if (filename != NULL)
Packit 6bd9ab
  {
Packit 6bd9ab
    errno = 0;
Packit 6bd9ab
    if ((fd = open(filename, O_RDWR, 0644)) < 0)
Packit 6bd9ab
    {
Packit 6bd9ab
      if (errno == ENOENT)
Packit 6bd9ab
        return 0; /* if file doesn't exist it cannot be locked */
Packit 6bd9ab
      log_log(LOG_ERR, "cannot open lock file (%s): %s", filename, strerror(errno));
Packit 6bd9ab
      exit(EXIT_FAILURE);
Packit 6bd9ab
    }
Packit 6bd9ab
    if (lockf(fd, F_TEST, 0) < 0)
Packit 6bd9ab
    {
Packit 6bd9ab
      if (close(fd))
Packit 6bd9ab
        log_log(LOG_WARNING, "problem closing fd: %s", strerror(errno));
Packit 6bd9ab
      return -1;
Packit 6bd9ab
    }
Packit 6bd9ab
    if (close(fd))
Packit 6bd9ab
      log_log(LOG_WARNING, "problem closing fd: %s", strerror(errno));
Packit 6bd9ab
  }
Packit 6bd9ab
  return 0;
Packit 6bd9ab
}
Packit 6bd9ab
Packit 6bd9ab
/* write the current process id to the specified file */
Packit 6bd9ab
static void create_pidfile(const char *filename)
Packit 6bd9ab
{
Packit 6bd9ab
  int fd;
Packit 6bd9ab
  char buffer[20];
Packit 6bd9ab
  if (filename != NULL)
Packit 6bd9ab
  {
Packit 6bd9ab
    mkdirname(filename);
Packit 6bd9ab
    if ((fd = open(filename, O_RDWR | O_CREAT, 0644)) < 0)
Packit 6bd9ab
    {
Packit 6bd9ab
      log_log(LOG_ERR, "cannot create pid file (%s): %s",
Packit 6bd9ab
              filename, strerror(errno));
Packit 6bd9ab
      exit(EXIT_FAILURE);
Packit 6bd9ab
    }
Packit 6bd9ab
    if (lockf(fd, F_TLOCK, 0) < 0)
Packit 6bd9ab
    {
Packit 6bd9ab
      log_log(LOG_ERR, "cannot lock pid file (%s): %s",
Packit 6bd9ab
              filename, strerror(errno));
Packit 6bd9ab
      exit(EXIT_FAILURE);
Packit 6bd9ab
    }
Packit 6bd9ab
    if (ftruncate(fd, 0) < 0)
Packit 6bd9ab
    {
Packit 6bd9ab
      log_log(LOG_ERR, "cannot truncate pid file (%s): %s",
Packit 6bd9ab
              filename, strerror(errno));
Packit 6bd9ab
      exit(EXIT_FAILURE);
Packit 6bd9ab
    }
Packit 6bd9ab
    mysnprintf(buffer, sizeof(buffer), "%lu\n", (unsigned long int)getpid());
Packit 6bd9ab
    if (write(fd, buffer, strlen(buffer)) != (int)strlen(buffer))
Packit 6bd9ab
    {
Packit 6bd9ab
      log_log(LOG_ERR, "error writing pid file (%s): %s",
Packit 6bd9ab
              filename, strerror(errno));
Packit 6bd9ab
      exit(EXIT_FAILURE);
Packit 6bd9ab
    }
Packit 6bd9ab
    /* we keep the pidfile open so the lock remains valid */
Packit 6bd9ab
  }
Packit 6bd9ab
}
Packit 6bd9ab
Packit 6bd9ab
/* try to install signal handler and check result */
Packit 6bd9ab
static void install_sighandler(int signum, void (*handler) (int))
Packit 6bd9ab
{
Packit 6bd9ab
  struct sigaction act;
Packit 6bd9ab
  memset(&act, 0, sizeof(struct sigaction));
Packit 6bd9ab
  act.sa_handler = handler;
Packit 6bd9ab
  sigemptyset(&act.sa_mask);
Packit 6bd9ab
  act.sa_flags = SA_RESTART | SA_NOCLDSTOP;
Packit 6bd9ab
  if (sigaction(signum, &act, NULL) != 0)
Packit 6bd9ab
  {
Packit 6bd9ab
    log_log(LOG_ERR, "error installing signal handler for '%s': %s",
Packit 6bd9ab
            signame(signum), strerror(errno));
Packit 6bd9ab
    exit(EXIT_FAILURE);
Packit 6bd9ab
  }
Packit 6bd9ab
}
Packit 6bd9ab
Packit 6bd9ab
static void worker_cleanup(void *arg)
Packit 6bd9ab
{
Packit 6bd9ab
  MYLDAP_SESSION *session = (MYLDAP_SESSION *)arg;
Packit 6bd9ab
  myldap_session_close(session);
Packit 6bd9ab
}
Packit 6bd9ab
Packit 6bd9ab
static void *worker(void UNUSED(*arg))
Packit 6bd9ab
{
Packit 6bd9ab
  MYLDAP_SESSION *session;
Packit 6bd9ab
  int csock;
Packit 6bd9ab
  int j;
Packit 6bd9ab
  struct sockaddr_storage addr;
Packit 6bd9ab
  socklen_t alen;
Packit 6bd9ab
  fd_set fds;
Packit 6bd9ab
  struct timeval tv;
Packit 6bd9ab
  /* create a new LDAP session */
Packit 6bd9ab
  session = myldap_create_session();
Packit 6bd9ab
  /* clean up the session if we're done */
Packit 6bd9ab
  pthread_cleanup_push(worker_cleanup, session);
Packit 6bd9ab
  /* start waiting for incoming connections */
Packit 6bd9ab
  while (1)
Packit 6bd9ab
  {
Packit 6bd9ab
    /* time out connection to LDAP server if needed */
Packit 6bd9ab
    myldap_session_check(session);
Packit 6bd9ab
    /* set up the set of fds to wait on */
Packit 6bd9ab
    FD_ZERO(&fds);
Packit 6bd9ab
    FD_SET(nslcd_serversocket, &fds);
Packit 6bd9ab
    /* set up our timeout value */
Packit 6bd9ab
    tv.tv_sec = nslcd_cfg->idle_timelimit;
Packit 6bd9ab
    tv.tv_usec = 0;
Packit 6bd9ab
    /* wait for a new connection */
Packit 6bd9ab
    j = select(nslcd_serversocket + 1, &fds, NULL, NULL,
Packit 6bd9ab
               nslcd_cfg->idle_timelimit > 0 ? &tv : NULL);
Packit 6bd9ab
    /* check result of select() */
Packit 6bd9ab
    if (j < 0)
Packit 6bd9ab
    {
Packit 6bd9ab
      if (errno == EINTR)
Packit 6bd9ab
        log_log(LOG_DEBUG, "select() failed (ignored): %s", strerror(errno));
Packit 6bd9ab
      else
Packit 6bd9ab
        log_log(LOG_ERR, "select() failed: %s", strerror(errno));
Packit 6bd9ab
      continue;
Packit 6bd9ab
    }
Packit 6bd9ab
    /* see if our file descriptor is actually ready */
Packit 6bd9ab
    if (!FD_ISSET(nslcd_serversocket, &fds))
Packit 6bd9ab
      continue;
Packit 6bd9ab
    /* wait for a new connection */
Packit 6bd9ab
    alen = (socklen_t)sizeof(struct sockaddr_storage);
Packit 6bd9ab
    csock = accept(nslcd_serversocket, (struct sockaddr *)&addr, &alen;;
Packit 6bd9ab
    if (csock < 0)
Packit 6bd9ab
    {
Packit 6bd9ab
      if ((errno == EINTR) || (errno == EAGAIN) || (errno == EWOULDBLOCK))
Packit 6bd9ab
        log_log(LOG_DEBUG, "accept() failed (ignored): %s", strerror(errno));
Packit 6bd9ab
      else
Packit 6bd9ab
        log_log(LOG_ERR, "accept() failed: %s", strerror(errno));
Packit 6bd9ab
      continue;
Packit 6bd9ab
    }
Packit 6bd9ab
    /* make sure O_NONBLOCK is not inherited */
Packit 6bd9ab
    if ((j = fcntl(csock, F_GETFL, 0)) < 0)
Packit 6bd9ab
    {
Packit 6bd9ab
      log_log(LOG_ERR, "fctnl(F_GETFL) failed: %s", strerror(errno));
Packit 6bd9ab
      if (close(csock))
Packit 6bd9ab
        log_log(LOG_WARNING, "problem closing socket: %s", strerror(errno));
Packit 6bd9ab
      continue;
Packit 6bd9ab
    }
Packit 6bd9ab
    if (fcntl(csock, F_SETFL, j & ~O_NONBLOCK) < 0)
Packit 6bd9ab
    {
Packit 6bd9ab
      log_log(LOG_ERR, "fctnl(F_SETFL,~O_NONBLOCK) failed: %s", strerror(errno));
Packit 6bd9ab
      if (close(csock))
Packit 6bd9ab
        log_log(LOG_WARNING, "problem closing socket: %s", strerror(errno));
Packit 6bd9ab
      continue;
Packit 6bd9ab
    }
Packit 6bd9ab
    /* indicate new connection to logging module (generates unique id) */
Packit 6bd9ab
    log_newsession();
Packit 6bd9ab
    /* handle the connection */
Packit 6bd9ab
    handleconnection(csock, session);
Packit 6bd9ab
    /* indicate end of session in log messages */
Packit 6bd9ab
    log_clearsession();
Packit 6bd9ab
  }
Packit 6bd9ab
  pthread_cleanup_pop(1);
Packit 6bd9ab
  return NULL;
Packit 6bd9ab
}
Packit 6bd9ab
Packit 6bd9ab
/* function to disable lookups through the nss_ldap module to avoid lookup
Packit 6bd9ab
   loops */
Packit 6bd9ab
static void disable_nss_ldap(void)
Packit 6bd9ab
{
Packit 6bd9ab
  void *handle;
Packit 6bd9ab
  char *error;
Packit 6bd9ab
  char **version_info;
Packit 6bd9ab
  int *enable_flag;
Packit 6bd9ab
  /* try to load the NSS module */
Packit 6bd9ab
#ifdef RTLD_NODELETE
Packit 6bd9ab
  handle = dlopen(NSS_LDAP_SONAME, RTLD_LAZY | RTLD_NODELETE);
Packit 6bd9ab
#else /* not RTLD_NODELETE */
Packit 6bd9ab
  handle = dlopen(NSS_LDAP_SONAME, RTLD_LAZY);
Packit 6bd9ab
#endif /* RTLD_NODELETE */
Packit 6bd9ab
  if (handle == NULL)
Packit 6bd9ab
  {
Packit 6bd9ab
    log_log(LOG_WARNING, "Warning: NSS_LDAP module not loaded: %s", dlerror());
Packit 6bd9ab
    return;
Packit 6bd9ab
  }
Packit 6bd9ab
  /* clear any existing errors */
Packit 6bd9ab
  dlerror();
Packit 6bd9ab
  /* lookup the NSS version if possible */
Packit 6bd9ab
  version_info = (char **)dlsym(handle, "_nss_" MODULE_NAME "_version");
Packit 6bd9ab
  error = dlerror();
Packit 6bd9ab
  if ((version_info != NULL) && (error == NULL))
Packit 6bd9ab
    log_log(LOG_DEBUG, "NSS_LDAP %s %s", version_info[0], version_info[1]);
Packit 6bd9ab
  else
Packit 6bd9ab
    log_log(LOG_WARNING, "Warning: NSS_LDAP version missing: %s", error);
Packit 6bd9ab
  /* clear any existing errors */
Packit 6bd9ab
  dlerror();
Packit 6bd9ab
  /* try to look up the flag */
Packit 6bd9ab
  enable_flag = (int *)dlsym(handle, "_nss_" MODULE_NAME "_enablelookups");
Packit 6bd9ab
  error = dlerror();
Packit 6bd9ab
  if ((enable_flag == NULL) || (error != NULL))
Packit 6bd9ab
  {
Packit 6bd9ab
    log_log(LOG_WARNING, "Warning: %s (probably older NSS module loaded)",
Packit 6bd9ab
            error);
Packit 6bd9ab
    /* fall back to changing the way host lookup is done */
Packit 6bd9ab
#ifdef HAVE___NSS_CONFIGURE_LOOKUP
Packit 6bd9ab
    if (__nss_configure_lookup("hosts", "files dns"))
Packit 6bd9ab
      log_log(LOG_ERR, "unable to override hosts lookup method: %s",
Packit 6bd9ab
              strerror(errno));
Packit 6bd9ab
#endif /* HAVE___NSS_CONFIGURE_LOOKUP */
Packit 6bd9ab
    dlclose(handle);
Packit 6bd9ab
    return;
Packit 6bd9ab
  }
Packit 6bd9ab
  /* disable nss_ldap */
Packit 6bd9ab
  *enable_flag = 0;
Packit 6bd9ab
#ifdef RTLD_NODELETE
Packit 6bd9ab
  /* only close the handle if RTLD_NODELETE was used */
Packit 6bd9ab
  dlclose(handle);
Packit 6bd9ab
#endif /* RTLD_NODELETE */
Packit 6bd9ab
}
Packit 6bd9ab
Packit 6bd9ab
/* poke the OOM killer so nslcd will never get killed */
Packit 6bd9ab
static void adjust_oom_score(void)
Packit 6bd9ab
{
Packit 6bd9ab
  int oom_adj_fd;
Packit 6bd9ab
  if ((oom_adj_fd = open(OOM_SCORE_ADJ_FILE, O_WRONLY)) >= 0)
Packit 6bd9ab
  {
Packit 6bd9ab
    if (write(oom_adj_fd, OOM_SCORE_ADJ, strlen(OOM_SCORE_ADJ)) < 0)
Packit 6bd9ab
      log_log(LOG_WARNING, "writing oom score adjustment of %s failed: %s",
Packit 6bd9ab
        OOM_SCORE_ADJ, strerror(errno));
Packit 6bd9ab
    close(oom_adj_fd);
Packit 6bd9ab
  }
Packit 6bd9ab
  else
Packit 6bd9ab
  {
Packit 6bd9ab
    log_log(LOG_DEBUG, "could not open %s to adjust the OOM score: %s",
Packit 6bd9ab
      OOM_SCORE_ADJ_FILE, strerror(errno));
Packit 6bd9ab
  }
Packit 6bd9ab
}
Packit 6bd9ab
Packit 6bd9ab
/* the main program... */
Packit 6bd9ab
int main(int argc, char *argv[])
Packit 6bd9ab
{
Packit 6bd9ab
  int i;
Packit 6bd9ab
  sigset_t signalmask, oldmask;
Packit 6bd9ab
#ifdef HAVE_PTHREAD_TIMEDJOIN_NP
Packit 6bd9ab
  struct timespec ts;
Packit 6bd9ab
#endif /* HAVE_PTHREAD_TIMEDJOIN_NP */
Packit 6bd9ab
  /* block all these signals so our worker threads won't handle them */
Packit 6bd9ab
  sigemptyset(&signalmask);
Packit 6bd9ab
  sigaddset(&signalmask, SIGHUP);
Packit 6bd9ab
  sigaddset(&signalmask, SIGINT);
Packit 6bd9ab
  sigaddset(&signalmask, SIGQUIT);
Packit 6bd9ab
  sigaddset(&signalmask, SIGABRT);
Packit 6bd9ab
  sigaddset(&signalmask, SIGPIPE);
Packit 6bd9ab
  sigaddset(&signalmask, SIGTERM);
Packit 6bd9ab
  sigaddset(&signalmask, SIGUSR1);
Packit 6bd9ab
  sigaddset(&signalmask, SIGUSR2);
Packit 6bd9ab
  pthread_sigmask(SIG_BLOCK, &signalmask, &oldmask);
Packit 6bd9ab
  /* close all file descriptors (except stdin/out/err) */
Packit 6bd9ab
  daemonize_closefds();
Packit 6bd9ab
  /* parse the command line */
Packit 6bd9ab
  parse_cmdline(argc, argv);
Packit 6bd9ab
  /* clean the environment */
Packit 6bd9ab
#ifdef HAVE_CLEARENV
Packit 6bd9ab
  if (clearenv() || putenv("HOME=/") || putenv("TMPDIR=/tmp") ||
Packit 6bd9ab
      putenv("LDAPNOINIT=1"))
Packit 6bd9ab
  {
Packit 6bd9ab
    log_log(LOG_ERR, "clearing environment failed");
Packit 6bd9ab
    exit(EXIT_FAILURE);
Packit 6bd9ab
  }
Packit 6bd9ab
#else /* not HAVE_CLEARENV */
Packit 6bd9ab
  /* this is a bit ugly */
Packit 6bd9ab
  environ = sane_environment;
Packit 6bd9ab
#endif /* not HAVE_CLEARENV */
Packit 6bd9ab
  /* disable the nss_ldap module for this process */
Packit 6bd9ab
  disable_nss_ldap();
Packit 6bd9ab
  /* set LDAP log level */
Packit 6bd9ab
  if (myldap_set_debuglevel(nslcd_debugging) != LDAP_SUCCESS)
Packit 6bd9ab
    exit(EXIT_FAILURE);
Packit 6bd9ab
  /* read configuration file */
Packit 6bd9ab
  cfg_init(NSLCD_CONF_PATH);
Packit 6bd9ab
  /* set default mode for pidfile and socket */
Packit 6bd9ab
  (void)umask((mode_t)0022);
Packit 6bd9ab
  /* see if someone already locked the pidfile
Packit 6bd9ab
     if --check option was given exit TRUE if daemon runs
Packit 6bd9ab
     (pidfile locked), FALSE otherwise */
Packit 6bd9ab
  if (nslcd_checkonly)
Packit 6bd9ab
  {
Packit 6bd9ab
    if (is_locked(NSLCD_PIDFILE))
Packit 6bd9ab
    {
Packit 6bd9ab
      log_log(LOG_DEBUG, "pidfile (%s) is locked", NSLCD_PIDFILE);
Packit 6bd9ab
      exit(EXIT_SUCCESS);
Packit 6bd9ab
    }
Packit 6bd9ab
    else
Packit 6bd9ab
    {
Packit 6bd9ab
      log_log(LOG_DEBUG, "pidfile (%s) is not locked", NSLCD_PIDFILE);
Packit 6bd9ab
      exit(EXIT_FAILURE);
Packit 6bd9ab
    }
Packit 6bd9ab
  }
Packit 6bd9ab
  /* change directory */
Packit 6bd9ab
  if (chdir("/") != 0)
Packit 6bd9ab
  {
Packit 6bd9ab
    log_log(LOG_ERR, "chdir failed: %s", strerror(errno));
Packit 6bd9ab
    exit(EXIT_FAILURE);
Packit 6bd9ab
  }
Packit 6bd9ab
  /* normal check for pidfile locked */
Packit 6bd9ab
  if (is_locked(NSLCD_PIDFILE))
Packit 6bd9ab
  {
Packit 6bd9ab
    log_log(LOG_ERR, "nslcd may already be active, cannot acquire lock (%s): %s",
Packit 6bd9ab
            NSLCD_PIDFILE, strerror(errno));
Packit 6bd9ab
    exit(EXIT_FAILURE);
Packit 6bd9ab
  }
Packit 6bd9ab
  /* daemonize */
Packit 6bd9ab
  if ((!nslcd_debugging) && (!nslcd_nofork))
Packit 6bd9ab
  {
Packit 6bd9ab
    errno = 0;
Packit 6bd9ab
    if (daemonize_daemon() != 0)
Packit 6bd9ab
    {
Packit 6bd9ab
      log_log(LOG_ERR, "unable to daemonize: %s", strerror(errno));
Packit 6bd9ab
      exit(EXIT_FAILURE);
Packit 6bd9ab
    }
Packit 6bd9ab
  }
Packit 6bd9ab
  /* intilialize logging */
Packit 6bd9ab
  if (!nslcd_debugging)
Packit 6bd9ab
  {
Packit 6bd9ab
    daemonize_redirect_stdio();
Packit 6bd9ab
    log_startlogging();
Packit 6bd9ab
  }
Packit 6bd9ab
  /* write pidfile */
Packit 6bd9ab
  create_pidfile(NSLCD_PIDFILE);
Packit 6bd9ab
  /* log start */
Packit 6bd9ab
  log_log(LOG_INFO, "version %s starting", VERSION);
Packit 6bd9ab
  /* install handler to close stuff off on exit and log notice */
Packit 6bd9ab
  if (atexit(exithandler))
Packit 6bd9ab
  {
Packit 6bd9ab
    log_log(LOG_ERR, "atexit() failed: %s", strerror(errno));
Packit 6bd9ab
    daemonize_ready(EXIT_FAILURE, "atexit() failed\n");
Packit 6bd9ab
    exit(EXIT_FAILURE);
Packit 6bd9ab
  }
Packit 6bd9ab
  adjust_oom_score();
Packit 6bd9ab
  /* create socket */
Packit 6bd9ab
  nslcd_serversocket = create_socket(NSLCD_SOCKET);
Packit 6bd9ab
  /* start subprocess to do invalidating if reconnect_invalidate is set */
Packit 6bd9ab
  for (i = 0; i < LM_NONE; i++)
Packit 6bd9ab
    if (nslcd_cfg->reconnect_invalidate[i])
Packit 6bd9ab
      break;
Packit 6bd9ab
  if (i < LM_NONE)
Packit 6bd9ab
    invalidator_start();
Packit 6bd9ab
  /* change nslcd group and supplemental groups */
Packit 6bd9ab
  if ((nslcd_cfg->gid != NOGID) && (nslcd_cfg->uidname != NULL))
Packit 6bd9ab
  {
Packit 6bd9ab
#ifdef HAVE_INITGROUPS
Packit 6bd9ab
    /* load supplementary groups */
Packit 6bd9ab
    if (initgroups(nslcd_cfg->uidname, nslcd_cfg->gid) < 0)
Packit 6bd9ab
      log_log(LOG_WARNING, "cannot initgroups(\"%s\",%lu) (ignored): %s",
Packit 6bd9ab
              nslcd_cfg->uidname, (unsigned long int)nslcd_cfg->gid, strerror(errno));
Packit 6bd9ab
    else
Packit 6bd9ab
      log_log(LOG_DEBUG, "initgroups(\"%s\",%lu) done",
Packit 6bd9ab
              nslcd_cfg->uidname, (unsigned long int)nslcd_cfg->gid);
Packit 6bd9ab
#else /* not HAVE_INITGROUPS */
Packit 6bd9ab
#ifdef HAVE_SETGROUPS
Packit 6bd9ab
    /* just drop all supplemental groups */
Packit 6bd9ab
    if (setgroups(0, NULL) < 0)
Packit 6bd9ab
      log_log(LOG_WARNING, "cannot setgroups(0,NULL) (ignored): %s",
Packit 6bd9ab
              strerror(errno));
Packit 6bd9ab
    else
Packit 6bd9ab
      log_log(LOG_DEBUG, "setgroups(0,NULL) done");
Packit 6bd9ab
#else /* not HAVE_SETGROUPS */
Packit 6bd9ab
    log_log(LOG_DEBUG, "neither initgroups() or setgroups() available");
Packit 6bd9ab
#endif /* not HAVE_SETGROUPS */
Packit 6bd9ab
#endif /* not HAVE_INITGROUPS */
Packit 6bd9ab
  }
Packit 6bd9ab
  /* change to nslcd gid */
Packit 6bd9ab
  if (nslcd_cfg->gid != NOGID)
Packit 6bd9ab
  {
Packit 6bd9ab
    if (setgid(nslcd_cfg->gid) != 0)
Packit 6bd9ab
    {
Packit 6bd9ab
      log_log(LOG_ERR, "cannot setgid(%lu): %s",
Packit 6bd9ab
              (unsigned long int)nslcd_cfg->gid, strerror(errno));
Packit 6bd9ab
      daemonize_ready(EXIT_FAILURE, "cannot setgid()\n");
Packit 6bd9ab
      exit(EXIT_FAILURE);
Packit 6bd9ab
    }
Packit 6bd9ab
    log_log(LOG_DEBUG, "setgid(%lu) done", (unsigned long int)nslcd_cfg->gid);
Packit 6bd9ab
  }
Packit 6bd9ab
  /* change to nslcd uid */
Packit 6bd9ab
  if (nslcd_cfg->uid != NOUID)
Packit 6bd9ab
  {
Packit 6bd9ab
    if (setuid(nslcd_cfg->uid) != 0)
Packit 6bd9ab
    {
Packit 6bd9ab
      log_log(LOG_ERR, "cannot setuid(%lu): %s",
Packit 6bd9ab
              (unsigned long int)nslcd_cfg->uid, strerror(errno));
Packit 6bd9ab
      daemonize_ready(EXIT_FAILURE, "cannot setuid()\n");
Packit 6bd9ab
      exit(EXIT_FAILURE);
Packit 6bd9ab
    }
Packit 6bd9ab
    log_log(LOG_DEBUG, "setuid(%lu) done", (unsigned long int)nslcd_cfg->uid);
Packit 6bd9ab
  }
Packit 6bd9ab
  /* start worker threads */
Packit 6bd9ab
  log_log(LOG_INFO, "accepting connections");
Packit 6bd9ab
  nslcd_threads = (pthread_t *)malloc(nslcd_cfg->threads * sizeof(pthread_t));
Packit 6bd9ab
  if (nslcd_threads == NULL)
Packit 6bd9ab
  {
Packit 6bd9ab
    log_log(LOG_CRIT, "main(): malloc() failed to allocate memory");
Packit 6bd9ab
    daemonize_ready(EXIT_FAILURE, "malloc() failed to allocate memory\n");
Packit 6bd9ab
    exit(EXIT_FAILURE);
Packit 6bd9ab
  }
Packit 6bd9ab
  for (i = 0; i < nslcd_cfg->threads; i++)
Packit 6bd9ab
  {
Packit 6bd9ab
    if (pthread_create(&nslcd_threads[i], NULL, worker, NULL))
Packit 6bd9ab
    {
Packit 6bd9ab
      log_log(LOG_ERR, "unable to start worker thread %d: %s",
Packit 6bd9ab
              i, strerror(errno));
Packit 6bd9ab
      daemonize_ready(EXIT_FAILURE, "unable to start worker thread\n");
Packit 6bd9ab
      exit(EXIT_FAILURE);
Packit 6bd9ab
    }
Packit 6bd9ab
  }
Packit 6bd9ab
  /* install signal handlers for some signals */
Packit 6bd9ab
  install_sighandler(SIGHUP, sig_handler);
Packit 6bd9ab
  install_sighandler(SIGINT, sig_handler);
Packit 6bd9ab
  install_sighandler(SIGQUIT, sig_handler);
Packit 6bd9ab
  install_sighandler(SIGABRT, sig_handler);
Packit 6bd9ab
  install_sighandler(SIGPIPE, SIG_IGN);
Packit 6bd9ab
  install_sighandler(SIGTERM, sig_handler);
Packit 6bd9ab
  install_sighandler(SIGUSR1, sig_handler);
Packit 6bd9ab
  install_sighandler(SIGUSR2, SIG_IGN);
Packit 6bd9ab
  /* signal the starting process to exit because we can provide services now */
Packit 6bd9ab
  daemonize_ready(EXIT_SUCCESS, NULL);
Packit 6bd9ab
  /* enable receiving of signals */
Packit 6bd9ab
  pthread_sigmask(SIG_SETMASK, &oldmask, NULL);
Packit 6bd9ab
  /* wait until we received a signal */
Packit 6bd9ab
  while ((nslcd_receivedsignal == 0) || (nslcd_receivedsignal == SIGUSR1))
Packit 6bd9ab
  {
Packit 6bd9ab
    sleep(INT_MAX); /* sleep as long as we can or until we receive a signal */
Packit 6bd9ab
    if (nslcd_receivedsignal == SIGUSR1)
Packit 6bd9ab
    {
Packit 6bd9ab
      log_log(LOG_INFO, "caught signal %s (%d), refresh retries",
Packit 6bd9ab
              signame(nslcd_receivedsignal), nslcd_receivedsignal);
Packit 6bd9ab
      myldap_immediate_reconnect();
Packit 6bd9ab
      nslcd_receivedsignal = 0;
Packit 6bd9ab
    }
Packit 6bd9ab
  }
Packit 6bd9ab
  /* print something about received signal */
Packit 6bd9ab
  log_log(LOG_INFO, "caught signal %s (%d), shutting down",
Packit 6bd9ab
          signame(nslcd_receivedsignal), nslcd_receivedsignal);
Packit 6bd9ab
  /* cancel all running threads */
Packit 6bd9ab
  for (i = 0; i < nslcd_cfg->threads; i++)
Packit 6bd9ab
    if (pthread_cancel(nslcd_threads[i]))
Packit 6bd9ab
      log_log(LOG_WARNING, "failed to stop thread %d (ignored): %s",
Packit 6bd9ab
              i, strerror(errno));
Packit 6bd9ab
  /* close server socket to trigger failures in threads waiting on accept() */
Packit 6bd9ab
  close(nslcd_serversocket);
Packit 6bd9ab
  nslcd_serversocket = -1;
Packit 6bd9ab
  /* if we can, wait a few seconds for the threads to finish */
Packit 6bd9ab
#ifdef HAVE_PTHREAD_TIMEDJOIN_NP
Packit 6bd9ab
  ts.tv_sec = time(NULL) + 3;
Packit 6bd9ab
  ts.tv_nsec = 0;
Packit 6bd9ab
#endif /* HAVE_PTHREAD_TIMEDJOIN_NP */
Packit 6bd9ab
  for (i = 0; i < nslcd_cfg->threads; i++)
Packit 6bd9ab
  {
Packit 6bd9ab
#ifdef HAVE_PTHREAD_TIMEDJOIN_NP
Packit 6bd9ab
    pthread_timedjoin_np(nslcd_threads[i], NULL, &ts);
Packit 6bd9ab
#endif /* HAVE_PTHREAD_TIMEDJOIN_NP */
Packit 6bd9ab
    if (pthread_kill(nslcd_threads[i], 0) == 0)
Packit 6bd9ab
      log_log(LOG_ERR, "thread %d is still running, shutting down anyway", i);
Packit 6bd9ab
  }
Packit 6bd9ab
  /* we're done */
Packit 6bd9ab
  return EXIT_SUCCESS;
Packit 6bd9ab
}