diff options
-rw-r--r-- | laps.spec | 6 | ||||
-rw-r--r-- | src/usr/share/doc/laps/README.md | 4 | ||||
-rw-r--r-- | src/usr/share/doc/laps/changes | 4 | ||||
-rw-r--r-- | src/usr/share/doc/laps/version.txt | 2 | ||||
-rwxr-xr-x | src/usr/share/laps/laps.sh | 76 |
5 files changed, 64 insertions, 28 deletions
@@ -1,6 +1,6 @@ %define debug_package %{nil} Name: laps -Version: 0.0.2 +Version: 0.0.3 Release: 1 Summary: local administrator password solution @@ -44,5 +44,5 @@ cp -pr %{name}*/src/* "%{buildroot}" %{_datadir}/%{name} %changelog -* Wed Oct 24 2018 B Stack <bgstack15@gmail.com> 0.0.2-1 -- initial rpm built +* Fri Mar 1 2019 B Stack <bgstack15@gmail.com> 0.0.3-1 +- rpm built diff --git a/src/usr/share/doc/laps/README.md b/src/usr/share/doc/laps/README.md index 204b97d..7b5c95f 100644 --- a/src/usr/share/doc/laps/README.md +++ b/src/usr/share/doc/laps/README.md @@ -12,6 +12,10 @@ See /etc/laps/laps.conf.example for how to configure the client. The administrator needs to write **/etc/laps/laps.conf** and **/etc/laps/lapsldap.conf**. Copying and modifying the example config files is the recommended way to provide the configs. +For first use, use the -f flag to force the password change so the timestamp is initialized. + + /usr/share/laps/laps.sh -f + # Prepare the domain The OU where the Linux systems are placed in the domain will need some ACLS set up, which are identical to what the LAPS documentation describes. For a brief summary: diff --git a/src/usr/share/doc/laps/changes b/src/usr/share/doc/laps/changes index 9566fdc..51a0c15 100644 --- a/src/usr/share/doc/laps/changes +++ b/src/usr/share/doc/laps/changes @@ -2,3 +2,7 @@ - fix $2 read action should provide date of expiration on -d 1 - fix #3 add readme.md to front directory - fix #4 laps does not recognize expired kerberos tickets + +* Mar 1 2019 B Stack <bgstack15@gmail.com> 0.0.3-1 +- fix #5 document the recommended use of "-f" for first run +- merge !1 handle empty password change timestamp LDAP attribute diff --git a/src/usr/share/doc/laps/version.txt b/src/usr/share/doc/laps/version.txt index 4e379d2..bcab45a 100644 --- a/src/usr/share/doc/laps/version.txt +++ b/src/usr/share/doc/laps/version.txt @@ -1 +1 @@ -0.0.2 +0.0.3 diff --git a/src/usr/share/laps/laps.sh b/src/usr/share/laps/laps.sh index 15280d3..c81e7a4 100755 --- a/src/usr/share/laps/laps.sh +++ b/src/usr/share/laps/laps.sh @@ -6,7 +6,7 @@ # Title: Local Administrator Password Solution for Linux # Purpose: LAPS Equivalent for GNU/Linux # Package: laps -# History: +# History: see upstream project at https://gitlab.com/bgstack15/laps # Usage: # Reference: ftemplate.sh 2018-09-12a; framework.sh 2018-09-12a # Improve: @@ -23,7 +23,7 @@ # sed (sed) # awk (gawk) fiversion="2018-09-12a" -lapsversion="2018-10-24b" +lapsversion="2019-03-01a" usage() { ${PAGER:-/usr/bin/less -F} >&2 <<ENDUSAGE @@ -108,6 +108,7 @@ main_workflow() { # 2. fetch timestamp from ldap LAPS_epoch="$( wrapper_get_timestamp_from_ldap "${LAPS_LDAPSEARCH_BIN}" "${LAPS_LDAPSEARCH_FLAGS}" "${LAPS_LDAPSEARCH_FILTER}" "${LAPS_ATTRIB_TIME}" "${LAPS_LDAPCONF}" "${LAPS_DATETIME_PY}" "${LAPS_KRB5CC_TMPFILE}" )" + test $? -eq 0 || return 1 # 3. check timestamp to see if close to expiration check_ts_against_expiration_threshold "${LAPS_THRESHOLD}" "${LAPS_epoch}" "${LAPS_FORCE}" @@ -178,26 +179,44 @@ get_attrib_from_ldap() { # execute to check for ldap or kerberos errors ___gtfl_stderr="$( KRB5CCNAME="${___gtfl_krb5cc_tmpfile}" LDAPCONF="${___gtfl_ldapconf}" "${___gtfl_ldapsearch_bin}" ${___gtfl_ldapsearch_flags} "${___gtfl_ldapsearch_filter}" "${___gtfl_attrib}" 2>&1 1>/dev/null )" - if echo "${___gtfl_stderr}" | grep -qiE 'Ticket expired' ; + if test "$?" -ne 0 ; then - ferror "Kerberos ticket expired. Any values from ldap will be garbage." - elif echo "${___gtfl_stderr}" | grep -qi -e 'SASL(-1): generic failure: GSSAPI Error: An invalid name was supplied (Success)' ; - then - ferror "GSSAPI Error: Invalid name (Success). Try using \"SASL_NOCANON on\" in lapsldap.conf. Any values from ldap will be garbage." - elif echo "${___gtfl_stderr}" | grep -qi -e 'TLS: hostname does not match CN in peer certificate' ; - then - ferror "TLS: hostname does not match CN. Try using \"TLS_REQCERT allow\" in lapsldap.conf. Any values from ldap will be garbage." - else - { - echo "other ldap error:" - echo "${___gtfl_stderr}" - } | debuglevoutput 9 + if echo "${___gtfl_stderr}" | grep -qiE 'Ticket expired' ; + then + ferror "Fatal: Kerberos ticket expired." + return 1; + elif echo "${___gtfl_stderr}" | grep -qi -e 'SASL(-1): generic failure: GSSAPI Error: An invalid name was supplied (Success)' ; + then + ferror "Fatal: GSSAPI Error: Invalid name (Success). Try using \"SASL_NOCANON on\" in lapsldap.conf." + return 1; + elif echo "${___gtfl_stderr}" | grep -qi -e 'TLS: hostname does not match CN in peer certificate' ; + then + ferror "Fatal: TLS: hostname does not match CN. Try using \"TLS_REQCERT allow\" in lapsldap.conf." + return 1; + else + { + echo "Fatal: other ldap error:" + echo "${___gtfl_stderr}" + } | debuglevoutput 9 + return 1; + fi fi # execute for actually fetching the value - ___gtfl_attrib="$( KRB5CCNAME="${___gtfl_krb5cc_tmpfile}" LDAPCONF="${___gtfl_ldapconf}" "${___gtfl_ldapsearch_bin}" ${___gtfl_ldapsearch_flags} "${___gtfl_ldapsearch_filter}" "${___gtfl_attrib}" 2>/dev/null | sed -r -e 's/^#.*$//;' -e '/^\s*$/d' | grep -iE -e "^${___gtfl_attrib}:" | awk '{print $2}' )" + ___gtfl_attrib="$( { KRB5CCNAME="${___gtfl_krb5cc_tmpfile}" LDAPCONF="${___gtfl_ldapconf}" \ + "${___gtfl_ldapsearch_bin}" ${___gtfl_ldapsearch_flags} "${___gtfl_ldapsearch_filter}" \ + "${___gtfl_attrib}" 2>/dev/null ; \ + echo "$?" > "${LAPS_LDAPSEARCH_STATUS_TMPFILE}" ; \ + } | sed -r -e 's/^#.*$//;' -e '/^\s*$/d' | grep -iE -e "^${___gtfl_attrib}:" | awk '{print $2}' )" + ___gtfl_ldap_success="$( { cat "${LAPS_LDAPSEARCH_STATUS_TMPFILE}" 2>/dev/null ; echo "1" ; } | head -n1 )" + if test "${___gtfl_ldap_success}" != "0" ; + then + ferror "Fatal: LDAP lookup failed" + return 1 + fi - # no value means either the ldap connection malfunctioned or there was no attribute by that name defined. + # here we can be sure that an empty value means there was no attribute by + # that name defined or it had an actual empty value. echo "${___gtfl_attrib}" @@ -215,8 +234,14 @@ wrapper_get_timestamp_from_ldap() { ___wgtfl_krb5cc_tmpfile="${7}" ts_filetime="$( get_attrib_from_ldap "${___wgtfl_ldapsearch_bin}" "${___wgtfl_ldapsearch_flags}" "${___wgtfl_ldapsearch_filter}" "${___wgtfl_attrib}" "${___wgtfl_ldapconf}" "${___wgtfl_krb5cc_tmpfile}" )" - debuglev 3 && ferror "timestamp(FILETIME): ${ts_filetime}" - ts_epoch="$( "${___wgtfl_datetime_py}" -e "${ts_filetime}" )" + test "$?" -eq 0 || return 1 + + ts_epoch=0 + if test -n "$ts_filetime" ; + then + debuglev 3 && ferror "timestamp(FILETIME): ${ts_filetime}" + ts_epoch="$( "${___wgtfl_datetime_py}" -e "${ts_filetime}" )" + fi debuglev 2 && ferror "timestamp(epoch): ${ts_epoch}" debuglev 1 && ferror "timestamp(UTC): $( date -u -d "@${ts_epoch}" "+%FT%TZ" )" @@ -373,7 +398,7 @@ wrapper_change_password() { then echo "0" > "${LAPS_PASSWORD_STATUS_TMPFILE}" else - ___wcp_stdout="$( echo -e "$(echo ${___wcp_phrase})\n$(echo ${___wcp_phrase})" | "${___wcp_passwd_bin}" "${___wcp_user}" ; echo "$?" > "${LAPS_PASSWORD_STATUS_TMPFILE}" )" + ___wcp_stdout="$( printf "%s\n%s\n" "${___wcp_phrase}" "${___wcp_phrase}" | "${___wcp_passwd_bin}" "${___wcp_user}" ; echo "$?" > "${LAPS_PASSWORD_STATUS_TMPFILE}" )" fi ___wcp_passwd_result="$( cat "${LAPS_PASSWORD_STATUS_TMPFILE}" )" @@ -383,7 +408,7 @@ wrapper_change_password() { debuglev 4 && ferror "${___wcp_stdout}" ;; *) - # successful operation + # failed operation ferror "${scriptfile}: 8 fatal! Unable to change password for ${___wcp_user}:\n${___wcp_stdout}" exit 8 ;; @@ -504,8 +529,8 @@ clean_laps() { # Delayed cleanup if test -z "${LAPS_NO_CLEAN}" ; then - nohup /bin/bash <<EOF 1>/dev/null 2>&1 & -sleep "${LAPS_CLEANUP_SEC:-300}" ; /bin/rm -r "${LAPS_TMPDIR:-NOTHINGTODELETE}" 1>/dev/null 2>&1 ; + nohup /bin/sh <<EOF 1>/dev/null 2>&1 & +sleep "${LAPS_CLEANUP_SEC:-3}" ; /bin/rm -r "${LAPS_TMPDIR:-NOTHINGTODELETE}" 1>/dev/null 2>&1 ; EOF fi } @@ -634,6 +659,7 @@ test -z "${LAPS_TMPDIR}" && LAPS_TMPDIR="$( mktemp -d /tmp/laps.XXXXXXXXXX )" test -z "${LAPS_KRB5CC_TMPFILE}" && LAPS_KRB5CC_TMPFILE="$( TMPDIR="${LAPS_TMPDIR}" mktemp )" test -z "${LAPS_LDIF_TMPFILE}" && LAPS_LDIF_TMPFILE="$( TMPDIR="${LAPS_TMPDIR}" mktemp )" test -z "${LAPS_LDAPMODIFY_STATUS_TMPFILE}" && LAPS_LDAPMODIFY_STATUS_TMPFILE="$( TMPDIR="${LAPS_TMPDIR}" mktemp )" +test -z "${LAPS_LDAPSEARCH_STATUS_TMPFILE}" && LAPS_LDAPSEARCH_STATUS_TMPFILE="$( TMPDIR="${LAPS_TMPDIR}" mktemp )" test -z "${LAPS_PASSWORD_STATUS_TMPFILE}" && LAPS_PASSWORD_STATUS_TMPFILE="$( TMPDIR="${LAPS_TMPDIR}" mktemp )" define_if_new LAPS_KINIT_HOST_SCRIPT "/usr/share/bgscripts/work/kinit-host.sh" define_if_new LAPS_KINIT_HOST_SCRIPT_DEFAULT "/usr/share/bgscripts/work/kinit-host.sh" @@ -676,7 +702,9 @@ define_if_new LAPS_INTERACTIVE 0 # SET TRAPS #trap "CTRLC" 2 #trap "CTRLZ" 18 -trap '__ec=$? ; clean_laps ; trap "" 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 ; exit ${__ec} ;' 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 +# do NOT catch SIGCHLD (17) because dash will actually exit then (bash seems to +# ignore our attempt to catch it) +trap '__ec=$? ; clean_laps ; trap "" 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 18 19 20 ; exit ${__ec} ;' 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 18 19 20 # DEBUG SIMPLECONF debuglev 5 && { |