s3-auth: On successful user mapping set mapped_to_guest to false.
[metze/samba/wip.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.logon_domain.string) {
77                 domain = talloc_strdup(mem_ctx,
78                                         logon_info->info3.base.logon_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         *mapped_to_guest = false;
129
130         pw = smb_getpwnam(mem_ctx, fuser, &unixuser, true);
131         if (pw) {
132                 if (!unixuser) {
133                         return NT_STATUS_NO_MEMORY;
134                 }
135                 /* if a real user check pam account restrictions */
136                 /* only really perfomed if "obey pam restriction" is true */
137                 /* do this before an eventual mapping to guest occurs */
138                 status = smb_pam_accountcheck(pw->pw_name, cli_name);
139                 if (!NT_STATUS_IS_OK(status)) {
140                         DEBUG(1, ("PAM account restrictions prevent user "
141                                   "[%s] login\n", unixuser));
142                         return status;
143                 }
144         }
145         if (!pw) {
146
147                 /* this was originally the behavior of Samba 2.2, if a user
148                    did not have a local uid but has been authenticated, then
149                    map them to a guest account */
150
151                 if (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_UID) {
152                         *mapped_to_guest = true;
153                         fuser = talloc_strdup(mem_ctx, lp_guestaccount());
154                         if (!fuser) {
155                                 return NT_STATUS_NO_MEMORY;
156                         }
157                         pw = smb_getpwnam(mem_ctx, fuser, &unixuser, true);
158                 }
159
160                 /* extra sanity check that the guest account is valid */
161                 if (!pw) {
162                         DEBUG(1, ("Username %s is invalid on this system\n",
163                                   fuser));
164                         return NT_STATUS_LOGON_FAILURE;
165                 }
166         }
167
168         if (!unixuser) {
169                 return NT_STATUS_NO_MEMORY;
170         }
171
172         *username = talloc_strdup(mem_ctx, unixuser);
173         if (!*username) {
174                 return NT_STATUS_NO_MEMORY;
175         }
176         *ntuser = user;
177         *ntdomain = domain;
178         *_pw = pw;
179
180         return NT_STATUS_OK;
181 }
182
183 NTSTATUS make_session_info_krb5(TALLOC_CTX *mem_ctx,
184                                 char *ntuser,
185                                 char *ntdomain,
186                                 char *username,
187                                 struct passwd *pw,
188                                 struct PAC_LOGON_INFO *logon_info,
189                                 bool mapped_to_guest, bool username_was_mapped,
190                                 DATA_BLOB *session_key,
191                                 struct auth_session_info **session_info)
192 {
193         NTSTATUS status;
194         struct auth_serversupplied_info *server_info;
195
196         if (mapped_to_guest) {
197                 status = make_server_info_guest(mem_ctx, &server_info);
198                 if (!NT_STATUS_IS_OK(status)) {
199                         DEBUG(1, ("make_server_info_guest failed: %s!\n",
200                                   nt_errstr(status)));
201                         return status;
202                 }
203
204         } else if (logon_info) {
205                 /* pass the unmapped username here since map_username()
206                    will be called again in make_server_info_info3() */
207
208                 status = make_server_info_info3(mem_ctx,
209                                                 ntuser, ntdomain,
210                                                 &server_info,
211                                                 &logon_info->info3);
212                 if (!NT_STATUS_IS_OK(status)) {
213                         DEBUG(1, ("make_server_info_info3 failed: %s!\n",
214                                   nt_errstr(status)));
215                         return status;
216                 }
217
218         } else {
219                 /*
220                  * We didn't get a PAC, we have to make up the user
221                  * ourselves. Try to ask the pdb backend to provide
222                  * SID consistency with ntlmssp session setup
223                  */
224                 struct samu *sampass;
225                 /* The stupid make_server_info_XX functions here
226                    don't take a talloc context. */
227                 struct auth_serversupplied_info *tmp = NULL;
228
229                 sampass = samu_new(talloc_tos());
230                 if (sampass == NULL) {
231                         return NT_STATUS_NO_MEMORY;
232                 }
233
234                 if (pdb_getsampwnam(sampass, username)) {
235                         DEBUG(10, ("found user %s in passdb, calling "
236                                    "make_server_info_sam\n", username));
237                         status = make_server_info_sam(&tmp, sampass);
238                 } else {
239                         /*
240                          * User not in passdb, make it up artificially
241                          */
242                         DEBUG(10, ("didn't find user %s in passdb, calling "
243                                    "make_server_info_pw\n", username));
244                         status = make_server_info_pw(&tmp, username, pw);
245                 }
246
247                 TALLOC_FREE(sampass);
248
249                 if (!NT_STATUS_IS_OK(status)) {
250                         DEBUG(1, ("make_server_info_[sam|pw] failed: %s!\n",
251                                   nt_errstr(status)));
252                         return status;
253                 }
254
255                 /* Steal tmp server info into the server_info pointer. */
256                 server_info = talloc_move(mem_ctx, &tmp);
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                 if (server_info->info3 != NULL) {
263                         server_info->info3->base.logon_domain.string =
264                                 talloc_strdup(server_info->info3, ntdomain);
265                 }
266         }
267
268         server_info->nss_token |= username_was_mapped;
269
270         status = create_local_token(mem_ctx, server_info, session_key, ntuser, session_info);
271         talloc_free(server_info);
272         if (!NT_STATUS_IS_OK(status)) {
273                 DEBUG(10,("failed to create local token: %s\n",
274                           nt_errstr(status)));
275                 return status;
276         }
277
278         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                                 struct PAC_LOGON_INFO *logon_info,
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 */