/*	$NetBSD: msctrl.c,v 1.2 2021/08/14 16:14:56 christos Exp $	*/
/* $OpenLDAP$ */
/* This work is part of OpenLDAP Software .
 *
 * Copyright 1998-2021 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 
__RCSID("$NetBSD: msctrl.c,v 1.2 2021/08/14 16:14:56 christos Exp $");
#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,
			1, &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 */
#ifdef LDAP_CONTROL_X_SERVER_NOTIFICATION
int
ldap_create_server_notification_control( LDAP *ld,
                                    LDAPControl **ctrlp )
{
	assert( ld != NULL );
	assert( LDAP_VALID( ld ) );
	assert( ctrlp != NULL );
	ld->ld_errno = ldap_control_create( LDAP_CONTROL_X_SERVER_NOTIFICATION,
		0, NULL, 0, ctrlp );
	return ld->ld_errno;
}
#endif /* LDAP_CONTROL_X_SERVER_NOTIFICATION */