1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  *
3*0Sstevel@tonic-gate  * Copyright %G% Sun Microsystems, Inc.
4*0Sstevel@tonic-gate  * All Rights Reserved
5*0Sstevel@tonic-gate  *
6*0Sstevel@tonic-gate  *
7*0Sstevel@tonic-gate  * Comments:
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  */
10*0Sstevel@tonic-gate 
11*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
12*0Sstevel@tonic-gate 
13*0Sstevel@tonic-gate #include <stdio.h>
14*0Sstevel@tonic-gate #include <string.h>
15*0Sstevel@tonic-gate #include "lber.h"
16*0Sstevel@tonic-gate #include "ldap.h"
17*0Sstevel@tonic-gate #include "ldap-private.h"
18*0Sstevel@tonic-gate #include "ldap-int.h"
19*0Sstevel@tonic-gate 
20*0Sstevel@tonic-gate static int ldap_control_copy_contents(LDAPControl *, LDAPControl *);
21*0Sstevel@tonic-gate 
22*0Sstevel@tonic-gate void ldap_control_free (LDAPControl *ctrl)
23*0Sstevel@tonic-gate {
24*0Sstevel@tonic-gate 	if (ctrl != NULL){
25*0Sstevel@tonic-gate 		if (ctrl->ldctl_oid)
26*0Sstevel@tonic-gate 			free (ctrl->ldctl_oid);
27*0Sstevel@tonic-gate 		if (ctrl->ldctl_value.bv_val != NULL)
28*0Sstevel@tonic-gate 			free (ctrl->ldctl_value.bv_val);
29*0Sstevel@tonic-gate 		free ((char *)ctrl);
30*0Sstevel@tonic-gate 	}
31*0Sstevel@tonic-gate 	return;
32*0Sstevel@tonic-gate }
33*0Sstevel@tonic-gate 
34*0Sstevel@tonic-gate void ldap_controls_free (LDAPControl **ctrls)
35*0Sstevel@tonic-gate {
36*0Sstevel@tonic-gate 	int i;
37*0Sstevel@tonic-gate 
38*0Sstevel@tonic-gate 	if (ctrls == NULL)
39*0Sstevel@tonic-gate 		return;
40*0Sstevel@tonic-gate 
41*0Sstevel@tonic-gate 	for (i = 0; ctrls[i] != NULL; i++){
42*0Sstevel@tonic-gate 		ldap_control_free(ctrls[i]);
43*0Sstevel@tonic-gate 	}
44*0Sstevel@tonic-gate 	free((char *)ctrls);
45*0Sstevel@tonic-gate }
46*0Sstevel@tonic-gate 
47*0Sstevel@tonic-gate LDAPControl * ldap_control_dup(LDAPControl *ctrl)
48*0Sstevel@tonic-gate {
49*0Sstevel@tonic-gate 	LDAPControl *newctrl;
50*0Sstevel@tonic-gate 
51*0Sstevel@tonic-gate 	if ((newctrl = (LDAPControl *)calloc(1, sizeof(LDAPControl))) == NULL)
52*0Sstevel@tonic-gate 		return (NULL);
53*0Sstevel@tonic-gate 
54*0Sstevel@tonic-gate 	if (ldap_control_copy_contents(newctrl, ctrl) != LDAP_SUCCESS) {
55*0Sstevel@tonic-gate 		free(newctrl);
56*0Sstevel@tonic-gate 		return (NULL);
57*0Sstevel@tonic-gate 	}
58*0Sstevel@tonic-gate 
59*0Sstevel@tonic-gate 	return(newctrl);
60*0Sstevel@tonic-gate }
61*0Sstevel@tonic-gate 
62*0Sstevel@tonic-gate 
63*0Sstevel@tonic-gate static int ldap_control_copy_contents(LDAPControl *ctrl_dst,
64*0Sstevel@tonic-gate LDAPControl *ctrl_src)
65*0Sstevel@tonic-gate {
66*0Sstevel@tonic-gate 	size_t  len;
67*0Sstevel@tonic-gate 
68*0Sstevel@tonic-gate 	if (NULL == ctrl_dst || NULL == ctrl_src) {
69*0Sstevel@tonic-gate 		return (LDAP_PARAM_ERROR);
70*0Sstevel@tonic-gate 	}
71*0Sstevel@tonic-gate 
72*0Sstevel@tonic-gate 	ctrl_dst->ldctl_iscritical = ctrl_src->ldctl_iscritical;
73*0Sstevel@tonic-gate 
74*0Sstevel@tonic-gate 	/* fill in the fields of this new control */
75*0Sstevel@tonic-gate 	if ((ctrl_dst->ldctl_oid = strdup(ctrl_src->ldctl_oid)) == NULL) {
76*0Sstevel@tonic-gate 		return (LDAP_NO_MEMORY);
77*0Sstevel@tonic-gate 	}
78*0Sstevel@tonic-gate 
79*0Sstevel@tonic-gate 	len = (size_t)(ctrl_src->ldctl_value).bv_len;
80*0Sstevel@tonic-gate 	if (ctrl_src->ldctl_value.bv_val == NULL || len <= 0) {
81*0Sstevel@tonic-gate 		ctrl_dst->ldctl_value.bv_len = 0;
82*0Sstevel@tonic-gate 		ctrl_dst->ldctl_value.bv_val = NULL;
83*0Sstevel@tonic-gate 	} else {
84*0Sstevel@tonic-gate 		ctrl_dst->ldctl_value.bv_len = len;
85*0Sstevel@tonic-gate 		if ((ctrl_dst->ldctl_value.bv_val = malloc(len))
86*0Sstevel@tonic-gate 			== NULL) {
87*0Sstevel@tonic-gate 			free(ctrl_dst->ldctl_oid);
88*0Sstevel@tonic-gate 			return (LDAP_NO_MEMORY);
89*0Sstevel@tonic-gate 		}
90*0Sstevel@tonic-gate 		SAFEMEMCPY(ctrl_dst->ldctl_value.bv_val,
91*0Sstevel@tonic-gate 			ctrl_src->ldctl_value.bv_val, len);
92*0Sstevel@tonic-gate 	}
93*0Sstevel@tonic-gate 
94*0Sstevel@tonic-gate 	return (LDAP_SUCCESS);
95*0Sstevel@tonic-gate }
96*0Sstevel@tonic-gate 
97*0Sstevel@tonic-gate 
98*0Sstevel@tonic-gate LDAPControl ** ldap_controls_dup(LDAPControl ** ctrls)
99*0Sstevel@tonic-gate {
100*0Sstevel@tonic-gate 	int i;
101*0Sstevel@tonic-gate 	LDAPControl **newctrls;
102*0Sstevel@tonic-gate 
103*0Sstevel@tonic-gate 	for (i = 0; ctrls[i] != NULL; i++);
104*0Sstevel@tonic-gate 	newctrls = (LDAPControl **)calloc(i+1, sizeof(LDAPControl*));
105*0Sstevel@tonic-gate 	if (newctrls == NULL) {
106*0Sstevel@tonic-gate 		return (NULL);
107*0Sstevel@tonic-gate 	}
108*0Sstevel@tonic-gate 
109*0Sstevel@tonic-gate 	for (i = 0; ctrls[i] != NULL; i++) {
110*0Sstevel@tonic-gate 		newctrls[i] = ldap_control_dup(ctrls[i]);
111*0Sstevel@tonic-gate 		if (newctrls[i] == NULL) {
112*0Sstevel@tonic-gate 			ldap_controls_free(newctrls);
113*0Sstevel@tonic-gate 			return (NULL);
114*0Sstevel@tonic-gate 		}
115*0Sstevel@tonic-gate 	}
116*0Sstevel@tonic-gate 	return (newctrls);
117*0Sstevel@tonic-gate }
118*0Sstevel@tonic-gate 
119*0Sstevel@tonic-gate int ldap_controls_code (BerElement *ber, LDAPControl **ctrls)
120*0Sstevel@tonic-gate {
121*0Sstevel@tonic-gate 	int i, rc;
122*0Sstevel@tonic-gate 
123*0Sstevel@tonic-gate 	if (ctrls && ctrls[0]){
124*0Sstevel@tonic-gate 		rc = ber_printf(ber, "t{", LDAP_TAG_CONTROL_LIST);
125*0Sstevel@tonic-gate 		if (rc == -1){
126*0Sstevel@tonic-gate 			ber_free(ber, 1);
127*0Sstevel@tonic-gate 			return(LDAP_ENCODING_ERROR);
128*0Sstevel@tonic-gate 		}
129*0Sstevel@tonic-gate 
130*0Sstevel@tonic-gate 		for (i = 0; ctrls[i] != NULL; i++){
131*0Sstevel@tonic-gate 			rc = ber_printf(ber, "{s", ctrls[i]->ldctl_oid);
132*0Sstevel@tonic-gate 			if (rc == -1){
133*0Sstevel@tonic-gate 				ber_free(ber, 1);
134*0Sstevel@tonic-gate 				return(LDAP_ENCODING_ERROR);
135*0Sstevel@tonic-gate 			}
136*0Sstevel@tonic-gate 			if (ctrls[i]->ldctl_iscritical){
137*0Sstevel@tonic-gate 				rc = ber_printf(ber, "b",  ctrls[i]->ldctl_iscritical);
138*0Sstevel@tonic-gate 				if (rc == -1){
139*0Sstevel@tonic-gate 					ber_free(ber, 1);
140*0Sstevel@tonic-gate 					return(LDAP_ENCODING_ERROR);
141*0Sstevel@tonic-gate 				}
142*0Sstevel@tonic-gate 			}
143*0Sstevel@tonic-gate 
144*0Sstevel@tonic-gate 			if (ctrls[i]->ldctl_value.bv_val)
145*0Sstevel@tonic-gate 				rc = ber_printf(ber, "o}", ctrls[i]->ldctl_value.bv_val, ctrls[i]->ldctl_value.bv_len);
146*0Sstevel@tonic-gate 			else
147*0Sstevel@tonic-gate 				rc = ber_printf(ber, "}");
148*0Sstevel@tonic-gate 			if (rc == -1){
149*0Sstevel@tonic-gate 				ber_free(ber, 1);
150*0Sstevel@tonic-gate 				return(LDAP_ENCODING_ERROR);
151*0Sstevel@tonic-gate 			}
152*0Sstevel@tonic-gate 		}
153*0Sstevel@tonic-gate 
154*0Sstevel@tonic-gate 		rc = ber_printf(ber, "}");
155*0Sstevel@tonic-gate 		if (rc == -1){
156*0Sstevel@tonic-gate 			ber_free(ber, 1);
157*0Sstevel@tonic-gate 			return(LDAP_ENCODING_ERROR);
158*0Sstevel@tonic-gate 		}
159*0Sstevel@tonic-gate 	}
160*0Sstevel@tonic-gate 	return (LDAP_SUCCESS);
161*0Sstevel@tonic-gate }
162*0Sstevel@tonic-gate 
163*0Sstevel@tonic-gate /* Decode the sequence of control from the ber, return a NULL terminated list of LDAPControl* */
164*0Sstevel@tonic-gate LDAPControl ** ldap_controls_decode(BerElement *ber, int *errcode)
165*0Sstevel@tonic-gate {
166*0Sstevel@tonic-gate 	LDAPControl ** ctrls = NULL;
167*0Sstevel@tonic-gate 
168*0Sstevel@tonic-gate 	char *opaque;
169*0Sstevel@tonic-gate 	unsigned int tag, len;
170*0Sstevel@tonic-gate 	int i = 0, count = 0;
171*0Sstevel@tonic-gate 
172*0Sstevel@tonic-gate 	BerElement tmpber = *ber;
173*0Sstevel@tonic-gate 
174*0Sstevel@tonic-gate 	for (tag = ber_first_element(&tmpber, &len, &opaque);
175*0Sstevel@tonic-gate 		 tag != LBER_DEFAULT;
176*0Sstevel@tonic-gate 		 tag = ber_next_element(&tmpber, &len, opaque )) {
177*0Sstevel@tonic-gate 		count ++;
178*0Sstevel@tonic-gate 		ber_skip_tag(&tmpber, &len);
179*0Sstevel@tonic-gate 	}
180*0Sstevel@tonic-gate 
181*0Sstevel@tonic-gate 
182*0Sstevel@tonic-gate 	if ((ctrls = (LDAPControl **)calloc(count + 1, sizeof(LDAPControl *))) == NULL){
183*0Sstevel@tonic-gate 		*errcode = LDAP_NO_MEMORY;
184*0Sstevel@tonic-gate 		return(NULL);
185*0Sstevel@tonic-gate 	}
186*0Sstevel@tonic-gate 
187*0Sstevel@tonic-gate 	for (tag = ber_first_element(ber, &len, &opaque );
188*0Sstevel@tonic-gate 		 tag != LBER_DEFAULT;
189*0Sstevel@tonic-gate 		 tag = ber_next_element (ber, &len, opaque )) {
190*0Sstevel@tonic-gate 		LDAPControl *aCtrl;
191*0Sstevel@tonic-gate 		unsigned int ttag, tlen;
192*0Sstevel@tonic-gate 
193*0Sstevel@tonic-gate 		if ((aCtrl = (LDAPControl *)calloc(1, sizeof(LDAPControl))) == NULL) {
194*0Sstevel@tonic-gate 			*errcode = LDAP_NO_MEMORY;
195*0Sstevel@tonic-gate 			ldap_controls_free(ctrls);
196*0Sstevel@tonic-gate 			return (NULL);
197*0Sstevel@tonic-gate 		}
198*0Sstevel@tonic-gate 		if (ber_scanf(ber, "{a", &aCtrl->ldctl_oid) == LBER_ERROR){
199*0Sstevel@tonic-gate 			*errcode = LDAP_PROTOCOL_ERROR;
200*0Sstevel@tonic-gate 			free(aCtrl);
201*0Sstevel@tonic-gate 			ldap_controls_free(ctrls);
202*0Sstevel@tonic-gate 			return (NULL);
203*0Sstevel@tonic-gate 		}
204*0Sstevel@tonic-gate 		aCtrl->ldctl_iscritical = 0;
205*0Sstevel@tonic-gate 		ttag = ber_peek_tag(ber, &tlen);
206*0Sstevel@tonic-gate 		if (ttag == 0x01) { /* Boolean : criticality */
207*0Sstevel@tonic-gate 			if (ber_scanf(ber, "b", &aCtrl->ldctl_iscritical) == LBER_ERROR){
208*0Sstevel@tonic-gate 				*errcode = LDAP_PROTOCOL_ERROR;
209*0Sstevel@tonic-gate 				free(aCtrl);
210*0Sstevel@tonic-gate 				ldap_controls_free(ctrls);
211*0Sstevel@tonic-gate 				return (NULL);
212*0Sstevel@tonic-gate 			}
213*0Sstevel@tonic-gate 			ttag = ber_peek_tag(ber, &tlen);
214*0Sstevel@tonic-gate 		}
215*0Sstevel@tonic-gate 		if (ttag == 0x04) { /* Octet string : value (it's optional)*/
216*0Sstevel@tonic-gate 			if (ber_scanf(ber, "o", &aCtrl->ldctl_value) == LBER_ERROR){
217*0Sstevel@tonic-gate 				*errcode = LDAP_PROTOCOL_ERROR;
218*0Sstevel@tonic-gate 				free(aCtrl);
219*0Sstevel@tonic-gate 				ldap_controls_free(ctrls);
220*0Sstevel@tonic-gate 				return (NULL);
221*0Sstevel@tonic-gate 			}
222*0Sstevel@tonic-gate 
223*0Sstevel@tonic-gate 		} else if (ttag != LBER_DEFAULT){
224*0Sstevel@tonic-gate 			*errcode = LDAP_PROTOCOL_ERROR;
225*0Sstevel@tonic-gate 			free(aCtrl);
226*0Sstevel@tonic-gate 			ldap_controls_free(ctrls);
227*0Sstevel@tonic-gate 			return (NULL);
228*0Sstevel@tonic-gate 		}
229*0Sstevel@tonic-gate 
230*0Sstevel@tonic-gate 		if (ber_scanf(ber, "}") == LBER_ERROR){
231*0Sstevel@tonic-gate 			*errcode = LDAP_PROTOCOL_ERROR;
232*0Sstevel@tonic-gate 			free(aCtrl);
233*0Sstevel@tonic-gate 			ldap_controls_free(ctrls);
234*0Sstevel@tonic-gate 			return (NULL);
235*0Sstevel@tonic-gate 		}
236*0Sstevel@tonic-gate 		/* add aCtrl in ctrls */
237*0Sstevel@tonic-gate 		ctrls[i++] = aCtrl;
238*0Sstevel@tonic-gate 	}
239*0Sstevel@tonic-gate 	return (ctrls);
240*0Sstevel@tonic-gate }
241*0Sstevel@tonic-gate 
242*0Sstevel@tonic-gate /* build an allocated LDAPv3 control.  Returns an LDAP error code. */
243*0Sstevel@tonic-gate int ldap_build_control(char *oid, BerElement *ber, int freeber,
244*0Sstevel@tonic-gate char iscritical, LDAPControl **ctrlp)
245*0Sstevel@tonic-gate {
246*0Sstevel@tonic-gate 	int		rc;
247*0Sstevel@tonic-gate 	struct berval	*bvp;
248*0Sstevel@tonic-gate 
249*0Sstevel@tonic-gate 	if (ber == NULL) {
250*0Sstevel@tonic-gate 		bvp = NULL;
251*0Sstevel@tonic-gate 	} else {
252*0Sstevel@tonic-gate 		/* allocate struct berval with contents of the BER encoding */
253*0Sstevel@tonic-gate 		rc = ber_flatten(ber, &bvp);
254*0Sstevel@tonic-gate 		if (freeber) {
255*0Sstevel@tonic-gate 			ber_free(ber, 1);
256*0Sstevel@tonic-gate 		}
257*0Sstevel@tonic-gate 		if (rc == -1) {
258*0Sstevel@tonic-gate 			return (LDAP_NO_MEMORY);
259*0Sstevel@tonic-gate 		}
260*0Sstevel@tonic-gate 	}
261*0Sstevel@tonic-gate 
262*0Sstevel@tonic-gate 	/* allocate the new control structure */
263*0Sstevel@tonic-gate 	if ((*ctrlp = (LDAPControl *)calloc(1, sizeof (LDAPControl)))
264*0Sstevel@tonic-gate 	    == NULL) {
265*0Sstevel@tonic-gate 		if (bvp != NULL) {
266*0Sstevel@tonic-gate 			ber_bvfree(bvp);
267*0Sstevel@tonic-gate 		}
268*0Sstevel@tonic-gate 		return (LDAP_NO_MEMORY);
269*0Sstevel@tonic-gate 	}
270*0Sstevel@tonic-gate 
271*0Sstevel@tonic-gate 	/* fill in the fields of this new control */
272*0Sstevel@tonic-gate 	(*ctrlp)->ldctl_iscritical = iscritical;
273*0Sstevel@tonic-gate 	if (((*ctrlp)->ldctl_oid = strdup(oid)) == NULL) {
274*0Sstevel@tonic-gate 		free(*ctrlp);
275*0Sstevel@tonic-gate 		*ctrlp = NULL;
276*0Sstevel@tonic-gate 		if (bvp != NULL) {
277*0Sstevel@tonic-gate 			ber_bvfree(bvp);
278*0Sstevel@tonic-gate 		}
279*0Sstevel@tonic-gate 		return (LDAP_NO_MEMORY);
280*0Sstevel@tonic-gate 	}
281*0Sstevel@tonic-gate 
282*0Sstevel@tonic-gate 	if (bvp == NULL) {
283*0Sstevel@tonic-gate 		(*ctrlp)->ldctl_value.bv_len = 0;
284*0Sstevel@tonic-gate 		(*ctrlp)->ldctl_value.bv_val = NULL;
285*0Sstevel@tonic-gate 	} else {
286*0Sstevel@tonic-gate 		(*ctrlp)->ldctl_value = *bvp;	/* struct copy */
287*0Sstevel@tonic-gate 		free(bvp);	/* free container, not contents! */
288*0Sstevel@tonic-gate 	}
289*0Sstevel@tonic-gate 
290*0Sstevel@tonic-gate 	return (LDAP_SUCCESS);
291*0Sstevel@tonic-gate }
292