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