Add a new API function, openpam_subst(3), which replaces substitution
codes in a string with the values of selected PAM items. Use it for prompts. Furthermore, modify pam_get_user(3) and pam_get_authtok(3) to look for module options named {user,authtok,oldauthtok}_prompt, as appropriate. If found, these options take precedence over both the caller's prompt and the PAM_{USER,AUTHTOK,OLDAUTHTOK}_PROMPT items. The usefulness of these options is somewhat limited by the fact that the policy file parser does not support quoted strings; that's next on the todo list. git-svn-id: svn+ssh://svn.openpam.org/svn/openpam/trunk@455 185d5e19-27fe-0310-9dcf-9bff6b9f3609
This commit is contained in:
parent
8b88ff5959
commit
81b5c45be2
10
HISTORY
10
HISTORY
|
@ -2,6 +2,16 @@ OpenPAM Lycopsida 2011-??-??
|
|||
|
||||
- ENHANCE: removed static build autodetection, which didn't work anyway.
|
||||
Use an explicit, user-specified preprocessor variable instead.
|
||||
|
||||
- ENHANCE: cleaned up the documentation a bit.
|
||||
|
||||
- ENHANCE: added openpam_subst(3), allowing certain PAM items to be
|
||||
embedded in strings such as prompts. Apply it to the prompts used
|
||||
by pam_get_user(3) and pam_get_authtok(3).
|
||||
|
||||
- ENHANCE: add support for the user_prompt, authtok_prompt and
|
||||
oldauthtok_prompt module options, which override the prompts passed
|
||||
by the module to pam_set_user(3) and pam_get_authtok(3).
|
||||
============================================================================
|
||||
OpenPAM Hydrangea 2007-12-21
|
||||
|
||||
|
|
|
@ -44,6 +44,7 @@ OMAN = \
|
|||
openpam_readline.3 \
|
||||
openpam_restore_cred.3 \
|
||||
openpam_set_option.3 \
|
||||
openpam_subst.3 \
|
||||
openpam_ttyconv.3 \
|
||||
pam_error.3 \
|
||||
pam_get_authtok.3 \
|
||||
|
|
|
@ -59,6 +59,12 @@ openpam_borrow_cred(pam_handle_t *_pamh,
|
|||
const struct passwd *_pwd)
|
||||
OPENPAM_NONNULL((1,2));
|
||||
|
||||
int
|
||||
openpam_subst(const pam_handle_t *_pamh,
|
||||
char *_buf,
|
||||
size_t *_bufsize,
|
||||
const char *_template);
|
||||
|
||||
void
|
||||
openpam_free_data(pam_handle_t *_pamh,
|
||||
void *_data,
|
||||
|
|
|
@ -24,6 +24,7 @@ libpam_la_SOURCES = \
|
|||
openpam_restore_cred.c \
|
||||
openpam_set_option.c \
|
||||
openpam_static.c \
|
||||
openpam_subst.c \
|
||||
openpam_ttyconv.c \
|
||||
pam_acct_mgmt.c \
|
||||
pam_authenticate.c \
|
||||
|
|
|
@ -0,0 +1,168 @@
|
|||
/*-
|
||||
* Copyright (c) 2011 Dag-Erling Smørgrav
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer
|
||||
* in this position and unchanged.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include "config.h"
|
||||
#endif
|
||||
|
||||
#include <security/pam_appl.h>
|
||||
|
||||
#include "openpam_impl.h"
|
||||
|
||||
#define subst_char(ch) do { \
|
||||
int _ch = (ch); \
|
||||
if (buf && len < *bufsize) \
|
||||
*buf++ = _ch; \
|
||||
++len; \
|
||||
} while (0)
|
||||
|
||||
#define subst_string(s) do { \
|
||||
const char *_s = (s); \
|
||||
while (*_s) \
|
||||
subst_char(*_s++); \
|
||||
} while (0)
|
||||
|
||||
#define subst_item(i) do { \
|
||||
int _i = (i); \
|
||||
const void *_p; \
|
||||
ret = pam_get_item(pamh, _i, &_p); \
|
||||
if (ret == PAM_SUCCESS && _p != NULL) \
|
||||
subst_string(_p); \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* OpenPAM internal
|
||||
*
|
||||
* Substitute PAM item values in a string
|
||||
*/
|
||||
|
||||
int
|
||||
openpam_subst(const pam_handle_t *pamh,
|
||||
char *buf, size_t *bufsize, const char *template)
|
||||
{
|
||||
size_t len;
|
||||
int ret;
|
||||
|
||||
ENTERS(template);
|
||||
if (template == NULL)
|
||||
template = "(null)";
|
||||
|
||||
len = 1; /* initialize to 1 for terminating NUL */
|
||||
ret = PAM_SUCCESS;
|
||||
while (*template && ret == PAM_SUCCESS) {
|
||||
if (template[0] == '%') {
|
||||
++template;
|
||||
switch (*template) {
|
||||
case 's':
|
||||
subst_item(PAM_SERVICE);
|
||||
break;
|
||||
case 't':
|
||||
subst_item(PAM_TTY);
|
||||
break;
|
||||
case 'h':
|
||||
subst_item(PAM_HOST);
|
||||
break;
|
||||
case 'u':
|
||||
subst_item(PAM_USER);
|
||||
break;
|
||||
case 'H':
|
||||
subst_item(PAM_RHOST);
|
||||
break;
|
||||
case 'U':
|
||||
subst_item(PAM_RUSER);
|
||||
break;
|
||||
case '\0':
|
||||
subst_char('%');
|
||||
break;
|
||||
default:
|
||||
subst_char('%');
|
||||
subst_char(*template);
|
||||
}
|
||||
++template;
|
||||
} else {
|
||||
subst_char(*template++);
|
||||
}
|
||||
}
|
||||
if (buf)
|
||||
*buf = '\0';
|
||||
if (ret == PAM_SUCCESS) {
|
||||
if (len > *bufsize)
|
||||
ret = PAM_TRY_AGAIN;
|
||||
*bufsize = len;
|
||||
}
|
||||
RETURNC(ret);
|
||||
}
|
||||
|
||||
/*
|
||||
* Error codes:
|
||||
*
|
||||
* =pam_get_item
|
||||
* !PAM_SYMBOL_ERR
|
||||
* PAM_TRY_AGAIN
|
||||
*/
|
||||
|
||||
/**
|
||||
* The =openpam_subst function expands a string, substituting PAM item
|
||||
* values for all occurrences of specific substitution codes.
|
||||
* The =template argument points to the initial string.
|
||||
* The result is stored in the buffer pointed to by the =buf argument; the
|
||||
* =bufsize argument specifies the size of that buffer.
|
||||
* The actual size of the resulting string, including the terminating NUL
|
||||
* character, is stored in the location pointed to by the =bufsize
|
||||
* argument.
|
||||
*
|
||||
* If =buf is NULL, or if the buffer is too small to hold the expanded
|
||||
* string, =bufsize is updated to reflect the amount of space required to
|
||||
* hold the entire string, and =openpam_subst returns =PAM_TRY_AGAIN.
|
||||
*
|
||||
* If =openpam_subst fails for any other reason, the =bufsize argument is
|
||||
* untouched, but part of the buffer may still have been overwritten.
|
||||
*
|
||||
* Substitution codes are introduced by a percent character and correspond
|
||||
* to PAM items:
|
||||
*
|
||||
* %H:
|
||||
* Replaced by the current value of the =PAM_RHOST item.
|
||||
* %h:
|
||||
* Replaced by the current value of the =PAM_HOST item.
|
||||
* %s:
|
||||
* Replaced by the current value of the =PAM_SERVICE item.
|
||||
* %t:
|
||||
* Replaced by the current value of the =PAM_TTY item.
|
||||
* %U:
|
||||
* Replaced by the current value of the =PAM_RUSER item.
|
||||
* %u:
|
||||
* Replaced by the current value of the =PAM_USER item.
|
||||
*
|
||||
* >pam_get_authtok
|
||||
* >pam_get_item
|
||||
* >pam_get_user
|
||||
*
|
||||
* AUTHOR DES
|
||||
*/
|
|
@ -65,8 +65,10 @@ pam_get_authtok(pam_handle_t *pamh,
|
|||
const char **authtok,
|
||||
const char *prompt)
|
||||
{
|
||||
char prompt_buf[1024];
|
||||
size_t prompt_size;
|
||||
const void *oldauthtok, *prevauthtok, *promptp;
|
||||
const char *default_prompt;
|
||||
const char *prompt_option, *default_prompt;
|
||||
char *resp, *resp2;
|
||||
int pitem, r, style, twice;
|
||||
|
||||
|
@ -78,6 +80,7 @@ pam_get_authtok(pam_handle_t *pamh,
|
|||
switch (item) {
|
||||
case PAM_AUTHTOK:
|
||||
pitem = PAM_AUTHTOK_PROMPT;
|
||||
prompt_option = "authtok_prompt";
|
||||
default_prompt = authtok_prompt;
|
||||
r = pam_get_item(pamh, PAM_OLDAUTHTOK, &oldauthtok);
|
||||
if (r == PAM_SUCCESS && oldauthtok != NULL) {
|
||||
|
@ -87,6 +90,7 @@ pam_get_authtok(pam_handle_t *pamh,
|
|||
break;
|
||||
case PAM_OLDAUTHTOK:
|
||||
pitem = PAM_OLDAUTHTOK_PROMPT;
|
||||
prompt_option = "oldauthtok_prompt";
|
||||
default_prompt = oldauthtok_prompt;
|
||||
twice = 0;
|
||||
break;
|
||||
|
@ -103,13 +107,21 @@ pam_get_authtok(pam_handle_t *pamh,
|
|||
else if (openpam_get_option(pamh, "use_first_pass"))
|
||||
RETURNC(r == PAM_SUCCESS ? PAM_AUTH_ERR : r);
|
||||
}
|
||||
if (prompt == NULL) {
|
||||
r = pam_get_item(pamh, pitem, &promptp);
|
||||
if (r != PAM_SUCCESS || promptp == NULL)
|
||||
prompt = default_prompt;
|
||||
else
|
||||
/* pam policy overrides the module's choice */
|
||||
if ((promptp = openpam_get_option(pamh, prompt_option)) != NULL)
|
||||
prompt = promptp;
|
||||
/* no prompt provided, see if there is one tucked away somewhere */
|
||||
if (prompt == NULL)
|
||||
if (pam_get_item(pamh, pitem, &promptp) && promptp != NULL)
|
||||
prompt = promptp;
|
||||
}
|
||||
/* fall back to hardcoded default */
|
||||
if (prompt == NULL)
|
||||
prompt = default_prompt;
|
||||
/* expand */
|
||||
prompt_size = sizeof prompt_buf;
|
||||
r = openpam_subst(pamh, prompt_buf, &prompt_size, prompt);
|
||||
if (r == PAM_SUCCESS && prompt_size <= sizeof prompt_buf)
|
||||
prompt = prompt_buf;
|
||||
style = openpam_get_option(pamh, "echo_pass") ?
|
||||
PAM_PROMPT_ECHO_ON : PAM_PROMPT_ECHO_OFF;
|
||||
r = pam_prompt(pamh, style, &resp, "%s", prompt);
|
||||
|
@ -164,6 +176,13 @@ pam_get_authtok(pam_handle_t *pamh,
|
|||
* If it is =NULL, the =PAM_AUTHTOK_PROMPT or =PAM_OLDAUTHTOK_PROMPT item,
|
||||
* as appropriate, will be used.
|
||||
* If that item is also =NULL, a hardcoded default prompt will be used.
|
||||
* Either way, the prompt is expanded using =openpam_subst before it is
|
||||
* passed to the conversation function.
|
||||
*
|
||||
* If =pam_get_authtok is called from a module and the ;authtok_prompt /
|
||||
* ;oldauthtok_prompt option is set in the policy file, the value of that
|
||||
* option takes precedence over both the =prompt argument and the
|
||||
* =PAM_AUTHTOK_PROMPT / =PAM_OLDAUTHTOK_PROMPT item.
|
||||
*
|
||||
* If =item is set to =PAM_AUTHTOK and there is a non-null =PAM_OLDAUTHTOK
|
||||
* item, =pam_get_authtok will ask the user to confirm the new token by
|
||||
|
@ -172,4 +191,5 @@ pam_get_authtok(pam_handle_t *pamh,
|
|||
*
|
||||
* >pam_get_item
|
||||
* >pam_get_user
|
||||
* >openpam_subst
|
||||
*/
|
||||
|
|
|
@ -62,6 +62,8 @@ pam_get_user(pam_handle_t *pamh,
|
|||
const char **user,
|
||||
const char *prompt)
|
||||
{
|
||||
char prompt_buf[1024];
|
||||
size_t prompt_size;
|
||||
const void *promptp;
|
||||
char *resp;
|
||||
int r;
|
||||
|
@ -72,13 +74,22 @@ pam_get_user(pam_handle_t *pamh,
|
|||
r = pam_get_item(pamh, PAM_USER, (const void **)user);
|
||||
if (r == PAM_SUCCESS && *user != NULL)
|
||||
RETURNC(PAM_SUCCESS);
|
||||
if (prompt == NULL) {
|
||||
r = pam_get_item(pamh, PAM_USER_PROMPT, &promptp);
|
||||
if (r != PAM_SUCCESS || promptp == NULL)
|
||||
prompt = user_prompt;
|
||||
else
|
||||
/* pam policy overrides the module's choice */
|
||||
if ((promptp = openpam_get_option(pamh, "user_prompt")) != NULL)
|
||||
prompt = promptp;
|
||||
/* no prompt provided, see if there is one tucked away somewhere */
|
||||
if (prompt == NULL)
|
||||
if (pam_get_item(pamh, PAM_USER_PROMPT, &promptp) &&
|
||||
promptp != NULL)
|
||||
prompt = promptp;
|
||||
}
|
||||
/* fall back to hardcoded default */
|
||||
if (prompt == NULL)
|
||||
prompt = user_prompt;
|
||||
/* expand */
|
||||
prompt_size = sizeof prompt_buf;
|
||||
r = openpam_subst(pamh, prompt_buf, &prompt_size, prompt);
|
||||
if (r == PAM_SUCCESS && prompt_size <= sizeof prompt_buf)
|
||||
prompt = prompt_buf;
|
||||
r = pam_prompt(pamh, PAM_PROMPT_ECHO_ON, &resp, "%s", prompt);
|
||||
if (r != PAM_SUCCESS)
|
||||
RETURNC(r);
|
||||
|
@ -109,9 +120,16 @@ pam_get_user(pam_handle_t *pamh,
|
|||
*
|
||||
* The =prompt argument specifies a prompt to use if no user name is
|
||||
* cached.
|
||||
* If it is =NULL, the =PAM_USER_PROMPT will be used.
|
||||
* If it is =NULL, the =PAM_USER_PROMPT item will be used.
|
||||
* If that item is also =NULL, a hardcoded default prompt will be used.
|
||||
* Either way, the prompt is expanded using =openpam_subst before it is
|
||||
* passed to the conversation function.
|
||||
*
|
||||
* If =pam_get_user is called from a module and the ;user_prompt option is
|
||||
* set in the policy file, the value of that option takes precedence over
|
||||
* both the =prompt argument and the =PAM_USER_PROMPT item.
|
||||
*
|
||||
* >pam_get_item
|
||||
* >pam_get_authtok
|
||||
* >openpam_subst
|
||||
*/
|
||||
|
|
Loading…
Reference in New Issue