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 <errno.h>
35 #include <sys/stat.h>
36 
37 #include <sys/types.h>
38 
39 #ifdef WIN32
40 #include <winsock2.h>
41 #include <direct.h> /* _getcwd */
42 #else
43 #include <unistd.h>
44 
45 #include <sys/socket.h>
46 #include <netinet/in.h>
47 #include <arpa/inet.h>
48 #endif
49 
50 #include "wzd_structs.h"
51 
52 #include "wzd_fs.h"
53 #include "wzd_group.h"
54 #include "wzd_libmain.h"
55 #include "wzd_log.h"
56 #include "wzd_misc.h"
57 #include "wzd_user.h"
58 
59 #include "wzd_debug.h"
60 
61 #endif /* WZD_USE_PCH */
62 
63 static gid_t _max_gid = 0;
64 static wzd_group_t ** _group_array = NULL;
65 
66 /** \brief Allocate a new empty structure for a group
67  */
group_allocate(void)68 wzd_group_t * group_allocate(void)
69 {
70   wzd_group_t * group;
71 
72   group = wzd_malloc(sizeof(wzd_group_t));
73 
74   WZD_ASSERT_RETURN(group != NULL, NULL);
75   if (group == NULL) {
76     out_log(LEVEL_CRITICAL,"FATAL group_allocate out of memory\n");
77     return NULL;
78   }
79 
80   group_init_struct(group);
81 
82   return group;
83 }
84 
85 /** \brief Initialize members of struct \a group
86  */
group_init_struct(wzd_group_t * group)87 void group_init_struct(wzd_group_t * group)
88 {
89   WZD_ASSERT_VOID(group != NULL);
90   if (group == NULL) return;
91 
92   memset(group,0,sizeof(wzd_group_t));
93 
94   group->gid = (gid_t)-1;
95   group->groupperms = 0xffffffff;
96 }
97 
98 /** \brief Free memory used by a \a group structure
99  */
group_free(wzd_group_t * group)100 void group_free(wzd_group_t * group)
101 {
102   if (group == NULL) return;
103 
104   ip_list_free(group->ip_list);
105   wzd_free(group);
106 }
107 
108 /** \brief Create a new group, giving default parameters
109  * \return The new group, or NULL. If \a err is provided, set it to
110  * the error code.
111  */
group_create(const char * groupname,wzd_context_t * context,wzd_config_t * config,int * err)112 wzd_group_t * group_create(const char * groupname, wzd_context_t * context, wzd_config_t * config, int * err)
113 {
114   wzd_group_t * newgroup;
115   const char * homedir;
116 
117   WZD_ASSERT_RETURN( groupname != NULL, NULL );
118   if (groupname == NULL) {
119     if (err) *err = E_PARAM_NULL;
120     return NULL;
121   }
122 
123   if (strlen(groupname) == 0 || strlen(groupname) >= HARD_GROUPNAME_LENGTH) {
124     if (err) *err = E_PARAM_BIG;
125     return NULL;
126   }
127 
128   if (GetGroupByName(groupname) != NULL) {
129     if (err) *err = E_PARAM_EXIST;
130     return NULL;
131   }
132 
133   /* homedir */
134   if (context != NULL) {
135     wzd_user_t * me;
136 
137     me = GetUserByID(context->userid);
138     if (me != NULL && me->group_num > 0) {
139       wzd_group_t * mygroup = GetGroupByID(me->groups[0]);
140       homedir = mygroup->defaultpath;
141     } else {
142       homedir = me->rootpath;
143     }
144 
145     /* check if homedir exist */
146     {
147       fs_filestat_t s;
148       if (fs_file_stat(homedir,&s) || !S_ISDIR(s.mode)) {
149         out_log(LEVEL_HIGH,"WARNING homedir %s does not exist (while creating group %s)\n",homedir,groupname);
150       }
151     }
152   } else {
153     out_log(LEVEL_HIGH,"WARNING could not get a default homedir for new group %s\n",groupname);
154     /** \todo use a config parameter or a default group to get the
155      * default path ?
156      */
157     homedir = "";
158   }
159 
160   if (strlen(homedir) >= WZD_MAX_PATH) {
161     out_log(LEVEL_HIGH,"ERROR homedir is too long (>= %d chars) while creating group %s\n",WZD_MAX_PATH,groupname);
162     if (err) *err = E_PARAM_BIG;
163     return NULL;
164   }
165 
166   /* finally, create the new group */
167   newgroup = group_allocate();
168   strncpy(newgroup->groupname,groupname,HARD_GROUPNAME_LENGTH);
169   strncpy(newgroup->defaultpath,homedir,WZD_MAX_PATH);
170 
171   return newgroup;
172 }
173 
174 /** \brief Register a group to the main server
175  * \return The gid of the registered group, or -1 on error
176  */
group_register(wzd_group_t * group,u16_t backend_id)177 gid_t group_register(wzd_group_t * group, u16_t backend_id)
178 {
179   gid_t gid;
180 
181   WZD_ASSERT(group != NULL);
182   if (group == NULL) return (gid_t)-1;
183 
184   WZD_ASSERT(group->gid != (gid_t)-1);
185   if (group->gid == (gid_t)-1) return (gid_t)-1;
186 
187   /* safety check */
188   if (group->gid >= INT_MAX) {
189     out_log(LEVEL_HIGH, "ERROR group_register(gid=%d): gid too big\n",group->gid);
190     return (gid_t)-1;
191   }
192 
193   WZD_MUTEX_LOCK(SET_MUTEX_USER);
194 
195   gid = group->gid;
196 
197   if (gid >= _max_gid) {
198     size_t size; /* size of extent */
199 
200     if (gid >= _max_gid + 255)
201       size = gid - _max_gid;
202     else
203       size = 256;
204     _group_array = wzd_realloc(_group_array, (_max_gid + size + 1)*sizeof(wzd_group_t*));
205     memset(_group_array + _max_gid, 0, (size+1) * sizeof(wzd_group_t*));
206     _max_gid = _max_gid + size;
207   }
208 
209   if (_group_array[gid] != NULL) {
210     out_log(LEVEL_NORMAL, "INFO group_register(gid=%d): another group is already present (%s)\n",gid,_group_array[gid]->groupname);
211     WZD_MUTEX_UNLOCK(SET_MUTEX_USER);
212     return -1;
213   }
214 
215   _group_array[gid] = group;
216   group->backend_id = backend_id;
217 
218   out_log(LEVEL_FLOOD,"DEBUG registered gid %d with backend %d\n",gid,backend_id);
219 
220   WZD_MUTEX_UNLOCK(SET_MUTEX_USER);
221   return gid;
222 }
223 
224 /** \brief Update a registered group atomically. Datas are copied,
225  * and old group is freed.
226  * A pointer to the old group is still valid (change is done in-place)
227  * If the gid had changed, the group will be moved
228  * \return 0 if ok
229  */
group_update(gid_t gid,wzd_group_t * new_group)230 int group_update(gid_t gid, wzd_group_t * new_group)
231 {
232   wzd_group_t * buffer;
233 
234   if (gid == (gid_t)-1) return -1;
235   if (gid > _max_gid) return -1;
236   if (_group_array[gid] == NULL) return -2;
237 
238   if (gid != new_group->gid) {
239     if (_group_array[new_group->gid] != NULL) return -3;
240   }
241 
242   /* same group ? do nothing */
243   if (gid == new_group->gid && _group_array[gid] == new_group) return 0;
244 
245   WZD_MUTEX_LOCK(SET_MUTEX_USER);
246   /* backup old group */
247   buffer = wzd_malloc(sizeof(wzd_group_t));
248   *buffer = *_group_array[gid];
249   /* update group */
250   *_group_array[gid] = *new_group;
251   group_free(buffer);
252   if (gid != new_group->gid) {
253     _group_array[new_group->gid] = _group_array[gid];
254     _group_array[gid] = NULL;
255   }
256   WZD_MUTEX_UNLOCK(SET_MUTEX_USER);
257 
258   return 0;
259 }
260 
261 /** \brief Unregister a group to the main server
262  * The \a group struct must be freed using group_free()
263  * \return The unregistered group structure, or NULL on error
264  */
group_unregister(gid_t gid)265 wzd_group_t * group_unregister(gid_t gid)
266 {
267   wzd_group_t * group = NULL;
268 
269   WZD_ASSERT_RETURN(gid != (gid_t)-1, NULL);
270   if (gid == (gid_t)-1) return NULL;
271 
272   if (gid > _max_gid) return NULL;
273 
274   WZD_MUTEX_LOCK(SET_MUTEX_USER);
275 
276   if (_group_array[gid] != NULL) {
277     group = _group_array[gid];
278     _group_array[gid] = NULL;
279   }
280 
281   WZD_MUTEX_UNLOCK(SET_MUTEX_USER);
282   out_log(LEVEL_FLOOD,"DEBUG unregistered gid %d\n",gid);
283 
284   return group;
285 }
286 
287 /** \brief Free memory used to register groups
288  * \warning Also free ALL registered groups !
289  */
group_free_registry(void)290 void group_free_registry(void)
291 {
292   gid_t gid;
293   WZD_MUTEX_LOCK(SET_MUTEX_USER);
294   if (_group_array != NULL) {
295     for (gid=0; gid<=_max_gid; gid++) {
296       group_free(_group_array[gid]);
297     }
298   }
299   wzd_free(_group_array);
300   _group_array = NULL;
301   _max_gid = 0;
302   WZD_MUTEX_UNLOCK(SET_MUTEX_USER);
303 }
304 
305 /** \brief Get registered group using the \a gid
306  * \return The group, or NULL
307  */
group_get_by_id(gid_t gid)308 wzd_group_t * group_get_by_id(gid_t gid)
309 {
310   if (gid == (gid_t)-1) return NULL;
311   if (gid > _max_gid) return NULL;
312   if (_max_gid == 0) return NULL;
313 
314   return _group_array[gid];
315 }
316 
317 /** \brief Get registered group using the \a name
318  * \return The group, or NULL
319  * \todo Re-implement the function using a hash table
320  */
group_get_by_name(const char * groupname)321 wzd_group_t * group_get_by_name(const char * groupname)
322 {
323   gid_t gid;
324 
325   if (groupname == NULL || strlen(groupname)<1 || _max_gid==0) return NULL;
326 
327   /* We don't need to lock the access since the _group_array can only grow */
328   for (gid=0; gid<=_max_gid; gid++) {
329     if (_group_array[gid] != NULL
330         && _group_array[gid]->groupname != NULL
331         && strcmp(groupname,_group_array[gid]->groupname)==0)
332       return _group_array[gid];
333   }
334   return NULL;
335 }
336 
337 /** \brief Get list or groups register for a specific backend
338  * The returned list is terminated by -1, and must be freed with wzd_free()
339  */
group_get_list(u16_t backend_id)340 gid_t * group_get_list(u16_t backend_id)
341 {
342   gid_t * gid_list = NULL;
343   gid_t size;
344   int index;
345   gid_t gid;
346 
347   /** \todo XXX we should use locks (and be careful to avoid deadlocks) */
348 
349   /** \todo it would be better to get the real number of used gid */
350   size = _max_gid;
351 
352   gid_list = (gid_t*)wzd_malloc((size+1)*sizeof(gid_t));
353   index = 0;
354   /* We don't need to lock the access since the _group_array can only grow */
355   for (gid=0; gid<size; gid++) {
356     if (_group_array[gid] != NULL
357         && _group_array[gid]->gid != INVALID_USER)
358       gid_list[index++] = _group_array[gid]->gid;
359   }
360   gid_list[index] = (gid_t)-1;
361   gid_list[size] = (gid_t)-1;
362 
363   return gid_list;
364 }
365 
366 /** \brief Find the first free gid, starting from \a start
367  */
group_find_free_gid(gid_t start)368 gid_t group_find_free_gid(gid_t start)
369 {
370   gid_t gid;
371 
372   if (start == (gid_t)-1) start = 0;
373 
374   /** \todo locking may be harmful if this function is called from another
375    * group_x() function
376    */
377 /*  WZD_MUTEX_LOCK(SET_MUTEX_USER);*/
378   for (gid = start; gid < _max_gid && gid != (gid_t)-1; gid++) {
379     if (_group_array[gid] == NULL) break;
380   }
381 /*  WZD_MUTEX_UNLOCK(SET_MUTEX_USER);*/
382 
383   return gid;
384 }
385 
386 /** \brief Add an ip to the list of authorized/forbidden ips
387  * \return 0 if ok
388  */
group_ip_add(wzd_group_t * group,const char * ip,int is_authorized)389 int group_ip_add(wzd_group_t * group, const char * ip, int is_authorized)
390 {
391   WZD_ASSERT( group != NULL );
392   if (group == NULL) return -1;
393 
394   /** \note The number of stored ips per group is no more limited */
395 
396   return ip_add_check(&group->ip_list, ip, is_authorized);
397 }
398 
399