Skip to main content
A while back, D3 introduced the concept of Host Authentication to give users the ability to manage passwords and password standards using O/S authentication ( Active Directory, LDAP, whatever ). This is detailed in the D3 System Administration Guides:

https://www3.rocketsoftware.com/rocketd3/support/documentation/d3nt/103/admin/index.htm
https://www3.rocketsoftware.com/rocketd3/support/documentation/d3linux/103/admin/index.htm
https://www3.rocketsoftware.com/rocketd3/support/documentation/AIX/103/admin/index.htm

While that is a really good thing to implement and highly recommended by Rocket D3 staff, including myself, sometimes it can be a bit challenging to implement. For those of you who simply want a way to enforce D3 password standards ( expiry, history, length, character content ) from within D3 itself, you might want to take a look at this program I wrote for an end user. To implement it, you would call this program from the USERS file item logon macro ( somewhere after TERM-TYPE on A12 and before you LOGTO any account ) and create a file in DM ( or somewhere else with a Q-pointer thereto from DM ). Details in the program comments. Have a look, enjoy, and please post any comments, improvements or other points of view herein.

* userpwd.pgm - bsc 09/29/21
*
* Manage password criteria:
* Expiry
* Length
* Character content
* History
*
* NOTE: D3 supports multiple user passwords in
* A7 of the users item, support for that
* not yet implemented in this program
*
  prompt ''
  open 'users' to f.users else stop
*
* userpwd file must exist either in DM
* or Q-pointed from DM, else program disabled
*
  open 'userpwd' to f.pwd else stop
  read uitem from f.users,@user else stop
*
* If no current password, program disabled
*
  pwcur = uitem<7,1>
  if len(pwcur) = 8 else stop
*
* Set up expiry days, password history count
* and valid character constants
*
  pwexp = 90
  pwcnt = 6
  nchar = "0123456789"
  uchar = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
  lchar = "abcdefghijklmnopqrstuvwxyz"
  schar = "!#$%_-"
*
* Read the userpwd item or initialize and make
* sure the current password exists in history
*
  read pitem from f.pwd,@user else
    pitem = uitem<7,1>
    pitem<2> = date()
  end
  locate pwcur in pitem<1> setting ix else
    pitem<pwcnt> = ""
    ins pwcur before pitem<1,1>
    del pitem<1,pwcnt+1>
  end
  write pitem on f.pwd,@user
*
* Set up expiry date and check to see if the
* current password is expired or will soon,
* prompt for new password in either case
*
  dtexp = pitem<2> + pwexp
  begin case
    case dtexp <= date()
      crt "Password is expired"
      gosub EnterPwd
      if pwnew = "" then execute "off"
    case dtexp <= (date() + 15)
      crt "Password expires in ":(dtexp - date()):" day(s)"
      crt "Change Password (y)?":
      input yesno
      if yesno[1,1] = "y" then
        gosub EnterPwd
        if pwnew = "" then execute "off"
      end
  end case
*
stop
*
EnterPwd:
*
* If any failure to meet standards,
* pwnew set to null telling main
* program to fail and log user off
*
  casing on
  crt "Enter new password: ":
  echo off
  input pwnew
  echo on
*
  pwlen = len(pwnew)
  if pwlen < 8 then
    crt "Failed: shorter than 8 characters"
    pwnew = ""
  end else
    isnum = 0
    islow = 0
    isupr = 0
    isspc = 0
    for px = 1 to pwlen
      wch = pwnew[px,1]
      if index(nchar,wch,1) then isnum = 1
      if index(uchar,wch,1) then isupr = 1
      if index(lchar,wch,1) then islow = 1
      if index(schar,wch,1) then isspc = 1
    next px
  end
*
  begin case
    case not(isnum)
      crt "Failed: no numeric characers (":nchar:")"
      pwnew = ""
    case not(isupr)
      crt "Failed: no upper-case characers (":uchar:")"
      pwnew = ""
    case not(islow)
      crt "Failed: no lower-case characers (":lchar:")"
      pwnew = ""
    case not(isspc)
      crt "Failed: no special characers (":schar:")"
      pwnew = ""
  end case
*
* Reenter password to make sure they match
*
  if pwnew = "" else
    crt "Reenter new password: ":
    echo off
    input w
    echo on
    if w = pwnew else
      crt "Passwords do not match."
      pwnew = ""
    end
  end
*
* Make sure new password is not in recent usage list
*
  if pwnew = "" else
    pwnew = iconv(pwnew,"u0c")
    locate pwnew in pitem<1> setting ix then
      crt "Failed: password recently used"
      pwnew = ""
    end else
*
* If everything good, update password history
* file and write new password on users file
*
      writev pwnew on f.users,@user,7
      ins pwnew before pitem<1,1>
      del pitem<1,pwcnt+1>
      pitem<2> = date()
      write pitem on f.pwd,@user
    end
  end
  casing off
return
*
* End of source



------------------------------
Brian S. Cram
Principal Technical Support Engineer
Rocket Software
------------------------------
A while back, D3 introduced the concept of Host Authentication to give users the ability to manage passwords and password standards using O/S authentication ( Active Directory, LDAP, whatever ). This is detailed in the D3 System Administration Guides:

https://www3.rocketsoftware.com/rocketd3/support/documentation/d3nt/103/admin/index.htm
https://www3.rocketsoftware.com/rocketd3/support/documentation/d3linux/103/admin/index.htm
https://www3.rocketsoftware.com/rocketd3/support/documentation/AIX/103/admin/index.htm

While that is a really good thing to implement and highly recommended by Rocket D3 staff, including myself, sometimes it can be a bit challenging to implement. For those of you who simply want a way to enforce D3 password standards ( expiry, history, length, character content ) from within D3 itself, you might want to take a look at this program I wrote for an end user. To implement it, you would call this program from the USERS file item logon macro ( somewhere after TERM-TYPE on A12 and before you LOGTO any account ) and create a file in DM ( or somewhere else with a Q-pointer thereto from DM ). Details in the program comments. Have a look, enjoy, and please post any comments, improvements or other points of view herein.

* userpwd.pgm - bsc 09/29/21
*
* Manage password criteria:
* Expiry
* Length
* Character content
* History
*
* NOTE: D3 supports multiple user passwords in
* A7 of the users item, support for that
* not yet implemented in this program
*
  prompt ''
  open 'users' to f.users else stop
*
* userpwd file must exist either in DM
* or Q-pointed from DM, else program disabled
*
  open 'userpwd' to f.pwd else stop
  read uitem from f.users,@user else stop
*
* If no current password, program disabled
*
  pwcur = uitem<7,1>
  if len(pwcur) = 8 else stop
*
* Set up expiry days, password history count
* and valid character constants
*
  pwexp = 90
  pwcnt = 6
  nchar = "0123456789"
  uchar = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
  lchar = "abcdefghijklmnopqrstuvwxyz"
  schar = "!#$%_-"
*
* Read the userpwd item or initialize and make
* sure the current password exists in history
*
  read pitem from f.pwd,@user else
    pitem = uitem<7,1>
    pitem<2> = date()
  end
  locate pwcur in pitem<1> setting ix else
    pitem<pwcnt> = ""
    ins pwcur before pitem<1,1>
    del pitem<1,pwcnt+1>
  end
  write pitem on f.pwd,@user
*
* Set up expiry date and check to see if the
* current password is expired or will soon,
* prompt for new password in either case
*
  dtexp = pitem<2> + pwexp
  begin case
    case dtexp <= date()
      crt "Password is expired"
      gosub EnterPwd
      if pwnew = "" then execute "off"
    case dtexp <= (date() + 15)
      crt "Password expires in ":(dtexp - date()):" day(s)"
      crt "Change Password (y)?":
      input yesno
      if yesno[1,1] = "y" then
        gosub EnterPwd
        if pwnew = "" then execute "off"
      end
  end case
*
stop
*
EnterPwd:
*
* If any failure to meet standards,
* pwnew set to null telling main
* program to fail and log user off
*
  casing on
  crt "Enter new password: ":
  echo off
  input pwnew
  echo on
*
  pwlen = len(pwnew)
  if pwlen < 8 then
    crt "Failed: shorter than 8 characters"
    pwnew = ""
  end else
    isnum = 0
    islow = 0
    isupr = 0
    isspc = 0
    for px = 1 to pwlen
      wch = pwnew[px,1]
      if index(nchar,wch,1) then isnum = 1
      if index(uchar,wch,1) then isupr = 1
      if index(lchar,wch,1) then islow = 1
      if index(schar,wch,1) then isspc = 1
    next px
  end
*
  begin case
    case not(isnum)
      crt "Failed: no numeric characers (":nchar:")"
      pwnew = ""
    case not(isupr)
      crt "Failed: no upper-case characers (":uchar:")"
      pwnew = ""
    case not(islow)
      crt "Failed: no lower-case characers (":lchar:")"
      pwnew = ""
    case not(isspc)
      crt "Failed: no special characers (":schar:")"
      pwnew = ""
  end case
*
* Reenter password to make sure they match
*
  if pwnew = "" else
    crt "Reenter new password: ":
    echo off
    input w
    echo on
    if w = pwnew else
      crt "Passwords do not match."
      pwnew = ""
    end
  end
*
* Make sure new password is not in recent usage list
*
  if pwnew = "" else
    pwnew = iconv(pwnew,"u0c")
    locate pwnew in pitem<1> setting ix then
      crt "Failed: password recently used"
      pwnew = ""
    end else
*
* If everything good, update password history
* file and write new password on users file
*
      writev pwnew on f.users,@user,7
      ins pwnew before pitem<1,1>
      del pitem<1,pwcnt+1>
      pitem<2> = date()
      write pitem on f.pwd,@user
    end
  end
  casing off
return
*
* End of source



------------------------------
Brian S. Cram
Principal Technical Support Engineer
Rocket Software
------------------------------
Morning Brian,

Nice post!  sorry for the late reply but you know work gets in the way!

I just wanted to mention that we decided to go somewhere in the middle as far as login and who controls the password.  We still create the user but use a subroutine to verify the password via LDAP and our AD server.  This way we still can limit access but use AD as the single password for all systems.   If anyone is interested I could scrub the program and share.

Thanks Again for keeping us thinking.

Craig

------------------------------
Craig Curtis
System Programmer
Sevier Valley School District
Richfield UT United States
------------------------------
Morning Brian,

Nice post!  sorry for the late reply but you know work gets in the way!

I just wanted to mention that we decided to go somewhere in the middle as far as login and who controls the password.  We still create the user but use a subroutine to verify the password via LDAP and our AD server.  This way we still can limit access but use AD as the single password for all systems.   If anyone is interested I could scrub the program and share.

Thanks Again for keeping us thinking.

Craig

------------------------------
Craig Curtis
System Programmer
Sevier Valley School District
Richfield UT United States
------------------------------
Hey, Craig, I don't know about anyone else, but I'd LOVE to see that at your convenience! Thanks in advance.

------------------------------
Brian S. Cram
Principal Technical Support Engineer
Rocket Software
------------------------------
Hey, Craig, I don't know about anyone else, but I'd LOVE to see that at your convenience! Thanks in advance.

------------------------------
Brian S. Cram
Principal Technical Support Engineer
Rocket Software
------------------------------
here is the pick basic code.  Don't laugh :)

CNTR = 0

EXECUTE "BREAK-KEY-OFF"
EXECUTE "CLS"

10 IF CNTR = 3 THEN EXECUTE "OFF"
CRT "Case sensitive Password"
CRT "SSD Password Please:":
ECHO OFF
INPUT PASSWORD.ORG
IF PASSWORD.ORG = '' THEN CNTR += 1; GOTO 10
ECHO ON
WHO = ICONV(0, 'U50BB')
INITIALS.ORG = FIELD(WHO, ' ', 3)

DOME = "!php ldap.php ":INITIALS.ORG:" '":PASSWORD.ORG:"'"
EXECUTE DOME CAPTURING OUT

IF OUT<1> = "success" THEN
* GOOD LDAP LOGIN
CRT "GOOD LOGIN"
END ELSE
CNTR += 1
CRT "BAD LOGIN, ATTEMPT ":CNTR
GOTO 10
END
EXECUTE "BREAK-KEY-ON" CAPTURING OUT
CRT "HIT YOUR CAPS LOCK"

and you will need the php file ldap.php - this does the actual authentication.  Use this for both our web server authentication and for the D3 users.   Have sanitized with xx  

<?php 
// this is in production. This provides authentication services for web.login and also d3 users login

ini_set('display_errors', 0);
error_reporting(0);

$cnname = $argv[1];
$password = $argv[2];

$attributes_ad = array("displayName","description","cn");
$tree = "DC=xx,DC=xx,DC=xx";

$username = $cnname."@xx.xx.xx";
$samaccountname = $cnname;

//ldap_set_option(NULL, LDAP_OPT_DEBUG_LEVEL, 7);

$con = ldap_connect('ldaps://xx.xx.xx.xx:636' );
ldap_set_option($con, LDAP_OPT_PROTOCOL_VERSION, 3);
ldap_set_option($con, LDAP_OPT_REFERRALS, 0);
ldap_set_option($con, LDAP_OPT_NETWORK_TIMEOUT, 1);
ldap_set_option($con, LDAP_OPT_DIAGNOSTIC_MESSAGE, 0);

if ($bind = ldap_bind($con, $username, $password)) {
print "success\\r\\n";
$result = ldap_search($con,$tree,"(sAMAccountName=$samaccountname)");
$data = ldap_get_entries($con, $result);
print_r( $data[0]['employeeid'][0]);
print "\\n\\r"
} else {
print "failure\\n\\r";
}

?>


------------------------------
Craig Curtis
System Programmer
Sevier Valley School District
Richfield UT United States
------------------------------