1/* ldapexop.c -- a tool for performing well-known extended operations */
2/* $OpenLDAP$ */
3/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4 *
5 * Copyright 2005-2011 The OpenLDAP Foundation.
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted only as authorized by the OpenLDAP
10 * Public License.
11 *
12 * A copy of this license is available in the file LICENSE in the
13 * top-level directory of the distribution or, alternatively, at
14 * <http://www.OpenLDAP.org/license.html>.
15 */
16/* ACKNOWLEDGEMENTS:
17 * This work was originally developed by Pierangelo Masarati for inclusion
18 * in OpenLDAP Software based, in part, on other client tools.
19 */
20
21#include "portable.h"
22
23#include <stdio.h>
24
25#include <ac/stdlib.h>
26
27#include <ac/ctype.h>
28#include <ac/socket.h>
29#include <ac/string.h>
30#include <ac/time.h>
31#include <ac/unistd.h>
32
33#include <ldap.h>
34#include "ldif.h"
35#include "lutil.h"
36#include "lutil_ldap.h"
37#include "ldap_defaults.h"
38
39#include "common.h"
40
41void
42usage( void )
43{
44	fprintf( stderr, _("Issue LDAP extended operations\n\n"));
45	fprintf( stderr, _("usage: %s [options] <oid|oid:data|oid::b64data>\n"), prog);
46	fprintf( stderr, _("       %s [options] whoami\n"), prog);
47	fprintf( stderr, _("       %s [options] cancel <id>\n"), prog);
48	fprintf( stderr, _("       %s [options] refresh <DN> [<ttl>]\n"), prog);
49	tool_common_usage();
50	exit( EXIT_FAILURE );
51}
52
53
54const char options[] = ""
55	"d:D:e:h:H:InNO:o:p:QR:U:vVw:WxX:y:Y:Z";
56
57int
58handle_private_option( int i )
59{
60	switch ( i ) {
61	default:
62		return 0;
63	}
64	return 1;
65}
66
67
68int
69main( int argc, char *argv[] )
70{
71	int		rc;
72
73	LDAP		*ld = NULL;
74
75	char		*matcheddn = NULL, *text = NULL, **refs = NULL;
76	LDAPControl **ctrls = NULL;
77	int		id, code;
78	LDAPMessage	*res = NULL;
79
80	tool_init( TOOL_EXOP );
81	prog = lutil_progname( "ldapexop", argc, argv );
82
83	/* LDAPv3 only */
84	protocol = LDAP_VERSION3;
85
86	tool_args( argc, argv );
87
88	if ( argc - optind < 1 ) {
89		usage();
90	}
91
92	ld = tool_conn_setup( 0, 0 );
93
94	tool_bind( ld );
95
96	argv += optind;
97	argc -= optind;
98
99	if ( strcasecmp( argv[ 0 ], "whoami" ) == 0 ) {
100		tool_server_controls( ld, NULL, 0 );
101
102		rc = ldap_whoami( ld, NULL, NULL, &id );
103		if ( rc != LDAP_SUCCESS ) {
104			tool_perror( "ldap_extended_operation", rc, NULL, NULL, NULL, NULL );
105			rc = EXIT_FAILURE;
106			goto skip;
107		}
108
109	} else if ( strcasecmp( argv[ 0 ], "cancel" ) == 0 ) {
110		int		cancelid;
111
112		switch ( argc ) {
113		case 2:
114			 if ( lutil_atoi( &cancelid, argv[ 1 ] ) != 0 || cancelid < 0 ) {
115				fprintf( stderr, "invalid cancelid=%s\n\n", argv[ 1 ] );
116				usage();
117			}
118			break;
119
120		default:
121			fprintf( stderr, "need cancelid\n\n" );
122			usage();
123		}
124
125		rc = ldap_cancel( ld, cancelid, NULL, NULL, &id );
126		if ( rc != LDAP_SUCCESS ) {
127			tool_perror( "ldap_cancel", rc, NULL, NULL, NULL, NULL );
128			rc = EXIT_FAILURE;
129			goto skip;
130		}
131
132	} else if ( strcasecmp( argv[ 0 ], "passwd" ) == 0 ) {
133		fprintf( stderr, "use ldappasswd(1) instead.\n\n", argv[ 0 ] );
134		usage();
135		/* TODO? */
136
137	} else if ( strcasecmp( argv[ 0 ], "refresh" ) == 0 ) {
138		int		ttl = 3600;
139		struct berval	dn;
140
141		switch ( argc ) {
142		case 3:
143			ttl = atoi( argv[ 2 ] );
144
145		case 2:
146			dn.bv_val = argv[ 1 ];
147			dn.bv_len = strlen( dn.bv_val );
148			break;
149
150		default:
151			fprintf( stderr, _("need DN [ttl]\n\n") );
152			usage();
153		}
154
155		tool_server_controls( ld, NULL, 0 );
156
157		rc = ldap_refresh( ld, &dn, ttl, NULL, NULL, &id );
158		if ( rc != LDAP_SUCCESS ) {
159			tool_perror( "ldap_extended_operation", rc, NULL, NULL, NULL, NULL );
160			rc = EXIT_FAILURE;
161			goto skip;
162		}
163
164	} else {
165		char *p;
166
167		if ( argc != 1 ) {
168			usage();
169		}
170
171		p = strchr( argv[ 0 ], ':' );
172		if ( p == argv[ 0 ] ) {
173			usage();
174		}
175
176		if ( p != NULL )
177			*p++ = '\0';
178
179		if ( tool_is_oid( argv[ 0 ] ) ) {
180			struct berval	reqdata;
181			struct berval	type;
182			struct berval	value;
183			int		freeval;
184
185			if ( p != NULL ) {
186				p[ -1 ] = ':';
187				ldif_parse_line2( argv[ 0 ], &type, &value, &freeval );
188				p[ -1 ] = '\0';
189
190				if ( freeval ) {
191					reqdata = value;
192				} else {
193					ber_dupbv( &reqdata, &value );
194				}
195			}
196
197
198			tool_server_controls( ld, NULL, 0 );
199
200			rc = ldap_extended_operation( ld, argv[ 0 ], p ? &reqdata : NULL, NULL, NULL, &id );
201			if ( rc != LDAP_SUCCESS ) {
202				tool_perror( "ldap_extended_operation", rc, NULL, NULL, NULL, NULL );
203				rc = EXIT_FAILURE;
204				goto skip;
205			}
206		} else {
207			fprintf( stderr, "unknown exop \"%s\"\n\n", argv[ 0 ] );
208			usage();
209		}
210	}
211
212	for ( ; ; ) {
213		struct timeval	tv;
214
215		if ( tool_check_abandon( ld, id ) ) {
216			tool_exit( ld, LDAP_CANCELLED );
217		}
218
219		tv.tv_sec = 0;
220		tv.tv_usec = 100000;
221
222		rc = ldap_result( ld, LDAP_RES_ANY, LDAP_MSG_ALL, &tv, &res );
223		if ( rc < 0 ) {
224			tool_perror( "ldap_result", rc, NULL, NULL, NULL, NULL );
225			rc = EXIT_FAILURE;
226			goto skip;
227		}
228
229		if ( rc != 0 ) {
230			break;
231		}
232	}
233
234	rc = ldap_parse_result( ld, res,
235		&code, &matcheddn, &text, &refs, &ctrls, 0 );
236	if ( rc == LDAP_SUCCESS ) {
237		rc = code;
238	}
239
240	if ( rc != LDAP_SUCCESS ) {
241		tool_perror( "ldap_parse_result", rc, NULL, matcheddn, text, refs );
242		rc = EXIT_FAILURE;
243		goto skip;
244	}
245
246	if ( strcasecmp( argv[ 0 ], "whoami" ) == 0 ) {
247		char		*retoid = NULL;
248		struct berval	*retdata = NULL;
249
250		rc = ldap_parse_extended_result( ld, res, &retoid, &retdata, 0 );
251
252		if ( rc != LDAP_SUCCESS ) {
253			tool_perror( "ldap_parse_extended_result", rc, NULL, NULL, NULL, NULL );
254			rc = EXIT_FAILURE;
255			goto skip;
256		}
257
258		if ( retdata != NULL ) {
259			if ( retdata->bv_len == 0 ) {
260				printf(_("anonymous\n") );
261			} else {
262				printf("%s\n", retdata->bv_val );
263			}
264		}
265
266		ber_memfree( retoid );
267		ber_bvfree( retdata );
268
269	} else if ( strcasecmp( argv[ 0 ], "cancel" ) == 0 ) {
270		/* no extended response; returns specific errors */
271		assert( 0 );
272
273	} else if ( strcasecmp( argv[ 0 ], "passwd" ) == 0 ) {
274		/* TODO */
275
276	} else if ( strcasecmp( argv[ 0 ], "refresh" ) == 0 ) {
277		int	newttl;
278
279		rc = ldap_parse_refresh( ld, res, &newttl );
280
281		if ( rc != LDAP_SUCCESS ) {
282			tool_perror( "ldap_parse_refresh", rc, NULL, NULL, NULL, NULL );
283			rc = EXIT_FAILURE;
284			goto skip;
285		}
286
287		printf( "newttl=%d\n", newttl );
288
289	} else if ( tool_is_oid( argv[ 0 ] ) ) {
290		char		*retoid = NULL;
291		struct berval	*retdata = NULL;
292
293		if( ldif < 2 ) {
294			printf(_("# extended operation response\n"));
295		}
296
297		rc = ldap_parse_extended_result( ld, res, &retoid, &retdata, 0 );
298		if ( rc != LDAP_SUCCESS ) {
299			tool_perror( "ldap_parse_extended_result", rc, NULL, NULL, NULL, NULL );
300			rc = EXIT_FAILURE;
301			goto skip;
302		}
303
304		if ( ldif < 2 && retoid != NULL ) {
305			tool_write_ldif( ldif ? LDIF_PUT_COMMENT : LDIF_PUT_VALUE,
306				"oid", retoid, strlen(retoid) );
307		}
308
309		ber_memfree( retoid );
310
311		if( retdata != NULL ) {
312			if ( ldif < 2 ) {
313				tool_write_ldif( ldif ? LDIF_PUT_COMMENT : LDIF_PUT_BINARY,
314					"data", retdata->bv_val, retdata->bv_len );
315			}
316
317			ber_bvfree( retdata );
318		}
319	}
320
321	if( verbose || code != LDAP_SUCCESS ||
322		( matcheddn && *matcheddn ) || ( text && *text ) || refs ) {
323		printf( _("Result: %s (%d)\n"), ldap_err2string( code ), code );
324
325		if( text && *text ) {
326			printf( _("Additional info: %s\n"), text );
327		}
328
329		if( matcheddn && *matcheddn ) {
330			printf( _("Matched DN: %s\n"), matcheddn );
331		}
332
333		if( refs ) {
334			int i;
335			for( i=0; refs[i]; i++ ) {
336				printf(_("Referral: %s\n"), refs[i] );
337			}
338		}
339	}
340
341    if (ctrls) {
342		tool_print_ctrls( ld, ctrls );
343		ldap_controls_free( ctrls );
344	}
345
346	ber_memfree( text );
347	ber_memfree( matcheddn );
348	ber_memvfree( (void **) refs );
349
350skip:
351	/* disconnect from server */
352	if ( res )
353		ldap_msgfree( res );
354	tool_exit( ld, code == LDAP_SUCCESS ? EXIT_SUCCESS : EXIT_FAILURE );
355}
356