PMDF popstore & MessageStore Manager's Guide


Previous Contents Index


Chapter 14
Miscellaneous Subroutines

Sites can override five aspects of the popstore and MessageStore by providing callable subroutines:

The first two subroutines are only of interest to sites which bill users for connect time or disk storage and want to change how the popstore and MessageStore computes those quantities; see Section 14.1 for details. The next two subroutines are of interest to sites who want to spread the popstore/msgstore user or message files across multiple disks as described in Section 14.2.1

The last subroutine is of interest to sites who want to increase the security of popstore/msgstore passwords for example by comparing the proposed password to a dictionary or to a site-maintained history of previous passwords. See Section 14.3.

Note

1 Note that on UNIX systems, this can be done using symbolic links; the popstore/msgstore will correctly follow hard and symbolic links.

14.1 Computation Subroutines

By default, the popstore/msgstore uses straightforward algorithms to compute elapsed connect times and disk storage over time:


elapsed_time := end_time - start_time 
storage := (end_time - start_time) / (86400 seconds/hour) * 
              size / (1024 bytes/block) 
where the quantities above have the following interpretations:

elapsed_time

Elapsed time measured in units of seconds.

end_time

Ending time measured in units of seconds elapsed since 1 January 1970 at 0:00:00.0.

start_time

Starting time measured in units of seconds elapsed since 1 January 1970 at 0:00:00.0.

storage

Amount of storage as measured in units of block days with 1 block equal to 1024 bytes.

size

Size of the stored object as measured in units of bytes.

Sites wanting to use different algorithms can do so by supplying executable subroutines via shared images. The subroutine to compute the elapsed time must have the name compute_connect and be of the form


 
#include <time.h> 
#ifdef __VMS 
#  include "pmdf_com:popstore.h" 
#else 
#  include "/pmdf/include/popstore.h" 
#endif 
 
uint32 compute_connect (start_time, end_time) 
  time_t start_time; 
  time_t end_time; 
 
The calling arguments for compute_connect are as described below and the subroutine must return the elapsed time, as measured in seconds, between the starting and ending times:

start_time

Starting time measured in units of seconds elapsed since 1 January 1970 at 0:00:00.0. Used for input only.

end_time

Ending time measured in units of seconds elapsed since 1 January 1970 at 0:00:00.0. Used for input only.

A C code realization of the default algorithm used by the popstore/msgstore to compute connect time is given in Example 14-1.

Example 14-1 Default compute_connect Subroutine

 
#include <time.h> 
#ifdef __VMS 
#  include "pmdf_com:popstore.h" 
#else 
#  include "/pmdf/include/popstore.h" 
#endif 
 
uint32 compute_connect (start_time, end_time) 
  time_t start_time; 
  time_t end_time; 
{ 
  return ((uint32)difftime (end_time, start_time)); 
} 
 

The subroutine to compute storage must have the name compute_block_days and be of the form


 
#include <time.h> 
#ifdef __VMS 
#  include "pmdf_com:popstore.h" 
#else 
#  include "/pmdf/include/popstore.h" 
#endif 
 
void compute_block_days (start_time, end_time, size, result, 
                         remainder) 
  time_t  start_time; 
  time_t  end_time; 
  uint32  size; 
  uint32 *result; 
  uint32 *remainder; 
 
The input arguments to the subroutine are described below. On output, the subroutine must return in *result the storage as measured in units of block days. In addition, the subroutine must return in *remainder any roundoff, as measured in byte seconds.

start_time

Starting time measured in units of seconds elapsed since 1 January 1970 at 0:00:00.0. Used for input only.

end_time

Ending time measured in units of seconds elapsed since 1 January 1970 at 0:00:00.0. Used for input only.

result

Amount of storage as measured in units of block days with 1 block equal to 1024 bytes. Used for output only.

remainder

Roundoff in storage as measured in units of byte seconds. Used for input and output. On input, this will be the roundoff left over from a previous computation and which should be incorporated into this new computation. On output, this should be set to the roundoff resulting from computing the result.

The default subroutine used by the popstore/msgstore is shown in Example 14-2.

Example 14-2 Default compute_block_days Subroutine

 
#include <time.h> 
#ifdef __VMS 
#  include "pmdf_com:popstore.h" 
#else 
#  include "/pmdf/include/popstore.h" 
#endif 
 
void compute_block_days (start_time, end_time, size, result, 
                         remainder) 
  time_t  start_time; 
  time_t  end_time; 
  uint32  size; 
  uint32 *result; 
  uint32 *remainder; 
{ 
  double blocks, days, value; 
 
  days       = difftime (end_time, start_time) / 86400.0; 
  blocks     = size / 1024.0; 
  value      = (days * blocks) + (*remainder / (86400.0 * 1024.0)); 
  *result    = (uint32)value; 
  *remainder = (uint32)((value - (uint32)value) * 86400.0 * 1024.0); 
} 
 

The COMPUTE_CONNECT and COMPUTE_BLOCK_DAYS options must be used to point the popstore/msgstore at the shared image or images containing the compute_connect and compute_block_days subroutines. See Section 3.4 for details. When linking the subroutines into shared images, use link commands of the forms shown in Section 13.2.1. The subroutines can be tested with the TEST command of the command line management utility.

14.2 File Locations

By default, the popstore/msgstore stores all message files on the same disk as described in Section 1.4. Likewise for account profile files as described in Section 1.3.9. On UNIX systems, links --- symbolic or hard --- can be used to relocate subdirectories in these trees thereby allowing files to be spread across any number of disks. The popstore/msgstore will automatically handle such links; no special configuration of the popstore/msgstore is required to accomodate links.

Sites wanting to relocate the entire message or profile directory tree to another disk should do so using either the UNIX PMDF tailor file, the NT registry, or the OpenVMS popstore/msgstore logicals. On UNIX and NT systems, manually move the tree in question and change the corresponding PMDF_POPSTORE_MESSAGES or PMDF_POPSTORE_PROFILES entry in the /etc/pmdf_tailor file (UNIX) or registry (NT). On OpenVMS systems, manually move the directory tree in question and then change the corresponding definition of the PMDF_POPSTORE_MESSAGES or PMDF_POPSTORE_PROFILES logical. Changing the values of those logicals is best done by first seeing how they are defined in the pmdf_startup.com procedure in the SYS$STARTUP: directory. Then, create a pmdf_site_startup.com command procedure which redefines the logicals, pointing to the correct disk and directory. Place that command procedure in the PMDF_COM: directory. It will then be seen and executed by PMDF each time you boot your system.

Now, some sites can want to actually spread message or profile files across more than one disk. Again, UNIX systems can use symbolic links to accomplish this. However, OpenVMS systems lack such a mechanism. Consequently, an alternate mechanism for relocating files is provided for all platforms. This mechanism involves the use of site-supplied subroutines made available to the popstore/msgstore via shared images. When the popstore/msgstore needs to access a message or a profile file, it first generates a default path to the file and then checks for a site-supplied subroutine. If the subroutine does not exist, the default path is used. If the subroutine does exist, it is called with the file path and filename in question. The subroutine can then change the path to the file; the popstore/msgstore will use the changed path to access the file. In addition to supplying subroutines, text files listing the path to each directory tree must also be supplied. These text files are used when the popstore/msgstore must search for a message or profile file.

Note

Only use this mechanism when actually spreading a profile or message file directory tree across more than one disk. Using this mechanism when merely moving an entire profile or message file directory tree to another disk is not worth the effort required and can be accomplished more easily using previously described mechanisms.

The name of the subroutine to map message file filenames is map_message_filename; the name of the subroutine to map account profile filenames is map_profile_filename. Their existence and location are made known to the popstore/msgstore using the MAP_MESSAGE_FILENAME and MAP_PROFILE_FILENAME options documented in Sections 3.4 and 3.3, respectively. Sites can supply one or both of these subroutines. When linking the subroutines into shared images, use link commands of the forms given in Section 13.2.1.

The subroutines take the form


 
#ifdef __VMS 
#  include "pmdf_com:popstore.h" 
#else 
#  include "/pmdf/include/popstore.h" 
#endif 
 
void map_message_filename (version, def_name, def_len, def_path_len, 
                           new_name, new_len, max_new_len, new_path_len) 
  uint32 version 
  char   *def_name; 
  int     def_len; 
  int     def_path_len; 
  char   *new_name; 
  int    *new_len; 
  int     max_new_len; 
  int    *new_path_len; 
 
void map_profile_filename (version, def_name, def_len, def_path_len, 
                           new_name, new_len, max_new_len, new_path_len) 
  uint32 version 
  char   *def_name; 
  int     def_len; 
  int     def_path_len; 
  char   *new_name; 
  int    *new_len; 
  int     max_new_len; 
  int    *new_path_len; 
 
The input and output arguments to the subroutines are as follows:

version

For map_message_filename, this argument is the current value of the MESSAGE_FILENAME_VERSION option. For map_profile_filename, this argument is the current value of the PROFILE_FILENAME_VERSION option. Used for input only.

def_name

The default file specification including the full path and filename. This string is NULL terminated. Used for input only.

def_len

The length in bytes of the default file specification. The length does not include any NULL terminator. Used for input only.

def_path_len

The length in bytes of the path specification in the default file specification. That is, the first def_path_len bytes of def_name is the path specification for the file. Used for input only.

new_name

The new file specification which should be used. This must include both the full path and filename for the file and must be NULL terminated. Note that the filename portion of the file specification must not be altered; only the path specification portion of the file specification can be changed. The default directory name in the path should not be removed---it is part of the popstore's user domain naming system. default is the default user domain. Used for output only.

new_len

The length in bytes, not including the NULL terminator, of the new file specification. Used for output only.

max_new_len

Maximum length in bytes of new_name, not including a trailing NULL terminator. The name passed back in new_name can not exceed this length. Used for input only. Note that the following relationship will always hold:
def_path_len <= 252 bytes <= max_new_len

new_path_len

The length in bytes of the path specification portion of the new file specification. Used for output only.

The site-supplied subroutine is passed the default file specification and must return on output a new file specification. If no change is to be made to the file specification, then the input arguments should simply be copied to the output arguments. If a change is made, the resulting file specification must have the same filename. The subroutine can only change the path portion of the file specification. (On OpenVMS systems, this is the device and directory portion of the specification.) Moreover, for profile file names, the default directory name should be left untouched. That name is part of the popstore's user domain naming system.

Note that for message filenames, the last character in the filename portion of the specification indicates the value of the MESSAGE_FILENAME_VERSION option which was in force when the message file in question was initially created. The default value for that option is 0. When implementing a map_message_filename subroutine, it is a good idea to increment that value to 1. Then your subroutine can distinguish between files generated when no algorithm was in place and files generated when an algorithm was first used. Yes, there's no immediate value in doing this. However, should you then change your algorithm, you will then want to distinguish between your new algorithm and your old algorithm. When you change your algorithm, then again increment the version number. You can then distinguish between the no algorithm case, version 0, the original algorithm case, version 1, and the revised algorithm case, version 2.

The command line management utility includes a TEST command which should be used to test map_message_filename and map_profile_filename subroutines. Use that utility to test your subroutines before integrating them into the popstore with the MAP_MESSAGE_FILENAME and MAP_PROFILE_FILENAME options. Moreover, when you use that TEST command, the utility will tell you how each message or profile filename would be mapped by your subroutine. That information is provided for each message or user account currently used by the popstore. You can use that information to help relocate each popstore file to the correct new location required by your subroutine.

When a map_message_filename subroutine is provided, you must also supply a corresponding popstore_message_paths file. That file is a world readable text file which should be placed in the PMDF table directory. For each top-level directory tree used to store message files, a path to that tree must be given in the text file. One path per line in the file. Similarly, when a map_profile_filename subroutine is provided, a corresponding popstore_profile_paths file must be provided in the PMDF table directory. These files are then used by the popstore when it must conduct scans for message or profile files. Scans for profile files are only done to rebuild the user database or to test a map_profile_filename subroutine. However, scans for message files happen regularly when the popstore's message bouncer runs. An example file is given in Example 14-4.

A sample map_profile_filename is shown in Example 14-3. That sample subroutine implements, for UNIX systems, a directory tree split as depicted below:
Default filename New filename
/pmdf/user/default/a/* /disk0/profiles/default/a/*
... ...
/pmdf/user/default/m/* /disk0/profiles/default/m/*
   
/pmdf/user/default/n/* /disk1/profiles/default/n/*
... ...
/pmdf/user/default/z/* /disk1/profiles/default/z/*
   
/pmdf/user/default/0/* /disk2/profiles/default/0/*
... ...
/pmdf/user/default/9/* /disk2/profiles/default/9/*
For example, the profile file normally stored in /pmdf/user/default/r/o/b/rob is relocated to /disk1/profiles/default/r/o/b/rob. The popstore_profile_paths file corresponding to this mapping is shown in Example 14-4.

Example 14-3 UNIX map_profile_filename Sample Subroutine

 
#include <string.h> 
#include "/pmdf/include/popstore.h" 
 
void map_profile_filename (uint32 version, char *def_name, 
                           int def_len, int def_path_len, 
                           char *new_name, int *new_len, 
                           int max_new_len, int *new_path_len) 
{ 
  char c; 
  /* 
   *  We assume that def_name will be of the form 
   *  /pmdf/user/domain/x/y/z/filename.  This assumption is 
   *  governed by the value of the option PMDF_POPSTORE_PROFILES 
   *  in the /etc/pmdf_tailor file. 
   */ 
  strcpy (new_name, "/disk#/profiles/"); 
  c = def_name[def_path_len-6]; 
  if ('a' <= c && c <= 'm') new_name[5] = '0'; 
  else if ('n' <= c && c <= 'z') new_name[5] = '1'; 
  else new_name[5] = '2'; 
  strcat (&new_name[16], &def_name[11]); 
  *new_path_len = def_path_len + 5; 
  *new_len = strlen (new_name); 
} 
 

Example 14-4 UNIX /pmdf/table/popstore_profile_paths Sample File

/disk0/profiles/ 
/disk1/profiles/ 
/disk2/profiles/ 

A similar example for OpenVMS systems is shown in Examples 14-5 and 14-6. That sample subroutine implements, the directory tree split as depicted below:
Default filename New filename
PMDF_POPSTORE_PROFILES:[DEFAULT.A...]*.; DISK0:[PROFILES.DEFAULT.A...]*.;
... ...
PMDF_POPSTORE_PROFILES:[DEFAULT.M...]*.; DISK0:[PROFILES.DEFAULT.M...]*.;
   
PMDF_POPSTORE_PROFILES:[DEFAULT.N...]*.; DISK1:[PROFILES.DEFAULT.N...]*.;
... ...
PMDF_POPSTORE_PROFILES:[DEFAULT.Z...]*.; DISK1:[PROFILES.DEFAULT.Z...]*.;
   
PMDF_POPSTORE_PROFILES:[DEFAULT.0...]*.; DISK2:[PROFILES.DEFAULT.0...]*.;
... ...
PMDF_POPSTORE_PROFILES:[DEFAULT.9...]*.; DISK2:[PROFILES.DEFAULT.9...]*.;
For example, the profile file normally stored in


PMDF_POPSTORE_PROFILES:[DEFAULT.R.O.B]rob.; 
is relocated to


DISK1:[PROFILES.DEFAULT.R.O.B]rob. 
The popstore_profile_paths file corresponding to this mapping is shown in Example 14-6.

Example 14-5 OpenVMS map_profile_filename Sample Subroutine

 
#include <string.h> 
#include "pmdf_com:popstore.h" 
 
void map_profile_filename (uint32 version, char *def_name, 
                           int def_len, int def_path_len, 
                           char *new_name, int *new_len, 
                           int max_new_len, int *new_path_len) 
{ 
  char c; 
   *  We assume that def_name will be of the form 
   *  PMDF_POPSTORE_PROFILES:[DEFAULT.X.Y.Z]filename. 
   */ 
  strcpy (new_name, "DISK#:[PROFILES.DEFAULT.X.Y.Z]"); 
  c = def_name[def_path_len-6]; 
  if ('a' <= c && c <= 'm') new_name[4] = '0'; 
  else if ('n' <= c && c <= 'z') new_name[4] = '1'; 
  else new_name[4] = '2'; 
  strcat (&new_name[16], &def_name[24]); 
  *new_path_len = def_path_len + 8; 
  *new_len = strlen (new_name); 
} 
 

Example 14-6 OpenVMS PMDF_TABLE:popstore_profile_paths. Sample File

DISK0:[PROFILES...]*.;* 
DISK1:[PROFILES...]*.;* 
DISK2:[PROFILES...]*.;* 

14.3 Subroutine To Validate A Password

The popstore/msgstore has support for certain reasonableness checks on a proposed password when a user or administrator attempts to change an account's password. The validate_password subroutine can be specified by sites who wish to add additional validation, such as a dictionary or history check.

The validate_password subroutine's existence and location are made known to the popstore/msgstore using the VALIDATE_PASSWORD option documented in Section 3.3. When linking this subroutine into a shared image, use link commands of the forms given in Section 13.2.1.

The subroutine takes the form


 
#ifdef __VMS 
#include "pmdf_com:popstore.h" 
#else 
#include "/pmdf/include/popstore.h" 
#endif 
 
int validate_password (password, password_len, username, username_len, 
                       errmsg, errmsg_len, errmsg_max) 
    char *password; 
    int password_len; 
    char *username; 
    int username_len; 
    char *errmsg; 
    int *errmsg_len; 
    int errmsg_max; 
 
The input and output arguments to the subroutines are as follows:

password

The new password. Used for input only.

password_len

The length in bytes of the new password, not including any NULL terminator. Used for input only.

username

The username of the account whose password is being changed. Used for input only.

username_len

The length in bytes of the username, not including any NULL terminator. Used for input only.

errmsg

Address of a character array that validate_password should put an error message into if the password validation fails. The length of the message must not be longer than errmsg_max bytes. Used for output only.

errmsg_len

The length in bytes of the error message that validate_password put into the errmsg array. Set this to 0 if no error message was placed there. Used for output only.

errmsg_max

The size in bytes of the character array that errmsg points to. Used for input only.

The validate_password subroutine should return one of the following statuses:

POPSTORE_SUCCESS

If the password passed all validation checks and was accepted.

POPSTORE_PWDNOTOK

If the password failed a validation check and was rejected.

A sample validate_password routine is shown in Example 14-7 and can be found at, on OpenVMS:


PMDF_ROOT:[DOC.EXAMPLES]POPSTORE_VALIDATE_PASSWORD.C 
And on UNIX:


/pmdf/doc/examples/popstore_validate_password.c 

Example 14-7 validate_password Sample Subroutine

 
#ifdef __VMS 
#include "pmdf_com:popstore.h" 
#else 
#include "/pmdf/include/popstore.h" 
#endif 
#include <string.h> 
 
int validate_password (char *password, int password_len, 
                       char *username, int username_len, 
                       char *errmsg, int *errmsg_len, int errmsg_max) 
{ 
#define MSG "Password rejected by validate_password" 
 
    (*errmsg_len) = 0; 
    errmsg[0] = '\0'; 
 
    /* for example, reject a password of "invalid", otherwise accept */ 
    if ((password_len == 7) && 
        (password[0] == 'i') && 
        (password[1] == 'n') && 
        (password[2] == 'v') && 
        (password[3] == 'a') && 
        (password[4] == 'l') && 
        (password[5] == 'i') && 
        (password[6] == 'd')) 
    { 
        (*errmsg_len) = (strlen(MSG)>errmsg_max ? errmsg_max : strlen(MSG)); 
        strncpy (errmsg, MSG, (*errmsg_len)); 
        return (POPSTORE_PWDNOTOK); 
    } 
    else 
        return (POPSTORE_SUCCESS); 
} 
 


Index Contents