]> git.sur5r.net Git - openldap/blob - servers/slapd/back-ldbm/alias.c
Import strdup() -> ch_strdup() change from -devel.
[openldap] / servers / slapd / back-ldbm / alias.c
1 /*
2  * Copyright (c) 1998 Will Ballantyne, ITSD, Government of BC
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms are permitted
6  * provided that this notice is preserved and that due credit is given
7  * to ITSD, Government of BC. The name of ITSD
8  * may not be used to endorse or promote products derived from this
9  * software without specific prior written permission. This software
10  * is provided ``as is'' without express or implied warranty.
11  */
12
13 #include "portable.h"
14
15 #include <stdio.h>
16 #include <string.h>
17 #include <ac/socket.h>          /* Get struct sockaddr for slap.h */
18 #include "slap.h"
19 #include "back-ldbm.h"
20 #include "proto-back-ldbm.h"
21
22 /*
23  * given an alias object, dereference it to its end point.
24  * entry returned has reader lock 
25  */
26 Entry *derefAlias_r ( Backend     *be,
27                     Connection  *conn,
28                     Operation   *op,
29                     Entry       *e)
30 {
31   Attribute *a;
32   int       depth;
33   char      **pastAliases;
34   char      *matched;
35
36   Debug( LDAP_DEBUG_TRACE, "<= checking for alias for dn %s\n", e->e_dn, 0, 0 );
37
38   /*
39    * try to deref fully, up to a maximum depth.  If the max depth exceeded
40    * then send an error
41    */
42   for ( depth = 0;
43         ( ( a = attr_find( e->e_attrs, "aliasedobjectname" ) ) != NULL) &&
44           ( depth < be->be_maxDerefDepth );
45         ++depth) 
46   {
47
48     /* 
49      * make sure there is a defined aliasedobjectname.  
50      * can only have one value so just use first value (0) in the attr list. 
51      */     
52     if (a->a_vals[0] && a->a_vals[0]->bv_val) {
53       char *newDN, *oldDN;
54
55       Debug( LDAP_DEBUG_TRACE, "<= %s is an alias for %s\n", 
56              e->e_dn, a->a_vals[0]->bv_val, 0 );
57       newDN = ch_strdup (a->a_vals[0]->bv_val);
58       oldDN = ch_strdup (e->e_dn);
59
60       /*
61        * ok, so what happens if there is an alias in the DN of a dereferenced
62        * alias object?  
63        */
64       if ( (e = dn2entry_r( be, newDN, &matched )) == NULL ) {
65
66         /* could not deref return error  */
67         Debug( LDAP_DEBUG_TRACE, 
68                "<= %s is a dangling alias to %s\n", 
69                oldDN, newDN, 0 );
70         send_ldap_result( conn, op, LDAP_ALIAS_PROBLEM, "",
71                           "Dangling Alias" );
72
73                         if(matched != NULL) free(matched);
74       }
75       free (newDN);
76       free (oldDN);
77     }
78     else {
79       /*
80        * there was an aliasedobjectname defined but no data.
81        * this can't happen, right?
82        */
83         Debug( LDAP_DEBUG_TRACE, 
84                "<= %s has no data in aliasedobjectname attribute\n", 
85                e->e_dn, 0, 0 );
86         send_ldap_result( conn, op, LDAP_ALIAS_PROBLEM, "",
87                           "Alias missing aliasedobjectname" );
88     }
89   }
90
91   /*
92    * warn if we pulled out due to exceeding the maximum deref depth
93    */
94   if ( depth >= be->be_maxDerefDepth ) {
95     Debug( LDAP_DEBUG_TRACE, 
96            "<= %s exceeded maximum deref depth %d\n", 
97            e->e_dn, be->be_maxDerefDepth, 0 );
98     send_ldap_result( conn, op, LDAP_ALIAS_PROBLEM, "",
99                         "Maximum alias dereference depth exceeded" );
100   }
101
102   return e;
103 }
104
105 /*
106  * given a DN fully deref it and return the real DN or original DN if it fails
107  */
108 char *derefDN ( Backend     *be,
109                 Connection  *conn,
110                 Operation   *op,
111                 char        *dn
112 )
113 {
114   struct ldbminfo *li = (struct ldbminfo *) be->be_private;
115   char  *matched;
116   char  *newDN = NULL;
117   int   depth;
118   Entry         *eMatched;
119   Entry         *eDeref;
120   Entry         *eNew;
121   
122
123   Debug( LDAP_DEBUG_TRACE, 
124          "<= dereferencing dn %s\n", 
125          dn, 0, 0 );
126   
127   newDN = ch_strdup ( dn );
128
129   /* while we don't have a matched dn, deref the DN */
130   for ( depth = 0;
131         ( (eMatched = dn2entry_r( be, newDN, &matched )) == NULL) &&
132           (depth < be->be_maxDerefDepth);
133         ++depth ) {
134     
135     /* free reader lock */
136     cache_return_entry_r(&li->li_cache, eMatched);
137
138     if ((matched != NULL) && *matched) {        
139       char *submatch;
140       
141       /* 
142        * make sure there actually is an entry for the matched part 
143        */
144       if ( (eMatched = dn2entry_r( be, matched, &submatch )) != NULL) {
145         char  *remainder; /* part before the aliased part */
146         int  rlen = strlen(newDN) - strlen(matched);
147         
148         Debug( LDAP_DEBUG_TRACE, "<= matched %s\n", matched, 0, 0 );
149         
150         remainder = ch_malloc (rlen + 1);
151         strncpy ( remainder, newDN, rlen );
152         remainder[rlen] = '\0';
153         
154         Debug( LDAP_DEBUG_TRACE, "<= remainder %s\n", remainder, 0, 0 );
155         
156         if ((eNew = derefAlias_r( be, conn, op, eMatched )) == NULL) {
157           free (matched);
158           matched = NULL;
159           free (newDN);
160           newDN = NULL;
161           free (remainder);
162           break; /*  no associated entry, dont deref */
163         }
164         else {
165
166           Debug( LDAP_DEBUG_TRACE, "<= l&g we have %s vs %s \n", matched, eNew->e_dn, 0 );
167
168           if (!strcasecmp (matched, eNew->e_dn)) {
169             /* newDN same as old so not an alias, no need to go further */
170             free (newDN);
171             newDN = NULL;
172             free (matched);
173             matched = NULL;
174             free (remainder);
175             break;
176           }
177
178           /* 
179            * we have dereferenced the aliased part so put
180            * the new dn together
181            */
182           free (newDN);
183           newDN = ch_malloc (strlen(eMatched->e_dn) + rlen + 1);
184           strcpy (newDN, remainder);
185           strcat (newDN, eMatched->e_dn);
186           Debug( LDAP_DEBUG_TRACE, "<= expanded to %s\n", newDN, 0, 0 );
187
188           free (matched);
189           matched = NULL;
190           free (remainder);
191
192           /* free reader lock */
193           cache_return_entry_r(&li->li_cache, eNew);
194         }
195         /* free reader lock */
196         cache_return_entry_r(&li->li_cache, eMatched);
197       }
198       else {
199         if(submatch != NULL) free(submatch);
200         break; /* there was no entry for the matched part */
201       }
202     }
203     else {
204       break; /* there was no matched part */
205     }
206   }
207   
208   /*
209    * the final part of the DN might be an alias 
210    * so try to dereference it.
211    */
212   if ( (eNew = dn2entry_r( be, newDN, &matched )) != NULL) {
213     if ((eDeref = derefAlias_r( be, conn, op, eNew )) != NULL) {
214       free (newDN);
215       newDN = ch_strdup (eDeref->e_dn);
216       /* free reader lock */
217       cache_return_entry_r(&li->li_cache, eDeref);
218     }
219     /* free reader lock */
220     cache_return_entry_r(&li->li_cache, eNew);
221   }
222   
223   /*
224    * warn if we exceeded the max depth as the resulting DN may not be dereferenced
225    */
226   if (depth >= be->be_maxDerefDepth) {
227     Debug( LDAP_DEBUG_TRACE, 
228            "<= max deref depth exceeded in derefDN for %s, result %s\n", 
229            dn, newDN, 0 );
230     send_ldap_result( conn, op, LDAP_ALIAS_PROBLEM, "",
231                       "Maximum alias dereference depth exceeded for base" );
232   }
233
234   if (newDN == NULL) {
235     newDN = ch_strdup ( dn );
236   }
237   
238   Debug( LDAP_DEBUG_TRACE, "<= returning deref DN of  %s\n", newDN, 0, 0 ); 
239   if (matched != NULL) free(matched);
240
241   return newDN;
242 }