summaryrefslogtreecommitdiff
path: root/src/pam_radius_auth.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/pam_radius_auth.c')
-rw-r--r--src/pam_radius_auth.c84
1 files changed, 65 insertions, 19 deletions
diff --git a/src/pam_radius_auth.c b/src/pam_radius_auth.c
index c4274fa..7f29f37 100644
--- a/src/pam_radius_auth.c
+++ b/src/pam_radius_auth.c
@@ -203,10 +203,11 @@ static int get_ipaddr(char *host, struct sockaddr *addr, char *port)
}
/*
- * take server->hostname, and convert it to server->ip
+ * Lookup server->hostname, to get server->ip
* Done once when server list parsed. The last part, the
* if port isn't set in config, it needs to be set to either
* radius or raddacct
+ * returns 0 on success, otherwise non-zero
*/
static int host2server(pam_handle_t * pamh, radius_server_t * server)
{
@@ -216,7 +217,7 @@ static int host2server(pam_handle_t * pamh, radius_server_t * server)
/* hostname might be [ipv6::address] */
strncpy(hostbuffer, server->hostname, sizeof(hostbuffer) - 1);
- hostbuffer[sizeof(hostbuffer) - 1] = 0;
+ hostbuffer[sizeof(hostbuffer) - 1] = 0; /* ensure null term */
hostname = hostbuffer;
portstart = hostbuffer;
if (hostname[0] == '[') {
@@ -653,7 +654,7 @@ static void cleanup_conf(pam_handle_t * pamh, void *arg, int unused)
static int parse_conffile(pam_handle_t * pamh, radius_conf_t * cf)
{
static struct stat last_st;
- int line = 0, timeout;
+ int line = 0, timeout, ret = 0;
const char *cfname = cf->conf_file;
char *p;
radius_server_t *server = NULL, *tmp;
@@ -661,8 +662,10 @@ static int parse_conffile(pam_handle_t * pamh, radius_conf_t * cf)
char hostname[BUFFER_SIZE], secret[BUFFER_SIZE], buffer[BUFFER_SIZE];
char srcip[BUFFER_SIZE];
- if (!cfname || !*cfname)
- return -1;
+ if (!cfname || !*cfname) {
+ ret = -1;
+ goto done;
+ }
if (last_st.st_ino) {
struct stat st;
@@ -670,18 +673,22 @@ static int parse_conffile(pam_handle_t * pamh, radius_conf_t * cf)
rst = stat(cfname, &st);
if (!rst && st.st_ino == last_st.st_ino && st.st_mtime ==
last_st.st_mtime && st.st_ctime == last_st.st_ctime) {
+ /* no changes to savconf, so just return */
return 1;
}
}
- if (cf->server) /* we already had sockets open and bound, cleanup */
+ if (cf->server) { /* we already had sockets open and bound, cleanup */
pam_set_data(pamh, "rad_conf_cleanup", NULL, NULL);
+ cf->server = NULL; /* in case reuse and no servers found */
+ }
/* the first time around, read the configuration file */
if ((fserver = fopen(cfname, "r")) == (FILE *) NULL) {
_pam_log(pamh, LOG_ERR, "Could not open configuration file %s:"
" %m", cfname);
- return -1;
+ ret = -1;
+ goto done;
}
while (!feof(fserver) &&
@@ -746,6 +753,20 @@ static int parse_conffile(pam_handle_t * pamh, radius_conf_t * cf)
}
}
continue;
+ } else if (!strcmp(hostname, "mapped_priv_user")) {
+ /* mapped account name of radius privileged user for
+ * uid/auid fixup */
+ if (scancnt < 2)
+ _pam_log(pamh, LOG_ERR,
+ "ERROR reading %s, line %d:"
+ " only %d fields", cf->conf_file, line,
+ scancnt);
+ else
+ snprintf(cf->privusrmap, sizeof cf->privusrmap, "%s",
+ secret);
+ snprintf(savconf.privusrmap, sizeof savconf.privusrmap,
+ "%s", secret);
+ continue;
} else if (!strcmp(hostname, "debug")) {
/* allow setting debug in config file as well */
cf->debug = cfg_debug = 1;
@@ -766,7 +787,8 @@ static int parse_conffile(pam_handle_t * pamh, radius_conf_t * cf)
_pam_log(pamh, LOG_ERR,
"Unable to allocate server info for %s: %m",
hostname);
- return -1;
+ ret = -1;
+ goto done;
}
tmp->sockfd = -1; /* mark as uninitialized */
if (server) {
@@ -804,17 +826,18 @@ static int parse_conffile(pam_handle_t * pamh, radius_conf_t * cf)
if (!cf->server) { /* no server found, die a horrible death */
_pam_log(pamh, LOG_ERR, "No server found in"
" configuration file %s", cf->conf_file);
- return -1;
+ ret = -1;
}
/*
* save the server in savconf for next call (if any) to _parse_args()
* for the same config file (will be overridden if a different config
- * file
+ * file; need to do that even if NULL, so we don't re-use old bad data
*/
+done:
savconf.server = cf->server;
- return 0;
+ return ret;
}
static int setup_sock(pam_handle_t * pamh, radius_server_t * server,
@@ -1178,7 +1201,7 @@ static int talk_radius(radius_conf_t * conf, AUTH_HDR * request,
* If the user says he wants the bug,
* give in.
*/
- } else { /* authentication request */
+ } else { /* authentication request */
if (conf->accounting_bug) {
p = "";
}
@@ -1318,21 +1341,23 @@ static int rad_converse(pam_handle_t * pamh, int msg_style, char *message,
/*
* We'll create the home directory if needed, and we'll write the flat file
* mapping entry. It's done at this point, because this is the end of the
- * authentication phase (and authorization, too, since authorization is part of
- * authentication phase for RADIUS) for ssh, login, etc.
+ * authentication phase (and authorization, too, since authorization is
+ * part of * authentication phase for RADIUS) for ssh, login, etc.
*/
static void
-setup_userinfo(pam_handle_t * pamh, const char *user, int debug, int privileged)
+setup_userinfo(pam_handle_t * pamh, radius_conf_t *cfg, const char *user,
+ int debug, int privileged)
{
struct passwd *pw;
/*
- * set SUDO_PROMPT in env so that it prompts as the login user, not the mapped
- * user, unless (unlikely) the prompt has already been set.
+ * set SUDO_PROMPT in env so that it prompts as the login user, not the
+ * mapped * user, unless (unlikely) the prompt has already been set.
* It won't hurt to do this if the user wasn't mapped.
*/
if (!pam_getenv(pamh, "SUDO_PROMPT")) {
- char nprompt[strlen("SUDO_PROMPT=[sudo] password for ") + strlen(user) + 3]; /* + 3 for ": " and the \0 */
+ char nprompt[strlen("SUDO_PROMPT=[sudo] password for ") +
+ strlen(user) + 3]; /* + 3 for ": " and the \0 */
snprintf(nprompt, sizeof nprompt,
"SUDO_PROMPT=[sudo] password for %s: ", user);
if (pam_putenv(pamh, nprompt) != PAM_SUCCESS)
@@ -1349,6 +1374,27 @@ setup_userinfo(pam_handle_t * pamh, const char *user, int debug, int privileged)
}
/*
+ * because the RADIUS protocol is single pass, we always have the
+ * pw_uid of the unprivileged account at this point. Set things up
+ * so we use the uid of the privileged radius account.
+ */
+ if (privileged) {
+ struct passwd *pwp;
+ if (!cfg->privusrmap[0] || !(pwp = getpwnam(cfg->privusrmap))) {
+ _pam_log(pamh, LOG_WARNING, "Failed to find uid for"
+ " privileged account %s, uid may be wrong"
+ " for user %s",
+ cfg->privusrmap[0] ? cfg->privusrmap :
+ "(unset in config)", user);
+ }
+ else if (pwp && pw->pw_uid != pwp->pw_uid) {
+ syslog(LOG_DEBUG, "OLSON wrmap user=%s, but uid=%u, change to %u",
+ user, pw->pw_uid, pwp->pw_uid);
+ pw->pw_uid = pwp->pw_uid;
+ }
+ }
+
+ /*
* We don't "fail" on errors here, since they are not fatal for
* the session, although they can result in name or uid lookups not
* working correctly.
@@ -1601,7 +1647,7 @@ PAM_EXTERN int pam_sm_authenticate(pam_handle_t * pamh, int flags, int argc,
"=%d, min for priv=%d", privlvl,
config.min_priv_lvl);
}
- setup_userinfo(pamh, user, debug,
+ setup_userinfo(pamh, &config, user, debug,
privlvl >= config.min_priv_lvl);
retval = PAM_SUCCESS;
} else {