nsswitch/winbindd_pam.c

説明を見る。
00001 /*
00002    Unix SMB/CIFS implementation.
00003 
00004    Winbind daemon - pam auth funcions
00005 
00006    Copyright (C) Andrew Tridgell 2000
00007    Copyright (C) Tim Potter 2001
00008    Copyright (C) Andrew Bartlett 2001-2002
00009    Copyright (C) Guenther Deschner 2005
00010    
00011    This program is free software; you can redistribute it and/or modify
00012    it under the terms of the GNU General Public License as published by
00013    the Free Software Foundation; either version 2 of the License, or
00014    (at your option) any later version.
00015    
00016    This program is distributed in the hope that it will be useful,
00017    but WITHOUT ANY WARRANTY; without even the implied warranty of
00018    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019    GNU General Public License for more details.
00020    
00021    You should have received a copy of the GNU General Public License
00022    along with this program; if not, write to the Free Software
00023    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00024 */
00025 
00026 #include "includes.h"
00027 #include "winbindd.h"
00028 #undef DBGC_CLASS
00029 #define DBGC_CLASS DBGC_WINBIND
00030 
00031 static NTSTATUS append_info3_as_txt(TALLOC_CTX *mem_ctx, 
00032                                     struct winbindd_cli_state *state, 
00033                                     NET_USER_INFO_3 *info3) 
00034 {
00035         fstring str_sid;
00036 
00037         state->response.data.auth.info3.logon_time = 
00038                 nt_time_to_unix(info3->logon_time);
00039         state->response.data.auth.info3.logoff_time = 
00040                 nt_time_to_unix(info3->logoff_time);
00041         state->response.data.auth.info3.kickoff_time = 
00042                 nt_time_to_unix(info3->kickoff_time);
00043         state->response.data.auth.info3.pass_last_set_time = 
00044                 nt_time_to_unix(info3->pass_last_set_time);
00045         state->response.data.auth.info3.pass_can_change_time = 
00046                 nt_time_to_unix(info3->pass_can_change_time);
00047         state->response.data.auth.info3.pass_must_change_time = 
00048                 nt_time_to_unix(info3->pass_must_change_time);
00049 
00050         state->response.data.auth.info3.logon_count = info3->logon_count;
00051         state->response.data.auth.info3.bad_pw_count = info3->bad_pw_count;
00052 
00053         state->response.data.auth.info3.user_rid = info3->user_rid;
00054         state->response.data.auth.info3.group_rid = info3->group_rid;
00055         sid_to_string(str_sid, &(info3->dom_sid.sid));
00056         fstrcpy(state->response.data.auth.info3.dom_sid, str_sid);
00057 
00058         state->response.data.auth.info3.num_groups = info3->num_groups;
00059         state->response.data.auth.info3.user_flgs = info3->user_flgs;
00060 
00061         state->response.data.auth.info3.acct_flags = info3->acct_flags;
00062         state->response.data.auth.info3.num_other_sids = info3->num_other_sids;
00063 
00064         unistr2_to_ascii(state->response.data.auth.info3.user_name, 
00065                 &info3->uni_user_name, -1);
00066         unistr2_to_ascii(state->response.data.auth.info3.full_name, 
00067                 &info3->uni_full_name, -1);
00068         unistr2_to_ascii(state->response.data.auth.info3.logon_script, 
00069                 &info3->uni_logon_script, -1);
00070         unistr2_to_ascii(state->response.data.auth.info3.profile_path, 
00071                 &info3->uni_profile_path, -1);
00072         unistr2_to_ascii(state->response.data.auth.info3.home_dir, 
00073                 &info3->uni_home_dir, -1);
00074         unistr2_to_ascii(state->response.data.auth.info3.dir_drive, 
00075                 &info3->uni_dir_drive, -1);
00076 
00077         unistr2_to_ascii(state->response.data.auth.info3.logon_srv, 
00078                 &info3->uni_logon_srv, -1);
00079         unistr2_to_ascii(state->response.data.auth.info3.logon_dom, 
00080                 &info3->uni_logon_dom, -1);
00081 
00082         return NT_STATUS_OK;
00083 }
00084 
00085 static NTSTATUS append_info3_as_ndr(TALLOC_CTX *mem_ctx, 
00086                                     struct winbindd_cli_state *state, 
00087                                     NET_USER_INFO_3 *info3) 
00088 {
00089         prs_struct ps;
00090         uint32 size;
00091         if (!prs_init(&ps, 256 /* Random, non-zero number */, mem_ctx, MARSHALL)) {
00092                 return NT_STATUS_NO_MEMORY;
00093         }
00094         if (!net_io_user_info3("", info3, &ps, 1, 3, False)) {
00095                 prs_mem_free(&ps);
00096                 return NT_STATUS_UNSUCCESSFUL;
00097         }
00098 
00099         size = prs_data_size(&ps);
00100         SAFE_FREE(state->response.extra_data.data);
00101         state->response.extra_data.data = SMB_MALLOC(size);
00102         if (!state->response.extra_data.data) {
00103                 prs_mem_free(&ps);
00104                 return NT_STATUS_NO_MEMORY;
00105         }
00106         memset( state->response.extra_data.data, '\0', size );
00107         prs_copy_all_data_out((char *)state->response.extra_data.data, &ps);
00108         state->response.length += size;
00109         prs_mem_free(&ps);
00110         return NT_STATUS_OK;
00111 }
00112 
00113 static NTSTATUS check_info3_in_group(TALLOC_CTX *mem_ctx, 
00114                                      NET_USER_INFO_3 *info3,
00115                                      const char *group_sid) 
00116 /**
00117  * Check whether a user belongs to a group or list of groups.
00118  *
00119  * @param mem_ctx talloc memory context.
00120  * @param info3 user information, including group membership info.
00121  * @param group_sid One or more groups , separated by commas.
00122  *
00123  * @return NT_STATUS_OK on success,
00124  *    NT_STATUS_LOGON_FAILURE if the user does not belong,
00125  *    or other NT_STATUS_IS_ERR(status) for other kinds of failure.
00126  */
00127 {
00128         DOM_SID *require_membership_of_sid;
00129         size_t num_require_membership_of_sid;
00130         DOM_SID *all_sids;
00131         size_t num_all_sids = (2 + info3->num_groups2 + info3->num_other_sids);
00132         size_t i, j = 0, k;
00133         size_t group_sid_length;
00134         const char *search_location;
00135         char *single_group_sid;
00136         const char *comma;
00137 
00138         /* Parse the 'required group' SID */
00139         
00140         if (!group_sid || !group_sid[0]) {
00141                 /* NO sid supplied, all users may access */
00142                 return NT_STATUS_OK;
00143         }
00144 
00145         num_require_membership_of_sid = 1;
00146         group_sid_length = strlen(group_sid);
00147         for (i = 0; i < group_sid_length; i++) {
00148                 if (',' == group_sid[i]) {
00149                         num_require_membership_of_sid++;
00150                 }
00151         }
00152 
00153         require_membership_of_sid = TALLOC_ARRAY(mem_ctx, DOM_SID, num_require_membership_of_sid);
00154         if (!require_membership_of_sid)
00155                 return NT_STATUS_NO_MEMORY;
00156 
00157         i = 0;
00158         search_location = group_sid;
00159 
00160         if (num_require_membership_of_sid > 1) {
00161 
00162                 /* Allocate the maximum possible size */
00163                 single_group_sid = TALLOC(mem_ctx, group_sid_length);
00164                 if (!single_group_sid)
00165                         return NT_STATUS_NO_MEMORY;
00166 
00167                 while ( (comma = strstr(search_location, ",")) != NULL ) {
00168 
00169                         strncpy(single_group_sid, search_location, comma - search_location);
00170                         single_group_sid[comma - search_location] = 0;
00171 
00172                         if (!string_to_sid(&require_membership_of_sid[i++], single_group_sid)) {
00173                                 DEBUG(0, ("check_info3_in_group: could not parse %s as a SID!", 
00174                                           single_group_sid));
00175                         
00176                                 return NT_STATUS_INVALID_PARAMETER;
00177                         }
00178 
00179                         search_location = comma + 1;
00180                 }
00181         }
00182 
00183         if (!string_to_sid(&require_membership_of_sid[i++], search_location)) {
00184                 DEBUG(0, ("check_info3_in_group: could not parse %s as a SID!", 
00185                           search_location));
00186 
00187                 return NT_STATUS_INVALID_PARAMETER;
00188         }
00189 
00190         all_sids = TALLOC_ARRAY(mem_ctx, DOM_SID, num_all_sids);
00191         if (!all_sids)
00192                 return NT_STATUS_NO_MEMORY;
00193 
00194         /* and create (by appending rids) the 'domain' sids */
00195         
00196         sid_copy(&all_sids[0], &(info3->dom_sid.sid));
00197         
00198         if (!sid_append_rid(&all_sids[0], info3->user_rid)) {
00199                 DEBUG(3,("could not append user's primary RID 0x%x\n",
00200                          info3->user_rid));                     
00201                 
00202                 return NT_STATUS_INVALID_PARAMETER;
00203         }
00204         j++;
00205 
00206         sid_copy(&all_sids[1], &(info3->dom_sid.sid));
00207                 
00208         if (!sid_append_rid(&all_sids[1], info3->group_rid)) {
00209                 DEBUG(3,("could not append additional group rid 0x%x\n",
00210                          info3->group_rid));                    
00211                 
00212                 return NT_STATUS_INVALID_PARAMETER;
00213         }
00214         j++;    
00215 
00216         for (i = 0; i < info3->num_groups2; i++) {
00217         
00218                 sid_copy(&all_sids[j], &(info3->dom_sid.sid));
00219                 
00220                 if (!sid_append_rid(&all_sids[j], info3->gids[i].g_rid)) {
00221                         DEBUG(3,("could not append additional group rid 0x%x\n",
00222                                 info3->gids[i].g_rid));                 
00223                                 
00224                         return NT_STATUS_INVALID_PARAMETER;
00225                 }
00226                 j++;
00227         }
00228 
00229         /* Copy 'other' sids.  We need to do sid filtering here to
00230            prevent possible elevation of privileges.  See:
00231 
00232            http://www.microsoft.com/windows2000/techinfo/administration/security/sidfilter.asp
00233          */
00234 
00235         for (i = 0; i < info3->num_other_sids; i++) {
00236                 sid_copy(&all_sids[info3->num_groups2 + i + 2],
00237                          &info3->other_sids[i].sid);
00238                 j++;
00239         }
00240 
00241         for (i = 0; i < j; i++) {
00242                 fstring sid1, sid2;
00243                 DEBUG(10, ("User has SID: %s\n", 
00244                            sid_to_string(sid1, &all_sids[i])));
00245                 for (k = 0; k < num_require_membership_of_sid; k++) {
00246                         if (sid_equal(&require_membership_of_sid[k], &all_sids[i])) {
00247                                 DEBUG(10, ("SID %s matches %s - user permitted to authenticate!\n", 
00248                                            sid_to_string(sid1, &require_membership_of_sid[k]), sid_to_string(sid2, &all_sids[i])));
00249                                 return NT_STATUS_OK;
00250                         }
00251                 }
00252         }
00253         
00254         /* Do not distinguish this error from a wrong username/pw */
00255 
00256         return NT_STATUS_LOGON_FAILURE;
00257 }
00258 
00259 struct winbindd_domain *find_auth_domain(struct winbindd_cli_state *state, 
00260                                         const char *domain_name)
00261 {
00262         struct winbindd_domain *domain;
00263 
00264         if (IS_DC) {
00265                 domain = find_domain_from_name_noinit(domain_name);
00266                 if (domain == NULL) {
00267                         DEBUG(3, ("Authentication for domain [%s] refused"
00268                                   "as it is not a trusted domain\n", 
00269                                   domain_name));
00270                 }
00271                 return domain;
00272         }
00273 
00274         if (is_myname(domain_name)) {
00275                 DEBUG(3, ("Authentication for domain %s (local domain "
00276                           "to this server) not supported at this "
00277                           "stage\n", domain_name));
00278                 return NULL;
00279         }
00280 
00281         /* we can auth against trusted domains */
00282         if (state->request.flags & WBFLAG_PAM_CONTACT_TRUSTDOM) {
00283                 domain = find_domain_from_name_noinit(domain_name);
00284                 if (domain == NULL) {
00285                         DEBUG(3, ("Authentication for domain [%s] skipped " 
00286                                   "as it is not a trusted domain\n", 
00287                                   domain_name));
00288                 } else {
00289                         return domain;
00290                 } 
00291         }
00292 
00293         return find_our_domain();
00294 }
00295 
00296 static void set_auth_errors(struct winbindd_response *resp, NTSTATUS result)
00297 {
00298         resp->data.auth.nt_status = NT_STATUS_V(result);
00299         fstrcpy(resp->data.auth.nt_status_string, nt_errstr(result));
00300 
00301         /* we might have given a more useful error above */
00302         if (*resp->data.auth.error_string == '\0') 
00303                 fstrcpy(resp->data.auth.error_string,
00304                         get_friendly_nt_error_msg(result));
00305         resp->data.auth.pam_error = nt_status_to_pam(result);
00306 }
00307 
00308 static NTSTATUS fillup_password_policy(struct winbindd_domain *domain,
00309                                        struct winbindd_cli_state *state)
00310 {
00311         struct winbindd_methods *methods;
00312         NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
00313         SAM_UNK_INFO_1 password_policy;
00314 
00315         methods = domain->methods;
00316 
00317         status = methods->password_policy(domain, state->mem_ctx, &password_policy);
00318         if (NT_STATUS_IS_ERR(status)) {
00319                 return status;
00320         }
00321 
00322         state->response.data.auth.policy.min_length_password =
00323                 password_policy.min_length_password;
00324         state->response.data.auth.policy.password_history =
00325                 password_policy.password_history;
00326         state->response.data.auth.policy.password_properties =
00327                 password_policy.password_properties;
00328         state->response.data.auth.policy.expire =
00329                 nt_time_to_unix_abs(&(password_policy.expire));
00330         state->response.data.auth.policy.min_passwordage = 
00331                 nt_time_to_unix_abs(&(password_policy.min_passwordage));
00332 
00333         return NT_STATUS_OK;
00334 }
00335 
00336 static NTSTATUS get_max_bad_attempts_from_lockout_policy(struct winbindd_domain *domain, 
00337                                                          TALLOC_CTX *mem_ctx, 
00338                                                          uint16 *max_allowed_bad_attempts)
00339 {
00340         struct winbindd_methods *methods;
00341         NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
00342         SAM_UNK_INFO_12 lockout_policy;
00343 
00344         *max_allowed_bad_attempts = 0;
00345 
00346         methods = domain->methods;
00347 
00348         status = methods->lockout_policy(domain, mem_ctx, &lockout_policy);
00349         if (NT_STATUS_IS_ERR(status)) {
00350                 return status;
00351         }
00352 
00353         *max_allowed_bad_attempts = lockout_policy.bad_attempt_lockout;
00354 
00355         return NT_STATUS_OK;
00356 }
00357 
00358 static NTSTATUS get_pwd_properties(struct winbindd_domain *domain, 
00359                                    TALLOC_CTX *mem_ctx, 
00360                                    uint32 *password_properties)
00361 {
00362         struct winbindd_methods *methods;
00363         NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
00364         SAM_UNK_INFO_1 password_policy;
00365 
00366         *password_properties = 0;
00367 
00368         methods = domain->methods;
00369 
00370         status = methods->password_policy(domain, mem_ctx, &password_policy);
00371         if (NT_STATUS_IS_ERR(status)) {
00372                 return status;
00373         }
00374 
00375         *password_properties = password_policy.password_properties;
00376 
00377         return NT_STATUS_OK;
00378 }
00379 
00380 #ifdef HAVE_KRB5
00381 
00382 static const char *generate_krb5_ccache(TALLOC_CTX *mem_ctx, 
00383                                         const char *type,
00384                                         uid_t uid,
00385                                         BOOL *internal_ccache)
00386 {
00387         /* accept FILE and WRFILE as krb5_cc_type from the client and then
00388          * build the full ccname string based on the user's uid here -
00389          * Guenther*/
00390 
00391         const char *gen_cc = NULL;
00392 
00393         *internal_ccache = True;
00394 
00395         if (uid == -1) {
00396                 goto memory_ccache;
00397         }
00398 
00399         if (!type || type[0] == '\0') {
00400                 goto memory_ccache;
00401         }
00402 
00403         if (strequal(type, "FILE")) {
00404                 gen_cc = talloc_asprintf(mem_ctx, "FILE:/tmp/krb5cc_%d", uid);
00405         } else if (strequal(type, "WRFILE")) {
00406                 gen_cc = talloc_asprintf(mem_ctx, "WRFILE:/tmp/krb5cc_%d", uid);
00407         } else {
00408                 DEBUG(10,("we don't allow to set a %s type ccache\n", type));
00409                 goto memory_ccache;
00410         }
00411 
00412         *internal_ccache = False;
00413         goto done;
00414 
00415   memory_ccache:
00416         gen_cc = talloc_strdup(mem_ctx, "MEMORY:winbindd_pam_ccache");
00417 
00418   done:
00419         if (gen_cc == NULL) {
00420                 DEBUG(0,("out of memory\n"));
00421                 return NULL;
00422         }
00423 
00424         DEBUG(10,("using ccache: %s %s\n", gen_cc, *internal_ccache ? "(internal)":""));
00425 
00426         return gen_cc;
00427 }
00428 
00429 static void setup_return_cc_name(struct winbindd_cli_state *state, const char *cc)
00430 {
00431         const char *type = state->request.data.auth.krb5_cc_type;
00432 
00433         state->response.data.auth.krb5ccname[0] = '\0';
00434 
00435         if (type[0] == '\0') {
00436                 return;
00437         }
00438 
00439         if (!strequal(type, "FILE") &&
00440             !strequal(type, "WRFILE")) {
00441                 DEBUG(10,("won't return krbccname for a %s type ccache\n", 
00442                         type));
00443                 return;
00444         }
00445         
00446         fstrcpy(state->response.data.auth.krb5ccname, cc);
00447 }
00448 
00449 #endif
00450 
00451 static uid_t get_uid_from_state(struct winbindd_cli_state *state)
00452 {
00453         uid_t uid = -1;
00454 
00455         uid = state->request.data.auth.uid;
00456 
00457         if (uid < 0) {
00458                 DEBUG(1,("invalid uid: '%d'\n", uid));
00459                 return -1;
00460         }
00461         return uid;
00462 }
00463 
00464 /**********************************************************************
00465  Authenticate a user with a clear text password using Kerberos and fill up
00466  ccache if required
00467  **********************************************************************/
00468 
00469 static NTSTATUS winbindd_raw_kerberos_login(struct winbindd_domain *domain,
00470                                             struct winbindd_cli_state *state,
00471                                             NET_USER_INFO_3 **info3)
00472 {
00473 #ifdef HAVE_KRB5
00474         NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
00475         krb5_error_code krb5_ret;
00476         DATA_BLOB tkt, session_key_krb5;
00477         DATA_BLOB ap_rep, session_key;
00478         PAC_DATA *pac_data = NULL;
00479         PAC_LOGON_INFO *logon_info = NULL;
00480         char *client_princ = NULL;
00481         char *client_princ_out = NULL;
00482         char *local_service = NULL;
00483         const char *cc = NULL;
00484         const char *principal_s = NULL;
00485         const char *service = NULL;
00486         char *realm = NULL;
00487         fstring name_domain, name_user;
00488         time_t ticket_lifetime = 0;
00489         time_t renewal_until = 0;
00490         uid_t uid = -1;
00491         ADS_STRUCT *ads;
00492         time_t time_offset = 0;
00493         BOOL internal_ccache = True;
00494 
00495         ZERO_STRUCT(session_key);
00496         ZERO_STRUCT(session_key_krb5);
00497         ZERO_STRUCT(tkt);
00498         ZERO_STRUCT(ap_rep);
00499 
00500         ZERO_STRUCTP(info3);
00501 
00502         *info3 = NULL;
00503         
00504         /* 1st step: 
00505          * prepare a krb5_cc_cache string for the user */
00506 
00507         uid = get_uid_from_state(state);
00508         if (uid == -1) {
00509                 DEBUG(0,("no valid uid\n"));
00510         }
00511 
00512         cc = generate_krb5_ccache(state->mem_ctx,
00513                                   state->request.data.auth.krb5_cc_type,
00514                                   state->request.data.auth.uid, 
00515                                   &internal_ccache);
00516         if (cc == NULL) {
00517                 return NT_STATUS_NO_MEMORY;
00518         }
00519 
00520 
00521         /* 2nd step: 
00522          * get kerberos properties */
00523         
00524         if (domain->private_data) {
00525                 ads = (ADS_STRUCT *)domain->private_data;
00526                 time_offset = ads->auth.time_offset; 
00527         }
00528 
00529 
00530         /* 3rd step: 
00531          * do kerberos auth and setup ccache as the user */
00532 
00533         parse_domain_user(state->request.data.auth.user, name_domain, name_user);
00534 
00535         realm = domain->alt_name;
00536         strupper_m(realm);
00537         
00538         principal_s = talloc_asprintf(state->mem_ctx, "%s@%s", name_user, realm); 
00539         if (principal_s == NULL) {
00540                 return NT_STATUS_NO_MEMORY;
00541         }
00542 
00543         service = talloc_asprintf(state->mem_ctx, "%s/%s@%s", KRB5_TGS_NAME, realm, realm);
00544         if (service == NULL) {
00545                 return NT_STATUS_NO_MEMORY;
00546         }
00547 
00548         /* if this is a user ccache, we need to act as the user to let the krb5
00549          * library handle the chown, etc. */
00550 
00551         /************************ NON-ROOT **********************/
00552 
00553         if (!internal_ccache) {
00554 
00555                 set_effective_uid(uid);
00556                 DEBUG(10,("winbindd_raw_kerberos_login: uid is %d\n", uid));
00557         }
00558 
00559         krb5_ret = kerberos_kinit_password_ext(principal_s, 
00560                                                state->request.data.auth.pass, 
00561                                                time_offset, 
00562                                                &ticket_lifetime,
00563                                                &renewal_until,
00564                                                cc, 
00565                                                True,
00566                                                True,
00567                                                WINBINDD_PAM_AUTH_KRB5_RENEW_TIME);
00568 
00569         if (krb5_ret) {
00570                 DEBUG(1,("winbindd_raw_kerberos_login: kinit failed for '%s' with: %s (%d)\n", 
00571                         principal_s, error_message(krb5_ret), krb5_ret));
00572                 result = krb5_to_nt_status(krb5_ret);
00573                 goto failed;
00574         }
00575 
00576         /* does http_timestring use heimdals libroken strftime?? - Guenther */
00577         DEBUG(10,("got TGT for %s in %s (valid until: %s (%d), renewable till: %s (%d))\n", 
00578                 principal_s, cc, 
00579                 http_timestring(ticket_lifetime), (int)ticket_lifetime, 
00580                 http_timestring(renewal_until), (int)renewal_until));
00581 
00582         /* we cannot continue with krb5 when UF_DONT_REQUIRE_PREAUTH is set,
00583          * in that case fallback to NTLM - gd */ 
00584 
00585         if ((ticket_lifetime == 0) && (renewal_until == 0)) {
00586                 result = NT_STATUS_INVALID_LOGON_TYPE;
00587                 goto failed;
00588         }
00589 
00590         client_princ = talloc_strdup(state->mem_ctx, global_myname());
00591         if (client_princ == NULL) {
00592                 result = NT_STATUS_NO_MEMORY;
00593                 goto failed;
00594         }
00595         strlower_m(client_princ);
00596 
00597         local_service = talloc_asprintf(state->mem_ctx, "%s$@%s", client_princ, lp_realm());
00598         if (local_service == NULL) {
00599                 DEBUG(0,("winbindd_raw_kerberos_login: out of memory\n"));
00600                 result = NT_STATUS_NO_MEMORY;
00601                 goto failed;
00602         }
00603 
00604         krb5_ret = cli_krb5_get_ticket(local_service, 
00605                                        time_offset, 
00606                                        &tkt, 
00607                                        &session_key_krb5, 
00608                                        0, 
00609                                        cc,
00610                                        NULL);
00611         if (krb5_ret) {
00612                 DEBUG(1,("winbindd_raw_kerberos_login: failed to get ticket for %s: %s\n", 
00613                         local_service, error_message(krb5_ret)));
00614                 result = krb5_to_nt_status(krb5_ret);
00615                 goto failed;
00616         }
00617 
00618         if (!internal_ccache) {
00619                 gain_root_privilege();
00620         }
00621 
00622         /************************ NON-ROOT **********************/
00623 
00624         result = ads_verify_ticket(state->mem_ctx, 
00625                                    lp_realm(), 
00626                                    time_offset,
00627                                    &tkt, 
00628                                    &client_princ_out, 
00629                                    &pac_data, 
00630                                    &ap_rep, 
00631                                    &session_key);       
00632         if (!NT_STATUS_IS_OK(result)) {
00633                 DEBUG(0,("winbindd_raw_kerberos_login: ads_verify_ticket failed: %s\n", 
00634                         nt_errstr(result)));
00635                 goto failed;
00636         }
00637 
00638         if (!pac_data) {
00639                 DEBUG(3,("winbindd_raw_kerberos_login: no pac data\n"));
00640                 result = NT_STATUS_INVALID_PARAMETER;
00641                 goto failed;
00642         }
00643                         
00644         logon_info = get_logon_info_from_pac(pac_data);
00645         if (logon_info == NULL) {
00646                 DEBUG(1,("winbindd_raw_kerberos_login: no logon info\n"));
00647                 result = NT_STATUS_INVALID_PARAMETER;
00648                 goto failed;
00649         }
00650 
00651         DEBUG(10,("winbindd_raw_kerberos_login: winbindd validated ticket of %s\n", 
00652                 local_service));
00653 
00654 
00655         /* last step: 
00656          * put results together */
00657 
00658         *info3 = &logon_info->info3;
00659 
00660         /* if we had a user's ccache then return that string for the pam
00661          * environment */
00662 
00663         if (!internal_ccache) {
00664                 
00665                 setup_return_cc_name(state, cc);
00666 
00667                 result = add_ccache_to_list(principal_s,
00668                                             cc,
00669                                             service,
00670                                             state->request.data.auth.user,
00671                                             realm,
00672                                             uid,
00673                                             time(NULL),
00674                                             ticket_lifetime,
00675                                             renewal_until, 
00676                                             False);
00677 
00678                 if (!NT_STATUS_IS_OK(result)) {
00679                         DEBUG(10,("winbindd_raw_kerberos_login: failed to add ccache to list: %s\n", 
00680                                 nt_errstr(result)));
00681                 }
00682         } else {
00683 
00684                 /* need to delete the memory cred cache, it is not used anymore */
00685 
00686                 krb5_ret = ads_kdestroy(cc);
00687                 if (krb5_ret) {
00688                         DEBUG(3,("winbindd_raw_kerberos_login: "
00689                                  "could not destroy krb5 credential cache: "
00690                                  "%s\n", error_message(krb5_ret)));
00691                 }
00692 
00693         }
00694 
00695         result = NT_STATUS_OK;
00696 
00697         goto done;
00698 
00699 failed:
00700 
00701         /* we could have created a new credential cache with a valid tgt in it
00702          * but we werent able to get or verify the service ticket for this
00703          * local host and therefor didn't get the PAC, we need to remove that
00704          * cache entirely now */
00705 
00706         krb5_ret = ads_kdestroy(cc);
00707         if (krb5_ret) {
00708                 DEBUG(3,("winbindd_raw_kerberos_login: "
00709                          "could not destroy krb5 credential cache: "
00710                          "%s\n", error_message(krb5_ret)));
00711         }
00712 
00713         if (!NT_STATUS_IS_OK(remove_ccache(state->request.data.auth.user))) {
00714                 DEBUG(3,("winbindd_raw_kerberos_login: "
00715                           "could not remove ccache for user %s\n",
00716                         state->request.data.auth.user));
00717         }
00718 
00719 done:
00720         data_blob_free(&session_key);
00721         data_blob_free(&session_key_krb5);
00722         data_blob_free(&ap_rep);
00723         data_blob_free(&tkt);
00724 
00725         SAFE_FREE(client_princ_out);
00726 
00727         if (!internal_ccache) {
00728                 gain_root_privilege();
00729         }
00730 
00731         return result;
00732 #else 
00733         return NT_STATUS_NOT_SUPPORTED;
00734 #endif /* HAVE_KRB5 */
00735 }
00736 
00737 void winbindd_pam_auth(struct winbindd_cli_state *state)
00738 {
00739         struct winbindd_domain *domain;
00740         fstring name_domain, name_user;
00741 
00742         /* Ensure null termination */
00743         state->request.data.auth.user
00744                 [sizeof(state->request.data.auth.user)-1]='\0';
00745 
00746         /* Ensure null termination */
00747         state->request.data.auth.pass
00748                 [sizeof(state->request.data.auth.pass)-1]='\0';
00749 
00750         DEBUG(3, ("[%5lu]: pam auth %s\n", (unsigned long)state->pid,
00751                   state->request.data.auth.user));
00752 
00753         /* Parse domain and username */
00754         
00755         ws_name_return( state->request.data.auth.user, WB_REPLACE_CHAR );
00756 
00757         if (!canonicalize_username(state->request.data.auth.user,
00758                                name_domain, name_user)) {
00759                 set_auth_errors(&state->response, NT_STATUS_NO_SUCH_USER);
00760                 DEBUG(5, ("Plain text authentication for %s returned %s "
00761                           "(PAM: %d)\n",
00762                           state->request.data.auth.user, 
00763                           state->response.data.auth.nt_status_string,
00764                           state->response.data.auth.pam_error));
00765                 request_error(state);
00766                 return;
00767         }
00768 
00769         domain = find_auth_domain(state, name_domain);
00770 
00771         if (domain == NULL) {
00772                 set_auth_errors(&state->response, NT_STATUS_NO_SUCH_USER);
00773                 DEBUG(5, ("Plain text authentication for %s returned %s "
00774                           "(PAM: %d)\n",
00775                           state->request.data.auth.user, 
00776                           state->response.data.auth.nt_status_string,
00777                           state->response.data.auth.pam_error));
00778                 request_error(state);
00779                 return;
00780         }
00781 
00782         sendto_domain(state, domain);
00783 }
00784 
00785 NTSTATUS winbindd_dual_pam_auth_cached(struct winbindd_domain *domain,
00786                                        struct winbindd_cli_state *state,
00787                                        NET_USER_INFO_3 **info3)
00788 {
00789         NTSTATUS result = NT_STATUS_LOGON_FAILURE;
00790         uint16 max_allowed_bad_attempts; 
00791         fstring name_domain, name_user;
00792         DOM_SID sid;
00793         enum lsa_SidType type;
00794         uchar new_nt_pass[NT_HASH_LEN];
00795         const uint8 *cached_nt_pass;
00796         const uint8 *cached_salt;
00797         NET_USER_INFO_3 *my_info3;
00798         time_t kickoff_time, must_change_time;
00799         BOOL password_good = False;
00800 
00801         *info3 = NULL;
00802 
00803         ZERO_STRUCTP(info3);
00804 
00805         DEBUG(10,("winbindd_dual_pam_auth_cached\n"));
00806 
00807         /* Parse domain and username */
00808         
00809         parse_domain_user(state->request.data.auth.user, name_domain, name_user);
00810 
00811 
00812         if (!lookup_cached_name(state->mem_ctx,
00813                                 name_domain,
00814                                 name_user,
00815                                 &sid,
00816                                 &type)) {
00817                 DEBUG(10,("winbindd_dual_pam_auth_cached: no such user in the cache\n"));
00818                 return NT_STATUS_NO_SUCH_USER;
00819         }
00820 
00821         if (type != SID_NAME_USER) {
00822                 DEBUG(10,("winbindd_dual_pam_auth_cached: not a user (%s)\n", sid_type_lookup(type)));
00823                 return NT_STATUS_LOGON_FAILURE;
00824         }
00825 
00826         result = winbindd_get_creds(domain, 
00827                                     state->mem_ctx, 
00828                                     &sid, 
00829                                     &my_info3, 
00830                                     &cached_nt_pass,
00831                                     &cached_salt);
00832         if (!NT_STATUS_IS_OK(result)) {
00833                 DEBUG(10,("winbindd_dual_pam_auth_cached: failed to get creds: %s\n", nt_errstr(result)));
00834                 return result;
00835         }
00836 
00837         *info3 = my_info3;
00838 
00839         E_md4hash(state->request.data.auth.pass, new_nt_pass);
00840 
00841 #if DEBUG_PASSWORD
00842         dump_data(100, (const char *)new_nt_pass, NT_HASH_LEN);
00843         dump_data(100, (const char *)cached_nt_pass, NT_HASH_LEN);
00844         if (cached_salt) {
00845                 dump_data(100, (const char *)cached_salt, NT_HASH_LEN);
00846         }
00847 #endif
00848 
00849         if (cached_salt) {
00850                 /* In this case we didn't store the nt_hash itself,
00851                    but the MD5 combination of salt + nt_hash. */
00852                 uchar salted_hash[NT_HASH_LEN];
00853                 E_md5hash(cached_salt, new_nt_pass, salted_hash);
00854 
00855                 password_good = (memcmp(cached_nt_pass, salted_hash, NT_HASH_LEN) == 0) ?
00856                         True : False;
00857         } else {
00858                 /* Old cached cred - direct store of nt_hash (bad bad bad !). */
00859                 password_good = (memcmp(cached_nt_pass, new_nt_pass, NT_HASH_LEN) == 0) ?
00860                         True : False;
00861         }
00862 
00863         if (password_good) {
00864 
00865                 /* User *DOES* know the password, update logon_time and reset
00866                  * bad_pw_count */
00867         
00868                 my_info3->user_flgs |= LOGON_CACHED_ACCOUNT;
00869         
00870                 if (my_info3->acct_flags & ACB_AUTOLOCK) {
00871                         return NT_STATUS_ACCOUNT_LOCKED_OUT;
00872                 }
00873         
00874                 if (my_info3->acct_flags & ACB_DISABLED) {
00875                         return NT_STATUS_ACCOUNT_DISABLED;
00876                 }
00877         
00878                 if (my_info3->acct_flags & ACB_WSTRUST) {
00879                         return NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT;
00880                 }
00881         
00882                 if (my_info3->acct_flags & ACB_SVRTRUST) {
00883                         return NT_STATUS_NOLOGON_SERVER_TRUST_ACCOUNT;
00884                 }
00885         
00886                 if (my_info3->acct_flags & ACB_DOMTRUST) {
00887                         return NT_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT;
00888                 }
00889 
00890                 if (!(my_info3->acct_flags & ACB_NORMAL)) {
00891                         DEBUG(0,("winbindd_dual_pam_auth_cached: whats wrong with that one?: 0x%08x\n", 
00892                                 my_info3->acct_flags));
00893                         return NT_STATUS_LOGON_FAILURE;
00894                 }
00895 
00896                 kickoff_time = nt_time_to_unix(my_info3->kickoff_time);
00897                 if (kickoff_time != 0 && time(NULL) > kickoff_time) {
00898                         return NT_STATUS_ACCOUNT_EXPIRED;
00899                 }
00900 
00901                 must_change_time = nt_time_to_unix(my_info3->pass_must_change_time);
00902                 if (must_change_time != 0 && must_change_time < time(NULL)) {
00903                         /* we allow grace logons when the password has expired */
00904                         my_info3->user_flgs |= LOGON_GRACE_LOGON;
00905                         /* return NT_STATUS_PASSWORD_EXPIRED; */
00906                         goto success;
00907                 }
00908         
00909 #ifdef HAVE_KRB5
00910                 /* FIXME: what else points out that the remote domain is AD ? */
00911                 if (!strequal(domain->name, domain->alt_name) &&
00912                     (state->request.flags & WBFLAG_PAM_KRB5)) {
00913 
00914                         uid_t uid = -1;
00915                         const char *cc = NULL;
00916                         char *realm = NULL;
00917                         const char *principal_s = NULL;
00918                         const char *service = NULL;
00919                         BOOL internal_ccache = False;
00920 
00921                         uid = get_uid_from_state(state);
00922                         if (uid == -1) {
00923                                 DEBUG(0,("winbindd_dual_pam_auth_cached: invalid uid\n"));
00924                                 return NT_STATUS_INVALID_PARAMETER;
00925                         }
00926 
00927                         cc = generate_krb5_ccache(state->mem_ctx,
00928                                                 state->request.data.auth.krb5_cc_type,
00929                                                 state->request.data.auth.uid,
00930                                                 &internal_ccache);
00931                         if (cc == NULL) {
00932                                 return NT_STATUS_NO_MEMORY;
00933                         }
00934 
00935                         realm = domain->alt_name;
00936                         strupper_m(realm);
00937 
00938                         principal_s = talloc_asprintf(state->mem_ctx, "%s@%s", name_user, realm);
00939                         if (principal_s == NULL) {
00940                                 return NT_STATUS_NO_MEMORY;
00941                         }
00942 
00943                         service = talloc_asprintf(state->mem_ctx, "%s/%s@%s", KRB5_TGS_NAME, realm, realm);
00944                         if (service == NULL) {
00945                                 return NT_STATUS_NO_MEMORY;
00946                         }
00947 
00948                         if (!internal_ccache) {
00949 
00950                                 setup_return_cc_name(state, cc);
00951 
00952                                 result = add_ccache_to_list(principal_s,
00953                                                             cc,
00954                                                             service,
00955                                                             state->request.data.auth.user,
00956                                                             domain->alt_name,
00957                                                             uid,
00958                                                             time(NULL),
00959                                                             time(NULL) + lp_winbind_cache_time(),
00960                                                             time(NULL) + WINBINDD_PAM_AUTH_KRB5_RENEW_TIME,
00961                                                             True);
00962 
00963                                 if (!NT_STATUS_IS_OK(result)) {
00964                                         DEBUG(10,("winbindd_dual_pam_auth_cached: failed "
00965                                                 "to add ccache to list: %s\n",
00966                                                 nt_errstr(result)));
00967                                 }
00968                         }
00969                 }
00970 #endif /* HAVE_KRB5 */
00971  success:
00972                 /* FIXME: we possibly should handle logon hours as well (does xp when
00973                  * offline?) see auth/auth_sam.c:sam_account_ok for details */
00974 
00975                 unix_to_nt_time(&my_info3->logon_time, time(NULL));
00976                 my_info3->bad_pw_count = 0;
00977 
00978                 result = winbindd_update_creds_by_info3(domain,
00979                                                         state->mem_ctx,
00980                                                         state->request.data.auth.user,
00981                                                         state->request.data.auth.pass,
00982                                                         my_info3);
00983                 if (!NT_STATUS_IS_OK(result)) {
00984                         DEBUG(1,("winbindd_dual_pam_auth_cached: failed to update creds: %s\n",
00985                                 nt_errstr(result)));
00986                         return result;
00987                 }
00988 
00989                 return NT_STATUS_OK;
00990 
00991         }
00992 
00993         /* User does *NOT* know the correct password, modify info3 accordingly */
00994 
00995         /* failure of this is not critical */
00996         result = get_max_bad_attempts_from_lockout_policy(domain, state->mem_ctx, &max_allowed_bad_attempts);
00997         if (!NT_STATUS_IS_OK(result)) {
00998                 DEBUG(10,("winbindd_dual_pam_auth_cached: failed to get max_allowed_bad_attempts. "
00999                           "Won't be able to honour account lockout policies\n"));
01000         }
01001 
01002         /* increase counter */
01003         my_info3->bad_pw_count++;
01004 
01005         if (max_allowed_bad_attempts == 0) {
01006                 goto failed;
01007         }
01008 
01009         /* lockout user */
01010         if (my_info3->bad_pw_count >= max_allowed_bad_attempts) {
01011 
01012                 uint32 password_properties;
01013 
01014                 result = get_pwd_properties(domain, state->mem_ctx, &password_properties);
01015                 if (!NT_STATUS_IS_OK(result)) {
01016                         DEBUG(10,("winbindd_dual_pam_auth_cached: failed to get password properties.\n"));
01017                 }
01018 
01019                 if ((my_info3->user_rid != DOMAIN_USER_RID_ADMIN) || 
01020                     (password_properties & DOMAIN_LOCKOUT_ADMINS)) {
01021                         my_info3->acct_flags |= ACB_AUTOLOCK;
01022                 }
01023         }
01024 
01025 failed:
01026         result = winbindd_update_creds_by_info3(domain,
01027                                                 state->mem_ctx,
01028                                                 state->request.data.auth.user,
01029                                                 NULL,
01030                                                 my_info3);
01031 
01032         if (!NT_STATUS_IS_OK(result)) {
01033                 DEBUG(0,("winbindd_dual_pam_auth_cached: failed to update creds %s\n", 
01034                         nt_errstr(result)));
01035         }
01036 
01037         return NT_STATUS_LOGON_FAILURE;
01038 }
01039 
01040 NTSTATUS winbindd_dual_pam_auth_kerberos(struct winbindd_domain *domain,
01041                                          struct winbindd_cli_state *state, 
01042                                          NET_USER_INFO_3 **info3)
01043 {
01044         struct winbindd_domain *contact_domain;
01045         fstring name_domain, name_user;
01046         NTSTATUS result;
01047 
01048         DEBUG(10,("winbindd_dual_pam_auth_kerberos\n"));
01049         
01050         /* Parse domain and username */
01051         
01052         parse_domain_user(state->request.data.auth.user, name_domain, name_user);
01053 
01054         /* what domain should we contact? */
01055         
01056         if ( IS_DC ) {
01057                 if (!(contact_domain = find_domain_from_name(name_domain))) {
01058                         DEBUG(3, ("Authentication for domain for [%s] -> [%s]\\[%s] failed as %s is not a trusted domain\n", 
01059                                   state->request.data.auth.user, name_domain, name_user, name_domain)); 
01060                         result = NT_STATUS_NO_SUCH_USER;
01061                         goto done;
01062                 }
01063                 
01064         } else {
01065                 if (is_myname(name_domain)) {
01066                         DEBUG(3, ("Authentication for domain %s (local domain to this server) not supported at this stage\n", name_domain));
01067                         result =  NT_STATUS_NO_SUCH_USER;
01068                         goto done;
01069                 }
01070                 
01071                 contact_domain = find_domain_from_name(name_domain);
01072                 if (contact_domain == NULL) {
01073                         DEBUG(3, ("Authentication for domain for [%s] -> [%s]\\[%s] failed as %s is not a trusted domain\n", 
01074                                   state->request.data.auth.user, name_domain, name_user, name_domain)); 
01075 
01076                         contact_domain = find_our_domain();
01077                 }
01078         }
01079 
01080         if (contact_domain->initialized && 
01081             contact_domain->active_directory) {
01082                 goto try_login;
01083         }
01084 
01085         if (!contact_domain->initialized) {
01086                 init_dc_connection(contact_domain);
01087         }
01088 
01089         if (!contact_domain->active_directory) {
01090                 DEBUG(3,("krb5 auth requested but domain is not Active Directory\n"));
01091                 return NT_STATUS_INVALID_LOGON_TYPE;
01092         }
01093 try_login:
01094         result = winbindd_raw_kerberos_login(contact_domain, state, info3);
01095 done:
01096         return result;
01097 }
01098 
01099 NTSTATUS winbindd_dual_pam_auth_samlogon(struct winbindd_domain *domain,
01100                                          struct winbindd_cli_state *state,
01101                                          NET_USER_INFO_3 **info3)
01102 {
01103 
01104         struct rpc_pipe_client *netlogon_pipe;
01105         uchar chal[8];
01106         DATA_BLOB lm_resp;
01107         DATA_BLOB nt_resp;
01108         int attempts = 0;
01109         unsigned char local_lm_response[24];
01110         unsigned char local_nt_response[24];
01111         struct winbindd_domain *contact_domain;
01112         fstring name_domain, name_user;
01113         BOOL retry;
01114         NTSTATUS result;
01115         NET_USER_INFO_3 *my_info3;
01116 
01117         ZERO_STRUCTP(info3);
01118 
01119         *info3 = NULL;
01120 
01121         my_info3 = TALLOC_ZERO_P(state->mem_ctx, NET_USER_INFO_3);
01122         if (my_info3 == NULL) {
01123                 return NT_STATUS_NO_MEMORY;
01124         }
01125 
01126 
01127         DEBUG(10,("winbindd_dual_pam_auth_samlogon\n"));
01128         
01129         /* Parse domain and username */
01130         
01131         parse_domain_user(state->request.data.auth.user, name_domain, name_user);
01132 
01133         /* do password magic */
01134         
01135 
01136         generate_random_buffer(chal, 8);
01137         if (lp_client_ntlmv2_auth()) {
01138                 DATA_BLOB server_chal;
01139                 DATA_BLOB names_blob;
01140                 DATA_BLOB nt_response;
01141                 DATA_BLOB lm_response;
01142                 server_chal = data_blob_talloc(state->mem_ctx, chal, 8); 
01143                 
01144                 /* note that the 'workgroup' here is a best guess - we don't know
01145                    the server's domain at this point.  The 'server name' is also
01146                    dodgy... 
01147                 */
01148                 names_blob = NTLMv2_generate_names_blob(global_myname(), lp_workgroup());
01149                 
01150                 if (!SMBNTLMv2encrypt(name_user, name_domain, 
01151                                       state->request.data.auth.pass, 
01152                                       &server_chal, 
01153                                       &names_blob,
01154                                       &lm_response, &nt_response, NULL)) {
01155                         data_blob_free(&names_blob);
01156                         data_blob_free(&server_chal);
01157                         DEBUG(0, ("winbindd_pam_auth: SMBNTLMv2encrypt() failed!\n"));
01158                         result = NT_STATUS_NO_MEMORY;
01159                         goto done;
01160                 }
01161                 data_blob_free(&names_blob);
01162                 data_blob_free(&server_chal);
01163                 lm_resp = data_blob_talloc(state->mem_ctx, lm_response.data,
01164                                            lm_response.length);
01165                 nt_resp = data_blob_talloc(state->mem_ctx, nt_response.data,
01166                                            nt_response.length);
01167                 data_blob_free(&lm_response);
01168                 data_blob_free(&nt_response);
01169 
01170         } else {
01171                 if (lp_client_lanman_auth() 
01172                     && SMBencrypt(state->request.data.auth.pass, 
01173                                   chal, 
01174                                   local_lm_response)) {
01175                         lm_resp = data_blob_talloc(state->mem_ctx, 
01176                                                    local_lm_response, 
01177                                                    sizeof(local_lm_response));
01178                 } else {
01179                         lm_resp = data_blob(NULL, 0);
01180                 }
01181                 SMBNTencrypt(state->request.data.auth.pass, 
01182                              chal,
01183                              local_nt_response);
01184 
01185                 nt_resp = data_blob_talloc(state->mem_ctx, 
01186                                            local_nt_response, 
01187                                            sizeof(local_nt_response));
01188         }
01189         
01190         /* what domain should we contact? */
01191         
01192         if ( IS_DC ) {
01193                 if (!(contact_domain = find_domain_from_name(name_domain))) {
01194                         DEBUG(3, ("Authentication for domain for [%s] -> [%s]\\[%s] failed as %s is not a trusted domain\n", 
01195                                   state->request.data.auth.user, name_domain, name_user, name_domain)); 
01196                         result = NT_STATUS_NO_SUCH_USER;
01197                         goto done;
01198                 }
01199                 
01200         } else {
01201                 if (is_myname(name_domain)) {
01202                         DEBUG(3, ("Authentication for domain %s (local domain to this server) not supported at this stage\n", name_domain));
01203                         result =  NT_STATUS_NO_SUCH_USER;
01204                         goto done;
01205                 }
01206 
01207                 contact_domain = find_our_domain();
01208         }
01209 
01210         /* check authentication loop */
01211 
01212         do {
01213 
01214                 ZERO_STRUCTP(my_info3);
01215                 retry = False;
01216 
01217                 result = cm_connect_netlogon(contact_domain, &netlogon_pipe);
01218 
01219                 if (!NT_STATUS_IS_OK(result)) {
01220                         DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
01221                         goto done;
01222                 }
01223 
01224                 result = rpccli_netlogon_sam_network_logon(netlogon_pipe,
01225                                                            state->mem_ctx,
01226                                                            0,
01227                                                            contact_domain->dcname, /* server name */
01228                                                            name_user,              /* user name */
01229                                                            name_domain,            /* target domain */
01230                                                            global_myname(),        /* workstation */
01231                                                            chal,
01232                                                            lm_resp,
01233                                                            nt_resp,
01234                                                            my_info3);
01235                 attempts += 1;
01236 
01237                 /* We have to try a second time as cm_connect_netlogon
01238                    might not yet have noticed that the DC has killed
01239                    our connection. */
01240 
01241                 if (NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL)) {
01242                         retry = True;
01243                         continue;
01244                 }
01245                 
01246                 /* if we get access denied, a possible cause was that we had
01247                    and open connection to the DC, but someone changed our
01248                    machine account password out from underneath us using 'net
01249                    rpc changetrustpw' */
01250                    
01251                 if ( NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED) ) {
01252                         DEBUG(3,("winbindd_pam_auth: sam_logon returned "
01253                                  "ACCESS_DENIED.  Maybe the trust account "
01254                                 "password was changed and we didn't know it. "
01255                                  "Killing connections to domain %s\n",
01256                                 name_domain));
01257                         invalidate_cm_connection(&contact_domain->conn);
01258                         retry = True;
01259                 } 
01260                 
01261         } while ( (attempts < 2) && retry );
01262 
01263         /* handle the case where a NT4 DC does not fill in the acct_flags in
01264          * the samlogon reply info3. When accurate info3 is required by the
01265          * caller, we look up the account flags ourselve - gd */
01266 
01267         if ((state->request.flags & WBFLAG_PAM_INFO3_TEXT) && 
01268             (my_info3->acct_flags == 0) && NT_STATUS_IS_OK(result)) {
01269 
01270                 struct rpc_pipe_client *samr_pipe;
01271                 POLICY_HND samr_domain_handle, user_pol;
01272                 SAM_USERINFO_CTR *user_ctr;
01273                 NTSTATUS status_tmp;
01274                 uint32 acct_flags;
01275 
01276                 ZERO_STRUCT(user_ctr);
01277 
01278                 status_tmp = cm_connect_sam(contact_domain, state->mem_ctx, 
01279                                             &samr_pipe, &samr_domain_handle);
01280 
01281                 if (!NT_STATUS_IS_OK(status_tmp)) {
01282                         DEBUG(3, ("could not open handle to SAMR pipe: %s\n", 
01283                                 nt_errstr(status_tmp)));
01284                         goto done;
01285                 }
01286 
01287                 status_tmp = rpccli_samr_open_user(samr_pipe, state->mem_ctx, 
01288                                                    &samr_domain_handle,
01289                                                    MAXIMUM_ALLOWED_ACCESS,
01290                                                    my_info3->user_rid, &user_pol);
01291 
01292                 if (!NT_STATUS_IS_OK(status_tmp)) {
01293                         DEBUG(3, ("could not open user handle on SAMR pipe: %s\n",
01294                                 nt_errstr(status_tmp)));
01295                         goto done;
01296                 }
01297 
01298                 status_tmp = rpccli_samr_query_userinfo(samr_pipe, state->mem_ctx, 
01299                                                         &user_pol, 16, &user_ctr);
01300 
01301                 if (!NT_STATUS_IS_OK(status_tmp)) {
01302                         DEBUG(3, ("could not query user info on SAMR pipe: %s\n",
01303                                 nt_errstr(status_tmp)));
01304                         rpccli_samr_close(samr_pipe, state->mem_ctx, &user_pol);
01305                         goto done;
01306                 }
01307 
01308                 acct_flags = user_ctr->info.id16->acb_info;
01309 
01310                 if (acct_flags == 0) {
01311                         rpccli_samr_close(samr_pipe, state->mem_ctx, &user_pol);
01312                         goto done;
01313                 }
01314 
01315                 my_info3->acct_flags = acct_flags;
01316 
01317                 DEBUG(10,("successfully retrieved acct_flags 0x%x\n", acct_flags));
01318 
01319                 rpccli_samr_close(samr_pipe, state->mem_ctx, &user_pol);
01320         }
01321 
01322         *info3 = my_info3;
01323 done:
01324         return result;
01325 }
01326 
01327 enum winbindd_result winbindd_dual_pam_auth(struct winbindd_domain *domain,
01328                                             struct winbindd_cli_state *state) 
01329 {
01330         NTSTATUS result = NT_STATUS_LOGON_FAILURE;
01331         fstring name_domain, name_user;
01332         NET_USER_INFO_3 *info3 = NULL;
01333         
01334         /* Ensure null termination */
01335         state->request.data.auth.user[sizeof(state->request.data.auth.user)-1]='\0';
01336 
01337         /* Ensure null termination */
01338         state->request.data.auth.pass[sizeof(state->request.data.auth.pass)-1]='\0';
01339 
01340         DEBUG(3, ("[%5lu]: dual pam auth %s\n", (unsigned long)state->pid,
01341                   state->request.data.auth.user));
01342 
01343         /* Parse domain and username */
01344         
01345         ws_name_return( state->request.data.auth.user, WB_REPLACE_CHAR );
01346 
01347         parse_domain_user(state->request.data.auth.user, name_domain, name_user);
01348 
01349         if (domain->online == False) {
01350                 result = NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND;
01351                 if (domain->startup) {
01352                         /* Logons are very important to users. If we're offline and
01353                            we get a request within the first 30 seconds of startup,
01354                            try very hard to find a DC and go online. */
01355 
01356                         DEBUG(10,("winbindd_dual_pam_auth: domain: %s offline and auth "
01357                                 "request in startup mode.\n", domain->name ));
01358 
01359                         winbindd_flush_negative_conn_cache(domain);
01360                         result = init_dc_connection(domain);
01361                 }
01362         }
01363 
01364         DEBUG(10,("winbindd_dual_pam_auth: domain: %s last was %s\n", domain->name, domain->online ? "online":"offline"));
01365 
01366         /* Check for Kerberos authentication */
01367         if (domain->online && (state->request.flags & WBFLAG_PAM_KRB5)) {
01368         
01369                 result = winbindd_dual_pam_auth_kerberos(domain, state, &info3);
01370 
01371                 if (NT_STATUS_IS_OK(result)) {
01372                         DEBUG(10,("winbindd_dual_pam_auth_kerberos succeeded\n"));
01373                         goto process_result;
01374                 } else {
01375                         DEBUG(10,("winbindd_dual_pam_auth_kerberos failed: %s\n", nt_errstr(result)));
01376                 }
01377 
01378                 if (NT_STATUS_EQUAL(result, NT_STATUS_NO_LOGON_SERVERS) ||
01379                     NT_STATUS_EQUAL(result, NT_STATUS_IO_TIMEOUT) ||
01380                     NT_STATUS_EQUAL(result, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
01381                         DEBUG(10,("winbindd_dual_pam_auth_kerberos setting domain to offline\n"));
01382                         /* Use set_domain_offline() instead of
01383                          * just set status offline, otherwise,
01384                          * domain will never goes online again
01385                          * --- BoYang */
01386                         set_domain_offline(domain);
01387                 }
01388 
01389                 /* there are quite some NT_STATUS errors where there is no
01390                  * point in retrying with a samlogon, we explictly have to take
01391                  * care not to increase the bad logon counter on the DC */
01392 
01393                 if (NT_STATUS_EQUAL(result, NT_STATUS_ACCOUNT_DISABLED) ||
01394                     NT_STATUS_EQUAL(result, NT_STATUS_ACCOUNT_EXPIRED) ||
01395                     NT_STATUS_EQUAL(result, NT_STATUS_ACCOUNT_LOCKED_OUT) ||
01396                     NT_STATUS_EQUAL(result, NT_STATUS_INVALID_LOGON_HOURS) ||
01397                     NT_STATUS_EQUAL(result, NT_STATUS_INVALID_WORKSTATION) ||
01398                     NT_STATUS_EQUAL(result, NT_STATUS_LOGON_FAILURE) ||
01399                     NT_STATUS_EQUAL(result, NT_STATUS_NO_SUCH_USER) ||
01400                     NT_STATUS_EQUAL(result, NT_STATUS_PASSWORD_EXPIRED) ||
01401                     NT_STATUS_EQUAL(result, NT_STATUS_PASSWORD_MUST_CHANGE) ||
01402                     NT_STATUS_EQUAL(result, NT_STATUS_WRONG_PASSWORD)) {
01403                         goto process_result;
01404                 }
01405                 
01406                 if (state->request.flags & WBFLAG_PAM_FALLBACK_AFTER_KRB5) {
01407                         DEBUG(3,("falling back to samlogon\n"));
01408                         goto sam_logon;
01409                 } else {
01410                         goto cached_logon;
01411                 }
01412         }
01413 
01414 sam_logon:
01415         /* Check for Samlogon authentication */
01416         if (domain->online) {
01417                 result = winbindd_dual_pam_auth_samlogon(domain, state, &info3);
01418         
01419                 if (NT_STATUS_IS_OK(result)) {
01420                         DEBUG(10,("winbindd_dual_pam_auth_samlogon succeeded\n"));
01421                         goto process_result;
01422                 } else {
01423                         DEBUG(10,("winbindd_dual_pam_auth_samlogon failed: %s\n", nt_errstr(result)));
01424                         if (domain->online) {
01425                                 /* We're still online - fail. */
01426                                 goto done;
01427                         }
01428                         /* Else drop through and see if we can check offline.... */
01429                 }
01430         }
01431 
01432 cached_logon:
01433         /* Check for Cached logons */
01434         if (!domain->online && (state->request.flags & WBFLAG_PAM_CACHED_LOGIN) && 
01435             lp_winbind_offline_logon()) {
01436         
01437                 result = winbindd_dual_pam_auth_cached(domain, state, &info3);
01438 
01439                 if (NT_STATUS_IS_OK(result)) {
01440                         DEBUG(10,("winbindd_dual_pam_auth_cached succeeded\n"));
01441                         goto process_result;
01442                 } else {
01443                         DEBUG(10,("winbindd_dual_pam_auth_cached failed: %s\n", nt_errstr(result)));
01444                         goto done;
01445                 }
01446         }
01447 
01448 process_result:
01449 
01450         if (NT_STATUS_IS_OK(result)) {
01451         
01452                 DOM_SID user_sid;
01453 
01454                 /* In all codepaths where result == NT_STATUS_OK info3 must have
01455                    been initialized. */
01456                 if (!info3) {
01457                         result = NT_STATUS_INTERNAL_ERROR;
01458                         goto done;
01459                 }
01460 
01461                 netsamlogon_cache_store(name_user, info3);
01462                 wcache_invalidate_samlogon(find_domain_from_name(name_domain), info3);
01463 
01464                 /* save name_to_sid info as early as possible */
01465                 sid_compose(&user_sid, &info3->dom_sid.sid, info3->user_rid);
01466                 cache_name2sid(domain, name_domain, name_user, SID_NAME_USER, &user_sid);
01467                 
01468                 /* Check if the user is in the right group */
01469 
01470                 if (!NT_STATUS_IS_OK(result = check_info3_in_group(state->mem_ctx, info3,
01471                                         state->request.data.auth.require_membership_of_sid))) {
01472                         DEBUG(3, ("User %s is not in the required group (%s), so plaintext authentication is rejected\n",
01473                                   state->request.data.auth.user, 
01474                                   state->request.data.auth.require_membership_of_sid));
01475                         goto done;
01476                 }
01477 
01478                 if (state->request.flags & WBFLAG_PAM_INFO3_NDR) {
01479                         result = append_info3_as_ndr(state->mem_ctx, state, info3);
01480                         if (!NT_STATUS_IS_OK(result)) {
01481                                 DEBUG(10,("Failed to append INFO3 (NDR): %s\n", nt_errstr(result)));
01482                                 goto done;
01483                         }
01484                 }
01485 
01486                 if (state->request.flags & WBFLAG_PAM_INFO3_TEXT) {
01487                         result = append_info3_as_txt(state->mem_ctx, state, info3);
01488                         if (!NT_STATUS_IS_OK(result)) {
01489                                 DEBUG(10,("Failed to append INFO3 (TXT): %s\n", nt_errstr(result)));
01490                                 goto done;
01491                         }
01492 
01493                 }
01494 
01495                 if ((state->request.flags & WBFLAG_PAM_CACHED_LOGIN)) {
01496 
01497                         /* Store in-memory creds for single-signon using ntlm_auth. */
01498                         result = winbindd_add_memory_creds(state->request.data.auth.user,
01499                                                         get_uid_from_state(state),
01500                                                         state->request.data.auth.pass);
01501 
01502                         if (!NT_STATUS_IS_OK(result)) {
01503                                 DEBUG(10,("Failed to store memory creds: %s\n", nt_errstr(result)));
01504                                 goto done;
01505                         }
01506 
01507                         if (lp_winbind_offline_logon()) {
01508                                 result = winbindd_store_creds(domain,
01509                                                       state->mem_ctx,
01510                                                       state->request.data.auth.user,
01511                                                       state->request.data.auth.pass,
01512                                                       info3, NULL);
01513                                 if (!NT_STATUS_IS_OK(result)) {
01514 
01515                                         /* Release refcount. */
01516                                         winbindd_delete_memory_creds(state->request.data.auth.user);
01517 
01518                                         DEBUG(10,("Failed to store creds: %s\n", nt_errstr(result)));
01519                                         goto done;
01520                                 }
01521                         }
01522                 }
01523 
01524                 if (state->request.flags & WBFLAG_PAM_GET_PWD_POLICY) {
01525                         result = fillup_password_policy(domain, state);
01526 
01527                         if (!NT_STATUS_IS_OK(result)) {
01528                                 DEBUG(10,("Failed to get password policies: %s\n", nt_errstr(result)));
01529                                 goto done;
01530                         }
01531                 }
01532 
01533                 if (state->request.flags & WBFLAG_PAM_UNIX_NAME) {
01534                         /* We've been asked to return the unix username, per 
01535                            'winbind use default domain' settings and the like */
01536 
01537                         fstring username_out;
01538                         const char *nt_username, *nt_domain;
01539 
01540                         if (!(nt_username = unistr2_tdup(state->mem_ctx, &info3->uni_user_name))) {
01541                                 /* If the server didn't give us one, just use the one we sent them */
01542                                 nt_username = name_user;
01543                         }
01544 
01545                         if (!(nt_domain = unistr2_tdup(state->mem_ctx, &info3->uni_logon_dom))) {
01546                                 /* If the server didn't give us one, just use the one we sent them */
01547                                 nt_domain = name_domain;
01548                         }
01549 
01550                         fill_domain_username(username_out, nt_domain, nt_username, True);
01551 
01552                         DEBUG(5, ("Setting unix username to [%s]\n", username_out));
01553 
01554                         SAFE_FREE(state->response.extra_data.data);
01555                         state->response.extra_data.data = SMB_STRDUP(username_out);
01556                         if (!state->response.extra_data.data) {
01557                                 result = NT_STATUS_NO_MEMORY;
01558                                 goto done;
01559                         }
01560                         state->response.length +=
01561                                 strlen((const char *)state->response.extra_data.data)+1;
01562                 }
01563         }
01564  
01565 
01566 done:
01567         /* give us a more useful (more correct?) error code */
01568         if ((NT_STATUS_EQUAL(result, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND) ||
01569             (NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL)))) {
01570                 result = NT_STATUS_NO_LOGON_SERVERS;
01571         }
01572         
01573         state->response.data.auth.nt_status = NT_STATUS_V(result);
01574         fstrcpy(state->response.data.auth.nt_status_string, nt_errstr(result));
01575 
01576         /* we might have given a more useful error above */
01577         if (!*state->response.data.auth.error_string) 
01578                 fstrcpy(state->response.data.auth.error_string, get_friendly_nt_error_msg(result));
01579         state->response.data.auth.pam_error = nt_status_to_pam(result);
01580 
01581         DEBUG(NT_STATUS_IS_OK(result) ? 5 : 2, ("Plain-text authentication for user %s returned %s (PAM: %d)\n", 
01582               state->request.data.auth.user, 
01583               state->response.data.auth.nt_status_string,
01584               state->response.data.auth.pam_error));          
01585 
01586         if ( NT_STATUS_IS_OK(result) && info3 &&
01587              (state->request.flags & WBFLAG_PAM_AFS_TOKEN) ) {
01588 
01589                 char *afsname = talloc_strdup(state->mem_ctx,
01590                                               lp_afs_username_map());
01591                 char *cell;
01592 
01593                 if (afsname == NULL) {
01594                         goto no_token;
01595                 }
01596 
01597                 afsname = talloc_string_sub(state->mem_ctx,
01598                                             lp_afs_username_map(),
01599                                             "%D", name_domain);
01600                 afsname = talloc_string_sub(state->mem_ctx, afsname,
01601                                             "%u", name_user);
01602                 afsname = talloc_string_sub(state->mem_ctx, afsname,
01603                                             "%U", name_user);
01604 
01605                 {
01606                         DOM_SID user_sid;
01607                         fstring sidstr;
01608 
01609                         sid_copy(&user_sid, &info3->dom_sid.sid);
01610                         sid_append_rid(&user_sid, info3->user_rid);
01611                         sid_to_string(sidstr, &user_sid);
01612                         afsname = talloc_string_sub(state->mem_ctx, afsname,
01613                                                     "%s", sidstr);
01614                 }
01615 
01616                 if (afsname == NULL) {
01617                         goto no_token;
01618                 }
01619 
01620                 strlower_m(afsname);
01621 
01622                 DEBUG(10, ("Generating token for user %s\n", afsname));
01623 
01624                 cell = strchr(afsname, '@');
01625 
01626                 if (cell == NULL) {
01627                         goto no_token;
01628                 }
01629 
01630                 *cell = '\0';
01631                 cell += 1;
01632 
01633                 /* Append an AFS token string */
01634                 SAFE_FREE(state->response.extra_data.data);
01635                 state->response.extra_data.data =
01636                         afs_createtoken_str(afsname, cell);
01637 
01638                 if (state->response.extra_data.data != NULL) {
01639                         state->response.length +=
01640                                 strlen((const char *)state->response.extra_data.data)+1;
01641                 }
01642 
01643         no_token:
01644                 TALLOC_FREE(afsname);
01645         }
01646         
01647         return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
01648 }
01649 
01650 
01651 /**********************************************************************
01652  Challenge Response Authentication Protocol 
01653 **********************************************************************/
01654 
01655 void winbindd_pam_auth_crap(struct winbindd_cli_state *state)
01656 {
01657         struct winbindd_domain *domain = NULL;
01658         const char *domain_name = NULL;
01659         NTSTATUS result;
01660 
01661         if (!state->privileged) {
01662                 char *error_string = NULL;
01663                 DEBUG(2, ("winbindd_pam_auth_crap: non-privileged access "
01664                           "denied.  !\n"));
01665                 DEBUGADD(2, ("winbindd_pam_auth_crap: Ensure permissions "
01666                              "on %s are set correctly.\n",
01667                              get_winbind_priv_pipe_dir()));
01668                 /* send a better message than ACCESS_DENIED */
01669                 error_string = talloc_asprintf(state->mem_ctx,
01670                                                "winbind client not authorized "
01671                                                "to use winbindd_pam_auth_crap."
01672                                                " Ensure permissions on %s "
01673                                                "are set correctly.",
01674                                                get_winbind_priv_pipe_dir());
01675                 fstrcpy(state->response.data.auth.error_string, error_string);
01676                 result = NT_STATUS_ACCESS_DENIED;
01677                 goto done;
01678         }
01679 
01680         /* Ensure null termination */
01681         state->request.data.auth_crap.user
01682                 [sizeof(state->request.data.auth_crap.user)-1]=0;
01683         state->request.data.auth_crap.domain
01684                 [sizeof(state->request.data.auth_crap.domain)-1]=0;
01685 
01686         DEBUG(3, ("[%5lu]: pam auth crap domain: [%s] user: %s\n",
01687                   (unsigned long)state->pid,
01688                   state->request.data.auth_crap.domain,
01689                   state->request.data.auth_crap.user));
01690 
01691         if (*state->request.data.auth_crap.domain != '\0') {
01692                 domain_name = state->request.data.auth_crap.domain;
01693         } else if (lp_winbind_use_default_domain()) {
01694                 domain_name = lp_workgroup();
01695         }
01696 
01697         if (domain_name != NULL)
01698                 domain = find_auth_domain(state, domain_name);
01699 
01700         if (domain != NULL) {
01701                 sendto_domain(state, domain);
01702                 return;
01703         }
01704 
01705         result = NT_STATUS_NO_SUCH_USER;
01706 
01707  done:
01708         set_auth_errors(&state->response, result);
01709         DEBUG(5, ("CRAP authentication for %s\\%s returned %s (PAM: %d)\n",
01710                   state->request.data.auth_crap.domain,
01711                   state->request.data.auth_crap.user, 
01712                   state->response.data.auth.nt_status_string,
01713                   state->response.data.auth.pam_error));
01714         request_error(state);
01715         return;
01716 }
01717 
01718 
01719 enum winbindd_result winbindd_dual_pam_auth_crap(struct winbindd_domain *domain,
01720                                                  struct winbindd_cli_state *state) 
01721 {
01722         NTSTATUS result;
01723         NET_USER_INFO_3 info3;
01724         struct rpc_pipe_client *netlogon_pipe;
01725         const char *name_user = NULL;
01726         const char *name_domain = NULL;
01727         const char *workstation;
01728         struct winbindd_domain *contact_domain;
01729         int attempts = 0;
01730         BOOL retry;
01731 
01732         DATA_BLOB lm_resp, nt_resp;
01733 
01734         /* This is child-only, so no check for privileged access is needed
01735            anymore */
01736 
01737         /* Ensure null termination */
01738         state->request.data.auth_crap.user[sizeof(state->request.data.auth_crap.user)-1]=0;
01739         state->request.data.auth_crap.domain[sizeof(state->request.data.auth_crap.domain)-1]=0;
01740 
01741         name_user = state->request.data.auth_crap.user;
01742 
01743         if (*state->request.data.auth_crap.domain) {
01744                 name_domain = state->request.data.auth_crap.domain;
01745         } else if (lp_winbind_use_default_domain()) {
01746                 name_domain = lp_workgroup();
01747         } else {
01748                 DEBUG(5,("no domain specified with username (%s) - failing auth\n", 
01749                          name_user));
01750                 result = NT_STATUS_NO_SUCH_USER;
01751                 goto done;
01752         }
01753 
01754         DEBUG(3, ("[%5lu]: pam auth crap domain: %s user: %s\n", (unsigned long)state->pid,
01755                   name_domain, name_user));
01756            
01757         if (*state->request.data.auth_crap.workstation) {
01758                 workstation = state->request.data.auth_crap.workstation;
01759         } else {
01760                 workstation = global_myname();
01761         }
01762 
01763         if (state->request.data.auth_crap.lm_resp_len > sizeof(state->request.data.auth_crap.lm_resp)
01764                 || state->request.data.auth_crap.nt_resp_len > sizeof(state->request.data.auth_crap.nt_resp)) {
01765                 DEBUG(0, ("winbindd_pam_auth_crap: invalid password length %u/%u\n", 
01766                           state->request.data.auth_crap.lm_resp_len, 
01767                           state->request.data.auth_crap.nt_resp_len));
01768                 result = NT_STATUS_INVALID_PARAMETER;
01769                 goto done;
01770         }
01771 
01772         lm_resp = data_blob_talloc(state->mem_ctx, state->request.data.auth_crap.lm_resp,
01773                                         state->request.data.auth_crap.lm_resp_len);
01774         nt_resp = data_blob_talloc(state->mem_ctx, state->request.data.auth_crap.nt_resp,
01775                                         state->request.data.auth_crap.nt_resp_len);
01776 
01777         /* what domain should we contact? */
01778         
01779         if ( IS_DC ) {
01780                 if (!(contact_domain = find_domain_from_name(name_domain))) {
01781                         DEBUG(3, ("Authentication for domain for [%s] -> [%s]\\[%s] failed as %s is not a trusted domain\n", 
01782                                   state->request.data.auth_crap.user, name_domain, name_user, name_domain)); 
01783                         result = NT_STATUS_NO_SUCH_USER;
01784                         goto done;
01785                 }
01786         } else {
01787                 if (is_myname(name_domain)) {
01788                         DEBUG(3, ("Authentication for domain %s (local domain to this server) not supported at this stage\n", name_domain));
01789                         result =  NT_STATUS_NO_SUCH_USER;
01790                         goto done;
01791                 }
01792                 contact_domain = find_our_domain();
01793         }
01794 
01795         do {
01796                 ZERO_STRUCT(info3);
01797                 retry = False;
01798 
01799                 netlogon_pipe = NULL;
01800                 result = cm_connect_netlogon(contact_domain, &netlogon_pipe);
01801 
01802                 if (!NT_STATUS_IS_OK(result)) {
01803                         DEBUG(3, ("could not open handle to NETLOGON pipe (error: %s)\n",
01804                                   nt_errstr(result)));
01805                         goto done;
01806                 }
01807 
01808                 result = rpccli_netlogon_sam_network_logon(netlogon_pipe,
01809                                                            state->mem_ctx,
01810                                                            state->request.data.auth_crap.logon_parameters,
01811                                                            contact_domain->dcname,
01812                                                            name_user,
01813                                                            name_domain, 
01814                                                                         /* Bug #3248 - found by Stefan Burkei. */
01815                                                            workstation, /* We carefully set this above so use it... */
01816                                                            state->request.data.auth_crap.chal,
01817                                                            lm_resp,
01818                                                            nt_resp,
01819                                                            &info3);
01820 
01821                 attempts += 1;
01822 
01823                 /* We have to try a second time as cm_connect_netlogon
01824                    might not yet have noticed that the DC has killed
01825                    our connection. */
01826 
01827                 if (NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL)) {
01828                         retry = True;
01829                         continue;
01830                 }
01831 
01832                 /* if we get access denied, a possible cause was that we had and open
01833                    connection to the DC, but someone changed our machine account password
01834                    out from underneath us using 'net rpc changetrustpw' */
01835                    
01836                 if ( NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED) ) {
01837                         DEBUG(3,("winbindd_pam_auth: sam_logon returned "
01838                                  "ACCESS_DENIED.  Maybe the trust account "
01839                                 "password was changed and we didn't know it. "
01840                                  "Killing connections to domain %s\n",
01841                                 name_domain));
01842                         invalidate_cm_connection(&contact_domain->conn);
01843                         retry = True;
01844                 } 
01845 
01846         } while ( (attempts < 2) && retry );
01847 
01848         if (NT_STATUS_IS_OK(result)) {
01849 
01850                 netsamlogon_cache_store(name_user, &info3);
01851                 wcache_invalidate_samlogon(find_domain_from_name(name_domain), &info3);
01852 
01853                 /* Check if the user is in the right group */
01854 
01855                 if (!NT_STATUS_IS_OK(result = check_info3_in_group(state->mem_ctx, &info3,
01856                                                         state->request.data.auth_crap.require_membership_of_sid))) {
01857                         DEBUG(3, ("User %s is not in the required group (%s), so plaintext authentication is rejected\n",
01858                                   state->request.data.auth_crap.user, 
01859                                   state->request.data.auth_crap.require_membership_of_sid));
01860                         goto done;
01861                 }
01862 
01863                 if (state->request.flags & WBFLAG_PAM_INFO3_NDR) {
01864                         result = append_info3_as_ndr(state->mem_ctx, state, &info3);
01865                 } else if (state->request.flags & WBFLAG_PAM_UNIX_NAME) {
01866                         /* ntlm_auth should return the unix username, per 
01867                            'winbind use default domain' settings and the like */
01868 
01869                         fstring username_out;
01870                         const char *nt_username, *nt_domain;
01871                         if (!(nt_username = unistr2_tdup(state->mem_ctx, &(info3.uni_user_name)))) {
01872                                 /* If the server didn't give us one, just use the one we sent them */
01873                                 nt_username = name_user;
01874                         }
01875 
01876                         if (!(nt_domain = unistr2_tdup(state->mem_ctx, &(info3.uni_logon_dom)))) {
01877                                 /* If the server didn't give us one, just use the one we sent them */
01878                                 nt_domain = name_domain;
01879                         }
01880 
01881                         fill_domain_username(username_out, nt_domain, nt_username, True);
01882 
01883                         DEBUG(5, ("Setting unix username to [%s]\n", username_out));
01884 
01885                         SAFE_FREE(state->response.extra_data.data);
01886                         state->response.extra_data.data = SMB_STRDUP(username_out);
01887                         if (!state->response.extra_data.data) {
01888                                 result = NT_STATUS_NO_MEMORY;
01889                                 goto done;
01890                         }
01891                         state->response.length +=
01892                                 strlen((const char *)state->response.extra_data.data)+1;
01893                 }
01894                 
01895                 if (state->request.flags & WBFLAG_PAM_USER_SESSION_KEY) {
01896                         memcpy(state->response.data.auth.user_session_key, info3.user_sess_key,
01897                                         sizeof(state->response.data.auth.user_session_key) /* 16 */);
01898                 }
01899                 if (state->request.flags & WBFLAG_PAM_LMKEY) {
01900                         memcpy(state->response.data.auth.first_8_lm_hash, info3.lm_sess_key,
01901                                         sizeof(state->response.data.auth.first_8_lm_hash) /* 8 */);
01902                 }
01903         }
01904 
01905 done:
01906 
01907         /* give us a more useful (more correct?) error code */
01908         if ((NT_STATUS_EQUAL(result, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND) ||
01909             (NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL)))) {
01910                 result = NT_STATUS_NO_LOGON_SERVERS;
01911         }
01912 
01913         if (state->request.flags & WBFLAG_PAM_NT_STATUS_SQUASH) {
01914                 result = nt_status_squash(result);
01915         }
01916 
01917         state->response.data.auth.nt_status = NT_STATUS_V(result);
01918         fstrcpy(state->response.data.auth.nt_status_string, nt_errstr(result));
01919 
01920         /* we might have given a more useful error above */
01921         if (!*state->response.data.auth.error_string) {
01922                 fstrcpy(state->response.data.auth.error_string, get_friendly_nt_error_msg(result));
01923         }
01924         state->response.data.auth.pam_error = nt_status_to_pam(result);
01925 
01926         DEBUG(NT_STATUS_IS_OK(result) ? 5 : 2, 
01927               ("NTLM CRAP authentication for user [%s]\\[%s] returned %s (PAM: %d)\n", 
01928                name_domain,
01929                name_user,
01930                state->response.data.auth.nt_status_string,
01931                state->response.data.auth.pam_error));         
01932 
01933         return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
01934 }
01935 
01936 /* Change a user password */
01937 
01938 void winbindd_pam_chauthtok(struct winbindd_cli_state *state)
01939 {
01940         fstring domain, user;
01941         struct winbindd_domain *contact_domain;
01942 
01943         DEBUG(3, ("[%5lu]: pam chauthtok %s\n", (unsigned long)state->pid,
01944                 state->request.data.chauthtok.user));
01945 
01946         /* Setup crap */
01947 
01948         if (!canonicalize_username(state->request.data.chauthtok.user, domain, user)) {
01949                 set_auth_errors(&state->response, NT_STATUS_NO_SUCH_USER);
01950                 DEBUG(5, ("winbindd_pam_chauthtok: canonicalize_username %s failed with %s"
01951                           "(PAM: %d)\n",
01952                           state->request.data.auth.user, 
01953                           state->response.data.auth.nt_status_string,
01954                           state->response.data.auth.pam_error));
01955                 request_error(state);
01956                 return;
01957         }
01958 
01959         contact_domain = find_domain_from_name(domain);
01960         if (!contact_domain) {
01961                 set_auth_errors(&state->response, NT_STATUS_NO_SUCH_USER);
01962                 DEBUG(3, ("Cannot change password for [%s] -> [%s]\\[%s] as %s is not a trusted domain\n", 
01963                           state->request.data.chauthtok.user, domain, user, domain)); 
01964                 request_error(state);
01965                 return;
01966         }
01967 
01968         sendto_domain(state, contact_domain);
01969 }
01970 
01971 enum winbindd_result winbindd_dual_pam_chauthtok(struct winbindd_domain *contact_domain,
01972                                                  struct winbindd_cli_state *state)
01973 {
01974         char *oldpass;
01975         char *newpass = NULL;
01976         POLICY_HND dom_pol;
01977         struct rpc_pipe_client *cli;
01978         BOOL got_info = False;
01979         SAM_UNK_INFO_1 info;
01980         SAMR_CHANGE_REJECT reject;
01981         NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
01982         fstring domain, user;
01983 
01984         DEBUG(3, ("[%5lu]: dual pam chauthtok %s\n", (unsigned long)state->pid,
01985                   state->request.data.auth.user));
01986 
01987         if (!parse_domain_user(state->request.data.chauthtok.user, domain, user)) {
01988                 goto done;
01989         }
01990 
01991         /* Change password */
01992 
01993         oldpass = state->request.data.chauthtok.oldpass;
01994         newpass = state->request.data.chauthtok.newpass;
01995 
01996         /* Initialize reject reason */
01997         state->response.data.auth.reject_reason = Undefined;
01998 
01999         /* Get sam handle */
02000 
02001         result = cm_connect_sam(contact_domain, state->mem_ctx, &cli,
02002                                 &dom_pol);
02003         if (!NT_STATUS_IS_OK(result)) {
02004                 DEBUG(1, ("could not get SAM handle on DC for %s\n", domain));
02005                 goto done;
02006         }
02007 
02008         result = rpccli_samr_chgpasswd3(cli, state->mem_ctx, user, newpass, oldpass, &info, &reject);
02009 
02010         /* Windows 2003 returns NT_STATUS_PASSWORD_RESTRICTION */
02011 
02012         if (NT_STATUS_EQUAL(result, NT_STATUS_PASSWORD_RESTRICTION) ) {
02013                 state->response.data.auth.policy.min_length_password = 
02014                         info.min_length_password;
02015                 state->response.data.auth.policy.password_history = 
02016                         info.password_history;
02017                 state->response.data.auth.policy.password_properties = 
02018                         info.password_properties;
02019                 state->response.data.auth.policy.expire = 
02020                         nt_time_to_unix_abs(&info.expire);
02021                 state->response.data.auth.policy.min_passwordage = 
02022                         nt_time_to_unix_abs(&info.min_passwordage);
02023 
02024                 state->response.data.auth.reject_reason = 
02025                         reject.reject_reason;
02026 
02027                 got_info = True;
02028         }
02029 
02030         /* only fallback when the chgpasswd3 call is not supported */
02031         if ((NT_STATUS_EQUAL(result, NT_STATUS(DCERPC_FAULT_OP_RNG_ERROR))) ||
02032                    (NT_STATUS_EQUAL(result, NT_STATUS_NOT_SUPPORTED)) ||
02033                    (NT_STATUS_EQUAL(result, NT_STATUS_NOT_IMPLEMENTED))) {
02034 
02035                 DEBUG(10,("Password change with chgpasswd3 failed with: %s, retrying chgpasswd_user\n", 
02036                         nt_errstr(result)));
02037                 
02038                 result = rpccli_samr_chgpasswd_user(cli, state->mem_ctx, user, newpass, oldpass);
02039 
02040                 /* Windows 2000 returns NT_STATUS_ACCOUNT_RESTRICTION.
02041                    Map to the same status code as Windows 2003. */
02042 
02043                 if ( NT_STATUS_EQUAL(NT_STATUS_ACCOUNT_RESTRICTION, result ) ) {
02044                         result = NT_STATUS_PASSWORD_RESTRICTION;                        
02045                 }
02046         }
02047 
02048 done: 
02049 
02050         if (NT_STATUS_IS_OK(result) && (state->request.flags & WBFLAG_PAM_CACHED_LOGIN)) {
02051 
02052                 /* Update the single sign-on memory creds. */
02053                 result = winbindd_replace_memory_creds(state->request.data.chauthtok.user,
02054                                                         newpass);
02055 
02056                 /* When we login from gdm or xdm and password expires,
02057                  * we change the password, but there are no memory crendentials.
02058                  * So, winbindd_replace_memory_creds() returns
02059                  * NT_STATUS_OBJECT_NAME_NOT_FOUND. This is not a failure.
02060                  * --- BoYang
02061                  * */
02062                 if (NT_STATUS_EQUAL(result, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
02063                         result = NT_STATUS_OK;
02064                 }
02065 
02066                 if (!NT_STATUS_IS_OK(result)) {
02067                         DEBUG(10,("Failed to replace memory creds: %s\n", nt_errstr(result)));
02068                         goto process_result;
02069                 }
02070 
02071                 if (lp_winbind_offline_logon()) {
02072                         result = winbindd_update_creds_by_name(contact_domain,
02073                                                          state->mem_ctx, user,
02074                                                          newpass);
02075                         /* Again, this happens when we login from gdm or xdm
02076                          * and the password expires, *BUT* cached crendentials
02077                          * don't exist. winbindd_update_creds_by_name()
02078                          * returns NT_STATUS_NO_SUCH_USER.
02079                          * This is not a failure.
02080                          * --- BoYang
02081                          * */
02082                         if (NT_STATUS_EQUAL(result, NT_STATUS_NO_SUCH_USER)) {
02083                                 result = NT_STATUS_OK;
02084                         }
02085                         if (!NT_STATUS_IS_OK(result)) {
02086                                 DEBUG(10,("Failed to store creds: %s\n", nt_errstr(result)));
02087                                 goto process_result;
02088                         }
02089                 }
02090         }
02091 
02092         if (!NT_STATUS_IS_OK(result) && !got_info && contact_domain) {
02093 
02094                 NTSTATUS policy_ret;
02095                 
02096                 policy_ret = fillup_password_policy(contact_domain, state);
02097 
02098                 /* failure of this is non critical, it will just provide no
02099                  * additional information to the client why the change has
02100                  * failed - Guenther */
02101 
02102                 if (!NT_STATUS_IS_OK(policy_ret)) {
02103                         DEBUG(10,("Failed to get password policies: %s\n", nt_errstr(policy_ret)));
02104                         goto process_result;
02105                 }
02106         }
02107 
02108 process_result:
02109 
02110         state->response.data.auth.nt_status = NT_STATUS_V(result);
02111         fstrcpy(state->response.data.auth.nt_status_string, nt_errstr(result));
02112         fstrcpy(state->response.data.auth.error_string, get_friendly_nt_error_msg(result));
02113         state->response.data.auth.pam_error = nt_status_to_pam(result);
02114 
02115         DEBUG(NT_STATUS_IS_OK(result) ? 5 : 2, 
02116               ("Password change for user [%s]\\[%s] returned %s (PAM: %d)\n", 
02117                domain,
02118                user,
02119                state->response.data.auth.nt_status_string,
02120                state->response.data.auth.pam_error));         
02121 
02122         return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
02123 }
02124 
02125 void winbindd_pam_logoff(struct winbindd_cli_state *state)
02126 {
02127         struct winbindd_domain *domain;
02128         fstring name_domain, user;
02129         uid_t caller_uid = (uid_t)-1;
02130         uid_t request_uid = state->request.data.logoff.uid;
02131 
02132         DEBUG(3, ("[%5lu]: pam logoff %s\n", (unsigned long)state->pid,
02133                 state->request.data.logoff.user));
02134 
02135         /* Ensure null termination */
02136         state->request.data.logoff.user
02137                 [sizeof(state->request.data.logoff.user)-1]='\0';
02138 
02139         state->request.data.logoff.krb5ccname
02140                 [sizeof(state->request.data.logoff.krb5ccname)-1]='\0';
02141 
02142         if (request_uid == (gid_t)-1) {
02143                 goto failed;
02144         }
02145 
02146         if (!canonicalize_username(state->request.data.logoff.user, name_domain, user)) {
02147                 goto failed;
02148         }
02149 
02150         if ((domain = find_auth_domain(state, name_domain)) == NULL) {
02151                 goto failed;
02152         }
02153 
02154         if ((sys_getpeereid(state->sock, &caller_uid)) != 0) {
02155                 DEBUG(1,("winbindd_pam_logoff: failed to check peerid: %s\n", 
02156                         strerror(errno)));
02157                 goto failed;
02158         }
02159 
02160         switch (caller_uid) {
02161                 case -1:
02162                         goto failed;
02163                 case 0:
02164                         /* root must be able to logoff any user - gd */
02165                         state->request.data.logoff.uid = request_uid;
02166                         break;
02167                 default:
02168                         if (caller_uid != request_uid) {
02169                                 DEBUG(1,("winbindd_pam_logoff: caller requested invalid uid\n"));
02170                                 goto failed;
02171                         }
02172                         state->request.data.logoff.uid = caller_uid;
02173                         break;
02174         }
02175 
02176         sendto_domain(state, domain);
02177         return;
02178 
02179  failed:
02180         set_auth_errors(&state->response, NT_STATUS_NO_SUCH_USER);
02181         DEBUG(5, ("Pam Logoff for %s returned %s "
02182                   "(PAM: %d)\n",
02183                   state->request.data.logoff.user,
02184                   state->response.data.auth.nt_status_string,
02185                   state->response.data.auth.pam_error));
02186         request_error(state);
02187         return;
02188 }
02189 
02190 enum winbindd_result winbindd_dual_pam_logoff(struct winbindd_domain *domain,
02191                                               struct winbindd_cli_state *state) 
02192 {
02193         NTSTATUS result = NT_STATUS_NOT_SUPPORTED;
02194 
02195         DEBUG(3, ("[%5lu]: pam dual logoff %s\n", (unsigned long)state->pid,
02196                 state->request.data.logoff.user));
02197 
02198         if (!(state->request.flags & WBFLAG_PAM_KRB5)) {
02199                 result = NT_STATUS_OK;
02200                 goto process_result;
02201         }
02202 
02203         if (state->request.data.logoff.krb5ccname[0] == '\0') {
02204                 result = NT_STATUS_OK;
02205                 goto process_result;
02206         }
02207 
02208 #ifdef HAVE_KRB5
02209         
02210         if (state->request.data.logoff.uid < 0) {
02211                 DEBUG(0,("winbindd_pam_logoff: invalid uid\n"));
02212                 goto process_result;
02213         }
02214 
02215         /* what we need here is to find the corresponding krb5 ccache name *we*
02216          * created for a given username and destroy it */
02217 
02218         if (!ccache_entry_exists(state->request.data.logoff.user)) {
02219                 result = NT_STATUS_OK;
02220                 DEBUG(10,("winbindd_pam_logoff: no entry found.\n"));
02221                 goto process_result;
02222         }
02223 
02224         if (!ccache_entry_identical(state->request.data.logoff.user, 
02225                                         state->request.data.logoff.uid,
02226                                         state->request.data.logoff.krb5ccname)) {
02227                 DEBUG(0,("winbindd_pam_logoff: cached entry differs.\n"));
02228                 goto process_result;
02229         }
02230 
02231         result = remove_ccache(state->request.data.logoff.user);
02232         if (!NT_STATUS_IS_OK(result)) {
02233                 DEBUG(0,("winbindd_pam_logoff: failed to remove ccache: %s\n",
02234                         nt_errstr(result)));
02235                 goto process_result;
02236         }
02237 
02238 #else
02239         result = NT_STATUS_NOT_SUPPORTED;
02240 #endif
02241 
02242 process_result:
02243 
02244         winbindd_delete_memory_creds(state->request.data.logoff.user);
02245 
02246         state->response.data.auth.nt_status = NT_STATUS_V(result);
02247         fstrcpy(state->response.data.auth.nt_status_string, nt_errstr(result));
02248         fstrcpy(state->response.data.auth.error_string, get_friendly_nt_error_msg(result));
02249         state->response.data.auth.pam_error = nt_status_to_pam(result);
02250 
02251         return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
02252 }
02253 
02254 /* Change user password with auth crap*/
02255 
02256 void winbindd_pam_chng_pswd_auth_crap(struct winbindd_cli_state *state)
02257 {
02258         struct winbindd_domain *domain = NULL;
02259         const char *domain_name = NULL;
02260 
02261         /* Ensure null termination */
02262         state->request.data.chng_pswd_auth_crap.user[
02263                 sizeof(state->request.data.chng_pswd_auth_crap.user)-1]=0;
02264         state->request.data.chng_pswd_auth_crap.domain[
02265                 sizeof(state->request.data.chng_pswd_auth_crap.domain)-1]=0;
02266         
02267         DEBUG(3, ("[%5lu]: pam change pswd auth crap domain: %s user: %s\n",
02268                   (unsigned long)state->pid,
02269                   state->request.data.chng_pswd_auth_crap.domain,
02270                   state->request.data.chng_pswd_auth_crap.user));
02271         
02272         if (*state->request.data.chng_pswd_auth_crap.domain != '\0') {
02273                 domain_name = state->request.data.chng_pswd_auth_crap.domain;
02274         } else if (lp_winbind_use_default_domain()) {
02275                 domain_name = lp_workgroup();
02276         }
02277 
02278         if (domain_name != NULL)
02279                 domain = find_domain_from_name(domain_name);
02280 
02281         if (domain != NULL) {
02282                 DEBUG(7, ("[%5lu]: pam auth crap changing pswd in domain: "
02283                           "%s\n", (unsigned long)state->pid,domain->name));
02284                 sendto_domain(state, domain);
02285                 return;
02286         }
02287 
02288         set_auth_errors(&state->response, NT_STATUS_NO_SUCH_USER);
02289         DEBUG(5, ("CRAP change password  for %s\\%s returned %s (PAM: %d)\n",
02290                   state->request.data.chng_pswd_auth_crap.domain,
02291                   state->request.data.chng_pswd_auth_crap.user, 
02292                   state->response.data.auth.nt_status_string,
02293                   state->response.data.auth.pam_error));
02294         request_error(state);
02295         return;
02296 }
02297 
02298 enum winbindd_result winbindd_dual_pam_chng_pswd_auth_crap(struct winbindd_domain *domainSt, struct winbindd_cli_state *state)
02299 {
02300         NTSTATUS result;
02301         DATA_BLOB new_nt_password;
02302         DATA_BLOB old_nt_hash_enc;
02303         DATA_BLOB new_lm_password;
02304         DATA_BLOB old_lm_hash_enc;
02305         fstring  domain,user;
02306         POLICY_HND dom_pol;
02307         struct winbindd_domain *contact_domain = domainSt;
02308         struct rpc_pipe_client *cli;
02309 
02310         /* Ensure null termination */
02311         state->request.data.chng_pswd_auth_crap.user[
02312                 sizeof(state->request.data.chng_pswd_auth_crap.user)-1]=0;
02313         state->request.data.chng_pswd_auth_crap.domain[
02314                 sizeof(state->request.data.chng_pswd_auth_crap.domain)-1]=0;
02315         *domain = 0;
02316         *user = 0;
02317         
02318         DEBUG(3, ("[%5lu]: pam change pswd auth crap domain: %s user: %s\n",
02319                   (unsigned long)state->pid,
02320                   state->request.data.chng_pswd_auth_crap.domain,
02321                   state->request.data.chng_pswd_auth_crap.user));
02322 
02323         if (lp_winbind_offline_logon()) {
02324                 DEBUG(0,("Refusing password change as winbind offline logons are enabled. "));
02325                 DEBUGADD(0,("Changing passwords here would risk inconsistent logons\n"));
02326                 result = NT_STATUS_ACCESS_DENIED;
02327                 goto done;
02328         }
02329 
02330         if (*state->request.data.chng_pswd_auth_crap.domain) {
02331                 fstrcpy(domain,state->request.data.chng_pswd_auth_crap.domain);
02332         } else {
02333                 parse_domain_user(state->request.data.chng_pswd_auth_crap.user,
02334                                   domain, user);
02335 
02336                 if(!*domain) {
02337                         DEBUG(3,("no domain specified with username (%s) - "
02338                                  "failing auth\n",
02339                                  state->request.data.chng_pswd_auth_crap.user));
02340                         result = NT_STATUS_NO_SUCH_USER;
02341                         goto done;
02342                 }
02343         }
02344 
02345         if (!*domain && lp_winbind_use_default_domain()) {
02346                 fstrcpy(domain,(char *)lp_workgroup());
02347         }
02348 
02349         if(!*user) {
02350                 fstrcpy(user, state->request.data.chng_pswd_auth_crap.user);
02351         }
02352 
02353         DEBUG(3, ("[%5lu]: pam auth crap domain: %s user: %s\n",
02354                   (unsigned long)state->pid, domain, user));
02355         
02356         /* Change password */
02357         new_nt_password = data_blob_talloc(
02358                 state->mem_ctx,
02359                 state->request.data.chng_pswd_auth_crap.new_nt_pswd,
02360                 state->request.data.chng_pswd_auth_crap.new_nt_pswd_len);
02361 
02362         old_nt_hash_enc = data_blob_talloc(
02363                 state->mem_ctx,
02364                 state->request.data.chng_pswd_auth_crap.old_nt_hash_enc,
02365                 state->request.data.chng_pswd_auth_crap.old_nt_hash_enc_len);
02366 
02367         if(state->request.data.chng_pswd_auth_crap.new_lm_pswd_len > 0) {
02368                 new_lm_password = data_blob_talloc(
02369                         state->mem_ctx,
02370                         state->request.data.chng_pswd_auth_crap.new_lm_pswd,
02371                         state->request.data.chng_pswd_auth_crap.new_lm_pswd_len);
02372 
02373                 old_lm_hash_enc = data_blob_talloc(
02374                         state->mem_ctx,
02375                         state->request.data.chng_pswd_auth_crap.old_lm_hash_enc,
02376                         state->request.data.chng_pswd_auth_crap.old_lm_hash_enc_len);
02377         } else {
02378                 new_lm_password.length = 0;
02379                 old_lm_hash_enc.length = 0;
02380         }
02381 
02382         /* Get sam handle */
02383 
02384         result = cm_connect_sam(contact_domain, state->mem_ctx, &cli, &dom_pol);
02385         if (!NT_STATUS_IS_OK(result)) {
02386                 DEBUG(1, ("could not get SAM handle on DC for %s\n", domain));
02387                 goto done;
02388         }
02389 
02390         result = rpccli_samr_chng_pswd_auth_crap(
02391                 cli, state->mem_ctx, user, new_nt_password, old_nt_hash_enc,
02392                 new_lm_password, old_lm_hash_enc);
02393 
02394  done:    
02395         state->response.data.auth.nt_status = NT_STATUS_V(result);
02396         fstrcpy(state->response.data.auth.nt_status_string, nt_errstr(result));
02397         fstrcpy(state->response.data.auth.error_string,
02398                 get_friendly_nt_error_msg(result));
02399         state->response.data.auth.pam_error = nt_status_to_pam(result);
02400 
02401         DEBUG(NT_STATUS_IS_OK(result) ? 5 : 2, 
02402               ("Password change for user [%s]\\[%s] returned %s (PAM: %d)\n", 
02403                domain, user,
02404                state->response.data.auth.nt_status_string,
02405                state->response.data.auth.pam_error));         
02406 
02407         return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
02408 }

Sambaに対してSat Aug 29 21:23:10 2009に生成されました。  doxygen 1.4.7