alias.c 6.47 KB
Newer Older
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
/*
 * Copyright (c) 1998 Will Ballantyne, ITSD, Government of BC
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms are permitted
 * provided that this notice is preserved and that due credit is given
 * to ITSD, Government of BC. The name of ITSD
 * may not be used to endorse or promote products derived from this
 * software without specific prior written permission. This software
 * is provided ``as is'' without express or implied warranty.
 */

#include "portable.h"

#include <stdio.h>
#include <string.h>
#include <ac/socket.h>		/* Get struct sockaddr for slap.h */
#include "slap.h"
#include "back-ldbm.h"
#include "proto-back-ldbm.h"

/*
 * given an alias object, dereference it to its end point.
 * entry returned has reader lock 
 */
Entry *derefAlias_r ( Backend     *be,
		    Connection	*conn,
		    Operation	*op,
		    Entry       *e)
{
  Attribute *a;
  int       depth;
  char      **pastAliases;
  char      *matched;

  Debug( LDAP_DEBUG_TRACE, "<= checking for alias for dn %s\n", e->e_dn, 0, 0 );

  /*
   * try to deref fully, up to a maximum depth.  If the max depth exceeded
   * then send an error
   */
  for ( depth = 0;
	( ( a = attr_find( e->e_attrs, "aliasedobjectname" ) ) != NULL) &&
	  ( depth < be->be_maxDerefDepth );
	++depth) 
  {

    /* 
     * make sure there is a defined aliasedobjectname.  
     * can only have one value so just use first value (0) in the attr list. 
     */	    
    if (a->a_vals[0] && a->a_vals[0]->bv_val) {
      char *newDN, *oldDN;

      Debug( LDAP_DEBUG_TRACE, "<= %s is an alias for %s\n", 
	     e->e_dn, a->a_vals[0]->bv_val, 0 );
57
58
      newDN = ch_strdup (a->a_vals[0]->bv_val);
      oldDN = ch_strdup (e->e_dn);
Kurt Zeilenga's avatar
Kurt Zeilenga committed
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114

      /*
       * ok, so what happens if there is an alias in the DN of a dereferenced
       * alias object?  
       */
      if ( (e = dn2entry_r( be, newDN, &matched )) == NULL ) {

	/* could not deref return error  */
	Debug( LDAP_DEBUG_TRACE, 
	       "<= %s is a dangling alias to %s\n", 
	       oldDN, newDN, 0 );
	send_ldap_result( conn, op, LDAP_ALIAS_PROBLEM, "",
			  "Dangling Alias" );

			if(matched != NULL) free(matched);
      }
      free (newDN);
      free (oldDN);
    }
    else {
      /*
       * there was an aliasedobjectname defined but no data.
       * this can't happen, right?
       */
	Debug( LDAP_DEBUG_TRACE, 
	       "<= %s has no data in aliasedobjectname attribute\n", 
	       e->e_dn, 0, 0 );
	send_ldap_result( conn, op, LDAP_ALIAS_PROBLEM, "",
			  "Alias missing aliasedobjectname" );
    }
  }

  /*
   * warn if we pulled out due to exceeding the maximum deref depth
   */
  if ( depth >= be->be_maxDerefDepth ) {
    Debug( LDAP_DEBUG_TRACE, 
	   "<= %s exceeded maximum deref depth %d\n", 
	   e->e_dn, be->be_maxDerefDepth, 0 );
    send_ldap_result( conn, op, LDAP_ALIAS_PROBLEM, "",
			"Maximum alias dereference depth exceeded" );
  }

  return e;
}

/*
 * given a DN fully deref it and return the real DN or original DN if it fails
 */
char *derefDN ( Backend     *be,
                Connection  *conn,
                Operation   *op,
                char        *dn
)
{
  struct ldbminfo *li = (struct ldbminfo *) be->be_private;
115
  char 	*matched = 0;
116
  char 	*newDN = NULL;
117
  int	depth, i;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
118
119
120
121
122
123
  Entry 	*eMatched;
  Entry 	*eDeref;
  Entry         *eNew;
  

  Debug( LDAP_DEBUG_TRACE, 
124
	 "<= dereferencing dn: \"%s\"\n", 
Kurt Zeilenga's avatar
Kurt Zeilenga committed
125
126
	 dn, 0, 0 );
  
127
128
  newDN = ch_strdup ( dn );

Kurt Zeilenga's avatar
Kurt Zeilenga committed
129
130
131
132
133
134
  /* while we don't have a matched dn, deref the DN */
  for ( depth = 0;
	( (eMatched = dn2entry_r( be, newDN, &matched )) == NULL) &&
	  (depth < be->be_maxDerefDepth);
	++depth ) {
    
135
    if ((matched != NULL) && *matched) {	
Kurt Zeilenga's avatar
Kurt Zeilenga committed
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
      char *submatch;
      
      /* 
       * make sure there actually is an entry for the matched part 
       */
      if ( (eMatched = dn2entry_r( be, matched, &submatch )) != NULL) {
	char  *remainder; /* part before the aliased part */
	int  rlen = strlen(newDN) - strlen(matched);
	
	Debug( LDAP_DEBUG_TRACE, "<= matched %s\n", matched, 0, 0 );
	
	remainder = ch_malloc (rlen + 1);
	strncpy ( remainder, newDN, rlen );
	remainder[rlen]	= '\0';
	
	Debug( LDAP_DEBUG_TRACE, "<= remainder %s\n", remainder, 0, 0 );
	
	if ((eNew = derefAlias_r( be, conn, op, eMatched )) == NULL) {
	  free (matched);
155
	  matched = NULL;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
156
	  free (newDN);
157
	  newDN = NULL;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
158
	  free (remainder);
159
	  remainder = NULL;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
160
161
162
163
164
165
	  break; /*  no associated entry, dont deref */
	}
	else {

	  Debug( LDAP_DEBUG_TRACE, "<= l&g we have %s vs %s \n", matched, eNew->e_dn, 0 );

166
167
168
169
	  i = strcasecmp (matched, eNew->e_dn);
          /* free reader lock */
          cache_return_entry_r(&li->li_cache, eNew);
	  if (! i) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
170
171
	    /* newDN same as old so not an alias, no need to go further */
	    free (newDN);
172
	    newDN = NULL;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
173
	    free (matched);
174
	    matched = NULL;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
175
176
177
178
179
180
181
182
183
184
185
186
187
188
	    free (remainder);
	    break;
	  }

	  /* 
	   * we have dereferenced the aliased part so put
	   * the new dn together
	   */
	  free (newDN);
	  newDN = ch_malloc (strlen(eMatched->e_dn) + rlen + 1);
	  strcpy (newDN, remainder);
	  strcat (newDN, eMatched->e_dn);
	  Debug( LDAP_DEBUG_TRACE, "<= expanded to %s\n", newDN, 0, 0 );

189
190
	  free (matched);
	  matched = NULL;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
	  free (remainder);
	}
        /* free reader lock */
        cache_return_entry_r(&li->li_cache, eMatched);
      }
      else {
	if(submatch != NULL) free(submatch);
	break; /* there was no entry for the matched part */
      }
    }
    else {
      break; /* there was no matched part */
    }
  }
  
206
207
208
209
  if(eMatched != NULL) {
    /* free reader lock */
    cache_return_entry_r(&li->li_cache, eMatched);
  }
210

Kurt Zeilenga's avatar
Kurt Zeilenga committed
211
212
213
214
215
216
217
  /*
   * the final part of the DN might be an alias 
   * so try to dereference it.
   */
  if ( (eNew = dn2entry_r( be, newDN, &matched )) != NULL) {
    if ((eDeref = derefAlias_r( be, conn, op, eNew )) != NULL) {
      free (newDN);
218
      newDN = ch_strdup (eDeref->e_dn);
Kurt Zeilenga's avatar
Kurt Zeilenga committed
219
220
221
222
223
224
225
226
227
228
229
230
      /* free reader lock */
      cache_return_entry_r(&li->li_cache, eDeref);
    }
    /* free reader lock */
    cache_return_entry_r(&li->li_cache, eNew);
  }
  
  /*
   * warn if we exceeded the max depth as the resulting DN may not be dereferenced
   */
  if (depth >= be->be_maxDerefDepth) {
    Debug( LDAP_DEBUG_TRACE, 
231
	   "<= max deref depth exceeded in derefDN for \"%s\", result \"%s\"\n", 
Kurt Zeilenga's avatar
Kurt Zeilenga committed
232
233
234
235
	   dn, newDN, 0 );
    send_ldap_result( conn, op, LDAP_ALIAS_PROBLEM, "",
		      "Maximum alias dereference depth exceeded for base" );
  }
236
237

  if (newDN == NULL) {
238
    newDN = ch_strdup ( dn );
239
  }
Kurt Zeilenga's avatar
Kurt Zeilenga committed
240
  
241
  Debug( LDAP_DEBUG_TRACE, "<= returning deref DN of \"%s\"\n", newDN, 0, 0 ); 
242
  if (matched != NULL) free(matched);
Kurt Zeilenga's avatar
Kurt Zeilenga committed
243
244
245

  return newDN;
}