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