Home | History | Annotate | Line # | Download | only in libldap
      1 /*	$NetBSD: modify.c,v 1.4 2025/09/05 21:16:21 christos Exp $	*/
      2 
      3 /* $OpenLDAP$ */
      4 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
      5  *
      6  * Copyright 1998-2024 The OpenLDAP Foundation.
      7  * All rights reserved.
      8  *
      9  * Redistribution and use in source and binary forms, with or without
     10  * modification, are permitted only as authorized by the OpenLDAP
     11  * Public License.
     12  *
     13  * A copy of this license is available in the file LICENSE in the
     14  * top-level directory of the distribution or, alternatively, at
     15  * <http://www.OpenLDAP.org/license.html>.
     16  */
     17 /* Portions Copyright (c) 1990 Regents of the University of Michigan.
     18  * All rights reserved.
     19  */
     20 
     21 #include <sys/cdefs.h>
     22 __RCSID("$NetBSD: modify.c,v 1.4 2025/09/05 21:16:21 christos Exp $");
     23 
     24 #include "portable.h"
     25 
     26 #include <stdio.h>
     27 
     28 #include <ac/socket.h>
     29 #include <ac/string.h>
     30 #include <ac/time.h>
     31 
     32 #include "ldap-int.h"
     33 
     34 /* A modify request/response looks like this:
     35  *        ModifyRequest ::= [APPLICATION 6] SEQUENCE {
     36  *             object          LDAPDN,
     37  *             changes         SEQUENCE OF change SEQUENCE {
     38  *                  operation       ENUMERATED {
     39  *                       add     (0),
     40  *                       delete  (1),
     41  *                       replace (2),
     42  *                       ...  },
     43  *                  modification    PartialAttribute } }
     44  *
     45  *        PartialAttribute ::= SEQUENCE {
     46  *             type       AttributeDescription,
     47  *             vals       SET OF value AttributeValue }
     48  *
     49  *        AttributeDescription ::= LDAPString
     50  *              -- Constrained to <attributedescription> [RFC4512]
     51  *
     52  *        AttributeValue ::= OCTET STRING
     53  *
     54  *        ModifyResponse ::= [APPLICATION 7] LDAPResult
     55  *
     56  * (Source: RFC 4511)
     57  */
     58 
     59 BerElement *
     60 ldap_build_modify_req(
     61 	LDAP *ld,
     62 	LDAP_CONST char *dn,
     63 	LDAPMod **mods,
     64 	LDAPControl **sctrls,
     65 	LDAPControl **cctrls,
     66 	ber_int_t *msgidp )
     67 {
     68 	BerElement	*ber;
     69 	int		i, rc;
     70 
     71 	/* create a message to send */
     72 	if ( (ber = ldap_alloc_ber_with_options( ld )) == NULL ) {
     73 		return( NULL );
     74 	}
     75 
     76 	LDAP_NEXT_MSGID( ld, *msgidp );
     77 	rc = ber_printf( ber, "{it{s{" /*}}}*/, *msgidp, LDAP_REQ_MODIFY, dn );
     78 	if ( rc == -1 ) {
     79 		ld->ld_errno = LDAP_ENCODING_ERROR;
     80 		ber_free( ber, 1 );
     81 		return( NULL );
     82 	}
     83 
     84 	/* allow mods to be NULL ("touch") */
     85 	if ( mods ) {
     86 		/* for each modification to be performed... */
     87 		for ( i = 0; mods[i] != NULL; i++ ) {
     88 			if (( mods[i]->mod_op & LDAP_MOD_BVALUES) != 0 ) {
     89 				rc = ber_printf( ber, "{e{s[V]N}N}",
     90 				    (ber_int_t) ( mods[i]->mod_op & ~LDAP_MOD_BVALUES ),
     91 				    mods[i]->mod_type, mods[i]->mod_bvalues );
     92 			} else {
     93 				rc = ber_printf( ber, "{e{s[v]N}N}",
     94 					(ber_int_t) mods[i]->mod_op,
     95 				    mods[i]->mod_type, mods[i]->mod_values );
     96 			}
     97 
     98 			if ( rc == -1 ) {
     99 				ld->ld_errno = LDAP_ENCODING_ERROR;
    100 				ber_free( ber, 1 );
    101 				return( NULL );
    102 			}
    103 		}
    104 	}
    105 
    106 	if ( ber_printf( ber, /*{{*/ "N}N}" ) == -1 ) {
    107 		ld->ld_errno = LDAP_ENCODING_ERROR;
    108 		ber_free( ber, 1 );
    109 		return( NULL );
    110 	}
    111 
    112 	/* Put Server Controls */
    113 	if( ldap_int_put_controls( ld, sctrls, ber ) != LDAP_SUCCESS ) {
    114 		ber_free( ber, 1 );
    115 		return( NULL );
    116 	}
    117 
    118 	if ( ber_printf( ber, /*{*/ "N}" ) == -1 ) {
    119 		ld->ld_errno = LDAP_ENCODING_ERROR;
    120 		ber_free( ber, 1 );
    121 		return( NULL );
    122 	}
    123 
    124 	return( ber );
    125 }
    126 
    127 /*
    128  * ldap_modify_ext - initiate an ldap extended modify operation.
    129  *
    130  * Parameters:
    131  *
    132  *	ld		LDAP descriptor
    133  *	dn		DN of the object to modify
    134  *	mods		List of modifications to make.  This is null-terminated
    135  *			array of struct ldapmod's, specifying the modifications
    136  *			to perform.
    137  *	sctrls	Server Controls
    138  *	cctrls	Client Controls
    139  *	msgidp	Message ID pointer
    140  *
    141  * Example:
    142  *	LDAPMod	*mods[] = {
    143  *			{ LDAP_MOD_ADD, "cn", { "babs jensen", "babs", 0 } },
    144  *			{ LDAP_MOD_REPLACE, "sn", { "babs jensen", "babs", 0 } },
    145  *			{ LDAP_MOD_DELETE, "ou", 0 },
    146  *			{ LDAP_MOD_INCREMENT, "uidNumber, { "1", 0 } }
    147  *			0
    148  *		}
    149  *	rc=  ldap_modify_ext( ld, dn, mods, sctrls, cctrls, &msgid );
    150  */
    151 int
    152 ldap_modify_ext( LDAP *ld,
    153 	LDAP_CONST char *dn,
    154 	LDAPMod **mods,
    155 	LDAPControl **sctrls,
    156 	LDAPControl **cctrls,
    157 	int *msgidp )
    158 {
    159 	BerElement	*ber;
    160 	int		rc;
    161 	ber_int_t	id;
    162 
    163 	Debug0( LDAP_DEBUG_TRACE, "ldap_modify_ext\n" );
    164 
    165 	/* check client controls */
    166 	rc = ldap_int_client_controls( ld, cctrls );
    167 	if( rc != LDAP_SUCCESS ) return rc;
    168 
    169 	ber = ldap_build_modify_req( ld, dn, mods, sctrls, cctrls, &id );
    170 	if( !ber )
    171 		return ld->ld_errno;
    172 
    173 	/* send the message */
    174 	*msgidp = ldap_send_initial_request( ld, LDAP_REQ_MODIFY, dn, ber, id );
    175 	return( *msgidp < 0 ? ld->ld_errno : LDAP_SUCCESS );
    176 }
    177 
    178 /*
    179  * ldap_modify - initiate an ldap modify operation.
    180  *
    181  * Parameters:
    182  *
    183  *	ld		LDAP descriptor
    184  *	dn		DN of the object to modify
    185  *	mods		List of modifications to make.  This is null-terminated
    186  *			array of struct ldapmod's, specifying the modifications
    187  *			to perform.
    188  *
    189  * Example:
    190  *	LDAPMod	*mods[] = {
    191  *			{ LDAP_MOD_ADD, "cn", { "babs jensen", "babs", 0 } },
    192  *			{ LDAP_MOD_REPLACE, "sn", { "babs jensen", "babs", 0 } },
    193  *			{ LDAP_MOD_DELETE, "ou", 0 },
    194  *			{ LDAP_MOD_INCREMENT, "uidNumber, { "1", 0 } }
    195  *			0
    196  *		}
    197  *	msgid = ldap_modify( ld, dn, mods );
    198  */
    199 int
    200 ldap_modify( LDAP *ld, LDAP_CONST char *dn, LDAPMod **mods )
    201 {
    202 	int rc, msgid;
    203 
    204 	Debug0( LDAP_DEBUG_TRACE, "ldap_modify\n" );
    205 
    206 	rc = ldap_modify_ext( ld, dn, mods, NULL, NULL, &msgid );
    207 
    208 	if ( rc != LDAP_SUCCESS )
    209 		return -1;
    210 
    211 	return msgid;
    212 }
    213 
    214 int
    215 ldap_modify_ext_s( LDAP *ld, LDAP_CONST char *dn,
    216 	LDAPMod **mods, LDAPControl **sctrl, LDAPControl **cctrl )
    217 {
    218 	int		rc;
    219 	int		msgid;
    220 	LDAPMessage	*res;
    221 
    222 	rc = ldap_modify_ext( ld, dn, mods, sctrl, cctrl, &msgid );
    223 
    224 	if ( rc != LDAP_SUCCESS )
    225 		return( rc );
    226 
    227 	if ( ldap_result( ld, msgid, LDAP_MSG_ALL, (struct timeval *) NULL, &res ) == -1 || !res )
    228 		return( ld->ld_errno );
    229 
    230 	return( ldap_result2error( ld, res, 1 ) );
    231 }
    232 
    233 int
    234 ldap_modify_s( LDAP *ld, LDAP_CONST char *dn, LDAPMod **mods )
    235 {
    236 	return ldap_modify_ext_s( ld, dn, mods, NULL, NULL );
    237 }
    238 
    239