/****************************************************************************** Start of gridmapdir functions ******************************************************************************/ #define _GNU_SOURCE #include #include #include #include /*include */ #include #include #include #include /*include */ /*include */ #include "gridmapdir.h" #define DIGIT_CHARS "0123456789" /****************************************************************************** Function: xdigit_to_value Description: Convert a ascii character representing a hexadecimal digit into a integer. Parameters: xdigit, character contain the hex digit. Returns: value contained in xdigit, or -1 on error. ******************************************************************************/ int xdigit_to_value(char xdigit); /****************************************************************************** Function: match_username Description: This function checks if a username matches. The match is expressed in the following regex: - if matching_type contains the MATCH_STRICT_PREFIX_NUM flag: username=~/^${usernameprefix}[0-9]+/ - otherwise: username=~/^${usernameprefix}/ (Later we'll allow generic regexps?) Parameters: username, usernameprefix, matching_type Returns: 0: success <>0: no match ******************************************************************************/ int match_username(const char * username, const char * regex, unsigned short matching_type); char * gridmapdir_otherlink(const char * gridmapdir, char * firstlink) { int ret; char * firstlinkpath = NULL; char * otherlinkdup = NULL; char * otherlinkpath = NULL; struct dirent * gridmapdirentry; DIR * gridmapdirstream; struct stat statbuf; ino_t firstinode; if (gridmapdir == NULL) return NULL; asprintf(&firstlinkpath, "%s/%s", gridmapdir, firstlink); if (firstlinkpath == NULL) /* Out of memory */ return NULL; ret = stat(firstlinkpath, &statbuf); free(firstlinkpath); firstlinkpath = NULL; if (ret != 0) return NULL; if (statbuf.st_nlink == 1) return NULL; if (statbuf.st_nlink > 2) { /*fprintf(stderr,"lcmaps_gridlist(): too many hardlinks found (%ld) for %s\n", statbuf.st_nlink, firstlink);*/ return NULL; } firstinode = statbuf.st_ino; /* save for comparisons */ if ((gridmapdirstream = opendir(gridmapdir)) == NULL) { /*fprintf(stderr,"lcmaps_gridlist(): error opening directory %s: %s\n", gridmapdir, strerror(errno));*/ return NULL; } if (gridmapdirstream != NULL) { while ((gridmapdirentry = readdir(gridmapdirstream)) != NULL) { if (strcmp(gridmapdirentry->d_name, firstlink) == 0) continue; asprintf(&otherlinkpath, "%s/%s", gridmapdir, gridmapdirentry->d_name); if (otherlinkpath == NULL) /* Out of memory */ return NULL; ret = stat(otherlinkpath, &statbuf); if ((ret == 0) && (statbuf.st_ino == firstinode)) { /* Thouch the file before returning for lease renewal */ utime(otherlinkpath, (struct utimbuf *) NULL); free(otherlinkpath); otherlinkpath = NULL; otherlinkdup = strdup(gridmapdirentry->d_name); closedir(gridmapdirstream); return otherlinkdup; } else { free(otherlinkpath); otherlinkpath = NULL; } } closedir(gridmapdirstream); } return NULL; } char * gridmapdir_urlencode(const char * rawstring) { int encodedchar = 0; int rawchar = 0; char * encodedstring = NULL; /* Allocate enough space to fit the whole string in incase every thing has to be encoded */ encodedstring = (char*)malloc(3 * strlen(rawstring) + 1); if (encodedstring == NULL) return NULL; while (rawstring[rawchar] != '\0') { if (isalnum(rawstring[rawchar])) { encodedstring[encodedchar] = tolower(rawstring[rawchar]); ++rawchar; ++encodedchar; } else if (rawstring[rawchar] == '\001' ) { sprintf(&encodedstring[encodedchar],":%s",rawstring+rawchar+1); encodedchar += strlen(rawstring+rawchar+1) + 1; break; } else { sprintf(&encodedstring[encodedchar], "%%%02x", rawstring[rawchar]); ++rawchar; encodedchar = encodedchar + 3; } } /* terminate the string */ encodedstring[encodedchar] = '\0'; return encodedstring; } /* void */ /* is linked in in plugin, so should not be exported, because otherwise available to other */ /* plugins */ int gridmapdir_newlease(const char * gridmapdir, const char * encodedglobusidp, const char * usernameprefix, unsigned short matching_type) { int ret; char * userfilename; char * encodedfilename = NULL; struct dirent * gridmapdirentry; DIR * gridmapdirstream; struct stat statbuf; if (gridmapdir == NULL) return 1; asprintf(&encodedfilename, "%s/%s", gridmapdir, encodedglobusidp); if (encodedfilename == NULL) /* Out of memory */ return 2; if (stat(encodedfilename, &statbuf) == 0) { /* encodedfilename exists, but has only one link (itself) --> remove it */ if (statbuf.st_nlink == 1) { /*lcmaps_log_debug (1, "%s: removing solitary leasename: %s\n", __func__, encodedfilename);*/ unlink(encodedfilename); } } /* Previously it was not checked if gridmapdir existed ! Do it now */ if ((gridmapdirstream = opendir(gridmapdir)) == NULL) { /*lcmaps_log_debug (1, "%s: error opening directory %s: %s\n", __func__, gridmapdir, strerror(errno));*/ return 3; } while ((gridmapdirentry = readdir(gridmapdirstream)) != NULL) { /* we dont want any files that dont look like acceptable usernames */ if (*(gridmapdirentry->d_name) == '%') continue; if (strcmp(gridmapdirentry->d_name, "root") == 0) continue; if (*(gridmapdirentry->d_name) == '.') continue; if (index(gridmapdirentry->d_name, '~') != NULL) continue; /* Check if the lease is beginnig with usernameprefix */ if (match_username(gridmapdirentry->d_name, usernameprefix, matching_type) != 0) continue; asprintf(&userfilename, "%s/%s", gridmapdir, gridmapdirentry->d_name); if (userfilename == NULL) /* Out of memory */ return 4; stat(userfilename, &statbuf); /* files with one link are not leased yet */ if (statbuf.st_nlink == 1) { ret = link(userfilename, encodedfilename); free(userfilename); if (ret != 0) { /* * link failed: this is probably because a VERY lucky * other process has obtained a lease for encodedfilename * while we were faffing around * OR the encodedfilename is already linked to another lease name ! */ /*lcmaps_log_debug(2, "%s: could not link\n", __func__);*/ closedir(gridmapdirstream); free(encodedfilename); return 5; } stat(encodedfilename, &statbuf); if (statbuf.st_nlink > 2) { /* two globusIDs have grabbed the same username: back off */ /* TODO it will prevent more conflicts if there is a random wait at this point */ unlink(encodedfilename); continue; } closedir(gridmapdirstream); free(encodedfilename); return 0; /* link worked ok, so return */ } else { free(userfilename); /* already in use, try next one */ } } /*lcmaps_log_debug (1, "%s: Unable to lease a poolaccount in gridmapdir: %s\n", __func__, gridmapdir);*/ closedir(gridmapdirstream); free(encodedfilename); return 6; /* no unleased names left: give up */ } int gridmapdir_userid(const char * gridmapdir, const char * globusidp, const char * usernameprefix, char ** useridp, unsigned short matching_type) { char * encodedfilename = NULL; char * encodedglobusidp = NULL; int rc = 0; struct stat statbuf; *useridp = NULL; /* must be a proper subject DN */ if (globusidp[0] != '/'){ rc = 4; goto cleanup; } encodedglobusidp = gridmapdir_urlencode(globusidp); /* Check if there was memory to create the encoded globusid */ if (encodedglobusidp == NULL) { rc = 3; goto cleanup; } /* Check if this lease is already available */ *useridp = gridmapdir_otherlink(gridmapdir, encodedglobusidp); /* * Check if we're running in safe mode (ONLY_USE_EXISTING_LEASE flag is set) * If so, we will neither create a new lease nor (re)move leases and * only return a username if it matches the prefix */ if ((matching_type&ONLY_USE_EXISTING_LEASE) == ONLY_USE_EXISTING_LEASE) { if (*useridp == NULL){ /* Will not try to create another lease! */ rc = 1; goto cleanup; } } /* * The lease is inconsistent with the usernameprefix from the grid-mapfile. * If OVERRIDE_INCONSISTANCY is set, remove the lease and set *useridp to NULL and * start over again. */ if ((*useridp != NULL) && ((match_username(*useridp, usernameprefix, matching_type)) != 0)) { /* unlink the DN if the 'OVERRIDE_INCONSISTENCY' parameter is added to 'matching_type' */ if ((matching_type&OVERRIDE_INCONSISTANCY) == OVERRIDE_INCONSISTANCY) { /* TODO extract new function "gridmapdir_removelease(const char * gridmapdir, const char * encodedglobusidp)"*/ /* full filepath building */ asprintf(&encodedfilename, "%s/%s", gridmapdir, encodedglobusidp); if (encodedfilename == NULL){ /* Out of memory */ rc = 3; goto cleanup; } /* unlink the encodedglobusid (represents DN) */ stat(encodedfilename, &statbuf); if (statbuf.st_nlink == 2) { /* Unlink the file found and clear all buffers*/ unlink(encodedfilename); free(encodedfilename); encodedfilename = NULL; free(*useridp); *useridp = NULL; } else { rc = 4; goto cleanup; } } else { rc = 1; goto cleanup; } } /* If there is still no lease create one */ if (*useridp == NULL) { /* create a new lease */ if (gridmapdir_newlease(gridmapdir, encodedglobusidp, usernameprefix, matching_type) == 0) { /* retreive the lease created by gridmapdir_newlease */ *useridp = gridmapdir_otherlink(gridmapdir, encodedglobusidp); /* check if now there is a consistent lease - possibly made by someone else */ if ((*useridp == NULL) || (match_username(*useridp, usernameprefix, matching_type) != 0)) { rc = 1; goto cleanup; } else { /* lease is valid */ rc = 0; goto cleanup; } } else { /* gridmapdir_newlease was not able to create a new lease */ rc = 8; goto cleanup; } } cleanup: free(encodedfilename); encodedfilename = NULL; free(encodedglobusidp); encodedglobusidp = NULL; if (rc != 0) { /* there was no mapping, return a NULL pointer in the useridp */ free(*useridp); *useridp = NULL; } return rc; } int gridmapdir_globusid(const char * gridmapdir, char * useridp, char ** globusidp) { int encodedptr = 0; int decodedptr = 0; char * encodedglobusidp = NULL; if (useridp[0] == '/') /* must not be a subject DN */ return 1; encodedglobusidp = gridmapdir_otherlink(gridmapdir, useridp); if (encodedglobusidp == NULL) /* not leased */ return 2; *globusidp = malloc(strlen(encodedglobusidp)+1); while (encodedglobusidp[encodedptr] != '\0') { if (encodedglobusidp[encodedptr] == ':') { sprintf((*globusidp)+decodedptr,"\001%s",encodedglobusidp+encodedptr+1); decodedptr += strlen(encodedglobusidp+encodedptr); break; } if (encodedglobusidp[encodedptr] != '%') { (*globusidp)[decodedptr] = encodedglobusidp[encodedptr]; ++encodedptr; ++decodedptr; } else { /* must be a %HH encoded character */ /* even paranoids have enemies ... */ if (encodedglobusidp[encodedptr+1] == '\0') break; if (encodedglobusidp[encodedptr+2] == '\0') break; (*globusidp)[decodedptr] = xdigit_to_value(encodedglobusidp[encodedptr+1]) * 16 + xdigit_to_value(encodedglobusidp[encodedptr+2]); encodedptr += 3; ++decodedptr; } } free(encodedglobusidp); /* terminate the string with a null byte*/ (*globusidp)[decodedptr] = '\0'; return 0; } int gridmapdir_userok(const char * gridmapdir, char * globusidp, char * userid) { char * encodedglobusidp = NULL; char * leasedname = NULL; if (globusidp[0] != '/') /* must be a proper subject DN */ return 1; encodedglobusidp = gridmapdir_urlencode(globusidp); if (encodedglobusidp != NULL){ leasedname = gridmapdir_otherlink(gridmapdir, encodedglobusidp); free(encodedglobusidp); } if (leasedname == NULL) return 1; if (strcmp(userid, leasedname) == 0) { free(leasedname); return 0; } else { free(leasedname); return 1; } } int xdigit_to_value(char xdigit) { if ((xdigit >= '0') && (xdigit <= '9')) return (xdigit - '0'); if ((xdigit >= 'a') && (xdigit <= 'f')) return (xdigit - 'a' + 0xa); if ((xdigit >= 'A') && (xdigit <= 'F')) return (xdigit - 'A' + 0xa); /* Illegal digit */ return -1; } int match_username(const char * username, const char * regex, unsigned short matching_type) { size_t size = 0; const char * rest = NULL; if (strncmp(regex, username, strlen(regex)) != 0) return -1; /* * Check if the string following the prefix consists entirely of digits * and that it is non-zero */ if ((matching_type&MATCH_STRICT_PREFIX_NUM) == MATCH_STRICT_PREFIX_NUM) { rest = username+strlen(regex); if ((size = strlen(rest)) <= 0) return -2; if ((strspn(rest, DIGIT_CHARS)) != size ) return 1; } return 0; } /****************************************************************************** End of gridmapdir functions ******************************************************************************/