#include #include #include #include #include #include #include #include #define CATEGORYFILE "/etc/secat.conf" /* Define data structures */ typedef struct selevel { char* name; char* sename; } selevel_t; /* catlist is a simple linked list of selevels extracted from the CATEGORYFILE */ typedef struct cat { struct cat *next; selevel_t level; } cat_t; static cat_t *catlist=NULL; /* Remove excess white space */ static char *strtrim(char *dest, char *source, int size) { int i=0; char *ptr=source; i=0; while(isspace(*ptr) && i < size) { ptr++; i++; } strncpy(dest,ptr,size); for(i=strlen(dest)-1; i> 0; i--) { if (!isspace(dest[i])) break; } dest[i+1]='\0'; return dest; } /* Process line from CATEGORYFILE. Remove white space and set name do data before the "=" and sename to data after it */ static int process_category(char *buffer, cat_t **cat) { char name[BUFSIZ]; char name1[BUFSIZ]; int namesize=sizeof(name); struct cat *next; char *ptr; char *tok=strtok_r(buffer,"=",&ptr); if (!tok) return 0; strncpy(name1,tok, BUFSIZ-1); strtrim(name,name1,namesize-1); if ( name[0]=='#' ) return 0; tok=strtok_r(NULL,"\0",&ptr); if (!tok) return 0; while (isspace(*tok)) tok++; next=(cat_t *) calloc(sizeof(cat_t), 1); if (!next) return 0; next->level.name=strdup(name); if (!next->level.name) { free(next); return 0; } strncpy(name1,tok, BUFSIZ-1); strtrim(name,name1,namesize-1); next->level.sename=strdup(name); if (!next->level.sename) { free(next->level.name); free(next); return 0; } *cat=next; return 1; } /* Read in CATEGORYFILE Only runs once per process. Might want to change to some kind of reload eventually, for long running processes. */ int init_context_translations() { FILE *cfg; cat_t *ptr=NULL; cat_t *next=NULL; size_t size=0; char *buffer=NULL; int ctr=0; if (catlist) return 0; cfg = fopen(CATEGORYFILE,"r"); if (cfg == NULL) return 1; ptr=catlist=calloc(1,sizeof(cat_t)); while (getline(&buffer, &size, cfg) > 0) { if (process_category(buffer, &next)) { ctr++; ptr->next=next; ptr=next; } } if (buffer) free(buffer); return 0; } /* Look for selevel via internal name */ static char *translate(const char *cat) { cat_t *ptr=NULL; if (catlist) for (ptr=catlist->next;ptr; ptr=ptr->next) if (strcmp(cat,ptr->level.name)==0) return strdup(ptr->level.sename); return strdup(cat); } /* Look for selevel via external name */ static char *untranslate(const char *sename) { cat_t *ptr=NULL; if (catlist) for(ptr=catlist->next;ptr; ptr=ptr->next) if (strcmp(sename,ptr->level.sename)==0) return strdup(ptr->level.name); return strdup(sename); } /* Look for selevel via external name */ int translate_context( const security_context_t oldcon, security_context_t *rcon) { const char *range=NULL; char *newrange=NULL; const char *ptr=NULL; context_t con=context_new(oldcon); if (! con) return -1; range=context_range_get(con); if (range) { if(strcmp(range,"s0") == 0 ) { context_range_set(con,NULL); } else { ptr=strrchr(range,':'); if (ptr) ptr++; else ptr=range; newrange=translate(ptr); if (newrange) { context_range_set(con,newrange); } } } *rcon=strdup(context_str(con)); context_free(con); return 0; } /* Look for selevel via external name */ int untranslate_context( const security_context_t oldcon, security_context_t *rcon) { const char *range=NULL; char *newrange=NULL; context_t con=context_new(oldcon); if (! con) return -1; range=context_range_get(con); if (range) { newrange=untranslate(range); if (newrange) { context_range_set(con,newrange); } } *rcon=strdup(context_str(con)); context_free(con); return 0; }