4

If I have a username and password pair how can I verify that they are actually correct in a Linux system? I know I can use passwd to do so but I want to do it programatically using C.

I should not require root privileges (so reading the shadow file is not an option).

Thank you.

user1618465
  • 1,813
  • 2
  • 32
  • 58

2 Answers2

2

If you are using a PAM, you might be able to make use of checkpassword-pam.

The manual has an example command (with debugging) which should give you a good place to start.

echo -e "username\0password\0timestamp\0" \
    | checkpassword-pam -s SERVICE \
    --debug --stdout -- /usr/bin/id 3<&0
Matt Clark
  • 27,671
  • 19
  • 68
  • 123
  • Can you provide a small code to see how to implement that? Thank you – user1618465 Nov 20 '17 at 19:30
  • I see that the function doing the check is `authenticate_using_pam (const char* service_name, const char* username, const char* password)` What should be the `service_name` parameter there? AFAIK at least to install a PAM module you need to be root. Don't you to use that API? – user1618465 Nov 20 '17 at 19:47
2

This is a simple example to check the password with some python code. No root privilegs are needed.

#!/usr/bin/python3

# simple linux password checker with
# standard python

import os, pty


def check_pass(user, passw):
    # returns: 0 if check ok
    #          1 check failed
    #          2 account locked
    if type(passw) is str:
        passw = passw.encode()
    pid, fd = pty.fork()
    # try to su a fake shell which returns '-c OK' on ok
    if not pid:
        # child
        argv = ('su', '-c', 'OK', '-s', '/bin/echo', user)
        os.execlp(argv[0], *argv)
        return  # SHOULD NEVER REACHED
    okflg = False
    locked = False
    while True:
        try:
            data = os.read(fd, 1024)
            ##print('data:', data, flush=True)
        except OSError:
            break
        if not data:
            break
        data = data.strip()
        if data == b'Password:':
            os.write(fd, passw + b'\r\n')
        elif data.endswith(b'OK'):
            okflg = True
            break
        elif data.find(b'locked') > -1:
            # show that account is locked
            locked = True
            print(data, flush=True)
            break
    os.close(fd)
    # check result from su and okflg
    if (not os.waitpid(pid, 0)[1]) and okflg:
        return 0
    return 2 if locked else 1


if __name__ == '__main__':
    print(check_pass('xx', 'yy'))
a99
  • 301
  • 3
  • 5