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