diff --git a/README.md b/README.md
index 20eae67..29f6a71 100644
--- a/README.md
+++ b/README.md
@@ -3,11 +3,12 @@
## Screenshot
-
+
## Warning
-Only tested under the MacBook Pro with Touch Bar, macOS 10.12.1.
+- I am not a security expert. While I am using this as a fun experiment on my personal computer, your security needs may vary.
+- This has only been tested on the 2016 15" MacBook Pro with Touch Bar running macOS 10.12.1.
## Building
@@ -31,6 +32,12 @@ Now if we try running our copy of `sudo`, it should work:
> ./sudo -s
+If you don't have a Mac with a biometric sensor, `sudo-touchid` will fail. If you'd still like to test whether the `LocalAuthentication` framework is working correctly, you can change the `kAuthPolicy` constant to `LAPolicyDeviceOwnerAuthentication` in `sudo/plugins/sudoers/auth/sudo_auth.m`. This will present a dialog box asking the user for his or her password:
+
+
+
+While not useful in practice, you can use this to verify that the `LocalAuthentication` code does in fact work.
+
## Installing
Replacing the system's `sudo` program is quite risky (can prevent your Mac from booting) and requires disabling System Integrity Protection (aka "Rootless").
diff --git a/pam.d/sudo b/pam.d/sudo
index 87551fb..1869df8 100644
--- a/pam.d/sudo
+++ b/pam.d/sudo
@@ -1,4 +1,5 @@
# sudo: auth account password session
+auth sufficient pam_smartcard.so
auth required pam_opendirectory.so
account required pam_permit.so
password required pam_deny.so
diff --git a/sudo-entitlements.plist b/sudo-entitlements.plist
new file mode 100644
index 0000000..c5bf520
--- /dev/null
+++ b/sudo-entitlements.plist
@@ -0,0 +1,10 @@
+
+
+
+
+ com.apple.private.AuthorizationServices
+
+ com.apple.security.sudo
+
+
+
diff --git a/sudo.xcodeproj/project.pbxproj b/sudo.xcodeproj/project.pbxproj
old mode 100644
new mode 100755
diff --git a/sudo.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/sudo.xcodeproj/project.xcworkspace/contents.xcworkspacedata
old mode 100644
new mode 100755
index f437590..919434a
--- a/sudo.xcodeproj/project.xcworkspace/contents.xcworkspacedata
+++ b/sudo.xcodeproj/project.xcworkspace/contents.xcworkspacedata
@@ -2,6 +2,6 @@
+ location = "self:">
diff --git a/sudo/plugins/sudoers/auth/sudo_auth.m b/sudo/plugins/sudoers/auth/sudo_auth.m
index a058d15..57cb383 100644
--- a/sudo/plugins/sudoers/auth/sudo_auth.m
+++ b/sudo/plugins/sudoers/auth/sudo_auth.m
@@ -458,39 +458,65 @@
typedef enum {
kTouchIDResultNone,
kTouchIDResultAllowed,
+ kTouchIDResultFallback,
+ kTouchIDResultCancel,
kTouchIDResultFailed
} TouchIDResult;
static const LAPolicy kAuthPolicy = 0x3f0;
+static const LAPolicy kAuthPolicyFallback = LAPolicyDeviceOwnerAuthentication;
int
touchid_setup(struct passwd *pw, char **prompt, sudo_auth *auth) {
@try {
LAContext *context = [[LAContext alloc] init];
- BOOL canAuthenticate = [context canEvaluatePolicy:kAuthPolicy error:nil];
+ BOOL canAuthenticate = [context canEvaluatePolicy:kAuthPolicy error:nil]
+ || [context canEvaluatePolicy:kAuthPolicyFallback error:nil];
[context release];
- return canAuthenticate ? AUTH_SUCCESS : AUTH_FAILURE;
+ return canAuthenticate ? AUTH_SUCCESS : AUTH_FATAL;
}
@catch(NSException *) {
// LAPolicyDeviceOwnerAuthenticationWithBiometrics may not be available on builds older than 10.12.1!
sudo_printf(SUDO_CONV_INFO_MSG, _("2"));
- return AUTH_FAILURE;
+ return AUTH_FATAL;
}
}
int
touchid_verify(struct passwd *pw, char *pass, sudo_auth *auth, struct sudo_conv_callback *callback) {
- LAContext *context = [[LAContext alloc] init];
__block TouchIDResult result = kTouchIDResultNone;
- [context evaluatePolicy:kAuthPolicy localizedReason:@"authenticate a privileged operation" reply:^(BOOL success, NSError *error) {
- result = success ? kTouchIDResultAllowed : kTouchIDResultFailed;
- CFRunLoopWakeUp(CFRunLoopGetCurrent());
- }];
-
- while (result == kTouchIDResultNone)
- CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, true);
+ while (result == kTouchIDResultFallback || result == kTouchIDResultNone) {
+ LAContext *context = [[LAContext alloc] init];
+ [context evaluatePolicy:(result != kTouchIDResultFallback ? kAuthPolicy : kAuthPolicyFallback) localizedReason:@"authenticate a privileged operation" reply:^(BOOL success, NSError *error) {
+ result = success ? kTouchIDResultAllowed : kTouchIDResultFailed;
+ switch (error.code) {
+ case LAErrorBiometryNotAvailable:
+ case LAErrorUserFallback:
+ result = kTouchIDResultFallback;
+ break;
+ case LAErrorUserCancel:
+ result = kTouchIDResultCancel;
+ break;
+ }
+ CFRunLoopWakeUp(CFRunLoopGetCurrent());
+ }];
+
+ result = kTouchIDResultNone;
+
+ while (result == kTouchIDResultNone) {
+ CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, true);
+ }
+
+ [context release];
+ }
- [context release];
- return result == kTouchIDResultAllowed ? AUTH_SUCCESS : AUTH_FAILURE;
+ switch (result) {
+ case kTouchIDResultCancel:
+ return AUTH_FATAL;
+ case kTouchIDResultAllowed:
+ return AUTH_SUCCESS;
+ default:
+ return AUTH_FAILURE;
+ }
}
diff --git a/sudo/plugins/sudoers/pwutil.c b/sudo/plugins/sudoers/pwutil.c
index 354866a..c115878 100644
--- a/sudo/plugins/sudoers/pwutil.c
+++ b/sudo/plugins/sudoers/pwutil.c
@@ -800,6 +800,8 @@ sudo_set_grlist(struct passwd *pw, char * const *groups, char * const *gids)
debug_return_int(0);
}
+#ifndef __APPLE_MEMBERSHIP__
+
bool
user_in_group(const struct passwd *pw, const char *group)
{
@@ -860,3 +862,22 @@ user_in_group(const struct passwd *pw, const char *group)
__func__, pw->pw_name, matched ? "" : "NOT ", group);
debug_return_bool(matched);
}
+
+#else
+
+#include
+
+int mbr_check_membership_ext(int, const void *, size_t, int, const void *, int, int *);
+
+bool
+user_in_group(const struct passwd *pw, const char *group)
+{
+ debug_decl(user_in_group, SUDOERS_DEBUG_NSS)
+ int is_member = 0;
+ int ret = mbr_check_membership_ext(ID_TYPE_UID, &pw->pw_uid, sizeof(pw->pw_uid), ID_TYPE_GROUPNAME, group, 0, &is_member);
+ sudo_debug_printf(SUDO_DEBUG_DEBUG, "%s: user %s %sin group %s (mbr_check: %d)", __func__, pw->pw_name, is_member ? "" : "NOT ", group, ret);
+
+ debug_return_bool((bool)is_member);
+}
+
+#endif