Giter Club home page Giter Club logo

pam_wtid's Introduction

pam_wtid

pam_wtid is a patching utility used to add support to Apple's pam_tid PAM module for watch authentication in addition to Touch ID. If you have a watch paired to your Mac or fingerprints enrolled for unlocking, you can use this module to authenticate sudo.

Screenshot

Preview Image

Install

make enable will patch the exisitng pam_tid binary on your system (found in /usr/lib/pam/), and place a modified version of pam_wtid in /usr/local/lib/pam. It will also modify /etc/pam.d/sudo to enable the PAM module.

make disable will remove the patched binary and revert the changes in /etc/pam.d/sudo.

Why

There are already a lot of really cool, open source PAM modules/utilities that add Tocuh ID and watch authentication to sudo. To name a few:

When my computer is docked in clamshell mode, I can only use watch unlocking. But if I am on the go, I want to use Touch ID over watch unlocking since it is usually quicker. I used to use pam-watchid, but on my new 2021 16" MacBook Pro only watch support works. Doing a little debugging, it seems that the context/sandbox in which the PAM module is called does not correctly link back to the current user, and I was seeing error messages from the LAPolicy framework that no fingerprints are enrolled.

How

Apple's Local Authentication framework gives an API to authenticate users through different LAPolicys. This is how all of programs above work.

For our purposes, there are only 2 important policies used to determine how a user authenticated:

LAPolicy.deviceOwnerAuthenticationWithBiometrics = 1

User authentication with biometry

LAPolicy.deviceOwnerAuthenticationWithBiometricsOrWatch = 4

User authentication with either biometry or Apple Watch.

pam-watchid forks pam-touchID to switch the policy from .deviceOwnerAuthenticationWithBiometrics to .deviceOwnerAuthenticationWithBiometricsOrWatch. I am unsure why the biometrics and watch policy fails to make Touch ID work on my new machine, because when the policy is only biometrics, Touch ID works as intended. I was able to reporduce this in a sample project when running the executable as root. I able to use Touch ID on its own, but after adding the watch option to the policy it failed to work. I will be updating this repo with the sample project and a link to a Radar since this seems like an OS bug.

Patching

Since the current Swift implementations had issues, I decided to see if Apple's own pam_tid had a similar problem. When reading through the source, I noticed some interesting code that attempts to determine the user authenticating and whether or not they are in an Aqua session. I figured this is enough of a reason to try and recompile the PAM module with watch support added.

I unfortunately was unable to compile the project, due to it depending on some internal headers I was not able to patch out easily. I also noticed that the call to LAEvaluatePolicy has an extra options dictionary argument, which is not available in the public API.

options = CFDictionaryCreateMutable(kCFAllocatorDefault, 2, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
CFDictionarySetValue(options, key, value);
CFDictionarySetValue(options, key2, value2);

context = LACreateNewContextWithACMContext(NULL, &error);
if (!context) {
    os_log_error(PAM_LOG, "unable to create context.");
    retval = PAM_AUTH_ERR;
    goto cleanup;
}

/* evaluate policy */
if (!LAEvaluatePolicy(context, kLAPolicyDeviceOwnerAuthenticationWithBiometrics, options, &error)) {
    // error is intended as failure means Touch ID is not usable which is in fact not an error but the state we need to handle
    if (CFErrorGetCode(error) != kLAErrorNotInteractive) {
        os_log_debug(PAM_LOG, "policy evaluation failed: %ld", CFErrorGetCode(error));
        retval = PAM_AUTH_ERR;
        goto cleanup;
    }
}

The options dictionary is filled with a few keys that are not publically documented, but it does have a refrence to the user's ID. If this fixed the issue I saw above, then watch support should be simple enough to add.

Since I couldn't compile this code easily and didn't particularly want to require it in Objective-C/Swift and attempt to call into the private API, I decided to try and figure out a binary patch. I only need to change the 2nd argument in the call from a 1 to a 4 to match the enumeration above, and thought that should be simple enoguh.

In the code, LAEvaluatePolicy is only called once. Using objtool we can dissassemble the pam_tid binary and search for this call:

❯❯❯ objdump -macho -d /usr/lib/pam/pam_tid.so.2 | grep "_LAEvaluatePolicy$" -B 8       
    4e3d:    e8 a5 0f 00 00     callq   _LACreateNewContextWithACMContext
    4e42:    48 85 c0           testq   %rax, %rax
    4e45:    0f 84 34 01 00 00  je      0x4f7f
    4e4b:    48 8d 4d c8        leaq    -56(%rbp), %rcx
    4e4f:    48 89 45 98        movq    %rax, -104(%rbp)
    4e53:    48 89 c7           movq    %rax, %rdi
    4e56:    be 01 00 00 00     movl    $1, %esi
    4e5b:    4c 89 e2           movq    %r12, %rdx
    4e5e:    e8 50 0b 00 00     callq   _LAEvaluatePolicy
--
    489c:    a1 83 01 d1        sub     x1, x29, #96
    48a0:    00 00 80 d2        mov     x0, #0
    48a4:    2e 04 00 94        bl      _LACreateNewContextWithACMContext
    48a8:    60 08 00 b4        cbz     x0, 0x49b4
    48ac:    f9 03 00 aa        mov     x25, x0
    48b0:    a3 83 01 d1        sub     x3, x29, #96
    48b4:    21 00 80 52        mov     w1, #1
    48b8:    e2 03 18 aa        mov     x2, x24
    48bc:    f3 02 00 94        bl      _LAEvaluatePolicy

Sure enough we get 2 results, one for the x86_64 slice and the other for the arm64e slice in the fat binary (used for universal support on Appple Silicon). We can see the registers esi and w1 (the second arguments in the x86_64/arm64e calling conventions) are set to 0x1.

At this point we just need to replace the corresponding bytes for the argument instruction with the updated LAPolicy value.

For x86_64:

be 01 00 00 00      ;; movl    $1, %esi
;; should be replaced with
be 04 00 00 00      ;; movl    $4, %esi

For arm64e:

21 00 80 52         ;; mov    w1, #1
;; should be replaced with
81 00 80 52         ;; mov    w1, #4

These can be verified using an online assembler.

After we know what to replace, it was trivial to write a Python script to find the bytes of the call to _LAEvaluatePolicy for both x86_64 and arm64e, and then backtrack to find the most recent instruction that set the 2nd argument to 0x1 and replace it with one that sets it to 0x4. This has the benefit of being slightly flexible if Apple recompiles the binary with a different compiler/small code changes. I found the binaries differed slightly between my machione on Big Sur versus my new one on Monterey so this method was better than simply doing a full find/replace on this code snippit.

The only other thing worth noting is we have to re-sign the library with an adhoc signature using codesign --force -s - pam_wtid.so, otherwise the system kills our module since its code signature was modified. Makes sense, but I thought this wasn't going to work the first time I tested out my patch!

Thoughts

This was a really fun project to hack on. Compilers/systems were some of my favorite classes in undergrad, so it was fun to try and use some of that knowledge to work backwards and write a pretty straightforward patch. Is this better than theoretically fixing the open source versions? Maybe? We are using something Apple's engineers wrote, but it is in a memory unsafe language instead of Swift ;). That being said, the harm of using this is pretty low and I know I will have it running on my machines for the mild convenience it adds, even if this project took more time than me typing in my password into sudo for 50 years.

pam_wtid's People

Contributors

inickt avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

Forkers

epk quantumlibet

pam_wtid's Issues

Can't get pam_wtid to work on Ventura

Hi!

Trying to setup pam_witd on macOS 13.0 Ventura and getting an error when trying to use sudo after:

❯ make enable
sudo mkdir -p /usr/local/lib/pam
sudo install -b -o root -g wheel -m 444 pam_wtid.so /usr/local/lib/pam/pam_wtid.so.2
sudo sed -E -i ".bak" "1s/^(#.*)$/\1\nauth       sufficient     pam_wtid.so/" "/etc/pam.d/sudo"
❯ sudo vim /etc/pam.d/sudo
sudo: unable to initialize PAM: No such file or directory

This what the sudo file look like:

❯ cat /etc/pam.d/sudo
# sudo: auth account password session
auth       sufficient     pam_wtid.so
auth       sufficient     pam_smartcard.so
auth       required       pam_opendirectory.so
account    required       pam_permit.so
password   required       pam_deny.so
session    required       pam_permit.so

Obviously make disable fails because of the above sudo error.
I can revert by booting into recovery (M1 here).

Some info:

❯ sw_vers
ProductName:		macOS
ProductVersion:		13.0
BuildVersion:		22A380
❯ xcode-select -p
/Applications/Xcode-14.1.0.app/Contents/Developer

Let me know if you need more info.

Unable to install on macOS 12.4 - Did not find extension point with identifier

python3 patch.py /usr/lib/pam/pam_tid.so.2 pam_wtid.so
Opening /usr/lib/pam/pam_tid.so.2
Error dissasembling binary:
2022-06-20 22:47:13.012 xcodebuild[77066:19841223] Requested but did not find extension point with identifier Xcode.IDEKit.ExtensionSentinelHostApplications for extension Xcode.DebuggerFoundation.AppExtensionHosts.watchOS of plug-in com.apple.dt.IDEWatchSupportCore
2022-06-20 22:47:13.012 xcodebuild[77066:19841223] Requested but did not find extension point with identifier Xcode.IDEKit.ExtensionPointIdentifierToBundleIdentifier for extension Xcode.DebuggerFoundation.AppExtensionToBundleIdentifierMap.watchOS of plug-in com.apple.dt.IDEWatchSupportCore
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/objdump: error: unknown argument '-cho'

make: *** [pam_wtid.so] Error 1

XCode is Version 13.4.1 (13F100) (in case that matters)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.