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