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(&reg_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(&reg_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(&reg_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 (&reg_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(&reg_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(&reg_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(&reg_line);
961       return 1;
962     }
963   }
964   while (ptr);
965 
966   /* end */
967   fclose(file_user);
968   free(line);
969   regfree(&reg_line);
970   return 0;
971 }
972 
973