summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorjeroennijhof <jeroen@jeroennijhof.nl>2014-04-22 14:23:16 +0200
committerjeroennijhof <jeroen@jeroennijhof.nl>2014-04-22 14:23:16 +0200
commite02d06d7b03a3c493c29c164620a3a2a03e55e27 (patch)
treed14879e08239b9d94b0b8834b756bb32f32b5df6
parentf5d56737dbd42abf45eac5f61152deb08a12d417 (diff)
parentcd79e4d89b8abfe399cddac9e8f53c7602efce77 (diff)
downloadpam_tacplus-e02d06d7b03a3c493c29c164620a3a2a03e55e27.tar.gz
pam_tacplus-e02d06d7b03a3c493c29c164620a3a2a03e55e27.zip
Merge pull request #8 from walterdejong/master
Thanks guys! But the pam_sm_authenticate() function was indeed looping over the tac_plus servers for authentication. The problem is when a tac_plus server is not working correctly you will be denied during authentication but I agree we need to find a better solution for that issue.
-rw-r--r--INSTALL5
-rw-r--r--pam_tacplus.c348
2 files changed, 190 insertions, 163 deletions
diff --git a/INSTALL b/INSTALL
index 007e939..3058c27 100644
--- a/INSTALL
+++ b/INSTALL
@@ -11,6 +11,11 @@ without warranty of any kind.
Basic Installation
==================
+$ aclocal
+$ autoconf
+$ autoheader
+$ libtoolize
+$ automake --add-missing
Briefly, the shell commands `./configure; make; make install' should
configure, build, and install this package. The following
diff --git a/pam_tacplus.c b/pam_tacplus.c
index 4dff634..3c8074f 100644
--- a/pam_tacplus.c
+++ b/pam_tacplus.c
@@ -1,5 +1,5 @@
/* pam_tacplus.c - PAM interface for TACACS+ protocol.
- *
+ *
* Copyright (C) 2010, Pawel Krawczyk <pawel.krawczyk@hush.com> and
* Jeroen Nijhof <jeroen@jeroennijhof.nl>
*
@@ -77,20 +77,20 @@ int _pam_send_account(int tac_fd, int type, const char *user, char *tty,
/* this is no longer needed */
tac_free_attrib(&attr);
-
+
if(retval < 0) {
_pam_log (LOG_WARNING, "%s: send %s accounting failed (task %hu)",
- __FUNCTION__,
+ __FUNCTION__,
tac_acct_flag2str(type),
task_id);
close(tac_fd);
return -1;
}
-
+
struct areply re;
if( tac_acct_read(tac_fd, &re) != TAC_PLUS_ACCT_STATUS_SUCCESS ) {
_pam_log (LOG_WARNING, "%s: accounting %s failed (task %hu)",
- __FUNCTION__,
+ __FUNCTION__,
tac_acct_flag2str(type),
task_id);
@@ -118,24 +118,25 @@ int _pam_account(pam_handle_t *pamh, int argc, const char **argv,
char *r_addr = NULL;
char *typemsg;
int status = PAM_SESSION_ERR;
-
+ int srv_i, tac_fd;
+
typemsg = tac_acct_flag2str(type);
ctrl = _pam_parse (argc, argv);
- if (ctrl & PAM_TAC_DEBUG)
- syslog (LOG_DEBUG, "%s: [%s] called (pam_tacplus v%u.%u.%u)"
- , __FUNCTION__, typemsg, PAM_TAC_VMAJ, PAM_TAC_VMIN, PAM_TAC_VPAT);
- if (ctrl & PAM_TAC_DEBUG)
+ if (ctrl & PAM_TAC_DEBUG) {
+ syslog (LOG_DEBUG, "%s: [%s] called (pam_tacplus v%u.%u.%u)",
+ __FUNCTION__, typemsg, PAM_TAC_VMAJ, PAM_TAC_VMIN, PAM_TAC_VPAT);
syslog(LOG_DEBUG, "%s: tac_srv_no=%d", __FUNCTION__, tac_srv_no);
-
+ }
+
if ((user = _pam_get_user(pamh)) == NULL)
return PAM_USER_UNKNOWN;
if (ctrl & PAM_TAC_DEBUG)
syslog(LOG_DEBUG, "%s: username [%s] obtained", __FUNCTION__, user);
-
+
tty = _pam_get_terminal(pamh);
- if(!strncmp(tty, "/dev/", 5))
+ if(!strncmp(tty, "/dev/", 5))
tty += 5;
if (ctrl & PAM_TAC_DEBUG)
syslog(LOG_DEBUG, "%s: tty [%s] obtained", __FUNCTION__, tty);
@@ -166,92 +167,50 @@ int _pam_account(pam_handle_t *pamh, int argc, const char **argv,
signal(SIGHUP, SIG_IGN);
}
- if(!(ctrl & PAM_TAC_ACCT)) {
- /* normal mode, send packet to the first available server */
- int srv_i = 0;
-
- status = PAM_SESSION_ERR;
- while ((status == PAM_SESSION_ERR) && (srv_i < tac_srv_no)) {
- int tac_fd;
-
- tac_fd = tac_connect_single(tac_srv[srv_i].addr, tac_srv[srv_i].key);
- if(tac_fd < 0) {
- _pam_log(LOG_WARNING, "%s: error sending %s (fd)",
- __FUNCTION__, typemsg);
- srv_i++;
- continue;
- }
+ status = PAM_SESSION_ERR;
+ for(srv_i = 0; srv_i < tac_srv_no; srv_i++) {
+ tac_fd = tac_connect_single(tac_srv[srv_i].addr, tac_srv[srv_i].key);
+ if (tac_fd < 0) {
+ _pam_log(LOG_WARNING, "%s: error sending %s (fd)",
+ __FUNCTION__, typemsg);
+ continue;
+ }
+ if (ctrl & PAM_TAC_DEBUG)
+ syslog(LOG_DEBUG, "%s: connected with fd=%d (srv %d)", __FUNCTION__, tac_fd, srv_i);
+ retval = _pam_send_account(tac_fd, type, user, tty, r_addr, cmd);
+ if (retval < 0) {
+ _pam_log(LOG_WARNING, "%s: error sending %s (acct)",
+ __FUNCTION__, typemsg);
+ } else {
+ status = PAM_SUCCESS;
if (ctrl & PAM_TAC_DEBUG)
- syslog(LOG_DEBUG, "%s: connected with fd=%d (srv %d)", __FUNCTION__, tac_fd, srv_i);
-
- retval = _pam_send_account(tac_fd, type, user, tty, r_addr, cmd);
- /* return code from function in this mode is
- status of the last server we tried to send
- packet to */
- if(retval < 0) {
- _pam_log(LOG_WARNING, "%s: error sending %s (acct)",
- __FUNCTION__, typemsg);
- } else {
- status = PAM_SUCCESS;
- if (ctrl & PAM_TAC_DEBUG)
- syslog(LOG_DEBUG, "%s: [%s] for [%s] sent",
- __FUNCTION__, typemsg,user);
- }
- close(tac_fd);
- srv_i++;
+ syslog(LOG_DEBUG, "%s: [%s] for [%s] sent", __FUNCTION__, typemsg, user);
}
- } else {
- /* send packet to all servers specified */
- int srv_i;
-
- status = PAM_SESSION_ERR;
- for(srv_i = 0; srv_i < tac_srv_no; srv_i++) {
- int tac_fd;
-
- tac_fd = tac_connect_single(tac_srv[srv_i].addr, tac_srv[srv_i].key);
- if(tac_fd < 0) {
- _pam_log(LOG_WARNING, "%s: error sending %s (fd)",
- __FUNCTION__, typemsg);
- continue;
- }
+ close(tac_fd);
- if (ctrl & PAM_TAC_DEBUG)
- syslog(LOG_DEBUG, "%s: connected with fd=%d (srv %d)", __FUNCTION__, tac_fd, srv_i);
-
- retval = _pam_send_account(tac_fd, type, user, tty, r_addr, cmd);
- /* return code from function in this mode is
- status of the last server we tried to send
- packet to */
- if(retval < 0) {
- _pam_log(LOG_WARNING, "%s: error sending %s (acct)",
- __FUNCTION__, typemsg);
- } else {
- status = PAM_SUCCESS;
- if (ctrl & PAM_TAC_DEBUG)
- syslog(LOG_DEBUG, "%s: [%s] for [%s] sent",
- __FUNCTION__, typemsg,user);
- }
- close(tac_fd);
+ if ((status == PAM_SUCCESS) && !(ctrl & PAM_TAC_ACCT)) {
+ /* do not send acct start/stop packets to _all_ servers */
+ break;
}
- } /* acct mode */
+ }
- if(type == TAC_PLUS_ACCT_FLAG_STOP) {
+ if (type == TAC_PLUS_ACCT_FLAG_STOP) {
signal(SIGALRM, SIG_DFL);
signal(SIGCHLD, SIG_DFL);
signal(SIGHUP, SIG_DFL);
}
return status;
-}
+}
/* Main PAM functions */
/* authenticates user on remote TACACS+ server
* returns PAM_SUCCESS if the supplied username and password
- * pair is valid
+ * pair is valid
*/
-PAM_EXTERN
+PAM_EXTERN
int pam_sm_authenticate (pam_handle_t * pamh, int flags,
int argc, const char **argv) {
@@ -261,119 +220,182 @@ int pam_sm_authenticate (pam_handle_t * pamh, int flags,
char *tty;
char *r_addr;
int srv_i;
- int tac_fd;
- int status = PAM_AUTH_ERR;
+ int tac_fd, status, msg, communicating;
user = pass = tty = r_addr = NULL;
- ctrl = _pam_parse (argc, argv);
+ ctrl = _pam_parse(argc, argv);
if (ctrl & PAM_TAC_DEBUG)
- syslog (LOG_DEBUG, "%s: called (pam_tacplus v%u.%u.%u)"
- , __FUNCTION__, PAM_TAC_VMAJ, PAM_TAC_VMIN, PAM_TAC_VPAT);
+ syslog(LOG_DEBUG, "%s: called (pam_tacplus v%u.%u.%u)",
+ __FUNCTION__, PAM_TAC_VMAJ, PAM_TAC_VMIN, PAM_TAC_VPAT);
if ((user = _pam_get_user(pamh)) == NULL)
return PAM_USER_UNKNOWN;
if (ctrl & PAM_TAC_DEBUG)
- syslog (LOG_DEBUG, "%s: user [%s] obtained", __FUNCTION__, user);
-
+ syslog(LOG_DEBUG, "%s: user [%s] obtained", __FUNCTION__, user);
+
/* uwzgledniac PAM_DISALLOW_NULL_AUTHTOK */
retval = tacacs_get_password (pamh, flags, ctrl, &pass);
if (retval != PAM_SUCCESS || pass == NULL || *pass == '\0') {
- _pam_log (LOG_ERR, "unable to obtain password");
+ _pam_log(LOG_ERR, "unable to obtain password");
return PAM_CRED_INSUFFICIENT;
}
retval = pam_set_item (pamh, PAM_AUTHTOK, pass);
if (retval != PAM_SUCCESS) {
- _pam_log (LOG_ERR, "unable to set password");
+ _pam_log(LOG_ERR, "unable to set password");
return PAM_CRED_INSUFFICIENT;
}
if (ctrl & PAM_TAC_DEBUG)
- syslog (LOG_DEBUG, "%s: password obtained", __FUNCTION__);
+ syslog(LOG_DEBUG, "%s: password obtained", __FUNCTION__);
tty = _pam_get_terminal(pamh);
- if (!strncmp (tty, "/dev/", 5))
+ if (!strncmp(tty, "/dev/", 5))
tty += 5;
if (ctrl & PAM_TAC_DEBUG)
- syslog (LOG_DEBUG, "%s: tty [%s] obtained", __FUNCTION__, tty);
+ syslog(LOG_DEBUG, "%s: tty [%s] obtained", __FUNCTION__, tty);
r_addr = _pam_get_rhost(pamh);
if (ctrl & PAM_TAC_DEBUG)
- syslog (LOG_DEBUG, "%s: rhost [%s] obtained", __FUNCTION__, r_addr);
+ syslog(LOG_DEBUG, "%s: rhost [%s] obtained", __FUNCTION__, r_addr);
+ status = PAM_AUTHINFO_UNAVAIL;
for (srv_i = 0; srv_i < tac_srv_no; srv_i++) {
- int msg = TAC_PLUS_AUTHEN_STATUS_FAIL;
if (ctrl & PAM_TAC_DEBUG)
- syslog (LOG_DEBUG, "%s: trying srv %d", __FUNCTION__, srv_i );
+ syslog(LOG_DEBUG, "%s: trying srv %d", __FUNCTION__, srv_i );
tac_fd = tac_connect_single(tac_srv[srv_i].addr, tac_srv[srv_i].key);
if (tac_fd < 0) {
- _pam_log (LOG_ERR, "connection failed srv %d: %m", srv_i);
- if (srv_i == tac_srv_no-1) {
- _pam_log (LOG_ERR, "no more servers to connect");
- return PAM_AUTHINFO_UNAVAIL;
- }
+ _pam_log(LOG_ERR, "connection failed srv %d: %m", srv_i);
continue;
}
-
if (tac_authen_send(tac_fd, user, pass, tty, r_addr) < 0) {
- _pam_log (LOG_ERR, "error sending auth req to TACACS+ server");
- status = PAM_AUTHINFO_UNAVAIL;
- } else {
+ close(tac_fd);
+ _pam_log(LOG_ERR, "error sending auth req to TACACS+ server");
+ continue;
+ }
+ communicating = 1;
+ while (communicating) {
msg = tac_authen_read(tac_fd);
- if (msg == TAC_PLUS_AUTHEN_STATUS_GETPASS) {
- if (ctrl & PAM_TAC_DEBUG)
- syslog (LOG_DEBUG, "%s: tac_cont_send called", __FUNCTION__);
- if (tac_cont_send(tac_fd, pass) < 0) {
- _pam_log (LOG_ERR, "error sending continue req to TACACS+ server");
- status = PAM_AUTHINFO_UNAVAIL;
- } else {
- msg = tac_authen_read(tac_fd);
- if (msg != TAC_PLUS_AUTHEN_STATUS_PASS) {
- _pam_log (LOG_ERR, "auth failed: %d", msg);
- status = PAM_AUTH_ERR;
- } else {
- /* OK, we got authenticated; save the server that
- accepted us for pam_sm_acct_mgmt and exit the loop */
- status = PAM_SUCCESS;
- active_server.addr = tac_srv[srv_i].addr;
- active_server.key = tac_srv[srv_i].key;
- close(tac_fd);
+ /* talk the protocol */
+ switch (msg) {
+ case TAC_PLUS_AUTHEN_STATUS_PASS:
+ /* success */
+ if (ctrl & PAM_TAC_DEBUG)
+ syslog(LOG_DEBUG, "tacacs status: TAC_PLUS_AUTHEN_STATUS_PASS");
+
+ status = PAM_SUCCESS;
+ communicating = 0;
+ active_server.addr = tac_srv[srv_i].addr;
+ active_server.key = tac_srv[srv_i].key;
+
+ if (ctrl & PAM_TAC_DEBUG)
+ syslog(LOG_DEBUG, "%s: active srv %d", __FUNCTION__, srv_i);
+ break;
+
+ case TAC_PLUS_AUTHEN_STATUS_FAIL:
+ /* forget it */
+ if (ctrl & PAM_TAC_DEBUG)
+ syslog(LOG_DEBUG, "tacacs status: TAC_PLUS_AUTHEN_STATUS_FAIL");
+
+ status = PAM_AUTH_ERR;
+ communicating = 0;
+ _pam_log(LOG_ERR, "auth failed: %d", msg);
+ break;
+
+ case TAC_PLUS_AUTHEN_STATUS_GETDATA:
+ /* not implemented */
+ if (ctrl & PAM_TAC_DEBUG)
+ syslog(LOG_DEBUG, "tacacs status: TAC_PLUS_AUTHEN_STATUS_GETDATA");
+
+ communicating = 0;
+ break;
+
+ case TAC_PLUS_AUTHEN_STATUS_GETUSER:
+ /* not implemented */
+ if (ctrl & PAM_TAC_DEBUG)
+ syslog(LOG_DEBUG, "tacacs status: TAC_PLUS_AUTHEN_STATUS_GETUSER");
+
+ communicating = 0;
+ break;
+
+ case TAC_PLUS_AUTHEN_STATUS_GETPASS:
+ if (ctrl & PAM_TAC_DEBUG)
+ syslog(LOG_DEBUG, "tacacs status: TAC_PLUS_AUTHEN_STATUS_GETPASS");
+
+ if (ctrl & PAM_TAC_DEBUG)
+ syslog(LOG_DEBUG, "%s: tac_cont_send called", __FUNCTION__);
+
+ if (tac_cont_send(tac_fd, pass) < 0) {
+ _pam_log (LOG_ERR, "error sending continue req to TACACS+ server");
+ communicating = 0;
+ break;
+ }
+ /* continue the while loop; go read tac response */
+ break;
+
+ case TAC_PLUS_AUTHEN_STATUS_RESTART:
+ /* try it again */
+ if (ctrl & PAM_TAC_DEBUG)
+ syslog(LOG_DEBUG, "tacacs status: TAC_PLUS_AUTHEN_STATUS_RESTART");
+
+ /*
+ * not implemented
+ * WdJ: I *think* you can just do tac_authen_send(user, pass) again
+ * but I'm not sure
+ */
+ communicating = 0;
+ break;
+
+ case TAC_PLUS_AUTHEN_STATUS_ERROR:
+ /* server has problems */
+ if (ctrl & PAM_TAC_DEBUG)
+ syslog(LOG_DEBUG, "tacacs status: TAC_PLUS_AUTHEN_STATUS_ERROR");
+
+ communicating = 0;
+ break;
+
+ case TAC_PLUS_AUTHEN_STATUS_FOLLOW:
+ /* server tells to try a different server address */
+ /* not implemented */
+ if (ctrl & PAM_TAC_DEBUG)
+ syslog(LOG_DEBUG, "tacacs status: TAC_PLUS_AUTHEN_STATUS_FOLLOW");
+
+ communicating = 0;
+ break;
+
+ default:
+ if (msg < 0) {
+ /* connection error */
+ communicating = 0;
if (ctrl & PAM_TAC_DEBUG)
- syslog (LOG_DEBUG, "%s: active srv %d", __FUNCTION__, srv_i );
-
+ syslog(LOG_DEBUG, "error communicating with tacacs server");
break;
}
- }
- } else if (msg != TAC_PLUS_AUTHEN_STATUS_PASS) {
- _pam_log (LOG_ERR, "auth failed: %d", msg);
- status = PAM_AUTH_ERR;
- } else {
- /* OK, we got authenticated; save the server that
- accepted us for pam_sm_acct_mgmt and exit the loop */
- status = PAM_SUCCESS;
- active_server.addr = tac_srv[srv_i].addr;
- active_server.key = tac_srv[srv_i].key;
- close(tac_fd);
-
- if (ctrl & PAM_TAC_DEBUG)
- syslog (LOG_DEBUG, "%s: active srv %d", __FUNCTION__, srv_i );
-
- break;
+
+ /* unknown response code */
+ communicating = 0;
+ if (ctrl & PAM_TAC_DEBUG)
+ syslog(LOG_DEBUG, "tacacs status: unknown response 0x%02x", msg);
}
- }
+ } /* end while(communicating) */
close(tac_fd);
+
+ if (status == PAM_SUCCESS || status == PAM_AUTH_ERR)
+ break;
}
+ if (status != PAM_SUCCESS && status != PAM_AUTH_ERR)
+ _pam_log(LOG_ERR, "no more servers to connect");
if (ctrl & PAM_TAC_DEBUG)
- syslog (LOG_DEBUG, "%s: exit with pam status: %i", __FUNCTION__, status);
+ syslog(LOG_DEBUG, "%s: exit with pam status: %d", __FUNCTION__, status);
- bzero (pass, strlen (pass));
+ bzero(pass, strlen (pass));
free(pass);
pass = NULL;
@@ -381,8 +403,8 @@ int pam_sm_authenticate (pam_handle_t * pamh, int flags,
} /* pam_sm_authenticate */
-/* no-op function to satisfy PAM authentication module */
-PAM_EXTERN
+/* no-op function to satisfy PAM authentication module */
+PAM_EXTERN
int pam_sm_setcred (pam_handle_t * pamh, int flags,
int argc, const char **argv) {
@@ -400,7 +422,7 @@ int pam_sm_setcred (pam_handle_t * pamh, int flags,
* his permission to access requested service
* returns PAM_SUCCESS if the service is allowed
*/
-PAM_EXTERN
+PAM_EXTERN
int pam_sm_acct_mgmt (pam_handle_t * pamh, int flags,
int argc, const char **argv) {
@@ -413,7 +435,7 @@ int pam_sm_acct_mgmt (pam_handle_t * pamh, int flags,
int tac_fd;
user = tty = r_addr = NULL;
-
+
/* this also obtains service name for authorization
this should be normally performed by pam_get_item(PAM_SERVICE)
but since PAM service names are incompatible TACACS+
@@ -424,15 +446,15 @@ int pam_sm_acct_mgmt (pam_handle_t * pamh, int flags,
if (ctrl & PAM_TAC_DEBUG)
syslog (LOG_DEBUG, "%s: called (pam_tacplus v%u.%u.%u)"
, __FUNCTION__, PAM_TAC_VMAJ, PAM_TAC_VMIN, PAM_TAC_VPAT);
-
+
if ((user = _pam_get_user(pamh)) == NULL)
return PAM_USER_UNKNOWN;
if (ctrl & PAM_TAC_DEBUG)
syslog(LOG_DEBUG, "%s: username obtained [%s]", __FUNCTION__, user);
-
+
tty = _pam_get_terminal(pamh);
- if(!strncmp(tty, "/dev/", 5))
+ if(!strncmp(tty, "/dev/", 5))
tty += 5;
if (ctrl & PAM_TAC_DEBUG)
syslog(LOG_DEBUG, "%s: tty obtained [%s]", __FUNCTION__, tty);
@@ -440,7 +462,7 @@ int pam_sm_acct_mgmt (pam_handle_t * pamh, int flags,
r_addr = _pam_get_rhost(pamh);
if (ctrl & PAM_TAC_DEBUG)
syslog(LOG_DEBUG, "%s: rhost obtained [%s]", __FUNCTION__, r_addr);
-
+
/* checks if user has been successfully authenticated
by TACACS+; we cannot solely authorize user if it hasn't
been authenticated or has been authenticated by method other
@@ -480,7 +502,7 @@ int pam_sm_acct_mgmt (pam_handle_t * pamh, int flags,
retval = tac_author_send(tac_fd, user, tty, r_addr, attr);
tac_free_attrib(&attr);
-
+
if(retval < 0) {
_pam_log (LOG_ERR, "error getting authorization");
if(arep.msg != NULL)
@@ -492,7 +514,7 @@ int pam_sm_acct_mgmt (pam_handle_t * pamh, int flags,
if (ctrl & PAM_TAC_DEBUG)
syslog(LOG_DEBUG, "%s: sent authorization request", __FUNCTION__);
-
+
tac_author_read(tac_fd, &arep);
if(arep.status != AUTHOR_STATUS_PASS_ADD &&
@@ -508,9 +530,9 @@ int pam_sm_acct_mgmt (pam_handle_t * pamh, int flags,
if (ctrl & PAM_TAC_DEBUG)
syslog(LOG_DEBUG, "%s: user [%s] successfully authorized", __FUNCTION__, user);
-
+
status = PAM_SUCCESS;
-
+
attr = arep.attr;
while (attr != NULL) {
char attribute[attr->attr_len];
@@ -565,30 +587,30 @@ int pam_sm_acct_mgmt (pam_handle_t * pamh, int flags,
/* accounting packets may be directed to any TACACS+ server,
* independent from those used for authentication and authorization;
* it may be also directed to all specified servers
- */
-PAM_EXTERN
+ */
+PAM_EXTERN
int pam_sm_open_session (pam_handle_t * pamh, int flags,
int argc, const char **argv) {
task_id=(short int) magic();
- return _pam_account(pamh, argc, argv, TAC_PLUS_ACCT_FLAG_START, NULL);
+ return _pam_account(pamh, argc, argv, TAC_PLUS_ACCT_FLAG_START, NULL);
} /* pam_sm_open_session */
/* sends STOP accounting request to the remote TACACS+ server
* returns PAM error only if the request was refused or there
* were problems connection to the server
*/
-PAM_EXTERN
+PAM_EXTERN
int pam_sm_close_session (pam_handle_t * pamh, int flags,
int argc, const char **argv) {
- return _pam_account(pamh, argc, argv, TAC_PLUS_ACCT_FLAG_STOP, NULL);
+ return _pam_account(pamh, argc, argv, TAC_PLUS_ACCT_FLAG_STOP, NULL);
} /* pam_sm_close_session */
#ifdef PAM_SM_PASSWORD
-/* no-op function for future use */
-PAM_EXTERN
+/* no-op function for future use */
+PAM_EXTERN
int pam_sm_chauthtok (pam_handle_t * pamh, int flags,
int argc, const char **argv) {