root/source3/auth/auth.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. smb_register_auth
  2. auth_find_backend_entry
  3. get_ntlm_challenge
  4. check_domain_match
  5. check_ntlm_password
  6. free_auth_context
  7. make_auth_context
  8. load_auth_module
  9. make_auth_context_text_list
  10. make_auth_context_subsystem
  11. make_auth_context_fixed

   1 /* 
   2    Unix SMB/CIFS implementation.
   3    Password and authentication handling
   4    Copyright (C) Andrew Bartlett         2001-2002
   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 
  22 #undef DBGC_CLASS
  23 #define DBGC_CLASS DBGC_AUTH
  24 
  25 static_decl_auth;
  26 
  27 static struct auth_init_function_entry *backends = NULL;
  28 
  29 static struct auth_init_function_entry *auth_find_backend_entry(const char *name);
  30 
  31 NTSTATUS smb_register_auth(int version, const char *name, auth_init_function init)
     /* [<][>][^][v][top][bottom][index][help] */
  32 {
  33         struct auth_init_function_entry *entry = backends;
  34 
  35         if (version != AUTH_INTERFACE_VERSION) {
  36                 DEBUG(0,("Can't register auth_method!\n"
  37                          "You tried to register an auth module with AUTH_INTERFACE_VERSION %d, while this version of samba uses %d\n",
  38                          version,AUTH_INTERFACE_VERSION));
  39                 return NT_STATUS_OBJECT_TYPE_MISMATCH;
  40         }
  41 
  42         if (!name || !init) {
  43                 return NT_STATUS_INVALID_PARAMETER;
  44         }
  45 
  46         DEBUG(5,("Attempting to register auth backend %s\n", name));
  47 
  48         if (auth_find_backend_entry(name)) {
  49                 DEBUG(0,("There already is an auth method registered with the name %s!\n", name));
  50                 return NT_STATUS_OBJECT_NAME_COLLISION;
  51         }
  52 
  53         entry = SMB_XMALLOC_P(struct auth_init_function_entry);
  54         entry->name = smb_xstrdup(name);
  55         entry->init = init;
  56 
  57         DLIST_ADD(backends, entry);
  58         DEBUG(5,("Successfully added auth method '%s'\n", name));
  59         return NT_STATUS_OK;
  60 }
  61 
  62 static struct auth_init_function_entry *auth_find_backend_entry(const char *name)
     /* [<][>][^][v][top][bottom][index][help] */
  63 {
  64         struct auth_init_function_entry *entry = backends;
  65 
  66         while(entry) {
  67                 if (strcmp(entry->name, name)==0) return entry;
  68                 entry = entry->next;
  69         }
  70 
  71         return NULL;
  72 }
  73 
  74 /****************************************************************************
  75  Try to get a challenge out of the various authentication modules.
  76  Returns a const char of length 8 bytes.
  77 ****************************************************************************/
  78 
  79 static void get_ntlm_challenge(struct auth_context *auth_context,
     /* [<][>][^][v][top][bottom][index][help] */
  80                                uint8_t chal[8])
  81 {
  82         DATA_BLOB challenge = data_blob_null;
  83         const char *challenge_set_by = NULL;
  84         auth_methods *auth_method;
  85         TALLOC_CTX *mem_ctx;
  86 
  87         if (auth_context->challenge.length) {
  88                 DEBUG(5, ("get_ntlm_challenge (auth subsystem): returning previous challenge by module %s (normal)\n", 
  89                           auth_context->challenge_set_by));
  90                 memcpy(chal, auth_context->challenge.data, 8);
  91                 return;
  92         }
  93 
  94         auth_context->challenge_may_be_modified = False;
  95 
  96         for (auth_method = auth_context->auth_method_list; auth_method; auth_method = auth_method->next) {
  97                 if (auth_method->get_chal == NULL) {
  98                         DEBUG(5, ("auth_get_challenge: module %s did not want to specify a challenge\n", auth_method->name));
  99                         continue;
 100                 }
 101 
 102                 DEBUG(5, ("auth_get_challenge: getting challenge from module %s\n", auth_method->name));
 103                 if (challenge_set_by != NULL) {
 104                         DEBUG(1, ("auth_get_challenge: CONFIGURATION ERROR: authentication method %s has already specified a challenge.  Challenge by %s ignored.\n", 
 105                                   challenge_set_by, auth_method->name));
 106                         continue;
 107                 }
 108 
 109                 mem_ctx = talloc_init("auth_get_challenge for module %s", auth_method->name);
 110                 if (!mem_ctx) {
 111                         smb_panic("talloc_init() failed!");
 112                 }
 113 
 114                 challenge = auth_method->get_chal(auth_context, &auth_method->private_data, mem_ctx);
 115                 if (!challenge.length) {
 116                         DEBUG(3, ("auth_get_challenge: getting challenge from authentication method %s FAILED.\n", 
 117                                   auth_method->name));
 118                 } else {
 119                         DEBUG(5, ("auth_get_challenge: successfully got challenge from module %s\n", auth_method->name));
 120                         auth_context->challenge = challenge;
 121                         challenge_set_by = auth_method->name;
 122                         auth_context->challenge_set_method = auth_method;
 123                 }
 124                 talloc_destroy(mem_ctx);
 125         }
 126 
 127         if (!challenge_set_by) {
 128                 uchar tmp[8];
 129 
 130                 generate_random_buffer(tmp, sizeof(tmp));
 131                 auth_context->challenge = data_blob_talloc(auth_context->mem_ctx, 
 132                                                            tmp, sizeof(tmp));
 133 
 134                 challenge_set_by = "random";
 135                 auth_context->challenge_may_be_modified = True;
 136         } 
 137 
 138         DEBUG(5, ("auth_context challenge created by %s\n", challenge_set_by));
 139         DEBUG(5, ("challenge is: \n"));
 140         dump_data(5, auth_context->challenge.data, auth_context->challenge.length);
 141 
 142         SMB_ASSERT(auth_context->challenge.length == 8);
 143 
 144         auth_context->challenge_set_by=challenge_set_by;
 145 
 146         memcpy(chal, auth_context->challenge.data, 8);
 147 }
 148 
 149 
 150 /**
 151  * Check user is in correct domain (if required)
 152  *
 153  * @param user Only used to fill in the debug message
 154  * 
 155  * @param domain The domain to be verified
 156  *
 157  * @return True if the user can connect with that domain, 
 158  *         False otherwise.
 159 **/
 160 
 161 static bool check_domain_match(const char *user, const char *domain) 
     /* [<][>][^][v][top][bottom][index][help] */
 162 {
 163         /*
 164          * If we aren't serving to trusted domains, we must make sure that
 165          * the validation request comes from an account in the same domain
 166          * as the Samba server
 167          */
 168 
 169         if (!lp_allow_trusted_domains() &&
 170             !(strequal("", domain) || 
 171               strequal(lp_workgroup(), domain) || 
 172               is_myname(domain))) {
 173                 DEBUG(1, ("check_domain_match: Attempt to connect as user %s from domain %s denied.\n", user, domain));
 174                 return False;
 175         } else {
 176                 return True;
 177         }
 178 }
 179 
 180 /**
 181  * Check a user's Plaintext, LM or NTLM password.
 182  *
 183  * Check a user's password, as given in the user_info struct and return various
 184  * interesting details in the server_info struct.
 185  *
 186  * This function does NOT need to be in a become_root()/unbecome_root() pair
 187  * as it makes the calls itself when needed.
 188  *
 189  * The return value takes precedence over the contents of the server_info 
 190  * struct.  When the return is other than NT_STATUS_OK the contents 
 191  * of that structure is undefined.
 192  *
 193  * @param user_info Contains the user supplied components, including the passwords.
 194  *                  Must be created with make_user_info() or one of its wrappers.
 195  *
 196  * @param auth_context Supplies the challenges and some other data. 
 197  *                  Must be created with make_auth_context(), and the challenges should be 
 198  *                  filled in, either at creation or by calling the challenge geneation 
 199  *                  function auth_get_challenge().  
 200  *
 201  * @param server_info If successful, contains information about the authentication, 
 202  *                    including a struct samu struct describing the user.
 203  *
 204  * @return An NTSTATUS with NT_STATUS_OK or an appropriate error.
 205  *
 206  **/
 207 
 208 static NTSTATUS check_ntlm_password(const struct auth_context *auth_context,
     /* [<][>][^][v][top][bottom][index][help] */
 209                                     const struct auth_usersupplied_info *user_info, 
 210                                     struct auth_serversupplied_info **server_info)
 211 {
 212         /* if all the modules say 'not for me' this is reasonable */
 213         NTSTATUS nt_status = NT_STATUS_NO_SUCH_USER;
 214         const char *unix_username;
 215         auth_methods *auth_method;
 216         TALLOC_CTX *mem_ctx;
 217 
 218         if (!user_info || !auth_context || !server_info)
 219                 return NT_STATUS_LOGON_FAILURE;
 220 
 221         DEBUG(3, ("check_ntlm_password:  Checking password for unmapped user [%s]\\[%s]@[%s] with the new password interface\n", 
 222                   user_info->client_domain, user_info->smb_name, user_info->wksta_name));
 223 
 224         DEBUG(3, ("check_ntlm_password:  mapped user is: [%s]\\[%s]@[%s]\n", 
 225                   user_info->domain, user_info->internal_username, user_info->wksta_name));
 226 
 227         if (auth_context->challenge.length != 8) {
 228                 DEBUG(0, ("check_ntlm_password:  Invalid challenge stored for this auth context - cannot continue\n"));
 229                 return NT_STATUS_LOGON_FAILURE;
 230         }
 231 
 232         if (auth_context->challenge_set_by)
 233                 DEBUG(10, ("check_ntlm_password: auth_context challenge created by %s\n",
 234                                         auth_context->challenge_set_by));
 235 
 236         DEBUG(10, ("challenge is: \n"));
 237         dump_data(5, auth_context->challenge.data, auth_context->challenge.length);
 238 
 239 #ifdef DEBUG_PASSWORD
 240         DEBUG(100, ("user_info has passwords of length %d and %d\n", 
 241                     (int)user_info->lm_resp.length, (int)user_info->nt_resp.length));
 242         DEBUG(100, ("lm:\n"));
 243         dump_data(100, user_info->lm_resp.data, user_info->lm_resp.length);
 244         DEBUG(100, ("nt:\n"));
 245         dump_data(100, user_info->nt_resp.data, user_info->nt_resp.length);
 246 #endif
 247 
 248         /* This needs to be sorted:  If it doesn't match, what should we do? */
 249         if (!check_domain_match(user_info->smb_name, user_info->domain))
 250                 return NT_STATUS_LOGON_FAILURE;
 251 
 252         for (auth_method = auth_context->auth_method_list;auth_method; auth_method = auth_method->next) {
 253                 NTSTATUS result;
 254 
 255                 mem_ctx = talloc_init("%s authentication for user %s\\%s", auth_method->name, 
 256                                             user_info->domain, user_info->smb_name);
 257 
 258                 result = auth_method->auth(auth_context, auth_method->private_data, mem_ctx, user_info, server_info);
 259 
 260                 /* check if the module did anything */
 261                 if ( NT_STATUS_V(result) == NT_STATUS_V(NT_STATUS_NOT_IMPLEMENTED) ) {
 262                         DEBUG(10,("check_ntlm_password: %s had nothing to say\n", auth_method->name));
 263                         talloc_destroy(mem_ctx);
 264                         continue;
 265                 }
 266 
 267                 nt_status = result;
 268 
 269                 if (NT_STATUS_IS_OK(nt_status)) {
 270                         DEBUG(3, ("check_ntlm_password: %s authentication for user [%s] succeeded\n", 
 271                                   auth_method->name, user_info->smb_name));
 272                 } else {
 273                         DEBUG(5, ("check_ntlm_password: %s authentication for user [%s] FAILED with error %s\n", 
 274                                   auth_method->name, user_info->smb_name, nt_errstr(nt_status)));
 275                 }
 276 
 277                 talloc_destroy(mem_ctx);
 278 
 279                 if ( NT_STATUS_IS_OK(nt_status))
 280                 {
 281                                 break;                  
 282                 }
 283         }
 284 
 285         /* successful authentication */
 286 
 287         if (NT_STATUS_IS_OK(nt_status)) {
 288                 unix_username = (*server_info)->unix_name;
 289                 if (!(*server_info)->guest) {
 290                         /* We might not be root if we are an RPC call */
 291                         become_root();
 292                         nt_status = smb_pam_accountcheck(unix_username);
 293                         unbecome_root();
 294 
 295                         if (NT_STATUS_IS_OK(nt_status)) {
 296                                 DEBUG(5, ("check_ntlm_password:  PAM Account for user [%s] succeeded\n", 
 297                                           unix_username));
 298                         } else {
 299                                 DEBUG(3, ("check_ntlm_password:  PAM Account for user [%s] FAILED with error %s\n", 
 300                                           unix_username, nt_errstr(nt_status)));
 301                         } 
 302                 }
 303 
 304                 if (NT_STATUS_IS_OK(nt_status)) {
 305                         DEBUG((*server_info)->guest ? 5 : 2, 
 306                               ("check_ntlm_password:  %sauthentication for user [%s] -> [%s] -> [%s] succeeded\n", 
 307                                (*server_info)->guest ? "guest " : "", 
 308                                user_info->smb_name, 
 309                                user_info->internal_username, 
 310                                unix_username));
 311                 }
 312 
 313                 return nt_status;
 314         }
 315 
 316         /* failed authentication; check for guest lapping */
 317 
 318         DEBUG(2, ("check_ntlm_password:  Authentication for user [%s] -> [%s] FAILED with error %s\n", 
 319                   user_info->smb_name, user_info->internal_username, 
 320                   nt_errstr(nt_status)));
 321         ZERO_STRUCTP(server_info); 
 322 
 323         return nt_status;
 324 }
 325 
 326 /***************************************************************************
 327  Clear out a auth_context, and destroy the attached TALLOC_CTX
 328 ***************************************************************************/
 329 
 330 static void free_auth_context(struct auth_context **auth_context)
     /* [<][>][^][v][top][bottom][index][help] */
 331 {
 332         auth_methods *auth_method;
 333 
 334         if (*auth_context) {
 335                 /* Free private data of context's authentication methods */
 336                 for (auth_method = (*auth_context)->auth_method_list; auth_method; auth_method = auth_method->next) {
 337                         TALLOC_FREE(auth_method->private_data);
 338                 }
 339 
 340                 talloc_destroy((*auth_context)->mem_ctx);
 341                 *auth_context = NULL;
 342         }
 343 }
 344 
 345 /***************************************************************************
 346  Make a auth_info struct
 347 ***************************************************************************/
 348 
 349 static NTSTATUS make_auth_context(struct auth_context **auth_context) 
     /* [<][>][^][v][top][bottom][index][help] */
 350 {
 351         TALLOC_CTX *mem_ctx;
 352 
 353         mem_ctx = talloc_init("authentication context");
 354 
 355         *auth_context = TALLOC_P(mem_ctx, struct auth_context);
 356         if (!*auth_context) {
 357                 DEBUG(0,("make_auth_context: talloc failed!\n"));
 358                 talloc_destroy(mem_ctx);
 359                 return NT_STATUS_NO_MEMORY;
 360         }
 361         ZERO_STRUCTP(*auth_context);
 362 
 363         (*auth_context)->mem_ctx = mem_ctx;
 364         (*auth_context)->check_ntlm_password = check_ntlm_password;
 365         (*auth_context)->get_ntlm_challenge = get_ntlm_challenge;
 366         (*auth_context)->free = free_auth_context;
 367 
 368         return NT_STATUS_OK;
 369 }
 370 
 371 bool load_auth_module(struct auth_context *auth_context, 
     /* [<][>][^][v][top][bottom][index][help] */
 372                       const char *module, auth_methods **ret) 
 373 {
 374         static bool initialised_static_modules = False;
 375 
 376         struct auth_init_function_entry *entry;
 377         char *module_name = smb_xstrdup(module);
 378         char *module_params = NULL;
 379         char *p;
 380         bool good = False;
 381 
 382         /* Initialise static modules if not done so yet */
 383         if(!initialised_static_modules) {
 384                 static_init_auth;
 385                 initialised_static_modules = True;
 386         }
 387 
 388         DEBUG(5,("load_auth_module: Attempting to find an auth method to match %s\n",
 389                  module));
 390 
 391         p = strchr(module_name, ':');
 392         if (p) {
 393                 *p = 0;
 394                 module_params = p+1;
 395                 trim_char(module_params, ' ', ' ');
 396         }
 397 
 398         trim_char(module_name, ' ', ' ');
 399 
 400         entry = auth_find_backend_entry(module_name);
 401 
 402         if (entry == NULL) {
 403                 if (NT_STATUS_IS_OK(smb_probe_module("auth", module_name))) {
 404                         entry = auth_find_backend_entry(module_name);
 405                 }
 406         }
 407 
 408         if (entry != NULL) {
 409                 if (!NT_STATUS_IS_OK(entry->init(auth_context, module_params, ret))) {
 410                         DEBUG(0,("load_auth_module: auth method %s did not correctly init\n",
 411                                  module_name));
 412                 } else {
 413                         DEBUG(5,("load_auth_module: auth method %s has a valid init\n",
 414                                  module_name));
 415                         good = True;
 416                 }
 417         } else {
 418                 DEBUG(0,("load_auth_module: can't find auth method %s!\n", module_name));
 419         }
 420 
 421         SAFE_FREE(module_name);
 422         return good;
 423 }
 424 
 425 /***************************************************************************
 426  Make a auth_info struct for the auth subsystem
 427 ***************************************************************************/
 428 
 429 static NTSTATUS make_auth_context_text_list(struct auth_context **auth_context, char **text_list) 
     /* [<][>][^][v][top][bottom][index][help] */
 430 {
 431         auth_methods *list = NULL;
 432         auth_methods *t = NULL;
 433         NTSTATUS nt_status;
 434 
 435         if (!text_list) {
 436                 DEBUG(2,("make_auth_context_text_list: No auth method list!?\n"));
 437                 return NT_STATUS_UNSUCCESSFUL;
 438         }
 439 
 440         if (!NT_STATUS_IS_OK(nt_status = make_auth_context(auth_context)))
 441                 return nt_status;
 442 
 443         for (;*text_list; text_list++) { 
 444                 if (load_auth_module(*auth_context, *text_list, &t)) {
 445                     DLIST_ADD_END(list, t, auth_methods *);
 446                 }
 447         }
 448 
 449         (*auth_context)->auth_method_list = list;
 450 
 451         return nt_status;
 452 }
 453 
 454 /***************************************************************************
 455  Make a auth_context struct for the auth subsystem
 456 ***************************************************************************/
 457 
 458 NTSTATUS make_auth_context_subsystem(struct auth_context **auth_context) 
     /* [<][>][^][v][top][bottom][index][help] */
 459 {
 460         char **auth_method_list = NULL; 
 461         NTSTATUS nt_status;
 462 
 463         if (lp_auth_methods()
 464             && !(auth_method_list = str_list_copy(talloc_tos(), 
 465                               lp_auth_methods()))) {
 466                 return NT_STATUS_NO_MEMORY;
 467         }
 468 
 469         if (auth_method_list == NULL) {
 470                 switch (lp_security()) 
 471                 {
 472                 case SEC_DOMAIN:
 473                         DEBUG(5,("Making default auth method list for security=domain\n"));
 474                         auth_method_list = str_list_make_v3(
 475                                 talloc_tos(), "guest sam winbind:ntdomain",
 476                                 NULL);
 477                         break;
 478                 case SEC_SERVER:
 479                         DEBUG(5,("Making default auth method list for security=server\n"));
 480                         auth_method_list = str_list_make_v3(
 481                                 talloc_tos(), "guest sam smbserver",
 482                                 NULL);
 483                         break;
 484                 case SEC_USER:
 485                         if (lp_encrypted_passwords()) { 
 486                                 if ((lp_server_role() == ROLE_DOMAIN_PDC) || (lp_server_role() == ROLE_DOMAIN_BDC)) {
 487                                         DEBUG(5,("Making default auth method list for DC, security=user, encrypt passwords = yes\n"));
 488                                         auth_method_list = str_list_make_v3(
 489                                                 talloc_tos(),
 490                                                 "guest sam winbind:trustdomain",
 491                                                 NULL);
 492                                 } else {
 493                                         DEBUG(5,("Making default auth method list for standalone security=user, encrypt passwords = yes\n"));
 494                                         auth_method_list = str_list_make_v3(
 495                                                 talloc_tos(), "guest sam",
 496                                                 NULL);
 497                                 }
 498                         } else {
 499                                 DEBUG(5,("Making default auth method list for security=user, encrypt passwords = no\n"));
 500                                 auth_method_list = str_list_make_v3(
 501                                         talloc_tos(), "guest unix", NULL);
 502                         }
 503                         break;
 504                 case SEC_SHARE:
 505                         if (lp_encrypted_passwords()) {
 506                                 DEBUG(5,("Making default auth method list for security=share, encrypt passwords = yes\n"));
 507                                 auth_method_list = str_list_make_v3(
 508                                         talloc_tos(), "guest sam", NULL);
 509                         } else {
 510                                 DEBUG(5,("Making default auth method list for security=share, encrypt passwords = no\n"));
 511                                 auth_method_list = str_list_make_v3(
 512                                         talloc_tos(), "guest unix", NULL);
 513                         }
 514                         break;
 515                 case SEC_ADS:
 516                         DEBUG(5,("Making default auth method list for security=ADS\n"));
 517                         auth_method_list = str_list_make_v3(
 518                                 talloc_tos(), "guest sam winbind:ntdomain",
 519                                 NULL);
 520                         break;
 521                 default:
 522                         DEBUG(5,("Unknown auth method!\n"));
 523                         return NT_STATUS_UNSUCCESSFUL;
 524                 }
 525         } else {
 526                 DEBUG(5,("Using specified auth order\n"));
 527         }
 528 
 529         nt_status = make_auth_context_text_list(auth_context,
 530                                                 auth_method_list);
 531 
 532         TALLOC_FREE(auth_method_list);
 533         return nt_status;
 534 }
 535 
 536 /***************************************************************************
 537  Make a auth_info struct with a fixed challenge
 538 ***************************************************************************/
 539 
 540 NTSTATUS make_auth_context_fixed(struct auth_context **auth_context, uchar chal[8]) 
     /* [<][>][^][v][top][bottom][index][help] */
 541 {
 542         NTSTATUS nt_status;
 543         if (!NT_STATUS_IS_OK(nt_status = make_auth_context_subsystem(auth_context))) {
 544                 return nt_status;
 545         }
 546 
 547         (*auth_context)->challenge = data_blob_talloc((*auth_context)->mem_ctx, chal, 8);
 548         (*auth_context)->challenge_set_by = "fixed";
 549         return nt_status;
 550 }
 551 
 552 

/* [<][>][^][v][top][bottom][index][help] */