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_ip.h"
55 #include "wzd_libmain.h"
56 #include "wzd_log.h"
57 #include "wzd_misc.h"
58 #include "wzd_user.h"
59
60 #include "wzd_debug.h"
61
62 #endif /* WZD_USE_PCH */
63
64 static uid_t _max_uid = 0;
65 static wzd_user_t ** _user_array = NULL;
66
67
68 /** \brief Allocate a new empty structure for a user
69 */
user_allocate(void)70 wzd_user_t * user_allocate(void)
71 {
72 wzd_user_t * user;
73
74 user = wzd_malloc(sizeof(wzd_user_t));
75
76 WZD_ASSERT_RETURN(user != NULL, NULL);
77 if (user == NULL) {
78 out_log(LEVEL_CRITICAL,"FATAL user_allocate out of memory\n");
79 return NULL;
80 }
81
82 user_init_struct(user);
83
84 return user;
85 }
86
87 /** \brief Initialize members of struct \a user
88 */
user_init_struct(wzd_user_t * user)89 void user_init_struct(wzd_user_t * user)
90 {
91 WZD_ASSERT_VOID(user != NULL);
92 if (user == NULL) return;
93
94 memset(user,0,sizeof(wzd_user_t));
95
96 user->uid = (uid_t)-1;
97 }
98
99 /** \brief Free memory used by a \a user structure
100 */
user_free(wzd_user_t * user)101 void user_free(wzd_user_t * user)
102 {
103 if (user == NULL) return;
104
105 ip_list_free(user->ip_list);
106 wzd_free(user);
107 }
108
109 /** \brief Create a new user, giving default parameters
110 * \return The new user, or NULL. If \a err is provided, set it to
111 * the error code.
112 */
user_create(const char * username,const char * pass,const char * groupname,wzd_context_t * context,wzd_config_t * config,int * err)113 wzd_user_t * user_create(const char * username, const char * pass, const char * groupname, wzd_context_t * context, wzd_config_t * config, int * err)
114 {
115 wzd_user_t * newuser;
116 wzd_group_t * group = NULL;
117 const char * homedir;
118 unsigned int ratio;
119
120 WZD_ASSERT_RETURN( username != NULL, NULL );
121 if (username == NULL) {
122 if (err) *err = E_PARAM_NULL;
123 return NULL;
124 }
125
126 if (strlen(username) == 0 || strlen(username) >= HARD_USERNAME_LENGTH) {
127 if (err) *err = E_PARAM_BIG;
128 return NULL;
129 }
130
131 if (GetUserByName(username) != NULL) {
132 if (err) *err = E_PARAM_EXIST;
133 return NULL;
134 }
135
136 if (groupname == NULL) {
137 if (err) *err = E_PARAM_NULL;
138 return NULL;
139 }
140
141 group = GetGroupByName(groupname);
142
143 if (group == NULL) {
144 if (err) *err = E_PARAM_INVALID;
145 return NULL;
146 }
147
148 /* create new user */
149 newuser = user_allocate();
150
151 homedir = group->defaultpath;
152 ratio = group->ratio;
153 newuser->userperms = group->groupperms;
154
155 /* check if homedir exist */
156 {
157 fs_filestat_t s;
158 if (fs_file_stat(homedir,&s) || !S_ISDIR(s.mode)) {
159 out_log(LEVEL_HIGH,"WARNING homedir %s does not exist (while creating user %s)\n",homedir,username);
160 }
161 }
162
163 strncpy(newuser->username, username, HARD_USERNAME_LENGTH-1);
164 strncpy(newuser->userpass, pass, MAX_PASS_LENGTH-1);
165 strncpy(newuser->rootpath, homedir, WZD_MAX_PATH-1);
166 newuser->group_num=0;
167 if (group != NULL) {
168 newuser->groups[0] = group->gid;
169 if (newuser->groups[0] != INVALID_USER) newuser->group_num = 1;
170 }
171
172 return newuser;
173 }
174
175 /** \brief Register a user to the main server
176 * \return The uid of the registered user, or -1 on error
177 */
user_register(wzd_user_t * user,u16_t backend_id)178 uid_t user_register(wzd_user_t * user, u16_t backend_id)
179 {
180 uid_t uid;
181
182 WZD_ASSERT(user != NULL);
183 if (user == NULL) return (uid_t)-1;
184
185 WZD_ASSERT(user->uid != (uid_t)-1);
186 if (user->uid == (uid_t)-1) return (uid_t)-1;
187
188 /* safety check */
189 if (user->uid >= INT_MAX) {
190 out_log(LEVEL_HIGH, "ERROR user_register(uid=%d): uid too big\n",user->uid);
191 return (uid_t)-1;
192 }
193
194 WZD_MUTEX_LOCK(SET_MUTEX_USER);
195
196 /** \todo we should check unicity of username */
197
198 uid = user->uid;
199
200 if (uid >= _max_uid) {
201 size_t size; /* size of extent */
202
203 if (uid >= _max_uid + 255)
204 size = uid - _max_uid;
205 else
206 size = 256;
207 _user_array = wzd_realloc(_user_array, (_max_uid + size + 1)*sizeof(wzd_user_t*));
208 memset(_user_array + _max_uid, 0, (size+1) * sizeof(wzd_user_t*));
209 _max_uid = _max_uid + size;
210 }
211
212 if (_user_array[uid] != NULL) {
213 out_log(LEVEL_NORMAL, "INFO user_register(uid=%d): another user is already present (%s)\n",uid,_user_array[uid]->username);
214 WZD_MUTEX_UNLOCK(SET_MUTEX_USER);
215 return -1;
216 }
217
218 _user_array[uid] = user;
219 user->backend_id = backend_id;
220
221 out_log(LEVEL_FLOOD,"DEBUG registered uid %d with backend %d\n",uid,backend_id);
222
223 WZD_MUTEX_UNLOCK(SET_MUTEX_USER);
224 return uid;
225 }
226
227 /** \brief Update a registered user atomically. Datas are copied,
228 * and old user is freed.
229 * A pointer to the old user is still valid (change is done in-place)
230 * If the uid had changed, the user will be moved
231 * \return 0 if ok
232 */
user_update(uid_t uid,wzd_user_t * new_user)233 int user_update(uid_t uid, wzd_user_t * new_user)
234 {
235 wzd_user_t * buffer;
236
237 if (uid == (uid_t)-1) return -1;
238 if (uid > _max_uid) return -1;
239 if (_user_array[uid] == NULL) return -2;
240
241 if (uid != new_user->uid) {
242 if (_user_array[new_user->uid] != NULL) return -3;
243 }
244
245 /* same user ? do nothing */
246 if (uid == new_user->uid && _user_array[uid] == new_user) return 0;
247
248 WZD_MUTEX_LOCK(SET_MUTEX_USER);
249 /* backup old user */
250 buffer = wzd_malloc(sizeof(wzd_user_t));
251 *buffer = *_user_array[uid];
252 /* update user */
253 *_user_array[uid] = *new_user;
254 user_free(buffer);
255 if (uid != new_user->uid) {
256 _user_array[new_user->uid] = _user_array[uid];
257 _user_array[uid] = NULL;
258 }
259 WZD_MUTEX_UNLOCK(SET_MUTEX_USER);
260
261 return 0;
262 }
263
264 /** \brief Unregister a user to the main server
265 * The \a user struct must be freed using user_free()
266 * \warning Unregistering a user at runtime can break the server if the user is being used
267 * \return The unregistered user structure, or NULL on error
268 */
user_unregister(uid_t uid)269 wzd_user_t * user_unregister(uid_t uid)
270 {
271 wzd_user_t * user = NULL;
272
273 WZD_ASSERT_RETURN(uid != (uid_t)-1, NULL);
274 if (uid == (uid_t)-1) return NULL;
275
276 if (uid > _max_uid) return NULL;
277
278 WZD_MUTEX_LOCK(SET_MUTEX_USER);
279
280 if (_user_array[uid] != NULL) {
281 user = _user_array[uid];
282 _user_array[uid] = NULL;
283 }
284
285 WZD_MUTEX_UNLOCK(SET_MUTEX_USER);
286 out_log(LEVEL_FLOOD,"DEBUG unregistered uid %d\n",uid);
287
288 return user;
289 }
290
291 /** \brief Free memory used to register users
292 * \warning Also free ALL registered users !
293 */
user_free_registry(void)294 void user_free_registry(void)
295 {
296 uid_t uid;
297 WZD_MUTEX_LOCK(SET_MUTEX_USER);
298 if (_user_array != NULL) {
299 for (uid=0; uid<=_max_uid; uid++) {
300 user_free(_user_array[uid]);
301 }
302 }
303 wzd_free(_user_array);
304 _user_array = NULL;
305 _max_uid = 0;
306 WZD_MUTEX_UNLOCK(SET_MUTEX_USER);
307 }
308
309 /** \brief Get registered user using the \a uid
310 * \return The user, or NULL
311 */
user_get_by_id(uid_t uid)312 wzd_user_t * user_get_by_id(uid_t uid)
313 {
314 if (uid == (uid_t)-1) return NULL;
315 if (uid > _max_uid) return NULL;
316 if (_max_uid == 0) return NULL;
317
318 return _user_array[uid];
319 }
320
321 /** \brief Get registered user using the \a name
322 * \return The user, or NULL
323 * \todo Re-implement the function using a hash table
324 */
user_get_by_name(const char * username)325 wzd_user_t * user_get_by_name(const char * username)
326 {
327 uid_t uid;
328
329 if (username == NULL || strlen(username)<1 || _max_uid==0) return NULL;
330
331 /* We don't need to lock the access since the _user_array can only grow */
332 for (uid=0; uid<=_max_uid; uid++) {
333 if (_user_array[uid] != NULL
334 && _user_array[uid]->username != NULL
335 && strcmp(username,_user_array[uid]->username)==0)
336 return _user_array[uid];
337 }
338 return NULL;
339 }
340
341 /** \brief Get list or users register for a specific backend
342 * The returned list is terminated by -1, and must be freed with wzd_free()
343 */
user_get_list(u16_t backend_id)344 uid_t * user_get_list(u16_t backend_id)
345 {
346 uid_t * uid_list = NULL;
347 uid_t size;
348 int index;
349 uid_t uid;
350
351 /* WZD_MUTEX_LOCK(SET_MUTEX_USER);*/
352
353 /** \todo it would be better to get the real number of used uid */
354 size = _max_uid;
355
356 uid_list = (uid_t*)wzd_malloc((size+1)*sizeof(uid_t));
357 index = 0;
358 /* We don't need to lock the access since the _user_array can only grow */
359 for (uid=0; uid<size; uid++) {
360 if (_user_array[uid] != NULL
361 && _user_array[uid]->uid != INVALID_USER)
362 uid_list[index++] = _user_array[uid]->uid;
363 }
364 uid_list[index] = (uid_t)-1;
365 uid_list[size] = (uid_t)-1;
366
367 /* WZD_MUTEX_UNLOCK(SET_MUTEX_USER);*/
368
369 return uid_list;
370 }
371
372 /** \brief Find the first free uid, starting from \a start
373 */
user_find_free_uid(uid_t start)374 uid_t user_find_free_uid(uid_t start)
375 {
376 uid_t uid;
377
378 if (start == (uid_t)-1) start = 0;
379
380 /** \todo locking may be harmful if this function is called from another
381 * user_x() function
382 */
383 /* WZD_MUTEX_LOCK(SET_MUTEX_USER);*/
384 for (uid = start; uid < _max_uid && uid != (uid_t)-1; uid++) {
385 if (_user_array[uid] == NULL) break;
386 }
387 /* WZD_MUTEX_UNLOCK(SET_MUTEX_USER);*/
388
389 return uid;
390 }
391
392 /** \brief Add an ip to the list of authorized/forbidden ips
393 * \return 0 if ok
394 */
user_ip_add(wzd_user_t * user,const char * ip,int is_authorized)395 int user_ip_add(wzd_user_t * user, const char * ip, int is_authorized)
396 {
397 WZD_ASSERT( user != NULL );
398 if (user == NULL) return -1;
399
400 /** \note The number of stored ips per user is no more limited */
401
402 return ip_add_check(&user->ip_list, ip, is_authorized);
403 }
404
405 /** \brief List all users in a particular group, optionally filtered by a flag
406 *
407 * Optional: a flag can be specified where only users with this flag set will be returned (use 0 to ignore)
408 * \return
409 * - a user list terminated by -1, must be freed with wzd_free()
410 * - NULL if no group with that gid was found
411 */
group_list_users(gid_t gid,char flag)412 uid_t * group_list_users(gid_t gid, char flag /* optional */)
413 {
414 uid_t * uid_list = NULL;
415 uid_t size;
416 int index;
417 uid_t uid;
418 int groups;
419
420 /* Check that the supplied gid is valid */
421 if (group_get_by_id(gid) == NULL)
422 return NULL;
423
424 /* WZD_MUTEX_LOCK(SET_MUTEX_USER);*/
425
426 /** \todo it would be better to get the real number of used uid */
427 size = _max_uid;
428
429 uid_list = (uid_t*)wzd_malloc((size+1)*sizeof(uid_t));
430 index = 0;
431 /* We don't need to lock the access since the _user_array can only grow */
432 for (uid=0; uid<size; uid++) {
433 if (_user_array[uid] != NULL && _user_array[uid]->uid != INVALID_USER) {
434 for (groups=0; groups<MAX_GROUPS_PER_USER; groups++) {
435 if (_user_array[uid]->groups[groups] == gid) {
436 /* Check if the user has a certain flag */
437 if (flag == 0 || strchr(_user_array[uid]->flags,flag)!=NULL) {
438 uid_list[index++] = _user_array[uid]->uid;
439 /* Found a match, stop cycling through groups list! */
440 groups = MAX_GROUPS_PER_USER;
441 }
442 }
443 }
444 }
445 }
446 uid_list[index] = (uid_t)-1;
447 uid_list[size] = (uid_t)-1;
448
449 /* WZD_MUTEX_UNLOCK(SET_MUTEX_USER);*/
450
451 return uid_list;
452 }
453
454