Bug Summary

File:src/usr.sbin/lpr/lpc/lpc.c
Warning:line 249, column 9
Null pointer passed as 1st argument to string length function

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple amd64-unknown-openbsd7.0 -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name lpc.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 1 -pic-is-pie -mframe-pointer=all -relaxed-aliasing -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -target-feature +retpoline-indirect-calls -target-feature +retpoline-indirect-branches -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/usr/src/usr.sbin/lpr/lpc/obj -resource-dir /usr/local/lib/clang/13.0.0 -I /usr/src/usr.sbin/lpr/lpc/../common_source -internal-isystem /usr/local/lib/clang/13.0.0/include -internal-externc-isystem /usr/include -O2 -fdebug-compilation-dir=/usr/src/usr.sbin/lpr/lpc/obj -ferror-limit 19 -fwrapv -D_RET_PROTECTOR -ret-protector -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-valloc -fno-builtin-free -fno-builtin-strdup -fno-builtin-strndup -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /home/ben/Projects/vmm/scan-build/2022-01-12-194120-40624-1 -x c /usr/src/usr.sbin/lpr/lpc/lpc.c
1/* $OpenBSD: lpc.c,v 1.20 2016/03/16 15:41:11 krw Exp $ */
2/* $NetBSD: lpc.c,v 1.11 2001/11/14 03:01:15 enami Exp $ */
3
4/*
5 * Copyright (c) 1983, 1993
6 * The Regents of the University of California. All rights reserved.
7 *
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34#include <dirent.h>
35#include <signal.h>
36#include <syslog.h>
37#include <unistd.h>
38#include <stdlib.h>
39#include <stdio.h>
40#include <err.h>
41#include <errno(*__errno()).h>
42#include <limits.h>
43#include <ctype.h>
44#include <string.h>
45#include <grp.h>
46
47#include "lp.h"
48#include "lpc.h"
49#include "extern.h"
50
51#ifndef LPR_OPER"operator"
52#define LPR_OPER"operator" "operator" /* group name of lpr operators */
53#endif
54
55/*
56 * lpc -- line printer control program
57 */
58
59#define MAX_CMDLINE200 200
60#define MAX_MARGV20 20
61int fromatty;
62
63char cmdline[MAX_CMDLINE200];
64int margc;
65char *margv[MAX_MARGV20];
66
67static void cmdscanner(void);
68static struct cmd *getcmd(char *);
69static void intr(int);
70static void makeargv(void);
71static int ingroup(char *);
72
73int
74main(int argc, char **argv)
75{
76 struct cmd *c;
77
78 effective_uid = geteuid();
79 real_uid = getuid();
80 effective_gid = getegid();
81 real_gid = getgid();
82 PRIV_ENDdo { int save_errno = (*__errno()); (void)setegid(real_gid); (
void)seteuid(real_uid); (*__errno()) = save_errno; } while (0
)
; /* be safe */
83
84 openlog("lpc", 0, LOG_LPR(6<<3));
85 if (--argc > 0) {
86 c = getcmd(*++argv);
87 if (c == (struct cmd *)-1) {
88 printf("?Ambiguous command\n");
89 exit(1);
90 }
91 if (c == 0) {
92 printf("?Invalid command\n");
93 exit(1);
94 }
95 if (c->c_priv && real_uid && ingroup(LPR_OPER"operator") == 0) {
96 printf("?Privileged command\n");
97 exit(1);
98 }
99 (*c->c_handler)(argc, argv);
100 exit(0);
101 }
102 fromatty = isatty(fileno(stdin)(!__isthreaded ? (((&__sF[0]))->_file) : (fileno)((&
__sF[0])))
);
103 signal(SIGINT2, intr);
104 for (;;)
105 cmdscanner();
106}
107
108volatile sig_atomic_t gotintr;
109
110static void
111intr(int signo)
112{
113 if (!fromatty)
114 _exit(0);
115 gotintr = 1;
116}
117
118/*
119 * Command parser.
120 */
121static void
122cmdscanner(void)
123{
124 struct cmd *c;
125
126 for (;;) {
127 if (gotintr) {
128 putchar('\n')(!__isthreaded ? __sputc('\n', (&__sF[1])) : (putc)('\n',
(&__sF[1])))
;
129 gotintr = 0;
130 }
131 if (fromatty) {
132 printf("lpc> ");
133 fflush(stdout(&__sF[1]));
134 }
135
136 siginterrupt(SIGINT2, 1);
137 if (fgets(cmdline, MAX_CMDLINE200, stdin(&__sF[0])) == NULL((void *)0)) {
138 if (errno(*__errno()) == EINTR4 && gotintr) {
139 siginterrupt(SIGINT2, 0);
140 return;
141 }
142 siginterrupt(SIGINT2, 0);
143 quit(0, NULL((void *)0));
144 }
145 siginterrupt(SIGINT2, 0);
146
147 makeargv();
148 if (margc == 0)
149 break;
150 c = getcmd(margv[0]);
151 if (c == (struct cmd *)-1) {
152 printf("?Ambiguous command\n");
153 continue;
154 }
155 if (c == 0) {
156 printf("?Invalid command\n");
157 continue;
158 }
159 if (c->c_priv && getuid() && ingroup(LPR_OPER"operator") == 0) {
160 printf("?Privileged command\n");
161 continue;
162 }
163 (*c->c_handler)(margc, margv);
164 }
165}
166
167static struct cmd *
168getcmd(char *name)
169{
170 char *p, *q;
171 struct cmd *c, *found;
172 int nmatches, longest;
173
174 longest = 0;
175 nmatches = 0;
176 found = 0;
177 for (c = cmdtab; (p = c->c_name) != NULL((void *)0); c++) {
178 for (q = name; *q == *p++; q++)
179 if (*q == 0) /* exact match? */
180 return(c);
181 if (!*q) { /* the name was a prefix */
182 if (q - name > longest) {
183 longest = q - name;
184 nmatches = 1;
185 found = c;
186 } else if (q - name == longest)
187 nmatches++;
188 }
189 }
190 if (nmatches > 1)
191 return((struct cmd *)-1);
192 return(found);
193}
194
195/*
196 * Slice a string up into argc/argv.
197 */
198static void
199makeargv(void)
200{
201 char *cp = cmdline;
202 char **ap = margv;
203
204 margc = 0;
205 while (margc < MAX_MARGV20 - 1 && (*ap = strsep(&cp, " \t\n")) != NULL((void *)0)) {
206 if (**ap != '\0') {
207 ap++;
208 margc++;
209 }
210 }
211 *ap = NULL((void *)0);
212}
213
214#define HELPINDENT((int)sizeof("directory")) ((int)sizeof("directory"))
215
216/*
217 * Help command.
218 */
219void
220help(int argc, char **argv)
221{
222 struct cmd *c;
223
224 if (argc == 1) {
1
Assuming 'argc' is equal to 1
2
Taking true branch
225 int i, j, w;
226 int columns, width = 0, lines;
227
228 printf("Commands may be abbreviated. Commands are:\n\n");
229 for (c = cmdtab; c->c_name; c++) {
3
Assuming pointer value is null
4
Loop condition is false. Execution continues on line 235
230 int len = strlen(c->c_name);
231
232 if (len > width)
233 width = len;
234 }
235 width = (width + 8) &~ 7;
236 columns = 80 / width;
237 if (columns
4.1
'columns' is not equal to 0
== 0)
5
Taking false branch
238 columns = 1;
239 lines = (NCMDS + columns - 1) / columns;
240 for (i = 0; i < lines; i++) {
6
Assuming 'i' is < 'lines'
7
Loop condition is true. Entering loop body
241 for (j = 0; j < columns; j++) {
8
Loop condition is true. Entering loop body
242 c = cmdtab + j * lines + i;
243 if (c->c_name
8.1
Field 'c_name' is null
)
9
Taking false branch
244 printf("%s", c->c_name);
245 if (c + lines >= &cmdtab[NCMDS]) {
10
Assuming the condition is false
11
Taking false branch
246 printf("\n");
247 break;
248 }
249 w = strlen(c->c_name);
12
Null pointer passed as 1st argument to string length function
250 while (w < width) {
251 w = (w + 8) &~ 7;
252 putchar('\t')(!__isthreaded ? __sputc('\t', (&__sF[1])) : (putc)('\t',
(&__sF[1])))
;
253 }
254 }
255 }
256 return;
257 }
258 while (--argc > 0) {
259 char *arg;
260
261 arg = *++argv;
262 c = getcmd(arg);
263 if (c == (struct cmd *)-1)
264 printf("?Ambiguous help command %s\n", arg);
265 else if (c == NULL((void *)0))
266 printf("?Invalid help command %s\n", arg);
267 else
268 printf("%-*s\t%s\n", HELPINDENT((int)sizeof("directory")),
269 c->c_name, c->c_help);
270 }
271}
272
273/*
274 * return non-zero if the user is a member of the given group
275 */
276static int
277ingroup(char *grname)
278{
279 static struct group *gptr = NULL((void *)0);
280 static gid_t groups[NGROUPS_MAX16];
281 static int ngroups;
282 gid_t gid;
283 int i;
284
285 if (gptr == NULL((void *)0)) {
286 if ((gptr = getgrnam(grname)) == NULL((void *)0)) {
287 warnx("Warning: unknown group `%s'", grname);
288 return(0);
289 }
290 if ((ngroups = getgroups(NGROUPS_MAX16, groups)) < 0)
291 err(1, "getgroups");
292 }
293 gid = gptr->gr_gid;
294 for (i = 0; i < ngroups; i++)
295 if (gid == groups[i])
296 return(1);
297 return(0);
298}