Bug Summary

File:sessreg.c
Location:line 363, 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
102static int utmp_none, wtmp_none;
103/*
104 * BSD specific variables. To make life much easier for Xstartup/Xreset
105 * maintainers, these arguments are accepted but ignored for sysV
106 */
107static int hflag, xflag, tflag;
108static char *host_name = NULL((void*)0);
109#if defined(USE_UTMP) && !defined(HAVE_PUTUTLINE1)
110static int sflag;
111static int slot_number;
112#endif
113static char *xservers_file, *ttys_file;
114static char *user_name;
115static int aflag, dflag;
116#ifdef USE_LASTLOG
117static const char *llog_file;
118static int llog_none, Lflag;
119#endif
120
121static char *program_name;
122
123#if defined(USE_UTMP) && !defined(HAVE_PUTUTLINE1)
124static int findslot (char *line_name, char *host_name, int addp, int slot);
125static int Xslot (char *ttys_file, char *servers_file, char *tty_line,
126 char *host_name, int addp);
127#endif
128
129static int
130usage (int x)
131{
132 if (x) {
133 fprintf (stderrstderr, "%s: usage %s {-a -d} [-w wtmp-file] [-u utmp-file]", program_name, program_name);
134#ifdef USE_LASTLOG
135 fprintf (stderrstderr, " [-L lastlog-file]");
136#endif
137 fprintf (stderrstderr, "\n");
138 fprintf (stderrstderr, " [-t ttys-file] [-l line-name] [-h host-name]\n");
139 fprintf (stderrstderr, " [-s slot-number] [-x servers-file] user-name\n");
140 exit (1);
141 }
142 return x;
143}
144
145static char *
146getstring (char ***avp, int *flagp)
147{
148 char **a = *avp;
149
150 usage ((*flagp)++);
151 if (*++*a)
152 return *a;
153 ++a;
154 usage (!*a);
155 *avp = a;
156 return *a;
157}
158
159#if defined(USE_UTMP) && !defined(HAVE_PUTUTLINE1)
160static int
161syserr (int x, const char *s)
162{
163 if (x == -1) {
164 perror (s);
165 exit (1);
166 }
167 return x;
168}
169#endif
170
171static int
172sysnerr (int x, const char *s)
173{
174 if (x == 0) {
175 perror (s);
176 exit (1);
177 }
178 return x;
179}
180
181int
182main (int argc, char **argv)
183{
184#if defined(USE_UTMP) && !defined(HAVE_PUTUTLINE1)
185 int utmp;
186#endif
187#ifndef USE_UTMPX
188 int wtmp;
189#endif
190 time_t current_time;
191#ifdef USE_UTMP
192 struct utmp utmp_entry;
193#endif
194#ifdef USE_UTMPX
195 struct utmpx utmpx_entry;
196#endif
197
198 program_name = argv[0];
199 while (*++argv && **argv == '-') {
1
Loop condition is false. Execution continues on line 245
200 switch (*++*argv) {
201 case 'w':
202 wtmp_file = getstring (&argv, &wflag);
203 if (!strcmp (wtmp_file, "none"))
204 wtmp_none = 1;
205 break;
206 case 'u':
207 utmp_file = getstring (&argv, &uflag);
208 if (!strcmp (utmp_file, "none"))
209 utmp_none = 1;
210 break;
211#ifdef USE_LASTLOG
212 case 'L':
213 llog_file = getstring (&argv, &Lflag);
214 if (!strcmp (llog_file, "none"))
215 llog_none = 1;
216 break;
217#endif
218 case 't':
219 ttys_file = getstring (&argv, &tflag);
220 break;
221 case 'l':
222 line = getstring (&argv, &lflag);
223 break;
224 case 'h':
225 host_name = getstring (&argv, &hflag);
226 break;
227 case 's':
228#if defined(USE_UTMP) && !defined(HAVE_PUTUTLINE1)
229 slot_number = atoi (getstring (&argv, &sflag));
230#endif
231 break;
232 case 'x':
233 xservers_file = getstring (&argv, &xflag);
234 break;
235 case 'a':
236 aflag++;
237 break;
238 case 'd':
239 dflag++;
240 break;
241 default:
242 usage (1);
243 }
244 }
245 usage (!(user_name = *argv++));
246 usage (*argv != NULL((void*)0));
247 /*
248 * complain if neither aflag nor dflag are set,
249 * or if both are set.
250 */
251 usage (!(aflag ^ dflag));
252 usage (xflag && !lflag);
253 /* set up default file names */
254 if (!wflag) {
2
Assuming 'wflag' is not equal to 0
3
Taking false branch
255 wtmp_file = WTMP_FILE"/var/log/wtmp";
256#if defined(USE_UTMPX) && defined(HAVE_UPDWTMPX1)
257 wtmpx_file = WTMPX_FILE"/var/log/wtmp";
258#endif
259 }
260#ifndef NO_UTMP
261 if (!uflag) {
4
Assuming 'uflag' is not equal to 0
5
Taking false branch
262 utmp_file = UTMP_FILE"/var/run/utmp";
263#if defined(USE_UTMPX) && defined(HAVE_UTMPXNAME1)
264 utmpx_file = UTMPX_FILE"/var/run/utmp";
265#endif
266 }
267#else
268 utmp_none = 1;
269#endif
270#ifdef USE_LASTLOG
271 if (!Lflag)
6
Assuming 'Lflag' is not equal to 0
7
Taking false branch
272 llog_file = LLOG_FILE"/var/log/lastlog";
273#endif
274#if defined(USE_UTMP) && !defined(HAVE_PUTUTLINE1)
275 if (!tflag)
276 ttys_file = TTYS_FILE"/etc/ttys";
277 if (!sflag && !utmp_none) {
278 if (xflag)
279 sysnerr (slot_number = Xslot (ttys_file, xservers_file, line, host_name, aflag), "Xslot");
280 else
281 sysnerr (slot_number = ttyslot (), "ttyslot");
282 }
283#endif
284 if (!lflag) {
8
Assuming 'lflag' is not equal to 0
9
Taking false branch
285 sysnerr ((line = ttyname (0)) != NULL((void*)0), "ttyname");
286 if (strncmp(line, "/dev/", 5) == 0)
287 line += 5;
288 }
289 time (&current_time);
290#ifdef USE_UTMP
291 set_utmp (&utmp_entry, line, user_name, host_name, current_time, aflag);
292#endif
293
294#ifdef USE_UTMPX
295 /* need to set utmpxname() before calling set_utmpx() for
296 UtmpxIdOpen to work */
297# ifdef HAVE_UTMPXNAME1
298 if (utmpx_file != NULL((void*)0)) {
10
Assuming 'utmpx_file' is equal to null
11
Taking false branch
299 utmpxname (utmpx_file);
300 }
301# endif
302 set_utmpx (&utmpx_entry, line, user_name,
303 host_name, current_time, aflag);
304#endif
305
306 if (!utmp_none) {
12
Assuming 'utmp_none' is not equal to 0
13
Taking false branch
307#ifdef USE_UTMPX
308# ifdef HAVE_UTMPXNAME1
309 if (utmpx_file != NULL((void*)0))
310# endif
311 {
312 setutxent ();
313 (void) getutxid (&utmpx_entry);
314 pututxline (&utmpx_entry);
315 endutxent ();
316 }
317#endif
318#ifdef USE_UTMP
319# ifdef HAVE_PUTUTLINE1
320 utmpname (utmp_file);
321 setutent ();
322 (void) getutid (&utmp_entry);
323 pututline (&utmp_entry);
324 endutent ();
325# else
326 utmp = open (utmp_file, O_RDWR02);
327 if (utmp != -1) {
328 syserr ((int) lseek (utmp, (long) slot_number * sizeof (struct utmp), 0), "lseek");
329 sysnerr (write (utmp, (char *) &utmp_entry, sizeof (utmp_entry))
330 == sizeof (utmp_entry), "write utmp entry");
331 close (utmp);
332 }
333# endif
334#endif /* USE_UTMP */
335 }
336 if (!wtmp_none) {
14
Assuming 'wtmp_none' is not equal to 0
15
Taking false branch
337#ifdef USE_UTMPX
338# ifdef HAVE_UPDWTMPX1
339 if (wtmpx_file != NULL((void*)0)) {
340 updwtmpx(wtmpx_file, &utmpx_entry);
341 }
342# endif
343#else
344 wtmp = open (wtmp_file, O_WRONLY01|O_APPEND02000);
345 if (wtmp != -1) {
346 sysnerr (write (wtmp, (char *) &utmp_entry, sizeof (utmp_entry))
347 == sizeof (utmp_entry), "write wtmp entry");
348 close (wtmp);
349 }
350#endif
351 }
352#ifdef USE_LASTLOG
353 if (aflag && !llog_none) {
16
Assuming 'llog_none' is 0
17
Taking true branch
354 int llog;
355 struct passwd *pwd = getpwnam(user_name);
356
357 sysnerr( pwd != NULL((void*)0), "get user id");
18
Assuming 'pwd' is equal to null
358 llog = open (llog_file, O_RDWR02);
359
360 if (llog != -1) {
19
Taking true branch
361 struct lastlog ll;
362
363 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')
364 != -1, "seeking lastlog entry");
365 memset(&ll, 0, sizeof(ll));
366 ll.ll_time = current_time;
367 if (line)
368 (void) strncpy (ll.ll_line, line, sizeof (ll.ll_line));
369 if (host_name)
370 (void) strncpy (ll.ll_host, host_name, sizeof (ll.ll_host));
371
372 sysnerr (write (llog, (char *) &ll, sizeof (ll))
373 == sizeof (ll), "write lastlog entry");
374 close (llog);
375 }
376 }
377#endif
378 return 0;
379}
380
381/*
382 * fill in the appropriate records of the utmp entry
383 */
384
385#ifdef USE_UTMP
386static void
387set_utmp (struct utmp *u, char *line, char *user, char *host, time_t date, int addp)
388{
389 memset (u, 0, sizeof (*u));
390 if (line)
391 (void) strncpy (u->ut_line, line, sizeof (u->ut_line));
392 else
393 memset (u->ut_line, 0, sizeof (u->ut_line));
394 if (addp && user)
395 (void) strncpy (u->ut_nameut_user, user, sizeof (u->ut_nameut_user));
396 else
397 memset (u->ut_nameut_user, 0, sizeof (u->ut_nameut_user));
398#ifdef HAVE_STRUCT_UTMP_UT_ID1
399 if (line) {
400 int i;
401 /*
402 * this is a bit crufty, but
403 * follows the apparent conventions in
404 * the ttys file. ut_id is only 4 bytes
405 * long, and the last 4 bytes of the line
406 * name are written into it, left justified.
407 */
408 i = strlen (line);
409 if (i >= sizeof (u->ut_id))
410 i -= sizeof (u->ut_id);
411 else
412 i = 0;
413 (void) strncpy (u->ut_id, line + i, sizeof (u->ut_id));
414 } else
415 memset (u->ut_id, 0, sizeof (u->ut_id));
416#endif
417#ifdef HAVE_STRUCT_UTMP_UT_PID1
418 if (addp)
419 u->ut_pid = getppid ();
420 else
421 u->ut_pid = 0;
422#endif
423#ifdef HAVE_STRUCT_UTMP_UT_TYPE1
424 if (addp)
425 u->ut_type = USER_PROCESS7;
426 else
427 u->ut_type = DEAD_PROCESS8;
428#endif
429#ifdef HAVE_STRUCT_UTMP_UT_HOST1
430 if (addp && host)
431 (void) strncpy (u->ut_host, host, sizeof (u->ut_host));
432 else
433 memset (u->ut_host, 0, sizeof (u->ut_host));
434#endif
435 u->ut_timeut_tv.tv_sec = date;
436}
437#endif /* USE_UTMP */
438
439#ifdef USE_UTMPX
440static int
441UtmpxIdOpen( char *utmpId )
442{
443 struct utmpx *u; /* pointer to entry in utmp file */
444 int status = 1; /* return code */
445
446 setutxent();
447
448 while ( (u = getutxent()) != NULL((void*)0) ) {
449
450 if ( (strncmp(u->ut_id, utmpId, 4) == 0 ) &&
451 u->ut_type != DEAD_PROCESS8 ) {
452
453 status = 0;
454 break;
455 }
456 }
457
458 endutxent();
459 return (status);
460}
461
462static void
463set_utmpx (struct utmpx *u, const char *line, const char *user,
464 const char *host, time_t date, int addp)
465{
466 static const char letters[] =
467 "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
468
469 if (line)
470 {
471 if(strcmp(line, ":0") == 0)
472 (void) strcpy(u->ut_line, "console");
473 else
474 (void) strncpy (u->ut_line, line, sizeof (u->ut_line));
475
476 strncpy(u->ut_host, line, sizeof(u->ut_host));
477#ifdef HAVE_STRUCT_UTMPX_UT_SYSLEN
478 u->ut_syslen = strlen(line);
479#endif
480 }
481 else
482 memset (u->ut_line, 0, sizeof (u->ut_line));
483 if (addp && user)
484 (void) strncpy (u->ut_user, user, sizeof (u->ut_user));
485 else
486 memset (u->ut_user, 0, sizeof (u->ut_user));
487
488 if (line) {
489 int i;
490 /*
491 * this is a bit crufty, but
492 * follows the apparent conventions in
493 * the ttys file. ut_id is only 4 bytes
494 * long, and the last 4 bytes of the line
495 * name are written into it, left justified.
496 */
497 i = strlen (line);
498 if (i >= sizeof (u->ut_id))
499 i -= sizeof (u->ut_id);
500 else
501 i = 0;
502 (void) strncpy (u->ut_id, line + i, sizeof (u->ut_id));
503
504 /* make sure there is no entry using identical ut_id */
505 if (!UtmpxIdOpen(u->ut_id) && addp) {
506 int limit = sizeof(letters) - 1;
507 int t = 0;
508
509 u->ut_id[1] = line[i];
510 u->ut_id[2] = line[i+1];
511 u->ut_id[3] = line[i+2];
512 do {
513 u->ut_id[0] = letters[t];
514 t++;
515 } while (!UtmpxIdOpen(u->ut_id) && (t < limit));
516 }
517 if (!addp && strstr(line, ":") != NULL((void*)0)) {
518 struct utmpx *tmpu;
519
520 while ( (tmpu = getutxent()) != NULL((void*)0) ) {
521 if ( (strcmp(tmpu->ut_host, line) == 0 ) &&
522 tmpu->ut_type != DEAD_PROCESS8 ) {
523 strncpy(u->ut_id, tmpu->ut_id,
524 sizeof(u->ut_id));
525 break;
526 }
527 }
528 endutxent();
529 }
530 } else
531 memset (u->ut_id, 0, sizeof (u->ut_id));
532
533 if (addp) {
534 u->ut_pid = getppid ();
535 u->ut_type = USER_PROCESS7;
536 } else {
537 u->ut_pid = 0;
538 u->ut_type = DEAD_PROCESS8;
539 }
540 u->ut_tv.tv_sec = date;
541 u->ut_tv.tv_usec = 0;
542}
543#endif /* USE_UTMPX */
544
545#if defined(USE_UTMP) && !defined(HAVE_PUTUTLINE1)
546/*
547 * compute the slot-number for an X display. This is computed
548 * by counting the lines in /etc/ttys and adding the line-number
549 * that the display appears on in Xservers. This is a poor
550 * design, but is limited by the non-existant interface to utmp.
551 * If host_name is non-NULL, assume it contains the display name,
552 * otherwise use the tty_line argument (i.e., the tty name).
553 */
554
555static int
556Xslot (char *ttys_file, char *servers_file, char *tty_line, char *host_name,
557 int addp)
558{
559 FILE *ttys, *servers;
560 int c;
561 int slot = 1;
562 int column0 = 1;
563 char servers_line[1024];
564 char disp_name[512];
565 int len;
566 char *pos;
567
568 /* remove screen number from the display name */
569 memset(disp_name, 0, sizeof(disp_name));
570 strncpy(disp_name, host_name ? host_name : tty_line, sizeof(disp_name)-1);
571 pos = strrchr(disp_name, ':');
572 if (pos) {
573 pos = strchr(pos, '.');
574 if (pos)
575 *pos = '\0';
576 }
577 sysnerr ((int)(long)(ttys = fopen (ttys_file, "r")), ttys_file);
578 while ((c = getc (ttys)_IO_getc (ttys)) != EOF(-1))
579 if (c == '\n') {
580 ++slot;
581 column0 = 1;
582 } else
583 column0 = 0;
584 if (!column0)
585 ++slot;
586 (void) fclose (ttys);
587 sysnerr ((int)(long)(servers = fopen (servers_file, "r")), servers_file);
588
589 len = strlen (disp_name);
590 column0 = 1;
591 while (fgets (servers_line, sizeof (servers_line), servers)) {
592 if (column0 && *servers_line != '#') {
593 if (!strncmp (disp_name, servers_line, len) &&
594 (servers_line[len] == ' ' ||
595 servers_line[len] == '\t'))
596 return slot;
597 ++slot;
598 }
599 if (servers_line[strlen(servers_line)-1] != '\n')
600 column0 = 0;
601 else
602 column0 = 1;
603 }
604 /*
605 * display not found in Xservers file - allocate utmp entry dinamically
606 */
607 return findslot (tty_line, host_name, addp, slot);
608}
609
610/*
611 * find a free utmp slot for the X display. This allocates a new entry
612 * past the regular tty entries if necessary, reusing existing entries
613 * (identified by (line,hostname)) if possible.
614 */
615static int
616findslot (char *line_name, char *host_name, int addp, int slot)
617{
618 int utmp;
619 struct utmp entry;
620 int found = 0;
621 int freeslot = -1;
622
623 syserr(utmp = open (utmp_file, O_RDONLY00), "open utmp");
624
625 /*
626 * first, try to locate a previous entry for this display
627 * also record location of a free slots in case we need a new one
628 */
629 syserr ((int) lseek (utmp, (long) slot * sizeof (struct utmp), 0), "lseek");
630
631 if (!host_name)
632 host_name = "";
633
634 while (read (utmp, (char *) &entry, sizeof (entry)) == sizeof (entry)) {
635 if (strncmp(entry.ut_line, line_name,
636 sizeof(entry.ut_line)) == 0
637#ifdef HAVE_STRUCT_UTMP_UT_HOST1
638 &&
639 strncmp(entry.ut_host, host_name,
640 sizeof(entry.ut_host)) == 0
641#endif
642 ) {
643 found = 1;
644 break;
645 }
646 if (freeslot < 0 && *entry.ut_nameut_user == '\0')
647 freeslot = slot;
648 ++slot;
649 }
650
651 close (utmp);
652
653 if (found)
654 return slot;
655 else if (!addp)
656 return 0; /* trying to delete a non-existing entry */
657 else if (freeslot < 0)
658 return slot; /* first slot past current entries */
659 else
660 return freeslot;
661}
662#endif