1 /*
2  * Copyright (c) 2001 by Sun Microsystems, Inc.
3  * All rights reserved.
4  */
5 
6 #pragma ident	"%Z%%M%	%I%	%E% SMI"
7 
8 /*
9  * The contents of this file are subject to the Netscape Public
10  * License Version 1.1 (the "License"); you may not use this file
11  * except in compliance with the License. You may obtain a copy of
12  * the License at http://www.mozilla.org/NPL/
13  *
14  * Software distributed under the License is distributed on an "AS
15  * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
16  * implied. See the License for the specific language governing
17  * rights and limitations under the License.
18  *
19  * The Original Code is Mozilla Communicator client code, released
20  * March 31, 1998.
21  *
22  * The Initial Developer of the Original Code is Netscape
23  * Communications Corporation. Portions created by Netscape are
24  * Copyright (C) 1998-1999 Netscape Communications Corporation. All
25  * Rights Reserved.
26  *
27  * Contributor(s):
28  */
29 /*
30  *  referral.c - routines for handling LDAPv3 referrals and references.
31  */
32 
33 #include "ldap-int.h"
34 
35 
36 LDAPMessage *
37 LDAP_CALL
38 ldap_first_reference( LDAP *ld, LDAPMessage *res )
39 {
40 	if ( !NSLDAPI_VALID_LDAP_POINTER( ld ) || res == NULLMSG ) {
41 		return( NULLMSG );
42 	}
43 
44 	if ( res->lm_msgtype == LDAP_RES_SEARCH_REFERENCE ) {
45 		return( res );
46 	}
47 
48 	return( ldap_next_reference( ld, res ));
49 }
50 
51 
52 LDAPMessage *
53 LDAP_CALL
54 ldap_next_reference( LDAP *ld, LDAPMessage *ref )
55 {
56 	if ( !NSLDAPI_VALID_LDAP_POINTER( ld ) || ref == NULLMSG ) {
57 		return( NULLMSG );		/* punt */
58 	}
59 
60 	for ( ref = ref->lm_chain; ref != NULLMSG; ref = ref->lm_chain ) {
61 		if ( ref->lm_msgtype == LDAP_RES_SEARCH_REFERENCE ) {
62 			return( ref );
63 		}
64 	}
65 
66 	return( NULLMSG );
67 }
68 
69 
70 int
71 LDAP_CALL
72 ldap_count_references( LDAP *ld, LDAPMessage *res )
73 {
74 	int	i;
75 
76 	if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) {
77 		return( -1 );
78 	}
79 
80 	for ( i = 0; res != NULL; res = res->lm_chain ) {
81 		if ( res->lm_msgtype == LDAP_RES_SEARCH_REFERENCE ) {
82 			++i;
83 		}
84 	}
85 
86 	return( i );
87 }
88 
89 
90 /*
91  * returns an LDAP error code.
92  */
93 int
94 LDAP_CALL
95 ldap_parse_reference( LDAP *ld, LDAPMessage *ref, char ***referralsp,
96     LDAPControl ***serverctrlsp, int freeit )
97 {
98 	int		err;
99 
100 	if ( !NSLDAPI_VALID_LDAP_POINTER( ld ) ||
101 	    !NSLDAPI_VALID_LDAPMESSAGE_REFERENCE_POINTER( ref )) {
102 		return( LDAP_PARAM_ERROR );
103 	}
104 
105 	err = nsldapi_parse_reference( ld, ref->lm_ber, referralsp,
106 		serverctrlsp );
107 
108 	LDAP_SET_LDERRNO( ld, err, NULL, NULL );
109 
110 	if ( freeit ) {
111 		ldap_msgfree( ref );
112 	}
113 
114 	return( err );
115 }
116 
117 
118 /*
119  * returns an LDAP error code indicating success or failure of parsing
120  * does NOT set any error information inside "ld"
121  */
122 int
123 nsldapi_parse_reference( LDAP *ld, BerElement *rber, char ***referralsp,
124     LDAPControl ***serverctrlsp )
125 {
126 	int		err;
127 	BerElement	ber;
128 	char		**refs;
129 
130 	/*
131 	 * Parse a searchResultReference message.  These are used in LDAPv3
132 	 * and beyond and look like this:
133 	 *
134 	 *	SearchResultReference ::= [APPLICATION 19] SEQUENCE OF LDAPURL
135 	 *
136 	 * all wrapped up in an LDAPMessage sequence which looks like this:
137 	 *
138 	 *	LDAPMessage ::= SEQUENCE {
139 	 *		messageID	MessageID,
140 	 *		SearchResultReference
141 	 *		controls	[0] Controls OPTIONAL
142 	 *	}
143 	 *
144 	 * ldap_result() pulls out the message id, so by the time a result
145 	 * message gets here we are conveniently sitting at the start of the
146 	 * SearchResultReference itself.
147 	 */
148 	err = LDAP_SUCCESS;	/* optimistic */
149 	ber = *rber;		/* struct copy */
150 
151 	if ( ber_scanf( &ber, "{v", &refs ) == LBER_ERROR ) {
152 	    err = LDAP_DECODING_ERROR;
153 	} else if ( serverctrlsp != NULL ) {
154 	    /* pull out controls (if requested and any are present) */
155 	    if ( ber_scanf( &ber, "}" ) == LBER_ERROR ) {
156 		err = LDAP_DECODING_ERROR;
157 	    } else {
158 		err = nsldapi_get_controls( &ber, serverctrlsp );
159 	    }
160 	}
161 
162 	if ( referralsp == NULL ) {
163 	    ldap_value_free( refs );
164 	} else {
165 	    *referralsp = refs;
166 	}
167 
168 	return( err );
169 }
170 
171 #ifdef _SOLARIS_SDK
172 
173 char ** ldap_get_reference_urls(LDAP *ld, LDAPMessage *res)
174 {
175         BerElement tmp;
176         char **urls = NULL;
177 
178         LDAPDebug( LDAP_DEBUG_TRACE, "ldap_get_reference_urls\n", 0, 0, 0 );
179 
180         if (res == NULL){
181                 ld->ld_errno = LDAP_PARAM_ERROR;
182                 return (NULL);
183         }
184         tmp = *res->lm_ber; /* struct copy */
185         if ( ber_scanf( &tmp, "{v}", &urls) == LBER_ERROR){
186                 ld->ld_errno = LDAP_DECODING_ERROR;
187                 return (NULL);
188         }
189         return (urls);
190 }
191 
192 #endif /* _SOLARIS_SDK */
193 
194