clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name nsinstall.c -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 -analyzer-config-compatibility-mode=true -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/var/lib/jenkins/workspace/nss-scan-build/nss/coreconf/nsinstall -ffunction-sections -fdata-sections -fcoverage-compilation-dir=/var/lib/jenkins/workspace/nss-scan-build/nss/coreconf/nsinstall -resource-dir /usr/lib/llvm-18/lib/clang/18 -D HAVE_STRERROR -D LINUX -D linux -D XP_UNIX -D XP_UNIX -D DEBUG -U NDEBUG -D _DEFAULT_SOURCE -D _BSD_SOURCE -D _POSIX_SOURCE -D SDB_MEASURE_USE_TEMP_DIR -D _REENTRANT -D DEBUG -U NDEBUG -D _DEFAULT_SOURCE -D _BSD_SOURCE -D _POSIX_SOURCE -D SDB_MEASURE_USE_TEMP_DIR -D _REENTRANT -D NSS_DISABLE_SSE3 -D NSS_NO_INIT_SUPPORT -D USE_UTIL_DIRECTLY -D NO_NSPR_10_SUPPORT -D SSL_DISABLE_DEPRECATED_CIPHER_SUITE_NAMES -I ../../../dist/Linux4.19_x86_64_gcc_glibc_PTH_64_DBG.OBJ/include -I ../../../dist/public/coreconf -I ../../../dist/private/coreconf -internal-isystem /usr/lib/llvm-18/lib/clang/18/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -std=c99 -ferror-limit 19 -fgnuc-version=4.2.1 -analyzer-output=html -analyzer-config stable-report-filename=true -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /tmp/scan-build-2024-05-18-082241-28900-1 -x c nsinstall.c
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | #include <stdio.h> /* OSF/1 requires this before grp.h, so put it first */ |
9 | #include <assert.h> |
10 | #include <fcntl.h> |
11 | #include <string.h> |
12 | #if defined(_WINDOWS) |
13 | #include <windows.h> |
14 | typedef unsigned int mode_t; |
15 | #else |
16 | #include <grp.h> |
17 | #include <pwd.h> |
18 | #include <errno.h> |
19 | #include <stdlib.h> |
20 | #include <unistd.h> |
21 | #include <utime.h> |
22 | #endif |
23 | #include <sys/types.h> |
24 | #include <sys/stat.h> |
25 | #include "pathsub.h" |
26 | |
27 | #define HAVE_LCHOWN |
28 | |
29 | #if defined(AIX) || defined(BSDI) || defined(HPUX) || defined(LINUX) || defined(SUNOS4) || defined(SCO) || defined(UNIXWARE) || defined(NTO) || defined(DARWIN) || defined(__riscos__) |
30 | #undef HAVE_LCHOWN |
31 | #endif |
32 | |
33 | #define HAVE_FCHMOD |
34 | |
35 | #ifdef LINUX |
36 | #include <getopt.h> |
37 | #endif |
38 | |
39 | #if defined(SCO) || defined(UNIXWARE) || defined(SNI) || defined(NCR) || defined(NEC) |
40 | #if !defined(S_ISLNK) && defined(S_IFLNK) |
41 | #define S_ISLNK(a) (((a) & S_IFMT) == S_IFLNK) |
42 | #endif |
43 | #endif |
44 | |
45 | #if defined(SNI) |
46 | extern int fchmod(int fildes, mode_t mode); |
47 | #endif |
48 | |
49 | |
50 | #ifdef GETCWD_CANT_MALLOC |
51 | |
52 | |
53 | |
54 | |
55 | static char * |
56 | getcwd_do_malloc(char *path, int len) { |
57 | |
58 | if (!path) { |
59 | path = malloc(PATH_MAX +1); |
60 | if (!path) return NULL; |
61 | } |
62 | return getcwd(path, PATH_MAX); |
63 | } |
64 | #define GETCWD getcwd_do_malloc |
65 | #else |
66 | #define GETCWD getcwd |
67 | #endif |
68 | |
69 | |
70 | static void |
71 | usage(void) |
72 | { |
73 | fprintf(stderr, |
74 | "usage: %s [-C cwd] [-L linkprefix] [-m mode] [-o owner] [-g group]\n" |
75 | " %*s [-DdltR] file [file ...] directory\n", |
76 | program, (int)strlen(program), ""); |
77 | exit(2); |
78 | } |
79 | |
80 | |
81 | static int |
82 | mkdirs(char *path, mode_t mode) |
83 | { |
84 | char * cp; |
85 | int rv; |
86 | struct stat sb; |
87 | |
88 | if (!path || !path[0]) |
89 | fail("Null pointer or empty string passed to mkdirs()"); |
90 | while (*path == '/' && path[1] == '/') |
91 | path++; |
92 | for (cp = strrchr(path, '/'); cp && cp != path && *(cp - 1) == '/'; cp--); |
93 | if (cp && cp != path) { |
94 | *cp = '\0'; |
95 | if ((stat(path, &sb) < 0 || !S_ISDIR(sb.st_mode)) && |
96 | mkdirs(path, mode) < 0) { |
97 | return -1; |
98 | } |
99 | *cp = '/'; |
100 | } |
101 | rv = mkdir(path, mode); |
102 | if (rv) { |
103 | if (errno != EEXIST) |
104 | fail("mkdirs cannot make %s", path); |
105 | fprintf(stderr, "directory creation race: %s\n", path); |
106 | if (!stat(path, &sb) && S_ISDIR(sb.st_mode)) |
107 | rv = 0; |
108 | } |
109 | return rv; |
110 | } |
111 | |
112 | static uid_t |
113 | touid(char *owner) |
114 | { |
115 | struct passwd *pw; |
116 | uid_t uid; |
117 | char *cp; |
118 | |
119 | if (!owner || !owner[0]) |
120 | fail("Null pointer or empty string passed to touid()"); |
121 | pw = getpwnam(owner); |
122 | if (pw) |
123 | return pw->pw_uid; |
124 | uid = strtol(owner, &cp, 0); |
125 | if (uid == 0 && cp == owner) |
126 | fail("cannot find uid for %s", owner); |
127 | return uid; |
128 | } |
129 | |
130 | static gid_t |
131 | togid(char *group) |
132 | { |
133 | struct group *gr; |
134 | gid_t gid; |
135 | char *cp; |
136 | |
137 | if (!group || !group[0]) |
138 | fail("Null pointer or empty string passed to togid()"); |
139 | gr = getgrnam(group); |
140 | if (gr) |
141 | return gr->gr_gid; |
142 | gid = strtol(group, &cp, 0); |
143 | if (gid == 0 && cp == group) |
144 | fail("cannot find gid for %s", group); |
145 | return gid; |
146 | } |
147 | |
148 | void * const uninit = (void *)0xdeadbeef; |
149 | |
150 | int |
151 | main(int argc, char **argv) |
152 | { |
153 | char * base = uninit; |
154 | char * bp = uninit; |
155 | char * cp = uninit; |
156 | char * cwd = 0; |
157 | char * group = 0; |
158 | char * linkname = 0; |
159 | char * linkprefix = 0; |
160 | char * name = uninit; |
161 | char * owner = 0; |
162 | char * todir = uninit; |
163 | char * toname = uninit; |
164 | |
165 | int bnlen = -1; |
166 | int cc = 0; |
167 | int dodir = 0; |
168 | int dolink = 0; |
169 | int dorelsymlink = 0; |
170 | int dotimes = 0; |
171 | int exists = 0; |
172 | int fromfd = -1; |
173 | int len = -1; |
174 | int lplen = 0; |
175 | int onlydir = 0; |
176 | int opt = -1; |
177 | int tdlen = -1; |
178 | int tofd = -1; |
179 | int wc = -1; |
180 | |
181 | mode_t mode = 0755; |
182 | |
183 | uid_t uid = -1; |
184 | gid_t gid = -1; |
185 | |
186 | struct stat sb; |
187 | struct stat tosb; |
188 | struct utimbuf utb; |
189 | char buf[BUFSIZ]; |
190 | |
191 | program = strrchr(argv[0], '/'); |
192 | if (!program) |
| 1 | Assuming 'program' is non-null | |
|
193 | program = strrchr(argv[0], '\\'); |
194 | program = program ? program+1 : argv[0]; |
| |
| |
195 | |
196 | |
197 | while ((opt = getopt(argc, argv, "C:DdlL:Rm:o:g:t")) != EOF) { |
| 4 | | Assuming the condition is false | |
|
| 5 | | Loop condition is false. Execution continues on line 221 | |
|
198 | switch (opt) { |
199 | case 'C': cwd = optarg; break; |
200 | case 'D': onlydir = 1; break; |
201 | case 'd': dodir = 1; break; |
202 | case 'l': dolink = 1; break; |
203 | case 'L': |
204 | linkprefix = optarg; |
205 | lplen = strlen(linkprefix); |
206 | dolink = 1; |
207 | break; |
208 | case 'R': dolink = dorelsymlink = 1; break; |
209 | case 'm': |
210 | mode = strtoul(optarg, &cp, 8); |
211 | if (mode == 0 && cp == optarg) |
212 | usage(); |
213 | break; |
214 | case 'o': owner = optarg; break; |
215 | case 'g': group = optarg; break; |
216 | case 't': dotimes = 1; break; |
217 | default: usage(); |
218 | } |
219 | } |
220 | |
221 | argc -= optind; |
222 | argv += optind; |
223 | if (argc < 2 - onlydir) |
| 6 | | Assuming the condition is false | |
|
| |
224 | usage(); |
225 | |
226 | todir = argv[argc-1]; |
227 | if ((stat(todir, &sb) < 0 || !S_ISDIR(sb.st_mode)) && |
| 8 | | Assuming the condition is false | |
|
| 9 | | Assuming the condition is true | |
|
228 | mkdirs(todir, 0777) < 0) { |
229 | fail("cannot mkdir -p %s", todir); |
230 | } |
231 | if (onlydir) |
| |
232 | return 0; |
233 | |
234 | if (!cwd) { |
| |
235 | cwd = GETCWD(0, PATH_MAX); |
236 | if (!cwd) |
| 12 | | Assuming 'cwd' is non-null | |
|
| |
237 | fail("could not get CWD"); |
238 | } |
239 | |
240 | |
241 | xchdir(todir); |
242 | todir = GETCWD(0, PATH_MAX); |
| 14 | | Value assigned to 'todir' | |
|
243 | if (!todir) |
| 15 | | Assuming 'todir' is null | |
|
| |
244 | fail("could not get CWD in todir"); |
245 | tdlen = strlen(todir); |
| 17 | | Null pointer passed to 1st parameter expecting 'nonnull' |
|
246 | |
247 | |
248 | xchdir(cwd); |
249 | |
250 | uid = owner ? touid(owner) : -1; |
251 | gid = group ? togid(group) : -1; |
252 | |
253 | while (--argc > 0) { |
254 | name = *argv++; |
255 | len = strlen(name); |
256 | base = xbasename(name); |
257 | bnlen = strlen(base); |
258 | size_t toname_len = tdlen + 1 + bnlen + 1; |
259 | toname = (char*)xmalloc(toname_len); |
260 | snprintf(toname, toname_len, "%s/%s", todir, base); |
261 | retry: |
262 | exists = (lstat(toname, &tosb) == 0); |
263 | |
264 | if (dodir) { |
265 | |
266 | if (exists && !S_ISDIR(tosb.st_mode)) { |
267 | int rv = unlink(toname); |
268 | if (rv) |
269 | fail("cannot unlink %s", toname); |
270 | exists = 0; |
271 | } |
272 | if (!exists && mkdir(toname, mode) < 0) { |
273 | |
274 | if (errno == EEXIST && !stat(toname, &sb) && |
275 | S_ISDIR(sb.st_mode)) { |
276 | fprintf(stderr, "directory creation race: %s\n", toname); |
277 | goto retry; |
278 | } |
279 | fail("cannot make directory %s", toname); |
280 | } |
281 | if ((owner || group) && chown(toname, uid, gid) < 0) |
282 | fail("cannot change owner of %s", toname); |
283 | } else if (dolink) { |
284 | if (*name == '/') { |
285 | |
286 | linkname = 0; |
287 | } else { |
288 | if (linkprefix) { |
289 | |
290 | len += lplen + 1; |
291 | linkname = (char*)xmalloc(len + 1); |
292 | snprintf(linkname, len+1, "%s/%s", linkprefix, name); |
293 | } else if (dorelsymlink) { |
294 | |
295 | linkname = (char*)xmalloc(PATH_MAX); |
296 | |
297 | if (*todir == '/') { |
298 | |
299 | lplen = relatepaths(todir, cwd, linkname); |
300 | strcpy(linkname + lplen, name); |
301 | } else { |
302 | |
303 | reversepath(todir, name, len, linkname); |
304 | xchdir(cwd); |
305 | } |
306 | |
307 | len = strlen(linkname); |
308 | } |
309 | name = linkname; |
310 | } |
311 | |
312 | |
313 | if (exists && |
314 | (!S_ISLNK(tosb.st_mode) || |
315 | readlink(toname, buf, sizeof buf) != len || |
316 | strncmp(buf, name, len) != 0)) { |
317 | int rmrv; |
318 | rmrv = (S_ISDIR(tosb.st_mode) ? rmdir : unlink)(toname); |
319 | if (rmrv < 0) { |
320 | fail("destination exists, cannot remove %s", toname); |
321 | } |
322 | exists = 0; |
323 | } |
324 | if (!exists && symlink(name, toname) < 0) { |
325 | if (errno == EEXIST) { |
326 | fprintf(stderr, "symlink creation race: %s\n", toname); |
327 | fail("symlink was attempted in working directory %s " |
328 | "from %s to %s.\n", cwd, name, toname); |
329 | goto retry; |
330 | } |
331 | diagnosePath(toname); |
332 | fail("cannot make symbolic link %s", toname); |
333 | } |
334 | #ifdef HAVE_LCHOWN |
335 | if ((owner || group) && lchown(toname, uid, gid) < 0) |
336 | fail("cannot change owner of %s", toname); |
337 | #endif |
338 | |
339 | if (linkname) { |
340 | free(linkname); |
341 | linkname = 0; |
342 | } |
343 | } else { |
344 | |
345 | fromfd = open(name, O_RDONLY); |
346 | if (fromfd < 0 || fstat(fromfd, &sb) < 0) |
347 | fail("cannot access %s", name); |
348 | if (exists && |
349 | (!S_ISREG(tosb.st_mode) || access(toname, W_OK) < 0)) { |
350 | int rmrv; |
351 | rmrv = (S_ISDIR(tosb.st_mode) ? rmdir : unlink)(toname); |
352 | if (rmrv < 0) { |
353 | fail("destination exists, cannot remove %s", toname); |
354 | } |
355 | } |
356 | tofd = open(toname, O_CREAT | O_WRONLY, 0666); |
357 | if (tofd < 0) |
358 | fail("cannot create %s", toname); |
359 | |
360 | bp = buf; |
361 | while ((cc = read(fromfd, bp, sizeof buf)) > 0) { |
362 | while ((wc = write(tofd, bp, cc)) > 0) { |
363 | if ((cc -= wc) == 0) |
364 | break; |
365 | bp += wc; |
366 | } |
367 | if (wc < 0) |
368 | fail("cannot write to %s", toname); |
369 | } |
370 | if (cc < 0) |
371 | fail("cannot read from %s", name); |
372 | |
373 | if (ftruncate(tofd, sb.st_size) < 0) |
374 | fail("cannot truncate %s", toname); |
375 | if (dotimes) { |
376 | utb.actime = sb.st_atime; |
377 | utb.modtime = sb.st_mtime; |
378 | if (utime(toname, &utb) < 0) |
379 | fail("cannot set times of %s", toname); |
380 | } |
381 | #ifdef HAVE_FCHMOD |
382 | if (fchmod(tofd, mode) < 0) |
383 | #else |
384 | if (chmod(toname, mode) < 0) |
385 | #endif |
386 | fail("cannot change mode of %s", toname); |
387 | |
388 | if ((owner || group) && fchown(tofd, uid, gid) < 0) |
389 | fail("cannot change owner of %s", toname); |
390 | |
391 | |
392 | if (close(tofd) < 0) |
393 | fail("close reports write error on %s", toname); |
394 | close(fromfd); |
395 | } |
396 | |
397 | free(toname); |
398 | } |
399 | |
400 | free(cwd); |
401 | free(todir); |
402 | return 0; |
403 | } |
404 | |