diff --git a/.hgignore b/.hgignore index 51f099d..b803631 100644 --- a/.hgignore +++ b/.hgignore @@ -10,6 +10,8 @@ ^autom4te.cache/ ^config\.log$ ^config\.status$ +^contrib/ncp_nss_lib/libnss_ncp\.so\.2$ +^contrib/ncp_nss_lib/test_ncp_nss$ ^contrib/pam/Makefile$ ^contrib/php/Makefile$ ^contrib/php/Makefile\.in$ diff --git a/.patches/ncpfs-2.2.6-r6/ncpfs-hg-commit-448.patch b/.patches/ncpfs-2.2.6-r6/ncpfs-hg-commit-448.patch new file mode 100644 index 0000000..1d3d25b --- /dev/null +++ b/.patches/ncpfs-2.2.6-r6/ncpfs-hg-commit-448.patch @@ -0,0 +1,4136 @@ +changeset: 448:1a8455ed3290 +user: Patrick Pollet +date: Sun Oct 16 02:40:25 2005 +0200 +files: .hgignore contrib/ncp_nss_lib/Makefile contrib/ncp_nss_lib/ncpfs.conf contrib/ncp_nss_lib/nss_cfgfile.c contrib/ncp_nss_lib/nss_cfgfile.h contrib/ncp_nss_lib/nss_ncp.c contrib/ncp_nss_lib/nss_ncp.h contrib/ncp_nss_lib/test_ncp_nss.c +description: +Add ncp_nss_lib to the ncpfs. Originally written in 2003. + + +diff -r 3143e61fb504 -r 1a8455ed3290 .hgignore +--- a/.hgignore Thu Sep 29 23:06:24 2005 +0200 ++++ b/.hgignore Sun Oct 16 02:40:25 2005 +0200 +@@ -10,6 +10,8 @@ + ^autom4te.cache/ + ^config\.log$ + ^config\.status$ ++^contrib/ncp_nss_lib/libnss_ncp\.so\.2$ ++^contrib/ncp_nss_lib/test_ncp_nss$ + ^contrib/pam/Makefile$ + ^contrib/php/Makefile$ + ^contrib/php/Makefile\.in$ +diff -r 3143e61fb504 -r 1a8455ed3290 contrib/ncp_nss_lib/Makefile +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/contrib/ncp_nss_lib/Makefile Sun Oct 16 02:40:25 2005 +0200 +@@ -0,0 +1,111 @@ ++# ++# ++# ++ ++top_srcdir = ../.. ++top_builddir = ../.. ++this_srcdir = ${top_srcdir}/lib ++ ++include ${top_builddir}/Make.rules ++ ++VERSION_SOLIB := 2 ++VERSION_SONAME := 2.3 ++ ++vpath %.c ${this_srcdir} ++ ++LIBS := ++REENTRANT_CFLAGS := -D_REENTRANT ++VERSIONED_LINK := yes ++ ++SHARED_NSSLIB := libnss_ncp.so ++SHARED_NSSLIB_BIN := $(SHARED_NSSLIB).$(VERSION_SOLIB) ++SHARED_NSSLIB_SONAME := $(SHARED_NSSLIB).$(VERSION_SONAME) ++ ++O_UTILS1 = test_ncp_nss.o\ ++ # ++O_TMP1 = ++UTILS1 = $(O_UTILS1:%.o=%) ++ ++CCFLAGS += -I. ++PIC_FLAGS := -fPIC ++NWCOMPAT := 1 ++ ++SHARED_VLINK := ++SHARED_VLINK_CFLAGS := ++ifeq ($(VERSIONED_LINK),yes) ++SHARED_VLINK := -Wl,-version-script=${this_srcdir}/libncp.vers ++SHARED_VLINK_CFLAGS := -DMULTIVERSION ++endif ++ ++ifeq ($(HAVE_ELF),yes) ++NCP_LIB = libncp.so ++NCPLIB_DIR = ../../lib ++LIBDEP = $(NCPLIB_DIR)/$(NCP_LIB) ++else ++NCP_LIB = libncp.a ++NCPLIB_DIR = ../../lib ++LIBDEP = $(NCPLIB_DIR)/$(NCP_LIB) ++endif ++ ++STATIC_BASE_OBJ := nss_ncp.o nss_cfgfile.o ++SHARED_BASE_OBJ := $(STATIC_BASE_OBJ:.o=.do) ++ ++SHARED_O_OBJ := $(SHARED_BASE_OBJ) ++ ++BASE_CFLAGS := -DHAVE_CONFIG_H -DMAKE_NCPLIB -D_GNU_SOURCE ++ ++SHARED_CFLAGS := $(CFLAGS) $(CCFLAGS) $(REENTRANT_CFLAGS) $(PIC_FLAGS) $(SHARED_VLINK_CFLAGS) ++ ++ ++.PHONY : all dep install install-dev clean mrproper distclean ++.PHONY : install_shared install_static install_static_su ++ ++all: $(SHARED_NSSLIB) $(UTILS1) ++ ++install: install_shared ++ ++%.d: %.c %h ++ set -e; $(CC) -M $(STATIC_CFLAGS) $(CFLAGS_$(@:.d=.o)) $(BASE_CFLAGS) $< \ ++ | sed 's,\($*\)\.o[ :]*,\1.o \1.do \1.to $@ : ,g' > $@; \ ++ [ -s $@ ] || rm -f $@ ++ ++$(STATIC_BASE_OBJ): %.o: %.c %.h ++ $(CC) $(STATIC_CFLAGS) $(CFLAGS_$@) $(BASE_CFLAGS) -o $@ -c $< ++ ++ ++$(SHARED_BASE_OBJ): %.do: %.c %.h ++ $(CC) $(SHARED_CFLAGS) $(CFLAGS_$(@:.do=.o)) $(BASE_CFLAGS) -o $@ -c $< ++ ++ ++$(O_UTILS1) $(O_TMP1): %.o: %.c ++ $(CC) $(CCFLAGS) $(CFLAGS) $(CFLAGS_$@) -o $@ -c $< ++ ++$(UTILS1):: %: %.o $(O_TMP1) ++ $(CC) $(LDFLAGS) $(CFLAGS) -o $@ $(addsuffix .o,$@) $(OBJS_$@) -L$(top_builddir)/lib -lnss_ncp -lncp $(LDFLAGS_$@) ++ ++ ++dep: ++ ++clean: ++ rm -f *.o *.do *.to *~ ++ ++mrproper: clean ++ rm -f $(UTILS) $(DISTFILE) ++ ++distclean: mrproper ++ ++install_shared: $(SHARED_NCPLIB_BIN) ++ $(INSTALL) -d $(DESTDIR)$(libsodir) ++ $(INSTALL) $(SHARED_NCPLIB_BIN) $(DESTDIR)$(libsodir) ++ -ldconfig ++ ++ ++$(SHARED_NSSLIB): $(SHARED_NSSLIB_BIN) ++ rm -f $@ ++ ln -sf $< $@ ++ ++$(SHARED_NSSLIB_BIN): $(SHARED_O_OBJ) ${this_srcdir}/libncp.vers ++ $(CC) -shared -o $@ -Wl,-soname=$(SHARED_NSSLIB_SONAME) $(SHARED_VLINK) $(SHARED_O_OBJ) -L$(NCPLIB_DIR) -lncp ${LIBS} ++ ++ ++ +diff -r 3143e61fb504 -r 1a8455ed3290 contrib/ncp_nss_lib/ncpfs.conf +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/contrib/ncp_nss_lib/ncpfs.conf Sun Oct 16 02:40:25 2005 +0200 +@@ -0,0 +1,29 @@ ++[Requester] ++ ++ ++[ncp_nss] ++useTree=1 ++server=INSA_ROOT ++startCtx= ++ctrlGroup= ++doPasswd=1 ++doShadow=1 ++doGroup=1 ++ ++defGid=100 ++defShell=/bin/bash ++debug=1 ++ ++fallbackUid=-1 ++fallbackGid=-1 ++ ++[pam] ++useTree=1 ++server=INSA_ROOT ++searchCtx=PC,S.PC,GCP.PC ++debug=1 ++mountLocally=1 ++createLocalHome=0 ++ ++zenOn= ++zenOff= +diff -r 3143e61fb504 -r 1a8455ed3290 contrib/ncp_nss_lib/nss_cfgfile.c +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/contrib/ncp_nss_lib/nss_cfgfile.c Sun Oct 16 02:40:25 2005 +0200 +@@ -0,0 +1,333 @@ ++/* ++ nss_cfgfile.c - Configuration file handling ++ Copyright (C) 2000 Petr Vandrovec ++ Copyright (C) 2003 Patrick Pollet ++ ++ 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 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 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ ++ Revision history: ++ ++ 1.00 2003, Jan 16 Patrick Pollet ++ Initial revision, stronly inspired by ncpfs/lib/cfgfile.c ++ ++ ++ */ ++ ++#include "config.h" ++ ++ ++#include "private/libncp-lock.h" ++ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "nss_cfgfile.h" ++// temporary define (waiting for a better Makefile) ++#define GLOBALCFGFILE "/etc/ncpfs.conf" ++#ifndef GLOBALCFGFILE ++#error "GLOBALCFGFILE must be defined" ++#endif ++ ++ ++// #define DEBUG 1 ++ ++static struct nss_ncp_conf* alloc_nss_ncp_conf (){ ++ struct nss_ncp_conf * conf; ++ ++ conf= (struct nss_ncp_conf *)malloc(sizeof(*conf)); ++ if (!conf) ++ return NULL; ++ return conf; ++} ++ ++ ++void free_nss_ncp_conf (struct nss_ncp_conf *conf){ ++#define FREEFIELD(x) do if (conf->x) {free(conf->x) ; conf->x=NULL;} while (0); ++ if (conf && conf !=&defConf) { ++ FREEFIELD(server); ++ FREEFIELD(startCtx); ++ FREEFIELD(ctrlGroup); ++ FREEFIELD(defShell); ++ } ++#undef FREEFIELD ++} ++ ++ ++struct cfgFile { ++ ncpt_mutex_t mutex; ++ FILE* file; ++}; ++ ++static struct cfgFile* cfgOpenFile( ++ const char* path, ++ int writeRequired) { ++ struct cfgFile* cfg; ++ ++ cfg = (struct cfgFile*)malloc(sizeof(*cfg)); ++ if (cfg) { ++ cfg->file = fopen(path, writeRequired ? "r+" : "r"); ++ if (cfg->file) { ++ ncpt_mutex_init(&cfg->mutex); ++ } else { ++ free(cfg); ++ cfg = NULL; ++ } ++ } ++ return cfg; ++} ++ ++static void cfgClose( ++ struct cfgFile* cfg) { ++ ncpt_mutex_lock(&cfg->mutex); ++ fclose(cfg->file); ++ ncpt_mutex_destroy(&cfg->mutex); ++ free(cfg); ++} ++ ++ ++struct check { ++ const char *option; /* configuration option */ ++ int mandatory; /* can be empty or null */ ++ int found; /*set to TRUE if found in cfg file */ ++ void ** value_ptr; /* temporary storage place */ ++ int isNum; /* 1 is numeric, 0 is string*/ ++ const char* defValue; ++}; ++ ++ ++#ifdef DEBUG ++void printResults (const char * infos,struct check * results) { ++ struct check* ptr; ++ printf ("%s\n",infos); ++ for (ptr=results; ptr->option; ptr++) { ++ if (ptr->isNum) ++ printf ("option=%s mandatory=%d found=%d value=%d isNum=%d defvalue=%s\n", ++ ptr->option,ptr->mandatory,ptr->found,(int*)*ptr->value_ptr,ptr->isNum,ptr->defValue); ++ else ++ printf ("option=%s mandatory=%d found=%d value=%s isNum=%d defvalue=%s\n", ++ ptr->option,ptr->mandatory,ptr->found,(char*)*ptr->value_ptr,ptr->isNum,ptr->defValue); ++ } ++ ++} ++ ++void printConf (const char* infos,struct nss_ncp_conf * conf) { ++ printf ("%s\n",infos); ++ printf ("debug=%d useTree=%d server=%s startCtx=%s ctrlGroup=%s defGid=%d defShell=%s fallbackUid=%d fallbackGid=%d " ++ "doPassword=%d doGroup=%d doShadow=%d\n", ++ conf->debug,conf->useTree,conf->server,conf->startCtx, ++ conf->ctrlGroup,conf->defGid,conf->defShell,conf->fallbackUid,conf->fallbackGid, ++ conf->doPassword,conf->doGroup,conf->doShadow); ++} ++#endif ++ ++ ++static int process_line (char* cptr, struct check *ptr) { ++ ++ char* sptr; // start of real value ++ char* eptr; // end of real value ++ char* errPtr; // err ++ ++ char ec; ++ char cc; ++ ++ while (*cptr && isspace(*cptr)) ++ cptr++; ++ if (*cptr != '=' && *cptr != ':') ++ return 1; //no equal sign found ++ cptr++; ++ ++ while (*cptr && isspace(*cptr)) ++ cptr++; ++ ++ // space are allowed in value only if surrounded by " or ' (eg a NDS control group) ++ if (*cptr == '"' || *cptr == '\'') ++ ec = *cptr++; ++ else ++ ec = 0; ++ sptr=cptr; ++ eptr=cptr; ++ while ((cc = *cptr++) != 0) { ++ if (cc == '\n') ++ break; ++ if (!ec && isspace(cc)) ++ break; ++ if (cc == ec) ++ break; ++ eptr++; ++ } ++ *eptr = 0; ++ if (ptr->isNum) { ++ (int *)*ptr->value_ptr=strtoul (sptr,&errPtr,0); ++ ptr->found= ((*sptr) && !(*errPtr)); //not empty and no error ++ } else { ++ if (eptr>sptr) { // do not take an empty string value ++ char *v=strdup(sptr); ++ if (v) { ++ (char*) *ptr->value_ptr=v; ++ ptr->found= TRUE; ++ }else ++ return 1; ++ } ++ } ++ ++ return 0; ++} ++ ++static int fix_conf (struct check *results) { ++ struct check* ptr; ++ ++ for (ptr=results; ptr->option; ptr++) { ++ if (! ptr->found) { ++ if (ptr->mandatory) { ++ traceForce(0,LOG_ERR, "ncp_nss aborting :missing mandatory information '%s=' in config file %s ",ptr->option,GLOBALCFGFILE); ++ return 1; ++ } ++ if (ptr->isNum) { ++ (int *)*ptr->value_ptr=strtoul (ptr->defValue,NULL,0); ++ }else { ++ char * v=strdup(ptr->defValue); ++ if (v) ++ (char*) *ptr->value_ptr=v; ++ else ++ return 1; ++ } ++ } ++ } ++ return 0; ++} ++ ++ ++static struct nss_ncp_conf *read_conf_file( const char * mySection, struct cfgFile *cfg) { ++ ++ struct nss_ncp_conf *conf; ++ ++ conf=alloc_nss_ncp_conf (); ++ if (!conf) ++ return NULL; ++ { ++ struct nss_ncp_conf * pconf=conf; ++ struct check check_confs[] = { ++ /*option mandat found value_ptr isNum defValue */ ++ {"debug", FALSE,FALSE,(void**)&conf->debug, TRUE, "0"}, ++ {"useTree", FALSE,FALSE,(void**)&conf->useTree, TRUE, "0"}, ++ {"server", TRUE,FALSE, (void**)&conf->server, FALSE, ""}, ++ {"startCtx", FALSE,FALSE,(void**)&conf->startCtx, FALSE, ""}, ++ {"ctrlGroup", FALSE,FALSE,(void**)&conf->ctrlGroup, FALSE, ""}, ++ {"defGid", FALSE,FALSE,(void**)&conf->defGid, TRUE, "100"}, ++ {"defShell", FALSE,FALSE,(void**)&conf->defShell, FALSE, "/bin/bash"}, ++ {"fallbackUid", FALSE,FALSE,(void**)&conf->fallbackUid, TRUE, "-1"}, ++ {"fallbackGid", FALSE,FALSE,(void**)&conf->fallbackGid, TRUE, "-1"}, ++ {"doPasswd", FALSE,FALSE,(void**)&conf->doPassword, TRUE, "0"}, ++ {"doGroup", FALSE,FALSE,(void**)&conf->doGroup, TRUE, "0"}, ++ {"doShadow", FALSE,FALSE,(void**)&conf->doShadow, TRUE, "0"}, ++ {NULL , FALSE,FALSE,NULL, FALSE, NULL} ++ }; ++ ++ char cfgline[16384]; ++ size_t seclen = strlen(mySection); ++ ++ ++#ifdef DEBUG ++// DO NOT DO IT A a second call (using test_ncp_nss -2) coredump !!! ++// printResults("before reading CFG",check_confs); ++#endif ++ ncpt_mutex_lock(&cfg->mutex); ++ //rewind(cfg->file); ++ while (fgets(cfgline, sizeof(cfgline)-1, cfg->file)) { ++ char* cptr = cfgline; ++ struct check* ptr; ++ ++ while (*cptr && isspace(*cptr)) ++ cptr++; ++ if (*cptr != '[') ++ continue; ++sstart:; ++ if (strncasecmp(++cptr, mySection, seclen)) ++ continue; ++ if (cptr[seclen] != ']') ++ continue; ++ while (fgets(cfgline, sizeof(cfgline) - 1, cfg->file)) { ++ cptr = cfgline; ++ ++ while (*cptr && isspace(*cptr)) ++ cptr++; ++ if (!*cptr) ++ continue; //empty line ++ if (*cptr == '[') // start of another section ++ goto ssend; ++ for (ptr=check_confs; ptr->option; ptr++) { ++ size_t keylen=strlen(ptr->option); ++ if (!strncasecmp(cptr, ptr->option,keylen)) { ++ cptr += keylen; ++ process_line (cptr,ptr); ++ } ++ } ++ } ++ } ++ ++ssend: ++#ifdef DEBUG ++ printResults("after reading CFG no error",check_confs); ++#endif ++#ifdef DEBUG ++ printConf("before fixing ",conf); ++#endif ++ ++ if (!fix_conf (check_confs)) { // fill in missing values with default, ++#ifdef DEBUG ++ printConf("after fixing ",conf); ++#endif ++ ncpt_mutex_unlock(&cfg->mutex); ++ return conf; ++ } ++ ++error: ++#ifdef DEBUG ++ printResults("after reading CFG error",check_confs); ++#endif ++ ncpt_mutex_unlock(&cfg->mutex); ++ free_nss_ncp_conf(conf); ++ return NULL; ++ } ++ ++} ++ ++struct nss_ncp_conf * parse_conf (char * confFile) { ++ ++ struct cfgFile *cfg; ++ struct nss_ncp_conf *conf; ++#ifdef DEBUG ++ printf("entering parse_conf\n"); ++#endif ++ //return &defConf; ++ cfg = cfgOpenFile(GLOBALCFGFILE, FALSE); ++ if (!cfg) ++ return NULL; ++ conf=read_conf_file(NSS_SECTION,cfg); ++ cfgClose(cfg); ++#ifdef DEBUG ++ if (conf) ++ printConf("final value ",conf); ++#endif ++ ++ return conf; ++} ++ +diff -r 3143e61fb504 -r 1a8455ed3290 contrib/ncp_nss_lib/nss_cfgfile.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/contrib/ncp_nss_lib/nss_cfgfile.h Sun Oct 16 02:40:25 2005 +0200 +@@ -0,0 +1,30 @@ ++#ifndef HAVE_NSS_CFGFILE ++#define HAVE_NSS_CFGFILE ++ ++#define TRUE 1 ++#define FALSE 0 ++ ++#define NSS_SECTION "ncp_nss" ++struct nss_ncp_conf { ++ int debug; ++ int useTree; // use Tree connection or server connection ++ char * server; // name of server or tree ++ char * startCtx; // start searching is this context (and below) ++ char * ctrlGroup; // limit search to members of this NDS group for passwd and shadow ++ gid_t defGid; // if no primary group found in NDS use this value ++ char * defShell; // if no shell found in NDS use this value ++ uid_t fallbackUid; // if no UID found in NDS use this one (-1= skip user, NFS_NOBODY= use this UID) ++ gid_t fallbackGid; // if no GID found in NDS use this one (-1= skip group, NFS_NOBODY= use this GID) ++ int doPassword; // if 0, will return immediarly NSS_STATUS_UNAVAILABLE even if ncp is listed in /etc/nsswitch.conf ++ int doGroup; // if 0, will return immediarly NSS_STATUS_UNAVAILABLE even if ncp is listed in /etc/nsswitch.conf ++ int doShadow; // if 0, will return immediarly NSS_STATUS_UNAVAILABLE even if ncp is listed in /etc/nsswitch.conf ++}; ++ ++ ++ ++static struct nss_ncp_conf defConf ={0,TRUE,"INSA_ROOT","[Root]",NULL,100,"/bin/bash",-1,-1,TRUE,TRUE,TRUE}; ++ ++struct nss_ncp_conf * parse_conf (char * confFile); ++void free_nss_ncp_conf (struct nss_ncp_conf *conf); ++ ++#endif +diff -r 3143e61fb504 -r 1a8455ed3290 contrib/ncp_nss_lib/nss_ncp.c +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/contrib/ncp_nss_lib/nss_ncp.c Sun Oct 16 02:40:25 2005 +0200 +@@ -0,0 +1,3091 @@ ++/************************************************************************** ++ nss_ncp.c NSS module for NDS ++ ++ Copyright (C) 2002 Patrick Pollet ++ ++ 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 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 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ ++ ++ Revision history: ++ ++ 1.00 2003, January 06 Patrick Pollet ++ initial release ++ 1.01 2003, January 08 Patrick Pollet ++ added conf structure and control group ++ added optional fallback UID and GID if none found in NDS (default is to skip user,group) ++ 1.02 2003, January 09 Patrick Pollet ++ added initgroups ++ 1.03 2003, January 10 Patrick Pollet ++ fixed bug in nds_user_info2 (bad structure received by nds_user_location2) ++ 1.04 2003, January 11 Patrick Pollet ++ fixed setting ndsXXX=NULL trees in case of errors in _nss_ncp_setxxent() ++ made always NAME_CONTEXT=[Root] in CreateContextAndConn ++ calling NWCCloseIteration only it some errors has occured in the search ++ 1.05 2003, January 15 Patrick Pollet ++ -Avoid multiple reading of conf file by removing recursive calls ++ in nss_ncp_getxxent_r in case a entry has no Unix infos in NDS ++ (replaced by a goto nextuser) ++ -Added missing free_nw_xxx_info when leaving nss_ncp_getxxent_r (fixed memory leaks) ++ -Added testing for failure in allocating tree structure in nss_ncp_setxxent_r ++ -if (id !=(uid_t)-1) and not if (id) in getentxx if we search by UID !!!! ++ -getentbyxx give a warning in syslog if more that one entry match the name or id search criteria ++ 1.06 2003, January 16 Patrick Pollet ++ -implemented reading of configuration file in /etc/nss_ncp.conf ++ -in case of fatal errors, force log in syslog by using calls to traceForce ( previously fatal ++ errors were only reported in debug mode, since the syslog file is not opened in normal mode) ++ 1.07 2003, January 16 Patrick Pollet ++ Speed up the search: ++ 1)config informations are stored in the internal trees structures ++ when calling nss_ncp_setxxent_r and freed by nss_ncp_endxxent_r ++ so we don't read again config file at every call to nss_ncp_getxxent_r ++ 2) group infos are really slow with big groups,so we added a flag doGroup in conf file ++ to skip the search (easier that to edit /etc/nsswitch.conf AND restarting nscd daemon). ++************************************************************************/ ++ ++ ++#include ++#include ++#include ++#include ++#include ++ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#include "nss_ncp.h" ++#include "nss_cfgfile.h" ++ ++// only if logfile has been opened by nss API functions (debug mode) ++void trace (int debugMode,int err,const char * format,... ) { ++ va_list args; ++ if (debugMode) { ++ va_start(args,format); ++ vsyslog (err,format,args); ++ va_end(args); ++ } ++} ++ ++// send a message to syslog even if log file not opened (debugMode is false) ++// needed for critical errors such a bad config file or ambiguous NDS search ++void traceForce (int debugMode,int err, const char * format,... ) { ++ va_list args; ++ ++ if (!debugMode) ++ openlog("ncp_nss", LOG_PID, LOG_AUTHPRIV); ++ va_start(args,format); ++ vsyslog (err,format,args); ++ va_end(args); ++ if (!debugMode) ++ closelog(); ++ ++} ++ ++ ++static int ++getnumber(int *val, const char **str) ++{ ++ const char *p = *str; ++ char *z; ++ ++ if (!*p) ++ return 1; ++ if (*p == ',') { ++ *str = p + 1; ++ return 1; ++ } ++ *val = strtoul(p, &z, 0); ++ if (p == z) ++ return -1; ++ if (*z == ',') ++ z++; ++ *str = z; ++ return 0; ++} ++ ++static char* copy_to_buffer (char ** buffer, size_t *buflen, char * value) { ++// copy the value to buffer , decrease buflen and return start of the value in buffer ++ size_t len=strlen(value)+1; ++ char * ptr=*buffer; ++ ++ if (len > *buflen) { ++ return NULL; ++ } ++ memcpy(*buffer, value, len); ++ *buflen -=len; ++ (*buffer) +=len; ++ return ptr; ++} ++ ++/********** ++struct nss_ncp_conf { ++ int debug; ++ int useTree; // use Tree connection or server connection ++ char * server; // name of server or tree ++ char * startCtx; // start searching is this context (and below) ++ char * ctrlGroup; // limit search to members of this NDS group for passwd and shadow ++ gid_t defGid; // if no primary group found in NDS use this value ++ char * defShell; // if no shell found in NDS use this value ++ uid_t fallbackUid; // if no UID found in NDS use this one (-1= skip user, NFS_NOBODY= use this UID) ++ gid_t fallbackGid; // if no GID found in NDS use this one (-1= skip group, NFS_NOBODY= use this GID) ++ int doPassword; // if 0, will return immediarly NSS_STATUS_UNAVAILABLE even if ncp is listed in /etc/nsswitch.conf ++ int doGroup; // if 0, will return immediarly NSS_STATUS_UNAVAILABLE even if ncp is listed in /etc/nsswitch.conf ++ int doShadow; // if 0, will return immediarly NSS_STATUS_UNAVAILABLE even if ncp is listed in /etc/nsswitch.conf ++}; ++**************/ ++ ++//one day we will read it from /etc/ncp_nss.conf ++ ++ ++/****************************************** internal structure for storing NDS user's password infos ***/ ++struct nw_user_info { ++ char * cn; ++ char * gecos; ++ char * shell; ++ char * dir; ++ char * fullName; ++ char * passwd; ++ uid_t uid; ++ gid_t gid; ++ int qflag; ++ ++ }; ++ ++static void init_nw_user_info (struct nw_user_info *ui,int qflag){ ++ ui->cn=NULL; ++ ui->gecos=NULL; ++ ui->shell=NULL; ++ ui->dir=NULL; ++ ui->fullName=NULL; ++ ui->passwd=NULL; ++ ui->uid=(uid_t)-1; ++ ui->gid=(gid_t)-1; ++ ui->qflag= qflag; ++} ++ ++static void free_nw_user_info (struct nw_user_info *ui){ ++#define FREEFIELD(x) do if (ui->x) {free(ui->x) ; ui->x=NULL;} while (0); ++ FREEFIELD(cn); ++ FREEFIELD(gecos); ++ FREEFIELD(shell); ++ FREEFIELD(dir); ++ FREEFIELD(fullName); ++ FREEFIELD(passwd); ++ ui->uid=(uid_t)-1; ++ ui->gid=(gid_t)-1; ++ ui->qflag=0; ++#undef FREEFIELD ++} ++ ++ ++static int fix_nw_user_info (struct nw_user_info *ui, struct nss_ncp_conf* conf){ ++/* fill NDS missing attributes (home, shell, gid, gecos) with default values ++ any user have a cn, and if uid was not found in NDS we consider ++ that the corresponding Unix account is not activated ++*/ ++ if (ui->cn) { ++ if (ui->uid== (uid_t)-1) ++ ui->uid=conf->fallbackUid; ++ if (ui->gid== (gid_t)-1) ++ ui->gid=conf->defGid; ++ if (!ui->gecos) { ++ ui->gecos= ui->fullName ? strdup(ui->fullName):strdup(""); ++ } ++ ui->shell= ui->shell ? ui->shell: strdup(conf->defShell); ++ ui->dir= ui->dir ? ui->dir: strdup(""); ++ ui->passwd= ui->passwd ? ui->passwd: strdup("x"); // cannot read passwd from ND ++ if (!ui->shell || !ui->dir || !ui->gecos || !ui->passwd) { ++ traceForce(conf->debug,LOG_ERR, "not enough memory when fixing nw_user_info\n ",ui->cn); ++ return 1; ++ } ++ }else { ++ ui->uid== (uid_t)-1; // unable to read CN (NDS browse rights not set) , skip it ! ++ } ++ return 0; ++} ++ ++ ++// return found info to caller in the format expected by NSS that is: ++// filling the passwd structure as pointers to the passed buffer ++ ++ ++static enum nss_status nw_user_info_to_passwd(struct nw_user_info ui,struct passwd *pwd, ++ char * buffer, size_t buflen, int * errnop, struct nss_ncp_conf *conf){ ++ ++ if (ui.uid != (uid_t)-1) { ++ pwd->pw_uid=ui.uid; ++ pwd->pw_gid=ui.gid; ++ ++ pwd->pw_name=copy_to_buffer (&buffer,&buflen,ui.cn); ++ if (!pwd->pw_name) goto outnomem; ++ pwd->pw_passwd=copy_to_buffer (&buffer,&buflen,ui.passwd); ++ if (!pwd->pw_passwd) goto outnomem; ++ pwd->pw_gecos=copy_to_buffer (&buffer,&buflen,ui.gecos); ++ if (!pwd->pw_gecos) goto outnomem; ++ pwd->pw_dir=copy_to_buffer (&buffer,&buflen,ui.dir); ++ if (!pwd->pw_dir) goto outnomem; ++ pwd->pw_shell=copy_to_buffer (&buffer,&buflen,ui.shell); ++ if (!pwd->pw_shell) goto outnomem; ++ ++ *errnop=0; ++ return NSS_STATUS_SUCCESS; ++outnomem: ++ traceForce(conf->debug,LOG_ERR, "not enough memory when copying nw_user_info to passwd for %s\n ",ui.cn); ++ *errnop=ERANGE; ++ return NSS_STATUS_TRYAGAIN; ++ } else { ++ trace(conf->debug,LOG_NOTICE, "user %s has no Unix UID in NDS\n ", ui.cn); ++ *errnop=ENOENT; ++ return NSS_STATUS_NOTFOUND; ++ } ++} ++ ++static void print_nw_user_info (struct nw_user_info ui){ ++ printf("%s:x:%d:%d:%s:%s:%s\n",ui.cn,ui.uid,ui.gid,ui.gecos,ui.dir,ui.shell); ++} ++ ++static void print_passwd (struct passwd pwd){ ++ printf("%s:%s:%d:%d:%s:%s:%s\n",pwd.pw_name,pwd.pw_passwd,pwd.pw_uid,pwd.pw_gid,pwd.pw_gecos,pwd.pw_dir,pwd.pw_shell); ++} ++ ++ ++/****************************************** internal structure for storing NDS group's infos ***/ ++struct nw_group_member { ++ struct nw_group_member* next; ++ char * member; ++}; ++ ++struct nw_group_info { ++ char * cn; ++ char * alias; ++ char * passwd; ++ gid_t gid; ++ struct nw_group_member * first; ++ struct nw_group_member * last; ++ int nbMembers; ++ int qflag; ++ }; ++ ++ ++static void init_nw_group_info (struct nw_group_info *gi,int qflag){ ++ gi->cn=NULL; ++ gi->alias=NULL; ++ gi->passwd=NULL; ++ gi->gid=(gid_t)-1; ++ gi->qflag= qflag; ++ gi->first=NULL; ++ gi->last=NULL; ++ gi->nbMembers=0; ++} ++ ++static void free_nw_group_info (struct nw_group_info *gi){ ++ ++ struct nw_group_member* p; ++ struct nw_group_member* bkp; ++#define FREEFIELD(x) do if (gi->x) {free(gi->x) ; gi->x=NULL;} while (0); ++ FREEFIELD(cn); ++ FREEFIELD(alias); ++ FREEFIELD(passwd); ++ gi->gid=(gid_t)-1; ++ gi->qflag=0; ++#undef FREEFIELD ++ for (p=gi->first; p; p=bkp) { ++ bkp=p->next; ++ free (p->member); ++ free(p); ++ } ++ gi->first=gi->last=NULL; ++ gi->nbMembers=0; ++} ++ ++ ++ ++static int fix_nw_group_info (struct nw_group_info *gi ,struct nss_ncp_conf* conf){ ++/* fill NDS missing attributes with default values ++ any group have a cn, and if gid was not found in NDS we will later consider ++ that the corresponding Unix group is not activated unless a fallback value is defined in conf ++*/ ++ if (gi->cn) { ++ if (gi->gid== (gid_t)-1) ++ gi->gid=conf->fallbackGid; ++ ++ gi->passwd= gi->passwd ? gi->passwd: strdup("x"); // cannot read passwd from NDS ++ if (!gi->passwd) { ++ traceForce(conf->debug,LOG_ERR, "not enough memory when allocating password for group %s\n ",gi->cn); ++ return 1; ++ } ++ if (gi->alias) { ++ if (gi->cn) free(gi->cn); ++ gi->cn=strdup(gi->alias); ++ if (!gi->cn) { ++ traceForce(conf->debug,LOG_ERR, "not enough memory when allocating alias for group %s\n ",gi->alias); ++ return 1; ++ } ++ } ++ }else { ++ gi->gid== (gid_t)-1; // unable to read CN (NDS browse rights not set) , skip it ! ++ } ++ return 0; ++} ++ ++ ++ ++/*********** ++return found info to caller in the format expected by NSS that is: ++filling the group structure as pointers to the passed buffer ++ ++struct group ++ { ++ char *gr_name; // Group name. ++ char *gr_passwd; // Password. ++ __gid_t gr_gid; // Group ID. ++ char **gr_mem; // Member list. ++ }; ++******************/ ++ ++static enum nss_status nw_group_info_to_group(struct nw_group_info gi,struct group *grp, ++ char * buffer, size_t buflen, int * errnop, struct nss_ncp_conf *conf){ ++ ++ if (gi.gid != (gid_t)-1) { ++ grp->gr_gid=gi.gid; ++ grp->gr_name=copy_to_buffer (&buffer,&buflen,gi.cn); ++ if (!grp->gr_name) goto outnomem; ++ grp->gr_passwd=copy_to_buffer (&buffer,&buflen,gi.passwd); ++ if (!grp->gr_passwd) goto outnomem; ++ ++ {// copy members to buffer ++ // names are stored backwards from end of buffer ++ // and adress pointers forward from start of buffer ++ // exit with NSS_STATUS_TRYAGAIN if buffer is too small ++ // code inspired from nss_mysql by Guillaume Morin ++ ++ size_t required=0; ++ char ** addPtr; ++ char * end_of_buffer,*tmp,*nm; ++ struct nw_group_member *p; ++ ++ for (p=gi.first;p;p=p->next) { ++ required += strlen(p->member)+1+sizeof(char**); ++ } ++ if (required + sizeof(char**) >=buflen) { ++ traceForce(conf->debug,LOG_ERR, "unable to copy members of group '%s' to buffer :need=%d have= %d\n",gi.cn,required,buflen); ++ goto outnomem; ++ } ++ addPtr= (char**)buffer; ++ grp->gr_mem=addPtr; ++ end_of_buffer= buffer+buflen-1; ++ p=gi.first; ++ while (p) { ++ end_of_buffer -=strlen(p->member)+1; ++ tmp=end_of_buffer; //do not change end_of_buffer when copying the new member ! ++ nm=copy_to_buffer(&tmp,&buflen,p->member); ++ if (!nm) { ++ traceForce(conf->debug,LOG_ERR, "not enough memory when copying nw_group_info to group for %s\n ",gi.cn); ++ goto outnomem; ++ } ++ *addPtr=nm; ++ //printf("%s=%s\n",p->member,*addPtr); ++ addPtr++; ++ p=p->next; ++ } ++ *addPtr=NULL; // end of table of pointers ++ } ++ *errnop=0; ++ return NSS_STATUS_SUCCESS; ++outnomem: ++ ++ *errnop=ERANGE; ++ return NSS_STATUS_TRYAGAIN; ++ } else { ++ trace(conf->debug,LOG_NOTICE, "group %s has no Unix GID in NDS\n ", gi.cn); ++ *errnop=ENOENT; ++ return NSS_STATUS_NOTFOUND; ++ } ++} ++ ++ ++static void print_nw_group_info (struct nw_group_info gi){ ++ struct nw_group_member* p; ++ ++ printf("%s:x:%d:%d members:",gi.cn,gi.gid,gi.nbMembers); ++ for (p=gi.first;p;p=p->next) { ++ printf("%s",p->member); ++ if (p->next) printf(","); ++ } ++ printf("\n"); ++} ++ ++static void print_group (struct group grp){ ++ char ** mmb; int num; ++ printf("%s:%s:%d:",grp.gr_name,grp.gr_passwd,grp.gr_gid); ++ for (mmb=grp.gr_mem,num=0;*mmb; mmb++,num++) { ++ if (num) ++ printf(","); ++ printf ("%s",*mmb); ++ ++ } ++ printf("\n"); ++ ++} ++ ++ ++/****************************************** internal structure for storing NDS user's shadow infos ***/ ++struct nw_shadow_info { ++ char * cn; ++ char * passwd; ++ long int lstchg; ++ long int sp_min; ++ long int sp_max; ++ long int sp_warn; ++ long int sp_inact; ++ long int sp_expire; ++ unsigned long sp_flag; ++ uid_t uid; ++ int qflag; ++ }; ++ ++static void init_nw_shadow_info (struct nw_shadow_info *si,int qflag){ ++ si->cn=NULL; ++ si->passwd=NULL; ++ si->lstchg=0; ++ si->sp_min=0; ++ si->sp_max=0; ++ si->sp_warn=0; ++ si->sp_inact=0; ++ si->sp_expire=0; ++ si->sp_flag=-1; ++ si->uid=(uid_t)-1; ++ si->qflag= qflag; ++} ++ ++static void free_nw_shadow_info (struct nw_shadow_info *si){ ++#define FREEFIELD(x) do if (si->x) {free(si->x) ; si->x=NULL;} while (0); ++ FREEFIELD(cn); ++ FREEFIELD(passwd); ++ si->lstchg=0; ++ si->sp_min=0; ++ si->sp_max=0; ++ si->sp_warn=0; ++ si->sp_inact=0; ++ si->sp_expire=0; ++ si->sp_flag=-1; ++ si->uid=(uid_t)-1; ++ si->qflag=0; ++#undef FREEFIELD ++} ++ ++ ++static int fix_nw_shadow_info (struct nw_shadow_info *si ,struct nss_ncp_conf *conf){ ++/* fill NDS missing attributes with default values ++ any user have a cn, and if uid was not found in NDS we will later consider ++ that the corresponding Unix account is not activated unless a fallback value is defined in conf ++*/ ++ if (si->cn) { ++ if (si->uid== (uid_t)-1) ++ si->uid=conf->fallbackUid; ++ si->lstchg= si->lstchg ? si->lstchg : time(NULL)/24/3600; ++ si->sp_min= si->sp_min ? si->sp_min: 0; ++ si->sp_max= si->sp_max ? si->sp_max: 99999; ++ si->sp_warn=si->sp_warn ? si->sp_warn: 7; ++ si->passwd= si->passwd ? si->passwd: strdup("!!"); // cannot read passwd from NDS ++ if (!si->passwd) { ++ traceForce(conf->debug,LOG_ERR, "not enough memory when allocating password for shadow user %s\n ",si->cn); ++ return 1; ++ ++ } ++ }else { ++ si->uid== (uid_t)-1; // unable to read CN (NDS browse rights not set) , skip it ! ++ } ++ return 0; ++} ++ ++/*** ++ return found info to caller in the format expected by NSS that is: ++ filling the shadow structure as pointers to the passed buffer ++ char *sp_namp; // Login nae. ++ char *sp_pwdp; // Encrypted password. ++ long int sp_lstchg; // Date of last change. ++ long int sp_min; // Minimum number of days between changes. ++ long int sp_max; // Maximum number of days between changes. ++ long int sp_warn; // Number of days to warn user to change the password. ++ long int sp_inact; // Number of days the account may be inactive. ++ long int sp_expire; // Number of days since 1970-01-01 until account expires. ++ unsigned long int sp_flag; // Reserved. ++*****/ ++ ++static enum nss_status nw_shadow_info_to_shadow(struct nw_shadow_info si,struct spwd *spw, ++ char * buffer, size_t buflen, int * errnop, struct nss_ncp_conf *conf){ ++ ++ if (si.uid != (uid_t)-1) { ++ spw->sp_namp=copy_to_buffer (&buffer,&buflen,si.cn); ++ if (!spw->sp_namp) goto outnomem; ++ spw->sp_pwdp=copy_to_buffer (&buffer,&buflen,si.passwd); ++ if (!spw->sp_pwdp) goto outnomem; ++ ++ spw->sp_lstchg=si.lstchg; ++ spw->sp_min=si.sp_min; ++ spw->sp_max=si.sp_max; ++ spw->sp_warn=si.sp_warn; ++ spw->sp_inact=si.sp_inact; ++ spw->sp_expire=si.sp_expire; ++ spw->sp_flag=si.sp_flag; ++ *errnop=0; ++ return NSS_STATUS_SUCCESS; ++outnomem: ++ traceForce(conf->debug,LOG_ERR, "not enough memory when copying nw_shadow_info to shadow for %s\n ",si.cn); ++ *errnop=ERANGE; ++ return NSS_STATUS_TRYAGAIN; ++ } else { ++ trace(conf->debug,LOG_NOTICE, "user %s has no Unix UID in NDS\n ", si.cn); ++ *errnop=ENOENT; ++ return NSS_STATUS_NOTFOUND; ++ } ++} ++ ++static void print_nw_shadow_info (struct nw_shadow_info si){ ++ ++ printf("%s[%d]:%s:%d:%d:%d:%d:%d:%d:%d\n",si.cn,si.uid,si.passwd,si.lstchg,si.sp_min,si.sp_max,si.sp_warn,si.sp_inact,si.sp_expire,si.sp_flag); ++} ++ ++static void print_shadow (struct spwd spw){ ++ printf("%s:%s:%ld:%ld:%ld:%ld:%ld:%ld:%ld\n",spw.sp_namp,spw.sp_pwdp,spw.sp_lstchg,spw.sp_min,spw.sp_max,spw.sp_warn,spw.sp_inact,spw.sp_expire,spw.sp_flag); ++} ++ ++ ++ ++/****************************************** internal structure for storing NDS user's groups infos ***/ ++struct nw_user_group_info { ++ char * cn; ++ uid_t uid; ++ gid_t* groups; ++ size_t used; ++ size_t alloc; ++ int qflag; ++ }; ++ ++ ++static void init_nw_user_group_info (struct nw_user_group_info *ui,int qflag){ ++ ui->cn=NULL; ++ ui->uid=(uid_t)-1; ++ ui->groups=NULL; ++ ui->used=0; ++ ui->alloc=0; ++ ui->qflag= qflag; ++} ++ ++static void free_nw_user_group_info (struct nw_user_group_info *ui){ ++#define FREEFIELD(x) do if (ui->x) {free(ui->x) ; ui->x=NULL;} while (0); ++ FREEFIELD(cn); ++ FREEFIELD(groups); ++ ui->used=0; ++ ui->alloc=0; ++ ui->uid=(uid_t)-1; ++ ui->qflag=0; ++#undef FREEFIELD ++} ++ ++ ++static int fix_nw_user_group_info (struct nw_user_group_info *ui ,struct nss_ncp_conf * conf){ ++/* fill NDS missing attributes with default values ++ any user have a cn, and if uid was not found in NDS we consider ++ that the corresponding Unix account is not activated unless a fallback value is defined in conf ++*/ ++ if (ui->cn) { ++ if (ui->uid== (uid_t)-1) ++ ui->uid=conf->fallbackUid; ++ }else { ++ ui->uid== (uid_t)-1; // unable to read CN (NDS browse rights not set) , skip it ! ++ } ++ return 0; ++} ++ ++ ++// return found info to caller in the format expected by NSS that is: ++// filling up groups array ++// code similar to nss_ldap ++ ++static enum nss_status nw_user_group_info_to_groups (struct nw_user_group_info ui,gid_t group, long int *start, ++ long int *size, gid_t * groups,long int limit,int *errnop,struct nss_ncp_conf * conf) { ++ ++ if (ui.uid != (uid_t)-1) { ++ int i; ++ for (i=0; idebug,LOG_ERR, "initgroups: not enough memory when reallocating group array for %s \n ",ui.cn); ++ *errnop=ERANGE; ++ return NSS_STATUS_TRYAGAIN; ++ } else { ++ trace(conf->debug,LOG_NOTICE, "user %s has no Unix UID in NDS\n ", ui.cn); ++ *errnop=ENOENT; ++ return NSS_STATUS_NOTFOUND; ++ } ++} ++ ++static void print_nw_user_group_info (struct nw_user_group_info ui){ ++ int i; ++ ++ printf("%s:%d:%d:%d:",ui.cn,ui.uid,ui.used,ui.alloc); ++ for (i=0;i attrname; ptr++) { ++ dserr = NWDSPutAttrName(ctx, attrlist, ptr->attrname); ++ if (dserr) { ++ traceForce(debugMode,LOG_WARNING, "NWDSPutAttrName(%s) failed with %s\n", ptr->attrname, strnwerror(dserr)); ++ goto bailoutbuf1; ++ } ++ } ++ dserr = NWDSAllocBuf(DEFAULT_MESSAGE_LEN, &info); ++ if (dserr) { ++ traceForce(debugMode,LOG_WARNING, "NWDSAllocBuf() failed with %s\n", strnwerror(dserr)); ++ goto bailoutbuf1; ++ } ++ iterHandle = NO_MORE_ITERATIONS; ++ do { ++ NWObjectCount attrs; ++ ++ dserr = NWDSRead(ctx, objname, DS_ATTRIBUTE_VALUES, 0, attrlist, &iterHandle, info); ++ if (dserr) { ++ if (dserr == ERR_NO_SUCH_ATTRIBUTE) ++ dserr = 0;// attribute is missing . OK ++ else ++ traceForce(debugMode,LOG_WARNING, "NWDSRead() failed for %s with %s\n", objname,strnwerror(dserr)); ++ goto bailoutbuf2; ++ } ++ dserr = NWDSGetAttrCount(ctx, info, &attrs); ++ if (dserr) { ++ traceForce(debugMode,LOG_WARNING, "NWDSGetAttrCount() failed with %s\n", strnwerror(dserr)); ++ goto bailoutcloit; ++ } ++ while (attrs--) { ++ NWDSChar attrname[MAX_SCHEMA_NAME_BYTES]; ++ enum SYNTAX synt; ++ NWObjectCount vals; ++ ++ dserr = NWDSGetAttrName(ctx, info, attrname, &vals, &synt); ++ if (dserr) { ++ traceForce(debugMode,LOG_WARNING, "NWDSGetAttrName() failed with %s\n", strnwerror(dserr)); ++ goto bailoutcloit; ++ } ++ while (vals--) { ++ size_t sz; ++ void *val; ++ ++ dserr = NWDSComputeAttrValSize(ctx, info, synt, &sz); ++ if (dserr) { ++ traceForce(debugMode,LOG_WARNING, "NWDSComputeAttrValSize() failed with %s\n", strnwerror(dserr)); ++ goto bailoutcloit; ++ } ++ val = malloc(sz); ++ if (!val) { ++ traceForce(debugMode,LOG_WARNING, "malloc() failed with %s\n", strnwerror(ENOMEM)); ++ goto bailoutcloit; ++ } ++ dserr = NWDSGetAttrVal(ctx, info, synt, val); ++ if (dserr) { ++ free(val); ++ traceForce(debugMode,LOG_WARNING, "NWDSGetAttrVal() failed with %s\n", strnwerror(dserr)); ++ goto bailoutcloit; ++ } ++ for (ptr = atlist; ptr->attrname; ptr++) { ++ if (!strcasecmp(ptr->attrname, attrname)) ++ break; ++ } ++ if (ptr->getval) { ++ if (ptr->synt != synt) { ++ traceForce(debugMode,LOG_WARNING, "Incompatible tree schema, %s has syntax %d instead of %d\n", attrname, synt, ptr->synt); ++ } else { ++ // ajout PP dserr= !!! en cas de pb mémoire ++ dserr = ptr->getval(ctx, val, arg); ++ } ++ } ++ free(val); ++ if (dserr) { ++ goto bailoutcloit; ++ } ++ } ++ } ++ } while (iterHandle != NO_MORE_ITERATIONS); ++bailoutcloit:; ++ if (iterHandle != NO_MORE_ITERATIONS) { ++ NWDSCCODE dserr2 = NWDSCloseIteration(ctx, DSV_READ, iterHandle); ++ if (dserr2) { ++ traceForce(debugMode,LOG_WARNING, "NWDSCloseIteration() failed with %s\n", strnwerror(dserr2)); ++ } ++ } ++bailoutbuf2:; ++ NWDSFreeBuf(info); ++bailoutbuf1:; ++ NWDSFreeBuf(attrlist); ++bailout:; ++ return dserr; ++} ++ ++ ++/*****************************************************GET USER INFO FROM NDS *************/ ++/************************************ helper functions to extract NDS properties ********/ ++// called as callbacks by nds_read_attrs ++ ++static NWDSCCODE nds_user_cn(NWDSContextHandle ctx, const void *val, void *arg){ ++ struct nw_user_info *ui = (struct nw_user_info *) arg; ++ ++ if (!ui->cn) { ++ char *v = strdup((const char *) val); ++ if (!v) { ++ traceForce(ui->qflag,LOG_WARNING, "Not enough memory for strdup()\n"); ++ return ENOMEM; ++ } ++ ui->cn = v; ++ trace(ui->qflag,LOG_NOTICE, "got a Unix cn %s from %s\n ", ui->cn, ATTR_CN); ++ } ++ return 0; ++} ++ ++static NWDSCCODE nds_user_unixuid(NWDSContextHandle ctx, const void *val, void *arg){ ++ struct nw_user_info *ui = (struct nw_user_info *) arg; ++ if (ui->uid == (uid_t) -1) { ++ ui->uid = *(const Integer_T *) val; ++ // talk a bit (real NDS8 attribute or dummy ?) ++ trace(ui->qflag,LOG_NOTICE, "got a Unix ID %d from %s\n ", ui->uid, ATTR_UID); ++ } ++ return 0; ++} ++ ++static NWDSCCODE nds_user_unixpgid(NWDSContextHandle ctx, const void *val, void *arg){ ++ struct nw_user_info *ui = (struct nw_user_info *) arg; ++ ++ if (ui->gid == (gid_t) -1) { ++ ui->gid = *(const Integer_T *) val; ++ // talk a bit (real NDS8 attribute or dummy ?) ++ trace(ui->qflag,LOG_NOTICE, "got a Unix PGID %d from %s\n ", ui->gid, ATTR_PGID); ++ } ++ return 0; ++} ++ ++// this is the same founction as above ??? ++// does Netware has two synonyms for the same property (UNIX:GID" ++// and UNIX:Primary GroupID??? ++static NWDSCCODE nds_user_unixgid(NWDSContextHandle ctx, const void *val, void *arg){ ++ struct nw_user_info *ui = (struct nw_user_info *) arg; ++ ++ if (ui->gid == (gid_t) -1) { ++ ui->gid = *(const Integer_T *) val; ++ // talk a bit (real NDS8 attribute or dummy ?) ++ trace(ui->qflag,LOG_NOTICE, "got a Unix GID %d from %s\n ", ui->gid, ATTR_GID); ++ } ++ return 0; ++} ++ ++static NWDSCCODE nds_user_unixhome(NWDSContextHandle ctx, const void *val, void *arg){ ++ struct nw_user_info *ui = (struct nw_user_info *) arg; ++ ++ if (!ui->dir) { ++ char *v = strdup((const char *) val); ++ if (!v) { ++ traceForce(ui->qflag,LOG_WARNING, "Not enough memory for strdup()\n"); ++ return ENOMEM; ++ } ++ ui->dir = v; ++ // talk a bit (real NDS8 attribute or dummy ?) ++ trace(ui->qflag,LOG_NOTICE, "got a Unix Home %s from %s\n ", ui->dir, ATTR_HOME); ++ } ++ return 0; ++} ++ ++static NWDSCCODE nds_user_unixshell(NWDSContextHandle ctx, const void *val, void *arg){ ++ struct nw_user_info *ui = (struct nw_user_info *) arg; ++ ++ if (!ui->shell) { ++ char *v = strdup((const char *) val); ++ if (!v) { ++ traceForce(ui->qflag,LOG_WARNING, "Not enough memory for strdup()\n"); ++ return ENOMEM; ++ } ++ ui->shell = v; ++ // talk a bit (real NDS8 attribute or dummy ?) ++ trace(ui->qflag,LOG_NOTICE, "got a Unix shell %s from %s\n ", ui->shell, ATTR_SHELL); ++ } ++ return 0; ++} ++ ++static NWDSCCODE nds_update_gecos(struct nw_user_info *ui, const char *str) { ++ char *v; ++ size_t sadd = strlen(str) + 1; ++ ++ if (ui->gecos) { // already got the name ++ size_t sold = strlen(ui->gecos); ++ trace(ui->qflag,LOG_NOTICE, "extending gecos %d %d\n",sadd,sold); ++ ++ v = realloc(ui->gecos, sold + 1 + sadd); ++ if (!v) { ++ traceForce(ui->qflag,LOG_WARNING, "Not enough memory for strdup()\n"); ++ return ENOMEM; ++ } ++ v[sold] = ','; ++ memcpy(v + sold+1, str, sadd); // bizarre sold a disparu dans pam_ncp ???? ++ } else { ++ trace(ui->qflag,LOG_NOTICE, "creating gecos %d \n",sadd); ++ v = malloc(sadd); ++ if (!v) { ++ traceForce(ui->qflag,LOG_WARNING, "Not enough memory for strdup()\n"); ++ return ENOMEM; ++ } ++ memcpy(v, str, sadd); ++ } ++ ui->gecos = v; ++ return 0; ++} ++ ++// PP we append the Comment after the full name, separated by a comma ++static NWDSCCODE nds_user_unixcomment(NWDSContextHandle ctx, const void *val, void *arg){ ++ struct nw_user_info *ui = (struct nw_user_info *) arg; ++ ++ // talk a bit (real NDS8 attribute or dummy ?) ++ trace(ui->qflag,LOG_NOTICE, "got a Unix Comment %s from %s\n ", (const char *) val, ATTR_COM); ++ return nds_update_gecos(ui, (const char *) val); ++} ++ ++// PP can be any naming attribute returning a SYN_CI_STRING see define before nds_user_info() ++// PP we add the name before any comment that can be there ++static NWDSCCODE nds_user_gecos(NWDSContextHandle ctx, const void *val, void *arg) { ++ struct nw_user_info *ui = (struct nw_user_info *) arg; ++ NWDSCCODE err; ++ ++ trace(ui->qflag,LOG_NOTICE, "before full name gecos is %s\n ", ui->gecos ? : "(null)"); ++ err = nds_update_gecos(ui, (const char *) val); ++ if (err) ++ return err; ++ trace(ui->qflag,LOG_NOTICE, "after full name gecos is %s\n ", ui->gecos); ++ return 0; ++} ++ ++// PP: id no NDS8 is present, collect the user's basic Unix informations from the location ++// strings with the format X:nnnnnnnn , X = [U,G,H,S,P,O,C,Z] upper of lower case ++// Of course, even if NDS8 IS present, we still look at these, just in case the migration ++// is not complete and to look for the user's ZENFLAG ++ ++static NWDSCCODE nds_user_location(NWDSContextHandle ctx, const void *val, void *arg){ ++ struct nw_user_info *ui = (struct nw_user_info *) arg; ++ const char *pt = (const char *) val; ++ char *v; ++ int n; ++ int err; ++ ++ trace(ui->qflag,LOG_NOTICE, "start of NW location got %s\n ", pt); ++ if (strlen(pt) > 2 && pt[1] == ':') { ++ const char *cur_pt = pt + 2; ++ switch (*pt) { ++ case 'u': //user ID leading spaces not significant ++ case 'U': ++ if (ui->uid == (uid_t) -1) { // do not overwrite a DS 8 answer ++ switch (getnumber(&n, &cur_pt)) { ++ case 0: ++ ui->uid = n; ++ break; ++ default: ++ traceForce(ui->qflag,LOG_ERR, "Invalid user ID %s\n", pt); ++ } ++ } ++ break; ++ case 'g': // primary group number GID leading spaces not significant ++ case 'G': ++ if (ui->gid == (gid_t) -1) { // do not overwrite a DS 8 answer ++ switch (getnumber(&n, &cur_pt)) { ++ case 0: ++ ui->gid = n; ++ break; ++ default: ++ traceForce(ui->qflag,LOG_ERR, "Invalid primary user GID %s\n", pt); ++ } ++ } ++ break; ++ case 'h': // home Unix all spaces significant (must have none ?) ++ case 'H': ++ if (!ui->dir) { // do not overwrite a DS 8 answer ++ v = strdup(cur_pt); ++ if (!v) { ++ traceForce(ui->qflag,LOG_WARNING, "Not enough memory for strdup()\n"); ++ return ENOMEM; ++ } ++ ui->dir = v; ++ } ++ break; ++ case 's': //shell Unix all spaces significant (must have none ?) ++ case 'S': ++ if (!ui->shell) { // do not overwrite a DS 8 answer ++ v = strdup(cur_pt); ++ if (!v) { ++ traceForce(ui->qflag,LOG_WARNING, "Not enough memory for strdup()\n"); ++ return ENOMEM; ++ } ++ ui->shell = v; ++ } ++ break; ++ case 'c': // comment all spaces significant. Will be appended to the gecos naming ++ case 'C': // attribute with a comma and set by calling chfn -f xxxx -o xxxx ++ // if comma are present in the string chfn will fails ++ trace(ui->qflag,LOG_NOTICE, "before comment gecos is %s\n ", ui->gecos); ++ err = nds_update_gecos(ui, cur_pt); ++ if (err) ++ return err; ++ trace(ui->qflag,LOG_NOTICE, "gecos %s\n ", ui->gecos); ++ break; ++ } ++ } ++ return 0; ++} ++ ++static NWDSCCODE nds_user_location2(NWDSContextHandle ctx, const void *val, void *arg){ ++ struct nw_user_info *ui = (struct nw_user_info *) arg; ++ const char *pt = (const char *) val; ++ char *v; ++ int n; ++ int err; ++ ++ trace(ui->qflag,LOG_NOTICE, "start of NW location got %s\n ", pt); ++ ++ if (strlen(pt) > 2 && pt[1] == ':') { ++ const char *cur_pt = pt + 2; ++ switch (*pt) { ++ case 'u': //user ID leading spaces not significant ++ case 'U': ++ if (ui->uid == (uid_t) -1) { // do not overwrite a DS 8 answer ++ switch (getnumber(&n, &cur_pt)) { ++ case 0: ++ ui->uid = n; ++ break; ++ default: ++ traceForce(ui->qflag,LOG_ERR, "Invalid user ID %s\n", pt); ++ } ++ } ++ } ++ ++ } ++ return 0; ++} ++ ++ ++static NWDSCCODE nds_user_info(NWDSContextHandle ctx, const NWDSChar * objname, void *ui, int modeDebug){ ++ static const struct attrop atlist[] = { ++ {ATTR_CN, nds_user_cn, SYN_CN}, ++ {ATTR_UID, nds_user_unixuid, SYN_UID}, ++ {ATTR_PGID, nds_user_unixpgid, SYN_PGID}, ++ {ATTR_GID, nds_user_unixgid, SYN_GID}, ++ {ATTR_HOME, nds_user_unixhome, SYN_HOME}, ++ {ATTR_SHELL, nds_user_unixshell, SYN_SHELL}, ++ {ATTR_COM, nds_user_unixcomment, SYN_COM}, ++ {ATTR_GECOS, nds_user_gecos, SYN_CI_STRING}, ++ {NULL, NULL, SYN_UNKNOWN} ++ }; ++ ++ static const struct attrop atlist2[] = { ++ {ATTR_LOCATION, nds_user_location, SYN_LOCATION}, ++ {NULL, NULL, SYN_UNKNOWN} ++ }; ++ ++ NWDSCCODE err; ++ ++// we must do TWO NDS queries since NDS does not return attributes in this order ++// studies of /var/log/secure showed that L attribute usually come out before the NDS8 ones ! ++ err = nds_read_attrs(ctx, objname, ui, atlist,modeDebug); ++ if (err) ++ return err; ++ return nds_read_attrs(ctx, objname, ui, atlist2,modeDebug); ++} ++ ++ ++/***************** GET limited user's information (used when searching for group members) */ ++/* we search only UID either stored in NDS8 attributes ( Real or Dummy) or in Location */ ++static NWDSCCODE nds_user_info2(NWDSContextHandle ctx, const NWDSChar * objname, void *ui,int modeDebug){ ++ static const struct attrop atlist[] = { ++ {ATTR_CN, nds_user_cn, SYN_CN}, ++ {ATTR_UID, nds_user_unixuid, SYN_UID}, ++ {NULL, NULL, SYN_UNKNOWN} ++ }; ++ ++ static const struct attrop atlist2[] = { ++ {ATTR_LOCATION, nds_user_location2, SYN_LOCATION}, ++ {NULL, NULL, SYN_UNKNOWN} ++ }; ++ ++ NWDSCCODE err; ++ ++// we must do TWO NDS queries since NDS does not return attributes in this order ++// studies of /var/log/secure showed that L attribute usually come out before the NDS8 ones ! ++ err = nds_read_attrs(ctx, objname, ui, atlist,modeDebug); ++ if (err) ++ return err; ++ return nds_read_attrs(ctx, objname, ui, atlist2,modeDebug); ++} ++ ++ ++/*****************************************************GET GROUP INFO FROM NDS *************/ ++ ++ ++/** gather Unix groups informations */ ++ ++static NWDSCCODE nds_group_cn(NWDSContextHandle ctx, const void *val, void *arg) ++{ ++ struct nw_group_info *gi = (struct nw_group_info *) arg; ++ ++ if (!gi->cn) { ++ char *v = strdup((const char *) val); ++ if (!v) { ++ traceForce(gi->qflag,LOG_WARNING, "Not enough memory for strdup()\n"); ++ return ENOMEM; ++ } ++ gi->cn = v; ++ trace(gi->qflag,LOG_NOTICE, "got a Unix cn %s from %s\n ", gi->cn, ATTR_CN); ++ } ++ return 0; ++} ++ ++ ++static NWDSCCODE nds_group_members(NWDSContextHandle ctx, const void *val, void *arg){ ++ ++ struct nw_group_info *gi = (struct nw_group_info *) arg; ++ NWDSCCODE err=0; ++ struct nw_user_info ui; ++ struct nw_group_member* newMember; ++ ++ ++ init_nw_user_info(&ui,gi->qflag); ++ //check whether member has some Unix properties ++ err=nds_user_info2(ctx, (const char *)val, &ui,gi->qflag); ++ if (!err && ui.uid !=(uid_t)-1 && ui.cn) { ++ char *v = strdup(ui.cn); ++ if (!v ) { ++ traceForce(gi->qflag,LOG_WARNING, "Not enough memory for adding member %s tp group %s\n",ui.cn,gi->cn); ++ err=ENOMEM; ++ } else { ++ newMember=malloc(sizeof(*newMember)); ++ if (newMember) { ++ newMember->member=v; ++ newMember->next=NULL; ++ if (!gi->first) gi->first=newMember; ++ else gi->last->next=newMember; ++ gi->last=newMember; ++ gi->nbMembers++; ++ trace(gi->qflag,LOG_NOTICE, "got a Unix members %s from %s\n ", ui.cn,gi->cn); ++ } else { ++ free(v); ++ traceForce(gi->qflag,LOG_WARNING, "Not enough memory for adding member %s tp group %s\n",ui.cn,gi->cn); ++ err=ENOMEM; ++ } ++ } ++ } ++ free_nw_user_info(&ui); ++ return err; ++} ++ ++ ++static NWDSCCODE nds_group_unixgid(NWDSContextHandle ctx, const void* val, void* arg) { ++ struct nw_group_info* gi = (struct nw_group_info*)arg; ++ ++ if (gi->gid == (gid_t)-1) { ++ gi->gid = *(const Integer_T*)val; ++ // talk a bit (real NDS8 attribute or dummy ?) ++ trace(gi->qflag,LOG_NOTICE, "got a Unix GID %d from %s\n ", gi->gid, ATTR_GID); ++ } ++ return 0; ++} ++ ++// PP: id no NDS8 is present, collect the group Unix ID from one of the location ++// string with the format G:nnn ++// can also used to specify a name of unix group different of the NDS'one ++// eg. everyone --> users or staff --> root ++static NWDSCCODE nds_group_location(NWDSContextHandle ctx, const void* val, void* arg) { ++ ++ struct nw_group_info* gi = (struct nw_group_info*)arg; ++ const char *pt= (const char*) val; ++ int n; ++ ++ if (strlen(pt)>2 && pt[1]==':') { ++ const char* cur_pt=pt+2; ++ switch (*pt) { ++ case 'g': ++ case 'G':if (gi->gid == (gid_t)-1) { ++ switch (getnumber(&n,&cur_pt)) { ++ case 0: gi->gid=n; break; ++ default:traceForce(gi->qflag,LOG_ERR, "Invalid group GID %s for %s\n",pt,gi->cn); ++ } ++ } ++ break; ++ case 'n': ++ case 'N': // unix equivalent name ++ if (!gi->alias) { ++ char* v = strdup(cur_pt); ++ if (!v) { ++ traceForce(gi->qflag,LOG_WARNING, "Not enough memory for strdup()\n"); ++ return ENOMEM; ++ } ++ gi->alias = v; ++ trace(gi->qflag,LOG_NOTICE, "group:got a Unix alias %s from %s\n ", gi->alias, gi->cn); ++ } ++ break; ++ } ++ } ++ return 0; ++} ++ ++ ++static NWDSCCODE nds_group_info(NWDSContextHandle ctx, const NWDSChar* objname, void * gi, int modeDebug) { ++ static const struct attrop atlist[] = { ++ { ATTR_CN, nds_group_cn, SYN_CN }, ++ { ATTR_GID, nds_group_unixgid, SYN_GID }, ++ { ATTR_MEMBERS, nds_group_members, SYN_MEMBERS}, ++ { NULL, NULL, SYN_UNKNOWN }}; ++ ++ static const struct attrop atlist2[] = { ++ {ATTR_LOCATION, nds_group_location, SYN_LOCATION}, ++ {NULL, NULL, SYN_UNKNOWN}}; ++ ++ ++ NWDSCCODE err; ++ ++// we must do TWO NDS queries since NDS does not return attributes in this order ++// studies of /var/log/secure showed that L attribute usually come out before the NDS8 ones ! ++ err = nds_read_attrs(ctx, objname, gi, atlist,modeDebug); ++ if (err) ++ return err; ++ return nds_read_attrs(ctx, objname, gi, atlist2,modeDebug); ++} ++ ++ ++/***************** GET limited group's information (used when searching for groups to which a user belongs) */ ++static NWDSCCODE nds_group_location2(NWDSContextHandle ctx, const void* val, void* arg) { ++ ++ struct nw_group_info* gi = (struct nw_group_info*)arg; ++ const char *pt= (const char*) val; ++ int n; ++ ++ if (strlen(pt)>2 && pt[1]==':') { ++ const char* cur_pt=pt+2; ++ switch (*pt) { ++ case 'g': ++ case 'G':if (gi->gid == (gid_t)-1) { ++ switch (getnumber(&n,&cur_pt)) { ++ case 0: gi->gid=n; break; ++ default:traceForce(gi->qflag,LOG_ERR, "Invalid group GID %s for %s\n",pt,gi->cn); ++ } ++ } ++ break; ++ } ++ } ++ return 0; ++} ++ ++/* we search only GID either stored in NDS8 attributes ( Real or Dummy) or in Location */ ++static NWDSCCODE nds_group_info2(NWDSContextHandle ctx, const NWDSChar* objname, void * gi, int modeDebug) { ++ ++ static const struct attrop atlist[] = { ++ { ATTR_GID, nds_group_unixgid, SYN_GID }, ++ { NULL, NULL, SYN_UNKNOWN }}; ++ ++ static const struct attrop atlist2[] = { ++ {ATTR_LOCATION, nds_group_location2, SYN_LOCATION}, ++ {NULL, NULL, SYN_UNKNOWN}}; ++ ++ ++ NWDSCCODE err; ++ ++// we must do TWO NDS queries since NDS does not return attributes in this order ++// studies of /var/log/secure showed that L attribute usually come out before the NDS8 ones ! ++ err = nds_read_attrs(ctx, objname, gi, atlist,modeDebug); ++ if (err) ++ return err; ++ return nds_read_attrs(ctx, objname, gi, atlist2,modeDebug); ++} ++ ++ ++/*****************************************************GET SHADOW INFO FROM NDS *************/ ++ ++static NWDSCCODE nds_shadow_cn(NWDSContextHandle ctx, const void *val, void *arg){ ++ ++ struct nw_shadow_info *si = (struct nw_shadow_info *) arg; ++ ++ if (!si->cn) { ++ char *v = strdup((const char *) val); ++ if (!v) { ++ traceForce(si->qflag & QF_DEBUG,LOG_WARNING, "Not enough memory for strdup()\n"); ++ return ENOMEM; ++ } ++ si->cn = v; ++ trace(si->qflag & QF_DEBUG,LOG_NOTICE, "shadow:got a Unix cn %s from %s\n ", si->cn, ATTR_CN); ++ } ++ return 0; ++} ++ ++ ++static NWDSCCODE nds_shadow_unixuid(NWDSContextHandle ctx, const void *val, void *arg){ ++ ++ struct nw_shadow_info *si = (struct nw_shadow_info *) arg; ++ if (si->uid == (uid_t) -1) { ++ si->uid = *(const Integer_T *) val; ++ // talk a bit (real NDS8 attribute or dummy ?) ++ trace(si->qflag & QF_DEBUG,LOG_NOTICE, "shadow: got a Unix ID %d from %s\n ", si->uid, ATTR_UID); ++ } ++ return 0; ++} ++ ++ ++// PP: id no NDS8 is present, collect the user's basic Unix informations from the location ++// strings with the format X:nnnnnnnn , X = [U,G,H,S,P,O,C,Z] upper of lower case ++// Of course, even if NDS8 IS present, we still look at these, just in case the migration ++// is not complete and to look for the user's ZENFLAG ++ ++static NWDSCCODE nds_shadow_location(NWDSContextHandle ctx, const void *val, void *arg){ ++ ++ struct nw_shadow_info *si = (struct nw_shadow_info *) arg; ++ const char *pt = (const char *) val; ++ char *v; ++ int n; ++ int err; ++ ++ trace(si->qflag & QF_DEBUG,LOG_NOTICE, "shadow: start of NW location got %s\n ", pt); ++ ++ if (strlen(pt) > 2 && pt[1] == ':') { ++ const char *cur_pt = pt + 2; ++ switch (*pt) { ++ case 'u': //user ID leading spaces not significant ++ case 'U': ++ if (si->uid == (uid_t) -1) { // do not overwrite a DS 8 answer ++ switch (getnumber(&n, &cur_pt)) { ++ case 0: ++ si->uid = n; ++ break; ++ default: ++ traceForce(si->qflag & QF_DEBUG,LOG_ERR, "shadow:Invalid user ID %s\n", pt); ++ } ++ } ++ break; ++ } ++ ++ } ++ return 0; ++} ++ ++static NWDSCCODE nds_shadow_pwd_expire(NWDSContextHandle ctx, const void *val, void *arg){ ++ struct nw_shadow_info *si = (struct nw_shadow_info *) arg; ++ si->sp_expire = *(const Time_T *) val/3600/24; ++ return 0; ++} ++ ++static NWDSCCODE nds_shadow_int_pwd_expire(NWDSContextHandle ctx, const void *val, void *arg){ ++ struct nw_shadow_info *si = (struct nw_shadow_info *) arg; ++ si->sp_min = *(const Integer_T *) val/3600/24; ++ si->sp_max = *(const Integer_T *) val/3600/24; ++ return 0; ++} ++ ++static NWDSCCODE nds_shadow_acct_expire(NWDSContextHandle ctx, const void *val, void *arg){ ++ struct nw_shadow_info *si = (struct nw_shadow_info *) arg; ++ si->sp_inact = *(const Time_T *) val/3600/24; ++ return 0; ++} ++ ++static NWDSCCODE nds_shadow_grace_pwd_expire (NWDSContextHandle ctx, const void *val, void *arg) { ++// in NDS it is the number of grace login, in Unix the number of DAYS ++ struct nw_shadow_info *si = (struct nw_shadow_info *) arg; ++ si->sp_warn = *(const Integer_T *) val; ++ return 0; ++} ++ ++ ++/*****************************************************GET USER SHADOW INFOS FROM NDS *************/ ++ ++static NWDSCCODE nds_shadow_info(NWDSContextHandle ctx, const NWDSChar * objname, void *si,int modeDebug){ ++ static const struct attrop atlist[] = { ++ {ATTR_CN, nds_shadow_cn, SYN_CN}, ++ {ATTR_UID, nds_shadow_unixuid, SYN_UID}, ++ {ATTR_DATE_PWD_EXPIRE,nds_shadow_pwd_expire,SYN_TIME}, ++ {ATTR_DATE_ACCT_EXPIRE,nds_shadow_acct_expire,SYN_TIME}, ++ {ATTR_INT_PWD_EXPIRE,nds_shadow_int_pwd_expire,SYN_INTERVAL}, ++ {ATTR_GRACE_LIMIT,nds_shadow_grace_pwd_expire,SYN_INTEGER}, ++ {NULL, NULL, SYN_UNKNOWN} ++ }; ++ ++ static const struct attrop atlist2[] = { ++ {ATTR_LOCATION, nds_shadow_location, SYN_LOCATION}, ++ {NULL, NULL, SYN_UNKNOWN} ++ }; ++ ++ NWDSCCODE err; ++ ++// we must do TWO NDS queries since NDS does not return attributes in this order ++// studies of /var/log/secure showed that L attribute usually come out before the NDS8 ones ! ++ err = nds_read_attrs(ctx, objname, si, atlist,modeDebug); ++ if (err) ++ return err; ++ return nds_read_attrs(ctx, objname, si, atlist2,modeDebug); ++} ++ ++ ++/***************get all group id of groups userName belongs to *********************/ ++ ++static NWDSCCODE nds_user_cn2(NWDSContextHandle ctx, const void *val, void *arg){ ++ ++ struct nw_user_group_info *ui = (struct nw_user_group_info *) arg; ++ if (!ui->cn) { ++ char *v = strdup((const char *) val); ++ if (!v) { ++ traceForce(ui->qflag,LOG_WARNING, "Not enough memory for strdup()\n"); ++ return ENOMEM; ++ } ++ ui->cn = v; ++ trace(ui->qflag & QF_DEBUG,LOG_NOTICE, "got a Unix cn %s from %s\n ", ui->cn, ATTR_CN); ++ } ++ return 0; ++} ++ ++ ++ ++static NWDSCCODE nds_user_unixuid2(NWDSContextHandle ctx, const void *val, void *arg){ ++ struct nw_user_group_info *ui = (struct nw_user_group_info *) arg; ++ if (ui->uid == (uid_t) -1) { ++ ui->uid = *(const Integer_T *) val; ++ // talk a bit (real NDS8 attribute or dummy ?) ++ trace(ui->qflag & QF_DEBUG,LOG_NOTICE, "got a Unix ID %d from %s\n ", ui->uid, ATTR_UID); ++ } ++ return 0; ++} ++ ++ ++static NWDSCCODE nds_user_location3(NWDSContextHandle ctx, const void *val, void *arg){ ++ struct nw_user_group_info *ui = (struct nw_user_group_info *) arg; ++ const char *pt = (const char *) val; ++ char *v; ++ int n; ++ int err; ++ ++ ++ trace(ui->qflag & QF_DEBUG,LOG_NOTICE, "start of NW location got %s\n ", pt); ++ ++ if (strlen(pt) > 2 && pt[1] == ':') { ++ const char *cur_pt = pt + 2; ++ switch (*pt) { ++ case 'u': //user ID leading spaces not significant ++ case 'U': ++ if (ui->uid == (uid_t) -1) { // do not overwrite a DS 8 answer ++ switch (getnumber(&n, &cur_pt)) { ++ case 0: ++ ui->uid = n; ++ break; ++ default: ++ traceForce(ui->qflag & QF_DEBUG,LOG_ERR, "Invalid user ID %s\n", pt); ++ } ++ } ++ break; ++ } ++ ++ } ++ return 0; ++} ++ ++static NWDSCCODE nds_get_one_user_group(NWDSContextHandle ctx, const void *val, void *arg){ ++ struct nw_user_group_info *ui = (struct nw_user_group_info *) arg; ++ struct nw_group_info gi; ++ NWDSCCODE ccode; ++ ++ init_nw_group_info(&gi,ui->qflag); ++ //check whether group has some Unix properties ++ trace(ui->qflag & QF_DEBUG,LOG_NOTICE, "found group %s for user %s\n ", (const char*)val, ui->cn); ++ ccode=nds_group_info2(ctx,(const char *)val,&gi,ui->qflag); ++ // found a real GID , no fallback here else all groups would have the same number !!!! ++ if (!ccode && gi.gid != (gid_t) -1) { ++ trace(ui->qflag & QF_DEBUG,LOG_NOTICE, "found group GID %d for user %s\n ", gi.gid, ui->cn); ++ if (ui->used >=ui->alloc) { ++ gid_t* np; ++ size_t ns; ++ if (ui->groups) { ++ ns=ui->alloc +8; ++ np=(gid_t*)realloc (ui->groups,ns*sizeof(gid_t)); ++ }else { ++ ns=8; ++ np=(gid_t*)malloc (ns*sizeof(gid_t)); ++ } ++ if (!np) { ++ traceForce(ui->qflag & QF_DEBUG,LOG_WARNING, "Not enough memory for allocating GID table\n"); ++ return ENOMEM; ++ } ++ ui->groups=np; ++ ui->alloc=ns; ++ } ++ ui->groups[ui->used++]=gi.gid; ++ } ++ free_nw_group_info(&gi); ++ return ccode; ++} ++ ++ ++static NWDSCCODE nds_get_user_groups(NWDSContextHandle ctx, const NWDSChar * objname, void *ui, int modeDebug){ ++// get all groups of userName ++static const struct attrop atlist[] = { ++ {ATTR_CN, nds_user_cn2, SYN_CN}, ++ {ATTR_UID, nds_user_unixuid2, SYN_UID}, ++ {ATTR_GRP_MBS, nds_get_one_user_group, SYN_GRP_MBS}, ++ {NULL, NULL, SYN_UNKNOWN} ++ }; ++ ++ static const struct attrop atlist2[] = { ++ {ATTR_LOCATION, nds_user_location3, SYN_LOCATION}, ++ {NULL, NULL, SYN_UNKNOWN} ++ }; ++ ++ NWDSCCODE err; ++ ++// we must do TWO NDS queries since NDS does not return attributes in this order ++// studies of /var/log/secure showed that L attribute usually come out before the NDS8 ones ! ++ err = nds_read_attrs(ctx, objname, ui, atlist,modeDebug); ++ if (err) ++ return err; ++ return nds_read_attrs(ctx, objname, ui, atlist2,modeDebug); ++ ++} ++ ++/*******************************************************************************************************************/ ++static NWDSCCODE CreateContextAndConn ( NWDSContextHandle *context,NWCONN_HANDLE *conn, struct nss_ncp_conf* conf) { ++ NWDSCCODE ccode; ++ nuint32 contextFlags; ++ ++ trace(conf->debug, LOG_NOTICE,"Entering create context and conn"); ++ ++ ccode = NWDSCreateContextHandle(context); ++ if(ccode) { ++ traceForce(conf->debug,LOG_WARNING,"Error creating context.\n"); ++ goto Exit1; ++ } ++ ++ trace(conf->debug, LOG_NOTICE,"CreateContextHandle OK"); ++ ++ //ccode=NWDSSetContext(*context, DCK_NAME_CONTEXT, conf->startCtx); ++ ++ ccode=NWDSSetContext(*context, DCK_NAME_CONTEXT, "[Root]"); ++ if(ccode){ ++ traceForce(conf->debug,LOG_WARNING,"Error NWDSSetContext(): %d\n",ccode); ++ goto Exit2; ++ } ++ ++ trace(conf->debug, LOG_NOTICE,"SetContext OK"); ++ ++ ccode= NWDSGetContext(*context, DCK_FLAGS, &contextFlags); ++ if( ccode){ ++ traceForce(conf->debug,LOG_WARNING,"NWDSGetContext (DCK_FLAGS) failed, returns %d\n", ccode); ++ goto Exit2; ++ } ++ ++ trace(conf->debug, LOG_NOTICE,"GetContext OK"); ++ ++ contextFlags|= DCV_TYPELESS_NAMES; ++ ccode= NWDSSetContext( *context, DCK_FLAGS, &contextFlags); ++ if( ccode) { ++ traceForce(conf->debug,LOG_WARNING,"NWDSSetContext (DCK_FLAGS DCV_TYPELESS_NAMES) failed, returns %d\n", ccode); ++ goto Exit2; ++ } ++ ++ trace(conf->debug, LOG_NOTICE,"SetContext OK"); ++ trace(conf->debug, LOG_NOTICE,"calling NWCCOpenConnByName ..."); ++ ++ if (conf->server[0] == '/') //using a permanent connection ++ ccode = ncp_open_mount(conf->server, conn); ++ else { ++ ++ if (!conf->useTree) ++ ccode = NWCCOpenConnByName(NULL, conf->server, NWCC_NAME_FORMAT_BIND, 0, 0, conn); ++ else ++ //ccode=NWCXAttachToTreeByName( conn, conf->server); ++ ccode = NWCCOpenConnByName(NULL, conf->server, NWCC_NAME_FORMAT_NDS_TREE, 0, 0, conn); ++ if (ccode) { ++ traceForce(conf->debug,LOG_WARNING,"Error: NWCCOpenConnByName failed %s\n",strnwerror(ccode)); ++ goto Exit2; ++ } ++ } ++ ++ trace(conf->debug, LOG_NOTICE,"NWCCOpenConnByName OK"); ++ ++ ccode= NWDSAddConnection(*context, *conn); ++ if (ccode) { ++ traceForce(conf->debug,LOG_WARNING,"Error: NWCCOpenConnByName failed %s\n",strnwerror(ccode)); ++ goto Exit2; ++ } ++ ++ trace(conf->debug, LOG_NOTICE,"AddConnection OK"); ++ ++ if (conf->debug & QF_DEBUG) { ++ char aux[512]; ++ aux[0] = 0; ++ if (!conf->useTree) { ++ NWCCGetConnInfo(*conn, NWCC_INFO_TREE_NAME, sizeof (aux), aux); ++ trace(conf->debug, LOG_DEBUG, "sucessful connection to tree %s by server %s \n",aux,conf->server); ++ }else { ++ NWCCGetConnInfo(*conn, NWCC_INFO_SERVER_NAME, sizeof (aux), aux); ++ trace(conf->debug,LOG_DEBUG, "successful connection by NDS server %s on tree %s\n", aux,conf->server); ++ } ++ } ++ ++Exit2: ++ if (ccode) { ++ trace(conf->debug, LOG_NOTICE,"Closing context and conn due to errors"); ++ if(conn) NWCCCloseConn (*conn); ++ if (context) NWDSFreeContext(*context); ++ *context=NULL; ++ *conn=NULL; ++ } ++Exit1: ++ trace(conf->debug, LOG_NOTICE,"leaving CreateContextAndConn"); ++ return ccode; ++} ++ ++ ++/**** PP TreeScaning routines ***********************/ ++ ++struct TreeNode { ++ struct TreeNode* left; ++ struct TreeNode* right; ++ struct TreeNode* next; ++ struct TreeNode** pprev; ++ size_t cnt; ++ char name [MAX_DN_CHARS+1]; ++}; ++ ++struct ObjectList { ++ struct TreeNode* first; ++ struct TreeNode* lin; ++ struct TreeNode* curr; ++ int dups; ++ size_t uniqueObjects; ++ size_t remainObjects; ++ size_t totalObjects; ++ NWDSContextHandle context; ++ NWCONN_HANDLE conn; ++ struct nss_ncp_conf * conf; ++}; ++ ++static struct ObjectList* __allocTree(int dups,struct nss_ncp_conf * conf) { ++ struct ObjectList* t; ++ ++ t = (struct ObjectList*)malloc(sizeof(*t)); ++ if (t) { ++ t->first = NULL; ++ t->lin = NULL; ++ t->curr = NULL; ++ t->dups = dups; ++ t->uniqueObjects = 0; ++ t->conf=conf; ++ } ++ return t; ++} ++ ++static void __freeNode(struct TreeNode* n) { ++ while (n) { ++ struct TreeNode* tmp; ++ ++ __freeNode(n->left); ++ tmp = n; ++ n = n->right; ++ free(tmp); ++ } ++} ++ ++static void __freeTree(struct ObjectList* t) { ++ if (t) { ++ struct TreeNode* n = t->first; ++ if (t->conf) ++ free_nss_ncp_conf(t->conf); ++ free(t); ++ __freeNode(n); ++ } ++} ++ ++static NWDSCCODE __allocNode(struct TreeNode** pn, const char* objectName) { ++ struct TreeNode* n; ++ size_t len=strlen(objectName); ++ ++ if (len > MAX_DN_CHARS) ++ return NWE_BUFFER_OVERFLOW; ++ n = (struct TreeNode*)malloc(sizeof(*n)); ++ if (!n) ++ return ERR_NOT_ENOUGH_MEMORY; ++ n->left = n->right = NULL; ++ n->cnt = 1; ++ memcpy(n->name, objectName, len + 1); ++ *pn = n; ++ return 0; ++} ++ ++static NWDSCCODE __insertNode(struct ObjectList* t, const char* objectName) { ++ struct TreeNode** p; ++ struct TreeNode* n; ++ NWDSCCODE err; ++ ++ p = &t->first; ++ while ((n = *p) != NULL) { ++ int cmp = strcasecmp(objectName, n->name); ++ if (cmp < 0) { ++ p = &n->left; ++ if (!*p) { ++ err = __allocNode(p, objectName); ++ if (!err) { ++ struct TreeNode* q = *p; ++ ++ q->next = n; ++ q->pprev = n->pprev; ++ n->pprev = &q->next; ++ *(q->pprev) = q; ++ t->uniqueObjects++; ++ t->totalObjects++; ++ } ++ return err; ++ } ++ } else if (cmp > 0) { ++ p = &n->right; ++ if (!*p) { ++ err = __allocNode(p, objectName); ++ if (!err) { ++ struct TreeNode* q = *p; ++ ++ q->next = n->next; ++ if (q->next) ++ q->next->pprev = &q->next; ++ n->next = q; ++ q->pprev = &n->next; ++ t->uniqueObjects++; ++ t->totalObjects++; ++ } ++ return err; ++ } ++ } else { ++ if (t->dups) { ++ n->cnt++; ++ t->totalObjects++; ++ return 0; ++ } else { ++ return EINVAL; // no dups allowed and one found ++ } ++ } ++ } ++ err = __allocNode(p, objectName); ++ if (!err) { ++ struct TreeNode* q = *p; ++ t->lin = q; ++ q->next = NULL; ++ q->pprev = &t->lin; ++ t->uniqueObjects++; ++ t->totalObjects++; ++ } ++ return err; ++} ++ ++static void print_nodes(struct TreeNode* n, int crlf) { ++ if (n) { ++ print_nodes(n->left,crlf); ++ if (crlf) ++ printf ("%s [%d]\n",n->name,n->cnt); ++ else ++ printf ("%s [%d]",n->name,n->cnt); ++ print_nodes(n->right,crlf); ++ } ++} ++ ++static void print_tree(struct ObjectList* t, int crlf) { ++ printf("total:%d unique:%d\n",t->totalObjects,t->uniqueObjects); ++ print_nodes (t->first,crlf); ++} ++ ++ ++// callback for getallentxx() ++static NWDSCCODE ++nds_insert_info(NWDSContextHandle ctx, const NWDSChar * objectName, void *tree, int modeDebug){ ++ return __insertNode((struct ObjectList*)tree, objectName); ++} ++ ++/* eot*/ ++ ++ ++/*** collecting in a tree every member of a group, if his UID defined in NDS */ ++ ++static NWDSCCODE ++nds_get_group_members(NWDSContextHandle ctx, const void *val, void *arg){ ++ ++ struct ObjectList *tree = (struct ObjectList *) arg; ++ NWDSCCODE ccode=0; ++ struct nw_user_info ui; ++ ++ init_nw_user_info(&ui,0); ++ //check whether member has some Unix properties ++ ccode=nds_user_info2(ctx, (const char *)val, &ui,tree->conf->debug); ++ // found a UID real (no fallback otherwise all users would have the same UID) ++ if (!ccode && ui.uid !=(uid_t)-1) { ++ ccode=__insertNode(tree,(const char *)val); ++ } ++ free_nw_user_info(&ui); ++ return ccode; ++} ++ ++ ++static NWDSCCODE ++getgroupmembers(NWDSContextHandle *context,NWCONN_HANDLE *conn, ++ const char* groupName,struct ObjectList * tree, struct nss_ncp_conf* conf){ ++// get all members of a group ++ ++ NWDSCCODE ccode; ++ ++ static const struct attrop atlist[] = { ++ { ATTR_MEMBERS, nds_get_group_members, SYN_MEMBERS}, ++ { NULL, NULL, SYN_UNKNOWN }}; ++ ++ NWDSCCODE err; ++ trace(conf->debug, LOG_NOTICE,"entering getgroupmembers for group %s",groupName); ++ ccode=CreateContextAndConn ( context,conn,conf); ++ if (ccode) ++ return ccode; ++ ccode=nds_read_attrs(*context, groupName, tree, atlist,conf->debug); ++ trace(conf->debug, LOG_NOTICE,"leaving getgroupmembers for group %s err=%s",groupName,strnwerror(ccode)); ++ return ccode; ++} ++ ++ ++// static lists. Allocated by nss_ncp_setxxent_r, used buy nss_ncp_getxxent_r and released by nss_ncp_endxxent_r ++// TODO :mutex and threads needed as in nss_ldap or nss_mysql ??? ++ ++static struct ObjectList* ndsUsers=NULL; ++static struct ObjectList* ndsGroups=NULL; ++static struct ObjectList* ndsShadows=NULL; ++ ++// description of a NDS class to be searched by getentbyxx ++struct class_info { ++ char * className; ++ char * nds8Attribute; //name of ID attribute in NDS8 ++ char * LID1; // markers in L attribute for ID (U: or G:) ++ char * LID2; // markers in L attribute for ID (u: or g:), may be in lower case ++ char * LAlias1;// markers in L attribute for alias (N:) ++ char * LAlias2; // markers in L attribute for alias (n:) may be in lower case ++ ++}; ++ ++// we care only about user's and group classes ++static struct class_info USER_CLASS = {"User", ATTR_UID,"U:","u:","N:","n:"}; ++static struct class_info GROUP_CLASS= {"Group",ATTR_GID,"G:","g:","N:","n:"}; ++ ++ ++/*protoptype of callback functions used in getentbyxx*/ ++ ++struct infoop { ++ NWDSCCODE (*getinfo) (NWDSContextHandle ctx , const NWDSChar * objectName, void * info, int debug); ++}; ++/* ++ currently match ++ nds_user_info(context,objectName,ui,modeDebug); ++ nds_user_info2(context,objectName,ui,modeDebug); ++ nds_group_info(context,objectName,gi,modeDebug); ++ nds_group_info2(context,objectName,gi,modeDebug); ++ nds_shadow_info(context,objectName,si,modeDebug); ++ nds_insert_info(context,objectName,tree,modeDebug): ++*/ ++ ++ ++// generic NDS search routine ++static NWDSCCODE getentbyxx( ++ NWDSContextHandle *retContext, // context to return (NULL= close when leaving) ++ NWCONN_HANDLE *retConn, // connexion to return (NULL= close when leaving) ++ struct class_info classType, // class to search (User of Group) ++ void *info, // structure to fill (can be nw_user_info,nw_shadow_info,nw_group_info or a ObjectList) ++ const struct infoop callBack, // routine to call for all found NDS objects ++ const char *unixName, // Unix objet name to find in NDS (if NULL search by ID) ++ uid_t id, // Unix ID to find in NDS , if -1 search by unixName) ++ int allEntries, // Ignore unixName and id and return all entries belonging to classType.className ++ struct nss_ncp_conf *conf) { // configuration record (debug...) ++ ++ NWDSContextHandle context; ++ NWCONN_HANDLE conn; ++ NWDSCCODE ccode; ++ nint32 iterationHandle= NO_MORE_ITERATIONS; // to be set as such at Exit4 ++ nint32 countObjectsSearched; ++ nuint32 objCntr,attrCntr,valCntr; ++ nuint32 objCount; ++ nuint32 attrCount; ++ char objectName[MAX_DN_CHARS+1]; ++ char attrName[MAX_SCHEMA_NAME_CHARS+1]; ++ nuint32 attrValCount; ++ nuint32 syntaxID; ++ nuint32 attrValSize; ++ char* attrVal; ++ ++ // buffers ++ pBuf_T searchFilter=NULL; // search filter ++ pBuf_T retBuf=NULL; // result buffer for NWDSSearch ++ pBuf_T attrNames=NULL; // specify which attribute values to return ++ Filter_Cursor_T* cur=NULL; // search expression tree temporary buffer ++ Object_Info_T objectInfo; ++ ++ ++ //few checks ++ ++ if (!allEntries) { ++ if (unixName && id !=(uid_t)-1) ++ return EINVAL; ++ if (!unixName && id ==(uid_t)-1) ++ return EINVAL; ++ } ++ ++ trace(conf->debug, LOG_NOTICE,"entering getentbyxx"); ++ ++ ccode=CreateContextAndConn ( &context,&conn,conf); ++ if (ccode) ++ return ccode; ++ ++ trace(conf->debug, LOG_NOTICE,"context and conn OK"); ++ /* ++ In order to search, we need: ++ A Filter Cursor (to build the search expression) ++ A Filter Buffer (to store the expression; used by NWDSSearch) ++ A Buffer to store which attributes we need information on ++ A Result Buffer (to store the search results) ++ */ ++ ccode = NWDSAllocBuf(DEFAULT_MESSAGE_LEN,&searchFilter); ++ if (ccode) { ++ traceForce(conf->debug,LOG_WARNING,"NWDSAllocBuf returned: %d\n", ccode); ++ goto Exit3; ++ } ++ trace(conf->debug, LOG_NOTICE,"NWDSAllocBuf searchFilter OK"); ++ // Initialize the searchFilter buffer ++ ccode = NWDSInitBuf(context,DSV_SEARCH_FILTER,searchFilter); ++ if (ccode) { ++ traceForce(conf->debug,LOG_WARNING,"NWDSInitBuf returned: %d\n", ccode); ++ goto Exit4; ++ } ++ ++ trace(conf->debug, LOG_NOTICE, "NWDSInitBuf searchFilter OK"); ++ ++ // Allocate a filter cursor to put the search expression ++ ccode = NWDSAllocFilter(&cur); ++ if (ccode) { ++ traceForce(conf->debug,LOG_WARNING,"NWDSAllocFilter returned: %d\n", ccode); ++ goto Exit4; ++ } ++ trace(conf->debug, LOG_NOTICE,"NWDSAllocFilter cur OK"); ++ // Build the expression tree in cur, then place into searchFilter ++ // Object Class = User ++ ccode = NWDSAddFilterToken(cur,FTOK_ANAME,"Object Class",SYN_CLASS_NAME); ++ if (ccode) { ++ traceForce(conf->debug,LOG_WARNING,"NWDSAddFilterToken OBJECTCLASS returned: %d\n", ccode); ++ goto Exit4; ++ } ++ ccode = NWDSAddFilterToken(cur,FTOK_EQ,NULL,0); ++ if (ccode) { ++ traceForce(conf->debug,LOG_WARNING,"NWDSAddFilterToken FTOK_EQ returned: %d\n", ccode); ++ goto Exit4; ++ } ++ ++ ccode = NWDSAddFilterToken(cur,FTOK_AVAL,classType.className,SYN_CLASS_NAME); ++ if (ccode) { ++ traceForce(conf->debug,LOG_WARNING,"NWDSAddFilterToken FTOK_AVAL User returned: %d\n", ccode); ++ goto Exit4; ++ } ++ ++ trace(conf->debug, LOG_NOTICE,"AddFilter for classname OK"); ++ ++ if (!allEntries) { ++ ccode = NWDSAddFilterToken(cur,FTOK_AND,NULL,0); ++ if (ccode ) { ++ traceForce(conf->debug,LOG_WARNING,"NWDSAddFilterToken FTOK_AND returned: %d\n", ccode); ++ goto Exit4; ++ } ++ ++ if (unixName) { ++ /* search for the CN or an alias in location strings */ ++ /* CN=unixName or L=N:unixNname or l=n:unixName */ ++ char buf1[255]; ++ char buf2[255]; ++ ++ if (strlen(unixName)+3 >sizeof(buf1)) { ++ //buffer overflow !!! ++ ccode=EINVAL; ++ traceForce(conf->debug,LOG_WARNING,"unixName %s is too long !!!!\n", unixName); ++ goto Exit4; ++ } ++ sprintf (buf1,"%s%s",classType.LAlias1,unixName); ++ sprintf (buf2,"%s%s",classType.LAlias2,unixName); ++ ++ ccode = NWDSAddFilterToken(cur,FTOK_LPAREN,NULL,0); ++ if (ccode ) { ++ traceForce(conf->debug,LOG_WARNING,"NWDSAddFilterToken FTOK_RPAREN returned: %d\n", ccode); ++ goto Exit4; ++ } ++ ++ ccode = NWDSAddFilterToken(cur,FTOK_ANAME,"CN",0); ++ if (ccode) { ++ traceForce(conf->debug,LOG_WARNING,"NWDSAddFilterToken FTOK_ANAME CN returned: %d\n", ccode); ++ goto Exit4; ++ } ++ ++ ccode = NWDSAddFilterToken(cur,FTOK_EQ,NULL,0); ++ if (ccode ) { ++ traceForce(conf->debug,LOG_WARNING,"NWDSAddFilterToken FTOK_EQ returned: %d\n", ccode); ++ goto Exit4; ++ } ++ ++ ccode = NWDSAddFilterToken(cur,FTOK_AVAL,unixName,SYN_CI_STRING); ++ if (ccode ) { ++ traceForce(conf->debug,LOG_WARNING,"NWDSAddFilterToken FTOK_AVAL %s returned: %d\n", unixName,ccode); ++ goto Exit4; ++ } ++ ccode = NWDSAddFilterToken(cur,FTOK_OR,NULL,0); ++ if (ccode ) { ++ traceForce(conf->debug,LOG_WARNING,"NWDSAddFilterToken FTOK_OR returned: %d\n", ccode); ++ goto Exit4; ++ } ++ ccode = NWDSAddFilterToken(cur,FTOK_ANAME,"L",0); ++ if (ccode) { ++ traceForce(conf->debug,LOG_WARNING,"NWDSAddFilterToken FTOK_ANAME L returned: %d\n", ccode); ++ goto Exit4; ++ } ++ ++ ccode = NWDSAddFilterToken(cur,FTOK_EQ,NULL,0); ++ if (ccode) { ++ traceForce(conf->debug,LOG_WARNING,"NWDSAddFilterToken FTOK_EQ returned: %d\n", ccode); ++ goto Exit4; ++ } ++ ccode = NWDSAddFilterToken(cur,FTOK_AVAL,buf1,SYN_CI_STRING); ++ if (ccode) { ++ traceForce(conf->debug,LOG_WARNING,"NWDSAddFilterToken FTOK_VAL %s returned: %d\n", buf1,ccode); ++ goto Exit4; ++ } ++ ccode = NWDSAddFilterToken(cur,FTOK_OR,NULL,0); ++ if (ccode) { ++ traceForce(conf->debug,LOG_WARNING,"NWDSAddFilterToken FTOK_OR returned: %d\n", ccode); ++ goto Exit4; ++ } ++ ccode = NWDSAddFilterToken(cur,FTOK_ANAME,"L",0); ++ if (ccode) { ++ traceForce(conf->debug,LOG_WARNING,"NWDSAddFilterToken FTOK_ANAME returned: %d\n", ccode); ++ goto Exit4; ++ } ++ ccode = NWDSAddFilterToken(cur,FTOK_EQ,NULL,0); ++ if (ccode) { ++ traceForce(conf->debug,LOG_WARNING,"NWDSAddFilterToken FTOK_END returned: %d\n", ccode); ++ goto Exit4; ++ } ++ ccode = NWDSAddFilterToken(cur,FTOK_AVAL,buf2,SYN_CI_STRING); ++ if (ccode) { ++ traceForce(conf->debug,LOG_WARNING,"NWDSAddFilterToken FTOK_AVAL %s returned: %d\n", buf2,ccode); ++ goto Exit4; ++ } ++ ccode = NWDSAddFilterToken(cur,FTOK_RPAREN,NULL,0); ++ if (ccode) { ++ traceForce(conf->debug,LOG_WARNING,"NWDSAddFilterToken FTOK_RPAREN returned: %d\n", ccode); ++ goto Exit4; ++ } ++ ++ } else { ++ if (id !=(uid_t)-1) { ++ /* search by UID.or GID ++ AND (L="U:xxxxx" OR L="u:xxxx" OR UNIX:UID = xxxx) for users ++ AND (L="G:xxxxx" OR L="g:xxxx" OR UNIX:GID = xxxx) for groups ++ */ ++ char buf1[80]; ++ char buf2[80]; ++ ++ sprintf (buf1,"%s%d",classType.LID1,id); ++ sprintf (buf2,"%s%d",classType.LID2,id); ++ ++ ccode = NWDSAddFilterToken(cur,FTOK_LPAREN,NULL,0); ++ if (ccode) { ++ traceForce(conf->debug,LOG_WARNING,"NWDSAddFilterToken FTOK_LPAREN returned: %d\n", ccode); ++ goto Exit4; ++ } ++ ccode = NWDSAddFilterToken(cur,FTOK_ANAME,"L",0); ++ if (ccode) { ++ traceForce(conf->debug,LOG_WARNING,"NWDSAddFilterToken FTOK_ANAME L returned: %d\n", ccode); ++ goto Exit4; ++ } ++ ++ ccode = NWDSAddFilterToken(cur,FTOK_EQ,NULL,0); ++ if (ccode) { ++ traceForce(conf->debug,LOG_WARNING,"NWDSAddFilterToken FTOK_EQ returned: %d\n", ccode); ++ goto Exit4; ++ } ++ ++ ccode = NWDSAddFilterToken(cur,FTOK_AVAL,buf1,SYN_CI_STRING); ++ if (ccode) { ++ traceForce(conf->debug,LOG_WARNING,"NWDSAddFilterToken FTOK_VAL %s returned: %d\n", buf1,ccode); ++ goto Exit4; ++ } ++ ccode = NWDSAddFilterToken(cur,FTOK_OR,NULL,0); ++ if (ccode) { ++ traceForce(conf->debug,LOG_WARNING,"NWDSAddFilterToken FTOK_OR returned: %d\n", ccode); ++ goto Exit4; ++ } ++ ccode = NWDSAddFilterToken(cur,FTOK_ANAME,"L",0); ++ if (ccode) { ++ traceForce(conf->debug,LOG_WARNING,"NWDSAddFilterToken FTOK_ANAME returned: %d\n", ccode); ++ goto Exit4; ++ } ++ ++ ccode = NWDSAddFilterToken(cur,FTOK_EQ,NULL,0); ++ if (ccode) { ++ traceForce(conf->debug,LOG_WARNING,"NWDSAddFilterToken FTOK_END returned: %d\n", ccode); ++ goto Exit4; ++ } ++ ccode = NWDSAddFilterToken(cur,FTOK_AVAL,buf2,SYN_CI_STRING); ++ if (ccode) { ++ traceForce(conf->debug,LOG_WARNING,"NWDSAddFilterToken FTOK_AVAL %s returned: %d\n", buf2,ccode); ++ goto Exit4; ++ } ++ ccode = NWDSAddFilterToken(cur,FTOK_OR,NULL,0); ++ if (ccode) { ++ traceForce(conf->debug,LOG_WARNING,"NWDSAddFilterToken FTOK_OR returned: %d\n", ccode); ++ goto Exit4; ++ } ++ ccode = NWDSAddFilterToken(cur,FTOK_ANAME,classType.nds8Attribute,0); ++ if (ccode) { ++ traceForce(conf->debug,LOG_WARNING,"NWDSAddFilterToken FTOK_ANAME returned: %d\n", ccode); ++ goto Exit4; ++ } ++ ++ ccode = NWDSAddFilterToken(cur,FTOK_EQ,NULL,0); ++ if (ccode) { ++ traceForce(conf->debug,LOG_WARNING,"NWDSAddFilterToken FTOK_END returned: %d\n", ccode); ++ goto Exit4; ++ } ++ ccode = NWDSAddFilterToken(cur,FTOK_AVAL,&buf1[2],SYN_INTEGER); ++ if (ccode) { ++ traceForce(conf->debug,LOG_WARNING,"NWDSAddFilterToken FTOK_AVAL %s returned: %d\n", buf2,ccode); ++ goto Exit4; ++ } ++ ccode = NWDSAddFilterToken(cur,FTOK_RPAREN,NULL,0); ++ if (ccode) { ++ traceForce(conf->debug,LOG_WARNING,"NWDSAddFilterToken FTOK_RPAREN returned: %d\n", ccode); ++ goto Exit4; ++ } ++ ++ } ++ } ++ } ++ ccode = NWDSAddFilterToken(cur,FTOK_END,NULL,0); ++ if (ccode) { ++ traceForce(conf->debug,LOG_WARNING,"NWDSAddFilterToken FTOK_END returned: %d\n", ccode); ++ goto Exit4; ++ } ++ ++ trace(conf->debug, LOG_NOTICE,"AddFilterToken FTOK_END OK"); ++ ++ // now place the cursor into the searchFilter buffer ++ // NWDSPutFilter frees the expression tree filter (cur) ++ // so if it succeeds, set cur to NULL so it won't be freed below ++ ccode = NWDSPutFilter(context,searchFilter,cur,NULL); ++ if (ccode) { ++ traceForce(conf->debug,LOG_WARNING,"NWDSPutFilter returned: %d\n", ccode); ++ goto Exit4; ++ } ++ else ++ cur=NULL; ++ ++ trace(conf->debug, LOG_NOTICE,"PutFilter OK"); ++ ++ // allocate and initialize the attrNames buffer (not used , needed ???) ++ ccode = NWDSAllocBuf(DEFAULT_MESSAGE_LEN,&attrNames); ++ if (ccode) { ++ traceForce(conf->debug,LOG_WARNING,"NWDSAllocBuf returned: %d\n", ccode); ++ goto Exit4; ++ } ++ ++ trace(conf->debug, LOG_NOTICE,"AllocBuf attrNamesOK"); ++ ++ ccode = NWDSInitBuf(context,DSV_SEARCH,attrNames); ++ if (ccode) { ++ traceForce(conf->debug,LOG_WARNING,"NWDSInitBuf returned: %d\n", ccode); ++ goto Exit4; ++ } ++ ++ trace(conf->debug, LOG_NOTICE,"InitBuf attrNames OK"); ++ ++ // Allocate a result buffer ++ ccode = NWDSAllocBuf(65500,&retBuf); ++ if (ccode) { ++ traceForce(conf->debug,LOG_WARNING,"NWDSAllocBuf returned: %d\n", ccode); ++ goto Exit4; ++ } ++ ++ trace(conf->debug, LOG_NOTICE,"AllocBuf retBuf OK, start searching..."); ++ ++ // PP 11-01-2003 ++ // with NCP_DEBUG=cleanup, if we exit here, usecount of the connection is still 1 (OK) ++ // so usecount is augmented below ++ //ccode=-1; ++ //goto Exit4; ++ ++ iterationHandle = NO_MORE_ITERATIONS; ++ // while NWDSSearch still can get some objects...( I expect 0 or 1) ++ do { ++ ccode = NWDSSearch(context, ++ //"[Root]", ++ conf->startCtx, ++ DS_SEARCH_SUBTREE, ++ FALSE, // don't dereference aliases ++ searchFilter, ++ FALSE, // we want ONLY attributes names ++ FALSE, // only want information in attrNames ++ attrNames, ++ &iterationHandle, ++ 0, // reserved ++ &countObjectsSearched, ++ retBuf); ++ if (ccode) { ++ traceForce(conf->debug,LOG_WARNING,"NWDSSearch returned: %s\n", strnwerror(ccode)); ++ goto Exit4; ++ } ++ // PP 11-01-2003 ++ // with NCP_DEBUG=cleanup, if we exit here, usecount of the connection is now 2 (bad) ++ // so it is NWDSSearch that augmented usecount !!!! ++ //ccode=-1; ++ //goto Exit4; ++ ++ ++ trace(conf->debug, LOG_NOTICE,"NWDSearch OK"); ++ // count the object returned in the buffer ++ ccode = NWDSGetObjectCount(context,retBuf,&objCount); ++ if (ccode) { ++ traceForce(conf->debug,LOG_WARNING,"NWDSGetObjectCount returned: %d\n", ccode); ++ goto Exit4; ++ } ++ if (objCount <= 0) { ++ ccode=-1; ++ goto Exit4; ++ } ++ if ( !allEntries && (objCount >1)) { ++ if (unixName) ++ traceForce(conf->debug,LOG_WARNING,"more than one NDS entry match the name=%s criteria. ",unixName); ++ else ++ traceForce(conf->debug,LOG_WARNING,"more than one NDS entry match the id=%d criteria. ",id); ++ } ++ trace(conf->debug, LOG_NOTICE,"GetObjectCount OK"); ++ // for the number of objects returned... ++ // for nss it should be only one !!! ++ for (objCntr=0;objCntrdebug,LOG_WARNING,"NWDSGetObjectName returned: %d\n", ccode); ++ goto Exit4; ++ } ++ ++ trace(conf->debug, LOG_NOTICE,"GetObjectName OK"); ++ ++ if (callBack.getinfo) { ++ ccode= callBack.getinfo(context,objectName,info,conf->debug); ++ if (ccode) ++ goto Exit4; ++ } ++ } ++ trace(conf->debug, LOG_NOTICE,"callback return OK"); ++ } while ((nuint32)iterationHandle != NO_MORE_ITERATIONS); ++ ++ trace(conf->debug, LOG_NOTICE,"End of iteration attrNamesOK"); ++ ++Exit4: ++ if ((nuint32)iterationHandle != NO_MORE_ITERATIONS){ ++ NWDSCCODE ccode2; ++ if (ccode2=NWDSCloseIteration(context,iterationHandle,DSV_SEARCH)) { ++ traceForce(conf->debug,LOG_WARNING,"NWDSCloseIteration returned: %d\n", ccode2); ++ } ++ } ++ if (retBuf) ++ NWDSFreeBuf(retBuf); ++ if (cur) ++ NWDSFreeFilter(cur, NULL); ++ if (searchFilter) ++ NWDSFreeBuf(searchFilter); ++ if (attrNames) ++ NWDSFreeBuf(attrNames); ++ ++ trace(conf->debug, LOG_NOTICE,"All buffers cleaned OK"); ++ ++Exit3: ++ if (ccode || !retConn){ ++ NWDSCCODE ccode2; ++ trace(conf->debug,LOG_NOTICE,"Closing connection %lx",conn); ++ ccode2=NWCCCloseConn (conn); ++ if (ccode2) ++ traceForce(conf->debug,LOG_WARNING,"NWCCloseConnection returned: %d %s\n", ccode,strnwerror(ccode2)); ++ }else ++ if (retConn) ++ *retConn=conn; ++Exit2: ++ if (ccode || !retContext) { ++ NWDSCCODE ccode2=NWDSFreeContext(context); ++ trace(conf->debug, LOG_NOTICE,"Freeing context"); ++ if (ccode2) ++ traceForce(conf->debug,LOG_WARNING,"NWDSFreeContext returned: %d %s\n", ccode,strnwerror(ccode2)); ++ }else ++ if (retContext) ++ *retContext=context; ++Exit1: ++ trace(conf->debug, LOG_NOTICE,"Leaving ..."); ++ return ccode; ++} ++ ++ ++ ++ ++static NWDSCCODE ++getpwdentbyxx(struct nw_user_info *ui, const char* userName, uid_t userId, struct nss_ncp_conf *conf){ ++ ++static const struct infoop getInfo={nds_user_info}; ++ ++return getentbyxx( ++ NULL, // context to return (NULL= close when leaving) ++ NULL, // connexion to return (NULL= close when leaving) ++ USER_CLASS, // class to search (User of Group) ++ ui, // structure to fill (can be nw_user_info,nw_shadow_info,nw_group_info) ++ getInfo, // routine to call for all found NDS objects ++ userName, // Unix objet name to find in NDS (if NULL search by ID) ++ userId, // Unix ID to find in NDS , if -1 search by unixName) ++ FALSE, // Ignore objectName and id and return all entries belonging to className ++ conf); // debug flag ++} ++ ++ ++static NWDSCCODE ++getgrpentbyxx(struct nw_group_info *gi, const char* groupName, gid_t groupId, struct nss_ncp_conf *conf){ ++ ++ static const struct infoop getInfo={nds_group_info}; ++ ++ return getentbyxx( ++ NULL, // context to return (NULL= close when leaving) ++ NULL, // connexion to return (NULL= close when leaving) ++ GROUP_CLASS, // class to search (User of Group) ++ gi, // structure to fill (can be nw_user_info,nw_shadow_info,nw_group_info) ++ getInfo, // routine to call for all found NDS objects ++ groupName, // Unix objet name to find in NDS (if NULL search by ID) ++ groupId, // Unix ID to find in NDS , if -1 search by unixName) ++ FALSE, // Ignore objectName and id and return all entries belonging to className ++ conf); // debug flag ++} ++ ++ ++ ++ ++static NWDSCCODE ++getspentbyxx(struct nw_shadow_info *si, const char* userName, struct nss_ncp_conf *conf){ ++// in shadow we search only by userName ++ static const struct infoop getInfo={nds_shadow_info}; ++ ++ return getentbyxx( ++ NULL, // context to return (NULL= close when leaving) ++ NULL, // connexion to return (NULL= close when leaving) ++ USER_CLASS, // class to search (User of Group) ++ si, // structure to fill (can be nw_user_info,nw_shadow_info,nw_group_info) ++ getInfo, // routine to call for all found NDS objects ++ userName, // Unix objet name to find in NDS (if NULL search by ID) ++ (uid_t)-1, // Unix ID to find in NDS , if -1 search by unixName) ++ FALSE, // Ignore objectName and id and return all entries belonging to className ++ conf); // debug flag ++} ++ ++static NWDSCCODE ++getusergroupsbyxx(struct nw_user_group_info *ui, const char* userName, uid_t userId, struct nss_ncp_conf *conf){ ++ ++static const struct infoop getInfo={nds_get_user_groups}; ++ ++ return getentbyxx( ++ NULL, // context to return (NULL= close when leaving) ++ NULL, // connexion to return (NULL= close when leaving) ++ USER_CLASS, // class to search (User of Group) ++ ui, // structure to fill (can be nw_user_info,nw_shadow_info,nw_group_info) ++ getInfo, // routine to call for all found NDS objects ++ userName, // Unix objet name to find in NDS (if NULL search by ID) ++ userId, // Unix ID to find in NDS , if -1 search by unixName) ++ FALSE, // Ignore objectName and id and return all entries belonging to className ++ conf); // debug flag ++} ++ ++ ++ ++static NWDSCCODE ++getallents(NWDSContextHandle *context,NWCONN_HANDLE *conn, ++ const struct class_info classType, struct ObjectList * tree, struct nss_ncp_conf *conf){ ++// called by all setxxent() if not control group is present in conf ++// get all entries by className ++// and add them to a sorted tree in memory ++// return context and conncetion for later use by ++ ++static const struct infoop getInfo={nds_insert_info}; ++ ++ return getentbyxx( ++ context, // context to return (NULL= close when leaving) ++ conn, // connexion to return (NULL= close when leaving) ++ classType, // class to search (User of Group) ++ tree, // structure to fill (can be nw_user_info,nw_shadow_info,nw_group_info) ++ getInfo, // routine to call for all found NDS objects ++ NULL, // Unix objet name to find in NDS (if NULL search by ID) ++ (uid_t)-1, // Unix ID to find in NDS , if -1 search by unixName) ++ TRUE, // Ignore objectName and id and return all entries belonging to className ++ conf); // debug flag ++} ++ ++/*******************************************************************************/ ++ ++ ++ ++/******************************* NSS API ***************************************/ ++ ++ ++enum nss_status _nss_ncp_initgroups (const char *userName, gid_t group, ++ long int *start, long int *size, gid_t * groups, ++ long int limit,int *errnop) { ++ ++ struct nw_user_group_info inf; ++ NWDSCCODE err; ++ struct nss_ncp_conf *conf= parse_conf(CNF_FILE); ++ ++ if (!conf || !conf->doGroup) ++ return NSS_STATUS_UNAVAIL; ++ if (conf->debug) { ++ openlog("ncp_nss", LOG_PID, LOG_AUTHPRIV); ++ trace (conf->debug, LOG_NOTICE,"nss_ncp_initgroups entering"); ++ } ++ ++ init_nw_user_group_info(&inf,conf->debug); ++ err= getusergroupsbyxx(&inf, userName, (uid_t)-1,conf); ++ switch (err) { ++ case 0: ++ if (conf->debug &QF_VERBOSE) ++ print_nw_user_group_info(inf); ++ if (!fix_nw_user_group_info(&inf,conf)) ++ err=nw_user_group_info_to_groups(inf,group,start,size,groups,limit,errnop,conf); ++ else err=NSS_STATUS_UNAVAIL; ++ break; ++ case -1: // NOT FOUND IN NDS ++ err=NSS_STATUS_NOTFOUND; ++ *errnop=ENOENT; ++ break; ++ default: // NDS error ++ err=NSS_STATUS_UNAVAIL; ++ *errnop=ENOENT; ++ break; ++ ++ } ++ free_nw_user_group_info(&inf); ++ if (conf->debug) { ++ trace (conf->debug, LOG_NOTICE,"nss_ncp_initgroups leaving"); ++ closelog(); ++ } ++ return err; ++} ++ ++ ++enum nss_status _nss_ncp_getpwnam_r (const char* name, struct passwd *pwd, ++ char * buffer, size_t buflen, int * errnop) { ++ ++ struct nw_user_info inf; ++ NWDSCCODE err; ++ struct nss_ncp_conf *conf= parse_conf(CNF_FILE); ++ ++ if (!conf || !conf->doPassword) ++ return NSS_STATUS_UNAVAIL; ++ ++ if (conf->debug) { ++ openlog("ncp_nss", LOG_PID, LOG_AUTHPRIV); ++ trace (conf->debug, LOG_NOTICE,"nss_ncp_getpwnam entering"); ++ } ++ init_nw_user_info(&inf,conf->debug); ++ err= getpwdentbyxx(&inf, name, (uid_t)-1,conf); ++ switch (err) { ++ case 0: ++ if (conf->debug &QF_VERBOSE) ++ print_nw_user_info(inf); ++ if (!fix_nw_user_info(&inf,conf)) ++ err=nw_user_info_to_passwd(inf,pwd,buffer,buflen,errnop,conf); ++ else err=NSS_STATUS_UNAVAIL; ++ break; ++ case -1: // NOT FOUND IN NDS ++ err=NSS_STATUS_NOTFOUND; ++ *errnop=ENOENT; ++ break; ++ default: // NDS error ++ err=NSS_STATUS_UNAVAIL; ++ *errnop=ENOENT; ++ break; ++ ++ } ++ free_nw_user_info(&inf); ++ if (conf->debug) { ++ trace (conf->debug, LOG_NOTICE,"nss_ncp_getpwnam leaving"); ++ closelog(); ++ } ++ return err; ++} ++ ++ ++enum nss_status _nss_ncp_getpwuid_r (uid_t uid, struct passwd *pwd, ++ char * buffer, size_t buflen, int * errnop) { ++ ++ struct nw_user_info inf; ++ NWDSCCODE err; ++ struct nss_ncp_conf *conf= parse_conf(CNF_FILE); ++ ++ if (!conf || !conf->doPassword) ++ return NSS_STATUS_UNAVAIL; ++ ++ if (conf->debug) { ++ openlog("ncp_nss", LOG_PID, LOG_AUTHPRIV); ++ trace (conf->debug, LOG_NOTICE,"nss_ncp_getpwuid entering"); ++ } ++ init_nw_user_info(&inf,conf->debug); ++ err= getpwdentbyxx(&inf, NULL, uid,conf); ++ switch (err) { ++ case 0: ++ if (conf->debug &QF_VERBOSE) ++ print_nw_user_info(inf); ++ if (!fix_nw_user_info(&inf,conf)) ++ err=nw_user_info_to_passwd(inf,pwd,buffer,buflen,errnop,conf); ++ else err=NSS_STATUS_UNAVAIL; ++ break; ++ case -1: // NOT FOUND IN NDS ++ err=NSS_STATUS_NOTFOUND; ++ *errnop=ENOENT; ++ break; ++ default: // NDS error ++ err=NSS_STATUS_UNAVAIL; ++ *errnop=ENOENT; ++ break; ++ ++ } ++ free_nw_user_info(&inf); ++ if (conf->debug) { ++ trace (conf->debug, LOG_NOTICE,"nss_ncp_getpwuid leaving"); ++ closelog(); ++ } ++ return err; ++} ++ ++ ++enum nss_status _nss_ncp_getgrnam_r (const char* name, struct group *grp, ++ char * buffer, size_t buflen, int * errnop) { ++ ++ struct nw_group_info inf; ++ NWDSCCODE err; ++ struct nss_ncp_conf *conf= parse_conf(CNF_FILE); ++ ++ if (!conf || !conf->doGroup) ++ return NSS_STATUS_UNAVAIL; ++ ++ if (conf->debug) { ++ openlog("ncp_nss", LOG_PID, LOG_AUTHPRIV); ++ trace (conf->debug, LOG_NOTICE,"nss_ncp_getgrnam entering"); ++ } ++ init_nw_group_info(&inf,conf->debug); ++ err= getgrpentbyxx(&inf, name, (gid_t)-1,conf); ++ switch (err) { ++ case 0: ++ if (conf->debug &QF_VERBOSE) ++ print_nw_group_info(inf); ++ if (!fix_nw_group_info(&inf,conf)) ++ err=nw_group_info_to_group(inf,grp,buffer,buflen,errnop,conf); ++ else err=NSS_STATUS_UNAVAIL; ++ break; ++ case -1: // NOT FOUND IN NDS ++ err=NSS_STATUS_NOTFOUND; ++ *errnop=ENOENT; ++ break; ++ default: // NDS error ++ err=NSS_STATUS_UNAVAIL; ++ *errnop=ENOENT; ++ break; ++ ++ } ++ free_nw_group_info(&inf); ++ if (conf->debug) { ++ trace (conf->debug, LOG_NOTICE,"nss_ncp_getgrnam leaving"); ++ closelog(); ++ } ++ return err; ++} ++ ++ ++enum nss_status _nss_ncp_getspnam_r (const char * name, struct spwd *spw, ++ char *buffer, size_t buflen,int * errnop) { ++ struct nw_shadow_info inf; ++ NWDSCCODE err; ++ struct nss_ncp_conf *conf= parse_conf(CNF_FILE); ++ ++ if (!conf || !conf->doShadow) ++ return NSS_STATUS_UNAVAIL; ++ ++ if (conf->debug) { ++ openlog("ncp_nss", LOG_PID, LOG_AUTHPRIV); ++ trace (conf->debug, LOG_NOTICE,"nss_ncp_getspnam entering"); ++ } ++ init_nw_shadow_info(&inf,conf->debug); ++ err= getspentbyxx(&inf, name,conf); ++ switch (err) { ++ case 0: ++ if (conf->debug &QF_VERBOSE) ++ print_nw_shadow_info(inf); ++ if (!fix_nw_shadow_info(&inf,conf)) ++ err=nw_shadow_info_to_shadow(inf,spw,buffer,buflen,errnop,conf); ++ else err=NSS_STATUS_UNAVAIL; ++ break; ++ case -1: // NOT FOUND IN NDS ++ err=NSS_STATUS_NOTFOUND; ++ *errnop=ENOENT; ++ break; ++ default: // NDS error ++ err=NSS_STATUS_UNAVAIL; ++ *errnop=ENOENT; ++ break; ++ ++ } ++ free_nw_shadow_info(&inf); ++ if (conf->debug) { ++ trace (conf->debug, LOG_NOTICE,"nss_ncp_getspnam leaving"); ++ closelog(); ++ } ++ return err; ++ ++} ++ ++ ++enum nss_status _nss_ncp_getgrgid_r (gid_t gid, struct group *grp, ++ char * buffer, size_t buflen, int * errnop) { ++ struct nw_group_info inf; ++ NWDSCCODE err; ++ struct nss_ncp_conf *conf= parse_conf(CNF_FILE); ++ ++ if (!conf || !conf->doGroup) ++ return NSS_STATUS_UNAVAIL; ++ ++ if (conf->debug) { ++ openlog("ncp_nss", LOG_PID, LOG_AUTHPRIV); ++ trace (conf->debug, LOG_NOTICE,"nss_ncp_getgrgid entering"); ++ } ++ init_nw_group_info(&inf,conf->debug); ++ err= getgrpentbyxx(&inf, NULL, gid,conf); ++ switch (err) { ++ case 0: ++ if (conf->debug &QF_VERBOSE) ++ print_nw_group_info(inf); ++ if (!fix_nw_group_info(&inf,conf)) ++ err=nw_group_info_to_group(inf,grp,buffer,buflen,errnop,conf); ++ else err=NSS_STATUS_UNAVAIL; ++ break; ++ case -1: // NOT FOUND IN NDS ++ err=NSS_STATUS_NOTFOUND; ++ *errnop=ENOENT; ++ break; ++ default: // NDS error ++ err=NSS_STATUS_UNAVAIL; ++ *errnop=ENOENT; ++ break; ++ ++ } ++ free_nw_group_info(&inf); ++ if (conf->debug) { ++ trace (conf->debug, LOG_NOTICE,"nss_ncp_getgrid leaving"); ++ closelog(); ++ } ++ return err; ++} ++ ++ ++enum nss_status _nss_ncp_setpwent(void) { ++ NWDSContextHandle context; ++ NWCONN_HANDLE conn; ++ NWDSCCODE ccode; ++ struct nss_ncp_conf *conf= parse_conf(CNF_FILE); ++ ++ if (!conf || !conf->doPassword) ++ return NSS_STATUS_UNAVAIL; ++ ++ if (conf->debug) { ++ openlog("ncp_nss", LOG_PID, LOG_AUTHPRIV); ++ trace (conf->debug, LOG_NOTICE,"nss_ncp_setpwent entering"); ++ } ++ ndsUsers= __allocTree(FALSE,conf); ++ if (ndsUsers) { ++ if (conf->ctrlGroup && conf->ctrlGroup[0]) // caution if empty string from conf or default ++ ccode=getgroupmembers(&context,&conn,conf->ctrlGroup,ndsUsers,conf); ++ else ++ ccode=getallents(&context,&conn,USER_CLASS,ndsUsers,conf); ++ ++ if (!ccode) { ++ ndsUsers->context=context; ++ ndsUsers->conn=conn; ++ ndsUsers->curr = ndsUsers->lin; ++ ndsUsers->remainObjects = ndsUsers->uniqueObjects; ++ ccode= NSS_STATUS_SUCCESS; ++ } else { ++ __freeTree(ndsUsers); ++ ndsUsers=NULL; ++ ccode= NSS_STATUS_UNAVAIL; ++ } ++ }else ++ ccode= NSS_STATUS_UNAVAIL; ++ ++ if (conf->debug) { ++ trace (conf->debug, LOG_NOTICE,"nss_ncp_setpwent leaving"); ++ closelog(); ++ } ++ return ccode; ++ ++} ++ ++enum nss_status _nss_ncp_setgrent(void) { ++ NWDSContextHandle context; ++ NWCONN_HANDLE conn; ++ enum nss_status ccode; ++ struct nss_ncp_conf *conf= parse_conf(CNF_FILE); ++ ++ if (!conf || !conf->doGroup) ++ return NSS_STATUS_UNAVAIL; ++ ++ if (conf->debug) { ++ openlog("ncp_nss", LOG_PID, LOG_AUTHPRIV); ++ trace (conf->debug, LOG_NOTICE,"nss_ncp_setgrent entering"); ++ } ++ ndsGroups= __allocTree(FALSE,conf); ++ if (ndsGroups) { ++ if (! getallents(&context,&conn,GROUP_CLASS,ndsGroups,conf)) { ++ ndsGroups->context=context; ++ ndsGroups->conn=conn; ++ ndsGroups->curr = ndsGroups->lin; ++ ndsGroups->remainObjects = ndsGroups->uniqueObjects; ++ ccode=NSS_STATUS_SUCCESS; ++ } else { ++ __freeTree(ndsGroups); ++ ndsGroups=NULL; ++ ccode=NSS_STATUS_UNAVAIL; ++ } ++ }else ++ ccode= NSS_STATUS_UNAVAIL; ++ ++ if (conf->debug) { ++ trace (conf->debug, LOG_NOTICE,"nss_ncp_setgrent leaving"); ++ closelog(); ++ } ++ return ccode; ++ ++} ++ ++ ++enum nss_status _nss_ncp_setspent (void) { ++ NWDSContextHandle context; ++ NWCONN_HANDLE conn; ++ NWDSCCODE ccode; ++ struct nss_ncp_conf *conf= parse_conf(CNF_FILE); ++ ++ if (!conf || !conf->doShadow) ++ return NSS_STATUS_UNAVAIL; ++ ++ if (conf->debug) { ++ openlog("ncp_nss", LOG_PID, LOG_AUTHPRIV); ++ trace (conf->debug, LOG_NOTICE,"nss_ncp_setspent entering"); ++ } ++ ndsShadows= __allocTree(FALSE,conf); ++ if (ndsShadows) { ++ if (conf->ctrlGroup && conf->ctrlGroup[0]) // caution if empty string from conf or default ++ ccode=getgroupmembers(&context,&conn,conf->ctrlGroup,ndsShadows,conf); ++ else ++ ccode=getallents(&context,&conn,USER_CLASS,ndsShadows,conf); ++ ++ if (!ccode) { ++ ndsShadows->context=context; ++ ndsShadows->conn=conn; ++ ndsShadows->curr = ndsShadows->lin; ++ ndsShadows->remainObjects = ndsShadows->uniqueObjects; ++ ccode=NSS_STATUS_SUCCESS; ++ } else { ++ __freeTree(ndsShadows); ++ ndsShadows=NULL; ++ ccode=NSS_STATUS_UNAVAIL; ++ } ++ }else ++ ccode= NSS_STATUS_UNAVAIL; ++ ++ if (conf->debug) { ++ trace (conf->debug, LOG_NOTICE,"nss_ncp_setspent leaving"); ++ closelog(); ++ } ++ return ccode; ++ ++} ++ ++ ++enum nss_status _nss_ncp_endpwent(void) { ++ enum nss_status ccode; ++ ++ ++ if (ndsUsers) { ++ struct nss_ncp_conf *conf=ndsUsers->conf; ++ ++ if (conf->debug) { ++ openlog("ncp_nss", LOG_PID, LOG_AUTHPRIV); ++ trace (conf->debug, LOG_NOTICE,"nss_ncp_endpwent entering"); ++ } ++ NWCCCloseConn (ndsUsers->conn); ++ NWDSFreeContext(ndsUsers->context); ++ __freeTree(ndsUsers); ++ ndsUsers=NULL; ++ trace (conf->debug, LOG_NOTICE,"nss_ncp_setpwent all cleaned up OK"); ++ if (conf->debug) { ++ trace (conf->debug, LOG_NOTICE,"nss_ncp_setpwent leaving"); ++ closelog(); ++ } ++ ccode=NSS_STATUS_SUCCESS; ++ }else { ++ trace (QF_DEBUG, LOG_ERR,"nss_ncp_endpwent called without a previous nss_ncp_setpwent: nothing to cleanup"); ++ ccode=NSS_STATUS_UNAVAIL; ++ } ++ return ccode; ++} ++ ++ ++enum nss_status _nss_ncp_endgrent(void) { ++ enum nss_status ccode; ++ ++ ++ if (ndsGroups) { ++ struct nss_ncp_conf *conf=ndsGroups->conf; ++ ++ if (conf->debug) { ++ openlog("ncp_nss", LOG_PID, LOG_AUTHPRIV); ++ trace (conf->debug, LOG_NOTICE,"nss_ncp_endgrent entering"); ++ } ++ NWCCCloseConn (ndsGroups->conn); ++ NWDSFreeContext(ndsGroups->context); ++ __freeTree(ndsGroups); ++ ndsGroups=NULL; ++ trace (conf->debug, LOG_NOTICE,"nss_ncp_endgrent all cleaned up OK"); ++ if (conf->debug) { ++ trace (conf->debug, LOG_NOTICE,"nss_ncp_endpwent leaving"); ++ closelog(); ++ } ++ ccode=NSS_STATUS_SUCCESS; ++ }else { ++ trace (QF_DEBUG, LOG_ERR,"nss_ncp_endgrent called without a previous nss_ncp_setgrent : nothing to cleanup"); ++ ccode=NSS_STATUS_UNAVAIL; ++ } ++ return ccode; ++} ++ ++ ++enum nss_status _nss_ncp_endspent (void) { ++ enum nss_status ccode; ++ ++ ++ if (ndsShadows) { ++ struct nss_ncp_conf *conf=ndsShadows->conf; ++ if (conf->debug) { ++ openlog("ncp_nss", LOG_PID, LOG_AUTHPRIV); ++ trace (conf->debug, LOG_NOTICE,"nss_ncp_endspent entering"); ++ } ++ ++ NWCCCloseConn (ndsShadows->conn); ++ NWDSFreeContext(ndsShadows->context); ++ __freeTree(ndsShadows); ++ ndsShadows=NULL; ++ trace (conf->debug, LOG_NOTICE,"nss_ncp_endspent all cleaned up up OK"); ++ if (conf->debug) { ++ trace (conf->debug, LOG_NOTICE,"nss_ncp_endspent leaving"); ++ closelog(); ++ } ++ ccode=NSS_STATUS_SUCCESS; ++ }else { ++ trace (QF_DEBUG, LOG_ERR,"nss_ncp_endspent called without a previous nss_ncp_setspent : nothing to cleanup"); ++ ccode=NSS_STATUS_UNAVAIL; ++ } ++ return ccode; ++} ++ ++enum nss_status _nss_ncp_getpwent_r(struct passwd *pwd, ++ char * buffer, size_t buflen, int * errnop) { ++ enum nss_status err; ++ ++ if (ndsUsers) { ++ struct TreeNode* n; ++ NWDSCCODE ccode; ++ struct nw_user_info ui; ++ struct nss_ncp_conf *conf=ndsUsers->conf; ++ const char* ndsName; ++ if (conf->debug) { ++ openlog("ncp_nss", LOG_PID, LOG_AUTHPRIV); ++ trace (conf->debug, LOG_NOTICE,"nss_ncp_getpwent entering"); ++ } ++ ++next_user:; // avoid a recursive call ++ n = ndsUsers->curr; ++ if (!n) { ++ //ready to scan again from the beginning (a good idea ??) ++ ndsUsers->curr = ndsUsers->lin; ++ ndsUsers->remainObjects = ndsUsers->uniqueObjects; ++ err= NSS_STATUS_NOTFOUND; ++ } else { ++ ndsName=n->name; ++ init_nw_user_info(&ui,conf->debug); ++ ccode=nds_user_info(ndsUsers->context,n->name,&ui,conf->debug); ++ ++ if (ccode) { ++ free_nw_user_info(&ui); ++ err=NSS_STATUS_NOTFOUND; ++ goto exit; ++ } ++ if (conf->debug &QF_VERBOSE) ++ print_nw_user_info(ui); ++ if (!fix_nw_user_info(&ui,conf)) ++ err=nw_user_info_to_passwd(ui,pwd,buffer,buflen,&errno,conf); ++ else err=NSS_STATUS_UNAVAIL; ++ free_nw_user_info(&ui); ++ switch (err) { ++ case NSS_STATUS_TRYAGAIN: ++ // buffer was too small ++ // do not advance to next user ++ // and let nss to try again with a bigger buffer; ++ break; ++ default: ++ // move to next user ++ if (!--n->cnt) { ++ ndsUsers->curr = n->next; ++ ndsUsers->remainObjects--; ++ } ++ if (err==NSS_STATUS_NOTFOUND) {// user has no unix property, skip ++ trace (conf->debug, LOG_NOTICE,"user %s has not Unix properties in NDS,skipping",ndsName); ++ goto next_user; ++ }else ++ err=NSS_STATUS_SUCCESS; ++ } ++ } ++exit: ++ if (conf->debug) { ++ trace (conf->debug, LOG_NOTICE,"nss_ncp_getpwent leaving"); ++ closelog(); ++ } ++ ++ }else { ++ err=NSS_STATUS_UNAVAIL; ++ } ++ return err; ++ ++} ++ ++ ++enum nss_status _nss_ncp_getgrent_r(struct group *grp, ++ char * buffer, size_t buflen, int * errnop) { ++ enum nss_status err; ++ ++ if (ndsGroups) { ++ struct TreeNode* n; ++ NWDSCCODE ccode; ++ const char* ndsName; ++ struct nw_group_info gi; ++ struct nss_ncp_conf *conf=ndsGroups->conf; ++ ++ if (conf->debug) { ++ openlog("ncp_nss", LOG_PID, LOG_AUTHPRIV); ++ trace (conf->debug, LOG_NOTICE,"nss_ncp_getgrent entering"); ++ } ++next_group:; // avoid a recursive call ++ n = ndsGroups->curr; ++ if (!n) { ++ //ready to scan again from the beginning (a good idea ??) ++ ndsGroups->curr = ndsGroups->lin; ++ ndsGroups->remainObjects = ndsGroups->uniqueObjects; ++ err= NSS_STATUS_NOTFOUND; ++ ++ }else { ++ ndsName=n->name; ++ init_nw_group_info(&gi,conf->debug); ++ ccode=nds_group_info(ndsGroups->context,n->name,&gi,conf->debug); ++ if (ccode) { ++ free_nw_group_info(&gi); ++ err= NSS_STATUS_NOTFOUND; ++ goto exit; ++ } ++ if (conf->debug &QF_VERBOSE) ++ print_nw_group_info(gi); ++ if (!fix_nw_group_info(&gi,conf)) ++ err=nw_group_info_to_group(gi,grp,buffer,buflen,&errno,conf); ++ else err=NSS_STATUS_UNAVAIL; ++ free_nw_group_info(&gi); ++ switch (err) { ++ case NSS_STATUS_TRYAGAIN: ++ // buffer was too small ++ // do not advance to next group ++ // and let nss to try again with a bigger buffer ++ break; ++ default: ++ // move to next group ++ if (!--n->cnt) { ++ ndsGroups->curr = n->next; ++ ndsGroups->remainObjects--; ++ } ++ if (err==NSS_STATUS_NOTFOUND) {// group has no unix property, skip ++ trace (conf->debug, LOG_NOTICE,"group %s has not Unix properties in NDS,skipping",ndsName); ++ goto next_group; ++ } else ++ err=NSS_STATUS_SUCCESS; ++ } ++ } ++exit: ++ if (conf->debug) { ++ trace (conf->debug, LOG_NOTICE,"nss_ncp_getgrent leaving"); ++ closelog(); ++ } ++ ++ }else { ++ err= NSS_STATUS_UNAVAIL; ++ } ++ return err; ++} ++ ++ ++enum nss_status _nss_ncp_getspent_r (struct spwd *spw, ++ char * buffer, size_t buflen,int * errnop) { ++ enum nss_status err; ++ ++ ++ if (ndsShadows) { ++ struct TreeNode* n; ++ NWDSCCODE ccode; ++ const char* ndsName; ++ struct nw_shadow_info si; ++ struct nss_ncp_conf *conf=ndsShadows->conf; ++ ++ if (conf->debug) { ++ openlog("ncp_nss", LOG_PID, LOG_AUTHPRIV); ++ trace (conf->debug, LOG_NOTICE,"nss_ncp_getgrent entering"); ++ } ++next_user:; // avoid a recursive call ++ n = ndsShadows->curr; ++ if (!n) { ++ //ready to scan again from the beginning (a good idea ??) ++ ndsShadows->curr = ndsShadows->lin; ++ ndsShadows->remainObjects = ndsShadows->uniqueObjects; ++ err= NSS_STATUS_NOTFOUND; ++ }else { ++ ndsName=n->name; ++ init_nw_shadow_info(&si,conf->debug); ++ ccode=nds_shadow_info(ndsShadows->context,n->name,&si,conf->debug); ++ if (ccode) { ++ free_nw_shadow_info(&si); ++ err=NSS_STATUS_NOTFOUND; ++ goto exit; ++ } ++ if (conf->debug &QF_VERBOSE) ++ print_nw_shadow_info(si); ++ if (!fix_nw_shadow_info(&si,conf)) ++ err=nw_shadow_info_to_shadow(si,spw,buffer,buflen,&errno,conf); ++ else err=NSS_STATUS_UNAVAIL; ++ free_nw_shadow_info(&si); ++ switch (err) { ++ case NSS_STATUS_TRYAGAIN: ++ // buffer was too small ++ // do not advance to next user ++ // and let nss to try again with a bigger buffer; ++ break; ++ default: ++ // move to next user ++ if (!--n->cnt) { ++ ndsShadows->curr = n->next; ++ ndsShadows->remainObjects--; ++ } ++ if (err==NSS_STATUS_NOTFOUND) {// user has no unix property, skip ++ trace (conf->debug, LOG_NOTICE,"user %s has not Unix properties in NDS,skipping",ndsName); ++ goto next_user; ++ } ++ else ++ err=NSS_STATUS_SUCCESS; ++ } ++ } ++exit: ++ if (conf->debug) { ++ trace (conf->debug, LOG_NOTICE,"nss_ncp_getspent leaving"); ++ closelog(); ++ } ++ }else { ++ return NSS_STATUS_UNAVAIL; ++ } ++ return err; ++ ++} ++ +diff -r 3143e61fb504 -r 1a8455ed3290 contrib/ncp_nss_lib/nss_ncp.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/contrib/ncp_nss_lib/nss_ncp.h Sun Oct 16 02:40:25 2005 +0200 +@@ -0,0 +1,175 @@ ++/************************************************************************** ++ nss_ncp.h header for NSS for NDS ++ ++ Copyright (C) 2002 Patrick Pollet ++ ++ 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 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 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ ++ ++ Revision history: ++ ++ 1.00 2003, January 06 Patrick Pollet ++ initial release ++ ++************************************************************************/ ++#ifndef HAVE_NSS_NCP_H ++#define HAVE_NSS_NCP_H ++ ++#define TRUE 1 ++#define FALSE 0 ++ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++#include ++ ++ ++ ++// USE_DUMMY_ATTRibutes must be set in the Makefile ++//#define USING_DUMMY_ATTRIBUTES ++ ++#ifndef USING_DUMMY_ATTRIBUTES ++// the real ones ++#define ATTR_UID "UNIX:UID" ++#define ATTR_PGNAME "UNIX:Primary GroupName" ++#define ATTR_PGID "UNIX:Primary GroupID" ++#define ATTR_GID "UNIX:GID" ++#define ATTR_SHELL "UNIX:Login Shell" ++#define ATTR_COM "UNIX:Comments" ++#define ATTR_HOME "UNIX:Home Directory" ++#else ++// dummy attributes for testing ++// created with Schemax with the same syntax ++// and associated to user class and group class ++#define ATTR_UID "LINUX:UID" ++#define ATTR_PGNAME "LINUX:Primary GroupName" ++#define ATTR_PGID "LINUX:Primary GroupID" ++#define ATTR_GID "LINUX:GID" ++#define ATTR_SHELL "LINUX:Login Shell" ++#define ATTR_COM "LINUX:Comments" ++#define ATTR_HOME "LINUX:Home Directory" ++#endif ++ ++// the attribute used to test presence of NDS8 ++// either real or dummy (not used yet) ++#define ATTR_NDS8 ATTR_UID ++ ++// other attributes used ++// absent NDS8 attributes are searched in L attribute ++// also new properties ( Zenux Flags, Other group...) ++ ++#define ATTR_CN "CN" ++#define ATTR_LOCATION "L" ++ ++#define ATTR_GRP_MBS "Group Membership" ++#define ATTR_MEMBERS "Member" ++#define ATTR_FULL_NAME "Full Name" ++ ++#define ATTR_DATE_PWD_EXPIRE "Password Expiration Time" ++#define ATTR_INT_PWD_EXPIRE "Password Expiration Interval" ++#define ATTR_GRACE_LIMIT "Login Grace Limit" ++#define ATTR_DATE_ACCT_EXPIRE "Login Expiration Time" ++ ++ ++// the proper naming attribute may be customized here (must be a CI_STRING ) ++#define ATTR_GECOS ATTR_FULL_NAME ++ ++// syntaxes of the used attributes ++#define SYN_CN SYN_CI_STRING ++#define SYN_LOCATION SYN_CI_STRING ++#define SYN_UID SYN_INTEGER ++#define SYN_PGNAME SYN_DIST_NAME ++#define SYN_PGID SYN_INTEGER ++#define SYN_GID SYN_INTEGER ++#define SYN_SHELL SYN_CE_STRING ++#define SYN_COM SYN_CI_STRING ++#define SYN_HOME SYN_CE_STRING ++#define SYN_GRP_MBS SYN_DIST_NAME ++#define SYN_MEMBERS SYN_DIST_NAME ++ ++ ++ ++#define QF_DEBUG 0x0001 ++#define QF_VERBOSE 0x0002 ++ ++#define NFS_NOBODY = 65534 ++#define CNF_FILE "/etc/nss_ncp.conf" ++ ++ ++ ++ ++/******************************* NSS API ***************************************/ ++ ++ ++enum nss_status _nss_ncp_initgroups (const char *userName, gid_t group, ++ long int *start, long int *size, gid_t * groups, ++ long int limit,int *errnop); ++ ++ ++enum nss_status _nss_ncp_getpwnam_r (const char* name, struct passwd *pwd, ++ char * buffer, size_t buflen, int * errnop); ++ ++ ++ ++enum nss_status _nss_ncp_getpwuid_r (uid_t uid, struct passwd *pwd, ++ char * buffer, size_t buflen, int * errnop); ++ ++ ++enum nss_status _nss_ncp_getgrnam_r (const char* name, struct group *grp, ++ char * buffer, size_t buflen, int * errnop); ++ ++ ++ ++enum nss_status _nss_ncp_getspnam_r (const char * name, struct spwd *spw, ++ char *buffer, size_t buflen,int * errnop); ++ ++ ++enum nss_status _nss_ncp_getgrgid_r (gid_t gid, struct group *grp, ++ char * buffer, size_t buflen, int * errnop); ++ ++ ++ ++enum nss_status _nss_ncp_setpwent(void); ++ ++enum nss_status _nss_ncp_setgrent(void); ++ ++enum nss_status _nss_ncp_setspent (void); ++ ++enum nss_status _nss_ncp_endpwent(void); ++ ++enum nss_status _nss_ncp_endgrent(void); ++ ++enum nss_status _nss_ncp_endspent (void); ++ ++enum nss_status _nss_ncp_getpwent_r(struct passwd *pwd, char * buffer, size_t buflen, int * errnop); ++ ++enum nss_status _nss_ncp_getgrent_r(struct group *grp,char * buffer, size_t buflen, int * errnop); ++ ++ ++enum nss_status _nss_ncp_getspent_r (struct spwd *spw,char * buffer, size_t buflen,int * errnop); ++ ++#endif +diff -r 3143e61fb504 -r 1a8455ed3290 contrib/ncp_nss_lib/test_ncp_nss.c +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/contrib/ncp_nss_lib/test_ncp_nss.c Sun Oct 16 02:40:25 2005 +0200 +@@ -0,0 +1,318 @@ ++/************************************************************************** ++ getpwduid.c:test program for NSS for NDS ++ ++ Copyright (C) 2002 Patrick Pollet ++ ++ 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 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 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ ++ ++ Revision history: ++ ++ 1.00 2003, January 06 Patrick Pollet ++ initial release ++ 1.01 2003, January 08 Patrick Pollet ++ added conf structure and control group ++ added optional fallback UID and GID if none found in NDS (default is to skip user,group) ++ 1.02 2003, January 09 Patrick Pollet ++ added initgroups ++ 1.03 2003, January 10 Patrick Pollet ++ fixed bug in nds_user_info2 (bad structure received by nds_user_location2) ++ 1.04 2003, January 11 Patrick Pollet ++ fixed setting ndsXXX=NULL trees in case of errors in _nss_ncp_setxxent() ++ made always NAME_CONTEXT=[Root] in CreateContextAndConn ++ calling NWCCloseIteration only it some errors has occured in the search ++ 1.05 ++ modified to use nss_ncp.so ++************************************************************************/ ++ ++ ++#define TRUE 1 ++#define FALSE 0 ++ ++#include ++#include ++#include ++#include ++ ++#ifdef VERBOSE ++#include ++#endif ++#include ++#include ++#include ++#include ++ ++#include "private/libintl.h" ++ ++#include ++#include ++#include ++#include ++ ++#include ++ ++#include "nss_ncp.h" ++#include "nss_cfgfile.h" ++ ++ ++ ++/**************** TESTING ******************/ ++ ++static void print_passwd (struct passwd pwd){ ++ printf("%s:%s:%d:%d:%s:%s:%s\n",pwd.pw_name,pwd.pw_passwd,pwd.pw_uid,pwd.pw_gid,pwd.pw_gecos,pwd.pw_dir,pwd.pw_shell); ++} ++ ++static void print_group (struct group grp){ ++ char ** mmb; int num; ++ printf("%s:%s:%d:",grp.gr_name,grp.gr_passwd,grp.gr_gid); ++ for (mmb=grp.gr_mem,num=0;*mmb; mmb++,num++) { ++ if (num) ++ printf(","); ++ printf ("%s",*mmb); ++ ++ } ++ printf("\n"); ++ ++} ++ ++static void print_shadow (struct spwd spw){ ++ printf("%s:%s:%ld:%ld:%ld:%ld:%ld:%ld:%ld\n",spw.sp_namp,spw.sp_pwdp,spw.sp_lstchg,spw.sp_min,spw.sp_max,spw.sp_warn,spw.sp_inact,spw.sp_expire,spw.sp_flag); ++} ++ ++ ++static void print_user_groups(gid_t * groups, long int start, long int size){ ++ int i; ++ printf("start=%d size=%d\n",start,size); ++ for (i=0; i $@; \ + [ -s $@ ] || rm -f $@ + +$(STATIC_BASE_OBJ): %.o: %.c %.h + $(CC) $(STATIC_CFLAGS) $(CFLAGS_$@) $(BASE_CFLAGS) -o $@ -c $< + + +$(SHARED_BASE_OBJ): %.do: %.c %.h + $(CC) $(SHARED_CFLAGS) $(CFLAGS_$(@:.do=.o)) $(BASE_CFLAGS) -o $@ -c $< + + +$(O_UTILS1) $(O_TMP1): %.o: %.c + $(CC) $(CCFLAGS) $(CFLAGS) $(CFLAGS_$@) -o $@ -c $< + +$(UTILS1):: %: %.o $(O_TMP1) + $(CC) $(LDFLAGS) $(CFLAGS) -o $@ $(addsuffix .o,$@) $(OBJS_$@) -L$(top_builddir)/lib -lnss_ncp -lncp $(LDFLAGS_$@) + + +dep: + +clean: + rm -f *.o *.do *.to *~ + +mrproper: clean + rm -f $(UTILS) $(DISTFILE) + +distclean: mrproper + +install_shared: $(SHARED_NCPLIB_BIN) + $(INSTALL) -d $(DESTDIR)$(libsodir) + $(INSTALL) $(SHARED_NCPLIB_BIN) $(DESTDIR)$(libsodir) + -ldconfig + + +$(SHARED_NSSLIB): $(SHARED_NSSLIB_BIN) + rm -f $@ + ln -sf $< $@ + +$(SHARED_NSSLIB_BIN): $(SHARED_O_OBJ) ${this_srcdir}/libncp.vers + $(CC) -shared -o $@ -Wl,-soname=$(SHARED_NSSLIB_SONAME) $(SHARED_VLINK) $(SHARED_O_OBJ) -L$(NCPLIB_DIR) -lncp ${LIBS} + + + diff --git a/contrib/ncp_nss_lib/ncpfs.conf b/contrib/ncp_nss_lib/ncpfs.conf new file mode 100644 index 0000000..b425904 --- /dev/null +++ b/contrib/ncp_nss_lib/ncpfs.conf @@ -0,0 +1,29 @@ +[Requester] + + +[ncp_nss] +useTree=1 +server=INSA_ROOT +startCtx= +ctrlGroup= +doPasswd=1 +doShadow=1 +doGroup=1 + +defGid=100 +defShell=/bin/bash +debug=1 + +fallbackUid=-1 +fallbackGid=-1 + +[pam] +useTree=1 +server=INSA_ROOT +searchCtx=PC,S.PC,GCP.PC +debug=1 +mountLocally=1 +createLocalHome=0 + +zenOn= +zenOff= diff --git a/contrib/ncp_nss_lib/nss_cfgfile.c b/contrib/ncp_nss_lib/nss_cfgfile.c new file mode 100644 index 0000000..0012983 --- /dev/null +++ b/contrib/ncp_nss_lib/nss_cfgfile.c @@ -0,0 +1,333 @@ +/* + nss_cfgfile.c - Configuration file handling + Copyright (C) 2000 Petr Vandrovec + Copyright (C) 2003 Patrick Pollet + + 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 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 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + Revision history: + + 1.00 2003, Jan 16 Patrick Pollet + Initial revision, stronly inspired by ncpfs/lib/cfgfile.c + + + */ + +#include "config.h" + + +#include "private/libncp-lock.h" + + +#include +#include +#include +#include +#include +#include +#include + +#include "nss_cfgfile.h" +// temporary define (waiting for a better Makefile) +#define GLOBALCFGFILE "/etc/ncpfs.conf" +#ifndef GLOBALCFGFILE +#error "GLOBALCFGFILE must be defined" +#endif + + +// #define DEBUG 1 + +static struct nss_ncp_conf* alloc_nss_ncp_conf (){ + struct nss_ncp_conf * conf; + + conf= (struct nss_ncp_conf *)malloc(sizeof(*conf)); + if (!conf) + return NULL; + return conf; +} + + +void free_nss_ncp_conf (struct nss_ncp_conf *conf){ +#define FREEFIELD(x) do if (conf->x) {free(conf->x) ; conf->x=NULL;} while (0); + if (conf && conf !=&defConf) { + FREEFIELD(server); + FREEFIELD(startCtx); + FREEFIELD(ctrlGroup); + FREEFIELD(defShell); + } +#undef FREEFIELD +} + + +struct cfgFile { + ncpt_mutex_t mutex; + FILE* file; +}; + +static struct cfgFile* cfgOpenFile( + const char* path, + int writeRequired) { + struct cfgFile* cfg; + + cfg = (struct cfgFile*)malloc(sizeof(*cfg)); + if (cfg) { + cfg->file = fopen(path, writeRequired ? "r+" : "r"); + if (cfg->file) { + ncpt_mutex_init(&cfg->mutex); + } else { + free(cfg); + cfg = NULL; + } + } + return cfg; +} + +static void cfgClose( + struct cfgFile* cfg) { + ncpt_mutex_lock(&cfg->mutex); + fclose(cfg->file); + ncpt_mutex_destroy(&cfg->mutex); + free(cfg); +} + + +struct check { + const char *option; /* configuration option */ + int mandatory; /* can be empty or null */ + int found; /*set to TRUE if found in cfg file */ + void ** value_ptr; /* temporary storage place */ + int isNum; /* 1 is numeric, 0 is string*/ + const char* defValue; +}; + + +#ifdef DEBUG +void printResults (const char * infos,struct check * results) { + struct check* ptr; + printf ("%s\n",infos); + for (ptr=results; ptr->option; ptr++) { + if (ptr->isNum) + printf ("option=%s mandatory=%d found=%d value=%d isNum=%d defvalue=%s\n", + ptr->option,ptr->mandatory,ptr->found,(int*)*ptr->value_ptr,ptr->isNum,ptr->defValue); + else + printf ("option=%s mandatory=%d found=%d value=%s isNum=%d defvalue=%s\n", + ptr->option,ptr->mandatory,ptr->found,(char*)*ptr->value_ptr,ptr->isNum,ptr->defValue); + } + +} + +void printConf (const char* infos,struct nss_ncp_conf * conf) { + printf ("%s\n",infos); + printf ("debug=%d useTree=%d server=%s startCtx=%s ctrlGroup=%s defGid=%d defShell=%s fallbackUid=%d fallbackGid=%d " + "doPassword=%d doGroup=%d doShadow=%d\n", + conf->debug,conf->useTree,conf->server,conf->startCtx, + conf->ctrlGroup,conf->defGid,conf->defShell,conf->fallbackUid,conf->fallbackGid, + conf->doPassword,conf->doGroup,conf->doShadow); +} +#endif + + +static int process_line (char* cptr, struct check *ptr) { + + char* sptr; // start of real value + char* eptr; // end of real value + char* errPtr; // err + + char ec; + char cc; + + while (*cptr && isspace(*cptr)) + cptr++; + if (*cptr != '=' && *cptr != ':') + return 1; //no equal sign found + cptr++; + + while (*cptr && isspace(*cptr)) + cptr++; + + // space are allowed in value only if surrounded by " or ' (eg a NDS control group) + if (*cptr == '"' || *cptr == '\'') + ec = *cptr++; + else + ec = 0; + sptr=cptr; + eptr=cptr; + while ((cc = *cptr++) != 0) { + if (cc == '\n') + break; + if (!ec && isspace(cc)) + break; + if (cc == ec) + break; + eptr++; + } + *eptr = 0; + if (ptr->isNum) { + (int *)*ptr->value_ptr=strtoul (sptr,&errPtr,0); + ptr->found= ((*sptr) && !(*errPtr)); //not empty and no error + } else { + if (eptr>sptr) { // do not take an empty string value + char *v=strdup(sptr); + if (v) { + (char*) *ptr->value_ptr=v; + ptr->found= TRUE; + }else + return 1; + } + } + + return 0; +} + +static int fix_conf (struct check *results) { + struct check* ptr; + + for (ptr=results; ptr->option; ptr++) { + if (! ptr->found) { + if (ptr->mandatory) { + traceForce(0,LOG_ERR, "ncp_nss aborting :missing mandatory information '%s=' in config file %s ",ptr->option,GLOBALCFGFILE); + return 1; + } + if (ptr->isNum) { + (int *)*ptr->value_ptr=strtoul (ptr->defValue,NULL,0); + }else { + char * v=strdup(ptr->defValue); + if (v) + (char*) *ptr->value_ptr=v; + else + return 1; + } + } + } + return 0; +} + + +static struct nss_ncp_conf *read_conf_file( const char * mySection, struct cfgFile *cfg) { + + struct nss_ncp_conf *conf; + + conf=alloc_nss_ncp_conf (); + if (!conf) + return NULL; + { + struct nss_ncp_conf * pconf=conf; + struct check check_confs[] = { + /*option mandat found value_ptr isNum defValue */ + {"debug", FALSE,FALSE,(void**)&conf->debug, TRUE, "0"}, + {"useTree", FALSE,FALSE,(void**)&conf->useTree, TRUE, "0"}, + {"server", TRUE,FALSE, (void**)&conf->server, FALSE, ""}, + {"startCtx", FALSE,FALSE,(void**)&conf->startCtx, FALSE, ""}, + {"ctrlGroup", FALSE,FALSE,(void**)&conf->ctrlGroup, FALSE, ""}, + {"defGid", FALSE,FALSE,(void**)&conf->defGid, TRUE, "100"}, + {"defShell", FALSE,FALSE,(void**)&conf->defShell, FALSE, "/bin/bash"}, + {"fallbackUid", FALSE,FALSE,(void**)&conf->fallbackUid, TRUE, "-1"}, + {"fallbackGid", FALSE,FALSE,(void**)&conf->fallbackGid, TRUE, "-1"}, + {"doPasswd", FALSE,FALSE,(void**)&conf->doPassword, TRUE, "0"}, + {"doGroup", FALSE,FALSE,(void**)&conf->doGroup, TRUE, "0"}, + {"doShadow", FALSE,FALSE,(void**)&conf->doShadow, TRUE, "0"}, + {NULL , FALSE,FALSE,NULL, FALSE, NULL} + }; + + char cfgline[16384]; + size_t seclen = strlen(mySection); + + +#ifdef DEBUG +// DO NOT DO IT A a second call (using test_ncp_nss -2) coredump !!! +// printResults("before reading CFG",check_confs); +#endif + ncpt_mutex_lock(&cfg->mutex); + //rewind(cfg->file); + while (fgets(cfgline, sizeof(cfgline)-1, cfg->file)) { + char* cptr = cfgline; + struct check* ptr; + + while (*cptr && isspace(*cptr)) + cptr++; + if (*cptr != '[') + continue; +sstart:; + if (strncasecmp(++cptr, mySection, seclen)) + continue; + if (cptr[seclen] != ']') + continue; + while (fgets(cfgline, sizeof(cfgline) - 1, cfg->file)) { + cptr = cfgline; + + while (*cptr && isspace(*cptr)) + cptr++; + if (!*cptr) + continue; //empty line + if (*cptr == '[') // start of another section + goto ssend; + for (ptr=check_confs; ptr->option; ptr++) { + size_t keylen=strlen(ptr->option); + if (!strncasecmp(cptr, ptr->option,keylen)) { + cptr += keylen; + process_line (cptr,ptr); + } + } + } + } + +ssend: +#ifdef DEBUG + printResults("after reading CFG no error",check_confs); +#endif +#ifdef DEBUG + printConf("before fixing ",conf); +#endif + + if (!fix_conf (check_confs)) { // fill in missing values with default, +#ifdef DEBUG + printConf("after fixing ",conf); +#endif + ncpt_mutex_unlock(&cfg->mutex); + return conf; + } + +error: +#ifdef DEBUG + printResults("after reading CFG error",check_confs); +#endif + ncpt_mutex_unlock(&cfg->mutex); + free_nss_ncp_conf(conf); + return NULL; + } + +} + +struct nss_ncp_conf * parse_conf (char * confFile) { + + struct cfgFile *cfg; + struct nss_ncp_conf *conf; +#ifdef DEBUG + printf("entering parse_conf\n"); +#endif + //return &defConf; + cfg = cfgOpenFile(GLOBALCFGFILE, FALSE); + if (!cfg) + return NULL; + conf=read_conf_file(NSS_SECTION,cfg); + cfgClose(cfg); +#ifdef DEBUG + if (conf) + printConf("final value ",conf); +#endif + + return conf; +} + diff --git a/contrib/ncp_nss_lib/nss_cfgfile.h b/contrib/ncp_nss_lib/nss_cfgfile.h new file mode 100644 index 0000000..cc71dc7 --- /dev/null +++ b/contrib/ncp_nss_lib/nss_cfgfile.h @@ -0,0 +1,30 @@ +#ifndef HAVE_NSS_CFGFILE +#define HAVE_NSS_CFGFILE + +#define TRUE 1 +#define FALSE 0 + +#define NSS_SECTION "ncp_nss" +struct nss_ncp_conf { + int debug; + int useTree; // use Tree connection or server connection + char * server; // name of server or tree + char * startCtx; // start searching is this context (and below) + char * ctrlGroup; // limit search to members of this NDS group for passwd and shadow + gid_t defGid; // if no primary group found in NDS use this value + char * defShell; // if no shell found in NDS use this value + uid_t fallbackUid; // if no UID found in NDS use this one (-1= skip user, NFS_NOBODY= use this UID) + gid_t fallbackGid; // if no GID found in NDS use this one (-1= skip group, NFS_NOBODY= use this GID) + int doPassword; // if 0, will return immediarly NSS_STATUS_UNAVAILABLE even if ncp is listed in /etc/nsswitch.conf + int doGroup; // if 0, will return immediarly NSS_STATUS_UNAVAILABLE even if ncp is listed in /etc/nsswitch.conf + int doShadow; // if 0, will return immediarly NSS_STATUS_UNAVAILABLE even if ncp is listed in /etc/nsswitch.conf +}; + + + +static struct nss_ncp_conf defConf ={0,TRUE,"INSA_ROOT","[Root]",NULL,100,"/bin/bash",-1,-1,TRUE,TRUE,TRUE}; + +struct nss_ncp_conf * parse_conf (char * confFile); +void free_nss_ncp_conf (struct nss_ncp_conf *conf); + +#endif diff --git a/contrib/ncp_nss_lib/nss_ncp.c b/contrib/ncp_nss_lib/nss_ncp.c new file mode 100644 index 0000000..550d53d --- /dev/null +++ b/contrib/ncp_nss_lib/nss_ncp.c @@ -0,0 +1,3091 @@ +/************************************************************************** + nss_ncp.c NSS module for NDS + + Copyright (C) 2002 Patrick Pollet + + 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 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 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + + Revision history: + + 1.00 2003, January 06 Patrick Pollet + initial release + 1.01 2003, January 08 Patrick Pollet + added conf structure and control group + added optional fallback UID and GID if none found in NDS (default is to skip user,group) + 1.02 2003, January 09 Patrick Pollet + added initgroups + 1.03 2003, January 10 Patrick Pollet + fixed bug in nds_user_info2 (bad structure received by nds_user_location2) + 1.04 2003, January 11 Patrick Pollet + fixed setting ndsXXX=NULL trees in case of errors in _nss_ncp_setxxent() + made always NAME_CONTEXT=[Root] in CreateContextAndConn + calling NWCCloseIteration only it some errors has occured in the search + 1.05 2003, January 15 Patrick Pollet + -Avoid multiple reading of conf file by removing recursive calls + in nss_ncp_getxxent_r in case a entry has no Unix infos in NDS + (replaced by a goto nextuser) + -Added missing free_nw_xxx_info when leaving nss_ncp_getxxent_r (fixed memory leaks) + -Added testing for failure in allocating tree structure in nss_ncp_setxxent_r + -if (id !=(uid_t)-1) and not if (id) in getentxx if we search by UID !!!! + -getentbyxx give a warning in syslog if more that one entry match the name or id search criteria + 1.06 2003, January 16 Patrick Pollet + -implemented reading of configuration file in /etc/nss_ncp.conf + -in case of fatal errors, force log in syslog by using calls to traceForce ( previously fatal + errors were only reported in debug mode, since the syslog file is not opened in normal mode) + 1.07 2003, January 16 Patrick Pollet + Speed up the search: + 1)config informations are stored in the internal trees structures + when calling nss_ncp_setxxent_r and freed by nss_ncp_endxxent_r + so we don't read again config file at every call to nss_ncp_getxxent_r + 2) group infos are really slow with big groups,so we added a flag doGroup in conf file + to skip the search (easier that to edit /etc/nsswitch.conf AND restarting nscd daemon). +************************************************************************/ + + +#include +#include +#include +#include +#include + + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "nss_ncp.h" +#include "nss_cfgfile.h" + +// only if logfile has been opened by nss API functions (debug mode) +void trace (int debugMode,int err,const char * format,... ) { + va_list args; + if (debugMode) { + va_start(args,format); + vsyslog (err,format,args); + va_end(args); + } +} + +// send a message to syslog even if log file not opened (debugMode is false) +// needed for critical errors such a bad config file or ambiguous NDS search +void traceForce (int debugMode,int err, const char * format,... ) { + va_list args; + + if (!debugMode) + openlog("ncp_nss", LOG_PID, LOG_AUTHPRIV); + va_start(args,format); + vsyslog (err,format,args); + va_end(args); + if (!debugMode) + closelog(); + +} + + +static int +getnumber(int *val, const char **str) +{ + const char *p = *str; + char *z; + + if (!*p) + return 1; + if (*p == ',') { + *str = p + 1; + return 1; + } + *val = strtoul(p, &z, 0); + if (p == z) + return -1; + if (*z == ',') + z++; + *str = z; + return 0; +} + +static char* copy_to_buffer (char ** buffer, size_t *buflen, char * value) { +// copy the value to buffer , decrease buflen and return start of the value in buffer + size_t len=strlen(value)+1; + char * ptr=*buffer; + + if (len > *buflen) { + return NULL; + } + memcpy(*buffer, value, len); + *buflen -=len; + (*buffer) +=len; + return ptr; +} + +/********** +struct nss_ncp_conf { + int debug; + int useTree; // use Tree connection or server connection + char * server; // name of server or tree + char * startCtx; // start searching is this context (and below) + char * ctrlGroup; // limit search to members of this NDS group for passwd and shadow + gid_t defGid; // if no primary group found in NDS use this value + char * defShell; // if no shell found in NDS use this value + uid_t fallbackUid; // if no UID found in NDS use this one (-1= skip user, NFS_NOBODY= use this UID) + gid_t fallbackGid; // if no GID found in NDS use this one (-1= skip group, NFS_NOBODY= use this GID) + int doPassword; // if 0, will return immediarly NSS_STATUS_UNAVAILABLE even if ncp is listed in /etc/nsswitch.conf + int doGroup; // if 0, will return immediarly NSS_STATUS_UNAVAILABLE even if ncp is listed in /etc/nsswitch.conf + int doShadow; // if 0, will return immediarly NSS_STATUS_UNAVAILABLE even if ncp is listed in /etc/nsswitch.conf +}; +**************/ + +//one day we will read it from /etc/ncp_nss.conf + + +/****************************************** internal structure for storing NDS user's password infos ***/ +struct nw_user_info { + char * cn; + char * gecos; + char * shell; + char * dir; + char * fullName; + char * passwd; + uid_t uid; + gid_t gid; + int qflag; + + }; + +static void init_nw_user_info (struct nw_user_info *ui,int qflag){ + ui->cn=NULL; + ui->gecos=NULL; + ui->shell=NULL; + ui->dir=NULL; + ui->fullName=NULL; + ui->passwd=NULL; + ui->uid=(uid_t)-1; + ui->gid=(gid_t)-1; + ui->qflag= qflag; +} + +static void free_nw_user_info (struct nw_user_info *ui){ +#define FREEFIELD(x) do if (ui->x) {free(ui->x) ; ui->x=NULL;} while (0); + FREEFIELD(cn); + FREEFIELD(gecos); + FREEFIELD(shell); + FREEFIELD(dir); + FREEFIELD(fullName); + FREEFIELD(passwd); + ui->uid=(uid_t)-1; + ui->gid=(gid_t)-1; + ui->qflag=0; +#undef FREEFIELD +} + + +static int fix_nw_user_info (struct nw_user_info *ui, struct nss_ncp_conf* conf){ +/* fill NDS missing attributes (home, shell, gid, gecos) with default values + any user have a cn, and if uid was not found in NDS we consider + that the corresponding Unix account is not activated +*/ + if (ui->cn) { + if (ui->uid== (uid_t)-1) + ui->uid=conf->fallbackUid; + if (ui->gid== (gid_t)-1) + ui->gid=conf->defGid; + if (!ui->gecos) { + ui->gecos= ui->fullName ? strdup(ui->fullName):strdup(""); + } + ui->shell= ui->shell ? ui->shell: strdup(conf->defShell); + ui->dir= ui->dir ? ui->dir: strdup(""); + ui->passwd= ui->passwd ? ui->passwd: strdup("x"); // cannot read passwd from ND + if (!ui->shell || !ui->dir || !ui->gecos || !ui->passwd) { + traceForce(conf->debug,LOG_ERR, "not enough memory when fixing nw_user_info\n ",ui->cn); + return 1; + } + }else { + ui->uid== (uid_t)-1; // unable to read CN (NDS browse rights not set) , skip it ! + } + return 0; +} + + +// return found info to caller in the format expected by NSS that is: +// filling the passwd structure as pointers to the passed buffer + + +static enum nss_status nw_user_info_to_passwd(struct nw_user_info ui,struct passwd *pwd, + char * buffer, size_t buflen, int * errnop, struct nss_ncp_conf *conf){ + + if (ui.uid != (uid_t)-1) { + pwd->pw_uid=ui.uid; + pwd->pw_gid=ui.gid; + + pwd->pw_name=copy_to_buffer (&buffer,&buflen,ui.cn); + if (!pwd->pw_name) goto outnomem; + pwd->pw_passwd=copy_to_buffer (&buffer,&buflen,ui.passwd); + if (!pwd->pw_passwd) goto outnomem; + pwd->pw_gecos=copy_to_buffer (&buffer,&buflen,ui.gecos); + if (!pwd->pw_gecos) goto outnomem; + pwd->pw_dir=copy_to_buffer (&buffer,&buflen,ui.dir); + if (!pwd->pw_dir) goto outnomem; + pwd->pw_shell=copy_to_buffer (&buffer,&buflen,ui.shell); + if (!pwd->pw_shell) goto outnomem; + + *errnop=0; + return NSS_STATUS_SUCCESS; +outnomem: + traceForce(conf->debug,LOG_ERR, "not enough memory when copying nw_user_info to passwd for %s\n ",ui.cn); + *errnop=ERANGE; + return NSS_STATUS_TRYAGAIN; + } else { + trace(conf->debug,LOG_NOTICE, "user %s has no Unix UID in NDS\n ", ui.cn); + *errnop=ENOENT; + return NSS_STATUS_NOTFOUND; + } +} + +static void print_nw_user_info (struct nw_user_info ui){ + printf("%s:x:%d:%d:%s:%s:%s\n",ui.cn,ui.uid,ui.gid,ui.gecos,ui.dir,ui.shell); +} + +static void print_passwd (struct passwd pwd){ + printf("%s:%s:%d:%d:%s:%s:%s\n",pwd.pw_name,pwd.pw_passwd,pwd.pw_uid,pwd.pw_gid,pwd.pw_gecos,pwd.pw_dir,pwd.pw_shell); +} + + +/****************************************** internal structure for storing NDS group's infos ***/ +struct nw_group_member { + struct nw_group_member* next; + char * member; +}; + +struct nw_group_info { + char * cn; + char * alias; + char * passwd; + gid_t gid; + struct nw_group_member * first; + struct nw_group_member * last; + int nbMembers; + int qflag; + }; + + +static void init_nw_group_info (struct nw_group_info *gi,int qflag){ + gi->cn=NULL; + gi->alias=NULL; + gi->passwd=NULL; + gi->gid=(gid_t)-1; + gi->qflag= qflag; + gi->first=NULL; + gi->last=NULL; + gi->nbMembers=0; +} + +static void free_nw_group_info (struct nw_group_info *gi){ + + struct nw_group_member* p; + struct nw_group_member* bkp; +#define FREEFIELD(x) do if (gi->x) {free(gi->x) ; gi->x=NULL;} while (0); + FREEFIELD(cn); + FREEFIELD(alias); + FREEFIELD(passwd); + gi->gid=(gid_t)-1; + gi->qflag=0; +#undef FREEFIELD + for (p=gi->first; p; p=bkp) { + bkp=p->next; + free (p->member); + free(p); + } + gi->first=gi->last=NULL; + gi->nbMembers=0; +} + + + +static int fix_nw_group_info (struct nw_group_info *gi ,struct nss_ncp_conf* conf){ +/* fill NDS missing attributes with default values + any group have a cn, and if gid was not found in NDS we will later consider + that the corresponding Unix group is not activated unless a fallback value is defined in conf +*/ + if (gi->cn) { + if (gi->gid== (gid_t)-1) + gi->gid=conf->fallbackGid; + + gi->passwd= gi->passwd ? gi->passwd: strdup("x"); // cannot read passwd from NDS + if (!gi->passwd) { + traceForce(conf->debug,LOG_ERR, "not enough memory when allocating password for group %s\n ",gi->cn); + return 1; + } + if (gi->alias) { + if (gi->cn) free(gi->cn); + gi->cn=strdup(gi->alias); + if (!gi->cn) { + traceForce(conf->debug,LOG_ERR, "not enough memory when allocating alias for group %s\n ",gi->alias); + return 1; + } + } + }else { + gi->gid== (gid_t)-1; // unable to read CN (NDS browse rights not set) , skip it ! + } + return 0; +} + + + +/*********** +return found info to caller in the format expected by NSS that is: +filling the group structure as pointers to the passed buffer + +struct group + { + char *gr_name; // Group name. + char *gr_passwd; // Password. + __gid_t gr_gid; // Group ID. + char **gr_mem; // Member list. + }; +******************/ + +static enum nss_status nw_group_info_to_group(struct nw_group_info gi,struct group *grp, + char * buffer, size_t buflen, int * errnop, struct nss_ncp_conf *conf){ + + if (gi.gid != (gid_t)-1) { + grp->gr_gid=gi.gid; + grp->gr_name=copy_to_buffer (&buffer,&buflen,gi.cn); + if (!grp->gr_name) goto outnomem; + grp->gr_passwd=copy_to_buffer (&buffer,&buflen,gi.passwd); + if (!grp->gr_passwd) goto outnomem; + + {// copy members to buffer + // names are stored backwards from end of buffer + // and adress pointers forward from start of buffer + // exit with NSS_STATUS_TRYAGAIN if buffer is too small + // code inspired from nss_mysql by Guillaume Morin + + size_t required=0; + char ** addPtr; + char * end_of_buffer,*tmp,*nm; + struct nw_group_member *p; + + for (p=gi.first;p;p=p->next) { + required += strlen(p->member)+1+sizeof(char**); + } + if (required + sizeof(char**) >=buflen) { + traceForce(conf->debug,LOG_ERR, "unable to copy members of group '%s' to buffer :need=%d have= %d\n",gi.cn,required,buflen); + goto outnomem; + } + addPtr= (char**)buffer; + grp->gr_mem=addPtr; + end_of_buffer= buffer+buflen-1; + p=gi.first; + while (p) { + end_of_buffer -=strlen(p->member)+1; + tmp=end_of_buffer; //do not change end_of_buffer when copying the new member ! + nm=copy_to_buffer(&tmp,&buflen,p->member); + if (!nm) { + traceForce(conf->debug,LOG_ERR, "not enough memory when copying nw_group_info to group for %s\n ",gi.cn); + goto outnomem; + } + *addPtr=nm; + //printf("%s=%s\n",p->member,*addPtr); + addPtr++; + p=p->next; + } + *addPtr=NULL; // end of table of pointers + } + *errnop=0; + return NSS_STATUS_SUCCESS; +outnomem: + + *errnop=ERANGE; + return NSS_STATUS_TRYAGAIN; + } else { + trace(conf->debug,LOG_NOTICE, "group %s has no Unix GID in NDS\n ", gi.cn); + *errnop=ENOENT; + return NSS_STATUS_NOTFOUND; + } +} + + +static void print_nw_group_info (struct nw_group_info gi){ + struct nw_group_member* p; + + printf("%s:x:%d:%d members:",gi.cn,gi.gid,gi.nbMembers); + for (p=gi.first;p;p=p->next) { + printf("%s",p->member); + if (p->next) printf(","); + } + printf("\n"); +} + +static void print_group (struct group grp){ + char ** mmb; int num; + printf("%s:%s:%d:",grp.gr_name,grp.gr_passwd,grp.gr_gid); + for (mmb=grp.gr_mem,num=0;*mmb; mmb++,num++) { + if (num) + printf(","); + printf ("%s",*mmb); + + } + printf("\n"); + +} + + +/****************************************** internal structure for storing NDS user's shadow infos ***/ +struct nw_shadow_info { + char * cn; + char * passwd; + long int lstchg; + long int sp_min; + long int sp_max; + long int sp_warn; + long int sp_inact; + long int sp_expire; + unsigned long sp_flag; + uid_t uid; + int qflag; + }; + +static void init_nw_shadow_info (struct nw_shadow_info *si,int qflag){ + si->cn=NULL; + si->passwd=NULL; + si->lstchg=0; + si->sp_min=0; + si->sp_max=0; + si->sp_warn=0; + si->sp_inact=0; + si->sp_expire=0; + si->sp_flag=-1; + si->uid=(uid_t)-1; + si->qflag= qflag; +} + +static void free_nw_shadow_info (struct nw_shadow_info *si){ +#define FREEFIELD(x) do if (si->x) {free(si->x) ; si->x=NULL;} while (0); + FREEFIELD(cn); + FREEFIELD(passwd); + si->lstchg=0; + si->sp_min=0; + si->sp_max=0; + si->sp_warn=0; + si->sp_inact=0; + si->sp_expire=0; + si->sp_flag=-1; + si->uid=(uid_t)-1; + si->qflag=0; +#undef FREEFIELD +} + + +static int fix_nw_shadow_info (struct nw_shadow_info *si ,struct nss_ncp_conf *conf){ +/* fill NDS missing attributes with default values + any user have a cn, and if uid was not found in NDS we will later consider + that the corresponding Unix account is not activated unless a fallback value is defined in conf +*/ + if (si->cn) { + if (si->uid== (uid_t)-1) + si->uid=conf->fallbackUid; + si->lstchg= si->lstchg ? si->lstchg : time(NULL)/24/3600; + si->sp_min= si->sp_min ? si->sp_min: 0; + si->sp_max= si->sp_max ? si->sp_max: 99999; + si->sp_warn=si->sp_warn ? si->sp_warn: 7; + si->passwd= si->passwd ? si->passwd: strdup("!!"); // cannot read passwd from NDS + if (!si->passwd) { + traceForce(conf->debug,LOG_ERR, "not enough memory when allocating password for shadow user %s\n ",si->cn); + return 1; + + } + }else { + si->uid== (uid_t)-1; // unable to read CN (NDS browse rights not set) , skip it ! + } + return 0; +} + +/*** + return found info to caller in the format expected by NSS that is: + filling the shadow structure as pointers to the passed buffer + char *sp_namp; // Login nae. + char *sp_pwdp; // Encrypted password. + long int sp_lstchg; // Date of last change. + long int sp_min; // Minimum number of days between changes. + long int sp_max; // Maximum number of days between changes. + long int sp_warn; // Number of days to warn user to change the password. + long int sp_inact; // Number of days the account may be inactive. + long int sp_expire; // Number of days since 1970-01-01 until account expires. + unsigned long int sp_flag; // Reserved. +*****/ + +static enum nss_status nw_shadow_info_to_shadow(struct nw_shadow_info si,struct spwd *spw, + char * buffer, size_t buflen, int * errnop, struct nss_ncp_conf *conf){ + + if (si.uid != (uid_t)-1) { + spw->sp_namp=copy_to_buffer (&buffer,&buflen,si.cn); + if (!spw->sp_namp) goto outnomem; + spw->sp_pwdp=copy_to_buffer (&buffer,&buflen,si.passwd); + if (!spw->sp_pwdp) goto outnomem; + + spw->sp_lstchg=si.lstchg; + spw->sp_min=si.sp_min; + spw->sp_max=si.sp_max; + spw->sp_warn=si.sp_warn; + spw->sp_inact=si.sp_inact; + spw->sp_expire=si.sp_expire; + spw->sp_flag=si.sp_flag; + *errnop=0; + return NSS_STATUS_SUCCESS; +outnomem: + traceForce(conf->debug,LOG_ERR, "not enough memory when copying nw_shadow_info to shadow for %s\n ",si.cn); + *errnop=ERANGE; + return NSS_STATUS_TRYAGAIN; + } else { + trace(conf->debug,LOG_NOTICE, "user %s has no Unix UID in NDS\n ", si.cn); + *errnop=ENOENT; + return NSS_STATUS_NOTFOUND; + } +} + +static void print_nw_shadow_info (struct nw_shadow_info si){ + + printf("%s[%d]:%s:%d:%d:%d:%d:%d:%d:%d\n",si.cn,si.uid,si.passwd,si.lstchg,si.sp_min,si.sp_max,si.sp_warn,si.sp_inact,si.sp_expire,si.sp_flag); +} + +static void print_shadow (struct spwd spw){ + printf("%s:%s:%ld:%ld:%ld:%ld:%ld:%ld:%ld\n",spw.sp_namp,spw.sp_pwdp,spw.sp_lstchg,spw.sp_min,spw.sp_max,spw.sp_warn,spw.sp_inact,spw.sp_expire,spw.sp_flag); +} + + + +/****************************************** internal structure for storing NDS user's groups infos ***/ +struct nw_user_group_info { + char * cn; + uid_t uid; + gid_t* groups; + size_t used; + size_t alloc; + int qflag; + }; + + +static void init_nw_user_group_info (struct nw_user_group_info *ui,int qflag){ + ui->cn=NULL; + ui->uid=(uid_t)-1; + ui->groups=NULL; + ui->used=0; + ui->alloc=0; + ui->qflag= qflag; +} + +static void free_nw_user_group_info (struct nw_user_group_info *ui){ +#define FREEFIELD(x) do if (ui->x) {free(ui->x) ; ui->x=NULL;} while (0); + FREEFIELD(cn); + FREEFIELD(groups); + ui->used=0; + ui->alloc=0; + ui->uid=(uid_t)-1; + ui->qflag=0; +#undef FREEFIELD +} + + +static int fix_nw_user_group_info (struct nw_user_group_info *ui ,struct nss_ncp_conf * conf){ +/* fill NDS missing attributes with default values + any user have a cn, and if uid was not found in NDS we consider + that the corresponding Unix account is not activated unless a fallback value is defined in conf +*/ + if (ui->cn) { + if (ui->uid== (uid_t)-1) + ui->uid=conf->fallbackUid; + }else { + ui->uid== (uid_t)-1; // unable to read CN (NDS browse rights not set) , skip it ! + } + return 0; +} + + +// return found info to caller in the format expected by NSS that is: +// filling up groups array +// code similar to nss_ldap + +static enum nss_status nw_user_group_info_to_groups (struct nw_user_group_info ui,gid_t group, long int *start, + long int *size, gid_t * groups,long int limit,int *errnop,struct nss_ncp_conf * conf) { + + if (ui.uid != (uid_t)-1) { + int i; + for (i=0; idebug,LOG_ERR, "initgroups: not enough memory when reallocating group array for %s \n ",ui.cn); + *errnop=ERANGE; + return NSS_STATUS_TRYAGAIN; + } else { + trace(conf->debug,LOG_NOTICE, "user %s has no Unix UID in NDS\n ", ui.cn); + *errnop=ENOENT; + return NSS_STATUS_NOTFOUND; + } +} + +static void print_nw_user_group_info (struct nw_user_group_info ui){ + int i; + + printf("%s:%d:%d:%d:",ui.cn,ui.uid,ui.used,ui.alloc); + for (i=0;i attrname; ptr++) { + dserr = NWDSPutAttrName(ctx, attrlist, ptr->attrname); + if (dserr) { + traceForce(debugMode,LOG_WARNING, "NWDSPutAttrName(%s) failed with %s\n", ptr->attrname, strnwerror(dserr)); + goto bailoutbuf1; + } + } + dserr = NWDSAllocBuf(DEFAULT_MESSAGE_LEN, &info); + if (dserr) { + traceForce(debugMode,LOG_WARNING, "NWDSAllocBuf() failed with %s\n", strnwerror(dserr)); + goto bailoutbuf1; + } + iterHandle = NO_MORE_ITERATIONS; + do { + NWObjectCount attrs; + + dserr = NWDSRead(ctx, objname, DS_ATTRIBUTE_VALUES, 0, attrlist, &iterHandle, info); + if (dserr) { + if (dserr == ERR_NO_SUCH_ATTRIBUTE) + dserr = 0;// attribute is missing . OK + else + traceForce(debugMode,LOG_WARNING, "NWDSRead() failed for %s with %s\n", objname,strnwerror(dserr)); + goto bailoutbuf2; + } + dserr = NWDSGetAttrCount(ctx, info, &attrs); + if (dserr) { + traceForce(debugMode,LOG_WARNING, "NWDSGetAttrCount() failed with %s\n", strnwerror(dserr)); + goto bailoutcloit; + } + while (attrs--) { + NWDSChar attrname[MAX_SCHEMA_NAME_BYTES]; + enum SYNTAX synt; + NWObjectCount vals; + + dserr = NWDSGetAttrName(ctx, info, attrname, &vals, &synt); + if (dserr) { + traceForce(debugMode,LOG_WARNING, "NWDSGetAttrName() failed with %s\n", strnwerror(dserr)); + goto bailoutcloit; + } + while (vals--) { + size_t sz; + void *val; + + dserr = NWDSComputeAttrValSize(ctx, info, synt, &sz); + if (dserr) { + traceForce(debugMode,LOG_WARNING, "NWDSComputeAttrValSize() failed with %s\n", strnwerror(dserr)); + goto bailoutcloit; + } + val = malloc(sz); + if (!val) { + traceForce(debugMode,LOG_WARNING, "malloc() failed with %s\n", strnwerror(ENOMEM)); + goto bailoutcloit; + } + dserr = NWDSGetAttrVal(ctx, info, synt, val); + if (dserr) { + free(val); + traceForce(debugMode,LOG_WARNING, "NWDSGetAttrVal() failed with %s\n", strnwerror(dserr)); + goto bailoutcloit; + } + for (ptr = atlist; ptr->attrname; ptr++) { + if (!strcasecmp(ptr->attrname, attrname)) + break; + } + if (ptr->getval) { + if (ptr->synt != synt) { + traceForce(debugMode,LOG_WARNING, "Incompatible tree schema, %s has syntax %d instead of %d\n", attrname, synt, ptr->synt); + } else { + // ajout PP dserr= !!! en cas de pb mémoire + dserr = ptr->getval(ctx, val, arg); + } + } + free(val); + if (dserr) { + goto bailoutcloit; + } + } + } + } while (iterHandle != NO_MORE_ITERATIONS); +bailoutcloit:; + if (iterHandle != NO_MORE_ITERATIONS) { + NWDSCCODE dserr2 = NWDSCloseIteration(ctx, DSV_READ, iterHandle); + if (dserr2) { + traceForce(debugMode,LOG_WARNING, "NWDSCloseIteration() failed with %s\n", strnwerror(dserr2)); + } + } +bailoutbuf2:; + NWDSFreeBuf(info); +bailoutbuf1:; + NWDSFreeBuf(attrlist); +bailout:; + return dserr; +} + + +/*****************************************************GET USER INFO FROM NDS *************/ +/************************************ helper functions to extract NDS properties ********/ +// called as callbacks by nds_read_attrs + +static NWDSCCODE nds_user_cn(NWDSContextHandle ctx, const void *val, void *arg){ + struct nw_user_info *ui = (struct nw_user_info *) arg; + + if (!ui->cn) { + char *v = strdup((const char *) val); + if (!v) { + traceForce(ui->qflag,LOG_WARNING, "Not enough memory for strdup()\n"); + return ENOMEM; + } + ui->cn = v; + trace(ui->qflag,LOG_NOTICE, "got a Unix cn %s from %s\n ", ui->cn, ATTR_CN); + } + return 0; +} + +static NWDSCCODE nds_user_unixuid(NWDSContextHandle ctx, const void *val, void *arg){ + struct nw_user_info *ui = (struct nw_user_info *) arg; + if (ui->uid == (uid_t) -1) { + ui->uid = *(const Integer_T *) val; + // talk a bit (real NDS8 attribute or dummy ?) + trace(ui->qflag,LOG_NOTICE, "got a Unix ID %d from %s\n ", ui->uid, ATTR_UID); + } + return 0; +} + +static NWDSCCODE nds_user_unixpgid(NWDSContextHandle ctx, const void *val, void *arg){ + struct nw_user_info *ui = (struct nw_user_info *) arg; + + if (ui->gid == (gid_t) -1) { + ui->gid = *(const Integer_T *) val; + // talk a bit (real NDS8 attribute or dummy ?) + trace(ui->qflag,LOG_NOTICE, "got a Unix PGID %d from %s\n ", ui->gid, ATTR_PGID); + } + return 0; +} + +// this is the same founction as above ??? +// does Netware has two synonyms for the same property (UNIX:GID" +// and UNIX:Primary GroupID??? +static NWDSCCODE nds_user_unixgid(NWDSContextHandle ctx, const void *val, void *arg){ + struct nw_user_info *ui = (struct nw_user_info *) arg; + + if (ui->gid == (gid_t) -1) { + ui->gid = *(const Integer_T *) val; + // talk a bit (real NDS8 attribute or dummy ?) + trace(ui->qflag,LOG_NOTICE, "got a Unix GID %d from %s\n ", ui->gid, ATTR_GID); + } + return 0; +} + +static NWDSCCODE nds_user_unixhome(NWDSContextHandle ctx, const void *val, void *arg){ + struct nw_user_info *ui = (struct nw_user_info *) arg; + + if (!ui->dir) { + char *v = strdup((const char *) val); + if (!v) { + traceForce(ui->qflag,LOG_WARNING, "Not enough memory for strdup()\n"); + return ENOMEM; + } + ui->dir = v; + // talk a bit (real NDS8 attribute or dummy ?) + trace(ui->qflag,LOG_NOTICE, "got a Unix Home %s from %s\n ", ui->dir, ATTR_HOME); + } + return 0; +} + +static NWDSCCODE nds_user_unixshell(NWDSContextHandle ctx, const void *val, void *arg){ + struct nw_user_info *ui = (struct nw_user_info *) arg; + + if (!ui->shell) { + char *v = strdup((const char *) val); + if (!v) { + traceForce(ui->qflag,LOG_WARNING, "Not enough memory for strdup()\n"); + return ENOMEM; + } + ui->shell = v; + // talk a bit (real NDS8 attribute or dummy ?) + trace(ui->qflag,LOG_NOTICE, "got a Unix shell %s from %s\n ", ui->shell, ATTR_SHELL); + } + return 0; +} + +static NWDSCCODE nds_update_gecos(struct nw_user_info *ui, const char *str) { + char *v; + size_t sadd = strlen(str) + 1; + + if (ui->gecos) { // already got the name + size_t sold = strlen(ui->gecos); + trace(ui->qflag,LOG_NOTICE, "extending gecos %d %d\n",sadd,sold); + + v = realloc(ui->gecos, sold + 1 + sadd); + if (!v) { + traceForce(ui->qflag,LOG_WARNING, "Not enough memory for strdup()\n"); + return ENOMEM; + } + v[sold] = ','; + memcpy(v + sold+1, str, sadd); // bizarre sold a disparu dans pam_ncp ???? + } else { + trace(ui->qflag,LOG_NOTICE, "creating gecos %d \n",sadd); + v = malloc(sadd); + if (!v) { + traceForce(ui->qflag,LOG_WARNING, "Not enough memory for strdup()\n"); + return ENOMEM; + } + memcpy(v, str, sadd); + } + ui->gecos = v; + return 0; +} + +// PP we append the Comment after the full name, separated by a comma +static NWDSCCODE nds_user_unixcomment(NWDSContextHandle ctx, const void *val, void *arg){ + struct nw_user_info *ui = (struct nw_user_info *) arg; + + // talk a bit (real NDS8 attribute or dummy ?) + trace(ui->qflag,LOG_NOTICE, "got a Unix Comment %s from %s\n ", (const char *) val, ATTR_COM); + return nds_update_gecos(ui, (const char *) val); +} + +// PP can be any naming attribute returning a SYN_CI_STRING see define before nds_user_info() +// PP we add the name before any comment that can be there +static NWDSCCODE nds_user_gecos(NWDSContextHandle ctx, const void *val, void *arg) { + struct nw_user_info *ui = (struct nw_user_info *) arg; + NWDSCCODE err; + + trace(ui->qflag,LOG_NOTICE, "before full name gecos is %s\n ", ui->gecos ? : "(null)"); + err = nds_update_gecos(ui, (const char *) val); + if (err) + return err; + trace(ui->qflag,LOG_NOTICE, "after full name gecos is %s\n ", ui->gecos); + return 0; +} + +// PP: id no NDS8 is present, collect the user's basic Unix informations from the location +// strings with the format X:nnnnnnnn , X = [U,G,H,S,P,O,C,Z] upper of lower case +// Of course, even if NDS8 IS present, we still look at these, just in case the migration +// is not complete and to look for the user's ZENFLAG + +static NWDSCCODE nds_user_location(NWDSContextHandle ctx, const void *val, void *arg){ + struct nw_user_info *ui = (struct nw_user_info *) arg; + const char *pt = (const char *) val; + char *v; + int n; + int err; + + trace(ui->qflag,LOG_NOTICE, "start of NW location got %s\n ", pt); + if (strlen(pt) > 2 && pt[1] == ':') { + const char *cur_pt = pt + 2; + switch (*pt) { + case 'u': //user ID leading spaces not significant + case 'U': + if (ui->uid == (uid_t) -1) { // do not overwrite a DS 8 answer + switch (getnumber(&n, &cur_pt)) { + case 0: + ui->uid = n; + break; + default: + traceForce(ui->qflag,LOG_ERR, "Invalid user ID %s\n", pt); + } + } + break; + case 'g': // primary group number GID leading spaces not significant + case 'G': + if (ui->gid == (gid_t) -1) { // do not overwrite a DS 8 answer + switch (getnumber(&n, &cur_pt)) { + case 0: + ui->gid = n; + break; + default: + traceForce(ui->qflag,LOG_ERR, "Invalid primary user GID %s\n", pt); + } + } + break; + case 'h': // home Unix all spaces significant (must have none ?) + case 'H': + if (!ui->dir) { // do not overwrite a DS 8 answer + v = strdup(cur_pt); + if (!v) { + traceForce(ui->qflag,LOG_WARNING, "Not enough memory for strdup()\n"); + return ENOMEM; + } + ui->dir = v; + } + break; + case 's': //shell Unix all spaces significant (must have none ?) + case 'S': + if (!ui->shell) { // do not overwrite a DS 8 answer + v = strdup(cur_pt); + if (!v) { + traceForce(ui->qflag,LOG_WARNING, "Not enough memory for strdup()\n"); + return ENOMEM; + } + ui->shell = v; + } + break; + case 'c': // comment all spaces significant. Will be appended to the gecos naming + case 'C': // attribute with a comma and set by calling chfn -f xxxx -o xxxx + // if comma are present in the string chfn will fails + trace(ui->qflag,LOG_NOTICE, "before comment gecos is %s\n ", ui->gecos); + err = nds_update_gecos(ui, cur_pt); + if (err) + return err; + trace(ui->qflag,LOG_NOTICE, "gecos %s\n ", ui->gecos); + break; + } + } + return 0; +} + +static NWDSCCODE nds_user_location2(NWDSContextHandle ctx, const void *val, void *arg){ + struct nw_user_info *ui = (struct nw_user_info *) arg; + const char *pt = (const char *) val; + char *v; + int n; + int err; + + trace(ui->qflag,LOG_NOTICE, "start of NW location got %s\n ", pt); + + if (strlen(pt) > 2 && pt[1] == ':') { + const char *cur_pt = pt + 2; + switch (*pt) { + case 'u': //user ID leading spaces not significant + case 'U': + if (ui->uid == (uid_t) -1) { // do not overwrite a DS 8 answer + switch (getnumber(&n, &cur_pt)) { + case 0: + ui->uid = n; + break; + default: + traceForce(ui->qflag,LOG_ERR, "Invalid user ID %s\n", pt); + } + } + } + + } + return 0; +} + + +static NWDSCCODE nds_user_info(NWDSContextHandle ctx, const NWDSChar * objname, void *ui, int modeDebug){ + static const struct attrop atlist[] = { + {ATTR_CN, nds_user_cn, SYN_CN}, + {ATTR_UID, nds_user_unixuid, SYN_UID}, + {ATTR_PGID, nds_user_unixpgid, SYN_PGID}, + {ATTR_GID, nds_user_unixgid, SYN_GID}, + {ATTR_HOME, nds_user_unixhome, SYN_HOME}, + {ATTR_SHELL, nds_user_unixshell, SYN_SHELL}, + {ATTR_COM, nds_user_unixcomment, SYN_COM}, + {ATTR_GECOS, nds_user_gecos, SYN_CI_STRING}, + {NULL, NULL, SYN_UNKNOWN} + }; + + static const struct attrop atlist2[] = { + {ATTR_LOCATION, nds_user_location, SYN_LOCATION}, + {NULL, NULL, SYN_UNKNOWN} + }; + + NWDSCCODE err; + +// we must do TWO NDS queries since NDS does not return attributes in this order +// studies of /var/log/secure showed that L attribute usually come out before the NDS8 ones ! + err = nds_read_attrs(ctx, objname, ui, atlist,modeDebug); + if (err) + return err; + return nds_read_attrs(ctx, objname, ui, atlist2,modeDebug); +} + + +/***************** GET limited user's information (used when searching for group members) */ +/* we search only UID either stored in NDS8 attributes ( Real or Dummy) or in Location */ +static NWDSCCODE nds_user_info2(NWDSContextHandle ctx, const NWDSChar * objname, void *ui,int modeDebug){ + static const struct attrop atlist[] = { + {ATTR_CN, nds_user_cn, SYN_CN}, + {ATTR_UID, nds_user_unixuid, SYN_UID}, + {NULL, NULL, SYN_UNKNOWN} + }; + + static const struct attrop atlist2[] = { + {ATTR_LOCATION, nds_user_location2, SYN_LOCATION}, + {NULL, NULL, SYN_UNKNOWN} + }; + + NWDSCCODE err; + +// we must do TWO NDS queries since NDS does not return attributes in this order +// studies of /var/log/secure showed that L attribute usually come out before the NDS8 ones ! + err = nds_read_attrs(ctx, objname, ui, atlist,modeDebug); + if (err) + return err; + return nds_read_attrs(ctx, objname, ui, atlist2,modeDebug); +} + + +/*****************************************************GET GROUP INFO FROM NDS *************/ + + +/** gather Unix groups informations */ + +static NWDSCCODE nds_group_cn(NWDSContextHandle ctx, const void *val, void *arg) +{ + struct nw_group_info *gi = (struct nw_group_info *) arg; + + if (!gi->cn) { + char *v = strdup((const char *) val); + if (!v) { + traceForce(gi->qflag,LOG_WARNING, "Not enough memory for strdup()\n"); + return ENOMEM; + } + gi->cn = v; + trace(gi->qflag,LOG_NOTICE, "got a Unix cn %s from %s\n ", gi->cn, ATTR_CN); + } + return 0; +} + + +static NWDSCCODE nds_group_members(NWDSContextHandle ctx, const void *val, void *arg){ + + struct nw_group_info *gi = (struct nw_group_info *) arg; + NWDSCCODE err=0; + struct nw_user_info ui; + struct nw_group_member* newMember; + + + init_nw_user_info(&ui,gi->qflag); + //check whether member has some Unix properties + err=nds_user_info2(ctx, (const char *)val, &ui,gi->qflag); + if (!err && ui.uid !=(uid_t)-1 && ui.cn) { + char *v = strdup(ui.cn); + if (!v ) { + traceForce(gi->qflag,LOG_WARNING, "Not enough memory for adding member %s tp group %s\n",ui.cn,gi->cn); + err=ENOMEM; + } else { + newMember=malloc(sizeof(*newMember)); + if (newMember) { + newMember->member=v; + newMember->next=NULL; + if (!gi->first) gi->first=newMember; + else gi->last->next=newMember; + gi->last=newMember; + gi->nbMembers++; + trace(gi->qflag,LOG_NOTICE, "got a Unix members %s from %s\n ", ui.cn,gi->cn); + } else { + free(v); + traceForce(gi->qflag,LOG_WARNING, "Not enough memory for adding member %s tp group %s\n",ui.cn,gi->cn); + err=ENOMEM; + } + } + } + free_nw_user_info(&ui); + return err; +} + + +static NWDSCCODE nds_group_unixgid(NWDSContextHandle ctx, const void* val, void* arg) { + struct nw_group_info* gi = (struct nw_group_info*)arg; + + if (gi->gid == (gid_t)-1) { + gi->gid = *(const Integer_T*)val; + // talk a bit (real NDS8 attribute or dummy ?) + trace(gi->qflag,LOG_NOTICE, "got a Unix GID %d from %s\n ", gi->gid, ATTR_GID); + } + return 0; +} + +// PP: id no NDS8 is present, collect the group Unix ID from one of the location +// string with the format G:nnn +// can also used to specify a name of unix group different of the NDS'one +// eg. everyone --> users or staff --> root +static NWDSCCODE nds_group_location(NWDSContextHandle ctx, const void* val, void* arg) { + + struct nw_group_info* gi = (struct nw_group_info*)arg; + const char *pt= (const char*) val; + int n; + + if (strlen(pt)>2 && pt[1]==':') { + const char* cur_pt=pt+2; + switch (*pt) { + case 'g': + case 'G':if (gi->gid == (gid_t)-1) { + switch (getnumber(&n,&cur_pt)) { + case 0: gi->gid=n; break; + default:traceForce(gi->qflag,LOG_ERR, "Invalid group GID %s for %s\n",pt,gi->cn); + } + } + break; + case 'n': + case 'N': // unix equivalent name + if (!gi->alias) { + char* v = strdup(cur_pt); + if (!v) { + traceForce(gi->qflag,LOG_WARNING, "Not enough memory for strdup()\n"); + return ENOMEM; + } + gi->alias = v; + trace(gi->qflag,LOG_NOTICE, "group:got a Unix alias %s from %s\n ", gi->alias, gi->cn); + } + break; + } + } + return 0; +} + + +static NWDSCCODE nds_group_info(NWDSContextHandle ctx, const NWDSChar* objname, void * gi, int modeDebug) { + static const struct attrop atlist[] = { + { ATTR_CN, nds_group_cn, SYN_CN }, + { ATTR_GID, nds_group_unixgid, SYN_GID }, + { ATTR_MEMBERS, nds_group_members, SYN_MEMBERS}, + { NULL, NULL, SYN_UNKNOWN }}; + + static const struct attrop atlist2[] = { + {ATTR_LOCATION, nds_group_location, SYN_LOCATION}, + {NULL, NULL, SYN_UNKNOWN}}; + + + NWDSCCODE err; + +// we must do TWO NDS queries since NDS does not return attributes in this order +// studies of /var/log/secure showed that L attribute usually come out before the NDS8 ones ! + err = nds_read_attrs(ctx, objname, gi, atlist,modeDebug); + if (err) + return err; + return nds_read_attrs(ctx, objname, gi, atlist2,modeDebug); +} + + +/***************** GET limited group's information (used when searching for groups to which a user belongs) */ +static NWDSCCODE nds_group_location2(NWDSContextHandle ctx, const void* val, void* arg) { + + struct nw_group_info* gi = (struct nw_group_info*)arg; + const char *pt= (const char*) val; + int n; + + if (strlen(pt)>2 && pt[1]==':') { + const char* cur_pt=pt+2; + switch (*pt) { + case 'g': + case 'G':if (gi->gid == (gid_t)-1) { + switch (getnumber(&n,&cur_pt)) { + case 0: gi->gid=n; break; + default:traceForce(gi->qflag,LOG_ERR, "Invalid group GID %s for %s\n",pt,gi->cn); + } + } + break; + } + } + return 0; +} + +/* we search only GID either stored in NDS8 attributes ( Real or Dummy) or in Location */ +static NWDSCCODE nds_group_info2(NWDSContextHandle ctx, const NWDSChar* objname, void * gi, int modeDebug) { + + static const struct attrop atlist[] = { + { ATTR_GID, nds_group_unixgid, SYN_GID }, + { NULL, NULL, SYN_UNKNOWN }}; + + static const struct attrop atlist2[] = { + {ATTR_LOCATION, nds_group_location2, SYN_LOCATION}, + {NULL, NULL, SYN_UNKNOWN}}; + + + NWDSCCODE err; + +// we must do TWO NDS queries since NDS does not return attributes in this order +// studies of /var/log/secure showed that L attribute usually come out before the NDS8 ones ! + err = nds_read_attrs(ctx, objname, gi, atlist,modeDebug); + if (err) + return err; + return nds_read_attrs(ctx, objname, gi, atlist2,modeDebug); +} + + +/*****************************************************GET SHADOW INFO FROM NDS *************/ + +static NWDSCCODE nds_shadow_cn(NWDSContextHandle ctx, const void *val, void *arg){ + + struct nw_shadow_info *si = (struct nw_shadow_info *) arg; + + if (!si->cn) { + char *v = strdup((const char *) val); + if (!v) { + traceForce(si->qflag & QF_DEBUG,LOG_WARNING, "Not enough memory for strdup()\n"); + return ENOMEM; + } + si->cn = v; + trace(si->qflag & QF_DEBUG,LOG_NOTICE, "shadow:got a Unix cn %s from %s\n ", si->cn, ATTR_CN); + } + return 0; +} + + +static NWDSCCODE nds_shadow_unixuid(NWDSContextHandle ctx, const void *val, void *arg){ + + struct nw_shadow_info *si = (struct nw_shadow_info *) arg; + if (si->uid == (uid_t) -1) { + si->uid = *(const Integer_T *) val; + // talk a bit (real NDS8 attribute or dummy ?) + trace(si->qflag & QF_DEBUG,LOG_NOTICE, "shadow: got a Unix ID %d from %s\n ", si->uid, ATTR_UID); + } + return 0; +} + + +// PP: id no NDS8 is present, collect the user's basic Unix informations from the location +// strings with the format X:nnnnnnnn , X = [U,G,H,S,P,O,C,Z] upper of lower case +// Of course, even if NDS8 IS present, we still look at these, just in case the migration +// is not complete and to look for the user's ZENFLAG + +static NWDSCCODE nds_shadow_location(NWDSContextHandle ctx, const void *val, void *arg){ + + struct nw_shadow_info *si = (struct nw_shadow_info *) arg; + const char *pt = (const char *) val; + char *v; + int n; + int err; + + trace(si->qflag & QF_DEBUG,LOG_NOTICE, "shadow: start of NW location got %s\n ", pt); + + if (strlen(pt) > 2 && pt[1] == ':') { + const char *cur_pt = pt + 2; + switch (*pt) { + case 'u': //user ID leading spaces not significant + case 'U': + if (si->uid == (uid_t) -1) { // do not overwrite a DS 8 answer + switch (getnumber(&n, &cur_pt)) { + case 0: + si->uid = n; + break; + default: + traceForce(si->qflag & QF_DEBUG,LOG_ERR, "shadow:Invalid user ID %s\n", pt); + } + } + break; + } + + } + return 0; +} + +static NWDSCCODE nds_shadow_pwd_expire(NWDSContextHandle ctx, const void *val, void *arg){ + struct nw_shadow_info *si = (struct nw_shadow_info *) arg; + si->sp_expire = *(const Time_T *) val/3600/24; + return 0; +} + +static NWDSCCODE nds_shadow_int_pwd_expire(NWDSContextHandle ctx, const void *val, void *arg){ + struct nw_shadow_info *si = (struct nw_shadow_info *) arg; + si->sp_min = *(const Integer_T *) val/3600/24; + si->sp_max = *(const Integer_T *) val/3600/24; + return 0; +} + +static NWDSCCODE nds_shadow_acct_expire(NWDSContextHandle ctx, const void *val, void *arg){ + struct nw_shadow_info *si = (struct nw_shadow_info *) arg; + si->sp_inact = *(const Time_T *) val/3600/24; + return 0; +} + +static NWDSCCODE nds_shadow_grace_pwd_expire (NWDSContextHandle ctx, const void *val, void *arg) { +// in NDS it is the number of grace login, in Unix the number of DAYS + struct nw_shadow_info *si = (struct nw_shadow_info *) arg; + si->sp_warn = *(const Integer_T *) val; + return 0; +} + + +/*****************************************************GET USER SHADOW INFOS FROM NDS *************/ + +static NWDSCCODE nds_shadow_info(NWDSContextHandle ctx, const NWDSChar * objname, void *si,int modeDebug){ + static const struct attrop atlist[] = { + {ATTR_CN, nds_shadow_cn, SYN_CN}, + {ATTR_UID, nds_shadow_unixuid, SYN_UID}, + {ATTR_DATE_PWD_EXPIRE,nds_shadow_pwd_expire,SYN_TIME}, + {ATTR_DATE_ACCT_EXPIRE,nds_shadow_acct_expire,SYN_TIME}, + {ATTR_INT_PWD_EXPIRE,nds_shadow_int_pwd_expire,SYN_INTERVAL}, + {ATTR_GRACE_LIMIT,nds_shadow_grace_pwd_expire,SYN_INTEGER}, + {NULL, NULL, SYN_UNKNOWN} + }; + + static const struct attrop atlist2[] = { + {ATTR_LOCATION, nds_shadow_location, SYN_LOCATION}, + {NULL, NULL, SYN_UNKNOWN} + }; + + NWDSCCODE err; + +// we must do TWO NDS queries since NDS does not return attributes in this order +// studies of /var/log/secure showed that L attribute usually come out before the NDS8 ones ! + err = nds_read_attrs(ctx, objname, si, atlist,modeDebug); + if (err) + return err; + return nds_read_attrs(ctx, objname, si, atlist2,modeDebug); +} + + +/***************get all group id of groups userName belongs to *********************/ + +static NWDSCCODE nds_user_cn2(NWDSContextHandle ctx, const void *val, void *arg){ + + struct nw_user_group_info *ui = (struct nw_user_group_info *) arg; + if (!ui->cn) { + char *v = strdup((const char *) val); + if (!v) { + traceForce(ui->qflag,LOG_WARNING, "Not enough memory for strdup()\n"); + return ENOMEM; + } + ui->cn = v; + trace(ui->qflag & QF_DEBUG,LOG_NOTICE, "got a Unix cn %s from %s\n ", ui->cn, ATTR_CN); + } + return 0; +} + + + +static NWDSCCODE nds_user_unixuid2(NWDSContextHandle ctx, const void *val, void *arg){ + struct nw_user_group_info *ui = (struct nw_user_group_info *) arg; + if (ui->uid == (uid_t) -1) { + ui->uid = *(const Integer_T *) val; + // talk a bit (real NDS8 attribute or dummy ?) + trace(ui->qflag & QF_DEBUG,LOG_NOTICE, "got a Unix ID %d from %s\n ", ui->uid, ATTR_UID); + } + return 0; +} + + +static NWDSCCODE nds_user_location3(NWDSContextHandle ctx, const void *val, void *arg){ + struct nw_user_group_info *ui = (struct nw_user_group_info *) arg; + const char *pt = (const char *) val; + char *v; + int n; + int err; + + + trace(ui->qflag & QF_DEBUG,LOG_NOTICE, "start of NW location got %s\n ", pt); + + if (strlen(pt) > 2 && pt[1] == ':') { + const char *cur_pt = pt + 2; + switch (*pt) { + case 'u': //user ID leading spaces not significant + case 'U': + if (ui->uid == (uid_t) -1) { // do not overwrite a DS 8 answer + switch (getnumber(&n, &cur_pt)) { + case 0: + ui->uid = n; + break; + default: + traceForce(ui->qflag & QF_DEBUG,LOG_ERR, "Invalid user ID %s\n", pt); + } + } + break; + } + + } + return 0; +} + +static NWDSCCODE nds_get_one_user_group(NWDSContextHandle ctx, const void *val, void *arg){ + struct nw_user_group_info *ui = (struct nw_user_group_info *) arg; + struct nw_group_info gi; + NWDSCCODE ccode; + + init_nw_group_info(&gi,ui->qflag); + //check whether group has some Unix properties + trace(ui->qflag & QF_DEBUG,LOG_NOTICE, "found group %s for user %s\n ", (const char*)val, ui->cn); + ccode=nds_group_info2(ctx,(const char *)val,&gi,ui->qflag); + // found a real GID , no fallback here else all groups would have the same number !!!! + if (!ccode && gi.gid != (gid_t) -1) { + trace(ui->qflag & QF_DEBUG,LOG_NOTICE, "found group GID %d for user %s\n ", gi.gid, ui->cn); + if (ui->used >=ui->alloc) { + gid_t* np; + size_t ns; + if (ui->groups) { + ns=ui->alloc +8; + np=(gid_t*)realloc (ui->groups,ns*sizeof(gid_t)); + }else { + ns=8; + np=(gid_t*)malloc (ns*sizeof(gid_t)); + } + if (!np) { + traceForce(ui->qflag & QF_DEBUG,LOG_WARNING, "Not enough memory for allocating GID table\n"); + return ENOMEM; + } + ui->groups=np; + ui->alloc=ns; + } + ui->groups[ui->used++]=gi.gid; + } + free_nw_group_info(&gi); + return ccode; +} + + +static NWDSCCODE nds_get_user_groups(NWDSContextHandle ctx, const NWDSChar * objname, void *ui, int modeDebug){ +// get all groups of userName +static const struct attrop atlist[] = { + {ATTR_CN, nds_user_cn2, SYN_CN}, + {ATTR_UID, nds_user_unixuid2, SYN_UID}, + {ATTR_GRP_MBS, nds_get_one_user_group, SYN_GRP_MBS}, + {NULL, NULL, SYN_UNKNOWN} + }; + + static const struct attrop atlist2[] = { + {ATTR_LOCATION, nds_user_location3, SYN_LOCATION}, + {NULL, NULL, SYN_UNKNOWN} + }; + + NWDSCCODE err; + +// we must do TWO NDS queries since NDS does not return attributes in this order +// studies of /var/log/secure showed that L attribute usually come out before the NDS8 ones ! + err = nds_read_attrs(ctx, objname, ui, atlist,modeDebug); + if (err) + return err; + return nds_read_attrs(ctx, objname, ui, atlist2,modeDebug); + +} + +/*******************************************************************************************************************/ +static NWDSCCODE CreateContextAndConn ( NWDSContextHandle *context,NWCONN_HANDLE *conn, struct nss_ncp_conf* conf) { + NWDSCCODE ccode; + nuint32 contextFlags; + + trace(conf->debug, LOG_NOTICE,"Entering create context and conn"); + + ccode = NWDSCreateContextHandle(context); + if(ccode) { + traceForce(conf->debug,LOG_WARNING,"Error creating context.\n"); + goto Exit1; + } + + trace(conf->debug, LOG_NOTICE,"CreateContextHandle OK"); + + //ccode=NWDSSetContext(*context, DCK_NAME_CONTEXT, conf->startCtx); + + ccode=NWDSSetContext(*context, DCK_NAME_CONTEXT, "[Root]"); + if(ccode){ + traceForce(conf->debug,LOG_WARNING,"Error NWDSSetContext(): %d\n",ccode); + goto Exit2; + } + + trace(conf->debug, LOG_NOTICE,"SetContext OK"); + + ccode= NWDSGetContext(*context, DCK_FLAGS, &contextFlags); + if( ccode){ + traceForce(conf->debug,LOG_WARNING,"NWDSGetContext (DCK_FLAGS) failed, returns %d\n", ccode); + goto Exit2; + } + + trace(conf->debug, LOG_NOTICE,"GetContext OK"); + + contextFlags|= DCV_TYPELESS_NAMES; + ccode= NWDSSetContext( *context, DCK_FLAGS, &contextFlags); + if( ccode) { + traceForce(conf->debug,LOG_WARNING,"NWDSSetContext (DCK_FLAGS DCV_TYPELESS_NAMES) failed, returns %d\n", ccode); + goto Exit2; + } + + trace(conf->debug, LOG_NOTICE,"SetContext OK"); + trace(conf->debug, LOG_NOTICE,"calling NWCCOpenConnByName ..."); + + if (conf->server[0] == '/') //using a permanent connection + ccode = ncp_open_mount(conf->server, conn); + else { + + if (!conf->useTree) + ccode = NWCCOpenConnByName(NULL, conf->server, NWCC_NAME_FORMAT_BIND, 0, 0, conn); + else + //ccode=NWCXAttachToTreeByName( conn, conf->server); + ccode = NWCCOpenConnByName(NULL, conf->server, NWCC_NAME_FORMAT_NDS_TREE, 0, 0, conn); + if (ccode) { + traceForce(conf->debug,LOG_WARNING,"Error: NWCCOpenConnByName failed %s\n",strnwerror(ccode)); + goto Exit2; + } + } + + trace(conf->debug, LOG_NOTICE,"NWCCOpenConnByName OK"); + + ccode= NWDSAddConnection(*context, *conn); + if (ccode) { + traceForce(conf->debug,LOG_WARNING,"Error: NWCCOpenConnByName failed %s\n",strnwerror(ccode)); + goto Exit2; + } + + trace(conf->debug, LOG_NOTICE,"AddConnection OK"); + + if (conf->debug & QF_DEBUG) { + char aux[512]; + aux[0] = 0; + if (!conf->useTree) { + NWCCGetConnInfo(*conn, NWCC_INFO_TREE_NAME, sizeof (aux), aux); + trace(conf->debug, LOG_DEBUG, "sucessful connection to tree %s by server %s \n",aux,conf->server); + }else { + NWCCGetConnInfo(*conn, NWCC_INFO_SERVER_NAME, sizeof (aux), aux); + trace(conf->debug,LOG_DEBUG, "successful connection by NDS server %s on tree %s\n", aux,conf->server); + } + } + +Exit2: + if (ccode) { + trace(conf->debug, LOG_NOTICE,"Closing context and conn due to errors"); + if(conn) NWCCCloseConn (*conn); + if (context) NWDSFreeContext(*context); + *context=NULL; + *conn=NULL; + } +Exit1: + trace(conf->debug, LOG_NOTICE,"leaving CreateContextAndConn"); + return ccode; +} + + +/**** PP TreeScaning routines ***********************/ + +struct TreeNode { + struct TreeNode* left; + struct TreeNode* right; + struct TreeNode* next; + struct TreeNode** pprev; + size_t cnt; + char name [MAX_DN_CHARS+1]; +}; + +struct ObjectList { + struct TreeNode* first; + struct TreeNode* lin; + struct TreeNode* curr; + int dups; + size_t uniqueObjects; + size_t remainObjects; + size_t totalObjects; + NWDSContextHandle context; + NWCONN_HANDLE conn; + struct nss_ncp_conf * conf; +}; + +static struct ObjectList* __allocTree(int dups,struct nss_ncp_conf * conf) { + struct ObjectList* t; + + t = (struct ObjectList*)malloc(sizeof(*t)); + if (t) { + t->first = NULL; + t->lin = NULL; + t->curr = NULL; + t->dups = dups; + t->uniqueObjects = 0; + t->conf=conf; + } + return t; +} + +static void __freeNode(struct TreeNode* n) { + while (n) { + struct TreeNode* tmp; + + __freeNode(n->left); + tmp = n; + n = n->right; + free(tmp); + } +} + +static void __freeTree(struct ObjectList* t) { + if (t) { + struct TreeNode* n = t->first; + if (t->conf) + free_nss_ncp_conf(t->conf); + free(t); + __freeNode(n); + } +} + +static NWDSCCODE __allocNode(struct TreeNode** pn, const char* objectName) { + struct TreeNode* n; + size_t len=strlen(objectName); + + if (len > MAX_DN_CHARS) + return NWE_BUFFER_OVERFLOW; + n = (struct TreeNode*)malloc(sizeof(*n)); + if (!n) + return ERR_NOT_ENOUGH_MEMORY; + n->left = n->right = NULL; + n->cnt = 1; + memcpy(n->name, objectName, len + 1); + *pn = n; + return 0; +} + +static NWDSCCODE __insertNode(struct ObjectList* t, const char* objectName) { + struct TreeNode** p; + struct TreeNode* n; + NWDSCCODE err; + + p = &t->first; + while ((n = *p) != NULL) { + int cmp = strcasecmp(objectName, n->name); + if (cmp < 0) { + p = &n->left; + if (!*p) { + err = __allocNode(p, objectName); + if (!err) { + struct TreeNode* q = *p; + + q->next = n; + q->pprev = n->pprev; + n->pprev = &q->next; + *(q->pprev) = q; + t->uniqueObjects++; + t->totalObjects++; + } + return err; + } + } else if (cmp > 0) { + p = &n->right; + if (!*p) { + err = __allocNode(p, objectName); + if (!err) { + struct TreeNode* q = *p; + + q->next = n->next; + if (q->next) + q->next->pprev = &q->next; + n->next = q; + q->pprev = &n->next; + t->uniqueObjects++; + t->totalObjects++; + } + return err; + } + } else { + if (t->dups) { + n->cnt++; + t->totalObjects++; + return 0; + } else { + return EINVAL; // no dups allowed and one found + } + } + } + err = __allocNode(p, objectName); + if (!err) { + struct TreeNode* q = *p; + t->lin = q; + q->next = NULL; + q->pprev = &t->lin; + t->uniqueObjects++; + t->totalObjects++; + } + return err; +} + +static void print_nodes(struct TreeNode* n, int crlf) { + if (n) { + print_nodes(n->left,crlf); + if (crlf) + printf ("%s [%d]\n",n->name,n->cnt); + else + printf ("%s [%d]",n->name,n->cnt); + print_nodes(n->right,crlf); + } +} + +static void print_tree(struct ObjectList* t, int crlf) { + printf("total:%d unique:%d\n",t->totalObjects,t->uniqueObjects); + print_nodes (t->first,crlf); +} + + +// callback for getallentxx() +static NWDSCCODE +nds_insert_info(NWDSContextHandle ctx, const NWDSChar * objectName, void *tree, int modeDebug){ + return __insertNode((struct ObjectList*)tree, objectName); +} + +/* eot*/ + + +/*** collecting in a tree every member of a group, if his UID defined in NDS */ + +static NWDSCCODE +nds_get_group_members(NWDSContextHandle ctx, const void *val, void *arg){ + + struct ObjectList *tree = (struct ObjectList *) arg; + NWDSCCODE ccode=0; + struct nw_user_info ui; + + init_nw_user_info(&ui,0); + //check whether member has some Unix properties + ccode=nds_user_info2(ctx, (const char *)val, &ui,tree->conf->debug); + // found a UID real (no fallback otherwise all users would have the same UID) + if (!ccode && ui.uid !=(uid_t)-1) { + ccode=__insertNode(tree,(const char *)val); + } + free_nw_user_info(&ui); + return ccode; +} + + +static NWDSCCODE +getgroupmembers(NWDSContextHandle *context,NWCONN_HANDLE *conn, + const char* groupName,struct ObjectList * tree, struct nss_ncp_conf* conf){ +// get all members of a group + + NWDSCCODE ccode; + + static const struct attrop atlist[] = { + { ATTR_MEMBERS, nds_get_group_members, SYN_MEMBERS}, + { NULL, NULL, SYN_UNKNOWN }}; + + NWDSCCODE err; + trace(conf->debug, LOG_NOTICE,"entering getgroupmembers for group %s",groupName); + ccode=CreateContextAndConn ( context,conn,conf); + if (ccode) + return ccode; + ccode=nds_read_attrs(*context, groupName, tree, atlist,conf->debug); + trace(conf->debug, LOG_NOTICE,"leaving getgroupmembers for group %s err=%s",groupName,strnwerror(ccode)); + return ccode; +} + + +// static lists. Allocated by nss_ncp_setxxent_r, used buy nss_ncp_getxxent_r and released by nss_ncp_endxxent_r +// TODO :mutex and threads needed as in nss_ldap or nss_mysql ??? + +static struct ObjectList* ndsUsers=NULL; +static struct ObjectList* ndsGroups=NULL; +static struct ObjectList* ndsShadows=NULL; + +// description of a NDS class to be searched by getentbyxx +struct class_info { + char * className; + char * nds8Attribute; //name of ID attribute in NDS8 + char * LID1; // markers in L attribute for ID (U: or G:) + char * LID2; // markers in L attribute for ID (u: or g:), may be in lower case + char * LAlias1;// markers in L attribute for alias (N:) + char * LAlias2; // markers in L attribute for alias (n:) may be in lower case + +}; + +// we care only about user's and group classes +static struct class_info USER_CLASS = {"User", ATTR_UID,"U:","u:","N:","n:"}; +static struct class_info GROUP_CLASS= {"Group",ATTR_GID,"G:","g:","N:","n:"}; + + +/*protoptype of callback functions used in getentbyxx*/ + +struct infoop { + NWDSCCODE (*getinfo) (NWDSContextHandle ctx , const NWDSChar * objectName, void * info, int debug); +}; +/* + currently match + nds_user_info(context,objectName,ui,modeDebug); + nds_user_info2(context,objectName,ui,modeDebug); + nds_group_info(context,objectName,gi,modeDebug); + nds_group_info2(context,objectName,gi,modeDebug); + nds_shadow_info(context,objectName,si,modeDebug); + nds_insert_info(context,objectName,tree,modeDebug): +*/ + + +// generic NDS search routine +static NWDSCCODE getentbyxx( + NWDSContextHandle *retContext, // context to return (NULL= close when leaving) + NWCONN_HANDLE *retConn, // connexion to return (NULL= close when leaving) + struct class_info classType, // class to search (User of Group) + void *info, // structure to fill (can be nw_user_info,nw_shadow_info,nw_group_info or a ObjectList) + const struct infoop callBack, // routine to call for all found NDS objects + const char *unixName, // Unix objet name to find in NDS (if NULL search by ID) + uid_t id, // Unix ID to find in NDS , if -1 search by unixName) + int allEntries, // Ignore unixName and id and return all entries belonging to classType.className + struct nss_ncp_conf *conf) { // configuration record (debug...) + + NWDSContextHandle context; + NWCONN_HANDLE conn; + NWDSCCODE ccode; + nint32 iterationHandle= NO_MORE_ITERATIONS; // to be set as such at Exit4 + nint32 countObjectsSearched; + nuint32 objCntr,attrCntr,valCntr; + nuint32 objCount; + nuint32 attrCount; + char objectName[MAX_DN_CHARS+1]; + char attrName[MAX_SCHEMA_NAME_CHARS+1]; + nuint32 attrValCount; + nuint32 syntaxID; + nuint32 attrValSize; + char* attrVal; + + // buffers + pBuf_T searchFilter=NULL; // search filter + pBuf_T retBuf=NULL; // result buffer for NWDSSearch + pBuf_T attrNames=NULL; // specify which attribute values to return + Filter_Cursor_T* cur=NULL; // search expression tree temporary buffer + Object_Info_T objectInfo; + + + //few checks + + if (!allEntries) { + if (unixName && id !=(uid_t)-1) + return EINVAL; + if (!unixName && id ==(uid_t)-1) + return EINVAL; + } + + trace(conf->debug, LOG_NOTICE,"entering getentbyxx"); + + ccode=CreateContextAndConn ( &context,&conn,conf); + if (ccode) + return ccode; + + trace(conf->debug, LOG_NOTICE,"context and conn OK"); + /* + In order to search, we need: + A Filter Cursor (to build the search expression) + A Filter Buffer (to store the expression; used by NWDSSearch) + A Buffer to store which attributes we need information on + A Result Buffer (to store the search results) + */ + ccode = NWDSAllocBuf(DEFAULT_MESSAGE_LEN,&searchFilter); + if (ccode) { + traceForce(conf->debug,LOG_WARNING,"NWDSAllocBuf returned: %d\n", ccode); + goto Exit3; + } + trace(conf->debug, LOG_NOTICE,"NWDSAllocBuf searchFilter OK"); + // Initialize the searchFilter buffer + ccode = NWDSInitBuf(context,DSV_SEARCH_FILTER,searchFilter); + if (ccode) { + traceForce(conf->debug,LOG_WARNING,"NWDSInitBuf returned: %d\n", ccode); + goto Exit4; + } + + trace(conf->debug, LOG_NOTICE, "NWDSInitBuf searchFilter OK"); + + // Allocate a filter cursor to put the search expression + ccode = NWDSAllocFilter(&cur); + if (ccode) { + traceForce(conf->debug,LOG_WARNING,"NWDSAllocFilter returned: %d\n", ccode); + goto Exit4; + } + trace(conf->debug, LOG_NOTICE,"NWDSAllocFilter cur OK"); + // Build the expression tree in cur, then place into searchFilter + // Object Class = User + ccode = NWDSAddFilterToken(cur,FTOK_ANAME,"Object Class",SYN_CLASS_NAME); + if (ccode) { + traceForce(conf->debug,LOG_WARNING,"NWDSAddFilterToken OBJECTCLASS returned: %d\n", ccode); + goto Exit4; + } + ccode = NWDSAddFilterToken(cur,FTOK_EQ,NULL,0); + if (ccode) { + traceForce(conf->debug,LOG_WARNING,"NWDSAddFilterToken FTOK_EQ returned: %d\n", ccode); + goto Exit4; + } + + ccode = NWDSAddFilterToken(cur,FTOK_AVAL,classType.className,SYN_CLASS_NAME); + if (ccode) { + traceForce(conf->debug,LOG_WARNING,"NWDSAddFilterToken FTOK_AVAL User returned: %d\n", ccode); + goto Exit4; + } + + trace(conf->debug, LOG_NOTICE,"AddFilter for classname OK"); + + if (!allEntries) { + ccode = NWDSAddFilterToken(cur,FTOK_AND,NULL,0); + if (ccode ) { + traceForce(conf->debug,LOG_WARNING,"NWDSAddFilterToken FTOK_AND returned: %d\n", ccode); + goto Exit4; + } + + if (unixName) { + /* search for the CN or an alias in location strings */ + /* CN=unixName or L=N:unixNname or l=n:unixName */ + char buf1[255]; + char buf2[255]; + + if (strlen(unixName)+3 >sizeof(buf1)) { + //buffer overflow !!! + ccode=EINVAL; + traceForce(conf->debug,LOG_WARNING,"unixName %s is too long !!!!\n", unixName); + goto Exit4; + } + sprintf (buf1,"%s%s",classType.LAlias1,unixName); + sprintf (buf2,"%s%s",classType.LAlias2,unixName); + + ccode = NWDSAddFilterToken(cur,FTOK_LPAREN,NULL,0); + if (ccode ) { + traceForce(conf->debug,LOG_WARNING,"NWDSAddFilterToken FTOK_RPAREN returned: %d\n", ccode); + goto Exit4; + } + + ccode = NWDSAddFilterToken(cur,FTOK_ANAME,"CN",0); + if (ccode) { + traceForce(conf->debug,LOG_WARNING,"NWDSAddFilterToken FTOK_ANAME CN returned: %d\n", ccode); + goto Exit4; + } + + ccode = NWDSAddFilterToken(cur,FTOK_EQ,NULL,0); + if (ccode ) { + traceForce(conf->debug,LOG_WARNING,"NWDSAddFilterToken FTOK_EQ returned: %d\n", ccode); + goto Exit4; + } + + ccode = NWDSAddFilterToken(cur,FTOK_AVAL,unixName,SYN_CI_STRING); + if (ccode ) { + traceForce(conf->debug,LOG_WARNING,"NWDSAddFilterToken FTOK_AVAL %s returned: %d\n", unixName,ccode); + goto Exit4; + } + ccode = NWDSAddFilterToken(cur,FTOK_OR,NULL,0); + if (ccode ) { + traceForce(conf->debug,LOG_WARNING,"NWDSAddFilterToken FTOK_OR returned: %d\n", ccode); + goto Exit4; + } + ccode = NWDSAddFilterToken(cur,FTOK_ANAME,"L",0); + if (ccode) { + traceForce(conf->debug,LOG_WARNING,"NWDSAddFilterToken FTOK_ANAME L returned: %d\n", ccode); + goto Exit4; + } + + ccode = NWDSAddFilterToken(cur,FTOK_EQ,NULL,0); + if (ccode) { + traceForce(conf->debug,LOG_WARNING,"NWDSAddFilterToken FTOK_EQ returned: %d\n", ccode); + goto Exit4; + } + ccode = NWDSAddFilterToken(cur,FTOK_AVAL,buf1,SYN_CI_STRING); + if (ccode) { + traceForce(conf->debug,LOG_WARNING,"NWDSAddFilterToken FTOK_VAL %s returned: %d\n", buf1,ccode); + goto Exit4; + } + ccode = NWDSAddFilterToken(cur,FTOK_OR,NULL,0); + if (ccode) { + traceForce(conf->debug,LOG_WARNING,"NWDSAddFilterToken FTOK_OR returned: %d\n", ccode); + goto Exit4; + } + ccode = NWDSAddFilterToken(cur,FTOK_ANAME,"L",0); + if (ccode) { + traceForce(conf->debug,LOG_WARNING,"NWDSAddFilterToken FTOK_ANAME returned: %d\n", ccode); + goto Exit4; + } + ccode = NWDSAddFilterToken(cur,FTOK_EQ,NULL,0); + if (ccode) { + traceForce(conf->debug,LOG_WARNING,"NWDSAddFilterToken FTOK_END returned: %d\n", ccode); + goto Exit4; + } + ccode = NWDSAddFilterToken(cur,FTOK_AVAL,buf2,SYN_CI_STRING); + if (ccode) { + traceForce(conf->debug,LOG_WARNING,"NWDSAddFilterToken FTOK_AVAL %s returned: %d\n", buf2,ccode); + goto Exit4; + } + ccode = NWDSAddFilterToken(cur,FTOK_RPAREN,NULL,0); + if (ccode) { + traceForce(conf->debug,LOG_WARNING,"NWDSAddFilterToken FTOK_RPAREN returned: %d\n", ccode); + goto Exit4; + } + + } else { + if (id !=(uid_t)-1) { + /* search by UID.or GID + AND (L="U:xxxxx" OR L="u:xxxx" OR UNIX:UID = xxxx) for users + AND (L="G:xxxxx" OR L="g:xxxx" OR UNIX:GID = xxxx) for groups + */ + char buf1[80]; + char buf2[80]; + + sprintf (buf1,"%s%d",classType.LID1,id); + sprintf (buf2,"%s%d",classType.LID2,id); + + ccode = NWDSAddFilterToken(cur,FTOK_LPAREN,NULL,0); + if (ccode) { + traceForce(conf->debug,LOG_WARNING,"NWDSAddFilterToken FTOK_LPAREN returned: %d\n", ccode); + goto Exit4; + } + ccode = NWDSAddFilterToken(cur,FTOK_ANAME,"L",0); + if (ccode) { + traceForce(conf->debug,LOG_WARNING,"NWDSAddFilterToken FTOK_ANAME L returned: %d\n", ccode); + goto Exit4; + } + + ccode = NWDSAddFilterToken(cur,FTOK_EQ,NULL,0); + if (ccode) { + traceForce(conf->debug,LOG_WARNING,"NWDSAddFilterToken FTOK_EQ returned: %d\n", ccode); + goto Exit4; + } + + ccode = NWDSAddFilterToken(cur,FTOK_AVAL,buf1,SYN_CI_STRING); + if (ccode) { + traceForce(conf->debug,LOG_WARNING,"NWDSAddFilterToken FTOK_VAL %s returned: %d\n", buf1,ccode); + goto Exit4; + } + ccode = NWDSAddFilterToken(cur,FTOK_OR,NULL,0); + if (ccode) { + traceForce(conf->debug,LOG_WARNING,"NWDSAddFilterToken FTOK_OR returned: %d\n", ccode); + goto Exit4; + } + ccode = NWDSAddFilterToken(cur,FTOK_ANAME,"L",0); + if (ccode) { + traceForce(conf->debug,LOG_WARNING,"NWDSAddFilterToken FTOK_ANAME returned: %d\n", ccode); + goto Exit4; + } + + ccode = NWDSAddFilterToken(cur,FTOK_EQ,NULL,0); + if (ccode) { + traceForce(conf->debug,LOG_WARNING,"NWDSAddFilterToken FTOK_END returned: %d\n", ccode); + goto Exit4; + } + ccode = NWDSAddFilterToken(cur,FTOK_AVAL,buf2,SYN_CI_STRING); + if (ccode) { + traceForce(conf->debug,LOG_WARNING,"NWDSAddFilterToken FTOK_AVAL %s returned: %d\n", buf2,ccode); + goto Exit4; + } + ccode = NWDSAddFilterToken(cur,FTOK_OR,NULL,0); + if (ccode) { + traceForce(conf->debug,LOG_WARNING,"NWDSAddFilterToken FTOK_OR returned: %d\n", ccode); + goto Exit4; + } + ccode = NWDSAddFilterToken(cur,FTOK_ANAME,classType.nds8Attribute,0); + if (ccode) { + traceForce(conf->debug,LOG_WARNING,"NWDSAddFilterToken FTOK_ANAME returned: %d\n", ccode); + goto Exit4; + } + + ccode = NWDSAddFilterToken(cur,FTOK_EQ,NULL,0); + if (ccode) { + traceForce(conf->debug,LOG_WARNING,"NWDSAddFilterToken FTOK_END returned: %d\n", ccode); + goto Exit4; + } + ccode = NWDSAddFilterToken(cur,FTOK_AVAL,&buf1[2],SYN_INTEGER); + if (ccode) { + traceForce(conf->debug,LOG_WARNING,"NWDSAddFilterToken FTOK_AVAL %s returned: %d\n", buf2,ccode); + goto Exit4; + } + ccode = NWDSAddFilterToken(cur,FTOK_RPAREN,NULL,0); + if (ccode) { + traceForce(conf->debug,LOG_WARNING,"NWDSAddFilterToken FTOK_RPAREN returned: %d\n", ccode); + goto Exit4; + } + + } + } + } + ccode = NWDSAddFilterToken(cur,FTOK_END,NULL,0); + if (ccode) { + traceForce(conf->debug,LOG_WARNING,"NWDSAddFilterToken FTOK_END returned: %d\n", ccode); + goto Exit4; + } + + trace(conf->debug, LOG_NOTICE,"AddFilterToken FTOK_END OK"); + + // now place the cursor into the searchFilter buffer + // NWDSPutFilter frees the expression tree filter (cur) + // so if it succeeds, set cur to NULL so it won't be freed below + ccode = NWDSPutFilter(context,searchFilter,cur,NULL); + if (ccode) { + traceForce(conf->debug,LOG_WARNING,"NWDSPutFilter returned: %d\n", ccode); + goto Exit4; + } + else + cur=NULL; + + trace(conf->debug, LOG_NOTICE,"PutFilter OK"); + + // allocate and initialize the attrNames buffer (not used , needed ???) + ccode = NWDSAllocBuf(DEFAULT_MESSAGE_LEN,&attrNames); + if (ccode) { + traceForce(conf->debug,LOG_WARNING,"NWDSAllocBuf returned: %d\n", ccode); + goto Exit4; + } + + trace(conf->debug, LOG_NOTICE,"AllocBuf attrNamesOK"); + + ccode = NWDSInitBuf(context,DSV_SEARCH,attrNames); + if (ccode) { + traceForce(conf->debug,LOG_WARNING,"NWDSInitBuf returned: %d\n", ccode); + goto Exit4; + } + + trace(conf->debug, LOG_NOTICE,"InitBuf attrNames OK"); + + // Allocate a result buffer + ccode = NWDSAllocBuf(65500,&retBuf); + if (ccode) { + traceForce(conf->debug,LOG_WARNING,"NWDSAllocBuf returned: %d\n", ccode); + goto Exit4; + } + + trace(conf->debug, LOG_NOTICE,"AllocBuf retBuf OK, start searching..."); + + // PP 11-01-2003 + // with NCP_DEBUG=cleanup, if we exit here, usecount of the connection is still 1 (OK) + // so usecount is augmented below + //ccode=-1; + //goto Exit4; + + iterationHandle = NO_MORE_ITERATIONS; + // while NWDSSearch still can get some objects...( I expect 0 or 1) + do { + ccode = NWDSSearch(context, + //"[Root]", + conf->startCtx, + DS_SEARCH_SUBTREE, + FALSE, // don't dereference aliases + searchFilter, + FALSE, // we want ONLY attributes names + FALSE, // only want information in attrNames + attrNames, + &iterationHandle, + 0, // reserved + &countObjectsSearched, + retBuf); + if (ccode) { + traceForce(conf->debug,LOG_WARNING,"NWDSSearch returned: %s\n", strnwerror(ccode)); + goto Exit4; + } + // PP 11-01-2003 + // with NCP_DEBUG=cleanup, if we exit here, usecount of the connection is now 2 (bad) + // so it is NWDSSearch that augmented usecount !!!! + //ccode=-1; + //goto Exit4; + + + trace(conf->debug, LOG_NOTICE,"NWDSearch OK"); + // count the object returned in the buffer + ccode = NWDSGetObjectCount(context,retBuf,&objCount); + if (ccode) { + traceForce(conf->debug,LOG_WARNING,"NWDSGetObjectCount returned: %d\n", ccode); + goto Exit4; + } + if (objCount <= 0) { + ccode=-1; + goto Exit4; + } + if ( !allEntries && (objCount >1)) { + if (unixName) + traceForce(conf->debug,LOG_WARNING,"more than one NDS entry match the name=%s criteria. ",unixName); + else + traceForce(conf->debug,LOG_WARNING,"more than one NDS entry match the id=%d criteria. ",id); + } + trace(conf->debug, LOG_NOTICE,"GetObjectCount OK"); + // for the number of objects returned... + // for nss it should be only one !!! + for (objCntr=0;objCntrdebug,LOG_WARNING,"NWDSGetObjectName returned: %d\n", ccode); + goto Exit4; + } + + trace(conf->debug, LOG_NOTICE,"GetObjectName OK"); + + if (callBack.getinfo) { + ccode= callBack.getinfo(context,objectName,info,conf->debug); + if (ccode) + goto Exit4; + } + } + trace(conf->debug, LOG_NOTICE,"callback return OK"); + } while ((nuint32)iterationHandle != NO_MORE_ITERATIONS); + + trace(conf->debug, LOG_NOTICE,"End of iteration attrNamesOK"); + +Exit4: + if ((nuint32)iterationHandle != NO_MORE_ITERATIONS){ + NWDSCCODE ccode2; + if (ccode2=NWDSCloseIteration(context,iterationHandle,DSV_SEARCH)) { + traceForce(conf->debug,LOG_WARNING,"NWDSCloseIteration returned: %d\n", ccode2); + } + } + if (retBuf) + NWDSFreeBuf(retBuf); + if (cur) + NWDSFreeFilter(cur, NULL); + if (searchFilter) + NWDSFreeBuf(searchFilter); + if (attrNames) + NWDSFreeBuf(attrNames); + + trace(conf->debug, LOG_NOTICE,"All buffers cleaned OK"); + +Exit3: + if (ccode || !retConn){ + NWDSCCODE ccode2; + trace(conf->debug,LOG_NOTICE,"Closing connection %lx",conn); + ccode2=NWCCCloseConn (conn); + if (ccode2) + traceForce(conf->debug,LOG_WARNING,"NWCCloseConnection returned: %d %s\n", ccode,strnwerror(ccode2)); + }else + if (retConn) + *retConn=conn; +Exit2: + if (ccode || !retContext) { + NWDSCCODE ccode2=NWDSFreeContext(context); + trace(conf->debug, LOG_NOTICE,"Freeing context"); + if (ccode2) + traceForce(conf->debug,LOG_WARNING,"NWDSFreeContext returned: %d %s\n", ccode,strnwerror(ccode2)); + }else + if (retContext) + *retContext=context; +Exit1: + trace(conf->debug, LOG_NOTICE,"Leaving ..."); + return ccode; +} + + + + +static NWDSCCODE +getpwdentbyxx(struct nw_user_info *ui, const char* userName, uid_t userId, struct nss_ncp_conf *conf){ + +static const struct infoop getInfo={nds_user_info}; + +return getentbyxx( + NULL, // context to return (NULL= close when leaving) + NULL, // connexion to return (NULL= close when leaving) + USER_CLASS, // class to search (User of Group) + ui, // structure to fill (can be nw_user_info,nw_shadow_info,nw_group_info) + getInfo, // routine to call for all found NDS objects + userName, // Unix objet name to find in NDS (if NULL search by ID) + userId, // Unix ID to find in NDS , if -1 search by unixName) + FALSE, // Ignore objectName and id and return all entries belonging to className + conf); // debug flag +} + + +static NWDSCCODE +getgrpentbyxx(struct nw_group_info *gi, const char* groupName, gid_t groupId, struct nss_ncp_conf *conf){ + + static const struct infoop getInfo={nds_group_info}; + + return getentbyxx( + NULL, // context to return (NULL= close when leaving) + NULL, // connexion to return (NULL= close when leaving) + GROUP_CLASS, // class to search (User of Group) + gi, // structure to fill (can be nw_user_info,nw_shadow_info,nw_group_info) + getInfo, // routine to call for all found NDS objects + groupName, // Unix objet name to find in NDS (if NULL search by ID) + groupId, // Unix ID to find in NDS , if -1 search by unixName) + FALSE, // Ignore objectName and id and return all entries belonging to className + conf); // debug flag +} + + + + +static NWDSCCODE +getspentbyxx(struct nw_shadow_info *si, const char* userName, struct nss_ncp_conf *conf){ +// in shadow we search only by userName + static const struct infoop getInfo={nds_shadow_info}; + + return getentbyxx( + NULL, // context to return (NULL= close when leaving) + NULL, // connexion to return (NULL= close when leaving) + USER_CLASS, // class to search (User of Group) + si, // structure to fill (can be nw_user_info,nw_shadow_info,nw_group_info) + getInfo, // routine to call for all found NDS objects + userName, // Unix objet name to find in NDS (if NULL search by ID) + (uid_t)-1, // Unix ID to find in NDS , if -1 search by unixName) + FALSE, // Ignore objectName and id and return all entries belonging to className + conf); // debug flag +} + +static NWDSCCODE +getusergroupsbyxx(struct nw_user_group_info *ui, const char* userName, uid_t userId, struct nss_ncp_conf *conf){ + +static const struct infoop getInfo={nds_get_user_groups}; + + return getentbyxx( + NULL, // context to return (NULL= close when leaving) + NULL, // connexion to return (NULL= close when leaving) + USER_CLASS, // class to search (User of Group) + ui, // structure to fill (can be nw_user_info,nw_shadow_info,nw_group_info) + getInfo, // routine to call for all found NDS objects + userName, // Unix objet name to find in NDS (if NULL search by ID) + userId, // Unix ID to find in NDS , if -1 search by unixName) + FALSE, // Ignore objectName and id and return all entries belonging to className + conf); // debug flag +} + + + +static NWDSCCODE +getallents(NWDSContextHandle *context,NWCONN_HANDLE *conn, + const struct class_info classType, struct ObjectList * tree, struct nss_ncp_conf *conf){ +// called by all setxxent() if not control group is present in conf +// get all entries by className +// and add them to a sorted tree in memory +// return context and conncetion for later use by + +static const struct infoop getInfo={nds_insert_info}; + + return getentbyxx( + context, // context to return (NULL= close when leaving) + conn, // connexion to return (NULL= close when leaving) + classType, // class to search (User of Group) + tree, // structure to fill (can be nw_user_info,nw_shadow_info,nw_group_info) + getInfo, // routine to call for all found NDS objects + NULL, // Unix objet name to find in NDS (if NULL search by ID) + (uid_t)-1, // Unix ID to find in NDS , if -1 search by unixName) + TRUE, // Ignore objectName and id and return all entries belonging to className + conf); // debug flag +} + +/*******************************************************************************/ + + + +/******************************* NSS API ***************************************/ + + +enum nss_status _nss_ncp_initgroups (const char *userName, gid_t group, + long int *start, long int *size, gid_t * groups, + long int limit,int *errnop) { + + struct nw_user_group_info inf; + NWDSCCODE err; + struct nss_ncp_conf *conf= parse_conf(CNF_FILE); + + if (!conf || !conf->doGroup) + return NSS_STATUS_UNAVAIL; + if (conf->debug) { + openlog("ncp_nss", LOG_PID, LOG_AUTHPRIV); + trace (conf->debug, LOG_NOTICE,"nss_ncp_initgroups entering"); + } + + init_nw_user_group_info(&inf,conf->debug); + err= getusergroupsbyxx(&inf, userName, (uid_t)-1,conf); + switch (err) { + case 0: + if (conf->debug &QF_VERBOSE) + print_nw_user_group_info(inf); + if (!fix_nw_user_group_info(&inf,conf)) + err=nw_user_group_info_to_groups(inf,group,start,size,groups,limit,errnop,conf); + else err=NSS_STATUS_UNAVAIL; + break; + case -1: // NOT FOUND IN NDS + err=NSS_STATUS_NOTFOUND; + *errnop=ENOENT; + break; + default: // NDS error + err=NSS_STATUS_UNAVAIL; + *errnop=ENOENT; + break; + + } + free_nw_user_group_info(&inf); + if (conf->debug) { + trace (conf->debug, LOG_NOTICE,"nss_ncp_initgroups leaving"); + closelog(); + } + return err; +} + + +enum nss_status _nss_ncp_getpwnam_r (const char* name, struct passwd *pwd, + char * buffer, size_t buflen, int * errnop) { + + struct nw_user_info inf; + NWDSCCODE err; + struct nss_ncp_conf *conf= parse_conf(CNF_FILE); + + if (!conf || !conf->doPassword) + return NSS_STATUS_UNAVAIL; + + if (conf->debug) { + openlog("ncp_nss", LOG_PID, LOG_AUTHPRIV); + trace (conf->debug, LOG_NOTICE,"nss_ncp_getpwnam entering"); + } + init_nw_user_info(&inf,conf->debug); + err= getpwdentbyxx(&inf, name, (uid_t)-1,conf); + switch (err) { + case 0: + if (conf->debug &QF_VERBOSE) + print_nw_user_info(inf); + if (!fix_nw_user_info(&inf,conf)) + err=nw_user_info_to_passwd(inf,pwd,buffer,buflen,errnop,conf); + else err=NSS_STATUS_UNAVAIL; + break; + case -1: // NOT FOUND IN NDS + err=NSS_STATUS_NOTFOUND; + *errnop=ENOENT; + break; + default: // NDS error + err=NSS_STATUS_UNAVAIL; + *errnop=ENOENT; + break; + + } + free_nw_user_info(&inf); + if (conf->debug) { + trace (conf->debug, LOG_NOTICE,"nss_ncp_getpwnam leaving"); + closelog(); + } + return err; +} + + +enum nss_status _nss_ncp_getpwuid_r (uid_t uid, struct passwd *pwd, + char * buffer, size_t buflen, int * errnop) { + + struct nw_user_info inf; + NWDSCCODE err; + struct nss_ncp_conf *conf= parse_conf(CNF_FILE); + + if (!conf || !conf->doPassword) + return NSS_STATUS_UNAVAIL; + + if (conf->debug) { + openlog("ncp_nss", LOG_PID, LOG_AUTHPRIV); + trace (conf->debug, LOG_NOTICE,"nss_ncp_getpwuid entering"); + } + init_nw_user_info(&inf,conf->debug); + err= getpwdentbyxx(&inf, NULL, uid,conf); + switch (err) { + case 0: + if (conf->debug &QF_VERBOSE) + print_nw_user_info(inf); + if (!fix_nw_user_info(&inf,conf)) + err=nw_user_info_to_passwd(inf,pwd,buffer,buflen,errnop,conf); + else err=NSS_STATUS_UNAVAIL; + break; + case -1: // NOT FOUND IN NDS + err=NSS_STATUS_NOTFOUND; + *errnop=ENOENT; + break; + default: // NDS error + err=NSS_STATUS_UNAVAIL; + *errnop=ENOENT; + break; + + } + free_nw_user_info(&inf); + if (conf->debug) { + trace (conf->debug, LOG_NOTICE,"nss_ncp_getpwuid leaving"); + closelog(); + } + return err; +} + + +enum nss_status _nss_ncp_getgrnam_r (const char* name, struct group *grp, + char * buffer, size_t buflen, int * errnop) { + + struct nw_group_info inf; + NWDSCCODE err; + struct nss_ncp_conf *conf= parse_conf(CNF_FILE); + + if (!conf || !conf->doGroup) + return NSS_STATUS_UNAVAIL; + + if (conf->debug) { + openlog("ncp_nss", LOG_PID, LOG_AUTHPRIV); + trace (conf->debug, LOG_NOTICE,"nss_ncp_getgrnam entering"); + } + init_nw_group_info(&inf,conf->debug); + err= getgrpentbyxx(&inf, name, (gid_t)-1,conf); + switch (err) { + case 0: + if (conf->debug &QF_VERBOSE) + print_nw_group_info(inf); + if (!fix_nw_group_info(&inf,conf)) + err=nw_group_info_to_group(inf,grp,buffer,buflen,errnop,conf); + else err=NSS_STATUS_UNAVAIL; + break; + case -1: // NOT FOUND IN NDS + err=NSS_STATUS_NOTFOUND; + *errnop=ENOENT; + break; + default: // NDS error + err=NSS_STATUS_UNAVAIL; + *errnop=ENOENT; + break; + + } + free_nw_group_info(&inf); + if (conf->debug) { + trace (conf->debug, LOG_NOTICE,"nss_ncp_getgrnam leaving"); + closelog(); + } + return err; +} + + +enum nss_status _nss_ncp_getspnam_r (const char * name, struct spwd *spw, + char *buffer, size_t buflen,int * errnop) { + struct nw_shadow_info inf; + NWDSCCODE err; + struct nss_ncp_conf *conf= parse_conf(CNF_FILE); + + if (!conf || !conf->doShadow) + return NSS_STATUS_UNAVAIL; + + if (conf->debug) { + openlog("ncp_nss", LOG_PID, LOG_AUTHPRIV); + trace (conf->debug, LOG_NOTICE,"nss_ncp_getspnam entering"); + } + init_nw_shadow_info(&inf,conf->debug); + err= getspentbyxx(&inf, name,conf); + switch (err) { + case 0: + if (conf->debug &QF_VERBOSE) + print_nw_shadow_info(inf); + if (!fix_nw_shadow_info(&inf,conf)) + err=nw_shadow_info_to_shadow(inf,spw,buffer,buflen,errnop,conf); + else err=NSS_STATUS_UNAVAIL; + break; + case -1: // NOT FOUND IN NDS + err=NSS_STATUS_NOTFOUND; + *errnop=ENOENT; + break; + default: // NDS error + err=NSS_STATUS_UNAVAIL; + *errnop=ENOENT; + break; + + } + free_nw_shadow_info(&inf); + if (conf->debug) { + trace (conf->debug, LOG_NOTICE,"nss_ncp_getspnam leaving"); + closelog(); + } + return err; + +} + + +enum nss_status _nss_ncp_getgrgid_r (gid_t gid, struct group *grp, + char * buffer, size_t buflen, int * errnop) { + struct nw_group_info inf; + NWDSCCODE err; + struct nss_ncp_conf *conf= parse_conf(CNF_FILE); + + if (!conf || !conf->doGroup) + return NSS_STATUS_UNAVAIL; + + if (conf->debug) { + openlog("ncp_nss", LOG_PID, LOG_AUTHPRIV); + trace (conf->debug, LOG_NOTICE,"nss_ncp_getgrgid entering"); + } + init_nw_group_info(&inf,conf->debug); + err= getgrpentbyxx(&inf, NULL, gid,conf); + switch (err) { + case 0: + if (conf->debug &QF_VERBOSE) + print_nw_group_info(inf); + if (!fix_nw_group_info(&inf,conf)) + err=nw_group_info_to_group(inf,grp,buffer,buflen,errnop,conf); + else err=NSS_STATUS_UNAVAIL; + break; + case -1: // NOT FOUND IN NDS + err=NSS_STATUS_NOTFOUND; + *errnop=ENOENT; + break; + default: // NDS error + err=NSS_STATUS_UNAVAIL; + *errnop=ENOENT; + break; + + } + free_nw_group_info(&inf); + if (conf->debug) { + trace (conf->debug, LOG_NOTICE,"nss_ncp_getgrid leaving"); + closelog(); + } + return err; +} + + +enum nss_status _nss_ncp_setpwent(void) { + NWDSContextHandle context; + NWCONN_HANDLE conn; + NWDSCCODE ccode; + struct nss_ncp_conf *conf= parse_conf(CNF_FILE); + + if (!conf || !conf->doPassword) + return NSS_STATUS_UNAVAIL; + + if (conf->debug) { + openlog("ncp_nss", LOG_PID, LOG_AUTHPRIV); + trace (conf->debug, LOG_NOTICE,"nss_ncp_setpwent entering"); + } + ndsUsers= __allocTree(FALSE,conf); + if (ndsUsers) { + if (conf->ctrlGroup && conf->ctrlGroup[0]) // caution if empty string from conf or default + ccode=getgroupmembers(&context,&conn,conf->ctrlGroup,ndsUsers,conf); + else + ccode=getallents(&context,&conn,USER_CLASS,ndsUsers,conf); + + if (!ccode) { + ndsUsers->context=context; + ndsUsers->conn=conn; + ndsUsers->curr = ndsUsers->lin; + ndsUsers->remainObjects = ndsUsers->uniqueObjects; + ccode= NSS_STATUS_SUCCESS; + } else { + __freeTree(ndsUsers); + ndsUsers=NULL; + ccode= NSS_STATUS_UNAVAIL; + } + }else + ccode= NSS_STATUS_UNAVAIL; + + if (conf->debug) { + trace (conf->debug, LOG_NOTICE,"nss_ncp_setpwent leaving"); + closelog(); + } + return ccode; + +} + +enum nss_status _nss_ncp_setgrent(void) { + NWDSContextHandle context; + NWCONN_HANDLE conn; + enum nss_status ccode; + struct nss_ncp_conf *conf= parse_conf(CNF_FILE); + + if (!conf || !conf->doGroup) + return NSS_STATUS_UNAVAIL; + + if (conf->debug) { + openlog("ncp_nss", LOG_PID, LOG_AUTHPRIV); + trace (conf->debug, LOG_NOTICE,"nss_ncp_setgrent entering"); + } + ndsGroups= __allocTree(FALSE,conf); + if (ndsGroups) { + if (! getallents(&context,&conn,GROUP_CLASS,ndsGroups,conf)) { + ndsGroups->context=context; + ndsGroups->conn=conn; + ndsGroups->curr = ndsGroups->lin; + ndsGroups->remainObjects = ndsGroups->uniqueObjects; + ccode=NSS_STATUS_SUCCESS; + } else { + __freeTree(ndsGroups); + ndsGroups=NULL; + ccode=NSS_STATUS_UNAVAIL; + } + }else + ccode= NSS_STATUS_UNAVAIL; + + if (conf->debug) { + trace (conf->debug, LOG_NOTICE,"nss_ncp_setgrent leaving"); + closelog(); + } + return ccode; + +} + + +enum nss_status _nss_ncp_setspent (void) { + NWDSContextHandle context; + NWCONN_HANDLE conn; + NWDSCCODE ccode; + struct nss_ncp_conf *conf= parse_conf(CNF_FILE); + + if (!conf || !conf->doShadow) + return NSS_STATUS_UNAVAIL; + + if (conf->debug) { + openlog("ncp_nss", LOG_PID, LOG_AUTHPRIV); + trace (conf->debug, LOG_NOTICE,"nss_ncp_setspent entering"); + } + ndsShadows= __allocTree(FALSE,conf); + if (ndsShadows) { + if (conf->ctrlGroup && conf->ctrlGroup[0]) // caution if empty string from conf or default + ccode=getgroupmembers(&context,&conn,conf->ctrlGroup,ndsShadows,conf); + else + ccode=getallents(&context,&conn,USER_CLASS,ndsShadows,conf); + + if (!ccode) { + ndsShadows->context=context; + ndsShadows->conn=conn; + ndsShadows->curr = ndsShadows->lin; + ndsShadows->remainObjects = ndsShadows->uniqueObjects; + ccode=NSS_STATUS_SUCCESS; + } else { + __freeTree(ndsShadows); + ndsShadows=NULL; + ccode=NSS_STATUS_UNAVAIL; + } + }else + ccode= NSS_STATUS_UNAVAIL; + + if (conf->debug) { + trace (conf->debug, LOG_NOTICE,"nss_ncp_setspent leaving"); + closelog(); + } + return ccode; + +} + + +enum nss_status _nss_ncp_endpwent(void) { + enum nss_status ccode; + + + if (ndsUsers) { + struct nss_ncp_conf *conf=ndsUsers->conf; + + if (conf->debug) { + openlog("ncp_nss", LOG_PID, LOG_AUTHPRIV); + trace (conf->debug, LOG_NOTICE,"nss_ncp_endpwent entering"); + } + NWCCCloseConn (ndsUsers->conn); + NWDSFreeContext(ndsUsers->context); + __freeTree(ndsUsers); + ndsUsers=NULL; + trace (conf->debug, LOG_NOTICE,"nss_ncp_setpwent all cleaned up OK"); + if (conf->debug) { + trace (conf->debug, LOG_NOTICE,"nss_ncp_setpwent leaving"); + closelog(); + } + ccode=NSS_STATUS_SUCCESS; + }else { + trace (QF_DEBUG, LOG_ERR,"nss_ncp_endpwent called without a previous nss_ncp_setpwent: nothing to cleanup"); + ccode=NSS_STATUS_UNAVAIL; + } + return ccode; +} + + +enum nss_status _nss_ncp_endgrent(void) { + enum nss_status ccode; + + + if (ndsGroups) { + struct nss_ncp_conf *conf=ndsGroups->conf; + + if (conf->debug) { + openlog("ncp_nss", LOG_PID, LOG_AUTHPRIV); + trace (conf->debug, LOG_NOTICE,"nss_ncp_endgrent entering"); + } + NWCCCloseConn (ndsGroups->conn); + NWDSFreeContext(ndsGroups->context); + __freeTree(ndsGroups); + ndsGroups=NULL; + trace (conf->debug, LOG_NOTICE,"nss_ncp_endgrent all cleaned up OK"); + if (conf->debug) { + trace (conf->debug, LOG_NOTICE,"nss_ncp_endpwent leaving"); + closelog(); + } + ccode=NSS_STATUS_SUCCESS; + }else { + trace (QF_DEBUG, LOG_ERR,"nss_ncp_endgrent called without a previous nss_ncp_setgrent : nothing to cleanup"); + ccode=NSS_STATUS_UNAVAIL; + } + return ccode; +} + + +enum nss_status _nss_ncp_endspent (void) { + enum nss_status ccode; + + + if (ndsShadows) { + struct nss_ncp_conf *conf=ndsShadows->conf; + if (conf->debug) { + openlog("ncp_nss", LOG_PID, LOG_AUTHPRIV); + trace (conf->debug, LOG_NOTICE,"nss_ncp_endspent entering"); + } + + NWCCCloseConn (ndsShadows->conn); + NWDSFreeContext(ndsShadows->context); + __freeTree(ndsShadows); + ndsShadows=NULL; + trace (conf->debug, LOG_NOTICE,"nss_ncp_endspent all cleaned up up OK"); + if (conf->debug) { + trace (conf->debug, LOG_NOTICE,"nss_ncp_endspent leaving"); + closelog(); + } + ccode=NSS_STATUS_SUCCESS; + }else { + trace (QF_DEBUG, LOG_ERR,"nss_ncp_endspent called without a previous nss_ncp_setspent : nothing to cleanup"); + ccode=NSS_STATUS_UNAVAIL; + } + return ccode; +} + +enum nss_status _nss_ncp_getpwent_r(struct passwd *pwd, + char * buffer, size_t buflen, int * errnop) { + enum nss_status err; + + if (ndsUsers) { + struct TreeNode* n; + NWDSCCODE ccode; + struct nw_user_info ui; + struct nss_ncp_conf *conf=ndsUsers->conf; + const char* ndsName; + if (conf->debug) { + openlog("ncp_nss", LOG_PID, LOG_AUTHPRIV); + trace (conf->debug, LOG_NOTICE,"nss_ncp_getpwent entering"); + } + +next_user:; // avoid a recursive call + n = ndsUsers->curr; + if (!n) { + //ready to scan again from the beginning (a good idea ??) + ndsUsers->curr = ndsUsers->lin; + ndsUsers->remainObjects = ndsUsers->uniqueObjects; + err= NSS_STATUS_NOTFOUND; + } else { + ndsName=n->name; + init_nw_user_info(&ui,conf->debug); + ccode=nds_user_info(ndsUsers->context,n->name,&ui,conf->debug); + + if (ccode) { + free_nw_user_info(&ui); + err=NSS_STATUS_NOTFOUND; + goto exit; + } + if (conf->debug &QF_VERBOSE) + print_nw_user_info(ui); + if (!fix_nw_user_info(&ui,conf)) + err=nw_user_info_to_passwd(ui,pwd,buffer,buflen,&errno,conf); + else err=NSS_STATUS_UNAVAIL; + free_nw_user_info(&ui); + switch (err) { + case NSS_STATUS_TRYAGAIN: + // buffer was too small + // do not advance to next user + // and let nss to try again with a bigger buffer; + break; + default: + // move to next user + if (!--n->cnt) { + ndsUsers->curr = n->next; + ndsUsers->remainObjects--; + } + if (err==NSS_STATUS_NOTFOUND) {// user has no unix property, skip + trace (conf->debug, LOG_NOTICE,"user %s has not Unix properties in NDS,skipping",ndsName); + goto next_user; + }else + err=NSS_STATUS_SUCCESS; + } + } +exit: + if (conf->debug) { + trace (conf->debug, LOG_NOTICE,"nss_ncp_getpwent leaving"); + closelog(); + } + + }else { + err=NSS_STATUS_UNAVAIL; + } + return err; + +} + + +enum nss_status _nss_ncp_getgrent_r(struct group *grp, + char * buffer, size_t buflen, int * errnop) { + enum nss_status err; + + if (ndsGroups) { + struct TreeNode* n; + NWDSCCODE ccode; + const char* ndsName; + struct nw_group_info gi; + struct nss_ncp_conf *conf=ndsGroups->conf; + + if (conf->debug) { + openlog("ncp_nss", LOG_PID, LOG_AUTHPRIV); + trace (conf->debug, LOG_NOTICE,"nss_ncp_getgrent entering"); + } +next_group:; // avoid a recursive call + n = ndsGroups->curr; + if (!n) { + //ready to scan again from the beginning (a good idea ??) + ndsGroups->curr = ndsGroups->lin; + ndsGroups->remainObjects = ndsGroups->uniqueObjects; + err= NSS_STATUS_NOTFOUND; + + }else { + ndsName=n->name; + init_nw_group_info(&gi,conf->debug); + ccode=nds_group_info(ndsGroups->context,n->name,&gi,conf->debug); + if (ccode) { + free_nw_group_info(&gi); + err= NSS_STATUS_NOTFOUND; + goto exit; + } + if (conf->debug &QF_VERBOSE) + print_nw_group_info(gi); + if (!fix_nw_group_info(&gi,conf)) + err=nw_group_info_to_group(gi,grp,buffer,buflen,&errno,conf); + else err=NSS_STATUS_UNAVAIL; + free_nw_group_info(&gi); + switch (err) { + case NSS_STATUS_TRYAGAIN: + // buffer was too small + // do not advance to next group + // and let nss to try again with a bigger buffer + break; + default: + // move to next group + if (!--n->cnt) { + ndsGroups->curr = n->next; + ndsGroups->remainObjects--; + } + if (err==NSS_STATUS_NOTFOUND) {// group has no unix property, skip + trace (conf->debug, LOG_NOTICE,"group %s has not Unix properties in NDS,skipping",ndsName); + goto next_group; + } else + err=NSS_STATUS_SUCCESS; + } + } +exit: + if (conf->debug) { + trace (conf->debug, LOG_NOTICE,"nss_ncp_getgrent leaving"); + closelog(); + } + + }else { + err= NSS_STATUS_UNAVAIL; + } + return err; +} + + +enum nss_status _nss_ncp_getspent_r (struct spwd *spw, + char * buffer, size_t buflen,int * errnop) { + enum nss_status err; + + + if (ndsShadows) { + struct TreeNode* n; + NWDSCCODE ccode; + const char* ndsName; + struct nw_shadow_info si; + struct nss_ncp_conf *conf=ndsShadows->conf; + + if (conf->debug) { + openlog("ncp_nss", LOG_PID, LOG_AUTHPRIV); + trace (conf->debug, LOG_NOTICE,"nss_ncp_getgrent entering"); + } +next_user:; // avoid a recursive call + n = ndsShadows->curr; + if (!n) { + //ready to scan again from the beginning (a good idea ??) + ndsShadows->curr = ndsShadows->lin; + ndsShadows->remainObjects = ndsShadows->uniqueObjects; + err= NSS_STATUS_NOTFOUND; + }else { + ndsName=n->name; + init_nw_shadow_info(&si,conf->debug); + ccode=nds_shadow_info(ndsShadows->context,n->name,&si,conf->debug); + if (ccode) { + free_nw_shadow_info(&si); + err=NSS_STATUS_NOTFOUND; + goto exit; + } + if (conf->debug &QF_VERBOSE) + print_nw_shadow_info(si); + if (!fix_nw_shadow_info(&si,conf)) + err=nw_shadow_info_to_shadow(si,spw,buffer,buflen,&errno,conf); + else err=NSS_STATUS_UNAVAIL; + free_nw_shadow_info(&si); + switch (err) { + case NSS_STATUS_TRYAGAIN: + // buffer was too small + // do not advance to next user + // and let nss to try again with a bigger buffer; + break; + default: + // move to next user + if (!--n->cnt) { + ndsShadows->curr = n->next; + ndsShadows->remainObjects--; + } + if (err==NSS_STATUS_NOTFOUND) {// user has no unix property, skip + trace (conf->debug, LOG_NOTICE,"user %s has not Unix properties in NDS,skipping",ndsName); + goto next_user; + } + else + err=NSS_STATUS_SUCCESS; + } + } +exit: + if (conf->debug) { + trace (conf->debug, LOG_NOTICE,"nss_ncp_getspent leaving"); + closelog(); + } + }else { + return NSS_STATUS_UNAVAIL; + } + return err; + +} + diff --git a/contrib/ncp_nss_lib/nss_ncp.h b/contrib/ncp_nss_lib/nss_ncp.h new file mode 100644 index 0000000..1d16e2e --- /dev/null +++ b/contrib/ncp_nss_lib/nss_ncp.h @@ -0,0 +1,175 @@ +/************************************************************************** + nss_ncp.h header for NSS for NDS + + Copyright (C) 2002 Patrick Pollet + + 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 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 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + + Revision history: + + 1.00 2003, January 06 Patrick Pollet + initial release + +************************************************************************/ +#ifndef HAVE_NSS_NCP_H +#define HAVE_NSS_NCP_H + +#define TRUE 1 +#define FALSE 0 + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + + + +// USE_DUMMY_ATTRibutes must be set in the Makefile +//#define USING_DUMMY_ATTRIBUTES + +#ifndef USING_DUMMY_ATTRIBUTES +// the real ones +#define ATTR_UID "UNIX:UID" +#define ATTR_PGNAME "UNIX:Primary GroupName" +#define ATTR_PGID "UNIX:Primary GroupID" +#define ATTR_GID "UNIX:GID" +#define ATTR_SHELL "UNIX:Login Shell" +#define ATTR_COM "UNIX:Comments" +#define ATTR_HOME "UNIX:Home Directory" +#else +// dummy attributes for testing +// created with Schemax with the same syntax +// and associated to user class and group class +#define ATTR_UID "LINUX:UID" +#define ATTR_PGNAME "LINUX:Primary GroupName" +#define ATTR_PGID "LINUX:Primary GroupID" +#define ATTR_GID "LINUX:GID" +#define ATTR_SHELL "LINUX:Login Shell" +#define ATTR_COM "LINUX:Comments" +#define ATTR_HOME "LINUX:Home Directory" +#endif + +// the attribute used to test presence of NDS8 +// either real or dummy (not used yet) +#define ATTR_NDS8 ATTR_UID + +// other attributes used +// absent NDS8 attributes are searched in L attribute +// also new properties ( Zenux Flags, Other group...) + +#define ATTR_CN "CN" +#define ATTR_LOCATION "L" + +#define ATTR_GRP_MBS "Group Membership" +#define ATTR_MEMBERS "Member" +#define ATTR_FULL_NAME "Full Name" + +#define ATTR_DATE_PWD_EXPIRE "Password Expiration Time" +#define ATTR_INT_PWD_EXPIRE "Password Expiration Interval" +#define ATTR_GRACE_LIMIT "Login Grace Limit" +#define ATTR_DATE_ACCT_EXPIRE "Login Expiration Time" + + +// the proper naming attribute may be customized here (must be a CI_STRING ) +#define ATTR_GECOS ATTR_FULL_NAME + +// syntaxes of the used attributes +#define SYN_CN SYN_CI_STRING +#define SYN_LOCATION SYN_CI_STRING +#define SYN_UID SYN_INTEGER +#define SYN_PGNAME SYN_DIST_NAME +#define SYN_PGID SYN_INTEGER +#define SYN_GID SYN_INTEGER +#define SYN_SHELL SYN_CE_STRING +#define SYN_COM SYN_CI_STRING +#define SYN_HOME SYN_CE_STRING +#define SYN_GRP_MBS SYN_DIST_NAME +#define SYN_MEMBERS SYN_DIST_NAME + + + +#define QF_DEBUG 0x0001 +#define QF_VERBOSE 0x0002 + +#define NFS_NOBODY = 65534 +#define CNF_FILE "/etc/nss_ncp.conf" + + + + +/******************************* NSS API ***************************************/ + + +enum nss_status _nss_ncp_initgroups (const char *userName, gid_t group, + long int *start, long int *size, gid_t * groups, + long int limit,int *errnop); + + +enum nss_status _nss_ncp_getpwnam_r (const char* name, struct passwd *pwd, + char * buffer, size_t buflen, int * errnop); + + + +enum nss_status _nss_ncp_getpwuid_r (uid_t uid, struct passwd *pwd, + char * buffer, size_t buflen, int * errnop); + + +enum nss_status _nss_ncp_getgrnam_r (const char* name, struct group *grp, + char * buffer, size_t buflen, int * errnop); + + + +enum nss_status _nss_ncp_getspnam_r (const char * name, struct spwd *spw, + char *buffer, size_t buflen,int * errnop); + + +enum nss_status _nss_ncp_getgrgid_r (gid_t gid, struct group *grp, + char * buffer, size_t buflen, int * errnop); + + + +enum nss_status _nss_ncp_setpwent(void); + +enum nss_status _nss_ncp_setgrent(void); + +enum nss_status _nss_ncp_setspent (void); + +enum nss_status _nss_ncp_endpwent(void); + +enum nss_status _nss_ncp_endgrent(void); + +enum nss_status _nss_ncp_endspent (void); + +enum nss_status _nss_ncp_getpwent_r(struct passwd *pwd, char * buffer, size_t buflen, int * errnop); + +enum nss_status _nss_ncp_getgrent_r(struct group *grp,char * buffer, size_t buflen, int * errnop); + + +enum nss_status _nss_ncp_getspent_r (struct spwd *spw,char * buffer, size_t buflen,int * errnop); + +#endif diff --git a/contrib/ncp_nss_lib/test_ncp_nss.c b/contrib/ncp_nss_lib/test_ncp_nss.c new file mode 100644 index 0000000..dfd0ba4 --- /dev/null +++ b/contrib/ncp_nss_lib/test_ncp_nss.c @@ -0,0 +1,318 @@ +/************************************************************************** + getpwduid.c:test program for NSS for NDS + + Copyright (C) 2002 Patrick Pollet + + 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 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 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + + Revision history: + + 1.00 2003, January 06 Patrick Pollet + initial release + 1.01 2003, January 08 Patrick Pollet + added conf structure and control group + added optional fallback UID and GID if none found in NDS (default is to skip user,group) + 1.02 2003, January 09 Patrick Pollet + added initgroups + 1.03 2003, January 10 Patrick Pollet + fixed bug in nds_user_info2 (bad structure received by nds_user_location2) + 1.04 2003, January 11 Patrick Pollet + fixed setting ndsXXX=NULL trees in case of errors in _nss_ncp_setxxent() + made always NAME_CONTEXT=[Root] in CreateContextAndConn + calling NWCCloseIteration only it some errors has occured in the search + 1.05 + modified to use nss_ncp.so +************************************************************************/ + + +#define TRUE 1 +#define FALSE 0 + +#include +#include +#include +#include + +#ifdef VERBOSE +#include +#endif +#include +#include +#include +#include + +#include "private/libintl.h" + +#include +#include +#include +#include + +#include + +#include "nss_ncp.h" +#include "nss_cfgfile.h" + + + +/**************** TESTING ******************/ + +static void print_passwd (struct passwd pwd){ + printf("%s:%s:%d:%d:%s:%s:%s\n",pwd.pw_name,pwd.pw_passwd,pwd.pw_uid,pwd.pw_gid,pwd.pw_gecos,pwd.pw_dir,pwd.pw_shell); +} + +static void print_group (struct group grp){ + char ** mmb; int num; + printf("%s:%s:%d:",grp.gr_name,grp.gr_passwd,grp.gr_gid); + for (mmb=grp.gr_mem,num=0;*mmb; mmb++,num++) { + if (num) + printf(","); + printf ("%s",*mmb); + + } + printf("\n"); + +} + +static void print_shadow (struct spwd spw){ + printf("%s:%s:%ld:%ld:%ld:%ld:%ld:%ld:%ld\n",spw.sp_namp,spw.sp_pwdp,spw.sp_lstchg,spw.sp_min,spw.sp_max,spw.sp_warn,spw.sp_inact,spw.sp_expire,spw.sp_flag); +} + + +static void print_user_groups(gid_t * groups, long int start, long int size){ + int i; + printf("start=%d size=%d\n",start,size); + for (i=0; i