File: mod_sample.c

package info (click to toggle)
proftpd 1.2.0pre9-4
  • links: PTS
  • area: main
  • in suites: slink
  • size: 2,392 kB
  • ctags: 2,648
  • sloc: ansic: 24,012; sh: 1,754; makefile: 536; perl: 281
file content (284 lines) | stat: -rw-r--r-- 9,428 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
/*
 * The following is an *EXAMPLE* ProFTPD module.  While it can be compiled
 * in to ProFTPD, it is not by default, and doesn't really do anything all
 * that terribly functional.
 */

/*
 * ProFTPD - FTP server daemon
 * Copyright (c) 1997, 1998 Public Flood Software
 *  
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307, USA.
 */

/*
 * sample module for ProFTPD
 * $Id: mod_sample.c,v 1.1 1999/10/05 04:28:16 macgyver Exp $
 */

#include "conf.h"

/* This sample configuration directive handler will get called
 * whenever the "FooBarDirective" directive is encountered in the
 * configuration file.
 */

MODRET add_foobardirective(cmd_rec *cmd)
{
  int b;
  config_rec *c;

  /* The CHECK_ARGS macro checks the number of arguments passed to the
   * directive against what we want.  Note that this is *one* less than
   * cmd->argc, because cmd->argc includes cmd->argv[0] (the directive
   * itself).  If CHECK_ARGS fails, a generic error is sent to the user
   */

  CHECK_ARGS(cmd,1);

  /* The CHECK_CONF macro makes sure that this directive is not being
   * "used" in the wrong context (i.e. if the directive is only available
   * or applicable inside certain contexts).  In this case, we are allowing
   * the directive inside of <Anonymous> and <Limit>, but nowhere else.
   * If this macro fails a generic error is logged and the handler aborts.
   */

  CHECK_CONF(cmd,CONF_ANON|CONF_LIMIT);

  b = get_boolean(cmd,1);
  if(b == -1)				/* get_boolean couldn't find a */
    CONF_ERROR(cmd,                     /* valid boolean value         */
    "requires a boolean value");

  /* add_config_param adds a configuration paramater to our current
   * configuration context.
   */

  c = add_config_param("FooBarDirective",1,(void*)b);

  /* By adding the CF_MERGEDOWN flag to the parameter we just created
   * we are telling proftpd that this parameter should be copied and
   * "merged" into all "lower" contexts until it either hits a
   * parameter w/ the same name or bottoms out.
   *
   * Example _without_ CF_MERGEDOWN:
   *
   * <VirtualHost>
   *      |----------\
   *             <Anonymous>
   *                 | - FooBarDirective  <------- Config places it here
   *                 |-----------\
   *                         <Directory>  <------- Doesn't apply here
   *                             |-------------\
   *                                        <Limit> <--- Or here.....
   *
   * Now, if we specify CF_MERGDOWN, the tree ends up looking like:
   *
   * <VirtualHost>
   *      |----------\
   *             <Anonymous>
   *                 | - FooBarDirective  <------- Config places it here
   *                 |-----------\
   *                         <Directory>  <------- Now, it DOES apply here
   *                             | - FooBarDirective
   *                             |-------------\
   *                                        <Limit> <-------- And here ...
   *                                           | - FooBarDirective
   *
   */

  c->flags |= CF_MERGEDOWN;

  /* Tell proftpd that we handled the request w/ no problems.
   */

  return HANDLED(cmd);
}

/* Example of a PRE_CMD handler here, which simply logs all received
 * commands via log_debug().  We are careful to return DECLINED, otherwise
 * other PRE_CMD handlers wouldn't get the request.  Note that in order
 * for this to work properly, this module would need to be loaded _last_,
 * or after any other modules which don't return DECLINED for all
 * their precmds.  In practice you should always return DECLINED unless
 * you plan on having your module actually handle the command (or
 * deny it).
 */

MODRET pre_cmd(cmd_rec *cmd)
{
  log_debug(DEBUG0,"RECEIVED: command '%s', arguments '%s'.",
            cmd->argv[0],cmd->arg);

  return DECLINED(cmd);
}

/* Next, an example of a LOG_CMD handler, which receives all commands
 * _after_ they have been processed, and additional only IF they were
 * successful.
 */

MODRET log_cmd(cmd_rec *cmd)
{
  log_debug(DEBUG0,"SUCCESSFUL: command '%s', arguments '%s'.",
            cmd->argv[0],cmd->arg);

  return DECLINED(cmd);
}

/* Now, a _slightly_ more useful handler.  We define POST_CMD handlers
 * for RETR, STOR and LIST/NLST, so we can calculate total data transfer
 * for a session.
 */

static unsigned long total_rx = 0, total_tx = 0;

MODRET post_cmd_retr(cmd_rec *cmd)
{
  /* The global variable 'session' contains lots of important data after
   * a file/directory transfer of any kind.  It doesn't get cleared until
   * mod_xfer gets a LOG_CMD, so we can still get to it here.
   */

  total_tx += session.xfer.total_bytes;
  return DECLINED(cmd);
}

MODRET post_cmd_stor(cmd_rec *cmd)
{
  total_rx += session.xfer.total_bytes;
  return DECLINED(cmd);
}

MODRET post_cmd_list(cmd_rec *cmd)
{
  return post_cmd_retr(cmd);
}

MODRET post_cmd_nlst(cmd_rec *cmd)
{
  return post_cmd_retr(cmd);
}

MODRET cmd_xfoo(cmd_rec *cmd)
{
  char *path;

  if(cmd->argc < 2)
    return ERROR_MSG(cmd,R_500,"XFOO command needs at least one argument");

  path = dir_realpath(cmd->tmp_pool,cmd->arg);

  if(!path) {
    add_response_err(R_500,"It appears that '%s' does not exist.",cmd->arg);
    return ERROR(cmd);
  }

  add_response_err(R_200,"XFOO command successful (yeah right!)");
  return HANDLED(cmd);
}

/* There are three tables which act as the "glue" between proftpd and
 * a module.  None of the tables are _required_ (however having none would
 * make the module fairly useless).
 */

/* The first table is the "configuration directive" table.  It specifies
 * handler routines in the module which will be used during configuration
 * file parsing.
 */

static conftable sample_config[] = {
  { "FooBarDirective",		add_foobardirective,                 },
  { NULL }
};

/* Each module can supply up to two initialization routines (via
 * the module structure at the bottom of this file).  The first
 * init function is called immediately after the module is loaded,
 * while the second is called after proftpd is connected to a client,
 * and the main proftpd server (if not in inetd mode) has forked off.
 * The second init function's purpose is to let the module perform
 * any necessary work once a client is connected and proftpd is ready
 * to service the new client.  In inetd mode, the "child init" function
 * will be called immediately after proftpd is loaded, because proftpd
 * is _always_ in "child mode" when run from inetd.  Note that both
 * of these initialization routines are optional.  If you don't need
 * them (or only need one), simply set the function pointer to NULL
 * in the module structure.
 */

static int sample_init()
{
  /* do something useful here, right? */

  return 0;
}

static int sample_child_init()
{
  /* same here */

  return 0;
}

/* command table ...
 * first  : command "type" (see the doc/API for more info)
 *
 * second : command "name", or the actual null-terminated ascii text
 *          sent by a client (in uppercase) for this command.  see
 *          include/ftp.h for macros which define all rfced FTP protocol
 *          commands.  Can also be the special macro C_ANY, which receives
 *          ALL commands.
 *
 * third  : command "group" (used for access control via Limit directives),
 *          this can be either G_DIRS (for commands related to directory
 *          listing), G_READ (for commands related to reading files), 
 *          G_WRITE (for commands related to file writing), or the
 *          special G_NONE for those commands against which the
 *          special <Limit READ|WRITE|DIRS> will not be applied.
 *
 * fourth : function pointer to your handler
 *
 * fifth  : TRUE if the command cannot be used before authentication
 *          (via USER/PASS), otherwise FALSE.
 *
 * sixth  : TRUE if the command can be sent during a file transfer
 *          (note: as of 1.1.5, this is obsolete)
 *
 */

cmdtable sample_commands[] = {
  { PRE_CMD,	C_ANY,	G_NONE, pre_cmd, 	FALSE, FALSE },
  { LOG_CMD,	C_ANY,	G_NONE, log_cmd, 	FALSE, FALSE },
  { POST_CMD,	C_RETR, G_NONE, post_cmd_retr,	FALSE, FALSE },
  { POST_CMD,	C_STOR,	G_NONE, post_cmd_stor,	FALSE, FALSE },
  { POST_CMD,	C_APPE, G_NONE, post_cmd_stor,	FALSE, FALSE },
  { POST_CMD,	C_LIST,	G_NONE,	post_cmd_list,	FALSE, FALSE },
  { POST_CMD,	C_NLST, G_NONE, post_cmd_nlst,	FALSE, FALSE },
  { CMD,	"XFOO",	G_DIRS,	cmd_xfoo,	TRUE,  FALSE },
  { 0,		NULL }
};

module sample_module = {
  NULL,NULL,			/* Always NULL */
  0x20,				/* API Version 2.0 */
  "sample",
  sample_config,		/* Sample configuration handler table */
  sample_commands,		/* Sample command handler table */
  NULL,				/* No authentication handler table */
  sample_init,			/* Initialization function */
  sample_child_init		/* Post-fork "child mode" init */
};