Unable to use CoreWLAN under root permission

I am working on developing a client to complete 8021.x wireless authentication by python.

According to the CoreWLAN Documentation scanForNetworks(withName:), I'm going to use scanForNetworksWithName_error_ and associateToEnterpriseNetwork_identity_username_password_error_ provided in CoreWLAN. And I wrote a script to have a try.

import os
import pwd
from CoreWLAN import CWWiFiClient
from Foundation import NSString

def get_real_user():
    sudo_user = os.environ.get('SUDO_USER')
    if sudo_user:
        return sudo_user
    return os.environ.get('USER', 'root')

def run_as_user(username):
    if os.geteuid() == 0:
        uid = pwd.getpwnam(username).pw_uid
        gid = pwd.getpwnam(username).pw_gid
        os.setuid(uid)

def connect_to_enterprise_network(ssid, username, password):
    try:
        real_user = get_real_user()
        if os.geteuid() == 0:
            run_as_user(real_user)

        client = CWWiFiClient.sharedWiFiClient()
        interface = client.interface()
        if not interface:
            print("no interface")
            return False

        print("scaning...")
        error = None
        scan_result, error = interface.scanForNetworksWithName_error_(ssid, None)
        if error:
            print(f"scan fialed: {error.localizedDescription()}")
            return False

        target_network = None
        for network in scan_result.allObjects():
            if network.ssid() == ssid:
                target_network = network
                break
        if not target_network:
            print("no target network")
            return False

        success, error = interface.associateToEnterpriseNetwork_identity_username_password_error_(
            target_network,
            None,
            NSString.stringWithString_(username),
            NSString.stringWithString_(password),
            None
        )

        if not success:
            print(f"connect failed: {error.localizedDescription() if error else 'unknown error'}")
            return False
        print("connect successfully")
        return True

    except Exception as e:
        print(f"exception: {str(e)}")
        return False

if __name__ == "__main__":
    ssid = "ssid"
    username = "username"
    password = "password"
    
    success = connect_to_enterprise_network(ssid, username, password)

However, I can only execute this script normally under non-root permissions. When I switch to root and execute it, the variable "scan_result.allObjects()" will be an object without any ssid and bssid. Finally the function prints "no target network" and returned.

<CWNetwork: 0x107104080> [ssid=(null), bssid=(null), security=WPA2 Enterprise, rssi=-52, channel=<CWChannel: 0x11e8a1fd0> [channelNumber=44(5GHz), channelWidth={20MHz}], ibss=0]

Compared with the value without sudo:

[<CWNetwork: 0x144650580> [ssid=ssid, bssid=<redacted>, security=WPA2 Enterprise, rssi=-55, channel=<CWChannel: 0x1247040d0> [channelNumber=149(5GHz), channelWidth={20MHz}], ibss=0]]

My python code will be included in an app that must be executed as a root user, so this issue can't be ignored and waiting for your help. THANKS!

Answered by DTS Engineer in 826022022

It’s better to reply as a reply, rather than in the comments; see Quinn’s Top Ten DevForums Tips for this and other titbits.

I can’t help you with third-party tools. If you need help with those, you should seek that via their support resources.

Lemme explain this issue from the perspective of Apple APIs. In recent releases we have changed Core WLAN to provide stronger privacy guarantees. Accessing Wi-Fi information now requires that the user grant you the Location privilege. This brings macOS in line with our other platforms.

What’s unique about macOS, however, is that it supports daemons. A daemon runs outside of any user login context. This causes problems here because the Location privilege is per user, so there’s no way to grant a daemon this privilege. So, if your ultimate intention is to create a daemon that gathers Wi-Fi information, you won’t be able to do that.

Note Many folks use the term daemon to mean code that runs in the background. That’s not the sense that I use it. Rather, I’m using it to mean a launchd daemon, that is, code that runs in the global execution context. If you’re unfamiliar with execution contexts on macOS, see Technote 2083 Daemons and Agents.

One option here is to do this work from an agent, that is, a program running in the background but in a specific user context. That works, but it has limitations. Some folks asking about this want to gather Wi-Fi information when no user is logged in, and using an agent won’t work for that because no agents are running when the Mac is setting at the login screen [1].

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

[1] Except pre-login agents, but those run as root and thus there’s no way to grant them the Location privilege.

Written by iLemonRain in 774777021
My python code will be included in an app that must be executed as a root user

I presume you’re using “app” in some generic sense, not in the sense of a program that the user launches by double clicking in the Finder. Because apps shouldn’t ever run as root.

Given that, how is your code being executed? Is it a launchd daemon? Or being started by a launchd daemon? Or something else?

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

It’s better to reply as a reply, rather than in the comments; see Quinn’s Top Ten DevForums Tips for this and other titbits.

I can’t help you with third-party tools. If you need help with those, you should seek that via their support resources.

Lemme explain this issue from the perspective of Apple APIs. In recent releases we have changed Core WLAN to provide stronger privacy guarantees. Accessing Wi-Fi information now requires that the user grant you the Location privilege. This brings macOS in line with our other platforms.

What’s unique about macOS, however, is that it supports daemons. A daemon runs outside of any user login context. This causes problems here because the Location privilege is per user, so there’s no way to grant a daemon this privilege. So, if your ultimate intention is to create a daemon that gathers Wi-Fi information, you won’t be able to do that.

Note Many folks use the term daemon to mean code that runs in the background. That’s not the sense that I use it. Rather, I’m using it to mean a launchd daemon, that is, code that runs in the global execution context. If you’re unfamiliar with execution contexts on macOS, see Technote 2083 Daemons and Agents.

One option here is to do this work from an agent, that is, a program running in the background but in a specific user context. That works, but it has limitations. Some folks asking about this want to gather Wi-Fi information when no user is logged in, and using an agent won’t work for that because no agents are running when the Mac is setting at the login screen [1].

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

[1] Except pre-login agents, but those run as root and thus there’s no way to grant them the Location privilege.

Unable to use CoreWLAN under root permission
 
 
Q