1
/* support.c - support functions for pam_tacplus.c
3
* Copyright (C) 2010, Pawel Krawczyk <pawel.krawczyk@hush.com> and
4
* Jeroen Nijhof <jeroen@nijhofnet.nl>
6
* This program is free software; you can redistribute it and/or modify
7
* it under the terms of the GNU General Public License as published by
8
* the Free Software Foundation; either version 2 of the License, or
9
* (at your option) any later version.
11
* This program is distributed in the hope that it will be useful,
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
* GNU General Public License for more details.
16
* You should have received a copy of the GNU General Public License
17
* along with this program - see the file COPYING.
19
* See `CHANGES' file for revision history.
23
#define PAM_SM_ACCOUNT
24
#define PAM_SM_SESSION
25
/* #define PAM_SM_PASSWORD */
28
#include <security/pam_appl.h>
30
#include <security/pam_modules.h>
32
#include "pam_tacplus.h"
36
struct addrinfo *tac_srv[TAC_PLUS_MAXSERVERS];
38
char *tac_srv_key[TAC_PLUS_MAXSERVERS];
39
int tac_srv_key_no = 0;
40
char *tac_service = NULL;
41
char *tac_protocol = NULL;
42
char *tac_prompt = NULL;
45
extern char *tac_login;
46
extern int tac_encryption;
47
extern int tac_timeout;
50
void *_xcalloc (size_t size) {
51
register void *val = calloc (1, size);
53
syslog (LOG_ERR, "xcalloc: calloc(1,%u) failed", (unsigned) size);
59
#define _xcalloc xcalloc
62
void _pam_log(int err, const char *format,...) {
66
va_start(args, format);
67
vsnprintf(msg, sizeof(msg), format, args);
68
openlog("PAM-tacplus", LOG_PID, LOG_AUTH);
69
syslog(err, "%s", msg);
74
char *_pam_get_user(pam_handle_t *pamh) {
78
retval = pam_get_user(pamh, (void *)&user, "Username: ");
79
if (retval != PAM_SUCCESS || user == NULL || *user == '\0') {
80
_pam_log(LOG_ERR, "unable to obtain username");
86
char *_pam_get_terminal(pam_handle_t *pamh) {
90
retval = pam_get_item(pamh, PAM_TTY, (void *)&tty);
91
if (retval != PAM_SUCCESS || tty == NULL || *tty == '\0') {
92
tty = ttyname(STDIN_FILENO);
93
if(tty == NULL || *tty == '\0')
99
char *_pam_get_rhost(pam_handle_t *pamh) {
103
retval = pam_get_item(pamh, PAM_RHOST, (void *)&rhost);
104
if (retval != PAM_SUCCESS || rhost == NULL || *rhost == '\0') {
110
/* stolen from pam_stress */
111
int converse(pam_handle_t * pamh, int nargs
112
,struct pam_message **message
113
,struct pam_response **response) {
116
struct pam_conv *conv;
118
if ((retval = pam_get_item (pamh, PAM_CONV, (void *)&conv)) == PAM_SUCCESS) {
119
#if (defined(__linux__) || defined(__NetBSD__))
120
retval = conv->conv (nargs, (const struct pam_message **) message,
122
retval = conv->conv (nargs, (struct pam_message **) message,
124
response, conv->appdata_ptr);
125
if (retval != PAM_SUCCESS) {
126
_pam_log(LOG_ERR, "(pam_tacplus) converse returned %d", retval);
127
_pam_log(LOG_ERR, "that is: %s", pam_strerror (pamh, retval));
130
_pam_log (LOG_ERR, "(pam_tacplus) converse failed to get pam_conv");
136
/* stolen from pam_stress */
137
int tacacs_get_password (pam_handle_t * pamh, int flags
138
,int ctrl, char **password) {
141
struct pam_message msg[1], *pmsg[1];
142
struct pam_response *resp;
145
if (ctrl & PAM_TAC_DEBUG)
146
syslog (LOG_DEBUG, "%s: called", __FUNCTION__);
148
/* set up conversation call */
150
msg[0].msg_style = PAM_PROMPT_ECHO_OFF;
153
msg[0].msg = "Password: ";
155
msg[0].msg = tac_prompt;
159
if ((retval = converse (pamh, 1, pmsg, &resp)) != PAM_SUCCESS)
163
if ((resp[0].resp == NULL) && (ctrl & PAM_TAC_DEBUG))
164
_pam_log (LOG_DEBUG, "pam_sm_authenticate: NULL authtok given");
165
pass = resp[0].resp; /* remember this! */
167
} else if (ctrl & PAM_TAC_DEBUG) {
168
_pam_log (LOG_DEBUG, "pam_sm_authenticate: no error reported");
169
_pam_log (LOG_DEBUG, "getting password, but NULL returned!?");
176
*password = pass; /* this *MUST* be free()'d by this module */
178
if(ctrl & PAM_TAC_DEBUG)
179
syslog(LOG_DEBUG, "%s: obtained password", __FUNCTION__);
184
int _pam_parse (int argc, const char **argv) {
187
/* otherwise the list will grow with each call */
188
tac_srv_no = tac_srv_key_no = 0;
191
for (ctrl = 0; argc-- > 0; ++argv) {
192
if (!strcmp (*argv, "debug")) { /* all */
193
ctrl |= PAM_TAC_DEBUG;
194
} else if (!strncmp (*argv, "service=", 8)) { /* author & acct */
195
tac_service = (char *) _xcalloc (strlen (*argv + 8) + 1);
196
strcpy (tac_service, *argv + 8);
197
} else if (!strncmp (*argv, "protocol=", 9)) { /* author & acct */
198
tac_protocol = (char *) _xcalloc (strlen (*argv + 9) + 1);
199
strcpy (tac_protocol, *argv + 9);
200
} else if (!strncmp (*argv, "prompt=", 7)) { /* authentication */
201
tac_prompt = (char *) _xcalloc (strlen (*argv + 7) + 1);
202
strcpy (tac_prompt, *argv + 7);
203
// Replace _ with space
205
for (chr = 0; chr < strlen(tac_prompt); chr++) {
206
if (tac_prompt[chr] == '_') {
207
tac_prompt[chr] = ' ';
210
} else if (!strcmp (*argv, "acct_all")) {
211
ctrl |= PAM_TAC_ACCT;
212
} else if (!strncmp (*argv, "server=", 7)) { /* authen & acct */
213
if(tac_srv_no < TAC_PLUS_MAXSERVERS) {
214
struct addrinfo hints, *servers, *server;
217
memset(&hints, 0, sizeof hints);
218
hints.ai_family = AF_UNSPEC; // use IPv4 or IPv6, whichever
219
hints.ai_socktype = SOCK_STREAM;
220
if ((rv = getaddrinfo(*argv + 7, "49", &hints, &servers)) == 0) {
221
for(server = servers; server != NULL; server = server->ai_next) {
222
tac_srv[tac_srv_no] = server;
227
"skip invalid server: %s (getaddrinfo: %s)",
228
*argv + 7, gai_strerror(rv));
231
_pam_log(LOG_ERR, "maximum number of servers (%d) exceeded, skipping",
232
TAC_PLUS_MAXSERVERS);
234
} else if (!strncmp (*argv, "secret=", 7)) {
236
if(tac_srv_key_no < TAC_PLUS_MAXSERVERS) {
237
tac_srv_key[tac_srv_key_no] = (char *) _xcalloc (strlen (*argv + 7) + 1);
238
strcpy (tac_srv_key[tac_srv_key_no], *argv + 7);
241
_pam_log(LOG_ERR, "maximum number of secrets (%d) exceeded, skipping",
242
TAC_PLUS_MAXSERVERS);
244
} else if (!strncmp (*argv, "timeout=", 8)) {
245
tac_timeout = atoi(*argv + 8);
246
} else if (!strncmp (*argv, "login=", 6)) {
247
tac_login = (char *) _xcalloc (strlen (*argv + 6) + 1);
248
strcpy (tac_login, *argv + 6);
250
_pam_log (LOG_WARNING, "unrecognized option: %s", *argv);
254
if (tac_srv_key_no == 0) {
258
for (;tac_srv_key_no < tac_srv_no;tac_srv_key_no++) {
259
tac_srv_key[tac_srv_key_no] = tac_srv_key[0];