6 #include <architecture/byte_order.h>
7 #include <security_cdsa_utilities/cssmdb.h>
8 #include "SharedMemoryClient.h"
10 #include <security_utilities/crc.h>
11 #include <securityd_client/ssnotify.h>
12 #include <Security/SecKeychain.h>
14 using namespace Security
;
16 //=================================================================================
18 //=================================================================================
21 static std::string
unixerrorstr(int errnum
) {
24 // might return ERANGE
25 /* int rx = */ strerror_r(errnum
, buf
, sizeof(buf
));
27 errstr
+= "(" + to_string(errnum
) + ")";
32 SharedMemoryClient::SharedMemoryClient (const char* segmentName
, SegmentOffsetType segmentSize
, uid_t uid
)
34 StLock
<Mutex
> _(mMutex
);
36 mSegmentName
= segmentName
;
37 mSegmentSize
= segmentSize
;
38 mSegment
= (u_int8_t
*) MAP_FAILED
;
39 mDataArea
= mDataPtr
= 0;
42 secdebug("MDSPRIVACY","[%03d] creating SharedMemoryClient with segmentName %s, size: %d", mUID
, segmentName
, segmentSize
);
44 if (segmentSize
< sizeof(u_int32_t
))
48 int segmentDescriptor
;
50 std::string
name(SharedMemoryCommon::SharedMemoryFilePath(mSegmentName
.c_str(), mUID
));
52 // make a connection to the shared memory block
53 segmentDescriptor
= open (name
.c_str(), O_RDONLY
, S_IROTH
);
54 if (segmentDescriptor
< 0) // error on opening the shared memory segment?
56 secdebug("MDSPRIVACY","[%03d] SharedMemoryClient open of %s failed: %s", mUID
, name
.c_str(), unixerrorstr(errno
).c_str());
57 // CssmError::throwMe (CSSM_ERRCODE_INTERNAL_ERROR);
62 // check that the file size is large enough to support operations
63 struct stat statResult
= {};
64 int result
= fstat(segmentDescriptor
, &statResult
);
66 secdebug("MDSPRIVACY","[%03d] SharedMemoryClient fstat failed: %d/%s", mUID
, result
, unixerrorstr(errno
).c_str());
67 UnixError::throwMe(errno
);
70 off_t sz
= statResult
.st_size
;
71 if(sz
< sizeof(SegmentOffsetType
)) {
72 close(segmentDescriptor
);
76 if(sz
> 4*segmentSize
) {
77 // File is too ridiculously large. Quit.
78 close(segmentDescriptor
);
82 // map the segment into place
83 mSegment
= (u_int8_t
*) mmap (NULL
, segmentSize
, PROT_READ
, MAP_SHARED
, segmentDescriptor
, 0);
84 close (segmentDescriptor
);
86 if (mSegment
== MAP_FAILED
)
88 secdebug("MDSPRIVACY","[%03d] SharedMemoryClient mmap failed: %d", mUID
, errno
);
92 mDataArea
= mSegment
+ sizeof (SegmentOffsetType
);
93 mDataMax
= mSegment
+ sz
;
94 mDataPtr
= mDataArea
+ GetProducerCount ();
99 SharedMemoryClient::~SharedMemoryClient ()
101 if (!uninitialized()) {
102 StLock
<Mutex
> _(mMutex
);
103 munmap (mSegment
, mSegmentSize
);
108 SegmentOffsetType
SharedMemoryClient::GetProducerCount ()
110 if (uninitialized()) {
111 secdebug("MDSPRIVACY","[%03d] SharedMemoryClient::GetProducerCount uninitialized", mUID
);
112 CssmError::throwMe(CSSM_ERRCODE_INTERNAL_ERROR
);
114 if( ((u_int8_t
*) (((u_int32_t
*) mSegment
) + 1)) > mDataMax
) {
115 // Check we can actually read this u_int32_t
116 secdebug("MDSPRIVACY","[%03d] SharedMemoryClient::GetProducerCount uint > mDataMax", mUID
);
117 CssmError::throwMe(CSSM_ERRCODE_INTERNAL_ERROR
);
120 SegmentOffsetType offset
= OSSwapBigToHostInt32 (*(u_int32_t
*) mSegment
);
121 if (&mSegment
[offset
] >= mDataMax
) {
122 secdebug("MDSPRIVACY","[%03d] SharedMemoryClient::GetProducerCount offset > mDataMax", mUID
);
123 CssmError::throwMe(CSSM_ERRCODE_INTERNAL_ERROR
);
129 void SharedMemoryClient::ReadData (void* buffer
, SegmentOffsetType length
)
131 if (uninitialized()) {
132 secdebug("MDSPRIVACY","[%03d] ReadData mSegment fail uninitialized: %p", mUID
, mSegment
);
133 CssmError::throwMe(CSSM_ERRCODE_INTERNAL_ERROR
);
136 u_int8_t
* bptr
= (u_int8_t
*) buffer
;
138 SegmentOffsetType bytesToEnd
= (SegmentOffsetType
)(mDataMax
- mDataPtr
);
140 // figure out how many bytes we can read
141 SegmentOffsetType bytesToRead
= (length
<= bytesToEnd
) ? length
: bytesToEnd
;
143 // move the first part of the data
144 memcpy (bptr
, mDataPtr
, bytesToRead
);
147 // see if we have anything else to read
148 mDataPtr
+= bytesToRead
;
150 length
-= bytesToRead
;
153 mDataPtr
= mDataArea
;
154 memcpy(bptr
, mDataPtr
, length
);
161 SegmentOffsetType
SharedMemoryClient::ReadOffset()
163 SegmentOffsetType offset
;
164 ReadData(&offset
, sizeof(SegmentOffsetType
));
165 offset
= OSSwapBigToHostInt32 (offset
);
171 bool SharedMemoryClient::ReadMessage (void* message
, SegmentOffsetType
&length
, UnavailableReason
&ur
)
173 StLock
<Mutex
> _(mMutex
);
175 if (uninitialized()) {
176 secdebug("MDSPRIVACY","[%03d] ReadMessage mSegment fail uninitialized: %p", mUID
, mSegment
);
177 CssmError::throwMe(CSSM_ERRCODE_INTERNAL_ERROR
);
182 size_t offset
= mDataPtr
- mDataArea
;
183 if (offset
== GetProducerCount())
185 secdebug("MDSPRIVACY","[%03d] ReadMessage GetProducerCount()", mUID
);
190 // get the length of the message in the buffer
191 length
= ReadOffset();
193 // we have the possibility that data is correct, figure out where the data is actually located
194 // get the length of the message stored there
195 if (length
== 0 || length
>= kPoolAvailableForData
)
197 secdebug("MDSPRIVACY","[%03d] ReadMessage length error: %d", mUID
, length
);
198 ur
= (length
== 0) ? kURNoMessage
: kURBufferCorrupt
;
200 // something's gone wrong, reset.
201 mDataPtr
= mDataArea
+ GetProducerCount ();
206 SegmentOffsetType crc
= ReadOffset();
208 // read the data into the buffer
209 ReadData (message
, length
);
212 SegmentOffsetType crc2
= CalculateCRC((u_int8_t
*) message
, length
);
215 ur
= kURBufferCorrupt
;
216 mDataPtr
= mDataArea
+ GetProducerCount ();
223 //=================================================================================
224 // SharedMemoryCommon
225 //=================================================================================
227 std::string
SharedMemoryCommon::SharedMemoryFilePath(const char *segmentName
, uid_t uid
) {
229 uid
= SharedMemoryCommon::fixUID(uid
);
230 path
= SharedMemoryCommon::kMDSMessagesDirectory
; // i.e. /private/var/db/mds/messages/
232 path
+= std::to_string(uid
) + "/"; // e.g. /private/var/db/mds/messages/501/
235 path
+= SharedMemoryCommon::kUserPrefix
; // e.g. /var/db/mds/messages/se_
236 path
+= segmentName
; // e.g. /var/db/mds/messages/501/se_SecurityMessages
240 std::string
SharedMemoryCommon::notificationDescription(int domain
, int event
) {
241 string domainstr
, eventstr
;
244 case Security::SecurityServer::kNotificationDomainAll
: domainstr
= "all"; break;
245 case Security::SecurityServer::kNotificationDomainDatabase
: domainstr
= "database"; break;
246 case Security::SecurityServer::kNotificationDomainPCSC
: domainstr
= "pcsc"; break;
247 case Security::SecurityServer::kNotificationDomainCDSA
: domainstr
= "CDSA"; break;
249 domainstr
= "unknown";
254 case kSecLockEvent
: eventstr
= "lock"; break;
255 case kSecUnlockEvent
: eventstr
= "unlock"; break;
256 case kSecAddEvent
: eventstr
= "add"; break;
257 case kSecDeleteEvent
: eventstr
= "delete"; break;
258 case kSecUpdateEvent
: eventstr
= "update"; break;
259 case kSecPasswordChangedEvent
: eventstr
= "passwordChange"; break;
260 case kSecDefaultChangedEvent
: eventstr
= "defaultChange"; break;
261 case kSecDataAccessEvent
: eventstr
= "dataAccess"; break;
262 case kSecKeychainListChangedEvent
: eventstr
= "listChange"; break;
263 case kSecTrustSettingsChangedEvent
: eventstr
= "trustSettings"; break;
265 domainstr
= "unknown";
269 return "Domain: " + domainstr
+ ", Event: " + eventstr
;