我试图通过添加提供的用户名将数据获取到通过 ssh 调用的进程中,例如
ssh user@smuggledata@host
我已经写了一个 PAM 模块,但是
- sshd 在调用 PAM 之前就已经确定该用户是坏用户
- 尽管我已经更改了 PAM_USER,但后续模块仍然根据提交的用户名进行身份验证。
我首先尝试使用auth requisite mymodule.so
和 中的代码运行代码pam_sm_authenticate()
。尽管代码被触发 - 但它不起作用:
May 1 22:40:30 animal sshd[3827]: Invalid user colin@example from 127.0.0.1
May 1 22:40:30 animal sshd[3827]: input_userauth_request: invalid user colin@example [preauth]
May 1 22:40:35 animal pam_pat[3827]: Retrieved username colin@example
May 1 22:40:35 animal pam_pat[3827]: checking char c against 3 dividers
May 1 22:40:35 animal pam_pat[3827]: checking char o against 3 dividers
May 1 22:40:35 animal pam_pat[3827]: checking char l against 3 dividers
May 1 22:40:35 animal pam_pat[3827]: checking char i against 3 dividers
May 1 22:40:35 animal pam_pat[3827]: checking char n against 3 dividers
May 1 22:40:35 animal pam_pat[3827]: checking char @ against 3 dividers
May 1 22:40:35 animal pam_pat[3827]: Found divider @
May 1 22:40:35 animal pam_pat[3827]: user=colin, data=example
May 1 22:40:35 animal sshd[3827]: pam_unix(sshd:auth): authentication failure; logname= uid=0 euid=0 tty=ssh ruser= rhost=127.0.0.1 user=colin
May 1 22:40:37 animal sshd[3827]: Failed password for invalid user colin@example from 127.0.0.1 port 43998 ssh2
May 1 22:41:28 animal sshd[3827]: Connection closed by 127.0.0.1 port 43998 [preauth]
请注意,当执行到达 pam_unix 时,身份验证失败,但用户将报告为 PAM_USER 中的转换值。密码是正确的,因此 pam_unix 可能未针对 PAM_USER 进行身份验证。
我还尝试了-account requisite mymodule.so
中的代码pam_sm_acct_mgmt()
,但代码没有被调用:
May 1 22:57:10 animal sshd[4105]: Invalid user colin@exmple from 127.0.0.1
May 1 22:57:10 animal sshd[4105]: input_userauth_request: invalid user colin@exmple [preauth]
May 1 22:57:16 animal sshd[4105]: pam_unix(sshd:auth): check pass; user unknown
May 1 22:57:16 animal sshd[4105]: pam_unix(sshd:auth): authentication failure; logname= uid=0 euid=0 tty=ssh ruser= rhost=127.0.0.1
May 1 22:57:18 animal sshd[4105]: Failed password for invalid user colin@exmple from 127.0.0.1 port 44118 ssh2
May 1 22:57:27 animal sshd[4105]: Connection closed by 127.0.0.1 port 44118 [preauth]
看着pam_unix 的源代码它检索的用户名pam_get_user()
显然指向 PAM_USER 以外的其他内容。
如何更改随后用于身份验证的用户值?
- 如何确保在对用户名进行任何其他处理之前发生这种情况?
- 有没有比写回 pam_get_user() 返回的指针更好的方法?
更新 代码(添加了 pam_get_user()):
char *submitted_name;
char work_bufr[PAT_BUFR];
char log_entry[PAT_BUFR];
int an_int;
char dividers[]="@%+";
int num_dividers;
char *cursor;
char divider_found[]="0";
const char *debug_user;
openlog("pam_pat", LOG_CONS | LOG_PID | LOG_NDELAY, LOG_AUTH);
/* retrieve a copy of the submitted username */
if (PAM_SUCCESS != pam_get_item(pamh, PAM_USER, (void *) &submitted_name) || !(submitted_name)) {
syslog (LOG_ERR, "Failed to retrieve username from pam");
closelog();
return(PAM_IGNORE);
}
syslog (LOG_ERR, "Retrieved username %s", submitted_name);
strncpy(work_bufr, submitted_name, PAT_BUFR);
submitted_name=work_bufr;
/* search for dividers and split string */
cursor=submitted_name;
an_int=PAT_BUFR;
num_dividers=(int)strlen(dividers);
while (--an_int && '\0'!=*cursor) {
syslog(LOG_ERR, "checking char %c against %d dividers", (int)*cursor, num_dividers);
for (int x=0; x<num_dividers; x++) {
if (*cursor==dividers[x]) {
syslog(LOG_ERR, "Found divider %c", *cursor);
an_int=0;
*divider_found=*cursor;
*cursor='\0';
if (PAM_SUCCESS==pam_set_item(pamh, PAM_USER, submitted_name)) {
++cursor;
syslog (LOG_ERR, "user=%s, data=%s",submitted_name,cursor);
setenv("PAM_PAT_DIVDR", divider_found, 1);
setenv("PAM_PAT_DATA", cursor, 1);
if (PAM_SUCCESS == pam_get_user(pamh, &debug_user, NULL)) {
syslog (LOG_ERR, "pam_get_user() found %s", debug_user);
}
closelog();
return(PAM_IGNORE);
} else {
syslog (LOG_ERR, "Failed to update username");
}
}
}
cursor++;
}
syslog (LOG_ERR, "Extended username not found.");
closelog();
return(PAM_IGNORE);
}
答案1
input_userauth_request() 是 sshd 中的一个函数,它提示输入用户名。
来回阅读有关pam_ldap(本地系统不一定知道正在验证的用户名)当未安装或未配置 LDAP NSS 库时,会弹出“sshd[xxx]: input_userauth_request: invalid user ...”消息。由此我推断 sshd 在移交给 PAM 之前首先尝试验证用户名(WTF?)。因此,为了避免这个初始错误,我需要编写一个 NSS 模块(大概实现 getpwnam() 但我希望我必须拆开 sshd 才能找出它是如何工作的)。
呃!
(而且我仍然不相信这会解决问题)
答案2
老线程,但我想整理一个完整的答案。
我有类似的需求,我几乎使用了这里提到的内容并将解决方案缝合在一起。
libnss-ato
- 这是必要的,以便仍然允许不存在的用户(我之前也使用过这个)我创建了一个简单的 PAM 模块(主要是返回的虚拟函数
PAM_SUCCESS
),但以下内容除外:
static char*
_find_base_user (const char *user)
{
char *p = NULL;
static char user_base[64] = {0};
if ((p = strchr(user, '@'))) {
memset(user_base, 0, 64);
strncpy(user_base, user, (int)(p - user));
return user_base;
}
return NULL;
}
int
pam_sm_authenticate (pam_handle_t *pamh,
int flags,
int argc,
const char **argv)
{
int ret = 0;
const char *user;
char *user_pfx = NULL;
ret = pam_get_user(pamh, &user, NULL);
if (ret != PAM_SUCCESS || user == NULL) {
pam_syslog(pamh, LOG_ERR, "no user specified");
} else {
pam_syslog(pamh, LOG_DEBUG, "user = %s", user);
}
user_pfx = _find_base_user(user);
if (user_pfx) {
pam_syslog(pamh, LOG_DEBUG, "user base name: %s", user_pfx);
} else {
pam_syslog(pamh, LOG_ERR, "no separator in user name found");
return PAM_SUCCESS;
}
ret = pam_set_item(pamh, PAM_USER, (const void *)user_pfx);
if (ret!= PAM_SUCCESS) {
pam_syslog(pamh, LOG_ERR, "user resetting failed");
return PAM_USER_UNKNOWN;
}
return PAM_SUCCESS;
}
让我们称之为这个pam_changeuser.so
,现在我将其添加到我的 PAM 堆栈的顶部(第一个模块)
auth required pam_changeuser.so
有了这个,我能够走私一些附加数据与用户名!
希望这对某人有帮助。
--
答案3
的手册页pam_get_user(3)
说它从 获得的用户那里获取其值pam_start(3)
。该函数反过来表示可以使用 来设置其结构中的元素pam_set_item(3)
。第三个函数的手册页提供了更改正在测试身份验证的用户名的明确参考。
该
pam_set_item
功能允许应用程序和PAM服务模块访问和更新item_type
.为此,创建 item 参数指向的对象的副本。支持以下 item_types [...]PAM_用户 将提供身份服务的实体的用户名。也就是说,在身份验证之后,PAM_USER 标识开始使用该服务的本地实体。请注意,该值可以通过 PAM 堆栈中的任何模块从某些内容(例如“anonymous”)映射到其他内容(例如“guest119”)。因此,应用程序应在每次调用 PAM 函数后查阅 PAM_USER 的值。