Bug Summary

File:sessreg.c
Location:line 370, column 32
Description:Access to field 'pw_uid' results in a dereference of a null pointer (loaded from variable 'pwd')

Annotated Source Code

1/*
2 * Copyright 1990, 1998 The Open Group
3 *
4 * Permission to use, copy, modify, distribute, and sell this software and its
5 * documentation for any purpose is hereby granted without fee, provided that
6 * the above copyright notice appear in all copies and that both that
7 * copyright notice and this permission notice appear in supporting
8 * documentation.
9 *
10 * The above copyright notice and this permission notice shall be included
11 * in all copies or substantial portions of the Software.
12 *
13 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
14 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
15 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
16 * IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
17 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
18 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
19 * OTHER DEALINGS IN THE SOFTWARE.
20 *
21 * Except as contained in this notice, the name of The Open Group shall
22 * not be used in advertising or otherwise to promote the sale, use or
23 * other dealings in this Software without prior written authorization
24 * from The Open Group.
25 *
26 */
27
28/*
29 * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
30 *
31 * Permission is hereby granted, free of charge, to any person obtaining a
32 * copy of this software and associated documentation files (the "Software"),
33 * to deal in the Software without restriction, including without limitation
34 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
35 * and/or sell copies of the Software, and to permit persons to whom the
36 * Software is furnished to do so, subject to the following conditions:
37 *
38 * The above copyright notice and this permission notice (including the next
39 * paragraph) shall be included in all copies or substantial portions of the
40 * Software.
41 *
42 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
43 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
44 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
45 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
46 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
47 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
48 * DEALINGS IN THE SOFTWARE.
49 */
50
51/*
52 * Author: Keith Packard, MIT X Consortium
53 * Lastlog support and dynamic utmp entry allocation
54 * by Andreas Stolcke <stolcke@icsi.berkeley.edu>
55 */
56
57/*
58 * sessreg
59 *
60 * simple wtmp/utmp frobber
61 *
62 * usage: sessreg [ -w <wtmp-file> ] [ -u <utmp-file> ]
63 * [ -l <line> ]
64 * [ -L <lastlog-file> ] / #ifdef USE_LASTLOG
65 * [ -h <host-name> ] / BSD only
66 * [ -s <slot-number> ] [ -x Xservers-file ] / BSD only
67 * [ -t <ttys-file> ] / BSD only
68 * [ -a ] [ -d ] user-name
69 *
70 * one of -a or -d must be specified
71 */
72
73#include "sessreg.h"
74
75#include <X11/Xos.h>
76#include <X11/Xfuncs.h>
77#include <stdio.h>
78#include <stdlib.h>
79#include <time.h>
80
81#ifdef USE_UTMP
82static void set_utmp (struct utmp *u, char *line, char *user, char *host,
83 time_t date, int addp);
84#endif
85
86#ifdef USE_UTMPX
87static void set_utmpx (struct utmpx *u, const char *line, const char *user,
88 const char *host, time_t date, int addp);
89#endif
90
91static int wflag, uflag, lflag;
92static const char *wtmp_file, *utmp_file;
93static char *line;
94#ifdef USE_UTMPX
95#ifdef HAVE_UPDWTMPX1
96static const char *wtmpx_file = NULL((void*)0);
97#endif
98#ifdef HAVE_UTMPXNAME1
99static const char *utmpx_file = NULL((void*)0);
100#endif
101#endif
102#ifndef WTMPX_FILE"/var/log/wtmp"
103#define WTMPX_FILE"/var/log/wtmp" _PATH_WTMPX"/var/log/wtmp"
104#endif
105#ifndef UTMPX_FILE"/var/run/utmp"
106#define UTMPX_FILE"/var/run/utmp" _PATH_UTMPX"/var/run/utmp"
107#endif
108
109static int utmp_none, wtmp_none;
110/*
111 * BSD specific variables. To make life much easier for Xstartup/Xreset
112 * maintainers, these arguments are accepted but ignored for sysV
113 */
114static int hflag, xflag, tflag;
115static char *host_name = NULL((void*)0);
116#if defined(USE_UTMP) && !defined(HAVE_PUTUTLINE1)
117static int sflag;
118static int slot_number;
119#endif
120static char *xservers_file, *ttys_file;
121static char *user_name;
122static int aflag, dflag;
123#ifdef USE_LASTLOG
124static const char *llog_file;
125static int llog_none, Lflag;
126#endif
127
128static char *program_name;
129
130#if defined(USE_UTMP) && !defined(HAVE_PUTUTLINE1)
131static int findslot (char *line_name, char *host_name, int addp, int slot);
132static int Xslot (char *ttys_file, char *servers_file, char *tty_line,
133 char *host_name, int addp);
134#endif
135
136static int
137usage (int x)
138{
139 if (x) {
140 fprintf (stderrstderr, "%s: usage %s {-a -d} [-w wtmp-file] [-u utmp-file]", program_name, program_name);
141#ifdef USE_LASTLOG
142 fprintf (stderrstderr, " [-L lastlog-file]");
143#endif
144 fprintf (stderrstderr, "\n");
145 fprintf (stderrstderr, " [-t ttys-file] [-l line-name] [-h host-name]\n");
146 fprintf (stderrstderr, " [-s slot-number] [-x servers-file] user-name\n");
147 exit (1);
148 }
149 return x;
150}
151
152static char *
153getstring (char ***avp, int *flagp)
154{
155 char **a = *avp;
156
157 usage ((*flagp)++);
158 if (*++*a)
159 return *a;
160 ++a;
161 usage (!*a);
162 *avp = a;
163 return *a;
164}
165
166#if defined(USE_UTMP) && !defined(HAVE_PUTUTLINE1)
167static int
168syserr (int x, const char *s)
169{
170 if (x == -1) {
171 perror (s);
172 exit (1);
173 }
174 return x;
175}
176#endif
177
178static int
179sysnerr (int x, const char *s)
180{
181 if (x == 0) {
182 perror (s);
183 exit (1);
184 }
185 return x;
186}
187
188int
189main (int argc, char **argv)
190{
191#if defined(USE_UTMP) && !defined(HAVE_PUTUTLINE1)
192 int utmp;
193#endif
194#ifndef USE_UTMPX
195 int wtmp;
196#endif
197 time_t current_time;
198#ifdef USE_UTMP
199 struct utmp utmp_entry;
200#endif
201#ifdef USE_UTMPX
202 struct utmpx utmpx_entry;
203#endif
204
205 program_name = argv[0];
206 while (*++argv && **argv == '-') {
1
Loop condition is false. Execution continues on line 252
207 switch (*++*argv) {
208 case 'w':
209 wtmp_file = getstring (&argv, &wflag);
210 if (!strcmp (wtmp_file, "none"))
211 wtmp_none = 1;
212 break;
213 case 'u':
214 utmp_file = getstring (&argv, &uflag);
215 if (!strcmp (utmp_file, "none"))
216 utmp_none = 1;
217 break;
218#ifdef USE_LASTLOG
219 case 'L':
220 llog_file = getstring (&argv, &Lflag);
221 if (!strcmp (llog_file, "none"))
222 llog_none = 1;
223 break;
224#endif
225 case 't':
226 ttys_file = getstring (&argv, &tflag);
227 break;
228 case 'l':
229 line = getstring (&argv, &lflag);
230 break;
231 case 'h':
232 host_name = getstring (&argv, &hflag);
233 break;
234 case 's':
235#if defined(USE_UTMP) && !defined(HAVE_PUTUTLINE1)
236 slot_number = atoi (getstring (&argv, &sflag));
237#endif
238 break;
239 case 'x':
240 xservers_file = getstring (&argv, &xflag);
241 break;
242 case 'a':
243 aflag++;
244 break;
245 case 'd':
246 dflag++;
247 break;
248 default:
249 usage (1);
250 }
251 }
252 usage (!(user_name = *argv++));
253 usage (*argv != NULL((void*)0));
254 /*
255 * complain if neither aflag nor dflag are set,
256 * or if both are set.
257 */
258 usage (!(aflag ^ dflag));
259 usage (xflag && !lflag);
260 /* set up default file names */
261 if (!wflag) {
2
Assuming 'wflag' is not equal to 0
3
Taking false branch
262 wtmp_file = WTMP_FILE"/var/log/wtmp";
263#if defined(USE_UTMPX) && defined(HAVE_UPDWTMPX1)
264 wtmpx_file = WTMPX_FILE"/var/log/wtmp";
265#endif
266 }
267#ifndef NO_UTMP
268 if (!uflag) {
4
Assuming 'uflag' is not equal to 0
5
Taking false branch
269 utmp_file = UTMP_FILE"/var/run/utmp";
270#if defined(USE_UTMPX) && defined(HAVE_UTMPXNAME1)
271 utmpx_file = UTMPX_FILE"/var/run/utmp";
272#endif
273 }
274#else
275 utmp_none = 1;
276#endif
277#ifdef USE_LASTLOG
278 if (!Lflag)
6
Assuming 'Lflag' is not equal to 0
7
Taking false branch
279 llog_file = LLOG_FILE"/var/log/lastlog";
280#endif
281#if defined(USE_UTMP) && !defined(HAVE_PUTUTLINE1)
282 if (!tflag)
283 ttys_file = TTYS_FILE"/etc/ttys";
284 if (!sflag && !utmp_none) {
285 if (xflag)
286 sysnerr (slot_number = Xslot (ttys_file, xservers_file, line, host_name, aflag), "Xslot");
287 else
288 sysnerr (slot_number = ttyslot (), "ttyslot");
289 }
290#endif
291 if (!lflag) {
8
Assuming 'lflag' is not equal to 0
9
Taking false branch
292 sysnerr ((line = ttyname (0)) != NULL((void*)0), "ttyname");
293 if (strncmp(line, "/dev/", 5) == 0)
294 line += 5;
295 }
296 time (&current_time);
297#ifdef USE_UTMP
298 set_utmp (&utmp_entry, line, user_name, host_name, current_time, aflag);
299#endif
300
301#ifdef USE_UTMPX
302 /* need to set utmpxname() before calling set_utmpx() for
303 UtmpxIdOpen to work */
304# ifdef HAVE_UTMPXNAME1
305 if (utmpx_file != NULL((void*)0)) {
10
Assuming 'utmpx_file' is equal to null
11
Taking false branch
306 utmpxname (utmpx_file);
307 }
308# endif
309 set_utmpx (&utmpx_entry, line, user_name,
310 host_name, current_time, aflag);
311#endif
312
313 if (!utmp_none) {
12
Assuming 'utmp_none' is not equal to 0
13
Taking false branch
314#ifdef USE_UTMPX
315# ifdef HAVE_UTMPXNAME1
316 if (utmpx_file != NULL((void*)0))
317# endif
318 {
319 setutxent ();
320 (void) getutxid (&utmpx_entry);
321 pututxline (&utmpx_entry);
322 endutxent ();
323 }
324#endif
325#ifdef USE_UTMP
326# ifdef HAVE_PUTUTLINE1
327 utmpname (utmp_file);
328 setutent ();
329 (void) getutid (&utmp_entry);
330 pututline (&utmp_entry);
331 endutent ();
332# else
333 utmp = open (utmp_file, O_RDWR02);
334 if (utmp != -1) {
335 syserr ((int) lseek (utmp, (long) slot_number * sizeof (struct utmp), 0), "lseek");
336 sysnerr (write (utmp, (char *) &utmp_entry, sizeof (utmp_entry))
337 == sizeof (utmp_entry), "write utmp entry");
338 close (utmp);
339 }
340# endif
341#endif /* USE_UTMP */
342 }
343 if (!wtmp_none) {
14
Assuming 'wtmp_none' is not equal to 0
15
Taking false branch
344#ifdef USE_UTMPX
345# ifdef HAVE_UPDWTMPX1
346 if (wtmpx_file != NULL((void*)0)) {
347 updwtmpx(wtmpx_file, &utmpx_entry);
348 }
349# endif
350#else
351 wtmp = open (wtmp_file, O_WRONLY01|O_APPEND02000);
352 if (wtmp != -1) {
353 sysnerr (write (wtmp, (char *) &utmp_entry, sizeof (utmp_entry))
354 == sizeof (utmp_entry), "write wtmp entry");
355 close (wtmp);
356 }
357#endif
358 }
359#ifdef USE_LASTLOG
360 if (aflag && !llog_none) {
16
Assuming 'llog_none' is 0
17
Taking true branch
361 int llog;
362 struct passwd *pwd = getpwnam(user_name);
363
364 sysnerr( pwd != NULL((void*)0), "get user id");
18
Assuming 'pwd' is equal to null
365 llog = open (llog_file, O_RDWR02);
366
367 if (llog != -1) {
19
Taking true branch
368 struct lastlog ll;
369
370 sysnerr (lseek(llog, (long) pwd->pw_uid*sizeof(ll), 0)
20
Access to field 'pw_uid' results in a dereference of a null pointer (loaded from variable 'pwd')
371 != -1, "seeking lastlog entry");
372 memset(&ll, 0, sizeof(ll));
373 ll.ll_time = current_time;
374 if (line)
375 (void) strncpy (ll.ll_line, line, sizeof (ll.ll_line));
376 if (host_name)
377 (void) strncpy (ll.ll_host, host_name, sizeof (ll.ll_host));
378
379 sysnerr (write (llog, (char *) &ll, sizeof (ll))
380 == sizeof (ll), "write lastlog entry");
381 close (llog);
382 }
383 }
384#endif
385 return 0;
386}
387
388/*
389 * fill in the appropriate records of the utmp entry
390 */
391
392#ifdef USE_UTMP
393static void
394set_utmp (struct utmp *u, char *line, char *user, char *host, time_t date, int addp)
395{
396 memset (u, 0, sizeof (*u));
397 if (line)
398 (void) strncpy (u->ut_line, line, sizeof (u->ut_line));
399 else
400 memset (u->ut_line, 0, sizeof (u->ut_line));
401 if (addp && user)
402 (void) strncpy (u->ut_nameut_user, user, sizeof (u->ut_nameut_user));
403 else
404 memset (u->ut_nameut_user, 0, sizeof (u->ut_nameut_user));
405#ifdef HAVE_STRUCT_UTMP_UT_ID1
406 if (line) {
407 int i;
408 /*
409 * this is a bit crufty, but
410 * follows the apparent conventions in
411 * the ttys file. ut_id is only 4 bytes
412 * long, and the last 4 bytes of the line
413 * name are written into it, left justified.
414 */
415 i = strlen (line);
416 if (i >= sizeof (u->ut_id))
417 i -= sizeof (u->ut_id);
418 else
419 i = 0;
420 (void) strncpy (u->ut_id, line + i, sizeof (u->ut_id));
421 } else
422 memset (u->ut_id, 0, sizeof (u->ut_id));
423#endif
424#ifdef HAVE_STRUCT_UTMP_UT_PID1
425 if (addp)
426 u->ut_pid = getppid ();
427 else
428 u->ut_pid = 0;
429#endif
430#ifdef HAVE_STRUCT_UTMP_UT_TYPE1
431 if (addp)
432 u->ut_type = USER_PROCESS7;
433 else
434 u->ut_type = DEAD_PROCESS8;
435#endif
436#ifdef HAVE_STRUCT_UTMP_UT_HOST1
437 if (addp && host)
438 (void) strncpy (u->ut_host, host, sizeof (u->ut_host));
439 else
440 memset (u->ut_host, 0, sizeof (u->ut_host));
441#endif
442 u->ut_timeut_tv.tv_sec = date;
443}
444#endif /* USE_UTMP */
445
446#ifdef USE_UTMPX
447static int
448UtmpxIdOpen( char *utmpId )
449{
450 struct utmpx *u; /* pointer to entry in utmp file */
451 int status = 1; /* return code */
452
453 setutxent();
454
455 while ( (u = getutxent()) != NULL((void*)0) ) {
456
457 if ( (strncmp(u->ut_id, utmpId, 4) == 0 ) &&
458 u->ut_type != DEAD_PROCESS8 ) {
459
460 status = 0;
461 break;
462 }
463 }
464
465 endutxent();
466 return (status);
467}
468
469static void
470set_utmpx (struct utmpx *u, const char *line, const char *user,
471 const char *host, time_t date, int addp)
472{
473 static const char letters[] =
474 "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
475
476 if (line)
477 {
478 if(strcmp(line, ":0") == 0)
479 (void) strcpy(u->ut_line, "console");
480 else
481 (void) strncpy (u->ut_line, line, sizeof (u->ut_line));
482
483 strncpy(u->ut_host, line, sizeof(u->ut_host));
484#ifdef HAVE_STRUCT_UTMPX_UT_SYSLEN
485 u->ut_syslen = strlen(line);
486#endif
487 }
488 else
489 memset (u->ut_line, 0, sizeof (u->ut_line));
490 if (addp && user)
491 (void) strncpy (u->ut_user, user, sizeof (u->ut_user));
492 else
493 memset (u->ut_user, 0, sizeof (u->ut_user));
494
495 if (line) {
496 int i;
497 /*
498 * this is a bit crufty, but
499 * follows the apparent conventions in
500 * the ttys file. ut_id is only 4 bytes
501 * long, and the last 4 bytes of the line
502 * name are written into it, left justified.
503 */
504 i = strlen (line);
505 if (i >= sizeof (u->ut_id))
506 i -= sizeof (u->ut_id);
507 else
508 i = 0;
509 (void) strncpy (u->ut_id, line + i, sizeof (u->ut_id));
510
511 /* make sure there is no entry using identical ut_id */
512 if (!UtmpxIdOpen(u->ut_id) && addp) {
513 int limit = sizeof(letters) - 1;
514 int t = 0;
515
516 u->ut_id[1] = line[i];
517 u->ut_id[2] = line[i+1];
518 u->ut_id[3] = line[i+2];
519 do {
520 u->ut_id[0] = letters[t];
521 t++;
522 } while (!UtmpxIdOpen(u->ut_id) && (t < limit));
523 }
524 if (!addp && strstr(line, ":") != NULL((void*)0)) {
525 struct utmpx *tmpu;
526
527 while ( (tmpu = getutxent()) != NULL((void*)0) ) {
528 if ( (strcmp(tmpu->ut_host, line) == 0 ) &&
529 tmpu->ut_type != DEAD_PROCESS8 ) {
530 strncpy(u->ut_id, tmpu->ut_id,
531 sizeof(u->ut_id));
532 break;
533 }
534 }
535 endutxent();
536 }
537 } else
538 memset (u->ut_id, 0, sizeof (u->ut_id));
539
540 if (addp) {
541 u->ut_pid = getppid ();
542 u->ut_type = USER_PROCESS7;
543 } else {
544 u->ut_pid = 0;
545 u->ut_type = DEAD_PROCESS8;
546 }
547 u->ut_tv.tv_sec = date;
548 u->ut_tv.tv_usec = 0;
549}
550#endif /* USE_UTMPX */
551
552#if defined(USE_UTMP) && !defined(HAVE_PUTUTLINE1)
553/*
554 * compute the slot-number for an X display. This is computed
555 * by counting the lines in /etc/ttys and adding the line-number
556 * that the display appears on in Xservers. This is a poor
557 * design, but is limited by the non-existant interface to utmp.
558 * If host_name is non-NULL, assume it contains the display name,
559 * otherwise use the tty_line argument (i.e., the tty name).
560 */
561
562static int
563Xslot (char *ttys_file, char *servers_file, char *tty_line, char *host_name,
564 int addp)
565{
566 FILE *ttys, *servers;
567 int c;
568 int slot = 1;
569 int column0 = 1;
570 char servers_line[1024];
571 char disp_name[512];
572 int len;
573 char *pos;
574
575 /* remove screen number from the display name */
576 memset(disp_name, 0, sizeof(disp_name));
577 strncpy(disp_name, host_name ? host_name : tty_line, sizeof(disp_name)-1);
578 pos = strrchr(disp_name, ':');
579 if (pos) {
580 pos = strchr(pos, '.');
581 if (pos)
582 *pos = '\0';
583 }
584 sysnerr ((int)(long)(ttys = fopen (ttys_file, "r")), ttys_file);
585 while ((c = getc (ttys)_IO_getc (ttys)) != EOF(-1))
586 if (c == '\n') {
587 ++slot;
588 column0 = 1;
589 } else
590 column0 = 0;
591 if (!column0)
592 ++slot;
593 (void) fclose (ttys);
594 sysnerr ((int)(long)(servers = fopen (servers_file, "r")), servers_file);
595
596 len = strlen (disp_name);
597 column0 = 1;
598 while (fgets (servers_line, sizeof (servers_line), servers)) {
599 if (column0 && *servers_line != '#') {
600 if (!strncmp (disp_name, servers_line, len) &&
601 (servers_line[len] == ' ' ||
602 servers_line[len] == '\t'))
603 return slot;
604 ++slot;
605 }
606 if (servers_line[strlen(servers_line)-1] != '\n')
607 column0 = 0;
608 else
609 column0 = 1;
610 }
611 /*
612 * display not found in Xservers file - allocate utmp entry dinamically
613 */
614 return findslot (tty_line, host_name, addp, slot);
615}
616
617/*
618 * find a free utmp slot for the X display. This allocates a new entry
619 * past the regular tty entries if necessary, reusing existing entries
620 * (identified by (line,hostname)) if possible.
621 */
622static int
623findslot (char *line_name, char *host_name, int addp, int slot)
624{
625 int utmp;
626 struct utmp entry;
627 int found = 0;
628 int freeslot = -1;
629
630 syserr(utmp = open (utmp_file, O_RDONLY00), "open utmp");
631
632 /*
633 * first, try to locate a previous entry for this display
634 * also record location of a free slots in case we need a new one
635 */
636 syserr ((int) lseek (utmp, (long) slot * sizeof (struct utmp), 0), "lseek");
637
638 if (!host_name)
639 host_name = "";
640
641 while (read (utmp, (char *) &entry, sizeof (entry)) == sizeof (entry)) {
642 if (strncmp(entry.ut_line, line_name,
643 sizeof(entry.ut_line)) == 0
644#ifdef HAVE_STRUCT_UTMP_UT_HOST1
645 &&
646 strncmp(entry.ut_host, host_name,
647 sizeof(entry.ut_host)) == 0
648#endif
649 ) {
650 found = 1;
651 break;
652 }
653 if (freeslot < 0 && *entry.ut_nameut_user == '\0')
654 freeslot = slot;
655 ++slot;
656 }
657
658 close (utmp);
659
660 if (found)
661 return slot;
662 else if (!addp)
663 return 0; /* trying to delete a non-existing entry */
664 else if (freeslot < 0)
665 return slot; /* first slot past current entries */
666 else
667 return freeslot;
668}
669#endif