open-src/xserver/xorg/sun-src/os/osaudit.c
author Niveditha Rau <Niveditha.Rau@Oracle.COM>
Fri, 06 Apr 2012 21:57:14 -0700
changeset 1265 0b5cc5c013e4
parent 1149 e852f51b09cd
permissions -rw-r--r--
7083537 Xorg 1.12 & associated module updates

/*
 * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice (including the next
 * paragraph) shall be included in all copies or substantial portions of the
 * Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 */

#ifdef HAVE_DIX_CONFIG_H
#include <dix-config.h>
#endif

#define XSERV_t
#define TRANS_SERVER
#include <X11/Xtrans/Xtrans.h>
#include <X11/Xtrans/Xtransint.h>

#include "misc.h"
#include "osdep.h"
#include "dixstruct.h"

static DevPrivateKeyRec OSAuditPrivKeyRec;
#define OSAuditPrivKey (&OSAuditPrivKeyRec)

#define GetOSAuditClient(pClient)    \
  ((OSAuditClientPrivatePtr) dixLookupPrivate(&(pClient)->devPrivates, OSAuditPrivKey))

#ifdef HAVE_LIBBSM	/* Solaris auditing implementation */
#include <ucred.h>
#include <bsm/adt.h>
#include <bsm/adt_event.h>

#ifdef ADT_xconnect
# define OS_AUDIT_IMPLEMENTED

typedef struct {
    adt_session_data_t	*ah;		/* audit handle */
    ClientState		 prevState;
} OSAuditClientPrivateRec, *OSAuditClientPrivatePtr;

static void
OSAuditClientInit (ClientPtr pClient)
{
    adt_session_data_t	*ah;		/* audit handle */
    ucred_t		*uc = NULL;	/* peer's ucred */
    XtransConnInfo	 ci;		/* peer's connection info */
    int			 peer;		/* peer's file descriptor */
    int			 saveid;

    OSAuditClientPrivatePtr	 priv = GetOSAuditClient(pClient);

    saveid = geteuid();
    if (saveid != 0) {
	/* reset privs back to root */
        if (seteuid(0) < 0) {
	    ErrorF("OSAuditClientInit: seteuid(0): %s\n", strerror(errno));
	    saveid = 0;
	}
    }
    
    if (adt_start_session(&ah, NULL, 0) != 0) {
	ErrorF("OSAuditClientInit: adt_start_session: %s\n", strerror(errno));
	goto end;
    }

    if (pClient->osPrivate == NULL) {
	ErrorF("OSAuditClientInit: NULL osPrivate: %s\n", strerror(errno));
	goto end;
    }
    ci = ((OsCommPtr)pClient->osPrivate)->trans_conn;
    peer = _XSERVTransGetConnectionNumber(ci);
    if (getpeerucred(peer, &uc) == 0) {
	if (adt_set_from_ucred(ah, uc, ADT_NEW) != 0) {
	    ErrorF("OSAuditClientInit: adt_set_from_ucred: %s\n",
		   strerror(errno));
	}
	ucred_free(uc);
    } else {
	if (adt_set_user(ah, ADT_NO_ATTRIB, ADT_NO_ATTRIB, ADT_NO_ATTRIB,
			 ADT_NO_ATTRIB, NULL, ADT_NEW) != 0) {
	    ErrorF("OSAuditClientInit: adt_set_user: %s\n", strerror(errno));
	}
    }

    priv->ah = ah;

  end:
    if (saveid != 0) {
	/* set privs back to user */
        if (seteuid(saveid) < 0) {
	    ErrorF("OSAuditClientInit: seteuid(saveid): %s\n", strerror(errno));
	}
    }

}

static void
OSAudit (ClientPtr pClient, int event_id, int status, int reason)
{
    adt_event_data_t	*event;		/* event handle */
    XtransConnInfo	 ci;		/* peer's connection info */
    int			 peer;		/* peer's file descriptor */
    int			 saveid;

    OSAuditClientPrivatePtr	 priv = GetOSAuditClient(pClient);

    if (priv->ah == NULL) {
	ErrorF("OSAudit: NULL adt_session_data: %s\n", strerror(errno));
	return;
    }

    if ((event = adt_alloc_event(priv->ah, event_id)) == NULL) {
	ErrorF("OSAudit: adt_set_from_ucred: %s\n", strerror(errno));
	return;
    }

    /* fill in event */
    switch (event_id) {
    case ADT_xconnect:
	if (pClient->osPrivate != NULL) {
	    ci = ((OsCommPtr)pClient->osPrivate)->trans_conn;
	    peer = _XSERVTransGetConnectionNumber(ci);
	} else {
	    peer = -1;
	}
	event->adt_xconnect.client = pClient->index;
	event->adt_xconnect.peer = peer;
	break;
    case ADT_xdisconnect:
	event->adt_xdisconnect.client = pClient->index;
	break;
    default:
	ErrorF("OSAudit: unknown event_id: %s\n", strerror(errno));
    }

    saveid = geteuid();
    if (saveid != 0) {
	/* reset privs back to root */
        if (seteuid(0) < 0) {
	    ErrorF("OSAuditClientInit: seteuid(0): %s\n", strerror(errno));
	    saveid = 0;
	}
    }
    
    if (adt_put_event(event, status, reason) != 0) {
	ErrorF("OSAudit: adt_put_event: %s\n", strerror(errno));
    }

    if (saveid != 0) {
	/* set privs back to user */
        if (seteuid(saveid) < 0) {
	    ErrorF("OSAuditClientInit: seteuid(saveid): %s\n", strerror(errno));
	}
    }    
    
    adt_free_event(event);
}

/* Called when new client connects or existing client disconnects */
static void
OSAuditClientStateChange(CallbackListPtr *pcbl, pointer nulldata, pointer calldata)
{
    NewClientInfoRec *pci = (NewClientInfoRec *)calldata;
    ClientPtr pClient = pci->client;
    OSAuditClientPrivatePtr	 priv = GetOSAuditClient(pClient);

    switch (pClient->clientState) {

    case ClientStateInitial:  /* client attempting to connect */
	OSAuditClientInit(pClient);
	break;

    case ClientStateRunning:  /* connection accepted */
	OSAudit (pClient, ADT_xconnect, ADT_SUCCESS, ADT_SUCCESS);
	break;

    case ClientStateGone:     /* connection terminating */
	if (priv->prevState == ClientStateInitial) /* was never accepted */
	    OSAudit (pClient, ADT_xconnect, ADT_FAILURE, EACCES);
	else	/* successful connection that ran for a while */
	    OSAudit (pClient, ADT_xdisconnect, ADT_SUCCESS, ADT_SUCCESS);
	adt_end_session(priv->ah);
	priv->ah = NULL;
	break;

    default:
	return; /* skip over setting prevState to an unknown state */
    }

    priv->prevState = pClient->clientState;
}
#endif /* ADT_xconnect */
#endif /* HAVE_LIBBSM -- Solaris auditing implementation */

/* Generic code to initialize all OS auditing implementations */
void
OSAuditInit(void)
{
#ifdef OS_AUDIT_IMPLEMENTED
    /* Reserve room in the client privates for the audit data */
    if (!dixRegisterPrivateKey(&OSAuditPrivKeyRec, PRIVATE_CLIENT,
			       sizeof(OSAuditClientPrivateRec)))
	FatalError("could not allocate OSAuditPrivKey\n");

    /* Register callback to be called on every client connect & disconnect */
    if (!AddCallback(&ClientStateCallback, OSAuditClientStateChange, NULL))
	FatalError("could not register OSAuditClientStateChange callback\n");
#else
/* nothing implemented for this OS */
    return;
#endif
}