以下是一个 PAM 服务模块样例。此示例将查看用户是否是允许访问此服务的组的成员。如果成功,则提供者随后将授予访问权限,如果失败则记录错误消息。该示例执行以下步骤:
解析从 /etc/pam.conf 中的配置行传递到此模块的标志。
此模块可接受 nowarn 和 debug 标志以及特定的标志 group。使用 group 标志可以配置模块,允许其访问除缺省使用的组 root 以外的特定组。有关示例,请参见源代码中 DEFAULT_GROUP 的定义。例如,要允许属于组 staff 的用户访问 telnet(1),用户可以使用以下行(位于 /etc/pam.conf 中的 telnet 栈中):
telnet account required pam_members_only.so.1 group=staff
获取用户名、服务名和主机名。
用户名通过调用 pam_get_user(3PAM)(用于从 PAM 句柄中检索当前用户名)获取。如果未设置用户名,则会拒绝访问。服务名和主机名通过调用 pam_get_item(3PAM) 获取。
验证要使用的信息。
如果未设置用户名,则拒绝访问。如果未定义要使用的组,则拒绝访问。
验证当前用户是否是允许访问此主机并且授予访问权限的特殊组的成员。
如果该特殊组已定义但根本不包含任何成员,则将返回 PAM_IGNORE,指明此模块不参与任何帐户验证过程。该决策将留给栈中的其他模块。
如果用户不是特殊组的成员,则会显示一条消息,通知用户访问被拒绝。
记录消息以记录此事件。
以下示例给出了 PAM 提供者样例的源代码。
此示例的源代码也可以通过 Sun 下载中心获得。请访问 http://www.sun.com/download/products.xml?id=41912db5
/*
* 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.";
int
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) {
syslog(LOG_AUTH|LOG_DEBUG,
"%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) {
syslog(LOG_NOTICE|LOG_AUTH,
"%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)
syslog(LOG_AUTH|LOG_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)
syslog(LOG_AUTH|LOG_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,
conversation->appdata_ptr);
if (debug && err != PAM_SUCCESS)
syslog(LOG_AUTH|LOG_DEBUG,
"%s: members_only: conversation returned "
"error %d (%s).", service, err,
pam_strerror(pamh, err));
/* free response (if any) */
if (res != NULL) {
if (res->resp)
free(res->resp);
free(res);
}
}
/* 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);
}