root/source3/winbindd/winbindd_pam.c

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

DEFINITIONS

This source file includes following definitions.
  1. append_info3_as_txt
  2. append_info3_as_ndr
  3. append_unix_username
  4. append_afs_token
  5. check_info3_in_group
  6. find_auth_domain
  7. fill_in_password_policy
  8. fillup_password_policy
  9. get_max_bad_attempts_from_lockout_policy
  10. get_pwd_properties
  11. generate_krb5_ccache
  12. setup_return_cc_name
  13. get_uid_from_state
  14. winbindd_raw_kerberos_login
  15. check_request_flags
  16. append_data
  17. winbindd_pam_auth
  18. winbindd_dual_pam_auth_cached
  19. winbindd_dual_pam_auth_kerberos
  20. winbindd_dual_pam_auth_samlogon
  21. winbindd_dual_pam_auth
  22. winbindd_pam_auth_crap
  23. winbindd_dual_pam_auth_crap
  24. winbindd_pam_chauthtok
  25. winbindd_dual_pam_chauthtok
  26. winbindd_pam_logoff
  27. winbindd_dual_pam_logoff
  28. winbindd_pam_chng_pswd_auth_crap
  29. winbindd_dual_pam_chng_pswd_auth_crap

   1 /*
   2    Unix SMB/CIFS implementation.
   3 
   4    Winbind daemon - pam auth funcions
   5 
   6    Copyright (C) Andrew Tridgell 2000
   7    Copyright (C) Tim Potter 2001
   8    Copyright (C) Andrew Bartlett 2001-2002
   9    Copyright (C) Guenther Deschner 2005
  10 
  11    This program is free software; you can redistribute it and/or modify
  12    it under the terms of the GNU General Public License as published by
  13    the Free Software Foundation; either version 3 of the License, or
  14    (at your option) any later version.
  15 
  16    This program is distributed in the hope that it will be useful,
  17    but WITHOUT ANY WARRANTY; without even the implied warranty of
  18    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  19    GNU General Public License for more details.
  20 
  21    You should have received a copy of the GNU General Public License
  22    along with this program.  If not, see <http://www.gnu.org/licenses/>.
  23 */
  24 
  25 #include "includes.h"
  26 #include "winbindd.h"
  27 #undef DBGC_CLASS
  28 #define DBGC_CLASS DBGC_WINBIND
  29 
  30 #define LOGON_KRB5_FAIL_CLOCK_SKEW      0x02000000
  31 
  32 static NTSTATUS append_info3_as_txt(TALLOC_CTX *mem_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
  33                                     struct winbindd_cli_state *state,
  34                                     struct netr_SamInfo3 *info3)
  35 {
  36         char *ex;
  37         size_t size;
  38         uint32_t i;
  39 
  40         state->response.data.auth.info3.logon_time =
  41                 nt_time_to_unix(info3->base.last_logon);
  42         state->response.data.auth.info3.logoff_time =
  43                 nt_time_to_unix(info3->base.last_logoff);
  44         state->response.data.auth.info3.kickoff_time =
  45                 nt_time_to_unix(info3->base.acct_expiry);
  46         state->response.data.auth.info3.pass_last_set_time =
  47                 nt_time_to_unix(info3->base.last_password_change);
  48         state->response.data.auth.info3.pass_can_change_time =
  49                 nt_time_to_unix(info3->base.allow_password_change);
  50         state->response.data.auth.info3.pass_must_change_time =
  51                 nt_time_to_unix(info3->base.force_password_change);
  52 
  53         state->response.data.auth.info3.logon_count = info3->base.logon_count;
  54         state->response.data.auth.info3.bad_pw_count = info3->base.bad_password_count;
  55 
  56         state->response.data.auth.info3.user_rid = info3->base.rid;
  57         state->response.data.auth.info3.group_rid = info3->base.primary_gid;
  58         sid_to_fstring(state->response.data.auth.info3.dom_sid, info3->base.domain_sid);
  59 
  60         state->response.data.auth.info3.num_groups = info3->base.groups.count;
  61         state->response.data.auth.info3.user_flgs = info3->base.user_flags;
  62 
  63         state->response.data.auth.info3.acct_flags = info3->base.acct_flags;
  64         state->response.data.auth.info3.num_other_sids = info3->sidcount;
  65 
  66         fstrcpy(state->response.data.auth.info3.user_name,
  67                 info3->base.account_name.string);
  68         fstrcpy(state->response.data.auth.info3.full_name,
  69                 info3->base.full_name.string);
  70         fstrcpy(state->response.data.auth.info3.logon_script,
  71                 info3->base.logon_script.string);
  72         fstrcpy(state->response.data.auth.info3.profile_path,
  73                 info3->base.profile_path.string);
  74         fstrcpy(state->response.data.auth.info3.home_dir,
  75                 info3->base.home_directory.string);
  76         fstrcpy(state->response.data.auth.info3.dir_drive,
  77                 info3->base.home_drive.string);
  78 
  79         fstrcpy(state->response.data.auth.info3.logon_srv,
  80                 info3->base.logon_server.string);
  81         fstrcpy(state->response.data.auth.info3.logon_dom,
  82                 info3->base.domain.string);
  83 
  84         ex = talloc_strdup(mem_ctx, "");
  85         NT_STATUS_HAVE_NO_MEMORY(ex);
  86 
  87         for (i=0; i < info3->base.groups.count; i++) {
  88                 ex = talloc_asprintf_append_buffer(ex, "0x%08X:0x%08X\n",
  89                                                    info3->base.groups.rids[i].rid,
  90                                                    info3->base.groups.rids[i].attributes);
  91                 NT_STATUS_HAVE_NO_MEMORY(ex);
  92         }
  93 
  94         for (i=0; i < info3->sidcount; i++) {
  95                 char *sid;
  96 
  97                 sid = dom_sid_string(mem_ctx, info3->sids[i].sid);
  98                 NT_STATUS_HAVE_NO_MEMORY(sid);
  99 
 100                 ex = talloc_asprintf_append_buffer(ex, "%s:0x%08X\n",
 101                                                    sid,
 102                                                    info3->sids[i].attributes);
 103                 NT_STATUS_HAVE_NO_MEMORY(ex);
 104 
 105                 talloc_free(sid);
 106         }
 107 
 108         size = talloc_get_size(ex);
 109 
 110         SAFE_FREE(state->response.extra_data.data);
 111         state->response.extra_data.data = SMB_MALLOC(size);
 112         if (!state->response.extra_data.data) {
 113                 return NT_STATUS_NO_MEMORY;
 114         }
 115         memcpy(state->response.extra_data.data, ex, size);
 116         talloc_free(ex);
 117 
 118         state->response.length += size;
 119 
 120         return NT_STATUS_OK;
 121 }
 122 
 123 static NTSTATUS append_info3_as_ndr(TALLOC_CTX *mem_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
 124                                     struct winbindd_cli_state *state,
 125                                     struct netr_SamInfo3 *info3)
 126 {
 127         DATA_BLOB blob;
 128         enum ndr_err_code ndr_err;
 129 
 130         ndr_err = ndr_push_struct_blob(&blob, mem_ctx, NULL, info3,
 131                                        (ndr_push_flags_fn_t)ndr_push_netr_SamInfo3);
 132         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
 133                 DEBUG(0,("append_info3_as_ndr: failed to append\n"));
 134                 return ndr_map_error2ntstatus(ndr_err);
 135         }
 136 
 137         SAFE_FREE(state->response.extra_data.data);
 138         state->response.extra_data.data = SMB_MALLOC(blob.length);
 139         if (!state->response.extra_data.data) {
 140                 data_blob_free(&blob);
 141                 return NT_STATUS_NO_MEMORY;
 142         }
 143 
 144         memset(state->response.extra_data.data, '\0', blob.length);
 145         memcpy(state->response.extra_data.data, blob.data, blob.length);
 146         state->response.length += blob.length;
 147 
 148         data_blob_free(&blob);
 149 
 150         return NT_STATUS_OK;
 151 }
 152 
 153 static NTSTATUS append_unix_username(TALLOC_CTX *mem_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
 154                                      struct winbindd_cli_state *state,
 155                                      const struct netr_SamInfo3 *info3,
 156                                      const char *name_domain,
 157                                      const char *name_user)
 158 {
 159         /* We've been asked to return the unix username, per
 160            'winbind use default domain' settings and the like */
 161 
 162         const char *nt_username, *nt_domain;
 163 
 164         nt_domain = talloc_strdup(mem_ctx, info3->base.domain.string);
 165         if (!nt_domain) {
 166                 /* If the server didn't give us one, just use the one
 167                  * we sent them */
 168                 nt_domain = name_domain;
 169         }
 170 
 171         nt_username = talloc_strdup(mem_ctx, info3->base.account_name.string);
 172         if (!nt_username) {
 173                 /* If the server didn't give us one, just use the one
 174                  * we sent them */
 175                 nt_username = name_user;
 176         }
 177 
 178         fill_domain_username(state->response.data.auth.unix_username,
 179                              nt_domain, nt_username, true);
 180 
 181         DEBUG(5,("Setting unix username to [%s]\n",
 182                 state->response.data.auth.unix_username));
 183 
 184         return NT_STATUS_OK;
 185 }
 186 
 187 static NTSTATUS append_afs_token(TALLOC_CTX *mem_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
 188                                  struct winbindd_cli_state *state,
 189                                  const struct netr_SamInfo3 *info3,
 190                                  const char *name_domain,
 191                                  const char *name_user)
 192 {
 193         char *afsname = NULL;
 194         char *cell;
 195 
 196         afsname = talloc_strdup(mem_ctx, lp_afs_username_map());
 197         if (afsname == NULL) {
 198                 return NT_STATUS_NO_MEMORY;
 199         }
 200 
 201         afsname = talloc_string_sub(mem_ctx,
 202                                     lp_afs_username_map(),
 203                                     "%D", name_domain);
 204         afsname = talloc_string_sub(mem_ctx, afsname,
 205                                     "%u", name_user);
 206         afsname = talloc_string_sub(mem_ctx, afsname,
 207                                     "%U", name_user);
 208 
 209         {
 210                 DOM_SID user_sid;
 211                 fstring sidstr;
 212 
 213                 sid_copy(&user_sid, info3->base.domain_sid);
 214                 sid_append_rid(&user_sid, info3->base.rid);
 215                 sid_to_fstring(sidstr, &user_sid);
 216                 afsname = talloc_string_sub(mem_ctx, afsname,
 217                                             "%s", sidstr);
 218         }
 219 
 220         if (afsname == NULL) {
 221                 return NT_STATUS_NO_MEMORY;
 222         }
 223 
 224         strlower_m(afsname);
 225 
 226         DEBUG(10, ("Generating token for user %s\n", afsname));
 227 
 228         cell = strchr(afsname, '@');
 229 
 230         if (cell == NULL) {
 231                 return NT_STATUS_NO_MEMORY;
 232         }
 233 
 234         *cell = '\0';
 235         cell += 1;
 236 
 237         /* Append an AFS token string */
 238         SAFE_FREE(state->response.extra_data.data);
 239         state->response.extra_data.data =
 240                 afs_createtoken_str(afsname, cell);
 241 
 242         if (state->response.extra_data.data != NULL) {
 243                 state->response.length +=
 244                         strlen((const char *)state->response.extra_data.data)+1;
 245         }
 246 
 247         return NT_STATUS_OK;
 248 }
 249 
 250 static NTSTATUS check_info3_in_group(TALLOC_CTX *mem_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
 251                                      struct netr_SamInfo3 *info3,
 252                                      const char *group_sid)
 253 /**
 254  * Check whether a user belongs to a group or list of groups.
 255  *
 256  * @param mem_ctx talloc memory context.
 257  * @param info3 user information, including group membership info.
 258  * @param group_sid One or more groups , separated by commas.
 259  *
 260  * @return NT_STATUS_OK on success,
 261  *    NT_STATUS_LOGON_FAILURE if the user does not belong,
 262  *    or other NT_STATUS_IS_ERR(status) for other kinds of failure.
 263  */
 264 {
 265         DOM_SID *require_membership_of_sid;
 266         size_t num_require_membership_of_sid;
 267         char *req_sid;
 268         const char *p;
 269         DOM_SID sid;
 270         size_t i;
 271         struct nt_user_token *token;
 272         TALLOC_CTX *frame = NULL;
 273         NTSTATUS status;
 274 
 275         /* Parse the 'required group' SID */
 276 
 277         if (!group_sid || !group_sid[0]) {
 278                 /* NO sid supplied, all users may access */
 279                 return NT_STATUS_OK;
 280         }
 281 
 282         if (!(token = TALLOC_ZERO_P(mem_ctx, struct nt_user_token))) {
 283                 DEBUG(0, ("talloc failed\n"));
 284                 return NT_STATUS_NO_MEMORY;
 285         }
 286 
 287         num_require_membership_of_sid = 0;
 288         require_membership_of_sid = NULL;
 289 
 290         p = group_sid;
 291 
 292         frame = talloc_stackframe();
 293         while (next_token_talloc(frame, &p, &req_sid, ",")) {
 294                 if (!string_to_sid(&sid, req_sid)) {
 295                         DEBUG(0, ("check_info3_in_group: could not parse %s "
 296                                   "as a SID!", req_sid));
 297                         TALLOC_FREE(frame);
 298                         return NT_STATUS_INVALID_PARAMETER;
 299                 }
 300 
 301                 status = add_sid_to_array(mem_ctx, &sid,
 302                                           &require_membership_of_sid,
 303                                           &num_require_membership_of_sid);
 304                 if (!NT_STATUS_IS_OK(status)) {
 305                         DEBUG(0, ("add_sid_to_array failed\n"));
 306                         TALLOC_FREE(frame);
 307                         return status;
 308                 }
 309         }
 310 
 311         TALLOC_FREE(frame);
 312 
 313         status = sid_array_from_info3(mem_ctx, info3,
 314                                       &token->user_sids,
 315                                       &token->num_sids,
 316                                       true, false);
 317         if (!NT_STATUS_IS_OK(status)) {
 318                 return status;
 319         }
 320 
 321         if (!NT_STATUS_IS_OK(status = add_aliases(get_global_sam_sid(),
 322                                                   token))
 323             || !NT_STATUS_IS_OK(status = add_aliases(&global_sid_Builtin,
 324                                                      token))) {
 325                 DEBUG(3, ("could not add aliases: %s\n",
 326                           nt_errstr(status)));
 327                 return status;
 328         }
 329 
 330         debug_nt_user_token(DBGC_CLASS, 10, token);
 331 
 332         for (i=0; i<num_require_membership_of_sid; i++) {
 333                 DEBUG(10, ("Checking SID %s\n", sid_string_dbg(
 334                                    &require_membership_of_sid[i])));
 335                 if (nt_token_check_sid(&require_membership_of_sid[i],
 336                                        token)) {
 337                         DEBUG(10, ("Access ok\n"));
 338                         return NT_STATUS_OK;
 339                 }
 340         }
 341 
 342         /* Do not distinguish this error from a wrong username/pw */
 343 
 344         return NT_STATUS_LOGON_FAILURE;
 345 }
 346 
 347 struct winbindd_domain *find_auth_domain(struct winbindd_cli_state *state,
     /* [<][>][^][v][top][bottom][index][help] */
 348                                         const char *domain_name)
 349 {
 350         struct winbindd_domain *domain;
 351 
 352         if (IS_DC) {
 353                 domain = find_domain_from_name_noinit(domain_name);
 354                 if (domain == NULL) {
 355                         DEBUG(3, ("Authentication for domain [%s] refused "
 356                                   "as it is not a trusted domain\n",
 357                                   domain_name));
 358                 }
 359                 return domain;
 360         }
 361 
 362         if (is_myname(domain_name)) {
 363                 DEBUG(3, ("Authentication for domain %s (local domain "
 364                           "to this server) not supported at this "
 365                           "stage\n", domain_name));
 366                 return NULL;
 367         }
 368 
 369         /* we can auth against trusted domains */
 370         if (state->request.flags & WBFLAG_PAM_CONTACT_TRUSTDOM) {
 371                 domain = find_domain_from_name_noinit(domain_name);
 372                 if (domain == NULL) {
 373                         DEBUG(3, ("Authentication for domain [%s] skipped "
 374                                   "as it is not a trusted domain\n",
 375                                   domain_name));
 376                 } else {
 377                         return domain;
 378                 }
 379         }
 380 
 381         return find_our_domain();
 382 }
 383 
 384 static void fill_in_password_policy(struct winbindd_response *r,
     /* [<][>][^][v][top][bottom][index][help] */
 385                                     const struct samr_DomInfo1 *p)
 386 {
 387         r->data.auth.policy.min_length_password =
 388                 p->min_password_length;
 389         r->data.auth.policy.password_history =
 390                 p->password_history_length;
 391         r->data.auth.policy.password_properties =
 392                 p->password_properties;
 393         r->data.auth.policy.expire      =
 394                 nt_time_to_unix_abs((NTTIME *)&(p->max_password_age));
 395         r->data.auth.policy.min_passwordage =
 396                 nt_time_to_unix_abs((NTTIME *)&(p->min_password_age));
 397 }
 398 
 399 static NTSTATUS fillup_password_policy(struct winbindd_domain *domain,
     /* [<][>][^][v][top][bottom][index][help] */
 400                                        struct winbindd_cli_state *state)
 401 {
 402         struct winbindd_methods *methods;
 403         NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
 404         struct samr_DomInfo1 password_policy;
 405 
 406         if ( !winbindd_can_contact_domain( domain ) ) {
 407                 DEBUG(5,("fillup_password_policy: No inbound trust to "
 408                          "contact domain %s\n", domain->name));
 409                 return NT_STATUS_NOT_SUPPORTED;
 410         }
 411 
 412         methods = domain->methods;
 413 
 414         status = methods->password_policy(domain, state->mem_ctx, &password_policy);
 415         if (NT_STATUS_IS_ERR(status)) {
 416                 return status;
 417         }
 418 
 419         fill_in_password_policy(&state->response, &password_policy);
 420 
 421         return NT_STATUS_OK;
 422 }
 423 
 424 static NTSTATUS get_max_bad_attempts_from_lockout_policy(struct winbindd_domain *domain,
     /* [<][>][^][v][top][bottom][index][help] */
 425                                                          TALLOC_CTX *mem_ctx,
 426                                                          uint16 *lockout_threshold)
 427 {
 428         struct winbindd_methods *methods;
 429         NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
 430         struct samr_DomInfo12 lockout_policy;
 431 
 432         *lockout_threshold = 0;
 433 
 434         methods = domain->methods;
 435 
 436         status = methods->lockout_policy(domain, mem_ctx, &lockout_policy);
 437         if (NT_STATUS_IS_ERR(status)) {
 438                 return status;
 439         }
 440 
 441         *lockout_threshold = lockout_policy.lockout_threshold;
 442 
 443         return NT_STATUS_OK;
 444 }
 445 
 446 static NTSTATUS get_pwd_properties(struct winbindd_domain *domain,
     /* [<][>][^][v][top][bottom][index][help] */
 447                                    TALLOC_CTX *mem_ctx,
 448                                    uint32 *password_properties)
 449 {
 450         struct winbindd_methods *methods;
 451         NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
 452         struct samr_DomInfo1 password_policy;
 453 
 454         *password_properties = 0;
 455 
 456         methods = domain->methods;
 457 
 458         status = methods->password_policy(domain, mem_ctx, &password_policy);
 459         if (NT_STATUS_IS_ERR(status)) {
 460                 return status;
 461         }
 462 
 463         *password_properties = password_policy.password_properties;
 464 
 465         return NT_STATUS_OK;
 466 }
 467 
 468 #ifdef HAVE_KRB5
 469 
 470 static const char *generate_krb5_ccache(TALLOC_CTX *mem_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
 471                                         const char *type,
 472                                         uid_t uid,
 473                                         bool *internal_ccache)
 474 {
 475         /* accept FILE and WRFILE as krb5_cc_type from the client and then
 476          * build the full ccname string based on the user's uid here -
 477          * Guenther*/
 478 
 479         const char *gen_cc = NULL;
 480 
 481         *internal_ccache = true;
 482 
 483         if (uid == -1) {
 484                 goto memory_ccache;
 485         }
 486 
 487         if (!type || type[0] == '\0') {
 488                 goto memory_ccache;
 489         }
 490 
 491         if (strequal(type, "FILE")) {
 492                 gen_cc = talloc_asprintf(mem_ctx, "FILE:/tmp/krb5cc_%d", uid);
 493         } else if (strequal(type, "WRFILE")) {
 494                 gen_cc = talloc_asprintf(mem_ctx, "WRFILE:/tmp/krb5cc_%d", uid);
 495         } else {
 496                 DEBUG(10,("we don't allow to set a %s type ccache\n", type));
 497                 goto memory_ccache;
 498         }
 499 
 500         *internal_ccache = false;
 501         goto done;
 502 
 503   memory_ccache:
 504         gen_cc = talloc_strdup(mem_ctx, "MEMORY:winbindd_pam_ccache");
 505 
 506   done:
 507         if (gen_cc == NULL) {
 508                 DEBUG(0,("out of memory\n"));
 509                 return NULL;
 510         }
 511 
 512         DEBUG(10,("using ccache: %s %s\n", gen_cc, *internal_ccache ? "(internal)":""));
 513 
 514         return gen_cc;
 515 }
 516 
 517 static void setup_return_cc_name(struct winbindd_cli_state *state, const char *cc)
     /* [<][>][^][v][top][bottom][index][help] */
 518 {
 519         const char *type = state->request.data.auth.krb5_cc_type;
 520 
 521         state->response.data.auth.krb5ccname[0] = '\0';
 522 
 523         if (type[0] == '\0') {
 524                 return;
 525         }
 526 
 527         if (!strequal(type, "FILE") &&
 528             !strequal(type, "WRFILE")) {
 529                 DEBUG(10,("won't return krbccname for a %s type ccache\n",
 530                         type));
 531                 return;
 532         }
 533 
 534         fstrcpy(state->response.data.auth.krb5ccname, cc);
 535 }
 536 
 537 #endif
 538 
 539 static uid_t get_uid_from_state(struct winbindd_cli_state *state)
     /* [<][>][^][v][top][bottom][index][help] */
 540 {
 541         uid_t uid = -1;
 542 
 543         uid = state->request.data.auth.uid;
 544 
 545         if (uid < 0) {
 546                 DEBUG(1,("invalid uid: '%u'\n", (unsigned int)uid));
 547                 return -1;
 548         }
 549         return uid;
 550 }
 551 
 552 /**********************************************************************
 553  Authenticate a user with a clear text password using Kerberos and fill up
 554  ccache if required
 555  **********************************************************************/
 556 
 557 static NTSTATUS winbindd_raw_kerberos_login(struct winbindd_domain *domain,
     /* [<][>][^][v][top][bottom][index][help] */
 558                                             struct winbindd_cli_state *state,
 559                                             struct netr_SamInfo3 **info3)
 560 {
 561 #ifdef HAVE_KRB5
 562         NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
 563         krb5_error_code krb5_ret;
 564         const char *cc = NULL;
 565         const char *principal_s = NULL;
 566         const char *service = NULL;
 567         char *realm = NULL;
 568         fstring name_domain, name_user;
 569         time_t ticket_lifetime = 0;
 570         time_t renewal_until = 0;
 571         uid_t uid = -1;
 572         ADS_STRUCT *ads;
 573         time_t time_offset = 0;
 574         bool internal_ccache = true;
 575 
 576         ZERO_STRUCTP(info3);
 577 
 578         *info3 = NULL;
 579 
 580         /* 1st step:
 581          * prepare a krb5_cc_cache string for the user */
 582 
 583         uid = get_uid_from_state(state);
 584         if (uid == -1) {
 585                 DEBUG(0,("no valid uid\n"));
 586         }
 587 
 588         cc = generate_krb5_ccache(state->mem_ctx,
 589                                   state->request.data.auth.krb5_cc_type,
 590                                   state->request.data.auth.uid,
 591                                   &internal_ccache);
 592         if (cc == NULL) {
 593                 return NT_STATUS_NO_MEMORY;
 594         }
 595 
 596 
 597         /* 2nd step:
 598          * get kerberos properties */
 599 
 600         if (domain->private_data) {
 601                 ads = (ADS_STRUCT *)domain->private_data;
 602                 time_offset = ads->auth.time_offset;
 603         }
 604 
 605 
 606         /* 3rd step:
 607          * do kerberos auth and setup ccache as the user */
 608 
 609         parse_domain_user(state->request.data.auth.user, name_domain, name_user);
 610 
 611         realm = domain->alt_name;
 612         strupper_m(realm);
 613 
 614         principal_s = talloc_asprintf(state->mem_ctx, "%s@%s", name_user, realm);
 615         if (principal_s == NULL) {
 616                 return NT_STATUS_NO_MEMORY;
 617         }
 618 
 619         service = talloc_asprintf(state->mem_ctx, "%s/%s@%s", KRB5_TGS_NAME, realm, realm);
 620         if (service == NULL) {
 621                 return NT_STATUS_NO_MEMORY;
 622         }
 623 
 624         /* if this is a user ccache, we need to act as the user to let the krb5
 625          * library handle the chown, etc. */
 626 
 627         /************************ ENTERING NON-ROOT **********************/
 628 
 629         if (!internal_ccache) {
 630                 set_effective_uid(uid);
 631                 DEBUG(10,("winbindd_raw_kerberos_login: uid is %d\n", uid));
 632         }
 633 
 634         result = kerberos_return_info3_from_pac(state->mem_ctx,
 635                                                 principal_s,
 636                                                 state->request.data.auth.pass,
 637                                                 time_offset,
 638                                                 &ticket_lifetime,
 639                                                 &renewal_until,
 640                                                 cc,
 641                                                 true,
 642                                                 true,
 643                                                 WINBINDD_PAM_AUTH_KRB5_RENEW_TIME,
 644                                                 info3);
 645         if (!internal_ccache) {
 646                 gain_root_privilege();
 647         }
 648 
 649         /************************ RETURNED TO ROOT **********************/
 650 
 651         if (!NT_STATUS_IS_OK(result)) {
 652                 goto failed;
 653         }
 654 
 655         DEBUG(10,("winbindd_raw_kerberos_login: winbindd validated ticket of %s\n",
 656                 principal_s));
 657 
 658         /* if we had a user's ccache then return that string for the pam
 659          * environment */
 660 
 661         if (!internal_ccache) {
 662 
 663                 setup_return_cc_name(state, cc);
 664 
 665                 result = add_ccache_to_list(principal_s,
 666                                             cc,
 667                                             service,
 668                                             state->request.data.auth.user,
 669                                             realm,
 670                                             uid,
 671                                             time(NULL),
 672                                             ticket_lifetime,
 673                                             renewal_until,
 674                                             false);
 675 
 676                 if (!NT_STATUS_IS_OK(result)) {
 677                         DEBUG(10,("winbindd_raw_kerberos_login: failed to add ccache to list: %s\n",
 678                                 nt_errstr(result)));
 679                 }
 680         } else {
 681 
 682                 /* need to delete the memory cred cache, it is not used anymore */
 683 
 684                 krb5_ret = ads_kdestroy(cc);
 685                 if (krb5_ret) {
 686                         DEBUG(3,("winbindd_raw_kerberos_login: "
 687                                  "could not destroy krb5 credential cache: "
 688                                  "%s\n", error_message(krb5_ret)));
 689                 }
 690 
 691         }
 692 
 693         return NT_STATUS_OK;
 694 
 695 failed:
 696 
 697         /* we could have created a new credential cache with a valid tgt in it
 698          * but we werent able to get or verify the service ticket for this
 699          * local host and therefor didn't get the PAC, we need to remove that
 700          * cache entirely now */
 701 
 702         krb5_ret = ads_kdestroy(cc);
 703         if (krb5_ret) {
 704                 DEBUG(3,("winbindd_raw_kerberos_login: "
 705                          "could not destroy krb5 credential cache: "
 706                          "%s\n", error_message(krb5_ret)));
 707         }
 708 
 709         if (!NT_STATUS_IS_OK(remove_ccache(state->request.data.auth.user))) {
 710                 DEBUG(3,("winbindd_raw_kerberos_login: "
 711                           "could not remove ccache for user %s\n",
 712                         state->request.data.auth.user));
 713         }
 714 
 715         return result;
 716 #else
 717         return NT_STATUS_NOT_SUPPORTED;
 718 #endif /* HAVE_KRB5 */
 719 }
 720 
 721 /****************************************************************
 722 ****************************************************************/
 723 
 724 static bool check_request_flags(uint32_t flags)
     /* [<][>][^][v][top][bottom][index][help] */
 725 {
 726         uint32_t flags_edata = WBFLAG_PAM_AFS_TOKEN |
 727                                WBFLAG_PAM_INFO3_TEXT |
 728                                WBFLAG_PAM_INFO3_NDR;
 729 
 730         if ( ( (flags & flags_edata) == WBFLAG_PAM_AFS_TOKEN) ||
 731              ( (flags & flags_edata) == WBFLAG_PAM_INFO3_NDR) ||
 732              ( (flags & flags_edata) == WBFLAG_PAM_INFO3_TEXT)||
 733               !(flags & flags_edata) ) {
 734                 return true;
 735         }
 736 
 737         DEBUG(1,("check_request_flags: invalid request flags[0x%08X]\n",flags));
 738 
 739         return false;
 740 }
 741 
 742 /****************************************************************
 743 ****************************************************************/
 744 
 745 static NTSTATUS append_data(struct winbindd_cli_state *state,
     /* [<][>][^][v][top][bottom][index][help] */
 746                             struct netr_SamInfo3 *info3,
 747                             const char *name_domain,
 748                             const char *name_user)
 749 {
 750         NTSTATUS result;
 751         uint32_t flags = state->request.flags;
 752 
 753         if (flags & WBFLAG_PAM_USER_SESSION_KEY) {
 754                 memcpy(state->response.data.auth.user_session_key,
 755                        info3->base.key.key,
 756                        sizeof(state->response.data.auth.user_session_key)
 757                        /* 16 */);
 758         }
 759 
 760         if (flags & WBFLAG_PAM_LMKEY) {
 761                 memcpy(state->response.data.auth.first_8_lm_hash,
 762                        info3->base.LMSessKey.key,
 763                        sizeof(state->response.data.auth.first_8_lm_hash)
 764                        /* 8 */);
 765         }
 766 
 767         if (flags & WBFLAG_PAM_INFO3_TEXT) {
 768                 result = append_info3_as_txt(state->mem_ctx, state, info3);
 769                 if (!NT_STATUS_IS_OK(result)) {
 770                         DEBUG(10,("Failed to append INFO3 (TXT): %s\n",
 771                                 nt_errstr(result)));
 772                         return result;
 773                 }
 774         }
 775 
 776         /* currently, anything from here on potentially overwrites extra_data. */
 777 
 778         if (flags & WBFLAG_PAM_INFO3_NDR) {
 779                 result = append_info3_as_ndr(state->mem_ctx, state, info3);
 780                 if (!NT_STATUS_IS_OK(result)) {
 781                         DEBUG(10,("Failed to append INFO3 (NDR): %s\n",
 782                                 nt_errstr(result)));
 783                         return result;
 784                 }
 785         }
 786 
 787         if (flags & WBFLAG_PAM_UNIX_NAME) {
 788                 result = append_unix_username(state->mem_ctx, state, info3,
 789                                               name_domain, name_user);
 790                 if (!NT_STATUS_IS_OK(result)) {
 791                         DEBUG(10,("Failed to append Unix Username: %s\n",
 792                                 nt_errstr(result)));
 793                         return result;
 794                 }
 795         }
 796 
 797         if (flags & WBFLAG_PAM_AFS_TOKEN) {
 798                 result = append_afs_token(state->mem_ctx, state, info3,
 799                                           name_domain, name_user);
 800                 if (!NT_STATUS_IS_OK(result)) {
 801                         DEBUG(10,("Failed to append AFS token: %s\n",
 802                                 nt_errstr(result)));
 803                         return result;
 804                 }
 805         }
 806 
 807         return NT_STATUS_OK;
 808 }
 809 
 810 void winbindd_pam_auth(struct winbindd_cli_state *state)
     /* [<][>][^][v][top][bottom][index][help] */
 811 {
 812         struct winbindd_domain *domain;
 813         fstring name_domain, name_user, mapped_user;
 814         char *mapped = NULL;
 815         NTSTATUS result;
 816         NTSTATUS name_map_status = NT_STATUS_UNSUCCESSFUL;
 817 
 818         /* Ensure null termination */
 819         state->request.data.auth.user
 820                 [sizeof(state->request.data.auth.user)-1]='\0';
 821 
 822         /* Ensure null termination */
 823         state->request.data.auth.pass
 824                 [sizeof(state->request.data.auth.pass)-1]='\0';
 825 
 826         DEBUG(3, ("[%5lu]: pam auth %s\n", (unsigned long)state->pid,
 827                   state->request.data.auth.user));
 828 
 829         if (!check_request_flags(state->request.flags)) {
 830                 result = NT_STATUS_INVALID_PARAMETER_MIX;
 831                 goto done;
 832         }
 833 
 834         /* Parse domain and username */
 835 
 836         name_map_status = normalize_name_unmap(state->mem_ctx,
 837                                                state->request.data.auth.user,
 838                                                &mapped);
 839 
 840         /* If the name normalization didnt' actually do anything,
 841            just use the original name */
 842 
 843         if (NT_STATUS_IS_OK(name_map_status)
 844             ||NT_STATUS_EQUAL(name_map_status, NT_STATUS_FILE_RENAMED)) {
 845                 fstrcpy(mapped_user, mapped);
 846         } else {
 847                 fstrcpy(mapped_user, state->request.data.auth.user);
 848         }
 849 
 850         if (!canonicalize_username(mapped_user, name_domain, name_user)) {
 851                 result = NT_STATUS_NO_SUCH_USER;
 852                 goto done;
 853         }
 854 
 855         domain = find_auth_domain(state, name_domain);
 856 
 857         if (domain == NULL) {
 858                 result = NT_STATUS_NO_SUCH_USER;
 859                 goto done;
 860         }
 861 
 862         sendto_domain(state, domain);
 863         return;
 864  done:
 865         set_auth_errors(&state->response, result);
 866         DEBUG(5, ("Plain text authentication for %s returned %s "
 867                   "(PAM: %d)\n",
 868                   state->request.data.auth.user,
 869                   state->response.data.auth.nt_status_string,
 870                   state->response.data.auth.pam_error));
 871         request_error(state);
 872 }
 873 
 874 NTSTATUS winbindd_dual_pam_auth_cached(struct winbindd_domain *domain,
     /* [<][>][^][v][top][bottom][index][help] */
 875                                        struct winbindd_cli_state *state,
 876                                        struct netr_SamInfo3 **info3)
 877 {
 878         NTSTATUS result = NT_STATUS_LOGON_FAILURE;
 879         uint16 max_allowed_bad_attempts;
 880         fstring name_domain, name_user;
 881         DOM_SID sid;
 882         enum lsa_SidType type;
 883         uchar new_nt_pass[NT_HASH_LEN];
 884         const uint8 *cached_nt_pass;
 885         const uint8 *cached_salt;
 886         struct netr_SamInfo3 *my_info3;
 887         time_t kickoff_time, must_change_time;
 888         bool password_good = false;
 889 #ifdef HAVE_KRB5
 890         struct winbindd_tdc_domain *tdc_domain = NULL;
 891 #endif
 892 
 893         *info3 = NULL;
 894 
 895         ZERO_STRUCTP(info3);
 896 
 897         DEBUG(10,("winbindd_dual_pam_auth_cached\n"));
 898 
 899         /* Parse domain and username */
 900 
 901         parse_domain_user(state->request.data.auth.user, name_domain, name_user);
 902 
 903 
 904         if (!lookup_cached_name(state->mem_ctx,
 905                                 name_domain,
 906                                 name_user,
 907                                 &sid,
 908                                 &type)) {
 909                 DEBUG(10,("winbindd_dual_pam_auth_cached: no such user in the cache\n"));
 910                 return NT_STATUS_NO_SUCH_USER;
 911         }
 912 
 913         if (type != SID_NAME_USER) {
 914                 DEBUG(10,("winbindd_dual_pam_auth_cached: not a user (%s)\n", sid_type_lookup(type)));
 915                 return NT_STATUS_LOGON_FAILURE;
 916         }
 917 
 918         result = winbindd_get_creds(domain,
 919                                     state->mem_ctx,
 920                                     &sid,
 921                                     &my_info3,
 922                                     &cached_nt_pass,
 923                                     &cached_salt);
 924         if (!NT_STATUS_IS_OK(result)) {
 925                 DEBUG(10,("winbindd_dual_pam_auth_cached: failed to get creds: %s\n", nt_errstr(result)));
 926                 return result;
 927         }
 928 
 929         *info3 = my_info3;
 930 
 931         E_md4hash(state->request.data.auth.pass, new_nt_pass);
 932 
 933         dump_data_pw("new_nt_pass", new_nt_pass, NT_HASH_LEN);
 934         dump_data_pw("cached_nt_pass", cached_nt_pass, NT_HASH_LEN);
 935         if (cached_salt) {
 936                 dump_data_pw("cached_salt", cached_salt, NT_HASH_LEN);
 937         }
 938 
 939         if (cached_salt) {
 940                 /* In this case we didn't store the nt_hash itself,
 941                    but the MD5 combination of salt + nt_hash. */
 942                 uchar salted_hash[NT_HASH_LEN];
 943                 E_md5hash(cached_salt, new_nt_pass, salted_hash);
 944 
 945                 password_good = (memcmp(cached_nt_pass, salted_hash, NT_HASH_LEN) == 0) ?
 946                         true : false;
 947         } else {
 948                 /* Old cached cred - direct store of nt_hash (bad bad bad !). */
 949                 password_good = (memcmp(cached_nt_pass, new_nt_pass, NT_HASH_LEN) == 0) ?
 950                         true : false;
 951         }
 952 
 953         if (password_good) {
 954 
 955                 /* User *DOES* know the password, update logon_time and reset
 956                  * bad_pw_count */
 957 
 958                 my_info3->base.user_flags |= NETLOGON_CACHED_ACCOUNT;
 959 
 960                 if (my_info3->base.acct_flags & ACB_AUTOLOCK) {
 961                         return NT_STATUS_ACCOUNT_LOCKED_OUT;
 962                 }
 963 
 964                 if (my_info3->base.acct_flags & ACB_DISABLED) {
 965                         return NT_STATUS_ACCOUNT_DISABLED;
 966                 }
 967 
 968                 if (my_info3->base.acct_flags & ACB_WSTRUST) {
 969                         return NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT;
 970                 }
 971 
 972                 if (my_info3->base.acct_flags & ACB_SVRTRUST) {
 973                         return NT_STATUS_NOLOGON_SERVER_TRUST_ACCOUNT;
 974                 }
 975 
 976                 if (my_info3->base.acct_flags & ACB_DOMTRUST) {
 977                         return NT_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT;
 978                 }
 979 
 980                 if (!(my_info3->base.acct_flags & ACB_NORMAL)) {
 981                         DEBUG(0,("winbindd_dual_pam_auth_cached: whats wrong with that one?: 0x%08x\n",
 982                                 my_info3->base.acct_flags));
 983                         return NT_STATUS_LOGON_FAILURE;
 984                 }
 985 
 986                 kickoff_time = nt_time_to_unix(my_info3->base.acct_expiry);
 987                 if (kickoff_time != 0 && time(NULL) > kickoff_time) {
 988                         return NT_STATUS_ACCOUNT_EXPIRED;
 989                 }
 990 
 991                 must_change_time = nt_time_to_unix(my_info3->base.force_password_change);
 992                 if (must_change_time != 0 && must_change_time < time(NULL)) {
 993                         /* we allow grace logons when the password has expired */
 994                         my_info3->base.user_flags |= NETLOGON_GRACE_LOGON;
 995                         /* return NT_STATUS_PASSWORD_EXPIRED; */
 996                         goto success;
 997                 }
 998 
 999 #ifdef HAVE_KRB5
1000                 if ((state->request.flags & WBFLAG_PAM_KRB5) &&
1001                     ((tdc_domain = wcache_tdc_fetch_domain(state->mem_ctx, name_domain)) != NULL) &&
1002                     ((tdc_domain->trust_type & NETR_TRUST_TYPE_UPLEVEL) ||
1003                     /* used to cope with the case winbindd starting without network. */
1004                     !strequal(tdc_domain->domain_name, tdc_domain->dns_name))) {
1005 
1006                         uid_t uid = -1;
1007                         const char *cc = NULL;
1008                         char *realm = NULL;
1009                         const char *principal_s = NULL;
1010                         const char *service = NULL;
1011                         bool internal_ccache = false;
1012 
1013                         uid = get_uid_from_state(state);
1014                         if (uid == -1) {
1015                                 DEBUG(0,("winbindd_dual_pam_auth_cached: invalid uid\n"));
1016                                 return NT_STATUS_INVALID_PARAMETER;
1017                         }
1018 
1019                         cc = generate_krb5_ccache(state->mem_ctx,
1020                                                 state->request.data.auth.krb5_cc_type,
1021                                                 state->request.data.auth.uid,
1022                                                 &internal_ccache);
1023                         if (cc == NULL) {
1024                                 return NT_STATUS_NO_MEMORY;
1025                         }
1026 
1027                         realm = domain->alt_name;
1028                         strupper_m(realm);
1029 
1030                         principal_s = talloc_asprintf(state->mem_ctx, "%s@%s", name_user, realm);
1031                         if (principal_s == NULL) {
1032                                 return NT_STATUS_NO_MEMORY;
1033                         }
1034 
1035                         service = talloc_asprintf(state->mem_ctx, "%s/%s@%s", KRB5_TGS_NAME, realm, realm);
1036                         if (service == NULL) {
1037                                 return NT_STATUS_NO_MEMORY;
1038                         }
1039 
1040                         if (!internal_ccache) {
1041 
1042                                 setup_return_cc_name(state, cc);
1043 
1044                                 result = add_ccache_to_list(principal_s,
1045                                                             cc,
1046                                                             service,
1047                                                             state->request.data.auth.user,
1048                                                             domain->alt_name,
1049                                                             uid,
1050                                                             time(NULL),
1051                                                             time(NULL) + lp_winbind_cache_time(),
1052                                                             time(NULL) + WINBINDD_PAM_AUTH_KRB5_RENEW_TIME,
1053                                                             true);
1054 
1055                                 if (!NT_STATUS_IS_OK(result)) {
1056                                         DEBUG(10,("winbindd_dual_pam_auth_cached: failed "
1057                                                 "to add ccache to list: %s\n",
1058                                                 nt_errstr(result)));
1059                                 }
1060                         }
1061                 }
1062 #endif /* HAVE_KRB5 */
1063  success:
1064                 /* FIXME: we possibly should handle logon hours as well (does xp when
1065                  * offline?) see auth/auth_sam.c:sam_account_ok for details */
1066 
1067                 unix_to_nt_time(&my_info3->base.last_logon, time(NULL));
1068                 my_info3->base.bad_password_count = 0;
1069 
1070                 result = winbindd_update_creds_by_info3(domain,
1071                                                         state->mem_ctx,
1072                                                         state->request.data.auth.user,
1073                                                         state->request.data.auth.pass,
1074                                                         my_info3);
1075                 if (!NT_STATUS_IS_OK(result)) {
1076                         DEBUG(1,("winbindd_dual_pam_auth_cached: failed to update creds: %s\n",
1077                                 nt_errstr(result)));
1078                         return result;
1079                 }
1080 
1081                 return NT_STATUS_OK;
1082 
1083         }
1084 
1085         /* User does *NOT* know the correct password, modify info3 accordingly */
1086 
1087         /* failure of this is not critical */
1088         result = get_max_bad_attempts_from_lockout_policy(domain, state->mem_ctx, &max_allowed_bad_attempts);
1089         if (!NT_STATUS_IS_OK(result)) {
1090                 DEBUG(10,("winbindd_dual_pam_auth_cached: failed to get max_allowed_bad_attempts. "
1091                           "Won't be able to honour account lockout policies\n"));
1092         }
1093 
1094         /* increase counter */
1095         my_info3->base.bad_password_count++;
1096 
1097         if (max_allowed_bad_attempts == 0) {
1098                 goto failed;
1099         }
1100 
1101         /* lockout user */
1102         if (my_info3->base.bad_password_count >= max_allowed_bad_attempts) {
1103 
1104                 uint32 password_properties;
1105 
1106                 result = get_pwd_properties(domain, state->mem_ctx, &password_properties);
1107                 if (!NT_STATUS_IS_OK(result)) {
1108                         DEBUG(10,("winbindd_dual_pam_auth_cached: failed to get password properties.\n"));
1109                 }
1110 
1111                 if ((my_info3->base.rid != DOMAIN_USER_RID_ADMIN) ||
1112                     (password_properties & DOMAIN_PASSWORD_LOCKOUT_ADMINS)) {
1113                         my_info3->base.acct_flags |= ACB_AUTOLOCK;
1114                 }
1115         }
1116 
1117 failed:
1118         result = winbindd_update_creds_by_info3(domain,
1119                                                 state->mem_ctx,
1120                                                 state->request.data.auth.user,
1121                                                 NULL,
1122                                                 my_info3);
1123 
1124         if (!NT_STATUS_IS_OK(result)) {
1125                 DEBUG(0,("winbindd_dual_pam_auth_cached: failed to update creds %s\n",
1126                         nt_errstr(result)));
1127         }
1128 
1129         return NT_STATUS_LOGON_FAILURE;
1130 }
1131 
1132 NTSTATUS winbindd_dual_pam_auth_kerberos(struct winbindd_domain *domain,
     /* [<][>][^][v][top][bottom][index][help] */
1133                                          struct winbindd_cli_state *state,
1134                                          struct netr_SamInfo3 **info3)
1135 {
1136         struct winbindd_domain *contact_domain;
1137         fstring name_domain, name_user;
1138         NTSTATUS result;
1139 
1140         DEBUG(10,("winbindd_dual_pam_auth_kerberos\n"));
1141 
1142         /* Parse domain and username */
1143 
1144         parse_domain_user(state->request.data.auth.user, name_domain, name_user);
1145 
1146         /* what domain should we contact? */
1147 
1148         if ( IS_DC ) {
1149                 if (!(contact_domain = find_domain_from_name(name_domain))) {
1150                         DEBUG(3, ("Authentication for domain for [%s] -> [%s]\\[%s] failed as %s is not a trusted domain\n",
1151                                   state->request.data.auth.user, name_domain, name_user, name_domain));
1152                         result = NT_STATUS_NO_SUCH_USER;
1153                         goto done;
1154                 }
1155 
1156         } else {
1157                 if (is_myname(name_domain)) {
1158                         DEBUG(3, ("Authentication for domain %s (local domain to this server) not supported at this stage\n", name_domain));
1159                         result =  NT_STATUS_NO_SUCH_USER;
1160                         goto done;
1161                 }
1162 
1163                 contact_domain = find_domain_from_name(name_domain);
1164                 if (contact_domain == NULL) {
1165                         DEBUG(3, ("Authentication for domain for [%s] -> [%s]\\[%s] failed as %s is not a trusted domain\n",
1166                                   state->request.data.auth.user, name_domain, name_user, name_domain));
1167 
1168                         contact_domain = find_our_domain();
1169                 }
1170         }
1171 
1172         if (contact_domain->initialized &&
1173             contact_domain->active_directory) {
1174                 goto try_login;
1175         }
1176 
1177         if (!contact_domain->initialized) {
1178                 init_dc_connection(contact_domain);
1179         }
1180 
1181         if (!contact_domain->active_directory) {
1182                 DEBUG(3,("krb5 auth requested but domain is not Active Directory\n"));
1183                 return NT_STATUS_INVALID_LOGON_TYPE;
1184         }
1185 try_login:
1186         result = winbindd_raw_kerberos_login(contact_domain, state, info3);
1187 done:
1188         return result;
1189 }
1190 
1191 typedef NTSTATUS (*netlogon_fn_t)(struct rpc_pipe_client *cli,
1192                                   TALLOC_CTX *mem_ctx,
1193                                   uint32 logon_parameters,
1194                                   const char *server,
1195                                   const char *username,
1196                                   const char *domain,
1197                                   const char *workstation,
1198                                   const uint8 chal[8],
1199                                   DATA_BLOB lm_response,
1200                                   DATA_BLOB nt_response,
1201                                   struct netr_SamInfo3 **info3);
1202 
1203 NTSTATUS winbindd_dual_pam_auth_samlogon(struct winbindd_domain *domain,
     /* [<][>][^][v][top][bottom][index][help] */
1204                                          struct winbindd_cli_state *state,
1205                                          struct netr_SamInfo3 **info3)
1206 {
1207 
1208         struct rpc_pipe_client *netlogon_pipe;
1209         uchar chal[8];
1210         DATA_BLOB lm_resp;
1211         DATA_BLOB nt_resp;
1212         int attempts = 0;
1213         unsigned char local_lm_response[24];
1214         unsigned char local_nt_response[24];
1215         struct winbindd_domain *contact_domain;
1216         fstring name_domain, name_user;
1217         bool retry;
1218         NTSTATUS result;
1219         struct netr_SamInfo3 *my_info3 = NULL;
1220 
1221         *info3 = NULL;
1222 
1223         DEBUG(10,("winbindd_dual_pam_auth_samlogon\n"));
1224 
1225         /* Parse domain and username */
1226 
1227         parse_domain_user(state->request.data.auth.user, name_domain, name_user);
1228 
1229         /* do password magic */
1230 
1231 
1232         generate_random_buffer(chal, 8);
1233         if (lp_client_ntlmv2_auth()) {
1234                 DATA_BLOB server_chal;
1235                 DATA_BLOB names_blob;
1236                 DATA_BLOB nt_response;
1237                 DATA_BLOB lm_response;
1238                 server_chal = data_blob_talloc(state->mem_ctx, chal, 8);
1239 
1240                 /* note that the 'workgroup' here is a best guess - we don't know
1241                    the server's domain at this point.  The 'server name' is also
1242                    dodgy...
1243                 */
1244                 names_blob = NTLMv2_generate_names_blob(global_myname(), lp_workgroup());
1245 
1246                 if (!SMBNTLMv2encrypt(name_user, name_domain,
1247                                       state->request.data.auth.pass,
1248                                       &server_chal,
1249                                       &names_blob,
1250                                       &lm_response, &nt_response, NULL)) {
1251                         data_blob_free(&names_blob);
1252                         data_blob_free(&server_chal);
1253                         DEBUG(0, ("winbindd_pam_auth: SMBNTLMv2encrypt() failed!\n"));
1254                         result = NT_STATUS_NO_MEMORY;
1255                         goto done;
1256                 }
1257                 data_blob_free(&names_blob);
1258                 data_blob_free(&server_chal);
1259                 lm_resp = data_blob_talloc(state->mem_ctx, lm_response.data,
1260                                            lm_response.length);
1261                 nt_resp = data_blob_talloc(state->mem_ctx, nt_response.data,
1262                                            nt_response.length);
1263                 data_blob_free(&lm_response);
1264                 data_blob_free(&nt_response);
1265 
1266         } else {
1267                 if (lp_client_lanman_auth()
1268                     && SMBencrypt(state->request.data.auth.pass,
1269                                   chal,
1270                                   local_lm_response)) {
1271                         lm_resp = data_blob_talloc(state->mem_ctx,
1272                                                    local_lm_response,
1273                                                    sizeof(local_lm_response));
1274                 } else {
1275                         lm_resp = data_blob_null;
1276                 }
1277                 SMBNTencrypt(state->request.data.auth.pass,
1278                              chal,
1279                              local_nt_response);
1280 
1281                 nt_resp = data_blob_talloc(state->mem_ctx,
1282                                            local_nt_response,
1283                                            sizeof(local_nt_response));
1284         }
1285 
1286         /* what domain should we contact? */
1287 
1288         if ( IS_DC ) {
1289                 if (!(contact_domain = find_domain_from_name(name_domain))) {
1290                         DEBUG(3, ("Authentication for domain for [%s] -> [%s]\\[%s] failed as %s is not a trusted domain\n",
1291                                   state->request.data.auth.user, name_domain, name_user, name_domain));
1292                         result = NT_STATUS_NO_SUCH_USER;
1293                         goto done;
1294                 }
1295 
1296         } else {
1297                 if (is_myname(name_domain)) {
1298                         DEBUG(3, ("Authentication for domain %s (local domain to this server) not supported at this stage\n", name_domain));
1299                         result =  NT_STATUS_NO_SUCH_USER;
1300                         goto done;
1301                 }
1302 
1303                 contact_domain = find_our_domain();
1304         }
1305 
1306         /* check authentication loop */
1307 
1308         do {
1309                 netlogon_fn_t logon_fn;
1310 
1311                 ZERO_STRUCTP(my_info3);
1312                 retry = false;
1313 
1314                 result = cm_connect_netlogon(contact_domain, &netlogon_pipe);
1315 
1316                 if (!NT_STATUS_IS_OK(result)) {
1317                         DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
1318                         goto done;
1319                 }
1320 
1321                 /* It is really important to try SamLogonEx here,
1322                  * because in a clustered environment, we want to use
1323                  * one machine account from multiple physical
1324                  * computers.
1325                  *
1326                  * With a normal SamLogon call, we must keep the
1327                  * credentials chain updated and intact between all
1328                  * users of the machine account (which would imply
1329                  * cross-node communication for every NTLM logon).
1330                  *
1331                  * (The credentials chain is not per NETLOGON pipe
1332                  * connection, but globally on the server/client pair
1333                  * by machine name).
1334                  *
1335                  * When using SamLogonEx, the credentials are not
1336                  * supplied, but the session key is implied by the
1337                  * wrapping SamLogon context.
1338                  *
1339                  *  -- abartlet 21 April 2008
1340                  */
1341 
1342                 logon_fn = contact_domain->can_do_samlogon_ex
1343                         ? rpccli_netlogon_sam_network_logon_ex
1344                         : rpccli_netlogon_sam_network_logon;
1345 
1346                 result = logon_fn(netlogon_pipe,
1347                                   state->mem_ctx,
1348                                   0,
1349                                   contact_domain->dcname, /* server name */
1350                                   name_user,              /* user name */
1351                                   name_domain,            /* target domain */
1352                                   global_myname(),        /* workstation */
1353                                   chal,
1354                                   lm_resp,
1355                                   nt_resp,
1356                                   &my_info3);
1357                 attempts += 1;
1358 
1359                 if ((NT_STATUS_V(result) == DCERPC_FAULT_OP_RNG_ERROR)
1360                     && contact_domain->can_do_samlogon_ex) {
1361                         DEBUG(3, ("Got a DC that can not do NetSamLogonEx, "
1362                                   "retrying with NetSamLogon\n"));
1363                         contact_domain->can_do_samlogon_ex = false;
1364                         retry = true;
1365                         continue;
1366                 }
1367 
1368                 /* We have to try a second time as cm_connect_netlogon
1369                    might not yet have noticed that the DC has killed
1370                    our connection. */
1371 
1372                 if (NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL)) {
1373                         retry = true;
1374                         continue;
1375                 }
1376 
1377                 /* if we get access denied, a possible cause was that we had
1378                    and open connection to the DC, but someone changed our
1379                    machine account password out from underneath us using 'net
1380                    rpc changetrustpw' */
1381 
1382                 if ( NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED) ) {
1383                         DEBUG(3,("winbindd_pam_auth: sam_logon returned "
1384                                  "ACCESS_DENIED.  Maybe the trust account "
1385                                 "password was changed and we didn't know it. "
1386                                  "Killing connections to domain %s\n",
1387                                 name_domain));
1388                         invalidate_cm_connection(&contact_domain->conn);
1389                         retry = true;
1390                 }
1391 
1392         } while ( (attempts < 2) && retry );
1393 
1394         /* handle the case where a NT4 DC does not fill in the acct_flags in
1395          * the samlogon reply info3. When accurate info3 is required by the
1396          * caller, we look up the account flags ourselve - gd */
1397 
1398         if ((state->request.flags & WBFLAG_PAM_INFO3_TEXT) &&
1399             NT_STATUS_IS_OK(result) && (my_info3->base.acct_flags == 0)) {
1400 
1401                 struct rpc_pipe_client *samr_pipe;
1402                 struct policy_handle samr_domain_handle, user_pol;
1403                 union samr_UserInfo *info = NULL;
1404                 NTSTATUS status_tmp;
1405                 uint32 acct_flags;
1406 
1407                 status_tmp = cm_connect_sam(contact_domain, state->mem_ctx,
1408                                             &samr_pipe, &samr_domain_handle);
1409 
1410                 if (!NT_STATUS_IS_OK(status_tmp)) {
1411                         DEBUG(3, ("could not open handle to SAMR pipe: %s\n",
1412                                 nt_errstr(status_tmp)));
1413                         goto done;
1414                 }
1415 
1416                 status_tmp = rpccli_samr_OpenUser(samr_pipe, state->mem_ctx,
1417                                                   &samr_domain_handle,
1418                                                   MAXIMUM_ALLOWED_ACCESS,
1419                                                   my_info3->base.rid,
1420                                                   &user_pol);
1421 
1422                 if (!NT_STATUS_IS_OK(status_tmp)) {
1423                         DEBUG(3, ("could not open user handle on SAMR pipe: %s\n",
1424                                 nt_errstr(status_tmp)));
1425                         goto done;
1426                 }
1427 
1428                 status_tmp = rpccli_samr_QueryUserInfo(samr_pipe, state->mem_ctx,
1429                                                        &user_pol,
1430                                                        16,
1431                                                        &info);
1432 
1433                 if (!NT_STATUS_IS_OK(status_tmp)) {
1434                         DEBUG(3, ("could not query user info on SAMR pipe: %s\n",
1435                                 nt_errstr(status_tmp)));
1436                         rpccli_samr_Close(samr_pipe, state->mem_ctx, &user_pol);
1437                         goto done;
1438                 }
1439 
1440                 acct_flags = info->info16.acct_flags;
1441 
1442                 if (acct_flags == 0) {
1443                         rpccli_samr_Close(samr_pipe, state->mem_ctx, &user_pol);
1444                         goto done;
1445                 }
1446 
1447                 my_info3->base.acct_flags = acct_flags;
1448 
1449                 DEBUG(10,("successfully retrieved acct_flags 0x%x\n", acct_flags));
1450 
1451                 rpccli_samr_Close(samr_pipe, state->mem_ctx, &user_pol);
1452         }
1453 
1454         *info3 = my_info3;
1455 done:
1456         return result;
1457 }
1458 
1459 enum winbindd_result winbindd_dual_pam_auth(struct winbindd_domain *domain,
     /* [<][>][^][v][top][bottom][index][help] */
1460                                             struct winbindd_cli_state *state)
1461 {
1462         NTSTATUS result = NT_STATUS_LOGON_FAILURE;
1463         NTSTATUS krb5_result = NT_STATUS_OK;
1464         fstring name_domain, name_user;
1465         char *mapped_user;
1466         fstring domain_user;
1467         struct netr_SamInfo3 *info3 = NULL;
1468         NTSTATUS name_map_status = NT_STATUS_UNSUCCESSFUL;
1469 
1470         /* Ensure null termination */
1471         state->request.data.auth.user[sizeof(state->request.data.auth.user)-1]='\0';
1472 
1473         /* Ensure null termination */
1474         state->request.data.auth.pass[sizeof(state->request.data.auth.pass)-1]='\0';
1475 
1476         DEBUG(3, ("[%5lu]: dual pam auth %s\n", (unsigned long)state->pid,
1477                   state->request.data.auth.user));
1478 
1479         if (!check_request_flags(state->request.flags)) {
1480                 result = NT_STATUS_INVALID_PARAMETER_MIX;
1481                 goto done;
1482         }
1483 
1484         /* Parse domain and username */
1485 
1486         name_map_status = normalize_name_unmap(state->mem_ctx,
1487                                                state->request.data.auth.user,
1488                                                &mapped_user);
1489 
1490         /* If the name normalization didnt' actually do anything,
1491            just use the original name */
1492 
1493         if (!NT_STATUS_IS_OK(name_map_status) &&
1494             !NT_STATUS_EQUAL(name_map_status, NT_STATUS_FILE_RENAMED))
1495         {
1496                 mapped_user = state->request.data.auth.user;
1497         }
1498 
1499         parse_domain_user(mapped_user, name_domain, name_user);
1500 
1501         if ( mapped_user != state->request.data.auth.user ) {
1502                 fstr_sprintf( domain_user, "%s\\%s", name_domain, name_user );
1503                 safe_strcpy( state->request.data.auth.user, domain_user,
1504                              sizeof(state->request.data.auth.user)-1 );
1505         }
1506 
1507         if (domain->online == false) {
1508                 result = NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND;
1509                 if (domain->startup) {
1510                         /* Logons are very important to users. If we're offline and
1511                            we get a request within the first 30 seconds of startup,
1512                            try very hard to find a DC and go online. */
1513 
1514                         DEBUG(10,("winbindd_dual_pam_auth: domain: %s offline and auth "
1515                                 "request in startup mode.\n", domain->name ));
1516 
1517                         winbindd_flush_negative_conn_cache(domain);
1518                         result = init_dc_connection(domain);
1519                 }
1520         }
1521 
1522         DEBUG(10,("winbindd_dual_pam_auth: domain: %s last was %s\n", domain->name, domain->online ? "online":"offline"));
1523 
1524         /* Check for Kerberos authentication */
1525         if (domain->online && (state->request.flags & WBFLAG_PAM_KRB5)) {
1526 
1527                 result = winbindd_dual_pam_auth_kerberos(domain, state, &info3);
1528                 /* save for later */
1529                 krb5_result = result;
1530 
1531 
1532                 if (NT_STATUS_IS_OK(result)) {
1533                         DEBUG(10,("winbindd_dual_pam_auth_kerberos succeeded\n"));
1534                         goto process_result;
1535                 } else {
1536                         DEBUG(10,("winbindd_dual_pam_auth_kerberos failed: %s\n", nt_errstr(result)));
1537                 }
1538 
1539                 if (NT_STATUS_EQUAL(result, NT_STATUS_NO_LOGON_SERVERS) ||
1540                     NT_STATUS_EQUAL(result, NT_STATUS_IO_TIMEOUT) ||
1541                     NT_STATUS_EQUAL(result, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1542                         DEBUG(10,("winbindd_dual_pam_auth_kerberos setting domain to offline\n"));
1543                         set_domain_offline( domain );
1544                         goto cached_logon;
1545                 }
1546 
1547                 /* there are quite some NT_STATUS errors where there is no
1548                  * point in retrying with a samlogon, we explictly have to take
1549                  * care not to increase the bad logon counter on the DC */
1550 
1551                 if (NT_STATUS_EQUAL(result, NT_STATUS_ACCOUNT_DISABLED) ||
1552                     NT_STATUS_EQUAL(result, NT_STATUS_ACCOUNT_EXPIRED) ||
1553                     NT_STATUS_EQUAL(result, NT_STATUS_ACCOUNT_LOCKED_OUT) ||
1554                     NT_STATUS_EQUAL(result, NT_STATUS_INVALID_LOGON_HOURS) ||
1555                     NT_STATUS_EQUAL(result, NT_STATUS_INVALID_WORKSTATION) ||
1556                     NT_STATUS_EQUAL(result, NT_STATUS_LOGON_FAILURE) ||
1557                     NT_STATUS_EQUAL(result, NT_STATUS_NO_SUCH_USER) ||
1558                     NT_STATUS_EQUAL(result, NT_STATUS_PASSWORD_EXPIRED) ||
1559                     NT_STATUS_EQUAL(result, NT_STATUS_PASSWORD_MUST_CHANGE) ||
1560                     NT_STATUS_EQUAL(result, NT_STATUS_WRONG_PASSWORD)) {
1561                         goto process_result;
1562                 }
1563 
1564                 if (state->request.flags & WBFLAG_PAM_FALLBACK_AFTER_KRB5) {
1565                         DEBUG(3,("falling back to samlogon\n"));
1566                         goto sam_logon;
1567                 } else {
1568                         goto cached_logon;
1569                 }
1570         }
1571 
1572 sam_logon:
1573         /* Check for Samlogon authentication */
1574         if (domain->online) {
1575                 result = winbindd_dual_pam_auth_samlogon(domain, state, &info3);
1576 
1577                 if (NT_STATUS_IS_OK(result)) {
1578                         DEBUG(10,("winbindd_dual_pam_auth_samlogon succeeded\n"));
1579                         /* add the Krb5 err if we have one */
1580                         if ( NT_STATUS_EQUAL(krb5_result, NT_STATUS_TIME_DIFFERENCE_AT_DC ) ) {
1581                                 info3->base.user_flags |= LOGON_KRB5_FAIL_CLOCK_SKEW;
1582                         }
1583                         goto process_result;
1584                 }
1585 
1586                 DEBUG(10,("winbindd_dual_pam_auth_samlogon failed: %s\n",
1587                           nt_errstr(result)));
1588 
1589                 if (NT_STATUS_EQUAL(result, NT_STATUS_NO_LOGON_SERVERS) ||
1590                     NT_STATUS_EQUAL(result, NT_STATUS_IO_TIMEOUT) ||
1591                     NT_STATUS_EQUAL(result, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND))
1592                 {
1593                         DEBUG(10,("winbindd_dual_pam_auth_samlogon setting domain to offline\n"));
1594                         set_domain_offline( domain );
1595                         goto cached_logon;
1596                 }
1597 
1598                         if (domain->online) {
1599                                 /* We're still online - fail. */
1600                                 goto done;
1601                         }
1602         }
1603 
1604 cached_logon:
1605         /* Check for Cached logons */
1606         if (!domain->online && (state->request.flags & WBFLAG_PAM_CACHED_LOGIN) &&
1607             lp_winbind_offline_logon()) {
1608 
1609                 result = winbindd_dual_pam_auth_cached(domain, state, &info3);
1610 
1611                 if (NT_STATUS_IS_OK(result)) {
1612                         DEBUG(10,("winbindd_dual_pam_auth_cached succeeded\n"));
1613                         goto process_result;
1614                 } else {
1615                         DEBUG(10,("winbindd_dual_pam_auth_cached failed: %s\n", nt_errstr(result)));
1616                         goto done;
1617                 }
1618         }
1619 
1620 process_result:
1621 
1622         if (NT_STATUS_IS_OK(result)) {
1623 
1624                 DOM_SID user_sid;
1625 
1626                 /* In all codepaths where result == NT_STATUS_OK info3 must have
1627                    been initialized. */
1628                 if (!info3) {
1629                         result = NT_STATUS_INTERNAL_ERROR;
1630                         goto done;
1631                 }
1632 
1633                 wcache_invalidate_samlogon(find_domain_from_name(name_domain), info3);
1634                 netsamlogon_cache_store(name_user, info3);
1635 
1636                 /* save name_to_sid info as early as possible (only if
1637                    this is our primary domain so we don't invalidate
1638                    the cache entry by storing the seq_num for the wrong
1639                    domain). */
1640                 if ( domain->primary ) {
1641                         sid_compose(&user_sid, info3->base.domain_sid,
1642                                     info3->base.rid);
1643                         cache_name2sid(domain, name_domain, name_user,
1644                                        SID_NAME_USER, &user_sid);
1645                 }
1646 
1647                 /* Check if the user is in the right group */
1648 
1649                 if (!NT_STATUS_IS_OK(result = check_info3_in_group(state->mem_ctx, info3,
1650                                         state->request.data.auth.require_membership_of_sid))) {
1651                         DEBUG(3, ("User %s is not in the required group (%s), so plaintext authentication is rejected\n",
1652                                   state->request.data.auth.user,
1653                                   state->request.data.auth.require_membership_of_sid));
1654                         goto done;
1655                 }
1656 
1657                 result = append_data(state, info3, name_domain, name_user);
1658                 if (!NT_STATUS_IS_OK(result)) {
1659                         goto done;
1660                 }
1661 
1662                 if ((state->request.flags & WBFLAG_PAM_CACHED_LOGIN)) {
1663 
1664                         /* Store in-memory creds for single-signon using ntlm_auth. */
1665                         result = winbindd_add_memory_creds(state->request.data.auth.user,
1666                                                         get_uid_from_state(state),
1667                                                         state->request.data.auth.pass);
1668 
1669                         if (!NT_STATUS_IS_OK(result)) {
1670                                 DEBUG(10,("Failed to store memory creds: %s\n", nt_errstr(result)));
1671                                 goto done;
1672                         }
1673 
1674                         if (lp_winbind_offline_logon()) {
1675                                 result = winbindd_store_creds(domain,
1676                                                       state->mem_ctx,
1677                                                       state->request.data.auth.user,
1678                                                       state->request.data.auth.pass,
1679                                                       info3, NULL);
1680                                 if (!NT_STATUS_IS_OK(result)) {
1681 
1682                                         /* Release refcount. */
1683                                         winbindd_delete_memory_creds(state->request.data.auth.user);
1684 
1685                                         DEBUG(10,("Failed to store creds: %s\n", nt_errstr(result)));
1686                                         goto done;
1687                                 }
1688                         }
1689                 }
1690 
1691 
1692                 if (state->request.flags & WBFLAG_PAM_GET_PWD_POLICY) {
1693                         struct winbindd_domain *our_domain = find_our_domain();
1694 
1695                         /* This is not entirely correct I believe, but it is
1696                            consistent.  Only apply the password policy settings
1697                            too warn users for our own domain.  Cannot obtain these
1698                            from trusted DCs all the  time so don't do it at all.
1699                            -- jerry */
1700 
1701                         result = NT_STATUS_NOT_SUPPORTED;
1702                         if (our_domain == domain ) {
1703                                 result = fillup_password_policy(our_domain, state);
1704                         }
1705 
1706                         if (!NT_STATUS_IS_OK(result)
1707                             && !NT_STATUS_EQUAL(result, NT_STATUS_NOT_SUPPORTED) )
1708                         {
1709                                 DEBUG(10,("Failed to get password policies for domain %s: %s\n",
1710                                           domain->name, nt_errstr(result)));
1711                                 goto done;
1712                         }
1713                 }
1714 
1715                 result = NT_STATUS_OK;
1716         }
1717 
1718 done:
1719         /* give us a more useful (more correct?) error code */
1720         if ((NT_STATUS_EQUAL(result, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND) ||
1721             (NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL)))) {
1722                 result = NT_STATUS_NO_LOGON_SERVERS;
1723         }
1724 
1725         set_auth_errors(&state->response, result);
1726 
1727         DEBUG(NT_STATUS_IS_OK(result) ? 5 : 2, ("Plain-text authentication for user %s returned %s (PAM: %d)\n",
1728               state->request.data.auth.user,
1729               state->response.data.auth.nt_status_string,
1730               state->response.data.auth.pam_error));
1731 
1732         return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
1733 }
1734 
1735 
1736 /**********************************************************************
1737  Challenge Response Authentication Protocol
1738 **********************************************************************/
1739 
1740 void winbindd_pam_auth_crap(struct winbindd_cli_state *state)
     /* [<][>][^][v][top][bottom][index][help] */
1741 {
1742         struct winbindd_domain *domain = NULL;
1743         const char *domain_name = NULL;
1744         NTSTATUS result;
1745 
1746         if (!check_request_flags(state->request.flags)) {
1747                 result = NT_STATUS_INVALID_PARAMETER_MIX;
1748                 goto done;
1749         }
1750 
1751         if (!state->privileged) {
1752                 char *error_string = NULL;
1753                 DEBUG(2, ("winbindd_pam_auth_crap: non-privileged access "
1754                           "denied.  !\n"));
1755                 DEBUGADD(2, ("winbindd_pam_auth_crap: Ensure permissions "
1756                              "on %s are set correctly.\n",
1757                              get_winbind_priv_pipe_dir()));
1758                 /* send a better message than ACCESS_DENIED */
1759                 error_string = talloc_asprintf(state->mem_ctx,
1760                                                "winbind client not authorized "
1761                                                "to use winbindd_pam_auth_crap."
1762                                                " Ensure permissions on %s "
1763                                                "are set correctly.",
1764                                                get_winbind_priv_pipe_dir());
1765                 fstrcpy(state->response.data.auth.error_string, error_string);
1766                 result = NT_STATUS_ACCESS_DENIED;
1767                 goto done;
1768         }
1769 
1770         /* Ensure null termination */
1771         state->request.data.auth_crap.user
1772                 [sizeof(state->request.data.auth_crap.user)-1]=0;
1773         state->request.data.auth_crap.domain
1774                 [sizeof(state->request.data.auth_crap.domain)-1]=0;
1775 
1776         DEBUG(3, ("[%5lu]: pam auth crap domain: [%s] user: %s\n",
1777                   (unsigned long)state->pid,
1778                   state->request.data.auth_crap.domain,
1779                   state->request.data.auth_crap.user));
1780 
1781         if (*state->request.data.auth_crap.domain != '\0') {
1782                 domain_name = state->request.data.auth_crap.domain;
1783         } else if (lp_winbind_use_default_domain()) {
1784                 domain_name = lp_workgroup();
1785         }
1786 
1787         if (domain_name != NULL)
1788                 domain = find_auth_domain(state, domain_name);
1789 
1790         if (domain != NULL) {
1791                 sendto_domain(state, domain);
1792                 return;
1793         }
1794 
1795         result = NT_STATUS_NO_SUCH_USER;
1796 
1797  done:
1798         set_auth_errors(&state->response, result);
1799         DEBUG(5, ("CRAP authentication for %s\\%s returned %s (PAM: %d)\n",
1800                   state->request.data.auth_crap.domain,
1801                   state->request.data.auth_crap.user,
1802                   state->response.data.auth.nt_status_string,
1803                   state->response.data.auth.pam_error));
1804         request_error(state);
1805         return;
1806 }
1807 
1808 
1809 enum winbindd_result winbindd_dual_pam_auth_crap(struct winbindd_domain *domain,
     /* [<][>][^][v][top][bottom][index][help] */
1810                                                  struct winbindd_cli_state *state)
1811 {
1812         NTSTATUS result;
1813         struct netr_SamInfo3 *info3 = NULL;
1814         struct rpc_pipe_client *netlogon_pipe;
1815         const char *name_user = NULL;
1816         const char *name_domain = NULL;
1817         const char *workstation;
1818         struct winbindd_domain *contact_domain;
1819         int attempts = 0;
1820         bool retry;
1821 
1822         DATA_BLOB lm_resp, nt_resp;
1823 
1824         /* This is child-only, so no check for privileged access is needed
1825            anymore */
1826 
1827         /* Ensure null termination */
1828         state->request.data.auth_crap.user[sizeof(state->request.data.auth_crap.user)-1]=0;
1829         state->request.data.auth_crap.domain[sizeof(state->request.data.auth_crap.domain)-1]=0;
1830 
1831         if (!check_request_flags(state->request.flags)) {
1832                 result = NT_STATUS_INVALID_PARAMETER_MIX;
1833                 goto done;
1834         }
1835 
1836         name_user = state->request.data.auth_crap.user;
1837 
1838         if (*state->request.data.auth_crap.domain) {
1839                 name_domain = state->request.data.auth_crap.domain;
1840         } else if (lp_winbind_use_default_domain()) {
1841                 name_domain = lp_workgroup();
1842         } else {
1843                 DEBUG(5,("no domain specified with username (%s) - failing auth\n",
1844                          name_user));
1845                 result = NT_STATUS_NO_SUCH_USER;
1846                 goto done;
1847         }
1848 
1849         DEBUG(3, ("[%5lu]: pam auth crap domain: %s user: %s\n", (unsigned long)state->pid,
1850                   name_domain, name_user));
1851 
1852         if (*state->request.data.auth_crap.workstation) {
1853                 workstation = state->request.data.auth_crap.workstation;
1854         } else {
1855                 workstation = global_myname();
1856         }
1857 
1858         if (state->request.data.auth_crap.lm_resp_len > sizeof(state->request.data.auth_crap.lm_resp)
1859                 || state->request.data.auth_crap.nt_resp_len > sizeof(state->request.data.auth_crap.nt_resp)) {
1860                 if (!(state->request.flags & WBFLAG_BIG_NTLMV2_BLOB) ||
1861                      state->request.extra_len != state->request.data.auth_crap.nt_resp_len) {
1862                         DEBUG(0, ("winbindd_pam_auth_crap: invalid password length %u/%u\n",
1863                                   state->request.data.auth_crap.lm_resp_len,
1864                                   state->request.data.auth_crap.nt_resp_len));
1865                         result = NT_STATUS_INVALID_PARAMETER;
1866                         goto done;
1867                 }
1868         }
1869 
1870         lm_resp = data_blob_talloc(state->mem_ctx, state->request.data.auth_crap.lm_resp,
1871                                         state->request.data.auth_crap.lm_resp_len);
1872 
1873         if (state->request.flags & WBFLAG_BIG_NTLMV2_BLOB) {
1874                 nt_resp = data_blob_talloc(state->mem_ctx,
1875                                            state->request.extra_data.data,
1876                                            state->request.data.auth_crap.nt_resp_len);
1877         } else {
1878                 nt_resp = data_blob_talloc(state->mem_ctx,
1879                                            state->request.data.auth_crap.nt_resp,
1880                                            state->request.data.auth_crap.nt_resp_len);
1881         }
1882 
1883         /* what domain should we contact? */
1884 
1885         if ( IS_DC ) {
1886                 if (!(contact_domain = find_domain_from_name(name_domain))) {
1887                         DEBUG(3, ("Authentication for domain for [%s] -> [%s]\\[%s] failed as %s is not a trusted domain\n",
1888                                   state->request.data.auth_crap.user, name_domain, name_user, name_domain));
1889                         result = NT_STATUS_NO_SUCH_USER;
1890                         goto done;
1891                 }
1892         } else {
1893                 if (is_myname(name_domain)) {
1894                         DEBUG(3, ("Authentication for domain %s (local domain to this server) not supported at this stage\n", name_domain));
1895                         result =  NT_STATUS_NO_SUCH_USER;
1896                         goto done;
1897                 }
1898                 contact_domain = find_our_domain();
1899         }
1900 
1901         do {
1902                 netlogon_fn_t logon_fn;
1903 
1904                 retry = false;
1905 
1906                 netlogon_pipe = NULL;
1907                 result = cm_connect_netlogon(contact_domain, &netlogon_pipe);
1908 
1909                 if (!NT_STATUS_IS_OK(result)) {
1910                         DEBUG(3, ("could not open handle to NETLOGON pipe (error: %s)\n",
1911                                   nt_errstr(result)));
1912                         goto done;
1913                 }
1914 
1915                 logon_fn = contact_domain->can_do_samlogon_ex
1916                         ? rpccli_netlogon_sam_network_logon_ex
1917                         : rpccli_netlogon_sam_network_logon;
1918 
1919                 result = logon_fn(netlogon_pipe,
1920                                   state->mem_ctx,
1921                                   state->request.data.auth_crap.logon_parameters,
1922                                   contact_domain->dcname,
1923                                   name_user,
1924                                   name_domain,
1925                                   /* Bug #3248 - found by Stefan Burkei. */
1926                                   workstation, /* We carefully set this above so use it... */
1927                                   state->request.data.auth_crap.chal,
1928                                   lm_resp,
1929                                   nt_resp,
1930                                   &info3);
1931 
1932                 if ((NT_STATUS_V(result) == DCERPC_FAULT_OP_RNG_ERROR)
1933                     && contact_domain->can_do_samlogon_ex) {
1934                         DEBUG(3, ("Got a DC that can not do NetSamLogonEx, "
1935                                   "retrying with NetSamLogon\n"));
1936                         contact_domain->can_do_samlogon_ex = false;
1937                         retry = true;
1938                         continue;
1939                 }
1940 
1941                 attempts += 1;
1942 
1943                 /* We have to try a second time as cm_connect_netlogon
1944                    might not yet have noticed that the DC has killed
1945                    our connection. */
1946 
1947                 if (NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL)) {
1948                         retry = true;
1949                         continue;
1950                 }
1951 
1952                 /* if we get access denied, a possible cause was that we had and open
1953                    connection to the DC, but someone changed our machine account password
1954                    out from underneath us using 'net rpc changetrustpw' */
1955 
1956                 if ( NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED) ) {
1957                         DEBUG(3,("winbindd_pam_auth: sam_logon returned "
1958                                  "ACCESS_DENIED.  Maybe the trust account "
1959                                 "password was changed and we didn't know it. "
1960                                  "Killing connections to domain %s\n",
1961                                 name_domain));
1962                         invalidate_cm_connection(&contact_domain->conn);
1963                         retry = true;
1964                 }
1965 
1966         } while ( (attempts < 2) && retry );
1967 
1968         if (NT_STATUS_IS_OK(result)) {
1969 
1970                 wcache_invalidate_samlogon(find_domain_from_name(name_domain), info3);
1971                 netsamlogon_cache_store(name_user, info3);
1972 
1973                 /* Check if the user is in the right group */
1974 
1975                 if (!NT_STATUS_IS_OK(result = check_info3_in_group(state->mem_ctx, info3,
1976                                                         state->request.data.auth_crap.require_membership_of_sid))) {
1977                         DEBUG(3, ("User %s is not in the required group (%s), so "
1978                                   "crap authentication is rejected\n",
1979                                   state->request.data.auth_crap.user,
1980                                   state->request.data.auth_crap.require_membership_of_sid));
1981                         goto done;
1982                 }
1983 
1984                 result = append_data(state, info3, name_domain, name_user);
1985                 if (!NT_STATUS_IS_OK(result)) {
1986                         goto done;
1987                 }
1988         }
1989 
1990 done:
1991 
1992         /* give us a more useful (more correct?) error code */
1993         if ((NT_STATUS_EQUAL(result, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND) ||
1994             (NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL)))) {
1995                 result = NT_STATUS_NO_LOGON_SERVERS;
1996         }
1997 
1998         if (state->request.flags & WBFLAG_PAM_NT_STATUS_SQUASH) {
1999                 result = nt_status_squash(result);
2000         }
2001 
2002         set_auth_errors(&state->response, result);
2003 
2004         DEBUG(NT_STATUS_IS_OK(result) ? 5 : 2,
2005               ("NTLM CRAP authentication for user [%s]\\[%s] returned %s (PAM: %d)\n",
2006                name_domain,
2007                name_user,
2008                state->response.data.auth.nt_status_string,
2009                state->response.data.auth.pam_error));
2010 
2011         return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
2012 }
2013 
2014 /* Change a user password */
2015 
2016 void winbindd_pam_chauthtok(struct winbindd_cli_state *state)
     /* [<][>][^][v][top][bottom][index][help] */
2017 {
2018         fstring domain, user;
2019         char *mapped_user;
2020         struct winbindd_domain *contact_domain;
2021         NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
2022 
2023         DEBUG(3, ("[%5lu]: pam chauthtok %s\n", (unsigned long)state->pid,
2024                 state->request.data.chauthtok.user));
2025 
2026         /* Setup crap */
2027 
2028         nt_status = normalize_name_unmap(state->mem_ctx,
2029                                          state->request.data.chauthtok.user,
2030                                          &mapped_user);
2031 
2032         /* Update the chauthtok name if we did any mapping */
2033 
2034         if (NT_STATUS_IS_OK(nt_status) ||
2035             NT_STATUS_EQUAL(nt_status, NT_STATUS_FILE_RENAMED))
2036         {
2037                 fstrcpy(state->request.data.chauthtok.user, mapped_user);
2038         }
2039 
2040         /* Must pass in state->...chauthtok.user because
2041            canonicalize_username() assumes an fstring().  Since
2042            we have already copied it (if necessary), this is ok. */
2043 
2044         if (!canonicalize_username(state->request.data.chauthtok.user, domain, user)) {
2045                 set_auth_errors(&state->response, NT_STATUS_NO_SUCH_USER);
2046                 DEBUG(5, ("winbindd_pam_chauthtok: canonicalize_username %s failed with %s"
2047                           "(PAM: %d)\n",
2048                           state->request.data.auth.user,
2049                           state->response.data.auth.nt_status_string,
2050                           state->response.data.auth.pam_error));
2051                 request_error(state);
2052                 return;
2053         }
2054 
2055         contact_domain = find_domain_from_name(domain);
2056         if (!contact_domain) {
2057                 set_auth_errors(&state->response, NT_STATUS_NO_SUCH_USER);
2058                 DEBUG(3, ("Cannot change password for [%s] -> [%s]\\[%s] as %s is not a trusted domain\n",
2059                           state->request.data.chauthtok.user, domain, user, domain));
2060                 request_error(state);
2061                 return;
2062         }
2063 
2064         sendto_domain(state, contact_domain);
2065 }
2066 
2067 enum winbindd_result winbindd_dual_pam_chauthtok(struct winbindd_domain *contact_domain,
     /* [<][>][^][v][top][bottom][index][help] */
2068                                                  struct winbindd_cli_state *state)
2069 {
2070         char *oldpass;
2071         char *newpass = NULL;
2072         struct policy_handle dom_pol;
2073         struct rpc_pipe_client *cli;
2074         bool got_info = false;
2075         struct samr_DomInfo1 *info = NULL;
2076         struct samr_ChangeReject *reject = NULL;
2077         NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
2078         fstring domain, user;
2079 
2080         DEBUG(3, ("[%5lu]: dual pam chauthtok %s\n", (unsigned long)state->pid,
2081                   state->request.data.auth.user));
2082 
2083         if (!parse_domain_user(state->request.data.chauthtok.user, domain, user)) {
2084                 goto done;
2085         }
2086 
2087         /* Change password */
2088 
2089         oldpass = state->request.data.chauthtok.oldpass;
2090         newpass = state->request.data.chauthtok.newpass;
2091 
2092         /* Initialize reject reason */
2093         state->response.data.auth.reject_reason = Undefined;
2094 
2095         /* Get sam handle */
2096 
2097         result = cm_connect_sam(contact_domain, state->mem_ctx, &cli,
2098                                 &dom_pol);
2099         if (!NT_STATUS_IS_OK(result)) {
2100                 DEBUG(1, ("could not get SAM handle on DC for %s\n", domain));
2101                 goto done;
2102         }
2103 
2104         result = rpccli_samr_chgpasswd_user3(cli, state->mem_ctx,
2105                                              user,
2106                                              newpass,
2107                                              oldpass,
2108                                              &info,
2109                                              &reject);
2110 
2111         /* Windows 2003 returns NT_STATUS_PASSWORD_RESTRICTION */
2112 
2113         if (NT_STATUS_EQUAL(result, NT_STATUS_PASSWORD_RESTRICTION) ) {
2114 
2115                 fill_in_password_policy(&state->response, info);
2116 
2117                 state->response.data.auth.reject_reason =
2118                         reject->reason;
2119 
2120                 got_info = true;
2121         }
2122 
2123         /* atm the pidl generated rpccli_samr_ChangePasswordUser3 function will
2124          * return with NT_STATUS_BUFFER_TOO_SMALL for w2k dcs as w2k just
2125          * returns with 4byte error code (NT_STATUS_NOT_SUPPORTED) which is too
2126          * short to comply with the samr_ChangePasswordUser3 idl - gd */
2127 
2128         /* only fallback when the chgpasswd_user3 call is not supported */
2129         if ((NT_STATUS_EQUAL(result, NT_STATUS(DCERPC_FAULT_OP_RNG_ERROR))) ||
2130                    (NT_STATUS_EQUAL(result, NT_STATUS_NOT_SUPPORTED)) ||
2131                    (NT_STATUS_EQUAL(result, NT_STATUS_BUFFER_TOO_SMALL)) ||
2132                    (NT_STATUS_EQUAL(result, NT_STATUS_NOT_IMPLEMENTED))) {
2133 
2134                 DEBUG(10,("Password change with chgpasswd_user3 failed with: %s, retrying chgpasswd_user2\n",
2135                         nt_errstr(result)));
2136 
2137                 result = rpccli_samr_chgpasswd_user2(cli, state->mem_ctx, user, newpass, oldpass);
2138 
2139                 /* Windows 2000 returns NT_STATUS_ACCOUNT_RESTRICTION.
2140                    Map to the same status code as Windows 2003. */
2141 
2142                 if ( NT_STATUS_EQUAL(NT_STATUS_ACCOUNT_RESTRICTION, result ) ) {
2143                         result = NT_STATUS_PASSWORD_RESTRICTION;
2144                 }
2145         }
2146 
2147 done:
2148 
2149         if (NT_STATUS_IS_OK(result) && (state->request.flags & WBFLAG_PAM_CACHED_LOGIN)) {
2150 
2151                 /* Update the single sign-on memory creds. */
2152                 result = winbindd_replace_memory_creds(state->request.data.chauthtok.user,
2153                                                         newpass);
2154 
2155                 /* When we login from gdm or xdm and password expires,
2156                  * we change password, but there are no memory crendentials
2157                  * So, winbindd_replace_memory_creds() returns
2158                  * NT_STATUS_OBJECT_NAME_NOT_FOUND. This is not a failure.
2159                  * --- BoYang
2160                  * */
2161                 if (NT_STATUS_EQUAL(result, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
2162                         result = NT_STATUS_OK;
2163                 }
2164 
2165                 if (!NT_STATUS_IS_OK(result)) {
2166                         DEBUG(10,("Failed to replace memory creds: %s\n", nt_errstr(result)));
2167                         goto process_result;
2168                 }
2169 
2170                 if (lp_winbind_offline_logon()) {
2171                         result = winbindd_update_creds_by_name(contact_domain,
2172                                                          state->mem_ctx, user,
2173                                                          newpass);
2174                         /* Again, this happens when we login from gdm or xdm
2175                          * and the password expires, *BUT* cached crendentials
2176                          * doesn't exist. winbindd_update_creds_by_name()
2177                          * returns NT_STATUS_NO_SUCH_USER.
2178                          * This is not a failure.
2179                          * --- BoYang
2180                          * */
2181                         if (NT_STATUS_EQUAL(result, NT_STATUS_NO_SUCH_USER)) {
2182                                 result = NT_STATUS_OK;
2183                         }
2184 
2185                         if (!NT_STATUS_IS_OK(result)) {
2186                                 DEBUG(10,("Failed to store creds: %s\n", nt_errstr(result)));
2187                                 goto process_result;
2188                         }
2189                 }
2190         }
2191 
2192         if (!NT_STATUS_IS_OK(result) && !got_info && contact_domain) {
2193 
2194                 NTSTATUS policy_ret;
2195 
2196                 policy_ret = fillup_password_policy(contact_domain, state);
2197 
2198                 /* failure of this is non critical, it will just provide no
2199                  * additional information to the client why the change has
2200                  * failed - Guenther */
2201 
2202                 if (!NT_STATUS_IS_OK(policy_ret)) {
2203                         DEBUG(10,("Failed to get password policies: %s\n", nt_errstr(policy_ret)));
2204                         goto process_result;
2205                 }
2206         }
2207 
2208 process_result:
2209 
2210         set_auth_errors(&state->response, result);
2211 
2212         DEBUG(NT_STATUS_IS_OK(result) ? 5 : 2,
2213               ("Password change for user [%s]\\[%s] returned %s (PAM: %d)\n",
2214                domain,
2215                user,
2216                state->response.data.auth.nt_status_string,
2217                state->response.data.auth.pam_error));
2218 
2219         return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
2220 }
2221 
2222 void winbindd_pam_logoff(struct winbindd_cli_state *state)
     /* [<][>][^][v][top][bottom][index][help] */
2223 {
2224         struct winbindd_domain *domain;
2225         fstring name_domain, user;
2226         uid_t caller_uid = (uid_t)-1;
2227         uid_t request_uid = state->request.data.logoff.uid;
2228 
2229         DEBUG(3, ("[%5lu]: pam logoff %s\n", (unsigned long)state->pid,
2230                 state->request.data.logoff.user));
2231 
2232         /* Ensure null termination */
2233         state->request.data.logoff.user
2234                 [sizeof(state->request.data.logoff.user)-1]='\0';
2235 
2236         state->request.data.logoff.krb5ccname
2237                 [sizeof(state->request.data.logoff.krb5ccname)-1]='\0';
2238 
2239         if (request_uid == (gid_t)-1) {
2240                 goto failed;
2241         }
2242 
2243         if (!canonicalize_username(state->request.data.logoff.user, name_domain, user)) {
2244                 goto failed;
2245         }
2246 
2247         if ((domain = find_auth_domain(state, name_domain)) == NULL) {
2248                 goto failed;
2249         }
2250 
2251         if ((sys_getpeereid(state->sock, &caller_uid)) != 0) {
2252                 DEBUG(1,("winbindd_pam_logoff: failed to check peerid: %s\n",
2253                         strerror(errno)));
2254                 goto failed;
2255         }
2256 
2257         switch (caller_uid) {
2258                 case -1:
2259                         goto failed;
2260                 case 0:
2261                         /* root must be able to logoff any user - gd */
2262                         state->request.data.logoff.uid = request_uid;
2263                         break;
2264                 default:
2265                         if (caller_uid != request_uid) {
2266                                 DEBUG(1,("winbindd_pam_logoff: caller requested invalid uid\n"));
2267                                 goto failed;
2268                         }
2269                         state->request.data.logoff.uid = caller_uid;
2270                         break;
2271         }
2272 
2273         sendto_domain(state, domain);
2274         return;
2275 
2276  failed:
2277         set_auth_errors(&state->response, NT_STATUS_NO_SUCH_USER);
2278         DEBUG(5, ("Pam Logoff for %s returned %s "
2279                   "(PAM: %d)\n",
2280                   state->request.data.logoff.user,
2281                   state->response.data.auth.nt_status_string,
2282                   state->response.data.auth.pam_error));
2283         request_error(state);
2284         return;
2285 }
2286 
2287 enum winbindd_result winbindd_dual_pam_logoff(struct winbindd_domain *domain,
     /* [<][>][^][v][top][bottom][index][help] */
2288                                               struct winbindd_cli_state *state)
2289 {
2290         NTSTATUS result = NT_STATUS_NOT_SUPPORTED;
2291 
2292         DEBUG(3, ("[%5lu]: pam dual logoff %s\n", (unsigned long)state->pid,
2293                 state->request.data.logoff.user));
2294 
2295         if (!(state->request.flags & WBFLAG_PAM_KRB5)) {
2296                 result = NT_STATUS_OK;
2297                 goto process_result;
2298         }
2299 
2300         if (state->request.data.logoff.krb5ccname[0] == '\0') {
2301                 result = NT_STATUS_OK;
2302                 goto process_result;
2303         }
2304 
2305 #ifdef HAVE_KRB5
2306 
2307         if (state->request.data.logoff.uid < 0) {
2308                 DEBUG(0,("winbindd_pam_logoff: invalid uid\n"));
2309                 goto process_result;
2310         }
2311 
2312         /* what we need here is to find the corresponding krb5 ccache name *we*
2313          * created for a given username and destroy it */
2314 
2315         if (!ccache_entry_exists(state->request.data.logoff.user)) {
2316                 result = NT_STATUS_OK;
2317                 DEBUG(10,("winbindd_pam_logoff: no entry found.\n"));
2318                 goto process_result;
2319         }
2320 
2321         if (!ccache_entry_identical(state->request.data.logoff.user,
2322                                         state->request.data.logoff.uid,
2323                                         state->request.data.logoff.krb5ccname)) {
2324                 DEBUG(0,("winbindd_pam_logoff: cached entry differs.\n"));
2325                 goto process_result;
2326         }
2327 
2328         result = remove_ccache(state->request.data.logoff.user);
2329         if (!NT_STATUS_IS_OK(result)) {
2330                 DEBUG(0,("winbindd_pam_logoff: failed to remove ccache: %s\n",
2331                         nt_errstr(result)));
2332                 goto process_result;
2333         }
2334 
2335 #else
2336         result = NT_STATUS_NOT_SUPPORTED;
2337 #endif
2338 
2339 process_result:
2340 
2341         winbindd_delete_memory_creds(state->request.data.logoff.user);
2342 
2343         set_auth_errors(&state->response, result);
2344 
2345         return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
2346 }
2347 
2348 /* Change user password with auth crap*/
2349 
2350 void winbindd_pam_chng_pswd_auth_crap(struct winbindd_cli_state *state)
     /* [<][>][^][v][top][bottom][index][help] */
2351 {
2352         struct winbindd_domain *domain = NULL;
2353         const char *domain_name = NULL;
2354 
2355         /* Ensure null termination */
2356         state->request.data.chng_pswd_auth_crap.user[
2357                 sizeof(state->request.data.chng_pswd_auth_crap.user)-1]=0;
2358         state->request.data.chng_pswd_auth_crap.domain[
2359                 sizeof(state->request.data.chng_pswd_auth_crap.domain)-1]=0;
2360 
2361         DEBUG(3, ("[%5lu]: pam change pswd auth crap domain: %s user: %s\n",
2362                   (unsigned long)state->pid,
2363                   state->request.data.chng_pswd_auth_crap.domain,
2364                   state->request.data.chng_pswd_auth_crap.user));
2365 
2366         if (*state->request.data.chng_pswd_auth_crap.domain != '\0') {
2367                 domain_name = state->request.data.chng_pswd_auth_crap.domain;
2368         } else if (lp_winbind_use_default_domain()) {
2369                 domain_name = lp_workgroup();
2370         }
2371 
2372         if (domain_name != NULL)
2373                 domain = find_domain_from_name(domain_name);
2374 
2375         if (domain != NULL) {
2376                 DEBUG(7, ("[%5lu]: pam auth crap changing pswd in domain: "
2377                           "%s\n", (unsigned long)state->pid,domain->name));
2378                 sendto_domain(state, domain);
2379                 return;
2380         }
2381 
2382         set_auth_errors(&state->response, NT_STATUS_NO_SUCH_USER);
2383         DEBUG(5, ("CRAP change password  for %s\\%s returned %s (PAM: %d)\n",
2384                   state->request.data.chng_pswd_auth_crap.domain,
2385                   state->request.data.chng_pswd_auth_crap.user,
2386                   state->response.data.auth.nt_status_string,
2387                   state->response.data.auth.pam_error));
2388         request_error(state);
2389         return;
2390 }
2391 
2392 enum winbindd_result winbindd_dual_pam_chng_pswd_auth_crap(struct winbindd_domain *domainSt, struct winbindd_cli_state *state)
     /* [<][>][^][v][top][bottom][index][help] */
2393 {
2394         NTSTATUS result;
2395         DATA_BLOB new_nt_password;
2396         DATA_BLOB old_nt_hash_enc;
2397         DATA_BLOB new_lm_password;
2398         DATA_BLOB old_lm_hash_enc;
2399         fstring  domain,user;
2400         struct policy_handle dom_pol;
2401         struct winbindd_domain *contact_domain = domainSt;
2402         struct rpc_pipe_client *cli;
2403 
2404         /* Ensure null termination */
2405         state->request.data.chng_pswd_auth_crap.user[
2406                 sizeof(state->request.data.chng_pswd_auth_crap.user)-1]=0;
2407         state->request.data.chng_pswd_auth_crap.domain[
2408                 sizeof(state->request.data.chng_pswd_auth_crap.domain)-1]=0;
2409         *domain = 0;
2410         *user = 0;
2411 
2412         DEBUG(3, ("[%5lu]: pam change pswd auth crap domain: %s user: %s\n",
2413                   (unsigned long)state->pid,
2414                   state->request.data.chng_pswd_auth_crap.domain,
2415                   state->request.data.chng_pswd_auth_crap.user));
2416 
2417         if (lp_winbind_offline_logon()) {
2418                 DEBUG(0,("Refusing password change as winbind offline logons are enabled. "));
2419                 DEBUGADD(0,("Changing passwords here would risk inconsistent logons\n"));
2420                 result = NT_STATUS_ACCESS_DENIED;
2421                 goto done;
2422         }
2423 
2424         if (*state->request.data.chng_pswd_auth_crap.domain) {
2425                 fstrcpy(domain,state->request.data.chng_pswd_auth_crap.domain);
2426         } else {
2427                 parse_domain_user(state->request.data.chng_pswd_auth_crap.user,
2428                                   domain, user);
2429 
2430                 if(!*domain) {
2431                         DEBUG(3,("no domain specified with username (%s) - "
2432                                  "failing auth\n",
2433                                  state->request.data.chng_pswd_auth_crap.user));
2434                         result = NT_STATUS_NO_SUCH_USER;
2435                         goto done;
2436                 }
2437         }
2438 
2439         if (!*domain && lp_winbind_use_default_domain()) {
2440                 fstrcpy(domain,(char *)lp_workgroup());
2441         }
2442 
2443         if(!*user) {
2444                 fstrcpy(user, state->request.data.chng_pswd_auth_crap.user);
2445         }
2446 
2447         DEBUG(3, ("[%5lu]: pam auth crap domain: %s user: %s\n",
2448                   (unsigned long)state->pid, domain, user));
2449 
2450         /* Change password */
2451         new_nt_password = data_blob_talloc(
2452                 state->mem_ctx,
2453                 state->request.data.chng_pswd_auth_crap.new_nt_pswd,
2454                 state->request.data.chng_pswd_auth_crap.new_nt_pswd_len);
2455 
2456         old_nt_hash_enc = data_blob_talloc(
2457                 state->mem_ctx,
2458                 state->request.data.chng_pswd_auth_crap.old_nt_hash_enc,
2459                 state->request.data.chng_pswd_auth_crap.old_nt_hash_enc_len);
2460 
2461         if(state->request.data.chng_pswd_auth_crap.new_lm_pswd_len > 0) {
2462                 new_lm_password = data_blob_talloc(
2463                         state->mem_ctx,
2464                         state->request.data.chng_pswd_auth_crap.new_lm_pswd,
2465                         state->request.data.chng_pswd_auth_crap.new_lm_pswd_len);
2466 
2467                 old_lm_hash_enc = data_blob_talloc(
2468                         state->mem_ctx,
2469                         state->request.data.chng_pswd_auth_crap.old_lm_hash_enc,
2470                         state->request.data.chng_pswd_auth_crap.old_lm_hash_enc_len);
2471         } else {
2472                 new_lm_password.length = 0;
2473                 old_lm_hash_enc.length = 0;
2474         }
2475 
2476         /* Get sam handle */
2477 
2478         result = cm_connect_sam(contact_domain, state->mem_ctx, &cli, &dom_pol);
2479         if (!NT_STATUS_IS_OK(result)) {
2480                 DEBUG(1, ("could not get SAM handle on DC for %s\n", domain));
2481                 goto done;
2482         }
2483 
2484         result = rpccli_samr_chng_pswd_auth_crap(
2485                 cli, state->mem_ctx, user, new_nt_password, old_nt_hash_enc,
2486                 new_lm_password, old_lm_hash_enc);
2487 
2488  done:
2489 
2490         set_auth_errors(&state->response, result);
2491 
2492         DEBUG(NT_STATUS_IS_OK(result) ? 5 : 2,
2493               ("Password change for user [%s]\\[%s] returned %s (PAM: %d)\n",
2494                domain, user,
2495                state->response.data.auth.nt_status_string,
2496                state->response.data.auth.pam_error));
2497 
2498         return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
2499 }

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