From 54abd2aa66069e6baf7769c496f46d9dba18db39 Mon Sep 17 00:00:00 2001 From: Gerald Carter Date: Fri, 30 Sep 2005 17:13:37 +0000 Subject: r10656: BIG merge from trunk. Features not copied over * \PIPE\unixinfo * winbindd's {group,alias}membership new functions * winbindd's lookupsids() functionality * swat (trunk changes to be reverted as per discussion with Deryck) (This used to be commit 939c3cb5d78e3a2236209b296aa8aba8bdce32d3) --- source3/libsmb/cliconnect.c | 27 +-- source3/libsmb/clidgram.c | 2 +- source3/libsmb/clientgen.c | 83 ++++--- source3/libsmb/clierror.c | 17 ++ source3/libsmb/clikrb5.c | 451 ++++++++++++++++++++++++++++++++++++++- source3/libsmb/clireadwrite.c | 12 +- source3/libsmb/clispnego.c | 5 +- source3/libsmb/clitrans.c | 19 +- source3/libsmb/credentials.c | 295 +++++++++++++++---------- source3/libsmb/errormap.c | 4 +- source3/libsmb/libsmb_compat.c | 2 +- source3/libsmb/libsmbclient.c | 89 +++++--- source3/libsmb/ntlmssp.c | 84 ++++++-- source3/libsmb/ntlmssp_parse.c | 6 +- source3/libsmb/ntlmssp_sign.c | 436 ++++++++++++++++++++----------------- source3/libsmb/passchange.c | 66 +++--- source3/libsmb/pwd_cache.c | 1 - source3/libsmb/smb_share_modes.c | 93 ++++---- source3/libsmb/smbdes.c | 78 ++----- source3/libsmb/smbencrypt.c | 30 +-- source3/libsmb/smberr.c | 1 + source3/libsmb/spnego.c | 4 +- source3/libsmb/trusts_util.c | 47 ++-- 23 files changed, 1216 insertions(+), 636 deletions(-) (limited to 'source3/libsmb') diff --git a/source3/libsmb/cliconnect.c b/source3/libsmb/cliconnect.c index 3d8e36c493..7ecc769517 100644 --- a/source3/libsmb/cliconnect.c +++ b/source3/libsmb/cliconnect.c @@ -532,7 +532,7 @@ static ADS_STATUS cli_session_setup_kerberos(struct cli_state *cli, const char * DEBUG(2,("Doing kerberos session setup\n")); /* generate the encapsulated kerberos5 ticket */ - rc = spnego_gen_negTokenTarg(principal, 0, &negTokenTarg, &session_key_krb5); + rc = spnego_gen_negTokenTarg(principal, 0, &negTokenTarg, &session_key_krb5, 0); if (rc) { DEBUG(1, ("spnego_gen_negTokenTarg failed: %s\n", error_message(rc))); @@ -600,7 +600,7 @@ static NTSTATUS cli_session_setup_ntlmssp(struct cli_state *cli, const char *use nt_status = ntlmssp_update(ntlmssp_state, blob_in, &blob_out); data_blob_free(&blob_in); - if (NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) { + if (NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED) || NT_STATUS_IS_OK(nt_status)) { if (turn == 1) { /* and wrap it in a SPNEGO wrapper */ msg1 = gen_negTokenInit(OID_NTLMSSP, blob_out); @@ -1337,25 +1337,6 @@ BOOL cli_connect(struct cli_state *cli, const char *host, struct in_addr *ip) return True; } -/**************************************************************************** - Initialise client credentials for authenticated pipe access. -****************************************************************************/ - -void init_creds(struct ntuser_creds *creds, const char* username, - const char* domain, const char* password) -{ - ZERO_STRUCTP(creds); - - pwd_set_cleartext(&creds->pwd, password); - - fstrcpy(creds->user_name, username); - fstrcpy(creds->domain, domain); - - if (!*username) { - creds->pwd.null_pwd = True; - } -} - /** establishes a connection to after the negprot. @param output_cli A fully initialised cli structure, non-null only on success @@ -1474,7 +1455,6 @@ NTSTATUS cli_full_connection(struct cli_state **output_cli, int signing_state, BOOL *retry) { - struct ntuser_creds creds; NTSTATUS nt_status; struct cli_state *cli = NULL; @@ -1513,8 +1493,7 @@ NTSTATUS cli_full_connection(struct cli_state **output_cli, } } - init_creds(&creds, user, domain, password); - cli_init_creds(cli, &creds); + cli_init_creds(cli, user, domain, password); *output_cli = cli; return NT_STATUS_OK; diff --git a/source3/libsmb/clidgram.c b/source3/libsmb/clidgram.c index 819616105e..dfb613238f 100644 --- a/source3/libsmb/clidgram.c +++ b/source3/libsmb/clidgram.c @@ -101,7 +101,7 @@ BOOL cli_send_mailslot(BOOL unique, const char *mailslot, DEBUGADD(4,("to %s IP %s\n", nmb_namestr(&dgram->dest_name), inet_ntoa(dest_ip))); - return message_send_pid(nmbd_pid, MSG_SEND_PACKET, &p, sizeof(p), + return message_send_pid(pid_to_procid(nmbd_pid), MSG_SEND_PACKET, &p, sizeof(p), False); } diff --git a/source3/libsmb/clientgen.c b/source3/libsmb/clientgen.c index f1794ab5dc..bc64cc919b 100644 --- a/source3/libsmb/clientgen.c +++ b/source3/libsmb/clientgen.c @@ -221,15 +221,16 @@ void cli_setup_bcc(struct cli_state *cli, void *p) Initialise credentials of a client structure. ****************************************************************************/ -void cli_init_creds(struct cli_state *cli, const struct ntuser_creds *usr) +void cli_init_creds(struct cli_state *cli, const char *username, const char *domain, const char *password) { - /* copy_nt_creds(&cli->usr, usr); */ - fstrcpy(cli->domain , usr->domain); - fstrcpy(cli->user_name, usr->user_name); - memcpy(&cli->pwd, &usr->pwd, sizeof(usr->pwd)); + fstrcpy(cli->domain, domain); + fstrcpy(cli->user_name, username); + pwd_set_cleartext(&cli->pwd, password); + if (!*username) { + cli->pwd.null_pwd = True; + } - DEBUG(10,("cli_init_creds: user %s domain %s\n", - cli->user_name, cli->domain)); + DEBUG(10,("cli_init_creds: user %s domain %s\n", cli->user_name, cli->domain)); } /**************************************************************************** @@ -260,7 +261,6 @@ void cli_setup_signing_state(struct cli_state *cli, int signing_state) struct cli_state *cli_initialise(struct cli_state *cli) { BOOL alloced_cli = False; - int i; /* Check the effective uid - make sure we are not setuid */ if (is_setuid_root()) { @@ -332,16 +332,9 @@ struct cli_state *cli_initialise(struct cli_state *cli) /* initialise signing */ cli_null_set_signing(cli); - for (i=0; ipipes[i].fnum = 0; - - cli->netlogon_pipe.fnum = 0; - cli->initialised = 1; cli->allocated = alloced_cli; - cli->pipe_idx = -1; - return cli; /* Clean up after malloc() error */ @@ -358,34 +351,42 @@ struct cli_state *cli_initialise(struct cli_state *cli) } /**************************************************************************** -close the session -****************************************************************************/ + External interface. + Close an open named pipe over SMB. Free any authentication data. + ****************************************************************************/ -void cli_nt_session_close(struct cli_state *cli) +void cli_rpc_pipe_close(struct rpc_pipe_client *cli) { - int i; - - for (i=0; ipipes[i].pipe_auth_flags & AUTH_PIPE_NTLMSSP) { - ntlmssp_end(&cli->pipes[i].ntlmssp_pipe_state); - } + if (!cli_close(cli->cli, cli->fnum)) { + DEBUG(0,("cli_rpc_pipe_close: cli_close failed on pipe %s " + "to machine %s. Error was %s\n", + cli->pipe_name, + cli->cli->desthost, + cli_errstr(cli->cli))); + } - if (cli->pipes[i].fnum != 0) - cli_close(cli, cli->pipes[i].fnum); - cli->pipes[i].fnum = 0; + if (cli->auth.cli_auth_data_free_func) { + (*cli->auth.cli_auth_data_free_func)(&cli->auth); } - cli->pipe_idx = -1; + + DEBUG(10,("cli_rpc_pipe_close: closed pipe %s to machine %s\n", + cli->pipe_name, cli->cli->desthost )); + + DLIST_REMOVE(cli->cli->pipe_list, cli); + talloc_destroy(cli->mem_ctx); } /**************************************************************************** -close the NETLOGON session holding the session key for NETSEC + Close all pipes open on this session. ****************************************************************************/ -void cli_nt_netlogon_netsec_session_close(struct cli_state *cli) +void cli_nt_pipes_close(struct cli_state *cli) { - if (cli->netlogon_pipe.fnum != 0) { - cli_close(cli, cli->netlogon_pipe.fnum); - cli->netlogon_pipe.fnum = 0; + struct rpc_pipe_client *cp, *next; + + for (cp = cli->pipe_list; cp; cp = next) { + next = cp->next; + cli_rpc_pipe_close(cp); } } @@ -395,8 +396,7 @@ void cli_nt_netlogon_netsec_session_close(struct cli_state *cli) void cli_close_connection(struct cli_state *cli) { - cli_nt_session_close(cli); - cli_nt_netlogon_netsec_session_close(cli); + cli_nt_pipes_close(cli); /* * tell our peer to free his resources. Wihtout this, when an @@ -410,8 +410,9 @@ void cli_close_connection(struct cli_state *cli) * the only user for this so far is smbmount which passes opened connection * down to kernel's smbfs module. */ - if ( (cli->cnum != (uint16)-1) && (cli->smb_rw_error != DO_NOT_DO_TDIS ) ) + if ( (cli->cnum != (uint16)-1) && (cli->smb_rw_error != DO_NOT_DO_TDIS ) ) { cli_tdis(cli); + } SAFE_FREE(cli->outbuf); SAFE_FREE(cli->inbuf); @@ -420,19 +421,16 @@ void cli_close_connection(struct cli_state *cli) data_blob_free(&cli->secblob); data_blob_free(&cli->user_session_key); - if (cli->pipes[cli->pipe_idx].pipe_auth_flags & AUTH_PIPE_NTLMSSP) - ntlmssp_end(&cli->pipes[cli->pipe_idx].ntlmssp_pipe_state); - if (cli->mem_ctx) { talloc_destroy(cli->mem_ctx); cli->mem_ctx = NULL; } - if (cli->fd != -1) + if (cli->fd != -1) { close(cli->fd); + } cli->fd = -1; cli->smb_rw_error = 0; - } /**************************************************************************** @@ -444,8 +442,9 @@ void cli_shutdown(struct cli_state *cli) BOOL allocated = cli->allocated; cli_close_connection(cli); ZERO_STRUCTP(cli); - if (allocated) + if (allocated) { free(cli); + } } /**************************************************************************** diff --git a/source3/libsmb/clierror.c b/source3/libsmb/clierror.c index 355a2adf34..6938702e1e 100644 --- a/source3/libsmb/clierror.c +++ b/source3/libsmb/clierror.c @@ -404,3 +404,20 @@ BOOL cli_is_dos_error(struct cli_state *cli) return cli_is_error(cli) && !(flgs2 & FLAGS2_32_BIT_ERROR_CODES); } + +/* Return the last error always as an NTSTATUS. */ + +NTSTATUS cli_get_nt_error(struct cli_state *cli) +{ + if (cli_is_nt_error(cli)) { + return cli_nt_error(cli); + } else if (cli_is_dos_error(cli)) { + uint32 ecode; + uint8 eclass; + cli_dos_error(cli, &eclass, &ecode); + return dos_to_ntstatus(eclass, ecode); + } else { + /* Something went wrong, we don't know what. */ + return NT_STATUS_UNSUCCESSFUL; + } +} diff --git a/source3/libsmb/clikrb5.c b/source3/libsmb/clikrb5.c index 1741c1db3c..e3ad5f17cb 100644 --- a/source3/libsmb/clikrb5.c +++ b/source3/libsmb/clikrb5.c @@ -3,6 +3,8 @@ simple kerberos5 routines for active directory Copyright (C) Andrew Tridgell 2001 Copyright (C) Luke Howard 2002-2003 + Copyright (C) Andrew Bartlett 2005 + Copyright (C) Guenther Deschner 2005 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -186,17 +188,107 @@ } #endif - void get_auth_data_from_tkt(DATA_BLOB *auth_data, krb5_ticket *tkt) +BOOL unwrap_pac(TALLOC_CTX *mem_ctx, DATA_BLOB *auth_data, DATA_BLOB *unwrapped_pac_data) { + DATA_BLOB pac_contents; + ASN1_DATA data; + int data_type; + + if (!auth_data->length) { + return False; + } + + asn1_load(&data, *auth_data); + asn1_start_tag(&data, ASN1_SEQUENCE(0)); + asn1_start_tag(&data, ASN1_SEQUENCE(0)); + asn1_start_tag(&data, ASN1_CONTEXT(0)); + asn1_read_Integer(&data, &data_type); + + if (data_type != KRB5_AUTHDATA_WIN2K_PAC ) { + DEBUG(10,("authorization data is not a Windows PAC (type: %d)\n", data_type)); + asn1_free(&data); + return False; + } + + asn1_end_tag(&data); + asn1_start_tag(&data, ASN1_CONTEXT(1)); + asn1_read_OctetString(&data, &pac_contents); + asn1_end_tag(&data); + asn1_end_tag(&data); + asn1_end_tag(&data); + asn1_free(&data); + + *unwrapped_pac_data = data_blob_talloc(mem_ctx, pac_contents.data, pac_contents.length); + + data_blob_free(&pac_contents); + + return True; +} + + BOOL get_auth_data_from_tkt(TALLOC_CTX *mem_ctx, DATA_BLOB *auth_data, krb5_ticket *tkt) +{ + DATA_BLOB auth_data_wrapped; + BOOL got_auth_data_pac = False; + int i; + #if defined(HAVE_KRB5_TKT_ENC_PART2) - if (tkt->enc_part2 && tkt->enc_part2->authorization_data && tkt->enc_part2->authorization_data[0] && tkt->enc_part2->authorization_data[0]->length) - *auth_data = data_blob(tkt->enc_part2->authorization_data[0]->contents, - tkt->enc_part2->authorization_data[0]->length); + if (tkt->enc_part2 && tkt->enc_part2->authorization_data && + tkt->enc_part2->authorization_data[0] && + tkt->enc_part2->authorization_data[0]->length) + { + for (i = 0; tkt->enc_part2->authorization_data[i] != NULL; i++) { + + if (tkt->enc_part2->authorization_data[i]->ad_type != + KRB5_AUTHDATA_IF_RELEVANT) { + DEBUG(10,("get_auth_data_from_tkt: ad_type is %d\n", + tkt->enc_part2->authorization_data[i]->ad_type)); + continue; + } + + auth_data_wrapped = data_blob(tkt->enc_part2->authorization_data[i]->contents, + tkt->enc_part2->authorization_data[i]->length); + + /* check if it is a PAC */ + got_auth_data_pac = unwrap_pac(mem_ctx, &auth_data_wrapped, auth_data); + data_blob_free(&auth_data_wrapped); + + if (!got_auth_data_pac) { + continue; + } + } + + return got_auth_data_pac; + } + #else - if (tkt->ticket.authorization_data && tkt->ticket.authorization_data->len) - *auth_data = data_blob(tkt->ticket.authorization_data->val->ad_data.data, - tkt->ticket.authorization_data->val->ad_data.length); + if (tkt->ticket.authorization_data && + tkt->ticket.authorization_data->len) + { + for (i = 0; i < tkt->ticket.authorization_data->len; i++) { + + if (tkt->ticket.authorization_data->val[i].ad_type != + KRB5_AUTHDATA_IF_RELEVANT) { + DEBUG(10,("get_auth_data_from_tkt: ad_type is %d\n", + tkt->ticket.authorization_data->val[i].ad_type)); + continue; + } + + auth_data_wrapped = data_blob(tkt->ticket.authorization_data->val[i].ad_data.data, + tkt->ticket.authorization_data->val[i].ad_data.length); + + /* check if it is a PAC */ + got_auth_data_pac = unwrap_pac(mem_ctx, &auth_data_wrapped, auth_data); + data_blob_free(&auth_data_wrapped); + + if (!got_auth_data_pac) { + continue; + } + } + + return got_auth_data_pac; + } #endif + return False; } krb5_const_principal get_principal_from_tkt(krb5_ticket *tkt) @@ -435,7 +527,7 @@ cleanup_princ: get a kerberos5 ticket for the given service */ int cli_krb5_get_ticket(const char *principal, time_t time_offset, - DATA_BLOB *ticket, DATA_BLOB *session_key_krb5) + DATA_BLOB *ticket, DATA_BLOB *session_key_krb5, uint32 extra_ap_opts) { krb5_error_code retval; krb5_data packet; @@ -475,7 +567,7 @@ int cli_krb5_get_ticket(const char *principal, time_t time_offset, if ((retval = ads_krb5_mk_req(context, &auth_context, - AP_OPTS_USE_SUBKEY, + AP_OPTS_USE_SUBKEY | (krb5_flags)extra_ap_opts, principal, ccdef, &packet))) { goto failed; @@ -550,10 +642,349 @@ failed: #endif } +void smb_krb5_checksum_from_pac_sig(krb5_checksum *cksum, + PAC_SIGNATURE_DATA *sig) +{ +#ifdef HAVE_CHECKSUM_IN_KRB5_CHECKSUM + cksum->cksumtype = (krb5_cksumtype)sig->type; + cksum->checksum.length = sig->signature.buf_len; + cksum->checksum.data = sig->signature.buffer; +#else + cksum->checksum_type = (krb5_cksumtype)sig->type; + cksum->length = sig->signature.buf_len; + cksum->contents = sig->signature.buffer; +#endif +} + +krb5_error_code smb_krb5_verify_checksum(krb5_context context, + krb5_keyblock *keyblock, + krb5_keyusage usage, + krb5_checksum *cksum, + uint8 *data, + size_t length) +{ + krb5_error_code ret; + + /* verify the checksum */ + + /* welcome to the wonderful world of samba's kerberos abstraction layer: + * + * function heimdal 0.6.1rc3 heimdal 0.7 MIT krb 1.4.2 + * ----------------------------------------------------------------------------- + * krb5_c_verify_checksum - works works + * krb5_verify_checksum works (6 args) works (6 args) broken (7 args) + */ + +#if defined(HAVE_KRB5_C_VERIFY_CHECKSUM) + { + krb5_boolean checksum_valid = False; + krb5_data input; + + input.data = (char *)data; + input.length = length; + + ret = krb5_c_verify_checksum(context, + keyblock, + usage, + &input, + cksum, + &checksum_valid); + if (!checksum_valid) + ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; + } + +#elif KRB5_VERIFY_CHECKSUM_ARGS == 6 && defined(HAVE_KRB5_CRYPTO_INIT) && defined(HAVE_KRB5_CRYPTO) && defined(HAVE_KRB5_CRYPTO_DESTROY) + + /* Warning: MIT's krb5_verify_checksum cannot be used as it will use a key + * without enctype and it ignores any key_usage types - Guenther */ + + { + + krb5_crypto crypto; + ret = krb5_crypto_init(context, + keyblock, + 0, + &crypto); + if (ret) { + DEBUG(0,("smb_krb5_verify_checksum: krb5_crypto_init() failed: %s\n", + error_message(ret))); + return ret; + } + + ret = krb5_verify_checksum(context, + crypto, + usage, + data, + length, + cksum); + + krb5_crypto_destroy(context, crypto); + } + +#else +#error UNKNOWN_KRB5_VERIFY_CHECKSUM_FUNCTION +#endif + + return ret; +} + +time_t get_authtime_from_tkt(krb5_ticket *tkt) +{ +#if defined(HAVE_KRB5_TKT_ENC_PART2) + return tkt->enc_part2->times.authtime; +#else + return tkt->ticket.authtime; +#endif +} + +static int get_kvno_from_ap_req(krb5_ap_req *ap_req) +{ +#ifdef HAVE_TICKET_POINTER_IN_KRB5_AP_REQ /* MIT */ + if (ap_req->ticket->enc_part.kvno) + return ap_req->ticket->enc_part.kvno; +#else /* Heimdal */ + if (ap_req->ticket.enc_part.kvno) + return *ap_req->ticket.enc_part.kvno; +#endif + return 0; +} + +static krb5_enctype get_enctype_from_ap_req(krb5_ap_req *ap_req) +{ +#ifdef HAVE_ETYPE_IN_ENCRYPTEDDATA /* Heimdal */ + return ap_req->ticket.enc_part.etype; +#else /* MIT */ + return ap_req->ticket->enc_part.enctype; +#endif +} + +static krb5_error_code +get_key_from_keytab(krb5_context context, + krb5_keytab keytab, + krb5_const_principal server, + krb5_enctype enctype, + krb5_kvno kvno, + krb5_keyblock **out_key) +{ + krb5_keytab_entry entry; + krb5_error_code ret; + krb5_keytab real_keytab; + char *name = NULL; + + if (keytab == NULL) { + krb5_kt_default(context, &real_keytab); + } else { + real_keytab = keytab; + } + + if ( DEBUGLEVEL >= 10 ) { + krb5_unparse_name(context, server, &name); + DEBUG(10,("get_key_from_keytab: will look for kvno %d, enctype %d and name: %s\n", + kvno, enctype, name)); + krb5_free_unparsed_name(context, name); + } + + ret = krb5_kt_get_entry(context, + real_keytab, + server, + kvno, + enctype, + &entry); + + if (ret) { + DEBUG(0,("get_key_from_keytab: failed to retrieve key: %s\n", error_message(ret))); + goto out; + } + +#ifdef HAVE_KRB5_KEYTAB_ENTRY_KEYBLOCK /* Heimdal */ + ret = krb5_copy_keyblock(context, &entry.keyblock, out_key); +#elif defined(HAVE_KRB5_KEYTAB_ENTRY_KEY) /* MIT */ + ret = krb5_copy_keyblock(context, &entry.key, out_key); +#else +#error UNKNOWN_KRB5_KEYTAB_ENTRY_FORMAT +#endif + + if (ret) { + DEBUG(0,("get_key_from_keytab: failed to copy key: %s\n", error_message(ret))); + goto out; + } + + smb_krb5_kt_free_entry(context, &entry); + +out: + if (keytab == NULL) { + krb5_kt_close(context, real_keytab); + } + + return ret; +} + +void smb_krb5_free_ap_req(krb5_context context, + krb5_ap_req *ap_req) +{ +#ifdef HAVE_KRB5_FREE_AP_REQ /* MIT */ + krb5_free_ap_req(context, ap_req); +#elif defined(HAVE_FREE_AP_REQ) /* Heimdal */ + free_AP_REQ(ap_req); +#else +#error UNKNOWN_KRB5_AP_REQ_FREE_FUNCTION +#endif +} + +/* Prototypes */ +#if defined(HAVE_DECODE_KRB5_AP_REQ) /* MIT */ +krb5_error_code decode_krb5_ap_req(const krb5_data *code, krb5_ap_req **rep); +#endif + +krb5_error_code smb_krb5_get_keyinfo_from_ap_req(krb5_context context, + const krb5_data *inbuf, + krb5_kvno *kvno, + krb5_enctype *enctype) +{ + krb5_error_code ret; +#ifdef HAVE_KRB5_DECODE_AP_REQ /* Heimdal */ + { + krb5_ap_req ap_req; + + ret = krb5_decode_ap_req(context, inbuf, &ap_req); + if (ret) + return ret; + + *kvno = get_kvno_from_ap_req(&ap_req); + *enctype = get_enctype_from_ap_req(&ap_req); + + smb_krb5_free_ap_req(context, &ap_req); + } +#elif defined(HAVE_DECODE_KRB5_AP_REQ) /* MIT */ + { + krb5_ap_req *ap_req = NULL; + + ret = decode_krb5_ap_req(inbuf, &ap_req); + if (ret) + return ret; + + *kvno = get_kvno_from_ap_req(ap_req); + *enctype = get_enctype_from_ap_req(ap_req); + + smb_krb5_free_ap_req(context, ap_req); + } +#else +#error UNKOWN_KRB5_AP_REQ_DECODING_FUNCTION +#endif + return ret; +} + +krb5_error_code krb5_rd_req_return_keyblock_from_keytab(krb5_context context, + krb5_auth_context *auth_context, + const krb5_data *inbuf, + krb5_const_principal server, + krb5_keytab keytab, + krb5_flags *ap_req_options, + krb5_ticket **ticket, + krb5_keyblock **keyblock) +{ + krb5_error_code ret; + krb5_ap_req *ap_req = NULL; + krb5_kvno kvno; + krb5_enctype enctype; + krb5_keyblock *local_keyblock; + + ret = krb5_rd_req(context, + auth_context, + inbuf, + server, + keytab, + ap_req_options, + ticket); + if (ret) { + return ret; + } + + ret = smb_krb5_get_keyinfo_from_ap_req(context, inbuf, &kvno, &enctype); + if (ret) { + return ret; + } + + ret = get_key_from_keytab(context, + keytab, + server, + enctype, + kvno, + &local_keyblock); + if (ret) { + DEBUG(0,("krb5_rd_req_return_keyblock_from_keytab: failed to call get_key_from_keytab\n")); + goto out; + } + +out: + if (ap_req) { + smb_krb5_free_ap_req(context, ap_req); + } + + if (ret && local_keyblock != NULL) { + krb5_free_keyblock(context, local_keyblock); + } else { + *keyblock = local_keyblock; + } + + return ret; +} + +krb5_error_code smb_krb5_parse_name_norealm(krb5_context context, + const char *name, + krb5_principal *principal) +{ +#ifdef HAVE_KRB5_PARSE_NAME_NOREALM + return krb5_parse_name_norealm(context, name, principal); +#endif + + /* we are cheating here because parse_name will in fact set the realm. + * We don't care as the only caller of smb_krb5_parse_name_norealm + * ignores the realm anyway when calling + * smb_krb5_principal_compare_any_realm later - Guenther */ + + return krb5_parse_name(context, name, principal); +} + +BOOL smb_krb5_principal_compare_any_realm(krb5_context context, + krb5_const_principal princ1, + krb5_const_principal princ2) +{ +#ifdef HAVE_KRB5_PRINCIPAL_COMPARE_ANY_REALM + + return krb5_principal_compare_any_realm(context, princ1, princ2); + +/* krb5_princ_size is a macro in MIT */ +#elif defined(HAVE_KRB5_PRINC_SIZE) || defined(krb5_princ_size) + + int i, len1, len2; + const krb5_data *p1, *p2; + + len1 = krb5_princ_size(context, princ1); + len2 = krb5_princ_size(context, princ2); + + if (len1 != len2) + return False; + + for (i = 0; i < len1; i++) { + + p1 = krb5_princ_component(context, CONST_DISCARD(krb5_principal, princ1), i); + p2 = krb5_princ_component(context, CONST_DISCARD(krb5_principal, princ2), i); + + if (p1->length != p2->length || memcmp(p1->data, p2->data, p1->length)) + return False; + } + + return True; +#else +#error NO_SUITABLE_PRINCIPAL_COMPARE_FUNCTION +#endif +} + #else /* HAVE_KRB5 */ /* this saves a few linking headaches */ int cli_krb5_get_ticket(const char *principal, time_t time_offset, - DATA_BLOB *ticket, DATA_BLOB *session_key_krb5) + DATA_BLOB *ticket, DATA_BLOB *session_key_krb5, uint32 extra_ap_opts) { DEBUG(0,("NO KERBEROS SUPPORT\n")); return 1; diff --git a/source3/libsmb/clireadwrite.c b/source3/libsmb/clireadwrite.c index 1220907629..55e36b646b 100644 --- a/source3/libsmb/clireadwrite.c +++ b/source3/libsmb/clireadwrite.c @@ -323,13 +323,13 @@ static BOOL cli_issue_write(struct cli_state *cli, int fnum, off_t offset, 0x0008 start of message mode named pipe protocol ****************************************************************************/ -size_t cli_write(struct cli_state *cli, +ssize_t cli_write(struct cli_state *cli, int fnum, uint16 write_mode, const char *buf, off_t offset, size_t size) { - int bwritten = 0; - int issued = 0; - int received = 0; + ssize_t bwritten = 0; + unsigned int issued = 0; + unsigned int received = 0; int mpx = 1; int block = cli->max_xmit - (smb_size+32); int blocks = (size + (block-1)) / block; @@ -343,8 +343,8 @@ size_t cli_write(struct cli_state *cli, while (received < blocks) { while ((issued - received < mpx) && (issued < blocks)) { - int bsent = issued * block; - int size1 = MIN(block, size - bsent); + ssize_t bsent = issued * block; + ssize_t size1 = MIN(block, size - bsent); if (!cli_issue_write(cli, fnum, offset + bsent, write_mode, diff --git a/source3/libsmb/clispnego.c b/source3/libsmb/clispnego.c index 85b7bd9e1e..33fc265f79 100644 --- a/source3/libsmb/clispnego.c +++ b/source3/libsmb/clispnego.c @@ -325,14 +325,15 @@ BOOL spnego_parse_krb5_wrap(DATA_BLOB blob, DATA_BLOB *ticket, uint8 tok_id[2]) */ int spnego_gen_negTokenTarg(const char *principal, int time_offset, DATA_BLOB *targ, - DATA_BLOB *session_key_krb5) + DATA_BLOB *session_key_krb5, uint32 extra_ap_opts) { int retval; DATA_BLOB tkt, tkt_wrapped; const char *krb_mechs[] = {OID_KERBEROS5_OLD, OID_NTLMSSP, NULL}; /* get a kerberos ticket for the service and extract the session key */ - retval = cli_krb5_get_ticket(principal, time_offset, &tkt, session_key_krb5); + retval = cli_krb5_get_ticket(principal, time_offset, + &tkt, session_key_krb5, extra_ap_opts); if (retval) return retval; diff --git a/source3/libsmb/clitrans.c b/source3/libsmb/clitrans.c index c6b1d465ff..5d3710b92e 100644 --- a/source3/libsmb/clitrans.c +++ b/source3/libsmb/clitrans.c @@ -464,8 +464,8 @@ BOOL cli_send_nt_trans(struct cli_state *cli, } /**************************************************************************** - receive a SMB nttrans response allocating the necessary memory - ****************************************************************************/ + Receive a SMB nttrans response allocating the necessary memory. +****************************************************************************/ BOOL cli_receive_nt_trans(struct cli_state *cli, char **param, unsigned int *param_len, @@ -503,7 +503,7 @@ BOOL cli_receive_nt_trans(struct cli_state *cli, */ if (cli_is_dos_error(cli)) { cli_dos_error(cli, &eclass, &ecode); - if (cli->pipes[cli->pipe_idx].fnum == 0 || !(eclass == ERRDOS && ecode == ERRmoredata)) { + if (!(eclass == ERRDOS && ecode == ERRmoredata)) { cli_signing_trans_stop(cli); return(False); } @@ -637,11 +637,22 @@ BOOL cli_receive_nt_trans(struct cli_state *cli, } if (cli_is_dos_error(cli)) { cli_dos_error(cli, &eclass, &ecode); - if(cli->pipes[cli->pipe_idx].fnum == 0 || !(eclass == ERRDOS && ecode == ERRmoredata)) { + if(!(eclass == ERRDOS && ecode == ERRmoredata)) { + cli_signing_trans_stop(cli); + return(False); + } + } + /* + * Likewise for NT_STATUS_BUFFER_TOO_SMALL + */ + if (cli_is_nt_error(cli)) { + if (!NT_STATUS_EQUAL(cli_nt_error(cli), + NT_STATUS_BUFFER_TOO_SMALL)) { cli_signing_trans_stop(cli); return(False); } } + /* parse out the total lengths again - they can shrink! */ if (SVAL(cli->inbuf,smb_ntr_TotalDataCount) < total_data) total_data = SVAL(cli->inbuf,smb_ntr_TotalDataCount); diff --git a/source3/libsmb/credentials.c b/source3/libsmb/credentials.c index 0d521bae8a..3f2dcd850b 100644 --- a/source3/libsmb/credentials.c +++ b/source3/libsmb/credentials.c @@ -2,6 +2,7 @@ Unix SMB/CIFS implementation. code to manipulate domain credentials Copyright (C) Andrew Tridgell 1997-1998 + Largely rewritten by Jeremy Allison 2005. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -21,8 +22,9 @@ #include "includes.h" /**************************************************************************** -represent a credential as a string + Represent a credential as a string. ****************************************************************************/ + char *credstr(const uchar *cred) { static fstring buf; @@ -34,182 +36,243 @@ char *credstr(const uchar *cred) /**************************************************************************** - setup the session key. -Input: 8 byte challenge block + Setup the session key. + Input: 8 byte challenge block 8 byte server challenge block 16 byte md4 encrypted password -Output: - 8 byte session key + Output: + 16 byte session key (last 8 bytes zero). ****************************************************************************/ -void cred_session_key(const DOM_CHAL *clnt_chal, const DOM_CHAL *srv_chal, const uchar *pass, - uchar session_key[8]) + +static void cred_create_session_key(const DOM_CHAL *clnt_chal_in, + const DOM_CHAL *srv_chal_in, + const uchar *pass_in, + uchar session_key_out[16]) { uint32 sum[2]; unsigned char sum2[8]; - sum[0] = IVAL(clnt_chal->data, 0) + IVAL(srv_chal->data, 0); - sum[1] = IVAL(clnt_chal->data, 4) + IVAL(srv_chal->data, 4); + sum[0] = IVAL(clnt_chal_in->data, 0) + IVAL(srv_chal_in->data, 0); + sum[1] = IVAL(clnt_chal_in->data, 4) + IVAL(srv_chal_in->data, 4); SIVAL(sum2,0,sum[0]); SIVAL(sum2,4,sum[1]); - cred_hash1(session_key, sum2, pass); + cred_hash1(session_key_out, sum2, pass_in); + memset(&session_key_out[8], '\0', 8); /* debug output */ - DEBUG(4,("cred_session_key\n")); + DEBUG(4,("cred_create_session_key\n")); - DEBUG(5,(" clnt_chal: %s\n", credstr(clnt_chal->data))); - DEBUG(5,(" srv_chal : %s\n", credstr(srv_chal->data))); + DEBUG(5,(" clnt_chal_in: %s\n", credstr(clnt_chal_in->data))); + DEBUG(5,(" srv_chal_in : %s\n", credstr(srv_chal_in->data))); DEBUG(5,(" clnt+srv : %s\n", credstr(sum2))); - DEBUG(5,(" sess_key : %s\n", credstr(session_key))); + DEBUG(5,(" sess_key_out : %s\n", credstr(session_key_out))); } - /**************************************************************************** -create a credential - -Input: - 8 byte sesssion key - 8 byte stored credential - 4 byte timestamp - -Output: - 8 byte credential + Utility function to step credential chain one forward. + Deliberately doesn't update the seed. See reseed comment below. ****************************************************************************/ -void cred_create(uchar session_key[8], DOM_CHAL *stor_cred, UTIME timestamp, - DOM_CHAL *cred) + +static void creds_step(struct dcinfo *dc) { - DOM_CHAL time_cred; + DOM_CHAL time_chal; - SIVAL(time_cred.data, 0, IVAL(stor_cred->data, 0) + timestamp.time); - SIVAL(time_cred.data, 4, IVAL(stor_cred->data, 4)); + DEBUG(5,("\tsequence = 0x%x\n", (unsigned int)dc->sequence )); - cred_hash2(cred->data, time_cred.data, session_key); + DEBUG(5,("\tseed: %s\n", credstr(dc->seed_chal.data) )); - /* debug output*/ - DEBUG(4,("cred_create\n")); + SIVAL(time_chal.data, 0, IVAL(dc->seed_chal.data, 0) + dc->sequence); + SIVAL(time_chal.data, 4, IVAL(dc->seed_chal.data, 4)); + + DEBUG(5,("\tseed+seq %s\n", credstr(time_chal.data) )); - DEBUG(5,(" sess_key : %s\n", credstr(session_key))); - DEBUG(5,(" stor_cred: %s\n", credstr(stor_cred->data))); - DEBUG(5,(" timestamp: %x\n" , timestamp.time)); - DEBUG(5,(" timecred : %s\n", credstr(time_cred.data))); - DEBUG(5,(" calc_cred: %s\n", credstr(cred->data))); -} + cred_hash2(dc->clnt_chal.data, time_chal.data, dc->sess_key); + DEBUG(5,("\tCLIENT %s\n", credstr(dc->clnt_chal.data) )); -/**************************************************************************** - check a supplied credential + SIVAL(time_chal.data, 0, IVAL(dc->seed_chal.data, 0) + dc->sequence + 1); + SIVAL(time_chal.data, 4, IVAL(dc->seed_chal.data, 4)); + + DEBUG(5,("\tseed+seq+1 %s\n", credstr(time_chal.data) )); -Input: - 8 byte received credential - 8 byte sesssion key - 8 byte stored credential - 4 byte timestamp + cred_hash2(dc->srv_chal.data, time_chal.data, dc->sess_key); + + DEBUG(5,("\tSERVER %s\n", credstr(dc->srv_chal.data) )); +} -Output: - returns 1 if computed credential matches received credential - returns 0 otherwise + +/**************************************************************************** + Create a server credential struct. ****************************************************************************/ -int cred_assert(DOM_CHAL *cred, uchar session_key[8], DOM_CHAL *stored_cred, - UTIME timestamp) + +void creds_server_init(struct dcinfo *dc, + DOM_CHAL *clnt_chal, + DOM_CHAL *srv_chal, + const char mach_pw[16], + DOM_CHAL *init_chal_out) { - DOM_CHAL cred2; + DEBUG(10,("creds_server_init: client chal : %s\n", credstr(clnt_chal->data) )); + DEBUG(10,("creds_server_init: server chal : %s\n", credstr(srv_chal->data) )); + dump_data_pw("creds_server_init: machine pass", mach_pw, 16); - cred_create(session_key, stored_cred, timestamp, &cred2); + /* Just in case this isn't already there */ + memcpy(dc->mach_pw, mach_pw, 16); - /* debug output*/ - DEBUG(4,("cred_assert\n")); + /* Generate the session key. */ + cred_create_session_key(clnt_chal, /* Stored client challenge. */ + srv_chal, /* Stored server challenge. */ + dc->mach_pw, /* input machine password. */ + dc->sess_key); /* output session key. */ - DEBUG(5,(" challenge : %s\n", credstr(cred->data))); - DEBUG(5,(" calculated: %s\n", credstr(cred2.data))); + dump_data_pw("creds_server_init: session key", dc->sess_key, 16); - if (memcmp(cred->data, cred2.data, 8) == 0) - { - DEBUG(5, ("credentials check ok\n")); - return True; - } - else - { - DEBUG(5, ("credentials check wrong\n")); + /* Generate the next client and server creds. */ + cred_hash2(dc->clnt_chal.data, /* output */ + clnt_chal->data, /* input */ + dc->sess_key); /* input */ + + cred_hash2(dc->srv_chal.data, /* output */ + srv_chal->data, /* input */ + dc->sess_key); /* input */ + + /* Seed is the client chal. */ + memcpy(dc->seed_chal.data, dc->clnt_chal.data, 8); + + DEBUG(10,("creds_server_init: clnt : %s\n", credstr(dc->clnt_chal.data) )); + DEBUG(10,("creds_server_init: server : %s\n", credstr(dc->srv_chal.data) )); + DEBUG(10,("creds_server_init: seed : %s\n", credstr(dc->seed_chal.data) )); + + memcpy(init_chal_out->data, dc->srv_chal.data, 8); +} + +/**************************************************************************** + Check a credential sent by the client. +****************************************************************************/ + +BOOL creds_server_check(const struct dcinfo *dc, const DOM_CHAL *rcv_cli_chal_in) +{ + if (memcmp(dc->clnt_chal.data, rcv_cli_chal_in->data, 8)) { + DEBUG(5,("creds_server_check: challenge : %s\n", credstr(rcv_cli_chal_in->data))); + DEBUG(5,("calculated: %s\n", credstr(dc->clnt_chal.data))); + DEBUG(0,("creds_server_check: credentials check failed.\n")); return False; } + DEBUG(10,("creds_server_check: credentials check OK.\n")); + return True; } - /**************************************************************************** - checks credentials; generates next step in the credential chain + Replace current seed chal. Internal function - due to split server step below. ****************************************************************************/ -BOOL clnt_deal_with_creds(uchar sess_key[8], - DOM_CRED *sto_clnt_cred, DOM_CRED *rcv_srv_cred) + +static void creds_reseed(struct dcinfo *dc) { - UTIME new_clnt_time; - uint32 new_cred; + DOM_CHAL time_chal; - DEBUG(5,("clnt_deal_with_creds: %d\n", __LINE__)); + SIVAL(time_chal.data, 0, IVAL(dc->seed_chal.data, 0) + dc->sequence + 1); + SIVAL(time_chal.data, 4, IVAL(dc->seed_chal.data, 4)); - /* increment client time by one second */ - new_clnt_time.time = sto_clnt_cred->timestamp.time + 1; + dc->seed_chal = time_chal; - /* check that the received server credentials are valid */ - if (!cred_assert(&rcv_srv_cred->challenge, sess_key, - &sto_clnt_cred->challenge, new_clnt_time)) - { - return False; - } + DEBUG(5,("cred_reseed: seed %s\n", credstr(dc->seed_chal.data) )); +} - /* first 4 bytes of the new seed is old client 4 bytes + clnt time + 1 */ - new_cred = IVAL(sto_clnt_cred->challenge.data, 0); - new_cred += new_clnt_time.time; +/**************************************************************************** + Step the server credential chain one forward. +****************************************************************************/ - /* store new seed in client credentials */ - SIVAL(sto_clnt_cred->challenge.data, 0, new_cred); +BOOL creds_server_step(struct dcinfo *dc, const DOM_CRED *received_cred, DOM_CRED *cred_out) +{ + dc->sequence = received_cred->timestamp.time; - DEBUG(5,(" new clnt cred: %s\n", credstr(sto_clnt_cred->challenge.data))); - return True; -} + creds_step(dc); + + /* Create the outgoing credentials */ + cred_out->timestamp.time = dc->sequence + 1; + cred_out->challenge = dc->srv_chal; + creds_reseed(dc); + + return creds_server_check(dc, &received_cred->challenge); +} /**************************************************************************** - checks credentials; generates next step in the credential chain + Create a client credential struct. ****************************************************************************/ -BOOL deal_with_creds(uchar sess_key[8], - DOM_CRED *sto_clnt_cred, - DOM_CRED *rcv_clnt_cred, DOM_CRED *rtn_srv_cred) + +void creds_client_init(struct dcinfo *dc, + DOM_CHAL *clnt_chal, + DOM_CHAL *srv_chal, + const char mach_pw[16], + DOM_CHAL *init_chal_out) { - UTIME new_clnt_time; - uint32 new_cred; + dc->sequence = time(NULL); - DEBUG(5,("deal_with_creds: %d\n", __LINE__)); + DEBUG(10,("creds_client_init: client chal : %s\n", credstr(clnt_chal->data) )); + DEBUG(10,("creds_client_init: server chal : %s\n", credstr(srv_chal->data) )); + dump_data_pw("creds_client_init: machine pass", mach_pw, 16); - /* check that the received client credentials are valid */ - if (!cred_assert(&rcv_clnt_cred->challenge, sess_key, - &sto_clnt_cred->challenge, rcv_clnt_cred->timestamp)) - { - return False; - } + /* Just in case this isn't already there */ + memcpy(dc->mach_pw, mach_pw, 16); - /* increment client time by one second */ - new_clnt_time.time = rcv_clnt_cred->timestamp.time + 1; + /* Generate the session key. */ + cred_create_session_key(clnt_chal, /* Stored client challenge. */ + srv_chal, /* Stored server challenge. */ + dc->mach_pw, /* input machine password. */ + dc->sess_key); /* output session key. */ - /* first 4 bytes of the new seed is old client 4 bytes + clnt time + 1 */ - new_cred = IVAL(sto_clnt_cred->challenge.data, 0); - new_cred += new_clnt_time.time; + dump_data_pw("creds_client_init: session key", dc->sess_key, 16); - DEBUG(5,("deal_with_creds: new_cred[0]=%x\n", new_cred)); + /* Generate the next client and server creds. */ + cred_hash2(dc->clnt_chal.data, /* output */ + clnt_chal->data, /* input */ + dc->sess_key); /* input */ - /* doesn't matter that server time is 0 */ - rtn_srv_cred->timestamp.time = 0; + cred_hash2(dc->srv_chal.data, /* output */ + srv_chal->data, /* input */ + dc->sess_key); /* input */ - DEBUG(5,("deal_with_creds: new_clnt_time=%x\n", new_clnt_time.time)); + /* Seed is the client cred. */ + memcpy(dc->seed_chal.data, dc->clnt_chal.data, 8); - /* create return credentials for inclusion in the reply */ - cred_create(sess_key, &sto_clnt_cred->challenge, new_clnt_time, - &rtn_srv_cred->challenge); - - DEBUG(5,("deal_with_creds: clnt_cred=%s\n", credstr(sto_clnt_cred->challenge.data))); + DEBUG(10,("creds_client_init: clnt : %s\n", credstr(dc->clnt_chal.data) )); + DEBUG(10,("creds_client_init: server : %s\n", credstr(dc->srv_chal.data) )); + DEBUG(10,("creds_client_init: seed : %s\n", credstr(dc->seed_chal.data) )); - /* store new seed in client credentials */ - SIVAL(sto_clnt_cred->challenge.data, 0, new_cred); + memcpy(init_chal_out->data, dc->clnt_chal.data, 8); +} + +/**************************************************************************** + Check a credential returned by the server. +****************************************************************************/ +BOOL creds_client_check(const struct dcinfo *dc, const DOM_CHAL *rcv_srv_chal_in) +{ + if (memcmp(dc->srv_chal.data, rcv_srv_chal_in->data, 8)) { + DEBUG(5,("creds_client_check: challenge : %s\n", credstr(rcv_srv_chal_in->data))); + DEBUG(5,("calculated: %s\n", credstr(dc->srv_chal.data))); + DEBUG(0,("creds_client_check: credentials check failed.\n")); + return False; + } + DEBUG(10,("creds_client_check: credentials check OK.\n")); return True; } + +/**************************************************************************** + Step the client credentials to the next element in the chain, updating the + current client and server credentials and the seed + produce the next authenticator in the sequence ready to send to + the server +****************************************************************************/ + +void creds_client_step(struct dcinfo *dc, DOM_CRED *next_cred_out) +{ + dc->sequence += 2; + creds_step(dc); + creds_reseed(dc); + + next_cred_out->challenge = dc->clnt_chal; + next_cred_out->timestamp.time = dc->sequence; +} diff --git a/source3/libsmb/errormap.c b/source3/libsmb/errormap.c index 8462fbee87..3c0b13ad6f 100644 --- a/source3/libsmb/errormap.c +++ b/source3/libsmb/errormap.c @@ -62,7 +62,7 @@ static const struct { {ERRDOS, 193, NT_STATUS_BAD_INITIAL_PC}, {ERRDOS, 87, NT_STATUS_INVALID_CID}, {ERRHRD, ERRgeneral, NT_STATUS_TIMER_NOT_CANCELED}, - {ERRDOS, 87, NT_STATUS_INVALID_PARAMETER}, + {ERRDOS, ERRinvalidparam, NT_STATUS_INVALID_PARAMETER}, {ERRDOS, ERRbadfile, NT_STATUS_NO_SUCH_DEVICE}, {ERRDOS, ERRbadfile, NT_STATUS_NO_SUCH_FILE}, {ERRDOS, ERRbadfunc, NT_STATUS_INVALID_DEVICE_REQUEST}, @@ -338,7 +338,7 @@ static const struct { {ERRDOS, 203, NT_STATUS(0xc0000100)}, {ERRDOS, 145, NT_STATUS_DIRECTORY_NOT_EMPTY}, {ERRHRD, ERRgeneral, NT_STATUS_FILE_CORRUPT_ERROR}, - {ERRDOS, 267, NT_STATUS_NOT_A_DIRECTORY}, + {ERRDOS, ERRbaddirectory, NT_STATUS_NOT_A_DIRECTORY}, {ERRHRD, ERRgeneral, NT_STATUS_BAD_LOGON_SESSION_STATE}, {ERRHRD, ERRgeneral, NT_STATUS_LOGON_SESSION_COLLISION}, {ERRDOS, 206, NT_STATUS_NAME_TOO_LONG}, diff --git a/source3/libsmb/libsmb_compat.c b/source3/libsmb/libsmb_compat.c index f9461f9368..5699e153bb 100644 --- a/source3/libsmb/libsmb_compat.c +++ b/source3/libsmb/libsmb_compat.c @@ -420,7 +420,7 @@ int smbc_open_print_job(const char *fname) { SMBCFILE * file = statcont->open_print_job(statcont, fname); if (!file) return -1; - return (int) file; + return file->cli_fd; } int smbc_list_print_jobs(const char *purl, smbc_list_print_job_fn fn) diff --git a/source3/libsmb/libsmbclient.c b/source3/libsmb/libsmbclient.c index fe8f878aa5..1e729abb22 100644 --- a/source3/libsmb/libsmbclient.c +++ b/source3/libsmb/libsmbclient.c @@ -80,6 +80,23 @@ static int DLIST_CONTAINS(SMBCFILE * list, SMBCFILE *p) { return False; } +/* + * Find an lsa pipe handle associated with a cli struct. + */ + +static struct rpc_pipe_client *find_lsa_pipe_hnd(struct cli_state *ipc_cli) +{ + struct rpc_pipe_client *pipe_hnd; + + for (pipe_hnd = ipc_cli->pipe_list; pipe_hnd; pipe_hnd = pipe_hnd->next) { + if (pipe_hnd->pipe_idx == PI_LSARPC) { + return pipe_hnd; + } + } + + return NULL; +} + static int smbc_close_ctx(SMBCCTX *context, SMBCFILE *file); static off_t smbc_lseek_ctx(SMBCCTX *context, SMBCFILE *file, off_t offset, int whence); @@ -800,6 +817,7 @@ SMBCSRV *smbc_attr_server(SMBCCTX *context, { struct in_addr ip; struct cli_state *ipc_cli; + struct rpc_pipe_client *pipe_hnd; NTSTATUS nt_status; SMBCSRV *ipc_srv=NULL; @@ -835,29 +853,27 @@ SMBCSRV *smbc_attr_server(SMBCCTX *context, return NULL; } - if(pol) { + pipe_hnd = cli_rpc_pipe_open_noauth(ipc_cli, PI_LSARPC, &nt_status); + if (!pipe_hnd) { + DEBUG(1, ("cli_nt_session_open fail!\n")); + errno = ENOTSUP; + cli_shutdown(ipc_cli); + return NULL; + } - if (!cli_nt_session_open(ipc_cli, PI_LSARPC)) { - DEBUG(1, ("cli_nt_session_open fail!\n")); - errno = ENOTSUP; - cli_shutdown(ipc_cli); - return NULL; - } - - /* Some systems don't support SEC_RIGHTS_MAXIMUM_ALLOWED, - but NT sends 0x2000000 so we might as well do it too. */ - - nt_status = cli_lsa_open_policy(ipc_cli, - ipc_cli->mem_ctx, - True, - GENERIC_EXECUTE_ACCESS, - pol); - - if (!NT_STATUS_IS_OK(nt_status)) { - errno = smbc_errno(context, ipc_cli); - cli_shutdown(ipc_cli); - return NULL; - } + /* Some systems don't support SEC_RIGHTS_MAXIMUM_ALLOWED, + but NT sends 0x2000000 so we might as well do it too. */ + + nt_status = rpccli_lsa_open_policy(pipe_hnd, + ipc_cli->mem_ctx, + True, + GENERIC_EXECUTE_ACCESS, + pol); + + if (!NT_STATUS_IS_OK(nt_status)) { + errno = smbc_errno(context, ipc_cli); + cli_shutdown(ipc_cli); + return NULL; } ipc_srv = SMB_MALLOC_P(SMBCSRV); @@ -1782,7 +1798,7 @@ static off_t smbc_lseek_ctx(SMBCCTX *context, SMBCFILE *file, off_t offset, int if (!cli_qfileinfo(targetcli, file->cli_fd, NULL, &size, NULL, NULL, NULL, NULL, NULL)) { - SMB_BIG_UINT b_size = size; + SMB_OFF_T b_size = size; if (!cli_getattrE(targetcli, file->cli_fd, NULL, &b_size, NULL, NULL, NULL)) { @@ -3041,7 +3057,7 @@ static off_t smbc_telldir_ctx(SMBCCTX *context, SMBCFILE *dir) /* * We return the pointer here as the offset */ - ret_val = (int)dir->dir_next; + ret_val = (off_t)(long)dir->dir_next; return ret_val; } @@ -3347,14 +3363,20 @@ static void convert_sid_to_string(struct cli_state *ipc_cli, char **domains = NULL; char **names = NULL; uint32 *types = NULL; - + struct rpc_pipe_client *pipe_hnd = find_lsa_pipe_hnd(ipc_cli); sid_to_string(str, sid); - if (numeric) return; /* no lookup desired */ - + if (numeric) { + return; /* no lookup desired */ + } + + if (!pipe_hnd) { + return; + } + /* Ask LSA to convert the sid to a name */ - if (!NT_STATUS_IS_OK(cli_lsa_lookup_sids(ipc_cli, ipc_cli->mem_ctx, + if (!NT_STATUS_IS_OK(rpccli_lsa_lookup_sids(pipe_hnd, ipc_cli->mem_ctx, pol, 1, sid, &domains, &names, &types)) || !domains || !domains[0] || !names || !names[0]) { @@ -3378,6 +3400,11 @@ static BOOL convert_string_to_sid(struct cli_state *ipc_cli, uint32 *types = NULL; DOM_SID *sids = NULL; BOOL result = True; + struct rpc_pipe_client *pipe_hnd = find_lsa_pipe_hnd(ipc_cli); + + if (!pipe_hnd) { + return False; + } if (numeric) { if (strncmp(str, "S-", 2) == 0) { @@ -3388,7 +3415,7 @@ static BOOL convert_string_to_sid(struct cli_state *ipc_cli, goto done; } - if (!NT_STATUS_IS_OK(cli_lsa_lookup_names(ipc_cli, ipc_cli->mem_ctx, + if (!NT_STATUS_IS_OK(rpccli_lsa_lookup_names(pipe_hnd, ipc_cli->mem_ctx, pol, 1, &str, &sids, &types))) { result = False; @@ -5161,7 +5188,7 @@ static int smbc_print_file_ctx(SMBCCTX *c_file, const char *fname, SMBCCTX *c_pr /* Try to open the file for reading ... */ - if ((int)(fid1 = c_file->open(c_file, fname, O_RDONLY, 0666)) < 0) { + if ((long)(fid1 = c_file->open(c_file, fname, O_RDONLY, 0666)) < 0) { DEBUG(3, ("Error, fname=%s, errno=%i\n", fname, errno)); return -1; /* smbc_open sets errno */ @@ -5170,7 +5197,7 @@ static int smbc_print_file_ctx(SMBCCTX *c_file, const char *fname, SMBCCTX *c_pr /* Now, try to open the printer file for writing */ - if ((int)(fid2 = c_print->open_print_job(c_print, printq)) < 0) { + if ((long)(fid2 = c_print->open_print_job(c_print, printq)) < 0) { saverr = errno; /* Save errno */ c_file->close_fn(c_file, fid1); diff --git a/source3/libsmb/ntlmssp.c b/source3/libsmb/ntlmssp.c index b02c2384a8..6b551e8774 100644 --- a/source3/libsmb/ntlmssp.c +++ b/source3/libsmb/ntlmssp.c @@ -5,6 +5,7 @@ Copyright (C) Andrew Tridgell 2001 Copyright (C) Andrew Bartlett 2001-2003 + Copyright (C) Andrew Bartlett 2005 (Updated from gensec). This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -217,6 +218,12 @@ NTSTATUS ntlmssp_update(NTLMSSP_STATE *ntlmssp_state, uint32 ntlmssp_command; int i; + if (ntlmssp_state->expected_state == NTLMSSP_DONE) { + /* Called update after negotiations finished. */ + DEBUG(1, ("Called NTLMSSP after state machine was 'done'\n")); + return NT_STATUS_INVALID_PARAMETER; + } + *out = data_blob(NULL, 0); if (!in.length && ntlmssp_state->stored_response.length) { @@ -348,6 +355,13 @@ static void ntlmssp_handle_neg_flags(struct ntlmssp_state *ntlmssp_state, if (!(neg_flags & NTLMSSP_NEGOTIATE_128)) { ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_128; + if (neg_flags & NTLMSSP_NEGOTIATE_56) { + ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_56; + } + } + + if (!(neg_flags & NTLMSSP_NEGOTIATE_56)) { + ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_56; } if (!(neg_flags & NTLMSSP_NEGOTIATE_KEY_EXCH)) { @@ -360,6 +374,34 @@ static void ntlmssp_handle_neg_flags(struct ntlmssp_state *ntlmssp_state, } +/** + Weaken NTLMSSP keys to cope with down-level clients and servers. + + We probably should have some parameters to control this, but as + it only occours for LM_KEY connections, and this is controlled + by the client lanman auth/lanman auth parameters, it isn't too bad. +*/ + +void ntlmssp_weaken_keys(NTLMSSP_STATE *ntlmssp_state) +{ + /* Key weakening not performed on the master key for NTLM2 + and does not occour for NTLM1. Therefore we only need + to do this for the LM_KEY. + */ + + if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_LM_KEY) { + if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_128) { + ; + } else if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_56) { + ntlmssp_state->session_key.data[7] = 0xa0; + } else { /* forty bits */ + ntlmssp_state->session_key.data[5] = 0xe5; + ntlmssp_state->session_key.data[6] = 0x38; + ntlmssp_state->session_key.data[7] = 0xb0; + } + ntlmssp_state->session_key.length = 8; + } +} /** * Next state function for the Negotiate packet @@ -398,6 +440,9 @@ static NTSTATUS ntlmssp_server_negotiate(struct ntlmssp_state *ntlmssp_state, return NT_STATUS_INVALID_PARAMETER; } + DEBUG(10, ("ntlmssp_server_negotiate: client = %s, domain = %s\n", + cliname ? cliname : "", domname ? domname : "")); + SAFE_FREE(cliname); SAFE_FREE(domname); @@ -495,7 +540,7 @@ static NTSTATUS ntlmssp_server_auth(struct ntlmssp_state *ntlmssp_state, DATA_BLOB lm_session_key = data_blob(NULL, 0); DATA_BLOB session_key = data_blob(NULL, 0); uint32 ntlmssp_command, auth_flags; - NTSTATUS nt_status; + NTSTATUS nt_status = NT_STATUS_OK; /* used by NTLM2 */ BOOL doing_ntlm2 = False; @@ -639,6 +684,9 @@ static NTSTATUS ntlmssp_server_auth(struct ntlmssp_state *ntlmssp_state, data_blob_free(&encrypted_session_key); return nt_status; } + + /* LM Key is incompatible. */ + ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_LM_KEY; } } @@ -710,11 +758,11 @@ static NTSTATUS ntlmssp_server_auth(struct ntlmssp_state *ntlmssp_state, if (!encrypted_session_key.data || encrypted_session_key.length != 16) { data_blob_free(&encrypted_session_key); DEBUG(1, ("Client-supplied KEY_EXCH session key was of invalid length (%u)!\n", - encrypted_session_key.length)); + (unsigned int)encrypted_session_key.length)); return NT_STATUS_INVALID_PARAMETER; } else if (!session_key.data || session_key.length != 16) { DEBUG(5, ("server session key is invalid (len == %u), cannot do KEY_EXCH!\n", - session_key.length)); + (unsigned int)session_key.length)); ntlmssp_state->session_key = session_key; } else { dump_data_pw("KEY_EXCH session key (enc):\n", encrypted_session_key.data, encrypted_session_key.length); @@ -731,6 +779,9 @@ static NTSTATUS ntlmssp_server_auth(struct ntlmssp_state *ntlmssp_state, ntlmssp_state->session_key = session_key; } + /* The client might need us to use a partial-strength session key */ + ntlmssp_weaken_keys(ntlmssp_state); + if (!NT_STATUS_IS_OK(nt_status)) { ntlmssp_state->session_key = data_blob(NULL, 0); } else if (ntlmssp_state->session_key.length) { @@ -739,8 +790,8 @@ static NTSTATUS ntlmssp_server_auth(struct ntlmssp_state *ntlmssp_state, data_blob_free(&encrypted_session_key); - /* allow arbitarily many authentications */ - ntlmssp_state->expected_state = NTLMSSP_AUTH; + /* Only one authentication allowed per server state. */ + ntlmssp_state->expected_state = NTLMSSP_DONE; return nt_status; } @@ -784,7 +835,8 @@ NTSTATUS ntlmssp_server_start(NTLMSSP_STATE **ntlmssp_state) NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_NTLM2 | NTLMSSP_NEGOTIATE_KEY_EXCH | - NTLMSSP_NEGOTIATE_SIGN; + NTLMSSP_NEGOTIATE_SIGN | + NTLMSSP_NEGOTIATE_SEAL; return NT_STATUS_OK; } @@ -851,7 +903,7 @@ static NTSTATUS ntlmssp_client_challenge(struct ntlmssp_state *ntlmssp_state, DATA_BLOB nt_response = data_blob(NULL, 0); DATA_BLOB session_key = data_blob(NULL, 0); DATA_BLOB encrypted_session_key = data_blob(NULL, 0); - NTSTATUS nt_status; + NTSTATUS nt_status = NT_STATUS_OK; if (!msrpc_parse(&reply, "CdBd", "NTLMSSP", @@ -977,8 +1029,6 @@ static NTSTATUS ntlmssp_client_challenge(struct ntlmssp_state *ntlmssp_state, hmac_md5(user_session_key, session_nonce, sizeof(session_nonce), session_key.data); dump_data_pw("NTLM2 session key:\n", session_key.data, session_key.length); } else { - - uchar lm_hash[16]; uchar nt_hash[16]; E_deshash(ntlmssp_state->password, lm_hash); @@ -998,8 +1048,8 @@ static NTSTATUS ntlmssp_client_challenge(struct ntlmssp_state *ntlmssp_state, session_key = data_blob_talloc(ntlmssp_state->mem_ctx, NULL, 16); if ((ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_LM_KEY) && lp_client_lanman_auth()) { - SMBsesskeygen_lmv1(lm_hash, lm_response.data, - session_key.data); + SMBsesskeygen_lm_sess_key(lm_hash, lm_response.data, + session_key.data); dump_data_pw("LM session key\n", session_key.data, session_key.length); } else { SMBsesskeygen_ntv1(nt_hash, NULL, session_key.data); @@ -1045,19 +1095,22 @@ static NTSTATUS ntlmssp_client_challenge(struct ntlmssp_state *ntlmssp_state, data_blob_free(&ntlmssp_state->chal); + ntlmssp_state->session_key = session_key; + + /* The client might be using 56 or 40 bit weakened keys */ + ntlmssp_weaken_keys(ntlmssp_state); + ntlmssp_state->chal = challenge_blob; ntlmssp_state->lm_resp = lm_response; ntlmssp_state->nt_resp = nt_response; - ntlmssp_state->session_key = session_key; - ntlmssp_state->expected_state = NTLMSSP_UNKNOWN; + ntlmssp_state->expected_state = NTLMSSP_DONE; if (!NT_STATUS_IS_OK(nt_status = ntlmssp_sign_init(ntlmssp_state))) { DEBUG(1, ("Could not setup NTLMSSP signing/sealing system (error was: %s)\n", nt_errstr(nt_status))); - return nt_status; } - return NT_STATUS_MORE_PROCESSING_REQUIRED; + return nt_status; } NTSTATUS ntlmssp_client_start(NTLMSSP_STATE **ntlmssp_state) @@ -1103,4 +1156,3 @@ NTSTATUS ntlmssp_client_start(NTLMSSP_STATE **ntlmssp_state) return NT_STATUS_OK; } - diff --git a/source3/libsmb/ntlmssp_parse.c b/source3/libsmb/ntlmssp_parse.c index 4b3043aec8..e71504867e 100644 --- a/source3/libsmb/ntlmssp_parse.c +++ b/source3/libsmb/ntlmssp_parse.c @@ -216,7 +216,7 @@ BOOL msrpc_parse(const DATA_BLOB *blob, /* if odd length and unicode */ return False; } - if (blob->data + ptr < (uint8 *)ptr || blob->data + ptr < blob->data) + if (blob->data + ptr < (uint8 *)(unsigned long)ptr || blob->data + ptr < blob->data) return False; if (0 < len1) { @@ -244,7 +244,7 @@ BOOL msrpc_parse(const DATA_BLOB *blob, return False; } - if (blob->data + ptr < (uint8 *)ptr || blob->data + ptr < blob->data) + if (blob->data + ptr < (uint8 *)(unsigned long)ptr || blob->data + ptr < blob->data) return False; if (0 < len1) { @@ -272,7 +272,7 @@ BOOL msrpc_parse(const DATA_BLOB *blob, return False; } - if (blob->data + ptr < (uint8 *)ptr || blob->data + ptr < blob->data) + if (blob->data + ptr < (uint8 *)(unsigned long)ptr || blob->data + ptr < blob->data) return False; *b = data_blob(blob->data + ptr, len1); diff --git a/source3/libsmb/ntlmssp_sign.c b/source3/libsmb/ntlmssp_sign.c index b810597076..51023ca356 100644 --- a/source3/libsmb/ntlmssp_sign.c +++ b/source3/libsmb/ntlmssp_sign.c @@ -2,8 +2,7 @@ * Unix SMB/CIFS implementation. * Version 3.0 * NTLMSSP Signing routines - * Copyright (C) Luke Kenneth Casson Leighton 1996-2001 - * Copyright (C) Andrew Bartlett 2003 + * Copyright (C) Andrew Bartlett 2003-2005 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -27,74 +26,25 @@ #define SRV_SIGN "session key to server-to-client signing key magic constant" #define SRV_SEAL "session key to server-to-client sealing key magic constant" -static void NTLMSSPcalc_ap( unsigned char *hash, unsigned char *data, int len) -{ - unsigned char index_i = hash[256]; - unsigned char index_j = hash[257]; - int ind; - - for (ind = 0; ind < len; ind++) - { - unsigned char tc; - unsigned char t; - - index_i++; - index_j += hash[index_i]; - - tc = hash[index_i]; - hash[index_i] = hash[index_j]; - hash[index_j] = tc; - - t = hash[index_i] + hash[index_j]; - data[ind] = data[ind] ^ hash[t]; - } - - hash[256] = index_i; - hash[257] = index_j; -} - -static void calc_hash(unsigned char hash[258], unsigned char *k2, int k2l) -{ - unsigned char j = 0; - int ind; - - for (ind = 0; ind < 256; ind++) - { - hash[ind] = (unsigned char)ind; - } - - for (ind = 0; ind < 256; ind++) - { - unsigned char tc; - - j += (hash[ind] + k2[ind%k2l]); - - tc = hash[ind]; - hash[ind] = hash[j]; - hash[j] = tc; - } - - hash[256] = 0; - hash[257] = 0; -} +/** + * Some notes on then NTLM2 code: + * + * NTLM2 is a AEAD system. This means that the data encrypted is not + * all the data that is signed. In DCE-RPC case, the headers of the + * DCE-RPC packets are also signed. This prevents some of the + * fun-and-games one might have by changing them. + * + */ -static void calc_ntlmv2_hash(unsigned char hash[258], unsigned char digest[16], - DATA_BLOB session_key, - const char *constant) +static void calc_ntlmv2_key(unsigned char subkey[16], + DATA_BLOB session_key, + const char *constant) { struct MD5Context ctx3; - - /* NOTE: This code is currently complate fantasy - it's - got more in common with reality than the previous code - (the LM session key is not the right thing to use) but - it still needs work */ - MD5Init(&ctx3); MD5Update(&ctx3, session_key.data, session_key.length); - MD5Update(&ctx3, (const unsigned char *)constant, strlen(constant)+1); - MD5Final(digest, &ctx3); - - calc_hash(hash, digest, 16); + MD5Update(&ctx3, constant, strlen(constant)+1); + MD5Final(subkey, &ctx3); } enum ntlmssp_direction { @@ -103,64 +53,107 @@ enum ntlmssp_direction { }; static NTSTATUS ntlmssp_make_packet_signature(NTLMSSP_STATE *ntlmssp_state, - const uchar *data, size_t length, - enum ntlmssp_direction direction, - DATA_BLOB *sig) + const uchar *data, size_t length, + const uchar *whole_pdu, size_t pdu_length, + enum ntlmssp_direction direction, + DATA_BLOB *sig, + BOOL encrypt_sig) { if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_NTLM2) { HMACMD5Context ctx; uchar seq_num[4]; uchar digest[16]; - SIVAL(seq_num, 0, ntlmssp_state->ntlmssp_seq_num); - - hmac_md5_init_limK_to_64((const unsigned char *)(ntlmssp_state->send_sign_const), 16, &ctx); - hmac_md5_update(seq_num, 4, &ctx); - hmac_md5_update(data, length, &ctx); - hmac_md5_final(digest, &ctx); - if (!msrpc_gen(sig, "dBd", NTLMSSP_SIGN_VERSION, digest, 8 /* only copy first 8 bytes */ - , ntlmssp_state->ntlmssp_seq_num)) { + *sig = data_blob(NULL, NTLMSSP_SIG_SIZE); + if (!sig->data) { return NT_STATUS_NO_MEMORY; } - if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_KEY_EXCH) { + switch (direction) { + case NTLMSSP_SEND: + DEBUG(100,("ntlmssp_make_packet_signature: SEND seq = %u, len = %u, pdu_len = %u\n", + ntlmssp_state->ntlm2_send_seq_num, + (unsigned int)length, + (unsigned int)pdu_length)); + + SIVAL(seq_num, 0, ntlmssp_state->ntlm2_send_seq_num); + ntlmssp_state->ntlm2_send_seq_num++; + hmac_md5_init_limK_to_64(ntlmssp_state->send_sign_key, 16, &ctx); + break; + case NTLMSSP_RECEIVE: + + DEBUG(100,("ntlmssp_make_packet_signature: RECV seq = %u, len = %u, pdu_len = %u\n", + ntlmssp_state->ntlm2_recv_seq_num, + (unsigned int)length, + (unsigned int)pdu_length)); + + SIVAL(seq_num, 0, ntlmssp_state->ntlm2_recv_seq_num); + ntlmssp_state->ntlm2_recv_seq_num++; + hmac_md5_init_limK_to_64(ntlmssp_state->recv_sign_key, 16, &ctx); + break; + } + + dump_data_pw("pdu data ", whole_pdu, pdu_length); + + hmac_md5_update(seq_num, 4, &ctx); + hmac_md5_update(whole_pdu, pdu_length, &ctx); + hmac_md5_final(digest, &ctx); + + if (encrypt_sig && (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_KEY_EXCH)) { switch (direction) { case NTLMSSP_SEND: - NTLMSSPcalc_ap(ntlmssp_state->send_sign_hash, sig->data+4, sig->length-4); + smb_arc4_crypt(ntlmssp_state->send_seal_arc4_state, digest, 8); break; case NTLMSSP_RECEIVE: - NTLMSSPcalc_ap(ntlmssp_state->recv_sign_hash, sig->data+4, sig->length-4); + smb_arc4_crypt(ntlmssp_state->recv_seal_arc4_state, digest, 8); break; } } + + SIVAL(sig->data, 0, NTLMSSP_SIGN_VERSION); + memcpy(sig->data + 4, digest, 8); + memcpy(sig->data + 12, seq_num, 4); + + dump_data_pw("ntlmssp v2 sig ", sig->data, sig->length); + } else { uint32 crc; crc = crc32_calc_buffer((const char *)data, length); - if (!msrpc_gen(sig, "dddd", NTLMSSP_SIGN_VERSION, 0, crc, ntlmssp_state->ntlmssp_seq_num)) { + if (!msrpc_gen(sig, "dddd", NTLMSSP_SIGN_VERSION, 0, crc, ntlmssp_state->ntlmv1_seq_num)) { return NT_STATUS_NO_MEMORY; } - dump_data_pw("ntlmssp hash:\n", ntlmssp_state->ntlmssp_hash, - sizeof(ntlmssp_state->ntlmssp_hash)); - NTLMSSPcalc_ap(ntlmssp_state->ntlmssp_hash, sig->data+4, sig->length-4); + ntlmssp_state->ntlmv1_seq_num++; + + dump_data_pw("ntlmssp hash:\n", ntlmssp_state->ntlmv1_arc4_state, + sizeof(ntlmssp_state->ntlmv1_arc4_state)); + smb_arc4_crypt(ntlmssp_state->ntlmv1_arc4_state, sig->data+4, sig->length-4); } return NT_STATUS_OK; } NTSTATUS ntlmssp_sign_packet(NTLMSSP_STATE *ntlmssp_state, const uchar *data, size_t length, + const uchar *whole_pdu, size_t pdu_length, DATA_BLOB *sig) { NTSTATUS nt_status; + + if (!ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_SIGN) { + DEBUG(3, ("NTLMSSP Signing not negotiated - cannot sign packet!\n")); + return NT_STATUS_INVALID_PARAMETER; + } + if (!ntlmssp_state->session_key.length) { DEBUG(3, ("NO session key, cannot check sign packet\n")); return NT_STATUS_NO_USER_SESSION_KEY; } - nt_status = ntlmssp_make_packet_signature(ntlmssp_state, data, length, NTLMSSP_SEND, sig); + nt_status = ntlmssp_make_packet_signature(ntlmssp_state, + data, length, + whole_pdu, pdu_length, + NTLMSSP_SEND, sig, True); - /* increment counter on send */ - ntlmssp_state->ntlmssp_seq_num++; return nt_status; } @@ -171,8 +164,9 @@ NTSTATUS ntlmssp_sign_packet(NTLMSSP_STATE *ntlmssp_state, */ NTSTATUS ntlmssp_check_packet(NTLMSSP_STATE *ntlmssp_state, - const uchar *data, size_t length, - const DATA_BLOB *sig) + const uchar *data, size_t length, + const uchar *whole_pdu, size_t pdu_length, + const DATA_BLOB *sig) { DATA_BLOB local_sig; NTSTATUS nt_status; @@ -187,32 +181,51 @@ NTSTATUS ntlmssp_check_packet(NTLMSSP_STATE *ntlmssp_state, (unsigned long)sig->length)); } - nt_status = ntlmssp_make_packet_signature(ntlmssp_state, data, - length, NTLMSSP_RECEIVE, &local_sig); + nt_status = ntlmssp_make_packet_signature(ntlmssp_state, + data, length, + whole_pdu, pdu_length, + NTLMSSP_RECEIVE, &local_sig, True); if (!NT_STATUS_IS_OK(nt_status)) { DEBUG(0, ("NTLMSSP packet check failed with %s\n", nt_errstr(nt_status))); + data_blob_free(&local_sig); return nt_status; } - if (memcmp(sig->data+sig->length - 8, local_sig.data+local_sig.length - 8, 8) != 0) { - DEBUG(5, ("BAD SIG: wanted signature of\n")); - dump_data(5, (const char *)local_sig.data, local_sig.length); - - DEBUG(5, ("BAD SIG: got signature of\n")); - dump_data(5, (const char *)(sig->data), sig->length); + if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_NTLM2) { + if (local_sig.length != sig->length || + memcmp(local_sig.data, sig->data, sig->length) != 0) { + DEBUG(5, ("BAD SIG NTLM2: wanted signature of\n")); + dump_data(5, local_sig.data, local_sig.length); - DEBUG(0, ("NTLMSSP packet check failed due to invalid signature!\n")); - return NT_STATUS_ACCESS_DENIED; - } + DEBUG(5, ("BAD SIG: got signature of\n")); + dump_data(5, sig->data, sig->length); + + DEBUG(0, ("NTLMSSP NTLM2 packet check failed due to invalid signature!\n")); + data_blob_free(&local_sig); + return NT_STATUS_ACCESS_DENIED; + } + } else { + if (local_sig.length != sig->length || + memcmp(local_sig.data + 8, sig->data + 8, sig->length - 8) != 0) { + DEBUG(5, ("BAD SIG NTLM1: wanted signature of\n")); + dump_data(5, local_sig.data, local_sig.length); + + DEBUG(5, ("BAD SIG: got signature of\n")); + dump_data(5, sig->data, sig->length); - /* increment counter on recieive */ - ntlmssp_state->ntlmssp_seq_num++; + DEBUG(0, ("NTLMSSP NTLM1 packet check failed due to invalid signature!\n")); + data_blob_free(&local_sig); + return NT_STATUS_ACCESS_DENIED; + } + } + dump_data_pw("checked ntlmssp signature\n", sig->data, sig->length); + DEBUG(10,("ntlmssp_check_packet: NTLMSSP signature OK !\n")); + data_blob_free(&local_sig); return NT_STATUS_OK; } - /** * Seal data with the NTLMSSP algorithm * @@ -220,8 +233,16 @@ NTSTATUS ntlmssp_check_packet(NTLMSSP_STATE *ntlmssp_state, NTSTATUS ntlmssp_seal_packet(NTLMSSP_STATE *ntlmssp_state, uchar *data, size_t length, + uchar *whole_pdu, size_t pdu_length, DATA_BLOB *sig) { + NTSTATUS nt_status; + + if (!ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_SEAL) { + DEBUG(3, ("NTLMSSP Sealing not negotiated - cannot seal packet!\n")); + return NT_STATUS_INVALID_PARAMETER; + } + if (!ntlmssp_state->session_key.length) { DEBUG(3, ("NO session key, cannot seal packet\n")); return NT_STATUS_NO_USER_SESSION_KEY; @@ -230,53 +251,44 @@ NTSTATUS ntlmssp_seal_packet(NTLMSSP_STATE *ntlmssp_state, DEBUG(10,("ntlmssp_seal_data: seal\n")); dump_data_pw("ntlmssp clear data\n", data, length); if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_NTLM2) { - HMACMD5Context ctx; - char seq_num[4]; - uchar digest[16]; - SIVAL(seq_num, 0, ntlmssp_state->ntlmssp_seq_num); - - hmac_md5_init_limK_to_64((const unsigned char *)(ntlmssp_state->send_sign_const), 16, &ctx); - hmac_md5_update((const unsigned char *)seq_num, 4, &ctx); - hmac_md5_update(data, length, &ctx); - hmac_md5_final(digest, &ctx); - - if (!msrpc_gen(sig, "dBd", NTLMSSP_SIGN_VERSION, digest, 8 /* only copy first 8 bytes */ - , ntlmssp_state->ntlmssp_seq_num)) { - return NT_STATUS_NO_MEMORY; + /* The order of these two operations matters - we must first seal the packet, + then seal the sequence number - this is becouse the send_seal_hash is not + constant, but is is rather updated with each iteration */ + nt_status = ntlmssp_make_packet_signature(ntlmssp_state, + data, length, + whole_pdu, pdu_length, + NTLMSSP_SEND, sig, False); + smb_arc4_crypt(ntlmssp_state->send_seal_arc4_state, data, length); + if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_KEY_EXCH) { + smb_arc4_crypt(ntlmssp_state->send_seal_arc4_state, sig->data+4, 8); } - - dump_data_pw("ntlmssp client sealing hash:\n", - ntlmssp_state->send_seal_hash, - sizeof(ntlmssp_state->send_seal_hash)); - NTLMSSPcalc_ap(ntlmssp_state->send_seal_hash, data, length); - dump_data_pw("ntlmssp client signing hash:\n", - ntlmssp_state->send_sign_hash, - sizeof(ntlmssp_state->send_sign_hash)); - NTLMSSPcalc_ap(ntlmssp_state->send_sign_hash, sig->data+4, sig->length-4); } else { uint32 crc; crc = crc32_calc_buffer((const char *)data, length); - if (!msrpc_gen(sig, "dddd", NTLMSSP_SIGN_VERSION, 0, crc, ntlmssp_state->ntlmssp_seq_num)) { + if (!msrpc_gen(sig, "dddd", NTLMSSP_SIGN_VERSION, 0, crc, ntlmssp_state->ntlmv1_seq_num)) { return NT_STATUS_NO_MEMORY; } /* The order of these two operations matters - we must first seal the packet, - then seal the sequence number - this is becouse the ntlmssp_hash is not + then seal the sequence number - this is becouse the ntlmv1_arc4_state is not constant, but is is rather updated with each iteration */ - dump_data_pw("ntlmssp hash:\n", ntlmssp_state->ntlmssp_hash, - sizeof(ntlmssp_state->ntlmssp_hash)); - NTLMSSPcalc_ap(ntlmssp_state->ntlmssp_hash, data, length); + dump_data_pw("ntlmv1 arc4 state:\n", ntlmssp_state->ntlmv1_arc4_state, + sizeof(ntlmssp_state->ntlmv1_arc4_state)); + smb_arc4_crypt(ntlmssp_state->ntlmv1_arc4_state, data, length); + + dump_data_pw("ntlmv1 arc4 state:\n", ntlmssp_state->ntlmv1_arc4_state, + sizeof(ntlmssp_state->ntlmv1_arc4_state)); + + smb_arc4_crypt(ntlmssp_state->ntlmv1_arc4_state, sig->data+4, sig->length-4); - dump_data_pw("ntlmssp hash:\n", ntlmssp_state->ntlmssp_hash, - sizeof(ntlmssp_state->ntlmssp_hash)); - NTLMSSPcalc_ap(ntlmssp_state->ntlmssp_hash, sig->data+4, sig->length-4); + ntlmssp_state->ntlmv1_seq_num++; + + nt_status = NT_STATUS_OK; } + dump_data_pw("ntlmssp signature\n", sig->data, sig->length); dump_data_pw("ntlmssp sealed data\n", data, length); - /* increment counter on send */ - ntlmssp_state->ntlmssp_seq_num++; - return NT_STATUS_OK; } @@ -286,26 +298,27 @@ NTSTATUS ntlmssp_seal_packet(NTLMSSP_STATE *ntlmssp_state, */ NTSTATUS ntlmssp_unseal_packet(NTLMSSP_STATE *ntlmssp_state, - uchar *data, size_t length, - DATA_BLOB *sig) + uchar *data, size_t length, + uchar *whole_pdu, size_t pdu_length, + DATA_BLOB *sig) { if (!ntlmssp_state->session_key.length) { DEBUG(3, ("NO session key, cannot unseal packet\n")); return NT_STATUS_NO_USER_SESSION_KEY; } - DEBUG(10,("ntlmssp__unseal_data: seal\n")); + DEBUG(10,("ntlmssp_unseal_data: seal\n")); dump_data_pw("ntlmssp sealed data\n", data, length); + if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_NTLM2) { - NTLMSSPcalc_ap(ntlmssp_state->recv_seal_hash, data, length); + /* First unseal the data. */ + smb_arc4_crypt(ntlmssp_state->recv_seal_arc4_state, data, length); + dump_data_pw("ntlmv2 clear data\n", data, length); } else { - dump_data_pw("ntlmssp hash:\n", ntlmssp_state->ntlmssp_hash, - sizeof(ntlmssp_state->ntlmssp_hash)); - NTLMSSPcalc_ap(ntlmssp_state->ntlmssp_hash, data, length); + smb_arc4_crypt(ntlmssp_state->ntlmv1_arc4_state, data, length); + dump_data_pw("ntlmv1 clear data\n", data, length); } - dump_data_pw("ntlmssp clear data\n", data, length); - - return ntlmssp_check_packet(ntlmssp_state, data, length, sig); + return ntlmssp_check_packet(ntlmssp_state, data, length, whole_pdu, pdu_length, sig); } /** @@ -326,6 +339,7 @@ NTSTATUS ntlmssp_sign_init(NTLMSSP_STATE *ntlmssp_state) if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_NTLM2) { + DATA_BLOB weak_session_key = ntlmssp_state->session_key; const char *send_sign_const; const char *send_seal_const; const char *recv_sign_const; @@ -352,62 +366,96 @@ NTSTATUS ntlmssp_sign_init(NTLMSSP_STATE *ntlmssp_state) break; } - calc_ntlmv2_hash(ntlmssp_state->send_sign_hash, - ntlmssp_state->send_sign_const, - ntlmssp_state->session_key, send_sign_const); - dump_data_pw("NTLMSSP send sign hash:\n", - ntlmssp_state->send_sign_hash, - sizeof(ntlmssp_state->send_sign_hash)); - - calc_ntlmv2_hash(ntlmssp_state->send_seal_hash, - ntlmssp_state->send_seal_const, - ntlmssp_state->session_key, send_seal_const); - dump_data_pw("NTLMSSP send sesl hash:\n", - ntlmssp_state->send_seal_hash, - sizeof(ntlmssp_state->send_seal_hash)); - - calc_ntlmv2_hash(ntlmssp_state->recv_sign_hash, - ntlmssp_state->recv_sign_const, - ntlmssp_state->session_key, recv_sign_const); - dump_data_pw("NTLMSSP receive sign hash:\n", - ntlmssp_state->recv_sign_hash, - sizeof(ntlmssp_state->recv_sign_hash)); - - calc_ntlmv2_hash(ntlmssp_state->recv_seal_hash, - ntlmssp_state->recv_seal_const, - ntlmssp_state->session_key, recv_seal_const); - dump_data_pw("NTLMSSP receive seal hash:\n", - ntlmssp_state->recv_sign_hash, - sizeof(ntlmssp_state->recv_sign_hash)); - - } - else if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_LM_KEY) { - if (!ntlmssp_state->session_key.data || ntlmssp_state->session_key.length < 8) { - /* can't sign or check signatures yet */ - DEBUG(5, ("NTLMSSP Sign/Seal - cannot use LM KEY yet\n")); - return NT_STATUS_UNSUCCESSFUL; + /** + Weaken NTLMSSP keys to cope with down-level clients, servers and export restrictions. + We probably should have some parameters to control this, once we get NTLM2 working. + */ + + if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_128) { + ; + } else if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_56) { + weak_session_key.length = 6; + } else { /* forty bits */ + weak_session_key.length = 5; } + + dump_data_pw("NTLMSSP weakend master key:\n", + weak_session_key.data, + weak_session_key.length); + + /* SEND */ + calc_ntlmv2_key(ntlmssp_state->send_sign_key, + ntlmssp_state->session_key, send_sign_const); + dump_data_pw("NTLMSSP send sign key:\n", + ntlmssp_state->send_sign_key, 16); + + calc_ntlmv2_key(ntlmssp_state->send_seal_key, + weak_session_key, send_seal_const); + dump_data_pw("NTLMSSP send seal key:\n", + ntlmssp_state->send_seal_key, 16); + + smb_arc4_init(ntlmssp_state->send_seal_arc4_state, + ntlmssp_state->send_seal_key, 16); + + dump_data_pw("NTLMSSP send seal arc4 state:\n", + ntlmssp_state->send_seal_arc4_state, + sizeof(ntlmssp_state->send_seal_arc4_state)); + + /* RECV */ + calc_ntlmv2_key(ntlmssp_state->recv_sign_key, + ntlmssp_state->session_key, recv_sign_const); + dump_data_pw("NTLMSSP recv send sign key:\n", + ntlmssp_state->recv_sign_key, 16); + + calc_ntlmv2_key(ntlmssp_state->recv_seal_key, + weak_session_key, recv_seal_const); - DEBUG(5, ("NTLMSSP Sign/Seal - using LM KEY\n")); + dump_data_pw("NTLMSSP recv seal key:\n", + ntlmssp_state->recv_seal_key, 16); + + smb_arc4_init(ntlmssp_state->recv_seal_arc4_state, + ntlmssp_state->recv_seal_key, 16); + + dump_data_pw("NTLMSSP recv seal arc4 state:\n", + ntlmssp_state->recv_seal_arc4_state, + sizeof(ntlmssp_state->recv_seal_arc4_state)); + + ntlmssp_state->ntlm2_send_seq_num = 0; + ntlmssp_state->ntlm2_recv_seq_num = 0; + - calc_hash(ntlmssp_state->ntlmssp_hash, ntlmssp_state->session_key.data, 8); - dump_data_pw("NTLMSSP hash:\n", ntlmssp_state->ntlmssp_hash, - sizeof(ntlmssp_state->ntlmssp_hash)); } else { - if (!ntlmssp_state->session_key.data || ntlmssp_state->session_key.length < 16) { - /* can't sign or check signatures yet */ - DEBUG(5, ("NTLMSSP Sign/Seal - cannot use NT KEY yet\n")); - return NT_STATUS_UNSUCCESSFUL; +#if 0 + /* Hmmm. Shouldn't we also weaken keys for ntlmv1 ? JRA. */ + + DATA_BLOB weak_session_key = ntlmssp_state->session_key; + /** + Weaken NTLMSSP keys to cope with down-level clients, servers and export restrictions. + We probably should have some parameters to control this, once we get NTLM2 working. + */ + + if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_128) { + ; + } else if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_56) { + weak_session_key.length = 6; + } else { /* forty bits */ + weak_session_key.length = 5; } - - DEBUG(5, ("NTLMSSP Sign/Seal - using NT KEY\n")); + dump_data_pw("NTLMSSP weakend master key:\n", + weak_session_key.data, + weak_session_key.length); +#endif - calc_hash(ntlmssp_state->ntlmssp_hash, ntlmssp_state->session_key.data, 16); - dump_data_pw("NTLMSSP hash:\n", ntlmssp_state->ntlmssp_hash, - sizeof(ntlmssp_state->ntlmssp_hash)); - } + DEBUG(5, ("NTLMSSP Sign/Seal - using NTLM1\n")); + + smb_arc4_init(ntlmssp_state->ntlmv1_arc4_state, + ntlmssp_state->session_key.data, ntlmssp_state->session_key.length); - ntlmssp_state->ntlmssp_seq_num = 0; + dump_data_pw("NTLMv1 arc4 state:\n", ntlmssp_state->ntlmv1_arc4_state, + sizeof(ntlmssp_state->ntlmv1_arc4_state)); + + ntlmssp_state->ntlmv1_seq_num = 0; + } return NT_STATUS_OK; } diff --git a/source3/libsmb/passchange.c b/source3/libsmb/passchange.c index 8bce9c86a1..b104a4678d 100644 --- a/source3/libsmb/passchange.c +++ b/source3/libsmb/passchange.c @@ -21,16 +21,17 @@ #include "includes.h" /************************************************************* -change a password on a remote machine using IPC calls + Change a password on a remote machine using IPC calls. *************************************************************/ + BOOL remote_password_change(const char *remote_machine, const char *user_name, const char *old_passwd, const char *new_passwd, char *err_str, size_t err_str_len) { struct nmb_name calling, called; struct cli_state cli; + struct rpc_pipe_client *pipe_hnd; struct in_addr ip; - struct ntuser_creds creds; NTSTATUS result; @@ -85,11 +86,9 @@ BOOL remote_password_change(const char *remote_machine, const char *user_name, return False; } - init_creds(&creds, "", "", NULL); - cli_init_creds(&cli, &creds); + cli_init_creds(&cli, "", "", NULL); } else { - init_creds(&creds, user_name, "", old_passwd); - cli_init_creds(&cli, &creds); + cli_init_creds(&cli, user_name, "", old_passwd); } if (!cli_send_tconX(&cli, "IPC$", "IPC", "", 1)) { @@ -99,14 +98,19 @@ BOOL remote_password_change(const char *remote_machine, const char *user_name, return False; } - /* Try not to give the password away to easily */ + /* Try not to give the password away too easily */ - cli.pipe_auth_flags = AUTH_PIPE_NTLMSSP; - cli.pipe_auth_flags |= AUTH_PIPE_SIGN; - cli.pipe_auth_flags |= AUTH_PIPE_SEAL; - - if ( !cli_nt_session_open( &cli, PI_SAMR ) ) { + pipe_hnd = cli_rpc_pipe_open_ntlmssp(&cli, + PI_SAMR, + PIPE_AUTH_LEVEL_PRIVACY, + "", /* what domain... ? */ + user_name, + old_passwd, + &result); + + if (!pipe_hnd) { if (lp_client_lanman_auth()) { + /* Use the old RAP method. */ if (!cli_oem_change_password(&cli, user_name, new_passwd, old_passwd)) { slprintf(err_str, err_str_len-1, "machine %s rejected the password change: Error was : %s.\n", remote_machine, cli_errstr(&cli) ); @@ -114,14 +118,16 @@ BOOL remote_password_change(const char *remote_machine, const char *user_name, return False; } } else { - slprintf(err_str, err_str_len-1, "machine %s does not support SAMR connections, but LANMAN password changed are disabled\n", - remote_machine); + slprintf(err_str, err_str_len-1, + "SAMR connection to machine %s failed. Error was %s, " + "but LANMAN password changed are disabled\n", + nt_errstr(result), remote_machine); cli_shutdown(&cli); return False; } } - if (NT_STATUS_IS_OK(result = cli_samr_chgpasswd_user(&cli, cli.mem_ctx, user_name, + if (NT_STATUS_IS_OK(result = rpccli_samr_chgpasswd_user(pipe_hnd, cli.mem_ctx, user_name, new_passwd, old_passwd))) { /* Great - it all worked! */ cli_shutdown(&cli); @@ -138,25 +144,25 @@ BOOL remote_password_change(const char *remote_machine, const char *user_name, } /* OK, that failed, so try again... */ - cli_nt_session_close(&cli); + cli_rpc_pipe_close(pipe_hnd); /* Try anonymous NTLMSSP... */ - init_creds(&creds, "", "", NULL); - cli_init_creds(&cli, &creds); + cli_init_creds(&cli, "", "", NULL); - cli.pipe_auth_flags = 0; - result = NT_STATUS_UNSUCCESSFUL; - /* OK, this is ugly, but... */ - if ( cli_nt_session_open( &cli, PI_SAMR ) - && NT_STATUS_IS_OK(result - = cli_samr_chgpasswd_user(&cli, cli.mem_ctx, user_name, - new_passwd, old_passwd))) { + /* OK, this is ugly, but... try an anonymous pipe. */ + pipe_hnd = cli_rpc_pipe_open_noauth(&cli, PI_SAMR, &result); + + if ( pipe_hnd && + (NT_STATUS_IS_OK(result = rpccli_samr_chgpasswd_user(pipe_hnd, + cli.mem_ctx, + user_name, + new_passwd, + old_passwd)))) { /* Great - it all worked! */ cli_shutdown(&cli); return True; - } else { if (!(NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED) || NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL))) { @@ -173,6 +179,7 @@ BOOL remote_password_change(const char *remote_machine, const char *user_name, just might not support SAMR password changes, so fall back */ if (lp_client_lanman_auth()) { + /* Use the old RAP method. */ if (cli_oem_change_password(&cli, user_name, new_passwd, old_passwd)) { /* SAMR failed, but the old LanMan protocol worked! */ @@ -185,9 +192,10 @@ BOOL remote_password_change(const char *remote_machine, const char *user_name, cli_shutdown(&cli); return False; } else { - slprintf(err_str, err_str_len-1, - "machine %s does not support SAMR connections, but LANMAN password changed are disabled\n", - remote_machine); + slprintf(err_str, err_str_len-1, + "SAMR connection to machine %s failed. Error was %s, " + "but LANMAN password changed are disabled\n", + nt_errstr(result), remote_machine); cli_shutdown(&cli); return False; } diff --git a/source3/libsmb/pwd_cache.c b/source3/libsmb/pwd_cache.c index e010f226a0..a0f3383e29 100644 --- a/source3/libsmb/pwd_cache.c +++ b/source3/libsmb/pwd_cache.c @@ -60,4 +60,3 @@ void pwd_get_cleartext(struct pwd_info *pwd, fstring clr) clr[0] = 0; } - diff --git a/source3/libsmb/smb_share_modes.c b/source3/libsmb/smb_share_modes.c index 87a386307c..7659d1cd6e 100644 --- a/source3/libsmb/smb_share_modes.c +++ b/source3/libsmb/smb_share_modes.c @@ -55,6 +55,12 @@ struct smbdb_ctx *smb_share_mode_db_open(const char *db_path) return smb_db; } +/* key and data records in the tdb locking database */ +struct locking_key { + SMB_DEV_T dev; + SMB_INO_T inode; +}; + int smb_share_mode_db_close(struct smbdb_ctx *db_ctx) { int ret = tdb_close(db_ctx->smb_tdb); @@ -102,10 +108,10 @@ struct locking_data { int num_share_mode_entries; BOOL delete_on_close; } s; - share_mode_entry dummy; /* Needed for alignment. */ + struct share_mode_entry dummy; /* Needed for alignment. */ } u; /* the following two entries are implicit - share_mode_entry modes[num_share_mode_entries]; + struct share_mode_entry modes[num_share_mode_entries]; char file_name[]; */ }; @@ -114,9 +120,9 @@ struct locking_data { * Check if an external smb_share_mode_entry and an internal share_mode entry match. */ -static int share_mode_entry_equal(const struct smb_share_mode_entry *e_entry, const share_mode_entry *entry) +static int share_mode_entry_equal(const struct smb_share_mode_entry *e_entry, const struct share_mode_entry *entry) { - return (e_entry->pid == entry->pid && + return (procid_equal(&e_entry->pid, &entry->pid) && e_entry->file_id == (uint32_t)entry->share_file_id && e_entry->open_time.tv_sec == entry->time.tv_sec && e_entry->open_time.tv_usec == entry->time.tv_usec && @@ -130,9 +136,9 @@ static int share_mode_entry_equal(const struct smb_share_mode_entry *e_entry, co * Create an internal Samba share_mode entry from an external smb_share_mode_entry. */ -static void create_share_mode_entry(share_mode_entry *out, const struct smb_share_mode_entry *in) +static void create_share_mode_entry(struct share_mode_entry *out, const struct smb_share_mode_entry *in) { - memset(out, '\0', sizeof(share_mode_entry)); + memset(out, '\0', sizeof(struct share_mode_entry)); out->pid = in->pid; out->share_file_id = (unsigned long)in->file_id; @@ -159,7 +165,7 @@ int smb_get_share_mode_entries(struct smbdb_ctx *db_ctx, struct smb_share_mode_entry *list = NULL; int num_share_modes = 0; struct locking_data *ld = NULL; /* internal samba db state. */ - share_mode_entry *shares = NULL; + struct share_mode_entry *shares = NULL; size_t i; int list_num; @@ -187,19 +193,24 @@ int smb_get_share_mode_entries(struct smbdb_ctx *db_ctx, memset(list, '\0', num_share_modes * sizeof(struct smb_share_mode_entry)); - shares = (share_mode_entry *)(db_data.dptr + sizeof(share_mode_entry)); + shares = (struct share_mode_entry *)(db_data.dptr + sizeof(struct share_mode_entry)); list_num = 0; for (i = 0; i < num_share_modes; i++) { - share_mode_entry *share = &shares[i]; + struct share_mode_entry *share = &shares[i]; struct smb_share_mode_entry *sme = &list[list_num]; - pid_t pid = share->pid; + struct process_id pid = share->pid; /* Check this process really exists. */ - if (kill(pid, 0) == -1 && (errno == ESRCH)) { + if (kill(procid_to_pid(&pid), 0) == -1 && (errno == ESRCH)) { continue; /* No longer exists. */ } + /* Ignore deferred open entries. */ + if (share->op_type == DEFERRED_OPEN_ENTRY) { + continue; + } + /* Copy into the external list. */ sme->dev = (uint64_t)share->dev; sme->ino = (uint64_t)share->inode; @@ -238,27 +249,27 @@ int smb_create_share_mode_entry(struct smbdb_ctx *db_ctx, TDB_DATA locking_key = get_locking_key(dev, ino); int orig_num_share_modes = 0; struct locking_data *ld = NULL; /* internal samba db state. */ - share_mode_entry *shares = NULL; + struct share_mode_entry *shares = NULL; char *new_data_p = NULL; size_t new_data_size = 0; db_data = tdb_fetch(db_ctx->smb_tdb, locking_key); if (!db_data.dptr) { /* We must create the entry. */ - db_data.dptr = malloc((2*sizeof(share_mode_entry)) + strlen(filename) + 1); + db_data.dptr = malloc((2*sizeof(struct share_mode_entry)) + strlen(filename) + 1); if (!db_data.dptr) { return -1; } ld = (struct locking_data *)db_data.dptr; ld->u.s.num_share_mode_entries = 1; ld->u.s.delete_on_close = 0; - shares = (share_mode_entry *)(db_data.dptr + sizeof(share_mode_entry)); + shares = (struct share_mode_entry *)(db_data.dptr + sizeof(struct share_mode_entry)); create_share_mode_entry(shares, new_entry); - memcpy(db_data.dptr + 2*sizeof(share_mode_entry), + memcpy(db_data.dptr + 2*sizeof(struct share_mode_entry), filename, strlen(filename) + 1); - db_data.dsize = 2*sizeof(share_mode_entry) + strlen(filename) + 1; + db_data.dsize = 2*sizeof(struct share_mode_entry) + strlen(filename) + 1; if (tdb_store(db_ctx->smb_tdb, locking_key, db_data, TDB_INSERT) == -1) { free(db_data.dptr); return -1; @@ -268,7 +279,7 @@ int smb_create_share_mode_entry(struct smbdb_ctx *db_ctx, } /* Entry exists, we must add a new entry. */ - new_data_p = malloc(db_data.dsize + sizeof(share_mode_entry)); + new_data_p = malloc(db_data.dsize + sizeof(struct share_mode_entry)); if (!new_data_p) { free(db_data.dptr); return -1; @@ -278,11 +289,11 @@ int smb_create_share_mode_entry(struct smbdb_ctx *db_ctx, orig_num_share_modes = ld->u.s.num_share_mode_entries; /* Copy the original data. */ - memcpy(new_data_p, db_data.dptr, (orig_num_share_modes+1)*sizeof(share_mode_entry)); + memcpy(new_data_p, db_data.dptr, (orig_num_share_modes+1)*sizeof(struct share_mode_entry)); /* Add in the new share mode */ - shares = (share_mode_entry *)(new_data_p + - ((orig_num_share_modes+1)*sizeof(share_mode_entry))); + shares = (struct share_mode_entry *)(new_data_p + + ((orig_num_share_modes+1)*sizeof(struct share_mode_entry))); create_share_mode_entry(shares, new_entry); @@ -290,11 +301,11 @@ int smb_create_share_mode_entry(struct smbdb_ctx *db_ctx, ld->u.s.num_share_mode_entries++; /* Append the original filename */ - memcpy(new_data_p + ((ld->u.s.num_share_mode_entries+1)*sizeof(share_mode_entry)), - db_data.dptr + ((orig_num_share_modes+1)*sizeof(share_mode_entry)), - db_data.dsize - ((orig_num_share_modes+1) * sizeof(share_mode_entry))); + memcpy(new_data_p + ((ld->u.s.num_share_mode_entries+1)*sizeof(struct share_mode_entry)), + db_data.dptr + ((orig_num_share_modes+1)*sizeof(struct share_mode_entry)), + db_data.dsize - ((orig_num_share_modes+1) * sizeof(struct share_mode_entry))); - new_data_size = db_data.dsize + sizeof(share_mode_entry); + new_data_size = db_data.dsize + sizeof(struct share_mode_entry); free(db_data.dptr); @@ -318,7 +329,7 @@ int smb_delete_share_mode_entry(struct smbdb_ctx *db_ctx, TDB_DATA locking_key = get_locking_key(dev, ino); int orig_num_share_modes = 0; struct locking_data *ld = NULL; /* internal samba db state. */ - share_mode_entry *shares = NULL; + struct share_mode_entry *shares = NULL; char *new_data_p = NULL; size_t filename_size = 0; size_t i, num_share_modes; @@ -331,7 +342,7 @@ int smb_delete_share_mode_entry(struct smbdb_ctx *db_ctx, ld = (struct locking_data *)db_data.dptr; orig_num_share_modes = ld->u.s.num_share_mode_entries; - shares = (share_mode_entry *)(db_data.dptr + sizeof(share_mode_entry)); + shares = (struct share_mode_entry *)(db_data.dptr + sizeof(struct share_mode_entry)); if (orig_num_share_modes == 1) { /* Only one entry - better be ours... */ @@ -346,22 +357,22 @@ int smb_delete_share_mode_entry(struct smbdb_ctx *db_ctx, } /* More than one - allocate a new record minus the one we'll delete. */ - new_data_p = malloc(db_data.dsize - sizeof(share_mode_entry)); + new_data_p = malloc(db_data.dsize - sizeof(struct share_mode_entry)); if (!new_data_p) { free(db_data.dptr); return -1; } /* Copy the header. */ - memcpy(new_data_p, db_data.dptr, sizeof(share_mode_entry)); + memcpy(new_data_p, db_data.dptr, sizeof(struct share_mode_entry)); num_share_modes = 0; for (i = 0; i < orig_num_share_modes; i++) { - share_mode_entry *share = &shares[i]; - pid_t pid = share->pid; + struct share_mode_entry *share = &shares[i]; + struct process_id pid = share->pid; /* Check this process really exists. */ - if (kill(pid, 0) == -1 && (errno == ESRCH)) { + if (kill(procid_to_pid(&pid), 0) == -1 && (errno == ESRCH)) { continue; /* No longer exists. */ } @@ -369,8 +380,8 @@ int smb_delete_share_mode_entry(struct smbdb_ctx *db_ctx, continue; /* This is our delete taget. */ } - memcpy(new_data_p + ((num_share_modes+1)*sizeof(share_mode_entry)), - share, sizeof(share_mode_entry) ); + memcpy(new_data_p + ((num_share_modes+1)*sizeof(struct share_mode_entry)), + share, sizeof(struct share_mode_entry) ); num_share_modes++; } @@ -383,10 +394,10 @@ int smb_delete_share_mode_entry(struct smbdb_ctx *db_ctx, } /* Copy the terminating filename. */ - fname_ptr = db_data.dptr + ((orig_num_share_modes+1) * sizeof(share_mode_entry)); + fname_ptr = db_data.dptr + ((orig_num_share_modes+1) * sizeof(struct share_mode_entry)); filename_size = db_data.dsize - (fname_ptr - db_data.dptr); - memcpy(new_data_p + ((num_share_modes+1)*sizeof(share_mode_entry)), + memcpy(new_data_p + ((num_share_modes+1)*sizeof(struct share_mode_entry)), fname_ptr, filename_size); @@ -398,7 +409,7 @@ int smb_delete_share_mode_entry(struct smbdb_ctx *db_ctx, ld = (struct locking_data *)db_data.dptr; ld->u.s.num_share_mode_entries = num_share_modes; - db_data.dsize = ((num_share_modes+1)*sizeof(share_mode_entry)) + filename_size; + db_data.dsize = ((num_share_modes+1)*sizeof(struct share_mode_entry)) + filename_size; if (tdb_store(db_ctx->smb_tdb, locking_key, db_data, TDB_REPLACE) == -1) { free(db_data.dptr); @@ -418,7 +429,7 @@ int smb_change_share_mode_entry(struct smbdb_ctx *db_ctx, TDB_DATA locking_key = get_locking_key(dev, ino); int num_share_modes = 0; struct locking_data *ld = NULL; /* internal samba db state. */ - share_mode_entry *shares = NULL; + struct share_mode_entry *shares = NULL; size_t i; int found_entry = 0; @@ -429,14 +440,14 @@ int smb_change_share_mode_entry(struct smbdb_ctx *db_ctx, ld = (struct locking_data *)db_data.dptr; num_share_modes = ld->u.s.num_share_mode_entries; - shares = (share_mode_entry *)(db_data.dptr + sizeof(share_mode_entry)); + shares = (struct share_mode_entry *)(db_data.dptr + sizeof(struct share_mode_entry)); for (i = 0; i < num_share_modes; i++) { - share_mode_entry *share = &shares[i]; - pid_t pid = share->pid; + struct share_mode_entry *share = &shares[i]; + struct process_id pid = share->pid; /* Check this process really exists. */ - if (kill(pid, 0) == -1 && (errno == ESRCH)) { + if (kill(procid_to_pid(&pid), 0) == -1 && (errno == ESRCH)) { continue; /* No longer exists. */ } diff --git a/source3/libsmb/smbdes.c b/source3/libsmb/smbdes.c index b7f0cd05c3..dc49396d9e 100644 --- a/source3/libsmb/smbdes.c +++ b/source3/libsmb/smbdes.c @@ -357,78 +357,24 @@ void cred_hash3(unsigned char *out, unsigned char *in, const unsigned char *key, des_crypt56(out + 8, in + 8, key2, forw); } -void SamOEMhash( unsigned char *data, const unsigned char *key, int val) -{ - unsigned char s_box[256]; - unsigned char index_i = 0; - unsigned char index_j = 0; - unsigned char j = 0; - int ind; - - for (ind = 0; ind < 256; ind++) { - s_box[ind] = (unsigned char)ind; - } - - for( ind = 0; ind < 256; ind++) { - unsigned char tc; +/***************************************************************** + arc4 crypt/decrypt with a 16 byte key. +*****************************************************************/ - j += (s_box[ind] + key[ind%16]); - - tc = s_box[ind]; - s_box[ind] = s_box[j]; - s_box[j] = tc; - } - for( ind = 0; ind < val; ind++) { - unsigned char tc; - unsigned char t; - - index_i++; - index_j += s_box[index_i]; - - tc = s_box[index_i]; - s_box[index_i] = s_box[index_j]; - s_box[index_j] = tc; +void SamOEMhash( unsigned char *data, const unsigned char key[16], size_t len) +{ + unsigned char arc4_state[258]; - t = s_box[index_i] + s_box[index_j]; - data[ind] = data[ind] ^ s_box[t]; - } + smb_arc4_init(arc4_state, key, 16); + smb_arc4_crypt(arc4_state, data, len); } -void SamOEMhashBlob( unsigned char *data, int len, DATA_BLOB *key) +void SamOEMhashBlob( unsigned char *data, size_t len, DATA_BLOB *key) { - unsigned char s_box[256]; - unsigned char index_i = 0; - unsigned char index_j = 0; - unsigned char j = 0; - int ind; - - for (ind = 0; ind < 256; ind++) { - s_box[ind] = (unsigned char)ind; - } - - for( ind = 0; ind < 256; ind++) { - unsigned char tc; - - j += (s_box[ind] + key->data[ind%key->length]); - - tc = s_box[ind]; - s_box[ind] = s_box[j]; - s_box[j] = tc; - } - for( ind = 0; ind < len; ind++) { - unsigned char tc; - unsigned char t; - - index_i++; - index_j += s_box[index_i]; + unsigned char arc4_state[258]; - tc = s_box[index_i]; - s_box[index_i] = s_box[index_j]; - s_box[index_j] = tc; - - t = s_box[index_i] + s_box[index_j]; - data[ind] = data[ind] ^ s_box[t]; - } + smb_arc4_init(arc4_state, key->data, key->length); + smb_arc4_crypt(arc4_state, data, len); } /* Decode a sam password hash into a password. The password hash is the diff --git a/source3/libsmb/smbencrypt.c b/source3/libsmb/smbencrypt.c index 8361c35a8e..0c9eacfe4c 100644 --- a/source3/libsmb/smbencrypt.c +++ b/source3/libsmb/smbencrypt.c @@ -308,32 +308,6 @@ void SMBsesskeygen_ntv1(const uchar kr[16], #endif } -void SMBsesskeygen_lmv1(const uchar lm_hash[16], - const uchar lm_resp[24], /* only uses 8 */ - uint8 sess_key[16]) -{ - /* Calculate the LM session key (effective length 40 bits, - but changes with each session) */ - - uchar p24[24]; - uchar partial_lm_hash[16]; - - memcpy(partial_lm_hash, lm_hash, 8); - memset(partial_lm_hash + 8, 0xbd, 8); - - SMBOWFencrypt(lm_hash, lm_resp, p24); - - memcpy(sess_key, p24, 16); - sess_key[5] = 0xe5; - sess_key[6] = 0x38; - sess_key[7] = 0xb0; - -#ifdef DEBUG_PASSWORD - DEBUG(100, ("SMBsesskeygen_lmv1:\n")); - dump_data(100, sess_key, 16); -#endif -} - void SMBsesskeygen_lm_sess_key(const uchar lm_hash[16], const uchar lm_resp[24], /* only uses 8 */ uint8 sess_key[16]) @@ -485,7 +459,7 @@ BOOL SMBNTLMv2encrypt(const char *user, const char *domain, const char *password encode a password buffer with a unicode password. The buffer is filled with random data to make it harder to attack. ************************************************************/ -BOOL encode_pw_buffer(char buffer[516], const char *password, int string_flags) +BOOL encode_pw_buffer(uint8 buffer[516], const char *password, int string_flags) { uchar new_pw[512]; size_t new_pw_len; @@ -496,7 +470,7 @@ BOOL encode_pw_buffer(char buffer[516], const char *password, int string_flags) memcpy(&buffer[512 - new_pw_len], new_pw, new_pw_len); - generate_random_buffer((unsigned char *)buffer, 512 - new_pw_len); + generate_random_buffer(buffer, 512 - new_pw_len); /* * The length of the new password is in the last 4 bytes of diff --git a/source3/libsmb/smberr.c b/source3/libsmb/smberr.c index a21063e52a..82a06bde2b 100644 --- a/source3/libsmb/smberr.c +++ b/source3/libsmb/smberr.c @@ -75,6 +75,7 @@ err_code_struct dos_msgs[] = { {"ERRlogonfailure",ERRlogonfailure,"Logon failure"}, {"ERRdiskfull",ERRdiskfull,"Disk full"}, {"ERRgeneral",ERRgeneral, "General failure"}, + {"ERRbaddirectory", ERRbaddirectory, "Bad directory name"}, {"ERRunknownlevel",ERRunknownlevel, "Unknown info level"}, {NULL,-1,NULL}}; diff --git a/source3/libsmb/spnego.c b/source3/libsmb/spnego.c index 2eaec61ed7..2cf3480fce 100644 --- a/source3/libsmb/spnego.c +++ b/source3/libsmb/spnego.c @@ -42,11 +42,11 @@ static BOOL read_negTokenInit(ASN1_DATA *asn1, negTokenInit_t *token) asn1_start_tag(asn1, ASN1_CONTEXT(0)); asn1_start_tag(asn1, ASN1_SEQUENCE(0)); - token->mechTypes = SMB_MALLOC_P(char *); + token->mechTypes = SMB_MALLOC_P(const char *); for (i = 0; !asn1->has_error && 0 < asn1_tag_remaining(asn1); i++) { token->mechTypes = - SMB_REALLOC_ARRAY(token->mechTypes, char *, i + 2); + SMB_REALLOC_ARRAY(token->mechTypes, const char *, i + 2); asn1_read_OID(asn1, &token->mechTypes[i]); } token->mechTypes[i] = NULL; diff --git a/source3/libsmb/trusts_util.c b/source3/libsmb/trusts_util.c index aab0d7d151..50fa613e72 100644 --- a/source3/libsmb/trusts_util.c +++ b/source3/libsmb/trusts_util.c @@ -29,22 +29,36 @@ Caller must have the cli connected to the netlogon pipe already. **********************************************************/ -static NTSTATUS just_change_the_password(struct cli_state *cli, TALLOC_CTX *mem_ctx, + +static NTSTATUS just_change_the_password(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx, unsigned char orig_trust_passwd_hash[16], unsigned char new_trust_passwd_hash[16], uint32 sec_channel_type) { NTSTATUS result; - /* ensure that schannel uses the right domain */ - fstrcpy(cli->domain, lp_workgroup()); - if (! NT_STATUS_IS_OK(result = cli_nt_establish_netlogon(cli, sec_channel_type, orig_trust_passwd_hash))) { - DEBUG(3,("just_change_the_password: unable to setup creds (%s)!\n", - nt_errstr(result))); - return result; + /* Check if the netlogon pipe is open using schannel. If so we + already have valid creds. If not we must set them up. */ + + if (cli->auth.auth_type != PIPE_AUTH_TYPE_SCHANNEL) { + uint32 neg_flags = NETLOGON_NEG_AUTH2_FLAGS; + + result = rpccli_netlogon_setup_creds(cli, + cli->cli->desthost, + lp_workgroup(), + global_myname(), + orig_trust_passwd_hash, + sec_channel_type, + &neg_flags); + + if (!NT_STATUS_IS_OK(result)) { + DEBUG(3,("just_change_the_password: unable to setup creds (%s)!\n", + nt_errstr(result))); + return result; + } } - - result = cli_net_srv_pwset(cli, mem_ctx, global_myname(), new_trust_passwd_hash); + + result = rpccli_net_srv_pwset(cli, mem_ctx, global_myname(), new_trust_passwd_hash); if (!NT_STATUS_IS_OK(result)) { DEBUG(0,("just_change_the_password: unable to change password (%s)!\n", @@ -59,7 +73,7 @@ static NTSTATUS just_change_the_password(struct cli_state *cli, TALLOC_CTX *mem_ Caller must have already setup the connection to the NETLOGON pipe **********************************************************/ -NTSTATUS trust_pw_change_and_store_it(struct cli_state *cli, TALLOC_CTX *mem_ctx, +NTSTATUS trust_pw_change_and_store_it(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx, const char *domain, unsigned char orig_trust_passwd_hash[16], uint32 sec_channel_type) @@ -99,7 +113,7 @@ NTSTATUS trust_pw_change_and_store_it(struct cli_state *cli, TALLOC_CTX *mem_ctx already setup the connection to the NETLOGON pipe **********************************************************/ -NTSTATUS trust_pw_find_change_and_store_it(struct cli_state *cli, +NTSTATUS trust_pw_find_change_and_store_it(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx, const char *domain) { @@ -116,7 +130,6 @@ NTSTATUS trust_pw_find_change_and_store_it(struct cli_state *cli, return trust_pw_change_and_store_it(cli, mem_ctx, domain, old_trust_passwd_hash, sec_channel_type); - } /********************************************************************* @@ -133,6 +146,7 @@ BOOL enumerate_domain_trusts( TALLOC_CTX *mem_ctx, const char *domain, struct in_addr dc_ip; uint32 enum_ctx = 0; struct cli_state *cli = NULL; + struct rpc_pipe_client *lsa_pipe; BOOL retry; *domain_names = NULL; @@ -156,21 +170,21 @@ BOOL enumerate_domain_trusts( TALLOC_CTX *mem_ctx, const char *domain, /* open the LSARPC_PIPE */ - if ( !cli_nt_session_open( cli, PI_LSARPC ) ) { - result = NT_STATUS_UNSUCCESSFUL; + lsa_pipe = cli_rpc_pipe_open_noauth( cli, PI_LSARPC, &result ); + if ( !lsa_pipe) { goto done; } /* get a handle */ - result = cli_lsa_open_policy(cli, mem_ctx, True, + result = rpccli_lsa_open_policy(lsa_pipe, mem_ctx, True, POLICY_VIEW_LOCAL_INFORMATION, &pol); if ( !NT_STATUS_IS_OK(result) ) goto done; /* Lookup list of trusted domains */ - result = cli_lsa_enum_trust_dom(cli, mem_ctx, &pol, &enum_ctx, + result = rpccli_lsa_enum_trust_dom(lsa_pipe, mem_ctx, &pol, &enum_ctx, num_domains, domain_names, sids); if ( !NT_STATUS_IS_OK(result) ) goto done; @@ -184,4 +198,3 @@ done: return NT_STATUS_IS_OK(result); } - -- cgit