source: src/router/proftpd/src/session.c @ 17876

Last change on this file since 17876 was 17876, checked in by BrainSlayer, 20 months ago

update proftp

File size: 9.2 KB
Line 
1/*
2 * ProFTPD - FTP server daemon
3 * Copyright (c) 2009-2011 The ProFTPD Project team
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, The ProFTPD Project team and other respective
20 * copyright holders give permission to link this program with OpenSSL, and
21 * distribute the resulting executable, without including the source code for
22 * OpenSSL in the source distribution.
23 *
24 * $Id: session.c,v 1.14 2011/05/23 21:22:24 castaglia Exp $
25 */
26
27#include "conf.h"
28
29/* From src/main.c */
30extern unsigned char is_master;
31
32static void sess_cleanup(int flags) {
33
34  /* Clear the scoreboard entry. */
35  if (ServerType == SERVER_STANDALONE) {
36
37    /* For standalone daemons, we only clear the scoreboard slot if we are
38     * an exiting child process.
39     */
40
41    if (!is_master) {
42      if (pr_scoreboard_entry_del(TRUE) < 0 &&
43          errno != EINVAL &&
44          errno != ENOENT) {
45        pr_log_debug(DEBUG1, "error deleting scoreboard entry: %s",
46          strerror(errno));
47      }
48    }
49
50  } else if (ServerType == SERVER_INETD) {
51    /* For inetd-spawned daemons, we always clear the scoreboard slot. */
52    if (pr_scoreboard_entry_del(TRUE) < 0 &&
53        errno != EINVAL &&
54        errno != ENOENT) {
55      pr_log_debug(DEBUG1, "error deleting scoreboard entry: %s",
56        strerror(errno));
57    }
58  }
59
60  /* If session.user is set, we have a valid login. */
61  if (session.user &&
62      session.wtmp_log) {
63    const char *sess_ttyname;
64
65    sess_ttyname = pr_session_get_ttyname(session.pool);
66    log_wtmp(sess_ttyname, "", pr_netaddr_get_sess_remote_name(),
67      pr_netaddr_get_sess_remote_addr());
68  }
69
70  /* These are necessary in order that cleanups associated with these pools
71   * (and their subpools) are properly run.
72   */
73  if (session.d) {
74    pr_inet_close(session.pool, session.d);
75    session.d = NULL;
76  }
77
78  if (session.c) {
79    pr_inet_close(session.pool, session.c);
80    session.c = NULL;
81  }
82
83  /* Run all the exit handlers */
84  pr_event_generate("core.exit", NULL);
85
86  if (!is_master ||
87      (ServerType == SERVER_INETD &&
88      !(flags & PR_SESS_END_FL_SYNTAX_CHECK))) {
89    pr_log_pri(PR_LOG_INFO, "%s session closed.",
90      pr_session_get_protocol(PR_SESS_PROTO_FL_LOGOUT));
91  }
92
93  log_closesyslog();
94}
95
96void pr_session_disconnect(module *m, int reason_code,
97    const char *details) {
98
99  session.disconnect_reason = reason_code;
100  session.disconnect_module = m;
101
102  if (details != NULL &&
103      session.notes != NULL) {
104    /* Stash any extra details in the session.notes table */
105    if (pr_table_add_dup(session.notes, "core.disconnect-details",
106        (char *) details, 0) < 0) {
107      int xerrno = errno;
108
109      if (xerrno != EEXIST) {
110        pr_log_debug(DEBUG5, "error stashing 'core.disconnect-details' in "
111          "session.notes: %s", strerror(xerrno));
112      }
113    }
114  }
115
116  pr_session_end(0);
117}
118
119void pr_session_end(int flags) {
120  int exitcode = 0;
121
122  sess_cleanup(flags);
123
124  if (flags & PR_SESS_END_FL_NOEXIT) {
125    return;
126  }
127
128#ifdef PR_USE_DEVEL
129  destroy_pool(session.pool);
130
131  if (is_master) {
132    main_server = NULL;
133    free_pools();
134    pr_proctitle_free();
135  }
136#endif /* PR_USE_DEVEL */
137
138#ifdef PR_DEVEL_PROFILE
139  /* Populating the gmon.out gprof file requires that the process exit
140   * via exit(3) or by returning from main().  Using _exit(2) doesn't allow
141   * the process the time to write its profile data out.
142   */
143  exit(exitcode);
144#else
145  _exit(exitcode);
146#endif /* PR_DEVEL_PROFILE */
147}
148
149const char *pr_session_get_disconnect_reason(char **details) {
150  const char *reason_str = NULL;
151
152  switch (session.disconnect_reason) {
153    case PR_SESS_DISCONNECT_UNSPECIFIED:
154      reason_str = "Unknown/unspecified";
155      break;
156
157    case PR_SESS_DISCONNECT_CLIENT_QUIT:
158      reason_str = "Quit";
159      break;
160
161    case PR_SESS_DISCONNECT_CLIENT_EOF:
162      reason_str = "Read EOF from client";
163      break;
164
165    case PR_SESS_DISCONNECT_SESSION_INIT_FAILED:
166      reason_str = "Session initialized failed";
167      break;
168
169    case PR_SESS_DISCONNECT_SIGNAL:
170      reason_str = "Terminated by signal";
171      break;
172
173    case PR_SESS_DISCONNECT_NOMEM:
174      reason_str = "Low memory";
175      break;
176
177    case PR_SESS_DISCONNECT_SERVER_SHUTDOWN:
178      reason_str = "Server shutting down";
179      break;
180
181    case PR_SESS_DISCONNECT_TIMEOUT:
182      reason_str = "Timeout exceeded";
183      break;
184
185    case PR_SESS_DISCONNECT_BANNED:
186      reason_str = "Banned";
187      break;
188
189    case PR_SESS_DISCONNECT_CONFIG_ACL:
190      reason_str = "Configured policy";
191      break;
192
193    case PR_SESS_DISCONNECT_MODULE_ACL:
194      reason_str = "Module-specific policy";
195      break;
196
197    case PR_SESS_DISCONNECT_BAD_CONFIG:
198      reason_str = "Server misconfiguration";
199      break;
200
201    case PR_SESS_DISCONNECT_BY_APPLICATION:
202      reason_str = "Application error";
203      break;
204  }
205
206  if (details != NULL) {
207    *details = pr_table_get(session.notes, "core.disconnect-details", NULL);
208  }
209
210  return reason_str;
211}
212
213const char *pr_session_get_protocol(int flags) {
214  const char *sess_proto;
215
216  sess_proto = pr_table_get(session.notes, "protocol", NULL);
217  if (sess_proto == NULL) {
218    sess_proto = "ftp";
219  }
220
221  if (!(flags & PR_SESS_PROTO_FL_LOGOUT)) {
222    /* Return the protocol as is. */
223    return sess_proto;
224  }
225
226  /* Otherwise, we need to return either "FTP" or "SSH2", for consistency. */
227  if (strncmp(sess_proto, "ftp", 4) == 0 ||
228      strncmp(sess_proto, "ftps", 5) == 0) {
229    return "FTP";
230 
231  } else if (strncmp(sess_proto, "ssh2", 5) == 0 ||
232             strncmp(sess_proto, "sftp", 5) == 0 ||
233             strncmp(sess_proto, "scp", 4) == 0 ||
234             strncmp(sess_proto, "publickey", 10) == 0) {
235    return "SSH2";
236  }
237
238  /* Should never reach here, but just in case... */
239  return "unknown";
240}
241
242int pr_session_set_idle(void) {
243  char *user = NULL;
244
245  pr_scoreboard_entry_update(session.pid,
246    PR_SCORE_BEGIN_IDLE, time(NULL),
247    PR_SCORE_CMD, "%s", "idle", NULL, NULL);
248
249  pr_scoreboard_entry_update(session.pid,
250    PR_SCORE_CMD_ARG, "%s", "", NULL, NULL);
251
252  if (session.user) {
253    user = session.user;
254
255  } else {
256    user = "(authenticating)";
257  }
258
259  pr_proctitle_set("%s - %s: IDLE", user, session.proc_prefix);
260  return 0;
261}
262
263int pr_session_set_protocol(const char *sess_proto) {
264  int count, res;
265
266  if (sess_proto == NULL) {
267    errno = EINVAL;
268    return -1;
269  }
270
271  count = pr_table_exists(session.notes, "protocol");
272  if (count > 0) {
273    res = pr_table_set(session.notes, pstrdup(session.pool, "protocol"),
274      pstrdup(session.pool, sess_proto), 0);
275
276    if (res == 0) {
277      /* Update the scoreboard entry for this session with the protocol. */
278      pr_scoreboard_entry_update(session.pid, PR_SCORE_PROTOCOL, sess_proto,
279        NULL);
280    }
281
282    return res;
283  }
284
285  res = pr_table_add(session.notes, pstrdup(session.pool, "protocol"),
286    pstrdup(session.pool, sess_proto), 0);
287
288  if (res == 0) {
289    /* Update the scoreboard entry for this session with the protocol. */
290    pr_scoreboard_entry_update(session.pid, PR_SCORE_PROTOCOL, sess_proto,
291      NULL);
292  }
293
294  return res;
295}
296
297static const char *sess_ttyname = NULL;
298
299const char *pr_session_get_ttyname(pool *p) {
300  char ttybuf[32];
301  const char *sess_proto, *tty_proto = NULL;
302
303  if (p == NULL) {
304    errno = EINVAL;
305    return NULL;
306  }
307
308  if (sess_ttyname) {
309    /* Return the cached name. */
310    return pstrdup(p, sess_ttyname);
311  }
312
313  sess_proto = pr_table_get(session.notes, "protocol", NULL);
314  if (sess_proto) {
315    if (strncmp(sess_proto, "ftp", 4) == 0 ||
316        strncmp(sess_proto, "ftps", 5) == 0) {
317#if (defined(BSD) && (BSD >= 199103))
318      tty_proto = "ftp";
319#else
320      tty_proto = "ftpd";
321#endif
322
323    } else if (strncmp(sess_proto, "ssh2", 5) == 0 ||
324               strncmp(sess_proto, "sftp", 5) == 0 ||
325               strncmp(sess_proto, "scp", 4) == 0 ||
326               strncmp(sess_proto, "publickey", 10) == 0) {
327
328      /* Just use the plain "ssh" string for the tty name for these cases. */
329      tty_proto = "ssh";
330
331      /* Cache the originally constructed tty name for any later retrievals. */
332      sess_ttyname = pstrdup(session.pool, tty_proto);
333      return pstrdup(p, sess_ttyname);
334    }
335  }
336
337  if (tty_proto == NULL) {
338#if (defined(BSD) && (BSD >= 199103))
339    tty_proto = "ftp";
340#else
341    tty_proto = "ftpd";
342#endif
343  }
344
345  memset(ttybuf, '\0', sizeof(ttybuf));
346#if (defined(BSD) && (BSD >= 199103))
347  snprintf(ttybuf, sizeof(ttybuf), "%s%ld", tty_proto,
348    (long) (session.pid ? session.pid : getpid()));
349#else
350  snprintf(ttybuf, sizeof(ttybuf), "%s%d", tty_proto,
351    (int) (session.pid ? session.pid : getpid()));
352#endif
353
354  /* Cache the originally constructed tty name for any later retrievals. */
355  sess_ttyname = pstrdup(session.pool, ttybuf);
356
357  return pstrdup(p, sess_ttyname);
358}
Note: See TracBrowser for help on using the repository browser.