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