|
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 |
}
|