Oracle Solaris Security for Developers Guide

Sample PAM Provider Service Module

A sample PAM service module follows. This example checks to see if the user is a member of a group that is permitted access to this service. The provider then grants access on success or logs an error message on failure. The example goes through the following steps:

  1. Parse the options passed to this module from the configuration line in /etc/pam.conf.

    This module accepts the nowarn and debug options as well as a specific option group. With the group option, the module can be configured to allow access for a particular group other than the group root that is used by default. See the definition of DEFAULT_GROUP in the source code for the example. For example, to allow telnet(1) access by users that belong to group staff, one could use the following line, which is in the telnet stack in /etc/pam.conf:

    telnet  account  required group=staff
  2. Get the username, service name and hostname.

    The username is obtained by calling pam_get_user(3PAM) which retrieves the current user name from the PAM handle. If the user name has not been set, access is denied. The service name and the host name are obtained by calling pam_get_item(3PAM).

  3. Validate the information to be worked on.

    If the user name is not set, deny access. If the group to be worked on is not defined, deny access.

  4. Verify that the current user is a member of the special group that allows access to this host and grant access.

    In the event that the special group is defined but contains no members at all, PAM_IGNORE is returned to indicate that this module does not participate in any account validation process. The decision is left to other modules on the stack.

  5. If the user is not a member of the special group, display a message to inform the user that access is denied.

    Log a message to record this event.

The following example shows the source code for the sample PAM provider.

Note –

The source code for this example is also available through the Sun download center. See

Example 3–3 Sample PAM Service Module

 * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.

#include <stdio.h>
#include <stdlib.h>
#include <grp.h>
#include <string.h>
#include <syslog.h>
#include <libintl.h>
#include <security/pam_appl.h>

 * by default, only users who are a member of group "root" are allowed access
#define	DEFAULT_GROUP "root"

static char *NOMSG =
	"Sorry, you are not on the access list for this host - access denied.";

pam_sm_acct_mgmt(pam_handle_t * pamh, int flags, int argc, const char **argv)
	char *user = NULL;
	char *host = NULL;
	char *service = NULL;
	const char *allowed_grp = DEFAULT_GROUP;
	char grp_buf[4096];
	struct group grp;
	struct pam_conv *conversation;
	struct pam_message message;
	struct pam_message *pmessage = &message;
	struct pam_response *res = NULL;
	int i;
	int nowarn = 0;
	int debug = 0;

	/* Set flags to display warnings if in debug mode. */
	for (i = 0; i < argc; i++) {
		if (strcasecmp(argv[i], "nowarn") == 0)
			nowarn = 1;
		else if (strcasecmp(argv[i], "debug") == 0)
			debug = 1;
		else if (strncmp(argv[i], "group=", 6) == 0)
			allowed_grp = &argv[i][6];
	if (flags & PAM_SILENT)
		nowarn = 1;

	/* Get user name,service name, and host name. */
	(void) pam_get_user(pamh, &user, NULL);
	(void) pam_get_item(pamh, PAM_SERVICE, (void **) &service);
	(void) pam_get_item(pamh, PAM_RHOST, (void **) &host);

	/* Deny access if user is NULL. */
	if (user == NULL) {
		    "%s: members_only: user not set", service);
		return (PAM_USER_UNKNOWN);

	if (host == NULL)
		host = "unknown";

	 * Deny access if vuser group is required and user is not in vuser
	 * group
	if (getgrnam_r(allowed_grp, &grp, grp_buf, sizeof (grp_buf)) == NULL) {
		    "%s: members_only: group \"%s\" not defined",
		    service, allowed_grp);
		return (PAM_SYSTEM_ERR);

	/* Ignore this module if group contains no members. */
	if (grp.gr_mem[0] == 0) {
		if (debug)
			    "%s: members_only: group %s empty: "
			    "all users allowed.", service, grp.gr_name);
		return (PAM_IGNORE);

	/* Check to see if user is in group. If so, return SUCCESS. */
	for (; grp.gr_mem[0]; grp.gr_mem++) {
		if (strcmp(grp.gr_mem[0], user) == 0) {
			if (debug)
				    "%s: user %s is member of group %s. "
				    "Access allowed.",
				    service, user, grp.gr_name);
			return (PAM_SUCCESS);

	 * User is not a member of the group.
	 * Set message style to error and specify denial message.
	message.msg_style = PAM_ERROR_MSG;
	message.msg = gettext(NOMSG);

	/* Use conversation function to display denial message to user. */
	(void) pam_get_item(pamh, PAM_CONV, (void **) &conversation);
	if (nowarn == 0 && conversation != NULL) {
		int err;
		err = conversation->conv(1, &pmessage, &res,
		if (debug && err != PAM_SUCCESS)
			    "%s: members_only: conversation returned "
			    "error %d (%s).", service, err,
			    pam_strerror(pamh, err));

		/* free response (if any) */
		if (res != NULL) {
			if (res->resp)

	/* Report denial to system log and return error to caller. */
	syslog(LOG_NOTICE | LOG_AUTH, "%s: members_only: "
	    "Connection for %s not allowed from %s", service, user, host);

	return (PAM_PERM_DENIED);