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