/* * Return the next au_class_entry having the given class name */ struct au_class_ent *getauclassnam(const char *name) { struct au_class_ent *c; char *nl; if(name == NULL) { return NULL; } /* Rewind to beginning of file */ setauclass(); pthread_mutex_lock(&mutex); if((fp == NULL) && ((fp = fopen(AUDIT_CLASS_FILE, "r")) == NULL)) { pthread_mutex_unlock(&mutex); return NULL; } c = get_class_area(); /* allocate */ if(c == NULL) { pthread_mutex_unlock(&mutex); return NULL; } while(fgets(linestr, AU_LINE_MAX, fp) != NULL) { /* Remove trailing new line character */ if((nl = strrchr(linestr, '\n')) != NULL) { *nl = '\0'; } /* parse tokptr to au_class_ent components */ if(classfromstr(linestr, delim, c) != NULL) { if(!strcmp(name, c->ac_name)) { pthread_mutex_unlock(&mutex); return c; } } } free_au_class_ent(c); pthread_mutex_unlock(&mutex); return NULL; }
/* * Convert the au_mask_t fields into a string value. If verbose is non-zero * the long flag names are used else the short (2-character)flag names are * used. * * XXXRW: If bits are specified that are not matched by any class, they are * omitted rather than rejected with EINVAL. * * XXXRW: This is not thread-safe as it relies on atomicity between * setauclass() and sequential calls to getauclassent(). This could be * fixed by iterating through the bitmask fields rather than iterating * through the classes. */ int getauditflagschar(char *auditstr, au_mask_t *masks, int verbose) { char class_ent_name[AU_CLASS_NAME_MAX]; char class_ent_desc[AU_CLASS_DESC_MAX]; struct au_class_ent c; char *strptr = auditstr; u_char sel; bzero(&c, sizeof(c)); bzero(class_ent_name, sizeof(class_ent_name)); bzero(class_ent_desc, sizeof(class_ent_desc)); c.ac_name = class_ent_name; c.ac_desc = class_ent_desc; /* * Enumerate the class entries, check if each is selected in either * the success or failure masks. */ setauclass(); while ((getauclassent_r(&c)) != NULL) { sel = 0; /* Dont do anything for class = no. */ if (c.ac_class == 0) continue; sel |= ((c.ac_class & masks->am_success) == c.ac_class) ? AU_PRS_SUCCESS : 0; sel |= ((c.ac_class & masks->am_failure) == c.ac_class) ? AU_PRS_FAILURE : 0; /* * No prefix should be attached if both success and failure * are selected. */ if ((sel & AU_PRS_BOTH) == 0) { if ((sel & AU_PRS_SUCCESS) != 0) { *strptr = '+'; strptr = strptr + 1; } else if ((sel & AU_PRS_FAILURE) != 0) { *strptr = '-'; strptr = strptr + 1; } } if (sel != 0) { if (verbose) { strlcpy(strptr, c.ac_desc, AU_CLASS_DESC_MAX); strptr += strlen(c.ac_desc); } else { strlcpy(strptr, c.ac_name, AU_CLASS_NAME_MAX); strptr += strlen(c.ac_name); } *strptr = ','; /* delimiter */ strptr = strptr + 1; } } /* Overwrite the last delimiter with the string terminator. */ if (strptr != auditstr) *(strptr-1) = '\0'; return (0); }
/* * xcacheauclass: * Read the entire audit_class file into memory. * Return a pointer to the requested entry in the cache * or a pointer to an invalid entry if the the class * requested is not known. * * Return < 0, do not set result pointer, if error. * Return 0, set result pointer to invalid entry, if class not in cache. * Return 1, set result pointer to a valid entry, if class is in cache. */ static int xcacheauclass(au_class_ent_t **result, char *class_name, au_class_t class_no, int flags) { static int invalid; static au_class_ent_t **class_tbl; static int called_once; static int lines = 0; char line[256]; FILE *fp; au_class_ent_t *p_class; int i; int hit = 0; char *s; (void) mutex_lock(&mutex_classcache); if (called_once == 0) { /* Count number of lines in the class file */ if ((fp = fopen(au_class_fname, "rF")) == NULL) { (void) mutex_unlock(&mutex_classcache); return (-1); } while (fgets(line, 256, fp) != NULL) { s = line + strspn(line, " \t\r\n"); if ((*s == '\0') || (*s == '#')) { continue; } lines++; } (void) fclose(fp); class_tbl = (au_class_ent_t **)calloc((size_t)lines + 1, sizeof (class_tbl)); if (class_tbl == NULL) { (void) mutex_unlock(&mutex_classcache); return (-2); } lines = 0; setauclass(); /* * This call to getauclassent is protected by * mutex_classcache, so we don't need to use the thread- * safe version (getauclassent_r). */ while ((p_class = getauclassent()) != NULL) { class_tbl[lines] = (au_class_ent_t *) malloc(sizeof (au_class_ent_t)); if (class_tbl[lines] == NULL) { (void) mutex_unlock(&mutex_classcache); return (-3); } class_tbl[lines]->ac_name = strdup(p_class->ac_name); class_tbl[lines]->ac_class = p_class->ac_class; class_tbl[lines]->ac_desc = strdup(p_class->ac_desc); #ifdef DEBUG2 printclass(class_tbl[lines]); #endif lines++; } endauclass(); invalid = lines; class_tbl[invalid] = (au_class_ent_t *) malloc(sizeof (au_class_ent_t)); if (class_tbl[invalid] == NULL) { (void) mutex_unlock(&mutex_classcache); return (-4); } class_tbl[invalid]->ac_name = "invalid class"; class_tbl[invalid]->ac_class = 0; class_tbl[invalid]->ac_desc = class_tbl[invalid]->ac_name; called_once = 1; #ifdef DEBUG2 for (i = 0; i <= lines; i++) { printclass(class_tbl[i]); } #endif } /* END if called_once */ *result = class_tbl[invalid]; if (flags & AU_CACHE_NAME) { for (i = 0; i < lines; i++) { if (strncmp(class_name, class_tbl[i]->ac_name, AU_CLASS_NAME_MAX) == 0) { *result = class_tbl[i]; hit = 1; break; } } } else if (flags & AU_CACHE_NUMBER) { for (i = 0; i < lines; i++) { if (class_no == class_tbl[i]->ac_class) { *result = class_tbl[i]; hit = 1; break; } } } (void) mutex_unlock(&mutex_classcache); return (hit); }