Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 : Authentication utility functions
4 : Copyright (C) Simo Sorce 2010
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 : #include "includes.h"
21 : #include "auth.h"
22 : #include "librpc/gen_ndr/krb5pac.h"
23 : #include "nsswitch/libwbclient/wbclient.h"
24 : #include "passdb.h"
25 : #include "lib/param/loadparm.h"
26 :
27 : #undef DBGC_CLASS
28 : #define DBGC_CLASS DBGC_AUTH
29 :
30 : #ifdef HAVE_KRB5
31 554 : NTSTATUS get_user_from_kerberos_info(TALLOC_CTX *mem_ctx,
32 : const char *cli_name,
33 : const char *princ_name,
34 : struct PAC_LOGON_INFO *logon_info,
35 : bool *is_mapped,
36 : bool *mapped_to_guest,
37 : char **ntuser,
38 : char **ntdomain,
39 : char **username,
40 : struct passwd **_pw)
41 : {
42 : NTSTATUS status;
43 554 : char *domain = NULL;
44 554 : char *realm = NULL;
45 554 : char *user = NULL;
46 : char *p;
47 554 : char *fuser = NULL;
48 554 : char *unixuser = NULL;
49 554 : struct passwd *pw = NULL;
50 :
51 554 : DEBUG(3, ("Kerberos ticket principal name is [%s]\n", princ_name));
52 :
53 554 : p = strchr_m(princ_name, '@');
54 554 : if (!p) {
55 0 : DEBUG(3, ("[%s] Doesn't look like a valid principal\n",
56 : princ_name));
57 0 : return NT_STATUS_LOGON_FAILURE;
58 : }
59 :
60 554 : user = talloc_strndup(mem_ctx, princ_name, p - princ_name);
61 554 : if (!user) {
62 0 : return NT_STATUS_NO_MEMORY;
63 : }
64 :
65 554 : realm = talloc_strdup(talloc_tos(), p + 1);
66 554 : if (!realm) {
67 0 : return NT_STATUS_NO_MEMORY;
68 : }
69 :
70 554 : if (!strequal(realm, lp_realm())) {
71 2 : DEBUG(3, ("Ticket for foreign realm %s@%s\n", user, realm));
72 2 : if (!lp_allow_trusted_domains()) {
73 0 : return NT_STATUS_LOGON_FAILURE;
74 : }
75 : }
76 :
77 554 : if (logon_info && logon_info->info3.base.logon_domain.string) {
78 554 : domain = talloc_strdup(mem_ctx,
79 : logon_info->info3.base.logon_domain.string);
80 554 : if (!domain) {
81 0 : return NT_STATUS_NO_MEMORY;
82 : }
83 554 : DEBUG(10, ("Domain is [%s] (using PAC)\n", domain));
84 : } else {
85 :
86 : /* If we have winbind running, we can (and must) shorten the
87 : username by using the short netbios name. Otherwise we will
88 : have inconsistent user names. With Kerberos, we get the
89 : fully qualified realm, with ntlmssp we get the short
90 : name. And even w2k3 does use ntlmssp if you for example
91 : connect to an ip address. */
92 :
93 : wbcErr wbc_status;
94 0 : struct wbcDomainInfo *info = NULL;
95 :
96 0 : DEBUG(10, ("Mapping [%s] to short name using winbindd\n",
97 : realm));
98 :
99 0 : wbc_status = wbcDomainInfo(realm, &info);
100 :
101 0 : if (WBC_ERROR_IS_OK(wbc_status)) {
102 0 : domain = talloc_strdup(mem_ctx,
103 0 : info->short_name);
104 0 : wbcFreeMemory(info);
105 : } else {
106 0 : DEBUG(3, ("Could not find short name: %s\n",
107 : wbcErrorString(wbc_status)));
108 0 : domain = talloc_strdup(mem_ctx, realm);
109 : }
110 0 : if (!domain) {
111 0 : return NT_STATUS_NO_MEMORY;
112 : }
113 0 : DEBUG(10, ("Domain is [%s] (using Winbind)\n", domain));
114 : }
115 :
116 810 : fuser = talloc_asprintf(mem_ctx,
117 : "%s%c%s",
118 : domain,
119 554 : *lp_winbind_separator(),
120 : user);
121 554 : if (!fuser) {
122 0 : return NT_STATUS_NO_MEMORY;
123 : }
124 :
125 554 : *is_mapped = map_username(mem_ctx, fuser, &fuser);
126 554 : if (!fuser) {
127 0 : return NT_STATUS_NO_MEMORY;
128 : }
129 554 : *mapped_to_guest = false;
130 :
131 554 : pw = smb_getpwnam(mem_ctx, fuser, &unixuser, true);
132 554 : if (pw) {
133 554 : if (!unixuser) {
134 0 : return NT_STATUS_NO_MEMORY;
135 : }
136 : /* if a real user check pam account restrictions */
137 : /* only really performed if "obey pam restriction" is true */
138 : /* do this before an eventual mapping to guest occurs */
139 554 : status = smb_pam_accountcheck(pw->pw_name, cli_name);
140 554 : if (!NT_STATUS_IS_OK(status)) {
141 0 : DEBUG(1, ("PAM account restrictions prevent user "
142 : "[%s] login\n", unixuser));
143 0 : return status;
144 : }
145 : }
146 554 : if (!pw) {
147 :
148 : /* this was originally the behavior of Samba 2.2, if a user
149 : did not have a local uid but has been authenticated, then
150 : map them to a guest account */
151 :
152 0 : if (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_UID) {
153 0 : *mapped_to_guest = true;
154 0 : fuser = talloc_strdup(mem_ctx, lp_guest_account());
155 0 : if (!fuser) {
156 0 : return NT_STATUS_NO_MEMORY;
157 : }
158 0 : pw = smb_getpwnam(mem_ctx, fuser, &unixuser, true);
159 : }
160 :
161 : /* extra sanity check that the guest account is valid */
162 0 : if (!pw) {
163 0 : DBG_NOTICE("Username %s is invalid on this system\n",
164 : fuser);
165 0 : return NT_STATUS_LOGON_FAILURE;
166 : }
167 : }
168 :
169 554 : if (!unixuser) {
170 0 : return NT_STATUS_NO_MEMORY;
171 : }
172 :
173 554 : *username = talloc_strdup(mem_ctx, unixuser);
174 554 : if (!*username) {
175 0 : return NT_STATUS_NO_MEMORY;
176 : }
177 554 : *ntuser = user;
178 554 : *ntdomain = domain;
179 554 : *_pw = pw;
180 :
181 554 : return NT_STATUS_OK;
182 : }
183 :
184 554 : NTSTATUS make_session_info_krb5(TALLOC_CTX *mem_ctx,
185 : char *ntuser,
186 : char *ntdomain,
187 : char *username,
188 : struct passwd *pw,
189 : const struct netr_SamInfo3 *info3,
190 : bool mapped_to_guest, bool username_was_mapped,
191 : DATA_BLOB *session_key,
192 : struct auth_session_info **session_info)
193 : {
194 : NTSTATUS status;
195 : struct auth_serversupplied_info *server_info;
196 :
197 554 : if (mapped_to_guest) {
198 0 : status = make_server_info_guest(mem_ctx, &server_info);
199 0 : if (!NT_STATUS_IS_OK(status)) {
200 0 : DEBUG(1, ("make_server_info_guest failed: %s!\n",
201 : nt_errstr(status)));
202 0 : return status;
203 : }
204 :
205 554 : } else if (info3) {
206 : /* pass the unmapped username here since map_username()
207 : will be called again in make_server_info_info3() */
208 :
209 554 : status = make_server_info_info3(mem_ctx,
210 : ntuser, ntdomain,
211 : &server_info,
212 : info3);
213 554 : if (!NT_STATUS_IS_OK(status)) {
214 0 : DEBUG(1, ("make_server_info_info3 failed: %s!\n",
215 : nt_errstr(status)));
216 0 : return status;
217 : }
218 :
219 : } else {
220 : /*
221 : * We didn't get a PAC, we have to make up the user
222 : * ourselves. Try to ask the pdb backend to provide
223 : * SID consistency with ntlmssp session setup
224 : */
225 : struct samu *sampass;
226 :
227 0 : sampass = samu_new(talloc_tos());
228 0 : if (sampass == NULL) {
229 0 : return NT_STATUS_NO_MEMORY;
230 : }
231 :
232 0 : if (pdb_getsampwnam(sampass, username)) {
233 0 : DEBUG(10, ("found user %s in passdb, calling "
234 : "make_server_info_sam\n", username));
235 0 : status = make_server_info_sam(mem_ctx,
236 : sampass,
237 : &server_info);
238 : } else {
239 : /*
240 : * User not in passdb, make it up artificially
241 : */
242 0 : DEBUG(10, ("didn't find user %s in passdb, calling "
243 : "make_server_info_pw\n", username));
244 0 : status = make_server_info_pw(mem_ctx,
245 : username,
246 : pw,
247 : &server_info);
248 : }
249 :
250 0 : TALLOC_FREE(sampass);
251 :
252 0 : if (!NT_STATUS_IS_OK(status)) {
253 0 : DEBUG(1, ("make_server_info_[sam|pw] failed: %s!\n",
254 : nt_errstr(status)));
255 0 : return status;
256 : }
257 :
258 : /* make_server_info_pw does not set the domain. Without this
259 : * we end up with the local netbios name in substitutions for
260 : * %D. */
261 :
262 0 : if (server_info->info3 != NULL) {
263 0 : server_info->info3->base.logon_domain.string =
264 0 : talloc_strdup(server_info->info3, ntdomain);
265 : }
266 : }
267 :
268 554 : server_info->nss_token |= username_was_mapped;
269 :
270 554 : status = create_local_token(mem_ctx, server_info, session_key, ntuser, session_info);
271 554 : talloc_free(server_info);
272 554 : if (!NT_STATUS_IS_OK(status)) {
273 0 : DEBUG(10,("failed to create local token: %s\n",
274 : nt_errstr(status)));
275 0 : return status;
276 : }
277 :
278 554 : return NT_STATUS_OK;
279 : }
280 :
281 : #else /* HAVE_KRB5 */
282 : NTSTATUS get_user_from_kerberos_info(TALLOC_CTX *mem_ctx,
283 : const char *cli_name,
284 : const char *princ_name,
285 : struct PAC_LOGON_INFO *logon_info,
286 : bool *is_mapped,
287 : bool *mapped_to_guest,
288 : char **ntuser,
289 : char **ntdomain,
290 : char **username,
291 : struct passwd **_pw)
292 : {
293 : return NT_STATUS_NOT_IMPLEMENTED;
294 : }
295 :
296 : NTSTATUS make_session_info_krb5(TALLOC_CTX *mem_ctx,
297 : char *ntuser,
298 : char *ntdomain,
299 : char *username,
300 : struct passwd *pw,
301 : const struct netr_SamInfo3 *info3,
302 : bool mapped_to_guest, bool username_was_mapped,
303 : DATA_BLOB *session_key,
304 : struct auth_session_info **session_info)
305 : {
306 : return NT_STATUS_NOT_IMPLEMENTED;
307 : }
308 :
309 : #endif /* HAVE_KRB5 */
|