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 * $P4: //depot/projects/trustedbsd/openbsm/libbsm/bsm_user.c#20 $ 31 */ 32 33 #include <config/config.h> 34 35 #include <bsm/libbsm.h> 36 37 #include <string.h> 38 #ifdef HAVE_PTHREAD_MUTEX_LOCK 39 #include <pthread.h> 40 #endif 41 #include <stdio.h> 42 #include <stdlib.h> 43 44 #ifndef HAVE_STRLCPY 45 #include <compat/strlcpy.h> 46 #endif 47 48 /* 49 * Parse the contents of the audit_user file into au_user_ent structures. 50 */ 51 52 static FILE *fp = NULL; 53 static char linestr[AU_LINE_MAX]; 54 static const char *user_delim = ":"; 55 56 #ifdef HAVE_PTHREAD_MUTEX_LOCK 57 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; 58 #endif 59 60 /* 61 * Parse one line from the audit_user file into the au_user_ent structure. 62 */ 63 static struct au_user_ent * 64 userfromstr(char *str, struct au_user_ent *u) 65 { 66 char *username, *always, *never; 67 char *last; 68 69 username = strtok_r(str, user_delim, &last); 70 always = strtok_r(NULL, user_delim, &last); 71 never = strtok_r(NULL, user_delim, &last); 72 73 if ((username == NULL) || (always == NULL) || (never == NULL)) 74 return (NULL); 75 76 if (strlen(username) >= AU_USER_NAME_MAX) 77 return (NULL); 78 79 strlcpy(u->au_name, username, AU_USER_NAME_MAX); 80 if (getauditflagsbin(always, &(u->au_always)) == -1) 81 return (NULL); 82 83 if (getauditflagsbin(never, &(u->au_never)) == -1) 84 return (NULL); 85 86 return (u); 87 } 88 89 /* 90 * Rewind to beginning of the file 91 */ 92 static void 93 setauuser_locked(void) 94 { 95 96 if (fp != NULL) 97 fseek(fp, 0, SEEK_SET); 98 } 99 100 void 101 setauuser(void) 102 { 103 104 #ifdef HAVE_PTHREAD_MUTEX_LOCK 105 pthread_mutex_lock(&mutex); 106 #endif 107 setauuser_locked(); 108 #ifdef HAVE_PTHREAD_MUTEX_LOCK 109 pthread_mutex_unlock(&mutex); 110 #endif 111 } 112 113 /* 114 * Close the file descriptor 115 */ 116 void 117 endauuser(void) 118 { 119 120 #ifdef HAVE_PTHREAD_MUTEX_LOCK 121 pthread_mutex_lock(&mutex); 122 #endif 123 if (fp != NULL) { 124 fclose(fp); 125 fp = NULL; 126 } 127 #ifdef HAVE_PTHREAD_MUTEX_LOCK 128 pthread_mutex_unlock(&mutex); 129 #endif 130 } 131 132 /* 133 * Enumerate the au_user_ent structures from the file 134 */ 135 static struct au_user_ent * 136 getauuserent_r_locked(struct au_user_ent *u) 137 { 138 char *nl; 139 140 if ((fp == NULL) && ((fp = fopen(AUDIT_USER_FILE, "r")) == NULL)) 141 return (NULL); 142 143 while (1) { 144 if (fgets(linestr, AU_LINE_MAX, fp) == NULL) 145 return (NULL); 146 147 /* Remove new lines. */ 148 if ((nl = strrchr(linestr, '\n')) != NULL) 149 *nl = '\0'; 150 151 /* Skip comments. */ 152 if (linestr[0] == '#') 153 continue; 154 155 /* Get the next structure. */ 156 if (userfromstr(linestr, u) == NULL) 157 return (NULL); 158 break; 159 } 160 161 return (u); 162 } 163 164 struct au_user_ent * 165 getauuserent_r(struct au_user_ent *u) 166 { 167 struct au_user_ent *up; 168 169 #ifdef HAVE_PTHREAD_MUTEX_LOCK 170 pthread_mutex_lock(&mutex); 171 #endif 172 up = getauuserent_r_locked(u); 173 #ifdef HAVE_PTHREAD_MUTEX_LOCK 174 pthread_mutex_unlock(&mutex); 175 #endif 176 return (up); 177 } 178 179 struct au_user_ent * 180 getauuserent(void) 181 { 182 static char user_ent_name[AU_USER_NAME_MAX]; 183 static struct au_user_ent u; 184 185 bzero(&u, sizeof(u)); 186 bzero(user_ent_name, sizeof(user_ent_name)); 187 u.au_name = user_ent_name; 188 189 return (getauuserent_r(&u)); 190 } 191 192 /* 193 * Find a au_user_ent structure matching the given user name. 194 */ 195 struct au_user_ent * 196 getauusernam_r(struct au_user_ent *u, const char *name) 197 { 198 struct au_user_ent *up; 199 200 if (name == NULL) 201 return (NULL); 202 203 #ifdef HAVE_PTHREAD_MUTEX_LOCK 204 pthread_mutex_lock(&mutex); 205 #endif 206 207 setauuser_locked(); 208 while ((up = getauuserent_r_locked(u)) != NULL) { 209 if (strcmp(name, u->au_name) == 0) { 210 #ifdef HAVE_PTHREAD_MUTEX_LOCK 211 pthread_mutex_unlock(&mutex); 212 #endif 213 return (up); 214 } 215 } 216 217 #ifdef HAVE_PTHREAD_MUTEX_LOCK 218 pthread_mutex_unlock(&mutex); 219 #endif 220 return (NULL); 221 222 } 223 224 struct au_user_ent * 225 getauusernam(const char *name) 226 { 227 static char user_ent_name[AU_USER_NAME_MAX]; 228 static struct au_user_ent u; 229 230 bzero(&u, sizeof(u)); 231 bzero(user_ent_name, sizeof(user_ent_name)); 232 u.au_name = user_ent_name; 233 234 return (getauusernam_r(&u, name)); 235 } 236 237 /* 238 * Read the default system wide audit classes from audit_control, combine with 239 * the per-user audit class and update the binary preselection mask. 240 */ 241 int 242 au_user_mask(char *username, au_mask_t *mask_p) 243 { 244 char auditstring[MAX_AUDITSTRING_LEN + 1]; 245 char user_ent_name[AU_USER_NAME_MAX]; 246 struct au_user_ent u, *up; 247 248 bzero(&u, sizeof(u)); 249 bzero(user_ent_name, sizeof(user_ent_name)); 250 u.au_name = user_ent_name; 251 252 /* Get user mask. */ 253 if ((up = getauusernam_r(&u, username)) != NULL) { 254 if (-1 == getfauditflags(&up->au_always, &up->au_never, 255 mask_p)) 256 return (-1); 257 return (0); 258 } 259 260 /* Read the default system mask. */ 261 if (getacflg(auditstring, MAX_AUDITSTRING_LEN) == 0) { 262 if (-1 == getauditflagsbin(auditstring, mask_p)) 263 return (-1); 264 return (0); 265 } 266 267 /* No masks defined. */ 268 return (-1); 269 } 270 271 /* 272 * Generate the process audit state by combining the audit masks passed as 273 * parameters with the system audit masks. 274 */ 275 int 276 getfauditflags(au_mask_t *usremask, au_mask_t *usrdmask, au_mask_t *lastmask) 277 { 278 char auditstring[MAX_AUDITSTRING_LEN + 1]; 279 280 if ((usremask == NULL) || (usrdmask == NULL) || (lastmask == NULL)) 281 return (-1); 282 283 lastmask->am_success = 0; 284 lastmask->am_failure = 0; 285 286 /* Get the system mask. */ 287 if (getacflg(auditstring, MAX_AUDITSTRING_LEN) == 0) { 288 if (getauditflagsbin(auditstring, lastmask) != 0) 289 return (-1); 290 } 291 292 ADDMASK(lastmask, usremask); 293 SUBMASK(lastmask, usrdmask); 294 295 return (0); 296 } 297