Novell is now a part of Micro Focus

NLM Issues and Strategies When Accessing NDS

Articles and Tips: article

BRENT REED
Developer Support Engineer
Developer Support

MARK OBERG
Developer Support Engineer
Developer Support

01 Aug 1996


This article discusses how an NLM can deal with the extra security requirements introduced by NDS. NetWare security is discussed in the context of three major services accessed by NLMs-Bindery, File System, and Directory Services. The article shows what rights an NLM has to these services and why.

Introduction

You have been writing NLMs for quite awhile now and are feeling pretty confident. You have taken for granted the privilege that as long as your NLM is accessing the local file server's file system or NetWare 3.x Bindery, you seem to have unlimited power. Now it's time to try your hand at Directory Services. You see NWDSLogin() and NWDSAuthenticate() but you don't want to use this API because you still want to be the all powerful NLM and still not have to worry about a password during unattended NLM loading.

So you take the first piece of sample code you get your hands on, strip out the NWDSLogin() and NWDSAuthenticate() and compile. The code seems to be running OK until it gets to . . . -672 Error No Access . . . "Hey, how come the insufficient rights?"

If you're an NLM programmer in the 3.x environment, moving to 4.x and Novell Directory Services (NDS), the previous example demonstrates a typical misunderstanding of NLM rights in the NDS environment. Correcting this requires adjustments in NLM design.

This article discusses how your NLM can deal with the extra security requirements introduced by NDS. As an introduction we discuss fundamental security and rights concepts that apply to an NLM and the differences that exist in rights issues between the 3.x and the 4.x environments. Even though NDS has some rights issues which are different, it does offer NLMs additional benefits.

The sample code that is referenced in this article can be found on ftp.novell.com:pub\netwire\ndevsup\05\xdsa7.exe or CompuServe forum NDEVSUP, library 05, and file xdsa7.exe. To show the benefits of leveraging NDS in an NLM we demonstrate how to read NLM configuration information from this secure, persistent, centrally administered, and replicated database.

NetWare Security in a Nut Shell

Because the network facilitates the sharing of computer resources, NetWare security is responsible for regulating access to these shared resources. For security reasons, who you are determines what you are allowed to do - your RIGHTS. Since NetWare is not implemented as a single security system, different NetWare services use different security systems.

The following sections briefly discuss NetWare security in the context of three major services accessed by NLMs-Bindery, File System, and Directory Services-what rights your NLM has to these services and why. Also, additional special considerations affect the NLM's rights (i.e. is it a client or an extension of the server).

The NLM- Extension of the Server or a Client?

An NLM which is running on a NetWare server is considered a modular extension of the NetWare operating system, or server. Therefore, the NLM is trusted and not restricted to server resources. Within this server-centered environment, the NLM is considered part of the server and therefore is all powerful, having Supervisor equivalent rights.

As an example, the Bindery and File System are systems which are "server" centered resources, complete systems on the server, and considered part of the server. Therefore, when the NLM is accessing the local Bindery or local File System it has all rights. The NLM is considered running on the "local" server; therefore, the NLM is acting as an extension of the server it's running on and the NLM has Supervisor equivalent rights on this server. Whenever the NLM needs to access a Bindery or File System which doesn't belong to the local server it is accessing a "remote" server on a different physical machine. In this situation, the NLM is no longer an extension of the local server but becomes a "client" of the "remote" server.

When first establishing a connection the client NLM has limited rights until it identifies itself as a valid user. For example, in the case of remote Bindery access, when your NLM first becomes a client by attaching to the remote host, it has limited read access to the Bindery until it identifies itself as a valid object by logging into the remote server. The remote File System requires the client to establish its object ID so it can perform client access control.

NDS adds an additional security system which is networked based instead of server based, requiring new security APIs you will need to be aware of and use. However, the security systems for server-based resources are still in place and your NLM will still have to identify itself to them before being able to access them.(For a 3.x NLM remote client to identity itself for increased rights to the 3.x server with a Bindery or a 4.x server with bindery emulation and for File System-and other server centric resources-access the client can use the APIs AttachToFileServer() and LoginToFileSever(). A 4.x NLM remote client accessing these 3.x resources would use these same APIs.)

However, in the case of the 4.x remote client accessing the 4.x server's File System and other server-based resources (such as Queue Management Services-QMS), it would first use NWDSLogin() to authenticate into Directory Services, thus establishing an Object ID other than [Public], and then use NWDSAuthenticate() to authenticate (bind) to the file server.

"Come on. My NLM is running on the local server, not accessing a remote server. How come my NLM doesn't seem to have SUPERVISOR rights when I access DS? I'm not going remote."

Directory Services is a "network" centered resource, often spanning multiple servers as one entity. Therefore Directory Services does not belong to one server; your NLM is just considered another client to DS. To be able to access the network to the fullest, your NLM must identify itself as an authentic client.

When your NLM first attaches to the directory, this attached client receives [Public] access to the Directory, which only gives it browse rights to the directory. Only after performing an NWDSLogin() will your NLM establish its credentials, therefore increasing its rights to the directory by authenticating to the directory.

Authentications Between Loads

"OK, so I don't have immediate Supervisor rights when accessing the Directory Services. Where am I going to store the password if my NLM is going to do unattended logins when the server is brought up? If my NLM only has [Public] rights which just allows my NLM rights to browse the Directory then I'm not going to be able to read a password attribute from the Directory."

One of the issues with having NLMs log in to NDS is that NLMs are required to load without administrator intervention when file servers are taken down and back up. Until the NLM authenticates to the Directory, it only has browse rights as object [Public]. We now demonstrate how your NLM can access Directory Services with persistent authentication.

An NLM on 4.x NetWare still has Supervisor access to the local file system. Using this access right, an NLM can store a password in a configuration file in a fairly secure place where Supervisor equivalence would be required. As an additional security measure, to minimize the risk of tampering by other administrators you could perform minimal encryption on the password.

The functions GetPasswordFromSys() and StorePasswordToSys() are integrated with NWDSLogin() to demonstrate this functionality around line number 727 of EXAMPSRV.C.

Benefits of an NLM Authenticating to NDS

Three benefits of using the functionality of NDS for NLM services are leverageable by having NLMs log in to the directory:

  • The NLMs receive a global identity for the service or services that they provide and act as a service location mechanism.

  • NLMs can use NDS and background authentication to access resources external to the local NetWare file system. The NLM is required to supply a password once-when it uses NWDSLogin() to authenticate to Directory Services-then background authentication during NWDSAuthenticate() does not require an NLM to pass another password. This greatly enhances security.

  • NLMs that log in as their identity can store global configuration or local specific configuration attributes in NDS to provide a fault tolerant configuration storage medium. This results in a service being able to have a globally accessible configuration store, represented as the NDS service object. Along with this storage, the rights to the configuration can be limited to read access for the NLM service, reserving modification rights for the administrator. This reduces the risk of sabotage from others.

Around line 563 in the example code, a description is stored when a service object is created. This represents a service configuration which is read with the GetDescription() function when the service comes up around line 826.

1 /****************************************************************************

   2 ** File: exampsrv.c

   3 **

   4 **      Description:

   5 **    This example server demonstrates one way to provide an NLM NDS

   6 **    authentication between NLM loads.  The NLM's identity in this

   7 **    example is passed on the command line.  The authentication is

   8 **    stored securely in the local file system with measures to protect

   9 **    it from other administrators.

  10 **

  11 **

  12 ** Program flow:

  13 **    1. Check for NLM identity on command line, if not present display usage.

  14 **    2. Call NWDSReadObjectInfo() to determine if object exists.  If object

  15 **       doesn't exist prompt is new service object is to be created.

  16 **       Create service object prompting for parameters if required.  Store

  17 **       password for service object in sys:system\exampsrv.cfg

  18 **    3. Look for a password in sys:system\exampsrv.cfg.  If found, try

  19 **       NWDSLogin(). If receive  669 instruct that the stored password is 
  20 **       invalid and prompt for different password or allow to exit.

  21 **    3. Once logged in, store any password changes in sys:system\exampsrv.cfg

  22 **    4. Read the local host servers DN and compare it with the service

  23 **       object's DN. If different attempt to change service object location

  24 **       if receive an error changing service location, fail because

  25 **       administrator may specify to not let the NLM load anywhere else

  26 **       through this mechanism using ACL assignment restricting rights

  27 **       for the service object to change the "Host Server" attribute."
  28 **    5. Read the NLM service "Description" attribute and display it on the"
  29 **       NLM screen to demonstrate an NLM getting it's configuration from

  30 **       the directory.

  31 **    6. Set the status attribute to UP.

  32 **    7. Display shutdown option.

  33 **    8. During shutdown, set the status attribute to DOWN.

  34 **

  35 **      Disclaimer:

  36 **

  37 **              Novell, Inc. makes no representations or warranties with respect to

  38 **              any NetWare software, and specifically disclaims any express or

  39 **              implied warranties of merchantability, title, or fitness for a

  40 **              particular purpose.

  41 **

  42 **              Distribution of any NetWare software is forbidden without the

  43 **              express written consent of Novell, Inc.  Further, Novell reserves

  44 **              the right to discontinue distribution of any NetWare software.

  45 **

  46 **              Novell is not responsible for lost profits or revenue, loss of use

  47 **              of the software, loss of data, costs of re creating lost data, the 
  48 **              cost of any substitute equipment or program, or claims by any party

  49 **              other than you.  Novell strongly recommends a backup be made before

  50 **              any software is installed.   Technical support for this software

  51 **              may be provided at the discretion of Novell.

  52 **

  53 **      Programmers:

  54 **

  55 **              Ini Who                                     Firm

  56 **                                                                                      
  57 **              MDO Mark Dale Oberg   Novell Developer Services Division

  58 **

  59 */

  60

  61 /****************************************************************************

  62 ** Include headers, macros, structures, typedefs, etc.

  63 */

  64    #include <stdio.h<<
  65         #include <malloc.h<<
  66    #include <string.h<<
  67         #include <conio.h<<
  68    #include <process.h<<
  69    #include <sys/types.h<<
  70    #include     <fcntl.h<<
  71         #include <niterror.h<<
  72         #include <nwdsapi.h<<
  73    #include <nwenvrn.h<<
  74    #include <signal.h<<
  75    #include <nwcntask.h<<
  76    #include <errno.h<<
  77    #include <ctype.h<<
  78    #include "dsaccess.h""
  79

  80         /*                                                                         
  81         ** Macro definitions

  82         */

  83

  84         #define PASSWORD_SIZE 100

  85

  86 /*************************************************************************

  87 ** ExitWithDisplayUsage

  88 */

  89 void ExitWithDisplayUsage(void)

  90         {

  91    printf("Syntax: load exampsrv "service object name"\n");"
  92         printf("Example:load exampsrv exampsrv.devsup.services.novell\n");"
  93    exit(0);

  94    }

  95

  96 /*****************************************************************************

  97 ** GetPassword prompts the user with "Password:" and accepts a string marking"
  98 ** each entered position with an asterisk.  if an <ESC< is entered a EFAILURE is<
  99 ** returned, otherwise ESUCCESS is returned.

 100 */

 101 uint32 GetPassword(char *password, int size)

 102         {

 103         int     index=0;

 104         WORD    x,y;

 105

 106         printf("Password: ");"
 107         y=wherey(); /* find current row */

 108

 109         do

 110                 {

 111                 x=wherex(); /* find current column */

 112                 password[index]=getch();

 113                 if(0x0D==password[index])

 114          {

 115                     password[index]='\0';

 116          }

 117       else if (0x1B==password[index]) /* detect esc */

 118          {

 119          password[0]='\0';

 120          return(EFAILURE);

 121          }

 122       else if(0x08==password[index] && 0&=index&1)      /* Backspace */&
 123                     {

 124                     index =2; 
 125                     gotoxy(x 1,y);                  /* backup */ 
 126                     putch(' ');                             /* clear output */

 127                     gotoxy(x 1,y);                  /* backup */ 
 128                     }

 129                 else

 130                     putch('*');

 131

 132                 index++;

 133                 x++; /* follow cursor position */

 134                 }while (password[index 1]    index size); 
 135

 136         if(index >= size)>
 137       {

 138                 password[0]='\0';

 139       return(EFAILURE);

 140       }

 141

 142         putch('\n');

 143    return(ESUCCESS);

 144         }

 145

 146

 147 /*****************************************************************************

 148 ** StorePasswordToSys() writes the provided password string to sys:system\

 149 ** exampsrv.cfg.  This file is used to store the NLM password between loads

 150 ** in a secure area on the sys:system volume.  It may be wise to modify

 151 ** this routine to encrypt the password file from plain text to protect the

 152 ** service object from administrators that have access to sys:system.

 153 */

 154 uint32 StorePasswordToSys(char *password)

 155    {

 156    FILE *fp;

 157    int length;

 158

 159         fp=fopen("sys:\\system\\exampsrv.cfg", "wb");"
 160         if(NULL == fp)

 161                 {

 162       return ( 1); 
 163       }

 164

 165         length = fwrite(password, sizeof(char), PASSWORD_SIZE, fp);

 166                 if(PASSWORD_SIZE != length)

 167                     {

 168          fclose(fp);

 169          return( 1); 
 170                     }

 171

 172    fclose(fp);

 173    return(0);

 174    }

 175

 176 /****************************************************************************

 177 ** GetPasswordFromSys() looks for the file sys:system\exampsrv.cfg and

 178 ** attempts to read a stored password from the file.

 179 */

 180 uint32 GetPasswordFromSys(char *password)

 181    {

 182    FILE *fp;

 183    int length;

 184

 185         fp=fopen("sys:\\system\\exampsrv.cfg", "rb");"
 186         if(NULL == fp)

 187                 {

 188       return ( 1); 
 189       }

 190

 191         length = fread(password, sizeof(char), PASSWORD_SIZE, fp);

 192                 if(PASSWORD_SIZE != length)

 193                     {

 194          fclose(fp);

 195          return( 1); 
 196                     }

 197

 198    fclose(fp);

 199    return(0);

 200    }

 201

 202 /****************************************************************************

 203 ** GetHostName reads the "Host Server" attribute for the provided object"
 204 */

 205 uint32 GetHostName(NWDSContextHandle cx, char *hostName, char *serverDN)

 206    {

 207    uint32 ccode;

 208         DS_HANDLE   *dsHandle;

 209         READ_DATA   *readData;

 210         char    *attrNames[]={"Host Server",NULL};"
 211

 212         /*                                                                          
 213         **      Opens a dsHandle to use for reading the "Host Server" value"
 214         */

 215         dsHandle=DSReadOpen(cx, attrNames);

 216         if(NULL==dsHandle)

 217                 {

 218                 printf("Failed DSReadOpen.\n");"
 219       ccode=ERR_NOT_ENOUGH_MEMORY;

 220                 goto Exit0;

 221                 }

 222

 223         /*                                                                          
 224         ** Initiates the read

 225         */

 226         ccode=DSReadSeek(

 227                     /*DS_HANDLE *readHandle,*/ dsHandle,

 228                     /*char *baseObjectName,            */ serverDN, /*read first object found on search */

 229                     /*NWDS_TYPE       infoType        )               */ 1   ); /* attribute names and values */

 230         if(ccode)

 231                 {

 232                 printf("Failed DSReadSeek During GetHostName: %d\n",ccode);"
 233                 goto Exit1;

 234                 }

 235

 236         /*                                                                          
 237         ** DSRead returns data until EOF is returned.

 238         */

 239         for(readData=DSRead(dsHandle);NULL !=readData && EOF != readData;readData=DSRead(dsHandle))&
 240                 {

 241                 switch (readData  readType) 
 242                     {

 243                     case ATTR: /* will be "Host Server" */"
 244                     break;

 245

 246                     case ATTR_VALUE:

 247             strcpy(hostName, (char *)readData  read.attrVal.value); 
 248                     }

 249                 free(readData);

 250                 }

 251

 252         if(NULL==readData)

 253                 {

 254                 printf("Failed DSRead.\n");"
 255                 }

 256

 257         /*                                                                          
 258         ** close the handle.

 259         */

 260 Exit1:

 261         DSClose(dsHandle); /* deallocate resources from DSSearchOpen */

 262 Exit0:

 263    return (ccode);

 264    }

 265

 266 /****************************************************************************

 267 ** GetDescription reads the "Description" attribute for the provided object"
 268 */

 269 uint32 GetDescription(NWDSContextHandle cx, char *description, char *serverDN)

 270    {

 271    uint32 ccode;

 272         DS_HANDLE   *dsHandle;

 273         READ_DATA   *readData;

 274         char    *attrNames[]={"Description",NULL};"
 275

 276         /*                                                                          
 277         **      Opens a dsHandle to use for reading the "Host Server" value"
 278         */

 279         dsHandle=DSReadOpen(cx, attrNames);

 280         if(NULL==dsHandle)

 281                 {

 282                 printf("Failed DSReadOpen.\n");"
 283       ccode=ERR_NOT_ENOUGH_MEMORY;

 284                 goto Exit0;

 285                 }

 286

 287         /*                                                                          
 288         ** Initiates the read

 289         */

 290         ccode=DSReadSeek(

 291                     /*DS_HANDLE *readHandle,*/ dsHandle,

 292                     /*char *baseObjectName,            */ serverDN, /*read first object found on search */

 293                     /*NWDS_TYPE       infoType        )    */ 1   ); /* attribute names and values */

 294         if(ccode)

 295                 {

 296                 printf("Failed DSReadSeek: %d\n",ccode);"
 297                 goto Exit1;

 298                 }

 299

 300         /*                                                                          
 301         ** DSRead returns data until EOF is returned.

 302         */

 303         for(readData=DSRead(dsHandle);NULL !=readData && EOF != readData;readData=DSRead(dsHandle))&
 304                 {

 305                 switch (readData  readType) 
 306                     {

 307                     case ATTR: /* will be "Description" */"
 308                     break;

 309

 310                     case ATTR_VALUE:

 311             strcpy(description, (char *)readData  read.attrVal.value); 
 312                     }

 313                 free(readData);

 314                 }

 315

 316         if(NULL==readData)

 317                 {

 318                 printf("Failed DSRead.\n");"
 319                 }

 320

 321         /*                                                                          
 322         ** close the handle.

 323         */

 324 Exit1:

 325         DSClose(dsHandle); /* deallocate resources from DSSearchOpen */

 326 Exit0:

 327    return (ccode);

 328    }

 329

 330

 331 /****************************************************************************

 332 ** SetHostName sets the objects host name

 333 */

 334 NWDSCCODE SetHostName(NWDSContextHandle context, char *serverDN, char *hostName)

 335    {

 336    NWDSCCODE ccode=0;

 337    Buf_T *modifyBuf;

 338    int32 iterationHandle = NO_MORE_ITERATIONS;

 339

 340    ccode=NWDSAllocBuf(DEFAULT_MESSAGE_LEN, &modifyBuf);&
 341         if(ccode)

 342                 {

 343                 goto Exit0;

 344                 }

 345

 346    ccode = NWDSInitBuf(context, DSV_MODIFY_ENTRY, modifyBuf);

 347    if(ccode)

 348         {

 349                 goto Exit1;

 350         }

 351

 352    ccode = NWDSPutChange(context, modifyBuf, DS_REMOVE_ATTRIBUTE,  "Host Server");"
 353         if(ccode)

 354         {

 355                 goto Exit1;

 356         }

 357

 358    ccode = NWDSPutChange(context, modifyBuf, DS_ADD_VALUE, "Host Server");"
 359    if(ccode)

 360         {

 361                 goto Exit1;

 362         }

 363

 364         ccode = NWDSPutAttrVal(context, modifyBuf, SYN_DIST_NAME, hostName);

 365    if(ccode)

 366         {

 367                 goto Exit1;

 368    }

 369

 370    ccode = NWDSModifyObject(context,

 371                     serverDN,

 372                     &iterationHandle,&
 373                     0,

 374                     modifyBuf);

 375 Exit1:

 376    NWDSFreeBuf(modifyBuf);

 377 Exit0:

 378    return(ccode);

 379    }

 380

 381

 382 /****************************************************************************

 383 ** updateFlag() sets the status flag and handles return codes.

 384 */

 385 NWDSCCODE updateFlag(NWDSContextHandle context, char *serverDN, Integer_T flag)

 386 {

 387    NWDSCCODE ccode=0;

 388    Buf_T *modifyBuf;

 389    int32 iterationHandle = NO_MORE_ITERATIONS;

 390

 391    ccode=NWDSAllocBuf(DEFAULT_MESSAGE_LEN, &modifyBuf);&
 392         if(ccode)

 393                 {

 394                 return(ccode);

 395                 }

 396

 397    ccode = NWDSInitBuf(context, DSV_MODIFY_ENTRY, modifyBuf);

 398    if(ccode)

 399         {

 400                 goto Exit1;

 401         }

 402         ccode = NWDSPutChange(context, modifyBuf, DS_REMOVE_ATTRIBUTE,  "Status");"
 403

 404         if(ccode)

 405         {

 406                 goto Exit1;

 407         }

 408

 409         ccode = NWDSPutChange(context, modifyBuf, DS_ADD_VALUE, "Status");"
 410    if(ccode)

 411         {

 412                 goto Exit1;

 413         }

 414

 415         ccode = NWDSPutAttrVal(context, modifyBuf, SYN_INTEGER, &flag);&
 416    if(ccode)

 417         {

 418                 goto Exit1;

 419    }

 420

 421    ccode = NWDSModifyObject(context,

 422                     serverDN,

 423                     &iterationHandle,&
 424                     0,

 425                     modifyBuf);

 426

 427 Exit1:

 428    NWDSFreeBuf(modifyBuf);

 429    return(ccode);

 430    }

 431

 432 /****************************************************************************

 433 **      SetStatusUp() modifies the status attribute of the object to be UP.

 434 */

 435 uint32 SetStatusUp(uint32 cx, char *object)

 436    {

 437    return updateFlag(cx, object, TRUE);

 438    }

 439

 440 /****************************************************************************

 441 **      SetStatusDown() modifies the status attribute of the object to be DOWN.

 442 */

 443 uint32 SetStatusDown(uint32 cx, char *object)

 444    {

 445    return updateFlag(cx, object, FALSE);

 446    }

 447

 448 /****************************************************************************

 449 **      GetLocalHostName gets the local servers DN.

 450 */

 451 uint32 GetLocalHostName(NWDSContextHandle cx, char *hostName)

 452    {

 453    uint32 ccode;

 454         LONG connection;

 455

 456         SetCurrentConnection( 1); /* get a non zero connection to the local host*/ 
 457         connection=GetCurrentConnection();

 458

 459    ccode=NWDSGetServerDN(cx, (int)connection, (char *)hostName);

 460         if(ccode)

 461                 {

 462                 printf("Error during NWDSGetServerDN()");"
 463                 }

 464

 465         ReturnConnection(connection);

 466    return (ccode);

 467    }

 468

 469 /****************************************************************************

 470 **      CreateServiceObject() allows exampsrv.nlm to create a new configuration

 471 ** at load time.  It prompts the user to login as an administrator, provide

 472 ** configuration information and then stores the configuration in DS.

 473 ** After storing the information a key pair is generated with a provided

 474 ** password for the NLM service. The password is stored in sys:system\

 475 ** exampsrv.cfg

 476 */

 477 uint32 CreateServiceObject(NWDSContextHandle cx, char *serviceDN)

 478    {

 479         NWDSCCODE ccode;

 480         Buf_T*addBuffer;

 481         NWDS_ITERATION iteration=NO_MORE_ITERATIONS;

 482    char description[250]="Default configuration";"
 483    char administrator[MAX_DN_CHARS+1];

 484    char hostName[MAX_DN_CHARS+1];

 485    char password[100+1];

 486    char verifyPassword[100+1];

 487    Integer_T status=FALSE;

 488

 489         /*                                                                         
 490         **      Prompt to login as an administrator that can create the service

 491    ** object.

 492         */

 493    printf("Enter administrator name to create object: ");"
 494    gets(administrator);

 495    GetPassword(password, 100);

 496

 497         /*                                                                         
 498         **      Login as the administrator

 499         */

 500         ccode=NWDSLogin(

 501                 /* NWDSContextHandle context, */     cx,

 502                 /* uint32 optionsFlag,            */      0,

 503                 /* char NWFAR *objectName,      */      administrator,

 504                 /* char NWFAR *password,                */      password,

 505                 /* uint32 validityPeriod                */      0 );

 506    if(ccode)

 507       {

 508       printf("Login failed.  Please check administrator name or password and try again.\n");"
 509       goto Exit0;

 510       }

 511

 512         /*                                                                         
 513         **      Get and verify a password to be associated with the server object.

 514         */

 515

 516    printf("Enter in a password to be associated with the service object.\n");"
 517    printf("This password will be the password that is used to authenticate\n");"
 518    printf("the service NLM assocaited with this service object.\n");"
 519

 520    do{

 521       ccode=GetPassword(password,100);

 522       if(ccode)

 523          {

 524          goto Exit1; /* logout and return */

 525          }

 526       printf("\n\nPlease retype the password to ensure it was typed correctly.\n");"
 527       ccode=GetPassword(verifyPassword,100);

 528       if(ccode)

 529          {

 530          goto Exit1; /* logout and return */

 531          }

 532

 533       if(strcmp(password, verifyPassword))

 534          {

 535          printf("The password was entered incorrectly. Please try again or press "ESC" to exit.");"
 536          ccode=EFAILURE;

 537          }

 538       }while(ccode);

 539

 540

 541         /*                                                                         
 542         **      Get service description from user.

 543         */

 544    printf("Enter service description.  This is representative of a service configuration.\n");"
 545    gets(description);

 546    if(!strlen(description))

 547       {

 548       strcpy(description,"Default Description");"
 549       }

 550

 551         /*                                                                         
 552         **      interrogate the local server for a host name.

 553         */

 554    ccode=GetLocalHostName(cx, hostName);

 555    if(ccode)

 556       {

 557       printf("Error GetLocalHostName(): %d\n",ccode);"
 558       goto Exit1;

 559       }

 560

 561         /*                                                                         
 562         **      Proceed to create the service object.

 563         */

 564    ccode=NWDSAllocBuf(DEFAULT_MESSAGE_LEN, &addBuffer);&
 565         if(ccode)

 566                 {

 567                 printf("Error NWDSAllocBuf().\n");"
 568                 goto Exit1;

 569                 }

 570

 571         ccode=NWDSInitBuf(cx, DSV_ADD_ENTRY, addBuffer);

 572    if(ccode)

 573       {

 574       printf("Error NWDSInitBuf()\n");"
 575       goto Exit2;

 576       }

 577

 578         ccode=NWDSPutAttrName(cx, addBuffer, "Object Class");"
 579    if(ccode)

 580       {

 581       printf("Error NWDSPutAttrName()\n");"
 582       goto Exit2;

 583       }

 584

 585         ccode=NWDSPutAttrVal(cx, addBuffer, SYN_CLASS_NAME, "DEVSUP:ExampleNLMService");"
 586    if(ccode)

 587       {

 588       printf("Error NWDSPutAttrVal()\n");"
 589       goto Exit2;

 590       }

 591

 592         ccode=NWDSPutAttrName(cx, addBuffer, "Description");"
 593    if(ccode)

 594       {

 595       printf("Error NWDSPutAttrName()\n");"
 596       goto Exit2;

 597       }

 598

 599         ccode=NWDSPutAttrVal(cx, addBuffer, SYN_CI_STRING, description);

 600    if(ccode)

 601       {

 602       printf("Error NWDSPutAttrVal()\n");"
 603       goto Exit2;

 604       }

 605

 606    ccode=NWDSPutAttrName(cx, addBuffer, "Host Server");"
 607    if(ccode)

 608       {

 609       printf("Error NWDSPutAttrName()\n");"
 610       goto Exit2;

 611       }

 612

 613    ccode=NWDSPutAttrVal(cx, addBuffer, SYN_DIST_NAME, hostName);

 614    if(ccode)

 615       {

 616       printf("Error NWDSPutAttrVal()\n");"
 617       goto Exit2;

 618       }

 619

 620         ccode=NWDSPutAttrName(cx, addBuffer, "Status");"
 621    if(ccode)

 622       {

 623       printf("Error NWDSPutAttrName()\n");"
 624       goto Exit2;

 625       }

 626

 627    ccode=NWDSPutAttrVal(cx, addBuffer, SYN_INTEGER, (void *)&status);&
 628    if(ccode)

 629       {

 630       printf("Error NWDSPutAttrVal()\n");"
 631       goto Exit2;

 632       }

 633

 634         ccode=NWDSAddObject(cx, serviceDN, &iteration, 0, addBuffer);&
 635         if(ccode)

 636                 {

 637                 printf("Error: NWDSAddObject(, %s,):%d",serviceDN, ccode);"
 638       goto Exit2;

 639                 }

 640

 641         /*                                                                         
 642         **      Associate an object key pair generated with the provided password

 643         */

 644         ccode=NWDSGenerateObjectKeyPair(cx, serviceDN, password, 0);

 645         if(ccode)

 646                 {

 647                 printf("Error NWDSGenerateObjectKeyPair(%s): %d",serviceDN,ccode);"
 648       goto Exit2;

 649                 }

 650

 651         /*                                                                         
 652         **      Store the service object password so that it comes up automatically

 653    ** next time.

 654         */

 655    ccode=StorePasswordToSys(password);

 656    if(ccode)

 657       {

 658       printf("password storage failed.");"
 659       }

 660

 661 Exit2:

 662         NWDSFreeBuf(addBuffer);

 663 Exit1:

 664    NWDSLogout(cx);

 665 Exit0:

 666    return(ccode);

 667    }

 668

 669 /****************************************************************************

 670 **      Program flow is fully contained in main.  Procedures are used to

 671 ** encapsulate implementation details.

 672 */

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

 674 {

 675    uint32 passwordFromFile=FALSE;

 676         NWDSContextHandle cx;

 677         NWDSCCODE   ccode;

 678    uint32 flags;

 679         char    password[255+1];

 680         char    description[255+1];

 681         char    dn[MAX_DN_CHARS+1];

 682         char    hostName[MAX_DN_CHARS+1];

 683         char    localHostName[MAX_DN_CHARS+1];

 684         Object_Info_T objectInfo;

 685    char key;

 686

 687    /*                                                                         
 688         **      Check command line args.

 689         */

 690    if(argc != 2)

 691       ExitWithDisplayUsage();

 692

 693         /*                                                                         
 694         **      Create a context for ds calls to use

 695         */

 696    cx=NWDSCreateContext();

 697         if(ERR_CONTEXT_CREATION == cx)                     /* error if negative value */

 698                 {

 699                 printf("Error creating context.\n");"
 700                 exit(0);

 701       }

 702

 703         /*                                                                         
 704         **      Clear the canonicalize flag so that all NDS names are reqiored to be

 705    ** full distinguished names relative to [Root].

 706         */

 707         ccode=NWDSGetContext(cx, DCK_FLAGS, &flags);&
 708         if(ccode)

 709                 {

 710                 printf("Error NWDSGetContext(): %d\n",ccode);"
 711                 goto Exit1;

 712                 }

 713

 714    flags ^= DCV_CANONICALIZE_NAMES;

 715

 716         ccode=NWDSSetContext(cx, DCK_FLAGS, &flags);&
 717         if(ccode)

 718                 {

 719                 printf("Error NWDSSetContext(): %d\n",ccode);"
 720                 goto Exit1;

 721                 }

 722

 723    /*                                                                         
 724         **      Does the specified service object exist?

 725         */

 726    ccode=NWDSReadObjectInfo(cx, argv[1], dn, &objectInfo);&
 727    if( 601==ccode) 
 728       {

 729       printf("The provided object \"%s\" does not exist.  Would you like to\n",argv[1]);"
 730       printf("create this service object? (Y/N)");"
 731       key=toupper(getch());

 732       putch('\n');

 733       if(key == 'Y')

 734          {

 735          ccode=CreateServiceObject(cx, argv[1]); /* create the service object */

 736          if(EFAILURE==ccode)

 737             {

 738             printf("Shuting down without creating service object.\n");"
 739             goto Exit1;

 740             }

 741          else if(ccode)

 742             {

 743             printf("serviceObject creation failed.\n");"
 744             goto Exit1;

 745             }

 746          }

 747       else if(ccode !=0)

 748          {

 749          goto Exit1; /* free context */

 750          }

 751       }

 752

 753         /*                                                                         
 754         **      Try getting password from sys:system, if not prompt for a valid password

 755         */

 756    ccode=GetPasswordFromSys(password); /* check for password in sys:system */

 757    if(ccode)

 758       {

 759       passwordFromFile=FALSE;

 760       printf("Enter a password for %s.\n",argv[1]);"
 761       GetPassword(password,255); /* prompt for password at command line */

 762       }

 763    else

 764       {

 765       passwordFromFile=TRUE;

 766       }

 767

 768         /*                                                                         
 769         **      Try logging in.  If  669 prompt for password.  If  601, prompt if a 
 770    ** new service object is to be created.

 771         */

 772         ccode=NWDSLogin(

 773                 /* NWDSContextHandle context, */     cx,

 774                 /* uint32 optionsFlag,            */      0,

 775                 /* char NWFAR *objectName,      */      argv[1],

 776                 /* char NWFAR *password,                */      password,

 777                 /* uint32 validityPeriod                */      0 );

 778

 779         switch(ccode)

 780       {

 781       /* password was incorrect, if from file allow for update */

 782       case  669: 
 783          if(passwordFromFile==TRUE)

 784             {

 785             printf("The stored password for %s is invalid.  Please enter the\n",argv[1]);"
 786             printf("correct password to update the stored password.\n");"
 787             GetPassword(password,255); /* prompt user for a password */

 788                  ccode=NWDSLogin(

 789                     /* NWDSContextHandle   context, */     cx,

 790                     /* uint32      optionsFlag,            */      0,

 791                     /* char NWFAR *objectName,     */      argv[1],

 792                     /* char NWFAR *password,               */      password,

 793                     /* uint32 validityPeriod               */      0 );

 794             if(ccode)

 795                {

 796                printf("Login failed.  Please check service object name provided\n");"
 797                printf("on the load line and password.\n");"
 798                goto Exit1;

 799                }

 800             else

 801                {

 802                ccode=StorePasswordToSys(password);

 803                if(ccode)

 804                   {

 805                   printf("Failure to store password.");"
 806                   }

 807                }

 808             }

 809          else

 810             {

 811             printf("The password you provided is incorrect.  Service load failed.\n");"
 812             goto Exit1;

 813             }

 814          break;

 815

 816       case 0:  /* success */

 817          break;

 818       default:

 819                 printf("NWDSLogin failure ccode: %d\n",ccode);"
 820       goto Exit1;

 821       }

 822

 823    /*                                                                         
 824         **      Determine if loading on same host.

 825         */

 826    GetLocalHostName(cx, localHostName);

 827

 828    GetHostName(cx, hostName, argv[1]);

 829

 830    if(strcmp(localHostName, hostName))

 831       {

 832       SetHostName(cx, hostName, argv[1]);

 833       }

 834

 835         /*                                                                         
 836         **      Set the status attribute to UP.

 837         */

 838    ccode=SetStatusUp(cx,argv[1]);

 839    if(ccode)

 840       {

 841       printf("SetStatusUp() failed %d.\n",ccode);"
 842       goto Exit2;

 843       }

 844

 845         /*                                                                         
 846         **      Read the NLM service "Description" attribute and display it on the"
 847    ** NLM screen to demonstrate an NLM getting it's configuration from

 848    ** the directory.

 849         */

 850    ccode=GetDescription(cx, description, argv[1]);

 851    if(ccode)

 852       {

 853       printf("Error during GetDescription(): %d\n",ccode);"
 854       goto Exit2;

 855       }

 856

 857    clrscr();

 858    printf("EXAMPSRV service is running as %s with a\n",argv[1]);"
 859    printf("Description: %s\n",description);"
 860

 861         /*                                                                         
 862         **      Display shutdown option, wait for NLM user to shutdown.  Also register

 863    ** for the down server event.

 864         */

 865    printf("Press any key to shutdown");"
 866    while(!kbhit())

 867       {

 868       delay(1);

 869       }

 870

 871         /*                                                                         
 872         **      Set the status attribute to DOWN.

 873         */

 874    ccode=SetStatusDown(cx,argv[1]);

 875    if(ccode)

 876       {

 877       printf("SetStatusDown() failed %d.\n",ccode);"
 878       }

 879

 880 Exit2:

 881         NWDSLogout(cx);

 882 Exit1:

 883    NWDSFreeContext(cx);

 884 }

* 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