1 /*        $NetBSD: modify.c,v 1.3 2021/08/14 16:14:56 christos Exp $  */
2 
3 /* $OpenLDAP$ */
4 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5  *
6  * Copyright 1998-2021 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.3 2021/08/14 16:14:56 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 *
ldap_build_modify_req(LDAP * ld,LDAP_CONST char * dn,LDAPMod ** mods,LDAPControl ** sctrls,LDAPControl ** cctrls,ber_int_t * msgidp)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
ldap_modify_ext(LDAP * ld,LDAP_CONST char * dn,LDAPMod ** mods,LDAPControl ** sctrls,LDAPControl ** cctrls,int * msgidp)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
ldap_modify(LDAP * ld,LDAP_CONST char * dn,LDAPMod ** mods)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
ldap_modify_ext_s(LDAP * ld,LDAP_CONST char * dn,LDAPMod ** mods,LDAPControl ** sctrl,LDAPControl ** cctrl)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
ldap_modify_s(LDAP * ld,LDAP_CONST char * dn,LDAPMod ** mods)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