1/*	$NetBSD: add.c,v 1.3 2021/08/14 16:14:55 christos Exp $	*/
2
3/* add.c */
4/* $OpenLDAP$ */
5/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
6 *
7 * Copyright 1998-2021 The OpenLDAP Foundation.
8 * All rights reserved.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted only as authorized by the OpenLDAP
12 * Public License.
13 *
14 * A copy of this license is available in the file LICENSE in the
15 * top-level directory of the distribution or, alternatively, at
16 * <http://www.OpenLDAP.org/license.html>.
17 */
18/* Portions Copyright (c) 1990 Regents of the University of Michigan.
19 * All rights reserved.
20 */
21
22#include <sys/cdefs.h>
23__RCSID("$NetBSD: add.c,v 1.3 2021/08/14 16:14:55 christos Exp $");
24
25#include "portable.h"
26
27#include <stdio.h>
28
29#include <ac/socket.h>
30#include <ac/string.h>
31#include <ac/time.h>
32
33#include "ldap-int.h"
34
35/* An LDAP Add Request/Response looks like this:
36 *        AddRequest ::= [APPLICATION 8] SEQUENCE {
37 *            entry           LDAPDN,
38 *            attributes      AttributeList }
39 *
40 *        AttributeList ::= SEQUENCE OF attribute Attribute
41 *
42 *        Attribute ::= PartialAttribute(WITH COMPONENTS {
43 *             ...,
44 *             vals (SIZE(1..MAX))})
45 *
46 *        PartialAttribute ::= SEQUENCE {
47 *             type       AttributeDescription,
48 *             vals       SET OF value AttributeValue }
49 *
50 *        AttributeDescription ::= LDAPString
51 *             -- Constrained to <attributedescription> [RFC4512]
52 *
53 *        AttributeValue ::= OCTET STRING
54 *
55 *        AddResponse ::= [APPLICATION 9] LDAPResult
56 * (Source: RFC 4511)
57 */
58
59/*
60 * ldap_add - initiate an ldap add operation.  Parameters:
61 *
62 *	ld		LDAP descriptor
63 *	dn		DN of the entry to add
64 *	mods		List of attributes for the entry.  This is a null-
65 *			terminated array of pointers to LDAPMod structures.
66 *			only the type and values in the structures need be
67 *			filled in.
68 *
69 * Example:
70 *	LDAPMod	*attrs[] = {
71 *			{ 0, "cn", { "babs jensen", "babs", 0 } },
72 *			{ 0, "sn", { "jensen", 0 } },
73 *			{ 0, "objectClass", { "person", 0 } },
74 *			0
75 *		}
76 *	msgid = ldap_add( ld, dn, attrs );
77 */
78int
79ldap_add( LDAP *ld, LDAP_CONST char *dn, LDAPMod **attrs )
80{
81	int rc;
82	int msgid;
83
84	rc = ldap_add_ext( ld, dn, attrs, NULL, NULL, &msgid );
85
86	if ( rc != LDAP_SUCCESS )
87		return -1;
88
89	return msgid;
90}
91
92
93BerElement *
94ldap_build_add_req(
95	LDAP *ld,
96	const char *dn,
97	LDAPMod **attrs,
98	LDAPControl **sctrls,
99	LDAPControl **cctrls,
100	ber_int_t	*msgidp )
101{
102	BerElement *ber;
103	int i, rc;
104
105	/* create a message to send */
106	if ( (ber = ldap_alloc_ber_with_options( ld )) == NULL ) {
107		return( NULL );
108	}
109
110	LDAP_NEXT_MSGID(ld, *msgidp);
111	rc = ber_printf( ber, "{it{s{", /* '}}}' */
112		*msgidp, LDAP_REQ_ADD, dn );
113
114	if ( rc == -1 ) {
115		ld->ld_errno = LDAP_ENCODING_ERROR;
116		ber_free( ber, 1 );
117		return( NULL );
118	}
119
120	/* allow attrs to be NULL ("touch"; should fail...) */
121	if ( attrs ) {
122		/* for each attribute in the entry... */
123		for ( i = 0; attrs[i] != NULL; i++ ) {
124			if ( ( attrs[i]->mod_op & LDAP_MOD_BVALUES) != 0 ) {
125				int j;
126
127				if ( attrs[i]->mod_bvalues == NULL ) {
128					ld->ld_errno = LDAP_PARAM_ERROR;
129					ber_free( ber, 1 );
130					return( NULL );
131				}
132
133				for ( j = 0; attrs[i]->mod_bvalues[ j ] != NULL; j++ ) {
134					if ( attrs[i]->mod_bvalues[ j ]->bv_val == NULL ) {
135						ld->ld_errno = LDAP_PARAM_ERROR;
136						ber_free( ber, 1 );
137						return( NULL );
138					}
139				}
140
141				rc = ber_printf( ber, "{s[V]N}", attrs[i]->mod_type,
142				    attrs[i]->mod_bvalues );
143
144			} else {
145				if ( attrs[i]->mod_values == NULL ) {
146					ld->ld_errno = LDAP_PARAM_ERROR;
147					ber_free( ber, 1 );
148					return( NULL );
149				}
150
151				rc = ber_printf( ber, "{s[v]N}", attrs[i]->mod_type,
152				    attrs[i]->mod_values );
153			}
154			if ( rc == -1 ) {
155				ld->ld_errno = LDAP_ENCODING_ERROR;
156				ber_free( ber, 1 );
157				return( NULL );
158			}
159		}
160	}
161
162	if ( ber_printf( ber, /*{{*/ "N}N}" ) == -1 ) {
163		ld->ld_errno = LDAP_ENCODING_ERROR;
164		ber_free( ber, 1 );
165		return( NULL );
166	}
167
168	/* Put Server Controls */
169	if( ldap_int_put_controls( ld, sctrls, ber ) != LDAP_SUCCESS ) {
170		ber_free( ber, 1 );
171		return( NULL );
172	}
173
174	if ( ber_printf( ber, /*{*/ "N}" ) == -1 ) {
175		ld->ld_errno = LDAP_ENCODING_ERROR;
176		ber_free( ber, 1 );
177		return( NULL );
178	}
179
180	return( ber );
181}
182
183/*
184 * ldap_add_ext - initiate an ldap extended add operation.  Parameters:
185 *
186 *	ld		LDAP descriptor
187 *	dn		DN of the entry to add
188 *	mods		List of attributes for the entry.  This is a null-
189 *			terminated array of pointers to LDAPMod structures.
190 *			only the type and values in the structures need be
191 *			filled in.
192 *	sctrl	Server Controls
193 *	cctrl	Client Controls
194 *	msgidp	Message ID pointer
195 *
196 * Example:
197 *	LDAPMod	*attrs[] = {
198 *			{ 0, "cn", { "babs jensen", "babs", 0 } },
199 *			{ 0, "sn", { "jensen", 0 } },
200 *			{ 0, "objectClass", { "person", 0 } },
201 *			0
202 *		}
203 *	rc = ldap_add_ext( ld, dn, attrs, NULL, NULL, &msgid );
204 */
205int
206ldap_add_ext(
207	LDAP *ld,
208	LDAP_CONST char *dn,
209	LDAPMod **attrs,
210	LDAPControl **sctrls,
211	LDAPControl **cctrls,
212	int	*msgidp )
213{
214	BerElement	*ber;
215	int		rc;
216	ber_int_t	id;
217
218	Debug0( LDAP_DEBUG_TRACE, "ldap_add_ext\n" );
219	assert( ld != NULL );
220	assert( LDAP_VALID( ld ) );
221	assert( dn != NULL );
222	assert( msgidp != NULL );
223
224	/* check client controls */
225	rc = ldap_int_client_controls( ld, cctrls );
226	if( rc != LDAP_SUCCESS ) return rc;
227
228	ber = ldap_build_add_req( ld, dn, attrs, sctrls, cctrls, &id );
229	if( !ber )
230		return ld->ld_errno;
231
232	/* send the message */
233	*msgidp = ldap_send_initial_request( ld, LDAP_REQ_ADD, dn, ber, id );
234
235	if(*msgidp < 0)
236		return ld->ld_errno;
237
238	return LDAP_SUCCESS;
239}
240
241int
242ldap_add_ext_s(
243	LDAP *ld,
244	LDAP_CONST char *dn,
245	LDAPMod **attrs,
246	LDAPControl **sctrls,
247	LDAPControl **cctrls )
248{
249	int		msgid, rc;
250	LDAPMessage	*res;
251
252	rc = ldap_add_ext( ld, dn, attrs, sctrls, cctrls, &msgid );
253
254	if ( rc != LDAP_SUCCESS )
255		return( rc );
256
257	if ( ldap_result( ld, msgid, LDAP_MSG_ALL, (struct timeval *) NULL, &res ) == -1 || !res )
258		return( ld->ld_errno );
259
260	return( ldap_result2error( ld, res, 1 ) );
261}
262
263int
264ldap_add_s( LDAP *ld, LDAP_CONST char *dn, LDAPMod **attrs )
265{
266	return ldap_add_ext_s( ld, dn, attrs, NULL, NULL );
267}
268
269