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