/* * Copyright (c) 2011, 2015, 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 #endif #define XSERV_t #define TRANS_SERVER #include #include #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 #include #include #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, void *nulldata, void *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 }