1149N/A/*
1265N/A * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
1149N/A *
1149N/A * Permission is hereby granted, free of charge, to any person obtaining a
1149N/A * copy of this software and associated documentation files (the "Software"),
1149N/A * to deal in the Software without restriction, including without limitation
1149N/A * the rights to use, copy, modify, merge, publish, distribute, sublicense,
1149N/A * and/or sell copies of the Software, and to permit persons to whom the
1149N/A * Software is furnished to do so, subject to the following conditions:
1149N/A *
1149N/A * The above copyright notice and this permission notice (including the next
1149N/A * paragraph) shall be included in all copies or substantial portions of the
1149N/A * Software.
1149N/A *
1149N/A * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1149N/A * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1149N/A * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
1149N/A * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
1149N/A * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
1149N/A * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
1149N/A * DEALINGS IN THE SOFTWARE.
1149N/A */
1149N/A
1149N/A#ifdef HAVE_DIX_CONFIG_H
1149N/A#include <dix-config.h>
1149N/A#endif
1149N/A
1149N/A#define XSERV_t
1149N/A#define TRANS_SERVER
1149N/A#include <X11/Xtrans/Xtrans.h>
1149N/A#include <X11/Xtrans/Xtransint.h>
1149N/A
1149N/A#include "misc.h"
1149N/A#include "osdep.h"
1149N/A#include "dixstruct.h"
1149N/A
1149N/Astatic DevPrivateKeyRec OSAuditPrivKeyRec;
1149N/A#define OSAuditPrivKey (&OSAuditPrivKeyRec)
1149N/A
1149N/A#define GetOSAuditClient(pClient) \
1149N/A ((OSAuditClientPrivatePtr) dixLookupPrivate(&(pClient)->devPrivates, OSAuditPrivKey))
1149N/A
1149N/A#ifdef HAVE_LIBBSM /* Solaris auditing implementation */
1149N/A#include <ucred.h>
1149N/A#include <bsm/adt.h>
1149N/A#include <bsm/adt_event.h>
1149N/A
1149N/A#ifdef ADT_xconnect
1149N/A# define OS_AUDIT_IMPLEMENTED
1149N/A
1149N/Atypedef struct {
1149N/A adt_session_data_t *ah; /* audit handle */
1149N/A ClientState prevState;
1149N/A} OSAuditClientPrivateRec, *OSAuditClientPrivatePtr;
1149N/A
1149N/Astatic void
1149N/AOSAuditClientInit (ClientPtr pClient)
1149N/A{
1149N/A adt_session_data_t *ah; /* audit handle */
1149N/A ucred_t *uc = NULL; /* peer's ucred */
1149N/A XtransConnInfo ci; /* peer's connection info */
1149N/A int peer; /* peer's file descriptor */
1149N/A int saveid;
1149N/A
1149N/A OSAuditClientPrivatePtr priv = GetOSAuditClient(pClient);
1149N/A
1149N/A saveid = geteuid();
1149N/A if (saveid != 0) {
1149N/A /* reset privs back to root */
1149N/A if (seteuid(0) < 0) {
1265N/A ErrorF("OSAuditClientInit: seteuid(0): %s\n", strerror(errno));
1149N/A saveid = 0;
1149N/A }
1149N/A }
1149N/A
1149N/A if (adt_start_session(&ah, NULL, 0) != 0) {
1265N/A ErrorF("OSAuditClientInit: adt_start_session: %s\n", strerror(errno));
1149N/A goto end;
1149N/A }
1149N/A
1149N/A if (pClient->osPrivate == NULL) {
1265N/A ErrorF("OSAuditClientInit: NULL osPrivate: %s\n", strerror(errno));
1149N/A goto end;
1149N/A }
1149N/A ci = ((OsCommPtr)pClient->osPrivate)->trans_conn;
1149N/A peer = _XSERVTransGetConnectionNumber(ci);
1149N/A if (getpeerucred(peer, &uc) == 0) {
1149N/A if (adt_set_from_ucred(ah, uc, ADT_NEW) != 0) {
1265N/A ErrorF("OSAuditClientInit: adt_set_from_ucred: %s\n",
1265N/A strerror(errno));
1149N/A }
1149N/A ucred_free(uc);
1149N/A } else {
1149N/A if (adt_set_user(ah, ADT_NO_ATTRIB, ADT_NO_ATTRIB, ADT_NO_ATTRIB,
1149N/A ADT_NO_ATTRIB, NULL, ADT_NEW) != 0) {
1265N/A ErrorF("OSAuditClientInit: adt_set_user: %s\n", strerror(errno));
1149N/A }
1149N/A }
1149N/A
1149N/A priv->ah = ah;
1149N/A
1149N/A end:
1149N/A if (saveid != 0) {
1149N/A /* set privs back to user */
1149N/A if (seteuid(saveid) < 0) {
1265N/A ErrorF("OSAuditClientInit: seteuid(saveid): %s\n", strerror(errno));
1149N/A }
1149N/A }
1149N/A
1149N/A}
1149N/A
1149N/Astatic void
1149N/AOSAudit (ClientPtr pClient, int event_id, int status, int reason)
1149N/A{
1149N/A adt_event_data_t *event; /* event handle */
1149N/A XtransConnInfo ci; /* peer's connection info */
1149N/A int peer; /* peer's file descriptor */
1149N/A int saveid;
1149N/A
1149N/A OSAuditClientPrivatePtr priv = GetOSAuditClient(pClient);
1149N/A
1149N/A if (priv->ah == NULL) {
1265N/A ErrorF("OSAudit: NULL adt_session_data: %s\n", strerror(errno));
1149N/A return;
1149N/A }
1149N/A
1149N/A if ((event = adt_alloc_event(priv->ah, event_id)) == NULL) {
1265N/A ErrorF("OSAudit: adt_set_from_ucred: %s\n", strerror(errno));
1149N/A return;
1149N/A }
1149N/A
1149N/A /* fill in event */
1149N/A switch (event_id) {
1149N/A case ADT_xconnect:
1149N/A if (pClient->osPrivate != NULL) {
1149N/A ci = ((OsCommPtr)pClient->osPrivate)->trans_conn;
1149N/A peer = _XSERVTransGetConnectionNumber(ci);
1149N/A } else {
1149N/A peer = -1;
1149N/A }
1149N/A event->adt_xconnect.client = pClient->index;
1149N/A event->adt_xconnect.peer = peer;
1149N/A break;
1149N/A case ADT_xdisconnect:
1149N/A event->adt_xdisconnect.client = pClient->index;
1149N/A break;
1149N/A default:
1265N/A ErrorF("OSAudit: unknown event_id: %s\n", strerror(errno));
1149N/A }
1149N/A
1149N/A saveid = geteuid();
1149N/A if (saveid != 0) {
1149N/A /* reset privs back to root */
1149N/A if (seteuid(0) < 0) {
1265N/A ErrorF("OSAuditClientInit: seteuid(0): %s\n", strerror(errno));
1149N/A saveid = 0;
1149N/A }
1149N/A }
1149N/A
1149N/A if (adt_put_event(event, status, reason) != 0) {
1265N/A ErrorF("OSAudit: adt_put_event: %s\n", strerror(errno));
1149N/A }
1149N/A
1149N/A if (saveid != 0) {
1149N/A /* set privs back to user */
1149N/A if (seteuid(saveid) < 0) {
1265N/A ErrorF("OSAuditClientInit: seteuid(saveid): %s\n", strerror(errno));
1149N/A }
1149N/A }
1149N/A
1149N/A adt_free_event(event);
1149N/A}
1149N/A
1149N/A/* Called when new client connects or existing client disconnects */
1149N/Astatic void
1149N/AOSAuditClientStateChange(CallbackListPtr *pcbl, pointer nulldata, pointer calldata)
1149N/A{
1149N/A NewClientInfoRec *pci = (NewClientInfoRec *)calldata;
1149N/A ClientPtr pClient = pci->client;
1149N/A OSAuditClientPrivatePtr priv = GetOSAuditClient(pClient);
1149N/A
1149N/A switch (pClient->clientState) {
1149N/A
1149N/A case ClientStateInitial: /* client attempting to connect */
1149N/A OSAuditClientInit(pClient);
1149N/A break;
1149N/A
1149N/A case ClientStateRunning: /* connection accepted */
1149N/A OSAudit (pClient, ADT_xconnect, ADT_SUCCESS, ADT_SUCCESS);
1149N/A break;
1149N/A
1149N/A case ClientStateGone: /* connection terminating */
1149N/A if (priv->prevState == ClientStateInitial) /* was never accepted */
1149N/A OSAudit (pClient, ADT_xconnect, ADT_FAILURE, EACCES);
1149N/A else /* successful connection that ran for a while */
1149N/A OSAudit (pClient, ADT_xdisconnect, ADT_SUCCESS, ADT_SUCCESS);
1149N/A adt_end_session(priv->ah);
1149N/A priv->ah = NULL;
1149N/A break;
1149N/A
1149N/A default:
1149N/A return; /* skip over setting prevState to an unknown state */
1149N/A }
1149N/A
1149N/A priv->prevState = pClient->clientState;
1149N/A}
1149N/A#endif /* ADT_xconnect */
1149N/A#endif /* HAVE_LIBBSM -- Solaris auditing implementation */
1149N/A
1149N/A/* Generic code to initialize all OS auditing implementations */
1149N/Avoid
1149N/AOSAuditInit(void)
1149N/A{
1149N/A#ifdef OS_AUDIT_IMPLEMENTED
1149N/A /* Reserve room in the client privates for the audit data */
1149N/A if (!dixRegisterPrivateKey(&OSAuditPrivKeyRec, PRIVATE_CLIENT,
1149N/A sizeof(OSAuditClientPrivateRec)))
1149N/A FatalError("could not allocate OSAuditPrivKey\n");
1149N/A
1149N/A /* Register callback to be called on every client connect & disconnect */
1149N/A if (!AddCallback(&ClientStateCallback, OSAuditClientStateChange, NULL))
1149N/A FatalError("could not register OSAuditClientStateChange callback\n");
1149N/A#else
1149N/A/* nothing implemented for this OS */
1149N/A return;
1149N/A#endif
1149N/A}