script to generate a user list from LDAP (with photos) like
[shellsnippets/shellsnippets.git] / mksh / sysadmin / getjpics.cgi
1 #!/bin/mksh
2 # $Id: getjpics.cgi 2530 2011-11-23 15:09:41Z tglase $
3 #-
4 # Copyright © 2011
5 #       Thorsten Glaser <t.glaser@tarent.de>
6 # Copyright (c) 2002, 2003, 2004, 2006, 2007, 2008, 2009, 2010, 2011
7 #       Thorsten Glaser <tg@mirbsd.org>
8 #
9 # Provided that these terms and disclaimer and all copyright notices
10 # are retained or reproduced in an accompanying document, permission
11 # is granted to deal in this work without restriction, including un-
12 # limited rights to use, publicly perform, distribute, sell, modify,
13 # merge, give away, or sublicence.
14 #
15 # This work is provided "AS IS" and WITHOUT WARRANTY of any kind, to
16 # the utmost extent permitted by applicable law, neither express nor
17 # implied; without malicious intent or gross negligence. In no event
18 # may a licensor, author or contributor be held liable for indirect,
19 # direct, other damage, loss, or other issues arising in any way out
20 # of dealing in the work, even if advised of the possibility of such
21 # damage or existence of a defect, except proven that it results out
22 # of said person's immediate fault when using the work as intended.
23 #-
24 # root@ucs:/usr/lib/cgi-bin/getjpics.cgi
25
26 export LC_ALL=C
27 unset LANGUAGE
28
29 if [[ $1 != really ]]; then
30         cd /var/www/jpics
31         if ! T=$(mktemp /var/www/jpics/index.htm.XXXXXXXXXX); then
32                 print Status: 501 Internal Server Error
33                 print
34                 print Could not create temporary file.
35                 exit 1
36         fi
37         chmod 644 "$T"
38         (mksh "$0" really "$@" >"$T") 2>&1 | \
39             logger -t 'getjpics stderr'
40         mv -f "$T" index.htm
41         print Status: 302 Moved
42         print Location: https://ucs.tarent.de/jpics/index.htm
43         print
44         print 'Moved <a href="/jpics/index.htm">here</a>.'
45         exit 0
46 fi
47
48 function ldapshow {
49         ldapsearch -xLLL "$@" | \
50             tr '\n' $'\a' | sed -e $'s/\a //g' | tr $'\a' '\n'
51         return ${PIPESTATUS[0]}
52 }
53
54 function b64decode {
55         [[ -o utf8-mode ]]; local u=$?
56         set +U
57         local c s="$*" t=
58         [[ -n $s ]] || { s=$(cat;print x); s=${s%x}; }
59         local -i i=0 n=${#s} p=0 v x
60         local -i16 o
61
62         while (( i < n )); do
63                 c=${s:(i++):1}
64                 case $c {
65                 (=)     break ;;
66                 ([A-Z]) (( v = 1#$c - 65 )) ;;
67                 ([a-z]) (( v = 1#$c - 71 )) ;;
68                 ([0-9]) (( v = 1#$c + 4 )) ;;
69                 (+)     v=62 ;;
70                 (/)     v=63 ;;
71                 (*)     continue ;;
72                 }
73                 (( x = (x << 6) | v ))
74                 case $((p++)) {
75                 (0)     continue ;;
76                 (1)     (( o = (x >> 4) & 255 )) ;;
77                 (2)     (( o = (x >> 2) & 255 )) ;;
78                 (3)     (( o = x & 255 ))
79                         p=0
80                         ;;
81                 }
82                 t+=\\x${o#16#}
83         done
84         print -n $t
85         (( u )) || set -U
86 }
87
88 function emit_html_start {
89         cat <<'EOF'
90 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
91  "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
92 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"><head>
93  <meta http-equiv="cache-control" content="no-cache" />
94  <meta http-equiv="content-type" content="text/html; charset=utf-8" />
95  <title>Jabber User Overview</title>
96 </head><body>
97 <h1>Jabber Groups</h1>
98 <p>As the Jabber server sees them.
99  <a href="/cgi-bin/getjpics.cgi">Refresh</a> (takes a few minutes!)
100 </p>
101 EOF
102 }
103
104 function emit_html_grpbeg {
105         local cn=$1 dsc=$2
106
107         print "<h2>$cn</h2>"
108         [[ -n $dsc ]] && print "<p style=\"font-size:large;\">$dsc</p>"
109         print '<table style="border:3px blue outset;" cellpadding="3">'
110 }
111
112 function emit_html_grpend {
113         print '</table>'
114 }
115
116 function emit_html_end {
117         print '</body></html>'
118 }
119
120 function process_dn {
121         local dn=$1 uid curdn curname curuid curphoto curtel skipped
122         local key value iserr e tdstyle
123
124         print '<tr>'
125         if [[ $dn != uid=+([0-9a-z-]),cn=users,dc=tarent,dc=de ]]; then
126                 print '<td colspan="2" style="background-color:red;"' \
127                     'align="left" valign="top">'
128                 print "\tInvald member DN: '$dn'"
129                 print '</td></tr>'
130                 return
131         fi
132         uid=${dn%%,*}
133         uid=${uid#*=}
134         curdn= curname= curuid= curphoto= curtel= skipped=-
135         set -A curmails
136         ldapshow -b cn=users,dc=tarent,dc=de -s one \
137             "(&(uid=${uid})(isJabberAccount=1))" \
138             dn mail uid jpegPhoto displayName telephoneNumber |&
139         while read -p key value; do
140                 if [[ $skipped != - ]]; then
141                         skipped+="$key $value|"
142                         continue
143                 fi
144                 case $key {
145                 (dn:)           curdn=$value ;;
146                 (dn::)          curdn=$(b64decode "$value") ;;
147                 (mail:)         curmails+=("$value") ;;
148                 (mail::)        curmails+=($(b64decode "$value")) ;;
149                 (uid:)          curuid=$value ;;
150                 (uid::)         curuid=$(b64decode "$value") ;;
151                 (jpegPhoto::)   curphoto=$value ;;
152                 (displayName:)          curname=$value ;;
153                 (displayName::)         curname=$(b64decode "$value") ;;
154                 (telephoneNumber:)      curtel=$value ;;
155                 (telephoneNumber::)     curtel=$(b64decode "$value") ;;
156                 }
157                 [[ -n $key ]] || skipped=
158         done
159         iserr=1
160         if [[ -z $curdn ]]; then
161                 e="No Jabber flag for '$dn'"
162         elif [[ $curdn != "$dn" ]]; then
163                 e="DN '$curdn' ≠ '$dn'"
164         elif [[ $curuid != "$uid" ]]; then
165                 e="UID '$curuid' ≠ '$uid' for '$dn'"
166         elif [[ -z $curname ]]; then
167                 e="No displayName in '$dn'"
168         elif [[ -n $skipped ]]; then
169                 e="Skipped content in '$dn': $skipped"
170         else
171                 iserr=0
172         fi
173         if (( iserr )); then
174                 print '<td colspan="2" style="background-color:red;"' \
175                     'align="left" valign="top">'
176                 print '\t'"$e"
177                 print '</td></tr>'
178                 return
179         fi
180         print '<td align="center" valign="center" rowspan="3"' \
181             'style="border:1px solid grey;">'
182         tdstyle=
183         if [[ -n $curphoto ]]; then
184                 [[ $alldns = *":$dn:"* ]] || \
185                     b64decode "$curphoto" >$curuid.jpg
186                 print "\t<img alt=\"$curuid photo\"" \
187                     "src=\"$curuid.jpg\" />"
188         else
189                 print -- -
190                 tdstyle='background-color:#999999; '
191         fi
192         tdstyle+='border:1px solid grey;'
193         print "</td><td style=\"$tdstyle"'" align="left" valign="top" height="1">'
194         print "\t<tt>$curuid</tt>"
195         print "</td></tr>"
196         print "<tr><td style=\"$tdstyle"'" align="left" valign="top">'
197         print '\t<div style="font-size:large;">'
198         print "\t\t$curname\n\t</div>"
199         [[ -n $curtel ]] && \
200             print "\t<p>$curtel</p>"
201         if (( ${#curmails[*]} > 0 )); then
202                 print '\t<p>'
203                 for x in "${curmails[@]}"; do
204                         print "\t\t$x<br />"
205                 done
206                 print '\t</p>'
207         fi
208         print "</td></tr>"
209         print "<tr><td style=\"$tdstyle"'" align="left" valign="bottom" height="1">'
210         print "\t<span style=\"font-size:small;\">$curdn</span>"
211         print '</td></tr>'
212 }
213
214
215 emit_html_start
216
217 alldns=:
218 curcn=
219 curgdsc=
220 set -A curmembers
221 ldapshow -b dc=tarent,dc=de -s sub \
222     '(&(objectClass=posixGroup)(|(cn=freelancer)(cn=mitarbeiter-berlin)(cn=systemaccount)(cn=mitarbeiter-bonn)))' \
223     cn description uniqueMember |&
224 exec 4>&p; exec 4>&-
225 exec 5<&p
226 while read -u5 key value; do
227         case $key {
228         (cn:)   curcn=$value ;;
229         (cn::)  curcn=$(b64decode "$value") ;;
230         (description:)
231                 curgdsc=$value ;;
232         (description::)
233                 curgdsc=$(b64decode "$value") ;;
234         (uniqueMember:)
235                 curmembers+=("$value")
236                 ;;
237         (uniqueMember::)
238                 curmembers+=($(b64decode "$value"))
239                 ;;
240         }
241
242         # ignore unknown lines / keys
243         [[ -z $key ]] || continue
244         # empty lines separate records
245
246         # ignore empty entries
247         if [[ -z $curcn ]]; then
248                 curgdsc=
249                 set -A curmembers
250                 continue
251         fi
252
253         emit_html_grpbeg "$curcn" "$curgdsc"
254
255         # short-circuit empty groups
256         if (( ${#curmembers[*]} == 0 )); then
257                 print '<tr><td colspan="2" align="center" valign="top">'
258                 print '\tEmpty group.'
259                 print '</td></tr>'
260                 emit_html_grpend
261                 curcn=
262                 curgdsc=
263                 set -A curmembers
264                 continue
265         fi
266
267         for dn in "${curmembers[@]}"; do
268                 print -r -- "$dn"
269         done | sort -u |&
270         exec 4>&p; exec 4>&-
271         exec 6<&p
272         while IFS= read -u6 dn; do
273                 process_dn "$dn"
274                 alldns+=$dn:
275         done
276
277         emit_html_grpend
278         curcn=
279         curgdsc=
280         set -A curmembers
281 done
282
283 emitted=0
284 ldapshow isJabberAccount=1 dn | sed -n '/^dn: /s///p' | sort -u | \
285     while IFS= read -r dn; do
286         [[ $alldns = *":$dn:"* ]] && continue
287         if (( !emitted )); then
288                 emit_html_grpbeg ENOENT \
289                     "This lists Jabber accounts in no Roster group"
290                 emitted=1
291         fi
292         process_dn "$dn"
293 done
294 (( emitted )) && emit_html_grpend
295
296 emit_html_end
297 exit 0