/*
    ldapdiff
    Copyright (C) 2000-2006 Thomas.Reith@rhoen.de

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/

#include <lber.h>
#include <ldap.h>

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <errno.h>
#include <syslog.h>

#include "ldapdiff.h"

char *ldifnormalizedn(char *dn)
{
 LDAPDN ldn;
 char   *ndn;
 int rc;

 if((rc = ldap_str2dn(dn,&ldn,LDAP_DN_FORMAT_LDAPV3)) != LDAP_SUCCESS){
  ldiflog(LOG0,"error: invalid dn [%s]",dn);
  ldiflog(LOG0,"ldap_str2dn() failed: file: %s, line: %d",__FILE__,__LINE__);
  ldiflog(LOG0,"ldap_err2string(): %s",ldap_err2string(rc));
  exit(EXITLDERROR);
 }
 if((rc = ldap_dn2str(ldn,&ndn,LDAP_DN_FORMAT_LDAPV3)) != LDAP_SUCCESS){
  ldiflog(LOG0,"ldap_dn2str() failed: file: %s, line: %d",__FILE__,__LINE__);
  ldiflog(LOG0,"ldap_err2string(): %s",ldap_err2string(rc));
  exit(EXITLDERROR);
 }
 ldap_dnfree(ldn);

 if(strcasecmp(dn,ndn) != 0){
  ldiflog(LOG2,"warning: dn normalized [%s]->[%s]",dn,ndn);
 }
 return ndn;
}

int ldifcheckbase(char *attrbase)
{
 char *confbase;

 confbase = ldifnormalizedn(ldifgetpconf(CONFBASEDN));

 if(strlen(attrbase) < strlen(confbase)){
  return -1;
 }

 if(strcasecmp(attrbase+strlen(attrbase)-strlen(confbase),confbase) != 0){
  return -1;
 }
 free(confbase);

 return 0;
}

teignore ldifcheckignore(char *attribute)
{
 char     *cignore;
 char     *ctok;

 cignore = LDDUP(ldifgetpconf(CONFIGNORE));

 ctok = strtok(cignore,", \t");
 while(ctok != NULL){
  if(strcasecmp(ctok,attribute) == 0){
   free(cignore);
   return ATTRIGNORE;
  }
  ctok = strtok(NULL,", \t");
 }

 free(cignore);
 return ATTRCHECK;
}

teignore ldifcheckignoreval(char *value)
{
 char     *cignore;
 char     *ctok;

 cignore = LDDUP(ldifgetpconf(CONFIGNOREVAL));

 ctok = strtok(cignore,", \t");
 while(ctok != NULL){
  if(strcasecmp(ctok,value) == 0){
   free(cignore);
   return ATTRIGNORE;
  }
  ctok = strtok(NULL,", \t");
 }

 free(cignore);
 return ATTRCHECK;
}

int ldifchecknoequality(char *attribute)
{
 char     *cnoequality;
 char     *ctok;

 cnoequality = LDDUP(ldifgetpconf(CONFNOEQUALITY));

 ctok = strtok(cnoequality,", \t");
 while(ctok != NULL){
  if(strcasecmp(ctok,attribute) == 0){
   free(cnoequality);
   return 0;
  }
  ctok = strtok(NULL,", \t");
 }

 free(cnoequality);
ldiflog(LOG0,"hossa %s",attribute);
 return 1;
}

char *ldifcheckalias(char *attribute)
{
 char     *calias;
 char     *ctok;

 static char     realstatic[MAXATTRLEN];

 calias = LDDUP(ldifgetpconf(CONFMAPALIAS));
 ctok = strtok(calias,",");
 while(ctok != NULL){
  char *alias;
  char *real;
  if((real = strchr(ctok,'=')) == NULL){
   ldiflog(LOG0,"ldifcheckalias() failed: file %s line %d",__FILE__,__LINE__);
   exit(EXITLDERROR);
  }
  *real = '\0';
  real++;
  alias = ctok;

  ldiftrim(alias);
  ldiftrim(real);
  if(strlen(real) == 0 || strlen(alias) == 0){
   ldiflog(LOG0,"ldifcheckalias() failed: file %s line %d",__FILE__,__LINE__);
   exit(EXITLDERROR);
  }

  if(strcasecmp(attribute,alias) == 0){
   ldiflog(LOG2,"attribute %s mapped to %s",attribute,real);
   sprintf(realstatic,"%s",real);
   free(calias);
   return realstatic;
  }

  ctok = strtok(NULL,",");
 }
 free(calias);
 return attribute;
}

void ldifaddentry(struct s_ldif *sldif,char *var,char *val,size_t val_len,teattrtype val_type)
{
 struct s_ldifentry *psldifentry;
 struct s_ldifval   *psldifval;
 struct s_ldifval   *tsldifval;

 if(sldif == NULL){
  /* this should never happen */
  ldiflog(LOG0,"fatal error: file %s line %d",__FILE__,__LINE__);
  exit(EXITLDERROR);
 }

 psldifval           = LDALLOC(1,sizeof(struct s_ldifval));
 psldifval->val      = LDBINDUP(val,val_len);
 psldifval->val_len  = val_len;

 psldifentry = sldif->attrlist;
 while(psldifentry != NULL){
  if(strcasecmp(psldifentry->var,var) == 0){
   tsldifval = psldifentry->vallist;
   while(tsldifval->next != NULL){
    tsldifval = tsldifval->next;
   }
   tsldifval->next = psldifval;
   return;
  }
  psldifentry = psldifentry->next;
 }

 psldifentry           = LDALLOC(1,sizeof(struct s_ldifentry));
 psldifentry->var      = LDDUP(var);
 psldifentry->vallist  = psldifval;
 psldifentry->val_type = val_type;
 
 if(sldif->attrlist == NULL){
  sldif->attrlist = psldifentry;
 }
 else{
  struct s_ldifentry *tsldifentry;

  tsldifentry = sldif->attrlist;
  while(tsldifentry->next != NULL){
   tsldifentry = tsldifentry->next;
  }
  tsldifentry->next = psldifentry;
 }
}

struct s_ldif* ldifadd(struct s_ldif** sldif,char *dnvar,char* dnval)
{
 struct s_ldif *psldif; 

 psldif        = LDALLOC(1,sizeof(struct s_ldif));
 psldif->dnvar = LDDUP(dnvar);
 psldif->dnval = LDDUP(dnval);

 if(*sldif == NULL){
  *sldif = psldif;
 }
 else{
  struct s_ldif *tsldif; 

  tsldif = *sldif;
  while(tsldif->next != NULL){
   tsldif = tsldif->next;
  }
  tsldif->next = psldif;
 }
 return psldif;
}

void ldiffree(struct s_ldif** sldif)
{
 struct s_ldif *psldif;
 struct s_ldif *tpsldif;

 psldif = *sldif;
 while(psldif != NULL){
  struct s_ldifentry *psldifentry;
  struct s_ldifentry *tpsldifentry;

  psldifentry = psldif->attrlist;
  while(psldifentry != NULL){
   struct s_ldifval *psldifval;
   struct s_ldifval *tpsldifval;

   psldifval = psldifentry->vallist;
   while(psldifval != NULL){
    free(psldifval->val);

    tpsldifval = psldifval;
    psldifval = psldifval->next;
    free(tpsldifval); 
   }

   free(psldifentry->var);

   tpsldifentry = psldifentry;
   psldifentry = psldifentry->next;
   free(tpsldifentry);
  }

  free(psldif->dnvar);
  free(psldif->dnval);

  tpsldif = psldif;
  psldif = psldif->next;
  free(tpsldif);
 }

 *sldif = NULL;
}

int ldifgetfilter(struct s_ldifentry *sldifentry,char *filter)
{
 struct s_ldifentry *psldifentry;
 struct s_ldifval   *psldifval;
 char *cfilter;
 char *cgroup;
 char *ctok;

 cfilter = LDDUP(ldifgetpconf(CONFFILTER));
 cgroup  = LDDUP(ldifgetpconf(CONFGROUP));
 
 ctok = strtok(cfilter,",");
 while(ctok != NULL){

  psldifentry = sldifentry;
  while(psldifentry != NULL){
   if(strcasecmp(ctok,psldifentry->var) == 0){ 
    int   count;

    if(psldifentry->val_type == ATTRBIN){
     ldiflog(LOG0,"error: filter attribute [%s] is binary",ctok);
     exit(EXITLDERROR);
    }
    
    count = 0;
    psldifval = psldifentry->vallist;
    while(psldifval != NULL){
     char *cval;
     cval = LDALLOC(psldifval->val_len+1,sizeof(char));
     strncpy(cval,psldifval->val,psldifval->val_len);
     sprintf(filter,"(&(%s)(%s=%s))",cgroup,ctok,cval);
     free(cval);
     count++;
     psldifval = psldifval->next;
    }

    if(count > 1){
     ldiflog(LOG0,"error: filter attribute [%s] not single valued",ctok);
     exit(EXITLDERROR);
    }

    free(cgroup);
    free(cfilter);
    return 0; 
   }
   psldifentry = psldifentry->next;
  }
  ctok = strtok(NULL,",");
 }
 free(cfilter);
 return -1;
}

void *ldifalloc(size_t nelem,size_t elsize,char* file,int line)
{
 void *p;
 if((p = calloc(nelem,elsize)) == NULL){
  ldiflog(LOG0,"calloc() failed file:%s line:%d %s",file,line,strerror(errno));
  exit(EXITLDERROR);
 }
 return(p);
}

char *ldifdup(char* s,char* file,int line)
{
 char *p;
 if((p = strdup(s)) == NULL){
  ldiflog(LOG0,"strdup() failed file:%s line:%d %s",file,line,strerror(errno));
  exit(EXITLDERROR);
 }
 return(p);
}

char *ldifbindup(char* s,size_t len,char *file,int line)
{
 char *p;

 if((p = calloc(len,sizeof(char))) == NULL){
  ldiflog(LOG0,"calloc() failed file:%s line:%d %s",file,line,strerror(errno));
  exit(EXITLDERROR);
 }
 return (char*)memcpy(p,s,len);
}

int ldifconfnormalize(char *s,char *var,char *val)
{
 char *valtmp;

 if((valtmp = strchr(s,':')) == NULL){
  return -1;
 }
 strncpy(var,s,valtmp - s);
 var[valtmp - s] = '\0';
 ldiftrim(var);

 strcpy(val,valtmp+1);
 ldiftrim(val);

 if(var[0] == '\0' || val[0] == '\0'){
  return -1;
 }
 return 0;
}

void ldiftrim(char *s)
{
 int   c1 = 0;
 int   c2 = 0;
 int   f  = 0;

 if(s == NULL){
  return;
 }

 while(s[c1] != 0){
  if((s[c1] != ' ' && s[c1] != '\t') || f == 1){
   s[c2] = s[c1];
   f = 1;
   c2++;
  }
  c1++;
 }
 s[c2] = 0;

 c1 = strlen(s) - 1;
 while(c1 >= 0){
  if(s[c1] == ' ' || s[c1] == '\t'){
   s[c1] = 0;
  }
  else{
   break;
  }
  c1--;
 }
}

int ldifgetfacility(char *facility)
{
 struct s_syslogcodes {
  char    *c_name;
  int      c_val;
 } syslogcodes[] = {
 { "local0", LOG_LOCAL0 },
 { "local1", LOG_LOCAL1 },
 { "local2", LOG_LOCAL2 },
 { "local3", LOG_LOCAL3 },
 { "local4", LOG_LOCAL4 },
 { "local5", LOG_LOCAL5 },
 { "local6", LOG_LOCAL6 },
 { "local7", LOG_LOCAL7 },
 { NULL, -1 }};

 int count = 0; 
 while(syslogcodes[count].c_name != NULL){
  if(strcmp(facility,syslogcodes[count].c_name) == 0){
   return syslogcodes[count].c_val;
  }
  count++;
 }
 return -1;
}


syntax highlighted by Code2HTML, v. 0.9.1