1#include <config.h>
2#include <stdio.h>
3#ifdef HAVE_SYS_TYPES_H
4#include <sys/types.h>
5#endif
6#ifdef HAVE_SYS_SOCKET_H
7#include <sys/socket.h>
8#endif
9
10#ifdef HAVE_DIRENT_H
11#  include <dirent.h>
12#else
13#    define dirent direct
14#    define NAMLEN(dirent) (dirent)->d_namlen
15#  ifdef HAVE_SYS_NDIR_H
16#    include <sys/ndir.h>
17#  endif
18#  ifdef HAVE_SYS_DIR_H
19#    include <sys/dir.h>
20#  endif
21#  ifdef HAVE_NDIR_H
22#    include <ndir.h>
23#  endif
24#endif
25
26#include <unistd.h>
27#ifdef HAVE_SYS_STAT_H
28#include <sys/stat.h>
29#endif
30#include <stdlib.h>
31#include <stdarg.h>
32#include <string.h>
33#include <mystring.h>
34#ifdef HAVE_SYS_TIME_H
35#include <sys/time.h>
36#endif
37#ifdef HAVE_TIME_H
38#include <time.h>
39#endif
40#include <pwd.h>
41#include <grp.h>
42#include <errno.h>
43#include <glob.h>
44
45#include "cwd.h"
46#include "options.h"
47#include "main.h"
48#include "login.h"
49#include "dirlist.h"
50
51/* pling added start 06/24/2009 */
52/* Calculcate the real file size based on stat info */
53static unsigned long long get_real_file_size(struct stat *st)
54{
55    unsigned long long file_size_64;
56    unsigned long long order;
57
58    /* Check whether file size > 4GB which exceeds 32-bit st->st_size
59     *  st->sb_blocks in units of 512 bytes.
60     *  If 'st->sb_blocks' x 512 > 4GB, then this file > 4GB.
61     */
62    if (st->st_blocks >= 8388608L)
63    {
64        order = st->st_blocks / 8388608L;  // order = # of 4GB
65        file_size_64 = 0x100000000 * order + (unsigned long)(st->st_size);
66    }
67    else
68        file_size_64 = st->st_size & 0xFFFFFFFF;
69
70    //printf("file_size_64 = %llu\n", file_size_64);
71
72    return file_size_64;
73}
74/* pling added end 06/24/2009 */
75
76struct hidegroup *hidegroups = NULL;
77
78void add_to_hidegroups(int gid)
79{
80    static struct hidegroup *tmp = NULL;
81    if (tmp)
82        tmp = tmp->next = malloc(sizeof(struct hidegroup));
83    else
84        hidegroups = tmp = malloc(sizeof(struct hidegroup));
85
86    if (tmp)
87    {
88      tmp->next = NULL;
89      tmp->data = gid;
90    }
91}
92
93void hidegroups_init()
94{
95    char *foo = strdup(config_getoption("HIDE_GROUP"));
96    char *foo_save = foo;
97    char *bar;
98    struct group *tmpgrp;
99
100    while ((bar = strtok(foo, ","))) {
101        foo = NULL; /* strtok requirement */
102        if ((strcmp(bar, "0")) && (!strtoul(bar, NULL, 10))) {
103            /* bar is not numeric */
104            if ((tmpgrp = getgrnam(bar)))
105                add_to_hidegroups(tmpgrp->gr_gid);
106        } else
107            if (strtoul(bar, NULL, 10))
108                add_to_hidegroups(strtoul(bar, NULL, 10));
109    }
110	free(foo_save);
111}
112
113void hidegroups_end()
114{
115    struct hidegroup *tmp = hidegroups;
116    if (hidegroups)
117        while (hidegroups->next) {
118            tmp = hidegroups->next;
119            free(hidegroups);
120            hidegroups = tmp;
121        }
122}
123
124/* Foxconn added start pling 06/20/2009 */
125#include "logging.h"
126int is_dir_allow_read(char *dir_name)
127{
128    char curr_dir[1024];
129    int allow_read = 0;
130
131    /* Change to the specified dir, and see if the
132     * "ALLOWCOMMAND_LIST" is enabled or not.
133     */
134    memset(curr_dir, 0, sizeof(curr_dir));
135    getcwd(curr_dir, sizeof(curr_dir)-1);
136
137    bftpd_log("Cwd='%s', checking '%s' for admin-read\n", curr_dir, dir_name);
138
139    if (chdir(dir_name))
140        bftpd_log("Unable to chdir '%s', errno=%d\n", dir_name, errno);
141    else
142    {
143        if (!strcasecmp(getoption_user("ALLOWCOMMAND_LIST"), "yes"))
144            allow_read = 1;
145    	    chdir(curr_dir);
146    }
147
148    return allow_read;
149}
150/* Foxconn added end pling 06/20/2009 */
151
152void bftpd_stat(char *name, FILE * client)
153{
154    struct stat statbuf;
155    char temp[MAXCMD + 3], linktarget[MAXCMD + 5], perm[11], timestr[17], uid[USERLEN + 1], gid[USERLEN + 1];
156    struct tm filetime;
157    time_t t;
158    static int first_time = 1;  /* Foxconn added pling 06/28/2010 */
159
160
161    if (lstat(name, (struct stat *) &statbuf) == -1) { // used for command_stat
162        fprintf(client, "213-Error: %s.\n", strerror(errno));
163        return;
164    }
165
166#if 0
167    /* Foxconn added start pling 06/20/2009 */
168    /* Don't let 'guest' user see "Admin-read" folders */
169    if (S_ISDIR(statbuf.st_mode) || S_ISLNK(statbuf.st_mode))
170    {
171        if (!is_dir_allow_read(name))
172            return;
173    }
174    /* Foxconn added end pling 06/20/2009 */
175#endif
176
177    //if ( strcmp(user, "admin") != 0 ) {
178    //    if ( !is_dir_allow_read(name) )
179    //        return;
180    //}
181
182#ifdef S_ISLNK
183	if (S_ISLNK(statbuf.st_mode)) {
184        /* Foxconn modified start pling 03/09/2010 */
185        /* Show links as directories, other Safari can't
186         * handle links properly.
187         * Note: in FAT32/NTFS, there are no links.
188         * This link is either "USB_Storage", "T_Drive"
189         * or other share names that user defines.
190         */
191		//strcpy(perm, "lrwxrwxrwx");
192		strcpy(perm, "drwxrwxrwx");
193        /* Foxconn modified end pling 03/09/2010 */
194        /* Foxconn modified start pling 06/20/2009 */
195        /* Don't show symlink */
196#if 0
197		temp[readlink(name, temp, sizeof(temp) - 1)] = '\0';
198		sprintf(linktarget, " -> %s", temp);
199#endif
200        linktarget[0] = '\0';
201        /* Foxconn modified end pling 06/20/2009 */
202	} else {
203#endif
204		strcpy(perm, "----------");
205		if (S_ISDIR(statbuf.st_mode))
206			perm[0] = 'd';
207		if (statbuf.st_mode & S_IRUSR)
208			perm[1] = 'r';
209		if (statbuf.st_mode & S_IWUSR)
210			perm[2] = 'w';
211		if (statbuf.st_mode & S_IXUSR)
212			perm[3] = 'x';
213		if (statbuf.st_mode & S_IRGRP)
214			perm[4] = 'r';
215		if (statbuf.st_mode & S_IWGRP)
216			perm[5] = 'w';
217		if (statbuf.st_mode & S_IXGRP)
218			perm[6] = 'x';
219		if (statbuf.st_mode & S_IROTH)
220			perm[7] = 'r';
221		if (statbuf.st_mode & S_IWOTH)
222			perm[8] = 'w';
223		if (statbuf.st_mode & S_IXOTH)
224			perm[9] = 'x';
225		linktarget[0] = '\0';
226#ifdef S_ISLNK
227	}
228#endif
229    memcpy(&filetime, localtime(&(statbuf.st_mtime)), sizeof(struct tm));
230    time(&t);
231    if (filetime.tm_year == localtime(&t)->tm_year)
232    	mystrncpy(timestr, ctime(&(statbuf.st_mtime)) + 4, 12);
233    else
234        strftime(timestr, sizeof(timestr), "%b %d  %G", &filetime);
235    mygetpwuid(statbuf.st_uid, passwdfile, uid)[8] = 0;
236    mygetpwuid(statbuf.st_gid, groupfile, gid)[8] = 0;
237
238    /* Foxconn added start pling 06/28/2010 */
239    /* Fix Chrome V4.0.249.78 FTP issue;
240     *  need to provide a "." directory entry for Chrome to
241     *  show properly.
242     */
243    if (first_time)
244    {
245    	fprintf(client, "%s %3i %-8s %-8s 0 %s .\r\n", "drwxrwxrwx",
246	    		(int) 1, uid, gid,
247			    timestr);
248        first_time = 0;
249    }
250    /* Foxconn added end pling 06/28/2010 */
251
252    /* Foxconn modified start pling 06/29/2009 */
253    /* Show big file size (>4GB) correctly */
254#if 0
255	fprintf(client, "%s %3i %-8s %-8s %8lu %s %s%s\r\n", perm,
256			(int) statbuf.st_nlink, uid, gid,
257			(unsigned long) statbuf.st_size,
258			timestr, name, linktarget);
259#endif
260    unsigned long long real_file_size = get_real_file_size(&statbuf);
261	fprintf(client, "%s %3i %-8s %-8s %llu %s %s%s\r\n", perm,
262			(int) statbuf.st_nlink, uid, gid,
263			(unsigned long long) real_file_size,
264			timestr, name, linktarget);
265    /* Foxconn modified end pling 06/29/2009 */
266}
267
268void dirlist_one_file(char *name, FILE *client, char verbose)
269{
270    struct stat statbuf;
271    struct hidegroup *tmp = hidegroups;
272    char *filename_index;      /* place where filename starts in path */
273
274    if (!stat(name, (struct stat *) &statbuf)) {
275        if (tmp)
276            do {
277                if (statbuf.st_gid == tmp->data)
278                    return;
279            } while ((tmp = tmp->next));
280    }
281
282    /* find start of filename after path */
283    filename_index = strrchr(name, '/');
284    if (filename_index)
285       filename_index++;   /* goto first character after '/' */
286    else
287       filename_index = name;
288
289    if (lstat(name, (struct stat *) &statbuf) == -1) { // used for command_stat
290       fprintf(client, "213-Error: %s.\n", strerror(errno));
291       return;
292    }
293
294    /* Foxconn added start pling 06/20/2009 */
295    /* Don't let 'guest' user see "Admin-read" folders */
296    if (S_ISDIR(statbuf.st_mode) || S_ISLNK(statbuf.st_mode))
297    {
298          if (!is_dir_allow_read(name))
299          return;
300    }
301    /* Foxconn added end pling 06/20/2009 */
302
303    if (verbose)
304        bftpd_stat(name, client);
305    else
306        fprintf(client, "%s\r\n", filename_index);
307}
308
309void dirlist(char *name, FILE * client, char verbose)
310{
311	DIR *directory;
312    char *cwd = NULL;
313    int i;
314	glob_t globbuf;
315    if ((strstr(name, "/.")) && strchr(name, '*'))
316        return; /* DoS protection */
317	if ((directory = opendir(name))) {
318	   closedir(directory);
319           cwd = bftpd_cwd_getcwd();
320           chdir(name);
321           glob("*", 0, NULL, &globbuf);
322	} else
323    	   glob(name, 0, NULL, &globbuf);
324
325	for (i = 0; i < globbuf.gl_pathc; i++)
326            dirlist_one_file(globbuf.gl_pathv[i], client, verbose);
327
328	globfree(&globbuf);
329	if (cwd) {
330  	   chdir(cwd);
331		free(cwd);
332	}
333}
334