summaryrefslogtreecommitdiff
path: root/auth-pam.c
diff options
context:
space:
mode:
Diffstat (limited to 'auth-pam.c')
-rw-r--r--auth-pam.c216
1 files changed, 110 insertions, 106 deletions
diff --git a/auth-pam.c b/auth-pam.c
index ab985d15b..e6fddecc0 100644
--- a/auth-pam.c
+++ b/auth-pam.c
@@ -28,31 +28,29 @@
28#include "ssh.h" 28#include "ssh.h"
29#include "xmalloc.h" 29#include "xmalloc.h"
30#include "log.h" 30#include "log.h"
31#include "auth-pam.h"
31#include "servconf.h" 32#include "servconf.h"
32#include "canohost.h" 33#include "canohost.h"
33#include "readpass.h" 34#include "readpass.h"
34 35
35RCSID("$Id: auth-pam.c,v 1.24 2001/02/05 12:42:17 stevesk Exp $"); 36RCSID("$Id: auth-pam.c,v 1.25 2001/02/07 01:58:34 djm Exp $");
36 37
37#define NEW_AUTHTOK_MSG \ 38#define NEW_AUTHTOK_MSG \
38 "Warning: Your password has expired, please change it now" 39 "Warning: Your password has expired, please change it now"
39 40
40/* Callbacks */ 41static int do_pam_conversation(int num_msg, const struct pam_message **msg,
41static int pamconv(int num_msg, const struct pam_message **msg, 42 struct pam_response **resp, void *appdata_ptr);
42 struct pam_response **resp, void *appdata_ptr);
43void pam_cleanup_proc(void *context);
44void pam_msg_cat(const char *msg);
45 43
46/* module-local variables */ 44/* module-local variables */
47static struct pam_conv conv = { 45static struct pam_conv conv = {
48 pamconv, 46 do_pam_conversation,
49 NULL 47 NULL
50}; 48};
49static char *pam_msg = NULL;
51static pam_handle_t *pamh = NULL; 50static pam_handle_t *pamh = NULL;
52static const char *pampasswd = NULL; 51static const char *pampasswd = NULL;
53static char *pam_msg = NULL;
54 52
55/* states for pamconv() */ 53/* states for do_pam_conversation() */
56enum { INITIAL_LOGIN, OTHER } pamstate = INITIAL_LOGIN; 54enum { INITIAL_LOGIN, OTHER } pamstate = INITIAL_LOGIN;
57/* remember whether pam_acct_mgmt() returned PAM_NEWAUTHTOK_REQD */ 55/* remember whether pam_acct_mgmt() returned PAM_NEWAUTHTOK_REQD */
58static int password_change_required = 0; 56static int password_change_required = 0;
@@ -80,14 +78,14 @@ int do_pam_authenticate(int flags)
80 * 78 *
81 * INITIAL_LOGIN mode simply feeds the password from the client into 79 * INITIAL_LOGIN mode simply feeds the password from the client into
82 * PAM in response to PAM_PROMPT_ECHO_OFF, and collects output 80 * PAM in response to PAM_PROMPT_ECHO_OFF, and collects output
83 * messages with pam_msg_cat(). This is used during initial 81 * messages with into pam_msg. This is used during initial
84 * authentication to bypass the normal PAM password prompt. 82 * authentication to bypass the normal PAM password prompt.
85 * 83 *
86 * OTHER mode handles PAM_PROMPT_ECHO_OFF with read_passphrase(prompt, 1) 84 * OTHER mode handles PAM_PROMPT_ECHO_OFF with read_passphrase(prompt, 1)
87 * and outputs messages to stderr. This mode is used if pam_chauthtok() 85 * and outputs messages to stderr. This mode is used if pam_chauthtok()
88 * is called to update expired passwords. 86 * is called to update expired passwords.
89 */ 87 */
90static int pamconv(int num_msg, const struct pam_message **msg, 88static int do_pam_conversation(int num_msg, const struct pam_message **msg,
91 struct pam_response **resp, void *appdata_ptr) 89 struct pam_response **resp, void *appdata_ptr)
92{ 90{
93 struct pam_response *reply; 91 struct pam_response *reply;
@@ -100,40 +98,28 @@ static int pamconv(int num_msg, const struct pam_message **msg,
100 return PAM_CONV_ERR; 98 return PAM_CONV_ERR;
101 99
102 for (count = 0; count < num_msg; count++) { 100 for (count = 0; count < num_msg; count++) {
103 switch(PAM_MSG_MEMBER(msg, count, msg_style)) { 101 if (pamstate == INITIAL_LOGIN) {
102 /*
103 * We can't use stdio yet, queue messages for
104 * printing later
105 */
106 switch(PAM_MSG_MEMBER(msg, count, msg_style)) {
104 case PAM_PROMPT_ECHO_ON: 107 case PAM_PROMPT_ECHO_ON:
105 if (pamstate == INITIAL_LOGIN) { 108 free(reply);
109 return PAM_CONV_ERR;
110 case PAM_PROMPT_ECHO_OFF:
111 if (pampasswd == NULL) {
106 free(reply); 112 free(reply);
107 return PAM_CONV_ERR; 113 return PAM_CONV_ERR;
108 } else {
109 fputs(PAM_MSG_MEMBER(msg, count, msg), stderr);
110 fgets(buf, sizeof(buf), stdin);
111 reply[count].resp = xstrdup(buf);
112 reply[count].resp_retcode = PAM_SUCCESS;
113 break;
114 }
115 case PAM_PROMPT_ECHO_OFF:
116 if (pamstate == INITIAL_LOGIN) {
117 if (pampasswd == NULL) {
118 free(reply);
119 return PAM_CONV_ERR;
120 }
121 reply[count].resp = xstrdup(pampasswd);
122 } else {
123 reply[count].resp =
124 xstrdup(read_passphrase(PAM_MSG_MEMBER(msg, count, msg), 1));
125 } 114 }
115 reply[count].resp = xstrdup(pampasswd);
126 reply[count].resp_retcode = PAM_SUCCESS; 116 reply[count].resp_retcode = PAM_SUCCESS;
127 break; 117 break;
128 case PAM_ERROR_MSG: 118 case PAM_ERROR_MSG:
129 case PAM_TEXT_INFO: 119 case PAM_TEXT_INFO:
130 if ((*msg)[count].msg != NULL) { 120 if ((*msg)[count].msg != NULL) {
131 if (pamstate == INITIAL_LOGIN) 121 message_cat(&pam_msg,
132 pam_msg_cat(PAM_MSG_MEMBER(msg, count, msg)); 122 PAM_MSG_MEMBER(msg, count, msg));
133 else {
134 fputs(PAM_MSG_MEMBER(msg, count, msg), stderr);
135 fputs("\n", stderr);
136 }
137 } 123 }
138 reply[count].resp = xstrdup(""); 124 reply[count].resp = xstrdup("");
139 reply[count].resp_retcode = PAM_SUCCESS; 125 reply[count].resp_retcode = PAM_SUCCESS;
@@ -141,6 +127,36 @@ static int pamconv(int num_msg, const struct pam_message **msg,
141 default: 127 default:
142 free(reply); 128 free(reply);
143 return PAM_CONV_ERR; 129 return PAM_CONV_ERR;
130 }
131 } else {
132 /*
133 * stdio is connected, so interact directly
134 */
135 switch(PAM_MSG_MEMBER(msg, count, msg_style)) {
136 case PAM_PROMPT_ECHO_ON:
137 fputs(PAM_MSG_MEMBER(msg, count, msg), stderr);
138 fgets(buf, sizeof(buf), stdin);
139 reply[count].resp = xstrdup(buf);
140 reply[count].resp_retcode = PAM_SUCCESS;
141 break;
142 case PAM_PROMPT_ECHO_OFF:
143 reply[count].resp = xstrdup(
144 read_passphrase(PAM_MSG_MEMBER(msg, count,
145 msg), 1));
146 reply[count].resp_retcode = PAM_SUCCESS;
147 break;
148 case PAM_ERROR_MSG:
149 case PAM_TEXT_INFO:
150 if ((*msg)[count].msg != NULL)
151 fprintf(stderr, "%s\n",
152 PAM_MSG_MEMBER(msg, count, msg));
153 reply[count].resp = xstrdup("");
154 reply[count].resp_retcode = PAM_SUCCESS;
155 break;
156 default:
157 free(reply);
158 return PAM_CONV_ERR;
159 }
144 } 160 }
145 } 161 }
146 162
@@ -154,25 +170,21 @@ void pam_cleanup_proc(void *context)
154{ 170{
155 int pam_retval; 171 int pam_retval;
156 172
157 if (pamh != NULL) 173 if (pamh) {
158 {
159 pam_retval = pam_close_session(pamh, 0); 174 pam_retval = pam_close_session(pamh, 0);
160 if (pam_retval != PAM_SUCCESS) { 175 if (pam_retval != PAM_SUCCESS)
161 log("Cannot close PAM session[%d]: %.200s", 176 log("Cannot close PAM session[%d]: %.200s",
162 pam_retval, PAM_STRERROR(pamh, pam_retval)); 177 pam_retval, PAM_STRERROR(pamh, pam_retval));
163 }
164 178
165 pam_retval = pam_setcred(pamh, PAM_DELETE_CRED); 179 pam_retval = pam_setcred(pamh, PAM_DELETE_CRED);
166 if (pam_retval != PAM_SUCCESS) { 180 if (pam_retval != PAM_SUCCESS)
167 debug("Cannot delete credentials[%d]: %.200s", 181 debug("Cannot delete credentials[%d]: %.200s",
168 pam_retval, PAM_STRERROR(pamh, pam_retval)); 182 pam_retval, PAM_STRERROR(pamh, pam_retval));
169 }
170 183
171 pam_retval = pam_end(pamh, pam_retval); 184 pam_retval = pam_end(pamh, pam_retval);
172 if (pam_retval != PAM_SUCCESS) { 185 if (pam_retval != PAM_SUCCESS)
173 log("Cannot release PAM authentication[%d]: %.200s", 186 log("Cannot release PAM authentication[%d]: %.200s",
174 pam_retval, PAM_STRERROR(pamh, pam_retval)); 187 pam_retval, PAM_STRERROR(pamh, pam_retval));
175 }
176 } 188 }
177} 189}
178 190
@@ -197,12 +209,13 @@ int auth_pam_password(struct passwd *pw, const char *password)
197 pamstate = INITIAL_LOGIN; 209 pamstate = INITIAL_LOGIN;
198 pam_retval = do_pam_authenticate(0); 210 pam_retval = do_pam_authenticate(0);
199 if (pam_retval == PAM_SUCCESS) { 211 if (pam_retval == PAM_SUCCESS) {
200 debug("PAM Password authentication accepted for user \"%.100s\"", 212 debug("PAM Password authentication accepted for "
201 pw->pw_name); 213 "user \"%.100s\"", pw->pw_name);
202 return 1; 214 return 1;
203 } else { 215 } else {
204 debug("PAM Password authentication for \"%.100s\" failed[%d]: %s", 216 debug("PAM Password authentication for \"%.100s\" "
205 pw->pw_name, pam_retval, PAM_STRERROR(pamh, pam_retval)); 217 "failed[%d]: %s", pw->pw_name, pam_retval,
218 PAM_STRERROR(pamh, pam_retval));
206 return 0; 219 return 0;
207 } 220 }
208} 221}
@@ -213,22 +226,21 @@ int do_pam_account(char *username, char *remote_user)
213 int pam_retval; 226 int pam_retval;
214 extern ServerOptions options; 227 extern ServerOptions options;
215 228
229 pam_set_conv(&conv);
230
216 debug("PAM setting rhost to \"%.200s\"", 231 debug("PAM setting rhost to \"%.200s\"",
217 get_canonical_hostname(options.reverse_mapping_check)); 232 get_canonical_hostname(options.reverse_mapping_check));
218 pam_retval = pam_set_item(pamh, PAM_RHOST, 233 pam_retval = pam_set_item(pamh, PAM_RHOST,
219 get_canonical_hostname(options.reverse_mapping_check)); 234 get_canonical_hostname(options.reverse_mapping_check));
220 if (pam_retval != PAM_SUCCESS) { 235 if (pam_retval != PAM_SUCCESS)
221 fatal("PAM set rhost failed[%d]: %.200s", 236 fatal("PAM set rhost failed[%d]: %.200s", pam_retval,
222 pam_retval, PAM_STRERROR(pamh, pam_retval)); 237 PAM_STRERROR(pamh, pam_retval));
223 } 238 if (remote_user) {
224
225 if (remote_user != NULL) {
226 debug("PAM setting ruser to \"%.200s\"", remote_user); 239 debug("PAM setting ruser to \"%.200s\"", remote_user);
227 pam_retval = pam_set_item(pamh, PAM_RUSER, remote_user); 240 pam_retval = pam_set_item(pamh, PAM_RUSER, remote_user);
228 if (pam_retval != PAM_SUCCESS) { 241 if (pam_retval != PAM_SUCCESS)
229 fatal("PAM set ruser failed[%d]: %.200s", 242 fatal("PAM set ruser failed[%d]: %.200s", pam_retval,
230 pam_retval, PAM_STRERROR(pamh, pam_retval)); 243 PAM_STRERROR(pamh, pam_retval));
231 }
232 } 244 }
233 245
234 pam_retval = pam_acct_mgmt(pamh, 0); 246 pam_retval = pam_acct_mgmt(pamh, 0);
@@ -237,13 +249,14 @@ int do_pam_account(char *username, char *remote_user)
237 /* This is what we want */ 249 /* This is what we want */
238 break; 250 break;
239 case PAM_NEW_AUTHTOK_REQD: 251 case PAM_NEW_AUTHTOK_REQD:
240 pam_msg_cat(NEW_AUTHTOK_MSG); 252 message_cat(&pam_msg, NEW_AUTHTOK_MSG);
241 /* flag that password change is necessary */ 253 /* flag that password change is necessary */
242 password_change_required = 1; 254 password_change_required = 1;
243 break; 255 break;
244 default: 256 default:
245 log("PAM rejected by account configuration[%d]: %.200s", 257 log("PAM rejected by account configuration[%d]: "
246 pam_retval, PAM_STRERROR(pamh, pam_retval)); 258 "%.200s", pam_retval, PAM_STRERROR(pamh,
259 pam_retval));
247 return(0); 260 return(0);
248 } 261 }
249 262
@@ -258,17 +271,15 @@ void do_pam_session(char *username, const char *ttyname)
258 if (ttyname != NULL) { 271 if (ttyname != NULL) {
259 debug("PAM setting tty to \"%.200s\"", ttyname); 272 debug("PAM setting tty to \"%.200s\"", ttyname);
260 pam_retval = pam_set_item(pamh, PAM_TTY, ttyname); 273 pam_retval = pam_set_item(pamh, PAM_TTY, ttyname);
261 if (pam_retval != PAM_SUCCESS) { 274 if (pam_retval != PAM_SUCCESS)
262 fatal("PAM set tty failed[%d]: %.200s", 275 fatal("PAM set tty failed[%d]: %.200s",
263 pam_retval, PAM_STRERROR(pamh, pam_retval)); 276 pam_retval, PAM_STRERROR(pamh, pam_retval));
264 }
265 } 277 }
266 278
267 pam_retval = pam_open_session(pamh, 0); 279 pam_retval = pam_open_session(pamh, 0);
268 if (pam_retval != PAM_SUCCESS) { 280 if (pam_retval != PAM_SUCCESS)
269 fatal("PAM session setup failed[%d]: %.200s", 281 fatal("PAM session setup failed[%d]: %.200s",
270 pam_retval, PAM_STRERROR(pamh, pam_retval)); 282 pam_retval, PAM_STRERROR(pamh, pam_retval));
271 }
272} 283}
273 284
274/* Set PAM credentials */ 285/* Set PAM credentials */
@@ -279,13 +290,12 @@ void do_pam_setcred(void)
279 debug("PAM establishing creds"); 290 debug("PAM establishing creds");
280 pam_retval = pam_setcred(pamh, PAM_ESTABLISH_CRED); 291 pam_retval = pam_setcred(pamh, PAM_ESTABLISH_CRED);
281 if (pam_retval != PAM_SUCCESS) { 292 if (pam_retval != PAM_SUCCESS) {
282 if(was_authenticated) { 293 if (was_authenticated)
283 fatal("PAM setcred failed[%d]: %.200s", 294 fatal("PAM setcred failed[%d]: %.200s",
284 pam_retval, PAM_STRERROR(pamh, pam_retval)); 295 pam_retval, PAM_STRERROR(pamh, pam_retval));
285 } else { 296 else
286 debug("PAM setcred failed[%d]: %.200s", 297 debug("PAM setcred failed[%d]: %.200s",
287 pam_retval, PAM_STRERROR(pamh, pam_retval)); 298 pam_retval, PAM_STRERROR(pamh, pam_retval));
288 }
289 } 299 }
290} 300}
291 301
@@ -307,15 +317,13 @@ void do_pam_chauthtok(void)
307 317
308 if (password_change_required) { 318 if (password_change_required) {
309 pamstate = OTHER; 319 pamstate = OTHER;
310 /* 320 /* XXX: should we really loop forever? */
311 * XXX: should we really loop forever?
312 */
313 do { 321 do {
314 pam_retval = pam_chauthtok(pamh, PAM_CHANGE_EXPIRED_AUTHTOK); 322 pam_retval = pam_chauthtok(pamh,
315 if (pam_retval != PAM_SUCCESS) { 323 PAM_CHANGE_EXPIRED_AUTHTOK);
324 if (pam_retval != PAM_SUCCESS)
316 log("PAM pam_chauthtok failed[%d]: %.200s", 325 log("PAM pam_chauthtok failed[%d]: %.200s",
317 pam_retval, PAM_STRERROR(pamh, pam_retval)); 326 pam_retval, PAM_STRERROR(pamh, pam_retval));
318 }
319 } while (pam_retval != PAM_SUCCESS); 327 } while (pam_retval != PAM_SUCCESS);
320 } 328 }
321} 329}
@@ -336,11 +344,9 @@ void start_pam(const char *user)
336 344
337 pam_retval = pam_start(SSHD_PAM_SERVICE, user, &conv, &pamh); 345 pam_retval = pam_start(SSHD_PAM_SERVICE, user, &conv, &pamh);
338 346
339 if (pam_retval != PAM_SUCCESS) { 347 if (pam_retval != PAM_SUCCESS)
340 fatal("PAM initialisation failed[%d]: %.200s", 348 fatal("PAM initialisation failed[%d]: %.200s",
341 pam_retval, PAM_STRERROR(pamh, pam_retval)); 349 pam_retval, PAM_STRERROR(pamh, pam_retval));
342 }
343
344#ifdef PAM_TTY_KLUDGE 350#ifdef PAM_TTY_KLUDGE
345 /* 351 /*
346 * Some PAM modules (e.g. pam_time) require a TTY to operate, 352 * Some PAM modules (e.g. pam_time) require a TTY to operate,
@@ -350,10 +356,9 @@ void start_pam(const char *user)
350 * Kludge: Set a fake PAM_TTY 356 * Kludge: Set a fake PAM_TTY
351 */ 357 */
352 pam_retval = pam_set_item(pamh, PAM_TTY, "ssh"); 358 pam_retval = pam_set_item(pamh, PAM_TTY, "ssh");
353 if (pam_retval != PAM_SUCCESS) { 359 if (pam_retval != PAM_SUCCESS)
354 fatal("PAM set tty failed[%d]: %.200s", 360 fatal("PAM set tty failed[%d]: %.200s",
355 pam_retval, PAM_STRERROR(pamh, pam_retval)); 361 pam_retval, PAM_STRERROR(pamh, pam_retval));
356 }
357#endif /* PAM_TTY_KLUDGE */ 362#endif /* PAM_TTY_KLUDGE */
358 363
359 fatal_add_cleanup(&pam_cleanup_proc, NULL); 364 fatal_add_cleanup(&pam_cleanup_proc, NULL);
@@ -377,26 +382,25 @@ void print_pam_messages(void)
377 fputs(pam_msg, stderr); 382 fputs(pam_msg, stderr);
378} 383}
379 384
380/* Append a message to the PAM message buffer */ 385/* Append a message to buffer */
381void pam_msg_cat(const char *msg) 386void message_cat(char **p, const char *a)
382{ 387{
383 char *p; 388 char *cp;
384 size_t new_msg_len; 389 size_t new_len;
385 size_t pam_msg_len;
386 390
387 new_msg_len = strlen(msg); 391 new_len = strlen(a);
388 392
389 if (pam_msg) { 393 if (*p) {
390 pam_msg_len = strlen(pam_msg); 394 size_t len = strlen(*p);
391 pam_msg = xrealloc(pam_msg, new_msg_len + pam_msg_len + 2); 395
392 p = pam_msg + pam_msg_len; 396 *p = xrealloc(*p, new_len + len + 2);
393 } else { 397 cp = *p + len;
394 pam_msg = p = xmalloc(new_msg_len + 2); 398 } else
395 } 399 *p = cp = xmalloc(new_len + 2);
396 400
397 memcpy(p, msg, new_msg_len); 401 memcpy(cp, a, new_len);
398 p[new_msg_len] = '\n'; 402 cp[new_len] = '\n';
399 p[new_msg_len + 1] = '\0'; 403 cp[new_len + 1] = '\0';
400} 404}
401 405
402#endif /* USE_PAM */ 406#endif /* USE_PAM */