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