1 /*
2 * ProFTPD - mod_sftp disconnect msgs
3 * Copyright (c) 2008-2017 TJ Saunders
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA.
18 *
19 * As a special exemption, TJ Saunders and other respective copyright holders
20 * give permission to link this program with OpenSSL, and distribute the
21 * resulting executable, without including the source code for OpenSSL in the
22 * source distribution.
23 */
24
25 #include "mod_sftp.h"
26 #include "ssh2.h"
27 #include "msg.h"
28 #include "packet.h"
29 #include "disconnect.h"
30
31 extern module sftp_module;
32
33 struct disconnect_reason {
34 uint32_t code;
35 const char *explain;
36 const char *lang;
37 };
38
39 static struct disconnect_reason explanations[] = {
40 { SFTP_SSH2_DISCONNECT_HOST_NOT_ALLOWED_TO_CONNECT, "Host not allowed to connect", NULL },
41 { SFTP_SSH2_DISCONNECT_PROTOCOL_ERROR, "Protocol error", NULL },
42 { SFTP_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED, "Key exchange failed", NULL },
43 { SFTP_SSH2_DISCONNECT_MAC_ERROR, "MAC error", NULL },
44 { SFTP_SSH2_DISCONNECT_COMPRESSION_ERROR, "Compression error", NULL },
45 { SFTP_SSH2_DISCONNECT_SERVICE_NOT_AVAILABLE, "Requested service not available", NULL },
46 { SFTP_SSH2_DISCONNECT_PROTOCOL_VERSION_NOT_SUPPORTED, "Protocol version not supported", NULL },
47 { SFTP_SSH2_DISCONNECT_HOST_KEY_NOT_VERIFIABLE, "Host key not verifiable", NULL },
48 { SFTP_SSH2_DISCONNECT_CONNECTION_LOST, "Connection lost", NULL },
49 { SFTP_SSH2_DISCONNECT_BY_APPLICATION, "Application disconnected", NULL },
50 { SFTP_SSH2_DISCONNECT_TOO_MANY_CONNECTIONS, "Too many connections", NULL },
51 { SFTP_SSH2_DISCONNECT_AUTH_CANCELLED_BY_USER, "Authentication cancelled by user", NULL },
52 { SFTP_SSH2_DISCONNECT_NO_MORE_AUTH_METHODS_AVAILABLE, "No other authentication mechanisms available", NULL },
53 { SFTP_SSH2_DISCONNECT_ILLEGAL_USER_NAME, "Illegal user name", NULL },
54 { 0, NULL, NULL }
55 };
56
57 static const char *trace_channel = "ssh2";
58
sftp_disconnect_get_str(uint32_t reason_code)59 const char *sftp_disconnect_get_str(uint32_t reason_code) {
60 register unsigned int i;
61
62 for (i = 0; explanations[i].explain; i++) {
63 if (explanations[i].code == reason_code) {
64 return explanations[i].explain;
65 }
66 }
67
68 errno = ENOENT;
69 return NULL;
70 }
71
sftp_disconnect_send(uint32_t reason,const char * explain,const char * file,int lineno,const char * func)72 void sftp_disconnect_send(uint32_t reason, const char *explain,
73 const char *file, int lineno, const char *func) {
74 struct ssh2_packet *pkt;
75 const pr_netaddr_t *remote_addr;
76 const char *lang = "en-US";
77 unsigned char *buf, *ptr;
78 uint32_t buflen, bufsz;
79 int sockfd;
80
81 /* Send the client a DISCONNECT mesg. */
82 pkt = sftp_ssh2_packet_create(sftp_pool);
83
84 remote_addr = pr_netaddr_get_sess_remote_addr();
85
86 buflen = bufsz = 1024;
87 ptr = buf = palloc(pkt->pool, bufsz);
88
89 if (explain == NULL) {
90 register unsigned int i;
91
92 for (i = 0; explanations[i].explain; i++) {
93 if (explanations[i].code == reason) {
94 explain = explanations[i].explain;
95 lang = explanations[i].lang;
96 if (lang == NULL) {
97 lang = "en-US";
98 }
99 break;
100 }
101 }
102
103 if (explain == NULL) {
104 explain = "Unknown reason";
105 }
106
107 } else {
108 lang = "en-US";
109 }
110
111 if (strlen(func) > 0) {
112 pr_trace_msg(trace_channel, 9, "disconnecting (%s) [at %s:%d:%s()]",
113 explain, file, lineno, func);
114
115 } else {
116 pr_trace_msg(trace_channel, 9, "disconnecting (%s) [at %s:%d]", explain,
117 file, lineno);
118 }
119
120 sftp_msg_write_byte(&buf, &buflen, SFTP_SSH2_MSG_DISCONNECT);
121 sftp_msg_write_int(&buf, &buflen, reason);
122 sftp_msg_write_string(&buf, &buflen, explain);
123 sftp_msg_write_string(&buf, &buflen, lang);
124
125 pkt->payload = ptr;
126 pkt->payload_len = (bufsz - buflen);
127
128 (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
129 "disconnecting %s (%s)", pr_netaddr_get_ipstr(remote_addr), explain);
130
131 /* If we are called very early in the connection lifetime, then the
132 * sftp_conn variable may not have been set yet, thus the conditional here.
133 */
134 if (sftp_conn != NULL) {
135 sockfd = sftp_conn->wfd;
136
137 } else {
138 sockfd = session.c->wfd;
139 }
140
141 /* Explicitly set a short poll timeout of 5 secs. */
142 sftp_ssh2_packet_set_poll_timeout(5);
143
144 if (sftp_ssh2_packet_write(sockfd, pkt) < 0) {
145 int xerrno = errno;
146
147 pr_trace_msg(trace_channel, 12,
148 "error writing DISCONNECT message: %s", strerror(xerrno));
149 }
150
151 destroy_pool(pkt->pool);
152 }
153
sftp_disconnect_conn(uint32_t reason,const char * explain,const char * file,int lineno,const char * func)154 void sftp_disconnect_conn(uint32_t reason, const char *explain,
155 const char *file, int lineno, const char *func) {
156 sftp_disconnect_send(reason, explain, file, lineno, func);
157
158 #ifdef PR_DEVEL_COREDUMP
159 pr_session_end(PR_SESS_END_FL_NOEXIT);
160 abort();
161
162 #else
163 pr_session_disconnect(&sftp_module, PR_SESS_DISCONNECT_BY_APPLICATION, NULL);
164 #endif /* PR_DEVEL_COREDUMP */
165 }
166