+
+int
+tool_check_abandon( LDAP *ld, int msgid )
+{
+ int rc;
+
+ switch ( gotintr ) {
+ case LDAP_REQ_EXTENDED:
+ rc = ldap_cancel_s( ld, msgid, NULL, NULL );
+ fprintf( stderr, "got interrupt, cancel got %d: %s\n",
+ rc, ldap_err2string( rc ) );
+ return -1;
+
+ case LDAP_REQ_ABANDON:
+ rc = ldap_abandon_ext( ld, msgid, NULL, NULL );
+ fprintf( stderr, "got interrupt, abandon got %d: %s\n",
+ rc, ldap_err2string( rc ) );
+ return -1;
+ }
+
+ return 0;
+}
+
+static int
+print_prepostread( LDAP *ld, LDAPControl *ctrl, struct berval *what)
+{
+ BerElement *ber;
+ struct berval bv;
+
+ tool_write_ldif( LDIF_PUT_COMMENT, "==> ",
+ what->bv_val, what->bv_len );
+ ber = ber_init( &ctrl->ldctl_value );
+ if ( ber == NULL ) {
+ /* error? */
+ return 1;
+
+ } else if ( ber_scanf( ber, "{m{" /*}}*/, &bv ) == LBER_ERROR ) {
+ /* error? */
+ return 1;
+
+ } else {
+ tool_write_ldif( LDIF_PUT_VALUE, "dn", bv.bv_val, bv.bv_len );
+
+ while ( ber_scanf( ber, "{m" /*}*/, &bv ) != LBER_ERROR ) {
+ int i;
+ BerVarray vals = NULL;
+
+ if ( ber_scanf( ber, "[W]", &vals ) == LBER_ERROR ||
+ vals == NULL )
+ {
+ /* error? */
+ return 1;
+ }
+
+ for ( i = 0; vals[ i ].bv_val != NULL; i++ ) {
+ tool_write_ldif(
+ ldif ? LDIF_PUT_COMMENT : LDIF_PUT_VALUE,
+ bv.bv_val, vals[ i ].bv_val, vals[ i ].bv_len );
+ }
+
+ ber_bvarray_free( vals );
+ }
+ }
+
+ if ( ber != NULL ) {
+ ber_free( ber, 1 );
+ }
+
+ tool_write_ldif( LDIF_PUT_COMMENT, "<== ",
+ what->bv_val, what->bv_len );
+
+ return 0;
+}
+
+static int
+print_preread( LDAP *ld, LDAPControl *ctrl )
+{
+ static struct berval what = BER_BVC( "preread" );
+
+ return print_prepostread( ld, ctrl, &what );
+}
+
+static int
+print_postread( LDAP *ld, LDAPControl *ctrl )
+{
+ static struct berval what = BER_BVC( "postread" );
+
+ return print_prepostread( ld, ctrl, &what );
+}
+
+static int
+print_paged_results( LDAP *ld, LDAPControl *ctrl )
+{
+ ber_int_t estimate;
+
+ /* note: pr_cookie is being malloced; it's freed
+ * the next time the control is sent, but the last
+ * time it's not; we don't care too much, because
+ * the last time an empty value is returned... */
+ if ( ldap_parse_pageresponse_control( ld, ctrl, &estimate, &pr_cookie )
+ != LDAP_SUCCESS )
+ {
+ /* error? */
+ return 1;
+
+ } else {
+ /* FIXME: check buffer overflow */
+ char buf[ BUFSIZ ], *ptr = buf;
+
+ if ( estimate > 0 ) {
+ ptr += snprintf( ptr, sizeof( buf ) - ( ptr - buf ),
+ "estimate=%d", estimate );
+ }
+
+ if ( pr_cookie.bv_len > 0 ) {
+ struct berval bv;
+
+ bv.bv_len = LUTIL_BASE64_ENCODE_LEN(
+ pr_cookie.bv_len ) + 1;
+ bv.bv_val = ber_memalloc( bv.bv_len + 1 );
+
+ bv.bv_len = lutil_b64_ntop(
+ (unsigned char *) pr_cookie.bv_val,
+ pr_cookie.bv_len,
+ bv.bv_val, bv.bv_len );
+
+ ptr += snprintf( ptr, sizeof( buf ) - ( ptr - buf ),
+ "%scookie=%s", ptr == buf ? "" : " ",
+ bv.bv_val );
+
+ ber_memfree( bv.bv_val );
+
+ pr_morePagedResults = 1;
+
+ } else {
+ ptr += snprintf( ptr, sizeof( buf ) - ( ptr - buf ),
+ "%scookie=", ptr == buf ? "" : " " );
+ }
+
+ tool_write_ldif( ldif ? LDIF_PUT_COMMENT : LDIF_PUT_VALUE,
+ "pagedresults", buf, ptr - buf );
+ }
+
+ return 0;
+}
+
+#ifdef LDAP_CONTROL_PASSWORDPOLICYREQUEST
+static int
+print_ppolicy( LDAP *ld, LDAPControl *ctrl )
+{
+ int expire = 0, grace = 0, rc;
+ LDAPPasswordPolicyError pperr;
+
+ rc = ldap_parse_passwordpolicy_control( ld, ctrl,
+ &expire, &grace, &pperr );
+ if ( rc == LDAP_SUCCESS ) {
+ char buf[ BUFSIZ ], *ptr = buf;
+
+ if ( expire != -1 ) {
+ ptr += snprintf( ptr, sizeof( buf ) - ( ptr - buf ),
+ "expire=%d", expire );
+ }
+
+ if ( grace != -1 ) {
+ ptr += snprintf( ptr, sizeof( buf ) - ( ptr - buf ),
+ "%sgrace=%d", ptr == buf ? "" : " ", grace );
+ }
+
+ if ( pperr != PP_noError ) {
+ ptr += snprintf( ptr, sizeof( buf ) - ( ptr - buf ),
+ "%serror=%s", ptr == buf ? "" : " ",
+ ldap_passwordpolicy_err2txt( pperr ) );
+ }
+
+ tool_write_ldif( ldif ? LDIF_PUT_COMMENT : LDIF_PUT_VALUE,
+ "ppolicy", buf, ptr - buf );
+ }
+
+ return rc;
+}
+#endif
+
+void tool_print_ctrls(
+ LDAP *ld,
+ LDAPControl **ctrls )
+{
+ int i;
+ char *ptr;
+
+ for ( i = 0; ctrls[i] != NULL; i++ ) {
+ /* control: OID criticality base64value */
+ struct berval b64 = BER_BVNULL;
+ ber_len_t len;
+ char *str;
+ int j;
+
+ len = ldif ? 2 : 0;
+ len += strlen( ctrls[i]->ldctl_oid );
+
+ /* add enough for space after OID and the critical value itself */
+ len += ctrls[i]->ldctl_iscritical
+ ? sizeof("true") : sizeof("false");
+
+ /* convert to base64 */
+ if ( ctrls[i]->ldctl_value.bv_len ) {
+ b64.bv_len = LUTIL_BASE64_ENCODE_LEN(
+ ctrls[i]->ldctl_value.bv_len ) + 1;
+ b64.bv_val = ber_memalloc( b64.bv_len + 1 );
+
+ b64.bv_len = lutil_b64_ntop(
+ (unsigned char *) ctrls[i]->ldctl_value.bv_val,
+ ctrls[i]->ldctl_value.bv_len,
+ b64.bv_val, b64.bv_len );
+ }
+
+ if ( b64.bv_len ) {
+ len += 1 + b64.bv_len;
+ }
+
+ ptr = str = malloc( len + 1 );
+ if ( ldif ) {
+ ptr = lutil_strcopy( ptr, ": " );
+ }
+ ptr = lutil_strcopy( ptr, ctrls[i]->ldctl_oid );
+ ptr = lutil_strcopy( ptr, ctrls[i]->ldctl_iscritical
+ ? " true" : " false" );
+
+ if ( b64.bv_len ) {
+ ptr = lutil_strcopy( ptr, " " );
+ ptr = lutil_strcopy( ptr, b64.bv_val );
+ }
+
+ if ( ldif < 2 ) {
+ tool_write_ldif( ldif ? LDIF_PUT_COMMENT : LDIF_PUT_VALUE,
+ "control", str, len );
+ }
+
+ free( str );
+ if ( b64.bv_len ) {
+ ber_memfree( b64.bv_val );
+ }
+
+ /* known controls */
+ for ( j = 0; tool_ctrl_response[j].oid != NULL; j++ ) {
+ if ( strcmp( tool_ctrl_response[j].oid, ctrls[i]->ldctl_oid ) == 0 ) {
+ if ( !tool_ctrl_response[j].mask & tool_type ) {
+ /* this control should not appear
+ * with this tool; warning? */
+ }
+ break;
+ }
+ }
+
+ if ( tool_ctrl_response[j].oid != NULL && tool_ctrl_response[j].func ) {
+ (void)tool_ctrl_response[j].func( ld, ctrls[i] );
+ }
+ }
+}
+
+int
+tool_write_ldif( int type, char *name, char *value, ber_len_t vallen )
+{
+ char *ldif;
+
+ if (( ldif = ldif_put( type, name, value, vallen )) == NULL ) {
+ return( -1 );
+ }
+
+ fputs( ldif, stdout );
+ ber_memfree( ldif );
+
+ return( 0 );
+}
+
+int
+tool_is_oid( const char *s )
+{
+ int first = 1;
+
+ if ( !isdigit( (unsigned char) s[ 0 ] ) ) {
+ return 0;
+ }
+
+ for ( ; s[ 0 ]; s++ ) {
+ if ( s[ 0 ] == '.' ) {
+ if ( s[ 1 ] == '\0' ) {
+ return 0;
+ }
+ first = 1;
+ continue;
+ }
+
+ if ( !isdigit( (unsigned char) s[ 0 ] ) ) {
+ return 0;
+ }
+
+ if ( first == 1 && s[ 0 ] == '0' && s[ 1 ] != '.' ) {
+ return 0;
+ }
+ first = 0;
+ }
+
+ return 1;
+}
+