1 /*
2     ldapdiff
3     Copyright (C) 2000-2008 Thomas.Reith@rhoen.de
4 
5     This program is free software: you can redistribute it and/or modify
6     it under the terms of the GNU General Public License as published by
7     the Free Software Foundation, either version 3 of the License, or
8     (at your option) any later version.
9 
10     This program is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13     GNU General Public License for more details.
14 
15     You should have received a copy of the GNU General Public License
16     along with this program.  If not, see <http://www.gnu.org/licenses/>.
17 */
18 
19 #include <lber.h>
20 #include <ldap.h>
21 
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 
26 #include "ldapdiff.h"
27 
cmodentry(struct s_modentry ** smodentry,char * var,char * val,size_t val_len,teattrtype val_type,temodentry emodentry)28 static void cmodentry(struct s_modentry **smodentry,char *var,char *val,size_t val_len,teattrtype val_type,temodentry emodentry)
29 {
30  struct s_modentry *psmodentry;
31  struct s_modentry *ptsmodentry;
32  struct s_ldifval  *psmodentryval;
33  struct s_ldifval  *ptsmodentryval;
34 
35  if(var == NULL || val == NULL){
36   return;
37  }
38 
39  psmodentryval          = LDALLOC(1,sizeof(struct s_ldifval));
40  psmodentryval->val     = LDBINDUP(val,val_len);
41  psmodentryval->val_len = val_len;
42 
43  psmodentry = *smodentry;
44  while(psmodentry != NULL){
45   if(strcasecmp(psmodentry->var,var) == 0){
46    ptsmodentryval = psmodentry->vallist;
47    while(ptsmodentryval->next != NULL){
48     ptsmodentryval = ptsmodentryval->next;
49    }
50    ptsmodentryval->next = psmodentryval;
51    return;
52   }
53   psmodentry = psmodentry->next;
54  }
55 
56  ptsmodentry           = LDALLOC(1,sizeof(struct s_modentry));
57  ptsmodentry->var      = LDDUP(var);
58  ptsmodentry->vallist  = psmodentryval;
59  ptsmodentry->val_type = val_type;
60  ptsmodentry->modtype  = emodentry;
61 
62  if(*smodentry == NULL){
63   *smodentry = ptsmodentry;
64  }
65  else{
66   struct s_modentry *usmodentry;
67   usmodentry = *smodentry;
68   while(usmodentry != NULL){
69    if(usmodentry->next == NULL){
70     usmodentry->next = ptsmodentry;
71     return;
72    }
73    usmodentry = usmodentry->next;
74   }
75  }
76 }
77 
cmod(struct s_mod ** smod,char * dnvar,char * dnval,char * var,char * val,size_t val_len,teattrtype val_type,temod emod,temodentry emodentry)78 static void cmod(struct s_mod **smod,char *dnvar,char *dnval,char *var,char *val,size_t val_len,teattrtype val_type,temod emod,temodentry emodentry)
79 {
80  struct s_mod *psmod;
81  struct s_mod *ptsmod;
82 
83  psmod = *smod;
84  while(psmod != NULL){
85   if(strcmp(psmod->dnval,dnval) == 0 && psmod->modtype == emod){
86    cmodentry(&psmod->attrlist,var,val,val_len,val_type,emodentry);
87    return;
88   }
89   psmod = psmod->next;
90  }
91 
92  ptsmod          = LDALLOC(1,sizeof(struct s_mod));
93  ptsmod->dnvar   = LDDUP(dnvar);
94  ptsmod->dnval   = LDDUP(dnval);
95  ptsmod->modtype = emod;
96 
97  cmodentry(&ptsmod->attrlist,var,val,val_len,val_type,emodentry);
98  if(*smod == NULL){
99   *smod = ptsmod;
100  }
101  else{
102   struct s_mod *usmod;
103   usmod = *smod;
104   while(usmod != NULL){
105    if(usmod->next == NULL){
106     usmod->next = ptsmod;
107     return;
108    }
109    usmod = usmod->next;
110   }
111  }
112 }
113 
ldifcmp(LDAP * ld,struct s_ldif * sldif,struct s_ldif * sldap,struct s_mod ** smod,struct s_schema * sschema)114 void ldifcmp(LDAP *ld,struct s_ldif *sldif,struct s_ldif *sldap,struct s_mod **smod,struct s_schema *sschema)
115 {
116  struct s_ldifentry *psldifentry;
117  struct s_ldifentry *psldapentry;
118  struct s_ldifval   *psldifval;
119  struct s_ldifval   *psldapval;
120  int                 attr_found;
121  int                 attr_modifybydeladd = 0;
122 
123  psldifentry = sldif->attrlist;
124  while(psldifentry != NULL){
125   if(ldifcheckignore(psldifentry->var) == ATTRIGNORE){
126    ldiflog(LOG2,"ignore  attr: %s",sldif->dnval);
127    psldifval = psldifentry->vallist;
128    while(psldifval != NULL){
129     ldiflogval(LOG2,"              %s: %s",psldifentry->var,psldifval->val,psldifval->val_len);
130     psldifval = psldifval->next;
131    }
132   }
133   else{
134    attr_found  = 0;
135    psldapentry = sldap->attrlist;
136    while(psldapentry != NULL){
137     if(strcasecmp(psldifentry->var,psldapentry->var) == 0){
138      int ldifcount = 0;
139      int ldapcount = 0;
140 
141      attr_found  = 1;
142 
143      psldifval = psldifentry->vallist;
144      while(psldifval != NULL){
145       if(ldifcheckignoreval(psldifval->val) != ATTRIGNORE){
146        ldifcount++;
147       }
148       else{
149        ldiflog(LOG2,"ignore ldif attrval: %s",sldif->dnval);
150        ldiflog(LOG2,"ignore ldif attrval: %s",psldifval->val);
151       }
152       psldifval = psldifval->next;
153      }
154 
155      psldapval = psldapentry->vallist;
156      while(psldapval != NULL){
157       if(ldifcheckignoreval(psldapval->val) != ATTRIGNORE){
158        ldapcount++;
159       }
160       else{
161        ldiflog(LOG2,"ignore ldap attrval: %s",sldap->dnval);
162        ldiflog(LOG2,"ignore ldap attrval: %s",psldapval->val);
163       }
164       psldapval = psldapval->next;
165      }
166 
167      if(ldapcount == ldifcount){
168       ldapcount = 0;
169       psldifval = psldifentry->vallist;
170       while(psldifval != NULL){
171        psldapval = psldapentry->vallist;
172        while(psldapval != NULL){
173         if(psldifval->val_len == psldapval->val_len){
174          if(memcmp(psldifval->val,psldapval->val,psldifval->val_len) == 0){
175           ldapcount++;
176          }
177          else{
178           /*
179           compare objectClass values case insensitive
180           */
181           if(strcasecmp(psldapentry->var,OCNAME) == 0){
182            if(strncasecmp(psldifval->val,psldapval->val,psldifval->val_len) == 0){
183             ldapcount++;
184            }
185           }
186          }
187         }
188         psldapval = psldapval->next;
189        }
190        psldifval = psldifval->next;
191       }
192      }
193 
194      if(ldifcount != ldapcount){
195       /*
196       case 1: attribute is different in ldif file
197       */
198       ldiflog(LOG2,"replace attr: %s",sldif->dnval);
199       psldapval = psldapentry->vallist;
200       while(psldapval != NULL){
201        ldiflogval(LOG2,"              %s: %s ->",psldapentry->var,psldapval->val,psldapval->val_len);
202        psldapval = psldapval->next;
203       }
204       psldifval = psldifentry->vallist;
205       while(psldifval != NULL){
206        if(strcmp(ldifgetpconf(CONFMODIFYBYDELADD),"yes") != 0){
207         cmod(smod,sldif->dnvar,sldif->dnval,psldifentry->var,psldifval->val,psldifval->val_len,psldifentry->val_type,MODMODIFY,MODATTRREPLACE);
208        }
209        ldiflogval(LOG2,"              %s: %s",psldifentry->var,psldifval->val,psldifval->val_len);
210        attr_modifybydeladd = 1;
211        psldifval = psldifval->next;
212       }
213      }
214     }
215     psldapentry = psldapentry->next;
216    }
217 
218    if(attr_found == 0){
219     /*
220     case 2: attribute doesn't exist in ldap
221     */
222     psldifval = psldifentry->vallist;
223     while(psldifval != NULL){
224      if(strcmp(ldifgetpconf(CONFMODIFYBYDELADD),"yes") != 0){
225       cmod(smod,sldif->dnvar,sldif->dnval,psldifentry->var,psldifval->val,psldifval->val_len,psldifentry->val_type,MODMODIFY,MODATTRADD);
226      }
227      ldiflog(LOG2,"add     attr: %s",sldif->dnval);
228      ldiflogval(LOG2,"              %s: %s",psldifentry->var,psldifval->val,psldifval->val_len);
229      attr_modifybydeladd = 1;
230      psldifval = psldifval->next;
231     }
232    }
233   }
234   psldifentry = psldifentry->next;
235  }
236 
237  psldapentry = sldap->attrlist;
238  while(psldapentry != NULL){
239   if(ldifcheckignore(psldapentry->var) == ATTRIGNORE){
240    ldiflog(LOG2,"ignore  attr: %s",sldap->dnval);
241    psldapval = psldapentry->vallist;
242    while(psldapval != NULL){
243     ldiflogval(LOG2,"              %s: %s",psldapentry->var,psldapval->val,psldapval->val_len);
244     psldapval = psldapval->next;
245    }
246   }
247   else{
248    psldifentry = sldif->attrlist;
249    attr_found  = 0;
250    while(psldifentry != NULL){
251     if(strcasecmp(psldapentry->var,psldifentry->var) == 0){
252      attr_found++;
253     }
254     psldifentry = psldifentry->next;
255    }
256    if(attr_found == 0){
257     /*
258     case 3: attribute doesn't exist in ldif
259     */
260     if((strcmp(ldifgetpconf(CONFDELETEATTRIBUTE),"yes") == 0) ||
261        (strstr(ldifgetpconf(CONFDELETEATTRIBUTE), psldapentry->var) != NULL)){
262      psldapval = psldapentry->vallist;
263      while(psldapval != NULL){
264       if(strcmp(ldifgetpconf(CONFMODIFYBYDELADD),"yes") != 0){
265        cmod(smod,sldap->dnvar,sldap->dnval,psldapentry->var,psldapval->val,psldapval->val_len,psldapentry->val_type,MODMODIFY,MODATTRDELETE);
266       }
267       ldiflog(LOG2,"delete  attr: %s",sldap->dnval);
268       ldiflogval(LOG2,"              %s: %s",psldapentry->var,psldapval->val,psldapval->val_len);
269       attr_modifybydeladd = 1;
270       psldapval = psldapval->next;
271      }
272     }
273     else{
274      ldiflog(LOG2,"deletion disabled: %s",sldap->dnval);
275     }
276    }
277   }
278   psldapentry = psldapentry->next;
279  }
280 
281  /*
282  if there are any replacement attributes and "confmodbydelete: yes" in ldapdiff.conf,
283  every detected entry will be deleted and the entry from the ldif file will be added
284  */
285  if(attr_modifybydeladd == 1 && strcmp(ldifgetpconf(CONFMODIFYBYDELADD),"yes") == 0){
286   ldiflog(LOG2,"delete & add: %s",sldif->dnval);
287   ldifdeletedn(sldif->dnvar,sldif->dnval,smod);
288   ldifadddn(sldif,smod);
289  }
290 }
291 
ldifadddn(struct s_ldif * sldif,struct s_mod ** smod)292 void ldifadddn(struct s_ldif *sldif,struct s_mod **smod)
293 {
294  struct s_ldifentry *psldifentry;
295  struct s_ldifval   *psldifval;
296 
297  psldifentry = sldif->attrlist;
298  while(psldifentry != NULL){
299   if(ldifcheckignore(psldifentry->var) == ATTRIGNORE){
300    ldiflog(LOG2,"ignore  attr: %s",sldif->dnval);
301    psldifval = psldifentry->vallist;
302    while(psldifval != NULL){
303     ldiflogval(LOG2,"              %s: %s",psldifentry->var,psldifval->val,psldifval->val_len);
304     psldifval = psldifval->next;
305    }
306   }
307   else{
308    if(strcmp(ldifgetpconf(CONFADDENTRY),"yes") == 0){
309     psldifval = psldifentry->vallist;
310     while(psldifval != NULL){
311      cmod(smod,sldif->dnvar,sldif->dnval,psldifentry->var,psldifval->val,psldifval->val_len,psldifentry->val_type,MODADD,MODATTRADD);
312      ldiflog(LOG2,"add    entry: %s",sldif->dnval);
313      ldiflogval(LOG2,"              %s: %s",psldifentry->var,psldifval->val,psldifval->val_len);
314      psldifval = psldifval->next;
315     }
316    }
317    else{
318     ldiflog(LOG2,"addition disabled: %s", sldif->dnval);
319    }
320   }
321   psldifentry = psldifentry->next;
322  }
323 }
324 
ldifdeletedn(char * dnvar,char * dnval,struct s_mod ** smod)325 void ldifdeletedn(char *dnvar,char *dnval,struct s_mod **smod)
326 {
327  if(strcmp(ldifgetpconf(CONFDELETEENTRY),"yes") == 0){
328   cmod(smod,dnvar,dnval,NULL,NULL,0,0,MODDELETE,MODATTRDELETE);
329   ldiflog(LOG2,"del    entry: %s",dnval);
330  }
331  else{
332   ldiflog(LOG2,"deletion disabled: %s",dnval);
333  }
334 }
335 
ldifdnalreadyexist(LDAP * ld,char * dn)336 int ldifdnalreadyexist(LDAP *ld,char *dn)
337 {
338  int          cn;
339  int          rc;
340  LDAPMessage *lr = NULL;
341 
342 #ifndef USE_DEPRECATED_API
343  rc = ldap_search_ext_s(ld,dn,LDAP_SCOPE_BASE,"(objectClass=*)",NULL,0,NULL,NULL,NULL,LDAP_MAXINT,&lr);
344 
345  if(rc != LDAP_SUCCESS && rc != LDAP_NO_SUCH_OBJECT){
346   ldiflog(LOG0,"ldap_search_ext_s() failed: file: %s, line: %d",__FILE__,__LINE__);
347   ldiflog(LOG0,"ldap_err2string(): %s",ldap_err2string(rc));
348   exit(EXITLDERROR);
349  }
350 #else
351  rc = ldap_search_s(ld,dn,LDAP_SCOPE_BASE,"(objectClass=*)",NULL,0,&lr);
352 
353  if(rc != LDAP_SUCCESS && rc != LDAP_NO_SUCH_OBJECT){
354   ldiflog(LOG0,"ldap_search() failed: file: %s, line: %d",__FILE__,__LINE__);
355   ldiflog(LOG0,"ldap_err2string(): %s",ldap_err2string(rc));
356   exit(EXITLDERROR);
357  }
358 #endif
359 
360  if((cn = ldap_count_entries(ld,lr)) == -1){
361   ldiflog(LOG0,"ldap_count_entries() failed: file: %s, line: %d",__FILE__,__LINE__);
362   ldap_get_option(ld,LDAP_OPT_ERROR_NUMBER,&rc);
363   ldiflog(LOG0,"ldap_err2string(): %s",ldap_err2string(rc));
364   exit(EXITLDERROR);
365  }
366 
367  if(ldap_msgfree(lr) == -1){
368   ldiflog(LOG0,"ldap_msgfree() failed: file: %s, line: %d",__FILE__,__LINE__);
369   exit(EXITLDERROR);
370  }
371 
372  return cn;
373 }
374