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