From ee396ef47db58c01c7ceaecfec60781c95ffeea1 Mon Sep 17 00:00:00 2001 From: Apple Date: Thu, 7 Apr 2005 20:24:52 +0000 Subject: [PATCH] securityd-61.tar.gz --- APPLE_LICENSE | 367 --------- TODO | 1 - doc/securityd.1 | 36 + etc/CodeEquivalenceCandidates | 29 +- etc/Localizable.strings | 11 - etc/StartupParameters.plist | 10 - etc/authorization.plist | 375 +++++---- etc/securityd | 5 - etc/securityd-installCD.plist | 12 + etc/startup.mk | 14 +- mig/mig.mk | 44 ++ mig/self.defs | 40 + securityd.xcode/project.pbxproj | 886 ++++++++++++++++------ src/AuthorizationDBPlist.cpp | 4 +- src/AuthorizationDBPlist.h | 2 - src/AuthorizationEngine.cpp | 6 +- src/AuthorizationEngine.h | 4 +- src/AuthorizationMechEval.cpp | 139 ++-- src/AuthorizationMechEval.h | 11 +- src/AuthorizationRule.cpp | 285 ++++--- src/AuthorizationRule.h | 19 +- src/acl_keychain.cpp | 10 +- src/acl_keychain.h | 2 - src/acls.cpp | 129 +++- src/acls.h | 90 ++- src/agentquery.cpp | 285 ++++--- src/agentquery.h | 91 ++- src/authhost.cpp | 175 +++++ src/{yarrowMigTypes.h => authhost.h} | 44 +- src/authority.cpp | 32 +- src/authority.h | 24 +- src/child.cpp | 378 ++-------- src/child.h | 68 +- src/codesigdb.cpp | 3 +- src/codesigdb.h | 2 - src/connection.cpp | 2 - src/connection.h | 7 +- src/database.cpp | 129 +++- src/database.h | 112 ++- src/dbcrypto.cpp | 37 +- src/dbcrypto.h | 7 +- src/entropy.cpp | 2 - src/entropy.h | 4 +- src/flippers.cpp | 2 - src/flippers.h | 2 - src/generate.pl | 4 +- src/kcdatabase.cpp | 422 ++++++++--- src/kcdatabase.h | 70 +- src/kckey.cpp | 50 +- src/kckey.h | 34 +- src/key.cpp | 33 +- src/key.h | 63 +- src/localdatabase.cpp | 130 ++-- src/localdatabase.h | 31 +- src/localkey.cpp | 60 +- src/localkey.h | 56 +- src/main.cpp | 193 ++--- src/notifications.cpp | 3 - src/notifications.h | 2 - src/pcsc++.cpp | 231 ------ src/pcsc++.h | 152 ---- src/pcscmonitor.cpp | 318 +++++++- src/pcscmonitor.h | 67 +- src/process.cpp | 96 ++- src/process.h | 28 +- src/reader.cpp | 87 ++- src/reader.h | 17 +- src/securityd.order | 1048 ++++++++++++++++++++------ src/securityserver.h | 60 -- src/server.cpp | 198 +++-- src/server.h | 96 ++- src/session.cpp | 293 ++++--- src/session.h | 69 +- src/structure.cpp | 66 +- src/structure.h | 65 +- src/tempdatabase.cpp | 44 +- src/tempdatabase.h | 22 +- src/token.cpp | 402 +++++++++- src/token.h | 92 ++- src/tokenaccess.cpp | 62 ++ src/tokenaccess.h | 87 +++ src/tokenacl.cpp | 192 +++++ src/tokenacl.h | 72 ++ src/tokencache.cpp | 267 +++++++ src/tokencache.h | 116 +++ src/tokend.cpp | 194 +++++ src/tokend.h | 121 +++ src/tokendatabase.cpp | 612 +++++++++++++-- src/tokendatabase.h | 174 ++++- src/tokenkey.cpp | 129 ++++ src/tokenkey.h | 65 ++ src/transition.cpp | 738 ++++++++++-------- src/transwalkers.cpp | 27 +- src/transwalkers.h | 94 ++- tests/AZNTest.cpp | 2 - tests/exectest.cpp | 2 - tests/testacls.cpp | 2 - tests/testauth.cpp | 2 - tests/testblobs.cpp | 2 - tests/testclient.cpp | 2 - tests/testclient.h | 2 - tests/testcrypto.cpp | 2 - tests/testutils.cpp | 2 - tests/testutils.h | 2 - 104 files changed, 7937 insertions(+), 3572 deletions(-) delete mode 100644 APPLE_LICENSE delete mode 100644 TODO create mode 100644 doc/securityd.1 delete mode 100644 etc/Localizable.strings delete mode 100644 etc/StartupParameters.plist delete mode 100755 etc/securityd create mode 100644 etc/securityd-installCD.plist create mode 100644 mig/mig.mk create mode 100644 mig/self.defs create mode 100644 src/authhost.cpp rename src/{yarrowMigTypes.h => authhost.h} (60%) delete mode 100644 src/pcsc++.cpp delete mode 100644 src/pcsc++.h delete mode 100644 src/securityserver.h create mode 100644 src/tokenaccess.cpp create mode 100644 src/tokenaccess.h create mode 100644 src/tokenacl.cpp create mode 100644 src/tokenacl.h create mode 100644 src/tokencache.cpp create mode 100644 src/tokencache.h create mode 100644 src/tokend.cpp create mode 100644 src/tokend.h create mode 100644 src/tokenkey.cpp create mode 100644 src/tokenkey.h diff --git a/APPLE_LICENSE b/APPLE_LICENSE deleted file mode 100644 index fe81a60..0000000 --- a/APPLE_LICENSE +++ /dev/null @@ -1,367 +0,0 @@ -APPLE PUBLIC SOURCE LICENSE -Version 2.0 - August 6, 2003 - -Please read this License carefully before downloading this software. -By downloading or using this software, you are agreeing to be bound by -the terms of this License. If you do not or cannot agree to the terms -of this License, please do not download or use the software. - -1. General; Definitions. This License applies to any program or other -work which Apple Computer, Inc. ("Apple") makes publicly available and -which contains a notice placed by Apple identifying such program or -work as "Original Code" and stating that it is subject to the terms of -this Apple Public Source License version 2.0 ("License"). As used in -this License: - -1.1 "Applicable Patent Rights" mean: (a) in the case where Apple is -the grantor of rights, (i) claims of patents that are now or hereafter -acquired, owned by or assigned to Apple and (ii) that cover subject -matter contained in the Original Code, but only to the extent -necessary to use, reproduce and/or distribute the Original Code -without infringement; and (b) in the case where You are the grantor of -rights, (i) claims of patents that are now or hereafter acquired, -owned by or assigned to You and (ii) that cover subject matter in Your -Modifications, taken alone or in combination with Original Code. - -1.2 "Contributor" means any person or entity that creates or -contributes to the creation of Modifications. - -1.3 "Covered Code" means the Original Code, Modifications, the -combination of Original Code and any Modifications, and/or any -respective portions thereof. - -1.4 "Externally Deploy" means: (a) to sublicense, distribute or -otherwise make Covered Code available, directly or indirectly, to -anyone other than You; and/or (b) to use Covered Code, alone or as -part of a Larger Work, in any way to provide a service, including but -not limited to delivery of content, through electronic communication -with a client other than You. - -1.5 "Larger Work" means a work which combines Covered Code or portions -thereof with code not governed by the terms of this License. - -1.6 "Modifications" mean any addition to, deletion from, and/or change -to, the substance and/or structure of the Original Code, any previous -Modifications, the combination of Original Code and any previous -Modifications, and/or any respective portions thereof. When code is -released as a series of files, a Modification is: (a) any addition to -or deletion from the contents of a file containing Covered Code; -and/or (b) any new file or other representation of computer program -statements that contains any part of Covered Code. - -1.7 "Original Code" means (a) the Source Code of a program or other -work as originally made available by Apple under this License, -including the Source Code of any updates or upgrades to such programs -or works made available by Apple under this License, and that has been -expressly identified by Apple as such in the header file(s) of such -work; and (b) the object code compiled from such Source Code and -originally made available by Apple under this License. - -1.8 "Source Code" means the human readable form of a program or other -work that is suitable for making modifications to it, including all -modules it contains, plus any associated interface definition files, -scripts used to control compilation and installation of an executable -(object code). - -1.9 "You" or "Your" means an individual or a legal entity exercising -rights under this License. For legal entities, "You" or "Your" -includes any entity which controls, is controlled by, or is under -common control with, You, where "control" means (a) the power, direct -or indirect, to cause the direction or management of such entity, -whether by contract or otherwise, or (b) ownership of fifty percent -(50%) or more of the outstanding shares or beneficial ownership of -such entity. - -2. Permitted Uses; Conditions & Restrictions. Subject to the terms -and conditions of this License, Apple hereby grants You, effective on -the date You accept this License and download the Original Code, a -world-wide, royalty-free, non-exclusive license, to the extent of -Apple's Applicable Patent Rights and copyrights covering the Original -Code, to do the following: - -2.1 Unmodified Code. You may use, reproduce, display, perform, -internally distribute within Your organization, and Externally Deploy -verbatim, unmodified copies of the Original Code, for commercial or -non-commercial purposes, provided that in each instance: - -(a) You must retain and reproduce in all copies of Original Code the -copyright and other proprietary notices and disclaimers of Apple as -they appear in the Original Code, and keep intact all notices in the -Original Code that refer to this License; and - -(b) You must include a copy of this License with every copy of Source -Code of Covered Code and documentation You distribute or Externally -Deploy, and You may not offer or impose any terms on such Source Code -that alter or restrict this License or the recipients' rights -hereunder, except as permitted under Section 6. - -2.2 Modified Code. You may modify Covered Code and use, reproduce, -display, perform, internally distribute within Your organization, and -Externally Deploy Your Modifications and Covered Code, for commercial -or non-commercial purposes, provided that in each instance You also -meet all of these conditions: - -(a) You must satisfy all the conditions of Section 2.1 with respect to -the Source Code of the Covered Code; - -(b) You must duplicate, to the extent it does not already exist, the -notice in Exhibit A in each file of the Source Code of all Your -Modifications, and cause the modified files to carry prominent notices -stating that You changed the files and the date of any change; and - -(c) If You Externally Deploy Your Modifications, You must make -Source Code of all Your Externally Deployed Modifications either -available to those to whom You have Externally Deployed Your -Modifications, or publicly available. Source Code of Your Externally -Deployed Modifications must be released under the terms set forth in -this License, including the license grants set forth in Section 3 -below, for as long as you Externally Deploy the Covered Code or twelve -(12) months from the date of initial External Deployment, whichever is -longer. You should preferably distribute the Source Code of Your -Externally Deployed Modifications electronically (e.g. download from a -web site). - -2.3 Distribution of Executable Versions. In addition, if You -Externally Deploy Covered Code (Original Code and/or Modifications) in -object code, executable form only, You must include a prominent -notice, in the code itself as well as in related documentation, -stating that Source Code of the Covered Code is available under the -terms of this License with information on how and where to obtain such -Source Code. - -2.4 Third Party Rights. You expressly acknowledge and agree that -although Apple and each Contributor grants the licenses to their -respective portions of the Covered Code set forth herein, no -assurances are provided by Apple or any Contributor that the Covered -Code does not infringe the patent or other intellectual property -rights of any other entity. Apple and each Contributor disclaim any -liability to You for claims brought by any other entity based on -infringement of intellectual property rights or otherwise. As a -condition to exercising the rights and licenses granted hereunder, You -hereby assume sole responsibility to secure any other intellectual -property rights needed, if any. For example, if a third party patent -license is required to allow You to distribute the Covered Code, it is -Your responsibility to acquire that license before distributing the -Covered Code. - -3. Your Grants. In consideration of, and as a condition to, the -licenses granted to You under this License, You hereby grant to any -person or entity receiving or distributing Covered Code under this -License a non-exclusive, royalty-free, perpetual, irrevocable license, -under Your Applicable Patent Rights and other intellectual property -rights (other than patent) owned or controlled by You, to use, -reproduce, display, perform, modify, sublicense, distribute and -Externally Deploy Your Modifications of the same scope and extent as -Apple's licenses under Sections 2.1 and 2.2 above. - -4. Larger Works. You may create a Larger Work by combining Covered -Code with other code not governed by the terms of this License and -distribute the Larger Work as a single product. In each such instance, -You must make sure the requirements of this License are fulfilled for -the Covered Code or any portion thereof. - -5. Limitations on Patent License. Except as expressly stated in -Section 2, no other patent rights, express or implied, are granted by -Apple herein. Modifications and/or Larger Works may require additional -patent licenses from Apple which Apple may grant in its sole -discretion. - -6. Additional Terms. You may choose to offer, and to charge a fee for, -warranty, support, indemnity or liability obligations and/or other -rights consistent with the scope of the license granted herein -("Additional Terms") to one or more recipients of Covered Code. -However, You may do so only on Your own behalf and as Your sole -responsibility, and not on behalf of Apple or any Contributor. You -must obtain the recipient's agreement that any such Additional Terms -are offered by You alone, and You hereby agree to indemnify, defend -and hold Apple and every Contributor harmless for any liability -incurred by or claims asserted against Apple or such Contributor by -reason of any such Additional Terms. - -7. Versions of the License. Apple may publish revised and/or new -versions of this License from time to time. Each version will be given -a distinguishing version number. Once Original Code has been published -under a particular version of this License, You may continue to use it -under the terms of that version. You may also choose to use such -Original Code under the terms of any subsequent version of this -License published by Apple. No one other than Apple has the right to -modify the terms applicable to Covered Code created under this -License. - -8. NO WARRANTY OR SUPPORT. The Covered Code may contain in whole or in -part pre-release, untested, or not fully tested works. The Covered -Code may contain errors that could cause failures or loss of data, and -may be incomplete or contain inaccuracies. You expressly acknowledge -and agree that use of the Covered Code, or any portion thereof, is at -Your sole and entire risk. THE COVERED CODE IS PROVIDED "AS IS" AND -WITHOUT WARRANTY, UPGRADES OR SUPPORT OF ANY KIND AND APPLE AND -APPLE'S LICENSOR(S) (COLLECTIVELY REFERRED TO AS "APPLE" FOR THE -PURPOSES OF SECTIONS 8 AND 9) AND ALL CONTRIBUTORS EXPRESSLY DISCLAIM -ALL WARRANTIES AND/OR CONDITIONS, EXPRESS OR IMPLIED, INCLUDING, BUT -NOT LIMITED TO, THE IMPLIED WARRANTIES AND/OR CONDITIONS OF -MERCHANTABILITY, OF SATISFACTORY QUALITY, OF FITNESS FOR A PARTICULAR -PURPOSE, OF ACCURACY, OF QUIET ENJOYMENT, AND NONINFRINGEMENT OF THIRD -PARTY RIGHTS. APPLE AND EACH CONTRIBUTOR DOES NOT WARRANT AGAINST -INTERFERENCE WITH YOUR ENJOYMENT OF THE COVERED CODE, THAT THE -FUNCTIONS CONTAINED IN THE COVERED CODE WILL MEET YOUR REQUIREMENTS, -THAT THE OPERATION OF THE COVERED CODE WILL BE UNINTERRUPTED OR -ERROR-FREE, OR THAT DEFECTS IN THE COVERED CODE WILL BE CORRECTED. NO -ORAL OR WRITTEN INFORMATION OR ADVICE GIVEN BY APPLE, AN APPLE -AUTHORIZED REPRESENTATIVE OR ANY CONTRIBUTOR SHALL CREATE A WARRANTY. -You acknowledge that the Covered Code is not intended for use in the -operation of nuclear facilities, aircraft navigation, communication -systems, or air traffic control machines in which case the failure of -the Covered Code could lead to death, personal injury, or severe -physical or environmental damage. - -9. LIMITATION OF LIABILITY. TO THE EXTENT NOT PROHIBITED BY LAW, IN NO -EVENT SHALL APPLE OR ANY CONTRIBUTOR BE LIABLE FOR ANY INCIDENTAL, -SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES ARISING OUT OF OR RELATING -TO THIS LICENSE OR YOUR USE OR INABILITY TO USE THE COVERED CODE, OR -ANY PORTION THEREOF, WHETHER UNDER A THEORY OF CONTRACT, WARRANTY, -TORT (INCLUDING NEGLIGENCE), PRODUCTS LIABILITY OR OTHERWISE, EVEN IF -APPLE OR SUCH CONTRIBUTOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH -DAMAGES AND NOTWITHSTANDING THE FAILURE OF ESSENTIAL PURPOSE OF ANY -REMEDY. SOME JURISDICTIONS DO NOT ALLOW THE LIMITATION OF LIABILITY OF -INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO THIS LIMITATION MAY NOT APPLY -TO YOU. In no event shall Apple's total liability to You for all -damages (other than as may be required by applicable law) under this -License exceed the amount of fifty dollars ($50.00). - -10. Trademarks. This License does not grant any rights to use the -trademarks or trade names "Apple", "Apple Computer", "Mac", "Mac OS", -"QuickTime", "QuickTime Streaming Server" or any other trademarks, -service marks, logos or trade names belonging to Apple (collectively -"Apple Marks") or to any trademark, service mark, logo or trade name -belonging to any Contributor. You agree not to use any Apple Marks in -or as part of the name of products derived from the Original Code or -to endorse or promote products derived from the Original Code other -than as expressly permitted by and in strict compliance at all times -with Apple's third party trademark usage guidelines which are posted -at http://www.apple.com/legal/guidelinesfor3rdparties.html. - -11. Ownership. Subject to the licenses granted under this License, -each Contributor retains all rights, title and interest in and to any -Modifications made by such Contributor. Apple retains all rights, -title and interest in and to the Original Code and any Modifications -made by or on behalf of Apple ("Apple Modifications"), and such Apple -Modifications will not be automatically subject to this License. Apple -may, at its sole discretion, choose to license such Apple -Modifications under this License, or on different terms from those -contained in this License or may choose not to license them at all. - -12. Termination. - -12.1 Termination. This License and the rights granted hereunder will -terminate: - -(a) automatically without notice from Apple if You fail to comply with -any term(s) of this License and fail to cure such breach within 30 -days of becoming aware of such breach; - -(b) immediately in the event of the circumstances described in Section -13.5(b); or - -(c) automatically without notice from Apple if You, at any time during -the term of this License, commence an action for patent infringement -against Apple; provided that Apple did not first commence -an action for patent infringement against You in that instance. - -12.2 Effect of Termination. Upon termination, You agree to immediately -stop any further use, reproduction, modification, sublicensing and -distribution of the Covered Code. All sublicenses to the Covered Code -which have been properly granted prior to termination shall survive -any termination of this License. Provisions which, by their nature, -should remain in effect beyond the termination of this License shall -survive, including but not limited to Sections 3, 5, 8, 9, 10, 11, -12.2 and 13. No party will be liable to any other for compensation, -indemnity or damages of any sort solely as a result of terminating -this License in accordance with its terms, and termination of this -License will be without prejudice to any other right or remedy of -any party. - -13. Miscellaneous. - -13.1 Government End Users. The Covered Code is a "commercial item" as -defined in FAR 2.101. Government software and technical data rights in -the Covered Code include only those rights customarily provided to the -public as defined in this License. This customary commercial license -in technical data and software is provided in accordance with FAR -12.211 (Technical Data) and 12.212 (Computer Software) and, for -Department of Defense purchases, DFAR 252.227-7015 (Technical Data -- -Commercial Items) and 227.7202-3 (Rights in Commercial Computer -Software or Computer Software Documentation). Accordingly, all U.S. -Government End Users acquire Covered Code with only those rights set -forth herein. - -13.2 Relationship of Parties. This License will not be construed as -creating an agency, partnership, joint venture or any other form of -legal association between or among You, Apple or any Contributor, and -You will not represent to the contrary, whether expressly, by -implication, appearance or otherwise. - -13.3 Independent Development. Nothing in this License will impair -Apple's right to acquire, license, develop, have others develop for -it, market and/or distribute technology or products that perform the -same or similar functions as, or otherwise compete with, -Modifications, Larger Works, technology or products that You may -develop, produce, market or distribute. - -13.4 Waiver; Construction. Failure by Apple or any Contributor to -enforce any provision of this License will not be deemed a waiver of -future enforcement of that or any other provision. Any law or -regulation which provides that the language of a contract shall be -construed against the drafter will not apply to this License. - -13.5 Severability. (a) If for any reason a court of competent -jurisdiction finds any provision of this License, or portion thereof, -to be unenforceable, that provision of the License will be enforced to -the maximum extent permissible so as to effect the economic benefits -and intent of the parties, and the remainder of this License will -continue in full force and effect. (b) Notwithstanding the foregoing, -if applicable law prohibits or restricts You from fully and/or -specifically complying with Sections 2 and/or 3 or prevents the -enforceability of either of those Sections, this License will -immediately terminate and You must immediately discontinue any use of -the Covered Code and destroy all copies of it that are in your -possession or control. - -13.6 Dispute Resolution. Any litigation or other dispute resolution -between You and Apple relating to this License shall take place in the -Northern District of California, and You and Apple hereby consent to -the personal jurisdiction of, and venue in, the state and federal -courts within that District with respect to this License. The -application of the United Nations Convention on Contracts for the -International Sale of Goods is expressly excluded. - -13.7 Entire Agreement; Governing Law. This License constitutes the -entire agreement between the parties with respect to the subject -matter hereof. This License shall be governed by the laws of the -United States and the State of California, except that body of -California law concerning conflicts of law. - -Where You are located in the province of Quebec, Canada, the following -clause applies: The parties hereby confirm that they have requested -that this License and all related documents be drafted in English. Les -parties ont exige que le present contrat et tous les documents -connexes soient rediges en anglais. - -EXHIBIT A. - -"Portions Copyright (c) 1999-2003 Apple Computer, Inc. All Rights -Reserved. - -This file contains Original Code and/or Modifications of Original Code -as defined in and that are subject to the Apple Public Source License -Version 2.0 (the 'License'). You may not use this file except in -compliance with the License. Please obtain a copy of the License at -http://www.opensource.apple.com/apsl/ and read it before using this -file. - -The Original Code and all software distributed under the License are -distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER -EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, -INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. -Please see the License for the specific language governing rights and -limitations under the License." diff --git a/TODO b/TODO deleted file mode 100644 index f3d66f7..0000000 --- a/TODO +++ /dev/null @@ -1 +0,0 @@ -SecurityServer is a work in progress. diff --git a/doc/securityd.1 b/doc/securityd.1 new file mode 100644 index 0000000..e9ded69 --- /dev/null +++ b/doc/securityd.1 @@ -0,0 +1,36 @@ +.\"Modified from man(1) of FreeBSD, the NetBSD mdoc.template, and mdoc.samples. +.\"See Also: +.\"man mdoc.samples for a complete listing of options +.\"man mdoc for the short list of editing options +.Dd Fri Sep 10 2004 \" DATE +.Dt securityd 1 \" Program name and manual section number +.Os Darwin +.Sh NAME \" Section Header - required - don't modify +.Nm securityd +.\" The following lines are read in generating the apropos(man -k) database. Use only key +.\" words here as the database is built based on the words here and in the .ND line. +.\" Use .Nm macro to designate other names for the documented program. +.Nd Security context daemon for Authorization and cryptographic operations +.Sh SYNOPSIS \" Section Header - required - don't modify +.Nm +.Sh DESCRIPTION \" Section Header - required - don't modify +.Nm +maintains security contexts and arbitrates cryptographic operations and Security Authorizations. Access to +keychain items is routed through +.Nm +to enforce access controls and to keep private keys out of +user process address space. Authorization calls also communicate with +.Nm +to enforce rules contained in the +.Pa /etc/authorization +database. All user interaction with +.Nm +is mediated through the +.Nm "Security Agent." +.Pp +This command is not intended to be invoked directly. +.Sh HISTORY +.Nm +was first introduced in Mac OS X version 10.0 (Cheetah) as the "Security Server" and was renamed in 10.4 (Panther). +.Sh AUTHORS +.An "Perry Kiehtreiber" diff --git a/etc/CodeEquivalenceCandidates b/etc/CodeEquivalenceCandidates index 77721b5..5c32ae4 100644 --- a/etc/CodeEquivalenceCandidates +++ b/etc/CodeEquivalenceCandidates @@ -1,18 +1,39 @@ -/System/Library/CoreServices/Finder.app -/Applications/iChat.app -/Applications/iSync.app +/Applications/Address Book.app +/Applications/Internet Connect.app /Applications/Mail.app /Applications/Safari.app +/Applications/Server/QTSS Publisher.app +/Applications/Server/Server Admin.app +/Applications/Server/Server Monitor.app +/Applications/Server/Workgroup Manager.app +/Applications/System Preferences.app /Applications/Utilities/AirPort Admin Utility.app /Applications/Utilities/Keychain Access.app /Applications/Utilities/Keychain Access.app/Contents/Resources/Keychain Agent +/Applications/iCal.app +/Applications/iChat.app +/Applications/iMovie.app +/Applications/iPhoto.app +/Applications/iSync.app +/Applications/iTunes.app +/System/Library/CoreServices/Finder.app /System/Library/CoreServices/loginwindow.app /System/Library/CoreServices/MirrorAgent.app /System/Library/CoreServices/SecurityAgent.app +/System/Library/CoreServices/SyncServer.app +/System/Library/CoreServices/SystemUIServer.app +/System/Library/CoreServices/dotmacsyncclient /System/Library/Filesystems/ftp.fs/mount_ftp /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/AE.framework/Versions/A/Support/AEServer +/System/Library/Frameworks/InstantMessage.framework/iChatAgent.app +/System/Library/Frameworks/SecurityFoundation.framework/Resources/kcSync.app +/System/Library/PreferencePanes/Mac.prefPane /System/Library/PrivateFrameworks/Admin.framework/Versions/A/Resources/writeconfig +/System/Library/PrivateFrameworks/Apple80211.framework/Resources/airport +/System/Library/PrivateFrameworks/Apple80211.framework/Resources/AirPortNetworkPrefs.bundle/Contents/Resources/AirPortCfgTool +/System/Library/PrivateFrameworks/DotmacLegacy.framework/Resources/dotMacTranslator /System/Library/PrivateFrameworks/InstantMessage.framework/iChatAgent.app +/System/Library/PrivateFrameworks/DMNotification.framework/Resources/dmnotifyd /System/Library/ScriptingAdditions/Keychain Scripting.app /sbin/mount_smbfs /sbin/mount_webdav @@ -21,6 +42,8 @@ /usr/bin/security /usr/bin/smbutil /usr/local/bin/cmsutil +/usr/sbin/configd /usr/sbin/pppd /usr/sbin/racoon /usr/sbin/systemkeychain +/usr/sbin/mDNSResponder diff --git a/etc/Localizable.strings b/etc/Localizable.strings deleted file mode 100644 index 2d6f3c5..0000000 --- a/etc/Localizable.strings +++ /dev/null @@ -1,11 +0,0 @@ - - - - - Starting SecurityServer - Starting SecurityServer - Stopping SecurityServer - Stopping SecurityServer - - - diff --git a/etc/StartupParameters.plist b/etc/StartupParameters.plist deleted file mode 100644 index 8f4fd0e..0000000 --- a/etc/StartupParameters.plist +++ /dev/null @@ -1,10 +0,0 @@ -{ - Description = "Apple Security Server"; - Provides = ("SecurityServer"); - OrderPreference = "None"; - Messages = - { - start = "Starting SecurityServer"; - stop = "Stopping SecurityServer"; - }; -} diff --git a/etc/authorization.plist b/etc/authorization.plist index 9f197a1..1b1efc1 100644 --- a/etc/authorization.plist +++ b/etc/authorization.plist @@ -3,7 +3,7 @@ comment - The name of the requested right is matched against the keys. An exact match has priority, otherwise the longest match from the start is used. Note that the right will only match wildcard rules (ending in a ".") during this reduction. + The name of the requested right is matched against the keys. An exact match has priority, otherwise the longest match from the start is used. Note that the right will only match wildcard rules (ending in a ".") during this reduction. allow rule: this is always allowed <key>com.apple.TestApp.benign</key> @@ -30,10 +30,7 @@ See remaining rules for examples. class rule comment - All other rights will be matched by this rule. -Credentials remain valid 5 minutes after they've been obtained. -An acquired credential is shared amongst all clients. - + All other rights will be matched by this rule. rule default @@ -56,18 +53,28 @@ An acquired credential is shared amongst all clients. class rule comment - wildcard right for modifying rights. Admins are allowed to modify any (non-wildcard) rights + wildcard right for modifying rights. Admins are allowed to modify any (non-wildcard) rights. Root does not require authentication. + k-of-n + 1 rule - authenticate-admin + + is-root + authenticate-admin + config.remove. class rule comment - wildcard right for deleting rights. Admins are allowed to delete any (non-wildcard) rights + wildcard right for deleting rights. Admins are allowed to delete any (non-wildcard) rights. Root does not require authentication. + k-of-n + 1 rule - authenticate-admin + + is-root + authenticate-admin + config.remove.system. @@ -84,10 +91,6 @@ An acquired credential is shared amongst all clients. See authopen(1) for information on the use of this right. group admin - mechanisms - - builtin:authenticate - shared timeout @@ -103,10 +106,6 @@ Credentials remain valid indefinitely after they've been obtained. An acquired credential is shared amongst all clients. group admin - mechanisms - - builtin:authenticate - shared @@ -120,14 +119,17 @@ builtin:krb5authenticate can be used to hinge local authentication on a successf builtin:krb5authnoverify skips the kdc verification. Both fall back on local authentication. mechanisms + builtin:auto-login,privileged loginwindow_builtin:login + builtin:reset-password,privileged authinternal - HomeDirMechanism:login + builtin:getuserinfo,privileged + builtin:sso,privileged + HomeDirMechanism:login,privileged + HomeDirMechanism:status MCXMechanism:login loginwindow_builtin:success - builtin:getuserinfo - builtin:sso - loginwindow_builtin:done + loginwindow_builtin:done system.login.done @@ -144,8 +146,8 @@ builtin:krb5authnoverify skips the kdc verification. Both fall back on local au class evaluate-mechanisms - tries - 1 + tries + 1 mechanisms push_hints_to_context @@ -165,8 +167,8 @@ builtin:krb5authnoverify skips the kdc verification. Both fall back on local au class evaluate-mechanisms - tries - 1 + tries + 1 mechanisms push_hints_to_context @@ -192,23 +194,19 @@ builtin:krb5authnoverify skips the kdc verification. Both fall back on local au shared - system.keychain.modify - - class - user - comment - Used by Keychain Access when editing a system keychain. - group - admin - mechanisms - - builtin:authenticate - - shared - - timeout - 300 - + system.keychain.modify + + class + user + comment + Used by Keychain Access when editing a system keychain. + group + admin + shared + + timeout + 300 + system.preferences allow-root @@ -216,19 +214,25 @@ builtin:krb5authnoverify skips the kdc verification. Both fall back on local au class user comment - This right is checked by the Admin framework when making changes to the system preferences. -Credentials remain valid forever. -An acquired credential is shared amongst all clients. -If the proccess that created the AuthorizationRef has uid = 0 this right will automatically be granted. + This right is checked by the Admin framework when making changes to the system preferences. group admin - mechanisms - - builtin:authenticate - shared + system.preferences.accounts + + allow-root + + class + user + comment + This right is checked by the Admin framework when making changes to the accounts preference pane + group + admin + shared + + system.printingmanager class @@ -238,6 +242,49 @@ If the proccess that created the AuthorizationRef has uid = 0 this right will au rule authenticate-admin + system.preferences.accessibility + + allow-root + + class + user + comment + This right is checked by the Admin framework when enabling or disabling the Accessibility APIs + group + admin + shared + + timeout + 0 + + com.apple.activitymonitor.kill + + class + user + comment + Used by Activity Monitor to authorize killing processes not owned by the user + group + admin + shared + + timeout + 0 + + com.apple.Safari.parental-controls + + allow-root + + class + user + comment + This right is checked when changing parental controls for Safari + group + admin + shared + + timeout + 0 + system.privilege.admin allow-root @@ -254,114 +301,113 @@ If the proccess that created the AuthorizationRef has uid = 0 this right will au group admin - mechanisms - - builtin:authenticate - shared timeout 300 - system.restart - + system.restart + class - evaluate-mechanisms - comment + evaluate-mechanisms + comment Multisession restart mechanisms - mechanisms - - RestartAuthorization:restart - RestartAuthorization:authenticate - RestartAuthorization:success - - - system.shutdown - - class - evaluate-mechanisms - comment + mechanisms + + RestartAuthorization:restart + RestartAuthorization:authenticate + RestartAuthorization:success + + + system.shutdown + + class + evaluate-mechanisms + comment Multisession shutdown mechanisms - mechanisms - - RestartAuthorization:shutdown - RestartAuthorization:authenticate - RestartAuthorization:success - - - system.burn - - class - allow - comment + mechanisms + + RestartAuthorization:shutdown + RestartAuthorization:authenticate + RestartAuthorization:success + + + system.burn + + class + allow + comment authorization to burn media - com.apple.server.admin.streaming - + system.services.directory.configure + + class + user + group + admin + allow-root + + shared + + timeout + 300 + comment + authorization to make directory service changes + + com.apple.server.admin.streaming + class user comment Used for admin requests with the QuickTime Streaming Server. - group - admin - shared - - allow-root - - timeout - 0 - - system.install.admin.user - + group + admin + shared + + allow-root + + timeout + 0 + + system.install.admin.user + class user comment Used by installer tool: user installling in admin domain (/Applications) - group - admin - mechanisms - - builtin:authenticate - - shared - - timeout - 300 - - system.install.root.user - + group + admin + shared + + timeout + 300 + + system.install.root.user + class user comment Used by installer tool: user installling in root domain (/System) - group - admin - mechanisms - - builtin:authenticate - - shared - - timeout - 300 - - system.install.root.admin - + group + admin + shared + + timeout + 300 + + system.install.root.admin + class user comment Used by installer tool: admin installling in root domain (/System) - group - admin - mechanisms - - builtin:authenticate - - shared - - timeout - 300 - + group + admin + shared + + timeout + 300 + com.apple.appserver.privilege.admin class @@ -393,10 +439,6 @@ If the proccess that created the AuthorizationRef has uid = 0 this right will au authorize privileged file operations from the finder group admin - mechanisms - - builtin:authenticate - shared timeout @@ -420,6 +462,24 @@ If the proccess that created the AuthorizationRef has uid = 0 this right will au builtin:generic-unlock + com.apple.builtin.confirm-access + + class + evaluate-mechanisms + mechanisms + + builtin:confirm-access + + + com.apple.builtin.confirm-access-password + + class + evaluate-mechanisms + mechanisms + + builtin:confirm-access-password + + rules @@ -438,25 +498,26 @@ If the proccess that created the AuthorizationRef has uid = 0 this right will au require the user asking for authorization to authenticate as an admin group admin - mechanisms - - builtin:authenticate - shared timeout 0 + authenticate-session-user + + class + user + comment + authenticate session owner + session-owner + + authenticate-session-owner class user comment authenticate session owner - mechanisms - - builtin:authenticate - session-owner @@ -470,10 +531,6 @@ If the proccess that created the AuthorizationRef has uid = 0 this right will au the owner as well as any admin can authorize group admin - mechanisms - - builtin:authenticate - session-owner shared @@ -487,6 +544,8 @@ If the proccess that created the AuthorizationRef has uid = 0 this right will au verify the user asking for authorization is an admin group admin + authenticate-user + shared true @@ -496,10 +555,10 @@ If the proccess that created the AuthorizationRef has uid = 0 this right will au class user + authenticate-user + comment verify the process that created this authref is root - group - nogroup appserver-user @@ -520,20 +579,26 @@ If the proccess that created the AuthorizationRef has uid = 0 this right will au class user comment - All other rights will be matched by this rule. Credentials remain valid 5 minutes after they've been obtained. + All other rights will be matched by this rule. Credentials remain valid 5 minutes after they've been obtained. An acquired credential is shared amongst all clients. group admin - mechanisms - - builtin:authenticate - shared timeout 300 + authenticate + + class + evaluate-mechanisms + mechanisms + + builtin:authenticate + authinternal + + diff --git a/etc/securityd b/etc/securityd deleted file mode 100755 index d5a444e..0000000 --- a/etc/securityd +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/sh - -. /etc/rc.common - -ConsoleMessage "No longer starting SecurityServer via StartupItems" diff --git a/etc/securityd-installCD.plist b/etc/securityd-installCD.plist new file mode 100644 index 0000000..ce87d8d --- /dev/null +++ b/etc/securityd-installCD.plist @@ -0,0 +1,12 @@ + + + + + ServiceName + com.apple.securityd + Command + /usr/sbin/securityd -c /var/tmp/tokencache -s off + OnDemand + + + diff --git a/etc/startup.mk b/etc/startup.mk index 720bc18..021f90f 100644 --- a/etc/startup.mk +++ b/etc/startup.mk @@ -13,7 +13,6 @@ AUTHORIZATION_PLIST=$(AUTHORIZATION_LOCATION)/authorization VARDB=$(DSTROOT)/private/var/db CANDIDATES=$(VARDB)/CodeEquivalenceCandidates -OLD_STARTUP_DST=$(SYSTEM_LIBRARY_DIR)/StartupItems/securityd DST=$(ETC_DIR)/mach_init.d SRC=$(SRCROOT)/etc @@ -35,18 +34,7 @@ profile: # install: mkdir -p $(DST) - cp $(SRC)/securityd.plist $(DST) - # Remove all OLD_STARTUP_DST-related actions when the Disks and - # Loginwindow StartupItems have removed their dependencies on - # "SecurityServer" - mkdir -p $(OLD_STARTUP_DST)/Resources/English.lproj - cp $(SRC)/StartupParameters.plist $(OLD_STARTUP_DST) - sed -e "s:@@@:$(SYSTEM_CORE_SERVICES_DIR):g" $(SRC)/securityd >$(OLD_STARTUP_DST)/securityd - cp $(SRC)/Localizable.strings $(OLD_STARTUP_DST)/Resources/English.lproj/Localizable.plist - chown -R root:wheel $(OLD_STARTUP_DST) - chmod 755 $(OLD_STARTUP_DST)/securityd - chmod 644 $(OLD_STARTUP_DST)/StartupParameters.plist - chmod 644 $(OLD_STARTUP_DST)/Resources/English.lproj/Localizable.plist + cp $(SRC)/securityd.plist $(SRC)/securityd-installCD.plist $(DST) mkdir -p $(AUTHORIZATION_LOCATION) cp $(SRC)/authorization.plist $(AUTHORIZATION_PLIST) chown root:admin $(AUTHORIZATION_PLIST) diff --git a/mig/mig.mk b/mig/mig.mk new file mode 100644 index 0000000..fbc058e --- /dev/null +++ b/mig/mig.mk @@ -0,0 +1,44 @@ +# +# Copyright (c) 2003-2004 Apple Computer, Inc. All Rights Reserved. +# +# @APPLE_LICENSE_HEADER_START@ +# +# This file contains Original Code and/or Modifications of Original Code +# as defined in and that are subject to the Apple Public Source License +# Version 2.0 (the 'License'). You may not use this file except in +# compliance with the License. Please obtain a copy of the License at +# http://www.opensource.apple.com/apsl/ and read it before using this +# file. +# +# The Original Code and all software distributed under the License are +# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER +# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, +# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. +# Please see the License for the specific language governing rights and +# limitations under the License. +# +# @APPLE_LICENSE_HEADER_END@ +# +# Makefile to build MIG-generated sources and headers +# +DERIVED_SRC = $(BUILT_PRODUCTS_DIR)/derived_src + +HDRS = $(DERIVED_SRC)/self.h +SRCS = $(DERIVED_SRC)/selfServer.cpp $(DERIVED_SRC)/selfUser.cpp + +build: $(HDRS) $(SRCS) + +install: build + +installhdrs: $(HDRS) + +installsrc: + +clean: + rm -f $(HDRS) $(SRCS) + +$(DERIVED_SRC)/self.h $(DERIVED_SRC)/selfServer.cpp $(DERIVED_SRC)/selfUser.cpp: $(SRCROOT)/mig/self.defs + mkdir -p $(DERIVED_SRC) + mig -server $(DERIVED_SRC)/selfServer.cpp -user $(DERIVED_SRC)/selfUser.cpp \ + -header $(DERIVED_SRC)/self.h $(SRCROOT)/mig/self.defs diff --git a/mig/self.defs b/mig/self.defs new file mode 100644 index 0000000..4a7e3bf --- /dev/null +++ b/mig/self.defs @@ -0,0 +1,40 @@ +// +// Copyright (c) 2004 Apple Computer, Inc. All Rights Reserved. +// +// @APPLE_LICENSE_HEADER_START@ +// +// This file contains Original Code and/or Modifications of Original Code +// as defined in and that are subject to the Apple Public Source License +// Version 2.0 (the 'License'). You may not use this file except in +// compliance with the License. Please obtain a copy of the License at +// http://www.opensource.apple.com/apsl/ and read it before using this +// file. +// +// The Original Code and all software distributed under the License are +// distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER +// EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, +// INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. +// Please see the License for the specific language governing rights and +// limitations under the License. +// +// @APPLE_LICENSE_HEADER_END@ +// +// self.defs - Mach RPC interface for messages security sends to itself +// +// Note: Main (ucsp) dispatch starts at 1000; make sure you don't overlap it. +// +#include +#include + +subsystem self 900; +serverprefix self_server_; +userprefix self_client_; + + +// +// Sent to ourselves upon receipt of a signal (so we get out from under +// the dreaded "can't do anything useful in a signal handler" problem). +// +simpleroutine handleSignal(requestport sport: mach_port_make_send_once_t; + in task_port: mach_port_t; in signal_number: int); diff --git a/securityd.xcode/project.pbxproj b/securityd.xcode/project.pbxproj index 2f4b736..d5ada2f 100644 --- a/securityd.xcode/project.pbxproj +++ b/securityd.xcode/project.pbxproj @@ -33,6 +33,34 @@ settings = { }; }; + 40689F840725DCE00021A502 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = authhost.h; + refType = 4; + sourceTree = ""; + }; + 40689F850725DCE00021A502 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = authhost.cpp; + refType = 4; + sourceTree = ""; + }; + 40689F860725DCE00021A502 = { + fileRef = 40689F840725DCE00021A502; + isa = PBXBuildFile; + settings = { + }; + }; + 40689F870725DCE00021A502 = { + fileRef = 40689F850725DCE00021A502; + isa = PBXBuildFile; + settings = { + }; + }; //400 //401 //402 @@ -43,78 +71,33 @@ //4C2 //4C3 //4C4 + 4C01B3D706FFC621004B3A01 = { + buildActionMask = 8; + dstPath = /usr/share/man/man1/; + dstSubfolderSpec = 0; + files = ( + 4C01B3DA06FFC640004B3A01, + ); + isa = PBXCopyFilesBuildPhase; + runOnlyForDeploymentPostprocessing = 1; + }; + 4C01B3DA06FFC640004B3A01 = { + fileRef = 4CE1878706FFC5D60079D235; + isa = PBXBuildFile; + settings = { + }; + }; 4C9264970534866F004B0E72 = { children = ( - 4C9264980534866F004B0E72, - 4C9264990534866F004B0E72, - 4C92649A0534866F004B0E72, - 4C92649B0534866F004B0E72, - 4C92649C0534866F004B0E72, - 4C92649D0534866F004B0E72, - 4C92649E0534866F004B0E72, - 4C92649F0534866F004B0E72, - 4C9264A00534866F004B0E72, - 4C9264A10534866F004B0E72, - 4C9264A20534866F004B0E72, - 4C9264A30534866F004B0E72, - 405845650663B2010083E58C, - 405845660663B2010083E58C, - 4C9264A40534866F004B0E72, - 4C9264A50534866F004B0E72, - 4CB5ACB906680AE000F359A9, - 4CB5ACBA06680AE000F359A9, - 4C9264A80534866F004B0E72, - 4C9264A90534866F004B0E72, - 4C9264AA0534866F004B0E72, - 4C9264AB0534866F004B0E72, - C2B8DBC705E6C3CE00E6E67C, - C2B8DBC805E6C3CE00E6E67C, - 4C9264AC0534866F004B0E72, - 4C9264AD0534866F004B0E72, - 4C9264AE0534866F004B0E72, - 4C9264AF0534866F004B0E72, - 4C9264B00534866F004B0E72, - 4C9264B10534866F004B0E72, - 4C9264B20534866F004B0E72, - 4C9264B30534866F004B0E72, - 4C9264B40534866F004B0E72, - C2B8DBC905E6C3CE00E6E67C, - C2B8DBCA05E6C3CE00E6E67C, - C207646305EAD713004FEEDA, - C207646405EAD713004FEEDA, - 4C9264B50534866F004B0E72, - 4C9264B60534866F004B0E72, - C20764E405ED250F004FEEDA, - C20764E505ED250F004FEEDA, - C20764E605ED250F004FEEDA, - C20764E705ED250F004FEEDA, 4C9264B70534866F004B0E72, - 4C9264B80534866F004B0E72, - 4C9264B90534866F004B0E72, - C2FDCABD0663CD5B0013F64C, - C2FDCABE0663CD5B0013F64C, - 4C9264BA0534866F004B0E72, - 4C9264BB0534866F004B0E72, - C2FDCABF0663CD5B0013F64C, - C2FDCAC00663CD5B0013F64C, - 4C9264BC0534866F004B0E72, - 4C9264BD0534866F004B0E72, - 4C9264BE0534866F004B0E72, - 4C9264BF0534866F004B0E72, - 4C9264C00534866F004B0E72, - 4C9264C10534866F004B0E72, - C28ACF9A05C9940B00447176, - C28ACF9B05C9940B00447176, - C20AF37C05F689540055732C, - C20AF37D05F689540055732C, - C2FDCAC10663CD5B0013F64C, - C2FDCAC20663CD5B0013F64C, - C2D425F105F3C07400CB11F8, - C2D425F205F3C07400CB11F8, - 4C9264C20534866F004B0E72, - 4C9264C30534866F004B0E72, - 4C9264C40534866F004B0E72, - 4C9264C70534866F004B0E72, + C28AE81406CD7DA100BE0061, + C2C8B29806F8A60F000EBDA2, + C28AE81706CD7DC500BE0061, + C28AE81A06CD7DE200BE0061, + C28AE82306CD7E0F00BE0061, + C28AE82606CD7E4700BE0061, + C28AE81106CD7D7800BE0061, + C28AE83906CD7EE900BE0061, ); isa = PBXGroup; path = src; @@ -401,14 +384,6 @@ refType = 4; sourceTree = ""; }; - 4C9264BD0534866F004B0E72 = { - fileEncoding = 30; - isa = PBXFileReference; - lastKnownFileType = sourcecode.c.h; - path = securityserver.h; - refType = 4; - sourceTree = ""; - }; 4C9264BE0534866F004B0E72 = { fileEncoding = 30; isa = PBXFileReference; @@ -465,14 +440,6 @@ refType = 4; sourceTree = ""; }; - 4C9264C70534866F004B0E72 = { - fileEncoding = 30; - isa = PBXFileReference; - lastKnownFileType = sourcecode.c.h; - path = yarrowMigTypes.h; - refType = 4; - sourceTree = ""; - }; 4C9264C80534866F004B0E72 = { fileRef = 4C9264980534866F004B0E72; isa = PBXBuildFile; @@ -659,12 +626,6 @@ settings = { }; }; - 4C9264E90534866F004B0E72 = { - fileRef = 4C9264BD0534866F004B0E72; - isa = PBXBuildFile; - settings = { - }; - }; 4C9264EA0534866F004B0E72 = { fileRef = 4C9264BE0534866F004B0E72; isa = PBXBuildFile; @@ -707,16 +668,13 @@ settings = { }; }; - 4C9264F30534866F004B0E72 = { - fileRef = 4C9264C70534866F004B0E72; - isa = PBXBuildFile; - settings = { - }; - }; 4CA1FEAC052A3C5800F22E42 = { children = ( - C276AAF20663FD7500B57276, 4C9264970534866F004B0E72, + C209B39106ADBB19007B9E6D, + 4CE1878506FFC5D60079D235, + C209B39406ADBB2B007B9E6D, + C28AE82006CD7DF500BE0061, 4CDD50150537658500FEC36D, 4CA1FEB7052A3C6D00F22E42, 4CD8CCBB055884E0006B3584, @@ -726,8 +684,6 @@ sourceTree = ""; }; 4CA1FEAE052A3C5800F22E42 = { - buildRules = ( - ); buildSettings = { BUILD_VARIANTS = debug; COPY_PHASE_STRIP = NO; @@ -735,19 +691,19 @@ GCC_DYNAMIC_NO_PIC = NO; GCC_ENABLE_FIX_AND_CONTINUE = YES; GCC_GENERATE_DEBUGGING_SYMBOLS = YES; + GCC_OPTIMIZATION_LEVEL = 0; ZERO_LINK = YES; }; isa = PBXBuildStyle; name = Development; }; 4CA1FEAF052A3C5800F22E42 = { - buildRules = ( - ); buildSettings = { CSSM_HEADERS = "$(BUILT_PRODUCTS_DIR)/Security.framework/Headers"; + DEAD_CODE_STRIPPING = YES; GCC_DYNAMIC_NO_PIC = NO; GCC_ENABLE_FIX_AND_CONTINUE = YES; - GCC_GENERATE_DEBUGGING_SYMBOLS = YES; + GCC_GENERATE_DEBUGGING_SYMBOLS = NO; ZERO_LINK = NO; }; isa = PBXBuildStyle; @@ -759,6 +715,7 @@ buildStyles = ( 4CA1FEAE052A3C5800F22E42, 4CA1FEAF052A3C5800F22E42, + C265A4DB06F12750000E5CFC, ); hasScannedForEncodings = 1; isa = PBXProject; @@ -769,6 +726,7 @@ 4CA1FEB5052A3C6D00F22E42, 4CDD4F7A053751FF00FEC36D, 4CA4EB2C0558848900CF7791, + C209B3A506ADBCAC007B9E6D, ); }; 4CA1FEB1052A3C6D00F22E42 = { @@ -795,11 +753,9 @@ C20764E905ED250F004FEEDA, C20764EB05ED250F004FEEDA, 4C9264E60534866F004B0E72, - C2FDCAC40663CD5B0013F64C, C2FDCAC60663CD5B0013F64C, 4C9264E80534866F004B0E72, C2FDCAC80663CD5B0013F64C, - 4C9264E90534866F004B0E72, 4C9264EB0534866F004B0E72, 4C9264ED0534866F004B0E72, C28ACF9D05C9940B00447176, @@ -807,7 +763,13 @@ C2FDCACA0663CD5B0013F64C, C2D425F405F3C07400CB11F8, 4C9264F00534866F004B0E72, - 4C9264F30534866F004B0E72, + C26EA9540688CF34007CE21D, + C209B3B506ADBE64007B9E6D, + C22A7F8F06AF06D9006087B7, + C26D533A06C1E70A00062E1E, + C28654B306DBC2A30021E6E5, + C2813C820730534A00E243E8, + 40689F860725DCE00021A502, ); isa = PBXHeadersBuildPhase; runOnlyForDeploymentPostprocessing = 0; @@ -837,7 +799,6 @@ C20764EA05ED250F004FEEDA, 4C9264E40534866F004B0E72, 4C9264E50534866F004B0E72, - C2FDCAC30663CD5B0013F64C, C2FDCAC50663CD5B0013F64C, 4C9264E70534866F004B0E72, C2FDCAC70663CD5B0013F64C, @@ -849,6 +810,14 @@ C2D425F305F3C07400CB11F8, 4C9264EE0534866F004B0E72, 4C9264EF0534866F004B0E72, + C26EA9530688CF34007CE21D, + C209B3B606ADBE64007B9E6D, + C209B3B706ADBE64007B9E6D, + C22A7F8E06AF06D9006087B7, + C26D533906C1E70A00062E1E, + C28654B206DBC2A30021E6E5, + C2813C810730534A00E243E8, + 40689F870725DCE00021A502, ); isa = PBXSourcesBuildPhase; runOnlyForDeploymentPostprocessing = 0; @@ -856,7 +825,6 @@ 4CA1FEB3052A3C6D00F22E42 = { buildActionMask = 2147483647; files = ( - C276AAD70663E7A400B57276, ); isa = PBXFrameworksBuildPhase; runOnlyForDeploymentPostprocessing = 0; @@ -866,32 +834,38 @@ 4CA1FEB1052A3C6D00F22E42, 4CA1FEB2052A3C6D00F22E42, 4CA1FEB3052A3C6D00F22E42, + 4C01B3D706FFC621004B3A01, ); buildSettings = { - BUILD_VARIANTS = "normal debug profile"; - CURRENT_PROJECT_VERSION = 16; - FRAMEWORK_SEARCH_PATHS = "/usr/local/SecurityPieces/Frameworks /usr/local/SecurityPieces/Components/securityd"; + BUILD_VARIANTS = "normal debug"; + CURRENT_PROJECT_VERSION = 61; + FRAMEWORK_SEARCH_PATHS = "/usr/local/SecurityPieces/Frameworks /usr/local/SecurityPieces/Components/securityd $(SYSTEM_LIBRARY_DIR)/PrivateFrameworks"; INSTALL_PATH = /usr/sbin; + OPT_CPPXFLAGS = "$(OPT_CXFLAGS) -fno-enforce-eh-specs -fno-implement-inlines -fcoalesce-templates"; + OPT_CXFLAGS = "-DNDEBUG $(OPT_INLINEXFLAGS)"; + OPT_INLINEXFLAGS = " -finline-functions --param max-inline-insns-single=150 --param max-inline-insns-auto=150 --param max-inline-insns=300 --param min-inline-insns=90"; + OPT_LDXFLAGS = "-dead_strip"; + OPT_LDXNOPIC = ",_nopic"; OTHER_ASFLAGS_debug = "$(OTHER_CFLAGS)"; OTHER_ASFLAGS_normal = "-DNDEBUG $(OTHER_CFLAGS)"; OTHER_ASFLAGS_profile = "-DNDEBUG $(OTHER_CFLAGS) -pg"; - OTHER_CFLAGS = ""; OTHER_CFLAGS_debug = "$(OTHER_CFLAGS) -O0 -fno-inline"; - OTHER_CFLAGS_normal = "-DNDEBUG $(OTHER_CFLAGS)"; - OTHER_CFLAGS_profile = "-DNDEBUG $(OTHER_CFLAGS) -pg"; - OTHER_CPLUSPLUSFLAGS_debug = "$(OTHER_CFLAGS) -O0 -fno-inline"; - OTHER_CPLUSPLUSFLAGS_normal = "-DNDEBUG $(OTHER_CFLAGS)"; - OTHER_CPLUSPLUSFLAGS_profile = "-DNDEBUG $(OTHER_CFLAGS) -pg"; - OTHER_LDFLAGS = ""; - OTHER_LDFLAGS_debug = "$(OTHER_LDFLAGS) \"-framework\" \"Security,_debug\" \"-framework\" \"IOKit\" \"-framework\" \"CoreFoundation\" \"-framework\" \"security_agent_client,_debug\" \"-framework\" \"security_cdsa_client,_debug\" \"-framework\" \"securityd_server,_debug\" \"-framework\" \"securityd_client,_debug\" \"-framework\" \"security_cdsa_utilities,_debug\" \"-framework\" \"security_utilities,_debug\""; - OTHER_LDFLAGS_normal = "$(OTHER_LDFLAGS) \"-framework\" \"Security\" \"-framework\" \"IOKit\" \"-framework\" \"CoreFoundation\" \"-framework\" \"security_agent_client\" \"-framework\" \"security_cdsa_client\" \"-framework\" \"securityd_server\" \"-framework\" \"securityd_client\" \"-framework\" \"security_cdsa_utilities\" \"-framework\" \"security_utilities\""; - OTHER_LDFLAGS_profile = "$(OTHER_LDFLAGS) \"-framework\" \"Security,_profile\" \"-framework\" \"IOKit\" \"-framework\" \"CoreFoundation\" \"-framework\" \"security_agent_client,_profile\" \"-framework\" \"security_cdsa_client,_profile\" \"-framework\" \"securityd_server,_profile\" \"-framework\" \"securityd_client,_profile\" \"-framework\" \"security_cdsa_utilities,_profile\" \"-framework\" \"security_utilities,_profile\" -pg"; + OTHER_CFLAGS_normal = "$(OPT_CXFLAGS) $(OTHER_CFLAGS)"; + OTHER_CFLAGS_profile = "$(OPT_CXFLAGS) $(OTHER_CFLAGS) -pg"; + OTHER_CPLUSPLUSFLAGS_debug = "$(OTHER_CPLUSPLUSFLAGS) -O0 -fno-inline"; + OTHER_CPLUSPLUSFLAGS_normal = "$(OPT_CPPXFLAGS) $(OTHER_CPLUSPLUSFLAGS)"; + OTHER_CPLUSPLUSFLAGS_profile = "$(OPT_CPPXFLAGS) $(OTHER_CPLUSPLUSFLAGS) -pg"; + OTHER_LDFLAGS = "-lbsm"; + OTHER_LDFLAGS_debug = "$(OTHER_LDFLAGS) \"-framework\" \"Security,_debug\" \"-framework\" \"PCSC,_debug\" \"-framework\" \"IOKit\" \"-framework\" \"CoreFoundation\" \"-framework\" \"security_agent_client,_debug\" \"-framework\" \"security_tokend_client,_debug\" \"-framework\" \"security_cdsa_client,_debug\" \"-framework\" \"securityd_server,_debug\" \"-framework\" \"securityd_client,_debug\" \"-framework\" \"security_cdsa_utilities,_debug\" \"-framework\" \"security_utilities,_debug\""; + OTHER_LDFLAGS_normal = "$(OPT_LDXFLAGS) $(OTHER_LDFLAGS) \"-framework\" \"Security\" \"-framework\" \"PCSC\" \"-framework\" \"IOKit\" \"-framework\" \"CoreFoundation\" \"-framework\" \"security_agent_client$(OPT_LDXNOPIC)\" \"-framework\" \"security_tokend_client$(OPT_LDXNOPIC)\" \"-framework\" \"security_cdsa_client$(OPT_LDXNOPIC)\" \"-framework\" \"securityd_server$(OPT_LDXNOPIC)\" \"-framework\" \"securityd_client$(OPT_LDXNOPIC)\" \"-framework\" \"security_cdsa_utilities$(OPT_LDXNOPIC)\" \"-framework\" \"security_utilities$(OPT_LDXNOPIC)\""; + OTHER_LDFLAGS_profile = "$(OPT_LDXFLAGS) $(OTHER_LDFLAGS) -pg \"-framework\" \"Security,_profile\" \"-framework\" \"PCSC,_profile\" \"-framework\" \"IOKit\" \"-framework\" \"CoreFoundation\" \"-framework\" \"security_agent_client,_profile\" \"-framework\" \"security_tokend_client,_profile\" \"-framework\" \"security_cdsa_client,_profile\" \"-framework\" \"securityd_server,_profile\" \"-framework\" \"securityd_client,_profile\" \"-framework\" \"security_cdsa_utilities,_profile\" \"-framework\" \"security_utilities,_profile\""; PRODUCT_NAME = securityd; SECTORDER_FLAGS = "-sectorder __TEXT __text src/securityd.order -e start"; VERSIONING_SYSTEM = "apple-generic"; WARNING_CFLAGS = "-Wmost -Wno-four-char-constants -Wno-unknown-pragmas"; }; dependencies = ( + C209B3AA06ADBD6D007B9E6D, 4CDD4FB80537552600FEC36D, 4CD8CCB6055884BD006B3584, ); @@ -911,7 +885,7 @@ 4CA1FEB7052A3C6D00F22E42 = { children = ( 4CA1FEB6052A3C6D00F22E42, - 4CDD4F7B053751FF00FEC36D, + C2904F9606D116A3005FF97E, ); isa = PBXGroup; name = Products; @@ -983,12 +957,12 @@ children = ( 4CD8CCBC055884E0006B3584, 4CD8CCBD055884E0006B3584, - 4CD8CCBE055884E0006B3584, - 4CD8CCBF055884E0006B3584, + C2A7B20F079F3A90000DB673, + C2A7B20E079F3A90000DB673, 4CD8CCC0055884E0006B3584, - 4CD8CCC1055884E0006B3584, ); isa = PBXGroup; + name = "Other Installs"; path = etc; refType = 4; sourceTree = ""; @@ -1009,22 +983,6 @@ refType = 4; sourceTree = ""; }; - 4CD8CCBE055884E0006B3584 = { - fileEncoding = 30; - isa = PBXFileReference; - lastKnownFileType = text.plist.strings; - path = Localizable.strings; - refType = 4; - sourceTree = ""; - }; - 4CD8CCBF055884E0006B3584 = { - fileEncoding = 30; - isa = PBXFileReference; - lastKnownFileType = text.script.sh; - path = securityd; - refType = 4; - sourceTree = ""; - }; 4CD8CCC0055884E0006B3584 = { fileEncoding = 30; isa = PBXFileReference; @@ -1033,14 +991,6 @@ refType = 4; sourceTree = ""; }; - 4CD8CCC1055884E0006B3584 = { - fileEncoding = 30; - isa = PBXFileReference; - lastKnownFileType = text.plist; - path = StartupParameters.plist; - refType = 4; - sourceTree = ""; - }; 4CDD4F79053751FF00FEC36D = { buildActionMask = 2147483647; files = ( @@ -1074,15 +1024,7 @@ name = flippers; productInstallPath = /usr/local/bin; productName = flippers; - productReference = 4CDD4F7B053751FF00FEC36D; - }; - 4CDD4F7B053751FF00FEC36D = { - explicitFileType = "compiled.mach-o.executable"; - includeInIndex = 0; - isa = PBXFileReference; - path = flippers; - refType = 3; - sourceTree = BUILT_PRODUCTS_DIR; + productReference = C2904F9606D116A3005FF97E; }; 4CDD4FB70537552600FEC36D = { containerPortal = 4CA1FEB0052A3C5800F22E42; @@ -1133,6 +1075,32 @@ refType = 0; sourceTree = ""; }; + 4CE1878506FFC5D60079D235 = { + children = ( + 4CE1878606FFC5D60079D235, + 4CE1878706FFC5D60079D235, + ); + isa = PBXGroup; + path = doc; + refType = 4; + sourceTree = ""; + }; + 4CE1878606FFC5D60079D235 = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text; + path = BLOBFORMAT; + refType = 4; + sourceTree = ""; + }; + 4CE1878706FFC5D60079D235 = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.man; + path = securityd.1; + refType = 4; + sourceTree = ""; + }; //4C0 //4C1 //4C2 @@ -1227,87 +1195,573 @@ settings = { }; }; - C20AF37C05F689540055732C = { + C209B39106ADBB19007B9E6D = { + children = ( + C209B3AD06ADBDB4007B9E6D, + C209B3AE06ADBDB4007B9E6D, + ); + isa = PBXGroup; + path = mig; + refType = 4; + sourceTree = ""; + }; + C209B39406ADBB2B007B9E6D = { + children = ( + C209B3B206ADBE64007B9E6D, + C209B3B306ADBE64007B9E6D, + C209B3B406ADBE64007B9E6D, + ); + isa = PBXGroup; + path = derived_src; + refType = 3; + sourceTree = BUILT_PRODUCTS_DIR; + }; + C209B3A406ADBCAC007B9E6D = { + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + isa = PBXShellScriptBuildPhase; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/bash; + shellScript = "make -f mig/mig.mk\n"; + }; + C209B3A506ADBCAC007B9E6D = { + buildPhases = ( + C209B3A406ADBCAC007B9E6D, + ); + buildSettings = { + OTHER_CFLAGS = ""; + OTHER_LDFLAGS = ""; + OTHER_REZFLAGS = ""; + PRODUCT_NAME = generate; + SECTORDER_FLAGS = ""; + WARNING_CFLAGS = "-Wmost -Wno-four-char-constants -Wno-unknown-pragmas"; + }; + dependencies = ( + ); + isa = PBXAggregateTarget; + name = mig; + productName = generate; + }; + C209B3A906ADBD6D007B9E6D = { + containerPortal = 4CA1FEB0052A3C5800F22E42; + isa = PBXContainerItemProxy; + proxyType = 1; + remoteGlobalIDString = C209B3A506ADBCAC007B9E6D; + remoteInfo = mig; + }; + C209B3AA06ADBD6D007B9E6D = { + isa = PBXTargetDependency; + target = C209B3A506ADBCAC007B9E6D; + targetProxy = C209B3A906ADBD6D007B9E6D; + }; + C209B3AD06ADBDB4007B9E6D = { fileEncoding = 30; isa = PBXFileReference; - lastKnownFileType = sourcecode.cpp.cpp; - path = tempdatabase.cpp; + lastKnownFileType = text; + path = mig.mk; refType = 4; sourceTree = ""; }; - C20AF37D05F689540055732C = { + C209B3AE06ADBDB4007B9E6D = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.mig; + path = self.defs; + refType = 4; + sourceTree = ""; + }; + C209B3B206ADBE64007B9E6D = { fileEncoding = 30; isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; - path = tempdatabase.h; + path = self.h; refType = 4; sourceTree = ""; }; - C20AF37E05F689540055732C = { - fileRef = C20AF37C05F689540055732C; + C209B3B306ADBE64007B9E6D = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = selfServer.cpp; + refType = 4; + sourceTree = ""; + }; + C209B3B406ADBE64007B9E6D = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = selfUser.cpp; + refType = 4; + sourceTree = ""; + }; + C209B3B506ADBE64007B9E6D = { + fileRef = C209B3B206ADBE64007B9E6D; isa = PBXBuildFile; settings = { }; }; - C20AF37F05F689540055732C = { - fileRef = C20AF37D05F689540055732C; + C209B3B606ADBE64007B9E6D = { + fileRef = C209B3B306ADBE64007B9E6D; isa = PBXBuildFile; settings = { }; }; - C276AAD60663E7A400B57276 = { - isa = PBXFileReference; - lastKnownFileType = wrapper.framework; - name = PCSC.framework; - path = /System/Library/Frameworks/PCSC.framework; - refType = 0; - sourceTree = ""; - }; - C276AAD70663E7A400B57276 = { - fileRef = C276AAD60663E7A400B57276; + C209B3B706ADBE64007B9E6D = { + fileRef = C209B3B406ADBE64007B9E6D; isa = PBXBuildFile; settings = { }; }; - C276AAF20663FD7500B57276 = { - children = ( - C2FDCABB0663CD5B0013F64C, - C2FDCABC0663CD5B0013F64C, - ); - isa = PBXGroup; - name = "Temporary (to utilities)"; - refType = 4; - sourceTree = ""; - }; - C28ACF9A05C9940B00447176 = { + C20AF37C05F689540055732C = { fileEncoding = 30; isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; - path = structure.cpp; + path = tempdatabase.cpp; refType = 4; sourceTree = ""; }; - C28ACF9B05C9940B00447176 = { + C20AF37D05F689540055732C = { fileEncoding = 30; isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; - path = structure.h; + path = tempdatabase.h; refType = 4; sourceTree = ""; }; - C28ACF9C05C9940B00447176 = { - fileRef = C28ACF9A05C9940B00447176; + C20AF37E05F689540055732C = { + fileRef = C20AF37C05F689540055732C; isa = PBXBuildFile; settings = { }; }; - C28ACF9D05C9940B00447176 = { - fileRef = C28ACF9B05C9940B00447176; + C20AF37F05F689540055732C = { + fileRef = C20AF37D05F689540055732C; isa = PBXBuildFile; settings = { }; }; - C2B8DBC705E6C3CE00E6E67C = { + C22A7F8C06AF06D9006087B7 = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = tokend.cpp; + refType = 4; + sourceTree = ""; + }; + C22A7F8D06AF06D9006087B7 = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = tokend.h; + refType = 4; + sourceTree = ""; + }; + C22A7F8E06AF06D9006087B7 = { + fileRef = C22A7F8C06AF06D9006087B7; + isa = PBXBuildFile; + settings = { + }; + }; + C22A7F8F06AF06D9006087B7 = { + fileRef = C22A7F8D06AF06D9006087B7; + isa = PBXBuildFile; + settings = { + }; + }; + C265A4DB06F12750000E5CFC = { + buildSettings = { + BUILD_VARIANTS = normal; + COPY_PHASE_STRIP = NO; + OPT_LDFLAGS = ""; + OPT_LDXFLAGS = ""; + OPT_LDXNOPIC = ""; + OTHER_CFLAGS_normal = "$(OTHER_CFLAGS) -O0 -fno-inline"; + OTHER_CPLUSPLUSFLAGS_normal = "$(OTHER_CPLUSPLUSFLAGS) -O0 -fno-inline"; + }; + isa = PBXBuildStyle; + name = "normal with debug"; + }; + C26D533706C1E70A00062E1E = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = tokenkey.cpp; + refType = 4; + sourceTree = ""; + }; + C26D533806C1E70A00062E1E = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = tokenkey.h; + refType = 4; + sourceTree = ""; + }; + C26D533906C1E70A00062E1E = { + fileRef = C26D533706C1E70A00062E1E; + isa = PBXBuildFile; + settings = { + }; + }; + C26D533A06C1E70A00062E1E = { + fileRef = C26D533806C1E70A00062E1E; + isa = PBXBuildFile; + settings = { + }; + }; + C26EA9510688CF34007CE21D = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = tokencache.cpp; + refType = 4; + sourceTree = ""; + }; + C26EA9520688CF34007CE21D = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = tokencache.h; + refType = 4; + sourceTree = ""; + }; + C26EA9530688CF34007CE21D = { + fileRef = C26EA9510688CF34007CE21D; + isa = PBXBuildFile; + settings = { + }; + }; + C26EA9540688CF34007CE21D = { + fileRef = C26EA9520688CF34007CE21D; + isa = PBXBuildFile; + settings = { + }; + }; + C276AAD60663E7A400B57276 = { + isa = PBXFileReference; + lastKnownFileType = wrapper.framework; + name = PCSC.framework; + path = /System/Library/Frameworks/PCSC.framework; + refType = 0; + sourceTree = ""; + }; + C2813C7F0730534A00E243E8 = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = tokenaccess.cpp; + refType = 4; + sourceTree = ""; + }; + C2813C800730534A00E243E8 = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = tokenaccess.h; + refType = 4; + sourceTree = ""; + }; + C2813C810730534A00E243E8 = { + fileRef = C2813C7F0730534A00E243E8; + isa = PBXBuildFile; + settings = { + }; + }; + C2813C820730534A00E243E8 = { + fileRef = C2813C800730534A00E243E8; + isa = PBXBuildFile; + settings = { + }; + }; + C28654B006DBC2A30021E6E5 = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = tokenacl.cpp; + refType = 4; + sourceTree = ""; + }; + C28654B106DBC2A30021E6E5 = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = tokenacl.h; + refType = 4; + sourceTree = ""; + }; + C28654B206DBC2A30021E6E5 = { + fileRef = C28654B006DBC2A30021E6E5; + isa = PBXBuildFile; + settings = { + }; + }; + C28654B306DBC2A30021E6E5 = { + fileRef = C28654B106DBC2A30021E6E5; + isa = PBXBuildFile; + settings = { + }; + }; + C28ACF9A05C9940B00447176 = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + path = structure.cpp; + refType = 4; + sourceTree = ""; + }; + C28ACF9B05C9940B00447176 = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + path = structure.h; + refType = 4; + sourceTree = ""; + }; + C28ACF9C05C9940B00447176 = { + fileRef = C28ACF9A05C9940B00447176; + isa = PBXBuildFile; + settings = { + }; + }; + C28ACF9D05C9940B00447176 = { + fileRef = C28ACF9B05C9940B00447176; + isa = PBXBuildFile; + settings = { + }; + }; + C28AE7FE06CD7CFF00BE0061 = { + children = ( + C2D425F205F3C07400CB11F8, + C2D425F105F3C07400CB11F8, + C26D533806C1E70A00062E1E, + C26D533706C1E70A00062E1E, + C2813C800730534A00E243E8, + C2813C7F0730534A00E243E8, + ); + isa = PBXGroup; + name = Token; + path = ""; + refType = 4; + sourceTree = ""; + }; + C28AE80106CD7D0E00BE0061 = { + children = ( + C20AF37D05F689540055732C, + C20AF37C05F689540055732C, + ); + isa = PBXGroup; + name = Temporary; + path = ""; + refType = 4; + sourceTree = ""; + }; + C28AE80406CD7D1D00BE0061 = { + children = ( + C20764E505ED250F004FEEDA, + C20764E405ED250F004FEEDA, + C20764E705ED250F004FEEDA, + C20764E605ED250F004FEEDA, + ); + isa = PBXGroup; + name = Local; + path = ""; + refType = 4; + sourceTree = ""; + }; + C28AE80706CD7D2700BE0061 = { + children = ( + C2B8DBCA05E6C3CE00E6E67C, + C2B8DBC905E6C3CE00E6E67C, + C207646405EAD713004FEEDA, + C207646305EAD713004FEEDA, + ); + isa = PBXGroup; + name = Keychain; + path = ""; + refType = 4; + sourceTree = ""; + }; + C28AE80A06CD7D3000BE0061 = { + children = ( + 4C9264B40534866F004B0E72, + 4C9264B20534866F004B0E72, + 4C9264B30534866F004B0E72, + ); + isa = PBXGroup; + name = Generate; + path = ""; + refType = 4; + sourceTree = ""; + }; + C28AE80E06CD7D5300BE0061 = { + children = ( + 4C9264B10534866F004B0E72, + 4C9264B00534866F004B0E72, + C28AE80A06CD7D3000BE0061, + ); + isa = PBXGroup; + name = Flippers; + path = ""; + refType = 4; + sourceTree = ""; + }; + C28AE81106CD7D7800BE0061 = { + children = ( + 40689F840725DCE00021A502, + 40689F850725DCE00021A502, + 4C92649F0534866F004B0E72, + 4C92649E0534866F004B0E72, + 4C9264A10534866F004B0E72, + 4C9264A00534866F004B0E72, + 4C9264A30534866F004B0E72, + 4C9264A20534866F004B0E72, + 405845660663B2010083E58C, + 405845650663B2010083E58C, + 4C9264A50534866F004B0E72, + 4C9264A40534866F004B0E72, + ); + isa = PBXGroup; + name = Authorization; + refType = 4; + sourceTree = ""; + }; + C28AE81406CD7DA100BE0061 = { + children = ( + 4C9264AB0534866F004B0E72, + 4C9264AA0534866F004B0E72, + C2B8DBC805E6C3CE00E6E67C, + C2B8DBC705E6C3CE00E6E67C, + 4C9264B60534866F004B0E72, + 4C9264B50534866F004B0E72, + 4C9264BB0534866F004B0E72, + 4C9264BA0534866F004B0E72, + 4C9264BF0534866F004B0E72, + 4C9264BE0534866F004B0E72, + 4C9264C10534866F004B0E72, + 4C9264C00534866F004B0E72, + C28ACF9B05C9940B00447176, + C28ACF9A05C9940B00447176, + ); + isa = PBXGroup; + name = "Core Structure"; + refType = 4; + sourceTree = ""; + }; + C28AE81706CD7DC500BE0061 = { + children = ( + C28AE80406CD7D1D00BE0061, + C28AE80706CD7D2700BE0061, + C28AE80106CD7D0E00BE0061, + C28AE7FE06CD7CFF00BE0061, + ); + isa = PBXGroup; + name = "Database Types"; + path = ""; + refType = 4; + sourceTree = ""; + }; + C28AE81A06CD7DE200BE0061 = { + children = ( + C2FDCABE0663CD5B0013F64C, + C2FDCABD0663CD5B0013F64C, + C2FDCAC00663CD5B0013F64C, + C2FDCABF0663CD5B0013F64C, + C2FDCAC20663CD5B0013F64C, + C2FDCAC10663CD5B0013F64C, + C22A7F8D06AF06D9006087B7, + C22A7F8C06AF06D9006087B7, + C26EA9520688CF34007CE21D, + C26EA9510688CF34007CE21D, + ); + isa = PBXGroup; + name = Smartcards; + refType = 4; + sourceTree = ""; + }; + C28AE82006CD7DF500BE0061 = { + children = ( + 4C9264BC0534866F004B0E72, + ); + isa = PBXGroup; + name = "Build Stuff"; + path = src; + refType = 4; + sourceTree = ""; + }; + C28AE82306CD7E0F00BE0061 = { + children = ( + 4C9264C20534866F004B0E72, + 4C9264C40534866F004B0E72, + 4C9264C30534866F004B0E72, + C28AE80E06CD7D5300BE0061, + ); + isa = PBXGroup; + name = Transit; + refType = 4; + sourceTree = ""; + }; + C28AE82606CD7E4700BE0061 = { + children = ( + 4C92649B0534866F004B0E72, + 4C92649A0534866F004B0E72, + C28654B106DBC2A30021E6E5, + C28654B006DBC2A30021E6E5, + 4C9264990534866F004B0E72, + 4C9264980534866F004B0E72, + ); + isa = PBXGroup; + name = ACLs; + refType = 4; + sourceTree = ""; + }; + C28AE83906CD7EE900BE0061 = { + children = ( + 4C92649D0534866F004B0E72, + 4C92649C0534866F004B0E72, + 4CB5ACBA06680AE000F359A9, + 4CB5ACB906680AE000F359A9, + 4C9264AF0534866F004B0E72, + 4C9264AE0534866F004B0E72, + 4C9264B90534866F004B0E72, + 4C9264B80534866F004B0E72, + 4C9264A90534866F004B0E72, + 4C9264A80534866F004B0E72, + ); + isa = PBXGroup; + name = Support; + refType = 4; + sourceTree = ""; + }; + C2904F9606D116A3005FF97E = { + explicitFileType = "compiled.mach-o.executable"; + includeInIndex = 0; + isa = PBXFileReference; + path = flippers; + refType = 3; + sourceTree = BUILT_PRODUCTS_DIR; + }; + C2A7B20E079F3A90000DB673 = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.xml; + path = "securityd-installCD.plist"; + refType = 4; + sourceTree = ""; + }; + C2A7B20F079F3A90000DB673 = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = text.xml; + path = securityd.plist; + refType = 4; + sourceTree = ""; + }; + C2B8DBC705E6C3CE00E6E67C = { fileEncoding = 30; isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; @@ -1363,6 +1817,16 @@ settings = { }; }; + C2C8B29806F8A60F000EBDA2 = { + children = ( + 4C9264AD0534866F004B0E72, + 4C9264AC0534866F004B0E72, + ); + isa = PBXGroup; + name = Crypto; + refType = 4; + sourceTree = ""; + }; C2D425F105F3C07400CB11F8 = { fileEncoding = 30; isa = PBXFileReference; @@ -1391,24 +1855,6 @@ settings = { }; }; - C2FDCABB0663CD5B0013F64C = { - fileEncoding = 30; - isa = PBXFileReference; - lastKnownFileType = sourcecode.cpp.cpp; - name = "pcsc++.cpp"; - path = "src/pcsc++.cpp"; - refType = 4; - sourceTree = ""; - }; - C2FDCABC0663CD5B0013F64C = { - fileEncoding = 30; - isa = PBXFileReference; - lastKnownFileType = sourcecode.c.h; - name = "pcsc++.h"; - path = "src/pcsc++.h"; - refType = 4; - sourceTree = ""; - }; C2FDCABD0663CD5B0013F64C = { fileEncoding = 30; isa = PBXFileReference; @@ -1457,18 +1903,6 @@ refType = 4; sourceTree = ""; }; - C2FDCAC30663CD5B0013F64C = { - fileRef = C2FDCABB0663CD5B0013F64C; - isa = PBXBuildFile; - settings = { - }; - }; - C2FDCAC40663CD5B0013F64C = { - fileRef = C2FDCABC0663CD5B0013F64C; - isa = PBXBuildFile; - settings = { - }; - }; C2FDCAC50663CD5B0013F64C = { fileRef = C2FDCABD0663CD5B0013F64C; isa = PBXBuildFile; diff --git a/src/AuthorizationDBPlist.cpp b/src/AuthorizationDBPlist.cpp index f7b49e1..ed48c32 100644 --- a/src/AuthorizationDBPlist.cpp +++ b/src/AuthorizationDBPlist.cpp @@ -3,8 +3,6 @@ * * @APPLE_LICENSE_HEADER_START@ * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. - * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in @@ -28,6 +26,8 @@ */ #include "AuthorizationDBPlist.h" +#include + namespace Authorization { diff --git a/src/AuthorizationDBPlist.h b/src/AuthorizationDBPlist.h index 4cbd6a5..1a365c8 100644 --- a/src/AuthorizationDBPlist.h +++ b/src/AuthorizationDBPlist.h @@ -3,8 +3,6 @@ * * @APPLE_LICENSE_HEADER_START@ * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. - * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in diff --git a/src/AuthorizationEngine.cpp b/src/AuthorizationEngine.cpp index a2d0f6e..a7078ae 100644 --- a/src/AuthorizationEngine.cpp +++ b/src/AuthorizationEngine.cpp @@ -3,8 +3,6 @@ * * @APPLE_LICENSE_HEADER_START@ * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. - * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in @@ -155,9 +153,9 @@ Engine::authorize(const AuthItemSet &inRights, const AuthItemSet &environment, secdebug("autheval", "evaluate rule %s for right %s returned %ld.", toplevelRule->name().c_str(), (*it)->name(), result); { - CodeSigning::OSXCode *processCode = Server::process().clientCode(); + RefPointer processCode = Server::process().clientCode(); string processName = processCode ? processCode->canonicalPath() : "unknown"; - CodeSigning::OSXCode *authCreatorCode = auth.creatorCode(); + RefPointer authCreatorCode = auth.creatorCode(); string authCreatorName = authCreatorCode ? authCreatorCode->canonicalPath() : "unknown"; if (result == errAuthorizationSuccess) diff --git a/src/AuthorizationEngine.h b/src/AuthorizationEngine.h index 6e40250..a54a5e8 100644 --- a/src/AuthorizationEngine.h +++ b/src/AuthorizationEngine.h @@ -3,8 +3,6 @@ * * @APPLE_LICENSE_HEADER_START@ * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. - * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in @@ -34,7 +32,7 @@ #include #include -#include +#include #include #include diff --git a/src/AuthorizationMechEval.cpp b/src/AuthorizationMechEval.cpp index 5f7a793..87ccdc2 100644 --- a/src/AuthorizationMechEval.cpp +++ b/src/AuthorizationMechEval.cpp @@ -3,8 +3,6 @@ * * @APPLE_LICENSE_HEADER_START@ * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. - * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in @@ -26,27 +24,28 @@ * securityd * */ - #include "AuthorizationMechEval.h" +#include +#include +#include namespace Authorization { -AgentMechanismRef::AgentMechanismRef(uid_t clientUID, const Session &session) : - RefPointer(new QueryInvokeMechanism(clientUID, session)) {} - -AgentMechanismRef::AgentMechanismRef() : - RefPointer(new QueryInvokeMechanism()) {} +AgentMechanismRef::AgentMechanismRef(const AuthHostType type, Session &session) : + RefPointer(new QueryInvokeMechanism(type, session)) {} // we need the vector of mechanisms -AgentMechanismEvaluator::AgentMechanismEvaluator(uid_t uid, const Session& session, const vector& inMechanisms) : +AgentMechanismEvaluator::AgentMechanismEvaluator(uid_t uid, Session& session, const vector& inMechanisms) : mMechanisms(inMechanisms), mClientUid(uid), mSession(session) { //set up environment } OSStatus -AgentMechanismEvaluator::run(const AuthValueVector &inArguments, const AuthItemSet &inHints, const AuthItemSet &inContext) +AgentMechanismEvaluator::run(const AuthValueVector &inArguments, const AuthItemSet &inHints, const AuthorizationToken &auth) { + const AuthItemSet &inContext = const_cast(auth).infoSet(); + // add process specifics to context? vector::const_iterator currentMechanism = mMechanisms.begin(); @@ -55,7 +54,7 @@ AgentMechanismEvaluator::run(const AuthValueVector &inArguments, const AuthItemS AuthItemSet hints = inHints; AuthItemSet context = inContext; - + while ( (result == kAuthorizationResultAllow) && (currentMechanism != mMechanisms.end()) ) // iterate mechanisms { @@ -67,72 +66,112 @@ AgentMechanismEvaluator::run(const AuthValueVector &inArguments, const AuthItemS { // no whitespace removal string pluginIn(currentMechanism->substr(0, extPlugin)); - string mechanismIn(currentMechanism->substr(extPlugin + 1)); - secdebug("AuthEvalMech", "external mech %s:%s", pluginIn.c_str(), mechanismIn.c_str()); + string mechanismIn, authhostIn; + + string::size_type extMechanism = currentMechanism->rfind(','); + AuthHostType hostType = securityAgent; + + if (extMechanism != string::npos) + { + if (extMechanism < extPlugin) + return errAuthorizationInternal; + + mechanismIn = currentMechanism->substr(extPlugin + 1, extMechanism - extPlugin - 1); + authhostIn = currentMechanism->substr(extMechanism + 1); + if (authhostIn == "privileged") + hostType = privilegedAuthHost; + } + else + mechanismIn = currentMechanism->substr(extPlugin + 1); + + secdebug("AuthEvalMech", "external mechanism %s:%s", pluginIn.c_str(), mechanismIn.c_str()); - AgentMechanismRef client(mClientUid, mSession); - client->initialize(pluginIn, mechanismIn); -// XXX/cs client->inferHints(Server::process()); - mClients[*currentMechanism] = client; + AgentMechanismRef client(hostType, mSession); + client->initialize(pluginIn, mechanismIn, inArguments); + mClients.insert(ClientMap::value_type(*currentMechanism, client)); } else if (*currentMechanism == "authinternal") { secdebug("AuthEvalMech", "performing authentication"); result = authinternal(context); + + AuthItem *rightItem = hints.find(AGENT_HINT_AUTHORIZE_RIGHT); + string right = (rightItem == NULL) ? string("") : rightItem->stringValue(); + CommonCriteria::AuditRecord auditrec(auth.creatorAuditToken()); + if (kAuthorizationResultAllow == result) + auditrec.submit(AUE_ssauthint, CommonCriteria::errNone, right.c_str()); + else // kAuthorizationResultDeny + auditrec.submit(AUE_ssauthint, CommonCriteria::errInvalidCredential, right.c_str()); } else if (*currentMechanism == "push_hints_to_context") { secdebug("AuthEvalMech", "evaluate push_hints_to_context"); - result = kAuthorizationResultAllow; // snarfcredential doesn't block evaluation, ever, it may restart - // create out context from input hints, no merge - // @@@ global copy template not being invoked... + // doesn't block evaluation, ever + result = kAuthorizationResultAllow; context = hints; } -#if 0 - else if (*currentMechanism == "switch_to_user") - { - AgentMechanismRef client(mClientUid, mSession); - client->terminate(); - } -#endif else return errAuthorizationInternal; } iter = mClients.find(*currentMechanism); - if (iter != mClients.end()) { try { - iter->second->run(inArguments, hints, context, &result); - secdebug("AuthEvalMech", "evaluate(%s) succeeded with result: %lu.", (iter->first).c_str(), result); + AgentMechanismRef &client = iter->second; + client->run(inArguments, hints, context, &result); + + bool interrupted = false; + while (client->state() == client->current) + { + // check for interruption + vector::const_iterator checkMechanism = mMechanisms.begin(); + while (*checkMechanism != *currentMechanism) { + ClientMap::iterator iter2 = mClients.find(*checkMechanism); + if (iter2->second->state() == iter2->second->interrupting) + { + client->deactivate(); + // nothing can happen until the client mechanism returns control to us + while (client->state() == client->deactivating) + client->receive(); + + secdebug("AuthEvalMech", "evaluate(%s) interrupted by %s.", (iter->first).c_str(), (iter2->first).c_str()); + + interrupted = true; + hints = iter2->second->inHints(); + context = iter2->second->inContext(); + currentMechanism = checkMechanism; + break; + } + else + checkMechanism++; + } + if (client->state() == client->current) + client->receive(); + } + + if (interrupted) + { + // clear reason for restart from interrupt + uint32_t reason = SecurityAgent::worldChanged; + AuthItemRef retryHint(AGENT_HINT_RETRY_REASON, AuthValueOverlay(sizeof(reason), &reason)); + hints.erase(retryHint); hints.insert(retryHint); // replace + + result = kAuthorizationResultAllow; + continue; + } + else + secdebug("AuthEvalMech", "evaluate(%s) with result: %lu.", (iter->first).c_str(), result); } catch (...) { - secdebug("AuthEvalMech", "exception from mech eval or client death"); + secdebug("AuthEvalMech", "exception during evaluate(%s).", (iter->first).c_str()); result = kAuthorizationResultUndefined; } } - // we own outHints and outContext - switch(result) - { - case kAuthorizationResultAllow: - secdebug("AuthEvalMech", "result allow"); - currentMechanism++; - break; - case kAuthorizationResultDeny: - secdebug("AuthEvalMech", "result deny"); - break; - case kAuthorizationResultUndefined: - secdebug("AuthEvalMech", "result undefined"); - break; // abort evaluation - case kAuthorizationResultUserCanceled: - secdebug("AuthEvalMech", "result canceled"); - break; // stop evaluation, return some sideband - default: - break; // abort evaluation - } + if (result == kAuthorizationResultAllow) + currentMechanism++; } if ((result == kAuthorizationResultUserCanceled) || diff --git a/src/AuthorizationMechEval.h b/src/AuthorizationMechEval.h index 5a6375d..dc6d5ea 100644 --- a/src/AuthorizationMechEval.h +++ b/src/AuthorizationMechEval.h @@ -3,8 +3,6 @@ * * @APPLE_LICENSE_HEADER_START@ * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. - * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in @@ -41,15 +39,14 @@ namespace Authorization { class AgentMechanismRef : public RefPointer { public: - AgentMechanismRef(uid_t clientUID, const Session &session); - AgentMechanismRef(); + AgentMechanismRef(const AuthHostType type, Session &session); }; class AgentMechanismEvaluator { public: - AgentMechanismEvaluator(uid_t uid, const Session &session, const vector& inMechanisms); - OSStatus run(const AuthValueVector &arguments, const AuthItemSet &hints, const AuthItemSet &context); + AgentMechanismEvaluator(uid_t uid, Session &session, const vector& inMechanisms); + OSStatus run(const AuthValueVector &inArguments, const AuthItemSet &inHints, const AuthorizationToken &auth); AuthorizationResult AgentMechanismEvaluator::authinternal(AuthItemSet &context); @@ -62,7 +59,7 @@ private: ClientMap mClients; uid_t mClientUid; - const Session &mSession; + Session &mSession; AuthItemSet mHints; AuthItemSet mContext; diff --git a/src/AuthorizationRule.cpp b/src/AuthorizationRule.cpp index 847ae60..fdbbac9 100644 --- a/src/AuthorizationRule.cpp +++ b/src/AuthorizationRule.cpp @@ -3,8 +3,6 @@ * * @APPLE_LICENSE_HEADER_START@ * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. - * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in @@ -32,6 +30,9 @@ #include #include #include +#include +#include +#include #include "authority.h" #include "server.h" #include "process.h" @@ -41,7 +42,11 @@ #include #include #include +#include +extern "C" { +#include +} // // Rule class @@ -64,9 +69,11 @@ CFStringRef RuleImpl::kRuleDenyID = CFSTR(kAuthorizationRuleClassDeny); CFStringRef RuleImpl::kRuleUserID = CFSTR(kAuthorizationRuleClassUser); CFStringRef RuleImpl::kRuleDelegateID = CFSTR(kAuthorizationRightRule); CFStringRef RuleImpl::kRuleMechanismsID = CFSTR(kAuthorizationRuleClassMechanisms); +CFStringRef RuleImpl::kRuleAuthenticateUserID = CFSTR(kAuthorizationRuleParameterAuthenticateUser); + string -RuleImpl::Attribute::getString(CFDictionaryRef config, CFStringRef key, bool required = false, char *defaultValue = NULL) +RuleImpl::Attribute::getString(CFDictionaryRef config, CFStringRef key, bool required = false, char *defaultValue = "") { CFTypeRef value = CFDictionaryGetValue(config, key); if (value && (CFGetTypeID(value) == CFStringGetTypeID())) @@ -129,44 +136,6 @@ RuleImpl::Attribute::getBool(CFDictionaryRef config, CFStringRef key, bool requi return boolValue; } -// add reference to string that we're modifying -void -RuleImpl::Attribute::setString(CFMutableDictionaryRef config, CFStringRef key, string &value) -{ - CFStringRef cfstringValue = CFStringCreateWithCString(NULL /*allocator*/, value.c_str(), kCFStringEncodingUTF8); - - if (cfstringValue) - { - CFDictionarySetValue(config, key, cfstringValue); - CFRelease(cfstringValue); - } - else - MacOSError::throwMe(errAuthorizationInternal); // XXX/cs invalid attribute -} - -void -RuleImpl::Attribute::setDouble(CFMutableDictionaryRef config, CFStringRef key, double value) -{ - CFNumberRef doubleValue = CFNumberCreate(NULL /*allocator*/, kCFNumberDoubleType, doubleValue); - - if (doubleValue) - { - CFDictionarySetValue(config, key, doubleValue); - CFRelease(doubleValue); - } - else - MacOSError::throwMe(errAuthorizationInternal); // XXX/cs invalid attribute -} - -void -RuleImpl::Attribute::setBool(CFMutableDictionaryRef config, CFStringRef key, bool value) -{ - if (value) - CFDictionarySetValue(config, key, kCFBooleanTrue); - else - CFDictionarySetValue(config, key, kCFBooleanFalse); -} - vector RuleImpl::Attribute::getVector(CFDictionaryRef config, CFStringRef key, bool required = false) { @@ -240,7 +209,7 @@ bool RuleImpl::Attribute::getLocalizedPrompts(CFDictionaryRef config, map(CFDictionaryGetValue(cfRules, CFSTR("authenticate"))); + if (cfRuleDef && CFGetTypeID(cfRuleDef) == CFDictionaryGetTypeID()) + mEvalDef = Attribute::getVector(cfRuleDef, kMechanismsID); + } mTries = int(Attribute::getDouble(cfRight, kTriesID, false, 3.0)); // XXX/cs double(kAuthorizationMaxTries) + mAuthenticateUser = Attribute::getBool(cfRight, kRuleAuthenticateUserID, false, true); secdebug("authrule", "%s : rule user in group \"%s\" timeout %g%s%s", inRightName.c_str(), @@ -296,10 +272,11 @@ RuleImpl::RuleImpl(const string &inRightName, CFDictionaryRef cfRight, CFDiction // mechanisms to evaluate mEvalDef = Attribute::getVector(cfRight, kMechanismsID, true); mTries = int(Attribute::getDouble(cfRight, kTriesID, false, 0.0)); // "forever" + mShared = Attribute::getBool(cfRight, kSharedID, false, true); } else if (classTag == kAuthorizationRightRule) { - assert(cfRules); // this had better not be a rule + assert(cfRules); // rules can't delegate to other rules secdebug("authrule", "%s : rule delegate rule", inRightName.c_str()); mType = kRuleDelegation; @@ -313,7 +290,7 @@ RuleImpl::RuleImpl(const string &inRightName, CFDictionaryRef cfRight, CFDiction CFRelease(ruleDefRef); if (!cfRuleDef || CFGetTypeID(cfRuleDef) != CFDictionaryGetTypeID()) MacOSError::throwMe(errAuthorizationInternal); // XXX/cs invalid rule - mRuleDef.push_back(Rule(ruleDefString, cfRuleDef, NULL)); + mRuleDef.push_back(Rule(ruleDefString, cfRuleDef, cfRules)); } else // array { @@ -326,7 +303,7 @@ RuleImpl::RuleImpl(const string &inRightName, CFDictionaryRef cfRight, CFDiction CFRelease(ruleNameRef); if (!cfRuleDef || (CFGetTypeID(cfRuleDef) != CFDictionaryGetTypeID())) MacOSError::throwMe(errAuthorizationInternal); // XXX/cs invalid rule - mRuleDef.push_back(Rule(*it, cfRuleDef, NULL)); + mRuleDef.push_back(Rule(*it, cfRuleDef, cfRules)); } } @@ -347,7 +324,6 @@ RuleImpl::RuleImpl(const string &inRightName, CFDictionaryRef cfRight, CFDiction // it _must_ have a definition for "rule" which will be used as a delegate // it may have a comment (not extracted here) // it may have a default prompt, or a whole dictionary of languages (not extracted here) - assert(cfRules); mType = kRuleDelegation; string ruleName = Attribute::getString(cfRight, kRuleDelegateID, true); secdebug("authrule", "%s : rule delegate rule (1): %s", inRightName.c_str(), ruleName.c_str()); @@ -357,7 +333,7 @@ RuleImpl::RuleImpl(const string &inRightName, CFDictionaryRef cfRight, CFDiction CFRelease(ruleNameRef); if (!cfRuleDef || CFGetTypeID(cfRuleDef) != CFDictionaryGetTypeID()) MacOSError::throwMe(errAuthorizationInternal); // XXX/cs invalid rule - mRuleDef.push_back(Rule(ruleName, cfRuleDef, NULL)); + mRuleDef.push_back(Rule(ruleName, cfRuleDef, cfRules)); } Attribute::getLocalizedPrompts(cfRight, mLocalizedPrompts); @@ -373,31 +349,37 @@ void RuleImpl::setAgentHints(const AuthItemRef &inRight, const Rule &inTopLevelRule, AuthItemSet &environmentToClient, AuthorizationToken &auth) const { string authorizeString(inRight->name()); + environmentToClient.erase(AuthItemRef(AGENT_HINT_AUTHORIZE_RIGHT)); environmentToClient.insert(AuthItemRef(AGENT_HINT_AUTHORIZE_RIGHT, AuthValueOverlay(authorizeString))); - - // XXX/cs pid/uid/client should only be added when we're ready to call the agent - pid_t cPid = Server::process().pid(); - environmentToClient.insert(AuthItemRef(AGENT_HINT_CLIENT_PID, AuthValueOverlay(sizeof(pid_t), &cPid))); - - uid_t cUid = auth.creatorUid(); - environmentToClient.insert(AuthItemRef(AGENT_HINT_CLIENT_UID, AuthValueOverlay(sizeof(uid_t), &cUid))); pid_t creatorPid = auth.creatorPid(); + environmentToClient.erase(AuthItemRef(AGENT_HINT_CREATOR_PID)); environmentToClient.insert(AuthItemRef(AGENT_HINT_CREATOR_PID, AuthValueOverlay(sizeof(pid_t), &creatorPid))); + + Process &thisProcess = Server::process(); + RefPointer clientCode = auth.creatorCode(); + SecurityAgent::RequestorType requestorType = SecurityAgent::unknown; + string bundlePath; + if (clientCode) { - CodeSigning::OSXCode *osxcode = auth.creatorCode(); - if (!osxcode) - MacOSError::throwMe(errAuthorizationDenied); - - string encodedBundle = osxcode->encode(); + string encodedBundle = clientCode->encode(); char bundleType = (encodedBundle.c_str())[0]; // yay, no accessor - string bundlePath = osxcode->canonicalPath(); - - environmentToClient.insert(AuthItemRef(AGENT_HINT_CLIENT_TYPE, AuthValueOverlay(sizeof(bundleType), &bundleType))); - environmentToClient.insert(AuthItemRef(AGENT_HINT_CLIENT_PATH, AuthValueOverlay(bundlePath))); + switch(bundleType) + { + case 'b': requestorType = SecurityAgent::bundle; break; + case 't': requestorType = SecurityAgent::tool; break; + } + bundlePath = clientCode->canonicalPath(); } - + + AuthItemSet processHints = SecurityAgent::Client::clientHints(requestorType, bundlePath, thisProcess.pid(), thisProcess.uid()); + environmentToClient.erase(AuthItemRef(AGENT_HINT_CLIENT_TYPE)); + environmentToClient.erase(AuthItemRef(AGENT_HINT_CLIENT_PATH)); + environmentToClient.erase(AuthItemRef(AGENT_HINT_CLIENT_PID)); + environmentToClient.erase(AuthItemRef(AGENT_HINT_CLIENT_UID)); + environmentToClient.insert(processHints.begin(), processHints.end()); + map defaultPrompts = inTopLevelRule->localizedPrompts(); if (defaultPrompts.empty()) @@ -416,37 +398,10 @@ RuleImpl::setAgentHints(const AuthItemRef &inRight, const Rule &inTopLevelRule, // add rulename as a hint string ruleName = name(); + environmentToClient.erase(AuthItemRef(AGENT_HINT_AUTHORIZE_RULE)); environmentToClient.insert(AuthItemRef(AGENT_HINT_AUTHORIZE_RULE, AuthValueOverlay(ruleName))); } -string -RuleImpl::agentNameForAuth(const AuthorizationToken &auth) const -{ - uint8_t hash[20]; - AuthorizationBlob authBlob = auth.handle(); - CssmData hashedData = CssmData::wrap(&hash, sizeof(hash)); - CssmData data = CssmData::wrap(&authBlob, sizeof(authBlob)); - CssmClient::Digest ctx(Server::csp(), CSSM_ALGID_SHA1); - try { - ctx.digest(data, hashedData); - } - catch (CssmError &e) - { - secdebug("auth", "digesting authref failed (%lu)", e.osStatus()); - return string("SecurityAgentMechanism"); - } - - uint8_t *point = static_cast(hashedData.data()); - for (uint8_t i=0; i < hashedData.length(); point++, i++) - { - uint8 value = (*point % 62) + '0'; - if (value > '9') value += 7; - if (value > 'Z') value += 6; - *point = value; - } - return string(static_cast(hashedData.data()), hashedData.length()); -} - OSStatus RuleImpl::evaluateAuthorization(const AuthItemRef &inRight, const Rule &inRule, AuthItemSet &environmentToClient, @@ -467,12 +422,12 @@ RuleImpl::evaluateAuthorization(const AuthItemRef &inRight, const Rule &inRule, uint32 tries; SecurityAgent::Reason reason = SecurityAgent::noReason; - Process &cltProc = Server::process(); + Process &cltProc = Server::process(); // Authorization preserves creator's UID in setuid processes uid_t cltUid = (cltProc.uid() != 0) ? cltProc.uid() : auth.creatorUid(); secdebug("AuthEvalMech", "Mechanism invocation by process %d (UID %d)", cltProc.pid(), cltUid); - - AgentMechanismEvaluator eval(cltUid, cltProc.session(), mEvalDef); + + AgentMechanismEvaluator eval(cltUid, auth.session(), mEvalDef); for (tries = 0; tries < mTries; tries++) { @@ -481,7 +436,7 @@ RuleImpl::evaluateAuthorization(const AuthItemRef &inRight, const Rule &inRule, AuthItemRef triesHint(AGENT_HINT_TRIES, AuthValueOverlay(sizeof(tries), &tries)); environmentToClient.erase(triesHint); environmentToClient.insert(triesHint); // replace - status = eval.run(AuthValueVector(), environmentToClient, auth.infoSet()); + status = eval.run(AuthValueVector(), environmentToClient, auth); if ((status == errAuthorizationSuccess) || (status == errAuthorizationCanceled)) // @@@ can only pass back sideband through context @@ -496,11 +451,9 @@ RuleImpl::evaluateAuthorization(const AuthItemRef &inRight, const Rule &inRule, // deny is the default status = errAuthorizationDenied; - // fetch context and construct a credential to be tested - AuthItemSet inContext = auth.infoSet(); - CredentialSet newCredentials = makeCredentials(inContext); + CredentialSet newCredentials = makeCredentials(auth); // clear context after extracting credentials - auth.clearInfoSet(); + auth.scrubInfoSet(); for (CredentialSet::const_iterator it = newCredentials.begin(); it != newCredentials.end(); ++it) { @@ -520,13 +473,14 @@ RuleImpl::evaluateAuthorization(const AuthItemRef &inRight, const Rule &inRule, } // verify that this credential authorizes right - status = evaluateCredentialForRight(inRight, inRule, environmentToClient, now, newCredential, true); + status = evaluateCredentialForRight(auth, inRight, inRule, environmentToClient, now, newCredential, true); if (status == errAuthorizationSuccess) { // whack an equivalent credential, so it gets updated to a later achieved credential which must have been more stringent credentials.erase(newCredential); credentials.insert(newCredential); // use valid credential to set context info + // XXX/cs keeping this for now, such that the uid is passed back auth.setCredentialInfo(newCredential); secdebug("SSevalMech", "added valid credential for user %s", newCredential->username().c_str()); status = errAuthorizationSuccess; @@ -543,9 +497,13 @@ RuleImpl::evaluateAuthorization(const AuthItemRef &inRight, const Rule &inRule, if ((status == errAuthorizationCanceled) || (status == errAuthorizationInternal)) { - auth.clearInfoSet(); + auth.scrubInfoSet(); break; } + else // last mechanism is now authentication - fail + if (status == errAuthorizationDenied) + reason = SecurityAgent::invalidPassphrase; + } // If we fell out of the loop because of too many tries, notify user @@ -556,9 +514,12 @@ RuleImpl::evaluateAuthorization(const AuthItemRef &inRight, const Rule &inRule, environmentToClient.erase(retryHint); environmentToClient.insert(retryHint); // replace AuthItemRef triesHint(AGENT_HINT_TRIES, AuthValueOverlay(sizeof(tries), &tries)); environmentToClient.erase(triesHint); environmentToClient.insert(triesHint); // replace - eval.run(AuthValueVector(), environmentToClient, auth.infoSet()); + eval.run(AuthValueVector(), environmentToClient, auth); // XXX/cs is this still necessary? - auth.clearInfoSet(); + auth.scrubInfoSet(); + + CommonCriteria::AuditRecord auditrec(auth.creatorAuditToken()); + auditrec.submit(AUE_ssauthorize, CommonCriteria::errTooManyTries, inRight->name()); } return status; @@ -567,8 +528,10 @@ RuleImpl::evaluateAuthorization(const AuthItemRef &inRight, const Rule &inRule, // create externally verified credentials on the basis of // mechanism-provided information CredentialSet -RuleImpl::makeCredentials(const AuthItemSet &context) const +RuleImpl::makeCredentials(const AuthorizationToken &auth) const { + // fetch context and construct a credential to be tested + const AuthItemSet &context = const_cast(auth).infoSet(); CredentialSet newCredentials; do { @@ -607,7 +570,13 @@ RuleImpl::makeCredentials(const AuthItemSet &context) const secdebug("AuthEvalMech", "found password"); string password = (**found).stringValue(); secdebug("AuthEvalMech", "falling back on username/password credential if valid"); - newCredentials.insert(Credential(username, password, mShared)); + Credential newCred(username, password, mShared); + newCredentials.insert(newCred); + CommonCriteria::AuditRecord auditrec(auth.creatorAuditToken()); + if (newCred->isValid()) + auditrec.submit(AUE_ssauthorize, CommonCriteria::errNone, name().c_str()); + else + auditrec.submit(AUE_ssauthorize, CommonCriteria::errInvalidCredential, name().c_str()); } } } while(0); @@ -627,18 +596,26 @@ RuleImpl::evaluateSessionOwner(const AuthItemRef &inRight, const Rule &inRule, OSStatus status = noErr; // @@@ we have no access to current requester uid here and the process uid is only taken when the authorization is created // meaning that a process like loginwindow that drops privs later is screwed. - uid_t uid = auth.creatorUid(); + + uid_t uid; + Session &session = auth.session(); + + if (session.haveOriginatorUid()) + uid = session.originatorUid(); + else + uid = auth.creatorUid(); Server::active().longTermActivity(); struct passwd *pw = getpwuid(uid); if (pw != NULL) { - // avoid hinting a locked account (ie. root) + // avoid hinting a locked account if ( (pw->pw_passwd == NULL) || strcmp(pw->pw_passwd, "*") ) { // Check if username will authorize the request and set username to // be used as a hint to the user if so - status = evaluateCredentialForRight(inRight, inRule, environment, now, Credential(pw->pw_name, pw->pw_uid, pw->pw_gid, mShared), true); + secdebug("AuthEvalMech", "preflight credential from current user, result follows:"); + status = evaluateCredentialForRight(auth, inRight, inRule, environment, now, Credential(pw->pw_name, pw->pw_uid, pw->pw_gid, mShared), true); if (status == errAuthorizationSuccess) usernamehint = pw->pw_name; @@ -653,7 +630,7 @@ RuleImpl::evaluateSessionOwner(const AuthItemRef &inRight, const Rule &inRule, // Return errAuthorizationSuccess if this rule allows access based on the specified credential, // return errAuthorizationDenied otherwise. OSStatus -RuleImpl::evaluateCredentialForRight(const AuthItemRef &inRight, const Rule &inRule, const AuthItemSet &environment, CFAbsoluteTime now, const Credential &credential, bool ignoreShared) const +RuleImpl::evaluateCredentialForRight(const AuthorizationToken &auth, const AuthItemRef &inRight, const Rule &inRule, const AuthItemSet &environment, CFAbsoluteTime now, const Credential &credential, bool ignoreShared) const { assert(mType == kUser); @@ -687,14 +664,13 @@ RuleImpl::evaluateCredentialForRight(const AuthItemRef &inRight, const Rule &inR return errAuthorizationSuccess; } - // XXX/cs replace with remembered session-owner once that functionality is added to SecurityServer if (mSessionOwner) { - uid_t console_user; - struct stat console_stat; - if (!lstat("/dev/console", &console_stat)) - { - console_user = console_stat.st_uid; + Session &session = auth.session(); + if (session.haveOriginatorUid()) + { + uid_t console_user = session.originatorUid(); + if (credential->uid() == console_user) { secdebug("autheval", "user %s is session-owner(uid: %d), granting right %s", user, console_user, inRight->name()); @@ -709,35 +685,36 @@ RuleImpl::evaluateCredentialForRight(const AuthItemRef &inRight, const Rule &inR { const char *groupname = mGroupName.c_str(); Server::active().longTermActivity(); - struct group *gr = getgrnam(groupname); - if (!gr) + + if (!groupname) return errAuthorizationDenied; - - // Is this the default group of this user? - // PR-2875126 declares gr_gid int, as opposed to advertised (getgrent(3)) gid_t - // When this is fixed this warning should go away. - if (credential->gid() == gr->gr_gid) - { - secdebug("autheval", "user %s has group %s(%d) as default group, granting right %s", - user, groupname, gr->gr_gid, inRight->name()); - endgrent(); - return errAuthorizationSuccess; - } - - for (char **group = gr->gr_mem; *group; ++group) + + do { - if (!strcmp(*group, user)) + uuid_t group_uuid, user_uuid; + int is_member; + + if (mbr_group_name_to_uuid(groupname, group_uuid)) + break; + + if (mbr_uid_to_uuid(credential->uid(), user_uuid)) + break; + + if (mbr_check_membership(user_uuid, group_uuid, &is_member)) + break; + + if (is_member) { secdebug("autheval", "user %s is a member of group %s, granting right %s", user, groupname, inRight->name()); - endgrent(); return errAuthorizationSuccess; } + } - + while (0); + secdebug("autheval", "user %s is not a member of group %s, denying right %s", user, groupname, inRight->name()); - endgrent(); } return errAuthorizationDenied; @@ -763,19 +740,22 @@ RuleImpl::evaluateUser(const AuthItemRef &inRight, const Rule &inRule, return errAuthorizationSuccess; } - // if this is a "is-admin" rule check that and return - // XXX/cs add way to specify is-admin class of rule: if (mNoVerify) - if (name() == kAuthorizationRuleIsAdmin) + // if we're not supposed to authenticate evaluate the session-owner against the group + if (!mAuthenticateUser) { string username; - if (!evaluateSessionOwner(inRight, inRule, environmentToClient, now, auth, username)) + OSStatus status = evaluateSessionOwner(inRight, inRule, environmentToClient, now, auth, username); + + if (!status) return errAuthorizationSuccess; + + return errAuthorizationDenied; } // First -- go though the credentials we either already used or obtained during this authorize operation. for (CredentialSet::const_iterator it = credentials.begin(); it != credentials.end(); ++it) { - OSStatus status = evaluateCredentialForRight(inRight, inRule, environmentToClient, now, *it, true); + OSStatus status = evaluateCredentialForRight(auth, inRight, inRule, environmentToClient, now, *it, true); if (status != errAuthorizationDenied) { // add credential to authinfo @@ -789,7 +769,7 @@ RuleImpl::evaluateUser(const AuthItemRef &inRight, const Rule &inRule, { for (CredentialSet::const_iterator it = inCredentials->begin(); it != inCredentials->end(); ++it) { - OSStatus status = evaluateCredentialForRight(inRight, inRule, environmentToClient, now, *it, false); + OSStatus status = evaluateCredentialForRight(auth, inRight, inRule, environmentToClient, now, *it, false); if (status == errAuthorizationSuccess) { // Add the credential we used to the output set. @@ -835,13 +815,13 @@ RuleImpl::evaluateMechanismOnly(const AuthItemRef &inRight, const Rule &inRule, uint32 tries = 0; OSStatus status; - Process &cltProc = Server::process(); + Process &cltProc = Server::process(); // Authorization preserves creator's UID in setuid processes uid_t cltUid = (cltProc.uid() != 0) ? cltProc.uid() : auth.creatorUid(); secdebug("AuthEvalMech", "Mechanism invocation by process %d (UID %d)", cltProc.pid(), cltUid); { - AgentMechanismEvaluator eval(cltUid, cltProc.session(), mEvalDef); + AgentMechanismEvaluator eval(cltUid, auth.session(), mEvalDef); do { @@ -849,7 +829,7 @@ RuleImpl::evaluateMechanismOnly(const AuthItemRef &inRight, const Rule &inRule, AuthItemRef triesHint(AGENT_HINT_TRIES, AuthValueOverlay(sizeof(tries), &tries)); environmentToClient.erase(triesHint); environmentToClient.insert(triesHint); // replace - status = eval.run(AuthValueVector(), environmentToClient, auth.infoSet()); + status = eval.run(AuthValueVector(), environmentToClient, auth); if ((status == errAuthorizationSuccess) || (status == errAuthorizationCanceled)) // @@@ can only pass back sideband through context @@ -858,7 +838,7 @@ RuleImpl::evaluateMechanismOnly(const AuthItemRef &inRight, const Rule &inRule, auth.setInfoSet(eval.context()); if (status == errAuthorizationSuccess) { - outCredentials = makeCredentials(eval.context()); + outCredentials = makeCredentials(auth); } } @@ -869,13 +849,16 @@ RuleImpl::evaluateMechanismOnly(const AuthItemRef &inRight, const Rule &inRule, || ((mTries > 0) // mTries > 0 means we try up to mTries times && (tries < mTries)))); } + + // HACK kill all hosts to free pages for low memory systems + if (name() == "system.login.console") + { + QueryInvokeMechanism query(securityAgent, auth.session()); + query.terminateAgent(); + QueryInvokeMechanism query2(privilegedAuthHost, auth.session()); + query2.terminateAgent(); + } - if (name() == "system.login.console") - { - QueryInvokeMechanism query(cltUid, cltProc.session()); - query.terminateAgent(); - } - return status; } diff --git a/src/AuthorizationRule.h b/src/AuthorizationRule.h index 21a4f20..d83c5a4 100644 --- a/src/AuthorizationRule.h +++ b/src/AuthorizationRule.h @@ -3,8 +3,6 @@ * * @APPLE_LICENSE_HEADER_START@ * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. - * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in @@ -57,10 +55,8 @@ private: // internal machinery // evaluate credential for right - OSStatus evaluateCredentialForRight(const AuthItemRef &inRight, const Rule &inRule, - const AuthItemSet &environment, - CFAbsoluteTime now, const Credential &credential, bool ignoreShared) const; - + OSStatus evaluateCredentialForRight(const AuthorizationToken &auth, const AuthItemRef &inRight, const Rule &inRule, + const AuthItemSet &environment, CFAbsoluteTime now, const Credential &credential, bool ignoreShared) const; OSStatus evaluateRules(const AuthItemRef &inRight, const Rule &inRule, AuthItemSet &environmentToClient, AuthorizationFlags flags, @@ -72,8 +68,6 @@ private: // perform authorization based on running specified mechanisms (see evaluateMechanism) OSStatus evaluateAuthorization(const AuthItemRef &inRight, const Rule &inRule, AuthItemSet &environmentToClient, AuthorizationFlags flags, CFAbsoluteTime now, const CredentialSet *inCredentials, CredentialSet &credentials, AuthorizationToken &auth) const; - OSStatus evaluateAuthorizationOld(const AuthItemRef &inRight, const Rule &inRule, AuthItemSet &environmentToClient, AuthorizationFlags flags, CFAbsoluteTime now, const CredentialSet *inCredentials, CredentialSet &credentials, AuthorizationToken &auth) const; - OSStatus evaluateUser(const AuthItemRef &inRight, const Rule &inRule, AuthItemSet &environmentToClient, AuthorizationFlags flags, CFAbsoluteTime now, const CredentialSet *inCredentials, CredentialSet &credentials, @@ -84,8 +78,7 @@ private: // find username hint based on session owner OSStatus evaluateSessionOwner(const AuthItemRef &inRight, const Rule &inRule, const AuthItemSet &environment, const CFAbsoluteTime now, const AuthorizationToken &auth, string& usernamehint) const; - string agentNameForAuth(const AuthorizationToken &auth) const; - CredentialSet makeCredentials(const AuthItemSet &context) const; + CredentialSet makeCredentials(const AuthorizationToken &auth) const; map localizedPrompts() const { return mLocalizedPrompts; } @@ -112,6 +105,7 @@ private: vector mRuleDef; uint32_t mKofN; mutable uint32_t mTries; + bool mAuthenticateUser; map mLocalizedPrompts; private: @@ -123,9 +117,6 @@ private: static double getDouble(CFDictionaryRef config, CFStringRef key, bool required, double defaultValue); static string getString(CFDictionaryRef config, CFStringRef key, bool required, char *defaultValue); static vector getVector(CFDictionaryRef config, CFStringRef key, bool required); - static void setString(CFMutableDictionaryRef config, CFStringRef key, string &value); - static void setDouble(CFMutableDictionaryRef config, CFStringRef key, double value); - static void setBool(CFMutableDictionaryRef config, CFStringRef key, bool value); static bool getLocalizedPrompts(CFDictionaryRef config, map &localizedPrompts); }; @@ -147,7 +138,7 @@ private: static CFStringRef kRuleUserID; static CFStringRef kRuleDelegateID; static CFStringRef kRuleMechanismsID; - + static CFStringRef kRuleAuthenticateUserID; }; class Rule : public RefPointer diff --git a/src/acl_keychain.cpp b/src/acl_keychain.cpp index 2970217..6ac8eb7 100644 --- a/src/acl_keychain.cpp +++ b/src/acl_keychain.cpp @@ -3,8 +3,6 @@ * * @APPLE_LICENSE_HEADER_START@ * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. - * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in @@ -101,7 +99,7 @@ bool KeychainPromptAclSubject::validate(const AclValidationContext &context, } // does the user need to type in the passphrase? - const Database *db = env->database(); + const Database *db = env->database; bool needPassphrase = db && (selector.flags & CSSM_ACL_KEYCHAIN_PROMPT_REQUIRE_PASSPHRASE); // ask the user @@ -187,8 +185,8 @@ KeychainPromptAclSubject *KeychainPromptAclSubject::Maker::make(Version version, break; case jaguarVersion: pub(selector); - selector.version = n2h (selector.version); - selector.flags = n2h (selector.flags); + selector.version = n2h(selector.version); + selector.flags = n2h(selector.flags); pub(description); break; } @@ -197,7 +195,7 @@ KeychainPromptAclSubject *KeychainPromptAclSubject::Maker::make(Version version, KeychainPromptAclSubject::KeychainPromptAclSubject(string descr, const CSSM_ACL_KEYCHAIN_PROMPT_SELECTOR &sel) - : SimpleAclSubject(CSSM_ACL_SUBJECT_TYPE_KEYCHAIN_PROMPT, CSSM_SAMPLE_TYPE_KEYCHAIN_PROMPT), + : SimpleAclSubject(CSSM_ACL_SUBJECT_TYPE_KEYCHAIN_PROMPT), selector(sel), description(descr) { // check selector version diff --git a/src/acl_keychain.h b/src/acl_keychain.h index 764b931..bbdec1a 100644 --- a/src/acl_keychain.h +++ b/src/acl_keychain.h @@ -3,8 +3,6 @@ * * @APPLE_LICENSE_HEADER_START@ * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. - * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in diff --git a/src/acls.cpp b/src/acls.cpp index 8cfd5ba..e2be78f 100644 --- a/src/acls.cpp +++ b/src/acls.cpp @@ -3,8 +3,6 @@ * * @APPLE_LICENSE_HEADER_START@ * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. - * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in @@ -25,12 +23,15 @@ // -// acls - SecurityServer ACL implementation +// acls - securityd ACL implementation // #include "acls.h" #include "connection.h" #include "server.h" -#include +#include "agentquery.h" +#include "tokendatabase.h" + +// ACL subjects whose Environments we implement #include #include #include @@ -44,27 +45,33 @@ SecurityServerAcl::~SecurityServerAcl() // -// Each SecurityServerAcl type must provide some indication of a database -// it is associated with. The default, naturally, is "none". +// The default implementation of the ACL interface simply uses the local ObjectAcl +// data. You can customize this by implementing instantiateAcl() [from ObjectAcl] +// or by overriding these methods as desired. +// Note: While you can completely ignore the ObjectAcl personality if you wish, it's +// usually smarter to adapt it. // -const Database *SecurityServerAcl::relatedDatabase() const -{ return NULL; } +void SecurityServerAcl::getOwner(AclOwnerPrototype &owner) +{ + ObjectAcl::cssmGetOwner(owner); +} +void SecurityServerAcl::getAcl(const char *tag, uint32 &count, AclEntryInfo *&acls) +{ + ObjectAcl::cssmGetAcl(tag, count, acls); +} -// -// Provide environmental information to get/change-ACL calls. -// Also make them virtual so our children can override them. -// -void SecurityServerAcl::cssmChangeAcl(const AclEdit &edit, const AccessCredentials *cred) +void SecurityServerAcl::changeAcl(const AclEdit &edit, const AccessCredentials *cred, + Database *db) { - SecurityServerEnvironment env(*this); + SecurityServerEnvironment env(*this, db); ObjectAcl::cssmChangeAcl(edit, cred, &env); } -void SecurityServerAcl::cssmChangeOwner(const AclOwnerPrototype &newOwner, - const AccessCredentials *cred) +void SecurityServerAcl::changeOwner(const AclOwnerPrototype &newOwner, + const AccessCredentials *cred, Database *db) { - SecurityServerEnvironment env(*this); + SecurityServerEnvironment env(*this, db); ObjectAcl::cssmChangeOwner(newOwner, cred, &env); } @@ -72,23 +79,42 @@ void SecurityServerAcl::cssmChangeOwner(const AclOwnerPrototype &newOwner, // // Modified validate() methods to connect all the conduits... // -void SecurityServerAcl::validate(AclAuthorization auth, const AccessCredentials *cred) +void SecurityServerAcl::validate(AclAuthorization auth, const AccessCredentials *cred, Database *db) { - SecurityServerEnvironment env(*this); + SecurityServerEnvironment env(*this, db); StLock objectSequence(aclSequence); StLock processSequence(Server::process().aclSequence); ObjectAcl::validate(auth, cred, &env); } -void SecurityServerAcl::validate(AclAuthorization auth, const Context &context) +void SecurityServerAcl::validate(AclAuthorization auth, const Context &context, Database *db) { validate(auth, - context.get(CSSM_ATTRIBUTE_ACCESS_CREDENTIALS)); + context.get(CSSM_ATTRIBUTE_ACCESS_CREDENTIALS), db); } // -// Implement our environment object +// External storage interface +// +Adornable &SecurityServerEnvironment::store(const AclSubject *subject) +{ + switch (subject->type()) { + case CSSM_ACL_SUBJECT_TYPE_PREAUTH: + { + if (TokenDatabase *tokenDb = dynamic_cast(database)) + return tokenDb->common().store(); + } + break; + default: + break; + } + CssmError::throwMe(CSSM_ERRCODE_ACL_SUBJECT_TYPE_NOT_SUPPORTED); +} + + +// +// ProcessAclSubject personality: uid/gid/pid come from the active Process object // uid_t SecurityServerEnvironment::getuid() const { @@ -105,8 +131,67 @@ pid_t SecurityServerEnvironment::getpid() const return Server::process().pid(); } + +// +// CodeSignatureAclSubject personality: take code signature from active Process object +// bool SecurityServerEnvironment::verifyCodeSignature(const CodeSigning::Signature *signature, const CssmData *comment) { return Server::codeSignatures().verify(Server::process(), signature, comment); } + + +// +// PromptedAclSubject personality: Get a secret by prompting through SecurityAgent +// +bool SecurityServerEnvironment::getSecret(CssmOwnedData &secret, const CssmData &prompt) const +{ + //@@@ ignoring prompt - not used right now + if (database) { + QueryPIN query(*database); + if (!query()) { // success + secret = query.pin(); + return true; + } + } + return false; +} + + +// +// SecretAclSubject personality: externally validate a secret (passphrase etc.) +// Right now, this always goes to the (Token)Database object, because that's where +// the PIN ACL entries are. We could direct this at the ObjectAcl (database or key) +// instead and rely on tokend to perform the PIN mapping, but the generic tokend +// wrappers do not (currently) perform any ACL validation, so every tokend would have +// to re-implement that. Perhaps in the next ACL revamp cycle... +// +bool SecurityServerEnvironment::validateSecret(const SecretAclSubject *me, + const AccessCredentials *cred) +{ + return database && database->validateSecret(me, cred); +} + + +// +// PreAuthenticationAclSubject personality - refer to database (ObjectAcl) +// +ObjectAcl *SecurityServerEnvironment::preAuthSource() +{ + return database ? &database->acl() : NULL; +} + + +// +// The default AclSource denies having an ACL at all +// +SecurityServerAcl &AclSource::acl() +{ + CssmError::throwMe(CSSM_ERRCODE_OBJECT_ACL_NOT_SUPPORTED); +} + +Database *AclSource::relatedDatabase() +{ + return NULL; +} diff --git a/src/acls.h b/src/acls.h index 9ea4504..3a8453e 100644 --- a/src/acls.h +++ b/src/acls.h @@ -3,8 +3,6 @@ * * @APPLE_LICENSE_HEADER_START@ * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. - * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in @@ -25,15 +23,30 @@ // -// acls - SecurityServer ACL implementation +// acls - securityd ACL implementation +// +// These classes implement securityd's local ACL machine in terms of the generic +// ObjectAcl model. In particular, they define securityd's AclValidationEnvironment, +// which hooks the real-world state into the abstract AclSubject submachines. +// +// Note that these classes are *complete* but *extendable*. The default implementation +// uses unmodified local ObjectAcl state. Subclasses (and certain AclSubjects) may delegate +// validation to outside agents (such as a tokend) and thus act as caching forwarding agents. +// Don't assume. // #ifndef _H_ACLS #define _H_ACLS -#include "securityserver.h" +#include #include +#include #include #include +#include +#include +#include + +using namespace SecurityServer; class Connection; @@ -45,25 +58,26 @@ class Database; // class SecurityServerAcl : public ObjectAcl { public: - SecurityServerAcl(AclKind k, Allocator &alloc) : ObjectAcl(alloc), mKind(k) { } + SecurityServerAcl() : ObjectAcl(Allocator::standard()) { } virtual ~SecurityServerAcl(); - - AclKind kind() const { return mKind; } // validation calls restated - void validate(AclAuthorization auth, const AccessCredentials *cred); - void validate(AclAuthorization auth, const Context &context); + void validate(AclAuthorization auth, const AccessCredentials *cred, Database *relatedDatabase); + void validate(AclAuthorization auth, const Context &context, Database *relatedDatabase); - void cssmChangeAcl(const AclEdit &edit, const AccessCredentials *cred); - void cssmChangeOwner(const AclOwnerPrototype &newOwner, const AccessCredentials *cred); + // CSSM layer ACL calls + virtual void getOwner(AclOwnerPrototype &owner); + virtual void getAcl(const char *tag, uint32 &count, AclEntryInfo *&acls); + virtual void changeAcl(const AclEdit &edit, const AccessCredentials *cred, + Database *relatedDatabase); + virtual void changeOwner(const AclOwnerPrototype &newOwner, const AccessCredentials *cred, + Database *relatedDatabase); - virtual const Database *relatedDatabase() const; + // to be provided by implementations + virtual AclKind aclKind() const = 0; // aclSequence is taken to serialize ACL validations to pick up mutual changes Mutex aclSequence; - -private: - AclKind mKind; }; @@ -75,18 +89,54 @@ private: // class SecurityServerEnvironment : public virtual AclValidationEnvironment, public virtual ProcessAclSubject::Environment, - public virtual CodeSignatureAclSubject::Environment { + public virtual CodeSignatureAclSubject::Environment, + public virtual SecretAclSubject::Environment, + public virtual PromptedAclSubject::Environment, + public virtual PreAuthorizationAcls::Environment { public: - SecurityServerEnvironment(const SecurityServerAcl &baseAcl) - : acl(baseAcl) { } + SecurityServerEnvironment(SecurityServerAcl &baseAcl, Database *db) + : acl(baseAcl), database(db) { } - const SecurityServerAcl &acl; + SecurityServerAcl &acl; + Database * const database; - const Database *database() const { return acl.relatedDatabase(); } uid_t getuid() const; gid_t getgid() const; pid_t getpid() const; bool verifyCodeSignature(const CodeSigning::Signature *signature, const CssmData *comment); + bool validateSecret(const SecretAclSubject *me, const AccessCredentials *cred); + bool getSecret(CssmOwnedData &secret, const CssmData &prompt) const; + ObjectAcl *preAuthSource(); + Adornable &store(const AclSubject *subject); +}; + + +// +// An abstract source of a SecurityServerAcl. +// There is a default implementation, which throws OBJECT_ACL_NOT_SUPPORTED. +// +class AclSource { +protected: + AclSource() { } + +public: + virtual SecurityServerAcl &acl(); // defaults to "no ACL; throw exception" + virtual Database *relatedDatabase(); // optionally, a Database related to me + + // forward ACL calls, passing some locally obtained stuff along + + void getOwner(AclOwnerPrototype &owner) + { return acl().getOwner(owner); } + void getAcl(const char *tag, uint32 &count, AclEntryInfo *&acls) + { return acl().getAcl(tag, count, acls); } + void changeAcl(const AclEdit &edit, const AccessCredentials *cred) + { return acl().changeAcl(edit, cred, relatedDatabase()); } + void changeOwner(const AclOwnerPrototype &newOwner, const AccessCredentials *cred) + { return acl().changeOwner(newOwner, cred, relatedDatabase()); } + void validate(AclAuthorization auth, const AccessCredentials *cred) + { acl().validate(auth, cred, relatedDatabase()); } + void validate(AclAuthorization auth, const Context &context) + { acl().validate(auth, context, relatedDatabase()); } }; diff --git a/src/agentquery.cpp b/src/agentquery.cpp index cb1d4aa..c8118ef 100644 --- a/src/agentquery.cpp +++ b/src/agentquery.cpp @@ -3,8 +3,6 @@ * * @APPLE_LICENSE_HEADER_START@ * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. - * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in @@ -28,8 +26,6 @@ // #include "agentquery.h" #include "authority.h" -#include "server.h" -#include "session.h" #include #include @@ -71,44 +67,18 @@ static void getNoSA(char *buffer, size_t bufferSize, const char *fmt, ...) #endif //NOSA -// -// The default Mach service name for SecurityAgent -// -const char SecurityAgentQuery::defaultName[] = "com.apple.SecurityAgent"; - using SecurityAgent::Reason; using namespace Authorization; -// -// Construct a query object -// - -SecurityAgentQuery::SecurityAgentQuery() : - SecurityAgent::Client(Server::process().uid(), - Server::session().bootstrapPort(), - defaultName), - mClientSession(Server::session()) +SecurityAgentQuery::SecurityAgentQuery(const AuthHostType type, Session &session) : mAuthHostType(type), mHostInstance(session.authhost(mAuthHostType)), mConnection(&Server::connection()) { - secdebug("SecurityAgentQuery", "new query"); - - // XXX/cs set up the general settings for the client as hints - // any invoke will merge these and whatever the client passes on invoke - -} - -SecurityAgentQuery::SecurityAgentQuery(uid_t clientUID, - const Session &clientSession, - const char *agentName) : -SecurityAgent::Client(clientUID, clientSession.bootstrapPort(), agentName ? agentName : defaultName), - mClientSession(clientSession) -{ - secdebug("SecurityAgentQuery", "new query"); + secdebug("SecurityAgentQuery", "new SecurityAgentQuery(%p)", this); } SecurityAgentQuery::~SecurityAgentQuery() { - secdebug("SecurityAgentQuery", "query dying"); - Server::connection().useAgent(NULL); + secdebug("SecurityAgentQuery", "SecurityAgentQuery(%p) dying", this); + mConnection->useAgent(NULL); #if defined(NOSA) if (getenv("NOSA")) { @@ -117,39 +87,45 @@ SecurityAgentQuery::~SecurityAgentQuery() } #endif - if (state() != dead) + if (SecurityAgent::Client::state() != SecurityAgent::Client::dead) destroy(); } void SecurityAgentQuery::activate() { - if (isActive()) - return; - - // Before popping up an agent: is UI session allowed? - if (!(mClientSession.attributes() & sessionHasGraphicAccess)) - CssmError::throwMe(CSSM_ERRCODE_NO_USER_INTERACTION); - // this may take a while Server::active().longTermActivity(); - Server::connection().useAgent(this); + mConnection->useAgent(this); try { - SecurityAgent::Client::activate(); + SecurityAgent::Client::activate(mHostInstance->activate()); } catch (...) { - Server::connection().useAgent(NULL); // guess not + mConnection->useAgent(NULL); // guess not throw; } - - } - void SecurityAgentQuery::inferHints(Process &thisProcess) { - AuthItemSet processHints = clientHints(thisProcess.clientCode(), thisProcess.pid(), thisProcess.uid()); + RefPointer clientCode = thisProcess.clientCode(); + SecurityAgent::RequestorType requestorType = SecurityAgent::unknown; + string bundlePath; + + if (clientCode) + { + string encodedBundle = clientCode->encode(); + char bundleType = (encodedBundle.c_str())[0]; // yay, no accessor + switch(bundleType) + { + case 'b': requestorType = SecurityAgent::bundle; break; + case 't': requestorType = SecurityAgent::tool; break; + } + bundlePath = clientCode->canonicalPath(); + } + + AuthItemSet processHints = clientHints(requestorType, bundlePath, thisProcess.pid(), thisProcess.uid()); mClientHints.insert(processHints.begin(), processHints.end()); } @@ -159,7 +135,7 @@ SecurityAgentQuery::readChoice() allow = false; remember = false; - AuthItem *allowAction = mContext.find(AGENT_CONTEXT_ALLOW); + AuthItem *allowAction = outContext().find(AGENT_CONTEXT_ALLOW); if (allowAction) { string allowString; @@ -168,7 +144,7 @@ SecurityAgentQuery::readChoice() allow = true; } - AuthItem *rememberAction = mContext.find(AGENT_CONTEXT_REMEMBER_ACTION); + AuthItem *rememberAction = outContext().find(AGENT_CONTEXT_REMEMBER_ACTION); if (rememberAction) { string rememberString; @@ -181,15 +157,29 @@ SecurityAgentQuery::readChoice() void SecurityAgentQuery::terminate() { - if (!isActive()) - activate(); + activate(); // @@@ This happens already in the destructor; presumably we do this to tear things down orderly - Server::connection(true).useAgent(NULL); + mConnection->useAgent(NULL); SecurityAgent::Client::terminate(); } +void +SecurityAgentQuery::create(const char *pluginId, const char *mechanismId, const SessionId inSessionId) +{ + activate(); + OSStatus status = SecurityAgent::Client::create(pluginId, mechanismId, inSessionId); + if (status) + { + secdebug("SecurityAgentQuery", "agent went walkabout, restarting"); + Session &session = mHostInstance->session(); + mHostInstance = session.authhost(mAuthHostType, true); + activate(); + status = SecurityAgent::Client::create(pluginId, mechanismId, inSessionId); + } + if (status) MacOSError::throwMe(status); +} // // Perform the "rogue app" access query dialog @@ -236,8 +226,6 @@ Reason QueryKeychainUse::queryUser (const char *database, const char *descriptio } #endif - activate(); - // prepopulate with client hints hints.insert(mClientHints.begin(), mClientHints.end()); @@ -254,7 +242,7 @@ Reason QueryKeychainUse::queryUser (const char *database, const char *descriptio if (mPassphraseCheck) { - status = create("builtin", "confirm-access-password", NULL); + create("builtin", "confirm-access-password", NULL); CssmAutoData data(Allocator::standard(Allocator::sensitive)); @@ -272,7 +260,8 @@ Reason QueryKeychainUse::queryUser (const char *database, const char *descriptio AuthItemRef retryHint(AGENT_HINT_RETRY_REASON, AuthValueOverlay(sizeof(reason), &reason)); hints.erase(retryHint); hints.insert(retryHint); // replace - status = invoke(arguments, hints, context); + setInput(hints, context); + status = invoke(); if (retryCount > kMaximumAuthorizationTries) { @@ -281,7 +270,7 @@ Reason QueryKeychainUse::queryUser (const char *database, const char *descriptio checkResult(); - AuthItem *passwordItem = mContext.find(kAuthorizationEnvironmentPassword); + AuthItem *passwordItem = outContext().find(kAuthorizationEnvironmentPassword); if (!passwordItem) continue; @@ -292,7 +281,8 @@ Reason QueryKeychainUse::queryUser (const char *database, const char *descriptio else { create("builtin", "confirm-access", NULL); - invoke(arguments, hints, context); + setInput(hints, context); + invoke(); } readChoice(); @@ -332,9 +322,10 @@ bool QueryCodeCheck::operator () (const char *aclPath) hints.insert(AuthItemRef(AGENT_HINT_APPLICATION_PATH, AuthValueOverlay(strlen(aclPath), const_cast(aclPath)))); - MacOSError::check(create("builtin", "code-identity", NULL)); + create("builtin", "code-identity", NULL); - status = invoke(arguments, hints, context); + setInput(hints, context); + status = invoke(); checkResult(); @@ -349,7 +340,7 @@ bool QueryCodeCheck::operator () (const char *aclPath) // or we can't get another passphrase. Accept() should consume the passphrase // if it is accepted. If no passphrase is acceptable, throw out of here. // -Reason QueryUnlock::query() +Reason QueryOld::query() { Reason reason = SecurityAgent::noReason; OSStatus status; @@ -367,8 +358,6 @@ Reason QueryUnlock::query() return database.decode(passphrase) ? SecurityAgent::noReason : SecurityAgent::invalidPassphrase; } #endif - activate(); - // prepopulate with client hints @@ -377,7 +366,7 @@ Reason QueryUnlock::query() hints.insert(mClientHints.begin(), mClientHints.end()); - MacOSError::check(create("builtin", "unlock-keychain", NULL)); + create("builtin", "unlock-keychain", NULL); do { @@ -394,7 +383,8 @@ Reason QueryUnlock::query() AuthItemRef retryHint(AGENT_HINT_RETRY_REASON, AuthValueOverlay(sizeof(reason), &reason)); hints.erase(retryHint); hints.insert(retryHint); // replace - status = invoke(arguments, hints, context); + setInput(hints, context); + status = invoke(); if (retryCount > maxTries) { @@ -403,13 +393,14 @@ Reason QueryUnlock::query() checkResult(); - AuthItem *passwordItem = mContext.find(kAuthorizationEnvironmentPassword); + AuthItem *passwordItem = outContext().find(kAuthorizationEnvironmentPassword); if (!passwordItem) continue; passwordItem->getCssmData(passphrase); + } - while (reason = database.decode(passphrase) ? SecurityAgent::noReason : SecurityAgent::invalidPassphrase); + while (reason = accept(passphrase)); return SecurityAgent::noReason; } @@ -418,12 +409,39 @@ Reason QueryUnlock::query() // // Get existing passphrase (unlock) Query // -Reason QueryUnlock::operator () () +Reason QueryOld::operator () () { return query(); } +// +// End-classes for old secrets +// +Reason QueryUnlock::accept(CssmManagedData &passphrase) +{ + if (safer_cast(database).decode(passphrase)) + return SecurityAgent::noReason; + else + return SecurityAgent::invalidPassphrase; +} + + +QueryPIN::QueryPIN(Database &db) + : QueryOld(db), mPin(Allocator::standard()) +{ + this->inferHints(Server::process()); +} + + +Reason QueryPIN::accept(CssmManagedData &pin) +{ + // no retries for now + mPin = pin; + return SecurityAgent::noReason; +} + + // // Obtain passphrases and submit them to the accept() method until it is accepted // or we can't get another passphrase. Accept() should consume the passphrase @@ -451,8 +469,6 @@ Reason QueryNewPassphrase::query() } #endif - activate(); - // prepopulate with client hints hints.insert(mClientHints.begin(), mClientHints.end()); @@ -462,10 +478,10 @@ Reason QueryNewPassphrase::query() switch (initialReason) { case SecurityAgent::newDatabase: - MacOSError::check(create("builtin", "new-passphrase", NULL)); + create("builtin", "new-passphrase", NULL); break; case SecurityAgent::changePassphrase: - MacOSError::check(create("builtin", "change-passphrase", NULL)); + create("builtin", "change-passphrase", NULL); break; default: assert(false); @@ -484,7 +500,8 @@ Reason QueryNewPassphrase::query() AuthItemRef retryHint(AGENT_HINT_RETRY_REASON, AuthValueOverlay(sizeof(reason), &reason)); hints.erase(retryHint); hints.insert(retryHint); // replace - status = invoke(arguments, hints, context); + setInput(hints, context); + status = invoke(); if (retryCount > maxTries) { @@ -495,19 +512,19 @@ Reason QueryNewPassphrase::query() if (SecurityAgent::changePassphrase == initialReason) { - AuthItem *oldPasswordItem = mContext.find(AGENT_PASSWORD); + AuthItem *oldPasswordItem = outContext().find(AGENT_PASSWORD); if (!oldPasswordItem) continue; oldPasswordItem->getCssmData(oldPassphrase); } - AuthItem *passwordItem = mContext.find(AGENT_CONTEXT_NEW_PASSWORD); + AuthItem *passwordItem = outContext().find(AGENT_CONTEXT_NEW_PASSWORD); if (!passwordItem) continue; passwordItem->getCssmData(passphrase); - + } while (reason = accept(passphrase, (initialReason == SecurityAgent::changePassphrase) ? &oldPassphrase.get() : NULL)); @@ -532,7 +549,7 @@ Reason QueryNewPassphrase::accept(CssmManagedData &passphrase, CssmData *oldPass //@@@ This validation presumes ASCII - UTF8 might be more lenient // if we have an old passphrase, check it - if (oldPassphrase && !database.validatePassphrase(*oldPassphrase)) + if (oldPassphrase && !safer_cast(database).validatePassphrase(*oldPassphrase)) return SecurityAgent::oldPassphraseWrong; // sanity check the new passphrase (but allow user override) @@ -573,8 +590,6 @@ Reason QueryGenericPassphrase::query(const char *prompt, bool verify, } #endif - activate(); - hints.insert(mClientHints.begin(), mClientHints.end()); hints.insert(AuthItemRef(AGENT_HINT_CUSTOM_PROMPT, AuthValueOverlay(prompt ? strlen(prompt) : 0, const_cast(prompt)))); // XXX/gh defined by dmitch but no analogous hint in @@ -582,20 +597,20 @@ Reason QueryGenericPassphrase::query(const char *prompt, bool verify, // CSSM_ATTRIBUTE_ALERT_TITLE (optional alert panel title) if (false == verify) { // import - MacOSError::check(create("builtin", "generic-unlock", NULL)); + create("builtin", "generic-unlock", NULL); } else { // verify passphrase (export) // new-passphrase-generic works with the pre-4 June 2004 agent; // generic-new-passphrase is required for the new agent - MacOSError::check(create("builtin", "generic-new-passphrase", NULL)); + create("builtin", "generic-new-passphrase", NULL); } AuthItem *passwordItem; do { - - status = invoke(arguments, hints, context); + setInput(hints, context); + status = invoke(); checkResult(); - passwordItem = mContext.find(AGENT_PASSWORD); + passwordItem = outContext().find(AGENT_PASSWORD); } while (!passwordItem); @@ -605,20 +620,93 @@ Reason QueryGenericPassphrase::query(const char *prompt, bool verify, } -QueryInvokeMechanism::QueryInvokeMechanism() : - SecurityAgentQuery() { } +// +// Get a DB blob's passphrase--keychain synchronization +// -QueryInvokeMechanism::QueryInvokeMechanism(uid_t clientUID, const Session &session, const char *agentName) : - SecurityAgentQuery(clientUID, session, agentName) +void QueryDBBlobSecret::addHint(const char *name, const void *value, UInt32 valueLen, UInt32 flags) { + AuthorizationItem item = { name, valueLen, const_cast(value), flags }; + mClientHints.insert(AuthItemRef(item)); +} + +Reason QueryDBBlobSecret::operator () (DatabaseCryptoCore &dbCore, const DbBlob *secretsBlob) +{ + return query(dbCore, secretsBlob); +} + +Reason QueryDBBlobSecret::query(DatabaseCryptoCore &dbCore, const DbBlob *secretsBlob) +{ + Reason reason = SecurityAgent::noReason; + CssmAutoData passphrase(Allocator::standard(Allocator::sensitive)); + OSStatus status; // not really used; remove? + AuthValueVector arguments; + AuthItemSet hints/*NUKEME*/, context; + +#if defined(NOSA) + if (getenv("NOSA")) { + // FIXME akin to 3690984 + return SecurityAgent::noReason; + } +#endif + + hints.insert(mClientHints.begin(), mClientHints.end()); + + create("builtin", "generic-unlock-kcblob", NULL); + + AuthItem *secretItem; + + int retryCount = 0; + + do { + AuthItemRef triesHint(AGENT_HINT_TRIES, AuthValueOverlay(sizeof(retryCount), &retryCount)); + hints.erase(triesHint); hints.insert(triesHint); // replace + + if (++retryCount > maxTries) + { + reason = SecurityAgent::tooManyTries; + } + + AuthItemRef retryHint(AGENT_HINT_RETRY_REASON, AuthValueOverlay(sizeof(reason), &reason)); + hints.erase(retryHint); hints.insert(retryHint); // replace + + setInput(hints, context); + status = invoke(); + checkResult(); + secretItem = outContext().find(AGENT_PASSWORD); + if (!secretItem) + continue; + secretItem->getCssmData(passphrase); + + } while (reason = accept(passphrase, dbCore, secretsBlob)); + + return reason; } -void QueryInvokeMechanism::initialize(const string &inPluginId, const string &inMechanismId, const SessionId inSessionId) +Reason QueryDBBlobSecret::accept(CssmManagedData &passphrase, + DatabaseCryptoCore &dbCore, + const DbBlob *secretsBlob) { - activate(); + try { + dbCore.setup(secretsBlob, passphrase); + dbCore.decodeCore(secretsBlob, NULL); + } catch (const CommonError &err) { + // XXX/gh Are there errors other than this? + return SecurityAgent::invalidPassphrase; + } + return SecurityAgent::noReason; +} + +QueryInvokeMechanism::QueryInvokeMechanism(const AuthHostType type, Session &session) : + SecurityAgentQuery(type, session) { } - if (init == state()) - MacOSError::check(create(inPluginId.c_str(), inMechanismId.c_str(), inSessionId)); +void QueryInvokeMechanism::initialize(const string &inPluginId, const string &inMechanismId, const AuthValueVector &inArguments, const SessionId inSessionId) +{ + if (SecurityAgent::Client::init == SecurityAgent::Client::state()) + { + create(inPluginId.c_str(), inMechanismId.c_str(), inSessionId); + mArguments = inArguments; + } } // XXX/cs should return AuthorizationResult @@ -627,16 +715,17 @@ void QueryInvokeMechanism::run(const AuthValueVector &inArguments, AuthItemSet & // prepopulate with client hints inHints.insert(mClientHints.begin(), mClientHints.end()); - MacOSError::check(invoke(inArguments, inHints, inContext)); + setArguments(inArguments); + setInput(inHints, inContext); + MacOSError::check(invoke()); if (outResult) *outResult = result(); - inHints = hints(); - inContext = context(); + inHints = outHints(); + inContext = outContext(); } void QueryInvokeMechanism::terminateAgent() { terminate(); } - diff --git a/src/agentquery.h b/src/agentquery.h index 16a34ad..63d244d 100644 --- a/src/agentquery.h +++ b/src/agentquery.h @@ -3,8 +3,6 @@ * * @APPLE_LICENSE_HEADER_START@ * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. - * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in @@ -30,29 +28,24 @@ #ifndef _H_AGENTQUERY #define _H_AGENTQUERY -#include "securityserver.h" #include #include #include #include "kcdatabase.h" #include "AuthorizationEngine.h" +#include "authhost.h" +#include "server.h" +#include "session.h" using Authorization::AuthItemSet; using Authorization::AuthValueVector; -using Security::CodeSigning::OSXCode; -// -// The common machinery of retryable SecurityAgent queries -// -class Session; +using Security::OSXCode; -class SecurityAgentQuery : protected SecurityAgent::Client { +class SecurityAgentQuery : public SecurityAgent::Client { public: typedef SecurityAgent::Reason Reason; - static const char defaultName[]; - - SecurityAgentQuery(); - SecurityAgentQuery(uid_t clientUID, const Session &clientSession, const char *agentName = defaultName); + SecurityAgentQuery(const AuthHostType type = securityAgent, Session &session = Server::session()); void inferHints(Process &thisProcess); @@ -60,17 +53,21 @@ public: virtual void activate(); virtual void terminate(); + void create(const char *pluginId, const char *mechanismId, const SessionId inSessionId); public: void readChoice(); bool allow; bool remember; + AuthHostType mAuthHostType; + RefPointer mHostInstance; protected: AuthItemSet mClientHints; private: - const Session &mClientSession; + Port mPort; + const RefPointer mConnection; }; // @@ -98,41 +95,66 @@ public: // // A query for an existing passphrase // -class QueryUnlock : public SecurityAgentQuery { +class QueryOld : public SecurityAgentQuery { static const int maxTries = kMaximumAuthorizationTries; public: - QueryUnlock(KeychainDatabase &db) : database(db) { } + QueryOld(Database &db) : database(db) { } - KeychainDatabase &database; + Database &database; Reason operator () (); protected: Reason query(); - void queryInteractive(CssmOwnedData &passphrase); - void retryInteractive(CssmOwnedData &passphrase, Reason reason); + virtual Reason accept(CssmManagedData &) = 0; +}; + + +class QueryUnlock : public QueryOld { +public: + QueryUnlock(KeychainDatabase &db) : QueryOld(db) { } + +protected: Reason accept(CssmManagedData &passphrase); }; +// +// Repurpose QueryUnlock for PIN prompting +// Not very clean - but this stuff is an outdated hack as it is... +// +class QueryPIN : public QueryOld { +public: + QueryPIN(Database &db); + + const CssmData &pin() const { return mPin; } + +protected: + Reason accept(CssmManagedData &pin); + +private: + CssmAutoData mPin; // PIN obtained +}; + + // // A query for a new passphrase // class QueryNewPassphrase : public SecurityAgentQuery { static const int maxTries = 7; public: - QueryNewPassphrase(KeychainDatabase &db, Reason reason) : + QueryNewPassphrase(Database &db, Reason reason) : database(db), initialReason(reason), mPassphrase(Allocator::standard(Allocator::sensitive)), mPassphraseValid(false) { } - KeychainDatabase &database; + Database &database; Reason operator () (CssmOwnedData &passphrase); protected: Reason query(); - Reason accept(CssmManagedData &passphrase, CssmData *oldPassphrase); + virtual Reason accept(CssmManagedData &passphrase, CssmData *oldPassphrase); private: Reason initialReason; @@ -155,16 +177,33 @@ protected: }; -class QueryInvokeMechanism : public RefCount, SecurityAgentQuery { +// +// Generic secret query (not associated with a database) +// +class QueryDBBlobSecret : public SecurityAgentQuery { + static const int maxTries = kMaximumAuthorizationTries; public: - QueryInvokeMechanism(); - QueryInvokeMechanism(uid_t clientUID, const Session &session, const char *agentName = NULL); - void initialize(const string &inPluginId, const string &inMechanismId, const SessionId inSessionId = 0); + QueryDBBlobSecret() { } + Reason operator () (DatabaseCryptoCore &dbCore, const DbBlob *secretsBlob); + + void addHint(const char *name, const void *value = NULL, UInt32 valueLen = 0, UInt32 flags = 0); + +protected: + Reason query(DatabaseCryptoCore &dbCore, const DbBlob *secretsBlob); + Reason accept(CssmManagedData &passphrase, DatabaseCryptoCore &dbCore, const DbBlob *secretsBlob); +}; + +class QueryInvokeMechanism : public SecurityAgentQuery, public RefCount { +public: + QueryInvokeMechanism(const AuthHostType type, Session &session); + void initialize(const string &inPluginId, const string &inMechanismId, const AuthValueVector &arguments, const SessionId inSessionId = 0); void run(const AuthValueVector &inArguments, AuthItemSet &inHints, AuthItemSet &inContext, AuthorizationResult *outResult); bool operator () (const string &inPluginId, const string &inMechanismId, const Authorization::AuthValueVector &inArguments, AuthItemSet &inHints, AuthItemSet &inContext, AuthorizationResult *outResult); void terminateAgent(); //~QueryInvokeMechanism(); + + AuthValueVector mArguments; }; #endif //_H_AGENTQUERY diff --git a/src/authhost.cpp b/src/authhost.cpp new file mode 100644 index 0000000..a35edf1 --- /dev/null +++ b/src/authhost.cpp @@ -0,0 +1,175 @@ +/* + * Copyright (c) 2000-2004 Apple Computer, Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +#include +#include +#include "authhost.h" +#include "server.h" + +#include +#include + + +AuthHostInstance::AuthHostInstance(Session &session, AuthHostType host) : + mHostType(host) +{ + secdebug("authhost", "authhost born (%p)", this); + referent(session); + session.addReference(*this); +} + +AuthHostInstance::~AuthHostInstance() +{ + secdebug("authhost", "authhost died (%p)", this); + + // clean up + servicePort ().destroy (); +} + +Session &AuthHostInstance::session() const +{ + return referent(); +} + +void +AuthHostInstance::childAction() +{ + // Setup the environment for the SecurityAgent + unsetenv("USER"); + unsetenv("LOGNAME"); + unsetenv("HOME"); + + // close down any files that might have been open at this point + int maxDescriptors = getdtablesize (); + int i; + + int devnull = open(_PATH_DEVNULL, O_RDWR, 0); + if (devnull >= 0) for (i = 0; i < 3; ++i) + { + dup2(devnull, i); + } + + for (i = 3; i < maxDescriptors; ++i) + { + close (i); + } + + // construct path to SecurityAgent + char agentExecutable[PATH_MAX + 1]; + const char *path = getenv("SECURITYAGENT"); + if (!path) + path = "/System/Library/CoreServices/SecurityAgent.app"; + + if ((mHostType == userAuthHost) || (mHostType == privilegedAuthHost)) + { + snprintf(agentExecutable, sizeof(agentExecutable), "%s/Contents/Resources/authorizationhost", path); + + secdebug("AuthHostInstance", "execl(%s)", agentExecutable); + execl(agentExecutable, agentExecutable, NULL); + } + else + { + snprintf(agentExecutable, sizeof(agentExecutable), "%s/Contents/MacOS/SecurityAgent", path); + + struct group *agentGroup = getgrnam("securityagent"); + gid_t agentGID = static_cast(-2); + if (agentGroup) + { + agentGID = agentGroup->gr_gid; + endgrent(); + } + + struct passwd *agentUser = getpwnam("securityagent"); + uid_t agentUID = static_cast(-2); + if (agentUser) + { + agentUID = agentUser->pw_uid; + endpwent(); + } + + setuid(agentUID); + setgid(agentGID); + + CFRef userPrefs(session().copyUserPrefs()); + + FILE *mbox = tmpfile(); + + if (userPrefs && mbox) + { + if (fwrite(CFDataGetBytePtr(userPrefs), CFDataGetLength(userPrefs), 1, mbox) != 1) + fclose(mbox); + else + { + char mboxFdString[20]; + fflush(mbox); + if ((int)sizeof(mboxFdString) > snprintf(mboxFdString, sizeof(mboxFdString), "%d", fileno(mbox))) + setenv("SECURITYAGENT_USERPREFS_FD", mboxFdString, 1); + } + } + + secdebug("AuthHostInstance", "execl(%s) as user (%d,%d)", agentExecutable, agentUID, agentGID); + execl(agentExecutable, agentExecutable, NULL); + } + + secdebug("AuthHostInstance", "execl failed, errno=%d", errno); + // Unconditional suicide follows. + // See comments below on why we can't use abort() +#if 1 + _exit(1); +#else + // NOTE: OS X abort() is implemented as kill(getuid()), which fails + // for a setuid-root process that has setuid'd. Go back to root to die... + setuid(0); + abort(); +#endif +} + +Port +AuthHostInstance::activate() +{ + StLock _(*this); + if (state() != alive) + { + if (!(session().attributes() & sessionHasGraphicAccess)) + CssmError::throwMe(CSSM_ERRCODE_NO_USER_INTERACTION); + + Security::MachPlusPlus::StBootstrap bootSaver(session().bootstrapPort()); + + fork(); + switch (ServerChild::state()) { + case Child::alive: + secdebug("AuthHostInstance", "%p (pid %d) has launched", this, pid()); + break; + case Child::dead: + secdebug("AuthHostInstance", "%p (pid %d) failed on startup", this, pid()); + break; + default: + assert(false); + } + } + + if (!ready()) + CssmError::throwMe(CSSM_ERRCODE_NO_USER_INTERACTION); + + return servicePort(); +} diff --git a/src/yarrowMigTypes.h b/src/authhost.h similarity index 60% rename from src/yarrowMigTypes.h rename to src/authhost.h index cd8871c..5ec87e4 100644 --- a/src/yarrowMigTypes.h +++ b/src/authhost.h @@ -1,10 +1,8 @@ /* - * Copyright (c) 2000-2001,2004 Apple Computer, Inc. All Rights Reserved. + * Copyright (c) 2004 Apple Computer, Inc. All Rights Reserved. * * @APPLE_LICENSE_HEADER_START@ * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. - * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in @@ -22,27 +20,33 @@ * * @APPLE_LICENSE_HEADER_END@ */ +#ifndef _H_AUTHHOST +#define _H_AUTHHOST +#include "structure.h" +#include "child.h" -// -// yarrowMigTypes.h - type equivalence declarations for Yarrow's MIG -// interface -// -#include - -// @@@ who forgot that one? -extern "C" kern_return_t mig_deallocate(vm_address_t addr, vm_size_t size); +class Session; -namespace Security -{ +typedef enum { + privilegedAuthHost, + securityAgent, + userAuthHost +} AuthHostType; -typedef void *Data; +class AuthHostInstance : public PerSession, public ServerChild { +public: + AuthHostInstance(Session &session, AuthHostType host); + virtual ~AuthHostInstance(); -// -// The server's bootstrap name -// -#define YARROW_SERVER_NAME "YarrowServer" + Session &session() const; + Port activate(); + +protected: + void childAction(); -} // end namespace Security +private: + AuthHostType mHostType; +}; -using namespace Security; +#endif /* _H_AUTHHOST */ diff --git a/src/authority.cpp b/src/authority.cpp index f9b0f3e..8e328cb 100644 --- a/src/authority.cpp +++ b/src/authority.cpp @@ -3,8 +3,6 @@ * * @APPLE_LICENSE_HEADER_START@ * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. - * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in @@ -35,6 +33,8 @@ #include +#include // AuditToken + using Authorization::AuthItemSet; using Authorization::AuthItemRef; using Authorization::AuthValue; @@ -43,7 +43,9 @@ using Authorization::AuthValueOverlay; // // The global dictionary of extant AuthorizationTokens // -AuthorizationToken::AuthMap AuthorizationToken::authMap; // set of extant authorizations +//AuthorizationToken::AuthMap AuthorizationToken::authMap; // set of extant authorizations +//@@@ Workaround ONLY! Don't destruct this map on termination +AuthorizationToken::AuthMap &AuthorizationToken::authMap = *new AuthMap; // set of extant authorizations Mutex AuthorizationToken::authMapLock; // lock for mAuthorizations (only) @@ -51,12 +53,16 @@ Mutex AuthorizationToken::authMapLock; // lock for mAuthorizations (only) // // Create an authorization token. // -AuthorizationToken::AuthorizationToken(Session &ssn, const CredentialSet &base, const security_token_t &securityToken) +AuthorizationToken::AuthorizationToken(Session &ssn, const CredentialSet &base, +const audit_token_t &auditToken) : mBaseCreds(base), mTransferCount(INT_MAX), - mCreatorUid(securityToken.val[0]), mCreatorCode(Server::process().clientCode()), - mCreatorPid(Server::process().pid()) + mCreatorPid(Server::process().pid()), + mCreatorAuditToken(auditToken) { + mCreatorUid = mCreatorAuditToken.euid(); + mCreatorGid = mCreatorAuditToken.egid(); + // link to session referent(ssn); @@ -262,3 +268,17 @@ AuthorizationToken::clearInfoSet() setInfoSet(dstInfoSet); } +void +AuthorizationToken::scrubInfoSet() +{ + AuthItemSet srcInfoSet = infoSet(), dstInfoSet; + AuthItemSet::const_iterator end = srcInfoSet.end(); + for (AuthItemSet::const_iterator it = srcInfoSet.begin(); it != end; ++it) + { + const AuthItemRef &item = *it; + if (item->flags() == kAuthorizationContextFlagExtractable) + dstInfoSet.insert(item); + } + secdebug("SSauth", "Authorization %p scrubbing context", this); + setInfoSet(dstInfoSet); +} diff --git a/src/authority.h b/src/authority.h index 4b2200c..7c70d98 100644 --- a/src/authority.h +++ b/src/authority.h @@ -3,8 +3,6 @@ * * @APPLE_LICENSE_HEADER_START@ * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. - * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in @@ -30,21 +28,22 @@ #ifndef _H_AUTHORITY #define _H_AUTHORITY -#include "securityserver.h" #include -#include +#include +#include #include "database.h" using Authorization::Credential; using Authorization::CredentialSet; using Authorization::AuthItemSet; +using Security::CommonCriteria::AuditToken; class Process; class Session; class AuthorizationToken : public PerSession { public: - AuthorizationToken(Session &ssn, const CredentialSet &base, const security_token_t &securityToken); + AuthorizationToken(Session &ssn, const CredentialSet &base, const audit_token_t &auditToken); ~AuthorizationToken(); Session &session() const; @@ -69,13 +68,17 @@ public: bool mayInternalize(Process &proc, bool countIt = true); uid_t creatorUid() const { return mCreatorUid; } - CodeSigning::OSXCode *creatorCode() const { return mCreatorCode; } + gid_t creatorGid() const { return mCreatorGid; } + OSXCode *creatorCode() const { return mCreatorCode; } pid_t creatorPid() const { return mCreatorPid; } + const AuditToken &creatorAuditToken() const { return mCreatorAuditToken; } + AuthItemSet infoSet(AuthorizationString tag = NULL); void setInfoSet(AuthItemSet &newInfoSet); void setCredentialInfo(const Credential &inCred); void clearInfoSet(); + void scrubInfoSet(); public: static AuthorizationToken &find(const AuthorizationBlob &blob); @@ -102,15 +105,18 @@ private: typedef set ProcessSet; ProcessSet mUsingProcesses; // set of process objects using this token - uid_t mCreatorUid; // Uid of proccess that created this authorization - RefPointer mCreatorCode; // code id of creator + uid_t mCreatorUid; // Uid of process that created this authorization + gid_t mCreatorGid; // Gid of process that created this authorization + RefPointer mCreatorCode; // code id of creator pid_t mCreatorPid; // Pid of processs that created this authorization + + AuditToken mCreatorAuditToken; // Audit token of the process that created this authorization AuthItemSet mInfoSet; // Side band info gathered from evaluations in this session private: typedef map > AuthMap; - static AuthMap authMap; // set of extant authorizations + static AuthMap &authMap; // set of extant authorizations static Mutex authMapLock; // lock for mAuthorizations (only) }; diff --git a/src/child.cpp b/src/child.cpp index 27b9deb..2a5db79 100644 --- a/src/child.cpp +++ b/src/child.cpp @@ -3,8 +3,6 @@ * * @APPLE_LICENSE_HEADER_START@ * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. - * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in @@ -28,330 +26,104 @@ // child - track a single child process and its belongings // #include "child.h" -#include #include -#include - -kern_return_t -ucsp_server_handleSignal(mach_port_t sport, - mach_port_t task_port, - int signal_number) -{ - try { - if (task_port != mach_task_self()) { - Syslog::error("handleSignal: recieved from someone other than myself"); - } else { - ChildManager::childManager.handleSignal(signal_number); - } - } catch(...) {} - mach_port_deallocate(mach_task_self(), task_port); - - return 0; -} - -kern_return_t -ucsp_server_registerChild(mach_port_t sport, - mach_port_t rport, - mach_port_t task_port) -{ - mach_port_t childPort = rport; - try { - pid_t pid; - kern_return_t kt = pid_for_task(task_port, &pid); - if (kt) { - Syslog::error("registerChild: pid_for_task returned: %d", kt); - } else { - ChildManager::childManager.registerChild(pid, childPort); - } - } catch(...) {} - - if (childPort) { - // Dealloc the childPort unless registerChild set it to zero, which indicates it took over ownership. - mach_port_deallocate(mach_task_self(), childPort); - } - - if (task_port) - mach_port_deallocate(mach_task_self(), task_port); - - return 0; -} // -// A Child object represents a UNIX process that was forked by us -// and may have some state associated with it. -// Although some children may be created per session (such as SecurityAgent instances) -// in general child processes are PerGlobal. +// We use a static Mutex to coordinate checkin // -class Child -{ -public: - Child(pid_t pid); - ~Child(); - - void waitStatus(int status); - int waitStatus() const { return mStatus; } - - void childPort(mach_port_t &childPort); - - // Return our childPort and transfer ownership of it. - mach_port_t childPort() { mach_port_t childPort = mChildPort; mChildPort = 0; return childPort; } - - void eraseFromMap(); - void insertInMap(); - - // Wait for the child to register or die. If it registered mChildPort will be non zero, it will be 0 if it didn't. - void waitForRegister(); - -private: - Mutex mLockInternal; - StLock mLock; - pid_t mPid; - - // Service port for this child. - // This should only be nonzero while this object owns the port. Once it is retrieved ownership is handed off. - mach_port_t mChildPort; - - int mStatus; // Exit status if child died. - bool mInMap; -}; - +Mutex ServerChild::mCheckinLock; // -// Construct a Child object. +// Make and break ServerChildren // -Child::Child(pid_t pid) : - mLock(mLockInternal), mPid(pid), mChildPort(0), mStatus(0), mInMap(false) +ServerChild::ServerChild() + : mCheckinCond(mCheckinLock) { } -Child::~Child() -{ - try { - eraseFromMap(); - if (mChildPort) { - // Dealloc our mChildPort someone else took over ownership. - mach_port_deallocate(mach_task_self(), mChildPort); - } - } catch (...) {} -} - -void -Child::eraseFromMap() -{ - if (mInMap) - ChildManager::childManager.eraseChild(mPid); -} - -void -Child::insertInMap() -{ - ChildManager::childManager.insertChild(mPid, this); - mInMap = true; -} - -void -Child::waitStatus(int status) -{ - mStatus = status; - mLock.unlock(); // Unlock the lock to unblock waitForRegister() -} - -void -Child::childPort(mach_port_t &childPort) -{ - mChildPort = childPort; - childPort = 0; // Tell our caller that we consumed the child port. - - mLock.unlock(); // Unlock the lock to unblock waitForRegister() -} - -void -Child::waitForRegister() -{ - // Try to lock the lock again (this won't succeed until we get a register or wait result). - mLock.lock(); - // Unlock as soon as we get the lock. - mLock.unlock(); -} - // -// ChildManager - Singleton Child Manager class +// If the ServerChild is destroyed, kill its process, nice or hard. // - -// The signleton ChildManager. -ChildManager ChildManager::childManager; - -ChildManager::ChildManager() -{ -} - -ChildManager::~ChildManager() -{ -} - -bool -ChildManager::forkChild(mach_port_t &outChildPort, int &outWaitStatus) -{ - StLock lock(mLock, false); - pid_t pid; - - /* Retry fork 10 times on failure after that just give up. */ - for (int tries = 0; tries < 10; ++tries) - { - lock.lock(); // aquire the lock - pid = fork(); - if (pid != pid_t(-1)) - break; - - /* Something went wrong. */ - lock.unlock(); // Release the lock so we aren't holding it during the usleep below. - - int err = errno; - if (err == EINTR) - continue; - - if (err == EAGAIN || err == ENOMEM) - usleep(100 * tries); - else - UnixError::throwMe(err); - } - - if (pid == 0) - { - // Child - return true. - return true; - } - else - { - Child child(pid); - child.insertInMap(); // Insert child into the map. - lock.unlock(); // Unlock as soon as we are done accessing mChildMap. - - child.waitForRegister(); - - // Remove child from the map. - child.eraseFromMap(); - - // Transfer ownership of child's childPort to our caller. - outChildPort = child.childPort(); - - if (!outChildPort) - outWaitStatus = child.waitStatus(); - - // Parent - return false - return false; - } -} - -void -ChildManager::handleSignal(int signal_number) -{ - if (signal_number == SIGCHLD) - handleSigChild(); -} - -void -ChildManager::registerChild(pid_t pid, mach_port_t &childPort) -{ - StLock _(mLock); - Child *child = findChild(pid); - if (child) - child->childPort(childPort); -} - -// Assumes mLock is not locked. -void -ChildManager::eraseChild(pid_t pid) -{ - StLock _(mLock); - mChildMap.erase(pid); -} - -// Assumes mLock is already locked. -void -ChildManager::insertChild(pid_t pid, Child *child) -{ - mChildMap[pid] = child; +// In case you wonder about the tango below, it's making sure we +// get to "It's dead, Jim" with the minimum number of checkChildren() +// calls while still working correctly if this is the only thread alive. +// +//@@@ We *could* define a "soft shutdown" MIG message to send to all +//@@@ ServerChildren in this situation. +// +ServerChild::~ServerChild() +{ + if (state() == alive) { + this->kill(SIGTERM); // shoot it once + checkChildren(); // check for quick death + if (state() == alive) { + usleep(300000); // give it some grace + if (state() == alive) { // could have been reaped by another thread + checkChildren(); // check again + if (state() == alive) { // it... just... won't... die... + this->kill(SIGKILL); // take THAT! + checkChildren(); + if (state() == alive) // stuck zombie + abandon(); // leave the body behind + } + } + } + } } // -// Private functions +// Parent action during fork: wait until ready or dead, then return // - -Child * -ChildManager::findChild(pid_t pid) +void ServerChild::parentAction() { - ChildMap::iterator it = mChildMap.find(pid); - if (it == mChildMap.end()) - return NULL; + // wait for either checkin or (premature) death + secdebug("serverchild", "%p (pid %d) waiting for checkin", this, pid()); + StLock _(mCheckinLock); + while (!ready() && state() == alive) + mCheckinCond.wait(); - return it->second; + // so what happened? + if (state() == dead) { + // our child died + secdebug("serverchild", "%p (pid %d) died before checking in", this, pid()); + } else if (ready()) { + // child has checked in and is ready for service + secdebug("serverchild", "%p (pid %d) ready for service on port %d", + this, pid(), mServicePort.port()); + } else + assert(false); // how did we ever get here?! } -void -ChildManager::handleSigChild() -{ - for (int tries = 0; tries < 10; ++tries) - { - int status; - pid_t pid = waitpid(-1, &status, WNOHANG|WUNTRACED); - switch (pid) - { - case 0: - if (tries == 0) - Syslog::notice("Spurious SIGCHLD ignored"); - break; - case -1: - { - int err = errno; - if (err == ECHILD) - { - if (tries == 0) - Syslog::notice("Spurious SIGCHLD ignored"); - break; - } - - if (err != EINTR) - { - Syslog::error("waitpid after SIGCHLD failed: %s", strerror(err)); - break; - } - } - default: - if (WIFEXITED(status) || WIFSIGNALED(status)) - { - if (WIFEXITED(status)) - secdebug("child", "child with pid: %d exited: %d", pid, WEXITSTATUS(status)); - else if (WCOREDUMP(status)) - secdebug("child", "child with pid: %d terminated by signal: %d and dumped core", pid, WTERMSIG(status)); - else - secdebug("child", "child with pid: %d terminated by signal: %d", pid, WTERMSIG(status)); - - waitStatusForPid(pid, status); - } - else if (WSTOPSIG(status)) - { - secdebug("child", "child with pid: %d stopped by signal: %d", pid, WSTOPSIG(status)); - } - else - { - Syslog::error("child with pid: %d bogus waitpid status: %d", pid, status); - } - tries = 1; - } - } -} - -void -ChildManager::waitStatusForPid(pid_t pid, int status) -{ - StLock _(mLock); - Child *child = findChild(pid); - if (child) - child->waitStatus(status); +// +// Death action during fork: release the waiting creator thread, if any +// +void ServerChild::dying() +{ + secdebug("serverchild", "%p is dead; resuming parent thread (if any)", this); + mCheckinCond.signal(); +} + + +void ServerChild::checkIn(Port servicePort, pid_t pid) +{ + if (ServerChild *child = Child::find(pid)) { + // Child was alive when last seen. Store service port and signal parent thread + { + StLock _(mCheckinLock); + child->mServicePort = servicePort; + servicePort.modRefs(MACH_PORT_RIGHT_SEND, +1); // retain send right + secdebug("serverchild", "%p (pid %d) checking in; resuming parent thread", + child, pid); + } + child->mCheckinCond.signal(); + } else { + // Child has died; is wrong kind; or spurious checkin. + // If it was a proper child, death notifications will wake up the parent thread + secdebug("serverchild", "pid %d not in child set; checkin ignored", pid); + } } diff --git a/src/child.h b/src/child.h index cd9b8a5..587627a 100644 --- a/src/child.h +++ b/src/child.h @@ -3,8 +3,6 @@ * * @APPLE_LICENSE_HEADER_START@ * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. - * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in @@ -30,49 +28,49 @@ #ifndef _CHILD_H_ #define _CHILD_H_ 1 -#include "securityserver.h" +#include +#include + +using MachPlusPlus::Port; +using MachPlusPlus::TaskPort; -class Child; // -// ChildManager - Singleton Child Manager class +// ServerChild builds on the generic UNIX Child abstraction. +// The child is expected to engage in a checkin protocol after launch, +// whereby it RPC-calls childCheckIn in securityd and thus authenticates +// and declares readiness to provide service. +// +// @@@ PerWhat are these, if they are at all? // -class ChildManager -{ +class ServerChild : public UnixPlusPlus::Child { public: - // The singleton childManager. - static ChildManager childManager; - - ChildManager(); - ~ChildManager(); - - // Return true in the child. Return false in the parent and set outChildPort to 0 if the child died prematuely. In this case outWaitStatus contains the result of a waitpid() on the child. if outChildPort is non 0 it's a send right to contact the child on. - bool forkChild(mach_port_t &outChildPort, int &outWaitStatus); - - // SigChild signal handler - void handleSignal(int signal); + ServerChild(); + ~ServerChild(); + + Port servicePort() const { return mServicePort; } + bool ready() const { return mServicePort; } - // Be notified a child just contacted us on our main server port telling us it's child port. Set childPort to 0 iff we don't wish it to be deallocated by our caller. - void registerChild(pid_t pid, mach_port_t &childPort); - - // Assumes mLock is not locked (called by Child's eraseFromMap() function). - void eraseChild(pid_t pid); +public: + static void checkIn(Port servicePort, pid_t pid); - // Assumes mLock is already locked (called by Child's insertInMap() function). - void insertChild(pid_t pid, Child *child); +protected: + void childAction() = 0; // must be provided by subclass + void parentAction(); // fully implemented + void dying(); // fully implemented private: - Child *findChild(pid_t pid); - - void handleSigChild(); + Port mServicePort; // child's main service port - // Be notifed of a term or signal waitpid() status. - void waitStatusForPid(pid_t pid, int status); - - - typedef std::map ChildMap; - ChildMap mChildMap; - Mutex mLock; +private: + typedef map CheckinMap; + static CheckinMap mCheckinMap; + + // The parent side will wait on mCheckinCond until the child checks in + // or fails. During that time ONLY, mCheckinLock protects the entire Child + // object. + static Mutex mCheckinLock; + Condition mCheckinCond; }; diff --git a/src/codesigdb.cpp b/src/codesigdb.cpp index c148260..d8094fa 100644 --- a/src/codesigdb.cpp +++ b/src/codesigdb.cpp @@ -3,8 +3,6 @@ * * @APPLE_LICENSE_HEADER_START@ * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. - * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in @@ -32,6 +30,7 @@ #include "server.h" #include "agentquery.h" #include +#include // diff --git a/src/codesigdb.h b/src/codesigdb.h index 47a3173..5b38e04 100644 --- a/src/codesigdb.h +++ b/src/codesigdb.h @@ -3,8 +3,6 @@ * * @APPLE_LICENSE_HEADER_START@ * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. - * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in diff --git a/src/connection.cpp b/src/connection.cpp index d99dcc9..ba2e64c 100644 --- a/src/connection.cpp +++ b/src/connection.cpp @@ -3,8 +3,6 @@ * * @APPLE_LICENSE_HEADER_START@ * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. - * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in diff --git a/src/connection.h b/src/connection.h index 03c7dbd..72d5d80 100644 --- a/src/connection.h +++ b/src/connection.h @@ -3,8 +3,6 @@ * * @APPLE_LICENSE_HEADER_START@ * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. - * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in @@ -30,9 +28,8 @@ #ifndef _H_CONNECTION #define _H_CONNECTION -#include "securityserver.h" #include -#include +#include #include "process.h" #include "session.h" #include "key.h" @@ -46,7 +43,7 @@ class Session; // // A Connection object represents an established connection between a client -// and the SecurityServer. Note that in principle, a client process can have +// and securityd. Note that in principle, a client process can have // multiple Connections (each represented by an IPC channel), though there will // usually be only one. // diff --git a/src/database.cpp b/src/database.cpp index a7b7242..edc689d 100644 --- a/src/database.cpp +++ b/src/database.cpp @@ -3,8 +3,6 @@ * * @APPLE_LICENSE_HEADER_START@ * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. - * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in @@ -37,6 +35,8 @@ #include #include +using namespace UnixPlusPlus; + // // DbCommon basics @@ -56,7 +56,6 @@ Session &DbCommon::session() const // Database basics // Database::Database(Process &proc) - : SecurityServerAcl(dbAcl, Allocator::standard()) { referent(proc); } @@ -76,10 +75,130 @@ void DbCommon::sleepProcessing() // nothing } +void DbCommon::lockProcessing() +{ + // nothing +} + void Database::releaseKey(Key &key) { - removeReference(key); + kill(key); +} + +void Database::releaseSearch(Search &search) +{ + kill(search); +} + +void Database::releaseRecord(Record &record) +{ + kill(record); +} + +void Database::dbName(const char *name) +{ + CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED); +} + + +// +// Functions that aren't implemented at the Database level but can stay that way +// +void Database::findFirst(const CssmQuery &query, + CssmDbRecordAttributeData *inAttributes, mach_msg_type_number_t inAttributesLength, + CssmData *data, RefPointer &key, RefPointer &search, RefPointer &record, + CssmDbRecordAttributeData * &outAttributes, mach_msg_type_number_t &outAttributesLength) +{ + secdebug("database", "%p calling unimplemented findFirst", this); + CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED); +} + +void Database::findNext(Search *search, + CssmDbRecordAttributeData *inAttributes, mach_msg_type_number_t inAttributesLength, + CssmData *data, RefPointer &key, RefPointer &record, + CssmDbRecordAttributeData * &outAttributes, mach_msg_type_number_t &outAttributesLength) +{ + secdebug("database", "%p calling unimplemented findNext", this); + CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED); +} + +void Database::findRecordHandle(Record *record, + CssmDbRecordAttributeData *inAttributes, mach_msg_type_number_t inAttributesLength, + CssmData *data, RefPointer &key, + CssmDbRecordAttributeData * &outAttributes, mach_msg_type_number_t &outAttributesLength) +{ + secdebug("database", "%p calling unimplemented findRecordHandle", this); + CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED); +} + +void Database::insertRecord(CSSM_DB_RECORDTYPE recordtype, + const CssmDbRecordAttributeData *attributes, mach_msg_type_number_t inAttributesLength, + const CssmData &data, RecordHandle &record) +{ + secdebug("database", "%p calling unimplemented insertRecord", this); + CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED); +} + +void Database::modifyRecord(CSSM_DB_RECORDTYPE recordtype, Record *record, + const CssmDbRecordAttributeData *attributes, mach_msg_type_number_t inAttributesLength, + const CssmData *data, CSSM_DB_MODIFY_MODE modifyMode) +{ + secdebug("database", "%p calling unimplemented modifyRecord", this); + CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED); +} + +void Database::deleteRecord(Database::Record *record) +{ + secdebug("database", "%p calling unimplemented deleteRecord", this); + CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED); +} + +void Database::authenticate(CSSM_DB_ACCESS_TYPE, const AccessCredentials *) +{ + secdebug("database", "%p calling unimplemented authenticate", this); + CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED); +} + +SecurityServerAcl &Database::acl() +{ + secdebug("database", "%p has no ACL implementation", this); + CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED); +} + +bool Database::isLocked() const +{ + secdebug("database", "%p calling unimplemented isLocked", this); + CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED); +} + + +// +// SecurityServerAcl personality implementation. +// This is the trivial (type coding) stuff. The hard stuff is virtually mixed in. +// +Database *Database::relatedDatabase() +{ + return this; +} + +AclKind Database::aclKind() const +{ + return dbAcl; +} + +GenericHandle Database::aclHandle() const +{ + return HandleObject::handle(); +} + + +// +// Remote validation is not, by default, supported +// +bool Database::validateSecret(const AclSubject *, const AccessCredentials *) +{ + return false; } @@ -87,7 +206,7 @@ void Database::releaseKey(Key &key) // Implementation of a "system keychain unlock key store" // SystemKeychainKey::SystemKeychainKey(const char *path) - : mPath(path) + : mPath(path), mValid(false) { // explicitly set up a key header for a raw 3DES key CssmKey::Header &hdr = mKey.header(); diff --git a/src/database.h b/src/database.h index dc3c3a9..c1441cd 100644 --- a/src/database.h +++ b/src/database.h @@ -3,8 +3,6 @@ * * @APPLE_LICENSE_HEADER_START@ * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. - * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in @@ -34,7 +32,6 @@ #ifndef _H_DATABASE #define _H_DATABASE -#include "securityserver.h" #include "structure.h" #include "acls.h" #include "dbcrypto.h" @@ -69,7 +66,8 @@ public: Session &session() const; - virtual void sleepProcessing(); + virtual void sleepProcessing(); // generic action on system sleep + virtual void lockProcessing(); // generic action on "lock" requests }; @@ -78,7 +76,7 @@ public: // It maintains its protected semantic state (including keys) and provides controlled // access. // -class Database : public PerProcess, public SecurityServerAcl { +class Database : public PerProcess, public AclSource { static const NotificationEvent lockedEvent = kNotificationEventLocked; static const NotificationEvent unlockedEvent = kNotificationEventUnlocked; static const NotificationEvent passphraseChangedEvent = kNotificationEventPassphraseChanged; @@ -88,11 +86,31 @@ protected: public: Process& process() const; - - virtual void releaseKey(Key &key); - virtual CSSM_KEY_SIZE queryKeySize(Key &key) = 0; - // service calls + virtual bool transient() const = 0; // is transient store (reboot clears) + +public: + // + // A common class for objects that "belong" to a Database and + // don't have parents up the global stack. These will die along with + // the Database when it goes. + // + class Subsidiary : public PerProcess { + public: + Subsidiary(Database &db) { referent(db); } + Database &database() const { return referent(); } + Process &process() const { return database().process(); } + }; + + // + // Cryptographic service calls. + // These must be supported by any type of database. + // + virtual void releaseKey(Key &key); + virtual void queryKeySizeInBits(Key &key, CssmKeySize &result) = 0; + virtual void getOutputSize(const Context &context, Key &key, + uint32 inputSize, bool encrypt, uint32 &result) = 0; + virtual void generateSignature(const Context &context, Key &key, CSSM_ALGORITHMS signOnlyAlgorithm, const CssmData &data, CssmData &signature) = 0; virtual void verifySignature(const Context &context, Key &key, @@ -112,22 +130,68 @@ public: const AccessCredentials *cred, const AclEntryPrototype *owner, uint32 pubUsage, uint32 pubAttrs, uint32 privUsage, uint32 privAttrs, RefPointer &publicKey, RefPointer &privateKey) = 0; - virtual RefPointer deriveKey(const Context &context, Key *key, - const AccessCredentials *cred, const AclEntryPrototype *owner, - CssmData *param, uint32 usage, uint32 attrs) = 0; - virtual void wrapKey(const Context &context, Key *key, - Key &keyToBeWrapped, const AccessCredentials *cred, + virtual void wrapKey(const Context &context, const AccessCredentials *cred, + Key *wrappingKey, Key &keyToBeWrapped, const CssmData &descriptiveData, CssmKey &wrappedKey) = 0; - virtual RefPointer unwrapKey(const Context &context, Key *key, + virtual void unwrapKey(const Context &context, const AccessCredentials *cred, const AclEntryPrototype *owner, - uint32 usage, uint32 attrs, const CssmKey wrappedKey, - Key *publicKey, CssmData *descriptiveData) = 0; - - virtual uint32 getOutputSize(const Context &context, Key &key, - uint32 inputSize, bool encrypt = true) = 0; + Key *wrappingKey, Key *publicKey, CSSM_KEYUSE usage, CSSM_KEYATTR_FLAGS attrs, + const CssmKey wrappedKey, RefPointer &unwrappedKey, CssmData &descriptiveData) = 0; + virtual void deriveKey(const Context &context, Key *key, + const AccessCredentials *cred, const AclEntryPrototype *owner, + CssmData *param, uint32 usage, uint32 attrs, RefPointer &derivedKey) = 0; + + virtual void authenticate(CSSM_DB_ACCESS_TYPE mode, const AccessCredentials *cred); + virtual SecurityServerAcl &acl(); - virtual void authenticate(const AccessCredentials *cred) = 0; + virtual bool isLocked() const; + +public: + class Search : public Subsidiary { + public: + Search(Database &db) : Subsidiary(db) { } + }; + + class Record : public Subsidiary { + public: + Record(Database &db) : Subsidiary(db) { } + }; + + virtual void findFirst(const CssmQuery &query, + CssmDbRecordAttributeData *inAttributes, mach_msg_type_number_t inAttributesLength, + CssmData *data, RefPointer &key, RefPointer &search, + RefPointer &record, + CssmDbRecordAttributeData * &outAttributes, mach_msg_type_number_t &outAttributesLength); + virtual void findNext(Search *search, + CssmDbRecordAttributeData *inAttributes, mach_msg_type_number_t inAttributesLength, + CssmData *data, RefPointer &key, RefPointer &record, + CssmDbRecordAttributeData * &outAttributes, mach_msg_type_number_t &outAttributesLength); + virtual void findRecordHandle(Record *record, + CssmDbRecordAttributeData *inAttributes, mach_msg_type_number_t inAttributesLength, + CssmData *data, RefPointer &key, + CssmDbRecordAttributeData * &outAttributes, mach_msg_type_number_t &outAttributesLength); + + virtual void insertRecord(CSSM_DB_RECORDTYPE recordtype, + const CssmDbRecordAttributeData *attributes, mach_msg_type_number_t inAttributesLength, + const CssmData &data, RecordHandle &record); + virtual void modifyRecord(CSSM_DB_RECORDTYPE recordtype, Record *record, + const CssmDbRecordAttributeData *attributes, mach_msg_type_number_t inAttributesLength, + const CssmData *data, CSSM_DB_MODIFY_MODE modifyMode); + virtual void deleteRecord(Database::Record *record); + + virtual void releaseSearch(Search &search); + virtual void releaseRecord(Record &record); + +public: + // SecurityServerAcl personality + AclKind aclKind() const; + GenericHandle aclHandle() const; + Database *relatedDatabase(); + +public: + // support ACL remote secret validation (default is no support) + virtual bool validateSecret(const AclSubject *subject, const AccessCredentials *cred); public: static const int maxUnlockTryCount = 3; @@ -135,14 +199,12 @@ public: public: DbCommon& common() const { return parent(); } virtual const char *dbName() const = 0; - -protected: - AccessCredentials *mCred; // local access credentials (always valid) + virtual void dbName(const char *name); }; // -// This class implements a "system keychaiin unlock record" store +// This class implements a "system keychain unlock record" store // class SystemKeychainKey { public: diff --git a/src/dbcrypto.cpp b/src/dbcrypto.cpp index f885440..b850653 100644 --- a/src/dbcrypto.cpp +++ b/src/dbcrypto.cpp @@ -3,8 +3,6 @@ * * @APPLE_LICENSE_HEADER_START@ * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. - * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in @@ -37,15 +35,18 @@ #include #include - using namespace CssmClient; +using LowLevelMemoryUtilities::fieldOffsetOf; +// +// The CryptoCore constructor doesn't do anything interesting. +// It just initializes us to "empty". +// DatabaseCryptoCore::DatabaseCryptoCore() : mHaveMaster(false), mIsValid(false) { } - DatabaseCryptoCore::~DatabaseCryptoCore() { // key objects take care of themselves @@ -217,11 +218,11 @@ DbBlob *DatabaseCryptoCore::encodeCore(const DbBlob &blobTemplate, // sign the blob CssmData signChunk[] = { - CssmData(blob->data(), offsetof(DbBlob, blobSignature)), + CssmData(blob->data(), fieldOffsetOf(&DbBlob::blobSignature)), CssmData(blob->publicAclBlob(), publicAcl.length() + cryptoBlob.length()) }; CssmData signature(blob->blobSignature, sizeof(blob->blobSignature)); - GenerateMac signer(Server::csp(), CSSM_ALGID_SHA1HMAC_LEGACY); //@@@!!! CRUD + GenerateMac signer(Server::csp(), CSSM_ALGID_SHA1HMAC_LEGACY); signer.key(mSigningKey); signer.sign(signChunk, 2, signature); assert(signature.length() == sizeof(blob->blobSignature)); @@ -262,7 +263,7 @@ void DatabaseCryptoCore::decodeCore(DbBlob *blob, void **privateAclBlob) // verify signature on the whole blob CssmData signChunk[] = { - CssmData(blob->data(), offsetof(DbBlob, blobSignature)), + CssmData(blob->data(), fieldOffsetOf(&DbBlob::blobSignature)), CssmData(blob->publicAclBlob(), blob->publicAclBlobLength() + blob->cryptoBlobLength()) }; CSSM_ALGORITHMS verifyAlgorithm = CSSM_ALGID_SHA1HMAC; @@ -275,8 +276,6 @@ void DatabaseCryptoCore::decodeCore(DbBlob *blob, void **privateAclBlob) verifier.verify(signChunk, 2, CssmData(blob->blobSignature, sizeof(blob->blobSignature))); // all checks out; start extracting fields - this->mEncryptionKey = mEncryptionKey; - this->mSigningKey = mSigningKey; if (privateAclBlob) { // extract private ACL blob as a separately allocated area uint32 blobLength = decryptedBlob.length() - sizeof(DbBlob::PrivateBlob); @@ -290,6 +289,19 @@ void DatabaseCryptoCore::decodeCore(DbBlob *blob, void **privateAclBlob) } +// +// Make another DatabaseCryptoCore's operational secrets our own. +// Intended for keychain synchronization. +// +void DatabaseCryptoCore::importSecrets(const DatabaseCryptoCore &src) +{ + assert(src.isValid()); // must have called src.decodeCore() first + assert(hasMaster()); + mEncryptionKey = src.mEncryptionKey; + mSigningKey = src.mSigningKey; + mIsValid = true; +} + // // Encode a key blob // @@ -344,7 +356,7 @@ KeyBlob *DatabaseCryptoCore::encodeKeyCore(const CssmKey &inKey, // sign the blob CssmData signChunk[] = { - CssmData(blob->data(), offsetof(KeyBlob, blobSignature)), + CssmData(blob->data(), fieldOffsetOf(&KeyBlob::blobSignature)), CssmData(blob->publicAclBlob(), blob->publicAclBlobLength() + blob->cryptoBlobLength()) }; CssmData signature(blob->blobSignature, sizeof(blob->blobSignature)); @@ -379,7 +391,7 @@ void DatabaseCryptoCore::decodeKeyCore(KeyBlob *blob, // verify signature (check against corruption) CssmData signChunk[] = { - CssmData::wrap(blob, offsetof(KeyBlob, blobSignature)), + CssmData::wrap(blob, fieldOffsetOf(&KeyBlob::blobSignature)), CssmData(blob->publicAclBlob(), blob->publicAclBlobLength() + blob->cryptoBlobLength()) }; CSSM_ALGORITHMS verifyAlgorithm = CSSM_ALGID_SHA1HMAC; @@ -441,7 +453,8 @@ CssmClient::Key DatabaseCryptoCore::deriveDbMasterKey(const CssmData &passphrase CssmClient::DeriveKey makeKey(Server::csp(), CSSM_ALGID_PKCS5_PBKDF2, CSSM_ALGID_3DES_3KEY_EDE, 24 * 8); makeKey.iterationCount(1000); - makeKey.salt(CssmData::wrap(mSalt)); + CssmData salt = CssmData::wrap(mSalt); + makeKey.salt(salt); CSSM_PKCS5_PBKDF2_PARAMS params; params.Passphrase = passphrase; params.PseudoRandomFunction = CSSM_PKCS5_PBKDF2_PRF_HMAC_SHA1; diff --git a/src/dbcrypto.h b/src/dbcrypto.h index 00a6a19..3067b70 100644 --- a/src/dbcrypto.h +++ b/src/dbcrypto.h @@ -3,8 +3,6 @@ * * @APPLE_LICENSE_HEADER_START@ * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. - * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in @@ -30,10 +28,12 @@ #ifndef _H_DBCRYPTO #define _H_DBCRYPTO -#include "securityserver.h" +#include #include #include +using namespace SecurityServer; + // // A DatabaseCryptoCore object encapsulates the secret state of a database. @@ -58,6 +58,7 @@ public: void decodeCore(DbBlob *blob, void **privateAclBlob = NULL); DbBlob *encodeCore(const DbBlob &blobTemplate, const CssmData &publicAcl, const CssmData &privateAcl) const; + void importSecrets(const DatabaseCryptoCore &src); KeyBlob *encodeKeyCore(const CssmKey &key, const CssmData &publicAcl, const CssmData &privateAcl) const; diff --git a/src/entropy.cpp b/src/entropy.cpp index 7a2dccc..6cb47b2 100644 --- a/src/entropy.cpp +++ b/src/entropy.cpp @@ -3,8 +3,6 @@ * * @APPLE_LICENSE_HEADER_START@ * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. - * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in diff --git a/src/entropy.h b/src/entropy.h index 2dbdc07..9537ff2 100644 --- a/src/entropy.h +++ b/src/entropy.h @@ -3,8 +3,6 @@ * * @APPLE_LICENSE_HEADER_START@ * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. - * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in @@ -25,7 +23,7 @@ // -// yarrowseed - periodical to collect and seed entropy into /dev/random +// entropy - periodical to collect and seed entropy into /dev/random // #ifndef _H_ENTROPY #define _H_ENTROPY diff --git a/src/flippers.cpp b/src/flippers.cpp index 694fd9e..6f67415 100644 --- a/src/flippers.cpp +++ b/src/flippers.cpp @@ -3,8 +3,6 @@ * * @APPLE_LICENSE_HEADER_START@ * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. - * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in diff --git a/src/flippers.h b/src/flippers.h index 140c6cf..6e437c0 100644 --- a/src/flippers.h +++ b/src/flippers.h @@ -3,8 +3,6 @@ * * @APPLE_LICENSE_HEADER_START@ * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. - * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in diff --git a/src/generate.pl b/src/generate.pl index 3426267..4599316 100755 --- a/src/generate.pl +++ b/src/generate.pl @@ -27,14 +27,14 @@ open(CPP, ">$out_cpp") || die "$out_cpp: $!"; # cautionary headings to each file print H < // @@@ 4003540 workaround #include #include // for default owner ACLs #include @@ -88,16 +87,20 @@ KeychainDatabase::KeychainDatabase(const DLDbIdentifier &id, const DBParameters // establish initial ACL if (owner) - cssmSetInitial(*owner); + acl().cssmSetInitial(*owner); else - cssmSetInitial(new AnyAclSubject()); + acl().cssmSetInitial(new AnyAclSubject()); mValidData = true; // for now, create the blob immediately encode(); proc.addReference(*this); - secdebug("SSdb", "database %s(%p) created, common at %p", + + // this new keychain is unlocked; make it so + activity(); + + secdebug("KCdb", "database %s(%p) created, common at %p", common().dbName(), this, &common()); } @@ -109,19 +112,7 @@ KeychainDatabase::KeychainDatabase(const DLDbIdentifier &id, const DbBlob *blob, const AccessCredentials *cred) : LocalDatabase(proc), mValidData(false), version(0) { - // perform basic validation on the incoming blob - assert(blob); - blob->validate(CSSMERR_APPLEDL_INVALID_DATABASE_BLOB); - switch (blob->version()) { -#if defined(COMPAT_OSX_10_0) - case blob->version_MacOS_10_0: - break; -#endif - case blob->version_MacOS_10_1: - break; - default: - CssmError::throwMe(CSSMERR_APPLEDL_INCOMPATIBLE_DATABASE_BLOB); - } + validateBlob(blob); // save a copy of the credentials for later access control mCred = DataWalkers::copy(cred, Allocator::standard()); @@ -135,26 +126,101 @@ KeychainDatabase::KeychainDatabase(const DLDbIdentifier &id, const DbBlob *blob, session.findFirst(&KeychainDbCommon::identifier, ident)) { parent(*dbcom); //@@@ arbitrate sequence number here, perhaps update common().mParams - secdebug("SSdb", + secdebug("KCdb", "open database %s(%p) version %lx at known common %p", common().dbName(), this, blob->version(), &common()); } else { // DbCommon not present; make a new one parent(*new KeychainDbCommon(proc.session(), ident)); common().mParams = blob->params; - secdebug("SSdb", "open database %s(%p) version %lx with new common %p", + secdebug("KCdb", "open database %s(%p) version %lx with new common %p", common().dbName(), this, blob->version(), &common()); + // this DbCommon is locked; no timer or reference setting } proc.addReference(*this); } +// +// Special-purpose constructor for keychain synchronization. Copies an +// existing keychain but uses the operational keys from secretsBlob. The +// new KeychainDatabase will silently replace the existing KeychainDatabase +// as soon as the client declares that re-encoding of all keychain items is +// finished. This is a little perilous since it allows a client to dictate +// securityd state, but we try to ensure that only the client that started +// the re-encoding can declare it done. +// +KeychainDatabase::KeychainDatabase(KeychainDatabase &src, Process &proc, + const DbBlob *secretsBlob, const CssmData &agentData) + : LocalDatabase(proc), mValidData(false), version(0), mBlob(NULL) +{ + validateBlob(secretsBlob); + + // get the passphrase to unlock secretsBlob + QueryDBBlobSecret query; + query.inferHints(proc); + query.addHint(AGENT_HINT_KCSYNC_DICT, agentData.data(), agentData.length()); + DatabaseCryptoCore keysCore; + if (query(keysCore, secretsBlob) != SecurityAgent::noReason) + CssmError::throwMe(CSSM_ERRCODE_OPERATION_AUTH_DENIED); + // keysCore is now ready to yield its secrets to us + + mCred = DataWalkers::copy(src.mCred, Allocator::standard()); + + // Give this KeychainDatabase a temporary name + std::string newDbName = std::string("////") + std::string(src.identifier().dbName()); + DLDbIdentifier newDLDbIdent(src.identifier().dlDbIdentifier().ssuid(), newDbName.c_str(), src.identifier().dlDbIdentifier().dbLocation()); + DbIdentifier ident(newDLDbIdent, src.identifier()); + + // create common block and initialize + RefPointer newCommon = new KeychainDbCommon(proc.session(), ident); + StLock _(*newCommon); + parent(*newCommon); + + // set initial database parameters from the source keychain + common().mParams = src.common().mParams; + + // establish the source keychain's master secret as ours + // @@@ NB: this is a v. 0.1 assumption. We *should* trigger new UI + // that offers the user the option of using the existing password + // or choosing a new one. That would require a new + // SecurityAgentQuery type, new UI, and--possibly--modifications to + // ensure that the new password is available here to generate the + // new master secret. + src.unlockDb(); // precaution for masterKey() + common().setup(src.blob(), src.common().masterKey()); + + // import the operational secrets + common().importSecrets(keysCore); + + // import source keychain's ACL + CssmData pubAcl, privAcl; + src.acl().exportBlob(pubAcl, privAcl); + importBlob(pubAcl.data(), privAcl.data()); + src.acl().allocator.free(pubAcl); + src.acl().allocator.free(privAcl); + + // indicate that this keychain should be allowed to do some otherwise + // risky things required for copying, like re-encoding keys + mRecodingSource = &src; + + common().setUnlocked(); + mValidData = true; + + encode(); + + proc.addReference(*this); + secdebug("SSdb", "database %s(%p) created as copy, common at %p", + common().dbName(), this, &common()); +} + + // // Destroy a Database // KeychainDatabase::~KeychainDatabase() { - secdebug("SSdb", "deleting database %s(%p) common %p", + secdebug("KCdb", "deleting database %s(%p) common %p", common().dbName(), this, &common()); Allocator::standard().free(mCred); Allocator::standard().free(mBlob); @@ -174,6 +240,21 @@ const char *KeychainDatabase::dbName() const return common().dbName(); } +bool KeychainDatabase::transient() const +{ + return false; // has permanent store +} + +AclKind KeychainDatabase::aclKind() const +{ + return dbAcl; +} + +Database *KeychainDatabase::relatedDatabase() +{ + return this; +} + static inline KeychainKey &myKey(Key *key) { @@ -184,22 +265,47 @@ static inline KeychainKey &myKey(Key *key) // // (Re-)Authenticate the database. This changes the stored credentials. // -void KeychainDatabase::authenticate(const AccessCredentials *cred) +void KeychainDatabase::authenticate(CSSM_DB_ACCESS_TYPE mode, + const AccessCredentials *cred) { StLock _(common()); - AccessCredentials *newCred = DataWalkers::copy(cred, Allocator::standard()); - Allocator::standard().free(mCred); - mCred = newCred; + + // the (Apple specific) RESET bit means "lock the database now" + switch (mode) { + case CSSM_DB_ACCESS_RESET: + secdebug("KCdb", "%p ACCESS_RESET triggers keychain lock", this); + common().lockDb(); + break; + default: + // store the new credentials for future use + secdebug("KCdb", "%p authenticate stores new database credentials", this); + AccessCredentials *newCred = DataWalkers::copy(cred, Allocator::standard()); + Allocator::standard().free(mCred); + mCred = newCred; + } } // -// Make a new KeychainKey +// Make a new KeychainKey. +// If PERMANENT is off, make a temporary key instead. +// The db argument allows you to create for another KeychainDatabase (only); +// it defaults to ourselves. // +RefPointer KeychainDatabase::makeKey(Database &db, const CssmKey &newKey, + uint32 moreAttributes, const AclEntryPrototype *owner) +{ + + if (moreAttributes & CSSM_KEYATTR_PERMANENT) + return new KeychainKey(db, newKey, moreAttributes, owner); + else + return process().makeTemporaryKey(newKey, moreAttributes, owner); +} + RefPointer KeychainDatabase::makeKey(const CssmKey &newKey, uint32 moreAttributes, const AclEntryPrototype *owner) { - return new KeychainKey(*this, newKey, moreAttributes, owner); + return makeKey(*this, newKey, moreAttributes, owner); } @@ -230,7 +336,7 @@ void KeychainDatabase::encode() Allocator::standard().free(mBlob); mBlob = blob; version = common().version; - secdebug("SSdb", "encoded database %p common %p(%s) version %ld params=(%ld,%d)", + secdebug("KCdb", "encoded database %p common %p(%s) version %ld params=(%ld,%d)", this, &common(), dbName(), version, common().mParams.idleTimeout, common().mParams.lockOnSleep); } @@ -250,8 +356,8 @@ void KeychainDatabase::changePassphrase(const AccessCredentials *cred) // establish NEW secret establishNewSecrets(cred, SecurityAgent::changePassphrase); - common().version++; // blob state changed - secdebug("SSdb", "Database %s(%p) master secret changed", common().dbName(), this); + common().invalidateBlob(); // blob state changed + secdebug("KCdb", "Database %s(%p) master secret changed", common().dbName(), this); encode(); // force rebuild of local blob // send out a notification @@ -261,6 +367,51 @@ void KeychainDatabase::changePassphrase(const AccessCredentials *cred) activity(); } +// +// Second stage of keychain synchronization: overwrite the original keychain's +// (this KeychainDatabase's) operational secrets +// +void KeychainDatabase::commitSecretsForSync(KeychainDatabase &cloneDb) +{ + StLock _(common()); + + // try to detect spoofing + if (cloneDb.mRecodingSource != this) + CssmError::throwMe(CSSM_ERRCODE_INVALID_DB_HANDLE); + + // in case we autolocked since starting the sync + unlockDb(); + cloneDb.unlockDb(); + + // Decode all keys whose handles refer to this on-disk keychain so that + // if the holding client commits the key back to disk, it's encoded with + // the new operational secrets. The recoding client *must* hold a write + // lock for the on-disk keychain from the moment it starts recoding key + // items until after this call. + // + // @@@ This specific implementation is a workaround for 4003540. + std::vector handleList; + HandleObject::findAllRefs(handleList); + size_t count = handleList.size(); + if (count > 0) { + for (unsigned int n = 0; n < count; ++n) { + RefPointer kckey = + HandleObject::findRefAndLock(handleList[n], CSSMERR_CSP_INVALID_KEY_REFERENCE); + StLock _(*kckey/*, true*/); + if (kckey->database().global().identifier() == identifier()) { + kckey->key(); // force decode + kckey->invalidateBlob(); + secdebug("kcrecode", "changed extant key %p (proc %d)", + &*kckey, kckey->process().pid()); + } + } + } + + // it is now safe to replace the old op secrets + common().importSecrets(cloneDb.common()); + common().invalidateBlob(); +} + // // Extract the database master key as a proper Key object. @@ -272,8 +423,11 @@ RefPointer KeychainDatabase::extractMasterKey(Database &db, // get and hold common lock StLock _(common()); + // force lock to require re-validation of credentials + lockDb(); + // unlock to establish master secret - makeUnlocked(cred); + makeUnlocked(); // extract the raw cryptographic key CssmClient::WrapKey wrap(Server::csp(), CSSM_ALGID_NONE); @@ -281,25 +435,7 @@ RefPointer KeychainDatabase::extractMasterKey(Database &db, wrap(common().masterKey(), key); // make the key object and return it - return new KeychainKey(db, key, attrs & Key::managedAttributes, owner); -} - - -// -// Construct a binary blob of moderate size that is suitable for constructing -// an index identifying this database. -// We construct this from the database's marker blob, which is created with -// the database is made, and stays stable thereafter. -// Note: Ownership of the index blob passes to the caller. -// @@@ This means that physical copies share this index. -// -void KeychainDatabase::getDbIndex(CssmData &indexData) -{ - if (!mBlob) - encode(); // force blob creation - assert(mBlob); - CssmData signature = CssmData::wrap(mBlob->randomSignature); - indexData = CssmAutoData(Allocator::standard(), signature).release(); + return makeKey(db, key, attrs & LocalKey::managedAttributes, owner); } @@ -324,13 +460,12 @@ void KeychainDatabase::makeUnlocked() void KeychainDatabase::makeUnlocked(const AccessCredentials *cred) { if (isLocked()) { - secdebug("SSdb", "%p(%p) unlocking for makeUnlocked()", this, &common()); + secdebug("KCdb", "%p(%p) unlocking for makeUnlocked()", this, &common()); assert(mBlob || (mValidData && common().hasMaster())); establishOldSecrets(cred); common().setUnlocked(); // mark unlocked - activity(); // set timeout timer } else if (!mValidData) { // need to decode to get our ACLs, master secret available - secdebug("SSdb", "%p(%p) is unlocked; decoding for makeUnlocked()", this, &common()); + secdebug("KCdb", "%p(%p) is unlocked; decoding for makeUnlocked()", this, &common()); if (!decode()) CssmError::throwMe(CSSM_ERRCODE_OPERATION_AUTH_DENIED); } @@ -391,13 +526,13 @@ bool KeychainDatabase::decode() void *privateAclBlob; if (common().unlockDb(mBlob, &privateAclBlob)) { if (!mValidData) { - importBlob(mBlob->publicAclBlob(), privateAclBlob); + acl().importBlob(mBlob->publicAclBlob(), privateAclBlob); mValidData = true; } Allocator::standard().free(privateAclBlob); return true; } - secdebug("SSdb", "%p decode failed", this); + secdebug("KCdb", "%p decode failed", this); return false; } @@ -430,7 +565,7 @@ void KeychainDatabase::establishOldSecrets(const AccessCredentials *creds) // interactively prompt the user - no additional data case CSSM_SAMPLE_TYPE_KEYCHAIN_PROMPT: { - secdebug("SSdb", "%p attempting interactive unlock", this); + secdebug("KCdb", "%p attempting interactive unlock", this); QueryUnlock query(*this); query.inferHints(Server::process()); if (query() == SecurityAgent::noReason) @@ -441,21 +576,21 @@ void KeychainDatabase::establishOldSecrets(const AccessCredentials *creds) case CSSM_SAMPLE_TYPE_PASSWORD: if (sample.length() != 2) CssmError::throwMe(CSSM_ERRCODE_INVALID_SAMPLE_VALUE); - secdebug("SSdb", "%p attempting passphrase unlock", this); + secdebug("KCdb", "%p attempting passphrase unlock", this); if (decode(sample[1])) return; break; // try to open with a given master key - Data:CSP or KeyHandle, Data:CssmKey case CSSM_WORDID_SYMMETRIC_KEY: assert(mBlob); - secdebug("SSdb", "%p attempting explicit key unlock", this); - common().setup(mBlob, keyFromCreds(sample)); + secdebug("KCdb", "%p attempting explicit key unlock", this); + common().setup(mBlob, keyFromCreds(sample, 4)); if (decode()) return; break; // explicitly defeat the default action but don't try anything in particular case CSSM_WORDID_CANCELED: - secdebug("SSdb", "%p defeat default action", this); + secdebug("KCdb", "%p defeat default action", this); break; default: // Unknown sub-sample for unlocking. @@ -464,7 +599,7 @@ void KeychainDatabase::establishOldSecrets(const AccessCredentials *creds) // But instead we try to be tolerant and continue on. // This DOES however count as an explicit attempt at specifying unlock, // so we will no longer try the default case below... - secdebug("SSdb", "%p unknown sub-sample unlock (%ld) ignored", this, sample.type()); + secdebug("KCdb", "%p unknown sub-sample unlock (%ld) ignored", this, sample.type()); break; } } @@ -475,7 +610,7 @@ void KeychainDatabase::establishOldSecrets(const AccessCredentials *creds) // attempt system-keychain unlock SystemKeychainKey systemKeychain(kSystemUnlockFile); if (systemKeychain.matches(mBlob->randomSignature)) { - secdebug("SSdb", "%p attempting system unlock", this); + secdebug("KCdb", "%p attempting system unlock", this); common().setup(mBlob, CssmClient::Key(Server::csp(), systemKeychain.key(), true)); if (decode()) return; @@ -507,7 +642,7 @@ void KeychainDatabase::establishNewSecrets(const AccessCredentials *creds, Secur // interactively prompt the user case CSSM_SAMPLE_TYPE_KEYCHAIN_PROMPT: { - secdebug("SSdb", "%p specified interactive passphrase", this); + secdebug("KCdb", "%p specified interactive passphrase", this); QueryNewPassphrase query(*this, reason); query.inferHints(Server::process()); CssmAutoData passphrase(Allocator::standard(Allocator::sensitive)); @@ -519,19 +654,19 @@ void KeychainDatabase::establishNewSecrets(const AccessCredentials *creds, Secur break; // try to use an explicitly given passphrase case CSSM_SAMPLE_TYPE_PASSWORD: - secdebug("SSdb", "%p specified explicit passphrase", this); + secdebug("KCdb", "%p specified explicit passphrase", this); if (sample.length() != 2) CssmError::throwMe(CSSM_ERRCODE_INVALID_SAMPLE_VALUE); common().setup(NULL, sample[1]); return; // try to open with a given master key case CSSM_WORDID_SYMMETRIC_KEY: - secdebug("SSdb", "%p specified explicit master key", this); - common().setup(NULL, keyFromCreds(sample)); + secdebug("KCdb", "%p specified explicit master key", this); + common().setup(NULL, keyFromCreds(sample, 3)); return; // explicitly defeat the default action but don't try anything in particular case CSSM_WORDID_CANCELED: - secdebug("SSdb", "%p defeat default action", this); + secdebug("KCdb", "%p defeat default action", this); break; default: // Unknown sub-sample for acquiring new secret. @@ -540,7 +675,7 @@ void KeychainDatabase::establishNewSecrets(const AccessCredentials *creds, Secur // But instead we try to be tolerant and continue on. // This DOES however count as an explicit attempt at specifying unlock, // so we will no longer try the default case below... - secdebug("SSdb", "%p unknown sub-sample acquisition (%ld) ignored", + secdebug("KCdb", "%p unknown sub-sample acquisition (%ld) ignored", this, sample.type()); break; } @@ -565,20 +700,21 @@ void KeychainDatabase::establishNewSecrets(const AccessCredentials *creds, Secur // Given a (truncated) Database credentials TypedList specifying a master key, // locate the key and return a reference to it. // -CssmClient::Key KeychainDatabase::keyFromCreds(const TypedList &sample) +CssmClient::Key KeychainDatabase::keyFromCreds(const TypedList &sample, unsigned int requiredLength) { // decode TypedList structure (sample type; Data:CSPHandle; Data:CSSM_KEY) assert(sample.type() == CSSM_WORDID_SYMMETRIC_KEY); - if (sample.length() != 3 + if (sample.length() != requiredLength || sample[1].type() != CSSM_LIST_ELEMENT_DATUM - || sample[2].type() != CSSM_LIST_ELEMENT_DATUM) + || sample[2].type() != CSSM_LIST_ELEMENT_DATUM + || (requiredLength == 4 && sample[3].type() != CSSM_LIST_ELEMENT_DATUM)) CssmError::throwMe(CSSM_ERRCODE_INVALID_SAMPLE_VALUE); CSSM_CSP_HANDLE &handle = *sample[1].data().interpretedAs(CSSM_ERRCODE_INVALID_SAMPLE_VALUE); CssmKey &key = *sample[2].data().interpretedAs(CSSM_ERRCODE_INVALID_SAMPLE_VALUE); if (key.header().cspGuid() == gGuidAppleCSPDL) { // handleOrKey is a SecurityServer KeyHandle; ignore key argument - return myKey(Server::key(handle)); + return safer_cast(*Server::key(handle)); } else { // not a KeyHandle reference; use key as a raw key if (key.header().blobType() != CSSM_KEYBLOB_RAW) @@ -650,6 +786,25 @@ void KeychainDatabase::decodeKey(KeyBlob *blob, CssmKey &key, void * &pubAcl, vo activity(); } +// +// Given a KeychainKey (that implicitly belongs to another keychain), +// return it encoded using this keychain's operational secrets. +// +KeyBlob *KeychainDatabase::recodeKey(KeychainKey &oldKey) +{ + if (mRecodingSource != &oldKey.referent()) { + CssmError::throwMe(CSSMERR_CSP_INVALID_KEY); + } + oldKey.instantiateAcl(); // make sure key is decoded + CssmData publicAcl, privateAcl; + oldKey.exportBlob(publicAcl, privateAcl); + // NB: blob's memory belongs to caller, not the common + KeyBlob *blob = common().encodeKeyCore(oldKey.cssmKey(), publicAcl, privateAcl); + oldKey.acl().allocator.free(publicAcl); + oldKey.acl().allocator.free(privateAcl); + return blob; +} + // // Modify database parameters @@ -659,9 +814,9 @@ void KeychainDatabase::setParameters(const DBParameters ¶ms) StLock _(common()); makeUnlocked(); common().mParams = params; - common().version++; // invalidate old blobs - activity(); - secdebug("SSdb", "%p common %p(%s) set params=(%ld,%d)", + common().invalidateBlob(); // invalidate old blobs + activity(); // (also resets the timeout timer) + secdebug("KCdb", "%p common %p(%s) set params=(%ld,%d)", this, &common(), dbName(), params.idleTimeout, params.lockOnSleep); } @@ -678,6 +833,16 @@ void KeychainDatabase::getParameters(DBParameters ¶ms) } +// +// RIGHT NOW, database ACLs are attached to the database. +// This will soon move upstairs. +// +SecurityServerAcl &KeychainDatabase::acl() +{ + return *this; +} + + // // Intercept ACL change requests and reset blob validity // @@ -693,8 +858,26 @@ void KeychainDatabase::changedAcl() version = 0; } -const Database *KeychainDatabase::relatedDatabase() const -{ return this; } + +// +// Check an incoming DbBlob for basic viability +// +void KeychainDatabase::validateBlob(const DbBlob *blob) +{ + // perform basic validation on the blob + assert(blob); + blob->validate(CSSMERR_APPLEDL_INVALID_DATABASE_BLOB); + switch (blob->version()) { +#if defined(COMPAT_OSX_10_0) + case blob->version_MacOS_10_0: + break; +#endif + case blob->version_MacOS_10_1: + break; + default: + CssmError::throwMe(CSSMERR_APPLEDL_INCOMPATIBLE_DATABASE_BLOB); + } +} // @@ -737,18 +920,39 @@ void KeychainDatabase::dumpNode() // DbCommon basic features // KeychainDbCommon::KeychainDbCommon(Session &ssn, const DbIdentifier &id) - : DbCommon(ssn), mIdentifier(id), sequence(0), version(1), + : DbCommon(ssn), sequence(0), version(1), mIdentifier(id), mIsLocked(true), mValidParams(false) -{ } +{ + // match existing DbGlobal or create a new one + Server &server = Server::active(); + StLock _(server); + if (KeychainDbGlobal *dbglobal = + server.findFirst(&KeychainDbGlobal::identifier, identifier())) { + parent(*dbglobal); + secdebug("KCdb", "%p linking to existing DbGlobal %p", this, dbglobal); + } else { + // DbGlobal not present; make a new one + parent(*new KeychainDbGlobal(identifier())); + secdebug("KCdb", "%p linking to new DbGlobal %p", this, &global()); + } + + // link lifetime to the Session + session().addReference(*this); +} KeychainDbCommon::~KeychainDbCommon() { - secdebug("SSdb", "DbCommon %p destroyed", this); + secdebug("KCdb", "DbCommon %p destroyed", this); // explicitly unschedule ourselves Server::active().clearTimer(this); } +KeychainDbGlobal &KeychainDbCommon::global() const +{ + return parent(); +} + void KeychainDbCommon::makeNewSecrets() { @@ -760,7 +964,6 @@ void KeychainDbCommon::makeNewSecrets() // we're now officially "unlocked"; set the timer setUnlocked(); - activity(); // set lock timer } @@ -779,9 +982,9 @@ bool KeychainDbCommon::unlockDb(DbBlob *blob, void **privateAclBlob) // in an astonishing variety of ways if the passphrase is wrong. assert(hasMaster()); decodeCore(blob, privateAclBlob); - secdebug("SSdb", "%p unlock successful", this); + secdebug("KCdb", "%p unlock successful", this); } catch (...) { - secdebug("SSdb", "%p unlock failed", this); + secdebug("KCdb", "%p unlock failed", this); return false; } @@ -793,7 +996,6 @@ bool KeychainDbCommon::unlockDb(DbBlob *blob, void **privateAclBlob) } setUnlocked(); // mark unlocked - activity(); // set lock timer // broadcast unlock notification notify(kNotificationEventUnlocked); @@ -802,25 +1004,25 @@ bool KeychainDbCommon::unlockDb(DbBlob *blob, void **privateAclBlob) void KeychainDbCommon::setUnlocked() { - session().addReference(*this); // active/held - mIsLocked = false; // mark unlocked + session().addReference(*this); // active/held + mIsLocked = false; // mark unlocked + activity(); // set timeout timer } -void KeychainDbCommon::lockDb(bool forSleep) +void KeychainDbCommon::lockDb() { - StLock locker(*this); + StLock _(*this); if (!isLocked()) { - if (forSleep && !mParams.lockOnSleep) - return; // it doesn't want to - + secdebug("KCdb", "common %s(%p) locking", dbName(), this); DatabaseCryptoCore::invalidate(); notify(kNotificationEventLocked); Server::active().clearTimer(this); mIsLocked = true; // mark locked - locker.unlock(); // release DbCommon lock now - session().removeReference(*this); // remove active/hold + + // this call may destroy us if we have no databases anymore + session().removeReference(*this); } } @@ -831,7 +1033,7 @@ DbBlob *KeychainDbCommon::encode(KeychainDatabase &db) // export database ACL to blob form CssmData pubAcl, privAcl; - db.exportBlob(pubAcl, privAcl); + db.acl().exportBlob(pubAcl, privAcl); // tell the cryptocore to form the blob DbBlob form; @@ -844,8 +1046,8 @@ DbBlob *KeychainDbCommon::encode(KeychainDatabase &db) DbBlob *blob = encodeCore(form, pubAcl, privAcl); // clean up and go - db.allocator.free(pubAcl); - db.allocator.free(privAcl); + db.acl().allocator.free(pubAcl); + db.acl().allocator.free(privAcl); return blob; } @@ -874,14 +1076,14 @@ void KeychainDbCommon::notify(NotificationEvent event) // void KeychainDbCommon::action() { - secdebug("SSdb", "common %s(%p) locked by timer", dbName(), this); + secdebug("KCdb", "common %s(%p) locked by timer", dbName(), this); lockDb(); } void KeychainDbCommon::activity() { if (!isLocked()) { - secdebug("SSdb", "setting DbCommon %p timer to %d", + secdebug("KCdb", "setting DbCommon %p timer to %d", this, int(mParams.idleTimeout)); Server::active().setTimer(this, Time::Interval(int(mParams.idleTimeout))); } @@ -889,5 +1091,27 @@ void KeychainDbCommon::activity() void KeychainDbCommon::sleepProcessing() { - lockDb(true); + secdebug("KCdb", "common %s(%p) sleep-lock processing", dbName(), this); + StLock _(*this); + if (mParams.lockOnSleep) + lockDb(); +} + +void KeychainDbCommon::lockProcessing() +{ + lockDb(); +} + + +// +// Keychain global objects +// +KeychainDbGlobal::KeychainDbGlobal(const DbIdentifier &id) + : mIdentifier(id) +{ +} + +KeychainDbGlobal::~KeychainDbGlobal() +{ + secdebug("KCdb", "DbGlobal %p destroyed", this); } diff --git a/src/kcdatabase.h b/src/kcdatabase.h index 99047c8..61f147b 100644 --- a/src/kcdatabase.h +++ b/src/kcdatabase.h @@ -3,8 +3,6 @@ * * @APPLE_LICENSE_HEADER_START@ * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. - * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in @@ -40,6 +38,11 @@ class KeychainDbCommon; class KeychainKey; +// +// We identify KeychainDatabases uniquely by a combination of +// a DLDbIdentifier and a database (blob) identifier. Equivalence +// by DbIdentifier is the criterion for parent-side merging. +// class DbIdentifier { public: DbIdentifier(const DLDbIdentifier &id, DbBlob::Signature sig) @@ -67,6 +70,22 @@ private: }; +// +// A vestigal system-global database instance +// We don't (yet) use it for anything. Perhaps it should carry our ACL... +// +class KeychainDbGlobal : public PerGlobal { +public: + KeychainDbGlobal(const DbIdentifier &id); + ~KeychainDbGlobal(); + + const DbIdentifier &identifier() const { return mIdentifier; } + +private: + DbIdentifier mIdentifier; // database external identifier [const] +}; + + // // KeychainDatabase DbCommons // @@ -76,10 +95,13 @@ public: KeychainDbCommon(Session &ssn, const DbIdentifier &id); ~KeychainDbCommon(); + KeychainDbGlobal &global() const; + bool unlockDb(DbBlob *blob, void **privateAclBlob = NULL); - void lockDb(bool forSleep = false); // versatile lock primitive + void lockDb(); // make locked (if currently unlocked) bool isLocked() const { return mIsLocked; } // lock status void setUnlocked(); + void invalidateBlob() { version++; } void activity(); // reset lock timeout @@ -94,6 +116,7 @@ public: void notify(NotificationEvent event); void sleepProcessing(); + void lockProcessing(); public: // debugging @@ -103,7 +126,6 @@ protected: void action(); // timer queue action to lock keychain public: - DbIdentifier mIdentifier; // database external identifier [const] // all following data locked with object lock uint32 sequence; // change sequence number DBParameters mParams; // database parameters (arbitrated copy) @@ -111,6 +133,8 @@ public: uint32 version; // version stamp for change tracking private: + DbIdentifier mIdentifier; // database external identifier [const] + // all following data protected by object lock bool mIsLocked; // logically locked bool mValidParams; // mParams has been set }; @@ -121,15 +145,22 @@ private: // It maintains its protected semantic state (including keys) and provides controlled // access. // -class KeychainDatabase : public LocalDatabase { +class KeychainDatabase : public LocalDatabase, private virtual SecurityServerAcl { friend class KeychainDbCommon; public: KeychainDatabase(const DLDbIdentifier &id, const DBParameters ¶ms, Process &proc, const AccessCredentials *cred, const AclEntryPrototype *owner); + KeychainDatabase(const DLDbIdentifier &id, const DbBlob *blob, Process &proc, + const AccessCredentials *cred); + // keychain synchronization + KeychainDatabase(KeychainDatabase &src, Process &proc, const DbBlob *secretsBlob, const CssmData &agentData); virtual ~KeychainDatabase(); KeychainDbCommon &common() const; const char *dbName() const; + bool transient() const; + + KeychainDbGlobal &global() const { return common().global(); } public: static const int maxUnlockTryCount = 3; @@ -140,13 +171,12 @@ public: public: // encoding/decoding databases DbBlob *blob(); - KeychainDatabase(const DLDbIdentifier &id, const DbBlob *blob, Process &proc, - const AccessCredentials *cred); - void authenticate(const AccessCredentials *cred); + + void authenticate(CSSM_DB_ACCESS_TYPE mode, const AccessCredentials *cred); void changePassphrase(const AccessCredentials *cred); RefPointer extractMasterKey(Database &db, const AccessCredentials *cred, const AclEntryPrototype *owner, uint32 usage, uint32 attrs); - void getDbIndex(CssmData &indexData); + void commitSecretsForSync(KeychainDatabase &cloneDb); // lock/unlock processing void lockDb(); // unconditional lock @@ -164,24 +194,32 @@ public: // encoding/decoding keys void decodeKey(KeyBlob *blob, CssmKey &key, void * &pubAcl, void * &privAcl); KeyBlob *encodeKey(const CssmKey &key, const CssmData &pubAcl, const CssmData &privAcl); - + KeyBlob *recodeKey(KeychainKey &oldKey); bool validBlob() const { return mBlob && version == common().version; } // manage database parameters void setParameters(const DBParameters ¶ms); void getParameters(DBParameters ¶ms); + + // where's my (database) ACL? + SecurityServerAcl &acl(); + + AclKind aclKind() const; + Database *relatedDatabase(); // ACL state management hooks void instantiateAcl(); void changedAcl(); - const Database *relatedDatabase() const; // "self", for SecurityServerAcl's sake + + // miscellaneous utilities + static void validateBlob(const DbBlob *blob); // debugging IFDUMP(void dumpNode()); protected: - RefPointer makeKey(const CssmKey &newKey, uint32 moreAttributes, - const AclEntryPrototype *owner); + RefPointer makeKey(const CssmKey &newKey, uint32 moreAttributes, const AclEntryPrototype *owner); + RefPointer makeKey(Database &db, const CssmKey &newKey, uint32 moreAttributes, const AclEntryPrototype *owner); void makeUnlocked(); // interior version of unlock() void makeUnlocked(const AccessCredentials *cred); // like () with explicit cred @@ -190,10 +228,10 @@ protected: void establishOldSecrets(const AccessCredentials *creds); void establishNewSecrets(const AccessCredentials *creds, SecurityAgent::Reason reason); - static CssmClient::Key keyFromCreds(const TypedList &sample); + static CssmClient::Key keyFromCreds(const TypedList &sample, unsigned int requiredLength); void encode(); // (re)generate mBlob if needed - + private: // all following data is locked by the common lock bool mValidData; // valid ACL and params (blob decoded) @@ -202,6 +240,8 @@ private: DbBlob *mBlob; // database blob (encoded) AccessCredentials *mCred; // local access credentials (always valid) + + RefPointer mRecodingSource; // keychain synchronization ONLY; should not require accessors }; #endif //_H_KCDATABASE diff --git a/src/kckey.cpp b/src/kckey.cpp index 7c33808..780f8cc 100644 --- a/src/kckey.cpp +++ b/src/kckey.cpp @@ -3,8 +3,6 @@ * * @APPLE_LICENSE_HEADER_START@ * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. - * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in @@ -25,7 +23,7 @@ // -// key - representation of SecurityServer key objects +// key - representation of securityd key objects // #include "kckey.h" #include "server.h" @@ -38,7 +36,7 @@ // Note that this doesn't decode the blob (yet). // KeychainKey::KeychainKey(Database &db, const KeyBlob *blob) - : LocalKey(db) + : LocalKey(db, n2h(blob->header.attributes())) { // perform basic validation on the incoming blob assert(blob); @@ -68,9 +66,10 @@ KeychainKey::KeychainKey(Database &db, const KeyBlob *blob) // KeychainKey::KeychainKey(Database &db, const CssmKey &newKey, uint32 moreAttributes, const AclEntryPrototype *owner) - : LocalKey(db, newKey, moreAttributes, owner) + : LocalKey(db, newKey, moreAttributes) { assert(moreAttributes & CSSM_KEYATTR_PERMANENT); + setOwner(owner); mBlob = NULL; mValidBlob = false; db.addReference(*this); @@ -121,7 +120,7 @@ void KeychainKey::decode() CssmKey key; database().decodeKey(mBlob, key, publicAcl, privateAcl); mKey = CssmClient::Key(Server::csp(), key); - importBlob(publicAcl, privateAcl); + acl().importBlob(publicAcl, privateAcl); // publicAcl points into the blob; privateAcl was allocated for us Allocator::standard().free(privateAcl); @@ -145,11 +144,10 @@ KeyBlob *KeychainKey::blob() { if (!mValidBlob) { assert(mValidKey); // must have valid key to encode - //@@@ release mBlob memory here // export Key ACL to blob form CssmData pubAcl, privAcl; - exportBlob(pubAcl, privAcl); + acl().exportBlob(pubAcl, privAcl); // assemble external key form CssmKey externalKey = mKey; @@ -163,15 +161,22 @@ KeyBlob *KeychainKey::blob() mValidBlob = true; // clean up and go - database().allocator.free(pubAcl); - database().allocator.free(privAcl); + acl().allocator.free(pubAcl); + acl().allocator.free(privAcl); } return mBlob; } +void KeychainKey::invalidateBlob() +{ + mValidBlob = false; +} + // -// Intercept ACL change requests and reset blob validity +// Override ACL-related methods and events. +// Decode the key before ACL activity; invalidate the stored blob on ACL edits; +// and return the key's database as "related". // void KeychainKey::instantiateAcl() { @@ -180,8 +185,25 @@ void KeychainKey::instantiateAcl() void KeychainKey::changedAcl() { - mValidBlob = false; + invalidateBlob(); +} + + +// +// We're a key (duh) +// +AclKind KeychainKey::aclKind() const +{ + return keyAcl; } -const Database *KeychainKey::relatedDatabase() const -{ return &database(); } + +Database *KeychainKey::relatedDatabase() +{ + return &database(); +} + +SecurityServerAcl &KeychainKey::acl() +{ + return *this; +} diff --git a/src/kckey.h b/src/kckey.h index 9d1a259..b42a43c 100644 --- a/src/kckey.h +++ b/src/kckey.h @@ -3,8 +3,6 @@ * * @APPLE_LICENSE_HEADER_START@ * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. - * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in @@ -39,19 +37,18 @@ class KeychainDatabase; // -// A Key object represents a CSSM_KEY known to the SecurityServer. -// We give each Key a handle that allows our clients to access it, while we use -// the Key's ACL to control such accesses. -// A Key can be used by multiple Connections. Whether more than one Key can represent -// the same actual key object is up to the CSP we use, so let's be tolerant about that. +// A KeychainKey object represents a CssmKey that is stored in a KeychainDatabase. // -// A note on key attributes: We keep two sets of attribute bits. The internal bits are used -// when talking to our CSP; the external bits are used when negotiating with our client(s). -// The difference is the bits in managedAttributes, which relate to persistent key storage -// and are not digestible by our CSP. The internal attributes are kept in mKey. The external -// ones are kept in mAttributes. +// This is a LocalKey with deferred instantiation. A KeychainKey always exists in one of +// two states: +// (*) Decoded: The CssmKey is valid; the blob may or may not be. +// (*) Encoded: The blob is valid, the CssmKey may or may not be. +// One of (blob, CssmKey) is always valid. The process of decoding the CssmKey from the +// blob (and vice versa) requires keychain cryptography, which unlocks the keychain +// (implicitly as needed). +// Other than that, this is just a LocalKey. // -class KeychainKey : public LocalKey { +class KeychainKey : public LocalKey, public SecurityServerAcl { public: KeychainKey(Database &db, const KeyBlob *blob); KeychainKey(Database &db, const CssmKey &newKey, uint32 moreAttributes, @@ -62,12 +59,19 @@ public: // we can also yield an encoded KeyBlob *if* we belong to a database KeyBlob *blob(); + + void invalidateBlob(); // ACL state management hooks void instantiateAcl(); void changedAcl(); - const Database *relatedDatabase() const; - CSSM_KEYATTR_FLAGS attributes() { return mAttributes; } + Database *relatedDatabase(); + +public: + // SecurityServerAcl personality + AclKind aclKind() const; + + SecurityServerAcl &acl(); private: void decode(); diff --git a/src/key.cpp b/src/key.cpp index c418e36..04a9208 100644 --- a/src/key.cpp +++ b/src/key.cpp @@ -3,8 +3,6 @@ * * @APPLE_LICENSE_HEADER_START@ * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. - * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in @@ -25,39 +23,14 @@ // -// key - representation of SecurityServer key objects +// key - representation of securityd key objects // #include "key.h" #include "server.h" -#include "database.h" #include -Key::Key() - : SecurityServerAcl(keyAcl, Allocator::standard()) -{ -} - - -Database &Key::database() const -{ - return referent(); -} - - -// -// Form a KeySpec with checking and masking -// -Key::KeySpec::KeySpec(uint32 usage, uint32 attrs) - : CssmClient::KeySpec(usage, (attrs & ~managedAttributes) | forcedAttributes) -{ - if (attrs & generatedAttributes) - CssmError::throwMe(CSSMERR_CSP_INVALID_KEYATTR_MASK); -} - -Key::KeySpec::KeySpec(uint32 usage, uint32 attrs, const CssmData &label) - : CssmClient::KeySpec(usage, (attrs & ~managedAttributes) | forcedAttributes, label) +Key::Key(Database &db) + : Database::Subsidiary(db) { - if (attrs & generatedAttributes) - CssmError::throwMe(CSSMERR_CSP_INVALID_KEYATTR_MASK); } diff --git a/src/key.h b/src/key.h index 70c4fc7..b6c9e00 100644 --- a/src/key.h +++ b/src/key.h @@ -3,8 +3,6 @@ * * @APPLE_LICENSE_HEADER_START@ * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. - * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in @@ -25,13 +23,13 @@ // -// key - representation of SecurityServer key objects +// key - representation of securityd key objects // #ifndef _H_KEY #define _H_KEY -#include "securityserver.h" #include "structure.h" +#include "database.h" #include "acls.h" #include #include @@ -41,44 +39,41 @@ class Database; // -// A Key object represents a CSSM_KEY known to the SecurityServer. -// We give each Key a handle that allows our clients to access it, while we use -// the Key's ACL to control such accesses. -// A Key can be used by multiple Connections. Whether more than one Key can represent -// the same actual key object is up to the CSP we use, so let's be tolerant about that. +// A Key object represents a cryptographic key known to securityd and accessed by clients +// through securityd key references (KeyHandles). A Key may be raw or reference inside securityd, +// but from outside it is always a reference key, and we hide (as best we can) the details of +// its local storage and nature. +// +// Key is a very abstract class; it defines the minimal interface that all actual securityd +// keys must provide. Actual Key subclasses are produced by (subclasses of) Databases, which +// act as Key factories. Most Database subclasses will define Key class hierarchies to track +// their internal structure, but from out here, all we know is that Databases yield Key objects +// when asked nicely, and those subclass objects implement the Key protocol. +// +// A Key can be used by multiple Connections, even at the same time. It is possible for multiple +// Key objects to represent the same underlying cryptographic secret, so don't assume a 1-1 mapping. // -// A note on key attributes: We keep two sets of attribute bits. The internal bits are used -// when talking to our CSP; the external bits are used when negotiating with our client(s). -// The difference is the bits in managedAttributes, which relate to persistent key storage -// and are not digestible by our CSP. The internal attributes are kept in mKey. The external -// ones are kept in mAttributes. +// Key is completely agnostic as to how the key is stored or maintained. +// For all you know, it might be a virtual artifact of the Key subclass. // -class Key : public PerProcess, public SecurityServerAcl { +// All Key subclasses support ACLs. However, different subclasses may host +// their SecurityServerAcls at different levels of the object mesh. Don't assume. +// +// Key::attribute is there for a reason. If you want to check attributes, +// use it rather than returnKey - it may be much, much faster. +// +class Key : public Database::Subsidiary, public AclSource { public: - Key(); - - Database &database() const; + Key(Database &db); virtual const CssmData &canonicalDigest() = 0; - virtual CSSM_KEYATTR_FLAGS attributes() = 0; - virtual void returnKey(Handle &h, CssmKey::Header &hdr) = 0; + Database &database() const { return referent(); } -public: - // key attributes that should not be passed on to the CSP - static const uint32 managedAttributes = KeyBlob::managedAttributes; - // these attributes are "forced on" in internal keys (but not always in external attributes) - static const uint32 forcedAttributes = KeyBlob::forcedAttributes; - // these attributes are internally generated, and invalid on input - static const uint32 generatedAttributes = - CSSM_KEYATTR_ALWAYS_SENSITIVE | CSSM_KEYATTR_NEVER_EXTRACTABLE; + virtual CSSM_KEYATTR_FLAGS attributes() = 0; + bool attribute(CSSM_KEYATTR_FLAGS f) { return attributes() & f; } - // a version of KeySpec that self-checks and masks for CSP operation - class KeySpec : public CssmClient::KeySpec { - public: - KeySpec(uint32 usage, uint32 attrs); - KeySpec(uint32 usage, uint32 attrs, const CssmData &label); - }; + virtual void returnKey(Handle &h, CssmKey::Header &hdr) = 0; }; diff --git a/src/localdatabase.cpp b/src/localdatabase.cpp index f486373..1ffc954 100644 --- a/src/localdatabase.cpp +++ b/src/localdatabase.cpp @@ -3,8 +3,6 @@ * * @APPLE_LICENSE_HEADER_START@ * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. - * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in @@ -60,10 +58,10 @@ static inline LocalKey &myKey(Key &key) // // Key inquiries // -CSSM_KEY_SIZE LocalDatabase::queryKeySize(Key &key) +void LocalDatabase::queryKeySizeInBits(Key &key, CssmKeySize &result) { CssmClient::Key theKey(Server::csp(), myKey(key)); - return theKey.sizeInBits(); + result = theKey.sizeInBits(); } @@ -160,10 +158,10 @@ void LocalDatabase::generateKey(const Context &context, // generate key // @@@ turn "none" return into reference if permanent (only) CssmKey key; - generate(key, Key::KeySpec(usage, attrs)); + generate(key, LocalKey::KeySpec(usage, attrs)); // register and return the generated key - newKey = makeKey(key, attrs & Key::managedAttributes, owner); + newKey = makeKey(key, attrs & LocalKey::managedAttributes, owner); } void LocalDatabase::generateKey(const Context &context, @@ -181,33 +179,12 @@ void LocalDatabase::generateKey(const Context &context, // generate keys // @@@ turn "none" return into reference if permanent (only) CssmKey pubKey, privKey; - generate(pubKey, Key::KeySpec(pubUsage, pubAttrs), - privKey, Key::KeySpec(privUsage, privAttrs)); + generate(pubKey, LocalKey::KeySpec(pubUsage, pubAttrs), + privKey, LocalKey::KeySpec(privUsage, privAttrs)); // register and return the generated keys - publicKey = makeKey(pubKey, pubAttrs & Key::managedAttributes, owner); - privateKey = makeKey(privKey, privAttrs & Key::managedAttributes, owner); -} - -RefPointer LocalDatabase::deriveKey(const Context &context, Key *baseKey, - const AccessCredentials *cred, const AclEntryPrototype *owner, - CssmData *param, uint32 usage, uint32 attrs) -{ - // prepare a key-derivation context - if (baseKey) { - baseKey->validate(CSSM_ACL_AUTHORIZATION_DERIVE, cred); - context.replace(CSSM_ATTRIBUTE_KEY, myKey(*baseKey).cssmKey()); - } - CssmClient::DeriveKey derive(Server::csp(), context.algorithm(), CSSM_ALGID_NONE); - derive.override(context); - - // derive key - // @@@ turn "none" return into reference if permanent (only) - CssmKey key; - derive(param, Key::KeySpec(usage, attrs), key); - - // register and return the generated key - return makeKey(key, attrs & Key::managedAttributes, owner); + publicKey = makeKey(pubKey, pubAttrs & LocalKey::managedAttributes, owner); + privateKey = makeKey(privKey, privAttrs & LocalKey::managedAttributes, owner); } @@ -217,73 +194,86 @@ RefPointer LocalDatabase::deriveKey(const Context &context, Key *baseKey, // case of "cleartext" (null algorithm) wrapping for import/export. // -void LocalDatabase::wrapKey(const Context &context, Key *key, - Key &keyToBeWrapped, const AccessCredentials *cred, - const CssmData &descriptiveData, CssmKey &wrappedKey) +void LocalDatabase::wrapKey(const Context &context, const AccessCredentials *cred, + Key *wrappingKey, Key &keyToBeWrapped, + const CssmData &descriptiveData, CssmKey &wrappedKey) { keyToBeWrapped.validate(context.algorithm() == CSSM_ALGID_NONE ? CSSM_ACL_AUTHORIZATION_EXPORT_CLEAR : CSSM_ACL_AUTHORIZATION_EXPORT_WRAPPED, cred); - if(!(keyToBeWrapped.attributes() & CSSM_KEYATTR_EXTRACTABLE)) { - CssmError::throwMe(CSSMERR_CSP_INVALID_KEYATTR_MASK); - } - if (key) { - context.replace(CSSM_ATTRIBUTE_KEY, myKey(*key).cssmKey()); - key->validate(CSSM_ACL_AUTHORIZATION_ENCRYPT, context); + if (wrappingKey) { + context.replace(CSSM_ATTRIBUTE_KEY, myKey(*wrappingKey).cssmKey()); + wrappingKey->validate(CSSM_ACL_AUTHORIZATION_ENCRYPT, context); } CssmClient::WrapKey wrap(Server::csp(), context.algorithm()); wrap.override(context); - wrap.cred(const_cast(cred)); //@@@ const madness - fix in client/pod + wrap.cred(cred); wrap(myKey(keyToBeWrapped), wrappedKey, &descriptiveData); } -RefPointer LocalDatabase::unwrapKey(const Context &context, Key *key, +void LocalDatabase::unwrapKey(const Context &context, const AccessCredentials *cred, const AclEntryPrototype *owner, - uint32 usage, uint32 attrs, const CssmKey wrappedKey, - Key *publicKey, CssmData *descriptiveData) + Key *wrappingKey, Key *publicKey, CSSM_KEYUSE usage, CSSM_KEYATTR_FLAGS attrs, + const CssmKey wrappedKey, RefPointer &unwrappedKey, CssmData &descriptiveData) { - if (key) { - context.replace(CSSM_ATTRIBUTE_KEY, myKey(*key).cssmKey()); - key->validate(CSSM_ACL_AUTHORIZATION_DECRYPT, context); + if (wrappingKey) { + context.replace(CSSM_ATTRIBUTE_KEY, myKey(*wrappingKey).cssmKey()); + wrappingKey->validate(CSSM_ACL_AUTHORIZATION_DECRYPT, context); } + // we are not checking access on the public key, if any + CssmClient::UnwrapKey unwrap(Server::csp(), context.algorithm()); unwrap.override(context); - CssmKey unwrappedKey; - unwrap.cred(const_cast(cred)); //@@@ const madness - fix in client/pod + unwrap.cred(cred); + + // the AclEntryInput will have to live until unwrap is done + AclEntryInput ownerInput; if (owner) { - AclEntryInput ownerInput(*owner); //@@@ const trouble - fix in client/pod - unwrap.aclEntry(ownerInput); - } + ownerInput.proto() = *owner; + unwrap.owner(ownerInput); + } + + CssmKey result; + unwrap(wrappedKey, LocalKey::KeySpec(usage, attrs), result, &descriptiveData, + publicKey ? &myKey(*publicKey).cssmKey() : NULL); + unwrappedKey = makeKey(result, attrs & LocalKey::managedAttributes, owner); +} + - // @@@ Invoking conversion operator to CssmKey & on *publicKey and take the address of the result. - unwrap(wrappedKey, Key::KeySpec(usage, attrs), unwrappedKey, - descriptiveData, publicKey ? &static_cast(myKey(*publicKey)) : NULL); +// +// Key derivation +// +void LocalDatabase::deriveKey(const Context &context, Key *key, + const AccessCredentials *cred, const AclEntryPrototype *owner, + CssmData *param, uint32 usage, uint32 attrs, RefPointer &derivedKey) +{ + if (key) { + key->validate(CSSM_ACL_AUTHORIZATION_DERIVE, cred); + context.replace(CSSM_ATTRIBUTE_KEY, myKey(*key).cssmKey()); + } + CssmClient::DeriveKey derive(Server::csp(), context.algorithm(), CSSM_ALGID_NONE); + derive.override(context); + + // derive key + // @@@ turn "none" return into reference if permanent (only) + CssmKey dKey; + derive(param, LocalKey::KeySpec(usage, attrs), dKey); - return makeKey(unwrappedKey, attrs & Key::managedAttributes, owner); + // register and return the generated key + derivedKey = makeKey(dKey, attrs & LocalKey::managedAttributes, owner); } // // Miscellaneous CSSM functions // -uint32 LocalDatabase::getOutputSize(const Context &context, Key &key, uint32 inputSize, bool encrypt) +void LocalDatabase::getOutputSize(const Context &context, Key &key, uint32 inputSize, + bool encrypt, uint32 &result) { // We're fudging here somewhat, since the context can be any type. // ctx.override will fix the type, and no-one's the wiser. context.replace(CSSM_ATTRIBUTE_KEY, myKey(key).cssmKey()); CssmClient::Digest ctx(Server::csp(), context.algorithm()); ctx.override(context); - return ctx.getOutputSize(inputSize, encrypt); -} - - -// -// (Re-)Authenticate the database. This changes the stored credentials. -// -void LocalDatabase::authenticate(const AccessCredentials *cred) -{ - StLock _(common()); - AccessCredentials *newCred = DataWalkers::copy(cred, Allocator::standard()); - Allocator::standard().free(mCred); - mCred = newCred; + result = ctx.getOutputSize(inputSize, encrypt); } diff --git a/src/localdatabase.h b/src/localdatabase.h index 74553a4..7e1f53f 100644 --- a/src/localdatabase.h +++ b/src/localdatabase.h @@ -3,8 +3,6 @@ * * @APPLE_LICENSE_HEADER_START@ * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. - * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in @@ -49,7 +47,7 @@ public: public: //void releaseKey(Key &key); - CSSM_KEY_SIZE queryKeySize(Key &key); + void queryKeySizeInBits(Key &key, CssmKeySize &result); // service calls void generateSignature(const Context &context, Key &key, CSSM_ALGORITHMS signOnlyAlgorithm, @@ -66,32 +64,29 @@ public: void generateKey(const Context &context, const AccessCredentials *cred, const AclEntryPrototype *owner, - uint32 usage, uint32 attrs, RefPointer &newKey); + CSSM_KEYUSE usage, CSSM_KEYATTR_FLAGS attrs, RefPointer &newKey); void generateKey(const Context &context, const AccessCredentials *cred, const AclEntryPrototype *owner, - uint32 pubUsage, uint32 pubAttrs, uint32 privUsage, uint32 privAttrs, + CSSM_KEYUSE pubUsage, CSSM_KEYATTR_FLAGS pubAttrs, + CSSM_KEYUSE privUsage, CSSM_KEYATTR_FLAGS privAttrs, RefPointer &publicKey, RefPointer &privateKey); - RefPointer deriveKey(const Context &context, Key *key, + void deriveKey(const Context &context, Key *key, const AccessCredentials *cred, const AclEntryPrototype *owner, - CssmData *param, uint32 usage, uint32 attrs); + CssmData *param, uint32 usage, uint32 attrs, RefPointer &derivedKey); - void wrapKey(const Context &context, Key *key, - Key &keyToBeWrapped, const AccessCredentials *cred, + void wrapKey(const Context &context, const AccessCredentials *cred, + Key *wrappingKey, Key &keyToBeWrapped, const CssmData &descriptiveData, CssmKey &wrappedKey); - RefPointer unwrapKey(const Context &context, Key *key, + void unwrapKey(const Context &context, const AccessCredentials *cred, const AclEntryPrototype *owner, - uint32 usage, uint32 attrs, const CssmKey wrappedKey, - Key *publicKey, CssmData *descriptiveData); + Key *wrappingKey, Key *publicKey, CSSM_KEYUSE usage, CSSM_KEYATTR_FLAGS attrs, + const CssmKey wrappedKey, RefPointer &unwrappedKey, CssmData &descriptiveData); - uint32 getOutputSize(const Context &context, Key &key, uint32 inputSize, bool encrypt = true); - + void getOutputSize(const Context &context, Key &key, uint32 inputSize, bool encrypt, uint32 &result); + protected: virtual RefPointer makeKey(const CssmKey &newKey, uint32 moreAttributes, const AclEntryPrototype *owner) = 0; - -public: - // encoding/decoding databases - void authenticate(const AccessCredentials *cred); }; #endif //_H_LOCALDATABASE diff --git a/src/localkey.cpp b/src/localkey.cpp index 4550d60..e50d82f 100644 --- a/src/localkey.cpp +++ b/src/localkey.cpp @@ -3,8 +3,6 @@ * * @APPLE_LICENSE_HEADER_START@ * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. - * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in @@ -36,35 +34,26 @@ // // Create a Key from an explicit CssmKey. // -LocalKey::LocalKey(Database &db, const CssmKey &newKey, uint32 moreAttributes, - const AclEntryPrototype *owner) - : mDigest(Server::csp().allocator()) +LocalKey::LocalKey(Database &db, const CssmKey &newKey, CSSM_KEYATTR_FLAGS moreAttributes) + : Key(db), mDigest(Server::csp().allocator()) { - referent(db); mValidKey = true; setup(newKey, moreAttributes); - - // establish initial ACL; reinterpret empty (null-list) owner as NULL for resilence's sake - if (owner && !owner->subject().empty()) - cssmSetInitial(*owner); // specified - else - cssmSetInitial(new AnyAclSubject()); // defaulted secdebug("SSkey", "%p (handle 0x%lx) created from key alg=%ld use=0x%lx attr=0x%lx db=%p", this, handle(), mKey.header().algorithm(), mKey.header().usage(), mAttributes, &db); } -LocalKey::LocalKey(Database &db) - : mValidKey(false), mAttributes(0), mDigest(Server::csp().allocator()) +LocalKey::LocalKey(Database &db, CSSM_KEYATTR_FLAGS attributes) + : Key(db), mValidKey(false), mAttributes(attributes), mDigest(Server::csp().allocator()) { - referent(db); } // // Set up the CssmKey part of this Key according to instructions. // -void LocalKey::setup(const CssmKey &newKey, uint32 moreAttributes) +void LocalKey::setup(const CssmKey &newKey, CSSM_KEYATTR_FLAGS moreAttributes) { mKey = CssmClient::Key(Server::csp(), newKey, false); CssmKey::Header &header = mKey->header(); @@ -90,6 +79,16 @@ LocalKey::~LocalKey() } +void LocalKey::setOwner(const AclEntryPrototype *owner) +{ + // establish initial ACL; reinterpret empty (null-list) owner as NULL for resilence's sake + if (owner && !owner->subject().empty()) + acl().cssmSetInitial(*owner); // specified + else + acl().cssmSetInitial(new AnyAclSubject()); // defaulted +} + + LocalDatabase &LocalKey::database() const { return referent(); @@ -110,13 +109,22 @@ CssmClient::Key LocalKey::keyValue() } +// +// Return external key attributees +// +CSSM_KEYATTR_FLAGS LocalKey::attributes() +{ + return mAttributes; +} + + // // Return a key's handle and header in external form // void LocalKey::returnKey(Handle &h, CssmKey::Header &hdr) { // return handle - h = handle(); + h = this->handle(); // obtain the key header, from the valid key or the blob if no valid key if (mValidKey) { @@ -162,3 +170,21 @@ void LocalKey::getHeader(CssmKey::Header &) { assert(false); } + + +// +// Form a KeySpec with checking and masking +// +LocalKey::KeySpec::KeySpec(CSSM_KEYUSE usage, CSSM_KEYATTR_FLAGS attrs) + : CssmClient::KeySpec(usage, (attrs & ~managedAttributes) | forcedAttributes) +{ + if (attrs & generatedAttributes) + CssmError::throwMe(CSSMERR_CSP_INVALID_KEYATTR_MASK); +} + +LocalKey::KeySpec::KeySpec(CSSM_KEYUSE usage, CSSM_KEYATTR_FLAGS attrs, const CssmData &label) + : CssmClient::KeySpec(usage, (attrs & ~managedAttributes) | forcedAttributes, label) +{ + if (attrs & generatedAttributes) + CssmError::throwMe(CSSMERR_CSP_INVALID_KEYATTR_MASK); +} diff --git a/src/localkey.h b/src/localkey.h index f2b47bd..adc1d63 100644 --- a/src/localkey.h +++ b/src/localkey.h @@ -3,8 +3,6 @@ * * @APPLE_LICENSE_HEADER_START@ * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. - * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in @@ -39,22 +37,29 @@ class LocalDatabase; // -// A Key object represents a CSSM_KEY known to the SecurityServer. -// We give each Key a handle that allows our clients to access it, while we use -// the Key's ACL to control such accesses. -// A Key can be used by multiple Connections. Whether more than one Key can represent -// the same actual key object is up to the CSP we use, so let's be tolerant about that. +// A LocalKey object represents a CssmKey known to securityd. This subclass of Key is the +// parent of all Key objects that rely on local storage of the raw key matter. Cryptographic +// operations are performed by a local CSP within securityd's address space. +// +// LocalKeys are paired with LocalDatabases; LocalKey subclasses must be produced by, and must +// belong to, subclasses of LocalDatabase. +// +// LocalKeys implement their ACLs with a local evaluation machine that does not rely on an outside +// agent for evaluation. It is still possible for different subclasses of LocalDatabase to host +// their ObjectAcl instances at different globality layers. // -// A note on key attributes: We keep two sets of attribute bits. The internal bits are used -// when talking to our CSP; the external bits are used when negotiating with our client(s). -// The difference is the bits in managedAttributes, which relate to persistent key storage -// and are not digestible by our CSP. The internal attributes are kept in mKey. The external -// ones are kept in mAttributes. +// Since the local CSP refuses to deal with storage-related key attributes, we split the keys's +// CSSM_KEY_ATTRBITS into two parts: +// (*) The KeyHeader.attributes() contain attributes as seen by the local CSP. +// (*) The local mAttributes member contains attributes as seen by the client. +// The two are related by a simple formula: take the external attributes, remove the global-storage +// bits, add the EXTRACTABLE bit (so securityd itself can get at the key matter), and use that in +// the CssmKey. The reverse transition is done on the way out. A local subclass of KeySpec is used +// to make this more consistent. Just follow the pattern. // class LocalKey : public Key { public: - LocalKey(Database &db, const CssmKey &newKey, uint32 moreAttributes, - const AclEntryPrototype *owner = NULL); + LocalKey(Database &db, const CssmKey &newKey, uint32 moreAttributes); virtual ~LocalKey(); LocalDatabase &database() const; @@ -72,14 +77,31 @@ public: // generate the canonical key digest const CssmData &canonicalDigest(); - CSSM_KEYATTR_FLAGS attributes() { return mAttributes; } + CSSM_KEYATTR_FLAGS attributes(); + +public: + // key attributes that should not be passed on to the CSP + static const CSSM_KEYATTR_FLAGS managedAttributes = KeyBlob::managedAttributes; + // these attributes are "forced on" in internal keys (but not always in external attributes) + static const CSSM_KEYATTR_FLAGS forcedAttributes = KeyBlob::forcedAttributes; + // these attributes are internally generated, and invalid on input + static const CSSM_KEYATTR_FLAGS generatedAttributes = + CSSM_KEYATTR_ALWAYS_SENSITIVE | CSSM_KEYATTR_NEVER_EXTRACTABLE; + + // a version of KeySpec that self-checks and masks for CSP operation + class KeySpec : public CssmClient::KeySpec { + public: + KeySpec(CSSM_KEYUSE usage, CSSM_KEYATTR_FLAGS attrs); + KeySpec(CSSM_KEYUSE usage, CSSM_KEYATTR_FLAGS attrs, const CssmData &label); + }; private: - void setup(const CssmKey &newKey, uint32 attrs); + void setup(const CssmKey &newKey, CSSM_KEYATTR_FLAGS attrs); CssmClient::Key keyValue(); protected: - LocalKey(Database &db); + LocalKey(Database &db, CSSM_KEYATTR_FLAGS attributes); + void setOwner(const AclEntryPrototype *owner); virtual void getKey(); // decode into mKey or throw virtual void getHeader(CssmKey::Header &hdr); // get header (only) without mKey diff --git a/src/main.cpp b/src/main.cpp index d765ec8..ef34365 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -3,8 +3,6 @@ * * @APPLE_LICENSE_HEADER_START@ * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. - * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in @@ -29,23 +27,24 @@ // #include -#include "securityserver.h" #include "server.h" #include "entropy.h" - -#include -#include #include "authority.h" #include "session.h" #include "pcscmonitor.h" +#include "self.h" -#include +#include #include +#include +#include +#include +#include #include #include +#include -#include // #define PERFORMANCE_MEASUREMENT 1 @@ -56,37 +55,27 @@ // ACL subject types (their makers are instantiated here) #include #include +#include #include #include #include #include #include -#include +#include #include "acl_keychain.h" -namespace Security -{ - -// -// Program options (set by argument scan and environment) -// -uint32 debugMode = 0; -const char *bootstrapName = NULL; - -} // end namespace Security - - // // Local functions of the main program driver // -static void usage(const char *me); -static void handleSIGCHLD(int); -static void handleSIGOther(int); -IFDEBUG(static void handleSIGdebug(int)); +static void usage(const char *me) __attribute__((noreturn)); +static void handleSignals(int sig); +static PCSCMonitor::ServiceLevel scOptions(const char *optionString); + static Port gMainServerPort; + // // Main driver // @@ -98,28 +87,38 @@ int main(int argc, char *argv[]) #endif Debug::trace (kSecTraceSecurityServerStart); + + // clear the umask - we know what we're doing + secdebug("SS", "starting umask was 0%o", ::umask(0)); + ::umask(0); // program arguments (preset to defaults) + bool debugMode = false; + const char *bootstrapName = NULL; bool doFork = false; - bool forceCssmInit = false; bool reExecute = false; int workerTimeout = 0; int maxThreads = 0; const char *authorizationConfig = "/etc/authorization"; + const char *tokenCacheDir = "/var/db/TokenCache"; const char *entropyFile = "/var/db/SystemEntropyCache"; const char *equivDbFile = EQUIVALENCEDBPATH; + const char *smartCardOptions = getenv("SMARTCARDS"); // parse command line arguments extern char *optarg; extern int optind; int arg; - while ((arg = getopt(argc, argv, "a:de:E:fN:t:T:X")) != -1) { + while ((arg = getopt(argc, argv, "a:c:de:E:fN:s:t:T:X")) != -1) { switch (arg) { case 'a': authorizationConfig = optarg; break; + case 'c': + tokenCacheDir = optarg; + break; case 'd': - debugMode++; + debugMode = true; break; case 'e': equivDbFile = optarg; @@ -128,11 +127,14 @@ int main(int argc, char *argv[]) entropyFile = optarg; break; case 'f': - forceCssmInit = true; + fprintf(stderr, "%s: the -f option is obsolete\n", argv[0]); break; case 'N': bootstrapName = optarg; break; + case 's': + smartCardOptions = optarg; + break; case 't': if ((maxThreads = atoi(optarg)) < 0) maxThreads = 0; @@ -155,16 +157,16 @@ int main(int argc, char *argv[]) usage(argv[0]); // figure out the bootstrap name - IFDEBUG(if (!bootstrapName) bootstrapName = getenv(SECURITYSERVER_BOOTSTRAP_ENV)); - - if (!bootstrapName) { - bootstrapName = SECURITYSERVER_BOOTSTRAP_NAME; + if (!bootstrapName) { + bootstrapName = getenv(SECURITYSERVER_BOOTSTRAP_ENV); + if (!bootstrapName) + bootstrapName = SECURITYSERVER_BOOTSTRAP_NAME; } - + // configure logging first if (debugMode) { Syslog::open(bootstrapName, LOG_AUTHPRIV, LOG_PERROR); - Syslog::notice("SecurityServer started in debug mode"); + Syslog::notice("%s started in debug mode", argv[0]); } else { Syslog::open(bootstrapName, LOG_AUTHPRIV, LOG_CONS); } @@ -183,13 +185,25 @@ int main(int argc, char *argv[]) } // turn into a properly diabolical daemon unless debugMode is on - if (!debugMode) { + if (!debugMode && getppid() != 1) { if (!Daemon::incarnate(doFork)) exit(1); // can't daemonize if (reExecute && !Daemon::executeSelf(argv)) exit(1); // can't self-execute } + + // arm signal handlers; code below may generate signals we want to see + if (signal(SIGCHLD, handleSignals) == SIG_ERR) + secdebug("SS", "Cannot handle SIGCHLD: errno=%d", errno); + if (signal(SIGINT, handleSignals) == SIG_ERR) + secdebug("SS", "Cannot handle SIGINT: errno=%d", errno); + if (signal(SIGTERM, handleSignals) == SIG_ERR) + secdebug("SS", "Cannot handle SIGTERM: errno=%d", errno); +#if !defined(NDEBUG) + if (signal(SIGUSR1, handleSignals) == SIG_ERR) + secdebug("SS", "Cannot handle SIGHUP: errno=%d", errno); +#endif //NDEBUG // create a code signing engine CodeSigning::OSXSigner signer; @@ -201,15 +215,14 @@ int main(int argc, char *argv[]) new AnyAclSubject::Maker(); new PasswordAclSubject::Maker(); new ProtectedPasswordAclSubject::Maker(); + new PromptedAclSubject::Maker(); new ThresholdAclSubject::Maker(); new CommentAclSubject::Maker(); new ProcessAclSubject::Maker(); new CodeSignatureAclSubject::Maker(signer); new KeychainPromptAclSubject::Maker(); - - // add a temporary registration for a subject type that went out in 10.2 seed 1 - // this should probably be removed for the next major release >10.2 - new KeychainPromptAclSubject::Maker(CSSM_WORDID__RESERVED_1); + new PreAuthorizationAcls::OriginMaker(); + new PreAuthorizationAcls::SourceMaker(); // establish the code equivalents database CodeSignatures codeSignatures(equivDbFile); @@ -217,7 +230,7 @@ int main(int argc, char *argv[]) // create the main server object and register it Server server(authority, codeSignatures, bootstrapName); - // Remember the primary service port to send signal events to. + // Remember the primary service port to send signal events to gMainServerPort = server.primaryServicePort(); // set server configuration from arguments, if specified @@ -226,39 +239,33 @@ int main(int argc, char *argv[]) if (maxThreads) server.maxThreads(maxThreads); - // add the RNG seed timer to it + // add the RNG seed timer # if defined(NDEBUG) EntropyManager entropy(server, entropyFile); # else - if (!getuid()) new EntropyManager(server, entropyFile); + if (getuid() == 0) new EntropyManager(server, entropyFile); # endif + + // create a token-cache interface +#if !defined(NDEBUG) + if (const char *s = getenv("TOKENCACHE")) + tokenCacheDir = s; +#endif //NDEBUG + TokenCache tokenCache(tokenCacheDir); - // create smartcard monitors to manage external token devices - PCSCMonitor secureCards(server); + // create a smartcard monitor to manage external token devices + PCSCMonitor secureCards(server, tokenCache, scOptions(smartCardOptions)); // create the RootSession object (if -d, give it graphics and tty attributes) - RootSession rootSession(server.primaryServicePort(), + RootSession rootSession(server, debugMode ? (sessionHasGraphicAccess | sessionHasTTY) : 0); - - // set up signal handlers - if (signal(SIGCHLD, handleSIGCHLD) == SIG_ERR) - secdebug("SS", "Cannot handle SIGCHLD: errno=%d", errno); - if (signal(SIGINT, handleSIGOther) == SIG_ERR) - secdebug("SS", "Cannot handle SIGINT: errno=%d", errno); - if (signal(SIGTERM, handleSIGOther) == SIG_ERR) - secdebug("SS", "Cannot handle SIGTERM: errno=%d", errno); -#if !defined(NDEBUG) - if (signal(SIGUSR1, handleSIGdebug) == SIG_ERR) - secdebug("SS", "Cannot handle SIGHUP: errno=%d", errno); -#endif //NDEBUG - // initialize CSSM now if requested - if (forceCssmInit) - server.loadCssm(); + // install MDS and initialize the local CSSM + server.loadCssm(); + // okay, we're ready to roll Syslog::notice("Entering service"); secdebug("SS", "%s initialized", bootstrapName); - Debug::trace (kSecTraceSecurityServerInitialized); #ifdef PERFORMANCE_MEASUREMENT @@ -283,6 +290,7 @@ int main(int argc, char *argv[]) fclose (f); #endif + // go server.run(); // fell out of runloop (should not happen) @@ -296,46 +304,49 @@ int main(int argc, char *argv[]) // static void usage(const char *me) { - fprintf(stderr, "Usage: %s [-df] [-t maxthreads] [-T threadTimeout]" - "\t[-N bootstrapName] [-a authConfigFile]\n", me); + fprintf(stderr, "Usage: %s [-dX]" + "\n\t[-a authConfigFile] Authorization configuration file" + "\n\t[-c tokencache] smartcard token cache directory" + "\n\t[-e equivDatabase] path to code equivalence database" + "\n\t[-N serviceName] MACH service name" + "\n\t[-s off|on|conservative|aggressive] smartcard operation level" + "\n\t[-t maxthreads] [-T threadTimeout] server thread control" + "\n", me); exit(2); } // -// Handle SIGCHLD signals to reap our children (zombie cleanup) +// Translate strings (e.g. "conservative") into PCSCMonitor service levels // -static void handleSIGCHLD(int signal_number) +static PCSCMonitor::ServiceLevel scOptions(const char *optionString) { - kern_return_t kt = ucsp_client_handleSignal(gMainServerPort, mach_task_self(), signal_number); - if (kt) - syslog(LOG_ERR, "ucsp_client_handleSignal returned: %d", kt); + if (optionString) + if (!strcmp(optionString, "off")) + return PCSCMonitor::forcedOff; + else if (!strcmp(optionString, "on")) + return PCSCMonitor::forcedOn; + else if (!strcmp(optionString, "conservative")) + return PCSCMonitor::conservative; + else if (!strcmp(optionString, "aggressive")) + return PCSCMonitor::aggressive; + else if (!strcmp(optionString, "external")) + return PCSCMonitor::externalDaemon; + else + usage("securityd"); + else + return PCSCMonitor::aggressive; } // -// Handle some other signals to shut down cleanly (and with logging) +// Handle signals. +// We send ourselves a message (through the "self" service), so actual +// actions happen on the normal event loop path. Note that another thread +// may be picking up the message immediately. // -static void handleSIGOther(int sig) +static void handleSignals(int sig) { - switch (sig) { - case SIGINT: - //secdebug("SS", "Interrupt signal; terminating"); - Syslog::notice("received interrupt signal; terminating"); - exit(0); - case SIGTERM: - //secdebug("SS", "Termination signal; terminating"); - Syslog::notice("received termination signal; terminating"); - exit(0); - } + if (kern_return_t rc = self_client_handleSignal(gMainServerPort, mach_task_self(), sig)) + Syslog::error("self-send failed (mach error %d)", rc); } - - -#if !defined(NDEBUG) - -static void handleSIGdebug(int) -{ - NodeCore::dumpAll(); -} - -#endif //NDEBUG diff --git a/src/notifications.cpp b/src/notifications.cpp index 2224dd9..0ac6a36 100644 --- a/src/notifications.cpp +++ b/src/notifications.cpp @@ -3,8 +3,6 @@ * * @APPLE_LICENSE_HEADER_START@ * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. - * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in @@ -121,7 +119,6 @@ void ProcessListener::notifyMe(NotificationDomain domain, // send mach message (via MIG simpleroutine) if (IFDEBUG(kern_return_t rc =) ucsp_notify_sender_notify(mPort, - MACH_SEND_TIMEOUT, 0, domain, event, data.data(), data.length(), 0 /*@@@ placeholder for sender ID */)) secdebug("notify", "%p send failed (error=%d)", this, rc); diff --git a/src/notifications.h b/src/notifications.h index 9a0ea92..115df09 100644 --- a/src/notifications.h +++ b/src/notifications.h @@ -3,8 +3,6 @@ * * @APPLE_LICENSE_HEADER_START@ * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. - * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in diff --git a/src/pcsc++.cpp b/src/pcsc++.cpp deleted file mode 100644 index 99d9655..0000000 --- a/src/pcsc++.cpp +++ /dev/null @@ -1,231 +0,0 @@ -/* - * Copyright (c) 2004 Apple Computer, Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - - -// -// pcsc++ - PCSC client interface layer in C++ -// -#include "pcsc++.h" -#include - - -namespace Security { -namespace PCSC { - - -// -// Internal utilities -// -static void decode(vector &names, const char *buffer, size_t size) -{ - names.clear(); - for (size_t pos = 0; pos < size - 1; ) { - size_t len = strlen(buffer + pos); - names.push_back(string(buffer + pos, len)); - pos += len + 1; - } -} - -inline void decode(vector &names, const vector &buffer, size_t size) -{ - decode(names, &buffer[0], size); -} - - -// -// PCSC domain errors -// -Error::Error(long err) : error(err) -{ - IFDEBUG(debugDiagnose(this)); -} - - -const char *Error::what() const throw () -{ - return pcsc_stringify_error(error); -} - - -void Error::throwMe(long err) -{ - throw Error(err); -} - - -OSStatus Error::osStatus() const -{ - return -1; //@@@ preliminary -} - -int Error::unixError() const -{ - return EINVAL; //@@@ preliminary -} - -#if !defined(NDEBUG) -void Error::debugDiagnose(const void *id) const -{ - secdebug("exception", "%p PCSC::Error %s (%ld) osStatus %ld", - id, pcsc_stringify_error(error), error, osStatus()); -} -#endif //NDEBUG - - -// -// PodWrappers -// -void ReaderState::set(const char *name, unsigned long known) -{ - clearPod(); - szReader = name; - pvUserData = NULL; - dwCurrentState = known; -} - - -void ReaderState::lastKnown(unsigned long s) -{ - // clear out CHANGED and UNAVAILABLE - dwCurrentState = s & ~(SCARD_STATE_CHANGED | SCARD_STATE_UNAVAILABLE); -} - - -#if defined(DEBUGDUMP) - -void ReaderState::dump() -{ - Debug::dump("reader(%s) state=0x%lx events=0x%lx", - szReader ? szReader : "(null)", dwCurrentState, dwEventState); - Debug::dumpData(" ATR", rgbAtr, cbAtr); -} - -#endif //DEBUGDUMP - - -// -// Session objects -// -Session::Session() - : mIsOpen(false) -{ - open(); -} - - -Session::~Session() -{ - if (mIsOpen) - Error::check(SCardReleaseContext(mContext)); -} - - -// -// (Re)establish PCSC context. -// Don't fail on SCARD_F_INTERNAL_ERROR (pcscd not running). -void Session::open() -{ - if (!mIsOpen) { - try { - Error::check(::SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &mContext)); - mIsOpen = true; - secdebug("pcsc", "context opened"); - } catch (const Error &err) { - if (err.error == long(SCARD_F_INTERNAL_ERROR)) { - secdebug("pcsc", "context not opened"); - return; - } - } - } -} - - -bool Session::check(long rc) -{ - switch (rc) { - case SCARD_S_SUCCESS: - return true; // got reader(s), call succeeded - case SCARD_E_READER_UNAVAILABLE: - return false; // no readers, but don't treat as error - default: - Error::throwMe(rc); - return false; // placebo - } -} - - -void Session::listReaders(vector &readers, const char *groups) -{ - mReaderBuffer.resize(1000); //@@@ preliminary hack - unsigned long size = mReaderBuffer.size(); - if (check(::SCardListReaders(mContext, groups, &mReaderBuffer[0], &size))) - decode(readers, mReaderBuffer, size); - else - readers.clear(); // treat as success (returning zero readers) -} - - -// -// Reader status check -// -void Session::statusChange(ReaderState *readers, unsigned int nReaders, long timeout) -{ - if (nReaders == 0) - return; // no readers, no foul - check(::SCardGetStatusChange(mContext, timeout, readers, nReaders)); -} - - -// -// PCSC Card objects -// -Card::Card() - : mIsOpen(false) -{ -} - -Card::~Card() -{ -} - -void Card::open(Session &session, const char *reader, - unsigned long share, unsigned long protocols) -{ - Error::check(::SCardConnect(session.mContext, - reader, share, protocols, &mHandle, &mProtocol)); - mIsOpen = true; -} - -void Card::close(unsigned long disposition) -{ - if (mIsOpen) { - Error::check(::SCardDisconnect(mHandle, disposition)); - mIsOpen = false; - } -} - - -} // namespace PCSC -} // namespace Security diff --git a/src/pcsc++.h b/src/pcsc++.h deleted file mode 100644 index 6c839aa..0000000 --- a/src/pcsc++.h +++ /dev/null @@ -1,152 +0,0 @@ -/* - * Copyright (c) 2004 Apple Computer, Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - - -// -// pcsc++ - PCSC client interface layer in C++ -// -// NOTE: TO BE MOVED TO security_utilities LAYER. -// -#ifndef _H_PCSC_PP -#define _H_PCSC_PP - -#include -#include -#include -#include -#include -#include - -#include - - -namespace Security { -namespace PCSC { - - -// -// PCSC-domain error exceptions -// -class Error : public CommonError { -public: - Error(long err); - - const long error; - OSStatus osStatus() const; - int unixError() const; - const char *what () const throw (); - - static void check(long err) { if (err != SCARD_S_SUCCESS) throwMe(err); } - static void throwMe(long err); - -private: - IFDEBUG(void debugDiagnose(const void *id) const); -}; - - -// -// A PODWrapper for the PCSC READERSTATE structure -// -class ReaderState : public PodWrapper { -public: - void set(const char *name, unsigned long known = SCARD_STATE_UNAWARE); - - const char *name() const { return szReader; } - void name(const char *s) { szReader = s; } - - unsigned long lastKnown() const { return dwCurrentState; } - void lastKnown(unsigned long s); - - unsigned long state() const { return dwEventState; } - bool state(unsigned long it) const { return state() & it; } - bool changed() const { return state(SCARD_STATE_CHANGED); } - - template - T * &userData() { return reinterpret_cast(pvUserData); } - - // DataOid access to the ATR data - const void *data() const { return rgbAtr; } - size_t length() const { return cbAtr; } - - IFDUMP(void dump()); -}; - - -// -// A Session represents the entire process state for the PCSC protocol -// -class Session { - friend class Card; -public: - Session(); - virtual ~Session(); - - void open(); - bool isOpen() const { return mIsOpen; } - - void listReaders(vector &readers, const char *groups = NULL); - - void statusChange(ReaderState *readers, unsigned int nReaders, - long timeout = 0); - void statusChange(vector &readers, long timeout = 0) - { statusChange(&readers[0], readers.size(), timeout); } - -private: - bool check(long rc); - -private: - bool mIsOpen; - SCARDCONTEXT mContext; - std::vector mReaderBuffer; -}; - - -// -// A Card represents a PCSC-managed card slot -// -class Card { -public: - static const unsigned long defaultProtocols = SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1; - - Card(); - ~Card(); - - void open(Session &session, const char *reader, - unsigned long share = SCARD_SHARE_SHARED, - unsigned long protocols = defaultProtocols); - void close(unsigned long disposition = SCARD_LEAVE_CARD); - -private: - bool mIsOpen; - long mHandle; - unsigned long mProtocol; -}; - - -} // namespce PCSC -} // namespace Security - - -#endif //_H_PCSC_PP diff --git a/src/pcscmonitor.cpp b/src/pcscmonitor.cpp index bd98ce2..47a0eef 100644 --- a/src/pcscmonitor.cpp +++ b/src/pcscmonitor.cpp @@ -3,8 +3,6 @@ * * @APPLE_LICENSE_HEADER_START@ * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. - * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in @@ -28,55 +26,66 @@ // pcscmonitor - use PCSC to monitor smartcard reader/card state for securityd // // PCSCMonitor is the "glue" between PCSC and the securityd objects representing -// smartcard-related things. Its job is to translate real-world events into -// securityd-speak. -// Inputs are primarily security notifications sent from pcscd. We can also use -// MachServer-based timers to do things periodically or after some delay, though -// periodic actions are discouraged for the obvious reasons. +// smartcard-related things. Its job is to manage the daemon and translate real-world +// events (such as card and device insertions) into the securityd object web. +// +// PCSCMonitor uses multiple inheritance to the hilt. It is (among others) +// (*) A notification listener, to listen to pcscd state notifications +// (*) A MachServer::Timer, to handle timed actions +// (*) A NotificationPort::Receiver, to get IOKit notifications of device insertions +// (*) A Child, to watch and manage the pcscd process // #include "pcscmonitor.h" +#include +#include + + +// +// Fixed configuration parameters +// +static const char PCSCD_EXEC_PATH[] = "/usr/sbin/pcscd"; // override with $PCSCDAEMON +static const char PCSCD_WORKING_DIR[] = "/var/run/pcscd"; // pcscd's working directory +static const Time::Interval PCSCD_IDLE_SHUTDOWN(120); // kill daemon if no devices present // // Construct a PCSCMonitor. // We strongly assume there's only one of us around here. // -// Note that by construction, we *are* a notification Listener. -// The (unique index) port we use is zero (the null port), since we're -// not actually delivering the event anywhere (else). +// Note that this constructor may well run before the server loop has started. +// Don't call anything here that requires an active server loop (like Server::active()). +// In fact, you should push all the hard work into a timer, so as not to hold up the +// general startup process. // -PCSCMonitor::PCSCMonitor(Server &srv) +PCSCMonitor::PCSCMonitor(Server &srv, TokenCache &tc, ServiceLevel level) : Listener(kNotificationDomainPCSC, SecurityServer::kNotificationAllEvents), - server(srv) -{ - // initial reader poll - if (mSession.isOpen()) { - pollReaders(); -// server.setTimer(this, Time::Interval(5)); - - // setup complete - secdebug("sc", "pcsc monitor initialized"); - } -} - - -PCSCMonitor::~PCSCMonitor() + MachServer::Timer(true), // "heavy" timer task + server(srv), cache(tc), + mServiceLevel(level), + mTimerAction(&PCSCMonitor::initialSetup), + mGoingToSleep(false) { + // do all the smartcard-related work once the event loop has started + server.setTimer(this, Time::now()); // ASAP } // -// (Re)poll PCSC for smartcard status +// Poll PCSC for smartcard status. +// We are enumerating all readers on each call. // void PCSCMonitor::pollReaders() { + // open PCSC session if it's not already open + mSession.open(); + // enumerate readers vector names; // will hold reader name C strings throughout mSession.listReaders(names); size_t count = names.size(); - secdebug("sc", "%ld reader(s) in system", count); + secdebug("pcsc", "%ld reader(s) in system", count); - // inquire into reader state + // build the PCSC status inquiry array vector states(count); // reader status array (PCSC style) for (unsigned int n = 0; n < count; n++) { PCSC::ReaderState &state = states[n]; @@ -93,15 +102,17 @@ void PCSCMonitor::pollReaders() state.userData() = it->second; } } + + // now ask PCSC for status changes mSession.statusChange(states); #if DEBUGDUMP - if (Debug::dumping("sc")) + if (Debug::dumping("pcsc")) for (unsigned int n = 0; n < count; n++) states[n].dump(); #endif - // make set of previously known reader objects (to catch those who disappeared) - set current; + // make a set of previously known reader objects (to catch those who disappeared) + ReaderSet current; copy_second(mReaders.begin(), mReaders.end(), inserter(current, current.end())); // match state array against them @@ -114,20 +125,68 @@ void PCSCMonitor::pollReaders() // accounted for this reader current.erase(reader); } else { - RefPointer newReader = new Reader(state); + RefPointer newReader = new Reader(cache, state); mReaders.insert(make_pair(state.name(), newReader)); + Syslog::notice("Token reader %s inserted into system", state.name()); + newReader->update(state); // initial state setup } } - // now deal with dead readers - for (set::iterator it = current.begin(); it != current.end(); it++) { - secdebug("sc", "killing reader %s", (*it)->name().c_str()); + // now deal with vanished readers + for (ReaderSet::iterator it = current.begin(); it != current.end(); it++) { + secdebug("pcsc", "removing reader %s", (*it)->name().c_str()); + Syslog::notice("Token reader %s removed from system", (*it)->name().c_str()); (*it)->kill(); // prepare to die mReaders.erase((*it)->name()); // remove from reader map } } +void PCSCMonitor::launchPcscd() +{ + // launch pcscd + secdebug("pcsc", "launching pcscd to handle smartcard device(s)"); + assert(Child::state() != alive); + Child::reset(); + Child::fork(); + + // if pcscd doesn't report a reader found soon, we'll kill it off + server.setTimer(this, PCSCD_IDLE_SHUTDOWN); +} + + +// +// Code to launch pcscd (run in child as a result of Child::fork()) +// +void PCSCMonitor::childAction() +{ + // move aside any old play area + const char *aside = tempnam("/tmp", "pcscd"); + if (::rename(PCSCD_WORKING_DIR, aside)) + switch (errno) { + case ENOENT: // no /tmp/pcsc (fine) + break; + default: + secdebug("pcsc", "failed too move %s - errno=%d", PCSCD_WORKING_DIR, errno); + _exit(101); + } + else + secdebug("pcsc", "old /tmp/pcsc moved to %s", aside); + + // lessen the pain for debugging +#if !defined(NDEBUG) + freopen("/tmp/pcsc.debuglog", "a", stdout); // shut up pcsc dumps to stdout +#endif //NDEBUG + + // execute the daemon + const char *pcscdPath = PCSCD_EXEC_PATH; + if (const char *env = getenv("PCSCDAEMON")) + pcscdPath = env; + secdebug("pcsc", "exec(%s,-f)", pcscdPath); + execl(pcscdPath, pcscdPath, "-f", NULL); +} + + // // Event notifier. // These events are sent by pcscd for our (sole) benefit. @@ -135,10 +194,31 @@ void PCSCMonitor::pollReaders() void PCSCMonitor::notifyMe(SecurityServer::NotificationDomain domain, SecurityServer::NotificationEvent event, const CssmData &data) { - //@@@ need some kind of locking, of course... + Server::active().longTermActivity(); + StLock _(*this); + assert(mServiceLevel == externalDaemon || Child::state() == alive); pollReaders(); - //server.setTimer(this, Time::Interval(0.5)); - //secdebug("adhoc", "pcsc change event"); + scheduleTimer(mReaders.empty() && !mGoingToSleep); +} + + +// +// Power event notifications +// +void PCSCMonitor::systemWillSleep() +{ + StLock _(*this); + secdebug("pcsc", "setting sleep marker (%ld readers as of now)", mReaders.size()); + mGoingToSleep = true; + server.clearTimer(this); +} + +void PCSCMonitor::systemIsWaking() +{ + StLock _(*this); + secdebug("pcsc", "clearing sleep marker (%ld readers as of now)", mReaders.size()); + mGoingToSleep = false; + scheduleTimer(mReaders.empty()); } @@ -147,5 +227,165 @@ void PCSCMonitor::notifyMe(SecurityServer::NotificationDomain domain, // void PCSCMonitor::action() { - // not used at the moment; timer is not scheduled + StLock _(*this); + (this->*mTimerAction)(); + mTimerAction = &PCSCMonitor::noDeviceTimeout; +} + + +// +// Update the timeout timer as requested (and indicated by context) +// +void PCSCMonitor::scheduleTimer(bool enable) +{ + if (Child::state() == alive) // we ran pcscd; let's manage it + if (enable) { + secdebug("pcsc", "setting idle timer for %g seconds", PCSCD_IDLE_SHUTDOWN.seconds()); + server.setTimer(this, PCSCD_IDLE_SHUTDOWN); + } else if (Timer::scheduled()) { + secdebug("pcsc", "clearing idle timer"); + server.clearTimer(this); + } +} + + +// +// Perform the initial PCSC subsystem initialization. +// This runs (shortly) after securityd is fully functional and the +// server loop as started. +// +void PCSCMonitor::initialSetup() +{ + switch (mServiceLevel) { + case forcedOff: + secdebug("pcsc", "smartcard operation is FORCED OFF"); + break; + + case forcedOn: + secdebug("pcsc", "pcscd launch is forced on"); + launchPcscd(); + break; + + case externalDaemon: + secdebug("pcsc", "using external pcscd (if any); no launch operations"); + break; + + default: + secdebug("pcsc", "setting up automatic PCSC management in %s mode", + mServiceLevel == conservative ? "conservative" : "aggressive"); + + // receive Mach-based IOKit notifications through mIOKitNotifier + server.add(mIOKitNotifier); + + // receive power event notifications (through our IOPowerWatcher personality) + server.add(this); + + // ask for IOKit notifications for all new USB devices and process present ones + IOKit::DeviceMatch usbSelector(kIOUSBInterfaceClassName); + IOKit::DeviceMatch pcCardSelector("IOPCCard16Device"); + mIOKitNotifier.add(usbSelector, *this); // this will scan existing USB devices + mIOKitNotifier.add(pcCardSelector, *this); // ditto for PC Card devices + } + + // we are NOT scanning for PCSC devices here. Pcscd will send us a notification when it's up +} + + +// +// This function is called (as a timer function) when there haven't been any (recognized) +// smartcard devicees in the system for a while. +// +void PCSCMonitor::noDeviceTimeout() +{ + secdebug("pcsc", "killing pcscd (no smartcard devices present for %g seconds)", + PCSCD_IDLE_SHUTDOWN.seconds()); + assert(mReaders.empty()); + Child::kill(SIGTERM); +} + + +// +// IOKit device event notification. +// Here we listen for newly inserted devices and check whether to launch pcscd. +// +void PCSCMonitor::ioChange(IOKit::DeviceIterator &iterator) +{ + assert(mServiceLevel != externalDaemon && mServiceLevel != forcedOff); + if (Child::state() == alive) { + secdebug("pcsc", "pcscd is alive; ignoring device insertion(s)"); + return; + } + secdebug("pcsc", "processing device insertion notices"); + while (IOKit::Device dev = iterator()) { + bool launch = false; + switch (deviceSupport(dev)) { + case definite: + launch = true; + break; + case possible: + launch = (mServiceLevel == aggressive); + break; + case impossible: + break; + } + if (launch) { + launchPcscd(); + return; + } + } + secdebug("pcsc", "no relevant devices found"); +} + + +// +// Check an IOKit device that's just come online to see if it's +// a smartcard device of some sort. +// +PCSCMonitor::DeviceSupport PCSCMonitor::deviceSupport(const IOKit::Device &dev) +{ + try { + secdebug("scsel", "%s", dev.path().c_str()); + CFRef cfClass(dev.property("bInterfaceClass")); + if (!cfClass) { + secdebug("scsel", " device without device class (ignored)"); + return impossible; + } + switch (IFDEBUG(uint32 clas =) cfNumber(cfClass)) { + case kUSBChipSmartCardInterfaceClass: // CCID smartcard reader - go + secdebug("scsel", " CCID smartcard reader recognized"); + return definite; + case kUSBVendorSpecificInterfaceClass: + secdebug("scsel", " Vendor-specific device - possible match"); + return possible; + default: + secdebug("scsel", " class %ld is not a smartcard device", clas); + return impossible; + } + } catch (...) { + secdebug("scsel", " exception while examining device - ignoring it"); + return impossible; + } +} + + +// +// This gets called (by the Unix/Child system) when pcscd has died for any reason +// +void PCSCMonitor::dying() +{ + Server::active().longTermActivity(); + StLock _(*this); + assert(Child::state() == dead); + if (!mReaders.empty()) { + // uh-oh. We had readers connected when pcscd suddenly left + secdebug("pcsc", "%ld readers were present when pcscd died", mReaders.size()); + for (ReaderMap::const_iterator it = mReaders.begin(); it != mReaders.end(); it++) { + Reader *reader = it->second; + secdebug("pcsc", "removing reader %s", reader->name().c_str()); + reader->kill(); // prepare to die + } + mReaders.erase(mReaders.begin(), mReaders.end()); + secdebug("pcsc", "orphaned readers cleared"); + } + //@@@ this is where we would attempt a restart, if we wanted to... } diff --git a/src/pcscmonitor.h b/src/pcscmonitor.h index fee7b4c..6ef6328 100644 --- a/src/pcscmonitor.h +++ b/src/pcscmonitor.h @@ -3,8 +3,6 @@ * * @APPLE_LICENSE_HEADER_START@ * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. - * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in @@ -30,12 +28,15 @@ #ifndef _H_PCSCMONITOR #define _H_PCSCMONITOR -#include "securityserver.h" #include "server.h" +#include "tokencache.h" #include "reader.h" #include "token.h" #include "notifications.h" -#include "pcsc++.h" +#include +#include +#include +#include #include @@ -45,26 +46,72 @@ // various related players in securityd. There should be at most one of these // objects active within securityd. // -class PCSCMonitor : private Listener, private MachServer::Timer { +class PCSCMonitor : private Listener, + private MachServer::Timer, + private IOKit::NotificationPort::Receiver, + private MachPlusPlus::PowerWatcher, + private UnixPlusPlus::Child, + private Mutex { public: - PCSCMonitor(Server &server); - virtual ~PCSCMonitor(); + enum ServiceLevel { + forcedOff, // no service under any circumstances + conservative, // launch pcscd for certain smartcard devices + aggressive, // launch pcscd for possible smartcard devices + forcedOn, // keep pcscd running at all times + externalDaemon // use externally launched daemon + }; + + PCSCMonitor(Server &server, TokenCache &cache, ServiceLevel level = conservative); protected: void pollReaders(); + Server &server; + TokenCache &cache; + +protected: + // Listener void notifyMe(SecurityServer::NotificationDomain domain, SecurityServer::NotificationEvent event, const CssmData &data); + // MachServer::Timer void action(); - Server &server; + // NotificationPort::Receiver + void ioChange(IOKit::DeviceIterator &iterator); + + // PowerWatcher + void systemWillSleep(); + void systemIsWaking(); + + // Unix++/Child + void childAction(); + void dying(); + +protected: + void launchPcscd(); + void scheduleTimer(bool enable); + void initialSetup(); + void noDeviceTimeout(); + + enum DeviceSupport { + impossible, // certain this is not a smartcard + definite, // definitely a smartcard device + possible // perhaps... we're not sure + }; + DeviceSupport deviceSupport(const IOKit::Device &dev); private: - PCSC::Session mSession; + ServiceLevel mServiceLevel; // level of service requested/determined + void (PCSCMonitor::*mTimerAction)(); // what to do when our timer fires + bool mGoingToSleep; // between sleep and wakeup; special timer handling + + PCSC::Session mSession; // PCSC client session + IOKit::MachPortNotificationPort mIOKitNotifier; // IOKit connection typedef map > ReaderMap; - ReaderMap mReaders; + typedef set > ReaderSet; + ReaderMap mReaders; // presently known PCSC Readers (aka slots) }; diff --git a/src/process.cpp b/src/process.cpp index 7dce80d..87caf65 100644 --- a/src/process.cpp +++ b/src/process.cpp @@ -3,8 +3,6 @@ * * @APPLE_LICENSE_HEADER_START@ * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. - * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in @@ -39,50 +37,89 @@ // Construct a Process object. // Process::Process(Port servicePort, TaskPort taskPort, - const ClientSetupInfo *info, const char *identity, uid_t uid, gid_t gid) - : mTaskPort(taskPort), mByteFlipped(false), mUid(uid), mGid(gid), - mClientIdent(deferred) + const ClientSetupInfo *info, const char *identity, const CommonCriteria::AuditToken &audit) + : mTaskPort(taskPort), mByteFlipped(false), mPid(audit.pid()), mUid(audit.euid()), mGid(audit.egid()) { - // examine info passed - assert(info); - uint32 pversion = info->version; - if (pversion == SSPROTOVERSION) { - // correct protocol, same byte order, cool - } else { - Flippers::flip(pversion); - if (pversion == SSPROTOVERSION) { - // correct protocol, reversed byte order - mByteFlipped = true; - } else { - // unsupported protocol version - CssmError::throwMe(CSSM_ERRCODE_INCOMPATIBLE_VERSION); - } - } - // set parent session parent(Session::find(servicePort)); // let's take a look at our wannabe client... - mPid = mTaskPort.pid(); + if (mTaskPort.pid() != mPid) { + secdebug("SS", "Task/pid setup mismatch pid=%d task=%d(%d) for %s", + mPid, mTaskPort.port(), mTaskPort.pid(), + (identity && identity[0]) ? identity : "(unknown)"); + CssmError::throwMe(CSSMERR_CSSM_ADDIN_AUTHENTICATE_FAILED); // you lied! + } + + setup(info, identity); secdebug("SS", "New process %p(%d) uid=%d gid=%d session=%p TP=%d %sfor %s", this, mPid, mUid, mGid, &session(), mTaskPort.port(), mByteFlipped ? "FLIP " : "", (identity && identity[0]) ? identity : "(unknown)"); +} + + +// +// Screen a process setup request for an existing process. +// This usually means the client has called exec(2) and forgotten all about itself. +// Though it could be a nefarious attempt to fool us... +// +void Process::reset(Port servicePort, TaskPort taskPort, + const ClientSetupInfo *info, const char *identity, const CommonCriteria::AuditToken &audit) +{ + if (servicePort != session().servicePort() || taskPort != mTaskPort) { + secdebug("SS", "Process %p(%d) reset mismatch (sp %d-%d, tp %d-%d) for %s", + this, pid(), servicePort.port(), session().servicePort().port(), taskPort.port(), mTaskPort.port(), + (identity && identity[0]) ? identity : "(unknown)"); + CssmError::throwMe(CSSMERR_CSSM_ADDIN_AUTHENTICATE_FAILED); // liar + } + + setup(info, identity); + + secdebug("SS", "process %p(%d) has reset; now %sfor %s", + this, mPid, mByteFlipped ? "FLIP " : "", + (identity && identity[0]) ? identity : "(unknown)"); +} + + +// +// Common set processing +// +void Process::setup(const ClientSetupInfo *info, const char *identity) +{ + // process setup info + assert(info); + uint32 pversion; + if (info->order == 0x1234) { // right side up + pversion = info->version; + } else if (info->order == 0x34120000) { // flip side up + pversion = ntohl(info->version); + mByteFlipped = true; + } else // non comprende + CssmError::throwMe(CSSM_ERRCODE_INCOMPATIBLE_VERSION); + + // check wire protocol version + if (pversion != SSPROTOVERSION) + CssmError::throwMe(CSSM_ERRCODE_INCOMPATIBLE_VERSION); + // process identity (if given) try { - mClientCode = CodeSigning::OSXCode::decode(identity); + mClientCode = OSXCode::decode(identity); + mClientIdent = deferred; // will calculate code identity when needed } catch (...) { secdebug("SS", "process %p(%d) identity decode threw exception", this, pid()); - } - if (!mClientCode) { + mClientCode = NULL; mClientIdent = unknown; // no chance to squeeze a code identity from this secdebug("SS", "process %p(%d) no clientCode - marked anonymous", this, pid()); } } +// +// Clean up a Process object +// Process::~Process() { // tell all our authorizations that we're gone @@ -123,7 +160,7 @@ Session& Process::session() const } -Database &Process::localStore() +LocalDatabase &Process::localStore() { StLock _(*this); if (!mLocalStore) @@ -131,6 +168,12 @@ Database &Process::localStore() return *mLocalStore; } +Key *Process::makeTemporaryKey(const CssmKey &key, CSSM_KEYATTR_FLAGS moreAttributes, + const AclEntryPrototype *owner) +{ + return safer_cast(localStore()).makeKey(key, moreAttributes, owner); +} + // // Change the session of a process. @@ -210,7 +253,6 @@ bool Process::removeAuthorization(AuthorizationToken *auth) Iter it = mAuthorizations.lower_bound(auth); bool isLast; if (it == mAuthorizations.end() || auth != *it) { - Syslog::error("process is missing authorization to remove"); // temp. diagnostic isLast = true; } else { Iter next = it; ++next; // following element diff --git a/src/process.h b/src/process.h index 6b2fffe..97735f3 100644 --- a/src/process.h +++ b/src/process.h @@ -3,8 +3,6 @@ * * @APPLE_LICENSE_HEADER_START@ * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. - * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in @@ -30,11 +28,11 @@ #ifndef _H_PROCESS #define _H_PROCESS -#include "securityserver.h" #include "structure.h" #include #include -#include "key.h" +#include +#include "localkey.h" #include "codesigdb.h" #include "notifications.h" #include @@ -55,8 +53,12 @@ class Process : public PerProcess, public CodeSignatures::Identity { public: Process(Port servicePort, TaskPort tPort, const ClientSetupInfo *info, const char *identity, - uid_t uid, gid_t gid); + const CommonCriteria::AuditToken &audit); virtual ~Process(); + + void reset(Port servicePort, TaskPort tPort, + const ClientSetupInfo *info, const char *identity, + const CommonCriteria::AuditToken &audit); uid_t uid() const { return mUid; } gid_t gid() const { return mGid; } @@ -64,21 +66,25 @@ public: TaskPort taskPort() const { return mTaskPort; } bool byteFlipped() const { return mByteFlipped; } - CodeSigning::OSXCode *clientCode() const { return (mClientIdent == unknown) ? NULL : mClientCode; } + OSXCode *clientCode() const { return (mClientIdent == unknown) ? NULL : mClientCode; } void addAuthorization(AuthorizationToken *auth); void checkAuthorization(AuthorizationToken *auth); bool removeAuthorization(AuthorizationToken *auth); + using PerProcess::kill; void kill(); - void changeSession(Port servicePort); + + void changeSession(Port servicePort); // very special indeed void requestNotifications(Port port, NotificationDomain domain, NotificationMask events); void stopNotifications(Port port); Session& session() const; - Database &localStore(); + LocalDatabase &localStore(); + Key *makeTemporaryKey(const CssmKey &key, CSSM_KEYATTR_FLAGS moreAttributes, + const AclEntryPrototype *owner); // aclSequence is taken to serialize ACL validations to pick up mutual changes Mutex aclSequence; @@ -88,6 +94,8 @@ public: protected: std::string getPath() const; const CssmData getHash(CodeSigning::OSXSigner &signer) const; + + void setup(const ClientSetupInfo *info, const char *identity); private: // peer state: established during connection startup; fixed thereafter @@ -97,7 +105,7 @@ private: uid_t mUid; // UNIX uid credential gid_t mGid; // primary UNIX gid credential - RefPointer mClientCode; // code object for client (NULL if unknown) + RefPointer mClientCode; // code object for client (NULL if unknown) mutable enum { deferred, known, unknown } mClientIdent; // state of client identity mutable auto_ptr mCachedSignature; // cached signature (if already known) @@ -113,7 +121,7 @@ private: // // Convenience comparison // -inline bool operator == (Process &p1, Process &p2) +inline bool operator == (const Process &p1, const Process &p2) { return &p1 == &p2; } diff --git a/src/reader.cpp b/src/reader.cpp index 10dd394..ac476b3 100644 --- a/src/reader.cpp +++ b/src/reader.cpp @@ -3,8 +3,6 @@ * * @APPLE_LICENSE_HEADER_START@ * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. - * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in @@ -30,21 +28,27 @@ #include "reader.h" -Reader::Reader(const PCSC::ReaderState &state) - : mToken(NULL) +// +// Construct a Reader +// This does not commence state tracking; call update to start up the reader. +// +Reader::Reader(TokenCache &tc, const PCSC::ReaderState &state) + : cache(tc), mToken(NULL) { - mName = state.name(); + mName = state.name(); // remember separate copy of name + mPrintName = mName; //@@@ how to make this readable? Use IOKit information? secdebug("reader", "%p (%s) new reader", this, name().c_str()); - transit(state); } - Reader::~Reader() { secdebug("reader", "%p (%s) destroyed", this, name().c_str()); } +// +// Killing a reader forcibly removes its Token, if any +// void Reader::kill() { if (mToken) @@ -53,44 +57,47 @@ void Reader::kill() } -void Reader::update(const PCSC::ReaderState &state) -{ - transit(state); -} - - // // State transition matrix for a reader, based on PCSC state changes // -void Reader::transit(const PCSC::ReaderState &state) +void Reader::update(const PCSC::ReaderState &state) { - if (state.state(SCARD_STATE_UNAVAILABLE)) { - // reader is unusable (probably being removed) - secdebug("reader", "%p (%s) unavailable (0x%lx)", - this, name().c_str(), state.state()); - if (mToken) - removeToken(); - } else if (state.state(SCARD_STATE_EMPTY)) { - // reader is empty (no token present) - secdebug("reader", "%p (%s) empty (0x%lx)", - this, name().c_str(), state.state()); - if (mToken) - removeToken(); - } else if (state.state(SCARD_STATE_PRESENT)) { - // reader has a token inserted - secdebug("reader", "%p (%s) card present (0x%lx)", - this, name().c_str(), state.state()); - //@@@ is this hack worth it (with notifications in)?? - if (mToken && CssmData(state) != CssmData(pcscState())) - removeToken(); // incomplete but better than nothing - //@@@ or should we call some verify-still-the-same function of tokend? - if (!mToken) - insertToken(); - } else { - secdebug("reader", "%p (%s) unexpected state change (0x%ld to 0x%lx)", - this, name().c_str(), mState.state(), state.state()); - } + // set new state + IFDEBUG(unsigned long oldState = mState.state()); mState = state; + mState.name(mName.c_str()); // (fix name pointer, unchanged) + + try { + if (state.state(SCARD_STATE_UNAVAILABLE)) { + // reader is unusable (probably being removed) + secdebug("reader", "%p (%s) unavailable (0x%lx)", + this, name().c_str(), state.state()); + if (mToken) + removeToken(); + } else if (state.state(SCARD_STATE_EMPTY)) { + // reader is empty (no token present) + secdebug("reader", "%p (%s) empty (0x%lx)", + this, name().c_str(), state.state()); + if (mToken) + removeToken(); + } else if (state.state(SCARD_STATE_PRESENT)) { + // reader has a token inserted + secdebug("reader", "%p (%s) card present (0x%lx)", + this, name().c_str(), state.state()); + //@@@ is this hack worth it (with notifications in)?? + if (mToken && CssmData(state) != CssmData(pcscState())) + removeToken(); // incomplete but better than nothing + //@@@ or should we call some verify-still-the-same function of tokend? + //@@@ (I think pcsc will return an error if the card changed?) + if (!mToken) + insertToken(); + } else { + secdebug("reader", "%p (%s) unexpected state change (0x%lx to 0x%lx)", + this, name().c_str(), oldState, state.state()); + } + } catch (...) { + secdebug("reader", "state update exception (ignored)"); + } } diff --git a/src/reader.h b/src/reader.h index 346f996..84cb931 100644 --- a/src/reader.h +++ b/src/reader.h @@ -3,8 +3,6 @@ * * @APPLE_LICENSE_HEADER_START@ * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. - * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in @@ -30,10 +28,10 @@ #ifndef _H_READER #define _H_READER -#include "securityserver.h" #include "structure.h" #include "token.h" -#include "pcsc++.h" +#include "tokencache.h" +#include // @@ -42,12 +40,15 @@ // class Reader : public PerGlobal { public: - Reader(const PCSC::ReaderState &state); + Reader(TokenCache &cache, const PCSC::ReaderState &state); ~Reader(); + TokenCache &cache; + void kill(); string name() const { return mName; } + string printName() const { return mPrintName; } const PCSC::ReaderState &pcscState() const { return mState; } void update(const PCSC::ReaderState &state); @@ -55,14 +56,14 @@ public: IFDUMP(void dumpNode()); protected: - void transit(const PCSC::ReaderState &state); void insertToken(); void removeToken(); private: - string mName; // PCSC reader name + string mName; // PCSC reader name + string mPrintName; // human readable name of reader PCSC::ReaderState mState; // name field not valid (use mName) - Token *mToken; // token inserted here (also in references) + Token *mToken; // token inserted here (also in references) }; diff --git a/src/securityd.order b/src/securityd.order index 20bbfc2..e181296 100644 --- a/src/securityd.order +++ b/src/securityd.order @@ -1,265 +1,839 @@ -__ZN13Authorization8RightSetD1Ev -__ZN13Authorization8RightSetD4Ev -__ZN13Authorization8RightSetD2Ev -__ZN13Authorization15MutableRightSetD4Ev -__ZN13Authorization15MutableRightSetD1Ev +__Znwm +dyld_stub_binding_helper +__ZNSt24__default_alloc_templateILb1ELi0EE8allocateEm +__ZNSt24__default_alloc_templateILb1ELi0EE5_LockC4Ev +__ZNSt24__default_alloc_templateILb1ELi0EE9_S_refillEm +__ZNSt24__default_alloc_templateILb1ELi0EE14_S_chunk_allocEmRi +__ZNSt24__default_alloc_templateILb1ELi0EE5_LockD4Ev +__ZN8Security5MutexC1Eb +__ZN8Security5MutexC4Eb +__ZN8Security5MutexC2Eb +__ZN8Security15ThreadStoreSlotC2EPFvPvE +__ZN8Security15ThreadStoreSlotC4EPFvPvE +__call_mod_init_funcs +__start +__call_objcInit +__dyld_func_lookup +_crt_basename +_crt_strbeginswith +_main +__ZN8Security6Syslog4openEPKcii +__ZN8Security11CodeSigning9OSXSignerC1Ev +__ZN8Security11CodeSigning9OSXSignerC4Ev +__ZN8Security10CssmClient7CSPImplC1ERKNS_4GuidE +__ZN8Security10CssmClient7CSPImplC4ERKNS_4GuidE +__ZN8Security10CssmClient14AttachmentImplC2ERKNS_4GuidEm +__ZN8Security10CssmClient14AttachmentImplC4ERKNS_4GuidEm +__ZN8Security10CssmClient8CssmImpl8standardEv +__ZN8Security17ModuleNexusCommon6createEPFPvvE +__ZN8Security5Mutex4lockEv +__ZN8Security5Mutex6unlockEv +__ZN8Security5MutexD1Ev +__ZN8Security5MutexD4Ev +__ZdlPv +__ZN8Security10CssmClient8CssmImpl12StandardCssm3getEv +__ZN8Security10CssmClient8CssmImplC4Eb +__ZN8Security10CssmClient10ObjectImplC4Ev +__ZN8Security10CssmClient8CssmImpl5setupEv +___dynamic_cast +__ZNK10__cxxabiv120__si_class_type_info12__do_dyncastEiNS_17__class_type_info10__sub_kindEPKS1_PKvS4_S6_RNS1_16__dyncast_resultE +__ZNKSt9type_infoeqERKS_ +__ZN8Security10CssmClient8CssmImpl10autoModuleERKNS_4GuidE +__ZN8Security10CssmClient10ModuleImplC1ERKNS_4GuidERKNS0_4CssmE +__ZN8Security10CssmClient10ModuleImplC4ERKNS_4GuidERKNS0_4CssmE +__ZN8Security10CssmClient10ObjectImplC4ERKNS0_6ObjectE +__ZN8Security10CssmClient10ObjectImpl8addChildEv +__ZN8Security10CssmClient14AttachmentImpl4makeEm +__ZN9AuthorityC1EPKc +__ZN9AuthorityC4EPKc +__ZN13Authorization6EngineC2EPKc +__ZN13Authorization6EngineC4EPKc +__ZN13Authorization20AuthorizationDBPlistC1EPKc +__ZN13Authorization20AuthorizationDBPlistC4EPKc +__ZNSsC1EPKcRKSaIcE +__ZNSsC4EPKcRKSaIcE +__ZNSs12_S_constructIPKcEEPcT_S3_RKSaIcESt20forward_iterator_tag +__ZNSs4_Rep9_S_createEmRKSaIcE +__ZNSs12_Alloc_hiderC4EPcRKSaIcE +__ZN8Security10AclSubject5MakerC2El +__ZN8Security10AclSubject5MakerC4El +__ZN14CodeSignaturesC1EPKc +__ZN14CodeSignaturesC4EPKc +__ZN8Security12UnixPlusPlus6UnixDbC1Ev +__ZN8Security12UnixPlusPlus6UnixDbC4Ev +__ZN8Security12UnixPlusPlus6UnixDb4openEPKcii6DBTYPE +__ZN8Security12UnixPlusPlus6UnixDb5closeEv +__ZN8Security12UnixPlusPlus6UnixDb5flushEi +__ZN6ServerC1ER9AuthorityR14CodeSignaturesPKc +__ZN6ServerC4ER9AuthorityR14CodeSignaturesPKc +__ZN8Security5MutexC2ENS0_4TypeEb +__ZN8Security5MutexC4ENS0_4TypeEb +__ZN8Security12MachPlusPlus10MachServerC2EPKc +__ZN8Security12MachPlusPlus10MachServerC4EPKc +__ZN8Security12MachPlusPlus5Error5checkEi +__ZN8Security12MachPlusPlus11ReceivePortC1EPKcRKNS0_9BootstrapE +__ZN8Security12MachPlusPlus11ReceivePortC4EPKcRKNS0_9BootstrapE +__ZNK8Security12MachPlusPlus9Bootstrap15checkInOptionalEPKc +__ZNK8Security12MachPlusPlus9Bootstrap10registerAsEjPKc +__ZN8Security12MachPlusPlus10MachServer5setupEPKc +__ZN8Security18DevRandomGeneratorC2Eb +__ZN8Security18DevRandomGeneratorC4Eb +__ZN8Security12MachPlusPlus16PortPowerWatcherC2Ev +__ZN8Security12MachPlusPlus16PortPowerWatcherC4Ev +__ZN8Security12MachPlusPlus14IOPowerWatcherC4Ev +__ZN8Security10CssmClient8CssmImplC1Ev +__ZN8Security10CssmClient8CssmImplC4Ev +__ZN8Security10CssmClient8CssmImpl12StandardCssm7setCssmEPS1_ +__ZN8Security10CssmClient7CSPImplC1ERKNS0_6ModuleE +__ZN8Security10CssmClient7CSPImplC4ERKNS0_6ModuleE +__ZN8Security10CssmClient14AttachmentImplC2ERKNS0_6ModuleEm +__ZN8Security10CssmClient14AttachmentImplC4ERKNS0_6ModuleEm +__ZN8Security14CommonCriteria10TerminalIdC1Ev +__ZN8Security14CommonCriteria10TerminalIdC4Ev +__ZN8Security14CommonCriteria12AuditSession15registerSessionEv +__ZN8Security12MachPlusPlus10MachServer3addERNS1_7HandlerE +__ZN14EntropyManagerC1ERN8Security12MachPlusPlus10MachServerEPKc +__ZN14EntropyManagerC4ERN8Security12MachPlusPlus10MachServerEPKc +__ZN8Security4Time3nowEv +__ZN8Security12UnixPlusPlus8FileDesc4openEPKcit +__ZN8Security12UnixPlusPlus8FileDesc4readEPvm +__ZN8Security18DevRandomGenerator10addEntropyEPKvm +__ZN8Security12UnixPlusPlus8FileDesc5writeEPKvm +__ZN8Security12UnixPlusPlus8FileDesc5closeEv +__ZN14EntropyManager6actionEv +__ZN14EntropyManager14collectEntropyEv +__ZN14EntropyManager17updateEntropyFileEv +__ZN8Security18DevRandomGenerator6randomEPvm +__ZN8Security12MachPlusPlus10MachServer8setTimerEPNS1_5TimerENS_4Time8AbsoluteE +__ZN10TokenCacheC1EPKc +__ZN10TokenCacheC4EPKc +__ZNSsC1ERKSs +__ZNSsC4ERKSs +__ZNKSs13get_allocatorEv +__ZN10TokenCache7makedirEPKcitNS_5OwnerE +__ZN8Security12UnixPlusPlus7makedirEPKcit +__ZNSsD4Ev +__ZNK6Rooted4pathEPKc +__ZNSs6appendEPKcm +__ZNSs7reserveEm +__ZNSs4_Rep8_M_cloneERKSaIcEm +__ZNKSs7_M_iendEv +__ZNSs15_M_replace_safeIPKcEERSsN9__gnu_cxx17__normal_iteratorIPcSsEES6_T_S7_ +__ZNKSs9_M_ibeginEv +__ZNSs9_M_mutateEmmm +__ZNSs4_Rep10_M_destroyERKSaIcE +__Z9scOptionsPKc +__ZN11PCSCMonitorC1ER6ServerR10TokenCacheNS_12ServiceLevelE +__ZN11PCSCMonitorC4ER6ServerR10TokenCacheNS_12ServiceLevelE +__ZN8ListenerC2Emm +__ZN8ListenerC4Emm +__ZN8Listener5setupEv +__ZN8Security12UnixPlusPlus5ChildC2Ev +__ZN8Security12UnixPlusPlus5ChildC4Ev +__ZN8Security4PCSC7SessionC1Ev +__ZN8Security4PCSC7SessionC4Ev +__ZNSaIcED4Ev +__ZN8Security5IOKit24MachPortNotificationPortC1Ev +__ZN8Security5IOKit24MachPortNotificationPortC4Ev +__ZN8Security5IOKit16NotificationPortC4Ev +__ZN8Security5IOKit10MasterPortC4Ev +__ZN11RootSessionC1ER6Serverm +__ZN11RootSessionC4ER6Serverm +__ZN7SessionC4EN8Security12MachPlusPlus9BootstrapENS1_4PortEm +__ZN8Security12HandleObject5StateC1Ev +__ZN8Security12HandleObject5StateC4Ev +__ZN8Security12HandleObject5State4makeEPS0_ +__ZN8NodeCore6parentERS_ +__ZN6Server8loadCssmEv +__ZN8Security9MDSClient9DirectoryC1Ev +__ZN8Security9MDSClient9DirectoryC4Ev +__ZN8Security9Allocator8standardEm +__ZN8Security28CssmAllocatorMemoryFunctionsC1ERNS_9AllocatorE +__ZN8Security28CssmAllocatorMemoryFunctionsC4ERNS_9AllocatorE +__ZN8Security28CssmAllocatorMemoryFunctions11relayMallocEmPv +__ZN16DefaultAllocator6mallocEm +__ZN8Security28CssmAllocatorMemoryFunctions9relayFreeEPvS1_ +__ZN16DefaultAllocator4freeEPv +__ZN8Security9MDSClient9Directory7installEv +__ZN8Security10CssmClient8CssmImpl8activateEv +__ZN8Security10CssmClient14AttachmentImpl8activateEv +__ZNK8Security10CssmClient14AttachmentImpl6moduleEv +__ZNK10__cxxabiv121__vmi_class_type_info12__do_dyncastEiNS_17__class_type_info10__sub_kindEPKS1_PKvS4_S6_RNS1_16__dyncast_resultE +__ZN8Security10CssmClient10ModuleImpl8activateEv +__ZNK8Security10CssmClient10ModuleImpl7sessionEv +__ZNK8Security10CssmClient10ObjectImpl9allocatorEv +__ZN8Security6Syslog6noticeEPKcz +__ZN6Server3runEv +__ZN8Security12MachPlusPlus10MachServer3runEmi +__ZN8Security12MachPlusPlus10MachServer15runServerThreadEb +__ZN8Security12MachPlusPlus7MessageC1Em +__ZN8Security12MachPlusPlus7MessageC4Em +__ZN8Security12MachPlusPlus7Message9setBufferEm +__ZN8Security12MachPlusPlus7Message7releaseEv +__Znam +__ZN8Security12MachPlusPlus10MachServer12processTimerEv +__ZN11PCSCMonitor6actionEv +__ZN11PCSCMonitor12initialSetupEv +__ZN6Server12SleepWatcher3addEPN8Security12MachPlusPlus12PowerWatcherE +__ZN8Security5IOKit11DeviceMatchC1EPKc +__ZN8Security5IOKit11DeviceMatchC4EPKc +__ZN8Security5IOKit16NotificationPort3addENS0_11DeviceMatchERNS1_8ReceiverEPKc +__ZN11PCSCMonitor8ioChangeERN8Security5IOKit14DeviceIteratorE +__ZN8Security5IOKit14DeviceIteratorclEv +__ZN11PCSCMonitor13deviceSupportERKN8Security5IOKit6DeviceE +__ZNK8Security5IOKit6Device8propertyEPKc +__ZN8Security8cfNumberEPK10__CFNumber +__ZN8Security5IOKit6DeviceD1Ev +__ZN8Security5IOKit6DeviceD4Ev +__ZN8Security5IOKit14DeviceIteratorD4Ev +__ZN8Security12MachPlusPlus10MachServer26releaseDeferredAllocationsEv __ZN6Server6handleEP17mach_msg_header_tS1_ __Z11ucsp_serverP17mach_msg_header_tS0_ -__ZN6Server14notifyDeadNameEN8Security12MachPlusPlus4PortE -past end of text +__Z7_XsetupP17mach_msg_header_tS0_ +__Z29__MIG_check__Request__setup_tP18__Request__setup_t +__Z17ucsp_server_setupjj13audit_token_tPljN8Security14SecurityServer15ClientSetupInfoEPKc +__ZN6Server15setupConnectionENS_12ConnectLevelEN8Security12MachPlusPlus4PortES3_S3_RK13audit_token_tPKNS1_14SecurityServer15ClientSetupInfoEPKc +__ZN8Security14CommonCriteria10AuditTokenC1ERK13audit_token_t +__ZN8Security14CommonCriteria10AuditTokenC4ERK13audit_token_t +__ZN7ProcessC1EN8Security12MachPlusPlus4PortENS1_8TaskPortEPKNS0_14SecurityServer15ClientSetupInfoEPKcjj +__ZN7ProcessC4EN8Security12MachPlusPlus4PortENS1_8TaskPortEPKNS0_14SecurityServer15ClientSetupInfoEPKcjj +__ZN14CodeSignatures8IdentityC2Ev +__ZN14CodeSignatures8IdentityC4Ev +__ZN7Session4findEN8Security12MachPlusPlus4PortE +__ZNK8Security12MachPlusPlus8TaskPort3pidEv +__ZN8Security7OSXCode6decodeEPKc +__ZNK8Security12MachPlusPlus10MachServer12notifyIfDeadENS0_4PortEb +__ZN8Security12MachPlusPlus4Port13requestNotifyEjij +__ZN10ConnectionC1ER7ProcessN8Security12MachPlusPlus4PortE +__ZN10ConnectionC4ER7ProcessN8Security12MachPlusPlus4PortE +__Z21_XauthorizationCreateP17mach_msg_header_tS0_ +__Z43__MIG_check__Request__authorizationCreate_tP32__Request__authorizationCreate_t +__Z31ucsp_server_authorizationCreatejj13audit_token_tPlP20AuthorizationItemSetjS2_mS2_jS2_PN8Security14SecurityServer17AuthorizationBlobE __ZN6Server10connectionEj -__ZN6Server15requestCompleteEv -__ZN6Server15setupConnectionENS_12ConnectLevelEN8Security12MachPlusPlus4PortES3_S3_RK16security_token_tPKNS1_14SecurityServer15ClientSetupInfoEPKc +__ZN10Connection9beginWorkEv +__ZN13Authorization11AuthItemSetC1EPK20AuthorizationItemSet +__ZN13Authorization11AuthItemSetC4EPK20AuthorizationItemSet +__ZNK7Process7sessionEv +__ZN7Session10authCreateERKN13Authorization11AuthItemSetES3_mRN8Security14SecurityServer17AuthorizationBlobERK13audit_token_t +__ZN18AuthorizationTokenC1ER7SessionRKSt3setIN13Authorization10CredentialESt4lessIS4_ESaIS4_EERK13audit_token_t +__ZN18AuthorizationTokenC4ER7SessionRKSt3setIN13Authorization10CredentialESt4lessIS4_ESaIS4_EERK13audit_token_t +__ZN6Server7processEv __ZN6Server10connectionEb __ZN10Connection9checkWorkEv -__ZN7ProcessD4Ev -__ZN7Session4findEN8Security12MachPlusPlus4PortE -__ZN7ProcessC4EN8Security12MachPlusPlus4PortENS1_8TaskPortEPKNS0_14SecurityServer15ClientSetupInfoEPKcjj -__ZNK13Authorization4Rule17evaluateMechanismEPK20AuthorizationItemSetR18AuthorizationTokenRSt3setINS_10CredentialESt4lessIS7_ESaIS7_EE -__ZNK13Authorization4Rule16agentNameForAuthERK18AuthorizationToken -__ZN7Process13endConnectionER10Connection +__ZN13Authorization11AuthItemSetC1Ev +__ZN13Authorization11AuthItemSetC4Ev +__ZN8NodeCore8referentERS_ +__ZN13Authorization6Engine9authorizeERKNS_11AuthItemSetES3_mPKSt3setINS_10CredentialESt4lessIS5_ESaIS5_EEPS9_RS1_R18AuthorizationToken +__ZN13Authorization20AuthorizationDBPlist4syncEd +__ZN13Authorization20AuthorizationDBPlist4loadEd +__ZN13Authorization20AuthorizationDBPlist11parseConfigEPK14__CFDictionary +__ZN13Authorization20AuthorizationDBPlist9parseRuleEPKvS2_Pv +__ZN13Authorization20AuthorizationDBPlist8addRightEPK10__CFStringPK14__CFDictionary +__ZN8Security8cfStringEPK10__CFStringb +__ZNSsC4Ev +__ZNSs6assignEPKcm +__ZdaPv +__ZN13Authorization4RuleC1Ev +__ZN13Authorization4RuleC4Ev +__ZN13Authorization8RuleImplC4Ev +__ZN13Authorization4RuleC1ERKSsPK14__CFDictionaryS5_ +__ZN13Authorization4RuleC4ERKSsPK14__CFDictionaryS5_ +__ZN13Authorization8RuleImplC4ERKSsPK14__CFDictionaryS5_ +__ZN13Authorization8RuleImpl9Attribute9getStringEPK14__CFDictionaryPK10__CFStringbPc +__ZNKSs7compareEPKc +__ZNSs6assignERKSs +__ZNSs4_Rep7_M_grabERKSaIcES2_ +__ZN13Authorization8RuleImpl9Attribute9getDoubleEPK14__CFDictionaryPK10__CFStringbd +__ZN13Authorization8RuleImpl9Attribute7getBoolEPK14__CFDictionaryPK10__CFStringbb +__ZN13Authorization8RuleImpl9Attribute9getVectorEPK14__CFDictionaryPK10__CFStringb +__ZSt13__destroy_auxIPSsEvT_S1_12__false_type +__ZNSt24__default_alloc_templateILb1ELi0EE10deallocateEPvm +__ZN13Authorization8RuleImpl9Attribute19getLocalizedPromptsEPK14__CFDictionaryRSt3mapISsSsSt4lessISsESaISt4pairIKSsSsEEE +__ZNKSs7compareERKSs +__ZN13Authorization11AuthItemSetD1Ev +__ZN13Authorization11AuthItemSetD4Ev +__ZN7Process16addAuthorizationEP18AuthorizationToken +__ZN18AuthorizationToken10addProcessER7Process +__ZN6Server15requestCompleteEv __ZN10Connection7endWorkEv -__ZN7Process15beginConnectionER10Connection -__ZN10Connection9beginWorkEv +__Z26_XauthorizationInternalizeP17mach_msg_header_tS0_ +__Z36ucsp_server_authorizationInternalizejj13audit_token_tPl25AuthorizationExternalFormPN8Security14SecurityServer17AuthorizationBlobE +__ZN7Session15authInternalizeERK25AuthorizationExternalFormRN8Security14SecurityServer17AuthorizationBlobE __ZN18AuthorizationToken4findERKN8Security14SecurityServer17AuthorizationBlobE -__Z17ucsp_server_setupjj16security_token_tPljN8Security14SecurityServer15ClientSetupInfoEPKc -__ZN13Authorization4RuleC4ERKSsPK14__CFDictionaryS5_ -__ZN7Process18checkAuthorizationEP18AuthorizationToken -__ZNK13Authorization20AuthorizationDBPlist7getRuleERKNS_5RightE -__ZN7Session16mergeCredentialsERSt3setIN13Authorization10CredentialESt4lessIS2_ESaIS2_EE -__ZN13Authorization15MutableRightSet9push_backERKNS_5RightE -__ZN13Authorization6Engine9authorizeERKNS_8RightSetEPK20AuthorizationItemSetmPKSt3setINS_10CredentialESt4lessIS8_ESaIS8_EEPSC_PNS_15MutableRightSetER18AuthorizationToken -__ZN7Session13authGetRightsERKN8Security14SecurityServer17AuthorizationBlobERKN13Authorization8RightSetEPK20AuthorizationItemSetmRNS5_15MutableRightSetE -__Z26ucsp_server_getSessionInfojj16security_token_tPlPmS1_ -__Z35ucsp_server_authorizationCopyRightsjj16security_token_tPlN8Security14SecurityServer17AuthorizationBlobEP20AuthorizationItemSetjS5_mS5_jS5_PS5_PjS6_ -__ZN10ConnectionC4ER7ProcessN8Security12MachPlusPlus4PortE -__ZN7Session10addProcessEP7Process -__ZN18AuthorizationToken16mergeCredentialsERKSt3setIN13Authorization10CredentialESt4lessIS2_ESaIS2_EE -__ZNK13Authorization4Rule21evaluateMechanismOnlyERKNS_5RightERKS0_RNS_15MutableRightSetER18AuthorizationTokenRSt3setINS_10CredentialESt4lessISB_ESaISB_EE -__ZN7Session10authCreateERKN13Authorization8RightSetEPK20AuthorizationItemSetmRN8Security14SecurityServer17AuthorizationBlobE -__ZN10Connection5abortEb +__ZN13Authorization5Error7throwMeEi +___cxa_allocate_exception +__ZN13Authorization5ErrorC4Ei +__ZN8Security11CommonErrorC2Ev +__ZN8Security11CommonErrorC4Ev +___cxa_throw +___cxa_get_globals +__Z21get_globals_init_oncev +__Unwind_RaiseException +save_world +_uw_init_context_1 +_uw_frame_state_for +__Unwind_Find_FDE +__Unwind_Find_registered_FDE +_examine_objects +_search_object +_init_object +_classify_object_over_fdes +_get_cie_encoding +_read_uleb128 +_read_sleb128 +_base_from_object +_read_encoded_value_with_base +_size_of_encoded_value +_add_fdes +_fde_split +_fde_single_encoding_compare +_frame_heapsort +_extract_cie_info +_read_uleb128 +_read_sleb128 +_execute_cfa_program +_size_of_encoded_value +_uw_update_context_1 +_base_of_encoded_value +_read_encoded_value_with_base +___gxx_personality_v0 +__Unwind_GetLanguageSpecificData +_uw_update_context +__Z17parse_lsda_headerP15_Unwind_ContextPKhP16lsda_header_info +__Unwind_GetRegionStart +__Z12read_uleb128PKhPj +__Z21base_of_encoded_valuehP15_Unwind_Context +__Unwind_GetIP +__Z28read_encoded_value_with_basehjPKhPj +__Z12read_sleb128PKhPi +__Z15get_ttype_entryP16lsda_header_infoj +__Z21size_of_encoded_valueh +__Z16get_adjusted_ptrPKSt9type_infoS1_PPv +__ZNKSt9type_info14__is_pointer_pEv +__ZNK10__cxxabiv117__class_type_info10__do_catchEPKSt9type_infoPPvj +__ZNK10__cxxabiv117__class_type_info11__do_upcastEPKS0_PPv +__ZNK10__cxxabiv120__si_class_type_info11__do_upcastEPKNS_17__class_type_infoEPKvRNS1_15__upcast_resultE +__ZNK10__cxxabiv117__class_type_info11__do_upcastEPKS0_PKvRNS0_15__upcast_resultE +__Unwind_RaiseException_Phase2 +__Unwind_SetGR +__Unwind_SetIP +_uw_install_context_1 +_init_dwarf_reg_size_table +eh_rest_world_r10 +rest_world_eh_r7r8 +__Unwind_Resume +___cxa_begin_catch +__ZN8Security9CssmError9cssmErrorERKNS_11CommonErrorEl +__ZNK13Authorization5Error8osStatusEv +___cxa_end_catch +___cxa_get_globals_fast +__Unwind_DeleteException +__Z23__gxx_exception_cleanup19_Unwind_Reason_CodeP17_Unwind_Exception +__ZN8Security11CommonErrorD2Ev +__ZN8Security11CommonErrorD4Ev +__ZNSt9exceptionD2Ev +__ZNSt9exceptionD4Ev +___cxa_free_exception +__Z26_XauthorizationExternalizeP17mach_msg_header_tS0_ +__Z36ucsp_server_authorizationExternalizejj13audit_token_tPlN8Security14SecurityServer17AuthorizationBlobEP25AuthorizationExternalForm +__ZN7Session15authExternalizeERKN8Security14SecurityServer17AuthorizationBlobER25AuthorizationExternalForm __ZN7Session13authorizationERKN8Security14SecurityServer17AuthorizationBlobE -__ZN18AuthorizationTokenC4ER7SessionRKSt3setIN13Authorization10CredentialESt4lessIS4_ESaIS4_EE -__ZNK18AuthorizationToken14effectiveCredsEv -__ZN10ConnectionC1ER7ProcessN8Security12MachPlusPlus4PortE -__ZN9XDatabaseC4ERKN8Security14DLDbIdentifierEPKNS0_14SecurityServer6DbBlobER7ProcessPKNS0_17AccessCredentialsE -__ZN7ProcessC1EN8Security12MachPlusPlus4PortENS1_8TaskPortEPKNS0_14SecurityServer15ClientSetupInfoEPKcjj -__ZN5DbKeyC4EcRKN8Security8CssmDataEbj -__ZN18AuthorizationToken10endProcessER7Process -__Z7_XsetupP17mach_msg_header_tS0_ -__ZN13Authorization5RightD1Ev -__ZN13Authorization5RightD4Ev -__ZN7Process19removeAuthorizationEP18AuthorizationToken -__ZN7Session13removeProcessEP7Process -__ZN7Session4findEm -__ZNK13Authorization4Rule12evaluateUserERKNS_5RightERKS0_RNS_15MutableRightSetEmdPKSt3setINS_10CredentialESt4lessIS9_ESaIS9_EERSD_R18AuthorizationToken -__ZN18AuthorizationToken17setCredentialInfoERKN13Authorization10CredentialE +__ZN7Process18checkAuthorizationEP18AuthorizationToken +__ZNK18AuthorizationToken14mayExternalizeER7Process +__ZN18AuthorizationToken14mayInternalizeER7Processb __Z16_XgetSessionInfoP17mach_msg_header_tS0_ -__ZN18SecurityAgentQuery8activateEv -__ZN13Authorization4Rule9Attribute9getVectorEPK14__CFDictionaryPK10__CFStringb -__ZN13Authorization8RightSetC1EPK20AuthorizationItemSet -__ZN13Authorization8RightSetC4EPK20AuthorizationItemSet -__ZN13Authorization8RightSetC2EPK20AuthorizationItemSet -__ZN18DatabaseCryptoCore10decodeCoreEPN8Security14SecurityServer6DbBlobEPPv -__ZN18DatabaseCryptoCore10makeRawKeyEPvmmm -__ZNK13Authorization4Rule26evaluateCredentialForRightERKNS_5RightERKS0_PK20AuthorizationItemSetdRKNS_10CredentialEb -__ZN14CodeSignatures7addLinkERKN8Security8CssmDataES3_PKcb -__ZN13Authorization4RuleD4Ev -__ZN14CodeSignatures8makeLinkERNS_8IdentityERKSsbj -__ZN13Authorization20AuthorizationDBPlist4syncEd -__ZN13Authorization15MutableRightSetC4EmRKNS_5RightE -__ZN13Authorization15MutableRightSetC1EmRKNS_5RightE -__ZN13Authorization5RightC1Ev -__ZN7ProcessD0Ev -__ZN13Authorization5RightC4Ev -__ZN17AuthorizationItemC2Ev -__ZN17AuthorizationItemC4Ev -__Z31ucsp_server_authorizationCreatejj16security_token_tPlP20AuthorizationItemSetjS2_mS2_jS2_PN8Security14SecurityServer17AuthorizationBlobE -__Z20ucsp_server_decodeDbjj16security_token_tPlPmPN8Security11DataWalkers18DLDbFlatIdentifierEjS5_PNS2_17AccessCredentialsEjS7_Pvj -__ZN13Authorization15MutableRightSet4growEm -__ZN13Authorization10CredentialD4Ev -__ZN13Authorization10CredentialD1Ev -__ZN13Authorization5RightC1EPKcmPKv -__ZN13Authorization5RightC4EPKcmPKv -__Z20ucsp_server_isLockedjj16security_token_tPlmPi -__ZN14CodeSignatures8IdentityC2Ev -__ZN14CodeSignatures8IdentityC4Ev -__ZN18AuthorizationToken10addProcessER7Process -__ZN7Process16addAuthorizationEP18AuthorizationToken -__ZN18SecurityAgentQuery9terminateEv -__Z29__MIG_check__Request__setup_tP18__Request__setup_t -__ZN7Session15authExternalizeERKN8Security14SecurityServer17AuthorizationBlobER25AuthorizationExternalForm __Z38__MIG_check__Request__getSessionInfo_tP27__Request__getSessionInfo_t -__ZN26CheckingReconstituteWalkerC4EPvS0_mb -__Z20ucsp_server_setupNewjj16security_token_tPljN8Security14SecurityServer15ClientSetupInfoEPKcPj -__ZN18AuthorizationToken7DeleterC4ERKN8Security14SecurityServer17AuthorizationBlobE -__ZN7Session8authFreeERKN8Security14SecurityServer17AuthorizationBlobEm -__ZN14DynamicSessionC4ERKN8Security12MachPlusPlus9BootstrapE -__ZN13Authorization15MutableRightSetC4ERKNS_8RightSetE -__ZN13Authorization15MutableRightSetC1ERKNS_8RightSetE -__ZN7Process4killEb -__ZN20QueryInvokeMechanismclERKSsS1_PK24AuthorizationValueVectorRKN13Authorization8RightSetES8_PmRP20AuthorizationItemSetSC_ -__ZNK13Authorization14CredentialImplltERKS0_ -__Z30ucsp_server_addCodeEquivalencejj16security_token_tPlPvjS1_jPKci -__ZN18AuthorizationToken7infoSetEv +__Z26ucsp_server_getSessionInfojj13audit_token_tPlPmS1_ +__ZN7Session4findEm +__ZN6Server7sessionEv +_cdsa_notify_server +__Xmach_notify_dead_name +_cdsa_mach_notify_dead_name +__ZN6Server14notifyDeadNameEN8Security12MachPlusPlus4PortE +__ZN10Connection5abortEb __ZN10ConnectionD0Ev __ZN10ConnectionD4Ev -__ZN7SessionC4EN8Security12MachPlusPlus9BootstrapENS1_4PortEm +__ZN8NodeCoreD2Ev +__ZN8NodeCoreD4Ev +__ZN8Security5MutexD2Ev +__Z22_XauthorizationReleaseP17mach_msg_header_tS0_ +__Z44__MIG_check__Request__authorizationRelease_tP33__Request__authorizationRelease_t +__Z32ucsp_server_authorizationReleasejj13audit_token_tPlN8Security14SecurityServer17AuthorizationBlobEm +__ZN7Session8authFreeERKN8Security14SecurityServer17AuthorizationBlobEm +__ZN18AuthorizationToken7DeleterC1ERKN8Security14SecurityServer17AuthorizationBlobE +__ZN18AuthorizationToken7DeleterC4ERKN8Security14SecurityServer17AuthorizationBlobE +__ZN7Process19removeAuthorizationEP18AuthorizationToken +__ZN18AuthorizationToken10endProcessER7Process +__ZN7Process4killEv +__ZN8NodeCore4killEv +__ZN8NodeCore15clearReferencesEv +__ZN7ProcessD0Ev +__ZN7ProcessD4Ev +__ZN18AuthorizationTokenD0Ev +__ZN18AuthorizationTokenD4Ev __ZN14CodeSignatures8IdentityD2Ev __ZN14CodeSignatures8IdentityD4Ev -__ZN5DbKeyC1EcRKN8Security8CssmDataEbj -__ZN13Authorization4RuleD1Ev -__Z10_XisLockedP17mach_msg_header_tS0_ -__ZNK13Authorization4Rule8evaluateERKNS_5RightERKS0_RNS_15MutableRightSetEmdPKSt3setINS_10CredentialESt4lessIS9_ESaIS9_EERSD_R18AuthorizationToken +__ZN8Security12HandleObjectD2Ev +__ZN8Security12HandleObjectD4Ev +__ZN8Security12HandleObject5State5eraseEPS0_ +__ZN18AuthorizationToken7Deleter6removeEv +__ZN8Security13GenericBundleC1EPKcS2_ +__ZN8Security13GenericBundleC4EPKcS2_ +__Z10_XsetupNewP17mach_msg_header_tS0_ +__Z32__MIG_check__Request__setupNew_tP21__Request__setupNew_t +__Z20ucsp_server_setupNewjj13audit_token_tPljN8Security14SecurityServer15ClientSetupInfoEPKcPj +__ZN14DynamicSessionC1EN8Security12MachPlusPlus8TaskPortE +__ZN14DynamicSessionC4EN8Security12MachPlusPlus8TaskPortE +__ZN8Security12MachPlusPlus11ReceivePortC2EPKcRKNS0_9BootstrapE +__ZN8Security12MachPlusPlus10MachServer3addENS0_4PortE +__ZNK8Security12MachPlusPlus10MachServer14notifyIfUnusedENS0_4PortEb +__ZN7Process13changeSessionEN8Security12MachPlusPlus4PortE +__Z14_XsetupSessionP17mach_msg_header_tS0_ +__Z36__MIG_check__Request__setupSession_tP25__Request__setupSession_t +__Z24ucsp_server_setupSessionjj13audit_token_tPlmm +__ZN14DynamicSession15setupAttributesEmm +__ZN14DynamicSession15checkOriginatorEv +__Z13_XsetupThreadP17mach_msg_header_tS0_ +__Z23ucsp_server_setupThreadjj13audit_token_tPlj __Z25_XauthorizationCopyRightsP17mach_msg_header_tS0_ -__ZN13Authorization4RuleC1ERKSsPK14__CFDictionaryS5_ -__ZN18AuthorizationTokenD4Ev -__Z32ucsp_server_authorizationReleasejj16security_token_tPlN8Security14SecurityServer17AuthorizationBlobEm -__ZN7Process11addDatabaseEP9XDatabase -__ZN7Session15authInternalizeERK25AuthorizationExternalFormRN8Security14SecurityServer17AuthorizationBlobE -__ZN7Process14removeDatabaseEP9XDatabase -__ZN9XDatabaseD4Ev -__ZN7Session16addAuthorizationEP18AuthorizationToken +__Z47__MIG_check__Request__authorizationCopyRights_tP36__Request__authorizationCopyRights_t +__Z35ucsp_server_authorizationCopyRightsjj13audit_token_tPlN8Security14SecurityServer17AuthorizationBlobEP20AuthorizationItemSetjS5_mS5_jS5_PS5_PjS6_ +__ZN26CheckingReconstituteWalkerC1EPvS0_mb +__ZN26CheckingReconstituteWalkerC4EPvS0_mb +__ZN13Authorization11AuthItemRefC4ERK17AuthorizationItem +__ZN13Authorization8AuthItemC4ERK17AuthorizationItem +__ZN7Session13authGetRightsERKN8Security14SecurityServer17AuthorizationBlobERKN13Authorization11AuthItemSetES8_mRS6_ +__ZNK18AuthorizationToken14effectiveCredsEv +__ZNK18AuthorizationToken7sessionEv +__ZNK13Authorization20AuthorizationDBPlist7getRuleERKNS_11AuthItemRefE +__ZNK13Authorization8RuleImpl8evaluateERKNS_11AuthItemRefERKNS_4RuleERNS_11AuthItemSetEmdPKSt3setINS_10CredentialESt4lessISA_ESaISA_EERSE_R18AuthorizationToken +__ZNK13Authorization8RuleImpl21evaluateMechanismOnlyERKNS_11AuthItemRefERKNS_4RuleERNS_11AuthItemSetER18AuthorizationTokenRSt3setINS_10CredentialESt4lessISC_ESaISC_EE +__ZN13Authorization23AgentMechanismEvaluatorC1EjRK7SessionRKSt6vectorISsSaISsEE +__ZN13Authorization23AgentMechanismEvaluatorC4EjRK7SessionRKSt6vectorISsSaISsEE +__ZNK13Authorization8RuleImpl13setAgentHintsERKNS_11AuthItemRefERKNS_4RuleERNS_11AuthItemSetER18AuthorizationToken +__ZN13Authorization11AuthItemRefC1EPKc +__ZN13Authorization11AuthItemRefC4EPKc +__ZN13Authorization8AuthItemC4EPKc +__ZN13Authorization8AuthItemD1Ev +__ZN13Authorization8AuthItemD4Ev +__ZN13Authorization11AuthItemRefC1EPKc18AuthorizationValuem +__ZN13Authorization11AuthItemRefC4EPKc18AuthorizationValuem +__ZN13Authorization8AuthItemC4EPKc18AuthorizationValuem +__ZNK13Authorization8AuthItemltERKS0_ +__ZNK8Security13GenericBundle6encodeEv +__ZStplIcSt11char_traitsIcESaIcEESbIT_T0_T1_EPKS3_RKS6_ +__ZNSs7replaceEN9__gnu_cxx17__normal_iteratorIPcSsEES2_PKcS4_ +__ZNSs7replaceEmmPKcm +__ZNSs6appendERKSs +__ZNSs15_M_replace_safeIN9__gnu_cxx17__normal_iteratorIPcSsEEEERSsS3_S3_T_S5_ +__ZNSs13_S_copy_charsEPcN9__gnu_cxx17__normal_iteratorIS_SsEES2_ +__ZNK8Security13GenericBundle13canonicalPathEv +__ZN13SecurityAgent6Client11clientHintsENS_13RequestorTypeERSsij +__ZNKSs5c_strEv +__ZN13Authorization23AgentMechanismEvaluator3runERKNS_15AuthValueVectorERKNS_11AuthItemSetERK18AuthorizationToken +__ZN18AuthorizationToken7infoSetEPKc +__ZNKSs4findEcm +__ZNKSs6substrEmm +__ZNSsC1ERKSsmm +__ZNSsC4ERKSsmm +__ZNKSs8_M_checkEm +__ZNKSs7_M_foldEmm +__ZNSs12_S_constructIN9__gnu_cxx17__normal_iteratorIPcSsEEEES2_T_S4_RKSaIcESt20forward_iterator_tag +__ZNKSs5rfindEcm +__ZN13Authorization17AgentMechanismRefC4E12AuthHostType +__ZN20QueryInvokeMechanismC1E12AuthHostType +__ZN20QueryInvokeMechanismC4E12AuthHostType +__ZN18SecurityAgentQueryC4E12AuthHostType +__ZN13SecurityAgent6ClientC2Ev +__ZN13SecurityAgent6ClientC4Ev +__ZN7Session8authhostE12AuthHostTypeb +__ZN16AuthHostInstanceC1ER7Session12AuthHostType +__ZN16AuthHostInstanceC4ER7Session12AuthHostType +__ZN11ServerChildC2Ev +__ZN11ServerChildC4Ev +__ZN8Security9ConditionC1ERNS_5MutexE +__ZN8Security9ConditionC4ERNS_5MutexE +__ZN8NodeCore12addReferenceERS_ +__ZN20QueryInvokeMechanism10initializeERKSsS1_RKN13Authorization15AuthValueVectorEj +__ZN18SecurityAgentQuery6createEPKcS1_j +__ZN18SecurityAgentQuery8activateEv +__ZN8Security12MachPlusPlus10MachServer16longTermActivityEv +__ZN8Security6Thread3runEv +__ZN16AuthHostInstance8activateEv +__ZN8Security6Thread6runnerEPv +__ZNK16AuthHostInstance7sessionEv +__ZN8Security12MachPlusPlus10MachServer10LoadThread6actionEv +__ZN8Security12MachPlusPlus11StBootstrapC1ERKNS0_9BootstrapERKNS0_8TaskPortE +__ZN8Security12MachPlusPlus10MachServer9addThreadEPNS_6ThreadE +__ZN8Security12MachPlusPlus11StBootstrapC4ERKNS0_9BootstrapERKNS0_8TaskPortE +__ZN8Security12UnixPlusPlus5Child4forkEv +__ZN11ServerChild12parentActionEv +__ZN8Security9Condition4waitEv +__Z14_XchildCheckInP17mach_msg_header_tS0_ +__Z24ucsp_server_childCheckInjjj +__ZN11ServerChild7checkInEN8Security12MachPlusPlus4PortEi +__ZN8Security12UnixPlusPlus5Child11findGenericEi +__ZN8Security9Condition6signalEv +__ZN8Security12MachPlusPlus11StBootstrapD1Ev +__ZN8Security12MachPlusPlus11StBootstrapD4Ev +__ZN13SecurityAgent6Client8activateEN8Security12MachPlusPlus4PortE +__ZN13SecurityAgent6Client6createEPKcS2_j +_sa_request_client_create +__ZN13SecurityAgent6Client7receiveEv +__ZN13SecurityAgent7Clients7receiveEv +__ZN8Security12MachPlusPlus7Message7receiveEjijj +__ZN8Security12MachPlusPlus7Message5checkEi +_secagentreply_server +__XdidCreate +_sa_reply_server_didCreate +__ZNK13SecurityAgent7Clients4findEj +__ZN13SecurityAgent6Client12setStagePortEj +__ZN8Security12MachPlusPlus7MessageD1Ev +__ZN8Security12MachPlusPlus7MessageD4Ev +__ZN20QueryInvokeMechanism3runERKN13Authorization15AuthValueVectorERNS0_11AuthItemSetES5_Pm +__ZN13SecurityAgent6Client6invokeEv +__ZNK13Authorization11AuthItemSet4copyERP20AuthorizationItemSetRmRN8Security9AllocatorE +__ZNK13Authorization15AuthValueVector4copyEPP24AuthorizationValueVectorPm +_sa_request_client_invoke +__ZN13SecurityAgent6Client5checkEi +__XsetResult +___MIG_check__Request__setResult_t +_sa_reply_server_setResult +__ZN13Authorization11AuthItemSetaSERK20AuthorizationItemSet +__ZN8Security12MachPlusPlus10deallocateEjm +__ZN13Authorization23AgentMechanismEvaluator12authinternalERNS_11AuthItemSetE +__ZNSsC1EPKcmRKSaIcE +__ZNSsC4EPKcmRKSaIcE +__ZN13Authorization10CredentialC1ERKSsS2_b +__ZN13Authorization10CredentialC4ERKSsS2_b +__ZN13Authorization14CredentialImplC4ERKSsS2_b __ZNK13Authorization14CredentialImpl7isValidEv -__ZN13Authorization20AuthorizationDBPlist4loadEv -__ZN18AuthorizationToken10setInfoSetER20AuthorizationItemSet -__ZN13Authorization4Rule9Attribute7getBoolEPK14__CFDictionaryPK10__CFStringbb -__ZN7Session19removeAuthorizationEP18AuthorizationToken -__ZN13Authorization4Rule9Attribute9getStringEPK14__CFDictionaryPK10__CFStringbPc -__Z36ucsp_server_authorizationExternalizejj16security_token_tPlN8Security14SecurityServer17AuthorizationBlobEP25AuthorizationExternalForm -__ZN20QueryInvokeMechanismC1EjRK18AuthorizationTokenPKc +__ZN8Security6Syslog4infoEPKcz +__ZN13Authorization10CredentialD1Ev +__ZN13Authorization10CredentialD4Ev +__ZN13Authorization14CredentialImplD4Ev +__ZN13Authorization11AuthItemSet4findEPKc +__ZN8Security14CommonCriteria11AuditRecord6submitEsiPKc +__ZN18AuthorizationToken10setInfoSetERN13Authorization11AuthItemSetE +__ZNK13Authorization8RuleImpl15makeCredentialsERK18AuthorizationToken +__ZN13Authorization10CredentialC1ERKSsjjb +__ZN13Authorization10CredentialC4ERKSsjjb +__ZN13Authorization14CredentialImplC4ERKSsjjb __ZN18SecurityAgentQueryD4Ev -__ZN20QueryInvokeMechanismC4EjRK18AuthorizationTokenPKc -__ZN18SecurityAgentQueryC2EjR7SessionPKc -__ZN18SecurityAgentQueryC4EjR7SessionPKc -__ZN18AuthorizationToken7DeleterC1ERKN8Security14SecurityServer17AuthorizationBlobE -__ZNK18DatabaseCryptoCore17deriveDbMasterKeyERKN8Security8CssmDataE -__ZN18AuthorizationTokenC1ER7SessionRKSt3setIN13Authorization10CredentialESt4lessIS4_ESaIS4_EE +__ZN13SecurityAgent6Client7destroyEv +_sa_request_client_destroy +__ZN13SecurityAgent6ClientD2Ev +__ZN13SecurityAgent6ClientD4Ev +__ZN13SecurityAgent6Client8teardownEv +__ZN20QueryInvokeMechanism14terminateAgentEv +__ZN18SecurityAgentQuery9terminateEv +__ZN13SecurityAgent6Client9terminateEv +_sa_request_client_terminate +__ZN7Session16mergeCredentialsERSt3setIN13Authorization10CredentialESt4lessIS2_ESaIS2_EE __ZNK13Authorization14CredentialImpl8isSharedEv -__Z21_XauthorizationCreateP17mach_msg_header_tS0_ -__Z22_XauthorizationReleaseP17mach_msg_header_tS0_ -__Z23ucsp_server_setupThreadjj16security_token_tPlj -__Z33ucsp_server_authorizationCopyInfojj16security_token_tPlN8Security14SecurityServer17AuthorizationBlobEPKcPP20AuthorizationItemSetPjS8_ -__ZN7Session11authGetInfoERKN8Security14SecurityServer17AuthorizationBlobEPKcRP20AuthorizationItemSet -__ZN7Session14clearResourcesEv -__ZN8Listener6removeEN8Security12MachPlusPlus4PortE -__ZN8ListenerC4ER7ProcessN8Security12MachPlusPlus4PortEmm -__ZN6Server8loadCssmEv -__Z47__MIG_check__Request__authorizationCopyRights_tP36__Request__authorizationCopyRights_t -__ZN13Authorization4Rule9Attribute19getLocalizedPromptsEPK14__CFDictionaryRSt3mapISsSsSt4lessISsESaISt4pairIKSsSsEEE -__Z32__MIG_check__Request__isLocked_tP21__Request__isLocked_t -__ZN13Authorization15MutableRightSet4swapERS0_ -__ZN9XDatabaseC1ERKN8Security14DLDbIdentifierEPKNS0_14SecurityServer6DbBlobER7ProcessPKNS0_17AccessCredentialsE -__Z36ucsp_server_authorizationInternalizejj16security_token_tPl25AuthorizationExternalFormPN8Security14SecurityServer17AuthorizationBlobE -__Z20_XaddCodeEquivalenceP17mach_msg_header_tS0_ -__ZN8Listener6notifyEmmRKN8Security8CssmDataE -__Z10_XdecodeDbP17mach_msg_header_tS0_ -__Z21ucsp_server_releaseDbjj16security_token_tPlm -__Z26_XauthorizationExternalizeP17mach_msg_header_tS0_ -_main -__ZN18AuthorizationToken7Deleter6removeEv -__ZN18DatabaseCryptoCoreC4Ev -__ZN18AuthorizationTokenD1Ev -__ZN18AuthorizationToken14mayInternalizeER7Processb -__ZN7Session9eliminateEN8Security12MachPlusPlus4PortE +__ZN18AuthorizationToken16mergeCredentialsERKSt3setIN13Authorization10CredentialESt4lessIS2_ESaIS2_EE +__Z10flipClientv +__ZN8Security12MachPlusPlus10MachServer15releaseWhenDoneERNS_9AllocatorEPv +__Z13handleSignalsi +__ZN8Security13GenericBundleD0Ev +_self_client_handleSignal +__ZN8Security13GenericBundleD4Ev +__Z11self_serverP17mach_msg_header_tS0_ +__Z14_XhandleSignalP17mach_msg_header_tS0_ +__Z36__MIG_check__Request__handleSignal_tP25__Request__handleSignal_t +__Z24self_server_handleSignaljji +__ZN8Security12UnixPlusPlus5Child13checkChildrenEv +__ZN8Security12UnixPlusPlus5Child4buryEi +__ZN11ServerChild5dyingEv +__Z23_XauthorizationCopyInfoP17mach_msg_header_tS0_ +__Z45__MIG_check__Request__authorizationCopyInfo_tP34__Request__authorizationCopyInfo_t +__Z33ucsp_server_authorizationCopyInfojj13audit_token_tPlN8Security14SecurityServer17AuthorizationBlobEPKcPP20AuthorizationItemSetPjS8_ +__ZN7Session11authGetInfoERKN8Security14SecurityServer17AuthorizationBlobEPKcRN13Authorization11AuthItemSetE +__Z28_XsetSessionDistinguishedUidP17mach_msg_header_tS0_ +__Z50__MIG_check__Request__setSessionDistinguishedUid_tP39__Request__setSessionDistinguishedUid_t +__Z38ucsp_server_setSessionDistinguishedUidjj13audit_token_tPlmj +__ZN14DynamicSession13originatorUidEj +__Z21_XsetSessionUserPrefsP17mach_msg_header_tS0_ +__Z43__MIG_check__Request__setSessionUserPrefs_tP32__Request__setSessionUserPrefs_t +__Z31ucsp_server_setSessionUserPrefsjj13audit_token_tPlmPvj +__ZN14DynamicSession12setUserPrefsEPK8__CFData +__ZNK13Authorization10CredentialltERKS0_ +__ZNK13Authorization14CredentialImplltERKS0_ __ZN13Authorization14CredentialImpl5mergeERKS0_ -__ZN9XDatabase6Common6unlockEPN8Security14SecurityServer6DbBlobEPPv -__ZN13Authorization14CredentialImplC4ERKSsS2_b -__ZN9XDatabase6Common8activityEv -__ZN6ServerC4ER9AuthorityR14CodeSignaturesPKc -__ZN7SessionC2EN8Security12MachPlusPlus9BootstrapENS1_4PortEm -__Z44__MIG_check__Request__authorizationRelease_tP33__Request__authorizationRelease_t -__Z43__MIG_check__Request__authorizationCreate_tP32__Request__authorizationCreate_t -__ZN9XDatabaseD0Ev -__Z11_XreleaseDbP17mach_msg_header_tS0_ -__ZN14DynamicSessionC1ERKN8Security12MachPlusPlus9BootstrapE -__Z26_XauthorizationInternalizeP17mach_msg_header_tS0_ -__Z24ucsp_server_setupSessionjj16security_token_tPlmm -__Z10_XsetupNewP17mach_msg_header_tS0_ -__ZN9XDatabase6CommonC4ERKNS_12DbIdentifierERNS_9CommonMapE -__ZN9XDatabase6CommonC1ERKNS_12DbIdentifierERNS_9CommonMapE -__ZN18DatabaseCryptoCoreC2Ev -__Z14_XsetupSessionP17mach_msg_header_tS0_ -__Z34ucsp_server_unlockDbWithPassphrasejj16security_token_tPlmPvj -__ZN7Session5setupEmm -__ZN7Session15setupAttributesEm -__Z48__MIG_check__Request__authorizationExternalize_tP37__Request__authorizationExternalize_t -__ZN14CodeSignatures8Identity13canonicalNameERKSs +__Z10_XdecodeDbP17mach_msg_header_tS0_ __Z32__MIG_check__Request__decodeDb_tP21__Request__decodeDb_t -__ZN13Authorization4Rule9Attribute9getDoubleEPK14__CFDictionaryPK10__CFStringbd -__Z42__MIG_check__Request__addCodeEquivalence_tP31__Request__addCodeEquivalence_tPS0_ -__ZN8Listener8notifyMeEmmRKN8Security8CssmDataE -__ZNK18AuthorizationToken14mayExternalizeER7Process -__ZN14EntropyManager17updateEntropyFileEv -__ZNK13Authorization14CredentialImpl12creationTimeEv -__ZN9XDatabase6decodeEv +__Z20ucsp_server_decodeDbjj13audit_token_tPlPmPN8Security11DataWalkers18DLDbFlatIdentifierEjS5_PNS2_17AccessCredentialsEjS7_Pvj +__ZN8Security6DbNameC1EPKcPK16cssm_net_address +__ZN8Security6DbNameC4EPKcPK16cssm_net_address +__ZN16KeychainDatabaseC1ERKN8Security14DLDbIdentifierEPKNS0_14SecurityServer6DbBlobER7ProcessPKNS0_17AccessCredentialsE +__ZN16KeychainDatabaseC4ERKN8Security14DLDbIdentifierEPKNS0_14SecurityServer6DbBlobER7ProcessPKNS0_17AccessCredentialsE +__ZN8Security9ObjectAclC2ERNS_9AllocatorE +__ZN8Security9ObjectAclC4ERNS_9AllocatorE +__ZN13LocalDatabaseC2ER7Process +__ZN13LocalDatabaseC4ER7Process +__ZN8DatabaseC2ER7Process +__ZN8DatabaseC4ER7Process +__ZN16KeychainDatabase12validateBlobEPKN8Security14SecurityServer6DbBlobE __ZNK8Security14SecurityServer10CommonBlob8validateEl __ZNK8Security14SecurityServer10CommonBlob7isValidEv -__Z13_XsetupThreadP17mach_msg_header_tS0_ -__ZN9XDatabase6unlockERKN8Security8CssmDataE -__Z23_XauthorizationCopyInfoP17mach_msg_header_tS0_ -__Z31ucsp_server_requestNotificationjj16security_token_tPljmm -__ZN16KeychainNotifier6notifyERKN8Security14DLDbIdentifierEi +__ZNK8Database7processEv +__ZNK10__cxxabiv117__class_type_info12__do_dyncastEiNS0_10__sub_kindEPKS0_PKvS3_S5_RNS0_16__dyncast_resultE +__ZN16KeychainDbCommonC1ER7SessionRK12DbIdentifier +__ZN16KeychainDbCommonC4ER7SessionRK12DbIdentifier +__ZN8DbCommonC2ER7Session +__ZN8DbCommonC4ER7Session +__ZN18DatabaseCryptoCoreC2Ev +__ZN18DatabaseCryptoCoreC4Ev +__ZN16KeychainDbGlobalC1ERK12DbIdentifier +__ZN16KeychainDbGlobalC4ERK12DbIdentifier +__ZNK8DbCommon7sessionEv +__ZNK16KeychainDatabase6commonEv +__Z16_XauthenticateDbP17mach_msg_header_tS0_ +__Z38__MIG_check__Request__authenticateDb_tP27__Request__authenticateDb_t +__Z26ucsp_server_authenticateDbjj13audit_token_tPlmmPN8Security17AccessCredentialsEjS3_ +__ZN8Security11ListElement4lastEv +__ZN8Security11ListElement4listEv +__ZN8Security11ListElement4dataEv +__ZN6Server8databaseEm +__ZN8Security12HandleObject5State6locateEml +__ZN16KeychainDatabase12authenticateEmPKN8Security17AccessCredentialsE +__Z24_XunlockDbWithPassphraseP17mach_msg_header_tS0_ +__Z46__MIG_check__Request__unlockDbWithPassphrase_tP35__Request__unlockDbWithPassphrase_t +__Z34ucsp_server_unlockDbWithPassphrasejj13audit_token_tPlmPvj +__ZN6Server8keychainEm +__ZN16KeychainDatabase8unlockDbERKN8Security8CssmDataE +__ZN16KeychainDatabase12makeUnlockedERKN8Security8CssmDataE +__ZN16KeychainDatabase6decodeERKN8Security8CssmDataE __ZN18DatabaseCryptoCore5setupEPKN8Security14SecurityServer6DbBlobERKNS0_8CssmDataE -__ZN14DynamicSessionD4Ev -__ZN9XDatabase16lockAllDatabasesERNS_9CommonMapEb -__ZN9XDatabase6CommonD4Ev -__ZN13Authorization14CredentialImplC1ERKSsS2_b -__ZN13Authorization10CredentialC4ERKSsS2_b -__ZN13Authorization10CredentialC1ERKSsS2_b -__ZN20QueryInvokeMechanism14terminateAgentEv -__ZN9XDatabase6decodeERKN8Security8CssmDataE -__ZN9XDatabase12makeUnlockedERKN8Security8CssmDataE +__ZNK18DatabaseCryptoCore17deriveDbMasterKeyERKN8Security8CssmDataE +__ZN8Security10CssmClient5CryptC2ERKNS0_3CSPEm +__ZN8Security10CssmClient5CryptC4ERKNS0_3CSPEm +__ZN8Security10CssmClient7ContextC2ERKNS0_3CSPEm +__ZN8Security10CssmClient7ContextC4ERKNS0_3CSPEm +__ZN8Security10CssmClient10ObjectImplC2ERKNS0_6ObjectE +__ZN8Security10CssmClient9DeriveKeyclEPNS_8CssmDataERKNS0_7KeySpecE +__ZN8Security10CssmClient9DeriveKey8activateEv +__ZN8Security10CssmClient10ObjectImpl5checkEl +__ZNK8Security10CssmClient9RccBearer12compositeRccEv +__ZN8Security10CssmClient7KeyImplC1ERKNS0_3CSPE +__ZN8Security10CssmClient7KeyImplC4ERKNS0_3CSPE +__ZN8Security10CssmClient7KeyImpl8activateEv +__ZN8Security10CssmClient7ContextD2Ev +__ZN8Security10CssmClient7ContextD4Ev +__ZN8Security10CssmClient7Context10deactivateEv +__ZN8Security10CssmClient10ObjectImplD2Ev +__ZN8Security10CssmClient10ObjectImplD4Ev +__ZN8Security10CssmClient10ObjectImpl11removeChildEv +__ZN16KeychainDatabase6decodeEv +__ZN16KeychainDbCommon8unlockDbEPN8Security14SecurityServer6DbBlobEPPv +__ZN18DatabaseCryptoCore10decodeCoreEPN8Security14SecurityServer6DbBlobEPPv +__ZN8Security10CssmClient5Crypt3keyERKNS0_3KeyE +__ZN8Security10CssmClient7Decrypt7decryptEPKNS_8CssmDataEmPS2_mRS2_ +__ZN8Security10CssmClient5Crypt8activateEv +__ZN18DatabaseCryptoCore10makeRawKeyEPvmmm +__ZN8Security10CssmClient9UnwrapKeyclERKNS_7CssmKeyERKNS0_7KeySpecERS2_PNS_8CssmDataEPS3_ +__ZN8Security10CssmClient7KeyImplC1ERKNS0_3CSPERK8cssm_keyb +__ZN8Security10CssmClient7KeyImplC4ERKNS0_3CSPERK8cssm_keyb +__ZN8Security7CssmKeyC2ERK8cssm_key +__ZN8Security7CssmKeyC4ERK8cssm_key +__ZN8Security10CssmClient9VerifyMac6verifyEPKNS_8CssmDataEmRS3_ +__ZN8Security10CssmClient10MacContext8activateEv +__ZN16KeychainDbCommon11setUnlockedEv +__ZN16KeychainDbCommon8activityEv +__ZN16KeychainDbCommon6notifyEm +__ZN8Security19NameValueDictionaryC1Ev +__ZN8Security19NameValueDictionaryC4Ev +__ZN8Security19NameValueDictionary41MakeNameValueDictionaryFromDLDbIdentifierERKNS_14DLDbIdentifierERS0_ +__ZN8Security13NameValuePairC4EmRKNS_8CssmDataE +__ZN8Security13NameValuePair9CloneDataERKNS_8CssmDataE +__ZN8Security19NameValueDictionary6InsertEPNS_13NameValuePairE +__ZN8Security19NameValueDictionary6ExportERNS_8CssmDataE +__ZNK8Security19NameValueDictionary13CountElementsEv +__ZN8Security19NameValueDictionary10GetElementEi +__ZNK8Security13NameValuePair6ExportERNS_8CssmDataE +__ZN8Listener6notifyEmmRKN8Security8CssmDataE +__ZN8Security19NameValueDictionaryD1Ev +__ZN8Security19NameValueDictionaryD4Ev +__ZN8Security13NameValuePairD4Ev +__ZN16KeychainDatabase3aclEv +__ZN8Security9ObjectAcl10importBlobEPKvS2_ +__ZN8Security9ObjectAcl5Entry10importBlobERNS_23LowLevelMemoryUtilities6ReaderES4_ +__ZN8Security9ObjectAcl13importSubjectERNS_23LowLevelMemoryUtilities6ReaderES3_ +__ZN8Security9ObjectAcl4makeEmRNS_23LowLevelMemoryUtilities6ReaderES3_ +__ZN8Security9ObjectAcl8makerForEl +__ZNK8Security13AnyAclSubject5Maker4makeEhRNS_23LowLevelMemoryUtilities6ReaderES4_ +__ZN8Security10AclSubjectC2Emh +__ZN8Security10AclSubjectC4Emh +__ZN8Security9ObjectAcl8AclEntry10importBlobERNS_23LowLevelMemoryUtilities6ReaderES4_ +__ZN8Security9ObjectAcl3addERKSsRKNS0_8AclEntryE +__ZN8Security9ObjectAcl3addERKSsNS0_8AclEntryEm +__ZN8Security9ObjectAcl5EntryD2Ev +__ZN8Security9ObjectAcl5EntryD4Ev +__Z11_XreleaseDbP17mach_msg_header_tS0_ +__Z33__MIG_check__Request__releaseDb_tP22__Request__releaseDb_t +__Z21ucsp_server_releaseDbjj13audit_token_tPlm +__ZN8NodeCore4killERS_ +__ZN8NodeCore15removeReferenceERS_ +__ZN16KeychainDatabaseD0Ev +__ZN16KeychainDatabaseD4Ev __ZN17SecurityServerAclD2Ev -__Z36__MIG_check__Request__setupSession_tP25__Request__setupSession_t __ZN17SecurityServerAclD4Ev -__Z32__MIG_check__Request__setupNew_tP21__Request__setupNew_t -__ZN13Authorization20AuthorizationDBPlist11parseConfigEP14__CFDictionary -__Z48__MIG_check__Request__authorizationInternalize_tP37__Request__authorizationInternalize_t -__ZN14EntropyManagerC4ERN8Security12MachPlusPlus10MachServerEPKc -__Z33__MIG_check__Request__releaseDb_tP22__Request__releaseDb_t -__ZN14EntropyManager6actionEv -__ZN16KeychainNotifier6unlockERKN8Security14DLDbIdentifierE -__ZN7SessionD4Ev +__ZN8Security9ObjectAclD2Ev +__ZN8Security9ObjectAclD4Ev +__ZN8Security10AclSubjectD2Ev +__ZN8Security10AclSubjectD4Ev __Z21_XrequestNotificationP17mach_msg_header_tS0_ -__ZN11RootSessionC4EN8Security12MachPlusPlus4PortEm -__Z24_XunlockDbWithPassphraseP17mach_msg_header_tS0_ -__Z7initMdsv -__Z45__MIG_check__Request__authorizationCopyInfo_tP34__Request__authorizationCopyInfo_t -__Z13handleSIGCHLDi -__Z35__MIG_check__Request__setupThread_tP24__Request__setupThread_t -__ZN13Authorization20AuthorizationDBPlistC4EPKc -__ZN18DatabaseCryptoCoreD4Ev -__Z28ucsp_server_stopNotificationjj16security_token_tPlj -__ZN6Server15notifyNoSendersEN8Security12MachPlusPlus4PortEj -__ZN7Process20requestNotificationsEN8Security12MachPlusPlus4PortEmm -__ZN8ListenerC1ER7ProcessN8Security12MachPlusPlus4PortEmm -__ZN11RootSessionC1EN8Security12MachPlusPlus4PortEm -__Z46__MIG_check__Request__unlockDbWithPassphrase_tP35__Request__unlockDbWithPassphrase_t -__ZN14EntropyManagerC1ERN8Security12MachPlusPlus10MachServerEPKc __Z43__MIG_check__Request__requestNotification_tP32__Request__requestNotification_t -__ZN6ServerC1ER9AuthorityR14CodeSignaturesPKc -__ZN18DatabaseCryptoCoreD2Ev -__ZN7Process17stopNotificationsEN8Security12MachPlusPlus4PortE -__ZN7SessionD2Ev -__ZN14DynamicSession7releaseEv -__Z18_XstopNotificationP17mach_msg_header_tS0_ -__ZN14DynamicSessionD0Ev -__Z40__MIG_check__Request__stopNotification_tP29__Request__stopNotification_t -__ZN13Authorization20AuthorizationDBPlistC1EPKc -__ZN9XDatabase6CommonD0Ev -__ZN9XDatabase7discardEPNS_6CommonE -__ZN13Authorization14CredentialImpl10invalidateEv -__ZN13Authorization6EngineC4EPKc -__ZN8ListenerD4Ev -__ZN8ListenerD0Ev -__Z14handleSIGOtheri -__ZN13Authorization6EngineC2EPKc -__ZN9AuthorityC1EPKc -__ZN9AuthorityC4EPKc -__ZN14CodeSignaturesC1EPKc -__ZN14EntropyManager14collectEntropyEv -__ZN14CodeSignaturesC4EPKc +__Z31ucsp_server_requestNotificationjj13audit_token_tPljmm +__ZN7Process20requestNotificationsEN8Security12MachPlusPlus4PortEmm +__ZN15ProcessListenerC1ER7ProcessN8Security12MachPlusPlus4PortEmm +__ZN15ProcessListenerC4ER7ProcessN8Security12MachPlusPlus4PortEmm +__ZN8ListenerC4EN8Security12MachPlusPlus4PortEmm +__ZNK8Security17CssmSubserviceUideqERK19cssm_subservice_uid +__ZN8Security6DbNameD1Ev +__ZN8Security6DbNameD4Ev +__Z10_XisLockedP17mach_msg_header_tS0_ +__Z32__MIG_check__Request__isLocked_tP21__Request__isLocked_t +__Z20ucsp_server_isLockedjj13audit_token_tPlmPi +__Z11_XdecodeKeyP17mach_msg_header_tS0_ +__Z33__MIG_check__Request__decodeKey_tP22__Request__decodeKey_t +__Z21ucsp_server_decodeKeyjj13audit_token_tPlPmPN8Security7CssmKey6HeaderEmPvj +__ZN11KeychainKeyC1ER8DatabasePKN8Security14SecurityServer7KeyBlobE +__ZN11KeychainKeyC4ER8DatabasePKN8Security14SecurityServer7KeyBlobE +__ZN8LocalKeyC2ER8Databasem +__ZN8LocalKeyC4ER8Databasem +__ZN3KeyC2ER8Database +__ZN3KeyC4ER8Database +__ZN8LocalKey9returnKeyERmRN8Security7CssmKey6HeaderE +__ZN11KeychainKey9getHeaderERN8Security7CssmKey6HeaderE +__Z9_XdecryptP17mach_msg_header_tS0_ +__Z31__MIG_check__Request__decrypt_tP20__Request__decrypt_t +__Z19ucsp_server_decryptjj13audit_token_tPlN8Security7ContextEPvPNS2_4AttrEjmS3_jPS3_Pj +__Z8relocateRN8Security7ContextEPvPNS0_4AttrEm +__ZN6Server3keyEm +__ZN13LocalDatabase7decryptERKN8Security7ContextER3KeyRKNS0_8CssmDataERS6_ +__ZN8LocalKey8keyValueEv +__ZN11KeychainKey6getKeyEv +__ZN11KeychainKey6decodeEv +__ZNK11KeychainKey8databaseEv +__ZN16KeychainDatabase9decodeKeyEPN8Security14SecurityServer7KeyBlobERNS0_7CssmKeyERPvS7_ +__ZN16KeychainDatabase8unlockDbEv +__ZN16KeychainDatabase12makeUnlockedEv +__ZN16KeychainDatabase12makeUnlockedEPKN8Security17AccessCredentialsE +__ZN8Security10CssmClient7KeyImplD0Ev +__ZN8Security10CssmClient7KeyImplD4Ev +__ZN8Security10CssmClient7KeyImpl10deactivateEv +__ZN8Security10CssmClient9AclBearerD2Ev +__ZN8Security10CssmClient9AclBearerD4Ev +__ZN15ProcessListener8notifyMeEmmRKN8Security8CssmDataE _ucsp_notify_sender_notify -__ZN6Server3runEv -__ZN13Authorization14CredentialImplD4Ev +__ZNK18DatabaseCryptoCore13decodeKeyCoreEPN8Security14SecurityServer7KeyBlobERNS0_7CssmKeyERPvS7_ +__ZN8Security4h2niERNS_7CssmKey6HeaderE +__ZN8Security4n2hiERNS_7CssmKey6HeaderE +__ZN8Security10CssmClient9UnwrapKeyclERKNS_7CssmKeyERKNS0_7KeySpecERS2_PNS_8CssmDataE +__ZN11KeychainKey3aclEv +__ZNK8Security19ThresholdAclSubject5Maker4makeEhRNS_23LowLevelMemoryUtilities6ReaderES4_ +__ZNK24KeychainPromptAclSubject5Maker4makeEhRN8Security23LowLevelMemoryUtilities6ReaderES4_ +__ZN24KeychainPromptAclSubjectC1ESsRK33cssm_acl_keychain_prompt_selector +__ZN24KeychainPromptAclSubjectC4ESsRK33cssm_acl_keychain_prompt_selector +__ZN8Security19ThresholdAclSubjectC1EmmRKSt6vectorINS_10RefPointerINS_10AclSubjectEEESaIS4_EE +__ZN8Security19ThresholdAclSubjectC4EmmRKSt6vectorINS_10RefPointerINS_10AclSubjectEEESaIS4_EE +__ZNK8Security23CodeSignatureAclSubject5Maker4makeEhRNS_23LowLevelMemoryUtilities6ReaderES4_ +__ZN8Security11CodeSigning9OSXSigner7restoreEjPKvm +__ZN8Security23CodeSignatureAclSubjectC4ERNS_9AllocatorEPKNS_11CodeSigning9SignatureEPKvm +__ZN8Security12CssmAutoData5resetEv +__ZN8Security7Context4findEmPK22cssm_context_attributej +__ZN11KeychainKey15relatedDatabaseEv +__ZN17SecurityServerAcl8validateElRKN8Security7ContextEP8Database +__ZN17SecurityServerAcl8validateElPKN8Security17AccessCredentialsEP8Database +__ZN8Security9ObjectAcl8validateElPKNS_17AccessCredentialsEPNS_24AclValidationEnvironmentE +__ZN8Security9ObjectAcl9validatesElPKNS_17AccessCredentialsEPNS_24AclValidationEnvironmentE +__ZN8Security9ObjectAcl9validatesERNS_20AclValidationContextE +__ZN11KeychainKey14instantiateAclEv +__ZNK8Security20AclValidationContext9s_credTagEv +__ZNK8Security20AclValidationContext7credTagEv +__ZNK8Security9ObjectAcl8getRangeERKSsRSt4pairISt17_Rb_tree_iteratorIS3_IS1_NS0_8AclEntryEERKS6_PS7_ESA_E +__ZNK8Security9ObjectAcl8AclEntry10authorizesEl +__ZN8Security20AclValidationContext8entryTagERKSs +__ZNK8Security9ObjectAcl8AclEntry8validateERKNS_20AclValidationContextE +__ZNK8Security16SimpleAclSubject8validateERKNS_20AclValidationContextE +__ZNK8Security9TypedList8isProperEv +__ZNK8Security11ListElement4wordEv +__ZNK8Security19ThresholdAclSubject8validateERKNS_20AclValidationContextERKNS_9TypedListE +__ZNK8Security23CodeSignatureAclSubject8validateERKNS_20AclValidationContextE +__ZNK8Security13CssmOwnedData3getEv +__ZN25SecurityServerEnvironment19verifyCodeSignatureEPKN8Security11CodeSigning9SignatureEPKNS0_8CssmDataE +__ZN14CodeSignatures6verifyER7ProcessPKN8Security11CodeSigning9SignatureEPKNS2_8CssmDataE +__ZNK7Process7getHashERN8Security11CodeSigning9OSXSignerE +__ZN8Security11CodeSigning9OSXSigner4signERKNS0_8SignableE +__ZNK8Security13GenericBundle12scanContentsERNS_11CodeSigning6Signer5StateE +__ZNK8Security13GenericBundle14executablePathEv +__ZNK8Security13GenericBundle8cfBundleEv +__ZN8Security8cfStringEPK7__CFURLb +__ZN8Security7OSXCode8scanFileEPKcRNS_11CodeSigning6Signer5StateE +__ZN8Security11CodeSigning9OSXSigner8Digester17enumerateContentsEPKvm +__ZN8Security10CssmClient6Digest6digestEPKNS_8CssmDataEm +__ZN8Security10CssmClient6Digest8activateEv +__ZN8Security10CssmClient6DigestclERNS_8CssmDataE +__ZN14CodeSignatures4findERNS_8IdentityEj +__ZN5DbKeyC4EcRKN8Security8CssmDataEbj +__ZNK8Security12UnixPlusPlus6UnixDb3getERKNS_8CssmDataERS2_i +__ZN8Security15CssmManagedDataD2Ev +__ZN8Security15CssmManagedDataD4Ev +__ZN14CodeSignatures8Identity13canonicalNameERKSs +__ZNK7Process7getPathEv +__ZNK8Security8CssmList6lengthEv +__ZNK8Security8CssmListixEj +__ZNK24KeychainPromptAclSubject8validateERKN8Security20AclValidationContextERKNS0_9TypedListE +__ZNK10__cxxabiv121__vmi_class_type_info20__do_find_public_srcEiPKvPKNS_17__class_type_infoES2_ +__ZNK10__cxxabiv117__class_type_info20__do_find_public_srcEiPKvPKS0_S2_ +__ZN16QueryKeychainUseC1EbPK8Database +__ZN16QueryKeychainUseC4EbPK8Database +__ZN16AuthHostInstanceD0Ev +__ZN16AuthHostInstanceD4Ev +__ZN11ServerChildD2Ev +__ZN11ServerChildD4Ev +__ZN8Security9ConditionD1Ev +__ZN8Security9ConditionD4Ev +__ZN8Security12UnixPlusPlus5ChildD2Ev +__ZN8Security12UnixPlusPlus5ChildD4Ev +__ZN18SecurityAgentQuery10inferHintsER7Process +__ZNK16KeychainDatabase6dbNameEv +__ZN16QueryKeychainUse9queryUserEPKcS1_l +__ZN13SecurityAgent6Client11checkResultEv +__ZN13Authorization8AuthItem11getCssmDataERN8Security12CssmAutoDataE +__ZN18SensitiveAllocator4freeEPv +__ZN18SecurityAgentQuery10readChoiceEv +__ZN13Authorization8AuthItem9getStringERSs +__ZN18SecurityAgentQueryD2Ev +__ZN8Security20AclValidationContextD2Ev +__ZN8Security20AclValidationContextD4Ev +__ZN8Security24AclValidationEnvironmentD2Ev +__ZN8Security24AclValidationEnvironmentD4Ev +__ZN8Security10CssmClient7Context8overrideERKNS_7ContextE +__Z12_XreleaseKeyP17mach_msg_header_tS0_ +__Z34__MIG_check__Request__releaseKey_tP23__Request__releaseKey_t +__Z22ucsp_server_releaseKeyjj13audit_token_tPlm +__ZN8Database10releaseKeyER3Key +__ZN11KeychainKeyD0Ev +__ZN11KeychainKeyD4Ev +__ZN8Security23CodeSignatureAclSubjectD0Ev +__ZN8Security23CodeSignatureAclSubjectD4Ev +__ZN8LocalKeyD2Ev +__ZN8LocalKeyD4Ev +__Z18_XpostNotificationP17mach_msg_header_tS0_ +__Z40__MIG_check__Request__postNotification_tP29__Request__postNotification_t +__Z28ucsp_server_postNotificationjmmPvj +__ZN8Listener6removeEN8Security12MachPlusPlus4PortE +__ZN8ListenerD4Ev +__ZNK13Authorization8RuleImpl12evaluateUserERKNS_11AuthItemRefERKNS_4RuleERNS_11AuthItemSetEmdPKSt3setINS_10CredentialESt4lessISA_ESaISA_EERSE_R18AuthorizationToken +__ZNK13Authorization8RuleImpl26evaluateCredentialForRightERKNS_11AuthItemRefERKNS_4RuleERKNS_11AuthItemSetEdRKNS_10CredentialEb +__ZNK13Authorization14CredentialImpl12creationTimeEv +__ZN18AuthorizationToken17setCredentialInfoERKN13Authorization10CredentialE +__ZNK8Security14ExecutableTool13canonicalPathEv +__ZN13Authorization14CredentialImpl10invalidateEv +__ZNK13Authorization8RuleImpl21evaluateAuthorizationERKNS_11AuthItemRefERKNS_4RuleERNS_11AuthItemSetEmdPKSt3setINS_10CredentialESt4lessISA_ESaISA_EERSE_R18AuthorizationToken +__ZNK13Authorization8RuleImpl20evaluateSessionOwnerERKNS_11AuthItemRefERKNS_4RuleERKNS_11AuthItemSetEdRK18AuthorizationTokenRSs +__ZNK14DynamicSession13originatorUidEv +__ZN18AuthorizationToken12scrubInfoSetEv +__ZNK8Security14ExecutableTool6encodeEv diff --git a/src/securityserver.h b/src/securityserver.h deleted file mode 100644 index 3c71207..0000000 --- a/src/securityserver.h +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (c) 2000-2004 Apple Computer, Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - - -// -// securityserver.h - master header file for the SecurityServer. -// -#ifndef _H_SECURITYSERVER -#define _H_SECURITYSERVER - -#include -#include -#include -#include -#include -//#include -#include -#include -#include -#include -#include -#include - -namespace Security { - -using namespace SecurityServer; -using namespace UnixPlusPlus; - - -// -// Logging and verbosity levels -// -extern uint32 debugMode; -extern const char *bootstrapName; - -} // end namespace Security - -#endif //_H_SECURITYSERVER diff --git a/src/server.cpp b/src/server.cpp index af82dd7..f440a7d 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -3,8 +3,6 @@ * * @APPLE_LICENSE_HEADER_START@ * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. - * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in @@ -25,14 +23,19 @@ // -// server - the actual SecurityServer server object +// server - securityd main server object // -#include // knowledge of mig message sizes +#include // MIG ucsp service +#include "self.h" // MIG self service +#include +#include #include "server.h" #include "session.h" #include "acls.h" #include "notifications.h" +#include "child.h" #include +#include using namespace MachPlusPlus; @@ -56,10 +59,16 @@ Server::Server(Authority &authority, CodeSignatures &signatures, const char *boo mBootstrapName(bootstrapName), mCSPModule(gGuidAppleCSP, mCssm), mCSP(mCSPModule), mAuthority(authority), - mCodeSignatures(signatures) + mCodeSignatures(signatures), + mAudit(geteuid(), getpid()) { + // make me eternal (in the object mesh) + ref(); + + mAudit.registerSession(); + // engage the subsidiary port handler for sleep notifications - add(sleepWatcher); + add(sleepWatcher); } @@ -129,39 +138,30 @@ RefPointer Server::key(KeyHandle key) RefPointer Server::database(DbHandle db) { - RefPointer database = - HandleObject::findRef(db, CSSMERR_DL_INVALID_DB_HANDLE); - if (database->process() != process()) - CssmError::throwMe(CSSMERR_DL_INVALID_DB_HANDLE); - return database; + return find(db, CSSMERR_DL_INVALID_DB_HANDLE); } RefPointer Server::keychain(DbHandle db) { - RefPointer keychain = - HandleObject::findRef(db, CSSMERR_DL_INVALID_DB_HANDLE); - if (keychain->process() != process()) - CssmError::throwMe(CSSMERR_DL_INVALID_DB_HANDLE); - return keychain; + return find(db, CSSMERR_DL_INVALID_DB_HANDLE); } -RefPointer Server::optionalDatabase(DbHandle db) +RefPointer Server::optionalDatabase(DbHandle db, bool persistent) { - if (db == noDb) - return &process().localStore(); - else + if (persistent && db != noDb) return database(db); + else + return &process().localStore(); } // // Locate an ACL bearer (database or key) by handle // -SecurityServerAcl &Server::aclBearer(AclKind kind, CSSM_HANDLE handle) +AclSource &Server::aclBearer(AclKind kind, CSSM_HANDLE handle) { - SecurityServerAcl &bearer = - HandleObject::find(handle, CSSMERR_CSSM_INVALID_ADDIN_HANDLE); - if (kind != bearer.kind()) + AclSource &bearer = HandleObject::find(handle, CSSMERR_CSSM_INVALID_ADDIN_HANDLE); + if (kind != bearer.acl().aclKind()) CssmError::throwMe(CSSMERR_CSSM_INVALID_HANDLE_USAGE); return bearer; } @@ -174,37 +174,55 @@ void Server::run() { MachServer::run(0x10000, MACH_RCV_TRAILER_TYPE(MACH_MSG_TRAILER_FORMAT_0) | - MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_SENDER)); + MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_AUDIT)); +} + + +// +// Handle thread overflow. MachServer will call this if it has hit its thread +// limit and yet still needs another thread. +// +void Server::threadLimitReached(UInt32 limit) +{ + Syslog::notice("securityd has reached its thread limit (%ld) - service deadlock is possible", + limit); } // // The primary server run-loop function. -// Invokes the MIG-generated main dispatch function (ucsp_server). +// Invokes the MIG-generated main dispatch function (ucsp_server), as well +// as the self-send dispatch (self_server). // For debug builds, look up request names in a MIG-generated table // for better debug-log messages. // boolean_t ucsp_server(mach_msg_header_t *, mach_msg_header_t *); +boolean_t self_server(mach_msg_header_t *, mach_msg_header_t *); #if defined(NDEBUG) boolean_t Server::handle(mach_msg_header_t *in, mach_msg_header_t *out) { - return ucsp_server(in, out); + return ucsp_server(in, out) || self_server(in, out); } #else //NDEBUG -static const struct IPCName { const char *name; int ipc; } ipcNames[] = - { subsystem_to_name_map_ucsp }; // macro generated by MIG, from ucsp.h +struct IPCName { const char *name; int ipc; }; +static IPCName ucspNames[] = { subsystem_to_name_map_ucsp }; // generated by MIG +static IPCName selfNames[] = { subsystem_to_name_map_self }; // generated by MIG boolean_t Server::handle(mach_msg_header_t *in, mach_msg_header_t *out) { - const int first = ipcNames[0].ipc; - const char *name = (in->msgh_id >= first && in->msgh_id < first + ucsp_MSG_COUNT) ? - ipcNames[in->msgh_id - first].name : "OUT OF BOUNDS"; + const int id = in->msgh_id; + const int ucspBase = ucspNames[0].ipc; + const int selfBase = selfNames[0].ipc; + const char *name = + (id >= ucspBase && id < ucspBase + ucsp_MSG_COUNT) ? ucspNames[id - ucspBase].name : + (id >= selfBase && id < selfBase + self_MSG_COUNT) ? selfNames[id - selfBase].name : + "OUT OF BOUNDS"; secdebug("SSreq", "begin %s (%d)", name, in->msgh_id); - boolean_t result = ucsp_server(in, out); + boolean_t result = ucsp_server(in, out) || self_server(in, out); secdebug("SSreq", "end %s (%d)", name, in->msgh_id); return result; } @@ -220,7 +238,7 @@ boolean_t Server::handle(mach_msg_header_t *in, mach_msg_header_t *out) // in the case of session re-initialization (see below). // void Server::setupConnection(ConnectLevel type, Port servicePort, Port replyPort, Port taskPort, - const security_token_t &securityToken, const ClientSetupInfo *info, const char *identity) + const audit_token_t &auditToken, const ClientSetupInfo *info, const char *identity) { // first, make or find the process based on task port StLock _(*this); @@ -229,12 +247,16 @@ void Server::setupConnection(ConnectLevel type, Port servicePort, Port replyPort // The client has talked to us before and now wants to create a new session. proc->changeSession(servicePort); } + if (proc && type == connectNewProcess) { + // the client has amnesia - reset it + assert(info && identity); + proc->reset(servicePort, taskPort, info, identity, AuditToken(auditToken)); + } if (!proc) { if (type == connectNewThread) // client error (or attack) CssmError::throwMe(CSSM_ERRCODE_INTERNAL_ERROR); assert(info && identity); - proc = new Process(servicePort, taskPort, info, identity, - securityToken.val[0], securityToken.val[1]); + proc = new Process(servicePort, taskPort, info, identity, AuditToken(auditToken)); notifyIfDead(taskPort); } @@ -292,6 +314,7 @@ void Server::notifyDeadName(Port port) if (Listener::remove(port)) return; + // well, what IS IT?! secdebug("server", "spurious dead port notification for port %d", port.port()); } @@ -307,6 +330,46 @@ void Server::notifyNoSenders(Port port, mach_port_mscount_t) } +// +// Handling signals. +// These are sent as Mach messages from ourselves to escape the limitations of +// the signal handler environment. +// +kern_return_t self_server_handleSignal(mach_port_t sport, + mach_port_t taskPort, int sig) +{ + try { + if (taskPort != mach_task_self()) { + Syslog::error("handleSignal: received from someone other than myself"); + secdebug("SS", "unauthorized handleSignal"); + return 0; + } + secdebug("SS", "dispatching indirect signal %d", sig); + switch (sig) { + case SIGCHLD: + ServerChild::checkChildren(); + break; + case SIGINT: + case SIGTERM: + secdebug("SS", "signal %d received: terminating", sig); + Syslog::notice("securityd terminating due to signal %d", sig); + exit(0); +#if defined(DEBUGDUMP) + case SIGUSR1: + NodeCore::dumpAll(); + break; +#endif //DEBUGDUMP + default: + assert(false); + } + } catch(...) { + secdebug("SS", "exception handling a signal (ignored)"); + } + mach_port_deallocate(mach_task_self(), taskPort); + return 0; +} + + // // Notifier for system sleep events // @@ -314,63 +377,48 @@ void Server::SleepWatcher::systemWillSleep() { secdebug("SS", "sleep notification received"); Session::processSystemSleep(); + secdebug("server", "distributing sleep event to %ld clients", mPowerClients.size()); + for (set::const_iterator it = mPowerClients.begin(); it != mPowerClients.end(); it++) + (*it)->systemWillSleep(); } +void Server::SleepWatcher::systemIsWaking() +{ + secdebug("server", "distributing wakeup event to %ld clients", mPowerClients.size()); + for (set::const_iterator it = mPowerClients.begin(); it != mPowerClients.end(); it++) + (*it)->systemIsWaking(); +} -// -// Return the primary Cryptographic Service Provider. -// This will be lazily loaded when it is first requested. -// -CssmClient::CSP &Server::getCsp() +void Server::SleepWatcher::add(PowerWatcher *client) { - if (!mCssm->isActive()) - loadCssm(); - return mCSP; + assert(mPowerClients.find(client) == mPowerClients.end()); + mPowerClients.insert(client); +} + +void Server::SleepWatcher::remove(PowerWatcher *client) +{ + assert(mPowerClients.find(client) != mPowerClients.end()); + mPowerClients.erase(client); } // // Initialize the CSSM/MDS subsystem. -// This is thread-safe and can be done lazily. +// This was once done lazily on demand. These days, we are setting up the +// system MDS here, and CSSM is pretty much always needed, so this is called +// early during program startup. Do note that the server may not (yet) be running. // -static void initMds(); - void Server::loadCssm() { if (!mCssm->isActive()) { StLock _(*this); if (!mCssm->isActive()) { - try { - initMds(); - } catch (const CssmError &error) { - switch (error.osStatus()) { - case CSSMERR_DL_MDS_ERROR: - case CSSMERR_DL_OS_ACCESS_DENIED: - secdebug("SS", "MDS initialization failed; continuing"); - Syslog::warning("MDS initialization failed; continuing"); - break; - default: - throw; - } - } + secdebug("SS", "Installing MDS"); + MDSClient::mds().install(); secdebug("SS", "CSSM initializing"); mCssm->init(); mCSP->attach(); - IFDEBUG(char guids[Guid::stringRepLength+1]); - secdebug("SS", "CSSM ready with CSP %s", mCSP->guid().toString(guids)); + secdebug("SS", "CSSM ready with CSP %s", mCSP->guid().toString().c_str()); } } } - -#include - -static void initMds() -{ - secdebug("SS", "MDS initializing"); - CssmAllocatorMemoryFunctions memory(Allocator::standard()); - MDS_FUNCS functions; - MDS_HANDLE handle; - CssmError::check(MDS_Initialize(NULL, &memory, &functions, &handle)); - CssmError::check(MDS_Install(handle)); - CssmError::check(MDS_Terminate(handle)); -} diff --git a/src/server.h b/src/server.h index 64a1373..80c0992 100644 --- a/src/server.h +++ b/src/server.h @@ -3,8 +3,6 @@ * * @APPLE_LICENSE_HEADER_START@ * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. - * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in @@ -25,15 +23,15 @@ // -// server - the actual Server object +// server - securityd main server object // #ifndef _H_SERVER #define _H_SERVER -#include "securityserver.h" #include "structure.h" #include #include +#include #include #include #include @@ -51,6 +49,7 @@ #define EQUIVALENCEDBPATH "/var/db/CodeEquivalenceDatabase" + // // The authority itself. You will usually only have one of these. // @@ -60,6 +59,17 @@ public: ~Authority(); }; +// +// The server object itself. This is the "go to" object for anyone who wants +// to access the server's global state. It runs the show. +// There is only one Server, and its name is Server::active(). +// +// Server also acts as the global-scope nexus of securityd's object mesh. +// Sessions have Server as their parent, and global-scope objects have it +// as their referent. The Server is never kill()ed; though kill(globalObject) +// may make sense. Also, we can search for global-scope objects by using the +// findFirst/allReferences feature of Node<>. +// class Server : public PerGlobal, public MachPlusPlus::MachServer, public UniformRandomBlobs { @@ -76,24 +86,55 @@ public: // static Server &active() { return safer_cast(MachServer::active()); } static const char *bootstrapName() { return active().mBootstrapName.c_str(); } + + // + // Each thread has at most one "active connection". If the server is currently + // servicing a request received through a Connection, that's it. Otherwise + // there is none. + // + static Connection &connection(mach_port_t replyPort); // find by reply port and make active + static Connection &connection(bool tolerant = false); // return active (or fail unless tolerant) + static void requestComplete(); // de-activate active connection - static Connection &connection(mach_port_t replyPort); - static Connection &connection(bool tolerant = false); - static void requestComplete(); - + // + // Process and session of the active Connection + // static Process &process(); static Session &session(); + // + // Find objects from their client handles. + // These will all throw on invalid handles, and the RefPointer<> results are always non-NULL. + // static RefPointer key(KeyHandle key); static RefPointer optionalKey(KeyHandle k) { return (k == noKey) ? NULL : key(k); } static RefPointer database(DbHandle db); static RefPointer keychain(DbHandle db); - static RefPointer optionalDatabase(DbHandle db); + static RefPointer optionalDatabase(DbHandle db, bool persistent = true); + static AclSource &aclBearer(AclKind kind, CSSM_HANDLE handle); + + // Generic version of handle lookup + template + static RefPointer find(CSSM_HANDLE handle, CSSM_RETURN notFoundError) + { + RefPointer object = + HandleObject::findRef(handle, notFoundError); + if (object->process() != Server::process()) + CssmError::throwMe(notFoundError); + return object; + } + + // + // publicly accessible components of the active server + // static Authority &authority() { return active().mAuthority; } static CodeSignatures &codeSignatures() { return active().mCodeSignatures; } - static SecurityServerAcl &aclBearer(AclKind kind, CSSM_HANDLE handle); - static CssmClient::CSP &csp() { return active().getCsp(); } + static CssmClient::CSP &csp() { return active().mCSP; } +public: + // + // Initialize CSSM and MDS + // void loadCssm(); public: @@ -104,7 +145,7 @@ public: connectNewThread }; void setupConnection(ConnectLevel type, Port servicePort, Port replyPort, Port taskPort, - const security_token_t &securityToken, + const audit_token_t &auditToken, const ClientSetupInfo *info = NULL, const char *executablePath = NULL); void endConnection(Port replyPort); @@ -119,14 +160,29 @@ protected: boolean_t handle(mach_msg_header_t *in, mach_msg_header_t *out); void notifyDeadName(Port port); void notifyNoSenders(Port port, mach_port_mscount_t); - + void threadLimitReached(UInt32 count); + private: - class SleepWatcher : public MachPlusPlus::PortPowerWatcher { - public: - void systemWillSleep(); - }; - SleepWatcher sleepWatcher; + class SleepWatcher : public MachPlusPlus::PortPowerWatcher { + public: + void systemWillSleep(); + void systemIsWaking(); + + void add(PowerWatcher *client); + void remove(PowerWatcher *client); + + private: + set mPowerClients; + }; + + SleepWatcher sleepWatcher; +public: + using MachServer::add; + using MachServer::remove; + void add(MachPlusPlus::PowerWatcher *client) { StLock _(*this); sleepWatcher.add(client); } + void remove(MachPlusPlus::PowerWatcher *client) { StLock _(*this); sleepWatcher.remove(client); } + private: // mach bootstrap registration name std::string mBootstrapName; @@ -146,10 +202,12 @@ private: CssmClient::Cssm mCssm; // CSSM instance CssmClient::Module mCSPModule; // CSP module CssmClient::CSP mCSP; // CSP attachment - CssmClient::CSP &getCsp(); // lazily initialize, then return CSP attachment Authority &mAuthority; CodeSignatures &mCodeSignatures; + + // Per-process audit initialization + CommonCriteria::AuditSession mAudit; }; #endif //_H_SERVER diff --git a/src/session.cpp b/src/session.cpp index 98c2762..6bd0abf 100644 --- a/src/session.cpp +++ b/src/session.cpp @@ -3,8 +3,6 @@ * * @APPLE_LICENSE_HEADER_START@ * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. - * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in @@ -50,65 +48,13 @@ PortMap Session::mSessions; // Session::Session(Bootstrap bootstrap, Port servicePort, SessionAttributeBits attrs) : mBootstrap(bootstrap), mServicePort(servicePort), - mAttributes(attrs), mDying(false) + mAttributes(attrs), mSecurityAgent(NULL), mAuthHost(NULL) { secdebug("SSsession", "%p CREATED: handle=0x%lx bootstrap=%d service=%d attrs=0x%lx", this, handle(), mBootstrap.port(), mServicePort.port(), mAttributes); } -void Session::release() -{ - // nothing by default -} - - -// -// The root session inherits the startup bootstrap and service port -// -RootSession::RootSession(Port servicePort, SessionAttributeBits attrs) - : Session(Bootstrap(), servicePort, sessionIsRoot | sessionWasInitialized | attrs) -{ - ref(); // eternalize - - // self-install (no thread safety issues here) - mSessions[mServicePort] = this; -} - - -// -// Dynamic sessions use the given bootstrap and re-register in it -// -DynamicSession::DynamicSession(const Bootstrap &bootstrap) - : ReceivePort(Server::active().bootstrapName(), bootstrap), - Session(bootstrap, *this) -{ - // tell the server to listen to our port - Server::active().add(*this); - - // register for port notifications - Server::active().notifyIfDead(bootstrapPort()); //@@@??? still needed? - Server::active().notifyIfUnused(*this); - - // self-register - StLock _(mSessions); - assert(!mSessions[*this]); // can't be registered already (we just made it) - mSessions[*this] = this; -} - -DynamicSession::~DynamicSession() -{ - // remove our service port from the server - Server::active().remove(*this); -} - - -void DynamicSession::release() -{ - mBootstrap.destroy(); -} - - // // Destroy a Session // @@ -152,20 +98,22 @@ void Session::destroy(Port servPort) StLock _(mSessions); PortMap::iterator it = mSessions.find(servPort); assert(it != mSessions.end()); - Session *session = it->second; - session->kill(); + RefPointer session = it->second; mSessions.erase(it); + session->kill(); } void Session::kill() { - release(); - - StLock _(mLock); - - // this session is now officially dying - mDying = true; - + StLock _(*this); + + // release authorization host objects + { + StLock _(mAuthHostLock); + mSecurityAgent = NULL; + mAuthHost = NULL; + } + // invalidate shared credentials { StLock _(mCredsLock); @@ -183,13 +131,141 @@ void Session::kill() // -// Relay lockAllDatabases to all known sessions +// On system sleep, call sleepProcessing on all DbCommons of all Sessions // void Session::processSystemSleep() { StLock _(mSessions); for (PortMap::const_iterator it = mSessions.begin(); it != mSessions.end(); it++) - it->second->allReferences(&DbCommon::sleepProcessing); + it->second->allReferences(&DbCommon::sleepProcessing); +} + + +// +// On "lockAll", call sleepProcessing on all DbCommons of this session (only) +// +void Session::processLockAll() +{ + allReferences(&DbCommon::lockProcessing); +} + + +// +// The root session inherits the startup bootstrap and service port +// +RootSession::RootSession(Server &server, SessionAttributeBits attrs) + : Session(Bootstrap(), server.primaryServicePort(), + sessionIsRoot | sessionWasInitialized | attrs) +{ + parent(server); // the Server is our parent + ref(); // eternalize + + // self-install (no thread safety issues here) + mSessions[mServicePort] = this; +} + +uid_t RootSession::originatorUid() const +{ + return 0; // it's root, obviously +} + +CFDataRef RootSession::copyUserPrefs() +{ + return NULL; +} + +// +// Dynamic sessions use the given bootstrap and re-register in it +// +DynamicSession::DynamicSession(TaskPort taskPort) + : ReceivePort(Server::active().bootstrapName(), taskPort.bootstrap()), + Session(taskPort.bootstrap(), *this), + mOriginatorTask(taskPort), mHaveOriginatorUid(false) +{ + // link to Server as the global nexus in the object mesh + parent(Server::active()); + + // tell the server to listen to our port + Server::active().add(*this); + + // register for port notifications + Server::active().notifyIfDead(bootstrapPort()); //@@@??? still needed? + Server::active().notifyIfUnused(*this); + + // self-register + StLock _(mSessions); + assert(!mSessions[*this]); // can't be registered already (we just made it) + mSessions[*this] = this; + + secdebug("SSsession", "%p dynamic session originator=%d (pid=%d)", + this, mOriginatorTask.port(), taskPort.pid()); +} + +DynamicSession::~DynamicSession() +{ + // remove our service port from the server + Server::active().remove(*this); +} + + +void DynamicSession::kill() +{ + StLock _(*this); + mBootstrap.destroy(); // release our bootstrap port + Session::kill(); // continue with parent kill +} + + +// +// Set up a DynamicSession. +// This call must be made from a process within the session, and it must be the first +// such process to make the call. +// +void DynamicSession::setupAttributes(SessionCreationFlags flags, SessionAttributeBits attrs) +{ + StLock _(*this); + secdebug("SSsession", "%p setup flags=0x%lx attrs=0x%lx", this, flags, attrs); + if (attrs & ~settableAttributes) + MacOSError::throwMe(errSessionInvalidAttributes); + checkOriginator(); + if (attribute(sessionWasInitialized)) + MacOSError::throwMe(errSessionAuthorizationDenied); + setAttributes(attrs | sessionWasInitialized); +} + + +// +// Check whether the calling process is the session originator. +// If it's not, throw. +// +void DynamicSession::checkOriginator() +{ + if (mOriginatorTask != Server::process().taskPort()) + MacOSError::throwMe(errSessionAuthorizationDenied); +} + + +// +// The "originator uid" is a uid value that can be provided by the session originator +// and retrieved by anyone. Securityd places no semantic meaning on this value. +// +uid_t DynamicSession::originatorUid() const +{ + if (mHaveOriginatorUid) + return mOriginatorUid; + else + MacOSError::throwMe(errSessionValueNotSet); +} + + +void DynamicSession::originatorUid(uid_t uid) +{ + checkOriginator(); + if (mHaveOriginatorUid) // must not re-set this + MacOSError::throwMe(errSessionAuthorizationDenied); + mHaveOriginatorUid = true; + mOriginatorUid = uid; + secdebug("SSsession", "%p session uid set to %d", this, uid); } @@ -200,13 +276,13 @@ OSStatus Session::authCreate(const AuthItemSet &rights, const AuthItemSet &environment, AuthorizationFlags flags, AuthorizationBlob &newHandle, - const security_token_t &securityToken) + const audit_token_t &auditToken) { // invoke the authorization computation engine CredentialSet resultCreds; - // this will acquire mLock, so we delay acquiring it - auto_ptr auth(new AuthorizationToken(*this, resultCreds, securityToken)); + // this will acquire the object lock, so we delay acquiring it (@@@ no longer needed) + auto_ptr auth(new AuthorizationToken(*this, resultCreds, auditToken)); // Make a copy of the mSessionCreds CredentialSet sessionCreds; @@ -214,7 +290,7 @@ OSStatus Session::authCreate(const AuthItemSet &rights, StLock _(mCredsLock); sessionCreds = mSessionCreds; } - + AuthItemSet outRights; OSStatus result = Server::authority().authorize(rights, environment, flags, &sessionCreds, &resultCreds, outRights, *auth); @@ -297,7 +373,7 @@ OSStatus Session::authExternalize(const AuthorizationBlob &authBlob, AuthorizationExternalForm &extForm) { const AuthorizationToken &auth = authorization(authBlob); - StLock _(mLock); + StLock _(*this); if (auth.mayExternalize(Server::process())) { memset(&extForm, 0, sizeof(extForm)); AuthorizationExternalBlob &extBlob = @@ -322,7 +398,7 @@ OSStatus Session::authInternalize(const AuthorizationExternalForm &extForm, // check for permission and do it if (sourceAuth.mayInternalize(Server::process(), true)) { - StLock _(mLock); + StLock _(*this); authBlob = extBlob.blob; Server::process().addAuthorization(&sourceAuth); secdebug("SSauth", "Authorization %p internalized", &sourceAuth); @@ -333,29 +409,18 @@ OSStatus Session::authInternalize(const AuthorizationExternalForm &extForm, // -// Set up a (new-ish) Session. -// This call must be made from a process within the session, and it must be the first -// such process to make the call. +// The default session setup operation always fails. +// Subclasses can override this to support session setup calls. // -void Session::setup(SessionCreationFlags flags, SessionAttributeBits attrs) +void Session::setupAttributes(SessionCreationFlags flags, SessionAttributeBits attrs) { - // check current process object - it may have been cached before the client's bootstrap switch - Process *process = &Server::process(); - process->session().setupAttributes(attrs); -} - - -void Session::setupAttributes(SessionAttributeBits attrs) -{ - secdebug("SSsession", "%p setup attrs=0x%lx", this, attrs); - if (attrs & ~settableAttributes) - MacOSError::throwMe(errSessionInvalidAttributes); - if (attribute(sessionWasInitialized)) - MacOSError::throwMe(errSessionAuthorizationDenied); - setAttributes(attrs | sessionWasInitialized); + MacOSError::throwMe(errSessionAuthorizationDenied); } +// +// Authorization database I/O +// OSStatus Session::authorizationdbGet(AuthorizationString inRightName, CFDictionaryRef *rightDict) { string rightName(inRightName); @@ -445,6 +510,48 @@ AuthorizationToken &Session::authorization(const AuthorizationBlob &blob) return auth; } +RefPointer +Session::authhost(const AuthHostType hostType, const bool restart) +{ + StLock _(mAuthHostLock); + + if (hostType == privilegedAuthHost) + { + if (restart || !mAuthHost || (mAuthHost->state() != Security::UnixPlusPlus::Child::alive)) + { + if (mAuthHost) + PerSession::kill(*mAuthHost); + mAuthHost = new AuthHostInstance(*this, hostType); + } + return mAuthHost; + } + else /* if (hostType == securityAgent) */ + { + if (restart || !mSecurityAgent || (mSecurityAgent->state() != Security::UnixPlusPlus::Child::alive)) + { + if (mSecurityAgent) + PerSession::kill(*mSecurityAgent); + mSecurityAgent = new AuthHostInstance(*this, hostType); + } + return mSecurityAgent; + } +} + +void DynamicSession::setUserPrefs(CFDataRef userPrefsDict) +{ + checkOriginator(); + StLock _(*this); + mSessionAgentPrefs = userPrefsDict; +} + +CFDataRef DynamicSession::copyUserPrefs() +{ + StLock _(*this); + if (mSessionAgentPrefs) + CFRetain(mSessionAgentPrefs); + return mSessionAgentPrefs; +} + // // Debug dumping @@ -454,10 +561,8 @@ AuthorizationToken &Session::authorization(const AuthorizationBlob &blob) void Session::dumpNode() { PerSession::dumpNode(); - if (mDying) - Debug::dump(" DYING"); - Debug::dump(" boot=%d service=%d attrs=0x%lx", - mBootstrap.port(), mServicePort.port(), mAttributes); + Debug::dump(" boot=%d service=%d attrs=0x%lx authhost=%p securityagent=%p", + mBootstrap.port(), mServicePort.port(), mAttributes, mAuthHost, mSecurityAgent); } #endif //DEBUGDUMP diff --git a/src/session.h b/src/session.h index b9950c2..b252964 100644 --- a/src/session.h +++ b/src/session.h @@ -3,8 +3,6 @@ * * @APPLE_LICENSE_HEADER_START@ * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. - * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in @@ -30,10 +28,10 @@ #ifndef _H_SESSION #define _H_SESSION -#include "securityserver.h" #include "structure.h" #include "acls.h" #include "authority.h" +#include "authhost.h" #include #include #include @@ -48,7 +46,8 @@ using __gnu_cxx::hash_map; class Key; class Connection; - +class Server; +class AuthHostInstance; // // A Session object represents one or more Connections that are known to @@ -68,8 +67,6 @@ public: Bootstrap bootstrapPort() const { return mBootstrap; } Port servicePort() const { return mServicePort; } - virtual void release(); - IFDUMP(virtual void dumpNode()); public: @@ -78,10 +75,12 @@ public: SessionAttributeBits attributes() const { return mAttributes; } bool attribute(SessionAttributeBits bits) const { return mAttributes & bits; } - - static void setup(SessionCreationFlags flags, SessionAttributeBits attrs); - void setupAttributes(SessionAttributeBits attrs); - + + virtual void setupAttributes(SessionCreationFlags flags, SessionAttributeBits attrs); + virtual bool haveOriginatorUid() const = 0; + virtual uid_t originatorUid() const = 0; + virtual CFDataRef copyUserPrefs() = 0; + protected: void setAttributes(SessionAttributeBits attrs) { mAttributes |= attrs; } @@ -89,7 +88,7 @@ public: const CredentialSet &authCredentials() const { return mSessionCreds; } OSStatus authCreate(const AuthItemSet &rights, const AuthItemSet &environment, - AuthorizationFlags flags, AuthorizationBlob &newHandle, const security_token_t &securityToken); + AuthorizationFlags flags, AuthorizationBlob &newHandle, const audit_token_t &auditToken); void authFree(const AuthorizationBlob &auth, AuthorizationFlags flags); OSStatus authGetRights(const AuthorizationBlob &auth, const AuthItemSet &requestedRights, const AuthItemSet &environment, @@ -116,27 +115,43 @@ protected: public: static Session &find(Port servPort); static Session &find(SecuritySessionId id); + template static SessionType &find(SecuritySessionId id); static void destroy(Port servPort); static void processSystemSleep(); - + void processLockAll(); + + RefPointer authhost(const AuthHostType hostType = securityAgent, const bool restart = false); + protected: - mutable Mutex mLock; // object lock - Bootstrap mBootstrap; // session bootstrap port Port mServicePort; // SecurityServer service port for this session SessionAttributeBits mAttributes; // attribute bits (see AuthSession.h) - bool mDying; // session is dying mutable Mutex mCredsLock; // lock for mSessionCreds CredentialSet mSessionCreds; // shared session authorization credentials + mutable Mutex mAuthHostLock; + AuthHostInstance *mSecurityAgent; + AuthHostInstance *mAuthHost; + + CFRef mSessionAgentPrefs; + void kill(); private: static PortMap mSessions; }; +template +SessionType &Session::find(SecuritySessionId id) +{ + if (SessionType *ssn = dynamic_cast(&find(id))) + return *ssn; + else + MacOSError::throwMe(errSessionInvalidId); +} + // // The RootSession is the session (i.e. bootstrap dictionary) of system daemons that are @@ -147,7 +162,11 @@ private: // class RootSession : public Session { public: - RootSession(Port servicePort, SessionAttributeBits attrs = 0); + RootSession(Server &server, SessionAttributeBits attrs = 0); + + bool haveOriginatorUid() const { return true; } + uid_t originatorUid() const; + CFDataRef copyUserPrefs(); }; @@ -159,11 +178,25 @@ public: // class DynamicSession : private ReceivePort, public Session { public: - DynamicSession(const Bootstrap &bootstrap); + DynamicSession(TaskPort taskPort); ~DynamicSession(); + void setupAttributes(SessionCreationFlags flags, SessionAttributeBits attrs); + + bool haveOriginatorUid() const { return mHaveOriginatorUid; } + uid_t originatorUid() const; + void originatorUid(uid_t uid); + void setUserPrefs(CFDataRef userPrefsDict); + CFDataRef copyUserPrefs(); + protected: - void release(); + void checkOriginator(); // fail unless current process is originator + void kill(); // augment parent's kill + +private: + Port mOriginatorTask; // originating process's task port + bool mHaveOriginatorUid; // originator uid was set by session originator + uid_t mOriginatorUid; // uid as set by session originator }; diff --git a/src/structure.cpp b/src/structure.cpp index 4d6dd36..0f1c8e7 100644 --- a/src/structure.cpp +++ b/src/structure.cpp @@ -3,8 +3,6 @@ * * @APPLE_LICENSE_HEADER_START@ * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. - * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in @@ -43,6 +41,56 @@ NodeCore::~NodeCore() } +// +// Basic object mesh maintainance +// +void NodeCore::parent(NodeCore &p) +{ + StLock _(*this); + mParent = &p; +} + +void NodeCore::referent(NodeCore &r) +{ + StLock _(*this); + assert(!mReferent); + mReferent = &r; +} + +void NodeCore::clearReferent() +{ + StLock _(*this); + if (mReferent) + assert(!mReferent->hasReference(*this)); + mReferent = NULL; +} + + +void NodeCore::addReference(NodeCore &p) +{ + StLock _(*this); + assert(p.mReferent == this); + mReferences.insert(&p); +} + +void NodeCore::removeReference(NodeCore &p) +{ + StLock _(*this); + assert(hasReference(p)); + mReferences.erase(&p); +} + +#if !defined(NDEBUG) + +bool NodeCore::hasReference(NodeCore &p) +{ + assert(p.refCountForDebuggingOnly() > 0); + return mReferences.find(&p) != mReferences.end(); +} + +#endif //NDEBUG + + // // ClearReferences clears the reference set but does not propagate // anything; it is NOT recursive. @@ -72,6 +120,15 @@ void NodeCore::kill() } +void NodeCore::kill(NodeCore &ref) +{ + StLock _(*this); + assert(hasReference(ref)); + ref.kill(); + removeReference(ref); +} + + // // NodeCore-level support for state dumping. // Call NodeCore::dumpAll() to debug-dump all nodes. @@ -110,8 +167,11 @@ void NodeCore::dump() dumpNode(); if (!mReferences.empty()) { Debug::dump(" {"); - for (ReferenceSet::const_iterator it = mReferences.begin(); it != mReferences.end(); it++) + for (ReferenceSet::const_iterator it = mReferences.begin(); it != mReferences.end(); it++) { Debug::dump(" %p", it->get()); + if ((*it)->mReferent != this) + Debug::dump("!*INVALID*"); + } Debug::dump(" }"); } Debug::dump("\n"); diff --git a/src/structure.h b/src/structure.h index f5b61bf..025d7f2 100644 --- a/src/structure.h +++ b/src/structure.h @@ -3,8 +3,6 @@ * * @APPLE_LICENSE_HEADER_START@ * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. - * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in @@ -30,9 +28,12 @@ #ifndef _H_STRUCTURE #define _H_STRUCTURE -#include "securityserver.h" #include +#include #include +#include + +using MachPlusPlus::Port; // @@ -73,22 +74,31 @@ public: NodeCore() : Mutex(Mutex::recursive) { } #endif virtual ~NodeCore(); - - bool hasParent() const { return mParent; } - bool hasReferent() const { return mReferent; } + + void addReference(NodeCore &p); + void removeReference(NodeCore &p); // reference set operations template void allReferences(void (Sub::*func)()); template - Sub *findFirst(Value (Sub::*func)() const, Value compare); + RefPointer findFirst(Value (Sub::*func)() const, Value compare); void clearReferences(); - virtual void kill(); // always invoke NodeCore's in your override + virtual void kill(); // kill all references and self + virtual void kill(NodeCore &ref); // kill ref from my references() // for STL ordering (so we can have sets of RefPointers of NodeCores) bool operator < (const NodeCore &other) const { return this < &other; } + +protected: + void parent(NodeCore &p); // set parent + void referent(NodeCore &r); // set referent + void clearReferent(); // clear referent + + bool hasParent() const { return mParent; } + bool hasReferent() const { return mReferent; } private: RefPointer mParent; @@ -96,6 +106,8 @@ private: typedef set > ReferenceSet; ReferenceSet mReferences; + IFDEBUG(bool hasReference(NodeCore &p)); + #if defined(DEBUGDUMP) public: // dump support NodeCore(); // dump-only constructor (registers node) @@ -110,17 +122,31 @@ public: // dump support }; +// +// Call a member on each reference of a Node<> object. +// The object lock is held throughout, and we keep a RefPointer to each object +// as it's being processed. Thus it's safe for a reference to self-unlink in +// the object mesh; it'll get destroyed after its method returns. +// template void NodeCore::allReferences(void (Sub::*func)()) { StLock _(*this); for (ReferenceSet::const_iterator it = mReferences.begin(); it != mReferences.end(); it++) - if (Sub *sub = dynamic_cast(it->get())) + if (RefPointer sub = dynamic_cast(it->get())) (sub->*func)(); } + +// +// Find a reference of a Node<> object that satisfies a simple "method returns value" +// condition. There is no defined order of the scan, so if the condition is not unique, +// any one reference may be returned. If none are found, we return NULL. +// This returns a RefPointer: lifetime of the returned instance (if any) is ensured even +// if it is asynchronously removed from the references set. +// template -Sub *NodeCore::findFirst(Value (Sub::*func)() const, Value compare) +RefPointer NodeCore::findFirst(Value (Sub::*func)() const, Value compare) { StLock _(*this); for (ReferenceSet::const_iterator it = mReferences.begin(); it != mReferences.end(); it++) @@ -138,17 +164,9 @@ Sub *NodeCore::findFirst(Value (Sub::*func)() const, Value compare) template class Node : public NodeCore { protected: - void parent(Glob &p) - { StLock _(*this); mParent = &p; } - - virtual void referent(Base &r) - { StLock _(*this); mReferent = &r; } - - void clearReferent() - { - StLock _(*this); - mReferent = NULL; - } + // type-safer versions of node mesh setters + void parent(Glob &p) { NodeCore::parent(p); } + void referent(Base &r) { NodeCore::referent(r); } public: template @@ -160,9 +178,8 @@ public: { assert(mReferent); return safer_cast(*mReferent); } public: - void addReference(Base &p) - { StLock _(*this); assert(p.mReferent == this); mReferences.insert(&p); } - void removeReference(Base &p) { StLock _(*this); mReferences.erase(&p); } + void addReference(Base &p) { NodeCore::addReference(p); } + void removeReference(Base &p) { NodeCore::removeReference(p); } }; diff --git a/src/tempdatabase.cpp b/src/tempdatabase.cpp index 4d64dae..6be1e05 100644 --- a/src/tempdatabase.cpp +++ b/src/tempdatabase.cpp @@ -3,8 +3,6 @@ * * @APPLE_LICENSE_HEADER_START@ * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. - * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in @@ -37,23 +35,47 @@ #include "agentquery.h" -class TempKey : public LocalKey { +// +// Temporary-space Key objects are almost normal LocalKeys, with the key +// matter always preloaded (and thus no deferral of instantiation). +// A TempKey bears its own ACL. +// +class TempKey : public LocalKey, public SecurityServerAcl { public: TempKey(Database &db, const CssmKey &newKey, uint32 moreAttributes, const AclEntryPrototype *owner = NULL); -}; + Database *relatedDatabase(); + + SecurityServerAcl &acl() { return *this; } + +public: + // SecurityServerAcl personality + AclKind aclKind() const; +}; TempKey::TempKey(Database &db, const CssmKey &newKey, uint32 moreAttributes, const AclEntryPrototype *owner) - : LocalKey(db, newKey, moreAttributes, owner) + : LocalKey(db, newKey, moreAttributes) { - secdebug("SS adhoc", "Creating temporary (local) key"); // XXX/gh + setOwner(owner); db.addReference(*this); } +AclKind TempKey::aclKind() const +{ + return keyAcl; +} + + +Database *TempKey::relatedDatabase() +{ + return NULL; +} + + // // Create a Database object from initial parameters (create operation) // @@ -73,6 +95,11 @@ const char *TempDatabase::dbName() const return "(transient)"; } +bool TempDatabase::transient() const +{ + return true; +} + // // Invoke the Security Agent to get a passphrase (other than for a Keychain) @@ -117,9 +144,9 @@ void TempDatabase::makeSecurePassphraseKey(const Context &context, CssmClient::UnwrapKey unwrap(Server::csp(), CSSM_ALGID_NONE); CssmKey cspKey; - unwrap(rawKey, Key::KeySpec(usage, attrs), cspKey); + unwrap(rawKey, TempKey::KeySpec(usage, attrs), cspKey); - newKey = makeKey(cspKey, attrs & Key::managedAttributes, owner); + newKey = makeKey(cspKey, attrs & TempKey::managedAttributes, owner); } @@ -150,5 +177,6 @@ void TempDatabase::generateKey(const Context &context, RefPointer TempDatabase::makeKey(const CssmKey &newKey, uint32 moreAttributes, const AclEntryPrototype *owner) { + assert(!newKey.attribute(CSSM_KEYATTR_PERMANENT)); return new TempKey(*this, newKey, moreAttributes, owner); } diff --git a/src/tempdatabase.h b/src/tempdatabase.h index 7d3b50e..1019554 100644 --- a/src/tempdatabase.h +++ b/src/tempdatabase.h @@ -3,8 +3,6 @@ * * @APPLE_LICENSE_HEADER_START@ * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. - * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in @@ -38,29 +36,31 @@ // -// A Database object represents an Apple CSP/DL open database (DL/DB) object. -// It maintains its protected semantic state (including keys) and provides controlled -// access. +// A TempDatabase is simply a container of (a subclass of) LocalKey. +// When it dies, all its contents irretrievably vanish. There is no DbCommon +// or global object; each TempDatabase is completely distinct. +// Database ACLs are not (currently) supported on TempDatabases. // class TempDatabase : public LocalDatabase { public: TempDatabase(Process &proc); const char *dbName() const; + bool transient() const; + + RefPointer makeKey(const CssmKey &newKey, uint32 moreAttributes, + const AclEntryPrototype *owner); void generateKey(const Context &context, - const AccessCredentials *cred, - const AclEntryPrototype *owner, uint32 usage, - uint32 attrs, RefPointer &newKey); + const AccessCredentials *cred, + const AclEntryPrototype *owner, uint32 usage, + uint32 attrs, RefPointer &newKey); protected: void getSecurePassphrase(const Context &context, string &passphrase); void makeSecurePassphraseKey(const Context &context, const AccessCredentials *cred, const AclEntryPrototype *owner, uint32 usage, uint32 attrs, RefPointer &newKey); - - RefPointer makeKey(const CssmKey &newKey, uint32 moreAttributes, - const AclEntryPrototype *owner); }; #endif //_H_TEMPDATABASE diff --git a/src/token.cpp b/src/token.cpp index 9772864..faf7172 100644 --- a/src/token.cpp +++ b/src/token.cpp @@ -3,8 +3,6 @@ * * @APPLE_LICENSE_HEADER_START@ * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. - * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in @@ -28,11 +26,40 @@ // token - internal representation of a (single distinct) hardware token // #include "token.h" +#include "tokendatabase.h" #include "reader.h" #include "notifications.h" +#include "child.h" +#include "server.h" +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +using namespace MDSClient; + + +// +// SSID -> Token map +// +Token::SSIDMap Token::mSubservices; +// Make sure to always take mSSIDLock after we take the Token lock +// itself or own it's own. +Mutex Token::mSSIDLock; +// +// Token construction and destruction is trivial; the good stuff +// happens in insert() and remove() below. +// Token::Token() + : mFaulted(false), mTokend(NULL), mResetLevel(1) { secdebug("token", "%p created", this); } @@ -40,41 +67,388 @@ Token::Token() Token::~Token() { - secdebug("token", "%p destroyed", this); + secdebug("token", "%p (%s:%ld) destroyed", + this, mGuid.toString().c_str(), mSubservice); } Reader &Token::reader() const { - return referent(); + return referent< ::Reader>(); +} + +TokenDaemon &Token::tokend() +{ + StLock _(*this); + if (mFaulted) + CssmError::throwMe(CSSM_ERRCODE_DEVICE_FAILED); + if (mTokend) + return *mTokend; + else + CssmError::throwMe(CSSM_ERRCODE_DEVICE_FAILED); } -void Token::insert(Reader &slot) +// +// We don't currently use a database handle to tokend. +// This is just to satisfy the TokenAcl. +// +GenericHandle Token::tokenHandle() const +{ + return noDb; // we don't currently use tokend-side DbHandles +} + + +// +// Token is the SecurityServerAcl for the token +// +AclKind Token::aclKind() const +{ + return dbAcl; +} + +Token &Token::token() { - referent(slot); - mState = slot.pcscState(); - //@@@ pupulate MDS here - notify(kNotificationCDSAInsertion); + return *this; } +// +// Find Token by subservice id. +// Throws if ssid is invalid (i.e. always returns non-NULL) +// +RefPointer Token::find(uint32 ssid) +{ + StLock _(mSSIDLock); + SSIDMap::const_iterator it = mSubservices.find(ssid); + if (it == mSubservices.end()) + CssmError::throwMe(CSSMERR_CSSM_INVALID_SUBSERVICEID); + else + return it->second; +} + + +// +// Reset management. +// A Token has a "reset level", a number that is incremented whenever a token +// (hardware) reset is reported (as an error) by tokend. TokenAcls have their +// own matching level, which is that of the Token's when the ACL was last synchronized +// with tokend. Thus, incrementing the reset level invalidates all TokenAcls +// (without the need to enumerate them all). +// Note that a Token starts with a level of 1, while ACLs start at zero. This forces +// them to initially load their state from tokend. +// +Token::ResetGeneration Token::resetGeneration() const +{ + return mResetLevel; +} + +void Token::resetAcls() +{ + StLock _(*this); + mResetLevel++; + secdebug("token", "%p reset (level=%d, propagating to %ld common(s)", + this, mResetLevel, mCommons.size()); + for (CommonSet::const_iterator it = mCommons.begin(); it != mCommons.end(); it++) + RefPointer(*it)->resetAcls(); +} + +void Token::addCommon(TokenDbCommon &dbc) +{ + mCommons.insert(&dbc); +} + +void Token::removeCommon(TokenDbCommon &dbc) +{ + assert(mCommons.find(&dbc) != mCommons.end()); + mCommons.erase(&dbc); +} + + +// +// Process the logical insertion of a Token into a Reader. +// From the client's point of view, this is where the CSSM subservice is created, +// characterized, and activated. From tokend's point of view, this is where +// we're analyzing the token, determine its characteristics, and get ready to +// use it. +// +void Token::insert(::Reader &slot) +{ + try { + // this might take a while... + Server::active().longTermActivity(); + + // take Token lock and hold throughout insertion + StLock _(*this); + + Syslog::debug("token inserted into reader %s", slot.name().c_str()); + secdebug("token", "%p begin insertion into slot %p (reader %s)", + this, &slot, slot.name().c_str()); + referent(slot); + mState = slot.pcscState(); + + RefPointer tokend = chooseTokend(); + if (!tokend) { + secdebug("token", "%p no token daemons available - faulting this card", this); + fault(false); + } + + // tell the tokend object to relay faults to us + tokend->faultRelay(this); + + // locate or establish cache directories + if (tokend->hasTokenUid()) { + secdebug("token", "%p CHOOSING %s (score=%ld, uid=\"%s\")", + this, tokend->bundlePath().c_str(), tokend->score(), tokend->tokenUid().c_str()); + mCache = new TokenCache::Token(reader().cache, + tokend->bundleIdentifier() + ":" + tokend->tokenUid()); + } else { + secdebug("token", "%p CHOOSING %s (score=%ld, temporary)", + this, tokend->bundlePath().c_str(), tokend->score()); + mCache = new TokenCache::Token(reader().cache); + } + secdebug("token", "%p token cache at %s", this, mCache->root().c_str()); + + // here's the primary parameters of the new subservice + mGuid = gGuidAppleSdCSPDL; + mSubservice = mCache->subservice(); + + // establish work areas with tokend + char mdsDirectory[PATH_MAX]; + char printName[PATH_MAX]; + tokend->establish(mGuid, mSubservice, + (mCache->type() != TokenCache::Token::existing ? kSecTokendEstablishNewCache : 0) | kSecTokendEstablishMakeMDS, + mCache->cachePath().c_str(), mCache->workPath().c_str(), + mdsDirectory, printName); + + // establish print name + if (mCache->type() == TokenCache::Token::existing) { + mPrintName = mCache->printName(); + if (mPrintName.empty()) + mPrintName = printName; + } else + mPrintName = printName; + if (mPrintName.empty()) { + // last resort - new card and tokend didn't give us one + snprintf(printName, sizeof(printName), "smart card #%ld", mSubservice); + mPrintName = printName; + } + if (mCache->type() != TokenCache::Token::existing) + mCache->printName(mPrintName); // store in cache + + // install MDS + secdebug("token", "%p installing MDS from %s(%s)", this, + tokend->bundlePath().c_str(), + mdsDirectory[0] ? mdsDirectory : "ALL"); + string holdGuid = mGuid.toString(); // extend lifetime of .toString() + MDS_InstallDefaults mdsDefaults = { + holdGuid.c_str(), + mSubservice, + tokend->hasTokenUid() ? tokend->tokenUid().c_str() : "", + this->printName().c_str() + }; + mds().install(&mdsDefaults, + tokend->bundlePath().c_str(), + mdsDirectory[0] ? mdsDirectory : NULL, + NULL); + + { + // commit to insertion + StLock _(mSSIDLock); + assert(mSubservices.find(mSubservice) == mSubservices.end()); + mSubservices.insert(make_pair(mSubservice, this)); + } + + // assign mTokend right before notification - mustn't be set if + // anything goes wrong during insertion + mTokend = tokend; + + notify(kNotificationCDSAInsertion); + + Syslog::notice("reader %s inserted token \"%s\" (%s) subservice %ld using driver %s", + slot.name().c_str(), mPrintName.c_str(), + mTokend->hasTokenUid() ? mTokend->tokenUid().c_str() : "NO UID", + mSubservice, mTokend->bundleIdentifier().c_str()); + secdebug("token", "%p inserted as %s:%ld", this, mGuid.toString().c_str(), mSubservice); + } catch (const CommonError &err) { + Syslog::notice("token in reader %s cannot be used (error %ld)", slot.name().c_str(), err.osStatus()); + secdebug("token", "exception during insertion processing"); + fault(false); + } catch (...) { + // exception thrown during insertion processing. Mark faulted + Syslog::notice("token in reader %s cannot be used", slot.name().c_str()); + secdebug("token", "exception during insertion processing"); + fault(false); + } +} + + +// +// Process the logical removal of a Token from a Reader. +// Most of the time, this is asynchronous - someone has yanked the physical +// token out of a physical slot, and we're left with changing our universe +// to conform to the new realities. Reality #1 is that we can't talk to the +// physical token anymore. +// +// Note that if we're in FAULT mode, there really isn't a TokenDaemon around +// to kick. We're just holding on to represent the fact that there *is* a (useless) +// token in the slot, and now it's been finally yanked. Good riddance. +// void Token::remove() { - //@@@ clear MDS here + StLock _(*this); + Syslog::notice("reader %s removed token \"%s\" (%s) subservice %ld", + reader().name().c_str(), mPrintName.c_str(), + mTokend + ? (mTokend->hasTokenUid() ? mTokend->tokenUid().c_str() : "NO UID") + : "NO tokend", + mSubservice); + secdebug("token", "%p begin removal from slot %p (reader %s)", + this, &reader(), reader().name().c_str()); + if (mTokend) + mTokend->faultRelay(NULL); // unregister (no more faults, please) notify(kNotificationCDSARemoval); - clearReferent(); + mds().uninstall(mGuid.toString().c_str(), mSubservice); + this->kill(); + secdebug("token", "%p removal complete", this); +} + + +// +// Set the token to fault state. +// This essentially "cuts off" all operations on an inserted token and makes +// them fail. It also sends a FAULT notification via CSSM to any clients. +// Only one fault is actually processed; multiple calls are ignored. +// +// Note that a faulted token is not REMOVED; it's still physically present. +// No fault is declared when a token is actually removed. +// +void Token::fault(bool async) +{ + StLock _(*this); + if (!mFaulted) { // first one + secdebug("token", "%p %s FAULT", this, async ? "ASYNCHRONOUS" : "SYNCHRONOUS"); + + // mark faulted + mFaulted = true; + + // send CDSA notification + notify(kNotificationCDSAFailure); + + // cast off our TokenDaemon for good + mTokend = NULL; + } + + // if this is a synchronous fault, abort this operation now + if (!async) + CssmError::throwMe(CSSM_ERRCODE_DEVICE_FAILED); +} + + +void Token::relayFault(bool async) +{ + secdebug("token", "%p fault relayed from tokend", this); + this->fault(async); +} + + +// +// This is the "kill" hook for Token as a Node<> object. +// +void Token::kill() +{ + StLock _(*this); + if (mTokend) + { + mTokend = NULL; // cast loose our tokend (if any) + // Take us out of the map + StLock _(mSSIDLock); + SSIDMap::iterator it = mSubservices.find(mSubservice); + assert(it != mSubservices.end() && it->second == this); + if (it != mSubservices.end() && it->second == this) + mSubservices.erase(it); + } + + resetAcls(); // release our TokenDbCommons + PerGlobal::kill(); // generic action + } // // Send CDSA-layer notifications for this token. // These events are usually received by CDSA plugins working with securityd. -// @@@ Need to add CDSA identifier as data // void Token::notify(NotificationEvent event) { - Listener::notify(kNotificationDomainCDSA, event, CssmData()); + NameValueDictionary nvd; + CssmSubserviceUid ssuid(mGuid, NULL, mSubservice, + CSSM_SERVICE_DL | CSSM_SERVICE_CSP); + nvd.Insert(new NameValuePair(SSUID_KEY, CssmData::wrap(ssuid))); + CssmData data; + nvd.Export(data); + + // inject notification into Security event system + Listener::notify(kNotificationDomainCDSA, event, data); + + // clean up + free (data.data()); +} + + +// +// Choose a token daemon for our card. +// +// Right now, we probe tokends sequentially. If there are many tokends, it would be +// faster to launch them in parallel (relying on PCSC transactions to separate them); +// but it's not altogether clear whether this would slow things down on low-memory +// systems by forcing (excessive) swapping. There is room for future experimentation. +// +RefPointer Token::chooseTokend() +{ + //@@@ CodeRepository should learn to update from disk changes to be re-usable + CodeRepository candidates("Security/tokend", ".tokend", "TOKENDAEMONPATH", false); + candidates.update(); + //@@@ we could sort by reverse "maxScore" and avoid launching those who won't cut it anyway... + + RefPointer leader; + for (CodeRepository::const_iterator it = candidates.begin(); + it != candidates.end(); it++) { + try { + // any pre-launch screening of candidate *it goes here + + RefPointer tokend = new TokenDaemon(*it, + reader().name(), reader().pcscState(), reader().cache); + + if (tokend->state() == ServerChild::dead) // ah well, this one's no good + continue; + + // probe the (single) tokend + if (!tokend->probe()) // non comprende... + continue; + + // we got a contender! + if (!leader || tokend->score() > leader->score()) + leader = tokend; // a new front runner, he is... + } catch (...) { + secdebug("token", "exception setting up %s (moving on)", (*it)->canonicalPath().c_str()); + } + } + return leader; +} + + +// +// Token::Access mediates calls through TokenDaemon to the actual daemon out there. +// +Token::Access::Access(Token &myToken) + : token(myToken) +{ + mTokend = &token.tokend(); // throws if faulted or otherwise inappropriate +} + +Token::Access::~Access() +{ } @@ -86,6 +460,8 @@ void Token::notify(NotificationEvent event) void Token::dumpNode() { PerGlobal::dumpNode(); + Debug::dump(" %s[%ld] tokend=%p", + mGuid.toString().c_str(), mSubservice, mTokend.get()); } #endif //DEBUGDUMP diff --git a/src/token.h b/src/token.h index b487146..06a118d 100644 --- a/src/token.h +++ b/src/token.h @@ -3,8 +3,6 @@ * * @APPLE_LICENSE_HEADER_START@ * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. - * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in @@ -30,33 +28,105 @@ #ifndef _H_TOKEN #define _H_TOKEN -#include "securityserver.h" #include "structure.h" -#include "pcsc++.h" - +#include "tokencache.h" +#include "tokenacl.h" +#include "tokend.h" +#include +#include class Reader; +class TokenDbCommon; // -// Token is the global-scope object representing a smartcard token +// Token is the global-scope object representing a smartcard token. +// It also acts as the global-scope database object for the TokenDatabase representing +// its content, and carries the ObjectAcls for objects on the token. // -class Token : public PerGlobal { +class Token : public PerGlobal, public virtual TokenAcl, public FaultRelay { +public: + class Access; friend class Access; + public: Token(); ~Token(); - Reader &reader() const; + ::Reader &reader() const; + TokenDaemon &tokend(); + GenericHandle tokenHandle() const; + uint32 subservice() const { return mSubservice; } + std::string printName() const { return mPrintName; } + TokenCache::Token &cache() const { return *mCache; } - void insert(Reader &slot); + void insert(::Reader &slot); void remove(); void notify(NotificationEvent event); - + void fault(bool async); + + void kill(); + IFDUMP(void dumpNode()); + + static RefPointer find(uint32 ssid); + + ResetGeneration resetGeneration() const; + bool resetGeneration(ResetGeneration rg) const { return rg == resetGeneration(); } + void resetAcls(); + +public: + // SecurityServerAcl and TokenAcl personalities + AclKind aclKind() const; + Token &token(); // myself + + // FaultRelay personality + void relayFault(bool async); + +public: + class Access { + public: + Access(Token &token); + ~Access(); + + Token &token; + + TokenDaemon &tokend() const { return *mTokend; } + TokenDaemon &operator () () const { return tokend(); } + + private: + RefPointer mTokend; + }; +public: + // keep track of TokenDbCommons for reset processing + // (this interface is for TokenDbCommon only) + void addCommon(TokenDbCommon &dbc); + void removeCommon(TokenDbCommon &dbc); + private: - PCSC::ReaderState mState; + RefPointer chooseTokend(); + +private: + bool mFaulted; // fault state flag + RefPointer mTokend; // the (one) tokend that runs the card + RefPointer mCache; // token cache reference + std::string mPrintName; // print name of token + + Guid mGuid; // our CSP/DL's Guid + uint32 mSubservice; // dynamic subservice of gGuidAppleSdCSPDL + PCSC::ReaderState mState; // reader state as of insertion + + TokenDaemon::Score mScore; // score of winning tokend + +private: + typedef map SSIDMap; + static SSIDMap mSubservices; + static Mutex mSSIDLock; + + typedef set CommonSet; + CommonSet mCommons; + ResetGeneration mResetLevel; }; diff --git a/src/tokenaccess.cpp b/src/tokenaccess.cpp new file mode 100644 index 0000000..0e68232 --- /dev/null +++ b/src/tokenaccess.cpp @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2004 Apple Computer, Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + + +// +// tokenaccess - access management to a TokenDatabase's Token's TokenDaemon's tokend +// +#include "tokenaccess.h" + + +// +// Process an exception thrown (presumably) by a TokenDaemon interface call. +// +void Access::operator () (const CssmError &err) +{ + if (++mIteration > 2) { + secdebug("tokendb", "retry failed; aborting operation"); + throw; + } + + //@@@ hack until tokend returns RESET + if (err.error == -1) { + secdebug("tokendb", "TEMP HACK (error -1) action - reset and retry"); + token.resetAcls(); + return; + } + + if (CSSM_ERR_IS_CONVERTIBLE(err.error)) + switch (CSSM_ERRCODE(err.error)) { + case CSSM_ERRCODE_OPERATION_AUTH_DENIED: + case CSSM_ERRCODE_OBJECT_USE_AUTH_DENIED: + // @@@ do something more focused here, but for now... + secdebug("tokendb", "tokend denies auth; we're punting for now"); + throw; + case CSSM_ERRCODE_DEVICE_RESET: + secdebug("tokendb", "tokend signals reset; clearing and retrying"); + token.resetAcls(); + return; // induce retry + } + // all others are non-recoverable + throw; +} diff --git a/src/tokenaccess.h b/src/tokenaccess.h new file mode 100644 index 0000000..2ad4211 --- /dev/null +++ b/src/tokenaccess.h @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2004 Apple Computer, Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + + +// +// tokenaccess - access management to a TokenDatabase's Token's TokenDaemon's tokend +// +#ifndef _H_TOKENACCESS +#define _H_TOKENACCESS + +#include "tokendatabase.h" +#include "tokenkey.h" +#include "server.h" + + +// +// Turn a Key into a TokenKey, when we know that it's that +// +inline TokenKey &myKey(Key &key) +{ + return safer_cast(key); +} + + +// +// The common access/retry/management framework for calls that go to the actual daemon. +// +class Access : public Token::Access { +public: + Access(Token &token) : Token::Access(token), mIteration(0) + { Server::active().longTermActivity(); } + template + Access(Token &token, Whatever &it) : Token::Access(token) + { add(it); Server::active().longTermActivity(); } + + void operator () (const CssmError &err); + using Token::Access::operator (); + + void add(TokenAcl &acl) { mAcls.insert(&acl); } + void add(TokenAcl *acl) { if (acl) mAcls.insert(acl); } + void add(AclSource &src) { add(dynamic_cast(src.acl())); } + void add(AclSource *src) { if (src) add(*src); } + void add(Key &key) { mAcls.insert(&myKey(key)); } + +private: + set mAcls; // TokenAcl subclasses to clear on retry + unsigned int mIteration; // iteration count (try, retry, give up) +}; + + +// +// A nice little macro bracket to apply it. +// You must declare an Access called 'access' before doing +// TRY +// some actions +// GUARD(a call to tokend) +// DONE +// +#define TRY for (;;) { +#define GUARD try { +#define DONE return; \ + } catch (const CssmError &error) { \ + access(error); \ + } } + + +#endif //_H_TOKENACCESS diff --git a/src/tokenacl.cpp b/src/tokenacl.cpp new file mode 100644 index 0000000..efaf36a --- /dev/null +++ b/src/tokenacl.cpp @@ -0,0 +1,192 @@ +/* + * Copyright (c) 2004 Apple Computer, Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + + +// +// tokenacl - Token-based ACL implementation +// +#include "tokenacl.h" +#include "tokend.h" +#include "token.h" +#include "tokendatabase.h" +#include "agentquery.h" +#include +#include + + +// +// A TokenAcl initializes to "invalid, needs update". +// Note how our Token will start its ResetGeneration at 1, while we start at zero. +// +TokenAcl::TokenAcl() + : mLastReset(0) +{ +} + + +// +// Instantiate is called (by the ACL machinery core) before this ACL object's +// contents are used in any way. Here is where we fetch the ACL data from tokend +// (if we haven't got it yet). +// +void TokenAcl::instantiateAcl() +{ + if (token().resetGeneration(mLastReset)) + return; + + secdebug("tokenacl", "%p loading ACLs from tokend", this); + + // read owner + AclOwnerPrototype *owner = NULL; + token().tokend().getOwner(aclKind(), tokenHandle(), owner); + assert(owner); + + // read entries + uint32 count; + AclEntryInfo *infos; + token().tokend().getAcl(aclKind(), tokenHandle(), NULL, count, infos); + + // commit to setting the ACL data + ObjectAcl::owner(*owner); + ObjectAcl::entries(count, infos); + + // and if we actually made it to here... + mLastReset = token().resetGeneration(); +} + + +// +// The ACL machinery core calls this after successfully making changes to our ACL. +// +void TokenAcl::changedAcl() +{ +} + + +// +// CSSM-layer read gates. This accesses a cached version prepared in our instantiateAcl(). +// +void TokenAcl::getOwner(AclOwnerPrototype &owner) +{ + ObjectAcl::cssmGetOwner(owner); +} + +void TokenAcl::getAcl(const char *tag, uint32 &count, AclEntryInfo *&acls) +{ + ObjectAcl::cssmGetAcl(tag, count, acls); +} + + +// +// CSSM-layer write gates. +// This doesn't directly write to the local ObjectAcl at all. The call is relayed to +// tokend, and the resulting ACL is being re-read when next needed. +// +void TokenAcl::changeAcl(const AclEdit &edit, const AccessCredentials *cred, Database *db) +{ + // changeAcl from/to a PIN (source) ACL has special UI handling here + // @@@ this is an ad-hoc hack; general solution awaits the ACL machinery rebuild later + instantiateAcl(); // (redundant except in error cases) + if (TokenDatabase *tokenDb = dynamic_cast(db)) + if (edit.mode() == CSSM_ACL_EDIT_MODE_REPLACE) + if (const AclEntryInput *input = edit.newEntry()) { + unsigned int pin; + if (sscanf(input->proto().s_tag().c_str(), "PIN%d", &pin) == 1) { + // assume this is a PIN change request + pinChange(pin, edit.handle(), *tokenDb); + invalidateAcl(); + return; + } + } + + // hand the request off to tokend to do as it will + token().tokend().changeAcl(aclKind(), tokenHandle(), Required(cred), edit); + invalidateAcl(); +} + +void TokenAcl::changeOwner(const AclOwnerPrototype &newOwner, + const AccessCredentials *cred, Database *db) +{ + token().tokend().changeOwner(aclKind(), tokenHandle(), Required(cred), newOwner); + invalidateAcl(); +} + + +// +// Ad-hoc PIN change processing. +// This cooks a suitable changeAcl call to tokend, ad hoc. +// It does NOT complete the originating request; it replaces it completely. +// (Completion processing requires not-yet-implemented ACL machine UI coalescing features.) +// +class QueryNewPin : public QueryNewPassphrase { +public: + QueryNewPin(unsigned int pinn, CSSM_ACL_HANDLE h, TokenDatabase &db, Reason reason) + : QueryNewPassphrase(db, reason), pin(pinn), handle(h) { } + + const unsigned int pin; + const CSSM_ACL_HANDLE handle; + + Reason accept(CssmManagedData &passphrase, CssmData *oldPassphrase); +}; + +SecurityAgent::Reason QueryNewPin::accept(CssmManagedData &passphrase, CssmData *oldPassphrase) +{ + assert(oldPassphrase); // we don't handle the new-pin case (yet) + + // form a changeAcl query and send it to tokend + try { + TrackingAllocator alloc(Allocator::standard()); + AclEntryPrototype proto(TypedList(alloc, CSSM_ACL_SUBJECT_TYPE_PROMPTED_PASSWORD, + new(alloc) ListElement(passphrase) + )); + proto.authorization() = AuthorizationGroup(CSSM_ACL_AUTHORIZATION_PREAUTH(pin), alloc); + char pintag[10]; sprintf(pintag, "PIN%d", pin); + proto.tag(pintag); + AclEntryInput input(proto); + AclEdit edit(CSSM_ACL_EDIT_MODE_REPLACE, handle, &input); + AutoCredentials cred(alloc); + cred += TypedList(alloc, CSSM_SAMPLE_TYPE_PROMPTED_PASSWORD, + new(alloc) ListElement(*oldPassphrase)); + safer_cast(database).token().tokend().changeAcl(dbAcl, noDb, cred, edit); + return SecurityAgent::noReason; + } catch (const CssmError &err) { + switch (err.error) { + default: + return SecurityAgent::unknownReason; + } + } catch (...) { + return SecurityAgent::unknownReason; + } +} + +void TokenAcl::pinChange(unsigned int pin, CSSM_ACL_HANDLE handle, TokenDatabase &database) +{ + QueryNewPin query(pin, handle, database, SecurityAgent::changePassphrase); + CssmAutoData newPin(Allocator::standard(Allocator::sensitive)); + switch (query(newPin)) { + case SecurityAgent::noReason: // worked + return; + default: + CssmError::throwMe(CSSM_ERRCODE_INTERNAL_ERROR); + } +} diff --git a/src/tokenacl.h b/src/tokenacl.h new file mode 100644 index 0000000..5268c95 --- /dev/null +++ b/src/tokenacl.h @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2004 Apple Computer, Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +#ifndef _H_TOKENACL +#define _H_TOKENACL + + +// +// tokenacl - Token-based ACL implementation +// +#include "acls.h" +#include + +class Token; +class TokenDatabase; + + +// +// The Token version of a SecurityServerAcl. +// +class TokenAcl : public virtual SecurityServerAcl { +public: + TokenAcl(); + + typedef unsigned int ResetGeneration; + +public: + // implement SecurityServerAcl + void getOwner(AclOwnerPrototype &owner); + void getAcl(const char *tag, uint32 &count, AclEntryInfo *&acls); + void changeAcl(const AclEdit &edit, const AccessCredentials *cred, + Database *relatedDatabase); + void changeOwner(const AclOwnerPrototype &newOwner, const AccessCredentials *cred, + Database *relatedDatabase); + + void instantiateAcl(); + void changedAcl(); + +public: + // required from our MDC + virtual Token &token() = 0; + virtual GenericHandle tokenHandle() const = 0; + +protected: + void invalidateAcl() { mLastReset = 0; } + void pinChange(unsigned int pin, CSSM_ACL_HANDLE handle, TokenDatabase &database); + +private: + ResetGeneration mLastReset; +}; + + +#endif //_H_TOKENACL diff --git a/src/tokencache.cpp b/src/tokencache.cpp new file mode 100644 index 0000000..c843340 --- /dev/null +++ b/src/tokencache.cpp @@ -0,0 +1,267 @@ +/* + * Copyright (c) 2004 Apple Computer, Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + + +// +// tokencache - persistent (on-disk) hardware token directory +// +// Here's the basic disk layout, rooted at /var/db/TokenCache (or $TOKENCACHE): +// TBA +// +#include "tokencache.h" +#include +#include +#include + +using namespace UnixPlusPlus; + + +// +// Here are the uid/gid values we assign to token daemons and their cache files +// +#define TOKEND_UID "tokend" +#define TOKEND_GID "tokend" +#define TOKEND_UID_FALLBACK uid_t(-2) +#define TOKEND_GID_FALLBACK gid_t(-2) + + +// +// Fixed relative file paths +// + +// relative to cache root (use cache->path()) +static const char configDir[] = "config"; +static const char lastSSIDFile[] = "config/lastSSID"; +static const char tokensDir[] = "tokens"; + +// relative to token directory (use token->path()) +static const char ssidFile[] = "SSID"; +static const char workDir[] = "work"; +static const char cacheDir[] = "cache"; + + +// +// Internal file I/O helpers. These read/write entire files. +// Note that the defaulted read functions do NOT write the default +// to disk; they work fine in read-only disk areas. +// +static uint32 getFile(const string &path, uint32 defaultValue) +{ + try { + FileDesc fd(path); + string s; fd.readAll(s); + uint32 value; sscanf(s.c_str(), "%ld", &value); + return value; + } catch (...) { + return defaultValue; + } +} + +static string getFile(const string &path, const string &defaultValue) +{ + try { + FileDesc fd(path); + string s; fd.readAll(s); + return s; + } catch (...) { + return defaultValue; + } +} + + +static void putFile(const string &path, uint32 value) +{ + char buffer[64]; + snprintf(buffer, sizeof(buffer), "%ld\n", value); + FileDesc(path, O_WRONLY | O_CREAT | O_TRUNC).writeAll(buffer); +} + +static void putFile(const string &path, const string &value) +{ + FileDesc(path, O_WRONLY | O_CREAT | O_TRUNC).writeAll(value); +} + + +// +// The "rooted tree" utility class +// +void Rooted::root(const string &r) +{ + assert(mRoot.empty()); // can't re-set this + mRoot = r; +} + +string Rooted::path(const char *sub) const +{ + if (sub == NULL) + return mRoot; + return mRoot + "/" + sub; +} + + +// +// Open a TokenCache. +// If the cache does not exist at the path given, initialize it. +// If that fails, throw an exception. +// +TokenCache::TokenCache(const char *where) + : Rooted(where), mLastSubservice(0) +{ + makedir(root(), O_CREAT, 0711, securityd); + makedir(path(configDir), O_CREAT, 0700, securityd); + makedir(path(tokensDir), O_CREAT, 0711, securityd); + + // get the path for the SSID file. Don't call getFile unless the file exists (avoids exception overhead) + string idFilePath = path (lastSSIDFile); + struct stat st; + if (stat (idFilePath.c_str (), &st) == -1) { + mLastSubservice = 1; + } else { + mLastSubservice = getFile(idFilePath, 1); + } + + // identify uid/gid for token daemons + struct passwd *pw = getpwnam(TOKEND_UID); + mTokendUid = pw ? pw->pw_uid : TOKEND_UID_FALLBACK; + struct group *gr = getgrnam(TOKEND_GID); + mTokendGid = gr ? gr->gr_gid : TOKEND_GID_FALLBACK; + + secdebug("tokencache", "token cache rooted at %s (last ssid=%ld, uid/gid=%d/%d)", + root().c_str(), mLastSubservice, mTokendUid, mTokendGid); +} + +TokenCache::~TokenCache() +{ +} + + +// +// Get a new, unused subservice id number. +// Update the tracking file so we won't hand it out again (ever) within this cache. +// +uint32 TokenCache::allocateSubservice() +{ + putFile(path(lastSSIDFile), ++mLastSubservice); + return mLastSubservice; +} + + +// +// A slightly souped-up UnixPlusPlus::makedir +// +void TokenCache::makedir(const char *path, int flags, mode_t mode, Owner owner) +{ + UnixPlusPlus::makedir(path, flags, mode); + switch(owner) { + case securityd: + // leave it alone; we own it alrady + break; + case tokend: + ::chown(path, tokendUid(), tokendGid()); + break; + } +} + + +// +// Make a cache entry from a valid tokenUid. +// This will locate an existing entry or make a new one. +// +TokenCache::Token::Token(TokenCache &c, const string &tokenUid) + : Rooted(c.path(string(tokensDir) + "/" + tokenUid)), cache(c) +{ + cache.makedir(root(), O_CREAT, 0711, securityd); + if (mSubservice = getFile(path(ssidFile), 0)) { + secdebug("tokencache", "found token \"%s\" ssid=%ld", tokenUid.c_str(), mSubservice); + init(existing); + } else { + mSubservice = cache.allocateSubservice(); // allocate new, unique ssid... + putFile(path(ssidFile), mSubservice); // ... and save it in cache + secdebug("tokencache", "new token \"%s\" ssid=%ld", tokenUid.c_str(), mSubservice); + init(created); + } +} + + +// +// Make a cache entry that is temporary and will never be reused. +// +TokenCache::Token::Token(TokenCache &c) + : cache(c) +{ + mSubservice = cache.allocateSubservice(); // new, unique id + char rootForm[30]; snprintf(rootForm, sizeof(rootForm), + "%s/temporary:%ld", tokensDir, mSubservice); + root(cache.path(rootForm)); + cache.makedir(root(), O_CREAT | O_EXCL, 0711, securityd); + putFile(path(ssidFile), mSubservice); // ... and save it in cache + secdebug("tokencache", "temporary token \"%s\" ssid=%ld", rootForm, mSubservice); + init(temporary); +} + + +// +// Common constructor setup code +// +void TokenCache::Token::init(Type type) +{ + mType = type; + cache.makedir(workPath(), O_CREAT, 0700, tokend); + cache.makedir(cachePath(), O_CREAT, 0700, tokend); +} + + +// +// The Token destructor might clean or preen a bit, but shouldn't take +// too long (or too much effort). +// +TokenCache::Token::~Token() +{ + if (type() == temporary) + secdebug("tokencache", "@@@ should delete the cache directory here..."); +} + + +// +// Attributes of TokenCache::Tokens +// +string TokenCache::Token::workPath() const +{ + return path("Work"); +} + +string TokenCache::Token::cachePath() const +{ + return path("Cache"); +} + + +string TokenCache::Token::printName() const +{ + return getFile(path("PrintName"), ""); +} + +void TokenCache::Token::printName(const string &name) +{ + putFile(path("PrintName"), name); +} diff --git a/src/tokencache.h b/src/tokencache.h new file mode 100644 index 0000000..a6336d4 --- /dev/null +++ b/src/tokencache.h @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2004 Apple Computer, Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + + +// +// tokencache - persistent (on-disk) hardware token directory +// +#ifndef _H_TOKENCACHE +#define _H_TOKENCACHE + +#include +#include + + +// +// A little helper +// +class Rooted { +public: + Rooted() { } + Rooted(const char *root) : mRoot(root) { } + Rooted(const string &root) : mRoot(root) { } + + string root() const { return mRoot; } + string path(const char *sub) const; + string path(const string &sub) const { return path(sub.c_str()); } + +protected: + void root(const string &s); + +private: + string mRoot; // root of this tree +}; + + +// +// An on-disk cache area. +// You'll only want a single one, though nothing keeps you from +// making multiples if you like. +// +class TokenCache : public Rooted { +public: + TokenCache(const char *root); + ~TokenCache(); + + uid_t tokendUid() const { return mTokendUid; } + gid_t tokendGid() const { return mTokendGid; } + +public: + class Token : public RefCount, public Rooted { + public: + friend class TokenCache; + Token(TokenCache &cache, const std::string &uid); + Token(TokenCache &cache); + ~Token(); + + enum Type { existing, created, temporary }; + Type type() const { return mType; } + + TokenCache &cache; + uint32 subservice() const { return mSubservice; } + string workPath() const; + string cachePath() const; + + string printName() const; + void printName(const string &name); + + uid_t tokendUid() const { return cache.tokendUid(); } + gid_t tokendGid() const { return cache.tokendGid(); } + + protected: + void init(Type type); + + private: + uint32 mSubservice; // subservice id assigned + Type mType; // type of Token cache entry + }; + +public: + uint32 allocateSubservice(); + +private: + enum Owner { securityd, tokend }; + void makedir(const char *path, int flags, mode_t mode, Owner owner); + void makedir(const string &path, int flags, mode_t mode, Owner owner) + { return makedir(path.c_str(), flags, mode, owner); } + +private: + uint32 mLastSubservice; // last subservice id issued + + uid_t mTokendUid; // uid of daemons accessing this token cache + gid_t mTokendGid; // gid of daemons accessing this token cache +}; + + +#endif //_H_TOKENCACHE diff --git a/src/tokend.cpp b/src/tokend.cpp new file mode 100644 index 0000000..1707618 --- /dev/null +++ b/src/tokend.cpp @@ -0,0 +1,194 @@ +/* + * Copyright (c) 2004 Apple Computer, Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + + +// +// tokend - internal tracker for a tokend smartcard driver process +// +#include "tokend.h" +#include + + +// +// Construct a TokenDaemon. +// This will (try to) execute the actual tokend at 'path'; it will not communicate +// with it beyond the standard securityd checkin mechanism. +// The constructor will return if the tokend is either checked in and ready, or +// it has died (or been unable to start at all). It's then our owner's responsibility +// to manage us from there, including deleting us eventually. +// +TokenDaemon::TokenDaemon(RefPointer code, + const string &reader, const PCSC::ReaderState &readerState, TokenCache &cache) + : Tokend::ClientSession(Allocator::standard(), Allocator::standard()), + mMe(code), mReaderName(reader), mState(readerState), + mFaultRelay(NULL), mFaulted(false), mProbed(false), + mUid(cache.tokendUid()), mGid(cache.tokendGid()) +{ + this->fork(); + switch (ServerChild::state()) { + case alive: + Tokend::ClientSession::servicePort(ServerChild::servicePort()); + secdebug("tokend", "%p (pid %d) %s has launched", this, pid(), bundlePath().c_str()); + break; + case dead: + // tokend died or quit before becoming ready + secdebug("tokend", "%p (pid %d) %s failed on startup", this, pid(), bundlePath().c_str()); + break; + default: + assert(false); + } +} + + +// +// The destructor for TokenDaemon *may* be called with tokend still alive. +// We rely on ServerChild's destructor to kill it for us. +// If we wanted to do something especally nice just for tokend (such as sending +// a "go die" message), we'd do it here. +// +TokenDaemon::~TokenDaemon() +{ + secdebug("tokend", "%p (pid %d) %s is being destroyed", this, pid(), bundlePath().c_str()); +} + + +// +// Calculate a tokenUid as a concatenation of tokend identifier and uid +// +std::string TokenDaemon::tokenUid() const +{ + assert(hasTokenUid()); + return mTokenUid; +} + + +// +// Access to custom Info.plist fields +// +uint32 TokenDaemon::maxScore() const +{ + return cfNumber(CFNumberRef(mMe->infoPlistItem("TokendBestScore")), INT_MAX); +} + + +// +// Our childAction is to launch tokend after preparing its environment +// +void TokenDaemon::childAction() +{ + + // permanently relinquish high privilege +#if defined(NDEBUG) + UnixError::check(::setgid(mGid)); + UnixError::check(::setuid(mUid)); +#else //NDEBUG + // best effort, okay if not + ::setgid(mGid); + ::setuid(mUid); +#endif //NDEBUG + secdebug("tokend", "uid=%d gid=%d", getuid(), getgid()); + + // go run the tokend + char protocol[20]; snprintf(protocol, sizeof(protocol), "%d", TDPROTOVERSION); + secdebug("tokend", "executing %s(\"%s\",%s)", + mMe->executablePath().c_str(), mReaderName.c_str(), protocol); + execl(mMe->executablePath().c_str(), + mMe->executablePath().c_str(), + protocol, // #1: protocol version + mReaderName.c_str(), // #2: reader name + CssmData::wrap(mState).toHex().c_str(), // #3: PCSC reader state (hex) + NULL); +} + + +// +// This will be called (by the UnixChild layer) when UNIX tells us that our tokend +// has died. That means it's quite dead (a Zombie) already. +// +void TokenDaemon::dying() +{ + ServerChild::dying(); // honor prior engagement + fault(true, "token daemon has died"); // flag asynchronous fault +} + + +// +// Declare a fault. +//@@@ Semantics TBD. +// +void TokenDaemon::fault(bool async, const char *reason) +{ + if (!mFaulted) { + secdebug("tokend", "%p declaring %s FAULT condition: %s", + this, async ? "ASYNCHRONOUS" : "SYNCHRONOUS", reason); + Syslog::notice("card in reader %s has faulted (%s)", + mReaderName.c_str(), reason); + mFaulted = true; + if (mFaultRelay) + mFaultRelay->relayFault(async); + } + if (!async) + CssmError::throwMe(CSSM_ERRCODE_FUNCTION_FAILED); +} + + +// +// A fault signalled from the ClientSession layer is just a (synchronous) fault +// of TokenDaemon itself. +// +void TokenDaemon::fault() +{ + this->fault(false, "tokend service failed"); +} + + +// +// Overridden Tokend::ClientSession methods (to siphon off some return data). +// Note that this does NOT include the Access magic; you still have to use +// TokenDaemon::Access to mediate the call. +// +bool TokenDaemon::probe() +{ + secdebug("tokend", "%p probing", this); + ClientSession::probe(mScore, mTokenUid); + secdebug("tokend", "%p probed score=%ld tokenUid=\"%s\"", this, mScore, mTokenUid.c_str()); + mProbed = true; + return mScore > 0; +} + + +// +// Debug dump support +// +#if defined(DEBUGDUMP) + +void TokenDaemon::dumpNode() +{ + PerGlobal::dumpNode(); + if (mFaulted) + Debug::dump(" FAULT"); + Debug::dump(" service=%d/%d", + ClientSession::servicePort().port(), ServerChild::servicePort().port()); +} + +#endif //DEBUGDUMP diff --git a/src/tokend.h b/src/tokend.h new file mode 100644 index 0000000..6e407ab --- /dev/null +++ b/src/tokend.h @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2004 Apple Computer, Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + + +// +// tokend - internal tracker for a tokend smartcard driver process +// +#ifndef _H_TOKEND +#define _H_TOKEND + +#include "structure.h" +#include "child.h" +#include "tokencache.h" +#include +#include +#include + + +// +// A Mix-in for classes that can receive (progated) fault nofications +// +class FaultRelay { +public: + virtual void relayFault(bool async) = 0; +}; + + +// +// A TokenDaemon object is the ServerChild object representing the real +// tokend process driving a token. It provides the only (official) communications +// and control point between securityd and that tokend. +// +// TokenDaemon is sufficiently aware to track changes in its tokend, particularly +// any sudden, violent, agonizing death it may have suffered. +// If TokenDaemon communications with its tokend break down for any rason, it declares +// a FAULT condition and cuts off any further attempts at communication. There is no way +// to recover from a FAULT condition. (You can create a new TokenDaemon and try again, +// of course.) Fault is propagated to the owner object through a simple callback scheme. +// +// If TokenDaemon is destroyed while its process is still alive, it will (try to) kill +// it right there and then. That's good enough for hard error recovery, though you may +// try to let it down easier to allow it to save its caches and wind down. Caller's choice. +// +// NB: If you ever want to make TokenDaemon BE a GenericBundle, you must switch NodeCore +// AND OSXCode to virtually derive RefCount. +// +class TokenDaemon : public PerGlobal, public ServerChild, public Tokend::ClientSession { +public: + TokenDaemon(RefPointer code, + const std::string &reader, const PCSC::ReaderState &state, TokenCache &cache); + virtual ~TokenDaemon(); + + bool faulted() const { return mFaulted; } + void fault(bool async, const char *reason); + + void faultRelay(FaultRelay *rcv) { mFaultRelay = rcv; } + + string bundlePath() const { return mMe->canonicalPath(); } + string bundleIdentifier() const { return mMe->identifier(); } + uint32 maxScore() const; + + Score score() const { return mScore; } + bool hasTokenUid() const { return !mTokenUid.empty(); } + std::string tokenUid() const; + + uid_t uid() const { return mUid; } + gid_t gid() const { return mGid; } + + // startup phase calls + using ClientSession::probe; + bool probe(); + + IFDUMP(void dumpNode()); + +protected: + void childAction(); + void dying(); + + void fault(); // relay from Tokend::ClientSession + +private: + RefPointer mMe; // code object for the tokend (it's an Application) + std::string mReaderName; // PCSC name of reader we're working with + PCSC::ReaderState mState; // card state at time of creation (not updated after that) + + // fault processing + FaultRelay *mFaultRelay; // forward initial fault declarations to this object + bool mFaulted; // fault condition + + // returned by tokend scoring system + bool mProbed; // probe() has succeeded; mScore/mTokenUid valid + Score mScore; // token support score as returned by probe() + std::string mTokenUid; // tokenUid as returned by probe(), may be empty + + // credentials of underlying process + uid_t mUid; // uid of tokend process + gid_t mGid; // gid of tokend process +}; + + +#endif //_H_TOKEND diff --git a/src/tokendatabase.cpp b/src/tokendatabase.cpp index 653898b..fcbee16 100644 --- a/src/tokendatabase.cpp +++ b/src/tokendatabase.cpp @@ -3,8 +3,6 @@ * * @APPLE_LICENSE_HEADER_START@ * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. - * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in @@ -28,24 +26,107 @@ // tokendatabase - software database container implementation. // #include "tokendatabase.h" +#include "tokenkey.h" +#include "tokenaccess.h" #include "process.h" -#include "key.h" +#include "server.h" +#include "localkey.h" // to retrieve local raw keys +#include + +// +// Construct a TokenDbCommon +// +TokenDbCommon::TokenDbCommon(Session &ssn, Token &tk, const char *name) + : DbCommon(ssn), mDbName(name ? name : ""), mResetLevel(0) +{ + parent(tk); +} + +Token &TokenDbCommon::token() const +{ + return parent(); +} -class TokenKey : public Key { -public: -}; +string TokenDbCommon::dbName() const +{ + return token().printName().c_str(); +} // -// Construct a TokenDatabase +// A TokenDbCommon holds per-session adornments for the ACL machine // -TokenDatabase::TokenDatabase(Process &proc) +Adornable &TokenDbCommon::store() +{ + StLock _(*this); + + // if this is the first one, hook for lifetime + if (mAdornments.empty()) { + session().addReference(*this); // hold and slave to SSN lifetime + token().addCommon(*this); // register with Token + } + + // return our (now active) adornments + return mAdornments; +} + +void TokenDbCommon::resetAcls() +{ + StLock _(*this); + if (!mAdornments.empty()) { + mAdornments.clearAdornments(); // clear ACL state + session().removeReference(*this); // unhook from SSN + token().removeCommon(*this); // unregister from Token + } +} + + +// +// Process (our part of) a "lock all" request. +// Smartcard tokens interpret a "lock" as a forced card reset, transmitted +// to tokend as an authenticate request. +// @@@ Virtual reset for multi-session tokens. Right now, we're using the sledge hammer. +// +void TokenDbCommon::lockProcessing() +{ + Access access(token()); + access().authenticate(CSSM_DB_ACCESS_RESET, NULL); +} + + +// +// Construct a TokenDatabase given subservice information. +// We are currently ignoring the 'name' argument. +// +TokenDatabase::TokenDatabase(uint32 ssid, Process &proc, + const char *name, const AccessCredentials *cred) : Database(proc) { + // locate Token object + RefPointer token = Token::find(ssid); + + Session &session = process().session(); + StLock _(session); + if (TokenDbCommon *dbcom = session.findFirst(&TokenDbCommon::subservice, ssid)) { + parent(*dbcom); + secdebug("tokendb", "open tokendb %p(%ld) at known common %p", + this, subservice(), dbcom); + } else { + // DbCommon not present; make a new one + parent(*new TokenDbCommon(proc.session(), *token, name)); + secdebug("tokendb", "open tokendb %p(%ld) with new common %p", + this, subservice(), &common()); + } + mOpenCreds = copy(cred, Allocator::standard()); proc.addReference(*this); } +TokenDatabase::~TokenDatabase() +{ + Allocator::standard().free(mOpenCreds); +} + // // Basic Database virtual implementations @@ -55,26 +136,120 @@ TokenDbCommon &TokenDatabase::common() const return parent(); } +TokenDaemon &TokenDatabase::tokend() +{ + return common().token().tokend(); +} + const char *TokenDatabase::dbName() const { - return "<>"; + return common().dbName().c_str(); +} + +bool TokenDatabase::transient() const +{ + //@@@ let tokend decide? Are there any secure transient keystores? + return false; } -static inline TokenKey &myKey(Key &key) +SecurityServerAcl &TokenDatabase::acl() { - return safer_cast(key); + return token(); +} + +bool TokenDatabase::isLocked() const +{ + Access access(token()); + return access().isLocked(); +} + + +// +// TokenDatabases implement the dbName-setting function. +// This sets the print name of the token, which is persistently +// stored in the token cache. So this is a de-facto rename of +// the token, at least on this system. +// +void TokenDatabase::dbName(const char *name) +{ + CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED); +} + + +// +// Given a key handle and CssmKey returned from tokend, create a Key representing +// it. This takes care of raw returns by turning them into keys of the process's +// local transient store. +// +RefPointer TokenDatabase::makeKey(KeyHandle hKey, const CssmKey *key, + const AclEntryPrototype *owner) +{ + switch (key->blobType()) { + case CSSM_KEYBLOB_REFERENCE: + return new TokenKey(*this, hKey, key->header()); + case CSSM_KEYBLOB_RAW: + return process().makeTemporaryKey(*key, 0, owner); + default: + CssmError::throwMe(CSSM_ERRCODE_INTERNAL_ERROR); // bad key return from tokend + } + //@@@ Server::releaseWhenDone(key); +} + + +// +// Adjust key attributes for newly created keys +// +static CSSM_KEYATTR_FLAGS modattrs(CSSM_KEYATTR_FLAGS attrs) +{ + static const CSSM_KEYATTR_FLAGS CSSM_KEYATTR_RETURN_FLAGS = 0xff000000; + switch (attrs & CSSM_KEYATTR_RETURN_FLAGS) { + case CSSM_KEYATTR_RETURN_REF: + case CSSM_KEYATTR_RETURN_DATA: + break; // as requested + case CSSM_KEYATTR_RETURN_NONE: + CssmError::throwMe(CSSMERR_CSP_UNSUPPORTED_KEYATTR_MASK); + case CSSM_KEYATTR_RETURN_DEFAULT: + if (attrs & CSSM_KEYATTR_PERMANENT) + attrs |= CSSM_KEYATTR_RETURN_REF; + else + attrs |= CSSM_KEYATTR_RETURN_DATA; + break; + } + return attrs; } +// +// TokenDatabases support remote secret validation by sending a secret +// (aka passphrase et al) to tokend for processing. +// +bool TokenDatabase::validateSecret(const AclSubject *subject, const AccessCredentials *cred) +{ + secdebug("tokendb", "%p attempting remote validation", this); + try { + Access access(token()); + // @@@ Use cached mode + access().authenticate(CSSM_DB_ACCESS_READ, cred); + secdebug("tokendb", "%p remote validation successful", this); + return true; + } catch (...) { + secdebug("tokendb", "%p remote validation failed", this); + return false; + } +} // // Key inquiries // -CSSM_KEY_SIZE TokenDatabase::queryKeySize(Key &key) +void TokenDatabase::queryKeySizeInBits(Key &key, CssmKeySize &result) { - CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED); + Access access(token()); + TRY + GUARD + access().queryKeySizeInBits(myKey(key).tokenHandle(), result); + DONE } @@ -84,28 +259,45 @@ CSSM_KEY_SIZE TokenDatabase::queryKeySize(Key &key) void TokenDatabase::generateSignature(const Context &context, Key &key, CSSM_ALGORITHMS signOnlyAlgorithm, const CssmData &data, CssmData &signature) { + Access access(token(), key); + TRY key.validate(CSSM_ACL_AUTHORIZATION_SIGN, context); - CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED); + GUARD + access().generateSignature(context, myKey(key).tokenHandle(), data, signature, signOnlyAlgorithm); + DONE } + void TokenDatabase::verifySignature(const Context &context, Key &key, CSSM_ALGORITHMS verifyOnlyAlgorithm, const CssmData &data, const CssmData &signature) { - CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED); + Access access(token(), key); + TRY + GUARD + access().verifySignature(context, myKey(key).tokenHandle(), data, signature, verifyOnlyAlgorithm); + DONE } void TokenDatabase::generateMac(const Context &context, Key &key, const CssmData &data, CssmData &mac) { + Access access(token()); + TRY key.validate(CSSM_ACL_AUTHORIZATION_MAC, context); - CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED); + GUARD + access().generateMac(context, myKey(key).tokenHandle(), data, mac); + DONE } void TokenDatabase::verifyMac(const Context &context, Key &key, const CssmData &data, const CssmData &mac) { + Access access(token()); + TRY key.validate(CSSM_ACL_AUTHORIZATION_MAC, context); - CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED); + GUARD + access().verifyMac(context, myKey(key).tokenHandle(), data, mac); + DONE } @@ -115,15 +307,24 @@ void TokenDatabase::verifyMac(const Context &context, Key &key, void TokenDatabase::encrypt(const Context &context, Key &key, const CssmData &clear, CssmData &cipher) { + Access access(token()); + TRY key.validate(CSSM_ACL_AUTHORIZATION_ENCRYPT, context); - CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED); + GUARD + access().encrypt(context, myKey(key).tokenHandle(), clear, cipher); + DONE } + void TokenDatabase::decrypt(const Context &context, Key &key, const CssmData &cipher, CssmData &clear) { + Access access(token()); + TRY key.validate(CSSM_ACL_AUTHORIZATION_DECRYPT, context); - CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED); + GUARD + access().decrypt(context, myKey(key).tokenHandle(), cipher, clear); + DONE } @@ -134,24 +335,35 @@ void TokenDatabase::decrypt(const Context &context, Key &key, // void TokenDatabase::generateKey(const Context &context, const AccessCredentials *cred, const AclEntryPrototype *owner, - uint32 usage, uint32 attrs, RefPointer &newKey) + CSSM_KEYUSE usage, CSSM_KEYATTR_FLAGS attrs, RefPointer &newKey) { - CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED); + Access access(token()); + TRY + GUARD + KeyHandle hKey; + CssmKey *result; + access().generateKey(context, cred, owner, usage, modattrs(attrs), hKey, result); + newKey = makeKey(hKey, result, owner); + DONE } void TokenDatabase::generateKey(const Context &context, const AccessCredentials *cred, const AclEntryPrototype *owner, - uint32 pubUsage, uint32 pubAttrs, uint32 privUsage, uint32 privAttrs, + CSSM_KEYUSE pubUsage, CSSM_KEYATTR_FLAGS pubAttrs, + CSSM_KEYUSE privUsage, CSSM_KEYATTR_FLAGS privAttrs, RefPointer &publicKey, RefPointer &privateKey) { - CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED); -} - -RefPointer TokenDatabase::deriveKey(const Context &context, Key *baseKey, - const AccessCredentials *cred, const AclEntryPrototype *owner, - CssmData *param, uint32 usage, uint32 attrs) -{ - CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED); + Access access(token()); + TRY + GUARD + KeyHandle hPrivate, hPublic; + CssmKey *privKey, *pubKey; + access().generateKey(context, cred, owner, + pubUsage, modattrs(pubAttrs), privUsage, modattrs(privAttrs), + hPublic, pubKey, hPrivate, privKey); + publicKey = makeKey(hPublic, pubKey, owner); + privateKey = makeKey(hPrivate, privKey, owner); + DONE } @@ -160,36 +372,350 @@ RefPointer TokenDatabase::deriveKey(const Context &context, Key *baseKey, // Note that the key argument (the key in the context) is optional because of the special // case of "cleartext" (null algorithm) wrapping for import/export. // +void TokenDatabase::wrapKey(const Context &context, const AccessCredentials *cred, + Key *wrappingKey, Key &subjectKey, + const CssmData &descriptiveData, CssmKey &wrappedKey) +{ + Access access(token()); + InputKey cWrappingKey(wrappingKey); + InputKey cSubjectKey(subjectKey); + TRY + subjectKey.validate(context.algorithm() == CSSM_ALGID_NONE ? + CSSM_ACL_AUTHORIZATION_EXPORT_CLEAR : CSSM_ACL_AUTHORIZATION_EXPORT_WRAPPED, + cred); + if (wrappingKey) + wrappingKey->validate(CSSM_ACL_AUTHORIZATION_ENCRYPT, context); + GUARD + CssmKey *rWrappedKey; + access().wrapKey(context, cred, + cWrappingKey, cWrappingKey, cSubjectKey, cSubjectKey, + descriptiveData, rWrappedKey); + wrappedKey = *rWrappedKey; + //@@@ ownership of wrappedKey.keyData() ?? + DONE +} -void TokenDatabase::wrapKey(const Context &context, Key *key, - Key &keyToBeWrapped, const AccessCredentials *cred, - const CssmData &descriptiveData, CssmKey &wrappedKey) +void TokenDatabase::unwrapKey(const Context &context, + const AccessCredentials *cred, const AclEntryPrototype *owner, + Key *wrappingKey, Key *publicKey, CSSM_KEYUSE usage, CSSM_KEYATTR_FLAGS attrs, + const CssmKey wrappedKey, RefPointer &unwrappedKey, CssmData &descriptiveData) { - CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED); + Access access(token()); + InputKey cWrappingKey(wrappingKey); + InputKey cPublicKey(publicKey); + TRY + if (wrappingKey) + wrappingKey->validate(CSSM_ACL_AUTHORIZATION_DECRYPT, context); + // we are not checking access on the public key, if any + GUARD + KeyHandle hKey; + CssmKey *result; + access().unwrapKey(context, cred, owner, + cWrappingKey, cWrappingKey, cPublicKey, cPublicKey, + wrappedKey, usage, modattrs(attrs), descriptiveData, hKey, result); + unwrappedKey = makeKey(hKey, result, owner); + DONE } -RefPointer TokenDatabase::unwrapKey(const Context &context, Key *key, + +// +// Key derivation +// +void TokenDatabase::deriveKey(const Context &context, Key *sourceKey, const AccessCredentials *cred, const AclEntryPrototype *owner, - uint32 usage, uint32 attrs, const CssmKey wrappedKey, - Key *publicKey, CssmData *descriptiveData) + CssmData *param, CSSM_KEYUSE usage, CSSM_KEYATTR_FLAGS attrs, RefPointer &derivedKey) { - CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED); + Access access(token()); + InputKey cSourceKey(sourceKey); + TRY + if (sourceKey) + sourceKey->validate(CSSM_ACL_AUTHORIZATION_DERIVE, cred); + GUARD + KeyHandle hKey; + CssmKey *result; + CssmData params = param ? *param : CssmData(); + access().deriveKey(noDb, context, + cSourceKey, cSourceKey, + usage, modattrs(attrs), params, cred, owner, + hKey, result); + if (param) { + *param = params; + //@@@ leak? what's the rule here? + } + derivedKey = makeKey(hKey, result, owner); + DONE } // // Miscellaneous CSSM functions // -uint32 TokenDatabase::getOutputSize(const Context &context, Key &key, uint32 inputSize, bool encrypt) +void TokenDatabase::getOutputSize(const Context &context, Key &key, + uint32 inputSize, bool encrypt, uint32 &result) { - CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED); + Access access(token()); + TRY + GUARD + access().getOutputSize(context, myKey(key).tokenHandle(), inputSize, encrypt, result); + DONE } // -// (Re-)Authenticate the database. This changes the stored credentials. +// (Re-)Authenticate the database. +// We use dbAuthenticate as the catch-all "do something about authentication" call. // -void TokenDatabase::authenticate(const AccessCredentials *cred) +void TokenDatabase::authenticate(CSSM_DB_ACCESS_TYPE mode, const AccessCredentials *cred) { - CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED); + if (mode != CSSM_DB_ACCESS_RESET && cred) { + int pin; + if (sscanf(cred->EntryTag, "PIN%d", &pin) == 1) + return validate(CSSM_ACL_AUTHORIZATION_PREAUTH(pin), cred); + } + + Access access(token()); + access().authenticate(mode, cred); + switch (mode) { + case CSSM_DB_ACCESS_RESET: + // this mode is known to trigger "lockdown" (i.e. reset) + common().resetAcls(); + break; + default: + { + // no idea what that did to the token; + // But let's remember the new creds for our own sake. + AccessCredentials *newCred = copy(cred, Allocator::standard()); + Allocator::standard().free(mOpenCreds); + mOpenCreds = newCred; + break; + } + } +} + + +// +// Data access interface. +// +// Note that the attribute vectors are passed between our two IPC interfaces +// as relocated but contiguous memory blocks (to avoid an extra copy). This means +// you can read them at will, but can't change them in transit unless you're +// willing to repack them right here. +// +void TokenDatabase::findFirst(const CssmQuery &query, + CssmDbRecordAttributeData *inAttributes, mach_msg_type_number_t inAttributesLength, + CssmData *data, RefPointer &key, + RefPointer &rSearch, RefPointer &rRecord, + CssmDbRecordAttributeData * &outAttributes, mach_msg_type_number_t &outAttributesLength) +{ + Access access(token()); + RefPointer search = new Search(*this); + RefPointer record = new Record(*this); + TRY + KeyHandle hKey = noKey; + validate(CSSM_ACL_AUTHORIZATION_DB_READ, openCreds()); + GUARD + record->tokenHandle() = access().Tokend::ClientSession::findFirst(query, + inAttributes, inAttributesLength, search->tokenHandle(), NULL, hKey, + outAttributes, outAttributesLength); + if (!record->tokenHandle()) { // no match (but no other error) + rRecord = NULL; // return null record + return; + } + if (data) { + if (!hKey) + record->validate(CSSM_ACL_AUTHORIZATION_DB_READ, openCreds()); + CssmDbRecordAttributeData *noAttributes; + mach_msg_type_number_t noAttributesLength; + access().Tokend::ClientSession::findRecordHandle(record->tokenHandle(), + NULL, 0, data, hKey, noAttributes, noAttributesLength); + if (hKey) { // tokend returned a key reference & data + CssmKey &keyForm = *data->interpretedAs(CSSMERR_CSP_INVALID_KEY); + key = new TokenKey(*this, hKey, keyForm.header()); + } + } + rSearch = search->commit(); + rRecord = record->commit(); + DONE +} + +void TokenDatabase::findNext(Database::Search *rSearch, + CssmDbRecordAttributeData *inAttributes, mach_msg_type_number_t inAttributesLength, + CssmData *data, RefPointer &key, RefPointer &rRecord, + CssmDbRecordAttributeData * &outAttributes, mach_msg_type_number_t &outAttributesLength) +{ + Access access(token()); + RefPointer record = new Record(*this); + Search *search = safe_cast(rSearch); + TRY + KeyHandle hKey = noKey; + validate(CSSM_ACL_AUTHORIZATION_DB_READ, openCreds()); + GUARD + record->tokenHandle() = access().Tokend::ClientSession::findNext( + search->tokenHandle(), inAttributes, inAttributesLength, + NULL, hKey, outAttributes, outAttributesLength); + if (!record->tokenHandle()) { // no more matches + releaseSearch(*search); // release search handle (consumed by EOD) + rRecord = NULL; // return null record + return; + } + if (data) { + if (!hKey) + record->validate(CSSM_ACL_AUTHORIZATION_DB_READ, openCreds()); + CssmDbRecordAttributeData *noAttributes; + mach_msg_type_number_t noAttributesLength; + access().Tokend::ClientSession::findRecordHandle(record->tokenHandle(), + NULL, 0, data, hKey, noAttributes, noAttributesLength); + if (hKey) { // tokend returned a key reference & data + CssmKey &keyForm = *data->interpretedAs(CSSMERR_CSP_INVALID_KEY); + key = new TokenKey(*this, hKey, keyForm.header()); + } + } + rRecord = record->commit(); + DONE +} + +void TokenDatabase::findRecordHandle(Database::Record *rRecord, + CssmDbRecordAttributeData *inAttributes, mach_msg_type_number_t inAttributesLength, + CssmData *data, RefPointer &key, + CssmDbRecordAttributeData * &outAttributes, mach_msg_type_number_t &outAttributesLength) +{ + Access access(token()); + Record *record = safe_cast(rRecord); + access.add(*record); + TRY + KeyHandle hKey = noKey; + validate(CSSM_ACL_AUTHORIZATION_DB_READ, openCreds()); + if (data) + record->validate(CSSM_ACL_AUTHORIZATION_DB_READ, openCreds()); + GUARD + access().Tokend::ClientSession::findRecordHandle(record->tokenHandle(), + inAttributes, inAttributesLength, data, hKey, outAttributes, outAttributesLength); + rRecord = record; + if (hKey != noKey && data) { // tokend returned a key reference & data + CssmKey &keyForm = *data->interpretedAs(CSSMERR_CSP_INVALID_KEY); + key = new TokenKey(*this, hKey, keyForm.header()); + } + DONE +} + +void TokenDatabase::insertRecord(CSSM_DB_RECORDTYPE recordType, + const CssmDbRecordAttributeData *attributes, mach_msg_type_number_t attributesLength, + const CssmData &data, RefPointer &rRecord) +{ + Access access(token()); + RefPointer record = new Record(*this); + access.add(*record); + TRY + validate(CSSM_ACL_AUTHORIZATION_DB_INSERT, openCreds()); + GUARD + access().Tokend::ClientSession::insertRecord(recordType, + attributes, attributesLength, data, record->tokenHandle()); + rRecord = record; + DONE +} + +void TokenDatabase::modifyRecord(CSSM_DB_RECORDTYPE recordType, Record *rRecord, + const CssmDbRecordAttributeData *attributes, mach_msg_type_number_t attributesLength, + const CssmData *data, CSSM_DB_MODIFY_MODE modifyMode) +{ + Access access(token()); + Record *record = safe_cast(rRecord); + access.add(*record); + TRY + validate(CSSM_ACL_AUTHORIZATION_DB_MODIFY, openCreds()); + record->validate(CSSM_ACL_AUTHORIZATION_DB_MODIFY, openCreds()); + GUARD + access().Tokend::ClientSession::modifyRecord(recordType, + record->tokenHandle(), attributes, attributesLength, data, modifyMode); + DONE +} + +void TokenDatabase::deleteRecord(Database::Record *rRecord) +{ + Access access(token(), *this); + Record *record = safe_cast(rRecord); + access.add(*record); + TRY + validate(CSSM_ACL_AUTHORIZATION_DB_DELETE, openCreds()); + record->validate(CSSM_ACL_AUTHORIZATION_DB_DELETE, openCreds()); + GUARD + access().Tokend::ClientSession::deleteRecord(record->tokenHandle()); + DONE +} + + +// +// Record/Search object handling +// +TokenDatabase::Search::~Search() +{ + if (mHandle) + try { + database().token().tokend().Tokend::ClientSession::releaseSearch(mHandle); + } catch (...) { + secdebug("tokendb", "%p release search handle %ld threw (ignored)", + this, mHandle); + } +} + +TokenDatabase::Record::~Record() +{ + if (mHandle) + try { + database().token().tokend().Tokend::ClientSession::releaseRecord(mHandle); + } catch (...) { + secdebug("tokendb", "%p release record handle %ld threw (ignored)", + this, mHandle); + } +} + + +// +// TokenAcl personality of Record +// +AclKind TokenDatabase::Record::aclKind() const +{ + return objectAcl; +} + +Token &TokenDatabase::Record::token() +{ + return safer_cast(database()).token(); +} + +GenericHandle TokenDatabase::Record::tokenHandle() const +{ + return Handler::tokenHandle(); +} + + +// +// Local utility classes +// +void TokenDatabase::InputKey::setup(Key *key) +{ + if (TokenKey *myKey = dynamic_cast(key)) { + // one of ours + mKeyHandle = myKey->tokenHandle(); + mKeyPtr = NULL; + } else if (LocalKey *hisKey = dynamic_cast(key)) { + // a local key - turn into raw form + CssmClient::WrapKey wrap(Server::csp(), CSSM_ALGID_NONE); + wrap(hisKey->cssmKey(), mKey); + mKeyHandle = noKey; + mKeyPtr = &mKey; + } else { + // no key at all + mKeyHandle = noKey; + mKeyPtr = NULL; + } +} + + +TokenDatabase::InputKey::~InputKey() +{ + if (mKeyPtr) { + //@@@ Server::csp().freeKey(mKey) ?? + Server::csp()->allocator().free(mKey.keyData()); + } } diff --git a/src/tokendatabase.h b/src/tokendatabase.h index 6f8ccba..fa177a9 100644 --- a/src/tokendatabase.h +++ b/src/tokendatabase.h @@ -3,8 +3,6 @@ * * @APPLE_LICENSE_HEADER_START@ * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. - * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in @@ -27,46 +25,127 @@ // // tokendatabase - software database container implementation. // -// A TokenDatabase is a software storage container, -// implemented in cooperation by the AppleCSLDP CDSA plugin and this daemon. +// A TokenDatabase represents access to an external (secure) storage container +// of some kind (usually a smartcard token). // #ifndef _H_TOKENDATABASE #define _H_TOKENDATABASE #include "database.h" +#include "tokenacl.h" +#include "session.h" +#include "token.h" +#include class TokenDatabase; class TokenDbCommon; class TokenKey; +class TokenDaemon; + + +// +// The global per-system object for a TokenDatabase (the TokenDbGlobal so to +// speak) is the Token object itself (from token.h). +// // // TokenDatabase DbCommons // -class TokenDbCommon : public DbCommon { -public: - TokenDbCommon(Session &ssn); +class TokenDbCommon : public DbCommon, public Adornable { public: + TokenDbCommon(Session &ssn, Token &tk, const char *name); + + Token &token() const; + uint32 subservice() const { return token().subservice(); } + std::string dbName() const; + + Adornable &store(); + void resetAcls(); + + void lockProcessing(); + + typedef Token::ResetGeneration ResetGeneration; + +private: + std::string mDbName; // name given during open + Adornable mAdornments; // Adornable for ACL store + + ResetGeneration mResetLevel; // validity tag }; // -// A Database object represents an Apple CSP/DL open database (DL/DB) object. -// It maintains its protected semantic state (including keys) and provides controlled -// access. +// A Database object represents a SC/CSPDL per-process access to a token. // class TokenDatabase : public Database { friend class TokenDbCommon; public: - TokenDatabase(Process &proc); + TokenDatabase(uint32 ssid, Process &proc, const char *name, const AccessCredentials *cred); + ~TokenDatabase(); TokenDbCommon &common() const; - + Token &token() const { return common().token(); } + TokenDaemon &tokend(); + uint32 subservice() const { return common().subservice(); } const char *dbName() const; + void dbName(const char *name); + bool transient() const; + + SecurityServerAcl &acl(); // it's our Token + + bool isLocked() const; + + bool validateSecret(const AclSubject *subject, const AccessCredentials *cred); + + const AccessCredentials *openCreds() const { return mOpenCreds; } + +protected: + // any Process-referent concept handle we hand out to the client + class Handler { + public: + Handler() : mHandle(0) { } + CSSM_HANDLE &tokenHandle() { return mHandle; } + CSSM_HANDLE tokenHandle() const { return mHandle; } + + protected: + CSSM_HANDLE mHandle; + }; + + // CSSM-style search handles (returned by findFirst) + struct Search : public Database::Search, public Handler { + Search(TokenDatabase &db) : Database::Search(db) { } + TokenDatabase &database() const { return referent(); } + ~Search(); + + Search *commit() { database().addReference(*this); return this; } + }; + + // CSSM-style record handles (returned by findFirst/findNext et al) + struct Record : public Database::Record, public Handler, public TokenAcl { + Record(TokenDatabase &db) : Database::Record(db) { } + TokenDatabase &database() const { return referent(); } + ~Record(); + + Record *commit() { database().addReference(*this); return this; } + + void validate(AclAuthorization auth, const AccessCredentials *cred) + { TokenAcl::validate(auth, cred, &database()); } + + // TokenAcl personality + AclKind aclKind() const; + Token &token(); + using Handler::tokenHandle; + GenericHandle tokenHandle() const; + }; public: - CSSM_KEY_SIZE queryKeySize(Key &key); + // + // Cryptographic service calls + // + void queryKeySizeInBits(Key &key, CssmKeySize &result); + void getOutputSize(const Context &context, Key &key, uint32 inputSize, bool encrypt, uint32 &result); // service calls void generateSignature(const Context &context, Key &key, CSSM_ALGORITHMS signOnlyAlgorithm, @@ -88,23 +167,70 @@ public: const AccessCredentials *cred, const AclEntryPrototype *owner, uint32 pubUsage, uint32 pubAttrs, uint32 privUsage, uint32 privAttrs, RefPointer &publicKey, RefPointer &privateKey); - RefPointer deriveKey(const Context &context, Key *key, + void deriveKey(const Context &context, Key *key, const AccessCredentials *cred, const AclEntryPrototype *owner, - CssmData *param, uint32 usage, uint32 attrs); + CssmData *param, uint32 usage, uint32 attrs, RefPointer &derivedKey); - void wrapKey(const Context &context, Key *key, - Key &keyToBeWrapped, const AccessCredentials *cred, + void wrapKey(const Context &context, const AccessCredentials *cred, + Key *hWrappingKey, Key &keyToBeWrapped, const CssmData &descriptiveData, CssmKey &wrappedKey); - RefPointer unwrapKey(const Context &context, Key *key, + void unwrapKey(const Context &context, const AccessCredentials *cred, const AclEntryPrototype *owner, - uint32 usage, uint32 attrs, const CssmKey wrappedKey, - Key *publicKey, CssmData *descriptiveData); - - uint32 getOutputSize(const Context &context, Key &key, uint32 inputSize, bool encrypt = true); + Key *wrappingKey, Key *publicKey, CSSM_KEYUSE usage, CSSM_KEYATTR_FLAGS attrs, + const CssmKey wrappedKey, RefPointer &unwrappedKey, CssmData &descriptiveData); public: - // encoding/decoding databases - void authenticate(const AccessCredentials *cred); + // + // Data-access calls + // + void findFirst(const CssmQuery &query, + CssmDbRecordAttributeData *inAttributes, mach_msg_type_number_t inAttributesLength, + CssmData *data, RefPointer &key, + RefPointer &search, RefPointer &record, + CssmDbRecordAttributeData * &outAttributes, mach_msg_type_number_t &outAttributesLength); + void findNext(Database::Search *search, + CssmDbRecordAttributeData *inAttributes, mach_msg_type_number_t inAttributesLength, + CssmData *data, RefPointer &key, RefPointer &record, + CssmDbRecordAttributeData * &outAttributes, mach_msg_type_number_t &outAttributesLength); + void findRecordHandle(Database::Record *record, + CssmDbRecordAttributeData *inAttributes, mach_msg_type_number_t inAttributesLength, + CssmData *data, RefPointer &key, + CssmDbRecordAttributeData * &outAttributes, mach_msg_type_number_t &outAttributesLength); + void insertRecord(CSSM_DB_RECORDTYPE recordtype, + const CssmDbRecordAttributeData *attributes, mach_msg_type_number_t inAttributesLength, + const CssmData &data, RefPointer &record); + void modifyRecord(CSSM_DB_RECORDTYPE recordtype, Record *record, + const CssmDbRecordAttributeData *attributes, mach_msg_type_number_t inAttributesLength, + const CssmData *data, CSSM_DB_MODIFY_MODE modifyMode); + void deleteRecord(Database::Record *record); + + // authenticate to database + void authenticate(CSSM_DB_ACCESS_TYPE mode, const AccessCredentials *cred); + +private: + // internal utilities + RefPointer makeKey(KeyHandle hKey, const CssmKey *key, + const AclEntryPrototype *owner); + + class InputKey { + public: + InputKey(Key *key) { setup(key); } + InputKey(Key &key) { setup(&key); } + ~InputKey(); + + operator KeyHandle () const { return mKeyHandle; } + operator const CssmKey * () const { return mKeyPtr; } + + private: + KeyHandle mKeyHandle; + CssmKey mKey; + CssmKey *mKeyPtr; + + void setup(Key *key); + }; + +private: + AccessCredentials *mOpenCreds; // credentials passed during open }; diff --git a/src/tokenkey.cpp b/src/tokenkey.cpp new file mode 100644 index 0000000..def8cbd --- /dev/null +++ b/src/tokenkey.cpp @@ -0,0 +1,129 @@ +/* + * Copyright (c) 2004 Apple Computer, Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + + +// +// tokenkey - remote reference key on an attached hardware token +// +#include "tokenkey.h" +#include "tokendatabase.h" + + +// +// Construct a TokenKey from a reference handle and key header +// +TokenKey::TokenKey(TokenDatabase &db, KeyHandle tokenKey, const CssmKey::Header &hdr) + : Key(db), mKey(tokenKey), mHeader(hdr) +{ + db.addReference(*this); +} + + +// +// Destruction of a TokenKey releases the reference from tokend +// +TokenKey::~TokenKey() +{ + try { + database().token().tokend().releaseKey(mKey); + } catch (...) { + secdebug("tokendb", "%p release key handle %ld threw (ignored)", + this, mKey); + } +} + + +// +// Links through the object mesh +// +TokenDatabase &TokenKey::database() const +{ + return referent(); +} + +Token &TokenKey::token() +{ + return database().token(); +} + +GenericHandle TokenKey::tokenHandle() const +{ + return mKey; // tokend-side handle +} + + +// +// Canonical external attributes (taken directly from the key header) +// +CSSM_KEYATTR_FLAGS TokenKey::attributes() +{ + return mHeader.attributes(); +} + + +// +// Return-to-caller processing (trivial in this case) +// +void TokenKey::returnKey(Handle &h, CssmKey::Header &hdr) +{ + h = this->handle(); + hdr = mHeader; +} + + +// +// We're a key (duh) +// +AclKind TokenKey::aclKind() const +{ + return keyAcl; +} + + +// +// Right now, key ACLs are at the process level +// +SecurityServerAcl &TokenKey::acl() +{ + return *this; +} + + +// +// The related database is, naturally enough, the TokenDatabase we're in +// +Database *TokenKey::relatedDatabase() +{ + return &database(); +} + + +// +// Generate the canonical key digest. +// This is not currently supported through tokend. If we need it, +// we'll have to force unlock and fake it (in tokend, most likely). +// +const CssmData &TokenKey::canonicalDigest() +{ + CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED); +} diff --git a/src/tokenkey.h b/src/tokenkey.h new file mode 100644 index 0000000..fac45fb --- /dev/null +++ b/src/tokenkey.h @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2004 Apple Computer, Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +#ifndef _H_TOKENKEY +#define _H_TOKENKEY + + +// +// tokenkey - remote reference key on an attached hardware token +// +#include "key.h" +#include "tokenacl.h" + +class TokenDatabase; + + +// +// The token-specific instance of a Key +// +class TokenKey : public Key, public TokenAcl { +public: + TokenKey(TokenDatabase &db, KeyHandle hKey, const CssmKey::Header &hdr); + ~TokenKey(); + + TokenDatabase &database() const; + Token &token(); + const CssmKey::Header &header() const { return mHeader; } + KeyHandle tokenHandle() const; + + CSSM_KEYATTR_FLAGS attributes(); + void returnKey(Handle &h, CssmKey::Header &hdr); + const CssmData &canonicalDigest(); + + SecurityServerAcl &acl(); + Database *relatedDatabase(); + +public: + // SecurityServerAcl personality + AclKind aclKind() const; + +private: + KeyHandle mKey; // tokend reference handle + CssmKey::Header mHeader; // key header as maintained by tokend +}; + +#endif //_H_TOKENKEY diff --git a/src/transition.cpp b/src/transition.cpp index 0d1f909..63d12eb 100644 --- a/src/transition.cpp +++ b/src/transition.cpp @@ -3,8 +3,6 @@ * * @APPLE_LICENSE_HEADER_START@ * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. - * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in @@ -25,24 +23,27 @@ // -// transition - SecurityServer IPC-to-class-methods transition layer +// transition - securityd IPC-to-class-methods transition layer // #include #include "server.h" #include "session.h" #include "database.h" #include "kcdatabase.h" +#include "tokendatabase.h" #include "kckey.h" #include "transwalkers.h" +#include "child.h" #include #include #include + // // Bracket Macros // -#define UCSP_ARGS mach_port_t servicePort, mach_port_t replyPort, security_token_t securityToken, \ +#define UCSP_ARGS mach_port_t servicePort, mach_port_t replyPort, audit_token_t auditToken, \ CSSM_RETURN *rcode #define CONTEXT_ARGS Context context, Pointer contextBase, Context::Attr *attributes, mach_msg_type_number_t attrSize @@ -56,9 +57,16 @@ Connection &connection __attribute__((unused)) = *connRef; catch (Connection *conn) { *rcode = 0; } \ catch (...) { *rcode = CssmError::merge(CSSM_ERRCODE_INTERNAL_ERROR, CSSM_ ## base ## _BASE_ERROR); } +#define BEGIN_IPCS try { +#define END_IPCS(more) } catch (...) { } \ + mach_port_deallocate(mach_task_self(), serverPort); more; return KERN_SUCCESS; + #define DATA_IN(base) void *base, mach_msg_type_number_t base##Length #define DATA_OUT(base) void **base, mach_msg_type_number_t *base##Length #define DATA(base) CssmData(base, base##Length) +#define OPTDATA(base) (base ? &CssmData(base, base##Length) : NULL) + +#define SSBLOB(Type, name) makeBlob(DATA(name)) #define COPY_IN(type,name) type *name, mach_msg_type_number_t name##Length, type *name##Base #define COPY_OUT(type,name) \ @@ -69,28 +77,6 @@ using LowLevelMemoryUtilities::increment; using LowLevelMemoryUtilities::difference; -// -// An OutputData object will take memory allocated within the SecurityServer, -// hand it to the MIG return-output parameters, and schedule it to be released -// after the MIG reply has been sent. It will also get rid of it in case of -// error. -// -class OutputData : public CssmData { -public: - OutputData(void **outP, mach_msg_type_number_t *outLength) - : mData(*outP), mLength(*outLength) { } - ~OutputData() - { mData = data(); mLength = length(); Server::releaseWhenDone(mData); } - - void operator = (const CssmData &source) - { CssmData::operator = (source); } - -private: - void * &mData; - mach_msg_type_number_t &mLength; -}; - - // // Setup/Teardown functions. // @@ -98,7 +84,7 @@ kern_return_t ucsp_server_setup(UCSP_ARGS, mach_port_t taskPort, ClientSetupInfo { BEGIN_IPCN Server::active().setupConnection(Server::connectNewProcess, servicePort, replyPort, - taskPort, securityToken, &info, identity); + taskPort, auditToken, &info, identity); END_IPCN(CSSM) return KERN_SUCCESS; } @@ -109,9 +95,9 @@ kern_return_t ucsp_server_setupNew(UCSP_ARGS, mach_port_t taskPort, { BEGIN_IPCN try { - RefPointer session = new DynamicSession(TaskPort(taskPort).bootstrap()); + RefPointer session = new DynamicSession(taskPort); Server::active().setupConnection(Server::connectNewSession, session->servicePort(), replyPort, - taskPort, securityToken, &info, identity); + taskPort, auditToken, &info, identity); *newServicePort = session->servicePort(); } catch (const MachPlusPlus::Error &err) { switch (err.error) { @@ -129,7 +115,7 @@ kern_return_t ucsp_server_setupThread(UCSP_ARGS, mach_port_t taskPort) { BEGIN_IPCN Server::active().setupConnection(Server::connectNewThread, servicePort, replyPort, - taskPort, securityToken); + taskPort, auditToken); END_IPCN(CSSM) return KERN_SUCCESS; } @@ -144,145 +130,166 @@ kern_return_t ucsp_server_teardown(UCSP_ARGS) } - // -// DL Interface +// Common database operations // -kern_return_t ucsp_server_attach(UCSP_ARGS, COPY_IN(CssmSubserviceUid, ssUid), AttachmentHandle *attachment) +kern_return_t ucsp_server_authenticateDb(UCSP_ARGS, DbHandle db, + CSSM_DB_ACCESS_TYPE accessType, COPY_IN(AccessCredentials, cred)) { BEGIN_IPC - secdebug("dl", "attach"); - relocate(ssUid, ssUidBase, ssUidLength); - // @@@ - *attachment = 0; + secdebug("dl", "authenticateDb"); + relocate(cred, credBase, credLength); + // ignoring accessType + Server::database(db)->authenticate(accessType, cred); END_IPC(DL) } -kern_return_t ucsp_server_detach(UCSP_ARGS, AttachmentHandle attachment) +kern_return_t ucsp_server_releaseDb(UCSP_ARGS, DbHandle db) { BEGIN_IPC - secdebug("dl", "detach"); - // @@@ + connection.process().kill(*Server::database(db)); END_IPC(DL) } -kern_return_t ucsp_server_openDb(UCSP_ARGS, AttachmentHandle attachment, DATA_IN(name), - COPY_IN(CssmNetAddress, location), CSSM_DB_ACCESS_TYPE accessType, - COPY_IN(AccessCredentials, accessCredentials), DATA_IN(openParameters), DbHandle *db) + +kern_return_t ucsp_server_getDbName(UCSP_ARGS, DbHandle db, char name[PATH_MAX]) { BEGIN_IPC - secdebug("dl", "openDb"); - //DATA(name); - relocate(location, locationBase, locationLength); - relocate(accessCredentials, accessCredentialsBase, accessCredentialsLength); - //DATA(openParameters); - // @@@ - *db = 0; + string result = Server::database(db)->dbName(); + assert(result.length() < PATH_MAX); + memcpy(name, result.c_str(), result.length() + 1); END_IPC(DL) } -kern_return_t ucsp_server_createDb2(UCSP_ARGS, AttachmentHandle attachment, DATA_IN(name), - COPY_IN(CssmNetAddress, location), COPY_IN(CSSM_DBINFO, dbInfo), CSSM_DB_ACCESS_TYPE accessType, - COPY_IN(AccessCredentials, accessCredentials), COPY_IN(AclEntryPrototype, aclEntryPrototype), - DATA_IN(openParameters), DbHandle *db) +kern_return_t ucsp_server_setDbName(UCSP_ARGS, DbHandle db, const char *name) { BEGIN_IPC - secdebug("dl", "createDb2"); - //DATA(name); - relocate(location, locationBase, locationLength); - relocate(dbInfo, dbInfoBase, dbInfoLength); - relocate(accessCredentials, accessCredentialsBase, accessCredentialsLength); - relocate(aclEntryPrototype, aclEntryPrototypeBase, aclEntryPrototypeLength); - //DATA(openParameters); - // @@@ - *db = 0; + Server::database(db)->dbName(name); END_IPC(DL) } -kern_return_t ucsp_server_deleteDb(UCSP_ARGS, AttachmentHandle attachment, - DATA_IN(name), COPY_IN(CssmNetAddress, location), COPY_IN(AccessCredentials, accessCredentials)) + +// +// External database interface +// +kern_return_t ucsp_server_openToken(UCSP_ARGS, uint32 ssid, FilePath name, + COPY_IN(AccessCredentials, accessCredentials), DbHandle *db) { BEGIN_IPC - secdebug("dl", "deleteDb"); - //DATA(name); - relocate(location, locationBase, locationLength); relocate(accessCredentials, accessCredentialsBase, accessCredentialsLength); - // @@@ + *db = (new TokenDatabase(ssid, connection.process(), name, accessCredentials))->handle(); END_IPC(DL) } -kern_return_t ucsp_server_getDbNames(UCSP_ARGS, AttachmentHandle attachment, - COPY_OUT(CSSM_NAME_LIST, outNameList)) +kern_return_t ucsp_server_findFirst(UCSP_ARGS, DbHandle db, + COPY_IN(CssmQuery, query), + COPY_IN(CssmDbRecordAttributeData, inAttributes), + COPY_OUT(CssmDbRecordAttributeData, outAttributes), + boolean_t getData, + DATA_OUT(data), KeyHandle *hKey, SearchHandle *hSearch, RecordHandle *hRecord) { BEGIN_IPC - secdebug("dl", "getDbNames"); - // @@@ - - CSSM_NAME_LIST *nameList; - //Attachment &a = Proccess::attachment(attachment); - //nameList = a.copyNameList(); - Copier nameLists(nameList, Allocator::standard()); // make flat copy - //a.freeNameList(nameList); // Release original - *outNameListLength = nameLists.length(); - //flips(nameLists.value(), outNameList, outNameListBase); - Server::releaseWhenDone(nameLists.keep()); // throw flat copy out when done - END_IPC(DL) -} + relocate(query, queryBase, queryLength); + relocate(inAttributes, inAttributesBase, inAttributesLength); -kern_return_t ucsp_server_getDbNameFromHandle(UCSP_ARGS, DbHandle db, DATA_OUT(name)) -{ - BEGIN_IPC - secdebug("dl", "getDbNameFromHandle"); - // @@@ + RefPointer search; + RefPointer record; + RefPointer key; + CssmData outData; //OutputData outData(data, dataLength); + CssmDbRecordAttributeData *outAttrs; mach_msg_type_number_t outAttrsLength; + Server::database(db)->findFirst(*query, inAttributes, inAttributesLength, + getData ? &outData : NULL, key, search, record, outAttrs, outAttrsLength); + + // handle nothing-found case without exceptions + if (!record) { + *hRecord = noRecord; + *hSearch = noSearch; + *hKey = noKey; + } else { + // return handles + *hRecord = record->handle(); + *hSearch = search->handle(); + *hKey = key ? key->handle() : noKey; + + // return attributes (assumes relocated flat blob) + flips(outAttrs, outAttributes, outAttributesBase); + *outAttributesLength = outAttrsLength; + + // return data (temporary fix) + if (getData) { + *data = outData.data(); + *dataLength = outData.length(); + } + } END_IPC(DL) } -kern_return_t ucsp_server_closeDb(UCSP_ARGS, DbHandle db) +kern_return_t ucsp_server_findNext(UCSP_ARGS, SearchHandle hSearch, + COPY_IN(CssmDbRecordAttributeData, inAttributes), + COPY_OUT(CssmDbRecordAttributeData, outAttributes), + boolean_t getData, DATA_OUT(data), KeyHandle *hKey, + RecordHandle *hRecord) { BEGIN_IPC - secdebug("dl", "closeDb"); - // @@@ + relocate(inAttributes, inAttributesBase, inAttributesLength); + RefPointer search = + Server::find(hSearch, CSSMERR_DL_INVALID_RESULTS_HANDLE); + RefPointer record; + RefPointer key; + CssmData outData; //OutputData outData(data, dataLength); + CssmDbRecordAttributeData *outAttrs; mach_msg_type_number_t outAttrsLength; + search->database().findNext(search, inAttributes, inAttributesLength, + getData ? &outData : NULL, key, record, outAttrs, outAttrsLength); + + // handle nothing-found case without exceptions + if (!record) { + *hRecord = noRecord; + *hKey = noKey; + } else { + // return handles + *hRecord = record->handle(); + *hKey = key ? key->handle() : noKey; + + // return attributes (assumes relocated flat blob) + flips(outAttrs, outAttributes, outAttributesBase); + *outAttributesLength = outAttrsLength; + + // return data (temporary fix) + if (getData) { + *data = outData.data(); + *dataLength = outData.length(); + } + } END_IPC(DL) } -kern_return_t ucsp_server_authenticateDb(UCSP_ARGS, DbHandle db, - CSSM_DB_ACCESS_TYPE accessType, COPY_IN(AccessCredentials, cred)) +kern_return_t ucsp_server_findRecordHandle(UCSP_ARGS, RecordHandle hRecord, + COPY_IN(CssmDbRecordAttributeData, inAttributes), + COPY_OUT(CssmDbRecordAttributeData, outAttributes), + boolean_t getData, DATA_OUT(data), KeyHandle *hKey) { BEGIN_IPC - secdebug("dl", "authenticateDb"); - relocate(cred, credBase, credLength); - // @@@ Pass in accessType. - Server::database(db)->authenticate(cred); - END_IPC(DL) -} + relocate(inAttributes, inAttributesBase, inAttributesLength); + RefPointer record = + Server::find(hRecord, CSSMERR_DL_INVALID_RECORD_UID); + RefPointer key; + CssmData outData; //OutputData outData(data, dataLength); + CssmDbRecordAttributeData *outAttrs; mach_msg_type_number_t outAttrsLength; + record->database().findRecordHandle(record, inAttributes, inAttributesLength, + getData ? &outData : NULL, key, outAttrs, outAttrsLength); + + // return handles + *hKey = key ? key->handle() : noKey; -kern_return_t ucsp_server_createRelation(UCSP_ARGS, DbHandle db, - CSSM_DB_RECORDTYPE recordType, - RelationName relationName, - uint32 attributeCount, - COPY_IN(CSSM_DB_SCHEMA_ATTRIBUTE_INFO, attributes), - uint32 indexCount, - COPY_IN(CSSM_DB_SCHEMA_INDEX_INFO, indices)) -{ - BEGIN_IPC - secdebug("dl", "createRelation"); - CheckingReconstituteWalker relocator(attributes, attributesBase, attributesLength, - Server::process().byteFlipped()); - for (uint32 ix = 0; ix < attributeCount; ++ix) - walk(relocator, attributes[ix]); - CheckingReconstituteWalker relocator2(indices, indicesBase, indicesLength, - Server::process().byteFlipped()); - for (uint32 ix = 0; ix < indexCount; ++ix) - walk(relocator, indices[ix]); - // @@@ - END_IPC(DL) -} + // return attributes (assumes relocated flat blob) + flips(outAttrs, outAttributes, outAttributesBase); + *outAttributesLength = outAttrsLength; -kern_return_t ucsp_server_destroyRelation(UCSP_ARGS, DbHandle db, CSSM_DB_RECORDTYPE recordType) -{ - BEGIN_IPC - secdebug("dl", "destroyRelation"); - // @@@ + // return data (temporary fix) + if (getData) { + *data = outData.data(); + *dataLength = outData.length(); + } END_IPC(DL) } @@ -290,63 +297,49 @@ kern_return_t ucsp_server_insertRecord(UCSP_ARGS, DbHandle db, CSSM_DB_RECORDTYP COPY_IN(CssmDbRecordAttributeData, attributes), DATA_IN(data), RecordHandle *record) { BEGIN_IPC - secdebug("dl", "insertRecord"); - // @@@ + relocate(attributes, attributesBase, attributesLength); + Server::database(db)->insertRecord(recordType, attributes, attributesLength, + DATA(data), *record); END_IPC(DL) } -kern_return_t ucsp_server_deleteRecord(UCSP_ARGS, RecordHandle record) +kern_return_t ucsp_server_modifyRecord(UCSP_ARGS, DbHandle db, RecordHandle *hRecord, + CSSM_DB_RECORDTYPE recordType, COPY_IN(CssmDbRecordAttributeData, attributes), + boolean_t setData, DATA_IN(data), CSSM_DB_MODIFY_MODE modifyMode) { BEGIN_IPC - secdebug("dl", "deleteRecord"); - // @@@ + relocate(attributes, attributesBase, attributesLength); + CssmData newData(DATA(data)); + RefPointer record = + Server::find(*hRecord, CSSMERR_DL_INVALID_RECORD_UID); + Server::database(db)->modifyRecord(recordType, record, attributes, attributesLength, + setData ? &newData : NULL, modifyMode); + // note that the record handle presented to the client never changes here + // (we could, but have no reason to - our record handles are just always up to date) END_IPC(DL) } -kern_return_t ucsp_server_modifyRecord(UCSP_ARGS, RecordHandle record, CSSM_DB_RECORDTYPE recordType, - COPY_IN(CssmDbRecordAttributeData, attributes), DATA_IN(data), CSSM_DB_MODIFY_MODE modifyMode) +kern_return_t ucsp_server_deleteRecord(UCSP_ARGS, DbHandle db, RecordHandle hRecord) { BEGIN_IPC - secdebug("dl", "modifyRecord"); - // @@@ + Server::database(db)->deleteRecord( + Server::find(hRecord, CSSMERR_DL_INVALID_RECORD_UID)); END_IPC(DL) } -kern_return_t ucsp_server_findFirstRecord(UCSP_ARGS, DbHandle db, - COPY_IN(CssmQuery, query), - SearchHandle *search, - COPY_IN(CssmDbRecordAttributeData, inAttributes), - COPY_OUT(CssmDbRecordAttributeData, outAttributes), - boolean_t getData, - DATA_OUT(data), - RecordHandle *record -) -{ - BEGIN_IPC - secdebug("dl", "findFirstRecord"); - // @@@ - END_IPC(DL) -} - -kern_return_t ucsp_server_findNextRecord(UCSP_ARGS, SearchHandle search, - COPY_IN(CssmDbRecordAttributeData, inAttributes), - COPY_OUT(CssmDbRecordAttributeData, outAttributes), - boolean_t getData, - DATA_OUT(data), - RecordHandle *record) +kern_return_t ucsp_server_releaseSearch(UCSP_ARGS, SearchHandle hSearch) { BEGIN_IPC - secdebug("dl", "findNextRecord"); - // @@@ + RefPointer search = Server::find(hSearch, 0); + search->database().releaseSearch(*search); END_IPC(DL) } -kern_return_t ucsp_server_abortFind(UCSP_ARGS, SearchHandle search) +kern_return_t ucsp_server_releaseRecord(UCSP_ARGS, RecordHandle hRecord) { BEGIN_IPC - secdebug("dl", "abortFind"); - //delete &Process::search(search); - // @@@ + RefPointer record = Server::find(hRecord, 0); + record->database().releaseRecord(*record); END_IPC(DL) } @@ -363,18 +356,9 @@ kern_return_t ucsp_server_getRecordFromHandle(UCSP_ARGS, RecordHandle record, END_IPC(DL) } -kern_return_t ucsp_server_freeRecordHandle(UCSP_ARGS, RecordHandle record) -{ - BEGIN_IPC - secdebug("dl", "freeRecordHandle"); - //delete &Process::record(record); - // @@@ - END_IPC(DL) -} - // -// Database management +// Internal database management // kern_return_t ucsp_server_createDb(UCSP_ARGS, DbHandle *db, COPY_IN(DLDbFlatIdentifier, ident), @@ -389,47 +373,55 @@ kern_return_t ucsp_server_createDb(UCSP_ARGS, DbHandle *db, END_IPC(DL) } -kern_return_t ucsp_server_decodeDb(UCSP_ARGS, DbHandle *db, - COPY_IN(DLDbFlatIdentifier, ident), COPY_IN(AccessCredentials, cred), DATA_IN(blob)) +// keychain synchronization +// @@@ caller should be required to call decodeDb() to get a DbHandle +// instead of passing the blob itself +kern_return_t ucsp_server_cloneDbForSync(UCSP_ARGS, DATA_IN(blob), + DbHandle srcDb, DATA_IN(agentData), DbHandle *newDb) { BEGIN_IPC - relocate(cred, credBase, credLength); - relocate(ident, identBase, identLength); - *db = (new KeychainDatabase(*ident, DATA(blob).interpretedAs(), - connection.process(), cred))->handle(); + RefPointer srcKC = Server::keychain(srcDb); + *newDb = (new KeychainDatabase(*srcKC, connection.process(), + SSBLOB(DbBlob, blob), DATA(agentData)))->handle(); END_IPC(DL) } -kern_return_t ucsp_server_encodeDb(UCSP_ARGS, DbHandle db, DATA_OUT(blob)) +kern_return_t ucsp_server_commitDbForSync(UCSP_ARGS, DbHandle srcDb, + DbHandle cloneDb, DATA_OUT(blob)) { BEGIN_IPC - DbBlob *dbBlob = Server::keychain(db)->blob(); // memory owned by database - *blob = dbBlob; - *blobLength = dbBlob->length(); - END_IPC(DL) -} + RefPointer srcKC = Server::keychain(srcDb); + RefPointer cloneKC = Server::keychain(cloneDb); + srcKC->commitSecretsForSync(*cloneKC); -kern_return_t ucsp_server_releaseDb(UCSP_ARGS, DbHandle db) -{ - BEGIN_IPC - connection.process().removeReference(*Server::database(db)); + // re-encode blob for convenience + if (blob && blobLength) { + DbBlob *dbBlob = srcKC->blob(); + *blob = dbBlob; + *blobLength = dbBlob->length(); + } else { + secdebug("kcrecode", "No blob can be returned to client"); + } END_IPC(DL) } -kern_return_t ucsp_server_getDbIndex(UCSP_ARGS, DbHandle db, DATA_OUT(index)) +kern_return_t ucsp_server_decodeDb(UCSP_ARGS, DbHandle *db, + COPY_IN(DLDbFlatIdentifier, ident), COPY_IN(AccessCredentials, cred), DATA_IN(blob)) { BEGIN_IPC - OutputData indexData(index, indexLength); - Server::keychain(db)->getDbIndex(indexData); + relocate(cred, credBase, credLength); + relocate(ident, identBase, identLength); + *db = (new KeychainDatabase(*ident, SSBLOB(DbBlob, blob), + connection.process(), cred))->handle(); END_IPC(DL) } -kern_return_t ucsp_server_authenticateDb(UCSP_ARGS, DbHandle db, - COPY_IN(AccessCredentials, cred)) +kern_return_t ucsp_server_encodeDb(UCSP_ARGS, DbHandle db, DATA_OUT(blob)) { BEGIN_IPC - relocate(cred, credBase, credLength); - Server::database(db)->authenticate(cred); + DbBlob *dbBlob = Server::keychain(db)->blob(); // memory owned by database + *blob = dbBlob; + *blobLength = dbBlob->length(); END_IPC(DL) } @@ -456,17 +448,10 @@ kern_return_t ucsp_server_changePassphrase(UCSP_ARGS, DbHandle db, END_IPC(DL) } -kern_return_t ucsp_server_lockDb(UCSP_ARGS, DbHandle db) -{ - BEGIN_IPC - Server::keychain(db)->lockDb(); - END_IPC(DL) -} - -kern_return_t ucsp_server_lockAll (UCSP_ARGS, boolean_t forSleep) +kern_return_t ucsp_server_lockAll (UCSP_ARGS, boolean_t) { BEGIN_IPC - connection.session().allReferences(&DbCommon::sleepProcessing); + connection.session().processLockAll(); END_IPC(DL) } @@ -487,7 +472,7 @@ kern_return_t ucsp_server_unlockDbWithPassphrase(UCSP_ARGS, DbHandle db, DATA_IN kern_return_t ucsp_server_isLocked(UCSP_ARGS, DbHandle db, boolean_t *locked) { BEGIN_IPC - *locked = Server::keychain(db)->isLocked(); + *locked = Server::database(db)->isLocked(); END_IPC(DL) } @@ -519,12 +504,32 @@ kern_return_t ucsp_server_decodeKey(UCSP_ARGS, KeyHandle *keyh, CssmKey::Header DbHandle db, DATA_IN(blob)) { BEGIN_IPC - RefPointer key = new KeychainKey(*Server::keychain(db), DATA(blob).interpretedAs()); + RefPointer key = new KeychainKey(*Server::keychain(db), SSBLOB(KeyBlob, blob)); key->returnKey(*keyh, *header); flip(*header); END_IPC(CSP) } +// keychain synchronization +kern_return_t ucsp_server_recodeKey(UCSP_ARGS, DbHandle oldDb, KeyHandle keyh, + DbHandle newDb, DATA_OUT(newBlob)) +{ + BEGIN_IPC + // If the old key is passed in as DATA_IN(oldBlob): + // RefPointer key = new KeychainKey(*Server::keychain(oldDb), SSBLOB(KeyBlob, oldBlob)); + RefPointer key = Server::key(keyh); + if (KeychainKey *kckey = dynamic_cast(key.get())) { + KeyBlob *blob = Server::keychain(newDb)->recodeKey(*kckey); + *newBlob = blob; + *newBlobLength = blob->length(); + Server::releaseWhenDone(*newBlob); + // @@@ stop leaking blob + } else { // not a KeychainKey + CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_REFERENCE); + } + END_IPC(CSP) +} + kern_return_t ucsp_server_releaseKey(UCSP_ARGS, KeyHandle keyh) { BEGIN_IPC @@ -537,7 +542,7 @@ kern_return_t ucsp_server_queryKeySizeInBits(UCSP_ARGS, KeyHandle keyh, CSSM_KEY { BEGIN_IPC RefPointer key = Server::key(keyh); - *length = key->database().queryKeySize(*key); + key->database().queryKeySizeInBits(*key, CssmKeySize::overlay(*length)); END_IPC(CSP) } @@ -547,7 +552,7 @@ kern_return_t ucsp_server_getOutputSize(UCSP_ARGS, CONTEXT_ARGS, KeyHandle keyh, BEGIN_IPC relocate(context, contextBase, attributes, attrSize); RefPointer key = Server::key(keyh); - *outputSize = key->database().getOutputSize(context, *key, inputSize, encrypt); + key->database().getOutputSize(context, *key, inputSize, encrypt, *outputSize); END_IPC(CSP) } @@ -560,21 +565,6 @@ kern_return_t ucsp_server_getKeyDigest(UCSP_ARGS, KeyHandle key, DATA_OUT(digest END_IPC(CSP) } -// -// RNG interface -// -kern_return_t ucsp_server_generateRandom(UCSP_ARGS, uint32 bytes, DATA_OUT(data)) -{ - BEGIN_IPC - Allocator &allocator = Allocator::standard(Allocator::sensitive); - void *buffer = allocator.malloc(bytes); - Server::active().random(buffer, bytes); - *data = buffer; - *dataLength = bytes; - Server::releaseWhenDone(allocator, buffer); - END_IPC(CSP) -} - // // Signatures and MACs @@ -662,7 +652,8 @@ kern_return_t ucsp_server_generateKey(UCSP_ARGS, DbHandle db, CONTEXT_ARGS, relocate(cred, credBase, credLength); relocate(owner, ownerBase, ownerLength); //@@@ preliminary interpretation - will get "type handle" - RefPointer database = Server::optionalDatabase(db); + RefPointer database = + Server::optionalDatabase(db, attrs & CSSM_KEYATTR_PERMANENT); RefPointer key; database->generateKey(context, cred, owner, usage, attrs, key); key->returnKey(*newKey, *newHeader); @@ -679,8 +670,9 @@ kern_return_t ucsp_server_generateKeyPair(UCSP_ARGS, DbHandle db, CONTEXT_ARGS, relocate(context, contextBase, attributes, attrSize); relocate(cred, credBase, credLength); relocate(owner, ownerBase, ownerLength); + RefPointer database = + Server::optionalDatabase(db, (privAttrs | pubAttrs) & CSSM_KEYATTR_PERMANENT); RefPointer pub, priv; - RefPointer database = Server::optionalDatabase(db); database->generateKey(context, cred, owner, pubUsage, pubAttrs, privUsage, privAttrs, pub, priv); pub->returnKey(*pubKey, *pubHeader); @@ -692,97 +684,112 @@ kern_return_t ucsp_server_generateKeyPair(UCSP_ARGS, DbHandle db, CONTEXT_ARGS, // -// Key derivation. -// This is a bit strained; the incoming 'param' value may have structure -// and needs to be handled on a per-algorithm basis, which means we have to -// know which key derivation algorithms we support for passing to our CSP(s). -// The default behavior is to handle "flat" data blobs, which is as good -// a default as we can manage. -// NOTE: The param-specific handling must be synchronized with the client library -// code (in sstransit.h). +// Key wrapping and unwrapping // -kern_return_t ucsp_server_deriveKey(UCSP_ARGS, DbHandle db, CONTEXT_ARGS, KeyHandle keyh, - COPY_IN(AccessCredentials, cred), COPY_IN(AclEntryPrototype, owner), - COPY_IN(void, paramInputData), DATA_OUT(paramOutput), - uint32 usage, uint32 attrs, KeyHandle *newKey, CssmKey::Header *newHeader) +kern_return_t ucsp_server_wrapKey(UCSP_ARGS, CONTEXT_ARGS, KeyHandle hWrappingKey, + COPY_IN(AccessCredentials, cred), KeyHandle hKeyToBeWrapped, + DATA_IN(descriptiveData), CssmKey *wrappedKey, DATA_OUT(keyData)) +{ + BEGIN_IPC + relocate(context, contextBase, attributes, attrSize); + relocate(cred, credBase, credLength); + RefPointer subjectKey = Server::key(hKeyToBeWrapped); + RefPointer wrappingKey = Server::optionalKey(hWrappingKey); + if ((context.algorithm() == CSSM_ALGID_NONE && subjectKey->attribute(CSSM_KEYATTR_SENSITIVE)) + || !subjectKey->attribute(CSSM_KEYATTR_EXTRACTABLE)) + CssmError::throwMe(CSSMERR_CSP_INVALID_KEYATTR_MASK); + pickDb(subjectKey, wrappingKey)->wrapKey(context, cred, wrappingKey, *subjectKey, DATA(descriptiveData), *wrappedKey); + + // transmit key data back as a separate blob + OutputData keyDatas(keyData, keyDataLength); + keyDatas = wrappedKey->keyData(); + flip(*wrappedKey); + END_IPC(CSP) +} + +kern_return_t ucsp_server_unwrapKey(UCSP_ARGS, DbHandle db, CONTEXT_ARGS, + KeyHandle hWrappingKey, COPY_IN(AccessCredentials, cred), COPY_IN(AclEntryPrototype, owner), + KeyHandle hPublicKey, CssmKey wrappedKey, DATA_IN(wrappedKeyData), + CSSM_KEYUSE usage, CSSM_KEYATTR_FLAGS attrs, DATA_OUT(descriptiveData), + KeyHandle *newKey, CssmKey::Header *newHeader) { BEGIN_IPC relocate(context, contextBase, attributes, attrSize); + flip(wrappedKey); + wrappedKey.keyData() = DATA(wrappedKeyData); relocate(cred, credBase, credLength); relocate(owner, ownerBase, ownerLength); - - // munge together the incoming 'param' value according to algorithm - CssmData param; - switch (context.algorithm()) { - case CSSM_ALGID_PKCS5_PBKDF2: - relocate((CSSM_PKCS5_PBKDF2_PARAMS *)paramInputData, - (CSSM_PKCS5_PBKDF2_PARAMS *)paramInputDataBase, - paramInputDataLength); - param = CssmData(paramInputData, sizeof(CSSM_PKCS5_PBKDF2_PARAMS)); - break; - default: - param = CssmData(paramInputData, paramInputDataLength); - break; - } - RefPointer database = Server::optionalDatabase(db); - RefPointer theKey = database->deriveKey(context, Server::optionalKey(keyh), - cred, owner, ¶m, usage, attrs); - theKey->returnKey(*newKey, *newHeader); + OutputData descriptiveDatas(descriptiveData, descriptiveDataLength); + RefPointer wrappingKey = Server::optionalKey(hWrappingKey); + RefPointer unwrappedKey; + pickDb(Server::optionalDatabase(db), wrappingKey)->unwrapKey(context, cred, owner, + wrappingKey, Server::optionalKey(hPublicKey), + usage, attrs, wrappedKey, unwrappedKey, descriptiveDatas); + unwrappedKey->returnKey(*newKey, *newHeader); flip(*newHeader); - if (param.length()) { - if (!param) // CSP screwed up - CssmError::throwMe(CSSM_ERRCODE_INTERNAL_ERROR); - if (paramInputDataLength) // using incoming buffer; make a copy - param = CssmAutoData(Server::csp().allocator(), param).release(); - OutputData(paramOutput, paramOutputLength) = param; // return the data - } END_IPC(CSP) } // -// Key wrapping and unwrapping +// Key derivation. // -kern_return_t ucsp_server_wrapKey(UCSP_ARGS, CONTEXT_ARGS, KeyHandle keyh, - COPY_IN(AccessCredentials, cred), KeyHandle keyToBeWrappedh, - DATA_IN(descriptiveData), CssmKey *wrappedKey, DATA_OUT(keyData)) +// Note that the "param" argument can have structure. The walker for the +// (artificial) POD CssmDeriveData handles those that are known; if you add +// an algorithm with structured param, you need to add a case there. +// +kern_return_t ucsp_server_deriveKey(UCSP_ARGS, DbHandle db, CONTEXT_ARGS, KeyHandle hKey, + COPY_IN(AccessCredentials, cred), COPY_IN(AclEntryPrototype, owner), + COPY_IN(CssmDeriveData, paramInput), DATA_OUT(paramOutput), + uint32 usage, uint32 attrs, KeyHandle *newKey, CssmKey::Header *newHeader) { BEGIN_IPC relocate(context, contextBase, attributes, attrSize); relocate(cred, credBase, credLength); - RefPointer inputKey = Server::key(keyToBeWrappedh); - inputKey->database().wrapKey(context, Server::optionalKey(keyh), - *inputKey, cred, DATA(descriptiveData), *wrappedKey); - // transmit key data back as a separate blob - *keyData = wrappedKey->data(); - *keyDataLength = wrappedKey->length(); - Server::releaseWhenDone(*keyData); - flip(*wrappedKey); + relocate(owner, ownerBase, ownerLength); + relocate(paramInput, paramInputBase, paramInputLength); + if (!paramInput || paramInput->algorithm != context.algorithm()) + CssmError::throwMe(CSSMERR_CSP_INTERNAL_ERROR); // client layer fault + + RefPointer database = + Server::optionalDatabase(db, attrs & CSSM_KEYATTR_PERMANENT); + RefPointer key = Server::optionalKey(hKey); + CssmData *param = paramInput ? ¶mInput->baseData : NULL; + RefPointer derivedKey; + pickDb(Server::optionalDatabase(db, attrs & CSSM_KEYATTR_PERMANENT), + key)->deriveKey(context, key, cred, owner, param, usage, attrs, derivedKey); + derivedKey->returnKey(*newKey, *newHeader); + flip(*newHeader); + if (param && param->length()) { + if (!param->data()) // CSP screwed up + CssmError::throwMe(CSSM_ERRCODE_INTERNAL_ERROR); + if (paramInputLength) // using incoming buffer; make a copy + *param = CssmAutoData(Server::csp().allocator(), *param).release(); + OutputData(paramOutput, paramOutputLength) = *param; // return the data + } END_IPC(CSP) } -kern_return_t ucsp_server_unwrapKey(UCSP_ARGS, DbHandle db, CONTEXT_ARGS, KeyHandle keyh, - COPY_IN(AccessCredentials, cred), COPY_IN(AclEntryPrototype, owner), - KeyHandle publicKeyh, CssmKey wrappedKey, DATA_IN(wrappedKeyData), - uint32 usage, uint32 attr, DATA_OUT(descriptiveData), - KeyHandle *newKey, CssmKey::Header *newHeader) + +// +// Random generation +// +kern_return_t ucsp_server_generateRandom(UCSP_ARGS, uint32 ssid, CONTEXT_ARGS, DATA_OUT(data)) { BEGIN_IPC relocate(context, contextBase, attributes, attrSize); - flip(wrappedKey); - wrappedKey.KeyData = DATA(wrappedKeyData); - relocate(cred, credBase, credLength); - relocate(owner, ownerBase, ownerLength); - RefPointer database = Server::optionalDatabase(db); - CssmData descriptiveDatas; - RefPointer theKey = database->unwrapKey(context, Server::optionalKey(keyh), - cred, owner, usage, attr, wrappedKey, - Server::optionalKey(publicKeyh), &descriptiveDatas); - theKey->returnKey(*newKey, *newHeader); - flip(*newHeader); - *descriptiveData = descriptiveDatas.data(); - *descriptiveDataLength = descriptiveDatas.length(); - Server::releaseWhenDone(*descriptiveData); + if (ssid) + CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED); + + // default version (use /dev/random) + Allocator &allocator = Allocator::standard(Allocator::sensitive); + if (size_t bytes = context.getInt(CSSM_ATTRIBUTE_OUTPUT_SIZE)) { + void *buffer = allocator.malloc(bytes); + Server::active().random(buffer, bytes); + *data = buffer; + *dataLength = bytes; + Server::releaseWhenDone(allocator, buffer); + } END_IPC(CSP) } @@ -796,7 +803,7 @@ kern_return_t ucsp_server_getOwner(UCSP_ARGS, AclKind kind, KeyHandle key, { BEGIN_IPC AclOwnerPrototype owner; - Server::aclBearer(kind, key).cssmGetOwner(owner); // allocates memory in owner + Server::aclBearer(kind, key).getOwner(owner); // allocates memory in owner Copier owners(&owner, Allocator::standard()); // make flat copy { ChunkFreeWalker free; walk(free, owner); } // release chunked original *ownerOutLength = owners.length(); @@ -811,7 +818,7 @@ kern_return_t ucsp_server_setOwner(UCSP_ARGS, AclKind kind, KeyHandle key, BEGIN_IPC relocate(cred, credBase, credLength); relocate(owner, ownerBase, ownerLength); - Server::aclBearer(kind, key).cssmChangeOwner(*owner, cred); + Server::aclBearer(kind, key).changeOwner(*owner, cred); END_IPC(CSP) } @@ -822,9 +829,9 @@ kern_return_t ucsp_server_getAcl(UCSP_ARGS, AclKind kind, KeyHandle key, BEGIN_IPC uint32 count; AclEntryInfo *aclList; - Server::aclBearer(kind, key).cssmGetAcl(haveTag ? tag : NULL, count, aclList); + Server::aclBearer(kind, key).getAcl(haveTag ? tag : NULL, count, aclList); *countp = count; - Copier aclsOut(AclEntryInfo::overlay(aclList), count); // make flat copy + Copier aclsOut(aclList, count); // make flat copy { // release the chunked memory originals ChunkFreeWalker free; @@ -856,11 +863,82 @@ kern_return_t ucsp_server_changeAcl(UCSP_ARGS, AclKind kind, KeyHandle key, BEGIN_IPC relocate(cred, credBase, credLength); relocate(acl, aclBase, aclLength); - Server::aclBearer(kind, key).cssmChangeAcl(AclEdit(mode, handle, acl), cred); + Server::aclBearer(kind, key).changeAcl(AclEdit(mode, handle, acl), cred); + END_IPC(CSP) +} + + +// +// Login/Logout +// +kern_return_t ucsp_server_login(UCSP_ARGS, COPY_IN(AccessCredentials, cred), DATA_IN(name)) +{ + BEGIN_IPC + relocate(cred, credBase, credLength); + CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED); + END_IPC(CSP) +} + +kern_return_t ucsp_server_logout(UCSP_ARGS) +{ + BEGIN_IPC + CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED); END_IPC(CSP) } +// +// Miscellaneous CSP-related calls +// +kern_return_t ucsp_server_getStatistics(UCSP_ARGS, uint32 ssid, CSPOperationalStatistics *statistics) +{ + BEGIN_IPC + CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED); + END_IPC(CSP) +} + +kern_return_t ucsp_server_getTime(UCSP_ARGS, uint32 ssid, CSSM_ALGORITHMS algorithm, DATA_OUT(data)) +{ + BEGIN_IPC + CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED); + END_IPC(CSP) +} + +kern_return_t ucsp_server_getCounter(UCSP_ARGS, uint32 ssid, DATA_OUT(data)) +{ + BEGIN_IPC + CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED); + END_IPC(CSP) +} + +kern_return_t ucsp_server_selfVerify(UCSP_ARGS, uint32 ssid) +{ + BEGIN_IPC + CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED); + END_IPC(CSP) +} + + +// +// Passthrough calls (separate for CSP and DL passthroughs) +// +kern_return_t ucsp_server_cspPassThrough(UCSP_ARGS, uint32 ssid, uint32 id, CONTEXT_ARGS, + KeyHandle hKey, DATA_IN(inData), DATA_OUT(outData)) +{ + BEGIN_IPC + CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED); + END_IPC(CSP) +} + +kern_return_t ucsp_server_dlPassThrough(UCSP_ARGS, uint32 ssid, uint32 id, + DATA_IN(inData), DATA_OUT(outData)) +{ + BEGIN_IPC + CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED); + END_IPC(DL) +} + + // // Database key management. // ExtractMasterKey looks vaguely like a key derivation operation, and is in fact @@ -875,7 +953,8 @@ kern_return_t ucsp_server_extractMasterKey(UCSP_ARGS, DbHandle db, CONTEXT_ARGS, relocate(cred, credBase, credLength); relocate(owner, ownerBase, ownerLength); RefPointer keychain = Server::keychain(sourceDb); - RefPointer masterKey = keychain->extractMasterKey(*Server::optionalDatabase(db), + RefPointer masterKey = keychain->extractMasterKey( + *Server::optionalDatabase(db, attrs & CSSM_KEYATTR_PERMANENT), cred, owner, usage, attrs); masterKey->returnKey(*newKey, *newHeader); flip(*newHeader); @@ -898,7 +977,7 @@ kern_return_t ucsp_server_authorizationCreate(UCSP_ARGS, Authorization::AuthItemSet rights(inRights), environment(inEnvironment); *rcode = connection.process().session().authCreate(rights, environment, - flags, *authorization, securityToken); + flags, *authorization, auditToken); END_IPC(CSSM) } @@ -991,10 +1070,44 @@ kern_return_t ucsp_server_setupSession(UCSP_ARGS, SessionCreationFlags flags, SessionAttributeBits attrs) { BEGIN_IPC - Session::setup(flags, attrs); + Server::process().session().setupAttributes(flags, attrs); END_IPC(CSSM) } +kern_return_t ucsp_server_setSessionDistinguishedUid(UCSP_ARGS, + SecuritySessionId sessionId, uid_t user) +{ + BEGIN_IPC + Session::find(sessionId).originatorUid(user); + END_IPC(CSSM) +} + +kern_return_t ucsp_server_getSessionDistinguishedUid(UCSP_ARGS, + SecuritySessionId sessionId, uid_t *user) +{ + BEGIN_IPC + *user = Session::find(sessionId).originatorUid(); + END_IPC(CSSM) +} + +kern_return_t ucsp_server_setSessionUserPrefs(UCSP_ARGS, SecuritySessionId sessionId, DATA_IN(userPrefs)) +{ + BEGIN_IPC + CFRef data(CFDataCreate(NULL, (UInt8 *)userPrefs, userPrefsLength)); + + if (!data) + { + *rcode = errSessionValueNotSet; + return 0; + } + + Session::find(sessionId).setUserPrefs(data); + *rcode = 0; + + END_IPC(CSSM) +} + + // // Notification core subsystem @@ -1013,11 +1126,11 @@ kern_return_t ucsp_server_stopNotification(UCSP_ARGS, mach_port_t receiver) END_IPC(CSSM) } -kern_return_t ucsp_server_postNotification(UCSP_ARGS, uint32 domain, uint32 event, DATA_IN(data)) +kern_return_t ucsp_server_postNotification(mach_port_t serverPort, uint32 domain, uint32 event, DATA_IN(data)) { - BEGIN_IPC - Listener::notify(domain, event, DATA(data)); - END_IPC(CSSM) + BEGIN_IPCS + Listener::notify(domain, event, DATA(data)); + END_IPCS() } @@ -1105,3 +1218,16 @@ kern_return_t ucsp_server_setAlternateSystemRoot(UCSP_ARGS, const char *root) Server::codeSignatures().open((string(root) + EQUIVALENCEDBPATH).c_str()); END_IPC(CSSM) } + + +// +// Child check-in service. +// Note that this isn't using the standard argument pattern. +// +kern_return_t ucsp_server_childCheckIn(mach_port_t serverPort, + mach_port_t servicePort, mach_port_t taskPort) +{ + BEGIN_IPCS + ServerChild::checkIn(servicePort, TaskPort(taskPort).pid()); + END_IPCS(mach_port_deallocate(mach_task_self(), taskPort)) +} diff --git a/src/transwalkers.cpp b/src/transwalkers.cpp index 50a54db..0d8fa4a 100644 --- a/src/transwalkers.cpp +++ b/src/transwalkers.cpp @@ -3,8 +3,6 @@ * * @APPLE_LICENSE_HEADER_START@ * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. - * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in @@ -88,3 +86,28 @@ void FlipWalker::doFlips(bool active) secdebug("flipwalkers", "outbound flips done"); } } + + +// +// Choose a Database from a choice of two sources, giving preference +// to persistent stores and to earlier sources. +// +Database *pickDb(Database *db1, Database *db2) +{ + // persistent db1 always wins + if (db1 && !db1->transient()) + return db1; + + // persistent db2 is next choice + if (db2 && !db2->transient()) + return db2; + + // pick any existing transient database + if (db1) + return db1; + if (db2) + return db2; + + // none at all. use the canonical transient store + return Server::optionalDatabase(noDb); +} diff --git a/src/transwalkers.h b/src/transwalkers.h index 67b4cb6..148ed22 100644 --- a/src/transwalkers.h +++ b/src/transwalkers.h @@ -3,8 +3,6 @@ * * @APPLE_LICENSE_HEADER_START@ * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. - * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in @@ -55,7 +53,7 @@ bool flipClient(); // A CheckingReconstituteWalker is a variant of an ordinary ReconstituteWalker // that checks object pointers and sizes against the incoming block limits. // It throws an exception if incoming data has pointers outside the incoming block. -// This avoids trouble inside of the SecurityServer caused (by bug or malice) +// This avoids trouble inside of securityd caused (by bug or malice) // from someone spoofing the client access side. // class CheckingReconstituteWalker { @@ -150,48 +148,39 @@ void relocate(Context &context, void *base, Context::Attr *attrs, uint32 attrSiz // // A FlipWalker is a walker operator that collects its direct invocations // into a set of memory objects. These objects can then collectively be -// byte-flipped (exactly once :-) at the flick of a function. +// byte-flipped (exactly once :-) at the flick of a method. // class FlipWalker { private: - struct FlipBase { - virtual ~FlipBase() { } + struct Base { + virtual ~Base() { } virtual void flip() const = 0; }; template - struct FlipRef : public FlipBase { + struct FlipRef : public Base { T &obj; FlipRef(T &s) : obj(s) { } - void flip() const -{ secdebug("outflip", "%p flip/ref %s@%p", this, Debug::typeName(obj).c_str(), &obj); -{ Flippers::flip(obj); } -} + void flip() const { Flippers::flip(obj); } }; template - struct FlipPtr : public FlipBase { + struct FlipPtr : public Base { T * &obj; FlipPtr(T * &s) : obj(s) { } - void flip() const -{ secdebug("outflip", "%p flip/ptr %s@%p(%p)", this, Debug::typeName(obj).c_str(), &obj, obj); -{ Flippers::flip(*obj); Flippers::flip(obj); } -} -}; + void flip() const { Flippers::flip(*obj); Flippers::flip(obj); } + }; template - struct FlipBlob : public FlipBase { + struct FlipBlob : public Base { T * &obj; FlipBlob(T * &s) : obj(s) { } - void flip() const -{ secdebug("outflip", "%p flip/blob %s@%p(%p)", this, Debug::typeName(obj).c_str(), &obj, obj); -{ Flippers::flip(obj); } -} + void flip() const { Flippers::flip(obj); } }; struct Flipper { - FlipBase *impl; - Flipper(FlipBase *p) : impl(p) { } + Base *impl; + Flipper(Base *p) : impl(p) { } bool operator < (const Flipper &other) const { return impl < other.impl; } }; @@ -232,6 +221,12 @@ void flip(T &addr) } } + +// +// Take an object at value, flip it, and return appropriately flipped +// addr/base pointers ready to be returned through IPC. +// Note that this doesn't set the outgoing length (aka 'fooLength') field. +// template void flips(T *value, T ** &addr, T ** &base) { @@ -245,4 +240,55 @@ void flips(T *value, T ** &addr, T ** &base) } +// +// Take a DATA type RPC argument purportedly representing a Blob of some kind, +// turn it into a Blob, and fail properly if it's not kosher. +// +template +const BlobType *makeBlob(const CssmData &blobData, CSSM_RETURN error = CSSM_ERRCODE_INVALID_DATA) +{ + if (!blobData.data() || blobData.length() < sizeof(BlobType)) + CssmError::throwMe(error); + const BlobType *blob = static_cast(blobData.data()); + if (blob->totalLength != blobData.length()) + CssmError::throwMe(error); + return blob; +} + + +// +// An OutputData object will take memory allocated within securityd, +// hand it to the MIG return-output parameters, and schedule it to be released +// after the MIG reply has been sent. It will also get rid of it in case of +// error. +// +class OutputData : public CssmData { +public: + OutputData(void **outP, mach_msg_type_number_t *outLength) + : mData(*outP), mLength(*outLength) { } + ~OutputData() + { mData = data(); mLength = length(); Server::releaseWhenDone(mData); } + + void operator = (const CssmData &source) + { CssmData::operator = (source); } + +private: + void * &mData; + mach_msg_type_number_t &mLength; +}; + + +// +// Choose a Database from a choice of two sources, giving preference +// to persistent stores and to earlier sources. +// +Database *pickDb(Database *db1, Database *db2); + +static inline Database *dbOf(Key *key) { return key ? &key->database() : NULL; } + +inline Database *pickDb(Key *k1, Key *k2) { return pickDb(dbOf(k1), dbOf(k2)); } +inline Database *pickDb(Database *db1, Key *k2) { return pickDb(db1, dbOf(k2)); } +inline Database *pickDb(Key *k1, Database *db2) { return pickDb(dbOf(k1), db2); } + + #endif //_H_TRANSWALKERS diff --git a/tests/AZNTest.cpp b/tests/AZNTest.cpp index b4c1082..a3d5dee 100644 --- a/tests/AZNTest.cpp +++ b/tests/AZNTest.cpp @@ -3,8 +3,6 @@ * * @APPLE_LICENSE_HEADER_START@ * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. - * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in diff --git a/tests/exectest.cpp b/tests/exectest.cpp index 8809f29..101b9c8 100644 --- a/tests/exectest.cpp +++ b/tests/exectest.cpp @@ -3,8 +3,6 @@ * * @APPLE_LICENSE_HEADER_START@ * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. - * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in diff --git a/tests/testacls.cpp b/tests/testacls.cpp index 7975f41..0fab166 100644 --- a/tests/testacls.cpp +++ b/tests/testacls.cpp @@ -3,8 +3,6 @@ * * @APPLE_LICENSE_HEADER_START@ * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. - * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in diff --git a/tests/testauth.cpp b/tests/testauth.cpp index d017a7c..790b4bd 100644 --- a/tests/testauth.cpp +++ b/tests/testauth.cpp @@ -3,8 +3,6 @@ * * @APPLE_LICENSE_HEADER_START@ * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. - * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in diff --git a/tests/testblobs.cpp b/tests/testblobs.cpp index 910d648..f769a50 100644 --- a/tests/testblobs.cpp +++ b/tests/testblobs.cpp @@ -3,8 +3,6 @@ * * @APPLE_LICENSE_HEADER_START@ * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. - * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in diff --git a/tests/testclient.cpp b/tests/testclient.cpp index 05b72fd..6935510 100644 --- a/tests/testclient.cpp +++ b/tests/testclient.cpp @@ -3,8 +3,6 @@ * * @APPLE_LICENSE_HEADER_START@ * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. - * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in diff --git a/tests/testclient.h b/tests/testclient.h index c0b5e6f..cbcd72a 100644 --- a/tests/testclient.h +++ b/tests/testclient.h @@ -3,8 +3,6 @@ * * @APPLE_LICENSE_HEADER_START@ * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. - * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in diff --git a/tests/testcrypto.cpp b/tests/testcrypto.cpp index 20329cb..4357229 100644 --- a/tests/testcrypto.cpp +++ b/tests/testcrypto.cpp @@ -3,8 +3,6 @@ * * @APPLE_LICENSE_HEADER_START@ * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. - * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in diff --git a/tests/testutils.cpp b/tests/testutils.cpp index ebcbe18..3b6bd89 100644 --- a/tests/testutils.cpp +++ b/tests/testutils.cpp @@ -3,8 +3,6 @@ * * @APPLE_LICENSE_HEADER_START@ * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. - * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in diff --git a/tests/testutils.h b/tests/testutils.h index d355064..343a3f9 100644 --- a/tests/testutils.h +++ b/tests/testutils.h @@ -3,8 +3,6 @@ * * @APPLE_LICENSE_HEADER_START@ * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. - * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in -- 2.45.2