]> git.saurik.com Git - apple/securityd.git/blobdiff - src/tokenacl.cpp
securityd-61.tar.gz
[apple/securityd.git] / src / tokenacl.cpp
diff --git a/src/tokenacl.cpp b/src/tokenacl.cpp
new file mode 100644 (file)
index 0000000..efaf36a
--- /dev/null
@@ -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 <security_utilities/trackingallocator.h>
+#include <security_cdsa_utilities/cssmbridge.h>
+
+
+//
+// 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<TokenDatabase *>(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<TokenDatabase &>(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);
+       }
+}