diff options
-rw-r--r-- | ChangeLog | 3 | ||||
-rw-r--r-- | Makefile.in | 21 | ||||
-rw-r--r-- | auth-pam.c | 239 | ||||
-rw-r--r-- | auth-pam.h | 15 | ||||
-rw-r--r-- | bsd-misc.c | 22 | ||||
-rw-r--r-- | bsd-misc.h | 13 | ||||
-rw-r--r-- | defines.h | 8 | ||||
-rw-r--r-- | includes.h | 7 | ||||
-rw-r--r-- | ssh.h | 6 | ||||
-rw-r--r-- | sshd.c | 321 |
10 files changed, 374 insertions, 281 deletions
@@ -2,6 +2,9 @@ | |||
2 | - OpenBSD CVS updates: | 2 | - OpenBSD CVS updates: |
3 | - [auth-passwd.c] | 3 | - [auth-passwd.c] |
4 | check for NULL 1st | 4 | check for NULL 1st |
5 | - Removed most of the pam code into its own file auth-pam.[ch]. This | ||
6 | cleaned up sshd.c up significantly. | ||
7 | - Several other cleanups | ||
5 | 8 | ||
6 | 19991229 | 9 | 19991229 |
7 | - Applied another NetBSD portability patch from David Rankin | 10 | - Applied another NetBSD portability patch from David Rankin |
diff --git a/Makefile.in b/Makefile.in index 050032277..3364a20ad 100644 --- a/Makefile.in +++ b/Makefile.in | |||
@@ -31,7 +31,7 @@ LDFLAGS=-L. @LDFLAGS@ | |||
31 | GNOME_CFLAGS=`gnome-config --cflags gnome gnomeui` | 31 | GNOME_CFLAGS=`gnome-config --cflags gnome gnomeui` |
32 | GNOME_LIBS=`gnome-config --libs gnome gnomeui` | 32 | GNOME_LIBS=`gnome-config --libs gnome gnomeui` |
33 | 33 | ||
34 | OBJS= atomicio.o authfd.o authfile.o auth-krb4.o auth-passwd.o \ | 34 | OBJS= atomicio.o authfd.o authfile.o auth-krb4.o auth-passwd.o auth-pam.o \ |
35 | auth-rhosts.o auth-rh-rsa.o auth-rsa.o auth-skey.o bsd-daemon.o \ | 35 | auth-rhosts.o auth-rh-rsa.o auth-rsa.o auth-skey.o bsd-daemon.o \ |
36 | bsd-login.o bsd-misc.o bsd-mktemp.o bsd-snprintf.o bsd-strlcat.o \ | 36 | bsd-login.o bsd-misc.o bsd-mktemp.o bsd-snprintf.o bsd-strlcat.o \ |
37 | bsd-strlcpy.o bufaux.o buffer.o canohost.o channels.o cipher.o \ | 37 | bsd-strlcpy.o bufaux.o buffer.o canohost.o channels.o cipher.o \ |
@@ -48,6 +48,12 @@ LIBOBJS= atomicio.o authfd.o authfile.o bsd-daemon.o bsd-misc.o \ | |||
48 | packet.o radix.o readpass.o rsa.o tildexpand.o ttymodes.o uidswap.o \ | 48 | packet.o radix.o readpass.o rsa.o tildexpand.o ttymodes.o uidswap.o \ |
49 | xmalloc.o | 49 | xmalloc.o |
50 | 50 | ||
51 | SSHOBJS= ssh.o sshconnect.o log-client.o readconf.o clientloop.o | ||
52 | |||
53 | SSHDOBJS= sshd.o auth-rhosts.o auth-krb4.o auth-pam.o auth-passwd.o \ | ||
54 | auth-rsa.o auth-rh-rsa.o pty.o log-server.o login.o servconf.o \ | ||
55 | serverloop.o bsd-login.o md5crypt.o | ||
56 | |||
51 | all: $(OBJS) $(TARGETS) manpages | 57 | all: $(OBJS) $(TARGETS) manpages |
52 | 58 | ||
53 | $(OBJS): config.h | 59 | $(OBJS): config.h |
@@ -58,16 +64,11 @@ libssh.a: $(LIBOBJS) | |||
58 | $(AR) rv $@ $(LIBOBJS) | 64 | $(AR) rv $@ $(LIBOBJS) |
59 | $(RANLIB) $@ | 65 | $(RANLIB) $@ |
60 | 66 | ||
61 | ssh: ssh.o sshconnect.o log-client.o readconf.o clientloop.o libssh.a | 67 | ssh: $(SSHOBJS) libssh.a |
62 | $(CC) -o $@ ssh.o sshconnect.o log-client.o readconf.o \ | 68 | $(CC) -o $@ $(SSHOBJS) $(LDFLAGS) -lssh $(LIBS) |
63 | clientloop.o $(LDFLAGS) -lssh $(LIBS) | ||
64 | 69 | ||
65 | sshd: sshd.o auth-rhosts.o auth-krb4.o auth-passwd.o auth-rsa.o \ | 70 | sshd: $(SSHDOBJS) libssh.a |
66 | auth-rh-rsa.o pty.o log-server.o login.o servconf.o serverloop.o \ | 71 | $(CC) -o $@ $(SSHDOBJS) $(LDFLAGS) -lssh $(LIBS) $(LIBWRAP) |
67 | bsd-login.o md5crypt.o libssh.a | ||
68 | $(CC) -o $@ sshd.o auth-rhosts.o auth-krb4.o auth-passwd.o \ | ||
69 | auth-rsa.o auth-rh-rsa.o pty.o log-server.o login.o servconf.o \ | ||
70 | serverloop.o bsd-login.o md5crypt.o $(LDFLAGS) -lssh $(LIBS) $(LIBWRAP) | ||
71 | 72 | ||
72 | scp: scp.o libssh.a | 73 | scp: scp.o libssh.a |
73 | $(CC) -o $@ scp.o $(LDFLAGS) -lssh $(LIBS) | 74 | $(CC) -o $@ scp.o $(LDFLAGS) -lssh $(LIBS) |
diff --git a/auth-pam.c b/auth-pam.c new file mode 100644 index 000000000..8d872689c --- /dev/null +++ b/auth-pam.c | |||
@@ -0,0 +1,239 @@ | |||
1 | /* | ||
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 | |||
16 | RCSID("$Id: auth-pam.c,v 1.1 1999/12/30 04:11:25 damien Exp $"); | ||
17 | |||
18 | /* Callbacks */ | ||
19 | static int pamconv(int num_msg, const struct pam_message **msg, | ||
20 | struct pam_response **resp, void *appdata_ptr); | ||
21 | void pam_cleanup_proc(void *context); | ||
22 | |||
23 | /* module-local variables */ | ||
24 | static struct pam_conv conv = { | ||
25 | pamconv, | ||
26 | NULL | ||
27 | }; | ||
28 | static struct pam_handle_t *pamh = NULL; | ||
29 | static const char *pampasswd = NULL; | ||
30 | static 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 */ | ||
34 | static 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 */ | ||
94 | void 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 */ | ||
121 | int 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 */ | ||
148 | int 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 */ | ||
177 | void do_pam_session(char *username, char *ttyname) | ||
178 | { | ||
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 */ | ||
194 | void 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 */ | ||
205 | void 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 */ | ||
212 | void start_pam(struct passwd *pw) | ||
213 | { | ||
214 | int pam_retval; | ||
215 | |||
216 | debug("Starting up PAM with username \"%.200s\"", pw->pw_name); | ||
217 | |||
218 | pam_retval = pam_start("sshd", pw->pw_name, &conv, (pam_handle_t**)&pamh); | ||
219 | if (pam_retval != PAM_SUCCESS) | ||
220 | fatal("PAM initialisation failed: %.200s", PAM_STRERROR((pam_handle_t *)pamh, pam_retval)); | ||
221 | |||
222 | fatal_add_cleanup(&pam_cleanup_proc, NULL); | ||
223 | } | ||
224 | |||
225 | /* Return list of PAM enviornment strings */ | ||
226 | char **fetch_pam_environment(void) | ||
227 | { | ||
228 | return(pam_getenvlist((pam_handle_t *)pamh)); | ||
229 | } | ||
230 | |||
231 | /* Print any messages that have been generated during authentication */ | ||
232 | /* or account checking to stderr */ | ||
233 | void print_pam_messages(void) | ||
234 | { | ||
235 | if (pamconv_msg != NULL) | ||
236 | fprintf(stderr, pamconv_msg); | ||
237 | } | ||
238 | |||
239 | #endif /* USE_PAM */ | ||
diff --git a/auth-pam.h b/auth-pam.h new file mode 100644 index 000000000..1f3bc252f --- /dev/null +++ b/auth-pam.h | |||
@@ -0,0 +1,15 @@ | |||
1 | #include "includes.h" | ||
2 | #ifdef USE_PAM | ||
3 | |||
4 | #include <pwd.h> /* For struct passwd */ | ||
5 | |||
6 | void start_pam(struct passwd *pw); | ||
7 | void finish_pam(void); | ||
8 | int auth_pam_password(struct passwd *pw, const char *password); | ||
9 | char **fetch_pam_environment(void); | ||
10 | int do_pam_account(char *username, char *remote_user); | ||
11 | void do_pam_session(char *username, char *ttyname); | ||
12 | void do_pam_setcred(); | ||
13 | void print_pam_messages(void); | ||
14 | |||
15 | #endif /* USE_PAM */ | ||
diff --git a/bsd-misc.c b/bsd-misc.c index c952fd0f3..0ffe5168b 100644 --- a/bsd-misc.c +++ b/bsd-misc.c | |||
@@ -212,3 +212,25 @@ int setenv(const char *name, const char *value, int overwrite) | |||
212 | return(result); | 212 | return(result); |
213 | } | 213 | } |
214 | #endif /* !HAVE_SETENV */ | 214 | #endif /* !HAVE_SETENV */ |
215 | |||
216 | #ifndef HAVE_SETLOGIN | ||
217 | int setlogin(const char *name) | ||
218 | { | ||
219 | return(0); | ||
220 | } | ||
221 | #endif /* !HAVE_SETLOGIN */ | ||
222 | |||
223 | #ifndef HAVE_INNETGR | ||
224 | int innetgr(const char *netgroup, const char *host, | ||
225 | const char *user, const char *domain) | ||
226 | { | ||
227 | return(0); | ||
228 | } | ||
229 | #endif /* HAVE_INNETGR */ | ||
230 | |||
231 | #if !defined(HAVE_SETEUID) && defined(HAVE_SETREUID) | ||
232 | int seteuid(uid_t euid) | ||
233 | { | ||
234 | return(setreuid(-1,euid)); | ||
235 | } | ||
236 | #endif /* !defined(HAVE_SETEUID) && defined(HAVE_SETREUID) */ | ||
diff --git a/bsd-misc.h b/bsd-misc.h index 990dd408e..fabaa00b3 100644 --- a/bsd-misc.h +++ b/bsd-misc.h | |||
@@ -51,4 +51,17 @@ void setproctitle(const char *fmt, ...); | |||
51 | int setenv(const char *name, const char *value, int overwrite); | 51 | int setenv(const char *name, const char *value, int overwrite); |
52 | #endif /* !HAVE_SETENV */ | 52 | #endif /* !HAVE_SETENV */ |
53 | 53 | ||
54 | #ifndef HAVE_SETLOGIN | ||
55 | int setlogin(const char *name); | ||
56 | #endif /* !HAVE_SETLOGIN */ | ||
57 | |||
58 | #ifndef HAVE_INNETGR | ||
59 | int innetgr(const char *netgroup, const char *host, | ||
60 | const char *user, const char *domain); | ||
61 | #endif /* HAVE_INNETGR */ | ||
62 | |||
63 | #if !defined(HAVE_SETEUID) && defined(HAVE_SETREUID) | ||
64 | int seteuid(uid_t euid); | ||
65 | #endif /* !defined(HAVE_SETEUID) && defined(HAVE_SETREUID) */ | ||
66 | |||
54 | #endif /* _BSD_MISC_H */ | 67 | #endif /* _BSD_MISC_H */ |
@@ -226,11 +226,3 @@ typedef unsigned int size_t; | |||
226 | # define PAM_STRERROR(a,b) pam_strerror((a),(b)) | 226 | # define PAM_STRERROR(a,b) pam_strerror((a),(b)) |
227 | #endif | 227 | #endif |
228 | 228 | ||
229 | #if !defined(HAVE_SETEUID) && defined(HAVE_SETREUID) | ||
230 | # define seteuid(a) setreuid(-1,a) | ||
231 | #endif /* !defined(HAVE_SETEUID) && defined(HAVE_SETREUID) */ | ||
232 | |||
233 | #ifndef HAVE_INNETGR | ||
234 | # define innetgr(a,b,c,d) (0) | ||
235 | #endif /* HAVE_INNETGR */ | ||
236 | |||
diff --git a/includes.h b/includes.h index 3fe76553b..bc7db419a 100644 --- a/includes.h +++ b/includes.h | |||
@@ -79,6 +79,13 @@ static /**/const char *const rcsid[] = { (char *)rcsid, "\100(#)" msg } | |||
79 | #ifdef USE_PAM | 79 | #ifdef USE_PAM |
80 | # include <security/pam_appl.h> | 80 | # include <security/pam_appl.h> |
81 | #endif | 81 | #endif |
82 | #ifdef HAVE_POLL_H | ||
83 | # include <poll.h> | ||
84 | #else | ||
85 | # ifdef HAVE_SYS_POLL_H | ||
86 | # include <sys/poll.h> | ||
87 | # endif | ||
88 | #endif | ||
82 | 89 | ||
83 | #include "version.h" | 90 | #include "version.h" |
84 | #include "bsd-misc.h" | 91 | #include "bsd-misc.h" |
@@ -13,7 +13,7 @@ | |||
13 | * | 13 | * |
14 | */ | 14 | */ |
15 | 15 | ||
16 | /* RCSID("$Id: ssh.h,v 1.21 1999/12/21 13:12:39 damien Exp $"); */ | 16 | /* RCSID("$Id: ssh.h,v 1.22 1999/12/30 04:08:44 damien Exp $"); */ |
17 | 17 | ||
18 | #ifndef SSH_H | 18 | #ifndef SSH_H |
19 | #define SSH_H | 19 | #define SSH_H |
@@ -741,4 +741,8 @@ char *skey_fake_keyinfo(char *username); | |||
741 | int auth_skey_password(struct passwd * pw, const char *password); | 741 | int auth_skey_password(struct passwd * pw, const char *password); |
742 | #endif /* SKEY */ | 742 | #endif /* SKEY */ |
743 | 743 | ||
744 | #ifdef USE_PAM | ||
745 | #include "auth-pam.h" | ||
746 | #endif /* USE_PAM */ | ||
747 | |||
744 | #endif /* SSH_H */ | 748 | #endif /* SSH_H */ |
@@ -11,15 +11,7 @@ | |||
11 | */ | 11 | */ |
12 | 12 | ||
13 | #include "includes.h" | 13 | #include "includes.h" |
14 | RCSID("$Id: sshd.c,v 1.48 1999/12/28 23:25:41 damien Exp $"); | 14 | RCSID("$Id: sshd.c,v 1.49 1999/12/30 04:08:44 damien Exp $"); |
15 | |||
16 | #ifdef HAVE_POLL_H | ||
17 | # include <poll.h> | ||
18 | #else /* HAVE_POLL_H */ | ||
19 | # ifdef HAVE_SYS_POLL_H | ||
20 | # include <sys/poll.h> | ||
21 | # endif /* HAVE_SYS_POLL_H */ | ||
22 | #endif /* HAVE_POLL_H */ | ||
23 | 15 | ||
24 | #include "xmalloc.h" | 16 | #include "xmalloc.h" |
25 | #include "rsa.h" | 17 | #include "rsa.h" |
@@ -143,183 +135,6 @@ void do_child(const char *command, struct passwd * pw, const char *term, | |||
143 | const char *display, const char *auth_proto, | 135 | const char *display, const char *auth_proto, |
144 | const char *auth_data, const char *ttyname); | 136 | const char *auth_data, const char *ttyname); |
145 | 137 | ||
146 | #ifdef USE_PAM | ||
147 | static int pamconv(int num_msg, const struct pam_message **msg, | ||
148 | struct pam_response **resp, void *appdata_ptr); | ||
149 | int do_pam_auth(const char *user, const char *password); | ||
150 | void do_pam_account(char *username, char *remote_user); | ||
151 | void do_pam_session(char *username, char *ttyname); | ||
152 | void do_pam_setcred(); | ||
153 | void pam_cleanup_proc(void *context); | ||
154 | |||
155 | static struct pam_conv conv = { | ||
156 | pamconv, | ||
157 | NULL | ||
158 | }; | ||
159 | struct pam_handle_t *pamh = NULL; | ||
160 | const char *pampasswd = NULL; | ||
161 | char *pamconv_msg = NULL; | ||
162 | |||
163 | static int pamconv(int num_msg, const struct pam_message **msg, | ||
164 | struct pam_response **resp, void *appdata_ptr) | ||
165 | { | ||
166 | struct pam_response *reply; | ||
167 | int count; | ||
168 | size_t msg_len; | ||
169 | char *p; | ||
170 | |||
171 | /* PAM will free this later */ | ||
172 | reply = malloc(num_msg * sizeof(*reply)); | ||
173 | if (reply == NULL) | ||
174 | return PAM_CONV_ERR; | ||
175 | |||
176 | for(count = 0; count < num_msg; count++) { | ||
177 | switch (msg[count]->msg_style) { | ||
178 | case PAM_PROMPT_ECHO_OFF: | ||
179 | if (pampasswd == NULL) { | ||
180 | free(reply); | ||
181 | return PAM_CONV_ERR; | ||
182 | } | ||
183 | reply[count].resp_retcode = PAM_SUCCESS; | ||
184 | reply[count].resp = xstrdup(pampasswd); | ||
185 | break; | ||
186 | |||
187 | case PAM_TEXT_INFO: | ||
188 | reply[count].resp_retcode = PAM_SUCCESS; | ||
189 | reply[count].resp = xstrdup(""); | ||
190 | |||
191 | if (msg[count]->msg == NULL) | ||
192 | break; | ||
193 | |||
194 | debug("Adding PAM message: %s", msg[count]->msg); | ||
195 | |||
196 | msg_len = strlen(msg[count]->msg); | ||
197 | if (pamconv_msg) { | ||
198 | size_t n = strlen(pamconv_msg); | ||
199 | pamconv_msg = xrealloc(pamconv_msg, n + msg_len + 2); | ||
200 | p = pamconv_msg + n; | ||
201 | } else { | ||
202 | pamconv_msg = p = xmalloc(msg_len + 2); | ||
203 | } | ||
204 | memcpy(p, msg[count]->msg, msg_len); | ||
205 | p[msg_len] = '\n'; | ||
206 | p[msg_len + 1] = '\0'; | ||
207 | break; | ||
208 | |||
209 | case PAM_PROMPT_ECHO_ON: | ||
210 | case PAM_ERROR_MSG: | ||
211 | default: | ||
212 | free(reply); | ||
213 | return PAM_CONV_ERR; | ||
214 | } | ||
215 | } | ||
216 | |||
217 | *resp = reply; | ||
218 | |||
219 | return PAM_SUCCESS; | ||
220 | } | ||
221 | |||
222 | void pam_cleanup_proc(void *context) | ||
223 | { | ||
224 | int pam_retval; | ||
225 | |||
226 | if (pamh != NULL) | ||
227 | { | ||
228 | pam_retval = pam_close_session((pam_handle_t *)pamh, 0); | ||
229 | if (pam_retval != PAM_SUCCESS) { | ||
230 | log("Cannot close PAM session: %.200s", | ||
231 | PAM_STRERROR((pam_handle_t *)pamh, pam_retval)); | ||
232 | } | ||
233 | |||
234 | pam_retval = pam_setcred((pam_handle_t *)pamh, PAM_DELETE_CRED); | ||
235 | if (pam_retval != PAM_SUCCESS) { | ||
236 | log("Cannot delete credentials: %.200s", | ||
237 | PAM_STRERROR((pam_handle_t *)pamh, pam_retval)); | ||
238 | } | ||
239 | |||
240 | pam_retval = pam_end((pam_handle_t *)pamh, pam_retval); | ||
241 | if (pam_retval != PAM_SUCCESS) { | ||
242 | log("Cannot release PAM authentication: %.200s", | ||
243 | PAM_STRERROR((pam_handle_t *)pamh, pam_retval)); | ||
244 | } | ||
245 | } | ||
246 | } | ||
247 | |||
248 | int do_pam_auth(const char *user, const char *password) | ||
249 | { | ||
250 | int pam_retval; | ||
251 | |||
252 | if ((options.permit_empty_passwd == 0) && (password[0] == '\0')) | ||
253 | return 0; | ||
254 | |||
255 | pampasswd = password; | ||
256 | |||
257 | pam_retval = pam_authenticate((pam_handle_t *)pamh, 0); | ||
258 | if (pam_retval == PAM_SUCCESS) { | ||
259 | debug("PAM Password authentication accepted for user \"%.100s\"", user); | ||
260 | return 1; | ||
261 | } else { | ||
262 | debug("PAM Password authentication for \"%.100s\" failed: %s", | ||
263 | user, PAM_STRERROR((pam_handle_t *)pamh, pam_retval)); | ||
264 | return 0; | ||
265 | } | ||
266 | } | ||
267 | |||
268 | void do_pam_account(char *username, char *remote_user) | ||
269 | { | ||
270 | int pam_retval; | ||
271 | |||
272 | debug("PAM setting rhost to \"%.200s\"", get_canonical_hostname()); | ||
273 | pam_retval = pam_set_item((pam_handle_t *)pamh, PAM_RHOST, | ||
274 | get_canonical_hostname()); | ||
275 | if (pam_retval != PAM_SUCCESS) { | ||
276 | log("PAM set rhost failed: %.200s", PAM_STRERROR((pam_handle_t *)pamh, pam_retval)); | ||
277 | do_fake_authloop(username); | ||
278 | } | ||
279 | |||
280 | if (remote_user != NULL) { | ||
281 | debug("PAM setting ruser to \"%.200s\"", remote_user); | ||
282 | pam_retval = pam_set_item((pam_handle_t *)pamh, PAM_RUSER, remote_user); | ||
283 | if (pam_retval != PAM_SUCCESS) { | ||
284 | log("PAM set ruser failed: %.200s", PAM_STRERROR((pam_handle_t *)pamh, pam_retval)); | ||
285 | do_fake_authloop(username); | ||
286 | } | ||
287 | } | ||
288 | |||
289 | pam_retval = pam_acct_mgmt((pam_handle_t *)pamh, 0); | ||
290 | if (pam_retval != PAM_SUCCESS) { | ||
291 | log("PAM rejected by account configuration: %.200s", PAM_STRERROR((pam_handle_t *)pamh, pam_retval)); | ||
292 | do_fake_authloop(username); | ||
293 | } | ||
294 | } | ||
295 | |||
296 | void do_pam_session(char *username, char *ttyname) | ||
297 | { | ||
298 | int pam_retval; | ||
299 | |||
300 | if (ttyname != NULL) { | ||
301 | debug("PAM setting tty to \"%.200s\"", ttyname); | ||
302 | pam_retval = pam_set_item((pam_handle_t *)pamh, PAM_TTY, ttyname); | ||
303 | if (pam_retval != PAM_SUCCESS) | ||
304 | fatal("PAM set tty failed: %.200s", PAM_STRERROR((pam_handle_t *)pamh, pam_retval)); | ||
305 | } | ||
306 | |||
307 | pam_retval = pam_open_session((pam_handle_t *)pamh, 0); | ||
308 | if (pam_retval != PAM_SUCCESS) | ||
309 | fatal("PAM session setup failed: %.200s", PAM_STRERROR((pam_handle_t *)pamh, pam_retval)); | ||
310 | } | ||
311 | |||
312 | void do_pam_setcred() | ||
313 | { | ||
314 | int pam_retval; | ||
315 | |||
316 | debug("PAM establishing creds"); | ||
317 | pam_retval = pam_setcred((pam_handle_t *)pamh, PAM_ESTABLISH_CRED); | ||
318 | if (pam_retval != PAM_SUCCESS) | ||
319 | fatal("PAM setcred failed: %.200s", PAM_STRERROR((pam_handle_t *)pamh, pam_retval)); | ||
320 | } | ||
321 | #endif /* USE_PAM */ | ||
322 | |||
323 | /* | 138 | /* |
324 | * Signal handler for SIGHUP. Sshd execs itself when it receives SIGHUP; | 139 | * Signal handler for SIGHUP. Sshd execs itself when it receives SIGHUP; |
325 | * the effect is to reread the configuration file (and to regenerate | 140 | * the effect is to reread the configuration file (and to regenerate |
@@ -973,20 +788,7 @@ main(int ac, char **av) | |||
973 | verbose("Closing connection to %.100s", remote_ip); | 788 | verbose("Closing connection to %.100s", remote_ip); |
974 | 789 | ||
975 | #ifdef USE_PAM | 790 | #ifdef USE_PAM |
976 | { | 791 | finish_pam(); |
977 | int retval; | ||
978 | |||
979 | if (pamh != NULL) { | ||
980 | debug("Closing PAM session."); | ||
981 | retval = pam_close_session((pam_handle_t *)pamh, 0); | ||
982 | |||
983 | debug("Terminating PAM library."); | ||
984 | if (pam_end((pam_handle_t *)pamh, retval) != PAM_SUCCESS) | ||
985 | log("Cannot release PAM authentication."); | ||
986 | |||
987 | fatal_remove_cleanup(&pam_cleanup_proc, NULL); | ||
988 | } | ||
989 | } | ||
990 | #endif /* USE_PAM */ | 792 | #endif /* USE_PAM */ |
991 | 793 | ||
992 | packet_close(); | 794 | packet_close(); |
@@ -1306,17 +1108,7 @@ do_authentication(char *user) | |||
1306 | pw = &pwcopy; | 1108 | pw = &pwcopy; |
1307 | 1109 | ||
1308 | #ifdef USE_PAM | 1110 | #ifdef USE_PAM |
1309 | { | 1111 | start_pam(pw); |
1310 | int pam_retval; | ||
1311 | |||
1312 | debug("Starting up PAM with username \"%.200s\"", pw->pw_name); | ||
1313 | |||
1314 | pam_retval = pam_start("sshd", pw->pw_name, &conv, (pam_handle_t**)&pamh); | ||
1315 | if (pam_retval != PAM_SUCCESS) | ||
1316 | fatal("PAM initialisation failed: %.200s", PAM_STRERROR((pam_handle_t *)pamh, pam_retval)); | ||
1317 | |||
1318 | fatal_add_cleanup(&pam_cleanup_proc, NULL); | ||
1319 | } | ||
1320 | #endif | 1112 | #endif |
1321 | 1113 | ||
1322 | /* | 1114 | /* |
@@ -1334,7 +1126,7 @@ do_authentication(char *user) | |||
1334 | (!options.kerberos_authentication || options.kerberos_or_local_passwd) && | 1126 | (!options.kerberos_authentication || options.kerberos_or_local_passwd) && |
1335 | #endif /* KRB4 */ | 1127 | #endif /* KRB4 */ |
1336 | #ifdef USE_PAM | 1128 | #ifdef USE_PAM |
1337 | do_pam_auth(pw->pw_name, "")) { | 1129 | auth_pam_password(pw, "")) { |
1338 | #else /* USE_PAM */ | 1130 | #else /* USE_PAM */ |
1339 | auth_password(pw, "")) { | 1131 | auth_password(pw, "")) { |
1340 | #endif /* USE_PAM */ | 1132 | #endif /* USE_PAM */ |
@@ -1477,9 +1269,6 @@ do_authloop(struct passwd * pw) | |||
1477 | authenticated = auth_rhosts(pw, client_user); | 1269 | authenticated = auth_rhosts(pw, client_user); |
1478 | 1270 | ||
1479 | snprintf(user, sizeof user, " ruser %s", client_user); | 1271 | snprintf(user, sizeof user, " ruser %s", client_user); |
1480 | #ifndef USE_PAM | ||
1481 | xfree(client_user); | ||
1482 | #endif /* USE_PAM */ | ||
1483 | break; | 1272 | break; |
1484 | 1273 | ||
1485 | case SSH_CMSG_AUTH_RHOSTS_RSA: | 1274 | case SSH_CMSG_AUTH_RHOSTS_RSA: |
@@ -1512,9 +1301,6 @@ do_authloop(struct passwd * pw) | |||
1512 | BN_clear_free(client_host_key_n); | 1301 | BN_clear_free(client_host_key_n); |
1513 | 1302 | ||
1514 | snprintf(user, sizeof user, " ruser %s", client_user); | 1303 | snprintf(user, sizeof user, " ruser %s", client_user); |
1515 | #ifndef USE_PAM | ||
1516 | xfree(client_user); | ||
1517 | #endif /* USE_PAM */ | ||
1518 | break; | 1304 | break; |
1519 | 1305 | ||
1520 | case SSH_CMSG_AUTH_RSA: | 1306 | case SSH_CMSG_AUTH_RSA: |
@@ -1545,7 +1331,7 @@ do_authloop(struct passwd * pw) | |||
1545 | 1331 | ||
1546 | #ifdef USE_PAM | 1332 | #ifdef USE_PAM |
1547 | /* Do PAM auth with password */ | 1333 | /* Do PAM auth with password */ |
1548 | authenticated = do_pam_auth(pw->pw_name, password); | 1334 | authenticated = auth_pam_password(pw, password); |
1549 | #else /* USE_PAM */ | 1335 | #else /* USE_PAM */ |
1550 | /* Try authentication with the password. */ | 1336 | /* Try authentication with the password. */ |
1551 | authenticated = auth_password(pw, password); | 1337 | authenticated = auth_password(pw, password); |
@@ -1615,29 +1401,24 @@ do_authloop(struct passwd * pw) | |||
1615 | get_remote_port(), | 1401 | get_remote_port(), |
1616 | user); | 1402 | user); |
1617 | 1403 | ||
1618 | #ifndef USE_PAM | ||
1619 | if (authenticated) | ||
1620 | return; | ||
1621 | |||
1622 | if (attempt > AUTH_FAIL_MAX) | ||
1623 | packet_disconnect(AUTH_FAIL_MSG, pw->pw_name); | ||
1624 | #else /* USE_PAM */ | ||
1625 | if (authenticated) { | 1404 | if (authenticated) { |
1626 | do_pam_account(pw->pw_name, client_user); | 1405 | #ifdef USE_PAM |
1627 | 1406 | if (!do_pam_account(pw->pw_name, client_user)) | |
1628 | if (client_user != NULL) | 1407 | { |
1629 | xfree(client_user); | 1408 | if (client_user != NULL) |
1409 | xfree(client_user); | ||
1630 | 1410 | ||
1411 | do_fake_authloop(pw->pw_name); | ||
1412 | } | ||
1413 | #endif /* USE_PAM */ | ||
1631 | return; | 1414 | return; |
1632 | } | 1415 | } |
1633 | 1416 | ||
1634 | if (attempt > AUTH_FAIL_MAX) { | 1417 | if (client_user != NULL) |
1635 | if (client_user != NULL) | 1418 | xfree(client_user); |
1636 | xfree(client_user); | ||
1637 | 1419 | ||
1420 | if (attempt > AUTH_FAIL_MAX) | ||
1638 | packet_disconnect(AUTH_FAIL_MSG, pw->pw_name); | 1421 | packet_disconnect(AUTH_FAIL_MSG, pw->pw_name); |
1639 | } | ||
1640 | #endif /* USE_PAM */ | ||
1641 | 1422 | ||
1642 | /* Send a message indicating that the authentication attempt failed. */ | 1423 | /* Send a message indicating that the authentication attempt failed. */ |
1643 | packet_start(SSH_SMSG_FAILURE); | 1424 | packet_start(SSH_SMSG_FAILURE); |
@@ -1672,8 +1453,10 @@ do_fake_authloop(char *user) | |||
1672 | for (attempt = 1;; attempt++) { | 1453 | for (attempt = 1;; attempt++) { |
1673 | /* Read a packet. This will not return if the client disconnects. */ | 1454 | /* Read a packet. This will not return if the client disconnects. */ |
1674 | int plen; | 1455 | int plen; |
1456 | #ifndef SKEY | ||
1457 | (void)packet_read(&plen); | ||
1458 | #else /* SKEY */ | ||
1675 | int type = packet_read(&plen); | 1459 | int type = packet_read(&plen); |
1676 | #ifdef SKEY | ||
1677 | int dlen; | 1460 | int dlen; |
1678 | char *password, *skeyinfo; | 1461 | char *password, *skeyinfo; |
1679 | /* Try to send a fake s/key challenge. */ | 1462 | /* Try to send a fake s/key challenge. */ |
@@ -1845,7 +1628,7 @@ do_authenticated(struct passwd * pw) | |||
1845 | 1628 | ||
1846 | #ifdef USE_PAM | 1629 | #ifdef USE_PAM |
1847 | /* do the pam_open_session since we have the pty */ | 1630 | /* do the pam_open_session since we have the pty */ |
1848 | do_pam_session(pw->pw_name,ttyname); | 1631 | do_pam_session(pw->pw_name, ttyname); |
1849 | #endif /* USE_PAM */ | 1632 | #endif /* USE_PAM */ |
1850 | 1633 | ||
1851 | break; | 1634 | break; |
@@ -1925,7 +1708,7 @@ do_authenticated(struct passwd * pw) | |||
1925 | 1708 | ||
1926 | #ifdef USE_PAM | 1709 | #ifdef USE_PAM |
1927 | do_pam_setcred(); | 1710 | do_pam_setcred(); |
1928 | #endif | 1711 | #endif /* USE_PAM */ |
1929 | if (forced_command != NULL) | 1712 | if (forced_command != NULL) |
1930 | goto do_forced_command; | 1713 | goto do_forced_command; |
1931 | debug("Forking shell."); | 1714 | debug("Forking shell."); |
@@ -1943,7 +1726,7 @@ do_authenticated(struct passwd * pw) | |||
1943 | 1726 | ||
1944 | #ifdef USE_PAM | 1727 | #ifdef USE_PAM |
1945 | do_pam_setcred(); | 1728 | do_pam_setcred(); |
1946 | #endif | 1729 | #endif /* USE_PAM */ |
1947 | if (forced_command != NULL) | 1730 | if (forced_command != NULL) |
1948 | goto do_forced_command; | 1731 | goto do_forced_command; |
1949 | /* Get command from the packet. */ | 1732 | /* Get command from the packet. */ |
@@ -2221,10 +2004,9 @@ do_exec_pty(const char *command, int ptyfd, int ttyfd, | |||
2221 | quiet_login = stat(line, &st) >= 0; | 2004 | quiet_login = stat(line, &st) >= 0; |
2222 | 2005 | ||
2223 | #ifdef USE_PAM | 2006 | #ifdef USE_PAM |
2224 | /* output the results of the pamconv() */ | 2007 | if (!quiet_login) |
2225 | if (!quiet_login && pamconv_msg != NULL) | 2008 | print_pam_messages(); |
2226 | fprintf(stderr, pamconv_msg); | 2009 | #endif /* USE_PAM */ |
2227 | #endif | ||
2228 | 2010 | ||
2229 | /* | 2011 | /* |
2230 | * If the user has logged in before, display the time of last | 2012 | * If the user has logged in before, display the time of last |
@@ -2389,6 +2171,39 @@ read_environment_file(char ***env, unsigned int *envsize, | |||
2389 | fclose(f); | 2171 | fclose(f); |
2390 | } | 2172 | } |
2391 | 2173 | ||
2174 | #ifdef USE_PAM | ||
2175 | /* | ||
2176 | * Sets any environment variables which have been specified by PAM | ||
2177 | */ | ||
2178 | void do_pam_environment(char ***env, int *envsize) | ||
2179 | { | ||
2180 | char *equals, var_name[512], var_val[512]; | ||
2181 | char **pam_env; | ||
2182 | int i; | ||
2183 | |||
2184 | if ((pam_env = fetch_pam_environment()) == NULL) | ||
2185 | return; | ||
2186 | |||
2187 | for(i = 0; pam_env[i] != NULL; i++) { | ||
2188 | if ((equals = strstr(pam_env[i], "=")) == NULL) | ||
2189 | continue; | ||
2190 | |||
2191 | if (strlen(pam_env[i]) < (sizeof(var_name) - 1)) | ||
2192 | { | ||
2193 | memset(var_name, '\0', sizeof(var_name)); | ||
2194 | memset(var_val, '\0', sizeof(var_val)); | ||
2195 | |||
2196 | strncpy(var_name, pam_env[i], equals - pam_env[i]); | ||
2197 | strcpy(var_val, equals + 1); | ||
2198 | |||
2199 | debug("PAM environment: %s=%s", var_name, var_val); | ||
2200 | |||
2201 | child_set_env(env, envsize, var_name, var_val); | ||
2202 | } | ||
2203 | } | ||
2204 | } | ||
2205 | #endif /* USE_PAM */ | ||
2206 | |||
2392 | /* | 2207 | /* |
2393 | * Performs common processing for the child, such as setting up the | 2208 | * Performs common processing for the child, such as setting up the |
2394 | * environment, closing extra file descriptors, setting the user and group | 2209 | * environment, closing extra file descriptors, setting the user and group |
@@ -2421,11 +2236,9 @@ do_child(const char *command, struct passwd * pw, const char *term, | |||
2421 | } | 2236 | } |
2422 | #endif /* USE_PAM */ | 2237 | #endif /* USE_PAM */ |
2423 | 2238 | ||
2424 | #ifdef HAVE_SETLOGIN | ||
2425 | /* Set login name in the kernel. */ | 2239 | /* Set login name in the kernel. */ |
2426 | if (setlogin(pw->pw_name) < 0) | 2240 | if (setlogin(pw->pw_name) < 0) |
2427 | error("setlogin failed: %s", strerror(errno)); | 2241 | error("setlogin failed: %s", strerror(errno)); |
2428 | #endif /* HAVE_SETLOGIN */ | ||
2429 | 2242 | ||
2430 | /* Set uid, gid, and groups. */ | 2243 | /* Set uid, gid, and groups. */ |
2431 | /* Login(1) does this as well, and it needs uid 0 for the "-h" | 2244 | /* Login(1) does this as well, and it needs uid 0 for the "-h" |
@@ -2526,23 +2339,7 @@ do_child(const char *command, struct passwd * pw, const char *term, | |||
2526 | 2339 | ||
2527 | #ifdef USE_PAM | 2340 | #ifdef USE_PAM |
2528 | /* Pull in any environment variables that may have been set by PAM. */ | 2341 | /* Pull in any environment variables that may have been set by PAM. */ |
2529 | { | 2342 | do_pam_environment(&env, &envsize); |
2530 | char *equals, var_name[512], var_val[512]; | ||
2531 | char **pam_env = pam_getenvlist((pam_handle_t *)pamh); | ||
2532 | int i; | ||
2533 | for(i = 0; pam_env && pam_env[i]; i++) { | ||
2534 | equals = strstr(pam_env[i], "="); | ||
2535 | if ((strlen(pam_env[i]) < (sizeof(var_name) - 1)) && (equals != NULL)) | ||
2536 | { | ||
2537 | debug("PAM environment: %s=%s", var_name, var_val); | ||
2538 | memset(var_name, '\0', sizeof(var_name)); | ||
2539 | memset(var_val, '\0', sizeof(var_val)); | ||
2540 | strncpy(var_name, pam_env[i], equals - pam_env[i]); | ||
2541 | strcpy(var_val, equals + 1); | ||
2542 | child_set_env(&env, &envsize, var_name, var_val); | ||
2543 | } | ||
2544 | } | ||
2545 | } | ||
2546 | #endif /* USE_PAM */ | 2343 | #endif /* USE_PAM */ |
2547 | 2344 | ||
2548 | if (xauthfile) | 2345 | if (xauthfile) |