"Fossies" - the Fresh Open Source Software Archive 
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
For more information about "ftp_limitlogin.c" see the
Fossies "Dox" file reference documentation.
1 /* Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 /*
18 * Original Copyright (c) 2005 Covalent Technologies
19 *
20 * FTP Protocol module for Apache 2.0
21 */
22
23 #include "mod_ftp.h"
24 #include "ftp_internal.h"
25
26 #include "ap_mpm.h" /* For MPM query interface */
27 #include "apr_dbm.h"
28 #if !(defined(WIN32) || defined(NETWARE))
29 #include "unixd.h"
30 #endif
31
32 #define FTP_SERVER_LIMIT_KEY "FireballXL5OnDVD"
33 #define FTP_DB_FILE_MODE ( APR_UREAD | APR_UWRITE | APR_GREAD | APR_WREAD )
34
35 /*
36 * We also use the below as a state variable. Ugly.
37 */
38 static apr_global_mutex_t *ftp_lock = NULL;
39
40 static apr_status_t ftp_mutex_init(server_rec *s, apr_pool_t *p)
41 {
42 ftp_server_config *fsc = ftp_get_module_config(s->module_config);
43
44 if (fsc->limit_perip || fsc->limit_peruser || fsc->limit_perserver)
45 return apr_global_mutex_create(&ftp_lock,
46 apr_pstrcat(p, fsc->limitdbfile, ".LoCK", NULL),
47 APR_LOCK_DEFAULT, p);
48 else
49 return APR_SUCCESS;
50 }
51
52 static apr_status_t ftp_mutex_on(void)
53 {
54 return apr_global_mutex_lock(ftp_lock);
55 }
56
57 static apr_status_t ftp_mutex_off(void)
58 {
59 return apr_global_mutex_unlock(ftp_lock);
60 }
61
62 static apr_status_t ftp_db_init(server_rec *s, apr_pool_t *p)
63 {
64 apr_status_t rv;
65 apr_dbm_t *dbf;
66 ftp_server_config *fsc = ftp_get_module_config(s->module_config);
67
68 /*
69 * Noop in cases where we have not
70 * setup or enabled the actual mutex. We know
71 * that this is (still) NULL if ftp_mutex_init() determined
72 * it didn't need to bother with login limits.
73 */
74 if (!ftp_lock)
75 return APR_SUCCESS;
76
77 ftp_mutex_on();
78 if ((rv = apr_dbm_open(&dbf, fsc->limitdbfile,
79 APR_DBM_RWCREATE, FTP_DB_FILE_MODE, p)) != APR_SUCCESS) {
80 ap_log_error(APLOG_MARK, APLOG_ERR, rv, s,
81 "Cannot create FTPLimitDBFile file `%s'",
82 fsc->limitdbfile);
83 ftp_mutex_off();
84 return rv;
85 }
86 apr_dbm_close(dbf);
87 #if !defined(OS2) && !defined(WIN32) && !defined(BEOS) && !defined(NETWARE)
88 if (geteuid() == 0) {
89 int ign;
90 #if MODULE_MAGIC_NUMBER_MAJOR < 20081201
91 #define ap_unixd_config unixd_config
92 #endif
93 ign = chown(fsc->limitdbfile, ap_unixd_config.user_id, -1);
94 ign = chown(apr_pstrcat(p, fsc->limitdbfile, ".LoCK", NULL),
95 ap_unixd_config.user_id, -1);
96 ign = chown(apr_pstrcat(p, fsc->limitdbfile, ".db", NULL),
97 ap_unixd_config.user_id, -1);
98 ign = chown(apr_pstrcat(p, fsc->limitdbfile, ".dir", NULL),
99 ap_unixd_config.user_id, -1);
100 ign = chown(apr_pstrcat(p, fsc->limitdbfile, ".pag", NULL),
101 ap_unixd_config.user_id, -1);
102 }
103 #endif
104 ftp_mutex_off();
105
106 return APR_SUCCESS;
107 }
108
109 apr_status_t ftp_mutexdb_init(server_rec *s, apr_pool_t *p)
110 {
111 apr_status_t rv;
112 if ((rv = ftp_mutex_init(s, p)) != APR_SUCCESS)
113 return rv;
114 return ftp_db_init(s, p);
115 }
116
117 apr_status_t ftp_mutexdb_child_init(server_rec *s, apr_pool_t *p)
118 {
119 ftp_server_config *fsc = ftp_get_module_config(s->module_config);
120
121 if (!ftp_lock)
122 return APR_SUCCESS;
123 else
124 return apr_global_mutex_child_init(&ftp_lock, fsc->limitdbfile, p);
125 }
126
127 apr_status_t ftp_mutexdb_cleanup(void *data)
128 {
129 server_rec *s = data;
130 ftp_server_config *fsc = ftp_get_module_config(s->module_config);
131 apr_pool_t *p;
132
133 if (ftp_lock) {
134 apr_global_mutex_destroy(ftp_lock);
135 apr_pool_create_ex(&p, s->process->pool, NULL, NULL);
136 apr_pool_tag(p, "ftp_mutex");
137 if (p) {
138 unlink(apr_pstrcat(p, fsc->limitdbfile, ".db", NULL));
139 unlink(apr_pstrcat(p, fsc->limitdbfile, ".dir", NULL));
140 unlink(apr_pstrcat(p, fsc->limitdbfile, ".pag", NULL));
141 unlink(apr_pstrcat(p, fsc->limitdbfile, ".LoCK", NULL));
142 unlink(fsc->limitdbfile);
143 apr_pool_destroy(p);
144 }
145 ftp_lock = NULL;
146 }
147
148 return APR_SUCCESS;
149 }
150
151 #define MYMIN(a,b) ( (a) < (b) ? (a) : (b) )
152
153 ftp_loginlimit_t ftp_limitlogin_check(const char *user, request_rec *r)
154 {
155 apr_status_t rv;
156 conn_rec *c = r->connection;
157 apr_datum_t ukey;
158 apr_datum_t ikey;
159 apr_datum_t skey;
160 apr_datum_t val;
161 apr_dbm_t *dbf;
162 char temp[10]; /* Note: This means only values <=
163 * 999,999,999 */
164 int uval = 0;
165 int ival = 0;
166 int sval = 0;
167 char *tkey;
168 char *sname = (r->server->server_hostname
169 ? r->server->server_hostname
170 : "unknown");
171 ftp_server_config *fsc =
172 ftp_get_module_config(r->server->module_config);
173
174 if (!ftp_lock)
175 return FTP_LIMIT_OK;
176
177 ftp_mutex_on();
178 if ((rv = apr_dbm_open(&dbf, fsc->limitdbfile,
179 APR_DBM_RWCREATE, FTP_DB_FILE_MODE, r->pool)) != APR_SUCCESS) {
180 ap_log_error(APLOG_MARK, APLOG_ERR, rv, r->server,
181 "Cannot open FTPLimitDBFile file `%s' for login check",
182 fsc->limitdbfile);
183 ftp_mutex_off();
184 return FTP_LIMIT_ERROR;
185 }
186 /*
187 * First we check the user settings.
188 * This is a safe cast, this is a lookup key.
189 */
190 tkey = apr_psprintf(r->pool, "%s-%s", sname, user);
191 ukey.dptr = (char *) tkey;
192 ukey.dsize = strlen(tkey);
193 rv = apr_dbm_fetch(dbf, ukey, &val); /* error for non-existant? */
194 if (val.dptr != NULL && val.dsize > 0) {
195 apr_cpystrn(temp, val.dptr, MYMIN(sizeof(temp), val.dsize + 1));
196 uval = atoi(temp);
197 }
198 if (fsc->limit_peruser && uval >= fsc->limit_peruser) {
199 ftp_mutex_off();
200 return FTP_LIMIT_HIT_PERUSER;
201 }
202 /*
203 * Now we check the IP settings.
204 * This is a safe cast, this is a lookup key.
205 */
206 tkey = apr_psprintf(r->pool, "%s-%s", sname, c->remote_ip);
207 ikey.dptr = (char *) tkey;
208 ikey.dsize = strlen(tkey);
209 rv = apr_dbm_fetch(dbf, ikey, &val); /* error for non-existant? */
210 if (val.dptr != NULL && val.dsize > 0) {
211 apr_cpystrn(temp, val.dptr, MYMIN(sizeof(temp), val.dsize + 1));
212 ival = atoi(temp);
213 }
214 if (fsc->limit_perip && ival >= fsc->limit_perip) {
215 ftp_mutex_off();
216 return FTP_LIMIT_HIT_PERIP;
217 }
218 /*
219 * OK, so we're not up against the per user or IP limit,
220 * we need to check the perserver limit then
221 */
222
223 tkey = apr_psprintf(r->pool, "%s-%s", sname, FTP_SERVER_LIMIT_KEY);
224 skey.dptr = (char *) tkey;
225 skey.dsize = strlen(tkey);
226 rv = apr_dbm_fetch(dbf, skey, &val); /* error for non-existant? */
227 if (val.dptr != NULL && val.dsize > 0) {
228 apr_cpystrn(temp, val.dptr, MYMIN(sizeof(temp), val.dsize + 1));
229 sval = atoi(temp);
230 }
231 if (fsc->limit_perserver && sval >= fsc->limit_perserver) {
232 ftp_mutex_off();
233 return FTP_LIMIT_HIT_PERSERVER;
234 }
235
236 /*
237 * Oh joy. Oh rapture. We have room for this person. We
238 * now go ahead and update these values in the DB "atomically".
239 * If not (that is, if we check and then, if OK, we *then*
240 * update), we hit a race condition.
241 */
242 sval++;
243 uval++;
244 ival++;
245 apr_snprintf(temp, sizeof(temp), "%d", uval);
246 val.dptr = temp;
247 val.dsize = strlen(temp);
248 rv = apr_dbm_store(dbf, ukey, val);
249
250 apr_snprintf(temp, sizeof(temp), "%d", ival);
251 val.dptr = temp;
252 val.dsize = strlen(temp);
253 rv = apr_dbm_store(dbf, ikey, val);
254
255 apr_snprintf(temp, sizeof(temp), "%d", sval);
256 val.dptr = temp;
257 val.dsize = strlen(temp);
258 rv = apr_dbm_store(dbf, skey, val);
259
260 apr_dbm_close(dbf);
261
262 ftp_mutex_off();
263
264 return FTP_LIMIT_OK;
265 }
266
267 int ftp_limitlogin_loggedout(conn_rec *c)
268 {
269 ftp_connection *fc = ftp_get_module_config(c->conn_config);
270 apr_status_t rv;
271 apr_datum_t ukey;
272 apr_datum_t ikey;
273 apr_datum_t skey;
274 apr_datum_t val;
275 apr_dbm_t *dbf;
276 char temp[10]; /* Note: This means only values <=
277 * 999,999,999 */
278 int uval = 0;
279 int ival = 0;
280 int sval = 0;
281 char *tkey;
282 char *sname = (fc->orig_server->server_hostname
283 ? fc->orig_server->server_hostname
284 : "unknown");
285 ftp_server_config *fsc =
286 ftp_get_module_config(fc->orig_server->module_config);
287
288 if (!ftp_lock)
289 return 0;
290
291 ftp_mutex_on();
292 if ((rv = apr_dbm_open(&dbf, fsc->limitdbfile,
293 APR_DBM_RWCREATE, FTP_DB_FILE_MODE, fc->login_pool))
294 != APR_SUCCESS) {
295 ap_log_error(APLOG_MARK, APLOG_ERR, rv, fc->orig_server,
296 "Cannot open FTPLimitDBFile file `%s' for logged out update",
297 fsc->limitdbfile);
298 ftp_mutex_off();
299 return rv;
300 }
301 /*
302 * This is a safe cast, it's a lookup key
303 */
304 tkey = apr_psprintf(c->pool, "%s-%s", sname, fc->user);
305 ukey.dptr = (char *) tkey;
306 ukey.dsize = strlen(tkey);
307 rv = apr_dbm_fetch(dbf, ukey, &val); /* error for non-existant? */
308 if (val.dptr != NULL && val.dsize > 0) {
309 apr_cpystrn(temp, val.dptr, MYMIN(sizeof(temp), val.dsize + 1));
310 uval = atoi(temp);
311 }
312
313 tkey = apr_psprintf(c->pool, "%s-%s", sname, c->remote_ip);
314 ikey.dptr = (char *) tkey;
315 ikey.dsize = strlen(tkey);
316 rv = apr_dbm_fetch(dbf, ikey, &val); /* error for non-existant? */
317 if (val.dptr != NULL && val.dsize > 0) {
318 apr_cpystrn(temp, val.dptr, MYMIN(sizeof(temp), val.dsize + 1));
319 ival = atoi(temp);
320 }
321
322 tkey = apr_psprintf(c->pool, "%s-%s", sname, FTP_SERVER_LIMIT_KEY);
323 skey.dptr = tkey;
324 skey.dsize = strlen(tkey);
325 rv = apr_dbm_fetch(dbf, skey, &val); /* error for non-existant? */
326 if (val.dptr != NULL && val.dsize > 0) {
327 apr_cpystrn(temp, val.dptr, MYMIN(sizeof(temp), val.dsize + 1));
328 sval = atoi(temp);
329 }
330 sval--;
331 uval--;
332 ival--;
333 if (sval < 0)
334 sval = 0;
335 if (uval < 0)
336 uval = 0;
337 if (ival < 0)
338 ival = 0;
339
340 apr_snprintf(temp, sizeof(temp), "%d", uval);
341 val.dptr = temp;
342 val.dsize = strlen(temp);
343 rv = apr_dbm_store(dbf, ukey, val);
344
345 apr_snprintf(temp, sizeof(temp), "%d", ival);
346 val.dptr = temp;
347 val.dsize = strlen(temp);
348 rv = apr_dbm_store(dbf, ikey, val);
349
350 apr_snprintf(temp, sizeof(temp), "%d", sval);
351 val.dptr = temp;
352 val.dsize = strlen(temp);
353 rv = apr_dbm_store(dbf, skey, val);
354
355 apr_dbm_close(dbf);
356
357 ftp_mutex_off();
358
359 return 0;
360 }