Bug Summary

File:src/libexec/login_lchpass/../../usr.bin/passwd/local_passwd.c
Warning:line 131, column 2
The return value from the call to 'setuid' is not checked. If an error occurs in 'setuid', the following code may execute with unexpected privileges

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 local_passwd.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/libexec/login_lchpass/obj -resource-dir /usr/local/lib/clang/13.0.0 -internal-isystem /usr/local/lib/clang/13.0.0/include -internal-externc-isystem /usr/include -O2 -Wno-unused -fdebug-compilation-dir=/usr/src/libexec/login_lchpass/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/libexec/login_lchpass/../../usr.bin/passwd/local_passwd.c
1/* $OpenBSD: local_passwd.c,v 1.62 2021/10/24 21:24:17 deraadt Exp $ */
2
3/*-
4 * Copyright (c) 1990 The Regents of the University of California.
5 * All rights reserved.
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 * 3. Neither the name of the University nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32#include <sys/types.h>
33#include <sys/stat.h>
34#include <sys/uio.h>
35
36#include <err.h>
37#include <errno(*__errno()).h>
38#include <fcntl.h>
39#include <paths.h>
40#include <pwd.h>
41#include <stdio.h>
42#include <stdlib.h>
43#include <signal.h>
44#include <string.h>
45#include <unistd.h>
46#include <util.h>
47#include <login_cap.h>
48#include <readpassphrase.h>
49
50#define UNCHANGED_MSG"Password unchanged." "Password unchanged."
51
52static uid_t uid;
53extern int pwd_check(login_cap_t *, char *);
54extern int pwd_gettries(login_cap_t *);
55
56int local_passwd(char *, int);
57char *getnewpasswd(struct passwd *, login_cap_t *, int);
58void kbintr(int);
59
60int
61local_passwd(char *uname, int authenticated)
62{
63 struct passwd *pw, *opw;
64 login_cap_t *lc;
65 sigset_t fullset;
66 time_t period;
67 int i, pfd, tfd = -1;
68 int pwflags = _PASSWORD_OMITV70x02;
69
70 if (!(pw = getpwnam_shadow(uname))) {
71 warnx("unknown user %s.", uname);
72 return(1);
73 }
74
75 if (unveil(_PATH_MASTERPASSWD_LOCK"/etc/ptmp", "rwc") == -1)
76 err(1, "unveil %s", _PATH_MASTERPASSWD_LOCK"/etc/ptmp");
77 if (unveil(_PATH_MASTERPASSWD"/etc/master.passwd", "r") == -1)
78 err(1, "unveil %s", _PATH_MASTERPASSWD"/etc/master.passwd");
79 if (unveil(_PATH_LOGIN_CONF"/etc/login.conf", "r") == -1)
80 err(1, "unveil %s", _PATH_LOGIN_CONF"/etc/login.conf");
81 if (unveil(_PATH_LOGIN_CONF"/etc/login.conf" ".db", "r") == -1)
82 err(1, "unveil %s.db", _PATH_LOGIN_CONF"/etc/login.conf");
83 if (unveil(_PATH_BSHELL"/bin/sh", "x") == -1)
84 err(1, "unveil %s", _PATH_BSHELL"/bin/sh");
85 if (unveil(_PATH_SHELLS"/etc/shells", "r") == -1)
86 err(1, "unveil %s", _PATH_SHELLS"/etc/shells");
87 if (unveil(_PATH_PWD_MKDB"/usr/sbin/pwd_mkdb", "x") == -1)
88 err(1, "unveil %s", _PATH_PWD_MKDB"/usr/sbin/pwd_mkdb");
89 if (pledge("stdio rpath wpath cpath getpw tty id proc exec", NULL((void *)0)) == -1)
90 err(1, "pledge");
91
92 if ((opw = pw_dup(pw)) == NULL((void *)0)) {
93 warn(NULL((void *)0));
94 return(1);
95 }
96 if ((lc = login_getclass(pw->pw_class)) == NULL((void *)0)) {
97 warnx("unable to get login class for user %s.", uname);
98 free(opw);
99 return(1);
100 }
101
102 uid = authenticated ? pw->pw_uid : getuid();
103 if (uid && uid != pw->pw_uid) {
104 warnx("login/uid mismatch, username argument required.");
105 free(opw);
106 return(1);
107 }
108
109 /* Get the new password. */
110 pw->pw_passwd = getnewpasswd(pw, lc, authenticated);
111
112 if (pledge("stdio rpath wpath cpath getpw id proc exec", NULL((void *)0)) == -1)
113 err(1, "pledge");
114
115 /* Reset password change time based on login.conf. */
116 period = (time_t)login_getcaptime(lc, "passwordtime", 0, 0);
117 if (period > 0) {
118 pw->pw_change = time(NULL((void *)0)) + period;
119 } else {
120 /*
121 * If the pw change time is the same we only need
122 * to update the spwd.db file.
123 */
124 if (pw->pw_change != 0)
125 pw->pw_change = 0;
126 else
127 pwflags = _PASSWORD_SECUREONLY0x01;
128 }
129
130 /* Drop user's real uid and block all signals to avoid a DoS. */
131 setuid(0);
The return value from the call to 'setuid' is not checked. If an error occurs in 'setuid', the following code may execute with unexpected privileges
132 sigfillset(&fullset);
133 sigdelset(&fullset, SIGINT2);
134 sigprocmask(SIG_BLOCK1, &fullset, NULL((void *)0));
135
136 if (pledge("stdio rpath wpath cpath proc exec", NULL((void *)0)) == -1)
137 err(1, "pledge");
138
139 /* Get a lock on the passwd file and open it. */
140 pw_init();
141 for (i = 1; (tfd = pw_lock(0)) == -1; i++) {
142 if (i == 4)
143 (void)fputs("Attempting to lock password file, "
144 "please wait or press ^C to abort", stderr(&__sF[2]));
145 (void)signal(SIGINT2, kbintr);
146 if (i % 16 == 0)
147 fputc('.', stderr(&__sF[2]));
148 usleep(250000);
149 (void)signal(SIGINT2, SIG_IGN(void (*)(int))1);
150 }
151 if (i >= 4)
152 fputc('\n', stderr(&__sF[2]));
153 pfd = open(_PATH_MASTERPASSWD"/etc/master.passwd", O_RDONLY0x0000 | O_CLOEXEC0x10000);
154 if (pfd == -1)
155 pw_error(_PATH_MASTERPASSWD"/etc/master.passwd", 1, 1);
156
157 /* Update master.passwd file and rebuild spwd.db. */
158 pw_copy(pfd, tfd, pw, opw);
159 free(opw);
160 if (pw_mkdb(uname, pwflags) == -1)
161 pw_error(NULL((void *)0), 0, 1);
162
163 fprintf(stderr(&__sF[2]), "passwd: password updated successfully\n");
164
165 return(0);
166}
167
168char *
169getnewpasswd(struct passwd *pw, login_cap_t *lc, int authenticated)
170{
171 static char hash[_PASSWORD_LEN128];
172 char newpass[1024];
173 char *p, *pref;
174 int tries, pwd_tries;
175 sig_t saveint, savequit;
176
177 saveint = signal(SIGINT2, kbintr);
178 savequit = signal(SIGQUIT3, kbintr);
179
180 if (!authenticated) {
181 fprintf(stderr(&__sF[2]), "Changing password for %s.\n", pw->pw_name);
182 if (uid != 0 && pw->pw_passwd[0] != '\0') {
183 char oldpass[1024];
184
185 p = readpassphrase("Old password:", oldpass,
186 sizeof(oldpass), RPP_ECHO_OFF0x00);
187 if (p == NULL((void *)0) || *p == '\0') {
188 fprintf(stderr(&__sF[2]), "%s\n", UNCHANGED_MSG"Password unchanged.");
189 pw_abort();
190 exit(p == NULL((void *)0) ? 1 : 0);
191 }
192 if (crypt_checkpass(p, pw->pw_passwd) != 0) {
193 errno(*__errno()) = EACCES13;
194 explicit_bzero(oldpass, sizeof(oldpass));
195 pw_error(NULL((void *)0), 1, 1);
196 }
197 explicit_bzero(oldpass, sizeof(oldpass));
198 }
199 }
200
201 pwd_tries = pwd_gettries(lc);
202
203 for (newpass[0] = '\0', tries = 0;;) {
204 char repeat[1024];
205
206 p = readpassphrase("New password:", newpass, sizeof(newpass),
207 RPP_ECHO_OFF0x00);
208 if (p == NULL((void *)0) || *p == '\0') {
209 fprintf(stderr(&__sF[2]), "%s\n", UNCHANGED_MSG"Password unchanged.");
210 pw_abort();
211 exit(p == NULL((void *)0) ? 1 : 0);
212 }
213 if (strcmp(p, "s/key") == 0) {
214 fprintf(stderr(&__sF[2]), "That password collides with a system feature. Choose another.\n");
215 continue;
216 }
217
218 if ((tries++ < pwd_tries || pwd_tries == 0) &&
219 pwd_check(lc, p) == 0)
220 continue;
221 p = readpassphrase("Retype new password:", repeat, sizeof(repeat),
222 RPP_ECHO_OFF0x00);
223 if (p != NULL((void *)0) && strcmp(newpass, p) == 0) {
224 explicit_bzero(repeat, sizeof(repeat));
225 break;
226 }
227 fprintf(stderr(&__sF[2]), "Mismatch; try again, EOF to quit.\n");
228 explicit_bzero(repeat, sizeof(repeat));
229 explicit_bzero(newpass, sizeof(newpass));
230 }
231
232 (void)signal(SIGINT2, saveint);
233 (void)signal(SIGQUIT3, savequit);
234
235 pref = login_getcapstr(lc, "localcipher", NULL((void *)0), NULL((void *)0));
236 if (crypt_newhash(newpass, pref, hash, sizeof(hash)) != 0) {
237 fprintf(stderr(&__sF[2]), "Couldn't generate hash.\n");
238 explicit_bzero(newpass, sizeof(newpass));
239 pw_error(NULL((void *)0), 0, 0);
240 }
241 explicit_bzero(newpass, sizeof(newpass));
242 free(pref);
243 return hash;
244}
245
246void
247kbintr(int signo)
248{
249 dprintf(STDOUT_FILENO1, "\n%s\n", UNCHANGED_MSG"Password unchanged.");
250 _exit(0);
251}