From a9bfce1292bcf46d2a35d6be9fd8fff44ea6ec33 Mon Sep 17 00:00:00 2001 From: Howard Chu Date: Sat, 17 Nov 2018 18:33:41 -0800 Subject: [PATCH] Add some MS AD controls --- clients/tools/common.c | 38 +++++ clients/tools/ldapsearch.c | 180 ++++++++++++++++++++++- include/ldap.h | 57 ++++++++ libraries/libldap/Makefile.in | 6 +- libraries/libldap/msctrl.c | 262 ++++++++++++++++++++++++++++++++++ 5 files changed, 540 insertions(+), 3 deletions(-) create mode 100644 libraries/libldap/msctrl.c diff --git a/clients/tools/common.c b/clients/tools/common.c index 23829eada0..14704b2350 100644 --- a/clients/tools/common.c +++ b/clients/tools/common.c @@ -155,6 +155,9 @@ static int print_whatfailed( LDAP *ld, LDAPControl *ctrl ); #endif static int print_syncstate( LDAP *ld, LDAPControl *ctrl ); static int print_syncdone( LDAP *ld, LDAPControl *ctrl ); +#ifdef LDAP_CONTROL_X_DIRSYNC +static int print_dirsync( LDAP *ld, LDAPControl *ctrl ); +#endif static struct tool_ctrls_t { const char *oid; @@ -181,6 +184,9 @@ static struct tool_ctrls_t { #endif { LDAP_CONTROL_SYNC_STATE, TOOL_SEARCH, print_syncstate }, { LDAP_CONTROL_SYNC_DONE, TOOL_SEARCH, print_syncdone }, +#ifdef LDAP_CONTROL_X_DIRSYNC + { LDAP_CONTROL_X_DIRSYNC, TOOL_SEARCH, print_dirsync }, +#endif { NULL, 0, NULL } }; @@ -2468,6 +2474,38 @@ print_syncdone( LDAP *ld, LDAPControl *ctrl ) return 0; } +#ifdef LDAP_CONTROL_X_DIRSYNC +static int +print_dirsync( LDAP *ld, LDAPControl *ctrl ) +{ + int rc, continueFlag; + struct berval cookie; + + rc = ldap_parse_dirsync_control( ld, ctrl, + &continueFlag, &cookie ); + if ( rc == LDAP_SUCCESS ) { + printf(_("# DirSync control continueFlag=%d\n"), continueFlag ); + if ( !BER_BVISNULL( &cookie )) { + if ( ldif_is_not_printable( cookie.bv_val, cookie.bv_len ) ) { + struct berval bv; + + bv.bv_len = LUTIL_BASE64_ENCODE_LEN( cookie.bv_len ) + 1; + bv.bv_val = ber_memalloc( bv.bv_len + 1 ); + + bv.bv_len = lutil_b64_ntop( + (unsigned char *) cookie.bv_val, cookie.bv_len, + bv.bv_val, bv.bv_len ); + + printf(_("# cookie:: %s\n"), bv.bv_val ); + ber_memfree( bv.bv_val ); + } else { + printf(_("# cookie: %s\n"), cookie.bv_val ); + } + } + } +} +#endif + #ifdef LDAP_CONTROL_AUTHZID_RESPONSE static int print_authzid( LDAP *ld, LDAPControl *ctrl ) diff --git a/clients/tools/ldapsearch.c b/clients/tools/ldapsearch.c index 543c6cefba..f0c062292a 100644 --- a/clients/tools/ldapsearch.c +++ b/clients/tools/ldapsearch.c @@ -138,6 +138,16 @@ usage( void ) fprintf( stderr, _(" (ldapv3-vlv-09 virtual list views)\n")); #ifdef LDAP_CONTROL_X_DEREF fprintf( stderr, _(" [!]deref=derefAttr:attr[,...][;derefAttr:attr[,...][;...]]\n")); +#endif +#ifdef LDAP_CONTROL_X_DIRSYNC + fprintf( stderr, _(" !dirSync=/[/]\n")); + fprintf( stderr, _(" (MS AD DirSync)\n")); +#endif +#ifdef LDAP_CONTROL_X_EXTENDED_DN + fprintf( stderr, _(" [!]extendedDn= (MS AD Extended DN\n")); +#endif +#ifdef LDAP_CONTROL_X_SHOW_DELETED + fprintf( stderr, _(" [!]showDeleted (MS AD Show Deleted)\n")); #endif fprintf( stderr, _(" [!][=:] (generic control; no response handling)\n")); fprintf( stderr, _(" -f file read operations from `file'\n")); @@ -245,6 +255,22 @@ static LDAPDerefSpec *ds; static struct berval derefval; #endif +#ifdef LDAP_CONTROL_X_DIRSYNC +static int dirSync; +static int dirSyncFlags; +static int dirSyncMaxAttrCount; +static struct berval dirSyncCookie; +#endif + +#ifdef LDAP_CONTROL_X_EXTENDED_DN +static int extendedDn; +static int extendedDnFlag; +#endif + +#ifdef LDAP_CONTROL_X_SHOW_DELETED +static int showDeleted; +#endif + static int ctrl_add( void ) { @@ -625,6 +651,101 @@ handle_private_option( int i ) ldap_memfree( specs ); #endif /* LDAP_CONTROL_X_DEREF */ +#ifdef LDAP_CONTROL_X_DIRSYNC + } else if ( strcasecmp( control, "dirSync" ) == 0 ) { + char *maxattrp; + char *cookiep; + int num, tmp; + if( dirSync ) { + fprintf( stderr, + _("dirSync control previously specified\n")); + exit( EXIT_FAILURE ); + } + if ( cvalue == NULL ) { + fprintf( stderr, _("missing specification of dirSync control\n")); + exit( EXIT_FAILURE ); + } + if( !crit ) { + fprintf( stderr, + _("dirSync: critical flag required\n") ); + usage(); + } + maxattrp = strchr( cvalue, '/' ); + if ( maxattrp == NULL ) { + fprintf( stderr, _("dirSync control value \"%s\" invalid\n"), + cvalue ); + exit( EXIT_FAILURE ); + } + *maxattrp++ = '\0'; + cookiep = strchr( maxattrp, '/' ); + if ( cookiep != NULL ) { + *cookiep++ = '\0'; + if ( *cookiep != '\0' ) { + ber_str2bv( cookiep, 0, 0, &dirSyncCookie ); + } + } + num = sscanf( cvalue, "%d", &tmp ); + if ( num != 1 ) { + fprintf( stderr, + _("Invalid value for dirSync, %s.\n"), + cvalue ); + exit( EXIT_FAILURE ); + } + dirSyncFlags = tmp; + + num = sscanf( maxattrp, "%d", &tmp ); + if ( num != 1 ) { + fprintf( stderr, + _("Invalid value for dirSync, %s.\n"), + maxattrp ); + exit( EXIT_FAILURE ); + } + dirSyncMaxAttrCount = tmp; + + dirSync = 1 + crit; +#endif /* LDAP_CONTROL_X_DIRSYNC */ + +#ifdef LDAP_CONTROL_X_EXTENDED_DN + } else if ( strcasecmp( control, "extendedDn" ) == 0 ) { + int num, tmp; + if( extendedDn ) { + fprintf( stderr, + _("extendedDn control previously specified\n")); + exit( EXIT_FAILURE ); + } + if ( cvalue == NULL ) { + fprintf( stderr, _("missing specification of extendedDn control\n")); + exit( EXIT_FAILURE ); + } + num = sscanf( cvalue, "%d", &tmp ); + if ( num != 1 ) { + fprintf( stderr, + _("Invalid value for extendedDn, %s.\n"), + cvalue ); + exit( EXIT_FAILURE ); + } + + extendedDnFlag = tmp; + extendedDn = 1 + crit; +#endif /* LDAP_CONTROL_X_EXTENDED_DN */ + +#ifdef LDAP_CONTROL_X_SHOW_DELETED + } else if ( strcasecmp( control, "showDeleted" ) == 0 ) { + int num, tmp; + if( showDeleted ) { + fprintf( stderr, + _("showDeleted control previously specified\n")); + exit( EXIT_FAILURE ); + } + if ( cvalue != NULL ) { + fprintf( stderr, + _("showDeleted: no control value expected\n") ); + usage(); + } + + showDeleted = 1 + crit; +#endif /* LDAP_CONTROL_X_SHOW_DELETED */ + } else if ( tool_is_oid( control ) ) { if ( c != NULL ) { int i; @@ -923,6 +1044,15 @@ getNextPage: #endif #ifdef LDAP_CONTROL_X_DEREF || derefcrit +#endif +#ifdef LDAP_CONTROL_X_DIRSYNC + || dirSync +#endif +#ifdef LDAP_CONTROL_X_EXTENDED_DN + || extendedDn +#endif +#ifdef LDAP_CONTROL_X_SHOW_DELETED + || showDeleted #endif || domainScope || pagedResults @@ -1090,7 +1220,7 @@ getNextPage: } c[i].ldctl_oid = LDAP_CONTROL_VLVREQUEST; - c[i].ldctl_iscritical = sss > 1; + c[i].ldctl_iscritical = vlv > 1; i++; } #ifdef LDAP_CONTROL_X_DEREF @@ -1122,6 +1252,54 @@ getNextPage: i++; } #endif /* LDAP_CONTROL_X_DEREF */ +#ifdef LDAP_CONTROL_X_DIRSYNC + if ( dirSync ) { + if ( ctrl_add() ) { + tool_exit( ld, EXIT_FAILURE ); + } + + if ( ldap_create_dirsync_value( ld, + dirSyncFlags, dirSyncMaxAttrCount, &dirSyncCookie, + &c[i].ldctl_value ) ) + { + tool_exit( ld, EXIT_FAILURE ); + } + + c[i].ldctl_oid = LDAP_CONTROL_X_DIRSYNC; + c[i].ldctl_iscritical = dirSync > 1; + i++; + } +#endif +#ifdef LDAP_CONTROL_X_EXTENDED_DN + if ( extendedDn ) { + if ( ctrl_add() ) { + tool_exit( ld, EXIT_FAILURE ); + } + + if ( ldap_create_extended_dn_value( ld, + extendedDnFlag, &c[i].ldctl_value ) ) + { + tool_exit( ld, EXIT_FAILURE ); + } + + c[i].ldctl_oid = LDAP_CONTROL_X_EXTENDED_DN; + c[i].ldctl_iscritical = extendedDn > 1; + i++; + } +#endif +#ifdef LDAP_CONTROL_X_SHOW_DELETED + if ( showDeleted ) { + if ( ctrl_add() ) { + tool_exit( ld, EXIT_FAILURE ); + } + + c[i].ldctl_oid = LDAP_CONTROL_X_SHOW_DELETED; + c[i].ldctl_value.bv_val = NULL; + c[i].ldctl_value.bv_len = 0; + c[i].ldctl_iscritical = showDeleted > 1; + i++; + } +#endif } tool_server_controls( ld, c, i ); diff --git a/include/ldap.h b/include/ldap.h index 1d42f0d055..c58c576d3a 100644 --- a/include/ldap.h +++ b/include/ldap.h @@ -347,6 +347,14 @@ typedef struct ldapcontrol { /* MS Active Directory controls - not implemented in slapd(8) */ #define LDAP_CONTROL_X_EXTENDED_DN "1.2.840.113556.1.4.529" +#define LDAP_CONTROL_X_SHOW_DELETED "1.2.840.113556.1.4.417" +#define LDAP_CONTROL_X_DIRSYNC "1.2.840.113556.1.4.841" + +#define LDAP_CONTROL_X_DIRSYNC_OBJECT_SECURITY 0x00000001 +#define LDAP_CONTROL_X_DIRSYNC_ANCESTORS_FIRST 0x00000800 +#define LDAP_CONTROL_X_DIRSYNC_PUBLIC_DATA_ONLY 0x00002000 +#define LDAP_CONTROL_X_DIRSYNC_INCREMENTAL_VALUES 0x80000000 + /* */ #define LDAP_CONTROL_X_SESSION_TRACKING "1.3.6.1.4.1.21008.108.63.1" @@ -2547,6 +2555,55 @@ ldap_parse_session_tracking_control LDAP_P(( #endif /* LDAP_CONTROL_X_SESSION_TRACKING */ +/* + * in msctrl.c + */ +#ifdef LDAP_CONTROL_X_DIRSYNC +LDAP_F( int ) +ldap_create_dirsync_value LDAP_P(( + LDAP *ld, + int flags, + int maxAttrCount, + struct berval *cookie, + struct berval *value )); + +LDAP_F( int ) +ldap_create_dirsync_control LDAP_P(( + LDAP *ld, + int flags, + int maxAttrCount, + struct berval *cookie, + LDAPControl **ctrlp )); + +LDAP_F( int ) +ldap_parse_dirsync_control LDAP_P(( + LDAP *ld, + LDAPControl *ctrl, + int *continueFlag, + struct berval *cookie )); +#endif /* LDAP_CONTROL_X_DIRSYNC */ + +#ifdef LDAP_CONTROL_X_EXTENDED_DN +LDAP_F( int ) +ldap_create_extended_dn_value LDAP_P(( + LDAP *ld, + int flag, + struct berval *value )); + +LDAP_F( int ) +ldap_create_extended_dn_control LDAP_P(( + LDAP *ld, + int flag, + LDAPControl **ctrlp )); +#endif /* LDAP_CONTROL_X_EXTENDED_DN */ + +#ifdef LDAP_CONTROL_X_SHOW_DELETED +LDAP_F( int ) +ldap_create_show_deleted_control LDAP_P(( + LDAP *ld, + LDAPControl **ctrlp )); +#endif /* LDAP_CONTROL_X_SHOW_DELETED */ + /* * in assertion.c */ diff --git a/libraries/libldap/Makefile.in b/libraries/libldap/Makefile.in index cd902c99dc..afab839b58 100644 --- a/libraries/libldap/Makefile.in +++ b/libraries/libldap/Makefile.in @@ -28,7 +28,8 @@ SRCS = bind.c open.c result.c error.c compare.c search.c \ charray.c os-local.c dnssrv.c utf-8.c utf-8-conv.c \ tls2.c tls_o.c tls_g.c tls_m.c \ turn.c ppolicy.c dds.c txn.c ldap_sync.c stctrl.c \ - assertion.c deref.c ldifutil.c ldif.c fetch.c lbase64.c + assertion.c deref.c ldifutil.c ldif.c fetch.c lbase64.c \ + msctrl.c OBJS = bind.lo open.lo result.lo error.lo compare.lo search.lo \ controls.lo messages.lo references.lo extended.lo cyrus.lo \ @@ -41,7 +42,8 @@ OBJS = bind.lo open.lo result.lo error.lo compare.lo search.lo \ charray.lo os-local.lo dnssrv.lo utf-8.lo utf-8-conv.lo \ tls2.lo tls_o.lo tls_g.lo tls_m.lo \ turn.lo ppolicy.lo dds.lo txn.lo ldap_sync.lo stctrl.lo \ - assertion.lo deref.lo ldifutil.lo ldif.lo fetch.lo lbase64.lo + assertion.lo deref.lo ldifutil.lo ldif.lo fetch.lo lbase64.lo \ + msctrl.lo LDAP_INCDIR= ../../include LDAP_LIBDIR= ../../libraries diff --git a/libraries/libldap/msctrl.c b/libraries/libldap/msctrl.c new file mode 100644 index 0000000000..bbfc2f5198 --- /dev/null +++ b/libraries/libldap/msctrl.c @@ -0,0 +1,262 @@ +/* $OpenLDAP$ */ +/* This work is part of OpenLDAP Software . + * + * Copyright 1998-2018 The OpenLDAP Foundation. + * Portions Copyright 2018 Howard Chu. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted only as authorized by the OpenLDAP + * Public License. + * + * A copy of this license is available in the file LICENSE in the + * top-level directory of the distribution or, alternatively, at + * . + */ +/* ACKNOWLEDGEMENTS: + * This work was developed by Howard Chu for inclusion in + * OpenLDAP Software. + */ + +#include "portable.h" + +#include +#include +#include +#include + +#include "ldap-int.h" + +/* MS Active Directory controls - not implemented in slapd(8) */ + +#ifdef LDAP_CONTROL_X_DIRSYNC + +int +ldap_create_dirsync_value( + LDAP *ld, + int flags, + int maxAttrCount, + struct berval *cookie, + struct berval *value ) +{ + BerElement *ber = NULL; + ber_tag_t tag; + + if ( ld == NULL || cookie == NULL || + value == NULL ) + { + if ( ld ) { + ld->ld_errno = LDAP_PARAM_ERROR; + } + + return LDAP_PARAM_ERROR; + } + + assert( LDAP_VALID( ld ) ); + ld->ld_errno = LDAP_SUCCESS; + + /* maxAttrCount less than 0x100000 is treated as 0x100000 by server */ + + /* prepare value */ + value->bv_val = NULL; + value->bv_len = 0; + + ber = ldap_alloc_ber_with_options( ld ); + if ( ber == NULL ) { + ld->ld_errno = LDAP_NO_MEMORY; + return ld->ld_errno; + } + + tag = ber_printf( ber, "{iiO}", flags, maxAttrCount, cookie ); + if ( tag == LBER_ERROR ) { + ld->ld_errno = LDAP_ENCODING_ERROR; + goto done; + } + + if ( ber_flatten2( ber, value, 1 ) == -1 ) { + ld->ld_errno = LDAP_NO_MEMORY; + } + +done:; + if ( ber != NULL ) { + ber_free( ber, 1 ); + } + + return ld->ld_errno; +} + +int +ldap_create_dirsync_control( + LDAP *ld, + int flags, + int maxAttrCount, + struct berval *cookie, + LDAPControl **ctrlp ) +{ + struct berval value; + + if ( ctrlp == NULL ) { + ld->ld_errno = LDAP_PARAM_ERROR; + return ld->ld_errno; + } + + ld->ld_errno = ldap_create_dirsync_value( ld, + flags, maxAttrCount, cookie, &value ); + if ( ld->ld_errno == LDAP_SUCCESS ) { + ld->ld_errno = ldap_control_create( LDAP_CONTROL_X_DIRSYNC, + 0, &value, 0, ctrlp ); + if ( ld->ld_errno != LDAP_SUCCESS ) { + LDAP_FREE( value.bv_val ); + } + } + + return ld->ld_errno; +} + +int +ldap_parse_dirsync_control( + LDAP *ld, + LDAPControl *ctrl, + int *continueFlag, + struct berval *cookie ) +{ + BerElement *ber; + ber_tag_t tag; + ber_len_t len; + int unused; + + if ( ld == NULL || + ctrl == NULL || + continueFlag == NULL || + cookie == NULL ) + { + if ( ld ) { + ld->ld_errno = LDAP_PARAM_ERROR; + } + + /* NOTE: we want the caller to get all or nothing; + * we could allow some of the pointers to be NULL, + * if one does not want part of the data */ + return LDAP_PARAM_ERROR; + } + + *continueFlag = 0; + BER_BVZERO( cookie ); + + ber = ber_init( &ctrl->ldctl_value ); + + if ( ber == NULL ) { + ld->ld_errno = LDAP_NO_MEMORY; + return ld->ld_errno; + } + + tag = ber_scanf( ber, "{iio}", continueFlag, &unused, cookie ); + if ( tag == LBER_DEFAULT ) + tag = LBER_ERROR; + + (void)ber_free( ber, 1 ); + + if ( tag == LBER_ERROR ) { + return LDAP_DECODING_ERROR; + } + + return ld->ld_errno; +} + +#endif /* LDAP_CONTROL_X_DIRSYNC */ + +#ifdef LDAP_CONTROL_X_SHOW_DELETED + +int +ldap_create_show_deleted_control( LDAP *ld, + LDAPControl **ctrlp ) +{ + assert( ld != NULL ); + assert( LDAP_VALID( ld ) ); + assert( ctrlp != NULL ); + + ld->ld_errno = ldap_control_create( LDAP_CONTROL_X_SHOW_DELETED, + 0, NULL, 0, ctrlp ); + + return ld->ld_errno; +} + +#endif /* LDAP_CONTROL_X_SHOW_DELETED */ + +#ifdef LDAP_CONTROL_X_EXTENDED_DN + +int +ldap_create_extended_dn_value( + LDAP *ld, + int flag, + struct berval *value ) +{ + BerElement *ber = NULL; + ber_tag_t tag; + + if ( ld == NULL || + value == NULL ) + { + if ( ld ) { + ld->ld_errno = LDAP_PARAM_ERROR; + } + + return LDAP_PARAM_ERROR; + } + + assert( LDAP_VALID( ld ) ); + ld->ld_errno = LDAP_SUCCESS; + + /* prepare value */ + value->bv_val = NULL; + value->bv_len = 0; + + ber = ldap_alloc_ber_with_options( ld ); + if ( ber == NULL ) { + ld->ld_errno = LDAP_NO_MEMORY; + return ld->ld_errno; + } + tag = ber_printf( ber, "{i}", flag ); + if ( tag == LBER_ERROR ) { + ld->ld_errno = LDAP_ENCODING_ERROR; + goto done; + } + + if ( ber_flatten2( ber, value, 1 ) == -1 ) { + ld->ld_errno = LDAP_NO_MEMORY; + } + +done:; + if ( ber != NULL ) { + ber_free( ber, 1 ); + } + + return ld->ld_errno; +} + +int +ldap_create_extended_dn_control( + LDAP *ld, + int flag, + LDAPControl **ctrlp ) +{ + struct berval value; + + if ( ctrlp == NULL ) { + ld->ld_errno = LDAP_PARAM_ERROR; + return ld->ld_errno; + } + + ld->ld_errno = ldap_create_extended_dn_value( ld, flag, &value ); + if ( ld->ld_errno == LDAP_SUCCESS ) { + ld->ld_errno = ldap_control_create( LDAP_CONTROL_X_EXTENDED_DN, + 0, &value, 0, ctrlp ); + if ( ld->ld_errno != LDAP_SUCCESS ) { + LDAP_FREE( value.bv_val ); + } + } + + return ld->ld_errno; +} + +#endif /* LDAP_CONTROL_X_EXTENDED_DN */