2
nslcd.c - ldap local connection daemon
4
Copyright (C) 2006 West Consulting
5
Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 Arthur de Jong
7
This library is free software; you can redistribute it and/or
8
modify it under the terms of the GNU Lesser General Public
9
License as published by the Free Software Foundation; either
10
version 2.1 of the License, or (at your option) any later version.
12
This library is distributed in the hope that it will be useful,
13
but WITHOUT ANY WARRANTY; without even the implied warranty of
14
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15
Lesser General Public License for more details.
17
You should have received a copy of the GNU Lesser General Public
18
License along with this library; if not, write to the Free Software
19
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
30
#endif /* HAVE_STDINT_H */
31
#include <sys/types.h>
32
#include <sys/param.h>
36
#endif /* HAVE_GETOPT_H */
43
#include <sys/socket.h>
48
#endif /* HAVE_NSS_H */
50
#ifdef HAVE_PTHREAD_NP_H
51
#include <pthread_np.h>
52
#endif /* HAVE_PTHREAD_NP_H */
53
#ifndef HAVE_GETOPT_LONG
54
#include "compat/getopt_long.h"
55
#endif /* not HAVE_GETOPT_LONG */
56
#include "compat/daemon.h"
65
#include "compat/attrs.h"
66
#include "compat/getpeercred.h"
67
#include "compat/socket.h"
69
/* read timeout is half a second because clients should send their request
70
quickly, write timeout is 60 seconds because clients could be taking some
71
time to process the results */
72
#define READ_TIMEOUT 500
73
#define WRITE_TIMEOUT 60*1000
75
/* buffer sizes for I/O */
76
#define READBUFFER_MINSIZE 32
77
#define READBUFFER_MAXSIZE 64
78
#define WRITEBUFFER_MINSIZE 64
79
#define WRITEBUFFER_MAXSIZE 1*1024*1024
81
/* flag to indicate if we are in debugging mode */
82
static int nslcd_debugging=0;
84
/* flag to indicate user requested the --check option */
85
static int nslcd_checkonly=0;
87
/* the exit flag to indicate that a signal was received */
88
static volatile int nslcd_exitsignal=0;
90
/* the server socket used for communication */
91
static int nslcd_serversocket=-1;
93
/* thread ids of all running threads */
94
static pthread_t *nslcd_threads;
96
/* if we don't have clearenv() we have to do this the hard way */
99
/* the definition of the environment */
100
extern char **environ;
102
/* the environment we want to use */
103
static char *sane_environment[] = {
110
#endif /* not HAVE_CLEARENV */
112
/* display version information */
113
static void display_version(FILE *fp)
115
fprintf(fp,"%s\n",PACKAGE_STRING);
116
fprintf(fp,"Written by Luke Howard and Arthur de Jong.\n\n");
117
fprintf(fp,"Copyright (C) 1997-2013 Luke Howard, Arthur de Jong and West Consulting\n"
118
"This is free software; see the source for copying conditions. There is NO\n"
119
"warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n");
122
/* display usage information */
123
static void display_usage(FILE *fp,const char *program_name)
125
fprintf(fp,"Usage: %s [OPTION]...\n",program_name);
126
fprintf(fp,"Name Service LDAP connection daemon.\n");
127
fprintf(fp," -c, --check check if the daemon already is running\n");
128
fprintf(fp," -d, --debug don't fork and print debugging to stderr\n");
129
fprintf(fp," --help display this help and exit\n");
130
fprintf(fp," --version output version information and exit\n");
132
"Report bugs to <%s>.\n",PACKAGE_BUGREPORT);
135
/* the definition of options for getopt(). see getopt(2) */
136
static struct option const nslcd_options[] =
138
{ "check", no_argument, NULL, 'c' },
139
{ "debug", no_argument, NULL, 'd' },
140
{ "help", no_argument, NULL, 'h' },
141
{ "version", no_argument, NULL, 'V' },
144
#define NSLCD_OPTIONSTRING "cdhV"
146
/* parse command line options and save settings in struct */
147
static void parse_cmdline(int argc,char *argv[])
150
while ((optc=getopt_long(argc,argv,NSLCD_OPTIONSTRING,nslcd_options,NULL))!=-1)
154
case 'c': /* -c, --check check if the daemon already is running */
157
case 'd': /* -d, --debug don't fork and print debugging to stderr */
159
log_setdefaultloglevel(LOG_DEBUG);
161
case 'h': /* --help display this help and exit */
162
display_usage(stdout,argv[0]);
164
case 'V': /* --version output version information and exit */
165
display_version(stdout);
167
case ':': /* missing required parameter */
168
case '?': /* unknown option character or extraneous parameter */
170
fprintf(stderr,"Try '%s --help' for more information.\n",
175
/* check for remaining arguments */
178
fprintf(stderr,"%s: unrecognized option '%s'\n",
179
argv[0],argv[optind]);
180
fprintf(stderr,"Try '%s --help' for more information.\n",
186
/* get a name of a signal with a given signal number */
187
static const char *signame(int signum)
191
case SIGHUP: return "SIGHUP"; /* Hangup detected */
192
case SIGINT: return "SIGINT"; /* Interrupt from keyboard */
193
case SIGQUIT: return "SIGQUIT"; /* Quit from keyboard */
194
case SIGILL: return "SIGILL"; /* Illegal Instruction */
195
case SIGABRT: return "SIGABRT"; /* Abort signal from abort(3) */
196
case SIGFPE: return "SIGFPE"; /* Floating point exception */
197
case SIGKILL: return "SIGKILL"; /* Kill signal */
198
case SIGSEGV: return "SIGSEGV"; /* Invalid memory reference */
199
case SIGPIPE: return "SIGPIPE"; /* Broken pipe */
200
case SIGALRM: return "SIGALRM"; /* Timer signal from alarm(2) */
201
case SIGTERM: return "SIGTERM"; /* Termination signal */
202
case SIGUSR1: return "SIGUSR1"; /* User-defined signal 1 */
203
case SIGUSR2: return "SIGUSR2"; /* User-defined signal 2 */
204
case SIGCHLD: return "SIGCHLD"; /* Child stopped or terminated */
205
case SIGCONT: return "SIGCONT"; /* Continue if stopped */
206
case SIGSTOP: return "SIGSTOP"; /* Stop process */
207
case SIGTSTP: return "SIGTSTP"; /* Stop typed at tty */
208
case SIGTTIN: return "SIGTTIN"; /* tty input for background process */
209
case SIGTTOU: return "SIGTTOU"; /* tty output for background process */
211
case SIGBUS: return "SIGBUS"; /* Bus error */
214
case SIGPOLL: return "SIGPOLL"; /* Pollable event */
217
case SIGPROF: return "SIGPROF"; /* Profiling timer expired */
220
case SIGSYS: return "SIGSYS"; /* Bad argument to routine */
223
case SIGTRAP: return "SIGTRAP"; /* Trace/breakpoint trap */
226
case SIGURG: return "SIGURG"; /* Urgent condition on socket */
229
case SIGVTALRM: return "SIGVTALRM"; /* Virtual alarm clock */
232
case SIGXCPU: return "SIGXCPU"; /* CPU time limit exceeded */
235
case SIGXFSZ: return "SIGXFSZ"; /* File size limit exceeded */
237
default: return "UNKNOWN";
241
/* signal handler for closing down */
242
static void sigexit_handler(int signum)
244
/* just save the signal to indicate that we're stopping */
245
nslcd_exitsignal=signum;
248
/* do some cleaning up before terminating */
249
static void exithandler(void)
251
/* close socket if it's still in use */
252
if (nslcd_serversocket >= 0)
254
if (close(nslcd_serversocket))
255
log_log(LOG_WARNING,"problem closing server socket (ignored): %s",strerror(errno));
257
/* remove existing named socket */
258
if (unlink(NSLCD_SOCKET)<0)
260
log_log(LOG_DEBUG,"unlink() of "NSLCD_SOCKET" failed (ignored): %s",
264
if (unlink(NSLCD_PIDFILE)<0)
266
log_log(LOG_DEBUG,"unlink() of "NSLCD_PIDFILE" failed (ignored): %s",
270
log_log(LOG_INFO,"version %s bailing out",VERSION);
273
/* create the directory for the specified file to reside in */
274
static void mkdirname(const char *filename)
277
tmpname=strdup(filename);
278
if (tmpname==NULL) return;
279
path=dirname(tmpname);
280
if (mkdir(path,(mode_t)0755)==0)
282
/* if directory was just created, set correct ownership */
283
if (lchown(path,nslcd_cfg->ldc_uid,nslcd_cfg->ldc_gid)<0)
284
log_log(LOG_WARNING,"problem setting permissions for %s: %s",path,strerror(errno));
289
/* returns a socket ready to answer requests from the client,
291
static int create_socket(const char *filename)
295
struct sockaddr_un addr;
296
/* create a socket */
297
if ( (sock=socket(PF_UNIX,SOCK_STREAM,0))<0 )
299
log_log(LOG_ERR,"cannot create socket: %s",strerror(errno));
302
if (sock>=FD_SETSIZE)
304
log_log(LOG_ERR,"socket file descriptor number too high (%d)",sock);
307
/* remove existing named socket */
308
if (unlink(filename)<0)
310
log_log(LOG_DEBUG,"unlink() of %s failed (ignored): %s",
311
filename,strerror(errno));
313
/* do not block on accept() */
314
if ((i=fcntl(sock,F_GETFL,0))<0)
316
log_log(LOG_ERR,"fctnl(F_GETFL) failed: %s",strerror(errno));
318
log_log(LOG_WARNING,"problem closing socket: %s",strerror(errno));
321
if (fcntl(sock,F_SETFL,i|O_NONBLOCK)<0)
323
log_log(LOG_ERR,"fctnl(F_SETFL,O_NONBLOCK) failed: %s",strerror(errno));
325
log_log(LOG_WARNING,"problem closing socket: %s",strerror(errno));
328
/* create the directory if needed */
330
/* create socket address structure */
331
memset(&addr,0,sizeof(struct sockaddr_un));
332
addr.sun_family=AF_UNIX;
333
strncpy(addr.sun_path,filename,sizeof(addr.sun_path));
334
addr.sun_path[sizeof(addr.sun_path)-1]='\0';
335
/* bind to the named socket */
336
if (bind(sock,(struct sockaddr *)&addr,SUN_LEN(&addr)))
338
log_log(LOG_ERR,"bind() to %s failed: %s",filename,strerror(errno));
340
log_log(LOG_WARNING,"problem closing socket: %s",strerror(errno));
343
/* close the file descriptor on exec */
344
if (fcntl(sock,F_SETFD,FD_CLOEXEC)<0)
346
log_log(LOG_ERR,"fctnl(F_SETFL,FD_CLOEXEC) on %s failed: %s",filename,strerror(errno));
348
log_log(LOG_WARNING,"problem closing socket: %s",strerror(errno));
351
/* set permissions of socket so anybody can do requests */
352
/* Note: we use chmod() here instead of fchmod() because
353
fchmod does not work on sockets
354
http://www.opengroup.org/onlinepubs/009695399/functions/fchmod.html
355
http://lkml.org/lkml/2005/5/16/11 */
356
if (chmod(filename,(mode_t)0666))
358
log_log(LOG_ERR,"chmod(0666) of %s failed: %s",filename,strerror(errno));
360
log_log(LOG_WARNING,"problem closing socket: %s",strerror(errno));
363
/* start listening for connections */
364
if (listen(sock,SOMAXCONN)<0)
366
log_log(LOG_ERR,"listen() failed: %s",strerror(errno));
368
log_log(LOG_WARNING,"problem closing socket: %s",strerror(errno));
375
/* read the version information and action from the stream
376
this function returns the read action in location pointer to by action */
377
static int read_header(TFILE *fp,int32_t *action)
380
/* read the protocol version */
381
READ_TYPE(fp,tmpint32,int32_t);
382
if (tmpint32 != (int32_t)NSLCD_VERSION)
384
log_log(LOG_DEBUG,"wrong nslcd version id (%d)",(int)tmpint32);
387
/* read the request type */
388
READ(fp,action,sizeof(int32_t));
392
/* read a request message, returns <0 in case of errors,
393
this function closes the socket */
394
static void handleconnection(int sock,MYLDAP_SESSION *session)
402
if (getpeercred(sock,&uid,&gid,&pid))
403
log_log(LOG_DEBUG,"connection from unknown client: %s",strerror(errno));
405
log_log(LOG_DEBUG,"connection from pid=%d uid=%d gid=%d",
406
(int)pid,(int)uid,(int)gid);
407
/* create a stream object */
408
if ((fp=tio_fdopen(sock,READ_TIMEOUT,WRITE_TIMEOUT,
409
READBUFFER_MINSIZE,READBUFFER_MAXSIZE,
410
WRITEBUFFER_MINSIZE,WRITEBUFFER_MAXSIZE))==NULL)
412
log_log(LOG_WARNING,"cannot create stream for writing: %s",strerror(errno));
417
if (read_header(fp,&action))
425
case NSLCD_ACTION_CONFIG_GET: (void)nslcd_config_get(fp,session); break;
426
case NSLCD_ACTION_ALIAS_BYNAME: (void)nslcd_alias_byname(fp,session); break;
427
case NSLCD_ACTION_ALIAS_ALL: (void)nslcd_alias_all(fp,session); break;
428
case NSLCD_ACTION_ETHER_BYNAME: (void)nslcd_ether_byname(fp,session); break;
429
case NSLCD_ACTION_ETHER_BYETHER: (void)nslcd_ether_byether(fp,session); break;
430
case NSLCD_ACTION_ETHER_ALL: (void)nslcd_ether_all(fp,session); break;
431
case NSLCD_ACTION_GROUP_BYNAME: (void)nslcd_group_byname(fp,session); break;
432
case NSLCD_ACTION_GROUP_BYGID: (void)nslcd_group_bygid(fp,session); break;
433
case NSLCD_ACTION_GROUP_BYMEMBER: (void)nslcd_group_bymember(fp,session); break;
434
case NSLCD_ACTION_GROUP_ALL: (void)nslcd_group_all(fp,session); break;
435
case NSLCD_ACTION_HOST_BYNAME: (void)nslcd_host_byname(fp,session); break;
436
case NSLCD_ACTION_HOST_BYADDR: (void)nslcd_host_byaddr(fp,session); break;
437
case NSLCD_ACTION_HOST_ALL: (void)nslcd_host_all(fp,session); break;
438
case NSLCD_ACTION_NETGROUP_BYNAME: (void)nslcd_netgroup_byname(fp,session); break;
439
case NSLCD_ACTION_NETWORK_BYNAME: (void)nslcd_network_byname(fp,session); break;
440
case NSLCD_ACTION_NETWORK_BYADDR: (void)nslcd_network_byaddr(fp,session); break;
441
case NSLCD_ACTION_NETWORK_ALL: (void)nslcd_network_all(fp,session); break;
442
case NSLCD_ACTION_PASSWD_BYNAME: (void)nslcd_passwd_byname(fp,session,uid); break;
443
case NSLCD_ACTION_PASSWD_BYUID: (void)nslcd_passwd_byuid(fp,session,uid); break;
444
case NSLCD_ACTION_PASSWD_ALL: (void)nslcd_passwd_all(fp,session,uid); break;
445
case NSLCD_ACTION_PROTOCOL_BYNAME: (void)nslcd_protocol_byname(fp,session); break;
446
case NSLCD_ACTION_PROTOCOL_BYNUMBER:(void)nslcd_protocol_bynumber(fp,session); break;
447
case NSLCD_ACTION_PROTOCOL_ALL: (void)nslcd_protocol_all(fp,session); break;
448
case NSLCD_ACTION_RPC_BYNAME: (void)nslcd_rpc_byname(fp,session); break;
449
case NSLCD_ACTION_RPC_BYNUMBER: (void)nslcd_rpc_bynumber(fp,session); break;
450
case NSLCD_ACTION_RPC_ALL: (void)nslcd_rpc_all(fp,session); break;
451
case NSLCD_ACTION_SERVICE_BYNAME: (void)nslcd_service_byname(fp,session); break;
452
case NSLCD_ACTION_SERVICE_BYNUMBER: (void)nslcd_service_bynumber(fp,session); break;
453
case NSLCD_ACTION_SERVICE_ALL: (void)nslcd_service_all(fp,session); break;
454
case NSLCD_ACTION_SHADOW_BYNAME: if (uid==0) (void)nslcd_shadow_byname(fp,session);
455
else log_log(LOG_DEBUG,"denied shadow request by non-root user"); break;
456
case NSLCD_ACTION_SHADOW_ALL: if (uid==0) (void)nslcd_shadow_all(fp,session);
457
else log_log(LOG_DEBUG,"denied shadow request by non-root user"); break;
458
case NSLCD_ACTION_PAM_AUTHC: (void)nslcd_pam_authc(fp,session,uid); break;
459
case NSLCD_ACTION_PAM_AUTHZ: (void)nslcd_pam_authz(fp,session); break;
460
case NSLCD_ACTION_PAM_SESS_O: (void)nslcd_pam_sess_o(fp,session); break;
461
case NSLCD_ACTION_PAM_SESS_C: (void)nslcd_pam_sess_c(fp,session); break;
462
case NSLCD_ACTION_PAM_PWMOD: (void)nslcd_pam_pwmod(fp,session,uid); break;
464
log_log(LOG_WARNING,"invalid request id: %d",(int)action);
467
/* we're done with the request */
468
myldap_session_cleanup(session);
473
/* test to see if we can lock the specified file */
474
static int is_locked(const char* filename)
480
if ((fd=open(filename,O_RDWR,0644))<0)
483
return 0; /* if file doesn't exist it cannot be locked */
484
log_log(LOG_ERR,"cannot open lock file (%s): %s",filename,strerror(errno));
487
if (lockf(fd,F_TEST,0)<0)
490
log_log(LOG_WARNING,"problem closing fd: %s",strerror(errno));
494
log_log(LOG_WARNING,"problem closing fd: %s",strerror(errno));
499
/* write the current process id to the specified file */
500
static void create_pidfile(const char *filename)
507
if ((fd=open(filename,O_RDWR|O_CREAT,0644))<0)
509
log_log(LOG_ERR,"cannot create pid file (%s): %s",filename,strerror(errno));
512
if (lockf(fd,F_TLOCK,0)<0)
514
log_log(LOG_ERR,"cannot lock pid file (%s): %s",filename,strerror(errno));
517
if (ftruncate(fd,0)<0)
519
log_log(LOG_ERR,"cannot truncate pid file (%s): %s",filename,strerror(errno));
522
mysnprintf(buffer,sizeof(buffer),"%d\n",(int)getpid());
523
if (write(fd,buffer,strlen(buffer))!=(int)strlen(buffer))
525
log_log(LOG_ERR,"error writing pid file (%s): %s",filename,strerror(errno));
528
/* we keep the pidfile open so the lock remains valid */
532
/* try to install signal handler and check result */
533
static void install_sighandler(int signum,void (*handler) (int))
535
struct sigaction act;
536
memset(&act,0,sizeof(struct sigaction));
537
act.sa_handler=handler;
538
sigemptyset(&act.sa_mask);
539
act.sa_flags=SA_RESTART|SA_NOCLDSTOP;
540
if (sigaction(signum,&act,NULL)!=0)
542
log_log(LOG_ERR,"error installing signal handler for '%s': %s",signame(signum),strerror(errno));
547
static void worker_cleanup(void *arg)
549
MYLDAP_SESSION *session=(MYLDAP_SESSION *)arg;
550
myldap_session_close(session);
553
static void *worker(void UNUSED(*arg))
555
MYLDAP_SESSION *session;
558
struct sockaddr_storage addr;
562
/* create a new LDAP session */
563
session=myldap_create_session();
564
/* clean up the session if we're done */
565
pthread_cleanup_push(worker_cleanup,session);
566
/* start waiting for incoming connections */
569
/* time out connection to LDAP server if needed */
570
myldap_session_check(session);
571
/* set up the set of fds to wait on */
573
FD_SET(nslcd_serversocket,&fds);
574
/* set up our timeout value */
575
tv.tv_sec=nslcd_cfg->ldc_idle_timelimit;
577
/* wait for a new connection */
578
j=select(nslcd_serversocket+1,&fds,NULL,NULL,nslcd_cfg->ldc_idle_timelimit>0?&tv:NULL);
579
/* check result of select() */
583
log_log(LOG_DEBUG,"select() failed (ignored): %s",strerror(errno));
585
log_log(LOG_ERR,"select() failed: %s",strerror(errno));
588
/* see if our file descriptor is actually ready */
589
if (!FD_ISSET(nslcd_serversocket,&fds))
591
/* wait for a new connection */
592
alen=(socklen_t)sizeof(struct sockaddr_storage);
593
csock=accept(nslcd_serversocket,(struct sockaddr *)&addr,&alen);
596
if ((errno==EINTR)||(errno==EAGAIN)||(errno==EWOULDBLOCK))
597
log_log(LOG_DEBUG,"accept() failed (ignored): %s",strerror(errno));
599
log_log(LOG_ERR,"accept() failed: %s",strerror(errno));
602
/* make sure O_NONBLOCK is not inherited */
603
if ((j=fcntl(csock,F_GETFL,0))<0)
605
log_log(LOG_ERR,"fctnl(F_GETFL) failed: %s",strerror(errno));
607
log_log(LOG_WARNING,"problem closing socket: %s",strerror(errno));
610
if (fcntl(csock,F_SETFL,j&~O_NONBLOCK)<0)
612
log_log(LOG_ERR,"fctnl(F_SETFL,~O_NONBLOCK) failed: %s",strerror(errno));
614
log_log(LOG_WARNING,"problem closing socket: %s",strerror(errno));
617
/* indicate new connection to logging module (generates unique id) */
619
/* handle the connection */
620
handleconnection(csock,session);
621
/* indicate end of session in log messages */
624
pthread_cleanup_pop(1);
628
/* function to disable lookups through the nss_ldap module to avoid lookup
630
static void disable_nss_ldap(void)
635
/* try to load the NSS module */
637
handle=dlopen(NSS_LDAP_SONAME,RTLD_LAZY|RTLD_NODELETE);
638
#else /* not RTLD_NODELETE */
639
handle=dlopen(NSS_LDAP_SONAME,RTLD_LAZY);
640
#endif /* RTLD_NODELETE */
643
log_log(LOG_WARNING,"Warning: LDAP NSS module not loaded: %s",dlerror());
646
/* clear any existing errors */
648
/* try to look up the flag */
649
enable_flag=(int *)dlsym(handle,"_nss_ldap_enablelookups");
653
log_log(LOG_WARNING,"Warning: %s (probably older NSS module loaded)",error);
654
/* fall back to changing the way host lookup is done */
655
#ifdef HAVE___NSS_CONFIGURE_LOOKUP
656
if (__nss_configure_lookup("hosts","files dns"))
657
log_log(LOG_ERR,"unable to override hosts lookup method: %s",strerror(errno));
658
#endif /* HAVE___NSS_CONFIGURE_LOOKUP */
662
/* disable nss_ldap */
665
/* only close the handle if RTLD_NODELETE was used */
667
#endif /* RTLD_NODELETE */
670
/* the main program... */
671
int main(int argc,char *argv[])
674
sigset_t signalmask,oldmask;
675
#ifdef HAVE_PTHREAD_TIMEDJOIN_NP
677
#endif /* HAVE_PTHREAD_TIMEDJOIN_NP */
678
/* parse the command line */
679
parse_cmdline(argc,argv);
680
/* clean the environment */
684
putenv("TMPDIR=/tmp") ||
685
putenv("LDAPNOINIT=1") )
687
log_log(LOG_ERR,"clearing environment failed");
690
#else /* not HAVE_CLEARENV */
691
/* this is a bit ugly */
692
environ=sane_environment;
693
#endif /* not HAVE_CLEARENV */
694
/* disable the nss_ldap module for this process */
696
/* set LDAP log level */
697
if (myldap_set_debuglevel(nslcd_debugging)!=LDAP_SUCCESS)
699
/* read configuration file */
700
cfg_init(NSLCD_CONF_PATH);
701
/* set default mode for pidfile and socket */
702
(void)umask((mode_t)0022);
703
/* see if someone already locked the pidfile
704
if --check option was given:
705
exit TRUE if daemon runs (pidfile locked), FALSE otherwise */
708
if (is_locked(NSLCD_PIDFILE))
710
log_log(LOG_DEBUG,"pidfile (%s) is locked",NSLCD_PIDFILE);
715
log_log(LOG_DEBUG,"pidfile (%s) is not locked",NSLCD_PIDFILE);
719
/* normal check for pidfile locked */
720
if (is_locked(NSLCD_PIDFILE))
722
log_log(LOG_ERR,"daemon may already be active, cannot acquire lock (%s): %s",NSLCD_PIDFILE,strerror(errno));
725
/* close all file descriptors (except stdin/out/err) */
726
i=sysconf(_SC_OPEN_MAX)-1;
727
/* if the system does not have OPEN_MAX just close the first 32 and
728
hope we closed enough */
734
if ((!nslcd_debugging)&&(daemon(0,0)<0))
736
log_log(LOG_ERR,"unable to daemonize: %s",strerror(errno));
739
/* intilialize logging */
740
if (!nslcd_debugging)
742
log_log(LOG_INFO,"version %s starting",VERSION);
744
create_pidfile(NSLCD_PIDFILE);
745
/* install handler to close stuff off on exit and log notice */
746
if (atexit(exithandler))
748
log_log(LOG_ERR,"atexit() failed: %s",strerror(errno));
752
nslcd_serversocket=create_socket(NSLCD_SOCKET);
753
if ((nslcd_cfg->ldc_gid!=NOGID)&&(nslcd_cfg->ldc_uidname!=NULL))
755
#ifdef HAVE_INITGROUPS
756
/* load supplementary groups */
757
if (initgroups(nslcd_cfg->ldc_uidname,nslcd_cfg->ldc_gid)<0)
758
log_log(LOG_WARNING,"cannot initgroups(\"%s\",%d) (ignored): %s",
759
nslcd_cfg->ldc_uidname,(int)nslcd_cfg->ldc_gid,strerror(errno));
761
log_log(LOG_DEBUG,"initgroups(\"%s\",%d) done",
762
nslcd_cfg->ldc_uidname,(int)nslcd_cfg->ldc_gid);
763
#else /* not HAVE_INITGROUPS */
764
#ifdef HAVE_SETGROUPS
765
/* just drop all supplemental groups */
766
if (setgroups(0,NULL)<0)
767
log_log(LOG_WARNING,"cannot setgroups(0,NULL) (ignored): %s",strerror(errno));
769
log_log(LOG_DEBUG,"setgroups(0,NULL) done");
770
#else /* not HAVE_SETGROUPS */
771
log_log(LOG_DEBUG,"neither initgroups() or setgroups() available");
772
#endif /* not HAVE_SETGROUPS */
773
#endif /* not HAVE_INITGROUPS */
775
/* change to nslcd gid */
776
if (nslcd_cfg->ldc_gid!=NOGID)
778
if (setgid(nslcd_cfg->ldc_gid)!=0)
780
log_log(LOG_ERR,"cannot setgid(%d): %s",(int)nslcd_cfg->ldc_gid,strerror(errno));
783
log_log(LOG_DEBUG,"setgid(%d) done",(int)nslcd_cfg->ldc_gid);
785
/* change to nslcd uid */
786
if (nslcd_cfg->ldc_uid!=NOUID)
788
if (setuid(nslcd_cfg->ldc_uid)!=0)
790
log_log(LOG_ERR,"cannot setuid(%d): %s",(int)nslcd_cfg->ldc_uid,strerror(errno));
793
log_log(LOG_DEBUG,"setuid(%d) done",(int)nslcd_cfg->ldc_uid);
795
/* block all these signals so our worker threads won't handle them */
796
sigemptyset(&signalmask);
797
sigaddset(&signalmask,SIGHUP);
798
sigaddset(&signalmask,SIGINT);
799
sigaddset(&signalmask,SIGQUIT);
800
sigaddset(&signalmask,SIGABRT);
801
sigaddset(&signalmask,SIGPIPE);
802
sigaddset(&signalmask,SIGTERM);
803
sigaddset(&signalmask,SIGUSR1);
804
sigaddset(&signalmask,SIGUSR2);
805
pthread_sigmask(SIG_BLOCK,&signalmask,&oldmask);
806
/* start worker threads */
807
log_log(LOG_INFO,"accepting connections");
808
nslcd_threads=(pthread_t *)malloc(nslcd_cfg->ldc_threads*sizeof(pthread_t));
809
if (nslcd_threads==NULL)
811
log_log(LOG_CRIT,"main(): malloc() failed to allocate memory");
814
for (i=0;i<nslcd_cfg->ldc_threads;i++)
816
if (pthread_create(&nslcd_threads[i],NULL,worker,NULL))
818
log_log(LOG_ERR,"unable to start worker thread %d: %s",i,strerror(errno));
822
pthread_sigmask(SIG_SETMASK,&oldmask,NULL);
823
/* install signalhandlers for some signals */
824
install_sighandler(SIGHUP, sigexit_handler);
825
install_sighandler(SIGINT, sigexit_handler);
826
install_sighandler(SIGQUIT,sigexit_handler);
827
install_sighandler(SIGABRT,sigexit_handler);
828
install_sighandler(SIGPIPE,SIG_IGN);
829
install_sighandler(SIGTERM,sigexit_handler);
830
install_sighandler(SIGUSR1,sigexit_handler);
831
install_sighandler(SIGUSR2,sigexit_handler);
832
/* wait until we received a signal */
833
while (nslcd_exitsignal==0)
835
sleep(INT_MAX); /* sleep as long as we can or until we receive a signal */
837
/* print something about received signal */
838
log_log(LOG_INFO,"caught signal %s (%d), shutting down",
839
signame(nslcd_exitsignal),nslcd_exitsignal);
840
/* cancel all running threads */
841
for (i=0;i<nslcd_cfg->ldc_threads;i++)
842
if (pthread_cancel(nslcd_threads[i]))
843
log_log(LOG_WARNING,"failed to stop thread %d (ignored): %s",i,strerror(errno));
844
/* close server socket to trigger failures in threads waiting on accept() */
845
close(nslcd_serversocket);
846
nslcd_serversocket=-1;
847
/* if we can, wait a few seconds for the threads to finish */
848
#ifdef HAVE_PTHREAD_TIMEDJOIN_NP
849
ts.tv_sec=time(NULL)+3;
851
#endif /* HAVE_PTHREAD_TIMEDJOIN_NP */
852
for (i=0;i<nslcd_cfg->ldc_threads;i++)
854
#ifdef HAVE_PTHREAD_TIMEDJOIN_NP
855
pthread_timedjoin_np(nslcd_threads[i],NULL,&ts);
856
#endif /* HAVE_PTHREAD_TIMEDJOIN_NP */
857
if (pthread_kill(nslcd_threads[i],0)==0)
858
log_log(LOG_ERR,"thread %d is still running, shutting down anyway",i);