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