summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile.am34
-rw-r--r--configure.ac33
-rw-r--r--log.c187
-rw-r--r--log.h60
-rw-r--r--nslcd-client.c132
-rw-r--r--nslcd-client.h40
-rw-r--r--nslcd-server.c218
-rw-r--r--nslcd-server.h34
-rw-r--r--nslcd.c481
-rw-r--r--nslcd.h76
-rw-r--r--xmalloc.c59
-rw-r--r--xmalloc.h38
12 files changed, 1366 insertions, 26 deletions
diff --git a/Makefile.am b/Makefile.am
index 459510a..3a2bfa7 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,23 +1,25 @@
# Makefile.am - use automake to generate Makefile.in
+#
# Copyright (C) 2006 Luke Howard
# Copyright (C) 2006 West consulting
# Copyright (C) 2006 Arthur de Jong
#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
-# (at your option) any later version.
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Library General Public
+# License as published by the Free Software Foundation; either
+# version 2 of the License, or (at your option) any later version.
#
-# This program is distributed in the hope that it will be useful,
+# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Library General Public License for more details.
#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+# You should have received a copy of the GNU Library General Public
+# License along with this library; if not, write to the Free
+# Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+# MA 02110-1301 USA
-noinst_PROGRAMS = nss_ldap.so
+noinst_PROGRAMS = nss_ldap.so nslcd ndlscdcl
INST_UID=root
if AIX
INST_GID=system
@@ -39,6 +41,16 @@ nss_ldap_so_SOURCES = ldap-nss.c ldap-pwd.c ldap-grp.c ldap-netgrp.c ldap-rpc.c
nss_ldap_so_LDFLAGS = @nss_ldap_so_LDFLAGS@
+nslcd_SOURCES = nslcd.c nslcd.h \
+ nslcd-server.c nslcd-server.h \
+ log.c log.h \
+ xmalloc.c xmalloc.h \
+ ldap-nss.c ldap-schema.c util.c resolve.c \
+ dnsconfig.c pagectrl.c \
+ ldap-pwd.c
+
+ndlscdcl_SOURCES = nslcd-client.c nslcd-client.h nslcd.h
+
NSS_LDAP_PATH_CONF = @NSS_LDAP_PATH_CONF@
NSS_LDAP_PATH_ROOTPASSWD = @NSS_LDAP_PATH_ROOTPASSWD@
diff --git a/configure.ac b/configure.ac
index fa0e157..f720ce3 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,21 +1,23 @@
# configure.ac - process this file with autoconf to produce configure
+#
# Copyright (C) 2006 Luke Howard
# Copyright (C) 2006 West Consulting
# Copyright (C) 2006 Arthur de Jong
#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Library General Public License as published
-# by the Free Software Foundation; either version 2 of the License, or (at
-# your option) any later version.
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Library General Public
+# License as published by the Free Software Foundation; either
+# version 2 of the License, or (at your option) any later version.
#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library
-# General Public License for more details.
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Library General Public License for more details.
#
-# You should have received a copy of the GNU Library General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+# You should have received a copy of the GNU Library General Public
+# License along with this library; if not, write to the Free
+# Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+# MA 02110-1301 USA
AC_PREREQ(2.59)
AC_COPYRIGHT(
@@ -213,10 +215,7 @@ AC_CHECK_HEADERS(net/route.h)
AC_CHECK_HEADERS(netinet/if_ether.h)
AC_CHECK_HEADERS(netinet/ether.h)
AC_CHECK_HEADERS(ctype.h)
-dnl AC_CHECK_HEADERS(db.h)
-dnl AC_CHECK_HEADERS(db1/db.h)
-dnl AC_CHECK_HEADERS(db_185.h)
-dnl AC_CHECK_HEADERS(db3/db_185.h)
+AC_CHECK_HEADERS(getopt.h)
AC_CHECK_HEADERS(alignof.h)
AC_CHECK_HEADERS(rpc/rpcent.h)
AC_CHECK_HEADERS(sys/byteorder.h)
@@ -228,6 +227,7 @@ AC_CHECK_HEADERS(strings.h)
AC_CHECK_HEADERS(gssldap.h)
AC_CHECK_HEADERS(gsssasl.h)
AC_CHECK_HEADERS(gssapi/gssapi_krb5.h gssapi.h)
+AC_CHECK_HEADERS(grp.h)
AC_CHECK_LIB(resolv, main)
AC_CHECK_LIB(nsl, main)
@@ -244,6 +244,9 @@ AC_CHECK_FUNCS(nsdispatch)
AC_CHECK_FUNCS(pthread_atfork)
AC_CHECK_FUNCS(ether_aton)
AC_CHECK_FUNCS(ether_ntoa)
+AC_CHECK_FUNCS(setgroups)
+
+AC_TYPE_SIGNAL
AC_MSG_CHECKING(for struct ether_addr)
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <sys/types.h>
diff --git a/log.c b/log.c
new file mode 100644
index 0000000..f3083a9
--- /dev/null
+++ b/log.c
@@ -0,0 +1,187 @@
+/*
+ log.c - logging funtions
+
+ Copyright (C) 2002, 2003 Arthur de Jong.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ MA 02110-1301 USA
+*/
+
+
+#include "config.h"
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <syslog.h>
+#include <stdarg.h>
+#include <errno.h>
+#include <string.h>
+
+#include "log.h"
+#include "xmalloc.h"
+
+
+/* set the logname */
+#undef PACKAGE
+#define PACKAGE "nslcd"
+
+
+/* storage for logging modes */
+static struct cvsd_log {
+ FILE *fp; /* NULL==syslog */
+ int loglevel;
+ struct cvsd_log *next;
+} *cvsd_loglist=NULL;
+
+
+/* default loglevel when no logging is configured */
+static int prelogging_loglevel=LOG_INFO;
+
+
+/* set loglevel when no logging is configured */
+void log_setdefaultloglevel(int loglevel)
+{
+ prelogging_loglevel=loglevel;
+}
+
+
+/* add logging method to configuration list */
+static void log_addlogging_fp(FILE *fp,int loglevel)
+{
+ struct cvsd_log *tmp,*lst;
+ /* create new logstruct */
+ tmp=(struct cvsd_log *)xmalloc(sizeof(struct cvsd_log));
+ tmp->fp=fp;
+ tmp->loglevel=loglevel;
+ tmp->next=NULL;
+ /* save the struct in the list */
+ if (cvsd_loglist==NULL)
+ cvsd_loglist=tmp;
+ else
+ {
+ for (lst=cvsd_loglist;lst->next!=NULL;lst=lst->next);
+ lst->next=tmp;
+ }
+}
+
+
+/* configure logging to a file */
+void log_addlogging_file(const char *filename,int loglevel)
+{
+ FILE *fp;
+ fp=fopen(filename,"a");
+ if (fp==NULL)
+ {
+ log_log(LOG_ERR,"cannot open logfile (%s) for appending: %s",filename,strerror(errno));
+ exit(1);
+ }
+ log_addlogging_fp(fp,loglevel);
+}
+
+
+/* configure logging to syslog */
+void log_addlogging_syslog(int loglevel)
+{
+ openlog(PACKAGE,LOG_PID,LOG_DAEMON);
+ log_addlogging_fp(NULL,loglevel);
+}
+
+
+/* configure a null logging mode (no logging) */
+void log_addlogging_none()
+{
+ /* this is a hack, but it's so easy */
+ log_addlogging_fp(NULL,LOG_EMERG);
+}
+
+
+/* start the logging with the configured logging methods
+ if no method is configured yet, logging is done to syslog */
+void log_startlogging(void)
+{
+ if (cvsd_loglist==NULL)
+ log_addlogging_syslog(LOG_INFO);
+ prelogging_loglevel=-1;
+}
+
+
+/* log the given message using the configured logging method */
+void log_log(int pri,const char *format, ...)
+{
+ int res;
+ struct cvsd_log *lst;
+ /* TODO: make this something better */
+ #define maxbufferlen 120
+ char buffer[maxbufferlen];
+ va_list ap;
+ /* make the message */
+ va_start(ap,format);
+ res=vsnprintf(buffer,maxbufferlen,format,ap);
+ if ((res<0)||(res>=maxbufferlen))
+ {
+ /* truncate with "..." */
+ buffer[maxbufferlen-2]='.';
+ buffer[maxbufferlen-3]='.';
+ buffer[maxbufferlen-4]='.';
+ }
+ buffer[maxbufferlen-1]='\0';
+ va_end(ap);
+ /* do the logging */
+ if (prelogging_loglevel>=0)
+ {
+ /* if logging is not yet defined, log to stderr */
+ if (pri<=prelogging_loglevel)
+ fprintf(stderr,"%s: %s\n",PACKAGE,buffer);
+ }
+ else
+ {
+ for (lst=cvsd_loglist;lst!=NULL;lst=lst->next)
+ {
+ if (pri<=lst->loglevel)
+ {
+ if (lst->fp==NULL) /* syslog */
+ syslog(pri,"%s",buffer);
+ else /* file */
+ {
+ fprintf(lst->fp,"%s: %s\n",PACKAGE,buffer);
+ fflush(lst->fp);
+ }
+ }
+ }
+ }
+}
+
+
+/* return the syslog loglevel represented by the string
+ return -1 on unknown */
+int log_getloglevel(const char *lvl)
+{
+ if ( strcmp(lvl,"crit")==0 )
+ return LOG_CRIT;
+ else if ( (strcmp(lvl,"error")==0) ||
+ (strcmp(lvl,"err")==0) )
+ return LOG_ERR;
+ else if ( strcmp(lvl,"warning")==0 )
+ return LOG_WARNING;
+ else if ( strcmp(lvl,"notice")==0 )
+ return LOG_NOTICE;
+ else if ( strcmp(lvl,"info")==0 )
+ return LOG_INFO;
+ else if ( strcmp(lvl,"debug")==0 )
+ return LOG_DEBUG;
+ else
+ return -1; /* unknown */
+}
diff --git a/log.h b/log.h
new file mode 100644
index 0000000..0cadbeb
--- /dev/null
+++ b/log.h
@@ -0,0 +1,60 @@
+/*
+ log.h - definitions of logging funtions
+
+ Copyright (C) 2002, 2003 Arthur de Jong.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ MA 02110-1301 USA
+*/
+
+
+#ifndef _LOG_H
+#define _LOG_H 1
+
+
+#include <syslog.h>
+
+
+/* set loglevel when no logging is configured */
+void log_setdefaultloglevel(int loglevel);
+
+
+/* configure logging to a file */
+void log_addlogging_file(const char *filename,int loglevel);
+
+
+/* configure logging to syslog */
+void log_addlogging_syslog(int loglevel);
+
+
+/* configure a null logging mode (no logging) */
+void log_addlogging_none(void);
+
+
+/* start the logging with the configured logging methods
+ if no method is configured yet, logging is done to syslog */
+void log_startlogging(void);
+
+
+/* log the given message using the configured logging method */
+void log_log(int pri,const char *format, ...);
+
+
+/* return the syslog loglevel represented by the string
+ return -1 on unknown */
+int log_getloglevel(const char *lvl);
+
+
+#endif /* not _LOG_H */
diff --git a/nslcd-client.c b/nslcd-client.c
new file mode 100644
index 0000000..cfb91d5
--- /dev/null
+++ b/nslcd-client.c
@@ -0,0 +1,132 @@
+/*
+ nslcd-client.c - request/response functions for nslcd communication
+
+ Copyright (C) 2006 West Consulting
+ Copyright (C) 2006 Arthur de Jong
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ MA 02110-1301 USA
+*/
+
+#include <stdint.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <errno.h>
+
+#include "nslcd-client.h"
+
+
+/* returns a socket to the server or NULL on error (see errno),
+ socket should be closed with fclose() */
+FILE *nslcd_client_open()
+{
+ int sock;
+ struct sockaddr_un addr;
+ FILE *fp;
+ /* create a socket */
+ if ( (sock=socket(PF_UNIX,SOCK_STREAM,0))<0 )
+ return NULL;
+ /* create socket address structure */
+ addr.sun_family=AF_UNIX;
+ strcpy(addr.sun_path,NSLCD_SOCKET);
+ /* connect to the socket */
+ if (connect(sock,(struct sockaddr *)&addr,sizeof(struct sockaddr_un))<0)
+ {
+ close(sock);
+ return NULL;
+ }
+ /* create a stream object */
+ if ((fp=fdopen(sock,"w+"))==NULL)
+ {
+ close(sock);
+ return NULL;
+ }
+ /* return the stream */
+ return fp;
+}
+
+
+/* helper marco for writes, bails out on any write problems */
+#define WRITE(socket, buf, count) \
+ if (fwrite(buf, 1, count, socket) < (count)) \
+ { return -1; }
+
+
+/* helper macro for writing 32-bit integer values, uses tmpint32 as
+ temporary value (should be defined by caller) */
+#define WRITE_INT32(socket, i) \
+ tmpint32 = (int32_t)(i); \
+ WRITE(socket, &tmpint32, sizeof(int32_t))
+
+
+/* write a request message, returns <0 in case of errors */
+int nslcd_client_writerequest(FILE *sock,int type,char *name,size_t count)
+{
+ int32_t tmpint32;
+ /* see nslcd.h for protocol definition */
+ WRITE_INT32(sock, NSLCD_VERSION);
+ WRITE_INT32(sock, type);
+ WRITE_INT32(sock, count);
+ WRITE(sock, name, count);
+ WRITE_INT32(sock, NSLCD_MAGIC);
+ if (fflush(sock)<0)
+ return -1;
+ return 0; /* success */
+}
+
+
+/* read a response message */
+int nslcd_client_readresponse(FILE *sock,void *buf,size_t bufsize)
+{
+ /* see nslcd.h for protocol definition */
+ /* TODO: validate */
+ return -1; /* not implemented */
+}
+
+
+/* the main program... , for now just for testing */
+int main(int argc,char *argv[])
+{
+ FILE *sock;
+ char buf[1024];
+ /* open socket */
+ if ((sock=nslcd_client_open())==NULL)
+ {
+ fprintf(stderr,"test: socket unavailable: %s\n", strerror(errno));
+ return 1;
+ }
+ /* write request */
+ if (nslcd_client_writerequest(sock,NSLCD_RT_GETPWBYNAME,"aart",6)<0)
+ {
+ fprintf(stderr,"test: write failed: %s\n", strerror(errno));
+ return 1;
+ }
+ /* read response */
+ if (nslcd_client_readresponse(sock,buf,1024)<0)
+ {
+ fprintf(stderr,"test: read failed: %s\n", strerror(errno));
+ return 1;
+ }
+ /* print results */
+
+
+ /* close */
+ fclose(sock);
+ return 0;
+}
diff --git a/nslcd-client.h b/nslcd-client.h
new file mode 100644
index 0000000..4511695
--- /dev/null
+++ b/nslcd-client.h
@@ -0,0 +1,40 @@
+/*
+ nslcd-client.c - request/response functions for nslcd communication
+
+ Copyright (C) 2006 West Consulting
+ Copyright (C) 2006 Arthur de Jong
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ MA 02110-1301 USA
+*/
+
+#ifndef _NSLCD_CLIENT_H
+#define _NSLCD_CLIENT_H 1
+
+#include <stdio.h>
+
+#include "nslcd.h"
+
+/* returns a socket to the server or NULL on error (see errno),
+ socket should be closed with fclose() */
+FILE *nslcd_client_open(void);
+
+/* write a request message, returns <0 in case of errors */
+int nslcd_client_writerequest(FILE *sock,int type,char *name,size_t count);
+
+/* read a response message */
+int nslcd_client_readresponse(FILE *sock,void *buf,size_t bufsize);
+
+#endif /* not _NSLCD_CLIENT_H */
diff --git a/nslcd-server.c b/nslcd-server.c
new file mode 100644
index 0000000..e464752
--- /dev/null
+++ b/nslcd-server.c
@@ -0,0 +1,218 @@
+/*
+ nslcd-server.c - server socket routines
+
+ Copyright (C) 2006 West Consulting
+ Copyright (C) 2006 Arthur de Jong
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ MA 02110-1301 USA
+*/
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <malloc.h>
+#include <stdio.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <errno.h>
+#include <fcntl.h>
+
+/* temp added for ldap requests */
+#include <pwd.h>
+#include <ldap.h>
+#include "ldap-nss.h"
+
+#include "nslcd-server.h"
+#include "log.h"
+
+
+/* returns a socket ready to answer requests from the client,
+ return <0 on error */
+int nslcd_server_open(void)
+{
+ int sock;
+ /*int flag;*/
+ struct sockaddr_un addr;
+
+ /* create a socket */
+ if ( (sock=socket(PF_UNIX,SOCK_STREAM,0))<0 )
+ {
+ log_log(LOG_ERR,"cannot create socket: %s",strerror(errno));
+ exit(1);
+ }
+
+ /* create socket address structure */
+ addr.sun_family=AF_UNIX;
+ strcpy(addr.sun_path,NSLCD_SOCKET);
+
+ /* unlink to socket */
+ if (unlink(NSLCD_SOCKET)<0)
+ {
+ log_log(LOG_DEBUG,"unlink() of "NSLCD_SOCKET" failed (ignored): %s",
+ strerror(errno));
+ }
+
+ /* bind to the socket */
+ if (bind(sock,(struct sockaddr *)&addr,sizeof(struct sockaddr_un))<0)
+ {
+ log_log(LOG_ERR,"bind() to "NSLCD_SOCKET" failed: %s",
+ strerror(errno));
+ if (close(sock))
+ log_log(LOG_WARNING,"problem closing socket: %s",strerror(errno));
+ exit(1);
+ }
+
+#ifdef NONBLOCKING
+ /* we are going to block for now and implement threading later on */
+ /* do not block on accept() */
+ if ((flag=fcntl(sock,F_GETFL,0))<0)
+ {
+ log_log(LOG_ERR,"fctnl(F_GETFL) failed: %s",strerror(errno));
+ if (close(sock))
+ log_log(LOG_WARNING,"problem closing socket: %s",strerror(errno));
+ exit(1);
+ }
+ if (fcntl(sock,F_SETFL,flag|O_NONBLOCK)<0)
+ {
+ log_log(LOG_ERR,"fctnl(F_SETFL,O_NONBLOCK) failed: %s",strerror(errno));
+ if (close(sock))
+ log_log(LOG_WARNING,"problem closing socket: %s",strerror(errno));
+ exit(1);
+ }
+#endif /* NONBLOCKING */
+
+ /* close the file descriptor on exit */
+ if (fcntl(sock,F_SETFD,FD_CLOEXEC)<0)
+ {
+ log_log(LOG_ERR,"fctnl(F_SETFL,O_NONBLOCK) failed: %s",strerror(errno));
+ if (close(sock))
+ log_log(LOG_WARNING,"problem closing socket: %s",strerror(errno));
+ exit(1);
+ }
+
+#ifdef DONT_FOR_NOW
+ /* Set permissions for the socket. */
+ chmod (_PATH_NSCDSOCKET, DEFFILEMODE);
+#endif /* DONT_FOR_NOW */
+
+ /* start listening for connections */
+ if (listen(sock,SOMAXCONN)<0)
+ {
+ log_log(LOG_ERR,"listen() failed: %s",strerror(errno));
+ if (close(sock))
+ log_log(LOG_WARNING,"problem closing socket: %s",strerror(errno));
+ exit(1);
+ }
+
+ /* we're done */
+ return sock;
+}
+
+/* FIXME: the following write can fail with EINTR */
+
+/* helper marco for writes, bails out on any write problems */
+#define WRITE(sock, buf, count) \
+ if (write(sock, buf, count) < (count)) \
+ { close(sock); return -1; }
+
+/* helper macro for writing 32-bit integer values, uses tmpint32 as
+ temporary value (should be defined by caller) */
+#define WRITE_INT32(sock, i) \
+ tmpint32 = (int32_t)(i); \
+ WRITE(sock, &tmpint32, sizeof(int32_t))
+
+/* FIXME: the following read can fail with EINTR */
+
+#define READ(sock, buf, count) \
+ if (read(sock, buf, count) < (count)) \
+ { close(sock); return -1; }
+
+/* helper macro for writing 32-bit integer values, uses tmpint32 as
+ temporary value (should be defined by caller) */
+#define READ_INT32(sock, i) \
+ READ(sock, &tmpint32, sizeof(int32_t)); \
+ i = tmpint32;
+
+
+/* temp decl here */
+enum nss_status
+_nss_ldap_parse_pw (LDAPMessage * e,
+ struct ldap_state * pvt,
+ void *result, char *buffer, size_t buflen);
+
+
+
+/* handle a connection */
+static int nslcd_server_handlerequest(int type, char *key)
+{
+ struct passwd result;
+ enum nss_status s;
+ char buffer[1024];
+ int errnop;
+ struct ldap_args args;
+
+ printf("request id=%d key=%s\n", (int)type, key);
+
+ switch (type)
+ {
+ case NSLCD_RT_GETPWBYNAME:
+ LA_INIT(args);
+ LA_STRING(args) = key;
+ LA_TYPE(args) = LA_TYPE_STRING;
+ s=_nss_ldap_getbyname(&args,&result,buffer,1024,&errnop,_nss_ldap_filt_getpwnam,LM_PASSWD,_nss_ldap_parse_pw);
+ /* TODO: print s, result and buffer */
+ break;
+ default:
+ return -1;
+ }
+
+ return 0; /* success */
+}
+
+/* read a request message, returns <0 in case of errors,
+ on errors, socket is closed by callee */
+int nslcd_server_readrequest(int sock)
+{
+ int32_t tmpint32, tmp2, type;
+ size_t count;
+ char *key;
+ READ_INT32(sock, tmp2);
+ if (tmp2 != NSLCD_VERSION)
+ return -1; /* FIXME: report protocol error */
+ READ_INT32(sock, type);
+ READ_INT32(sock, count);
+ key = (char *)malloc(count+1);
+ if (key == NULL)
+ return -1; /* FIXME: report memory allocation errors */
+ READ(sock, key, count);
+ key[count]=0;
+ READ_INT32(sock, tmp2);
+ if (tmp2 != NSLCD_MAGIC)
+ return -1; /* FIXME: report protocol error */
+
+ /* pass the request to the request handler */
+ return nslcd_server_handlerequest(type, key);
+}
+
+/* read a response message */
+int nslcd_client_writeresponse(int sock, void *buf)
+{
+ /* TODO: validate */
+ return -1; /* not implemented */
+}
+
+
+/* probably use fwrite and fiends */
diff --git a/nslcd-server.h b/nslcd-server.h
new file mode 100644
index 0000000..8796721
--- /dev/null
+++ b/nslcd-server.h
@@ -0,0 +1,34 @@
+/*
+ nslcd-server.h - server socket routines
+
+ Copyright (C) 2006 West Consulting
+ Copyright (C) 2006 Arthur de Jong
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ MA 02110-1301 USA
+*/
+
+#include "nslcd.h"
+
+/* returns a socket ready to answer requests from the client,
+ return <0 on error */
+int nslcd_server_open(void);
+
+/* read a request message, returns <0 in case of errors,
+ on errors, socket is closed by callee */
+int nslcd_server_readrequest(int socket);
+
+/* write a response message */
+int nslcd_client_writeresponse(int socket, void *buf);
diff --git a/nslcd.c b/nslcd.c
new file mode 100644
index 0000000..56e2ab8
--- /dev/null
+++ b/nslcd.c
@@ -0,0 +1,481 @@
+/*
+ nslcd.c - ldap local connection daemon
+
+ Copyright (C) 2006 West Consulting
+ Copyright (C) 2006 Arthur de Jong
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ MA 02110-1301 USA
+*/
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/wait.h>
+#include <string.h>
+#include <stdio.h>
+#ifdef HAVE_LBER_H
+#include <lber.h>
+#endif /* HAVE_LBER_H */
+#ifdef HAVE_LDAP_H
+#include <ldap.h>
+#endif /* HAVE_LDAP_H */
+#if defined(HAVE_THREAD_H)
+#include <thread.h>
+#elif defined(HAVE_PTHREAD_H)
+#include <pthread.h>
+#endif
+#ifdef HAVE_GETOPT_H
+#include <getopt.h>
+#endif /* HAVE_GETOPT_H */
+#include <assert.h>
+#include <signal.h>
+#include <errno.h>
+#include <unistd.h>
+#include <fcntl.h>
+#ifdef HAVE_GRP_H
+#include <grp.h>
+#endif /* HAVE_GRP_H */
+#include <sys/stat.h>
+
+#include "ldap-nss.h"
+#include "util.h"
+#include "nslcd.h"
+#include "nslcd-server.h"
+#include "xmalloc.h"
+#include "log.h"
+
+
+/* the definition of the environment */
+extern char **environ;
+
+
+/* flag to indictate if we are in debugging mode */
+static int nslcd_debugging=0;
+
+
+/* the exit flag to indicate that a signal was received */
+static volatile int nslcd_exitsignal=0;
+
+
+/* the server socket used for communication */
+static int nslcd_serversocket=-1;
+
+/* the number of seconds to sleep when no more
+ connections can be listened for */
+#define SLEEPSECS 5
+
+
+/* display version information */
+static void display_version(FILE *fp)
+{
+ fprintf(fp,"%s\n",PACKAGE_STRING);
+ fprintf(fp,"Written by Luke Howard and Arthur de Jong.\n\n");
+ fprintf(fp,"Copyright (C) 1997-2006 Luke Howard and Arthur de Jong\n"
+ "This is free software; see the source for copying conditions. There is NO\n"
+ "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n");
+}
+
+
+/* display usage information to stdout and exit(status) */
+static void display_usage(FILE *fp, const char *program_name)
+{
+ fprintf(fp,"Usage: %s [OPTION]...\n",program_name);
+ fprintf(fp,"Name Service LDAP connection daemon.\n");
+ fprintf(fp," -f, --config=FILE use FILE as configfile (default %s)\n",NSS_LDAP_PATH_CONF);
+ fprintf(fp," -d, --debug don't fork and print debugging to stderr\n");
+ fprintf(fp," --help display this help and exit\n");
+ fprintf(fp," --version output version information and exit\n");
+ fprintf(fp,"\n"
+ "Report bugs to <%s>.\n",PACKAGE_BUGREPORT);
+}
+
+
+/* the definition of options for getopt(). see getopt(2) */
+static struct option const nslcd_options[] =
+{
+ { "debug", no_argument, NULL, 'd' },
+ { "help", no_argument, NULL, 'h' },
+ { "version", no_argument, NULL, 'V' },
+ { NULL, 0, NULL, 0 }
+};
+#define NSLCD_OPTIONSTRING "dhV"
+
+
+/* parse command line options and save settings in struct */
+static void parse_cmdline(int argc,char *argv[])
+{
+ int optc;
+ while ((optc=getopt_long(argc,argv,NSLCD_OPTIONSTRING,nslcd_options,NULL))!=-1)
+ {
+ switch (optc)
+ {
+ case 'd': /* -d, --debug don't fork and print debugging to stderr */
+ nslcd_debugging=1;
+ log_setdefaultloglevel(LOG_DEBUG);
+ break;
+ case 'h': /* --help display this help and exit */
+ display_usage(stdout,argv[0]);
+ exit(0);
+ case 'V': /* --version output version information and exit */
+ display_version(stdout);
+ exit(0);
+ case ':': /* missing required parameter */
+ case '?': /* unknown option character or extraneous parameter */
+ default:
+ fprintf(stderr,"Try `%s --help' for more information.\n",
+ argv[0]);
+ exit(1);
+ }
+ }
+ /* check for remaining arguments */
+ if (optind<argc)
+ {
+ fprintf(stderr,"%s: unrecognized option `%s'\n",
+ argv[0],argv[optind]);
+ fprintf(stderr,"Try `%s --help' for more information.\n",
+ argv[0]);
+ exit(1);
+ }
+}
+
+
+/* get a name of a signal with a given signal number */
+static const char *signame(int signum)
+{
+ switch (signum)
+ {
+ case SIGHUP: return "SIGHUP"; /* Hangup detected */
+ case SIGINT: return "SIGINT"; /* Interrupt from keyboard */
+ case SIGQUIT: return "SIGQUIT"; /* Quit from keyboard */
+ case SIGILL: return "SIGILL"; /* Illegal Instruction */
+ case SIGABRT: return "SIGABRT"; /* Abort signal from abort(3) */
+ case SIGFPE: return "SIGFPE"; /* Floating point exception */
+ case SIGKILL: return "SIGKILL"; /* Kill signal */
+ case SIGSEGV: return "SIGSEGV"; /* Invalid memory reference */
+ case SIGPIPE: return "SIGPIPE"; /* Broken pipe */
+ case SIGALRM: return "SIGALRM"; /* Timer signal from alarm(2) */
+ case SIGTERM: return "SIGTERM"; /* Termination signal */
+ case SIGUSR1: return "SIGUSR1"; /* User-defined signal 1 */
+ case SIGUSR2: return "SIGUSR2"; /* User-defined signal 2 */
+ case SIGCHLD: return "SIGCHLD"; /* Child stopped or terminated */
+ case SIGCONT: return "SIGCONT"; /* Continue if stopped */
+ case SIGSTOP: return "SIGSTOP"; /* Stop process */
+ case SIGTSTP: return "SIGTSTP"; /* Stop typed at tty */
+ case SIGTTIN: return "SIGTTIN"; /* tty input for background process */
+ case SIGTTOU: return "SIGTTOU"; /* tty output for background process */
+#ifdef SIGBUS
+ case SIGBUS: return "SIGBUS"; /* Bus error */
+#endif
+#ifdef SIGPOLL
+ case SIGPOLL: return "SIGPOLL"; /* Pollable event */
+#endif
+#ifdef SIGPROF
+ case SIGPROF: return "SIGPROF"; /* Profiling timer expired */
+#endif
+#ifdef SIGSYS
+ case SIGSYS: return "SIGSYS"; /* Bad argument to routine */
+#endif
+#ifdef SIGTRAP
+ case SIGTRAP: return "SIGTRAP"; /* Trace/breakpoint trap */
+#endif
+#ifdef SIGURG
+ case SIGURG: return "SIGURG"; /* Urgent condition on socket */
+#endif
+#ifdef SIGVTALRM
+ case SIGVTALRM: return "SIGVTALRM"; /* Virtual alarm clock */
+#endif
+#ifdef SIGXCPU
+ case SIGXCPU: return "SIGXCPU"; /* CPU time limit exceeded */
+#endif
+#ifdef SIGXFSZ
+ case SIGXFSZ: return "SIGXFSZ"; /* File size limit exceeded */
+#endif
+ default: return "UNKNOWN";
+ }
+}
+
+
+/* signal handler for closing down */
+static RETSIGTYPE sigexit_handler(int signum)
+{
+ nslcd_exitsignal=signum;
+}
+
+
+/* do some cleaning up before terminating */
+static void exithandler(void)
+{
+ if (nslcd_serversocket >= 0)
+ {
+ if (close(nslcd_serversocket))
+ log_log(LOG_WARNING,"problem closing server socket (ignored): %s",strerror(errno));
+ }
+ log_log(LOG_INFO,"version %s bailing out",VERSION);
+}
+
+
+/* handle a connection by doing fork() and stuff */
+static void handleconnection(int csock)
+{
+ socklen_t alen;
+ struct ucred client;
+
+ /* look up process information from client */
+ alen=sizeof(struct ucred);
+ if (getsockopt(csock,SOL_SOCKET,SO_PEERCRED,&client,&alen) < 0)
+ {
+ log_log(LOG_ERR,"getsockopt(SO_PEERCRED) failed: %s", strerror(errno));
+ if (close(csock))
+ log_log(LOG_WARNING,"problem closing socket: %s",strerror(errno));
+ return;
+ }
+
+ /* log connection */
+ log_log(LOG_INFO,"connection from pid=%d uid=%d gid=%d",
+ (int)client.pid,(int)client.uid,(int)client.gid);
+
+ /* FIXME: implement handling of connection */
+
+ nslcd_server_readrequest(csock);
+
+}
+
+
+/* accept a connection on the socket */
+static void acceptconnection(void)
+{
+ int csock;
+ int j;
+ struct sockaddr_storage addr;
+ socklen_t alen;
+
+ /* accept a new connection */
+ alen=(socklen_t)sizeof(struct sockaddr_storage);
+ csock=accept(nslcd_serversocket,(struct sockaddr *)&addr,&alen);
+ if (csock<0)
+ {
+ if ((errno==EINTR)||(errno==EAGAIN)||(errno==EWOULDBLOCK))
+ {
+ log_log(LOG_DEBUG,"debug: accept() failed (ignored): %s",strerror(errno));
+ return;
+ }
+ log_log(LOG_ERR,"accept() failed: %s",strerror(errno));
+ return;
+ }
+
+ /* make sure O_NONBLOCK is not inherited */
+ if ((j=fcntl(csock,F_GETFL,0))<0)
+ {
+ log_log(LOG_ERR,"fctnl(F_GETFL) failed: %s",strerror(errno));
+ if (close(csock))
+ log_log(LOG_WARNING,"problem closing socket: %s",strerror(errno));
+ return;
+ }
+ if (fcntl(csock,F_SETFL,j&~O_NONBLOCK)<0)
+ {
+ log_log(LOG_ERR,"fctnl(F_SETFL,~O_NONBLOCK) failed: %s",strerror(errno));
+ if (close(csock))
+ log_log(LOG_WARNING,"problem closing socket: %s",strerror(errno));
+ return;
+ }
+
+ /* handle the connection */
+ handleconnection(csock);
+}
+
+
+/* write the current process id to the specified file */
+static void write_pidfile(const char *filename)
+{
+ FILE *fp;
+ if (filename!=NULL)
+ {
+ if ((fp=fopen(filename,"w"))==NULL)
+ {
+ log_log(LOG_ERR,"cannot open pid file (%s): %s",filename,strerror(errno));
+ exit(1);
+ }
+ if (fprintf(fp,"%d\n",(int)getpid())<=0)
+ {
+ log_log(LOG_ERR,"error writing pid file (%s)",filename);
+ exit(1);
+ }
+ if (fclose(fp))
+ {
+ log_log(LOG_ERR,"error writing pid file (%s): %s",filename,strerror(errno));
+ exit(1);
+ }
+ }
+}
+
+
+/* try to install signal handler and check result */
+static void install_sighandler(int signum,RETSIGTYPE (*handler) (int))
+{
+ struct sigaction act;
+ memset(&act,0,sizeof(struct sigaction));
+ act.sa_handler=handler;
+ sigemptyset(&act.sa_mask);
+ act.sa_flags=SA_RESTART|SA_NOCLDSTOP;
+ if (sigaction(signum,&act,NULL)!=0)
+ {
+ log_log(LOG_ERR,"error installing signal handler for '%s': %s",signame(signum),strerror(errno));
+ exit(1);
+ }
+}
+
+
+/* the main program... */
+int main(int argc,char *argv[])
+{
+ gid_t mygid=-1;
+ uid_t myuid=-1;
+
+ /* parse the command line */
+ parse_cmdline(argc,argv);
+
+ /* clear the environment */
+ /* TODO:implement */
+
+ /* check if we are already running */
+ /* FIXME: implement */
+
+ /* daemonize */
+ if ((!nslcd_debugging)&&(daemon(0,0)<0))
+ {
+ log_log(LOG_ERR,"unable to daemonize: %s",strerror(errno));
+ exit(1);
+ }
+
+ /* set default mode for pidfile and socket */
+ umask(0022);
+
+ /* intilialize logging */
+ if (!nslcd_debugging)
+ log_startlogging();
+ log_log(LOG_INFO,"version %s starting",VERSION);
+
+ /* install handler to close stuff off on exit and log notice */
+ atexit(exithandler);
+
+ /* write pidfile */
+ write_pidfile(NSLCD_PIDFILE);
+
+ /* create socket */
+ nslcd_serversocket=nslcd_server_open();
+
+#ifdef HAVE_SETGROUPS
+ /* drop all supplemental groups */
+ if (setgroups(0,NULL)<0)
+ {
+ log_log(LOG_WARNING,"cannot setgroups(0,NULL) (ignored): %s",strerror(errno));
+ }
+ else
+ {
+ log_log(LOG_DEBUG,"debug: setgroups(0,NULL) done");
+ }
+#else /* HAVE_SETGROUPS */
+ log_log(LOG_DEBUG,"debug: setgroups() not available");
+#endif /* not HAVE_SETGROUPS */
+
+#ifdef USE_CAPABILITIES
+ /* if we are using capbilities, set them to be kept
+ across setuid() calls so we can limit them later on */
+ if (prctl(PR_SET_KEEPCAPS,1))
+ {
+ log_log(LOG_ERR,"cannot prctl(PR_SET_KEEPCAPS,1): %s",strerror(errno));
+ exit(1);
+ }
+ log_log(LOG_DEBUG,"debug: prctl(PR_SET_KEEPCAPS,1) done");
+ /* dump the current capabilities */
+ caps=cap_get_proc();
+ log_log(LOG_DEBUG,"debug: current capabilities: %s",cap_to_text(caps,NULL));
+ cap_free(caps);
+#endif /* USE_CAPABILITIES */
+
+ /* change to nslcd gid */
+ if (mygid!=((gid_t)-1))
+ {
+ if (setgid(mygid)!=0)
+ {
+ log_log(LOG_ERR,"cannot setgid(%d): %s",(int)mygid,strerror(errno));
+ exit(1);
+ }
+ log_log(LOG_DEBUG,"debug: setgid(%d) done",mygid);
+ }
+
+ /* change to nslcd uid */
+ if (myuid!=((uid_t)-1))
+ {
+ if (setuid(myuid)!=0)
+ {
+ log_log(LOG_ERR,"cannot setuid(%d): %s",(int)myuid,strerror(errno));
+ exit(1);
+ }
+ log_log(LOG_DEBUG,"debug: setuid(%d) done",myuid);
+ }
+
+#ifdef USE_CAPABILITIES
+ /* limit the capabilities */
+ if (cap_set_proc(mycapabilities)!=0)
+ {
+ log_log(LOG_ERR,"cannot cap_set_proc(%s): %s",cap_to_text(mycapabilities,NULL),strerror(errno));
+ exit(1);
+ }
+ log_log(LOG_DEBUG,"debug: cap_set_proc(%2) done",cap_to_text(mycapabilities,NULL));
+ /* we no longer need this so we should free it */
+ cap_free(mycapabilities);
+ /* dump the current capabilities */
+ caps=cap_get_proc();
+ log_log(LOG_DEBUG,"debug: current capabilities: %s",cap_to_text(caps,NULL));
+ cap_free(caps);
+#endif /* USE_CAPABILITIES */
+
+ /* install signalhandlers for some other signals */
+ install_sighandler(SIGHUP, sigexit_handler);
+ install_sighandler(SIGINT, sigexit_handler);
+ install_sighandler(SIGQUIT,sigexit_handler);
+ install_sighandler(SIGILL, sigexit_handler);
+ install_sighandler(SIGABRT,sigexit_handler);
+ install_sighandler(SIGSEGV,sigexit_handler);
+ install_sighandler(SIGPIPE,sigexit_handler);
+ install_sighandler(SIGALRM,sigexit_handler);
+ install_sighandler(SIGTERM,sigexit_handler);
+ install_sighandler(SIGUSR1,sigexit_handler);
+ install_sighandler(SIGUSR2,sigexit_handler);
+
+ /* TODO: install signal handlers for reloading configuration */
+
+ log_log(LOG_INFO,"accepting connections");
+
+ /* start waiting for incoming connections */
+ while (nslcd_exitsignal==0)
+ {
+ /* wait for a new connection */
+ acceptconnection();
+ }
+
+ /* print something about received signals */
+ if (nslcd_exitsignal!=0)
+ {
+ log_log(LOG_INFO,"caught signal %s (%d), shutting down",
+ signame(nslcd_exitsignal),nslcd_exitsignal);
+ }
+
+ return 1;
+}
diff --git a/nslcd.h b/nslcd.h
new file mode 100644
index 0000000..42d7676
--- /dev/null
+++ b/nslcd.h
@@ -0,0 +1,76 @@
+/*
+ nslcd.h - file describing client/server protocol
+
+ Copyright (C) 2006 West Consulting
+ Copyright (C) 2006 Arthur de Jong
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ MA 02110-1301 USA
+*/
+
+#ifndef _NSLCD_H
+#define _NSLCD_H 1
+
+/*
+ A request messages basically looks like:
+ int32 NSLCD_VERSION
+ int32 NSLCD_RT_*
+ int32 length(name)
+ ... name
+ int32 NSLCD_MAGIC
+ (any messages not fitting this should be ignored
+ closing the connection)
+ A response looks like:
+ int32 NSLCD_VERSION
+ int32 NSLCD_RT_* (the original request type)
+ int32 length(result)
+ ... result
+ int32 NSLCD_MAGIC
+*/
+
+/* TODO: generate this file from a .in file */
+
+/* The location of the socket used for communicating. */
+#define NSLCD_SOCKET "/tmp/nslcd.socket"
+
+/* The location of the pidfile used for checking availability of the nslcd. */
+#define NSLCD_PIDFILE "/tmp/nslcd.pid"
+
+/* The current version of the protocol. */
+#define NSLCD_VERSION 1
+
+/* The magic number passed back and forth. This is to reducte the change of
+ handling non-valid requests (e.g. some random data). */
+#define NSLCD_MAGIC 0x8642
+
+/* Request types. */
+#define NSLCD_RT_GETPWBYNAME 1
+#define NSLCD_RT_GETPWBYUID 2
+#define NSLCD_RT_GETGRBYNAME 3
+#define NSLCD_RT_GETGRBYGID 4
+#define NSLCD_RT_GETHOSTBYNAME 5
+#define NSLCD_RT_GETHOSTBYNAMEv6 7
+#define NSLCD_RT_GETHOSTBYADDR 8
+#define NSLCD_RT_GETHOSTBYADDRv6 9
+#define NSLCD_RT_LASTDBREQ NSLCD_RT_GETHOSTBYADDRv6
+
+/* Request result. */
+#define NSLCD_RS_TRYAGAIN 1
+#define NSLCD_RS_UNAVAIL 2
+#define NSLCD_RS_NOTFOUND 3
+#define NSLCD_RS_SUCCESS 0
+#define NSLCD_RS_RETURN 4
+
+#endif /* not _NSLCD_H */
diff --git a/xmalloc.c b/xmalloc.c
new file mode 100644
index 0000000..f316ad8
--- /dev/null
+++ b/xmalloc.c
@@ -0,0 +1,59 @@
+/*
+ xmalloc.c - malloc wrapper
+
+ Copyright (C) 2002, 2003, 2006 Arthur de Jong.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ MA 02110-1301 USA
+*/
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "xmalloc.h"
+#include "log.h"
+
+
+/* malloc wrapper */
+void *xmalloc(size_t size)
+{
+ void *tmp;
+ if ((tmp=malloc(size))==NULL)
+ {
+ log_log(LOG_CRIT,"malloc() failed");
+ exit(1);
+ }
+ return tmp;
+}
+
+
+/* strdup wrapper */
+char *xstrdup(const char *s)
+{
+ char *tmp;
+ int l;
+ if (s==NULL)
+ {
+ log_log(LOG_CRIT,"xstrdup() called with NULL");
+ exit(1);
+ }
+ l=strlen(s);
+ tmp=(char *)xmalloc((l+1)*sizeof(char));
+ strncpy(tmp,s,l);
+ tmp[l]='\0';
+ return tmp;
+}
diff --git a/xmalloc.h b/xmalloc.h
new file mode 100644
index 0000000..d361a7b
--- /dev/null
+++ b/xmalloc.h
@@ -0,0 +1,38 @@
+/*
+ xmalloc.h - malloc wrapper
+
+ Copyright (C) 2002 Arthur de Jong.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ MA 02110-1301 USA
+*/
+
+
+#ifndef _XMALLOC_H
+#define _XMALLOC_H 1
+
+
+#include <stdlib.h>
+
+
+/* malloc wrapper */
+void *xmalloc(size_t size);
+
+
+/* strdup wrapper */
+char *xstrdup(const char *s);
+
+
+#endif /* not _XMALLOC_H */