mirror of
git://git.code.sf.net/p/zsh/code
synced 2025-01-19 11:31:26 +01:00
51455, 51461: new completion for the OpenLDAP client tools including a helper function for LDAP search filters
This commit is contained in:
parent
6f4aa1d949
commit
c83ce203f5
5 changed files with 349 additions and 2 deletions
|
@ -1,3 +1,10 @@
|
|||
2023-02-19 Oliver Kiddle <opk@zsh.org>
|
||||
|
||||
* 51455, 51461: Completion/Unix/Type/_ldap_attributes
|
||||
Completion/BSD/Command/_ldap, Completion/Unix/Command/_openldap,
|
||||
Completion/Unix/Type/_ldap_filters: new completion for the OpenLDAP
|
||||
client tools including a helper function for LDAP search filters
|
||||
|
||||
2023-02-17 Oliver Kiddle <opk@zsh.org>
|
||||
|
||||
* 51447: Src/Zle/zle_keymap.c: silence compiler maybe-uninitialized
|
||||
|
|
|
@ -80,8 +80,8 @@ else
|
|||
'-x[use simple authentication]' \
|
||||
'-Z[use StartTLS]' \
|
||||
'-z+[specify maximum number of results or 0 for no limit]:size limit [0]:' \
|
||||
'::filter:' \
|
||||
'*:attribute:'
|
||||
'1: :_ldap_filters' \
|
||||
'*: :_ldap_attributes'
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
|
222
Completion/Unix/Command/_openldap
Normal file
222
Completion/Unix/Command/_openldap
Normal file
|
@ -0,0 +1,222 @@
|
|||
#compdef ldapadd ldapcompare ldapdelete ldapexop ldapmodify ldapmodrdn ldappasswd ldapsearch ldapurl ldapwhoami
|
||||
|
||||
local curcontext="$curcontext" nm="$compstate[nmatches]"
|
||||
local -a args auth state line expl
|
||||
|
||||
args=( '*-e[general extensions]:extension:->general-extensions' )
|
||||
|
||||
case $service in
|
||||
ldapadd|ldapcompare|ldapdelete|ldapexop|ldapmodify|ldapmodrdn|ldappasswd|ldapsearch|ldapwhoami)
|
||||
if (( $words[(I)-[^Z]#Z[^Z]#] )); then
|
||||
args+=( '*-Z[require success for start TLS request]' )
|
||||
elif (( ! $words[(I)-[^Z]#Z] )); then
|
||||
args+=( '-Z[start TLS request]' )
|
||||
fi
|
||||
args+=(
|
||||
'!(-)-VV' '-V[display version information]'
|
||||
'*-d+[set LDAP debugging level]:level:((1\:trace 2\:packets 4\:args 8\:conns 10\:ber 2048\:parse -1\:all))'
|
||||
"-n[show what would be done but don't actually do it]"
|
||||
'-v[verbose output]'
|
||||
"-N[don't use reverse DNS to canonicalize SASL host name]"
|
||||
'*-o+[specify any ldap.conf options]: : _values option
|
||||
"ldif_wrap[specify width]\:width"
|
||||
"nettimeout[specify timeout]\:timeout (seconds)"'
|
||||
)
|
||||
auth=(
|
||||
'-D[specify bind DN]:binddn'
|
||||
'-H[specify LDAP URIs]:uri'
|
||||
'-P[specify protocol version]:version [3]:(2 3)'
|
||||
+ simple
|
||||
'(sasl)-x[use simple authentication]'
|
||||
'(sasl -W -y)-w+[specify bind password]:bind password'
|
||||
'(sasl -w -y)-W[prompt for bind password]'
|
||||
'(sasl -w -W)-y+[read password from file]:file:_files'
|
||||
+ sasl
|
||||
'(simple)-O+[specify SASL security properties]: : _values -s , property
|
||||
none noplain noactive nodict noanonymous forwardsec passcred
|
||||
minssf\:factor maxssf\:factor maxbufsize\:factor'
|
||||
'(simple)-X+[specify SASL authorization identity]:authzid:->authzids'
|
||||
'(simple)-Y+[specify SASL mechanism]:mechanism:compadd -M "m:{a-zA-Z}={A-Za-z}" EXTERNAL GSSAPI' # iana has a full list but cyrus support seems limited
|
||||
'(simple)-R+[specify SASL realm]:realm'
|
||||
'(simple)-U+[specify SASL authentication identity]:authcid'
|
||||
'(simple)-I[use SASL Interactive mode]'
|
||||
'(simple)-Q[use SASL Quiet mode]'
|
||||
)
|
||||
;|
|
||||
ldapadd|ldapcompare|ldapdelete|ldapmodify|ldapmodrdn|ldapsearch)
|
||||
if (( $words[(I)-[^M]#M[^M]#] )); then
|
||||
args+=( '*-M[enable Manage DSA IT control critical]' )
|
||||
elif (( ! $words[(I)-[^M]#M] )); then
|
||||
args+=( '-M[enable Manage DSA IT control]' )
|
||||
fi
|
||||
;|
|
||||
ldapadd|ldapdelete|ldapmodify|ldapmodrdn|ldapsearch)
|
||||
# ldapexop documents but doesn't implement this
|
||||
args+=( '(1 2 *)-f+[read operations from file]:file:_files' )
|
||||
;|
|
||||
ldapadd|ldapdelete|ldapmodify|ldapmodrdn|ldapsearch)
|
||||
args+=( "-c[continuous operation mode (don't stop on errors)]" )
|
||||
;|
|
||||
ldapdelete|ldapsearch)
|
||||
args+=( '-z+[specify size limit]:size limit (entries)' )
|
||||
;|
|
||||
ldapadd|ldapmodify)
|
||||
args+=(
|
||||
'-S+[write records that are skipped due to an error to file]:file:_files'
|
||||
'*-E+[modify extensions]:extension:->modify-extensions'
|
||||
)
|
||||
;|
|
||||
ldapurl|ldapsearch)
|
||||
args+=(
|
||||
'(decompose)-s+[specify search scope]:search scope [sub]:(base one sub children)'
|
||||
)
|
||||
;|
|
||||
ldapdelete|ldapmodrdn|ldapurl|ldapwhoami) args+=( '!*-E+:extension' ) ;|
|
||||
|
||||
ldapadd) args+=( '!-a' ) ;;
|
||||
ldapmodify) args+=( '-a[add new entries]' ) ;;
|
||||
ldapcompare)
|
||||
args+=(
|
||||
'-z[quiet mode - no output aside return status]'
|
||||
'*-E+[compare extensions]:extension:->compare-extensions'
|
||||
)
|
||||
;;
|
||||
ldapdelete)
|
||||
args+=(
|
||||
'-r[do a recursive delete]'
|
||||
'*: :_guard "^-*" "distinguished name"'
|
||||
)
|
||||
;;
|
||||
ldapexop) args+=( '*:: :->extended-operations' ) ;;
|
||||
ldapmodrdn)
|
||||
args+=(
|
||||
'-r[remove old RDN values from the entry]'
|
||||
'-s[specify new superior entry to move target to]:entry'
|
||||
'1:distinguished name'
|
||||
'2:relative distinguished name'
|
||||
)
|
||||
;;
|
||||
ldappasswd)
|
||||
args+=(
|
||||
'(-a -t)-A[prompt for old password]'
|
||||
'(-A -t)-a+[specify old password]:password'
|
||||
'(-A -a)-t+[read old password from file]:file:_files'
|
||||
'(-s -T)-S[prompt for new password]'
|
||||
'(-S -T)-s+[specify new password]:password'
|
||||
'(-S -s)-T+[read new password from file]:file:_files'
|
||||
)
|
||||
;;
|
||||
ldapsearch)
|
||||
if (( $words[(I)-[^L]#L[^L]#L[^L]#] )); then
|
||||
args+=( '*-L[LDIF format without comments and version]' )
|
||||
elif (( $words[(I)-[^L]#L[^L]#] )); then
|
||||
args+=( '*-L[LDIF format without comments]' )
|
||||
elif ! (( $words[(I)-[^L]#L[^L]#L[^L]#L] )); then
|
||||
args+=( '-L[LDIFv1 format]' )
|
||||
else
|
||||
args+=( '!*-L' )
|
||||
fi
|
||||
if (( $words[(I)-[^t]#t[^t]#] )); then
|
||||
args+=( '*-t[write all retrieved values to files in temporary directory]' )
|
||||
elif (( ! $words[(I)-[^t]#t] )); then
|
||||
args+=( '-t[write binary values to files in temporary directory]' )
|
||||
fi
|
||||
|
||||
args+=(
|
||||
'-a+[specify how aliases dereferencing is done]:deref [never]:(never always search find)'
|
||||
'-A[retrieve attributes only (no values)]'
|
||||
'-b+[specify base dn for search]:basedn'
|
||||
'*-E+[search extensions]:extension:->search-extensions'
|
||||
'-F+[specify URL prefix for temporary files]:prefix [file:///tmp//]'
|
||||
'-l+[specify time limit for search]:time limit (seconds)'
|
||||
'-S+[sort results by specified attribute]:attribute:_ldap_attributes'
|
||||
'-T[write files to specified directory]:path [/tmp]:_directories'
|
||||
'-u[include User Friendly entry names in the output]'
|
||||
'1: :_ldap_filters'
|
||||
'2: : _alternative
|
||||
"attributes:attribute:_ldap_attributes"
|
||||
"attributes:attribute:((1.1\:no\ attributes \*\:all\ user\ attributes \+\:all\ operational\ attributes))"'
|
||||
'*:attribute:_ldap_attributes -F line'
|
||||
)
|
||||
;;
|
||||
ldapurl)
|
||||
args+=(
|
||||
- compose
|
||||
'-a+[set a list of attribute selectors]:attribute selectors (comma separated)'
|
||||
'-b+[set the searchbase]:search base'
|
||||
'-f+[set the URL filter]:filter:_ldap_filters'
|
||||
'-h+[set the host]:host:_hosts'
|
||||
'-p+[set the tcp port]:port:(389 636)'
|
||||
'-S+[set the URL scheme]:scheme:(ldap ldaps)'
|
||||
- decompose
|
||||
'(-s)-H+[specify URI to be exploded]:uri'
|
||||
)
|
||||
;;
|
||||
esac
|
||||
|
||||
_arguments -C -S -s $args $auth
|
||||
|
||||
case $state in
|
||||
extended-operations)
|
||||
case $CURRENT:$words[1] in
|
||||
1:*)
|
||||
if compset -P '*::'; then
|
||||
_message -e data 'base64 data'
|
||||
elif compset -P '*:'; then
|
||||
_message -e data data
|
||||
else
|
||||
_alternative \
|
||||
'oids::_guard "(<->(|.))#" oid' \
|
||||
'operations:operation:(whoami cancel refresh)'
|
||||
fi
|
||||
;;
|
||||
2:cancel) _message -e ids 'cancel id' ;;
|
||||
2:refresh) _message -e names 'distinguished name' ;;
|
||||
3:refresh) _message -e times 'ttl' ;;
|
||||
*) _message 'no more arguments' ;;
|
||||
esac
|
||||
;;
|
||||
*-extensions)
|
||||
if ! compset -P \!; then
|
||||
_description criticality expl critical
|
||||
compadd -S "" "$expl[@]" \!
|
||||
fi
|
||||
;|
|
||||
modify-extensions) _values extension 'txn:txn:(abort commit)' ;;
|
||||
compare-extensions) _values extension dontUseCopy ;;
|
||||
search-extensions)
|
||||
_values extension \
|
||||
'mv[matched values filter]:filter:_ldap_filters' \
|
||||
'pr[paged results/prompt]:size[/prompt|noprompt]' \
|
||||
'sss[server side sorting]: :_sequence -s / _ldap_attributes' \
|
||||
'subentries: :(true false)' \
|
||||
'sync:sync[/cookie][/slimit]:((ro\:refreshOnly rp\:refreshAndPersist))' \
|
||||
'vlv[virtual list view]:before/after(/offset/count|\:value' \
|
||||
'deref:derefAttr:_sequence _ldap_attributes' \
|
||||
dontUseCopy domainScope
|
||||
;;
|
||||
general-extensions)
|
||||
_values extension \
|
||||
'assert:filter:_ldap_filters' \
|
||||
'authzid:authzid:->authzids' \
|
||||
{post,pre}'read: :_sequence _ldap_attributes' \
|
||||
'sessiontracking:username:_users' \
|
||||
'chaining:behavior:(chainingPreferred chainingRequired referralsPreferred referralsRequired)' \
|
||||
bauthzid manageDSAit noop ppolicy relax abandon cancel ignore
|
||||
;&
|
||||
authzids)
|
||||
if [[ $state != authzids ]]; then
|
||||
: # fall-through from above without the authzids state
|
||||
elif compset -P 'u:'; then
|
||||
_description users expl authzid
|
||||
_users "$expl[@]"
|
||||
elif compset -P 'dn:'; then
|
||||
_message -e ids 'distinguished name'
|
||||
else
|
||||
_description prefixes expl prefix
|
||||
compadd -S: "$expl[@]" u dn
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
[[ nm -ne "$compstate[nmatches]" ]]
|
27
Completion/Unix/Type/_ldap_attributes
Normal file
27
Completion/Unix/Type/_ldap_attributes
Normal file
|
@ -0,0 +1,27 @@
|
|||
#autoload
|
||||
|
||||
local -a expl attrs
|
||||
|
||||
# These come from dumping attributes from basic installations of both openldap
|
||||
# and FreeIPA and combining results. It is possible to have custom additions so
|
||||
# a definitive list is not possible Hence the use of -x with compadd.
|
||||
#
|
||||
attrs=(
|
||||
associatedDomain authenticationMethod automountInformation automountKey
|
||||
automountMapName bindTimeLimit cACertificate;binary cn dc defaultSearchBase
|
||||
defaultServerList description displayName dn followReferrals gecos gidNumber
|
||||
givenName homeDirectory info initials ipaCertIssuerSerial ipaCertSubject
|
||||
ipaConfigString ipaKeyExtUsage ipaKeyTrust ipaNTSecurityIdentifier
|
||||
ipaPublicKey ipaUniqueID ipHostNumber loginShell mail member memberUid
|
||||
mepManagedBy nisDomain nisNetgroupTriple o objectClass objectClassMap ou
|
||||
pwdAllowUserChange pwdAttribute pwdCheckQuality pwdExpireWarning
|
||||
pwdFailureCountInterval pwdGraceAuthNLimit pwdInHistory pwdLockout
|
||||
pwdLockoutDuration pwdMaxAge pwdMaxFailure pwdMinAge pwdMinLength
|
||||
pwdMustChange pwdSafeModify searchTimeLimit serviceSearchDescriptor sn
|
||||
telephoneNumber uid uidNumber userCertificate;binary userPKCS12
|
||||
userSMIMECertificate
|
||||
)
|
||||
|
||||
_description ldap-attributes expl "ldap attribute"
|
||||
compadd "${@:/-X/-x}" "${expl[@]:/-X/-x}" \
|
||||
-M 'm:{a-zA-Z}={A-Za-z} r:[^A-Z]||[A-Z]=* r:|=*' -a attrs
|
91
Completion/Unix/Type/_ldap_filters
Normal file
91
Completion/Unix/Type/_ldap_filters
Normal file
|
@ -0,0 +1,91 @@
|
|||
#autoload
|
||||
|
||||
# LDAP search filters conforming to RFC4515
|
||||
|
||||
local -a expl excl optype disp end pre
|
||||
local -i nest=0
|
||||
local open='(' close=')' andop='&' orop='|'
|
||||
|
||||
[[ -prefix - ]] && return 1
|
||||
|
||||
local -a matchingrules=( # From RFC4517
|
||||
bitStringMatch booleanMatch caseExactIA5Match
|
||||
caseExactMatch caseExactOrderingMatch caseExactSubstringsMatch
|
||||
caseIgnoreIA5Match caseIgnoreIA5SubstringsMatch caseIgnoreListMatch
|
||||
caseIgnoreListSubstringsMatch caseIgnoreMatch caseIgnoreOrderingMatch
|
||||
caseIgnoreSubstringsMatch directoryStringFirstComponentMatch
|
||||
distinguishedNameMatch generalizedTimeMatch generalizedTimeOrderingMatch
|
||||
integerFirstComponentMatch integerMatch integerOrderingMatch keywordMatch
|
||||
numericStringMatch numericStringOrderingMatch numericStringSubstringsMatch
|
||||
objectIdentifierFirstComponentMatch objectIdentifierMatch octetStringMatch
|
||||
octetStringOrderingMatch telephoneNumberMatch telephoneNumberSubstringsMatch
|
||||
uniqueMemberMatch wordMatch
|
||||
)
|
||||
local -a classes=( # Sampled from real servers, arbitrary other values allowed
|
||||
automount automountMap cosTemplate dcObject device dnaSharedConfig domain
|
||||
domainRelatedObject DUAConfigProfile extensibleObject groupOfNames
|
||||
groupOfPrincipals ieee802device inetOrgPerson inetuser ipaassociation ipaca
|
||||
ipacaacl ipaCertificate ipaCertMapConfigObject ipacertprofile ipaConfigObject
|
||||
ipaDomainIDRange ipaDomainLevelConfig ipaGuiConfig ipahbacrule ipahbacservice
|
||||
ipahbacservicegroup ipahost ipahostgroup ipaIDrange ipaKeyPolicy
|
||||
ipakrbprincipal ipaNameResolutionData ipaNTDomainAttrs ipaNTGroupAttrs
|
||||
ipaNTUserAttrs ipaobject ipaPublicKeyObject ipaReplTopoManagedServer
|
||||
ipaservice ipaSshGroupOfPubKeys ipasshhost ipasshuser ipasudorule
|
||||
ipaSupportedDomainLevelConfig ipaTrustedADDomainRange ipaUserAuthTypeClass
|
||||
ipausergroup ipHost krbContainer krbprincipal krbprincipalaux
|
||||
krbrealmcontainer krbTicketPolicyAux mepManagedEntry mepOriginEntry
|
||||
nestedGroup nisDomainObject nisNetgroup nsContainer nsDS5Replica nshost
|
||||
organization organizationalPerson organizationalRole organizationalUnit
|
||||
person pilotObject pkiCA pkiuser posixAccount posixGroup pwdPolicy
|
||||
shadowAccount simpleSecurityObject top
|
||||
)
|
||||
|
||||
compquote open close andop orop
|
||||
open=${(q)open} close=${(q)close}
|
||||
# default to double rather than backslash quoting
|
||||
[[ -z $compstate[quote] && -z $PREFIX ]] && pre='"('
|
||||
|
||||
zstyle -s ":completion:${curcontext}:operators" list-separator sep || sep=--
|
||||
print -v disp -f "%s $sep %s" \| or \& and \! not
|
||||
end=( ") $sep end" )
|
||||
excl=( ! \\\| \& ) # compadd -F uses globs: only | needs quoting
|
||||
|
||||
local -a query=(
|
||||
\( /$'*\0[ \t\n]#'/ \) # strip off any preceding arguments
|
||||
\(
|
||||
\( "/${open}!/" -'optype[++nest]=1;pre=""'
|
||||
\| "/${open}${(q)orop}/" -'optype[++nest]=2;pre=""'
|
||||
\| "/${open}${andop}/" -'optype[++nest]=3;pre=""'
|
||||
\| '/[]/' ':operators:operator:compadd -F "( ${(q)excl[optype[nest]]} )" -d disp -P ${pre:-${(Q)open}} -S ${(Q)open} \| \& \!' \)
|
||||
\|
|
||||
\( "/${open}[^\\)]##/" "%$close%" # pass over whole var=value, needed due to lack of backtracking after the following
|
||||
\| "/${open}(#i)homeDirectory=/" '/[]/' ':directories:directory:_directories -P / -W / -r ") \t\n\-"'
|
||||
\| "/${open}(#i)loginShell=/" '/[]/' ':shells:shell:compadd -S ${(Q)close} ${(f)^"$(</etc/shells)"}(N)'
|
||||
\| "/${open}(#i)mail=/" '/[]/' ':email-addresses:mail:_email_addresses -S ${(Q)close}'
|
||||
\| "/${open}(#i)objectClass=/" '/[]/' ':object-classes:class:compadd -S ${(Q)close} -M "m:{a-zA-Z}={A-Za-z} r:[^A-Z]||[A-Z]=* r:|=*" -a classes'
|
||||
\| "/${open}(#i)(automountKey|(member|)uid)=/" '/[]/' ':users:username:_users -S ${(Q)close}'
|
||||
\| "/${open}(#i)cn=/" '/[]/' ':cn:cn: _alternative "users:user:_users -S ${close}" "groups:group:_groups -S ${close}" "hosts:host:_hosts -S ${close}"'
|
||||
\|
|
||||
'/[^:=<>~]##/' '%[=:<>~]%' -'pre=""'
|
||||
':object-types:object type:_ldap_attributes -P ${pre:-${(Q)open}} -S = -r ":=~<> \t\n\-"'
|
||||
\(
|
||||
'/:/'
|
||||
'/[^:]##:=/' ':matching-rules:matching rule:compadd -S ":=" -a matchingrules'
|
||||
\|
|
||||
'/([~<>]|)=/' ':operators:operator:compadd -S "" "<=" \>= \~='
|
||||
\)
|
||||
'/[^\\)]##/' "%$close%" ': _message -e object-values "object value (* for presence check)"'
|
||||
\)
|
||||
"/$close/" -'(( nest ))' ':brackets:bracket:compadd ${=query[nest]:+-S ""} \)'
|
||||
\(
|
||||
# This use of -P/-d and an empty match works around a limitation/bug where
|
||||
# mixed use of -P removes any quoting
|
||||
"/$close/" ':operators:operator:compadd ${=query[nest-1]:+-S ""} -d end -P ${(Q)close} ""'
|
||||
\( // -'(( --nest ))' \| '//' -'((!nest))' '/[]/' ': compadd ""' \)
|
||||
\) \#
|
||||
// -'(( nest && optype[nest] > 1 ))'
|
||||
\) \#
|
||||
)
|
||||
|
||||
_regex_arguments _ldap_search_filters "$query[@]"
|
||||
_ldap_search_filters
|
Loading…
Reference in a new issue