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