Novell is now a part of Micro Focus

Novell Directory Services Q & A

Articles and Tips: article

JOHN BUCKLE
Developer Support Engineer
Developer Support

01 Feb 1997


Novell Directory Services Q & A

Q. What's the best way to determine if an NDS object exists? Do you have to use NWDSRead()?

A. While it is possible to use NWDSRead() and pass an empty input buffer, this method still requires you to allocate an input and output buffer even though both buffers will be empty. A better approach is to use the function NWDSReadObjectInfo().

NWDSCCODE N_API

NWDSReadObjectInfo(

 NWDSContextHandle  context,

 pnstr8             object,

 pnstr8             distName,

 pObject_Info_T     info);

This function will return ERR_NO_SUCH_ENTRY if the object does not exist. The object's distinguished name and the base class are also returned through the parameters. This function is also useful when you need an object's distinguished name for use in SYN_DIST_NAME attributes. Listing 1 shows an example of how this can be used.

Q. Where are ERR_NO_SUCH_ENTRYand the other error codes defined?

A. In NWDSERR.H.

Q. There are eight opcodes specified in the documentation for NWDSPutChange(), some of which appear to perform the same action. What are the differences between the opcodes?

A. Four new opcodes were added to simplify coding so that you don't have to worry about adding duplicate values or removing nonexistent ones. This allows you to pack more commands into an input buffer without worrying about a command aborting the processing of the buffer by returning an unnecessary error code. The following are some supplementary notes to those given in the documentation.


Opcode
Description

DS_ADD_ATTRIBUTE

Contrary to what is stated in the documentation, this opcode always returns SUCCESS, even whenadding an existing, illegal, or bogus attribute. This is useful since it allows you to make sure the attribute is present by adding theattribute to the object prior to adding the value, as shown in Listing 1. The documentation suggests this would return ERR_ATTRIBUTE_ALREADY_EXISTSif the attribute exists and stop any further processing of the input buffer.

DS_REMOVE_ATTRIBUTE

Returns an error if the attribute is missing. Attributes that are in the class's naming attributesor are mandatory cannot be removed. This opcode will delete all values associatedwith the attribute.

DS_CLEAR_ATTRIBUTE

Differs from the previous opcode because it does not return an error if the attribute is missing.

DS_ADD_VALUE

Returns an error if the attribute already has this value, or if the attribute is single valued and already has a value.

DS_ADDITIONAL_VALUE

Adds an additional value to a multiple valued attribute. Returns an error if the attributeis empty or a single valued attribute.

DS_OVERWRITE_VALUE

Can be used with single and multiple valued attributes. Does not return an error if the attributehas this value, or if the attribute is single valued and already has a value. In the latter case the new value replaces the old.

DS_REMOVE_VALUE

Returns an error if the value is not present.

DS_CLEAR_VALUE

Differs from the previous opcode because it does not return an error if the value is missing.

Q. When I unload an NLM that has authenticated to NDS, the console screen reports that the NLM has not released all its resources. Why is that?

A. The NLM has to log out of NDS and return all handles and buffers before unloading.

Q. I tried that but it didn't work. I trapped SIGTERM using signal() and released all the resources within the signal handler.

A. The SIGTERM signal handler is run by the console thread and does not own the resources you were returning. Hence some were missed. You should use the same thread that authenticated to NDS to also log out from NDS. Listing 2 gives an example of this. See the article "Graceful NLM Demise" in Novell Developer Notes, January 1996.

Q. In the book NetWare 4.0 NLM Programming the author using the APIs AdvertiseService() and ShutdownAdvertising(). Why is there no mention of these APIs in the documentation?

A. These functions are documented in "SAP for NLMs" in the "Transport Function Reference" book of the NWSDK. The use of SAP to advertise services is no longer encouraged and dedicated SAP numbers are rarely issued. Services should be advertised using NDS. See the article "Using NDS to Make a Service Globally Accessible" in Novell DeveloperNotes, April 1996.

Listing 1

ccode = NWDSReadObjectInfo(Handle,object,distName,& objectInfo) ;& objectInfo) ;
if (ccode){

   printf("Cannot locate object %40.40s",object) ;

   return ccode ;

}



NWDSInitBuf(Handle,DSV_MODIFY_ENTRY,Input);



NWDSPutChange (Handle,Input,DS_ADD_ATTRIBUTE,"App:Back_Link");

NWDSPutChange (Handle,Input,DS_ADD_VALUE,"App:Back_Link");

NWDSPutAttrVal(Handle,Input,SYN_DIST_NAME,distName);

Listing 2

/*

** Sample NLM Authenticating to NDS

*/



int ThreadID    = 0 ;

int ExitNow     = 0 ;

int ThreadCount = 0 ;



NWDSContextHandle   Handle = (NWDSContextHandle) ERR_CONTEXT_CREATION ;

NWDSCCODE           Login  = 0x8801 ;

Buf_T *             Input  = 0 ;

Buf_T *             Output = 0 ;



void SigTermProc(int)

{

   ExitNow = 1 ;

   ResumeThread(ThreadID);



   while (ThreadCount)

      ThreadSwitchWithDelay();

}



void main(int argc, char * argv[])

{

   ThreadCount ++ ;

   ThreadID = GetThreadID();

   signal(SIGTERM,SigTermProc);



   /*

   ** Get admin account and password from the user.

   ** (See "NLM Issues and Strategies when Accessing NDS"

   **       Developer Notes, August 1996).

   */



   LoginToTree(Admin,Password);



   /*

   ** What happens here depends on the application.

   ** In this case the thread suspends itself and waits

   ** to be unloaded. This would be the situation if it

   ** was handling NCP Extension requests.

   */



   if (! ExitNow) SuspendThread(ThreadID);



   /*

   ** Make sure there are no other threads around using

   ** the NDS variables.

   */



   while (ThreadCount > 1)

      ThreadSwitchWithDelay();



   LogoutFromTree() ;

   ThreadCount ;

}



NWDSCCODE LoginToTree(char * admin, char * password)

{

   if ((Handle = NWDSCreateContext()) == ERR_CONTEXT_CREATION)

      return ERR_CONTEXT_CREATION;



   NWDSSetContext(Handle,DCK_NAME_CONTEXT,"[Root]");



   Login = NWDSLogin(Handle,0,admin,password,0);



   NWDSAllocBuf(DEFAULT_MESSAGE_LEN,& Input) ;& Input) ;
   NWDSAllocBuf(DEFAULT_MESSAGE_LEN,& Output) ;& Output) ;


   return Login ;

}



NWDSCCODE LogoutFromTree()

{

   if (Login == 0) NWDSLogout(Handle);



   if (Input)  NWDSFreeBuf(Input);

   if (Output) NWDSFreeBuf(Output);

   if (Handle != ERR_CONTEXT_CREATION)

      NWDSFreeContext(Handle) ;



   return 0 ;

}

* Originally published in Novell AppNotes


Disclaimer

The origin of this information may be internal or external to Novell. While Novell makes all reasonable efforts to verify this information, Novell does not make explicit or implied claims to its validity.

© Copyright Micro Focus or one of its affiliates