Coverage Report

Created: 2026-02-14 07:07

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/samba/source3/lib/username.c
Line
Count
Source
1
/* 
2
   Unix SMB/CIFS implementation.
3
   Username handling
4
   Copyright (C) Andrew Tridgell 1992-1998
5
   Copyright (C) Jeremy Allison 1997-2001.
6
   Copyright (C) Andrew Bartlett 2002
7
8
   This program is free software; you can redistribute it and/or modify
9
   it under the terms of the GNU General Public License as published by
10
   the Free Software Foundation; either version 3 of the License, or
11
   (at your option) any later version.
12
13
   This program is distributed in the hope that it will be useful,
14
   but WITHOUT ANY WARRANTY; without even the implied warranty of
15
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
   GNU General Public License for more details.
17
18
   You should have received a copy of the GNU General Public License
19
   along with this program.  If not, see <http://www.gnu.org/licenses/>.
20
*/
21
22
#include "includes.h"
23
#include "system/passwd.h"
24
#include "../lib/util/memcache.h"
25
#include "../lib/util/util_pw.h"
26
#include "lib/util/string_wrappers.h"
27
28
/* internal functions */
29
static struct passwd *uname_string_combinations(char *s, TALLOC_CTX *mem_ctx,
30
            struct passwd * (*fn) (TALLOC_CTX *mem_ctx, const char *),
31
            int N);
32
static struct passwd *uname_string_combinations2(char *s, TALLOC_CTX *mem_ctx, int offset,
33
             struct passwd * (*fn) (TALLOC_CTX *mem_ctx, const char *),
34
             int N);
35
36
static struct passwd *getpwnam_alloc_cached(TALLOC_CTX *mem_ctx, const char *name)
37
0
{
38
0
  struct passwd *pw, *for_cache;
39
40
0
  pw = (struct passwd *)memcache_lookup_talloc(
41
0
    NULL, GETPWNAM_CACHE, data_blob_string_const_null(name));
42
0
  if (pw != NULL) {
43
0
    return tcopy_passwd(mem_ctx, pw);
44
0
  }
45
46
0
  pw = getpwnam(name);
47
0
  if (pw == NULL) {
48
0
    return NULL;
49
0
  }
50
51
0
  for_cache = tcopy_passwd(talloc_tos(), pw);
52
0
  if (for_cache == NULL) {
53
0
    return NULL;
54
0
  }
55
56
0
  memcache_add_talloc(NULL, GETPWNAM_CACHE,
57
0
      data_blob_string_const_null(name), &for_cache);
58
59
0
  return tcopy_passwd(mem_ctx, pw);
60
0
}
61
62
/****************************************************************************
63
 Flush all cached passwd structs.
64
****************************************************************************/
65
66
void flush_pwnam_cache(void)
67
0
{
68
0
        memcache_flush(NULL, GETPWNAM_CACHE);
69
0
}
70
71
/****************************************************************************
72
 Get a users home directory.
73
****************************************************************************/
74
75
char *get_user_home_dir(TALLOC_CTX *mem_ctx, const char *user)
76
0
{
77
0
  struct passwd *pass;
78
0
  char *result;
79
80
  /* Ensure the user exists. */
81
82
0
  pass = Get_Pwnam_alloc(mem_ctx, user);
83
84
0
  if (!pass)
85
0
    return(NULL);
86
87
  /* Return home directory from struct passwd. */
88
89
0
  result = talloc_move(mem_ctx, &pass->pw_dir);
90
91
0
  TALLOC_FREE(pass);
92
0
  return result;
93
0
}
94
95
/****************************************************************************
96
 * A wrapper for getpwnam().  The following variations are tried:
97
 *   - as transmitted
98
 *   - in all lower case if this differs from transmitted
99
 *   - in all upper case if this differs from transmitted
100
 *   - using lp_username_level() for permutations.
101
****************************************************************************/
102
103
static struct passwd *Get_Pwnam_internals(TALLOC_CTX *mem_ctx,
104
            const char *user, char *user2)
105
0
{
106
0
  struct passwd *ret = NULL;
107
108
0
  if (!user2 || !(*user2))
109
0
    return(NULL);
110
111
0
  if (!user || !(*user))
112
0
    return(NULL);
113
114
  /* Try in all lower case first as this is the most 
115
     common case on UNIX systems */
116
0
  if (!strlower_m(user2)) {
117
0
    DEBUG(5,("strlower_m %s failed\n", user2));
118
0
    goto done;
119
0
  }
120
121
0
  DEBUG(5,("Trying _Get_Pwnam(), username as lowercase is %s\n",user2));
122
0
  ret = getpwnam_alloc_cached(mem_ctx, user2);
123
0
  if(ret)
124
0
    goto done;
125
126
  /* Try as given, if username wasn't originally lowercase */
127
0
  if(strcmp(user, user2) != 0) {
128
0
    DEBUG(5,("Trying _Get_Pwnam(), username as given is %s\n",
129
0
       user));
130
0
    ret = getpwnam_alloc_cached(mem_ctx, user);
131
0
    if(ret)
132
0
      goto done;
133
0
  }
134
135
  /* Try as uppercase, if username wasn't originally uppercase */
136
0
  if (!strupper_m(user2)) {
137
0
    goto done;
138
0
  }
139
140
0
  if(strcmp(user, user2) != 0) {
141
0
    DEBUG(5,("Trying _Get_Pwnam(), username as uppercase is %s\n",
142
0
       user2));
143
0
    ret = getpwnam_alloc_cached(mem_ctx, user2);
144
0
    if(ret)
145
0
      goto done;
146
0
  }
147
148
  /* Try all combinations up to usernamelevel */
149
0
  if (!strlower_m(user2)) {
150
0
    DEBUG(5,("strlower_m %s failed\n", user2));
151
0
    goto done;
152
0
  }
153
0
  DEBUG(5,("Checking combinations of %d uppercase letters in %s\n",
154
0
     lp_username_level(), user2));
155
0
  ret = uname_string_combinations(user2, mem_ctx, getpwnam_alloc_cached,
156
0
          lp_username_level());
157
158
0
done:
159
0
  DEBUG(5,("Get_Pwnam_internals %s find user [%s]!\n",ret ?
160
0
     "did":"didn't", user));
161
162
0
  return ret;
163
0
}
164
165
/****************************************************************************
166
 Get_Pwnam wrapper without modification.
167
  NOTE: This with NOT modify 'user'! 
168
  This will return an allocated structure
169
****************************************************************************/
170
171
struct passwd *Get_Pwnam_alloc(TALLOC_CTX *mem_ctx, const char *user)
172
0
{
173
0
  fstring user2;
174
175
0
  if ( *user == '\0' ) {
176
0
    DEBUG(10,("Get_Pwnam: empty username!\n"));
177
0
    return NULL;
178
0
  }
179
180
0
  fstrcpy(user2, user);
181
182
0
  DEBUG(5,("Finding user %s\n", user));
183
184
0
  return Get_Pwnam_internals(mem_ctx, user, user2);
185
0
}
186
187
/* The functions below have been taken from password.c and slightly modified */
188
/****************************************************************************
189
 Apply a function to upper/lower case combinations
190
 of a string and return true if one of them returns true.
191
 Try all combinations with N uppercase letters.
192
 offset is the first char to try and change (start with 0)
193
 it assumes the string starts lowercased
194
****************************************************************************/
195
196
static struct passwd *uname_string_combinations2(char *s, TALLOC_CTX *mem_ctx,
197
             int offset,
198
             struct passwd *(*fn)(TALLOC_CTX *mem_ctx, const char *),
199
             int N)
200
0
{
201
0
  ssize_t len = (ssize_t)strlen(s);
202
0
  int i;
203
0
  struct passwd *ret;
204
205
0
  if (N <= 0 || offset >= len)
206
0
    return(fn(mem_ctx, s));
207
208
0
  for (i=offset;i<(len-(N-1));i++) {
209
0
    char c = s[i];
210
0
    if (!islower_m((int)c))
211
0
      continue;
212
0
    s[i] = toupper_m(c);
213
0
    ret = uname_string_combinations2(s, mem_ctx, i+1, fn, N-1);
214
0
    if(ret)
215
0
      return(ret);
216
0
    s[i] = c;
217
0
  }
218
0
  return(NULL);
219
0
}
220
221
/****************************************************************************
222
 Apply a function to upper/lower case combinations
223
 of a string and return true if one of them returns true.
224
 Try all combinations with up to N uppercase letters.
225
 offset is the first char to try and change (start with 0)
226
 it assumes the string starts lowercased
227
****************************************************************************/
228
229
static struct passwd * uname_string_combinations(char *s, TALLOC_CTX *mem_ctx,
230
             struct passwd * (*fn)(TALLOC_CTX *mem_ctx, const char *),
231
             int N)
232
0
{
233
0
  int n;
234
0
  struct passwd *ret;
235
236
0
  for (n=1;n<=N;n++) {
237
0
    ret = uname_string_combinations2(s,mem_ctx,0,fn,n);
238
0
    if(ret)
239
0
      return(ret);
240
0
  }  
241
0
  return(NULL);
242
0
}
243