Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sudo-project
GitHub Repository: sudo-project/sudo
Path: blob/main/plugins/sudoers/auth/passwd.c
1532 views
1
/*
2
* SPDX-License-Identifier: ISC
3
*
4
* Copyright (c) 1999-2005, 2010-2015 Todd C. Miller <[email protected]>
5
*
6
* Permission to use, copy, modify, and distribute this software for any
7
* purpose with or without fee is hereby granted, provided that the above
8
* copyright notice and this permission notice appear in all copies.
9
*
10
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17
*
18
* Sponsored in part by the Defense Advanced Research Projects
19
* Agency (DARPA) and Air Force Research Laboratory, Air Force
20
* Materiel Command, USAF, under agreement number F39502-99-1-0512.
21
*/
22
23
#include <config.h>
24
25
#include <sys/types.h>
26
#include <stdio.h>
27
#include <stdlib.h>
28
#include <string.h>
29
#include <unistd.h>
30
#include <pwd.h>
31
32
#include <sudoers.h>
33
#include "sudo_auth.h"
34
35
#define DESLEN 13
36
#define HAS_AGEINFO(p, l) (l == 18 && p[DESLEN] == ',')
37
38
int
39
sudo_passwd_init(const struct sudoers_context *ctx, struct passwd *pw,
40
sudo_auth *auth)
41
{
42
debug_decl(sudo_passwd_init, SUDOERS_DEBUG_AUTH);
43
44
/* Only initialize once. */
45
if (auth->data != NULL)
46
debug_return_int(AUTH_SUCCESS);
47
48
#ifdef HAVE_SKEYACCESS
49
if (skeyaccess(pw, ctx->user.tty, NULL, NULL) == 0)
50
debug_return_int(AUTH_FAILURE);
51
#endif
52
sudo_setspent();
53
auth->data = sudo_getepw(pw);
54
sudo_endspent();
55
debug_return_int(auth->data ? AUTH_SUCCESS : AUTH_ERROR);
56
}
57
58
#ifdef HAVE_CRYPT
59
int
60
sudo_passwd_verify(const struct sudoers_context *ctx, struct passwd *pw,
61
const char *pass, sudo_auth *auth, struct sudo_conv_callback *callback)
62
{
63
char des_pass[9], *epass;
64
char *pw_epasswd = auth->data;
65
size_t pw_len;
66
int ret;
67
debug_decl(sudo_passwd_verify, SUDOERS_DEBUG_AUTH);
68
69
/* An empty plain-text password must match an empty encrypted password. */
70
if (pass[0] == '\0')
71
debug_return_int(pw_epasswd[0] ? AUTH_FAILURE : AUTH_SUCCESS);
72
73
/*
74
* Truncate to 8 chars if standard DES since not all crypt()'s do this.
75
*/
76
pw_len = strlen(pw_epasswd);
77
if (pw_len == DESLEN || HAS_AGEINFO(pw_epasswd, pw_len)) {
78
(void)strlcpy(des_pass, pass, sizeof(des_pass));
79
pass = des_pass;
80
}
81
82
/*
83
* Normal UN*X password check.
84
* HP-UX may add aging info (separated by a ',') at the end so
85
* only compare the first DESLEN characters in that case.
86
*/
87
epass = (char *) crypt(pass, pw_epasswd);
88
ret = AUTH_FAILURE;
89
if (epass != NULL) {
90
if (HAS_AGEINFO(pw_epasswd, pw_len) && strlen(epass) == DESLEN) {
91
if (strncmp(pw_epasswd, epass, DESLEN) == 0)
92
ret = AUTH_SUCCESS;
93
} else {
94
if (strcmp(pw_epasswd, epass) == 0)
95
ret = AUTH_SUCCESS;
96
}
97
}
98
99
explicit_bzero(des_pass, sizeof(des_pass));
100
101
debug_return_int(ret);
102
}
103
#else
104
/*
105
* Constant-time string match, compares "candidate" against "target".
106
* Will always traverse the entirety of "candidate".
107
* Returns 0 for match, -1 for mismatch.
108
*/
109
static int
110
timingsafe_strmatch(const char *candidate, const char *target)
111
{
112
int ret = 0;
113
debug_decl(timingsafe_strmatch, SUDOERS_DEBUG_AUTH);
114
115
for (;;) {
116
ret |= *candidate ^ *target;
117
if (*candidate == '\0')
118
break;
119
candidate++;
120
target += *target != '\0';
121
}
122
debug_return_int(ret ? -1 : 0);
123
}
124
125
int
126
sudo_passwd_verify(const struct sudoers_context *ctx, struct passwd *pw,
127
const char *pass, sudo_auth *auth, struct sudo_conv_callback *callback)
128
{
129
int (* volatile cmp)(const char *, const char *) = timingsafe_strmatch;
130
const char *pw_passwd = auth->data;
131
int ret;
132
debug_decl(sudo_passwd_verify, SUDOERS_DEBUG_AUTH);
133
134
/* Simple string compare for systems without crypt(). */
135
if (cmp(pass, pw_passwd) == 0)
136
ret = AUTH_SUCCESS;
137
else
138
ret = AUTH_FAILURE;
139
140
debug_return_int(ret);
141
}
142
#endif
143
144
int
145
sudo_passwd_cleanup(const struct sudoers_context *ctx, struct passwd *pw,
146
sudo_auth *auth, bool force)
147
{
148
debug_decl(sudo_passwd_cleanup, SUDOERS_DEBUG_AUTH);
149
150
if (auth->data != NULL) {
151
/* Zero out encrypted password before freeing. */
152
size_t len = strlen((char *)auth->data);
153
freezero(auth->data, len);
154
auth->data = NULL;
155
}
156
157
debug_return_int(AUTH_SUCCESS);
158
}
159
160