#include "httpd.h" #include "http_config.h" #include "http_core.h" #include "http_log.h" #include "http_main.h" #include "http_protocol.h" #include "util_script.h" #include #include #include #include #include #include #include #include #include #include #include #include "x509ac.h" #include "x509ac-supp.h" #include #include #ifndef LDAP_PORT #define LDAP_PORT 389 #endif /* LDAP_PORT */ #define DEBUG_LDAP 1 #define MOD_AUTH_SIS_LDAP_VERSION_S "0.1" module MODULE_VAR_EXPORT ldap_sisauth_module; typedef struct _info_share_auth_config_rec { LDAP *ld; char *ldap_server, *base_dn, *uid_attr, *group_attr; char filter[512]; char *user_dn; char *bind_dn, *bind_pass; int ldap_port; int auth_ldapauthoritative; LDAPMessage *result; char *attributeCertificatePath; char *dummy; char *sisACL; char *cacertificatefile; char method_number[6]; char *rolehierarchy; } info_share_ldap_auth_config_rec; struct ip_vs_cb_rule_field { char name[512]; char value[256]; char *presentvalue; }; struct ip_vs_cb_rule_field rule_fields[] = { {"sis:1.Role:1.", "", "" }, {"sis:1.Group:1.", "", "" }, {"sis:1.Permission:1.access1:1.", "", "" }, {"sis:1.Permission:1.access2:1.", "", "" }, {"sis:1.OU:1.", "", "" } }; /* ** i need to remove this junk from chandra's code of xml parsing */ int len_cr=2, len_lf=2, len_sp=1, len_la=1, len_ra=1, len_fs=1, len_ex=1, max_char_len=1; char *c_cr="\r", *c_lf="\n", *c_sp=" ", *c_la="<", *c_ra=">", *c_fs="/", *c_ex="!"; int num_rule_fields = sizeof(rule_fields) / sizeof(struct ip_vs_cb_rule_field); static void *create_info_share_ldap_auth_dir_config(pool *p,char *d) { info_share_ldap_auth_config_rec *cr; cr=(info_share_ldap_auth_config_rec *) ap_pcalloc(p,sizeof(info_share_ldap_auth_config_rec)); if (cr == (info_share_ldap_auth_config_rec *) NULL) return (NULL); cr->ld=(LDAP *) NULL; cr->ldap_server=NULL; cr->base_dn=NULL; cr->user_dn=NULL; cr->bind_dn=NULL; cr->bind_pass=NULL; cr->uid_attr=NULL; cr->group_attr=ap_pstrdup(p,"uniqueMember"); cr->ldap_port=LDAP_PORT; cr->auth_ldapauthoritative=0; /* fortress is secure by default */ cr->cacertificatefile=NULL; cr->sisACL=NULL; cr->rolehierarchy = NULL; return (cr); } static const char *set_ldap_server(cmd_parms *cmd,info_share_ldap_auth_config_rec *cr, char *arg) { cr->ldap_server=ap_pstrdup(cmd->pool,arg); return (NULL); } static const char *set_ldap_port(cmd_parms *cmd,info_share_ldap_auth_config_rec *cr, char *arg) { cr->ldap_port=atoi(arg); return (NULL); } static const char *set_base_dn(cmd_parms *cmd,info_share_ldap_auth_config_rec *cr, char *arg) { cr->base_dn=ap_pstrdup(cmd->pool,arg); return (NULL); } static const char *set_group_attr(cmd_parms *cmd,info_share_ldap_auth_config_rec *cr, const char *arg) { cr->group_attr=ap_pstrdup(cmd->pool,arg); return (NULL); } static const char *set_bind_dn(cmd_parms *cmd,info_share_ldap_auth_config_rec *cr, char *arg) { cr->bind_dn=ap_pstrdup(cmd->pool,arg); return (NULL); } static const char *set_bind_pass(cmd_parms *cmd,info_share_ldap_auth_config_rec *cr, char *arg) { cr->bind_pass=ap_pstrdup(cmd->pool,arg); return (NULL); } static const char *set_uid_attr(cmd_parms *cmd,info_share_ldap_auth_config_rec *cr, char *arg) { cr->uid_attr=ap_pstrdup(cmd->pool,arg); return (NULL); } static const char *set_ldapauthoritative(cmd_parms *cmd,info_share_ldap_auth_config_rec *cr,char *arg) { char *a=ap_pstrdup(cmd->pool,arg); if (a != NULL) { if ((strcmp(a,"no") == 0) || (strcmp(a,"off") == 0)) { cr->auth_ldapauthoritative=0; } else { if ((strcmp(a,"yes") == 0) || (strcmp(a,"on") == 0)) { cr->auth_ldapauthoritative=1; } else { ap_log_error(APLOG_MARK,APLOG_NOERRNO | APLOG_ERR,NULL, "[mod_auth_ldap.c] - AuthLDAPAuthoritative has unexpected argument"); } } } else { ap_log_error(APLOG_MARK,APLOG_NOERRNO | APLOG_ERR,NULL, "[mod_auth_ldap.c] - AuthLDAPAuthoritative is missing its argument"); } return (NULL); } static const char *set_ldap_cacertificatefile(cmd_parms *cmd,info_share_ldap_auth_config_rec *cr, char *arg) { cr->cacertificatefile=ap_pstrdup(cmd->pool,arg); return (NULL); } static const char *set_ldap_sisACL(cmd_parms *cmd,info_share_ldap_auth_config_rec *cr, char *arg) { cr->sisACL=ap_pstrdup(cmd->pool,arg); return (NULL); } static const char *set_ldap_sisRoleHierarchy(cmd_parms *cmd,info_share_ldap_auth_config_rec *cr, char *arg) { cr->rolehierarchy=ap_pstrdup(cmd->pool,arg); return (NULL); } char *mstrstr(char *source, char *substr, size_t n) { char *p = NULL; int subStrLen = 0; p = strstr(source, substr); if(p == NULL) { subStrLen = strlen(substr); if(!memcmp(source + n - subStrLen, substr, subStrLen)) p = source + n - subStrLen; } return p; } void print_rule_fld_values() { int i = 0; for(i=0; i < num_rule_fields;i++) fprintf(stderr,"%s:%s%s\n",rule_fields[i].name,rule_fields[i].value,rule_fields[i].presentvalue); return; } void clear_rule_fld_values() { int i = 0; for(i=0; i < num_rule_fields;i++) { rule_fields[i].value[0] = '\0'; free(rule_fields[i].presentvalue); } return; } void clear_rule_fld_values1() { int i = 0; for(i=0; i < num_rule_fields;i++) { rule_fields[i].value[0] = '\0'; rule_fields[i].presentvalue = NULL;; } return; } int get_tag_range(char *tag, int pos, char *hay_begin, char *hay_end, char **needle_begin, char **needle_end) { char temp_buf[67]; int curr_pos = 0; int skip_len = 0; int hay_len = 0; int buf_len = 0; char *p = NULL; char *p_tmp = NULL; char *p1 = NULL; char *p_end = NULL; char *p_beg = NULL; char *tag_left = NULL; char *tag_right = NULL; hay_len = hay_end - hay_begin; buf_len = hay_len; p = hay_begin; while(curr_pos < pos) { /* ** First Remove any leading comments */ sprintf(temp_buf, "%s%s--", c_la, c_ex); if((p_tmp = mstrstr(p, temp_buf, hay_len)) != NULL) { /* ** Found the beginning of comment marker "" */ sprintf(temp_buf, "--%s", c_ra); if((p1 = mstrstr(p_tmp, temp_buf, buf_len - (p_tmp - hay_begin))) != NULL) { p = p1 + strlen(temp_buf); hay_len = buf_len - (p - hay_begin); continue; } else { (void) fprintf(stderr,"Bad xml data, no ending comment tag\n"); break; } } sprintf(temp_buf, "%s%s", c_fs, tag); /* ** First look for end position "/tag" i.e., the vicinity of */ if((p_end = mstrstr(p, temp_buf, hay_len)) != NULL) { curr_pos++; if(curr_pos == pos) { /* ** Now look for begin position of the "tag" i.e., the vicinity of */ if((p_beg = mstrstr(p, tag, hay_len)) != NULL) { /* ** First verify that it is a real tag */ tag_left = p_beg; tag_right = p_beg + strlen(tag); /* ** i.e, Below is a check for situations like AtagB */ if(( (memcmp(tag_left - len_sp, c_sp, len_sp)) && (memcmp(tag_left - len_ra, c_la, len_la)) && (memcmp(tag_left - len_cr, c_cr, len_cr)) && (memcmp(tag_left - len_lf, c_lf, len_lf)) ) || ( (memcmp(tag_right, c_sp, len_sp)) && (memcmp(tag_right, c_ra, len_ra)) && (memcmp(tag_right, c_cr, len_cr)) && (memcmp(tag_right, c_lf, len_lf)) ) ) { p = tag_right; hay_len = buf_len - (p - hay_begin); --curr_pos; continue; } p_beg = tag_right; /* ** Find the position of '>' for p_beg */ p = mstrstr(p_beg, c_ra, p_end - p_beg); if(p == NULL) { p_beg = NULL; p_end = NULL; break; } /* ** Find the position of '<' for beginning from p_beg */ p_tmp = mstrstr(p_beg, c_la, p_end - p_beg); /* ** Below is a check for tag */ if(p_tmp && (p_tmp < p)) { hay_len = buf_len - (p - hay_begin); --curr_pos; continue; } /* ** Now eliminate all unwanted characters between p_beg and p_end ** such as white space, line feed, carriage return until until ** right and left anchors are seen respectively */ if(p != NULL) p_beg = p + len_ra; else { /* ** We didn't find the '>' for p_beg */ p_beg = NULL; p_end = NULL; break; } /* ** Find the position of left anchor for p_end */ while((p_end - max_char_len) > p_beg) { skip_len = len_la; if(!memcmp(p_end - skip_len, c_la, skip_len)) { p_end -= skip_len; break; } skip_len = len_sp; if(!memcmp(p_end - skip_len, c_sp, skip_len)) p_end -= skip_len; skip_len = len_cr; if(!memcmp(p_end - skip_len, c_cr, skip_len)) p_end -= skip_len; skip_len = len_lf; if(!memcmp(p_end - skip_len, c_lf, skip_len)) p_end -= skip_len; } } } else { /* ** Advance p for the next ...data... block */ p = p_end + strlen(temp_buf); hay_len = buf_len - (p - hay_begin); } } else /* ** No specified needle found in the hay */ break; } *needle_begin = p_beg; *needle_end = p_end; return 0; } int xml_tag_parser(char *buf) { int buf_len =strlen(buf); int ret = 0; int field_count = 0; short done_yet = 0; int skip_len = 0; int pos = 0; char tag[64]; char pos_str[10]; char *p = NULL; char *p1 = NULL; char *fld_spec_beg = NULL; char *fld_spec_end = NULL; char *data_beg = NULL; char *data_end = NULL; char *tag_beg = NULL; char *tag_end = NULL; for(field_count = 0; field_count < num_rule_fields; field_count++) { fld_spec_beg = &(rule_fields[field_count].name[0]); fld_spec_end = &(rule_fields[field_count].name[strlen(rule_fields[field_count].name)]); data_beg = buf; data_end =(char *) (buf+buf_len); while(fld_spec_beg < fld_spec_end) { p = (char *)memchr(fld_spec_beg, ':', fld_spec_end - fld_spec_beg); if(!p) { (void) fprintf(stderr,"Invalid rule field specification '%s'\n", rule_fields[field_count].name); return -1; } memcpy(tag, fld_spec_beg, p - fld_spec_beg); tag[p - fld_spec_beg] = '\0'; p += 1; p1 = (char *)memchr(p, '.', fld_spec_end - p); if(!p1) { (void) fprintf(stderr,"Invalid rule field specification '%s'\n", rule_fields[field_count].name); return -1; } memcpy(pos_str, p, p1 - p); pos_str[p1 - p] = '\0'; fld_spec_beg = ++p1; pos = atoi(pos_str); get_tag_range(tag, pos, data_beg, data_end, &tag_beg, &tag_end); if((!tag_beg) || (!tag_end)) { (void) fprintf(stderr,"get_tag_range() returned NULL either for tag_beg or tag_end, " "tag_beg=%u, " "tag_end=%u, " "tag=%s, " "pos=%d ", ((tag_beg) ? (unsigned int) tag_beg : 0), ((tag_end) ? (unsigned int) tag_end : 0), tag, pos); return -1; } if(fld_spec_beg == fld_spec_end) { /* We have parsed all the sub fields of the field specified in the rule. ** Now parse data between tag_beg and tag_end and store in the field value ** after skipping white spaces, carriage returns and line feeds. */ done_yet = 0; while((tag_beg < tag_end) && !done_yet) { done_yet = 1; skip_len = len_sp; if(!memcmp(tag_beg, c_sp, skip_len)) { tag_beg += skip_len; done_yet = 0; } skip_len = len_cr; if(!memcmp(tag_beg, c_cr, skip_len)) { tag_beg += skip_len; done_yet = 0; } skip_len = len_lf; if(!memcmp(tag_beg, c_lf, skip_len)) { tag_beg += skip_len; done_yet = 0; } } done_yet = 0; while((tag_beg < tag_end) && !done_yet) { skip_len = len_sp; if(memcmp(tag_end - skip_len, c_sp, skip_len)) skip_len = 0; if(!skip_len) { skip_len = len_cr; if(memcmp(tag_end - skip_len, c_cr, skip_len)) skip_len = 0; } if(!skip_len) { skip_len = len_lf; if(memcmp(tag_end - skip_len, c_lf, skip_len)) skip_len = 0; } if(skip_len) tag_end -= skip_len; else done_yet = 1; } if(tag_beg != tag_end) { if((tag_end - tag_beg) < sizeof(rule_fields[field_count].value)) { memcpy(rule_fields[field_count].value, tag_beg, tag_end - tag_beg); rule_fields[field_count].value[tag_end - tag_beg] = '\0'; } else (void) fprintf(stderr,"tag value size=%d is larger than its container size=%d for rule tag '%s' of field spec '%s'\n", (tag_end - tag_beg), sizeof(rule_fields[field_count].value), tag, rule_fields[field_count].name); } else (void) fprintf(stderr,"No value found for rule field spec '%s'\n", rule_fields[field_count].name); } else { data_beg = tag_beg; data_end = tag_end; } } } return ret; } char * mystrstr(string, substring) register char *string; /* String to search. */ char *substring; /* Substring to try to find in string. */ { register char *a, *b; b = substring; if (*b == 0) { return string; } for ( ; *string != 0; string += 1) { if (*string != *b) { continue; } a = string; while (1) { if (*b == 0) { return string; } if (*a++ != *b++) { break; } } b = substring; } return (char *) 0; } char *findMatch(const char *string, const char *startsubstring, const char *endsubstring) { char *startptr; char *endptr; startptr = (char *) 0; endptr = (char *) 0; startptr = mystrstr(string, startsubstring); if (startptr == (char *) 0) return (char *) 0; endptr = mystrstr(startptr, endsubstring); if (endptr == (char *) 0) return (char *) 0; return ( (char *)strndup(startptr, endptr-startptr)); } static const command_rec info_share_ldap_auth_cmds[]= { {"LDAP_Server",set_ldap_server,NULL,OR_AUTHCFG,TAKE1,"LDAP server"}, {"LDAP_Port", set_ldap_port, NULL,OR_AUTHCFG,TAKE1,"LDAP port"}, {"Base_DN", set_base_dn, NULL,OR_AUTHCFG,TAKE1,"Base DN"}, {"UID_Attr", set_uid_attr, NULL,OR_AUTHCFG,TAKE1,"uid"}, {"Group_Attr", set_group_attr, NULL,OR_AUTHCFG,TAKE1, "Group attribute"}, {"Bind_DN", set_bind_dn, NULL,OR_AUTHCFG,TAKE1,"Bind DN"}, {"Bind_Pass", set_bind_pass, NULL,OR_AUTHCFG,TAKE1,"Bind Password"}, {"CACertificateFile", set_ldap_cacertificatefile, NULL,OR_AUTHCFG,TAKE1,"Attribute certificate ca certificatefile"}, {"Role_Hierarchy", set_ldap_sisRoleHierarchy, NULL,OR_AUTHCFG,TAKE1,"Role Hierarchy file"}, {"SISrequire", set_ldap_sisACL, NULL,OR_AUTHCFG,TAKE1,"Attribute certificate ACL"}, {"AuthLDAPAuthoritative",set_ldapauthoritative,NULL,OR_AUTHCFG,TAKE1, "Set to no to allow control to be passed along to lower modules if the uid is not known to this module"}, {NULL} }; int getAttributeResult(info_share_ldap_auth_config_rec *cr, LDAPMessage *res,request_rec *r, int next) { LDAPMessage *ent; BerElement *ber; LDAP *ld; char *attr, **vals; int error = -1; ld = cr->ld; for (ent=ldap_first_entry(ld,res); ent != NULL; ent=ldap_next_entry(ld,ent)) { for (attr=ldap_first_attribute(ld,ent,&ber); attr != NULL; attr=ldap_next_attribute(ld,ent,ber)) { if (strcasecmp(attr,"attributeCertificateAttribute;binary") == 0) { if ((vals=ldap_get_values(ld,ent,attr)) != NULL) { if (vals[next-1] != NULL) { cr->attributeCertificatePath=ap_pstrdup(r->pool,vals[next-1]); ap_log_rerror(APLOG_MARK,APLOG_NOERRNO | APLOG_ERR,r, "dumpattrpat: %s=:%s:", attr,vals[next-1]); error = 1; } if (vals) ldap_value_free(vals); } } } } return error; } static void dumpResult(LDAP *ld,LDAPMessage *res,request_rec *r) { LDAPMessage *ent; BerElement *ber; int i; char *attr, **vals; ap_log_rerror(APLOG_MARK,APLOG_NOERRNO | APLOG_ERR,r, "XXXXXXXX"); for (ent=ldap_first_entry(ld,res); ent != NULL; ent=ldap_next_entry(ld,ent)) { for (attr=ldap_first_attribute(ld,ent,&ber); attr != NULL; attr=ldap_next_attribute(ld,ent,ber)) { if (strcasecmp(attr,"jpegphoto") != 0) { if ((vals=ldap_get_values(ld,ent,attr)) != NULL) { for (i=0; vals[i] != NULL; i++) { ap_log_rerror(APLOG_MARK,APLOG_NOERRNO | APLOG_ERR,r, "dump: %s=%s",attr,vals[i]); } if (vals) ldap_value_free(vals); } } } } } /* ** ldapFindUserDN() ** return the DN of the user ** ** Parameters: ** LDAP *ld valid handle to LDAP ** char *base_dn LDAP base Distinguised Name ** char *uid_attrib LDAP uid attribute, e.g. "uid" ** char *userid the userid to check ** request_rect *r needed for writing log in Win2K ** char *bind_dn Bind_DN, can be NULL ** char *bind_pass Bind_Pass, can be NULL ** ** Return Values: ** pointer to DN of the userid if found, NULL otherwise ** ** Limitations and Comments: ** ld must be valid. ** ** any LDAP sdk should work. returns pointer to a malloc'd space, the ** caller is responsible to free it. ** ** Development History: ** who when why ** ma_muquit@fccc.edu Nov-29-1998 first cut for my own web server ** mhttpd ** muquit@muquit.com Mar-15-2001 bind with bind and pass if provided. */ static char *ldapFindUserDN(info_share_ldap_auth_config_rec *cr,LDAP *ld,char *base_dn,char *uid_attrib, char *userid,request_rec *r,char *bind_dn,char *bind_pass) { int count = 0; int bound=0, rc=(-1); LDAPMessage *entry; char *dn, szfilter[256]; cr->result=(LDAPMessage *) NULL; entry=(LDAPMessage *) NULL; dn=(char *) NULL; /* prepare filter with UidAttr. */ ap_snprintf(szfilter,sizeof(szfilter)-1,"(%s=%s)",uid_attrib,userid); /* ** if the bind DN and bind password is specified, try to bind with ** them first. */ if (bind_dn != NULL && bind_pass != NULL) { if (ldap_simple_bind_s(ld,bind_dn,bind_pass) == LDAP_SUCCESS) { bound=1; } else { ap_log_rerror(APLOG_MARK,APLOG_NOERRNO | APLOG_ERR,r, "[mod_auth_ldap.c] - Warning: bind with DN \"%s\" and password (not shown) did not succeed",bind_dn); } } else { #ifdef DEBUG_LDAP ap_log_rerror(APLOG_MARK,APLOG_NOERRNO | APLOG_ERR,r, "[mod_auth_ldap.c] - Bind_DN/Bind_Pass is not provided"); #endif /* DEBUG_LDAP */ } /* Bind anonymously now only if not bound yet. */ if (bound == 0) { if (ldap_simple_bind_s(ld,base_dn,NULL) != LDAP_SUCCESS) { #ifdef DEBUG_LDAP ap_log_rerror(APLOG_MARK,APLOG_NOERRNO | APLOG_ERR,r, "[mod_auth_ldap.c] - ldap_simple_bind_s() failed"); #endif /* DEBUG_LDAP */ return ((char *) NULL); } } /* search to find the dn for the user */ rc=ldap_search_s(ld, base_dn, LDAP_SCOPE_SUBTREE, szfilter, NULL, 0, &cr->result); if (rc != LDAP_SUCCESS) { ap_log_rerror(APLOG_MARK,APLOG_NOERRNO | APLOG_ERR,r, "[mod_auth_ldap.c] - ldap_search_s() failed"); /* note: ldap_err2string() returns pointer to a static space */ ap_log_rerror(APLOG_MARK,APLOG_NOERRNO | APLOG_ERR,r, "[mod_auth_ldap.c] - Error: %s",ldap_err2string(rc)); return (NULL); } /* found something, better be a single match */ if ((count = ldap_count_entries(ld,cr->result)) != 1) { if (count > 0) { ap_log_rerror(APLOG_MARK,APLOG_NOERRNO | APLOG_ERR,r, "[mod_auth_ldap.c] - multiple matches found for: %s",userid); } else { if (bound == 0) { ap_log_rerror(APLOG_MARK,APLOG_NOERRNO | APLOG_ERR,r, "[mod_auth_ldap.c] - do we have anonymous access? no user found for: %s",userid); } else { ap_log_rerror(APLOG_MARK,APLOG_NOERRNO | APLOG_ERR,r, "[mod_auth_ldap.c] - no user found for: %s",userid); } } if (cr->result != (LDAPMessage *) NULL) ldap_msgfree(cr->result); return (NULL); } if ((entry=ldap_first_entry(ld,cr->result)) == NULL) { #ifdef DEBUG_LDAP ap_log_rerror(APLOG_MARK,APLOG_NOERRNO | APLOG_ERR,r, "[mod_auth_ldap.c] - %s=%s Unknown in LDAP server",uid_attrib,userid); #endif /* DEBUG_LDAP */ return (NULL); } if ((dn=ldap_get_dn(ld,entry)) == NULL) { ap_log_rerror(APLOG_MARK,APLOG_NOERRNO | APLOG_ERR,r, "[mod_auth_ldap.c] - could not obtain DN from LDAP for user %s",userid); return (NULL); } return (dn); /* caller must free it */ } static int validateAttributeCertificate(info_share_ldap_auth_config_rec *cr, request_rec *r, char *CAfile); /* ** calculate the time difference between 2 timeval structures */ void tvsub( struct timeval *out, struct timeval *in ) { if( (out->tv_usec -= in->tv_usec) < 0 ) { out->tv_sec--; out->tv_usec += 1000000; } out->tv_sec -= in->tv_sec; } /* ** validate the user id via LDAP ** Returns: ** DECLINED if ldap server is not defined in config file ** AUTH_REQUIRED for any other kind of errors ** OK if authorized */ static int info_share_ldap_authenticate_user(request_rec *r, info_share_ldap_auth_config_rec *cr, char *user) { int rc, i, error, res; char *dn, szfilter[256], sztdn[256]; #if 1 struct timeval tv_end; struct timeval tv_start; float triptime; /* calculate algorithm begin Time */ gettimeofday(&tv_start , (struct timezone *) 0); #endif /* if no user is specified, keep asking */ if (user == NULL || *user == '\0') { return(-1); } #ifdef DEBUG_LDAP ap_log_rerror(APLOG_MARK,APLOG_NOERRNO | APLOG_ERR,r, "[mod_auth_ldap.c] - LDAP server=%s,Port=%d",cr->ldap_server,cr->ldap_port); #endif /* DEBUG_LDAP */ /* mm, aug-20-199 */ if (cr->ldap_server == NULL) return (-1); if (cr->ld != NULL) { #ifdef DEBUG_LDAP ap_log_rerror(APLOG_MARK,APLOG_NOERRNO | APLOG_ERR,r, "[mod_auth_ldap.c] - closing connection to LDAP server: %s", cr->ldap_server); #endif /* DEBUG_LDAP */ ldap_unbind_s(cr->ld); } #ifdef DEBUG_LDAP ap_log_rerror(APLOG_MARK,APLOG_NOERRNO | APLOG_ERR,r, "mod_auth_ldap.c] - opening connection to LDAP server: %s at port: %d",cr->ldap_server,cr->ldap_port); #endif /* DEBUG_LDAP */ /* connect to LDAP server */ cr->ld=ldap_open(cr->ldap_server,cr->ldap_port); if (cr->ld == (LDAP *) NULL) { ap_log_rerror(APLOG_MARK,APLOG_NOERRNO | APLOG_ERR,r, "[mod_auth_ldap.c] - Could not connect to LDAP server %s at port %d",cr->ldap_server,cr->ldap_port); // ap_note_basic_auth_failure(r); return (-1); } /* now get the User DN */ dn=ldapFindUserDN(cr, cr->ld,cr->base_dn,cr->uid_attr,user,r, cr->bind_dn,cr->bind_pass); if (dn == (char *) NULL) { #ifdef DEBUG_LDAP ap_log_rerror(APLOG_MARK,APLOG_NOERRNO | APLOG_ERR,r, "[mod_auth_ldap.c] - ldapFindUserDN() didn't return any DN for user \"%s\" with attr \"%s\"",user,cr->uid_attr); return (-1); #endif /* DEBUG_LDAP */ } /* calculate algorithm end Time */ gettimeofday(&tv_end , (struct timezone *) 0); tvsub(&tv_end,&tv_start); triptime = tv_end.tv_sec*1000.00+(tv_end.tv_usec/1000.00); ap_log_rerror(APLOG_MARK,APLOG_NOERRNO | APLOG_ERR,r, "the total execution time for ldap access = %f ms", triptime); #ifdef DEBUG_LDAP ap_log_rerror(APLOG_MARK,APLOG_NOERRNO | APLOG_ERR,r, "[mod_auth_ldap.c] - ldapFindUserDN() return DN for user \"%s\" with attr \"%s\"",user,cr->uid_attr); #endif /* DEBUG_LDAP */ /* store user DN, we'll use it later if needed*/ cr->user_dn=ap_pstrdup(r->pool,dn); #ifdef DEBUG_LDAP ap_log_rerror(APLOG_MARK,APLOG_NOERRNO | APLOG_ERR,r, "[mod_auth_ldap.c] - User DN: %s",dn); #endif /* DEBUG_LDAP */ error = getAttributeResult(cr,cr->result,r, 1); for (i=2; error > 0; i++) { if ( (error = validateAttributeCertificate(cr, r,cr->cacertificatefile )) >= 0) { // free(cr->attributeCertificatePath); break; } error = getAttributeResult(cr,cr->result,r, i); ap_log_rerror(APLOG_MARK,APLOG_NOERRNO | APLOG_ERR,r, "arr is %d",error); } ap_log_rerror(APLOG_MARK,APLOG_NOERRNO | APLOG_ERR,r, "post arr is %d",error); /* free things we won't need */ if (cr->result != (LDAPMessage *) NULL) ldap_msgfree(cr->result); if (dn != (char *) NULL) { /* * if free is called, it dies in Windows 2000 if compiled with * iPlanet C SDK 5.08. ldap_memfree() is suggested use with most of * the SDKs anyway. * - muquit@muquit.com Sep-24-2002 */ /* (void) free(dn);*/ ldap_memfree(dn); dn=NULL; } if (cr->cacertificatefile == NULL) return -1; return (error); } /* attribute certificate validation code goes here */ #if 1 int verify_callback (int ok, X509_STORE_CTX * stor) { return ok; } int X509AC_verify_certlocal(X509_STORE_CTX * verify_ctx, X509AC * ac, request_rec *r) { int diff = 0; X509* issuer = NULL; X509* issuer2= NULL; X509_NAME * acIssuer = NULL; int i = 0; EVP_PKEY * pkey = NULL; int ret = -1; /* ok, first do a validity time check */ diff = X509_cmp_current_time(ac->info->validity->notBefore); if(diff == 0) { return -1; } if(diff > 0) { return -2; } #ifdef DEBUG_LDAP ap_log_rerror(APLOG_MARK,APLOG_NOERRNO | APLOG_ERR,r, "[mod_auth_ldap.c] - succesful till return -2"); #endif /* DEBUG_LDAP */ diff = X509_cmp_current_time(ac->info->validity->notAfter); if(diff == 0) { return -3; } if(diff < 0) { return -4; } #ifdef DEBUG_LDAP ap_log_rerror(APLOG_MARK,APLOG_NOERRNO | APLOG_ERR,r, "[mod_auth_ldap.c] - succesful till return -4"); #endif /* DEBUG_LDAP */ /* get the AC issuer name */ acIssuer = X509AC_get_issuer_name(ac); if (!acIssuer) { return -5; } #ifdef DEBUG_LDAP ap_log_rerror(APLOG_MARK,APLOG_NOERRNO | APLOG_ERR,r, "[mod_auth_ldap.c] - succesful till return -5"); #endif /* DEBUG_LDAP */ /* now try to find AC issuer in untrusted chain of context */ for (i = 0; i < sk_X509_num(verify_ctx->untrusted); i++) { X509_NAME * subject = NULL; char subject_name[128]; issuer = sk_X509_value(verify_ctx->untrusted, i); if(!issuer) { return -6; } #ifdef DEBUG_LDAP ap_log_rerror(APLOG_MARK,APLOG_NOERRNO | APLOG_ERR,r, "[mod_auth_ldap.c] - succesful till return -6"); #endif /* DEBUG_LDAP */ /* AC issuer name needs to match issuer cert subject */ /* get the cert subject name (the possible issuer) */ subject = X509_get_subject_name(issuer); if (!subject) { return -7; } X509_NAME_oneline(subject,subject_name,128); if(X509_NAME_cmp(acIssuer, subject)==0) { break; /* found it */ } else { issuer = NULL; } } // end for if(!issuer) { return -8; } #ifdef DEBUG_LDAP ap_log_rerror(APLOG_MARK,APLOG_NOERRNO | APLOG_ERR,r, "[mod_auth_ldap.c] - succesful till return -8"); #endif /* DEBUG_LDAP */ /* now verify the signature on the AC */ pkey = X509_get_pubkey(issuer); if (pkey == NULL) { return(-9); } if(pkey->type != EVP_PKEY_RSA) return(-10); if ((ASN1_item_verify(ASN1_ITEM_rptr(X509AC_INFO),ac->algor, ac->signature,ac->info,pkey)) <=0) { return (-11); } /* alright now set the verify context to hold the located issuer cert */ verify_ctx->cert=issuer; /* call the standard verify routine on the issuer cert */ ret = X509_verify_cert(verify_ctx); X509_STORE_CTX_cleanup(verify_ctx); if (ret <= 0) { ret = X509_STORE_CTX_get_error(verify_ctx); if (ret == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT || ret == X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY) { X509_STORE_CTX_set_error(verify_ctx,X509_V_OK); ret = 1; } } #ifdef DEBUG_LDAP ap_log_rerror(APLOG_MARK,APLOG_NOERRNO | APLOG_ERR,r, "[mod_auth_ldap.c] - succesful till return all"); #endif /* DEBUG_LDAP */ return ret; } // end X509AC_verify_cert static int validateAttributeCertificate(info_share_ldap_auth_config_rec *cr, request_rec *r, char *CAfile) { FILE *fp; int ret; X509AC *ac; X509 *issuer; X509_STORE *store; char nameString[ONELINELEN]; X509_NAME *issuerSubjectName; X509_STORE_CTX verify_ctx; STACK_OF(X509) * issuer_certs; char mfile[56]; int fd; const char *t; OpenSSL_add_all_algorithms (); ERR_load_crypto_strings (); clear_rule_fld_values1(); BIO *out; strcpy(mfile, "/tmp/apache_shmem.XXXX"); out = BIO_new_file(mfile, "w"); /* Error occurred */ if(!out) { #ifdef DEBUG_LDAP perror("fopen"); ap_log_rerror(APLOG_MARK,APLOG_NOERRNO | APLOG_ERR,r, "[mod_auth_ldap.c] - Error opening attribute certificate file"); #endif /* DEBUG_LDAP */ return -1; } BIO_printf(out,"%s",cr->attributeCertificatePath); BIO_free(out); if (!(fp = fopen (mfile, "r"))) { #ifdef DEBUG_LDAP ap_log_rerror(APLOG_MARK,APLOG_NOERRNO | APLOG_ERR,r, "[mod_auth_ldap.c] - Error opening attribute certificate file"); #endif /* DEBUG_LDAP */ return -1; } if (!(ac = PEM_read_X509AC (fp, NULL, NULL))) { #ifdef DEBUG_LDAP ap_log_rerror(APLOG_MARK,APLOG_NOERRNO | APLOG_ERR,r, "[mod_auth_ldap.c] - Error reading attribute certificate file"); #endif /* DEBUG_LDAP */ return -1; } fclose (fp); /* create the cert store and set the verify callback */ if (!(store = X509_STORE_new ())) { ap_log_rerror(APLOG_MARK,APLOG_NOERRNO | APLOG_ERR,r, "[mod_auth_ldap.c] - Error creating X509_STORE_CTX object"); return -1; } X509_STORE_set_verify_cb_func (store, verify_callback); if (X509_STORE_load_locations (store, CAfile, NULL) != 1) { ap_log_rerror(APLOG_MARK,APLOG_NOERRNO | APLOG_ERR,r, "[mod_auth_ldap.c] - Error loading the CA file or directory"); return -1; } if (X509_STORE_set_default_paths (store) != 1) { ap_log_rerror(APLOG_MARK,APLOG_NOERRNO | APLOG_ERR,r, "[mod_auth_ldap.c] - Error loading the system-wide CA certificates"); return -1; } /* load the issuer cert and put it in a stack */ if (!(fp = fopen (mfile, "r"))) { ap_log_rerror(APLOG_MARK,APLOG_NOERRNO | APLOG_ERR,r, "[mod_auth_ldap.c] - Error reading issuer certificate file"); return -1; } if (!(issuer = PEM_read_X509 (fp, NULL, NULL, NULL))) { ap_log_rerror(APLOG_MARK,APLOG_NOERRNO | APLOG_ERR,r, "[mod_auth_ldap.c] - Error reading issuer certificate in file"); return -1; } fclose (fp); issuerSubjectName = X509_get_subject_name(issuer); if (!issuerSubjectName) { ap_log_rerror(APLOG_MARK,APLOG_NOERRNO | APLOG_ERR,r, "[mod_auth_ldap.c] - Error getting subject name"); return -1; } X509_NAME_oneline(issuerSubjectName,nameString,ONELINELEN); #ifdef DEBUG_LDAP ap_log_rerror(APLOG_MARK,APLOG_NOERRNO | APLOG_ERR,r, "[mod_auth_ldap.c] - Issuer subject: %s", nameString); #endif /* DEBUG_LDAP */ issuer_certs = sk_X509_new_null(); sk_X509_push(issuer_certs, issuer); /* init our context, with NULL instead of the X509 cert to be verified, and add the issuer certs */ if (X509_STORE_CTX_init (&verify_ctx, store, issuer, NULL) != 1) { ap_log_rerror(APLOG_MARK,APLOG_NOERRNO | APLOG_ERR,r, "[mod_auth_ldap.c] - Error initializing verification context"); return -1; } ret=X509AC_verify_cert(&verify_ctx, ac); // ret=X509AC_verify_certlocal(verify_ctx, ac, r); /* free all the stuff (there is much more I know)*/ sk_X509_free(issuer_certs); X509_STORE_CTX_cleanup(&verify_ctx); X509_STORE_free(store); { X509_ATTRIBUTE *attribute; int i, j, attr_count; ASN1_TYPE *attr_type; ASN1_PRINTABLESTRING *astring; int nid = 0; /* attributes */ attr_count = X509at_get_attr_count(ac->info->attributes); if (attr_count>0) ap_log_rerror(APLOG_MARK,APLOG_NOERRNO | APLOG_ERR,r, "Attributes present: %i \n", attr_count); else { ap_log_rerror(APLOG_MARK,APLOG_NOERRNO | APLOG_ERR,r, "No Attributes present: %i \n", attr_count); clear_rule_fld_values(); return ret; } /* iterate through attributes */ for(i=0;iinfo->attributes,i); attr_type = X509_ATTRIBUTE_get0_type(attribute,i); nid = OBJ_obj2nid(attribute->object); astring = (ASN1_PRINTABLESTRING *)X509_ATTRIBUTE_get0_data(attribute,0,ASN1_TYPE_get(attr_type),NULL); ret=xml_tag_parser(astring->data); ap_log_rerror(APLOG_MARK,APLOG_NOERRNO | APLOG_ERR,r, "[mod_auth_ldap.c] - ac is %s",astring->data); } /* end for*/ for(i=0; i < num_rule_fields;i++) rule_fields[i].presentvalue = findMatch(cr->sisACL,rule_fields[i].name,","); ap_log_rerror(APLOG_MARK,APLOG_NOERRNO | APLOG_ERR,r, "[mod_auth_ldap.c] - Error initializing verificationa baba context"); for(i=0, ret=0; i < num_rule_fields;i++) { if (rule_fields[i].presentvalue != NULL) { ap_log_rerror(APLOG_MARK,APLOG_NOERRNO | APLOG_ERR,r, "i=%d:%s:%s:%s:cmpval%d",i,rule_fields[i].name,rule_fields[i].value, (rule_fields[i].presentvalue+strlen(rule_fields[i].name)+1),(strcasecmp(rule_fields[i].value,(rule_fields[i].presentvalue+strlen(rule_fields[i].name)+1)))); if (strcasecmp(rule_fields[i].value,(rule_fields[i].presentvalue+strlen(rule_fields[i].name)+1)) != 0) { ret = -1; break; } } } } ap_log_rerror(APLOG_MARK,APLOG_NOERRNO | APLOG_ERR,r, " out of loop ..........."); clear_rule_fld_values(); return ret; } #endif static int info_share_ldap_authenticate_basic_user(request_rec *r, info_share_ldap_auth_config_rec *cr) { char *user; char bind_dn[MAX_STRING_LEN]; user=strdup(findMatch(cr->dummy, "CN", "/") + 3); cr->base_dn=strdup(findMatch(cr->dummy, "O", "/")+2); sprintf(bind_dn, "cn=manager,%s",cr->base_dn); cr->bind_dn=strdup(bind_dn); cr->ldap_server=strdup(strrchr(cr->dummy,'@')+1); ap_log_rerror(APLOG_MARK,APLOG_NOERRNO | APLOG_ERR,r, "[mod_auth_ldap.c] - LDAP server=%s,Port=%d base_dn = %s, bind_dn = %s",cr->ldap_server,cr->ldap_port, cr->base_dn, cr->bind_dn); #ifdef DEBUG_LDAP ap_log_rerror(APLOG_MARK,APLOG_NOERRNO | APLOG_ERR,r, "[mod_auth_ldap.c] - LDAP server=%s,Port=%d",cr->ldap_server,cr->ldap_port); #endif /* DEBUG_LDAP */ if (info_share_ldap_authenticate_user(r, cr, user) < 0 ) { #ifdef DEBUG_LDAP ap_log_rerror(APLOG_MARK,APLOG_NOERRNO | APLOG_ERR,r, "[mod_auth_ldap.c] - Invalid Login or Password for:%s",user); #endif /* DEBUG_LDAP */ return (-1); } else { #ifdef DEBUG_LDAP ap_log_rerror(APLOG_MARK,APLOG_NOERRNO | APLOG_ERR,r, "[mod_auth_ldap.c] - valid Login or Password for:%s",user); #endif /* DEBUG_LDAP */ } free (user); return 1; } /* called to check to see if resource being requested requires authorization. */ static int info_share_ldap_check_user_access(request_rec *r) { const array_header *reqs_arr; require_line *reqs; register int x; int rc, m; const char *t, *w; info_share_ldap_auth_config_rec *cr; conn_rec *c; char *attr, *user=r->connection->user; cr=(info_share_ldap_auth_config_rec *) NULL; reqs_arr=(array_header *)NULL; reqs=(require_line *) NULL; cr=(info_share_ldap_auth_config_rec *) ap_get_module_config(r->per_dir_config,&ldap_sisauth_module); reqs_arr=ap_requires(r); reqs=reqs_arr ? (require_line *) reqs_arr->elts : NULL; m=r->method_number; c=r->connection; if (!cr->auth_ldapauthoritative) return DECLINED; if (!ap_ctx_get(r->connection->client->ctx, "ssl")) { ap_log_rerror(APLOG_MARK,APLOG_NOERRNO | APLOG_ERR,r, "[mod_info_share_auth_ldap.c] - not an SSL connection"); return HTTP_FORBIDDEN; } if ( (r->method_number == M_POST) || (r->method_number == M_PUT)) strcpy(cr->method_number,"writeread"); if (r->method_number == M_GET) strcpy(cr->method_number,"read"); ap_log_rerror(APLOG_MARK,APLOG_NOERRNO | APLOG_ERR,r, "[mod_info_share_auth_ldap.c] - method is %s", cr->method_number); SSL *ssl = (SSL *) ap_ctx_get(r->connection->client->ctx, "ssl"); SSL_SESSION *session = (SSL_SESSION *) SSL_get_session(ssl); if (session) { X509 *peer = session->peer; if (!peer) { ap_log_rerror(APLOG_MARK,APLOG_NOERRNO | APLOG_ERR,r, "[mod_info_share_auth_ldap.c] - peer certificate not found"); return HTTP_FORBIDDEN; } { char buf[1024]; X509_NAME_oneline( X509_get_subject_name(peer), buf, sizeof buf); ap_log_rerror(APLOG_MARK,APLOG_NOERRNO | APLOG_ERR,r, "[mod_info_share_auth_ldap.c] - subject \"%s\" ",buf); cr->dummy=ap_pstrdup(r->pool, buf); } } #if 0 if (info_share_ldap_authenticate_basic_user(r, cr) < 0 ) return HTTP_FORBIDDEN; #else { struct timeval tv_end; struct timeval tv_start; float triptime; /* calculate algorithm begin Time */ gettimeofday(&tv_start , (struct timezone *) 0); if (info_share_ldap_authenticate_basic_user(r, cr) < 0 ) return HTTP_FORBIDDEN; /* calculate algorithm end Time */ gettimeofday(&tv_end , (struct timezone *) 0); tvsub(&tv_end,&tv_start); triptime = tv_end.tv_sec*1000.00+(tv_end.tv_usec/1000.00); ap_log_rerror(APLOG_MARK,APLOG_NOERRNO | APLOG_ERR,r, "the total execution time to authorize access = %f ms", triptime); } #endif return OK; } /*--------------------------------------------------------------------------*/ /* Finally, the list of callback routines and data structures that */ /* provide the hooks into our module from the other parts of the server. */ /*--------------------------------------------------------------------------*/ module ldap_sisauth_module = { STANDARD_MODULE_STUFF, NULL, /* module initializer */ create_info_share_ldap_auth_dir_config, /* per-directory config creator */ NULL, /* dir config merger */ NULL, /* server config creator */ NULL, /* server config merger */ info_share_ldap_auth_cmds, /* command table */ NULL, /* [7] list of handlers */ NULL, /* [2] filename-to-URI translation */ NULL, /* [4] check access by host address */ NULL, /* [5] check/validate user_id */ info_share_ldap_check_user_access, /* [6] check auth */ NULL, /* [7] MIME type checker/setter */ NULL, /* [8] fixups */ NULL, /* [10] logger */ NULL, /* [3] header parser */ NULL, /* process initializer */ NULL, /* process exit/cleanup */ NULL /* [1] post read_request handling */ };