Files
ncpfs/lib/nwclient.c
2026-04-28 20:56:05 +02:00

1817 lines
54 KiB
C

/*
nwclient.c - Client oriented calls
Copyright (C) 2001 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 2001, Feb 18 Patrick Pollet
Initial release.
1.01 2001, March 9 Patrick Pollet
Removed NWDSScanConnsForTrees.Is now in nwnet.c
Corrected NWCXGetPermConnInfo(NWCC_INFO_AUTHENT_STATE).
Corrected NWCXSplitNameAndContext (had no return values)
1.02 2001, March 12 Patrick Pollet
#131:Corrected NWCXIsDSAuthenticated ( return 0 if not dxh) and not -1
#137:__NWCXGetPermConnList made static ( now internal only ?)
#341: added tests for null pointers in NWCXAttachToTreeByName,NWCXGetDefault*
#389: better error code NWE_BIND_NO_SUCH_PROP
NWCXGetNDSVolumeServerAndResourceName now allows null pointers for serverName/resourceName
1.03 2001, March 16 Patrick Pollet
#284 (NWDSCreateContextHandleMnt): added missing NWDSFreeContext
Rewrote the attribute reading part
Added NWCXGetIntAttributeValues, NWCXGetStringAttributeValues,
NWCXGetMultiStringAttributeValues, NWCXGetAttributeValuesAsString,
Added reading the ~/.nwinfos file to fetch default tree, ctx, user if none in environnment
Added NWCXGetDefaultServer call to NWCXAttachToTreeByName()
1.04 2001, May 31 Petr Vandrovec <vandrove@vc.cvut.cz>
Add include strings.h, use ncpt_atomic_*, not atomic_*,
use size_t for size...
1.05 2001, July 15 Petr Vandrovec <vandrove@vc.cvut.cz>
Fixed NWCXSplitNameAndContext to honor ctx's settings.
1.06 2001, October 21 Patrick.Pollet@insa-lyon.fr
Fixed NWCXSplitNameAndContext to allow NULL name or context .
Mofified NWCXAttachToTreeByName() to use the new NWCCOpenConnByname((,,NWCC_NAME_FORMAT_NDS_TREE,...)
1.07 2001, December 7 Patrick.Pollet@insa-lyon.fr
Reverted NWCXAttachToTreeByName() to use the old code since (see #define USE_OLD_CODE)
new NWCCOpenConnByname((,,NWCC_NAME_FORMAT_NDS_TREE,...) is sometimes capricious
1.08 2002, January 20 Petr Vandrovec <vandrove@vc.cvut.cz>
Moved NWCC_INFO_MOUNT_POINT code from here to nwcalls.c.
Compile portions need by ncpumount even when NDS_SUPPORT is disabled.
1.09 2002, January 25 Patrick.Pollet@insa-lyon.fr
Implemented LoginScript reading API calls
Removed NWDSAbbreviateName in __docopy_string when retrieving a SYN_DIST_NAME
*/
#include "config.h"
#include <string.h>
#include <strings.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <sys/mman.h>
#include <ncp/nwcalls.h>
#include <ncp/nwnet.h>
#include <ncp/nwclient.h>
#include "nwnet_i.h"
#ifdef NCP_KERNEL_NCPFS_AVAILABLE
#include <mntent.h>
#endif
#include <pwd.h>
#include <sys/stat.h>
#ifndef ENOPKG
#define ENOPKG ENOSYS
#endif
/*should be in ndslib.h ?*/
#define NWE_BIND_NO_SUCH_PROP NWE_NCP_NOT_SUPPORTED
#undef DEBUG_PRINT
#if 1
/*read hard degugging*/
void printConn (NWCONN_HANDLE conn, int stage);
void printConn (NWCONN_HANDLE conn, int stage) {
printf("%s\n",conn->mount_point);
printf ("------ info from kernel--------------------------------\n");
printf ("infoV2.version %d\n",conn->i.version);
printf ("infoV2.mounted_uid %lu\n",conn->i.mounted_uid);
printf ("infoV2.connection %d\n",conn->i.connection);
printf ("infoV2.buffer_size %d\n",conn->i.buffer_size);
printf ("infoV2.volume_number %d\n",conn->i.volume_number);
printf ("infoV2.directory_id %d\n",conn->i.directory_id);
printf ("infoV2.dummy1 %d\n",conn->i.dummy1);
printf ("infoV2.dummy2 %d\n",conn->i.dummy2);
printf ("infoV2.dummy3 %d\n",conn->i.dummy3);
printf ("------ info from ncplib (recreated stage %d) ---------\n",stage);
printf ("is_connected %d\n",conn->is_connected);
printf ("nds_conn %p\n",conn->nds_conn);
printf ("nds_ring %p/%p\n",conn->nds_ring.prev, conn->nds_ring.next);
printf ("user %s\n",conn->user);
printf ("user_id_is_valid %d\n",conn->user_id_valid);
printf ("user_id %x\n",conn->user_id);
printf ("mount_fid %d\n",conn->mount_fid);
printf ("mount_point %s\n",conn->mount_point);
printf ("ncpt_atomic_t store_count %d\n",ncpt_atomic_read(&conn->store_count));
printf ("state %d\n",conn->state);
printf ("connstate %x\n", conn->connState);
printf ("sign_wanted %x\n", ncp_get_sign_wanted(conn));
printf ("sign_active %x\n", ncp_get_sign_active(conn));
printf ("serverInfo.valid %x\n",conn->serverInfo.valid);
printf ("serverInfo.serverName %s\n",conn->serverInfo.serverName);
printf ("serverInfo.version.major %x\n",conn->serverInfo.version.major);
printf ("serverInfo.version.minor %x\n",conn->serverInfo.version.minor);
printf ("serverInfo.version.revision %x\n",conn->serverInfo.version.revision);
printf ("NET_ADDRESS_TYPE nt %x\n",conn->nt);
}
#endif
static int NWCIsPermanentConnection (NWCONN_HANDLE conn) {
return (ncp_get_conn_type(conn) == NCP_CONN_PERMANENT);
}
NWCCODE NWCXGetPermConnInfo(NWCONN_HANDLE conn, nuint info, size_t len, void* buffer) {
if (!buffer) /*just in case*/
return ERR_NULL_POINTER;
if (!NWCIsPermanentConnection(conn))
return NWE_REQUESTER_FAILURE;
switch (info) {
case NWCC_INFO_AUTHENT_STATE:
{ /* must be authenticated since it is permanently mounted ? */
#ifdef NDS_SUPPORT
if (NWIsDSServer(conn,NULL))
return ncp_put_req_size_unsigned(buffer, len, NWCC_AUTHENT_STATE_NDS);
else
#endif
return ncp_put_req_size_unsigned(buffer, len, NWCC_AUTHENT_STATE_BIND);
}
default:
return NWCCGetConnInfo(conn,info,len,buffer);
}
}
#ifdef NDS_SUPPORT
int NWCXIsDSServer ( NWCONN_HANDLE conn, NWDSChar * treeName) {
/* same as API return 1 if OK but removes the trailings '_____'*/
if (!treeName)
return NWIsDSServer(conn,NULL);
if (NWIsDSServer(conn,treeName)) {
char *p;
p = strchr(treeName, '\0') - 1;
while ((p >= treeName) && (*p == '_'))
p--;
treeName[ p - treeName + 1] = 0;
return 1;
}
else {
treeName[0]=0;
return 0;
}
}
int NWCXIsSameTree (NWCONN_HANDLE conn, const NWDSChar *treeName) {
/* return 1 if OK */
char treeName2[MAX_TREE_NAME_CHARS+1]="";
if (NWCXIsDSServer(conn,treeName2)) {
if (!treeName)
return 0;
return (!strcasecmp(treeName,treeName2));
}
else return 0;
}
#endif
int NWCXIsSameServer(NWCONN_HANDLE conn, const NWDSChar* server) {
/* return 1 if OK */
char server2[NCP_BINDERY_NAME_LEN + 1];
NWCCODE err;
if (!server) {
return 0;
}
err = NWCCGetConnInfo(conn, NWCC_INFO_SERVER_NAME, sizeof(server2), server2);
if (err) {
return 0;
}
return !strcasecmp(server,server2);
}
#ifdef NDS_SUPPORT
NWDSCCODE NWCXIsDSAuthenticated(NWDSContextHandle ctx){
/* return non zero if a context has authentication keys*/
NWDS_HANDLE dxh;
dxh=ctx->ds_connection;
if (! dxh) /* should not be ???*/
return 0;
return
(dxh->authinfo!=NULL);
}
#endif
static
NWCCODE __NWCXGetPermConnList (NWCONN_HANDLE* conns , int maxEntries, int* curEntries,
uid_t uid,const NWDSChar* treeName, const NWDSChar* serverName){
/* returns the list of permanent connexions belonging to user uid*/
/* if uid=-1 = all Permanent connections (Root only) */
/* if treeName !=NUll only them */
/*if serverName !=NULL only them*/
#ifdef NCP_KERNEL_NCPFS_AVAILABLE
FILE* mtab;
NWCONN_HANDLE conn;
struct mntent* mnt_ent;
#if 0
char aux[256];
/* char aux2[256];*/
char* user;
#endif
uid_t callerUid=getuid();
int alluid = 0;
*curEntries=0;
if ((uid == (uid_t)-1)) {
/*only root can scan all connections*/
if (callerUid != 0) {
return EACCES;
}
alluid = 1;
} else if (uid != callerUid) {
/*only root can scan other user connections*/
if (callerUid != 0) {
return EACCES;
}
}
#ifdef NDS_SUPPORT
if (treeName && serverName) { /*should never happen on this internal function ? */
return NWE_REQUESTER_FAILURE;
}
#else
if (treeName) {
return ENOPKG;
}
#endif
if ((mtab = fopen(MOUNTED, "r")) == NULL) {
return errno;
}
while ((*curEntries <maxEntries)&&(mnt_ent = getmntent(mtab))) {
/* printf("%s %s %s\n ",mnt_ent->mnt_type,mnt_ent->mnt_fsname,mnt_ent->mnt_dir);*/
if (strcmp(mnt_ent->mnt_type, "ncpfs") != 0) {
continue;
}
#if 0
/*printf("%s %s %s\n ",mnt_ent->mnt_type,mnt_ent->mnt_fsname,mnt_ent->mnt_dir);*/
if (strlen(mnt_ent->mnt_fsname) >= sizeof(aux)) {
continue;
}
strcpy(aux, mnt_ent->mnt_fsname);
user = strchr(aux, '/');
if (!user) {
continue;
}
*user++ = '\0';
/* strcpy(aux2, mnt_ent->mnt_dir);
printf("-->%s %s %s\n ",aux,user,aux2);*/
#endif
if (ncp_open_mount(mnt_ent->mnt_dir, &conn)) {
/* printf("failed%s\n","");*/
continue;
}
if (alluid || (conn->i.mounted_uid == uid)) {
int addit;
#ifdef NDS_SUPPORT
if (treeName)
addit = NWCXIsSameTree(conn, treeName);
else
#endif
if (serverName)
addit = NWCXIsSameServer(conn, serverName);
else
addit = 1;
if (addit) {
*conns++ = conn;
(*curEntries)++;
/* printf("OK %d\n",*curEntries);*/
} else {
NWCCCloseConn(conn); /*free memory only */
}
} else {
NWCCCloseConn(conn); /*free memory only */
}
}
fclose(mtab);
return 0;
#else
return ENOPKG;
#endif /* NCP_KERNEL_NCPFS_AVAILABLE */
}
NWCCODE NWCXGetPermConnList (NWCONN_HANDLE* conns , int maxEntries, int* curEntries, uid_t uid){
/* returns the list of permanent connexions belonging to user uid*/
/* if uid=-1 = all Permanent connections (Root only) */
return __NWCXGetPermConnList (conns,maxEntries,curEntries,uid,NULL,NULL);
}
NWCCODE NWCXGetPermConnListByTreeName (NWCONN_HANDLE* conns, int maxEntries,
int* curEntries, uid_t uid,
const NWDSChar *treeName){
return __NWCXGetPermConnList (conns,maxEntries,curEntries,uid,treeName,NULL);
}
NWCCODE NWCXGetPermConnListByServerName (NWCONN_HANDLE* conns , int maxEntries,
int* curEntries, uid_t uid,
const NWDSChar *serverName){
return __NWCXGetPermConnList (conns,maxEntries,curEntries,uid,NULL,serverName);
}
#ifdef NDS_SUPPORT
NWDSCCODE NWDSSetContextHandleTree(NWDSContextHandle ctx, const NWDSChar * treeName)
{
#define MAXCONNS 64
NWDSCCODE err;
NWCONN_HANDLE conns[MAXCONNS];
int curEntries;
int i;
wchar_t treeNameW[MAX_DN_CHARS+1];
char treeNameUTF[MAX_DN_CHARS*4 + 1];
if (!treeName)
return ERR_NULL_POINTER;
err = NWDSXlateFromCtx(ctx, treeNameW, sizeof(treeNameW), treeName);
if (err)
return err;
err = iconv_wchar_t_to_external(treeNameW, treeNameUTF, sizeof(treeNameUTF));
if (err)
return err;
err = NWDSSetTreeNameW(ctx, treeNameW);
if (err) {
return err;
}
err = NWCXGetPermConnListByTreeName(conns, MAXCONNS, &curEntries, getuid(), treeNameUTF);
if (err) {
return err;
}
for (i = 0; i < curEntries; i++) {
NWCONN_HANDLE conn = conns[i];
err = NWDSAddConnection(ctx, conn);
if (err) {
NWCCCloseConn(conn);
continue;
}
}
return 0;
}
NWDSCCODE NWDSCreateContextHandleMnt(NWDSContextHandle* pctx, const NWDSChar * treeName)
{
NWDSCCODE err;
NWDSContextHandle ctx;
if (!pctx) {
return ERR_NULL_POINTER;
}
err = NWDSCreateContextHandle(&ctx);
if (err)
return err;
err = NWDSSetContextHandleTree(ctx, treeName);
if (err)
NWDSFreeContext(ctx);
else
*pctx = ctx;
return err;
}
//#define NOENV 1 <-- testing reading of .nwinfos file
#undef NOENV
#define NWINFOS ".nwinfos"
/**********************************************/
#define NDS_USER "NDS_USER"
#define NDS_GECOS "NDS_GECOS"
#define NDS_SHELL "NDS_SHELL"
#define NDS_HOME "NDS_HOME"
#define NDS_UID "NDS_UID"
#define NDS_GID "NDS_GID"
#define NDS_HOME_SERVER "NDS_HOME_SERVER"
#define NDS_HOME_VOLUME "NDS_HOME_VOLUME"
#define NDS_HOME_PATH "NDS_HOME_PATH"
#define NDS_HOME_MNT_PNT "NDS_HOME_MNT_PNT"
#define NDS_EMAIL "NDS_EMAIL"
#define NDS_PREFERRED_SERVER "NDS_PREFERRED_SERVER"
#define NDS_PREFERRED_TREE "NDS_PREFERRED_TREE"
#define NDS_PREFERRED_NAME_CTX "NDS_PREFERRED_NAME_CTX"
/***********************************************/
static char* readnwinfosfile (char * user, const char * info, const char * forTree, long * err) {
/* strongly inspired from ncplib.c: ncp_fopen_nwc and ncp_get_nwc_ent
user (=NULL) current user
info : variable name we are looking for
if forTree= NULL any tree will do
else forTree must be equals to NWCLIENT_PREFERRED_TREE=xxxx
stored in ~/.nwinfos file */
FILE *f;
static char value[1024]=""; /*static value of matching line*/
char concernTree[1024]=""; /*tree read from ~/.nwinfos file */
char line[1024]="";
char path[1024]="";
char * home=NULL;
char *p;
int line_len;
struct stat st;
if (!user) {
home = getenv("HOME");
} else {
struct passwd *pwd;
if ((pwd = getpwnam(user)) != NULL) {
home = pwd->pw_dir;
}
}
if ((home == NULL)
|| (strlen(home) + sizeof(NWINFOS) + 2 > sizeof(path))) {
*err = ENAMETOOLONG;
return NULL;
}
strcpy(path, home);
strcat(path, "/");
strcat(path, NWINFOS);
#ifdef NOENV
printf ("searching %s\n",path);
#endif
if (stat(path, &st) != 0) {
*err = errno;
return NULL;
}
if (st.st_uid != getuid()) {
*err = EACCES;
return NULL;
}
if (st.st_uid != getuid()) {
*err = EACCES;
return NULL;
}
if ((st.st_mode & (S_IRWXO | S_IRWXG)) != 0) {
*err = NCPLIB_INVALID_MODE;
return NULL;
}
f=fopen(path, "r");
if (!f) {
*err=errno;
return NULL;
}
value[0]=0; /*reset statics */
concernTree[0]=0;
while (fgets(line, sizeof(line), f) != NULL) {
if ((line[0] == '\n')|| (line[0] == '#'))
continue;
line_len = strlen(line);
if (line[line_len - 1] == '\n') {
line[line_len - 1] = '\0';
}
p=strchr(line,'=');
if (!p)
continue;
*p=0;
if (!strcasecmp(line,info)) {
strcpy(value,p+1);
#ifdef NOENV
printf ("found required info %s=%s\n",info,value);
#endif
}
if (!strcasecmp(line,NDS_PREFERRED_TREE)) {
strcpy(concernTree,p+1);
#ifdef NOENV
printf ("this file concerns tree %s\n",concernTree);
#endif
}
if (value[0] && concernTree[0])
break; /* got both */
}
fclose(f);
#ifdef NOENV
printf ("found for tree %s :pref_tree = %s required info %s=%s\n",
forTree,concernTree,info,value);
#endif
if (!value[0]) return NULL; /* not found */
if (!forTree) return value; /* Ok for any tree */
return strcasecmp(forTree,concernTree)? NULL:value;
}
/* we are using the same env names as the Caldera client (hope they won't mind)
#define PREFER_TREE_ENV "NWCLIENT_PREFERRED_TREE"
#define PREFER_CTX_ENV "NWCLIENT_DEFAULT_NAME_CONTEXT"
#define PREFER_SRV_ENV "NWCLIENT_PREFERRED_SERVER"
#define PREFER_USER_ENV "NWCLIENT_DEFAULT_USER"
this one is an extra by PP for a possible autologon
#define PREFER_PWD_ENV "NWCLIENT_DEFAULT_PASSWORD"
*/
NWDSCCODE NWCXGetPreferredDSTree (NWDSChar * preferTree, size_t maxLen){
char * res=NULL;
long err;
if (!preferTree)
return ERR_NULL_POINTER;
#ifndef NOENV
res =getenv (PREFER_TREE_ENV);
#endif
if (!res)
res=readnwinfosfile (NULL,NDS_PREFERRED_TREE,NULL, &err);
if (!res)
return err;
if (strlen (res)+1 >maxLen)
return NWE_BUFFER_OVERFLOW;
strcpy(preferTree,res);
return 0;
}
NWDSCCODE NWCXGetDefaultNameContext (const NWDSChar* forTree,
NWDSChar * nameContext, size_t maxLen){
char * res=NULL;
long err;
if (!nameContext)
return ERR_NULL_POINTER;
#ifndef NOENV
res =getenv (PREFER_CTX_ENV);
#endif
if (!res)
res=readnwinfosfile (NULL,NDS_PREFERRED_NAME_CTX,forTree,&err);
if (!res)
return err;
if (strlen (res)+1 >maxLen)
return NWE_BUFFER_OVERFLOW;
strcpy(nameContext,res);
return 0;
}
NWDSCCODE NWCXGetPreferredServer (const NWDSChar * forTree,
NWDSChar *preferedServer, size_t maxLen){
char * res=NULL;
if (!preferedServer)
return ERR_NULL_POINTER;
#ifndef NOENV
res = getenv(PREFER_SRV_ENV);
#endif
if (!res) {
long err;
res=readnwinfosfile (NULL, NDS_PREFERRED_SERVER, forTree, &err);
if (!res) {
return err;
}
}
/* test that this server DO belongs to tree forTree*/
/* NULL means any tree or even bindery (?)*/
if (forTree) {
NWCONN_HANDLE conn;
NWCCODE err;
err = NWCCOpenConnByName(NULL, res, NWCC_NAME_FORMAT_BIND, 0, NWCC_RESERVED, &conn);
if (err) {
return -1; /* better code for not available ? */
}
err = !NWCXIsSameTree(conn, forTree);
NWCCCloseConn(conn);
if (err) {
return -1; /* not same tree ignore it */
}
}
if (strlen(res) + 1 > maxLen) {
return NWE_BUFFER_OVERFLOW;
}
strcpy(preferedServer, res);
return 0;
}
NWDSCCODE NWCXGetDefaultUserName (const NWDSChar * forTree,
NWDSChar *defaultName, size_t maxLen){
/*may be we should return current user's Unix name if nothing found in env ? */
char * res=NULL;
long err;
if (!defaultName)
return ERR_NULL_POINTER;
#ifndef NOENV
res =getenv (PREFER_USER_ENV);
#endif
if (!res)
res=readnwinfosfile (NULL,NDS_USER,forTree, &err);
if (!res)
return err;
if (strlen (res)+1 >maxLen)
return NWE_BUFFER_OVERFLOW;
strcpy(defaultName,res);
return 0;
}
NWDSCCODE NWCXGetDefaultPassword (const NWDSChar * forTree,
NWDSChar *defaultPWD, size_t maxLen){
char * res=NULL;
if (!defaultPWD)
return ERR_NULL_POINTER;
(void) forTree; /* not yet used */
res =getenv (PREFER_PWD_ENV);
if (!res)
return -1;
if (strlen (res)+1 >maxLen)
return NWE_BUFFER_OVERFLOW;
strcpy(defaultPWD,res);
return 0;
}
#define USE_OLD_CODE
NWDSCCODE NWCXAttachToTreeByName( NWCONN_HANDLE* conn, const NWDSChar * treeName){
#ifdef USE_OLD_CODE
struct ncp_conn *connInit;
struct ncp_bindery_object obj;
long err;
char prefered_server[MAX_DN_BYTES+1];
if (!conn || !treeName)
return ERR_NULL_POINTER;
/* NULL nearest server ????*/
if ((connInit = ncp_open(NULL, &err)) == NULL){
return err;
}
#if 0
printf ("searching for default server in tree %s\n",treeName);
#endif
/* see if there is a default server in env */
err=NWCXGetPreferredServer(treeName,prefered_server,sizeof(prefered_server));
if (!err) {
#if 0
printf ("found default server %s\n",prefered_server);
#endif
err=NWCCOpenConnByName(connInit,prefered_server,NWCC_NAME_FORMAT_BIND,
0, NWCC_RESERVED,conn);
/*we already checked in NWCXGetPreferredServer that server belongs to the target tree */
if (!err) {
#if 0
printf ("OK on server %s\n",prefered_server);
printConn (*conn,1);
#endif
NWCCCloseConn(connInit);
return 0;
}
}
/* try to speed up search of all servers but first checking that treeName exists */
{
nint32 scanIndex=-1;
char myTreeName [MAX_DN_CHARS+1];
NWDSContextHandle ctx;
int found=0;
err= NWDSCreateContextHandle (&ctx);
if (err)
return err;
while (!found && (err=NWDSScanForAvailableTrees(ctx,connInit,"*",&scanIndex,myTreeName)==0)){
/*printf (" comparing %s and %s \n",treeName,myTreeName);*/
found=!strcasecmp(treeName,myTreeName);
}
NWDSFreeContext(ctx);
/*printf ("found=%d\n",err);*/
if (!found) /* 0x89FC*/
{
NWCCCloseConn(connInit);
return NWE_BIND_NO_SUCH_PROP;
}
}
obj.object_id = 0xffffffff;
err=NWE_BIND_NO_SUCH_PROP;
while (ncp_scan_bindery_object(connInit, obj.object_id,
NCP_BINDERY_FSERVER, "*",
&obj) == 0){
// do not ask AXIS CD ROM TOWERS they are bugged in opening conns !!!!
/*printf ("trying server %s\n",obj.object_name);*/
if (!strncmp ("AXIS",obj.object_name,4)) {
continue;
}
err=NWCCOpenConnByName(connInit,obj.object_name,NWCC_NAME_FORMAT_BIND,
0, NWCC_RESERVED,conn);
if (err)
continue;
if (NWCXIsSameTree (*conn,treeName))
break; /* gotcha*/
NWCCCloseConn(*conn);
err=NWE_BIND_NO_SUCH_PROP;
}
NWCCCloseConn(connInit);
return err;
#else
/* much shorter !!! but does not always works , when nearest server does not belong to the target tree*/
/* we get a Server unknown error 0x89FC */
/* printf ("using new code\n");*/
return NWCCOpenConnByName(NULL, treeName, NWCC_NAME_FORMAT_NDS_TREE,
NWCC_OPEN_NEW_CONN,
NWCC_RESERVED, conn);
#endif
}
NWDSCCODE NWCXSplitNameAndContext (NWDSContextHandle ctx, const NWDSChar * dn,
NWDSChar * name, NWDSChar* context) {
NWDSCCODE err;
wchar_t wdn[MAX_DN_CHARS + 1];
wchar_t* cptr;
wchar_t* wctx;
err = NWDSXlateFromCtx(ctx, wdn, sizeof(wdn), dn);
if (err) {
return err;
}
cptr = wdn;
while (*cptr && *cptr != L'.') {
if (*cptr == L'\\') {
if (!*++cptr) {
return ERR_INVALID_OBJECT_NAME;
}
}
cptr++;
}
if (*cptr) {
wctx = cptr + 1;
*cptr = 0;
} else {
wctx = cptr;
}
if (name) {
err = NWDSXlateToCtx(ctx, name, MAX_DN_BYTES, wdn, NULL);
if (err) {
return err;
}
}
if (context) {
err = NWDSXlateToCtx(ctx, context, MAX_DN_BYTES, wctx, NULL);
if (err) {
return err;
}
}
return 0;
}
/* internal only !!!!
called with "real buffer" for single valued
or a temp buffer for with multivalued attributes
we process attributes with variable size (CI_LIST, CI_OCTET..
and return them as strings with comma separators
attributes with fields are emitted on a single line with "," as separator*/
static NWDSCCODE __docopy_string (UNUSED(NWDSContextHandle ctx), const void* val,
const enum SYNTAX synt, size_t currentSize,
char* result, size_t maxSize){
int l;
#ifdef DEBUG_PRINT
printf ("__docopy_string got :%s synt = %d cursize=%d maxsize= %d\n",(char *)val,synt,currentSize,maxSize );
#endif
if (currentSize > maxSize) return NWE_BUFFER_OVERFLOW;
if (!result) return ERR_NULL_POINTER;
switch (synt) {
case SYN_DIST_NAME:
case SYN_CI_STRING:
case SYN_CE_STRING:
case SYN_PR_STRING:
case SYN_NU_STRING:
case SYN_TEL_NUMBER:
case SYN_CLASS_NAME:
l = snprintf(result, maxSize, "%s", (const char *)val);
break;
case SYN_PATH:{
const Path_T* p = (const Path_T*)val;
l = snprintf(result, maxSize, "%u,%s,%s", p->nameSpaceType, p->volumeName, p->path);
}
break;
case SYN_TYPED_NAME:{
const Typed_Name_T* tn = (const Typed_Name_T*)val;
l = snprintf(result, maxSize, "%u,%u,%s", tn->interval, tn->level, tn->objectName);
}
break;
case SYN_FAX_NUMBER:{
const Fax_Number_T* fn = (const Fax_Number_T*)val;
l = snprintf(result, maxSize, "%s,%zu", fn->telephoneNumber, fn->parameters.numOfBits);
}
break;
case SYN_EMAIL_ADDRESS:{
const EMail_Address_T* ea = (const EMail_Address_T*)val;
/*change the SMTP:aaa@bbbb to SMTP,aaa@bbbb */
char* p=strchr(ea->address,':');
if (p) *p=',';
l = snprintf(result, maxSize, "%u,%s", ea->type, ea->address);
}
break;
case SYN_PO_ADDRESS:{
const NWDSChar* const* pa = (const NWDSChar* const*)val;
l = snprintf(result, maxSize, "%s,%s,%s,%s,%s,%s", pa[0], pa[1], pa[2], pa[3], pa[4], pa[5]);
}
break;
case SYN_HOLD:{
const Hold_T* h = (const Hold_T*)val;
l = snprintf(result, maxSize, "%u,%s", h->amount, h->objectName);
}
break;
case SYN_TIMESTAMP:{
const TimeStamp_T* stamp = (const TimeStamp_T*)val;
l = snprintf(result, maxSize, "%u,%u,%u", stamp->wholeSeconds, stamp->replicaNum, stamp->eventID);
}
break;
case SYN_BACK_LINK:{
const Back_Link_T* bl = (const Back_Link_T*)val;
l = snprintf(result, maxSize, "%08X,%s", bl->remoteID, bl->objectName);
}
break;
case SYN_CI_LIST:{
const CI_List_T* ol = (const CI_List_T*)val;
const CI_List_T* p;
size_t len=1;
char *aux=result;
for(p=ol;p;p=p->next) {
len=+strlen(p->s)+1;
}
if (len >=maxSize)
return NWE_BUFFER_OVERFLOW;
if (len==1) {
result[0]=0;
return 0;
}
for (p=ol;p;p=p->next) {
len=strlen(p->s);
memcpy(aux,p->s,len);
aux+=len;
*(aux++)=',';
}
*(--aux)=0;
}
return 0;
case SYN_OCTET_LIST:{
const Octet_List_T* ol = (const Octet_List_T*)val;
size_t i;
char *aux;
if (20 + (ol->length+1)*3+1 >=maxSize)
return NWE_BUFFER_OVERFLOW;
sprintf(result, "%zu", ol->length);
aux = result + strlen(result);
for (i = 0; i < ol->length; i++) {
sprintf(aux, ",%02X", ol->data[i]);
aux += 3;
}
}
return 0;
case SYN_OCTET_STRING:{
const Octet_String_T* os = (const Octet_String_T*)val;
size_t i;
char *aux;
#ifdef DEBUG_PRINT
printf ("len %d\n",os->length);
#endif
if (20 + (os->length+1)*3+1 >=maxSize)
return NWE_BUFFER_OVERFLOW;
sprintf(result, "%zu", os->length);
aux = result + strlen(result);
for (i = 0; i < os->length; i++) {
sprintf(aux, ",%02X", os->data[i]);
aux += 3;
}
}
return 0;
case SYN_NET_ADDRESS:{
const Net_Address_T* na = (const Net_Address_T*)val;
size_t z;
char *aux;
z=na->addressLength;
if (40 + 3*(z+2)+1 >=maxSize)
return NWE_BUFFER_OVERFLOW;
sprintf(result, "%u,%zu", na->addressType, na->addressLength);
aux = result + strlen(result);
for (z = 0; z < na->addressLength; z++) {
sprintf(aux, ",%02X", na->address[z]);
aux += 3;
}
}
return 0;
case SYN_OBJECT_ACL:{
const Object_ACL_T* oacl = (const Object_ACL_T*)val;
l = snprintf(result, maxSize, "%s,%s,%08X", oacl->protectedAttrName, oacl->subjectName, oacl->privileges);
}
break;
default:
return EINVAL;
}
if (l < 0 || (size_t)l >= maxSize) {
return NWE_BUFFER_OVERFLOW;
}
return 0;
}
static
NWDSCCODE docopy_string(NWDSContextHandle ctx, const void * val, const enum SYNTAX synt, size_t currentSize,
void * result, size_t maxSize){
return __docopy_string(ctx, val, synt, currentSize, (char*)result, maxSize);
}
static
NWDSCCODE docopy_int(UNUSED(NWDSContextHandle ctx), const void * val, const enum SYNTAX synt, UNUSED(size_t currentSize),
void * result, size_t maxSize) {
#ifdef DEBUG_PRINT
printf ("docopy_int got :%s synt = %d cursize=%d maxsize= %d\n",(char *)val,synt,currentSize,maxSize );
#endif
if (!result) {
return ERR_NULL_POINTER;
}
switch (synt) {
case SYN_BOOLEAN:
return ncp_put_req_size_unsigned(result, maxSize, *(const Boolean_T*)val);
case SYN_COUNTER:
return ncp_put_req_size_unsigned(result, maxSize, *(const Counter_T*)val);
case SYN_INTEGER:
return ncp_put_req_size_unsigned(result, maxSize, *(const Integer_T*)val);
case SYN_INTERVAL:
return ncp_put_req_size_unsigned(result, maxSize, *(const Integer_T*)val);
case SYN_TIME:
return ncp_put_req_size_unsigned(result, maxSize, *(const Time_T*)val);
default:
return EINVAL;
}
}
/***********************************************************************/
struct strlistnode {
struct strlistnode* next;
char * str;
};
struct strlist {
struct strlistnode* first;
struct strlistnode* last;
};
static struct strlist* initlist (void) {
struct strlist* l;
l=(struct strlist*) malloc(sizeof(*l));
if (l) {
l->first=l->last=NULL;
}
return l;
}
static void freelist ( struct strlist* l) {
if (l) {
struct strlistnode* p;
struct strlistnode* q=NULL;
for (p=l->first;p;p=q) {
q=p->next;
free(p->str);
free(p);
}
}
}
static NWDSCCODE addstring (char * str, struct strlist * l) {
char * v;
struct strlistnode* newNode;
if (!l)
return ERR_NULL_POINTER;
v= strdup(str);
if (!v)
return ENOMEM;
newNode=malloc (sizeof (*newNode));
if (!newNode)
return ENOMEM;
newNode->str=v;
newNode->next=NULL;
if (l->last)
l->last->next=newNode;
else
l->first=newNode;
l->last=newNode;
return 0;
}
static NWDSCCODE strlist_to_string (struct strlist * l, char ** result, char sep) {
/*convert a linked list to a string with sep between strings */
size_t ln;
char* aux;
struct strlistnode * p;
*result = NULL;
if (!l)
return ERR_NULL_POINTER;
/*compute needed memory */
ln = 1;
for (p = l->first; p; p = p->next)
ln += strlen(p->str) + 1;
if (ln == 1)
return 0;
aux = (char*)malloc(ln);
if (!aux)
return ENOMEM;
*result = aux;
/*transfert to result with commas between strings */
for (p = l->first;p; p = p->next) {
ln = strlen(p->str);
memcpy(aux, p->str, ln);
aux += ln;
*aux++ = sep;
}
*--aux = 0; /* remove last comma */
return 0;
}
/***********************************************************************/
/* append the new string to a linked list */
static NWDSCCODE docopy_multistring(NWDSContextHandle ctx, const void * val, const enum SYNTAX synt, size_t currentSize,
void * result, UNUSED(size_t maxSize)) {
NWDSCCODE err;
char tmpBuf[MAX_DN_BYTES+1];
struct strlist* l=(struct strlist *) result;
#ifdef DEBUG_PRINT
printf ("docopy_multistring got :%s synt = %d cursize=%d maxsize= %d\n",(char *)val,synt,currentSize,maxSize );
#endif
/*copy string to tmpBuffer */
err = __docopy_string(ctx, val, synt, currentSize, tmpBuf, sizeof(tmpBuf));
if (!err) {
/* and add to list if Ok */
err= addstring(tmpBuf,l);
}
return err;
}
/*-------------------------------------------------------------------------*/
/* Function : ReadAttributesValues */
/* */
/* Description : */
/* Function for reading an set of attributes values */
/* nearly same as the one used in pam_ncp_auth.c/pamncp.c snapin */
/* except a "more complex" copying call back */
/*-------------------------------------------------------------------------*/
// element of the table of attributes to read
struct attrop {
const NWDSChar* attrname;
NWDSCCODE (*copyval)(NWDSContextHandle, const void* val, const enum SYNTAX synt,
size_t currentSize, void* result, size_t maxSize);
enum SYNTAX synt;
int maxsize;
};
static NWDSCCODE ReadAttributesValues(NWDSContextHandle ctx,
const char* objname,
void* arg,
struct attrop* atlist) {
Buf_T* inBuf=NULL;
Buf_T* outBuf=NULL;
NWDSCCODE dserr;
struct attrop* ptr;
nuint32 iterHandle;
iterHandle = NO_MORE_ITERATIONS; // test at bailout point !!!
#ifdef DEBUG_PRINT
{
char aux [8192];
NWDSCanonicalizeName(ctx,objname,aux);
printf ("readattr called for %s %s fqdn=%s \n",objname,atlist->attrname,aux);
}
#endif
dserr = NWDSAllocBuf(DEFAULT_MESSAGE_LEN, &inBuf);
if (dserr) {
goto bailout;
}
dserr = NWDSInitBuf(ctx, DSV_READ, inBuf);
if (dserr) {
goto bailout;
}
for (ptr = atlist; ptr->attrname; ptr++) {
dserr = NWDSPutAttrName(ctx, inBuf, ptr->attrname);
if (dserr) {
goto bailout;
}
}
dserr = NWDSAllocBuf(DEFAULT_MESSAGE_LEN, &outBuf);
if (dserr) {
goto bailout;
}
do {
nuint32 attrs;
dserr = NWDSRead(ctx, objname, DS_ATTRIBUTE_VALUES, 0, inBuf, &iterHandle, outBuf);
if (dserr) {
/* caller must complains or not upon */
/*ERR_NO_SUCH_ATTRIBUTE*/
/*ERR_NO_SUCH_ENTRY*/
goto bailout;
}
dserr = NWDSGetAttrCount(ctx, outBuf, &attrs);
if (dserr) {
goto bailout;
}
#ifdef DEBUG_PRINT
printf ("attr count %d\n",attrs);
#endif
while (attrs--) {
char attrname[MAX_SCHEMA_NAME_CHARS+1];
nuint32 synt;
nuint32 vals;
dserr = NWDSGetAttrName(ctx, outBuf, attrname, &vals, &synt);
if (dserr) {
goto bailout;
}
#ifdef DEBUG_PRINT
printf ("val count %d\n",vals);
#endif
while (vals--) {
size_t sz;
void* val;
dserr = NWDSComputeAttrValSize(ctx, outBuf, synt, &sz);
if (dserr) {
goto bailout;
}
val = malloc(sz);
if (!val) {
goto bailout;
}
dserr = NWDSGetAttrVal(ctx, outBuf, synt, val);
if (dserr) {
free(val);
goto bailout;
}
for (ptr = atlist; ptr->attrname; ptr++) {
#if 0
printf ("%s:%d:%p\n",ptr->attrname,ptr->synt,ptr->copyval);
#endif
if (!strcmp(ptr->attrname, attrname))
#if 0
printf ("ok\n");
#endif
break;
}
#if 0
printf ("%s:%d:%p\n",ptr->attrname,ptr->synt,ptr->copyval);
#endif
#ifdef DEBUG_PRINT
printf (ptr->copyval? "non null\n":"null\n");
#endif
if (ptr->copyval) {
if (ptr->synt != synt) {
dserr=ERR_NO_SUCH_ATTRIBUTE;
} else {
#ifdef DEBUG_PRINT
printf ("zy go\n");
#endif
dserr= ptr->copyval(ctx,val,synt,sz, arg,ptr->maxsize);
}
}else {
dserr=ERR_NO_SUCH_ATTRIBUTE;
/* mistyped: happens with upcae/lowcase errors */
}
free(val);
if (dserr) {
goto bailout;
}
}
}
} while (iterHandle != NO_MORE_ITERATIONS);
bailout:;
if (iterHandle != NO_MORE_ITERATIONS) {
// let's keep the final dserr as the 'out of memory error' from ptr->getval()
NWDSCloseIteration(ctx, DSV_READ, iterHandle);
}
if (inBuf) NWDSFreeBuf(inBuf);
if (outBuf) NWDSFreeBuf(outBuf);
#ifdef DEBUG_PRINT
printf ("readattr ended with code :%s\n",strnwerror(dserr));
#endif
return dserr;
}
/* specific buffer extracting functions that replace docopy_* */
struct nw_home_info {
char* hs;
char* hrn;
};
/* Note that this function is completely wrong: host server is DN, and you should use DN operations on it...
* Cutting it at first dot is nonsense... It might work, but there is no reason why it should... */
static NWDSCCODE docopy_host_server(UNUSED(NWDSContextHandle ctx),
const void* val, UNUSED(const enum SYNTAX synt),
UNUSED(size_t currentSize), void* result, UNUSED(size_t maxSize)) {
struct nw_home_info* hi = (struct nw_home_info*)result;
char buf [MAX_DN_CHARS];
char * dot;
char *v;
#ifdef DEBUG_PRINT
printf ("docopy_host_server got :%s synt = %d cursize=%d maxsize= %d\n",(char *)val,synt,currentSize,maxSize );
#endif
strcpy(buf,(const char *) val);
dot = strchr(buf, '.'); // trim out the context part ( it that good enough ???)
if (dot) *dot=0;
v = strdup(buf);
if (!v) {
return ENOMEM;
}
hi->hs = v;
return 0;
}
static NWDSCCODE docopy_host_resource_name(UNUSED(NWDSContextHandle ctx),
const void* val, UNUSED(const enum SYNTAX synt),
UNUSED(size_t currentSize), void* result, UNUSED(size_t maxSize)) {
struct nw_home_info* hi = (struct nw_home_info*)result;
char* v = strdup((const char*)val);
#ifdef DEBUG_PRINT
printf ("docopy_host_resource got :%s synt = %d cursize=%d maxsize= %d\n",(char *)val,synt,currentSize,maxSize );
#endif
if (!v) {
return ENOMEM;
}
hi->hrn =v;
return 0;
}
static NWDSCCODE docopy_home_directory(UNUSED(NWDSContextHandle ctx),
const void* val, UNUSED(const enum SYNTAX synt),
UNUSED(size_t currentSize), void* result, UNUSED(size_t maxSize)) {
const Path_T* pa = (const Path_T*) val;
Path_T* result_int = (Path_T*)result;
char * v;
result_int->nameSpaceType=pa->nameSpaceType;
v = strdup(pa->path);
if (!v)
return ENOMEM;
result_int->path=v;
v = strdup(pa->volumeName);
if (!v)
return ENOMEM;
result_int->volumeName=v;
return 0;
}
/******************************************************************************/
NWDSCCODE NWCXGetNDSVolumeServerAndResourceName(NWDSContextHandle ctx,
const NWDSChar* ndsName,
NWDSChar* serverName,
size_t serverNameMaxLen,
NWDSChar *resourceName,
size_t resourceNameMaxLen){
static struct attrop atlist[] = {
{ATTR_HOST_SERVER, docopy_host_server, SYN_DIST_NAME ,9999},
{ATTR_HOST_RN, docopy_host_resource_name, SYN_CI_STRING ,9999},
{ NULL, NULL, SYN_UNKNOWN ,0 }};
struct nw_home_info hi ={NULL,NULL};
NWDSCCODE dserr;
if (!ndsName )
return ERR_NULL_POINTER;
dserr=ReadAttributesValues(ctx,ndsName,&hi,atlist);
if (!dserr) {
if (serverName && hi.hs) {
if (strlen(hi.hs) <serverNameMaxLen)
strcpy(serverName,hi.hs);
else
dserr=NWE_BUFFER_OVERFLOW;
}
if (resourceName &&hi.hrn) {
if (strlen(hi.hrn) <resourceNameMaxLen)
strcpy(resourceName,hi.hrn);
else
dserr= NWE_BUFFER_OVERFLOW;
}
}
#ifdef DEBUG_PRINT
printf ("%s %s:\n",hi.hs,hi.hrn);
#endif
if (hi.hs) free( hi.hs);
if (hi.hrn) free( hi.hrn);
return dserr;
}
NWDSCCODE NWCXGetObjectHomeDirectory(NWDSContextHandle ctx,
const NWDSChar* ndsName,
NWDSChar* serverName,
size_t serverNameMaxLen,
NWDSChar *resourceName,
size_t resourceNameMaxLen,
NWDSChar* NDSVolumeName,
size_t NDSVolumeNameMaxLen,
NWDSChar* pathName,
size_t pathNameMaxLen) {
Path_T reply={0,NULL,NULL};
static struct attrop atlist[] = {
{ ATTR_HOME_NW , docopy_home_directory, SYN_PATH ,9999},
{ NULL, NULL, SYN_UNKNOWN ,0 }};
NWDSCCODE dserr;
if (!ndsName )
return ERR_NULL_POINTER;
dserr=ReadAttributesValues(ctx,ndsName,&reply,atlist);
if (!dserr) {
if (NDSVolumeName && reply.volumeName) {
if (strlen(reply.volumeName) <NDSVolumeNameMaxLen)
strcpy(NDSVolumeName,reply.volumeName);
else
dserr=NWE_BUFFER_OVERFLOW;
}
if (pathName && reply.path) {
if (strlen(reply.path) <pathNameMaxLen)
strcpy(pathName,reply.path);
else
dserr=NWE_BUFFER_OVERFLOW;
}
if (serverName || resourceName){
if (reply.volumeName)
dserr=NWCXGetNDSVolumeServerAndResourceName(ctx,reply.volumeName,
serverName,serverNameMaxLen,
resourceName,resourceNameMaxLen);
else dserr=ERR_NO_SUCH_ATTRIBUTE;
}
}
#ifdef DEBUG_PRINT
printf ("%s %s\n",reply.volumeName,reply.path);
printf ("%s %s %s %s\n",NDSVolumeName,pathName,serverName,resourceName);
#endif
if (reply.path) free (reply.path);
if (reply.volumeName) free (reply.volumeName);
#ifdef DEBUG_PRINT
printf ("%s:\n",strnwerror(dserr));
#endif
return dserr;
}
NWDSCCODE NWCXGetObjectLastLoginTime(NWDSContextHandle ctx,
const NWDSChar* ndsName,
time_t * tm){
int int_tm;
NWDSCCODE err;
err = NWCXGetIntAttributeValue(ctx, ndsName, ATTR_LOGIN_TIME, &int_tm);
if (!err) {
*tm = int_tm;
}
return err;
}
NWDSCCODE NWCXGetObjectMessageServer(NWDSContextHandle ctx,
const NWDSChar* ndsName,
NWDSChar* serverName,
int serverNameMaxLen){
return NWCXGetStringAttributeValue(ctx,ndsName,ATTR_MESSAGE_SERVER,serverName,serverNameMaxLen);
}
/*** login script reading & writing ****************************************/
struct loginScriptInfo {
const NWDSChar * user;
char * buffer;
int bytesRead;
int max;
};
static NWDSCCODE docopy_login_script(NWDSContextHandle ctx, const void * val, const enum SYNTAX synt, size_t currentSize,
void * result, size_t maxSize){
// code from contrib/testing/dstream.c
static char attrName[MAX_DN_CHARS + 1]=ATTR_LOGIN_SCRIPT;
struct loginScriptInfo* lsi=result;
nuint8 hndl[6];
NWCONN_HANDLE fileConn;
ncp_off64_t fileSize;
NWDSCCODE err ;
(void) val;(void) maxSize;(void) synt;(void) currentSize; // warnings out !
if (!lsi->buffer) return ERR_NULL_POINTER;
#if 0
printf("do_copy_login_script called for %s\n", lsi->user);
#endif
//err=ERR_NO_SUCH_ATTRIBUTE;
err= __NWDSOpenStream(ctx, lsi->user, attrName, 0, &fileConn, hndl, &fileSize);
if(err==0){
lsi->bytesRead=ncp_read ( fileConn,hndl,0, lsi->max-1,lsi->buffer);
if (lsi->bytesRead <0 ) {// some error occured
err=-1;
lsi->bytesRead=0;
}
lsi->buffer[lsi->bytesRead]='\0';
ncp_close_file(fileConn,hndl);
NWCCCloseConn(fileConn);
#if 0
printf("%s:%d/%d bytes read from login script, err=%d\n",lsi->user, lsi->bytesRead,lsi->max,err);
#endif
}
return err;
}
NWDSCCODE NWCXGetObjectLoginScript(NWDSContextHandle ctx,const NWDSChar* objectName,
char* buffer, int * len, int maxlen) {
static struct attrop atlist[] = {
{ ATTR_LOGIN_SCRIPT , docopy_login_script, SYN_STREAM ,9999},
{ NULL, NULL, SYN_UNKNOWN ,0 }};
NWDSCCODE dserr;
struct loginScriptInfo lsi;
if (!objectName) return ERR_NULL_POINTER;
lsi.user=objectName;
lsi.buffer=buffer;
lsi.max=maxlen;
lsi.bytesRead=0;
dserr= ReadAttributesValues(ctx,objectName,&lsi,atlist);
if (!dserr) {
*len=lsi.bytesRead;
}
return dserr;
}
NWDSCCODE NWCXGetContextLoginScript(NWDSContextHandle ctx,const NWDSChar* objectName,
char* buffer, int * len,int maxlen){
// PP: I am not too happy with this code, but it seems to works even if current user's have a
// Default Name context in environnment of a .nwclient file.
char context[MAX_DN_BYTES+1];
char fqdn[MAX_DN_BYTES+1];
NWDSCCODE dserr;
NWDSContextHandle ctx2;
if (!objectName) return ERR_NULL_POINTER;
// we must convert relative name to a FQDN and then climb up contexts up to root
dserr= NWDSCanonicalizeName(ctx,objectName,fqdn);
if (!dserr) {
// we must duplicate context handle and have a [Root] name context there
dserr= NWDSDuplicateContextHandle(ctx, &ctx2);
if (dserr)
return dserr;
dserr=NWDSSetContext(ctx2, DCK_NAME_CONTEXT, "[Root]");
if (dserr) {
NWDSFreeContext(ctx2);
return dserr;
}
// let's climb up until we found one
dserr=NWCXSplitNameAndContext(ctx2,fqdn,NULL,context);
if (!dserr) {
//printf ("trying to get context LS of %s from %s\n",fqdn,context);
dserr=ERR_NO_SUCH_ATTRIBUTE;
while (dserr==ERR_NO_SUCH_ATTRIBUTE && context[0]) {
//printf ("trying to get context LS from %s\n",context);
dserr=NWCXGetObjectLoginScript(ctx2,context,buffer,len,maxlen);
if (dserr)
NWCXSplitNameAndContext(ctx2,context,NULL,context);
}
}
NWDSFreeContext(ctx2);
}
return dserr;
}
NWDSCCODE NWCXGetProfileLoginScript(NWDSContextHandle ctx,const NWDSChar* objectName,
char* buffer, int * len, int maxlen){
char profile[MAX_DN_BYTES+1];
NWDSCCODE dserr;
if (!objectName) {
return ERR_NULL_POINTER;
}
dserr = NWCXGetStringAttributeValue(ctx, objectName, ATTR_PROFILE, profile, sizeof(profile));
if (!dserr) {
#if 0
printf ("reading Login Script of profile %s for object %s\n",profile,objectName);
#endif
dserr = NWCXGetObjectLoginScript(ctx, profile, buffer, len, maxlen);
}
return dserr;
}
/* read a single valued string attribute */
NWDSCCODE NWCXGetStringAttributeValue (NWDSContextHandle ctx,
const NWDSChar* objectName,
const NWDSChar* attrName,
char* buffer, int maxlen) {
struct attrop atlist[] = {
{ attrName, docopy_string, SYN_UNKNOWN, maxlen},
{ NULL, NULL, SYN_UNKNOWN, 0 }};
NWDSCCODE dserr;
if (!objectName )
return ERR_NULL_POINTER;
dserr=NWDSGetSyntaxID(ctx, attrName, &atlist[0].synt);
#ifdef DEBUG_PRINT
printf ("err NWDSGetSyntaxID %s for object %s\n",attrName,strnwerror(dserr));
#endif
if (dserr)
return dserr;
switch (atlist[0].synt) {
case SYN_COUNTER:
case SYN_INTEGER:
case SYN_INTERVAL:
case SYN_BOOLEAN:
case SYN_TIME:
dserr=EINVAL;
break;
default:
dserr=ReadAttributesValues(ctx,objectName,buffer,atlist);
break;
}
return dserr;
}
/* read a single valued numeric/boolean attribute */
NWDSCCODE NWCXGetIntAttributeValue (NWDSContextHandle ctx,
const NWDSChar* objectName,
const NWDSChar* attrName,
int * value){
int aux=0;
struct attrop atlist[] = {
{ attrName, docopy_int, SYN_UNKNOWN, sizeof(aux) },
{ NULL, NULL, SYN_UNKNOWN, 0 }};
NWDSCCODE dserr;
if (!objectName )
return ERR_NULL_POINTER;
dserr=NWDSGetSyntaxID(ctx, attrName, &atlist[0].synt);
#ifdef DEBUG_PRINT
printf ("err NWDSGetSyntaxID %s for object %s\n",attrName,strnwerror(dserr));
#endif
if (dserr)
return dserr;
switch (atlist[0].synt) {
case SYN_COUNTER:
case SYN_INTEGER:
case SYN_INTERVAL:
case SYN_BOOLEAN:
case SYN_TIME:
dserr=ReadAttributesValues(ctx,objectName,&aux,atlist);
break;
default: dserr=EINVAL;
}
if (!dserr)
*value= aux;
return dserr;
}
/* read a multi valued string attribute */
/*does check for syntax flag being DS_STRING and ! DS_SINGLE */
/* caller MUST free the buffer created here */
NWDSCCODE NWCXGetMultiStringAttributeValue (NWDSContextHandle ctx,
const NWDSChar* objectName,
const NWDSChar* attrName,
char** buffer) {
struct attrop atlist[] = {
{ attrName, docopy_multistring, SYN_UNKNOWN, MAX_DN_BYTES + 1},
{ NULL, NULL, SYN_UNKNOWN ,0 }};
NWDSCCODE dserr;
struct strlist *l=NULL;
if (!objectName )
return ERR_NULL_POINTER;
dserr=NWDSGetSyntaxID(ctx, attrName, &atlist[0].synt);
#ifdef DEBUG_PRINT
printf (" NWDSGetSyntaxID (%d) %s for object %s returned :%s\n",atlist[0].synt,attrName,objectName,strnwerror(dserr));
#endif
if (dserr)
return dserr;
l = initlist();
if (!l)
return ENOMEM;
switch (atlist[0].synt) {
case SYN_COUNTER:
case SYN_INTEGER:
case SYN_INTERVAL:
case SYN_BOOLEAN:
case SYN_TIME:
dserr=EINVAL;
break;
default:
dserr=ReadAttributesValues(ctx,objectName,l,atlist);
break;
}
if (!dserr) {
dserr=strlist_to_string(l,buffer,',');
}
freelist(l);
return dserr;
}
/* read & convert to string a single valued attribute */
NWDSCCODE NWCXGetAttributeValueAsString (NWDSContextHandle ctx,
const NWDSChar* objectName,
const NWDSChar* attrName,
char* buffer, size_t maxlen) {
enum SYNTAX synt;
int auxint=0;
NWDSCCODE dserr;
char aux[128];
dserr=NWDSGetSyntaxID(ctx, attrName, &synt);
#ifdef DEBUG_PRINT
printf ("NWDSGetSyntaxID: %s %s %d\n",strnwerror(dserr),attrName,synt);
#endif
if (dserr)
return dserr;
switch (synt) {
case SYN_COUNTER:
case SYN_INTEGER:
case SYN_INTERVAL:
case SYN_BOOLEAN:
dserr=NWCXGetIntAttributeValue(ctx,objectName,attrName,&auxint);
if (!dserr) {
if (synt == SYN_BOOLEAN) {
sprintf(aux,"%s", (auxint == 0)?"false":"true");
} else {
sprintf(aux,"%u",auxint);
}
if (strlen(aux)<maxlen)
strcpy(buffer,aux);
else dserr=NWE_BUFFER_OVERFLOW;
}
break;
case SYN_TIME:
dserr=NWCXGetIntAttributeValue(ctx,objectName,attrName,&auxint);
if (!dserr) {
time_t t;
t = auxint;
sprintf(aux,"%s", ctime(&t));
/* remove LF added by ctime */
if (strlen(aux)>0 && aux[strlen(aux)-1]=='\n')
aux[strlen(aux)-1]=0;
if (strlen(aux)<maxlen)
strcpy(buffer,aux);
else dserr=NWE_BUFFER_OVERFLOW;
}
break;
default:
dserr=NWCXGetStringAttributeValue(ctx,objectName,attrName,buffer,maxlen);
}
return dserr;
}
#endif /* NDS_SUPPORT */