diff options
Diffstat (limited to 'sshd.c')
-rw-r--r-- | sshd.c | 195 |
1 files changed, 98 insertions, 97 deletions
@@ -18,7 +18,7 @@ agent connections. | |||
18 | */ | 18 | */ |
19 | 19 | ||
20 | #include "includes.h" | 20 | #include "includes.h" |
21 | RCSID("$Id: sshd.c,v 1.2 1999/10/27 13:42:05 damien Exp $"); | 21 | RCSID("$Id: sshd.c,v 1.3 1999/10/28 03:20:30 damien Exp $"); |
22 | 22 | ||
23 | #include "xmalloc.h" | 23 | #include "xmalloc.h" |
24 | #include "rsa.h" | 24 | #include "rsa.h" |
@@ -117,6 +117,7 @@ RSA *public_key; | |||
117 | /* Prototypes for various functions defined later in this file. */ | 117 | /* Prototypes for various functions defined later in this file. */ |
118 | void do_connection(int privileged_port); | 118 | void do_connection(int privileged_port); |
119 | void do_authentication(char *user, int privileged_port); | 119 | void do_authentication(char *user, int privileged_port); |
120 | void eat_packets_and_disconnect(const char *user); | ||
120 | void do_authenticated(struct passwd *pw); | 121 | void do_authenticated(struct passwd *pw); |
121 | void do_exec_pty(const char *command, int ptyfd, int ttyfd, | 122 | void do_exec_pty(const char *command, int ptyfd, int ttyfd, |
122 | const char *ttyname, struct passwd *pw, const char *term, | 123 | const char *ttyname, struct passwd *pw, const char *term, |
@@ -131,7 +132,7 @@ void do_child(const char *command, struct passwd *pw, const char *term, | |||
131 | #ifdef HAVE_PAM | 132 | #ifdef HAVE_PAM |
132 | static int pamconv(int num_msg, const struct pam_message **msg, | 133 | static int pamconv(int num_msg, const struct pam_message **msg, |
133 | struct pam_response **resp, void *appdata_ptr); | 134 | struct pam_response **resp, void *appdata_ptr); |
134 | void do_pam_authentication(const char *username, const char *password, | 135 | void do_pam_account_and_session(const char *username, const char *password, |
135 | const char *remote_user, const char *remote_host); | 136 | const char *remote_user, const char *remote_host); |
136 | void pam_cleanup_proc(void *context); | 137 | void pam_cleanup_proc(void *context); |
137 | 138 | ||
@@ -158,7 +159,7 @@ static int pamconv(int num_msg, const struct pam_message **msg, | |||
158 | switch (msg[count]->msg_style) | 159 | switch (msg[count]->msg_style) |
159 | { | 160 | { |
160 | case PAM_PROMPT_ECHO_OFF: | 161 | case PAM_PROMPT_ECHO_OFF: |
161 | if (pampasswd == NULL) | 162 | if (pampasswd == NULL) |
162 | { | 163 | { |
163 | free(reply); | 164 | free(reply); |
164 | return PAM_CONV_ERR; | 165 | return PAM_CONV_ERR; |
@@ -198,59 +199,30 @@ void pam_cleanup_proc(void *context) | |||
198 | } | 199 | } |
199 | } | 200 | } |
200 | 201 | ||
201 | void do_pam_authentication(const char *username, const char *password, const char *remote_user, const char *remote_host) | 202 | void do_pam_account_and_session(const char *username, const char *password, const char *remote_user, const char *remote_host) |
202 | { | 203 | { |
203 | int pam_auth_ok = 1; | 204 | if (remote_host && (PAM_SUCCESS != pam_set_item((pam_handle_t *)pamh, PAM_RHOST, remote_host))) |
204 | |||
205 | pampasswd = password; | ||
206 | |||
207 | do | ||
208 | { | 205 | { |
209 | if (PAM_SUCCESS != pam_start("ssh", username, &conv, (pam_handle_t**)&pamh)) | 206 | log("PAM setup failed."); |
210 | { | 207 | eat_packets_and_disconnect(username); |
211 | pam_auth_ok = 0; | 208 | } |
212 | break; | ||
213 | } | ||
214 | |||
215 | fatal_add_cleanup(&pam_cleanup_proc, NULL); | ||
216 | |||
217 | if (remote_host && (PAM_SUCCESS != pam_set_item((pam_handle_t *)pamh, PAM_RHOST, remote_host))) | ||
218 | { | ||
219 | pam_auth_ok = 0; | ||
220 | break; | ||
221 | } | ||
222 | 209 | ||
223 | if (remote_user && (PAM_SUCCESS != pam_set_item((pam_handle_t *)pamh, PAM_RUSER, remote_user))) | 210 | if (remote_user && (PAM_SUCCESS != pam_set_item((pam_handle_t *)pamh, PAM_RUSER, remote_user))) |
224 | { | 211 | { |
225 | pam_auth_ok = 0; | 212 | log("PAM setup failed."); |
226 | break; | 213 | eat_packets_and_disconnect(username); |
227 | } | 214 | } |
228 | 215 | ||
229 | if (PAM_SUCCESS != pam_authenticate((pam_handle_t *)pamh, 0)) | 216 | if (PAM_SUCCESS != pam_acct_mgmt((pam_handle_t *)pamh, 0)) |
230 | { | 217 | { |
231 | pam_auth_ok = 0; | 218 | log("PAM rejected by account configuration."); |
232 | break; | 219 | eat_packets_and_disconnect(username); |
233 | } | 220 | } |
234 | |||
235 | if (PAM_SUCCESS != pam_acct_mgmt((pam_handle_t *)pamh, 0)) | ||
236 | { | ||
237 | pam_auth_ok = 0; | ||
238 | break; | ||
239 | } | ||
240 | 221 | ||
241 | if (PAM_SUCCESS != pam_open_session((pam_handle_t *)pamh, 0)) | 222 | if (PAM_SUCCESS != pam_open_session((pam_handle_t *)pamh, 0)) |
242 | { | ||
243 | pam_auth_ok = 0; | ||
244 | break; | ||
245 | } | ||
246 | } while (0); | ||
247 | |||
248 | if (!pam_auth_ok) | ||
249 | { | 223 | { |
250 | packet_start(SSH_SMSG_FAILURE); | 224 | log("PAM session setup failed."); |
251 | packet_send(); | 225 | eat_packets_and_disconnect(username); |
252 | packet_write_wait(); | ||
253 | packet_disconnect("PAM authentication failed."); | ||
254 | } | 226 | } |
255 | } | 227 | } |
256 | #endif /* HAVE_PAM */ | 228 | #endif /* HAVE_PAM */ |
@@ -1151,48 +1123,8 @@ do_authentication(char *user, int privileged_port) | |||
1151 | /* Verify that the user is a valid user. */ | 1123 | /* Verify that the user is a valid user. */ |
1152 | pw = getpwnam(user); | 1124 | pw = getpwnam(user); |
1153 | if (!pw || !allowed_user(pw)) | 1125 | if (!pw || !allowed_user(pw)) |
1154 | { | 1126 | eat_packets_and_disconnect(user); |
1155 | /* The user does not exist or access is denied, | 1127 | |
1156 | but fake indication that authentication is needed. */ | ||
1157 | packet_start(SSH_SMSG_FAILURE); | ||
1158 | packet_send(); | ||
1159 | packet_write_wait(); | ||
1160 | |||
1161 | /* Keep reading packets, and always respond with a failure. This is to | ||
1162 | avoid disclosing whether such a user really exists. */ | ||
1163 | for (;;) | ||
1164 | { | ||
1165 | /* Read a packet. This will not return if the client disconnects. */ | ||
1166 | int plen; | ||
1167 | int type = packet_read(&plen); | ||
1168 | #ifdef SKEY | ||
1169 | int passw_len; | ||
1170 | char *password, *skeyinfo; | ||
1171 | if (options.password_authentication && | ||
1172 | options.skey_authentication == 1 && | ||
1173 | type == SSH_CMSG_AUTH_PASSWORD && | ||
1174 | (password = packet_get_string(&passw_len)) != NULL && | ||
1175 | passw_len == 5 && | ||
1176 | strncasecmp(password, "s/key", 5) == 0 && | ||
1177 | (skeyinfo = skey_fake_keyinfo(user)) != NULL ){ | ||
1178 | /* Send a fake s/key challenge. */ | ||
1179 | packet_send_debug(skeyinfo); | ||
1180 | } | ||
1181 | #endif | ||
1182 | /* Send failure. This should be indistinguishable from a failed | ||
1183 | authentication. */ | ||
1184 | packet_start(SSH_SMSG_FAILURE); | ||
1185 | packet_send(); | ||
1186 | packet_write_wait(); | ||
1187 | if (++authentication_failures >= MAX_AUTH_FAILURES) { | ||
1188 | packet_disconnect("Too many authentication failures for %.100s from %.200s", | ||
1189 | user, get_canonical_hostname()); | ||
1190 | } | ||
1191 | } | ||
1192 | /*NOTREACHED*/ | ||
1193 | abort(); | ||
1194 | } | ||
1195 | |||
1196 | /* Take a copy of the returned structure. */ | 1128 | /* Take a copy of the returned structure. */ |
1197 | memset(&pwcopy, 0, sizeof(pwcopy)); | 1129 | memset(&pwcopy, 0, sizeof(pwcopy)); |
1198 | pwcopy.pw_name = xstrdup(pw->pw_name); | 1130 | pwcopy.pw_name = xstrdup(pw->pw_name); |
@@ -1203,6 +1135,18 @@ do_authentication(char *user, int privileged_port) | |||
1203 | pwcopy.pw_shell = xstrdup(pw->pw_shell); | 1135 | pwcopy.pw_shell = xstrdup(pw->pw_shell); |
1204 | pw = &pwcopy; | 1136 | pw = &pwcopy; |
1205 | 1137 | ||
1138 | #ifdef HAVE_PAM | ||
1139 | if (PAM_SUCCESS != pam_start("ssh", pw->pw_name, &conv, (pam_handle_t**)&pamh)) | ||
1140 | { | ||
1141 | packet_start(SSH_SMSG_FAILURE); | ||
1142 | packet_send(); | ||
1143 | packet_write_wait(); | ||
1144 | packet_disconnect("PAM initialisation failed."); | ||
1145 | } | ||
1146 | #endif | ||
1147 | |||
1148 | fatal_add_cleanup(&pam_cleanup_proc, NULL); | ||
1149 | |||
1206 | /* If we are not running as root, the user must have the same uid as the | 1150 | /* If we are not running as root, the user must have the same uid as the |
1207 | server. */ | 1151 | server. */ |
1208 | if (getuid() != 0 && pw->pw_uid != getuid()) | 1152 | if (getuid() != 0 && pw->pw_uid != getuid()) |
@@ -1460,10 +1404,18 @@ do_authentication(char *user, int privileged_port) | |||
1460 | } | 1404 | } |
1461 | 1405 | ||
1462 | #ifdef HAVE_PAM | 1406 | #ifdef HAVE_PAM |
1463 | /* Authentication will be handled later */ | 1407 | pampasswd = password; |
1464 | /* keep password around until then */ | 1408 | |
1465 | authenticated = 1; | 1409 | if (PAM_SUCCESS == pam_authenticate((pam_handle_t *)pamh, 0)) |
1466 | break; | 1410 | { |
1411 | log("PAM Password authentication accepted for %.100s.", user); | ||
1412 | authenticated = 1; | ||
1413 | break; | ||
1414 | } else | ||
1415 | { | ||
1416 | log("PAM Password authentication for %.100s failed.", user); | ||
1417 | break; | ||
1418 | } | ||
1467 | #else /* HAVE_PAM */ | 1419 | #else /* HAVE_PAM */ |
1468 | /* Try authentication with the password. */ | 1420 | /* Try authentication with the password. */ |
1469 | if (auth_password(pw, password)) | 1421 | if (auth_password(pw, password)) |
@@ -1519,7 +1471,7 @@ do_authentication(char *user, int privileged_port) | |||
1519 | } | 1471 | } |
1520 | 1472 | ||
1521 | #ifdef HAVE_PAM | 1473 | #ifdef HAVE_PAM |
1522 | do_pam_authentication(pw->pw_name, password, client_user, get_canonical_hostname()); | 1474 | do_pam_account_and_session(pw->pw_name, password, client_user, get_canonical_hostname()); |
1523 | 1475 | ||
1524 | /* Clean up */ | 1476 | /* Clean up */ |
1525 | if (client_user != NULL) | 1477 | if (client_user != NULL) |
@@ -1541,6 +1493,55 @@ do_authentication(char *user, int privileged_port) | |||
1541 | do_authenticated(pw); | 1493 | do_authenticated(pw); |
1542 | } | 1494 | } |
1543 | 1495 | ||
1496 | /* Read authentication messages, but return only failures until */ | ||
1497 | /* max auth attempts exceeded, then disconnect */ | ||
1498 | void eat_packets_and_disconnect(const char *user) | ||
1499 | { | ||
1500 | int authentication_failures = 0; | ||
1501 | |||
1502 | packet_start(SSH_SMSG_FAILURE); | ||
1503 | packet_send(); | ||
1504 | packet_write_wait(); | ||
1505 | |||
1506 | /* Keep reading packets, and always respond with a failure. This is to | ||
1507 | avoid disclosing whether such a user really exists. */ | ||
1508 | while(1) | ||
1509 | { | ||
1510 | /* Read a packet. This will not return if the client disconnects. */ | ||
1511 | int plen; | ||
1512 | #ifndef SKEY | ||
1513 | (void) packet_read(&plen); | ||
1514 | #else /* SKEY */ | ||
1515 | int type = packet_read(&plen); | ||
1516 | int passw_len; | ||
1517 | char *password, *skeyinfo; | ||
1518 | if (options.password_authentication && | ||
1519 | options.skey_authentication == 1 && | ||
1520 | type == SSH_CMSG_AUTH_PASSWORD && | ||
1521 | (password = packet_get_string(&passw_len)) != NULL && | ||
1522 | passw_len == 5 && | ||
1523 | strncasecmp(password, "s/key", 5) == 0 && | ||
1524 | (skeyinfo = skey_fake_keyinfo(user)) != NULL ) | ||
1525 | { | ||
1526 | /* Send a fake s/key challenge. */ | ||
1527 | packet_send_debug(skeyinfo); | ||
1528 | } | ||
1529 | #endif /* SKEY */ | ||
1530 | /* Send failure. This should be indistinguishable from a failed | ||
1531 | authentication. */ | ||
1532 | packet_start(SSH_SMSG_FAILURE); | ||
1533 | packet_send(); | ||
1534 | packet_write_wait(); | ||
1535 | if (++authentication_failures >= MAX_AUTH_FAILURES) | ||
1536 | { | ||
1537 | packet_disconnect("Too many authentication failures for %.100s from %.200s", | ||
1538 | user, get_canonical_hostname()); | ||
1539 | } | ||
1540 | } | ||
1541 | /*NOTREACHED*/ | ||
1542 | abort(); | ||
1543 | } | ||
1544 | |||
1544 | /* Prepares for an interactive session. This is called after the user has | 1545 | /* Prepares for an interactive session. This is called after the user has |
1545 | been successfully authenticated. During this message exchange, pseudo | 1546 | been successfully authenticated. During this message exchange, pseudo |
1546 | terminals are allocated, X11, TCP/IP, and authentication agent forwardings | 1547 | terminals are allocated, X11, TCP/IP, and authentication agent forwardings |