|
1 /* |
|
2 * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. |
|
3 * |
|
4 * Permission is hereby granted, free of charge, to any person obtaining a |
|
5 * copy of this software and associated documentation files (the "Software"), |
|
6 * to deal in the Software without restriction, including without limitation |
|
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, |
|
8 * and/or sell copies of the Software, and to permit persons to whom the |
|
9 * Software is furnished to do so, subject to the following conditions: |
|
10 * |
|
11 * The above copyright notice and this permission notice (including the next |
|
12 * paragraph) shall be included in all copies or substantial portions of the |
|
13 * Software. |
|
14 * |
|
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
|
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
|
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
|
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
|
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
|
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
|
21 * DEALINGS IN THE SOFTWARE. |
|
22 */ |
|
23 |
|
24 #ifdef HAVE_DIX_CONFIG_H |
|
25 #include <dix-config.h> |
|
26 #endif |
|
27 |
|
28 #define XSERV_t |
|
29 #define TRANS_SERVER |
|
30 #include <X11/Xtrans/Xtrans.h> |
|
31 #include <X11/Xtrans/Xtransint.h> |
|
32 |
|
33 #include "misc.h" |
|
34 #include "osdep.h" |
|
35 #include "dixstruct.h" |
|
36 |
|
37 static DevPrivateKeyRec OSAuditPrivKeyRec; |
|
38 #define OSAuditPrivKey (&OSAuditPrivKeyRec) |
|
39 |
|
40 #define GetOSAuditClient(pClient) \ |
|
41 ((OSAuditClientPrivatePtr) dixLookupPrivate(&(pClient)->devPrivates, OSAuditPrivKey)) |
|
42 |
|
43 #ifdef HAVE_LIBBSM /* Solaris auditing implementation */ |
|
44 #include <ucred.h> |
|
45 #include <bsm/adt.h> |
|
46 #include <bsm/adt_event.h> |
|
47 |
|
48 #ifdef ADT_xconnect |
|
49 # define OS_AUDIT_IMPLEMENTED |
|
50 |
|
51 typedef struct { |
|
52 adt_session_data_t *ah; /* audit handle */ |
|
53 ClientState prevState; |
|
54 } OSAuditClientPrivateRec, *OSAuditClientPrivatePtr; |
|
55 |
|
56 static void |
|
57 OSAuditClientInit (ClientPtr pClient) |
|
58 { |
|
59 adt_session_data_t *ah; /* audit handle */ |
|
60 ucred_t *uc = NULL; /* peer's ucred */ |
|
61 XtransConnInfo ci; /* peer's connection info */ |
|
62 int peer; /* peer's file descriptor */ |
|
63 int saveid; |
|
64 |
|
65 OSAuditClientPrivatePtr priv = GetOSAuditClient(pClient); |
|
66 |
|
67 saveid = geteuid(); |
|
68 if (saveid != 0) { |
|
69 /* reset privs back to root */ |
|
70 if (seteuid(0) < 0) { |
|
71 Error("OSAuditClientInit: seteuid(0)"); |
|
72 saveid = 0; |
|
73 } |
|
74 } |
|
75 |
|
76 if (adt_start_session(&ah, NULL, 0) != 0) { |
|
77 Error("OSAuditClientInit: adt_start_session"); |
|
78 goto end; |
|
79 } |
|
80 |
|
81 if (pClient->osPrivate == NULL) { |
|
82 Error("OSAuditClientInit: NULL osPrivate"); |
|
83 goto end; |
|
84 } |
|
85 ci = ((OsCommPtr)pClient->osPrivate)->trans_conn; |
|
86 peer = _XSERVTransGetConnectionNumber(ci); |
|
87 if (getpeerucred(peer, &uc) == 0) { |
|
88 if (adt_set_from_ucred(ah, uc, ADT_NEW) != 0) { |
|
89 Error("OSAuditClientInit: adt_set_from_ucred"); |
|
90 } |
|
91 ucred_free(uc); |
|
92 } else { |
|
93 if (adt_set_user(ah, ADT_NO_ATTRIB, ADT_NO_ATTRIB, ADT_NO_ATTRIB, |
|
94 ADT_NO_ATTRIB, NULL, ADT_NEW) != 0) { |
|
95 Error("OSAuditClientInit: adt_set_user"); |
|
96 } |
|
97 } |
|
98 |
|
99 priv->ah = ah; |
|
100 |
|
101 end: |
|
102 if (saveid != 0) { |
|
103 /* set privs back to user */ |
|
104 if (seteuid(saveid) < 0) { |
|
105 Error("OSAuditClientInit: seteuid(saveid)"); |
|
106 } |
|
107 } |
|
108 |
|
109 } |
|
110 |
|
111 static void |
|
112 OSAudit (ClientPtr pClient, int event_id, int status, int reason) |
|
113 { |
|
114 adt_event_data_t *event; /* event handle */ |
|
115 XtransConnInfo ci; /* peer's connection info */ |
|
116 int peer; /* peer's file descriptor */ |
|
117 int saveid; |
|
118 |
|
119 OSAuditClientPrivatePtr priv = GetOSAuditClient(pClient); |
|
120 |
|
121 if (priv->ah == NULL) { |
|
122 Error("OSAudit: NULL adt_session_data"); |
|
123 return; |
|
124 } |
|
125 |
|
126 if ((event = adt_alloc_event(priv->ah, event_id)) == NULL) { |
|
127 Error("OSAudit: adt_set_from_ucred"); |
|
128 return; |
|
129 } |
|
130 |
|
131 /* fill in event */ |
|
132 switch (event_id) { |
|
133 case ADT_xconnect: |
|
134 if (pClient->osPrivate != NULL) { |
|
135 ci = ((OsCommPtr)pClient->osPrivate)->trans_conn; |
|
136 peer = _XSERVTransGetConnectionNumber(ci); |
|
137 } else { |
|
138 peer = -1; |
|
139 } |
|
140 event->adt_xconnect.client = pClient->index; |
|
141 event->adt_xconnect.peer = peer; |
|
142 break; |
|
143 case ADT_xdisconnect: |
|
144 event->adt_xdisconnect.client = pClient->index; |
|
145 break; |
|
146 default: |
|
147 Error("OSAudit: unknown event_id"); |
|
148 } |
|
149 |
|
150 saveid = geteuid(); |
|
151 if (saveid != 0) { |
|
152 /* reset privs back to root */ |
|
153 if (seteuid(0) < 0) { |
|
154 Error("OSAuditClientInit: seteuid(0)"); |
|
155 saveid = 0; |
|
156 } |
|
157 } |
|
158 |
|
159 if (adt_put_event(event, status, reason) != 0) { |
|
160 Error("OSAudit: adt_put_event"); |
|
161 } |
|
162 |
|
163 if (saveid != 0) { |
|
164 /* set privs back to user */ |
|
165 if (seteuid(saveid) < 0) { |
|
166 Error("OSAuditClientInit: seteuid(saveid)"); |
|
167 } |
|
168 } |
|
169 |
|
170 adt_free_event(event); |
|
171 } |
|
172 |
|
173 /* Called when new client connects or existing client disconnects */ |
|
174 static void |
|
175 OSAuditClientStateChange(CallbackListPtr *pcbl, pointer nulldata, pointer calldata) |
|
176 { |
|
177 NewClientInfoRec *pci = (NewClientInfoRec *)calldata; |
|
178 ClientPtr pClient = pci->client; |
|
179 OSAuditClientPrivatePtr priv = GetOSAuditClient(pClient); |
|
180 |
|
181 switch (pClient->clientState) { |
|
182 |
|
183 case ClientStateInitial: /* client attempting to connect */ |
|
184 OSAuditClientInit(pClient); |
|
185 break; |
|
186 |
|
187 case ClientStateRunning: /* connection accepted */ |
|
188 OSAudit (pClient, ADT_xconnect, ADT_SUCCESS, ADT_SUCCESS); |
|
189 break; |
|
190 |
|
191 case ClientStateGone: /* connection terminating */ |
|
192 if (priv->prevState == ClientStateInitial) /* was never accepted */ |
|
193 OSAudit (pClient, ADT_xconnect, ADT_FAILURE, EACCES); |
|
194 else /* successful connection that ran for a while */ |
|
195 OSAudit (pClient, ADT_xdisconnect, ADT_SUCCESS, ADT_SUCCESS); |
|
196 adt_end_session(priv->ah); |
|
197 priv->ah = NULL; |
|
198 break; |
|
199 |
|
200 default: |
|
201 return; /* skip over setting prevState to an unknown state */ |
|
202 } |
|
203 |
|
204 priv->prevState = pClient->clientState; |
|
205 } |
|
206 #endif /* ADT_xconnect */ |
|
207 #endif /* HAVE_LIBBSM -- Solaris auditing implementation */ |
|
208 |
|
209 /* Generic code to initialize all OS auditing implementations */ |
|
210 void |
|
211 OSAuditInit(void) |
|
212 { |
|
213 #ifdef OS_AUDIT_IMPLEMENTED |
|
214 /* Reserve room in the client privates for the audit data */ |
|
215 if (!dixRegisterPrivateKey(&OSAuditPrivKeyRec, PRIVATE_CLIENT, |
|
216 sizeof(OSAuditClientPrivateRec))) |
|
217 FatalError("could not allocate OSAuditPrivKey\n"); |
|
218 |
|
219 /* Register callback to be called on every client connect & disconnect */ |
|
220 if (!AddCallback(&ClientStateCallback, OSAuditClientStateChange, NULL)) |
|
221 FatalError("could not register OSAuditClientStateChange callback\n"); |
|
222 #else |
|
223 /* nothing implemented for this OS */ |
|
224 return; |
|
225 #endif |
|
226 } |