#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <ldap.h>
#include <sys/time.h>
#include <sys/stat.h>
#include <dirent.h>
#include "ad_func.h"
#include "create_alias_files.h"
int sgs_debug_level=0;
char *
addto_w_newline(char *addto, char *addfrom)
{
int x=0, y=0;
if(addto==NULL)
{
addto=malloc(strlen(addfrom)+3);
if(addto==NULL) return addto;
addto[0]='\0';
}else{
addto=realloc(addto, strlen(addto)+strlen(addfrom)+3);
}
for(;addto[x]!='\0';x++) continue;
if(addto[x]=='\0')
{
for(;addfrom[y]!='\0';) addto[x++]=addfrom[y++];
/*addto[x++]='\r';*/
addto[x++]='\n';
addto[x]='\0';
}
return addto;
}
void
ad_repair_escapechars(char *ob)
{
int before=0, after=0, escnum;
char temp[3];
temp[0]='\0'; temp[1]='\0'; temp[2]='\0';
for(;ob[before]!='\0';before++)
{
if(ob[before]=='\\')
{
if(ob[before+1]!='\0' && ob[before+2]!='\0')
{
temp[0]=ob[before+1]; temp[1]=ob[before+2];
escnum=strtol(temp, NULL, 16);
switch(escnum)
{
case 34: /* " */
case 43: /* + */
case 44: /* , */
case 59: /* ; */
case 60: /* < */
case 62: /* > */
/* The backslash is accepted as escaped hex so do not change it */
/*case 92: */ /* \ */
ob[after++]=(char)escnum;
before+=2;
continue;
break;
default:
break;
}
}
}
ob[after++]=ob[before];
}
ob[after]='\0';
}
void
ad_separate_userdnparts(char **parts, char *user, char *rest)
{
int x;
user[0]='\0'; rest[0]='\0';
strncpy(user, parts[0], CHAR_MAX);
ad_repair_escapechars(user);
strncpy(rest, parts[1], CHAR_MAX);
for(x=2;parts[x]!=NULL && x<100;x++)
sprintf(rest, "%s,%s", rest, parts[x]);
}
char *
ad_getmailaddress(LDAP *ad_conn, const char *base, const char *filter)
{
LDAPMessage *msg, *sub_entry;
char *attr_mail[]= {AD_MAIL_FIELD, (char *)0};
struct timeval timeout;
char **t, *member;
timeout.tv_sec = AD_TIMEOUT_SEC; timeout.tv_usec = 0;
if(ldap_search_st(ad_conn, base, LDAP_SCOPE_SUBTREE, filter, attr_mail, 0, &timeout, &msg)!=LDAP_SUCCESS)
{
if(sgs_debug_level>=3) printf("LDAP could not complete group member email address search for filter: %s\n", filter);
return NULL;
}
if(ldap_count_entries(ad_conn, msg)!=1)
{
if(sgs_debug_level>=3) printf("LDAP could not identify single member: %s\n", filter);
return NULL;
}
if((sub_entry=ldap_first_entry(ad_conn, msg))==NULL)
{
if(sgs_debug_level>=3) printf("Could not retrieve group member %s result entry\n", filter);
return NULL;
}
if((t=ldap_get_values(ad_conn, sub_entry, AD_MAIL_FIELD))==NULL)
{
if(sgs_debug_level>=3) printf("LDAP returned null for the alias member email address for %s\n", filter);
return NULL;
}
if(ldap_count_values(t)<1)
{
if(sgs_debug_level>=3) printf("LDAP returned zero entries for the alias member email address for %s\n", filter);
return NULL;
}
strtok(t[0],"@");
if(strlen(t[0])>=CHAR_MAX)
{
if(sgs_debug_level>=1) printf("LDAP returned an email address that exceeded %d: %s\n", CHAR_MAX, t[0]);
return NULL;
}
member=malloc(strlen(t[0])+1);
strcpy(member, t[0]);
ldap_value_free(t);
return member;
}
char *
ad_getgroupmembers(LDAP *ld, const char *base, const char *site, const char *group, char *email)
{
LDAPMessage *msg, *sub_entry=NULL;
struct timeval timeout;
char filter[CHAR_MAX], tbase[CHAR_MAX], tempuser[CHAR_MAX], temprestofdn[CHAR_MAX];
char *attr_member[]= {AD_MAIL_FIELD, AD_MEMBER_FIELD, (char *)0};
char **tempm, **dnparts, *tmem, *members=NULL;
int m;
#ifdef CONNECT_TO_LOCAL_LDAP_SERVERS
LDAP *tld;
int x=0, y=0, start=0;
LDAPMessage *tmsg, *t_entry=NULL;
char tdomain[CHAR_MAX];
ad_defs *ad;
#endif
timeout.tv_sec = AD_TIMEOUT_SEC; timeout.tv_usec = 0;
if(strlen(group)+4>CHAR_MAX)
{
if(sgs_debug_level>=2) printf("ad_getgroupmembers: Group filter string out of bounds error: group=%s\n", group);
return NULL;
}
sprintf(filter, "(&(objectClass=Group)(cn=%s))", group);
if(strlen(base)+strlen(site)+5>CHAR_MAX)
{
if(sgs_debug_level>=2) printf("ad_getgroupmembers: Site specific base string out of bounds error: site=%s\n", site);
return NULL;
}
if(site[0]=='\0') strcpy(tbase, base);
else sprintf(tbase, "dc=%s,%s", site, base);
if(ldap_search_st(ld, tbase, LDAP_SCOPE_SUBTREE, filter, attr_member, 0, &timeout, &msg)!=LDAP_SUCCESS)
{
if(sgs_debug_level>=2) printf("LDAP could not complete group member search for site: %s, group: %s\n", site, group);
return NULL;
}
if(ldap_count_entries(ld, msg)<1)
{
if(sgs_debug_level>=2) printf("LDAP could find no match for the filter: %s\n", filter);
return NULL;
}
if((sub_entry=ldap_first_entry(ld, msg))==NULL)
{
if(sgs_debug_level>=3) printf("Could not retrieve result entry for site: %s, group: %s\n", site, group);
return NULL;
}
if((tempm=ldap_get_values(ld, sub_entry, AD_MAIL_FIELD))==NULL)
{
if(sgs_debug_level>=1) printf("LDAP returned null for the email for group %s\n", group);
return NULL;
}
strtok(tempm[0],"@");
if(strlen(tempm[0])>=CHAR_MAX)
{
if(sgs_debug_level>=1) printf("LDAP returned an email address that exceeded %d for group %s: %s\n", CHAR_MAX, group, tempm[0]);
return NULL;
}
strcpy(email, tempm[0]);
ldap_value_free(tempm);
if((tempm=ldap_get_values(ld, sub_entry, AD_MEMBER_FIELD))==NULL)
{
#ifdef CONNECT_TO_LOCAL_LDAP_SERVERS
/*connect here to the local ldap server and retrieve the necessary entry data*/
ad=get_ad_defaults();
if(!ad->is_complete){
if(sgs_debug_level>=0) printf("Could not retrieve active directory connection defaults\n");
return NULL;
}
for(x=0;tbase[x]!='\0';x++)
{
if(tbase[x]=='=') { start=1; x++; }
if(tbase[x]==',') { start=0; tdomain[y++]='.'; }
if(start) tdomain[y++]=tbase[x];
if(y>=CHAR_MAX) { tdomain[y]='\0'; break; }
}
tdomain[y]='\0';
if(sgs_debug_level>=2) printf("Initializing connection to %s\n", tdomain);
if((tld=ad_init(tdomain, 0, 0))==0)
{
if(sgs_debug_level>=0) printf("Could not initialize connection to active directory domain: %s\n", tdomain);
return NULL;
}
if(ad_bind(tld, ad->general_user, ad->general_pw)!=AD_SUCCESS)
{
ad_close(tld);
if(sgs_debug_level>=0) printf("Could not bind to active directory with user: %s\n", ad->general_user);
return NULL;
}
if(ldap_search_st(tld, tbase, LDAP_SCOPE_SUBTREE, filter, attr_member, 0, &timeout, &tmsg)!=LDAP_SUCCESS)
{
if(sgs_debug_level>=2) printf("LDAP could not complete group member search in domain: %s, for site: %s, group: %s\n", tdomain, site, group);
ad_close(tld);
return NULL;
}
if(ldap_count_entries(tld, tmsg)!=1)
{
if(sgs_debug_level>=2) printf("LDAP could find no match for the filter: %s, in domain: %s\n", filter, tdomain);
ad_close(tld);
return NULL;
}
if((t_entry=ldap_first_entry(tld, tmsg))==NULL)
{
if(sgs_debug_level>=3) printf("Could not retrieve result entry for domain: %s, site: %s, group: %s\n", tdomain, site, group);
ad_close(tld);
return NULL;
}
if((tempm=ldap_get_values(tld, t_entry, AD_MEMBER_FIELD))==NULL){
if(sgs_debug_level>=2) printf("LDAP returned null for the group members of domain: %s, %s, %s\n", tdomain, site, group);
ad_close(tld);
return NULL;
}
#endif
}
for(m=0;m<ldap_count_values(tempm);m++)
{
if(strlen(tempm[m])>=CHAR_MAX)
{
if(sgs_debug_level>=3) printf("LDAP returned a user dn that exceeded %d: %s\n", CHAR_MAX, tempm[m]);
continue;
}
/*separate and escape special characters with \hex equivalent*/
dnparts=ldap_explode_dn(tempm[m], 0);
/*form up the two parts, user and rest, escaping the special characters back to normal for AD*/
ad_separate_userdnparts(dnparts, tempuser, temprestofdn);
if(sgs_debug_level>=3) printf("Attempting to retrieve email address for %s (Escaped dn: %s,%s)\n", tempm[m], tempuser, temprestofdn);
tmem=ad_getmailaddress(ld, temprestofdn, tempuser);
if(tmem==NULL)
{
if(sgs_debug_level>=3) printf("Could not retrieve email address...\n");
continue;
}
if(sgs_debug_level>=3) printf("Email address added to list: %s\n", tmem);
members=addto_w_newline(members, tmem);
free(tmem);
ldap_value_free(dnparts);
}
ldap_value_free(tempm);
if(members==NULL) if(sgs_debug_level>=2) printf("Could not retrieve any members for %s, %s\n", site, group);
return members;
}
int
ad_create_alias_file(LDAP *ld, const char *base, const char *site, const char *group)
{
char filename[CHAR_MAX];
char *members;
char email[CHAR_MAX];
int fd;
if((members=ad_getgroupmembers(ld, base, site, group, email))==NULL)
{
if(sgs_debug_level>=1) printf("Could not properly recover members for %s, %s\n", site, group);
return AD_ERROR;
}
sprintf(filename, "%s/%s%s", ALIAS_DIR_HEADER, ALIAS_FILE_HEADER, email);
if(sgs_debug_level>=3) printf("File to create: %s\n", filename);
if((fd=open(TEMPFILENAME, O_CREAT|O_TRUNC|O_WRONLY, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH))==-1)
{
if(sgs_debug_level>=1) printf("Could not open temp file, %s, for writing\n", TEMPFILENAME);
return AD_ERROR;
}
if(write(fd, members, strlen(members))!=strlen(members))
{
if(sgs_debug_level>=1) printf("Could not write all group member names to: %s\n", filename);
close(fd);
return AD_ERROR;
}
close(fd);
free(members);
if(rename(TEMPFILENAME, filename)==-1)
{
if(sgs_debug_level>=1) printf("Could not move file to %s\n", filename);
return AD_ERROR;
}
if(sgs_debug_level>=1) printf("Alias file successfully created in: %s\n", filename);
return AD_SUCCESS;
}
int
ad_get_ldapdncount(char **dn)
{
int x=0;
for(;x<100;x++) if(dn[x]==NULL) return x;
return 0;
}
sitegroup *
ad_get_sitegroups(LDAP *ld, const char *base, const char *site, const char *group, int *num_sgs)
{
LDAPMessage *msg, *sub_entry=NULL;
char filter[CHAR_MAX];
char tsite[CHAR_MAX];
char *attr_cn[]= {AD_CN_FIELD, (char *)0};
struct timeval timeout;
char **tempm, *tmem;
int entry_count, s, m, base_count, sub_entry_count;
static sitegroup sgs[MAX_SITEGROUPS];
*num_sgs=0;
timeout.tv_sec = AD_TIMEOUT_SEC; timeout.tv_usec = 0;
strcpy(filter, "(&(objectClass=Group)(mail=*))");
if(ldap_search_st(ld, base, LDAP_SCOPE_SUBTREE, filter, attr_cn, 0, &timeout, &msg)!=LDAP_SUCCESS)
{
if(sgs_debug_level>=1) printf("LDAP could not complete group member search\n");
return NULL;
}
if((entry_count=ldap_count_entries(ld, msg))<1)
{
if(sgs_debug_level>=1) printf("LDAP could find no match for the filter: %s\n", filter);
return NULL;
}
if(sgs_debug_level>=2) printf("LDAP search for site, %s, has recovered %d entries\n", site, entry_count);
/*each entry is for each subdomain the dn was found in*/
/*get the component part count from the base*/
tempm=ldap_explode_dn(base,1);
base_count=ad_get_ldapdncount(tempm);
ldap_value_free(tempm);
for(s=0;s<entry_count;s++)
{
if((sub_entry=(s==0?ldap_first_entry(ld, msg):ldap_next_entry(ld, sub_entry)))==NULL)
{
if(sgs_debug_level>=1) printf("Could not retrieve result entry %d\n", s);
continue;
}
tmem=ldap_get_dn(ld, sub_entry);
tempm=ldap_explode_dn(tmem,1);
sub_entry_count=ad_get_ldapdncount(tempm)-base_count-1;
if(sub_entry_count>0 && strcasecmp(AD_USERS_CONTAINER_STRING, tempm[sub_entry_count])!=0)
{
if(site!=NULL && strcasecmp(site, tempm[sub_entry_count])!=0)
{
if(sgs_debug_level>=3) printf("Entry does not match requested site %s: %s\n", site, tempm[sub_entry_count]);
free(tmem);
ldap_value_free(tempm);
continue;
}
if(strlen(tempm[sub_entry_count])>=CHAR_MAX)
{
if(sgs_debug_level>=1) printf("LDAP returned a site name that exceeded %d: %s\n", CHAR_MAX, tempm[sub_entry_count]);
continue;
}
strcpy(tsite, tempm[sub_entry_count]);
}
else
{
tsite[0]='\0';
if(sgs_debug_level>=3) printf("LDAP returned null for the site name for entry %d\n", s);
}
if((tempm=ldap_get_values(ld, sub_entry, AD_CN_FIELD))==NULL)
{
if(sgs_debug_level>=1) printf("LDAP returned null for the group name for entry %d\n", s);
continue;
}
for(m=0;m<ldap_count_values(tempm);m++)
{
if(strlen(tempm[m])>=CHAR_MAX)
{
if(sgs_debug_level>=1) printf("LDAP returned a group name that exceeded %d: %s\n", CHAR_MAX, tempm[m]);
continue;
}
if(group==NULL || strcasecmp(group, tempm[m])==0)
{
sgs[*num_sgs].site=malloc(strlen(tsite)+1);
strcpy(sgs[*num_sgs].site,tsite);
sgs[*num_sgs].group=malloc(strlen(tempm[m])+1);
strcpy(sgs[(*num_sgs)++].group,tempm[m]);
if(sgs_debug_level>=3) printf("Site: %s, Group: %s has been added to the search list\n", sgs[*num_sgs-1].site, sgs[*num_sgs-1].group);
if(*num_sgs>=MAX_SITEGROUPS)
{
if(sgs_debug_level>=1) printf("ad_get_sitegroups has reached max sitegroups: %d\n", MAX_SITEGROUPS);
ldap_value_free(tempm);
return sgs;
}
}else{
if(sgs_debug_level>=3) printf("Entry does not match requested group %s: %s\n", group, tempm[m]);
continue;
}
}
ldap_value_free(tempm);
}
return sgs;
}
int
ad_create_aliases(const char *site, const char *group)
{
LDAP * ld;
sitegroup *sgs;
int x, num_sgs;
ad_defs *ad=get_ad_defaults();
if(!ad->is_complete){
if(sgs_debug_level>=0) printf("Could not retrieve active directory connection defaults\n");
return AD_ERROR;
}
if((ld=ad_init(ad->server, AD_USE_GC, AD_ONLY_USE_SSL))==0)
{
if(sgs_debug_level>=0) printf("Could not initialize connection to active directory server: %s\n", ad->server);
return AD_ERROR;
}
if(ad_bind(ld, ad->general_user, ad->general_pw)!=AD_SUCCESS)
{
ad_close(ld);
if(sgs_debug_level>=0) printf("Could not bind to active directory with user: %s\n", ad->general_user);
return AD_ERROR;
}
if((sgs=ad_get_sitegroups(ld, ad->basedn, site, group, &num_sgs))==NULL)
{
if(sgs_debug_level>=0) printf("Could not retrieve available sites and groups\n");
ad_close(ld);
return AD_ERROR;
}
for(x=0;x<num_sgs;x++)
{
if(ad_create_alias_file(ld, ad->basedn, sgs->site, sgs->group)!=AD_SUCCESS)
{
if(sgs_debug_level>=0) printf("Could not create alias file for site: %s, group: %s\n", (sgs->site!=NULL?sgs->site:"ALL"), (sgs->group!=NULL?sgs->group:"ALL"));
}else{
if(sgs_debug_level>=0) printf("Successfully created alias file for site: %s, group: %s\n", (sgs->site!=NULL?sgs->site:"ALL"), (sgs->group!=NULL?sgs->group:"ALL"));
}
sgs++;
}
ad_close(ld);
return AD_SUCCESS;
}
void
kill_old_files(void)
{
DIR *dir;
struct dirent *entry;
char dead[CHAR_MAX];
if(sgs_debug_level>=0) printf("Looking in %s for old alias file removal\n", ALIAS_DIR_HEADER);
if((dir=opendir(ALIAS_DIR_HEADER))==NULL)
{
if(sgs_debug_level>=1) printf("Could not open directory to clean: %s\n", ALIAS_DIR_HEADER);
return;
}
for(;(entry=readdir(dir))!=NULL;)
{
if(strlen(entry->d_name)<=2) continue;
if(strstr(entry->d_name, ALIAS_FILE_HEADER)!=NULL)
{
if(strlen(ALIAS_DIR_HEADER)+strlen(entry->d_name)+2>CHAR_MAX)
{
if(sgs_debug_level>=2) printf("To be deleted filename size is greater than %d: %s/%s. Skipping...\n", CHAR_MAX, ALIAS_DIR_HEADER, entry->d_name);
continue;
}
sprintf(dead, "%s/%s", ALIAS_DIR_HEADER, entry->d_name);
if(sgs_debug_level>=2) printf("unlinking file: %s\n", dead);
if(unlink(dead)==-1) if(sgs_debug_level>=2) printf("Could not unlink file: %s\n", dead);
}else if(sgs_debug_level>=3)printf("Filename: %s/%s does not match alias file prefix %s\n", ALIAS_DIR_HEADER, entry->d_name, ALIAS_FILE_HEADER);
}
}
void
show_usage(char *prog_name)
{
printf("%s [-V] [-s site] [-g group] [-q] [-d 1-3] [-R] [-h]\n", prog_name);
printf("\t-s sitename\tOnly create alias files for groups within this site.\n");
printf("\t-g groupname\tOnly create alias files for this group name.\n");
printf("\t-q\t\tQuiet, display no output\n");
printf("\t-d debug level\tDebug verbosity level to display: 1-3.\n");
printf("\t-R\t\tRemove all files in alias directory: %s\n\t\t\tprior to creating new files.\n", ALIAS_DIR_HEADER);
printf("\t\t\tFiles must match alias header: %s to be deleted.\n", ALIAS_FILE_HEADER);
printf("\t-V\t\tDisplays version then exits.\n");
printf("\t-h\t\tDisplay this output.\n");
exit(0);
}
int
main(int argc, char **argv)
{
int x=1, kill_files=0;
char *tsite=NULL, *tgroup=NULL;
sgs_debug_level=0;
if(argc<=1) printf("Creating all available alias files\n");
else
{
for(;x<argc;x+=2)
{
if(argv[x][0]=='-')
{
switch(argv[x][1])
{
case 's':
if(x+1<argc && argv[x+1] && strlen(argv[x+1])<CHAR_MAX) tsite=argv[x+1];
else show_usage(argv[0]);
break;
case 'g':
if(x+1<argc && argv[x+1] && strlen(argv[x+1])<CHAR_MAX) tgroup=argv[x+1];
else show_usage(argv[0]);
break;
case 'd':
if(x+1<argc && argv[x+1] && strlen(argv[x+1])<CHAR_MAX && (sgs_debug_level=atoi(argv[x+1]))>0 && sgs_debug_level<=3) printf("debug level: %d\n", sgs_debug_level);
else show_usage(argv[0]);
break;
case 'q':
sgs_debug_level=-1;
x--;
break;
case 'R':
kill_files=1;
x--;
break;
case 'V':
printf("%s version: %s\n", argv[0], AD_CURRENT_VERSION);
exit(0);
break;
case 'h':
default:
show_usage(argv[0]);
break;
}
}else show_usage(argv[0]);
}
}
if(kill_files==1) kill_old_files();
if(ad_create_aliases(tsite, tgroup)!=AD_SUCCESS) _exit(1);
return 0;
}
syntax highlighted by Code2HTML, v. 0.9.1