add generic LDAP parser for assockit
authorThorsten Glaser <tg@mirbsd.org>
Fri, 26 Apr 2013 16:12:51 +0000 (18:12 +0200)
committerThorsten Glaser <tg@mirbsd.org>
Fri, 26 Apr 2013 16:12:51 +0000 (18:12 +0200)
mksh/assockit.ksh
mksh/assoldap.ksh [new file with mode: 0644]

index 82f2a01..145b774 100644 (file)
@@ -1,7 +1,9 @@
-# $MirOS: contrib/hosted/tg/assockit.ksh,v 1.2 2011/07/05 20:15:26 tg Exp $
+# $MirOS: contrib/hosted/tg/assockit.ksh,v 1.3 2013/04/26 16:10:20 tg Exp $
 #-
 # Copyright © 2011
-#      Thorsten Glaser <tg@mirbsd.org>
+#      Thorsten “mirabilos” Glaser <tg@mirbsd.org>
+# Copyright © 2013
+#      Thorsten Glaser <t.glaser@tarent.de>
 #
 # Provided that these terms and disclaimer and all copyright notices
 # are retained or reproduced in an accompanying document, permission
@@ -152,14 +154,14 @@ function asso_loadv {
 # result is in the global variable asso_y
 function asso_loadk {
        if (( $# < 1 )); then
-               print -u2 'assockit.ksh: syntax: asso_loadv key [key ...]'
+               print -u2 'assockit.ksh: syntax: asso_loadk key [key ...]'
                return 2
        fi
 
        asso__lookup 0 "$@" || return 1
        (( asso_f & ASSO_MASK_ARR )) || return 1
        nameref _keys=${asso_b}${asso_k#16#}_k
-       set -A asso_y -- ${_keys[*]}
+       set -A asso_y -- "${_keys[@]}"
 }
 
 # set a string value
@@ -480,6 +482,7 @@ function asso__r_free {
                        local _ob=$asso_b _ok=$asso_k
                        asso_b=$asso_b${asso_k#16#}
                        nameref _s=${asso_b}_f
+                       #XXX not "${!_s[@]}" since indicēs are numbers atm
                        for asso_k in ${!_s[*]}; do
                                asso__r_free
                        done
diff --git a/mksh/assoldap.ksh b/mksh/assoldap.ksh
new file mode 100644 (file)
index 0000000..5854598
--- /dev/null
@@ -0,0 +1,128 @@
+#-
+# Copyright © 2013
+#      Thorsten Glaser <t.glaser@tarent.de>
+#
+# Provided that these terms and disclaimer and all copyright notices
+# are retained or reproduced in an accompanying document, permission
+# is granted to deal in this work without restriction, including un‐
+# limited rights to use, publicly perform, distribute, sell, modify,
+# merge, give away, or sublicence.
+#
+# This work is provided “AS IS” and WITHOUT WARRANTY of any kind, to
+# the utmost extent permitted by applicable law, neither express nor
+# implied; without malicious intent or gross negligence. In no event
+# may a licensor, author or contributor be held liable for indirect,
+# direct, other damage, loss, or other issues arising in any way out
+# of dealing in the work, even if advised of the possibility of such
+# damage or existence of a defect, except proven that it results out
+# of said person’s immediate fault when using the work as intended.
+#-
+# Generic LDAP (LDIF) parser into associative arrays.
+
+# include assockit and pure-mksh base64 decoder, unless already done
+mydir=$(realpath "$(dirname "$0")")
+[[ -n $ASSO_VAL ]] || PATH="$mydir:$mydir/..:$PATH" . assockit.ksh
+typeset -f Lb64decode >/dev/null || PATH="$mydir:$mydir/..:$PATH" . base64
+
+# Syntax: asso_setldap arrayname index ... -- ldapsearch-options
+function asso_setldap {
+       # parse options
+       local arrpath ldapopts x i=0 T dn line value
+       set -A arrpath
+       while (( $# )); do
+               [[ $1 = -- ]] && break
+               arrpath[i++]=$1
+               shift
+       done
+       if [[ $1 != -- ]]; then
+               print -u2 'assoldap.ksh: syntax: asso_setldap arraypath -- ldappath'
+               return 255
+       fi
+       shift
+       set -A ldapopts -- "$@"
+
+       # just in case, unset the target array and create it as associative
+       asso__lookup 1 "${arrpath[@]}"
+       asso__r_free
+       asso__r_setf $ASSO_AASS
+
+       # call ldapsearch with decent output format
+       if ! T=$(mktemp -d /tmp/assoldap.XXXXXXXXXX); then
+               print -u2 'assoldap.ksh: could not create temporary directory'
+               return 255
+       fi
+       (ldapsearch -xLLL "${ldapopts[@]}"; echo $? >"$T/err") | \
+           tr '\n' $'\a' | sed -e $'s/\a //g' | tr $'\a' '\n' >"$T/out"
+       i=$(<"$T/err")
+       if (( i )); then
+               print -u2 'assoldap.ksh: ldapsearch returned error'
+               rm -rf "$T"
+               return $i
+       fi
+       if [[ ! -s $T/out ]]; then
+               # empty output
+               rm -rf "$T"
+               return 0
+       fi
+
+       # parse LDIF (without linewraps)
+       while IFS= read -r line; do
+               if [[ -z $line ]]; then
+                       dn=
+                       continue
+               fi
+               value=${line##+([!:]):?(:)*( )}
+               if [[ $value = "$line" ]]; then
+                       print -ru2 "assoldap.ksh: malformed line: $line"
+                       rm -rf "$T"
+                       return 255
+               fi
+               x=${line%%*( )"$value"}
+               if [[ $x = "$line" ]]; then
+                       print -ru2 "assoldap.ksh: malformed line: $line"
+                       rm -rf "$T"
+                       return 255
+               fi
+               [[ $x = *:: ]] && value=$(Lb64decode "$value")
+               x=${x%%+(:)}
+               if [[ -z $dn ]]; then
+                       if [[ $x = dn ]]; then
+                               dn=$value
+                       else
+                               print -ru2 "assoldap.ksh: not dn: $line"
+                               rm -rf "$T"
+                               return 255
+                       fi
+               elif [[ $x = dn ]]; then
+                       print -ru2 "assoldap.ksh: unexpected dn ($dn): $line"
+                       rm -rf "$T"
+                       return 255
+               fi
+               asso_sets "$value" "${arrpath[@]}" "$dn" "$x"
+       done <"$T/out"
+       rm -rf "$T"
+       if [[ -n $dn ]]; then
+               print -u2 'assoldap.ksh: missing empty line at EOT'
+               return 255
+       fi
+       return 0
+}
+
+:||\
+{
+       # for testing
+       LDAPTLS_CACERT=/etc/ssl/certs/dc.lan.tarent.de.cer \
+           asso_setldap users -- \
+           -H ldaps://dc.lan.tarent.de -b cn=users,dc=tarent,dc=de -s one \
+           isJabberAccount=1 cn uid
+       if (( $? )); then
+               print -u2 An error occurred: $?
+               exit 1
+       fi
+       print "uid (dn) = cn"
+       asso_loadk users
+       for user_dn in "${asso_y[@]}"; do
+               print -r -- "$(asso_getv users "$user_dn" uid)" \
+                   "($user_dn) = $(asso_getv users "$user_dn" cn)"
+       done | sort
+}