Bug Summary

File:src/libexec/login_lchpass/../../usr.bin/passwd/local_passwd.c
Warning:line 133, 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.4 -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name local_passwd.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 -mrelocation-model pic -pic-level 1 -pic-is-pie -mframe-pointer=all -relaxed-aliasing -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -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/llvm16/lib/clang/16 -internal-isystem /usr/local/llvm16/lib/clang/16/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 -fcf-protection=branch -fno-jump-tables -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/scan/2024-01-11-140451-98009-1 -x c /usr/src/libexec/login_lchpass/../../usr.bin/passwd/local_passwd.c
1/* $OpenBSD: local_passwd.c,v 1.64 2023/05/08 17:15:43 tobias 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_LOGIN_CONF_D"/etc/login.conf.d", "r") == -1)
84 err(1, "unveil %s", _PATH_LOGIN_CONF_D"/etc/login.conf.d");
85 if (unveil(_PATH_BSHELL"/bin/sh", "x") == -1)
86 err(1, "unveil %s", _PATH_BSHELL"/bin/sh");
87 if (unveil(_PATH_SHELLS"/etc/shells", "r") == -1)
88 err(1, "unveil %s", _PATH_SHELLS"/etc/shells");
89 if (unveil(_PATH_PWD_MKDB"/usr/sbin/pwd_mkdb", "x") == -1)
90 err(1, "unveil %s", _PATH_PWD_MKDB"/usr/sbin/pwd_mkdb");
91 if (pledge("stdio rpath wpath cpath getpw tty id proc exec", NULL((void *)0)) == -1)
92 err(1, "pledge");
93
94 if ((opw = pw_dup(pw)) == NULL((void *)0)) {
95 warn(NULL((void *)0));
96 return(1);
97 }
98 if ((lc = login_getclass(pw->pw_class)) == NULL((void *)0)) {
99 warnx("unable to get login class for user %s.", uname);
100 free(opw);
101 return(1);
102 }
103
104 uid = authenticated ? pw->pw_uid : getuid();
105 if (uid && uid != pw->pw_uid) {
106 warnx("login/uid mismatch, username argument required.");
107 free(opw);
108 return(1);
109 }
110
111 /* Get the new password. */
112 pw->pw_passwd = getnewpasswd(pw, lc, authenticated);
113
114 if (pledge("stdio rpath wpath cpath getpw id proc exec", NULL((void *)0)) == -1)
115 err(1, "pledge");
116
117 /* Reset password change time based on login.conf. */
118 period = (time_t)login_getcaptime(lc, "passwordtime", 0, 0);
119 if (period > 0) {
120 pw->pw_change = time(NULL((void *)0)) + period;
121 } else {
122 /*
123 * If the pw change time is the same we only need
124 * to update the spwd.db file.
125 */
126 if (pw->pw_change != 0)
127 pw->pw_change = 0;
128 else
129 pwflags = _PASSWORD_SECUREONLY0x01;
130 }
131
132 /* Drop user's real uid and block all signals to avoid a DoS. */
133 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
134 sigfillset(&fullset);
135 sigdelset(&fullset, SIGINT2);
136 sigprocmask(SIG_BLOCK1, &fullset, NULL((void *)0));
137
138 if (pledge("stdio rpath wpath cpath proc exec", NULL((void *)0)) == -1)
139 err(1, "pledge");
140
141 /* Get a lock on the passwd file and open it. */
142 pw_init();
143 for (i = 1; (tfd = pw_lock(0)) == -1; i++) {
144 if (i == 4)
145 (void)fputs("Attempting to lock password file, "
146 "please wait or press ^C to abort", stderr(&__sF[2]));
147 (void)signal(SIGINT2, kbintr);
148 if (i % 16 == 0)
149 fputc('.', stderr(&__sF[2]));
150 usleep(250000);
151 (void)signal(SIGINT2, SIG_IGN(void (*)(int))1);
152 }
153 if (i >= 4)
154 fputc('\n', stderr(&__sF[2]));
155 pfd = open(_PATH_MASTERPASSWD"/etc/master.passwd", O_RDONLY0x0000 | O_CLOEXEC0x10000);
156 if (pfd == -1)
157 pw_error(_PATH_MASTERPASSWD"/etc/master.passwd", 1, 1);
158
159 /* Update master.passwd file and rebuild spwd.db. */
160 pw_copy(pfd, tfd, pw, opw);
161 free(opw);
162 if (pw_mkdb(uname, pwflags) == -1)
163 pw_error(NULL((void *)0), 0, 1);
164
165 fprintf(stderr(&__sF[2]), "passwd: password updated successfully\n");
166
167 return(0);
168}
169
170char *
171getnewpasswd(struct passwd *pw, login_cap_t *lc, int authenticated)
172{
173 static char hash[_PASSWORD_LEN128];
174 char newpass[1024];
175 char *p, *pref;
176 int tries, pwd_tries;
177 sig_t saveint, savequit;
178
179 saveint = signal(SIGINT2, kbintr);
180 savequit = signal(SIGQUIT3, kbintr);
181
182 if (!authenticated) {
183 fprintf(stderr(&__sF[2]), "Changing password for %s.\n", pw->pw_name);
184 if (uid != 0 && pw->pw_passwd[0] != '\0') {
185 char oldpass[1024];
186
187 p = readpassphrase("Old password:", oldpass,
188 sizeof(oldpass), RPP_ECHO_OFF0x00);
189 if (p == NULL((void *)0) || *p == '\0') {
190 fprintf(stderr(&__sF[2]), "%s\n", UNCHANGED_MSG"Password unchanged.");
191 pw_abort();
192 exit(p == NULL((void *)0) ? 1 : 0);
193 }
194 if (crypt_checkpass(p, pw->pw_passwd) != 0) {
195 errno(*__errno()) = EACCES13;
196 explicit_bzero(oldpass, sizeof(oldpass));
197 pw_error(NULL((void *)0), 1, 1);
198 }
199 explicit_bzero(oldpass, sizeof(oldpass));
200 }
201 }
202
203 pwd_tries = pwd_gettries(lc);
204
205 for (newpass[0] = '\0', tries = -1;;) {
206 char repeat[1024];
207
208 p = readpassphrase("New password:", newpass, sizeof(newpass),
209 RPP_ECHO_OFF0x00);
210 if (p == NULL((void *)0) || *p == '\0') {
211 fprintf(stderr(&__sF[2]), "%s\n", UNCHANGED_MSG"Password unchanged.");
212 pw_abort();
213 exit(p == NULL((void *)0) ? 1 : 0);
214 }
215 if (strcmp(p, "s/key") == 0) {
216 fprintf(stderr(&__sF[2]), "That password collides with a system feature. Choose another.\n");
217 continue;
218 }
219
220 if ((pwd_tries == 0 || ++tries < pwd_tries) &&
221 pwd_check(lc, p) == 0)
222 continue;
223 p = readpassphrase("Retype new password:", repeat, sizeof(repeat),
224 RPP_ECHO_OFF0x00);
225 if (p != NULL((void *)0) && strcmp(newpass, p) == 0) {
226 explicit_bzero(repeat, sizeof(repeat));
227 break;
228 }
229 fprintf(stderr(&__sF[2]), "Mismatch; try again, EOF to quit.\n");
230 explicit_bzero(repeat, sizeof(repeat));
231 explicit_bzero(newpass, sizeof(newpass));
232 }
233
234 (void)signal(SIGINT2, saveint);
235 (void)signal(SIGQUIT3, savequit);
236
237 pref = login_getcapstr(lc, "localcipher", NULL((void *)0), NULL((void *)0));
238 if (crypt_newhash(newpass, pref, hash, sizeof(hash)) != 0) {
239 fprintf(stderr(&__sF[2]), "Couldn't generate hash.\n");
240 explicit_bzero(newpass, sizeof(newpass));
241 pw_error(NULL((void *)0), 0, 0);
242 }
243 explicit_bzero(newpass, sizeof(newpass));
244 free(pref);
245 return hash;
246}
247
248void
249kbintr(int signo)
250{
251 dprintf(STDOUT_FILENO1, "\n%s\n", UNCHANGED_MSG"Password unchanged.");
252 _exit(0);
253}