1 /* vi:ai:et:ts=8 sw=2
2 */
3 /*
4 * wzdftpd - a modular and cool ftp server
5 * Copyright (C) 2002-2004 Pierre Chifflier
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 *
21 * As a special exemption, Pierre Chifflier
22 * and other respective copyright holders give permission to link this program
23 * with OpenSSL, and distribute the resulting executable, without including
24 * the source code for OpenSSL in the source distribution.
25 */
26
27 #include "wzd_all.h"
28
29 #ifndef WZD_USE_PCH
30
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <sys/stat.h>
35 #include <time.h>
36 #include <errno.h>
37
38 #ifdef WIN32
39 #include <winsock2.h>
40 #else
41 #include <sys/types.h>
42 #include <sys/socket.h>
43 #include <netinet/in.h>
44 #include <arpa/inet.h>
45
46 #include <dlfcn.h>
47 #endif
48
49
50 #if defined(BSD) && !(defined(__MACH__) && defined(__APPLE__))
51 #define DL_ARG DL_LAZY
52 #else
53 #define DL_ARG RTLD_NOW
54 #endif
55
56 #include "wzd_structs.h"
57
58 #include "wzd_backend.h"
59 #include "wzd_cache.h"
60 #include "wzd_configfile.h"
61 #include "wzd_fs.h"
62 #include "wzd_group.h"
63 #include "wzd_misc.h"
64 #include "wzd_libmain.h"
65 #include "wzd_log.h"
66 #include "wzd_user.h"
67
68 #include "wzd_debug.h"
69
70 #ifdef NEED_UNDERSCORE
71 #define DL_PREFIX "_"
72 #else
73 #define DL_PREFIX
74 #endif
75
76 #endif /* WZD_USE_PCH */
77
78
79 static int _trigger_user_max_dl(wzd_user_t * user);
80 static int _trigger_user_max_ul(wzd_user_t * user);
81
82
83 /** \brief Get backend version
84 */
backend_get_version(wzd_backend_def_t * backend)85 char *backend_get_version(wzd_backend_def_t *backend)
86 {
87 char ** version_found;
88
89 if (backend->handle)
90 version_found = (char**)dlsym(backend->handle,DL_PREFIX "wzd_backend_version");
91 else
92 return NULL;
93
94 return (*version_found);
95 }
96
97 /** \brief Get backend name
98 *
99 * \note This is generally the short name of the backend (for ex, pgsql), and
100 * is different from the name defined in the config (the shared library name).
101 */
backend_get_name(wzd_backend_def_t * backend)102 char *backend_get_name(wzd_backend_def_t *backend)
103 {
104 char ** backend_name;
105
106 if (backend->handle)
107 backend_name = (char**)dlsym(backend->handle,DL_PREFIX "wzd_backend_name");
108 else
109 return NULL;
110
111 return (*backend_name);
112 }
113
114 /** \brief Initialize a newly allocated wzd_backend_def_t structure
115 */
backend_clear_struct(wzd_backend_def_t * backend)116 static void backend_clear_struct(wzd_backend_def_t *backend)
117 {
118 if (backend->param) {
119 wzd_free(backend->param);
120 backend->param = NULL;
121 }
122 wzd_free(backend->filename);
123 backend->filename = NULL;
124 backend->handle = NULL;
125
126 if (backend->b) {
127 wzd_free(backend->b->name);
128 }
129
130 wzd_free(backend->b);
131 backend->b = NULL;
132 }
133
134 /** \brief Validate backend by checking needed functions, and if a specific version is required
135 *
136 * \param backend The shared library file name
137 * \param pred A predicate (for ex, >=)
138 * \param version The version to be compared, by the predicate, to the backend version
139 *
140 * \return
141 * - a newly allocated structure for the backend, or
142 * - NULL if some functions are missing (check logs for details)
143 *
144 * \note Actually, \a pred and \a version are ignored
145 */
backend_validate(const char * backend,const char * pred,const char * version)146 wzd_backend_def_t * backend_validate(const char *backend, const char *pred, const char *version)
147 {
148 fs_filestat_t st;
149 int ret;
150 wzd_backend_def_t * def;
151
152 ret = fs_file_lstat(backend,&st);
153 if (ret) {
154 out_log(LEVEL_HIGH,"Could not stat backend '%s'\n",backend);
155 out_log(LEVEL_HIGH,"errno: %d error: %s\n",errno, strerror(errno));
156 return NULL;
157 }
158
159 def = backend_register(backend, NULL /* dynamic backend */);
160 if (def == NULL) {
161 out_err(LEVEL_HIGH,"ERROR while registering backend '%s'\n",backend);
162 return NULL;
163 }
164
165 return def;
166 }
167
168 /**
169 * \brief Initialize backend
170 * \param backend The backend name
171 */
backend_init(wzd_backend_def_t * backend)172 int backend_init(wzd_backend_def_t * backend)
173 {
174 wzd_backend_t * b;
175 int ret;
176
177 WZD_ASSERT(backend != NULL);
178 if (backend == NULL) return -1;
179
180 b = backend->b;
181
182 WZD_ASSERT(backend != NULL);
183 if (backend == NULL) return -1;
184
185 if (b->backend_init) {
186 wzd_string_t * str;
187 /* LOGFILE */
188 str = config_get_string(mainConfig->cfg_file, b->name, "param", NULL);
189 if (str) {
190 wzd_free(backend->param);
191 backend->param = wzd_strdup(str_tochar(str));
192 str_deallocate(str);
193 }
194
195 ret = (b->backend_init)(backend->param);
196 if (ret) {
197 out_log(LEVEL_HIGH,"ERROR could not backend %s, init function returned %d\n",backend->filename,ret);
198 return 1;
199 }
200 }
201
202 return 0;
203 }
204
205 /** \brief Register backend
206 * Use \a filename for dynamic modules (shared libraries)
207 * \a fcn for static modules.
208 * When loading a static module, \a filename is used as a comment
209 */
backend_register(const char * filename,backend_init_function_t fcn)210 struct wzd_backend_def_t * backend_register(const char * filename, backend_init_function_t fcn)
211 {
212 wzd_backend_def_t * def = NULL;
213 wzd_backend_t * b;
214 void * handle = NULL;
215 int ret;
216
217 if (filename == NULL && fcn == NULL) return NULL;
218
219 if (fcn == NULL) {
220 /* test dlopen */
221 handle = dlopen(filename,DL_ARG);
222 if (!handle) {
223 out_log(LEVEL_HIGH,"Could not dlopen backend '%s'\n",filename);
224 out_log(LEVEL_HIGH,"errno: %d error: %s\n",errno, strerror(errno));
225 out_log(LEVEL_HIGH,"dlerror: %s\n",dlerror());
226 return NULL;
227 }
228
229 fcn = (backend_init_function_t)dlsym(handle, DL_PREFIX "wzd_backend_init");
230 if (fcn == NULL) {
231 out_err(LEVEL_HIGH,"%s does not seem to be a valid backend - function %s was not found\n",filename,"wzd_backend_init");
232 dlclose(handle);
233 return NULL;
234 }
235 }
236
237 b = wzd_malloc(sizeof(wzd_backend_t));
238 memset(b,0,sizeof(wzd_backend_t));
239 b->struct_version = STRUCT_BACKEND_VERSION;
240 b->backend_id = 1; /** \todo auto-increment */
241
242 ret = (*fcn)(b);
243
244 if (ret != 0) {
245 out_log(LEVEL_HIGH,"ERROR could not backend %s, init function returned %d\n",filename,ret);
246 wzd_free(b);
247 if (handle != NULL) dlclose(handle);
248 return NULL;
249 }
250
251 def = wzd_malloc(sizeof(wzd_backend_def_t));
252 memset(def,0,sizeof(wzd_backend_def_t));
253 if (handle != NULL) {
254 def->handle = handle;
255 def->filename = wzd_strdup(filename);
256 }
257 def->b = b;
258
259 return def;
260 }
261
262 /** \brief Close backend and associated resources
263 *
264 * Call backend exit function (if defined), mark backend as closed, and
265 * unloads shared library if present.
266 *
267 * \note The backend structure must still be removed from list
268 *
269 * \return
270 * - 0 if ok
271 * - 1 if an error occurred
272 */
backend_close(const char * backend)273 int backend_close(const char *backend)
274 {
275 int (*fini_fcn)(void) = NULL;
276 int ret;
277
278 if (!backend || !mainConfig->backends) return 1;
279
280 if (backend_inuse(backend) > 0) {
281 out_log(LEVEL_NORMAL,"Attempting to close backend %s while in use\n",backend);
282 return 1;
283 }
284
285 /* step 1: check that backend == mainConfig->backend.name */
286 if (strcmp(backend,mainConfig->backends->filename)!=0) return 1;
287
288 /* step 2: call end function */
289 if (mainConfig->backends->b) {
290 fini_fcn = mainConfig->backends->b->backend_exit;
291 }
292 if (fini_fcn) {
293 ret = (*fini_fcn)();
294 if (ret) {
295 out_log(LEVEL_CRITICAL,"Backend %s reported errors on exit (handle %lu)\n",
296 backend,(unsigned long)mainConfig->backends->handle);
297 /* return 1;*/
298 }
299 }
300
301 /* close backend */
302 ret = 0;
303 if (mainConfig->backends->handle)
304 {
305 char * tempname = strdup(backend);
306 ret = dlclose(mainConfig->backends->handle);
307 if (ret) {
308 #ifdef WIN32
309 ret = GetLastError();
310 out_log(LEVEL_INFO," Could not close backend %s (handle %lu)\n Error %d %s\n",
311 tempname,mainConfig->backends->handle, ret,strerror(ret));
312 #else
313 out_log(LEVEL_INFO,"Could not close backend %s (handle %lu)\n",
314 tempname,(unsigned long)mainConfig->backends->handle);
315 out_log(LEVEL_INFO," Error '%s'\n",dlerror());
316 #endif
317 backend_clear_struct(mainConfig->backends);
318
319 free(tempname);
320 return 1;
321 }
322 free(tempname);
323 }
324
325 backend_clear_struct(mainConfig->backends);
326
327 /** \todo XXX remove backend from list */
328
329 return 0;
330 }
331
332 /** \brief Reload backend
333 *
334 * \todo backend_reload is not yet implemented
335 *
336 * \param backend The backend (short) name
337 *
338 * \return
339 * - 0 if ok
340 * - 1 if an error occurred (the backend may be in inconsistant state)
341 */
backend_reload(const char * backend)342 int backend_reload(const char *backend)
343 {
344 int ret;
345
346 #if 0
347 ret = backend_close(backend);
348 if (ret) return 1;
349
350 ret = backend_init(backend,0 /* max users */,0 /* max groups */);
351 if (ret) return 1;
352 #endif
353 out_log(LEVEL_HIGH,"backend_reload: not yet implemented\n");
354
355 return 1;
356 }
357
358 /**
359 * \brief Get user informations
360 * \param userid The user id, or the special value (uid_t)-2
361 *
362 * Search backend for user with the corresponding uid and return the corresponding struct.
363 *
364 * If the argument is -2, this function returns an array of uid (ended with -1) containing
365 * the list of all known users (you have to cast the return to a (uid_t *) to use it). You must
366 * free the returned array using wzd_free().
367 */
backend_get_user(uid_t userid)368 wzd_user_t * backend_get_user(uid_t userid)
369 {
370 wzd_backend_t * b;
371
372 if (userid == (uid_t)-1) return NULL;
373
374 if ( (b = mainConfig->backends->b) && b->backend_get_user)
375 return b->backend_get_user(userid);
376
377 if (b == NULL)
378 out_log(LEVEL_CRITICAL,"Attempt to call a backend function on %s:%d while there is no available backend !\n", __FILE__, __LINE__);
379 else
380 out_log(LEVEL_CRITICAL,"FATAL: backend %s does not define get_user method\n",b->name);
381 return NULL;
382 }
383
384
385 /** \brief Search for user with name \a name in backends
386 *
387 * If an user is found, its uid is stored in \a userid. If \a user is not NULL,
388 * the structure is copied (and should be freed using free() )
389 */
backend_find_user(const char * name,wzd_user_t * user,int * userid)390 int backend_find_user(const char *name, wzd_user_t * user, int * userid)
391 {
392 int ret;
393 wzd_backend_t * b;
394
395 if ( (b = mainConfig->backends->b) && b->backend_find_user)
396 ret = b->backend_find_user(name,user);
397 else {
398 if (b == NULL)
399 out_log(LEVEL_CRITICAL,"Attempt to call a backend function on %s:%d while there is no available backend !\n", __FILE__, __LINE__);
400 else
401 out_log(LEVEL_CRITICAL,"FATAL: backend %s does not define find_user method\n",b->name);
402 return -1;
403 }
404
405 if (ret >= 0) {
406 if (user) {
407 wzd_user_t * _tmp_user;
408 _tmp_user = GetUserByID(ret);
409 if (!_tmp_user) return -1;
410 memcpy(user,_tmp_user,sizeof(wzd_user_t));
411 }
412 if (userid) *userid = ret;
413 return 0;
414 }
415 return ret;
416 }
417
418 /** \brief Get user identified by \a id from backend
419 *
420 * \param id The uid of the user
421 *
422 * \return A wzd_user_t structure, or NULL if not found
423 */
GetUserByID(uid_t id)424 wzd_user_t * GetUserByID(uid_t id)
425 {
426 wzd_user_t *user;
427 wzd_backend_t * b;
428
429 if (!mainConfig) return NULL;
430
431 if (id == (uid_t)-1) return NULL;
432
433 if ( (b = mainConfig->backends->b) && b->backend_get_user) {
434 WZD_MUTEX_LOCK(SET_MUTEX_BACKEND);
435 user = b->backend_get_user(id);
436 WZD_MUTEX_UNLOCK(SET_MUTEX_BACKEND);
437 }
438 else {
439 if (b == NULL)
440 out_log(LEVEL_CRITICAL,"Attempt to call a backend function on %s:%d while there is no available backend !\n", __FILE__, __LINE__);
441 else
442 out_log(LEVEL_CRITICAL,"FATAL: backend %s does not define get_user method\n",b->name);
443 return NULL;
444 }
445
446 return user;
447 }
448
449 /** \brief Get user identified by \a name from backend
450 *
451 * \param name The name of the user
452 *
453 * \return A wzd_user_t structure, or NULL if not found
454 */
GetUserByName(const char * name)455 wzd_user_t * GetUserByName(const char *name)
456 {
457 uid_t uid;
458 wzd_user_t * user=NULL;
459 wzd_backend_t * b;
460
461 if (!mainConfig || !name || strlen(name)<=0) return NULL;
462 out_err(LEVEL_CRITICAL,"GetUserByName %s\n",name);
463
464 if ( (b = mainConfig->backends->b) && b->backend_find_user) {
465 WZD_MUTEX_LOCK(SET_MUTEX_BACKEND);
466 uid = b->backend_find_user(name,user);
467 WZD_MUTEX_UNLOCK(SET_MUTEX_BACKEND);
468 }
469 else {
470 if (b == NULL)
471 out_log(LEVEL_CRITICAL,"Attempt to call a backend function on %s:%d while there is no available backend !\n", __FILE__, __LINE__);
472 else
473 out_log(LEVEL_CRITICAL,"FATAL: backend %s does not define find_user method\n",b->name);
474 return NULL;
475 }
476
477 if (uid != (uid_t)-1) {
478 return GetUserByID( uid );
479 }
480 return NULL;
481 }
482
483 /** \brief Get user ID identified by \a name from backend
484 *
485 * \param name The name of the user
486 *
487 * \return The unique identifier of the user, or -1 if not found
488 */
GetUserIDByName(const char * name)489 uid_t GetUserIDByName(const char *name)
490 {
491 wzd_user_t * user;
492
493 if ( (user=GetUserByName(name)) )
494 return user->uid;
495
496 return (uid_t)-1;
497 }
498
499
500
501
502
503 /**
504 * \brief Get group informations
505 * \param groupid The group id, or the special value (gid_t)-2
506 *
507 * Search backend for group with the corresponding gid and return the corresponding struct.
508 *
509 * If the argument is -2, this function returns an array of gid (ended with -1) containing
510 * the list of all known groups (you have to cast the return to a (gid_t *) to use it). You must
511 * free the returned array using wzd_free().
512 */
backend_get_group(gid_t groupid)513 wzd_group_t * backend_get_group(gid_t groupid)
514 {
515 wzd_backend_t * b;
516 if ( (b = mainConfig->backends->b) && b->backend_get_group)
517 return b->backend_get_group(groupid);
518
519 if (b == NULL)
520 out_log(LEVEL_CRITICAL,"Attempt to call a backend function on %s:%d while there is no available backend !\n", __FILE__, __LINE__);
521 else
522 out_log(LEVEL_CRITICAL,"FATAL: backend %s does not define get_group method\n",b->name);
523 return NULL;
524 }
525
526 /** \brief Search for group with name \a name in backends
527 *
528 * If a group is found, its gid is stored in \a groupid. If \a group is not NULL,
529 * the structure is copied (and should be freed using free() )
530 */
backend_find_group(const char * name,wzd_group_t * group,int * groupid)531 int backend_find_group(const char *name, wzd_group_t * group, int * groupid)
532 {
533 int ret;
534 wzd_backend_t * b;
535
536 if ( (b = mainConfig->backends->b) && b->backend_find_group)
537 ret = b->backend_find_group(name,group);
538 else {
539 if (b == NULL)
540 out_log(LEVEL_CRITICAL,"Attempt to call a backend function on %s:%d while there is no available backend !\n", __FILE__, __LINE__);
541 else
542 out_log(LEVEL_CRITICAL,"FATAL: backend %s does not define find_group method\n",b->name);
543 return -1;
544 }
545
546 if (ret >= 0) {
547 if (group) {
548 wzd_group_t * _tmp_group;
549 _tmp_group = GetGroupByID(ret);
550 if (!_tmp_group) return -1;
551 memcpy(group,_tmp_group,sizeof(wzd_group_t));
552 }
553 if (groupid) *groupid = ret;
554 return 0;
555 }
556 return ret;
557 }
558
559
560 /** \brief Get group identified by \a id from backend
561 *
562 * \param id The gid of the group
563 *
564 * \return A wzd_group_t structure, or NULL if not found
565 */
GetGroupByID(gid_t id)566 wzd_group_t * GetGroupByID(gid_t id)
567 {
568 wzd_group_t * group = NULL;
569 wzd_backend_t * b;
570
571 if (!mainConfig) return NULL;
572
573 if ( (b = mainConfig->backends->b) && b->backend_get_group) {
574 WZD_MUTEX_LOCK(SET_MUTEX_BACKEND);
575 group = b->backend_get_group(id);
576 WZD_MUTEX_UNLOCK(SET_MUTEX_BACKEND);
577 }
578 else {
579 if (b == NULL)
580 out_log(LEVEL_CRITICAL,"Attempt to call a backend function on %s:%d while there is no available backend !\n", __FILE__, __LINE__);
581 else
582 out_log(LEVEL_CRITICAL,"FATAL: backend %s does not define get_group method\n",b->name);
583 return NULL;
584 }
585
586 return group;
587 }
588
589 /** \brief Get group identified by \a name from backend
590 *
591 * \param name The name of the group
592 *
593 * \return A wzd_group_t structure, or NULL if not found
594 */
GetGroupByName(const char * name)595 wzd_group_t * GetGroupByName(const char *name)
596 {
597 gid_t gid;
598 wzd_group_t * group = NULL;
599 wzd_backend_t * b;
600
601 if (!mainConfig || !name || strlen(name)<=0) return NULL;
602
603 if ( (b = mainConfig->backends->b) && b->backend_find_group) {
604 WZD_MUTEX_LOCK(SET_MUTEX_BACKEND);
605 gid = b->backend_find_group(name,group);
606 WZD_MUTEX_UNLOCK(SET_MUTEX_BACKEND);
607 }
608 else {
609 if (b == NULL)
610 out_log(LEVEL_CRITICAL,"Attempt to call a backend function on %s:%d while there is no available backend !\n", __FILE__, __LINE__);
611 else
612 out_log(LEVEL_CRITICAL,"FATAL: backend %s does not define find_group method\n",b->name);
613 return NULL;
614 }
615
616 if (gid != (gid_t)-1) {
617 return GetGroupByID( gid );
618 }
619
620 return NULL;
621 }
622
623 /** \brief Get group ID identified by \a name from backend
624 *
625 * \param name The name of the group
626 *
627 * \return The unique identifier of the group, or -1 if not found
628 */
GetGroupIDByName(const char * name)629 gid_t GetGroupIDByName(const char *name)
630 {
631 wzd_group_t * group;
632
633 if ( (group=GetGroupByName(name)) )
634 return group->gid;
635
636 return (gid_t)-1;
637 }
638
639
640 /** \brief Check if \a name is a defined in backend, and retrieve the associated structure
641 */
backend_validate_login(const char * name,wzd_user_t * user,uid_t * userid)642 int backend_validate_login(const char *name, wzd_user_t * user, uid_t * userid)
643 {
644 uid_t ret;
645 wzd_backend_t * b;
646
647 if ( (b = mainConfig->backends->b) && b->backend_validate_login) {
648 WZD_MUTEX_LOCK(SET_MUTEX_BACKEND);
649 ret = b->backend_validate_login(name,user);
650 WZD_MUTEX_UNLOCK(SET_MUTEX_BACKEND);
651 }
652 else {
653 if (b == NULL)
654 out_log(LEVEL_CRITICAL,"Attempt to call a backend function on %s:%d while there is no available backend !\n", __FILE__, __LINE__);
655 else
656 out_log(LEVEL_CRITICAL,"FATAL: backend %s does not define validate_login method\n",b->name);
657 return -1;
658 }
659
660 if (ret != (uid_t)-1) {
661 if (user) {
662 wzd_user_t * _tmp_user;
663 _tmp_user = GetUserByID(ret);
664 if (!_tmp_user) return -1;
665 memcpy(user,_tmp_user,sizeof(wzd_user_t));
666 }
667 *userid = ret;
668 return 0;
669 }
670 return -1;
671 }
672
673 /** \brief Check user and password, and retrieve associated structure
674 */
backend_validate_pass(const char * name,const char * pass,wzd_user_t * user,uid_t * userid)675 int backend_validate_pass(const char *name, const char *pass, wzd_user_t *user, uid_t * userid)
676 {
677 uid_t ret;
678 wzd_backend_t * b;
679
680 if ( (b = mainConfig->backends->b) && b->backend_validate_pass) {
681 WZD_MUTEX_LOCK(SET_MUTEX_BACKEND);
682 ret = b->backend_validate_pass(name,pass,user);
683 WZD_MUTEX_UNLOCK(SET_MUTEX_BACKEND);
684 }
685 else {
686 if (b == NULL)
687 out_log(LEVEL_CRITICAL,"Attempt to call a backend function on %s:%d while there is no available backend !\n", __FILE__, __LINE__);
688 else
689 out_log(LEVEL_CRITICAL,"FATAL: backend %s does not define validate_pass method\n",b->name);
690 return -1;
691 }
692
693 if (ret != (uid_t)-1) {
694 if (user) {
695 wzd_user_t * _tmp_user;
696 _tmp_user = GetUserByID(ret);
697 if (!_tmp_user) return -1;
698 memcpy(user,_tmp_user,sizeof(wzd_user_t));
699 }
700 *userid = ret;
701 return 0;
702 }
703 return -1;
704 }
705
706 /** \brief Commit changes to backend
707 */
backend_commit_changes(const char * backend)708 int backend_commit_changes(const char *backend)
709 {
710 wzd_backend_t * b;
711
712 if ( (b = mainConfig->backends->b) && b->backend_commit_changes)
713 return b->backend_commit_changes();
714
715 if (b == NULL)
716 out_log(LEVEL_CRITICAL,"Attempt to call a backend function on %s:%d while there is no available backend !\n", __FILE__, __LINE__);
717 else
718 out_log(LEVEL_CRITICAL,"FATAL: backend %s does not define commit_changes method\n",b->name);
719 return -1;
720 }
721
722 /** \brief Check if a backend is currently used
723 * \return The number of users connected currently using this backend
724 */
backend_inuse(const char * backend)725 int backend_inuse(const char *backend)
726 {
727 int count;
728 ListElmt * elmnt;
729 wzd_context_t * context;
730 u16_t backend_id = 0;
731 wzd_user_t * user;
732 /* unusually, if backend is not loaded it is not in use ... so no error here */
733 if (mainConfig->backends==NULL || mainConfig->backends->handle==NULL)
734 return -1;
735
736 /* find backend id */
737 if (strcmp(backend,mainConfig->backends->b->name)==0)
738 backend_id = mainConfig->backends->b->backend_id;
739
740 if (backend_id == 0) return -1;
741
742 /* count user logged in */
743 count = 0;
744 for (elmnt=list_head(context_list); elmnt != NULL; elmnt = list_next(elmnt)) {
745 context = list_data(elmnt);
746 if (context->magic == CONTEXT_MAGIC) {
747 user = GetUserByID(context->userid);
748 if (user->backend_id == backend_id)
749 count++;
750 }
751 }
752
753 return count;
754 }
755
756 /** \brief Send user modifications to backend
757 *
758 * The modified user is identified by the backend and the \a uid.
759 * \a mod_type is used to determine which values are changed, and the new values
760 * are taken from the structure \a user.
761 *
762 * If the user does not exist, the backend will add it. If \a user is NULL, the user
763 * is deleted.
764 */
backend_mod_user(const char * backend,uid_t uid,wzd_user_t * user,unsigned long mod_type)765 int backend_mod_user(const char *backend, uid_t uid, wzd_user_t * user, unsigned long mod_type)
766 {
767 int ret;
768 wzd_backend_t * b;
769 wzd_user_t * new_user;
770
771 WZD_MUTEX_LOCK(SET_MUTEX_BACKEND);
772
773 if ( (b = mainConfig->backends->b) && b->backend_mod_user)
774 ret = b->backend_mod_user(uid,user,mod_type);
775 else {
776 if (b == NULL)
777 out_log(LEVEL_CRITICAL,"Attempt to call a backend function on %s:%d while there is no available backend !\n", __FILE__, __LINE__);
778 else
779 out_log(LEVEL_CRITICAL,"FATAL: backend %s does not define mod_user method\n",b->name);
780 WZD_MUTEX_UNLOCK(SET_MUTEX_BACKEND);
781 return -1;
782 }
783
784 if (ret == 0) {
785 if (mod_type & _USER_MAX_ULS) _trigger_user_max_ul(user);
786 if (mod_type & _USER_MAX_DLS) _trigger_user_max_dl(user);
787 }
788
789 /* usercache_invalidate( predicate_name, (void *)name );*/
790
791 if (!ret && user) { /* modification ok, reload user */
792 if ( (b = mainConfig->backends->b) && b->backend_get_user)
793 new_user = b->backend_get_user(user->uid);
794 else {
795 if (b == NULL)
796 out_log(LEVEL_CRITICAL,"Attempt to call a backend function on %s:%d while there is no available backend !\n", __FILE__, __LINE__);
797 else
798 out_log(LEVEL_CRITICAL,"FATAL: backend %s does not define get_user method\n",b->name);
799 WZD_MUTEX_UNLOCK(SET_MUTEX_BACKEND);
800 return -1;
801 }
802
803 if (new_user != user) {
804 if (new_user) {
805 *user = *new_user;
806 wzd_free(new_user);
807 } else {
808 wzd_free(user);
809 }
810 }
811 }
812
813 WZD_MUTEX_UNLOCK(SET_MUTEX_BACKEND);
814 return ret;
815 }
816
817 /** \brief Send group modifications to backend
818 *
819 * The modified group is identified by the backend and the \a gid.
820 * \a mod_type is used to determine which values are changed, and the new values
821 * are taken from the structure \a group.
822 *
823 * If the group. does not exist, the backend will add it. If \a group. is NULL, the group.
824 * is deleted.
825 */
backend_mod_group(const char * backend,gid_t gid,wzd_group_t * group,unsigned long mod_type)826 int backend_mod_group(const char *backend, gid_t gid, wzd_group_t * group, unsigned long mod_type)
827 {
828 int ret;
829 wzd_backend_t * b;
830 wzd_group_t * new_group;
831
832 WZD_MUTEX_LOCK(SET_MUTEX_BACKEND);
833
834 if ( (b = mainConfig->backends->b) && b->backend_mod_group)
835 ret = b->backend_mod_group(gid,group,mod_type);
836 else {
837 if (b == NULL)
838 out_log(LEVEL_CRITICAL,"Attempt to call a backend function on %s:%d while there is no available backend !\n", __FILE__, __LINE__);
839 else
840 out_log(LEVEL_CRITICAL,"FATAL: backend %s does not define mod_group method\n",b->name);
841 WZD_MUTEX_UNLOCK(SET_MUTEX_BACKEND);
842 return -1;
843 }
844
845 /* groupcache_invalidate( predicate_groupname, (void *)name );*/
846
847 if (!ret && group) { /* modification ok, reload group */
848 if ( (b = mainConfig->backends->b) && b->backend_get_group)
849 new_group = b->backend_get_group(group->gid);
850 else {
851 if (b == NULL)
852 out_log(LEVEL_CRITICAL,"Attempt to call a backend function on %s:%d while there is no available backend !\n", __FILE__, __LINE__);
853 else
854 out_log(LEVEL_CRITICAL,"FATAL: backend %s does not define get_user method\n",b->name);
855 WZD_MUTEX_UNLOCK(SET_MUTEX_BACKEND);
856 return -1;
857 }
858
859 if (new_group != group) {
860 if (new_group) {
861 *group = *new_group;
862 wzd_free(new_group);
863 } else {
864 wzd_free(group);
865 }
866 }
867 }
868
869 WZD_MUTEX_UNLOCK(SET_MUTEX_BACKEND);
870 return ret;
871 }
872
873
874
875
876
877
_trigger_user_max_dl(wzd_user_t * user)878 static int _trigger_user_max_dl(wzd_user_t * user)
879 {
880 ListElmt * el;
881 wzd_context_t * context;
882
883 if (!user) return 0;
884 for (el = list_head(context_list); el != NULL; el = list_next(el))
885 {
886 context = list_data(el);
887 if (context->magic == CONTEXT_MAGIC &&
888 context->userid == user->uid)
889 {
890 context->current_dl_limiter.maxspeed = user->max_dl_speed;
891 }
892 }
893
894 return 0;
895 }
896
_trigger_user_max_ul(wzd_user_t * user)897 static int _trigger_user_max_ul(wzd_user_t * user)
898 {
899 ListElmt * el;
900 wzd_context_t * context;
901
902 if (!user) return 0;
903 for (el = list_head(context_list); el != NULL; el = list_next(el))
904 {
905 context = list_data(el);
906 if (context->magic == CONTEXT_MAGIC &&
907 context->userid == user->uid)
908 {
909 context->current_ul_limiter.maxspeed = user->max_ul_speed;
910 }
911 }
912
913 return 0;
914 }
915
916