Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support macOS High Sierra, upgrading sudo to version 86. #25

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 9 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,12 @@

## Screenshot

![Screenshot](images/Screenshot.png)
<img src="https://github.com/mattrajca/sudo-touchid/blob/master/images/Screenshot.png?raw=true" width=556 height=284 />

## 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

Expand All @@ -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:

<img src="https://github.com/mattrajca/sudo-touchid/blob/master/images/auto_fallback.png?raw=true" width=556 height=301 />

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").
Expand Down
1 change: 1 addition & 0 deletions pam.d/sudo
Original file line number Diff line number Diff line change
@@ -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
Expand Down
10 changes: 10 additions & 0 deletions sudo-entitlements.plist
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.private.AuthorizationServices</key>
<array>
<string>com.apple.security.sudo</string>
</array>
</dict>
</plist>
Empty file modified sudo.xcodeproj/project.pbxproj
100644 → 100755
Empty file.
2 changes: 1 addition & 1 deletion sudo.xcodeproj/project.xcworkspace/contents.xcworkspacedata
100644 → 100755

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

52 changes: 39 additions & 13 deletions sudo/plugins/sudoers/auth/sudo_auth.m
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
}
21 changes: 21 additions & 0 deletions sudo/plugins/sudoers/pwutil.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down Expand Up @@ -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 <membership.h>

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