1 /*- 2 * Copyright (c) 2004 Apple Inc. 3 * Copyright (c) 2006 Robert N. M. Watson 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. Neither the name of Apple Inc. ("Apple") nor the names of 15 * its contributors may be used to endorse or promote products derived 16 * from this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND 19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR 22 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 26 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 27 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 * POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31 #include <config/config.h> 32 33 #include <bsm/libbsm.h> 34 35 #include <string.h> 36 #ifdef HAVE_PTHREAD_MUTEX_LOCK 37 #include <pthread.h> 38 #endif 39 #include <stdio.h> 40 #include <stdlib.h> 41 42 #ifndef HAVE_STRLCPY 43 #include <compat/strlcpy.h> 44 #endif 45 46 /* 47 * Parse the contents of the audit_user file into au_user_ent structures. 48 */ 49 50 static FILE *fp = NULL; 51 static char linestr[AU_LINE_MAX]; 52 static const char *user_delim = ":"; 53 54 #ifdef HAVE_PTHREAD_MUTEX_LOCK 55 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; 56 #endif 57 58 /* 59 * Parse one line from the audit_user file into the au_user_ent structure. 60 */ 61 static struct au_user_ent * 62 userfromstr(char *str, struct au_user_ent *u) 63 { 64 char *username, *always, *never; 65 char *last; 66 67 username = strtok_r(str, user_delim, &last); 68 always = strtok_r(NULL, user_delim, &last); 69 never = strtok_r(NULL, user_delim, &last); 70 71 if ((username == NULL) || (always == NULL) || (never == NULL)) 72 return (NULL); 73 74 if (strlen(username) >= AU_USER_NAME_MAX) 75 return (NULL); 76 77 strlcpy(u->au_name, username, AU_USER_NAME_MAX); 78 if (getauditflagsbin(always, &(u->au_always)) == -1) 79 return (NULL); 80 81 if (getauditflagsbin(never, &(u->au_never)) == -1) 82 return (NULL); 83 84 return (u); 85 } 86 87 /* 88 * Rewind to beginning of the file 89 */ 90 static void 91 setauuser_locked(void) 92 { 93 94 if (fp != NULL) 95 fseek(fp, 0, SEEK_SET); 96 } 97 98 void 99 setauuser(void) 100 { 101 102 #ifdef HAVE_PTHREAD_MUTEX_LOCK 103 pthread_mutex_lock(&mutex); 104 #endif 105 setauuser_locked(); 106 #ifdef HAVE_PTHREAD_MUTEX_LOCK 107 pthread_mutex_unlock(&mutex); 108 #endif 109 } 110 111 /* 112 * Close the file descriptor 113 */ 114 void 115 endauuser(void) 116 { 117 118 #ifdef HAVE_PTHREAD_MUTEX_LOCK 119 pthread_mutex_lock(&mutex); 120 #endif 121 if (fp != NULL) { 122 fclose(fp); 123 fp = NULL; 124 } 125 #ifdef HAVE_PTHREAD_MUTEX_LOCK 126 pthread_mutex_unlock(&mutex); 127 #endif 128 } 129 130 /* 131 * Enumerate the au_user_ent structures from the file 132 */ 133 static struct au_user_ent * 134 getauuserent_r_locked(struct au_user_ent *u) 135 { 136 char *nl; 137 138 if ((fp == NULL) && ((fp = fopen(AUDIT_USER_FILE, "r")) == NULL)) 139 return (NULL); 140 141 while (1) { 142 if (fgets(linestr, AU_LINE_MAX, fp) == NULL) 143 return (NULL); 144 145 /* Remove new lines. */ 146 if ((nl = strrchr(linestr, '\n')) != NULL) 147 *nl = '\0'; 148 149 /* Skip comments. */ 150 if (linestr[0] == '#') 151 continue; 152 153 /* Get the next structure. */ 154 if (userfromstr(linestr, u) == NULL) 155 return (NULL); 156 break; 157 } 158 159 return (u); 160 } 161 162 struct au_user_ent * 163 getauuserent_r(struct au_user_ent *u) 164 { 165 struct au_user_ent *up; 166 167 #ifdef HAVE_PTHREAD_MUTEX_LOCK 168 pthread_mutex_lock(&mutex); 169 #endif 170 up = getauuserent_r_locked(u); 171 #ifdef HAVE_PTHREAD_MUTEX_LOCK 172 pthread_mutex_unlock(&mutex); 173 #endif 174 return (up); 175 } 176 177 struct au_user_ent * 178 getauuserent(void) 179 { 180 static char user_ent_name[AU_USER_NAME_MAX]; 181 static struct au_user_ent u; 182 183 bzero(&u, sizeof(u)); 184 bzero(user_ent_name, sizeof(user_ent_name)); 185 u.au_name = user_ent_name; 186 187 return (getauuserent_r(&u)); 188 } 189 190 /* 191 * Find a au_user_ent structure matching the given user name. 192 */ 193 struct au_user_ent * 194 getauusernam_r(struct au_user_ent *u, const char *name) 195 { 196 struct au_user_ent *up; 197 198 if (name == NULL) 199 return (NULL); 200 201 #ifdef HAVE_PTHREAD_MUTEX_LOCK 202 pthread_mutex_lock(&mutex); 203 #endif 204 205 setauuser_locked(); 206 while ((up = getauuserent_r_locked(u)) != NULL) { 207 if (strcmp(name, u->au_name) == 0) { 208 #ifdef HAVE_PTHREAD_MUTEX_LOCK 209 pthread_mutex_unlock(&mutex); 210 #endif 211 return (up); 212 } 213 } 214 215 #ifdef HAVE_PTHREAD_MUTEX_LOCK 216 pthread_mutex_unlock(&mutex); 217 #endif 218 return (NULL); 219 220 } 221 222 struct au_user_ent * 223 getauusernam(const char *name) 224 { 225 static char user_ent_name[AU_USER_NAME_MAX]; 226 static struct au_user_ent u; 227 228 bzero(&u, sizeof(u)); 229 bzero(user_ent_name, sizeof(user_ent_name)); 230 u.au_name = user_ent_name; 231 232 return (getauusernam_r(&u, name)); 233 } 234 235 /* 236 * Read the default system wide audit classes from audit_control, combine with 237 * the per-user audit class and update the binary preselection mask. 238 */ 239 int 240 au_user_mask(char *username, au_mask_t *mask_p) 241 { 242 char auditstring[MAX_AUDITSTRING_LEN + 1]; 243 char user_ent_name[AU_USER_NAME_MAX]; 244 struct au_user_ent u, *up; 245 246 bzero(&u, sizeof(u)); 247 bzero(user_ent_name, sizeof(user_ent_name)); 248 u.au_name = user_ent_name; 249 250 /* Get user mask. */ 251 if ((up = getauusernam_r(&u, username)) != NULL) { 252 if (-1 == getfauditflags(&up->au_always, &up->au_never, 253 mask_p)) 254 return (-1); 255 return (0); 256 } 257 258 /* Read the default system mask. */ 259 if (getacflg(auditstring, MAX_AUDITSTRING_LEN) == 0) { 260 if (-1 == getauditflagsbin(auditstring, mask_p)) 261 return (-1); 262 return (0); 263 } 264 265 /* No masks defined. */ 266 return (-1); 267 } 268 269 /* 270 * Generate the process audit state by combining the audit masks passed as 271 * parameters with the system audit masks. 272 */ 273 int 274 getfauditflags(au_mask_t *usremask, au_mask_t *usrdmask, au_mask_t *lastmask) 275 { 276 char auditstring[MAX_AUDITSTRING_LEN + 1]; 277 278 if ((usremask == NULL) || (usrdmask == NULL) || (lastmask == NULL)) 279 return (-1); 280 281 lastmask->am_success = 0; 282 lastmask->am_failure = 0; 283 284 /* Get the system mask. */ 285 if (getacflg(auditstring, MAX_AUDITSTRING_LEN) == 0) { 286 if (getauditflagsbin(auditstring, lastmask) != 0) 287 return (-1); 288 } 289 290 ADDMASK(lastmask, usremask); 291 SUBMASK(lastmask, usrdmask); 292 293 return (0); 294 } 295