1/*
2 * @APPLE_LICENSE_HEADER_START@
3 *
4 * Copyright (c) 2010 Apple Computer, Inc.  All Rights Reserved.
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24
25#define DEBUG_SECURE_PROMPT 0
26#if DEBUG_SECURE_PROMPT
27#   define DEBUG_ASSERT_PRODUCTION_CODE         0
28#   define DEBUG_ASSERT_COMPONENT_NAME_STRING   "IOHIDSecurePromptClient"
29#endif
30
31#include <AssertMacros.h>
32#include <IOKit/IOLib.h>
33#include <sys/proc.h>
34#include <IOKit/IOCommandGate.h>
35#include <IOKit/hidsystem/IOHIKeyboardMapper.h>
36#include <IOKit/crypto/AppleFDEKeyStore.h>
37#include <uuid/uuid.h>
38#include "IOHIDSecurePromptClient.h"
39
40/******************************************************************************/
41/*  Helper functions
42 */
43static void         __EraseData(OSData *target);
44static void         __EraseDataArray(OSArray *target);
45static void         __EraseMemory(void *mem, UInt32 size);
46static void         __InsertBytes(void *dest, UInt32 insertPoint, UInt32 destCount, void *source, UInt32 sourceCount, UInt32 size);
47
48/******************************************************************************/
49/*  Through the course of this file, the word hash is used to mean a cryprographically
50    secure one way hash
51 */
52extern unsigned int hid_adb_2_usb_keymap[];  //In Cosmo_USB2ADB.cpp
53
54#undef super
55#define super IOUserClient
56
57OSDefineMetaClassAndStructors(IOHIDSecurePromptClient, IOUserClient)
58
59/******************************************************************************/
60/*  The IOHIDSecurePromptClient_RawKeystrokeData stores raw keycodes for use later
61    if we need to generate a new set of UTF32Chars for comparison.
62 */
63typedef struct IOHIDSecurePromptClient_RawKeystrokeData {
64    UInt8               modifier[4];
65    UInt8               code[4];
66}   IOHIDSecurePromptClient_RawKeystrokeData;
67
68#ifndef UTF32Char
69    typedef UInt32      UTF32Char;
70#endif
71
72/*  The keyqueue message is sent to the subscribee letting them know that a new
73    keystroke has been queued up.
74 */
75typedef struct IOHIDSecurePromptClient_KeyqueueMessage {
76    mach_msg_header_t   message;
77    mach_msg_body_t     body;
78    UInt32              id;
79}   IOHIDSecurePromptClient_KeyqueueMessage;
80
81/*  The keyqueue entry stores the correspondence between the id sent via the
82    keyqueue message and the actual keycode delivered.
83 */
84typedef struct IOHIDSecurePromptClient_KeyqueueEntry {
85    UInt16          id;
86    UInt8           modifier;
87    UInt8           code;
88}   IOHIDSecurePromptClient_KeyqueueEntry;
89
90/*  The IOHIDSecurePromptClient_ExpansionData structure stores all of the instance data for
91    the IOHIDSecurePromptClient class.
92 */
93typedef struct IOHIDSecurePromptClient_ExpansionData {
94    UInt8           gathering;          // Are we currently gathering keystrokes?
95    UInt8           dead;               // Has this client been closed or abandoned?
96    UInt8           uuidState;          // See kUUIDState* below
97    UInt16          nextQueueID;        // Used to keyqueue ids above
98    UInt16          insertionPoint;     // The insertion point for new characters
99    UInt16          stringLength;       // Valid data length in the unicode and raw keystroke buffers
100    UInt16          bufferLength;       // Maximum size of the unicode and raw keystroke buffers
101    UInt32          layout;             // The keyboard layout used for code ->> value translation
102    OSData          *layouts;           // All of the keyboard layouts
103                                        // probably won't be an OSData in the end
104    IONotifier      *keyboardNotifier;  // This is the notifier set up by the instantiating class
105                                        // the client is responsible for releasing it.
106    mach_port_t     port;               // The notification port supplied by the client user
107    UTF32Char       *unicode;           // This is a buffer of UTF32Char's
108    IOHIDSecurePromptClient_RawKeystrokeData
109                    *rawKeystrokes;     // This is a buffer of IOHIDSecurePromptClient_RawKeystrokeData's
110    OSArray         *messageQueue;      // A queue of all of the key ids that have been sent out but not yet gotten back
111    uuid_t          uuid;         	  	// The uuid is used to idetify the password in the keystore. Therefore, if two
112                                        // clients have the same uuid, they identify the same password. Care must be taken
113                                        // so that two clients do not *modify* the same password, however. That would be bad.
114                                        // This is the reason for uuidState above and kUUIDState* below.
115    IOCommandGate   *gate;              // The command gate used to serialize data coming from all
116                                        // of the keyboards and the client user.
117    kbdBitVector    keyState;           // A bitvector to store the key state information
118    IOByteCount     keyStateSize;       // The size of said bitvector
119
120}   IOHIDSecurePromptClient_ExpansionData;
121
122enum {
123    kUUIDStateNeverSaved,   // client has no coresponding keystore entry
124    kUUIDStateIsDirty,      // client has a keystore entry, but it is not in sync with internal data
125    kUUIDStateIsClean,      // client and keystore are in sync
126    kUUIDStateIsGhost       // client ghosts a keystore entry. It cannot gather new data.
127};
128enum {
129    kControlModifier = 0x1,
130    kShiftModifier   = 0x2,
131    kOptionModifier  = 0x4,
132    kCommandModifier = 0x8
133};
134
135
136
137
138/******************************************************************************/
139bool
140IOHIDSecurePromptClient::initWithTask(task_t owningTask,
141                                      void* security_id,
142                                      UInt32 type,
143                                      OSDictionary * properties)
144{
145    require(super::initWithTask(owningTask, security_id, type), init_error);
146
147    _reserved = (IOHIDSecurePromptClient_ExpansionData*)IOMalloc(sizeof(IOHIDSecurePromptClient_ExpansionData));
148    require(_reserved, init_error);
149
150    bzero(_reserved, sizeof(IOHIDSecurePromptClient_ExpansionData));
151
152    // initially we allow for a 32 character password but will grow it if needed
153    require_noerr(ensureBufferSize(32), init_error);
154
155    _reserved->messageQueue = OSArray::withCapacity(4);
156    require(_reserved->messageQueue, init_error);
157
158    _reserved->keyStateSize = 4*((NX_NUMKEYCODES+(EVK_BITS_PER_UNIT-1))/EVK_BITS_PER_UNIT);
159    _reserved->keyState = (kbdBitVector) IOMalloc(_reserved->keyStateSize);
160    bzero(_reserved->keyState, _reserved->keyStateSize);
161    require(_reserved->keyState, init_error);
162    uuid_generate(_reserved->uuid);
163
164#if DEBUG_SECURE_PROMPT
165#warning remove
166    uuid_string_t string;
167    uuid_unparse(_reserved->uuid, string);
168    IOLog("%s made UUID %s\n", __func__, string);
169#endif
170
171    _reserved->uuidState = kUUIDStateNeverSaved;
172
173// vtn3 TODO: setup layouts
174
175    return super::initWithTask(owningTask, security_id, type, properties);
176
177init_error:
178    releaseReserved();
179    return false;
180}
181
182/******************************************************************************/
183bool
184IOHIDSecurePromptClient::start(IOService * provider)
185{
186    if (!_reserved->gate) {
187        IOWorkLoop *loop = provider->getWorkLoop();
188        require(loop, start_error);
189
190        _reserved->gate = IOCommandGate::commandGate(this);
191        require(_reserved->gate, start_error);
192
193        require(kIOReturnSuccess == loop->addEventSource(_reserved->gate), start_error);
194    }
195
196    require(valid(), start_error);
197
198    return super::start(provider);
199
200start_error:
201    return false;
202}
203
204/******************************************************************************/
205void
206IOHIDSecurePromptClient::releaseReserved()
207{
208    if (_reserved) {
209        if (_reserved->gate) {
210            _reserved->gate->release();
211            _reserved->gate = NULL;
212        }
213        if (_reserved->layouts) {
214            _reserved->layouts->release();
215            _reserved->layouts = NULL;
216        }
217
218        ensureBufferSize(0); // special case erase
219
220        if (_reserved->keyboardNotifier) {
221            _reserved->keyboardNotifier->remove();
222            _reserved->keyboardNotifier = NULL;
223        }
224        if (_reserved->keyState) {
225            IOFree( _reserved->keyState, _reserved->keyStateSize);
226            _reserved->keyState = NULL;
227            _reserved->keyStateSize = 0;
228        }
229        IOFree(_reserved, sizeof(IOHIDSecurePromptClient_ExpansionData));
230        _reserved = NULL;
231    }
232}
233
234/******************************************************************************/
235void
236IOHIDSecurePromptClient::free()
237{
238    sync();
239    releaseReserved();
240    super::free();
241}
242
243/******************************************************************************/
244bool
245IOHIDSecurePromptClient::gathering()
246{
247    require(valid(), uninitialized_data);
248    return _reserved->gathering;
249
250uninitialized_data:
251    return false;
252}
253
254/******************************************************************************/
255bool
256IOHIDSecurePromptClient::dead()
257{
258    require(_reserved, uninitialized_data);
259    return _reserved->dead;
260
261uninitialized_data:
262    return true;
263}
264
265/******************************************************************************/
266void
267IOHIDSecurePromptClient::setNotifier(IONotifier *notifier)
268{
269    require(valid(), exit_early);
270    if (_reserved->keyboardNotifier)
271        _reserved->keyboardNotifier->remove();
272
273    _reserved->keyboardNotifier = notifier;
274    if (notifier)
275        notifier->retain();
276
277exit_early:
278    ;
279}
280
281/******************************************************************************/
282IOReturn
283IOHIDSecurePromptClient::postKey(UInt32 key,
284                                 bool down)
285{
286    uintptr_t p1 = key;
287    uintptr_t p2 = down;
288    require(valid(), uninitialized_data);
289    return _reserved->gate->runAction(OSMemberFunctionCast(IOCommandGate::Action,
290                                                               this,
291                                                               &IOHIDSecurePromptClient::postKeyGated),
292                                          (void*)p1, (void*)p2);
293uninitialized_data:
294    return kIOReturnInternalError;
295}
296
297/******************************************************************************/
298/*  There is some debate about using the HID keys or the old ADB keys that come
299    into the function. Everything that comes in right now will be goes from HID
300    to ADB and back to HID.
301 */
302IOReturn
303IOHIDSecurePromptClient::postKeyGated(void * p1, void * p2, void *, void *)
304{
305    UInt32 key = (uintptr_t)p1;
306    bool down = (uintptr_t)p2;
307    bool keep = false;
308    bool wasDown = false;
309    UInt8 hidCode = key < 0x80 ? hid_adb_2_usb_keymap[key] : 0xff;
310    IOReturn result = kIOReturnInternalError;
311
312    if (dead()) {
313        return kIOReturnNotOpen;
314    }
315    if (!gathering()) {
316        return kIOReturnNotReady;
317    }
318    require(valid(), finished);
319
320    result = kIOReturnBadArgument;
321    require(key < 0xff, finished);
322
323    wasDown = EVK_IS_KEYDOWN(key, _reserved->keyState);
324
325    // record all presses, even if we don't suppress them
326    if (down) {
327        if (!wasDown) {
328            EVK_KEYDOWN(key, _reserved->keyState);
329        }
330    }
331    else {
332        if (wasDown) {
333            EVK_KEYUP(key, _reserved->keyState);
334        }
335        // suppress ups
336        result = kIOReturnSuccess;
337        goto finished;
338    }
339
340    if (modifierDown(kControlModifier | kCommandModifier)) {
341        // control or command and we don't use it
342        goto finished;
343    }
344
345    if ((hidCode >= 0x04) && (hidCode <= 0x27)) // a-z, 0-9
346        keep = true;
347    if ((hidCode >= 0x2c) && (hidCode <= 0x38)) // space, [, ], etc.
348        keep = true;
349    if ((hidCode >= 0x54) && (hidCode <= 0x63)) // most keypad
350        keep = true;
351    if ((hidCode >= 0x85) && (hidCode <= 0x86)) // keypad comma, =
352        keep = true;
353
354    if (keep && down && !wasDown) {
355        // This will suppress all repeats and multiple keypresses
356        queueMessage(key);
357        // The secure client has claimed this key for its own. Suppress.
358        result = kIOReturnSuccess;
359    }
360    else {
361        // this is a key that we do not want to suppress.
362    }
363
364finished:
365    return result;
366}
367
368/******************************************************************************/
369void
370IOHIDSecurePromptClient::queueMessage(UInt8 code)
371{
372    require(valid(), uninitialized_data);
373    // This block is for scoping purposes only.
374    {
375        // set up all the data structures
376        UInt8 modifier = modifierState();
377        UInt16 id = _reserved->nextQueueID++;
378        IOHIDSecurePromptClient_KeyqueueEntry entry = {
379            id,
380            modifier,
381            code
382        };
383        IOHIDSecurePromptClient_KeyqueueMessage msg = {
384            {
385                MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND,0),
386                sizeof(IOHIDSecurePromptClient_KeyqueueMessage),
387                _reserved->port,
388                MACH_PORT_NULL,
389                0,
390                keyMessage
391            },
392            {
393                0
394            },
395            id
396        };
397
398        // add the message to our internal queue
399        OSData          *entryData = OSData::withBytes(&entry, sizeof(entry));
400        require(entryData, out_of_memory);
401        _reserved->messageQueue->setObject(entryData);
402        entryData->release();
403
404        // and finally send the message
405        kern_return_t ret = mach_msg_send_from_kernel(&msg.message, msg.message.msgh_size);
406        switch ( ret ) {
407            case MACH_MSG_SUCCESS: /* Message is posted */
408                // good
409                break;
410            case MACH_SEND_TIMED_OUT: /* Already has a message posted */
411                // bad
412                IOLog("%s: Unexpected response to mach_msg_send_from_kernel\n", __func__);
413                break;
414            default: /* Log the error */
415                // ugly
416                IOLog("%s: Very unexpected response to mach_msg_send_from_kernel: 0x%08x\n", __func__, ret);
417                break;
418        }
419    }
420out_of_memory:
421uninitialized_data:
422    ;
423}
424
425/******************************************************************************/
426IOReturn
427IOHIDSecurePromptClient::clientClose()
428{
429    OSIterator *itr = NULL;
430    require(_reserved, uninitialized_data);
431    sync();
432    _reserved->gathering = false;
433    _reserved->dead = true;
434
435    // notify all providers of the state change
436    itr = getProviderIterator();
437    if (itr) {
438        bool done = false;
439        while (!done) {
440            OSObject *provider;
441            while (!done && (NULL != (provider = itr->getNextObject()))) {
442                IOService *parent = OSDynamicCast(IOService, provider);
443                detach(parent);
444            }
445            if (itr->isValid()) {
446                done = true;
447            }
448            else {
449                // we may end up sending the mseeage to the same provider twice.
450                // that should not cause any issues.
451                itr->reset();
452            }
453        }
454        itr->release();
455    }
456
457uninitialized_data:
458    return super::clientClose();
459}
460
461/******************************************************************************/
462IOReturn
463IOHIDSecurePromptClient::registerNotificationPort(mach_port_t port,
464                                                  UInt32 type,
465                                                  io_user_reference_t refCon)
466{
467    require(valid(), uninitialized_data);
468    // A type of 1 was chosen for no particular reason.
469    if (type == 1) {
470        _reserved->port = port;
471        return kIOReturnSuccess;
472    }
473uninitialized_data:
474    return super::registerNotificationPort(port, type, refCon);
475}
476
477/******************************************************************************/
478IOExternalMethod *
479IOHIDSecurePromptClient::getTargetAndMethodForIndex(IOService ** targetP,
480                                                    UInt32 index)
481{
482    static const IOExternalMethod methodTemplate[] = {
483        // 0: kIOHIDSecurePromptClient_setGatheringMethod
484        { NULL, (IOMethod)&IOHIDSecurePromptClient::setGatheringMethod,	kIOUCScalarIScalarO, 1, 0 },
485        // 1: kIOHIDSecurePromptClient_setLayoutMethod
486        { NULL, (IOMethod)&IOHIDSecurePromptClient::setLayoutMethod,	kIOUCScalarIScalarO, 1, 0 },
487        // 2: kIOHIDSecurePromptClient_confirmKeyMethod
488        { NULL, (IOMethod)&IOHIDSecurePromptClient::confirmKeyMethod, 	kIOUCScalarIScalarO, 1, 1 },
489        // 3: kIOHIDSecurePromptClient_getGatheringMethod
490        { NULL, (IOMethod)&IOHIDSecurePromptClient::getGatheringMethod, kIOUCScalarIScalarO, 1, 0 },
491        // 4: kIOHIDSecurePromptClient_deleteKeysMethod
492        { NULL, (IOMethod)&IOHIDSecurePromptClient::deleteKeysMethod, 	kIOUCScalarIScalarO, 2, 1 },
493        // 5: kIOHIDSecurePromptClient_getLayoutMethod
494        { NULL, (IOMethod)&IOHIDSecurePromptClient::getLayoutMethod, 	kIOUCScalarIScalarO, 1, 0 },
495        // 6: kIOHIDSecurePromptClient_getIdentifierMethod
496        { NULL, (IOMethod)&IOHIDSecurePromptClient::getIdentifierMethod, kIOUCScalarIScalarO, 0, 1 },
497        // 7: kIOHIDSecurePromptClient_compareClientMethod
498        { NULL, (IOMethod)&IOHIDSecurePromptClient::compareClientMethod, kIOUCScalarIScalarO, 1, 0 },
499        // 8: kIOHIDSecurePromptClient_setUUIDMethod
500        { NULL, (IOMethod)&IOHIDSecurePromptClient::setUUIDMethod, 		kIOUCStructIStructO, sizeof(uuid_t), 0 },
501        // 9: kIOHIDSecurePromptClient_getUUIDMethod
502        { NULL, (IOMethod)&IOHIDSecurePromptClient::getUUIDMethod, 		kIOUCStructIStructO, 0, sizeof(uuid_t) },
503        // 10: kIOHIDSecurePromptClient_getInsertionPoint
504        { NULL, (IOMethod)&IOHIDSecurePromptClient::getInsertionPointMethod,  kIOUCScalarIScalarO, 0, 1 },
505        // 11: kIOHIDSecurePromptClient_setInsertionPoint
506        { NULL, (IOMethod)&IOHIDSecurePromptClient::setInsertionPointMethod,  kIOUCScalarIScalarO, 1, 0 },
507        // 12: kIOHIDSecurePromptClient_injectString
508        { NULL, (IOMethod)&IOHIDSecurePromptClient::injectStringMethod, kIOUCStructIStructO, kIOUCVariableStructureSize, 0 },
509        // 13: redacted
510        { NULL, NULL, 0, 0, 0 },
511    };
512
513    require(valid(), uninitialized_data);
514    require(index < (sizeof(methodTemplate) / sizeof(methodTemplate[0])), bad_argument);
515
516    *targetP = this;
517    return( (IOExternalMethod *)(methodTemplate + index) );
518
519uninitialized_data:
520bad_argument:
521    return NULL;
522}
523
524/******************************************************************************/
525IOReturn
526IOHIDSecurePromptClient::setGatheringMethod(void * p1, void * p2 __unused, void * p3 __unused, void * p4 __unused, void * p5 __unused, void * p6 __unused)
527{
528    UInt32 state = (uintptr_t)p1;
529    return setGathering(state);
530}
531
532/******************************************************************************/
533IOReturn
534IOHIDSecurePromptClient::setGathering(UInt32 state)
535{
536    uintptr_t tempState = state ? true : false;
537    require(valid(), uninitialized_data);
538    require(_reserved->uuidState != kUUIDStateIsGhost, uninitialized_data);
539
540    if (gathering() != tempState) {
541        _reserved->gathering = tempState;
542
543        // notify all providers of the state change
544        OSIterator *itr = getProviderIterator();
545        if (itr) {
546            bool done = false;
547            while (!done) {
548                OSObject *provider;
549                while (!done && (NULL != (provider = itr->getNextObject()))) {
550                    IOService *parent = OSDynamicCast(IOService, provider);
551                    parent->message(gatheringMessage, this, (void*)tempState);
552                }
553                if (itr->isValid()) {
554                    done = true;
555                }
556                else {
557                    // we may end up sending the mseeage to the same provider twice.
558                    // that should not cause any issues.
559                    itr->reset();
560                }
561            }
562            itr->release();
563        }
564    }
565
566// vtn3 TODO: release local modifier flags
567
568    // clear out any queued keystrokes
569    if (_reserved->messageQueue) {
570    	__EraseDataArray(_reserved->messageQueue);
571        _reserved->messageQueue->release();
572    }
573    _reserved->messageQueue = OSArray::withCapacity(4);
574
575    return kIOReturnSuccess;
576
577uninitialized_data:
578    return kIOReturnNotOpen;
579}
580
581/******************************************************************************/
582IOReturn
583IOHIDSecurePromptClient::setLayoutMethod(void * p1, void * p2, void * p3, void * p4, void * p5 __unused, void * p6 __unused)
584{
585    require(valid(), uninitialized_data);
586    return _reserved->gate->runAction(OSMemberFunctionCast(IOCommandGate::Action,
587                                                               this,
588                                                               &IOHIDSecurePromptClient::setLayoutGated),
589                                          p1, p2, p3, p4);
590uninitialized_data:
591    return kIOReturnInternalError;
592}
593
594/******************************************************************************/
595IOReturn
596IOHIDSecurePromptClient::setLayoutGated(void * p1, void * p2 __unused, void * p3 __unused, void * p4 __unused)
597{
598    UInt32 layout = (uintptr_t)p1;
599    return setLayout(layout);
600}
601
602/******************************************************************************/
603IOReturn
604IOHIDSecurePromptClient::setLayout(UInt32 layout)
605{
606    require(valid(), uninitialized_data);
607    require(_reserved->uuidState != kUUIDStateIsGhost, uninitialized_data);
608
609    if (_reserved->uuidState == kUUIDStateIsClean)
610        _reserved->uuidState = kUUIDStateIsDirty;
611
612// vtn3 TODO: validate layout entry
613
614    _reserved->layout = layout;
615
616    // clear out any queued keystrokes
617    if (_reserved->messageQueue) {
618        __EraseDataArray(_reserved->messageQueue);
619        _reserved->messageQueue->release();
620    }
621    _reserved->messageQueue = OSArray::withCapacity(4);
622
623    // vtn3 TODO: release local modifier flags
624    // vtn3 TODO: remap value queue
625
626    return kIOReturnSuccess;
627
628uninitialized_data:
629    return kIOReturnInternalError;
630}
631
632/******************************************************************************/
633IOReturn
634IOHIDSecurePromptClient::confirmKeyMethod(void * p1, void * p2, void * p3, void * p4, void * p5 __unused, void * p6 __unused)
635{
636    require(valid(), uninitialized_data);
637    return _reserved->gate->runAction(OSMemberFunctionCast(IOCommandGate::Action,
638                                                               this,
639                                                               &IOHIDSecurePromptClient::confirmKeyGated),
640                                          p1, p2, p3, p4);
641uninitialized_data:
642    return kIOReturnInternalError;
643}
644
645/******************************************************************************/
646IOReturn
647IOHIDSecurePromptClient::confirmKeyGated(void * p1, void * p2, void * /* p3 */, void * /* p4 */)
648{
649    UInt32 id = (uintptr_t)p1;
650    return confirmKey(id, (UInt32*)p2);
651}
652
653/******************************************************************************/
654IOReturn
655IOHIDSecurePromptClient::confirmKey(UInt32 id,
656                                    UInt32 *count)
657{
658    unsigned int index = 0;
659    IOReturn result = kIOReturnBadArgument;
660    OSCollectionIterator *iterator = NULL;
661
662    require(valid(), uninitialized_data);
663    require(_reserved->uuidState != kUUIDStateIsGhost, uninitialized_data);
664    result = kIOReturnInternalError;
665    require(count, invalid_argument);
666    result = kIOReturnBadMessageID;
667
668    // Search through the queue for the supplied ID
669    iterator = OSCollectionIterator::withCollection(_reserved->messageQueue);
670    require(iterator, finished);
671    do {
672        OSObject * obj = iterator->getNextObject();
673        if (!obj) {
674            if (iterator->isValid()) {
675                goto finished;
676            }
677            else {
678                iterator->reset();
679            }
680        }
681        else {
682            OSData *entryData = OSDynamicCast(OSData, obj);
683            IOHIDSecurePromptClient_KeyqueueEntry *entry = NULL;
684            if (entryData == NULL) {
685                IOLog("%s: Found bad index in messageQueue: %d\n", __func__, index);
686                continue;
687            }
688            entry = (IOHIDSecurePromptClient_KeyqueueEntry*)entryData->getBytesNoCopy();
689            if (entry->id == id) {
690                // We have a match. Append it and remove it from the queue.
691                result = appendConfirmedKeyCode(entry->modifier, entry->code);
692                __EraseData(entryData);
693                _reserved->messageQueue->removeObject(index);
694
695                // Now set the return count
696                *count = _reserved->stringLength;
697                goto finished;
698            }
699        }
700    }
701    while (true);
702
703finished:
704invalid_argument:
705uninitialized_data:
706    if (iterator)
707        iterator->release();
708
709    return result;
710}
711
712/******************************************************************************/
713IOReturn
714IOHIDSecurePromptClient::appendConfirmedKeyCode(UInt8 modifier,
715                                                UInt8 code)
716{
717    // Remap the zero key (a) to be an invalid key code
718    IOReturn    result = kIOReturnInternalError;
719    UInt8       newCode = code ? code : 0xff;
720    IOHIDSecurePromptClient_RawKeystrokeData newKeystroke = {{ modifier }, { newCode }};
721
722    // vtn3 TODO: get real value here.
723    UTF32Char   newUnicode = (modifier << 16) | newCode;
724    require(valid(), exit_early);
725
726    if (_reserved->uuidState == kUUIDStateIsClean)
727        _reserved->uuidState = kUUIDStateIsDirty;
728
729    // vtn3 TODO: do something intelegent here.
730    // if there is a previous key code
731    // if it combines
732    // replace the old entry
733    // otherwise
734    {
735        // append the new entry
736        result = kIOReturnNoMemory;
737        require_noerr(ensureBufferSize(_reserved->stringLength + 1), exit_early);
738        __InsertBytes(_reserved->unicode, _reserved->insertionPoint, _reserved->stringLength, &newUnicode, 1, sizeof(newUnicode));
739        __InsertBytes(_reserved->rawKeystrokes, _reserved->insertionPoint, _reserved->stringLength, &newKeystroke, 1, sizeof(newKeystroke));
740        __EraseMemory(&newKeystroke, sizeof(newKeystroke));
741        __EraseMemory(&newUnicode, sizeof(newUnicode));
742        _reserved->insertionPoint++;
743        _reserved->stringLength++;
744        //IOLog("%s insertionPoint = %d; stringLength = %d; bufferLength = %d\n", __func__, _reserved->insertionPoint, _reserved->stringLength, _reserved->bufferLength);
745    }
746    result = kIOReturnSuccess;
747
748exit_early:
749    return result;
750}
751
752/******************************************************************************/
753IOReturn
754IOHIDSecurePromptClient::deleteKeysMethod(void * p1, void * p2, void * p3, void * p4, void * p5 __unused, void * p6 __unused)
755{
756    require(valid(), uninitialized_data);
757    return _reserved->gate->runAction(OSMemberFunctionCast(IOCommandGate::Action,
758                                                           this,
759                                                           &IOHIDSecurePromptClient::deleteKeysGated),
760                                      p1, p2, p3, p4);
761uninitialized_data:
762    return kIOReturnInternalError;
763}
764
765/******************************************************************************/
766IOReturn
767IOHIDSecurePromptClient::deleteKeysGated(void * p1, void * p2, void * p3, void * p4 __unused)
768{
769    UInt32 length;
770    IOReturn result;
771    require(p3, invalid_argument);
772    result = deleteKeys((intptr_t)p1, (uintptr_t)p2, &length);
773    *(UInt64*)p3 = length;
774    return result;
775
776invalid_argument:
777    return kIOReturnBadArgument;
778}
779
780/******************************************************************************/
781IOReturn
782IOHIDSecurePromptClient::deleteKeys(SInt32 index,
783                                    UInt32 count,
784                                    UInt32 *newLength)
785{
786    require(valid(), uninitialized_data);
787    require(_reserved->uuidState != kUUIDStateIsGhost, uninitialized_data);
788    {
789        SInt32 deleteBegin = index;
790
791        // in case of early return, make sure newLength returns the length
792        *newLength = _reserved->stringLength;
793
794        if ((count == 0) || (_reserved->stringLength == 0)) {
795            // this is a valid exit early case
796            return kIOReturnSuccess;
797        }
798
799        if (deleteBegin < 0) {
800            // delete from the end
801            deleteBegin = _reserved->stringLength - count;
802            if (deleteBegin < 0)
803                deleteBegin = 0;
804        }
805        require(_reserved->stringLength > (unsigned)deleteBegin, overrun);
806
807        if (((SInt64)count) > _reserved->stringLength - deleteBegin) {
808            count = _reserved->stringLength - deleteBegin;
809        }
810
811        memmove(_reserved->unicode + deleteBegin,
812                _reserved->unicode + (deleteBegin + count),
813                (_reserved->stringLength - deleteBegin - count) * sizeof(UTF32Char));
814        memmove(_reserved->rawKeystrokes + deleteBegin,
815                _reserved->rawKeystrokes + (deleteBegin + count),
816                (_reserved->stringLength - deleteBegin - count) * sizeof(IOHIDSecurePromptClient_RawKeystrokeData));
817
818        // note it is dirty
819        if (_reserved->uuidState == kUUIDStateIsClean)
820            _reserved->uuidState = kUUIDStateIsDirty;
821
822        _reserved->stringLength -= count;
823        *newLength = _reserved->stringLength;
824
825        // adjust insertion point
826        if (_reserved->insertionPoint > index) {
827            _reserved->insertionPoint -= count;
828            if (_reserved->insertionPoint < index) {
829                _reserved->insertionPoint = index;
830            }
831        }
832
833        //IOLog("%s insertionPoint = %d; stringLength = %d; bufferLength = %d\n", __func__, _reserved->insertionPoint, _reserved->stringLength, _reserved->bufferLength);
834
835        return kIOReturnSuccess;
836    }
837uninitialized_data:
838    return kIOReturnInternalError;
839overrun:
840    return kIOReturnOverrun;
841}
842
843/******************************************************************************/
844bool
845IOHIDSecurePromptClient::valid()
846{
847    require(_reserved, invalid);
848// vtn3 TODO: require layouts
849//    require(_reserved->layouts, invalid);
850    nrequire(_reserved->dead, invalid);
851    require(_reserved->unicode, invalid);
852    require(_reserved->rawKeystrokes, invalid);
853    require(_reserved->messageQueue, invalid);
854    require(_reserved->gate, invalid);
855    require(_reserved->keyState, invalid);
856    require(_reserved->insertionPoint <= _reserved->stringLength, invalid);
857
858    return true;
859invalid:
860    return false;
861}
862
863/******************************************************************************/
864#define CONTROL_DOWN(X)     (EVK_IS_KEYDOWN(0x3b, X) || EVK_IS_KEYDOWN(0x3e, X)) // ADB Control keys
865#define SHIFT_DOWN(X)       (EVK_IS_KEYDOWN(0x38, X) || EVK_IS_KEYDOWN(0x3c, X)) // ADB Shift keys
866#define OPTION_DOWN(X)      (EVK_IS_KEYDOWN(0x3a, X) || EVK_IS_KEYDOWN(0x3d, X)) // ADB Alt keys
867#define COMMAND_DOWN(X)     (EVK_IS_KEYDOWN(0x37, X) || EVK_IS_KEYDOWN(0x36, X)) // ADB GUI keys
868
869/******************************************************************************/
870UInt8
871IOHIDSecurePromptClient::modifierState()
872{
873    UInt8 result = (CONTROL_DOWN(_reserved->keyState)   ? kControlModifier  : 0) |
874                   (SHIFT_DOWN(_reserved->keyState)     ? kShiftModifier    : 0) |
875                   (OPTION_DOWN(_reserved->keyState)    ? kOptionModifier   : 0) |
876                   (COMMAND_DOWN(_reserved->keyState)   ? kCommandModifier  : 0);
877    return result;
878}
879
880/******************************************************************************/
881bool
882IOHIDSecurePromptClient::modifierDown(UInt8 modifierFlag)
883{
884    bool result = (modifierState() & modifierFlag) ? true : false;
885    return result;
886}
887
888/******************************************************************************/
889IOReturn
890IOHIDSecurePromptClient::getIdentifierMethod(void * p1, void * p2 __unused, void * p3 __unused, void * p4 __unused, void * p5 __unused, void * p6 __unused)
891{
892    require(valid() && p1, uninitialized_data);
893
894    *(UInt64*)p1 = identifier();
895    return kIOReturnSuccess;
896
897uninitialized_data:
898    return kIOReturnInternalError;
899}
900
901/******************************************************************************/
902uint64_t
903IOHIDSecurePromptClient::identifier()
904{
905    uint64_t result = 0xffffffff & (uint64_t)this;
906    return result;
907}
908
909/******************************************************************************/
910IOReturn
911IOHIDSecurePromptClient::compareClientMethod(void * p1, void *, void *, void *, void *, void *)
912{
913    // We deviate from our idiom above because we do not wish to hold both
914    // gates at the same time. Probably would not cause a problem, but it is possible,
915    OSData          *tempData = NULL;
916    IOReturn        result = kIOReturnInternalError;
917    uint64_t        targetID = (uintptr_t)p1;
918    OSIterator      *siblings = NULL;
919    IORegistryEntry *parent = NULL;
920    IOHIDSecurePromptClient *target = NULL;
921    uuid_t          targetUUID;
922    uuid_t          selfUUID;
923    UInt8           *targetBuffer = NULL;
924    UInt8           *selfBuffer = NULL;
925    uint32_t        targetBufferSize;
926    uint32_t        selfBufferSize;
927
928    require(valid(), uninitialized_data);
929    require(AppleFDEKeyStore::instance, uninitialized_data);
930
931    // find the target
932    parent = getParentEntry(gIOServicePlane);
933    require(parent, no_siblings);
934    siblings = parent->getChildIterator(gIOServicePlane);
935    require(siblings, no_siblings);
936
937    while(NULL != (target = nextForIterator(siblings))) {
938        if (target->identifier() == targetID)
939            break;
940    }
941
942    require(target, no_target);
943    require(target->valid(), no_target);
944
945    result = target->getUUIDMethod(targetUUID, NULL, NULL, NULL, NULL, NULL);
946    require(result == kIOReturnSuccess, no_target);
947
948    result = getUUIDMethod(selfUUID, NULL, NULL, NULL, NULL, NULL);
949    require(result == kIOReturnSuccess, no_target);
950
951    sync();
952    target->sync();
953
954#if DEBUG_SECURE_PROMPT
955#warning remove
956    uuid_string_t string;
957    uuid_unparse(selfUUID, string);
958    IOLog("%s of UUID %s to", __func__, string);
959    uuid_unparse(targetUUID, string);
960    IOLog(" UUID %s", string);
961#endif
962
963    targetBuffer = (UInt8*)IOMalloc(AKS_MAX_PASSPHRASE_SIZE);
964    selfBuffer = (UInt8*)IOMalloc(AKS_MAX_PASSPHRASE_SIZE);
965    require(targetBuffer && selfBuffer, out_of_memory);
966
967    // check the buffers
968    targetBufferSize = AKS_MAX_PASSPHRASE_SIZE;
969    result = AppleFDEKeyStore::instance->getPassphrase(targetUUID, targetBuffer, targetBufferSize, &targetBufferSize);
970    require(result == kIOReturnSuccess, keystore_error);
971    selfBufferSize = AKS_MAX_PASSPHRASE_SIZE;
972    result = AppleFDEKeyStore::instance->getPassphrase(selfUUID, selfBuffer, selfBufferSize, &selfBufferSize);
973    require(result == kIOReturnSuccess, keystore_error);
974
975    if ((targetBufferSize == selfBufferSize) && (0 == memcmp(targetBuffer, selfBuffer, targetBufferSize))) {
976        goto success;
977    }
978
979    // for each acceptable layout
980        // setLayout on self in gate to that layout
981        // sync
982        // check the buffers (see above)
983
984    // if you get here, you have failed
985    result = kIOReturnNotPrivileged;
986
987success:
988keystore_error:
989out_of_memory:
990    if (targetBuffer) {
991        __EraseMemory(targetBuffer, AKS_MAX_PASSPHRASE_SIZE);
992        IOFree(targetBuffer, AKS_MAX_PASSPHRASE_SIZE);
993    }
994    if (selfBuffer) {
995        __EraseMemory(selfBuffer, AKS_MAX_PASSPHRASE_SIZE);
996        IOFree(selfBuffer, AKS_MAX_PASSPHRASE_SIZE);
997    }
998
999no_target:
1000    if (siblings) {
1001        siblings->release();
1002    }
1003
1004no_siblings:
1005    if (tempData) {
1006        __EraseData(tempData);
1007        tempData->release();
1008    }
1009
1010uninitialized_data:
1011    return result;
1012}
1013
1014/******************************************************************************/
1015IOReturn
1016IOHIDSecurePromptClient::getUUIDMethod(void * p1, void * p2 __unused, void * p3 __unused, void * p4 __unused, void * p5 __unused, void * p6 __unused)
1017{
1018    return _reserved->gate->runAction(OSMemberFunctionCast(IOCommandGate::Action,
1019                                                           this,
1020                                                           &IOHIDSecurePromptClient::getUUIDGated),
1021                                      p1, p2, p3, p4);
1022}
1023
1024/******************************************************************************/
1025IOReturn
1026IOHIDSecurePromptClient::getUUIDGated(void * p1, void * p2 __unused, void * p3 __unused, void * p4 __unused)
1027{
1028    UInt8 *data = (UInt8*)p1;
1029
1030    require(valid(), uninitialized_data);
1031    require(p1, uninitialized_data);
1032
1033    if (_reserved->uuidState == kUUIDStateNeverSaved)
1034        _reserved->uuidState = kUUIDStateIsDirty;
1035
1036    bcopy(_reserved->uuid, data, sizeof(uuid_t));
1037    return kIOReturnSuccess;
1038
1039uninitialized_data:
1040    return kIOReturnInternalError;
1041}
1042
1043/******************************************************************************/
1044IOReturn
1045IOHIDSecurePromptClient::setUUIDMethod(void * p1, void * p2, void * p3, void * p4, void * p5 __unused, void * p6 __unused)
1046{
1047    return _reserved->gate->runAction(OSMemberFunctionCast(IOCommandGate::Action,
1048                                                           this,
1049                                                           &IOHIDSecurePromptClient::setUUIDGated),
1050                                      p1, p2, p3, p4);
1051}
1052
1053/******************************************************************************/
1054IOReturn
1055IOHIDSecurePromptClient::setUUIDGated(void * p1, void * p2 __unused, void * p3 __unused,void * p4 __unused)
1056{
1057    require(valid(), uninitialized_data);
1058    require(p1, uninitialized_data);
1059    return setUUID((UInt8*)p1);
1060
1061uninitialized_data:
1062    return kIOReturnInternalError;
1063}
1064
1065/******************************************************************************/
1066IOReturn
1067IOHIDSecurePromptClient::setUUID(UInt8* bytes_in)
1068{
1069    IOReturn result = kIOReturnNoMemory;
1070    uint32_t bufferSize = AKS_MAX_PASSPHRASE_SIZE;
1071
1072    bcopy(bytes_in, _reserved->uuid, sizeof(uuid_t));
1073
1074#if DEBUG_SECURE_PROMPT
1075#warning remove
1076    uuid_string_t string;
1077    uuid_unparse(_reserved->uuid, string);
1078    IOLog("%s set UUID to %s\n", __func__, string);
1079#endif
1080
1081    if (_reserved->uuidState != kUUIDStateIsGhost) {
1082        setGathering(0);
1083        _reserved->uuidState = kUUIDStateIsGhost;
1084    }
1085
1086    UInt8 *buffer = (UInt8*)IOMalloc(AKS_MAX_PASSPHRASE_SIZE);
1087    require(buffer, out_of_memory);
1088
1089    // check the UUIDs
1090    bufferSize = AKS_MAX_PASSPHRASE_SIZE;
1091    result = AppleFDEKeyStore::instance->getPassphrase(_reserved->uuid, buffer, bufferSize, &bufferSize);
1092    require(result == kIOReturnSuccess, bad_uuid);
1093
1094bad_uuid:
1095out_of_memory:
1096    if (buffer) {
1097		__EraseMemory(buffer, AKS_MAX_PASSPHRASE_SIZE);
1098		IOFree(buffer, AKS_MAX_PASSPHRASE_SIZE);
1099    }
1100
1101    return result;
1102}
1103
1104/******************************************************************************/
1105IOReturn
1106IOHIDSecurePromptClient::getInsertionPointMethod(void * p1, void *, void *, void *, void *, void *)
1107{
1108    require(valid() && p1, uninitialized_data);
1109
1110    *(uint64_t*)p1 = getInsertionPoint();
1111    return kIOReturnSuccess;
1112
1113uninitialized_data:
1114    return kIOReturnInternalError;
1115}
1116
1117/******************************************************************************/
1118uint64_t
1119IOHIDSecurePromptClient::getInsertionPoint()
1120{
1121    return _reserved->insertionPoint;
1122}
1123
1124/******************************************************************************/
1125IOReturn
1126IOHIDSecurePromptClient::setInsertionPointMethod(void * p1, void * p2, void * p3,
1127                                                 void * p4, void * p5 __unused, void * p6 __unused)
1128{
1129    return _reserved->gate->runAction(OSMemberFunctionCast(IOCommandGate::Action,
1130                                                           this,
1131                                                           &IOHIDSecurePromptClient::setInsertionPointGated),
1132                                      p1, p2, p3, p4);
1133}
1134
1135/******************************************************************************/
1136IOReturn
1137IOHIDSecurePromptClient::setInsertionPointGated(void * p1, void * p2 __unused, void * p3 __unused,void * p4 __unused)
1138{
1139    IOReturn result = kIOReturnBadArgument;
1140    uintptr_t value = (uintptr_t)p1;
1141
1142    require(valid(), bad_argument);
1143    require(value < 0x0fff, bad_argument); // cannot set the insertion pointer past the 4000th character
1144
1145    if (value == 0) {
1146        _reserved->insertionPoint = 0;
1147    }
1148    else {
1149        if (value >= _reserved->stringLength) {
1150            _reserved->insertionPoint = _reserved->stringLength;
1151        }
1152        else {
1153            _reserved->insertionPoint = value;
1154        }
1155    }
1156    result = kIOReturnSuccess;
1157
1158bad_argument:
1159    return result;
1160}
1161
1162/******************************************************************************/
1163IOReturn
1164IOHIDSecurePromptClient::injectStringMethod(void * p1, void * p2, void * p3,
1165                                            void * p4, void * p5 __unused, void * p6 __unused)
1166{
1167    return _reserved->gate->runAction(OSMemberFunctionCast(IOCommandGate::Action,
1168                                                           this,
1169                                                           &IOHIDSecurePromptClient::injectStringGated),
1170                                      p1, p2, p3, p4);
1171}
1172
1173/******************************************************************************/
1174IOReturn
1175IOHIDSecurePromptClient::injectStringGated(void * p1, void * p2, void * p3 __unused,void * p4 __unused)
1176{
1177    IOReturn result = kIOReturnBadArgument;
1178    IOHIDSecurePromptClient_RawKeystrokeData * dummyRawData = NULL;
1179    UTF32Char *string = (UTF32Char*)p1;
1180    intptr_t length = (intptr_t)p2 / sizeof(UTF32Char);
1181    vm_size_t dummyDataSize = length * sizeof(IOHIDSecurePromptClient_RawKeystrokeData);
1182
1183    require(valid(), bad_argument);
1184    require(p1, bad_argument);
1185
1186    require((length > 0) && (length < 0x0fff), bad_argument); // not going to insert more than 4000 characters
1187
1188    dummyRawData = (IOHIDSecurePromptClient_RawKeystrokeData*)IOMalloc(dummyDataSize);
1189    memset(dummyRawData, 0xff, dummyDataSize);
1190
1191    __InsertBytes(_reserved->rawKeystrokes, _reserved->insertionPoint, _reserved->stringLength, string, length,  sizeof(UTF32Char));
1192    __InsertBytes(_reserved->unicode, _reserved->insertionPoint, _reserved->stringLength, dummyRawData, length,  sizeof(UTF32Char));
1193    __EraseMemory(string, length * sizeof(UTF32Char));
1194    _reserved->insertionPoint += length;
1195    result = kIOReturnSuccess;
1196
1197bad_argument:
1198    if (dummyRawData)
1199        IOFree(dummyRawData, dummyDataSize);
1200    return result;
1201}
1202
1203/******************************************************************************/
1204IOReturn
1205IOHIDSecurePromptClient::getGatheringMethod(void * p1, void * p2 __unused, void * p3 __unused, void * p4 __unused, void * p5 __unused, void * p6 __unused)
1206{
1207    require(valid(), uninitialized_data);
1208    require(p1, uninitialized_data);
1209
1210    *(UInt64*)p1 = gathering();
1211
1212    return kIOReturnSuccess;
1213
1214uninitialized_data:
1215    *(UInt64*)p1 = false;
1216
1217    return kIOReturnInternalError;
1218}
1219
1220/******************************************************************************/
1221void
1222IOHIDSecurePromptClient::sync()
1223{
1224    if (_reserved && _reserved->gate && !_reserved->dead)
1225        _reserved->gate->runAction(OSMemberFunctionCast(IOCommandGate::Action,
1226                                                        this,
1227                                                        &IOHIDSecurePromptClient::syncGated),
1228                                   0, 0, 0, 0);
1229}
1230
1231/******************************************************************************/
1232IOReturn
1233IOHIDSecurePromptClient::syncGated(void * p1 __unused, void * p2 __unused, void * p3 __unused,void * p4 __unused)
1234{
1235    if (_reserved && (_reserved->uuidState == kUUIDStateIsDirty) && valid()) {
1236        IOReturn result;
1237
1238        // this will return an error if the passphrase does not exist. don't care.
1239        AppleFDEKeyStore::instance->deletePassphrase(_reserved->uuid);
1240
1241        if (_reserved->stringLength > 0) {
1242            result = AppleFDEKeyStore::instance->setPassphrase(_reserved->uuid,
1243                                                               _reserved->unicode,
1244                                                               _reserved->stringLength * sizeof(UTF32Char));
1245            if (result != kIOReturnSuccess)
1246                IOLog("%s failed to setPassphrase for code: %08x\n", __func__, result);
1247        }
1248
1249        _reserved->uuidState = kUUIDStateIsClean;
1250
1251#if DEBUG_SECURE_PROMPT
1252#warning remove
1253        uuid_string_t string;
1254        uuid_unparse(_reserved->uuid, string);
1255        IOLog("%s on %s\n", __func__, string);
1256#endif
1257    }
1258    return kIOReturnSuccess;
1259}
1260
1261/******************************************************************************/
1262IOReturn
1263IOHIDSecurePromptClient::getLayoutMethod(void * p1, void * p2 __unused, void * p3 __unused, void * p4 __unused, void * p5 __unused, void * p6 __unused)
1264{
1265    require(valid(), uninitialized_data);
1266    require(p1, uninitialized_data);
1267
1268    *(UInt64*)p1 = _reserved->layout;
1269
1270    return kIOReturnSuccess;
1271
1272uninitialized_data:
1273    *(UInt64*)p1 = 0;
1274
1275    return kIOReturnInternalError;
1276}
1277
1278/******************************************************************************/
1279IOHIDSecurePromptClient*
1280IOHIDSecurePromptClient::nextForIterator(OSIterator * iterator)
1281{
1282    IOHIDSecurePromptClient *client = NULL;
1283    do {
1284        OSObject * obj = iterator->getNextObject();
1285        if (!obj) {
1286            if (iterator->isValid()) {
1287                return NULL;
1288            }
1289            else {
1290                iterator->reset();
1291            }
1292        }
1293        else {
1294            client = OSDynamicCast(IOHIDSecurePromptClient, obj);
1295        }
1296    }
1297    while (!client);
1298
1299    return client;
1300}
1301
1302/******************************************************************************/
1303void
1304__EraseData(OSData *target)
1305{
1306    if (target) {
1307        unsigned int size = target->getLength();
1308        if (size) {
1309            void *bytes = (void*)target->getBytesNoCopy();
1310            __EraseMemory(bytes, size);
1311        }
1312    }
1313}
1314
1315/******************************************************************************/
1316void
1317__EraseMemory(void *mem, UInt32 size)
1318{
1319    if (mem) {
1320        // overwrite with 1s, then 0s, just in case. Just in case why? Just do it, K?
1321        memset(mem, 0xFF, size);
1322        memset(mem, 0x00, size);
1323    }
1324}
1325
1326/******************************************************************************/
1327void __EraseDataArray(OSArray *target)
1328{
1329    OSCollectionIterator *iterator = NULL;
1330    require(target, finished);
1331
1332    iterator = OSCollectionIterator::withCollection(target);
1333    require(iterator, finished);
1334    do {
1335        OSObject * obj = iterator->getNextObject();
1336        if (!obj) {
1337            if (iterator->isValid()) {
1338                goto finished;
1339            }
1340            else {
1341                iterator->reset();
1342            }
1343        }
1344        else {
1345            OSData *dict = OSDynamicCast(OSData, obj);
1346            __EraseData(dict);
1347        }
1348    }
1349    while (true);
1350
1351finished:
1352    if (iterator)
1353        iterator->release();
1354}
1355
1356/******************************************************************************/
1357IOReturn
1358IOHIDSecurePromptClient::ensureBufferSize(UInt32 size)
1359{
1360    IOReturn result = kIOReturnSuccess;
1361    UInt8 *oldBuffer = NULL;
1362    UInt32 oldBufferSize = 0;
1363    UInt8 *newBuffer = NULL;
1364    UInt8 *newKeystrokeOffset;
1365    UInt32 newBufferSize = 0;
1366    UInt32 newSize = size;
1367
1368    if (_reserved->bufferLength >= size)
1369        goto finished;
1370    if (!size) {
1371        oldBuffer = (UInt8*)_reserved->unicode;
1372        oldBufferSize = _reserved->bufferLength * (sizeof(UTF32Char) + sizeof(IOHIDSecurePromptClient_RawKeystrokeData));
1373        goto finished;
1374    }
1375
1376    // round size up to next power of two
1377    newSize--;
1378    newSize |= newSize >> 1;
1379    newSize |= newSize >> 2;
1380    newSize |= newSize >> 4;
1381    newSize |= newSize >> 8;
1382    newSize |= newSize >> 16;
1383    newSize++;
1384
1385    result = kIOReturnNoMemory;
1386    require(newSize < 1024, finished);
1387
1388    newBufferSize = newSize * (sizeof(UTF32Char) + sizeof(IOHIDSecurePromptClient_RawKeystrokeData));
1389    newBuffer = (UInt8*)IOMalloc(newBufferSize);
1390    require(newBuffer, finished);
1391    newKeystrokeOffset = newBuffer + newSize * sizeof(UTF32Char);
1392    memcpy(newBuffer, _reserved->unicode, _reserved->stringLength * sizeof(UTF32Char));
1393    memcpy(newKeystrokeOffset, _reserved->rawKeystrokes, _reserved->stringLength * sizeof(IOHIDSecurePromptClient_RawKeystrokeData));
1394    oldBuffer = (UInt8*)_reserved->unicode;
1395    oldBufferSize = _reserved->bufferLength * (sizeof(UTF32Char) + sizeof(IOHIDSecurePromptClient_RawKeystrokeData));
1396    _reserved->unicode = (UTF32Char*)newBuffer;
1397    _reserved->rawKeystrokes = (IOHIDSecurePromptClient_RawKeystrokeData*)newKeystrokeOffset;
1398    _reserved->bufferLength = newSize;
1399    newBuffer = NULL;
1400    result = kIOReturnSuccess;
1401
1402finished:
1403    if (newBuffer)
1404        IOFree(newBuffer, newBufferSize);
1405    if (oldBuffer) {
1406        __EraseMemory(oldBuffer, oldBufferSize);
1407        IOFree(oldBuffer, oldBufferSize);
1408    }
1409
1410    return result;
1411}
1412
1413/******************************************************************************/
1414void
1415__InsertBytes(void *dest, UInt32 insertPoint, UInt32 destCount, void *source, UInt32 sourceCount, UInt32 size)
1416{
1417    UInt8 *destBytes = (UInt8*)dest;
1418    UInt8 *sourceBytes = (UInt8*)source;
1419    require(destBytes && sourceBytes && sourceCount && size, bad_parameter);
1420    if (insertPoint > destCount) {
1421        insertPoint = destCount;
1422    }
1423    if (insertPoint < destCount) {
1424        memmove(destBytes + (insertPoint + sourceCount) * size, destBytes + insertPoint * size, sourceCount * size);
1425    }
1426    memcpy(destBytes + insertPoint * size, sourceBytes, sourceCount * size);
1427
1428bad_parameter:
1429    ;
1430}
1431
1432/******************************************************************************/
1433
1434/******************************************************************************/
1435