Forum: Cfengine Help
Subject: I think I have created a solution for keeping admin passwords in sync 
on AIX
Author: raymondcox
Link to topic: https://cfengine.com/forum/read.php?3,20974,20974#msg-20974

I have posted a couple of times about syncing select AIX users between all of 
my machines. I initially had a file that required me to manually update the 
password entries. That turned out to be a pretty bad idea, and I don't think it 
really fits into the CFengine philosophy.

The latest solution I have come up with is a variation on the first method with 
a little LINUX flavor thrown in, it seems to do what I want most of the time.

This first section works exactly as I expect and seems pretty reliable. A file 
called /var/cfengine/cache/cfsec_shadow gets generated with the proper values.


# 
# Used to update the file /etc/security/passwd on an AIX system by creating a 
file that mimics 
#  the format of the /etc/shadow file in LINUX.
# Dependancies:
#
#  /fixes/scripts/cfpasswd
#  Perl script used for dumping the passwords of the admin users defined in the 
slist admin_users.
#    /fixes/scripts/cfpasswd:
#      #!/usr/bin/perl
#
#      $_user = $ARGV[0];
#
#      ($account, $passwd, $uid, $gid, $quota, $comment, $gcos, $home, $shell) 
= getpwnam($_user);
#      print "$passwd";
#
#
#

body common control {

    bundlesequence => { "harvest_passwords" };
    inputs         => { "adminlist.cf", 
"/var/cfengine/inputs/cfengine_stdlib.cf", "/var/cfengine/inputs/site.cf", };
}
#
bundle agent harvest_passwords {


files:

  tssdev::

    "/etc/security/passwd"
      handle  => "detect_master_AIX_password_change",
      comment => "Check to see if the /etc/security/passwd file has been 
updated since the last run",
      changes => detect_all_change,
      classes => if_repaired("password_was_updated");

methods:

  password_was_updated::

    "update_passwords"  usebundle =>   
regen_AIX_mock_shadow_file_for_admin_users;


}

# Convert the entries in /etc/security/passwd on AIX from:
#
#tstusr1:
#        password = bNR2bnq./xYWM
#        lastupdate = 1299424296
#        flags = ADMCHG
#
#tstusr2:
#        password = 7f23WTTmyCHg6
#        lastupdate = 1299165612
#        flags = ADMCHG
# TO:
#
#
#tstusr1:bNR2bnq./xYWM:
#tstusr2:7f23WTTmyCHg6:
#tstusr3:8fPb6gQQrBDGA:
#tstusr4:Wdffu2kUDRM4I:


bundle agent regen_AIX_mock_shadow_file_for_admin_users
{


files:
  aix::

    "/var/cfengine/cache/cfsec_shadow"
      handle  => "mock_shadow_file",
      comment => "Updating passwords in /etc/shadow and /etc/security/passwd",
      edit_defaults => empty,
      create    => "true",
      classes  => if_ok("shadowpass_is_go"),
      edit_line => insert;


methods:

  shadowpass_is_go::

    "update_admin_pass"  usebundle  => passlist;
}

bundle edit_line insert 
{
vars:
  "admin_users"  slist => { "tstusr1", "tstusr2", "tstusr3", "tstusr4" };
  "admin_pass[$(admin_users)]"  string => execresult("/fixes/scripts/cfpasswd 
$(admin_users)","useshell");

insert_lines:

  "$(admin_users):$(admin_pass[$(admin_users)]):";
}

##########################################################################


This next part is where I start to have a little unpredictable behavior. I seem 
to be able to update the password reliably, but the lastupdate field does not 
always get set as I would expect. The last field that I have attempted to deal 
with is the flags section, I have not yet figured out how to replace the value 
ADMCHG with a space. cf-promises yells at me every time I attempt it, but in 
all fairness I have not decided that I really need to clear it yet. 


bundle agent passlist
{

vars:
  "myepoch"      string => execresult("/usr/bin/date +%s","useshell"),
                 policy => "free";

files:

    "/tmp/passwd"
        handle  =>  "update_etc_security_passwd",
        comment   => "Keep passwords up to date",
        edit_line => security_edit("$(myepoch)"); 


reports:
  aix::
    "Sending: $(myepoch) to security_edit";

}

##########################################################################

bundle edit_line security_edit(epoch) {

vars:
    "mypasswd" int => 
readstringarray("mypasswd_array","/var/cfengine/cache/cfsec_shadow","#[^\n]*",":",200,10000);
    "admchg"   string => "ADMCHG";
    #"newadmchg" string => " ";

    "shadow_users" slist => getindices("mypasswd_array"),
      policy => "overridable";


  replace_patterns:

      "^(\tpassword) = (?!$(mypasswd_array[$(shadow_users)][1])).*$"
         handle  =>  "update_password_in_file",
         comment =>  "Updates the hashsed password in /etc/security/passwd 
based on a single reference system",
         replace_with  => new_password("$(mypasswd_array[$(shadow_users)][1])"),
         select_region => user_region("$(shadow_users)");

      "^(\tlastupdate) = (?!$(epoch)).*$"
         handle  =>  "keep_changed_password_from_expiring",
         comment =>  "Emulates the admin changing their own password on each 
machine",
         replace_with  =>  new_epoch("$(epoch)"),
         select_region =>  user_region("$(shadow_users)");

      #"^(\tflags) = $(admchg).*$"
        #handle  =>  "clear_admchg_flag",
        #comment  =>  "Remove the requirement for admins to change their 
password at first login This should not apply to the reference system",
        #replace_with  => clear_admchg,
        #select_region  =>  user_region("$(shadow_users)");

}

##########################################################################

body replace_with new_password(password) {

    replace_value => "$(match.1) = $(password)";

}

body replace_with new_epoch(newepoch) {

    replace_value => "$(match.1) = $(newepoch)";

}

#body replace_with clear_admchg  {
#
   #replace_value => "$(match.1) = "$(newadmchg)";
#
#}

##########################################################################

body select_region user_region(userid) {


   select_start => "^$(userid):$";
   select_end   => "^(\tflags) = .*$";
   #include_start_delimiter  => "true";
   #include_end_delimiter  => "true";

}

##########################################################################




I really like CFengine, but sometimes it drives me a little nuts. edit_line is 
extremely powerful at being able to replace formatted text, however I have not 
found a function that allows me to obtain a value from formatted text.

The recreation of the /var/cfengine/cache/cfsec_shadow file every time the 
/etc/passwd file is modified is a little inefficient, and I will probably 
modify that to just update the fields that are different but this is working 
for now.


Any suggestions/criticisms or otherwise are welcome and greatly appreciated.

_______________________________________________
Help-cfengine mailing list
Help-cfengine@cfengine.org
https://cfengine.org/mailman/listinfo/help-cfengine

Reply via email to