xref: /illumos-gate/usr/src/lib/libldap5/sources/ldap/common/psearch.c (revision 4de2612967d06c4fdbf524a62556a1e8118a006f)
1 #pragma ident	"%Z%%M%	%I%	%E% SMI"
2 
3 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
4  *
5  * The contents of this file are subject to the Netscape Public License
6  * Version 1.0 (the "NPL"); you may not use this file except in
7  * compliance with the NPL.  You may obtain a copy of the NPL at
8  * http://www.mozilla.org/NPL/
9  *
10  * Software distributed under the NPL is distributed on an "AS IS" basis,
11  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
12  * for the specific language governing rights and limitations under the
13  * NPL.
14  *
15  * The Initial Developer of this code under the NPL is Netscape
16  * Communications Corporation.  Portions created by Netscape are
17  * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
18  * Reserved.
19  */
20 /*
21  * psearch.c - Persistent search and "Entry Change Notification" support.
22  */
23 #include "ldap-int.h"
24 
25 
26 int
27 LDAP_CALL
28 ldap_create_persistentsearch_control( LDAP *ld, int changetypes,
29     int changesonly, int return_echg_ctls, char ctl_iscritical,
30     LDAPControl **ctrlp )
31 {
32     BerElement	*ber;
33     int		rc;
34 
35     if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) {
36 	return( LDAP_PARAM_ERROR );
37     }
38 
39     if ( ctrlp == NULL || ( changetypes & ~LDAP_CHANGETYPE_ANY ) != 0 ) {
40 	rc = LDAP_PARAM_ERROR;
41 	goto report_error_and_return;
42     }
43 
44     /*
45      * create a Persistent Search control.  The control value looks like this:
46      *
47      *	PersistentSearch ::= SEQUENCE {
48      *		changeTypes INTEGER,
49      *		-- the changeTypes field is the logical OR of
50      *		-- one or more of these values: add (1), delete (2),
51      *		-- modify (4), modDN (8).  It specifies which types of
52      *		-- changes will cause an entry to be returned.
53      *		changesOnly BOOLEAN, -- skip initial search?
54      *		returnECs BOOLEAN,   -- return "Entry Change" controls?
55      *	}
56      */
57     if (( nsldapi_alloc_ber_with_options( ld, &ber )) != LDAP_SUCCESS ) {
58 	rc = LDAP_NO_MEMORY;
59 	goto report_error_and_return;
60     }
61 
62     if ( ber_printf( ber, "{ibb}", changetypes, changesonly,
63 	    return_echg_ctls ) == -1 ) {
64 	ber_free( ber, 1 );
65 	rc = LDAP_ENCODING_ERROR;
66 	goto report_error_and_return;
67     }
68 
69     rc = nsldapi_build_control( LDAP_CONTROL_PERSISTENTSEARCH, ber, 1,
70 	    ctl_iscritical, ctrlp );
71 
72 report_error_and_return:
73     LDAP_SET_LDERRNO( ld, rc, NULL, NULL );
74     return( rc );
75 }
76 
77 
78 int
79 LDAP_CALL
80 ldap_parse_entrychange_control( LDAP *ld, LDAPControl **ctrls, int *chgtypep,
81     char **prevdnp, int *chgnumpresentp, ber_int_t *chgnump )
82 {
83     BerElement		*ber;
84     int			rc, i, changetype;
85     ber_len_t		len;
86     ber_int_t		along;
87     char		*previousdn;
88 
89     if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) {
90 	return( LDAP_PARAM_ERROR );
91     }
92 
93     /*
94      * find the entry change notification in the list of controls
95      */
96     for ( i = 0; ctrls != NULL && ctrls[i] != NULL; ++i ) {
97 	if ( strcmp( ctrls[i]->ldctl_oid, LDAP_CONTROL_ENTRYCHANGE ) == 0 ) {
98 	    break;
99 	}
100     }
101 
102     if ( ctrls == NULL || ctrls[i] == NULL ) {
103 	rc = LDAP_CONTROL_NOT_FOUND;
104 	goto report_error_and_return;
105     }
106 
107     /*
108      * allocate a BER element from the control value and parse it.  The control
109      * value should look like this:
110      *
111      *	EntryChangeNotification ::= SEQUENCE {
112      *	     changeType ENUMERATED {
113      *	 	add             (1),  -- these values match the
114      *	 	delete          (2),  -- values used for changeTypes
115      *	 	modify          (4),  -- in the PersistentSearch control.
116      *	 	modDN           (8),
117      *	     },
118      *	     previousDN   LDAPDN OPTIONAL,     -- modDN ops. only
119      *	     changeNumber INTEGER OPTIONAL,    -- if supported
120      *	}
121      */
122     if (( ber = ber_init( &(ctrls[i]->ldctl_value))) == NULL ) {
123 	rc = LDAP_NO_MEMORY;
124 	goto report_error_and_return;
125     }
126 
127     if ( ber_scanf( ber, "{e", &along ) == LBER_ERROR ) {
128 	ber_free( ber, 1 );
129 	rc = LDAP_DECODING_ERROR;
130 	goto report_error_and_return;
131     }
132     changetype = (int)along;	/* XXX lossy cast */
133 
134     if ( changetype == LDAP_CHANGETYPE_MODDN ) {
135 	if ( ber_scanf( ber, "a", &previousdn ) == LBER_ERROR ) {
136 	    ber_free( ber, 1 );
137 	    rc = LDAP_DECODING_ERROR;
138 	    goto report_error_and_return;
139 	}
140     } else {
141 	previousdn = NULL;
142     }
143 
144     if ( chgtypep != NULL ) {
145 	*chgtypep = changetype;
146     }
147     if ( prevdnp != NULL ) {
148 	*prevdnp = previousdn;
149     } else if ( previousdn != NULL ) {
150 	NSLDAPI_FREE( previousdn );
151     }
152 
153     if ( chgnump != NULL ) {	/* check for optional changenumber */
154 	if ( ber_peek_tag( ber, &len ) == LBER_INTEGER
155 		&& ber_get_int( ber, chgnump ) != LBER_ERROR ) {
156 	    if ( chgnumpresentp != NULL ) {
157 		*chgnumpresentp = 1;
158 	    }
159 	} else {
160 	    if ( chgnumpresentp != NULL ) {
161 		*chgnumpresentp = 0;
162 	    }
163 	}
164     }
165 
166     ber_free( ber, 1 );
167     rc = LDAP_SUCCESS;
168 
169 report_error_and_return:
170     LDAP_SET_LDERRNO( ld, rc, NULL, NULL );
171     return( rc );
172 }
173