Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/crypto/openssh/auth-pam.c
34677 views
1
/*-
2
* Copyright (c) 2002 Networks Associates Technology, Inc.
3
* All rights reserved.
4
*
5
* This software was developed for the FreeBSD Project by ThinkSec AS and
6
* NAI Labs, the Security Research Division of Network Associates, Inc.
7
* under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the
8
* DARPA CHATS research program.
9
*
10
* Redistribution and use in source and binary forms, with or without
11
* modification, are permitted provided that the following conditions
12
* are met:
13
* 1. Redistributions of source code must retain the above copyright
14
* notice, this list of conditions and the following disclaimer.
15
* 2. Redistributions in binary form must reproduce the above copyright
16
* notice, this list of conditions and the following disclaimer in the
17
* documentation and/or other materials provided with the distribution.
18
*
19
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
23
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29
* SUCH DAMAGE.
30
*/
31
/*
32
* Copyright (c) 2003,2004 Damien Miller <[email protected]>
33
* Copyright (c) 2003,2004 Darren Tucker <[email protected]>
34
*
35
* Permission to use, copy, modify, and distribute this software for any
36
* purpose with or without fee is hereby granted, provided that the above
37
* copyright notice and this permission notice appear in all copies.
38
*
39
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
40
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
41
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
42
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
43
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
44
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
45
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
46
*/
47
48
/* Based on FreeBSD: src/crypto/openssh/auth2-pam-freebsd.c,v 1.11 2003/03/31 13:48:18 des */
49
50
#include "includes.h"
51
52
#include <sys/types.h>
53
#include <sys/stat.h>
54
#include <sys/wait.h>
55
56
#include <errno.h>
57
#include <signal.h>
58
#include <stdarg.h>
59
#include <stdlib.h>
60
#include <string.h>
61
#include <unistd.h>
62
63
#ifdef USE_PAM
64
#if defined(HAVE_SECURITY_PAM_APPL_H)
65
#include <security/pam_appl.h>
66
#elif defined (HAVE_PAM_PAM_APPL_H)
67
#include <pam/pam_appl.h>
68
#endif
69
70
/* OpenGroup RFC86.0 and XSSO specify no "const" on arguments */
71
#ifdef PAM_SUN_CODEBASE
72
# define sshpam_const /* Solaris, HP-UX, SunOS */
73
#else
74
# define sshpam_const const /* LinuxPAM, OpenPAM, AIX */
75
#endif
76
77
/* Ambiguity in spec: is it an array of pointers or a pointer to an array? */
78
#ifdef PAM_SUN_CODEBASE
79
# define PAM_MSG_MEMBER(msg, n, member) ((*(msg))[(n)].member)
80
#else
81
# define PAM_MSG_MEMBER(msg, n, member) ((msg)[(n)]->member)
82
#endif
83
84
#include "xmalloc.h"
85
#include "sshbuf.h"
86
#include "ssherr.h"
87
#include "hostfile.h"
88
#include "auth.h"
89
#include "auth-pam.h"
90
#include "canohost.h"
91
#include "log.h"
92
#include "msg.h"
93
#include "packet.h"
94
#include "misc.h"
95
#include "servconf.h"
96
#include "ssh2.h"
97
#include "auth-options.h"
98
#include "misc.h"
99
#ifdef GSSAPI
100
#include "ssh-gss.h"
101
#endif
102
#include "monitor_wrap.h"
103
#include "srclimit.h"
104
#include "blacklist_client.h"
105
106
extern ServerOptions options;
107
extern struct sshbuf *loginmsg;
108
extern u_int utmp_len;
109
110
/* so we don't silently change behaviour */
111
#ifdef USE_POSIX_THREADS
112
# error "USE_POSIX_THREADS replaced by UNSUPPORTED_POSIX_THREADS_HACK"
113
#endif
114
115
/*
116
* Formerly known as USE_POSIX_THREADS, using this is completely unsupported
117
* and generally a bad idea. Use at own risk and do not expect support if
118
* this breaks.
119
*/
120
#ifdef UNSUPPORTED_POSIX_THREADS_HACK
121
#include <pthread.h>
122
/*
123
* Avoid namespace clash when *not* using pthreads for systems *with*
124
* pthreads, which unconditionally define pthread_t via sys/types.h
125
* (e.g. Linux)
126
*/
127
typedef pthread_t sp_pthread_t;
128
#else
129
typedef pid_t sp_pthread_t;
130
#define pthread_exit fake_pthread_exit
131
#define pthread_create fake_pthread_create
132
#define pthread_cancel fake_pthread_cancel
133
#define pthread_join fake_pthread_join
134
#endif
135
136
struct pam_ctxt {
137
sp_pthread_t pam_thread;
138
int pam_psock;
139
int pam_csock;
140
int pam_done;
141
};
142
143
static void sshpam_free_ctx(void *);
144
static struct pam_ctxt *cleanup_ctxt;
145
146
#ifndef UNSUPPORTED_POSIX_THREADS_HACK
147
/*
148
* Simulate threads with processes.
149
*/
150
151
static int sshpam_thread_status = -1;
152
static sshsig_t sshpam_oldsig;
153
154
static void
155
sshpam_sigchld_handler(int sig)
156
{
157
ssh_signal(SIGCHLD, SIG_DFL);
158
if (cleanup_ctxt == NULL)
159
return; /* handler called after PAM cleanup, shouldn't happen */
160
if (waitpid(cleanup_ctxt->pam_thread, &sshpam_thread_status, WNOHANG)
161
<= 0) {
162
/* PAM thread has not exitted, privsep slave must have */
163
kill(cleanup_ctxt->pam_thread, SIGTERM);
164
while (waitpid(cleanup_ctxt->pam_thread,
165
&sshpam_thread_status, 0) == -1) {
166
if (errno == EINTR)
167
continue;
168
return;
169
}
170
}
171
if (sshpam_thread_status == -1)
172
return;
173
if (WIFSIGNALED(sshpam_thread_status)) {
174
if (signal_is_crash(WTERMSIG(sshpam_thread_status)))
175
_exit(EXIT_CHILD_CRASH);
176
} else if (!WIFEXITED(sshpam_thread_status))
177
_exit(EXIT_CHILD_CRASH);
178
}
179
180
/* ARGSUSED */
181
static void
182
pthread_exit(void *value)
183
{
184
_exit(0);
185
}
186
187
/* ARGSUSED */
188
static int
189
pthread_create(sp_pthread_t *thread, const void *attr,
190
void *(*thread_start)(void *), void *arg)
191
{
192
pid_t pid;
193
struct pam_ctxt *ctx = arg;
194
195
sshpam_thread_status = -1;
196
switch ((pid = fork())) {
197
case -1:
198
error("fork(): %s", strerror(errno));
199
return errno;
200
case 0:
201
close(ctx->pam_psock);
202
ctx->pam_psock = -1;
203
thread_start(arg);
204
_exit(1);
205
default:
206
*thread = pid;
207
close(ctx->pam_csock);
208
ctx->pam_csock = -1;
209
sshpam_oldsig = ssh_signal(SIGCHLD, sshpam_sigchld_handler);
210
return (0);
211
}
212
}
213
214
static int
215
pthread_cancel(sp_pthread_t thread)
216
{
217
ssh_signal(SIGCHLD, sshpam_oldsig);
218
return (kill(thread, SIGTERM));
219
}
220
221
/* ARGSUSED */
222
static int
223
pthread_join(sp_pthread_t thread, void **value)
224
{
225
int status;
226
227
if (sshpam_thread_status != -1)
228
return (sshpam_thread_status);
229
ssh_signal(SIGCHLD, sshpam_oldsig);
230
while (waitpid(thread, &status, 0) == -1) {
231
if (errno == EINTR)
232
continue;
233
fatal("%s: waitpid: %s", __func__, strerror(errno));
234
}
235
return (status);
236
}
237
#endif
238
239
240
static pam_handle_t *sshpam_handle = NULL;
241
static int sshpam_err = 0;
242
static int sshpam_authenticated = 0;
243
static int sshpam_session_open = 0;
244
static int sshpam_cred_established = 0;
245
static int sshpam_account_status = -1;
246
static int sshpam_maxtries_reached = 0;
247
static char **sshpam_env = NULL;
248
static Authctxt *sshpam_authctxt = NULL;
249
static const char *sshpam_password = NULL;
250
static char *sshpam_rhost = NULL;
251
static char *sshpam_laddr = NULL;
252
253
/* Some PAM implementations don't implement this */
254
#ifndef HAVE_PAM_GETENVLIST
255
static char **
256
pam_getenvlist(pam_handle_t *pamh)
257
{
258
/*
259
* XXX - If necessary, we can still support environment passing
260
* for platforms without pam_getenvlist by searching for known
261
* env vars (e.g. KRB5CCNAME) from the PAM environment.
262
*/
263
return NULL;
264
}
265
#endif
266
267
#ifndef HAVE_PAM_PUTENV
268
static int
269
pam_putenv(pam_handle_t *pamh, const char *name_value)
270
{
271
return PAM_SUCCESS;
272
}
273
#endif /* HAVE_PAM_PUTENV */
274
275
/*
276
* Some platforms, notably Solaris, do not enforce password complexity
277
* rules during pam_chauthtok() if the real uid of the calling process
278
* is 0, on the assumption that it's being called by "passwd" run by root.
279
* This wraps pam_chauthtok and sets/restore the real uid so PAM will do
280
* the right thing.
281
*/
282
#ifdef SSHPAM_CHAUTHTOK_NEEDS_RUID
283
static int
284
sshpam_chauthtok_ruid(pam_handle_t *pamh, int flags)
285
{
286
int result;
287
288
if (sshpam_authctxt == NULL)
289
fatal("PAM: sshpam_authctxt not initialized");
290
if (setreuid(sshpam_authctxt->pw->pw_uid, -1) == -1)
291
fatal("%s: setreuid failed: %s", __func__, strerror(errno));
292
result = pam_chauthtok(pamh, flags);
293
if (setreuid(0, -1) == -1)
294
fatal("%s: setreuid failed: %s", __func__, strerror(errno));
295
return result;
296
}
297
# define pam_chauthtok(a,b) (sshpam_chauthtok_ruid((a), (b)))
298
#endif
299
300
static void
301
sshpam_password_change_required(int reqd)
302
{
303
extern struct sshauthopt *auth_opts;
304
static int saved_port, saved_agent, saved_x11;
305
306
debug3("%s %d", __func__, reqd);
307
if (sshpam_authctxt == NULL)
308
fatal("%s: PAM authctxt not initialized", __func__);
309
sshpam_authctxt->force_pwchange = reqd;
310
if (reqd) {
311
saved_port = auth_opts->permit_port_forwarding_flag;
312
saved_agent = auth_opts->permit_agent_forwarding_flag;
313
saved_x11 = auth_opts->permit_x11_forwarding_flag;
314
auth_opts->permit_port_forwarding_flag = 0;
315
auth_opts->permit_agent_forwarding_flag = 0;
316
auth_opts->permit_x11_forwarding_flag = 0;
317
} else {
318
if (saved_port)
319
auth_opts->permit_port_forwarding_flag = saved_port;
320
if (saved_agent)
321
auth_opts->permit_agent_forwarding_flag = saved_agent;
322
if (saved_x11)
323
auth_opts->permit_x11_forwarding_flag = saved_x11;
324
}
325
}
326
327
/* Import regular and PAM environment from subprocess */
328
static void
329
import_environments(struct sshbuf *b)
330
{
331
char *env;
332
u_int n, i, num_env;
333
int r;
334
335
debug3("PAM: %s entering", __func__);
336
337
#ifndef UNSUPPORTED_POSIX_THREADS_HACK
338
/* Import variables set by do_pam_account */
339
if ((r = sshbuf_get_u32(b, &n)) != 0)
340
fatal("%s: buffer error: %s", __func__, ssh_err(r));
341
if (n > INT_MAX)
342
fatal("%s: invalid PAM account status %u", __func__, n);
343
sshpam_account_status = (int)n;
344
if ((r = sshbuf_get_u32(b, &n)) != 0)
345
fatal("%s: buffer error: %s", __func__, ssh_err(r));
346
sshpam_password_change_required(n != 0);
347
348
/* Import environment from subprocess */
349
if ((r = sshbuf_get_u32(b, &num_env)) != 0)
350
fatal("%s: buffer error: %s", __func__, ssh_err(r));
351
if (num_env > 1024) {
352
fatal_f("received %u environment variables, expected <= 1024",
353
num_env);
354
}
355
sshpam_env = xcalloc(num_env + 1, sizeof(*sshpam_env));
356
debug3("PAM: num env strings %u", num_env);
357
for(i = 0; i < num_env; i++) {
358
if ((r = sshbuf_get_cstring(b, &(sshpam_env[i]), NULL)) != 0)
359
fatal("%s: buffer error: %s", __func__, ssh_err(r));
360
}
361
sshpam_env[num_env] = NULL;
362
363
/* Import PAM environment from subprocess */
364
if ((r = sshbuf_get_u32(b, &num_env)) != 0)
365
fatal("%s: buffer error: %s", __func__, ssh_err(r));
366
if (num_env > 1024) {
367
fatal_f("received %u PAM env variables, expected <= 1024",
368
num_env);
369
}
370
debug("PAM: num PAM env strings %u", num_env);
371
for (i = 0; i < num_env; i++) {
372
if ((r = sshbuf_get_cstring(b, &env, NULL)) != 0)
373
fatal("%s: buffer error: %s", __func__, ssh_err(r));
374
/* Errors are not fatal here */
375
if ((r = pam_putenv(sshpam_handle, env)) != PAM_SUCCESS) {
376
error("PAM: pam_putenv: %s",
377
pam_strerror(sshpam_handle, r));
378
}
379
/*
380
* XXX this possibly leaks env because it is not documented
381
* what pam_putenv() does with it. Does it copy it? Does it
382
* take ownweship? We don't know, so it's safest just to leak.
383
*/
384
}
385
#endif
386
}
387
388
/*
389
* Conversation function for authentication thread.
390
*/
391
static int
392
sshpam_thread_conv(int n, sshpam_const struct pam_message **msg,
393
struct pam_response **resp, void *data)
394
{
395
struct sshbuf *buffer;
396
struct pam_ctxt *ctxt;
397
struct pam_response *reply;
398
int r, i;
399
u_char status;
400
401
debug3("PAM: %s entering, %d messages", __func__, n);
402
*resp = NULL;
403
404
if (data == NULL) {
405
error("PAM: conversation function passed a null context");
406
return (PAM_CONV_ERR);
407
}
408
ctxt = data;
409
if (n <= 0 || n > PAM_MAX_NUM_MSG)
410
return (PAM_CONV_ERR);
411
412
if ((reply = calloc(n, sizeof(*reply))) == NULL)
413
return PAM_CONV_ERR;
414
if ((buffer = sshbuf_new()) == NULL) {
415
free(reply);
416
return PAM_CONV_ERR;
417
}
418
419
for (i = 0; i < n; ++i) {
420
switch (PAM_MSG_MEMBER(msg, i, msg_style)) {
421
case PAM_PROMPT_ECHO_OFF:
422
case PAM_PROMPT_ECHO_ON:
423
if ((r = sshbuf_put_cstring(buffer,
424
PAM_MSG_MEMBER(msg, i, msg))) != 0)
425
fatal("%s: buffer error: %s",
426
__func__, ssh_err(r));
427
if (ssh_msg_send(ctxt->pam_csock,
428
PAM_MSG_MEMBER(msg, i, msg_style), buffer) == -1)
429
goto fail;
430
431
if (ssh_msg_recv(ctxt->pam_csock, buffer) == -1)
432
goto fail;
433
if ((r = sshbuf_get_u8(buffer, &status)) != 0)
434
fatal("%s: buffer error: %s",
435
__func__, ssh_err(r));
436
if (status != PAM_AUTHTOK)
437
goto fail;
438
if ((r = sshbuf_get_cstring(buffer,
439
&reply[i].resp, NULL)) != 0)
440
fatal("%s: buffer error: %s",
441
__func__, ssh_err(r));
442
break;
443
case PAM_ERROR_MSG:
444
case PAM_TEXT_INFO:
445
if ((r = sshbuf_put_cstring(buffer,
446
PAM_MSG_MEMBER(msg, i, msg))) != 0)
447
fatal("%s: buffer error: %s",
448
__func__, ssh_err(r));
449
if (ssh_msg_send(ctxt->pam_csock,
450
PAM_MSG_MEMBER(msg, i, msg_style), buffer) == -1)
451
goto fail;
452
break;
453
default:
454
goto fail;
455
}
456
sshbuf_reset(buffer);
457
}
458
sshbuf_free(buffer);
459
*resp = reply;
460
return (PAM_SUCCESS);
461
462
fail:
463
for(i = 0; i < n; i++) {
464
free(reply[i].resp);
465
}
466
free(reply);
467
sshbuf_free(buffer);
468
return (PAM_CONV_ERR);
469
}
470
471
/*
472
* Authentication thread.
473
*/
474
static void *
475
sshpam_thread(void *ctxtp)
476
{
477
struct pam_ctxt *ctxt = ctxtp;
478
struct sshbuf *buffer = NULL;
479
struct pam_conv sshpam_conv;
480
int r, flags = (options.permit_empty_passwd == 0 ?
481
PAM_DISALLOW_NULL_AUTHTOK : 0);
482
#ifndef UNSUPPORTED_POSIX_THREADS_HACK
483
extern char **environ;
484
char **env_from_pam;
485
u_int i;
486
const char *pam_user;
487
const char **ptr_pam_user = &pam_user;
488
char *tz = getenv("TZ");
489
490
sshpam_err = pam_get_item(sshpam_handle, PAM_USER,
491
(sshpam_const void **)ptr_pam_user);
492
if (sshpam_err != PAM_SUCCESS)
493
goto auth_fail;
494
495
environ[0] = NULL;
496
if (tz != NULL)
497
if (setenv("TZ", tz, 1) == -1)
498
error("PAM: could not set TZ environment: %s",
499
strerror(errno));
500
501
if (sshpam_authctxt != NULL) {
502
setproctitle("%s [pam]",
503
sshpam_authctxt->valid ? pam_user : "unknown");
504
}
505
#endif
506
507
sshpam_conv.conv = sshpam_thread_conv;
508
sshpam_conv.appdata_ptr = ctxt;
509
510
if (sshpam_authctxt == NULL)
511
fatal("%s: PAM authctxt not initialized", __func__);
512
513
if ((buffer = sshbuf_new()) == NULL)
514
fatal("%s: sshbuf_new failed", __func__);
515
516
sshpam_err = pam_set_item(sshpam_handle, PAM_CONV,
517
(const void *)&sshpam_conv);
518
if (sshpam_err != PAM_SUCCESS)
519
goto auth_fail;
520
sshpam_err = pam_authenticate(sshpam_handle, flags);
521
if (sshpam_err == PAM_MAXTRIES)
522
sshpam_set_maxtries_reached(1);
523
if (sshpam_err != PAM_SUCCESS)
524
goto auth_fail;
525
526
if (!do_pam_account()) {
527
sshpam_err = PAM_ACCT_EXPIRED;
528
goto auth_fail;
529
}
530
if (sshpam_authctxt->force_pwchange) {
531
sshpam_err = pam_chauthtok(sshpam_handle,
532
PAM_CHANGE_EXPIRED_AUTHTOK);
533
if (sshpam_err != PAM_SUCCESS)
534
goto auth_fail;
535
sshpam_password_change_required(0);
536
}
537
538
if ((r = sshbuf_put_cstring(buffer, "OK")) != 0)
539
fatal("%s: buffer error: %s", __func__, ssh_err(r));
540
541
#ifndef UNSUPPORTED_POSIX_THREADS_HACK
542
/* Export variables set by do_pam_account */
543
if ((r = sshbuf_put_u32(buffer, sshpam_account_status)) != 0 ||
544
(r = sshbuf_put_u32(buffer, sshpam_authctxt->force_pwchange)) != 0)
545
fatal("%s: buffer error: %s", __func__, ssh_err(r));
546
547
/* Export any environment strings set in child */
548
for (i = 0; environ[i] != NULL; i++) {
549
/* Count */
550
if (i > INT_MAX)
551
fatal("%s: too many environment strings", __func__);
552
}
553
if ((r = sshbuf_put_u32(buffer, i)) != 0)
554
fatal("%s: buffer error: %s", __func__, ssh_err(r));
555
for (i = 0; environ[i] != NULL; i++) {
556
if ((r = sshbuf_put_cstring(buffer, environ[i])) != 0)
557
fatal("%s: buffer error: %s", __func__, ssh_err(r));
558
}
559
/* Export any environment strings set by PAM in child */
560
env_from_pam = pam_getenvlist(sshpam_handle);
561
for (i = 0; env_from_pam != NULL && env_from_pam[i] != NULL; i++) {
562
/* Count */
563
if (i > INT_MAX)
564
fatal("%s: too many PAM environment strings", __func__);
565
}
566
if ((r = sshbuf_put_u32(buffer, i)) != 0)
567
fatal("%s: buffer error: %s", __func__, ssh_err(r));
568
for (i = 0; env_from_pam != NULL && env_from_pam[i] != NULL; i++) {
569
if ((r = sshbuf_put_cstring(buffer, env_from_pam[i])) != 0)
570
fatal("%s: buffer error: %s", __func__, ssh_err(r));
571
}
572
#endif /* UNSUPPORTED_POSIX_THREADS_HACK */
573
574
/* XXX - can't do much about an error here */
575
ssh_msg_send(ctxt->pam_csock, sshpam_err, buffer);
576
sshbuf_free(buffer);
577
pthread_exit(NULL);
578
579
auth_fail:
580
if ((r = sshbuf_put_cstring(buffer,
581
pam_strerror(sshpam_handle, sshpam_err))) != 0)
582
fatal("%s: buffer error: %s", __func__, ssh_err(r));
583
/* XXX - can't do much about an error here */
584
if (sshpam_err == PAM_ACCT_EXPIRED)
585
ssh_msg_send(ctxt->pam_csock, PAM_ACCT_EXPIRED, buffer);
586
else if (sshpam_maxtries_reached)
587
ssh_msg_send(ctxt->pam_csock, PAM_MAXTRIES, buffer);
588
else
589
ssh_msg_send(ctxt->pam_csock, PAM_AUTH_ERR, buffer);
590
sshbuf_free(buffer);
591
pthread_exit(NULL);
592
593
return (NULL); /* Avoid warning for non-pthread case */
594
}
595
596
void
597
sshpam_thread_cleanup(void)
598
{
599
struct pam_ctxt *ctxt = cleanup_ctxt;
600
601
debug3("PAM: %s entering", __func__);
602
if (ctxt != NULL && ctxt->pam_thread != 0) {
603
pthread_cancel(ctxt->pam_thread);
604
pthread_join(ctxt->pam_thread, NULL);
605
close(ctxt->pam_psock);
606
close(ctxt->pam_csock);
607
memset(ctxt, 0, sizeof(*ctxt));
608
cleanup_ctxt = NULL;
609
}
610
}
611
612
static int
613
sshpam_null_conv(int n, sshpam_const struct pam_message **msg,
614
struct pam_response **resp, void *data)
615
{
616
debug3("PAM: %s entering, %d messages", __func__, n);
617
return (PAM_CONV_ERR);
618
}
619
620
static struct pam_conv null_conv = { sshpam_null_conv, NULL };
621
622
static int
623
sshpam_store_conv(int n, sshpam_const struct pam_message **msg,
624
struct pam_response **resp, void *data)
625
{
626
struct pam_response *reply;
627
int r, i;
628
629
debug3("PAM: %s called with %d messages", __func__, n);
630
*resp = NULL;
631
632
if (n <= 0 || n > PAM_MAX_NUM_MSG)
633
return (PAM_CONV_ERR);
634
635
if ((reply = calloc(n, sizeof(*reply))) == NULL)
636
return (PAM_CONV_ERR);
637
638
for (i = 0; i < n; ++i) {
639
switch (PAM_MSG_MEMBER(msg, i, msg_style)) {
640
case PAM_ERROR_MSG:
641
case PAM_TEXT_INFO:
642
if ((r = sshbuf_putf(loginmsg, "%s\n",
643
PAM_MSG_MEMBER(msg, i, msg))) != 0)
644
fatal("%s: buffer error: %s",
645
__func__, ssh_err(r));
646
reply[i].resp_retcode = PAM_SUCCESS;
647
break;
648
default:
649
goto fail;
650
}
651
}
652
*resp = reply;
653
return (PAM_SUCCESS);
654
655
fail:
656
for(i = 0; i < n; i++) {
657
free(reply[i].resp);
658
}
659
free(reply);
660
return (PAM_CONV_ERR);
661
}
662
663
static struct pam_conv store_conv = { sshpam_store_conv, NULL };
664
665
void
666
sshpam_cleanup(void)
667
{
668
if (sshpam_handle == NULL || !mm_is_monitor())
669
return;
670
debug("PAM: cleanup");
671
pam_set_item(sshpam_handle, PAM_CONV, (const void *)&null_conv);
672
if (sshpam_session_open) {
673
debug("PAM: closing session");
674
pam_close_session(sshpam_handle, PAM_SILENT);
675
sshpam_session_open = 0;
676
}
677
if (sshpam_cred_established) {
678
debug("PAM: deleting credentials");
679
pam_setcred(sshpam_handle, PAM_DELETE_CRED);
680
sshpam_cred_established = 0;
681
}
682
sshpam_authenticated = 0;
683
pam_end(sshpam_handle, sshpam_err);
684
sshpam_handle = NULL;
685
}
686
687
static int
688
sshpam_init(struct ssh *ssh, Authctxt *authctxt)
689
{
690
const char *pam_user, *user = authctxt->user;
691
const char **ptr_pam_user = &pam_user;
692
int r;
693
694
if (options.pam_service_name == NULL)
695
fatal_f("internal error: NULL PAM service name");
696
#if defined(PAM_SUN_CODEBASE) && defined(PAM_MAX_RESP_SIZE)
697
/* Protect buggy PAM implementations from excessively long usernames */
698
if (strlen(user) >= PAM_MAX_RESP_SIZE)
699
fatal("Username too long from %s port %d",
700
ssh_remote_ipaddr(ssh), ssh_remote_port(ssh));
701
#endif
702
if (sshpam_handle == NULL) {
703
if (ssh == NULL) {
704
fatal("%s: called initially with no "
705
"packet context", __func__);
706
}
707
}
708
if (sshpam_handle != NULL) {
709
/* We already have a PAM context; check if the user matches */
710
sshpam_err = pam_get_item(sshpam_handle,
711
PAM_USER, (sshpam_const void **)ptr_pam_user);
712
if (sshpam_err == PAM_SUCCESS && strcmp(user, pam_user) == 0)
713
return (0);
714
pam_end(sshpam_handle, sshpam_err);
715
sshpam_handle = NULL;
716
}
717
debug("PAM: initializing for \"%s\" with service \"%s\"", user,
718
options.pam_service_name);
719
sshpam_err = pam_start(options.pam_service_name, user,
720
&store_conv, &sshpam_handle);
721
sshpam_authctxt = authctxt;
722
723
if (sshpam_err != PAM_SUCCESS) {
724
pam_end(sshpam_handle, sshpam_err);
725
sshpam_handle = NULL;
726
return (-1);
727
}
728
729
if (ssh != NULL && sshpam_rhost == NULL) {
730
/*
731
* We need to cache these as we don't have packet context
732
* during the kbdint flow.
733
*/
734
sshpam_rhost = xstrdup(auth_get_canonical_hostname(ssh,
735
options.use_dns));
736
sshpam_laddr = get_local_ipaddr(
737
ssh_packet_get_connection_in(ssh));
738
}
739
if (sshpam_rhost != NULL) {
740
debug("PAM: setting PAM_RHOST to \"%s\"", sshpam_rhost);
741
sshpam_err = pam_set_item(sshpam_handle, PAM_RHOST,
742
sshpam_rhost);
743
if (sshpam_err != PAM_SUCCESS) {
744
pam_end(sshpam_handle, sshpam_err);
745
sshpam_handle = NULL;
746
return (-1);
747
}
748
}
749
if (ssh != NULL && sshpam_laddr != NULL) {
750
char *conninfo;
751
752
/* Put SSH_CONNECTION in the PAM environment too */
753
xasprintf(&conninfo, "SSH_CONNECTION=%.50s %d %.50s %d",
754
ssh_remote_ipaddr(ssh), ssh_remote_port(ssh),
755
sshpam_laddr, ssh_local_port(ssh));
756
if ((r = pam_putenv(sshpam_handle, conninfo)) != PAM_SUCCESS)
757
logit("pam_putenv: %s", pam_strerror(sshpam_handle, r));
758
free(conninfo);
759
}
760
761
#ifdef PAM_TTY_KLUDGE
762
/*
763
* Some silly PAM modules (e.g. pam_time) require a TTY to operate.
764
* sshd doesn't set the tty until too late in the auth process and
765
* may not even set one (for tty-less connections)
766
*/
767
debug("PAM: setting PAM_TTY to \"ssh\"");
768
sshpam_err = pam_set_item(sshpam_handle, PAM_TTY, "ssh");
769
if (sshpam_err != PAM_SUCCESS) {
770
pam_end(sshpam_handle, sshpam_err);
771
sshpam_handle = NULL;
772
return (-1);
773
}
774
#endif
775
return (0);
776
}
777
778
static void
779
expose_authinfo(const char *caller)
780
{
781
char *auth_info;
782
783
/*
784
* Expose authentication information to PAM.
785
* The environment variable is versioned. Please increment the
786
* version suffix if the format of session_info changes.
787
*/
788
if (sshpam_authctxt->session_info == NULL)
789
auth_info = xstrdup("");
790
else if ((auth_info = sshbuf_dup_string(
791
sshpam_authctxt->session_info)) == NULL)
792
fatal("%s: sshbuf_dup_string failed", __func__);
793
794
debug2("%s: auth information in SSH_AUTH_INFO_0", caller);
795
do_pam_putenv("SSH_AUTH_INFO_0", auth_info);
796
free(auth_info);
797
}
798
799
static void *
800
sshpam_init_ctx(Authctxt *authctxt)
801
{
802
struct pam_ctxt *ctxt;
803
int result, socks[2];
804
805
debug3("PAM: %s entering", __func__);
806
/*
807
* Refuse to start if we don't have PAM enabled or do_pam_account
808
* has previously failed.
809
*/
810
if (!options.use_pam || sshpam_account_status == 0)
811
return NULL;
812
813
/* Initialize PAM */
814
if (sshpam_init(NULL, authctxt) == -1) {
815
error("PAM: initialization failed");
816
return (NULL);
817
}
818
819
expose_authinfo(__func__);
820
ctxt = xcalloc(1, sizeof *ctxt);
821
822
/* Start the authentication thread */
823
if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, socks) == -1) {
824
error("PAM: failed create sockets: %s", strerror(errno));
825
free(ctxt);
826
return (NULL);
827
}
828
ctxt->pam_psock = socks[0];
829
ctxt->pam_csock = socks[1];
830
result = pthread_create(&ctxt->pam_thread, NULL, sshpam_thread, ctxt);
831
if (result != 0) {
832
error("PAM: failed to start authentication thread: %s",
833
strerror(result));
834
close(socks[0]);
835
close(socks[1]);
836
free(ctxt);
837
return (NULL);
838
}
839
cleanup_ctxt = ctxt;
840
return (ctxt);
841
}
842
843
static int
844
sshpam_query(void *ctx, char **name, char **info,
845
u_int *num, char ***prompts, u_int **echo_on)
846
{
847
struct sshbuf *buffer;
848
struct pam_ctxt *ctxt = ctx;
849
size_t plen;
850
u_char type;
851
char *msg;
852
size_t len, mlen, nmesg = 0;
853
int r;
854
855
debug3("PAM: %s entering", __func__);
856
if ((buffer = sshbuf_new()) == NULL)
857
fatal("%s: sshbuf_new failed", __func__);
858
*name = xstrdup("");
859
*info = xstrdup("");
860
*prompts = xmalloc(sizeof(char *));
861
**prompts = NULL;
862
plen = 0;
863
*echo_on = xmalloc(sizeof(u_int));
864
while (ssh_msg_recv(ctxt->pam_psock, buffer) == 0) {
865
if (++nmesg > PAM_MAX_NUM_MSG)
866
fatal_f("too many query messages");
867
if ((r = sshbuf_get_u8(buffer, &type)) != 0 ||
868
(r = sshbuf_get_cstring(buffer, &msg, &mlen)) != 0)
869
fatal("%s: buffer error: %s", __func__, ssh_err(r));
870
switch (type) {
871
case PAM_PROMPT_ECHO_ON:
872
case PAM_PROMPT_ECHO_OFF:
873
*num = 1;
874
len = plen + mlen + 1;
875
**prompts = xreallocarray(**prompts, 1, len);
876
strlcpy(**prompts + plen, msg, len - plen);
877
plen += mlen;
878
**echo_on = (type == PAM_PROMPT_ECHO_ON);
879
free(msg);
880
sshbuf_free(buffer);
881
return (0);
882
case PAM_ERROR_MSG:
883
case PAM_TEXT_INFO:
884
/* accumulate messages */
885
len = plen + mlen + 2;
886
**prompts = xreallocarray(**prompts, 1, len);
887
strlcpy(**prompts + plen, msg, len - plen);
888
plen += mlen;
889
strlcat(**prompts + plen, "\n", len - plen);
890
plen++;
891
free(msg);
892
break;
893
case PAM_ACCT_EXPIRED:
894
case PAM_MAXTRIES:
895
if (type == PAM_ACCT_EXPIRED)
896
sshpam_account_status = 0;
897
if (type == PAM_MAXTRIES)
898
sshpam_set_maxtries_reached(1);
899
/* FALLTHROUGH */
900
case PAM_AUTH_ERR:
901
debug3("PAM: %s", pam_strerror(sshpam_handle, type));
902
if (**prompts != NULL && strlen(**prompts) != 0) {
903
free(*info);
904
*info = **prompts;
905
**prompts = NULL;
906
*num = 0;
907
**echo_on = 0;
908
ctxt->pam_done = -1;
909
free(msg);
910
sshbuf_free(buffer);
911
return 0;
912
}
913
/* FALLTHROUGH */
914
case PAM_SUCCESS:
915
if (**prompts != NULL) {
916
/* drain any accumulated messages */
917
debug("PAM: %s", **prompts);
918
if ((r = sshbuf_put(loginmsg, **prompts,
919
strlen(**prompts))) != 0)
920
fatal("%s: buffer error: %s",
921
__func__, ssh_err(r));
922
free(**prompts);
923
**prompts = NULL;
924
}
925
if (type == PAM_SUCCESS) {
926
if (!sshpam_authctxt->valid ||
927
(sshpam_authctxt->pw->pw_uid == 0 &&
928
options.permit_root_login != PERMIT_YES))
929
fatal("Internal error: PAM auth "
930
"succeeded when it should have "
931
"failed");
932
import_environments(buffer);
933
*num = 0;
934
**echo_on = 0;
935
ctxt->pam_done = 1;
936
free(msg);
937
sshbuf_free(buffer);
938
return (0);
939
}
940
BLACKLIST_NOTIFY(NULL, BLACKLIST_BAD_USER,
941
sshpam_authctxt->user);
942
error("PAM: %s for %s%.100s from %.100s", msg,
943
sshpam_authctxt->valid ? "" : "illegal user ",
944
sshpam_authctxt->user, sshpam_rhost);
945
/* FALLTHROUGH */
946
default:
947
*num = 0;
948
**echo_on = 0;
949
free(msg);
950
ctxt->pam_done = -1;
951
sshbuf_free(buffer);
952
return (-1);
953
}
954
}
955
sshbuf_free(buffer);
956
return (-1);
957
}
958
959
/*
960
* Returns a junk password of identical length to that the user supplied.
961
* Used to mitigate timing attacks against crypt(3)/PAM stacks that
962
* vary processing time in proportion to password length.
963
*/
964
static char *
965
fake_password(const char *wire_password)
966
{
967
const char junk[] = "\b\n\r\177INCORRECT";
968
char *ret = NULL;
969
size_t i, l = wire_password != NULL ? strlen(wire_password) : 0;
970
971
if (l >= INT_MAX)
972
fatal("%s: password length too long: %zu", __func__, l);
973
974
ret = malloc(l + 1);
975
if (ret == NULL)
976
return NULL;
977
for (i = 0; i < l; i++)
978
ret[i] = junk[i % (sizeof(junk) - 1)];
979
ret[i] = '\0';
980
return ret;
981
}
982
983
/* XXX - see also comment in auth-chall.c:verify_response */
984
static int
985
sshpam_respond(void *ctx, u_int num, char **resp)
986
{
987
struct sshbuf *buffer;
988
struct pam_ctxt *ctxt = ctx;
989
char *fake;
990
int r;
991
992
debug2("PAM: %s entering, %u responses", __func__, num);
993
switch (ctxt->pam_done) {
994
case 1:
995
sshpam_authenticated = 1;
996
return (0);
997
case 0:
998
break;
999
default:
1000
return (-1);
1001
}
1002
if (num != 1) {
1003
error("PAM: expected one response, got %u", num);
1004
return (-1);
1005
}
1006
if ((buffer = sshbuf_new()) == NULL)
1007
fatal("%s: sshbuf_new failed", __func__);
1008
if (sshpam_authctxt->valid &&
1009
(sshpam_authctxt->pw->pw_uid != 0 ||
1010
options.permit_root_login == PERMIT_YES)) {
1011
if ((r = sshbuf_put_cstring(buffer, *resp)) != 0)
1012
fatal("%s: buffer error: %s", __func__, ssh_err(r));
1013
} else {
1014
fake = fake_password(*resp);
1015
if ((r = sshbuf_put_cstring(buffer, fake)) != 0)
1016
fatal("%s: buffer error: %s", __func__, ssh_err(r));
1017
free(fake);
1018
}
1019
if (ssh_msg_send(ctxt->pam_psock, PAM_AUTHTOK, buffer) == -1) {
1020
sshbuf_free(buffer);
1021
return (-1);
1022
}
1023
sshbuf_free(buffer);
1024
return (1);
1025
}
1026
1027
static void
1028
sshpam_free_ctx(void *ctxtp)
1029
{
1030
struct pam_ctxt *ctxt = ctxtp;
1031
1032
debug3("PAM: %s entering", __func__);
1033
sshpam_thread_cleanup();
1034
free(ctxt);
1035
/*
1036
* We don't call sshpam_cleanup() here because we may need the PAM
1037
* handle at a later stage, e.g. when setting up a session. It's
1038
* still on the cleanup list, so pam_end() *will* be called before
1039
* the server process terminates.
1040
*/
1041
}
1042
1043
KbdintDevice sshpam_device = {
1044
"pam",
1045
sshpam_init_ctx,
1046
sshpam_query,
1047
sshpam_respond,
1048
sshpam_free_ctx
1049
};
1050
1051
KbdintDevice mm_sshpam_device = {
1052
"pam",
1053
mm_sshpam_init_ctx,
1054
mm_sshpam_query,
1055
mm_sshpam_respond,
1056
mm_sshpam_free_ctx
1057
};
1058
1059
/*
1060
* This replaces auth-pam.c
1061
*/
1062
void
1063
start_pam(struct ssh *ssh)
1064
{
1065
Authctxt *authctxt = (Authctxt *)ssh->authctxt;
1066
1067
if (!options.use_pam)
1068
fatal("PAM: initialisation requested when UsePAM=no");
1069
1070
if (sshpam_init(ssh, authctxt) == -1)
1071
fatal("PAM: initialisation failed");
1072
}
1073
1074
void
1075
finish_pam(void)
1076
{
1077
sshpam_cleanup();
1078
}
1079
1080
1081
u_int
1082
do_pam_account(void)
1083
{
1084
debug("%s: called", __func__);
1085
if (sshpam_account_status != -1)
1086
return (sshpam_account_status);
1087
1088
expose_authinfo(__func__);
1089
1090
sshpam_err = pam_acct_mgmt(sshpam_handle, 0);
1091
debug3("PAM: %s pam_acct_mgmt = %d (%s)", __func__, sshpam_err,
1092
pam_strerror(sshpam_handle, sshpam_err));
1093
1094
if (sshpam_err != PAM_SUCCESS && sshpam_err != PAM_NEW_AUTHTOK_REQD) {
1095
sshpam_account_status = 0;
1096
return (sshpam_account_status);
1097
}
1098
1099
if (sshpam_err == PAM_NEW_AUTHTOK_REQD)
1100
sshpam_password_change_required(1);
1101
1102
sshpam_account_status = 1;
1103
return (sshpam_account_status);
1104
}
1105
1106
void
1107
do_pam_setcred(void)
1108
{
1109
sshpam_err = pam_set_item(sshpam_handle, PAM_CONV,
1110
(const void *)&store_conv);
1111
if (sshpam_err != PAM_SUCCESS)
1112
fatal("PAM: failed to set PAM_CONV: %s",
1113
pam_strerror(sshpam_handle, sshpam_err));
1114
debug("PAM: establishing credentials");
1115
sshpam_err = pam_setcred(sshpam_handle, PAM_ESTABLISH_CRED);
1116
if (sshpam_err == PAM_SUCCESS) {
1117
sshpam_cred_established = 1;
1118
return;
1119
}
1120
if (sshpam_authenticated)
1121
fatal("PAM: pam_setcred(): %s",
1122
pam_strerror(sshpam_handle, sshpam_err));
1123
else
1124
debug("PAM: pam_setcred(): %s",
1125
pam_strerror(sshpam_handle, sshpam_err));
1126
}
1127
1128
#if 0
1129
static int
1130
sshpam_tty_conv(int n, sshpam_const struct pam_message **msg,
1131
struct pam_response **resp, void *data)
1132
{
1133
char input[PAM_MAX_MSG_SIZE];
1134
struct pam_response *reply;
1135
int i;
1136
1137
debug3("PAM: %s called with %d messages", __func__, n);
1138
1139
*resp = NULL;
1140
1141
if (n <= 0 || n > PAM_MAX_NUM_MSG || !isatty(STDIN_FILENO))
1142
return (PAM_CONV_ERR);
1143
1144
if ((reply = calloc(n, sizeof(*reply))) == NULL)
1145
return (PAM_CONV_ERR);
1146
1147
for (i = 0; i < n; ++i) {
1148
switch (PAM_MSG_MEMBER(msg, i, msg_style)) {
1149
case PAM_PROMPT_ECHO_OFF:
1150
reply[i].resp =
1151
read_passphrase(PAM_MSG_MEMBER(msg, i, msg),
1152
RP_ALLOW_STDIN);
1153
reply[i].resp_retcode = PAM_SUCCESS;
1154
break;
1155
case PAM_PROMPT_ECHO_ON:
1156
fprintf(stderr, "%s\n", PAM_MSG_MEMBER(msg, i, msg));
1157
if (fgets(input, sizeof input, stdin) == NULL)
1158
input[0] = '\0';
1159
if ((reply[i].resp = strdup(input)) == NULL)
1160
goto fail;
1161
reply[i].resp_retcode = PAM_SUCCESS;
1162
break;
1163
case PAM_ERROR_MSG:
1164
case PAM_TEXT_INFO:
1165
fprintf(stderr, "%s\n", PAM_MSG_MEMBER(msg, i, msg));
1166
reply[i].resp_retcode = PAM_SUCCESS;
1167
break;
1168
default:
1169
goto fail;
1170
}
1171
}
1172
*resp = reply;
1173
return (PAM_SUCCESS);
1174
1175
fail:
1176
for(i = 0; i < n; i++) {
1177
free(reply[i].resp);
1178
}
1179
free(reply);
1180
return (PAM_CONV_ERR);
1181
}
1182
1183
static struct pam_conv tty_conv = { sshpam_tty_conv, NULL };
1184
#endif
1185
1186
/*
1187
* XXX this should be done in the authentication phase, but ssh1 doesn't
1188
* support that
1189
*/
1190
void
1191
do_pam_chauthtok(void)
1192
{
1193
fatal("Password expired");
1194
#if 0
1195
sshpam_err = pam_set_item(sshpam_handle, PAM_CONV,
1196
(const void *)&tty_conv);
1197
if (sshpam_err != PAM_SUCCESS)
1198
fatal("PAM: failed to set PAM_CONV: %s",
1199
pam_strerror(sshpam_handle, sshpam_err));
1200
debug("PAM: changing password");
1201
sshpam_err = pam_chauthtok(sshpam_handle, PAM_CHANGE_EXPIRED_AUTHTOK);
1202
if (sshpam_err != PAM_SUCCESS)
1203
fatal("PAM: pam_chauthtok(): %s",
1204
pam_strerror(sshpam_handle, sshpam_err));
1205
#endif
1206
}
1207
1208
void
1209
do_pam_session(struct ssh *ssh)
1210
{
1211
debug3("PAM: opening session");
1212
1213
expose_authinfo(__func__);
1214
1215
sshpam_err = pam_set_item(sshpam_handle, PAM_CONV,
1216
(const void *)&store_conv);
1217
if (sshpam_err != PAM_SUCCESS)
1218
fatal("PAM: failed to set PAM_CONV: %s",
1219
pam_strerror(sshpam_handle, sshpam_err));
1220
sshpam_err = pam_open_session(sshpam_handle, 0);
1221
if (sshpam_err == PAM_SUCCESS)
1222
sshpam_session_open = 1;
1223
else {
1224
sshpam_session_open = 0;
1225
auth_restrict_session(ssh);
1226
error("PAM: pam_open_session(): %s",
1227
pam_strerror(sshpam_handle, sshpam_err));
1228
}
1229
1230
}
1231
1232
int
1233
is_pam_session_open(void)
1234
{
1235
return sshpam_session_open;
1236
}
1237
1238
/*
1239
* Set a PAM environment string. We need to do this so that the session
1240
* modules can handle things like Kerberos/GSI credentials that appear
1241
* during the ssh authentication process.
1242
*/
1243
int
1244
do_pam_putenv(char *name, char *value)
1245
{
1246
int ret = 1;
1247
char *compound;
1248
size_t len;
1249
1250
len = strlen(name) + strlen(value) + 2;
1251
compound = xmalloc(len);
1252
1253
snprintf(compound, len, "%s=%s", name, value);
1254
ret = pam_putenv(sshpam_handle, compound);
1255
free(compound);
1256
1257
return (ret);
1258
}
1259
1260
char **
1261
fetch_pam_child_environment(void)
1262
{
1263
return sshpam_env;
1264
}
1265
1266
char **
1267
fetch_pam_environment(void)
1268
{
1269
return (pam_getenvlist(sshpam_handle));
1270
}
1271
1272
void
1273
free_pam_environment(char **env)
1274
{
1275
char **envp;
1276
1277
if (env == NULL)
1278
return;
1279
1280
for (envp = env; *envp; envp++)
1281
free(*envp);
1282
free(env);
1283
}
1284
1285
/*
1286
* "Blind" conversation function for password authentication. Assumes that
1287
* echo-off prompts are for the password and stores messages for later
1288
* display.
1289
*/
1290
static int
1291
sshpam_passwd_conv(int n, sshpam_const struct pam_message **msg,
1292
struct pam_response **resp, void *data)
1293
{
1294
struct pam_response *reply;
1295
int r, i;
1296
size_t len;
1297
1298
debug3("PAM: %s called with %d messages", __func__, n);
1299
1300
*resp = NULL;
1301
1302
if (n <= 0 || n > PAM_MAX_NUM_MSG)
1303
return (PAM_CONV_ERR);
1304
1305
if ((reply = calloc(n, sizeof(*reply))) == NULL)
1306
return (PAM_CONV_ERR);
1307
1308
for (i = 0; i < n; ++i) {
1309
switch (PAM_MSG_MEMBER(msg, i, msg_style)) {
1310
case PAM_PROMPT_ECHO_OFF:
1311
if (sshpam_password == NULL)
1312
goto fail;
1313
if ((reply[i].resp = strdup(sshpam_password)) == NULL)
1314
goto fail;
1315
reply[i].resp_retcode = PAM_SUCCESS;
1316
break;
1317
case PAM_ERROR_MSG:
1318
case PAM_TEXT_INFO:
1319
len = strlen(PAM_MSG_MEMBER(msg, i, msg));
1320
if (len > 0) {
1321
if ((r = sshbuf_putf(loginmsg, "%s\n",
1322
PAM_MSG_MEMBER(msg, i, msg))) != 0)
1323
fatal("%s: buffer error: %s",
1324
__func__, ssh_err(r));
1325
}
1326
if ((reply[i].resp = strdup("")) == NULL)
1327
goto fail;
1328
reply[i].resp_retcode = PAM_SUCCESS;
1329
break;
1330
default:
1331
goto fail;
1332
}
1333
}
1334
*resp = reply;
1335
return (PAM_SUCCESS);
1336
1337
fail:
1338
for(i = 0; i < n; i++) {
1339
free(reply[i].resp);
1340
}
1341
free(reply);
1342
return (PAM_CONV_ERR);
1343
}
1344
1345
static struct pam_conv passwd_conv = { sshpam_passwd_conv, NULL };
1346
1347
/*
1348
* Attempt password authentication via PAM
1349
*/
1350
int
1351
sshpam_auth_passwd(Authctxt *authctxt, const char *password)
1352
{
1353
int flags = (options.permit_empty_passwd == 0 ?
1354
PAM_DISALLOW_NULL_AUTHTOK : 0);
1355
char *fake = NULL;
1356
1357
if (!options.use_pam || sshpam_handle == NULL)
1358
fatal("PAM: %s called when PAM disabled or failed to "
1359
"initialise.", __func__);
1360
1361
sshpam_password = password;
1362
sshpam_authctxt = authctxt;
1363
1364
/*
1365
* If the user logging in is invalid, or is root but is not permitted
1366
* by PermitRootLogin, use an invalid password to prevent leaking
1367
* information via timing (eg if the PAM config has a delay on fail).
1368
*/
1369
if (!authctxt->valid || (authctxt->pw->pw_uid == 0 &&
1370
options.permit_root_login != PERMIT_YES))
1371
sshpam_password = fake = fake_password(password);
1372
1373
sshpam_err = pam_set_item(sshpam_handle, PAM_CONV,
1374
(const void *)&passwd_conv);
1375
if (sshpam_err != PAM_SUCCESS)
1376
fatal("PAM: %s: failed to set PAM_CONV: %s", __func__,
1377
pam_strerror(sshpam_handle, sshpam_err));
1378
1379
expose_authinfo(__func__);
1380
1381
sshpam_err = pam_authenticate(sshpam_handle, flags);
1382
sshpam_password = NULL;
1383
free(fake);
1384
if (sshpam_err == PAM_MAXTRIES)
1385
sshpam_set_maxtries_reached(1);
1386
if (sshpam_err == PAM_SUCCESS && authctxt->valid) {
1387
debug("PAM: password authentication accepted for %.100s",
1388
authctxt->user);
1389
return 1;
1390
} else {
1391
debug("PAM: password authentication failed for %.100s: %s",
1392
authctxt->valid ? authctxt->user : "an illegal user",
1393
pam_strerror(sshpam_handle, sshpam_err));
1394
return 0;
1395
}
1396
}
1397
1398
int
1399
sshpam_get_maxtries_reached(void)
1400
{
1401
return sshpam_maxtries_reached;
1402
}
1403
1404
void
1405
sshpam_set_maxtries_reached(int reached)
1406
{
1407
if (reached == 0 || sshpam_maxtries_reached)
1408
return;
1409
sshpam_maxtries_reached = 1;
1410
options.password_authentication = 0;
1411
options.kbd_interactive_authentication = 0;
1412
}
1413
#endif /* USE_PAM */
1414
1415