OpenCoverage

loginrec.c

Absolute File Name:/home/opencoverage/opencoverage/guest-scripts/openssh/src/loginrec.c
Source codeSwitch to Preprocessed file
LineSourceCount
1/*-
2 * Copyright (c) 2000 Andre Lucas. All rights reserved.-
3 * Portions copyright (c) 1998 Todd C. Miller-
4 * Portions copyright (c) 1996 Jason Downs-
5 * Portions copyright (c) 1996 Theo de Raadt-
6 *-
7 * Redistribution and use in source and binary forms, with or without-
8 * modification, are permitted provided that the following conditions-
9 * are met:-
10 * 1. Redistributions of source code must retain the above copyright-
11 * notice, this list of conditions and the following disclaimer.-
12 * 2. Redistributions in binary form must reproduce the above copyright-
13 * notice, this list of conditions and the following disclaimer in the-
14 * documentation and/or other materials provided with the distribution.-
15 *-
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR-
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES-
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.-
19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,-
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT-
21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,-
22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY-
23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT-
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF-
25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.-
26 */-
27-
28/*-
29 * The btmp logging code is derived from login.c from util-linux and is under-
30 * the the following license:-
31 *-
32 * Copyright (c) 1980, 1987, 1988 The Regents of the University of California.-
33 * All rights reserved.-
34 *-
35 * Redistribution and use in source and binary forms are permitted-
36 * provided that the above copyright notice and this paragraph are-
37 * duplicated in all such forms and that any documentation,-
38 * advertising materials, and other materials related to such-
39 * distribution and use acknowledge that the software was developed-
40 * by the University of California, Berkeley. The name of the-
41 * University may not be used to endorse or promote products derived-
42 * from this software without specific prior written permission.-
43 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR-
44 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED-
45 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.-
46 */-
47-
48-
49/**-
50 ** loginrec.c: platform-independent login recording and lastlog retrieval-
51 **/-
52-
53/*-
54 * The new login code explained-
55 * ============================-
56 *-
57 * This code attempts to provide a common interface to login recording-
58 * (utmp and friends) and last login time retrieval.-
59 *-
60 * Its primary means of achieving this is to use 'struct logininfo', a-
61 * union of all the useful fields in the various different types of-
62 * system login record structures one finds on UNIX variants.-
63 *-
64 * We depend on autoconf to define which recording methods are to be-
65 * used, and which fields are contained in the relevant data structures-
66 * on the local system. Many C preprocessor symbols affect which code-
67 * gets compiled here.-
68 *-
69 * The code is designed to make it easy to modify a particular-
70 * recording method, without affecting other methods nor requiring so-
71 * many nested conditional compilation blocks as were commonplace in-
72 * the old code.-
73 *-
74 * For login recording, we try to use the local system's libraries as-
75 * these are clearly most likely to work correctly. For utmp systems-
76 * this usually means login() and logout() or setutent() etc., probably-
77 * in libutil, along with logwtmp() etc. On these systems, we fall back-
78 * to writing the files directly if we have to, though this method-
79 * requires very thorough testing so we do not corrupt local auditing-
80 * information. These files and their access methods are very system-
81 * specific indeed.-
82 *-
83 * For utmpx systems, the corresponding library functions are-
84 * setutxent() etc. To the author's knowledge, all utmpx systems have-
85 * these library functions and so no direct write is attempted. If such-
86 * a system exists and needs support, direct analogues of the [uw]tmp-
87 * code should suffice.-
88 *-
89 * Retrieving the time of last login ('lastlog') is in some ways even-
90 * more problemmatic than login recording. Some systems provide a-
91 * simple table of all users which we seek based on uid and retrieve a-
92 * relatively standard structure. Others record the same information in-
93 * a directory with a separate file, and others don't record the-
94 * information separately at all. For systems in the latter category,-
95 * we look backwards in the wtmp or wtmpx file for the last login entry-
96 * for our user. Naturally this is slower and on busy systems could-
97 * incur a significant performance penalty.-
98 *-
99 * Calling the new code-
100 * ---------------------
101 *-
102 * In OpenSSH all login recording and retrieval is performed in-
103 * login.c. Here you'll find working examples. Also, in the logintest.c-
104 * program there are more examples.-
105 *-
106 * Internal handler calling method-
107 * --------------------------------
108 *-
109 * When a call is made to login_login() or login_logout(), both-
110 * routines set a struct logininfo flag defining which action (log in,-
111 * or log out) is to be taken. They both then call login_write(), which-
112 * calls whichever of the many structure-specific handlers autoconf-
113 * selects for the local system.-
114 *-
115 * The handlers themselves handle system data structure specifics. Both-
116 * struct utmp and struct utmpx have utility functions (see-
117 * construct_utmp*()) to try to make it simpler to add extra systems-
118 * that introduce new features to either structure.-
119 *-
120 * While it may seem terribly wasteful to replicate so much similar-
121 * code for each method, experience has shown that maintaining code to-
122 * write both struct utmp and utmpx in one function, whilst maintaining-
123 * support for all systems whether they have library support or not, is-
124 * a difficult and time-consuming task.-
125 *-
126 * Lastlog support proceeds similarly. Functions login_get_lastlog()-
127 * (and its OpenSSH-tuned friend login_get_lastlog_time()) call-
128 * getlast_entry(), which tries one of three methods to find the last-
129 * login time. It uses local system lastlog support if it can,-
130 * otherwise it tries wtmp or wtmpx before giving up and returning 0,-
131 * meaning "tilt".-
132 *-
133 * Maintenance-
134 * ------------
135 *-
136 * In many cases it's possible to tweak autoconf to select the correct-
137 * methods for a particular platform, either by improving the detection-
138 * code (best), or by presetting DISABLE_<method> or CONF_<method>_FILE-
139 * symbols for the platform.-
140 *-
141 * Use logintest to check which symbols are defined before modifying-
142 * configure.ac and loginrec.c. (You have to build logintest yourself-
143 * with 'make logintest' as it's not built by default.)-
144 *-
145 * Otherwise, patches to the specific method(s) are very helpful!-
146 */-
147-
148#include "includes.h"-
149-
150#include <sys/types.h>-
151#include <sys/stat.h>-
152#include <sys/socket.h>-
153#ifdef HAVE_SYS_TIME_H-
154# include <sys/time.h>-
155#endif-
156-
157#include <netinet/in.h>-
158-
159#include <errno.h>-
160#include <fcntl.h>-
161#ifdef HAVE_PATHS_H-
162# include <paths.h>-
163#endif-
164#include <pwd.h>-
165#include <stdarg.h>-
166#include <string.h>-
167#include <time.h>-
168#include <unistd.h>-
169-
170#include "xmalloc.h"-
171#include "sshkey.h"-
172#include "hostfile.h"-
173#include "ssh.h"-
174#include "loginrec.h"-
175#include "log.h"-
176#include "atomicio.h"-
177#include "packet.h"-
178#include "canohost.h"-
179#include "auth.h"-
180#include "sshbuf.h"-
181#include "ssherr.h"-
182-
183#ifdef HAVE_UTIL_H-
184# include <util.h>-
185#endif-
186-
187/**-
188 ** prototypes for helper functions in this file-
189 **/-
190-
191#if HAVE_UTMP_H-
192void set_utmp_time(struct logininfo *li, struct utmp *ut);-
193void construct_utmp(struct logininfo *li, struct utmp *ut);-
194#endif-
195-
196#ifdef HAVE_UTMPX_H-
197void set_utmpx_time(struct logininfo *li, struct utmpx *ut);-
198void construct_utmpx(struct logininfo *li, struct utmpx *ut);-
199#endif-
200-
201int utmp_write_entry(struct logininfo *li);-
202int utmpx_write_entry(struct logininfo *li);-
203int wtmp_write_entry(struct logininfo *li);-
204int wtmpx_write_entry(struct logininfo *li);-
205int lastlog_write_entry(struct logininfo *li);-
206int syslogin_write_entry(struct logininfo *li);-
207-
208int getlast_entry(struct logininfo *li);-
209int lastlog_get_entry(struct logininfo *li);-
210int utmpx_get_entry(struct logininfo *li);-
211int wtmp_get_entry(struct logininfo *li);-
212int wtmpx_get_entry(struct logininfo *li);-
213-
214extern struct sshbuf *loginmsg;-
215-
216/* pick the shortest string */-
217#define MIN_SIZEOF(s1,s2) (sizeof(s1) < sizeof(s2) ? sizeof(s1) : sizeof(s2))-
218-
219/**-
220 ** platform-independent login functions-
221 **/-
222-
223/*-
224 * login_login(struct logininfo *) - Record a login-
225 *-
226 * Call with a pointer to a struct logininfo initialised with-
227 * login_init_entry() or login_alloc_entry()-
228 *-
229 * Returns:-
230 * >0 if successful-
231 * 0 on failure (will use OpenSSH's logging facilities for diagnostics)-
232 */-
233int-
234login_login(struct logininfo *li)-
235{-
236 li->type = LTYPE_LOGIN;-
237 return (login_write(li));
never executed: return (login_write(li));
0
238}-
239-
240-
241/*-
242 * login_logout(struct logininfo *) - Record a logout-
243 *-
244 * Call as with login_login()-
245 *-
246 * Returns:-
247 * >0 if successful-
248 * 0 on failure (will use OpenSSH's logging facilities for diagnostics)-
249 */-
250int-
251login_logout(struct logininfo *li)-
252{-
253 li->type = LTYPE_LOGOUT;-
254 return (login_write(li));
never executed: return (login_write(li));
0
255}-
256-
257/*-
258 * login_get_lastlog_time(int) - Retrieve the last login time-
259 *-
260 * Retrieve the last login time for the given uid. Will try to use the-
261 * system lastlog facilities if they are available, but will fall back-
262 * to looking in wtmp/wtmpx if necessary-
263 *-
264 * Returns:-
265 * 0 on failure, or if user has never logged in-
266 * Time in seconds from the epoch if successful-
267 *-
268 * Useful preprocessor symbols:-
269 * DISABLE_LASTLOG: If set, *never* even try to retrieve lastlog-
270 * info-
271 * USE_LASTLOG: If set, indicates the presence of system lastlog-
272 * facilities. If this and DISABLE_LASTLOG are not set,-
273 * try to retrieve lastlog information from wtmp/wtmpx.-
274 */-
275unsigned int-
276login_get_lastlog_time(const uid_t uid)-
277{-
278 struct logininfo li;-
279-
280 if (login_get_lastlog(&li, uid))
login_get_lastlog(&li, uid)Description
TRUEnever evaluated
FALSEnever evaluated
0
281 return (li.tv_sec);
never executed: return (li.tv_sec);
0
282 else-
283 return (0);
never executed: return (0);
0
284}-
285-
286/*-
287 * login_get_lastlog(struct logininfo *, int) - Retrieve a lastlog entry-
288 *-
289 * Retrieve a logininfo structure populated (only partially) with-
290 * information from the system lastlog data, or from wtmp/wtmpx if no-
291 * system lastlog information exists.-
292 *-
293 * Note this routine must be given a pre-allocated logininfo.-
294 *-
295 * Returns:-
296 * >0: A pointer to your struct logininfo if successful-
297 * 0 on failure (will use OpenSSH's logging facilities for diagnostics)-
298 */-
299struct logininfo *-
300login_get_lastlog(struct logininfo *li, const uid_t uid)-
301{-
302 struct passwd *pw;-
303-
304 memset(li, '\0', sizeof(*li));-
305 li->uid = uid;-
306-
307 /*-
308 * If we don't have a 'real' lastlog, we need the username to-
309 * reliably search wtmp(x) for the last login (see-
310 * wtmp_get_entry().)-
311 */-
312 pw = getpwuid(uid);-
313 if (pw == NULL)
pw == ((void *)0)Description
TRUEnever evaluated
FALSEnever evaluated
0
314 fatal("%s: Cannot find account for uid %ld", __func__,
never executed: fatal("%s: Cannot find account for uid %ld", __func__, (long)uid);
0
315 (long)uid);
never executed: fatal("%s: Cannot find account for uid %ld", __func__, (long)uid);
0
316-
317 if (strlcpy(li->username, pw->pw_name, sizeof(li->username)) >=
strlcpy(li->us...(li->username)Description
TRUEnever evaluated
FALSEnever evaluated
0
318 sizeof(li->username)) {
strlcpy(li->us...(li->username)Description
TRUEnever evaluated
FALSEnever evaluated
0
319 error("%s: username too long (%lu > max %lu)", __func__,-
320 (unsigned long)strlen(pw->pw_name),-
321 (unsigned long)sizeof(li->username) - 1);-
322 return NULL;
never executed: return ((void *)0) ;
0
323 }-
324-
325 if (getlast_entry(li))
getlast_entry(li)Description
TRUEnever evaluated
FALSEnever evaluated
0
326 return (li);
never executed: return (li);
0
327 else-
328 return (NULL);
never executed: return ( ((void *)0) );
0
329}-
330-
331/*-
332 * login_alloc_entry(int, char*, char*, char*) - Allocate and initialise-
333 * a logininfo structure-
334 *-
335 * This function creates a new struct logininfo, a data structure-
336 * meant to carry the information required to portably record login info.-
337 *-
338 * Returns a pointer to a newly created struct logininfo. If memory-
339 * allocation fails, the program halts.-
340 */-
341struct-
342logininfo *login_alloc_entry(pid_t pid, const char *username,-
343 const char *hostname, const char *line)-
344{-
345 struct logininfo *newli;-
346-
347 newli = xmalloc(sizeof(*newli));-
348 login_init_entry(newli, pid, username, hostname, line);-
349 return (newli);
never executed: return (newli);
0
350}-
351-
352-
353/* login_free_entry(struct logininfo *) - free struct memory */-
354void-
355login_free_entry(struct logininfo *li)-
356{-
357 free(li);-
358}
never executed: end of block
0
359-
360-
361/* login_init_entry(struct logininfo *, int, char*, char*, char*)-
362 * - initialise a struct logininfo-
363 *-
364 * Populates a new struct logininfo, a data structure meant to carry-
365 * the information required to portably record login info.-
366 *-
367 * Returns: 1-
368 */-
369int-
370login_init_entry(struct logininfo *li, pid_t pid, const char *username,-
371 const char *hostname, const char *line)-
372{-
373 struct passwd *pw;-
374-
375 memset(li, 0, sizeof(*li));-
376-
377 li->pid = pid;-
378-
379 /* set the line information */-
380 if (line)
lineDescription
TRUEnever evaluated
FALSEnever evaluated
0
381 line_fullname(li->line, line, sizeof(li->line));
never executed: line_fullname(li->line, line, sizeof(li->line));
0
382-
383 if (username) {
usernameDescription
TRUEnever evaluated
FALSEnever evaluated
0
384 strlcpy(li->username, username, sizeof(li->username));-
385 pw = getpwnam(li->username);-
386 if (pw == NULL) {
pw == ((void *)0)Description
TRUEnever evaluated
FALSEnever evaluated
0
387 fatal("%s: Cannot find user \"%s\"", __func__,-
388 li->username);-
389 }
never executed: end of block
0
390 li->uid = pw->pw_uid;-
391 }
never executed: end of block
0
392-
393 if (hostname)
hostnameDescription
TRUEnever evaluated
FALSEnever evaluated
0
394 strlcpy(li->hostname, hostname, sizeof(li->hostname));
never executed: strlcpy(li->hostname, hostname, sizeof(li->hostname));
0
395-
396 return (1);
never executed: return (1);
0
397}-
398-
399/*-
400 * login_set_current_time(struct logininfo *) - set the current time-
401 *-
402 * Set the current time in a logininfo structure. This function is-
403 * meant to eliminate the need to deal with system dependencies for-
404 * time handling.-
405 */-
406void-
407login_set_current_time(struct logininfo *li)-
408{-
409 struct timeval tv;-
410-
411 gettimeofday(&tv, NULL);-
412-
413 li->tv_sec = tv.tv_sec;-
414 li->tv_usec = tv.tv_usec;-
415}
never executed: end of block
0
416-
417/* copy a sockaddr_* into our logininfo */-
418void-
419login_set_addr(struct logininfo *li, const struct sockaddr *sa,-
420 const unsigned int sa_size)-
421{-
422 unsigned int bufsize = sa_size;-
423-
424 /* make sure we don't overrun our union */-
425 if (sizeof(li->hostaddr) < sa_size)
sizeof(li->hostaddr) < sa_sizeDescription
TRUEnever evaluated
FALSEnever evaluated
0
426 bufsize = sizeof(li->hostaddr);
never executed: bufsize = sizeof(li->hostaddr);
0
427-
428 memcpy(&li->hostaddr.sa, sa, bufsize);-
429}
never executed: end of block
0
430-
431-
432/**-
433 ** login_write: Call low-level recording functions based on autoconf-
434 ** results-
435 **/-
436int-
437login_write(struct logininfo *li)-
438{-
439#ifndef HAVE_CYGWIN-
440 if (geteuid() != 0) {
geteuid() != 0Description
TRUEnever evaluated
FALSEnever evaluated
0
441 logit("Attempt to write login records by non-root user (aborting)");-
442 return (1);
never executed: return (1);
0
443 }-
444#endif-
445-
446 /* set the timestamp */-
447 login_set_current_time(li);-
448#ifdef USE_LOGIN-
449 syslogin_write_entry(li);-
450#endif-
451#ifdef USE_LASTLOG-
452 if (li->type == LTYPE_LOGIN)
li->type == 7Description
TRUEnever evaluated
FALSEnever evaluated
0
453 lastlog_write_entry(li);
never executed: lastlog_write_entry(li);
0
454#endif-
455#ifdef USE_UTMP-
456 utmp_write_entry(li);-
457#endif-
458#ifdef USE_WTMP-
459 wtmp_write_entry(li);-
460#endif-
461#ifdef USE_UTMPX-
462 utmpx_write_entry(li);-
463#endif-
464#ifdef USE_WTMPX-
465 wtmpx_write_entry(li);-
466#endif-
467#ifdef CUSTOM_SYS_AUTH_RECORD_LOGIN-
468 if (li->type == LTYPE_LOGIN &&-
469 !sys_auth_record_login(li->username,li->hostname,li->line,-
470 &loginmsg))-
471 logit("Writing login record failed for %s", li->username);-
472#endif-
473#ifdef SSH_AUDIT_EVENTS-
474 if (li->type == LTYPE_LOGIN)-
475 audit_session_open(li);-
476 else if (li->type == LTYPE_LOGOUT)-
477 audit_session_close(li);-
478#endif-
479 return (0);
never executed: return (0);
0
480}-
481-
482#ifdef LOGIN_NEEDS_UTMPX-
483int-
484login_utmp_only(struct logininfo *li)-
485{-
486 li->type = LTYPE_LOGIN;-
487 login_set_current_time(li);-
488# ifdef USE_UTMP-
489 utmp_write_entry(li);-
490# endif-
491# ifdef USE_WTMP-
492 wtmp_write_entry(li);-
493# endif-
494# ifdef USE_UTMPX-
495 utmpx_write_entry(li);-
496# endif-
497# ifdef USE_WTMPX-
498 wtmpx_write_entry(li);-
499# endif-
500 return (0);-
501}-
502#endif-
503-
504/**-
505 ** getlast_entry: Call low-level functions to retrieve the last login-
506 ** time.-
507 **/-
508-
509/* take the uid in li and return the last login time */-
510int-
511getlast_entry(struct logininfo *li)-
512{-
513#ifdef USE_LASTLOG-
514 return(lastlog_get_entry(li));
never executed: return(lastlog_get_entry(li));
0
515#else /* !USE_LASTLOG */-
516#if defined(USE_UTMPX) && defined(HAVE_SETUTXDB) && \-
517 defined(UTXDB_LASTLOGIN) && defined(HAVE_GETUTXUSER)-
518 return (utmpx_get_entry(li));-
519#endif-
520-
521#if defined(DISABLE_LASTLOG)-
522 /* On some systems we shouldn't even try to obtain last login-
523 * time, e.g. AIX */-
524 return (0);-
525# elif defined(USE_WTMP) && \-
526 (defined(HAVE_TIME_IN_UTMP) || defined(HAVE_TV_IN_UTMP))-
527 /* retrieve last login time from utmp */-
528 return (wtmp_get_entry(li));-
529# elif defined(USE_WTMPX) && \-
530 (defined(HAVE_TIME_IN_UTMPX) || defined(HAVE_TV_IN_UTMPX))-
531 /* If wtmp isn't available, try wtmpx */-
532 return (wtmpx_get_entry(li));-
533# else-
534 /* Give up: No means of retrieving last login time */-
535 return (0);-
536# endif /* DISABLE_LASTLOG */-
537#endif /* USE_LASTLOG */-
538}-
539-
540-
541-
542/*-
543 * 'line' string utility functions-
544 *-
545 * These functions process the 'line' string into one of three forms:-
546 *-
547 * 1. The full filename (including '/dev')-
548 * 2. The stripped name (excluding '/dev')-
549 * 3. The abbreviated name (e.g. /dev/ttyp00 -> yp00-
550 * /dev/pts/1 -> ts/1 )-
551 *-
552 * Form 3 is used on some systems to identify a .tmp.? entry when-
553 * attempting to remove it. Typically both addition and removal is-
554 * performed by one application - say, sshd - so as long as the choice-
555 * uniquely identifies a terminal it's ok.-
556 */-
557-
558-
559/*-
560 * line_fullname(): add the leading '/dev/' if it doesn't exist make-
561 * sure dst has enough space, if not just copy src (ugh)-
562 */-
563char *-
564line_fullname(char *dst, const char *src, u_int dstsize)-
565{-
566 memset(dst, '\0', dstsize);-
567 if ((strncmp(src, "/dev/", 5) == 0) || (dstsize < (strlen(src) + 5)))
never executed: __result = (((const unsigned char *) (const char *) ( src ))[3] - __s2[3]);
never executed: end of block
never executed: end of block
never executed: __result = (((const unsigned char *) (const char *) ( "/dev/" ))[3] - __s2[3]);
never executed: end of block
never executed: end of block
( (__extension... , 5 ))) == 0)Description
TRUEnever evaluated
FALSEnever evaluated
__builtin_constant_p ( 5 )Description
TRUEnever evaluated
FALSEnever evaluated
__builtin_constant_p ( src )Description
TRUEnever evaluated
FALSEnever evaluated
strlen ( src )...size_t) ( 5 ))Description
TRUEnever evaluated
FALSEnever evaluated
__builtin_cons..._p ( "/dev/" )Description
TRUEnever evaluated
FALSEnever evaluated
strlen ( "/dev...size_t) ( 5 ))Description
TRUEnever evaluated
FALSEnever evaluated
__s1_len > 0Description
TRUEnever evaluated
FALSEnever evaluated
__result == 0Description
TRUEnever evaluated
FALSEnever evaluated
__s1_len > 1Description
TRUEnever evaluated
FALSEnever evaluated
__result == 0Description
TRUEnever evaluated
FALSEnever evaluated
__s1_len > 2Description
TRUEnever evaluated
FALSEnever evaluated
__result == 0Description
TRUEnever evaluated
FALSEnever evaluated
__s2_len > 0Description
TRUEnever evaluated
FALSEnever evaluated
__result == 0Description
TRUEnever evaluated
FALSEnever evaluated
__s2_len > 1Description
TRUEnever evaluated
FALSEnever evaluated
__result == 0Description
TRUEnever evaluated
FALSEnever evaluated
__s2_len > 2Description
TRUEnever evaluated
FALSEnever evaluated
__result == 0Description
TRUEnever evaluated
FALSEnever evaluated
(dstsize < (strlen(src) + 5))Description
TRUEnever evaluated
FALSEnever evaluated
0
568 strlcpy(dst, src, dstsize);
never executed: strlcpy(dst, src, dstsize);
0
569 else {-
570 strlcpy(dst, "/dev/", dstsize);-
571 strlcat(dst, src, dstsize);-
572 }
never executed: end of block
0
573 return (dst);
never executed: return (dst);
0
574}-
575-
576/* line_stripname(): strip the leading '/dev' if it exists, return dst */-
577char *-
578line_stripname(char *dst, const char *src, int dstsize)-
579{-
580 memset(dst, '\0', dstsize);-
581 if (strncmp(src, "/dev/", 5) == 0)
never executed: __result = (((const unsigned char *) (const char *) ( src ))[3] - __s2[3]);
never executed: end of block
never executed: end of block
never executed: __result = (((const unsigned char *) (const char *) ( "/dev/" ))[3] - __s2[3]);
never executed: end of block
never executed: end of block
(__extension__..." , 5 ))) == 0Description
TRUEnever evaluated
FALSEnever evaluated
__builtin_constant_p ( 5 )Description
TRUEnever evaluated
FALSEnever evaluated
__builtin_constant_p ( src )Description
TRUEnever evaluated
FALSEnever evaluated
strlen ( src )...size_t) ( 5 ))Description
TRUEnever evaluated
FALSEnever evaluated
__builtin_cons..._p ( "/dev/" )Description
TRUEnever evaluated
FALSEnever evaluated
strlen ( "/dev...size_t) ( 5 ))Description
TRUEnever evaluated
FALSEnever evaluated
__s1_len > 0Description
TRUEnever evaluated
FALSEnever evaluated
__result == 0Description
TRUEnever evaluated
FALSEnever evaluated
__s1_len > 1Description
TRUEnever evaluated
FALSEnever evaluated
__result == 0Description
TRUEnever evaluated
FALSEnever evaluated
__s1_len > 2Description
TRUEnever evaluated
FALSEnever evaluated
__result == 0Description
TRUEnever evaluated
FALSEnever evaluated
__s2_len > 0Description
TRUEnever evaluated
FALSEnever evaluated
__result == 0Description
TRUEnever evaluated
FALSEnever evaluated
__s2_len > 1Description
TRUEnever evaluated
FALSEnever evaluated
__result == 0Description
TRUEnever evaluated
FALSEnever evaluated
__s2_len > 2Description
TRUEnever evaluated
FALSEnever evaluated
__result == 0Description
TRUEnever evaluated
FALSEnever evaluated
0
582 strlcpy(dst, src + 5, dstsize);
never executed: strlcpy(dst, src + 5, dstsize);
0
583 else-
584 strlcpy(dst, src, dstsize);
never executed: strlcpy(dst, src, dstsize);
0
585 return (dst);
never executed: return (dst);
0
586}-
587-
588/*-
589 * line_abbrevname(): Return the abbreviated (usually four-character)-
590 * form of the line (Just use the last <dstsize> characters of the-
591 * full name.)-
592 *-
593 * NOTE: use strncpy because we do NOT necessarily want zero-
594 * termination-
595 */-
596char *-
597line_abbrevname(char *dst, const char *src, int dstsize)-
598{-
599 size_t len;-
600-
601 memset(dst, '\0', dstsize);-
602-
603 /* Always skip prefix if present */-
604 if (strncmp(src, "/dev/", 5) == 0)
never executed: __result = (((const unsigned char *) (const char *) ( src ))[3] - __s2[3]);
never executed: end of block
never executed: end of block
never executed: __result = (((const unsigned char *) (const char *) ( "/dev/" ))[3] - __s2[3]);
never executed: end of block
never executed: end of block
(__extension__..." , 5 ))) == 0Description
TRUEnever evaluated
FALSEnever evaluated
__builtin_constant_p ( 5 )Description
TRUEnever evaluated
FALSEnever evaluated
__builtin_constant_p ( src )Description
TRUEnever evaluated
FALSEnever evaluated
strlen ( src )...size_t) ( 5 ))Description
TRUEnever evaluated
FALSEnever evaluated
__builtin_cons..._p ( "/dev/" )Description
TRUEnever evaluated
FALSEnever evaluated
strlen ( "/dev...size_t) ( 5 ))Description
TRUEnever evaluated
FALSEnever evaluated
__s1_len > 0Description
TRUEnever evaluated
FALSEnever evaluated
__result == 0Description
TRUEnever evaluated
FALSEnever evaluated
__s1_len > 1Description
TRUEnever evaluated
FALSEnever evaluated
__result == 0Description
TRUEnever evaluated
FALSEnever evaluated
__s1_len > 2Description
TRUEnever evaluated
FALSEnever evaluated
__result == 0Description
TRUEnever evaluated
FALSEnever evaluated
__s2_len > 0Description
TRUEnever evaluated
FALSEnever evaluated
__result == 0Description
TRUEnever evaluated
FALSEnever evaluated
__s2_len > 1Description
TRUEnever evaluated
FALSEnever evaluated
__result == 0Description
TRUEnever evaluated
FALSEnever evaluated
__s2_len > 2Description
TRUEnever evaluated
FALSEnever evaluated
__result == 0Description
TRUEnever evaluated
FALSEnever evaluated
0
605 src += 5;
never executed: src += 5;
0
606-
607#ifdef WITH_ABBREV_NO_TTY-
608 if (strncmp(src, "tty", 3) == 0)-
609 src += 3;-
610#endif-
611-
612 len = strlen(src);-
613-
614 if (len > 0) {
len > 0Description
TRUEnever evaluated
FALSEnever evaluated
0
615 if (((int)len - dstsize) > 0)
((int)len - dstsize) > 0Description
TRUEnever evaluated
FALSEnever evaluated
0
616 src += ((int)len - dstsize);
never executed: src += ((int)len - dstsize);
0
617-
618 /* note: _don't_ change this to strlcpy */-
619 strncpy(dst, src, (size_t)dstsize);-
620 }
never executed: end of block
0
621-
622 return (dst);
never executed: return (dst);
0
623}-
624-
625/**-
626 ** utmp utility functions-
627 **-
628 ** These functions manipulate struct utmp, taking system differences-
629 ** into account.-
630 **/-
631-
632#if defined(USE_UTMP) || defined (USE_WTMP) || defined (USE_LOGIN)-
633-
634/* build the utmp structure */-
635void-
636set_utmp_time(struct logininfo *li, struct utmp *ut)-
637{-
638# if defined(HAVE_TV_IN_UTMP)-
639 ut->ut_tv.tv_sec = li->tv_sec;-
640 ut->ut_tv.tv_usec = li->tv_usec;-
641# elif defined(HAVE_TIME_IN_UTMP)-
642 ut->ut_time = li->tv_sec;-
643# endif-
644}
never executed: end of block
0
645-
646void-
647construct_utmp(struct logininfo *li,-
648 struct utmp *ut)-
649{-
650# ifdef HAVE_ADDR_V6_IN_UTMP-
651 struct sockaddr_in6 *sa6;-
652# endif-
653-
654 memset(ut, '\0', sizeof(*ut));-
655-
656 /* First fill out fields used for both logins and logouts */-
657-
658# ifdef HAVE_ID_IN_UTMP-
659 line_abbrevname(ut->ut_id, li->line, sizeof(ut->ut_id));-
660# endif-
661-
662# ifdef HAVE_TYPE_IN_UTMP-
663 /* This is done here to keep utmp constants out of struct logininfo */-
664 switch (li->type) {-
665 case LTYPE_LOGIN:
never executed: case 7:
0
666 ut->ut_type = USER_PROCESS;-
667 break;
never executed: break;
0
668 case LTYPE_LOGOUT:
never executed: case 8:
0
669 ut->ut_type = DEAD_PROCESS;-
670 break;
never executed: break;
0
671 }-
672# endif-
673 set_utmp_time(li, ut);-
674-
675 line_stripname(ut->ut_line, li->line, sizeof(ut->ut_line));-
676-
677# ifdef HAVE_PID_IN_UTMP-
678 ut->ut_pid = li->pid;-
679# endif-
680-
681 /* If we're logging out, leave all other fields blank */-
682 if (li->type == LTYPE_LOGOUT)
li->type == 8Description
TRUEnever evaluated
FALSEnever evaluated
0
683 return;
never executed: return;
0
684-
685 /*-
686 * These fields are only used when logging in, and are blank-
687 * for logouts.-
688 */-
689-
690 /* Use strncpy because we don't necessarily want null termination */-
691 strncpy(ut->ut_name, li->username,-
692 MIN_SIZEOF(ut->ut_name, li->username));-
693# ifdef HAVE_HOST_IN_UTMP-
694 strncpy(ut->ut_host, li->hostname,-
695 MIN_SIZEOF(ut->ut_host, li->hostname));-
696# endif-
697# ifdef HAVE_ADDR_IN_UTMP-
698 /* this is just a 32-bit IP address */-
699 if (li->hostaddr.sa.sa_family == AF_INET)
li->hostaddr.sa.sa_family == 2Description
TRUEnever evaluated
FALSEnever evaluated
0
700 ut->ut_addr = li->hostaddr.sa_in.sin_addr.s_addr;
never executed: ut-> ut_addr_v6[0] = li->hostaddr.sa_in.sin_addr.s_addr;
0
701# endif-
702# ifdef HAVE_ADDR_V6_IN_UTMP-
703 /* this is just a 128-bit IPv6 address */-
704 if (li->hostaddr.sa.sa_family == AF_INET6) {
li->hostaddr.s...a_family == 10Description
TRUEnever evaluated
FALSEnever evaluated
0
705 sa6 = ((struct sockaddr_in6 *)&li->hostaddr.sa);-
706 memcpy(ut->ut_addr_v6, sa6->sin6_addr.s6_addr, 16);-
707 if (IN6_IS_ADDR_V4MAPPED(&sa6->sin6_addr)) {
(__extension__... (0xffff); }))Description
TRUEnever evaluated
FALSEnever evaluated
0
708 ut->ut_addr_v6[0] = ut->ut_addr_v6[3];-
709 ut->ut_addr_v6[1] = 0;-
710 ut->ut_addr_v6[2] = 0;-
711 ut->ut_addr_v6[3] = 0;-
712 }
never executed: end of block
0
713 }
never executed: end of block
0
714# endif-
715}
never executed: end of block
0
716#endif /* USE_UTMP || USE_WTMP || USE_LOGIN */-
717-
718/**-
719 ** utmpx utility functions-
720 **-
721 ** These functions manipulate struct utmpx, accounting for system-
722 ** variations.-
723 **/-
724-
725#if defined(USE_UTMPX) || defined (USE_WTMPX)-
726/* build the utmpx structure */-
727void-
728set_utmpx_time(struct logininfo *li, struct utmpx *utx)-
729{-
730# if defined(HAVE_TV_IN_UTMPX)-
731 utx->ut_tv.tv_sec = li->tv_sec;-
732 utx->ut_tv.tv_usec = li->tv_usec;-
733# elif defined(HAVE_TIME_IN_UTMPX)-
734 utx->ut_time = li->tv_sec;-
735# endif-
736}-
737-
738void-
739construct_utmpx(struct logininfo *li, struct utmpx *utx)-
740{-
741# ifdef HAVE_ADDR_V6_IN_UTMP-
742 struct sockaddr_in6 *sa6;-
743# endif-
744 memset(utx, '\0', sizeof(*utx));-
745-
746# ifdef HAVE_ID_IN_UTMPX-
747 line_abbrevname(utx->ut_id, li->line, sizeof(utx->ut_id));-
748# endif-
749-
750 /* this is done here to keep utmp constants out of loginrec.h */-
751 switch (li->type) {-
752 case LTYPE_LOGIN:-
753 utx->ut_type = USER_PROCESS;-
754 break;-
755 case LTYPE_LOGOUT:-
756 utx->ut_type = DEAD_PROCESS;-
757 break;-
758 }-
759 line_stripname(utx->ut_line, li->line, sizeof(utx->ut_line));-
760 set_utmpx_time(li, utx);-
761 utx->ut_pid = li->pid;-
762-
763 /* strncpy(): Don't necessarily want null termination */-
764 strncpy(utx->ut_user, li->username,-
765 MIN_SIZEOF(utx->ut_user, li->username));-
766-
767 if (li->type == LTYPE_LOGOUT)-
768 return;-
769-
770 /*-
771 * These fields are only used when logging in, and are blank-
772 * for logouts.-
773 */-
774-
775# ifdef HAVE_HOST_IN_UTMPX-
776 strncpy(utx->ut_host, li->hostname,-
777 MIN_SIZEOF(utx->ut_host, li->hostname));-
778# endif-
779# ifdef HAVE_ADDR_IN_UTMPX-
780 /* this is just a 32-bit IP address */-
781 if (li->hostaddr.sa.sa_family == AF_INET)-
782 utx->ut_addr = li->hostaddr.sa_in.sin_addr.s_addr;-
783# endif-
784# ifdef HAVE_ADDR_V6_IN_UTMP-
785 /* this is just a 128-bit IPv6 address */-
786 if (li->hostaddr.sa.sa_family == AF_INET6) {-
787 sa6 = ((struct sockaddr_in6 *)&li->hostaddr.sa);-
788 memcpy(utx->ut_addr_v6, sa6->sin6_addr.s6_addr, 16);-
789 if (IN6_IS_ADDR_V4MAPPED(&sa6->sin6_addr)) {-
790 utx->ut_addr_v6[0] = utx->ut_addr_v6[3];-
791 utx->ut_addr_v6[1] = 0;-
792 utx->ut_addr_v6[2] = 0;-
793 utx->ut_addr_v6[3] = 0;-
794 }-
795 }-
796# endif-
797# ifdef HAVE_SYSLEN_IN_UTMPX-
798 /* ut_syslen is the length of the utx_host string */-
799 utx->ut_syslen = MIN(strlen(li->hostname), sizeof(utx->ut_host));-
800# endif-
801}-
802#endif /* USE_UTMPX || USE_WTMPX */-
803-
804/**-
805 ** Low-level utmp functions-
806 **/-
807-
808/* FIXME: (ATL) utmp_write_direct needs testing */-
809#ifdef USE_UTMP-
810-
811/* if we can, use pututline() etc. */-
812# if !defined(DISABLE_PUTUTLINE) && defined(HAVE_SETUTENT) && \-
813 defined(HAVE_PUTUTLINE)-
814# define UTMP_USE_LIBRARY-
815# endif-
816-
817-
818/* write a utmp entry with the system's help (pututline() and pals) */-
819# ifdef UTMP_USE_LIBRARY-
820static int-
821utmp_write_library(struct logininfo *li, struct utmp *ut)-
822{-
823 setutent();-
824 pututline(ut);-
825# ifdef HAVE_ENDUTENT-
826 endutent();-
827# endif-
828 return (1);-
829}-
830# else /* UTMP_USE_LIBRARY */-
831-
832/*-
833 * Write a utmp entry direct to the file-
834 * This is a slightly modification of code in OpenBSD's login.c-
835 */-
836static int-
837utmp_write_direct(struct logininfo *li, struct utmp *ut)-
838{-
839 struct utmp old_ut;-
840 register int fd;-
841 int tty;-
842-
843 /* FIXME: (ATL) ttyslot() needs local implementation */-
844-
845#if defined(HAVE_GETTTYENT)-
846 struct ttyent *ty;-
847-
848 tty=0;-
849 setttyent();-
850 while (NULL != (ty = getttyent())) {-
851 tty++;-
852 if (!strncmp(ty->ty_name, ut->ut_line, sizeof(ut->ut_line)))-
853 break;-
854 }-
855 endttyent();-
856-
857 if (NULL == ty) {-
858 logit("%s: tty not found", __func__);-
859 return (0);-
860 }-
861#else /* FIXME */-
862-
863 tty = ttyslot(); /* seems only to work for /dev/ttyp? style names */-
864-
865#endif /* HAVE_GETTTYENT */-
866-
867 if (tty > 0 && (fd = open(UTMP_FILE, O_RDWR|O_CREAT, 0644)) >= 0) {-
868 off_t pos, ret;-
869-
870 pos = (off_t)tty * sizeof(struct utmp);-
871 if ((ret = lseek(fd, pos, SEEK_SET)) == -1) {-
872 logit("%s: lseek: %s", __func__, strerror(errno));-
873 close(fd);-
874 return (0);-
875 }-
876 if (ret != pos) {-
877 logit("%s: Couldn't seek to tty %d slot in %s",-
878 __func__, tty, UTMP_FILE);-
879 close(fd);-
880 return (0);-
881 }-
882 /*-
883 * Prevent luser from zero'ing out ut_host.-
884 * If the new ut_line is empty but the old one is not-
885 * and ut_line and ut_name match, preserve the old ut_line.-
886 */-
887 if (atomicio(read, fd, &old_ut, sizeof(old_ut)) == sizeof(old_ut) &&-
888 (ut->ut_host[0] == '\0') && (old_ut.ut_host[0] != '\0') &&-
889 (strncmp(old_ut.ut_line, ut->ut_line, sizeof(ut->ut_line)) == 0) &&-
890 (strncmp(old_ut.ut_name, ut->ut_name, sizeof(ut->ut_name)) == 0))-
891 memcpy(ut->ut_host, old_ut.ut_host, sizeof(ut->ut_host));-
892-
893 if ((ret = lseek(fd, pos, SEEK_SET)) == -1) {-
894 logit("%s: lseek: %s", __func__, strerror(errno));-
895 close(fd);-
896 return (0);-
897 }-
898 if (ret != pos) {-
899 logit("%s: Couldn't seek to tty %d slot in %s",-
900 __func__, tty, UTMP_FILE);-
901 close(fd);-
902 return (0);-
903 }-
904 if (atomicio(vwrite, fd, ut, sizeof(*ut)) != sizeof(*ut)) {-
905 logit("%s: error writing %s: %s", __func__,-
906 UTMP_FILE, strerror(errno));-
907 close(fd);-
908 return (0);-
909 }-
910-
911 close(fd);-
912 return (1);-
913 } else {-
914 return (0);-
915 }-
916}-
917# endif /* UTMP_USE_LIBRARY */-
918-
919static int-
920utmp_perform_login(struct logininfo *li)-
921{-
922 struct utmp ut;-
923-
924 construct_utmp(li, &ut);-
925# ifdef UTMP_USE_LIBRARY-
926 if (!utmp_write_library(li, &ut)) {-
927 logit("%s: utmp_write_library() failed", __func__);-
928 return (0);-
929 }-
930# else-
931 if (!utmp_write_direct(li, &ut)) {-
932 logit("%s: utmp_write_direct() failed", __func__);-
933 return (0);-
934 }-
935# endif-
936 return (1);-
937}-
938-
939-
940static int-
941utmp_perform_logout(struct logininfo *li)-
942{-
943 struct utmp ut;-
944-
945 construct_utmp(li, &ut);-
946# ifdef UTMP_USE_LIBRARY-
947 if (!utmp_write_library(li, &ut)) {-
948 logit("%s: utmp_write_library() failed", __func__);-
949 return (0);-
950 }-
951# else-
952 if (!utmp_write_direct(li, &ut)) {-
953 logit("%s: utmp_write_direct() failed", __func__);-
954 return (0);-
955 }-
956# endif-
957 return (1);-
958}-
959-
960-
961int-
962utmp_write_entry(struct logininfo *li)-
963{-
964 switch(li->type) {-
965 case LTYPE_LOGIN:-
966 return (utmp_perform_login(li));-
967-
968 case LTYPE_LOGOUT:-
969 return (utmp_perform_logout(li));-
970-
971 default:-
972 logit("%s: invalid type field", __func__);-
973 return (0);-
974 }-
975}-
976#endif /* USE_UTMP */-
977-
978-
979/**-
980 ** Low-level utmpx functions-
981 **/-
982-
983/* not much point if we don't want utmpx entries */-
984#ifdef USE_UTMPX-
985-
986/* if we have the wherewithall, use pututxline etc. */-
987# if !defined(DISABLE_PUTUTXLINE) && defined(HAVE_SETUTXENT) && \-
988 defined(HAVE_PUTUTXLINE)-
989# define UTMPX_USE_LIBRARY-
990# endif-
991-
992-
993/* write a utmpx entry with the system's help (pututxline() and pals) */-
994# ifdef UTMPX_USE_LIBRARY-
995static int-
996utmpx_write_library(struct logininfo *li, struct utmpx *utx)-
997{-
998 setutxent();-
999 pututxline(utx);-
1000-
1001# ifdef HAVE_ENDUTXENT-
1002 endutxent();-
1003# endif-
1004 return (1);-
1005}-
1006-
1007# else /* UTMPX_USE_LIBRARY */-
1008-
1009/* write a utmp entry direct to the file */-
1010static int-
1011utmpx_write_direct(struct logininfo *li, struct utmpx *utx)-
1012{-
1013 logit("%s: not implemented!", __func__);-
1014 return (0);-
1015}-
1016# endif /* UTMPX_USE_LIBRARY */-
1017-
1018static int-
1019utmpx_perform_login(struct logininfo *li)-
1020{-
1021 struct utmpx utx;-
1022-
1023 construct_utmpx(li, &utx);-
1024# ifdef UTMPX_USE_LIBRARY-
1025 if (!utmpx_write_library(li, &utx)) {-
1026 logit("%s: utmp_write_library() failed", __func__);-
1027 return (0);-
1028 }-
1029# else-
1030 if (!utmpx_write_direct(li, &ut)) {-
1031 logit("%s: utmp_write_direct() failed", __func__);-
1032 return (0);-
1033 }-
1034# endif-
1035 return (1);-
1036}-
1037-
1038-
1039static int-
1040utmpx_perform_logout(struct logininfo *li)-
1041{-
1042 struct utmpx utx;-
1043-
1044 construct_utmpx(li, &utx);-
1045# ifdef HAVE_ID_IN_UTMPX-
1046 line_abbrevname(utx.ut_id, li->line, sizeof(utx.ut_id));-
1047# endif-
1048# ifdef HAVE_TYPE_IN_UTMPX-
1049 utx.ut_type = DEAD_PROCESS;-
1050# endif-
1051-
1052# ifdef UTMPX_USE_LIBRARY-
1053 utmpx_write_library(li, &utx);-
1054# else-
1055 utmpx_write_direct(li, &utx);-
1056# endif-
1057 return (1);-
1058}-
1059-
1060int-
1061utmpx_write_entry(struct logininfo *li)-
1062{-
1063 switch(li->type) {-
1064 case LTYPE_LOGIN:-
1065 return (utmpx_perform_login(li));-
1066 case LTYPE_LOGOUT:-
1067 return (utmpx_perform_logout(li));-
1068 default:-
1069 logit("%s: invalid type field", __func__);-
1070 return (0);-
1071 }-
1072}-
1073#endif /* USE_UTMPX */-
1074-
1075-
1076/**-
1077 ** Low-level wtmp functions-
1078 **/-
1079-
1080#ifdef USE_WTMP-
1081-
1082/*-
1083 * Write a wtmp entry direct to the end of the file-
1084 * This is a slight modification of code in OpenBSD's logwtmp.c-
1085 */-
1086static int-
1087wtmp_write(struct logininfo *li, struct utmp *ut)-
1088{-
1089 struct stat buf;-
1090 int fd, ret = 1;-
1091-
1092 if ((fd = open(WTMP_FILE, O_WRONLY|O_APPEND, 0)) < 0) {-
1093 logit("%s: problem writing %s: %s", __func__,-
1094 WTMP_FILE, strerror(errno));-
1095 return (0);-
1096 }-
1097 if (fstat(fd, &buf) == 0)-
1098 if (atomicio(vwrite, fd, ut, sizeof(*ut)) != sizeof(*ut)) {-
1099 ftruncate(fd, buf.st_size);-
1100 logit("%s: problem writing %s: %s", __func__,-
1101 WTMP_FILE, strerror(errno));-
1102 ret = 0;-
1103 }-
1104 close(fd);-
1105 return (ret);-
1106}-
1107-
1108static int-
1109wtmp_perform_login(struct logininfo *li)-
1110{-
1111 struct utmp ut;-
1112-
1113 construct_utmp(li, &ut);-
1114 return (wtmp_write(li, &ut));-
1115}-
1116-
1117-
1118static int-
1119wtmp_perform_logout(struct logininfo *li)-
1120{-
1121 struct utmp ut;-
1122-
1123 construct_utmp(li, &ut);-
1124 return (wtmp_write(li, &ut));-
1125}-
1126-
1127-
1128int-
1129wtmp_write_entry(struct logininfo *li)-
1130{-
1131 switch(li->type) {-
1132 case LTYPE_LOGIN:-
1133 return (wtmp_perform_login(li));-
1134 case LTYPE_LOGOUT:-
1135 return (wtmp_perform_logout(li));-
1136 default:-
1137 logit("%s: invalid type field", __func__);-
1138 return (0);-
1139 }-
1140}-
1141-
1142-
1143/*-
1144 * Notes on fetching login data from wtmp/wtmpx-
1145 *-
1146 * Logouts are usually recorded with (amongst other things) a blank-
1147 * username on a given tty line. However, some systems (HP-UX is one)-
1148 * leave all fields set, but change the ut_type field to DEAD_PROCESS.-
1149 *-
1150 * Since we're only looking for logins here, we know that the username-
1151 * must be set correctly. On systems that leave it in, we check for-
1152 * ut_type==USER_PROCESS (indicating a login.)-
1153 *-
1154 * Portability: Some systems may set something other than USER_PROCESS-
1155 * to indicate a login process. I don't know of any as I write. Also,-
1156 * it's possible that some systems may both leave the username in-
1157 * place and not have ut_type.-
1158 */-
1159-
1160/* return true if this wtmp entry indicates a login */-
1161static int-
1162wtmp_islogin(struct logininfo *li, struct utmp *ut)-
1163{-
1164 if (strncmp(li->username, ut->ut_name,-
1165 MIN_SIZEOF(li->username, ut->ut_name)) == 0) {-
1166# ifdef HAVE_TYPE_IN_UTMP-
1167 if (ut->ut_type & USER_PROCESS)-
1168 return (1);-
1169# else-
1170 return (1);-
1171# endif-
1172 }-
1173 return (0);-
1174}-
1175-
1176int-
1177wtmp_get_entry(struct logininfo *li)-
1178{-
1179 struct stat st;-
1180 struct utmp ut;-
1181 int fd, found = 0;-
1182-
1183 /* Clear the time entries in our logininfo */-
1184 li->tv_sec = li->tv_usec = 0;-
1185-
1186 if ((fd = open(WTMP_FILE, O_RDONLY)) < 0) {-
1187 logit("%s: problem opening %s: %s", __func__,-
1188 WTMP_FILE, strerror(errno));-
1189 return (0);-
1190 }-
1191 if (fstat(fd, &st) != 0) {-
1192 logit("%s: couldn't stat %s: %s", __func__,-
1193 WTMP_FILE, strerror(errno));-
1194 close(fd);-
1195 return (0);-
1196 }-
1197-
1198 /* Seek to the start of the last struct utmp */-
1199 if (lseek(fd, -(off_t)sizeof(struct utmp), SEEK_END) == -1) {-
1200 /* Looks like we've got a fresh wtmp file */-
1201 close(fd);-
1202 return (0);-
1203 }-
1204-
1205 while (!found) {-
1206 if (atomicio(read, fd, &ut, sizeof(ut)) != sizeof(ut)) {-
1207 logit("%s: read of %s failed: %s", __func__,-
1208 WTMP_FILE, strerror(errno));-
1209 close (fd);-
1210 return (0);-
1211 }-
1212 if (wtmp_islogin(li, &ut) ) {-
1213 found = 1;-
1214 /*-
1215 * We've already checked for a time in struct-
1216 * utmp, in login_getlast()-
1217 */-
1218# ifdef HAVE_TIME_IN_UTMP-
1219 li->tv_sec = ut.ut_time;-
1220# else-
1221# if HAVE_TV_IN_UTMP-
1222 li->tv_sec = ut.ut_tv.tv_sec;-
1223# endif-
1224# endif-
1225 line_fullname(li->line, ut.ut_line,-
1226 MIN_SIZEOF(li->line, ut.ut_line));-
1227# ifdef HAVE_HOST_IN_UTMP-
1228 strlcpy(li->hostname, ut.ut_host,-
1229 MIN_SIZEOF(li->hostname, ut.ut_host));-
1230# endif-
1231 continue;-
1232 }-
1233 /* Seek back 2 x struct utmp */-
1234 if (lseek(fd, -(off_t)(2 * sizeof(struct utmp)), SEEK_CUR) == -1) {-
1235 /* We've found the start of the file, so quit */-
1236 close(fd);-
1237 return (0);-
1238 }-
1239 }-
1240-
1241 /* We found an entry. Tidy up and return */-
1242 close(fd);-
1243 return (1);-
1244}-
1245# endif /* USE_WTMP */-
1246-
1247-
1248/**-
1249 ** Low-level wtmpx functions-
1250 **/-
1251-
1252#ifdef USE_WTMPX-
1253/*-
1254 * Write a wtmpx entry direct to the end of the file-
1255 * This is a slight modification of code in OpenBSD's logwtmp.c-
1256 */-
1257static int-
1258wtmpx_write(struct logininfo *li, struct utmpx *utx)-
1259{-
1260#ifndef HAVE_UPDWTMPX-
1261 struct stat buf;-
1262 int fd, ret = 1;-
1263-
1264 if ((fd = open(WTMPX_FILE, O_WRONLY|O_APPEND, 0)) < 0) {-
1265 logit("%s: problem opening %s: %s", __func__,-
1266 WTMPX_FILE, strerror(errno));-
1267 return (0);-
1268 }-
1269-
1270 if (fstat(fd, &buf) == 0)-
1271 if (atomicio(vwrite, fd, utx, sizeof(*utx)) != sizeof(*utx)) {-
1272 ftruncate(fd, buf.st_size);-
1273 logit("%s: problem writing %s: %s", __func__,-
1274 WTMPX_FILE, strerror(errno));-
1275 ret = 0;-
1276 }-
1277 close(fd);-
1278-
1279 return (ret);-
1280#else-
1281 updwtmpx(WTMPX_FILE, utx);-
1282 return (1);-
1283#endif-
1284}-
1285-
1286-
1287static int-
1288wtmpx_perform_login(struct logininfo *li)-
1289{-
1290 struct utmpx utx;-
1291-
1292 construct_utmpx(li, &utx);-
1293 return (wtmpx_write(li, &utx));-
1294}-
1295-
1296-
1297static int-
1298wtmpx_perform_logout(struct logininfo *li)-
1299{-
1300 struct utmpx utx;-
1301-
1302 construct_utmpx(li, &utx);-
1303 return (wtmpx_write(li, &utx));-
1304}-
1305-
1306-
1307int-
1308wtmpx_write_entry(struct logininfo *li)-
1309{-
1310 switch(li->type) {-
1311 case LTYPE_LOGIN:-
1312 return (wtmpx_perform_login(li));-
1313 case LTYPE_LOGOUT:-
1314 return (wtmpx_perform_logout(li));-
1315 default:-
1316 logit("%s: invalid type field", __func__);-
1317 return (0);-
1318 }-
1319}-
1320-
1321/* Please see the notes above wtmp_islogin() for information about the-
1322 next two functions */-
1323-
1324/* Return true if this wtmpx entry indicates a login */-
1325static int-
1326wtmpx_islogin(struct logininfo *li, struct utmpx *utx)-
1327{-
1328 if (strncmp(li->username, utx->ut_user,-
1329 MIN_SIZEOF(li->username, utx->ut_user)) == 0 ) {-
1330# ifdef HAVE_TYPE_IN_UTMPX-
1331 if (utx->ut_type == USER_PROCESS)-
1332 return (1);-
1333# else-
1334 return (1);-
1335# endif-
1336 }-
1337 return (0);-
1338}-
1339-
1340-
1341int-
1342wtmpx_get_entry(struct logininfo *li)-
1343{-
1344 struct stat st;-
1345 struct utmpx utx;-
1346 int fd, found=0;-
1347-
1348 /* Clear the time entries */-
1349 li->tv_sec = li->tv_usec = 0;-
1350-
1351 if ((fd = open(WTMPX_FILE, O_RDONLY)) < 0) {-
1352 logit("%s: problem opening %s: %s", __func__,-
1353 WTMPX_FILE, strerror(errno));-
1354 return (0);-
1355 }-
1356 if (fstat(fd, &st) != 0) {-
1357 logit("%s: couldn't stat %s: %s", __func__,-
1358 WTMPX_FILE, strerror(errno));-
1359 close(fd);-
1360 return (0);-
1361 }-
1362-
1363 /* Seek to the start of the last struct utmpx */-
1364 if (lseek(fd, -(off_t)sizeof(struct utmpx), SEEK_END) == -1 ) {-
1365 /* probably a newly rotated wtmpx file */-
1366 close(fd);-
1367 return (0);-
1368 }-
1369-
1370 while (!found) {-
1371 if (atomicio(read, fd, &utx, sizeof(utx)) != sizeof(utx)) {-
1372 logit("%s: read of %s failed: %s", __func__,-
1373 WTMPX_FILE, strerror(errno));-
1374 close (fd);-
1375 return (0);-
1376 }-
1377 /*-
1378 * Logouts are recorded as a blank username on a particular-
1379 * line. So, we just need to find the username in struct utmpx-
1380 */-
1381 if (wtmpx_islogin(li, &utx)) {-
1382 found = 1;-
1383# if defined(HAVE_TV_IN_UTMPX)-
1384 li->tv_sec = utx.ut_tv.tv_sec;-
1385# elif defined(HAVE_TIME_IN_UTMPX)-
1386 li->tv_sec = utx.ut_time;-
1387# endif-
1388 line_fullname(li->line, utx.ut_line, sizeof(li->line));-
1389# if defined(HAVE_HOST_IN_UTMPX)-
1390 strlcpy(li->hostname, utx.ut_host,-
1391 MIN_SIZEOF(li->hostname, utx.ut_host));-
1392# endif-
1393 continue;-
1394 }-
1395 if (lseek(fd, -(off_t)(2 * sizeof(struct utmpx)), SEEK_CUR) == -1) {-
1396 close(fd);-
1397 return (0);-
1398 }-
1399 }-
1400-
1401 close(fd);-
1402 return (1);-
1403}-
1404#endif /* USE_WTMPX */-
1405-
1406/**-
1407 ** Low-level libutil login() functions-
1408 **/-
1409-
1410#ifdef USE_LOGIN-
1411static int-
1412syslogin_perform_login(struct logininfo *li)-
1413{-
1414 struct utmp *ut;-
1415-
1416 ut = xmalloc(sizeof(*ut));-
1417 construct_utmp(li, ut);-
1418 login(ut);-
1419 free(ut);-
1420-
1421 return (1);
never executed: return (1);
0
1422}-
1423-
1424static int-
1425syslogin_perform_logout(struct logininfo *li)-
1426{-
1427# ifdef HAVE_LOGOUT-
1428 char line[UT_LINESIZE];-
1429-
1430 (void)line_stripname(line, li->line, sizeof(line));-
1431-
1432 if (!logout(line))
!logout(line)Description
TRUEnever evaluated
FALSEnever evaluated
0
1433 logit("%s: logout() returned an error", __func__);
never executed: logit("%s: logout() returned an error", __func__);
0
1434# ifdef HAVE_LOGWTMP-
1435 else-
1436 logwtmp(line, "", "");
never executed: logwtmp(line, "", "");
0
1437# endif-
1438 /* FIXME: (ATL - if the need arises) What to do if we have-
1439 * login, but no logout? what if logout but no logwtmp? All-
1440 * routines are in libutil so they should all be there,-
1441 * but... */-
1442# endif-
1443 return (1);
never executed: return (1);
0
1444}-
1445-
1446int-
1447syslogin_write_entry(struct logininfo *li)-
1448{-
1449 switch (li->type) {-
1450 case LTYPE_LOGIN:
never executed: case 7:
0
1451 return (syslogin_perform_login(li));
never executed: return (syslogin_perform_login(li));
0
1452 case LTYPE_LOGOUT:
never executed: case 8:
0
1453 return (syslogin_perform_logout(li));
never executed: return (syslogin_perform_logout(li));
0
1454 default:
never executed: default:
0
1455 logit("%s: Invalid type field", __func__);-
1456 return (0);
never executed: return (0);
0
1457 }-
1458}-
1459#endif /* USE_LOGIN */-
1460-
1461/* end of file log-syslogin.c */-
1462-
1463/**-
1464 ** Low-level lastlog functions-
1465 **/-
1466-
1467#ifdef USE_LASTLOG-
1468-
1469#if !defined(LASTLOG_WRITE_PUTUTXLINE) || !defined(HAVE_GETLASTLOGXBYNAME)-
1470/* open the file (using filemode) and seek to the login entry */-
1471static int-
1472lastlog_openseek(struct logininfo *li, int *fd, int filemode)-
1473{-
1474 off_t offset;-
1475 char lastlog_file[1024];-
1476 struct stat st;-
1477-
1478 if (stat(LASTLOG_FILE, &st) != 0) {
stat( "/var/lo...g" , &st) != 0Description
TRUEnever evaluated
FALSEnever evaluated
0
1479 logit("%s: Couldn't stat %s: %s", __func__,-
1480 LASTLOG_FILE, strerror(errno));-
1481 return (0);
never executed: return (0);
0
1482 }-
1483 if (S_ISDIR(st.st_mode)) {
(((( st.st_mod... == (0040000))Description
TRUEnever evaluated
FALSEnever evaluated
0
1484 snprintf(lastlog_file, sizeof(lastlog_file), "%s/%s",-
1485 LASTLOG_FILE, li->username);-
1486 } else if (S_ISREG(st.st_mode)) {
never executed: end of block
(((( st.st_mod... == (0100000))Description
TRUEnever evaluated
FALSEnever evaluated
0
1487 strlcpy(lastlog_file, LASTLOG_FILE, sizeof(lastlog_file));-
1488 } else {
never executed: end of block
0
1489 logit("%s: %.100s is not a file or directory!", __func__,-
1490 LASTLOG_FILE);-
1491 return (0);
never executed: return (0);
0
1492 }-
1493-
1494 *fd = open(lastlog_file, filemode, 0600);-
1495 if (*fd < 0) {
*fd < 0Description
TRUEnever evaluated
FALSEnever evaluated
0
1496 debug("%s: Couldn't open %s: %s", __func__,-
1497 lastlog_file, strerror(errno));-
1498 return (0);
never executed: return (0);
0
1499 }-
1500-
1501 if (S_ISREG(st.st_mode)) {
(((( st.st_mod... == (0100000))Description
TRUEnever evaluated
FALSEnever evaluated
0
1502 /* find this uid's offset in the lastlog file */-
1503 offset = (off_t) ((u_long)li->uid * sizeof(struct lastlog));-
1504-
1505 if (lseek(*fd, offset, SEEK_SET) != offset) {
lseek(*fd, off... 0 ) != offsetDescription
TRUEnever evaluated
FALSEnever evaluated
0
1506 logit("%s: %s->lseek(): %s", __func__,-
1507 lastlog_file, strerror(errno));-
1508 close(*fd);-
1509 return (0);
never executed: return (0);
0
1510 }-
1511 }
never executed: end of block
0
1512-
1513 return (1);
never executed: return (1);
0
1514}-
1515#endif /* !LASTLOG_WRITE_PUTUTXLINE || !HAVE_GETLASTLOGXBYNAME */-
1516-
1517#ifdef LASTLOG_WRITE_PUTUTXLINE-
1518int-
1519lastlog_write_entry(struct logininfo *li)-
1520{-
1521 switch(li->type) {-
1522 case LTYPE_LOGIN:-
1523 return 1; /* lastlog written by pututxline */-
1524 default:-
1525 logit("lastlog_write_entry: Invalid type field");-
1526 return 0;-
1527 }-
1528}-
1529#else /* LASTLOG_WRITE_PUTUTXLINE */-
1530int-
1531lastlog_write_entry(struct logininfo *li)-
1532{-
1533 struct lastlog last;-
1534 int fd;-
1535-
1536 switch(li->type) {-
1537 case LTYPE_LOGIN:
never executed: case 7:
0
1538 /* create our struct lastlog */-
1539 memset(&last, '\0', sizeof(last));-
1540 line_stripname(last.ll_line, li->line, sizeof(last.ll_line));-
1541 strlcpy(last.ll_host, li->hostname,-
1542 MIN_SIZEOF(last.ll_host, li->hostname));-
1543 last.ll_time = li->tv_sec;-
1544 -
1545 if (!lastlog_openseek(li, &fd, O_RDWR|O_CREAT))
!lastlog_opens...d, 02 | 0100 )Description
TRUEnever evaluated
FALSEnever evaluated
0
1546 return (0);
never executed: return (0);
0
1547 -
1548 /* write the entry */-
1549 if (atomicio(vwrite, fd, &last, sizeof(last)) != sizeof(last)) {
atomicio((ssiz...= sizeof(last)Description
TRUEnever evaluated
FALSEnever evaluated
0
1550 close(fd);-
1551 logit("%s: Error writing to %s: %s", __func__,-
1552 LASTLOG_FILE, strerror(errno));-
1553 return (0);
never executed: return (0);
0
1554 }-
1555 -
1556 close(fd);-
1557 return (1);
never executed: return (1);
0
1558 default:
never executed: default:
0
1559 logit("%s: Invalid type field", __func__);-
1560 return (0);
never executed: return (0);
0
1561 }-
1562}-
1563#endif /* LASTLOG_WRITE_PUTUTXLINE */-
1564-
1565#ifdef HAVE_GETLASTLOGXBYNAME-
1566int-
1567lastlog_get_entry(struct logininfo *li)-
1568{-
1569 struct lastlogx l, *ll;-
1570-
1571 if ((ll = getlastlogxbyname(li->username, &l)) == NULL) {-
1572 memset(&l, '\0', sizeof(l));-
1573 ll = &l;-
1574 }-
1575 line_fullname(li->line, ll->ll_line, sizeof(li->line));-
1576 strlcpy(li->hostname, ll->ll_host,-
1577 MIN_SIZEOF(li->hostname, ll->ll_host));-
1578 li->tv_sec = ll->ll_tv.tv_sec;-
1579 li->tv_usec = ll->ll_tv.tv_usec;-
1580 return (1);-
1581}-
1582#else /* HAVE_GETLASTLOGXBYNAME */-
1583int-
1584lastlog_get_entry(struct logininfo *li)-
1585{-
1586 struct lastlog last;-
1587 int fd, ret;-
1588-
1589 if (!lastlog_openseek(li, &fd, O_RDONLY))
!lastlog_opens...(li, &fd, 00 )Description
TRUEnever evaluated
FALSEnever evaluated
0
1590 return (0);
never executed: return (0);
0
1591-
1592 ret = atomicio(read, fd, &last, sizeof(last));-
1593 close(fd);-
1594-
1595 switch (ret) {-
1596 case 0:
never executed: case 0:
0
1597 memset(&last, '\0', sizeof(last));-
1598 /* FALLTHRU */-
1599 case sizeof(last):
code before this statement never executed: case sizeof(last):
never executed: case sizeof(last):
0
1600 line_fullname(li->line, last.ll_line, sizeof(li->line));-
1601 strlcpy(li->hostname, last.ll_host,-
1602 MIN_SIZEOF(li->hostname, last.ll_host));-
1603 li->tv_sec = last.ll_time;-
1604 return (1);
never executed: return (1);
0
1605 case -1:
never executed: case -1:
0
1606 error("%s: Error reading from %s: %s", __func__,-
1607 LASTLOG_FILE, strerror(errno));-
1608 return (0);
never executed: return (0);
0
1609 default:
never executed: default:
0
1610 error("%s: Error reading from %s: Expecting %d, got %d",-
1611 __func__, LASTLOG_FILE, (int)sizeof(last), ret);-
1612 return (0);
never executed: return (0);
0
1613 }-
1614-
1615 /* NOTREACHED */-
1616 return (0);
dead code: return (0);
-
1617}-
1618#endif /* HAVE_GETLASTLOGXBYNAME */-
1619#endif /* USE_LASTLOG */-
1620-
1621#if defined(USE_UTMPX) && defined(HAVE_SETUTXDB) && \-
1622 defined(UTXDB_LASTLOGIN) && defined(HAVE_GETUTXUSER)-
1623int-
1624utmpx_get_entry(struct logininfo *li)-
1625{-
1626 struct utmpx *utx;-
1627-
1628 if (setutxdb(UTXDB_LASTLOGIN, NULL) != 0)-
1629 return (0);-
1630 utx = getutxuser(li->username);-
1631 if (utx == NULL) {-
1632 endutxent();-
1633 return (0);-
1634 }-
1635-
1636 line_fullname(li->line, utx->ut_line,-
1637 MIN_SIZEOF(li->line, utx->ut_line));-
1638 strlcpy(li->hostname, utx->ut_host,-
1639 MIN_SIZEOF(li->hostname, utx->ut_host));-
1640 li->tv_sec = utx->ut_tv.tv_sec;-
1641 li->tv_usec = utx->ut_tv.tv_usec;-
1642 endutxent();-
1643 return (1);-
1644}-
1645#endif /* USE_UTMPX && HAVE_SETUTXDB && UTXDB_LASTLOGIN && HAVE_GETUTXUSER */-
1646-
1647#ifdef USE_BTMP-
1648 /*-
1649 * Logs failed login attempts in _PATH_BTMP if that exists.-
1650 * The most common login failure is to give password instead of username.-
1651 * So the _PATH_BTMP file checked for the correct permission, so that-
1652 * only root can read it.-
1653 */-
1654-
1655void-
1656record_failed_login(const char *username, const char *hostname,-
1657 const char *ttyn)-
1658{-
1659 int fd;-
1660 struct utmp ut;-
1661 struct sockaddr_storage from;-
1662 socklen_t fromlen = sizeof(from);-
1663 struct sockaddr_in *a4;-
1664 struct sockaddr_in6 *a6;-
1665 time_t t;-
1666 struct stat fst;-
1667-
1668 if (geteuid() != 0)
geteuid() != 0Description
TRUEnever evaluated
FALSEnever evaluated
0
1669 return;
never executed: return;
0
1670 if ((fd = open(_PATH_BTMP, O_WRONLY | O_APPEND)) < 0) {
(fd = open("/v...| 02000 )) < 0Description
TRUEnever evaluated
FALSEnever evaluated
0
1671 debug("Unable to open the btmp file %s: %s", _PATH_BTMP,-
1672 strerror(errno));-
1673 return;
never executed: return;
0
1674 }-
1675 if (fstat(fd, &fst) < 0) {
fstat(fd, &fst) < 0Description
TRUEnever evaluated
FALSEnever evaluated
0
1676 logit("%s: fstat of %s failed: %s", __func__, _PATH_BTMP,-
1677 strerror(errno));-
1678 goto out;
never executed: goto out;
0
1679 }-
1680 if((fst.st_mode & (S_IXGRP | S_IRWXO)) || (fst.st_uid != 0)){
(fst.st_mode &...>> 3) >> 3) ))Description
TRUEnever evaluated
FALSEnever evaluated
(fst.st_uid != 0)Description
TRUEnever evaluated
FALSEnever evaluated
0
1681 logit("Excess permission or bad ownership on file %s",-
1682 _PATH_BTMP);-
1683 goto out;
never executed: goto out;
0
1684 }-
1685-
1686 memset(&ut, 0, sizeof(ut));-
1687 /* strncpy because we don't necessarily want nul termination */-
1688 strncpy(ut.ut_user, username, sizeof(ut.ut_user));-
1689 strlcpy(ut.ut_line, "ssh:notty", sizeof(ut.ut_line));-
1690-
1691 time(&t);-
1692 ut.ut_time = t; /* ut_time is not always a time_t */-
1693 ut.ut_type = LOGIN_PROCESS;-
1694 ut.ut_pid = getpid();-
1695-
1696 /* strncpy because we don't necessarily want nul termination */-
1697 strncpy(ut.ut_host, hostname, sizeof(ut.ut_host));-
1698-
1699 if (packet_connection_is_on_socket() &&
ssh_packet_con...(active_state)Description
TRUEnever evaluated
FALSEnever evaluated
0
1700 getpeername(packet_get_connection_in(),
getpeername(ss...&fromlen) == 0Description
TRUEnever evaluated
FALSEnever evaluated
0
1701 (struct sockaddr *)&from, &fromlen) == 0) {
getpeername(ss...&fromlen) == 0Description
TRUEnever evaluated
FALSEnever evaluated
0
1702 ipv64_normalise_mapped(&from, &fromlen);-
1703 if (from.ss_family == AF_INET) {
from.ss_family == 2Description
TRUEnever evaluated
FALSEnever evaluated
0
1704 a4 = (struct sockaddr_in *)&from;-
1705 memcpy(&ut.ut_addr, &(a4->sin_addr),-
1706 MIN_SIZEOF(ut.ut_addr, a4->sin_addr));-
1707 }
never executed: end of block
0
1708#ifdef HAVE_ADDR_V6_IN_UTMP-
1709 if (from.ss_family == AF_INET6) {
from.ss_family == 10Description
TRUEnever evaluated
FALSEnever evaluated
0
1710 a6 = (struct sockaddr_in6 *)&from;-
1711 memcpy(&ut.ut_addr_v6, &(a6->sin6_addr),-
1712 MIN_SIZEOF(ut.ut_addr_v6, a6->sin6_addr));-
1713 }
never executed: end of block
0
1714#endif-
1715 }
never executed: end of block
0
1716-
1717 if (atomicio(vwrite, fd, &ut, sizeof(ut)) != sizeof(ut))
atomicio((ssiz... != sizeof(ut)Description
TRUEnever evaluated
FALSEnever evaluated
0
1718 error("Failed to write to %s: %s", _PATH_BTMP,
never executed: error("Failed to write to %s: %s", "/var/log/btmp", strerror( (*__errno_location ()) ));
0
1719 strerror(errno));
never executed: error("Failed to write to %s: %s", "/var/log/btmp", strerror( (*__errno_location ()) ));
0
1720-
1721out:
code before this statement never executed: out:
0
1722 close(fd);-
1723}
never executed: end of block
0
1724#endif /* USE_BTMP */-
Source codeSwitch to Preprocessed file

Generated by Squish Coco 4.2.2