| /* |
| * CDDL HEADER START |
| * |
| * The contents of this file are subject to the terms of the |
| * Common Development and Distribution License (the "License"). |
| * You may not use this file except in compliance with the License. |
| * |
| * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE |
| * or http://www.opensolaris.org/os/licensing. |
| * See the License for the specific language governing permissions |
| * and limitations under the License. |
| * |
| * When distributing Covered Code, include this CDDL HEADER in each |
| * file and include the License file at usr/src/OPENSOLARIS.LICENSE. |
| * If applicable, add the following below this CDDL HEADER, with the |
| * fields enclosed by brackets "[]" replaced with your own identifying |
| * information: Portions Copyright [yyyy] [name of copyright owner] |
| * |
| * CDDL HEADER END |
| */ |
| /* |
| * Copyright 2006 Sun Microsystems, Inc. All rights reserved. |
| * Use is subject to license terms. |
| */ |
| |
| /* |
| * This file contains the audit hook support code for auditing. |
| */ |
| |
| #pragma ident "%Z%%M% %I% %E% SMI" |
| |
| #include <sys/types.h> |
| #include <sys/proc.h> |
| #include <sys/vnode.h> |
| #include <sys/vfs.h> |
| #include <sys/file.h> |
| #include <sys/user.h> |
| #include <sys/stropts.h> |
| #include <sys/systm.h> |
| #include <sys/pathname.h> |
| #include <sys/syscall.h> |
| #include <sys/fcntl.h> |
| #include <sys/ipc_impl.h> |
| #include <sys/msg_impl.h> |
| #include <sys/sem_impl.h> |
| #include <sys/shm_impl.h> |
| #include <sys/kmem.h> /* for KM_SLEEP */ |
| #include <sys/socket.h> |
| #include <sys/cmn_err.h> /* snprintf... */ |
| #include <sys/debug.h> |
| #include <sys/thread.h> |
| #include <netinet/in.h> |
| #include <c2/audit.h> /* needs to be included before user.h */ |
| #include <c2/audit_kernel.h> /* for M_DONTWAIT */ |
| #include <c2/audit_kevents.h> |
| #include <c2/audit_record.h> |
| #include <sys/strsubr.h> |
| #include <sys/tihdr.h> |
| #include <sys/tiuser.h> |
| #include <sys/timod.h> |
| #include <sys/model.h> /* for model_t */ |
| #include <sys/disp.h> /* for servicing_interrupt() */ |
| #include <sys/devpolicy.h> |
| #include <sys/crypto/ioctladmin.h> |
| #include <inet/kssl/kssl.h> |
| #include <sys/tsol/label.h> |
| |
| static void add_return_token(caddr_t *, unsigned int scid, int err, int rval); |
| |
| static void audit_pathbuild(struct pathname *pnp); |
| |
| /* |
| * ROUTINE: AUDIT_NEWPROC |
| * PURPOSE: initialize the child p_audit_data structure |
| * CALLBY: GETPROC |
| * NOTE: All threads for the parent process are locked at this point. |
| * We are essentially running singled threaded for this reason. |
| * GETPROC is called when system creates a new process. |
| * By the time AUDIT_NEWPROC is called, the child proc |
| * structure has already been initialized. What we need |
| * to do is to allocate the child p_audit_data and |
| * initialize it with the content of current parent process. |
| */ |
| |
| void |
| audit_newproc(struct proc *cp) /* initialized child proc structure */ |
| { |
| p_audit_data_t *pad; /* child process audit data */ |
| p_audit_data_t *opad; /* parent process audit data */ |
| |
| pad = kmem_cache_alloc(au_pad_cache, KM_SLEEP); |
| |
| P2A(cp) = pad; |
| |
| opad = P2A(curproc); |
| |
| /* |
| * copy the audit data. Note that all threads of current |
| * process have been "held". Thus there is no race condition |
| * here with mutiple threads trying to alter the cwrd |
| * structure (such as releasing it). |
| * |
| * The audit context in the cred is "duplicated" for the new |
| * proc by elsewhere crhold'ing the parent's cred which it shares. |
| * |
| * We still want to hold things since auditon() [A_SETUMASK, |
| * A_SETSMASK] could be walking through the processes to |
| * update things. |
| */ |
| mutex_enter(&opad->pad_lock); /* lock opad structure during copy */ |
| pad->pad_data = opad->pad_data; /* copy parent's process audit data */ |
| au_pathhold(pad->pad_root); |
| au_pathhold(pad->pad_cwd); |
| mutex_exit(&opad->pad_lock); /* current proc will keep cwrd open */ |
| |
| /* |
| * finish auditing of parent here so that it will be done |
| * before child has a chance to run. We include the child |
| * pid since the return value in the return token is a dummy |
| * one and contains no useful information (it is included to |
| * make the audit record structure consistant). |
| * |
| * tad_flag is set if auditing is on |
| */ |
| if (((t_audit_data_t *)T2A(curthread))->tad_flag) |
| au_uwrite(au_to_arg32(0, "child PID", (uint32_t)cp->p_pid)); |
| |
| /* |
| * finish up audit record generation here because child process |
| * is set to run before parent process. We distinguish here |
| * between FORK, FORK1, or VFORK by the saved system call ID. |
| */ |
| audit_finish(0, ((t_audit_data_t *)T2A(curthread))->tad_scid, 0, 0); |
| } |
| |
| /* |
| * ROUTINE: AUDIT_PFREE |
| * PURPOSE: deallocate the per-process udit data structure |
| * CALLBY: EXIT |
| * FORK_FAIL |
| * NOTE: all lwp except current one have stopped in SEXITLWPS |
| * why we are single threaded? |
| * . all lwp except current one have stopped in SEXITLWPS. |
| */ |
| void |
| audit_pfree(struct proc *p) /* proc structure to be freed */ |
| |
| { /* AUDIT_PFREE */ |
| |
| p_audit_data_t *pad; |
| |
| pad = P2A(p); |
| |
| /* better be a per process audit data structure */ |
| ASSERT(pad != (p_audit_data_t *)0); |
| |
| if (pad == pad0) { |
| return; |
| } |
| |
| /* deallocate all auditing resources for this process */ |
| au_pathrele(pad->pad_root); |
| au_pathrele(pad->pad_cwd); |
| |
| /* |
| * Since the pad structure is completely overwritten after alloc, |
| * we don't bother to clear it. |
| */ |
| |
| kmem_cache_free(au_pad_cache, pad); |
| } |
| |
| /* |
| * ROUTINE: AUDIT_THREAD_CREATE |
| * PURPOSE: allocate per-process thread audit data structure |
| * CALLBY: THREAD_CREATE |
| * NOTE: This is called just after *t was bzero'd. |
| * We are single threaded in this routine. |
| * TODO: |
| * QUESTION: |
| */ |
| |
| void |
| audit_thread_create(kthread_id_t t) |
| { |
| t_audit_data_t *tad; /* per-thread audit data */ |
| |
| tad = kmem_zalloc(sizeof (struct t_audit_data), KM_SLEEP); |
| |
| T2A(t) = tad; /* set up thread audit data ptr */ |
| tad->tad_thread = t; /* back ptr to thread: DEBUG */ |
| } |
| |
| /* |
| * ROUTINE: AUDIT_THREAD_FREE |
| * PURPOSE: free the per-thread audit data structure |
| * CALLBY: THREAD_FREE |
| * NOTE: most thread data is clear after return |
| */ |
| void |
| audit_thread_free(kthread_t *t) |
| { |
| t_audit_data_t *tad; |
| au_defer_info_t *attr; |
| |
| tad = T2A(t); |
| |
| /* thread audit data must still be set */ |
| |
| if (tad == tad0) { |
| return; |
| } |
| |
| if (tad == NULL) { |
| return; |
| } |
| |
| t->t_audit_data = 0; |
| |
| /* must not have any audit record residual */ |
| ASSERT(tad->tad_ad == NULL); |
| |
| /* saved path must be empty */ |
| ASSERT(tad->tad_aupath == NULL); |
| |
| if (tad->tad_atpath) |
| au_pathrele(tad->tad_atpath); |
| |
| attr = tad->tad_defer_head; |
| while (attr != NULL) { |
| au_defer_info_t *tmp_attr = attr; |
| |
| au_free_rec(attr->audi_ad); |
| |
| attr = attr->audi_next; |
| kmem_free(tmp_attr, sizeof (au_defer_info_t)); |
| } |
| |
| kmem_free(tad, sizeof (*tad)); |
| } |
| |
| /* |
| * ROUTINE: AUDIT_SAVEPATH |
| * PURPOSE: |
| * CALLBY: LOOKUPPN |
| * |
| * NOTE: We have reached the end of a path in fs/lookup.c. |
| * We get two pieces of information here: |
| * the vnode of the last component (vp) and |
| * the status of the last access (flag). |
| * TODO: |
| * QUESTION: |
| */ |
| |
| /*ARGSUSED*/ |
| int |
| audit_savepath( |
| struct pathname *pnp, /* pathname to lookup */ |
| struct vnode *vp, /* vnode of the last component */ |
| int flag, /* status of the last access */ |
| cred_t *cr) /* cred of requestor */ |
| { |
| |
| t_audit_data_t *tad; /* current thread */ |
| p_audit_data_t *pad; /* current process */ |
| au_kcontext_t *kctx = SET_KCTX_PZ; |
| |
| if (kctx == NULL) { |
| zone_status_t zstate = zone_status_get(curproc->p_zone); |
| ASSERT(zstate != ZONE_IS_READY); |
| return (0); |
| } |
| |
| tad = U2A(u); |
| ASSERT(tad != (t_audit_data_t *)0); |
| pad = P2A(curproc); |
| ASSERT(pad != (p_audit_data_t *)0); |
| |
| /* |
| * this event being audited or do we need path information |
| * later? This might be for a chdir/chroot or open (add path |
| * to file pointer. If the path has already been found for an |
| * open/creat then we don't need to process the path. |
| * |
| * S2E_SP (PAD_SAVPATH) flag comes from audit_s2e[].au_ctrl. Used with |
| * chroot, chdir, open, creat system call processing. It determines |
| * if audit_savepath() will discard the path or we need it later. |
| * PAD_PATHFND means path already included in this audit record. It |
| * is used in cases where multiple path lookups are done per |
| * system call. The policy flag, AUDIT_PATH, controls if multiple |
| * paths are allowed. |
| * S2E_NPT (PAD_NOPATH) flag comes from audit_s2e[].au_ctrl. Used with |
| * exit processing to inhibit any paths that may be added due to |
| * closes. |
| */ |
| if ((tad->tad_flag == 0 && !(tad->tad_ctrl & PAD_SAVPATH)) || |
| ((tad->tad_ctrl & PAD_PATHFND) && |
| !(kctx->auk_policy & AUDIT_PATH)) || |
| (tad->tad_ctrl & PAD_NOPATH)) { |
| return (0); |
| } |
| |
| tad->tad_ctrl |= PAD_NOPATH; /* prevent possible reentry */ |
| |
| audit_pathbuild(pnp); |
| tad->tad_vn = vp; |
| |
| /* |
| * are we auditing only if error, or if it is not open or create |
| * otherwise audit_setf will do it |
| */ |
| |
| if (tad->tad_flag) { |
| if (flag && (tad->tad_scid == SYS_open || |
| tad->tad_scid == SYS_open64 || |
| tad->tad_scid == SYS_creat || |
| tad->tad_scid == SYS_creat64 || |
| tad->tad_scid == SYS_fsat)) { |
| tad->tad_ctrl |= PAD_TRUE_CREATE; |
| } |
| |
| /* add token to audit record for this name */ |
| au_uwrite(au_to_path(tad->tad_aupath)); |
| |
| /* add the attributes of the object */ |
| if (vp) { |
| /* |
| * only capture attributes when there is no error |
| * lookup will not return the vnode of the failing |
| * component. |
| * |
| * if there was a lookup error, then don't add |
| * attribute. if lookup in vn_create(), |
| * then don't add attribute, |
| * it will be added at end of vn_create(). |
| */ |
| if (!flag && !(tad->tad_ctrl & PAD_NOATTRB)) |
| audit_attributes(vp); |
| } |
| } |
| |
| /* free up space if we're not going to save path (open, crate) */ |
| if ((tad->tad_ctrl & PAD_SAVPATH) == 0) { |
| if (tad->tad_aupath != NULL) { |
| au_pathrele(tad->tad_aupath); |
| tad->tad_aupath = NULL; |
| tad->tad_vn = NULL; |
| } |
| } |
| if (tad->tad_ctrl & PAD_MLD) |
| tad->tad_ctrl |= PAD_PATHFND; |
| |
| tad->tad_ctrl &= ~PAD_NOPATH; /* restore */ |
| return (0); |
| } |
| |
| static void |
| audit_pathbuild(struct pathname *pnp) |
| { |
| char *pp; /* pointer to path */ |
| int len; /* length of incoming segment */ |
| int newsect; /* path requires a new section */ |
| struct audit_path *pfxapp; /* prefix for path */ |
| struct audit_path *newapp; /* new audit_path */ |
| t_audit_data_t *tad; /* current thread */ |
| p_audit_data_t *pad; /* current process */ |
| |
| tad = U2A(u); |
| ASSERT(tad != NULL); |
| pad = P2A(curproc); |
| ASSERT(pad != NULL); |
| |
| len = (pnp->pn_path - pnp->pn_buf) + 1; /* +1 for terminator */ |
| ASSERT(len > 0); |
| |
| /* adjust for path prefix: tad_aupath, ATPATH, CRD, or CWD */ |
| mutex_enter(&pad->pad_lock); |
| if (tad->tad_aupath != NULL) { |
| pfxapp = tad->tad_aupath; |
| } else if (tad->tad_scid == SYS_fsat && pnp->pn_buf[0] != '/') { |
| ASSERT(tad->tad_atpath != NULL); |
| pfxapp = tad->tad_atpath; |
| } else if (tad->tad_ctrl & PAD_ABSPATH) { |
| pfxapp = pad->pad_root; |
| } else { |
| pfxapp = pad->pad_cwd; |
| } |
| au_pathhold(pfxapp); |
| mutex_exit(&pad->pad_lock); |
| |
| /* get an expanded buffer to hold the anchored path */ |
| newsect = tad->tad_ctrl & PAD_ATPATH; |
| newapp = au_pathdup(pfxapp, newsect, len); |
| au_pathrele(pfxapp); |
| |
| pp = newapp->audp_sect[newapp->audp_cnt] - len; |
| if (!newsect) { |
| /* overlay previous NUL terminator */ |
| *(pp - 1) = '/'; |
| } |
| |
| /* now add string of processed path */ |
| bcopy(pnp->pn_buf, pp, len); |
| pp[len - 1] = '\0'; |
| |
| /* perform path simplification as necessary */ |
| audit_fixpath(newapp, len); |
| |
| if (tad->tad_aupath) |
| au_pathrele(tad->tad_aupath); |
| tad->tad_aupath = newapp; |
| |
| /* for case where multiple lookups in one syscall (rename) */ |
| tad->tad_ctrl &= ~(PAD_ABSPATH | PAD_ATPATH); |
| } |
| |
| |
| |
| /*ARGSUSED*/ |
| |
| /* |
| * ROUTINE: AUDIT_ADDCOMPONENT |
| * PURPOSE: extend the path by the component accepted |
| * CALLBY: LOOKUPPN |
| * NOTE: This function is called only when there is an error in |
| * parsing a path component |
| * TODO: Add the error component to audit record |
| * QUESTION: what is this for |
| */ |
| |
| void |
| audit_addcomponent(struct pathname *pnp) |
| { |
| au_kcontext_t *kctx = SET_KCTX_PZ; |
| t_audit_data_t *tad; |
| |
| if (kctx == NULL) { |
| zone_status_t zstate = zone_status_get(curproc->p_zone); |
| ASSERT(zstate != ZONE_IS_READY); |
| return; |
| } |
| |
| tad = U2A(u); |
| /* |
| * S2E_SP (PAD_SAVPATH) flag comes from audit_s2e[].au_ctrl. Used with |
| * chroot, chdir, open, creat system call processing. It determines |
| * if audit_savepath() will discard the path or we need it later. |
| * PAD_PATHFND means path already included in this audit record. It |
| * is used in cases where multiple path lookups are done per |
| * system call. The policy flag, AUDIT_PATH, controls if multiple |
| * paths are allowed. |
| * S2E_NPT (PAD_NOPATH) flag comes from audit_s2e[].au_ctrl. Used with |
| * exit processing to inhibit any paths that may be added due to |
| * closes. |
| */ |
| if ((tad->tad_flag == 0 && !(tad->tad_ctrl & PAD_SAVPATH)) || |
| ((tad->tad_ctrl & PAD_PATHFND) && |
| !(kctx->auk_policy & AUDIT_PATH)) || |
| (tad->tad_ctrl & PAD_NOPATH)) { |
| return; |
| } |
| |
| return; |
| |
| } /* AUDIT_ADDCOMPONENT */ |
| |
| |
| |
| |
| |
| |
| |
| |
| /* |
| * ROUTINE: AUDIT_ANCHORPATH |
| * PURPOSE: |
| * CALLBY: LOOKUPPN |
| * NOTE: |
| * anchor path at "/". We have seen a symbolic link or entering for the |
| * first time we will throw away any saved path if path is anchored. |
| * |
| * flag = 0, path is relative. |
| * flag = 1, path is absolute. Free any saved path and set flag to PAD_ABSPATH. |
| * |
| * If the (new) path is absolute, then we have to throw away whatever we have |
| * already accumulated since it is being superceeded by new path which is |
| * anchored at the root. |
| * Note that if the path is relative, this function does nothing |
| * TODO: |
| * QUESTION: |
| */ |
| /*ARGSUSED*/ |
| void |
| audit_anchorpath(struct pathname *pnp, int flag) |
| { |
| au_kcontext_t *kctx = SET_KCTX_PZ; |
| t_audit_data_t *tad; |
| |
| if (kctx == NULL) { |
| zone_status_t zstate = zone_status_get(curproc->p_zone); |
| ASSERT(zstate != ZONE_IS_READY); |
| return; |
| } |
| |
| tad = U2A(u); |
| |
| /* |
| * this event being audited or do we need path information |
| * later? This might be for a chdir/chroot or open (add path |
| * to file pointer. If the path has already been found for an |
| * open/creat then we don't need to process the path. |
| * |
| * S2E_SP (PAD_SAVPATH) flag comes from audit_s2e[].au_ctrl. Used with |
| * chroot, chdir, open, creat system call processing. It determines |
| * if audit_savepath() will discard the path or we need it later. |
| * PAD_PATHFND means path already included in this audit record. It |
| * is used in cases where multiple path lookups are done per |
| * system call. The policy flag, AUDIT_PATH, controls if multiple |
| * paths are allowed. |
| * S2E_NPT (PAD_NOPATH) flag comes from audit_s2e[].au_ctrl. Used with |
| * exit processing to inhibit any paths that may be added due to |
| * closes. |
| */ |
| if ((tad->tad_flag == 0 && !(tad->tad_ctrl & PAD_SAVPATH)) || |
| ((tad->tad_ctrl & PAD_PATHFND) && |
| !(kctx->auk_policy & AUDIT_PATH)) || |
| (tad->tad_ctrl & PAD_NOPATH)) { |
| return; |
| } |
| |
| if (flag) { |
| tad->tad_ctrl |= PAD_ABSPATH; |
| if (tad->tad_aupath != NULL) { |
| au_pathrele(tad->tad_aupath); |
| tad->tad_aupath = NULL; |
| tad->tad_vn = NULL; |
| } |
| } |
| } |
| |
| |
| /* |
| * symbolic link. Save previous components. |
| * |
| * the path seen so far looks like this |
| * |
| * +-----------------------+----------------+ |
| * | path processed so far | remaining path | |
| * +-----------------------+----------------+ |
| * \-----------------------/ |
| * save this string if |
| * symbolic link relative |
| * (but don't include symlink component) |
| */ |
| |
| /*ARGSUSED*/ |
| |
| |
| /* |
| * ROUTINE: AUDIT_SYMLINK |
| * PURPOSE: |
| * CALLBY: LOOKUPPN |
| * NOTE: |
| * TODO: |
| * QUESTION: |
| */ |
| void |
| audit_symlink(struct pathname *pnp, struct pathname *sympath) |
| { |
| char *sp; /* saved initial pp */ |
| char *cp; /* start of symlink path */ |
| uint_t len_path; /* processed path before symlink */ |
| t_audit_data_t *tad; |
| au_kcontext_t *kctx = SET_KCTX_PZ; |
| |
| if (kctx == NULL) { |
| zone_status_t zstate = zone_status_get(curproc->p_zone); |
| ASSERT(zstate != ZONE_IS_READY); |
| return; |
| } |
| |
| tad = U2A(u); |
| |
| /* |
| * this event being audited or do we need path information |
| * later? This might be for a chdir/chroot or open (add path |
| * to file pointer. If the path has already been found for an |
| * open/creat then we don't need to process the path. |
| * |
| * S2E_SP (PAD_SAVPATH) flag comes from audit_s2e[].au_ctrl. Used with |
| * chroot, chdir, open, creat system call processing. It determines |
| * if audit_savepath() will discard the path or we need it later. |
| * PAD_PATHFND means path already included in this audit record. It |
| * is used in cases where multiple path lookups are done per |
| * system call. The policy flag, AUDIT_PATH, controls if multiple |
| * paths are allowed. |
| * S2E_NPT (PAD_NOPATH) flag comes from audit_s2e[].au_ctrl. Used with |
| * exit processing to inhibit any paths that may be added due to |
| * closes. |
| */ |
| if ((tad->tad_flag == 0 && |
| !(tad->tad_ctrl & PAD_SAVPATH)) || |
| ((tad->tad_ctrl & PAD_PATHFND) && |
| !(kctx->auk_policy & AUDIT_PATH)) || |
| (tad->tad_ctrl & PAD_NOPATH)) { |
| return; |
| } |
| |
| /* |
| * if symbolic link is anchored at / then do nothing. |
| * When we cycle back to begin: in lookuppn() we will |
| * call audit_anchorpath() with a flag indicating if the |
| * path is anchored at / or is relative. We will release |
| * any saved path at that point. |
| * |
| * Note In the event that an error occurs in pn_combine then |
| * we want to remain pointing at the component that caused the |
| * path to overflow the pnp structure. |
| */ |
| if (sympath->pn_buf[0] == '/') |
| return; |
| |
| /* backup over last component */ |
| sp = cp = pnp->pn_path; |
| while (*--cp != '/' && cp > pnp->pn_buf) |
| ; |
| |
| len_path = cp - pnp->pn_buf; |
| |
| /* is there anything to save? */ |
| if (len_path) { |
| pnp->pn_path = cp; |
| audit_pathbuild(pnp); |
| pnp->pn_path = sp; |
| } |
| } |
| |
| /* |
| * file_is_public : determine whether events for the file (corresponding to |
| * the specified file attr) should be audited or ignored. |
| * |
| * returns: 1 - if audit policy and file attributes indicate that |
| * file is effectively public. read events for |
| * the file should not be audited. |
| * 0 - otherwise |
| * |
| * The required attributes to be considered a public object are: |
| * - owned by root, AND |
| * - world-readable (permissions for other include read), AND |
| * - NOT world-writeable (permissions for other don't |
| * include write) |
| * (mode doesn't need to be checked for symlinks) |
| */ |
| int |
| file_is_public(struct vattr *attr) |
| { |
| au_kcontext_t *kctx = SET_KCTX_PZ; |
| |
| if (kctx == NULL) { |
| zone_status_t zstate = zone_status_get(curproc->p_zone); |
| ASSERT(zstate != ZONE_IS_READY); |
| return (0); |
| } |
| |
| if (!(kctx->auk_policy & AUDIT_PUBLIC) && (attr->va_uid == 0) && |
| ((attr->va_type == VLNK) || |
| ((attr->va_mode & (VREAD>>6)) != 0) && |
| ((attr->va_mode & (VWRITE>>6)) == 0))) { |
| return (1); |
| } |
| return (0); |
| } |
| |
| |
| /* |
| * ROUTINE: AUDIT_ATTRIBUTES |
| * PURPOSE: Audit the attributes so we can tell why the error occured |
| * CALLBY: AUDIT_SAVEPATH |
| * AUDIT_VNCREATE_FINISH |
| * AUS_FCHOWN...audit_event.c...audit_path.c |
| * NOTE: |
| * TODO: |
| * QUESTION: |
| */ |
| void |
| audit_attributes(struct vnode *vp) |
| { |
| struct vattr attr; |
| struct t_audit_data *tad; |
| |
| tad = U2A(u); |
| |
| if (vp) { |
| attr.va_mask = AT_ALL; |
| if (VOP_GETATTR(vp, &attr, 0, CRED()) != 0) |
| return; |
| |
| if (file_is_public(&attr) && (tad->tad_ctrl & PAD_PUBLIC_EV)) { |
| /* |
| * This is a public object and a "public" event |
| * (i.e., read only) -- either by definition |
| * (e.g., stat, access...) or by virtue of write access |
| * not being requested (e.g. mmap). |
| * Flag it in the tad to prevent this audit at the end. |
| */ |
| tad->tad_ctrl |= PAD_NOAUDIT; |
| } else { |
| au_uwrite(au_to_attr(&attr)); |
| audit_sec_attributes(&(u_ad), vp); |
| } |
| } |
| } |
| |
| |
| /* |
| * ROUTINE: AUDIT_FALLOC |
| * PURPOSE: allocating a new file structure |
| * CALLBY: FALLOC |
| * NOTE: file structure already initialized |
| * TODO: |
| * QUESTION: |
| */ |
| |
| void |
| audit_falloc(struct file *fp) |
| { /* AUDIT_FALLOC */ |
| |
| f_audit_data_t *fad; |
| |
| /* allocate per file audit structure if there a'int any */ |
| ASSERT(F2A(fp) == NULL); |
| |
| fad = kmem_zalloc(sizeof (struct f_audit_data), KM_SLEEP); |
| |
| F2A(fp) = fad; |
| |
| fad->fad_thread = curthread; /* file audit data back ptr; DEBUG */ |
| } |
| |
| /* |
| * ROUTINE: AUDIT_UNFALLOC |
| * PURPOSE: deallocate file audit data structure |
| * CALLBY: CLOSEF |
| * UNFALLOC |
| * NOTE: |
| * TODO: |
| * QUESTION: |
| */ |
| |
| void |
| audit_unfalloc(struct file *fp) |
| { |
| f_audit_data_t *fad; |
| |
| fad = F2A(fp); |
| |
| if (!fad) { |
| return; |
| } |
| if (fad->fad_aupath != NULL) { |
| au_pathrele(fad->fad_aupath); |
| } |
| fp->f_audit_data = 0; |
| kmem_free(fad, sizeof (struct f_audit_data)); |
| } |
| |
| /* |
| * ROUTINE: AUDIT_EXIT |
| * PURPOSE: |
| * CALLBY: EXIT |
| * NOTE: |
| * TODO: |
| * QUESTION: why cmw code as offset by 2 but not here |
| */ |
| /* ARGSUSED */ |
| void |
| audit_exit(int code, int what) |
| { |
| struct t_audit_data *tad; |
| tad = U2A(u); |
| |
| /* |
| * tad_scid will be set by audit_start even if we are not auditing |
| * the event. |
| */ |
| if (tad->tad_scid == SYS_exit) { |
| /* |
| * if we are auditing the exit system call, then complete |
| * audit record generation (no return from system call). |
| */ |
| if (tad->tad_flag && tad->tad_event == AUE_EXIT) |
| audit_finish(0, SYS_exit, 0, 0); |
| return; |
| } |
| |
| /* |
| * Anyone auditing the system call that was aborted? |
| */ |
| if (tad->tad_flag) { |
| au_uwrite(au_to_text("event aborted")); |
| audit_finish(0, tad->tad_scid, 0, 0); |
| } |
| |
| /* |
| * Generate an audit record for process exit if preselected. |
| */ |
| (void) audit_start(0, SYS_exit, 0, 0); |
| audit_finish(0, SYS_exit, 0, 0); |
| } |
| |
| /* |
| * ROUTINE: AUDIT_CORE_START |
| * PURPOSE: |
| * CALLBY: PSIG |
| * NOTE: |
| * TODO: |
| */ |
| void |
| audit_core_start(int sig) |
| { |
| au_event_t event; |
| au_state_t estate; |
| t_audit_data_t *tad; |
| au_kcontext_t *kctx; |
| |
| tad = U2A(u); |
| |
| ASSERT(tad != (t_audit_data_t *)0); |
| |
| ASSERT(tad->tad_scid == 0); |
| ASSERT(tad->tad_event == 0); |
| ASSERT(tad->tad_evmod == 0); |
| ASSERT(tad->tad_ctrl == 0); |
| ASSERT(tad->tad_flag == 0); |
| ASSERT(tad->tad_aupath == NULL); |
| |
| kctx = SET_KCTX_PZ; |
| |
| if (kctx == NULL) { |
| zone_status_t zstate = zone_status_get(curproc->p_zone); |
| ASSERT(zstate != ZONE_IS_READY); |
| return; |
| } |
| |
| /* get basic event for system call */ |
| event = AUE_CORE; |
| estate = kctx->auk_ets[event]; |
| |
| if ((tad->tad_flag = auditme(kctx, tad, estate)) == 0) |
| return; |
| |
| /* reset the flags for non-user attributable events */ |
| tad->tad_ctrl = PAD_CORE; |
| tad->tad_scid = 0; |
| |
| /* if auditing not enabled, then don't generate an audit record */ |
| |
| if (!((kctx->auk_auditstate == AUC_AUDITING || |
| kctx->auk_auditstate == AUC_INIT_AUDIT) || |
| kctx->auk_auditstate == AUC_NOSPACE)) { |
| tad->tad_flag = 0; |
| tad->tad_ctrl = 0; |
| return; |
| } |
| |
| tad->tad_event = event; |
| tad->tad_evmod = 0; |
| |
| ASSERT(tad->tad_ad == NULL); |
| |
| au_write(&(u_ad), au_to_arg32(1, "signal", (uint32_t)sig)); |
| } |
| |
| /* |
| * ROUTINE: AUDIT_CORE_FINISH |
| * PURPOSE: |
| * CALLBY: PSIG |
| * NOTE: |
| * TODO: |
| * QUESTION: |
| */ |
| |
| /*ARGSUSED*/ |
| void |
| audit_core_finish(int code) |
| { |
| int flag; |
| t_audit_data_t *tad; |
| au_kcontext_t *kctx; |
| |
| tad = U2A(u); |
| |
| ASSERT(tad != (t_audit_data_t *)0); |
| |
| if ((flag = tad->tad_flag) == 0) { |
| tad->tad_event = 0; |
| tad->tad_evmod = 0; |
| tad->tad_ctrl = 0; |
| ASSERT(tad->tad_aupath == NULL); |
| return; |
| } |
| tad->tad_flag = 0; |
| |
| kctx = SET_KCTX_PZ; |
| if (kctx == NULL) { |
| zone_status_t zstate = zone_status_get(curproc->p_zone); |
| ASSERT(zstate != ZONE_IS_READY); |
| return; |
| } |
| |
| /* kludge for error 0, should use `code==CLD_DUMPED' instead */ |
| if (flag = audit_success(kctx, tad, 0)) { |
| cred_t *cr = CRED(); |
| const auditinfo_addr_t *ainfo = crgetauinfo(cr); |
| |
| ASSERT(ainfo != NULL); |
| |
| /* |
| * Add a subject token (no locks since our private copy of |
| * credential |
| */ |
| AUDIT_SETSUBJ(&(u_ad), cr, ainfo); |
| |
| /* Add an optional group token */ |
| AUDIT_SETGROUP(&(u_ad), cr, kctx); |
| |
| /* Add slabel token */ |
| if (is_system_labeled()) |
| au_write(&(u_ad), au_to_label(CR_SL(cr))); |
| |
| /* Add a return token (should use f argument) */ |
| add_return_token((caddr_t *)&(u_ad), tad->tad_scid, 0, 0); |
| |
| AS_INC(as_generated, 1, kctx); |
| AS_INC(as_kernel, 1, kctx); |
| } |
| |
| /* Close up everything */ |
| au_close(kctx, &(u_ad), flag, tad->tad_event, tad->tad_evmod); |
| |
| /* free up any space remaining with the path's */ |
| if (tad->tad_aupath != NULL) { |
| au_pathrele(tad->tad_aupath); |
| tad->tad_aupath = NULL; |
| tad->tad_vn = NULL; |
| } |
| tad->tad_event = 0; |
| tad->tad_evmod = 0; |
| tad->tad_ctrl = 0; |
| } |
| |
| /*ARGSUSED*/ |
| void |
| audit_stropen(struct vnode *vp, dev_t *devp, int flag, cred_t *crp) |
| { |
| } |
| |
| /*ARGSUSED*/ |
| void |
| audit_strclose(struct vnode *vp, int flag, cred_t *crp) |
| { |
| } |
| |
| /*ARGSUSED*/ |
| void |
| audit_strioctl(struct vnode *vp, int cmd, intptr_t arg, int flag, |
| int copyflag, cred_t *crp, int *rvalp) |
| { |
| } |
| |
| |
| /*ARGSUSED*/ |
| void |
| audit_strgetmsg(struct vnode *vp, struct strbuf *mctl, struct strbuf *mdata, |
| unsigned char *pri, int *flag, int fmode) |
| { |
| struct stdata *stp; |
| t_audit_data_t *tad = U2A(u); |
| |
| ASSERT(tad != (t_audit_data_t *)0); |
| |
| stp = vp->v_stream; |
| |
| /* lock stdata from audit_sock */ |
| mutex_enter(&stp->sd_lock); |
| |
| /* proceed ONLY if user is being audited */ |
| if (!tad->tad_flag) { |
| /* |
| * this is so we will not add audit data onto |
| * a thread that is not being audited. |
| */ |
| stp->sd_t_audit_data = NULL; |
| mutex_exit(&stp->sd_lock); |
| return; |
| } |
| |
| stp->sd_t_audit_data = (caddr_t)curthread; |
| mutex_exit(&stp->sd_lock); |
| } |
| |
| /*ARGSUSED*/ |
| void |
| audit_strputmsg(struct vnode *vp, struct strbuf *mctl, struct strbuf *mdata, |
| unsigned char pri, int flag, int fmode) |
| { |
| struct stdata *stp; |
| t_audit_data_t *tad = U2A(u); |
| |
| ASSERT(tad != (t_audit_data_t *)0); |
| |
| stp = vp->v_stream; |
| |
| /* lock stdata from audit_sock */ |
| mutex_enter(&stp->sd_lock); |
| |
| /* proceed ONLY if user is being audited */ |
| if (!tad->tad_flag) { |
| /* |
| * this is so we will not add audit data onto |
| * a thread that is not being audited. |
| */ |
| stp->sd_t_audit_data = NULL; |
| mutex_exit(&stp->sd_lock); |
| return; |
| } |
| |
| stp->sd_t_audit_data = (caddr_t)curthread; |
| mutex_exit(&stp->sd_lock); |
| } |
| |
| /* |
| * ROUTINE: AUDIT_CLOSEF |
| * PURPOSE: |
| * CALLBY: CLOSEF |
| * NOTE: |
| * release per file audit resources when file structure is being released. |
| * |
| * IMPORTANT NOTE: Since we generate an audit record here, we may sleep |
| * on the audit queue if it becomes full. This means |
| * audit_closef can not be called when f_count == 0. Since |
| * f_count == 0 indicates the file structure is free, another |
| * process could attempt to use the file while we were still |
| * asleep waiting on the audit queue. This would cause the |
| * per file audit data to be corrupted when we finally do |
| * wakeup. |
| * TODO: |
| * QUESTION: |
| */ |
| |
| void |
| audit_closef(struct file *fp) |
| { /* AUDIT_CLOSEF */ |
| f_audit_data_t *fad; |
| t_audit_data_t *tad; |
| int success; |
| au_state_t estate; |
| struct vnode *vp; |
| token_t *ad = NULL; |
| struct vattr attr; |
| short evmod = 0; |
| const auditinfo_addr_t *ainfo; |
| int getattr_ret; |
| cred_t *cr; |
| au_kcontext_t *kctx = SET_KCTX_PZ; |
| |
| if (kctx == NULL) { |
| zone_status_t zstate = zone_status_get(curproc->p_zone); |
| ASSERT(zstate != ZONE_IS_READY); |
| return; |
| } |
| |
| fad = F2A(fp); |
| estate = kctx->auk_ets[AUE_CLOSE]; |
| tad = U2A(u); |
| cr = CRED(); |
| |
| /* audit record already generated by system call envelope */ |
| if (tad->tad_event == AUE_CLOSE) { |
| /* so close audit event will have bits set */ |
| tad->tad_evmod |= (short)fad->fad_flags; |
| return; |
| } |
| |
| /* if auditing not enabled, then don't generate an audit record */ |
| if (!((kctx->auk_auditstate == AUC_AUDITING || |
| kctx->auk_auditstate == AUC_INIT_AUDIT) || |
| kctx->auk_auditstate == AUC_NOSPACE)) |
| return; |
| |
| ainfo = crgetauinfo(cr); |
| if (ainfo == NULL) |
| return; |
| |
| success = ainfo->ai_mask.as_success & estate; |
| |
| /* not selected for this event */ |
| if (success == 0) |
| return; |
| |
| /* |
| * can't use audit_attributes here since we use a private audit area |
| * to build the audit record instead of the one off the thread. |
| */ |
| if ((vp = fp->f_vnode) != NULL) { |
| attr.va_mask = AT_ALL; |
| getattr_ret = VOP_GETATTR(vp, &attr, 0, CRED()); |
| } |
| |
| /* |
| * When write was not used and the file can be considered public, |
| * then skip the audit. |
| */ |
| if ((getattr_ret == 0) && ((fp->f_flag & FWRITE) == 0)) { |
| if (file_is_public(&attr)) { |
| return; |
| } |
| } |
| |
| evmod = (short)fad->fad_flags; |
| if (fad->fad_aupath != NULL) { |
| au_write((caddr_t *)&(ad), au_to_path(fad->fad_aupath)); |
| } else { |
| #ifdef _LP64 |
| au_write((caddr_t *)&(ad), au_to_arg64( |
| 1, "no path: fp", (uint64_t)fp)); |
| #else |
| au_write((caddr_t *)&(ad), au_to_arg32( |
| 1, "no path: fp", (uint32_t)fp)); |
| #endif |
| } |
| |
| if (getattr_ret == 0) { |
| au_write((caddr_t *)&(ad), au_to_attr(&attr)); |
| audit_sec_attributes((caddr_t *)&(ad), vp); |
| } |
| |
| /* Add a subject token */ |
| AUDIT_SETSUBJ((caddr_t *)&(ad), cr, ainfo); |
| |
| /* add an optional group token */ |
| AUDIT_SETGROUP((caddr_t *)&(ad), cr, kctx); |
| |
| /* add slabel token */ |
| if (is_system_labeled()) |
| au_write((caddr_t *)&(ad), au_to_label(CR_SL(cr))); |
| |
| /* add a return token */ |
| add_return_token((caddr_t *)&(ad), tad->tad_scid, 0, 0); |
| |
| AS_INC(as_generated, 1, kctx); |
| AS_INC(as_kernel, 1, kctx); |
| |
| /* |
| * Close up everything |
| * Note: path space recovery handled by normal system |
| * call envelope if not at last close. |
| * Note there is no failure at this point since |
| * this represents closes due to exit of process, |
| * thus we always indicate successful closes. |
| */ |
| au_close(kctx, (caddr_t *)&(ad), AU_OK | AU_DEFER, |
| AUE_CLOSE, evmod); |
| } |
| |
| /* |
| * ROUTINE: AUDIT_SET |
| * PURPOSE: Audit the file path and file attributes. |
| * CALLBY: SETF |
| * NOTE: SETF associate a file pointer with user area's open files. |
| * TODO: |
| * call audit_finish directly ??? |
| * QUESTION: |
| */ |
| |
| /*ARGSUSED*/ |
| void |
| audit_setf(file_t *fp, int fd) |
| { |
| f_audit_data_t *fad; |
| t_audit_data_t *tad; |
| |
| if (fp == NULL) |
| return; |
| |
| tad = T2A(curthread); |
| fad = F2A(fp); |
| |
| if (!(tad->tad_scid == SYS_open || tad->tad_scid == SYS_creat || |
| tad->tad_scid == SYS_open64 || tad->tad_scid == SYS_creat64 || |
| tad->tad_scid == SYS_fsat)) |
| return; |
| |
| /* no path */ |
| if (tad->tad_aupath == 0) |
| return; |
| |
| /* |
| * assign path information associated with file audit data |
| * use tad hold |
| */ |
| fad->fad_aupath = tad->tad_aupath; |
| tad->tad_aupath = NULL; |
| tad->tad_vn = NULL; |
| |
| if (!(tad->tad_ctrl & PAD_TRUE_CREATE)) { |
| /* adjust event type */ |
| switch (tad->tad_event) { |
| case AUE_OPEN_RC: |
| tad->tad_event = AUE_OPEN_R; |
| tad->tad_ctrl |= PAD_PUBLIC_EV; |
| break; |
| case AUE_OPEN_RTC: |
| tad->tad_event = AUE_OPEN_RT; |
| break; |
| case AUE_OPEN_WC: |
| tad->tad_event = AUE_OPEN_W; |
| break; |
| case AUE_OPEN_WTC: |
| tad->tad_event = AUE_OPEN_WT; |
| break; |
| case AUE_OPEN_RWC: |
| tad->tad_event = AUE_OPEN_RW; |
| break; |
| case AUE_OPEN_RWTC: |
| tad->tad_event = AUE_OPEN_RWT; |
| break; |
| default: |
| break; |
| } |
| } |
| } |
| |
| |
| /* |
| * ROUTINE: AUDIT_COPEN |
| * PURPOSE: |
| * CALLBY: COPEN |
| * NOTE: |
| * TODO: |
| * QUESTION: |
| */ |
| /*ARGSUSED*/ |
| void |
| audit_copen(int fd, file_t *fp, vnode_t *vp) |
| { |
| } |
| |
| void |
| audit_ipc(int type, int id, void *vp) |
| { |
| /* if not auditing this event, then do nothing */ |
| if (ad_flag == 0) |
| return; |
| |
| switch (type) { |
| case AT_IPC_MSG: |
| au_uwrite(au_to_ipc(AT_IPC_MSG, id)); |
| au_uwrite(au_to_ipc_perm(&(((kmsqid_t *)vp)->msg_perm))); |
| break; |
| case AT_IPC_SEM: |
| au_uwrite(au_to_ipc(AT_IPC_SEM, id)); |
| au_uwrite(au_to_ipc_perm(&(((ksemid_t *)vp)->sem_perm))); |
| break; |
| case AT_IPC_SHM: |
| au_uwrite(au_to_ipc(AT_IPC_SHM, id)); |
| au_uwrite(au_to_ipc_perm(&(((kshmid_t *)vp)->shm_perm))); |
| break; |
| } |
| } |
| |
| void |
| audit_ipcget(int type, void *vp) |
| { |
| /* if not auditing this event, then do nothing */ |
| if (ad_flag == 0) |
| return; |
| |
| switch (type) { |
| case NULL: |
| au_uwrite(au_to_ipc_perm((struct kipc_perm *)vp)); |
| break; |
| case AT_IPC_MSG: |
| au_uwrite(au_to_ipc_perm(&(((kmsqid_t *)vp)->msg_perm))); |
| break; |
| case AT_IPC_SEM: |
| au_uwrite(au_to_ipc_perm(&(((ksemid_t *)vp)->sem_perm))); |
| break; |
| case AT_IPC_SHM: |
| au_uwrite(au_to_ipc_perm(&(((kshmid_t *)vp)->shm_perm))); |
| break; |
| } |
| } |
| |
| /* |
| * ROUTINE: AUDIT_REBOOT |
| * PURPOSE: |
| * CALLBY: |
| * NOTE: |
| * At this point we know that the system call reboot will not return. We thus |
| * have to complete the audit record generation and put it onto the queue. |
| * This might be fairly useless if the auditing daemon is already dead.... |
| * TODO: |
| * QUESTION: who calls audit_reboot |
| */ |
| |
| void |
| audit_reboot(void) |
| { |
| int flag; |
| t_audit_data_t *tad; |
| au_kcontext_t *kctx = SET_KCTX_PZ; |
| |
| if (kctx == NULL) { |
| zone_status_t zstate = zone_status_get(curproc->p_zone); |
| ASSERT(zstate != ZONE_IS_READY); |
| return; |
| } |
| |
| tad = U2A(u); |
| |
| /* if not auditing this event, then do nothing */ |
| if (tad->tad_flag == 0) |
| return; |
| |
| /* do preselection on success/failure */ |
| if (flag = audit_success(kctx, tad, 0)) { |
| /* add a process token */ |
| |
| cred_t *cr = CRED(); |
| const auditinfo_addr_t *ainfo = crgetauinfo(cr); |
| |
| if (ainfo == NULL) |
| return; |
| |
| AUDIT_SETSUBJ(&(u_ad), cr, ainfo); |
| |
| /* add an optional group token */ |
| AUDIT_SETGROUP(&(u_ad), cr, kctx); |
| |
| /* add slabel token */ |
| if (is_system_labeled()) |
| au_uwrite(au_to_label(CR_SL(cr))); |
| |
| /* add a return token */ |
| add_return_token((caddr_t *)&(u_ad), tad->tad_scid, 0, 0); |
| |
| AS_INC(as_generated, 1, kctx); |
| AS_INC(as_kernel, 1, kctx); |
| } |
| |
| /* |
| * Flow control useless here since we're going |
| * to drop everything in the queue anyway. Why |
| * block and wait. There aint anyone left alive to |
| * read the records remaining anyway. |
| */ |
| |
| /* Close up everything */ |
| au_close(kctx, &(u_ad), flag | AU_DONTBLOCK, |
| tad->tad_event, tad->tad_evmod); |
| } |
| |
| void |
| audit_setfsat_path(int argnum) |
| { |
| klwp_id_t clwp = ttolwp(curthread); |
| struct file *fp; |
| uint32_t fd; |
| t_audit_data_t *tad; |
| struct f_audit_data *fad; |
| p_audit_data_t *pad; /* current process */ |
| |
| struct b { |
| long arg1; |
| long arg2; |
| long arg3; |
| long arg4; |
| long arg5; |
| } *uap1; |
| |
| if (clwp == NULL) |
| return; |
| uap1 = (struct b *)&clwp->lwp_ap[1]; |
| |
| tad = U2A(u); |
| |
| ASSERT(tad != NULL); |
| |
| if (tad->tad_scid != SYS_fsat) |
| return; |
| |
| switch (argnum) { |
| case 1: |
| fd = (uint32_t)uap1->arg1; |
| break; |
| case 2: |
| fd = (uint32_t)uap1->arg2; |
| break; |
| case 3: |
| fd = (uint32_t)uap1->arg3; |
| break; |
| case 4: |
| fd = (uint32_t)uap1->arg4; |
| break; |
| case 5: |
| fd = (uint32_t)uap1->arg5; |
| break; |
| default: |
| return; |
| } |
| |
| if (tad->tad_atpath != NULL) { |
| au_pathrele(tad->tad_atpath); |
| tad->tad_atpath = NULL; |
| } |
| if (fd != AT_FDCWD) { |
| if ((fp = getf(fd)) == NULL) |
| return; |
| |
| fad = F2A(fp); |
| ASSERT(fad); |
| au_pathhold(fad->fad_aupath); |
| tad->tad_atpath = fad->fad_aupath; |
| releasef(fd); |
| } else { |
| pad = P2A(curproc); |
| mutex_enter(&pad->pad_lock); |
| au_pathhold(pad->pad_cwd); |
| tad->tad_atpath = pad->pad_cwd; |
| mutex_exit(&pad->pad_lock); |
| } |
| } |
| |
| void |
| audit_symlink_create(vnode_t *dvp, char *sname, char *target, int error) |
| { |
| t_audit_data_t *tad; |
| vnode_t *vp; |
| |
| tad = U2A(u); |
| |
| /* if not auditing this event, then do nothing */ |
| if (tad->tad_flag == 0) |
| return; |
| |
| au_uwrite(au_to_text(target)); |
| |
| if (error) |
| return; |
| |
| error = VOP_LOOKUP(dvp, sname, &vp, NULL, NO_FOLLOW, NULL, CRED()); |
| if (error == 0) { |
| audit_attributes(vp); |
| VN_RELE(vp); |
| } |
| } |
| |
| /* |
| * ROUTINE: AUDIT_VNCREATE_START |
| * PURPOSE: set flag so path name lookup in create will not add attribute |
| * CALLBY: VN_CREATE |
| * NOTE: |
| * TODO: |
| * QUESTION: |
| */ |
| |
| void |
| audit_vncreate_start() |
| { |
| t_audit_data_t *tad; |
| |
| tad = U2A(u); |
| tad->tad_ctrl |= PAD_NOATTRB; |
| } |
| |
| /* |
| * ROUTINE: AUDIT_VNCREATE_FINISH |
| * PURPOSE: |
| * CALLBY: VN_CREATE |
| * NOTE: |
| * TODO: |
| * QUESTION: |
| */ |
| void |
| audit_vncreate_finish(struct vnode *vp, int error) |
| { |
| t_audit_data_t *tad; |
| |
| if (error) |
| return; |
| |
| tad = U2A(u); |
| |
| /* if not auditing this event, then do nothing */ |
| if (tad->tad_flag == 0) |
| return; |
| |
| if (tad->tad_ctrl & PAD_TRUE_CREATE) { |
| audit_attributes(vp); |
| } |
| |
| if (tad->tad_ctrl & PAD_CORE) { |
| audit_attributes(vp); |
| tad->tad_ctrl &= ~PAD_CORE; |
| } |
| |
| if (!error && ((tad->tad_event == AUE_MKNOD) || |
| (tad->tad_event == AUE_MKDIR))) { |
| audit_attributes(vp); |
| } |
| |
| /* for case where multiple lookups in one syscall (rename) */ |
| tad->tad_ctrl &= ~PAD_NOATTRB; |
| } |
| |
| |
| |
| |
| |
| |
| |
| |
| /* |
| * ROUTINE: AUDIT_EXEC |
| * PURPOSE: Records the function arguments and environment variables |
| * CALLBY: EXEC_ARGS |
| * NOTE: |
| * TODO: |
| * QUESTION: |
| */ |
| |
| /*ARGSUSED*/ |
| void |
| audit_exec( |
| const char *argstr, /* argument strings */ |
| const char *envstr, /* environment strings */ |
| ssize_t argc, /* total # arguments */ |
| ssize_t envc) /* total # environment variables */ |
| { |
| t_audit_data_t *tad; |
| au_kcontext_t *kctx = SET_KCTX_PZ; |
| |
| ASSERT(kctx != NULL); |
| |
| tad = U2A(u); |
| |
| /* if not auditing this event, then do nothing */ |
| if (!tad->tad_flag) |
| return; |
| |
| /* return if not interested in argv or environment variables */ |
| if (!(kctx->auk_policy & (AUDIT_ARGV|AUDIT_ARGE))) |
| return; |
| |
| if (kctx->auk_policy & AUDIT_ARGV) { |
| au_uwrite(au_to_exec_args(argstr, argc)); |
| } |
| |
| if (kctx->auk_policy & AUDIT_ARGE) { |
| au_uwrite(au_to_exec_env(envstr, envc)); |
| } |
| } |
| |
| /* |
| * ROUTINE: AUDIT_ENTERPROM |
| * PURPOSE: |
| * CALLBY: KBDINPUT |
| * ZSA_XSINT |
| * NOTE: |
| * TODO: |
| * QUESTION: |
| */ |
| void |
| audit_enterprom(int flg) |
| { |
| token_t *rp = NULL; |
| int sorf; |
| |
| if (flg) |
| sorf = AUM_SUCC; |
| else |
| sorf = AUM_FAIL; |
| |
| AUDIT_ASYNC_START(rp, AUE_ENTERPROM, sorf); |
| |
| au_write((caddr_t *)&(rp), au_to_text("kmdb")); |
| |
| if (flg) |
| au_write((caddr_t *)&(rp), au_to_return32(0, 0)); |
| else |
| au_write((caddr_t *)&(rp), au_to_return32(ECANCELED, 0)); |
| |
| AUDIT_ASYNC_FINISH(rp, AUE_ENTERPROM, NULL); |
| } |
| |
| |
| /* |
| * ROUTINE: AUDIT_EXITPROM |
| * PURPOSE: |
| * CALLBY: KBDINPUT |
| * ZSA_XSINT |
| * NOTE: |
| * TODO: |
| * QUESTION: |
| */ |
| void |
| audit_exitprom(int flg) |
| { |
| int sorf; |
| token_t *rp = NULL; |
| |
| if (flg) |
| sorf = AUM_SUCC; |
| else |
| sorf = AUM_FAIL; |
| |
| AUDIT_ASYNC_START(rp, AUE_EXITPROM, sorf); |
| |
| au_write((caddr_t *)&(rp), au_to_text("kmdb")); |
| |
| if (flg) |
| au_write((caddr_t *)&(rp), au_to_return32(0, 0)); |
| else |
| au_write((caddr_t *)&(rp), au_to_return32(ECANCELED, 0)); |
| |
| AUDIT_ASYNC_FINISH(rp, AUE_EXITPROM, NULL); |
| } |
| |
| struct fcntla { |
| int fdes; |
| int cmd; |
| intptr_t arg; |
| }; |
| |
| /* |
| * ROUTINE: AUDIT_C2_REVOKE |
| * PURPOSE: |
| * CALLBY: FCNTL |
| * NOTE: |
| * TODO: |
| * QUESTION: are we keeping this func |
| */ |
| |
| /*ARGSUSED*/ |
| int |
| audit_c2_revoke(struct fcntla *uap, rval_t *rvp) |
| { |
| return (0); |
| } |
| |
| |
| /* |
| * ROUTINE: AUDIT_CHDIREC |
| * PURPOSE: |
| * CALLBY: CHDIREC |
| * NOTE: The main function of CHDIREC |
| * TODO: Move the audit_chdirec hook above the VN_RELE in vncalls.c |
| * QUESTION: |
| */ |
| |
| /*ARGSUSED*/ |
| void |
| audit_chdirec(vnode_t *vp, vnode_t **vpp) |
| { |
| int chdir; |
| int fchdir; |
| struct audit_path **appp; |
| struct file *fp; |
| f_audit_data_t *fad; |
| p_audit_data_t *pad = P2A(curproc); |
| t_audit_data_t *tad = T2A(curthread); |
| |
| struct a { |
| long fd; |
| } *uap = (struct a *)ttolwp(curthread)->lwp_ap; |
| |
| if ((tad->tad_scid == SYS_chdir) || (tad->tad_scid == SYS_chroot)) { |
| chdir = tad->tad_scid == SYS_chdir; |
| if (tad->tad_aupath) { |
| mutex_enter(&pad->pad_lock); |
| if (chdir) |
| appp = &(pad->pad_cwd); |
| else |
| appp = &(pad->pad_root); |
| au_pathrele(*appp); |
| /* use tad hold */ |
| *appp = tad->tad_aupath; |
| tad->tad_aupath = NULL; |
| mutex_exit(&pad->pad_lock); |
| } |
| } else if ((tad->tad_scid == SYS_fchdir) || |
| (tad->tad_scid == SYS_fchroot)) { |
| fchdir = tad->tad_scid == SYS_fchdir; |
| if ((fp = getf(uap->fd)) == NULL) |
| return; |
| fad = F2A(fp); |
| if (fad->fad_aupath) { |
| au_pathhold(fad->fad_aupath); |
| mutex_enter(&pad->pad_lock); |
| if (fchdir) |
| appp = &(pad->pad_cwd); |
| else |
| appp = &(pad->pad_root); |
| au_pathrele(*appp); |
| *appp = fad->fad_aupath; |
| mutex_exit(&pad->pad_lock); |
| if (tad->tad_flag) { |
| au_uwrite(au_to_path(fad->fad_aupath)); |
| audit_attributes(fp->f_vnode); |
| } |
| } |
| releasef(uap->fd); |
| } |
| } |
| |
| /* |
| * ROUTINE: AUDIT_GETF |
| * PURPOSE: |
| * CALLBY: GETF_INTERNAL |
| * NOTE: The main function of GETF_INTERNAL is to associate a given |
| * file descriptor with a file structure and increment the |
| * file pointer reference count. |
| * TODO: remove pass in of fpp. |
| * increment a reference count so that even if a thread with same process delete |
| * the same object, it will not panic our system |
| * QUESTION: |
| * where to decrement the f_count????????????????? |
| * seems like I need to set a flag if f_count incrmented through audit_getf |
| */ |
| |
| /*ARGSUSED*/ |
| int |
| audit_getf(int fd) |
| { |
| #ifdef NOTYET |
| t_audit_data_t *tad; |
| |
| tad = T2A(curthread); |
| |
| if (!(tad->tad_scid == SYS_open || tad->tad_scid == SYS_creat)) |
| return; |
| #endif |
| return (0); |
| } |
| |
| /* |
| * Audit hook for stream based socket and tli request. |
| * Note that we do not have user context while executing |
| * this code so we had to record them earlier during the |
| * putmsg/getmsg to figure out which user we are dealing with. |
| */ |
| |
| /*ARGSUSED*/ |
| void |
| audit_sock( |
| int type, /* type of tihdr.h header requests */ |
| queue_t *q, /* contains the process and thread audit data */ |
| mblk_t *mp, /* contains the tihdr.h header structures */ |
| int from) /* timod or sockmod request */ |
| { |
| int32_t len; |
| int32_t offset; |
| struct sockaddr_in *sock_data; |
| struct T_conn_req *conn_req; |
| struct T_conn_ind *conn_ind; |
| struct T_unitdata_req *unitdata_req; |
| struct T_unitdata_ind *unitdata_ind; |
| au_state_t estate; |
| t_audit_data_t *tad; |
| caddr_t saved_thread_ptr; |
| au_mask_t amask; |
| const auditinfo_addr_t *ainfo; |
| au_kcontext_t *kctx; |
| zone_status_t zstate; |
| |
| if (q->q_stream == NULL) |
| return; |
| mutex_enter(&q->q_stream->sd_lock); |
| /* are we being audited */ |
| saved_thread_ptr = q->q_stream->sd_t_audit_data; |
| /* no pointer to thread, nothing to do */ |
| if (saved_thread_ptr == NULL) { |
| mutex_exit(&q->q_stream->sd_lock); |
| return; |
| } |
| /* only allow one addition of a record token */ |
| q->q_stream->sd_t_audit_data = NULL; |
| /* |
| * thread is not the one being audited, then nothing to do |
| * This could be the stream thread handling the module |
| * service routine. In this case, the context for the audit |
| * record can no longer be assumed. Simplest to just drop |
| * the operation. |
| */ |
| if (curthread != (kthread_id_t)saved_thread_ptr) { |
| mutex_exit(&q->q_stream->sd_lock); |
| return; |
| } |
| if (curthread->t_sysnum >= SYS_so_socket && |
| curthread->t_sysnum <= SYS_sockconfig) { |
| mutex_exit(&q->q_stream->sd_lock); |
| return; |
| } |
| mutex_exit(&q->q_stream->sd_lock); |
| /* |
| * we know that the thread that did the put/getmsg is the |
| * one running. Now we can get the TAD and see if we should |
| * add an audit token. |
| */ |
| tad = U2A(u); |
| |
| kctx = SET_KCTX_PZ; |
| if (kctx == NULL) { |
| zstate = zone_status_get(curproc->p_zone); |
| ASSERT(zstate != ZONE_IS_READY); |
| return; |
| } |
| |
| /* proceed ONLY if user is being audited */ |
| if (!tad->tad_flag) |
| return; |
| |
| ainfo = crgetauinfo(CRED()); |
| if (ainfo == NULL) |
| return; |
| amask = ainfo->ai_mask; |
| |
| /* |
| * Figure out the type of stream networking request here. |
| * Note that getmsg and putmsg are always preselected |
| * because during the beginning of the system call we have |
| * not yet figure out which of the socket or tli request |
| * we are looking at until we are here. So we need to check |
| * against that specific request and reset the type of event. |
| */ |
| switch (type) { |
| case T_CONN_REQ: /* connection request */ |
| conn_req = (struct T_conn_req *)mp->b_rptr; |
| if (conn_req->DEST_offset < sizeof (struct T_conn_req)) |
| return; |
| offset = conn_req->DEST_offset; |
| len = conn_req->DEST_length; |
| estate = kctx->auk_ets[AUE_SOCKCONNECT]; |
| if (amask.as_success & estate || amask.as_failure & estate) { |
| tad->tad_event = AUE_SOCKCONNECT; |
| break; |
| } else { |
| return; |
| } |
| case T_CONN_IND: /* connectionless receive request */ |
| conn_ind = (struct T_conn_ind *)mp->b_rptr; |
| if (conn_ind->SRC_offset < sizeof (struct T_conn_ind)) |
| return; |
| offset = conn_ind->SRC_offset; |
| len = conn_ind->SRC_length; |
| estate = kctx->auk_ets[AUE_SOCKACCEPT]; |
| if (amask.as_success & estate || amask.as_failure & estate) { |
| tad->tad_event = AUE_SOCKACCEPT; |
| break; |
| } else { |
| return; |
| } |
| case T_UNITDATA_REQ: /* connectionless send request */ |
| unitdata_req = (struct T_unitdata_req *)mp->b_rptr; |
| if (unitdata_req->DEST_offset < sizeof (struct T_unitdata_req)) |
| return; |
| offset = unitdata_req->DEST_offset; |
| len = unitdata_req->DEST_length; |
| estate = kctx->auk_ets[AUE_SOCKSEND]; |
| if (amask.as_success & estate || amask.as_failure & estate) { |
| tad->tad_event = AUE_SOCKSEND; |
| break; |
| } else { |
| return; |
| } |
| case T_UNITDATA_IND: /* connectionless receive request */ |
| unitdata_ind = (struct T_unitdata_ind *)mp->b_rptr; |
| if (unitdata_ind->SRC_offset < sizeof (struct T_unitdata_ind)) |
| return; |
| offset = unitdata_ind->SRC_offset; |
| len = unitdata_ind->SRC_length; |
| estate = kctx->auk_ets[AUE_SOCKRECEIVE]; |
| if (amask.as_success & estate || amask.as_failure & estate) { |
| tad->tad_event = AUE_SOCKRECEIVE; |
| break; |
| } else { |
| return; |
| } |
| default: |
| return; |
| } |
| |
| /* |
| * we are only interested in tcp stream connections, |
| * not unix domain stuff |
| */ |
| if ((len < 0) || (len > sizeof (struct sockaddr_in))) { |
| tad->tad_event = AUE_GETMSG; |
| return; |
| } |
| /* skip over TPI header and point to the ip address */ |
| sock_data = (struct sockaddr_in *)((char *)mp->b_rptr + offset); |
| |
| switch (sock_data->sin_family) { |
| case AF_INET: |
| au_write(&(tad->tad_ad), au_to_sock_inet(sock_data)); |
| break; |
| default: /* reset to AUE_PUTMSG if not a inet request */ |
| tad->tad_event = AUE_GETMSG; |
| break; |
| } |
| } |
| |
| void |
| audit_lookupname() |
| { |
| } |
| |
| /*ARGSUSED*/ |
| int |
| audit_pathcomp(struct pathname *pnp, vnode_t *cvp, cred_t *cr) |
| { |
| return (0); |
| } |
| |
| static void |
| add_return_token(caddr_t *ad, unsigned int scid, int err, int rval) |
| { |
| unsigned int sy_flags; |
| |
| #ifdef _SYSCALL32_IMPL |
| if (lwp_getdatamodel( |
| ttolwp(curthread)) == DATAMODEL_NATIVE) |
| sy_flags = sysent[scid].sy_flags & SE_RVAL_MASK; |
| else |
| sy_flags = sysent32[scid].sy_flags & SE_RVAL_MASK; |
| #else |
| sy_flags = sysent[scid].sy_flags & SE_RVAL_MASK; |
| #endif |
| |
| if (sy_flags == SE_64RVAL) |
| au_write(ad, au_to_return64(err, rval)); |
| else |
| au_write(ad, au_to_return32(err, rval)); |
| |
| } |
| |
| /*ARGSUSED*/ |
| void |
| audit_fdsend(fd, fp, error) |
| int fd; |
| struct file *fp; |
| int error; /* ignore for now */ |
| { |
| t_audit_data_t *tad; /* current thread */ |
| f_audit_data_t *fad; /* per file audit structure */ |
| struct vnode *vp; /* for file attributes */ |
| |
| /* is this system call being audited */ |
| tad = U2A(u); |
| ASSERT(tad != (t_audit_data_t *)0); |
| if (!tad->tad_flag) |
| return; |
| |
| fad = F2A(fp); |
| |
| /* add path and file attributes */ |
| if (fad != NULL && fad->fad_aupath != NULL) { |
| au_uwrite(au_to_arg32(0, "send fd", (uint32_t)fd)); |
| au_uwrite(au_to_path(fad->fad_aupath)); |
| } else { |
| au_uwrite(au_to_arg32(0, "send fd", (uint32_t)fd)); |
| #ifdef _LP64 |
| au_uwrite(au_to_arg64(0, "no path", (uint64_t)fp)); |
| #else |
| au_uwrite(au_to_arg32(0, "no path", (uint32_t)fp)); |
| #endif |
| } |
| vp = fp->f_vnode; /* include vnode attributes */ |
| audit_attributes(vp); |
| } |
| |
| /* |
| * Record privileges sucessfully used and we attempted to use but |
| * didn't have. |
| */ |
| void |
| audit_priv(int priv, const priv_set_t *set, int flag) |
| { |
| t_audit_data_t *tad; |
| int sbit; |
| priv_set_t *target; |
| |
| /* Make sure this isn't being called in an interrupt context */ |
| ASSERT(servicing_interrupt() == 0); |
| |
| tad = U2A(u); |
| |
| if (tad->tad_flag == 0) |
| return; |
| |
| target = flag ? &tad->tad_sprivs : &tad->tad_fprivs; |
| sbit = flag ? PAD_SPRIVUSE : PAD_FPRIVUSE; |
| |
| /* Tell audit_success() and audit_finish() that we saw this case */ |
| if (!(tad->tad_evmod & sbit)) { |
| /* Clear set first time around */ |
| priv_emptyset(target); |
| tad->tad_evmod |= sbit; |
| } |
| |
| /* Save the privileges in the tad */ |
| if (priv == PRIV_ALL) { |
| priv_fillset(target); |
| } else { |
| ASSERT(set != NULL || priv != PRIV_NONE); |
| if (set != NULL) |
| priv_union(set, target); |
| if (priv != PRIV_NONE) |
| priv_addset(target, priv); |
| } |
| } |
| |
| /* |
| * Audit the setpriv() system call; the operation, the set name and |
| * the current value as well as the set argument are put in the |
| * audit trail. |
| */ |
| void |
| audit_setppriv(int op, int set, const priv_set_t *newpriv, const cred_t *ocr) |
| { |
| t_audit_data_t *tad; |
| const priv_set_t *oldpriv; |
| priv_set_t report; |
| const char *setname; |
| |
| tad = U2A(u); |
| |
| if (tad->tad_flag == 0) |
| return; |
| |
| oldpriv = priv_getset(ocr, set); |
| |
| /* Generate the actual record, include the before and after */ |
| au_uwrite(au_to_arg32(2, "op", op)); |
| setname = priv_getsetbynum(set); |
| |
| switch (op) { |
| case PRIV_OFF: |
| /* Report privileges actually switched off */ |
| report = *oldpriv; |
| priv_intersect(newpriv, &report); |
| au_uwrite(au_to_privset(setname, &report, AUT_PRIV, 0)); |
| break; |
| case PRIV_ON: |
| /* Report privileges actually switched on */ |
| report = *oldpriv; |
| priv_inverse(&report); |
| priv_intersect(newpriv, &report); |
| au_uwrite(au_to_privset(setname, &report, AUT_PRIV, 0)); |
| break; |
| case PRIV_SET: |
| /* Report before and after */ |
| au_uwrite(au_to_privset(setname, oldpriv, AUT_PRIV, 0)); |
| au_uwrite(au_to_privset(setname, newpriv, AUT_PRIV, 0)); |
| break; |
| } |
| } |
| |
| /* |
| * Dump the full device policy setting in the audit trail. |
| */ |
| void |
| audit_devpolicy(int nitems, const devplcysys_t *items) |
| { |
| t_audit_data_t *tad; |
| int i; |
| |
| tad = U2A(u); |
| |
| if (tad->tad_flag == 0) |
| return; |
| |
| for (i = 0; i < nitems; i++) { |
| au_uwrite(au_to_arg32(2, "major", items[i].dps_maj)); |
| if (items[i].dps_minornm[0] == '\0') { |
| au_uwrite(au_to_arg32(2, "lomin", items[i].dps_lomin)); |
| au_uwrite(au_to_arg32(2, "himin", items[i].dps_himin)); |
| } else |
| au_uwrite(au_to_text(items[i].dps_minornm)); |
| |
| au_uwrite(au_to_privset("read", &items[i].dps_rdp, |
| AUT_PRIV, 0)); |
| au_uwrite(au_to_privset("write", &items[i].dps_wrp, |
| AUT_PRIV, 0)); |
| } |
| } |
| |
| /*ARGSUSED*/ |
| void |
| audit_fdrecv(fd, fp) |
| int fd; |
| struct file *fp; |
| { |
| t_audit_data_t *tad; /* current thread */ |
| f_audit_data_t *fad; /* per file audit structure */ |
| struct vnode *vp; /* for file attributes */ |
| |
| /* is this system call being audited */ |
| tad = U2A(u); |
| ASSERT(tad != (t_audit_data_t *)0); |
| if (!tad->tad_flag) |
| return; |
| |
| fad = F2A(fp); |
| |
| /* add path and file attributes */ |
| if (fad != NULL && fad->fad_aupath != NULL) { |
| au_uwrite(au_to_arg32(0, "recv fd", (uint32_t)fd)); |
| au_uwrite(au_to_path(fad->fad_aupath)); |
| } else { |
| au_uwrite(au_to_arg32(0, "recv fd", (uint32_t)fd)); |
| #ifdef _LP64 |
| au_uwrite(au_to_arg64(0, "no path", (uint64_t)fp)); |
| #else |
| au_uwrite(au_to_arg32(0, "no path", (uint32_t)fp)); |
| #endif |
| } |
| vp = fp->f_vnode; /* include vnode attributes */ |
| audit_attributes(vp); |
| } |
| |
| /* |
| * ROUTINE: AUDIT_CRYPTOADM |
| * PURPOSE: Records arguments to administrative ioctls on /dev/cryptoadm |
| * CALLBY: CRYPTO_LOAD_DEV_DISABLED, CRYPTO_LOAD_SOFT_DISABLED, |
| * CRYPTO_UNLOAD_SOFT_MODULE, CRYPTO_LOAD_SOFT_CONFIG, |
| * CRYPTO_POOL_CREATE, CRYPTO_POOL_WAIT, CRYPTO_POOL_RUN, |
| * CRYPTO_LOAD_DOOR |
| * NOTE: |
| * TODO: |
| * QUESTION: |
| */ |
| |
| void |
| audit_cryptoadm(int cmd, char *module_name, crypto_mech_name_t *mech_names, |
| uint_t mech_count, uint_t device_instance, uint32_t rv, int error) |
| { |
| boolean_t mech_list_required = B_FALSE; |
| cred_t *cr = CRED(); |
| t_audit_data_t *tad; |
| token_t *ad = NULL; |
| const auditinfo_addr_t *ainfo = crgetauinfo(cr); |
| char buffer[MAXNAMELEN * 2]; |
| au_kcontext_t *kctx = SET_KCTX_PZ; |
| |
| ASSERT(kctx != NULL); |
| |
| tad = U2A(u); |
| if (tad == NULL) |
| return; |
| |
| if (ainfo == NULL) |
| return; |
| |
| tad->tad_event = AUE_CRYPTOADM; |
| |
| if (audit_success(kctx, tad, error) != AU_OK) |
| return; |
| |
| /* Add a subject token */ |
| AUDIT_SETSUBJ((caddr_t *)&(ad), cr, ainfo); |
| |
| /* add an optional group token */ |
| AUDIT_SETGROUP((caddr_t *)&(ad), cr, kctx); |
| |
| /* add slabel token */ |
| if (is_system_labeled()) |
| au_write((caddr_t *)&ad, au_to_label(CR_SL(cr))); |
| |
| switch (cmd) { |
| case CRYPTO_LOAD_DEV_DISABLED: |
| if (error == 0 && rv == CRYPTO_SUCCESS) { |
| (void) snprintf(buffer, sizeof (buffer), |
| "op=CRYPTO_LOAD_DEV_DISABLED, module=%s," |
| " dev_instance=%d", |
| module_name, device_instance); |
| mech_list_required = B_TRUE; |
| } else { |
| (void) snprintf(buffer, sizeof (buffer), |
| "op=CRYPTO_LOAD_DEV_DISABLED, return_val=%d", rv); |
| } |
| break; |
| |
| case CRYPTO_LOAD_SOFT_DISABLED: |
| if (error == 0 && rv == CRYPTO_SUCCESS) { |
| (void) snprintf(buffer, sizeof (buffer), |
| "op=CRYPTO_LOAD_SOFT_DISABLED, module=%s", |
| module_name); |
| mech_list_required = B_TRUE; |
| } else { |
| (void) snprintf(buffer, sizeof (buffer), |
| "op=CRYPTO_LOAD_SOFT_DISABLED, return_val=%d", rv); |
| } |
| break; |
| |
| case CRYPTO_UNLOAD_SOFT_MODULE: |
| if (error == 0 && rv == CRYPTO_SUCCESS) { |
| (void) snprintf(buffer, sizeof (buffer), |
| "op=CRYPTO_UNLOAD_SOFT_MODULE, module=%s", |
| module_name); |
| } else { |
| (void) snprintf(buffer, sizeof (buffer), |
| "op=CRYPTO_UNLOAD_SOFT_MODULE, return_val=%d", rv); |
| } |
| break; |
| |
| case CRYPTO_LOAD_SOFT_CONFIG: |
| if (error == 0 && rv == CRYPTO_SUCCESS) { |
| (void) snprintf(buffer, sizeof (buffer), |
| "op=CRYPTO_LOAD_SOFT_CONFIG, module=%s", |
| module_name); |
| mech_list_required = B_TRUE; |
| } else { |
| (void) snprintf(buffer, sizeof (buffer), |
| "op=CRYPTO_LOAD_SOFT_CONFIG, return_val=%d", rv); |
| } |
| break; |
| |
| case CRYPTO_POOL_CREATE: |
| (void) snprintf(buffer, sizeof (buffer), |
| "op=CRYPTO_POOL_CREATE"); |
| break; |
| |
| case CRYPTO_POOL_WAIT: |
| (void) snprintf(buffer, sizeof (buffer), "op=CRYPTO_POOL_WAIT"); |
| break; |
| |
| case CRYPTO_POOL_RUN: |
| (void) snprintf(buffer, sizeof (buffer), "op=CRYPTO_POOL_RUN"); |
| break; |
| |
| case CRYPTO_LOAD_DOOR: |
| if (error == 0 && rv == CRYPTO_SUCCESS) |
| (void) snprintf(buffer, sizeof (buffer), |
| "op=CRYPTO_LOAD_DOOR"); |
| else |
| (void) snprintf(buffer, sizeof (buffer), |
| "op=CRYPTO_LOAD_DOOR, return_val=%d", rv); |
| break; |
| |
| default: |
| return; |
| } |
| |
| au_write((caddr_t *)&ad, au_to_text(buffer)); |
| |
| if (mech_list_required) { |
| int i; |
| |
| if (mech_count == 0) { |
| au_write((caddr_t *)&ad, au_to_text("mech=list empty")); |
| } else { |
| char *pb = buffer; |
| size_t l = sizeof (buffer); |
| size_t n; |
| char space[2] = ":"; |
| |
| n = snprintf(pb, l, "mech="); |
| |
| for (i = 0; i < mech_count; i++) { |
| pb += n; |
| l -= n; |
| if (l < 0) |
| l = 0; |
| |
| if (i == mech_count - 1) |
| (void) strcpy(space, ""); |
| |
| n = snprintf(pb, l, "%s%s", mech_names[i], |
| space); |
| } |
| au_write((caddr_t *)&ad, au_to_text(buffer)); |
| } |
| } |
| |
| /* add a return token */ |
| if (error || (rv != CRYPTO_SUCCESS)) |
| add_return_token((caddr_t *)&ad, tad->tad_scid, -1, error); |
| else |
| add_return_token((caddr_t *)&ad, tad->tad_scid, 0, rv); |
| |
| AS_INC(as_generated, 1, kctx); |
| AS_INC(as_kernel, 1, kctx); |
| |
| au_close(kctx, (caddr_t *)&ad, AU_OK, AUE_CRYPTOADM, 0); |
| } |
| |
| /* |
| * Audit the kernel SSL administration command. The address and the |
| * port number for the SSL instance, and the proxy port are put in the |
| * audit trail. |
| */ |
| void |
| audit_kssl(int cmd, void *params, int error) |
| { |
| cred_t *cr = CRED(); |
| t_audit_data_t *tad; |
| token_t *ad = NULL; |
| const auditinfo_addr_t *ainfo = crgetauinfo(cr); |
| au_kcontext_t *kctx = SET_KCTX_PZ; |
| |
| ASSERT(kctx != NULL); |
| tad = U2A(u); |
| |
| if (ainfo == NULL) |
| return; |
| |
| tad->tad_event = AUE_CONFIGKSSL; |
| |
| if (audit_success(kctx, tad, error) != AU_OK) |
| return; |
| |
| /* Add a subject token */ |
| AUDIT_SETSUBJ((caddr_t *)&ad, cr, ainfo); |
| |
| /* add an optional group token */ |
| AUDIT_SETGROUP((caddr_t *)&ad, cr, kctx); |
| |
| /* Add slabel token */ |
| if (is_system_labeled()) |
| au_write(&(u_ad), au_to_label(CR_SL(cr))); |
| |
| switch (cmd) { |
| case KSSL_ADD_ENTRY: { |
| char buf[32]; |
| kssl_params_t *kp = (kssl_params_t *)params; |
| struct sockaddr_in *saddr = &(kp->kssl_addr); |
| |
| au_write((caddr_t *)&ad, au_to_text("op=KSSL_ADD_ENTRY")); |
| au_write((caddr_t *)&ad, au_to_in_addr(&(saddr->sin_addr))); |
| (void) snprintf(buf, sizeof (buf), "SSL port=%d", |
| saddr->sin_port); |
| au_write((caddr_t *)&ad, au_to_text(buf)); |
| |
| (void) snprintf(buf, sizeof (buf), "proxy port=%d", |
| kp->kssl_proxy_port); |
| au_write((caddr_t *)&ad, au_to_text(buf)); |
| break; |
| } |
| |
| case KSSL_DELETE_ENTRY: { |
| char buf[32]; |
| struct sockaddr_in *saddr = (struct sockaddr_in *)params; |
| |
| au_write((caddr_t *)&ad, au_to_text("op=KSSL_DELETE_ENTRY")); |
| au_write((caddr_t *)&ad, au_to_in_addr(&(saddr->sin_addr))); |
| (void) snprintf(buf, sizeof (buf), "SSL port=%d", |
| saddr->sin_port); |
| au_write((caddr_t *)&ad, au_to_text(buf)); |
| break; |
| } |
| |
| default: |
| return; |
| } |
| |
| /* add a return token */ |
| add_return_token((caddr_t *)&ad, tad->tad_scid, error, 0); |
| |
| AS_INC(as_generated, 1, kctx); |
| AS_INC(as_kernel, 1, kctx); |
| |
| au_close(kctx, (caddr_t *)&ad, AU_OK, AUE_CONFIGKSSL, 0); |
| } |
| |
| /* |
| * ROUTINE: AUDIT_SEC_ATTRIBUTES |
| * PURPOSE: Add security attributes |
| * CALLBY: AUDIT_ATTRIBUTES |
| * AUDIT_CLOSEF |
| * AUS_CLOSE |
| * NOTE: |
| * TODO: |
| * QUESTION: |
| */ |
| |
| void |
| audit_sec_attributes(caddr_t *ad, struct vnode *vp) |
| { |
| /* Dump the SL */ |
| if (is_system_labeled()) { |
| ts_label_t *tsl; |
| bslabel_t *bsl; |
| |
| tsl = getflabel(vp); |
| if (tsl == NULL) |
| return; /* nothing else to do */ |
| |
| bsl = label2bslabel(tsl); |
| if (bsl == NULL) |
| return; /* nothing else to do */ |
| au_write(ad, au_to_label(bsl)); |
| label_rele(tsl); |
| } |
| |
| } /* AUDIT_SEC_ATTRIBUTES */ |