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 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 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>
| 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 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 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 $");
| 28__FBSDID("$FreeBSD: head/lib/libc/gen/pututxline.c 218846 2011-02-19 11:31:56Z 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{
| 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;
| 46 struct stat sb;
|
| 47 FILE *fp; 48 int fd;
|
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);
| 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;
| 57 errno = EFTYPE;
|
58 return (NULL); 59 } 60 61 fp = fdopen(fd, "r+"); 62 if (fp == NULL) { 63 _close(fd); 64 return (NULL); 65 }
| 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{
| 66 return (fp); 67} 68 69static int 70utx_active_add(const struct futx *fu) 71{
|
73 FILE *fp;
| |
74 struct futx fe;
| 72 struct futx fe;
|
| 73 FILE *fp;
|
75 off_t partial = -1;
| 74 off_t partial = -1;
|
| 75 int error, ret;
|
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)
| 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) {
| 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. */
| 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);
| 91 if (memcmp(fu->fu_id, fe.fu_id, sizeof(fe.fu_id)) == 92 0) { 93 ret = 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. */
| 94 goto exact; 95 } 96 if (fe.fu_type != DEAD_PROCESS) 97 break; 98 /* FALLTHROUGH */ 99 default: 100 /* Allow us to overwrite unused records. */
|
100 if (partial == -1) 101 partial = ftello(fp) - (off_t)sizeof fe;
| 101 if (partial == -1) { 102 partial = ftello(fp); 103 /* 104 * Distinguish errors from valid values so we 105 * don't overwrite good data by accident. 106 */ 107 if (partial != -1) 108 partial -= (off_t)sizeof(fe); 109 }
|
102 break; 103 } 104 }
| 110 break; 111 } 112 }
|
105
| 113
|
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)
| 114 /* 115 * No exact match found. Use the partial match. If no partial 116 * match was found, just append a new record. 117 */ 118 if (partial != -1)
|
111 fseeko(fp, partial, SEEK_SET);
| 119 ret = fseeko(fp, partial, SEEK_SET);
|
112exact:
| 120exact:
|
113 fwrite(fu, sizeof *fu, 1, fp);
| 121 if (ret == -1) 122 error = errno; 123 else if (fwrite(fu, sizeof(*fu), 1, fp) < 1) 124 error = errno; 125 else 126 error = 0;
|
114 fclose(fp);
| 127 fclose(fp);
|
115 return (0);
| 128 errno = error; 129 return (error == 0 ? 0 : 1);
|
116} 117 118static int 119utx_active_remove(struct futx *fu) 120{
| 130} 131 132static int 133utx_active_remove(struct futx *fu) 134{
|
121 FILE *fp;
| |
122 struct futx fe;
| 135 struct futx fe;
|
| 136 FILE *fp; 137 int error, ret;
|
123 124 /* 125 * Remove user login sessions, having the same ut_id. 126 */ 127 fp = futx_open(_PATH_UTX_ACTIVE); 128 if (fp == NULL)
| 138 139 /* 140 * Remove user login sessions, having the same ut_id. 141 */ 142 fp = futx_open(_PATH_UTX_ACTIVE); 143 if (fp == NULL)
|
129 return (1); 130 while (fread(&fe, sizeof fe, 1, fp) == 1) {
| 144 return (-1); 145 error = ESRCH; 146 ret = -1; 147 while (fread(&fe, sizeof(fe), 1, fp) == 1 && ret != 0)
|
131 switch (fe.fu_type) { 132 case USER_PROCESS: 133 case INIT_PROCESS: 134 case LOGIN_PROCESS:
| 148 switch (fe.fu_type) { 149 case USER_PROCESS: 150 case INIT_PROCESS: 151 case LOGIN_PROCESS:
|
135 if (memcmp(fu->fu_id, fe.fu_id, sizeof fe.fu_id) != 0)
| 152 if (memcmp(fu->fu_id, fe.fu_id, sizeof(fe.fu_id)) != 0)
|
136 continue; 137 138 /* Terminate session. */
| 153 continue; 154 155 /* Terminate session. */
|
139 fseeko(fp, -(off_t)sizeof fe, SEEK_CUR); 140 fwrite(fu, sizeof *fu, 1, fp); 141 fclose(fp); 142 return (0);
| 156 if (fseeko(fp, -(off_t)sizeof(fe), SEEK_CUR) == -1) 157 error = errno; 158 else if (fwrite(fu, sizeof(*fu), 1, fp) < 1) 159 error = errno; 160 else 161 ret = 0; 162
|
143 }
| 163 }
|
144 }
| |
145 146 fclose(fp);
| 164 165 fclose(fp);
|
147 errno = ESRCH; 148 return (1);
| 166 errno = error; 167 return (ret);
|
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{
| 168} 169 170static void 171utx_active_purge(void) 172{ 173 174 truncate(_PATH_UTX_ACTIVE, 0); 175} 176 177static int 178utx_lastlogin_add(const struct futx *fu) 179{
|
161 FILE *fp;
| |
162 struct futx fe;
| 180 struct futx fe;
|
| 181 FILE *fp; 182 int error, ret;
|
163
| 183
|
| 184 ret = 0; 185
|
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)
| 186 /* 187 * Write an entry to lastlogin. Overwrite the entry if the 188 * current user already has an entry. If not, append a new 189 * entry. 190 */ 191 fp = futx_open(_PATH_UTX_LASTLOGIN); 192 if (fp == NULL)
|
171 return (1);
| 193 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;
| 194 while (fread(&fe, sizeof fe, 1, fp) == 1) { 195 if (strncmp(fu->fu_user, fe.fu_user, sizeof fe.fu_user) != 0) 196 continue;
|
175
| 197
|
176 /* Found a previous lastlogin entry for this user. */
| 198 /* Found a previous lastlogin entry for this user. */
|
177 fseeko(fp, -(off_t)sizeof fe, SEEK_CUR);
| 199 ret = fseeko(fp, -(off_t)sizeof fe, SEEK_CUR);
|
178 break; 179 }
| 200 break; 201 }
|
180 fwrite(fu, sizeof *fu, 1, fp);
| 202 if (ret == -1) 203 error = errno; 204 else if (fwrite(fu, sizeof *fu, 1, fp) < 1) { 205 error = errno; 206 ret = -1; 207 }
|
181 fclose(fp);
| 208 fclose(fp);
|
182 return (0);
| 209 errno = error; 210 return (ret);
|
183} 184 185static void 186utx_lastlogin_upgrade(void) 187{
| 211} 212 213static void 214utx_lastlogin_upgrade(void) 215{
|
188 int fd;
| |
189 struct stat sb;
| 216 struct stat sb;
|
| 217 int fd;
|
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{
| 218 219 fd = _open(_PATH_UTX_LASTLOGIN, O_RDWR, 0644); 220 if (fd < 0) 221 return; 222 223 /* 224 * Truncate broken lastlogin files. In the future we should 225 * check for older versions of the file format here and try to 226 * upgrade it. 227 */ 228 if (_fstat(fd, &sb) != -1 && sb.st_size % sizeof(struct futx) != 0) 229 ftruncate(fd, 0); 230 _close(fd); 231} 232 233static int 234utx_log_add(const struct futx *fu) 235{
|
208 int fd; 209 uint16_t l;
| |
210 struct iovec vec[2];
| 236 struct iovec vec[2];
|
| 237 int error, fd; 238 uint16_t l;
|
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 */
| 239 240 /* 241 * Append an entry to the log file. We only need to append 242 * records to this file, so to conserve space, trim any trailing 243 * zero-bytes. Prepend a length field, indicating the length of 244 * the record, excluding the length field itself. 245 */
|
218 for (l = sizeof *fu; l > 0 && ((const char *)fu)[l - 1] == '\0'; l--);
| 246 for (l = sizeof(*fu); l > 0 && ((const char *)fu)[l - 1] == '\0'; l--) ;
|
219 vec[0].iov_base = &l;
| 247 vec[0].iov_base = &l;
|
220 vec[0].iov_len = sizeof l;
| 248 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)
| 249 vec[1].iov_base = __DECONST(void *, fu); 250 vec[1].iov_len = l; 251 l = htobe16(l); 252 253 fd = _open(_PATH_UTX_LOG, O_CREAT|O_WRONLY|O_APPEND, 0644); 254 if (fd < 0)
|
227 return (1); 228 _writev(fd, vec, 2);
| 255 return (-1); 256 if (_writev(fd, vec, 2) == -1) 257 error = errno; 258 else 259 error = 0;
|
229 _close(fd);
| 260 _close(fd);
|
230 return (0);
| 261 errno = error; 262 return (error == 0 ? 0 : 1);
|
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);
| 263} 264 265struct utmpx * 266pututxline(const struct utmpx *utmpx) 267{ 268 struct futx fu; 269 int bad = 0; 270 271 utx_to_futx(utmpx, &fu);
|
240
| 272
|
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: 249 break; 250 case USER_PROCESS: 251 bad |= utx_active_add(&fu); 252 bad |= utx_lastlogin_add(&fu); 253 break; 254#if 0 /* XXX: Are these records of any use to us? */ 255 case INIT_PROCESS: 256 case LOGIN_PROCESS: 257 bad |= utx_active_add(&fu); 258 break; 259#endif 260 case DEAD_PROCESS: 261 /* 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:
| 273 switch (fu.fu_type) { 274 case BOOT_TIME: 275 case SHUTDOWN_TIME: 276 utx_active_purge(); 277 utx_lastlogin_upgrade(); 278 break; 279 case OLD_TIME: 280 case NEW_TIME: 281 break; 282 case USER_PROCESS: 283 bad |= utx_active_add(&fu); 284 bad |= utx_lastlogin_add(&fu); 285 break; 286#if 0 /* XXX: Are these records of any use to us? */ 287 case INIT_PROCESS: 288 case LOGIN_PROCESS: 289 bad |= utx_active_add(&fu); 290 break; 291#endif 292 case DEAD_PROCESS: 293 /* 294 * In case writing a logout entry fails, never attempt 295 * to write it to utx.log. The logout entry's ut_id 296 * might be invalid. 297 */ 298 if (utx_active_remove(&fu) != 0) 299 return (NULL); 300 break; 301 default:
|
| 302 errno = EINVAL;
|
270 return (NULL); 271 } 272 273 bad |= utx_log_add(&fu); 274 return (bad ? NULL : futx_to_utx(&fu)); 275}
| 303 return (NULL); 304 } 305 306 bad |= utx_log_add(&fu); 307 return (bad ? NULL : futx_to_utx(&fu)); 308}
|