xref: /freebsd/lib/libpam/modules/pam_tacplus/pam_tacplus.c (revision 1b6c76a2fe091c74f08427e6c870851025a9cf67)
1 /*-
2  * Copyright 1998 Juniper Networks, Inc.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  *
26  *	$FreeBSD$
27  */
28 
29 #include <sys/param.h>
30 
31 #include <pwd.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <syslog.h>
35 #include <taclib.h>
36 #include <unistd.h>
37 
38 #define PAM_SM_AUTH
39 #include <security/pam_modules.h>
40 
41 #include "pam_mod_misc.h"
42 
43 /* Option names, including the "=" sign. */
44 #define OPT_CONF		"conf="
45 #define OPT_TMPL		"template_user="
46 
47 typedef int (*set_func)(struct tac_handle *, const char *);
48 
49 static int	 do_item(pam_handle_t *, struct tac_handle *, int,
50 		    set_func, const char *);
51 static char	*get_msg(struct tac_handle *);
52 static int	 set_msg(struct tac_handle *, const char *);
53 
54 static int
55 do_item(pam_handle_t *pamh, struct tac_handle *tach, int item,
56     set_func func, const char *funcname)
57 {
58 	int retval;
59 	const void *value;
60 
61 	if ((retval = pam_get_item(pamh, item, &value)) != PAM_SUCCESS)
62 	    return retval;
63 	if (value != NULL && (*func)(tach, (const char *)value) == -1) {
64 		syslog(LOG_CRIT, "%s: %s", funcname, tac_strerror(tach));
65 		tac_close(tach);
66 		return PAM_SERVICE_ERR;
67 	}
68 	return PAM_SUCCESS;
69 }
70 
71 static char *
72 get_msg(struct tac_handle *tach)
73 {
74 	char *msg;
75 
76 	if ((msg = tac_get_msg(tach)) == NULL) {
77 		syslog(LOG_CRIT, "tac_get_msg: %s", tac_strerror(tach));
78 		tac_close(tach);
79 		return NULL;
80 	}
81 	return msg;
82 }
83 
84 static int
85 set_msg(struct tac_handle *tach, const char *msg)
86 {
87 	if (tac_set_msg(tach, msg) == -1) {
88 		syslog(LOG_CRIT, "tac_set_msg: %s", tac_strerror(tach));
89 		tac_close(tach);
90 		return -1;
91 	}
92 	return 0;
93 }
94 
95 PAM_EXTERN int
96 pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc,
97     const char **argv)
98 {
99 	int retval;
100 	struct tac_handle *tach;
101 	const char *conf_file = NULL;
102 	const char *template_user = NULL;
103 	int options = 0;
104 	int i;
105 
106 	for (i = 0;  i < argc;  i++) {
107 		size_t len;
108 
109 		pam_std_option(&options, argv[i]);
110 		if (strncmp(argv[i], OPT_CONF, (len = strlen(OPT_CONF))) == 0)
111 			conf_file = argv[i] + len;
112 		else if (strncmp(argv[i], OPT_TMPL,
113 		    (len = strlen(OPT_TMPL))) == 0)
114 			template_user = argv[i] + len;
115 	}
116 
117 	if ((tach = tac_open()) == NULL) {
118 		syslog(LOG_CRIT, "tac_open failed");
119 		return PAM_SERVICE_ERR;
120 	}
121 	if (tac_config(tach, conf_file) == -1) {
122 		syslog(LOG_ALERT, "tac_config: %s", tac_strerror(tach));
123 		tac_close(tach);
124 		return PAM_SERVICE_ERR;
125 	}
126 	if (tac_create_authen(tach, TAC_AUTHEN_LOGIN, TAC_AUTHEN_TYPE_ASCII,
127 	    TAC_AUTHEN_SVC_LOGIN) == -1) {
128 		syslog(LOG_CRIT, "tac_create_authen: %s", tac_strerror(tach));
129 		tac_close(tach);
130 		return PAM_SERVICE_ERR;
131 	}
132 	if ((retval = do_item(pamh, tach, PAM_USER,
133 	    tac_set_user, "tac_set_user")) != PAM_SUCCESS)
134 		return retval;
135 	if ((retval = do_item(pamh, tach, PAM_TTY,
136 	    tac_set_port, "tac_set_port")) != PAM_SUCCESS)
137 		return retval;
138 	if ((retval = do_item(pamh, tach, PAM_RHOST,
139 	    tac_set_rem_addr, "tac_set_rem_addr")) != PAM_SUCCESS)
140 		return retval;
141 	for ( ; ; ) {
142 		char *srvr_msg;
143 		size_t msg_len;
144 		const char *user_msg;
145 		char *data_msg;
146 		int sflags;
147 		int status;
148 		int echo;
149 
150 		if ((sflags = tac_send_authen(tach)) == -1) {
151 			syslog(LOG_CRIT, "tac_send_authen: %s",
152 			    tac_strerror(tach));
153 			tac_close(tach);
154 			return PAM_AUTHINFO_UNAVAIL;
155 		}
156 		status = TAC_AUTHEN_STATUS(sflags);
157 		echo = TAC_AUTHEN_NOECHO(sflags) ? 0 : PAM_OPT_ECHO_PASS;
158 		switch (status) {
159 
160 		case TAC_AUTHEN_STATUS_PASS:
161 			tac_close(tach);
162 			if (template_user != NULL) {
163 				const void *item;
164 				const char *user;
165 
166 				/*
167 				 * If the given user name doesn't exist in
168 				 * the local password database, change it
169 				 * to the value given in the "template_user"
170 				 * option.
171 				 */
172 				retval = pam_get_item(pamh, PAM_USER, &item);
173 				if (retval != PAM_SUCCESS)
174 					return retval;
175 				user = (const char *)item;
176 				if (getpwnam(user) == NULL)
177 					pam_set_item(pamh, PAM_USER,
178 					    template_user);
179 			}
180 			return PAM_SUCCESS;
181 
182 		case TAC_AUTHEN_STATUS_FAIL:
183 			tac_close(tach);
184 			return PAM_AUTH_ERR;
185 
186 		case TAC_AUTHEN_STATUS_GETUSER:
187 		case TAC_AUTHEN_STATUS_GETPASS:
188 			if ((srvr_msg = get_msg(tach)) == NULL)
189 				return PAM_SERVICE_ERR;
190 			if (status == TAC_AUTHEN_STATUS_GETUSER)
191 				retval = pam_get_user(pamh, &user_msg,
192 				    srvr_msg[0] != '\0' ? srvr_msg : NULL);
193 			else if (status == TAC_AUTHEN_STATUS_GETPASS)
194 				retval = pam_get_pass(pamh, &user_msg,
195 				    srvr_msg[0] != '\0' ? srvr_msg :
196 				    "Password:", options | echo);
197 			free(srvr_msg);
198 			if (retval != PAM_SUCCESS) {
199 				/* XXX - send a TACACS+ abort packet */
200 				tac_close(tach);
201 				return retval;
202 			}
203 			if (set_msg(tach, user_msg) == -1)
204 				return PAM_SERVICE_ERR;
205 			break;
206 
207 		case TAC_AUTHEN_STATUS_GETDATA:
208 			if ((srvr_msg = get_msg(tach)) == NULL)
209 				return PAM_SERVICE_ERR;
210 			retval = pam_prompt(pamh,
211 			    (options|echo) & PAM_OPT_ECHO_PASS ?
212 			    PAM_PROMPT_ECHO_ON : PAM_PROMPT_ECHO_OFF,
213 			    srvr_msg[0] != '\0' ? srvr_msg : "Data:",
214 			    &data_msg);
215 			free(srvr_msg);
216 			if (retval != PAM_SUCCESS) {
217 				/* XXX - send a TACACS+ abort packet */
218 				tac_close(tach);
219 				return retval;
220 			}
221 			retval = set_msg(tach, data_msg);
222 			memset(data_msg, 0, strlen(data_msg));
223 			free(data_msg);
224 			if (retval == -1)
225 				return PAM_SERVICE_ERR;
226 			break;
227 
228 		case TAC_AUTHEN_STATUS_ERROR:
229 			srvr_msg = (char *)tac_get_data(tach, &msg_len);
230 			if (srvr_msg != NULL && msg_len != 0) {
231 				syslog(LOG_CRIT, "tac_send_authen:"
232 				    " server detected error: %s", srvr_msg);
233 				free(srvr_msg);
234 			} else
235 				syslog(LOG_CRIT,
236 				    "tac_send_authen: server detected error");
237 			tac_close(tach);
238 			return PAM_AUTHINFO_UNAVAIL;
239 			break;
240 
241 		case TAC_AUTHEN_STATUS_RESTART:
242 		case TAC_AUTHEN_STATUS_FOLLOW:
243 		default:
244 			syslog(LOG_CRIT,
245 			    "tac_send_authen: unexpected status %#x", status);
246 			tac_close(tach);
247 			return PAM_AUTHINFO_UNAVAIL;
248 		}
249 	}
250 }
251 
252 PAM_EXTERN int
253 pam_sm_setcred(pam_handle_t *pamh, int flags, int argc, const char **argv)
254 {
255 	return PAM_SUCCESS;
256 }
257 
258 PAM_MODULE_ENTRY("pam_tacplus");
259