diff options
-rw-r--r-- | Makefile.am | 34 | ||||
-rw-r--r-- | configure.ac | 33 | ||||
-rw-r--r-- | log.c | 187 | ||||
-rw-r--r-- | log.h | 60 | ||||
-rw-r--r-- | nslcd-client.c | 132 | ||||
-rw-r--r-- | nslcd-client.h | 40 | ||||
-rw-r--r-- | nslcd-server.c | 218 | ||||
-rw-r--r-- | nslcd-server.h | 34 | ||||
-rw-r--r-- | nslcd.c | 481 | ||||
-rw-r--r-- | nslcd.h | 76 | ||||
-rw-r--r-- | xmalloc.c | 59 | ||||
-rw-r--r-- | xmalloc.h | 38 |
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> @@ -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 */ +} @@ -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); @@ -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; +} @@ -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 */ |