1 /*
2  * ProFTPD - FTP server daemon
3  * Copyright (c) 2006-2017 The ProFTPD Project team
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA.
18  *
19  * As a special exemption, The ProFTPD Project team and other respective
20  * copyright holders give permission to link this program with OpenSSL, and
21  * distribute the resulting executable, without including the source code for
22  * OpenSSL in the source distribution.
23  */
24 
25 /* Lastlog code */
26 
27 #include "conf.h"
28 
29 #ifdef PR_USE_LASTLOG
30 
log_lastlog(uid_t uid,const char * user_name,const char * tty,const pr_netaddr_t * remote_addr)31 int log_lastlog(uid_t uid, const char *user_name, const char *tty,
32     const pr_netaddr_t *remote_addr) {
33   struct lastlog ll;
34   struct stat st;
35   int fd, res;
36   char path[PR_TUNABLE_PATH_MAX] = {'\0'};
37 
38   memset(&ll, 0, sizeof(ll));
39   sstrncpy(ll.ll_line, tty, sizeof(ll.ll_line));
40   sstrncpy(ll.ll_host, pr_netaddr_get_ipstr(remote_addr),
41     sizeof(ll.ll_host));
42   time((time_t *) &ll.ll_time);
43 
44   /* Determine whether lastlog is a file or a directory, and act
45    * appropriately.
46    */
47   if (stat(PR_LASTLOG_PATH, &st) < 0) {
48     int xerrno = errno;
49 
50     pr_log_pri(PR_LOG_NOTICE, "unable to stat '%s': %s",
51       PR_LASTLOG_PATH, strerror(xerrno));
52 
53     errno = xerrno;
54     return -1;
55   }
56 
57   if (S_ISDIR(st.st_mode)) {
58     memset(path, '\0', sizeof(path));
59     pr_snprintf(path, sizeof(path), "%s/%s", PR_LASTLOG_PATH, user_name);
60     path[sizeof(path)-1] = '\0';
61 
62     fd = open(path, O_RDWR|O_CREAT, 0600);
63     if (fd < 0) {
64       int xerrno = errno;
65 
66       pr_log_pri(PR_LOG_NOTICE, "unable to open '%s': %s", path,
67         strerror(xerrno));
68 
69       errno = xerrno;
70       return -1;
71     }
72 
73   } else if (S_ISREG(st.st_mode)) {
74     off_t offset;
75 
76     sstrncpy(path, PR_LASTLOG_PATH, sizeof(path));
77 
78     fd = open(path, O_RDWR|O_CREAT, 0600);
79     if (fd < 0) {
80       int xerrno = errno;
81 
82       pr_log_pri(PR_LOG_NOTICE, "unable to open '%s': %s", path,
83         strerror(xerrno));
84 
85       errno = xerrno;
86       return -1;
87     }
88 
89     /* Seek to the offset in the lastlog file for this UID. */
90     offset = (off_t) ((long) uid * sizeof(ll));
91 
92     if (lseek(fd, offset, SEEK_SET) != offset) {
93       int xerrno = errno;
94 
95       pr_log_pri(PR_LOG_NOTICE, "unable to seek to correct lastlog location "
96         "in '%s': %s", path, strerror(xerrno));
97       (void) close(fd);
98 
99       errno = xerrno;
100       return -1;
101     }
102 
103   } else {
104     pr_log_pri(PR_LOG_NOTICE, "%s is not a file or directory",
105       PR_LASTLOG_PATH);
106     errno = EINVAL;
107     return -1;
108   }
109 
110   res = write(fd, &ll, sizeof(ll));
111   if (res != sizeof(ll)) {
112     int xerrno = errno;
113 
114     pr_log_pri(PR_LOG_WARNING, "error updating lastlog: %s",
115       strerror(xerrno));
116     (void) close(fd);
117 
118     errno = xerrno;
119     return -1;
120   }
121 
122   (void) close(fd);
123   return 0;
124 }
125 
126 #endif /* PR_USE_LASTLOG */
127