#include #include #include #include #include #include #include #include #include #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=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=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=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;xbasedn, 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(;x0 && 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; }