s3-auth set session_info->sanitized_username in create_local_token()
[amitay/samba.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                 TALLOC_FREE(sampass);
246
247                 if (!NT_STATUS_IS_OK(status)) {
248                         DEBUG(1, ("make_server_info_[sam|pw] failed: %s!\n",
249                                   nt_errstr(status)));
250                         return status;
251                 }
252
253                 /* make_server_info_pw does not set the domain. Without this
254                  * we end up with the local netbios name in substitutions for
255                  * %D. */
256
257                 if (server_info->info3 != NULL) {
258                         server_info->info3->base.domain.string =
259                                 talloc_strdup(server_info->info3, ntdomain);
260                 }
261         }
262
263         server_info->nss_token |= username_was_mapped;
264
265         status = create_local_token(mem_ctx, server_info, session_key, ntuser, session_info);
266         talloc_free(server_info);
267         if (!NT_STATUS_IS_OK(status)) {
268                 DEBUG(10,("failed to create local token: %s\n",
269                           nt_errstr(status)));
270                 return status;
271         }
272
273         return NT_STATUS_OK;
274 }
275
276 #else /* HAVE_KRB5 */
277 NTSTATUS get_user_from_kerberos_info(TALLOC_CTX *mem_ctx,
278                                      const char *cli_name,
279                                      const char *princ_name,
280                                      struct PAC_LOGON_INFO *logon_info,
281                                      bool *is_mapped,
282                                      bool *mapped_to_guest,
283                                      char **ntuser,
284                                      char **ntdomain,
285                                      char **username,
286                                      struct passwd **_pw)
287 {
288         return NT_STATUS_NOT_IMPLEMENTED;
289 }
290
291 NTSTATUS make_session_info_krb5(TALLOC_CTX *mem_ctx,
292                                 char *ntuser,
293                                 char *ntdomain,
294                                 char *username,
295                                 struct passwd *pw,
296                                 struct PAC_LOGON_INFO *logon_info,
297                                 bool mapped_to_guest, bool username_was_mapped,
298                                 DATA_BLOB *session_key,
299                                 struct auth_session_info **session_info)
300 {
301         return NT_STATUS_NOT_IMPLEMENTED;
302 }
303
304 #endif /* HAVE_KRB5 */