#include <stdlib.h> #include <gdbm.h> #include <time.h> #include <errno.h> #include <sys/types.h> #include <sys/stat.h> #include <unistd.h> #include <stdio.h> #include <string.h> #include <ldap.h> #include <lber.h> #include <conf.h> #include "config.h" #include "util.h" #include "dbaccess.h" #include "mailhandler.h" #ifndef __LCLINT__ #include <syslog.h> #endif extern struct conf cfg; extern char* sender; extern char** receivers; extern char* subject; extern int verbose; /** * Cache for file pointed to by cfg.mailheader */ char* header=NULL; /** * Cache for file pointed to by cfg.mailfooter */ char* footer=NULL; /** * Persistant connection to the LDAP server */ LDAP *ldcon; void dbCacheHF(void) { if (header!=NULL || footer!=NULL) return; if (cfg.mailheader!=NULL) { header=readFile(cfg.mailheader); } if (cfg.mailfooter!=NULL) { footer=readFile(cfg.mailfooter); } if (header==NULL) header=""; if (footer==NULL) footer=""; } int dbCheck( char* she, char* me) { GDBM_FILE dbf=NULL; char *fname=NULL; datum data; datum key; time_t t; // Skip the whole hassle, if the admin feels lucky if (cfg.dbexp==0) return TRUE; fname=(char*)calloc(strlen(me)+strlen(cfg.dbdir)+5,sizeof(char)); if (fname==NULL) oom(); strcpy(fname,cfg.dbdir); if (fname[strlen(fname)-1]!='/') fname[strlen(fname)]='/'; strcat(fname,me); dbf=dbOpen(fname,GDBM_READER); if (dbf==NULL) dbf=dbOpen(fname,GDBM_WRCREAT); if (dbf==NULL) { syslog(LOG_MAIL|LOG_WARNING,"CRIT/IO %s",fname); exit(EXIT_FAILURE); } key.dptr=she; key.dsize=(int)strlen(she)+1; data=gdbm_fetch(dbf,key); if (data.dptr==NULL) { gdbm_close(dbf); free(fname); return TRUE; } gdbm_close(dbf); memcpy(&t,data.dptr,sizeof(t)); free(data.dptr); free(fname); if (time(NULL)-t>TIMEFACTOR*cfg.dbexp) return TRUE; return FALSE; } void dbLock( char* he, char* me) { GDBM_FILE dbf; char *fname; datum key; datum data; time_t ret; // Skip the whole hassle, if the admin feels lucky if (cfg.dbexp==0) return; fname=(char*)calloc(strlen(me)+strlen(cfg.dbdir)+5,sizeof(char)); if (fname==NULL) oom(); strcpy(fname,cfg.dbdir); if (fname[strlen(fname)-1]!='/') fname[strlen(fname)]='/'; strcat(fname,me); dbf=gdbm_open(fname,0,GDBM_WRITER,cfg.umask,NULL); if (dbf==NULL) { syslog(LOG_MAIL|LOG_WARNING,"CRIT/IO %s",fname); exit(EXIT_FAILURE); } key.dptr=he; key.dsize=strlen(he)+1; ret=time(NULL); data.dptr=(char*)malloc(sizeof(ret)); if (data.dptr==NULL) oom(); memcpy(data.dptr,&ret,sizeof(ret)); data.dsize=(int)sizeof(ret); free(fname); if (gdbm_store(dbf,key,data,GDBM_REPLACE)!=0) { gdbm_close(dbf); syslog(LOG_MAIL|LOG_WARNING,"CRIT/IO %s",me); exit (EXIT_FAILURE); } gdbm_close(dbf); } GDBM_FILE dbOpen( char* fname, int mode) { GDBM_FILE dbf; int retrycount=0; struct stat fs; if (fname==NULL) return NULL; if ( (mode==GDBM_READER) && (stat(fname,&fs)==-1) ) return NULL; do { dbf=gdbm_open(fname,0,mode,cfg.umask,NULL); if (dbf!=NULL) break; retrycount++; sleep(1+(int) (10.0*rand()/(RAND_MAX+1.0))); } while ((errno == EAGAIN) && (retrycount<=10)); return dbf; } void dbClose(GDBM_FILE dbf_ptr) { if (dbf_ptr==NULL) return; gdbm_close(dbf_ptr); dbf_ptr=NULL; } int dbContains(const char* str_ptr, GDBM_FILE dbf_ptr) { datum key; if ((str_ptr==NULL) || (dbf_ptr==NULL)) return FALSE; key.dptr=(char*)str_ptr; key.dsize=(int)strlen(key.dptr)+1; if (gdbm_exists(dbf_ptr,key)) return TRUE; return FALSE; } void dbConnect() { int rc; ldcon=ldap_init(cfg.server,cfg.port); if (ldcon==NULL) { syslog(LOG_MAIL|LOG_ERR,"CRIT/LDAP Connection failed"); exit(EXIT_FAILURE); } #ifdef HAVE_LDAP_SET_OPTION if (cfg.protver==LDAP_PROTOCOL_DETECT) { int prot=LDAP_VERSION2; ldap_set_option(ldcon,LDAP_OPT_PROTOCOL_VERSION, &prot); if (ldap_simple_bind_s(ldcon,cfg.uid,cfg.pwd)==LDAP_SUCCESS) return; prot=LDAP_VERSION3; ldap_set_option(ldcon,LDAP_OPT_PROTOCOL_VERSION, &prot); if (ldap_simple_bind_s(ldcon,cfg.uid,cfg.pwd)==LDAP_SUCCESS) return; } else ldap_set_option(ldcon,LDAP_OPT_PROTOCOL_VERSION, &cfg.protver); #endif rc=ldap_simple_bind_s(ldcon,cfg.uid,cfg.pwd); if (rc!=LDAP_SUCCESS) { syslog(LOG_MAIL|LOG_ERR,"CRIT/LDAP %s",ldap_err2string(rc)); exit(EXIT_FAILURE); } } void dbDisconnect() { if (header!=NULL) { free(header); header=NULL;} if (footer!=NULL) { free(footer); footer=NULL;} ldap_unbind(ldcon); } char** dbQuery(const char* mail) { LDAPMessage *res; struct timeval maxwait; char *tmp=NULL; char **entry; char **retbuf; int i; maxwait.tv_sec=LDAPQUERY_MAXWAIT; maxwait.tv_usec=0; cpyStr(&tmp,cfg.qfilter); expandVars(&tmp,cfg.map_receiver,(char*)mail); expandVars(&tmp,cfg.map_sender,sender); i=ldap_search_st(ldcon,cfg.base,cfg.scope,tmp,cfg.macro_attr,0,&maxwait,&res); if (i!=LDAP_SUCCESS) { if (verbose>=LVL_WARN) { syslog(LOG_MAIL|LOG_WARNING,"WARN/LDAP Wrong query base?"); } retbuf=(char**)calloc(1,sizeof(char**)); if (retbuf==NULL) oom(); return retbuf; } i=ldap_count_entries(ldcon,res); retbuf=(char**)calloc(i+1,sizeof(char**)); if (retbuf==NULL) oom(); if (i==0){ if (verbose>=LVL_DEBUG) syslog(LOG_MAIL|LOG_DEBUG,"DEBUG/LDAP No match: %s",tmp); return retbuf; } free(tmp); tmp=NULL; dbCacheHF(); res=ldap_first_entry(ldcon,res); if (res==NULL) return retbuf; i=0; while(res!=NULL) { int count=0; char **attr; entry=ldap_get_values(ldcon,res,cfg.result); if (entry!=NULL && entry[0]!=NULL) { retbuf[i]=(char*)malloc((strlen(header)+strlen(footer)+strlen(entry[0])+5)*sizeof(char)); if (retbuf[i]==NULL) oom(); retbuf[i][0]=(char)NULL; strcat(retbuf[i],header); strcat(retbuf[i],entry[0]); strcat(retbuf[i],footer); expandVars(&retbuf[i],cfg.map_subject,subject); expandVars(&retbuf[i],cfg.map_sender,sender); expandVars(&retbuf[i],cfg.map_receiver,(char*)mail); while(cfg.macro_name[count]!=NULL) { attr=ldap_get_values(ldcon,res,cfg.macro_attr[count]); if (attr!=NULL && attr[0]!=NULL) { expandVars(&retbuf[i],cfg.macro_name[count],attr[0]); ldap_value_free(attr); } else expandVars(&retbuf[i],cfg.macro_name[count],""); count++; } ldap_value_free(entry); i++; } res=ldap_next_entry(ldcon,res); } return retbuf; }