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