lib/param: Move all enum declarations to lib/param
[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 #include "lib/param/loadparm.h"
26
27 #undef DBGC_CLASS
28 #define DBGC_CLASS DBGC_AUTH
29
30 #ifdef HAVE_KRB5
31 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         char *domain = NULL;
44         char *realm = NULL;
45         char *user = NULL;
46         char *p;
47         char *fuser = NULL;
48         char *unixuser = NULL;
49         struct passwd *pw = NULL;
50
51         DEBUG(3, ("Kerberos ticket principal name is [%s]\n", princ_name));
52
53         p = strchr_m(princ_name, '@');
54         if (!p) {
55                 DEBUG(3, ("[%s] Doesn't look like a valid principal\n",
56                           princ_name));
57                 return NT_STATUS_LOGON_FAILURE;
58         }
59
60         user = talloc_strndup(mem_ctx, princ_name, p - princ_name);
61         if (!user) {
62                 return NT_STATUS_NO_MEMORY;
63         }
64
65         realm = talloc_strdup(talloc_tos(), p + 1);
66         if (!realm) {
67                 return NT_STATUS_NO_MEMORY;
68         }
69
70         if (!strequal(realm, lp_realm())) {
71                 DEBUG(3, ("Ticket for foreign realm %s@%s\n", user, realm));
72                 if (!lp_allow_trusted_domains()) {
73                         return NT_STATUS_LOGON_FAILURE;
74                 }
75         }
76
77         if (logon_info && logon_info->info3.base.logon_domain.string) {
78                 domain = talloc_strdup(mem_ctx,
79                                         logon_info->info3.base.logon_domain.string);
80                 if (!domain) {
81                         return NT_STATUS_NO_MEMORY;
82                 }
83                 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                 struct wbcDomainInfo *info = NULL;
95
96                 DEBUG(10, ("Mapping [%s] to short name using winbindd\n",
97                            realm));
98
99                 wbc_status = wbcDomainInfo(realm, &info);
100
101                 if (WBC_ERROR_IS_OK(wbc_status)) {
102                         domain = talloc_strdup(mem_ctx,
103                                                 info->short_name);
104                         wbcFreeMemory(info);
105                 } else {
106                         DEBUG(3, ("Could not find short name: %s\n",
107                                   wbcErrorString(wbc_status)));
108                         domain = talloc_strdup(mem_ctx, realm);
109                 }
110                 if (!domain) {
111                         return NT_STATUS_NO_MEMORY;
112                 }
113                 DEBUG(10, ("Domain is [%s] (using Winbind)\n", domain));
114         }
115
116         fuser = talloc_asprintf(mem_ctx,
117                                 "%s%c%s",
118                                 domain,
119                                 *lp_winbind_separator(),
120                                 user);
121         if (!fuser) {
122                 return NT_STATUS_NO_MEMORY;
123         }
124
125         *is_mapped = map_username(mem_ctx, fuser, &fuser);
126         if (!fuser) {
127                 return NT_STATUS_NO_MEMORY;
128         }
129         *mapped_to_guest = false;
130
131         pw = smb_getpwnam(mem_ctx, fuser, &unixuser, true);
132         if (pw) {
133                 if (!unixuser) {
134                         return NT_STATUS_NO_MEMORY;
135                 }
136                 /* if a real user check pam account restrictions */
137                 /* only really perfomed if "obey pam restriction" is true */
138                 /* do this before an eventual mapping to guest occurs */
139                 status = smb_pam_accountcheck(pw->pw_name, cli_name);
140                 if (!NT_STATUS_IS_OK(status)) {
141                         DEBUG(1, ("PAM account restrictions prevent user "
142                                   "[%s] login\n", unixuser));
143                         return status;
144                 }
145         }
146         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                 if (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_UID) {
153                         *mapped_to_guest = true;
154                         fuser = talloc_strdup(mem_ctx, lp_guestaccount());
155                         if (!fuser) {
156                                 return NT_STATUS_NO_MEMORY;
157                         }
158                         pw = smb_getpwnam(mem_ctx, fuser, &unixuser, true);
159                 }
160
161                 /* extra sanity check that the guest account is valid */
162                 if (!pw) {
163                         DEBUG(1, ("Username %s is invalid on this system\n",
164                                   fuser));
165                         return NT_STATUS_LOGON_FAILURE;
166                 }
167         }
168
169         if (!unixuser) {
170                 return NT_STATUS_NO_MEMORY;
171         }
172
173         *username = talloc_strdup(mem_ctx, unixuser);
174         if (!*username) {
175                 return NT_STATUS_NO_MEMORY;
176         }
177         *ntuser = user;
178         *ntdomain = domain;
179         *_pw = pw;
180
181         return NT_STATUS_OK;
182 }
183
184 NTSTATUS make_session_info_krb5(TALLOC_CTX *mem_ctx,
185                                 char *ntuser,
186                                 char *ntdomain,
187                                 char *username,
188                                 struct passwd *pw,
189                                 struct PAC_LOGON_INFO *logon_info,
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         if (mapped_to_guest) {
198                 status = make_server_info_guest(mem_ctx, &server_info);
199                 if (!NT_STATUS_IS_OK(status)) {
200                         DEBUG(1, ("make_server_info_guest failed: %s!\n",
201                                   nt_errstr(status)));
202                         return status;
203                 }
204
205         } else if (logon_info) {
206                 /* pass the unmapped username here since map_username()
207                    will be called again in make_server_info_info3() */
208
209                 status = make_server_info_info3(mem_ctx,
210                                                 ntuser, ntdomain,
211                                                 &server_info,
212                                                 &logon_info->info3);
213                 if (!NT_STATUS_IS_OK(status)) {
214                         DEBUG(1, ("make_server_info_info3 failed: %s!\n",
215                                   nt_errstr(status)));
216                         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                 /* The stupid make_server_info_XX functions here
227                    don't take a talloc context. */
228                 struct auth_serversupplied_info *tmp = NULL;
229
230                 sampass = samu_new(talloc_tos());
231                 if (sampass == NULL) {
232                         return NT_STATUS_NO_MEMORY;
233                 }
234
235                 if (pdb_getsampwnam(sampass, username)) {
236                         DEBUG(10, ("found user %s in passdb, calling "
237                                    "make_server_info_sam\n", username));
238                         status = make_server_info_sam(&tmp, sampass);
239                 } else {
240                         /*
241                          * User not in passdb, make it up artificially
242                          */
243                         DEBUG(10, ("didn't find user %s in passdb, calling "
244                                    "make_server_info_pw\n", username));
245                         status = make_server_info_pw(&tmp, username, pw);
246                 }
247
248                 TALLOC_FREE(sampass);
249
250                 if (!NT_STATUS_IS_OK(status)) {
251                         DEBUG(1, ("make_server_info_[sam|pw] failed: %s!\n",
252                                   nt_errstr(status)));
253                         return status;
254                 }
255
256                 /* Steal tmp server info into the server_info pointer. */
257                 server_info = talloc_move(mem_ctx, &tmp);
258
259                 /* make_server_info_pw does not set the domain. Without this
260                  * we end up with the local netbios name in substitutions for
261                  * %D. */
262
263                 if (server_info->info3 != NULL) {
264                         server_info->info3->base.logon_domain.string =
265                                 talloc_strdup(server_info->info3, ntdomain);
266                 }
267         }
268
269         server_info->nss_token |= username_was_mapped;
270
271         status = create_local_token(mem_ctx, server_info, session_key, ntuser, session_info);
272         talloc_free(server_info);
273         if (!NT_STATUS_IS_OK(status)) {
274                 DEBUG(10,("failed to create local token: %s\n",
275                           nt_errstr(status)));
276                 return status;
277         }
278
279         return NT_STATUS_OK;
280 }
281
282 #else /* HAVE_KRB5 */
283 NTSTATUS get_user_from_kerberos_info(TALLOC_CTX *mem_ctx,
284                                      const char *cli_name,
285                                      const char *princ_name,
286                                      struct PAC_LOGON_INFO *logon_info,
287                                      bool *is_mapped,
288                                      bool *mapped_to_guest,
289                                      char **ntuser,
290                                      char **ntdomain,
291                                      char **username,
292                                      struct passwd **_pw)
293 {
294         return NT_STATUS_NOT_IMPLEMENTED;
295 }
296
297 NTSTATUS make_session_info_krb5(TALLOC_CTX *mem_ctx,
298                                 char *ntuser,
299                                 char *ntdomain,
300                                 char *username,
301                                 struct passwd *pw,
302                                 struct PAC_LOGON_INFO *logon_info,
303                                 bool mapped_to_guest, bool username_was_mapped,
304                                 DATA_BLOB *session_key,
305                                 struct auth_session_info **session_info)
306 {
307         return NT_STATUS_NOT_IMPLEMENTED;
308 }
309
310 #endif /* HAVE_KRB5 */