xref: /netbsd-src/external/bsd/openldap/dist/servers/slapd/back-meta/add.c (revision 549b59ed3ccf0d36d3097190a0db27b770f3a839)
1 /*	$NetBSD: add.c,v 1.3 2021/08/14 16:15:00 christos Exp $	*/
2 
3 /* $OpenLDAP$ */
4 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5  *
6  * Copyright 1999-2021 The OpenLDAP Foundation.
7  * Portions Copyright 2001-2003 Pierangelo Masarati.
8  * Portions Copyright 1999-2003 Howard Chu.
9  * All rights reserved.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted only as authorized by the OpenLDAP
13  * Public License.
14  *
15  * A copy of this license is available in the file LICENSE in the
16  * top-level directory of the distribution or, alternatively, at
17  * <http://www.OpenLDAP.org/license.html>.
18  */
19 /* ACKNOWLEDGEMENTS:
20  * This work was initially developed by the Howard Chu for inclusion
21  * in OpenLDAP Software and subsequently enhanced by Pierangelo
22  * Masarati.
23  */
24 
25 
26 #include <sys/cdefs.h>
27 __RCSID("$NetBSD: add.c,v 1.3 2021/08/14 16:15:00 christos Exp $");
28 
29 #include "portable.h"
30 
31 #include <stdio.h>
32 
33 #include <ac/string.h>
34 #include <ac/socket.h>
35 
36 #include "slap.h"
37 #include "../back-ldap/back-ldap.h"
38 #include "back-meta.h"
39 
40 int
meta_back_add(Operation * op,SlapReply * rs)41 meta_back_add( Operation *op, SlapReply *rs )
42 {
43 	metainfo_t	*mi = ( metainfo_t * )op->o_bd->be_private;
44 	metatarget_t	*mt;
45 	metaconn_t	*mc;
46 	int		i, candidate = -1;
47 	int		isupdate;
48 	Attribute	*a;
49 	LDAPMod		**attrs;
50 	struct berval	mdn = BER_BVNULL, mapped;
51 	dncookie	dc;
52 	int		msgid;
53 	ldap_back_send_t	retrying = LDAP_BACK_RETRYING;
54 	LDAPControl	**ctrls = NULL;
55 
56 	Debug(LDAP_DEBUG_ARGS, "==> meta_back_add: %s\n",
57 			op->o_req_dn.bv_val );
58 
59 	/*
60 	 * get the current connection
61 	 */
62 	mc = meta_back_getconn( op, rs, &candidate, LDAP_BACK_SENDERR );
63 	if ( !mc || !meta_back_dobind( op, rs, mc, LDAP_BACK_SENDERR ) ) {
64 		return rs->sr_err;
65 	}
66 
67 	assert( mc->mc_conns[ candidate ].msc_ld != NULL );
68 
69 	/*
70 	 * Rewrite the add dn, if needed
71 	 */
72 	mt = mi->mi_targets[ candidate ];
73 	dc.target = mt;
74 	dc.conn = op->o_conn;
75 	dc.rs = rs;
76 	dc.ctx = "addDN";
77 
78 	if ( ldap_back_dn_massage( &dc, &op->o_req_dn, &mdn ) ) {
79 		send_ldap_result( op, rs );
80 		goto done;
81 	}
82 
83 	/* Count number of attributes in entry ( +1 ) */
84 	for ( i = 1, a = op->ora_e->e_attrs; a; i++, a = a->a_next );
85 
86 	/* Create array of LDAPMods for ldap_add() */
87 	attrs = ch_malloc( sizeof( LDAPMod * )*i );
88 
89 	dc.ctx = "addAttrDN";
90 	isupdate = be_shadow_update( op );
91 	for ( i = 0, a = op->ora_e->e_attrs; a; a = a->a_next ) {
92 		int			j, is_oc = 0;
93 
94 		if ( !isupdate && !get_relax( op ) && a->a_desc->ad_type->sat_no_user_mod  )
95 		{
96 			continue;
97 		}
98 
99 		if ( a->a_desc == slap_schema.si_ad_objectClass
100 				|| a->a_desc == slap_schema.si_ad_structuralObjectClass )
101 		{
102 			is_oc = 1;
103 			mapped = a->a_desc->ad_cname;
104 
105 		} else {
106 			ldap_back_map( &mt->mt_rwmap.rwm_at,
107 					&a->a_desc->ad_cname, &mapped, BACKLDAP_MAP );
108 			if ( BER_BVISNULL( &mapped ) || BER_BVISEMPTY( &mapped ) ) {
109 				continue;
110 			}
111 		}
112 
113 		attrs[ i ] = ch_malloc( sizeof( LDAPMod ) );
114 		if ( attrs[ i ] == NULL ) {
115 			continue;
116 		}
117 		attrs[ i ]->mod_op = LDAP_MOD_BVALUES;
118 		attrs[ i ]->mod_type = mapped.bv_val;
119 
120 		if ( is_oc ) {
121 			for ( j = 0; !BER_BVISNULL( &a->a_vals[ j ] ); j++ )
122 				;
123 
124 			attrs[ i ]->mod_bvalues =
125 				(struct berval **)ch_malloc( ( j + 1 ) *
126 				sizeof( struct berval * ) );
127 
128 			for ( j = 0; !BER_BVISNULL( &a->a_vals[ j ] ); ) {
129 				struct ldapmapping	*mapping;
130 
131 				ldap_back_mapping( &mt->mt_rwmap.rwm_oc,
132 						&a->a_vals[ j ], &mapping, BACKLDAP_MAP );
133 
134 				if ( mapping == NULL ) {
135 					if ( mt->mt_rwmap.rwm_oc.drop_missing ) {
136 						continue;
137 					}
138 					attrs[ i ]->mod_bvalues[ j ] = &a->a_vals[ j ];
139 
140 				} else {
141 					attrs[ i ]->mod_bvalues[ j ] = &mapping->dst;
142 				}
143 				j++;
144 			}
145 			attrs[ i ]->mod_bvalues[ j ] = NULL;
146 
147 		} else {
148 			/*
149 			 * FIXME: dn-valued attrs should be rewritten
150 			 * to allow their use in ACLs at the back-ldap
151 			 * level.
152 			 */
153 			if ( a->a_desc->ad_type->sat_syntax ==
154 				slap_schema.si_syn_distinguishedName )
155 			{
156 				(void)ldap_dnattr_rewrite( &dc, a->a_vals );
157 				if ( a->a_vals == NULL ) {
158 					continue;
159 				}
160 			}
161 
162 			for ( j = 0; !BER_BVISNULL( &a->a_vals[ j ] ); j++ )
163 				;
164 
165 			attrs[ i ]->mod_bvalues = ch_malloc( ( j + 1 ) * sizeof( struct berval * ) );
166 			for ( j = 0; !BER_BVISNULL( &a->a_vals[ j ] ); j++ ) {
167 				attrs[ i ]->mod_bvalues[ j ] = &a->a_vals[ j ];
168 			}
169 			attrs[ i ]->mod_bvalues[ j ] = NULL;
170 		}
171 		i++;
172 	}
173 	attrs[ i ] = NULL;
174 
175 retry:;
176 	ctrls = op->o_ctrls;
177 	if ( meta_back_controls_add( op, rs, mc, candidate, &ctrls ) != LDAP_SUCCESS )
178 	{
179 		send_ldap_result( op, rs );
180 		goto cleanup;
181 	}
182 
183 	rs->sr_err = ldap_add_ext( mc->mc_conns[ candidate ].msc_ld, mdn.bv_val,
184 			      attrs, ctrls, NULL, &msgid );
185 	rs->sr_err = meta_back_op_result( mc, op, rs, candidate, msgid,
186 		mt->mt_timeout[ SLAP_OP_ADD ], ( LDAP_BACK_SENDRESULT | retrying ) );
187 	if ( rs->sr_err == LDAP_UNAVAILABLE && retrying ) {
188 		retrying &= ~LDAP_BACK_RETRYING;
189 		if ( meta_back_retry( op, rs, &mc, candidate, LDAP_BACK_SENDERR ) ) {
190 			/* if the identity changed, there might be need to re-authz */
191 			(void)mi->mi_ldap_extra->controls_free( op, rs, &ctrls );
192 			goto retry;
193 		}
194 	}
195 
196 cleanup:;
197 	(void)mi->mi_ldap_extra->controls_free( op, rs, &ctrls );
198 
199 	for ( --i; i >= 0; --i ) {
200 		free( attrs[ i ]->mod_bvalues );
201 		free( attrs[ i ] );
202 	}
203 	free( attrs );
204 	if ( mdn.bv_val != op->ora_e->e_dn ) {
205 		free( mdn.bv_val );
206 		BER_BVZERO( &mdn );
207 	}
208 
209 done:;
210 	if ( mc ) {
211 		meta_back_release_conn( mi, mc );
212 	}
213 
214 	return rs->sr_err;
215 }
216 
217