Coverage Report

Created: 2026-04-01 06:26

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/samba/source3/auth/pass_check.c
Line
Count
Source
1
/*
2
   Unix SMB/CIFS implementation.
3
   Password checking
4
   Copyright (C) Andrew Tridgell 1992-1998
5
6
   This program is free software; you can redistribute it and/or modify
7
   it under the terms of the GNU General Public License as published by
8
   the Free Software Foundation; either version 3 of the License, or
9
   (at your option) any later version.
10
11
   This program is distributed in the hope that it will be useful,
12
   but WITHOUT ANY WARRANTY; without even the implied warranty of
13
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
   GNU General Public License for more details.
15
16
   You should have received a copy of the GNU General Public License
17
   along with this program.  If not, see <http://www.gnu.org/licenses/>.
18
*/
19
20
/* this module is for checking a username/password against a system
21
   password database. The SMB encrypted password support is elsewhere */
22
23
#include "includes.h"
24
#include "system/passwd.h"
25
#include "auth.h"
26
27
#undef DBGC_CLASS
28
0
#define DBGC_CLASS DBGC_AUTH
29
30
#if !defined(WITH_PAM)
31
static char *ths_salt;
32
/* This must be writable. */
33
static char *get_this_salt(void)
34
{
35
  return ths_salt;
36
}
37
38
/* We may be setting a modified version of the same
39
 * string, so don't free before use. */
40
41
static const char *set_this_salt(const char *newsalt)
42
{
43
  char *orig_salt = ths_salt;
44
  ths_salt = SMB_STRDUP(newsalt);
45
  SAFE_FREE(orig_salt);
46
  return ths_salt;
47
}
48
49
static char *ths_crypted;
50
static const char *get_this_crypted(void)
51
{
52
  if (!ths_crypted) {
53
    return "";
54
  }
55
  return ths_crypted;
56
}
57
58
static const char *set_this_crypted(const char *newcrypted)
59
{
60
  char *orig_crypted = ths_crypted;
61
  ths_crypted = SMB_STRDUP(newcrypted);
62
  SAFE_FREE(orig_crypted);
63
  return ths_crypted;
64
}
65
#endif
66
67
68
69
70
71
72
73
/****************************************************************************
74
core of password checking routine
75
****************************************************************************/
76
static NTSTATUS password_check(const char *user, const char *password, const void *private_data)
77
0
{
78
0
#ifdef WITH_PAM
79
0
  const char *rhost = (const char *)private_data;
80
0
  return smb_pam_passcheck(user, rhost, password);
81
#else
82
83
  bool ret;
84
85
86
87
88
#ifdef ULTRIX_AUTH
89
  ret = (strcmp((char *)crypt16(password, get_this_salt()), get_this_crypted()) == 0);
90
  if (ret) {
91
    return NT_STATUS_OK;
92
        } else {
93
    return NT_STATUS_WRONG_PASSWORD;
94
  }
95
96
#endif /* ULTRIX_AUTH */
97
98
99
100
#ifdef HAVE_BIGCRYPT
101
  ret = (strcmp(bigcrypt(password, get_this_salt()), get_this_crypted()) == 0);
102
        if (ret) {
103
    return NT_STATUS_OK;
104
  } else {
105
    return NT_STATUS_WRONG_PASSWORD;
106
  }
107
#endif /* HAVE_BIGCRYPT */
108
109
#ifndef HAVE_CRYPT
110
  DEBUG(1, ("Warning - no crypt available\n"));
111
  return NT_STATUS_LOGON_FAILURE;
112
#else /* HAVE_CRYPT */
113
  ret = (strcmp((char *)crypt(password, get_this_salt()), get_this_crypted()) == 0);
114
        if (ret) {
115
    return NT_STATUS_OK;
116
  } else {
117
    return NT_STATUS_WRONG_PASSWORD;
118
  }
119
#endif /* HAVE_CRYPT */
120
#endif /* WITH_PAM */
121
0
}
122
123
124
125
/****************************************************************************
126
CHECK if a username/password is OK
127
the function pointer fn() points to a function to call when a successful
128
match is found and is used to update the encrypted password file 
129
return NT_STATUS_OK on correct match, appropriate error otherwise
130
****************************************************************************/
131
132
NTSTATUS pass_check(const struct passwd *pass,
133
        const char *user,
134
        const char *rhost,
135
        const char *password,
136
        bool run_cracker)
137
0
{
138
0
  char *pass2 = NULL;
139
140
0
  NTSTATUS nt_status;
141
142
0
#ifdef DEBUG_PASSWORD
143
0
  DEBUG(100, ("checking user=[%s] pass=[%s]\n", user, password));
144
0
#endif
145
146
0
  if (!password)
147
0
    return NT_STATUS_LOGON_FAILURE;
148
149
0
  if ((!*password) && !lp_null_passwords())
150
0
    return NT_STATUS_LOGON_FAILURE;
151
152
0
#if defined(WITH_PAM) 
153
154
  /*
155
   * If we're using PAM we want to short-circuit all the 
156
   * checks below and dive straight into the PAM code.
157
   */
158
159
0
  DEBUG(4, ("pass_check: Checking (PAM) password for user %s\n", user));
160
161
#else /* Not using PAM */
162
163
  DEBUG(4, ("pass_check: Checking password for user %s\n", user));
164
165
  if (!pass) {
166
    DEBUG(3, ("Couldn't find user %s\n", user));
167
    return NT_STATUS_NO_SUCH_USER;
168
  }
169
170
171
  /* Copy into global for the convenience of looping code */
172
  /* Also the place to keep the 'password' no matter what
173
     crazy struct it started in... */
174
  if (set_this_crypted(pass->pw_passwd) == NULL) {
175
    return NT_STATUS_NO_MEMORY;
176
  }
177
  if (set_this_salt(pass->pw_passwd) == NULL) {
178
    return NT_STATUS_NO_MEMORY;
179
  }
180
181
#ifdef HAVE_GETSPNAM
182
  {
183
    struct spwd *spass;
184
185
    /* many shadow systems require you to be root to get
186
       the password, in most cases this should already be
187
       the case when this function is called, except
188
       perhaps for IPC password changing requests */
189
190
    spass = getspnam(pass->pw_name);
191
    if (spass && spass->sp_pwdp) {
192
      if (set_this_crypted(spass->sp_pwdp) == NULL) {
193
        return NT_STATUS_NO_MEMORY;
194
      }
195
      if (set_this_salt(spass->sp_pwdp) == NULL) {
196
        return NT_STATUS_NO_MEMORY;
197
      }
198
    }
199
  }
200
#elif defined(IA_UINFO)
201
  {
202
    /* Need to get password with SVR4.2's ia_ functions
203
       instead of get{sp,pw}ent functions. Required by
204
       UnixWare 2.x, tested on version
205
       2.1. (tangent@cyberport.com) */
206
    uinfo_t uinfo;
207
    if (ia_openinfo(pass->pw_name, &uinfo) != -1)
208
      ia_get_logpwd(uinfo, &(pass->pw_passwd));
209
  }
210
#endif
211
212
213
#ifdef HAVE_GETPWANAM
214
  {
215
    struct passwd_adjunct *pwret;
216
    pwret = getpwanam(s);
217
    if (pwret && pwret->pwa_passwd) {
218
      if (set_this_crypted(pwret->pwa_passwd) == NULL) {
219
        return NT_STATUS_NO_MEMORY;
220
      }
221
    }
222
  }
223
#endif
224
225
226
#ifdef ULTRIX_AUTH
227
  {
228
    AUTHORIZATION *ap = getauthuid(pass->pw_uid);
229
    if (ap) {
230
      if (set_this_crypted(ap->a_password) == NULL) {
231
        endauthent();
232
        return NT_STATUS_NO_MEMORY;
233
      }
234
      endauthent();
235
    }
236
  }
237
#endif
238
239
240
  if (!get_this_crypted() || !*get_this_crypted()) {
241
    if (!lp_null_passwords()) {
242
      DEBUG(2, ("Disallowing %s with null password\n",
243
          user));
244
      return NT_STATUS_LOGON_FAILURE;
245
    }
246
    if (!*password) {
247
      DEBUG(3,
248
            ("Allowing access to %s with null password\n",
249
             user));
250
      return NT_STATUS_OK;
251
    }
252
  }
253
254
#endif /* defined(WITH_PAM) */
255
256
  /* try it as it came to us */
257
0
  nt_status = password_check(user, password, (const void *)rhost);
258
0
        if NT_STATUS_IS_OK(nt_status) {
259
0
    return (nt_status);
260
0
  } else if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_WRONG_PASSWORD)) {
261
                /* No point continuing if its not the password that's to blame (ie PAM disabled). */
262
0
                return (nt_status);
263
0
        }
264
265
0
  if (!run_cracker) {
266
0
    return (nt_status);
267
0
  }
268
269
  /* if the password was given to us with mixed case then we don't
270
   * need to proceed as we know it hasn't been case modified by the
271
   * client */
272
0
  if (strhasupper(password) && strhaslower(password)) {
273
0
    return nt_status;
274
0
  }
275
276
  /* make a copy of it */
277
0
  pass2 = talloc_strdup(talloc_tos(), password);
278
0
  if (!pass2) {
279
0
    return NT_STATUS_NO_MEMORY;
280
0
  }
281
282
  /* try all lowercase if it's currently all uppercase */
283
0
  if (strhasupper(pass2)) {
284
0
    if (!strlower_m(pass2)) {
285
0
      return NT_STATUS_INVALID_PARAMETER;
286
0
    }
287
0
    nt_status = password_check(user, pass2, (const void *)rhost);
288
0
    if (NT_STATUS_IS_OK(nt_status)) {
289
0
      return (nt_status);
290
0
    }
291
0
  }
292
293
0
  return NT_STATUS_WRONG_PASSWORD;
294
0
}