blob: 174d289f3bc5a4c9483718fbcefaea2d9f9e5c04 [file] [log] [blame]
Damien Millere72b7af1999-12-30 15:08:44 +11001/*
2 * Author: Damien Miller
3 * Copyright (c) 1999 Damien Miller <djm@mindrot.org>
4 * All rights reserved
5 * Created: Thursday December 30 1999
6 * PAM authentication and session management code.
7 */
8
9#include "includes.h"
10
11#ifdef USE_PAM
12#include "ssh.h"
13#include "xmalloc.h"
14#include "servconf.h"
15
Damien Miller2f6a0ad2000-05-31 11:20:11 +100016RCSID("$Id: auth-pam.c,v 1.5 2000/05/31 01:20:12 damien Exp $");
17
18#define NEW_AUTHTOK_MSG \
19 "Warning: You password has expired, please change it now"
Damien Millere72b7af1999-12-30 15:08:44 +110020
21/* Callbacks */
22static int pamconv(int num_msg, const struct pam_message **msg,
23 struct pam_response **resp, void *appdata_ptr);
24void pam_cleanup_proc(void *context);
Damien Miller2f6a0ad2000-05-31 11:20:11 +100025void pam_msg_cat(const char *msg);
Damien Millere72b7af1999-12-30 15:08:44 +110026
27/* module-local variables */
28static struct pam_conv conv = {
29 pamconv,
30 NULL
31};
32static struct pam_handle_t *pamh = NULL;
33static const char *pampasswd = NULL;
Damien Miller2f6a0ad2000-05-31 11:20:11 +100034static char *pam_msg = NULL;
Damien Millere72b7af1999-12-30 15:08:44 +110035
36/* PAM conversation function. This is really a kludge to get the password */
37/* into PAM and to pick up any messages generated by PAM into pamconv_msg */
38static int pamconv(int num_msg, const struct pam_message **msg,
39 struct pam_response **resp, void *appdata_ptr)
40{
41 struct pam_response *reply;
42 int count;
Damien Millere72b7af1999-12-30 15:08:44 +110043
44 /* PAM will free this later */
45 reply = malloc(num_msg * sizeof(*reply));
46 if (reply == NULL)
47 return PAM_CONV_ERR;
48
49 for(count = 0; count < num_msg; count++) {
50 switch (msg[count]->msg_style) {
51 case PAM_PROMPT_ECHO_OFF:
52 if (pampasswd == NULL) {
53 free(reply);
54 return PAM_CONV_ERR;
55 }
56 reply[count].resp_retcode = PAM_SUCCESS;
57 reply[count].resp = xstrdup(pampasswd);
58 break;
Damien Millere72b7af1999-12-30 15:08:44 +110059 case PAM_TEXT_INFO:
60 reply[count].resp_retcode = PAM_SUCCESS;
61 reply[count].resp = xstrdup("");
62
Damien Miller2f6a0ad2000-05-31 11:20:11 +100063 if (msg[count]->msg != NULL)
64 pam_msg_cat(msg[count]->msg);
Damien Millere72b7af1999-12-30 15:08:44 +110065
Damien Millere72b7af1999-12-30 15:08:44 +110066 break;
Damien Millere72b7af1999-12-30 15:08:44 +110067 default:
68 free(reply);
69 return PAM_CONV_ERR;
70 }
71 }
72
73 *resp = reply;
74
75 return PAM_SUCCESS;
76}
77
78/* Called at exit to cleanly shutdown PAM */
79void pam_cleanup_proc(void *context)
80{
81 int pam_retval;
82
83 if (pamh != NULL)
84 {
85 pam_retval = pam_close_session((pam_handle_t *)pamh, 0);
86 if (pam_retval != PAM_SUCCESS) {
87 log("Cannot close PAM session: %.200s",
Damien Miller2f6a0ad2000-05-31 11:20:11 +100088 PAM_STRERROR((pam_handle_t *)pamh, pam_retval));
Damien Millere72b7af1999-12-30 15:08:44 +110089 }
90
91 pam_retval = pam_setcred((pam_handle_t *)pamh, PAM_DELETE_CRED);
92 if (pam_retval != PAM_SUCCESS) {
93 log("Cannot delete credentials: %.200s",
Damien Miller2f6a0ad2000-05-31 11:20:11 +100094 PAM_STRERROR((pam_handle_t *)pamh, pam_retval));
Damien Millere72b7af1999-12-30 15:08:44 +110095 }
96
97 pam_retval = pam_end((pam_handle_t *)pamh, pam_retval);
98 if (pam_retval != PAM_SUCCESS) {
99 log("Cannot release PAM authentication: %.200s",
Damien Miller2f6a0ad2000-05-31 11:20:11 +1000100 PAM_STRERROR((pam_handle_t *)pamh, pam_retval));
Damien Millere72b7af1999-12-30 15:08:44 +1100101 }
102 }
103}
104
105/* Attempt password authentation using PAM */
106int auth_pam_password(struct passwd *pw, const char *password)
107{
108 extern ServerOptions options;
109 int pam_retval;
110
111 /* deny if no user. */
112 if (pw == NULL)
113 return 0;
114 if (pw->pw_uid == 0 && options.permit_root_login == 2)
115 return 0;
116 if (*password == '\0' && options.permit_empty_passwd == 0)
117 return 0;
118
119 pampasswd = password;
120
121 pam_retval = pam_authenticate((pam_handle_t *)pamh, 0);
122 if (pam_retval == PAM_SUCCESS) {
Damien Miller2f6a0ad2000-05-31 11:20:11 +1000123 debug("PAM Password authentication accepted for user \"%.100s\"",
124 pw->pw_name);
Damien Millere72b7af1999-12-30 15:08:44 +1100125 return 1;
126 } else {
127 debug("PAM Password authentication for \"%.100s\" failed: %s",
128 pw->pw_name, PAM_STRERROR((pam_handle_t *)pamh, pam_retval));
129 return 0;
130 }
131}
132
133/* Do account management using PAM */
134int do_pam_account(char *username, char *remote_user)
135{
136 int pam_retval;
Damien Miller2f6a0ad2000-05-31 11:20:11 +1000137
Damien Millere72b7af1999-12-30 15:08:44 +1100138 debug("PAM setting rhost to \"%.200s\"", get_canonical_hostname());
139 pam_retval = pam_set_item((pam_handle_t *)pamh, PAM_RHOST,
140 get_canonical_hostname());
141 if (pam_retval != PAM_SUCCESS) {
Damien Miller2f6a0ad2000-05-31 11:20:11 +1000142 fatal("PAM set rhost failed: %.200s",
143 PAM_STRERROR((pam_handle_t *)pamh, pam_retval));
Damien Millere72b7af1999-12-30 15:08:44 +1100144 }
145
146 if (remote_user != NULL) {
147 debug("PAM setting ruser to \"%.200s\"", remote_user);
148 pam_retval = pam_set_item((pam_handle_t *)pamh, PAM_RUSER, remote_user);
149 if (pam_retval != PAM_SUCCESS) {
Damien Miller2f6a0ad2000-05-31 11:20:11 +1000150 fatal("PAM set ruser failed: %.200s",
151 PAM_STRERROR((pam_handle_t *)pamh, pam_retval));
Damien Millere72b7af1999-12-30 15:08:44 +1100152 }
153 }
154
155 pam_retval = pam_acct_mgmt((pam_handle_t *)pamh, 0);
Damien Miller2f6a0ad2000-05-31 11:20:11 +1000156 switch (pam_retval) {
157 case PAM_SUCCESS:
158 /* This is what we want */
159 break;
160 case PAM_NEW_AUTHTOK_REQD:
161 pam_msg_cat(NEW_AUTHTOK_MSG);
162 break;
163 default:
164 log("PAM rejected by account configuration: %.200s",
165 PAM_STRERROR((pam_handle_t *)pamh, pam_retval));
166 return(0);
Damien Millere72b7af1999-12-30 15:08:44 +1100167 }
168
169 return(1);
170}
171
172/* Do PAM-specific session initialisation */
Damien Miller3e955e72000-01-27 10:55:38 +1100173void do_pam_session(char *username, const char *ttyname)
Damien Millere72b7af1999-12-30 15:08:44 +1100174{
175 int pam_retval;
176
177 if (ttyname != NULL) {
178 debug("PAM setting tty to \"%.200s\"", ttyname);
179 pam_retval = pam_set_item((pam_handle_t *)pamh, PAM_TTY, ttyname);
Damien Miller2f6a0ad2000-05-31 11:20:11 +1000180 if (pam_retval != PAM_SUCCESS) {
181 fatal("PAM set tty failed: %.200s",
182 PAM_STRERROR((pam_handle_t *)pamh, pam_retval));
183 }
Damien Millere72b7af1999-12-30 15:08:44 +1100184 }
185
186 pam_retval = pam_open_session((pam_handle_t *)pamh, 0);
Damien Miller2f6a0ad2000-05-31 11:20:11 +1000187 if (pam_retval != PAM_SUCCESS) {
188 fatal("PAM session setup failed: %.200s",
189 PAM_STRERROR((pam_handle_t *)pamh, pam_retval));
190 }
Damien Millere72b7af1999-12-30 15:08:44 +1100191}
192
193/* Set PAM credentials */
194void do_pam_setcred()
195{
196 int pam_retval;
197
198 debug("PAM establishing creds");
199 pam_retval = pam_setcred((pam_handle_t *)pamh, PAM_ESTABLISH_CRED);
Damien Miller2f6a0ad2000-05-31 11:20:11 +1000200 if (pam_retval != PAM_SUCCESS) {
201 fatal("PAM setcred failed: %.200s",
202 PAM_STRERROR((pam_handle_t *)pamh, pam_retval));
203 }
Damien Millere72b7af1999-12-30 15:08:44 +1100204}
205
206/* Cleanly shutdown PAM */
207void finish_pam(void)
208{
209 pam_cleanup_proc(NULL);
210 fatal_remove_cleanup(&pam_cleanup_proc, NULL);
211}
212
213/* Start PAM authentication for specified account */
214void start_pam(struct passwd *pw)
215{
216 int pam_retval;
217
218 debug("Starting up PAM with username \"%.200s\"", pw->pw_name);
219
Damien Millerd0cff3e2000-04-20 23:12:58 +1000220 pam_retval = pam_start(SSHD_PAM_SERVICE, pw->pw_name, &conv,
221 (pam_handle_t**)&pamh);
Damien Millere72b7af1999-12-30 15:08:44 +1100222
Damien Miller2f6a0ad2000-05-31 11:20:11 +1000223 if (pam_retval != PAM_SUCCESS) {
224 fatal("PAM initialisation failed: %.200s",
225 PAM_STRERROR((pam_handle_t *)pamh, pam_retval));
226 }
227
Damien Millere72b7af1999-12-30 15:08:44 +1100228 fatal_add_cleanup(&pam_cleanup_proc, NULL);
229}
230
231/* Return list of PAM enviornment strings */
232char **fetch_pam_environment(void)
233{
Damien Miller1bead332000-04-30 00:47:29 +1000234#ifdef HAVE_PAM_GETENVLIST
Damien Millere72b7af1999-12-30 15:08:44 +1100235 return(pam_getenvlist((pam_handle_t *)pamh));
Damien Miller1bead332000-04-30 00:47:29 +1000236#else /* HAVE_PAM_GETENVLIST */
237 return(NULL);
238#endif /* HAVE_PAM_GETENVLIST */
Damien Millere72b7af1999-12-30 15:08:44 +1100239}
240
241/* Print any messages that have been generated during authentication */
242/* or account checking to stderr */
243void print_pam_messages(void)
244{
Damien Miller2f6a0ad2000-05-31 11:20:11 +1000245 if (pam_msg != NULL)
246 fprintf(stderr, pam_msg);
247}
248
249/* Append a message to the PAM message buffer */
250void pam_msg_cat(const char *msg)
251{
252 char *p;
253 size_t new_msg_len;
254 size_t pam_msg_len;
255
256 new_msg_len = strlen(msg);
257
258 if (pam_msg) {
259 pam_msg_len = strlen(pam_msg);
260 pam_msg = xrealloc(pam_msg, new_msg_len + pam_msg_len + 2);
261 p = pam_msg + pam_msg_len;
262 } else {
263 pam_msg = p = xmalloc(new_msg_len + 2);
264 }
265
266 memcpy(p, msg, new_msg_len);
267 p[new_msg_len] = '\n';
268 p[new_msg_len + 1] = '\0';
Damien Millere72b7af1999-12-30 15:08:44 +1100269}
270
271#endif /* USE_PAM */