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