source: trunk/samba/source/smbd/sesssetup.c @ 26

Last change on this file since 26 was 26, checked in by Paul Smedley, 14 years ago

Updated source to 3.0.25rc1

File size: 46.4 KB
Line 
1/*
2   Unix SMB/CIFS implementation.
3   handle SMBsessionsetup
4   Copyright (C) Andrew Tridgell 1998-2001
5   Copyright (C) Andrew Bartlett      2001
6   Copyright (C) Jim McDonough <jmcd@us.ibm.com> 2002
7   Copyright (C) Luke Howard          2003
8
9   This program is free software; you can redistribute it and/or modify
10   it under the terms of the GNU General Public License as published by
11   the Free Software Foundation; either version 2 of the License, or
12   (at your option) any later version.
13   
14   This program is distributed in the hope that it will be useful,
15   but WITHOUT ANY WARRANTY; without even the implied warranty of
16   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17   GNU General Public License for more details.
18   
19   You should have received a copy of the GNU General Public License
20   along with this program; if not, write to the Free Software
21   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22*/
23
24#include "includes.h"
25
26extern struct auth_context *negprot_global_auth_context;
27extern BOOL global_encrypted_passwords_negotiated;
28extern BOOL global_spnego_negotiated;
29extern enum protocol_types Protocol;
30extern int max_send;
31
32uint32 global_client_caps = 0;
33
34/*
35  on a logon error possibly map the error to success if "map to guest"
36  is set approriately
37*/
38static NTSTATUS do_map_to_guest(NTSTATUS status, auth_serversupplied_info **server_info,
39                                const char *user, const char *domain)
40{
41        if (NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)) {
42                if ((lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_USER) || 
43                    (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_PASSWORD)) {
44                        DEBUG(3,("No such user %s [%s] - using guest account\n",
45                                 user, domain));
46                        status = make_server_info_guest(server_info);
47                }
48        }
49
50        if (NT_STATUS_EQUAL(status, NT_STATUS_WRONG_PASSWORD)) {
51                if (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_PASSWORD) {
52                        DEBUG(3,("Registered username %s for guest access\n",user));
53                        status = make_server_info_guest(server_info);
54                }
55        }
56
57        return status;
58}
59
60/****************************************************************************
61 Add the standard 'Samba' signature to the end of the session setup.
62****************************************************************************/
63
64static int add_signature(char *outbuf, char *p)
65{
66        char *start = p;
67        fstring lanman;
68
69        fstr_sprintf( lanman, "Samba %s", SAMBA_VERSION_STRING);
70
71        p += srvstr_push(outbuf, p, "Unix", -1, STR_TERMINATE);
72        p += srvstr_push(outbuf, p, lanman, -1, STR_TERMINATE);
73        p += srvstr_push(outbuf, p, lp_workgroup(), -1, STR_TERMINATE);
74
75        return PTR_DIFF(p, start);
76}
77
78/****************************************************************************
79 Start the signing engine if needed. Don't fail signing here.
80****************************************************************************/
81
82static void sessionsetup_start_signing_engine(const auth_serversupplied_info *server_info, char *inbuf)
83{
84        if (!server_info->guest && !srv_signing_started()) {
85                /* We need to start the signing engine
86                 * here but a W2K client sends the old
87                 * "BSRSPYL " signature instead of the
88                 * correct one. Subsequent packets will
89                 * be correct.
90                 */
91                srv_check_sign_mac(inbuf, False);
92        }
93}
94
95/****************************************************************************
96 Send a security blob via a session setup reply.
97****************************************************************************/
98
99static BOOL reply_sesssetup_blob(connection_struct *conn, char *outbuf,
100                                 DATA_BLOB blob, NTSTATUS nt_status)
101{
102        char *p;
103
104        if (!NT_STATUS_IS_OK(nt_status) && !NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
105                ERROR_NT(nt_status_squash(nt_status));
106        } else {
107                set_message(outbuf,4,0,True);
108
109                nt_status = nt_status_squash(nt_status);
110                SIVAL(outbuf, smb_rcls, NT_STATUS_V(nt_status));
111                SSVAL(outbuf, smb_vwv0, 0xFF); /* no chaining possible */
112                SSVAL(outbuf, smb_vwv3, blob.length);
113                p = smb_buf(outbuf);
114
115                /* should we cap this? */
116                memcpy(p, blob.data, blob.length);
117                p += blob.length;
118
119                p += add_signature( outbuf, p );
120
121                set_message_end(outbuf,p);
122        }
123
124        show_msg(outbuf);
125        return send_smb(smbd_server_fd(),outbuf);
126}
127
128/****************************************************************************
129 Do a 'guest' logon, getting back the
130****************************************************************************/
131
132static NTSTATUS check_guest_password(auth_serversupplied_info **server_info) 
133{
134        struct auth_context *auth_context;
135        auth_usersupplied_info *user_info = NULL;
136       
137        NTSTATUS nt_status;
138        unsigned char chal[8];
139
140        ZERO_STRUCT(chal);
141
142        DEBUG(3,("Got anonymous request\n"));
143
144        if (!NT_STATUS_IS_OK(nt_status = make_auth_context_fixed(&auth_context, chal))) {
145                return nt_status;
146        }
147
148        if (!make_user_info_guest(&user_info)) {
149                (auth_context->free)(&auth_context);
150                return NT_STATUS_NO_MEMORY;
151        }
152       
153        nt_status = auth_context->check_ntlm_password(auth_context, user_info, server_info);
154        (auth_context->free)(&auth_context);
155        free_user_info(&user_info);
156        return nt_status;
157}
158
159
160#ifdef HAVE_KRB5
161
162#if 0
163/* Experiment that failed. See "only happens with a KDC" comment below. */
164/****************************************************************************
165 Cerate a clock skew error blob for a Windows client.
166****************************************************************************/
167
168static BOOL make_krb5_skew_error(DATA_BLOB *pblob_out)
169{
170        krb5_context context = NULL;
171        krb5_error_code kerr = 0;
172        krb5_data reply;
173        krb5_principal host_princ = NULL;
174        char *host_princ_s = NULL;
175        BOOL ret = False;
176
177        *pblob_out = data_blob(NULL,0);
178
179        initialize_krb5_error_table();
180        kerr = krb5_init_context(&context);
181        if (kerr) {
182                return False;
183        }
184        /* Create server principal. */
185        asprintf(&host_princ_s, "%s$@%s", global_myname(), lp_realm());
186        if (!host_princ_s) {
187                goto out;
188        }
189        strlower_m(host_princ_s);
190
191        kerr = smb_krb5_parse_name(context, host_princ_s, &host_princ);
192        if (kerr) {
193                DEBUG(10,("make_krb5_skew_error: smb_krb5_parse_name failed for name %s: Error %s\n",
194                        host_princ_s, error_message(kerr) ));
195                goto out;
196        }
197       
198        kerr = smb_krb5_mk_error(context, KRB5KRB_AP_ERR_SKEW, host_princ, &reply);
199        if (kerr) {
200                DEBUG(10,("make_krb5_skew_error: smb_krb5_mk_error failed: Error %s\n",
201                        error_message(kerr) ));
202                goto out;
203        }
204
205        *pblob_out = data_blob(reply.data, reply.length);
206        kerberos_free_data_contents(context,&reply);
207        ret = True;
208
209  out:
210
211        if (host_princ_s) {
212                SAFE_FREE(host_princ_s);
213        }
214        if (host_princ) {
215                krb5_free_principal(context, host_princ);
216        }
217        krb5_free_context(context);
218        return ret;
219}
220#endif
221
222/****************************************************************************
223 Reply to a session setup spnego negotiate packet for kerberos.
224****************************************************************************/
225
226static int reply_spnego_kerberos(connection_struct *conn, 
227                                 char *inbuf, char *outbuf,
228                                 int length, int bufsize,
229                                 DATA_BLOB *secblob,
230                                 BOOL *p_invalidate_vuid)
231{
232        TALLOC_CTX *mem_ctx;
233        DATA_BLOB ticket;
234        char *client, *p, *domain;
235        fstring netbios_domain_name;
236        struct passwd *pw;
237        fstring user;
238        int sess_vuid;
239        NTSTATUS ret;
240        PAC_DATA *pac_data;
241        DATA_BLOB ap_rep, ap_rep_wrapped, response;
242        auth_serversupplied_info *server_info = NULL;
243        DATA_BLOB session_key = data_blob(NULL, 0);
244        uint8 tok_id[2];
245        DATA_BLOB nullblob = data_blob(NULL, 0);
246        fstring real_username;
247        BOOL map_domainuser_to_guest = False;
248        BOOL username_was_mapped;
249        PAC_LOGON_INFO *logon_info = NULL;
250
251        ZERO_STRUCT(ticket);
252        ZERO_STRUCT(pac_data);
253        ZERO_STRUCT(ap_rep);
254        ZERO_STRUCT(ap_rep_wrapped);
255        ZERO_STRUCT(response);
256
257        /* Normally we will always invalidate the intermediate vuid. */
258        *p_invalidate_vuid = True;
259
260        mem_ctx = talloc_init("reply_spnego_kerberos");
261        if (mem_ctx == NULL) {
262                return ERROR_NT(nt_status_squash(NT_STATUS_NO_MEMORY));
263        }
264
265        if (!spnego_parse_krb5_wrap(*secblob, &ticket, tok_id)) {
266                talloc_destroy(mem_ctx);
267                return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE));
268        }
269
270        ret = ads_verify_ticket(mem_ctx, lp_realm(), 0, &ticket, &client, &pac_data, &ap_rep, &session_key);
271
272        data_blob_free(&ticket);
273
274        if (!NT_STATUS_IS_OK(ret)) {
275#if 0
276                /* Experiment that failed. See "only happens with a KDC" comment below. */
277
278                if (NT_STATUS_EQUAL(ret, NT_STATUS_TIME_DIFFERENCE_AT_DC)) {
279
280                        /*
281                         * Windows in this case returns NT_STATUS_MORE_PROCESSING_REQUIRED
282                         * with a negTokenTarg blob containing an krb5_error struct ASN1 encoded
283                         * containing KRB5KRB_AP_ERR_SKEW. The client then fixes its
284                         * clock and continues rather than giving an error. JRA.
285                         * -- Looks like this only happens with a KDC. JRA.
286                         */
287
288                        BOOL ok = make_krb5_skew_error(&ap_rep);
289                        if (!ok) {
290                                talloc_destroy(mem_ctx);
291                                return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE));
292                        }
293                        ap_rep_wrapped = spnego_gen_krb5_wrap(ap_rep, TOK_ID_KRB_ERROR);
294                        response = spnego_gen_auth_response(&ap_rep_wrapped, ret, OID_KERBEROS5_OLD);
295                        reply_sesssetup_blob(conn, outbuf, response, NT_STATUS_MORE_PROCESSING_REQUIRED);
296
297                        /*
298                         * In this one case we don't invalidate the intermediate vuid.
299                         * as we're expecting the client to re-use it for the next
300                         * sessionsetupX packet. JRA.
301                         */
302
303                        *p_invalidate_vuid = False;
304
305                        data_blob_free(&ap_rep);
306                        data_blob_free(&ap_rep_wrapped);
307                        data_blob_free(&response);
308                        talloc_destroy(mem_ctx);
309                        return -1; /* already replied */
310                }
311#else
312                if (!NT_STATUS_EQUAL(ret, NT_STATUS_TIME_DIFFERENCE_AT_DC)) {
313                        ret = NT_STATUS_LOGON_FAILURE;
314                }
315#endif
316                DEBUG(1,("Failed to verify incoming ticket with error %s!\n", nt_errstr(ret))); 
317                talloc_destroy(mem_ctx);
318                return ERROR_NT(nt_status_squash(ret));
319        }
320
321        DEBUG(3,("Ticket name is [%s]\n", client));
322
323        p = strchr_m(client, '@');
324        if (!p) {
325                DEBUG(3,("Doesn't look like a valid principal\n"));
326                data_blob_free(&ap_rep);
327                data_blob_free(&session_key);
328                SAFE_FREE(client);
329                talloc_destroy(mem_ctx);
330                return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE));
331        }
332
333        *p = 0;
334
335        /* save the PAC data if we have it */
336
337        if (pac_data) {
338                logon_info = get_logon_info_from_pac(pac_data);
339                if (logon_info) {
340                        netsamlogon_cache_store( client, &logon_info->info3 );
341                }
342        }
343
344        if (!strequal(p+1, lp_realm())) {
345                DEBUG(3,("Ticket for foreign realm %s@%s\n", client, p+1));
346                if (!lp_allow_trusted_domains()) {
347                        data_blob_free(&ap_rep);
348                        data_blob_free(&session_key);
349                        SAFE_FREE(client);
350                        talloc_destroy(mem_ctx);
351                        return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE));
352                }
353        }
354
355        /* this gives a fully qualified user name (ie. with full realm).
356           that leads to very long usernames, but what else can we do? */
357
358        domain = p+1;
359
360        if (logon_info && logon_info->info3.hdr_logon_dom.uni_str_len) {
361
362                unistr2_to_ascii(netbios_domain_name, &logon_info->info3.uni_logon_dom, -1);
363                domain = netbios_domain_name;
364                DEBUG(10, ("Mapped to [%s] (using PAC)\n", domain));
365
366        } else {
367
368                /* If we have winbind running, we can (and must) shorten the
369                   username by using the short netbios name. Otherwise we will
370                   have inconsistent user names. With Kerberos, we get the
371                   fully qualified realm, with ntlmssp we get the short
372                   name. And even w2k3 does use ntlmssp if you for example
373                   connect to an ip address. */
374
375                struct winbindd_request wb_request;
376                struct winbindd_response wb_response;
377                NSS_STATUS wb_result;
378
379                ZERO_STRUCT(wb_request);
380                ZERO_STRUCT(wb_response);
381
382                DEBUG(10, ("Mapping [%s] to short name\n", domain));
383
384                fstrcpy(wb_request.domain_name, domain);
385
386                wb_result = winbindd_request_response(WINBINDD_DOMAIN_INFO,
387                                             &wb_request, &wb_response);
388
389                if (wb_result == NSS_STATUS_SUCCESS) {
390
391                        fstrcpy(netbios_domain_name,
392                                wb_response.data.domain_info.name);
393                        domain = netbios_domain_name;
394
395                        DEBUG(10, ("Mapped to [%s] (using Winbind)\n", domain));
396                } else {
397                        DEBUG(3, ("Could not find short name -- winbind "
398                                  "not running?\n"));
399                }
400        }
401
402        fstr_sprintf(user, "%s%c%s", domain, *lp_winbind_separator(), client);
403       
404        /* lookup the passwd struct, create a new user if necessary */
405
406        username_was_mapped = map_username( user );
407
408        pw = smb_getpwnam( mem_ctx, user, real_username, True );
409
410        if (pw) {
411                /* if a real user check pam account restrictions */
412                /* only really perfomed if "obey pam restriction" is true */
413                /* do this before an eventual mappign to guest occurs */
414                ret = smb_pam_accountcheck(pw->pw_name);
415                if (  !NT_STATUS_IS_OK(ret)) {
416                        DEBUG(1, ("PAM account restriction prevents user login\n"));
417                        data_blob_free(&ap_rep);
418                        data_blob_free(&session_key);
419                        TALLOC_FREE(mem_ctx);
420                        return ERROR_NT(nt_status_squash(ret));
421                }
422        }
423
424        if (!pw) {
425
426                /* this was originally the behavior of Samba 2.2, if a user
427                   did not have a local uid but has been authenticated, then
428                   map them to a guest account */
429
430                if (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_UID){ 
431                        map_domainuser_to_guest = True;
432                        fstrcpy(user,lp_guestaccount());
433                        pw = smb_getpwnam( mem_ctx, user, real_username, True );
434                } 
435
436                /* extra sanity check that the guest account is valid */
437
438                if ( !pw ) {
439                        DEBUG(1,("Username %s is invalid on this system\n", user));
440                        SAFE_FREE(client);
441                        data_blob_free(&ap_rep);
442                        data_blob_free(&session_key);
443                        TALLOC_FREE(mem_ctx);
444                        return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE));
445                }
446        }
447
448        /* setup the string used by %U */
449       
450        sub_set_smb_name( real_username );
451        reload_services(True);
452
453        if ( map_domainuser_to_guest ) {
454                make_server_info_guest(&server_info);
455        } else if (logon_info) {
456                /* pass the unmapped username here since map_username()
457                   will be called again from inside make_server_info_info3() */
458               
459                ret = make_server_info_info3(mem_ctx, client, domain, 
460                                             &server_info, &logon_info->info3);
461                if ( !NT_STATUS_IS_OK(ret) ) {
462                        DEBUG(1,("make_server_info_info3 failed: %s!\n",
463                                 nt_errstr(ret)));
464                        SAFE_FREE(client);
465                        data_blob_free(&ap_rep);
466                        data_blob_free(&session_key);
467                        TALLOC_FREE(mem_ctx);
468                        return ERROR_NT(nt_status_squash(ret));
469                }
470
471        } else {
472                ret = make_server_info_pw(&server_info, real_username, pw);
473
474                if ( !NT_STATUS_IS_OK(ret) ) {
475                        DEBUG(1,("make_server_info_pw failed: %s!\n",
476                                 nt_errstr(ret)));
477                        SAFE_FREE(client);
478                        data_blob_free(&ap_rep);
479                        data_blob_free(&session_key);
480                        TALLOC_FREE(mem_ctx);
481                        return ERROR_NT(nt_status_squash(ret));
482                }
483
484                /* make_server_info_pw does not set the domain. Without this
485                 * we end up with the local netbios name in substitutions for
486                 * %D. */
487
488                if (server_info->sam_account != NULL) {
489                        pdb_set_domain(server_info->sam_account, domain, PDB_SET);
490                }
491        }
492
493        server_info->was_mapped |= username_was_mapped;
494       
495        /* we need to build the token for the user. make_server_info_guest()
496           already does this */
497       
498        if ( !server_info->ptok ) {
499                ret = create_local_token( server_info );
500                if ( !NT_STATUS_IS_OK(ret) ) {
501                        SAFE_FREE(client);
502                        data_blob_free(&ap_rep);
503                        data_blob_free(&session_key);
504                        TALLOC_FREE( mem_ctx );
505                        TALLOC_FREE( server_info );
506                        return ERROR_NT(nt_status_squash(ret));
507                }
508        }
509
510        /* register_vuid keeps the server info */
511        /* register_vuid takes ownership of session_key, no need to free after this.
512           A better interface would copy it.... */
513        sess_vuid = register_vuid(server_info, session_key, nullblob, client);
514
515        SAFE_FREE(client);
516
517        if (sess_vuid == UID_FIELD_INVALID ) {
518                ret = NT_STATUS_LOGON_FAILURE;
519        } else {
520                /* current_user_info is changed on new vuid */
521                reload_services( True );
522
523                set_message(outbuf,4,0,True);
524                SSVAL(outbuf, smb_vwv3, 0);
525                       
526                if (server_info->guest) {
527                        SSVAL(outbuf,smb_vwv2,1);
528                }
529               
530                SSVAL(outbuf, smb_uid, sess_vuid);
531
532                sessionsetup_start_signing_engine(server_info, inbuf);
533        }
534
535        /* wrap that up in a nice GSS-API wrapping */
536        if (NT_STATUS_IS_OK(ret)) {
537                ap_rep_wrapped = spnego_gen_krb5_wrap(ap_rep, TOK_ID_KRB_AP_REP);
538        } else {
539                ap_rep_wrapped = data_blob(NULL, 0);
540        }
541        response = spnego_gen_auth_response(&ap_rep_wrapped, ret, OID_KERBEROS5_OLD);
542        reply_sesssetup_blob(conn, outbuf, response, ret);
543
544        data_blob_free(&ap_rep);
545        data_blob_free(&ap_rep_wrapped);
546        data_blob_free(&response);
547        TALLOC_FREE(mem_ctx);
548
549        return -1; /* already replied */
550}
551#endif
552
553/****************************************************************************
554 Send a session setup reply, wrapped in SPNEGO.
555 Get vuid and check first.
556 End the NTLMSSP exchange context if we are OK/complete fail
557 This should be split into two functions, one to handle each
558 leg of the NTLM auth steps.
559***************************************************************************/
560
561static BOOL reply_spnego_ntlmssp(connection_struct *conn, char *inbuf, char *outbuf,
562                                 uint16 vuid,
563                                 AUTH_NTLMSSP_STATE **auth_ntlmssp_state,
564                                 DATA_BLOB *ntlmssp_blob, NTSTATUS nt_status, 
565                                 BOOL wrap) 
566{
567        BOOL ret;
568        DATA_BLOB response;
569        struct auth_serversupplied_info *server_info = NULL;
570
571        if (NT_STATUS_IS_OK(nt_status)) {
572                server_info = (*auth_ntlmssp_state)->server_info;
573        } else {
574                nt_status = do_map_to_guest(nt_status, 
575                                            &server_info, 
576                                            (*auth_ntlmssp_state)->ntlmssp_state->user, 
577                                            (*auth_ntlmssp_state)->ntlmssp_state->domain);
578        }
579
580        if (NT_STATUS_IS_OK(nt_status)) {
581                int sess_vuid;
582                DATA_BLOB nullblob = data_blob(NULL, 0);
583                DATA_BLOB session_key = data_blob((*auth_ntlmssp_state)->ntlmssp_state->session_key.data, (*auth_ntlmssp_state)->ntlmssp_state->session_key.length);
584
585                /* register_vuid keeps the server info */
586                sess_vuid = register_vuid(server_info, session_key, nullblob, (*auth_ntlmssp_state)->ntlmssp_state->user);
587                (*auth_ntlmssp_state)->server_info = NULL;
588
589                if (sess_vuid == UID_FIELD_INVALID ) {
590                        nt_status = NT_STATUS_LOGON_FAILURE;
591                } else {
592                       
593                        /* current_user_info is changed on new vuid */
594                        reload_services( True );
595
596                        set_message(outbuf,4,0,True);
597                        SSVAL(outbuf, smb_vwv3, 0);
598                       
599                        if (server_info->guest) {
600                                SSVAL(outbuf,smb_vwv2,1);
601                        }
602                       
603                        SSVAL(outbuf,smb_uid,sess_vuid);
604
605                        sessionsetup_start_signing_engine(server_info, inbuf);
606                }
607        }
608
609        if (wrap) {
610                response = spnego_gen_auth_response(ntlmssp_blob, nt_status, OID_NTLMSSP);
611        } else {
612                response = *ntlmssp_blob;
613        }
614
615        ret = reply_sesssetup_blob(conn, outbuf, response, nt_status);
616        if (wrap) {
617                data_blob_free(&response);
618        }
619
620        /* NT_STATUS_MORE_PROCESSING_REQUIRED from our NTLMSSP code tells us,
621           and the other end, that we are not finished yet. */
622
623        if (!ret || !NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
624                /* NB. This is *NOT* an error case. JRA */
625                auth_ntlmssp_end(auth_ntlmssp_state);
626                /* Kill the intermediate vuid */
627                invalidate_vuid(vuid);
628        }
629
630        return ret;
631}
632
633/****************************************************************************
634 Is this a krb5 mechanism ?
635****************************************************************************/
636
637static NTSTATUS parse_spnego_mechanisms(DATA_BLOB blob_in, DATA_BLOB *pblob_out, BOOL *p_is_krb5)
638{
639        char *OIDs[ASN1_MAX_OIDS];
640        int i;
641
642        *p_is_krb5 = False;
643
644        /* parse out the OIDs and the first sec blob */
645        if (!parse_negTokenTarg(blob_in, OIDs, pblob_out)) {
646                return NT_STATUS_LOGON_FAILURE;
647        }
648
649        /* only look at the first OID for determining the mechToken --
650           accoirding to RFC2478, we should choose the one we want
651           and renegotiate, but i smell a client bug here.. 
652           
653           Problem observed when connecting to a member (samba box)
654           of an AD domain as a user in a Samba domain.  Samba member
655           server sent back krb5/mskrb5/ntlmssp as mechtypes, but the
656           client (2ksp3) replied with ntlmssp/mskrb5/krb5 and an
657           NTLMSSP mechtoken.                 --jerry              */
658
659#ifdef HAVE_KRB5       
660        if (strcmp(OID_KERBEROS5, OIDs[0]) == 0 ||
661            strcmp(OID_KERBEROS5_OLD, OIDs[0]) == 0) {
662                *p_is_krb5 = True;
663        }
664#endif
665               
666        for (i=0;OIDs[i];i++) {
667                DEBUG(5,("parse_spnego_mechanisms: Got OID %s\n", OIDs[i]));
668                free(OIDs[i]);
669        }
670        return NT_STATUS_OK;
671}
672
673/****************************************************************************
674 Reply to a session setup spnego negotiate packet.
675****************************************************************************/
676
677static int reply_spnego_negotiate(connection_struct *conn, 
678                                  char *inbuf,
679                                  char *outbuf,
680                                  uint16 vuid,
681                                  int length, int bufsize,
682                                  DATA_BLOB blob1,
683                                  AUTH_NTLMSSP_STATE **auth_ntlmssp_state)
684{
685        DATA_BLOB secblob;
686        DATA_BLOB chal;
687        BOOL got_kerberos_mechanism = False;
688        NTSTATUS status;
689
690        status = parse_spnego_mechanisms(blob1, &secblob, &got_kerberos_mechanism);
691        if (!NT_STATUS_IS_OK(status)) {
692                /* Kill the intermediate vuid */
693                invalidate_vuid(vuid);
694                return ERROR_NT(nt_status_squash(status));
695        }
696
697        DEBUG(3,("reply_spnego_negotiate: Got secblob of size %lu\n", (unsigned long)secblob.length));
698
699#ifdef HAVE_KRB5
700        if ( got_kerberos_mechanism && ((lp_security()==SEC_ADS) || lp_use_kerberos_keytab()) ) {
701                BOOL destroy_vuid = True;
702                int ret = reply_spnego_kerberos(conn, inbuf, outbuf, 
703                                                length, bufsize, &secblob, &destroy_vuid);
704                data_blob_free(&secblob);
705                if (destroy_vuid) {
706                        /* Kill the intermediate vuid */
707                        invalidate_vuid(vuid);
708                }
709                return ret;
710        }
711#endif
712
713        if (*auth_ntlmssp_state) {
714                auth_ntlmssp_end(auth_ntlmssp_state);
715        }
716
717        status = auth_ntlmssp_start(auth_ntlmssp_state);
718        if (!NT_STATUS_IS_OK(status)) {
719                /* Kill the intermediate vuid */
720                invalidate_vuid(vuid);
721                return ERROR_NT(nt_status_squash(status));
722        }
723
724        status = auth_ntlmssp_update(*auth_ntlmssp_state, 
725                                        secblob, &chal);
726
727        data_blob_free(&secblob);
728
729        reply_spnego_ntlmssp(conn, inbuf, outbuf, vuid, auth_ntlmssp_state,
730                             &chal, status, True);
731
732        data_blob_free(&chal);
733
734        /* already replied */
735        return -1;
736}
737
738/****************************************************************************
739 Reply to a session setup spnego auth packet.
740****************************************************************************/
741
742static int reply_spnego_auth(connection_struct *conn, char *inbuf, char *outbuf,
743                             uint16 vuid,
744                             int length, int bufsize,
745                             DATA_BLOB blob1,
746                             AUTH_NTLMSSP_STATE **auth_ntlmssp_state)
747{
748        DATA_BLOB auth = data_blob(NULL,0);
749        DATA_BLOB auth_reply = data_blob(NULL,0);
750        DATA_BLOB secblob = data_blob(NULL,0);
751        NTSTATUS status = NT_STATUS_INVALID_PARAMETER;
752
753        if (!spnego_parse_auth(blob1, &auth)) {
754#if 0
755                file_save("auth.dat", blob1.data, blob1.length);
756#endif
757                /* Kill the intermediate vuid */
758                invalidate_vuid(vuid);
759
760                return ERROR_NT(nt_status_squash(NT_STATUS_INVALID_PARAMETER));
761        }
762
763        if (auth.data[0] == ASN1_APPLICATION(0)) {
764                /* Might be a second negTokenTarg packet */
765
766                BOOL got_krb5_mechanism = False;
767                status = parse_spnego_mechanisms(auth, &secblob, &got_krb5_mechanism);
768                if (NT_STATUS_IS_OK(status)) {
769                        DEBUG(3,("reply_spnego_auth: Got secblob of size %lu\n", (unsigned long)secblob.length));
770#ifdef HAVE_KRB5
771                        if ( got_krb5_mechanism && ((lp_security()==SEC_ADS) || lp_use_kerberos_keytab()) ) {
772                                BOOL destroy_vuid = True;
773                                int ret = reply_spnego_kerberos(conn, inbuf, outbuf, 
774                                                                length, bufsize, &secblob, &destroy_vuid);
775                                data_blob_free(&secblob);
776                                data_blob_free(&auth);
777                                if (destroy_vuid) {
778                                        /* Kill the intermediate vuid */
779                                        invalidate_vuid(vuid);
780                                }
781                                return ret;
782                        }
783#endif
784                }
785        }
786
787        /* If we get here it wasn't a negTokenTarg auth packet. */
788        data_blob_free(&secblob);
789       
790        if (!*auth_ntlmssp_state) {
791                /* Kill the intermediate vuid */
792                invalidate_vuid(vuid);
793
794                /* auth before negotiatiate? */
795                return ERROR_NT(nt_status_squash(NT_STATUS_INVALID_PARAMETER));
796        }
797       
798        status = auth_ntlmssp_update(*auth_ntlmssp_state, 
799                                        auth, &auth_reply);
800
801        data_blob_free(&auth);
802
803        reply_spnego_ntlmssp(conn, inbuf, outbuf, vuid, 
804                             auth_ntlmssp_state,
805                             &auth_reply, status, True);
806               
807        data_blob_free(&auth_reply);
808
809        /* and tell smbd that we have already replied to this packet */
810        return -1;
811}
812
813/****************************************************************************
814 List to store partial SPNEGO auth fragments.
815****************************************************************************/
816
817static struct pending_auth_data *pd_list;
818
819/****************************************************************************
820 Delete an entry on the list.
821****************************************************************************/
822
823static void delete_partial_auth(struct pending_auth_data *pad)
824{
825        if (!pad) {
826                return;
827        }
828        DLIST_REMOVE(pd_list, pad);
829        data_blob_free(&pad->partial_data);
830        SAFE_FREE(pad);
831}
832
833/****************************************************************************
834 Search for a partial SPNEGO auth fragment matching an smbpid.
835****************************************************************************/
836
837static struct pending_auth_data *get_pending_auth_data(uint16 smbpid)
838{
839        struct pending_auth_data *pad;
840
841        for (pad = pd_list; pad; pad = pad->next) {
842                if (pad->smbpid == smbpid) {
843                        break;
844                }
845        }
846        return pad;
847}
848
849/****************************************************************************
850 Check the size of an SPNEGO blob. If we need more return NT_STATUS_MORE_PROCESSING_REQUIRED,
851 else return NT_STATUS_OK. Don't allow the blob to be more than 64k.
852****************************************************************************/
853
854static NTSTATUS check_spnego_blob_complete(uint16 smbpid, uint16 vuid, DATA_BLOB *pblob)
855{
856        struct pending_auth_data *pad = NULL;
857        ASN1_DATA data;
858        size_t needed_len = 0;
859
860        pad = get_pending_auth_data(smbpid);
861
862        /* Ensure we have some data. */
863        if (pblob->length == 0) {
864                /* Caller can cope. */
865                DEBUG(2,("check_spnego_blob_complete: zero blob length !\n"));
866                delete_partial_auth(pad);
867                return NT_STATUS_OK;
868        }
869
870        /* Were we waiting for more data ? */
871        if (pad) {
872                DATA_BLOB tmp_blob;
873                size_t copy_len = MIN(65536, pblob->length);
874
875                /* Integer wrap paranoia.... */
876
877                if (pad->partial_data.length + copy_len < pad->partial_data.length ||
878                    pad->partial_data.length + copy_len < copy_len) {
879
880                        DEBUG(2,("check_spnego_blob_complete: integer wrap "
881                                "pad->partial_data.length = %u, "
882                                "copy_len = %u\n",
883                                (unsigned int)pad->partial_data.length,
884                                (unsigned int)copy_len ));
885
886                        delete_partial_auth(pad);
887                        return NT_STATUS_INVALID_PARAMETER;
888                }
889
890                DEBUG(10,("check_spnego_blob_complete: "
891                        "pad->partial_data.length = %u, "
892                        "pad->needed_len = %u, "
893                        "copy_len = %u, "
894                        "pblob->length = %u,\n",
895                        (unsigned int)pad->partial_data.length,
896                        (unsigned int)pad->needed_len,
897                        (unsigned int)copy_len,
898                        (unsigned int)pblob->length ));
899
900                tmp_blob = data_blob(NULL,
901                                pad->partial_data.length + copy_len);
902
903                /* Concatenate the two (up to copy_len) bytes. */
904                memcpy(tmp_blob.data,
905                        pad->partial_data.data,
906                        pad->partial_data.length);
907                memcpy(tmp_blob.data + pad->partial_data.length,
908                        pblob->data,
909                        copy_len);
910
911                /* Replace the partial data. */
912                data_blob_free(&pad->partial_data);
913                pad->partial_data = tmp_blob;
914                ZERO_STRUCT(tmp_blob);
915
916                /* Are we done ? */
917                if (pblob->length >= pad->needed_len) {
918                        /* Yes, replace pblob. */
919                        data_blob_free(pblob);
920                        *pblob = pad->partial_data;
921                        ZERO_STRUCT(pad->partial_data);
922                        delete_partial_auth(pad);
923                        return NT_STATUS_OK;
924                }
925
926                /* Still need more data. */
927                pad->needed_len -= copy_len;
928                return NT_STATUS_MORE_PROCESSING_REQUIRED;
929        }
930
931        if ((pblob->data[0] != ASN1_APPLICATION(0)) &&
932            (pblob->data[0] != ASN1_CONTEXT(1))) {
933                /* Not something we can determine the
934                 * length of.
935                 */
936                return NT_STATUS_OK;
937        }
938
939        /* This is a new SPNEGO sessionsetup - see if
940         * the data given in this blob is enough.
941         */
942
943        asn1_load(&data, *pblob);
944        asn1_start_tag(&data, pblob->data[0]);
945        if (data.has_error || data.nesting == NULL) {
946                asn1_free(&data);
947                /* Let caller catch. */
948                return NT_STATUS_OK;
949        }
950
951        /* Integer wrap paranoia.... */
952
953        if (data.nesting->taglen + data.nesting->start < data.nesting->taglen ||
954            data.nesting->taglen + data.nesting->start < data.nesting->start) {
955
956                DEBUG(2,("check_spnego_blob_complete: integer wrap "
957                        "data.nesting->taglen = %u, "
958                        "data.nesting->start = %u\n",
959                        (unsigned int)data.nesting->taglen,
960                        (unsigned int)data.nesting->start ));
961
962                asn1_free(&data);
963                return NT_STATUS_INVALID_PARAMETER;
964        }
965
966        /* Total length of the needed asn1 is the tag length
967         * plus the current offset. */
968
969        needed_len = data.nesting->taglen + data.nesting->start;
970        asn1_free(&data);
971
972        DEBUG(10,("check_spnego_blob_complete: needed_len = %u, "
973                "pblob->length = %u\n",
974                (unsigned int)needed_len,
975                (unsigned int)pblob->length ));
976
977        if (needed_len <= pblob->length) {
978                /* Nothing to do - blob is complete. */
979                return NT_STATUS_OK;
980        }
981
982        /* Refuse the blob if it's bigger than 64k. */
983        if (needed_len > 65536) {
984                DEBUG(2,("check_spnego_blob_complete: needed_len too large (%u)\n",
985                        (unsigned int)needed_len ));
986                return NT_STATUS_INVALID_PARAMETER;
987        }
988
989        /* We must store this blob until complete. */
990        pad = SMB_MALLOC(sizeof(struct pending_auth_data));
991        if (!pad) {
992                return NT_STATUS_NO_MEMORY;
993        }
994        pad->needed_len = needed_len - pblob->length;
995        pad->partial_data = data_blob(pblob->data, pblob->length);
996        if (pad->partial_data.data == NULL) {
997                SAFE_FREE(pad);
998                return NT_STATUS_NO_MEMORY;
999        }
1000        pad->smbpid = smbpid;
1001        pad->vuid = vuid;
1002        DLIST_ADD(pd_list, pad);
1003
1004        return NT_STATUS_MORE_PROCESSING_REQUIRED;
1005}
1006
1007/****************************************************************************
1008 Reply to a session setup command.
1009 conn POINTER CAN BE NULL HERE !
1010****************************************************************************/
1011
1012static int reply_sesssetup_and_X_spnego(connection_struct *conn, char *inbuf,
1013                                        char *outbuf,
1014                                        int length,int bufsize)
1015{
1016        uint8 *p;
1017        DATA_BLOB blob1;
1018        int ret;
1019        size_t bufrem;
1020        fstring native_os, native_lanman, primary_domain;
1021        char *p2;
1022        uint16 data_blob_len = SVAL(inbuf, smb_vwv7);
1023        enum remote_arch_types ra_type = get_remote_arch();
1024        int vuid = SVAL(inbuf,smb_uid);
1025        user_struct *vuser = NULL;
1026        NTSTATUS status = NT_STATUS_OK;
1027        uint16 smbpid = SVAL(inbuf,smb_pid);
1028
1029        DEBUG(3,("Doing spnego session setup\n"));
1030
1031        if (global_client_caps == 0) {
1032                global_client_caps = IVAL(inbuf,smb_vwv10);
1033
1034                if (!(global_client_caps & CAP_STATUS32)) {
1035                        remove_from_common_flags2(FLAGS2_32_BIT_ERROR_CODES);
1036                }
1037
1038        }
1039               
1040        p = (uint8 *)smb_buf(inbuf);
1041
1042        if (data_blob_len == 0) {
1043                /* an invalid request */
1044                return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE));
1045        }
1046
1047        bufrem = smb_bufrem(inbuf, p);
1048        /* pull the spnego blob */
1049        blob1 = data_blob(p, MIN(bufrem, data_blob_len));
1050
1051#if 0
1052        file_save("negotiate.dat", blob1.data, blob1.length);
1053#endif
1054
1055        p2 = inbuf + smb_vwv13 + data_blob_len;
1056        p2 += srvstr_pull_buf(inbuf, native_os, p2, sizeof(native_os), STR_TERMINATE);
1057        p2 += srvstr_pull_buf(inbuf, native_lanman, p2, sizeof(native_lanman), STR_TERMINATE);
1058        p2 += srvstr_pull_buf(inbuf, primary_domain, p2, sizeof(primary_domain), STR_TERMINATE);
1059        DEBUG(3,("NativeOS=[%s] NativeLanMan=[%s] PrimaryDomain=[%s]\n", 
1060                native_os, native_lanman, primary_domain));
1061
1062        if ( ra_type == RA_WIN2K ) {
1063                /* Vista sets neither the OS or lanman strings */
1064
1065                if ( !strlen(native_os) && !strlen(native_lanman) )
1066                        set_remote_arch(RA_VISTA);
1067               
1068                /* Windows 2003 doesn't set the native lanman string,
1069                   but does set primary domain which is a bug I think */
1070                           
1071                if ( !strlen(native_lanman) ) {
1072                        ra_lanman_string( primary_domain );
1073                } else {
1074                        ra_lanman_string( native_lanman );
1075                }
1076        }
1077               
1078        vuser = get_partial_auth_user_struct(vuid);
1079        if (!vuser) {
1080                struct pending_auth_data *pad = get_pending_auth_data(smbpid);
1081                if (pad) {
1082                        DEBUG(10,("reply_sesssetup_and_X_spnego: found pending vuid %u\n",
1083                                (unsigned int)pad->vuid ));
1084                        vuid = pad->vuid;
1085                        vuser = get_partial_auth_user_struct(vuid);
1086                }
1087        }
1088
1089        if (!vuser) {
1090                vuid = register_vuid(NULL, data_blob(NULL, 0), data_blob(NULL, 0), NULL);
1091                if (vuid == UID_FIELD_INVALID ) {
1092                        data_blob_free(&blob1);
1093                        return ERROR_NT(nt_status_squash(NT_STATUS_INVALID_PARAMETER));
1094                }
1095       
1096                vuser = get_partial_auth_user_struct(vuid);
1097        }
1098
1099        if (!vuser) {
1100                data_blob_free(&blob1);
1101                return ERROR_NT(nt_status_squash(NT_STATUS_INVALID_PARAMETER));
1102        }
1103       
1104        SSVAL(outbuf,smb_uid,vuid);
1105
1106        /* Large (greater than 4k) SPNEGO blobs are split into multiple
1107         * sessionsetup requests as the Windows limit on the security blob
1108         * field is 4k. Bug #4400. JRA.
1109         */
1110
1111        status = check_spnego_blob_complete(smbpid, vuid, &blob1);
1112        if (!NT_STATUS_IS_OK(status)) {
1113                if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
1114                        /* Real error - kill the intermediate vuid */
1115                        invalidate_vuid(vuid);
1116                }
1117                data_blob_free(&blob1);
1118                return ERROR_NT(nt_status_squash(status));
1119        }
1120
1121        if (blob1.data[0] == ASN1_APPLICATION(0)) {
1122                /* its a negTokenTarg packet */
1123                ret = reply_spnego_negotiate(conn, inbuf, outbuf, vuid, length, bufsize, blob1,
1124                                             &vuser->auth_ntlmssp_state);
1125                data_blob_free(&blob1);
1126                return ret;
1127        }
1128
1129        if (blob1.data[0] == ASN1_CONTEXT(1)) {
1130                /* its a auth packet */
1131                ret = reply_spnego_auth(conn, inbuf, outbuf, vuid, length, bufsize, blob1,
1132                                        &vuser->auth_ntlmssp_state);
1133                data_blob_free(&blob1);
1134                return ret;
1135        }
1136
1137        if (strncmp((char *)(blob1.data), "NTLMSSP", 7) == 0) {
1138                DATA_BLOB chal;
1139                if (!vuser->auth_ntlmssp_state) {
1140                        status = auth_ntlmssp_start(&vuser->auth_ntlmssp_state);
1141                        if (!NT_STATUS_IS_OK(status)) {
1142                                /* Kill the intermediate vuid */
1143                                invalidate_vuid(vuid);
1144                                data_blob_free(&blob1);
1145                                return ERROR_NT(nt_status_squash(status));
1146                        }
1147                }
1148
1149                status = auth_ntlmssp_update(vuser->auth_ntlmssp_state,
1150                                                blob1, &chal);
1151               
1152                data_blob_free(&blob1);
1153               
1154                reply_spnego_ntlmssp(conn, inbuf, outbuf, vuid, 
1155                                           &vuser->auth_ntlmssp_state,
1156                                           &chal, status, False);
1157                data_blob_free(&chal);
1158                return -1;
1159        }
1160
1161        /* what sort of packet is this? */
1162        DEBUG(1,("Unknown packet in reply_sesssetup_and_X_spnego\n"));
1163
1164        data_blob_free(&blob1);
1165
1166        return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE));
1167}
1168
1169/****************************************************************************
1170 On new VC == 0, shutdown *all* old connections and users.
1171 It seems that only NT4.x does this. At W2K and above (XP etc.).
1172 a new session setup with VC==0 is ignored.
1173****************************************************************************/
1174
1175static int shutdown_other_smbds(TDB_CONTEXT *tdb, TDB_DATA kbuf, TDB_DATA dbuf,
1176                                void *p)
1177{
1178        struct sessionid *sessionid = (struct sessionid *)dbuf.dptr;
1179        const char *ip = (const char *)p;
1180
1181        if (!process_exists(pid_to_procid(sessionid->pid))) {
1182                return 0;
1183        }
1184
1185        if (sessionid->pid == sys_getpid()) {
1186                return 0;
1187        }
1188
1189        if (strcmp(ip, sessionid->ip_addr) != 0) {
1190                return 0;
1191        }
1192
1193        message_send_pid(pid_to_procid(sessionid->pid), MSG_SHUTDOWN,
1194                         NULL, 0, True);
1195        return 0;
1196}
1197
1198static void setup_new_vc_session(void)
1199{
1200        DEBUG(2,("setup_new_vc_session: New VC == 0, if NT4.x compatible we would close all old resources.\n"));
1201#if 0
1202        conn_close_all();
1203        invalidate_all_vuids();
1204#endif
1205        if (lp_reset_on_zero_vc()) {
1206                session_traverse(shutdown_other_smbds, client_addr());
1207        }
1208}
1209
1210/****************************************************************************
1211 Reply to a session setup command.
1212****************************************************************************/
1213
1214int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf,
1215                          int length,int bufsize)
1216{
1217        int sess_vuid;
1218        int   smb_bufsize;   
1219        DATA_BLOB lm_resp;
1220        DATA_BLOB nt_resp;
1221        DATA_BLOB plaintext_password;
1222        fstring user;
1223        fstring sub_user; /* Sainitised username for substituion */
1224        fstring domain;
1225        fstring native_os;
1226        fstring native_lanman;
1227        fstring primary_domain;
1228        static BOOL done_sesssetup = False;
1229        auth_usersupplied_info *user_info = NULL;
1230        auth_serversupplied_info *server_info = NULL;
1231
1232        NTSTATUS nt_status;
1233
1234        BOOL doencrypt = global_encrypted_passwords_negotiated;
1235
1236        DATA_BLOB session_key;
1237       
1238        START_PROFILE(SMBsesssetupX);
1239
1240        ZERO_STRUCT(lm_resp);
1241        ZERO_STRUCT(nt_resp);
1242        ZERO_STRUCT(plaintext_password);
1243
1244        DEBUG(3,("wct=%d flg2=0x%x\n", CVAL(inbuf, smb_wct), SVAL(inbuf, smb_flg2)));
1245
1246        /* a SPNEGO session setup has 12 command words, whereas a normal
1247           NT1 session setup has 13. See the cifs spec. */
1248        if (CVAL(inbuf, smb_wct) == 12 &&
1249            (SVAL(inbuf, smb_flg2) & FLAGS2_EXTENDED_SECURITY)) {
1250                if (!global_spnego_negotiated) {
1251                        DEBUG(0,("reply_sesssetup_and_X:  Rejecting attempt at SPNEGO session setup when it was not negoitiated.\n"));
1252                        return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE));
1253                }
1254
1255                if (SVAL(inbuf,smb_vwv4) == 0) {
1256                        setup_new_vc_session();
1257                }
1258                return reply_sesssetup_and_X_spnego(conn, inbuf, outbuf, length, bufsize);
1259        }
1260
1261        smb_bufsize = SVAL(inbuf,smb_vwv2);
1262
1263        if (Protocol < PROTOCOL_NT1) {
1264                uint16 passlen1 = SVAL(inbuf,smb_vwv7);
1265
1266                /* Never do NT status codes with protocols before NT1 as we don't get client caps. */
1267                remove_from_common_flags2(FLAGS2_32_BIT_ERROR_CODES);
1268
1269                if ((passlen1 > MAX_PASS_LEN) || (passlen1 > smb_bufrem(inbuf, smb_buf(inbuf)))) {
1270                        return ERROR_NT(nt_status_squash(NT_STATUS_INVALID_PARAMETER));
1271                }
1272
1273                if (doencrypt) {
1274                        lm_resp = data_blob(smb_buf(inbuf), passlen1);
1275                } else {
1276                        plaintext_password = data_blob(smb_buf(inbuf), passlen1+1);
1277                        /* Ensure null termination */
1278                        plaintext_password.data[passlen1] = 0;
1279                }
1280
1281                srvstr_pull_buf(inbuf, user, smb_buf(inbuf)+passlen1, sizeof(user), STR_TERMINATE);
1282                *domain = 0;
1283
1284        } else {
1285                uint16 passlen1 = SVAL(inbuf,smb_vwv7);
1286                uint16 passlen2 = SVAL(inbuf,smb_vwv8);
1287                enum remote_arch_types ra_type = get_remote_arch();
1288                char *p = smb_buf(inbuf);   
1289                char *save_p = smb_buf(inbuf);
1290                uint16 byte_count;
1291                       
1292
1293                if(global_client_caps == 0) {
1294                        global_client_caps = IVAL(inbuf,smb_vwv11);
1295               
1296                        if (!(global_client_caps & CAP_STATUS32)) {
1297                                remove_from_common_flags2(FLAGS2_32_BIT_ERROR_CODES);
1298                        }
1299
1300                        /* client_caps is used as final determination if client is NT or Win95.
1301                           This is needed to return the correct error codes in some
1302                           circumstances.
1303                        */
1304               
1305                        if(ra_type == RA_WINNT || ra_type == RA_WIN2K || ra_type == RA_WIN95) {
1306                                if(!(global_client_caps & (CAP_NT_SMBS | CAP_STATUS32))) {
1307                                        set_remote_arch( RA_WIN95);
1308                                }
1309                        }
1310                }
1311
1312                if (!doencrypt) {
1313                        /* both Win95 and WinNT stuff up the password lengths for
1314                           non-encrypting systems. Uggh.
1315                           
1316                           if passlen1==24 its a win95 system, and its setting the
1317                           password length incorrectly. Luckily it still works with the
1318                           default code because Win95 will null terminate the password
1319                           anyway
1320                           
1321                           if passlen1>0 and passlen2>0 then maybe its a NT box and its
1322                           setting passlen2 to some random value which really stuffs
1323                           things up. we need to fix that one.  */
1324                       
1325                        if (passlen1 > 0 && passlen2 > 0 && passlen2 != 24 && passlen2 != 1)
1326                                passlen2 = 0;
1327                }
1328               
1329                /* check for nasty tricks */
1330                if (passlen1 > MAX_PASS_LEN || passlen1 > smb_bufrem(inbuf, p)) {
1331                        return ERROR_NT(nt_status_squash(NT_STATUS_INVALID_PARAMETER));
1332                }
1333
1334                if (passlen2 > MAX_PASS_LEN || passlen2 > smb_bufrem(inbuf, p+passlen1)) {
1335                        return ERROR_NT(nt_status_squash(NT_STATUS_INVALID_PARAMETER));
1336                }
1337
1338                /* Save the lanman2 password and the NT md4 password. */
1339               
1340                if ((doencrypt) && (passlen1 != 0) && (passlen1 != 24)) {
1341                        doencrypt = False;
1342                }
1343
1344                if (doencrypt) {
1345                        lm_resp = data_blob(p, passlen1);
1346                        nt_resp = data_blob(p+passlen1, passlen2);
1347                } else {
1348                        pstring pass;
1349                        BOOL unic=SVAL(inbuf, smb_flg2) & FLAGS2_UNICODE_STRINGS;
1350
1351#if 0
1352                        /* This was the previous fix. Not sure if it's still valid. JRA. */
1353                        if ((ra_type == RA_WINNT) && (passlen2 == 0) && unic && passlen1) {
1354                                /* NT4.0 stuffs up plaintext unicode password lengths... */
1355                                srvstr_pull(inbuf, pass, smb_buf(inbuf) + 1,
1356                                        sizeof(pass), passlen1, STR_TERMINATE);
1357#endif
1358
1359                        if (unic && (passlen2 == 0) && passlen1) {
1360                                /* Only a ascii plaintext password was sent. */
1361                                srvstr_pull(inbuf, pass, smb_buf(inbuf), sizeof(pass),
1362                                        passlen1, STR_TERMINATE|STR_ASCII);
1363                        } else {
1364                                srvstr_pull(inbuf, pass, smb_buf(inbuf), 
1365                                        sizeof(pass),  unic ? passlen2 : passlen1, 
1366                                        STR_TERMINATE);
1367                        }
1368                        plaintext_password = data_blob(pass, strlen(pass)+1);
1369                }
1370               
1371                p += passlen1 + passlen2;
1372                p += srvstr_pull_buf(inbuf, user, p, sizeof(user), STR_TERMINATE);
1373                p += srvstr_pull_buf(inbuf, domain, p, sizeof(domain), STR_TERMINATE);
1374                p += srvstr_pull_buf(inbuf, native_os, p, sizeof(native_os), STR_TERMINATE);
1375                p += srvstr_pull_buf(inbuf, native_lanman, p, sizeof(native_lanman), STR_TERMINATE);
1376
1377                /* not documented or decoded by Ethereal but there is one more string
1378                   in the extra bytes which is the same as the PrimaryDomain when using
1379                   extended security.  Windows NT 4 and 2003 use this string to store
1380                   the native lanman string. Windows 9x does not include a string here
1381                   at all so we have to check if we have any extra bytes left */
1382               
1383                byte_count = SVAL(inbuf, smb_vwv13);
1384                if ( PTR_DIFF(p, save_p) < byte_count)
1385                        p += srvstr_pull_buf(inbuf, primary_domain, p, sizeof(primary_domain), STR_TERMINATE);
1386                else 
1387                        fstrcpy( primary_domain, "null" );
1388
1389                DEBUG(3,("Domain=[%s]  NativeOS=[%s] NativeLanMan=[%s] PrimaryDomain=[%s]\n",
1390                         domain, native_os, native_lanman, primary_domain));
1391
1392                if ( ra_type == RA_WIN2K ) {
1393                        if ( strlen(native_lanman) == 0 )
1394                                ra_lanman_string( primary_domain );
1395                        else
1396                                ra_lanman_string( native_lanman );
1397                }
1398
1399        }
1400
1401        if (SVAL(inbuf,smb_vwv4) == 0) {
1402                setup_new_vc_session();
1403        }
1404
1405        DEBUG(3,("sesssetupX:name=[%s]\\[%s]@[%s]\n", domain, user, get_remote_machine_name()));
1406
1407        if (*user) {
1408                if (global_spnego_negotiated) {
1409                       
1410                        /* This has to be here, because this is a perfectly valid behaviour for guest logons :-( */
1411                       
1412                        DEBUG(0,("reply_sesssetup_and_X:  Rejecting attempt at 'normal' session setup after negotiating spnego.\n"));
1413                        return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE));
1414                }
1415                fstrcpy(sub_user, user);
1416        } else {
1417                fstrcpy(sub_user, lp_guestaccount());
1418        }
1419
1420        sub_set_smb_name(sub_user);
1421
1422        reload_services(True);
1423       
1424        if (lp_security() == SEC_SHARE) {
1425                /* in share level we should ignore any passwords */
1426
1427                data_blob_free(&lm_resp);
1428                data_blob_free(&nt_resp);
1429                data_blob_clear_free(&plaintext_password);
1430
1431                map_username(sub_user);
1432                add_session_user(sub_user);
1433                add_session_workgroup(domain);
1434                /* Then force it to null for the benfit of the code below */
1435                *user = 0;
1436        }
1437       
1438        if (!*user) {
1439
1440                nt_status = check_guest_password(&server_info);
1441
1442        } else if (doencrypt) {
1443                if (!negprot_global_auth_context) {
1444                        DEBUG(0, ("reply_sesssetup_and_X:  Attempted encrypted session setup without negprot denied!\n"));
1445                        return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE));
1446                }
1447                nt_status = make_user_info_for_reply_enc(&user_info, user, domain,
1448                                                         lm_resp, nt_resp);
1449                if (NT_STATUS_IS_OK(nt_status)) {
1450                        nt_status = negprot_global_auth_context->check_ntlm_password(negprot_global_auth_context, 
1451                                                                                     user_info, 
1452                                                                                     &server_info);
1453                }
1454        } else {
1455                struct auth_context *plaintext_auth_context = NULL;
1456                const uint8 *chal;
1457
1458                nt_status = make_auth_context_subsystem(&plaintext_auth_context);
1459
1460                if (NT_STATUS_IS_OK(nt_status)) {
1461                        chal = plaintext_auth_context->get_ntlm_challenge(plaintext_auth_context);
1462                       
1463                        if (!make_user_info_for_reply(&user_info, 
1464                                                      user, domain, chal,
1465                                                      plaintext_password)) {
1466                                nt_status = NT_STATUS_NO_MEMORY;
1467                        }
1468               
1469                        if (NT_STATUS_IS_OK(nt_status)) {
1470                                nt_status = plaintext_auth_context->check_ntlm_password(plaintext_auth_context, 
1471                                                                                        user_info, 
1472                                                                                        &server_info); 
1473                               
1474                                (plaintext_auth_context->free)(&plaintext_auth_context);
1475                        }
1476                }
1477        }
1478
1479        free_user_info(&user_info);
1480       
1481        if (!NT_STATUS_IS_OK(nt_status)) {
1482                nt_status = do_map_to_guest(nt_status, &server_info, user, domain);
1483        }
1484       
1485        if (!NT_STATUS_IS_OK(nt_status)) {
1486                data_blob_free(&nt_resp);
1487                data_blob_free(&lm_resp);
1488                data_blob_clear_free(&plaintext_password);
1489                return ERROR_NT(nt_status_squash(nt_status));
1490        }
1491
1492        /* Ensure we can't possible take a code path leading to a null defref. */
1493        if (!server_info) {
1494                return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE));
1495        }
1496
1497        nt_status = create_local_token(server_info);
1498        if (!NT_STATUS_IS_OK(nt_status)) {
1499                DEBUG(10, ("create_local_token failed: %s\n",
1500                           nt_errstr(nt_status)));
1501                data_blob_free(&nt_resp);
1502                data_blob_free(&lm_resp);
1503                data_blob_clear_free(&plaintext_password);
1504                return ERROR_NT(nt_status_squash(nt_status));
1505        }
1506
1507        if (server_info->user_session_key.data) {
1508                session_key = data_blob(server_info->user_session_key.data, server_info->user_session_key.length);
1509        } else {
1510                session_key = data_blob(NULL, 0);
1511        }
1512
1513        data_blob_clear_free(&plaintext_password);
1514       
1515        /* it's ok - setup a reply */
1516        set_message(outbuf,3,0,True);
1517        if (Protocol >= PROTOCOL_NT1) {
1518                char *p = smb_buf( outbuf );
1519                p += add_signature( outbuf, p );
1520                set_message_end( outbuf, p );
1521                /* perhaps grab OS version here?? */
1522        }
1523       
1524        if (server_info->guest) {
1525                SSVAL(outbuf,smb_vwv2,1);
1526        }
1527
1528        /* register the name and uid as being validated, so further connections
1529           to a uid can get through without a password, on the same VC */
1530
1531        if (lp_security() == SEC_SHARE) {
1532                sess_vuid = UID_FIELD_INVALID;
1533                data_blob_free(&session_key);
1534                TALLOC_FREE(server_info);
1535        } else {
1536                /* register_vuid keeps the server info */
1537                sess_vuid = register_vuid(server_info, session_key,
1538                                          nt_resp.data ? nt_resp : lm_resp,
1539                                          sub_user);
1540                if (sess_vuid == UID_FIELD_INVALID) {
1541                        data_blob_free(&nt_resp);
1542                        data_blob_free(&lm_resp);
1543                        return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE));
1544                }
1545
1546                /* current_user_info is changed on new vuid */
1547                reload_services( True );
1548
1549                sessionsetup_start_signing_engine(server_info, inbuf);
1550        }
1551
1552        data_blob_free(&nt_resp);
1553        data_blob_free(&lm_resp);
1554       
1555        SSVAL(outbuf,smb_uid,sess_vuid);
1556        SSVAL(inbuf,smb_uid,sess_vuid);
1557       
1558        if (!done_sesssetup)
1559                max_send = MIN(max_send,smb_bufsize);
1560       
1561        done_sesssetup = True;
1562       
1563        END_PROFILE(SMBsesssetupX);
1564        return chain_reply(inbuf,outbuf,length,bufsize);
1565}
Note: See TracBrowser for help on using the repository browser.