diff options
author | Simo Sorce <idra@samba.org> | 2008-02-01 14:24:31 -0500 |
---|---|---|
committer | Simo Sorce <idra@samba.org> | 2008-02-01 14:24:31 -0500 |
commit | 2fffc9a1b1fe2a1490e867bb38462e50c282d2b3 (patch) | |
tree | 428e09c9b35138db8b7ca7161c659a71aa129d29 /source3/libsmb | |
parent | 93a3c5b3f9927973b4ad1496f593ea147052d1e1 (diff) | |
parent | b708005a7106db26d7df689b887b419c9f2ea41c (diff) | |
download | samba-2fffc9a1b1fe2a1490e867bb38462e50c282d2b3.tar.gz samba-2fffc9a1b1fe2a1490e867bb38462e50c282d2b3.tar.bz2 samba-2fffc9a1b1fe2a1490e867bb38462e50c282d2b3.zip |
Merge branch 'v3-2-test' of ssh://git.samba.org/data/git/samba into v3-2-test
(This used to be commit 7dbfc7bdc65314466a83e8121b35c9bcb24b2631)
Diffstat (limited to 'source3/libsmb')
29 files changed, 2048 insertions, 571 deletions
diff --git a/source3/libsmb/cliconnect.c b/source3/libsmb/cliconnect.c index 52ff69953e..f3926b777b 100644 --- a/source3/libsmb/cliconnect.c +++ b/source3/libsmb/cliconnect.c @@ -98,7 +98,7 @@ static NTSTATUS cli_session_setup_lanman2(struct cli_state *cli, /* send a session setup command */ memset(cli->outbuf,'\0',smb_size); - set_message(cli->outbuf,10, 0, True); + cli_set_message(cli->outbuf,10, 0, True); SCVAL(cli->outbuf,smb_com,SMBsesssetupX); cli_setup_packet(cli); @@ -168,7 +168,7 @@ static NTSTATUS cli_session_setup_guest(struct cli_state *cli) uint32 capabilities = cli_session_setup_capabilities(cli); memset(cli->outbuf, '\0', smb_size); - set_message(cli->outbuf,13,0,True); + cli_set_message(cli->outbuf,13,0,True); SCVAL(cli->outbuf,smb_com,SMBsesssetupX); cli_setup_packet(cli); @@ -228,7 +228,7 @@ static NTSTATUS cli_session_setup_plaintext(struct cli_state *cli, fstr_sprintf( lanman, "Samba %s", SAMBA_VERSION_STRING); memset(cli->outbuf, '\0', smb_size); - set_message(cli->outbuf,13,0,True); + cli_set_message(cli->outbuf,13,0,True); SCVAL(cli->outbuf,smb_com,SMBsesssetupX); cli_setup_packet(cli); @@ -377,7 +377,7 @@ static NTSTATUS cli_session_setup_nt1(struct cli_state *cli, const char *user, /* send a session setup command */ memset(cli->outbuf,'\0',smb_size); - set_message(cli->outbuf,13,0,True); + cli_set_message(cli->outbuf,13,0,True); SCVAL(cli->outbuf,smb_com,SMBsesssetupX); cli_setup_packet(cli); @@ -457,7 +457,7 @@ static bool cli_session_setup_blob_send(struct cli_state *cli, DATA_BLOB blob) /* send a session setup command */ memset(cli->outbuf,'\0',smb_size); - set_message(cli->outbuf,12,0,True); + cli_set_message(cli->outbuf,12,0,True); SCVAL(cli->outbuf,smb_com,SMBsesssetupX); cli_setup_packet(cli); @@ -863,8 +863,7 @@ ADS_STATUS cli_session_setup_spnego(struct cli_state *cli, const char *user, /* If we get a bad principal, try to guess it if we have a valid host NetBIOS name. */ - if (strequal(principal, - "not_defined_in_RFC4178@please_ignore")) { + if (strequal(principal, ADS_IGNORE_PRINCIPAL)) { SAFE_FREE(principal); } @@ -873,13 +872,27 @@ ADS_STATUS cli_session_setup_spnego(struct cli_state *cli, const char *user, !strequal(star_smbserver_name, cli->desthost)) { char *realm = NULL; + char *machine = NULL; + char *host = NULL; DEBUG(3,("cli_session_setup_spnego: got a " "bad server principal, trying to guess ...\n")); + host = strchr_m(cli->desthost, '.'); + if (host) { + machine = SMB_STRNDUP(cli->desthost, + host - cli->desthost); + } else { + machine = SMB_STRDUP(cli->desthost); + } + if (machine == NULL) { + return ADS_ERROR_NT(NT_STATUS_NO_MEMORY); + } + realm = kerberos_get_default_realm_from_ccache(); if (realm && *realm) { if (asprintf(&principal, "%s$@%s", - cli->desthost, realm) < 0) { + machine, realm) < 0) { + SAFE_FREE(machine); SAFE_FREE(realm); return ADS_ERROR_NT(NT_STATUS_NO_MEMORY); } @@ -887,6 +900,7 @@ ADS_STATUS cli_session_setup_spnego(struct cli_state *cli, const char *user, "server principal=%s\n", principal ? principal : "<null>")); } + SAFE_FREE(machine); SAFE_FREE(realm); } @@ -959,8 +973,8 @@ NTSTATUS cli_session_setup(struct cli_state *cli, if ((cli->sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) == 0 && !lp_client_plaintext_auth() && (*pass)) { - DEBUG(1, ("Server requested plaintext password but 'client use plaintext auth'" - " is disabled\n")); + DEBUG(1, ("Server requested plaintext password but " + "'client plaintext auth' is disabled\n")); return NT_STATUS_ACCESS_DENIED; } @@ -986,8 +1000,8 @@ NTSTATUS cli_session_setup(struct cli_state *cli, if ((cli->sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) == 0) { if (!lp_client_plaintext_auth() && (*pass)) { - DEBUG(1, ("Server requested plaintext password but 'client use plaintext auth'" - " is disabled\n")); + DEBUG(1, ("Server requested plaintext password but " + "'client plaintext auth' is disabled\n")); return NT_STATUS_ACCESS_DENIED; } return cli_session_setup_plaintext(cli, user, pass, workgroup); @@ -1029,7 +1043,7 @@ NTSTATUS cli_session_setup(struct cli_state *cli, bool cli_ulogoff(struct cli_state *cli) { memset(cli->outbuf,'\0',smb_size); - set_message(cli->outbuf,2,0,True); + cli_set_message(cli->outbuf,2,0,True); SCVAL(cli->outbuf,smb_com,SMBulogoffX); cli_setup_packet(cli); SSVAL(cli->outbuf,smb_vwv0,0xFF); @@ -1086,8 +1100,9 @@ bool cli_send_tconX(struct cli_state *cli, } else { if((cli->sec_mode & (NEGOTIATE_SECURITY_USER_LEVEL|NEGOTIATE_SECURITY_CHALLENGE_RESPONSE)) == 0) { if (!lp_client_plaintext_auth() && (*pass)) { - DEBUG(1, ("Server requested plaintext password but 'client use plaintext auth'" - " is disabled\n")); + DEBUG(1, ("Server requested plaintext " + "password but 'client plaintext " + "auth' is disabled\n")); return False; } @@ -1106,7 +1121,7 @@ bool cli_send_tconX(struct cli_state *cli, slprintf(fullshare, sizeof(fullshare)-1, "\\\\%s\\%s", cli->desthost, share); - set_message(cli->outbuf,4, 0, True); + cli_set_message(cli->outbuf,4, 0, True); SCVAL(cli->outbuf,smb_com,SMBtconX); cli_setup_packet(cli); @@ -1157,7 +1172,7 @@ bool cli_send_tconX(struct cli_state *cli, bool cli_tdis(struct cli_state *cli) { memset(cli->outbuf,'\0',smb_size); - set_message(cli->outbuf,0,0,True); + cli_set_message(cli->outbuf,0,0,True); SCVAL(cli->outbuf,smb_com,SMBtdis); SSVAL(cli->outbuf,smb_tid,cli->cnum); cli_setup_packet(cli); @@ -1189,7 +1204,7 @@ void cli_negprot_send(struct cli_state *cli) memset(cli->outbuf,'\0',smb_size); /* setup the protocol strings */ - set_message(cli->outbuf,0,0,True); + cli_set_message(cli->outbuf,0,0,True); p = smb_buf(cli->outbuf); for (numprots=0; @@ -1229,7 +1244,7 @@ bool cli_negprot(struct cli_state *cli) numprots++) plength += strlen(prots[numprots].name)+2; - set_message(cli->outbuf,0,plength,True); + cli_set_message(cli->outbuf,0,plength,True); p = smb_buf(cli->outbuf); for (numprots=0; @@ -1798,15 +1813,15 @@ NTSTATUS cli_raw_tcon(struct cli_state *cli, char *p; if (!lp_client_plaintext_auth() && (*pass)) { - DEBUG(1, ("Server requested plaintext password but 'client use plaintext auth'" - " is disabled\n")); + DEBUG(1, ("Server requested plaintext password but 'client " + "plaintext auth' is disabled\n")); return NT_STATUS_ACCESS_DENIED; } memset(cli->outbuf,'\0',smb_size); memset(cli->inbuf,'\0',smb_size); - set_message(cli->outbuf, 0, 0, True); + cli_set_message(cli->outbuf, 0, 0, True); SCVAL(cli->outbuf,smb_com,SMBtcon); cli_setup_packet(cli); diff --git a/source3/libsmb/clidfs.c b/source3/libsmb/clidfs.c index e0c40b52ed..16582f8049 100644 --- a/source3/libsmb/clidfs.c +++ b/source3/libsmb/clidfs.c @@ -58,6 +58,52 @@ static struct sockaddr_storage dest_ss; static struct client_connection *connections; +static bool cli_check_msdfs_proxy(TALLOC_CTX *ctx, + struct cli_state *cli, + const char *sharename, + char **pp_newserver, + char **pp_newshare, + bool force_encrypt, + const char *username, + const char *password, + const char *domain); + +/******************************************************************** + Ensure a connection is encrypted. +********************************************************************/ + +NTSTATUS cli_cm_force_encryption(struct cli_state *c, + const char *username, + const char *password, + const char *domain, + const char *sharename) +{ + NTSTATUS status = cli_force_encryption(c, + username, + password, + domain); + + if (NT_STATUS_EQUAL(status,NT_STATUS_NOT_SUPPORTED)) { + d_printf("Encryption required and " + "server that doesn't support " + "UNIX extensions - failing connect\n"); + } else if (NT_STATUS_EQUAL(status,NT_STATUS_UNKNOWN_REVISION)) { + d_printf("Encryption required and " + "can't get UNIX CIFS extensions " + "version from server.\n"); + } else if (NT_STATUS_EQUAL(status,NT_STATUS_UNSUPPORTED_COMPRESSION)) { + d_printf("Encryption required and " + "share %s doesn't support " + "encryption.\n", sharename); + } else if (!NT_STATUS_IS_OK(status)) { + d_printf("Encryption required and " + "setup failed with error %s.\n", + nt_errstr(status)); + } + + return status; +} + /******************************************************************** Return a connection to a server. ********************************************************************/ @@ -65,7 +111,8 @@ static struct client_connection *connections; static struct cli_state *do_connect(TALLOC_CTX *ctx, const char *server, const char *share, - bool show_sessetup) + bool show_sessetup, + bool force_encrypt) { struct cli_state *c = NULL; struct nmb_name called, calling; @@ -109,6 +156,9 @@ static struct cli_state *do_connect(TALLOC_CTX *ctx, /* have to open a new connection */ if (!(c=cli_initialise()) || (cli_set_port(c, port) != port)) { d_printf("Connection to %s failed\n", server_n); + if (c) { + cli_shutdown(c); + } return NULL; } status = cli_connect(c, server_n, &ss); @@ -116,6 +166,7 @@ static struct cli_state *do_connect(TALLOC_CTX *ctx, d_printf("Connection to %s failed (Error %s)\n", server_n, nt_errstr(status)); + cli_shutdown(c); return NULL; } @@ -197,9 +248,14 @@ static struct cli_state *do_connect(TALLOC_CTX *ctx, if ((c->capabilities & CAP_DFS) && cli_check_msdfs_proxy(ctx, c, sharename, - &newserver, &newshare)) { + &newserver, &newshare, + force_encrypt, + username, + password, + lp_workgroup())) { cli_shutdown(c); - return do_connect(ctx, newserver, newshare, false); + return do_connect(ctx, newserver, + newshare, false, force_encrypt); } /* must be a normal share */ @@ -211,6 +267,18 @@ static struct cli_state *do_connect(TALLOC_CTX *ctx, return NULL; } + if (force_encrypt) { + status = cli_cm_force_encryption(c, + username, + password, + lp_workgroup(), + sharename); + if (!NT_STATUS_IS_OK(status)) { + cli_shutdown(c); + return NULL; + } + } + DEBUG(4,(" tconx ok\n")); return c; } @@ -269,7 +337,8 @@ static struct cli_state *cli_cm_connect(TALLOC_CTX *ctx, struct cli_state *referring_cli, const char *server, const char *share, - bool show_hdr) + bool show_hdr, + bool force_encrypt) { struct client_connection *node; @@ -279,7 +348,7 @@ static struct cli_state *cli_cm_connect(TALLOC_CTX *ctx, return NULL; } - node->cli = do_connect(ctx, server, share, show_hdr); + node->cli = do_connect(ctx, server, share, show_hdr, force_encrypt); if ( !node->cli ) { TALLOC_FREE( node ); @@ -331,7 +400,8 @@ struct cli_state *cli_cm_open(TALLOC_CTX *ctx, struct cli_state *referring_cli, const char *server, const char *share, - bool show_hdr) + bool show_hdr, + bool force_encrypt) { struct cli_state *c; @@ -339,7 +409,8 @@ struct cli_state *cli_cm_open(TALLOC_CTX *ctx, c = cli_cm_find(server, share); if (!c) { - c = cli_cm_connect(ctx, referring_cli, server, share, show_hdr); + c = cli_cm_connect(ctx, referring_cli, + server, share, show_hdr, force_encrypt); } return c; @@ -776,7 +847,9 @@ bool cli_resolve_path(TALLOC_CTX *ctx, /* Check for the referral. */ if (!(cli_ipc = cli_cm_open(ctx, rootcli, - rootcli->desthost, "IPC$", false))) { + rootcli->desthost, + "IPC$", false, + (rootcli->trans_enc_state != NULL)))) { return false; } @@ -818,7 +891,10 @@ bool cli_resolve_path(TALLOC_CTX *ctx, /* Open the connection to the target server & share */ if ((*targetcli = cli_cm_open(ctx, rootcli, - server, share, false)) == NULL) { + server, + share, + false, + (rootcli->trans_enc_state != NULL))) == NULL) { d_printf("Unable to follow dfs referral [\\%s\\%s]\n", server, share ); return false; @@ -905,11 +981,15 @@ bool cli_resolve_path(TALLOC_CTX *ctx, /******************************************************************** ********************************************************************/ -bool cli_check_msdfs_proxy(TALLOC_CTX *ctx, +static bool cli_check_msdfs_proxy(TALLOC_CTX *ctx, struct cli_state *cli, const char *sharename, char **pp_newserver, - char **pp_newshare ) + char **pp_newshare, + bool force_encrypt, + const char *username, + const char *password, + const char *domain) { CLIENT_DFS_REFERRAL *refs = NULL; size_t num_refs = 0; @@ -944,6 +1024,17 @@ bool cli_check_msdfs_proxy(TALLOC_CTX *ctx, return false; } + if (force_encrypt) { + NTSTATUS status = cli_cm_force_encryption(cli, + username, + password, + lp_workgroup(), + "IPC$"); + if (!NT_STATUS_IS_OK(status)) { + return false; + } + } + res = cli_dfs_get_referral(ctx, cli, fullpath, &refs, &num_refs, &consumed); if (!cli_tdis(cli)) { diff --git a/source3/libsmb/clidgram.c b/source3/libsmb/clidgram.c index 76630bd504..66c6ee1022 100644 --- a/source3/libsmb/clidgram.c +++ b/source3/libsmb/clidgram.c @@ -81,7 +81,7 @@ bool cli_send_mailslot(struct messaging_context *msg_ctx, return False; } - set_message(ptr,17,strlen(mailslot) + 1 + len,True); + cli_set_message(ptr,17,strlen(mailslot) + 1 + len,True); memcpy(ptr,tmp,4); SCVAL(ptr,smb_com,SMBtrans); diff --git a/source3/libsmb/clientgen.c b/source3/libsmb/clientgen.c index 1a6fb8f93f..042b3bdfb0 100644 --- a/source3/libsmb/clientgen.c +++ b/source3/libsmb/clientgen.c @@ -20,6 +20,21 @@ #include "includes.h" +/******************************************************************* + Setup the word count and byte count for a client smb message. +********************************************************************/ + +int cli_set_message(char *buf,int num_words,int num_bytes,bool zero) +{ + if (zero && (num_words || num_bytes)) { + memset(buf + smb_size,'\0',num_words*2 + num_bytes); + } + SCVAL(buf,smb_wct,num_words); + SSVAL(buf,smb_vwv + num_words*SIZEOFWORD,num_bytes); + smb_setlen(buf,smb_size + num_words*2 + num_bytes - 4); + return (smb_size + num_words*2 + num_bytes); +} + /**************************************************************************** Change the timeout (in milliseconds). ****************************************************************************/ @@ -71,6 +86,17 @@ static ssize_t client_receive_smb(struct cli_state *cli, size_t maxlen) break; } } + + if (cli_encryption_on(cli)) { + NTSTATUS status = cli_decrypt_message(cli); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0, ("SMB decryption failed on incoming packet! Error %s\n", + nt_errstr(status))); + cli->smb_rw_error = SMB_READ_BAD_DECRYPT; + return -1; + } + } + show_msg(cli->inbuf); return len; } @@ -85,7 +111,7 @@ bool cli_receive_smb(struct cli_state *cli) /* fd == -1 causes segfaults -- Tom (tom@ninja.nl) */ if (cli->fd == -1) - return False; + return false; again: len = client_receive_smb(cli, 0); @@ -100,7 +126,7 @@ bool cli_receive_smb(struct cli_state *cli) int fnum = SVAL(cli->inbuf,smb_vwv2); unsigned char level = CVAL(cli->inbuf,smb_vwv3+1); if (!cli->oplock_handler(cli, fnum, level)) { - return False; + return false; } } /* try to prevent loops */ @@ -114,7 +140,7 @@ bool cli_receive_smb(struct cli_state *cli) DEBUG(0, ("Receiving SMB: Server stopped responding\n")); close(cli->fd); cli->fd = -1; - return False; + return false; } if (!cli_check_sign_mac(cli)) { @@ -135,16 +161,16 @@ bool cli_receive_smb(struct cli_state *cli) * Set bad sig but don't close fd. */ cli->smb_rw_error = SMB_READ_BAD_SIG; - return True; + return true; } DEBUG(0, ("SMB Signature verification failed on incoming packet!\n")); cli->smb_rw_error = SMB_READ_BAD_SIG; close(cli->fd); cli->fd = -1; - return False; + return false; }; - return True; + return true; } /**************************************************************************** @@ -154,16 +180,13 @@ bool cli_receive_smb(struct cli_state *cli) ssize_t cli_receive_smb_data(struct cli_state *cli, char *buffer, size_t len) { - if (cli->timeout > 0) { - return read_socket_with_timeout(cli->fd, buffer, len, - len, cli->timeout, &cli->smb_rw_error); - } else { - return read_data(cli->fd, buffer, len, &cli->smb_rw_error); - } + return read_socket_with_timeout(cli->fd, buffer, len, len, + cli->timeout, &cli->smb_rw_error); } /**************************************************************************** Read a smb readX header. + We can only use this if encryption and signing are off. ****************************************************************************/ bool cli_receive_smb_readX_header(struct cli_state *cli) @@ -171,7 +194,7 @@ bool cli_receive_smb_readX_header(struct cli_state *cli) ssize_t len, offset; if (cli->fd == -1) - return False; + return false; again: @@ -199,7 +222,7 @@ bool cli_receive_smb_readX_header(struct cli_state *cli) if (cli->oplock_handler) { int fnum = SVAL(cli->inbuf,smb_vwv2); unsigned char level = CVAL(cli->inbuf,smb_vwv3+1); - if (!cli->oplock_handler(cli, fnum, level)) return False; + if (!cli->oplock_handler(cli, fnum, level)) return false; } /* try to prevent loops */ SCVAL(cli->inbuf,smb_com,0xFF); @@ -238,14 +261,14 @@ bool cli_receive_smb_readX_header(struct cli_state *cli) } } - return True; + return true; read_err: cli->smb_rw_error = SMB_READ_ERROR; close(cli->fd); cli->fd = -1; - return False; + return false; } static ssize_t write_socket(int fd, const char *buf, size_t len) @@ -272,32 +295,54 @@ bool cli_send_smb(struct cli_state *cli) size_t len; size_t nwritten=0; ssize_t ret; + char *buf_out = cli->outbuf; + bool enc_on = cli_encryption_on(cli); /* fd == -1 causes segfaults -- Tom (tom@ninja.nl) */ if (cli->fd == -1) - return False; + return false; cli_calculate_sign_mac(cli); - len = smb_len(cli->outbuf) + 4; + if (enc_on) { + NTSTATUS status = cli_encrypt_message(cli, &buf_out); + if (!NT_STATUS_IS_OK(status)) { + close(cli->fd); + cli->fd = -1; + cli->smb_rw_error = SMB_WRITE_ERROR; + DEBUG(0,("Error in encrypting client message. Error %s\n", + nt_errstr(status) )); + return false; + } + } + + len = smb_len(buf_out) + 4; while (nwritten < len) { - ret = write_socket(cli->fd,cli->outbuf+nwritten,len - nwritten); + ret = write_socket(cli->fd,buf_out+nwritten,len - nwritten); if (ret <= 0) { + if (enc_on) { + cli_free_enc_buffer(cli, buf_out); + } close(cli->fd); cli->fd = -1; cli->smb_rw_error = SMB_WRITE_ERROR; DEBUG(0,("Error writing %d bytes to client. %d (%s)\n", (int)len,(int)ret, strerror(errno) )); - return False; + return false; } nwritten += ret; } + + if (enc_on) { + cli_free_enc_buffer(cli, buf_out); + } + /* Increment the mid so we can tell between responses. */ cli->mid++; if (!cli->mid) cli->mid++; - return True; + return true; } /**************************************************************************** @@ -347,7 +392,7 @@ bool cli_send_smb_direct_writeX(struct cli_state *cli, DEBUG(0,("Error writing %d extradata " "bytes to client. %d (%s)\n", (int)extradata,(int)ret, strerror(errno) )); - return False; + return false; } nwritten += ret; } @@ -409,7 +454,7 @@ void cli_init_creds(struct cli_state *cli, const char *username, const char *dom fstrcpy(cli->user_name, username); pwd_set_cleartext(&cli->pwd, password); if (!*username) { - cli->pwd.null_pwd = True; + cli->pwd.null_pwd = true; } DEBUG(10,("cli_init_creds: user %s domain %s\n", cli->user_name, cli->domain)); @@ -424,16 +469,16 @@ void cli_setup_signing_state(struct cli_state *cli, int signing_state) if (signing_state == Undefined) return; - if (signing_state == False) { - cli->sign_info.allow_smb_signing = False; - cli->sign_info.mandatory_signing = False; + if (signing_state == false) { + cli->sign_info.allow_smb_signing = false; + cli->sign_info.mandatory_signing = false; return; } - cli->sign_info.allow_smb_signing = True; + cli->sign_info.allow_smb_signing = true; if (signing_state == Required) - cli->sign_info.mandatory_signing = True; + cli->sign_info.mandatory_signing = true; } /**************************************************************************** @@ -470,8 +515,8 @@ struct cli_state *cli_initialise(void) cli->outbuf = (char *)SMB_MALLOC(cli->bufsize+SAFETY_MARGIN); cli->inbuf = (char *)SMB_MALLOC(cli->bufsize+SAFETY_MARGIN); cli->oplock_handler = cli_oplock_ack; - cli->case_sensitive = False; - cli->smb_rw_error = 0; + cli->case_sensitive = false; + cli->smb_rw_error = SMB_READ_OK; cli->use_spnego = lp_client_use_spnego(); @@ -481,13 +526,13 @@ struct cli_state *cli_initialise(void) client routines using DOS errors instead of STATUS32 ones. This intended only as a temporary hack. */ if (getenv("CLI_FORCE_DOSERR")) - cli->force_dos_errors = True; + cli->force_dos_errors = true; if (lp_client_signing()) - cli->sign_info.allow_smb_signing = True; + cli->sign_info.allow_smb_signing = true; if (lp_client_signing() == Required) - cli->sign_info.mandatory_signing = True; + cli->sign_info.mandatory_signing = true; if (!cli->outbuf || !cli->inbuf) goto error; @@ -522,7 +567,7 @@ struct cli_state *cli_initialise(void) /**************************************************************************** External interface. Close an open named pipe over SMB. Free any authentication data. - Returns False if the cli_close call failed. + Returns false if the cli_close call failed. ****************************************************************************/ bool cli_rpc_pipe_close(struct rpc_pipe_client *cli) @@ -530,7 +575,7 @@ bool cli_rpc_pipe_close(struct rpc_pipe_client *cli) bool ret; if (!cli) { - return False; + return false; } ret = cli_close(cli->cli, cli->fnum); @@ -606,7 +651,7 @@ void cli_shutdown(struct cli_state *cli) close(cli->fd); } cli->fd = -1; - cli->smb_rw_error = 0; + cli->smb_rw_error = SMB_READ_OK; SAFE_FREE(cli); } @@ -650,15 +695,15 @@ bool cli_send_keepalive(struct cli_state *cli) { if (cli->fd == -1) { DEBUG(3, ("cli_send_keepalive: fd == -1\n")); - return False; + return false; } if (!send_keepalive(cli->fd)) { close(cli->fd); cli->fd = -1; DEBUG(0,("Error sending keepalive packet to client.\n")); - return False; + return false; } - return True; + return true; } /**************************************************************************** @@ -674,7 +719,7 @@ bool cli_echo(struct cli_state *cli, uint16 num_echos, SMB_ASSERT(length < 1024); memset(cli->outbuf,'\0',smb_size); - set_message(cli->outbuf,1,length,True); + cli_set_message(cli->outbuf,1,length,true); SCVAL(cli->outbuf,smb_com,SMBecho); SSVAL(cli->outbuf,smb_tid,65535); SSVAL(cli->outbuf,smb_vwv0,num_echos); @@ -689,13 +734,13 @@ bool cli_echo(struct cli_state *cli, uint16 num_echos, for (i=0; i<num_echos; i++) { if (!cli_receive_smb(cli)) { - return False; + return false; } if (cli_is_error(cli)) { - return False; + return false; } } - return True; + return true; } diff --git a/source3/libsmb/clifile.c b/source3/libsmb/clifile.c index 001a42d4b9..9b4c380d40 100644 --- a/source3/libsmb/clifile.c +++ b/source3/libsmb/clifile.c @@ -429,7 +429,7 @@ bool cli_rename(struct cli_state *cli, const char *fname_src, const char *fname_ memset(cli->outbuf,'\0',smb_size); memset(cli->inbuf,'\0',smb_size); - set_message(cli->outbuf,1, 0, true); + cli_set_message(cli->outbuf,1, 0, true); SCVAL(cli->outbuf,smb_com,SMBmv); SSVAL(cli->outbuf,smb_tid,cli->cnum); @@ -470,7 +470,7 @@ bool cli_ntrename(struct cli_state *cli, const char *fname_src, const char *fnam memset(cli->outbuf,'\0',smb_size); memset(cli->inbuf,'\0',smb_size); - set_message(cli->outbuf, 4, 0, true); + cli_set_message(cli->outbuf, 4, 0, true); SCVAL(cli->outbuf,smb_com,SMBntrename); SSVAL(cli->outbuf,smb_tid,cli->cnum); @@ -512,7 +512,7 @@ bool cli_nt_hardlink(struct cli_state *cli, const char *fname_src, const char *f memset(cli->outbuf,'\0',smb_size); memset(cli->inbuf,'\0',smb_size); - set_message(cli->outbuf, 4, 0, true); + cli_set_message(cli->outbuf, 4, 0, true); SCVAL(cli->outbuf,smb_com,SMBntrename); SSVAL(cli->outbuf,smb_tid,cli->cnum); @@ -554,7 +554,7 @@ bool cli_unlink_full(struct cli_state *cli, const char *fname, uint16 attrs) memset(cli->outbuf,'\0',smb_size); memset(cli->inbuf,'\0',smb_size); - set_message(cli->outbuf,1, 0, true); + cli_set_message(cli->outbuf,1, 0, true); SCVAL(cli->outbuf,smb_com,SMBunlink); SSVAL(cli->outbuf,smb_tid,cli->cnum); @@ -600,7 +600,7 @@ bool cli_mkdir(struct cli_state *cli, const char *dname) memset(cli->outbuf,'\0',smb_size); memset(cli->inbuf,'\0',smb_size); - set_message(cli->outbuf,0, 0, true); + cli_set_message(cli->outbuf,0, 0, true); SCVAL(cli->outbuf,smb_com,SMBmkdir); SSVAL(cli->outbuf,smb_tid,cli->cnum); @@ -636,7 +636,7 @@ bool cli_rmdir(struct cli_state *cli, const char *dname) memset(cli->outbuf,'\0',smb_size); memset(cli->inbuf,'\0',smb_size); - set_message(cli->outbuf,0, 0, true); + cli_set_message(cli->outbuf,0, 0, true); SCVAL(cli->outbuf,smb_com,SMBrmdir); SSVAL(cli->outbuf,smb_tid,cli->cnum); @@ -719,7 +719,7 @@ int cli_nt_create_full(struct cli_state *cli, const char *fname, memset(cli->outbuf,'\0',smb_size); memset(cli->inbuf,'\0',smb_size); - set_message(cli->outbuf,24,0, true); + cli_set_message(cli->outbuf,24,0, true); SCVAL(cli->outbuf,smb_com,SMBntcreateX); SSVAL(cli->outbuf,smb_tid,cli->cnum); @@ -815,7 +815,7 @@ int cli_open(struct cli_state *cli, const char *fname, int flags, int share_mode memset(cli->outbuf,'\0',smb_size); memset(cli->inbuf,'\0',smb_size); - set_message(cli->outbuf,15,0, true); + cli_set_message(cli->outbuf,15,0, true); SCVAL(cli->outbuf,smb_com,SMBopenX); SSVAL(cli->outbuf,smb_tid,cli->cnum); @@ -863,7 +863,7 @@ bool cli_close(struct cli_state *cli, int fnum) memset(cli->outbuf,'\0',smb_size); memset(cli->inbuf,'\0',smb_size); - set_message(cli->outbuf,3,0,True); + cli_set_message(cli->outbuf,3,0,True); SCVAL(cli->outbuf,smb_com,SMBclose); SSVAL(cli->outbuf,smb_tid,cli->cnum); @@ -896,7 +896,7 @@ NTSTATUS cli_locktype(struct cli_state *cli, int fnum, memset(cli->outbuf,'\0',smb_size); memset(cli->inbuf,'\0', smb_size); - set_message(cli->outbuf,8,0,True); + cli_set_message(cli->outbuf,8,0,True); SCVAL(cli->outbuf,smb_com,SMBlockingX); SSVAL(cli->outbuf,smb_tid,cli->cnum); @@ -948,7 +948,7 @@ bool cli_lock(struct cli_state *cli, int fnum, memset(cli->outbuf,'\0',smb_size); memset(cli->inbuf,'\0', smb_size); - set_message(cli->outbuf,8,0,True); + cli_set_message(cli->outbuf,8,0,True); SCVAL(cli->outbuf,smb_com,SMBlockingX); SSVAL(cli->outbuf,smb_tid,cli->cnum); @@ -1001,7 +1001,7 @@ bool cli_unlock(struct cli_state *cli, int fnum, uint32 offset, uint32 len) memset(cli->outbuf,'\0',smb_size); memset(cli->inbuf,'\0',smb_size); - set_message(cli->outbuf,8,0,True); + cli_set_message(cli->outbuf,8,0,True); SCVAL(cli->outbuf,smb_com,SMBlockingX); SSVAL(cli->outbuf,smb_tid,cli->cnum); @@ -1053,7 +1053,7 @@ bool cli_lock64(struct cli_state *cli, int fnum, memset(cli->outbuf,'\0',smb_size); memset(cli->inbuf,'\0', smb_size); - set_message(cli->outbuf,8,0,True); + cli_set_message(cli->outbuf,8,0,True); SCVAL(cli->outbuf,smb_com,SMBlockingX); SSVAL(cli->outbuf,smb_tid,cli->cnum); @@ -1108,7 +1108,7 @@ bool cli_unlock64(struct cli_state *cli, int fnum, SMB_BIG_UINT offset, SMB_BIG_ memset(cli->outbuf,'\0',smb_size); memset(cli->inbuf,'\0',smb_size); - set_message(cli->outbuf,8,0,True); + cli_set_message(cli->outbuf,8,0,True); SCVAL(cli->outbuf,smb_com,SMBlockingX); SSVAL(cli->outbuf,smb_tid,cli->cnum); @@ -1255,7 +1255,7 @@ bool cli_getattrE(struct cli_state *cli, int fd, memset(cli->outbuf,'\0',smb_size); memset(cli->inbuf,'\0',smb_size); - set_message(cli->outbuf,1,0,True); + cli_set_message(cli->outbuf,1,0,True); SCVAL(cli->outbuf,smb_com,SMBgetattrE); SSVAL(cli->outbuf,smb_tid,cli->cnum); @@ -1307,7 +1307,7 @@ bool cli_getatr(struct cli_state *cli, const char *fname, memset(cli->outbuf,'\0',smb_size); memset(cli->inbuf,'\0',smb_size); - set_message(cli->outbuf,0,0,True); + cli_set_message(cli->outbuf,0,0,True); SCVAL(cli->outbuf,smb_com,SMBgetatr); SSVAL(cli->outbuf,smb_tid,cli->cnum); @@ -1359,7 +1359,7 @@ bool cli_setattrE(struct cli_state *cli, int fd, memset(cli->outbuf,'\0',smb_size); memset(cli->inbuf,'\0',smb_size); - set_message(cli->outbuf,7,0,True); + cli_set_message(cli->outbuf,7,0,True); SCVAL(cli->outbuf,smb_com,SMBsetattrE); SSVAL(cli->outbuf,smb_tid,cli->cnum); @@ -1398,7 +1398,7 @@ bool cli_setatr(struct cli_state *cli, const char *fname, uint16 attr, time_t t) memset(cli->outbuf,'\0',smb_size); memset(cli->inbuf,'\0',smb_size); - set_message(cli->outbuf,8,0,True); + cli_set_message(cli->outbuf,8,0,True); SCVAL(cli->outbuf,smb_com,SMBsetatr); SSVAL(cli->outbuf,smb_tid,cli->cnum); @@ -1452,7 +1452,7 @@ bool cli_chkpath(struct cli_state *cli, const char *path) } memset(cli->outbuf,'\0',smb_size); - set_message(cli->outbuf,0,0,True); + cli_set_message(cli->outbuf,0,0,True); SCVAL(cli->outbuf,smb_com,SMBcheckpath); SSVAL(cli->outbuf,smb_tid,cli->cnum); cli_setup_packet(cli); @@ -1483,7 +1483,7 @@ bool cli_chkpath(struct cli_state *cli, const char *path) bool cli_dskattr(struct cli_state *cli, int *bsize, int *total, int *avail) { memset(cli->outbuf,'\0',smb_size); - set_message(cli->outbuf,0,0,True); + cli_set_message(cli->outbuf,0,0,True); SCVAL(cli->outbuf,smb_com,SMBdskattr); SSVAL(cli->outbuf,smb_tid,cli->cnum); cli_setup_packet(cli); @@ -1512,7 +1512,7 @@ int cli_ctemp(struct cli_state *cli, const char *path, char **tmp_path) memset(cli->outbuf,'\0',smb_size); memset(cli->inbuf,'\0',smb_size); - set_message(cli->outbuf,3,0,True); + cli_set_message(cli->outbuf,3,0,True); SCVAL(cli->outbuf,smb_com,SMBctemp); SSVAL(cli->outbuf,smb_tid,cli->cnum); @@ -1565,7 +1565,7 @@ NTSTATUS cli_raw_ioctl(struct cli_state *cli, int fnum, uint32 code, DATA_BLOB * memset(cli->outbuf,'\0',smb_size); memset(cli->inbuf,'\0',smb_size); - set_message(cli->outbuf, 3, 0, True); + cli_set_message(cli->outbuf, 3, 0, True); SCVAL(cli->outbuf,smb_com,SMBioctl); cli_setup_packet(cli); diff --git a/source3/libsmb/clifsinfo.c b/source3/libsmb/clifsinfo.c index 1a75d144b2..fb923378ab 100644 --- a/source3/libsmb/clifsinfo.c +++ b/source3/libsmb/clifsinfo.c @@ -2,6 +2,7 @@ Unix SMB/CIFS implementation. FS info functions Copyright (C) Stefan (metze) Metzmacher 2003 + Copyright (C) Jeremy Allison 2007 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 @@ -301,3 +302,368 @@ cleanup: return ret; } + +/****************************************************************************** + Send/receive the request encryption blob. +******************************************************************************/ + +static NTSTATUS enc_blob_send_receive(struct cli_state *cli, DATA_BLOB *in, DATA_BLOB *out, DATA_BLOB *param_out) +{ + uint16 setup; + char param[4]; + char *rparam=NULL, *rdata=NULL; + unsigned int rparam_count=0, rdata_count=0; + NTSTATUS status = NT_STATUS_OK; + + setup = TRANSACT2_SETFSINFO; + + SSVAL(param,0,0); + SSVAL(param,2,SMB_REQUEST_TRANSPORT_ENCRYPTION); + + if (!cli_send_trans(cli, SMBtrans2, + NULL, + 0, 0, + &setup, 1, 0, + param, 4, 0, + (char *)in->data, in->length, CLI_BUFFER_SIZE)) { + status = cli_nt_error(cli); + goto out; + } + + if (!cli_receive_trans(cli, SMBtrans2, + &rparam, &rparam_count, + &rdata, &rdata_count)) { + status = cli_nt_error(cli); + goto out; + } + + if (cli_is_error(cli)) { + status = cli_nt_error(cli); + if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) { + goto out; + } + } + + *out = data_blob(rdata, rdata_count); + *param_out = data_blob(rparam, rparam_count); + + out: + + SAFE_FREE(rparam); + SAFE_FREE(rdata); + return status; +} + +/****************************************************************************** + Make a client state struct. +******************************************************************************/ + +static struct smb_trans_enc_state *make_cli_enc_state(enum smb_trans_enc_type smb_enc_type) +{ + struct smb_trans_enc_state *es = NULL; + es = SMB_MALLOC_P(struct smb_trans_enc_state); + if (!es) { + return NULL; + } + ZERO_STRUCTP(es); + es->smb_enc_type = smb_enc_type; + + if (smb_enc_type == SMB_TRANS_ENC_GSS) { +#if defined(HAVE_GSSAPI) && defined(HAVE_KRB5) + es->s.gss_state = SMB_MALLOC_P(struct smb_tran_enc_state_gss); + if (!es->s.gss_state) { + SAFE_FREE(es); + return NULL; + } + ZERO_STRUCTP(es->s.gss_state); +#else + DEBUG(0,("make_cli_enc_state: no krb5 compiled.\n")); + SAFE_FREE(es); + return NULL; +#endif + } + return es; +} + +/****************************************************************************** + Start a raw ntlmssp encryption. +******************************************************************************/ + +NTSTATUS cli_raw_ntlm_smb_encryption_start(struct cli_state *cli, + const char *user, + const char *pass, + const char *domain) +{ + DATA_BLOB blob_in = data_blob_null; + DATA_BLOB blob_out = data_blob_null; + DATA_BLOB param_out = data_blob_null; + NTSTATUS status = NT_STATUS_UNSUCCESSFUL; + struct smb_trans_enc_state *es = make_cli_enc_state(SMB_TRANS_ENC_NTLM); + + if (!es) { + return NT_STATUS_NO_MEMORY; + } + status = ntlmssp_client_start(&es->s.ntlmssp_state); + if (!NT_STATUS_IS_OK(status)) { + goto fail; + } + + ntlmssp_want_feature(es->s.ntlmssp_state, NTLMSSP_FEATURE_SESSION_KEY); + es->s.ntlmssp_state->neg_flags |= (NTLMSSP_NEGOTIATE_SIGN|NTLMSSP_NEGOTIATE_SEAL); + + if (!NT_STATUS_IS_OK(status = ntlmssp_set_username(es->s.ntlmssp_state, user))) { + goto fail; + } + if (!NT_STATUS_IS_OK(status = ntlmssp_set_domain(es->s.ntlmssp_state, domain))) { + goto fail; + } + if (!NT_STATUS_IS_OK(status = ntlmssp_set_password(es->s.ntlmssp_state, pass))) { + goto fail; + } + + do { + status = ntlmssp_update(es->s.ntlmssp_state, blob_in, &blob_out); + data_blob_free(&blob_in); + data_blob_free(¶m_out); + if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED) || NT_STATUS_IS_OK(status)) { + NTSTATUS trans_status = enc_blob_send_receive(cli, + &blob_out, + &blob_in, + ¶m_out); + if (!NT_STATUS_EQUAL(trans_status, + NT_STATUS_MORE_PROCESSING_REQUIRED) && + !NT_STATUS_IS_OK(trans_status)) { + status = trans_status; + } else { + if (param_out.length == 2) { + es->enc_ctx_num = SVAL(param_out.data, 0); + } + } + } + data_blob_free(&blob_out); + } while (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)); + + data_blob_free(&blob_in); + + if (NT_STATUS_IS_OK(status)) { + /* Replace the old state, if any. */ + if (cli->trans_enc_state) { + common_free_encryption_state(&cli->trans_enc_state); + } + cli->trans_enc_state = es; + cli->trans_enc_state->enc_on = True; + es = NULL; + } + + fail: + + common_free_encryption_state(&es); + return status; +} + +#if defined(HAVE_GSSAPI) && defined(HAVE_KRB5) + +#ifndef SMB_GSS_REQUIRED_FLAGS +#define SMB_GSS_REQUIRED_FLAGS (GSS_C_CONF_FLAG|GSS_C_INTEG_FLAG|GSS_C_MUTUAL_FLAG|GSS_C_REPLAY_FLAG|GSS_C_SEQUENCE_FLAG) +#endif + +/****************************************************************************** + Get client gss blob to send to a server. +******************************************************************************/ + +static NTSTATUS make_cli_gss_blob(struct smb_trans_enc_state *es, + const char *service, + const char *host, + NTSTATUS status_in, + DATA_BLOB spnego_blob_in, + DATA_BLOB *p_blob_out) +{ + const char *krb_mechs[] = {OID_KERBEROS5, NULL}; + OM_uint32 ret; + OM_uint32 min; + gss_name_t srv_name; + gss_buffer_desc input_name; + gss_buffer_desc *p_tok_in; + gss_buffer_desc tok_out, tok_in; + DATA_BLOB blob_out = data_blob_null; + DATA_BLOB blob_in = data_blob_null; + char *host_princ_s = NULL; + OM_uint32 ret_flags = 0; + NTSTATUS status = NT_STATUS_OK; + + gss_OID_desc nt_hostbased_service = + {10, CONST_DISCARD(char *,"\x2a\x86\x48\x86\xf7\x12\x01\x02\x01\x04")}; + + memset(&tok_out, '\0', sizeof(tok_out)); + + /* Get a ticket for the service@host */ + asprintf(&host_princ_s, "%s@%s", service, host); + if (host_princ_s == NULL) { + return NT_STATUS_NO_MEMORY; + } + + input_name.value = host_princ_s; + input_name.length = strlen(host_princ_s) + 1; + + ret = gss_import_name(&min, + &input_name, + &nt_hostbased_service, + &srv_name); + + if (ret != GSS_S_COMPLETE) { + SAFE_FREE(host_princ_s); + return map_nt_error_from_gss(ret, min); + } + + if (spnego_blob_in.length == 0) { + p_tok_in = GSS_C_NO_BUFFER; + } else { + /* Remove the SPNEGO wrapper */ + if (!spnego_parse_auth_response(spnego_blob_in, status_in, OID_KERBEROS5, &blob_in)) { + status = NT_STATUS_UNSUCCESSFUL; + goto fail; + } + tok_in.value = blob_in.data; + tok_in.length = blob_in.length; + p_tok_in = &tok_in; + } + + ret = gss_init_sec_context(&min, + GSS_C_NO_CREDENTIAL, /* Use our default cred. */ + &es->s.gss_state->gss_ctx, + srv_name, + GSS_C_NO_OID, /* default OID. */ + GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG | GSS_C_SEQUENCE_FLAG, + GSS_C_INDEFINITE, /* requested ticket lifetime. */ + NULL, /* no channel bindings */ + p_tok_in, + NULL, /* ignore mech type */ + &tok_out, + &ret_flags, + NULL); /* ignore time_rec */ + + status = map_nt_error_from_gss(ret, min); + if (!NT_STATUS_IS_OK(status) && !NT_STATUS_EQUAL(status,NT_STATUS_MORE_PROCESSING_REQUIRED)) { + ADS_STATUS adss = ADS_ERROR_GSS(ret, min); + DEBUG(10,("make_cli_gss_blob: gss_init_sec_context failed with %s\n", + ads_errstr(adss))); + goto fail; + } + + if ((ret_flags & SMB_GSS_REQUIRED_FLAGS) != SMB_GSS_REQUIRED_FLAGS) { + status = NT_STATUS_ACCESS_DENIED; + } + + blob_out = data_blob(tok_out.value, tok_out.length); + + /* Wrap in an SPNEGO wrapper */ + *p_blob_out = gen_negTokenTarg(krb_mechs, blob_out); + + fail: + + data_blob_free(&blob_out); + data_blob_free(&blob_in); + SAFE_FREE(host_princ_s); + gss_release_name(&min, &srv_name); + if (tok_out.value) { + gss_release_buffer(&min, &tok_out); + } + return status; +} + +/****************************************************************************** + Start a SPNEGO gssapi encryption context. +******************************************************************************/ + +NTSTATUS cli_gss_smb_encryption_start(struct cli_state *cli) +{ + DATA_BLOB blob_recv = data_blob_null; + DATA_BLOB blob_send = data_blob_null; + DATA_BLOB param_out = data_blob_null; + NTSTATUS status = NT_STATUS_UNSUCCESSFUL; + fstring fqdn; + const char *servicename; + struct smb_trans_enc_state *es = make_cli_enc_state(SMB_TRANS_ENC_GSS); + + if (!es) { + return NT_STATUS_NO_MEMORY; + } + + name_to_fqdn(fqdn, cli->desthost); + strlower_m(fqdn); + + servicename = "cifs"; + status = make_cli_gss_blob(es, servicename, fqdn, NT_STATUS_OK, blob_recv, &blob_send); + if (!NT_STATUS_EQUAL(status,NT_STATUS_MORE_PROCESSING_REQUIRED)) { + servicename = "host"; + status = make_cli_gss_blob(es, servicename, fqdn, NT_STATUS_OK, blob_recv, &blob_send); + if (!NT_STATUS_EQUAL(status,NT_STATUS_MORE_PROCESSING_REQUIRED)) { + goto fail; + } + } + + do { + data_blob_free(&blob_recv); + status = enc_blob_send_receive(cli, &blob_send, &blob_recv, ¶m_out); + if (param_out.length == 2) { + es->enc_ctx_num = SVAL(param_out.data, 0); + } + data_blob_free(&blob_send); + status = make_cli_gss_blob(es, servicename, fqdn, status, blob_recv, &blob_send); + } while (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)); + data_blob_free(&blob_recv); + + if (NT_STATUS_IS_OK(status)) { + /* Replace the old state, if any. */ + if (cli->trans_enc_state) { + common_free_encryption_state(&cli->trans_enc_state); + } + cli->trans_enc_state = es; + cli->trans_enc_state->enc_on = True; + es = NULL; + } + + fail: + + common_free_encryption_state(&es); + return status; +} +#else +NTSTATUS cli_gss_smb_encryption_start(struct cli_state *cli) +{ + return NT_STATUS_NOT_SUPPORTED; +} +#endif + +/******************************************************************** + Ensure a connection is encrypted. +********************************************************************/ + +NTSTATUS cli_force_encryption(struct cli_state *c, + const char *username, + const char *password, + const char *domain) +{ + uint16 major, minor; + uint32 caplow, caphigh; + + if (!SERVER_HAS_UNIX_CIFS(c)) { + return NT_STATUS_NOT_SUPPORTED; + } + + if (!cli_unix_extensions_version(c, &major, &minor, &caplow, &caphigh)) { + return NT_STATUS_UNKNOWN_REVISION; + } + + if (!(caplow & CIFS_UNIX_TRANSPORT_ENCRYPTION_CAP)) { + return NT_STATUS_UNSUPPORTED_COMPRESSION; + } + + if (c->use_kerberos) { + return cli_gss_smb_encryption_start(c); + } + return cli_raw_ntlm_smb_encryption_start(c, + username, + password, + domain); +} diff --git a/source3/libsmb/clilist.c b/source3/libsmb/clilist.c index 2e4c360507..d5c7db09e9 100644 --- a/source3/libsmb/clilist.c +++ b/source3/libsmb/clilist.c @@ -521,7 +521,7 @@ int cli_list_old(struct cli_state *cli,const char *Mask,uint16 attribute, memset(cli->outbuf,'\0',smb_size); memset(cli->inbuf,'\0',smb_size); - set_message(cli->outbuf,2,0,True); + cli_set_message(cli->outbuf,2,0,True); SCVAL(cli->outbuf,smb_com,SMBsearch); @@ -581,7 +581,7 @@ int cli_list_old(struct cli_state *cli,const char *Mask,uint16 attribute, memset(cli->outbuf,'\0',smb_size); memset(cli->inbuf,'\0',smb_size); - set_message(cli->outbuf,2,0,True); + cli_set_message(cli->outbuf,2,0,True); SCVAL(cli->outbuf,smb_com,SMBfclose); SSVAL(cli->outbuf,smb_tid,cli->cnum); cli_setup_packet(cli); diff --git a/source3/libsmb/climessage.c b/source3/libsmb/climessage.c index 13ef1d43d4..00c25aa725 100644 --- a/source3/libsmb/climessage.c +++ b/source3/libsmb/climessage.c @@ -29,7 +29,7 @@ int cli_message_start_build(struct cli_state *cli, const char *host, const char /* construct a SMBsendstrt command */ memset(cli->outbuf,'\0',smb_size); - set_message(cli->outbuf,0,0,True); + cli_set_message(cli->outbuf,0,0,True); SCVAL(cli->outbuf,smb_com,SMBsendstrt); SSVAL(cli->outbuf,smb_tid,cli->cnum); cli_setup_packet(cli); @@ -75,7 +75,7 @@ int cli_message_text_build(struct cli_state *cli, const char *msg, int len, int char *p; memset(cli->outbuf,'\0',smb_size); - set_message(cli->outbuf,1,0,True); + cli_set_message(cli->outbuf,1,0,True); SCVAL(cli->outbuf,smb_com,SMBsendtxt); SSVAL(cli->outbuf,smb_tid,cli->cnum); cli_setup_packet(cli); @@ -132,7 +132,7 @@ int cli_message_end_build(struct cli_state *cli, int grp) char *p; memset(cli->outbuf,'\0',smb_size); - set_message(cli->outbuf,1,0,True); + cli_set_message(cli->outbuf,1,0,True); SCVAL(cli->outbuf,smb_com,SMBsendend); SSVAL(cli->outbuf,smb_tid,cli->cnum); diff --git a/source3/libsmb/clioplock.c b/source3/libsmb/clioplock.c index 2e54f5a781..ef8b396461 100644 --- a/source3/libsmb/clioplock.c +++ b/source3/libsmb/clioplock.c @@ -32,7 +32,7 @@ bool cli_oplock_ack(struct cli_state *cli, int fnum, unsigned char level) cli->outbuf = buf; memset(buf,'\0',smb_size); - set_message(buf,8,0,True); + cli_set_message(buf,8,0,True); SCVAL(buf,smb_com,SMBlockingX); SSVAL(buf,smb_tid, cli->cnum); diff --git a/source3/libsmb/cliprint.c b/source3/libsmb/cliprint.c index 7fbdb97c01..223ddb4186 100644 --- a/source3/libsmb/cliprint.c +++ b/source3/libsmb/cliprint.c @@ -195,7 +195,7 @@ int cli_spl_open(struct cli_state *cli, const char *fname, int flags, int share_ memset(cli->outbuf,'\0',smb_size); memset(cli->inbuf,'\0',smb_size); - set_message(cli->outbuf,15,0,True); + cli_set_message(cli->outbuf,15,0,True); SCVAL(cli->outbuf,smb_com,SMBsplopen); SSVAL(cli->outbuf,smb_tid,cli->cnum); @@ -242,7 +242,7 @@ bool cli_spl_close(struct cli_state *cli, int fnum) memset(cli->outbuf,'\0',smb_size); memset(cli->inbuf,'\0',smb_size); - set_message(cli->outbuf,3,0,True); + cli_set_message(cli->outbuf,3,0,True); SCVAL(cli->outbuf,smb_com,SMBsplclose); SSVAL(cli->outbuf,smb_tid,cli->cnum); diff --git a/source3/libsmb/cliquota.c b/source3/libsmb/cliquota.c index 206576f040..f369d28dff 100644 --- a/source3/libsmb/cliquota.c +++ b/source3/libsmb/cliquota.c @@ -150,7 +150,7 @@ bool cli_get_user_quota(struct cli_state *cli, int quota_fnum, SMB_NTQUOTA_STRUC SIVAL(params, 8,0x00000000); SIVAL(params,12,0x00000024); - sid_len = sid_size(&pqt->sid); + sid_len = ndr_size_dom_sid(&pqt->sid, 0); data_len = sid_len+8; SIVAL(data, 0, 0x00000000); SIVAL(data, 4, sid_len); @@ -213,7 +213,7 @@ bool cli_set_user_quota(struct cli_state *cli, int quota_fnum, SMB_NTQUOTA_STRUC SSVAL(params,0,quota_fnum); - sid_len = sid_size(&pqt->sid); + sid_len = ndr_size_dom_sid(&pqt->sid, 0); SIVAL(data,0,0); SIVAL(data,4,sid_len); SBIG_UINT(data, 8,(SMB_BIG_UINT)0); diff --git a/source3/libsmb/clirap.c b/source3/libsmb/clirap.c index 54504f608d..4c5e338606 100644 --- a/source3/libsmb/clirap.c +++ b/source3/libsmb/clirap.c @@ -297,6 +297,7 @@ bool cli_NetServerEnum(struct cli_state *cli, char *workgroup, uint32 stype, STR_TERMINATE|STR_UPPER); if (len == (size_t)-1) { + SAFE_FREE(last_entry); return false; } p += len; @@ -805,6 +806,137 @@ bool cli_qpathinfo2(struct cli_state *cli, const char *fname, } /**************************************************************************** + Get the stream info +****************************************************************************/ + +bool cli_qpathinfo_streams(struct cli_state *cli, const char *fname, + TALLOC_CTX *mem_ctx, + unsigned int *pnum_streams, + struct stream_struct **pstreams) +{ + unsigned int data_len = 0; + unsigned int param_len = 0; + uint16 setup = TRANSACT2_QPATHINFO; + char *param; + char *rparam=NULL, *rdata=NULL; + char *p; + unsigned int num_streams; + struct stream_struct *streams; + unsigned int ofs; + size_t namelen = 2*(strlen(fname)+1); + + param = SMB_MALLOC_ARRAY(char, 6+namelen+2); + if (param == NULL) { + return false; + } + p = param; + memset(p, 0, 6); + SSVAL(p, 0, SMB_FILE_STREAM_INFORMATION); + p += 6; + p += clistr_push(cli, p, fname, namelen, STR_TERMINATE); + + param_len = PTR_DIFF(p, param); + + if (!cli_send_trans(cli, SMBtrans2, + NULL, /* name */ + -1, 0, /* fid, flags */ + &setup, 1, 0, /* setup, len, max */ + param, param_len, 10, /* param, len, max */ + NULL, data_len, cli->max_xmit /* data, len, max */ + )) { + return false; + } + + if (!cli_receive_trans(cli, SMBtrans2, + &rparam, ¶m_len, + &rdata, &data_len)) { + return false; + } + + if (!rdata) { + SAFE_FREE(rparam); + return false; + } + + num_streams = 0; + streams = NULL; + ofs = 0; + + while ((data_len > ofs) && (data_len - ofs >= 24)) { + uint32_t nlen, len; + ssize_t size; + void *vstr; + struct stream_struct *tmp; + uint8_t *tmp_buf; + + tmp = TALLOC_REALLOC_ARRAY(mem_ctx, streams, + struct stream_struct, + num_streams+1); + + if (tmp == NULL) { + goto fail; + } + streams = tmp; + + nlen = IVAL(rdata, ofs + 0x04); + + streams[num_streams].size = IVAL_TO_SMB_OFF_T( + rdata, ofs + 0x08); + streams[num_streams].alloc_size = IVAL_TO_SMB_OFF_T( + rdata, ofs + 0x10); + + if (nlen > data_len - (ofs + 24)) { + goto fail; + } + + /* + * We need to null-terminate src, how do I do this with + * convert_string_talloc?? + */ + + tmp_buf = TALLOC_ARRAY(streams, uint8_t, nlen+2); + if (tmp_buf == NULL) { + goto fail; + } + + memcpy(tmp_buf, rdata+ofs+24, nlen); + tmp_buf[nlen] = 0; + tmp_buf[nlen+1] = 0; + + size = convert_string_talloc(streams, CH_UTF16, CH_UNIX, + tmp_buf, nlen+2, &vstr, + false); + TALLOC_FREE(tmp_buf); + + if (size == -1) { + goto fail; + } + streams[num_streams].name = (char *)vstr; + num_streams++; + + len = IVAL(rdata, ofs); + if (len > data_len - ofs) { + goto fail; + } + if (len == 0) break; + ofs += len; + } + + SAFE_FREE(rdata); + SAFE_FREE(rparam); + + *pnum_streams = num_streams; + *pstreams = streams; + return true; + + fail: + TALLOC_FREE(streams); + SAFE_FREE(rdata); + SAFE_FREE(rparam); + return false; +} + +/**************************************************************************** Send a qfileinfo QUERY_FILE_NAME_INFO call. ****************************************************************************/ diff --git a/source3/libsmb/clireadwrite.c b/source3/libsmb/clireadwrite.c index d77875bae5..af13ed8f73 100644 --- a/source3/libsmb/clireadwrite.c +++ b/source3/libsmb/clireadwrite.c @@ -34,7 +34,7 @@ static bool cli_issue_read(struct cli_state *cli, int fnum, off_t offset, if ((SMB_BIG_UINT)offset >> 32) bigoffset = True; - set_message(cli->outbuf,bigoffset ? 12 : 10,0,True); + cli_set_message(cli->outbuf,bigoffset ? 12 : 10,0,True); SCVAL(cli->outbuf,smb_com,SMBreadX); SSVAL(cli->outbuf,smb_tid,cli->cnum); @@ -65,8 +65,8 @@ ssize_t cli_read(struct cli_state *cli, int fnum, char *buf, off_t offset, size_ size_t size2; size_t readsize; ssize_t total = 0; - /* We can only do direct reads if not signing. */ - bool direct_reads = !client_is_signing_on(cli); + /* We can only do direct reads if not signing or encrypting. */ + bool direct_reads = !client_is_signing_on(cli) && !cli_encryption_on(cli); if (size == 0) return 0; @@ -76,7 +76,9 @@ ssize_t cli_read(struct cli_state *cli, int fnum, char *buf, off_t offset, size_ * rounded down to a multiple of 1024. */ - if (client_is_signing_on(cli) == False && (cli->posix_capabilities & CIFS_UNIX_LARGE_READ_CAP)) { + if (client_is_signing_on(cli) == false && + cli_encryption_on(cli) == false && + (cli->posix_capabilities & CIFS_UNIX_LARGE_READ_CAP)) { readsize = CLI_SAMBA_MAX_POSIX_LARGE_READX_SIZE; } else if (cli->capabilities & CAP_LARGE_READX) { if (cli->is_samba) { @@ -132,6 +134,8 @@ ssize_t cli_read(struct cli_state *cli, int fnum, char *buf, off_t offset, size_ return -1; } + /* size2 is the number of bytes the server returned. + * Might be zero. */ size2 = SVAL(cli->inbuf, smb_vwv5); size2 |= (((unsigned int)(SVAL(cli->inbuf, smb_vwv7))) << 16); @@ -143,27 +147,32 @@ ssize_t cli_read(struct cli_state *cli, int fnum, char *buf, off_t offset, size_ return -1; } - if (!direct_reads) { - /* Copy data into buffer */ - p = smb_base(cli->inbuf) + SVAL(cli->inbuf,smb_vwv6); - memcpy(buf + total, p, size2); - } else { - /* Ensure the remaining data matches the return size. */ - ssize_t toread = smb_len_large(cli->inbuf) - SVAL(cli->inbuf,smb_vwv6); - - /* Ensure the size is correct. */ - if (toread != size2) { - DEBUG(5,("direct read logic fail toread (%d) != size2 (%u)\n", - (int)toread, (unsigned int)size2 )); - return -1; - } - - /* Read data directly into buffer */ - toread = cli_receive_smb_data(cli,buf+total,size2); - if (toread != size2) { - DEBUG(5,("direct read read failure toread (%d) != size2 (%u)\n", - (int)toread, (unsigned int)size2 )); - return -1; + if (size2) { + /* smb_vwv6 is the offset in the packet of the returned + * data bytes. Only valid if size2 != 0. */ + + if (!direct_reads) { + /* Copy data into buffer */ + p = smb_base(cli->inbuf) + SVAL(cli->inbuf,smb_vwv6); + memcpy(buf + total, p, size2); + } else { + /* Ensure the remaining data matches the return size. */ + ssize_t toread = smb_len_large(cli->inbuf) - SVAL(cli->inbuf,smb_vwv6); + + /* Ensure the size is correct. */ + if (toread != size2) { + DEBUG(5,("direct read logic fail toread (%d) != size2 (%u)\n", + (int)toread, (unsigned int)size2 )); + return -1; + } + + /* Read data directly into buffer */ + toread = cli_receive_smb_data(cli,buf+total,size2); + if (toread != size2) { + DEBUG(5,("direct read read failure toread (%d) != size2 (%u)\n", + (int)toread, (unsigned int)size2 )); + return -1; + } } } @@ -203,7 +212,7 @@ static bool cli_issue_readraw(struct cli_state *cli, int fnum, off_t offset, memset(cli->outbuf,'\0',smb_size); memset(cli->inbuf,'\0',smb_size); - set_message(cli->outbuf,10,0,True); + cli_set_message(cli->outbuf,10,0,True); SCVAL(cli->outbuf,smb_com,SMBreadbraw); SSVAL(cli->outbuf,smb_tid,cli->cnum); @@ -295,8 +304,8 @@ static bool cli_issue_write(struct cli_state *cli, { char *p; bool large_writex = false; - /* We can only do direct writes if not signing. */ - bool direct_writes = !client_is_signing_on(cli); + /* We can only do direct writes if not signing and not encrypting. */ + bool direct_writes = !client_is_signing_on(cli) && !cli_encryption_on(cli); if (!direct_writes && size + 1 > cli->bufsize) { cli->outbuf = (char *)SMB_REALLOC(cli->outbuf, size + 1024); @@ -319,9 +328,9 @@ static bool cli_issue_write(struct cli_state *cli, } if (large_writex) { - set_message(cli->outbuf,14,0,True); + cli_set_message(cli->outbuf,14,0,True); } else { - set_message(cli->outbuf,12,0,True); + cli_set_message(cli->outbuf,12,0,True); } SCVAL(cli->outbuf,smb_com,SMBwriteX); @@ -402,21 +411,25 @@ ssize_t cli_write(struct cli_state *cli, mpx = 1; } + /* Default (small) writesize. */ + writesize = (cli->max_xmit - (smb_size+32)) & ~1023; + if (write_mode == 0 && !client_is_signing_on(cli) && + !cli_encryption_on(cli) && (cli->posix_capabilities & CIFS_UNIX_LARGE_WRITE_CAP) && (cli->capabilities & CAP_LARGE_FILES)) { /* Only do massive writes if we can do them direct - * with no signing - not on a pipe. */ + * with no signing or encrypting - not on a pipe. */ writesize = CLI_SAMBA_MAX_POSIX_LARGE_WRITEX_SIZE; - } else if (cli->capabilities & CAP_LARGE_READX) { + } else if (cli->capabilities & CAP_LARGE_WRITEX) { if (cli->is_samba) { - writesize = CLI_SAMBA_MAX_LARGE_READX_SIZE; - } else { - writesize = CLI_WINDOWS_MAX_LARGE_READX_SIZE; + writesize = CLI_SAMBA_MAX_LARGE_WRITEX_SIZE; + } else if (!client_is_signing_on(cli)) { + /* Windows restricts signed writes to max_xmit. + * Found by Volker. */ + writesize = CLI_WINDOWS_MAX_LARGE_WRITEX_SIZE; } - } else { - writesize = (cli->max_xmit - (smb_size+32)) & ~1023; } blocks = (size + (writesize-1)) / writesize; @@ -471,7 +484,7 @@ ssize_t cli_smbwrite(struct cli_state *cli, memset(cli->outbuf,'\0',smb_size); memset(cli->inbuf,'\0',smb_size); - set_message(cli->outbuf,5, 0,True); + cli_set_message(cli->outbuf,5, 0,True); SCVAL(cli->outbuf,smb_com,SMBwrite); SSVAL(cli->outbuf,smb_tid,cli->cnum); diff --git a/source3/libsmb/clisecdesc.c b/source3/libsmb/clisecdesc.c index 46a6609415..adc6fba9af 100644 --- a/source3/libsmb/clisecdesc.c +++ b/source3/libsmb/clisecdesc.c @@ -28,9 +28,8 @@ SEC_DESC *cli_query_secdesc(struct cli_state *cli, int fnum, char param[8]; char *rparam=NULL, *rdata=NULL; unsigned int rparam_count=0, rdata_count=0; - prs_struct pd; - bool pd_initialized = False; SEC_DESC *psd = NULL; + NTSTATUS status; SIVAL(param, 0, fnum); SIVAL(param, 4, 0x7); @@ -56,15 +55,12 @@ SEC_DESC *cli_query_secdesc(struct cli_state *cli, int fnum, if (cli_is_error(cli)) goto cleanup; - if (!prs_init(&pd, rdata_count, mem_ctx, UNMARSHALL)) { - goto cleanup; - } - pd_initialized = True; - prs_copy_data_in(&pd, rdata, rdata_count); - prs_set_offset(&pd,0); + status = unmarshall_sec_desc(mem_ctx, (uint8 *)rdata, rdata_count, + &psd); - if (!sec_io_desc("sd data", &psd, &pd, 1)) { - DEBUG(1,("Failed to parse secdesc\n")); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(10, ("unmarshall_sec_desc failed: %s\n", + nt_errstr(status))); goto cleanup; } @@ -73,8 +69,6 @@ SEC_DESC *cli_query_secdesc(struct cli_state *cli, int fnum, SAFE_FREE(rparam); SAFE_FREE(rdata); - if (pd_initialized) - prs_mem_free(&pd); return psd; } @@ -87,20 +81,16 @@ bool cli_set_secdesc(struct cli_state *cli, int fnum, SEC_DESC *sd) char *rparam=NULL, *rdata=NULL; unsigned int rparam_count=0, rdata_count=0; uint32 sec_info = 0; - TALLOC_CTX *mem_ctx; - prs_struct pd; + TALLOC_CTX *frame = talloc_stackframe(); bool ret = False; - - if ((mem_ctx = talloc_init("cli_set_secdesc")) == NULL) { - DEBUG(0,("talloc_init failed.\n")); - goto cleanup; - } - - prs_init(&pd, 0, mem_ctx, MARSHALL); - prs_give_memory(&pd, NULL, 0, True); - - if (!sec_io_desc("sd data", &sd, &pd, 1)) { - DEBUG(1,("Failed to marshall secdesc\n")); + uint8 *data; + size_t len; + NTSTATUS status; + + status = marshall_sec_desc(talloc_tos(), sd, &data, &len); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(10, ("marshall_sec_desc failed: %s\n", + nt_errstr(status))); goto cleanup; } @@ -119,7 +109,7 @@ bool cli_set_secdesc(struct cli_state *cli, int fnum, SEC_DESC *sd) 0, NULL, 0, 0, param, 8, 0, - prs_data_p(&pd), prs_offset(&pd), 0)) { + (char *)data, len, 0)) { DEBUG(1,("Failed to send NT_TRANSACT_SET_SECURITY_DESC\n")); goto cleanup; } @@ -139,8 +129,7 @@ bool cli_set_secdesc(struct cli_state *cli, int fnum, SEC_DESC *sd) SAFE_FREE(rparam); SAFE_FREE(rdata); - talloc_destroy(mem_ctx); + TALLOC_FREE(frame); - prs_mem_free(&pd); return ret; } diff --git a/source3/libsmb/clitrans.c b/source3/libsmb/clitrans.c index a6f7f7fec1..bfb31fdb74 100644 --- a/source3/libsmb/clitrans.c +++ b/source3/libsmb/clitrans.c @@ -43,7 +43,7 @@ bool cli_send_trans(struct cli_state *cli, int trans, this_ldata = MIN(ldata,cli->max_xmit - (500+lsetup*2+this_lparam)); memset(cli->outbuf,'\0',smb_size); - set_message(cli->outbuf,14+lsetup,0,True); + cli_set_message(cli->outbuf,14+lsetup,0,True); SCVAL(cli->outbuf,smb_com,trans); SSVAL(cli->outbuf,smb_tid, cli->cnum); cli_setup_packet(cli); @@ -107,7 +107,7 @@ bool cli_send_trans(struct cli_state *cli, int trans, this_lparam = MIN(lparam-tot_param,cli->max_xmit - 500); /* hack */ this_ldata = MIN(ldata-tot_data,cli->max_xmit - (500+this_lparam)); - set_message(cli->outbuf,trans==SMBtrans?8:9,0,True); + cli_set_message(cli->outbuf,trans==SMBtrans?8:9,0,True); SCVAL(cli->outbuf,smb_com,(trans==SMBtrans ? SMBtranss : SMBtranss2)); outparam = smb_buf(cli->outbuf); @@ -368,7 +368,7 @@ bool cli_send_nt_trans(struct cli_state *cli, this_ldata = MIN(ldata,cli->max_xmit - (500+lsetup*2+this_lparam)); memset(cli->outbuf,'\0',smb_size); - set_message(cli->outbuf,19+lsetup,0,True); + cli_set_message(cli->outbuf,19+lsetup,0,True); SCVAL(cli->outbuf,smb_com,SMBnttrans); SSVAL(cli->outbuf,smb_tid, cli->cnum); cli_setup_packet(cli); @@ -424,7 +424,7 @@ bool cli_send_nt_trans(struct cli_state *cli, this_lparam = MIN(lparam-tot_param,cli->max_xmit - 500); /* hack */ this_ldata = MIN(ldata-tot_data,cli->max_xmit - (500+this_lparam)); - set_message(cli->outbuf,18,0,True); + cli_set_message(cli->outbuf,18,0,True); SCVAL(cli->outbuf,smb_com,SMBnttranss); /* XXX - these should probably be aligned */ diff --git a/source3/libsmb/doserr.c b/source3/libsmb/doserr.c index 84cc898187..a3043a2152 100644 --- a/source3/libsmb/doserr.c +++ b/source3/libsmb/doserr.c @@ -1,18 +1,18 @@ -/* +/* * Unix SMB/CIFS implementation. * DOS error routines * Copyright (C) Tim Potter 2002. - * + * * 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 * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program; if not, see <http://www.gnu.org/licenses/>. */ @@ -21,12 +21,16 @@ #include "includes.h" -typedef const struct -{ +typedef const struct { const char *dos_errstr; WERROR werror; } werror_code_struct; +typedef const struct { + WERROR werror; + const char *friendly_errstr; +} werror_str_struct; + werror_code_struct dos_errs[] = { { "WERR_OK", WERR_OK }, @@ -59,7 +63,9 @@ werror_code_struct dos_errs[] = { "WERR_JOB_NOT_FOUND", WERR_JOB_NOT_FOUND }, { "WERR_DEST_NOT_FOUND", WERR_DEST_NOT_FOUND }, { "WERR_NOT_LOCAL_DOMAIN", WERR_NOT_LOCAL_DOMAIN }, + { "WERR_USER_EXISTS", WERR_USER_EXISTS }, { "WERR_NO_LOGON_SERVERS", WERR_NO_LOGON_SERVERS }, + { "WERR_NO_SUCH_LOGON_SESSION", WERR_NO_SUCH_LOGON_SESSION }, { "WERR_PRINTER_DRIVER_IN_USE", WERR_PRINTER_DRIVER_IN_USE }, { "WERR_STATUS_MORE_ENTRIES ", WERR_STATUS_MORE_ENTRIES }, { "WERR_DFS_NO_SUCH_VOL", WERR_DFS_NO_SUCH_VOL }, @@ -67,11 +73,13 @@ werror_code_struct dos_errs[] = { "WERR_DFS_NO_SUCH_SERVER", WERR_DFS_NO_SUCH_SERVER }, { "WERR_DFS_INTERNAL_ERROR", WERR_DFS_INTERNAL_ERROR }, { "WERR_DFS_CANT_CREATE_JUNCT", WERR_DFS_CANT_CREATE_JUNCT }, + { "WERR_INVALID_COMPUTER_NAME", WERR_INVALID_COMPUTER_NAME }, { "WERR_MACHINE_LOCKED", WERR_MACHINE_LOCKED }, - { "WERR_DOMAIN_CONTROLLER_NOT_FOUND", WERR_DOMAIN_CONTROLLER_NOT_FOUND }, + { "WERR_DC_NOT_FOUND", WERR_DC_NOT_FOUND }, { "WERR_SETUP_NOT_JOINED", WERR_SETUP_NOT_JOINED }, { "WERR_SETUP_ALREADY_JOINED", WERR_SETUP_ALREADY_JOINED }, { "WERR_SETUP_DOMAIN_CONTROLLER", WERR_SETUP_DOMAIN_CONTROLLER }, + { "WERR_DEFAULT_JOIN_REQUIRED", WERR_DEFAULT_JOIN_REQUIRED }, { "WERR_DEVICE_NOT_AVAILABLE", WERR_DEVICE_NOT_AVAILABLE }, { "WERR_LOGON_FAILURE", WERR_LOGON_FAILURE }, { "WERR_NO_SUCH_DOMAIN", WERR_NO_SUCH_DOMAIN }, @@ -85,12 +93,36 @@ werror_code_struct dos_errs[] = { "WERR_REG_CORRUPT", WERR_REG_CORRUPT }, { "WERR_REG_IO_FAILURE", WERR_REG_IO_FAILURE }, { "WERR_REG_FILE_INVALID", WERR_REG_FILE_INVALID }, + { "WERR_NO_SUCH_SERVICE", WERR_NO_SUCH_SERVICE }, { "WERR_SERVICE_DISABLED", WERR_SERVICE_DISABLED }, { "WERR_CAN_NOT_COMPLETE", WERR_CAN_NOT_COMPLETE}, { "WERR_INVALID_FLAGS", WERR_INVALID_FLAGS}, + { "WERR_PASSWORD_MUST_CHANGE", WERR_PASSWORD_MUST_CHANGE }, + { "WERR_DOMAIN_CONTROLLER_NOT_FOUND", WERR_DOMAIN_CONTROLLER_NOT_FOUND }, + { "WERR_ACCOUNT_LOCKED_OUT", WERR_ACCOUNT_LOCKED_OUT }, { NULL, W_ERROR(0) } }; +werror_str_struct dos_err_strs[] = { + { WERR_OK, "Success" }, + { WERR_ACCESS_DENIED, "Access is denied" }, + { WERR_INVALID_PARAM, "Invalid parameter" }, + { WERR_NOT_SUPPORTED, "Not supported" }, + { WERR_BAD_PASSWORD, "A bad password was supplied" }, + { WERR_NOMEM, "Out of memory" }, + { WERR_NO_LOGON_SERVERS, "No logon servers found" }, + { WERR_NO_SUCH_LOGON_SESSION, "No such logon session" }, + { WERR_DOMAIN_CONTROLLER_NOT_FOUND, "A domain controller could not be found" }, + { WERR_DC_NOT_FOUND, "A domain controller could not be found" }, + { WERR_SETUP_NOT_JOINED, "Join failed" }, + { WERR_SETUP_ALREADY_JOINED, "Machine is already joined" }, + { WERR_SETUP_DOMAIN_CONTROLLER, "Machine is a Domain Controller" }, + { WERR_LOGON_FAILURE, "Invalid logon credentials" }, + { WERR_USER_EXISTS, "User account already exists" }, + { WERR_PASSWORD_MUST_CHANGE, "The password must be changed" }, + { WERR_ACCOUNT_LOCKED_OUT, "Account locked out" }, +}; + /***************************************************************************** Returns a DOS error message. not amazingly helpful, but better than a number. *****************************************************************************/ @@ -101,7 +133,7 @@ const char *dos_errstr(WERROR werror) int idx = 0; while (dos_errs[idx].dos_errstr != NULL) { - if (W_ERROR_V(dos_errs[idx].werror) == + if (W_ERROR_V(dos_errs[idx].werror) == W_ERROR_V(werror)) return dos_errs[idx].dos_errstr; idx++; @@ -113,6 +145,24 @@ const char *dos_errstr(WERROR werror) return result; } +/***************************************************************************** + Get friendly error string for WERRORs + *****************************************************************************/ + +const char *get_friendly_werror_msg(WERROR werror) +{ + int i = 0; + + for (i = 0; i < ARRAY_SIZE(dos_err_strs); i++) { + if (W_ERROR_V(dos_err_strs[i].werror) == + W_ERROR_V(werror)) { + return dos_err_strs[i].friendly_errstr; + } + } + + return dos_errstr(werror); +} + /* compat function for samba4 */ const char *win_errstr(WERROR werror) { diff --git a/source3/libsmb/dsgetdcname.c b/source3/libsmb/dsgetdcname.c index f8089cbd6a..e0be76cc85 100644 --- a/source3/libsmb/dsgetdcname.c +++ b/source3/libsmb/dsgetdcname.c @@ -1,10 +1,10 @@ /* Unix SMB/CIFS implementation. - DsGetDcname + dsgetdcname Copyright (C) Gerald Carter 2006 - Copyright (C) Guenther Deschner 2007 + Copyright (C) Guenther Deschner 2007-2008 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 @@ -259,7 +259,7 @@ static NTSTATUS unpack_dsdcinfo(TALLOC_CTX *mem_ctx, /**************************************************************** ****************************************************************/ -static char *DsGetDcName_cache_key(TALLOC_CTX *mem_ctx, const char *domain) +static char *dsgetdcname_cache_key(TALLOC_CTX *mem_ctx, const char *domain) { if (!mem_ctx || !domain) { return NULL; @@ -271,7 +271,7 @@ static char *DsGetDcName_cache_key(TALLOC_CTX *mem_ctx, const char *domain) /**************************************************************** ****************************************************************/ -static NTSTATUS DsGetDcName_cache_delete(TALLOC_CTX *mem_ctx, +static NTSTATUS dsgetdcname_cache_delete(TALLOC_CTX *mem_ctx, const char *domain_name) { char *key; @@ -280,7 +280,7 @@ static NTSTATUS DsGetDcName_cache_delete(TALLOC_CTX *mem_ctx, return NT_STATUS_INTERNAL_DB_ERROR; } - key = DsGetDcName_cache_key(mem_ctx, domain_name); + key = dsgetdcname_cache_key(mem_ctx, domain_name); if (!key) { return NT_STATUS_NO_MEMORY; } @@ -295,13 +295,13 @@ static NTSTATUS DsGetDcName_cache_delete(TALLOC_CTX *mem_ctx, /**************************************************************** ****************************************************************/ -static NTSTATUS DsGetDcName_cache_store(TALLOC_CTX *mem_ctx, +static NTSTATUS dsgetdcname_cache_store(TALLOC_CTX *mem_ctx, const char *domain_name, struct DS_DOMAIN_CONTROLLER_INFO *info) { time_t expire_time; char *key; - bool ret = False; + bool ret = false; DATA_BLOB blob; unsigned char *buf = NULL; int len = 0; @@ -310,7 +310,7 @@ static NTSTATUS DsGetDcName_cache_store(TALLOC_CTX *mem_ctx, return NT_STATUS_INTERNAL_DB_ERROR; } - key = DsGetDcName_cache_key(mem_ctx, domain_name); + key = dsgetdcname_cache_key(mem_ctx, domain_name); if (!key) { return NT_STATUS_NO_MEMORY; } @@ -341,7 +341,7 @@ static NTSTATUS DsGetDcName_cache_store(TALLOC_CTX *mem_ctx, /**************************************************************** ****************************************************************/ -static NTSTATUS DsGetDcName_cache_refresh(TALLOC_CTX *mem_ctx, +static NTSTATUS dsgetdcname_cache_refresh(TALLOC_CTX *mem_ctx, const char *domain_name, struct GUID *domain_guid, uint32_t flags, @@ -358,9 +358,9 @@ static NTSTATUS DsGetDcName_cache_refresh(TALLOC_CTX *mem_ctx, if (ads_cldap_netlogon(info->domain_controller_name, info->domain_name, &r)) { - DsGetDcName_cache_delete(mem_ctx, domain_name); + dsgetdcname_cache_delete(mem_ctx, domain_name); - return DsGetDcName_cache_store(mem_ctx, + return dsgetdcname_cache_store(mem_ctx, info->domain_name, info); } @@ -371,7 +371,7 @@ static NTSTATUS DsGetDcName_cache_refresh(TALLOC_CTX *mem_ctx, /**************************************************************** ****************************************************************/ -#define RETURN_ON_FALSE(x) if (!x) return False; +#define RETURN_ON_FALSE(x) if (!x) return false; static bool check_cldap_reply_required_flags(uint32_t ret_flags, uint32_t req_flags) @@ -398,13 +398,13 @@ static bool check_cldap_reply_required_flags(uint32_t ret_flags, if (req_flags & DS_WRITABLE_REQUIRED) RETURN_ON_FALSE(ret_flags & ADS_WRITABLE); - return True; + return true; } /**************************************************************** ****************************************************************/ -static NTSTATUS DsGetDcName_cache_fetch(TALLOC_CTX *mem_ctx, +static NTSTATUS dsgetdcname_cache_fetch(TALLOC_CTX *mem_ctx, const char *domain_name, struct GUID *domain_guid, uint32_t flags, @@ -420,7 +420,7 @@ static NTSTATUS DsGetDcName_cache_fetch(TALLOC_CTX *mem_ctx, return NT_STATUS_INTERNAL_DB_ERROR; } - key = DsGetDcName_cache_key(mem_ctx, domain_name); + key = dsgetdcname_cache_key(mem_ctx, domain_name); if (!key) { return NT_STATUS_NO_MEMORY; } @@ -454,7 +454,7 @@ static NTSTATUS DsGetDcName_cache_fetch(TALLOC_CTX *mem_ctx, /**************************************************************** ****************************************************************/ -static NTSTATUS DsGetDcName_cached(TALLOC_CTX *mem_ctx, +static NTSTATUS dsgetdcname_cached(TALLOC_CTX *mem_ctx, const char *domain_name, struct GUID *domain_guid, uint32_t flags, @@ -462,12 +462,12 @@ static NTSTATUS DsGetDcName_cached(TALLOC_CTX *mem_ctx, struct DS_DOMAIN_CONTROLLER_INFO **info) { NTSTATUS status; - bool expired = False; + bool expired = false; - status = DsGetDcName_cache_fetch(mem_ctx, domain_name, domain_guid, + status = dsgetdcname_cache_fetch(mem_ctx, domain_name, domain_guid, flags, site_name, info, &expired); if (!NT_STATUS_IS_OK(status)) { - DEBUG(10,("DsGetDcName_cached: cache fetch failed with: %s\n", + DEBUG(10,("dsgetdcname_cached: cache fetch failed with: %s\n", nt_errstr(status))); return NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND; } @@ -477,7 +477,7 @@ static NTSTATUS DsGetDcName_cached(TALLOC_CTX *mem_ctx, } if (expired) { - status = DsGetDcName_cache_refresh(mem_ctx, domain_name, + status = dsgetdcname_cache_refresh(mem_ctx, domain_name, domain_guid, flags, site_name, *info); if (!NT_STATUS_IS_OK(status)) { @@ -503,24 +503,24 @@ static bool check_allowed_required_flags(uint32_t flags) debug_dsdcinfo_flags(10, flags); if (return_type == (DS_RETURN_FLAT_NAME|DS_RETURN_DNS_NAME)) { - return False; + return false; } if (offered_type == (DS_IS_DNS_NAME|DS_IS_FLAT_NAME)) { - return False; + return false; } if (query_type == (DS_BACKGROUND_ONLY|DS_FORCE_REDISCOVERY)) { - return False; + return false; } #if 0 if ((flags & DS_RETURN_DNS_NAME) && (!(flags & DS_IP_REQUIRED))) { printf("gd: here5 \n"); - return False; + return false; } #endif - return True; + return true; } /**************************************************************** @@ -739,7 +739,7 @@ static NTSTATUS process_dc_dns(TALLOC_CTX *mem_ctx, struct DS_DOMAIN_CONTROLLER_INFO **info) { int i = 0; - bool valid_dc = False; + bool valid_dc = false; struct cldap_netlogon_reply r; const char *dc_hostname, *dc_domain_name; const char *dc_address; @@ -754,7 +754,7 @@ static NTSTATUS process_dc_dns(TALLOC_CTX *mem_ctx, if ((ads_cldap_netlogon(dclist[i]->hostname, domain_name, &r)) && (check_cldap_reply_required_flags(r.flags, flags))) { - valid_dc = True; + valid_dc = true; break; } @@ -837,7 +837,7 @@ static NTSTATUS process_dc_netbios(TALLOC_CTX *mem_ctx, /**************************************************************** ****************************************************************/ -static NTSTATUS DsGetDcName_rediscover(TALLOC_CTX *mem_ctx, +static NTSTATUS dsgetdcname_rediscover(TALLOC_CTX *mem_ctx, const char *domain_name, struct GUID *domain_guid, uint32_t flags, @@ -848,7 +848,7 @@ static NTSTATUS DsGetDcName_rediscover(TALLOC_CTX *mem_ctx, struct ip_service_name *dclist; int num_dcs; - DEBUG(10,("DsGetDcName_rediscover\n")); + DEBUG(10,("dsgetdcname_rediscover\n")); if (flags & DS_IS_FLAT_NAME) { @@ -891,13 +891,12 @@ static NTSTATUS DsGetDcName_rediscover(TALLOC_CTX *mem_ctx, } /******************************************************************** - DsGetDcName. + dsgetdcname. This will be the only public function here. ********************************************************************/ -NTSTATUS DsGetDcName(TALLOC_CTX *mem_ctx, - const char *computer_name, +NTSTATUS dsgetdcname(TALLOC_CTX *mem_ctx, const char *domain_name, struct GUID *domain_guid, const char *site_name, @@ -907,9 +906,9 @@ NTSTATUS DsGetDcName(TALLOC_CTX *mem_ctx, NTSTATUS status = NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND; struct DS_DOMAIN_CONTROLLER_INFO *myinfo = NULL; - DEBUG(10,("DsGetDcName: computer_name: %s, domain_name: %s, " + DEBUG(10,("dsgetdcname: domain_name: %s, " "domain_guid: %s, site_name: %s, flags: 0x%08x\n", - computer_name, domain_name, + domain_name, domain_guid ? GUID_string(mem_ctx, domain_guid) : "(null)", site_name, flags)); @@ -924,7 +923,7 @@ NTSTATUS DsGetDcName(TALLOC_CTX *mem_ctx, goto rediscover; } - status = DsGetDcName_cached(mem_ctx, domain_name, domain_guid, + status = dsgetdcname_cached(mem_ctx, domain_name, domain_guid, flags, site_name, &myinfo); if (NT_STATUS_IS_OK(status)) { *info = myinfo; @@ -936,12 +935,12 @@ NTSTATUS DsGetDcName(TALLOC_CTX *mem_ctx, } rediscover: - status = DsGetDcName_rediscover(mem_ctx, domain_name, + status = dsgetdcname_rediscover(mem_ctx, domain_name, domain_guid, flags, site_name, &myinfo); if (NT_STATUS_IS_OK(status)) { - DsGetDcName_cache_store(mem_ctx, domain_name, myinfo); + dsgetdcname_cache_store(mem_ctx, domain_name, myinfo); *info = myinfo; } diff --git a/source3/libsmb/errormap.c b/source3/libsmb/errormap.c index ce826ae999..4ec30f7e17 100644 --- a/source3/libsmb/errormap.c +++ b/source3/libsmb/errormap.c @@ -1502,3 +1502,108 @@ WERROR ntstatus_to_werror(NTSTATUS error) /* a lame guess */ return W_ERROR(NT_STATUS_V(error) & 0xffff); } + +#if defined(HAVE_GSSAPI) +/******************************************************************************* + Map between gssapi errors and NT status. I made these up :-(. JRA. +*******************************************************************************/ + +static const struct { + unsigned long gss_err; + NTSTATUS ntstatus; +} gss_to_ntstatus_errormap[] = { +#if defined(GSS_S_CALL_INACCESSIBLE_READ) + {GSS_S_CALL_INACCESSIBLE_READ, NT_STATUS_INVALID_PARAMETER}, +#endif +#if defined(GSS_S_CALL_INACCESSIBLE_WRITE) + {GSS_S_CALL_INACCESSIBLE_WRITE, NT_STATUS_INVALID_PARAMETER}, +#endif +#if defined(GSS_S_CALL_BAD_STRUCTURE) + {GSS_S_CALL_BAD_STRUCTURE, NT_STATUS_INVALID_PARAMETER}, +#endif +#if defined(GSS_S_BAD_MECH) + {GSS_S_BAD_MECH, NT_STATUS_INVALID_PARAMETER}, +#endif +#if defined(GSS_S_BAD_NAME) + {GSS_S_BAD_NAME, NT_STATUS_INVALID_ACCOUNT_NAME}, +#endif +#if defined(GSS_S_BAD_NAMETYPE) + {GSS_S_BAD_NAMETYPE, NT_STATUS_INVALID_PARAMETER}, +#endif +#if defined(GSS_S_BAD_BINDINGS) + {GSS_S_BAD_BINDINGS, NT_STATUS_INVALID_PARAMETER}, +#endif +#if defined(GSS_S_BAD_STATUS) + {GSS_S_BAD_STATUS, NT_STATUS_UNSUCCESSFUL}, +#endif +#if defined(GSS_S_BAD_SIG) + {GSS_S_BAD_SIG, NT_STATUS_ACCESS_DENIED}, +#endif +#if defined(GSS_S_NO_CRED) + {GSS_S_NO_CRED, NT_STATUS_ACCESS_DENIED}, +#endif +#if defined(GSS_S_NO_CONTEXT) + {GSS_S_NO_CONTEXT, NT_STATUS_ACCESS_DENIED}, +#endif +#if defined(GSS_S_DEFECTIVE_TOKEN) + {GSS_S_DEFECTIVE_TOKEN, NT_STATUS_ACCESS_DENIED}, +#endif +#if defined(GSS_S_DEFECTIVE_CREDENTIAL) + {GSS_S_DEFECTIVE_CREDENTIAL, NT_STATUS_ACCESS_DENIED}, +#endif +#if defined(GSS_S_CREDENTIALS_EXPIRED) + {GSS_S_CREDENTIALS_EXPIRED, NT_STATUS_PASSWORD_EXPIRED}, +#endif +#if defined(GSS_S_CONTEXT_EXPIRED) + {GSS_S_CONTEXT_EXPIRED, NT_STATUS_PASSWORD_EXPIRED}, +#endif +#if defined(GSS_S_BAD_QOP) + {GSS_S_BAD_QOP, NT_STATUS_ACCESS_DENIED}, +#endif +#if defined(GSS_S_UNAUTHORIZED) + {GSS_S_UNAUTHORIZED, NT_STATUS_ACCESS_DENIED}, +#endif +#if defined(GSS_S_UNAVAILABLE) + {GSS_S_UNAVAILABLE, NT_STATUS_UNSUCCESSFUL}, +#endif +#if defined(GSS_S_DUPLICATE_ELEMENT) + {GSS_S_DUPLICATE_ELEMENT, NT_STATUS_INVALID_PARAMETER}, +#endif +#if defined(GSS_S_NAME_NOT_MN) + {GSS_S_NAME_NOT_MN, NT_STATUS_INVALID_PARAMETER}, +#endif + { 0, NT_STATUS_OK } +}; + +/********************************************************************* + Map an NT error code from a gssapi error code. +*********************************************************************/ + +NTSTATUS map_nt_error_from_gss(uint32 gss_maj, uint32 minor) +{ + int i = 0; + + if (gss_maj == GSS_S_COMPLETE) { + return NT_STATUS_OK; + } + + if (gss_maj == GSS_S_CONTINUE_NEEDED) { + return NT_STATUS_MORE_PROCESSING_REQUIRED; + } + + if (gss_maj == GSS_S_FAILURE) { + return map_nt_error_from_unix((int)minor); + } + + /* Look through list */ + while(gss_to_ntstatus_errormap[i].gss_err != 0) { + if (gss_to_ntstatus_errormap[i].gss_err == gss_maj) { + return gss_to_ntstatus_errormap[i].ntstatus; + } + i++; + } + + /* Default return */ + return NT_STATUS_ACCESS_DENIED; +} +#endif diff --git a/source3/libsmb/libsmbclient.c b/source3/libsmb/libsmbclient.c index 2ff2830256..2eb580a52d 100644 --- a/source3/libsmb/libsmbclient.c +++ b/source3/libsmb/libsmbclient.c @@ -6,6 +6,7 @@ Copyright (C) John Terpstra 2000 Copyright (C) Tom Jansen (Ninja ISD) 2002 Copyright (C) Derrell Lipman 2003, 2004 + Copyright (C) Jeremy Allison 2007, 2008 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 @@ -591,13 +592,58 @@ smbc_remove_unused_server(SMBCCTX * context, return 0; } +/**************************************************************** + * Call the auth_fn with fixed size (fstring) buffers. + ***************************************************************/ + +static void call_auth_fn(TALLOC_CTX *ctx, + SMBCCTX *context, + const char *server, + const char *share, + char **pp_workgroup, + char **pp_username, + char **pp_password) +{ + fstring workgroup; + fstring username; + fstring password; + + strlcpy(workgroup, *pp_workgroup, sizeof(workgroup)); + strlcpy(username, *pp_username, sizeof(username)); + strlcpy(password, *pp_password, sizeof(password)); + + if (context->internal->_auth_fn_with_context != NULL) { + (context->internal->_auth_fn_with_context)( + context, + server, share, + workgroup, sizeof(workgroup), + username, sizeof(username), + password, sizeof(password)); + } else { + (context->callbacks.auth_fn)( + server, share, + workgroup, sizeof(workgroup), + username, sizeof(username), + password, sizeof(password)); + } + + TALLOC_FREE(*pp_workgroup); + TALLOC_FREE(*pp_username); + TALLOC_FREE(*pp_password); + + *pp_workgroup = talloc_strdup(ctx, workgroup); + *pp_username = talloc_strdup(ctx, username); + *pp_password = talloc_strdup(ctx, password); +} + static SMBCSRV * -find_server(SMBCCTX *context, +find_server(TALLOC_CTX *ctx, + SMBCCTX *context, const char *server, const char *share, - char *workgroup, - char *username, - char *password) + char **pp_workgroup, + char **pp_username, + char **pp_password) { SMBCSRV *srv; int auth_called = 0; @@ -605,22 +651,15 @@ find_server(SMBCCTX *context, check_server_cache: srv = (context->callbacks.get_cached_srv_fn)(context, server, share, - workgroup, username); - - if (!auth_called && !srv && (!username[0] || !password[0])) { - if (context->internal->_auth_fn_with_context != NULL) { - (context->internal->_auth_fn_with_context)( - context, - server, share, - workgroup, strlen(workgroup)+1, - username, strlen(username)+1, - password, strlen(password)+1); - } else { - (context->callbacks.auth_fn)( - server, share, - workgroup, strlen(workgroup)+1, - username, strlen(username)+1, - password, strlen(password)+1); + *pp_workgroup, *pp_username); + + if (!auth_called && !srv && (!*pp_username || !(*pp_username)[0] || + !*pp_password || !(*pp_password)[0])) { + call_auth_fn(ctx, context, server, share, + pp_workgroup, pp_username, pp_password); + + if (!pp_workgroup || !pp_username || !pp_password) { + return NULL; } /* @@ -651,12 +690,12 @@ find_server(SMBCCTX *context, (context->callbacks.remove_cached_srv_fn)(context, srv); } - + /* * Maybe there are more cached connections to this * server */ - goto check_server_cache; + goto check_server_cache; } return srv; @@ -677,13 +716,14 @@ find_server(SMBCCTX *context, */ static SMBCSRV * -smbc_server(SMBCCTX *context, +smbc_server(TALLOC_CTX *ctx, + SMBCCTX *context, bool connect_if_not_found, const char *server, const char *share, - char *workgroup, - char *username, - char *password) + char **pp_workgroup, + char **pp_username, + char **pp_password) { SMBCSRV *srv=NULL; struct cli_state *c; @@ -705,8 +745,8 @@ smbc_server(SMBCCTX *context, } /* Look for a cached connection */ - srv = find_server(context, server, share, - workgroup, username, password); + srv = find_server(ctx, context, server, share, + pp_workgroup, pp_username, pp_password); /* * If we found a connection and we're only allowed one share per @@ -724,23 +764,27 @@ smbc_server(SMBCCTX *context, */ if (srv->cli->cnum == (uint16) -1) { /* Ensure we have accurate auth info */ - if (context->internal->_auth_fn_with_context != NULL) { - (context->internal->_auth_fn_with_context)( - context, - server, share, - workgroup, strlen(workgroup)+1, - username, strlen(username)+1, - password, strlen(password)+1); - } else { - (context->callbacks.auth_fn)( - server, share, - workgroup, strlen(workgroup)+1, - username, strlen(username)+1, - password, strlen(password)+1); - } + call_auth_fn(ctx, context, server, share, + pp_workgroup, pp_username, pp_password); + + if (!*pp_workgroup || !*pp_username || !*pp_password) { + errno = ENOMEM; + cli_shutdown(srv->cli); + srv->cli = NULL; + (context->callbacks.remove_cached_srv_fn)(context, + srv); + return NULL; + } + + /* + * We don't need to renegotiate encryption + * here as the encryption context is not per + * tid. + */ - if (! cli_send_tconX(srv->cli, share, "?????", - password, strlen(password)+1)) { + if (!cli_send_tconX(srv->cli, share, "?????", + *pp_password, + strlen(*pp_password)+1)) { errno = smbc_errno(context, srv->cli); cli_shutdown(srv->cli); @@ -774,6 +818,11 @@ smbc_server(SMBCCTX *context, return NULL; } + if (!*pp_workgroup || !*pp_username || !*pp_password) { + errno = ENOMEM; + return NULL; + } + make_nmb_name(&calling, context->netbios_name, 0x0); make_nmb_name(&called , server, 0x20); @@ -870,21 +919,21 @@ smbc_server(SMBCCTX *context, return NULL; } - username_used = username; + username_used = *pp_username; if (!NT_STATUS_IS_OK(cli_session_setup(c, username_used, - password, strlen(password), - password, strlen(password), - workgroup))) { + *pp_password, strlen(*pp_password), + *pp_password, strlen(*pp_password), + *pp_workgroup))) { /* Failed. Try an anonymous login, if allowed by flags. */ username_used = ""; if ((context->flags & SMBCCTX_FLAG_NO_AUTO_ANONYMOUS_LOGON) || !NT_STATUS_IS_OK(cli_session_setup(c, username_used, - password, 1, - password, 0, - workgroup))) { + *pp_password, 1, + *pp_password, 0, + *pp_workgroup))) { cli_shutdown(c); errno = EPERM; @@ -895,7 +944,7 @@ smbc_server(SMBCCTX *context, DEBUG(4,(" session setup ok\n")); if (!cli_send_tconX(c, share, "?????", - password, strlen(password)+1)) { + *pp_password, strlen(*pp_password)+1)) { errno = smbc_errno(context, c); cli_shutdown(c); return NULL; @@ -903,6 +952,30 @@ smbc_server(SMBCCTX *context, DEBUG(4,(" tconx ok\n")); + if (context->internal->_smb_encryption_level) { + /* Attempt UNIX smb encryption. */ + if (!NT_STATUS_IS_OK(cli_force_encryption(c, + username_used, + *pp_password, + *pp_workgroup))) { + + /* + * context->internal->_smb_encryption_level == 1 + * means don't fail if encryption can't be negotiated, + * == 2 means fail if encryption can't be negotiated. + */ + + DEBUG(4,(" SMB encrypt failed\n")); + + if (context->internal->_smb_encryption_level == 2) { + cli_shutdown(c); + errno = EPERM; + return NULL; + } + } + DEBUG(4,(" SMB encrypt ok\n")); + } + /* * Ok, we have got a nice connection * Let's allocate a server structure. @@ -925,8 +998,9 @@ smbc_server(SMBCCTX *context, /* Let the cache function set errno if it wants to */ errno = 0; if ((context->callbacks.add_cached_srv_fn)(context, srv, - server, share, - workgroup, username)) { + server, share, + *pp_workgroup, + *pp_username)) { int saved_errno = errno; DEBUG(3, (" Failed to add server to cache\n")); errno = saved_errno; @@ -957,13 +1031,13 @@ smbc_server(SMBCCTX *context, * connection. This works similarly to smbc_server(). */ static SMBCSRV * -smbc_attr_server(SMBCCTX *context, - const char *server, - const char *share, - char *workgroup, - char *username, - char *password, - POLICY_HND *pol) +smbc_attr_server(TALLOC_CTX *ctx, + SMBCCTX *context, + const char *server, + const char *share, + char **pp_workgroup, + char **pp_username, + char **pp_password) { int flags; struct sockaddr_storage ss; @@ -977,27 +1051,19 @@ smbc_attr_server(SMBCCTX *context, * our "special" share name '*IPC$', which is an impossible real share * name due to the leading asterisk. */ - ipc_srv = find_server(context, server, "*IPC$", - workgroup, username, password); + ipc_srv = find_server(ctx, context, server, "*IPC$", + pp_workgroup, pp_username, pp_password); if (!ipc_srv) { /* We didn't find a cached connection. Get the password */ - if (*password == '\0') { + if (!*pp_password || (*pp_password)[0] == '\0') { /* ... then retrieve it now. */ - if (context->internal->_auth_fn_with_context != NULL) { - (context->internal->_auth_fn_with_context)( - context, - server, share, - workgroup, strlen(workgroup)+1, - username, strlen(username)+1, - password, strlen(password)+1); - } else { - (context->callbacks.auth_fn)( - server, share, - workgroup, strlen(workgroup)+1, - username, strlen(username)+1, - password, strlen(password)+1); - } + call_auth_fn(ctx, context, server, share, + pp_workgroup, pp_username, pp_password); + if (!*pp_workgroup || !*pp_username || !*pp_password) { + errno = ENOMEM; + return NULL; + } } flags = 0; @@ -1007,11 +1073,13 @@ smbc_attr_server(SMBCCTX *context, zero_addr(&ss); nt_status = cli_full_connection(&ipc_cli, - global_myname(), server, - &ss, 0, "IPC$", "?????", - username, workgroup, - password, flags, - Undefined, NULL); + global_myname(), server, + &ss, 0, "IPC$", "?????", + *pp_username, + *pp_workgroup, + *pp_password, + flags, + Undefined, NULL); if (! NT_STATUS_IS_OK(nt_status)) { DEBUG(1,("cli_full_connection failed! (%s)\n", nt_errstr(nt_status))); @@ -1019,6 +1087,30 @@ smbc_attr_server(SMBCCTX *context, return NULL; } + if (context->internal->_smb_encryption_level) { + /* Attempt UNIX smb encryption. */ + if (!NT_STATUS_IS_OK(cli_force_encryption(ipc_cli, + *pp_username, + *pp_password, + *pp_workgroup))) { + + /* + * context->internal->_smb_encryption_level == 1 + * means don't fail if encryption can't be negotiated, + * == 2 means fail if encryption can't be negotiated. + */ + + DEBUG(4,(" SMB encrypt failed on IPC$\n")); + + if (context->internal->_smb_encryption_level == 2) { + cli_shutdown(ipc_cli); + errno = EPERM; + return NULL; + } + } + DEBUG(4,(" SMB encrypt ok on IPC$\n")); + } + ipc_srv = SMB_MALLOC_P(SMBCSRV); if (!ipc_srv) { errno = ENOMEM; @@ -1029,46 +1121,44 @@ smbc_attr_server(SMBCCTX *context, ZERO_STRUCTP(ipc_srv); ipc_srv->cli = ipc_cli; - if (pol) { - pipe_hnd = cli_rpc_pipe_open_noauth(ipc_srv->cli, - PI_LSARPC, - &nt_status); - if (!pipe_hnd) { - DEBUG(1, ("cli_nt_session_open fail!\n")); - errno = ENOTSUP; - cli_shutdown(ipc_srv->cli); - free(ipc_srv); - return NULL; - } + pipe_hnd = cli_rpc_pipe_open_noauth(ipc_srv->cli, + PI_LSARPC, + &nt_status); + if (!pipe_hnd) { + DEBUG(1, ("cli_nt_session_open fail!\n")); + errno = ENOTSUP; + cli_shutdown(ipc_srv->cli); + free(ipc_srv); + 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, - talloc_tos(), - True, - GENERIC_EXECUTE_ACCESS, - pol); - - if (!NT_STATUS_IS_OK(nt_status)) { - errno = smbc_errno(context, ipc_srv->cli); - cli_shutdown(ipc_srv->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, + talloc_tos(), + True, + GENERIC_EXECUTE_ACCESS, + &ipc_srv->pol); + + if (!NT_STATUS_IS_OK(nt_status)) { + errno = smbc_errno(context, ipc_srv->cli); + cli_shutdown(ipc_srv->cli); + return NULL; } /* now add it to the cache (internal or external) */ errno = 0; /* let cache function set errno if it likes */ if ((context->callbacks.add_cached_srv_fn)(context, ipc_srv, - server, - "*IPC$", - workgroup, - username)) { + server, + "*IPC$", + *pp_workgroup, + *pp_username)) { DEBUG(3, (" Failed to add server to cache\n")); if (errno == 0) { errno = ENOMEM; @@ -1094,10 +1184,10 @@ smbc_open_ctx(SMBCCTX *context, int flags, mode_t mode) { - char *server, *share, *user, *password, *workgroup; - char *path; + char *server = NULL, *share = NULL, *user = NULL, *password = NULL, *workgroup = NULL; + char *path = NULL; char *targetpath = NULL; - struct cli_state *targetcli; + struct cli_state *targetcli = NULL; SMBCSRV *srv = NULL; SMBCFILE *file = NULL; int fd; @@ -1144,8 +1234,8 @@ smbc_open_ctx(SMBCCTX *context, } } - srv = smbc_server(context, True, - server, share, workgroup, user, password); + srv = smbc_server(frame, context, True, + server, share, &workgroup, &user, &password); if (!srv) { if (errno == EPERM) errno = EACCES; @@ -1288,10 +1378,10 @@ smbc_read_ctx(SMBCCTX *context, size_t count) { int ret; - char *server, *share, *user, *password; - char *path; + char *server = NULL, *share = NULL, *user = NULL, *password = NULL; + char *path = NULL; char *targetpath = NULL; - struct cli_state *targetcli; + struct cli_state *targetcli = NULL; TALLOC_CTX *frame = talloc_stackframe(); /* @@ -1389,10 +1479,10 @@ smbc_write_ctx(SMBCCTX *context, { int ret; off_t offset; - char *server, *share, *user, *password; - char *path; + char *server = NULL, *share = NULL, *user = NULL, *password = NULL; + char *path = NULL; char *targetpath = NULL; - struct cli_state *targetcli; + struct cli_state *targetcli = NULL; TALLOC_CTX *frame = talloc_stackframe(); /* First check all pointers before dereferencing them */ @@ -1471,10 +1561,10 @@ smbc_close_ctx(SMBCCTX *context, SMBCFILE *file) { SMBCSRV *srv; - char *server, *share, *user, *password; - char *path; + char *server = NULL, *share = NULL, *user = NULL, *password = NULL; + char *path = NULL; char *targetpath = NULL; - struct cli_state *targetcli; + struct cli_state *targetcli = NULL; TALLOC_CTX *frame = talloc_stackframe(); if (!context || !context->internal || @@ -1563,9 +1653,9 @@ smbc_getatr(SMBCCTX * context, struct timespec *change_time_ts, SMB_INO_T *ino) { - char *fixedpath; + char *fixedpath = NULL; char *targetpath = NULL; - struct cli_state *targetcli; + struct cli_state *targetcli = NULL; time_t write_time; TALLOC_CTX *frame = talloc_stackframe(); @@ -1634,11 +1724,11 @@ smbc_getatr(SMBCCTX * context, if (create_time_ts != NULL) { *create_time_ts = w_time_ts; } - + if (access_time_ts != NULL) { *access_time_ts = w_time_ts; } - + if (change_time_ts != NULL) { *change_time_ts = w_time_ts; } @@ -1749,10 +1839,10 @@ static int smbc_unlink_ctx(SMBCCTX *context, const char *fname) { - char *server, *share, *user, *password, *workgroup; - char *path; - char *targetpath; - struct cli_state *targetcli; + char *server = NULL, *share = NULL, *user = NULL, *password = NULL, *workgroup = NULL; + char *path = NULL; + char *targetpath = NULL; + struct cli_state *targetcli = NULL; SMBCSRV *srv = NULL; TALLOC_CTX *frame = talloc_stackframe(); @@ -1795,8 +1885,8 @@ smbc_unlink_ctx(SMBCCTX *context, } } - srv = smbc_server(context, True, - server, share, workgroup, user, password); + srv = smbc_server(frame, context, True, + server, share, &workgroup, &user, &password); if (!srv) { TALLOC_FREE(frame); @@ -1871,21 +1961,21 @@ smbc_rename_ctx(SMBCCTX *ocontext, SMBCCTX *ncontext, const char *nname) { - char *server1; - char *share1; - char *server2; - char *share2; - char *user1; - char *user2; - char *password1; - char *password2; - char *workgroup; - char *path1; - char *path2; - char *targetpath1; - char *targetpath2; - struct cli_state *targetcli1; - struct cli_state *targetcli2; + char *server1 = NULL; + char *share1 = NULL; + char *server2 = NULL; + char *share2 = NULL; + char *user1 = NULL; + char *user2 = NULL; + char *password1 = NULL; + char *password2 = NULL; + char *workgroup = NULL; + char *path1 = NULL; + char *path2 = NULL; + char *targetpath1 = NULL; + char *targetpath2 = NULL; + struct cli_state *targetcli1 = NULL; + struct cli_state *targetcli2 = NULL; SMBCSRV *srv = NULL; TALLOC_CTX *frame = talloc_stackframe(); @@ -1962,8 +2052,8 @@ smbc_rename_ctx(SMBCCTX *ocontext, return -1; } - srv = smbc_server(ocontext, True, - server1, share1, workgroup, user1, password1); + srv = smbc_server(frame, ocontext, True, + server1, share1, &workgroup, &user1, &password1); if (!srv) { TALLOC_FREE(frame); return -1; @@ -2025,10 +2115,10 @@ smbc_lseek_ctx(SMBCCTX *context, int whence) { SMB_OFF_T size; - char *server, *share, *user, *password; - char *path; - char *targetpath; - struct cli_state *targetcli; + char *server = NULL, *share = NULL, *user = NULL, *password = NULL; + char *path = NULL; + char *targetpath = NULL; + struct cli_state *targetcli = NULL; TALLOC_CTX *frame = talloc_stackframe(); if (!context || !context->internal || @@ -2171,6 +2261,9 @@ smbc_setup_stat(SMBCCTX *context, #ifdef HAVE_STAT_ST_BLOCKS st->st_blocks = (size+511)/512; #endif +#ifdef HAVE_STRUCT_STAT_ST_RDEV + st->st_rdev = 0; +#endif st->st_uid = getuid(); st->st_gid = getgid(); @@ -2198,13 +2291,13 @@ smbc_stat_ctx(SMBCCTX *context, const char *fname, struct stat *st) { - SMBCSRV *srv; - char *server; - char *share; - char *user; - char *password; - char *workgroup; - char *path; + SMBCSRV *srv = NULL; + char *server = NULL; + char *share = NULL; + char *user = NULL; + char *password = NULL; + char *workgroup = NULL; + char *path = NULL; struct timespec write_time_ts; struct timespec access_time_ts; struct timespec change_time_ts; @@ -2253,8 +2346,8 @@ smbc_stat_ctx(SMBCCTX *context, } } - srv = smbc_server(context, True, - server, share, workgroup, user, password); + srv = smbc_server(frame, context, True, + server, share, &workgroup, &user, &password); if (!srv) { TALLOC_FREE(frame); @@ -2274,7 +2367,7 @@ smbc_stat_ctx(SMBCCTX *context, st->st_ino = ino; - smbc_setup_stat(context, st, path, size, mode); + smbc_setup_stat(context, st, (char *) fname, size, mode); set_atimespec(st, access_time_ts); set_ctimespec(st, change_time_ts); @@ -2300,13 +2393,13 @@ smbc_fstat_ctx(SMBCCTX *context, struct timespec write_time_ts; SMB_OFF_T size; uint16 mode; - char *server; - char *share; - char *user; - char *password; - char *path; - char *targetpath; - struct cli_state *targetcli; + char *server = NULL; + char *share = NULL; + char *user = NULL; + char *password = NULL; + char *path = NULL; + char *targetpath = NULL; + struct cli_state *targetcli = NULL; SMB_INO_T ino = 0; TALLOC_CTX *frame = talloc_stackframe(); @@ -2688,14 +2781,14 @@ smbc_opendir_ctx(SMBCCTX *context, const char *fname) { int saved_errno; - char *server, *share, *user, *password, *options; - char *workgroup; - char *path; + char *server = NULL, *share = NULL, *user = NULL, *password = NULL, *options = NULL; + char *workgroup = NULL; + char *path = NULL; uint16 mode; - char *p; + char *p = NULL; SMBCSRV *srv = NULL; SMBCFILE *dir = NULL; - struct _smbc_callbacks *cb; + struct _smbc_callbacks *cb = NULL; struct sockaddr_storage rem_ss; TALLOC_CTX *frame = talloc_stackframe(); @@ -2884,8 +2977,8 @@ smbc_opendir_ctx(SMBCCTX *context, * workgroups/domains that it knows about. */ - srv = smbc_server(context, True, server, "IPC$", - workgroup, user, password); + srv = smbc_server(frame, context, True, server, "IPC$", + &workgroup, &user, &password); if (!srv) { continue; } @@ -2938,8 +3031,8 @@ smbc_opendir_ctx(SMBCCTX *context, * establish a connection if one does not already * exist. */ - srv = smbc_server(context, False, server, "IPC$", - workgroup, user, password); + srv = smbc_server(frame, context, False, server, "IPC$", + &workgroup, &user, &password); /* * If no existing server and not an IP addr, look for @@ -2977,9 +3070,9 @@ smbc_opendir_ctx(SMBCCTX *context, * Get a connection to IPC$ on the server if * we do not already have one */ - srv = smbc_server(context, True, + srv = smbc_server(frame, context, True, buserver, "IPC$", - workgroup, user, password); + &workgroup, &user, &password); if (!srv) { DEBUG(0, ("got no contact to IPC$\n")); if (dir) { @@ -3010,10 +3103,10 @@ smbc_opendir_ctx(SMBCCTX *context, /* If we hadn't found the server, get one now */ if (!srv) { - srv = smbc_server(context, True, + srv = smbc_server(frame, context, True, server, "IPC$", - workgroup, - user, password); + &workgroup, + &user, &password); } if (!srv) { @@ -3072,8 +3165,8 @@ smbc_opendir_ctx(SMBCCTX *context, /* We connect to the server and list the directory */ dir->dir_type = SMBC_FILE_SHARE; - srv = smbc_server(context, True, server, share, - workgroup, user, password); + srv = smbc_server(frame, context, True, server, share, + &workgroup, &user, &password); if (!srv) { if (dir) { @@ -3440,15 +3533,15 @@ smbc_mkdir_ctx(SMBCCTX *context, const char *fname, mode_t mode) { - SMBCSRV *srv; - char *server; - char *share; - char *user; - char *password; - char *workgroup; - char *path; - char *targetpath; - struct cli_state *targetcli; + SMBCSRV *srv = NULL; + char *server = NULL; + char *share = NULL; + char *user = NULL; + char *password = NULL; + char *workgroup = NULL; + char *path = NULL; + char *targetpath = NULL; + struct cli_state *targetcli = NULL; TALLOC_CTX *frame = talloc_stackframe(); if (!context || !context->internal || @@ -3490,8 +3583,8 @@ smbc_mkdir_ctx(SMBCCTX *context, } } - srv = smbc_server(context, True, - server, share, workgroup, user, password); + srv = smbc_server(frame, context, True, + server, share, &workgroup, &user, &password); if (!srv) { @@ -3548,15 +3641,15 @@ static int smbc_rmdir_ctx(SMBCCTX *context, const char *fname) { - SMBCSRV *srv; - char *server; - char *share; - char *user; - char *password; - char *workgroup; - char *path; - char *targetpath; - struct cli_state *targetcli; + SMBCSRV *srv = NULL; + char *server = NULL; + char *share = NULL; + char *user = NULL; + char *password = NULL; + char *workgroup = NULL; + char *path = NULL; + char *targetpath = NULL; + struct cli_state *targetcli = NULL; TALLOC_CTX *frame = talloc_stackframe(); if (!context || !context->internal || @@ -3598,8 +3691,8 @@ smbc_rmdir_ctx(SMBCCTX *context, } } - srv = smbc_server(context, True, - server, share, workgroup, user, password); + srv = smbc_server(frame, context, True, + server, share, &workgroup, &user, &password); if (!srv) { @@ -3833,13 +3926,13 @@ smbc_chmod_ctx(SMBCCTX *context, const char *fname, mode_t newmode) { - SMBCSRV *srv; - char *server; - char *share; - char *user; - char *password; - char *workgroup; - char *path; + SMBCSRV *srv = NULL; + char *server = NULL; + char *share = NULL; + char *user = NULL; + char *password = NULL; + char *workgroup = NULL; + char *path = NULL; uint16 mode; TALLOC_CTX *frame = talloc_stackframe(); @@ -3882,8 +3975,8 @@ smbc_chmod_ctx(SMBCCTX *context, } } - srv = smbc_server(context, True, - server, share, workgroup, user, password); + srv = smbc_server(frame, context, True, + server, share, &workgroup, &user, &password); if (!srv) { TALLOC_FREE(frame); @@ -3912,13 +4005,13 @@ smbc_utimes_ctx(SMBCCTX *context, const char *fname, struct timeval *tbuf) { - SMBCSRV *srv; - char *server; - char *share; - char *user; - char *password; - char *workgroup; - char *path; + SMBCSRV *srv = NULL; + char *server = NULL; + char *share = NULL; + char *user = NULL; + char *password = NULL; + char *workgroup = NULL; + char *path = NULL; time_t access_time; time_t write_time; TALLOC_CTX *frame = talloc_stackframe(); @@ -3988,8 +4081,8 @@ smbc_utimes_ctx(SMBCCTX *context, } } - srv = smbc_server(context, True, - server, share, workgroup, user, password); + srv = smbc_server(frame, context, True, + server, share, &workgroup, &user, &password); if (!srv) { TALLOC_FREE(frame); @@ -4596,7 +4689,15 @@ dos_attr_parse(SMBCCTX *context, frame = talloc_stackframe(); while (next_token_talloc(frame, &p, &tok, "\t,\r\n")) { if (StrnCaseCmp(tok, "MODE:", 5) == 0) { - dad->mode = strtol(tok+5, NULL, 16); + long request = strtol(tok+5, NULL, 16); + if (request == 0) { + dad->mode = (request | + (IS_DOS_DIR(dad->mode) + ? FILE_ATTRIBUTE_DIRECTORY + : FILE_ATTRIBUTE_NORMAL)); + } else { + dad->mode = request; + } continue; } @@ -5624,16 +5725,15 @@ smbc_setxattr_ctx(SMBCCTX *context, { int ret; int ret2; - SMBCSRV *srv; - SMBCSRV *ipc_srv; - char *server; - char *share; - char *user; - char *password; - char *workgroup; - char *path; - POLICY_HND pol; - DOS_ATTR_DESC *dad; + SMBCSRV *srv = NULL; + SMBCSRV *ipc_srv = NULL; + char *server = NULL; + char *share = NULL; + char *user = NULL; + char *password = NULL; + char *workgroup = NULL; + char *path = NULL; + DOS_ATTR_DESC *dad = NULL; struct { const char * create_time_attr; const char * access_time_attr; @@ -5682,17 +5782,16 @@ smbc_setxattr_ctx(SMBCCTX *context, } } - srv = smbc_server(context, True, - server, share, workgroup, user, password); + srv = smbc_server(frame, context, True, + server, share, &workgroup, &user, &password); if (!srv) { TALLOC_FREE(frame); return -1; /* errno set by smbc_server */ } if (! srv->no_nt_session) { - ipc_srv = smbc_attr_server(context, server, share, - workgroup, user, password, - &pol); + ipc_srv = smbc_attr_server(frame, context, server, share, + &workgroup, &user, &password); if (! ipc_srv) { srv->no_nt_session = True; } @@ -5718,7 +5817,7 @@ smbc_setxattr_ctx(SMBCCTX *context, if (ipc_srv) { ret = cacl_set(talloc_tos(), srv->cli, - ipc_srv->cli, &pol, path, + ipc_srv->cli, &ipc_srv->pol, path, namevalue, (*namevalue == '*' ? SMBC_XATTR_MODE_SET @@ -5782,7 +5881,7 @@ smbc_setxattr_ctx(SMBCCTX *context, ret = -1; } else { ret = cacl_set(talloc_tos(), srv->cli, - ipc_srv->cli, &pol, path, + ipc_srv->cli, &ipc_srv->pol, path, namevalue, (*namevalue == '*' ? SMBC_XATTR_MODE_SET @@ -5812,7 +5911,7 @@ smbc_setxattr_ctx(SMBCCTX *context, ret = -1; } else { ret = cacl_set(talloc_tos(), srv->cli, - ipc_srv->cli, &pol, path, + ipc_srv->cli, &ipc_srv->pol, path, namevalue, SMBC_XATTR_MODE_CHOWN, 0); } TALLOC_FREE(frame); @@ -5839,8 +5938,8 @@ smbc_setxattr_ctx(SMBCCTX *context, ret = -1; } else { ret = cacl_set(talloc_tos(), srv->cli, - ipc_srv->cli, &pol, path, - namevalue, SMBC_XATTR_MODE_CHOWN, 0); + ipc_srv->cli, &ipc_srv->pol, path, + namevalue, SMBC_XATTR_MODE_CHGRP, 0); } TALLOC_FREE(frame); return ret; @@ -5922,15 +6021,14 @@ smbc_getxattr_ctx(SMBCCTX *context, size_t size) { int ret; - SMBCSRV *srv; - SMBCSRV *ipc_srv; - char *server; - char *share; - char *user; - char *password; - char *workgroup; - char *path; - POLICY_HND pol; + SMBCSRV *srv = NULL; + SMBCSRV *ipc_srv = NULL; + char *server = NULL; + char *share = NULL; + char *user = NULL; + char *password = NULL; + char *workgroup = NULL; + char *path = NULL; struct { const char * create_time_attr; const char * access_time_attr; @@ -5978,17 +6076,16 @@ smbc_getxattr_ctx(SMBCCTX *context, } } - srv = smbc_server(context, True, - server, share, workgroup, user, password); + srv = smbc_server(frame, context, True, + server, share, &workgroup, &user, &password); if (!srv) { TALLOC_FREE(frame); return -1; /* errno set by smbc_server */ } if (! srv->no_nt_session) { - ipc_srv = smbc_attr_server(context, server, share, - workgroup, user, password, - &pol); + ipc_srv = smbc_attr_server(frame, context, server, share, + &workgroup, &user, &password); if (! ipc_srv) { srv->no_nt_session = True; } @@ -6041,7 +6138,7 @@ smbc_getxattr_ctx(SMBCCTX *context, /* Yup. */ ret = cacl_get(context, talloc_tos(), srv, ipc_srv == NULL ? NULL : ipc_srv->cli, - &pol, path, + &ipc_srv->pol, path, CONST_DISCARD(char *, name), CONST_DISCARD(char *, value), size); if (ret < 0 && errno == 0) { @@ -6064,15 +6161,14 @@ smbc_removexattr_ctx(SMBCCTX *context, const char *name) { int ret; - SMBCSRV *srv; - SMBCSRV *ipc_srv; - char *server; - char *share; - char *user; - char *password; - char *workgroup; - char *path; - POLICY_HND pol; + SMBCSRV *srv = NULL; + SMBCSRV *ipc_srv = NULL; + char *server = NULL; + char *share = NULL; + char *user = NULL; + char *password = NULL; + char *workgroup = NULL; + char *path = NULL; TALLOC_CTX *frame = talloc_stackframe(); if (!context || !context->internal || @@ -6114,17 +6210,16 @@ smbc_removexattr_ctx(SMBCCTX *context, } } - srv = smbc_server(context, True, - server, share, workgroup, user, password); + srv = smbc_server(frame, context, True, + server, share, &workgroup, &user, &password); if (!srv) { TALLOC_FREE(frame); return -1; /* errno set by smbc_server */ } if (! srv->no_nt_session) { - ipc_srv = smbc_attr_server(context, server, share, - workgroup, user, password, - &pol); + ipc_srv = smbc_attr_server(frame, context, server, share, + &workgroup, &user, &password); if (! ipc_srv) { srv->no_nt_session = True; } @@ -6143,7 +6238,7 @@ smbc_removexattr_ctx(SMBCCTX *context, /* Yup. */ ret = cacl_set(talloc_tos(), srv->cli, - ipc_srv->cli, &pol, path, + ipc_srv->cli, &ipc_srv->pol, path, NULL, SMBC_XATTR_MODE_REMOVE_ALL, 0); TALLOC_FREE(frame); return ret; @@ -6163,7 +6258,7 @@ smbc_removexattr_ctx(SMBCCTX *context, /* Yup. */ ret = cacl_set(talloc_tos(), srv->cli, - ipc_srv->cli, &pol, path, + ipc_srv->cli, &ipc_srv->pol, path, name + 19, SMBC_XATTR_MODE_REMOVE, 0); TALLOC_FREE(frame); return ret; @@ -6186,6 +6281,7 @@ smbc_listxattr_ctx(SMBCCTX *context, * the complete set of attribute names, always, rather than only those * attribute names which actually exist for a file. Hmmm... */ + size_t retsize; const char supported_old[] = "system.*\0" "system.*+\0" @@ -6229,22 +6325,24 @@ smbc_listxattr_ctx(SMBCCTX *context, if (context->internal->_full_time_names) { supported = supported_new; + retsize = sizeof(supported_new); } else { supported = supported_old; + retsize = sizeof(supported_old); } if (size == 0) { - return sizeof(supported); + return retsize; } - if (sizeof(supported) > size) { + if (retsize > size) { errno = ERANGE; return -1; } /* this can't be strcpy() because there are embedded null characters */ - memcpy(list, supported, sizeof(supported)); - return sizeof(supported); + memcpy(list, supported, retsize); + return retsize; } @@ -6256,11 +6354,11 @@ static SMBCFILE * smbc_open_print_job_ctx(SMBCCTX *context, const char *fname) { - char *server; - char *share; - char *user; - char *password; - char *path; + char *server = NULL; + char *share = NULL; + char *user = NULL; + char *password = NULL; + char *path = NULL; TALLOC_CTX *frame = talloc_stackframe(); if (!context || !context->internal || @@ -6399,13 +6497,13 @@ smbc_list_print_jobs_ctx(SMBCCTX *context, const char *fname, smbc_list_print_job_fn fn) { - SMBCSRV *srv; - char *server; - char *share; - char *user; - char *password; - char *workgroup; - char *path; + SMBCSRV *srv = NULL; + char *server = NULL; + char *share = NULL; + char *user = NULL; + char *password = NULL; + char *workgroup = NULL; + char *path = NULL; TALLOC_CTX *frame = talloc_stackframe(); if (!context || !context->internal || @@ -6447,8 +6545,8 @@ smbc_list_print_jobs_ctx(SMBCCTX *context, } } - srv = smbc_server(context, True, - server, share, workgroup, user, password); + srv = smbc_server(frame, context, True, + server, share, &workgroup, &user, &password); if (!srv) { TALLOC_FREE(frame); @@ -6476,13 +6574,13 @@ smbc_unlink_print_job_ctx(SMBCCTX *context, const char *fname, int id) { - SMBCSRV *srv; - char *server; - char *share; - char *user; - char *password; - char *workgroup; - char *path; + SMBCSRV *srv = NULL; + char *server = NULL; + char *share = NULL; + char *user = NULL; + char *password = NULL; + char *workgroup = NULL; + char *path = NULL; int err; TALLOC_CTX *frame = talloc_stackframe(); @@ -6525,8 +6623,8 @@ smbc_unlink_print_job_ctx(SMBCCTX *context, } } - srv = smbc_server(context, True, - server, share, workgroup, user, password); + srv = smbc_server(frame, context, True, + server, share, &workgroup, &user, &password); if (!srv) { @@ -6724,6 +6822,7 @@ smbc_option_set(SMBCCTX *context, bool b; smbc_get_auth_data_with_context_fn auth_fn; void *v; + const char *s; } option_value; va_start(ap, option_name); @@ -6772,6 +6871,19 @@ smbc_option_set(SMBCCTX *context, */ option_value.v = va_arg(ap, void *); context->internal->_user_data = option_value.v; + } else if (strcmp(option_name, "smb_encrypt_level") == 0) { + /* + * Save an encoded value for encryption level. + * 0 = off, 1 = attempt, 2 = required. + */ + option_value.s = va_arg(ap, const char *); + if (strcmp(option_value.s, "none") == 0) { + context->internal->_smb_encryption_level = 0; + } else if (strcmp(option_value.s, "request") == 0) { + context->internal->_smb_encryption_level = 1; + } else if (strcmp(option_value.s, "require") == 0) { + context->internal->_smb_encryption_level = 2; + } } va_end(ap); @@ -6821,6 +6933,35 @@ smbc_option_get(SMBCCTX *context, * with smbc_option_get() */ return context->internal->_user_data; + } else if (strcmp(option_name, "smb_encrypt_level") == 0) { + /* + * Return the current smb encrypt negotiate option as a string. + */ + switch (context->internal->_smb_encryption_level) { + case 0: + return (void *) "none"; + case 1: + return (void *) "request"; + case 2: + return (void *) "require"; + } + } else if (strcmp(option_name, "smb_encrypt_on") == 0) { + /* + * Return the current smb encrypt status option as a bool. + * false = off, true = on. We don't know what server is + * being requested, so we only return true if all servers + * are using an encrypted connection. + */ + SMBCSRV *s; + unsigned int num_servers = 0; + + for (s = context->internal->_servers; s; s = s->next) { + num_servers++; + if (s->cli->trans_enc_state == NULL) { + return (void *)false; + } + } + return (void *) (bool) (num_servers > 0); } return NULL; diff --git a/source3/libsmb/namequery.c b/source3/libsmb/namequery.c index 853fe979b7..ad16452e3e 100644 --- a/source3/libsmb/namequery.c +++ b/source3/libsmb/namequery.c @@ -1299,11 +1299,11 @@ static NTSTATUS resolve_hosts(const char *name, int name_type, Resolve via "ADS" method. *********************************************************/ -NTSTATUS resolve_ads(const char *name, - int name_type, - const char *sitename, - struct ip_service **return_iplist, - int *return_count) +static NTSTATUS resolve_ads(const char *name, + int name_type, + const char *sitename, + struct ip_service **return_iplist, + int *return_count) { int i, j; NTSTATUS status; @@ -1422,14 +1422,13 @@ NTSTATUS resolve_ads(const char *name, resolve_hosts() when looking up DC's via SRV RR entries in DNS **********************************************************************/ -NTSTATUS internal_resolve_name(const char *name, +static NTSTATUS internal_resolve_name(const char *name, int name_type, const char *sitename, struct ip_service **return_iplist, int *return_count, const char *resolve_order) { - const char *name_resolve_list; char *tok; const char *ptr; NTSTATUS status = NT_STATUS_UNSUCCESSFUL; @@ -1483,16 +1482,10 @@ NTSTATUS internal_resolve_name(const char *name, return NT_STATUS_INVALID_PARAMETER; } - if (!resolve_order) { - name_resolve_list = lp_name_resolve_order(); - } else { - name_resolve_list = resolve_order; - } - - if (!name_resolve_list[0]) { + if (!resolve_order[0]) { ptr = "host"; } else { - ptr = name_resolve_list; + ptr = resolve_order; } /* iterate through the name resolution backends */ diff --git a/source3/libsmb/nmblib.c b/source3/libsmb/nmblib.c index 2ff925ef36..15a9a93ff2 100644 --- a/source3/libsmb/nmblib.c +++ b/source3/libsmb/nmblib.c @@ -740,6 +740,8 @@ struct packet_struct *parse_packet(char *buf,int length, if (!p) return(NULL); + ZERO_STRUCTP(p); /* initialize for possible padding */ + p->next = NULL; p->prev = NULL; p->ip = ip; diff --git a/source3/libsmb/ntlm_check.c b/source3/libsmb/ntlm_check.c index f8ed044f8a..ae10d7373d 100644 --- a/source3/libsmb/ntlm_check.c +++ b/source3/libsmb/ntlm_check.c @@ -182,7 +182,10 @@ NTSTATUS ntlm_password_check(TALLOC_CTX *mem_ctx, DATA_BLOB *user_sess_key, DATA_BLOB *lm_sess_key) { - static const unsigned char zeros[8] = { 0, }; + unsigned char zeros[8]; + + ZERO_STRUCT(zeros); + if (nt_pw == NULL) { DEBUG(3,("ntlm_password_check: NO NT password stored for user %s.\n", username)); diff --git a/source3/libsmb/ntlmssp.c b/source3/libsmb/ntlmssp.c index ed08e8102b..35c20ed647 100644 --- a/source3/libsmb/ntlmssp.c +++ b/source3/libsmb/ntlmssp.c @@ -823,7 +823,8 @@ static NTSTATUS ntlmssp_server_auth(struct ntlmssp_state *ntlmssp_state, session_key.data); DEBUG(10,("ntlmssp_server_auth: Created NTLM session key.\n")); } else { - static const uint8 zeros[24] = { 0, }; + uint8 zeros[24]; + ZERO_STRUCT(zeros); session_key = data_blob_talloc( ntlmssp_state->mem_ctx, NULL, 16); if (session_key.data == NULL) { @@ -1066,9 +1067,11 @@ static NTSTATUS ntlmssp_client_challenge(struct ntlmssp_state *ntlmssp_state, } if (!ntlmssp_state->nt_hash || !ntlmssp_state->lm_hash) { - static const uchar zeros[16] = { 0, }; + uchar zeros[16]; /* do nothing - blobs are zero length */ + ZERO_STRUCT(zeros); + /* session key is all zeros */ session_key = data_blob_talloc(ntlmssp_state->mem_ctx, zeros, 16); diff --git a/source3/libsmb/ntlmssp_parse.c b/source3/libsmb/ntlmssp_parse.c index ac8846ad1e..70377cba7d 100644 --- a/source3/libsmb/ntlmssp_parse.c +++ b/source3/libsmb/ntlmssp_parse.c @@ -170,6 +170,7 @@ bool msrpc_gen(DATA_BLOB *blob, /* a helpful macro to avoid running over the end of our blob */ #define NEED_DATA(amount) \ if ((head_ofs + amount) > blob->length) { \ + va_end(ap); \ return False; \ } @@ -216,16 +217,20 @@ bool msrpc_parse(const DATA_BLOB *blob, if ((len1 != len2) || (ptr + len1 < ptr) || (ptr + len1 < len1) || (ptr + len1 > blob->length)) { + va_end(ap); return false; } if (len1 & 1) { /* if odd length and unicode */ + va_end(ap); return false; } if (blob->data + ptr < (uint8 *)(unsigned long)ptr || - blob->data + ptr < blob->data) + blob->data + ptr < blob->data) { + va_end(ap); return false; + } if (0 < len1) { char *p = NULL; @@ -261,13 +266,16 @@ bool msrpc_parse(const DATA_BLOB *blob, if ((len1 != len2) || (ptr + len1 < ptr) || (ptr + len1 < len1) || (ptr + len1 > blob->length)) { + va_end(ap); return false; } if (blob->data + ptr < (uint8 *)(unsigned long)ptr || - blob->data + ptr < blob->data) + blob->data + ptr < blob->data) { + va_end(ap); return false; + } if (0 < len1) { char *p = NULL; @@ -304,13 +312,16 @@ bool msrpc_parse(const DATA_BLOB *blob, if ((len1 != len2) || (ptr + len1 < ptr) || (ptr + len1 < len1) || (ptr + len1 > blob->length)) { + va_end(ap); return false; } if (blob->data + ptr < (uint8 *)(unsigned long)ptr || - blob->data + ptr < blob->data) + blob->data + ptr < blob->data) { + va_end(ap); return false; + } *b = data_blob(blob->data + ptr, len1); } @@ -322,6 +333,7 @@ bool msrpc_parse(const DATA_BLOB *blob, NEED_DATA(len1); if (blob->data + head_ofs < (uint8 *)head_ofs || blob->data + head_ofs < blob->data) { + va_end(ap); return false; } @@ -337,7 +349,8 @@ bool msrpc_parse(const DATA_BLOB *blob, s = va_arg(ap, char *); if (blob->data + head_ofs < (uint8 *)head_ofs || - blob->data + head_ofs < blob->data) { + blob->data + head_ofs < blob->data) { + va_end(ap); return false; } @@ -351,11 +364,13 @@ bool msrpc_parse(const DATA_BLOB *blob, blob->length - head_ofs, STR_ASCII|STR_TERMINATE); if (ret == (size_t)-1 || p == NULL) { + va_end(ap); return false; } head_ofs += ret; if (strcmp(s, p) != 0) { TALLOC_FREE(p); + va_end(ap); return false; } TALLOC_FREE(p); diff --git a/source3/libsmb/smb_seal.c b/source3/libsmb/smb_seal.c new file mode 100644 index 0000000000..b5befbf7cd --- /dev/null +++ b/source3/libsmb/smb_seal.c @@ -0,0 +1,497 @@ +/* + Unix SMB/CIFS implementation. + SMB Transport encryption (sealing) code. + Copyright (C) Jeremy Allison 2007. + + 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 + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "includes.h" + +/****************************************************************************** + Pull out the encryption context for this packet. 0 means global context. +******************************************************************************/ + +NTSTATUS get_enc_ctx_num(const uint8_t *buf, uint16 *p_enc_ctx_num) +{ + if (smb_len(buf) < 8) { + return NT_STATUS_INVALID_BUFFER_SIZE; + } + + if (buf[4] == 0xFF) { + if (buf[5] == 'S' && buf [6] == 'M' && buf[7] == 'B') { + /* Not an encrypted buffer. */ + return NT_STATUS_NOT_FOUND; + } + if (buf[5] == 'E') { + *p_enc_ctx_num = SVAL(buf,6); + return NT_STATUS_OK; + } + } + return NT_STATUS_INVALID_NETWORK_RESPONSE; +} + +/****************************************************************************** + Generic code for client and server. + Is encryption turned on ? +******************************************************************************/ + +bool common_encryption_on(struct smb_trans_enc_state *es) +{ + return ((es != NULL) && es->enc_on); +} + +/****************************************************************************** + Generic code for client and server. + NTLM decrypt an incoming buffer. + Abartlett tells me that SSPI puts the signature first before the encrypted + output, so cope with the same for compatibility. +******************************************************************************/ + +NTSTATUS common_ntlm_decrypt_buffer(NTLMSSP_STATE *ntlmssp_state, char *buf) +{ + NTSTATUS status; + size_t buf_len = smb_len(buf) + 4; /* Don't forget the 4 length bytes. */ + size_t data_len; + char *inbuf; + DATA_BLOB sig; + + if (buf_len < 8 + NTLMSSP_SIG_SIZE) { + return NT_STATUS_BUFFER_TOO_SMALL; + } + + inbuf = (char *)smb_xmemdup(buf, buf_len); + + /* Adjust for the signature. */ + data_len = buf_len - 8 - NTLMSSP_SIG_SIZE; + + /* Point at the signature. */ + sig = data_blob_const(inbuf+8, NTLMSSP_SIG_SIZE); + + status = ntlmssp_unseal_packet(ntlmssp_state, + (unsigned char *)inbuf + 8 + NTLMSSP_SIG_SIZE, /* 4 byte len + 0xFF 'E' <enc> <ctx> */ + data_len, + (unsigned char *)inbuf + 8 + NTLMSSP_SIG_SIZE, + data_len, + &sig); + + if (!NT_STATUS_IS_OK(status)) { + SAFE_FREE(inbuf); + return status; + } + + memcpy(buf + 8, inbuf + 8 + NTLMSSP_SIG_SIZE, data_len); + + /* Reset the length and overwrite the header. */ + smb_setlen(buf,data_len + 4); + + SAFE_FREE(inbuf); + return NT_STATUS_OK; +} + +/****************************************************************************** + Generic code for client and server. + NTLM encrypt an outgoing buffer. Return the encrypted pointer in ppbuf_out. + Abartlett tells me that SSPI puts the signature first before the encrypted + output, so do the same for compatibility. +******************************************************************************/ + +NTSTATUS common_ntlm_encrypt_buffer(NTLMSSP_STATE *ntlmssp_state, + uint16 enc_ctx_num, + char *buf, + char **ppbuf_out) +{ + NTSTATUS status; + char *buf_out; + size_t data_len = smb_len(buf) - 4; /* Ignore the 0xFF SMB bytes. */ + DATA_BLOB sig; + + *ppbuf_out = NULL; + + if (data_len == 0) { + return NT_STATUS_BUFFER_TOO_SMALL; + } + + /* + * We know smb_len can't return a value > 128k, so no int overflow + * check needed. + */ + + buf_out = SMB_XMALLOC_ARRAY(char, 8 + NTLMSSP_SIG_SIZE + data_len); + + /* Copy the data from the original buffer. */ + + memcpy(buf_out + 8 + NTLMSSP_SIG_SIZE, buf + 8, data_len); + + smb_set_enclen(buf_out, smb_len(buf) + NTLMSSP_SIG_SIZE, enc_ctx_num); + + sig = data_blob(NULL, NTLMSSP_SIG_SIZE); + + status = ntlmssp_seal_packet(ntlmssp_state, + (unsigned char *)buf_out + 8 + NTLMSSP_SIG_SIZE, /* 4 byte len + 0xFF 'S' <enc> <ctx> */ + data_len, + (unsigned char *)buf_out + 8 + NTLMSSP_SIG_SIZE, + data_len, + &sig); + + if (!NT_STATUS_IS_OK(status)) { + data_blob_free(&sig); + SAFE_FREE(buf_out); + return status; + } + + /* First 16 data bytes are signature for SSPI compatibility. */ + memcpy(buf_out + 8, sig.data, NTLMSSP_SIG_SIZE); + *ppbuf_out = buf_out; + return NT_STATUS_OK; +} + +/****************************************************************************** + Generic code for client and server. + gss-api decrypt an incoming buffer. We insist that the size of the + unwrapped buffer must be smaller or identical to the incoming buffer. +******************************************************************************/ + +#if defined(HAVE_GSSAPI) && defined(HAVE_KRB5) +static NTSTATUS common_gss_decrypt_buffer(struct smb_tran_enc_state_gss *gss_state, char *buf) +{ + gss_ctx_id_t gss_ctx = gss_state->gss_ctx; + OM_uint32 ret = 0; + OM_uint32 minor = 0; + int flags_got = 0; + gss_buffer_desc in_buf, out_buf; + size_t buf_len = smb_len(buf) + 4; /* Don't forget the 4 length bytes. */ + + if (buf_len < 8) { + return NT_STATUS_BUFFER_TOO_SMALL; + } + + in_buf.value = buf + 8; + in_buf.length = buf_len - 8; + + ret = gss_unwrap(&minor, + gss_ctx, + &in_buf, + &out_buf, + &flags_got, /* did we get sign+seal ? */ + (gss_qop_t *) NULL); + + if (ret != GSS_S_COMPLETE) { + ADS_STATUS adss = ADS_ERROR_GSS(ret, minor); + DEBUG(0,("common_gss_encrypt_buffer: gss_unwrap failed. Error %s\n", + ads_errstr(adss) )); + return map_nt_error_from_gss(ret, minor); + } + + if (out_buf.length > in_buf.length) { + DEBUG(0,("common_gss_encrypt_buffer: gss_unwrap size (%u) too large (%u) !\n", + (unsigned int)out_buf.length, + (unsigned int)in_buf.length )); + gss_release_buffer(&minor, &out_buf); + return NT_STATUS_INVALID_PARAMETER; + } + + memcpy(buf + 8, out_buf.value, out_buf.length); + /* Reset the length and overwrite the header. */ + smb_setlen(buf, out_buf.length + 4); + + gss_release_buffer(&minor, &out_buf); + return NT_STATUS_OK; +} + +/****************************************************************************** + Generic code for client and server. + gss-api encrypt an outgoing buffer. Return the alloced encrypted pointer in buf_out. +******************************************************************************/ + +static NTSTATUS common_gss_encrypt_buffer(struct smb_tran_enc_state_gss *gss_state, + uint16 enc_ctx_num, + char *buf, + char **ppbuf_out) +{ + gss_ctx_id_t gss_ctx = gss_state->gss_ctx; + OM_uint32 ret = 0; + OM_uint32 minor = 0; + int flags_got = 0; + gss_buffer_desc in_buf, out_buf; + size_t buf_len = smb_len(buf) + 4; /* Don't forget the 4 length bytes. */ + + *ppbuf_out = NULL; + + if (buf_len < 8) { + return NT_STATUS_BUFFER_TOO_SMALL; + } + + in_buf.value = buf + 8; + in_buf.length = buf_len - 8; + + ret = gss_wrap(&minor, + gss_ctx, + true, /* we want sign+seal. */ + GSS_C_QOP_DEFAULT, + &in_buf, + &flags_got, /* did we get sign+seal ? */ + &out_buf); + + if (ret != GSS_S_COMPLETE) { + ADS_STATUS adss = ADS_ERROR_GSS(ret, minor); + DEBUG(0,("common_gss_encrypt_buffer: gss_wrap failed. Error %s\n", + ads_errstr(adss) )); + return map_nt_error_from_gss(ret, minor); + } + + if (!flags_got) { + /* Sign+seal not supported. */ + gss_release_buffer(&minor, &out_buf); + return NT_STATUS_NOT_SUPPORTED; + } + + /* Ya see - this is why I *hate* gss-api. I don't + * want to have to malloc another buffer of the + * same size + 8 bytes just to get a continuous + * header + buffer, but gss won't let me pass in + * a pre-allocated buffer. Bastards (and you know + * who you are....). I might fix this by + * going to "encrypt_and_send" passing in a file + * descriptor and doing scatter-gather write with + * TCP cork on Linux. But I shouldn't have to + * bother :-*(. JRA. + */ + + *ppbuf_out = (char *)SMB_MALLOC(out_buf.length + 8); /* We know this can't wrap. */ + if (!*ppbuf_out) { + gss_release_buffer(&minor, &out_buf); + return NT_STATUS_NO_MEMORY; + } + + memcpy(*ppbuf_out+8, out_buf.value, out_buf.length); + smb_set_enclen(*ppbuf_out, out_buf.length + 4, enc_ctx_num); + + gss_release_buffer(&minor, &out_buf); + return NT_STATUS_OK; +} +#endif + +/****************************************************************************** + Generic code for client and server. + Encrypt an outgoing buffer. Return the alloced encrypted pointer in buf_out. +******************************************************************************/ + +NTSTATUS common_encrypt_buffer(struct smb_trans_enc_state *es, char *buffer, char **buf_out) +{ + if (!common_encryption_on(es)) { + /* Not encrypting. */ + *buf_out = buffer; + return NT_STATUS_OK; + } + + switch (es->smb_enc_type) { + case SMB_TRANS_ENC_NTLM: + return common_ntlm_encrypt_buffer(es->s.ntlmssp_state, es->enc_ctx_num, buffer, buf_out); +#if defined(HAVE_GSSAPI) && defined(HAVE_KRB5) + case SMB_TRANS_ENC_GSS: + return common_gss_encrypt_buffer(es->s.gss_state, es->enc_ctx_num, buffer, buf_out); +#endif + default: + return NT_STATUS_NOT_SUPPORTED; + } +} + +/****************************************************************************** + Generic code for client and server. + Decrypt an incoming SMB buffer. Replaces the data within it. + New data must be less than or equal to the current length. +******************************************************************************/ + +NTSTATUS common_decrypt_buffer(struct smb_trans_enc_state *es, char *buf) +{ + if (!common_encryption_on(es)) { + /* Not decrypting. */ + return NT_STATUS_OK; + } + + switch (es->smb_enc_type) { + case SMB_TRANS_ENC_NTLM: + return common_ntlm_decrypt_buffer(es->s.ntlmssp_state, buf); +#if defined(HAVE_GSSAPI) && defined(HAVE_KRB5) + case SMB_TRANS_ENC_GSS: + return common_gss_decrypt_buffer(es->s.gss_state, buf); +#endif + default: + return NT_STATUS_NOT_SUPPORTED; + } +} + +#if defined(HAVE_GSSAPI) && defined(HAVE_KRB5) +/****************************************************************************** + Shutdown a gss encryption state. +******************************************************************************/ + +static void common_free_gss_state(struct smb_tran_enc_state_gss **pp_gss_state) +{ + OM_uint32 minor = 0; + struct smb_tran_enc_state_gss *gss_state = *pp_gss_state; + + if (gss_state->creds != GSS_C_NO_CREDENTIAL) { + gss_release_cred(&minor, &gss_state->creds); + } + if (gss_state->gss_ctx != GSS_C_NO_CONTEXT) { + gss_delete_sec_context(&minor, &gss_state->gss_ctx, NULL); + } + SAFE_FREE(*pp_gss_state); +} +#endif + +/****************************************************************************** + Shutdown an encryption state. +******************************************************************************/ + +void common_free_encryption_state(struct smb_trans_enc_state **pp_es) +{ + struct smb_trans_enc_state *es = *pp_es; + + if (es == NULL) { + return; + } + + if (es->smb_enc_type == SMB_TRANS_ENC_NTLM) { + if (es->s.ntlmssp_state) { + ntlmssp_end(&es->s.ntlmssp_state); + } + } +#if defined(HAVE_GSSAPI) && defined(HAVE_KRB5) + if (es->smb_enc_type == SMB_TRANS_ENC_GSS) { + /* Free the gss context handle. */ + if (es->s.gss_state) { + common_free_gss_state(&es->s.gss_state); + } + } +#endif + SAFE_FREE(es); + *pp_es = NULL; +} + +/****************************************************************************** + Free an encryption-allocated buffer. +******************************************************************************/ + +void common_free_enc_buffer(struct smb_trans_enc_state *es, char *buf) +{ + if (!common_encryption_on(es)) { + return; + } + + if (es->smb_enc_type == SMB_TRANS_ENC_NTLM) { + SAFE_FREE(buf); + return; + } + +#if defined(HAVE_GSSAPI) && defined(HAVE_KRB5) + if (es->smb_enc_type == SMB_TRANS_ENC_GSS) { + OM_uint32 min; + gss_buffer_desc rel_buf; + rel_buf.value = buf; + rel_buf.length = smb_len(buf) + 4; + gss_release_buffer(&min, &rel_buf); + } +#endif +} + +/****************************************************************************** + Client side encryption. +******************************************************************************/ + +/****************************************************************************** + Is client encryption on ? +******************************************************************************/ + +bool cli_encryption_on(struct cli_state *cli) +{ + /* If we supported multiple encrytion contexts + * here we'd look up based on tid. + */ + return common_encryption_on(cli->trans_enc_state); +} + +/****************************************************************************** + Shutdown a client encryption state. +******************************************************************************/ + +void cli_free_encryption_context(struct cli_state *cli) +{ + common_free_encryption_state(&cli->trans_enc_state); +} + +/****************************************************************************** + Free an encryption-allocated buffer. +******************************************************************************/ + +void cli_free_enc_buffer(struct cli_state *cli, char *buf) +{ + /* We know this is an smb buffer, and we + * didn't malloc, only copy, for a keepalive, + * so ignore non-session messages. */ + + if(CVAL(buf,0)) { + return; + } + + /* If we supported multiple encrytion contexts + * here we'd look up based on tid. + */ + common_free_enc_buffer(cli->trans_enc_state, buf); +} + +/****************************************************************************** + Decrypt an incoming buffer. +******************************************************************************/ + +NTSTATUS cli_decrypt_message(struct cli_state *cli) +{ + NTSTATUS status; + uint16 enc_ctx_num; + + /* Ignore non-session messages. */ + if(CVAL(cli->inbuf,0)) { + return NT_STATUS_OK; + } + + status = get_enc_ctx_num((const uint8_t *)cli->inbuf, &enc_ctx_num); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + if (enc_ctx_num != cli->trans_enc_state->enc_ctx_num) { + return NT_STATUS_INVALID_HANDLE; + } + + return common_decrypt_buffer(cli->trans_enc_state, cli->inbuf); +} + +/****************************************************************************** + Encrypt an outgoing buffer. Return the encrypted pointer in buf_out. +******************************************************************************/ + +NTSTATUS cli_encrypt_message(struct cli_state *cli, char **buf_out) +{ + /* Ignore non-session messages. */ + if(CVAL(cli->outbuf,0)) { + return NT_STATUS_OK; + } + + /* If we supported multiple encrytion contexts + * here we'd look up based on tid. + */ + return common_encrypt_buffer(cli->trans_enc_state, cli->outbuf, buf_out); +} diff --git a/source3/libsmb/smb_signing.c b/source3/libsmb/smb_signing.c index d5cbe3b125..f03c21bd0e 100644 --- a/source3/libsmb/smb_signing.c +++ b/source3/libsmb/smb_signing.c @@ -745,8 +745,8 @@ bool srv_oplock_set_signing(bool onoff) bool srv_check_sign_mac(const char *inbuf, bool must_be_ok) { - /* Check if it's a session keepalive. */ - if(CVAL(inbuf,0) == SMBkeepalive) { + /* Check if it's a non-session message. */ + if(CVAL(inbuf,0)) { return True; } @@ -759,8 +759,8 @@ bool srv_check_sign_mac(const char *inbuf, bool must_be_ok) void srv_calculate_sign_mac(char *outbuf) { - /* Check if it's a session keepalive. */ - if(CVAL(outbuf,0) == SMBkeepalive) { + /* Check if it's a non-session message. */ + if(CVAL(outbuf,0)) { return; } diff --git a/source3/libsmb/smbencrypt.c b/source3/libsmb/smbencrypt.c index 9e37d1d6cf..c547a4a003 100644 --- a/source3/libsmb/smbencrypt.c +++ b/source3/libsmb/smbencrypt.c @@ -443,7 +443,7 @@ bool SMBNTLMv2encrypt_hash(const char *user, const char *domain, const uchar nt_ the username and domain. This prevents username swapping during the auth exchange */ - if (!ntv2_owf_gen(nt_hash, user, domain, True, ntlm_v2_hash)) { + if (!ntv2_owf_gen(nt_hash, user, domain, False, ntlm_v2_hash)) { return False; } @@ -704,16 +704,22 @@ char *decrypt_trustdom_secret(const char *pass, DATA_BLOB *data_in) void encode_wkssvc_join_password_buffer(TALLOC_CTX *mem_ctx, const char *pwd, DATA_BLOB *session_key, - struct wkssvc_PasswordBuffer *pwd_buf) + struct wkssvc_PasswordBuffer **pwd_buf) { uint8_t buffer[516]; struct MD5Context ctx; - - DATA_BLOB confounded_session_key = data_blob_talloc(mem_ctx, NULL, 16); - + struct wkssvc_PasswordBuffer *my_pwd_buf = NULL; + DATA_BLOB confounded_session_key; int confounder_len = 8; uint8_t confounder[8]; + my_pwd_buf = talloc_zero(mem_ctx, struct wkssvc_PasswordBuffer); + if (!my_pwd_buf) { + return; + } + + confounded_session_key = data_blob_talloc(mem_ctx, NULL, 16); + encode_pw_buffer(buffer, pwd, STR_UNICODE); generate_random_buffer((uint8_t *)confounder, confounder_len); @@ -725,10 +731,12 @@ void encode_wkssvc_join_password_buffer(TALLOC_CTX *mem_ctx, SamOEMhashBlob(buffer, 516, &confounded_session_key); - memcpy(&pwd_buf->data[0], confounder, confounder_len); - memcpy(&pwd_buf->data[8], buffer, 516); + memcpy(&my_pwd_buf->data[0], confounder, confounder_len); + memcpy(&my_pwd_buf->data[8], buffer, 516); data_blob_free(&confounded_session_key); + + *pwd_buf = my_pwd_buf; } WERROR decode_wkssvc_join_password_buffer(TALLOC_CTX *mem_ctx, diff --git a/source3/libsmb/trusts_util.c b/source3/libsmb/trusts_util.c index 732dc78c75..1ca7d56a83 100644 --- a/source3/libsmb/trusts_util.c +++ b/source3/libsmb/trusts_util.c @@ -40,7 +40,7 @@ static NTSTATUS just_change_the_password(struct rpc_pipe_client *cli, TALLOC_CTX 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; + uint32 neg_flags = NETLOGON_NEG_SELECT_AUTH2_FLAGS; result = rpccli_netlogon_setup_creds(cli, cli->cli->desthost, /* server name */ diff --git a/source3/libsmb/unexpected.c b/source3/libsmb/unexpected.c index 92a609c42b..5fbc33cdf5 100644 --- a/source3/libsmb/unexpected.c +++ b/source3/libsmb/unexpected.c @@ -63,6 +63,8 @@ void unexpected_packet(struct packet_struct *p) len = build_packet(&buf[6], sizeof(buf)-6, p) + 6; + ZERO_STRUCT(key); /* needed for potential alignment */ + key.packet_type = p->packet_type; key.timestamp = p->timestamp; key.count = count++; @@ -86,6 +88,10 @@ static int traverse_fn(TDB_CONTEXT *ttdb, TDB_DATA kbuf, TDB_DATA dbuf, void *st { struct unexpected_key key; + if (kbuf.dsize != sizeof(key)) { + tdb_delete(ttdb, kbuf); + } + memcpy(&key, kbuf.dptr, sizeof(key)); if (lastt - key.timestamp > NMBD_UNEXPECTED_TIMEOUT) { @@ -134,6 +140,10 @@ static int traverse_match(TDB_CONTEXT *ttdb, TDB_DATA kbuf, TDB_DATA dbuf, int port; struct packet_struct *p; + if (kbuf.dsize != sizeof(key)) { + return 0; + } + memcpy(&key, kbuf.dptr, sizeof(key)); if (key.packet_type != state->match_type) return 0; |