blob: e3f4c425275031be970f8419d321c3e68a79bc87 [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 Miller1bead332000-04-30 00:47:29 +100016RCSID("$Id: auth-pam.c,v 1.4 2000/04/29 14:47:29 damien Exp $");
Damien Millere72b7af1999-12-30 15:08:44 +110017
18/* Callbacks */
19static int pamconv(int num_msg, const struct pam_message **msg,
20 struct pam_response **resp, void *appdata_ptr);
21void pam_cleanup_proc(void *context);
22
23/* module-local variables */
24static struct pam_conv conv = {
25 pamconv,
26 NULL
27};
28static struct pam_handle_t *pamh = NULL;
29static const char *pampasswd = NULL;
30static char *pamconv_msg = NULL;
31
32/* PAM conversation function. This is really a kludge to get the password */
33/* into PAM and to pick up any messages generated by PAM into pamconv_msg */
34static int pamconv(int num_msg, const struct pam_message **msg,
35 struct pam_response **resp, void *appdata_ptr)
36{
37 struct pam_response *reply;
38 int count;
39 size_t msg_len;
40 char *p;
41
42 /* PAM will free this later */
43 reply = malloc(num_msg * sizeof(*reply));
44 if (reply == NULL)
45 return PAM_CONV_ERR;
46
47 for(count = 0; count < num_msg; count++) {
48 switch (msg[count]->msg_style) {
49 case PAM_PROMPT_ECHO_OFF:
50 if (pampasswd == NULL) {
51 free(reply);
52 return PAM_CONV_ERR;
53 }
54 reply[count].resp_retcode = PAM_SUCCESS;
55 reply[count].resp = xstrdup(pampasswd);
56 break;
57
58 case PAM_TEXT_INFO:
59 reply[count].resp_retcode = PAM_SUCCESS;
60 reply[count].resp = xstrdup("");
61
62 if (msg[count]->msg == NULL)
63 break;
64
65 debug("Adding PAM message: %s", msg[count]->msg);
66
67 msg_len = strlen(msg[count]->msg);
68 if (pamconv_msg) {
69 size_t n = strlen(pamconv_msg);
70 pamconv_msg = xrealloc(pamconv_msg, n + msg_len + 2);
71 p = pamconv_msg + n;
72 } else {
73 pamconv_msg = p = xmalloc(msg_len + 2);
74 }
75 memcpy(p, msg[count]->msg, msg_len);
76 p[msg_len] = '\n';
77 p[msg_len + 1] = '\0';
78 break;
79
80 case PAM_PROMPT_ECHO_ON:
81 case PAM_ERROR_MSG:
82 default:
83 free(reply);
84 return PAM_CONV_ERR;
85 }
86 }
87
88 *resp = reply;
89
90 return PAM_SUCCESS;
91}
92
93/* Called at exit to cleanly shutdown PAM */
94void pam_cleanup_proc(void *context)
95{
96 int pam_retval;
97
98 if (pamh != NULL)
99 {
100 pam_retval = pam_close_session((pam_handle_t *)pamh, 0);
101 if (pam_retval != PAM_SUCCESS) {
102 log("Cannot close PAM session: %.200s",
103 PAM_STRERROR((pam_handle_t *)pamh, pam_retval));
104 }
105
106 pam_retval = pam_setcred((pam_handle_t *)pamh, PAM_DELETE_CRED);
107 if (pam_retval != PAM_SUCCESS) {
108 log("Cannot delete credentials: %.200s",
109 PAM_STRERROR((pam_handle_t *)pamh, pam_retval));
110 }
111
112 pam_retval = pam_end((pam_handle_t *)pamh, pam_retval);
113 if (pam_retval != PAM_SUCCESS) {
114 log("Cannot release PAM authentication: %.200s",
115 PAM_STRERROR((pam_handle_t *)pamh, pam_retval));
116 }
117 }
118}
119
120/* Attempt password authentation using PAM */
121int auth_pam_password(struct passwd *pw, const char *password)
122{
123 extern ServerOptions options;
124 int pam_retval;
125
126 /* deny if no user. */
127 if (pw == NULL)
128 return 0;
129 if (pw->pw_uid == 0 && options.permit_root_login == 2)
130 return 0;
131 if (*password == '\0' && options.permit_empty_passwd == 0)
132 return 0;
133
134 pampasswd = password;
135
136 pam_retval = pam_authenticate((pam_handle_t *)pamh, 0);
137 if (pam_retval == PAM_SUCCESS) {
138 debug("PAM Password authentication accepted for user \"%.100s\"", pw->pw_name);
139 return 1;
140 } else {
141 debug("PAM Password authentication for \"%.100s\" failed: %s",
142 pw->pw_name, PAM_STRERROR((pam_handle_t *)pamh, pam_retval));
143 return 0;
144 }
145}
146
147/* Do account management using PAM */
148int do_pam_account(char *username, char *remote_user)
149{
150 int pam_retval;
151
152 debug("PAM setting rhost to \"%.200s\"", get_canonical_hostname());
153 pam_retval = pam_set_item((pam_handle_t *)pamh, PAM_RHOST,
154 get_canonical_hostname());
155 if (pam_retval != PAM_SUCCESS) {
156 fatal("PAM set rhost failed: %.200s", PAM_STRERROR((pam_handle_t *)pamh, pam_retval));
157 }
158
159 if (remote_user != NULL) {
160 debug("PAM setting ruser to \"%.200s\"", remote_user);
161 pam_retval = pam_set_item((pam_handle_t *)pamh, PAM_RUSER, remote_user);
162 if (pam_retval != PAM_SUCCESS) {
163 fatal("PAM set ruser failed: %.200s", PAM_STRERROR((pam_handle_t *)pamh, pam_retval));
164 }
165 }
166
167 pam_retval = pam_acct_mgmt((pam_handle_t *)pamh, 0);
168 if (pam_retval != PAM_SUCCESS) {
169 log("PAM rejected by account configuration: %.200s", PAM_STRERROR((pam_handle_t *)pamh, pam_retval));
170 return(0);
171 }
172
173 return(1);
174}
175
176/* Do PAM-specific session initialisation */
Damien Miller3e955e72000-01-27 10:55:38 +1100177void do_pam_session(char *username, const char *ttyname)
Damien Millere72b7af1999-12-30 15:08:44 +1100178{
179 int pam_retval;
180
181 if (ttyname != NULL) {
182 debug("PAM setting tty to \"%.200s\"", ttyname);
183 pam_retval = pam_set_item((pam_handle_t *)pamh, PAM_TTY, ttyname);
184 if (pam_retval != PAM_SUCCESS)
185 fatal("PAM set tty failed: %.200s", PAM_STRERROR((pam_handle_t *)pamh, pam_retval));
186 }
187
188 pam_retval = pam_open_session((pam_handle_t *)pamh, 0);
189 if (pam_retval != PAM_SUCCESS)
190 fatal("PAM session setup failed: %.200s", PAM_STRERROR((pam_handle_t *)pamh, pam_retval));
191}
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);
200 if (pam_retval != PAM_SUCCESS)
201 fatal("PAM setcred failed: %.200s", PAM_STRERROR((pam_handle_t *)pamh, pam_retval));
202}
203
204/* Cleanly shutdown PAM */
205void finish_pam(void)
206{
207 pam_cleanup_proc(NULL);
208 fatal_remove_cleanup(&pam_cleanup_proc, NULL);
209}
210
211/* Start PAM authentication for specified account */
212void start_pam(struct passwd *pw)
213{
214 int pam_retval;
215
216 debug("Starting up PAM with username \"%.200s\"", pw->pw_name);
217
Damien Millerd0cff3e2000-04-20 23:12:58 +1000218 pam_retval = pam_start(SSHD_PAM_SERVICE, pw->pw_name, &conv,
219 (pam_handle_t**)&pamh);
Damien Millere72b7af1999-12-30 15:08:44 +1100220 if (pam_retval != PAM_SUCCESS)
221 fatal("PAM initialisation failed: %.200s", PAM_STRERROR((pam_handle_t *)pamh, pam_retval));
222
223 fatal_add_cleanup(&pam_cleanup_proc, NULL);
224}
225
226/* Return list of PAM enviornment strings */
227char **fetch_pam_environment(void)
228{
Damien Miller1bead332000-04-30 00:47:29 +1000229#ifdef HAVE_PAM_GETENVLIST
Damien Millere72b7af1999-12-30 15:08:44 +1100230 return(pam_getenvlist((pam_handle_t *)pamh));
Damien Miller1bead332000-04-30 00:47:29 +1000231#else /* HAVE_PAM_GETENVLIST */
232 return(NULL);
233#endif /* HAVE_PAM_GETENVLIST */
Damien Millere72b7af1999-12-30 15:08:44 +1100234}
235
236/* Print any messages that have been generated during authentication */
237/* or account checking to stderr */
238void print_pam_messages(void)
239{
240 if (pamconv_msg != NULL)
241 fprintf(stderr, pamconv_msg);
242}
243
244#endif /* USE_PAM */