pam_tacplus.c revision 90229
1169689Skan/*-
2169689Skan * Copyright 1998 Juniper Networks, Inc.
3169689Skan * All rights reserved.
4169689Skan * Copyright (c) 2001 Networks Associates Technologies, Inc.
5169689Skan * All rights reserved.
6169689Skan *
7169689Skan * Portions of this software were developed for the FreeBSD Project by
8169689Skan * ThinkSec AS and NAI Labs, the Security Research Division of Network
9169689Skan * Associates, Inc.  under DARPA/SPAWAR contract N66001-01-C-8035
10169689Skan * ("CBOSS"), as part of the DARPA CHATS research program.
11169689Skan *
12169689Skan * Redistribution and use in source and binary forms, with or without
13169689Skan * modification, are permitted provided that the following conditions
14169689Skan * are met:
15169689Skan * 1. Redistributions of source code must retain the above copyright
16169689Skan *    notice, this list of conditions and the following disclaimer.
17169689Skan * 2. Redistributions in binary form must reproduce the above copyright
18169689Skan *    notice, this list of conditions and the following disclaimer in the
19169689Skan *    documentation and/or other materials provided with the distribution.
20169689Skan * 3. The name of the author may not be used to endorse or promote
21169689Skan *    products derived from this software without specific prior written
22169689Skan *    permission.
23169689Skan *
24169689Skan * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
25169689Skan * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26169689Skan * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27169689Skan * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
28169689Skan * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29169689Skan * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30169689Skan * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31169689Skan * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32169689Skan * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33169689Skan * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34169689Skan * SUCH DAMAGE.
35169689Skan */
36169689Skan
37169689Skan#include <sys/cdefs.h>
38169689Skan__FBSDID("$FreeBSD: head/lib/libpam/modules/pam_tacplus/pam_tacplus.c 90229 2002-02-05 06:08:26Z des $");
39169689Skan
40169689Skan#include <sys/param.h>
41169689Skan
42169689Skan#include <pwd.h>
43169689Skan#include <stdlib.h>
44169689Skan#include <string.h>
45169689Skan#include <syslog.h>
46169689Skan#include <taclib.h>
47169689Skan#include <unistd.h>
48169689Skan
49169689Skan#define PAM_SM_AUTH
50169689Skan#define PAM_SM_ACCOUNT
51169689Skan#define PAM_SM_SESSION
52169689Skan#define PAM_SM_PASSWORD
53169689Skan
54169689Skan#include <security/pam_appl.h>
55169689Skan#include <security/pam_modules.h>
56169689Skan#include <security/pam_mod_misc.h>
57169689Skan
58169689Skanenum { PAM_OPT_CONF=PAM_OPT_STD_MAX, PAM_OPT_TEMPLATE_USER };
59169689Skan
60169689Skanstatic struct opttab other_options[] = {
61169689Skan	{ "conf",		PAM_OPT_CONF },
62169689Skan	{ "template_user",	PAM_OPT_TEMPLATE_USER },
63169689Skan	{ NULL, 0 }
64169689Skan};
65169689Skan
66169689Skantypedef int (*set_func)(struct tac_handle *, const char *);
67169689Skan
68169689Skanstatic int	 do_item(pam_handle_t *, struct tac_handle *, int,
69169689Skan		    set_func, const char *);
70169689Skanstatic char	*get_msg(struct tac_handle *);
71169689Skanstatic int	 set_msg(struct tac_handle *, const char *);
72169689Skan
73169689Skanstatic int
74169689Skando_item(pam_handle_t *pamh, struct tac_handle *tach, int item,
75169689Skan    set_func func, const char *funcname)
76169689Skan{
77169689Skan	int retval;
78169689Skan	const void *value;
79169689Skan
80169689Skan	retval = pam_get_item(pamh, item, &value);
81169689Skan	if (retval != PAM_SUCCESS)
82169689Skan	    return retval;
83169689Skan	if (value != NULL && (*func)(tach, (const char *)value) == -1) {
84169689Skan		syslog(LOG_CRIT, "%s: %s", funcname, tac_strerror(tach));
85169689Skan		tac_close(tach);
86169689Skan		return PAM_SERVICE_ERR;
87169689Skan	}
88169689Skan	return PAM_SUCCESS;
89169689Skan}
90169689Skan
91169689Skanstatic char *
92169689Skanget_msg(struct tac_handle *tach)
93169689Skan{
94169689Skan	char *msg;
95169689Skan
96169689Skan	msg = tac_get_msg(tach);
97169689Skan	if (msg == NULL) {
98169689Skan		syslog(LOG_CRIT, "tac_get_msg: %s", tac_strerror(tach));
99169689Skan		tac_close(tach);
100169689Skan		return NULL;
101169689Skan	}
102169689Skan	return msg;
103169689Skan}
104169689Skan
105169689Skanstatic int
106169689Skanset_msg(struct tac_handle *tach, const char *msg)
107169689Skan{
108169689Skan	if (tac_set_msg(tach, msg) == -1) {
109169689Skan		syslog(LOG_CRIT, "tac_set_msg: %s", tac_strerror(tach));
110169689Skan		tac_close(tach);
111169689Skan		return -1;
112169689Skan	}
113169689Skan	return 0;
114169689Skan}
115169689Skan
116169689SkanPAM_EXTERN int
117169689Skanpam_sm_authenticate(pam_handle_t *pamh, int flags __unused, int argc,
118169689Skan    const char **argv)
119169689Skan{
120169689Skan	struct options options;
121169689Skan	int retval;
122169689Skan	struct tac_handle *tach;
123169689Skan	char *conf_file;
124169689Skan	char *template_user;
125169689Skan
126169689Skan	pam_std_option(&options, other_options, argc, argv);
127169689Skan
128169689Skan	PAM_LOG("Options processed");
129169689Skan
130169689Skan	conf_file = NULL;
131169689Skan	pam_test_option(&options, PAM_OPT_CONF, &conf_file);
132169689Skan	template_user = NULL;
133169689Skan	pam_test_option(&options, PAM_OPT_TEMPLATE_USER, &template_user);
134169689Skan
135169689Skan	tach = tac_open();
136169689Skan	if (tach == NULL) {
137169689Skan		syslog(LOG_CRIT, "tac_open failed");
138169689Skan		PAM_RETURN(PAM_SERVICE_ERR);
139169689Skan	}
140169689Skan	if (tac_config(tach, conf_file) == -1) {
141169689Skan		syslog(LOG_ALERT, "tac_config: %s", tac_strerror(tach));
142169689Skan		tac_close(tach);
143169689Skan		PAM_RETURN(PAM_SERVICE_ERR);
144169689Skan	}
145169689Skan	if (tac_create_authen(tach, TAC_AUTHEN_LOGIN, TAC_AUTHEN_TYPE_ASCII,
146169689Skan	    TAC_AUTHEN_SVC_LOGIN) == -1) {
147169689Skan		syslog(LOG_CRIT, "tac_create_authen: %s", tac_strerror(tach));
148169689Skan		tac_close(tach);
149169689Skan		PAM_RETURN(PAM_SERVICE_ERR);
150169689Skan	}
151169689Skan
152169689Skan	PAM_LOG("Done tac_open() ... tac_close()");
153169689Skan
154169689Skan	retval = do_item(pamh, tach, PAM_USER, tac_set_user, "tac_set_user");
155169689Skan	if (retval != PAM_SUCCESS)
156169689Skan		PAM_RETURN(retval);
157169689Skan
158169689Skan	PAM_LOG("Done user");
159169689Skan
160169689Skan	retval = do_item(pamh, tach, PAM_TTY, tac_set_port, "tac_set_port");
161169689Skan	if (retval != PAM_SUCCESS)
162169689Skan		PAM_RETURN(retval);
163169689Skan
164169689Skan	PAM_LOG("Done tty");
165169689Skan
166169689Skan	retval = do_item(pamh, tach, PAM_RHOST, tac_set_rem_addr,
167169689Skan	    "tac_set_rem_addr");
168169689Skan	if (retval != PAM_SUCCESS)
169169689Skan		PAM_RETURN(retval);
170169689Skan
171169689Skan	for ( ; ; ) {
172169689Skan		char *srvr_msg;
173169689Skan		size_t msg_len;
174169689Skan		const char *user_msg;
175169689Skan		char *data_msg;
176169689Skan		int sflags;
177169689Skan		int status;
178169689Skan
179169689Skan		sflags = tac_send_authen(tach);
180169689Skan		if (sflags == -1) {
181169689Skan			syslog(LOG_CRIT, "tac_send_authen: %s",
182169689Skan			    tac_strerror(tach));
183169689Skan			tac_close(tach);
184169689Skan			PAM_RETURN(PAM_AUTHINFO_UNAVAIL);
185169689Skan		}
186169689Skan		status = TAC_AUTHEN_STATUS(sflags);
187169689Skan		if (!TAC_AUTHEN_NOECHO(sflags))
188169689Skan			pam_set_option(&options, PAM_OPT_ECHO_PASS);
189169689Skan		switch (status) {
190169689Skan
191169689Skan		case TAC_AUTHEN_STATUS_PASS:
192169689Skan			tac_close(tach);
193169689Skan			if (template_user != NULL) {
194169689Skan				const void *item;
195169689Skan				const char *user;
196169689Skan
197169689Skan				PAM_LOG("Trying template user: %s",
198169689Skan				    template_user);
199169689Skan
200169689Skan				/*
201169689Skan				 * If the given user name doesn't exist in
202169689Skan				 * the local password database, change it
203169689Skan				 * to the value given in the "template_user"
204169689Skan				 * option.
205169689Skan				 */
206169689Skan				retval = pam_get_item(pamh, PAM_USER, &item);
207169689Skan				if (retval != PAM_SUCCESS)
208169689Skan					PAM_RETURN(retval);
209169689Skan				user = (const char *)item;
210169689Skan				if (getpwnam(user) == NULL) {
211169689Skan					pam_set_item(pamh, PAM_USER,
212169689Skan					    template_user);
213169689Skan					PAM_LOG("Using template user");
214169689Skan				}
215169689Skan			}
216169689Skan			PAM_RETURN(PAM_SUCCESS);
217169689Skan
218169689Skan		case TAC_AUTHEN_STATUS_FAIL:
219169689Skan			tac_close(tach);
220169689Skan			PAM_VERBOSE_ERROR("TACACS+ authentication failed");
221169689Skan			PAM_RETURN(PAM_AUTH_ERR);
222169689Skan
223169689Skan		case TAC_AUTHEN_STATUS_GETUSER:
224169689Skan		case TAC_AUTHEN_STATUS_GETPASS:
225169689Skan			if ((srvr_msg = get_msg(tach)) == NULL)
226169689Skan				PAM_RETURN(PAM_SERVICE_ERR);
227169689Skan			if (status == TAC_AUTHEN_STATUS_GETUSER)
228169689Skan				retval = pam_get_user(pamh, &user_msg,
229169689Skan				    srvr_msg[0] != '\0' ? srvr_msg : NULL);
230169689Skan			else if (status == TAC_AUTHEN_STATUS_GETPASS)
231169689Skan				retval = pam_get_pass(pamh, &user_msg,
232169689Skan				    srvr_msg[0] != '\0' ? srvr_msg :
233169689Skan				    "Password:", &options);
234169689Skan			free(srvr_msg);
235169689Skan			if (retval != PAM_SUCCESS) {
236169689Skan				/* XXX - send a TACACS+ abort packet */
237169689Skan				tac_close(tach);
238169689Skan				PAM_RETURN(retval);
239169689Skan			}
240169689Skan			if (set_msg(tach, user_msg) == -1)
241169689Skan				PAM_RETURN(PAM_SERVICE_ERR);
242169689Skan			break;
243169689Skan
244169689Skan		case TAC_AUTHEN_STATUS_GETDATA:
245169689Skan			if ((srvr_msg = get_msg(tach)) == NULL)
246169689Skan				PAM_RETURN(PAM_SERVICE_ERR);
247169689Skan			retval = pam_prompt(pamh,
248169689Skan			    pam_test_option(&options, PAM_OPT_ECHO_PASS, NULL)
249169689Skan				? PAM_PROMPT_ECHO_ON : PAM_PROMPT_ECHO_OFF,
250169689Skan			    srvr_msg[0] != '\0' ? srvr_msg : "Data:",
251169689Skan			    &data_msg);
252169689Skan			free(srvr_msg);
253169689Skan			if (retval != PAM_SUCCESS) {
254169689Skan				/* XXX - send a TACACS+ abort packet */
255169689Skan				tac_close(tach);
256169689Skan				PAM_RETURN(retval);
257169689Skan			}
258169689Skan			retval = set_msg(tach, data_msg);
259169689Skan			memset(data_msg, 0, strlen(data_msg));
260169689Skan			free(data_msg);
261169689Skan			if (retval == -1)
262169689Skan				PAM_RETURN(PAM_SERVICE_ERR);
263169689Skan			break;
264169689Skan
265169689Skan		case TAC_AUTHEN_STATUS_ERROR:
266169689Skan			srvr_msg = (char *)tac_get_data(tach, &msg_len);
267169689Skan			if (srvr_msg != NULL && msg_len != 0) {
268169689Skan				syslog(LOG_CRIT, "tac_send_authen:"
269169689Skan				    " server detected error: %s", srvr_msg);
270169689Skan				free(srvr_msg);
271169689Skan			}
272169689Skan			else
273169689Skan				syslog(LOG_CRIT,
274169689Skan				    "tac_send_authen: server detected error");
275169689Skan			tac_close(tach);
276169689Skan			PAM_RETURN(PAM_AUTHINFO_UNAVAIL);
277169689Skan			break;
278169689Skan
279169689Skan		case TAC_AUTHEN_STATUS_RESTART:
280169689Skan		case TAC_AUTHEN_STATUS_FOLLOW:
281169689Skan		default:
282169689Skan			syslog(LOG_CRIT,
283169689Skan			    "tac_send_authen: unexpected status %#x", status);
284169689Skan			tac_close(tach);
285169689Skan			PAM_RETURN(PAM_AUTHINFO_UNAVAIL);
286169689Skan		}
287169689Skan	}
288169689Skan}
289169689Skan
290169689SkanPAM_EXTERN int
291169689Skanpam_sm_setcred(pam_handle_t *pamh __unused, int flags __unused, int argc, const char **argv)
292169689Skan{
293169689Skan	struct options options;
294169689Skan
295169689Skan	pam_std_option(&options, NULL, argc, argv);
296169689Skan
297169689Skan	PAM_LOG("Options processed");
298169689Skan
299169689Skan	PAM_RETURN(PAM_IGNORE);
300169689Skan}
301169689Skan
302169689SkanPAM_EXTERN int
303169689Skanpam_sm_acct_mgmt(pam_handle_t *pamh __unused, int flags __unused, int argc ,const char **argv)
304169689Skan{
305169689Skan	struct options options;
306169689Skan
307169689Skan	pam_std_option(&options, NULL, argc, argv);
308169689Skan
309169689Skan	PAM_LOG("Options processed");
310169689Skan
311169689Skan	PAM_RETURN(PAM_IGNORE);
312169689Skan}
313169689Skan
314169689SkanPAM_EXTERN int
315169689Skanpam_sm_chauthtok(pam_handle_t *pamh __unused, int flags __unused, int argc, const char **argv)
316169689Skan{
317169689Skan	struct options options;
318169689Skan
319169689Skan	pam_std_option(&options, NULL, argc, argv);
320169689Skan
321169689Skan	PAM_LOG("Options processed");
322169689Skan
323169689Skan	PAM_RETURN(PAM_IGNORE);
324169689Skan}
325169689Skan
326169689SkanPAM_EXTERN int
327169689Skanpam_sm_open_session(pam_handle_t *pamh __unused, int flags __unused, int argc, const char **argv)
328169689Skan{
329169689Skan	struct options options;
330169689Skan
331169689Skan	pam_std_option(&options, NULL, argc, argv);
332169689Skan
333169689Skan	PAM_LOG("Options processed");
334169689Skan
335169689Skan	PAM_RETURN(PAM_IGNORE);
336169689Skan}
337169689Skan
338169689SkanPAM_EXTERN int
339169689Skanpam_sm_close_session(pam_handle_t *pamh __unused, int flags __unused, int argc, const char **argv)
340169689Skan{
341169689Skan	struct options options;
342169689Skan
343169689Skan	pam_std_option(&options, NULL, argc, argv);
344169689Skan
345169689Skan	PAM_LOG("Options processed");
346169689Skan
347169689Skan	PAM_RETURN(PAM_IGNORE);
348169689Skan}
349169689Skan
350169689SkanPAM_MODULE_ENTRY("pam_tacplus");
351169689Skan