1 /*
2 * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
4 */
5
6 #pragma ident "%Z%%M% %I% %E% SMI"
7
8 /*
9 * tmplout.c: display template library output routines for LDAP clients
10 * 12 April 1994 by Mark C Smith
11 */
12
13 #include <stdio.h>
14 #include <string.h>
15 #include <ctype.h>
16 #include <time.h>
17 #include <tzfile.h>
18 #include <stdlib.h>
19 #ifdef MACOS
20 #include "macos.h"
21 #else /* MACOS */
22 #ifdef DOS
23 #include <malloc.h>
24 #include "msdos.h"
25 #else /* DOS */
26 #include <sys/time.h>
27 #include <sys/types.h>
28 #include <sys/file.h>
29 #endif /* DOS */
30 #endif /* MACOS */
31
32 #ifdef VMS
33 #include <sys/socket.h>
34 #endif /* VMS */
35
36 #include "lber.h"
37 #include "ldap.h"
38 #include "ldap-private.h"
39 #include "ldap-int.h"
40 #ifdef SUN
41 /*
42 * to include definition of FILTERFILE and or TEMPLATEFILE
43 */
44 #include "ldapconfig.h"
45 #endif
46
47 #ifdef NEEDPROTOS
48 static int do_entry2text( LDAP *ld, char *buf, char *base, LDAPMessage *entry,
49 struct ldap_disptmpl *tmpl, char **defattrs, char ***defvals,
50 writeptype writeproc, void *writeparm, char *eol, int rdncount,
51 unsigned int opts, char *urlprefix );
52 static int do_entry2text_search( LDAP *ld, char *dn, char *base,
53 LDAPMessage *entry, struct ldap_disptmpl *tmpllist, char **defattrs,
54 char ***defvals, writeptype writeproc, void *writeparm, char *eol,
55 int rdncount, unsigned int opts, char *urlprefix );
56 static int do_vals2text( LDAP *ld, char *buf, char **vals, char *label,
57 int labelwidth, unsigned int syntaxid, writeptype writeproc,
58 void *writeparm, char *eol, int rdncount, char *urlprefix );
59 static int max_label_len( struct ldap_disptmpl *tmpl );
60 static int output_label( char *buf, char *label, int width,
61 writeptype writeproc, void *writeparm, char *eol, int html );
62 static int output_dn( char *buf, char *dn, int width, int rdncount,
63 writeptype writeproc, void *writeparm, char *eol, char *urlprefix );
64 static void strcat_escaped( char *s1, char *s2 );
65 static char *time2text( char *ldtimestr, int dateonly );
66 static time_t gtime( struct tm *tm );
67 static int searchaction( LDAP *ld, char *buf, char *base, LDAPMessage *entry,
68 char *dn, struct ldap_tmplitem *tip, int labelwidth, int rdncount,
69 writeptype writeproc, void *writeparm, char *eol, char *urlprefix );
70 #else /* NEEDPROTOS */
71 static int do_entry2text();
72 static int do_entry2text_search();
73 static int do_vals2text();
74 static int max_label_len();
75 static int output_label();
76 static int output_dn();
77 static void strcat_escaped();
78 static char *time2text();
79 static time_t gtime();
80 static int searchaction();
81 #endif /* NEEDPROTOS */
82
83 #define DEF_LABEL_WIDTH 15
84 #define SEARCH_TIMEOUT_SECS 120
85 #define OCATTRNAME "objectClass"
86
87
88 #define NONFATAL_LDAP_ERR( err ) ( err == LDAP_SUCCESS || \
89 err == LDAP_TIMELIMIT_EXCEEDED || err == LDAP_SIZELIMIT_EXCEEDED )
90
91 #define DEF_LDAP_URL_PREFIX "ldap:///"
92
93
94 int
ldap_entry2text(LDAP * ld,char * buf,LDAPMessage * entry,struct ldap_disptmpl * tmpl,char ** defattrs,char *** defvals,writeptype writeproc,void * writeparm,char * eol,int rdncount,unsigned int opts)95 ldap_entry2text(
96 LDAP *ld,
97 char *buf, /* NULL for "use internal" */
98 LDAPMessage *entry,
99 struct ldap_disptmpl *tmpl,
100 char **defattrs,
101 char ***defvals,
102 writeptype writeproc,
103 void *writeparm,
104 char *eol,
105 int rdncount,
106 unsigned int opts
107 )
108 {
109 #if defined( SUN ) && defined( _REENTRANT )
110 int rv;
111
112 LOCK_LDAP(ld);
113 #endif
114 Debug( LDAP_DEBUG_TRACE, catgets(slapdcat, 1, 253, "ldap_entry2text\n"), 0, 0, 0 );
115
116 #if defined( SUN ) && defined( _REENTRANT )
117 rv = do_entry2text( ld, buf, NULL, entry, tmpl, defattrs, defvals,
118 writeproc, writeparm, eol, rdncount, opts, NULL );
119 UNLOCK_LDAP(ld);
120 return( rv );
121 #else
122 return( do_entry2text( ld, buf, NULL, entry, tmpl, defattrs, defvals,
123 writeproc, writeparm, eol, rdncount, opts, NULL ));
124 #endif
125 }
126
127
128
129 int
ldap_entry2html(LDAP * ld,char * buf,LDAPMessage * entry,struct ldap_disptmpl * tmpl,char ** defattrs,char *** defvals,writeptype writeproc,void * writeparm,char * eol,int rdncount,unsigned int opts,char * base,char * urlprefix)130 ldap_entry2html(
131 LDAP *ld,
132 char *buf, /* NULL for "use internal" */
133 LDAPMessage *entry,
134 struct ldap_disptmpl *tmpl,
135 char **defattrs,
136 char ***defvals,
137 writeptype writeproc,
138 void *writeparm,
139 char *eol,
140 int rdncount,
141 unsigned int opts,
142 char *base,
143 char *urlprefix
144 )
145 {
146 #if defined( SUN ) && defined( _REENTRANT )
147 int rv;
148
149 LOCK_LDAP(ld);
150 #endif
151 Debug( LDAP_DEBUG_TRACE, catgets(slapdcat, 1, 254, "ldap_entry2html\n"), 0, 0, 0 );
152
153 if ( urlprefix == NULL ) {
154 urlprefix = DEF_LDAP_URL_PREFIX;
155 }
156
157 #if defined( SUN ) && defined( _REENTRANT )
158 rv = do_entry2text( ld, buf, base, entry, tmpl, defattrs, defvals,
159 writeproc, writeparm, eol, rdncount, opts, urlprefix );
160 UNLOCK_LDAP(ld);
161 return( rv );
162 #else
163 return( do_entry2text( ld, buf, base, entry, tmpl, defattrs, defvals,
164 writeproc, writeparm, eol, rdncount, opts, urlprefix ));
165 #endif
166 }
167
168
169 static int
do_entry2text(LDAP * ld,char * buf,char * base,LDAPMessage * entry,struct ldap_disptmpl * tmpl,char ** defattrs,char *** defvals,writeptype writeproc,void * writeparm,char * eol,int rdncount,unsigned int opts,char * urlprefix)170 do_entry2text(
171 LDAP *ld,
172 char *buf, /* NULL for use-internal */
173 char *base, /* used for search actions */
174 LDAPMessage *entry,
175 struct ldap_disptmpl *tmpl,
176 char **defattrs,
177 char ***defvals,
178 writeptype writeproc,
179 void *writeparm,
180 char *eol,
181 int rdncount,
182 unsigned int opts,
183 char *urlprefix /* if non-NULL, do HTML */
184 )
185 {
186 int i, err, html, show, labelwidth;
187 int freebuf, freevals;
188 char *dn, **vals;
189 struct ldap_tmplitem *rowp, *colp;
190
191 if (( dn = ldap_get_dn( ld, entry )) == NULL ) {
192 return( ld->ld_errno );
193 }
194
195 if ( buf == NULL ) {
196 if (( buf = malloc( LDAP_DTMPL_BUFSIZ )) == NULL ) {
197 ld->ld_errno = LDAP_NO_MEMORY;
198 free( dn );
199 return( ld->ld_errno );
200 }
201 freebuf = 1;
202 } else {
203 freebuf = 0;
204 }
205
206 html = ( urlprefix != NULL );
207
208 if ( html ) {
209 /*
210 * add HTML intro. and title
211 */
212 if (!(( opts & LDAP_DISP_OPT_HTMLBODYONLY ) != 0 )) {
213 sprintf( buf, "<HTML>%s<HEAD>%s<TITLE>%s%s - ", eol, eol, eol,
214 ( tmpl == NULL ) ? "Entry" : tmpl->dt_name );
215 (*writeproc)( writeparm, buf, strlen( buf ));
216 output_dn( buf, dn, 0, rdncount, writeproc, writeparm, "", NULL );
217 sprintf( buf, "%s</TITLE>%s</HEAD>%s<BODY>%s<H3>%s - ", eol, eol,
218 eol, eol, ( tmpl == NULL ) ? "Entry" : tmpl->dt_name );
219 (*writeproc)( writeparm, buf, strlen( buf ));
220 output_dn( buf, dn, 0, rdncount, writeproc, writeparm, "", NULL );
221 sprintf( buf, "</H3>%s", eol );
222 (*writeproc)( writeparm, buf, strlen( buf ));
223 }
224
225 if (( opts & LDAP_DISP_OPT_NONLEAF ) != 0 &&
226 ( vals = ldap_explode_dn( dn, 0 )) != NULL ) {
227 char *untagged;
228
229 /*
230 * add "Move Up" link
231 */
232 sprintf( buf, "<A HREF=\"%s", urlprefix );
233 for ( i = 1; vals[ i ] != NULL; ++i ) {
234 if ( i > 1 ) {
235 strcat_escaped( buf, ", " );
236 }
237 strcat_escaped( buf, vals[ i ] );
238 }
239 if ( vals[ 1 ] != NULL ) {
240 untagged = strchr( vals[ 1 ], '=' );
241 } else {
242 untagged = "=The World";
243 }
244 sprintf( buf + strlen( buf ),
245 "%s\">Move Up To <EM>%s</EM></A>%s<BR>",
246 ( vals[ 1 ] == NULL ) ? "??one" : "",
247 ( untagged != NULL ) ? untagged + 1 : vals[ 1 ], eol, eol );
248 (*writeproc)( writeparm, buf, strlen( buf ));
249
250 /*
251 * add "Browse" link
252 */
253 untagged = strchr( vals[ 0 ], '=' );
254 sprintf( buf, "<A HREF=\"%s", urlprefix );
255 strcat_escaped( buf, dn );
256 sprintf( buf + strlen( buf ), "??one?(!(objectClass=dsa))\">Browse Below <EM>%s</EM></A>%s%s",
257 ( untagged != NULL ) ? untagged + 1 : vals[ 0 ], eol, eol );
258 (*writeproc)( writeparm, buf, strlen( buf ));
259
260 ldap_value_free( vals );
261 }
262
263 (*writeproc)( writeparm, "<HR>", 4 ); /* horizontal rule */
264 } else {
265 (*writeproc)( writeparm, "\"", 1 );
266 output_dn( buf, dn, 0, rdncount, writeproc, writeparm, "", NULL );
267 sprintf( buf, "\"%s", eol );
268 (*writeproc)( writeparm, buf, strlen( buf ));
269 }
270
271 if ( tmpl != NULL && ( opts & LDAP_DISP_OPT_AUTOLABELWIDTH ) != 0 ) {
272 labelwidth = max_label_len( tmpl ) + 3;
273 } else {
274 labelwidth = DEF_LABEL_WIDTH;;
275 }
276
277 err = LDAP_SUCCESS;
278
279 if ( tmpl == NULL ) {
280 BerElement *ber;
281 char *attr;
282
283 ber = NULL;
284 for ( attr = ldap_first_attribute( ld, entry, &ber );
285 NONFATAL_LDAP_ERR( err ) && attr != NULL;
286 attr = ldap_next_attribute( ld, entry, ber )) {
287 if (( vals = ldap_get_values( ld, entry, attr )) == NULL ) {
288 freevals = 0;
289 if ( defattrs != NULL ) {
290 for ( i = 0; defattrs[ i ] != NULL; ++i ) {
291 if ( strcasecmp( attr, defattrs[ i ] ) == 0 ) {
292 break;
293 }
294 }
295 if ( defattrs[ i ] != NULL ) {
296 vals = defvals[ i ];
297 }
298 }
299 } else {
300 freevals = 1;
301 }
302
303 if ( islower( *attr )) { /* cosmetic -- upcase attr. name */
304 *attr = toupper( *attr );
305 }
306
307 err = do_vals2text( ld, buf, vals, attr, labelwidth,
308 LDAP_SYN_CASEIGNORESTR, writeproc, writeparm, eol,
309 rdncount, urlprefix );
310 if ( freevals ) {
311 ldap_value_free( vals );
312 }
313 }
314 } else {
315 for ( rowp = ldap_first_tmplrow( tmpl );
316 NONFATAL_LDAP_ERR( err ) && rowp != NULLTMPLITEM;
317 rowp = ldap_next_tmplrow( tmpl, rowp )) {
318 for ( colp = ldap_first_tmplcol( tmpl, rowp ); colp != NULLTMPLITEM;
319 colp = ldap_next_tmplcol( tmpl, rowp, colp )) {
320 vals = NULL;
321 if ( colp->ti_attrname == NULL || ( vals = ldap_get_values( ld,
322 entry, colp->ti_attrname )) == NULL ) {
323 freevals = 0;
324 if ( !LDAP_IS_TMPLITEM_OPTION_SET( colp,
325 LDAP_DITEM_OPT_HIDEIFEMPTY ) && defattrs != NULL
326 && colp->ti_attrname != NULL ) {
327 for ( i = 0; defattrs[ i ] != NULL; ++i ) {
328 if ( strcasecmp( colp->ti_attrname, defattrs[ i ] )
329 == 0 ) {
330 break;
331 }
332 }
333 if ( defattrs[ i ] != NULL ) {
334 vals = defvals[ i ];
335 }
336 }
337 } else {
338 freevals = 1;
339 if ( LDAP_IS_TMPLITEM_OPTION_SET( colp,
340 LDAP_DITEM_OPT_SORTVALUES ) && vals[ 0 ] != NULL
341 && vals[ 1 ] != NULL ) {
342 ldap_sort_values( ld, vals, ldap_sort_strcasecmp );
343 }
344 }
345
346 /*
347 * don't bother even calling do_vals2text() if no values
348 * or boolean with value false and "hide if false" option set
349 */
350 show = ( vals != NULL && vals[ 0 ] != NULL );
351 if ( show && LDAP_GET_SYN_TYPE( colp->ti_syntaxid )
352 == LDAP_SYN_TYPE_BOOLEAN && LDAP_IS_TMPLITEM_OPTION_SET(
353 colp, LDAP_DITEM_OPT_HIDEIFFALSE ) &&
354 toupper( vals[ 0 ][ 0 ] ) != 'T' ) {
355 show = 0;
356 }
357
358 if ( colp->ti_syntaxid == LDAP_SYN_SEARCHACTION ) {
359 if (( opts & LDAP_DISP_OPT_DOSEARCHACTIONS ) != 0 ) {
360 if ( colp->ti_attrname == NULL || ( show &&
361 toupper( vals[ 0 ][ 0 ] ) == 'T' )) {
362 err = searchaction( ld, buf, base, entry, dn, colp,
363 labelwidth, rdncount, writeproc,
364 writeparm, eol, urlprefix );
365 }
366 }
367 show = 0;
368 }
369
370 if ( show ) {
371 err = do_vals2text( ld, buf, vals, colp->ti_label,
372 labelwidth, colp->ti_syntaxid, writeproc, writeparm,
373 eol, rdncount, urlprefix );
374 }
375
376 if ( freevals ) {
377 ldap_value_free( vals );
378 }
379 }
380 }
381 }
382
383 if ( html && !(( opts & LDAP_DISP_OPT_HTMLBODYONLY ) != 0 )) {
384 sprintf( buf, "</BODY>%s</HTML>%s", eol, eol );
385 (*writeproc)( writeparm, buf, strlen( buf ));
386 }
387
388 free( dn );
389 if ( freebuf ) {
390 free( buf );
391 }
392
393 return( err );
394 }
395
396
397 int
ldap_entry2text_search(LDAP * ld,char * dn,char * base,LDAPMessage * entry,struct ldap_disptmpl * tmpllist,char ** defattrs,char *** defvals,writeptype writeproc,void * writeparm,char * eol,int rdncount,unsigned int opts)398 ldap_entry2text_search(
399 LDAP *ld,
400 char *dn, /* if NULL, use entry */
401 char *base, /* if NULL, no search actions */
402 LDAPMessage *entry, /* if NULL, use dn */
403 struct ldap_disptmpl* tmpllist, /* if NULL, load default file */
404 char **defattrs,
405 char ***defvals,
406 writeptype writeproc,
407 void *writeparm,
408 char *eol,
409 int rdncount, /* if 0, display full DN */
410 unsigned int opts
411 )
412 {
413 #if defined( SUN ) && defined( _REENTRANT )
414 int rv;
415
416 LOCK_LDAP(ld);
417 #endif
418 Debug( LDAP_DEBUG_TRACE, catgets(slapdcat, 1, 255, "ldap_entry2text_search\n"), 0, 0, 0 );
419
420 #if defined( SUN ) && defined( _REENTRANT )
421 rv = do_entry2text_search( ld, dn, base, entry, tmpllist, defattrs,
422 defvals, writeproc, writeparm, eol, rdncount, opts, NULL );
423 UNLOCK_LDAP(ld);
424 return( rv );
425 #else
426 return( do_entry2text_search( ld, dn, base, entry, tmpllist, defattrs,
427 defvals, writeproc, writeparm, eol, rdncount, opts, NULL ));
428 #endif
429 }
430
431
432
433 int
ldap_entry2html_search(LDAP * ld,char * dn,char * base,LDAPMessage * entry,struct ldap_disptmpl * tmpllist,char ** defattrs,char *** defvals,writeptype writeproc,void * writeparm,char * eol,int rdncount,unsigned int opts,char * urlprefix)434 ldap_entry2html_search(
435 LDAP *ld,
436 char *dn, /* if NULL, use entry */
437 char *base, /* if NULL, no search actions */
438 LDAPMessage *entry, /* if NULL, use dn */
439 struct ldap_disptmpl* tmpllist, /* if NULL, load default file */
440 char **defattrs,
441 char ***defvals,
442 writeptype writeproc,
443 void *writeparm,
444 char *eol,
445 int rdncount, /* if 0, display full DN */
446 unsigned int opts,
447 char *urlprefix
448 )
449 {
450 #if defined( SUN ) && defined( _REENTRANT )
451 int rv;
452
453 LOCK_LDAP(ld);
454 #endif
455 Debug( LDAP_DEBUG_TRACE, catgets(slapdcat, 1, 256, "ldap_entry2html_search\n"), 0, 0, 0 );
456
457 #if defined( SUN ) && defined( _REENTRANT )
458 rv = do_entry2text_search( ld, dn, base, entry, tmpllist, defattrs,
459 defvals, writeproc, writeparm, eol, rdncount, opts, urlprefix );
460 UNLOCK_LDAP(ld);
461 return( rv );
462 #else
463 return( do_entry2text_search( ld, dn, base, entry, tmpllist, defattrs,
464 defvals, writeproc, writeparm, eol, rdncount, opts, urlprefix ));
465 #endif
466 }
467
468
469 static int
do_entry2text_search(LDAP * ld,char * dn,char * base,LDAPMessage * entry,struct ldap_disptmpl * tmpllist,char ** defattrs,char *** defvals,writeptype writeproc,void * writeparm,char * eol,int rdncount,unsigned int opts,char * urlprefix)470 do_entry2text_search(
471 LDAP *ld,
472 char *dn, /* if NULL, use entry */
473 char *base, /* if NULL, no search actions */
474 LDAPMessage *entry, /* if NULL, use dn */
475 struct ldap_disptmpl* tmpllist, /* if NULL, load default file */
476 char **defattrs,
477 char ***defvals,
478 writeptype writeproc,
479 void *writeparm,
480 char *eol,
481 int rdncount, /* if 0, display full DN */
482 unsigned int opts,
483 char *urlprefix
484 )
485 {
486 int err, freedn, freetmpls, html;
487 char *buf, **fetchattrs, **vals;
488 LDAPMessage *ldmp;
489 struct ldap_disptmpl *tmpl;
490 struct timeval timeout;
491
492 if ( dn == NULL && entry == NULLMSG ) {
493 ld->ld_errno = LDAP_PARAM_ERROR;
494 return( ld->ld_errno );
495 }
496
497 html = ( urlprefix != NULL );
498
499 timeout.tv_sec = SEARCH_TIMEOUT_SECS;
500 timeout.tv_usec = 0;
501
502 if (( buf = malloc( LDAP_DTMPL_BUFSIZ )) == NULL ) {
503 ld->ld_errno = LDAP_NO_MEMORY;
504 return( ld->ld_errno );
505 }
506
507 freedn = freetmpls = 0;
508 tmpl = NULL;
509
510 if ( tmpllist == NULL ) {
511 if (( err = ldap_init_templates( TEMPLATEFILE, &tmpllist )) != 0 ) {
512 sprintf( buf, "%sUnable to read template file %s (error %d)%s%s",
513 html ? "<!-- " : "", TEMPLATEFILE, err,
514 html ? "-->" : "", eol );
515 (*writeproc)( writeparm, buf, strlen( buf ));
516 }
517 freetmpls = 1;
518 }
519
520 if ( dn == NULL ) {
521 if (( dn = ldap_get_dn( ld, entry )) == NULL ) {
522 free( buf );
523 if ( freetmpls ) {
524 ldap_free_templates( tmpllist );
525 }
526 return( ld->ld_errno );
527 }
528 freedn = 1;
529 }
530
531
532 if ( tmpllist != NULL ) {
533 ldmp = NULLMSG;
534
535 if ( entry == NULL ) {
536 char *ocattrs[2];
537
538 ocattrs[0] = OCATTRNAME;
539 ocattrs[1] = NULL;
540 #ifdef CLDAP
541 if ( LDAP_IS_CLDAP( ld ))
542 err = cldap_search_s( ld, dn, LDAP_SCOPE_BASE,
543 "objectClass=*", ocattrs, 0, &ldmp, NULL );
544 else
545 #endif /* CLDAP */
546 err = ldap_search_st( ld, dn, LDAP_SCOPE_BASE,
547 "objectClass=*", ocattrs, 0, &timeout, &ldmp );
548
549 if ( err == LDAP_SUCCESS ) {
550 entry = ldap_first_entry( ld, ldmp );
551 }
552 }
553
554 if ( entry != NULL ) {
555 vals = ldap_get_values( ld, entry, OCATTRNAME );
556 tmpl = ldap_oc2template( vals, tmpllist );
557 if ( vals != NULL ) {
558 ldap_value_free( vals );
559 }
560 }
561 if ( ldmp != NULL ) {
562 ldap_msgfree( ldmp );
563 }
564 }
565
566 entry = NULL;
567
568 if ( tmpl == NULL ) {
569 fetchattrs = NULL;
570 } else {
571 fetchattrs = ldap_tmplattrs( tmpl, NULL, 1, LDAP_SYN_OPT_DEFER );
572 }
573
574 #ifdef CLDAP
575 if ( LDAP_IS_CLDAP( ld ))
576 err = cldap_search_s( ld, dn, LDAP_SCOPE_BASE, "objectClass=*",
577 fetchattrs, 0, &ldmp, NULL );
578 else
579 #endif /* CLDAP */
580 err = ldap_search_st( ld, dn, LDAP_SCOPE_BASE, "objectClass=*",
581 fetchattrs, 0, &timeout, &ldmp );
582
583 if ( freedn ) {
584 free( dn );
585 }
586 if ( fetchattrs != NULL ) {
587 ldap_value_free( fetchattrs );
588 }
589
590 if ( err != LDAP_SUCCESS ||
591 ( entry = ldap_first_entry( ld, ldmp )) == NULL ) {
592 if ( freetmpls ) {
593 ldap_free_templates( tmpllist );
594 }
595 free( buf );
596 return( ld->ld_errno );
597 }
598
599 err = do_entry2text( ld, buf, base, entry, tmpl, defattrs, defvals,
600 writeproc, writeparm, eol, rdncount, opts, urlprefix );
601
602 free( buf );
603 if ( freetmpls ) {
604 ldap_free_templates( tmpllist );
605 }
606 ldap_msgfree( ldmp );
607 return( err );
608 }
609
610
611 int
ldap_vals2text(LDAP * ld,char * buf,char ** vals,char * label,int labelwidth,unsigned int syntaxid,writeptype writeproc,void * writeparm,char * eol,int rdncount)612 ldap_vals2text(
613 LDAP *ld,
614 char *buf, /* NULL for "use internal" */
615 char **vals,
616 char *label,
617 int labelwidth, /* 0 means use default */
618 unsigned int syntaxid,
619 writeptype writeproc,
620 void *writeparm,
621 char *eol,
622 int rdncount
623 )
624 {
625 #if defined( SUN ) && defined( _REENTRANT )
626 int rv;
627
628 LOCK_LDAP(ld);
629 #endif
630 Debug( LDAP_DEBUG_TRACE, catgets(slapdcat, 1, 257, "ldap_vals2text\n"), 0, 0, 0 );
631
632 #if defined( SUN ) && defined( _REENTRANT )
633 rv = do_vals2text( ld, buf, vals, label, labelwidth, syntaxid,
634 writeproc, writeparm, eol, rdncount, NULL );
635 UNLOCK_LDAP(ld);
636 return( rv );
637 #else
638 return( do_vals2text( ld, buf, vals, label, labelwidth, syntaxid,
639 writeproc, writeparm, eol, rdncount, NULL ));
640 #endif
641 }
642
643
644 int
ldap_vals2html(LDAP * ld,char * buf,char ** vals,char * label,int labelwidth,unsigned int syntaxid,writeptype writeproc,void * writeparm,char * eol,int rdncount,char * urlprefix)645 ldap_vals2html(
646 LDAP *ld,
647 char *buf, /* NULL for "use internal" */
648 char **vals,
649 char *label,
650 int labelwidth, /* 0 means use default */
651 unsigned int syntaxid,
652 writeptype writeproc,
653 void *writeparm,
654 char *eol,
655 int rdncount,
656 char *urlprefix
657 )
658 {
659 #if defined( SUN ) && defined( _REENTRANT )
660 int rv;
661
662 LOCK_LDAP(ld);
663 #endif
664 Debug( LDAP_DEBUG_TRACE, catgets(slapdcat, 1, 258, "ldap_vals2html\n"), 0, 0, 0 );
665
666 if ( urlprefix == NULL ) {
667 urlprefix = DEF_LDAP_URL_PREFIX;
668 }
669
670 #if defined( SUN ) && defined( _REENTRANT )
671 rv = do_vals2text( ld, buf, vals, label, labelwidth, syntaxid,
672 writeproc, writeparm, eol, rdncount, urlprefix );
673 UNLOCK_LDAP(ld);
674 return( rv );
675 #else
676 return( do_vals2text( ld, buf, vals, label, labelwidth, syntaxid,
677 writeproc, writeparm, eol, rdncount, urlprefix ));
678 #endif
679 }
680
681
682 static int
do_vals2text(LDAP * ld,char * buf,char ** vals,char * label,int labelwidth,unsigned int syntaxid,writeptype writeproc,void * writeparm,char * eol,int rdncount,char * urlprefix)683 do_vals2text(
684 LDAP *ld,
685 char *buf, /* NULL for "use internal" */
686 char **vals,
687 char *label,
688 int labelwidth, /* 0 means use default */
689 unsigned int syntaxid,
690 writeptype writeproc,
691 void *writeparm,
692 char *eol,
693 int rdncount,
694 char *urlprefix
695 )
696 {
697 int i, html, writeoutval, freebuf, notascii;
698 char *p, *s, *outval;
699
700
701 if ( vals == NULL ) {
702 return( LDAP_SUCCESS );
703 }
704
705 html = ( urlprefix != NULL );
706
707 switch( LDAP_GET_SYN_TYPE( syntaxid )) {
708 case LDAP_SYN_TYPE_TEXT:
709 case LDAP_SYN_TYPE_BOOLEAN:
710 break; /* we only bother with these two types... */
711 default:
712 return( LDAP_SUCCESS );
713 }
714
715 if ( labelwidth == 0 || labelwidth < 0 ) {
716 labelwidth = DEF_LABEL_WIDTH;
717 }
718
719 if ( buf == NULL ) {
720 if (( buf = malloc( LDAP_DTMPL_BUFSIZ )) == NULL ) {
721 ld->ld_errno = LDAP_NO_MEMORY;
722 return( ld->ld_errno );
723 }
724 freebuf = 1;
725 } else {
726 freebuf = 0;
727 }
728
729 output_label( buf, label, labelwidth, writeproc, writeparm, eol, html );
730
731 for ( i = 0; vals[ i ] != NULL; ++i ) {
732 for ( p = vals[ i ]; *p != '\0'; ++p ) {
733 if ( !isascii( *p )) {
734 break;
735 }
736 }
737 notascii = ( *p != '\0' );
738 outval = notascii ? "(unable to display non-ASCII text value)"
739 : vals[ i ];
740
741 writeoutval = 0; /* if non-zero, write outval after switch */
742
743 switch( syntaxid ) {
744 case LDAP_SYN_CASEIGNORESTR:
745 ++writeoutval;
746 break;
747
748 case LDAP_SYN_RFC822ADDR:
749 if ( html ) {
750 strcpy( buf, "<DD><A HREF=\"mailto:" );
751 strcat_escaped( buf, outval );
752 sprintf( buf + strlen( buf ), "\">%s</A><BR>%s", outval, eol );
753 (*writeproc)( writeparm, buf, strlen( buf ));
754 } else {
755 ++writeoutval;
756 }
757 break;
758
759 case LDAP_SYN_DN: /* for now */
760 output_dn( buf, outval, labelwidth, rdncount, writeproc,
761 writeparm, eol, urlprefix );
762 break;
763
764 case LDAP_SYN_MULTILINESTR:
765 if ( i > 0 && !html ) {
766 output_label( buf, label, labelwidth, writeproc,
767 writeparm, eol, html );
768 }
769
770 p = s = outval;
771 while (( s = strchr( s, '$' )) != NULL ) {
772 *s++ = '\0';
773 while ( isspace( *s )) {
774 ++s;
775 }
776 if ( html ) {
777 sprintf( buf, "<DD>%s<BR>%s", p, eol );
778 } else {
779 sprintf( buf, "%-*s%s%s", labelwidth, " ", p, eol );
780 }
781 (*writeproc)( writeparm, buf, strlen( buf ));
782 p = s;
783 }
784 outval = p;
785 ++writeoutval;
786 break;
787
788 case LDAP_SYN_BOOLEAN:
789 outval = toupper( outval[ 0 ] ) == 'T' ? "TRUE" : "FALSE";
790 ++writeoutval;
791 break;
792
793 case LDAP_SYN_TIME:
794 case LDAP_SYN_DATE:
795 outval = time2text( outval, syntaxid == LDAP_SYN_DATE );
796 ++writeoutval;
797 break;
798
799 case LDAP_SYN_LABELEDURL:
800 if ( !notascii && ( p = strchr( outval, '$' )) != NULL ) {
801 *p++ = '\0';
802 while ( isspace( *p )) {
803 ++p;
804 }
805 s = outval;
806 } else if ( !notascii && ( s = strchr( outval, ' ' )) != NULL ) {
807 *s++ = '\0';
808 while ( isspace( *s )) {
809 ++s;
810 }
811 p = outval;
812 } else {
813 s = "URL";
814 p = outval;
815 }
816
817 /*
818 * at this point `s' points to the label & `p' to the URL
819 */
820 if ( html ) {
821 sprintf( buf, "<DD><A HREF=\"%s\">%s</A><BR>%s", p, s, eol );
822 } else {
823 sprintf( buf, "%-*s%s%s%-*s%s%s", labelwidth, " ",
824 s, eol, labelwidth + 2, " ",p , eol );
825 }
826 (*writeproc)( writeparm, buf, strlen( buf ));
827 break;
828
829 default:
830 sprintf( buf, " Can't display item type %ld%s",
831 syntaxid, eol );
832 (*writeproc)( writeparm, buf, strlen( buf ));
833 }
834
835 if ( writeoutval ) {
836 if ( html ) {
837 sprintf( buf, "<DD>%s<BR>%s", outval, eol );
838 } else {
839 sprintf( buf, "%-*s%s%s", labelwidth, " ", outval, eol );
840 }
841 (*writeproc)( writeparm, buf, strlen( buf ));
842 }
843 }
844
845 if ( freebuf ) {
846 free( buf );
847 }
848
849 return( LDAP_SUCCESS );
850 }
851
852
853 static int
max_label_len(struct ldap_disptmpl * tmpl)854 max_label_len( struct ldap_disptmpl *tmpl )
855 {
856 struct ldap_tmplitem *rowp, *colp;
857 int len, maxlen;
858
859 maxlen = 0;
860
861 for ( rowp = ldap_first_tmplrow( tmpl ); rowp != NULLTMPLITEM;
862 rowp = ldap_next_tmplrow( tmpl, rowp )) {
863 for ( colp = ldap_first_tmplcol( tmpl, rowp ); colp != NULLTMPLITEM;
864 colp = ldap_next_tmplcol( tmpl, rowp, colp )) {
865 if (( len = strlen( colp->ti_label )) > maxlen ) {
866 maxlen = len;
867 }
868 }
869 }
870
871 return( maxlen );
872 }
873
874
875 static int
output_label(char * buf,char * label,int width,writeptype writeproc,void * writeparm,char * eol,int html)876 output_label( char *buf, char *label, int width, writeptype writeproc,
877 void *writeparm, char *eol, int html )
878 {
879 char *p;
880
881 if ( html ) {
882 sprintf( buf, "<DT><B>%s</B>", label );
883 } else {
884 sprintf( buf, " %s:", label );
885 p = buf + strlen( buf );
886
887 while ( p - buf < width ) {
888 *p++ = ' ';
889 }
890
891 *p = '\0';
892 strcat( buf, eol );
893 }
894
895 return ((*writeproc)( writeparm, buf, strlen( buf )));
896 }
897
898
899 static int
output_dn(char * buf,char * dn,int width,int rdncount,writeptype writeproc,void * writeparm,char * eol,char * urlprefix)900 output_dn( char *buf, char *dn, int width, int rdncount,
901 writeptype writeproc, void *writeparm, char *eol, char *urlprefix )
902 {
903 char **dnrdns;
904 int i;
905
906 if (( dnrdns = ldap_explode_dn( dn, 1 )) == NULL ) {
907 return( -1 );
908 }
909
910 if ( urlprefix != NULL ) {
911 sprintf( buf, "<DD><A HREF=\"%s", urlprefix );
912 strcat_escaped( buf, dn );
913 strcat( buf, "\">" );
914 } else if ( width > 0 ) {
915 sprintf( buf, "%-*s", width, " " );
916 } else {
917 *buf = '\0';
918 }
919
920 for ( i = 0; dnrdns[ i ] != NULL && ( rdncount == 0 || i < rdncount );
921 ++i ) {
922 if ( i > 0 ) {
923 strcat( buf, ", " );
924 }
925 strcat( buf, dnrdns[ i ] );
926 }
927
928 if ( urlprefix != NULL ) {
929 strcat( buf, "</A><BR>" );
930 }
931
932 ldap_value_free( dnrdns );
933
934 strcat( buf, eol );
935
936 return ((*writeproc)( writeparm, buf, strlen( buf )));
937 }
938
939
940
941 #define HREF_CHAR_ACCEPTABLE( c ) (( c >= '-' && c <= '9' ) || \
942 ( c >= '@' && c <= 'Z' ) || \
943 ( c == '_' ) || \
944 ( c >= 'a' && c <= 'z' ))
945
946 static void
strcat_escaped(char * s1,char * s2)947 strcat_escaped( char *s1, char *s2 )
948 {
949 char *p, *q;
950 char *hexdig = "0123456789ABCDEF";
951
952 p = s1 + strlen( s1 );
953 for ( q = s2; *q != '\0'; ++q ) {
954 if ( HREF_CHAR_ACCEPTABLE( *q )) {
955 *p++ = *q;
956 } else {
957 *p++ = '%';
958 *p++ = hexdig[ *q >> 4 ];
959 *p++ = hexdig[ *q & 0x0F ];
960 }
961 }
962
963 *p = '\0';
964 }
965
966
967 #define GET2BYTENUM( p ) (( *p - '0' ) * 10 + ( *(p+1) - '0' ))
968
969 static char *
time2text(char * ldtimestr,int dateonly)970 time2text( char *ldtimestr, int dateonly )
971 {
972 struct tm t;
973 char *p, zone, *fmterr = "badly formatted time";
974 time_t gmttime;
975 int century;
976 static char timestr[128];
977
978 memset( (char *)&t, 0, sizeof( struct tm ));
979 if ( (int) strlen( ldtimestr ) < 13 ) {
980 return( fmterr );
981 }
982
983 for ( p = ldtimestr; p - ldtimestr < 12; ++p ) {
984 if ( !isdigit( *p )) {
985 return( fmterr );
986 }
987 }
988
989 p = ldtimestr;
990 century = GET2BYTENUM( p ) * 100; p += 2;
991 century += GET2BYTENUM( p ); p += 2;
992 /* tm_year is the offset of number of years from TM_YEAR_BASE */
993 t.tm_year = century - TM_YEAR_BASE;
994 t.tm_mon = GET2BYTENUM( p ) - 1; p += 2;
995 t.tm_mday = GET2BYTENUM( p ); p += 2;
996 t.tm_hour = GET2BYTENUM( p ); p += 2;
997 t.tm_min = GET2BYTENUM( p ); p += 2;
998 t.tm_sec = GET2BYTENUM( p ); p += 2;
999
1000 /*strftime will return for e.g. Thu Aug 19 2001 */
1001 if (strftime(timestr, sizeof(timestr), "%a %b %d %Y", &t) == 0) {
1002 return( fmterr );
1003 }
1004 if (dateonly) {
1005 strcpy(timestr + 11, timestr + 20);
1006 }
1007 return( timestr );
1008 }
1009
1010
1011
1012 /* gtime.c - inverse gmtime */
1013
1014 #if !defined( MACOS ) && !defined( _WIN32 ) && !defined( DOS )
1015 #include <sys/time.h>
1016 #endif /* !MACOS */
1017
1018 /* gtime(): the inverse of localtime().
1019 This routine was supplied by Mike Accetta at CMU many years ago.
1020 */
1021
1022 static int dmsize[] = {
1023 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
1024 };
1025
1026 #define dysize(y) \
1027 (((y) % 4) ? 365 : (((y) % 100) ? 366 : (((y) % 400) ? 365 : 366)))
1028
1029 #define YEAR(y) ((y) >= 100 ? (y) : (y) + 1900)
1030
1031 /* */
1032
gtime(struct tm * tm)1033 static time_t gtime ( struct tm *tm )
1034 {
1035 register int i,
1036 sec,
1037 mins,
1038 hour,
1039 mday,
1040 mon,
1041 year;
1042 register time_t result;
1043
1044 if ((sec = tm -> tm_sec) < 0 || sec > 59
1045 || (mins = tm -> tm_min) < 0 || mins > 59
1046 || (hour = tm -> tm_hour) < 0 || hour > 24
1047 || (mday = tm -> tm_mday) < 1 || mday > 31
1048 || (mon = tm -> tm_mon + 1) < 1 || mon > 12)
1049 return ((time_t) -1);
1050 if (hour == 24) {
1051 hour = 0;
1052 mday++;
1053 }
1054 year = YEAR (tm -> tm_year);
1055
1056 result = 0L;
1057 for (i = 1970; i < year; i++)
1058 result += dysize (i);
1059 if (dysize (year) == 366 && mon >= 3)
1060 result++;
1061 while (--mon)
1062 result += dmsize[mon - 1];
1063 result += mday - 1;
1064 result = 24 * result + hour;
1065 result = 60 * result + mins;
1066 result = 60 * result + sec;
1067
1068 return result;
1069 }
1070
1071 static int
searchaction(LDAP * ld,char * buf,char * base,LDAPMessage * entry,char * dn,struct ldap_tmplitem * tip,int labelwidth,int rdncount,writeptype writeproc,void * writeparm,char * eol,char * urlprefix)1072 searchaction( LDAP *ld, char *buf, char *base, LDAPMessage *entry, char *dn,
1073 struct ldap_tmplitem *tip, int labelwidth, int rdncount,
1074 writeptype writeproc, void *writeparm, char *eol, char *urlprefix )
1075 {
1076 int err, lderr, i, count, html;
1077 char **vals, **members;
1078 char *value, *filtpattern, *attr, *selectname;
1079 char *retattrs[2], filter[ 256 ];
1080 LDAPMessage *ldmp;
1081 struct timeval timeout;
1082
1083 html = ( urlprefix != NULL );
1084
1085 for ( i = 0; tip->ti_args != NULL && tip->ti_args[ i ] != NULL; ++i ) {
1086 ;
1087 }
1088 if ( i < 3 ) {
1089 return( LDAP_PARAM_ERROR );
1090 }
1091 attr = tip->ti_args[ 0 ];
1092 filtpattern = tip->ti_args[ 1 ];
1093 retattrs[ 0 ] = tip->ti_args[ 2 ];
1094 retattrs[ 1 ] = NULL;
1095 selectname = tip->ti_args[ 3 ];
1096
1097 vals = NULL;
1098 if ( attr == NULL ) {
1099 value = NULL;
1100 } else if ( strcasecmp( attr, "-dnb" ) == 0 ) {
1101 return( LDAP_PARAM_ERROR );
1102 } else if ( strcasecmp( attr, "-dnt" ) == 0 ) {
1103 value = dn;
1104 } else if (( vals = ldap_get_values( ld, entry, attr )) != NULL ) {
1105 value = vals[ 0 ];
1106 } else {
1107 value = NULL;
1108 }
1109
1110 ldap_build_filter( filter, sizeof( filter ), filtpattern, NULL, NULL, NULL,
1111 value, NULL );
1112
1113 if ( html ) {
1114 /*
1115 * if we are generating HTML, we add an HREF link that embodies this
1116 * search action as an LDAP URL, instead of actually doing the search
1117 * now.
1118 */
1119 sprintf( buf, "<DT><A HREF=\"%s", urlprefix );
1120 if ( base != NULL ) {
1121 strcat_escaped( buf, base );
1122 }
1123 strcat( buf, "??sub?" );
1124 strcat_escaped( buf, filter );
1125 sprintf( buf + strlen( buf ), "\"><B>%s</B></A><DD><BR>%s",
1126 tip->ti_label, eol );
1127 if ((*writeproc)( writeparm, buf, strlen( buf )) < 0 ) {
1128 return( LDAP_LOCAL_ERROR );
1129 }
1130 return( LDAP_SUCCESS );
1131 }
1132
1133 timeout.tv_sec = SEARCH_TIMEOUT_SECS;
1134 timeout.tv_usec = 0;
1135
1136 #ifdef CLDAP
1137 if ( LDAP_IS_CLDAP( ld ))
1138 lderr = cldap_search_s( ld, base, LDAP_SCOPE_SUBTREE, filter, retattrs,
1139 0, &ldmp, NULL );
1140 else
1141 #endif /* CLDAP */
1142 lderr = ldap_search_st( ld, base, LDAP_SCOPE_SUBTREE, filter, retattrs,
1143 0, &timeout, &ldmp );
1144
1145 if ( lderr == LDAP_SUCCESS || NONFATAL_LDAP_ERR( lderr )) {
1146 if (( count = ldap_count_entries( ld, ldmp )) > 0 ) {
1147 if (( members = (char **)malloc( (count + 1) * sizeof(char *)))
1148 == NULL ) {
1149 err = LDAP_NO_MEMORY;
1150 } else {
1151 for ( i = 0, entry = ldap_first_entry( ld, ldmp );
1152 entry != NULL;
1153 entry = ldap_next_entry( ld, entry ), ++i ) {
1154 members[ i ] = ldap_get_dn( ld, entry );
1155 }
1156 members[ i ] = NULL;
1157
1158 ldap_sort_values( ld, members, ldap_sort_strcasecmp );
1159
1160 err = do_vals2text( ld, NULL, members, tip->ti_label,
1161 html ? -1 : 0, LDAP_SYN_DN, writeproc, writeparm,
1162 eol, rdncount, urlprefix );
1163
1164 ldap_value_free( members );
1165 }
1166 }
1167 ldap_msgfree( ldmp );
1168 }
1169
1170
1171 if ( vals != NULL ) {
1172 ldap_value_free( vals );
1173 }
1174
1175 return(( err == LDAP_SUCCESS ) ? lderr : err );
1176 }
1177