Files
linamh/net-fs/ncpfs/files/ncpfs-hg-commit-448.patch
2026-04-20 09:42:39 +02:00

4137 lines
122 KiB
Diff
Raw Blame History

changeset: 448:1a8455ed3290
user: Patrick Pollet <patrick.pollet@cipcinsa.insa-lyon.fr>
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 <patrick.pollet@insa-lyon.fr>
+ Initial revision, stronly inspired by ncpfs/lib/cfgfile.c
+
+
+ */
+
+#include "config.h"
+
+
+#include "private/libncp-lock.h"
+
+
+#include <ctype.h>
+#include <stdio.h>
+#include <string.h>
+#include <strings.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <sys/syslog.h>
+
+#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 <patrick.pollet@insa-lyon.fr>
+ initial release
+ 1.01 2003, January 08 Patrick Pollet <patrick.pollet@insa-lyon.fr>
+ 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 <patrick.pollet@insa-lyon.fr>
+ added initgroups
+ 1.03 2003, January 10 Patrick Pollet <patrick.pollet@insa-lyon.fr>
+ fixed bug in nds_user_info2 (bad structure received by nds_user_location2)
+ 1.04 2003, January 11 Patrick Pollet <patrick.pollet@insa-lyon.fr>
+ 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 <patrick.pollet@insa-lyon.fr>
+ -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 <patrick.pollet@insa-lyon.fr>
+ -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 <patrick.pollet@insa-lyon.fr>
+ 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 <stdlib.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <errno.h>
+#include <ncp/nwnet.h>
+
+
+#include <unistd.h>
+#include <ctype.h>
+#include <wchar.h>
+#include <string.h>
+#include <pwd.h>
+#include <grp.h>
+#include <shadow.h>
+#include <sys/syslog.h>
+
+#include <nss.h>
+
+#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; i<ui.used; i++) {
+ gid_t gid=ui.groups[i];
+ if (gid != group) { // group number to skip
+ if (*start == *size)
+ if (limit <=0) { // no more space, realloc if permitted (limit <=0)
+ gid_t* ngroups=realloc(groups, 2* *size * sizeof(*groups));
+ if (!ngroups) {
+ goto outnomem;
+ }
+ groups=ngroups;
+ *size *=2;
+ }else // no reallocation permitted, leave returning found groups so far
+ break;
+ groups[*start]=gid;
+ *start +=1;
+ if (*start ==limit) {
+ break; // stop storing gids and return found groups so far
+ }
+ }
+ }
+ *errnop=0;
+ return NSS_STATUS_SUCCESS;
+outnomem:
+ traceForce(conf->debug,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 <ui.used;i++)
+ printf("%d ",ui.groups[i]);
+ printf("\n");
+}
+
+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<start; i++)
+ printf("%d ",groups[i]);
+ printf("\n");
+}
+
+
+/******************************************** generic NDS_Reading function ********************/
+// calllback function prototypes
+struct attrop {
+ const NWDSChar *attrname;
+ NWDSCCODE (*getval)(NWDSContextHandle, const void *val, void *arg);
+ enum SYNTAX synt;
+};
+
+
+static NWDSCCODE
+nds_read_attrs(NWDSContextHandle ctx, const NWDSChar * objname, void *arg, const struct attrop *atlist,int debugMode)
+{
+ Buf_T *attrlist;
+ Buf_T *info;
+ NWDSCCODE dserr;
+ const struct attrop *ptr;
+ nuint32 iterHandle;
+
+ dserr = NWDSAllocBuf(DEFAULT_MESSAGE_LEN, &attrlist);
+ if (dserr) {
+ traceForce(debugMode,LOG_WARNING, "NWDSAllocBuf() failed with %s\n", strnwerror(dserr));
+ goto bailout;
+ }
+ dserr = NWDSInitBuf(ctx, DSV_READ, attrlist);
+ if (dserr) {
+ traceForce(debugMode,LOG_WARNING, "NWDSInitBuf() failed with %s\n", strnwerror(dserr));
+ goto bailoutbuf1;
+ }
+ for (ptr = atlist; ptr->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;objCntr<objCount;objCntr++) {
+ // get an object name
+ ccode = NWDSGetObjectName(context,retBuf,objectName,&attrCount,&objectInfo);
+ if (ccode) {
+ traceForce(conf->debug,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 <patrick.pollet@insa-lyon.fr>
+ initial release
+
+************************************************************************/
+#ifndef HAVE_NSS_NCP_H
+#define HAVE_NSS_NCP_H
+
+#define TRUE 1
+#define FALSE 0
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <ncp/nwnet.h>
+
+#include <unistd.h>
+#include <ctype.h>
+#include <wchar.h>
+#include <string.h>
+
+#include <pwd.h>
+#include <grp.h>
+#include <shadow.h>
+#include <sys/syslog.h>
+
+#include <nss.h>
+
+
+
+// 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 <patrick.pollet@insa-lyon.fr>
+ initial release
+ 1.01 2003, January 08 Patrick Pollet <patrick.pollet@insa-lyon.fr>
+ 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 <patrick.pollet@insa-lyon.fr>
+ added initgroups
+ 1.03 2003, January 10 Patrick Pollet <patrick.pollet@insa-lyon.fr>
+ fixed bug in nds_user_info2 (bad structure received by nds_user_location2)
+ 1.04 2003, January 11 Patrick Pollet <patrick.pollet@insa-lyon.fr>
+ 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 <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <ncp/nwnet.h>
+
+#ifdef VERBOSE
+#include <ncp/ncplib.h>
+#endif
+#include <unistd.h>
+#include <ctype.h>
+#include <wchar.h>
+#include <string.h>
+
+#include "private/libintl.h"
+
+#include <pwd.h>
+#include <grp.h>
+#include <shadow.h>
+#include <sys/syslog.h>
+
+#include <nss.h>
+
+#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<start; i++)
+ printf("%d ",groups[i]);
+ printf("\n");
+}
+
+void give_details_on_user_groups(gid_t *groups, long int start){
+ struct group grp;
+ char buffer[65000];
+ long int i;
+ for (i=0; i<start;i++) {
+ enum nss_status err=_nss_ncp_getgrgid_r (groups[i],&grp,buffer,sizeof(buffer),&errno);
+ if (err==NSS_STATUS_SUCCESS)
+ print_group(grp);
+ else printf("nss result is %d for group %d\n",err,groups[i]);
+ }
+}
+
+#define _(X) gettext(X)
+
+static char *progname;
+
+static void usage(void)
+{
+ fprintf(stderr, _("usage: %s [options]\n"), progname);
+ exit (1);
+}
+
+static void help(void)
+{
+ printf(_("\n"
+ "usage: %s [options]\n"), progname);
+ printf(_("\n"
+ "-h Print this help text\n"
+ "-u id Unix User passwd info to search by uid in NDS\n"
+ "-n login Unix User passwd infos to search by name in NDS\n"
+ "-s login Unix User shadow infos to search by name in NDS\n"
+ "-i grpid Unix group to search by gid in NDS\n"
+ "-g grpname Unix group to search by name in NDS\n"
+ "-m login Get Unix groups of user login\n"
+ "-U all Unix users to search in NDS\n"
+ "-G all Unix groups to search in NDS\n"
+ "-S all Unix shadows to search in NDS\n"
+ "-D verbose mode (fill /var/log/secure && screen)\n"
+ "-T treeName use this Tree \n"
+ "-B serverName use this server\n"
+ "-C NDS ctx start in this context (default=[Root])\n"
+ "-O NDS group restrict user's search to this group\n"
+ "-f fallbackID if no UID,GID found in NDS use this one (default=-1 skip user & group)\n"
+ "-2 show the BUG (two calls )\n"
+ "\n"));
+ exit (1);
+}
+
+static void error ( char * s) {
+ printf (_("\n%s\n"),s);
+ exit (1);
+}
+
+/*************************************************************************
+** main
+*/
+int main (int argc, char** argv) {
+
+ const char* userName=NULL;
+ uid_t userId=-1;
+ const char* groupName=NULL;
+ gid_t groupId=-1;
+ const char* shadowName=NULL;
+ const char* memberName=NULL;
+ int opt;
+ int allUsers=0;
+ int allGroups=0;
+ int allShadows=0;
+ char buffer[65000];
+ int nbCalls=1;
+
+ struct passwd pwd;
+ struct group grp;
+ struct spwd spw;
+ enum nss_status err;
+
+ progname = argv[0];
+ while ((opt = getopt(argc, argv, "h?u:n:g:i:s:m:T:B:C:O:f:UGSD2")) != EOF)
+ {
+ switch (opt)
+ {
+ case 'n':
+ userName = optarg;
+ break;
+ case 'm':
+ memberName = optarg;
+ break;
+ case 's':
+ shadowName = optarg;
+ break;
+ case 'g':
+ groupName = optarg;
+ break;
+ case 'i':
+ groupId = strtoul(optarg, NULL, 0);
+ break;
+ case 'u':
+ userId = strtoul(optarg, NULL, 0);
+ break;
+ case 'U':
+ allUsers=1;
+ break;
+ case 'G':
+ allGroups=1;
+ break;
+ case 'S':
+ allShadows=1;
+ break;
+ case 'D':
+ defConf.debug=QF_DEBUG;
+ break;
+ case 'T':
+ defConf.server=optarg;
+ defConf.useTree=1;
+ break;
+ case 'B':
+ defConf.server=optarg;
+ defConf.useTree=0;
+ break;
+ case 'C':
+ defConf.startCtx=optarg;
+ break;
+ case 'O':
+ defConf.ctrlGroup=optarg;
+ break;
+ case 'f':
+ defConf.fallbackUid=strtoul(optarg, NULL, 0);
+ defConf.fallbackGid=strtoul(optarg, NULL, 0);
+ break;
+ case '2':
+ nbCalls=2;
+ break;
+ case 'h':
+ case '?':
+ help();
+
+ default:
+ usage();
+ }
+ }
+ if (defConf.debug)
+ openlog("ncp_nss", LOG_PID, LOG_AUTHPRIV);
+
+ while(nbCalls--) { // do it once or twice (freeze at the second !!!!)
+
+ if (userName) {
+ printf ("searching in passwd for login %s\n",userName);
+ if (_nss_ncp_getpwnam_r (userName,&pwd,buffer,sizeof(buffer),&errno)==NSS_STATUS_SUCCESS)
+ print_passwd(pwd);
+ }
+ if (memberName) {
+ #define MAX_GRP 30
+ gid_t groups[MAX_GRP];
+ long int start=0;
+ long int size=MAX_GRP;
+ printf ("searching groups of %s\n",memberName);
+ if ( _nss_ncp_initgroups (memberName, /*999 */ defConf.defGid,&start,&size,groups,0,&errno)==NSS_STATUS_SUCCESS) {
+ //long int *start, long int *size, gid_t * groups,long int limit,int *errnop) {
+ print_user_groups(groups,start,size);
+ give_details_on_user_groups(groups,start);// FREEZE AT THIS SECOND CALL to NWCCOpenConnByNAME !!!!
+ }
+
+ }
+ if (userId != -1) {
+ printf ("searching in passwd for uid %d\n",userId);
+ if ( _nss_ncp_getpwuid_r (userId, &pwd,buffer,sizeof(buffer),&errno)==NSS_STATUS_SUCCESS)
+ print_passwd(pwd);
+ }
+
+ if (allUsers) {
+ _nss_ncp_setpwent();
+
+ while ( _nss_ncp_getpwent_r(&pwd,buffer,sizeof(buffer),&errno)==NSS_STATUS_SUCCESS)
+ print_passwd(pwd);
+ _nss_ncp_endpwent();
+ }
+
+ if (groupName) {
+ printf ("searching in group for %s\n",groupName);
+ if (_nss_ncp_getgrnam_r (groupName,&grp,buffer,sizeof(buffer),&errno)==NSS_STATUS_SUCCESS) {
+ print_group(grp);
+ }
+ }
+
+ if (groupId != -1) {
+ printf ("searching in group for gid %d\n",groupId);
+ if ( _nss_ncp_getgrgid_r (groupId, &grp,buffer,sizeof(buffer),&errno)==NSS_STATUS_SUCCESS)
+ print_group(grp);
+ }
+
+ if (allGroups) {
+ _nss_ncp_setgrent();
+
+ while ( _nss_ncp_getgrent_r(&grp,buffer,sizeof(buffer),&errno)==NSS_STATUS_SUCCESS)
+ print_group(grp);
+ _nss_ncp_endgrent();
+ }
+
+ if (shadowName) {
+ printf ("searching in shadow for login %s\n",shadowName);
+ if (_nss_ncp_getspnam_r (shadowName,&spw,buffer,sizeof(buffer),&errno)==NSS_STATUS_SUCCESS)
+ print_shadow(spw);
+ }
+
+ if (allShadows) {
+ _nss_ncp_setspent();
+ while ( _nss_ncp_getspent_r(&spw,buffer,sizeof(buffer),&errno)==NSS_STATUS_SUCCESS)
+ print_shadow(spw);
+ _nss_ncp_endspent();
+ }
+ }
+
+ if (defConf.debug)
+ closelog();
+ exit(0);
+}