summaryrefslogtreecommitdiff
path: root/src/pam_radius_auth.c
diff options
context:
space:
mode:
authorDave Olson <olson@cumulusnetworks.com>2017-06-19 14:08:00 -0700
committerDave Olson <olson@cumulusnetworks.com>2017-06-20 18:29:11 -0700
commit61257dc81beebcf324027edb712305c376dd2052 (patch)
tree63d44b2d756e0a5bc68138e6f253c6c6fc295a28 /src/pam_radius_auth.c
parent3a47df99b207d85469d0a3126aacf491ba61c1d4 (diff)
downloadlibpam-radius-auth-61257dc81beebcf324027edb712305c376dd2052.tar.gz
libpam-radius-auth-61257dc81beebcf324027edb712305c376dd2052.zip
Add changes to allow VRF, and mapped users (no local accounts)
Add changes allow admins to set up RADIUS clients with no local knowledge of the RADIUS accounts (no adduser required, nor LDAP, etc.) This is done by using the nss-mapuser package. The only real change to this package is to set up the SUDO prompt, so it's the RADIUS login name, in the pam_sm_acct_mgmt entry point. Bumped the version to 1.4.1 Change the PACKAGE info in configure to reflect Cumulus, and also a few related fields. Changed maintiner to dev-support Also incorporated changes to make debuging builds easier under debian. Added comment and description of src_ip to the config file (author of the src_ip changes hadn't yet done that), and removed the location of config file from comments, since debian installs to a different location. Quieted config complaints; can't move to current because current is GPLv3, and this doesn't use autoconf. Tried to capture the 5 years of changes between 1.3.17 and 1.4.0 Added lintian overrides. Fixed up debian/copyright file to be standard format, and match (approximately) the source files. overrides don't quite work, because source vs binary confusion, but documents them Added debian install files Added man page for the plugin, and for the RADIUS client config file
Diffstat (limited to 'src/pam_radius_auth.c')
-rw-r--r--src/pam_radius_auth.c154
1 files changed, 111 insertions, 43 deletions
diff --git a/src/pam_radius_auth.c b/src/pam_radius_auth.c
index a9fd518..971dc01 100644
--- a/src/pam_radius_auth.c
+++ b/src/pam_radius_auth.c
@@ -525,13 +525,14 @@ static int initialize(radius_conf_t *conf, int accounting)
struct sockaddr_storage salocal6;
char hostname[BUFFER_SIZE];
char secret[BUFFER_SIZE];
+ char *vrfname = NULL;
char buffer[BUFFER_SIZE];
char *p;
FILE *fserver;
- radius_server_t *server = NULL;
+ radius_server_t *server = NULL, *tmp;
int timeout;
- int line = 0;
+ int line = 0, scancnt;
char src_ip[MAX_IP_LEN];
int seen_v6 = 0;
@@ -572,48 +573,73 @@ static int initialize(radius_conf_t *conf, int accounting)
break;
}
- timeout = 3;
- src_ip[0] = 0;
- if (sscanf(p, "%s %s %d %s", hostname, secret, &timeout, src_ip) < 2) {
- _pam_log(LOG_ERR, "ERROR reading %s, line %d: Could not read hostname or secret\n",
- conf->conf_file, line);
- continue; /* invalid line */
- } else { /* read it in and save the data */
- radius_server_t *tmp;
-
- tmp = malloc(sizeof(radius_server_t));
- if (server) {
- server->next = tmp;
- server = server->next;
- } else {
- conf->server = tmp;
- server= tmp; /* first time */
- }
+ scancnt = sscanf(p, "%s %s %d %s", hostname, secret, &timeout, src_ip);
- /* sometime later do memory checks here */
- server->hostname = strdup(hostname);
- server->secret = strdup(secret);
- server->accounting = accounting;
+ /* is it the name of a vrf we should bind to? */
+ if (!strcmp(hostname, "vrf-name")) {
+ if (scancnt < 2)
+ _pam_log(LOG_ERR, "ERROR reading %s, line %d: only %d fields\n",
+ conf->conf_file, line, scancnt);
+ else
+ vrfname = strdup(secret);
+ continue;
+ }
- if ((timeout < 1) || (timeout > 60)) {
- server->timeout = 3;
- } else {
- server->timeout = timeout;
- }
- server->next = NULL;
+ /* allow setting debug in config file as well */
+ if (!strcmp(hostname, "debug")) {
+ if (scancnt < 1)
+ _pam_log(LOG_ERR, "ERROR reading %s, line %d: only %d fields\n",
+ conf->conf_file, line, scancnt);
+ else
+ conf->debug = 1;
+ continue;
+ }
- if (src_ip[0]) {
- memset(&salocal, 0, sizeof(salocal));
- get_ipaddr(src_ip, (struct sockaddr *)&salocal, NULL);
- switch (salocal.ss_family) {
- case AF_INET:
- memcpy(&salocal4, &salocal, sizeof(salocal));
- break;
- case AF_INET6:
- seen_v6 = 1;
- memcpy(&salocal6, &salocal, sizeof(salocal));
- break;
- }
+ if (scancnt < 2) {
+ _pam_log(LOG_ERR, "ERROR reading %s, line %d: only %d fields\n",
+ conf->conf_file, line, scancnt);
+ continue; /* invalid line */
+ }
+ if (scancnt < 4) {
+ src_ip[0] = 0;
+ if (scancnt < 3)
+ timeout = 3; /* default timeout */
+ }
+
+ /* read it in and save the data */
+ tmp = malloc(sizeof(radius_server_t));
+ if (server) {
+ server->next = tmp;
+ server = server->next;
+ } else {
+ conf->server = tmp;
+ server= tmp; /* first time */
+ }
+
+ /* sometime later do memory checks here */
+ server->hostname = strdup(hostname);
+ server->secret = strdup(secret);
+ server->accounting = accounting;
+
+ memset(&server->ip, 0, sizeof server->ip);
+ if ((timeout < 1) || (timeout > 60)) {
+ server->timeout = 3;
+ } else {
+ server->timeout = timeout;
+ }
+ server->next = NULL;
+
+ if (src_ip[0]) {
+ memset(&salocal, 0, sizeof(salocal));
+ get_ipaddr(src_ip, (struct sockaddr *)&salocal, NULL);
+ switch (salocal.ss_family) {
+ case AF_INET:
+ memcpy(&salocal4, &salocal, sizeof(salocal));
+ break;
+ case AF_INET6:
+ seen_v6 = 1;
+ memcpy(&salocal6, &salocal, sizeof(salocal));
+ break;
}
}
}
@@ -639,6 +665,17 @@ static int initialize(radius_conf_t *conf, int accounting)
return PAM_AUTHINFO_UNAVAIL;
}
+ if (vrfname) {
+ /* do not fail if the bind fails, connection may succeed */
+ if (setsockopt(conf->sockfd, SOL_SOCKET, SO_BINDTODEVICE,
+ vrfname, strlen(vrfname)+1) < 0)
+ _pam_log(LOG_WARNING, "Binding socket to VRF %s failed: %m",
+ vrfname);
+ else if(conf->debug)
+ _pam_log(LOG_DEBUG, "Configured vrf as: %s", vrfname);
+ free(vrfname);
+ }
+
#ifndef HAVE_POLL_H
if (conf->sockfd >= FD_SETSIZE) {
_pam_log(LOG_ERR, "Unusable socket, FD is larger than %d\n", FD_SETSIZE);
@@ -1642,8 +1679,39 @@ PAM_EXTERN int pam_sm_chauthtok(pam_handle_t *pamh, int flags, int argc, CONST c
*/
PAM_EXTERN int pam_sm_acct_mgmt(pam_handle_t *pamh,int flags,int argc,CONST char **argv)
{
- int retval;
- retval = PAM_SUCCESS;
+ int retval = PAM_SUCCESS;
+ CONST char *user;
+ radius_conf_t config;
+
+ (void) _pam_parse(argc, argv, &config);
+
+ /* grab the user name */
+ retval = pam_get_user(pamh, &user, NULL);
+ if (retval != PAM_SUCCESS || user == NULL || strlen(user) > MAXPWNAM) {
+ return PAM_USER_UNKNOWN;
+ }
+
+ /*
+ * parse the config file. We don't make any connections here, so ignore
+ * any failures. For consistency only.
+ */
+ retval = initialize(&config, FALSE);
+
+ /*
+ * 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 */
+ snprintf(nprompt, sizeof nprompt,
+ "SUDO_PROMPT=[sudo] password for %s: ", user);
+ if (pam_putenv(pamh, nprompt) != PAM_SUCCESS)
+ _pam_log(LOG_NOTICE, "failed to set PAM sudo prompt "
+ "(%s)", nprompt);
+ }
+
return retval;
}