Remove fstring from map_username. Create a more sane interface than the called-parame...
[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         char *fuser = NULL;
44         char *unixuser = NULL;
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         fuser = talloc_asprintf(mem_ctx,
113                                 "%s%c%s",
114                                 domain,
115                                 *lp_winbind_separator(),
116                                 user);
117         if (!fuser) {
118                 return NT_STATUS_NO_MEMORY;
119         }
120
121         *is_mapped = map_username(mem_ctx, fuser, &fuser);
122         if (!fuser) {
123                 return NT_STATUS_NO_MEMORY;
124         }
125
126         pw = smb_getpwnam(mem_ctx, fuser, &unixuser, true);
127         if (pw) {
128                 if (!unixuser) {
129                         return NT_STATUS_NO_MEMORY;
130                 }
131                 /* if a real user check pam account restrictions */
132                 /* only really perfomed if "obey pam restriction" is true */
133                 /* do this before an eventual mapping to guest occurs */
134                 status = smb_pam_accountcheck(pw->pw_name, cli_name);
135                 if (!NT_STATUS_IS_OK(status)) {
136                         DEBUG(1, ("PAM account restrictions prevent user "
137                                   "[%s] login\n", unixuser));
138                         return status;
139                 }
140         }
141         if (!pw) {
142
143                 /* this was originally the behavior of Samba 2.2, if a user
144                    did not have a local uid but has been authenticated, then
145                    map them to a guest account */
146
147                 if (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_UID) {
148                         *mapped_to_guest = true;
149                         fuser = talloc_strdup(mem_ctx, lp_guestaccount());
150                         if (!fuser) {
151                                 return NT_STATUS_NO_MEMORY;
152                         }
153                         pw = smb_getpwnam(mem_ctx, fuser, &unixuser, true);
154                 }
155
156                 /* extra sanity check that the guest account is valid */
157                 if (!pw) {
158                         DEBUG(1, ("Username %s is invalid on this system\n",
159                                   fuser));
160                         return NT_STATUS_LOGON_FAILURE;
161                 }
162         }
163
164         if (!unixuser) {
165                 return NT_STATUS_NO_MEMORY;
166         }
167
168         *username = talloc_strdup(mem_ctx, unixuser);
169         if (!*username) {
170                 return NT_STATUS_NO_MEMORY;
171         }
172         *ntuser = user;
173         *ntdomain = domain;
174         *_pw = pw;
175
176         return NT_STATUS_OK;
177 }
178
179 NTSTATUS make_server_info_krb5(TALLOC_CTX *mem_ctx,
180                                 char *ntuser,
181                                 char *ntdomain,
182                                 char *username,
183                                 struct passwd *pw,
184                                 struct PAC_LOGON_INFO *logon_info,
185                                 bool mapped_to_guest,
186                                 struct auth_serversupplied_info **server_info)
187 {
188         NTSTATUS status;
189
190         if (mapped_to_guest) {
191                 status = make_server_info_guest(mem_ctx, server_info);
192                 if (!NT_STATUS_IS_OK(status)) {
193                         DEBUG(1, ("make_server_info_guest failed: %s!\n",
194                                   nt_errstr(status)));
195                         return status;
196                 }
197
198         } else if (logon_info) {
199                 /* pass the unmapped username here since map_username()
200                    will be called again in make_server_info_info3() */
201
202                 status = make_server_info_info3(mem_ctx,
203                                                 ntuser, ntdomain,
204                                                 server_info,
205                                                 &logon_info->info3);
206                 if (!NT_STATUS_IS_OK(status)) {
207                         DEBUG(1, ("make_server_info_info3 failed: %s!\n",
208                                   nt_errstr(status)));
209                         return status;
210                 }
211
212         } else {
213                 /*
214                  * We didn't get a PAC, we have to make up the user
215                  * ourselves. Try to ask the pdb backend to provide
216                  * SID consistency with ntlmssp session setup
217                  */
218                 struct samu *sampass;
219                 /* The stupid make_server_info_XX functions here
220                    don't take a talloc context. */
221                 struct auth_serversupplied_info *tmp = NULL;
222
223                 sampass = samu_new(talloc_tos());
224                 if (sampass == NULL) {
225                         return NT_STATUS_NO_MEMORY;
226                 }
227
228                 if (pdb_getsampwnam(sampass, username)) {
229                         DEBUG(10, ("found user %s in passdb, calling "
230                                    "make_server_info_sam\n", username));
231                         status = make_server_info_sam(&tmp, sampass);
232                 } else {
233                         /*
234                          * User not in passdb, make it up artificially
235                          */
236                         DEBUG(10, ("didn't find user %s in passdb, calling "
237                                    "make_server_info_pw\n", username));
238                         status = make_server_info_pw(&tmp, username, pw);
239                 }
240                 TALLOC_FREE(sampass);
241
242                 if (!NT_STATUS_IS_OK(status)) {
243                         DEBUG(1, ("make_server_info_[sam|pw] failed: %s!\n",
244                                   nt_errstr(status)));
245                         return status;
246                 }
247
248                 /* Steal tmp server info into the server_info pointer. */
249                 *server_info = talloc_move(mem_ctx, &tmp);
250
251                 /* make_server_info_pw does not set the domain. Without this
252                  * we end up with the local netbios name in substitutions for
253                  * %D. */
254
255                 if ((*server_info)->info3 != NULL) {
256                         (*server_info)->info3->base.domain.string =
257                                 talloc_strdup((*server_info)->info3, ntdomain);
258                 }
259
260         }
261
262         return NT_STATUS_OK;
263 }
264
265 #else /* HAVE_KRB5 */
266 NTSTATUS get_user_from_kerberos_info(TALLOC_CTX *mem_ctx,
267                                      const char *cli_name,
268                                      const char *princ_name,
269                                      struct PAC_LOGON_INFO *logon_info,
270                                      bool *is_mapped,
271                                      bool *mapped_to_guest,
272                                      char **ntuser,
273                                      char **ntdomain,
274                                      char **username,
275                                      struct passwd **_pw)
276 {
277         return NT_STATUS_NOT_IMPLEMENTED;
278 }
279
280 NTSTATUS make_server_info_krb5(TALLOC_CTX *mem_ctx,
281                                 char *ntuser,
282                                 char *ntdomain,
283                                 char *username,
284                                 struct passwd *pw,
285                                 struct PAC_LOGON_INFO *logon_info,
286                                 bool mapped_to_guest,
287                                 struct auth_serversupplied_info **server_info)
288 {
289         return NT_STATUS_NOT_IMPLEMENTED;
290 }
291
292 #endif /* HAVE_KRB5 */