1#include <config.h>
2#include <stdio.h>
3#include <pwd.h>
4#ifdef HAVE_SHADOW_H
5#include <shadow.h>
6#endif
7#include <sys/stat.h>
8#include <sys/types.h>
9#include <fcntl.h>
10#include <unistd.h>
11#include <string.h>
12#ifdef HAVE_CRYPT_H
13#include <crypt.h>
14#endif
15#ifdef WANT_PAM
16#include <security/pam_appl.h>
17#endif
18#ifdef HAVE_UTMP_H
19# include <utmp.h>
20# ifdef HAVE_PATHS_H
21#  include <paths.h>
22#  ifndef _PATH_WTMP
23#   define _PATH_WTMP "/dev/null"
24#   warning "<paths.h> doesn't set _PATH_WTMP. You can not use wtmp logging"
25#   warning "with bftpd."
26#  endif
27# else
28#  define _PATH_WTMP "/dev/null"
29#  warning "<paths.h> was not found. You can not use wtmp logging with bftpd."
30# endif
31#endif
32#include <errno.h>
33#include <grp.h>
34#include <stdlib.h>
35#ifdef HAVE_SYS_TIME_H
36#include <sys/time.h>
37#endif
38#ifdef HAVE_TIME_H
39#include <time.h>
40#endif
41
42#include "cwd.h"
43#include "dirlist.h"
44#include "mystring.h"
45#include "options.h"
46#include "login.h"
47#include "logging.h"
48#include "bftpdutmp.h"
49#include "main.h"
50
51#ifdef WANT_PAM
52char usepam = 0;
53pam_handle_t *pamh = NULL;
54#endif
55
56#ifdef HAVE_UTMP_H
57FILE *wtmp;
58#endif
59
60struct passwd userinfo;
61char userinfo_set = 0;
62
63/*zzz add for geting first partition, 12/11/2007 */
64#define NDEBUG //turn off to set assert and P1MSG
65#ifdef NDEBUG
66  #define P1MSG(args...)
67#else
68  #define P1MSG(args...) fprintf(stderr, "%s-%04d: ", __FILE__, __LINE__) ; fprintf(stderr, ## args)
69#endif // NDEBUG
70
71/* Foxconn added start by Jenny Zhao, 06/10/2011 @USB log */
72#include "bcmnvram.h"
73#include <errno.h>
74extern int g_isLanIp;
75extern char client_ip[32];
76
77/*
78 ** check whether an IP address is in the LAN subnet
79 **/
80int isLanSubnet(char *ipAddr)
81{
82    long netAddr, netMask, netIp;
83    netAddr = inet_addr(nvram_safe_get("lan_ipaddr"));
84    netMask = inet_addr(nvram_safe_get("lan_netmask"));
85    netIp   = inet_addr(ipAddr);
86    if ((netAddr & netMask) != (netIp & netMask))
87    {
88        return FALSE;
89    }
90    return TRUE;
91}
92
93void write_usb_access_log(void)
94{
95    if (!g_isLanIp)
96    {
97        FILE *fp;
98        char logBuffer[96];
99        if ((fp = fopen("/dev/aglog", "r+")) != NULL)
100        {
101            sprintf(logBuffer, "[USB remote access] from %s through FTP,", client_ip);
102            fwrite(logBuffer, sizeof(char), strlen(logBuffer)+1, fp);
103            fclose(fp);
104        }
105    }
106}
107
108void write_usb_fail_log(void)
109{
110    if (!g_isLanIp)
111    {
112        FILE *fp;
113        char logBuffer[96];
114        if ((fp = fopen("/dev/aglog", "r+")) != NULL)
115        {
116            sprintf(logBuffer, "[USB remote access rejected] from %s through FTP,", client_ip);
117            fwrite(logBuffer, sizeof(char), strlen(logBuffer)+1, fp);
118            fclose(fp);
119        }
120    }
121}
122/* Foxconn added end by Jenny Zhao, 06/10/2011 */
123
124
125static char mount_path[128];
126int readOnlyOnPart1 = 0; //@ftpRW
127
128static void scanPartitons()
129{
130    FILE *fp = 0;
131    char line[256];
132
133//===================================
134// parse /proc/mounts
135// format:
136// /dev/sdb1 /mnt/share/usb1/part1 vfat rw,sync 0 0
137//===================================
138
139
140    fp = fopen("/proc/mounts", "r");
141    mount_path[0] = 0;
142    readOnlyOnPart1 = 0;
143    if (fp)
144    {
145        while (1)
146        {
147            memset(line, 0x00, 256);
148            if (feof(fp))
149            {
150                break;
151            }
152
153            fgets(line, 256, fp);
154            if (strncmp(line, "/dev/sd", 7) == 0)
155            {
156                char *saveptr1;
157                char *token = strtok_r(line, " \t\n", &saveptr1);
158
159                if (token)
160                {
161                    token = strtok_r(NULL, " \t,\n", &saveptr1);
162
163                    P1MSG("save path %s \n", token);
164                    strcpy(mount_path, token);
165
166                    /*
167                    ** @ftpRW
168                    **  update the r/w mode from mount message
169                    */
170                    token = strtok_r(NULL, " \t,\n", &saveptr1);//fs type
171                    token = strtok_r(NULL, " \t,\n", &saveptr1);//rw
172                    if(!strstr(token,"w"))
173                        readOnlyOnPart1 = 1;
174
175
176                    break;
177                } //if token
178
179            }
180        } //while 1 -> read lines in files
181        fclose(fp);
182    }
183    else
184    {
185        fprintf(stderr, "open /porc/mount failed\n");
186    }
187}
188/* szzz added end */
189
190
191
192
193
194char *mygetpwuid (int uid, FILE * file, char *name)
195{
196    int _uid;
197    char foo[256];
198    int i;
199
200    if (file)
201    {
202        rewind (file);
203        while (fscanf (file, "%255s%*[^\n]\n", foo) != EOF)
204        {
205            if ((foo[0] == '#') || (!strchr (foo, ':'))
206                || (strchr (foo, ':') > foo + USERLEN - 1))
207                continue;
208            i = strchr (foo, ':') - foo;
209            strncpy (name, foo, i);
210            name[i] = 0;
211            sscanf (strchr (foo + i + 1, ':') + 1, "%i", &_uid);
212            if (_uid == uid)
213            {
214                if (name[0] == '\n')
215                    cutto (name, 1);
216                return name;
217            }
218        }
219    }
220    sprintf (name, "%i", uid);
221    return name;
222}
223
224int mygetpwnam (char *name, FILE * file)
225{
226    char _name[USERLEN + 1];
227    char foo[256];
228    int uid, i;
229
230    if (file)
231    {
232        rewind (file);
233        while (fscanf (file, "%255s%*[^\n]\n", foo) != EOF)
234        {
235            if ((foo[0] == '#') || (!strchr (foo, ':'))
236                || (strchr (foo, ':') > foo + USERLEN - 1))
237                continue;
238            i = strchr (foo, ':') - foo;
239            strncpy (_name, foo, i);
240            _name[i] = 0;
241            sscanf (strchr (foo + i + 1, ':') + 1, "%i", &uid);
242            if (_name[0] == '\n')
243                cutto (_name, 1);
244            if (!strcmp (name, _name))
245                return uid;
246        }
247    }
248    return -1;
249}
250
251#ifdef HAVE_UTMP_H
252void wtmp_init ()
253{
254    if (strcasecmp (config_getoption ("LOG_WTMP"), "no"))
255    {
256        if (!((wtmp = fopen (_PATH_WTMP, "a"))))
257            bftpd_log ("Warning: Unable to open %s.\n", _PATH_WTMP);
258    }
259}
260
261void bftpd_logwtmp (char type)
262{
263    struct utmp ut;
264
265    if (!wtmp)
266        return;
267    memset ((void *) &ut, 0, sizeof (ut));
268#ifdef _HAVE_UT_PID
269    ut.ut_pid = getpid ();
270#endif
271    sprintf (ut.ut_line, "ftp%i", (int) getpid ());
272    if (type)
273    {
274#ifdef _HAVE_UT_TYPE
275        ut.ut_type = USER_PROCESS;
276#endif
277        strncpy (ut.ut_name, user, sizeof (ut.ut_name));
278#ifdef _HAVE_UT_HOST
279        strncpy (ut.ut_host, remotehostname, sizeof (ut.ut_host));
280#endif
281    }
282    else
283    {
284#ifdef _HAVE_UT_TYPE
285        ut.ut_type = DEAD_PROCESS;
286#endif
287    }
288    time (&(ut.ut_time));
289    fseek (wtmp, 0, SEEK_END);
290    fwrite ((void *) &ut, sizeof (ut), 1, wtmp);
291    fflush (wtmp);
292}
293
294void wtmp_end ()
295{
296    if (wtmp)
297    {
298        if (state >= STATE_AUTHENTICATED)
299            bftpd_logwtmp (0);
300        fclose (wtmp);
301    }
302}
303#endif
304
305void login_init ()
306{
307    char *foo = config_getoption ("INITIAL_CHROOT");
308
309#ifdef HAVE_UTMP_H
310    wtmp_init ();
311#endif
312    if (foo[0])
313    {                           /* Initial chroot */
314        if (chroot (foo) == -1)
315        {
316            control_printf (SL_FAILURE, "421 Initial chroot failed.\r\n.");
317            exit (1);
318        }
319    }
320}
321
322int bftpd_setuid (uid_t uid)
323{
324    /* If we must open the data connections from port 20,
325     * we have to keep the possibility to regain root privileges */
326    if (!strcasecmp (config_getoption ("DATAPORT20"), "yes"))
327        return seteuid (uid);
328    else
329        return setuid (uid);
330}
331
332int bftpd_login (char *password)
333{
334    char str[256];
335    char *foo;
336    int maxusers;
337    char *file_auth;            /* if used, points to file used to auth users */
338    char *home_directory = NULL;        /* retrieved from auth_file */
339    char *anonymous = NULL;
340    char chfolder [256]=""; /* Foxconn add, Jasmine Yang, 09/12/2007 */
341    char tmpBuf[256] = "";/*foxconn, water, 11/07/2008*/
342
343    P1MSG("%s(%d)\r\n", __FUNCTION__, __LINE__);
344    str[0] = '\0';              /* avoid garbage in str */
345    file_auth = config_getoption ("FILE_AUTH");
346
347    if (!file_auth[0])          /* not using auth file */
348    {
349        // check to see if regular authentication is avail
350#ifndef NO_GETPWNAM
351        if (!getpwnam (user))
352        {
353            /* foxconn added start, zacker, 09/13/2010, @chrome_login */
354            if (strcasecmp (config_getoption ("ANONYMOUS_USER"), "yes")
355                && !strcasecmp (user, "anonymous"))
356            {
357                control_printf (SL_FAILURE, "530 Sorry, no ANONYMOUS access allowed.");
358                return 0; /* STATE_USER, for later command 'QUIT' handling */
359            }
360            /* foxconn added end, zacker, 09/13/2010, @chrome_login */
361            else
362            {
363                control_printf (SL_FAILURE, "421 Login incorrect.");
364                //printf ("%s(%d)\r\n", __FUNCTION__, __LINE__);
365                exit (0);
366            }
367        }
368#endif
369    }
370    /* we are using auth_file */
371    else
372    {
373        home_directory = check_file_password (file_auth, user, password);
374        anonymous = config_getoption ("ANONYMOUS_USER");
375        if (!home_directory)
376        {
377            if (!strcasecmp (anonymous, "yes"))
378                home_directory = "/";
379            else
380            {
381                control_printf (SL_FAILURE, "421 Authentication incorrect.");
382                //printf ("%s(%d)\r\n", __FUNCTION__, __LINE__);
383                exit (0);
384            }
385        }
386    }
387
388    if (strncasecmp (foo = config_getoption ("DENY_LOGIN"), "no", 2))
389    {
390        if (foo[0] != '\0')
391        {
392            if (strncasecmp (foo, "yes", 3))
393            {
394                control_printf (SL_FAILURE,
395                                "421-Server disabled.\r\n421 Reason: %s",
396                                foo);
397                //printf ("%s(%d)\r\n", __FUNCTION__, __LINE__);
398            }
399            else
400            {
401                control_printf (SL_FAILURE, "421 Login incorrect.");
402                //printf ("%s(%d)\r\n", __FUNCTION__, __LINE__);
403            }
404            bftpd_log ("Login as user '%s' failed: Server disabled.\n", user);
405            exit (0);
406        }
407    }
408    maxusers = strtoul (config_getoption ("USERLIMIT_GLOBAL"), NULL, 10);
409    if ((maxusers) && (maxusers == bftpdutmp_usercount ("*")))
410    {
411        control_printf (SL_FAILURE,
412                        "421 There are already %i users logged in.",
413                        maxusers);
414        bftpd_log ("Login as user '%s' failed. Too many users on server.\n",
415                   user);
416        //printf ("%s(%d)\r\n", __FUNCTION__, __LINE__);
417        exit (0);
418    }
419    maxusers = strtoul (config_getoption ("USERLIMIT_SINGLEUSER"), NULL, 10);
420    if ((maxusers) && (maxusers == bftpdutmp_usercount (user)))
421    {
422        control_printf (SL_FAILURE,
423                        "421 User %s is already logged in %i times.", user,
424                        maxusers);
425        bftpd_log ("Login as user '%s' failed. Already logged in %d times.",
426                   maxusers);
427        //printf ("%s(%d)\r\n", __FUNCTION__, __LINE__);
428        exit (0);
429    }
430
431    /* Check to see if we should block mulitple logins from the same machine.
432       -- Jesse <slicer69@hotmail.com>
433     */
434    maxusers = strtoul (config_getoption ("USERLIMIT_HOST"), NULL, 10);
435    if ((maxusers) && (maxusers == bftpdutmp_dup_ip_count (remotehostname)))
436    {
437        control_printf (SL_FAILURE,
438                        "421 Too many connections from your IP address.");
439        bftpd_log
440            ("Login as user '%s' failed. Already %d connections from %s.\n",
441             user, maxusers, remotehostname);
442        //printf ("%s(%d)\r\n", __FUNCTION__, __LINE__);
443        exit (0);
444    }
445
446    /* disable these checks when logging in via auth file */
447    if (!file_auth[0])
448    {
449#ifndef NO_GETPWNAM
450/* Foxconn add start, Jasmine Yang, 09/12/2007 */
451        //if (checkuser () || checkshell ())
452        if (checkuser ())
453/* Foxconn add end, Jasmine Yang, 09/12/2007 */
454        {
455            control_printf (SL_FAILURE, "421 Login incorrect.");
456            //printf ("%s(%d)\r\n", __FUNCTION__, __LINE__);
457            exit (0);
458        }
459#endif
460    }
461
462    /* do not do this check when we are using auth_file */
463    if (!file_auth[0])
464    {
465#ifndef NO_GETPWNAM
466        if (checkpass (password))
467            return 1;
468#endif
469    }
470
471    if (strcasecmp ((char *) config_getoption ("RATIO"), "none"))
472    {
473        sscanf ((char *) config_getoption ("RATIO"), "%i/%i", &ratio_send,
474                &ratio_recv);
475    }
476
477    /* do these checks if logging in via normal methods */
478    if (!file_auth[0])
479    {
480        strcpy (str, config_getoption ("ROOTDIR"));
481        if (!str[0])
482            strcpy (str, "%h");
483        P1MSG("userinfo.pw_name=%s,userinfo.pw_dir=%s\r\n",  userinfo.pw_name, userinfo.pw_dir);
484        replace (str, "%u", userinfo.pw_name);
485        strcpy(tmpBuf, userinfo.pw_dir);/*foxconn, water, 11/07/2008*/
486        replace (str, "%h", userinfo.pw_dir);
487        if (!strcasecmp (config_getoption ("RESOLVE_UIDS"), "yes"))
488        {
489            passwdfile = fopen ("/etc/passwd", "r");
490            groupfile = fopen ("/etc/group", "r");
491        }
492
493        setgid (userinfo.pw_gid);
494        initgroups (userinfo.pw_name, userinfo.pw_gid);
495        /* Foxconn add start, Jasmine Yang, 09/12/2007 */
496        scanPartitons(); //zzz, get first partition, 12/11/2007
497        /* Make sure the login folder is user's account name */
498
499        /* Foxconn Add Start : Steve Hsieh : 01/22/2008, @ftpRW {*/
500        /* -- should use shared dir in usb_setting page as root dir --*/
501
502        /*foxconn modified start, water, 11/07/2008,
503          I think it isn't a good solution, need further implement later*/
504        //sprintf (chfolder, "%s/%s", mount_path, userinfo.pw_name);
505        sprintf (chfolder, "%s%s", mount_path, tmpBuf);
506        /*foxconn modified end, water, 11/07/2008, it isn't a good solution, need further implement*/
507
508        /* Foxconn Add End : Steve Hsieh : 01/22/2008, @ftpRW }*/
509
510        //water add temporarily, no usb now, it will be removed soon, @debug 05/30/2008
511        //sprintf (chfolder, "/tmp");
512
513
514        /*
515        **  @ftpRW
516        **  if readonly fs, just use the "/" as root dir
517        */
518        //if (access (chfolder, 7) != 0)
519        if(readOnlyOnPart1)
520        {
521            /* zzz add. 12/11/2007 */
522            //set ftp root to "/" if the mounted partition is read only
523            bftpd_log("partition 1 is readonly\n");
524            sprintf (chfolder, "%s", mount_path);
525
526            printf("checking %s\n", mount_path);
527
528            if (access(chfolder, R_OK|X_OK) == 0 )
529            {
530                sprintf (chfolder, "%s", mount_path);
531            }
532            else
533            {
534                //zzz: Is this correct? Think twice??
535            sprintf(chfolder, "/tmp/samba/share/%s", userinfo.pw_name);
536            }
537            /* zzz added. 12/11/2007 */
538        }
539        else    //RW file system
540        {
541            /*
542            **  mkdir to the target shared forder if the dir is not exist
543            */
544            if (access (chfolder, R_OK) != 0)
545            {
546                char cmdx[512]="";
547                sprintf(cmdx,"mkdir -p %s",chfolder) ;
548                bftpd_log("create dir [%s]\n",chfolder);
549                system(cmdx);
550            }
551        }
552
553        /* Foxconn modified start pling 05/14/2009 */
554        /* Change rootdir to "/tmp" */
555        //strcpy(str,chfolder );
556        strcpy(str, "/tmp" );
557        /* Foxconn modified end pling 05/14/2009 */
558	/* Foxconn added start by Jenny Zhao, 06/10/2011 @USB log */
559        /* In fact, we want to write USB remote access log after "230
560	 * User logged in.". But the log file /dev/aglog can't be opened
561	 * after chroot to "/tmp",we write log at here before do chroot
562	 * function */
563        write_usb_access_log();
564        /* Foxconn added end by Jenny Zhao, 06/10/2011 */
565
566        /* Foxconn add end, Jasmine Yang, 09/12/2007 */
567        if (strcasecmp (config_getoption ("DO_CHROOT"), "no"))
568        {
569            bftpd_log("change for ROOTDIR [%s]\n",chfolder);
570            if (chroot (str))
571            {
572                control_printf (SL_FAILURE,
573                                "421 Unable to change root directory.\r\n%s.",
574                                strerror (errno));
575                //printf ("%s(%d)\r\n", __FUNCTION__, __LINE__);
576                exit (0);
577            }
578            if (bftpd_setuid (userinfo.pw_uid))
579            {
580                control_printf (SL_FAILURE, "421 Unable to change uid.");
581                //printf ("%s(%d)\r\n", __FUNCTION__, __LINE__);
582                exit (0);
583            }
584            if (chdir ("/"))
585            {
586                control_printf (SL_FAILURE,
587                                "421 Unable to change working directory.\r\n%s.",
588                                strerror (errno));
589                //printf ("%s(%d)\r\n", __FUNCTION__, __LINE__);
590                exit (0);
591            }
592        }
593        else
594        {
595            if (bftpd_setuid (userinfo.pw_uid))
596            {
597                control_printf (SL_FAILURE, "421 Unable to change uid.");
598                //printf ("%s(%d)\r\n", __FUNCTION__, __LINE__);
599                exit (0);
600            }
601            if (chdir (str))
602            {
603                control_printf (SL_FAILURE,
604                                "230 Couldn't change cwd to '%s': %s.", str,
605                                strerror (errno));
606                //printf ("%s(%d)\r\n", __FUNCTION__, __LINE__);
607                chdir ("/");
608            }
609        }
610
611    }                           /* end of if we are using regular authentication methods */
612
613    else                        /* we are using file authentication */
614    {
615        /* get home directory */
616        strcpy (str, config_getoption ("ROOTDIR"));
617        if (!str[0])
618            strcpy (str, "%h");
619        replace (str, "%h", home_directory);
620        replace (str, "%u", user);
621
622        /* see if we should change root */
623        if (!strcasecmp (config_getoption ("DO_CHROOT"), "yes"))
624        {
625            if (chroot (home_directory))
626            {
627                control_printf (SL_FAILURE,
628                                "421 Unable to change root directory.\r\n");
629                //printf ("%s(%d)\r\n", __FUNCTION__, __LINE__);
630                exit (0);
631            }
632            if (chdir ("/"))
633            {
634                control_printf (SL_FAILURE,
635                                "421 Unable to change working directory.\r\n");
636                //printf ("%s(%d)\r\n", __FUNCTION__, __LINE__);
637                exit (0);
638            }
639        }
640
641    }                           /* end of using file auth */
642
643    new_umask ();
644    print_file (230, config_getoption ("MOTD_USER"));
645    control_printf (SL_SUCCESS, "230 User logged in.");
646#ifdef HAVE_UTMP_H
647    bftpd_logwtmp (1);
648#endif
649    bftpdutmp_log (1);
650    bftpd_log ("Successfully logged in as user '%s'.\n", user);
651    if (config_getoption ("AUTO_CHDIR")[0])
652        chdir (config_getoption ("AUTO_CHDIR"));
653
654    state = STATE_AUTHENTICATED;
655    bftpd_cwd_init ();
656
657    /* a little clean up before we go */
658    if ((home_directory) && (strcmp (home_directory, "/")))
659        free (home_directory);
660    return 0;
661}
662
663
664/* Return 1 on failure and 0 on success. */
665int checkpass (char *password)
666{
667#ifndef NO_GETPWNAM
668    if (!getpwnam (user))
669        return 1;
670#endif
671
672    if (!strcasecmp (config_getoption ("ANONYMOUS_USER"), "yes"))
673        return 0;
674
675#ifdef WANT_PAM
676    if (!strcasecmp (config_getoption ("AUTH"), "pam"))
677        return checkpass_pam (password);
678    else
679#endif
680        return checkpass_pwd (password);
681}
682
683
684
685void login_end ()
686{
687#ifdef WANT_PAM
688    if (usepam)
689        return end_pam ();
690#endif
691#ifdef HAVE_UTMP_H
692    wtmp_end ();
693#endif
694}
695
696int checkpass_pwd (char *password)
697{
698#ifdef HAVE_SHADOW_H
699    struct spwd *shd;
700#endif
701/* Foxconn add start, Jasmine Yang, 09/12/2007 */
702    //if (strcmp(userinfo.pw_passwd, (char *) crypt(password, userinfo.pw_passwd))) {
703
704    P1MSG("%s(%d)userinfo.pw_passwd=%s , password=%s \r\n", __FUNCTION__,
705            __LINE__, userinfo.pw_passwd, password);
706
707    if (strcmp (userinfo.pw_passwd, password))
708    {
709/* Foxconn add end, Jasmine Yang, 09/12/2007 */
710#ifdef HAVE_SHADOW_H
711        if (!(shd = getspnam (user)))
712            return 1;
713        if (strcmp (shd->sp_pwdp, (char *) crypt (password, shd->sp_pwdp)))
714#endif
715            return 1;
716    }
717    return 0;
718}
719
720#ifdef WANT_PAM
721int conv_func (int num_msg, const struct pam_message **msgm,
722               struct pam_response **resp, void *appdata_ptr)
723{
724    struct pam_response *response;
725    int i;
726    response =
727        (struct pam_response *) malloc (sizeof (struct pam_response) *
728                                        num_msg);
729    for (i = 0; i < num_msg; i++)
730    {
731        response[i].resp = (char *) strdup (appdata_ptr);
732        response[i].resp_retcode = 0;
733    }
734    *resp = response;
735    return 0;
736}
737
738int checkpass_pam (char *password)
739{
740    struct pam_conv conv = { conv_func, password };
741    int retval = pam_start ("bftpd", user, (struct pam_conv *) &conv,
742                            (pam_handle_t **) & pamh);
743
744    if (retval != PAM_SUCCESS)
745    {
746        printf ("Error while initializing PAM: %s\n",
747                pam_strerror (pamh, retval));
748        return 1;
749    }
750    pam_fail_delay (pamh, 0);
751    retval = pam_authenticate (pamh, 0);
752    if (retval == PAM_SUCCESS)
753        retval = pam_acct_mgmt (pamh, 0);
754    if (retval == PAM_SUCCESS)
755        pam_open_session (pamh, 0);
756    if (retval != PAM_SUCCESS)
757        return 1;
758    else
759        return 0;
760}
761
762void end_pam ()
763{
764    if (pamh)
765    {
766        pam_close_session (pamh, 0);
767        pam_end (pamh, 0);
768    }
769}
770#endif
771
772int checkuser ()
773{
774
775    FILE *fd;
776    char *p;
777    char line[256];
778
779    if ((fd = fopen (config_getoption ("PATH_FTPUSERS"), "r")))
780    {
781        while (fgets (line, sizeof (line), fd))
782            if ((p = strchr (line, '\n')))
783            {
784                *p = '\0';
785                if (line[0] == '#')
786                    continue;
787                if (!strcasecmp (line, user))
788                {
789                    fclose (fd);
790                    return 1;
791                }
792            }
793        fclose (fd);
794    }
795    return 0;
796}
797
798int checkshell ()
799{
800#ifdef HAVE_GETUSERSHELL
801    char *cp;
802    struct passwd *pwd;
803
804    if (!strcasecmp (config_getoption ("AUTH_ETCSHELLS"), "no"))
805        return 0;
806
807    pwd = getpwnam (user);
808    while ((cp = getusershell ()))
809        if (!strcmp (cp, pwd->pw_shell))
810            break;
811    endusershell ();
812
813    if (!cp)
814        return 1;
815    else
816        return 0;
817#else
818    return 0;
819#   warning "Your system doesn't have getusershell(). You can not"
820#   warning "use /etc/shells authentication with bftpd."
821#endif
822}
823
824
825
826
827/*
828This function searches through a text file for a matching
829username. If a match is found, the password in the
830text file is compared to the password passed in to
831the function. If the password matches, the function
832returns the fourth field (home directory). On failure,
833it returns NULL.
834-- Jesse
835*/
836char *check_file_password (char *my_filename, char *my_username,
837                           char *my_password)
838{
839    FILE *my_file;
840    int found_user = 0;
841    char user[32], password[32], group[32], home_dir[32];
842    char *my_home_dir = NULL;
843    int return_value;
844
845    my_file = fopen (my_filename, "r");
846    if (!my_file)
847        return NULL;
848
849    return_value =
850        fscanf (my_file, "%s %s %s %s", user, password, group, home_dir);
851    if (!strcmp (user, my_username))
852        found_user = 1;
853
854    while ((!found_user) && (return_value != EOF))
855    {
856        return_value =
857            fscanf (my_file, "%s %s %s %s", user, password, group, home_dir);
858        if (!strcmp (user, my_username))
859            found_user = 1;
860    }
861
862    fclose (my_file);
863    if (found_user)
864    {
865        /* check password */
866        if (!strcmp (password, "*"))
867        {
868        }
869        else if (strcmp (password, my_password))
870            return NULL;
871
872        my_home_dir = calloc (strlen (home_dir), sizeof (char));
873        if (!my_home_dir)
874            return NULL;
875        strcpy (my_home_dir, home_dir);
876    }
877
878    return my_home_dir;
879}
880