Troubleshooting Linux or Unix runas problems for local users

Troubleshooting Linux or Unix runas problems for local users

book

Article ID: KB0084803

calendar_today

Updated On:

Products Versions
TIBCO DataSynapse GridServer -
Not Applicable -

Description

Resolution:
Using the runas facility on Linux or Unix can be very useful in many environments. However, understanding and configuring the PAM security system can be confusing if you're not familiar with it. We find that it is best to take a step-by-step approach, verifying the correctness of the configuration along the way.

This troubleshooting guide addresses the question specifically for running as local (/etc/passwd) users. Running as an LDAP user should work the same way, but we have not verified the guide at this time for LDAP users.

To perform this troubleshooting procedure, you must have root access on the target system. But you also need a separate account as a non-privileged user.

(1) Install the testpam2 utility from DataSynapse.

The source code for the testpam2 utility is at the bottom of this document. You must first install the PAM development libraries to compile this utility. If you don't have the PAM development environment set up, you'll get missing header file errors in your compile.

Compile similarly to this:

g++ -lpam -o testpam2 testpam2.cpp

Install the testpam2 utility on a local filesystem. (You can only use an NFS filesytem if you have set the no-root-squash option.) As root, change the owner to root and set the mode to 4755 (setuid root).

The testpam2 utility has the syntax:

testpam2 user pass [service]

Where the optional service parameter (default "dsengine") is the PAM service to use.

Success is indicated by a retval of 0 in each of the three output lines. If you're not squeamish about typing your password on the command line, you could verify that the testpam2 utility works at this time using your own username and password. But this is definitely a case where it's ok to be squeamish.

(2) Create a local user and verify it

As root, run the useradd command so that you create a local user, using a home directory on a local filesystem (/tmp is ok), and set a test password of e.g. shady1.

useradd -d /tmp/shady1 shady1
passwd shady1

Verify that you can su to that user with the specified password:

su shady1

(3) Verify that testpam2 utility can authenticate the test user

As your own username (not root, and not shady1), verify that testpam2 can authenticate against the su
and login services:

testpam2 shady1 shady1 su
testpam2 shady1 shady1 login

All lines should show a retval of 0. Any non-zero retval indicates failure. Common failure modes are 7 and
10.

(4) Set up the dsengine PAM service

As root, set up the dsengine PAM service. Older versions of the GridServer Administration Guide describe how to set up an LDAP-specific dsengine PAM service. But we want to authenticate a local user, so it's better to copy a working PAM service such as login. The easiest approach is to copy the auth and account sections from the login service, dropping the secure tty module. Here an example from one of our development linux systems:

login

#%PAM-1.0
auth required pam_securetty.so
auth include common-auth
auth required pam_nologin.so
auth required pam_mail.so
account include common-account
password include common-password
session include common-session
session required pam_resmgr.so

dsengine

#%PAM-1.0
auth include common-auth
auth required pam_nologin.so
account include common-account

As you can see, we decided we didn't need securetty nor mail.

(5) Check the dsengine service

Now, you should be able to verify the test user as yourself. First make sure that the test user verifies the test user:

su shady1
testpam2 shady1 shady1 dsengine
exit

You should see retval 0 on all three lines. Then make sure your non-privileged user id can verify the test user:
testpam2 shady1 shady1

(6) Success - now you can install the DSEngine

Once you've verified the correctness of the PAM installation, you can install the DSEngine and try using runas. Remember that the DSEngine install must mimic the testpam2 install :

- install DSEngine on a local filesystem (or on an NFS filesystem with no-root-squash)
- change the owner of the invokeRA program to root
- change the mode of the invokeRA program to 4755


Here is the testpam2.cpp source code (copy all text below this line to a file called testpam2.cpp).

extern "C" {
#include &ltsecurity/pam_appl.h>
}
#include &ltcstdio>
#include &ltstring>
#include &ltiostream>
using std::string;
using std::cout;
using std::endl;

extern "C" {

//
// removes the auth fail delay for Linux
//
void bogus_fail_delay(int retval, unsigned usec_delay, void* appdata_ptr) {
}

//
// pam conversation function(s)
//
int ds_pam_conv(int num_msg, struct pam_message **msg, struct pam_response** resp, void* appdata_ptr)
{
    // we expect the password to be set here; otherwise error
    if (appdata_ptr == NULL) {
        return PAM_CONV_ERR;
    }

    char* password = (char*) appdata_ptr;

    // use malloc since PAM is all C
    (*resp) = (struct pam_response*) malloc(sizeof(struct pam_response));
    struct pam_response *p_resp = *resp;

    // copy the password into the conversation response
    p_resp-&gtresp = (char*) malloc((strlen(password) + 1) * sizeof(char));
    strcpy(p_resp-&gtresp, password);

    // only recognized value
    p_resp-&gtresp_retcode = 0;

    return PAM_SUCCESS;
}

} // extern "C"

int main (int argc, char** argv) {
    if (argc < 3) {
    cout<<"Usage: "<&ltargv[0] <<" username password"<&ltendl;
    return 0;
    }
    string username(argv[1]);
    string password(argv[2]);
    char* service = "dsengine";
    if (argc > 3)
        service = argv[3];
    
    pam_handle_t *pamh = NULL;

    // the pam conversation structure
    struct pam_conv pamc = {
        ds_pam_conv,
        (void*) password.c_str()
    };

    // init the pam session
    int retval = pam_start( service,
                            username.c_str(),
                            &pamc,
             &pamh
                 );
cout<<"pam_start for service " << service << ", retval="<&ltretval<&ltendl;
    // authenticate the user
    if (retval == PAM_SUCCESS) {
#ifdef LINUX
        pam_set_item( pamh, PAM_FAIL_DELAY, (void*) bogus_fail_delay );
#endif
        retval = pam_authenticate( pamh, 0 );
    }
cout<<"pam_set_item retval="<&ltretval<&ltendl;
    // verify that the user is permitted access
    if (retval == PAM_SUCCESS) {
        retval = pam_acct_mgmt( pamh, 0 );
    }
cout<<"pam_acct_mgmt retval="<&ltretval<&ltendl;
    // close the session
    pam_end( pamh, PAM_SUCCESS );
}

Issue/Introduction

Troubleshooting Linux or Unix runas problems for local users