Depending on the application PAM services can be compiled as either 32-bit or 64-bitbinaries. Since PAM modules are loaded as shared objects viadlopen,they must be provided in both 32-bit and 64-bit versions in order to support use byeither form of application. For more information, see thedlopen(3C) man page.
For more information about how to install both the 32-bit and 64-bit versions of themodule so the PAM framework can load the appropriate version of the application, seeHow to Add a PAM Module inManaging Authentication in Oracle Solaris 11.4.
The following PAM consumer application is provided as an example. The example is a basicterminal-lock application that validates a user trying to access a terminal.
The example goes through the following steps:
Initialize the PAM session.
PAM sessions are initiated by calling thepam_start(3PAM) function. A PAM consumer application must firstestablish a PAM session before calling any of the other PAMfunctions.
Thepam_start(3PAM) function takes the following arguments:
plock – Service name, that is, the nameof the application. The service name is used by the PAM framework todetermine which rules in the configuration file,/etc/pam.conf or, the/etc/pam.d, are applicable. The servicename is generally used for logging and error-reporting.
pw->pw_name – The username is the nameof the user that the PAM framework acts on.
&conv – The conversation function,conv, which provides a generic means for PAMto communicate with a user or application. Conversation functionsare necessary because the PAM modules have no way of knowing howcommunication is to be conducted. Communication can be by means ofGUIs, the command line, a smart card reader, or other devices. Formore information, seeWriting Conversation Functions.
&pamh – The PAM handle,pamh, which is an opaque handle that is usedby the PAM framework to store information about the currentoperation. This handle is returned by a successful call topam_start().
Authenticate the user.
The application callspam_authenticate(3PAM) to authenticate the current user. Generally, theuser is required to enter a password or other authentication token dependingon the type of authentication service.
The PAM framework invokes the modules configured for the service nameplock which corresponds to the service module type ofauthentication,auth, in/etc/pam.d/plock. If there are noauth entries for theplock servicein either/etc/pam.conf or/etc/pam.d/plock, thenauthentries for theother service are searched in/etc/pam.conf and finally in the/etc/pam.d/other file.
Check account validity.
The example uses thepam_acct_mgmt(3PAM) function to check the validity of theauthenticated user's account. In this example,pam_acct_mgmt() checks for expiration of thepassword.
Thepam_acct_mgmt() function also uses thePAM_DISALLOW_NULL_AUTHTOK flag. Ifpam_acct_mgmt()returns PAM_NEW_AUTHTOK_REQD, thenpam_chauthtok(3PAM) should be called to allow the authenticated userto change the password.
Force the user to change passwords if the system discovers that thepassword has expired.
The example uses a loop to callpam_chauthtok() untilsuccess is returned. Thepam_chauthtok() function returnssuccess if the user successfully changes his or her authenticationinformation, which is usually the password. In this example, the loopcontinues until success is returned. More commonly, an application would seta maximum number of tries before terminating.
Callpam_setcred(3PAM).
Thepam_setcred(3PAM) function is used to establish, modify, or deleteuser credentials.pam_setcred() is typically called whena user has been authenticated. The call is made after the account has beenvalidated, but before a session has been opened. Thepam_setcred() function is used with thePAM_ESTABLISH_CRED flag to establish a new user session. If the session isthe renewal of an existing session, such as forlockscreen,pam_setcred() with thePAM_REFRESH_CRED flag should be called. If the session is changing thecredentials, such as usingsu or assuming a role, thenpam_setcred() with the PAM_REINITIALIZE_CRED flagshould be called.
Close the PAM session.
The PAM session is closed by calling thepam_end(3PAM) function.pam_end() frees allPAM resources as well.
The following example shows the source code for the sample PAM consumerapplication.
Example 5 Sample PAM Consumer Application/* * Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved. */#include <sys/types.h>#include <stdio.h>#include <unistd.h>#include <stdlib.h>#include <strings.h>#include <signal.h>#include <pwd.h>#include <errno.h>#include <security/pam_appl.h>extern int pam_tty_conv(int num_msg, struct pam_message **msg, struct pam_response **response, void *appdata_ptr);/* Disable keyboard interrupts (Ctrl-C, Ctrl-Z, Ctrl-\) */static voiddisable_kbd_signals(void) { (void) signal(SIGINT, SIG_IGN); (void) signal(SIGTSTP, SIG_IGN); (void) signal(SIGQUIT, SIG_IGN);}/* Terminate current user session, i.e., logout */static voidlogout() { pid_t pgroup = getpgrp(); (void) signal(SIGTERM, SIG_IGN); (void) fprintf(stderr, "Sorry, your session can't be restored.\n"); (void) fprintf(stderr, "Press return to terminate this session.\n"); (void) getchar(); (void) kill(-pgroup, SIGTERM); (void) sleep(2); (void) kill(-pgroup, SIGKILL); exit(-1);}int/*ARGSUSED*/main(int argc, char *argv) { struct pam_conv conv = {pam_tty_conv, NULL}; pam_handle_t *pamh; struct passwd *pw; int err; disable_kbd_signals(); if ((pw = getpwuid(getuid())) == NULL) { (void) fprintf(stderr, "plock: Can't get username: %s\n", strerror(errno)); exit(1); } /* Initialize PAM framework */ err = pam_start("plock", pw->pw_name, &conv, &pamh); if (err != PAM_SUCCESS) { (void) fprintf(stderr, "plock: pam_start failed: %s\n", pam_strerror(pamh, err)); exit(1); } /* Authenticate user in order to unlock screen */ do { (void) fprintf(stderr, "Terminal locked for %s. ", pw->pw_name); err = pam_authenticate(pamh, 0); if (err == PAM_USER_UNKNOWN) { logout(); } else if (err != PAM_SUCCESS) { (void) fprintf(stderr, "Invalid password.\n"); } } while (err != PAM_SUCCESS); /* Make sure account and password are still valid */ switch (err = pam_acct_mgmt(pamh, 0)) { case PAM_SUCCESS: break; case PAM_USER_UNKNOWN: case PAM_ACCT_EXPIRED: /* User not allowed in anymore */ logout(); break; case PAM_NEW_AUTHTOK_REQD: /* The user's password has expired. Get a new one */ do { err = pam_chauthtok(pamh, 0); } while (err == PAM_AUTHTOK_ERR); if (err != PAM_SUCCESS) logout(); break; default: logout(); } /* Establish the requested credentials */ if ((err = pam_setcred(pamh, PAM_ESTABLISH_CRED)) != PAM_SUCCESS) logout(); /* Open a session */ if ((err = pam_open_session(pamh, 0)) != PAM_SUCCESS) logout(); /* Close a session */ if ((err = pam_close_session(pamh, 0)) != PAM_SUCCESS) logout(); /* Delete the requested credentials */ if ((err = pam_setcred(pamh, PAM_DELETE_CRED)) != PAM_SUCCESS) logout(); if (pam_setcred(pamh, PAM_REFRESH_CRED) != PAM_SUCCESS) { logout(); } (void) pam_end(pamh, 0); return (0); /*NOTREACHED*/}
The preceding example,Example 5, Sample PAM Consumer Application, isa simple application that demonstrates only a few of the major PAM functions. Thissection describes some other PAM functions that can be useful.
Thepam_open_session(3PAM) function is called to open a new session after auser has been successfully authenticated.
Thepam_getenvlist(3PAM) function is called to establish a newenvironment.pam_getenvlist() returns a new environmentto be merged with the existing environment.
Thepam_eval(3PAM) function loads and evaluates a PAM configurationstored in a file specified by the caller. This function is called by thepam_user_policy(5) PAM module.