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 <stdlib.h>
28 #include <stdio.h>
29 #include <string.h>
30 #include <sys/types.h>
31 #include <signal.h>
32
33 #ifndef WIN32
34 #include <unistd.h>
35 #include <sys/param.h>
36 #include <sys/time.h>
37 #include <regex.h>
38 #else
39 #include "../../visual/gnu_regex/regex.h"
40 #endif
41
42 #include <libwzd-auth/wzd_auth.h>
43
44 #include <libwzd-core/wzd_backend.h>
45 #include <libwzd-core/wzd_group.h>
46 #include <libwzd-core/wzd_log.h>
47 #include <libwzd-core/wzd_misc.h>
48 #include <libwzd-core/wzd_user.h>
49 #include <libwzd-core/wzd_debug.h>
50
51 #include "libplaintext_main.h"
52 #include "libplaintext_file.h"
53
54
55 #define MAX_LINE 1024
56
57 static const char *tab_directives[] = {
58 "privgroup"
59 };
60
61 static regex_t reg_line;
62 static regmatch_t regmatch[3];
63
64 static char varname[2048];
65 static char value[2048];
66
67
68
find_directive(const char * name)69 static unsigned int find_directive(const char *name)
70 {
71 int i=0;
72
73 while (i<D_NUM) {
74 if (strncasecmp(tab_directives[i],name,strlen(tab_directives[i]))==0) return i+1;
75 i++;
76 }
77 return D_NONE;
78 }
79
80 /* IP allowing */
__user_ip_add(wzd_user_t * user,const char * newip)81 static int __user_ip_add(wzd_user_t * user, const char *newip)
82 {
83 /* of course this should never happen :) */
84 if (user == NULL || newip==NULL) return -1;
85
86 if (strlen(newip) < 1) return -1;
87 if (strlen(newip) >= MAX_IP_LENGTH) return -1; /* upper limit for an hostname */
88
89 if (ip_add_check(&user->ip_list, newip, 1 /* is_allowed */))
90 return 1;
91
92 return 0;
93 }
94
__group_ip_add(wzd_group_t * group,const char * newip)95 static int __group_ip_add(wzd_group_t * group, const char *newip)
96 {
97 /* of course this should never happen :) */
98 if (group == NULL || newip==NULL) return -1;
99
100 if (strlen(newip) < 1) return -1;
101 if (strlen(newip) >= MAX_IP_LENGTH) return -1; /* upper limit for an hostname */
102
103 if (ip_add_check(&group->ip_list, newip, 1 /* is_allowed */))
104 return 1;
105
106 return 0;
107 }
108
write_single_user(FILE * file,const wzd_user_t * user)109 int write_single_user(FILE * file, const wzd_user_t * user)
110 {
111 unsigned int j;
112 wzd_group_t * loop_group;
113 char buffer[4096], errbuf[1024];
114 struct wzd_ip_list_t * current_ip;
115
116 fprintf(file,"name=%s\n",user->username);
117 fprintf(file,"pass=%s\n",user->userpass);
118 fprintf(file,"home=%s\n",user->rootpath);
119 fprintf(file,"uid=%u\n",user->uid);
120 /* write ALL groups */
121
122 if (user->group_num>0) {
123 loop_group = group_get_by_id(user->groups[0]);
124 if (!loop_group) {
125 /* FIXME warn user */
126 snprintf(errbuf,sizeof(errbuf),"Invalid MAIN group %u for user %s\n",user->groups[0],user->username);
127 ERRLOG(errbuf);
128 } else {
129 strcpy(buffer,loop_group->groupname);
130 for (j=1; j<user->group_num; j++) {
131 strcat(buffer,",");
132 loop_group = group_get_by_id(user->groups[j]);
133 if (!loop_group) {
134 /* FIXME warn user */
135 snprintf(errbuf,sizeof(errbuf),"Invalid MAIN group %u for user %s\n",user->groups[j],user->username);
136 ERRLOG(errbuf);
137 } else {
138 strcat(buffer,loop_group->groupname);
139 }
140 }
141 fprintf(file,"groups=%s\n",buffer);
142 }
143 }
144 fprintf(file,"rights=0x%lx\n",user->userperms);
145 if (strlen(user->tagline)>0)
146 fprintf(file,"tagline=%s\n",user->tagline);
147 for (current_ip = user->ip_list; current_ip != NULL; current_ip = current_ip->next_ip) {
148 fprintf(file,"ip_allowed=%s\n",current_ip->regexp);
149 }
150 if (user->max_ul_speed)
151 fprintf(file,"max_ul_speed=%u\n",user->max_ul_speed);
152 if (user->max_dl_speed)
153 fprintf(file,"max_dl_speed=%u\n",user->max_dl_speed);
154
155 fprintf(file,"credits=%" PRIu64 "\n",user->credits);
156 fprintf(file,"bytes_ul_total=%" PRIu64 "\n",user->stats.bytes_ul_total);
157 fprintf(file,"bytes_dl_total=%" PRIu64 "\n",user->stats.bytes_dl_total);
158
159 if (user->stats.files_ul_total)
160 fprintf(file,"files_ul_total=%lu\n",user->stats.files_ul_total);
161 if (user->stats.files_dl_total)
162 fprintf(file,"files_dl_total=%lu\n",user->stats.files_dl_total);
163 if (user->ratio)
164 fprintf(file,"ratio=%u\n",user->ratio);
165 if (user->num_logins)
166 fprintf(file,"num_logins=%u\n",user->num_logins);
167 if (user->max_idle_time)
168 fprintf(file,"max_idle_time=%u\n",user->max_idle_time);
169 if (user->flags && strlen(user->flags)>0)
170 fprintf(file,"flags=%s\n",user->flags);
171 if (user->user_slots)
172 fprintf(file,"user_slots=%hd\n",(unsigned short)user->user_slots);
173 if (user->leech_slots)
174 fprintf(file,"leech_slots=%hd\n",(unsigned short)user->leech_slots);
175 if (user->last_login)
176 fprintf(file,"last_login=%ld\n",(unsigned long)user->last_login);
177 fprintf(file,"\n");
178
179 return 0;
180 }
181
write_single_group(FILE * file,const wzd_group_t * group)182 int write_single_group(FILE * file, const wzd_group_t * group)
183 {
184 struct wzd_ip_list_t * current_ip;
185
186 fprintf(file,"privgroup\t%s\n",group->groupname);
187 if (group->max_idle_time)
188 fprintf(file,"max_idle_time=%u\n",group->max_idle_time);
189 if (group->num_logins)
190 fprintf(file,"num_logins=%u\n",group->num_logins);
191 if (group->max_ul_speed)
192 fprintf(file,"max_ul_speed=%u\n",group->max_ul_speed);
193 if (group->max_dl_speed)
194 fprintf(file,"max_dl_speed=%u\n",group->max_dl_speed);
195 fprintf(file,"rights=0x%lx\n",group->groupperms);
196 if (strlen(group->tagline)>0)
197 fprintf(file,"tagline=%s\n",group->tagline);
198 fprintf(file,"gid=%u\n",group->gid);
199 for (current_ip = group->ip_list; current_ip != NULL; current_ip = current_ip->next_ip) {
200 fprintf(file,"ip_allowed=%s\n",current_ip->regexp);
201 }
202 if (strlen(group->defaultpath)>0)
203 fprintf(file,"default_home=%s\n",group->defaultpath);
204 if (group->ratio)
205 fprintf(file,"ratio=%u\n",group->ratio);
206 fprintf(file,"\n");
207
208 return 0;
209 }
210
211
write_user_file(void)212 int write_user_file(void)
213 {
214 #ifndef WIN32
215 sigset_t mask;
216 #endif
217 char filename[256];
218 char filenamenew[256];
219 char filenameold[256];
220 FILE *file, *fileold;
221 unsigned int i,j;
222 char buffer[4096];
223 char errbuf[1024];
224 const char * const file_header[] = {
225 "# general considerations:",
226 "#",
227 "# comment lines begin by #",
228 "# empty lines are removed",
229 "#",
230 "# directives have format: <tagname>=<value>",
231 "# with the regexp: ^([a-zA-Z0-9_]+)[ \\t]*=[ \\t]*(.+)",
232 "#",
233 "# directives are grouped into sections",
234 "# section begins by [SECTIONNAME]",
235 NULL /* you MUST keep this array NULL-ended ! */
236 };
237 wzd_user_t * loop_user;
238 wzd_group_t * loop_group;
239 uid_t * user_list;
240 gid_t * group_list;
241
242 #if 0
243 /* this loop has no real interest ...
244 * it is only used to access each struct once, to provoque SEGFAULT
245 * before we start to erase file in case there is a memory corruption.
246 * But of course, this should never happens - uh ?
247 */
248 for (elmnt=list_head(&user_list); elmnt; elmnt=list_next(elmnt))
249 {
250 loop_user = list_data(elmnt);
251 if (!loop_user) {
252 ERRLOG("plaintext: EMPTY node in user list !!!\n");
253 }
254 j = loop_user->username[0];
255 }
256 #endif
257
258 strcpy (filename,USERS_FILE);
259 strcpy (filenamenew,USERS_FILE);
260 strcat (filenamenew,".NEW");
261 strcpy (filenameold,USERS_FILE);
262 strcat (filenameold,".OLD");
263
264 /* file = fopen(filenamenew,"w");*/
265
266 /* FIXME i need to get a mutex here ? */
267 file = fopen(filename,"r");
268 if (!file) {
269 snprintf(errbuf,sizeof(errbuf),"Could not open file %s !\n",filename);
270 ERRLOG(errbuf);
271 return -1;
272 }
273 fileold = fopen(filenameold,"w+");
274 if (!fileold) {
275 snprintf(errbuf,sizeof(errbuf),"Could not open file %s !\n",filenameold);
276 ERRLOG(errbuf);
277 return -1;
278 }
279
280 /* first copy file to .old */
281 {
282 while ( (i=fread(buffer,1,4096,file)) > 0 )
283 {
284 j = fwrite(buffer,1,i,fileold);
285 if (!j) {
286 snprintf(errbuf,sizeof(errbuf),"ERROR writing to %s\n",filenameold);
287 ERRLOG(errbuf);
288 return -1;
289 }
290 }
291 }
292 fclose(fileold);
293
294 /* from this point we block signals, to avoid being interrupted when
295 * file is not fully written.
296 */
297 #ifndef WIN32
298 sigemptyset(&mask);
299 sigaddset(&mask,SIGINT);
300 if (sigprocmask(SIG_BLOCK,&mask,NULL)<0) {
301 ERRLOG("Unable to block SIGINT with sigprocmask\n");
302 }
303 #endif
304
305 file = freopen(filename,"w+",file);
306 if (!file) {
307 ERRLOG("unable to reopen users file (%s:%d)\n");
308 return -1;
309 }
310 fseek(file,SEEK_SET,0);
311
312 i=0;
313 while (file_header[i]) {
314 fprintf(file,"%s\n",file_header[i]);
315 i++;
316 }
317 fprintf(file,"\n");
318
319 fprintf(file,"# groups definitions\n");
320 fprintf(file,"[GROUPS]\n");
321 group_list = group_get_list(1 /* backend id */);
322 for (i=0; group_list[i]!=INVALID_GROUP; i++)
323 {
324 if (!(loop_group = group_get_by_id(group_list[i]))) {
325 ERRLOG("EMPTY NODE IN GROUP LIST !\n");
326 continue;
327 }
328 if (loop_group->groupname[0]=='\0') continue;
329 if (strcmp(loop_group->groupname,"nogroup")==0) continue;
330
331 if (write_single_group(file,loop_group)) {
332 /** \todo XXX print error message */
333 continue;
334 }
335 }
336 wzd_free(group_list);
337
338 fprintf(file,"# users definitions\n");
339 fprintf(file,"# users MUST begin by line name=<>\n");
340 fprintf(file,"[USERS]\n");
341 user_list = user_get_list(1 /* backend id */);
342 for (i=0; user_list[i]!=INVALID_USER; i++)
343 {
344 if (!(loop_user = user_get_by_id(user_list[i]))) {
345 ERRLOG("EMPTY NODE IN USER LIST !\n");
346 continue;
347 }
348 if (loop_user->username[0]=='\0') continue;
349 if (strcmp(loop_user->username,"nobody")==0) continue;
350
351 if (write_single_user(file,loop_user)) {
352 /** \todo XXX print error message */
353 continue;
354 }
355 }
356 wzd_free(user_list);
357
358 fclose(file);
359
360 /* unblock signals - if a SIGINT is pending, it should be harmless now */
361 #ifndef WIN32
362 if (sigprocmask(SIG_UNBLOCK,&mask,NULL)<0) {
363 ERRLOG("Unable to unblock SIGINT with sigprocmask\n");
364 }
365 #endif
366
367 /* FIXME need to release mutex */
368
369 #if 0
370 /* and now, the (as most as possible) atomic operation for the userfile */
371 {
372 if (rename(filename,filenameold)) return -1;
373 if (rename(filenamenew,filename)) return -1;
374 }
375 #endif
376
377 return 0;
378 }
379
380 /* Read a group
381 * Return a newly allocated group or NULL
382 */
read_single_group(FILE * file,const char * groupname,char * buffer,size_t length)383 wzd_group_t * read_single_group(FILE * file, const char *groupname, char * buffer, size_t length)
384 {
385 char errbuf[1024];
386 int err;
387 long num;
388 char * ptr;
389 wzd_group_t * group;
390
391 group = group_allocate();
392
393 strncpy(group->groupname,groupname,HARD_GROUPNAME_LENGTH-1);
394
395 group->gid = group_find_free_gid(0); /* default value for gid, for compat */
396
397 while ( fgets(buffer,MAX_LINE-1,file) != NULL ) {
398 chop(buffer);
399
400 if (strlen(buffer) == 0) return group;
401
402 err = regexec(®_line,buffer,3,regmatch,0);
403 if (err) {
404 snprintf(errbuf,sizeof(errbuf),"Line '%s' does not respect config line format - ignoring\n",buffer);
405 ERRLOG(errbuf);
406 continue;
407 }
408 memcpy(varname,buffer+regmatch[1].rm_so,regmatch[1].rm_eo-regmatch[1].rm_so);
409 varname[regmatch[1].rm_eo-regmatch[1].rm_so]='\0';
410 memcpy(value,buffer+regmatch[2].rm_so,regmatch[2].rm_eo-regmatch[2].rm_so);
411 value[regmatch[2].rm_eo-regmatch[2].rm_so]='\0';
412
413 if (strcmp("gid",varname)==0) {
414 num = strtol(value, &ptr, 0);
415 if (ptr == value || *ptr != '\0' || num < 0) { /* invalid number */
416 snprintf(errbuf,sizeof(errbuf),"Invalid gid %s\n",value);
417 ERRLOG(errbuf);
418 continue;
419 }
420 group->gid = num;
421 }
422 else if (strcasecmp(varname,"max_idle_time")==0) {
423 num = strtol(value, &ptr, 0);
424 if (ptr == value || *ptr != '\0' || num < 0) { /* invalid number */
425 snprintf(errbuf,sizeof(errbuf),"Invalid max_idle_time %s\n",value);
426 ERRLOG(errbuf);
427 continue;
428 }
429 group->max_idle_time = num;
430 } /* max_idle_time */
431 else if (strcmp("num_logins",varname)==0) {
432 num = strtol(value, &ptr, 0);
433 if (ptr == value || *ptr != '\0' || num < 0) { /* invalid number */
434 snprintf(errbuf,sizeof(errbuf),"Invalid num_logins %s\n",value);
435 ERRLOG(errbuf);
436 continue;
437 }
438 group->num_logins = (unsigned short)num;
439 } /* else if (strcmp("num_logins",... */
440
441 else if (strcmp("ip_allowed",varname)==0) {
442 err = __group_ip_add(group,value);
443 if (err != 0 ) {
444 snprintf(errbuf,sizeof(errbuf),"ERROR unable to add ip %s\n",value);
445 ERRLOG(errbuf);
446 continue;
447 }
448 } /* ip_allowed */
449 else if (strcmp("default_home",varname)==0) {
450 strncpy(group->defaultpath,value,WZD_MAX_PATH);
451 } /* default_home */
452 else if (strcmp("ratio",varname)==0) {
453 num = strtol(value, &ptr, 0);
454 if (ptr == value || *ptr != '\0' || num < 0) { /* invalid number */
455 snprintf(errbuf,sizeof(errbuf),"Invalid ratio %s\n",value);
456 ERRLOG(errbuf);
457 continue;
458 }
459 group->ratio = num;
460 } /* else if (strcmp("ratio",... */
461 else if (strcmp("rights",varname)==0) {
462 num = strtoul(value, &ptr, 0);
463 group->groupperms = num;
464 }
465 else if (strcmp("max_dl_speed",varname)==0) {
466 num = strtol(value, &ptr, 0);
467 if (ptr == value || *ptr != '\0' || num < 0) { /* invalid number */
468 snprintf(errbuf,sizeof(errbuf),"Invalid max_dl_speed %s\n",value);
469 ERRLOG(errbuf);
470 continue;
471 }
472 group->max_dl_speed = num;
473 } /* max_dl_speed */
474 else if (strcmp("max_ul_speed",varname)==0) {
475 num = strtol(value, &ptr, 0);
476 if (ptr == value || *ptr != '\0' || num < 0) { /* invalid number */
477 snprintf(errbuf,sizeof(errbuf),"Invalid max_ul_speed %s\n",value);
478 ERRLOG(errbuf);
479 continue;
480 }
481 group->max_ul_speed = num;
482 } /* max_ul_speed */
483 else if (strcmp("tagline",varname)==0) {
484 strncpy(group->tagline,value,MAX_TAGLINE_LENGTH);
485 } /* tagline */
486 else {
487 snprintf(errbuf,sizeof(errbuf),"ERROR Variable '%s' is not correct (value %s) - ignoring\n",varname,value);
488 ERRLOG(errbuf);
489 }
490 };
491
492 return group;
493 }
494
495 /* Read a user
496 * Return a newly allocated user or NULL
497 */
read_single_user(FILE * file,const char * username,char * buffer,size_t length)498 wzd_user_t * read_single_user(FILE * file, const char *username, char * buffer, size_t length)
499 {
500 char errbuf[1024];
501 int err;
502 char * ptr;
503 wzd_user_t * user;
504 long num;
505 unsigned long u_num;
506 u64_t ul_num;
507
508 user = user_allocate();
509
510 strncpy(user->username,username,HARD_USERNAME_LENGTH-1);
511
512 user->uid = user_find_free_uid(0); /* default value for uid, for compat */
513
514 while ( fgets(buffer,MAX_LINE-1,file) != NULL ) {
515 chop(buffer);
516
517 if (strlen(buffer) == 0) return user;
518
519 err = regexec(®_line,buffer,3,regmatch,0);
520 if (err) {
521 snprintf(errbuf,sizeof(errbuf),"Line '%s' does not respect config line format - ignoring\n",buffer);
522 ERRLOG(errbuf);
523 continue;
524 }
525 memcpy(varname,buffer+regmatch[1].rm_so,regmatch[1].rm_eo-regmatch[1].rm_so);
526 varname[regmatch[1].rm_eo-regmatch[1].rm_so]='\0';
527 memcpy(value,buffer+regmatch[2].rm_so,regmatch[2].rm_eo-regmatch[2].rm_so);
528 value[regmatch[2].rm_eo-regmatch[2].rm_so]='\0';
529
530 if (strcmp("uid",varname)==0) {
531 num = strtol(value, &ptr, 0);
532 if (ptr == value || *ptr != '\0' || num < 0) { /* invalid number */
533 snprintf(errbuf,sizeof(errbuf),"Invalid uid %s\n",value);
534 ERRLOG(errbuf);
535 continue;
536 }
537 user->uid = num;
538 }
539 else if (strcmp("home",varname)==0) {
540 /* remove trailing / */
541 if (value[strlen(value)-1] == '/' && strcmp(value,"/")!=0)
542 value[strlen(value)-1] = '\0';
543 DIRNORM(value,strlen(value),0);
544 strncpy(user->rootpath,value,WZD_MAX_PATH-1);
545 }
546 else if (strcmp("pass",varname)==0) {
547 strncpy(user->userpass,value,MAX_PASS_LENGTH-1);
548 }
549 else if (strcmp("flags",varname)==0) {
550 num = strlen(value);
551 if (num <= 0 || num >= MAX_FLAGS_NUM) { /* suspicious length ! */
552 continue;
553 }
554 strncpy(user->flags,value,MAX_FLAGS_NUM);
555 } /* flags */
556 else if (strcmp("uid",varname)==0) {
557 num = strtol(value, &ptr, 0);
558 if (ptr == value || *ptr != '\0' || num < 0) { /* invalid number */
559 snprintf(errbuf,sizeof(errbuf),"Invalid uid %s\n",value);
560 ERRLOG(errbuf);
561 continue;
562 }
563 user->uid = num;
564 }
565 else if (strcmp("rights",varname)==0) {
566 num = strtoul(value, &ptr, 0);
567 /* FIXME by default all users have CWD right FIXME */
568 user->userperms = num | RIGHT_CWD;
569 }
570 else if (strcmp("groups",varname)==0) {
571 wzd_group_t * _group;
572 char * group_ptr;
573
574 /* first group */
575 ptr = strtok_r(value,",",&group_ptr);
576 if (!ptr) continue;
577 _group = group_get_by_name(ptr);
578 if (_group != NULL) {
579 user->groups[user->group_num++] = _group->gid;
580 }
581
582 while ( (ptr = strtok_r(NULL,",",&group_ptr)) )
583 {
584 _group = group_get_by_name(ptr);
585 if (_group != NULL) {
586 user->groups[user->group_num++] = _group->gid;
587 }
588 }
589 } /* "groups" */
590 else if (strcmp("tagline",varname)==0) {
591 strncpy(user->tagline,value,MAX_TAGLINE_LENGTH);
592 } /* tagline */
593 else if (strcmp("max_ul_speed",varname)==0) {
594 num = strtol(value, &ptr, 0);
595 if (ptr == value || *ptr != '\0' || num < 0) { /* invalid number */
596 snprintf(errbuf,sizeof(errbuf),"Invalid max_ul_speed %s\n",value);
597 ERRLOG(errbuf);
598 continue;
599 }
600 user->max_ul_speed = num;
601 } /* max_ul_speed */
602 else if (strcmp("last_login",varname)==0) {
603 num = strtol(value, &ptr, 0);
604 if (ptr == value || *ptr != '\0' || num < 0) { /* invalid number */
605 snprintf(errbuf,sizeof(errbuf),"Invalid last_login %s\n",value);
606 ERRLOG(errbuf);
607 continue;
608 }
609 user->last_login = num;
610 } /* last_login */
611 else if (strcmp("max_dl_speed",varname)==0) {
612 num = strtol(value, &ptr, 0);
613 if (ptr == value || *ptr != '\0' || num < 0) { /* invalid number */
614 snprintf(errbuf,sizeof(errbuf),"Invalid max_dl_speed %s\n",value);
615 ERRLOG(errbuf);
616 continue;
617 }
618 user->max_dl_speed = num;
619 } /* max_dl_speed */
620 else if (strcmp("bytes_ul_total",varname)==0) {
621 ul_num = strtoull(value, &ptr, 0);
622 if (ptr == value || *ptr != '\0') { /* invalid number */
623 snprintf(errbuf,sizeof(errbuf),"Invalid bytes_ul_total %s\n",value);
624 ERRLOG(errbuf);
625 continue;
626 }
627 user->stats.bytes_ul_total = ul_num;
628 } /* bytes_ul_total */
629 else if (strcmp("bytes_dl_total",varname)==0) {
630 ul_num = strtoull(value, &ptr, 0);
631 if (ptr == value || *ptr != '\0') { /* invalid number */
632 snprintf(errbuf,sizeof(errbuf),"Invalid bytes_dl_total %s\n",value);
633 ERRLOG(errbuf);
634 continue;
635 }
636 user->stats.bytes_dl_total = ul_num;
637 } /* bytes_dl_total */
638 else if (strcmp("files_dl_total",varname)==0) {
639 u_num = strtoul(value, &ptr, 0);
640 if (ptr == value || *ptr != '\0') { /* invalid number */
641 snprintf(errbuf,sizeof(errbuf),"Invalid files_dl_total %s\n",value);
642 ERRLOG(errbuf);
643 continue;
644 }
645 user->stats.files_dl_total = u_num;
646 } /* files_dl_total */
647 else if (strcmp("files_ul_total",varname)==0) {
648 u_num = strtoul(value, &ptr, 0);
649 if (ptr == value || *ptr != '\0') { /* invalid number */
650 snprintf(errbuf,sizeof(errbuf),"Invalid files_ul_total %s\n",value);
651 ERRLOG(errbuf);
652 continue;
653 }
654 user->stats.files_ul_total = u_num;
655 } /* files_ul_total */
656 else if (strcmp("credits",varname)==0) {
657 ul_num = strtoull(value, &ptr, 0);
658 if (ptr == value || *ptr != '\0') { /* invalid number */
659 snprintf(errbuf,sizeof(errbuf),"Invalid credits %s\n",value);
660 ERRLOG(errbuf);
661 continue;
662 }
663 user->credits = ul_num;
664 } /* credits */
665
666 else if (strcmp("num_logins",varname)==0) {
667 num = strtol(value, &ptr, 0);
668 if (ptr == value || *ptr != '\0' || num < 0) { /* invalid number */
669 snprintf(errbuf,sizeof(errbuf),"Invalid number %s\n",value);
670 ERRLOG(errbuf);
671 continue;
672 }
673 user->num_logins = (unsigned short)num;
674 } /* else if (strcmp("num_logins",... */
675 else if (strcmp("ratio",varname)==0) {
676 num = strtol(value, &ptr, 0);
677 if (ptr == value || *ptr != '\0' || num < 0) { /* invalid number */
678 snprintf(errbuf,sizeof(errbuf),"Invalid ratio %s\n",value);
679 ERRLOG(errbuf);
680 continue;
681 }
682 user->ratio = num;
683 } /* else if (strcmp("ratio",... */
684 else if (strcmp("user_slots",varname)==0) {
685 u_num = strtoul(value, &ptr, 0);
686 if (ptr == value || *ptr != '\0') { /* invalid number */
687 snprintf(errbuf,sizeof(errbuf),"Invalid user_slots %s\n",value);
688 ERRLOG(errbuf);
689 continue;
690 }
691 user->user_slots = (unsigned short)u_num;
692 } /* else if (strcmp("user_slots",... */
693 else if (strcmp("leech_slots",varname)==0) {
694 u_num = strtoul(value, &ptr, 0);
695 if (ptr == value || *ptr != '\0') { /* invalid number */
696 snprintf(errbuf,sizeof(errbuf),"Invalid leech_slots %s\n",value);
697 ERRLOG(errbuf);
698 continue;
699 }
700 user->leech_slots = (unsigned short)u_num;
701 } /* else if (strcmp("user_slots",... */
702 else if (strcmp("max_idle_time",varname)==0) {
703 num = strtol(value, &ptr, 0);
704 if (ptr == value || *ptr != '\0' || num < 0) { /* invalid number */
705 snprintf(errbuf,sizeof(errbuf),"Invalid max_idle_time %s\n",value);
706 ERRLOG(errbuf);
707 continue;
708 }
709 user->max_idle_time = num;
710 } /* max_idle_time */
711 else if (strcmp("ip_allowed",varname)==0) {
712 err = __user_ip_add(user,value);
713 if (err != 0 ) {
714 snprintf(errbuf,sizeof(errbuf),"ERROR unable to add ip %s\n",value);
715 ERRLOG(errbuf);
716 continue;
717 }
718 } /* ip_allowed */
719 };
720
721 return user;
722 }
723
724 /* ignore section
725 */
section_ignore(FILE * file,const char * sectionname,char * buffer,size_t length)726 void section_ignore(FILE * file, const char *sectionname, char * buffer, size_t length)
727 {
728 while ( fgets(buffer,MAX_LINE-1,file) != NULL ) {
729 chop(buffer);
730
731 if (strlen(buffer) == 0) return;
732 };
733
734 return;
735 }
736
read_section_groups(FILE * file_user,char * line)737 int read_section_groups(FILE * file_user, char * line)
738 {
739 char c;
740 char *token;
741 char errbuf[1024];
742 unsigned int directive;
743 int err;
744 wzd_group_t * group_new = NULL;
745
746 #if 0
747 fprintf(stderr,"Entering section GROUPS\n");
748 #endif
749 while ( (c = getc(file_user)) != (char)EOF ) {
750 if (c=='\n') continue;
751 if (c=='#') { fgets(line+1,MAX_LINE-2,file_user); continue; } /* comment */
752 if (c == '[') { /* another section */
753 ungetc(c,file_user);
754 return 0;
755 }
756 line[0] = c; /* we avoid a stupid ungetc */
757 fgets(line+1,MAX_LINE-2,file_user);
758 while ( line[strlen(line)-1] == '\r' || line[strlen(line)-1] == '\n')
759 line[strlen(line)-1] = '\0'; /* clear trailing \n */
760 /* read config directive name */
761 /* NO NO NO if we use strtok, we will certainly destroy line if a space is present ! */
762 #if 0
763 token = strtok(line," \t");
764 if (!token) continue;
765 #endif
766
767 /** \todo XXX convert "privgroup toto" to "groupname=toto", and keep compatibility */
768 directive = find_directive(line);
769 switch (directive) {
770 case D_PRIVGROUP:
771 token = strtok(line," \t");
772 if (!token) continue;
773 token = strtok(NULL," \t\n");
774 if (!token) {
775 ERRLOG("privgroup should be followed by the group name !\n");
776 continue;
777 }
778
779 if (++group_count >= group_count_max) {
780 snprintf(errbuf,sizeof(errbuf),"Too many groups: %u\n",group_count);
781 ERRLOG(errbuf);
782 continue;
783 }
784
785 group_new = read_single_group(file_user, token, line, MAX_LINE);
786 /** \todo check if group is valid (gid != -1) and register it */
787
788 if (group_new->gid != (gid_t)-1) {
789 err = group_register(group_new, 1 /* XXX backend id */);
790 if ((gid_t)err != group_new->gid) {
791 snprintf(errbuf,sizeof(errbuf),"ERROR Could not register group %s\n",group_new->groupname);
792 ERRLOG(errbuf);
793 }
794 }
795
796 break;
797 default:
798 ERRLOG("Houston, we have a problem (invalid varname)\n");
799 break;
800 }
801 }
802 return 0;
803 }
804
read_section_users(FILE * file_user,char * line)805 int read_section_users(FILE * file_user, char * line)
806 {
807 char c;
808 int err;
809 char errbuf[1024];
810 wzd_user_t * user_new = NULL;
811
812 #if 0
813 fprintf(stderr,"Entering section USERS\n");
814 #endif
815 while ( (c = getc(file_user)) != (char)EOF ) {
816 if (c=='\n') continue;
817 if (c=='#') { fgets(line+1,MAX_LINE-2,file_user); continue; } /* comment */
818 if (c == '[') { /* another section */
819 ungetc(c,file_user);
820 return 0;
821 }
822 line[0] = c; /* we avoid a stupid ungetc */
823 fgets(line+1,MAX_LINE-2,file_user);
824 while ( line[strlen(line)-1] == '\r' || line[strlen(line)-1] == '\n')
825 line[strlen(line)-1] = '\0'; /* clear trailing \n */
826
827 if (line[0]=='\0') continue; /* empty line */
828
829 err = regexec(®_line,line,3,regmatch,0);
830 if (err) {
831 snprintf(errbuf,sizeof(errbuf),"Line '%s' does not respect config line format - ignoring\n",line);
832 ERRLOG(errbuf);
833 continue;
834 }
835 memcpy(varname,line+regmatch[1].rm_so,regmatch[1].rm_eo-regmatch[1].rm_so);
836 varname[regmatch[1].rm_eo-regmatch[1].rm_so]='\0';
837 memcpy(value,line+regmatch[2].rm_so,regmatch[2].rm_eo-regmatch[2].rm_so);
838 value[regmatch[2].rm_eo-regmatch[2].rm_so]='\0';
839
840 if (strcmp("name",varname)==0) {
841 if (++user_count >= user_count_max) {
842 snprintf(errbuf,sizeof(errbuf),"Too many users defined %u\n",user_count);
843 ERRLOG(errbuf);
844 continue;
845 }
846
847 user_new = read_single_user(file_user, value, line, MAX_LINE);
848
849 /** \todo check if user is valid (uid != -1, homedir != NULL etc.) */
850
851 if (user_new->uid != (uid_t)-1) {
852 err = user_register(user_new,1 /* XXX backend id */);
853 if ((uid_t)err != user_new->uid) {
854 snprintf(errbuf,sizeof(errbuf),"ERROR Could not register user %s\n",user_new->username);
855 ERRLOG(errbuf);
856 }
857 }
858
859 }
860 }
861 return 0;
862 }
863
read_files(const char * filename)864 int read_files(const char *filename)
865 {
866 FILE *file_user;
867 char * line, * token, *ptr;
868 int ret;
869 char errbuf[1024];
870
871 if (!filename || strlen(filename)>=256) {
872 ERRLOG("You MUST provide a parameter for the users file\n");
873 ERRLOG("Add param = /path/to/users in [plaintext] section in your config file\n");
874 ERRLOG("See Documentation for help\n");
875 return -1;
876 }
877 strncpy(USERS_FILE,filename,256);
878 file_user = fopen(USERS_FILE,"r");
879
880 if (file_user == NULL) {
881 ERRLOG("********************************************\n");
882 ERRLOG("\n");
883 ERRLOG("This is backend plaintext speaking:\n");
884 ERRLOG("Could not open file"); ERRLOG(USERS_FILE);
885 ERRLOG("\ndie die die !\n");
886 ERRLOG("\n");
887 ERRLOG("********************************************\n");
888 return -1;
889 }
890
891 line = malloc(MAX_LINE);
892 if (!line) {
893 ERRLOG("Could not malloc !\n");
894 return -1;
895 }
896
897 /* prepare regexp */
898 reg_line.re_nsub = 2;
899 ret = regcomp (®_line, "^([a-zA-Z0-9_]+)[ \t]*=[ \t]*(.+)", REG_EXTENDED);
900 if (ret) return 1; /* regexp could not be compiled */
901
902 /* initial size of user_pool */
903 user_count=0;
904 /* user_pool = malloc(256*sizeof(wzd_user_t));*/
905 group_count=0;
906 /* group_pool = malloc(256*sizeof(wzd_group_t));*/
907
908 #if 0
909 /* XXX We always add a user nobody and a group nogroup */
910 user = user_allocate();
911 list_ins_next(&user_list,NULL,user);
912 strcpy(user->username,"nobody");
913 strcpy(user->userpass,"------");
914 strcpy(user->rootpath,"/no/home");
915 strcpy(user->tagline,"nobody");
916 user->uid = (uid_t)-1;
917 user->userperms = RIGHT_CWD; /* should be enough ! */
918 user->group_num = 1;
919 user->groups[0] = (gid_t)-1;
920 user->max_ul_speed = 1; /* at this rate, even if you can download it will be ... slow ! */
921 user->max_dl_speed = 1;
922 user_count++;
923 #endif
924
925 #if 0
926 group = group_allocate();
927 list_ins_next(&group_list,NULL,group);
928 strcpy(group->groupname,"nogroup");
929 group->gid = (gid_t)-1;
930 group->groupperms = 0; /* should be enough ! */
931 group_count++;
932 #endif
933
934 while (1) {
935 ptr = fgets(line,MAX_LINE-1,file_user);
936 if (!ptr) { fclose(file_user); free(line); regfree(®_line); return 0; }
937 while ( strlen(line)>0 && (line[strlen(line)-1] == '\r' || line[strlen(line)-1] == '\n'))
938 line[strlen(line)-1] = '\0'; /* clear trailing \n */
939
940 if (line[0] == '\0' || line[0] == '#') { /* ignore empty lines & comments */
941 continue;
942 }
943
944 if (line[0] == '[') { /* we are beginning a section */
945 token = strtok_r(line+1,"]",&ptr);
946 if (strcasecmp("USERS",token)==0) ret = read_section_users(file_user,line);
947 else if (strcasecmp("GROUPS",token)==0) ret = read_section_groups(file_user,line);
948 else if (strcasecmp("HOSTS",token)==0) section_ignore(file_user,token,line,MAX_LINE);
949 else {
950 snprintf(errbuf,sizeof(errbuf),"Unkown section %s\n",token);
951 ERRLOG(errbuf);
952 regfree(®_line);
953 return 1;
954 }
955 continue;
956 } /* line begins by [ */
957 else { /* directive without section */
958 snprintf(errbuf,sizeof(errbuf),"directive without section in line '%s'\n",line);
959 ERRLOG(errbuf);
960 regfree(®_line);
961 return 1;
962 }
963 }
964 while (ptr);
965
966 /* end */
967 fclose(file_user);
968 free(line);
969 regfree(®_line);
970 return 0;
971 }
972
973