Deleted Added
sdiff udiff text old ( 215310 ) new ( 218846 )
full compact
1/*-
2 * Copyright (c) 2010 Ed Schouten <ed@FreeBSD.org>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright

--- 11 unchanged lines hidden (view full) ---

20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 */
26
27#include <sys/cdefs.h>
28__FBSDID("$FreeBSD: head/lib/libc/gen/pututxline.c 215310 2010-11-14 18:42:39Z ed $");
29
30#include "namespace.h"
31#include <sys/endian.h>
32#include <sys/stat.h>
33#include <sys/uio.h>
34#include <errno.h>
35#include <fcntl.h>
36#include <stdio.h>
37#include <string.h>
38#include <unistd.h>
39#include <utmpx.h>
40#include "utxdb.h"
41#include "un-namespace.h"
42
43static FILE *
44futx_open(const char *file)
45{
46 int fd;
47 FILE *fp;
48 struct stat sb;
49
50 fd = _open(file, O_CREAT|O_RDWR|O_EXLOCK, 0644);
51 if (fd < 0)
52 return (NULL);
53
54 /* Safety check: never use broken files. */
55 if (_fstat(fd, &sb) != -1 && sb.st_size % sizeof(struct futx) != 0) {
56 _close(fd);
57 errno = EINVAL;
58 return (NULL);
59 }
60
61 fp = fdopen(fd, "r+");
62 if (fp == NULL) {
63 _close(fd);
64 return (NULL);
65 }
66
67 return (fp);
68}
69
70static int
71utx_active_add(const struct futx *fu)
72{
73 FILE *fp;
74 struct futx fe;
75 off_t partial = -1;
76
77 /*
78 * Register user login sessions. Overwrite entries of sessions
79 * that have already been terminated.
80 */
81 fp = futx_open(_PATH_UTX_ACTIVE);
82 if (fp == NULL)
83 return (1);
84 while (fread(&fe, sizeof fe, 1, fp) == 1) {
85 switch (fe.fu_type) {
86 case USER_PROCESS:
87 case INIT_PROCESS:
88 case LOGIN_PROCESS:
89 case DEAD_PROCESS:
90 /* Overwrite when ut_id matches. */
91 if (memcmp(fu->fu_id, fe.fu_id, sizeof fe.fu_id) == 0) {
92 fseeko(fp, -(off_t)sizeof fe, SEEK_CUR);
93 goto exact;
94 }
95 if (fe.fu_type != DEAD_PROCESS)
96 break;
97 /* FALLTHROUGH */
98 default:
99 /* Allow us to overwrite unused records. */
100 if (partial == -1)
101 partial = ftello(fp) - (off_t)sizeof fe;
102 break;
103 }
104 }
105
106 /*
107 * No exact match found. Use the partial match. If no partial
108 * match was found, just append a new record.
109 */
110 if (partial != -1)
111 fseeko(fp, partial, SEEK_SET);
112exact:
113 fwrite(fu, sizeof *fu, 1, fp);
114 fclose(fp);
115 return (0);
116}
117
118static int
119utx_active_remove(struct futx *fu)
120{
121 FILE *fp;
122 struct futx fe;
123
124 /*
125 * Remove user login sessions, having the same ut_id.
126 */
127 fp = futx_open(_PATH_UTX_ACTIVE);
128 if (fp == NULL)
129 return (1);
130 while (fread(&fe, sizeof fe, 1, fp) == 1) {
131 switch (fe.fu_type) {
132 case USER_PROCESS:
133 case INIT_PROCESS:
134 case LOGIN_PROCESS:
135 if (memcmp(fu->fu_id, fe.fu_id, sizeof fe.fu_id) != 0)
136 continue;
137
138 /* Terminate session. */
139 fseeko(fp, -(off_t)sizeof fe, SEEK_CUR);
140 fwrite(fu, sizeof *fu, 1, fp);
141 fclose(fp);
142 return (0);
143 }
144 }
145
146 fclose(fp);
147 errno = ESRCH;
148 return (1);
149}
150
151static void
152utx_active_purge(void)
153{
154
155 truncate(_PATH_UTX_ACTIVE, 0);
156}
157
158static int
159utx_lastlogin_add(const struct futx *fu)
160{
161 FILE *fp;
162 struct futx fe;
163
164 /*
165 * Write an entry to lastlogin. Overwrite the entry if the
166 * current user already has an entry. If not, append a new
167 * entry.
168 */
169 fp = futx_open(_PATH_UTX_LASTLOGIN);
170 if (fp == NULL)
171 return (1);
172 while (fread(&fe, sizeof fe, 1, fp) == 1) {
173 if (strncmp(fu->fu_user, fe.fu_user, sizeof fe.fu_user) != 0)
174 continue;
175
176 /* Found a previous lastlogin entry for this user. */
177 fseeko(fp, -(off_t)sizeof fe, SEEK_CUR);
178 break;
179 }
180 fwrite(fu, sizeof *fu, 1, fp);
181 fclose(fp);
182 return (0);
183}
184
185static void
186utx_lastlogin_upgrade(void)
187{
188 int fd;
189 struct stat sb;
190
191 fd = _open(_PATH_UTX_LASTLOGIN, O_RDWR, 0644);
192 if (fd < 0)
193 return;
194
195 /*
196 * Truncate broken lastlogin files. In the future we should
197 * check for older versions of the file format here and try to
198 * upgrade it.
199 */
200 if (_fstat(fd, &sb) != -1 && sb.st_size % sizeof(struct futx) != 0)
201 ftruncate(fd, 0);
202 _close(fd);
203}
204
205static int
206utx_log_add(const struct futx *fu)
207{
208 int fd;
209 uint16_t l;
210 struct iovec vec[2];
211
212 /*
213 * Append an entry to the log file. We only need to append
214 * records to this file, so to conserve space, trim any trailing
215 * zero-bytes. Prepend a length field, indicating the length of
216 * the record, excluding the length field itself.
217 */
218 for (l = sizeof *fu; l > 0 && ((const char *)fu)[l - 1] == '\0'; l--);
219 vec[0].iov_base = &l;
220 vec[0].iov_len = sizeof l;
221 vec[1].iov_base = __DECONST(void *, fu);
222 vec[1].iov_len = l;
223 l = htobe16(l);
224
225 fd = _open(_PATH_UTX_LOG, O_CREAT|O_WRONLY|O_APPEND, 0644);
226 if (fd < 0)
227 return (1);
228 _writev(fd, vec, 2);
229 _close(fd);
230 return (0);
231}
232
233struct utmpx *
234pututxline(const struct utmpx *utmpx)
235{
236 struct futx fu;
237 int bad = 0;
238
239 utx_to_futx(utmpx, &fu);
240
241 switch (fu.fu_type) {
242 case BOOT_TIME:
243 case SHUTDOWN_TIME:
244 utx_active_purge();
245 utx_lastlogin_upgrade();
246 break;
247 case OLD_TIME:
248 case NEW_TIME:

--- 13 unchanged lines hidden (view full) ---

262 * In case writing a logout entry fails, never attempt
263 * to write it to utx.log. The logout entry's ut_id
264 * might be invalid.
265 */
266 if (utx_active_remove(&fu) != 0)
267 return (NULL);
268 break;
269 default:
270 return (NULL);
271 }
272
273 bad |= utx_log_add(&fu);
274 return (bad ? NULL : futx_to_utx(&fu));
275}