Как проверить пользователя и пароль на macOS программно? - PullRequest
0 голосов
/ 28 января 2020

У меня есть приложение, которое запрашивает имя пользователя и пароль пользователя. В настоящее время для Unix систем (большинство из них) я прочитал пароль ha sh из /etc/shadow, но для macOS это намного более громоздко (они используют свой собственный стандарт), поэтому я хотел знать, есть ли простой способ проверьте имена пользователей и пароли.

Я думал об использовании программы login странным образом, но это не лучшее решение.

Я использую golang, но решение в C или C ++ тоже было бы полезно.

Редактировать

Ответ от @TheNextman - именно то, о чем я просил, но разговаривая с другими людьми, они предлагают мне используйте PAM, потому что он работает с несколькими ОС. Мне потребовались некоторые усилия, чтобы понять это, потому что я искал простой API для проверки пользователей и паролей, что-то вроде verify(username string, password string) -> boolean, но я понял, что PAM является более общим и, следовательно, более сложным.

Но это код, который я использовал в итоге, он сделан в GO с C привязками.

package Authentication
import "C"
import (
    "encoding/json"
    "fmt"
    "github.com/vvanpo/golang-pam"
)

func ValidateUser(username, password string) (bool, error) {
    // TODO correct handle of errors
    UserPssword := userPassword{
        Username : username,
        Password : password,
    }
    b, _ := json.Marshal(UserPssword)

    conn := myConHand{
        username:C.CString(string(b)),
    }
    tx, _ := pam.Start("sshd", username, conn)

    r := tx.Authenticate(0)
    if r == pam.SUCCESS{
        return true, nil
    } else {
        return false, nil
    }
}

type userPassword struct {
    Username string
    Password string
}

type myConHand struct {
    username *C.char
}

//C.GoString
func (m myConHand) RespondPAM(msg_style int, msg string) (string, bool) {
    str := C.GoString(m.username)

    var UserPssword userPassword
    _ = json.Unmarshal([]byte(str), &UserPssword)

    switch msg_style {
    case pam.PROMPT_ECHO_OFF:
        fmt.Println("Password!!")
        return UserPssword.Password, true
    case pam.PROMPT_ECHO_ON:
        fmt.Println("Username!!")
        return UserPssword.Username, true
    case pam.ERROR_MSG:
        fmt.Println(msg)
        return "", true
    case pam.TEXT_INFO:
        fmt.Println(msg)
        return "", true
    default:
        return "", true
    }
}

У него есть некоторые проблемы, например, я использую сервис /etc/pam.d/sshd, потому что я знаю, что компьютеры Я буду использовать тот же сервис, но я не знаю, какая ОС имеет /etc/pam.d/sshd, другой вариант - создать свой собственный сервис, но мне придется создать его для каждого отдельного стандарта, который я нашел 3 Linux PAM, openPAM (macos) и Solaris PAM.

Но в целом я считаю, что это надежное решение, поскольку я повторно использую существующий механизм аутентификации.

1 Ответ

3 голосов
/ 29 января 2020

было бы полезно использовать решение в C или C ++

Вот пример в C с использованием CoreServices . Проверка ошибок и результатов для краткости опущена:

void on_logon(const char* username, const char* password) {
    CSIdentityQueryRef query;
    CFArrayRef idArray = NULL;
    CSIdentityRef result;
    CFStringRef cfUsername = NULL;
    CFStringRef cfPassword = NULL;

    cfUsername = CFStringCreateWithCString(NULL, username, kCFStringEncodingUTF8);
    query = CSIdentityQueryCreateForName(kCFAllocatorDefault, cfUsername, kCSIdentityQueryStringEquals, kCSIdentityClassUser,    CSGetDefaultIdentityAuthority());

    CSIdentityQueryExecute(query, kCSIdentityQueryGenerateUpdateEvents, NULL);

    idArray = CSIdentityQueryCopyResults(query);

    if (CFArrayGetCount(idArray) != 1)
    {
        // Username didn't match...
    }

    result = (CSIdentityRef) CFArrayGetValueAtIndex(idArray, 0);

    cfPassword = CFStringCreateWithCString(NULL, password, kCFStringEncodingUTF8);

    if (CSIdentityAuthenticateUsingPassword(result, cfPassword))
    {
        // Username and password are valid!!
    }

    CFRelease(cfUsername);
    CFRelease(idArray);
    CFRelease(cfPassword);
    CFRelease(query);
}
...