3078 lines
90 KiB
C
3078 lines
90 KiB
C
/**************************************************************************
|
||
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)
|
||
static 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:%ld:%ld:%ld:%ld:%ld:%ld:%ld\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) {
|
||
size_t 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){
|
||
size_t i;
|
||
|
||
printf("%s:%d:%zd:%zd:",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){
|
||
long int i;
|
||
printf("start=%ld size=%ld\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;
|
||
int n;
|
||
|
||
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;
|
||
int n;
|
||
|
||
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;
|
||
int n;
|
||
|
||
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 [%zd]\n",n->name,n->cnt);
|
||
else
|
||
printf ("%s [%zd]",n->name,n->cnt);
|
||
print_nodes(n->right,crlf);
|
||
}
|
||
}
|
||
|
||
static void print_tree(struct ObjectList* t, int crlf) {
|
||
printf("total:%zd unique:%zd\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 }};
|
||
|
||
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 {
|
||
const char * className;
|
||
const char * nds8Attribute; // name of ID attribute in NDS8
|
||
const char * LID1; // markers in L attribute for ID (U: or G:)
|
||
const char * LID2; // markers in L attribute for ID (u: or g:), may be in lower case
|
||
const char * LAlias1; // markers in L attribute for alias (N:)
|
||
const 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;
|
||
nuint32 iterationHandle = NO_MORE_ITERATIONS; // to be set as such at Exit4
|
||
nuint32 countObjectsSearched;
|
||
nuint32 objCntr;
|
||
nuint32 objCount;
|
||
nuint32 attrCount;
|
||
char objectName[MAX_DN_CHARS+1];
|
||
|
||
// 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 (iterationHandle != NO_MORE_ITERATIONS);
|
||
|
||
trace(conf->debug, LOG_NOTICE,"End of iteration attrNamesOK");
|
||
|
||
Exit4:
|
||
if (iterationHandle != NO_MORE_ITERATIONS){
|
||
NWDSCCODE ccode2;
|
||
if ((ccode2=NWDSCloseIteration(context,iterationHandle,DSV_SEARCH)) != 0) {
|
||
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;
|
||
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;
|
||
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();
|
||
|
||
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();
|
||
|
||
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();
|
||
|
||
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();
|
||
|
||
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();
|
||
|
||
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();
|
||
|
||
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();
|
||
|
||
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();
|
||
|
||
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();
|
||
|
||
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;
|
||
|
||
}
|
||
|