View | Details | Raw Unified | Return to bug 423 | Differences between
and this patch

Collapse All | Expand All

(-)openssh-3.5p1/Makefile.in (-2 / +12 lines)
Lines 25-30 Link Here
25
SFTP_SERVER=$(libexecdir)/sftp-server
25
SFTP_SERVER=$(libexecdir)/sftp-server
26
SSH_KEYSIGN=$(libexecdir)/ssh-keysign
26
SSH_KEYSIGN=$(libexecdir)/ssh-keysign
27
RAND_HELPER=$(libexecdir)/ssh-rand-helper
27
RAND_HELPER=$(libexecdir)/ssh-rand-helper
28
CHAUTHTOK_HELPER=$(libexecdir)/ssh-chauthtok-helper
28
PRIVSEP_PATH=@PRIVSEP_PATH@
29
PRIVSEP_PATH=@PRIVSEP_PATH@
29
SSH_PRIVSEP_USER=@SSH_PRIVSEP_USER@
30
SSH_PRIVSEP_USER=@SSH_PRIVSEP_USER@
30
31
Lines 35-41 Link Here
35
	-D_PATH_SSH_KEY_SIGN=\"$(SSH_KEYSIGN)\" \
36
	-D_PATH_SSH_KEY_SIGN=\"$(SSH_KEYSIGN)\" \
36
	-D_PATH_SSH_PIDDIR=\"$(piddir)\" \
37
	-D_PATH_SSH_PIDDIR=\"$(piddir)\" \
37
	-D_PATH_PRIVSEP_CHROOT_DIR=\"$(PRIVSEP_PATH)\" \
38
	-D_PATH_PRIVSEP_CHROOT_DIR=\"$(PRIVSEP_PATH)\" \
38
	-DSSH_RAND_HELPER=\"$(RAND_HELPER)\"
39
	-DSSH_RAND_HELPER=\"$(RAND_HELPER)\" \
40
	-DSSH_CHAUTHTOK_HELPER=\"$(CHAUTHTOK_HELPER)\"
39
41
40
CC=@CC@
42
CC=@CC@
41
LD=@LD@
43
LD=@LD@
Lines 55-64 Link Here
55
57
56
INSTALL_SSH_PRNG_CMDS=@INSTALL_SSH_PRNG_CMDS@
58
INSTALL_SSH_PRNG_CMDS=@INSTALL_SSH_PRNG_CMDS@
57
INSTALL_SSH_RAND_HELPER=@INSTALL_SSH_RAND_HELPER@
59
INSTALL_SSH_RAND_HELPER=@INSTALL_SSH_RAND_HELPER@
60
INSTALL_SSH_CHAUTHTOK_HELPER=yes
58
61
59
@NO_SFTP@SFTP_PROGS=sftp-server$(EXEEXT) sftp$(EXEEXT)
62
@NO_SFTP@SFTP_PROGS=sftp-server$(EXEEXT) sftp$(EXEEXT)
60
63
61
TARGETS=ssh$(EXEEXT) sshd$(EXEEXT) ssh-add$(EXEEXT) ssh-keygen$(EXEEXT) ssh-keyscan${EXEEXT} ssh-keysign${EXEEXT} ssh-agent$(EXEEXT) scp$(EXEEXT) ssh-rand-helper${EXEEXT} $(SFTP_PROGS)
64
TARGETS=ssh$(EXEEXT) sshd$(EXEEXT) ssh-add$(EXEEXT) ssh-keygen$(EXEEXT) ssh-keyscan${EXEEXT} ssh-keysign${EXEEXT} ssh-agent$(EXEEXT) scp$(EXEEXT) ssh-rand-helper${EXEEXT} ssh-chauthtok-helper${EXEEXT} $(SFTP_PROGS)
62
65
63
LIBSSH_OBJS=atomicio.o authfd.o authfile.o bufaux.o buffer.o canohost.o channels.o cipher.o compat.o compress.o crc32.o deattack.o dh.o dispatch.o fatal.o mac.o msg.o hostfile.o key.o kex.o kexdh.o kexgex.o log.o match.o misc.o mpaux.o nchan.o packet.o radix.o rijndael.o entropy.o readpass.o rsa.o scard.o scard-opensc.o ssh-dss.o ssh-rsa.o tildexpand.o ttymodes.o uidswap.o uuencode.o xmalloc.o monitor_wrap.o monitor_fdpass.o
66
LIBSSH_OBJS=atomicio.o authfd.o authfile.o bufaux.o buffer.o canohost.o channels.o cipher.o compat.o compress.o crc32.o deattack.o dh.o dispatch.o fatal.o mac.o msg.o hostfile.o key.o kex.o kexdh.o kexgex.o log.o match.o misc.o mpaux.o nchan.o packet.o radix.o rijndael.o entropy.o readpass.o rsa.o scard.o scard-opensc.o ssh-dss.o ssh-rsa.o tildexpand.o ttymodes.o uidswap.o uuencode.o xmalloc.o monitor_wrap.o monitor_fdpass.o
64
67
Lines 143-148 Link Here
143
ssh-rand-helper${EXEEXT}: $(LIBCOMPAT) libssh.a ssh-rand-helper.o
146
ssh-rand-helper${EXEEXT}: $(LIBCOMPAT) libssh.a ssh-rand-helper.o
144
	$(LD) -o $@ ssh-rand-helper.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS)
147
	$(LD) -o $@ ssh-rand-helper.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS)
145
148
149
ssh-chauthtok-helper${EXEEXT}: $(LIBCOMPAT) libssh.a ssh-chauthtok-helper.o
150
	$(LD) -o $@ ssh-chauthtok-helper.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBPAM) $(LIBS)
151
146
# test driver for the loginrec code - not built by default
152
# test driver for the loginrec code - not built by default
147
logintest: logintest.o $(LIBCOMPAT) libssh.a loginrec.o
153
logintest: logintest.o $(LIBCOMPAT) libssh.a loginrec.o
148
	$(LD) -o $@ logintest.o $(LDFLAGS) loginrec.o -lopenbsd-compat -lssh $(LIBS)
154
	$(LD) -o $@ logintest.o $(LDFLAGS) loginrec.o -lopenbsd-compat -lssh $(LIBS)
Lines 227-232 Link Here
227
	if test ! -z "$(INSTALL_SSH_RAND_HELPER)" ; then \
233
	if test ! -z "$(INSTALL_SSH_RAND_HELPER)" ; then \
228
		$(INSTALL) -m 0755 -s ssh-rand-helper $(DESTDIR)$(libexecdir)/ssh-rand-helper ; \
234
		$(INSTALL) -m 0755 -s ssh-rand-helper $(DESTDIR)$(libexecdir)/ssh-rand-helper ; \
229
	fi
235
	fi
236
	if test ! -z "$(INSTALL_SSH_CHAUTHTOK_HELPER)" ; then \
237
		$(INSTALL) -m 4711 -s ssh-chauthtok-helper $(DESTDIR)$(libexecdir)/ssh-chauthtok-helper ; \
238
	fi
230
	$(INSTALL) -m 4711 -s ssh-keysign $(DESTDIR)$(SSH_KEYSIGN)
239
	$(INSTALL) -m 4711 -s ssh-keysign $(DESTDIR)$(SSH_KEYSIGN)
231
	@NO_SFTP@$(INSTALL) -m 0755 -s sftp $(DESTDIR)$(bindir)/sftp
240
	@NO_SFTP@$(INSTALL) -m 0755 -s sftp $(DESTDIR)$(bindir)/sftp
232
	@NO_SFTP@$(INSTALL) -m 0755 -s sftp-server $(DESTDIR)$(SFTP_SERVER)
241
	@NO_SFTP@$(INSTALL) -m 0755 -s sftp-server $(DESTDIR)$(SFTP_SERVER)
Lines 330-335 Link Here
330
	-rm -r $(DESTDIR)$(SFTP_SERVER)$(EXEEXT)
339
	-rm -r $(DESTDIR)$(SFTP_SERVER)$(EXEEXT)
331
	-rm -f $(DESTDIR)$(SSH_KEYSIGN)$(EXEEXT)
340
	-rm -f $(DESTDIR)$(SSH_KEYSIGN)$(EXEEXT)
332
	-rm -f $(DESTDIR)$(RAND_HELPER)$(EXEEXT)
341
	-rm -f $(DESTDIR)$(RAND_HELPER)$(EXEEXT)
342
	-rm -f $(DESTDIR)$(CHAUTHTOK_HELPER)$(EXEEXT)
333
	-rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/ssh.1
343
	-rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/ssh.1
334
	-rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/scp.1
344
	-rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/scp.1
335
	-rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/ssh-add.1
345
	-rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/ssh-add.1
(-)openssh-3.5p1/auth-pam.c (-7 / +75 lines)
Lines 33-38 Link Here
33
#include "servconf.h"
33
#include "servconf.h"
34
#include "canohost.h"
34
#include "canohost.h"
35
#include "readpass.h"
35
#include "readpass.h"
36
#include "misc.h"
36
37
37
extern char *__progname;
38
extern char *__progname;
38
39
Lines 43-49 Link Here
43
#define NEW_AUTHTOK_MSG \
44
#define NEW_AUTHTOK_MSG \
44
	"Warning: Your password has expired, please change it now."
45
	"Warning: Your password has expired, please change it now."
45
#define NEW_AUTHTOK_MSG_PRIVSEP \
46
#define NEW_AUTHTOK_MSG_PRIVSEP \
46
	"Your password has expired, the session cannot proceed."
47
	"Warning: Your password has expired, please change it now."
47
48
48
static int do_pam_conversation(int num_msg, const struct pam_message **msg,
49
static int do_pam_conversation(int num_msg, const struct pam_message **msg,
49
	struct pam_response **resp, void *appdata_ptr);
50
	struct pam_response **resp, void *appdata_ptr);
Lines 186-197 Link Here
186
			    pam_retval, PAM_STRERROR(__pamh, pam_retval));
187
			    pam_retval, PAM_STRERROR(__pamh, pam_retval));
187
	}
188
	}
188
189
190
/* HP-UX doesn't like credentials to be deleted. Skip and rely on pam_end() */
191
#ifndef __hpux
189
	if (__pamh && creds_set) {
192
	if (__pamh && creds_set) {
190
		pam_retval = pam_setcred(__pamh, PAM_DELETE_CRED);
193
		pam_retval = pam_setcred(__pamh, PAM_DELETE_CRED);
191
		if (pam_retval != PAM_SUCCESS)
194
		if (pam_retval != PAM_SUCCESS)
192
			debug("Cannot delete credentials[%d]: %.200s", 
195
			debug("Cannot delete credentials[%d]: %.200s", 
193
			    pam_retval, PAM_STRERROR(__pamh, pam_retval));
196
			    pam_retval, PAM_STRERROR(__pamh, pam_retval));
194
	}
197
	}
198
#endif
195
199
196
	if (__pamh) {
200
	if (__pamh) {
197
		pam_retval = pam_end(__pamh, pam_retval);
201
		pam_retval = pam_end(__pamh, pam_retval);
Lines 256-262 Link Here
256
		case PAM_SUCCESS:
260
		case PAM_SUCCESS:
257
			/* This is what we want */
261
			/* This is what we want */
258
			break;
262
			break;
259
#if 0
263
#if 1
260
		case PAM_NEW_AUTHTOK_REQD:
264
		case PAM_NEW_AUTHTOK_REQD:
261
			message_cat(&__pam_msg, use_privsep ?
265
			message_cat(&__pam_msg, use_privsep ?
262
			    NEW_AUTHTOK_MSG_PRIVSEP : NEW_AUTHTOK_MSG);
266
			    NEW_AUTHTOK_MSG_PRIVSEP : NEW_AUTHTOK_MSG);
Lines 301-306 Link Here
301
	session_opened = 1;
305
	session_opened = 1;
302
}
306
}
303
307
308
/* Set the TTY after session is open */
309
void do_pam_set_tty(const char *ttyname) {
310
	int pam_retval;
311
	if (ttyname != NULL) {
312
		debug("PAM setting tty to \"%.200s\"", ttyname);
313
		pam_retval = pam_set_item(__pamh, PAM_TTY, ttyname);
314
		if (pam_retval != PAM_SUCCESS)
315
			fatal("PAM set tty failed[%d]: %.200s",
316
			    pam_retval, PAM_STRERROR(__pamh, pam_retval));
317
	}
318
}
319
304
/* Set PAM credentials */
320
/* Set PAM credentials */
305
void do_pam_setcred(int init)
321
void do_pam_setcred(int init)
306
{
322
{
Lines 331-336 Link Here
331
	return password_change_required;
347
	return password_change_required;
332
}
348
}
333
349
350
/* Call external pam_chauthtok helper */
351
int do_chauthtok_helper(void)
352
{
353
	mysig_t old_sigchld;
354
	pid_t pid;
355
	int retval;
356
	int pam_retval;
357
	const char *pam_user;
358
359
	pam_retval = pam_get_item(__pamh, PAM_USER, (const void **)&pam_user);
360
	debug2("pam_get_item(PAM_USER) = %d", pam_retval);
361
	if (pam_retval != PAM_SUCCESS) {
362
		fatal("Cannot pam_get_item PAM_USER: %.200s",
363
		    PAM_STRERROR(__pamh, pam_retval));
364
	}
365
366
	old_sigchld = mysignal(SIGCHLD, SIG_DFL);
367
368
	pid = fork();
369
	if (pid < 0) {
370
		fatal("Cannot fork %.200s: %.200s", SSH_CHAUTHTOK_HELPER,
371
		    strerror(errno));
372
	}
373
	if (pid == 0) {
374
		execl(SSH_CHAUTHTOK_HELPER, SSH_CHAUTHTOK_HELPER,
375
		    pam_user, (char *)0);
376
		fatal("Cannot execute %.200s: %.200s",
377
		    SSH_CHAUTHTOK_HELPER, strerror(errno));
378
	}
379
380
	if (waitpid(pid, &retval, 0) != pid)
381
		fatal("Cannot get exit status of %.200s (pid %d): %.200s",
382
		    SSH_CHAUTHTOK_HELPER, pid, strerror(errno));
383
384
	mysignal(SIGCHLD, old_sigchld);
385
386
	if (!WIFEXITED(retval)) {
387
       		if (WIFSIGNALED(retval)) {
388
	   		log("%.200s (pid %d) terminated by signal %d",
389
			    SSH_CHAUTHTOK_HELPER, pid, WTERMSIG(retval));
390
		} else {
391
	   		log("%.200s (pid %d) terminated abnormally",
392
			    SSH_CHAUTHTOK_HELPER, pid);
393
		}
394
	   	return 255;
395
	}
396
397
	return WEXITSTATUS(retval);
398
}
399
334
/*
400
/*
335
 * Have user change authentication token if pam_acct_mgmt() indicated
401
 * Have user change authentication token if pam_acct_mgmt() indicated
336
 * it was expired.  This needs to be called after an interactive
402
 * it was expired.  This needs to be called after an interactive
Lines 344-354 Link Here
344
	do_pam_set_conv(&conv);
410
	do_pam_set_conv(&conv);
345
411
346
	if (password_change_required) {
412
	if (password_change_required) {
347
		if (use_privsep)
413
		if (use_privsep) {
348
			fatal("Password changing is currently unsupported"
414
			pam_retval = do_chauthtok_helper();
349
			    " with privilege separation");
415
		} else {
350
		pamstate = OTHER;
416
			pamstate = OTHER;
351
		pam_retval = pam_chauthtok(__pamh, PAM_CHANGE_EXPIRED_AUTHTOK);
417
			pam_retval = pam_chauthtok(__pamh,
418
					 PAM_CHANGE_EXPIRED_AUTHTOK);
419
		}
352
		if (pam_retval != PAM_SUCCESS)
420
		if (pam_retval != PAM_SUCCESS)
353
			fatal("PAM pam_chauthtok failed[%d]: %.200s",
421
			fatal("PAM pam_chauthtok failed[%d]: %.200s",
354
			    pam_retval, PAM_STRERROR(__pamh, pam_retval));
422
			    pam_retval, PAM_STRERROR(__pamh, pam_retval));
(-)openssh-3.5p1/auth-pam.h (+1 lines)
Lines 39-44 Link Here
39
int do_pam_authenticate(int flags);
39
int do_pam_authenticate(int flags);
40
int do_pam_account(char *username, char *remote_user);
40
int do_pam_account(char *username, char *remote_user);
41
void do_pam_session(char *username, const char *ttyname);
41
void do_pam_session(char *username, const char *ttyname);
42
void do_pam_set_tty(const char *ttyname);
42
void do_pam_setcred(int init);
43
void do_pam_setcred(int init);
43
void print_pam_messages(void);
44
void print_pam_messages(void);
44
int is_pam_password_change_required(void);
45
int is_pam_password_change_required(void);
(-)openssh-3.5p1/session.c (-2 / +8 lines)
Lines 454-460 Link Here
454
	session_proctitle(s);
454
	session_proctitle(s);
455
455
456
#if defined(USE_PAM)
456
#if defined(USE_PAM)
457
	do_pam_session(s->pw->pw_name, NULL);
458
	do_pam_setcred(1);
457
	do_pam_setcred(1);
459
	if (is_pam_password_change_required())
458
	if (is_pam_password_change_required())
460
		packet_disconnect("Password change required but no "
459
		packet_disconnect("Password change required but no "
Lines 581-587 Link Here
581
	ttyfd = s->ttyfd;
580
	ttyfd = s->ttyfd;
582
581
583
#if defined(USE_PAM)
582
#if defined(USE_PAM)
584
	do_pam_session(s->pw->pw_name, s->tty);
583
	do_pam_set_tty(s->tty);
585
	do_pam_setcred(1);
584
	do_pam_setcred(1);
586
#endif
585
#endif
587
586
Lines 1238-1243 Link Here
1238
		 * Reestablish them here.
1237
		 * Reestablish them here.
1239
		 */
1238
		 */
1240
		do_pam_setcred(0);
1239
		do_pam_setcred(0);
1240
1241
		/*
1242
		 * We need to open the session here because PAM on HP-UX does not
1243
		 * work after the call to permanently_set_uid.
1244
		 */
1245
		do_pam_session(pw->pw_name,NULL);
1246
1241
# endif /* USE_PAM */
1247
# endif /* USE_PAM */
1242
# if defined(WITH_IRIX_PROJECT) || defined(WITH_IRIX_JOBS) || defined(WITH_IRIX_ARRAY)
1248
# if defined(WITH_IRIX_PROJECT) || defined(WITH_IRIX_JOBS) || defined(WITH_IRIX_ARRAY)
1243
		irix_setusercontext(pw);
1249
		irix_setusercontext(pw);
(-)openssh-3.5p1/ssh-chauthtok-helper.c (+270 lines)
Line 0 Link Here
1
/*
2
 * Copyright (c) 2002 Michael Steffens.  All rights reserved.
3
 *
4
 * Derived from auth-pam.c,
5
 * Copyright (c) 2000 Damien Miller.  All rights reserved.
6
 *
7
 * Redistribution and use in source and binary forms, with or without
8
 * modification, are permitted provided that the following conditions
9
 * are met:
10
 * 1. Redistributions of source code must retain the above copyright
11
 *    notice, this list of conditions and the following disclaimer.
12
 * 2. Redistributions in binary form must reproduce the above copyright
13
 *    notice, this list of conditions and the following disclaimer in the
14
 *    documentation and/or other materials provided with the distribution.
15
 *
16
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26
 */
27
28
/*
29
 * This program provides a workaround for sshd presently not supporting
30
 * user changes of expired passwords when running in privsep mode.
31
 *
32
 * When encountering an expired authentication token, the non-privileged
33
 * session daemon can delegate change to ssh-chauthtok-helper, which
34
 * should be installed suid root for performing this task.
35
 *
36
 * It is somewhat similar to the system passwd program, but dedicatedly
37
 * talks to modules configured for PAM service "sshd", rather than those
38
 * configured for passwd. These might be the same, but can also be
39
 * different.
40
 *
41
 * By nature this helper program can also be invoked by local users
42
 * directly, just as the passwd program can.  But in any case
43
 *
44
 * - non-root users can only change their own authentication tokens.
45
 *
46
 * - root users can change authentication tokens for others, but only
47
 *   with providing the old token.
48
 *
49
 * The second restriction is meant to be a fuse against the helper program
50
 * being accidentally invoked by a privileged daemon...
51
 *
52
 * The ssh-chauthtok-helper program unfortunately can't safely deal
53
 * with the PAM_RUSER and PAM_RHOST items, because there is no way of
54
 * preventing local users to feed in arbitrary values for these.
55
 * They are being left undefined here, relying on modules and their
56
 * configuration to decide whether to accept requests from unknown users
57
 * at unknown hosts.  (Always provided they have authenticated for the
58
 * local account, of course!)
59
 */
60
61
#include "includes.h"
62
63
#ifdef USE_PAM
64
65
#include "xmalloc.h"
66
#include "log.h"
67
#include "readpass.h"
68
69
#define SSHD_PAM_SERVICE "sshd"
70
71
#ifdef HAVE___PROGNAME
72
extern char *__progname;
73
#else
74
char *__progname;
75
#endif
76
77
int null_pam_conv;
78
79
/*
80
 * This is a downstripped version of do_pam_conversation() in pam-auth.c,
81
 * with the INITIAL_LOGIN mode removed.  At the time this program can be
82
 * run we already are authenticated and do have STDIN available.
83
 * The null_pam_conv flag enforces modules to be silent even if
84
 * they do not honor the PAM_SILENT flag.  We just don't need to tell
85
 * the user again that passwords are expired when calling pam_acct_mgmt(),
86
 * as this has already been done by the calling daemon.
87
 */
88
static int do_pam_conversation(int num_msg, const struct pam_message **msg,
89
	struct pam_response **resp, void *appdata_ptr)
90
{
91
	struct pam_response *reply;
92
	int count;
93
	char buf[1024];
94
95
	/* PAM will free this later */
96
	reply = xmalloc(num_msg * sizeof(*reply));
97
98
	for (count = 0; count < num_msg; count++) {
99
	       	/*
100
	       	 * stdio is connected, so interact directly
101
	       	 */
102
	       	switch(PAM_MSG_MEMBER(msg, count, msg_style)) {
103
	       	case PAM_PROMPT_ECHO_ON:
104
			if (null_pam_conv) {
105
				xfree(reply);
106
				return PAM_CONV_ERR;
107
			}
108
	       		fputs(PAM_MSG_MEMBER(msg, count, msg), stderr);
109
	       		fgets(buf, sizeof(buf), stdin);
110
	       		reply[count].resp = xstrdup(buf);
111
	       		reply[count].resp_retcode = PAM_SUCCESS;
112
	       		break;
113
	       	case PAM_PROMPT_ECHO_OFF:
114
			if (null_pam_conv) {
115
				xfree(reply);
116
				return PAM_CONV_ERR;
117
			}
118
	       		/*
119
			 * Lets's be a bit more paranoid than the original and
120
			 * avoid the read_passphrase() wrapper.  There is no
121
			 * need to care for non-tty, and eventually call
122
			 * ssh-askpass, as we don't have X11-forwarding at
123
			 * this point anyway.
124
			 */
125
	       		if (readpassphrase(PAM_MSG_MEMBER(msg, count, msg),
126
				buf, sizeof(buf), RPP_REQUIRE_TTY)) {
127
	       			reply[count].resp = xstrdup(buf);
128
	       		} else {
129
				reply[count].resp = xstrdup("");
130
	       		}
131
	       		memset(buf, 'x', sizeof(buf));
132
	       		reply[count].resp_retcode = PAM_SUCCESS;
133
	       		break;
134
	       	case PAM_ERROR_MSG:
135
	       	case PAM_TEXT_INFO:
136
	       		if (!null_pam_conv && PAM_MSG_MEMBER(msg, count, msg) != NULL)
137
	       			fprintf(stderr, "%s\n",
138
	       			    PAM_MSG_MEMBER(msg, count, msg));
139
	       		reply[count].resp = xstrdup("");
140
	       		reply[count].resp_retcode = PAM_SUCCESS;
141
	       		break;
142
	       	default:
143
	       		xfree(reply);
144
	       		return PAM_CONV_ERR;
145
	       	}
146
	}
147
148
	*resp = reply;
149
150
	return PAM_SUCCESS;
151
}
152
153
int main(int argc, char *argv[]) {
154
	struct passwd *pw;
155
	uid_t uid;
156
	uid_t euid;
157
	struct pam_conv conv = {
158
		(int (*)())do_pam_conversation,
159
		NULL
160
	};
161
	pam_handle_t *pamh;
162
	int pam_retval;
163
	int retval = 0;
164
165
        __progname = get_progname(argv[0]);
166
	log_init(__progname, SYSLOG_LEVEL_INFO,
167
		 SYSLOG_FACILITY_AUTH, 0);
168
169
	uid = getuid();
170
	euid = geteuid();
171
	if (euid != 0)
172
		fatal("Cannot change authtok using effective uid %ld", (long)euid);
173
174
	switch (argc) {
175
	case 2:
176
		if (!(pw = getpwnam(argv[1])))
177
			fatal("Cannot get uid of user %.200s: %.200s",
178
			    argv[1], strerror(errno));
179
		if (uid && pw->pw_uid != uid)
180
			fatal("Cannot chauthtok for user %.200s using uid %ld",
181
			    argv[1], (long)uid);
182
		break;
183
	default:
184
		fprintf(stderr, "Usage: ssh-chauthtok-helper <user>\n");
185
		return 1;
186
	}
187
188
	/* drop root real uid when changing authtok for another user */
189
	if (!uid && setuid(uid = pw->pw_uid))
190
		fatal("Cannot setuid %ld: %.200s", (long)uid, strerror(errno));
191
192
	null_pam_conv = 1;
193
194
	pam_retval = pam_start(SSHD_PAM_SERVICE, pw->pw_name, &conv, &pamh);
195
	switch (pam_retval) {
196
	case PAM_SUCCESS:
197
		break;
198
	default:
199
		fatal("PAM initialisation failed[%d]: %.200s",
200
		    pam_retval, PAM_STRERROR(pamh, pam_retval));
201
		break;
202
	}
203
204
	/*
205
	 * Some PAM implemetations (HP-UX) require pam_acct_mgmt() to
206
	 * be invoked before they can identify expired tokens on
207
	 * pam_chauthtok().
208
	 */
209
	pam_retval = pam_acct_mgmt(pamh, PAM_DISALLOW_NULL_AUTHTOK);
210
	switch (pam_retval) {
211
	case PAM_SUCCESS:
212
		/*
213
                 * We were called for changing expired authentication
214
		 * tokens and found nothing to do!  The caller should not
215
		 * consider this success...
216
		 */
217
		log("No expired authentication tokens found");
218
		retval = 255;
219
		break;
220
	case PAM_NEW_AUTHTOK_REQD:
221
		break;
222
	default:
223
		fatal("PAM pam_acct_mgmt failed[%d]: %.200s",
224
		    pam_retval, PAM_STRERROR(pamh, pam_retval));
225
		break;
226
	}
227
228
	/*
229
	 * pam_chauthtok() will perform authentication of its own, if required.
230
	 * For password change it will prompt for the old password only if
231
	 * the real uid is non-zero and the effective uid is zero.  It doesn't
232
	 * work with the effective uid being non-zero, which is why this
233
	 * program exists...
234
	 */
235
	if (!retval) {
236
		null_pam_conv = 0;
237
		pam_retval = pam_chauthtok(pamh, PAM_CHANGE_EXPIRED_AUTHTOK);
238
		switch (pam_retval) {
239
		case PAM_SUCCESS:
240
			break;
241
		default:
242
			log("PAM pam_chauthtok failed[%d]: %.200s",
243
			    pam_retval, PAM_STRERROR(pamh, pam_retval));
244
			break;
245
		}
246
		retval = pam_retval;
247
		null_pam_conv = 1;
248
	}
249
250
	pam_retval = pam_end(pamh, pam_retval);
251
	switch (pam_retval) {
252
	case PAM_SUCCESS:
253
		break;
254
	default:
255
		log("PAM pam_end failed[%d]: %.200s",
256
		    pam_retval, PAM_STRERROR(pamh, pam_retval));
257
		break;
258
	}
259
260
	return retval;
261
}
262
263
#else /* USE_PAM */
264
265
int main(int argc, char *argv[]) {
266
	fprintf(stderr, "Sorry, no PAM support...\n");
267
	return -1;
268
}
269
270
#endif /* USE_PAM */

Return to bug 423