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