1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 /* 30 * Interfaces to audit_class(5) (/etc/security/audit_class) 31 */ 32 33 #include <stdlib.h> 34 #include <stdio.h> 35 #include <limits.h> 36 #include <sys/types.h> 37 #include <bsm/audit.h> 38 #include <bsm/libbsm.h> 39 #include <string.h> 40 #include <synch.h> 41 42 static char au_class_fname[PATH_MAX] = AUDITCLASSFILE; 43 static FILE *au_class_file = NULL; 44 static mutex_t mutex_classfile = DEFAULTMUTEX; 45 static mutex_t mutex_classcache = DEFAULTMUTEX; 46 47 void 48 setauclass() 49 { 50 (void) mutex_lock(&mutex_classfile); 51 if (au_class_file) { 52 (void) fseek(au_class_file, 0L, 0); 53 } 54 (void) mutex_unlock(&mutex_classfile); 55 } 56 57 58 void 59 endauclass() 60 { 61 (void) mutex_lock(&mutex_classfile); 62 if (au_class_file) { 63 (void) fclose(au_class_file); 64 au_class_file = NULL; 65 } 66 (void) mutex_unlock(&mutex_classfile); 67 } 68 69 /* 70 * getauclassent(): 71 * This is not MT-safe because of the static variables. 72 */ 73 au_class_ent_t * 74 getauclassent() 75 { 76 static au_class_ent_t e; 77 static char cname[AU_CLASS_NAME_MAX]; 78 static char cdesc[AU_CLASS_DESC_MAX]; 79 80 e.ac_name = cname; 81 e.ac_desc = cdesc; 82 83 return (getauclassent_r(&e)); 84 } 85 86 /* 87 * getauclassent_r 88 * This is MT-safe if each thread passes in its own pointer 89 * to the space where the class entry is returned. Becareful 90 * to also allocate space from the cname and cdesc pointers 91 * in the au_class_ent structure. 92 */ 93 au_class_ent_t * 94 getauclassent_r(au_class_entry) 95 au_class_ent_t *au_class_entry; 96 { 97 int i, error = 0, found = 0; 98 char *s, input[256]; 99 unsigned long v; 100 101 if (au_class_entry == (au_class_ent_t *)NULL || 102 au_class_entry->ac_name == (char *)NULL || 103 au_class_entry->ac_desc == (char *)NULL) { 104 return ((au_class_ent_t *)NULL); 105 } 106 107 /* open audit class file if it isn't already */ 108 (void) mutex_lock(&mutex_classfile); 109 if (!au_class_file) { 110 if (!(au_class_file = fopen(au_class_fname, "rF"))) { 111 (void) mutex_unlock(&mutex_classfile); 112 return ((au_class_ent_t *)0); 113 } 114 } 115 116 while (fgets(input, 256, au_class_file)) { 117 if (input[0] != '#') { 118 s = input + strspn(input, " \t\r\n"); 119 if ((*s == '\0') || (*s == '#')) { 120 continue; 121 } 122 found = 1; 123 s = input; 124 125 /* parse bitfield */ 126 i = strcspn(s, ":"); 127 s[i] = '\0'; 128 if (strncmp(s, "0x", 2) == 0) { 129 (void) sscanf(&s[2], "%lx", &v); 130 } else { 131 (void) sscanf(s, "%lu", &v); 132 } 133 au_class_entry->ac_class = v; 134 s = &s[i+1]; 135 136 /* parse class name */ 137 i = strcspn(s, ":"); 138 s[i] = '\0'; 139 (void) strncpy(au_class_entry->ac_name, s, 140 AU_CLASS_NAME_MAX); 141 s = &s[i+1]; 142 143 /* parse class description */ 144 i = strcspn(s, "\n\0"); 145 s[i] = '\0'; 146 (void) strncpy(au_class_entry->ac_desc, s, 147 AU_CLASS_DESC_MAX); 148 149 break; 150 } 151 } 152 153 (void) mutex_unlock(&mutex_classfile); 154 155 if (!error && found) { 156 return (au_class_entry); 157 } else { 158 return ((au_class_ent_t *)0); 159 } 160 } 161 162 163 au_class_ent_t * 164 #ifdef __STDC__ 165 getauclassnam(char *name) 166 #else 167 getauclassnam(name) 168 char *name; 169 #endif 170 { 171 static au_class_ent_t e; 172 static char cname[AU_CLASS_NAME_MAX]; 173 static char cdesc[AU_CLASS_DESC_MAX]; 174 175 e.ac_name = cname; 176 e.ac_desc = cdesc; 177 178 return (getauclassnam_r(&e, name)); 179 } 180 181 au_class_ent_t * 182 #ifdef __STDC__ 183 getauclassnam_r(au_class_ent_t *e, char *name) 184 #else 185 getauclassnam_r() 186 au_class_ent_t *e; 187 char *name; 188 #endif 189 { 190 while (getauclassent_r(e) != NULL) { 191 if (strcmp(e->ac_name, name) == 0) { 192 return (e); 193 } 194 } 195 return ((au_class_ent_t *)NULL); 196 } 197 198 199 /* 200 * xcacheauclass: 201 * Read the entire audit_class file into memory. 202 * Return a pointer to the requested entry in the cache 203 * or a pointer to an invalid entry if the the class 204 * requested is not known. 205 * 206 * Return < 0, do not set result pointer, if error. 207 * Return 0, set result pointer to invalid entry, if class not in cache. 208 * Return 1, set result pointer to a valid entry, if class is in cache. 209 */ 210 static int 211 xcacheauclass(result, class_name, class_no, flags) 212 au_class_ent_t **result; /* set this pointer to an entry in the cache */ 213 char *class_name; /* name of class to look up */ 214 au_class_t class_no; 215 int flags; 216 { 217 static int invalid; 218 static au_class_ent_t **class_tbl; 219 static int called_once; 220 static int lines = 0; 221 222 char line[256]; 223 FILE *fp; 224 au_class_ent_t *p_class; 225 int i; 226 int hit = 0; 227 char *s; 228 229 (void) mutex_lock(&mutex_classcache); 230 if (called_once == 0) { 231 232 /* Count number of lines in the class file */ 233 if ((fp = fopen(au_class_fname, "rF")) == NULL) { 234 (void) mutex_unlock(&mutex_classcache); 235 return (-1); 236 } 237 while (fgets(line, 256, fp) != NULL) { 238 s = line + strspn(line, " \t\r\n"); 239 if ((*s == '\0') || (*s == '#')) { 240 continue; 241 } 242 lines++; 243 } 244 (void) fclose(fp); 245 class_tbl = (au_class_ent_t **)calloc((size_t)lines + 1, 246 sizeof (au_class_ent_t)); 247 if (class_tbl == NULL) { 248 (void) mutex_unlock(&mutex_classcache); 249 return (-2); 250 } 251 252 lines = 0; 253 setauclass(); 254 /* 255 * This call to getauclassent is protected by 256 * mutex_classcache, so we don't need to use the thread- 257 * safe version (getauclassent_r). 258 */ 259 while ((p_class = getauclassent()) != NULL) { 260 class_tbl[lines] = (au_class_ent_t *) 261 malloc(sizeof (au_class_ent_t)); 262 if (class_tbl[lines] == NULL) { 263 (void) mutex_unlock(&mutex_classcache); 264 return (-3); 265 } 266 class_tbl[lines]->ac_name = strdup(p_class->ac_name); 267 class_tbl[lines]->ac_class = p_class->ac_class; 268 class_tbl[lines]->ac_desc = strdup(p_class->ac_desc); 269 #ifdef DEBUG2 270 printclass(class_tbl[lines]); 271 #endif 272 lines++; 273 } 274 endauclass(); 275 invalid = lines; 276 class_tbl[invalid] = (au_class_ent_t *) 277 malloc(sizeof (au_class_ent_t)); 278 if (class_tbl[invalid] == NULL) { 279 (void) mutex_unlock(&mutex_classcache); 280 return (-4); 281 } 282 class_tbl[invalid]->ac_name = "invalid class"; 283 class_tbl[invalid]->ac_class = 0; 284 class_tbl[invalid]->ac_desc = class_tbl[invalid]->ac_name; 285 286 called_once = 1; 287 288 #ifdef DEBUG2 289 for (i = 0; i <= lines; i++) { 290 printclass(class_tbl[i]); 291 } 292 #endif 293 294 } /* END if called_once */ 295 *result = class_tbl[invalid]; 296 if (flags & AU_CACHE_NAME) { 297 for (i = 0; i < lines; i++) { 298 if (strcmp(class_name, class_tbl[i]->ac_name) == 0) { 299 *result = class_tbl[i]; 300 hit = 1; 301 break; 302 } 303 } 304 } else if (flags & AU_CACHE_NUMBER) { 305 for (i = 0; i < lines; i++) { 306 if (class_no == class_tbl[i]->ac_class) { 307 *result = class_tbl[i]; 308 hit = 1; 309 break; 310 } 311 } 312 } 313 (void) mutex_unlock(&mutex_classcache); 314 return (hit); 315 } 316 317 318 int 319 #ifdef __STDC__ 320 cacheauclass(au_class_ent_t **result, au_class_t class_no) 321 #else 322 cacheauclass(result, class_no) 323 au_class_ent_t **result; /* set this pointer to an entry in the cache */ 324 au_class_t class_no; 325 #endif 326 { 327 return (xcacheauclass(result, "", class_no, AU_CACHE_NUMBER)); 328 } 329 330 331 int 332 #ifdef __STDC__ 333 cacheauclassnam(au_class_ent_t **result, char *class_name) 334 #else 335 cacheauclassnam(result, class_name) 336 au_class_ent_t **result; /* set this pointer to an entry in the cache */ 337 char *class_name; 338 #endif 339 { 340 return (xcacheauclass(result, class_name, (au_class_t)0, 341 AU_CACHE_NAME)); 342 } 343 344 345 #ifdef DEBUG2 346 void 347 printclass(p_c) 348 au_class_ent_t *p_c; 349 { 350 printf("%x:%s:%s\n", p_c->ac_class, p_c->ac_name, p_c->ac_desc); 351 fflush(stdout); 352 } 353 354 355 #endif 356