From 39e0dbcf07251670b5475e9d0533c08a2712fffa Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Thu, 14 Feb 2008 11:29:54 -0800 Subject: Allow the mechOID to be written separately. Jeremy. (This used to be commit e3e08c6e7d270e1be7a9d3042b1f36f5a291f90a) --- source3/libsmb/clispnego.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'source3/libsmb') diff --git a/source3/libsmb/clispnego.c b/source3/libsmb/clispnego.c index f95b11e4cd..a75032a47d 100644 --- a/source3/libsmb/clispnego.c +++ b/source3/libsmb/clispnego.c @@ -498,11 +498,13 @@ DATA_BLOB spnego_gen_auth_response(DATA_BLOB *reply, NTSTATUS nt_status, asn1_write_enumerated(&data, negResult); asn1_pop_tag(&data); - if (reply->data != NULL) { + if (mechOID) { asn1_push_tag(&data,ASN1_CONTEXT(1)); asn1_write_OID(&data, mechOID); asn1_pop_tag(&data); - + } + + if (reply && reply->data != NULL) { asn1_push_tag(&data,ASN1_CONTEXT(2)); asn1_write_OctetString(&data, reply->data, reply->length); asn1_pop_tag(&data); -- cgit From 401c0a6551efe2ac574d4fa0337c15ee2dd61da7 Mon Sep 17 00:00:00 2001 From: Günther Deschner Date: Fri, 15 Feb 2008 13:51:54 +0100 Subject: Add netlogon_creds_client_check and netlogon_creds_client_step. Guenther (This used to be commit 41d33a2507e3fae7837bb8e42b1ac30cc31c31dc) --- source3/libsmb/credentials.c | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) (limited to 'source3/libsmb') diff --git a/source3/libsmb/credentials.c b/source3/libsmb/credentials.c index 1256a6210e..f03bf22df1 100644 --- a/source3/libsmb/credentials.c +++ b/source3/libsmb/credentials.c @@ -329,6 +329,25 @@ bool creds_client_check(const struct dcinfo *dc, const DOM_CHAL *rcv_srv_chal_in return True; } +bool netlogon_creds_client_check(const struct dcinfo *dc, + const struct netr_Credential *rcv_srv_chal_in) +{ + if (memcmp(dc->srv_chal.data, rcv_srv_chal_in->data, + sizeof(dc->srv_chal.data))) { + + DEBUG(0,("netlogon_creds_client_check: credentials check failed.\n")); + DEBUGADD(5,("netlogon_creds_client_check: challenge : %s\n", + credstr(rcv_srv_chal_in->data))); + DEBUGADD(5,("calculated: %s\n", credstr(dc->srv_chal.data))); + return false; + } + + DEBUG(10,("netlogon_creds_client_check: credentials check OK.\n")); + + return true; +} + + /**************************************************************************** Step the client credentials to the next element in the chain, updating the current client and server credentials and the seed @@ -345,3 +364,15 @@ void creds_client_step(struct dcinfo *dc, DOM_CRED *next_cred_out) next_cred_out->challenge = dc->clnt_chal; next_cred_out->timestamp.time = dc->sequence; } + +void netlogon_creds_client_step(struct dcinfo *dc, + struct netr_Authenticator *next_cred_out) +{ + dc->sequence += 2; + creds_step(dc); + creds_reseed(dc); + + memcpy(&next_cred_out->cred.data, &dc->clnt_chal.data, + sizeof(next_cred_out->cred.data)); + next_cred_out->timestamp = dc->sequence; +} -- cgit From f8bd3e82e5eda052ede2d294f08165cb23df9d90 Mon Sep 17 00:00:00 2001 From: Günther Deschner Date: Fri, 15 Feb 2008 17:30:38 +0100 Subject: Add netlogon_creds_server_check and netlogon_creds_server_step. Guenther (This used to be commit ea0bf74918e7b009439452ea14ed68b0ce620787) --- source3/libsmb/credentials.c | 45 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) (limited to 'source3/libsmb') diff --git a/source3/libsmb/credentials.c b/source3/libsmb/credentials.c index f03bf22df1..0043f4e6a9 100644 --- a/source3/libsmb/credentials.c +++ b/source3/libsmb/credentials.c @@ -225,6 +225,21 @@ bool creds_server_check(const struct dcinfo *dc, const DOM_CHAL *rcv_cli_chal_in return True; } +bool netlogon_creds_server_check(const struct dcinfo *dc, + const struct netr_Credential *rcv_cli_chal_in) +{ + if (memcmp(dc->clnt_chal.data, rcv_cli_chal_in->data, 8)) { + DEBUG(5,("netlogon_creds_server_check: challenge : %s\n", + credstr(rcv_cli_chal_in->data))); + DEBUG(5,("calculated: %s\n", credstr(dc->clnt_chal.data))); + DEBUG(2,("netlogon_creds_server_check: credentials check failed.\n")); + return false; + } + + DEBUG(10,("netlogon_creds_server_check: credentials check OK.\n")); + + return true; +} /**************************************************************************** Replace current seed chal. Internal function - due to split server step below. ****************************************************************************/ @@ -273,6 +288,36 @@ bool creds_server_step(struct dcinfo *dc, const DOM_CRED *received_cred, DOM_CRE return True; } +bool netlogon_creds_server_step(struct dcinfo *dc, + const struct netr_Authenticator *received_cred, + struct netr_Authenticator *cred_out) +{ + bool ret; + struct dcinfo tmp_dc = *dc; + + /* Do all operations on a temporary copy of the dc, + which we throw away if the checks fail. */ + + tmp_dc.sequence = received_cred->timestamp; + + creds_step(&tmp_dc); + + /* Create the outgoing credentials */ + cred_out->timestamp = tmp_dc.sequence + 1; + memcpy(&cred_out->cred, &tmp_dc.srv_chal, sizeof(cred_out->cred)); + + creds_reseed(&tmp_dc); + + ret = netlogon_creds_server_check(&tmp_dc, &received_cred->cred); + if (!ret) { + return false; + } + + /* creds step succeeded - replace the current creds. */ + *dc = tmp_dc; + return true; +} + /**************************************************************************** Create a client credential struct. ****************************************************************************/ -- cgit From 3f24ef18481417fd7d52856b3d68bec099a7b643 Mon Sep 17 00:00:00 2001 From: Günther Deschner Date: Fri, 15 Feb 2008 23:57:19 +0100 Subject: Replace DOM_CHAL with "struct netr_Credential" where we can right now. This allows to remove some more old netlogon client calls. Guenther (This used to be commit c0b1a876583230a5130f5df1965d6c742961bcdc) --- source3/libsmb/credentials.c | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) (limited to 'source3/libsmb') diff --git a/source3/libsmb/credentials.c b/source3/libsmb/credentials.c index 0043f4e6a9..328b931df0 100644 --- a/source3/libsmb/credentials.c +++ b/source3/libsmb/credentials.c @@ -42,9 +42,9 @@ char *credstr(const unsigned char *cred) ****************************************************************************/ static void creds_init_128(struct dcinfo *dc, - const DOM_CHAL *clnt_chal_in, - const DOM_CHAL *srv_chal_in, - const unsigned char mach_pw[16]) + const struct netr_Credential *clnt_chal_in, + const struct netr_Credential *srv_chal_in, + const unsigned char mach_pw[16]) { unsigned char zero[4], tmp[16]; HMACMD5Context ctx; @@ -94,9 +94,9 @@ static void creds_init_128(struct dcinfo *dc, ****************************************************************************/ static void creds_init_64(struct dcinfo *dc, - const DOM_CHAL *clnt_chal_in, - const DOM_CHAL *srv_chal_in, - const unsigned char mach_pw[16]) + const struct netr_Credential *clnt_chal_in, + const struct netr_Credential *srv_chal_in, + const unsigned char mach_pw[16]) { uint32 sum[2]; unsigned char sum2[8]; @@ -177,10 +177,10 @@ static void creds_step(struct dcinfo *dc) void creds_server_init(uint32 neg_flags, struct dcinfo *dc, - DOM_CHAL *clnt_chal, - DOM_CHAL *srv_chal, + struct netr_Credential *clnt_chal, + struct netr_Credential *srv_chal, const unsigned char mach_pw[16], - DOM_CHAL *init_chal_out) + struct netr_Credential *init_chal_out) { DEBUG(10,("creds_server_init: neg_flags : %x\n", (unsigned int)neg_flags)); DEBUG(10,("creds_server_init: client chal : %s\n", credstr(clnt_chal->data) )); @@ -246,7 +246,7 @@ bool netlogon_creds_server_check(const struct dcinfo *dc, static void creds_reseed(struct dcinfo *dc) { - DOM_CHAL time_chal; + struct netr_Credential time_chal; SIVAL(time_chal.data, 0, IVAL(dc->seed_chal.data, 0) + dc->sequence + 1); SIVAL(time_chal.data, 4, IVAL(dc->seed_chal.data, 4)); @@ -274,7 +274,8 @@ bool creds_server_step(struct dcinfo *dc, const DOM_CRED *received_cred, DOM_CRE /* Create the outgoing credentials */ cred_out->timestamp.time = tmp_dc.sequence + 1; - cred_out->challenge = tmp_dc.srv_chal; + memcpy(&cred_out->challenge.data, tmp_dc.srv_chal.data, + sizeof(cred_out->challenge.data)); creds_reseed(&tmp_dc); @@ -324,10 +325,10 @@ bool netlogon_creds_server_step(struct dcinfo *dc, void creds_client_init(uint32 neg_flags, struct dcinfo *dc, - DOM_CHAL *clnt_chal, - DOM_CHAL *srv_chal, + struct netr_Credential *clnt_chal, + struct netr_Credential *srv_chal, const unsigned char mach_pw[16], - DOM_CHAL *init_chal_out) + struct netr_Credential *init_chal_out) { dc->sequence = time(NULL); @@ -406,7 +407,8 @@ void creds_client_step(struct dcinfo *dc, DOM_CRED *next_cred_out) creds_step(dc); creds_reseed(dc); - next_cred_out->challenge = dc->clnt_chal; + memcpy(&next_cred_out->challenge.data, dc->clnt_chal.data, + sizeof(next_cred_out->challenge.data)); next_cred_out->timestamp.time = dc->sequence; } -- cgit From b6285fc0526ff15250242489047bb8d49a1948e6 Mon Sep 17 00:00:00 2001 From: Günther Deschner Date: Sat, 16 Feb 2008 15:14:04 +0100 Subject: Remove unused creds_server_check and creds_server_step. Guenther (This used to be commit 2fb73a3545634982d17d3823cb629f06c5779fc0) --- source3/libsmb/credentials.c | 41 ----------------------------------------- 1 file changed, 41 deletions(-) (limited to 'source3/libsmb') diff --git a/source3/libsmb/credentials.c b/source3/libsmb/credentials.c index 328b931df0..2dcbdf3cf9 100644 --- a/source3/libsmb/credentials.c +++ b/source3/libsmb/credentials.c @@ -213,18 +213,6 @@ void creds_server_init(uint32 neg_flags, Check a credential sent by the client. ****************************************************************************/ -bool creds_server_check(const struct dcinfo *dc, const DOM_CHAL *rcv_cli_chal_in) -{ - if (memcmp(dc->clnt_chal.data, rcv_cli_chal_in->data, 8)) { - DEBUG(5,("creds_server_check: challenge : %s\n", credstr(rcv_cli_chal_in->data))); - DEBUG(5,("calculated: %s\n", credstr(dc->clnt_chal.data))); - DEBUG(2,("creds_server_check: credentials check failed.\n")); - return False; - } - DEBUG(10,("creds_server_check: credentials check OK.\n")); - return True; -} - bool netlogon_creds_server_check(const struct dcinfo *dc, const struct netr_Credential *rcv_cli_chal_in) { @@ -260,35 +248,6 @@ static void creds_reseed(struct dcinfo *dc) Step the server credential chain one forward. ****************************************************************************/ -bool creds_server_step(struct dcinfo *dc, const DOM_CRED *received_cred, DOM_CRED *cred_out) -{ - bool ret; - struct dcinfo tmp_dc = *dc; - - /* Do all operations on a temporary copy of the dc, - which we throw away if the checks fail. */ - - tmp_dc.sequence = received_cred->timestamp.time; - - creds_step(&tmp_dc); - - /* Create the outgoing credentials */ - cred_out->timestamp.time = tmp_dc.sequence + 1; - memcpy(&cred_out->challenge.data, tmp_dc.srv_chal.data, - sizeof(cred_out->challenge.data)); - - creds_reseed(&tmp_dc); - - ret = creds_server_check(&tmp_dc, &received_cred->challenge); - if (!ret) { - return False; - } - - /* creds step succeeded - replace the current creds. */ - *dc = tmp_dc; - return True; -} - bool netlogon_creds_server_step(struct dcinfo *dc, const struct netr_Authenticator *received_cred, struct netr_Authenticator *cred_out) -- cgit From dd65a349350717eb17257ccf281561dd878ead12 Mon Sep 17 00:00:00 2001 From: Günther Deschner Date: Sat, 16 Feb 2008 16:04:01 +0100 Subject: Use rpccli_netr_ServerPasswordSet in "just_change_the_password()". Guenther (This used to be commit 33f91c894488687a42500e751eb9016d99d9129c) --- source3/libsmb/trusts_util.c | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) (limited to 'source3/libsmb') diff --git a/source3/libsmb/trusts_util.c b/source3/libsmb/trusts_util.c index 11f691bee6..1e92bf21de 100644 --- a/source3/libsmb/trusts_util.c +++ b/source3/libsmb/trusts_util.c @@ -58,7 +58,32 @@ static NTSTATUS just_change_the_password(struct rpc_pipe_client *cli, TALLOC_CTX } } - result = rpccli_net_srv_pwset(cli, mem_ctx, global_myname(), new_trust_passwd_hash); + { + struct netr_Authenticator clnt_creds, srv_cred; + struct samr_Password new_password; + + netlogon_creds_client_step(cli->dc, &clnt_creds); + + cred_hash3(new_password.hash, + new_trust_passwd_hash, + cli->dc->sess_key, 1); + + result = rpccli_netr_ServerPasswordSet(cli, mem_ctx, + cli->dc->remote_machine, + cli->dc->mach_acct, + sec_channel_type, + global_myname(), + &clnt_creds, + &srv_cred, + &new_password); + + /* Always check returned credentials. */ + if (!netlogon_creds_client_check(cli->dc, &srv_cred.cred)) { + DEBUG(0,("rpccli_netr_ServerPasswordSet: " + "credentials chain check failed\n")); + return NT_STATUS_ACCESS_DENIED; + } + } if (!NT_STATUS_IS_OK(result)) { DEBUG(0,("just_change_the_password: unable to change password (%s)!\n", -- cgit From 8027b7c25dfa5b4617c4fafbf1e4aaf4f7fee43a Mon Sep 17 00:00:00 2001 From: Günther Deschner Date: Sun, 17 Feb 2008 01:47:01 +0100 Subject: Use netr_SamInfo3 in samlogon cache and use ndr functions for storing the blob. Guenther (This used to be commit bf860ae1ac6765b1eb6e2ca9b667b19b4e661fda) --- source3/libsmb/samlogon_cache.c | 217 ++++++++++++++++++++++------------------ 1 file changed, 119 insertions(+), 98 deletions(-) (limited to 'source3/libsmb') diff --git a/source3/libsmb/samlogon_cache.c b/source3/libsmb/samlogon_cache.c index 4f791f66f6..e2a4b3898f 100644 --- a/source3/libsmb/samlogon_cache.c +++ b/source3/libsmb/samlogon_cache.c @@ -1,21 +1,21 @@ -/* +/* Unix SMB/CIFS implementation. Net_sam_logon info3 helpers Copyright (C) Alexander Bokovoy 2002. Copyright (C) Andrew Bartlett 2002. Copyright (C) Gerald Carter 2003. Copyright (C) Tim Potter 2003. - + 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 . */ @@ -29,12 +29,12 @@ static TDB_CONTEXT *netsamlogon_tdb = NULL; /*********************************************************************** open the tdb ***********************************************************************/ - + bool netsamlogon_cache_init(void) { if (!netsamlogon_tdb) { netsamlogon_tdb = tdb_open_log(lock_path(NETSAMLOGON_TDB), 0, - TDB_DEFAULT, O_RDWR | O_CREAT, 0600); + TDB_DEFAULT, O_RDWR | O_CREAT, 0600); } return (netsamlogon_tdb != NULL); @@ -47,37 +47,39 @@ bool netsamlogon_cache_init(void) bool netsamlogon_cache_shutdown(void) { - if(netsamlogon_tdb) + if (netsamlogon_tdb) { return (tdb_close(netsamlogon_tdb) == 0); - - return True; + } + + return true; } /*********************************************************************** Clear cache getpwnam and getgroups entries from the winbindd cache ***********************************************************************/ -void netsamlogon_clear_cached_user(TDB_CONTEXT *tdb, NET_USER_INFO_3 *user) + +void netsamlogon_clear_cached_user(TDB_CONTEXT *tdb, struct netr_SamInfo3 *info3) { - bool got_tdb = False; + bool got_tdb = false; DOM_SID sid; fstring key_str, sid_string; /* We may need to call this function from smbd which will not have - winbindd_cache.tdb open. Open the tdb if a NULL is passed. */ + winbindd_cache.tdb open. Open the tdb if a NULL is passed. */ if (!tdb) { - tdb = tdb_open_log(lock_path("winbindd_cache.tdb"), + tdb = tdb_open_log(lock_path("winbindd_cache.tdb"), WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE, TDB_DEFAULT, O_RDWR, 0600); if (!tdb) { DEBUG(5, ("netsamlogon_clear_cached_user: failed to open cache\n")); return; } - got_tdb = True; + got_tdb = true; } - sid_copy(&sid, &user->dom_sid.sid); - sid_append_rid(&sid, user->user_rid); + sid_copy(&sid, info3->base.domain_sid); + sid_append_rid(&sid, info3->base.rid); /* Clear U/SID cache entry */ @@ -95,157 +97,176 @@ void netsamlogon_clear_cached_user(TDB_CONTEXT *tdb, NET_USER_INFO_3 *user) tdb_delete(tdb, string_tdb_data(key_str)); - if (got_tdb) + if (got_tdb) { tdb_close(tdb); + } } /*********************************************************************** - Store a NET_USER_INFO_3 structure in a tdb for later user + Store a netr_SamInfo3 structure in a tdb for later user username should be in UTF-8 format ***********************************************************************/ -bool netsamlogon_cache_store( const char *username, NET_USER_INFO_3 *user ) +bool netsamlogon_cache_store(const char *username, struct netr_SamInfo3 *info3) { - TDB_DATA data; - fstring keystr, tmp; - prs_struct ps; - bool result = False; - DOM_SID user_sid; - time_t t = time(NULL); - TALLOC_CTX *mem_ctx; - + TDB_DATA data; + fstring keystr, tmp; + bool result = false; + DOM_SID user_sid; + time_t t = time(NULL); + TALLOC_CTX *mem_ctx; + DATA_BLOB blob; + enum ndr_err_code ndr_err; + struct netsamlogoncache_entry r; + + if (!info3) { + return false; + } if (!netsamlogon_cache_init()) { - DEBUG(0,("netsamlogon_cache_store: cannot open %s for write!\n", NETSAMLOGON_TDB)); - return False; + DEBUG(0,("netsamlogon_cache_store: cannot open %s for write!\n", + NETSAMLOGON_TDB)); + return false; } - sid_copy( &user_sid, &user->dom_sid.sid ); - sid_append_rid( &user_sid, user->user_rid ); + sid_copy(&user_sid, info3->base.domain_sid); + sid_append_rid(&user_sid, info3->base.rid); /* Prepare key as DOMAIN-SID/USER-RID string */ slprintf(keystr, sizeof(keystr), "%s", sid_to_fstring(tmp, &user_sid)); DEBUG(10,("netsamlogon_cache_store: SID [%s]\n", keystr)); - + + /* Prepare data */ + + if (!(mem_ctx = TALLOC_P( NULL, int))) { + DEBUG(0,("netsamlogon_cache_store: talloc() failed!\n")); + return false; + } + /* only Samba fills in the username, not sure why NT doesn't */ /* so we fill it in since winbindd_getpwnam() makes use of it */ - - if ( !user->uni_user_name.buffer ) { - init_unistr2( &user->uni_user_name, username, UNI_STR_TERMINATE ); - init_uni_hdr( &user->hdr_user_name, &user->uni_user_name ); + + if (!info3->base.account_name.string) { + info3->base.account_name.string = talloc_strdup(mem_ctx, username); } - - /* Prepare data */ - - if ( !(mem_ctx = TALLOC_P( NULL, int )) ) { - DEBUG(0,("netsamlogon_cache_store: talloc() failed!\n")); - return False; + + r.timestamp = t; + r.info3 = *info3; + + if (DEBUGLEVEL >= 10) { + NDR_PRINT_DEBUG(netsamlogoncache_entry, &r); } - prs_init( &ps, RPC_MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL); - - { - uint32 ts = (uint32)t; - if ( !prs_uint32( "timestamp", &ps, 0, &ts ) ) - return False; + ndr_err = ndr_push_struct_blob(&blob, mem_ctx, &r, + (ndr_push_flags_fn_t)ndr_push_netsamlogoncache_entry); + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + DEBUG(0,("netsamlogon_cache_store: failed to push entry to cache\n")); + TALLOC_FREE(mem_ctx); + return false; } - - if ( net_io_user_info3("", user, &ps, 0, 3, 0) ) - { - data.dsize = prs_offset( &ps ); - data.dptr = (uint8 *)prs_data_p( &ps ); - if (tdb_store_bystring(netsamlogon_tdb, keystr, data, TDB_REPLACE) != -1) - result = True; - - prs_mem_free( &ps ); + data.dsize = blob.length; + data.dptr = blob.data; + + if (tdb_store_bystring(netsamlogon_tdb, keystr, data, TDB_REPLACE) != -1) { + result = true; } - TALLOC_FREE( mem_ctx ); - + TALLOC_FREE(mem_ctx); + return result; } /*********************************************************************** - Retrieves a NET_USER_INFO_3 structure from a tdb. Caller must + Retrieves a netr_SamInfo3 structure from a tdb. Caller must free the user_info struct (malloc()'d memory) ***********************************************************************/ -NET_USER_INFO_3* netsamlogon_cache_get( TALLOC_CTX *mem_ctx, const DOM_SID *user_sid) +struct netr_SamInfo3 *netsamlogon_cache_get(TALLOC_CTX *mem_ctx, const DOM_SID *user_sid) { - NET_USER_INFO_3 *user = NULL; - TDB_DATA data; - prs_struct ps; - fstring keystr, tmp; - uint32 t; - + struct netr_SamInfo3 *info3 = NULL; + TDB_DATA data; + fstring keystr, tmp; + enum ndr_err_code ndr_err; + DATA_BLOB blob; + struct netsamlogoncache_entry r; + if (!netsamlogon_cache_init()) { - DEBUG(0,("netsamlogon_cache_get: cannot open %s for write!\n", NETSAMLOGON_TDB)); - return False; + DEBUG(0,("netsamlogon_cache_get: cannot open %s for write!\n", + NETSAMLOGON_TDB)); + return false; } /* Prepare key as DOMAIN-SID/USER-RID string */ slprintf(keystr, sizeof(keystr), "%s", sid_to_fstring(tmp, user_sid)); DEBUG(10,("netsamlogon_cache_get: SID [%s]\n", keystr)); data = tdb_fetch_bystring( netsamlogon_tdb, keystr ); - - if ( data.dptr ) { - user = TALLOC_ZERO_P(mem_ctx, NET_USER_INFO_3); - if (user == NULL) { - return NULL; - } + if (!data.dptr) { + return NULL; + } - prs_init( &ps, 0, mem_ctx, UNMARSHALL ); - prs_give_memory( &ps, (char *)data.dptr, data.dsize, True ); - - if ( !prs_uint32( "timestamp", &ps, 0, &t ) ) { - prs_mem_free( &ps ); - TALLOC_FREE(user); - return False; - } - - if ( !net_io_user_info3("", user, &ps, 0, 3, 0) ) { - TALLOC_FREE( user ); - } - - prs_mem_free( &ps ); + info3 = TALLOC_ZERO_P(mem_ctx, struct netr_SamInfo3); + if (!info3) { + goto done; + } + + blob.data = (uint8 *)data.dptr; + blob.length = data.dsize; + + ndr_err = ndr_pull_struct_blob(&blob, mem_ctx, &r, + (ndr_pull_flags_fn_t)ndr_pull_netsamlogoncache_entry); -#if 0 /* The netsamlogon cache needs to hang around. Something about + if (DEBUGLEVEL >= 10) { + NDR_PRINT_DEBUG(netsamlogoncache_entry, &r); + } + + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + DEBUG(0,("netsamlogon_cache_get: failed to pull entry from cache\n")); + tdb_delete(netsamlogon_tdb, data); + goto done; + } + + info3 = talloc_memdup(mem_ctx, &r.info3, sizeof(r.info3)); + + done: + SAFE_FREE(data.dptr); + + return info3; + +#if 0 /* The netsamlogon cache needs to hang around. Something about this feels wrong, but it is the only way we can get all of the groups. The old universal groups cache didn't expire either. --jerry */ { time_t now = time(NULL); uint32 time_diff; - + /* is the entry expired? */ time_diff = now - t; - + if ( (time_diff < 0 ) || (time_diff > lp_winbind_cache_time()) ) { DEBUG(10,("netsamlogon_cache_get: cache entry expired \n")); tdb_delete( netsamlogon_tdb, key ); TALLOC_FREE( user ); } -#endif } - - return user; +#endif } bool netsamlogon_cache_have(const DOM_SID *user_sid) { TALLOC_CTX *mem_ctx = talloc_init("netsamlogon_cache_have"); - NET_USER_INFO_3 *user = NULL; + struct netr_SamInfo3 *info3 = NULL; bool result; if (!mem_ctx) return False; - user = netsamlogon_cache_get(mem_ctx, user_sid); + info3 = netsamlogon_cache_get(mem_ctx, user_sid); - result = (user != NULL); + result = (info3 != NULL); talloc_destroy(mem_ctx); -- cgit From c1793b2b316a8f912dde14f806c84ac7d1491bf3 Mon Sep 17 00:00:00 2001 From: Günther Deschner Date: Sun, 17 Feb 2008 01:59:02 +0100 Subject: Use new IDL based PAC structures in clikrb5.c Guenther (This used to be commit 3b0135d57e1e70175a5eec49b603a2e5f700c770) --- source3/libsmb/clikrb5.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'source3/libsmb') diff --git a/source3/libsmb/clikrb5.c b/source3/libsmb/clikrb5.c index 844a3b35c0..c289740ab2 100644 --- a/source3/libsmb/clikrb5.c +++ b/source3/libsmb/clikrb5.c @@ -835,22 +835,22 @@ failed: #endif } - void smb_krb5_checksum_from_pac_sig(krb5_checksum *cksum, - PAC_SIGNATURE_DATA *sig) + void smb_krb5_checksum_from_pac_sig(krb5_checksum *cksum, + struct PAC_SIGNATURE_DATA *sig) { #ifdef HAVE_CHECKSUM_IN_KRB5_CHECKSUM cksum->cksumtype = (krb5_cksumtype)sig->type; - cksum->checksum.length = sig->signature.buf_len; - cksum->checksum.data = sig->signature.buffer; + cksum->checksum.length = sig->signature.length; + cksum->checksum.data = sig->signature.data; #else cksum->checksum_type = (krb5_cksumtype)sig->type; - cksum->length = sig->signature.buf_len; - cksum->contents = sig->signature.buffer; + cksum->length = sig->signature.length; + cksum->contents = sig->signature.data; #endif } krb5_error_code smb_krb5_verify_checksum(krb5_context context, - krb5_keyblock *keyblock, + const krb5_keyblock *keyblock, krb5_keyusage usage, krb5_checksum *cksum, uint8 *data, -- cgit From 5b8ebcf397e40bf1f9555c34fadbab2d7b5bf717 Mon Sep 17 00:00:00 2001 From: Günther Deschner Date: Sun, 17 Feb 2008 03:08:42 +0100 Subject: Remove unused creds_client_check and creds_client_step. Guenther (This used to be commit 1dcb32424d16cff968a8713352c93c48dec58674) --- source3/libsmb/credentials.c | 23 ----------------------- 1 file changed, 23 deletions(-) (limited to 'source3/libsmb') diff --git a/source3/libsmb/credentials.c b/source3/libsmb/credentials.c index 2dcbdf3cf9..9d33e6d93d 100644 --- a/source3/libsmb/credentials.c +++ b/source3/libsmb/credentials.c @@ -322,18 +322,6 @@ void creds_client_init(uint32 neg_flags, Check a credential returned by the server. ****************************************************************************/ -bool creds_client_check(const struct dcinfo *dc, const DOM_CHAL *rcv_srv_chal_in) -{ - if (memcmp(dc->srv_chal.data, rcv_srv_chal_in->data, 8)) { - DEBUG(5,("creds_client_check: challenge : %s\n", credstr(rcv_srv_chal_in->data))); - DEBUG(5,("calculated: %s\n", credstr(dc->srv_chal.data))); - DEBUG(0,("creds_client_check: credentials check failed.\n")); - return False; - } - DEBUG(10,("creds_client_check: credentials check OK.\n")); - return True; -} - bool netlogon_creds_client_check(const struct dcinfo *dc, const struct netr_Credential *rcv_srv_chal_in) { @@ -360,17 +348,6 @@ bool netlogon_creds_client_check(const struct dcinfo *dc, the server ****************************************************************************/ -void creds_client_step(struct dcinfo *dc, DOM_CRED *next_cred_out) -{ - dc->sequence += 2; - creds_step(dc); - creds_reseed(dc); - - memcpy(&next_cred_out->challenge.data, dc->clnt_chal.data, - sizeof(next_cred_out->challenge.data)); - next_cred_out->timestamp.time = dc->sequence; -} - void netlogon_creds_client_step(struct dcinfo *dc, struct netr_Authenticator *next_cred_out) { -- cgit From 441de75e58daf734c412a3e741608822289cac59 Mon Sep 17 00:00:00 2001 From: Tim Potter Date: Mon, 18 Feb 2008 21:00:51 +1100 Subject: Fix memory leaks on error path (This used to be commit 47dd0700b4320bf5ac9a80e71ae82d82d4554e6a) --- source3/libsmb/clifile.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'source3/libsmb') diff --git a/source3/libsmb/clifile.c b/source3/libsmb/clifile.c index 9b4c380d40..10c35a30cc 100644 --- a/source3/libsmb/clifile.c +++ b/source3/libsmb/clifile.c @@ -38,8 +38,15 @@ static bool cli_link_internal(struct cli_state *cli, const char *oldname, const size_t newlen = 2*(strlen(newname)+1); param = SMB_MALLOC_ARRAY(char, 6+newlen+2); + + if (!param) { + return false; + } + data = SMB_MALLOC_ARRAY(char, oldlen+2); - if (!param || !data) { + + if (!data) { + SAFE_FREE(param); return false; } -- cgit From 6548493de7680dedd429bf851fc57b577e06c673 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Sat, 23 Feb 2008 10:50:12 +0100 Subject: Fix a C++ warning (This used to be commit ac027a9b2e84d319f961ac0e84654a0e48920138) --- source3/libsmb/samlogon_cache.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'source3/libsmb') diff --git a/source3/libsmb/samlogon_cache.c b/source3/libsmb/samlogon_cache.c index e2a4b3898f..3cc0dcf0fb 100644 --- a/source3/libsmb/samlogon_cache.c +++ b/source3/libsmb/samlogon_cache.c @@ -228,7 +228,8 @@ struct netr_SamInfo3 *netsamlogon_cache_get(TALLOC_CTX *mem_ctx, const DOM_SID * goto done; } - info3 = talloc_memdup(mem_ctx, &r.info3, sizeof(r.info3)); + info3 = (struct netr_SamInfo3 *)talloc_memdup(mem_ctx, &r.info3, + sizeof(r.info3)); done: SAFE_FREE(data.dptr); -- cgit From a5e43bc81711e25cb07224df5e64f0120d4ef500 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Sat, 23 Feb 2008 21:40:39 +0100 Subject: Fix typo (This used to be commit 621db68f32f7007de8b2c4d7cf604a5778725615) --- source3/libsmb/cliconnect.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'source3/libsmb') diff --git a/source3/libsmb/cliconnect.c b/source3/libsmb/cliconnect.c index e97be98fc1..d88a5d6242 100644 --- a/source3/libsmb/cliconnect.c +++ b/source3/libsmb/cliconnect.c @@ -581,8 +581,8 @@ static bool cli_session_setup_blob(struct cli_state *cli, DATA_BLOB blob, DATA_B if (cli_is_error(cli) && !NT_STATUS_EQUAL( cli_get_nt_error(cli), NT_STATUS_MORE_PROCESSING_REQUIRED)) { - DEBUG(0, ("cli_session_setup_blob: recieve failed (%s)\n", - nt_errstr(cli_get_nt_error(cli)) )); + DEBUG(0, ("cli_session_setup_blob: receive failed " + "(%s)\n", nt_errstr(cli_get_nt_error(cli)))); cli->vuid = 0; return False; } -- cgit From 317639287886181edf08ccecad1b324e4cc55d0b Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Mon, 25 Feb 2008 15:24:49 +0100 Subject: Fix some warnings warning: ignoring return value of 'asprintf', declared with attribute warn_unused_result (This used to be commit ad37b7b0aee265a3e4d8b7552610f4b9a105434d) --- source3/libsmb/clifsinfo.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'source3/libsmb') diff --git a/source3/libsmb/clifsinfo.c b/source3/libsmb/clifsinfo.c index fb923378ab..f4945f812a 100644 --- a/source3/libsmb/clifsinfo.c +++ b/source3/libsmb/clifsinfo.c @@ -497,8 +497,7 @@ static NTSTATUS make_cli_gss_blob(struct smb_trans_enc_state *es, 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) { + if (asprintf(&host_princ_s, "%s@%s", service, host) == -1) { return NT_STATUS_NO_MEMORY; } -- cgit From c58e7427bf7200ad413c259f429f020b98d723ec Mon Sep 17 00:00:00 2001 From: Derrell Lipman Date: Tue, 26 Feb 2008 21:42:26 -0500 Subject: add a function to truncate a file to a specified size (This used to be commit 7e5752812d6d9e3bcf9a545cbdcf3afe2175dbc4) --- source3/libsmb/clifile.c | 49 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) (limited to 'source3/libsmb') diff --git a/source3/libsmb/clifile.c b/source3/libsmb/clifile.c index 10c35a30cc..12c427a6fa 100644 --- a/source3/libsmb/clifile.c +++ b/source3/libsmb/clifile.c @@ -888,6 +888,55 @@ bool cli_close(struct cli_state *cli, int fnum) } +/**************************************************************************** + Truncate a file to a specified size +****************************************************************************/ + +bool cli_ftruncate(struct cli_state *cli, int fnum, uint64_t size) +{ + unsigned int param_len = 6; + unsigned int data_len = 8; + uint16 setup = TRANSACT2_SETFILEINFO; + char param[6]; + unsigned char data[8]; + char *rparam=NULL, *rdata=NULL; + int saved_timeout = cli->timeout; + + SSVAL(param,0,fnum); + SSVAL(param,2,SMB_SET_FILE_END_OF_FILE_INFO); + SSVAL(param,4,0); + + SBVAL(data, 0, size); + + if (!cli_send_trans(cli, SMBtrans2, + NULL, /* name */ + -1, 0, /* fid, flags */ + &setup, 1, 0, /* setup, length, max */ + param, param_len, 2, /* param, length, max */ + (char *)&data, data_len,/* data, length, ... */ + cli->max_xmit)) { /* ... max */ + cli->timeout = saved_timeout; + return False; + } + + if (!cli_receive_trans(cli, SMBtrans2, + &rparam, ¶m_len, + &rdata, &data_len)) { + cli->timeout = saved_timeout; + SAFE_FREE(rdata); + SAFE_FREE(rparam); + return False; + } + + cli->timeout = saved_timeout; + + SAFE_FREE(rdata); + SAFE_FREE(rparam); + + return True; +} + + /**************************************************************************** send a lock with a specified locktype this is used for testing LOCKING_ANDX_CANCEL_LOCK -- cgit From fa341d526293f4d986f2f3d838a728ce4223ee88 Mon Sep 17 00:00:00 2001 From: Derrell Lipman Date: Tue, 26 Feb 2008 21:44:51 -0500 Subject: add smbc_ftruncate() to emulate POSIX ftruncate() (This used to be commit 6f5051b9c1405ab1dc3e697419ceedb3acac46d8) --- source3/libsmb/libsmb_compat.c | 6 ++++ source3/libsmb/libsmbclient.c | 75 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 81 insertions(+) (limited to 'source3/libsmb') diff --git a/source3/libsmb/libsmb_compat.c b/source3/libsmb/libsmb_compat.c index 573d087d6e..6042464fd2 100644 --- a/source3/libsmb/libsmb_compat.c +++ b/source3/libsmb/libsmb_compat.c @@ -289,6 +289,12 @@ int smbc_fstat(int fd, struct stat *st) return (statcont->fstat)(statcont, file, st); } +int smbc_ftruncate(int fd, off_t size) +{ + SMBCFILE * file = find_fd(fd); + return (statcont->ftruncate)(statcont, file, size); +} + int smbc_chmod(const char *url, mode_t mode) { return (statcont->chmod)(statcont, url, mode); diff --git a/source3/libsmb/libsmbclient.c b/source3/libsmb/libsmbclient.c index e84de59637..fe008ed6b6 100644 --- a/source3/libsmb/libsmbclient.c +++ b/source3/libsmb/libsmbclient.c @@ -2482,6 +2482,80 @@ smbc_fstat_ctx(SMBCCTX *context, } +/* + * Routine to truncate a file given by its file descriptor, to a specified size + */ + +static int +smbc_ftruncate_ctx(SMBCCTX *context, + SMBCFILE *file, + off_t length) +{ + SMB_OFF_T size = length; + char *server = NULL; + char *share = NULL; + char *user = NULL; + char *password = NULL; + char *path = NULL; + char *targetpath = NULL; + struct cli_state *targetcli = NULL; + TALLOC_CTX *frame = talloc_stackframe(); + + if (!context || !context->internal || + !context->internal->_initialized) { + errno = EINVAL; + TALLOC_FREE(frame); + return -1; + } + + if (!file || !DLIST_CONTAINS(context->internal->_files, file)) { + errno = EBADF; + TALLOC_FREE(frame); + return -1; + } + + if (!file->file) { + errno = EINVAL; + TALLOC_FREE(frame); + return -1; + } + + /*d_printf(">>>fstat: parsing %s\n", file->fname);*/ + if (smbc_parse_path(frame, + context, + file->fname, + NULL, + &server, + &share, + &path, + &user, + &password, + NULL)) { + errno = EINVAL; + TALLOC_FREE(frame); + return -1; + } + + /*d_printf(">>>fstat: resolving %s\n", path);*/ + if (!cli_resolve_path(frame, "", file->srv->cli, path, + &targetcli, &targetpath)) { + d_printf("Could not resolve %s\n", path); + TALLOC_FREE(frame); + return -1; + } + /*d_printf(">>>fstat: resolved path as %s\n", targetpath);*/ + + if (!cli_ftruncate(targetcli, file->cli_fd, size)) { + errno = EINVAL; + TALLOC_FREE(frame); + return -1; + } + + TALLOC_FREE(frame); + return 0; + +} + /* * Routine to open a directory * We accept the URL syntax explained in smbc_parse_path(), above. @@ -6703,6 +6777,7 @@ smbc_new_context(void) context->telldir = smbc_telldir_ctx; context->lseekdir = smbc_lseekdir_ctx; context->fstatdir = smbc_fstatdir_ctx; + context->ftruncate = smbc_ftruncate_ctx; context->chmod = smbc_chmod_ctx; context->utimes = smbc_utimes_ctx; context->setxattr = smbc_setxattr_ctx; -- cgit From 2d01ec2c390f8dd753600f22cefb17e7b8916ffd Mon Sep 17 00:00:00 2001 From: Günther Deschner Date: Wed, 27 Feb 2008 15:49:31 +0100 Subject: Use new LSA_POLICY defines in lsa rpc server code and other places. Guenther (This used to be commit 58cca9faf9db506bd2f6eab4a99ef85153797ab2) --- source3/libsmb/trusts_util.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source3/libsmb') diff --git a/source3/libsmb/trusts_util.c b/source3/libsmb/trusts_util.c index 1e92bf21de..c079fb149a 100644 --- a/source3/libsmb/trusts_util.c +++ b/source3/libsmb/trusts_util.c @@ -209,7 +209,7 @@ bool enumerate_domain_trusts( TALLOC_CTX *mem_ctx, const char *domain, /* get a handle */ result = rpccli_lsa_open_policy(lsa_pipe, mem_ctx, True, - POLICY_VIEW_LOCAL_INFORMATION, &pol); + LSA_POLICY_VIEW_LOCAL_INFORMATION, &pol); if ( !NT_STATUS_IS_OK(result) ) goto done; -- cgit From 7269a504fdd06fbbe24c2df8e084b41382d71269 Mon Sep 17 00:00:00 2001 From: Günther Deschner Date: Wed, 27 Feb 2008 19:38:48 +0100 Subject: Add my copyright. Guenther (This used to be commit d078a8757182d84dfd3307a2e1b751cf173aaa97) --- source3/libsmb/samlogon_cache.c | 1 + 1 file changed, 1 insertion(+) (limited to 'source3/libsmb') diff --git a/source3/libsmb/samlogon_cache.c b/source3/libsmb/samlogon_cache.c index 3cc0dcf0fb..0d855f4c6c 100644 --- a/source3/libsmb/samlogon_cache.c +++ b/source3/libsmb/samlogon_cache.c @@ -5,6 +5,7 @@ Copyright (C) Andrew Bartlett 2002. Copyright (C) Gerald Carter 2003. Copyright (C) Tim Potter 2003. + Copyright (C) Guenther Deschner 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 -- cgit From 1d940490e815bbdb7e4af23ace05ec9ac8fddae8 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Thu, 28 Feb 2008 02:22:13 -0800 Subject: Fix from Guenter Kukkukk to fix listing against OS/2 servers. OS/2 returns eclass == ERRDOS && ecode == ERRnofiles for a zero entry directory listing. Jeremy. (This used to be commit b34da627053581a9584367e177566d4a2cef7e82) --- source3/libsmb/clierror.c | 12 ++++++++++++ source3/libsmb/clilist.c | 16 +++++++++++++++- 2 files changed, 27 insertions(+), 1 deletion(-) (limited to 'source3/libsmb') diff --git a/source3/libsmb/clierror.c b/source3/libsmb/clierror.c index 587abade59..36746419f7 100644 --- a/source3/libsmb/clierror.c +++ b/source3/libsmb/clierror.c @@ -483,3 +483,15 @@ void cli_set_nt_error(struct cli_state *cli, NTSTATUS status) SSVAL(cli->inbuf,smb_flg2, SVAL(cli->inbuf,smb_flg2)|FLAGS2_32_BIT_ERROR_CODES); SIVAL(cli->inbuf, smb_rcls, NT_STATUS_V(status)); } + +/* Reset an error. */ + +void cli_reset_error(struct cli_state *cli) +{ + if (SVAL(cli->inbuf,smb_flg2) & FLAGS2_32_BIT_ERROR_CODES) { + SIVAL(cli->inbuf, smb_rcls, NT_STATUS_V(NT_STATUS_OK)); + } else { + SCVAL(cli->inbuf,smb_rcls,0); + SSVAL(cli->inbuf,smb_err,0); + } +} diff --git a/source3/libsmb/clilist.c b/source3/libsmb/clilist.c index e1b16154f2..50918458b0 100644 --- a/source3/libsmb/clilist.c +++ b/source3/libsmb/clilist.c @@ -328,7 +328,7 @@ int cli_list_new(struct cli_state *cli,const char *Mask,uint16 attribute, &rparam, ¶m_len, &rdata, &data_len) && cli_is_dos_error(cli)) { - /* we need to work around a Win95 bug - sometimes + /* We need to work around a Win95 bug - sometimes it gives ERRSRV/ERRerror temprarily */ uint8 eclass; uint32 ecode; @@ -337,6 +337,20 @@ int cli_list_new(struct cli_state *cli,const char *Mask,uint16 attribute, SAFE_FREE(rparam); cli_dos_error(cli, &eclass, &ecode); + + /* + * OS/2 might return "no more files", + * which just tells us, that searchcount is zero + * in this search. + * Guenter Kukkukk + */ + + if (eclass == ERRDOS && ecode == ERRnofiles) { + ff_searchcount = 0; + cli_reset_error(cli); + break; + } + if (eclass != ERRSRV || ecode != ERRerror) break; smb_msleep(100); -- cgit From 0d8985f2da43d35d8f940af112ad74a199778dd8 Mon Sep 17 00:00:00 2001 From: Günther Deschner Date: Thu, 28 Feb 2008 12:30:18 +0100 Subject: Let dsgetdcname() return a struct netr_DsRGetDCNameInfo. Guenther (This used to be commit b1a4b21f8c35dc23e5c986ebe44d3806055eb39b) --- source3/libsmb/dsgetdcname.c | 144 ++++++++++++++++++++----------------------- 1 file changed, 67 insertions(+), 77 deletions(-) (limited to 'source3/libsmb') diff --git a/source3/libsmb/dsgetdcname.c b/source3/libsmb/dsgetdcname.c index e0be76cc85..bc9f4b92c8 100644 --- a/source3/libsmb/dsgetdcname.c +++ b/source3/libsmb/dsgetdcname.c @@ -110,7 +110,7 @@ void debug_dsdcinfo_flags(int lvl, uint32_t flags) /********************************************************************* ********************************************************************/ -static int pack_dsdcinfo(struct DS_DOMAIN_CONTROLLER_INFO *info, +static int pack_dsdcinfo(struct netr_DsRGetDCNameInfo *info, unsigned char **buf) { unsigned char *buffer = NULL; @@ -122,9 +122,8 @@ static int pack_dsdcinfo(struct DS_DOMAIN_CONTROLLER_INFO *info, ZERO_STRUCT(guid_flat); - if (info->domain_guid) { - const struct GUID *guid = info->domain_guid; - smb_uuid_pack(*guid, &guid_flat); + if (!GUID_all_zero(&info->domain_guid)) { + smb_uuid_pack(info->domain_guid, &guid_flat); } again: @@ -132,17 +131,17 @@ static int pack_dsdcinfo(struct DS_DOMAIN_CONTROLLER_INFO *info, if (buflen > 0) { DEBUG(10,("pack_dsdcinfo: Packing domain %s (%s)\n", - info->domain_name, info->domain_controller_name)); + info->domain_name, info->dc_unc)); } len += tdb_pack(buffer+len, buflen-len, "ffdBffdff", - info->domain_controller_name, - info->domain_controller_address, - info->domain_controller_address_type, + info->dc_unc, + info->dc_address, + info->dc_address_type, UUID_FLAT_SIZE, guid_flat.info, info->domain_name, - info->dns_forest_name, - info->flags, + info->forest_name, + info->dc_flags, info->dc_site_name, info->client_site_name); @@ -169,33 +168,33 @@ static int pack_dsdcinfo(struct DS_DOMAIN_CONTROLLER_INFO *info, static NTSTATUS unpack_dsdcinfo(TALLOC_CTX *mem_ctx, unsigned char *buf, int buflen, - struct DS_DOMAIN_CONTROLLER_INFO **info_ret) + struct netr_DsRGetDCNameInfo **info_ret) { int len = 0; - struct DS_DOMAIN_CONTROLLER_INFO *info = NULL; + struct netr_DsRGetDCNameInfo *info = NULL; uint32_t guid_len = 0; unsigned char *guid_buf = NULL; UUID_FLAT guid_flat; /* forgive me 6 times */ - fstring domain_controller_name; - fstring domain_controller_address; + fstring dc_unc; + fstring dc_address; fstring domain_name; - fstring dns_forest_name; + fstring forest_name; fstring dc_site_name; fstring client_site_name; - info = TALLOC_ZERO_P(mem_ctx, struct DS_DOMAIN_CONTROLLER_INFO); + info = TALLOC_ZERO_P(mem_ctx, struct netr_DsRGetDCNameInfo); NT_STATUS_HAVE_NO_MEMORY(info); len += tdb_unpack(buf+len, buflen-len, "ffdBffdff", - &domain_controller_name, - &domain_controller_address, - &info->domain_controller_address_type, + &dc_unc, + &dc_address, + &info->dc_address_type, &guid_len, &guid_buf, &domain_name, - &dns_forest_name, - &info->flags, + &forest_name, + &info->dc_flags, &dc_site_name, &client_site_name); if (len == -1) { @@ -203,23 +202,23 @@ static NTSTATUS unpack_dsdcinfo(TALLOC_CTX *mem_ctx, goto failed; } - info->domain_controller_name = - talloc_strdup(mem_ctx, domain_controller_name); - info->domain_controller_address = - talloc_strdup(mem_ctx, domain_controller_address); + info->dc_unc = + talloc_strdup(mem_ctx, dc_unc); + info->dc_address = + talloc_strdup(mem_ctx, dc_address); info->domain_name = talloc_strdup(mem_ctx, domain_name); - info->dns_forest_name = - talloc_strdup(mem_ctx, dns_forest_name); + info->forest_name = + talloc_strdup(mem_ctx, forest_name); info->dc_site_name = talloc_strdup(mem_ctx, dc_site_name); info->client_site_name = talloc_strdup(mem_ctx, client_site_name); - if (!info->domain_controller_name || - !info->domain_controller_address || + if (!info->dc_unc || + !info->dc_address || !info->domain_name || - !info->dns_forest_name || + !info->forest_name || !info->dc_site_name || !info->client_site_name) { goto failed; @@ -235,16 +234,12 @@ static NTSTATUS unpack_dsdcinfo(TALLOC_CTX *mem_ctx, memcpy(&guid_flat.info, guid_buf, guid_len); smb_uuid_unpack(guid_flat, &guid); - info->domain_guid = (struct GUID *)talloc_memdup( - mem_ctx, &guid, sizeof(guid)); - if (!info->domain_guid) { - goto failed; - } + info->domain_guid = guid; SAFE_FREE(guid_buf); } DEBUG(10,("unpack_dcscinfo: Unpacked domain %s (%s)\n", - info->domain_name, info->domain_controller_name)); + info->domain_name, info->dc_unc)); *info_ret = info; @@ -297,7 +292,7 @@ static NTSTATUS dsgetdcname_cache_delete(TALLOC_CTX *mem_ctx, static NTSTATUS dsgetdcname_cache_store(TALLOC_CTX *mem_ctx, const char *domain_name, - struct DS_DOMAIN_CONTROLLER_INFO *info) + struct netr_DsRGetDCNameInfo *info) { time_t expire_time; char *key; @@ -346,7 +341,7 @@ static NTSTATUS dsgetdcname_cache_refresh(TALLOC_CTX *mem_ctx, struct GUID *domain_guid, uint32_t flags, const char *site_name, - struct DS_DOMAIN_CONTROLLER_INFO *info) + struct netr_DsRGetDCNameInfo *info) { struct cldap_netlogon_reply r; @@ -355,7 +350,7 @@ static NTSTATUS dsgetdcname_cache_refresh(TALLOC_CTX *mem_ctx, ZERO_STRUCT(r); - if (ads_cldap_netlogon(info->domain_controller_name, + if (ads_cldap_netlogon(info->dc_unc, info->domain_name, &r)) { dsgetdcname_cache_delete(mem_ctx, domain_name); @@ -409,7 +404,7 @@ static NTSTATUS dsgetdcname_cache_fetch(TALLOC_CTX *mem_ctx, struct GUID *domain_guid, uint32_t flags, const char *site_name, - struct DS_DOMAIN_CONTROLLER_INFO **info, + struct netr_DsRGetDCNameInfo **info, bool *expired) { char *key; @@ -438,13 +433,13 @@ static NTSTATUS dsgetdcname_cache_fetch(TALLOC_CTX *mem_ctx, data_blob_free(&blob); /* check flags */ - if (!check_cldap_reply_required_flags((*info)->flags, flags)) { + if (!check_cldap_reply_required_flags((*info)->dc_flags, flags)) { DEBUG(10,("invalid flags\n")); return NT_STATUS_INVALID_PARAMETER; } if ((flags & DS_IP_REQUIRED) && - ((*info)->domain_controller_address_type != ADS_INET_ADDRESS)) { + ((*info)->dc_address_type != DS_ADDRESS_TYPE_INET)) { return NT_STATUS_INVALID_PARAMETER_MIX; } @@ -459,7 +454,7 @@ static NTSTATUS dsgetdcname_cached(TALLOC_CTX *mem_ctx, struct GUID *domain_guid, uint32_t flags, const char *site_name, - struct DS_DOMAIN_CONTROLLER_INFO **info) + struct netr_DsRGetDCNameInfo **info) { NTSTATUS status; bool expired = false; @@ -663,40 +658,36 @@ static NTSTATUS discover_dc_dns(TALLOC_CTX *mem_ctx, ****************************************************************/ static NTSTATUS make_domain_controller_info(TALLOC_CTX *mem_ctx, - const char *domain_controller_name, - const char *domain_controller_address, - uint32_t domain_controller_address_type, + const char *dc_unc, + const char *dc_address, + uint32_t dc_address_type, const struct GUID *domain_guid, const char *domain_name, - const char *dns_forest_name, + const char *forest_name, uint32_t flags, const char *dc_site_name, const char *client_site_name, - struct DS_DOMAIN_CONTROLLER_INFO **info_out) + struct netr_DsRGetDCNameInfo **info_out) { - struct DS_DOMAIN_CONTROLLER_INFO *info; + struct netr_DsRGetDCNameInfo *info; - info = TALLOC_ZERO_P(mem_ctx, struct DS_DOMAIN_CONTROLLER_INFO); + info = TALLOC_ZERO_P(mem_ctx, struct netr_DsRGetDCNameInfo); NT_STATUS_HAVE_NO_MEMORY(info); - if (domain_controller_name) { - info->domain_controller_name = talloc_strdup(mem_ctx, - domain_controller_name); - NT_STATUS_HAVE_NO_MEMORY(info->domain_controller_name); + if (dc_unc) { + info->dc_unc = talloc_strdup(mem_ctx, dc_unc); + NT_STATUS_HAVE_NO_MEMORY(info->dc_unc); } - if (domain_controller_address) { - info->domain_controller_address = talloc_strdup(mem_ctx, - domain_controller_address); - NT_STATUS_HAVE_NO_MEMORY(info->domain_controller_address); + if (dc_address) { + info->dc_address = talloc_strdup(mem_ctx, dc_address); + NT_STATUS_HAVE_NO_MEMORY(info->dc_address); } - info->domain_controller_address_type = domain_controller_address_type; + info->dc_address_type = dc_address_type; if (domain_guid) { - info->domain_guid = (struct GUID *)talloc_memdup( - mem_ctx, domain_guid, sizeof(*domain_guid)); - NT_STATUS_HAVE_NO_MEMORY(info->domain_guid); + info->domain_guid = *domain_guid; } if (domain_name) { @@ -704,13 +695,12 @@ static NTSTATUS make_domain_controller_info(TALLOC_CTX *mem_ctx, NT_STATUS_HAVE_NO_MEMORY(info->domain_name); } - if (dns_forest_name) { - info->dns_forest_name = talloc_strdup(mem_ctx, - dns_forest_name); - NT_STATUS_HAVE_NO_MEMORY(info->dns_forest_name); + if (forest_name) { + info->forest_name = talloc_strdup(mem_ctx, forest_name); + NT_STATUS_HAVE_NO_MEMORY(info->forest_name); } - info->flags = flags; + info->dc_flags = flags; if (dc_site_name) { info->dc_site_name = talloc_strdup(mem_ctx, dc_site_name); @@ -736,7 +726,7 @@ static NTSTATUS process_dc_dns(TALLOC_CTX *mem_ctx, uint32_t flags, struct ip_service_name **dclist, int num_dcs, - struct DS_DOMAIN_CONTROLLER_INFO **info) + struct netr_DsRGetDCNameInfo **info) { int i = 0; bool valid_dc = false; @@ -779,12 +769,12 @@ static NTSTATUS process_dc_dns(TALLOC_CTX *mem_ctx, } dc_hostname = r.hostname; dc_domain_name = r.domain; - dc_flags |= ADS_DNS_DOMAIN | ADS_DNS_CONTROLLER; + dc_flags |= DS_DNS_DOMAIN | DS_DNS_CONTROLLER; } else { /* FIXME */ dc_hostname = r.hostname; dc_domain_name = r.domain; - dc_flags |= ADS_DNS_DOMAIN | ADS_DNS_CONTROLLER; + dc_flags |= DS_DNS_DOMAIN | DS_DNS_CONTROLLER; } if (flags & DS_IP_REQUIRED) { @@ -792,17 +782,17 @@ static NTSTATUS process_dc_dns(TALLOC_CTX *mem_ctx, print_sockaddr(addr, sizeof(addr), &dclist[i]->ss); dc_address = talloc_asprintf(mem_ctx, "\\\\%s", addr); - dc_address_type = ADS_INET_ADDRESS; + dc_address_type = DS_ADDRESS_TYPE_INET; } else { dc_address = talloc_asprintf(mem_ctx, "\\\\%s", r.netbios_hostname); - dc_address_type = ADS_NETBIOS_ADDRESS; + dc_address_type = DS_ADDRESS_TYPE_NETBIOS; } NT_STATUS_HAVE_NO_MEMORY(dc_address); smb_uuid_unpack(r.guid, &dc_guid); if (r.forest) { - dc_flags |= ADS_DNS_FOREST; + dc_flags |= DS_DNS_FOREST; } return make_domain_controller_info(mem_ctx, @@ -827,7 +817,7 @@ static NTSTATUS process_dc_netbios(TALLOC_CTX *mem_ctx, uint32_t flags, struct ip_service_name **dclist, int num_dcs, - struct DS_DOMAIN_CONTROLLER_INFO **info) + struct netr_DsRGetDCNameInfo **info) { /* FIXME: code here */ @@ -842,7 +832,7 @@ static NTSTATUS dsgetdcname_rediscover(TALLOC_CTX *mem_ctx, struct GUID *domain_guid, uint32_t flags, const char *site_name, - struct DS_DOMAIN_CONTROLLER_INFO **info) + struct netr_DsRGetDCNameInfo **info) { NTSTATUS status = NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND; struct ip_service_name *dclist; @@ -901,10 +891,10 @@ NTSTATUS dsgetdcname(TALLOC_CTX *mem_ctx, struct GUID *domain_guid, const char *site_name, uint32_t flags, - struct DS_DOMAIN_CONTROLLER_INFO **info) + struct netr_DsRGetDCNameInfo **info) { NTSTATUS status = NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND; - struct DS_DOMAIN_CONTROLLER_INFO *myinfo = NULL; + struct netr_DsRGetDCNameInfo *myinfo = NULL; DEBUG(10,("dsgetdcname: domain_name: %s, " "domain_guid: %s, site_name: %s, flags: 0x%08x\n", -- cgit From 4b5169f590425334d9ae3f2b7be2201e2e0b747e Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Tue, 12 Feb 2008 11:54:37 +0100 Subject: Add explicit buf arg to cli_encrypt_message and cli_calculate_sign_mac (This used to be commit db6ae9ed2326e6cd68475375d049084cf1d5a98c) --- source3/libsmb/cliconnect.c | 2 +- source3/libsmb/clientgen.c | 5 +++-- source3/libsmb/smb_seal.c | 6 +++--- source3/libsmb/smb_signing.c | 4 ++-- 4 files changed, 9 insertions(+), 8 deletions(-) (limited to 'source3/libsmb') diff --git a/source3/libsmb/cliconnect.c b/source3/libsmb/cliconnect.c index d88a5d6242..9c27d30166 100644 --- a/source3/libsmb/cliconnect.c +++ b/source3/libsmb/cliconnect.c @@ -757,7 +757,7 @@ static NTSTATUS cli_session_setup_ntlmssp(struct cli_state *cli, const char *use /* 'resign' the last message, so we get the right sequence numbers for checking the first reply from the server */ - cli_calculate_sign_mac(cli); + cli_calculate_sign_mac(cli, cli->outbuf); if (!cli_check_sign_mac(cli)) { nt_status = NT_STATUS_ACCESS_DENIED; diff --git a/source3/libsmb/clientgen.c b/source3/libsmb/clientgen.c index 3b7669f33e..2fd304f135 100644 --- a/source3/libsmb/clientgen.c +++ b/source3/libsmb/clientgen.c @@ -343,10 +343,11 @@ bool cli_send_smb(struct cli_state *cli) if (cli->fd == -1) return false; - cli_calculate_sign_mac(cli); + cli_calculate_sign_mac(cli, cli->outbuf); if (enc_on) { - NTSTATUS status = cli_encrypt_message(cli, &buf_out); + NTSTATUS status = cli_encrypt_message(cli, cli->outbuf, + &buf_out); if (!NT_STATUS_IS_OK(status)) { close(cli->fd); cli->fd = -1; diff --git a/source3/libsmb/smb_seal.c b/source3/libsmb/smb_seal.c index b5befbf7cd..a81ae9afd5 100644 --- a/source3/libsmb/smb_seal.c +++ b/source3/libsmb/smb_seal.c @@ -483,15 +483,15 @@ NTSTATUS cli_decrypt_message(struct cli_state *cli) Encrypt an outgoing buffer. Return the encrypted pointer in buf_out. ******************************************************************************/ -NTSTATUS cli_encrypt_message(struct cli_state *cli, char **buf_out) +NTSTATUS cli_encrypt_message(struct cli_state *cli, char *buf, char **buf_out) { /* Ignore non-session messages. */ - if(CVAL(cli->outbuf,0)) { + if (CVAL(buf,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); + return common_encrypt_buffer(cli->trans_enc_state, buf, buf_out); } diff --git a/source3/libsmb/smb_signing.c b/source3/libsmb/smb_signing.c index f03c21bd0e..eeaf28c3d1 100644 --- a/source3/libsmb/smb_signing.c +++ b/source3/libsmb/smb_signing.c @@ -573,9 +573,9 @@ void cli_free_signing_context(struct cli_state *cli) * Sign a packet with the current mechanism */ -void cli_calculate_sign_mac(struct cli_state *cli) +void cli_calculate_sign_mac(struct cli_state *cli, char *buf) { - cli->sign_info.sign_outgoing_message(cli->outbuf, &cli->sign_info); + cli->sign_info.sign_outgoing_message(buf, &cli->sign_info); } /** -- cgit From b9f7dd2909487f8e306774ee0475f8b20331a866 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Tue, 12 Feb 2008 23:16:37 +0100 Subject: Add explicit buf arg to cli_check_sign_mac (This used to be commit ffc1c8cc03e6bad40ed2be91392074b4f038a1bf) --- source3/libsmb/cliconnect.c | 2 +- source3/libsmb/clientgen.c | 2 +- source3/libsmb/smb_signing.c | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) (limited to 'source3/libsmb') diff --git a/source3/libsmb/cliconnect.c b/source3/libsmb/cliconnect.c index 9c27d30166..912b841d5e 100644 --- a/source3/libsmb/cliconnect.c +++ b/source3/libsmb/cliconnect.c @@ -759,7 +759,7 @@ static NTSTATUS cli_session_setup_ntlmssp(struct cli_state *cli, const char *use for checking the first reply from the server */ cli_calculate_sign_mac(cli, cli->outbuf); - if (!cli_check_sign_mac(cli)) { + if (!cli_check_sign_mac(cli, cli->inbuf)) { nt_status = NT_STATUS_ACCESS_DENIED; } } diff --git a/source3/libsmb/clientgen.c b/source3/libsmb/clientgen.c index 2fd304f135..ccd1cc67d5 100644 --- a/source3/libsmb/clientgen.c +++ b/source3/libsmb/clientgen.c @@ -164,7 +164,7 @@ bool cli_receive_smb(struct cli_state *cli) return false; } - if (!cli_check_sign_mac(cli)) { + if (!cli_check_sign_mac(cli, cli->inbuf)) { /* * If we get a signature failure in sessionsetup, then * the server sometimes just reflects the sent signature diff --git a/source3/libsmb/smb_signing.c b/source3/libsmb/smb_signing.c index eeaf28c3d1..bd6d97123d 100644 --- a/source3/libsmb/smb_signing.c +++ b/source3/libsmb/smb_signing.c @@ -584,9 +584,9 @@ void cli_calculate_sign_mac(struct cli_state *cli, char *buf) * which had a bad checksum, True otherwise. */ -bool cli_check_sign_mac(struct cli_state *cli) +bool cli_check_sign_mac(struct cli_state *cli, char *buf) { - if (!cli->sign_info.check_incoming_message(cli->inbuf, &cli->sign_info, True)) { + if (!cli->sign_info.check_incoming_message(buf, &cli->sign_info, True)) { free_signing_context(&cli->sign_info); return False; } -- cgit From 11b81cb8e419315abc8bf2d7b1a93424aa9788e9 Mon Sep 17 00:00:00 2001 From: Günther Deschner Date: Thu, 28 Feb 2008 13:58:34 +0100 Subject: Add WERR_TIME_SKEW to werror mapping tables. Guenther (This used to be commit 74767be627d48eb1a8deea3784847159b536a0fb) --- source3/libsmb/doserr.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'source3/libsmb') diff --git a/source3/libsmb/doserr.c b/source3/libsmb/doserr.c index a3043a2152..203f682599 100644 --- a/source3/libsmb/doserr.c +++ b/source3/libsmb/doserr.c @@ -84,6 +84,7 @@ werror_code_struct dos_errs[] = { "WERR_LOGON_FAILURE", WERR_LOGON_FAILURE }, { "WERR_NO_SUCH_DOMAIN", WERR_NO_SUCH_DOMAIN }, { "WERR_INVALID_SECURITY_DESCRIPTOR", WERR_INVALID_SECURITY_DESCRIPTOR }, + { "WERR_TIME_SKEW", WERR_TIME_SKEW }, { "WERR_INVALID_OWNER", WERR_INVALID_OWNER }, { "WERR_SERVER_UNAVAILABLE", WERR_SERVER_UNAVAILABLE }, { "WERR_IO_PENDING", WERR_IO_PENDING }, @@ -121,6 +122,7 @@ werror_str_struct dos_err_strs[] = { { WERR_USER_EXISTS, "User account already exists" }, { WERR_PASSWORD_MUST_CHANGE, "The password must be changed" }, { WERR_ACCOUNT_LOCKED_OUT, "Account locked out" }, + { WERR_TIME_SKEW, "Time difference between client and server" }, }; /***************************************************************************** -- cgit From 57a9fba097a5f5af7833eaf4355667dbfacaec43 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Thu, 28 Feb 2008 14:03:38 +0100 Subject: Make cli_struct a talloc parent (This used to be commit e69244a5c8c7c6b7c1897adc4b4b1cfdfc7a7999) --- source3/libsmb/clientgen.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'source3/libsmb') diff --git a/source3/libsmb/clientgen.c b/source3/libsmb/clientgen.c index ccd1cc67d5..592f050e90 100644 --- a/source3/libsmb/clientgen.c +++ b/source3/libsmb/clientgen.c @@ -537,7 +537,7 @@ struct cli_state *cli_initialise(void) return NULL; } - cli = SMB_MALLOC_P(struct cli_state); + cli = talloc(NULL, struct cli_state); if (!cli) { return NULL; } @@ -695,7 +695,7 @@ void cli_shutdown(struct cli_state *cli) cli->fd = -1; cli->smb_rw_error = SMB_READ_OK; - SAFE_FREE(cli); + TALLOC_FREE(cli); } /**************************************************************************** -- cgit From be4a76a861f3a152f1d1aebf937b06e1628f2d55 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Thu, 28 Feb 2008 14:04:54 +0100 Subject: Add cli_setup_packet_buf This is == cli_setup_packet but takes an explicit buffer argument (This used to be commit f64b46dc278899c3449cfd3dbb614aadcf5614d3) --- source3/libsmb/clientgen.c | 54 +++++++++++++++++++++++++++------------------- 1 file changed, 32 insertions(+), 22 deletions(-) (limited to 'source3/libsmb') diff --git a/source3/libsmb/clientgen.c b/source3/libsmb/clientgen.c index 592f050e90..64191239d3 100644 --- a/source3/libsmb/clientgen.c +++ b/source3/libsmb/clientgen.c @@ -450,31 +450,41 @@ bool cli_send_smb_direct_writeX(struct cli_state *cli, Setup basics in a outgoing packet. ****************************************************************************/ -void cli_setup_packet(struct cli_state *cli) +void cli_setup_packet_buf(struct cli_state *cli, char *buf) { + uint16 flags2; cli->rap_error = 0; - SSVAL(cli->outbuf,smb_pid,cli->pid); - SSVAL(cli->outbuf,smb_uid,cli->vuid); - SSVAL(cli->outbuf,smb_mid,cli->mid); - if (cli->protocol > PROTOCOL_CORE) { - uint16 flags2; - if (cli->case_sensitive) { - SCVAL(cli->outbuf,smb_flg,0x0); - } else { - /* Default setting, case insensitive. */ - SCVAL(cli->outbuf,smb_flg,0x8); - } - flags2 = FLAGS2_LONG_PATH_COMPONENTS; - if (cli->capabilities & CAP_UNICODE) - flags2 |= FLAGS2_UNICODE_STRINGS; - if ((cli->capabilities & CAP_DFS) && cli->dfsroot) - flags2 |= FLAGS2_DFS_PATHNAMES; - if (cli->capabilities & CAP_STATUS32) - flags2 |= FLAGS2_32_BIT_ERROR_CODES; - if (cli->use_spnego) - flags2 |= FLAGS2_EXTENDED_SECURITY; - SSVAL(cli->outbuf,smb_flg2, flags2); + SIVAL(buf,smb_rcls,0); + SSVAL(buf,smb_pid,cli->pid); + memset(buf+smb_pidhigh, 0, 12); + SSVAL(buf,smb_uid,cli->vuid); + SSVAL(buf,smb_mid,cli->mid); + + if (cli->protocol <= PROTOCOL_CORE) { + return; + } + + if (cli->case_sensitive) { + SCVAL(buf,smb_flg,0x0); + } else { + /* Default setting, case insensitive. */ + SCVAL(buf,smb_flg,0x8); } + flags2 = FLAGS2_LONG_PATH_COMPONENTS; + if (cli->capabilities & CAP_UNICODE) + flags2 |= FLAGS2_UNICODE_STRINGS; + if ((cli->capabilities & CAP_DFS) && cli->dfsroot) + flags2 |= FLAGS2_DFS_PATHNAMES; + if (cli->capabilities & CAP_STATUS32) + flags2 |= FLAGS2_32_BIT_ERROR_CODES; + if (cli->use_spnego) + flags2 |= FLAGS2_EXTENDED_SECURITY; + SSVAL(buf,smb_flg2, flags2); +} + +void cli_setup_packet(struct cli_state *cli) +{ + cli_setup_packet_buf(cli, cli->outbuf); } /**************************************************************************** -- cgit From 6e2e0e2ce7ebef473cf8f8787363500eb090d692 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Thu, 28 Feb 2008 06:01:09 -0800 Subject: Fix the build - don't use SMB_TRANS_ENC_GSS without KRB5. Jeremy. (This used to be commit d16c295642c3df49be02440427ded0cd9b4179f5) --- source3/libsmb/clifsinfo.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) (limited to 'source3/libsmb') diff --git a/source3/libsmb/clifsinfo.c b/source3/libsmb/clifsinfo.c index f4945f812a..0005c3908a 100644 --- a/source3/libsmb/clifsinfo.c +++ b/source3/libsmb/clifsinfo.c @@ -368,20 +368,16 @@ static struct smb_trans_enc_state *make_cli_enc_state(enum smb_trans_enc_type sm 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) + if (smb_enc_type == SMB_TRANS_ENC_GSS) { 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 } +#endif return es; } -- cgit From 1d41b5bd2a58dcc6966a3a49ccb063ff05e46125 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Thu, 28 Feb 2008 14:41:25 +0100 Subject: Add infrastructure to support async SMB requests (This used to be commit f5356825698a02df2d400b51dd95d1f857c83e81) --- source3/libsmb/async_smb.c | 483 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 483 insertions(+) create mode 100644 source3/libsmb/async_smb.c (limited to 'source3/libsmb') diff --git a/source3/libsmb/async_smb.c b/source3/libsmb/async_smb.c new file mode 100644 index 0000000000..21bcd5b9b1 --- /dev/null +++ b/source3/libsmb/async_smb.c @@ -0,0 +1,483 @@ +/* + Unix SMB/CIFS implementation. + Infrastructure for async SMB client requests + Copyright (C) Volker Lendecke 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 + 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 . +*/ + +#include "includes.h" + +/* + * Fetch an error out of a NBT packet + */ + +NTSTATUS cli_pull_error(char *buf) +{ + uint32_t flags2 = SVAL(buf, smb_flg2); + + if (flags2 & FLAGS2_32_BIT_ERROR_CODES) { + return NT_STATUS(IVAL(buf, smb_rcls)); + } + + return NT_STATUS_DOS(CVAL(buf, smb_rcls), SVAL(buf,smb_err)); +} + +/* + * Compatibility helper for the sync APIs: Fake NTSTATUS in cli->inbuf + */ + +void cli_set_error(struct cli_state *cli, NTSTATUS status) +{ + uint32_t flags2 = SVAL(cli->inbuf, smb_flg2); + + if (NT_STATUS_IS_DOS(status)) { + SSVAL(cli->inbuf, smb_flg2, + flags2 & ~FLAGS2_32_BIT_ERROR_CODES); + SCVAL(cli->inbuf, smb_rcls, NT_STATUS_DOS_CLASS(status)); + SSVAL(cli->inbuf, smb_err, NT_STATUS_DOS_CODE(status)); + return; + } + + SSVAL(cli->inbuf, smb_flg2, flags2 | FLAGS2_32_BIT_ERROR_CODES); + SIVAL(cli->inbuf, smb_rcls, NT_STATUS_V(status)); + return; +} + +/* + * Allocate a new mid + */ + +static uint16_t cli_new_mid(struct cli_state *cli) +{ + uint16_t result; + struct cli_request *req; + + while (true) { + result = cli->mid++; + if (result == 0) { + continue; + } + + for (req = cli->outstanding_requests; req; req = req->next) { + if (result == req->mid) { + break; + } + } + + if (req == NULL) { + return result; + } + } +} + +static char *cli_request_print(TALLOC_CTX *mem_ctx, struct async_req *req) +{ + char *result = async_req_print(mem_ctx, req); + struct cli_request *cli_req = cli_request_get(req); + + if (result == NULL) { + return NULL; + } + + return talloc_asprintf_append_buffer( + result, "mid=%d\n", cli_req->mid); +} + +static int cli_request_destructor(struct cli_request *req) +{ + if (req->enc_state != NULL) { + common_free_enc_buffer(req->enc_state, req->outbuf); + } + DLIST_REMOVE(req->cli->outstanding_requests, req); + return 0; +} + +/* + * Create a fresh async smb request + */ + +struct async_req *cli_request_new(TALLOC_CTX *mem_ctx, + struct event_context *ev, + struct cli_state *cli, + uint8_t num_words, size_t num_bytes, + struct cli_request **preq) +{ + struct async_req *result; + struct cli_request *cli_req; + size_t bufsize = smb_size + num_words * 2 + num_bytes; + + result = async_req_new(mem_ctx, ev); + if (result == NULL) { + return NULL; + } + + cli_req = (struct cli_request *)talloc_size( + result, sizeof(*cli_req) + bufsize); + if (cli_req == NULL) { + TALLOC_FREE(result); + return NULL; + } + talloc_set_name_const(cli_req, "struct cli_request"); + result->private_data = cli_req; + result->print = cli_request_print; + + cli_req->async = result; + cli_req->cli = cli; + cli_req->outbuf = ((char *)cli_req + sizeof(*cli_req)); + cli_req->sent = 0; + cli_req->mid = cli_new_mid(cli); + cli_req->inbuf = NULL; + cli_req->enc_state = NULL; + + SCVAL(cli_req->outbuf, smb_wct, num_words); + SSVAL(cli_req->outbuf, smb_vwv + num_words * 2, num_bytes); + + DLIST_ADD_END(cli->outstanding_requests, cli_req, + struct cli_request *); + talloc_set_destructor(cli_req, cli_request_destructor); + + DEBUG(10, ("cli_request_new: mid=%d\n", cli_req->mid)); + + *preq = cli_req; + return result; +} + +/* + * Convenience function to get the SMB part out of an async_req + */ + +struct cli_request *cli_request_get(struct async_req *req) +{ + if (req == NULL) { + return NULL; + } + return talloc_get_type_abort(req->private_data, struct cli_request); +} + +/* + * A PDU has arrived on cli->evt_inbuf + */ + +static void handle_incoming_pdu(struct cli_state *cli) +{ + struct cli_request *req; + uint16_t mid; + size_t raw_pdu_len, buf_len, pdu_len; + size_t rest_len; + NTSTATUS status; + + /* + * The encrypted PDU len might differ from the unencrypted one + */ + raw_pdu_len = smb_len(cli->evt_inbuf) + 4; + + /* + * TODO: Handle oplock break requests + */ + + if (cli_encryption_on(cli) && CVAL(cli->evt_inbuf, 0) == 0) { + uint16_t enc_ctx_num; + + status = get_enc_ctx_num((uint8_t *)cli->evt_inbuf, + &enc_ctx_num); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(10, ("get_enc_ctx_num returned %s\n", + nt_errstr(status))); + goto invalidate_requests; + } + + if (enc_ctx_num != cli->trans_enc_state->enc_ctx_num) { + DEBUG(10, ("wrong enc_ctx %d, expected %d\n", + enc_ctx_num, + cli->trans_enc_state->enc_ctx_num)); + status = NT_STATUS_INVALID_HANDLE; + goto invalidate_requests; + } + + status = common_decrypt_buffer(cli->trans_enc_state, + cli->evt_inbuf); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(10, ("common_decrypt_buffer returned %s\n", + nt_errstr(status))); + goto invalidate_requests; + } + } + + if (!cli_check_sign_mac(cli, cli->evt_inbuf)) { + DEBUG(10, ("cli_check_sign_mac failed\n")); + status = NT_STATUS_ACCESS_DENIED; + goto invalidate_requests; + } + + mid = SVAL(cli->evt_inbuf, smb_mid); + + DEBUG(10, ("handle_incoming_pdu: got mid %d\n", mid)); + + for (req = cli->outstanding_requests; req; req = req->next) { + if (req->mid == mid) { + break; + } + } + + buf_len = talloc_get_size(cli->evt_inbuf); + pdu_len = smb_len(cli->evt_inbuf) + 4; + rest_len = buf_len - raw_pdu_len; + + if (req == NULL) { + DEBUG(3, ("Request for mid %d not found, dumping PDU\n", mid)); + + memmove(cli->evt_inbuf, cli->evt_inbuf + raw_pdu_len, + buf_len - raw_pdu_len); + + cli->evt_inbuf = TALLOC_REALLOC_ARRAY(NULL, cli->evt_inbuf, + char, rest_len); + return; + } + + if (buf_len == pdu_len) { + /* + * Optimal case: Exactly one PDU was in the socket buffer + */ + req->inbuf = talloc_move(req, &cli->evt_inbuf); + goto done; + } + + DEBUG(11, ("buf_len = %d, pdu_len = %d, splitting buffer\n", + (int)buf_len, (int)pdu_len)); + + if (pdu_len < rest_len) { + /* + * The PDU is shorter, talloc_memdup that one. + */ + req->inbuf = (char *)talloc_memdup( + req, cli->evt_inbuf, pdu_len); + + memmove(cli->evt_inbuf, + cli->evt_inbuf + raw_pdu_len, + buf_len - raw_pdu_len); + + cli->evt_inbuf = TALLOC_REALLOC_ARRAY( + NULL, cli->evt_inbuf, char, rest_len); + } + else { + /* + * The PDU is larger than the rest, + * talloc_memdup the rest + */ + req->inbuf = talloc_move(req, &cli->evt_inbuf); + + cli->evt_inbuf = (char *)talloc_memdup( + cli, req->inbuf + raw_pdu_len, + rest_len); + } + + if ((req->inbuf == NULL) || (cli->evt_inbuf == NULL)) { + status = NT_STATUS_NO_MEMORY; + goto invalidate_requests; + } + + done: + async_req_done(req->async); + return; + + invalidate_requests: + + DEBUG(10, ("handle_incoming_pdu: Aborting with %s\n", + nt_errstr(status))); + + for (req = cli->outstanding_requests; req; req = req->next) { + async_req_error(req->async, status); + } + return; +} + +/* + * fd event callback. This is the basic connection to the socket + */ + +static void cli_state_handler(struct event_context *event_ctx, + struct fd_event *event, uint16 flags, void *p) +{ + struct cli_state *cli = (struct cli_state *)p; + struct cli_request *req; + + DEBUG(11, ("cli_state_handler called with flags %d\n", flags)); + + if (flags & EVENT_FD_READ) { + int res, available; + size_t old_size, new_size; + char *tmp; + + res = ioctl(cli->fd, FIONREAD, &available); + if (res == -1) { + DEBUG(10, ("ioctl(FIONREAD) failed: %s\n", + strerror(errno))); + goto sock_error; + } + + if (available == 0) { + /* EOF */ + goto sock_error; + } + + old_size = talloc_get_size(cli->evt_inbuf); + new_size = old_size + available; + + if (new_size < old_size) { + /* wrap */ + goto sock_error; + } + + tmp = TALLOC_REALLOC_ARRAY(cli, cli->evt_inbuf, char, + new_size); + if (tmp == NULL) { + /* nomem */ + goto sock_error; + } + cli->evt_inbuf = tmp; + + res = recv(cli->fd, cli->evt_inbuf + old_size, available, 0); + if (res == -1) { + DEBUG(10, ("recv failed: %s\n", strerror(errno))); + goto sock_error; + } + + DEBUG(11, ("cli_state_handler: received %d bytes, " + "smb_len(evt_inbuf) = %d\n", (int)res, + smb_len(cli->evt_inbuf))); + + /* recv *might* have returned less than announced */ + new_size = old_size + res; + + /* shrink, so I don't expect errors here */ + cli->evt_inbuf = TALLOC_REALLOC_ARRAY(cli, cli->evt_inbuf, + char, new_size); + + while ((cli->evt_inbuf != NULL) + && ((smb_len(cli->evt_inbuf) + 4) <= new_size)) { + /* + * we've got a complete NBT level PDU in evt_inbuf + */ + handle_incoming_pdu(cli); + new_size = talloc_get_size(cli->evt_inbuf); + } + } + + if (flags & EVENT_FD_WRITE) { + size_t to_send; + ssize_t sent; + + for (req = cli->outstanding_requests; req; req = req->next) { + to_send = smb_len(req->outbuf)+4; + if (to_send > req->sent) { + break; + } + } + + if (req == NULL) { + event_fd_set_not_writeable(event); + return; + } + + sent = send(cli->fd, req->outbuf + req->sent, + to_send - req->sent, 0); + + if (sent < 0) { + goto sock_error; + } + + req->sent += sent; + + if (req->sent == to_send) { + return; + } + } + return; + + sock_error: + for (req = cli->outstanding_requests; req; req = req->next) { + req->async->state = ASYNC_REQ_ERROR; + req->async->status = map_nt_error_from_unix(errno); + } + TALLOC_FREE(cli->fd_event); + close(cli->fd); + cli->fd = -1; +} + +/* + * Holder for a talloc_destructor, we need to zero out the pointers in cli + * when deleting + */ +struct cli_tmp_event { + struct cli_state *cli; +}; + +static int cli_tmp_event_destructor(struct cli_tmp_event *e) +{ + TALLOC_FREE(e->cli->fd_event); + TALLOC_FREE(e->cli->event_ctx); + return 0; +} + +/* + * Create a temporary event context for use in the sync helper functions + */ + +struct cli_tmp_event *cli_tmp_event_ctx(TALLOC_CTX *mem_ctx, + struct cli_state *cli) +{ + struct cli_tmp_event *state; + + if (cli->event_ctx != NULL) { + return NULL; + } + + state = talloc(mem_ctx, struct cli_tmp_event); + if (state == NULL) { + return NULL; + } + state->cli = cli; + talloc_set_destructor(state, cli_tmp_event_destructor); + + cli->event_ctx = event_context_init(state); + if (cli->event_ctx == NULL) { + TALLOC_FREE(state); + return NULL; + } + + cli->fd_event = event_add_fd(cli->event_ctx, state, cli->fd, + EVENT_FD_READ, cli_state_handler, cli); + if (cli->fd_event == NULL) { + TALLOC_FREE(state); + return NULL; + } + return state; +} + +/* + * Attach an event context permanently to a cli_struct + */ + +NTSTATUS cli_add_event_ctx(struct cli_state *cli, + struct event_context *event_ctx) +{ + cli->event_ctx = event_ctx; + cli->fd_event = event_add_fd(event_ctx, cli, cli->fd, EVENT_FD_READ, + cli_state_handler, cli); + if (cli->fd_event == NULL) { + return NT_STATUS_NO_MEMORY; + } + return NT_STATUS_OK; +} -- cgit From 525aac775ecef275dbd0732830a9bac0fd023135 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Thu, 28 Feb 2008 15:21:33 +0100 Subject: Add async cli_pull support This is the big (and potentially controversial) one. It took a phone call to explain to metze what is going on inside cli_pull_read_done, but I would really like everybody to understand this function. It is a very good and reasonably complex example of async programming. If we want more asynchronism in s3, this is what we will have to deal with :-) Make use of it in the smbclient "get" command. Volker (This used to be commit 844a163458c7585e4306a21ffdae5d08e03d6e4d) --- source3/libsmb/clireadwrite.c | 425 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 425 insertions(+) (limited to 'source3/libsmb') diff --git a/source3/libsmb/clireadwrite.c b/source3/libsmb/clireadwrite.c index af13ed8f73..5aee8f18bd 100644 --- a/source3/libsmb/clireadwrite.c +++ b/source3/libsmb/clireadwrite.c @@ -19,6 +19,431 @@ #include "includes.h" +/**************************************************************************** + Calculate the recommended read buffer size +****************************************************************************/ +static size_t cli_read_max_bufsize(struct cli_state *cli) +{ + if (!client_is_signing_on(cli) && !cli_encryption_on(cli) == false + && (cli->posix_capabilities & CIFS_UNIX_LARGE_READ_CAP)) { + return CLI_SAMBA_MAX_POSIX_LARGE_READX_SIZE; + } + if (cli->capabilities & CAP_LARGE_READX) { + return cli->is_samba + ? CLI_SAMBA_MAX_LARGE_READX_SIZE + : CLI_WINDOWS_MAX_LARGE_READX_SIZE; + } + return (cli->max_xmit - (smb_size+32)) & ~1023; +} + +/* + * Send a read&x request + */ + +struct async_req *cli_read_andx_send(TALLOC_CTX *mem_ctx, + struct cli_state *cli, int fnum, + off_t offset, size_t size) +{ + struct async_req *result; + struct cli_request *req; + bool bigoffset = False; + char *enc_buf; + + if (size > cli_read_max_bufsize(cli)) { + DEBUG(0, ("cli_read_andx_send got size=%d, can only handle " + "size=%d\n", (int)size, + (int)cli_read_max_bufsize(cli))); + return NULL; + } + + result = cli_request_new(mem_ctx, cli->event_ctx, cli, 12, 0, &req); + if (result == NULL) { + DEBUG(0, ("cli_request_new failed\n")); + return NULL; + } + + req = cli_request_get(result); + + req->data.read.ofs = offset; + req->data.read.size = size; + req->data.read.received = 0; + req->data.read.rcvbuf = NULL; + + if ((SMB_BIG_UINT)offset >> 32) + bigoffset = True; + + cli_set_message(req->outbuf, bigoffset ? 12 : 10, 0, False); + + SCVAL(req->outbuf,smb_com,SMBreadX); + SSVAL(req->outbuf,smb_tid,cli->cnum); + cli_setup_packet_buf(cli, req->outbuf); + + SCVAL(req->outbuf,smb_vwv0,0xFF); + SCVAL(req->outbuf,smb_vwv0+1,0); + SSVAL(req->outbuf,smb_vwv1,0); + SSVAL(req->outbuf,smb_vwv2,fnum); + SIVAL(req->outbuf,smb_vwv3,offset); + SSVAL(req->outbuf,smb_vwv5,size); + SSVAL(req->outbuf,smb_vwv6,size); + SSVAL(req->outbuf,smb_vwv7,(size >> 16)); + SSVAL(req->outbuf,smb_vwv8,0); + SSVAL(req->outbuf,smb_vwv9,0); + SSVAL(req->outbuf,smb_mid,req->mid); + + if (bigoffset) { + SIVAL(req->outbuf, smb_vwv10, + (((SMB_BIG_UINT)offset)>>32) & 0xffffffff); + } + + cli_calculate_sign_mac(cli, req->outbuf); + + event_fd_set_writeable(cli->fd_event); + + if (cli_encryption_on(cli)) { + NTSTATUS status; + status = cli_encrypt_message(cli, req->outbuf, &enc_buf); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0, ("Error in encrypting client message. " + "Error %s\n", nt_errstr(status))); + TALLOC_FREE(req); + return NULL; + } + req->outbuf = enc_buf; + req->enc_state = cli->trans_enc_state; + } + + return result; +} + +/* + * Pull the data out of a finished async read_and_x request. rcvbuf is + * talloced from the request, so better make sure that you copy it away before + * you talloc_free(req). "rcvbuf" is NOT a talloc_ctx of its own, so do not + * talloc_move it! + */ + +NTSTATUS cli_read_andx_recv(struct async_req *req, ssize_t *received, + uint8_t **rcvbuf) +{ + struct cli_request *cli_req = cli_request_get(req); + NTSTATUS status; + size_t size; + + SMB_ASSERT(req->state >= ASYNC_REQ_DONE); + if (req->state == ASYNC_REQ_ERROR) { + return req->status; + } + + status = cli_pull_error(cli_req->inbuf); + + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + /* size is the number of bytes the server returned. + * Might be zero. */ + size = SVAL(cli_req->inbuf, smb_vwv5); + size |= (((unsigned int)(SVAL(cli_req->inbuf, smb_vwv7))) << 16); + + if (size > cli_req->data.read.size) { + DEBUG(5,("server returned more than we wanted!\n")); + return NT_STATUS_UNEXPECTED_IO_ERROR; + } + + if (size < 0) { + DEBUG(5,("read return < 0!\n")); + return NT_STATUS_UNEXPECTED_IO_ERROR; + } + + *rcvbuf = (uint8_t *) + (smb_base(cli_req->inbuf) + SVAL(cli_req->inbuf, smb_vwv6)); + *received = size; + return NT_STATUS_OK; +} + +/* + * Parallel read support. + * + * cli_pull sends as many read&x requests as the server would allow via + * max_mux at a time. When replies flow back in, the data is written into + * the callback function "sink" in the right order. + */ + +struct cli_pull_state { + struct async_req *req; + + struct cli_state *cli; + uint16_t fnum; + off_t start_offset; + size_t size; + + NTSTATUS (*sink)(char *buf, size_t n, void *priv); + void *priv; + + size_t chunk_size; + + /* + * Outstanding requests + */ + int num_reqs; + struct async_req **reqs; + + /* + * For how many bytes did we send requests already? + */ + off_t requested; + + /* + * Next request index to push into "sink". This walks around the "req" + * array, taking care that the requests are pushed to "sink" in the + * right order. If necessary (i.e. replies don't come in in the right + * order), replies are held back in "reqs". + */ + int top_req; + + /* + * How many bytes did we push into "sink"? + */ + + off_t pushed; +}; + +static char *cli_pull_print(TALLOC_CTX *mem_ctx, struct async_req *req) +{ + struct cli_pull_state *state = talloc_get_type_abort( + req->private_data, struct cli_pull_state); + char *result; + + result = async_req_print(mem_ctx, req); + if (result == NULL) { + return NULL; + } + + return talloc_asprintf_append_buffer( + result, "num_reqs=%d, top_req=%d", + state->num_reqs, state->top_req); +} + +static void cli_pull_read_done(struct async_req *read_req); + +/* + * Prepare an async pull request + */ + +struct async_req *cli_pull_send(TALLOC_CTX *mem_ctx, struct cli_state *cli, + uint16_t fnum, off_t start_offset, + size_t size, size_t window_size, + NTSTATUS (*sink)(char *buf, size_t n, + void *priv), + void *priv) +{ + struct async_req *result; + struct cli_pull_state *state; + int i; + + result = async_req_new(mem_ctx, cli->event_ctx); + if (result == NULL) { + goto failed; + } + state = talloc(result, struct cli_pull_state); + if (state == NULL) { + goto failed; + } + result->private_data = state; + result->print = cli_pull_print; + state->req = result; + + state->cli = cli; + state->fnum = fnum; + state->start_offset = start_offset; + state->size = size; + state->sink = sink; + state->priv = priv; + + state->pushed = 0; + state->top_req = 0; + state->chunk_size = cli_read_max_bufsize(cli); + + state->num_reqs = MAX(window_size/state->chunk_size, 1); + state->num_reqs = MIN(state->num_reqs, cli->max_mux); + + state->reqs = TALLOC_ZERO_ARRAY(state, struct async_req *, + state->num_reqs); + if (state->reqs == NULL) { + goto failed; + } + + state->requested = 0; + + for (i=0; inum_reqs; i++) { + size_t size_left, request_thistime; + + if (state->requested >= size) { + state->num_reqs = i; + break; + } + + size_left = size - state->requested; + request_thistime = MIN(size_left, state->chunk_size); + + state->reqs[i] = cli_read_andx_send( + state->reqs, cli, fnum, + state->start_offset + state->requested, + request_thistime); + + if (state->reqs[i] == NULL) { + goto failed; + } + + state->reqs[i]->async.fn = cli_pull_read_done; + state->reqs[i]->async.priv = result; + + state->requested += request_thistime; + } + return result; + +failed: + TALLOC_FREE(result); + return NULL; +} + +/* + * Handle incoming read replies, push the data into sink and send out new + * requests if necessary. + */ + +static void cli_pull_read_done(struct async_req *read_req) +{ + struct async_req *pull_req = talloc_get_type_abort( + read_req->async.priv, struct async_req); + struct cli_pull_state *state = talloc_get_type_abort( + pull_req->private_data, struct cli_pull_state); + struct cli_request *read_state = cli_request_get(read_req); + NTSTATUS status; + + status = cli_read_andx_recv(read_req, &read_state->data.read.received, + &read_state->data.read.rcvbuf); + if (!NT_STATUS_IS_OK(status)) { + async_req_error(state->req, status); + return; + } + + /* + * This loop is the one to take care of out-of-order replies. All + * pending requests are in state->reqs, state->reqs[top_req] is the + * one that is to be pushed next. If however a request later than + * top_req is replied to, then we can't push yet. If top_req is + * replied to at a later point then, we need to push all the finished + * requests. + */ + + while (state->reqs[state->top_req] != NULL) { + struct cli_request *top_read; + + DEBUG(11, ("cli_pull_read_done: top_req = %d\n", + state->top_req)); + + if (state->reqs[state->top_req]->state < ASYNC_REQ_DONE) { + DEBUG(11, ("cli_pull_read_done: top request not yet " + "done\n")); + return; + } + + top_read = cli_request_get(state->reqs[state->top_req]); + + DEBUG(10, ("cli_pull_read_done: Pushing %d bytes, %d already " + "pushed\n", (int)top_read->data.read.received, + (int)state->pushed)); + + status = state->sink((char *)top_read->data.read.rcvbuf, + top_read->data.read.received, + state->priv); + if (!NT_STATUS_IS_OK(status)) { + async_req_error(state->req, status); + return; + } + state->pushed += top_read->data.read.received; + + TALLOC_FREE(state->reqs[state->top_req]); + + if (state->requested < state->size) { + struct async_req *new_req; + size_t size_left, request_thistime; + + size_left = state->size - state->requested; + request_thistime = MIN(size_left, state->chunk_size); + + DEBUG(10, ("cli_pull_read_done: Requesting %d bytes " + "at %d, position %d\n", + (int)request_thistime, + (int)(state->start_offset + + state->requested), + state->top_req)); + + new_req = cli_read_andx_send( + state->reqs, state->cli, state->fnum, + state->start_offset + state->requested, + request_thistime); + + if (async_req_nomem(new_req, state->req)) { + return; + } + + new_req->async.fn = cli_pull_read_done; + new_req->async.priv = pull_req; + + state->reqs[state->top_req] = new_req; + state->requested += request_thistime; + } + + state->top_req = (state->top_req+1) % state->num_reqs; + } + + async_req_done(pull_req); +} + +NTSTATUS cli_pull_recv(struct async_req *req, ssize_t *received) +{ + struct cli_pull_state *state = talloc_get_type_abort( + req->private_data, struct cli_pull_state); + + SMB_ASSERT(req->state >= ASYNC_REQ_DONE); + if (req->state == ASYNC_REQ_ERROR) { + return req->status; + } + *received = state->pushed; + return NT_STATUS_OK; +} + +NTSTATUS cli_pull(struct cli_state *cli, uint16_t fnum, + off_t start_offset, size_t size, size_t window_size, + NTSTATUS (*sink)(char *buf, size_t n, void *priv), + void *priv, ssize_t *received) +{ + TALLOC_CTX *frame = talloc_stackframe(); + struct async_req *req; + NTSTATUS result = NT_STATUS_NO_MEMORY; + + if (cli_tmp_event_ctx(frame, cli) == NULL) { + goto nomem; + } + + req = cli_pull_send(frame, cli, fnum, start_offset, size, window_size, + sink, priv); + if (req == NULL) { + goto nomem; + } + + while (req->state < ASYNC_REQ_DONE) { + event_loop_once(cli->event_ctx); + } + + result = cli_pull_recv(req, received); + nomem: + TALLOC_FREE(frame); + return result; +} + /**************************************************************************** Issue a single SMBread and don't wait for a reply. ****************************************************************************/ -- cgit From 95222d115a1ab676ecebdaa30d627608afb9758f Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Thu, 28 Feb 2008 15:26:01 +0100 Subject: Convert cli_read to use cli_pull (This used to be commit 719527f55e88f0c5fdceda5c807475aba299c79f) --- source3/libsmb/clireadwrite.c | 178 ++++-------------------------------------- 1 file changed, 15 insertions(+), 163 deletions(-) (limited to 'source3/libsmb') diff --git a/source3/libsmb/clireadwrite.c b/source3/libsmb/clireadwrite.c index 5aee8f18bd..c618509f01 100644 --- a/source3/libsmb/clireadwrite.c +++ b/source3/libsmb/clireadwrite.c @@ -444,175 +444,27 @@ NTSTATUS cli_pull(struct cli_state *cli, uint16_t fnum, return result; } -/**************************************************************************** -Issue a single SMBread and don't wait for a reply. -****************************************************************************/ - -static bool cli_issue_read(struct cli_state *cli, int fnum, off_t offset, - size_t size, int i) +static NTSTATUS cli_read_sink(char *buf, size_t n, void *priv) { - bool bigoffset = False; - - memset(cli->outbuf,'\0',smb_size); - memset(cli->inbuf,'\0',smb_size); - - if ((SMB_BIG_UINT)offset >> 32) - bigoffset = True; - - cli_set_message(cli->outbuf,bigoffset ? 12 : 10,0,True); - - SCVAL(cli->outbuf,smb_com,SMBreadX); - SSVAL(cli->outbuf,smb_tid,cli->cnum); - cli_setup_packet(cli); - - SCVAL(cli->outbuf,smb_vwv0,0xFF); - SSVAL(cli->outbuf,smb_vwv2,fnum); - SIVAL(cli->outbuf,smb_vwv3,offset); - SSVAL(cli->outbuf,smb_vwv5,size); - SSVAL(cli->outbuf,smb_vwv6,size); - SSVAL(cli->outbuf,smb_vwv7,(size >> 16)); - SSVAL(cli->outbuf,smb_mid,cli->mid + i); - - if (bigoffset) { - SIVAL(cli->outbuf,smb_vwv10,(((SMB_BIG_UINT)offset)>>32) & 0xffffffff); - } - - return cli_send_smb(cli); + char **pbuf = (char **)priv; + memcpy(*pbuf, buf, n); + *pbuf += n; + return NT_STATUS_OK; } -/**************************************************************************** - Read size bytes at offset offset using SMBreadX. -****************************************************************************/ - -ssize_t cli_read(struct cli_state *cli, int fnum, char *buf, off_t offset, size_t size) +ssize_t cli_read(struct cli_state *cli, int fnum, char *buf, + off_t offset, size_t size) { - char *p; - size_t size2; - size_t readsize; - ssize_t total = 0; - /* 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; - - /* - * Set readsize to the maximum size we can handle in one readX, - * rounded down to a multiple of 1024. - */ - - 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) { - readsize = CLI_SAMBA_MAX_LARGE_READX_SIZE; - } else { - readsize = CLI_WINDOWS_MAX_LARGE_READX_SIZE; - } - } else { - readsize = (cli->max_xmit - (smb_size+32)) & ~1023; - } - - while (total < size) { - readsize = MIN(readsize, size-total); - - /* Issue a read and receive a reply */ - - if (!cli_issue_read(cli, fnum, offset, readsize, 0)) - return -1; - - if (direct_reads) { - if (!cli_receive_smb_readX_header(cli)) - return -1; - } else { - if (!cli_receive_smb(cli)) - return -1; - } - - /* Check for error. Make sure to check for DOS and NT - errors. */ - - if (cli_is_error(cli)) { - bool recoverable_error = False; - NTSTATUS status = NT_STATUS_OK; - uint8 eclass = 0; - uint32 ecode = 0; - - if (cli_is_nt_error(cli)) - status = cli_nt_error(cli); - else - cli_dos_error(cli, &eclass, &ecode); - - /* - * ERRDOS ERRmoredata or STATUS_MORE_ENRTIES is a - * recoverable error, plus we have valid data in the - * packet so don't error out here. - */ - - if ((eclass == ERRDOS && ecode == ERRmoredata) || - NT_STATUS_V(status) == NT_STATUS_V(STATUS_MORE_ENTRIES)) - recoverable_error = True; - - if (!recoverable_error) - 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); - - if (size2 > readsize) { - DEBUG(5,("server returned more than we wanted!\n")); - return -1; - } else if (size2 < 0) { - DEBUG(5,("read return < 0!\n")); - 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; - } - } - } - - total += size2; - offset += size2; - - /* - * If the server returned less than we asked for we're at EOF. - */ + NTSTATUS status; + ssize_t ret; - if (size2 < readsize) - break; + status = cli_pull(cli, fnum, offset, size, size, + cli_read_sink, &buf, &ret); + if (!NT_STATUS_IS_OK(status)) { + cli_set_error(cli, status); + return -1; } - - return total; + return ret; } #if 0 /* relies on client_receive_smb(), now a static in libsmb/clientgen.c */ -- cgit From bddceee09a12e6308b5e27bf666d8948b2a894d1 Mon Sep 17 00:00:00 2001 From: Günther Deschner Date: Thu, 28 Feb 2008 23:15:11 +0100 Subject: Fix memleak in netsamlogon_cache_get(). Guenther (This used to be commit b736c77dc6c36dcdb601903fadf0ef7f163052a3) --- source3/libsmb/samlogon_cache.c | 1 + 1 file changed, 1 insertion(+) (limited to 'source3/libsmb') diff --git a/source3/libsmb/samlogon_cache.c b/source3/libsmb/samlogon_cache.c index 0d855f4c6c..73b570c383 100644 --- a/source3/libsmb/samlogon_cache.c +++ b/source3/libsmb/samlogon_cache.c @@ -226,6 +226,7 @@ struct netr_SamInfo3 *netsamlogon_cache_get(TALLOC_CTX *mem_ctx, const DOM_SID * if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { DEBUG(0,("netsamlogon_cache_get: failed to pull entry from cache\n")); tdb_delete(netsamlogon_tdb, data); + TALLOC_FREE(info3); goto done; } -- cgit From 45615d62838123bdf620a9c409d9868d47977800 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Fri, 29 Feb 2008 22:33:35 +0100 Subject: Check the right variable for being NULL (This used to be commit f2c67803792f1fd3929e922c1f626f8247e08992) --- source3/libsmb/ntlmssp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source3/libsmb') diff --git a/source3/libsmb/ntlmssp.c b/source3/libsmb/ntlmssp.c index 35c20ed647..8355669d9f 100644 --- a/source3/libsmb/ntlmssp.c +++ b/source3/libsmb/ntlmssp.c @@ -571,7 +571,7 @@ static NTSTATUS ntlmssp_server_negotiate(struct ntlmssp_state *ntlmssp_state, strlower_m(dnsdomname); dnsname = get_mydnsfullname(); - if (!dnsdomname) { + if (!dnsname) { return NT_STATUS_INVALID_COMPUTER_NAME; } -- cgit From 5e0d86c4076f9b04a2c79ab47b497924248050aa Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Fri, 29 Feb 2008 22:38:10 +0100 Subject: Restore 3.0 behaviour with empty /etc/hosts Jeremy, in 3.0 we allowed get_mydnsdomname and get_mydnsfullname to fail without filling in anything useful. Worked fine. Without this patch and a empty /etc/hosts and no DNS configured, session setup would return NT_STATUS_BAD_NETWORK_NAME. This is confusing at best, BAD_NETWORK_NAME afaik is only ever returned from tcon normally. This restores the 3.0 behaviour. Comments? Volker (This used to be commit 2bd3b7d474768f842921945d283eac10da2a1684) --- source3/libsmb/ntlmssp.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'source3/libsmb') diff --git a/source3/libsmb/ntlmssp.c b/source3/libsmb/ntlmssp.c index 8355669d9f..7082ea7e4e 100644 --- a/source3/libsmb/ntlmssp.c +++ b/source3/libsmb/ntlmssp.c @@ -566,13 +566,16 @@ static NTSTATUS ntlmssp_server_negotiate(struct ntlmssp_state *ntlmssp_state, /* This should be a 'netbios domain -> DNS domain' mapping */ dnsdomname = get_mydnsdomname(ntlmssp_state->mem_ctx); if (!dnsdomname) { - return NT_STATUS_BAD_NETWORK_NAME; + dnsdomname = talloc_strdup(ntlmssp_state->mem_ctx, ""); + } + if (!dnsdomname) { + return NT_STATUS_NO_MEMORY; } strlower_m(dnsdomname); dnsname = get_mydnsfullname(); if (!dnsname) { - return NT_STATUS_INVALID_COMPUTER_NAME; + dnsname = ""; } /* This creates the 'blob' of names that appears at the end of the packet */ -- cgit From 342859edfc244f2c80b6d080aa4edb214eb34a7b Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Sat, 1 Mar 2008 09:26:06 +0100 Subject: Revert "Convert cli_read to use cli_pull" This reverts commit 719527f55e88f0c5fdceda5c807475aba299c79f. (This used to be commit ac301fada257e2d3b50148109a3d44fa1421b0b4) --- source3/libsmb/clireadwrite.c | 178 ++++++++++++++++++++++++++++++++++++++---- 1 file changed, 163 insertions(+), 15 deletions(-) (limited to 'source3/libsmb') diff --git a/source3/libsmb/clireadwrite.c b/source3/libsmb/clireadwrite.c index c618509f01..5aee8f18bd 100644 --- a/source3/libsmb/clireadwrite.c +++ b/source3/libsmb/clireadwrite.c @@ -444,27 +444,175 @@ NTSTATUS cli_pull(struct cli_state *cli, uint16_t fnum, return result; } -static NTSTATUS cli_read_sink(char *buf, size_t n, void *priv) +/**************************************************************************** +Issue a single SMBread and don't wait for a reply. +****************************************************************************/ + +static bool cli_issue_read(struct cli_state *cli, int fnum, off_t offset, + size_t size, int i) { - char **pbuf = (char **)priv; - memcpy(*pbuf, buf, n); - *pbuf += n; - return NT_STATUS_OK; + bool bigoffset = False; + + memset(cli->outbuf,'\0',smb_size); + memset(cli->inbuf,'\0',smb_size); + + if ((SMB_BIG_UINT)offset >> 32) + bigoffset = True; + + cli_set_message(cli->outbuf,bigoffset ? 12 : 10,0,True); + + SCVAL(cli->outbuf,smb_com,SMBreadX); + SSVAL(cli->outbuf,smb_tid,cli->cnum); + cli_setup_packet(cli); + + SCVAL(cli->outbuf,smb_vwv0,0xFF); + SSVAL(cli->outbuf,smb_vwv2,fnum); + SIVAL(cli->outbuf,smb_vwv3,offset); + SSVAL(cli->outbuf,smb_vwv5,size); + SSVAL(cli->outbuf,smb_vwv6,size); + SSVAL(cli->outbuf,smb_vwv7,(size >> 16)); + SSVAL(cli->outbuf,smb_mid,cli->mid + i); + + if (bigoffset) { + SIVAL(cli->outbuf,smb_vwv10,(((SMB_BIG_UINT)offset)>>32) & 0xffffffff); + } + + return cli_send_smb(cli); } -ssize_t cli_read(struct cli_state *cli, int fnum, char *buf, - off_t offset, size_t size) +/**************************************************************************** + Read size bytes at offset offset using SMBreadX. +****************************************************************************/ + +ssize_t cli_read(struct cli_state *cli, int fnum, char *buf, off_t offset, size_t size) { - NTSTATUS status; - ssize_t ret; + char *p; + size_t size2; + size_t readsize; + ssize_t total = 0; + /* We can only do direct reads if not signing or encrypting. */ + bool direct_reads = !client_is_signing_on(cli) && !cli_encryption_on(cli); - status = cli_pull(cli, fnum, offset, size, size, - cli_read_sink, &buf, &ret); - if (!NT_STATUS_IS_OK(status)) { - cli_set_error(cli, status); - return -1; + if (size == 0) + return 0; + + /* + * Set readsize to the maximum size we can handle in one readX, + * rounded down to a multiple of 1024. + */ + + 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) { + readsize = CLI_SAMBA_MAX_LARGE_READX_SIZE; + } else { + readsize = CLI_WINDOWS_MAX_LARGE_READX_SIZE; + } + } else { + readsize = (cli->max_xmit - (smb_size+32)) & ~1023; + } + + while (total < size) { + readsize = MIN(readsize, size-total); + + /* Issue a read and receive a reply */ + + if (!cli_issue_read(cli, fnum, offset, readsize, 0)) + return -1; + + if (direct_reads) { + if (!cli_receive_smb_readX_header(cli)) + return -1; + } else { + if (!cli_receive_smb(cli)) + return -1; + } + + /* Check for error. Make sure to check for DOS and NT + errors. */ + + if (cli_is_error(cli)) { + bool recoverable_error = False; + NTSTATUS status = NT_STATUS_OK; + uint8 eclass = 0; + uint32 ecode = 0; + + if (cli_is_nt_error(cli)) + status = cli_nt_error(cli); + else + cli_dos_error(cli, &eclass, &ecode); + + /* + * ERRDOS ERRmoredata or STATUS_MORE_ENRTIES is a + * recoverable error, plus we have valid data in the + * packet so don't error out here. + */ + + if ((eclass == ERRDOS && ecode == ERRmoredata) || + NT_STATUS_V(status) == NT_STATUS_V(STATUS_MORE_ENTRIES)) + recoverable_error = True; + + if (!recoverable_error) + 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); + + if (size2 > readsize) { + DEBUG(5,("server returned more than we wanted!\n")); + return -1; + } else if (size2 < 0) { + DEBUG(5,("read return < 0!\n")); + 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; + } + } + } + + total += size2; + offset += size2; + + /* + * If the server returned less than we asked for we're at EOF. + */ + + if (size2 < readsize) + break; } - return ret; + + return total; } #if 0 /* relies on client_receive_smb(), now a static in libsmb/clientgen.c */ -- cgit From a34d158880b84cb4d14cc8055f4d5122d873bfbf Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Sat, 1 Mar 2008 09:26:18 +0100 Subject: Revert "Add async cli_pull support" This reverts commit 844a163458c7585e4306a21ffdae5d08e03d6e4d. (This used to be commit 5ab1cfda500de07ff3c712442ab2fc74eecc8886) --- source3/libsmb/clireadwrite.c | 425 ------------------------------------------ 1 file changed, 425 deletions(-) (limited to 'source3/libsmb') diff --git a/source3/libsmb/clireadwrite.c b/source3/libsmb/clireadwrite.c index 5aee8f18bd..af13ed8f73 100644 --- a/source3/libsmb/clireadwrite.c +++ b/source3/libsmb/clireadwrite.c @@ -19,431 +19,6 @@ #include "includes.h" -/**************************************************************************** - Calculate the recommended read buffer size -****************************************************************************/ -static size_t cli_read_max_bufsize(struct cli_state *cli) -{ - if (!client_is_signing_on(cli) && !cli_encryption_on(cli) == false - && (cli->posix_capabilities & CIFS_UNIX_LARGE_READ_CAP)) { - return CLI_SAMBA_MAX_POSIX_LARGE_READX_SIZE; - } - if (cli->capabilities & CAP_LARGE_READX) { - return cli->is_samba - ? CLI_SAMBA_MAX_LARGE_READX_SIZE - : CLI_WINDOWS_MAX_LARGE_READX_SIZE; - } - return (cli->max_xmit - (smb_size+32)) & ~1023; -} - -/* - * Send a read&x request - */ - -struct async_req *cli_read_andx_send(TALLOC_CTX *mem_ctx, - struct cli_state *cli, int fnum, - off_t offset, size_t size) -{ - struct async_req *result; - struct cli_request *req; - bool bigoffset = False; - char *enc_buf; - - if (size > cli_read_max_bufsize(cli)) { - DEBUG(0, ("cli_read_andx_send got size=%d, can only handle " - "size=%d\n", (int)size, - (int)cli_read_max_bufsize(cli))); - return NULL; - } - - result = cli_request_new(mem_ctx, cli->event_ctx, cli, 12, 0, &req); - if (result == NULL) { - DEBUG(0, ("cli_request_new failed\n")); - return NULL; - } - - req = cli_request_get(result); - - req->data.read.ofs = offset; - req->data.read.size = size; - req->data.read.received = 0; - req->data.read.rcvbuf = NULL; - - if ((SMB_BIG_UINT)offset >> 32) - bigoffset = True; - - cli_set_message(req->outbuf, bigoffset ? 12 : 10, 0, False); - - SCVAL(req->outbuf,smb_com,SMBreadX); - SSVAL(req->outbuf,smb_tid,cli->cnum); - cli_setup_packet_buf(cli, req->outbuf); - - SCVAL(req->outbuf,smb_vwv0,0xFF); - SCVAL(req->outbuf,smb_vwv0+1,0); - SSVAL(req->outbuf,smb_vwv1,0); - SSVAL(req->outbuf,smb_vwv2,fnum); - SIVAL(req->outbuf,smb_vwv3,offset); - SSVAL(req->outbuf,smb_vwv5,size); - SSVAL(req->outbuf,smb_vwv6,size); - SSVAL(req->outbuf,smb_vwv7,(size >> 16)); - SSVAL(req->outbuf,smb_vwv8,0); - SSVAL(req->outbuf,smb_vwv9,0); - SSVAL(req->outbuf,smb_mid,req->mid); - - if (bigoffset) { - SIVAL(req->outbuf, smb_vwv10, - (((SMB_BIG_UINT)offset)>>32) & 0xffffffff); - } - - cli_calculate_sign_mac(cli, req->outbuf); - - event_fd_set_writeable(cli->fd_event); - - if (cli_encryption_on(cli)) { - NTSTATUS status; - status = cli_encrypt_message(cli, req->outbuf, &enc_buf); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(0, ("Error in encrypting client message. " - "Error %s\n", nt_errstr(status))); - TALLOC_FREE(req); - return NULL; - } - req->outbuf = enc_buf; - req->enc_state = cli->trans_enc_state; - } - - return result; -} - -/* - * Pull the data out of a finished async read_and_x request. rcvbuf is - * talloced from the request, so better make sure that you copy it away before - * you talloc_free(req). "rcvbuf" is NOT a talloc_ctx of its own, so do not - * talloc_move it! - */ - -NTSTATUS cli_read_andx_recv(struct async_req *req, ssize_t *received, - uint8_t **rcvbuf) -{ - struct cli_request *cli_req = cli_request_get(req); - NTSTATUS status; - size_t size; - - SMB_ASSERT(req->state >= ASYNC_REQ_DONE); - if (req->state == ASYNC_REQ_ERROR) { - return req->status; - } - - status = cli_pull_error(cli_req->inbuf); - - if (!NT_STATUS_IS_OK(status)) { - return status; - } - - /* size is the number of bytes the server returned. - * Might be zero. */ - size = SVAL(cli_req->inbuf, smb_vwv5); - size |= (((unsigned int)(SVAL(cli_req->inbuf, smb_vwv7))) << 16); - - if (size > cli_req->data.read.size) { - DEBUG(5,("server returned more than we wanted!\n")); - return NT_STATUS_UNEXPECTED_IO_ERROR; - } - - if (size < 0) { - DEBUG(5,("read return < 0!\n")); - return NT_STATUS_UNEXPECTED_IO_ERROR; - } - - *rcvbuf = (uint8_t *) - (smb_base(cli_req->inbuf) + SVAL(cli_req->inbuf, smb_vwv6)); - *received = size; - return NT_STATUS_OK; -} - -/* - * Parallel read support. - * - * cli_pull sends as many read&x requests as the server would allow via - * max_mux at a time. When replies flow back in, the data is written into - * the callback function "sink" in the right order. - */ - -struct cli_pull_state { - struct async_req *req; - - struct cli_state *cli; - uint16_t fnum; - off_t start_offset; - size_t size; - - NTSTATUS (*sink)(char *buf, size_t n, void *priv); - void *priv; - - size_t chunk_size; - - /* - * Outstanding requests - */ - int num_reqs; - struct async_req **reqs; - - /* - * For how many bytes did we send requests already? - */ - off_t requested; - - /* - * Next request index to push into "sink". This walks around the "req" - * array, taking care that the requests are pushed to "sink" in the - * right order. If necessary (i.e. replies don't come in in the right - * order), replies are held back in "reqs". - */ - int top_req; - - /* - * How many bytes did we push into "sink"? - */ - - off_t pushed; -}; - -static char *cli_pull_print(TALLOC_CTX *mem_ctx, struct async_req *req) -{ - struct cli_pull_state *state = talloc_get_type_abort( - req->private_data, struct cli_pull_state); - char *result; - - result = async_req_print(mem_ctx, req); - if (result == NULL) { - return NULL; - } - - return talloc_asprintf_append_buffer( - result, "num_reqs=%d, top_req=%d", - state->num_reqs, state->top_req); -} - -static void cli_pull_read_done(struct async_req *read_req); - -/* - * Prepare an async pull request - */ - -struct async_req *cli_pull_send(TALLOC_CTX *mem_ctx, struct cli_state *cli, - uint16_t fnum, off_t start_offset, - size_t size, size_t window_size, - NTSTATUS (*sink)(char *buf, size_t n, - void *priv), - void *priv) -{ - struct async_req *result; - struct cli_pull_state *state; - int i; - - result = async_req_new(mem_ctx, cli->event_ctx); - if (result == NULL) { - goto failed; - } - state = talloc(result, struct cli_pull_state); - if (state == NULL) { - goto failed; - } - result->private_data = state; - result->print = cli_pull_print; - state->req = result; - - state->cli = cli; - state->fnum = fnum; - state->start_offset = start_offset; - state->size = size; - state->sink = sink; - state->priv = priv; - - state->pushed = 0; - state->top_req = 0; - state->chunk_size = cli_read_max_bufsize(cli); - - state->num_reqs = MAX(window_size/state->chunk_size, 1); - state->num_reqs = MIN(state->num_reqs, cli->max_mux); - - state->reqs = TALLOC_ZERO_ARRAY(state, struct async_req *, - state->num_reqs); - if (state->reqs == NULL) { - goto failed; - } - - state->requested = 0; - - for (i=0; inum_reqs; i++) { - size_t size_left, request_thistime; - - if (state->requested >= size) { - state->num_reqs = i; - break; - } - - size_left = size - state->requested; - request_thistime = MIN(size_left, state->chunk_size); - - state->reqs[i] = cli_read_andx_send( - state->reqs, cli, fnum, - state->start_offset + state->requested, - request_thistime); - - if (state->reqs[i] == NULL) { - goto failed; - } - - state->reqs[i]->async.fn = cli_pull_read_done; - state->reqs[i]->async.priv = result; - - state->requested += request_thistime; - } - return result; - -failed: - TALLOC_FREE(result); - return NULL; -} - -/* - * Handle incoming read replies, push the data into sink and send out new - * requests if necessary. - */ - -static void cli_pull_read_done(struct async_req *read_req) -{ - struct async_req *pull_req = talloc_get_type_abort( - read_req->async.priv, struct async_req); - struct cli_pull_state *state = talloc_get_type_abort( - pull_req->private_data, struct cli_pull_state); - struct cli_request *read_state = cli_request_get(read_req); - NTSTATUS status; - - status = cli_read_andx_recv(read_req, &read_state->data.read.received, - &read_state->data.read.rcvbuf); - if (!NT_STATUS_IS_OK(status)) { - async_req_error(state->req, status); - return; - } - - /* - * This loop is the one to take care of out-of-order replies. All - * pending requests are in state->reqs, state->reqs[top_req] is the - * one that is to be pushed next. If however a request later than - * top_req is replied to, then we can't push yet. If top_req is - * replied to at a later point then, we need to push all the finished - * requests. - */ - - while (state->reqs[state->top_req] != NULL) { - struct cli_request *top_read; - - DEBUG(11, ("cli_pull_read_done: top_req = %d\n", - state->top_req)); - - if (state->reqs[state->top_req]->state < ASYNC_REQ_DONE) { - DEBUG(11, ("cli_pull_read_done: top request not yet " - "done\n")); - return; - } - - top_read = cli_request_get(state->reqs[state->top_req]); - - DEBUG(10, ("cli_pull_read_done: Pushing %d bytes, %d already " - "pushed\n", (int)top_read->data.read.received, - (int)state->pushed)); - - status = state->sink((char *)top_read->data.read.rcvbuf, - top_read->data.read.received, - state->priv); - if (!NT_STATUS_IS_OK(status)) { - async_req_error(state->req, status); - return; - } - state->pushed += top_read->data.read.received; - - TALLOC_FREE(state->reqs[state->top_req]); - - if (state->requested < state->size) { - struct async_req *new_req; - size_t size_left, request_thistime; - - size_left = state->size - state->requested; - request_thistime = MIN(size_left, state->chunk_size); - - DEBUG(10, ("cli_pull_read_done: Requesting %d bytes " - "at %d, position %d\n", - (int)request_thistime, - (int)(state->start_offset - + state->requested), - state->top_req)); - - new_req = cli_read_andx_send( - state->reqs, state->cli, state->fnum, - state->start_offset + state->requested, - request_thistime); - - if (async_req_nomem(new_req, state->req)) { - return; - } - - new_req->async.fn = cli_pull_read_done; - new_req->async.priv = pull_req; - - state->reqs[state->top_req] = new_req; - state->requested += request_thistime; - } - - state->top_req = (state->top_req+1) % state->num_reqs; - } - - async_req_done(pull_req); -} - -NTSTATUS cli_pull_recv(struct async_req *req, ssize_t *received) -{ - struct cli_pull_state *state = talloc_get_type_abort( - req->private_data, struct cli_pull_state); - - SMB_ASSERT(req->state >= ASYNC_REQ_DONE); - if (req->state == ASYNC_REQ_ERROR) { - return req->status; - } - *received = state->pushed; - return NT_STATUS_OK; -} - -NTSTATUS cli_pull(struct cli_state *cli, uint16_t fnum, - off_t start_offset, size_t size, size_t window_size, - NTSTATUS (*sink)(char *buf, size_t n, void *priv), - void *priv, ssize_t *received) -{ - TALLOC_CTX *frame = talloc_stackframe(); - struct async_req *req; - NTSTATUS result = NT_STATUS_NO_MEMORY; - - if (cli_tmp_event_ctx(frame, cli) == NULL) { - goto nomem; - } - - req = cli_pull_send(frame, cli, fnum, start_offset, size, window_size, - sink, priv); - if (req == NULL) { - goto nomem; - } - - while (req->state < ASYNC_REQ_DONE) { - event_loop_once(cli->event_ctx); - } - - result = cli_pull_recv(req, received); - nomem: - TALLOC_FREE(frame); - return result; -} - /**************************************************************************** Issue a single SMBread and don't wait for a reply. ****************************************************************************/ -- cgit From 45a877f392a5449f4c3b7d39f9f8c78b57733d39 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Sat, 1 Mar 2008 09:26:27 +0100 Subject: Revert "Add infrastructure to support async SMB requests" This reverts commit f5356825698a02df2d400b51dd95d1f857c83e81. (This used to be commit 5f53a62be8a21b8d92ac44b18d202882500356e8) --- source3/libsmb/async_smb.c | 483 --------------------------------------------- 1 file changed, 483 deletions(-) delete mode 100644 source3/libsmb/async_smb.c (limited to 'source3/libsmb') diff --git a/source3/libsmb/async_smb.c b/source3/libsmb/async_smb.c deleted file mode 100644 index 21bcd5b9b1..0000000000 --- a/source3/libsmb/async_smb.c +++ /dev/null @@ -1,483 +0,0 @@ -/* - Unix SMB/CIFS implementation. - Infrastructure for async SMB client requests - Copyright (C) Volker Lendecke 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 - 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 . -*/ - -#include "includes.h" - -/* - * Fetch an error out of a NBT packet - */ - -NTSTATUS cli_pull_error(char *buf) -{ - uint32_t flags2 = SVAL(buf, smb_flg2); - - if (flags2 & FLAGS2_32_BIT_ERROR_CODES) { - return NT_STATUS(IVAL(buf, smb_rcls)); - } - - return NT_STATUS_DOS(CVAL(buf, smb_rcls), SVAL(buf,smb_err)); -} - -/* - * Compatibility helper for the sync APIs: Fake NTSTATUS in cli->inbuf - */ - -void cli_set_error(struct cli_state *cli, NTSTATUS status) -{ - uint32_t flags2 = SVAL(cli->inbuf, smb_flg2); - - if (NT_STATUS_IS_DOS(status)) { - SSVAL(cli->inbuf, smb_flg2, - flags2 & ~FLAGS2_32_BIT_ERROR_CODES); - SCVAL(cli->inbuf, smb_rcls, NT_STATUS_DOS_CLASS(status)); - SSVAL(cli->inbuf, smb_err, NT_STATUS_DOS_CODE(status)); - return; - } - - SSVAL(cli->inbuf, smb_flg2, flags2 | FLAGS2_32_BIT_ERROR_CODES); - SIVAL(cli->inbuf, smb_rcls, NT_STATUS_V(status)); - return; -} - -/* - * Allocate a new mid - */ - -static uint16_t cli_new_mid(struct cli_state *cli) -{ - uint16_t result; - struct cli_request *req; - - while (true) { - result = cli->mid++; - if (result == 0) { - continue; - } - - for (req = cli->outstanding_requests; req; req = req->next) { - if (result == req->mid) { - break; - } - } - - if (req == NULL) { - return result; - } - } -} - -static char *cli_request_print(TALLOC_CTX *mem_ctx, struct async_req *req) -{ - char *result = async_req_print(mem_ctx, req); - struct cli_request *cli_req = cli_request_get(req); - - if (result == NULL) { - return NULL; - } - - return talloc_asprintf_append_buffer( - result, "mid=%d\n", cli_req->mid); -} - -static int cli_request_destructor(struct cli_request *req) -{ - if (req->enc_state != NULL) { - common_free_enc_buffer(req->enc_state, req->outbuf); - } - DLIST_REMOVE(req->cli->outstanding_requests, req); - return 0; -} - -/* - * Create a fresh async smb request - */ - -struct async_req *cli_request_new(TALLOC_CTX *mem_ctx, - struct event_context *ev, - struct cli_state *cli, - uint8_t num_words, size_t num_bytes, - struct cli_request **preq) -{ - struct async_req *result; - struct cli_request *cli_req; - size_t bufsize = smb_size + num_words * 2 + num_bytes; - - result = async_req_new(mem_ctx, ev); - if (result == NULL) { - return NULL; - } - - cli_req = (struct cli_request *)talloc_size( - result, sizeof(*cli_req) + bufsize); - if (cli_req == NULL) { - TALLOC_FREE(result); - return NULL; - } - talloc_set_name_const(cli_req, "struct cli_request"); - result->private_data = cli_req; - result->print = cli_request_print; - - cli_req->async = result; - cli_req->cli = cli; - cli_req->outbuf = ((char *)cli_req + sizeof(*cli_req)); - cli_req->sent = 0; - cli_req->mid = cli_new_mid(cli); - cli_req->inbuf = NULL; - cli_req->enc_state = NULL; - - SCVAL(cli_req->outbuf, smb_wct, num_words); - SSVAL(cli_req->outbuf, smb_vwv + num_words * 2, num_bytes); - - DLIST_ADD_END(cli->outstanding_requests, cli_req, - struct cli_request *); - talloc_set_destructor(cli_req, cli_request_destructor); - - DEBUG(10, ("cli_request_new: mid=%d\n", cli_req->mid)); - - *preq = cli_req; - return result; -} - -/* - * Convenience function to get the SMB part out of an async_req - */ - -struct cli_request *cli_request_get(struct async_req *req) -{ - if (req == NULL) { - return NULL; - } - return talloc_get_type_abort(req->private_data, struct cli_request); -} - -/* - * A PDU has arrived on cli->evt_inbuf - */ - -static void handle_incoming_pdu(struct cli_state *cli) -{ - struct cli_request *req; - uint16_t mid; - size_t raw_pdu_len, buf_len, pdu_len; - size_t rest_len; - NTSTATUS status; - - /* - * The encrypted PDU len might differ from the unencrypted one - */ - raw_pdu_len = smb_len(cli->evt_inbuf) + 4; - - /* - * TODO: Handle oplock break requests - */ - - if (cli_encryption_on(cli) && CVAL(cli->evt_inbuf, 0) == 0) { - uint16_t enc_ctx_num; - - status = get_enc_ctx_num((uint8_t *)cli->evt_inbuf, - &enc_ctx_num); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(10, ("get_enc_ctx_num returned %s\n", - nt_errstr(status))); - goto invalidate_requests; - } - - if (enc_ctx_num != cli->trans_enc_state->enc_ctx_num) { - DEBUG(10, ("wrong enc_ctx %d, expected %d\n", - enc_ctx_num, - cli->trans_enc_state->enc_ctx_num)); - status = NT_STATUS_INVALID_HANDLE; - goto invalidate_requests; - } - - status = common_decrypt_buffer(cli->trans_enc_state, - cli->evt_inbuf); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(10, ("common_decrypt_buffer returned %s\n", - nt_errstr(status))); - goto invalidate_requests; - } - } - - if (!cli_check_sign_mac(cli, cli->evt_inbuf)) { - DEBUG(10, ("cli_check_sign_mac failed\n")); - status = NT_STATUS_ACCESS_DENIED; - goto invalidate_requests; - } - - mid = SVAL(cli->evt_inbuf, smb_mid); - - DEBUG(10, ("handle_incoming_pdu: got mid %d\n", mid)); - - for (req = cli->outstanding_requests; req; req = req->next) { - if (req->mid == mid) { - break; - } - } - - buf_len = talloc_get_size(cli->evt_inbuf); - pdu_len = smb_len(cli->evt_inbuf) + 4; - rest_len = buf_len - raw_pdu_len; - - if (req == NULL) { - DEBUG(3, ("Request for mid %d not found, dumping PDU\n", mid)); - - memmove(cli->evt_inbuf, cli->evt_inbuf + raw_pdu_len, - buf_len - raw_pdu_len); - - cli->evt_inbuf = TALLOC_REALLOC_ARRAY(NULL, cli->evt_inbuf, - char, rest_len); - return; - } - - if (buf_len == pdu_len) { - /* - * Optimal case: Exactly one PDU was in the socket buffer - */ - req->inbuf = talloc_move(req, &cli->evt_inbuf); - goto done; - } - - DEBUG(11, ("buf_len = %d, pdu_len = %d, splitting buffer\n", - (int)buf_len, (int)pdu_len)); - - if (pdu_len < rest_len) { - /* - * The PDU is shorter, talloc_memdup that one. - */ - req->inbuf = (char *)talloc_memdup( - req, cli->evt_inbuf, pdu_len); - - memmove(cli->evt_inbuf, - cli->evt_inbuf + raw_pdu_len, - buf_len - raw_pdu_len); - - cli->evt_inbuf = TALLOC_REALLOC_ARRAY( - NULL, cli->evt_inbuf, char, rest_len); - } - else { - /* - * The PDU is larger than the rest, - * talloc_memdup the rest - */ - req->inbuf = talloc_move(req, &cli->evt_inbuf); - - cli->evt_inbuf = (char *)talloc_memdup( - cli, req->inbuf + raw_pdu_len, - rest_len); - } - - if ((req->inbuf == NULL) || (cli->evt_inbuf == NULL)) { - status = NT_STATUS_NO_MEMORY; - goto invalidate_requests; - } - - done: - async_req_done(req->async); - return; - - invalidate_requests: - - DEBUG(10, ("handle_incoming_pdu: Aborting with %s\n", - nt_errstr(status))); - - for (req = cli->outstanding_requests; req; req = req->next) { - async_req_error(req->async, status); - } - return; -} - -/* - * fd event callback. This is the basic connection to the socket - */ - -static void cli_state_handler(struct event_context *event_ctx, - struct fd_event *event, uint16 flags, void *p) -{ - struct cli_state *cli = (struct cli_state *)p; - struct cli_request *req; - - DEBUG(11, ("cli_state_handler called with flags %d\n", flags)); - - if (flags & EVENT_FD_READ) { - int res, available; - size_t old_size, new_size; - char *tmp; - - res = ioctl(cli->fd, FIONREAD, &available); - if (res == -1) { - DEBUG(10, ("ioctl(FIONREAD) failed: %s\n", - strerror(errno))); - goto sock_error; - } - - if (available == 0) { - /* EOF */ - goto sock_error; - } - - old_size = talloc_get_size(cli->evt_inbuf); - new_size = old_size + available; - - if (new_size < old_size) { - /* wrap */ - goto sock_error; - } - - tmp = TALLOC_REALLOC_ARRAY(cli, cli->evt_inbuf, char, - new_size); - if (tmp == NULL) { - /* nomem */ - goto sock_error; - } - cli->evt_inbuf = tmp; - - res = recv(cli->fd, cli->evt_inbuf + old_size, available, 0); - if (res == -1) { - DEBUG(10, ("recv failed: %s\n", strerror(errno))); - goto sock_error; - } - - DEBUG(11, ("cli_state_handler: received %d bytes, " - "smb_len(evt_inbuf) = %d\n", (int)res, - smb_len(cli->evt_inbuf))); - - /* recv *might* have returned less than announced */ - new_size = old_size + res; - - /* shrink, so I don't expect errors here */ - cli->evt_inbuf = TALLOC_REALLOC_ARRAY(cli, cli->evt_inbuf, - char, new_size); - - while ((cli->evt_inbuf != NULL) - && ((smb_len(cli->evt_inbuf) + 4) <= new_size)) { - /* - * we've got a complete NBT level PDU in evt_inbuf - */ - handle_incoming_pdu(cli); - new_size = talloc_get_size(cli->evt_inbuf); - } - } - - if (flags & EVENT_FD_WRITE) { - size_t to_send; - ssize_t sent; - - for (req = cli->outstanding_requests; req; req = req->next) { - to_send = smb_len(req->outbuf)+4; - if (to_send > req->sent) { - break; - } - } - - if (req == NULL) { - event_fd_set_not_writeable(event); - return; - } - - sent = send(cli->fd, req->outbuf + req->sent, - to_send - req->sent, 0); - - if (sent < 0) { - goto sock_error; - } - - req->sent += sent; - - if (req->sent == to_send) { - return; - } - } - return; - - sock_error: - for (req = cli->outstanding_requests; req; req = req->next) { - req->async->state = ASYNC_REQ_ERROR; - req->async->status = map_nt_error_from_unix(errno); - } - TALLOC_FREE(cli->fd_event); - close(cli->fd); - cli->fd = -1; -} - -/* - * Holder for a talloc_destructor, we need to zero out the pointers in cli - * when deleting - */ -struct cli_tmp_event { - struct cli_state *cli; -}; - -static int cli_tmp_event_destructor(struct cli_tmp_event *e) -{ - TALLOC_FREE(e->cli->fd_event); - TALLOC_FREE(e->cli->event_ctx); - return 0; -} - -/* - * Create a temporary event context for use in the sync helper functions - */ - -struct cli_tmp_event *cli_tmp_event_ctx(TALLOC_CTX *mem_ctx, - struct cli_state *cli) -{ - struct cli_tmp_event *state; - - if (cli->event_ctx != NULL) { - return NULL; - } - - state = talloc(mem_ctx, struct cli_tmp_event); - if (state == NULL) { - return NULL; - } - state->cli = cli; - talloc_set_destructor(state, cli_tmp_event_destructor); - - cli->event_ctx = event_context_init(state); - if (cli->event_ctx == NULL) { - TALLOC_FREE(state); - return NULL; - } - - cli->fd_event = event_add_fd(cli->event_ctx, state, cli->fd, - EVENT_FD_READ, cli_state_handler, cli); - if (cli->fd_event == NULL) { - TALLOC_FREE(state); - return NULL; - } - return state; -} - -/* - * Attach an event context permanently to a cli_struct - */ - -NTSTATUS cli_add_event_ctx(struct cli_state *cli, - struct event_context *event_ctx) -{ - cli->event_ctx = event_ctx; - cli->fd_event = event_add_fd(event_ctx, cli, cli->fd, EVENT_FD_READ, - cli_state_handler, cli); - if (cli->fd_event == NULL) { - return NT_STATUS_NO_MEMORY; - } - return NT_STATUS_OK; -} -- cgit From 257b7b09298f7cb983b2f31b87fc5e46e0f62f0c Mon Sep 17 00:00:00 2001 From: Derrell Lipman Date: Thu, 28 Feb 2008 11:23:20 -0500 Subject: Initial revamp of the libsmbclient interface. The libsmbclient interface has suffered from difficulty of improvement and feature enrichment without causing ABI breakage. Although there were a number of issues, the primary ones were: (a) the user of the library would manually manipulate the context structure members, meaning that nothing in the context structure could change other than adding stuff at the end; (b) there were three methods of setting options: setting bits in a flags field within the context structure, setting explicit options variables within an options structure in the context structure, and by calling the smbc_option_set() function; (c) the authentication callback did not traditionally provide enough information to the callee which required adding an option for a callback with a different signature, and now there are requests for even more information at the callback, requiring yet a third signature and option to set it (if we implement that feature). This commit provides a reorganization of the code which fixes (a) and (b). The context structure is now entirely opaque, and there are setter and getter functions for manipulating it. This makes maintaining ABI consistency much, much easier. Additionally, the options setting/getting has been unified into a single mechanism using smbc_option_set() and smbc_option_get(). Yet to be completed is a refactoring of the authentication callback (c). The test programs in examples/libsmbclient have been modified (if necessary; some applications require no changes at all) for the new API and a few have been minimally tested. Derrell (This used to be commit d4b4bae8ded824d06ad5ab0e219f71187ee5c771) --- source3/libsmb/libsmb_cache.c | 74 +- source3/libsmb/libsmb_compat.c | 329 +- source3/libsmb/libsmb_context.c | 1283 +++++++ source3/libsmb/libsmb_dir.c | 1928 ++++++++++ source3/libsmb/libsmb_file.c | 859 +++++ source3/libsmb/libsmb_misc.c | 73 + source3/libsmb/libsmb_path.c | 399 +++ source3/libsmb/libsmb_printjob.c | 334 ++ source3/libsmb/libsmb_server.c | 675 ++++ source3/libsmb/libsmb_stat.c | 302 ++ source3/libsmb/libsmb_xattr.c | 2293 ++++++++++++ source3/libsmb/libsmbclient.c | 7233 -------------------------------------- 12 files changed, 8385 insertions(+), 7397 deletions(-) create mode 100644 source3/libsmb/libsmb_context.c create mode 100644 source3/libsmb/libsmb_dir.c create mode 100644 source3/libsmb/libsmb_file.c create mode 100644 source3/libsmb/libsmb_misc.c create mode 100644 source3/libsmb/libsmb_path.c create mode 100644 source3/libsmb/libsmb_printjob.c create mode 100644 source3/libsmb/libsmb_server.c create mode 100644 source3/libsmb/libsmb_stat.c create mode 100644 source3/libsmb/libsmb_xattr.c delete mode 100644 source3/libsmb/libsmbclient.c (limited to 'source3/libsmb') diff --git a/source3/libsmb/libsmb_cache.c b/source3/libsmb/libsmb_cache.c index b98df024fa..e0571fa9fe 100644 --- a/source3/libsmb/libsmb_cache.c +++ b/source3/libsmb/libsmb_cache.c @@ -22,11 +22,8 @@ */ #include "includes.h" - -#include "include/libsmbclient.h" -#include "../include/libsmb_internal.h" - -int smbc_default_cache_functions(SMBCCTX * context); +#include "libsmbclient.h" +#include "libsmb_internal.h" /* * Structure we use if internal caching mechanism is used @@ -48,9 +45,13 @@ struct smbc_server_cache { * Add a new connection to the server cache. * This function is only used if the external cache is not enabled */ -static int smbc_add_cached_server(SMBCCTX * context, SMBCSRV * newsrv, - const char * server, const char * share, - const char * workgroup, const char * username) +int +SMBC_add_cached_server(SMBCCTX * context, + SMBCSRV * newsrv, + const char * server, + const char * share, + const char * workgroup, + const char * username) { struct smbc_server_cache * srvcache = NULL; @@ -88,7 +89,7 @@ static int smbc_add_cached_server(SMBCCTX * context, SMBCSRV * newsrv, goto failed; } - DLIST_ADD((context->server_cache), srvcache); + DLIST_ADD((context->cache.server_cache_data), srvcache); return 0; failed: @@ -108,13 +109,17 @@ static int smbc_add_cached_server(SMBCCTX * context, SMBCSRV * newsrv, * returns server handle on success, NULL on error (not found) * This function is only used if the external cache is not enabled */ -static SMBCSRV * smbc_get_cached_server(SMBCCTX * context, const char * server, - const char * share, const char * workgroup, const char * user) +SMBCSRV * +SMBC_get_cached_server(SMBCCTX * context, + const char * server, + const char * share, + const char * workgroup, + const char * user) { struct smbc_server_cache * srv = NULL; /* Search the cache lines */ - for (srv=((struct smbc_server_cache *)context->server_cache);srv;srv=srv->next) { + for (srv = context->cache.server_cache_data; srv; srv = srv->next) { if (strcmp(server,srv->server_name) == 0 && strcmp(workgroup,srv->workgroup) == 0 && @@ -146,7 +151,7 @@ static SMBCSRV * smbc_get_cached_server(SMBCCTX * context, const char * server, * a connection to the server (other than the * attribute server connection) is cool. */ - if (context->options.one_share_per_server) { + if (context->one_share_per_server) { /* * The currently connected share name * doesn't match the requested share, so @@ -156,7 +161,7 @@ static SMBCSRV * smbc_get_cached_server(SMBCCTX * context, const char * server, /* Sigh. Couldn't disconnect. */ cli_shutdown(srv->server->cli); srv->server->cli = NULL; - context->callbacks.remove_cached_srv_fn(context, srv->server); + context->cache.remove_cached_server_fn(context, srv->server); continue; } @@ -171,7 +176,7 @@ static SMBCSRV * smbc_get_cached_server(SMBCCTX * context, const char * server, /* Out of memory. */ cli_shutdown(srv->server->cli); srv->server->cli = NULL; - context->callbacks.remove_cached_srv_fn(context, srv->server); + context->cache.remove_cached_server_fn(context, srv->server); continue; } @@ -190,15 +195,17 @@ static SMBCSRV * smbc_get_cached_server(SMBCCTX * context, const char * server, * returns 0 on success * This function is only used if the external cache is not enabled */ -static int smbc_remove_cached_server(SMBCCTX * context, SMBCSRV * server) +int +SMBC_remove_cached_server(SMBCCTX * context, + SMBCSRV * server) { struct smbc_server_cache * srv = NULL; - for (srv=((struct smbc_server_cache *)context->server_cache);srv;srv=srv->next) { + for (srv = context->cache.server_cache_data; srv; srv = srv->next) { if (server == srv->server) { /* remove this sucker */ - DLIST_REMOVE(context->server_cache, srv); + DLIST_REMOVE(context->cache.server_cache_data, srv); SAFE_FREE(srv->server_name); SAFE_FREE(srv->share_name); SAFE_FREE(srv->workgroup); @@ -216,40 +223,23 @@ static int smbc_remove_cached_server(SMBCCTX * context, SMBCSRV * server) * Try to remove all the servers in cache * returns 1 on failure and 0 if all servers could be removed. */ -static int smbc_purge_cached(SMBCCTX * context) +int +SMBC_purge_cached_servers(SMBCCTX * context) { struct smbc_server_cache * srv; struct smbc_server_cache * next; int could_not_purge_all = 0; - for (srv = ((struct smbc_server_cache *) context->server_cache), - next = (srv ? srv->next :NULL); + for (srv = context->cache.server_cache_data, + next = (srv ? srv->next :NULL); srv; - srv = next, next = (srv ? srv->next : NULL)) { + srv = next, + next = (srv ? srv->next : NULL)) { - if (smbc_remove_unused_server(context, srv->server)) { + if (SMBC_remove_unused_server(context, srv->server)) { /* could not be removed */ could_not_purge_all = 1; } } return could_not_purge_all; } - - - -/* - * This functions initializes all server-cache related functions - * to the default (internal) system. - * - * We use this to make the rest of the cache system static. - */ - -int smbc_default_cache_functions(SMBCCTX * context) -{ - context->callbacks.add_cached_srv_fn = smbc_add_cached_server; - context->callbacks.get_cached_srv_fn = smbc_get_cached_server; - context->callbacks.remove_cached_srv_fn = smbc_remove_cached_server; - context->callbacks.purge_cached_fn = smbc_purge_cached; - - return 0; -} diff --git a/source3/libsmb/libsmb_compat.c b/source3/libsmb/libsmb_compat.c index 6042464fd2..7a0536a92d 100644 --- a/source3/libsmb/libsmb_compat.c +++ b/source3/libsmb/libsmb_compat.c @@ -5,7 +5,7 @@ Copyright (C) Richard Sharpe 2000 Copyright (C) John Terpstra 2000 Copyright (C) Tom Jansen (Ninja ISD) 2002 - Copyright (C) Derrell Lipman 2003 + Copyright (C) Derrell Lipman 2003, 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 @@ -23,8 +23,7 @@ #include "includes.h" - -#include "include/libsmb_internal.h" +#include "libsmb_internal.h" struct smbc_compat_fdlist { SMBCFILE * file; @@ -39,7 +38,8 @@ static struct smbc_compat_fdlist * smbc_compat_fd_in_use = NULL; static struct smbc_compat_fdlist * smbc_compat_fd_avail = NULL; /* Find an fd and return the SMBCFILE * or NULL on failure */ -static SMBCFILE * find_fd(int fd) +static SMBCFILE * +find_fd(int fd) { struct smbc_compat_fdlist * f = smbc_compat_fd_in_use; while (f) { @@ -51,7 +51,8 @@ static SMBCFILE * find_fd(int fd) } /* Add an fd, returns 0 on success, -1 on error with errno set */ -static int add_fd(SMBCFILE * file) +static int +add_fd(SMBCFILE * file) { struct smbc_compat_fdlist * f = smbc_compat_fd_avail; @@ -90,7 +91,8 @@ static int add_fd(SMBCFILE * file) /* Delete an fd, returns 0 on success */ -static int del_fd(int fd) +static int +del_fd(int fd) { struct smbc_compat_fdlist * f = smbc_compat_fd_in_use; @@ -112,15 +114,17 @@ static int del_fd(int fd) -int smbc_init(smbc_get_auth_data_fn fn, int debug) +int +smbc_init(smbc_get_auth_data_fn fn, + int debug) { if (!smbc_compat_initialized) { statcont = smbc_new_context(); if (!statcont) return -1; - statcont->debug = debug; - statcont->callbacks.auth_fn = fn; + smbc_setDebug(statcont, debug); + smbc_setFunctionAuthData(statcont, fn); if (!smbc_init_context(statcont)) { smbc_free_context(statcont, False); @@ -135,7 +139,8 @@ int smbc_init(smbc_get_auth_data_fn fn, int debug) } -SMBCCTX *smbc_set_context(SMBCCTX * context) +SMBCCTX * +smbc_set_context(SMBCCTX * context) { SMBCCTX *old_context = statcont; @@ -151,307 +156,387 @@ SMBCCTX *smbc_set_context(SMBCCTX * context) } -int smbc_open(const char *furl, int flags, mode_t mode) +int +smbc_open(const char *furl, + int flags, + mode_t mode) { SMBCFILE * file; int fd; - file = (statcont->open)(statcont, furl, flags, mode); + file = smbc_getFunctionOpen(statcont)(statcont, furl, flags, mode); if (!file) return -1; fd = add_fd(file); if (fd == -1) - (statcont->close_fn)(statcont, file); + smbc_getFunctionClose(statcont)(statcont, file); return fd; } -int smbc_creat(const char *furl, mode_t mode) +int +smbc_creat(const char *furl, + mode_t mode) { SMBCFILE * file; int fd; - file = (statcont->creat)(statcont, furl, mode); + file = smbc_getFunctionCreat(statcont)(statcont, furl, mode); if (!file) return -1; fd = add_fd(file); if (fd == -1) { /* Hmm... should we delete the file too ? I guess we could try */ - (statcont->close_fn)(statcont, file); - (statcont->unlink)(statcont, furl); + smbc_getFunctionClose(statcont)(statcont, file); + smbc_getFunctionUnlink(statcont)(statcont, furl); } return fd; } -ssize_t smbc_read(int fd, void *buf, size_t bufsize) +ssize_t +smbc_read(int fd, + void *buf, + size_t bufsize) { SMBCFILE * file = find_fd(fd); - return (statcont->read)(statcont, file, buf, bufsize); + return smbc_getFunctionRead(statcont)(statcont, file, buf, bufsize); } -ssize_t smbc_write(int fd, void *buf, size_t bufsize) +ssize_t +smbc_write(int fd, + void *buf, + size_t bufsize) { SMBCFILE * file = find_fd(fd); - return (statcont->write)(statcont, file, buf, bufsize); + return smbc_getFunctionWrite(statcont)(statcont, file, buf, bufsize); } -off_t smbc_lseek(int fd, off_t offset, int whence) +off_t +smbc_lseek(int fd, + off_t offset, + int whence) { SMBCFILE * file = find_fd(fd); - return (statcont->lseek)(statcont, file, offset, whence); + return smbc_getFunctionLseek(statcont)(statcont, file, offset, whence); } -int smbc_close(int fd) +int +smbc_close(int fd) { SMBCFILE * file = find_fd(fd); del_fd(fd); - return (statcont->close_fn)(statcont, file); + return smbc_getFunctionClose(statcont)(statcont, file); } -int smbc_unlink(const char *fname) +int +smbc_unlink(const char *fname) { - return (statcont->unlink)(statcont, fname); + return smbc_getFunctionUnlink(statcont)(statcont, fname); } -int smbc_rename(const char *ourl, const char *nurl) +int +smbc_rename(const char *ourl, + const char *nurl) { - return (statcont->rename)(statcont, ourl, statcont, nurl); + return smbc_getFunctionRename(statcont)(statcont, ourl, + statcont, nurl); } -int smbc_opendir(const char *durl) +int +smbc_opendir(const char *durl) { SMBCFILE * file; int fd; - file = (statcont->opendir)(statcont, durl); + file = smbc_getFunctionOpendir(statcont)(statcont, durl); if (!file) return -1; fd = add_fd(file); if (fd == -1) - (statcont->closedir)(statcont, file); + smbc_getFunctionClosedir(statcont)(statcont, file); return fd; } -int smbc_closedir(int dh) +int +smbc_closedir(int dh) { SMBCFILE * file = find_fd(dh); del_fd(dh); - return (statcont->closedir)(statcont, file); + return smbc_getFunctionClosedir(statcont)(statcont, file); } -int smbc_getdents(unsigned int dh, struct smbc_dirent *dirp, int count) +int +smbc_getdents(unsigned int dh, + struct smbc_dirent *dirp, + int count) { SMBCFILE * file = find_fd(dh); - return (statcont->getdents)(statcont, file,dirp, count); + return smbc_getFunctionGetdents(statcont)(statcont, file, dirp, count); } -struct smbc_dirent* smbc_readdir(unsigned int dh) +struct smbc_dirent * +smbc_readdir(unsigned int dh) { SMBCFILE * file = find_fd(dh); - return (statcont->readdir)(statcont, file); + return smbc_getFunctionReaddir(statcont)(statcont, file); } -off_t smbc_telldir(int dh) +off_t +smbc_telldir(int dh) { SMBCFILE * file = find_fd(dh); - return (statcont->telldir)(statcont, file); + return smbc_getFunctionTelldir(statcont)(statcont, file); } -int smbc_lseekdir(int fd, off_t offset) +int +smbc_lseekdir(int fd, + off_t offset) { SMBCFILE * file = find_fd(fd); - return (statcont->lseekdir)(statcont, file, offset); + return smbc_getFunctionLseekdir(statcont)(statcont, file, offset); } -int smbc_mkdir(const char *durl, mode_t mode) +int +smbc_mkdir(const char *durl, + mode_t mode) { - return (statcont->mkdir)(statcont, durl, mode); + return smbc_getFunctionMkdir(statcont)(statcont, durl, mode); } -int smbc_rmdir(const char *durl) +int +smbc_rmdir(const char *durl) { - return (statcont->rmdir)(statcont, durl); + return smbc_getFunctionRmdir(statcont)(statcont, durl); } -int smbc_stat(const char *url, struct stat *st) +int +smbc_stat(const char *url, + struct stat *st) { - return (statcont->stat)(statcont, url, st); + return smbc_getFunctionStat(statcont)(statcont, url, st); } -int smbc_fstat(int fd, struct stat *st) +int +smbc_fstat(int fd, + struct stat *st) { SMBCFILE * file = find_fd(fd); - return (statcont->fstat)(statcont, file, st); + return smbc_getFunctionFstat(statcont)(statcont, file, st); } -int smbc_ftruncate(int fd, off_t size) +int +smbc_ftruncate(int fd, + off_t size) { SMBCFILE * file = find_fd(fd); - return (statcont->ftruncate)(statcont, file, size); + return smbc_getFunctionFtruncate(statcont)(statcont, file, size); } -int smbc_chmod(const char *url, mode_t mode) +int +smbc_chmod(const char *url, + mode_t mode) { - return (statcont->chmod)(statcont, url, mode); + return smbc_getFunctionChmod(statcont)(statcont, url, mode); } -int smbc_utimes(const char *fname, struct timeval *tbuf) +int +smbc_utimes(const char *fname, + struct timeval *tbuf) { - return (statcont->utimes)(statcont, fname, tbuf); + return smbc_getFunctionUtimes(statcont)(statcont, fname, tbuf); } #ifdef HAVE_UTIME_H -int smbc_utime(const char *fname, struct utimbuf *utbuf) +int +smbc_utime(const char *fname, + struct utimbuf *utbuf) { struct timeval tv[2]; if (utbuf == NULL) - return (statcont->utimes)(statcont, fname, NULL); + return smbc_getFunctionUtimes(statcont)(statcont, fname, NULL); tv[0].tv_sec = utbuf->actime; tv[1].tv_sec = utbuf->modtime; tv[0].tv_usec = tv[1].tv_usec = 0; - return (statcont->utimes)(statcont, fname, tv); + return smbc_getFunctionUtimes(statcont)(statcont, fname, tv); } #endif -int smbc_setxattr(const char *fname, - const char *name, - const void *value, - size_t size, - int flags) +int +smbc_setxattr(const char *fname, + const char *name, + const void *value, + size_t size, + int flags) { - return (statcont->setxattr)(statcont, fname, name, value, size, flags); + return smbc_getFunctionSetxattr(statcont)(statcont, + fname, name, + value, size, flags); } -int smbc_lsetxattr(const char *fname, - const char *name, - const void *value, - size_t size, - int flags) +int +smbc_lsetxattr(const char *fname, + const char *name, + const void *value, + size_t size, + int flags) { - return (statcont->setxattr)(statcont, fname, name, value, size, flags); + return smbc_getFunctionSetxattr(statcont)(statcont, + fname, name, + value, size, flags); } -int smbc_fsetxattr(int fd, - const char *name, - const void *value, - size_t size, - int flags) +int +smbc_fsetxattr(int fd, + const char *name, + const void *value, + size_t size, + int flags) { SMBCFILE * file = find_fd(fd); if (file == NULL) { errno = EBADF; return -1; } - return (statcont->setxattr)(statcont, file->fname, - name, value, size, flags); + return smbc_getFunctionSetxattr(statcont)(statcont, + file->fname, name, + value, size, flags); } -int smbc_getxattr(const char *fname, - const char *name, - const void *value, - size_t size) +int +smbc_getxattr(const char *fname, + const char *name, + const void *value, + size_t size) { - return (statcont->getxattr)(statcont, fname, name, value, size); + return smbc_getFunctionGetxattr(statcont)(statcont, + fname, name, + value, size); } -int smbc_lgetxattr(const char *fname, - const char *name, - const void *value, - size_t size) +int +smbc_lgetxattr(const char *fname, + const char *name, + const void *value, + size_t size) { - return (statcont->getxattr)(statcont, fname, name, value, size); + return smbc_getFunctionGetxattr(statcont)(statcont, + fname, name, + value, size); } -int smbc_fgetxattr(int fd, - const char *name, - const void *value, - size_t size) +int +smbc_fgetxattr(int fd, + const char *name, + const void *value, + size_t size) { SMBCFILE * file = find_fd(fd); if (file == NULL) { errno = EBADF; return -1; } - return (statcont->getxattr)(statcont, file->fname, name, value, size); + return smbc_getFunctionGetxattr(statcont)(statcont, + file->fname, name, + value, size); } -int smbc_removexattr(const char *fname, - const char *name) +int +smbc_removexattr(const char *fname, + const char *name) { - return (statcont->removexattr)(statcont, fname, name); + return smbc_getFunctionRemovexattr(statcont)(statcont, fname, name); } -int smbc_lremovexattr(const char *fname, - const char *name) +int +smbc_lremovexattr(const char *fname, + const char *name) { - return (statcont->removexattr)(statcont, fname, name); + return smbc_getFunctionRemovexattr(statcont)(statcont, fname, name); } -int smbc_fremovexattr(int fd, - const char *name) +int +smbc_fremovexattr(int fd, + const char *name) { SMBCFILE * file = find_fd(fd); if (file == NULL) { errno = EBADF; return -1; } - return (statcont->removexattr)(statcont, file->fname, name); + return smbc_getFunctionRemovexattr(statcont)(statcont, + file->fname, name); } -int smbc_listxattr(const char *fname, - char *list, - size_t size) +int +smbc_listxattr(const char *fname, + char *list, + size_t size) { - return (statcont->listxattr)(statcont, fname, list, size); + return smbc_getFunctionListxattr(statcont)(statcont, + fname, list, size); } -int smbc_llistxattr(const char *fname, - char *list, - size_t size) +int +smbc_llistxattr(const char *fname, + char *list, + size_t size) { - return (statcont->listxattr)(statcont, fname, list, size); + return smbc_getFunctionListxattr(statcont)(statcont, + fname, list, size); } -int smbc_flistxattr(int fd, - char *list, - size_t size) +int +smbc_flistxattr(int fd, + char *list, + size_t size) { SMBCFILE * file = find_fd(fd); if (file == NULL) { errno = EBADF; return -1; } - return (statcont->listxattr)(statcont, file->fname, list, size); + return smbc_getFunctionListxattr(statcont)(statcont, + file->fname, list, size); } -int smbc_print_file(const char *fname, const char *printq) +int +smbc_print_file(const char *fname, + const char *printq) { - return (statcont->print_file)(statcont, fname, statcont, printq); + return smbc_getFunctionPrintFile(statcont)(statcont, fname, + statcont, printq); } -int smbc_open_print_job(const char *fname) +int +smbc_open_print_job(const char *fname) { - SMBCFILE * file = (statcont->open_print_job)(statcont, fname); + SMBCFILE * file; + + file = smbc_getFunctionOpenPrintJob(statcont)(statcont, fname); if (!file) return -1; return file->cli_fd; } -int smbc_list_print_jobs(const char *purl, smbc_list_print_job_fn fn) +int +smbc_list_print_jobs(const char *purl, + smbc_list_print_job_fn fn) { - return (statcont->list_print_jobs)(statcont, purl, fn); + return smbc_getFunctionListPrintJobs(statcont)(statcont, purl, fn); } -int smbc_unlink_print_job(const char *purl, int id) +int +smbc_unlink_print_job(const char *purl, + int id) { - return (statcont->unlink_print_job)(statcont, purl, id); + return smbc_getFunctionUnlinkPrintJob(statcont)(statcont, purl, id); } diff --git a/source3/libsmb/libsmb_context.c b/source3/libsmb/libsmb_context.c new file mode 100644 index 0000000000..1505d50a43 --- /dev/null +++ b/source3/libsmb/libsmb_context.c @@ -0,0 +1,1283 @@ +/* + Unix SMB/Netbios implementation. + SMB client library implementation + Copyright (C) Andrew Tridgell 1998 + Copyright (C) Richard Sharpe 2000, 2002 + Copyright (C) John Terpstra 2000 + Copyright (C) Tom Jansen (Ninja ISD) 2002 + Copyright (C) Derrell Lipman 2003-2008 + 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 + 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 . +*/ + +#include "includes.h" +#include "libsmbclient.h" +#include "libsmb_internal.h" + + +/* + * Is the logging working / configfile read ? + */ +static int SMBC_initialized = 0; + + + +/* + * Get a new empty handle to fill in with your own info + */ +SMBCCTX * +smbc_new_context(void) +{ + SMBCCTX *context; + + context = SMB_MALLOC_P(SMBCCTX); + if (!context) { + errno = ENOMEM; + return NULL; + } + + + /* Initialize the context and establish reasonable defaults */ + ZERO_STRUCTP(context); + + context->debug = 0; + context->timeout = 20000; /* 20 seconds */ + + context->full_time_names = False; + context->share_mode = SMBC_SHAREMODE_DENY_NONE; + context->smb_encryption_level = 0; + context->browse_max_lmb_count = 3; /* # LMBs to query */ + context->urlencode_readdir_entries = False; + context->one_share_per_server = False; + context->use_kerberos = False; + context->fallback_after_kerberos = False; + context->no_auto_anonymous_login = False; + + context->server.get_auth_data_fn = SMBC_get_auth_data; + context->server.check_server_fn = SMBC_check_server; + context->server.remove_unused_server_fn = SMBC_remove_unused_server; + + context->cache.server_cache_data = NULL; + context->cache.add_cached_server_fn = SMBC_add_cached_server; + context->cache.get_cached_server_fn = SMBC_get_cached_server; + context->cache.remove_cached_server_fn = SMBC_remove_cached_server; + context->cache.purge_cached_server_fn = SMBC_purge_cached_servers; + + context->posix_emu.open_fn = SMBC_open_ctx; + context->posix_emu.creat_fn = SMBC_creat_ctx; + context->posix_emu.read_fn = SMBC_read_ctx; + context->posix_emu.write_fn = SMBC_write_ctx; + context->posix_emu.close_fn = SMBC_close_ctx; + context->posix_emu.unlink_fn = SMBC_unlink_ctx; + context->posix_emu.rename_fn = SMBC_rename_ctx; + context->posix_emu.lseek_fn = SMBC_lseek_ctx; + context->posix_emu.ftruncate_fn = SMBC_ftruncate_ctx; + context->posix_emu.stat_fn = SMBC_stat_ctx; + context->posix_emu.fstat_fn = SMBC_fstat_ctx; + context->posix_emu.opendir_fn = SMBC_opendir_ctx; + context->posix_emu.closedir_fn = SMBC_closedir_ctx; + context->posix_emu.readdir_fn = SMBC_readdir_ctx; + context->posix_emu.getdents_fn = SMBC_getdents_ctx; + context->posix_emu.mkdir_fn = SMBC_mkdir_ctx; + context->posix_emu.rmdir_fn = SMBC_rmdir_ctx; + context->posix_emu.telldir_fn = SMBC_telldir_ctx; + context->posix_emu.lseekdir_fn = SMBC_lseekdir_ctx; + context->posix_emu.fstatdir_fn = SMBC_fstatdir_ctx; + context->posix_emu.chmod_fn = SMBC_chmod_ctx; + context->posix_emu.utimes_fn = SMBC_utimes_ctx; + context->posix_emu.setxattr_fn = SMBC_setxattr_ctx; + context->posix_emu.getxattr_fn = SMBC_getxattr_ctx; + context->posix_emu.removexattr_fn = SMBC_removexattr_ctx; + context->posix_emu.listxattr_fn = SMBC_listxattr_ctx; + + context->printing.open_print_job_fn = SMBC_open_print_job_ctx; + context->printing.print_file_fn = SMBC_print_file_ctx; + context->printing.list_print_jobs_fn = SMBC_list_print_jobs_ctx; + context->printing.unlink_print_job_fn = SMBC_unlink_print_job_ctx; + + return context; +} + +/* + * Free a context + * + * Returns 0 on success. Otherwise returns 1, the SMBCCTX is _not_ freed + * and thus you'll be leaking memory if not handled properly. + * + */ +int +smbc_free_context(SMBCCTX *context, + int shutdown_ctx) +{ + if (!context) { + errno = EBADF; + return 1; + } + + if (shutdown_ctx) { + SMBCFILE * f; + DEBUG(1,("Performing aggressive shutdown.\n")); + + f = context->files; + while (f) { + (context->posix_emu.close_fn)(context, f); + f = f->next; + } + context->files = NULL; + + /* First try to remove the servers the nice way. */ + if (context->cache.purge_cached_server_fn(context)) { + SMBCSRV * s; + SMBCSRV * next; + DEBUG(1, ("Could not purge all servers, " + "Nice way shutdown failed.\n")); + s = context->servers; + while (s) { + DEBUG(1, ("Forced shutdown: %p (fd=%d)\n", + s, s->cli->fd)); + cli_shutdown(s->cli); + (context->cache.remove_cached_server_fn)(context, + s); + next = s->next; + DLIST_REMOVE(context->servers, s); + SAFE_FREE(s); + s = next; + } + context->servers = NULL; + } + } + else { + /* This is the polite way */ + if ((context->cache.purge_cached_server_fn)(context)) { + DEBUG(1, ("Could not purge all servers, " + "free_context failed.\n")); + errno = EBUSY; + return 1; + } + if (context->servers) { + DEBUG(1, ("Active servers in context, " + "free_context failed.\n")); + errno = EBUSY; + return 1; + } + if (context->files) { + DEBUG(1, ("Active files in context, " + "free_context failed.\n")); + errno = EBUSY; + return 1; + } + } + + /* Things we have to clean up */ + SAFE_FREE(context->workgroup); + SAFE_FREE(context->netbios_name); + SAFE_FREE(context->user); + + DEBUG(3, ("Context %p successfully freed\n", context)); + SAFE_FREE(context); + return 0; +} + + +/* + * Each time the context structure is changed, we have binary backward + * compatibility issues. Instead of modifying the public portions of the + * context structure to add new options, instead, we put them in the internal + * portion of the context structure and provide a set function for these new + * options. + */ +void +smbc_option_set(SMBCCTX *context, + char *option_name, + ... /* option_value */) +{ + va_list ap; + union { + int i; + bool b; + smbc_get_auth_data_with_context_fn auth_fn; + void *v; + const char *s; + } option_value; + + va_start(ap, option_name); + + if (strcmp(option_name, "debug_to_stderr") == 0) { + /* + * Log to standard error instead of standard output. + */ + option_value.b = (bool) va_arg(ap, int); + context->debug_stderr = option_value.b; + + } else if (strcmp(option_name, "full_time_names") == 0) { + /* + * Use new-style time attribute names, e.g. WRITE_TIME rather + * than the old-style names such as M_TIME. This allows also + * setting/getting CREATE_TIME which was previously + * unimplemented. (Note that the old C_TIME was supposed to + * be CHANGE_TIME but was confused and sometimes referred to + * CREATE_TIME.) + */ + option_value.b = (bool) va_arg(ap, int); + context->full_time_names = option_value.b; + + } else if (strcmp(option_name, "open_share_mode") == 0) { + /* + * The share mode to use for files opened with + * SMBC_open_ctx(). The default is SMBC_SHAREMODE_DENY_NONE. + */ + option_value.i = va_arg(ap, int); + context->share_mode = (smbc_share_mode) option_value.i; + + } else if (strcmp(option_name, "user_data") == 0) { + /* + * Save a user data handle which may be retrieved by the user + * with smbc_option_get() + */ + option_value.v = va_arg(ap, void *); + context->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->smb_encryption_level = 0; + } else if (strcmp(option_value.s, "request") == 0) { + context->smb_encryption_level = 1; + } else if (strcmp(option_value.s, "require") == 0) { + context->smb_encryption_level = 2; + } + } else if (strcmp(option_name, "browse_max_lmb_count") == 0) { + /* + * From how many local master browsers should the list of + * workgroups be retrieved? It can take up to 12 minutes or + * longer after a server becomes a local master browser, for + * it to have the entire browse list (the list of + * workgroups/domains) from an entire network. Since a client + * never knows which local master browser will be found first, + * the one which is found first and used to retrieve a browse + * list may have an incomplete or empty browse list. By + * requesting the browse list from multiple local master + * browsers, a more complete list can be generated. For small + * networks (few workgroups), it is recommended that this + * value be set to 0, causing the browse lists from all found + * local master browsers to be retrieved and merged. For + * networks with many workgroups, a suitable value for this + * variable is probably somewhere around 3. (Default: 3). + */ + option_value.i = va_arg(ap, int); + context->browse_max_lmb_count = option_value.i; + + } else if (strcmp(option_name, "urlencode_readdir_entries") == 0) { + /* + * There is a difference in the desired return strings from + * smbc_readdir() depending upon whether the filenames are to + * be displayed to the user, or whether they are to be + * appended to the path name passed to smbc_opendir() to call + * a further smbc_ function (e.g. open the file with + * smbc_open()). In the former case, the filename should be + * in "human readable" form. In the latter case, the smbc_ + * functions expect a URL which must be url-encoded. Those + * functions decode the URL. If, for example, smbc_readdir() + * returned a file name of "abc%20def.txt", passing a path + * with this file name attached to smbc_open() would cause + * smbc_open to attempt to open the file "abc def.txt" since + * the %20 is decoded into a space. + * + * Set this option to True if the names returned by + * smbc_readdir() should be url-encoded such that they can be + * passed back to another smbc_ call. Set it to False if the + * names returned by smbc_readdir() are to be presented to the + * user. + * + * For backwards compatibility, this option defaults to False. + */ + option_value.b = (bool) va_arg(ap, int); + context->urlencode_readdir_entries = option_value.b; + + } else if (strcmp(option_name, "one_share_per_server") == 0) { + /* + * Some Windows versions appear to have a limit to the number + * of concurrent SESSIONs and/or TREE CONNECTions. In + * one-shot programs (i.e. the program runs and then quickly + * ends, thereby shutting down all connections), it is + * probably reasonable to establish a new connection for each + * share. In long-running applications, the limitation can be + * avoided by using only a single connection to each server, + * and issuing a new TREE CONNECT when the share is accessed. + */ + option_value.b = (bool) va_arg(ap, int); + context->one_share_per_server = option_value.b; + + } else if (strcmp(option_name, "use_kerberos") == 0) { + option_value.b = (bool) va_arg(ap, int); + context->use_kerberos = option_value.b; + + } else if (strcmp(option_name, "fallback_after_kerberos") == 0) { + option_value.b = (bool) va_arg(ap, int); + context->fallback_after_kerberos = option_value.b; + + } else if (strcmp(option_name, "no_auto_anonymous_login") == 0) { + option_value.b = (bool) va_arg(ap, int); + context->no_auto_anonymous_login = option_value.b; + } + + va_end(ap); +} + + +/* + * Retrieve the current value of an option + */ +void * +smbc_option_get(SMBCCTX *context, + char *option_name) +{ + if (strcmp(option_name, "debug_stderr") == 0) { + /* + * Log to standard error instead of standard output. + */ +#if defined(__intptr_t_defined) || defined(HAVE_INTPTR_T) + return (void *) (intptr_t) context->debug_stderr; +#else + return (void *) context->debug_stderr; +#endif + + } else if (strcmp(option_name, "full_time_names") == 0) { + /* + * Use new-style time attribute names, e.g. WRITE_TIME rather + * than the old-style names such as M_TIME. This allows also + * setting/getting CREATE_TIME which was previously + * unimplemented. (Note that the old C_TIME was supposed to + * be CHANGE_TIME but was confused and sometimes referred to + * CREATE_TIME.) + */ +#if defined(__intptr_t_defined) || defined(HAVE_INTPTR_T) + return (void *) (intptr_t) context->full_time_names; +#else + return (void *) context->full_time_names; +#endif + + } else if (strcmp(option_name, "user_data") == 0) { + /* + * Return the user data handle which was saved by the user + * with smbc_option_set() + */ + return context->user_data; + + } else if (strcmp(option_name, "smb_encrypt_level") == 0) { + /* + * Return the current smb encrypt negotiate option as a string. + */ + switch (context->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->servers; s; s = s->next) { + num_servers++; + if (s->cli->trans_enc_state == NULL) { + return (void *)false; + } + } +#if defined(__intptr_t_defined) || defined(HAVE_INTPTR_T) + return (void *) (intptr_t) (bool) (num_servers > 0); +#else + return (void *) (bool) (num_servers > 0); +#endif + + } else if (strcmp(option_name, "browse_max_lmb_count") == 0) { + /* + * From how many local master browsers should the list of + * workgroups be retrieved? It can take up to 12 minutes or + * longer after a server becomes a local master browser, for + * it to have the entire browse list (the list of + * workgroups/domains) from an entire network. Since a client + * never knows which local master browser will be found first, + * the one which is found first and used to retrieve a browse + * list may have an incomplete or empty browse list. By + * requesting the browse list from multiple local master + * browsers, a more complete list can be generated. For small + * networks (few workgroups), it is recommended that this + * value be set to 0, causing the browse lists from all found + * local master browsers to be retrieved and merged. For + * networks with many workgroups, a suitable value for this + * variable is probably somewhere around 3. (Default: 3). + */ +#if defined(__intptr_t_defined) || defined(HAVE_INTPTR_T) + return (void *) (intptr_t) context->browse_max_lmb_count; +#else + return (void *) context->browse_max_lmb_count; +#endif + + } else if (strcmp(option_name, "urlencode_readdir_entries") == 0) { + /* + * There is a difference in the desired return strings from + * smbc_readdir() depending upon whether the filenames are to + * be displayed to the user, or whether they are to be + * appended to the path name passed to smbc_opendir() to call + * a further smbc_ function (e.g. open the file with + * smbc_open()). In the former case, the filename should be + * in "human readable" form. In the latter case, the smbc_ + * functions expect a URL which must be url-encoded. Those + * functions decode the URL. If, for example, smbc_readdir() + * returned a file name of "abc%20def.txt", passing a path + * with this file name attached to smbc_open() would cause + * smbc_open to attempt to open the file "abc def.txt" since + * the %20 is decoded into a space. + * + * Set this option to True if the names returned by + * smbc_readdir() should be url-encoded such that they can be + * passed back to another smbc_ call. Set it to False if the + * names returned by smbc_readdir() are to be presented to the + * user. + * + * For backwards compatibility, this option defaults to False. + */ +#if defined(__intptr_t_defined) || defined(HAVE_INTPTR_T) + return (void *) (intptr_t) context->urlencode_readdir_entries; +#else + return (void *) (bool) context->urlencode_readdir_entries; +#endif + + } else if (strcmp(option_name, "one_share_per_server") == 0) { + /* + * Some Windows versions appear to have a limit to the number + * of concurrent SESSIONs and/or TREE CONNECTions. In + * one-shot programs (i.e. the program runs and then quickly + * ends, thereby shutting down all connections), it is + * probably reasonable to establish a new connection for each + * share. In long-running applications, the limitation can be + * avoided by using only a single connection to each server, + * and issuing a new TREE CONNECT when the share is accessed. + */ +#if defined(__intptr_t_defined) || defined(HAVE_INTPTR_T) + return (void *) (intptr_t) context->one_share_per_server; +#else + return (void *) (bool) context->one_share_per_server; +#endif + + } else if (strcmp(option_name, "use_kerberos") == 0) { +#if defined(__intptr_t_defined) || defined(HAVE_INTPTR_T) + return (void *) (intptr_t) context->use_kerberos; +#else + return (void *) (bool) context->use_kerberos; +#endif + + } else if (strcmp(option_name, "fallback_after_kerberos") == 0) { +#if defined(__intptr_t_defined) || defined(HAVE_INTPTR_T) + return (void *) (intptr_t) context->fallback_after_kerberos; +#else + return (void *) (bool) context->fallback_after_kerberos; +#endif + + } else if (strcmp(option_name, "no_auto_anonymous_login") == 0) { +#if defined(__intptr_t_defined) || defined(HAVE_INTPTR_T) + return (void *) (intptr_t) context->no_auto_anonymous_login; +#else + return (void *) (bool) context->no_auto_anonymous_login; +#endif + } + + return NULL; +} + + +/* + * Initialize the library, etc. + * + * We accept a struct containing handle information. + * valid values for info->debug from 0 to 100, + * and insist that info->fn must be non-null. + */ +SMBCCTX * +smbc_init_context(SMBCCTX *context) +{ + int pid; + char *user = NULL; + char *home = NULL; + extern bool in_client; + + if (!context) { + errno = EBADF; + return NULL; + } + + /* Do not initialise the same client twice */ + if (context->initialized) { + return 0; + } + + if (!context->server.get_auth_data_fn || + context->debug < 0 || + context->debug > 100) { + + errno = EINVAL; + return NULL; + + } + + if (!SMBC_initialized) { + /* + * Do some library-wide intializations the first time we get + * called + */ + bool conf_loaded = False; + TALLOC_CTX *frame = talloc_stackframe(); + + /* Set this to what the user wants */ + DEBUGLEVEL = context->debug; + + load_case_tables(); + + setup_logging("libsmbclient", True); + if (context->debug_stderr) { + dbf = x_stderr; + x_setbuf(x_stderr, NULL); + } + + /* Here we would open the smb.conf file if needed ... */ + + in_client = True; /* FIXME, make a param */ + + home = getenv("HOME"); + if (home) { + char *conf = NULL; + if (asprintf(&conf, "%s/.smb/smb.conf", home) > 0) { + if (lp_load(conf, True, False, False, True)) { + conf_loaded = True; + } else { + DEBUG(5, ("Could not load config file: %s\n", + conf)); + } + SAFE_FREE(conf); + } + } + + if (!conf_loaded) { + /* + * Well, if that failed, try the get_dyn_CONFIGFILE + * Which points to the standard locn, and if that + * fails, silently ignore it and use the internal + * defaults ... + */ + + if (!lp_load(get_dyn_CONFIGFILE(), True, False, False, False)) { + DEBUG(5, ("Could not load config file: %s\n", + get_dyn_CONFIGFILE())); + } else if (home) { + char *conf; + /* + * We loaded the global config file. Now lets + * load user-specific modifications to the + * global config. + */ + if (asprintf(&conf, + "%s/.smb/smb.conf.append", + home) > 0) { + if (!lp_load(conf, True, False, False, False)) { + DEBUG(10, + ("Could not append config file: " + "%s\n", + conf)); + } + SAFE_FREE(conf); + } + } + } + + load_interfaces(); /* Load the list of interfaces ... */ + + reopen_logs(); /* Get logging working ... */ + + /* + * Block SIGPIPE (from lib/util_sock.c: write()) + * It is not needed and should not stop execution + */ + BlockSignals(True, SIGPIPE); + + /* Done with one-time initialisation */ + SMBC_initialized = 1; + + TALLOC_FREE(frame); + } + + if (!context->user) { + /* + * FIXME: Is this the best way to get the user info? + */ + user = getenv("USER"); + /* walk around as "guest" if no username can be found */ + if (!user) context->user = SMB_STRDUP("guest"); + else context->user = SMB_STRDUP(user); + } + + if (!context->netbios_name) { + /* + * We try to get our netbios name from the config. If that + * fails we fall back on constructing our netbios name from + * our hostname etc + */ + if (global_myname()) { + context->netbios_name = SMB_STRDUP(global_myname()); + } + else { + /* + * Hmmm, I want to get hostname as well, but I am too + * lazy for the moment + */ + pid = sys_getpid(); + context->netbios_name = (char *)SMB_MALLOC(17); + if (!context->netbios_name) { + errno = ENOMEM; + return NULL; + } + slprintf(context->netbios_name, 16, + "smbc%s%d", context->user, pid); + } + } + + DEBUG(1, ("Using netbios name %s.\n", context->netbios_name)); + + if (!context->workgroup) { + if (lp_workgroup()) { + context->workgroup = SMB_STRDUP(lp_workgroup()); + } + else { + /* TODO: Think about a decent default workgroup */ + context->workgroup = SMB_STRDUP("samba"); + } + } + + DEBUG(1, ("Using workgroup %s.\n", context->workgroup)); + + /* shortest timeout is 1 second */ + if (context->timeout > 0 && context->timeout < 1000) + context->timeout = 1000; + + /* + * FIXME: Should we check the function pointers here? + */ + + context->initialized = True; + + return context; +} + + +/* Return the verion of samba, and thus libsmbclient */ +const char * +smbc_version(void) +{ + return samba_version_string(); +} + + +/** Get the netbios name used for making connections */ +char * +smbc_getNetbiosName(SMBCCTX *c) +{ + return c->netbios_name; +} + +/** Set the netbios name used for making connections */ +void +smbc_setNetbiosName(SMBCCTX *c, char * netbios_name) +{ + c->netbios_name = netbios_name; +} + +/** Get the workgroup used for making connections */ +char * +smbc_getWorkgroup(SMBCCTX *c) +{ + return c->workgroup; +} + +/** Set the workgroup used for making connections */ +void +smbc_setWorkgroup(SMBCCTX *c, char * workgroup) +{ + c->workgroup = workgroup; +} + +/** Get the username used for making connections */ +char * +smbc_getUser(SMBCCTX *c) +{ + return c->user; +} + +/** Set the username used for making connections */ +void +smbc_setUser(SMBCCTX *c, char * user) +{ + c->user = user; +} + +/** Get the debug level */ +int +smbc_getDebug(SMBCCTX *c) +{ + return c->debug; +} + +/** Set the debug level */ +void +smbc_setDebug(SMBCCTX *c, int debug) +{ + c->debug = debug; +} + +/** + * Get the timeout used for waiting on connections and response data + * (in milliseconds) + */ +int +smbc_getTimeout(SMBCCTX *c) +{ + return c->timeout; +} + +/** + * Set the timeout used for waiting on connections and response data + * (in milliseconds) + */ +void +smbc_setTimeout(SMBCCTX *c, int timeout) +{ + c->timeout = timeout; +} + +/** Get the function for obtaining authentication data */ + +smbc_get_auth_data_fn +smbc_getFunctionAuthData(SMBCCTX *c) +{ + return c->server.get_auth_data_fn; +} + +/** Set the function for obtaining authentication data */ +void +smbc_setFunctionAuthData(SMBCCTX *c, smbc_get_auth_data_fn fn) +{ + c->server.get_auth_data_fn = fn; +} + +/** Get the function for checking if a server is still good */ +smbc_check_server_fn +smbc_getFunctionCheckServer(SMBCCTX *c) +{ + return c->server.check_server_fn; +} + +/** Set the function for checking if a server is still good */ +void +smbc_setFunctionCheckServer(SMBCCTX *c, smbc_check_server_fn fn) +{ + c->server.check_server_fn = fn; +} + +/** Get the function for removing a server if unused */ +smbc_remove_unused_server_fn +smbc_getFunctionRemoveUnusedServer(SMBCCTX *c) +{ + return c->server.remove_unused_server_fn; +} + +/** Set the function for removing a server if unused */ +void +smbc_setFunctionRemoveUnusedServer(SMBCCTX *c, + smbc_remove_unused_server_fn fn) +{ + c->server.remove_unused_server_fn = fn; +} + +/** Get the function to store private data of the server cache */ +struct +smbc_server_cache * smbc_getServerCacheData(SMBCCTX *c) +{ + return c->cache.server_cache_data; +} + +/** Set the function to store private data of the server cache */ +void +smbc_setServerCacheData(SMBCCTX *c, struct smbc_server_cache * cache) +{ + c->cache.server_cache_data = cache; +} + + +/** Get the function for adding a cached server */ +smbc_add_cached_srv_fn +smbc_getFunctionAddCachedServer(SMBCCTX *c) +{ + return c->cache.add_cached_server_fn; +} + +/** Set the function for adding a cached server */ +void +smbc_setFunctionAddCachedServer(SMBCCTX *c, smbc_add_cached_srv_fn fn) +{ + c->cache.add_cached_server_fn = fn; +} + +/** Get the function for server cache lookup */ +smbc_get_cached_srv_fn +smbc_getFunctionGetCachedServer(SMBCCTX *c) +{ + return c->cache.get_cached_server_fn; +} + +/** Set the function for server cache lookup */ +void +smbc_setFunctionGetCachedServer(SMBCCTX *c, smbc_get_cached_srv_fn fn) +{ + c->cache.get_cached_server_fn = fn; +} + +/** Get the function for server cache removal */ +smbc_remove_cached_srv_fn +smbc_getFunctionRemoveCachedServer(SMBCCTX *c) +{ + return c->cache.remove_cached_server_fn; +} + +/** Set the function for server cache removal */ +void +smbc_setFunctionRemoveCachedServer(SMBCCTX *c, + smbc_remove_cached_srv_fn fn) +{ + c->cache.remove_cached_server_fn = fn; +} + +/** + * Get the function for server cache purging. This function tries to + * remove all cached servers (e.g. on disconnect) + */ +smbc_purge_cached_srv_fn +smbc_getFunctionPurgeCachedServers(SMBCCTX *c) +{ + return c->cache.purge_cached_server_fn; +} + +/** + * Set the function for server cache purging. This function tries to + * remove all cached servers (e.g. on disconnect) + */ +void +smbc_setFunctionPurgeCachedServers(SMBCCTX *c, smbc_purge_cached_srv_fn fn) +{ + c->cache.purge_cached_server_fn = fn; +} + +/** + * Callable functions for files. + */ + +smbc_open_fn +smbc_getFunctionOpen(SMBCCTX *c) +{ + return c->posix_emu.open_fn; +} + +void +smbc_setFunctionOpen(SMBCCTX *c, smbc_open_fn fn) +{ + c->posix_emu.open_fn = fn; +} + +smbc_creat_fn +smbc_getFunctionCreat(SMBCCTX *c) +{ + return c->posix_emu.creat_fn; +} + +void +smbc_setFunctionCreat(SMBCCTX *c, smbc_creat_fn fn) +{ + c->posix_emu.creat_fn = fn; +} + +smbc_read_fn +smbc_getFunctionRead(SMBCCTX *c) +{ + return c->posix_emu.read_fn; +} + +void +smbc_setFunctionRead(SMBCCTX *c, smbc_read_fn fn) +{ + c->posix_emu.read_fn = fn; +} + +smbc_write_fn +smbc_getFunctionWrite(SMBCCTX *c) +{ + return c->posix_emu.write_fn; +} + +void +smbc_setFunctionWrite(SMBCCTX *c, smbc_write_fn fn) +{ + c->posix_emu.write_fn = fn; +} + +smbc_unlink_fn +smbc_getFunctionUnlink(SMBCCTX *c) +{ + return c->posix_emu.unlink_fn; +} + +void +smbc_setFunctionUnlink(SMBCCTX *c, smbc_unlink_fn fn) +{ + c->posix_emu.unlink_fn = fn; +} + +smbc_rename_fn +smbc_getFunctionRename(SMBCCTX *c) +{ + return c->posix_emu.rename_fn; +} + +void +smbc_setFunctionRename(SMBCCTX *c, smbc_rename_fn fn) +{ + c->posix_emu.rename_fn = fn; +} + +smbc_lseek_fn +smbc_getFunctionLseek(SMBCCTX *c) +{ + return c->posix_emu.lseek_fn; +} + +void +smbc_setFunctionLseek(SMBCCTX *c, smbc_lseek_fn fn) +{ + c->posix_emu.lseek_fn = fn; +} + +smbc_stat_fn +smbc_getFunctionStat(SMBCCTX *c) +{ + return c->posix_emu.stat_fn; +} + +void +smbc_setFunctionStat(SMBCCTX *c, smbc_stat_fn fn) +{ + c->posix_emu.stat_fn = fn; +} + +smbc_fstat_fn +smbc_getFunctionFstat(SMBCCTX *c) +{ + return c->posix_emu.fstat_fn; +} + +void +smbc_setFunctionFstat(SMBCCTX *c, smbc_fstat_fn fn) +{ + c->posix_emu.fstat_fn = fn; +} + +smbc_ftruncate_fn +smbc_getFunctionFtruncate(SMBCCTX *c) +{ + return c->posix_emu.ftruncate_fn; +} + +void +smbc_setFunctionFtruncate(SMBCCTX *c, smbc_ftruncate_fn fn) +{ + c->posix_emu.ftruncate_fn = fn; +} + +smbc_close_fn +smbc_getFunctionClose(SMBCCTX *c) +{ + return c->posix_emu.close_fn; +} + +void +smbc_setFunctionClose(SMBCCTX *c, smbc_close_fn fn) +{ + c->posix_emu.close_fn = fn; +} + + +/** + * Callable functions for directories. + */ + +smbc_opendir_fn +smbc_getFunctionOpendir(SMBCCTX *c) +{ + return c->posix_emu.opendir_fn; +} + +void +smbc_setFunctionOpendir(SMBCCTX *c, smbc_opendir_fn fn) +{ + c->posix_emu.opendir_fn = fn; +} + +smbc_closedir_fn +smbc_getFunctionClosedir(SMBCCTX *c) +{ + return c->posix_emu.closedir_fn; +} + +void +smbc_setFunctionClosedir(SMBCCTX *c, smbc_closedir_fn fn) +{ + c->posix_emu.closedir_fn = fn; +} + +smbc_readdir_fn +smbc_getFunctionReaddir(SMBCCTX *c) +{ + return c->posix_emu.readdir_fn; +} + +void +smbc_setFunctionReaddir(SMBCCTX *c, smbc_readdir_fn fn) +{ + c->posix_emu.readdir_fn = fn; +} + +smbc_getdents_fn +smbc_getFunctionGetdents(SMBCCTX *c) +{ + return c->posix_emu.getdents_fn; +} + +void +smbc_setFunctionGetdents(SMBCCTX *c, smbc_getdents_fn fn) +{ + c->posix_emu.getdents_fn = fn; +} + +smbc_mkdir_fn +smbc_getFunctionMkdir(SMBCCTX *c) +{ + return c->posix_emu.mkdir_fn; +} + +void +smbc_setFunctionMkdir(SMBCCTX *c, smbc_mkdir_fn fn) +{ + c->posix_emu.mkdir_fn = fn; +} + +smbc_rmdir_fn +smbc_getFunctionRmdir(SMBCCTX *c) +{ + return c->posix_emu.rmdir_fn; +} + +void +smbc_setFunctionRmdir(SMBCCTX *c, smbc_rmdir_fn fn) +{ + c->posix_emu.rmdir_fn = fn; +} + +smbc_telldir_fn +smbc_getFunctionTelldir(SMBCCTX *c) +{ + return c->posix_emu.telldir_fn; +} + +void +smbc_setFunctionTelldir(SMBCCTX *c, smbc_telldir_fn fn) +{ + c->posix_emu.telldir_fn = fn; +} + +smbc_lseekdir_fn +smbc_getFunctionLseekdir(SMBCCTX *c) +{ + return c->posix_emu.lseekdir_fn; +} + +void +smbc_setFunctionLseekdir(SMBCCTX *c, smbc_lseekdir_fn fn) +{ + c->posix_emu.lseekdir_fn = fn; +} + +smbc_fstatdir_fn +smbc_getFunctionFstatdir(SMBCCTX *c) +{ + return c->posix_emu.fstatdir_fn; +} + +void +smbc_setFunctionFstatdir(SMBCCTX *c, smbc_fstatdir_fn fn) +{ + c->posix_emu.fstatdir_fn = fn; +} + + +/** + * Callable functions applicable to both files and directories. + */ + +smbc_chmod_fn +smbc_getFunctionChmod(SMBCCTX *c) +{ + return c->posix_emu.chmod_fn; +} + +void +smbc_setFunctionChmod(SMBCCTX *c, smbc_chmod_fn fn) +{ + c->posix_emu.chmod_fn = fn; +} + +smbc_utimes_fn +smbc_getFunctionUtimes(SMBCCTX *c) +{ + return c->posix_emu.utimes_fn; +} + +void +smbc_setFunctionUtimes(SMBCCTX *c, smbc_utimes_fn fn) +{ + c->posix_emu.utimes_fn = fn; +} + +smbc_setxattr_fn +smbc_getFunctionSetxattr(SMBCCTX *c) +{ + return c->posix_emu.setxattr_fn; +} + +void +smbc_setFunctionSetxattr(SMBCCTX *c, smbc_setxattr_fn fn) +{ + c->posix_emu.setxattr_fn = fn; +} + +smbc_getxattr_fn +smbc_getFunctionGetxattr(SMBCCTX *c) +{ + return c->posix_emu.getxattr_fn; +} + +void +smbc_setFunctionGetxattr(SMBCCTX *c, smbc_getxattr_fn fn) +{ + c->posix_emu.getxattr_fn = fn; +} + +smbc_removexattr_fn +smbc_getFunctionRemovexattr(SMBCCTX *c) +{ + return c->posix_emu.removexattr_fn; +} + +void +smbc_setFunctionRemovexattr(SMBCCTX *c, smbc_removexattr_fn fn) +{ + c->posix_emu.removexattr_fn = fn; +} + +smbc_listxattr_fn +smbc_getFunctionListxattr(SMBCCTX *c) +{ + return c->posix_emu.listxattr_fn; +} + +void +smbc_setFunctionListxattr(SMBCCTX *c, smbc_listxattr_fn fn) +{ + c->posix_emu.listxattr_fn = fn; +} + + +/** + * Callable functions related to printing + */ + +smbc_print_file_fn +smbc_getFunctionPrintFile(SMBCCTX *c) +{ + return c->printing.print_file_fn; +} + +void +smbc_setFunctionPrintFile(SMBCCTX *c, smbc_print_file_fn fn) +{ + c->printing.print_file_fn = fn; +} + +smbc_open_print_job_fn +smbc_getFunctionOpenPrintJob(SMBCCTX *c) +{ + return c->printing.open_print_job_fn; +} + +void +smbc_setFunctionOpenPrintJob(SMBCCTX *c, + smbc_open_print_job_fn fn) +{ + c->printing.open_print_job_fn = fn; +} + +smbc_list_print_jobs_fn +smbc_getFunctionListPrintJobs(SMBCCTX *c) +{ + return c->printing.list_print_jobs_fn; +} + +void +smbc_setFunctionListPrintJobs(SMBCCTX *c, + smbc_list_print_jobs_fn fn) +{ + c->printing.list_print_jobs_fn = fn; +} + +smbc_unlink_print_job_fn +smbc_getFunctionUnlinkPrintJob(SMBCCTX *c) +{ + return c->printing.unlink_print_job_fn; +} + +void +smbc_setFunctionUnlinkPrintJob(SMBCCTX *c, + smbc_unlink_print_job_fn fn) +{ + c->printing.unlink_print_job_fn = fn; +} + diff --git a/source3/libsmb/libsmb_dir.c b/source3/libsmb/libsmb_dir.c new file mode 100644 index 0000000000..9cb3351433 --- /dev/null +++ b/source3/libsmb/libsmb_dir.c @@ -0,0 +1,1928 @@ +/* + Unix SMB/Netbios implementation. + SMB client library implementation + Copyright (C) Andrew Tridgell 1998 + Copyright (C) Richard Sharpe 2000, 2002 + Copyright (C) John Terpstra 2000 + Copyright (C) Tom Jansen (Ninja ISD) 2002 + Copyright (C) Derrell Lipman 2003-2008 + 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 + 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 . +*/ + +#include "includes.h" +#include "libsmbclient.h" +#include "libsmb_internal.h" + + +/* + * Routine to open a directory + * We accept the URL syntax explained in SMBC_parse_path(), above. + */ + +static void +remove_dir(SMBCFILE *dir) +{ + struct smbc_dir_list *d,*f; + + d = dir->dir_list; + while (d) { + + f = d; d = d->next; + + SAFE_FREE(f->dirent); + SAFE_FREE(f); + + } + + dir->dir_list = dir->dir_end = dir->dir_next = NULL; + +} + +static int +add_dirent(SMBCFILE *dir, + const char *name, + const char *comment, + uint32 type) +{ + struct smbc_dirent *dirent; + int size; + int name_length = (name == NULL ? 0 : strlen(name)); + int comment_len = (comment == NULL ? 0 : strlen(comment)); + + /* + * Allocate space for the dirent, which must be increased by the + * size of the name and the comment and 1 each for the null terminator. + */ + + size = sizeof(struct smbc_dirent) + name_length + comment_len + 2; + + dirent = (struct smbc_dirent *)SMB_MALLOC(size); + + if (!dirent) { + + dir->dir_error = ENOMEM; + return -1; + + } + + ZERO_STRUCTP(dirent); + + if (dir->dir_list == NULL) { + + dir->dir_list = SMB_MALLOC_P(struct smbc_dir_list); + if (!dir->dir_list) { + + SAFE_FREE(dirent); + dir->dir_error = ENOMEM; + return -1; + + } + ZERO_STRUCTP(dir->dir_list); + + dir->dir_end = dir->dir_next = dir->dir_list; + } + else { + + dir->dir_end->next = SMB_MALLOC_P(struct smbc_dir_list); + + if (!dir->dir_end->next) { + + SAFE_FREE(dirent); + dir->dir_error = ENOMEM; + return -1; + + } + ZERO_STRUCTP(dir->dir_end->next); + + dir->dir_end = dir->dir_end->next; + } + + dir->dir_end->next = NULL; + dir->dir_end->dirent = dirent; + + dirent->smbc_type = type; + dirent->namelen = name_length; + dirent->commentlen = comment_len; + dirent->dirlen = size; + + /* + * dirent->namelen + 1 includes the null (no null termination needed) + * Ditto for dirent->commentlen. + * The space for the two null bytes was allocated. + */ + strncpy(dirent->name, (name?name:""), dirent->namelen + 1); + dirent->comment = (char *)(&dirent->name + dirent->namelen + 1); + strncpy(dirent->comment, (comment?comment:""), dirent->commentlen + 1); + + return 0; + +} + +static void +list_unique_wg_fn(const char *name, + uint32 type, + const char *comment, + void *state) +{ + SMBCFILE *dir = (SMBCFILE *)state; + struct smbc_dir_list *dir_list; + struct smbc_dirent *dirent; + int dirent_type; + int do_remove = 0; + + dirent_type = dir->dir_type; + + if (add_dirent(dir, name, comment, dirent_type) < 0) { + + /* An error occurred, what do we do? */ + /* FIXME: Add some code here */ + } + + /* Point to the one just added */ + dirent = dir->dir_end->dirent; + + /* See if this was a duplicate */ + for (dir_list = dir->dir_list; + dir_list != dir->dir_end; + dir_list = dir_list->next) { + if (! do_remove && + strcmp(dir_list->dirent->name, dirent->name) == 0) { + /* Duplicate. End end of list need to be removed. */ + do_remove = 1; + } + + if (do_remove && dir_list->next == dir->dir_end) { + /* Found the end of the list. Remove it. */ + dir->dir_end = dir_list; + free(dir_list->next); + free(dirent); + dir_list->next = NULL; + break; + } + } +} + +static void +list_fn(const char *name, + uint32 type, + const char *comment, + void *state) +{ + SMBCFILE *dir = (SMBCFILE *)state; + int dirent_type; + + /* + * We need to process the type a little ... + * + * Disk share = 0x00000000 + * Print share = 0x00000001 + * Comms share = 0x00000002 (obsolete?) + * IPC$ share = 0x00000003 + * + * administrative shares: + * ADMIN$, IPC$, C$, D$, E$ ... are type |= 0x80000000 + */ + + if (dir->dir_type == SMBC_FILE_SHARE) { + switch (type) { + case 0 | 0x80000000: + case 0: + dirent_type = SMBC_FILE_SHARE; + break; + + case 1: + dirent_type = SMBC_PRINTER_SHARE; + break; + + case 2: + dirent_type = SMBC_COMMS_SHARE; + break; + + case 3 | 0x80000000: + case 3: + dirent_type = SMBC_IPC_SHARE; + break; + + default: + dirent_type = SMBC_FILE_SHARE; /* FIXME, error? */ + break; + } + } + else { + dirent_type = dir->dir_type; + } + + if (add_dirent(dir, name, comment, dirent_type) < 0) { + + /* An error occurred, what do we do? */ + /* FIXME: Add some code here */ + + } +} + +static void +dir_list_fn(const char *mnt, + file_info *finfo, + const char *mask, + void *state) +{ + + if (add_dirent((SMBCFILE *)state, finfo->name, "", + (finfo->mode&aDIR?SMBC_DIR:SMBC_FILE)) < 0) { + + /* Handle an error ... */ + + /* FIXME: Add some code ... */ + + } + +} + +static int +net_share_enum_rpc(struct cli_state *cli, + void (*fn)(const char *name, + uint32 type, + const char *comment, + void *state), + void *state) +{ + int i; + WERROR result; + ENUM_HND enum_hnd; + uint32 info_level = 1; + uint32 preferred_len = 0xffffffff; + uint32 type; + SRV_SHARE_INFO_CTR ctr; + fstring name = ""; + fstring comment = ""; + struct rpc_pipe_client *pipe_hnd; + NTSTATUS nt_status; + + /* Open the server service pipe */ + pipe_hnd = cli_rpc_pipe_open_noauth(cli, PI_SRVSVC, &nt_status); + if (!pipe_hnd) { + DEBUG(1, ("net_share_enum_rpc pipe open fail!\n")); + return -1; + } + + /* Issue the NetShareEnum RPC call and retrieve the response */ + init_enum_hnd(&enum_hnd, 0); + result = rpccli_srvsvc_net_share_enum(pipe_hnd, + talloc_tos(), + info_level, + &ctr, + preferred_len, + &enum_hnd); + + /* Was it successful? */ + if (!W_ERROR_IS_OK(result) || ctr.num_entries == 0) { + /* Nope. Go clean up. */ + goto done; + } + + /* For each returned entry... */ + for (i = 0; i < ctr.num_entries; i++) { + + /* pull out the share name */ + rpcstr_pull_unistr2_fstring( + name, &ctr.share.info1[i].info_1_str.uni_netname); + + /* pull out the share's comment */ + rpcstr_pull_unistr2_fstring( + comment, &ctr.share.info1[i].info_1_str.uni_remark); + + /* Get the type value */ + type = ctr.share.info1[i].info_1.type; + + /* Add this share to the list */ + (*fn)(name, type, comment, state); + } + +done: + /* Close the server service pipe */ + cli_rpc_pipe_close(pipe_hnd); + + /* Tell 'em if it worked */ + return W_ERROR_IS_OK(result) ? 0 : -1; +} + + +/* + * Verify that the options specified in a URL are valid + */ +int +SMBC_check_options(char *server, + char *share, + char *path, + char *options) +{ + DEBUG(4, ("SMBC_check_options(): server='%s' share='%s' " + "path='%s' options='%s'\n", + server, share, path, options)); + + /* No options at all is always ok */ + if (! *options) return 0; + + /* Currently, we don't support any options. */ + return -1; +} + + +SMBCFILE * +SMBC_opendir_ctx(SMBCCTX *context, + const char *fname) +{ + int saved_errno; + char *server = NULL, *share = NULL, *user = NULL, *password = NULL, *options = NULL; + char *workgroup = NULL; + char *path = NULL; + uint16 mode; + char *p = NULL; + SMBCSRV *srv = NULL; + SMBCFILE *dir = NULL; + struct sockaddr_storage rem_ss; + TALLOC_CTX *frame = talloc_stackframe(); + + if (!context || !context->initialized) { + DEBUG(4, ("no valid context\n")); + errno = EINVAL + 8192; + TALLOC_FREE(frame); + return NULL; + + } + + if (!fname) { + DEBUG(4, ("no valid fname\n")); + errno = EINVAL + 8193; + TALLOC_FREE(frame); + return NULL; + } + + if (SMBC_parse_path(frame, + context, + fname, + &workgroup, + &server, + &share, + &path, + &user, + &password, + &options)) { + DEBUG(4, ("no valid path\n")); + errno = EINVAL + 8194; + TALLOC_FREE(frame); + return NULL; + } + + DEBUG(4, ("parsed path: fname='%s' server='%s' share='%s' " + "path='%s' options='%s'\n", + fname, server, share, path, options)); + + /* Ensure the options are valid */ + if (SMBC_check_options(server, share, path, options)) { + DEBUG(4, ("unacceptable options (%s)\n", options)); + errno = EINVAL + 8195; + TALLOC_FREE(frame); + return NULL; + } + + if (!user || user[0] == (char)0) { + user = talloc_strdup(frame, context->user); + if (!user) { + errno = ENOMEM; + TALLOC_FREE(frame); + return NULL; + } + } + + dir = SMB_MALLOC_P(SMBCFILE); + + if (!dir) { + errno = ENOMEM; + TALLOC_FREE(frame); + return NULL; + } + + ZERO_STRUCTP(dir); + + dir->cli_fd = 0; + dir->fname = SMB_STRDUP(fname); + dir->srv = NULL; + dir->offset = 0; + dir->file = False; + dir->dir_list = dir->dir_next = dir->dir_end = NULL; + + if (server[0] == (char)0) { + + int i; + int count; + int max_lmb_count; + struct ip_service *ip_list; + struct ip_service server_addr; + struct user_auth_info u_info; + + if (share[0] != (char)0 || path[0] != (char)0) { + + errno = EINVAL + 8196; + if (dir) { + SAFE_FREE(dir->fname); + SAFE_FREE(dir); + } + TALLOC_FREE(frame); + return NULL; + } + + /* Determine how many local master browsers to query */ + max_lmb_count = (context->browse_max_lmb_count == 0 + ? INT_MAX + : context->browse_max_lmb_count); + + memset(&u_info, '\0', sizeof(u_info)); + u_info.username = talloc_strdup(frame,user); + u_info.password = talloc_strdup(frame,password); + if (!u_info.username || !u_info.password) { + if (dir) { + SAFE_FREE(dir->fname); + SAFE_FREE(dir); + } + TALLOC_FREE(frame); + return NULL; + } + + /* + * We have server and share and path empty but options + * requesting that we scan all master browsers for their list + * of workgroups/domains. This implies that we must first try + * broadcast queries to find all master browsers, and if that + * doesn't work, then try our other methods which return only + * a single master browser. + */ + + ip_list = NULL; + if (!NT_STATUS_IS_OK(name_resolve_bcast(MSBROWSE, 1, &ip_list, + &count))) + { + + SAFE_FREE(ip_list); + + if (!find_master_ip(workgroup, &server_addr.ss)) { + + if (dir) { + SAFE_FREE(dir->fname); + SAFE_FREE(dir); + } + errno = ENOENT; + TALLOC_FREE(frame); + return NULL; + } + + ip_list = (struct ip_service *)memdup( + &server_addr, sizeof(server_addr)); + if (ip_list == NULL) { + errno = ENOMEM; + TALLOC_FREE(frame); + return NULL; + } + count = 1; + } + + for (i = 0; i < count && i < max_lmb_count; i++) { + char addr[INET6_ADDRSTRLEN]; + char *wg_ptr = NULL; + struct cli_state *cli = NULL; + + print_sockaddr(addr, sizeof(addr), &ip_list[i].ss); + DEBUG(99, ("Found master browser %d of %d: %s\n", + i+1, MAX(count, max_lmb_count), + addr)); + + cli = get_ipc_connect_master_ip(talloc_tos(), + &ip_list[i], + &u_info, + &wg_ptr); + /* cli == NULL is the master browser refused to talk or + could not be found */ + if (!cli) { + continue; + } + + workgroup = talloc_strdup(frame, wg_ptr); + server = talloc_strdup(frame, cli->desthost); + + cli_shutdown(cli); + + if (!workgroup || !server) { + errno = ENOMEM; + TALLOC_FREE(frame); + return NULL; + } + + DEBUG(4, ("using workgroup %s %s\n", + workgroup, server)); + + /* + * For each returned master browser IP address, get a + * connection to IPC$ on the server if we do not + * already have one, and determine the + * workgroups/domains that it knows about. + */ + + srv = SMBC_server(frame, context, True, server, "IPC$", + &workgroup, &user, &password); + if (!srv) { + continue; + } + + dir->srv = srv; + dir->dir_type = SMBC_WORKGROUP; + + /* Now, list the stuff ... */ + + if (!cli_NetServerEnum(srv->cli, + workgroup, + SV_TYPE_DOMAIN_ENUM, + list_unique_wg_fn, + (void *)dir)) { + continue; + } + } + + SAFE_FREE(ip_list); + } else { + /* + * Server not an empty string ... Check the rest and see what + * gives + */ + if (*share == '\0') { + if (*path != '\0') { + + /* Should not have empty share with path */ + errno = EINVAL + 8197; + if (dir) { + SAFE_FREE(dir->fname); + SAFE_FREE(dir); + } + TALLOC_FREE(frame); + return NULL; + + } + + /* + * We don't know if is really a server name + * or is a workgroup/domain name. If we already have + * a server structure for it, we'll use it. + * Otherwise, check to see if <1D>, + * <1B>, or <20> translates. We check + * to see if is an IP address first. + */ + + /* + * See if we have an existing server. Do not + * establish a connection if one does not already + * exist. + */ + srv = SMBC_server(frame, context, False, server, "IPC$", + &workgroup, &user, &password); + + /* + * If no existing server and not an IP addr, look for + * LMB or DMB + */ + if (!srv && + !is_ipaddress(server) && + (resolve_name(server, &rem_ss, 0x1d) || /* LMB */ + resolve_name(server, &rem_ss, 0x1b) )) { /* DMB */ + + fstring buserver; + + dir->dir_type = SMBC_SERVER; + + /* + * Get the backup list ... + */ + if (!name_status_find(server, 0, 0, + &rem_ss, buserver)) { + + DEBUG(0, ("Could not get name of " + "local/domain master browser " + "for server %s\n", server)); + if (dir) { + SAFE_FREE(dir->fname); + SAFE_FREE(dir); + } + errno = EPERM; + TALLOC_FREE(frame); + return NULL; + + } + + /* + * Get a connection to IPC$ on the server if + * we do not already have one + */ + srv = SMBC_server(frame, context, True, + buserver, "IPC$", + &workgroup, &user, &password); + if (!srv) { + DEBUG(0, ("got no contact to IPC$\n")); + if (dir) { + SAFE_FREE(dir->fname); + SAFE_FREE(dir); + } + TALLOC_FREE(frame); + return NULL; + + } + + dir->srv = srv; + + /* Now, list the servers ... */ + if (!cli_NetServerEnum(srv->cli, server, + 0x0000FFFE, list_fn, + (void *)dir)) { + + if (dir) { + SAFE_FREE(dir->fname); + SAFE_FREE(dir); + } + TALLOC_FREE(frame); + return NULL; + } + } else if (srv || + (resolve_name(server, &rem_ss, 0x20))) { + + /* If we hadn't found the server, get one now */ + if (!srv) { + srv = SMBC_server(frame, context, True, + server, "IPC$", + &workgroup, + &user, &password); + } + + if (!srv) { + if (dir) { + SAFE_FREE(dir->fname); + SAFE_FREE(dir); + } + TALLOC_FREE(frame); + return NULL; + + } + + dir->dir_type = SMBC_FILE_SHARE; + dir->srv = srv; + + /* List the shares ... */ + + if (net_share_enum_rpc( + srv->cli, + list_fn, + (void *) dir) < 0 && + cli_RNetShareEnum( + srv->cli, + list_fn, + (void *)dir) < 0) { + + errno = cli_errno(srv->cli); + if (dir) { + SAFE_FREE(dir->fname); + SAFE_FREE(dir); + } + TALLOC_FREE(frame); + return NULL; + + } + } else { + /* Neither the workgroup nor server exists */ + errno = ECONNREFUSED; + if (dir) { + SAFE_FREE(dir->fname); + SAFE_FREE(dir); + } + TALLOC_FREE(frame); + return NULL; + } + + } + else { + /* + * The server and share are specified ... work from + * there ... + */ + char *targetpath; + struct cli_state *targetcli; + + /* We connect to the server and list the directory */ + dir->dir_type = SMBC_FILE_SHARE; + + srv = SMBC_server(frame, context, True, server, share, + &workgroup, &user, &password); + + if (!srv) { + if (dir) { + SAFE_FREE(dir->fname); + SAFE_FREE(dir); + } + TALLOC_FREE(frame); + return NULL; + } + + dir->srv = srv; + + /* Now, list the files ... */ + + p = path + strlen(path); + path = talloc_asprintf_append(path, "\\*"); + if (!path) { + if (dir) { + SAFE_FREE(dir->fname); + SAFE_FREE(dir); + } + TALLOC_FREE(frame); + return NULL; + } + + if (!cli_resolve_path(frame, "", srv->cli, path, + &targetcli, &targetpath)) { + d_printf("Could not resolve %s\n", path); + if (dir) { + SAFE_FREE(dir->fname); + SAFE_FREE(dir); + } + TALLOC_FREE(frame); + return NULL; + } + + if (cli_list(targetcli, targetpath, + aDIR | aSYSTEM | aHIDDEN, + dir_list_fn, (void *)dir) < 0) { + + if (dir) { + SAFE_FREE(dir->fname); + SAFE_FREE(dir); + } + saved_errno = SMBC_errno(context, targetcli); + + if (saved_errno == EINVAL) { + /* + * See if they asked to opendir something + * other than a directory. If so, the + * converted error value we got would have + * been EINVAL rather than ENOTDIR. + */ + *p = '\0'; /* restore original path */ + + if (SMBC_getatr(context, srv, path, + &mode, NULL, + NULL, NULL, NULL, NULL, + NULL) && + ! IS_DOS_DIR(mode)) { + + /* It is. Correct the error value */ + saved_errno = ENOTDIR; + } + } + + /* + * If there was an error and the server is no + * good any more... + */ + if (cli_is_error(targetcli) && + (context->server.check_server_fn)(context, srv)) { + + /* ... then remove it. */ + if ((context->server.remove_unused_server_fn)(context, + srv)) { + /* + * We could not remove the + * server completely, remove + * it from the cache so we + * will not get it again. It + * will be removed when the + * last file/dir is closed. + */ + (context->cache.remove_cached_server_fn)(context, srv); + } + } + + errno = saved_errno; + TALLOC_FREE(frame); + return NULL; + } + } + + } + + DLIST_ADD(context->files, dir); + TALLOC_FREE(frame); + return dir; + +} + +/* + * Routine to close a directory + */ + +int +SMBC_closedir_ctx(SMBCCTX *context, + SMBCFILE *dir) +{ + TALLOC_CTX *frame = talloc_stackframe(); + + if (!context || !context->initialized) { + errno = EINVAL; + TALLOC_FREE(frame); + return -1; + } + + if (!dir || !SMBC_dlist_contains(context->files, dir)) { + errno = EBADF; + TALLOC_FREE(frame); + return -1; + } + + remove_dir(dir); /* Clean it up */ + + DLIST_REMOVE(context->files, dir); + + if (dir) { + + SAFE_FREE(dir->fname); + SAFE_FREE(dir); /* Free the space too */ + } + + TALLOC_FREE(frame); + return 0; + +} + +static void +smbc_readdir_internal(SMBCCTX * context, + struct smbc_dirent *dest, + struct smbc_dirent *src, + int max_namebuf_len) +{ + if (context->urlencode_readdir_entries) { + + /* url-encode the name. get back remaining buffer space */ + max_namebuf_len = + SMBC_urlencode(dest->name, src->name, max_namebuf_len); + + /* We now know the name length */ + dest->namelen = strlen(dest->name); + + /* Save the pointer to the beginning of the comment */ + dest->comment = dest->name + dest->namelen + 1; + + /* Copy the comment */ + strncpy(dest->comment, src->comment, max_namebuf_len - 1); + dest->comment[max_namebuf_len - 1] = '\0'; + + /* Save other fields */ + dest->smbc_type = src->smbc_type; + dest->commentlen = strlen(dest->comment); + dest->dirlen = ((dest->comment + dest->commentlen + 1) - + (char *) dest); + } else { + + /* No encoding. Just copy the entry as is. */ + memcpy(dest, src, src->dirlen); + dest->comment = (char *)(&dest->name + src->namelen + 1); + } + +} + +/* + * Routine to get a directory entry + */ + +struct smbc_dirent * +SMBC_readdir_ctx(SMBCCTX *context, + SMBCFILE *dir) +{ + int maxlen; + struct smbc_dirent *dirp, *dirent; + TALLOC_CTX *frame = talloc_stackframe(); + + /* Check that all is ok first ... */ + + if (!context || !context->initialized) { + + errno = EINVAL; + DEBUG(0, ("Invalid context in SMBC_readdir_ctx()\n")); + TALLOC_FREE(frame); + return NULL; + + } + + if (!dir || !SMBC_dlist_contains(context->files, dir)) { + + errno = EBADF; + DEBUG(0, ("Invalid dir in SMBC_readdir_ctx()\n")); + TALLOC_FREE(frame); + return NULL; + + } + + if (dir->file != False) { /* FIXME, should be dir, perhaps */ + + errno = ENOTDIR; + DEBUG(0, ("Found file vs directory in SMBC_readdir_ctx()\n")); + TALLOC_FREE(frame); + return NULL; + + } + + if (!dir->dir_next) { + TALLOC_FREE(frame); + return NULL; + } + + dirent = dir->dir_next->dirent; + if (!dirent) { + + errno = ENOENT; + TALLOC_FREE(frame); + return NULL; + + } + + dirp = (struct smbc_dirent *)context->dirent; + maxlen = (sizeof(context->dirent) - + sizeof(struct smbc_dirent)); + + smbc_readdir_internal(context, dirp, dirent, maxlen); + + dir->dir_next = dir->dir_next->next; + + TALLOC_FREE(frame); + return dirp; +} + +/* + * Routine to get directory entries + */ + +int +SMBC_getdents_ctx(SMBCCTX *context, + SMBCFILE *dir, + struct smbc_dirent *dirp, + int count) +{ + int rem = count; + int reqd; + int maxlen; + char *ndir = (char *)dirp; + struct smbc_dir_list *dirlist; + TALLOC_CTX *frame = talloc_stackframe(); + + /* Check that all is ok first ... */ + + if (!context || !context->initialized) { + + errno = EINVAL; + TALLOC_FREE(frame); + return -1; + + } + + if (!dir || !SMBC_dlist_contains(context->files, dir)) { + + errno = EBADF; + TALLOC_FREE(frame); + return -1; + + } + + if (dir->file != False) { /* FIXME, should be dir, perhaps */ + + errno = ENOTDIR; + TALLOC_FREE(frame); + return -1; + + } + + /* + * Now, retrieve the number of entries that will fit in what was passed + * We have to figure out if the info is in the list, or we need to + * send a request to the server to get the info. + */ + + while ((dirlist = dir->dir_next)) { + struct smbc_dirent *dirent; + + if (!dirlist->dirent) { + + errno = ENOENT; /* Bad error */ + TALLOC_FREE(frame); + return -1; + + } + + /* Do urlencoding of next entry, if so selected */ + dirent = (struct smbc_dirent *)context->dirent; + maxlen = (sizeof(context->dirent) - + sizeof(struct smbc_dirent)); + smbc_readdir_internal(context, dirent, dirlist->dirent, maxlen); + + reqd = dirent->dirlen; + + if (rem < reqd) { + + if (rem < count) { /* We managed to copy something */ + + errno = 0; + TALLOC_FREE(frame); + return count - rem; + + } + else { /* Nothing copied ... */ + + errno = EINVAL; /* Not enough space ... */ + TALLOC_FREE(frame); + return -1; + + } + + } + + memcpy(ndir, dirent, reqd); /* Copy the data in ... */ + + ((struct smbc_dirent *)ndir)->comment = + (char *)(&((struct smbc_dirent *)ndir)->name + + dirent->namelen + + 1); + + ndir += reqd; + + rem -= reqd; + + dir->dir_next = dirlist = dirlist -> next; + } + + TALLOC_FREE(frame); + + if (rem == count) + return 0; + else + return count - rem; + +} + +/* + * Routine to create a directory ... + */ + +int +SMBC_mkdir_ctx(SMBCCTX *context, + const char *fname, + mode_t mode) +{ + 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->initialized) { + errno = EINVAL; + TALLOC_FREE(frame); + return -1; + } + + if (!fname) { + errno = EINVAL; + TALLOC_FREE(frame); + return -1; + } + + DEBUG(4, ("smbc_mkdir(%s)\n", fname)); + + if (SMBC_parse_path(frame, + context, + fname, + &workgroup, + &server, + &share, + &path, + &user, + &password, + NULL)) { + errno = EINVAL; + TALLOC_FREE(frame); + return -1; + } + + if (!user || user[0] == (char)0) { + user = talloc_strdup(frame, context->user); + if (!user) { + errno = ENOMEM; + TALLOC_FREE(frame); + return -1; + } + } + + srv = SMBC_server(frame, context, True, + server, share, &workgroup, &user, &password); + + if (!srv) { + + TALLOC_FREE(frame); + return -1; /* errno set by SMBC_server */ + + } + + /*d_printf(">>>mkdir: resolving %s\n", path);*/ + if (!cli_resolve_path(frame, "", srv->cli, path, + &targetcli, &targetpath)) { + d_printf("Could not resolve %s\n", path); + TALLOC_FREE(frame); + return -1; + } + /*d_printf(">>>mkdir: resolved path as %s\n", targetpath);*/ + + if (!cli_mkdir(targetcli, targetpath)) { + + errno = SMBC_errno(context, targetcli); + TALLOC_FREE(frame); + return -1; + + } + + TALLOC_FREE(frame); + return 0; + +} + +/* + * Our list function simply checks to see if a directory is not empty + */ + +static int smbc_rmdir_dirempty = True; + +static void +rmdir_list_fn(const char *mnt, + file_info *finfo, + const char *mask, + void *state) +{ + if (strncmp(finfo->name, ".", 1) != 0 && + strncmp(finfo->name, "..", 2) != 0) { + smbc_rmdir_dirempty = False; + } +} + +/* + * Routine to remove a directory + */ + +int +SMBC_rmdir_ctx(SMBCCTX *context, + const char *fname) +{ + 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->initialized) { + errno = EINVAL; + TALLOC_FREE(frame); + return -1; + } + + if (!fname) { + errno = EINVAL; + TALLOC_FREE(frame); + return -1; + } + + DEBUG(4, ("smbc_rmdir(%s)\n", fname)); + + if (SMBC_parse_path(frame, + context, + fname, + &workgroup, + &server, + &share, + &path, + &user, + &password, + NULL)) { + errno = EINVAL; + TALLOC_FREE(frame); + return -1; + } + + if (!user || user[0] == (char)0) { + user = talloc_strdup(frame, context->user); + if (!user) { + errno = ENOMEM; + TALLOC_FREE(frame); + return -1; + } + } + + srv = SMBC_server(frame, context, True, + server, share, &workgroup, &user, &password); + + if (!srv) { + + TALLOC_FREE(frame); + return -1; /* errno set by SMBC_server */ + + } + + /*d_printf(">>>rmdir: resolving %s\n", path);*/ + if (!cli_resolve_path(frame, "", srv->cli, path, + &targetcli, &targetpath)) { + d_printf("Could not resolve %s\n", path); + TALLOC_FREE(frame); + return -1; + } + /*d_printf(">>>rmdir: resolved path as %s\n", targetpath);*/ + + + if (!cli_rmdir(targetcli, targetpath)) { + + errno = SMBC_errno(context, targetcli); + + if (errno == EACCES) { /* Check if the dir empty or not */ + + /* Local storage to avoid buffer overflows */ + char *lpath; + + smbc_rmdir_dirempty = True; /* Make this so ... */ + + lpath = talloc_asprintf(frame, "%s\\*", + targetpath); + if (!lpath) { + errno = ENOMEM; + TALLOC_FREE(frame); + return -1; + } + + if (cli_list(targetcli, lpath, + aDIR | aSYSTEM | aHIDDEN, + rmdir_list_fn, NULL) < 0) { + + /* Fix errno to ignore latest error ... */ + DEBUG(5, ("smbc_rmdir: " + "cli_list returned an error: %d\n", + SMBC_errno(context, targetcli))); + errno = EACCES; + + } + + if (smbc_rmdir_dirempty) + errno = EACCES; + else + errno = ENOTEMPTY; + + } + + TALLOC_FREE(frame); + return -1; + + } + + TALLOC_FREE(frame); + return 0; + +} + +/* + * Routine to return the current directory position + */ + +off_t +SMBC_telldir_ctx(SMBCCTX *context, + SMBCFILE *dir) +{ + TALLOC_CTX *frame = talloc_stackframe(); + + if (!context || !context->initialized) { + + errno = EINVAL; + TALLOC_FREE(frame); + return -1; + + } + + if (!dir || !SMBC_dlist_contains(context->files, dir)) { + + errno = EBADF; + TALLOC_FREE(frame); + return -1; + + } + + if (dir->file != False) { /* FIXME, should be dir, perhaps */ + + errno = ENOTDIR; + TALLOC_FREE(frame); + return -1; + + } + + /* See if we're already at the end. */ + if (dir->dir_next == NULL) { + /* We are. */ + TALLOC_FREE(frame); + return -1; + } + + /* + * We return the pointer here as the offset + */ + TALLOC_FREE(frame); + return (off_t)(long)dir->dir_next->dirent; +} + +/* + * A routine to run down the list and see if the entry is OK + */ + +static struct smbc_dir_list * +check_dir_ent(struct smbc_dir_list *list, + struct smbc_dirent *dirent) +{ + + /* Run down the list looking for what we want */ + + if (dirent) { + + struct smbc_dir_list *tmp = list; + + while (tmp) { + + if (tmp->dirent == dirent) + return tmp; + + tmp = tmp->next; + + } + + } + + return NULL; /* Not found, or an error */ + +} + + +/* + * Routine to seek on a directory + */ + +int +SMBC_lseekdir_ctx(SMBCCTX *context, + SMBCFILE *dir, + off_t offset) +{ + long int l_offset = offset; /* Handle problems of size */ + struct smbc_dirent *dirent = (struct smbc_dirent *)l_offset; + struct smbc_dir_list *list_ent = (struct smbc_dir_list *)NULL; + TALLOC_CTX *frame = talloc_stackframe(); + + if (!context || !context->initialized) { + + errno = EINVAL; + TALLOC_FREE(frame); + return -1; + + } + + if (dir->file != False) { /* FIXME, should be dir, perhaps */ + + errno = ENOTDIR; + TALLOC_FREE(frame); + return -1; + + } + + /* Now, check what we were passed and see if it is OK ... */ + + if (dirent == NULL) { /* Seek to the begining of the list */ + + dir->dir_next = dir->dir_list; + TALLOC_FREE(frame); + return 0; + + } + + if (offset == -1) { /* Seek to the end of the list */ + dir->dir_next = NULL; + TALLOC_FREE(frame); + return 0; + } + + /* Now, run down the list and make sure that the entry is OK */ + /* This may need to be changed if we change the format of the list */ + + if ((list_ent = check_dir_ent(dir->dir_list, dirent)) == NULL) { + errno = EINVAL; /* Bad entry */ + TALLOC_FREE(frame); + return -1; + } + + dir->dir_next = list_ent; + + TALLOC_FREE(frame); + return 0; +} + +/* + * Routine to fstat a dir + */ + +int +SMBC_fstatdir_ctx(SMBCCTX *context, + SMBCFILE *dir, + struct stat *st) +{ + + if (!context || !context->initialized) { + + errno = EINVAL; + return -1; + } + + /* No code yet ... */ + return 0; +} + +int +SMBC_chmod_ctx(SMBCCTX *context, + const char *fname, + mode_t newmode) +{ + 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(); + + if (!context || !context->initialized) { + + errno = EINVAL; /* Best I can think of ... */ + TALLOC_FREE(frame); + return -1; + } + + if (!fname) { + errno = EINVAL; + TALLOC_FREE(frame); + return -1; + } + + DEBUG(4, ("smbc_chmod(%s, 0%3o)\n", fname, newmode)); + + if (SMBC_parse_path(frame, + context, + fname, + &workgroup, + &server, + &share, + &path, + &user, + &password, + NULL)) { + errno = EINVAL; + TALLOC_FREE(frame); + return -1; + } + + if (!user || user[0] == (char)0) { + user = talloc_strdup(frame, context->user); + if (!user) { + errno = ENOMEM; + TALLOC_FREE(frame); + return -1; + } + } + + srv = SMBC_server(frame, context, True, + server, share, &workgroup, &user, &password); + + if (!srv) { + TALLOC_FREE(frame); + return -1; /* errno set by SMBC_server */ + } + + mode = 0; + + if (!(newmode & (S_IWUSR | S_IWGRP | S_IWOTH))) mode |= aRONLY; + if ((newmode & S_IXUSR) && lp_map_archive(-1)) mode |= aARCH; + if ((newmode & S_IXGRP) && lp_map_system(-1)) mode |= aSYSTEM; + if ((newmode & S_IXOTH) && lp_map_hidden(-1)) mode |= aHIDDEN; + + if (!cli_setatr(srv->cli, path, mode, 0)) { + errno = SMBC_errno(context, srv->cli); + TALLOC_FREE(frame); + return -1; + } + + TALLOC_FREE(frame); + return 0; +} + +int +SMBC_utimes_ctx(SMBCCTX *context, + const char *fname, + struct timeval *tbuf) +{ + 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(); + + if (!context || !context->initialized) { + + errno = EINVAL; /* Best I can think of ... */ + TALLOC_FREE(frame); + return -1; + } + + if (!fname) { + errno = EINVAL; + TALLOC_FREE(frame); + return -1; + } + + if (tbuf == NULL) { + access_time = write_time = time(NULL); + } else { + access_time = tbuf[0].tv_sec; + write_time = tbuf[1].tv_sec; + } + + if (DEBUGLVL(4)) { + char *p; + char atimebuf[32]; + char mtimebuf[32]; + + strncpy(atimebuf, ctime(&access_time), sizeof(atimebuf) - 1); + atimebuf[sizeof(atimebuf) - 1] = '\0'; + if ((p = strchr(atimebuf, '\n')) != NULL) { + *p = '\0'; + } + + strncpy(mtimebuf, ctime(&write_time), sizeof(mtimebuf) - 1); + mtimebuf[sizeof(mtimebuf) - 1] = '\0'; + if ((p = strchr(mtimebuf, '\n')) != NULL) { + *p = '\0'; + } + + dbgtext("smbc_utimes(%s, atime = %s mtime = %s)\n", + fname, atimebuf, mtimebuf); + } + + if (SMBC_parse_path(frame, + context, + fname, + &workgroup, + &server, + &share, + &path, + &user, + &password, + NULL)) { + errno = EINVAL; + TALLOC_FREE(frame); + return -1; + } + + if (!user || user[0] == (char)0) { + user = talloc_strdup(frame, context->user); + if (!user) { + errno = ENOMEM; + TALLOC_FREE(frame); + return -1; + } + } + + srv = SMBC_server(frame, context, True, + server, share, &workgroup, &user, &password); + + if (!srv) { + TALLOC_FREE(frame); + return -1; /* errno set by SMBC_server */ + } + + if (!SMBC_setatr(context, srv, path, + 0, access_time, write_time, 0, 0)) { + TALLOC_FREE(frame); + return -1; /* errno set by SMBC_setatr */ + } + + TALLOC_FREE(frame); + return 0; +} + +/* + * Routine to unlink() a file + */ + +int +SMBC_unlink_ctx(SMBCCTX *context, + const char *fname) +{ + 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(); + + if (!context || !context->initialized) { + + errno = EINVAL; /* Best I can think of ... */ + TALLOC_FREE(frame); + return -1; + + } + + if (!fname) { + errno = EINVAL; + TALLOC_FREE(frame); + return -1; + + } + + if (SMBC_parse_path(frame, + context, + fname, + &workgroup, + &server, + &share, + &path, + &user, + &password, + NULL)) { + errno = EINVAL; + TALLOC_FREE(frame); + return -1; + } + + if (!user || user[0] == (char)0) { + user = talloc_strdup(frame, context->user); + if (!user) { + errno = ENOMEM; + TALLOC_FREE(frame); + return -1; + } + } + + srv = SMBC_server(frame, context, True, + server, share, &workgroup, &user, &password); + + if (!srv) { + TALLOC_FREE(frame); + return -1; /* SMBC_server sets errno */ + + } + + /*d_printf(">>>unlink: resolving %s\n", path);*/ + if (!cli_resolve_path(frame, "", srv->cli, path, + &targetcli, &targetpath)) { + d_printf("Could not resolve %s\n", path); + TALLOC_FREE(frame); + return -1; + } + /*d_printf(">>>unlink: resolved path as %s\n", targetpath);*/ + + if (!cli_unlink(targetcli, targetpath)) { + + errno = SMBC_errno(context, targetcli); + + if (errno == EACCES) { /* Check if the file is a directory */ + + int saverr = errno; + SMB_OFF_T size = 0; + uint16 mode = 0; + struct timespec write_time_ts; + struct timespec access_time_ts; + struct timespec change_time_ts; + SMB_INO_T ino = 0; + + if (!SMBC_getatr(context, srv, path, &mode, &size, + NULL, + &access_time_ts, + &write_time_ts, + &change_time_ts, + &ino)) { + + /* Hmmm, bad error ... What? */ + + errno = SMBC_errno(context, targetcli); + TALLOC_FREE(frame); + return -1; + + } + else { + + if (IS_DOS_DIR(mode)) + errno = EISDIR; + else + errno = saverr; /* Restore this */ + + } + } + + TALLOC_FREE(frame); + return -1; + + } + + TALLOC_FREE(frame); + return 0; /* Success ... */ + +} + +/* + * Routine to rename() a file + */ + +int +SMBC_rename_ctx(SMBCCTX *ocontext, + const char *oname, + SMBCCTX *ncontext, + const char *nname) +{ + 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(); + + if (!ocontext || !ncontext || + !ocontext->initialized || + !ncontext->initialized) { + + errno = EINVAL; /* Best I can think of ... */ + TALLOC_FREE(frame); + return -1; + } + + if (!oname || !nname) { + errno = EINVAL; + TALLOC_FREE(frame); + return -1; + } + + DEBUG(4, ("smbc_rename(%s,%s)\n", oname, nname)); + + if (SMBC_parse_path(frame, + ocontext, + oname, + &workgroup, + &server1, + &share1, + &path1, + &user1, + &password1, + NULL)) { + errno = EINVAL; + TALLOC_FREE(frame); + return -1; + } + + if (!user1 || user1[0] == (char)0) { + user1 = talloc_strdup(frame, ocontext->user); + if (!user1) { + errno = ENOMEM; + TALLOC_FREE(frame); + return -1; + } + } + + if (SMBC_parse_path(frame, + ncontext, + nname, + NULL, + &server2, + &share2, + &path2, + &user2, + &password2, + NULL)) { + errno = EINVAL; + TALLOC_FREE(frame); + return -1; + } + + if (!user2 || user2[0] == (char)0) { + user2 = talloc_strdup(frame, ncontext->user); + if (!user2) { + errno = ENOMEM; + TALLOC_FREE(frame); + return -1; + } + } + + if (strcmp(server1, server2) || strcmp(share1, share2) || + strcmp(user1, user2)) { + /* Can't rename across file systems, or users?? */ + errno = EXDEV; + TALLOC_FREE(frame); + return -1; + } + + srv = SMBC_server(frame, ocontext, True, + server1, share1, &workgroup, &user1, &password1); + if (!srv) { + TALLOC_FREE(frame); + return -1; + + } + + /*d_printf(">>>rename: resolving %s\n", path1);*/ + if (!cli_resolve_path(frame, "", srv->cli, path1, + &targetcli1, &targetpath1)) { + d_printf("Could not resolve %s\n", path1); + TALLOC_FREE(frame); + return -1; + } + /*d_printf(">>>rename: resolved path as %s\n", targetpath1);*/ + /*d_printf(">>>rename: resolving %s\n", path2);*/ + if (!cli_resolve_path(frame, "", srv->cli, path2, + &targetcli2, &targetpath2)) { + d_printf("Could not resolve %s\n", path2); + TALLOC_FREE(frame); + return -1; + } + /*d_printf(">>>rename: resolved path as %s\n", targetpath2);*/ + + if (strcmp(targetcli1->desthost, targetcli2->desthost) || + strcmp(targetcli1->share, targetcli2->share)) + { + /* can't rename across file systems */ + errno = EXDEV; + TALLOC_FREE(frame); + return -1; + } + + if (!cli_rename(targetcli1, targetpath1, targetpath2)) { + int eno = SMBC_errno(ocontext, targetcli1); + + if (eno != EEXIST || + !cli_unlink(targetcli1, targetpath2) || + !cli_rename(targetcli1, targetpath1, targetpath2)) { + + errno = eno; + TALLOC_FREE(frame); + return -1; + + } + } + + TALLOC_FREE(frame); + return 0; /* Success */ +} + diff --git a/source3/libsmb/libsmb_file.c b/source3/libsmb/libsmb_file.c new file mode 100644 index 0000000000..619176697b --- /dev/null +++ b/source3/libsmb/libsmb_file.c @@ -0,0 +1,859 @@ +/* + Unix SMB/Netbios implementation. + SMB client library implementation + Copyright (C) Andrew Tridgell 1998 + Copyright (C) Richard Sharpe 2000, 2002 + Copyright (C) John Terpstra 2000 + Copyright (C) Tom Jansen (Ninja ISD) 2002 + Copyright (C) Derrell Lipman 2003-2008 + 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 + 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 . +*/ + +#include "includes.h" +#include "libsmbclient.h" +#include "libsmb_internal.h" + + +/* + * Routine to open() a file ... + */ + +SMBCFILE * +SMBC_open_ctx(SMBCCTX *context, + const char *fname, + int flags, + mode_t mode) +{ + 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; + SMBCFILE *file = NULL; + int fd; + TALLOC_CTX *frame = talloc_stackframe(); + + if (!context || !context->initialized) { + + errno = EINVAL; /* Best I can think of ... */ + TALLOC_FREE(frame); + return NULL; + + } + + if (!fname) { + + errno = EINVAL; + TALLOC_FREE(frame); + return NULL; + + } + + if (SMBC_parse_path(frame, + context, + fname, + &workgroup, + &server, + &share, + &path, + &user, + &password, + NULL)) { + errno = EINVAL; + TALLOC_FREE(frame); + return NULL; + } + + if (!user || user[0] == (char)0) { + user = talloc_strdup(frame, context->user); + if (!user) { + errno = ENOMEM; + TALLOC_FREE(frame); + return NULL; + } + } + + srv = SMBC_server(frame, context, True, + server, share, &workgroup, &user, &password); + + if (!srv) { + if (errno == EPERM) errno = EACCES; + TALLOC_FREE(frame); + return NULL; /* SMBC_server sets errno */ + } + + /* Hmmm, the test for a directory is suspect here ... FIXME */ + + if (strlen(path) > 0 && path[strlen(path) - 1] == '\\') { + fd = -1; + } else { + file = SMB_MALLOC_P(SMBCFILE); + + if (!file) { + errno = ENOMEM; + TALLOC_FREE(frame); + return NULL; + } + + ZERO_STRUCTP(file); + + /*d_printf(">>>open: resolving %s\n", path);*/ + if (!cli_resolve_path(frame, "", srv->cli, path, &targetcli, &targetpath)) { + d_printf("Could not resolve %s\n", path); + SAFE_FREE(file); + TALLOC_FREE(frame); + return NULL; + } + /*d_printf(">>>open: resolved %s as %s\n", path, targetpath);*/ + + if ((fd = cli_open(targetcli, targetpath, flags, + context->share_mode)) < 0) { + + /* Handle the error ... */ + + SAFE_FREE(file); + errno = SMBC_errno(context, targetcli); + TALLOC_FREE(frame); + return NULL; + + } + + /* Fill in file struct */ + + file->cli_fd = fd; + file->fname = SMB_STRDUP(fname); + file->srv = srv; + file->offset = 0; + file->file = True; + + DLIST_ADD(context->files, file); + + /* + * If the file was opened in O_APPEND mode, all write + * operations should be appended to the file. To do that, + * though, using this protocol, would require a getattrE() + * call for each and every write, to determine where the end + * of the file is. (There does not appear to be an append flag + * in the protocol.) Rather than add all of that overhead of + * retrieving the current end-of-file offset prior to each + * write operation, we'll assume that most append operations + * will continuously write, so we'll just set the offset to + * the end of the file now and hope that's adequate. + * + * Note to self: If this proves inadequate, and O_APPEND + * should, in some cases, be forced for each write, add a + * field in the context options structure, for + * "strict_append_mode" which would select between the current + * behavior (if FALSE) or issuing a getattrE() prior to each + * write and forcing the write to the end of the file (if + * TRUE). Adding that capability will likely require adding + * an "append" flag into the _SMBCFILE structure to track + * whether a file was opened in O_APPEND mode. -- djl + */ + if (flags & O_APPEND) { + if (SMBC_lseek_ctx(context, file, 0, SEEK_END) < 0) { + (void) SMBC_close_ctx(context, file); + errno = ENXIO; + TALLOC_FREE(frame); + return NULL; + } + } + + TALLOC_FREE(frame); + return file; + + } + + /* Check if opendir needed ... */ + + if (fd == -1) { + int eno = 0; + + eno = SMBC_errno(context, srv->cli); + file = (context->posix_emu.opendir_fn)(context, fname); + if (!file) errno = eno; + TALLOC_FREE(frame); + return file; + + } + + errno = EINVAL; /* FIXME, correct errno ? */ + TALLOC_FREE(frame); + return NULL; + +} + +/* + * Routine to create a file + */ + +static int creat_bits = O_WRONLY | O_CREAT | O_TRUNC; /* FIXME: Do we need this */ + +SMBCFILE * +SMBC_creat_ctx(SMBCCTX *context, + const char *path, + mode_t mode) +{ + + if (!context || !context->initialized) { + + errno = EINVAL; + return NULL; + + } + + return SMBC_open_ctx(context, path, creat_bits, mode); +} + +/* + * Routine to read() a file ... + */ + +ssize_t +SMBC_read_ctx(SMBCCTX *context, + SMBCFILE *file, + void *buf, + size_t count) +{ + int ret; + 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(); + + /* + * offset: + * + * Compiler bug (possibly) -- gcc (GCC) 3.3.5 (Debian 1:3.3.5-2) -- + * appears to pass file->offset (which is type off_t) differently than + * a local variable of type off_t. Using local variable "offset" in + * the call to cli_read() instead of file->offset fixes a problem + * retrieving data at an offset greater than 4GB. + */ + off_t offset; + + if (!context || !context->initialized) { + + errno = EINVAL; + TALLOC_FREE(frame); + return -1; + + } + + DEBUG(4, ("smbc_read(%p, %d)\n", file, (int)count)); + + if (!file || !SMBC_dlist_contains(context->files, file)) { + errno = EBADF; + TALLOC_FREE(frame); + return -1; + + } + + offset = file->offset; + + /* Check that the buffer exists ... */ + + if (buf == NULL) { + errno = EINVAL; + TALLOC_FREE(frame); + return -1; + + } + + /*d_printf(">>>read: parsing %s\n", file->fname);*/ + if (SMBC_parse_path(frame, + context, + file->fname, + NULL, + &server, + &share, + &path, + &user, + &password, + NULL)) { + errno = EINVAL; + TALLOC_FREE(frame); + return -1; + } + + /*d_printf(">>>read: resolving %s\n", path);*/ + if (!cli_resolve_path(frame, "", file->srv->cli, path, + &targetcli, &targetpath)) { + d_printf("Could not resolve %s\n", path); + TALLOC_FREE(frame); + return -1; + } + /*d_printf(">>>fstat: resolved path as %s\n", targetpath);*/ + + ret = cli_read(targetcli, file->cli_fd, (char *)buf, offset, count); + + if (ret < 0) { + + errno = SMBC_errno(context, targetcli); + TALLOC_FREE(frame); + return -1; + + } + + file->offset += ret; + + DEBUG(4, (" --> %d\n", ret)); + + TALLOC_FREE(frame); + return ret; /* Success, ret bytes of data ... */ + +} + +/* + * Routine to write() a file ... + */ + +ssize_t +SMBC_write_ctx(SMBCCTX *context, + SMBCFILE *file, + void *buf, + size_t count) +{ + int ret; + off_t offset; + 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(); + + /* First check all pointers before dereferencing them */ + + if (!context || !context->initialized) { + + errno = EINVAL; + TALLOC_FREE(frame); + return -1; + + } + + if (!file || !SMBC_dlist_contains(context->files, file)) { + errno = EBADF; + TALLOC_FREE(frame); + return -1; + } + + /* Check that the buffer exists ... */ + + if (buf == NULL) { + errno = EINVAL; + TALLOC_FREE(frame); + return -1; + + } + + offset = file->offset; /* See "offset" comment in SMBC_read_ctx() */ + + /*d_printf(">>>write: parsing %s\n", file->fname);*/ + if (SMBC_parse_path(frame, + context, + file->fname, + NULL, + &server, + &share, + &path, + &user, + &password, + NULL)) { + errno = EINVAL; + TALLOC_FREE(frame); + return -1; + } + + /*d_printf(">>>write: resolving %s\n", path);*/ + if (!cli_resolve_path(frame, "", file->srv->cli, path, + &targetcli, &targetpath)) { + d_printf("Could not resolve %s\n", path); + TALLOC_FREE(frame); + return -1; + } + /*d_printf(">>>write: resolved path as %s\n", targetpath);*/ + + ret = cli_write(targetcli, file->cli_fd, 0, (char *)buf, offset, count); + + if (ret <= 0) { + errno = SMBC_errno(context, targetcli); + TALLOC_FREE(frame); + return -1; + + } + + file->offset += ret; + + TALLOC_FREE(frame); + return ret; /* Success, 0 bytes of data ... */ +} + +/* + * Routine to close() a file ... + */ + +int +SMBC_close_ctx(SMBCCTX *context, + SMBCFILE *file) +{ + SMBCSRV *srv; + 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->initialized) { + + errno = EINVAL; + TALLOC_FREE(frame); + return -1; + } + + if (!file || !SMBC_dlist_contains(context->files, file)) { + errno = EBADF; + TALLOC_FREE(frame); + return -1; + } + + /* IS a dir ... */ + if (!file->file) { + TALLOC_FREE(frame); + return (context->posix_emu.closedir_fn)(context, file); + } + + /*d_printf(">>>close: parsing %s\n", file->fname);*/ + if (SMBC_parse_path(frame, + context, + file->fname, + NULL, + &server, + &share, + &path, + &user, + &password, + NULL)) { + errno = EINVAL; + TALLOC_FREE(frame); + return -1; + } + + /*d_printf(">>>close: resolving %s\n", path);*/ + if (!cli_resolve_path(frame, "", file->srv->cli, path, + &targetcli, &targetpath)) { + d_printf("Could not resolve %s\n", path); + TALLOC_FREE(frame); + return -1; + } + /*d_printf(">>>close: resolved path as %s\n", targetpath);*/ + + if (!cli_close(targetcli, file->cli_fd)) { + + DEBUG(3, ("cli_close failed on %s. purging server.\n", + file->fname)); + /* Deallocate slot and remove the server + * from the server cache if unused */ + errno = SMBC_errno(context, targetcli); + srv = file->srv; + DLIST_REMOVE(context->files, file); + SAFE_FREE(file->fname); + SAFE_FREE(file); + (context->server.remove_unused_server_fn)(context, srv); + TALLOC_FREE(frame); + return -1; + + } + + DLIST_REMOVE(context->files, file); + SAFE_FREE(file->fname); + SAFE_FREE(file); + TALLOC_FREE(frame); + + return 0; +} + +/* + * Get info from an SMB server on a file. Use a qpathinfo call first + * and if that fails, use getatr, as Win95 sometimes refuses qpathinfo + */ +bool +SMBC_getatr(SMBCCTX * context, + SMBCSRV *srv, + char *path, + uint16 *mode, + SMB_OFF_T *size, + struct timespec *create_time_ts, + struct timespec *access_time_ts, + struct timespec *write_time_ts, + struct timespec *change_time_ts, + SMB_INO_T *ino) +{ + char *fixedpath = NULL; + char *targetpath = NULL; + struct cli_state *targetcli = NULL; + time_t write_time; + TALLOC_CTX *frame = talloc_stackframe(); + + if (!context || !context->initialized) { + + errno = EINVAL; + TALLOC_FREE(frame); + return -1; + } + + /* path fixup for . and .. */ + if (strequal(path, ".") || strequal(path, "..")) { + fixedpath = talloc_strdup(frame, "\\"); + if (!fixedpath) { + errno = ENOMEM; + TALLOC_FREE(frame); + return -1; + } + } else { + fixedpath = talloc_strdup(frame, path); + if (!fixedpath) { + errno = ENOMEM; + TALLOC_FREE(frame); + return -1; + } + trim_string(fixedpath, NULL, "\\.."); + trim_string(fixedpath, NULL, "\\."); + } + DEBUG(4,("SMBC_getatr: sending qpathinfo\n")); + + if (!cli_resolve_path(frame, "", srv->cli, fixedpath, + &targetcli, &targetpath)) { + d_printf("Couldn't resolve %s\n", path); + TALLOC_FREE(frame); + return False; + } + + if (!srv->no_pathinfo2 && + cli_qpathinfo2(targetcli, targetpath, + create_time_ts, + access_time_ts, + write_time_ts, + change_time_ts, + size, mode, ino)) { + TALLOC_FREE(frame); + return True; + } + + /* if this is NT then don't bother with the getatr */ + if (targetcli->capabilities & CAP_NT_SMBS) { + errno = EPERM; + TALLOC_FREE(frame); + return False; + } + + if (cli_getatr(targetcli, targetpath, mode, size, &write_time)) { + + struct timespec w_time_ts; + + w_time_ts = convert_time_t_to_timespec(write_time); + + if (write_time_ts != NULL) { + *write_time_ts = w_time_ts; + } + + 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; + } + + srv->no_pathinfo2 = True; + TALLOC_FREE(frame); + return True; + } + + errno = EPERM; + TALLOC_FREE(frame); + return False; + +} + +/* + * Set file info on an SMB server. Use setpathinfo call first. If that + * fails, use setattrE.. + * + * Access and modification time parameters are always used and must be + * provided. Create time, if zero, will be determined from the actual create + * time of the file. If non-zero, the create time will be set as well. + * + * "mode" (attributes) parameter may be set to -1 if it is not to be set. + */ +bool +SMBC_setatr(SMBCCTX * context, SMBCSRV *srv, char *path, + time_t create_time, + time_t access_time, + time_t write_time, + time_t change_time, + uint16 mode) +{ + int fd; + int ret; + TALLOC_CTX *frame = talloc_stackframe(); + + /* + * First, try setpathinfo (if qpathinfo succeeded), for it is the + * modern function for "new code" to be using, and it works given a + * filename rather than requiring that the file be opened to have its + * attributes manipulated. + */ + if (srv->no_pathinfo || + ! cli_setpathinfo(srv->cli, path, + create_time, + access_time, + write_time, + change_time, + mode)) { + + /* + * setpathinfo is not supported; go to plan B. + * + * cli_setatr() does not work on win98, and it also doesn't + * support setting the access time (only the modification + * time), so in all cases, we open the specified file and use + * cli_setattrE() which should work on all OS versions, and + * supports both times. + */ + + /* Don't try {q,set}pathinfo() again, with this server */ + srv->no_pathinfo = True; + + /* Open the file */ + if ((fd = cli_open(srv->cli, path, O_RDWR, DENY_NONE)) < 0) { + + errno = SMBC_errno(context, srv->cli); + TALLOC_FREE(frame); + return -1; + } + + /* Set the new attributes */ + ret = cli_setattrE(srv->cli, fd, + change_time, + access_time, + write_time); + + /* Close the file */ + cli_close(srv->cli, fd); + + /* + * Unfortunately, setattrE() doesn't have a provision for + * setting the access mode (attributes). We'll have to try + * cli_setatr() for that, and with only this parameter, it + * seems to work on win98. + */ + if (ret && mode != (uint16) -1) { + ret = cli_setatr(srv->cli, path, mode, 0); + } + + if (! ret) { + errno = SMBC_errno(context, srv->cli); + TALLOC_FREE(frame); + return False; + } + } + + TALLOC_FREE(frame); + return True; +} + +/* + * A routine to lseek() a file + */ + +off_t +SMBC_lseek_ctx(SMBCCTX *context, + SMBCFILE *file, + off_t offset, + int whence) +{ + SMB_OFF_T size; + 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->initialized) { + + errno = EINVAL; + TALLOC_FREE(frame); + return -1; + } + + if (!file || !SMBC_dlist_contains(context->files, file)) { + + errno = EBADF; + TALLOC_FREE(frame); + return -1; + + } + + if (!file->file) { + + errno = EINVAL; + TALLOC_FREE(frame); + return -1; /* Can't lseek a dir ... */ + + } + + switch (whence) { + case SEEK_SET: + file->offset = offset; + break; + + case SEEK_CUR: + file->offset += offset; + break; + + case SEEK_END: + /*d_printf(">>>lseek: parsing %s\n", file->fname);*/ + if (SMBC_parse_path(frame, + context, + file->fname, + NULL, + &server, + &share, + &path, + &user, + &password, + NULL)) { + errno = EINVAL; + TALLOC_FREE(frame); + return -1; + } + + /*d_printf(">>>lseek: resolving %s\n", path);*/ + if (!cli_resolve_path(frame, "", file->srv->cli, path, + &targetcli, &targetpath)) { + d_printf("Could not resolve %s\n", path); + TALLOC_FREE(frame); + return -1; + } + /*d_printf(">>>lseek: resolved path as %s\n", targetpath);*/ + + if (!cli_qfileinfo(targetcli, file->cli_fd, NULL, + &size, NULL, NULL, NULL, NULL, NULL)) + { + SMB_OFF_T b_size = size; + if (!cli_getattrE(targetcli, file->cli_fd, + NULL, &b_size, NULL, NULL, NULL)) + { + errno = EINVAL; + TALLOC_FREE(frame); + return -1; + } else + size = b_size; + } + file->offset = size + offset; + break; + + default: + errno = EINVAL; + break; + + } + + TALLOC_FREE(frame); + return file->offset; + +} + + +/* + * Routine to truncate a file given by its file descriptor, to a specified size + */ + +int +SMBC_ftruncate_ctx(SMBCCTX *context, + SMBCFILE *file, + off_t length) +{ + SMB_OFF_T size = length; + char *server = NULL; + char *share = NULL; + char *user = NULL; + char *password = NULL; + char *path = NULL; + char *targetpath = NULL; + struct cli_state *targetcli = NULL; + TALLOC_CTX *frame = talloc_stackframe(); + + if (!context || !context->initialized) { + + errno = EINVAL; + TALLOC_FREE(frame); + return -1; + } + + if (!file || !SMBC_dlist_contains(context->files, file)) { + errno = EBADF; + TALLOC_FREE(frame); + return -1; + } + + if (!file->file) { + errno = EINVAL; + TALLOC_FREE(frame); + return -1; + } + + /*d_printf(">>>fstat: parsing %s\n", file->fname);*/ + if (SMBC_parse_path(frame, + context, + file->fname, + NULL, + &server, + &share, + &path, + &user, + &password, + NULL)) { + errno = EINVAL; + TALLOC_FREE(frame); + return -1; + } + + /*d_printf(">>>fstat: resolving %s\n", path);*/ + if (!cli_resolve_path(frame, "", file->srv->cli, path, + &targetcli, &targetpath)) { + d_printf("Could not resolve %s\n", path); + TALLOC_FREE(frame); + return -1; + } + /*d_printf(">>>fstat: resolved path as %s\n", targetpath);*/ + + if (!cli_ftruncate(targetcli, file->cli_fd, size)) { + errno = EINVAL; + TALLOC_FREE(frame); + return -1; + } + + TALLOC_FREE(frame); + return 0; + +} diff --git a/source3/libsmb/libsmb_misc.c b/source3/libsmb/libsmb_misc.c new file mode 100644 index 0000000000..f2fd919ef6 --- /dev/null +++ b/source3/libsmb/libsmb_misc.c @@ -0,0 +1,73 @@ +/* + Unix SMB/Netbios implementation. + SMB client library implementation + Copyright (C) Andrew Tridgell 1998 + Copyright (C) Richard Sharpe 2000, 2002 + Copyright (C) John Terpstra 2000 + Copyright (C) Tom Jansen (Ninja ISD) 2002 + Copyright (C) Derrell Lipman 2003-2008 + 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 + 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 . +*/ + +#include "includes.h" +#include "libsmbclient.h" +#include "libsmb_internal.h" + + +/* + * check if an element is part of the list. + */ +int +SMBC_dlist_contains(SMBCFILE * list, SMBCFILE *p) +{ + if (!p || !list) return False; + do { + if (p == list) return True; + list = list->next; + } while (list); + return False; +} + + +/* + * Convert an SMB error into a UNIX error ... + */ +int +SMBC_errno(SMBCCTX *context, + struct cli_state *c) +{ + int ret = cli_errno(c); + + if (cli_is_dos_error(c)) { + uint8 eclass; + uint32 ecode; + + cli_dos_error(c, &eclass, &ecode); + + DEBUG(3,("smbc_error %d %d (0x%x) -> %d\n", + (int)eclass, (int)ecode, (int)ecode, ret)); + } else { + NTSTATUS status; + + status = cli_nt_error(c); + + DEBUG(3,("smbc errno %s -> %d\n", + nt_errstr(status), ret)); + } + + return ret; +} + diff --git a/source3/libsmb/libsmb_path.c b/source3/libsmb/libsmb_path.c new file mode 100644 index 0000000000..2533f536c3 --- /dev/null +++ b/source3/libsmb/libsmb_path.c @@ -0,0 +1,399 @@ +/* + Unix SMB/Netbios implementation. + SMB client library implementation + Copyright (C) Andrew Tridgell 1998 + Copyright (C) Richard Sharpe 2000, 2002 + Copyright (C) John Terpstra 2000 + Copyright (C) Tom Jansen (Ninja ISD) 2002 + Copyright (C) Derrell Lipman 2003-2008 + 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 + 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 . +*/ + +#include "includes.h" +#include "libsmbclient.h" +#include "libsmb_internal.h" + + +/* Used by urldecode_talloc() */ +static int +hex2int( unsigned int _char ) +{ + if ( _char >= 'A' && _char <='F') + return _char - 'A' + 10; + if ( _char >= 'a' && _char <='f') + return _char - 'a' + 10; + if ( _char >= '0' && _char <='9') + return _char - '0'; + return -1; +} + +/* + * SMBC_urldecode() + * and urldecode_talloc() (internal fn.) + * + * Convert strings of %xx to their single character equivalent. Each 'x' must + * be a valid hexadecimal digit, or that % sequence is left undecoded. + * + * dest may, but need not be, the same pointer as src. + * + * Returns the number of % sequences which could not be converted due to lack + * of two following hexadecimal digits. + */ +static int +urldecode_talloc(TALLOC_CTX *ctx, char **pp_dest, const char *src) +{ + int old_length = strlen(src); + int i = 0; + int err_count = 0; + size_t newlen = 1; + char *p, *dest; + + if (old_length == 0) { + return 0; + } + + *pp_dest = NULL; + for (i = 0; i < old_length; ) { + unsigned char character = src[i++]; + + if (character == '%') { + int a = i+1 < old_length ? hex2int(src[i]) : -1; + int b = i+1 < old_length ? hex2int(src[i+1]) : -1; + + /* Replace valid sequence */ + if (a != -1 && b != -1) { + /* Replace valid %xx sequence with %dd */ + character = (a * 16) + b; + if (character == '\0') { + break; /* Stop at %00 */ + } + i += 2; + } else { + err_count++; + } + } + newlen++; + } + + dest = TALLOC_ARRAY(ctx, char, newlen); + if (!dest) { + return err_count; + } + + err_count = 0; + for (p = dest, i = 0; i < old_length; ) { + unsigned char character = src[i++]; + + if (character == '%') { + int a = i+1 < old_length ? hex2int(src[i]) : -1; + int b = i+1 < old_length ? hex2int(src[i+1]) : -1; + + /* Replace valid sequence */ + if (a != -1 && b != -1) { + /* Replace valid %xx sequence with %dd */ + character = (a * 16) + b; + if (character == '\0') { + break; /* Stop at %00 */ + } + i += 2; + } else { + err_count++; + } + } + *p++ = character; + } + + *p = '\0'; + *pp_dest = dest; + return err_count; +} + +int +SMBC_urldecode(char *dest, + char *src, + size_t max_dest_len) +{ + TALLOC_CTX *frame = talloc_stackframe(); + char *pdest; + int ret = urldecode_talloc(frame, &pdest, src); + + if (pdest) { + strlcpy(dest, pdest, max_dest_len); + } + TALLOC_FREE(frame); + return ret; +} + +/* + * SMBC_urlencode() + * + * Convert any characters not specifically allowed in a URL into their %xx + * equivalent. + * + * Returns the remaining buffer length. + */ +int +SMBC_urlencode(char *dest, + char *src, + int max_dest_len) +{ + char hex[] = "0123456789ABCDEF"; + + for (; *src != '\0' && max_dest_len >= 3; src++) { + + if ((*src < '0' && + *src != '-' && + *src != '.') || + (*src > '9' && + *src < 'A') || + (*src > 'Z' && + *src < 'a' && + *src != '_') || + (*src > 'z')) { + *dest++ = '%'; + *dest++ = hex[(*src >> 4) & 0x0f]; + *dest++ = hex[*src & 0x0f]; + max_dest_len -= 3; + } else { + *dest++ = *src; + max_dest_len--; + } + } + + *dest++ = '\0'; + max_dest_len--; + + return max_dest_len; +} + +/* + * Function to parse a path and turn it into components + * + * The general format of an SMB URI is explain in Christopher Hertel's CIFS + * book, at http://ubiqx.org/cifs/Appendix-D.html. We accept a subset of the + * general format ("smb:" only; we do not look for "cifs:"). + * + * + * We accept: + * smb://[[[domain;]user[:password]@]server[/share[/path[/file]]]][?options] + * + * Meaning of URLs: + * + * smb:// Show all workgroups. + * + * The method of locating the list of workgroups varies + * depending upon the setting of the context variable + * context->browse_max_lmb_count. This value determines + * the maximum number of local master browsers to query + * for the list of workgroups. In order to ensure that + * a complete list of workgroups is obtained, all master + * browsers must be queried, but if there are many + * workgroups, the time spent querying can begin to add up. + * For small networks (not many workgroups), it is suggested + * that this variable be set to 0, indicating query all local + * master browsers. When the network has many workgroups, a + * reasonable setting for this variable might be around 3. + * + * smb://name/ if name<1D> or name<1B> exists, list servers in + * workgroup, else, if name<20> exists, list all shares + * for server ... + * + * If "options" are provided, this function returns the entire option list as a + * string, for later parsing by the caller. Note that currently, no options + * are supported. + */ + +static const char *smbc_prefix = "smb:"; + +int +SMBC_parse_path(TALLOC_CTX *ctx, + SMBCCTX *context, + const char *fname, + char **pp_workgroup, + char **pp_server, + char **pp_share, + char **pp_path, + char **pp_user, + char **pp_password, + char **pp_options) +{ + char *s; + const char *p; + char *q, *r; + int len; + + /* Ensure these returns are at least valid pointers. */ + *pp_server = talloc_strdup(ctx, ""); + *pp_share = talloc_strdup(ctx, ""); + *pp_path = talloc_strdup(ctx, ""); + *pp_user = talloc_strdup(ctx, ""); + *pp_password = talloc_strdup(ctx, ""); + + if (!*pp_server || !*pp_share || !*pp_path || + !*pp_user || !*pp_password) { + return -1; + } + + /* + * Assume we wont find an authentication domain to parse, so default + * to the workgroup in the provided context. + */ + if (pp_workgroup != NULL) { + *pp_workgroup = talloc_strdup(ctx, context->workgroup); + } + + if (pp_options) { + *pp_options = talloc_strdup(ctx, ""); + } + s = talloc_strdup(ctx, fname); + + /* see if it has the right prefix */ + len = strlen(smbc_prefix); + if (strncmp(s,smbc_prefix,len) || (s[len] != '/' && s[len] != 0)) { + return -1; /* What about no smb: ? */ + } + + p = s + len; + + /* Watch the test below, we are testing to see if we should exit */ + + if (strncmp(p, "//", 2) && strncmp(p, "\\\\", 2)) { + DEBUG(1, ("Invalid path (does not begin with smb://")); + return -1; + } + + p += 2; /* Skip the double slash */ + + /* See if any options were specified */ + if ((q = strrchr(p, '?')) != NULL ) { + /* There are options. Null terminate here and point to them */ + *q++ = '\0'; + + DEBUG(4, ("Found options '%s'", q)); + + /* Copy the options */ + if (*pp_options != NULL) { + TALLOC_FREE(*pp_options); + *pp_options = talloc_strdup(ctx, q); + } + } + + if (*p == '\0') { + goto decoding; + } + + if (*p == '/') { + int wl = strlen(context->workgroup); + + if (wl > 16) { + wl = 16; + } + + *pp_server = talloc_strdup(ctx, context->workgroup); + if (!*pp_server) { + return -1; + } + *pp_server[wl] = '\0'; + return 0; + } + + /* + * ok, its for us. Now parse out the server, share etc. + * + * However, we want to parse out [[domain;]user[:password]@] if it + * exists ... + */ + + /* check that '@' occurs before '/', if '/' exists at all */ + q = strchr_m(p, '@'); + r = strchr_m(p, '/'); + if (q && (!r || q < r)) { + char *userinfo = NULL; + const char *u; + + next_token_no_ltrim_talloc(ctx, &p, &userinfo, "@"); + if (!userinfo) { + return -1; + } + u = userinfo; + + if (strchr_m(u, ';')) { + char *workgroup; + next_token_no_ltrim_talloc(ctx, &u, &workgroup, ";"); + if (!workgroup) { + return -1; + } + if (pp_workgroup) { + *pp_workgroup = workgroup; + } + } + + if (strchr_m(u, ':')) { + next_token_no_ltrim_talloc(ctx, &u, pp_user, ":"); + if (!*pp_user) { + return -1; + } + *pp_password = talloc_strdup(ctx, u); + if (!*pp_password) { + return -1; + } + } else { + *pp_user = talloc_strdup(ctx, u); + if (!*pp_user) { + return -1; + } + } + } + + if (!next_token_talloc(ctx, &p, pp_server, "/")) { + return -1; + } + + if (*p == (char)0) { + goto decoding; /* That's it ... */ + } + + if (!next_token_talloc(ctx, &p, pp_share, "/")) { + return -1; + } + + /* + * Prepend a leading slash if there's a file path, as required by + * NetApp filers. + */ + if (*p != '\0') { + *pp_path = talloc_asprintf(ctx, + "\\%s", + p); + } else { + *pp_path = talloc_strdup(ctx, ""); + } + if (!*pp_path) { + return -1; + } + string_replace(*pp_path, '/', '\\'); + + decoding: + + (void) urldecode_talloc(ctx, pp_path, *pp_path); + (void) urldecode_talloc(ctx, pp_server, *pp_server); + (void) urldecode_talloc(ctx, pp_share, *pp_share); + (void) urldecode_talloc(ctx, pp_user, *pp_user); + (void) urldecode_talloc(ctx, pp_password, *pp_password); + + return 0; +} + diff --git a/source3/libsmb/libsmb_printjob.c b/source3/libsmb/libsmb_printjob.c new file mode 100644 index 0000000000..f106080b6f --- /dev/null +++ b/source3/libsmb/libsmb_printjob.c @@ -0,0 +1,334 @@ +/* + Unix SMB/Netbios implementation. + SMB client library implementation + Copyright (C) Andrew Tridgell 1998 + Copyright (C) Richard Sharpe 2000, 2002 + Copyright (C) John Terpstra 2000 + Copyright (C) Tom Jansen (Ninja ISD) 2002 + Copyright (C) Derrell Lipman 2003-2008 + 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 + 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 . +*/ + +#include "includes.h" +#include "libsmbclient.h" +#include "libsmb_internal.h" + + +/* + * Open a print file to be written to by other calls + */ + +SMBCFILE * +SMBC_open_print_job_ctx(SMBCCTX *context, + const char *fname) +{ + char *server = NULL; + char *share = NULL; + char *user = NULL; + char *password = NULL; + char *path = NULL; + TALLOC_CTX *frame = talloc_stackframe(); + + if (!context || !context->initialized) { + + errno = EINVAL; + TALLOC_FREE(frame); + return NULL; + } + + if (!fname) { + errno = EINVAL; + TALLOC_FREE(frame); + return NULL; + } + + DEBUG(4, ("SMBC_open_print_job_ctx(%s)\n", fname)); + + if (SMBC_parse_path(frame, + context, + fname, + NULL, + &server, + &share, + &path, + &user, + &password, + NULL)) { + errno = EINVAL; + TALLOC_FREE(frame); + return NULL; + } + + /* What if the path is empty, or the file exists? */ + + TALLOC_FREE(frame); + return (context->posix_emu.open_fn)(context, fname, O_WRONLY, 666); +} + +/* + * Routine to print a file on a remote server ... + * + * We open the file, which we assume to be on a remote server, and then + * copy it to a print file on the share specified by printq. + */ + +int +SMBC_print_file_ctx(SMBCCTX *c_file, + const char *fname, + SMBCCTX *c_print, + const char *printq) +{ + SMBCFILE *fid1; + SMBCFILE *fid2; + int bytes; + int saverr; + int tot_bytes = 0; + char buf[4096]; + TALLOC_CTX *frame = talloc_stackframe(); + + if (!c_file || !c_file->initialized || + !c_print || !c_print->initialized) { + + errno = EINVAL; + TALLOC_FREE(frame); + return -1; + + } + + if (!fname && !printq) { + + errno = EINVAL; + TALLOC_FREE(frame); + return -1; + + } + + /* Try to open the file for reading ... */ + + if ((long)(fid1 = smbc_getFunctionOpen(c_file)(c_file, fname, O_RDONLY, 0666)) < 0) { + DEBUG(3, ("Error, fname=%s, errno=%i\n", fname, errno)); + TALLOC_FREE(frame); + return -1; /* smbc_open sets errno */ + } + + /* Now, try to open the printer file for writing */ + + if ((long)(fid2 = smbc_getFunctionOpenPrintJob(c_print)(c_print, printq)) < 0) { + + saverr = errno; /* Save errno */ + smbc_getFunctionClose(c_file)(c_file, fid1); + errno = saverr; + TALLOC_FREE(frame); + return -1; + + } + + while ((bytes = smbc_getFunctionRead(c_file)(c_file, fid1, + buf, sizeof(buf))) > 0) { + + tot_bytes += bytes; + + if ((smbc_getFunctionWrite(c_print)(c_print, fid2, + buf, bytes)) < 0) { + + saverr = errno; + smbc_getFunctionClose(c_file)(c_file, fid1); + smbc_getFunctionClose(c_print)(c_print, fid2); + errno = saverr; + + } + + } + + saverr = errno; + + smbc_getFunctionClose(c_file)(c_file, fid1); /* We have to close these anyway */ + smbc_getFunctionClose(c_print)(c_print, fid2); + + if (bytes < 0) { + + errno = saverr; + TALLOC_FREE(frame); + return -1; + + } + + TALLOC_FREE(frame); + return tot_bytes; + +} + +/* + * Routine to list print jobs on a printer share ... + */ + +int +SMBC_list_print_jobs_ctx(SMBCCTX *context, + const char *fname, + smbc_list_print_job_fn fn) +{ + 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->initialized) { + + errno = EINVAL; + TALLOC_FREE(frame); + return -1; + } + + if (!fname) { + errno = EINVAL; + TALLOC_FREE(frame); + return -1; + } + + DEBUG(4, ("smbc_list_print_jobs(%s)\n", fname)); + + if (SMBC_parse_path(frame, + context, + fname, + &workgroup, + &server, + &share, + &path, + &user, + &password, + NULL)) { + errno = EINVAL; + TALLOC_FREE(frame); + return -1; + } + + if (!user || user[0] == (char)0) { + user = talloc_strdup(frame, context->user); + if (!user) { + errno = ENOMEM; + TALLOC_FREE(frame); + return -1; + } + } + + srv = SMBC_server(frame, context, True, + server, share, &workgroup, &user, &password); + + if (!srv) { + TALLOC_FREE(frame); + return -1; /* errno set by SMBC_server */ + } + + if (cli_print_queue(srv->cli, + (void (*)(struct print_job_info *))fn) < 0) { + errno = SMBC_errno(context, srv->cli); + TALLOC_FREE(frame); + return -1; + } + + TALLOC_FREE(frame); + return 0; + +} + +/* + * Delete a print job from a remote printer share + */ + +int +SMBC_unlink_print_job_ctx(SMBCCTX *context, + const char *fname, + int id) +{ + 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(); + + if (!context || !context->initialized) { + + errno = EINVAL; + TALLOC_FREE(frame); + return -1; + } + + if (!fname) { + errno = EINVAL; + TALLOC_FREE(frame); + return -1; + } + + DEBUG(4, ("smbc_unlink_print_job(%s)\n", fname)); + + if (SMBC_parse_path(frame, + context, + fname, + &workgroup, + &server, + &share, + &path, + &user, + &password, + NULL)) { + errno = EINVAL; + TALLOC_FREE(frame); + return -1; + } + + if (!user || user[0] == (char)0) { + user = talloc_strdup(frame, context->user); + if (!user) { + errno = ENOMEM; + TALLOC_FREE(frame); + return -1; + } + } + + srv = SMBC_server(frame, context, True, + server, share, &workgroup, &user, &password); + + if (!srv) { + + TALLOC_FREE(frame); + return -1; /* errno set by SMBC_server */ + + } + + if ((err = cli_printjob_del(srv->cli, id)) != 0) { + + if (err < 0) + errno = SMBC_errno(context, srv->cli); + else if (err == ERRnosuchprintjob) + errno = EINVAL; + TALLOC_FREE(frame); + return -1; + + } + + TALLOC_FREE(frame); + return 0; + +} + diff --git a/source3/libsmb/libsmb_server.c b/source3/libsmb/libsmb_server.c new file mode 100644 index 0000000000..978a843d30 --- /dev/null +++ b/source3/libsmb/libsmb_server.c @@ -0,0 +1,675 @@ +/* + Unix SMB/Netbios implementation. + SMB client library implementation + Copyright (C) Andrew Tridgell 1998 + Copyright (C) Richard Sharpe 2000, 2002 + Copyright (C) John Terpstra 2000 + Copyright (C) Tom Jansen (Ninja ISD) 2002 + Copyright (C) Derrell Lipman 2003-2008 + 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 + 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 . +*/ + +#include "includes.h" +#include "libsmbclient.h" +#include "libsmb_internal.h" + + +/* + * Check a server for being alive and well. + * returns 0 if the server is in shape. Returns 1 on error + * + * Also useable outside libsmbclient to enable external cache + * to do some checks too. + */ +int +SMBC_check_server(SMBCCTX * context, + SMBCSRV * server) +{ + socklen_t size; + struct sockaddr addr; + + size = sizeof(addr); + return (getpeername(server->cli->fd, &addr, &size) == -1); +} + +/* + * Remove a server from the cached server list it's unused. + * On success, 0 is returned. 1 is returned if the server could not be removed. + * + * Also useable outside libsmbclient + */ +int +SMBC_remove_unused_server(SMBCCTX * context, + SMBCSRV * srv) +{ + SMBCFILE * file; + + /* are we being fooled ? */ + if (!context || !context->initialized || !srv) { + return 1; + } + + /* Check all open files/directories for a relation with this server */ + for (file = context->files; file; file = file->next) { + if (file->srv == srv) { + /* Still used */ + DEBUG(3, ("smbc_remove_usused_server: " + "%p still used by %p.\n", + srv, file)); + return 1; + } + } + + DLIST_REMOVE(context->servers, srv); + + cli_shutdown(srv->cli); + srv->cli = NULL; + + DEBUG(3, ("smbc_remove_usused_server: %p removed.\n", srv)); + + (context->cache.remove_cached_server_fn)(context, srv); + + SAFE_FREE(srv); + return 0; +} + +/**************************************************************** + * Call the auth_fn with fixed size (fstring) buffers. + ***************************************************************/ +void +SMBC_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)); + + (context->server.get_auth_data_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); +} + + +void +SMBC_get_auth_data(const char *server, const char *share, + char *workgroup_buf, int workgroup_buf_len, + char *username_buf, int username_buf_len, + char *password_buf, int password_buf_len) +{ + /* Default function just uses provided data. Nothing to do. */ +} + + + +SMBCSRV * +SMBC_find_server(TALLOC_CTX *ctx, + SMBCCTX *context, + const char *server, + const char *share, + char **pp_workgroup, + char **pp_username, + char **pp_password) +{ + SMBCSRV *srv; + int auth_called = 0; + + check_server_cache: + + srv = (context->cache.get_cached_server_fn)(context, + server, share, + *pp_workgroup, + *pp_username); + + if (!auth_called && !srv && (!*pp_username || !(*pp_username)[0] || + !*pp_password || !(*pp_password)[0])) { + SMBC_call_auth_fn(ctx, context, server, share, + pp_workgroup, pp_username, pp_password); + + if (!pp_workgroup || !pp_username || !pp_password) { + return NULL; + } + + /* + * However, smbc_auth_fn may have picked up info relating to + * an existing connection, so try for an existing connection + * again ... + */ + auth_called = 1; + goto check_server_cache; + + } + + if (srv) { + if ((context->server.check_server_fn)(context, srv)) { + /* + * This server is no good anymore + * Try to remove it and check for more possible + * servers in the cache + */ + if ((context->server.remove_unused_server_fn)(context, + srv)) { + /* + * We could not remove the server completely, + * remove it from the cache so we will not get + * it again. It will be removed when the last + * file/dir is closed. + */ + (context->cache.remove_cached_server_fn)(context, + srv); + } + + /* + * Maybe there are more cached connections to this + * server + */ + goto check_server_cache; + } + + return srv; + } + + return NULL; +} + +/* + * Connect to a server, possibly on an existing connection + * + * Here, what we want to do is: If the server and username + * match an existing connection, reuse that, otherwise, establish a + * new connection. + * + * If we have to create a new connection, call the auth_fn to get the + * info we need, unless the username and password were passed in. + */ + +SMBCSRV * +SMBC_server(TALLOC_CTX *ctx, + SMBCCTX *context, + bool connect_if_not_found, + const char *server, + const char *share, + char **pp_workgroup, + char **pp_username, + char **pp_password) +{ + SMBCSRV *srv=NULL; + struct cli_state *c; + struct nmb_name called, calling; + const char *server_n = server; + struct sockaddr_storage ss; + int tried_reverse = 0; + int port_try_first; + int port_try_next; + const char *username_used; + NTSTATUS status; + + zero_addr(&ss); + ZERO_STRUCT(c); + + if (server[0] == 0) { + errno = EPERM; + return NULL; + } + + /* Look for a cached connection */ + srv = SMBC_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 + * server... + */ + if (srv && *share != '\0' && context->one_share_per_server) { + + /* + * ... then if there's no current connection to the share, + * connect to it. SMBC_find_server(), or rather the function + * pointed to by context->cache.get_cached_srv_fn which + * was called by SMBC_find_server(), will have issued a tree + * disconnect if the requested share is not the same as the + * one that was already connected. + */ + if (srv->cli->cnum == (uint16) -1) { + /* Ensure we have accurate auth info */ + SMBC_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->cache.remove_cached_server_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, "?????", + *pp_password, + strlen(*pp_password)+1)) { + + errno = SMBC_errno(context, srv->cli); + cli_shutdown(srv->cli); + srv->cli = NULL; + (context->cache.remove_cached_server_fn)(context, + srv); + srv = NULL; + } + + /* + * Regenerate the dev value since it's based on both + * server and share + */ + if (srv) { + srv->dev = (dev_t)(str_checksum(server) ^ + str_checksum(share)); + } + } + } + + /* If we have a connection... */ + if (srv) { + + /* ... then we're done here. Give 'em what they came for. */ + return srv; + } + + /* If we're not asked to connect when a connection doesn't exist... */ + if (! connect_if_not_found) { + /* ... then we're done here. */ + 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); + + DEBUG(4,("SMBC_server: server_n=[%s] server=[%s]\n", server_n, server)); + + DEBUG(4,(" -> server_n=[%s] server=[%s]\n", server_n, server)); + + again: + + zero_addr(&ss); + + /* have to open a new connection */ + if ((c = cli_initialise()) == NULL) { + errno = ENOMEM; + return NULL; + } + + if (context->use_kerberos) { + c->use_kerberos = True; + } + if (context->fallback_after_kerberos) { + c->fallback_after_kerberos = True; + } + + c->timeout = context->timeout; + + /* + * Force use of port 139 for first try if share is $IPC, empty, or + * null, so browse lists can work + */ + if (share == NULL || *share == '\0' || strcmp(share, "IPC$") == 0) { + port_try_first = 139; + port_try_next = 445; + } else { + port_try_first = 445; + port_try_next = 139; + } + + c->port = port_try_first; + + status = cli_connect(c, server_n, &ss); + if (!NT_STATUS_IS_OK(status)) { + + /* First connection attempt failed. Try alternate port. */ + c->port = port_try_next; + + status = cli_connect(c, server_n, &ss); + if (!NT_STATUS_IS_OK(status)) { + cli_shutdown(c); + errno = ETIMEDOUT; + return NULL; + } + } + + if (!cli_session_request(c, &calling, &called)) { + cli_shutdown(c); + if (strcmp(called.name, "*SMBSERVER")) { + make_nmb_name(&called , "*SMBSERVER", 0x20); + goto again; + } else { /* Try one more time, but ensure we don't loop */ + + /* Only try this if server is an IP address ... */ + + if (is_ipaddress(server) && !tried_reverse) { + fstring remote_name; + struct sockaddr_storage rem_ss; + + if (!interpret_string_addr(&rem_ss, server, + NI_NUMERICHOST)) { + DEBUG(4, ("Could not convert IP address " + "%s to struct sockaddr_storage\n", + server)); + errno = ETIMEDOUT; + return NULL; + } + + tried_reverse++; /* Yuck */ + + if (name_status_find("*", 0, 0, &rem_ss, remote_name)) { + make_nmb_name(&called, remote_name, 0x20); + goto again; + } + } + } + errno = ETIMEDOUT; + return NULL; + } + + DEBUG(4,(" session request ok\n")); + + if (!cli_negprot(c)) { + cli_shutdown(c); + errno = ETIMEDOUT; + return NULL; + } + + username_used = *pp_username; + + if (!NT_STATUS_IS_OK(cli_session_setup(c, username_used, + *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->no_auto_anonymous_login || + !NT_STATUS_IS_OK(cli_session_setup(c, username_used, + *pp_password, 1, + *pp_password, 0, + *pp_workgroup))) { + + cli_shutdown(c); + errno = EPERM; + return NULL; + } + } + + DEBUG(4,(" session setup ok\n")); + + if (!cli_send_tconX(c, share, "?????", + *pp_password, strlen(*pp_password)+1)) { + errno = SMBC_errno(context, c); + cli_shutdown(c); + return NULL; + } + + DEBUG(4,(" tconx ok\n")); + + if (context->smb_encryption_level) { + /* Attempt UNIX smb encryption. */ + if (!NT_STATUS_IS_OK(cli_force_encryption(c, + username_used, + *pp_password, + *pp_workgroup))) { + + /* + * context->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->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. + */ + + srv = SMB_MALLOC_P(SMBCSRV); + if (!srv) { + errno = ENOMEM; + goto failed; + } + + ZERO_STRUCTP(srv); + srv->cli = c; + srv->dev = (dev_t)(str_checksum(server) ^ str_checksum(share)); + srv->no_pathinfo = False; + srv->no_pathinfo2 = False; + srv->no_nt_session = False; + + /* now add it to the cache (internal or external) */ + /* Let the cache function set errno if it wants to */ + errno = 0; + if ((context->cache.add_cached_server_fn)(context, srv, + server, share, + *pp_workgroup, + *pp_username)) { + int saved_errno = errno; + DEBUG(3, (" Failed to add server to cache\n")); + errno = saved_errno; + if (errno == 0) { + errno = ENOMEM; + } + goto failed; + } + + DEBUG(2, ("Server connect ok: //%s/%s: %p\n", + server, share, srv)); + + DLIST_ADD(context->servers, srv); + return srv; + + failed: + cli_shutdown(c); + if (!srv) { + return NULL; + } + + SAFE_FREE(srv); + return NULL; +} + +/* + * Connect to a server for getting/setting attributes, possibly on an existing + * connection. This works similarly to SMBC_server(). + */ +SMBCSRV * +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; + struct cli_state *ipc_cli; + struct rpc_pipe_client *pipe_hnd; + NTSTATUS nt_status; + SMBCSRV *ipc_srv=NULL; + + /* + * See if we've already created this special connection. Reference + * our "special" share name '*IPC$', which is an impossible real share + * name due to the leading asterisk. + */ + ipc_srv = SMBC_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 (!*pp_password || (*pp_password)[0] == '\0') { + /* ... then retrieve it now. */ + SMBC_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; + if (context->use_kerberos) { + flags |= CLI_FULL_CONNECTION_USE_KERBEROS; + } + + zero_addr(&ss); + nt_status = cli_full_connection(&ipc_cli, + 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))); + errno = ENOTSUP; + return NULL; + } + + if (context->smb_encryption_level) { + /* Attempt UNIX smb encryption. */ + if (!NT_STATUS_IS_OK(cli_force_encryption(ipc_cli, + *pp_username, + *pp_password, + *pp_workgroup))) { + + /* + * context->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->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; + cli_shutdown(ipc_cli); + return NULL; + } + + ZERO_STRUCTP(ipc_srv); + ipc_srv->cli = ipc_cli; + + 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, + &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->cache.add_cached_server_fn)(context, ipc_srv, + server, + "*IPC$", + *pp_workgroup, + *pp_username)) { + DEBUG(3, (" Failed to add server to cache\n")); + if (errno == 0) { + errno = ENOMEM; + } + cli_shutdown(ipc_srv->cli); + free(ipc_srv); + return NULL; + } + + DLIST_ADD(context->servers, ipc_srv); + } + + return ipc_srv; +} diff --git a/source3/libsmb/libsmb_stat.c b/source3/libsmb/libsmb_stat.c new file mode 100644 index 0000000000..06238863b7 --- /dev/null +++ b/source3/libsmb/libsmb_stat.c @@ -0,0 +1,302 @@ +/* + Unix SMB/Netbios implementation. + SMB client library implementation + Copyright (C) Andrew Tridgell 1998 + Copyright (C) Richard Sharpe 2000, 2002 + Copyright (C) John Terpstra 2000 + Copyright (C) Tom Jansen (Ninja ISD) 2002 + Copyright (C) Derrell Lipman 2003-2008 + 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 + 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 . +*/ + +#include "includes.h" +#include "libsmbclient.h" +#include "libsmb_internal.h" + + +/* + * Generate an inode number from file name for those things that need it + */ + +static ino_t +generate_inode(SMBCCTX *context, + const char *name) +{ + if (!context || !context->initialized) { + + errno = EINVAL; + return -1; + + } + + if (!*name) return 2; /* FIXME, why 2 ??? */ + return (ino_t)str_checksum(name); + +} + +/* + * Routine to put basic stat info into a stat structure ... Used by stat and + * fstat below. + */ + +static int +setup_stat(SMBCCTX *context, + struct stat *st, + char *fname, + SMB_OFF_T size, + int mode) +{ + TALLOC_CTX *frame = talloc_stackframe(); + + st->st_mode = 0; + + if (IS_DOS_DIR(mode)) { + st->st_mode = SMBC_DIR_MODE; + } else { + st->st_mode = SMBC_FILE_MODE; + } + + if (IS_DOS_ARCHIVE(mode)) st->st_mode |= S_IXUSR; + if (IS_DOS_SYSTEM(mode)) st->st_mode |= S_IXGRP; + if (IS_DOS_HIDDEN(mode)) st->st_mode |= S_IXOTH; + if (!IS_DOS_READONLY(mode)) st->st_mode |= S_IWUSR; + + st->st_size = size; +#ifdef HAVE_STAT_ST_BLKSIZE + st->st_blksize = 512; +#endif +#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(); + + if (IS_DOS_DIR(mode)) { + st->st_nlink = 2; + } else { + st->st_nlink = 1; + } + + if (st->st_ino == 0) { + st->st_ino = generate_inode(context, fname); + } + + TALLOC_FREE(frame); + return True; /* FIXME: Is this needed ? */ + +} + +/* + * Routine to stat a file given a name + */ + +int +SMBC_stat_ctx(SMBCCTX *context, + const char *fname, + struct stat *st) +{ + 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; + SMB_OFF_T size = 0; + uint16 mode = 0; + SMB_INO_T ino = 0; + TALLOC_CTX *frame = talloc_stackframe(); + + if (!context || !context->initialized) { + + errno = EINVAL; /* Best I can think of ... */ + TALLOC_FREE(frame); + return -1; + } + + if (!fname) { + errno = EINVAL; + TALLOC_FREE(frame); + return -1; + } + + DEBUG(4, ("smbc_stat(%s)\n", fname)); + + if (SMBC_parse_path(frame, + context, + fname, + &workgroup, + &server, + &share, + &path, + &user, + &password, + NULL)) { + errno = EINVAL; + TALLOC_FREE(frame); + return -1; + } + + if (!user || user[0] == (char)0) { + user = talloc_strdup(frame,context->user); + if (!user) { + errno = ENOMEM; + TALLOC_FREE(frame); + return -1; + } + } + + srv = SMBC_server(frame, context, True, + server, share, &workgroup, &user, &password); + + if (!srv) { + TALLOC_FREE(frame); + return -1; /* errno set by SMBC_server */ + } + + if (!SMBC_getatr(context, srv, path, &mode, &size, + NULL, + &access_time_ts, + &write_time_ts, + &change_time_ts, + &ino)) { + errno = SMBC_errno(context, srv->cli); + TALLOC_FREE(frame); + return -1; + } + + st->st_ino = ino; + + setup_stat(context, st, (char *) fname, size, mode); + + set_atimespec(st, access_time_ts); + set_ctimespec(st, change_time_ts); + set_mtimespec(st, write_time_ts); + st->st_dev = srv->dev; + + TALLOC_FREE(frame); + return 0; + +} + +/* + * Routine to stat a file given an fd + */ + +int +SMBC_fstat_ctx(SMBCCTX *context, + SMBCFILE *file, + struct stat *st) +{ + struct timespec change_time_ts; + struct timespec access_time_ts; + struct timespec write_time_ts; + SMB_OFF_T size; + uint16 mode; + 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(); + + if (!context || !context->initialized) { + + errno = EINVAL; + TALLOC_FREE(frame); + return -1; + } + + if (!file || !SMBC_dlist_contains(context->files, file)) { + errno = EBADF; + TALLOC_FREE(frame); + return -1; + } + + if (!file->file) { + TALLOC_FREE(frame); + return (context->posix_emu.fstatdir_fn)(context, file, st); + } + + /*d_printf(">>>fstat: parsing %s\n", file->fname);*/ + if (SMBC_parse_path(frame, + context, + file->fname, + NULL, + &server, + &share, + &path, + &user, + &password, + NULL)) { + errno = EINVAL; + TALLOC_FREE(frame); + return -1; + } + + /*d_printf(">>>fstat: resolving %s\n", path);*/ + if (!cli_resolve_path(frame, "", file->srv->cli, path, + &targetcli, &targetpath)) { + d_printf("Could not resolve %s\n", path); + TALLOC_FREE(frame); + return -1; + } + /*d_printf(">>>fstat: resolved path as %s\n", targetpath);*/ + + if (!cli_qfileinfo(targetcli, file->cli_fd, &mode, &size, + NULL, + &access_time_ts, + &write_time_ts, + &change_time_ts, + &ino)) { + + time_t change_time, access_time, write_time; + + if (!cli_getattrE(targetcli, file->cli_fd, &mode, &size, + &change_time, &access_time, &write_time)) { + + errno = EINVAL; + TALLOC_FREE(frame); + return -1; + } + + change_time_ts = convert_time_t_to_timespec(change_time); + access_time_ts = convert_time_t_to_timespec(access_time); + write_time_ts = convert_time_t_to_timespec(write_time); + } + + st->st_ino = ino; + + setup_stat(context, st, file->fname, size, mode); + + set_atimespec(st, access_time_ts); + set_ctimespec(st, change_time_ts); + set_mtimespec(st, write_time_ts); + st->st_dev = file->srv->dev; + + TALLOC_FREE(frame); + return 0; + +} diff --git a/source3/libsmb/libsmb_xattr.c b/source3/libsmb/libsmb_xattr.c new file mode 100644 index 0000000000..93ca0706b2 --- /dev/null +++ b/source3/libsmb/libsmb_xattr.c @@ -0,0 +1,2293 @@ +/* + Unix SMB/Netbios implementation. + SMB client library implementation + Copyright (C) Andrew Tridgell 1998 + Copyright (C) Richard Sharpe 2000, 2002 + Copyright (C) John Terpstra 2000 + Copyright (C) Tom Jansen (Ninja ISD) 2002 + Copyright (C) Derrell Lipman 2003-2008 + 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 + 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 . +*/ + +#include "includes.h" +#include "libsmbclient.h" +#include "libsmb_internal.h" + + +/* + * Find an lsa pipe handle associated with a cli struct. + */ +static struct rpc_pipe_client * +find_lsa_pipe_hnd(struct cli_state *ipc_cli) +{ + struct rpc_pipe_client *pipe_hnd; + + for (pipe_hnd = ipc_cli->pipe_list; + pipe_hnd; + pipe_hnd = pipe_hnd->next) { + + if (pipe_hnd->pipe_idx == PI_LSARPC) { + return pipe_hnd; + } + } + + return NULL; +} + +/* + * Sort ACEs according to the documentation at + * http://support.microsoft.com/kb/269175, at least as far as it defines the + * order. + */ + +static int +ace_compare(SEC_ACE *ace1, + SEC_ACE *ace2) +{ + bool b1; + bool b2; + + /* If the ACEs are equal, we have nothing more to do. */ + if (sec_ace_equal(ace1, ace2)) { + return 0; + } + + /* Inherited follow non-inherited */ + b1 = ((ace1->flags & SEC_ACE_FLAG_INHERITED_ACE) != 0); + b2 = ((ace2->flags & SEC_ACE_FLAG_INHERITED_ACE) != 0); + if (b1 != b2) { + return (b1 ? 1 : -1); + } + + /* + * What shall we do with AUDITs and ALARMs? It's undefined. We'll + * sort them after DENY and ALLOW. + */ + b1 = (ace1->type != SEC_ACE_TYPE_ACCESS_ALLOWED && + ace1->type != SEC_ACE_TYPE_ACCESS_ALLOWED_OBJECT && + ace1->type != SEC_ACE_TYPE_ACCESS_DENIED && + ace1->type != SEC_ACE_TYPE_ACCESS_DENIED_OBJECT); + b2 = (ace2->type != SEC_ACE_TYPE_ACCESS_ALLOWED && + ace2->type != SEC_ACE_TYPE_ACCESS_ALLOWED_OBJECT && + ace2->type != SEC_ACE_TYPE_ACCESS_DENIED && + ace2->type != SEC_ACE_TYPE_ACCESS_DENIED_OBJECT); + if (b1 != b2) { + return (b1 ? 1 : -1); + } + + /* Allowed ACEs follow denied ACEs */ + b1 = (ace1->type == SEC_ACE_TYPE_ACCESS_ALLOWED || + ace1->type == SEC_ACE_TYPE_ACCESS_ALLOWED_OBJECT); + b2 = (ace2->type == SEC_ACE_TYPE_ACCESS_ALLOWED || + ace2->type == SEC_ACE_TYPE_ACCESS_ALLOWED_OBJECT); + if (b1 != b2) { + return (b1 ? 1 : -1); + } + + /* + * ACEs applying to an entity's object follow those applying to the + * entity itself + */ + b1 = (ace1->type == SEC_ACE_TYPE_ACCESS_ALLOWED_OBJECT || + ace1->type == SEC_ACE_TYPE_ACCESS_DENIED_OBJECT); + b2 = (ace2->type == SEC_ACE_TYPE_ACCESS_ALLOWED_OBJECT || + ace2->type == SEC_ACE_TYPE_ACCESS_DENIED_OBJECT); + if (b1 != b2) { + return (b1 ? 1 : -1); + } + + /* + * If we get this far, the ACEs are similar as far as the + * characteristics we typically care about (those defined by the + * referenced MS document). We'll now sort by characteristics that + * just seems reasonable. + */ + + if (ace1->type != ace2->type) { + return ace2->type - ace1->type; + } + + if (sid_compare(&ace1->trustee, &ace2->trustee)) { + return sid_compare(&ace1->trustee, &ace2->trustee); + } + + if (ace1->flags != ace2->flags) { + return ace1->flags - ace2->flags; + } + + if (ace1->access_mask != ace2->access_mask) { + return ace1->access_mask - ace2->access_mask; + } + + if (ace1->size != ace2->size) { + return ace1->size - ace2->size; + } + + return memcmp(ace1, ace2, sizeof(SEC_ACE)); +} + + +static void +sort_acl(SEC_ACL *the_acl) +{ + uint32 i; + if (!the_acl) return; + + qsort(the_acl->aces, the_acl->num_aces, sizeof(the_acl->aces[0]), + QSORT_CAST ace_compare); + + for (i=1;inum_aces;) { + if (sec_ace_equal(&the_acl->aces[i-1], &the_acl->aces[i])) { + int j; + for (j=i; jnum_aces-1; j++) { + the_acl->aces[j] = the_acl->aces[j+1]; + } + the_acl->num_aces--; + } else { + i++; + } + } +} + +/* convert a SID to a string, either numeric or username/group */ +static void +convert_sid_to_string(struct cli_state *ipc_cli, + POLICY_HND *pol, + fstring str, + bool numeric, + DOM_SID *sid) +{ + char **domains = NULL; + char **names = NULL; + enum lsa_SidType *types = NULL; + struct rpc_pipe_client *pipe_hnd = find_lsa_pipe_hnd(ipc_cli); + TALLOC_CTX *ctx; + + sid_to_fstring(str, sid); + + if (numeric) { + return; /* no lookup desired */ + } + + if (!pipe_hnd) { + return; + } + + /* Ask LSA to convert the sid to a name */ + + ctx = talloc_stackframe(); + + if (!NT_STATUS_IS_OK(rpccli_lsa_lookup_sids(pipe_hnd, ctx, + pol, 1, sid, &domains, + &names, &types)) || + !domains || !domains[0] || !names || !names[0]) { + TALLOC_FREE(ctx); + return; + } + + TALLOC_FREE(ctx); + /* Converted OK */ + + slprintf(str, sizeof(fstring) - 1, "%s%s%s", + domains[0], lp_winbind_separator(), + names[0]); +} + +/* convert a string to a SID, either numeric or username/group */ +static bool +convert_string_to_sid(struct cli_state *ipc_cli, + POLICY_HND *pol, + bool numeric, + DOM_SID *sid, + const char *str) +{ + enum lsa_SidType *types = NULL; + DOM_SID *sids = NULL; + bool result = True; + TALLOC_CTX *ctx = NULL; + struct rpc_pipe_client *pipe_hnd = find_lsa_pipe_hnd(ipc_cli); + + if (!pipe_hnd) { + return False; + } + + if (numeric) { + if (strncmp(str, "S-", 2) == 0) { + return string_to_sid(sid, str); + } + + result = False; + goto done; + } + + ctx = talloc_stackframe(); + if (!NT_STATUS_IS_OK(rpccli_lsa_lookup_names(pipe_hnd, ctx, + pol, 1, &str, NULL, 1, &sids, + &types))) { + result = False; + goto done; + } + + sid_copy(sid, &sids[0]); + done: + + TALLOC_FREE(ctx); + return result; +} + + +/* parse an ACE in the same format as print_ace() */ +static bool +parse_ace(struct cli_state *ipc_cli, + POLICY_HND *pol, + SEC_ACE *ace, + bool numeric, + char *str) +{ + char *p; + const char *cp; + char *tok; + unsigned int atype; + unsigned int aflags; + unsigned int amask; + DOM_SID sid; + SEC_ACCESS mask; + const struct perm_value *v; + struct perm_value { + const char *perm; + uint32 mask; + }; + TALLOC_CTX *frame = talloc_stackframe(); + + /* These values discovered by inspection */ + static const struct perm_value special_values[] = { + { "R", 0x00120089 }, + { "W", 0x00120116 }, + { "X", 0x001200a0 }, + { "D", 0x00010000 }, + { "P", 0x00040000 }, + { "O", 0x00080000 }, + { NULL, 0 }, + }; + + static const struct perm_value standard_values[] = { + { "READ", 0x001200a9 }, + { "CHANGE", 0x001301bf }, + { "FULL", 0x001f01ff }, + { NULL, 0 }, + }; + + + ZERO_STRUCTP(ace); + p = strchr_m(str,':'); + if (!p) { + TALLOC_FREE(frame); + return False; + } + *p = '\0'; + p++; + /* Try to parse numeric form */ + + if (sscanf(p, "%i/%i/%i", &atype, &aflags, &amask) == 3 && + convert_string_to_sid(ipc_cli, pol, numeric, &sid, str)) { + goto done; + } + + /* Try to parse text form */ + + if (!convert_string_to_sid(ipc_cli, pol, numeric, &sid, str)) { + TALLOC_FREE(frame); + return false; + } + + cp = p; + if (!next_token_talloc(frame, &cp, &tok, "/")) { + TALLOC_FREE(frame); + return false; + } + + if (StrnCaseCmp(tok, "ALLOWED", strlen("ALLOWED")) == 0) { + atype = SEC_ACE_TYPE_ACCESS_ALLOWED; + } else if (StrnCaseCmp(tok, "DENIED", strlen("DENIED")) == 0) { + atype = SEC_ACE_TYPE_ACCESS_DENIED; + } else { + TALLOC_FREE(frame); + return false; + } + + /* Only numeric form accepted for flags at present */ + + if (!(next_token_talloc(frame, &cp, &tok, "/") && + sscanf(tok, "%i", &aflags))) { + TALLOC_FREE(frame); + return false; + } + + if (!next_token_talloc(frame, &cp, &tok, "/")) { + TALLOC_FREE(frame); + return false; + } + + if (strncmp(tok, "0x", 2) == 0) { + if (sscanf(tok, "%i", &amask) != 1) { + TALLOC_FREE(frame); + return false; + } + goto done; + } + + for (v = standard_values; v->perm; v++) { + if (strcmp(tok, v->perm) == 0) { + amask = v->mask; + goto done; + } + } + + p = tok; + + while(*p) { + bool found = False; + + for (v = special_values; v->perm; v++) { + if (v->perm[0] == *p) { + amask |= v->mask; + found = True; + } + } + + if (!found) { + TALLOC_FREE(frame); + return false; + } + p++; + } + + if (*p) { + TALLOC_FREE(frame); + return false; + } + + done: + mask = amask; + init_sec_ace(ace, &sid, atype, mask, aflags); + TALLOC_FREE(frame); + return true; +} + +/* add an ACE to a list of ACEs in a SEC_ACL */ +static bool +add_ace(SEC_ACL **the_acl, + SEC_ACE *ace, + TALLOC_CTX *ctx) +{ + SEC_ACL *newacl; + SEC_ACE *aces; + + if (! *the_acl) { + (*the_acl) = make_sec_acl(ctx, 3, 1, ace); + return True; + } + + if ((aces = SMB_CALLOC_ARRAY(SEC_ACE, 1+(*the_acl)->num_aces)) == NULL) { + return False; + } + memcpy(aces, (*the_acl)->aces, (*the_acl)->num_aces * sizeof(SEC_ACE)); + memcpy(aces+(*the_acl)->num_aces, ace, sizeof(SEC_ACE)); + newacl = make_sec_acl(ctx, (*the_acl)->revision, + 1+(*the_acl)->num_aces, aces); + SAFE_FREE(aces); + (*the_acl) = newacl; + return True; +} + + +/* parse a ascii version of a security descriptor */ +static SEC_DESC * +sec_desc_parse(TALLOC_CTX *ctx, + struct cli_state *ipc_cli, + POLICY_HND *pol, + bool numeric, + char *str) +{ + const char *p = str; + char *tok; + SEC_DESC *ret = NULL; + size_t sd_size; + DOM_SID *group_sid=NULL; + DOM_SID *owner_sid=NULL; + SEC_ACL *dacl=NULL; + int revision=1; + + while (next_token_talloc(ctx, &p, &tok, "\t,\r\n")) { + + if (StrnCaseCmp(tok,"REVISION:", 9) == 0) { + revision = strtol(tok+9, NULL, 16); + continue; + } + + if (StrnCaseCmp(tok,"OWNER:", 6) == 0) { + if (owner_sid) { + DEBUG(5, ("OWNER specified more than once!\n")); + goto done; + } + owner_sid = SMB_CALLOC_ARRAY(DOM_SID, 1); + if (!owner_sid || + !convert_string_to_sid(ipc_cli, pol, + numeric, + owner_sid, tok+6)) { + DEBUG(5, ("Failed to parse owner sid\n")); + goto done; + } + continue; + } + + if (StrnCaseCmp(tok,"OWNER+:", 7) == 0) { + if (owner_sid) { + DEBUG(5, ("OWNER specified more than once!\n")); + goto done; + } + owner_sid = SMB_CALLOC_ARRAY(DOM_SID, 1); + if (!owner_sid || + !convert_string_to_sid(ipc_cli, pol, + False, + owner_sid, tok+7)) { + DEBUG(5, ("Failed to parse owner sid\n")); + goto done; + } + continue; + } + + if (StrnCaseCmp(tok,"GROUP:", 6) == 0) { + if (group_sid) { + DEBUG(5, ("GROUP specified more than once!\n")); + goto done; + } + group_sid = SMB_CALLOC_ARRAY(DOM_SID, 1); + if (!group_sid || + !convert_string_to_sid(ipc_cli, pol, + numeric, + group_sid, tok+6)) { + DEBUG(5, ("Failed to parse group sid\n")); + goto done; + } + continue; + } + + if (StrnCaseCmp(tok,"GROUP+:", 7) == 0) { + if (group_sid) { + DEBUG(5, ("GROUP specified more than once!\n")); + goto done; + } + group_sid = SMB_CALLOC_ARRAY(DOM_SID, 1); + if (!group_sid || + !convert_string_to_sid(ipc_cli, pol, + False, + group_sid, tok+6)) { + DEBUG(5, ("Failed to parse group sid\n")); + goto done; + } + continue; + } + + if (StrnCaseCmp(tok,"ACL:", 4) == 0) { + SEC_ACE ace; + if (!parse_ace(ipc_cli, pol, &ace, numeric, tok+4)) { + DEBUG(5, ("Failed to parse ACL %s\n", tok)); + goto done; + } + if(!add_ace(&dacl, &ace, ctx)) { + DEBUG(5, ("Failed to add ACL %s\n", tok)); + goto done; + } + continue; + } + + if (StrnCaseCmp(tok,"ACL+:", 5) == 0) { + SEC_ACE ace; + if (!parse_ace(ipc_cli, pol, &ace, False, tok+5)) { + DEBUG(5, ("Failed to parse ACL %s\n", tok)); + goto done; + } + if(!add_ace(&dacl, &ace, ctx)) { + DEBUG(5, ("Failed to add ACL %s\n", tok)); + goto done; + } + continue; + } + + DEBUG(5, ("Failed to parse security descriptor\n")); + goto done; + } + + ret = make_sec_desc(ctx, revision, SEC_DESC_SELF_RELATIVE, + owner_sid, group_sid, NULL, dacl, &sd_size); + + done: + SAFE_FREE(group_sid); + SAFE_FREE(owner_sid); + + return ret; +} + + +/* Obtain the current dos attributes */ +static DOS_ATTR_DESC * +dos_attr_query(SMBCCTX *context, + TALLOC_CTX *ctx, + const char *filename, + SMBCSRV *srv) +{ + struct timespec create_time_ts; + struct timespec write_time_ts; + struct timespec access_time_ts; + struct timespec change_time_ts; + SMB_OFF_T size = 0; + uint16 mode = 0; + SMB_INO_T inode = 0; + DOS_ATTR_DESC *ret; + + ret = TALLOC_P(ctx, DOS_ATTR_DESC); + if (!ret) { + errno = ENOMEM; + return NULL; + } + + /* Obtain the DOS attributes */ + if (!SMBC_getatr(context, srv, CONST_DISCARD(char *, filename), + &mode, &size, + &create_time_ts, + &access_time_ts, + &write_time_ts, + &change_time_ts, + &inode)) { + errno = SMBC_errno(context, srv->cli); + DEBUG(5, ("dos_attr_query Failed to query old attributes\n")); + return NULL; + } + + ret->mode = mode; + ret->size = size; + ret->create_time = convert_timespec_to_time_t(create_time_ts); + ret->access_time = convert_timespec_to_time_t(access_time_ts); + ret->write_time = convert_timespec_to_time_t(write_time_ts); + ret->change_time = convert_timespec_to_time_t(change_time_ts); + ret->inode = inode; + + return ret; +} + + +/* parse a ascii version of a security descriptor */ +static void +dos_attr_parse(SMBCCTX *context, + DOS_ATTR_DESC *dad, + SMBCSRV *srv, + char *str) +{ + int n; + const char *p = str; + char *tok = NULL; + TALLOC_CTX *frame = NULL; + struct { + const char * create_time_attr; + const char * access_time_attr; + const char * write_time_attr; + const char * change_time_attr; + } attr_strings; + + /* Determine whether to use old-style or new-style attribute names */ + if (context->full_time_names) { + /* new-style names */ + attr_strings.create_time_attr = "CREATE_TIME"; + attr_strings.access_time_attr = "ACCESS_TIME"; + attr_strings.write_time_attr = "WRITE_TIME"; + attr_strings.change_time_attr = "CHANGE_TIME"; + } else { + /* old-style names */ + attr_strings.create_time_attr = NULL; + attr_strings.access_time_attr = "A_TIME"; + attr_strings.write_time_attr = "M_TIME"; + attr_strings.change_time_attr = "C_TIME"; + } + + /* if this is to set the entire ACL... */ + if (*str == '*') { + /* ... then increment past the first colon if there is one */ + if ((p = strchr(str, ':')) != NULL) { + ++p; + } else { + p = str; + } + } + + frame = talloc_stackframe(); + while (next_token_talloc(frame, &p, &tok, "\t,\r\n")) { + if (StrnCaseCmp(tok, "MODE:", 5) == 0) { + 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; + } + + if (StrnCaseCmp(tok, "SIZE:", 5) == 0) { + dad->size = (SMB_OFF_T)atof(tok+5); + continue; + } + + n = strlen(attr_strings.access_time_attr); + if (StrnCaseCmp(tok, attr_strings.access_time_attr, n) == 0) { + dad->access_time = (time_t)strtol(tok+n+1, NULL, 10); + continue; + } + + n = strlen(attr_strings.change_time_attr); + if (StrnCaseCmp(tok, attr_strings.change_time_attr, n) == 0) { + dad->change_time = (time_t)strtol(tok+n+1, NULL, 10); + continue; + } + + n = strlen(attr_strings.write_time_attr); + if (StrnCaseCmp(tok, attr_strings.write_time_attr, n) == 0) { + dad->write_time = (time_t)strtol(tok+n+1, NULL, 10); + continue; + } + + if (attr_strings.create_time_attr != NULL) { + n = strlen(attr_strings.create_time_attr); + if (StrnCaseCmp(tok, attr_strings.create_time_attr, + n) == 0) { + dad->create_time = (time_t)strtol(tok+n+1, + NULL, 10); + continue; + } + } + + if (StrnCaseCmp(tok, "INODE:", 6) == 0) { + dad->inode = (SMB_INO_T)atof(tok+6); + continue; + } + } + TALLOC_FREE(frame); +} + +/***************************************************** + Retrieve the acls for a file. +*******************************************************/ + +static int +cacl_get(SMBCCTX *context, + TALLOC_CTX *ctx, + SMBCSRV *srv, + struct cli_state *ipc_cli, + POLICY_HND *pol, + char *filename, + char *attr_name, + char *buf, + int bufsize) +{ + uint32 i; + int n = 0; + int n_used; + bool all; + bool all_nt; + bool all_nt_acls; + bool all_dos; + bool some_nt; + bool some_dos; + bool exclude_nt_revision = False; + bool exclude_nt_owner = False; + bool exclude_nt_group = False; + bool exclude_nt_acl = False; + bool exclude_dos_mode = False; + bool exclude_dos_size = False; + bool exclude_dos_create_time = False; + bool exclude_dos_access_time = False; + bool exclude_dos_write_time = False; + bool exclude_dos_change_time = False; + bool exclude_dos_inode = False; + bool numeric = True; + bool determine_size = (bufsize == 0); + int fnum = -1; + SEC_DESC *sd; + fstring sidstr; + fstring name_sandbox; + char *name; + char *pExclude; + char *p; + struct timespec create_time_ts; + struct timespec write_time_ts; + struct timespec access_time_ts; + struct timespec change_time_ts; + time_t create_time = (time_t)0; + time_t write_time = (time_t)0; + time_t access_time = (time_t)0; + time_t change_time = (time_t)0; + SMB_OFF_T size = 0; + uint16 mode = 0; + SMB_INO_T ino = 0; + struct cli_state *cli = srv->cli; + struct { + const char * create_time_attr; + const char * access_time_attr; + const char * write_time_attr; + const char * change_time_attr; + } attr_strings; + struct { + const char * create_time_attr; + const char * access_time_attr; + const char * write_time_attr; + const char * change_time_attr; + } excl_attr_strings; + + /* Determine whether to use old-style or new-style attribute names */ + if (context->full_time_names) { + /* new-style names */ + attr_strings.create_time_attr = "CREATE_TIME"; + attr_strings.access_time_attr = "ACCESS_TIME"; + attr_strings.write_time_attr = "WRITE_TIME"; + attr_strings.change_time_attr = "CHANGE_TIME"; + + excl_attr_strings.create_time_attr = "CREATE_TIME"; + excl_attr_strings.access_time_attr = "ACCESS_TIME"; + excl_attr_strings.write_time_attr = "WRITE_TIME"; + excl_attr_strings.change_time_attr = "CHANGE_TIME"; + } else { + /* old-style names */ + attr_strings.create_time_attr = NULL; + attr_strings.access_time_attr = "A_TIME"; + attr_strings.write_time_attr = "M_TIME"; + attr_strings.change_time_attr = "C_TIME"; + + excl_attr_strings.create_time_attr = NULL; + excl_attr_strings.access_time_attr = "dos_attr.A_TIME"; + excl_attr_strings.write_time_attr = "dos_attr.M_TIME"; + excl_attr_strings.change_time_attr = "dos_attr.C_TIME"; + } + + /* Copy name so we can strip off exclusions (if any are specified) */ + strncpy(name_sandbox, attr_name, sizeof(name_sandbox) - 1); + + /* Ensure name is null terminated */ + name_sandbox[sizeof(name_sandbox) - 1] = '\0'; + + /* Play in the sandbox */ + name = name_sandbox; + + /* If there are any exclusions, point to them and mask them from name */ + if ((pExclude = strchr(name, '!')) != NULL) + { + *pExclude++ = '\0'; + } + + all = (StrnCaseCmp(name, "system.*", 8) == 0); + all_nt = (StrnCaseCmp(name, "system.nt_sec_desc.*", 20) == 0); + all_nt_acls = (StrnCaseCmp(name, "system.nt_sec_desc.acl.*", 24) == 0); + all_dos = (StrnCaseCmp(name, "system.dos_attr.*", 17) == 0); + some_nt = (StrnCaseCmp(name, "system.nt_sec_desc.", 19) == 0); + some_dos = (StrnCaseCmp(name, "system.dos_attr.", 16) == 0); + numeric = (* (name + strlen(name) - 1) != '+'); + + /* Look for exclusions from "all" requests */ + if (all || all_nt || all_dos) { + + /* Exclusions are delimited by '!' */ + for (; + pExclude != NULL; + pExclude = (p == NULL ? NULL : p + 1)) { + + /* Find end of this exclusion name */ + if ((p = strchr(pExclude, '!')) != NULL) + { + *p = '\0'; + } + + /* Which exclusion name is this? */ + if (StrCaseCmp(pExclude, "nt_sec_desc.revision") == 0) { + exclude_nt_revision = True; + } + else if (StrCaseCmp(pExclude, "nt_sec_desc.owner") == 0) { + exclude_nt_owner = True; + } + else if (StrCaseCmp(pExclude, "nt_sec_desc.group") == 0) { + exclude_nt_group = True; + } + else if (StrCaseCmp(pExclude, "nt_sec_desc.acl") == 0) { + exclude_nt_acl = True; + } + else if (StrCaseCmp(pExclude, "dos_attr.mode") == 0) { + exclude_dos_mode = True; + } + else if (StrCaseCmp(pExclude, "dos_attr.size") == 0) { + exclude_dos_size = True; + } + else if (excl_attr_strings.create_time_attr != NULL && + StrCaseCmp(pExclude, + excl_attr_strings.change_time_attr) == 0) { + exclude_dos_create_time = True; + } + else if (StrCaseCmp(pExclude, + excl_attr_strings.access_time_attr) == 0) { + exclude_dos_access_time = True; + } + else if (StrCaseCmp(pExclude, + excl_attr_strings.write_time_attr) == 0) { + exclude_dos_write_time = True; + } + else if (StrCaseCmp(pExclude, + excl_attr_strings.change_time_attr) == 0) { + exclude_dos_change_time = True; + } + else if (StrCaseCmp(pExclude, "dos_attr.inode") == 0) { + exclude_dos_inode = True; + } + else { + DEBUG(5, ("cacl_get received unknown exclusion: %s\n", + pExclude)); + errno = ENOATTR; + return -1; + } + } + } + + n_used = 0; + + /* + * If we are (possibly) talking to an NT or new system and some NT + * attributes have been requested... + */ + if (ipc_cli && (all || some_nt || all_nt_acls)) { + /* Point to the portion after "system.nt_sec_desc." */ + name += 19; /* if (all) this will be invalid but unused */ + + /* ... then obtain any NT attributes which were requested */ + fnum = cli_nt_create(cli, filename, CREATE_ACCESS_READ); + + if (fnum == -1) { + DEBUG(5, ("cacl_get failed to open %s: %s\n", + filename, cli_errstr(cli))); + errno = 0; + return -1; + } + + sd = cli_query_secdesc(cli, fnum, ctx); + + if (!sd) { + DEBUG(5, + ("cacl_get Failed to query old descriptor\n")); + errno = 0; + return -1; + } + + cli_close(cli, fnum); + + if (! exclude_nt_revision) { + if (all || all_nt) { + if (determine_size) { + p = talloc_asprintf(ctx, + "REVISION:%d", + sd->revision); + if (!p) { + errno = ENOMEM; + return -1; + } + n = strlen(p); + } else { + n = snprintf(buf, bufsize, + "REVISION:%d", + sd->revision); + } + } else if (StrCaseCmp(name, "revision") == 0) { + if (determine_size) { + p = talloc_asprintf(ctx, "%d", + sd->revision); + if (!p) { + errno = ENOMEM; + return -1; + } + n = strlen(p); + } else { + n = snprintf(buf, bufsize, "%d", + sd->revision); + } + } + + if (!determine_size && n > bufsize) { + errno = ERANGE; + return -1; + } + buf += n; + n_used += n; + bufsize -= n; + n = 0; + } + + if (! exclude_nt_owner) { + /* Get owner and group sid */ + if (sd->owner_sid) { + convert_sid_to_string(ipc_cli, pol, + sidstr, + numeric, + sd->owner_sid); + } else { + fstrcpy(sidstr, ""); + } + + if (all || all_nt) { + if (determine_size) { + p = talloc_asprintf(ctx, ",OWNER:%s", + sidstr); + if (!p) { + errno = ENOMEM; + return -1; + } + n = strlen(p); + } else if (sidstr[0] != '\0') { + n = snprintf(buf, bufsize, + ",OWNER:%s", sidstr); + } + } else if (StrnCaseCmp(name, "owner", 5) == 0) { + if (determine_size) { + p = talloc_asprintf(ctx, "%s", sidstr); + if (!p) { + errno = ENOMEM; + return -1; + } + n = strlen(p); + } else { + n = snprintf(buf, bufsize, "%s", + sidstr); + } + } + + if (!determine_size && n > bufsize) { + errno = ERANGE; + return -1; + } + buf += n; + n_used += n; + bufsize -= n; + n = 0; + } + + if (! exclude_nt_group) { + if (sd->group_sid) { + convert_sid_to_string(ipc_cli, pol, + sidstr, numeric, + sd->group_sid); + } else { + fstrcpy(sidstr, ""); + } + + if (all || all_nt) { + if (determine_size) { + p = talloc_asprintf(ctx, ",GROUP:%s", + sidstr); + if (!p) { + errno = ENOMEM; + return -1; + } + n = strlen(p); + } else if (sidstr[0] != '\0') { + n = snprintf(buf, bufsize, + ",GROUP:%s", sidstr); + } + } else if (StrnCaseCmp(name, "group", 5) == 0) { + if (determine_size) { + p = talloc_asprintf(ctx, "%s", sidstr); + if (!p) { + errno = ENOMEM; + return -1; + } + n = strlen(p); + } else { + n = snprintf(buf, bufsize, + "%s", sidstr); + } + } + + if (!determine_size && n > bufsize) { + errno = ERANGE; + return -1; + } + buf += n; + n_used += n; + bufsize -= n; + n = 0; + } + + if (! exclude_nt_acl) { + /* Add aces to value buffer */ + for (i = 0; sd->dacl && i < sd->dacl->num_aces; i++) { + + SEC_ACE *ace = &sd->dacl->aces[i]; + convert_sid_to_string(ipc_cli, pol, + sidstr, numeric, + &ace->trustee); + + if (all || all_nt) { + if (determine_size) { + p = talloc_asprintf( + ctx, + ",ACL:" + "%s:%d/%d/0x%08x", + sidstr, + ace->type, + ace->flags, + ace->access_mask); + if (!p) { + errno = ENOMEM; + return -1; + } + n = strlen(p); + } else { + n = snprintf( + buf, bufsize, + ",ACL:%s:%d/%d/0x%08x", + sidstr, + ace->type, + ace->flags, + ace->access_mask); + } + } else if ((StrnCaseCmp(name, "acl", 3) == 0 && + StrCaseCmp(name+3, sidstr) == 0) || + (StrnCaseCmp(name, "acl+", 4) == 0 && + StrCaseCmp(name+4, sidstr) == 0)) { + if (determine_size) { + p = talloc_asprintf( + ctx, + "%d/%d/0x%08x", + ace->type, + ace->flags, + ace->access_mask); + if (!p) { + errno = ENOMEM; + return -1; + } + n = strlen(p); + } else { + n = snprintf(buf, bufsize, + "%d/%d/0x%08x", + ace->type, + ace->flags, + ace->access_mask); + } + } else if (all_nt_acls) { + if (determine_size) { + p = talloc_asprintf( + ctx, + "%s%s:%d/%d/0x%08x", + i ? "," : "", + sidstr, + ace->type, + ace->flags, + ace->access_mask); + if (!p) { + errno = ENOMEM; + return -1; + } + n = strlen(p); + } else { + n = snprintf(buf, bufsize, + "%s%s:%d/%d/0x%08x", + i ? "," : "", + sidstr, + ace->type, + ace->flags, + ace->access_mask); + } + } + if (!determine_size && n > bufsize) { + errno = ERANGE; + return -1; + } + buf += n; + n_used += n; + bufsize -= n; + n = 0; + } + } + + /* Restore name pointer to its original value */ + name -= 19; + } + + if (all || some_dos) { + /* Point to the portion after "system.dos_attr." */ + name += 16; /* if (all) this will be invalid but unused */ + + /* Obtain the DOS attributes */ + if (!SMBC_getatr(context, srv, filename, &mode, &size, + &create_time_ts, + &access_time_ts, + &write_time_ts, + &change_time_ts, + &ino)) { + + errno = SMBC_errno(context, srv->cli); + return -1; + + } + + create_time = convert_timespec_to_time_t(create_time_ts); + access_time = convert_timespec_to_time_t(access_time_ts); + write_time = convert_timespec_to_time_t(write_time_ts); + change_time = convert_timespec_to_time_t(change_time_ts); + + if (! exclude_dos_mode) { + if (all || all_dos) { + if (determine_size) { + p = talloc_asprintf(ctx, + "%sMODE:0x%x", + (ipc_cli && + (all || some_nt) + ? "," + : ""), + mode); + if (!p) { + errno = ENOMEM; + return -1; + } + n = strlen(p); + } else { + n = snprintf(buf, bufsize, + "%sMODE:0x%x", + (ipc_cli && + (all || some_nt) + ? "," + : ""), + mode); + } + } else if (StrCaseCmp(name, "mode") == 0) { + if (determine_size) { + p = talloc_asprintf(ctx, "0x%x", mode); + if (!p) { + errno = ENOMEM; + return -1; + } + n = strlen(p); + } else { + n = snprintf(buf, bufsize, + "0x%x", mode); + } + } + + if (!determine_size && n > bufsize) { + errno = ERANGE; + return -1; + } + buf += n; + n_used += n; + bufsize -= n; + n = 0; + } + + if (! exclude_dos_size) { + if (all || all_dos) { + if (determine_size) { + p = talloc_asprintf( + ctx, + ",SIZE:%.0f", + (double)size); + if (!p) { + errno = ENOMEM; + return -1; + } + n = strlen(p); + } else { + n = snprintf(buf, bufsize, + ",SIZE:%.0f", + (double)size); + } + } else if (StrCaseCmp(name, "size") == 0) { + if (determine_size) { + p = talloc_asprintf( + ctx, + "%.0f", + (double)size); + if (!p) { + errno = ENOMEM; + return -1; + } + n = strlen(p); + } else { + n = snprintf(buf, bufsize, + "%.0f", + (double)size); + } + } + + if (!determine_size && n > bufsize) { + errno = ERANGE; + return -1; + } + buf += n; + n_used += n; + bufsize -= n; + n = 0; + } + + if (! exclude_dos_create_time && + attr_strings.create_time_attr != NULL) { + if (all || all_dos) { + if (determine_size) { + p = talloc_asprintf(ctx, + ",%s:%lu", + attr_strings.create_time_attr, + create_time); + if (!p) { + errno = ENOMEM; + return -1; + } + n = strlen(p); + } else { + n = snprintf(buf, bufsize, + ",%s:%lu", + attr_strings.create_time_attr, + create_time); + } + } else if (StrCaseCmp(name, attr_strings.create_time_attr) == 0) { + if (determine_size) { + p = talloc_asprintf(ctx, "%lu", create_time); + if (!p) { + errno = ENOMEM; + return -1; + } + n = strlen(p); + } else { + n = snprintf(buf, bufsize, + "%lu", create_time); + } + } + + if (!determine_size && n > bufsize) { + errno = ERANGE; + return -1; + } + buf += n; + n_used += n; + bufsize -= n; + n = 0; + } + + if (! exclude_dos_access_time) { + if (all || all_dos) { + if (determine_size) { + p = talloc_asprintf(ctx, + ",%s:%lu", + attr_strings.access_time_attr, + access_time); + if (!p) { + errno = ENOMEM; + return -1; + } + n = strlen(p); + } else { + n = snprintf(buf, bufsize, + ",%s:%lu", + attr_strings.access_time_attr, + access_time); + } + } else if (StrCaseCmp(name, attr_strings.access_time_attr) == 0) { + if (determine_size) { + p = talloc_asprintf(ctx, "%lu", access_time); + if (!p) { + errno = ENOMEM; + return -1; + } + n = strlen(p); + } else { + n = snprintf(buf, bufsize, + "%lu", access_time); + } + } + + if (!determine_size && n > bufsize) { + errno = ERANGE; + return -1; + } + buf += n; + n_used += n; + bufsize -= n; + n = 0; + } + + if (! exclude_dos_write_time) { + if (all || all_dos) { + if (determine_size) { + p = talloc_asprintf(ctx, + ",%s:%lu", + attr_strings.write_time_attr, + write_time); + if (!p) { + errno = ENOMEM; + return -1; + } + n = strlen(p); + } else { + n = snprintf(buf, bufsize, + ",%s:%lu", + attr_strings.write_time_attr, + write_time); + } + } else if (StrCaseCmp(name, attr_strings.write_time_attr) == 0) { + if (determine_size) { + p = talloc_asprintf(ctx, "%lu", write_time); + if (!p) { + errno = ENOMEM; + return -1; + } + n = strlen(p); + } else { + n = snprintf(buf, bufsize, + "%lu", write_time); + } + } + + if (!determine_size && n > bufsize) { + errno = ERANGE; + return -1; + } + buf += n; + n_used += n; + bufsize -= n; + n = 0; + } + + if (! exclude_dos_change_time) { + if (all || all_dos) { + if (determine_size) { + p = talloc_asprintf(ctx, + ",%s:%lu", + attr_strings.change_time_attr, + change_time); + if (!p) { + errno = ENOMEM; + return -1; + } + n = strlen(p); + } else { + n = snprintf(buf, bufsize, + ",%s:%lu", + attr_strings.change_time_attr, + change_time); + } + } else if (StrCaseCmp(name, attr_strings.change_time_attr) == 0) { + if (determine_size) { + p = talloc_asprintf(ctx, "%lu", change_time); + if (!p) { + errno = ENOMEM; + return -1; + } + n = strlen(p); + } else { + n = snprintf(buf, bufsize, + "%lu", change_time); + } + } + + if (!determine_size && n > bufsize) { + errno = ERANGE; + return -1; + } + buf += n; + n_used += n; + bufsize -= n; + n = 0; + } + + if (! exclude_dos_inode) { + if (all || all_dos) { + if (determine_size) { + p = talloc_asprintf( + ctx, + ",INODE:%.0f", + (double)ino); + if (!p) { + errno = ENOMEM; + return -1; + } + n = strlen(p); + } else { + n = snprintf(buf, bufsize, + ",INODE:%.0f", + (double) ino); + } + } else if (StrCaseCmp(name, "inode") == 0) { + if (determine_size) { + p = talloc_asprintf( + ctx, + "%.0f", + (double) ino); + if (!p) { + errno = ENOMEM; + return -1; + } + n = strlen(p); + } else { + n = snprintf(buf, bufsize, + "%.0f", + (double) ino); + } + } + + if (!determine_size && n > bufsize) { + errno = ERANGE; + return -1; + } + buf += n; + n_used += n; + bufsize -= n; + n = 0; + } + + /* Restore name pointer to its original value */ + name -= 16; + } + + if (n_used == 0) { + errno = ENOATTR; + return -1; + } + + return n_used; +} + +/***************************************************** +set the ACLs on a file given an ascii description +*******************************************************/ +static int +cacl_set(TALLOC_CTX *ctx, + struct cli_state *cli, + struct cli_state *ipc_cli, + POLICY_HND *pol, + const char *filename, + const char *the_acl, + int mode, + int flags) +{ + int fnum; + int err = 0; + SEC_DESC *sd = NULL, *old; + SEC_ACL *dacl = NULL; + DOM_SID *owner_sid = NULL; + DOM_SID *group_sid = NULL; + uint32 i, j; + size_t sd_size; + int ret = 0; + char *p; + bool numeric = True; + + /* the_acl will be null for REMOVE_ALL operations */ + if (the_acl) { + numeric = ((p = strchr(the_acl, ':')) != NULL && + p > the_acl && + p[-1] != '+'); + + /* if this is to set the entire ACL... */ + if (*the_acl == '*') { + /* ... then increment past the first colon */ + the_acl = p + 1; + } + + sd = sec_desc_parse(ctx, ipc_cli, pol, numeric, + CONST_DISCARD(char *, the_acl)); + + if (!sd) { + errno = EINVAL; + return -1; + } + } + + /* SMBC_XATTR_MODE_REMOVE_ALL is the only caller + that doesn't deref sd */ + + if (!sd && (mode != SMBC_XATTR_MODE_REMOVE_ALL)) { + errno = EINVAL; + return -1; + } + + /* The desired access below is the only one I could find that works + with NT4, W2KP and Samba */ + + fnum = cli_nt_create(cli, filename, CREATE_ACCESS_READ); + + if (fnum == -1) { + DEBUG(5, ("cacl_set failed to open %s: %s\n", + filename, cli_errstr(cli))); + errno = 0; + return -1; + } + + old = cli_query_secdesc(cli, fnum, ctx); + + if (!old) { + DEBUG(5, ("cacl_set Failed to query old descriptor\n")); + errno = 0; + return -1; + } + + cli_close(cli, fnum); + + switch (mode) { + case SMBC_XATTR_MODE_REMOVE_ALL: + old->dacl->num_aces = 0; + dacl = old->dacl; + break; + + case SMBC_XATTR_MODE_REMOVE: + for (i=0;sd->dacl && idacl->num_aces;i++) { + bool found = False; + + for (j=0;old->dacl && jdacl->num_aces;j++) { + if (sec_ace_equal(&sd->dacl->aces[i], + &old->dacl->aces[j])) { + uint32 k; + for (k=j; kdacl->num_aces-1;k++) { + old->dacl->aces[k] = + old->dacl->aces[k+1]; + } + old->dacl->num_aces--; + found = True; + dacl = old->dacl; + break; + } + } + + if (!found) { + err = ENOATTR; + ret = -1; + goto failed; + } + } + break; + + case SMBC_XATTR_MODE_ADD: + for (i=0;sd->dacl && idacl->num_aces;i++) { + bool found = False; + + for (j=0;old->dacl && jdacl->num_aces;j++) { + if (sid_equal(&sd->dacl->aces[i].trustee, + &old->dacl->aces[j].trustee)) { + if (!(flags & SMBC_XATTR_FLAG_CREATE)) { + err = EEXIST; + ret = -1; + goto failed; + } + old->dacl->aces[j] = sd->dacl->aces[i]; + ret = -1; + found = True; + } + } + + if (!found && (flags & SMBC_XATTR_FLAG_REPLACE)) { + err = ENOATTR; + ret = -1; + goto failed; + } + + for (i=0;sd->dacl && idacl->num_aces;i++) { + add_ace(&old->dacl, &sd->dacl->aces[i], ctx); + } + } + dacl = old->dacl; + break; + + case SMBC_XATTR_MODE_SET: + old = sd; + owner_sid = old->owner_sid; + group_sid = old->group_sid; + dacl = old->dacl; + break; + + case SMBC_XATTR_MODE_CHOWN: + owner_sid = sd->owner_sid; + break; + + case SMBC_XATTR_MODE_CHGRP: + group_sid = sd->group_sid; + break; + } + + /* Denied ACE entries must come before allowed ones */ + sort_acl(old->dacl); + + /* Create new security descriptor and set it */ + sd = make_sec_desc(ctx, old->revision, SEC_DESC_SELF_RELATIVE, + owner_sid, group_sid, NULL, dacl, &sd_size); + + fnum = cli_nt_create(cli, filename, + WRITE_DAC_ACCESS | WRITE_OWNER_ACCESS); + + if (fnum == -1) { + DEBUG(5, ("cacl_set failed to open %s: %s\n", + filename, cli_errstr(cli))); + errno = 0; + return -1; + } + + if (!cli_set_secdesc(cli, fnum, sd)) { + DEBUG(5, ("ERROR: secdesc set failed: %s\n", cli_errstr(cli))); + ret = -1; + } + + /* Clean up */ + + failed: + cli_close(cli, fnum); + + if (err != 0) { + errno = err; + } + + return ret; +} + + +int +SMBC_setxattr_ctx(SMBCCTX *context, + const char *fname, + const char *name, + const void *value, + size_t size, + int flags) +{ + int ret; + int ret2; + 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; + const char * write_time_attr; + const char * change_time_attr; + } attr_strings; + TALLOC_CTX *frame = talloc_stackframe(); + + if (!context || !context->initialized) { + + errno = EINVAL; /* Best I can think of ... */ + TALLOC_FREE(frame); + return -1; + } + + if (!fname) { + errno = EINVAL; + TALLOC_FREE(frame); + return -1; + } + + DEBUG(4, ("smbc_setxattr(%s, %s, %.*s)\n", + fname, name, (int) size, (const char*)value)); + + if (SMBC_parse_path(frame, + context, + fname, + &workgroup, + &server, + &share, + &path, + &user, + &password, + NULL)) { + errno = EINVAL; + TALLOC_FREE(frame); + return -1; + } + + if (!user || user[0] == (char)0) { + user = talloc_strdup(frame, context->user); + if (!user) { + errno = ENOMEM; + TALLOC_FREE(frame); + return -1; + } + } + + 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(frame, context, server, share, + &workgroup, &user, &password); + if (! ipc_srv) { + srv->no_nt_session = True; + } + } else { + ipc_srv = NULL; + } + + /* + * Are they asking to set the entire set of known attributes? + */ + if (StrCaseCmp(name, "system.*") == 0 || + StrCaseCmp(name, "system.*+") == 0) { + /* Yup. */ + char *namevalue = + talloc_asprintf(talloc_tos(), "%s:%s", + name+7, (const char *) value); + if (! namevalue) { + errno = ENOMEM; + ret = -1; + TALLOC_FREE(frame); + return -1; + } + + if (ipc_srv) { + ret = cacl_set(talloc_tos(), srv->cli, + ipc_srv->cli, &ipc_srv->pol, path, + namevalue, + (*namevalue == '*' + ? SMBC_XATTR_MODE_SET + : SMBC_XATTR_MODE_ADD), + flags); + } else { + ret = 0; + } + + /* get a DOS Attribute Descriptor with current attributes */ + dad = dos_attr_query(context, talloc_tos(), path, srv); + if (dad) { + /* Overwrite old with new, using what was provided */ + dos_attr_parse(context, dad, srv, namevalue); + + /* Set the new DOS attributes */ + if (! SMBC_setatr(context, srv, path, + dad->create_time, + dad->access_time, + dad->write_time, + dad->change_time, + dad->mode)) { + + /* cause failure if NT failed too */ + dad = NULL; + } + } + + /* we only fail if both NT and DOS sets failed */ + if (ret < 0 && ! dad) { + ret = -1; /* in case dad was null */ + } + else { + ret = 0; + } + + TALLOC_FREE(frame); + return ret; + } + + /* + * Are they asking to set an access control element or to set + * the entire access control list? + */ + if (StrCaseCmp(name, "system.nt_sec_desc.*") == 0 || + StrCaseCmp(name, "system.nt_sec_desc.*+") == 0 || + StrCaseCmp(name, "system.nt_sec_desc.revision") == 0 || + StrnCaseCmp(name, "system.nt_sec_desc.acl", 22) == 0 || + StrnCaseCmp(name, "system.nt_sec_desc.acl+", 23) == 0) { + + /* Yup. */ + char *namevalue = + talloc_asprintf(talloc_tos(), "%s:%s", + name+19, (const char *) value); + + if (! ipc_srv) { + ret = -1; /* errno set by SMBC_server() */ + } + else if (! namevalue) { + errno = ENOMEM; + ret = -1; + } else { + ret = cacl_set(talloc_tos(), srv->cli, + ipc_srv->cli, &ipc_srv->pol, path, + namevalue, + (*namevalue == '*' + ? SMBC_XATTR_MODE_SET + : SMBC_XATTR_MODE_ADD), + flags); + } + TALLOC_FREE(frame); + return ret; + } + + /* + * Are they asking to set the owner? + */ + if (StrCaseCmp(name, "system.nt_sec_desc.owner") == 0 || + StrCaseCmp(name, "system.nt_sec_desc.owner+") == 0) { + + /* Yup. */ + char *namevalue = + talloc_asprintf(talloc_tos(), "%s:%s", + name+19, (const char *) value); + + if (! ipc_srv) { + ret = -1; /* errno set by SMBC_server() */ + } + else if (! namevalue) { + errno = ENOMEM; + ret = -1; + } else { + ret = cacl_set(talloc_tos(), srv->cli, + ipc_srv->cli, &ipc_srv->pol, path, + namevalue, SMBC_XATTR_MODE_CHOWN, 0); + } + TALLOC_FREE(frame); + return ret; + } + + /* + * Are they asking to set the group? + */ + if (StrCaseCmp(name, "system.nt_sec_desc.group") == 0 || + StrCaseCmp(name, "system.nt_sec_desc.group+") == 0) { + + /* Yup. */ + char *namevalue = + talloc_asprintf(talloc_tos(), "%s:%s", + name+19, (const char *) value); + + if (! ipc_srv) { + /* errno set by SMBC_server() */ + ret = -1; + } + else if (! namevalue) { + errno = ENOMEM; + ret = -1; + } else { + ret = cacl_set(talloc_tos(), srv->cli, + ipc_srv->cli, &ipc_srv->pol, path, + namevalue, SMBC_XATTR_MODE_CHGRP, 0); + } + TALLOC_FREE(frame); + return ret; + } + + /* Determine whether to use old-style or new-style attribute names */ + if (context->full_time_names) { + /* new-style names */ + attr_strings.create_time_attr = "system.dos_attr.CREATE_TIME"; + attr_strings.access_time_attr = "system.dos_attr.ACCESS_TIME"; + attr_strings.write_time_attr = "system.dos_attr.WRITE_TIME"; + attr_strings.change_time_attr = "system.dos_attr.CHANGE_TIME"; + } else { + /* old-style names */ + attr_strings.create_time_attr = NULL; + attr_strings.access_time_attr = "system.dos_attr.A_TIME"; + attr_strings.write_time_attr = "system.dos_attr.M_TIME"; + attr_strings.change_time_attr = "system.dos_attr.C_TIME"; + } + + /* + * Are they asking to set a DOS attribute? + */ + if (StrCaseCmp(name, "system.dos_attr.*") == 0 || + StrCaseCmp(name, "system.dos_attr.mode") == 0 || + (attr_strings.create_time_attr != NULL && + StrCaseCmp(name, attr_strings.create_time_attr) == 0) || + StrCaseCmp(name, attr_strings.access_time_attr) == 0 || + StrCaseCmp(name, attr_strings.write_time_attr) == 0 || + StrCaseCmp(name, attr_strings.change_time_attr) == 0) { + + /* get a DOS Attribute Descriptor with current attributes */ + dad = dos_attr_query(context, talloc_tos(), path, srv); + if (dad) { + char *namevalue = + talloc_asprintf(talloc_tos(), "%s:%s", + name+16, (const char *) value); + if (! namevalue) { + errno = ENOMEM; + ret = -1; + } else { + /* Overwrite old with provided new params */ + dos_attr_parse(context, dad, srv, namevalue); + + /* Set the new DOS attributes */ + ret2 = SMBC_setatr(context, srv, path, + dad->create_time, + dad->access_time, + dad->write_time, + dad->change_time, + dad->mode); + + /* ret2 has True (success) / False (failure) */ + if (ret2) { + ret = 0; + } else { + ret = -1; + } + } + } else { + ret = -1; + } + + TALLOC_FREE(frame); + return ret; + } + + /* Unsupported attribute name */ + errno = EINVAL; + TALLOC_FREE(frame); + return -1; +} + +int +SMBC_getxattr_ctx(SMBCCTX *context, + const char *fname, + const char *name, + const void *value, + size_t size) +{ + int ret; + 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; + const char * write_time_attr; + const char * change_time_attr; + } attr_strings; + TALLOC_CTX *frame = talloc_stackframe(); + + if (!context || !context->initialized) { + + errno = EINVAL; /* Best I can think of ... */ + TALLOC_FREE(frame); + return -1; + } + + if (!fname) { + errno = EINVAL; + TALLOC_FREE(frame); + return -1; + } + + DEBUG(4, ("smbc_getxattr(%s, %s)\n", fname, name)); + + if (SMBC_parse_path(frame, + context, + fname, + &workgroup, + &server, + &share, + &path, + &user, + &password, + NULL)) { + errno = EINVAL; + TALLOC_FREE(frame); + return -1; + } + + if (!user || user[0] == (char)0) { + user = talloc_strdup(frame, context->user); + if (!user) { + errno = ENOMEM; + TALLOC_FREE(frame); + return -1; + } + } + + 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(frame, context, server, share, + &workgroup, &user, &password); + if (! ipc_srv) { + srv->no_nt_session = True; + } + } else { + ipc_srv = NULL; + } + + /* Determine whether to use old-style or new-style attribute names */ + if (context->full_time_names) { + /* new-style names */ + attr_strings.create_time_attr = "system.dos_attr.CREATE_TIME"; + attr_strings.access_time_attr = "system.dos_attr.ACCESS_TIME"; + attr_strings.write_time_attr = "system.dos_attr.WRITE_TIME"; + attr_strings.change_time_attr = "system.dos_attr.CHANGE_TIME"; + } else { + /* old-style names */ + attr_strings.create_time_attr = NULL; + attr_strings.access_time_attr = "system.dos_attr.A_TIME"; + attr_strings.write_time_attr = "system.dos_attr.M_TIME"; + attr_strings.change_time_attr = "system.dos_attr.C_TIME"; + } + + /* Are they requesting a supported attribute? */ + if (StrCaseCmp(name, "system.*") == 0 || + StrnCaseCmp(name, "system.*!", 9) == 0 || + StrCaseCmp(name, "system.*+") == 0 || + StrnCaseCmp(name, "system.*+!", 10) == 0 || + StrCaseCmp(name, "system.nt_sec_desc.*") == 0 || + StrnCaseCmp(name, "system.nt_sec_desc.*!", 21) == 0 || + StrCaseCmp(name, "system.nt_sec_desc.*+") == 0 || + StrnCaseCmp(name, "system.nt_sec_desc.*+!", 22) == 0 || + StrCaseCmp(name, "system.nt_sec_desc.revision") == 0 || + StrCaseCmp(name, "system.nt_sec_desc.owner") == 0 || + StrCaseCmp(name, "system.nt_sec_desc.owner+") == 0 || + StrCaseCmp(name, "system.nt_sec_desc.group") == 0 || + StrCaseCmp(name, "system.nt_sec_desc.group+") == 0 || + StrnCaseCmp(name, "system.nt_sec_desc.acl", 22) == 0 || + StrnCaseCmp(name, "system.nt_sec_desc.acl+", 23) == 0 || + StrCaseCmp(name, "system.dos_attr.*") == 0 || + StrnCaseCmp(name, "system.dos_attr.*!", 18) == 0 || + StrCaseCmp(name, "system.dos_attr.mode") == 0 || + StrCaseCmp(name, "system.dos_attr.size") == 0 || + (attr_strings.create_time_attr != NULL && + StrCaseCmp(name, attr_strings.create_time_attr) == 0) || + StrCaseCmp(name, attr_strings.access_time_attr) == 0 || + StrCaseCmp(name, attr_strings.write_time_attr) == 0 || + StrCaseCmp(name, attr_strings.change_time_attr) == 0 || + StrCaseCmp(name, "system.dos_attr.inode") == 0) { + + /* Yup. */ + ret = cacl_get(context, talloc_tos(), srv, + ipc_srv == NULL ? NULL : ipc_srv->cli, + &ipc_srv->pol, path, + CONST_DISCARD(char *, name), + CONST_DISCARD(char *, value), size); + if (ret < 0 && errno == 0) { + errno = SMBC_errno(context, srv->cli); + } + TALLOC_FREE(frame); + return ret; + } + + /* Unsupported attribute name */ + errno = EINVAL; + TALLOC_FREE(frame); + return -1; +} + + +int +SMBC_removexattr_ctx(SMBCCTX *context, + const char *fname, + const char *name) +{ + int ret; + 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->initialized) { + + errno = EINVAL; /* Best I can think of ... */ + TALLOC_FREE(frame); + return -1; + } + + if (!fname) { + errno = EINVAL; + TALLOC_FREE(frame); + return -1; + } + + DEBUG(4, ("smbc_removexattr(%s, %s)\n", fname, name)); + + if (SMBC_parse_path(frame, + context, + fname, + &workgroup, + &server, + &share, + &path, + &user, + &password, + NULL)) { + errno = EINVAL; + TALLOC_FREE(frame); + return -1; + } + + if (!user || user[0] == (char)0) { + user = talloc_strdup(frame, context->user); + if (!user) { + errno = ENOMEM; + TALLOC_FREE(frame); + return -1; + } + } + + 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(frame, context, server, share, + &workgroup, &user, &password); + if (! ipc_srv) { + srv->no_nt_session = True; + } + } else { + ipc_srv = NULL; + } + + if (! ipc_srv) { + TALLOC_FREE(frame); + return -1; /* errno set by SMBC_attr_server */ + } + + /* Are they asking to set the entire ACL? */ + if (StrCaseCmp(name, "system.nt_sec_desc.*") == 0 || + StrCaseCmp(name, "system.nt_sec_desc.*+") == 0) { + + /* Yup. */ + ret = cacl_set(talloc_tos(), srv->cli, + ipc_srv->cli, &ipc_srv->pol, path, + NULL, SMBC_XATTR_MODE_REMOVE_ALL, 0); + TALLOC_FREE(frame); + return ret; + } + + /* + * Are they asking to remove one or more spceific security descriptor + * attributes? + */ + if (StrCaseCmp(name, "system.nt_sec_desc.revision") == 0 || + StrCaseCmp(name, "system.nt_sec_desc.owner") == 0 || + StrCaseCmp(name, "system.nt_sec_desc.owner+") == 0 || + StrCaseCmp(name, "system.nt_sec_desc.group") == 0 || + StrCaseCmp(name, "system.nt_sec_desc.group+") == 0 || + StrnCaseCmp(name, "system.nt_sec_desc.acl", 22) == 0 || + StrnCaseCmp(name, "system.nt_sec_desc.acl+", 23) == 0) { + + /* Yup. */ + ret = cacl_set(talloc_tos(), srv->cli, + ipc_srv->cli, &ipc_srv->pol, path, + name + 19, SMBC_XATTR_MODE_REMOVE, 0); + TALLOC_FREE(frame); + return ret; + } + + /* Unsupported attribute name */ + errno = EINVAL; + TALLOC_FREE(frame); + return -1; +} + +int +SMBC_listxattr_ctx(SMBCCTX *context, + const char *fname, + char *list, + size_t size) +{ + /* + * This isn't quite what listxattr() is supposed to do. This returns + * 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" + "system.nt_sec_desc.revision\0" + "system.nt_sec_desc.owner\0" + "system.nt_sec_desc.owner+\0" + "system.nt_sec_desc.group\0" + "system.nt_sec_desc.group+\0" + "system.nt_sec_desc.acl.*\0" + "system.nt_sec_desc.acl\0" + "system.nt_sec_desc.acl+\0" + "system.nt_sec_desc.*\0" + "system.nt_sec_desc.*+\0" + "system.dos_attr.*\0" + "system.dos_attr.mode\0" + "system.dos_attr.c_time\0" + "system.dos_attr.a_time\0" + "system.dos_attr.m_time\0" + ; + const char supported_new[] = + "system.*\0" + "system.*+\0" + "system.nt_sec_desc.revision\0" + "system.nt_sec_desc.owner\0" + "system.nt_sec_desc.owner+\0" + "system.nt_sec_desc.group\0" + "system.nt_sec_desc.group+\0" + "system.nt_sec_desc.acl.*\0" + "system.nt_sec_desc.acl\0" + "system.nt_sec_desc.acl+\0" + "system.nt_sec_desc.*\0" + "system.nt_sec_desc.*+\0" + "system.dos_attr.*\0" + "system.dos_attr.mode\0" + "system.dos_attr.create_time\0" + "system.dos_attr.access_time\0" + "system.dos_attr.write_time\0" + "system.dos_attr.change_time\0" + ; + const char * supported; + + if (context->full_time_names) { + supported = supported_new; + retsize = sizeof(supported_new); + } else { + supported = supported_old; + retsize = sizeof(supported_old); + } + + if (size == 0) { + return retsize; + } + + if (retsize > size) { + errno = ERANGE; + return -1; + } + + /* this can't be strcpy() because there are embedded null characters */ + memcpy(list, supported, retsize); + return retsize; +} diff --git a/source3/libsmb/libsmbclient.c b/source3/libsmb/libsmbclient.c deleted file mode 100644 index fe008ed6b6..0000000000 --- a/source3/libsmb/libsmbclient.c +++ /dev/null @@ -1,7233 +0,0 @@ -/* - Unix SMB/Netbios implementation. - SMB client library implementation - Copyright (C) Andrew Tridgell 1998 - Copyright (C) Richard Sharpe 2000, 2002 - 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 - 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 . -*/ - -#include "includes.h" - -#include "include/libsmb_internal.h" - -struct smbc_dirent *smbc_readdir_ctx(SMBCCTX *context, SMBCFILE *dir); -struct smbc_dir_list *smbc_check_dir_ent(struct smbc_dir_list *list, - struct smbc_dirent *dirent); - -/* - * DOS Attribute values (used internally) - */ -typedef struct DOS_ATTR_DESC { - int mode; - SMB_OFF_T size; - time_t create_time; - time_t access_time; - time_t write_time; - time_t change_time; - SMB_INO_T inode; -} DOS_ATTR_DESC; - - -/* - * Internal flags for extended attributes - */ - -/* internal mode values */ -#define SMBC_XATTR_MODE_ADD 1 -#define SMBC_XATTR_MODE_REMOVE 2 -#define SMBC_XATTR_MODE_REMOVE_ALL 3 -#define SMBC_XATTR_MODE_SET 4 -#define SMBC_XATTR_MODE_CHOWN 5 -#define SMBC_XATTR_MODE_CHGRP 6 - -#define CREATE_ACCESS_READ READ_CONTROL_ACCESS - -/*We should test for this in configure ... */ -#ifndef ENOTSUP -#define ENOTSUP EOPNOTSUPP -#endif - -/* - * Functions exported by libsmb_cache.c that we need here - */ -int smbc_default_cache_functions(SMBCCTX *context); - -/* - * check if an element is part of the list. - * FIXME: Does not belong here ! - * Can anyone put this in a macro in dlinklist.h ? - * -- Tom - */ -static int DLIST_CONTAINS(SMBCFILE * list, SMBCFILE *p) { - if (!p || !list) return False; - do { - if (p == list) return True; - list = list->next; - } while (list); - return False; -} - -/* - * Find an lsa pipe handle associated with a cli struct. - */ -static struct rpc_pipe_client * -find_lsa_pipe_hnd(struct cli_state *ipc_cli) -{ - struct rpc_pipe_client *pipe_hnd; - - for (pipe_hnd = ipc_cli->pipe_list; - pipe_hnd; - pipe_hnd = pipe_hnd->next) { - - if (pipe_hnd->pipe_idx == PI_LSARPC) { - return pipe_hnd; - } - } - - return NULL; -} - -static int -smbc_close_ctx(SMBCCTX *context, - SMBCFILE *file); -static off_t -smbc_lseek_ctx(SMBCCTX *context, - SMBCFILE *file, - off_t offset, - int whence); - -extern bool in_client; - -/* - * Is the logging working / configfile read ? - */ -static int smbc_initialized = 0; - -static int -hex2int( unsigned int _char ) -{ - if ( _char >= 'A' && _char <='F') - return _char - 'A' + 10; - if ( _char >= 'a' && _char <='f') - return _char - 'a' + 10; - if ( _char >= '0' && _char <='9') - return _char - '0'; - return -1; -} - -/* - * smbc_urldecode() - * and smbc_urldecode_talloc() (internal fn.) - * - * Convert strings of %xx to their single character equivalent. Each 'x' must - * be a valid hexadecimal digit, or that % sequence is left undecoded. - * - * dest may, but need not be, the same pointer as src. - * - * Returns the number of % sequences which could not be converted due to lack - * of two following hexadecimal digits. - */ -static int -smbc_urldecode_talloc(TALLOC_CTX *ctx, char **pp_dest, const char *src) -{ - int old_length = strlen(src); - int i = 0; - int err_count = 0; - size_t newlen = 1; - char *p, *dest; - - if (old_length == 0) { - return 0; - } - - *pp_dest = NULL; - for (i = 0; i < old_length; ) { - unsigned char character = src[i++]; - - if (character == '%') { - int a = i+1 < old_length ? hex2int(src[i]) : -1; - int b = i+1 < old_length ? hex2int(src[i+1]) : -1; - - /* Replace valid sequence */ - if (a != -1 && b != -1) { - /* Replace valid %xx sequence with %dd */ - character = (a * 16) + b; - if (character == '\0') { - break; /* Stop at %00 */ - } - i += 2; - } else { - err_count++; - } - } - newlen++; - } - - dest = TALLOC_ARRAY(ctx, char, newlen); - if (!dest) { - return err_count; - } - - err_count = 0; - for (p = dest, i = 0; i < old_length; ) { - unsigned char character = src[i++]; - - if (character == '%') { - int a = i+1 < old_length ? hex2int(src[i]) : -1; - int b = i+1 < old_length ? hex2int(src[i+1]) : -1; - - /* Replace valid sequence */ - if (a != -1 && b != -1) { - /* Replace valid %xx sequence with %dd */ - character = (a * 16) + b; - if (character == '\0') { - break; /* Stop at %00 */ - } - i += 2; - } else { - err_count++; - } - } - *p++ = character; - } - - *p = '\0'; - *pp_dest = dest; - return err_count; -} - -int -smbc_urldecode(char *dest, char *src, size_t max_dest_len) -{ - TALLOC_CTX *frame = talloc_stackframe(); - char *pdest; - int ret = smbc_urldecode_talloc(frame, &pdest, src); - - if (pdest) { - strlcpy(dest, pdest, max_dest_len); - } - TALLOC_FREE(frame); - return ret; -} - -/* - * smbc_urlencode() - * - * Convert any characters not specifically allowed in a URL into their %xx - * equivalent. - * - * Returns the remaining buffer length. - */ -int -smbc_urlencode(char *dest, char *src, int max_dest_len) -{ - char hex[] = "0123456789ABCDEF"; - - for (; *src != '\0' && max_dest_len >= 3; src++) { - - if ((*src < '0' && - *src != '-' && - *src != '.') || - (*src > '9' && - *src < 'A') || - (*src > 'Z' && - *src < 'a' && - *src != '_') || - (*src > 'z')) { - *dest++ = '%'; - *dest++ = hex[(*src >> 4) & 0x0f]; - *dest++ = hex[*src & 0x0f]; - max_dest_len -= 3; - } else { - *dest++ = *src; - max_dest_len--; - } - } - - *dest++ = '\0'; - max_dest_len--; - - return max_dest_len; -} - -/* - * Function to parse a path and turn it into components - * - * The general format of an SMB URI is explain in Christopher Hertel's CIFS - * book, at http://ubiqx.org/cifs/Appendix-D.html. We accept a subset of the - * general format ("smb:" only; we do not look for "cifs:"). - * - * - * We accept: - * smb://[[[domain;]user[:password]@]server[/share[/path[/file]]]][?options] - * - * Meaning of URLs: - * - * smb:// Show all workgroups. - * - * The method of locating the list of workgroups varies - * depending upon the setting of the context variable - * context->options.browse_max_lmb_count. This value - * determine the maximum number of local master browsers to - * query for the list of workgroups. In order to ensure that - * a complete list of workgroups is obtained, all master - * browsers must be queried, but if there are many - * workgroups, the time spent querying can begin to add up. - * For small networks (not many workgroups), it is suggested - * that this variable be set to 0, indicating query all local - * master browsers. When the network has many workgroups, a - * reasonable setting for this variable might be around 3. - * - * smb://name/ if name<1D> or name<1B> exists, list servers in - * workgroup, else, if name<20> exists, list all shares - * for server ... - * - * If "options" are provided, this function returns the entire option list as a - * string, for later parsing by the caller. Note that currently, no options - * are supported. - */ - -static const char *smbc_prefix = "smb:"; - -static int -smbc_parse_path(TALLOC_CTX *ctx, - SMBCCTX *context, - const char *fname, - char **pp_workgroup, - char **pp_server, - char **pp_share, - char **pp_path, - char **pp_user, - char **pp_password, - char **pp_options) -{ - char *s; - const char *p; - char *q, *r; - int len; - - /* Ensure these returns are at least valid pointers. */ - *pp_server = talloc_strdup(ctx, ""); - *pp_share = talloc_strdup(ctx, ""); - *pp_path = talloc_strdup(ctx, ""); - *pp_user = talloc_strdup(ctx, ""); - *pp_password = talloc_strdup(ctx, ""); - - if (!*pp_server || !*pp_share || !*pp_path || - !*pp_user || !*pp_password) { - return -1; - } - - /* - * Assume we wont find an authentication domain to parse, so default - * to the workgroup in the provided context. - */ - if (pp_workgroup != NULL) { - *pp_workgroup = talloc_strdup(ctx, context->workgroup); - } - - if (pp_options) { - *pp_options = talloc_strdup(ctx, ""); - } - s = talloc_strdup(ctx, fname); - - /* see if it has the right prefix */ - len = strlen(smbc_prefix); - if (strncmp(s,smbc_prefix,len) || (s[len] != '/' && s[len] != 0)) { - return -1; /* What about no smb: ? */ - } - - p = s + len; - - /* Watch the test below, we are testing to see if we should exit */ - - if (strncmp(p, "//", 2) && strncmp(p, "\\\\", 2)) { - DEBUG(1, ("Invalid path (does not begin with smb://")); - return -1; - } - - p += 2; /* Skip the double slash */ - - /* See if any options were specified */ - if ((q = strrchr(p, '?')) != NULL ) { - /* There are options. Null terminate here and point to them */ - *q++ = '\0'; - - DEBUG(4, ("Found options '%s'", q)); - - /* Copy the options */ - if (*pp_options != NULL) { - TALLOC_FREE(*pp_options); - *pp_options = talloc_strdup(ctx, q); - } - } - - if (*p == '\0') { - goto decoding; - } - - if (*p == '/') { - int wl = strlen(context->workgroup); - - if (wl > 16) { - wl = 16; - } - - *pp_server = talloc_strdup(ctx, context->workgroup); - if (!*pp_server) { - return -1; - } - *pp_server[wl] = '\0'; - return 0; - } - - /* - * ok, its for us. Now parse out the server, share etc. - * - * However, we want to parse out [[domain;]user[:password]@] if it - * exists ... - */ - - /* check that '@' occurs before '/', if '/' exists at all */ - q = strchr_m(p, '@'); - r = strchr_m(p, '/'); - if (q && (!r || q < r)) { - char *userinfo = NULL; - const char *u; - - next_token_no_ltrim_talloc(ctx, &p, &userinfo, "@"); - if (!userinfo) { - return -1; - } - u = userinfo; - - if (strchr_m(u, ';')) { - char *workgroup; - next_token_no_ltrim_talloc(ctx, &u, &workgroup, ";"); - if (!workgroup) { - return -1; - } - if (pp_workgroup) { - *pp_workgroup = workgroup; - } - } - - if (strchr_m(u, ':')) { - next_token_no_ltrim_talloc(ctx, &u, pp_user, ":"); - if (!*pp_user) { - return -1; - } - *pp_password = talloc_strdup(ctx, u); - if (!*pp_password) { - return -1; - } - } else { - *pp_user = talloc_strdup(ctx, u); - if (!*pp_user) { - return -1; - } - } - } - - if (!next_token_talloc(ctx, &p, pp_server, "/")) { - return -1; - } - - if (*p == (char)0) { - goto decoding; /* That's it ... */ - } - - if (!next_token_talloc(ctx, &p, pp_share, "/")) { - return -1; - } - - /* - * Prepend a leading slash if there's a file path, as required by - * NetApp filers. - */ - if (*p != '\0') { - *pp_path = talloc_asprintf(ctx, - "\\%s", - p); - } else { - *pp_path = talloc_strdup(ctx, ""); - } - if (!*pp_path) { - return -1; - } - string_replace(*pp_path, '/', '\\'); - - decoding: - - (void) smbc_urldecode_talloc(ctx, pp_path, *pp_path); - (void) smbc_urldecode_talloc(ctx, pp_server, *pp_server); - (void) smbc_urldecode_talloc(ctx, pp_share, *pp_share); - (void) smbc_urldecode_talloc(ctx, pp_user, *pp_user); - (void) smbc_urldecode_talloc(ctx, pp_password, *pp_password); - - return 0; -} - -/* - * Verify that the options specified in a URL are valid - */ -static int -smbc_check_options(char *server, - char *share, - char *path, - char *options) -{ - DEBUG(4, ("smbc_check_options(): server='%s' share='%s' " - "path='%s' options='%s'\n", - server, share, path, options)); - - /* No options at all is always ok */ - if (! *options) return 0; - - /* Currently, we don't support any options. */ - return -1; -} - -/* - * Convert an SMB error into a UNIX error ... - */ -static int -smbc_errno(SMBCCTX *context, - struct cli_state *c) -{ - int ret = cli_errno(c); - - if (cli_is_dos_error(c)) { - uint8 eclass; - uint32 ecode; - - cli_dos_error(c, &eclass, &ecode); - - DEBUG(3,("smbc_error %d %d (0x%x) -> %d\n", - (int)eclass, (int)ecode, (int)ecode, ret)); - } else { - NTSTATUS status; - - status = cli_nt_error(c); - - DEBUG(3,("smbc errno %s -> %d\n", - nt_errstr(status), ret)); - } - - return ret; -} - -/* - * Check a server for being alive and well. - * returns 0 if the server is in shape. Returns 1 on error - * - * Also useable outside libsmbclient to enable external cache - * to do some checks too. - */ -static int -smbc_check_server(SMBCCTX * context, - SMBCSRV * server) -{ - socklen_t size; - struct sockaddr addr; - - size = sizeof(addr); - return (getpeername(server->cli->fd, &addr, &size) == -1); -} - -/* - * Remove a server from the cached server list it's unused. - * On success, 0 is returned. 1 is returned if the server could not be removed. - * - * Also useable outside libsmbclient - */ -int -smbc_remove_unused_server(SMBCCTX * context, - SMBCSRV * srv) -{ - SMBCFILE * file; - - /* are we being fooled ? */ - if (!context || !context->internal || - !context->internal->_initialized || !srv) return 1; - - - /* Check all open files/directories for a relation with this server */ - for (file = context->internal->_files; file; file=file->next) { - if (file->srv == srv) { - /* Still used */ - DEBUG(3, ("smbc_remove_usused_server: " - "%p still used by %p.\n", - srv, file)); - return 1; - } - } - - DLIST_REMOVE(context->internal->_servers, srv); - - cli_shutdown(srv->cli); - srv->cli = NULL; - - DEBUG(3, ("smbc_remove_usused_server: %p removed.\n", srv)); - - (context->callbacks.remove_cached_srv_fn)(context, srv); - - SAFE_FREE(srv); - 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(TALLOC_CTX *ctx, - SMBCCTX *context, - const char *server, - const char *share, - char **pp_workgroup, - char **pp_username, - char **pp_password) -{ - SMBCSRV *srv; - int auth_called = 0; - - check_server_cache: - - srv = (context->callbacks.get_cached_srv_fn)(context, server, share, - *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; - } - - /* - * However, smbc_auth_fn may have picked up info relating to - * an existing connection, so try for an existing connection - * again ... - */ - auth_called = 1; - goto check_server_cache; - - } - - if (srv) { - if ((context->callbacks.check_server_fn)(context, srv)) { - /* - * This server is no good anymore - * Try to remove it and check for more possible - * servers in the cache - */ - if ((context->callbacks.remove_unused_server_fn)(context, - srv)) { - /* - * We could not remove the server completely, - * remove it from the cache so we will not get - * it again. It will be removed when the last - * file/dir is closed. - */ - (context->callbacks.remove_cached_srv_fn)(context, - srv); - } - - /* - * Maybe there are more cached connections to this - * server - */ - goto check_server_cache; - } - - return srv; - } - - return NULL; -} - -/* - * Connect to a server, possibly on an existing connection - * - * Here, what we want to do is: If the server and username - * match an existing connection, reuse that, otherwise, establish a - * new connection. - * - * If we have to create a new connection, call the auth_fn to get the - * info we need, unless the username and password were passed in. - */ - -static SMBCSRV * -smbc_server(TALLOC_CTX *ctx, - SMBCCTX *context, - bool connect_if_not_found, - const char *server, - const char *share, - char **pp_workgroup, - char **pp_username, - char **pp_password) -{ - SMBCSRV *srv=NULL; - struct cli_state *c; - struct nmb_name called, calling; - const char *server_n = server; - struct sockaddr_storage ss; - int tried_reverse = 0; - int port_try_first; - int port_try_next; - const char *username_used; - NTSTATUS status; - - zero_addr(&ss); - ZERO_STRUCT(c); - - if (server[0] == 0) { - errno = EPERM; - return NULL; - } - - /* Look for a cached connection */ - 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 - * server... - */ - if (srv && *share != '\0' && context->options.one_share_per_server) { - - /* - * ... then if there's no current connection to the share, - * connect to it. find_server(), or rather the function - * pointed to by context->callbacks.get_cached_srv_fn which - * was called by find_server(), will have issued a tree - * disconnect if the requested share is not the same as the - * one that was already connected. - */ - if (srv->cli->cnum == (uint16) -1) { - /* Ensure we have accurate auth info */ - 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, "?????", - *pp_password, - strlen(*pp_password)+1)) { - - errno = smbc_errno(context, srv->cli); - cli_shutdown(srv->cli); - srv->cli = NULL; - (context->callbacks.remove_cached_srv_fn)(context, - srv); - srv = NULL; - } - - /* - * Regenerate the dev value since it's based on both - * server and share - */ - if (srv) { - srv->dev = (dev_t)(str_checksum(server) ^ - str_checksum(share)); - } - } - } - - /* If we have a connection... */ - if (srv) { - - /* ... then we're done here. Give 'em what they came for. */ - return srv; - } - - /* If we're not asked to connect when a connection doesn't exist... */ - if (! connect_if_not_found) { - /* ... then we're done here. */ - 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); - - DEBUG(4,("smbc_server: server_n=[%s] server=[%s]\n", server_n, server)); - - DEBUG(4,(" -> server_n=[%s] server=[%s]\n", server_n, server)); - - again: - - zero_addr(&ss); - - /* have to open a new connection */ - if ((c = cli_initialise()) == NULL) { - errno = ENOMEM; - return NULL; - } - - if (context->flags & SMB_CTX_FLAG_USE_KERBEROS) { - c->use_kerberos = True; - } - if (context->flags & SMB_CTX_FLAG_FALLBACK_AFTER_KERBEROS) { - c->fallback_after_kerberos = True; - } - - c->timeout = context->timeout; - - /* - * Force use of port 139 for first try if share is $IPC, empty, or - * null, so browse lists can work - */ - if (share == NULL || *share == '\0' || strcmp(share, "IPC$") == 0) { - port_try_first = 139; - port_try_next = 445; - } else { - port_try_first = 445; - port_try_next = 139; - } - - c->port = port_try_first; - - status = cli_connect(c, server_n, &ss); - if (!NT_STATUS_IS_OK(status)) { - - /* First connection attempt failed. Try alternate port. */ - c->port = port_try_next; - - status = cli_connect(c, server_n, &ss); - if (!NT_STATUS_IS_OK(status)) { - cli_shutdown(c); - errno = ETIMEDOUT; - return NULL; - } - } - - if (!cli_session_request(c, &calling, &called)) { - cli_shutdown(c); - if (strcmp(called.name, "*SMBSERVER")) { - make_nmb_name(&called , "*SMBSERVER", 0x20); - goto again; - } else { /* Try one more time, but ensure we don't loop */ - - /* Only try this if server is an IP address ... */ - - if (is_ipaddress(server) && !tried_reverse) { - fstring remote_name; - struct sockaddr_storage rem_ss; - - if (!interpret_string_addr(&rem_ss, server, - NI_NUMERICHOST)) { - DEBUG(4, ("Could not convert IP address " - "%s to struct sockaddr_storage\n", - server)); - errno = ETIMEDOUT; - return NULL; - } - - tried_reverse++; /* Yuck */ - - if (name_status_find("*", 0, 0, &rem_ss, remote_name)) { - make_nmb_name(&called, remote_name, 0x20); - goto again; - } - } - } - errno = ETIMEDOUT; - return NULL; - } - - DEBUG(4,(" session request ok\n")); - - if (!cli_negprot(c)) { - cli_shutdown(c); - errno = ETIMEDOUT; - return NULL; - } - - username_used = *pp_username; - - if (!NT_STATUS_IS_OK(cli_session_setup(c, username_used, - *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, - *pp_password, 1, - *pp_password, 0, - *pp_workgroup))) { - - cli_shutdown(c); - errno = EPERM; - return NULL; - } - } - - DEBUG(4,(" session setup ok\n")); - - if (!cli_send_tconX(c, share, "?????", - *pp_password, strlen(*pp_password)+1)) { - errno = smbc_errno(context, c); - cli_shutdown(c); - return NULL; - } - - 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. - */ - - srv = SMB_MALLOC_P(SMBCSRV); - if (!srv) { - errno = ENOMEM; - goto failed; - } - - ZERO_STRUCTP(srv); - srv->cli = c; - srv->dev = (dev_t)(str_checksum(server) ^ str_checksum(share)); - srv->no_pathinfo = False; - srv->no_pathinfo2 = False; - srv->no_nt_session = False; - - /* now add it to the cache (internal or external) */ - /* Let the cache function set errno if it wants to */ - errno = 0; - if ((context->callbacks.add_cached_srv_fn)(context, srv, - server, share, - *pp_workgroup, - *pp_username)) { - int saved_errno = errno; - DEBUG(3, (" Failed to add server to cache\n")); - errno = saved_errno; - if (errno == 0) { - errno = ENOMEM; - } - goto failed; - } - - DEBUG(2, ("Server connect ok: //%s/%s: %p\n", - server, share, srv)); - - DLIST_ADD(context->internal->_servers, srv); - return srv; - - failed: - cli_shutdown(c); - if (!srv) { - return NULL; - } - - SAFE_FREE(srv); - return NULL; -} - -/* - * Connect to a server for getting/setting attributes, possibly on an existing - * connection. This works similarly to smbc_server(). - */ -static SMBCSRV * -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; - struct cli_state *ipc_cli; - struct rpc_pipe_client *pipe_hnd; - NTSTATUS nt_status; - SMBCSRV *ipc_srv=NULL; - - /* - * See if we've already created this special connection. Reference - * our "special" share name '*IPC$', which is an impossible real share - * name due to the leading asterisk. - */ - 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 (!*pp_password || (*pp_password)[0] == '\0') { - /* ... then retrieve it now. */ - 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; - if (context->flags & SMB_CTX_FLAG_USE_KERBEROS) { - flags |= CLI_FULL_CONNECTION_USE_KERBEROS; - } - - zero_addr(&ss); - nt_status = cli_full_connection(&ipc_cli, - 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))); - errno = ENOTSUP; - 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; - cli_shutdown(ipc_cli); - return NULL; - } - - ZERO_STRUCTP(ipc_srv); - ipc_srv->cli = ipc_cli; - - 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, - &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$", - *pp_workgroup, - *pp_username)) { - DEBUG(3, (" Failed to add server to cache\n")); - if (errno == 0) { - errno = ENOMEM; - } - cli_shutdown(ipc_srv->cli); - free(ipc_srv); - return NULL; - } - - DLIST_ADD(context->internal->_servers, ipc_srv); - } - - return ipc_srv; -} - -/* - * Routine to open() a file ... - */ - -static SMBCFILE * -smbc_open_ctx(SMBCCTX *context, - const char *fname, - int flags, - mode_t mode) -{ - 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; - SMBCFILE *file = NULL; - int fd; - TALLOC_CTX *frame = talloc_stackframe(); - - if (!context || !context->internal || - !context->internal->_initialized) { - - errno = EINVAL; /* Best I can think of ... */ - TALLOC_FREE(frame); - return NULL; - - } - - if (!fname) { - - errno = EINVAL; - TALLOC_FREE(frame); - return NULL; - - } - - if (smbc_parse_path(frame, - context, - fname, - &workgroup, - &server, - &share, - &path, - &user, - &password, - NULL)) { - errno = EINVAL; - TALLOC_FREE(frame); - return NULL; - } - - if (!user || user[0] == (char)0) { - user = talloc_strdup(frame, context->user); - if (!user) { - errno = ENOMEM; - TALLOC_FREE(frame); - return NULL; - } - } - - srv = smbc_server(frame, context, True, - server, share, &workgroup, &user, &password); - - if (!srv) { - if (errno == EPERM) errno = EACCES; - TALLOC_FREE(frame); - return NULL; /* smbc_server sets errno */ - } - - /* Hmmm, the test for a directory is suspect here ... FIXME */ - - if (strlen(path) > 0 && path[strlen(path) - 1] == '\\') { - fd = -1; - } else { - file = SMB_MALLOC_P(SMBCFILE); - - if (!file) { - errno = ENOMEM; - TALLOC_FREE(frame); - return NULL; - } - - ZERO_STRUCTP(file); - - /*d_printf(">>>open: resolving %s\n", path);*/ - if (!cli_resolve_path(frame, "", srv->cli, path, &targetcli, &targetpath)) { - d_printf("Could not resolve %s\n", path); - SAFE_FREE(file); - TALLOC_FREE(frame); - return NULL; - } - /*d_printf(">>>open: resolved %s as %s\n", path, targetpath);*/ - - if ((fd = cli_open(targetcli, targetpath, flags, - context->internal->_share_mode)) < 0) { - - /* Handle the error ... */ - - SAFE_FREE(file); - errno = smbc_errno(context, targetcli); - TALLOC_FREE(frame); - return NULL; - - } - - /* Fill in file struct */ - - file->cli_fd = fd; - file->fname = SMB_STRDUP(fname); - file->srv = srv; - file->offset = 0; - file->file = True; - - DLIST_ADD(context->internal->_files, file); - - /* - * If the file was opened in O_APPEND mode, all write - * operations should be appended to the file. To do that, - * though, using this protocol, would require a getattrE() - * call for each and every write, to determine where the end - * of the file is. (There does not appear to be an append flag - * in the protocol.) Rather than add all of that overhead of - * retrieving the current end-of-file offset prior to each - * write operation, we'll assume that most append operations - * will continuously write, so we'll just set the offset to - * the end of the file now and hope that's adequate. - * - * Note to self: If this proves inadequate, and O_APPEND - * should, in some cases, be forced for each write, add a - * field in the context options structure, for - * "strict_append_mode" which would select between the current - * behavior (if FALSE) or issuing a getattrE() prior to each - * write and forcing the write to the end of the file (if - * TRUE). Adding that capability will likely require adding - * an "append" flag into the _SMBCFILE structure to track - * whether a file was opened in O_APPEND mode. -- djl - */ - if (flags & O_APPEND) { - if (smbc_lseek_ctx(context, file, 0, SEEK_END) < 0) { - (void) smbc_close_ctx(context, file); - errno = ENXIO; - TALLOC_FREE(frame); - return NULL; - } - } - - TALLOC_FREE(frame); - return file; - - } - - /* Check if opendir needed ... */ - - if (fd == -1) { - int eno = 0; - - eno = smbc_errno(context, srv->cli); - file = (context->opendir)(context, fname); - if (!file) errno = eno; - TALLOC_FREE(frame); - return file; - - } - - errno = EINVAL; /* FIXME, correct errno ? */ - TALLOC_FREE(frame); - return NULL; - -} - -/* - * Routine to create a file - */ - -static int creat_bits = O_WRONLY | O_CREAT | O_TRUNC; /* FIXME: Do we need this */ - -static SMBCFILE * -smbc_creat_ctx(SMBCCTX *context, - const char *path, - mode_t mode) -{ - - if (!context || !context->internal || - !context->internal->_initialized) { - - errno = EINVAL; - return NULL; - - } - - return smbc_open_ctx(context, path, creat_bits, mode); -} - -/* - * Routine to read() a file ... - */ - -static ssize_t -smbc_read_ctx(SMBCCTX *context, - SMBCFILE *file, - void *buf, - size_t count) -{ - int ret; - 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(); - - /* - * offset: - * - * Compiler bug (possibly) -- gcc (GCC) 3.3.5 (Debian 1:3.3.5-2) -- - * appears to pass file->offset (which is type off_t) differently than - * a local variable of type off_t. Using local variable "offset" in - * the call to cli_read() instead of file->offset fixes a problem - * retrieving data at an offset greater than 4GB. - */ - off_t offset; - - if (!context || !context->internal || - !context->internal->_initialized) { - errno = EINVAL; - TALLOC_FREE(frame); - return -1; - - } - - DEBUG(4, ("smbc_read(%p, %d)\n", file, (int)count)); - - if (!file || !DLIST_CONTAINS(context->internal->_files, file)) { - errno = EBADF; - TALLOC_FREE(frame); - return -1; - - } - - offset = file->offset; - - /* Check that the buffer exists ... */ - - if (buf == NULL) { - errno = EINVAL; - TALLOC_FREE(frame); - return -1; - - } - - /*d_printf(">>>read: parsing %s\n", file->fname);*/ - if (smbc_parse_path(frame, - context, - file->fname, - NULL, - &server, - &share, - &path, - &user, - &password, - NULL)) { - errno = EINVAL; - TALLOC_FREE(frame); - return -1; - } - - /*d_printf(">>>read: resolving %s\n", path);*/ - if (!cli_resolve_path(frame, "", file->srv->cli, path, - &targetcli, &targetpath)) { - d_printf("Could not resolve %s\n", path); - TALLOC_FREE(frame); - return -1; - } - /*d_printf(">>>fstat: resolved path as %s\n", targetpath);*/ - - ret = cli_read(targetcli, file->cli_fd, (char *)buf, offset, count); - - if (ret < 0) { - - errno = smbc_errno(context, targetcli); - TALLOC_FREE(frame); - return -1; - - } - - file->offset += ret; - - DEBUG(4, (" --> %d\n", ret)); - - TALLOC_FREE(frame); - return ret; /* Success, ret bytes of data ... */ - -} - -/* - * Routine to write() a file ... - */ - -static ssize_t -smbc_write_ctx(SMBCCTX *context, - SMBCFILE *file, - void *buf, - size_t count) -{ - int ret; - off_t offset; - 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(); - - /* First check all pointers before dereferencing them */ - - if (!context || !context->internal || - !context->internal->_initialized) { - errno = EINVAL; - TALLOC_FREE(frame); - return -1; - - } - - if (!file || !DLIST_CONTAINS(context->internal->_files, file)) { - errno = EBADF; - TALLOC_FREE(frame); - return -1; - } - - /* Check that the buffer exists ... */ - - if (buf == NULL) { - errno = EINVAL; - TALLOC_FREE(frame); - return -1; - - } - - offset = file->offset; /* See "offset" comment in smbc_read_ctx() */ - - /*d_printf(">>>write: parsing %s\n", file->fname);*/ - if (smbc_parse_path(frame, - context, - file->fname, - NULL, - &server, - &share, - &path, - &user, - &password, - NULL)) { - errno = EINVAL; - TALLOC_FREE(frame); - return -1; - } - - /*d_printf(">>>write: resolving %s\n", path);*/ - if (!cli_resolve_path(frame, "", file->srv->cli, path, - &targetcli, &targetpath)) { - d_printf("Could not resolve %s\n", path); - TALLOC_FREE(frame); - return -1; - } - /*d_printf(">>>write: resolved path as %s\n", targetpath);*/ - - ret = cli_write(targetcli, file->cli_fd, 0, (char *)buf, offset, count); - - if (ret <= 0) { - errno = smbc_errno(context, targetcli); - TALLOC_FREE(frame); - return -1; - - } - - file->offset += ret; - - TALLOC_FREE(frame); - return ret; /* Success, 0 bytes of data ... */ -} - -/* - * Routine to close() a file ... - */ - -static int -smbc_close_ctx(SMBCCTX *context, - SMBCFILE *file) -{ - SMBCSRV *srv; - 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 || - !context->internal->_initialized) { - - errno = EINVAL; - TALLOC_FREE(frame); - return -1; - } - - if (!file || !DLIST_CONTAINS(context->internal->_files, file)) { - errno = EBADF; - TALLOC_FREE(frame); - return -1; - } - - /* IS a dir ... */ - if (!file->file) { - TALLOC_FREE(frame); - return (context->closedir)(context, file); - } - - /*d_printf(">>>close: parsing %s\n", file->fname);*/ - if (smbc_parse_path(frame, - context, - file->fname, - NULL, - &server, - &share, - &path, - &user, - &password, - NULL)) { - errno = EINVAL; - TALLOC_FREE(frame); - return -1; - } - - /*d_printf(">>>close: resolving %s\n", path);*/ - if (!cli_resolve_path(frame, "", file->srv->cli, path, - &targetcli, &targetpath)) { - d_printf("Could not resolve %s\n", path); - TALLOC_FREE(frame); - return -1; - } - /*d_printf(">>>close: resolved path as %s\n", targetpath);*/ - - if (!cli_close(targetcli, file->cli_fd)) { - - DEBUG(3, ("cli_close failed on %s. purging server.\n", - file->fname)); - /* Deallocate slot and remove the server - * from the server cache if unused */ - errno = smbc_errno(context, targetcli); - srv = file->srv; - DLIST_REMOVE(context->internal->_files, file); - SAFE_FREE(file->fname); - SAFE_FREE(file); - (context->callbacks.remove_unused_server_fn)(context, srv); - TALLOC_FREE(frame); - return -1; - - } - - DLIST_REMOVE(context->internal->_files, file); - SAFE_FREE(file->fname); - SAFE_FREE(file); - TALLOC_FREE(frame); - - return 0; -} - -/* - * Get info from an SMB server on a file. Use a qpathinfo call first - * and if that fails, use getatr, as Win95 sometimes refuses qpathinfo - */ -static bool -smbc_getatr(SMBCCTX * context, - SMBCSRV *srv, - char *path, - uint16 *mode, - SMB_OFF_T *size, - struct timespec *create_time_ts, - struct timespec *access_time_ts, - struct timespec *write_time_ts, - struct timespec *change_time_ts, - SMB_INO_T *ino) -{ - char *fixedpath = NULL; - char *targetpath = NULL; - struct cli_state *targetcli = NULL; - time_t write_time; - TALLOC_CTX *frame = talloc_stackframe(); - - if (!context || !context->internal || - !context->internal->_initialized) { - errno = EINVAL; - TALLOC_FREE(frame); - return -1; - } - - /* path fixup for . and .. */ - if (strequal(path, ".") || strequal(path, "..")) { - fixedpath = talloc_strdup(frame, "\\"); - if (!fixedpath) { - errno = ENOMEM; - TALLOC_FREE(frame); - return -1; - } - } else { - fixedpath = talloc_strdup(frame, path); - if (!fixedpath) { - errno = ENOMEM; - TALLOC_FREE(frame); - return -1; - } - trim_string(fixedpath, NULL, "\\.."); - trim_string(fixedpath, NULL, "\\."); - } - DEBUG(4,("smbc_getatr: sending qpathinfo\n")); - - if (!cli_resolve_path(frame, "", srv->cli, fixedpath, - &targetcli, &targetpath)) { - d_printf("Couldn't resolve %s\n", path); - TALLOC_FREE(frame); - return False; - } - - if (!srv->no_pathinfo2 && - cli_qpathinfo2(targetcli, targetpath, - create_time_ts, - access_time_ts, - write_time_ts, - change_time_ts, - size, mode, ino)) { - TALLOC_FREE(frame); - return True; - } - - /* if this is NT then don't bother with the getatr */ - if (targetcli->capabilities & CAP_NT_SMBS) { - errno = EPERM; - TALLOC_FREE(frame); - return False; - } - - if (cli_getatr(targetcli, targetpath, mode, size, &write_time)) { - - struct timespec w_time_ts; - - w_time_ts = convert_time_t_to_timespec(write_time); - - if (write_time_ts != NULL) { - *write_time_ts = w_time_ts; - } - - 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; - } - - srv->no_pathinfo2 = True; - TALLOC_FREE(frame); - return True; - } - - errno = EPERM; - TALLOC_FREE(frame); - return False; - -} - -/* - * Set file info on an SMB server. Use setpathinfo call first. If that - * fails, use setattrE.. - * - * Access and modification time parameters are always used and must be - * provided. Create time, if zero, will be determined from the actual create - * time of the file. If non-zero, the create time will be set as well. - * - * "mode" (attributes) parameter may be set to -1 if it is not to be set. - */ -static bool -smbc_setatr(SMBCCTX * context, SMBCSRV *srv, char *path, - time_t create_time, - time_t access_time, - time_t write_time, - time_t change_time, - uint16 mode) -{ - int fd; - int ret; - TALLOC_CTX *frame = talloc_stackframe(); - - /* - * First, try setpathinfo (if qpathinfo succeeded), for it is the - * modern function for "new code" to be using, and it works given a - * filename rather than requiring that the file be opened to have its - * attributes manipulated. - */ - if (srv->no_pathinfo || - ! cli_setpathinfo(srv->cli, path, - create_time, - access_time, - write_time, - change_time, - mode)) { - - /* - * setpathinfo is not supported; go to plan B. - * - * cli_setatr() does not work on win98, and it also doesn't - * support setting the access time (only the modification - * time), so in all cases, we open the specified file and use - * cli_setattrE() which should work on all OS versions, and - * supports both times. - */ - - /* Don't try {q,set}pathinfo() again, with this server */ - srv->no_pathinfo = True; - - /* Open the file */ - if ((fd = cli_open(srv->cli, path, O_RDWR, DENY_NONE)) < 0) { - - errno = smbc_errno(context, srv->cli); - TALLOC_FREE(frame); - return -1; - } - - /* Set the new attributes */ - ret = cli_setattrE(srv->cli, fd, - change_time, - access_time, - write_time); - - /* Close the file */ - cli_close(srv->cli, fd); - - /* - * Unfortunately, setattrE() doesn't have a provision for - * setting the access mode (attributes). We'll have to try - * cli_setatr() for that, and with only this parameter, it - * seems to work on win98. - */ - if (ret && mode != (uint16) -1) { - ret = cli_setatr(srv->cli, path, mode, 0); - } - - if (! ret) { - errno = smbc_errno(context, srv->cli); - TALLOC_FREE(frame); - return False; - } - } - - TALLOC_FREE(frame); - return True; -} - - /* - * Routine to unlink() a file - */ - -static int -smbc_unlink_ctx(SMBCCTX *context, - const char *fname) -{ - 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(); - - if (!context || !context->internal || - !context->internal->_initialized) { - errno = EINVAL; /* Best I can think of ... */ - TALLOC_FREE(frame); - return -1; - - } - - if (!fname) { - errno = EINVAL; - TALLOC_FREE(frame); - return -1; - - } - - if (smbc_parse_path(frame, - context, - fname, - &workgroup, - &server, - &share, - &path, - &user, - &password, - NULL)) { - errno = EINVAL; - TALLOC_FREE(frame); - return -1; - } - - if (!user || user[0] == (char)0) { - user = talloc_strdup(frame, context->user); - if (!user) { - errno = ENOMEM; - TALLOC_FREE(frame); - return -1; - } - } - - srv = smbc_server(frame, context, True, - server, share, &workgroup, &user, &password); - - if (!srv) { - TALLOC_FREE(frame); - return -1; /* smbc_server sets errno */ - - } - - /*d_printf(">>>unlink: resolving %s\n", path);*/ - if (!cli_resolve_path(frame, "", srv->cli, path, - &targetcli, &targetpath)) { - d_printf("Could not resolve %s\n", path); - TALLOC_FREE(frame); - return -1; - } - /*d_printf(">>>unlink: resolved path as %s\n", targetpath);*/ - - if (!cli_unlink(targetcli, targetpath)) { - - errno = smbc_errno(context, targetcli); - - if (errno == EACCES) { /* Check if the file is a directory */ - - int saverr = errno; - SMB_OFF_T size = 0; - uint16 mode = 0; - struct timespec write_time_ts; - struct timespec access_time_ts; - struct timespec change_time_ts; - SMB_INO_T ino = 0; - - if (!smbc_getatr(context, srv, path, &mode, &size, - NULL, - &access_time_ts, - &write_time_ts, - &change_time_ts, - &ino)) { - - /* Hmmm, bad error ... What? */ - - errno = smbc_errno(context, targetcli); - TALLOC_FREE(frame); - return -1; - - } - else { - - if (IS_DOS_DIR(mode)) - errno = EISDIR; - else - errno = saverr; /* Restore this */ - - } - } - - TALLOC_FREE(frame); - return -1; - - } - - TALLOC_FREE(frame); - return 0; /* Success ... */ - -} - -/* - * Routine to rename() a file - */ - -static int -smbc_rename_ctx(SMBCCTX *ocontext, - const char *oname, - SMBCCTX *ncontext, - const char *nname) -{ - 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(); - - if (!ocontext || !ncontext || - !ocontext->internal || !ncontext->internal || - !ocontext->internal->_initialized || - !ncontext->internal->_initialized) { - errno = EINVAL; /* Best I can think of ... */ - TALLOC_FREE(frame); - return -1; - } - - if (!oname || !nname) { - errno = EINVAL; - TALLOC_FREE(frame); - return -1; - } - - DEBUG(4, ("smbc_rename(%s,%s)\n", oname, nname)); - - if (smbc_parse_path(frame, - ocontext, - oname, - &workgroup, - &server1, - &share1, - &path1, - &user1, - &password1, - NULL)) { - errno = EINVAL; - TALLOC_FREE(frame); - return -1; - } - - if (!user1 || user1[0] == (char)0) { - user1 = talloc_strdup(frame, ocontext->user); - if (!user1) { - errno = ENOMEM; - TALLOC_FREE(frame); - return -1; - } - } - - if (smbc_parse_path(frame, - ncontext, - nname, - NULL, - &server2, - &share2, - &path2, - &user2, - &password2, - NULL)) { - errno = EINVAL; - TALLOC_FREE(frame); - return -1; - } - - if (!user2 || user2[0] == (char)0) { - user2 = talloc_strdup(frame, ncontext->user); - if (!user2) { - errno = ENOMEM; - TALLOC_FREE(frame); - return -1; - } - } - - if (strcmp(server1, server2) || strcmp(share1, share2) || - strcmp(user1, user2)) { - /* Can't rename across file systems, or users?? */ - errno = EXDEV; - TALLOC_FREE(frame); - return -1; - } - - srv = smbc_server(frame, ocontext, True, - server1, share1, &workgroup, &user1, &password1); - if (!srv) { - TALLOC_FREE(frame); - return -1; - - } - - /*d_printf(">>>rename: resolving %s\n", path1);*/ - if (!cli_resolve_path(frame, "", srv->cli, path1, - &targetcli1, &targetpath1)) { - d_printf("Could not resolve %s\n", path1); - TALLOC_FREE(frame); - return -1; - } - /*d_printf(">>>rename: resolved path as %s\n", targetpath1);*/ - /*d_printf(">>>rename: resolving %s\n", path2);*/ - if (!cli_resolve_path(frame, "", srv->cli, path2, - &targetcli2, &targetpath2)) { - d_printf("Could not resolve %s\n", path2); - TALLOC_FREE(frame); - return -1; - } - /*d_printf(">>>rename: resolved path as %s\n", targetpath2);*/ - - if (strcmp(targetcli1->desthost, targetcli2->desthost) || - strcmp(targetcli1->share, targetcli2->share)) - { - /* can't rename across file systems */ - errno = EXDEV; - TALLOC_FREE(frame); - return -1; - } - - if (!cli_rename(targetcli1, targetpath1, targetpath2)) { - int eno = smbc_errno(ocontext, targetcli1); - - if (eno != EEXIST || - !cli_unlink(targetcli1, targetpath2) || - !cli_rename(targetcli1, targetpath1, targetpath2)) { - - errno = eno; - TALLOC_FREE(frame); - return -1; - - } - } - - TALLOC_FREE(frame); - return 0; /* Success */ -} - -/* - * A routine to lseek() a file - */ - -static off_t -smbc_lseek_ctx(SMBCCTX *context, - SMBCFILE *file, - off_t offset, - int whence) -{ - SMB_OFF_T size; - 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 || - !context->internal->_initialized) { - errno = EINVAL; - TALLOC_FREE(frame); - return -1; - } - - if (!file || !DLIST_CONTAINS(context->internal->_files, file)) { - - errno = EBADF; - TALLOC_FREE(frame); - return -1; - - } - - if (!file->file) { - - errno = EINVAL; - TALLOC_FREE(frame); - return -1; /* Can't lseek a dir ... */ - - } - - switch (whence) { - case SEEK_SET: - file->offset = offset; - break; - - case SEEK_CUR: - file->offset += offset; - break; - - case SEEK_END: - /*d_printf(">>>lseek: parsing %s\n", file->fname);*/ - if (smbc_parse_path(frame, - context, - file->fname, - NULL, - &server, - &share, - &path, - &user, - &password, - NULL)) { - errno = EINVAL; - TALLOC_FREE(frame); - return -1; - } - - /*d_printf(">>>lseek: resolving %s\n", path);*/ - if (!cli_resolve_path(frame, "", file->srv->cli, path, - &targetcli, &targetpath)) { - d_printf("Could not resolve %s\n", path); - TALLOC_FREE(frame); - return -1; - } - /*d_printf(">>>lseek: resolved path as %s\n", targetpath);*/ - - if (!cli_qfileinfo(targetcli, file->cli_fd, NULL, - &size, NULL, NULL, NULL, NULL, NULL)) - { - SMB_OFF_T b_size = size; - if (!cli_getattrE(targetcli, file->cli_fd, - NULL, &b_size, NULL, NULL, NULL)) - { - errno = EINVAL; - TALLOC_FREE(frame); - return -1; - } else - size = b_size; - } - file->offset = size + offset; - break; - - default: - errno = EINVAL; - break; - - } - - TALLOC_FREE(frame); - return file->offset; - -} - -/* - * Generate an inode number from file name for those things that need it - */ - -static ino_t -smbc_inode(SMBCCTX *context, - const char *name) -{ - if (!context || !context->internal || - !context->internal->_initialized) { - - errno = EINVAL; - return -1; - - } - - if (!*name) return 2; /* FIXME, why 2 ??? */ - return (ino_t)str_checksum(name); - -} - -/* - * Routine to put basic stat info into a stat structure ... Used by stat and - * fstat below. - */ - -static int -smbc_setup_stat(SMBCCTX *context, - struct stat *st, - char *fname, - SMB_OFF_T size, - int mode) -{ - TALLOC_CTX *frame = talloc_stackframe(); - - st->st_mode = 0; - - if (IS_DOS_DIR(mode)) { - st->st_mode = SMBC_DIR_MODE; - } else { - st->st_mode = SMBC_FILE_MODE; - } - - if (IS_DOS_ARCHIVE(mode)) st->st_mode |= S_IXUSR; - if (IS_DOS_SYSTEM(mode)) st->st_mode |= S_IXGRP; - if (IS_DOS_HIDDEN(mode)) st->st_mode |= S_IXOTH; - if (!IS_DOS_READONLY(mode)) st->st_mode |= S_IWUSR; - - st->st_size = size; -#ifdef HAVE_STAT_ST_BLKSIZE - st->st_blksize = 512; -#endif -#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(); - - if (IS_DOS_DIR(mode)) { - st->st_nlink = 2; - } else { - st->st_nlink = 1; - } - - if (st->st_ino == 0) { - st->st_ino = smbc_inode(context, fname); - } - - TALLOC_FREE(frame); - return True; /* FIXME: Is this needed ? */ - -} - -/* - * Routine to stat a file given a name - */ - -static int -smbc_stat_ctx(SMBCCTX *context, - const char *fname, - struct stat *st) -{ - 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; - SMB_OFF_T size = 0; - uint16 mode = 0; - SMB_INO_T ino = 0; - TALLOC_CTX *frame = talloc_stackframe(); - - if (!context || !context->internal || - !context->internal->_initialized) { - - errno = EINVAL; /* Best I can think of ... */ - TALLOC_FREE(frame); - return -1; - } - - if (!fname) { - errno = EINVAL; - TALLOC_FREE(frame); - return -1; - } - - DEBUG(4, ("smbc_stat(%s)\n", fname)); - - if (smbc_parse_path(frame, - context, - fname, - &workgroup, - &server, - &share, - &path, - &user, - &password, - NULL)) { - errno = EINVAL; - TALLOC_FREE(frame); - return -1; - } - - if (!user || user[0] == (char)0) { - user = talloc_strdup(frame,context->user); - if (!user) { - errno = ENOMEM; - TALLOC_FREE(frame); - return -1; - } - } - - srv = smbc_server(frame, context, True, - server, share, &workgroup, &user, &password); - - if (!srv) { - TALLOC_FREE(frame); - return -1; /* errno set by smbc_server */ - } - - if (!smbc_getatr(context, srv, path, &mode, &size, - NULL, - &access_time_ts, - &write_time_ts, - &change_time_ts, - &ino)) { - errno = smbc_errno(context, srv->cli); - TALLOC_FREE(frame); - return -1; - } - - st->st_ino = ino; - - smbc_setup_stat(context, st, (char *) fname, size, mode); - - set_atimespec(st, access_time_ts); - set_ctimespec(st, change_time_ts); - set_mtimespec(st, write_time_ts); - st->st_dev = srv->dev; - - TALLOC_FREE(frame); - return 0; - -} - -/* - * Routine to stat a file given an fd - */ - -static int -smbc_fstat_ctx(SMBCCTX *context, - SMBCFILE *file, - struct stat *st) -{ - struct timespec change_time_ts; - struct timespec access_time_ts; - struct timespec write_time_ts; - SMB_OFF_T size; - uint16 mode; - 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(); - - if (!context || !context->internal || - !context->internal->_initialized) { - errno = EINVAL; - TALLOC_FREE(frame); - return -1; - } - - if (!file || !DLIST_CONTAINS(context->internal->_files, file)) { - errno = EBADF; - TALLOC_FREE(frame); - return -1; - } - - if (!file->file) { - TALLOC_FREE(frame); - return (context->fstatdir)(context, file, st); - } - - /*d_printf(">>>fstat: parsing %s\n", file->fname);*/ - if (smbc_parse_path(frame, - context, - file->fname, - NULL, - &server, - &share, - &path, - &user, - &password, - NULL)) { - errno = EINVAL; - TALLOC_FREE(frame); - return -1; - } - - /*d_printf(">>>fstat: resolving %s\n", path);*/ - if (!cli_resolve_path(frame, "", file->srv->cli, path, - &targetcli, &targetpath)) { - d_printf("Could not resolve %s\n", path); - TALLOC_FREE(frame); - return -1; - } - /*d_printf(">>>fstat: resolved path as %s\n", targetpath);*/ - - if (!cli_qfileinfo(targetcli, file->cli_fd, &mode, &size, - NULL, - &access_time_ts, - &write_time_ts, - &change_time_ts, - &ino)) { - - time_t change_time, access_time, write_time; - - if (!cli_getattrE(targetcli, file->cli_fd, &mode, &size, - &change_time, &access_time, &write_time)) { - - errno = EINVAL; - TALLOC_FREE(frame); - return -1; - } - - change_time_ts = convert_time_t_to_timespec(change_time); - access_time_ts = convert_time_t_to_timespec(access_time); - write_time_ts = convert_time_t_to_timespec(write_time); - } - - st->st_ino = ino; - - smbc_setup_stat(context, st, file->fname, size, mode); - - set_atimespec(st, access_time_ts); - set_ctimespec(st, change_time_ts); - set_mtimespec(st, write_time_ts); - st->st_dev = file->srv->dev; - - TALLOC_FREE(frame); - return 0; - -} - -/* - * Routine to truncate a file given by its file descriptor, to a specified size - */ - -static int -smbc_ftruncate_ctx(SMBCCTX *context, - SMBCFILE *file, - off_t length) -{ - SMB_OFF_T size = length; - char *server = NULL; - char *share = NULL; - char *user = NULL; - char *password = NULL; - char *path = NULL; - char *targetpath = NULL; - struct cli_state *targetcli = NULL; - TALLOC_CTX *frame = talloc_stackframe(); - - if (!context || !context->internal || - !context->internal->_initialized) { - errno = EINVAL; - TALLOC_FREE(frame); - return -1; - } - - if (!file || !DLIST_CONTAINS(context->internal->_files, file)) { - errno = EBADF; - TALLOC_FREE(frame); - return -1; - } - - if (!file->file) { - errno = EINVAL; - TALLOC_FREE(frame); - return -1; - } - - /*d_printf(">>>fstat: parsing %s\n", file->fname);*/ - if (smbc_parse_path(frame, - context, - file->fname, - NULL, - &server, - &share, - &path, - &user, - &password, - NULL)) { - errno = EINVAL; - TALLOC_FREE(frame); - return -1; - } - - /*d_printf(">>>fstat: resolving %s\n", path);*/ - if (!cli_resolve_path(frame, "", file->srv->cli, path, - &targetcli, &targetpath)) { - d_printf("Could not resolve %s\n", path); - TALLOC_FREE(frame); - return -1; - } - /*d_printf(">>>fstat: resolved path as %s\n", targetpath);*/ - - if (!cli_ftruncate(targetcli, file->cli_fd, size)) { - errno = EINVAL; - TALLOC_FREE(frame); - return -1; - } - - TALLOC_FREE(frame); - return 0; - -} - -/* - * Routine to open a directory - * We accept the URL syntax explained in smbc_parse_path(), above. - */ - -static void -smbc_remove_dir(SMBCFILE *dir) -{ - struct smbc_dir_list *d,*f; - - d = dir->dir_list; - while (d) { - - f = d; d = d->next; - - SAFE_FREE(f->dirent); - SAFE_FREE(f); - - } - - dir->dir_list = dir->dir_end = dir->dir_next = NULL; - -} - -static int -add_dirent(SMBCFILE *dir, - const char *name, - const char *comment, - uint32 type) -{ - struct smbc_dirent *dirent; - int size; - int name_length = (name == NULL ? 0 : strlen(name)); - int comment_len = (comment == NULL ? 0 : strlen(comment)); - - /* - * Allocate space for the dirent, which must be increased by the - * size of the name and the comment and 1 each for the null terminator. - */ - - size = sizeof(struct smbc_dirent) + name_length + comment_len + 2; - - dirent = (struct smbc_dirent *)SMB_MALLOC(size); - - if (!dirent) { - - dir->dir_error = ENOMEM; - return -1; - - } - - ZERO_STRUCTP(dirent); - - if (dir->dir_list == NULL) { - - dir->dir_list = SMB_MALLOC_P(struct smbc_dir_list); - if (!dir->dir_list) { - - SAFE_FREE(dirent); - dir->dir_error = ENOMEM; - return -1; - - } - ZERO_STRUCTP(dir->dir_list); - - dir->dir_end = dir->dir_next = dir->dir_list; - } - else { - - dir->dir_end->next = SMB_MALLOC_P(struct smbc_dir_list); - - if (!dir->dir_end->next) { - - SAFE_FREE(dirent); - dir->dir_error = ENOMEM; - return -1; - - } - ZERO_STRUCTP(dir->dir_end->next); - - dir->dir_end = dir->dir_end->next; - } - - dir->dir_end->next = NULL; - dir->dir_end->dirent = dirent; - - dirent->smbc_type = type; - dirent->namelen = name_length; - dirent->commentlen = comment_len; - dirent->dirlen = size; - - /* - * dirent->namelen + 1 includes the null (no null termination needed) - * Ditto for dirent->commentlen. - * The space for the two null bytes was allocated. - */ - strncpy(dirent->name, (name?name:""), dirent->namelen + 1); - dirent->comment = (char *)(&dirent->name + dirent->namelen + 1); - strncpy(dirent->comment, (comment?comment:""), dirent->commentlen + 1); - - return 0; - -} - -static void -list_unique_wg_fn(const char *name, - uint32 type, - const char *comment, - void *state) -{ - SMBCFILE *dir = (SMBCFILE *)state; - struct smbc_dir_list *dir_list; - struct smbc_dirent *dirent; - int dirent_type; - int do_remove = 0; - - dirent_type = dir->dir_type; - - if (add_dirent(dir, name, comment, dirent_type) < 0) { - - /* An error occurred, what do we do? */ - /* FIXME: Add some code here */ - } - - /* Point to the one just added */ - dirent = dir->dir_end->dirent; - - /* See if this was a duplicate */ - for (dir_list = dir->dir_list; - dir_list != dir->dir_end; - dir_list = dir_list->next) { - if (! do_remove && - strcmp(dir_list->dirent->name, dirent->name) == 0) { - /* Duplicate. End end of list need to be removed. */ - do_remove = 1; - } - - if (do_remove && dir_list->next == dir->dir_end) { - /* Found the end of the list. Remove it. */ - dir->dir_end = dir_list; - free(dir_list->next); - free(dirent); - dir_list->next = NULL; - break; - } - } -} - -static void -list_fn(const char *name, - uint32 type, - const char *comment, - void *state) -{ - SMBCFILE *dir = (SMBCFILE *)state; - int dirent_type; - - /* - * We need to process the type a little ... - * - * Disk share = 0x00000000 - * Print share = 0x00000001 - * Comms share = 0x00000002 (obsolete?) - * IPC$ share = 0x00000003 - * - * administrative shares: - * ADMIN$, IPC$, C$, D$, E$ ... are type |= 0x80000000 - */ - - if (dir->dir_type == SMBC_FILE_SHARE) { - switch (type) { - case 0 | 0x80000000: - case 0: - dirent_type = SMBC_FILE_SHARE; - break; - - case 1: - dirent_type = SMBC_PRINTER_SHARE; - break; - - case 2: - dirent_type = SMBC_COMMS_SHARE; - break; - - case 3 | 0x80000000: - case 3: - dirent_type = SMBC_IPC_SHARE; - break; - - default: - dirent_type = SMBC_FILE_SHARE; /* FIXME, error? */ - break; - } - } - else { - dirent_type = dir->dir_type; - } - - if (add_dirent(dir, name, comment, dirent_type) < 0) { - - /* An error occurred, what do we do? */ - /* FIXME: Add some code here */ - - } -} - -static void -dir_list_fn(const char *mnt, - file_info *finfo, - const char *mask, - void *state) -{ - - if (add_dirent((SMBCFILE *)state, finfo->name, "", - (finfo->mode&aDIR?SMBC_DIR:SMBC_FILE)) < 0) { - - /* Handle an error ... */ - - /* FIXME: Add some code ... */ - - } - -} - -static int -net_share_enum_rpc(struct cli_state *cli, - void (*fn)(const char *name, - uint32 type, - const char *comment, - void *state), - void *state) -{ - int i; - WERROR result; - ENUM_HND enum_hnd; - uint32 info_level = 1; - uint32 preferred_len = 0xffffffff; - uint32 type; - SRV_SHARE_INFO_CTR ctr; - fstring name = ""; - fstring comment = ""; - struct rpc_pipe_client *pipe_hnd; - NTSTATUS nt_status; - - /* Open the server service pipe */ - pipe_hnd = cli_rpc_pipe_open_noauth(cli, PI_SRVSVC, &nt_status); - if (!pipe_hnd) { - DEBUG(1, ("net_share_enum_rpc pipe open fail!\n")); - return -1; - } - - /* Issue the NetShareEnum RPC call and retrieve the response */ - init_enum_hnd(&enum_hnd, 0); - result = rpccli_srvsvc_net_share_enum(pipe_hnd, - talloc_tos(), - info_level, - &ctr, - preferred_len, - &enum_hnd); - - /* Was it successful? */ - if (!W_ERROR_IS_OK(result) || ctr.num_entries == 0) { - /* Nope. Go clean up. */ - goto done; - } - - /* For each returned entry... */ - for (i = 0; i < ctr.num_entries; i++) { - - /* pull out the share name */ - rpcstr_pull_unistr2_fstring( - name, &ctr.share.info1[i].info_1_str.uni_netname); - - /* pull out the share's comment */ - rpcstr_pull_unistr2_fstring( - comment, &ctr.share.info1[i].info_1_str.uni_remark); - - /* Get the type value */ - type = ctr.share.info1[i].info_1.type; - - /* Add this share to the list */ - (*fn)(name, type, comment, state); - } - -done: - /* Close the server service pipe */ - cli_rpc_pipe_close(pipe_hnd); - - /* Tell 'em if it worked */ - return W_ERROR_IS_OK(result) ? 0 : -1; -} - - - -static SMBCFILE * -smbc_opendir_ctx(SMBCCTX *context, - const char *fname) -{ - int saved_errno; - char *server = NULL, *share = NULL, *user = NULL, *password = NULL, *options = NULL; - char *workgroup = NULL; - char *path = NULL; - uint16 mode; - char *p = NULL; - SMBCSRV *srv = NULL; - SMBCFILE *dir = NULL; - struct _smbc_callbacks *cb = NULL; - struct sockaddr_storage rem_ss; - TALLOC_CTX *frame = talloc_stackframe(); - - if (!context || !context->internal || - !context->internal->_initialized) { - DEBUG(4, ("no valid context\n")); - errno = EINVAL + 8192; - TALLOC_FREE(frame); - return NULL; - - } - - if (!fname) { - DEBUG(4, ("no valid fname\n")); - errno = EINVAL + 8193; - TALLOC_FREE(frame); - return NULL; - } - - if (smbc_parse_path(frame, - context, - fname, - &workgroup, - &server, - &share, - &path, - &user, - &password, - &options)) { - DEBUG(4, ("no valid path\n")); - errno = EINVAL + 8194; - TALLOC_FREE(frame); - return NULL; - } - - DEBUG(4, ("parsed path: fname='%s' server='%s' share='%s' " - "path='%s' options='%s'\n", - fname, server, share, path, options)); - - /* Ensure the options are valid */ - if (smbc_check_options(server, share, path, options)) { - DEBUG(4, ("unacceptable options (%s)\n", options)); - errno = EINVAL + 8195; - TALLOC_FREE(frame); - return NULL; - } - - if (!user || user[0] == (char)0) { - user = talloc_strdup(frame, context->user); - if (!user) { - errno = ENOMEM; - TALLOC_FREE(frame); - return NULL; - } - } - - dir = SMB_MALLOC_P(SMBCFILE); - - if (!dir) { - errno = ENOMEM; - TALLOC_FREE(frame); - return NULL; - } - - ZERO_STRUCTP(dir); - - dir->cli_fd = 0; - dir->fname = SMB_STRDUP(fname); - dir->srv = NULL; - dir->offset = 0; - dir->file = False; - dir->dir_list = dir->dir_next = dir->dir_end = NULL; - - if (server[0] == (char)0) { - - int i; - int count; - int max_lmb_count; - struct ip_service *ip_list; - struct ip_service server_addr; - struct user_auth_info u_info; - - if (share[0] != (char)0 || path[0] != (char)0) { - - errno = EINVAL + 8196; - if (dir) { - SAFE_FREE(dir->fname); - SAFE_FREE(dir); - } - TALLOC_FREE(frame); - return NULL; - } - - /* Determine how many local master browsers to query */ - max_lmb_count = (context->options.browse_max_lmb_count == 0 - ? INT_MAX - : context->options.browse_max_lmb_count); - - memset(&u_info, '\0', sizeof(u_info)); - u_info.username = talloc_strdup(frame,user); - u_info.password = talloc_strdup(frame,password); - if (!u_info.username || !u_info.password) { - if (dir) { - SAFE_FREE(dir->fname); - SAFE_FREE(dir); - } - TALLOC_FREE(frame); - return NULL; - } - - /* - * We have server and share and path empty but options - * requesting that we scan all master browsers for their list - * of workgroups/domains. This implies that we must first try - * broadcast queries to find all master browsers, and if that - * doesn't work, then try our other methods which return only - * a single master browser. - */ - - ip_list = NULL; - if (!NT_STATUS_IS_OK(name_resolve_bcast(MSBROWSE, 1, &ip_list, - &count))) - { - - SAFE_FREE(ip_list); - - if (!find_master_ip(workgroup, &server_addr.ss)) { - - if (dir) { - SAFE_FREE(dir->fname); - SAFE_FREE(dir); - } - errno = ENOENT; - TALLOC_FREE(frame); - return NULL; - } - - ip_list = (struct ip_service *)memdup( - &server_addr, sizeof(server_addr)); - if (ip_list == NULL) { - errno = ENOMEM; - TALLOC_FREE(frame); - return NULL; - } - count = 1; - } - - for (i = 0; i < count && i < max_lmb_count; i++) { - char addr[INET6_ADDRSTRLEN]; - char *wg_ptr = NULL; - struct cli_state *cli = NULL; - - print_sockaddr(addr, sizeof(addr), &ip_list[i].ss); - DEBUG(99, ("Found master browser %d of %d: %s\n", - i+1, MAX(count, max_lmb_count), - addr)); - - cli = get_ipc_connect_master_ip(talloc_tos(), - &ip_list[i], - &u_info, - &wg_ptr); - /* cli == NULL is the master browser refused to talk or - could not be found */ - if (!cli) { - continue; - } - - workgroup = talloc_strdup(frame, wg_ptr); - server = talloc_strdup(frame, cli->desthost); - - cli_shutdown(cli); - - if (!workgroup || !server) { - errno = ENOMEM; - TALLOC_FREE(frame); - return NULL; - } - - DEBUG(4, ("using workgroup %s %s\n", - workgroup, server)); - - /* - * For each returned master browser IP address, get a - * connection to IPC$ on the server if we do not - * already have one, and determine the - * workgroups/domains that it knows about. - */ - - srv = smbc_server(frame, context, True, server, "IPC$", - &workgroup, &user, &password); - if (!srv) { - continue; - } - - dir->srv = srv; - dir->dir_type = SMBC_WORKGROUP; - - /* Now, list the stuff ... */ - - if (!cli_NetServerEnum(srv->cli, - workgroup, - SV_TYPE_DOMAIN_ENUM, - list_unique_wg_fn, - (void *)dir)) { - continue; - } - } - - SAFE_FREE(ip_list); - } else { - /* - * Server not an empty string ... Check the rest and see what - * gives - */ - if (*share == '\0') { - if (*path != '\0') { - - /* Should not have empty share with path */ - errno = EINVAL + 8197; - if (dir) { - SAFE_FREE(dir->fname); - SAFE_FREE(dir); - } - TALLOC_FREE(frame); - return NULL; - - } - - /* - * We don't know if is really a server name - * or is a workgroup/domain name. If we already have - * a server structure for it, we'll use it. - * Otherwise, check to see if <1D>, - * <1B>, or <20> translates. We check - * to see if is an IP address first. - */ - - /* - * See if we have an existing server. Do not - * establish a connection if one does not already - * exist. - */ - srv = smbc_server(frame, context, False, server, "IPC$", - &workgroup, &user, &password); - - /* - * If no existing server and not an IP addr, look for - * LMB or DMB - */ - if (!srv && - !is_ipaddress(server) && - (resolve_name(server, &rem_ss, 0x1d) || /* LMB */ - resolve_name(server, &rem_ss, 0x1b) )) { /* DMB */ - - fstring buserver; - - dir->dir_type = SMBC_SERVER; - - /* - * Get the backup list ... - */ - if (!name_status_find(server, 0, 0, - &rem_ss, buserver)) { - - DEBUG(0, ("Could not get name of " - "local/domain master browser " - "for server %s\n", server)); - if (dir) { - SAFE_FREE(dir->fname); - SAFE_FREE(dir); - } - errno = EPERM; - TALLOC_FREE(frame); - return NULL; - - } - - /* - * Get a connection to IPC$ on the server if - * we do not already have one - */ - srv = smbc_server(frame, context, True, - buserver, "IPC$", - &workgroup, &user, &password); - if (!srv) { - DEBUG(0, ("got no contact to IPC$\n")); - if (dir) { - SAFE_FREE(dir->fname); - SAFE_FREE(dir); - } - TALLOC_FREE(frame); - return NULL; - - } - - dir->srv = srv; - - /* Now, list the servers ... */ - if (!cli_NetServerEnum(srv->cli, server, - 0x0000FFFE, list_fn, - (void *)dir)) { - - if (dir) { - SAFE_FREE(dir->fname); - SAFE_FREE(dir); - } - TALLOC_FREE(frame); - return NULL; - } - } else if (srv || - (resolve_name(server, &rem_ss, 0x20))) { - - /* If we hadn't found the server, get one now */ - if (!srv) { - srv = smbc_server(frame, context, True, - server, "IPC$", - &workgroup, - &user, &password); - } - - if (!srv) { - if (dir) { - SAFE_FREE(dir->fname); - SAFE_FREE(dir); - } - TALLOC_FREE(frame); - return NULL; - - } - - dir->dir_type = SMBC_FILE_SHARE; - dir->srv = srv; - - /* List the shares ... */ - - if (net_share_enum_rpc( - srv->cli, - list_fn, - (void *) dir) < 0 && - cli_RNetShareEnum( - srv->cli, - list_fn, - (void *)dir) < 0) { - - errno = cli_errno(srv->cli); - if (dir) { - SAFE_FREE(dir->fname); - SAFE_FREE(dir); - } - TALLOC_FREE(frame); - return NULL; - - } - } else { - /* Neither the workgroup nor server exists */ - errno = ECONNREFUSED; - if (dir) { - SAFE_FREE(dir->fname); - SAFE_FREE(dir); - } - TALLOC_FREE(frame); - return NULL; - } - - } - else { - /* - * The server and share are specified ... work from - * there ... - */ - char *targetpath; - struct cli_state *targetcli; - - /* We connect to the server and list the directory */ - dir->dir_type = SMBC_FILE_SHARE; - - srv = smbc_server(frame, context, True, server, share, - &workgroup, &user, &password); - - if (!srv) { - if (dir) { - SAFE_FREE(dir->fname); - SAFE_FREE(dir); - } - TALLOC_FREE(frame); - return NULL; - } - - dir->srv = srv; - - /* Now, list the files ... */ - - p = path + strlen(path); - path = talloc_asprintf_append(path, "\\*"); - if (!path) { - if (dir) { - SAFE_FREE(dir->fname); - SAFE_FREE(dir); - } - TALLOC_FREE(frame); - return NULL; - } - - if (!cli_resolve_path(frame, "", srv->cli, path, - &targetcli, &targetpath)) { - d_printf("Could not resolve %s\n", path); - if (dir) { - SAFE_FREE(dir->fname); - SAFE_FREE(dir); - } - TALLOC_FREE(frame); - return NULL; - } - - if (cli_list(targetcli, targetpath, - aDIR | aSYSTEM | aHIDDEN, - dir_list_fn, (void *)dir) < 0) { - - if (dir) { - SAFE_FREE(dir->fname); - SAFE_FREE(dir); - } - saved_errno = smbc_errno(context, targetcli); - - if (saved_errno == EINVAL) { - /* - * See if they asked to opendir something - * other than a directory. If so, the - * converted error value we got would have - * been EINVAL rather than ENOTDIR. - */ - *p = '\0'; /* restore original path */ - - if (smbc_getatr(context, srv, path, - &mode, NULL, - NULL, NULL, NULL, NULL, - NULL) && - ! IS_DOS_DIR(mode)) { - - /* It is. Correct the error value */ - saved_errno = ENOTDIR; - } - } - - /* - * If there was an error and the server is no - * good any more... - */ - cb = &context->callbacks; - if (cli_is_error(targetcli) && - (cb->check_server_fn)(context, srv)) { - - /* ... then remove it. */ - if ((cb->remove_unused_server_fn)(context, - srv)) { - /* - * We could not remove the - * server completely, remove - * it from the cache so we - * will not get it again. It - * will be removed when the - * last file/dir is closed. - */ - (cb->remove_cached_srv_fn)(context, - srv); - } - } - - errno = saved_errno; - TALLOC_FREE(frame); - return NULL; - } - } - - } - - DLIST_ADD(context->internal->_files, dir); - TALLOC_FREE(frame); - return dir; - -} - -/* - * Routine to close a directory - */ - -static int -smbc_closedir_ctx(SMBCCTX *context, - SMBCFILE *dir) -{ - TALLOC_CTX *frame = talloc_stackframe(); - - if (!context || !context->internal || - !context->internal->_initialized) { - errno = EINVAL; - TALLOC_FREE(frame); - return -1; - } - - if (!dir || !DLIST_CONTAINS(context->internal->_files, dir)) { - errno = EBADF; - TALLOC_FREE(frame); - return -1; - } - - smbc_remove_dir(dir); /* Clean it up */ - - DLIST_REMOVE(context->internal->_files, dir); - - if (dir) { - - SAFE_FREE(dir->fname); - SAFE_FREE(dir); /* Free the space too */ - } - - TALLOC_FREE(frame); - return 0; - -} - -static void -smbc_readdir_internal(SMBCCTX * context, - struct smbc_dirent *dest, - struct smbc_dirent *src, - int max_namebuf_len) -{ - if (context->options.urlencode_readdir_entries) { - - /* url-encode the name. get back remaining buffer space */ - max_namebuf_len = - smbc_urlencode(dest->name, src->name, max_namebuf_len); - - /* We now know the name length */ - dest->namelen = strlen(dest->name); - - /* Save the pointer to the beginning of the comment */ - dest->comment = dest->name + dest->namelen + 1; - - /* Copy the comment */ - strncpy(dest->comment, src->comment, max_namebuf_len - 1); - dest->comment[max_namebuf_len - 1] = '\0'; - - /* Save other fields */ - dest->smbc_type = src->smbc_type; - dest->commentlen = strlen(dest->comment); - dest->dirlen = ((dest->comment + dest->commentlen + 1) - - (char *) dest); - } else { - - /* No encoding. Just copy the entry as is. */ - memcpy(dest, src, src->dirlen); - dest->comment = (char *)(&dest->name + src->namelen + 1); - } - -} - -/* - * Routine to get a directory entry - */ - -struct smbc_dirent * -smbc_readdir_ctx(SMBCCTX *context, - SMBCFILE *dir) -{ - int maxlen; - struct smbc_dirent *dirp, *dirent; - TALLOC_CTX *frame = talloc_stackframe(); - - /* Check that all is ok first ... */ - - if (!context || !context->internal || - !context->internal->_initialized) { - - errno = EINVAL; - DEBUG(0, ("Invalid context in smbc_readdir_ctx()\n")); - TALLOC_FREE(frame); - return NULL; - - } - - if (!dir || !DLIST_CONTAINS(context->internal->_files, dir)) { - - errno = EBADF; - DEBUG(0, ("Invalid dir in smbc_readdir_ctx()\n")); - TALLOC_FREE(frame); - return NULL; - - } - - if (dir->file != False) { /* FIXME, should be dir, perhaps */ - - errno = ENOTDIR; - DEBUG(0, ("Found file vs directory in smbc_readdir_ctx()\n")); - TALLOC_FREE(frame); - return NULL; - - } - - if (!dir->dir_next) { - TALLOC_FREE(frame); - return NULL; - } - - dirent = dir->dir_next->dirent; - if (!dirent) { - - errno = ENOENT; - TALLOC_FREE(frame); - return NULL; - - } - - dirp = (struct smbc_dirent *)context->internal->_dirent; - maxlen = (sizeof(context->internal->_dirent) - - sizeof(struct smbc_dirent)); - - smbc_readdir_internal(context, dirp, dirent, maxlen); - - dir->dir_next = dir->dir_next->next; - - TALLOC_FREE(frame); - return dirp; -} - -/* - * Routine to get directory entries - */ - -static int -smbc_getdents_ctx(SMBCCTX *context, - SMBCFILE *dir, - struct smbc_dirent *dirp, - int count) -{ - int rem = count; - int reqd; - int maxlen; - char *ndir = (char *)dirp; - struct smbc_dir_list *dirlist; - TALLOC_CTX *frame = talloc_stackframe(); - - /* Check that all is ok first ... */ - - if (!context || !context->internal || - !context->internal->_initialized) { - - errno = EINVAL; - TALLOC_FREE(frame); - return -1; - - } - - if (!dir || !DLIST_CONTAINS(context->internal->_files, dir)) { - - errno = EBADF; - TALLOC_FREE(frame); - return -1; - - } - - if (dir->file != False) { /* FIXME, should be dir, perhaps */ - - errno = ENOTDIR; - TALLOC_FREE(frame); - return -1; - - } - - /* - * Now, retrieve the number of entries that will fit in what was passed - * We have to figure out if the info is in the list, or we need to - * send a request to the server to get the info. - */ - - while ((dirlist = dir->dir_next)) { - struct smbc_dirent *dirent; - - if (!dirlist->dirent) { - - errno = ENOENT; /* Bad error */ - TALLOC_FREE(frame); - return -1; - - } - - /* Do urlencoding of next entry, if so selected */ - dirent = (struct smbc_dirent *)context->internal->_dirent; - maxlen = (sizeof(context->internal->_dirent) - - sizeof(struct smbc_dirent)); - smbc_readdir_internal(context, dirent, dirlist->dirent, maxlen); - - reqd = dirent->dirlen; - - if (rem < reqd) { - - if (rem < count) { /* We managed to copy something */ - - errno = 0; - TALLOC_FREE(frame); - return count - rem; - - } - else { /* Nothing copied ... */ - - errno = EINVAL; /* Not enough space ... */ - TALLOC_FREE(frame); - return -1; - - } - - } - - memcpy(ndir, dirent, reqd); /* Copy the data in ... */ - - ((struct smbc_dirent *)ndir)->comment = - (char *)(&((struct smbc_dirent *)ndir)->name + - dirent->namelen + - 1); - - ndir += reqd; - - rem -= reqd; - - dir->dir_next = dirlist = dirlist -> next; - } - - TALLOC_FREE(frame); - - if (rem == count) - return 0; - else - return count - rem; - -} - -/* - * Routine to create a directory ... - */ - -static int -smbc_mkdir_ctx(SMBCCTX *context, - const char *fname, - mode_t mode) -{ - 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 || - !context->internal->_initialized) { - errno = EINVAL; - TALLOC_FREE(frame); - return -1; - } - - if (!fname) { - errno = EINVAL; - TALLOC_FREE(frame); - return -1; - } - - DEBUG(4, ("smbc_mkdir(%s)\n", fname)); - - if (smbc_parse_path(frame, - context, - fname, - &workgroup, - &server, - &share, - &path, - &user, - &password, - NULL)) { - errno = EINVAL; - TALLOC_FREE(frame); - return -1; - } - - if (!user || user[0] == (char)0) { - user = talloc_strdup(frame, context->user); - if (!user) { - errno = ENOMEM; - TALLOC_FREE(frame); - return -1; - } - } - - srv = smbc_server(frame, context, True, - server, share, &workgroup, &user, &password); - - if (!srv) { - - TALLOC_FREE(frame); - return -1; /* errno set by smbc_server */ - - } - - /*d_printf(">>>mkdir: resolving %s\n", path);*/ - if (!cli_resolve_path(frame, "", srv->cli, path, - &targetcli, &targetpath)) { - d_printf("Could not resolve %s\n", path); - TALLOC_FREE(frame); - return -1; - } - /*d_printf(">>>mkdir: resolved path as %s\n", targetpath);*/ - - if (!cli_mkdir(targetcli, targetpath)) { - - errno = smbc_errno(context, targetcli); - TALLOC_FREE(frame); - return -1; - - } - - TALLOC_FREE(frame); - return 0; - -} - -/* - * Our list function simply checks to see if a directory is not empty - */ - -static int smbc_rmdir_dirempty = True; - -static void -rmdir_list_fn(const char *mnt, - file_info *finfo, - const char *mask, - void *state) -{ - if (strncmp(finfo->name, ".", 1) != 0 && - strncmp(finfo->name, "..", 2) != 0) { - smbc_rmdir_dirempty = False; - } -} - -/* - * Routine to remove a directory - */ - -static int -smbc_rmdir_ctx(SMBCCTX *context, - const char *fname) -{ - 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 || - !context->internal->_initialized) { - errno = EINVAL; - TALLOC_FREE(frame); - return -1; - } - - if (!fname) { - errno = EINVAL; - TALLOC_FREE(frame); - return -1; - } - - DEBUG(4, ("smbc_rmdir(%s)\n", fname)); - - if (smbc_parse_path(frame, - context, - fname, - &workgroup, - &server, - &share, - &path, - &user, - &password, - NULL)) { - errno = EINVAL; - TALLOC_FREE(frame); - return -1; - } - - if (!user || user[0] == (char)0) { - user = talloc_strdup(frame, context->user); - if (!user) { - errno = ENOMEM; - TALLOC_FREE(frame); - return -1; - } - } - - srv = smbc_server(frame, context, True, - server, share, &workgroup, &user, &password); - - if (!srv) { - - TALLOC_FREE(frame); - return -1; /* errno set by smbc_server */ - - } - - /*d_printf(">>>rmdir: resolving %s\n", path);*/ - if (!cli_resolve_path(frame, "", srv->cli, path, - &targetcli, &targetpath)) { - d_printf("Could not resolve %s\n", path); - TALLOC_FREE(frame); - return -1; - } - /*d_printf(">>>rmdir: resolved path as %s\n", targetpath);*/ - - - if (!cli_rmdir(targetcli, targetpath)) { - - errno = smbc_errno(context, targetcli); - - if (errno == EACCES) { /* Check if the dir empty or not */ - - /* Local storage to avoid buffer overflows */ - char *lpath; - - smbc_rmdir_dirempty = True; /* Make this so ... */ - - lpath = talloc_asprintf(frame, "%s\\*", - targetpath); - if (!lpath) { - errno = ENOMEM; - TALLOC_FREE(frame); - return -1; - } - - if (cli_list(targetcli, lpath, - aDIR | aSYSTEM | aHIDDEN, - rmdir_list_fn, NULL) < 0) { - - /* Fix errno to ignore latest error ... */ - DEBUG(5, ("smbc_rmdir: " - "cli_list returned an error: %d\n", - smbc_errno(context, targetcli))); - errno = EACCES; - - } - - if (smbc_rmdir_dirempty) - errno = EACCES; - else - errno = ENOTEMPTY; - - } - - TALLOC_FREE(frame); - return -1; - - } - - TALLOC_FREE(frame); - return 0; - -} - -/* - * Routine to return the current directory position - */ - -static off_t -smbc_telldir_ctx(SMBCCTX *context, - SMBCFILE *dir) -{ - TALLOC_CTX *frame = talloc_stackframe(); - - if (!context || !context->internal || - !context->internal->_initialized) { - - errno = EINVAL; - TALLOC_FREE(frame); - return -1; - - } - - if (!dir || !DLIST_CONTAINS(context->internal->_files, dir)) { - - errno = EBADF; - TALLOC_FREE(frame); - return -1; - - } - - if (dir->file != False) { /* FIXME, should be dir, perhaps */ - - errno = ENOTDIR; - TALLOC_FREE(frame); - return -1; - - } - - /* See if we're already at the end. */ - if (dir->dir_next == NULL) { - /* We are. */ - TALLOC_FREE(frame); - return -1; - } - - /* - * We return the pointer here as the offset - */ - TALLOC_FREE(frame); - return (off_t)(long)dir->dir_next->dirent; -} - -/* - * A routine to run down the list and see if the entry is OK - */ - -struct smbc_dir_list * -smbc_check_dir_ent(struct smbc_dir_list *list, - struct smbc_dirent *dirent) -{ - - /* Run down the list looking for what we want */ - - if (dirent) { - - struct smbc_dir_list *tmp = list; - - while (tmp) { - - if (tmp->dirent == dirent) - return tmp; - - tmp = tmp->next; - - } - - } - - return NULL; /* Not found, or an error */ - -} - - -/* - * Routine to seek on a directory - */ - -static int -smbc_lseekdir_ctx(SMBCCTX *context, - SMBCFILE *dir, - off_t offset) -{ - long int l_offset = offset; /* Handle problems of size */ - struct smbc_dirent *dirent = (struct smbc_dirent *)l_offset; - struct smbc_dir_list *list_ent = (struct smbc_dir_list *)NULL; - TALLOC_CTX *frame = talloc_stackframe(); - - if (!context || !context->internal || - !context->internal->_initialized) { - - errno = EINVAL; - TALLOC_FREE(frame); - return -1; - - } - - if (dir->file != False) { /* FIXME, should be dir, perhaps */ - - errno = ENOTDIR; - TALLOC_FREE(frame); - return -1; - - } - - /* Now, check what we were passed and see if it is OK ... */ - - if (dirent == NULL) { /* Seek to the begining of the list */ - - dir->dir_next = dir->dir_list; - TALLOC_FREE(frame); - return 0; - - } - - if (offset == -1) { /* Seek to the end of the list */ - dir->dir_next = NULL; - TALLOC_FREE(frame); - return 0; - } - - /* Now, run down the list and make sure that the entry is OK */ - /* This may need to be changed if we change the format of the list */ - - if ((list_ent = smbc_check_dir_ent(dir->dir_list, dirent)) == NULL) { - errno = EINVAL; /* Bad entry */ - TALLOC_FREE(frame); - return -1; - } - - dir->dir_next = list_ent; - - TALLOC_FREE(frame); - return 0; -} - -/* - * Routine to fstat a dir - */ - -static int -smbc_fstatdir_ctx(SMBCCTX *context, - SMBCFILE *dir, - struct stat *st) -{ - - if (!context || !context->internal || - !context->internal->_initialized) { - errno = EINVAL; - return -1; - } - - /* No code yet ... */ - return 0; -} - -static int -smbc_chmod_ctx(SMBCCTX *context, - const char *fname, - mode_t newmode) -{ - 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(); - - if (!context || !context->internal || - !context->internal->_initialized) { - errno = EINVAL; /* Best I can think of ... */ - TALLOC_FREE(frame); - return -1; - } - - if (!fname) { - errno = EINVAL; - TALLOC_FREE(frame); - return -1; - } - - DEBUG(4, ("smbc_chmod(%s, 0%3o)\n", fname, newmode)); - - if (smbc_parse_path(frame, - context, - fname, - &workgroup, - &server, - &share, - &path, - &user, - &password, - NULL)) { - errno = EINVAL; - TALLOC_FREE(frame); - return -1; - } - - if (!user || user[0] == (char)0) { - user = talloc_strdup(frame, context->user); - if (!user) { - errno = ENOMEM; - TALLOC_FREE(frame); - return -1; - } - } - - srv = smbc_server(frame, context, True, - server, share, &workgroup, &user, &password); - - if (!srv) { - TALLOC_FREE(frame); - return -1; /* errno set by smbc_server */ - } - - mode = 0; - - if (!(newmode & (S_IWUSR | S_IWGRP | S_IWOTH))) mode |= aRONLY; - if ((newmode & S_IXUSR) && lp_map_archive(-1)) mode |= aARCH; - if ((newmode & S_IXGRP) && lp_map_system(-1)) mode |= aSYSTEM; - if ((newmode & S_IXOTH) && lp_map_hidden(-1)) mode |= aHIDDEN; - - if (!cli_setatr(srv->cli, path, mode, 0)) { - errno = smbc_errno(context, srv->cli); - TALLOC_FREE(frame); - return -1; - } - - TALLOC_FREE(frame); - return 0; -} - -static int -smbc_utimes_ctx(SMBCCTX *context, - const char *fname, - struct timeval *tbuf) -{ - 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(); - - if (!context || !context->internal || - !context->internal->_initialized) { - errno = EINVAL; /* Best I can think of ... */ - TALLOC_FREE(frame); - return -1; - } - - if (!fname) { - errno = EINVAL; - TALLOC_FREE(frame); - return -1; - } - - if (tbuf == NULL) { - access_time = write_time = time(NULL); - } else { - access_time = tbuf[0].tv_sec; - write_time = tbuf[1].tv_sec; - } - - if (DEBUGLVL(4)) { - char *p; - char atimebuf[32]; - char mtimebuf[32]; - - strncpy(atimebuf, ctime(&access_time), sizeof(atimebuf) - 1); - atimebuf[sizeof(atimebuf) - 1] = '\0'; - if ((p = strchr(atimebuf, '\n')) != NULL) { - *p = '\0'; - } - - strncpy(mtimebuf, ctime(&write_time), sizeof(mtimebuf) - 1); - mtimebuf[sizeof(mtimebuf) - 1] = '\0'; - if ((p = strchr(mtimebuf, '\n')) != NULL) { - *p = '\0'; - } - - dbgtext("smbc_utimes(%s, atime = %s mtime = %s)\n", - fname, atimebuf, mtimebuf); - } - - if (smbc_parse_path(frame, - context, - fname, - &workgroup, - &server, - &share, - &path, - &user, - &password, - NULL)) { - errno = EINVAL; - TALLOC_FREE(frame); - return -1; - } - - if (!user || user[0] == (char)0) { - user = talloc_strdup(frame, context->user); - if (!user) { - errno = ENOMEM; - TALLOC_FREE(frame); - return -1; - } - } - - srv = smbc_server(frame, context, True, - server, share, &workgroup, &user, &password); - - if (!srv) { - TALLOC_FREE(frame); - return -1; /* errno set by smbc_server */ - } - - if (!smbc_setatr(context, srv, path, - 0, access_time, write_time, 0, 0)) { - TALLOC_FREE(frame); - return -1; /* errno set by smbc_setatr */ - } - - TALLOC_FREE(frame); - return 0; -} - - -/* - * Sort ACEs according to the documentation at - * http://support.microsoft.com/kb/269175, at least as far as it defines the - * order. - */ - -static int -ace_compare(SEC_ACE *ace1, - SEC_ACE *ace2) -{ - bool b1; - bool b2; - - /* If the ACEs are equal, we have nothing more to do. */ - if (sec_ace_equal(ace1, ace2)) { - return 0; - } - - /* Inherited follow non-inherited */ - b1 = ((ace1->flags & SEC_ACE_FLAG_INHERITED_ACE) != 0); - b2 = ((ace2->flags & SEC_ACE_FLAG_INHERITED_ACE) != 0); - if (b1 != b2) { - return (b1 ? 1 : -1); - } - - /* - * What shall we do with AUDITs and ALARMs? It's undefined. We'll - * sort them after DENY and ALLOW. - */ - b1 = (ace1->type != SEC_ACE_TYPE_ACCESS_ALLOWED && - ace1->type != SEC_ACE_TYPE_ACCESS_ALLOWED_OBJECT && - ace1->type != SEC_ACE_TYPE_ACCESS_DENIED && - ace1->type != SEC_ACE_TYPE_ACCESS_DENIED_OBJECT); - b2 = (ace2->type != SEC_ACE_TYPE_ACCESS_ALLOWED && - ace2->type != SEC_ACE_TYPE_ACCESS_ALLOWED_OBJECT && - ace2->type != SEC_ACE_TYPE_ACCESS_DENIED && - ace2->type != SEC_ACE_TYPE_ACCESS_DENIED_OBJECT); - if (b1 != b2) { - return (b1 ? 1 : -1); - } - - /* Allowed ACEs follow denied ACEs */ - b1 = (ace1->type == SEC_ACE_TYPE_ACCESS_ALLOWED || - ace1->type == SEC_ACE_TYPE_ACCESS_ALLOWED_OBJECT); - b2 = (ace2->type == SEC_ACE_TYPE_ACCESS_ALLOWED || - ace2->type == SEC_ACE_TYPE_ACCESS_ALLOWED_OBJECT); - if (b1 != b2) { - return (b1 ? 1 : -1); - } - - /* - * ACEs applying to an entity's object follow those applying to the - * entity itself - */ - b1 = (ace1->type == SEC_ACE_TYPE_ACCESS_ALLOWED_OBJECT || - ace1->type == SEC_ACE_TYPE_ACCESS_DENIED_OBJECT); - b2 = (ace2->type == SEC_ACE_TYPE_ACCESS_ALLOWED_OBJECT || - ace2->type == SEC_ACE_TYPE_ACCESS_DENIED_OBJECT); - if (b1 != b2) { - return (b1 ? 1 : -1); - } - - /* - * If we get this far, the ACEs are similar as far as the - * characteristics we typically care about (those defined by the - * referenced MS document). We'll now sort by characteristics that - * just seems reasonable. - */ - - if (ace1->type != ace2->type) { - return ace2->type - ace1->type; - } - - if (sid_compare(&ace1->trustee, &ace2->trustee)) { - return sid_compare(&ace1->trustee, &ace2->trustee); - } - - if (ace1->flags != ace2->flags) { - return ace1->flags - ace2->flags; - } - - if (ace1->access_mask != ace2->access_mask) { - return ace1->access_mask - ace2->access_mask; - } - - if (ace1->size != ace2->size) { - return ace1->size - ace2->size; - } - - return memcmp(ace1, ace2, sizeof(SEC_ACE)); -} - - -static void -sort_acl(SEC_ACL *the_acl) -{ - uint32 i; - if (!the_acl) return; - - qsort(the_acl->aces, the_acl->num_aces, sizeof(the_acl->aces[0]), - QSORT_CAST ace_compare); - - for (i=1;inum_aces;) { - if (sec_ace_equal(&the_acl->aces[i-1], &the_acl->aces[i])) { - int j; - for (j=i; jnum_aces-1; j++) { - the_acl->aces[j] = the_acl->aces[j+1]; - } - the_acl->num_aces--; - } else { - i++; - } - } -} - -/* convert a SID to a string, either numeric or username/group */ -static void -convert_sid_to_string(struct cli_state *ipc_cli, - POLICY_HND *pol, - fstring str, - bool numeric, - DOM_SID *sid) -{ - char **domains = NULL; - char **names = NULL; - enum lsa_SidType *types = NULL; - struct rpc_pipe_client *pipe_hnd = find_lsa_pipe_hnd(ipc_cli); - TALLOC_CTX *ctx; - - sid_to_fstring(str, sid); - - if (numeric) { - return; /* no lookup desired */ - } - - if (!pipe_hnd) { - return; - } - - /* Ask LSA to convert the sid to a name */ - - ctx = talloc_stackframe(); - - if (!NT_STATUS_IS_OK(rpccli_lsa_lookup_sids(pipe_hnd, ctx, - pol, 1, sid, &domains, - &names, &types)) || - !domains || !domains[0] || !names || !names[0]) { - TALLOC_FREE(ctx); - return; - } - - TALLOC_FREE(ctx); - /* Converted OK */ - - slprintf(str, sizeof(fstring) - 1, "%s%s%s", - domains[0], lp_winbind_separator(), - names[0]); -} - -/* convert a string to a SID, either numeric or username/group */ -static bool -convert_string_to_sid(struct cli_state *ipc_cli, - POLICY_HND *pol, - bool numeric, - DOM_SID *sid, - const char *str) -{ - enum lsa_SidType *types = NULL; - DOM_SID *sids = NULL; - bool result = True; - TALLOC_CTX *ctx = NULL; - struct rpc_pipe_client *pipe_hnd = find_lsa_pipe_hnd(ipc_cli); - - if (!pipe_hnd) { - return False; - } - - if (numeric) { - if (strncmp(str, "S-", 2) == 0) { - return string_to_sid(sid, str); - } - - result = False; - goto done; - } - - ctx = talloc_stackframe(); - if (!NT_STATUS_IS_OK(rpccli_lsa_lookup_names(pipe_hnd, ctx, - pol, 1, &str, NULL, 1, &sids, - &types))) { - result = False; - goto done; - } - - sid_copy(sid, &sids[0]); - done: - - TALLOC_FREE(ctx); - return result; -} - - -/* parse an ACE in the same format as print_ace() */ -static bool -parse_ace(struct cli_state *ipc_cli, - POLICY_HND *pol, - SEC_ACE *ace, - bool numeric, - char *str) -{ - char *p; - const char *cp; - char *tok; - unsigned int atype; - unsigned int aflags; - unsigned int amask; - DOM_SID sid; - SEC_ACCESS mask; - const struct perm_value *v; - struct perm_value { - const char *perm; - uint32 mask; - }; - TALLOC_CTX *frame = talloc_stackframe(); - - /* These values discovered by inspection */ - static const struct perm_value special_values[] = { - { "R", 0x00120089 }, - { "W", 0x00120116 }, - { "X", 0x001200a0 }, - { "D", 0x00010000 }, - { "P", 0x00040000 }, - { "O", 0x00080000 }, - { NULL, 0 }, - }; - - static const struct perm_value standard_values[] = { - { "READ", 0x001200a9 }, - { "CHANGE", 0x001301bf }, - { "FULL", 0x001f01ff }, - { NULL, 0 }, - }; - - - ZERO_STRUCTP(ace); - p = strchr_m(str,':'); - if (!p) { - TALLOC_FREE(frame); - return False; - } - *p = '\0'; - p++; - /* Try to parse numeric form */ - - if (sscanf(p, "%i/%i/%i", &atype, &aflags, &amask) == 3 && - convert_string_to_sid(ipc_cli, pol, numeric, &sid, str)) { - goto done; - } - - /* Try to parse text form */ - - if (!convert_string_to_sid(ipc_cli, pol, numeric, &sid, str)) { - TALLOC_FREE(frame); - return false; - } - - cp = p; - if (!next_token_talloc(frame, &cp, &tok, "/")) { - TALLOC_FREE(frame); - return false; - } - - if (StrnCaseCmp(tok, "ALLOWED", strlen("ALLOWED")) == 0) { - atype = SEC_ACE_TYPE_ACCESS_ALLOWED; - } else if (StrnCaseCmp(tok, "DENIED", strlen("DENIED")) == 0) { - atype = SEC_ACE_TYPE_ACCESS_DENIED; - } else { - TALLOC_FREE(frame); - return false; - } - - /* Only numeric form accepted for flags at present */ - - if (!(next_token_talloc(frame, &cp, &tok, "/") && - sscanf(tok, "%i", &aflags))) { - TALLOC_FREE(frame); - return false; - } - - if (!next_token_talloc(frame, &cp, &tok, "/")) { - TALLOC_FREE(frame); - return false; - } - - if (strncmp(tok, "0x", 2) == 0) { - if (sscanf(tok, "%i", &amask) != 1) { - TALLOC_FREE(frame); - return false; - } - goto done; - } - - for (v = standard_values; v->perm; v++) { - if (strcmp(tok, v->perm) == 0) { - amask = v->mask; - goto done; - } - } - - p = tok; - - while(*p) { - bool found = False; - - for (v = special_values; v->perm; v++) { - if (v->perm[0] == *p) { - amask |= v->mask; - found = True; - } - } - - if (!found) { - TALLOC_FREE(frame); - return false; - } - p++; - } - - if (*p) { - TALLOC_FREE(frame); - return false; - } - - done: - mask = amask; - init_sec_ace(ace, &sid, atype, mask, aflags); - TALLOC_FREE(frame); - return true; -} - -/* add an ACE to a list of ACEs in a SEC_ACL */ -static bool -add_ace(SEC_ACL **the_acl, - SEC_ACE *ace, - TALLOC_CTX *ctx) -{ - SEC_ACL *newacl; - SEC_ACE *aces; - - if (! *the_acl) { - (*the_acl) = make_sec_acl(ctx, 3, 1, ace); - return True; - } - - if ((aces = SMB_CALLOC_ARRAY(SEC_ACE, 1+(*the_acl)->num_aces)) == NULL) { - return False; - } - memcpy(aces, (*the_acl)->aces, (*the_acl)->num_aces * sizeof(SEC_ACE)); - memcpy(aces+(*the_acl)->num_aces, ace, sizeof(SEC_ACE)); - newacl = make_sec_acl(ctx, (*the_acl)->revision, - 1+(*the_acl)->num_aces, aces); - SAFE_FREE(aces); - (*the_acl) = newacl; - return True; -} - - -/* parse a ascii version of a security descriptor */ -static SEC_DESC * -sec_desc_parse(TALLOC_CTX *ctx, - struct cli_state *ipc_cli, - POLICY_HND *pol, - bool numeric, - char *str) -{ - const char *p = str; - char *tok; - SEC_DESC *ret = NULL; - size_t sd_size; - DOM_SID *group_sid=NULL; - DOM_SID *owner_sid=NULL; - SEC_ACL *dacl=NULL; - int revision=1; - - while (next_token_talloc(ctx, &p, &tok, "\t,\r\n")) { - - if (StrnCaseCmp(tok,"REVISION:", 9) == 0) { - revision = strtol(tok+9, NULL, 16); - continue; - } - - if (StrnCaseCmp(tok,"OWNER:", 6) == 0) { - if (owner_sid) { - DEBUG(5, ("OWNER specified more than once!\n")); - goto done; - } - owner_sid = SMB_CALLOC_ARRAY(DOM_SID, 1); - if (!owner_sid || - !convert_string_to_sid(ipc_cli, pol, - numeric, - owner_sid, tok+6)) { - DEBUG(5, ("Failed to parse owner sid\n")); - goto done; - } - continue; - } - - if (StrnCaseCmp(tok,"OWNER+:", 7) == 0) { - if (owner_sid) { - DEBUG(5, ("OWNER specified more than once!\n")); - goto done; - } - owner_sid = SMB_CALLOC_ARRAY(DOM_SID, 1); - if (!owner_sid || - !convert_string_to_sid(ipc_cli, pol, - False, - owner_sid, tok+7)) { - DEBUG(5, ("Failed to parse owner sid\n")); - goto done; - } - continue; - } - - if (StrnCaseCmp(tok,"GROUP:", 6) == 0) { - if (group_sid) { - DEBUG(5, ("GROUP specified more than once!\n")); - goto done; - } - group_sid = SMB_CALLOC_ARRAY(DOM_SID, 1); - if (!group_sid || - !convert_string_to_sid(ipc_cli, pol, - numeric, - group_sid, tok+6)) { - DEBUG(5, ("Failed to parse group sid\n")); - goto done; - } - continue; - } - - if (StrnCaseCmp(tok,"GROUP+:", 7) == 0) { - if (group_sid) { - DEBUG(5, ("GROUP specified more than once!\n")); - goto done; - } - group_sid = SMB_CALLOC_ARRAY(DOM_SID, 1); - if (!group_sid || - !convert_string_to_sid(ipc_cli, pol, - False, - group_sid, tok+6)) { - DEBUG(5, ("Failed to parse group sid\n")); - goto done; - } - continue; - } - - if (StrnCaseCmp(tok,"ACL:", 4) == 0) { - SEC_ACE ace; - if (!parse_ace(ipc_cli, pol, &ace, numeric, tok+4)) { - DEBUG(5, ("Failed to parse ACL %s\n", tok)); - goto done; - } - if(!add_ace(&dacl, &ace, ctx)) { - DEBUG(5, ("Failed to add ACL %s\n", tok)); - goto done; - } - continue; - } - - if (StrnCaseCmp(tok,"ACL+:", 5) == 0) { - SEC_ACE ace; - if (!parse_ace(ipc_cli, pol, &ace, False, tok+5)) { - DEBUG(5, ("Failed to parse ACL %s\n", tok)); - goto done; - } - if(!add_ace(&dacl, &ace, ctx)) { - DEBUG(5, ("Failed to add ACL %s\n", tok)); - goto done; - } - continue; - } - - DEBUG(5, ("Failed to parse security descriptor\n")); - goto done; - } - - ret = make_sec_desc(ctx, revision, SEC_DESC_SELF_RELATIVE, - owner_sid, group_sid, NULL, dacl, &sd_size); - - done: - SAFE_FREE(group_sid); - SAFE_FREE(owner_sid); - - return ret; -} - - -/* Obtain the current dos attributes */ -static DOS_ATTR_DESC * -dos_attr_query(SMBCCTX *context, - TALLOC_CTX *ctx, - const char *filename, - SMBCSRV *srv) -{ - struct timespec create_time_ts; - struct timespec write_time_ts; - struct timespec access_time_ts; - struct timespec change_time_ts; - SMB_OFF_T size = 0; - uint16 mode = 0; - SMB_INO_T inode = 0; - DOS_ATTR_DESC *ret; - - ret = TALLOC_P(ctx, DOS_ATTR_DESC); - if (!ret) { - errno = ENOMEM; - return NULL; - } - - /* Obtain the DOS attributes */ - if (!smbc_getatr(context, srv, CONST_DISCARD(char *, filename), - &mode, &size, - &create_time_ts, - &access_time_ts, - &write_time_ts, - &change_time_ts, - &inode)) { - errno = smbc_errno(context, srv->cli); - DEBUG(5, ("dos_attr_query Failed to query old attributes\n")); - return NULL; - } - - ret->mode = mode; - ret->size = size; - ret->create_time = convert_timespec_to_time_t(create_time_ts); - ret->access_time = convert_timespec_to_time_t(access_time_ts); - ret->write_time = convert_timespec_to_time_t(write_time_ts); - ret->change_time = convert_timespec_to_time_t(change_time_ts); - ret->inode = inode; - - return ret; -} - - -/* parse a ascii version of a security descriptor */ -static void -dos_attr_parse(SMBCCTX *context, - DOS_ATTR_DESC *dad, - SMBCSRV *srv, - char *str) -{ - int n; - const char *p = str; - char *tok = NULL; - TALLOC_CTX *frame = NULL; - struct { - const char * create_time_attr; - const char * access_time_attr; - const char * write_time_attr; - const char * change_time_attr; - } attr_strings; - - /* Determine whether to use old-style or new-style attribute names */ - if (context->internal->_full_time_names) { - /* new-style names */ - attr_strings.create_time_attr = "CREATE_TIME"; - attr_strings.access_time_attr = "ACCESS_TIME"; - attr_strings.write_time_attr = "WRITE_TIME"; - attr_strings.change_time_attr = "CHANGE_TIME"; - } else { - /* old-style names */ - attr_strings.create_time_attr = NULL; - attr_strings.access_time_attr = "A_TIME"; - attr_strings.write_time_attr = "M_TIME"; - attr_strings.change_time_attr = "C_TIME"; - } - - /* if this is to set the entire ACL... */ - if (*str == '*') { - /* ... then increment past the first colon if there is one */ - if ((p = strchr(str, ':')) != NULL) { - ++p; - } else { - p = str; - } - } - - frame = talloc_stackframe(); - while (next_token_talloc(frame, &p, &tok, "\t,\r\n")) { - if (StrnCaseCmp(tok, "MODE:", 5) == 0) { - 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; - } - - if (StrnCaseCmp(tok, "SIZE:", 5) == 0) { - dad->size = (SMB_OFF_T)atof(tok+5); - continue; - } - - n = strlen(attr_strings.access_time_attr); - if (StrnCaseCmp(tok, attr_strings.access_time_attr, n) == 0) { - dad->access_time = (time_t)strtol(tok+n+1, NULL, 10); - continue; - } - - n = strlen(attr_strings.change_time_attr); - if (StrnCaseCmp(tok, attr_strings.change_time_attr, n) == 0) { - dad->change_time = (time_t)strtol(tok+n+1, NULL, 10); - continue; - } - - n = strlen(attr_strings.write_time_attr); - if (StrnCaseCmp(tok, attr_strings.write_time_attr, n) == 0) { - dad->write_time = (time_t)strtol(tok+n+1, NULL, 10); - continue; - } - - if (attr_strings.create_time_attr != NULL) { - n = strlen(attr_strings.create_time_attr); - if (StrnCaseCmp(tok, attr_strings.create_time_attr, - n) == 0) { - dad->create_time = (time_t)strtol(tok+n+1, - NULL, 10); - continue; - } - } - - if (StrnCaseCmp(tok, "INODE:", 6) == 0) { - dad->inode = (SMB_INO_T)atof(tok+6); - continue; - } - } - TALLOC_FREE(frame); -} - -/***************************************************** - Retrieve the acls for a file. -*******************************************************/ - -static int -cacl_get(SMBCCTX *context, - TALLOC_CTX *ctx, - SMBCSRV *srv, - struct cli_state *ipc_cli, - POLICY_HND *pol, - char *filename, - char *attr_name, - char *buf, - int bufsize) -{ - uint32 i; - int n = 0; - int n_used; - bool all; - bool all_nt; - bool all_nt_acls; - bool all_dos; - bool some_nt; - bool some_dos; - bool exclude_nt_revision = False; - bool exclude_nt_owner = False; - bool exclude_nt_group = False; - bool exclude_nt_acl = False; - bool exclude_dos_mode = False; - bool exclude_dos_size = False; - bool exclude_dos_create_time = False; - bool exclude_dos_access_time = False; - bool exclude_dos_write_time = False; - bool exclude_dos_change_time = False; - bool exclude_dos_inode = False; - bool numeric = True; - bool determine_size = (bufsize == 0); - int fnum = -1; - SEC_DESC *sd; - fstring sidstr; - fstring name_sandbox; - char *name; - char *pExclude; - char *p; - struct timespec create_time_ts; - struct timespec write_time_ts; - struct timespec access_time_ts; - struct timespec change_time_ts; - time_t create_time = (time_t)0; - time_t write_time = (time_t)0; - time_t access_time = (time_t)0; - time_t change_time = (time_t)0; - SMB_OFF_T size = 0; - uint16 mode = 0; - SMB_INO_T ino = 0; - struct cli_state *cli = srv->cli; - struct { - const char * create_time_attr; - const char * access_time_attr; - const char * write_time_attr; - const char * change_time_attr; - } attr_strings; - struct { - const char * create_time_attr; - const char * access_time_attr; - const char * write_time_attr; - const char * change_time_attr; - } excl_attr_strings; - - /* Determine whether to use old-style or new-style attribute names */ - if (context->internal->_full_time_names) { - /* new-style names */ - attr_strings.create_time_attr = "CREATE_TIME"; - attr_strings.access_time_attr = "ACCESS_TIME"; - attr_strings.write_time_attr = "WRITE_TIME"; - attr_strings.change_time_attr = "CHANGE_TIME"; - - excl_attr_strings.create_time_attr = "CREATE_TIME"; - excl_attr_strings.access_time_attr = "ACCESS_TIME"; - excl_attr_strings.write_time_attr = "WRITE_TIME"; - excl_attr_strings.change_time_attr = "CHANGE_TIME"; - } else { - /* old-style names */ - attr_strings.create_time_attr = NULL; - attr_strings.access_time_attr = "A_TIME"; - attr_strings.write_time_attr = "M_TIME"; - attr_strings.change_time_attr = "C_TIME"; - - excl_attr_strings.create_time_attr = NULL; - excl_attr_strings.access_time_attr = "dos_attr.A_TIME"; - excl_attr_strings.write_time_attr = "dos_attr.M_TIME"; - excl_attr_strings.change_time_attr = "dos_attr.C_TIME"; - } - - /* Copy name so we can strip off exclusions (if any are specified) */ - strncpy(name_sandbox, attr_name, sizeof(name_sandbox) - 1); - - /* Ensure name is null terminated */ - name_sandbox[sizeof(name_sandbox) - 1] = '\0'; - - /* Play in the sandbox */ - name = name_sandbox; - - /* If there are any exclusions, point to them and mask them from name */ - if ((pExclude = strchr(name, '!')) != NULL) - { - *pExclude++ = '\0'; - } - - all = (StrnCaseCmp(name, "system.*", 8) == 0); - all_nt = (StrnCaseCmp(name, "system.nt_sec_desc.*", 20) == 0); - all_nt_acls = (StrnCaseCmp(name, "system.nt_sec_desc.acl.*", 24) == 0); - all_dos = (StrnCaseCmp(name, "system.dos_attr.*", 17) == 0); - some_nt = (StrnCaseCmp(name, "system.nt_sec_desc.", 19) == 0); - some_dos = (StrnCaseCmp(name, "system.dos_attr.", 16) == 0); - numeric = (* (name + strlen(name) - 1) != '+'); - - /* Look for exclusions from "all" requests */ - if (all || all_nt || all_dos) { - - /* Exclusions are delimited by '!' */ - for (; - pExclude != NULL; - pExclude = (p == NULL ? NULL : p + 1)) { - - /* Find end of this exclusion name */ - if ((p = strchr(pExclude, '!')) != NULL) - { - *p = '\0'; - } - - /* Which exclusion name is this? */ - if (StrCaseCmp(pExclude, "nt_sec_desc.revision") == 0) { - exclude_nt_revision = True; - } - else if (StrCaseCmp(pExclude, "nt_sec_desc.owner") == 0) { - exclude_nt_owner = True; - } - else if (StrCaseCmp(pExclude, "nt_sec_desc.group") == 0) { - exclude_nt_group = True; - } - else if (StrCaseCmp(pExclude, "nt_sec_desc.acl") == 0) { - exclude_nt_acl = True; - } - else if (StrCaseCmp(pExclude, "dos_attr.mode") == 0) { - exclude_dos_mode = True; - } - else if (StrCaseCmp(pExclude, "dos_attr.size") == 0) { - exclude_dos_size = True; - } - else if (excl_attr_strings.create_time_attr != NULL && - StrCaseCmp(pExclude, - excl_attr_strings.change_time_attr) == 0) { - exclude_dos_create_time = True; - } - else if (StrCaseCmp(pExclude, - excl_attr_strings.access_time_attr) == 0) { - exclude_dos_access_time = True; - } - else if (StrCaseCmp(pExclude, - excl_attr_strings.write_time_attr) == 0) { - exclude_dos_write_time = True; - } - else if (StrCaseCmp(pExclude, - excl_attr_strings.change_time_attr) == 0) { - exclude_dos_change_time = True; - } - else if (StrCaseCmp(pExclude, "dos_attr.inode") == 0) { - exclude_dos_inode = True; - } - else { - DEBUG(5, ("cacl_get received unknown exclusion: %s\n", - pExclude)); - errno = ENOATTR; - return -1; - } - } - } - - n_used = 0; - - /* - * If we are (possibly) talking to an NT or new system and some NT - * attributes have been requested... - */ - if (ipc_cli && (all || some_nt || all_nt_acls)) { - /* Point to the portion after "system.nt_sec_desc." */ - name += 19; /* if (all) this will be invalid but unused */ - - /* ... then obtain any NT attributes which were requested */ - fnum = cli_nt_create(cli, filename, CREATE_ACCESS_READ); - - if (fnum == -1) { - DEBUG(5, ("cacl_get failed to open %s: %s\n", - filename, cli_errstr(cli))); - errno = 0; - return -1; - } - - sd = cli_query_secdesc(cli, fnum, ctx); - - if (!sd) { - DEBUG(5, - ("cacl_get Failed to query old descriptor\n")); - errno = 0; - return -1; - } - - cli_close(cli, fnum); - - if (! exclude_nt_revision) { - if (all || all_nt) { - if (determine_size) { - p = talloc_asprintf(ctx, - "REVISION:%d", - sd->revision); - if (!p) { - errno = ENOMEM; - return -1; - } - n = strlen(p); - } else { - n = snprintf(buf, bufsize, - "REVISION:%d", - sd->revision); - } - } else if (StrCaseCmp(name, "revision") == 0) { - if (determine_size) { - p = talloc_asprintf(ctx, "%d", - sd->revision); - if (!p) { - errno = ENOMEM; - return -1; - } - n = strlen(p); - } else { - n = snprintf(buf, bufsize, "%d", - sd->revision); - } - } - - if (!determine_size && n > bufsize) { - errno = ERANGE; - return -1; - } - buf += n; - n_used += n; - bufsize -= n; - n = 0; - } - - if (! exclude_nt_owner) { - /* Get owner and group sid */ - if (sd->owner_sid) { - convert_sid_to_string(ipc_cli, pol, - sidstr, - numeric, - sd->owner_sid); - } else { - fstrcpy(sidstr, ""); - } - - if (all || all_nt) { - if (determine_size) { - p = talloc_asprintf(ctx, ",OWNER:%s", - sidstr); - if (!p) { - errno = ENOMEM; - return -1; - } - n = strlen(p); - } else if (sidstr[0] != '\0') { - n = snprintf(buf, bufsize, - ",OWNER:%s", sidstr); - } - } else if (StrnCaseCmp(name, "owner", 5) == 0) { - if (determine_size) { - p = talloc_asprintf(ctx, "%s", sidstr); - if (!p) { - errno = ENOMEM; - return -1; - } - n = strlen(p); - } else { - n = snprintf(buf, bufsize, "%s", - sidstr); - } - } - - if (!determine_size && n > bufsize) { - errno = ERANGE; - return -1; - } - buf += n; - n_used += n; - bufsize -= n; - n = 0; - } - - if (! exclude_nt_group) { - if (sd->group_sid) { - convert_sid_to_string(ipc_cli, pol, - sidstr, numeric, - sd->group_sid); - } else { - fstrcpy(sidstr, ""); - } - - if (all || all_nt) { - if (determine_size) { - p = talloc_asprintf(ctx, ",GROUP:%s", - sidstr); - if (!p) { - errno = ENOMEM; - return -1; - } - n = strlen(p); - } else if (sidstr[0] != '\0') { - n = snprintf(buf, bufsize, - ",GROUP:%s", sidstr); - } - } else if (StrnCaseCmp(name, "group", 5) == 0) { - if (determine_size) { - p = talloc_asprintf(ctx, "%s", sidstr); - if (!p) { - errno = ENOMEM; - return -1; - } - n = strlen(p); - } else { - n = snprintf(buf, bufsize, - "%s", sidstr); - } - } - - if (!determine_size && n > bufsize) { - errno = ERANGE; - return -1; - } - buf += n; - n_used += n; - bufsize -= n; - n = 0; - } - - if (! exclude_nt_acl) { - /* Add aces to value buffer */ - for (i = 0; sd->dacl && i < sd->dacl->num_aces; i++) { - - SEC_ACE *ace = &sd->dacl->aces[i]; - convert_sid_to_string(ipc_cli, pol, - sidstr, numeric, - &ace->trustee); - - if (all || all_nt) { - if (determine_size) { - p = talloc_asprintf( - ctx, - ",ACL:" - "%s:%d/%d/0x%08x", - sidstr, - ace->type, - ace->flags, - ace->access_mask); - if (!p) { - errno = ENOMEM; - return -1; - } - n = strlen(p); - } else { - n = snprintf( - buf, bufsize, - ",ACL:%s:%d/%d/0x%08x", - sidstr, - ace->type, - ace->flags, - ace->access_mask); - } - } else if ((StrnCaseCmp(name, "acl", 3) == 0 && - StrCaseCmp(name+3, sidstr) == 0) || - (StrnCaseCmp(name, "acl+", 4) == 0 && - StrCaseCmp(name+4, sidstr) == 0)) { - if (determine_size) { - p = talloc_asprintf( - ctx, - "%d/%d/0x%08x", - ace->type, - ace->flags, - ace->access_mask); - if (!p) { - errno = ENOMEM; - return -1; - } - n = strlen(p); - } else { - n = snprintf(buf, bufsize, - "%d/%d/0x%08x", - ace->type, - ace->flags, - ace->access_mask); - } - } else if (all_nt_acls) { - if (determine_size) { - p = talloc_asprintf( - ctx, - "%s%s:%d/%d/0x%08x", - i ? "," : "", - sidstr, - ace->type, - ace->flags, - ace->access_mask); - if (!p) { - errno = ENOMEM; - return -1; - } - n = strlen(p); - } else { - n = snprintf(buf, bufsize, - "%s%s:%d/%d/0x%08x", - i ? "," : "", - sidstr, - ace->type, - ace->flags, - ace->access_mask); - } - } - if (!determine_size && n > bufsize) { - errno = ERANGE; - return -1; - } - buf += n; - n_used += n; - bufsize -= n; - n = 0; - } - } - - /* Restore name pointer to its original value */ - name -= 19; - } - - if (all || some_dos) { - /* Point to the portion after "system.dos_attr." */ - name += 16; /* if (all) this will be invalid but unused */ - - /* Obtain the DOS attributes */ - if (!smbc_getatr(context, srv, filename, &mode, &size, - &create_time_ts, - &access_time_ts, - &write_time_ts, - &change_time_ts, - &ino)) { - - errno = smbc_errno(context, srv->cli); - return -1; - - } - - create_time = convert_timespec_to_time_t(create_time_ts); - access_time = convert_timespec_to_time_t(access_time_ts); - write_time = convert_timespec_to_time_t(write_time_ts); - change_time = convert_timespec_to_time_t(change_time_ts); - - if (! exclude_dos_mode) { - if (all || all_dos) { - if (determine_size) { - p = talloc_asprintf(ctx, - "%sMODE:0x%x", - (ipc_cli && - (all || some_nt) - ? "," - : ""), - mode); - if (!p) { - errno = ENOMEM; - return -1; - } - n = strlen(p); - } else { - n = snprintf(buf, bufsize, - "%sMODE:0x%x", - (ipc_cli && - (all || some_nt) - ? "," - : ""), - mode); - } - } else if (StrCaseCmp(name, "mode") == 0) { - if (determine_size) { - p = talloc_asprintf(ctx, "0x%x", mode); - if (!p) { - errno = ENOMEM; - return -1; - } - n = strlen(p); - } else { - n = snprintf(buf, bufsize, - "0x%x", mode); - } - } - - if (!determine_size && n > bufsize) { - errno = ERANGE; - return -1; - } - buf += n; - n_used += n; - bufsize -= n; - n = 0; - } - - if (! exclude_dos_size) { - if (all || all_dos) { - if (determine_size) { - p = talloc_asprintf( - ctx, - ",SIZE:%.0f", - (double)size); - if (!p) { - errno = ENOMEM; - return -1; - } - n = strlen(p); - } else { - n = snprintf(buf, bufsize, - ",SIZE:%.0f", - (double)size); - } - } else if (StrCaseCmp(name, "size") == 0) { - if (determine_size) { - p = talloc_asprintf( - ctx, - "%.0f", - (double)size); - if (!p) { - errno = ENOMEM; - return -1; - } - n = strlen(p); - } else { - n = snprintf(buf, bufsize, - "%.0f", - (double)size); - } - } - - if (!determine_size && n > bufsize) { - errno = ERANGE; - return -1; - } - buf += n; - n_used += n; - bufsize -= n; - n = 0; - } - - if (! exclude_dos_create_time && - attr_strings.create_time_attr != NULL) { - if (all || all_dos) { - if (determine_size) { - p = talloc_asprintf(ctx, - ",%s:%lu", - attr_strings.create_time_attr, - create_time); - if (!p) { - errno = ENOMEM; - return -1; - } - n = strlen(p); - } else { - n = snprintf(buf, bufsize, - ",%s:%lu", - attr_strings.create_time_attr, - create_time); - } - } else if (StrCaseCmp(name, attr_strings.create_time_attr) == 0) { - if (determine_size) { - p = talloc_asprintf(ctx, "%lu", create_time); - if (!p) { - errno = ENOMEM; - return -1; - } - n = strlen(p); - } else { - n = snprintf(buf, bufsize, - "%lu", create_time); - } - } - - if (!determine_size && n > bufsize) { - errno = ERANGE; - return -1; - } - buf += n; - n_used += n; - bufsize -= n; - n = 0; - } - - if (! exclude_dos_access_time) { - if (all || all_dos) { - if (determine_size) { - p = talloc_asprintf(ctx, - ",%s:%lu", - attr_strings.access_time_attr, - access_time); - if (!p) { - errno = ENOMEM; - return -1; - } - n = strlen(p); - } else { - n = snprintf(buf, bufsize, - ",%s:%lu", - attr_strings.access_time_attr, - access_time); - } - } else if (StrCaseCmp(name, attr_strings.access_time_attr) == 0) { - if (determine_size) { - p = talloc_asprintf(ctx, "%lu", access_time); - if (!p) { - errno = ENOMEM; - return -1; - } - n = strlen(p); - } else { - n = snprintf(buf, bufsize, - "%lu", access_time); - } - } - - if (!determine_size && n > bufsize) { - errno = ERANGE; - return -1; - } - buf += n; - n_used += n; - bufsize -= n; - n = 0; - } - - if (! exclude_dos_write_time) { - if (all || all_dos) { - if (determine_size) { - p = talloc_asprintf(ctx, - ",%s:%lu", - attr_strings.write_time_attr, - write_time); - if (!p) { - errno = ENOMEM; - return -1; - } - n = strlen(p); - } else { - n = snprintf(buf, bufsize, - ",%s:%lu", - attr_strings.write_time_attr, - write_time); - } - } else if (StrCaseCmp(name, attr_strings.write_time_attr) == 0) { - if (determine_size) { - p = talloc_asprintf(ctx, "%lu", write_time); - if (!p) { - errno = ENOMEM; - return -1; - } - n = strlen(p); - } else { - n = snprintf(buf, bufsize, - "%lu", write_time); - } - } - - if (!determine_size && n > bufsize) { - errno = ERANGE; - return -1; - } - buf += n; - n_used += n; - bufsize -= n; - n = 0; - } - - if (! exclude_dos_change_time) { - if (all || all_dos) { - if (determine_size) { - p = talloc_asprintf(ctx, - ",%s:%lu", - attr_strings.change_time_attr, - change_time); - if (!p) { - errno = ENOMEM; - return -1; - } - n = strlen(p); - } else { - n = snprintf(buf, bufsize, - ",%s:%lu", - attr_strings.change_time_attr, - change_time); - } - } else if (StrCaseCmp(name, attr_strings.change_time_attr) == 0) { - if (determine_size) { - p = talloc_asprintf(ctx, "%lu", change_time); - if (!p) { - errno = ENOMEM; - return -1; - } - n = strlen(p); - } else { - n = snprintf(buf, bufsize, - "%lu", change_time); - } - } - - if (!determine_size && n > bufsize) { - errno = ERANGE; - return -1; - } - buf += n; - n_used += n; - bufsize -= n; - n = 0; - } - - if (! exclude_dos_inode) { - if (all || all_dos) { - if (determine_size) { - p = talloc_asprintf( - ctx, - ",INODE:%.0f", - (double)ino); - if (!p) { - errno = ENOMEM; - return -1; - } - n = strlen(p); - } else { - n = snprintf(buf, bufsize, - ",INODE:%.0f", - (double) ino); - } - } else if (StrCaseCmp(name, "inode") == 0) { - if (determine_size) { - p = talloc_asprintf( - ctx, - "%.0f", - (double) ino); - if (!p) { - errno = ENOMEM; - return -1; - } - n = strlen(p); - } else { - n = snprintf(buf, bufsize, - "%.0f", - (double) ino); - } - } - - if (!determine_size && n > bufsize) { - errno = ERANGE; - return -1; - } - buf += n; - n_used += n; - bufsize -= n; - n = 0; - } - - /* Restore name pointer to its original value */ - name -= 16; - } - - if (n_used == 0) { - errno = ENOATTR; - return -1; - } - - return n_used; -} - -/***************************************************** -set the ACLs on a file given an ascii description -*******************************************************/ -static int -cacl_set(TALLOC_CTX *ctx, - struct cli_state *cli, - struct cli_state *ipc_cli, - POLICY_HND *pol, - const char *filename, - const char *the_acl, - int mode, - int flags) -{ - int fnum; - int err = 0; - SEC_DESC *sd = NULL, *old; - SEC_ACL *dacl = NULL; - DOM_SID *owner_sid = NULL; - DOM_SID *group_sid = NULL; - uint32 i, j; - size_t sd_size; - int ret = 0; - char *p; - bool numeric = True; - - /* the_acl will be null for REMOVE_ALL operations */ - if (the_acl) { - numeric = ((p = strchr(the_acl, ':')) != NULL && - p > the_acl && - p[-1] != '+'); - - /* if this is to set the entire ACL... */ - if (*the_acl == '*') { - /* ... then increment past the first colon */ - the_acl = p + 1; - } - - sd = sec_desc_parse(ctx, ipc_cli, pol, numeric, - CONST_DISCARD(char *, the_acl)); - - if (!sd) { - errno = EINVAL; - return -1; - } - } - - /* SMBC_XATTR_MODE_REMOVE_ALL is the only caller - that doesn't deref sd */ - - if (!sd && (mode != SMBC_XATTR_MODE_REMOVE_ALL)) { - errno = EINVAL; - return -1; - } - - /* The desired access below is the only one I could find that works - with NT4, W2KP and Samba */ - - fnum = cli_nt_create(cli, filename, CREATE_ACCESS_READ); - - if (fnum == -1) { - DEBUG(5, ("cacl_set failed to open %s: %s\n", - filename, cli_errstr(cli))); - errno = 0; - return -1; - } - - old = cli_query_secdesc(cli, fnum, ctx); - - if (!old) { - DEBUG(5, ("cacl_set Failed to query old descriptor\n")); - errno = 0; - return -1; - } - - cli_close(cli, fnum); - - switch (mode) { - case SMBC_XATTR_MODE_REMOVE_ALL: - old->dacl->num_aces = 0; - dacl = old->dacl; - break; - - case SMBC_XATTR_MODE_REMOVE: - for (i=0;sd->dacl && idacl->num_aces;i++) { - bool found = False; - - for (j=0;old->dacl && jdacl->num_aces;j++) { - if (sec_ace_equal(&sd->dacl->aces[i], - &old->dacl->aces[j])) { - uint32 k; - for (k=j; kdacl->num_aces-1;k++) { - old->dacl->aces[k] = - old->dacl->aces[k+1]; - } - old->dacl->num_aces--; - found = True; - dacl = old->dacl; - break; - } - } - - if (!found) { - err = ENOATTR; - ret = -1; - goto failed; - } - } - break; - - case SMBC_XATTR_MODE_ADD: - for (i=0;sd->dacl && idacl->num_aces;i++) { - bool found = False; - - for (j=0;old->dacl && jdacl->num_aces;j++) { - if (sid_equal(&sd->dacl->aces[i].trustee, - &old->dacl->aces[j].trustee)) { - if (!(flags & SMBC_XATTR_FLAG_CREATE)) { - err = EEXIST; - ret = -1; - goto failed; - } - old->dacl->aces[j] = sd->dacl->aces[i]; - ret = -1; - found = True; - } - } - - if (!found && (flags & SMBC_XATTR_FLAG_REPLACE)) { - err = ENOATTR; - ret = -1; - goto failed; - } - - for (i=0;sd->dacl && idacl->num_aces;i++) { - add_ace(&old->dacl, &sd->dacl->aces[i], ctx); - } - } - dacl = old->dacl; - break; - - case SMBC_XATTR_MODE_SET: - old = sd; - owner_sid = old->owner_sid; - group_sid = old->group_sid; - dacl = old->dacl; - break; - - case SMBC_XATTR_MODE_CHOWN: - owner_sid = sd->owner_sid; - break; - - case SMBC_XATTR_MODE_CHGRP: - group_sid = sd->group_sid; - break; - } - - /* Denied ACE entries must come before allowed ones */ - sort_acl(old->dacl); - - /* Create new security descriptor and set it */ - sd = make_sec_desc(ctx, old->revision, SEC_DESC_SELF_RELATIVE, - owner_sid, group_sid, NULL, dacl, &sd_size); - - fnum = cli_nt_create(cli, filename, - WRITE_DAC_ACCESS | WRITE_OWNER_ACCESS); - - if (fnum == -1) { - DEBUG(5, ("cacl_set failed to open %s: %s\n", - filename, cli_errstr(cli))); - errno = 0; - return -1; - } - - if (!cli_set_secdesc(cli, fnum, sd)) { - DEBUG(5, ("ERROR: secdesc set failed: %s\n", cli_errstr(cli))); - ret = -1; - } - - /* Clean up */ - - failed: - cli_close(cli, fnum); - - if (err != 0) { - errno = err; - } - - return ret; -} - - -static int -smbc_setxattr_ctx(SMBCCTX *context, - const char *fname, - const char *name, - const void *value, - size_t size, - int flags) -{ - int ret; - int ret2; - 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; - const char * write_time_attr; - const char * change_time_attr; - } attr_strings; - TALLOC_CTX *frame = talloc_stackframe(); - - if (!context || !context->internal || - !context->internal->_initialized) { - errno = EINVAL; /* Best I can think of ... */ - TALLOC_FREE(frame); - return -1; - } - - if (!fname) { - errno = EINVAL; - TALLOC_FREE(frame); - return -1; - } - - DEBUG(4, ("smbc_setxattr(%s, %s, %.*s)\n", - fname, name, (int) size, (const char*)value)); - - if (smbc_parse_path(frame, - context, - fname, - &workgroup, - &server, - &share, - &path, - &user, - &password, - NULL)) { - errno = EINVAL; - TALLOC_FREE(frame); - return -1; - } - - if (!user || user[0] == (char)0) { - user = talloc_strdup(frame, context->user); - if (!user) { - errno = ENOMEM; - TALLOC_FREE(frame); - return -1; - } - } - - 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(frame, context, server, share, - &workgroup, &user, &password); - if (! ipc_srv) { - srv->no_nt_session = True; - } - } else { - ipc_srv = NULL; - } - - /* - * Are they asking to set the entire set of known attributes? - */ - if (StrCaseCmp(name, "system.*") == 0 || - StrCaseCmp(name, "system.*+") == 0) { - /* Yup. */ - char *namevalue = - talloc_asprintf(talloc_tos(), "%s:%s", - name+7, (const char *) value); - if (! namevalue) { - errno = ENOMEM; - ret = -1; - TALLOC_FREE(frame); - return -1; - } - - if (ipc_srv) { - ret = cacl_set(talloc_tos(), srv->cli, - ipc_srv->cli, &ipc_srv->pol, path, - namevalue, - (*namevalue == '*' - ? SMBC_XATTR_MODE_SET - : SMBC_XATTR_MODE_ADD), - flags); - } else { - ret = 0; - } - - /* get a DOS Attribute Descriptor with current attributes */ - dad = dos_attr_query(context, talloc_tos(), path, srv); - if (dad) { - /* Overwrite old with new, using what was provided */ - dos_attr_parse(context, dad, srv, namevalue); - - /* Set the new DOS attributes */ - if (! smbc_setatr(context, srv, path, - dad->create_time, - dad->access_time, - dad->write_time, - dad->change_time, - dad->mode)) { - - /* cause failure if NT failed too */ - dad = NULL; - } - } - - /* we only fail if both NT and DOS sets failed */ - if (ret < 0 && ! dad) { - ret = -1; /* in case dad was null */ - } - else { - ret = 0; - } - - TALLOC_FREE(frame); - return ret; - } - - /* - * Are they asking to set an access control element or to set - * the entire access control list? - */ - if (StrCaseCmp(name, "system.nt_sec_desc.*") == 0 || - StrCaseCmp(name, "system.nt_sec_desc.*+") == 0 || - StrCaseCmp(name, "system.nt_sec_desc.revision") == 0 || - StrnCaseCmp(name, "system.nt_sec_desc.acl", 22) == 0 || - StrnCaseCmp(name, "system.nt_sec_desc.acl+", 23) == 0) { - - /* Yup. */ - char *namevalue = - talloc_asprintf(talloc_tos(), "%s:%s", - name+19, (const char *) value); - - if (! ipc_srv) { - ret = -1; /* errno set by smbc_server() */ - } - else if (! namevalue) { - errno = ENOMEM; - ret = -1; - } else { - ret = cacl_set(talloc_tos(), srv->cli, - ipc_srv->cli, &ipc_srv->pol, path, - namevalue, - (*namevalue == '*' - ? SMBC_XATTR_MODE_SET - : SMBC_XATTR_MODE_ADD), - flags); - } - TALLOC_FREE(frame); - return ret; - } - - /* - * Are they asking to set the owner? - */ - if (StrCaseCmp(name, "system.nt_sec_desc.owner") == 0 || - StrCaseCmp(name, "system.nt_sec_desc.owner+") == 0) { - - /* Yup. */ - char *namevalue = - talloc_asprintf(talloc_tos(), "%s:%s", - name+19, (const char *) value); - - if (! ipc_srv) { - ret = -1; /* errno set by smbc_server() */ - } - else if (! namevalue) { - errno = ENOMEM; - ret = -1; - } else { - ret = cacl_set(talloc_tos(), srv->cli, - ipc_srv->cli, &ipc_srv->pol, path, - namevalue, SMBC_XATTR_MODE_CHOWN, 0); - } - TALLOC_FREE(frame); - return ret; - } - - /* - * Are they asking to set the group? - */ - if (StrCaseCmp(name, "system.nt_sec_desc.group") == 0 || - StrCaseCmp(name, "system.nt_sec_desc.group+") == 0) { - - /* Yup. */ - char *namevalue = - talloc_asprintf(talloc_tos(), "%s:%s", - name+19, (const char *) value); - - if (! ipc_srv) { - /* errno set by smbc_server() */ - ret = -1; - } - else if (! namevalue) { - errno = ENOMEM; - ret = -1; - } else { - ret = cacl_set(talloc_tos(), srv->cli, - ipc_srv->cli, &ipc_srv->pol, path, - namevalue, SMBC_XATTR_MODE_CHGRP, 0); - } - TALLOC_FREE(frame); - return ret; - } - - /* Determine whether to use old-style or new-style attribute names */ - if (context->internal->_full_time_names) { - /* new-style names */ - attr_strings.create_time_attr = "system.dos_attr.CREATE_TIME"; - attr_strings.access_time_attr = "system.dos_attr.ACCESS_TIME"; - attr_strings.write_time_attr = "system.dos_attr.WRITE_TIME"; - attr_strings.change_time_attr = "system.dos_attr.CHANGE_TIME"; - } else { - /* old-style names */ - attr_strings.create_time_attr = NULL; - attr_strings.access_time_attr = "system.dos_attr.A_TIME"; - attr_strings.write_time_attr = "system.dos_attr.M_TIME"; - attr_strings.change_time_attr = "system.dos_attr.C_TIME"; - } - - /* - * Are they asking to set a DOS attribute? - */ - if (StrCaseCmp(name, "system.dos_attr.*") == 0 || - StrCaseCmp(name, "system.dos_attr.mode") == 0 || - (attr_strings.create_time_attr != NULL && - StrCaseCmp(name, attr_strings.create_time_attr) == 0) || - StrCaseCmp(name, attr_strings.access_time_attr) == 0 || - StrCaseCmp(name, attr_strings.write_time_attr) == 0 || - StrCaseCmp(name, attr_strings.change_time_attr) == 0) { - - /* get a DOS Attribute Descriptor with current attributes */ - dad = dos_attr_query(context, talloc_tos(), path, srv); - if (dad) { - char *namevalue = - talloc_asprintf(talloc_tos(), "%s:%s", - name+16, (const char *) value); - if (! namevalue) { - errno = ENOMEM; - ret = -1; - } else { - /* Overwrite old with provided new params */ - dos_attr_parse(context, dad, srv, namevalue); - - /* Set the new DOS attributes */ - ret2 = smbc_setatr(context, srv, path, - dad->create_time, - dad->access_time, - dad->write_time, - dad->change_time, - dad->mode); - - /* ret2 has True (success) / False (failure) */ - if (ret2) { - ret = 0; - } else { - ret = -1; - } - } - } else { - ret = -1; - } - - TALLOC_FREE(frame); - return ret; - } - - /* Unsupported attribute name */ - errno = EINVAL; - TALLOC_FREE(frame); - return -1; -} - -static int -smbc_getxattr_ctx(SMBCCTX *context, - const char *fname, - const char *name, - const void *value, - size_t size) -{ - int ret; - 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; - const char * write_time_attr; - const char * change_time_attr; - } attr_strings; - TALLOC_CTX *frame = talloc_stackframe(); - - if (!context || !context->internal || - !context->internal->_initialized) { - errno = EINVAL; /* Best I can think of ... */ - TALLOC_FREE(frame); - return -1; - } - - if (!fname) { - errno = EINVAL; - TALLOC_FREE(frame); - return -1; - } - - DEBUG(4, ("smbc_getxattr(%s, %s)\n", fname, name)); - - if (smbc_parse_path(frame, - context, - fname, - &workgroup, - &server, - &share, - &path, - &user, - &password, - NULL)) { - errno = EINVAL; - TALLOC_FREE(frame); - return -1; - } - - if (!user || user[0] == (char)0) { - user = talloc_strdup(frame, context->user); - if (!user) { - errno = ENOMEM; - TALLOC_FREE(frame); - return -1; - } - } - - 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(frame, context, server, share, - &workgroup, &user, &password); - if (! ipc_srv) { - srv->no_nt_session = True; - } - } else { - ipc_srv = NULL; - } - - /* Determine whether to use old-style or new-style attribute names */ - if (context->internal->_full_time_names) { - /* new-style names */ - attr_strings.create_time_attr = "system.dos_attr.CREATE_TIME"; - attr_strings.access_time_attr = "system.dos_attr.ACCESS_TIME"; - attr_strings.write_time_attr = "system.dos_attr.WRITE_TIME"; - attr_strings.change_time_attr = "system.dos_attr.CHANGE_TIME"; - } else { - /* old-style names */ - attr_strings.create_time_attr = NULL; - attr_strings.access_time_attr = "system.dos_attr.A_TIME"; - attr_strings.write_time_attr = "system.dos_attr.M_TIME"; - attr_strings.change_time_attr = "system.dos_attr.C_TIME"; - } - - /* Are they requesting a supported attribute? */ - if (StrCaseCmp(name, "system.*") == 0 || - StrnCaseCmp(name, "system.*!", 9) == 0 || - StrCaseCmp(name, "system.*+") == 0 || - StrnCaseCmp(name, "system.*+!", 10) == 0 || - StrCaseCmp(name, "system.nt_sec_desc.*") == 0 || - StrnCaseCmp(name, "system.nt_sec_desc.*!", 21) == 0 || - StrCaseCmp(name, "system.nt_sec_desc.*+") == 0 || - StrnCaseCmp(name, "system.nt_sec_desc.*+!", 22) == 0 || - StrCaseCmp(name, "system.nt_sec_desc.revision") == 0 || - StrCaseCmp(name, "system.nt_sec_desc.owner") == 0 || - StrCaseCmp(name, "system.nt_sec_desc.owner+") == 0 || - StrCaseCmp(name, "system.nt_sec_desc.group") == 0 || - StrCaseCmp(name, "system.nt_sec_desc.group+") == 0 || - StrnCaseCmp(name, "system.nt_sec_desc.acl", 22) == 0 || - StrnCaseCmp(name, "system.nt_sec_desc.acl+", 23) == 0 || - StrCaseCmp(name, "system.dos_attr.*") == 0 || - StrnCaseCmp(name, "system.dos_attr.*!", 18) == 0 || - StrCaseCmp(name, "system.dos_attr.mode") == 0 || - StrCaseCmp(name, "system.dos_attr.size") == 0 || - (attr_strings.create_time_attr != NULL && - StrCaseCmp(name, attr_strings.create_time_attr) == 0) || - StrCaseCmp(name, attr_strings.access_time_attr) == 0 || - StrCaseCmp(name, attr_strings.write_time_attr) == 0 || - StrCaseCmp(name, attr_strings.change_time_attr) == 0 || - StrCaseCmp(name, "system.dos_attr.inode") == 0) { - - /* Yup. */ - ret = cacl_get(context, talloc_tos(), srv, - ipc_srv == NULL ? NULL : ipc_srv->cli, - &ipc_srv->pol, path, - CONST_DISCARD(char *, name), - CONST_DISCARD(char *, value), size); - if (ret < 0 && errno == 0) { - errno = smbc_errno(context, srv->cli); - } - TALLOC_FREE(frame); - return ret; - } - - /* Unsupported attribute name */ - errno = EINVAL; - TALLOC_FREE(frame); - return -1; -} - - -static int -smbc_removexattr_ctx(SMBCCTX *context, - const char *fname, - const char *name) -{ - int ret; - 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 || - !context->internal->_initialized) { - errno = EINVAL; /* Best I can think of ... */ - TALLOC_FREE(frame); - return -1; - } - - if (!fname) { - errno = EINVAL; - TALLOC_FREE(frame); - return -1; - } - - DEBUG(4, ("smbc_removexattr(%s, %s)\n", fname, name)); - - if (smbc_parse_path(frame, - context, - fname, - &workgroup, - &server, - &share, - &path, - &user, - &password, - NULL)) { - errno = EINVAL; - TALLOC_FREE(frame); - return -1; - } - - if (!user || user[0] == (char)0) { - user = talloc_strdup(frame, context->user); - if (!user) { - errno = ENOMEM; - TALLOC_FREE(frame); - return -1; - } - } - - 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(frame, context, server, share, - &workgroup, &user, &password); - if (! ipc_srv) { - srv->no_nt_session = True; - } - } else { - ipc_srv = NULL; - } - - if (! ipc_srv) { - TALLOC_FREE(frame); - return -1; /* errno set by smbc_attr_server */ - } - - /* Are they asking to set the entire ACL? */ - if (StrCaseCmp(name, "system.nt_sec_desc.*") == 0 || - StrCaseCmp(name, "system.nt_sec_desc.*+") == 0) { - - /* Yup. */ - ret = cacl_set(talloc_tos(), srv->cli, - ipc_srv->cli, &ipc_srv->pol, path, - NULL, SMBC_XATTR_MODE_REMOVE_ALL, 0); - TALLOC_FREE(frame); - return ret; - } - - /* - * Are they asking to remove one or more spceific security descriptor - * attributes? - */ - if (StrCaseCmp(name, "system.nt_sec_desc.revision") == 0 || - StrCaseCmp(name, "system.nt_sec_desc.owner") == 0 || - StrCaseCmp(name, "system.nt_sec_desc.owner+") == 0 || - StrCaseCmp(name, "system.nt_sec_desc.group") == 0 || - StrCaseCmp(name, "system.nt_sec_desc.group+") == 0 || - StrnCaseCmp(name, "system.nt_sec_desc.acl", 22) == 0 || - StrnCaseCmp(name, "system.nt_sec_desc.acl+", 23) == 0) { - - /* Yup. */ - ret = cacl_set(talloc_tos(), srv->cli, - ipc_srv->cli, &ipc_srv->pol, path, - name + 19, SMBC_XATTR_MODE_REMOVE, 0); - TALLOC_FREE(frame); - return ret; - } - - /* Unsupported attribute name */ - errno = EINVAL; - TALLOC_FREE(frame); - return -1; -} - -static int -smbc_listxattr_ctx(SMBCCTX *context, - const char *fname, - char *list, - size_t size) -{ - /* - * This isn't quite what listxattr() is supposed to do. This returns - * 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" - "system.nt_sec_desc.revision\0" - "system.nt_sec_desc.owner\0" - "system.nt_sec_desc.owner+\0" - "system.nt_sec_desc.group\0" - "system.nt_sec_desc.group+\0" - "system.nt_sec_desc.acl.*\0" - "system.nt_sec_desc.acl\0" - "system.nt_sec_desc.acl+\0" - "system.nt_sec_desc.*\0" - "system.nt_sec_desc.*+\0" - "system.dos_attr.*\0" - "system.dos_attr.mode\0" - "system.dos_attr.c_time\0" - "system.dos_attr.a_time\0" - "system.dos_attr.m_time\0" - ; - const char supported_new[] = - "system.*\0" - "system.*+\0" - "system.nt_sec_desc.revision\0" - "system.nt_sec_desc.owner\0" - "system.nt_sec_desc.owner+\0" - "system.nt_sec_desc.group\0" - "system.nt_sec_desc.group+\0" - "system.nt_sec_desc.acl.*\0" - "system.nt_sec_desc.acl\0" - "system.nt_sec_desc.acl+\0" - "system.nt_sec_desc.*\0" - "system.nt_sec_desc.*+\0" - "system.dos_attr.*\0" - "system.dos_attr.mode\0" - "system.dos_attr.create_time\0" - "system.dos_attr.access_time\0" - "system.dos_attr.write_time\0" - "system.dos_attr.change_time\0" - ; - const char * supported; - - 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 retsize; - } - - if (retsize > size) { - errno = ERANGE; - return -1; - } - - /* this can't be strcpy() because there are embedded null characters */ - memcpy(list, supported, retsize); - return retsize; -} - - -/* - * Open a print file to be written to by other calls - */ - -static SMBCFILE * -smbc_open_print_job_ctx(SMBCCTX *context, - const char *fname) -{ - char *server = NULL; - char *share = NULL; - char *user = NULL; - char *password = NULL; - char *path = NULL; - TALLOC_CTX *frame = talloc_stackframe(); - - if (!context || !context->internal || - !context->internal->_initialized) { - errno = EINVAL; - TALLOC_FREE(frame); - return NULL; - } - - if (!fname) { - errno = EINVAL; - TALLOC_FREE(frame); - return NULL; - } - - DEBUG(4, ("smbc_open_print_job_ctx(%s)\n", fname)); - - if (smbc_parse_path(frame, - context, - fname, - NULL, - &server, - &share, - &path, - &user, - &password, - NULL)) { - errno = EINVAL; - TALLOC_FREE(frame); - return NULL; - } - - /* What if the path is empty, or the file exists? */ - - TALLOC_FREE(frame); - return (context->open)(context, fname, O_WRONLY, 666); -} - -/* - * Routine to print a file on a remote server ... - * - * We open the file, which we assume to be on a remote server, and then - * copy it to a print file on the share specified by printq. - */ - -static int -smbc_print_file_ctx(SMBCCTX *c_file, - const char *fname, - SMBCCTX *c_print, - const char *printq) -{ - SMBCFILE *fid1; - SMBCFILE *fid2; - int bytes; - int saverr; - int tot_bytes = 0; - char buf[4096]; - TALLOC_CTX *frame = talloc_stackframe(); - - if (!c_file || !c_file->internal->_initialized || !c_print || - !c_print->internal->_initialized) { - - errno = EINVAL; - TALLOC_FREE(frame); - return -1; - - } - - if (!fname && !printq) { - - errno = EINVAL; - TALLOC_FREE(frame); - return -1; - - } - - /* Try to open the file for reading ... */ - - if ((long)(fid1 = (c_file->open)(c_file, fname, O_RDONLY, 0666)) < 0) { - DEBUG(3, ("Error, fname=%s, errno=%i\n", fname, errno)); - TALLOC_FREE(frame); - return -1; /* smbc_open sets errno */ - } - - /* Now, try to open the printer file for writing */ - - if ((long)(fid2 = (c_print->open_print_job)(c_print, printq)) < 0) { - - saverr = errno; /* Save errno */ - (c_file->close_fn)(c_file, fid1); - errno = saverr; - TALLOC_FREE(frame); - return -1; - - } - - while ((bytes = (c_file->read)(c_file, fid1, buf, sizeof(buf))) > 0) { - - tot_bytes += bytes; - - if (((c_print->write)(c_print, fid2, buf, bytes)) < 0) { - - saverr = errno; - (c_file->close_fn)(c_file, fid1); - (c_print->close_fn)(c_print, fid2); - errno = saverr; - - } - - } - - saverr = errno; - - (c_file->close_fn)(c_file, fid1); /* We have to close these anyway */ - (c_print->close_fn)(c_print, fid2); - - if (bytes < 0) { - - errno = saverr; - TALLOC_FREE(frame); - return -1; - - } - - TALLOC_FREE(frame); - return tot_bytes; - -} - -/* - * Routine to list print jobs on a printer share ... - */ - -static int -smbc_list_print_jobs_ctx(SMBCCTX *context, - const char *fname, - smbc_list_print_job_fn fn) -{ - 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 || - !context->internal->_initialized) { - errno = EINVAL; - TALLOC_FREE(frame); - return -1; - } - - if (!fname) { - errno = EINVAL; - TALLOC_FREE(frame); - return -1; - } - - DEBUG(4, ("smbc_list_print_jobs(%s)\n", fname)); - - if (smbc_parse_path(frame, - context, - fname, - &workgroup, - &server, - &share, - &path, - &user, - &password, - NULL)) { - errno = EINVAL; - TALLOC_FREE(frame); - return -1; - } - - if (!user || user[0] == (char)0) { - user = talloc_strdup(frame, context->user); - if (!user) { - errno = ENOMEM; - TALLOC_FREE(frame); - return -1; - } - } - - srv = smbc_server(frame, context, True, - server, share, &workgroup, &user, &password); - - if (!srv) { - TALLOC_FREE(frame); - return -1; /* errno set by smbc_server */ - } - - if (cli_print_queue(srv->cli, - (void (*)(struct print_job_info *))fn) < 0) { - errno = smbc_errno(context, srv->cli); - TALLOC_FREE(frame); - return -1; - } - - TALLOC_FREE(frame); - return 0; - -} - -/* - * Delete a print job from a remote printer share - */ - -static int -smbc_unlink_print_job_ctx(SMBCCTX *context, - const char *fname, - int id) -{ - 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(); - - if (!context || !context->internal || - !context->internal->_initialized) { - errno = EINVAL; - TALLOC_FREE(frame); - return -1; - } - - if (!fname) { - errno = EINVAL; - TALLOC_FREE(frame); - return -1; - } - - DEBUG(4, ("smbc_unlink_print_job(%s)\n", fname)); - - if (smbc_parse_path(frame, - context, - fname, - &workgroup, - &server, - &share, - &path, - &user, - &password, - NULL)) { - errno = EINVAL; - TALLOC_FREE(frame); - return -1; - } - - if (!user || user[0] == (char)0) { - user = talloc_strdup(frame, context->user); - if (!user) { - errno = ENOMEM; - TALLOC_FREE(frame); - return -1; - } - } - - srv = smbc_server(frame, context, True, - server, share, &workgroup, &user, &password); - - if (!srv) { - - TALLOC_FREE(frame); - return -1; /* errno set by smbc_server */ - - } - - if ((err = cli_printjob_del(srv->cli, id)) != 0) { - - if (err < 0) - errno = smbc_errno(context, srv->cli); - else if (err == ERRnosuchprintjob) - errno = EINVAL; - TALLOC_FREE(frame); - return -1; - - } - - TALLOC_FREE(frame); - return 0; - -} - -/* - * Get a new empty handle to fill in with your own info - */ -SMBCCTX * -smbc_new_context(void) -{ - SMBCCTX *context; - - context = SMB_MALLOC_P(SMBCCTX); - if (!context) { - errno = ENOMEM; - return NULL; - } - - ZERO_STRUCTP(context); - - context->internal = SMB_MALLOC_P(struct smbc_internal_data); - if (!context->internal) { - SAFE_FREE(context); - errno = ENOMEM; - return NULL; - } - - ZERO_STRUCTP(context->internal); - - /* ADD REASONABLE DEFAULTS */ - context->debug = 0; - context->timeout = 20000; /* 20 seconds */ - - context->options.browse_max_lmb_count = 3; /* # LMBs to query */ - context->options.urlencode_readdir_entries = False;/* backward compat */ - context->options.one_share_per_server = False;/* backward compat */ - context->internal->_share_mode = SMBC_SHAREMODE_DENY_NONE; - /* backward compat */ - - context->open = smbc_open_ctx; - context->creat = smbc_creat_ctx; - context->read = smbc_read_ctx; - context->write = smbc_write_ctx; - context->close_fn = smbc_close_ctx; - context->unlink = smbc_unlink_ctx; - context->rename = smbc_rename_ctx; - context->lseek = smbc_lseek_ctx; - context->stat = smbc_stat_ctx; - context->fstat = smbc_fstat_ctx; - context->opendir = smbc_opendir_ctx; - context->closedir = smbc_closedir_ctx; - context->readdir = smbc_readdir_ctx; - context->getdents = smbc_getdents_ctx; - context->mkdir = smbc_mkdir_ctx; - context->rmdir = smbc_rmdir_ctx; - context->telldir = smbc_telldir_ctx; - context->lseekdir = smbc_lseekdir_ctx; - context->fstatdir = smbc_fstatdir_ctx; - context->ftruncate = smbc_ftruncate_ctx; - context->chmod = smbc_chmod_ctx; - context->utimes = smbc_utimes_ctx; - context->setxattr = smbc_setxattr_ctx; - context->getxattr = smbc_getxattr_ctx; - context->removexattr = smbc_removexattr_ctx; - context->listxattr = smbc_listxattr_ctx; - context->open_print_job = smbc_open_print_job_ctx; - context->print_file = smbc_print_file_ctx; - context->list_print_jobs = smbc_list_print_jobs_ctx; - context->unlink_print_job = smbc_unlink_print_job_ctx; - - context->callbacks.check_server_fn = smbc_check_server; - context->callbacks.remove_unused_server_fn = smbc_remove_unused_server; - - smbc_default_cache_functions(context); - - return context; -} - -/* - * Free a context - * - * Returns 0 on success. Otherwise returns 1, the SMBCCTX is _not_ freed - * and thus you'll be leaking memory if not handled properly. - * - */ -int -smbc_free_context(SMBCCTX *context, - int shutdown_ctx) -{ - if (!context) { - errno = EBADF; - return 1; - } - - if (shutdown_ctx) { - SMBCFILE * f; - DEBUG(1,("Performing aggressive shutdown.\n")); - - f = context->internal->_files; - while (f) { - (context->close_fn)(context, f); - f = f->next; - } - context->internal->_files = NULL; - - /* First try to remove the servers the nice way. */ - if (context->callbacks.purge_cached_fn(context)) { - SMBCSRV * s; - SMBCSRV * next; - DEBUG(1, ("Could not purge all servers, " - "Nice way shutdown failed.\n")); - s = context->internal->_servers; - while (s) { - DEBUG(1, ("Forced shutdown: %p (fd=%d)\n", - s, s->cli->fd)); - cli_shutdown(s->cli); - (context->callbacks.remove_cached_srv_fn)(context, - s); - next = s->next; - DLIST_REMOVE(context->internal->_servers, s); - SAFE_FREE(s); - s = next; - } - context->internal->_servers = NULL; - } - } - else { - /* This is the polite way */ - if ((context->callbacks.purge_cached_fn)(context)) { - DEBUG(1, ("Could not purge all servers, " - "free_context failed.\n")); - errno = EBUSY; - return 1; - } - if (context->internal->_servers) { - DEBUG(1, ("Active servers in context, " - "free_context failed.\n")); - errno = EBUSY; - return 1; - } - if (context->internal->_files) { - DEBUG(1, ("Active files in context, " - "free_context failed.\n")); - errno = EBUSY; - return 1; - } - } - - /* Things we have to clean up */ - SAFE_FREE(context->workgroup); - SAFE_FREE(context->netbios_name); - SAFE_FREE(context->user); - - DEBUG(3, ("Context %p successfully freed\n", context)); - SAFE_FREE(context->internal); - SAFE_FREE(context); - return 0; -} - - -/* - * Each time the context structure is changed, we have binary backward - * compatibility issues. Instead of modifying the public portions of the - * context structure to add new options, instead, we put them in the internal - * portion of the context structure and provide a set function for these new - * options. - */ -void -smbc_option_set(SMBCCTX *context, - char *option_name, - ... /* option_value */) -{ - va_list ap; - union { - int i; - bool b; - smbc_get_auth_data_with_context_fn auth_fn; - void *v; - const char *s; - } option_value; - - va_start(ap, option_name); - - if (strcmp(option_name, "debug_to_stderr") == 0) { - /* - * Log to standard error instead of standard output. - */ - option_value.b = (bool) va_arg(ap, int); - context->internal->_debug_stderr = option_value.b; - - } else if (strcmp(option_name, "full_time_names") == 0) { - /* - * Use new-style time attribute names, e.g. WRITE_TIME rather - * than the old-style names such as M_TIME. This allows also - * setting/getting CREATE_TIME which was previously - * unimplemented. (Note that the old C_TIME was supposed to - * be CHANGE_TIME but was confused and sometimes referred to - * CREATE_TIME.) - */ - option_value.b = (bool) va_arg(ap, int); - context->internal->_full_time_names = option_value.b; - - } else if (strcmp(option_name, "open_share_mode") == 0) { - /* - * The share mode to use for files opened with - * smbc_open_ctx(). The default is SMBC_SHAREMODE_DENY_NONE. - */ - option_value.i = va_arg(ap, int); - context->internal->_share_mode = - (smbc_share_mode) option_value.i; - - } else if (strcmp(option_name, "auth_function") == 0) { - /* - * Use the new-style authentication function which includes - * the context. - */ - option_value.auth_fn = - va_arg(ap, smbc_get_auth_data_with_context_fn); - context->internal->_auth_fn_with_context = - option_value.auth_fn; - } else if (strcmp(option_name, "user_data") == 0) { - /* - * Save a user data handle which may be retrieved by the user - * with smbc_option_get() - */ - 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); -} - - -/* - * Retrieve the current value of an option - */ -void * -smbc_option_get(SMBCCTX *context, - char *option_name) -{ - if (strcmp(option_name, "debug_stderr") == 0) { - /* - * Log to standard error instead of standard output. - */ -#if defined(__intptr_t_defined) || defined(HAVE_INTPTR_T) - return (void *) (intptr_t) context->internal->_debug_stderr; -#else - return (void *) context->internal->_debug_stderr; -#endif - } else if (strcmp(option_name, "full_time_names") == 0) { - /* - * Use new-style time attribute names, e.g. WRITE_TIME rather - * than the old-style names such as M_TIME. This allows also - * setting/getting CREATE_TIME which was previously - * unimplemented. (Note that the old C_TIME was supposed to - * be CHANGE_TIME but was confused and sometimes referred to - * CREATE_TIME.) - */ -#if defined(__intptr_t_defined) || defined(HAVE_INTPTR_T) - return (void *) (intptr_t) context->internal->_full_time_names; -#else - return (void *) context->internal->_full_time_names; -#endif - - } else if (strcmp(option_name, "auth_function") == 0) { - /* - * Use the new-style authentication function which includes - * the context. - */ - return (void *) context->internal->_auth_fn_with_context; - } else if (strcmp(option_name, "user_data") == 0) { - /* - * Save a user data handle which may be retrieved by the user - * 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; -} - - -/* - * Initialise the library etc - * - * We accept a struct containing handle information. - * valid values for info->debug from 0 to 100, - * and insist that info->fn must be non-null. - */ -SMBCCTX * -smbc_init_context(SMBCCTX *context) -{ - int pid; - char *user = NULL; - char *home = NULL; - - if (!context || !context->internal) { - errno = EBADF; - return NULL; - } - - /* Do not initialise the same client twice */ - if (context->internal->_initialized) { - return 0; - } - - if ((!context->callbacks.auth_fn && - !context->internal->_auth_fn_with_context) || - context->debug < 0 || - context->debug > 100) { - - errno = EINVAL; - return NULL; - - } - - if (!smbc_initialized) { - /* - * Do some library-wide intializations the first time we get - * called - */ - bool conf_loaded = False; - TALLOC_CTX *frame = talloc_stackframe(); - - /* Set this to what the user wants */ - DEBUGLEVEL = context->debug; - - load_case_tables(); - - setup_logging("libsmbclient", True); - if (context->internal->_debug_stderr) { - dbf = x_stderr; - x_setbuf(x_stderr, NULL); - } - - /* Here we would open the smb.conf file if needed ... */ - - in_client = True; /* FIXME, make a param */ - - home = getenv("HOME"); - if (home) { - char *conf = NULL; - if (asprintf(&conf, "%s/.smb/smb.conf", home) > 0) { - if (lp_load(conf, True, False, False, True)) { - conf_loaded = True; - } else { - DEBUG(5, ("Could not load config file: %s\n", - conf)); - } - SAFE_FREE(conf); - } - } - - if (!conf_loaded) { - /* - * Well, if that failed, try the get_dyn_CONFIGFILE - * Which points to the standard locn, and if that - * fails, silently ignore it and use the internal - * defaults ... - */ - - if (!lp_load(get_dyn_CONFIGFILE(), True, False, False, False)) { - DEBUG(5, ("Could not load config file: %s\n", - get_dyn_CONFIGFILE())); - } else if (home) { - char *conf; - /* - * We loaded the global config file. Now lets - * load user-specific modifications to the - * global config. - */ - if (asprintf(&conf, - "%s/.smb/smb.conf.append", - home) > 0) { - if (!lp_load(conf, True, False, False, False)) { - DEBUG(10, - ("Could not append config file: " - "%s\n", - conf)); - } - SAFE_FREE(conf); - } - } - } - - load_interfaces(); /* Load the list of interfaces ... */ - - reopen_logs(); /* Get logging working ... */ - - /* - * Block SIGPIPE (from lib/util_sock.c: write()) - * It is not needed and should not stop execution - */ - BlockSignals(True, SIGPIPE); - - /* Done with one-time initialisation */ - smbc_initialized = 1; - - TALLOC_FREE(frame); - } - - if (!context->user) { - /* - * FIXME: Is this the best way to get the user info? - */ - user = getenv("USER"); - /* walk around as "guest" if no username can be found */ - if (!user) context->user = SMB_STRDUP("guest"); - else context->user = SMB_STRDUP(user); - } - - if (!context->netbios_name) { - /* - * We try to get our netbios name from the config. If that - * fails we fall back on constructing our netbios name from - * our hostname etc - */ - if (global_myname()) { - context->netbios_name = SMB_STRDUP(global_myname()); - } - else { - /* - * Hmmm, I want to get hostname as well, but I am too - * lazy for the moment - */ - pid = sys_getpid(); - context->netbios_name = (char *)SMB_MALLOC(17); - if (!context->netbios_name) { - errno = ENOMEM; - return NULL; - } - slprintf(context->netbios_name, 16, - "smbc%s%d", context->user, pid); - } - } - - DEBUG(1, ("Using netbios name %s.\n", context->netbios_name)); - - if (!context->workgroup) { - if (lp_workgroup()) { - context->workgroup = SMB_STRDUP(lp_workgroup()); - } - else { - /* TODO: Think about a decent default workgroup */ - context->workgroup = SMB_STRDUP("samba"); - } - } - - DEBUG(1, ("Using workgroup %s.\n", context->workgroup)); - - /* shortest timeout is 1 second */ - if (context->timeout > 0 && context->timeout < 1000) - context->timeout = 1000; - - /* - * FIXME: Should we check the function pointers here? - */ - - context->internal->_initialized = True; - - return context; -} - - -/* Return the verion of samba, and thus libsmbclient */ -const char * -smbc_version(void) -{ - return samba_version_string(); -} -- cgit From 4ba42cbe0f6bbd25848786e1a87c06aca79b98ea Mon Sep 17 00:00:00 2001 From: Derrell Lipman Date: Fri, 29 Feb 2008 13:34:35 -0500 Subject: Modified revamp of the libsmbclient interface. Given the tacit (if that) approval by some people, and clear disapproval by others for my proposed clean-up and reorganization of libsmbclient, I've come up with a slightly different approach. This commit changes back to the original libsmbclient.h SMBCCTX structure which will maintain ABI compatibility. I retain, here, the setter and getter functions which all new code should use. Older programs already compiled should continue to work fine. Older programs being recompiled will encounter compile-time errors (intentionally!) so that the code can be corrected to use the setter/getter interfaces. Although this doesn't clean up the interface in the way I had wanted, the code reorganization and requirement for new programs to use the setters and getters allows future progress to be made on libsmbclient without further muddying up the interface, while retaining the ABI compatibility that was the big issue causing disapproval. I hope that this compromise is adequate. Derrell (This used to be commit 56429a3d60b2a48963342f6340b3c01469a892c6) --- source3/libsmb/libsmb_cache.c | 2 +- source3/libsmb/libsmb_context.c | 305 ++++++++++++++++++++++----------------- source3/libsmb/libsmb_dir.c | 70 ++++----- source3/libsmb/libsmb_file.c | 36 ++--- source3/libsmb/libsmb_path.c | 7 +- source3/libsmb/libsmb_printjob.c | 14 +- source3/libsmb/libsmb_server.c | 33 +++-- source3/libsmb/libsmb_stat.c | 10 +- source3/libsmb/libsmb_xattr.c | 22 +-- 9 files changed, 272 insertions(+), 227 deletions(-) (limited to 'source3/libsmb') diff --git a/source3/libsmb/libsmb_cache.c b/source3/libsmb/libsmb_cache.c index e0571fa9fe..7ff92f1b4e 100644 --- a/source3/libsmb/libsmb_cache.c +++ b/source3/libsmb/libsmb_cache.c @@ -151,7 +151,7 @@ SMBC_get_cached_server(SMBCCTX * context, * a connection to the server (other than the * attribute server connection) is cool. */ - if (context->one_share_per_server) { + if (context->options.one_share_per_server) { /* * The currently connected share name * doesn't match the requested share, so diff --git a/source3/libsmb/libsmb_context.c b/source3/libsmb/libsmb_context.c index 1505d50a43..6b7a19e1e4 100644 --- a/source3/libsmb/libsmb_context.c +++ b/source3/libsmb/libsmb_context.c @@ -41,6 +41,15 @@ SMBCCTX * smbc_new_context(void) { SMBCCTX *context; + + /* + * All newly added context fields should be placed in SMBC_internal_data, + * not directly in SMBCCTX. + */ +# undef OLD +# define OLD(field) context->field +# undef NEW +# define NEW(field) context->internal->field context = SMB_MALLOC_P(SMBCCTX); if (!context) { @@ -48,66 +57,73 @@ smbc_new_context(void) return NULL; } - - /* Initialize the context and establish reasonable defaults */ ZERO_STRUCTP(context); + + context->internal = SMB_MALLOC_P(struct SMBC_internal_data); + if (!context->internal) { + SAFE_FREE(context); + errno = ENOMEM; + return NULL; + } + + /* Initialize the context and establish reasonable defaults */ + ZERO_STRUCTP(context->internal); - context->debug = 0; - context->timeout = 20000; /* 20 seconds */ + OLD(config.debug) = 0; + OLD(config.timeout) = 20000; /* 20 seconds */ - context->full_time_names = False; - context->share_mode = SMBC_SHAREMODE_DENY_NONE; - context->smb_encryption_level = 0; - context->browse_max_lmb_count = 3; /* # LMBs to query */ - context->urlencode_readdir_entries = False; - context->one_share_per_server = False; - context->use_kerberos = False; - context->fallback_after_kerberos = False; - context->no_auto_anonymous_login = False; + NEW(full_time_names) = False; + NEW(share_mode) = SMBC_SHAREMODE_DENY_NONE; + NEW(smb_encryption_level) = 0; + NEW(browse_max_lmb_count) = 3; /* # LMBs to query */ + NEW(urlencode_readdir_entries) = False; + NEW(one_share_per_server) = False; - context->server.get_auth_data_fn = SMBC_get_auth_data; - context->server.check_server_fn = SMBC_check_server; - context->server.remove_unused_server_fn = SMBC_remove_unused_server; + OLD(server.get_auth_data_fn) = SMBC_get_auth_data; + OLD(server.check_server_fn) = SMBC_check_server; + OLD(server.remove_unused_server_fn) = SMBC_remove_unused_server; - context->cache.server_cache_data = NULL; - context->cache.add_cached_server_fn = SMBC_add_cached_server; - context->cache.get_cached_server_fn = SMBC_get_cached_server; - context->cache.remove_cached_server_fn = SMBC_remove_cached_server; - context->cache.purge_cached_server_fn = SMBC_purge_cached_servers; + OLD(cache.server_cache_data) = NULL; + OLD(cache.add_cached_server_fn) = SMBC_add_cached_server; + OLD(cache.get_cached_server_fn) = SMBC_get_cached_server; + OLD(cache.remove_cached_server_fn) = SMBC_remove_cached_server; + OLD(cache.purge_cached_servers_fn) = SMBC_purge_cached_servers; - context->posix_emu.open_fn = SMBC_open_ctx; - context->posix_emu.creat_fn = SMBC_creat_ctx; - context->posix_emu.read_fn = SMBC_read_ctx; - context->posix_emu.write_fn = SMBC_write_ctx; - context->posix_emu.close_fn = SMBC_close_ctx; - context->posix_emu.unlink_fn = SMBC_unlink_ctx; - context->posix_emu.rename_fn = SMBC_rename_ctx; - context->posix_emu.lseek_fn = SMBC_lseek_ctx; - context->posix_emu.ftruncate_fn = SMBC_ftruncate_ctx; - context->posix_emu.stat_fn = SMBC_stat_ctx; - context->posix_emu.fstat_fn = SMBC_fstat_ctx; - context->posix_emu.opendir_fn = SMBC_opendir_ctx; - context->posix_emu.closedir_fn = SMBC_closedir_ctx; - context->posix_emu.readdir_fn = SMBC_readdir_ctx; - context->posix_emu.getdents_fn = SMBC_getdents_ctx; - context->posix_emu.mkdir_fn = SMBC_mkdir_ctx; - context->posix_emu.rmdir_fn = SMBC_rmdir_ctx; - context->posix_emu.telldir_fn = SMBC_telldir_ctx; - context->posix_emu.lseekdir_fn = SMBC_lseekdir_ctx; - context->posix_emu.fstatdir_fn = SMBC_fstatdir_ctx; - context->posix_emu.chmod_fn = SMBC_chmod_ctx; - context->posix_emu.utimes_fn = SMBC_utimes_ctx; - context->posix_emu.setxattr_fn = SMBC_setxattr_ctx; - context->posix_emu.getxattr_fn = SMBC_getxattr_ctx; - context->posix_emu.removexattr_fn = SMBC_removexattr_ctx; - context->posix_emu.listxattr_fn = SMBC_listxattr_ctx; + OLD(posix_emu.open_fn) = SMBC_open_ctx; + OLD(posix_emu.creat_fn) = SMBC_creat_ctx; + OLD(posix_emu.read_fn) = SMBC_read_ctx; + OLD(posix_emu.write_fn) = SMBC_write_ctx; + OLD(posix_emu.close_fn) = SMBC_close_ctx; + OLD(posix_emu.unlink_fn) = SMBC_unlink_ctx; + OLD(posix_emu.rename_fn) = SMBC_rename_ctx; + OLD(posix_emu.lseek_fn) = SMBC_lseek_ctx; + NEW(posix_emu.ftruncate_fn) = SMBC_ftruncate_ctx; + OLD(posix_emu.stat_fn) = SMBC_stat_ctx; + OLD(posix_emu.fstat_fn) = SMBC_fstat_ctx; + OLD(posix_emu.opendir_fn) = SMBC_opendir_ctx; + OLD(posix_emu.closedir_fn) = SMBC_closedir_ctx; + OLD(posix_emu.readdir_fn) = SMBC_readdir_ctx; + OLD(posix_emu.getdents_fn) = SMBC_getdents_ctx; + OLD(posix_emu.mkdir_fn) = SMBC_mkdir_ctx; + OLD(posix_emu.rmdir_fn) = SMBC_rmdir_ctx; + OLD(posix_emu.telldir_fn) = SMBC_telldir_ctx; + OLD(posix_emu.lseekdir_fn) = SMBC_lseekdir_ctx; + OLD(posix_emu.fstatdir_fn) = SMBC_fstatdir_ctx; + OLD(posix_emu.chmod_fn) = SMBC_chmod_ctx; + OLD(posix_emu.utimes_fn) = SMBC_utimes_ctx; + OLD(posix_emu.setxattr_fn) = SMBC_setxattr_ctx; + OLD(posix_emu.getxattr_fn) = SMBC_getxattr_ctx; + OLD(posix_emu.removexattr_fn) = SMBC_removexattr_ctx; + OLD(posix_emu.listxattr_fn) = SMBC_listxattr_ctx; - context->printing.open_print_job_fn = SMBC_open_print_job_ctx; - context->printing.print_file_fn = SMBC_print_file_ctx; - context->printing.list_print_jobs_fn = SMBC_list_print_jobs_ctx; - context->printing.unlink_print_job_fn = SMBC_unlink_print_job_ctx; + OLD(printing.open_print_job_fn) = SMBC_open_print_job_ctx; + OLD(printing.print_file_fn) = SMBC_print_file_ctx; + OLD(printing.list_print_jobs_fn) = SMBC_list_print_jobs_ctx; + OLD(printing.unlink_print_job_fn) = SMBC_unlink_print_job_ctx; return context; +#undef OLD +#undef NEW } /* @@ -130,20 +146,20 @@ smbc_free_context(SMBCCTX *context, SMBCFILE * f; DEBUG(1,("Performing aggressive shutdown.\n")); - f = context->files; + f = context->internal->files; while (f) { (context->posix_emu.close_fn)(context, f); f = f->next; } - context->files = NULL; + context->internal->files = NULL; /* First try to remove the servers the nice way. */ - if (context->cache.purge_cached_server_fn(context)) { + if (context->cache.purge_cached_servers_fn(context)) { SMBCSRV * s; SMBCSRV * next; DEBUG(1, ("Could not purge all servers, " "Nice way shutdown failed.\n")); - s = context->servers; + s = context->internal->servers; while (s) { DEBUG(1, ("Forced shutdown: %p (fd=%d)\n", s, s->cli->fd)); @@ -151,28 +167,28 @@ smbc_free_context(SMBCCTX *context, (context->cache.remove_cached_server_fn)(context, s); next = s->next; - DLIST_REMOVE(context->servers, s); + DLIST_REMOVE(context->internal->servers, s); SAFE_FREE(s); s = next; } - context->servers = NULL; + context->internal->servers = NULL; } } else { /* This is the polite way */ - if ((context->cache.purge_cached_server_fn)(context)) { + if ((context->cache.purge_cached_servers_fn)(context)) { DEBUG(1, ("Could not purge all servers, " "free_context failed.\n")); errno = EBUSY; return 1; } - if (context->servers) { + if (context->internal->servers) { DEBUG(1, ("Active servers in context, " "free_context failed.\n")); errno = EBUSY; return 1; } - if (context->files) { + if (context->internal->files) { DEBUG(1, ("Active files in context, " "free_context failed.\n")); errno = EBUSY; @@ -181,9 +197,9 @@ smbc_free_context(SMBCCTX *context, } /* Things we have to clean up */ - SAFE_FREE(context->workgroup); - SAFE_FREE(context->netbios_name); - SAFE_FREE(context->user); + SAFE_FREE(context->config.workgroup); + SAFE_FREE(context->config.netbios_name); + SAFE_FREE(context->config.user); DEBUG(3, ("Context %p successfully freed\n", context)); SAFE_FREE(context); @@ -219,7 +235,7 @@ smbc_option_set(SMBCCTX *context, * Log to standard error instead of standard output. */ option_value.b = (bool) va_arg(ap, int); - context->debug_stderr = option_value.b; + context->internal->debug_stderr = option_value.b; } else if (strcmp(option_name, "full_time_names") == 0) { /* @@ -231,7 +247,7 @@ smbc_option_set(SMBCCTX *context, * CREATE_TIME.) */ option_value.b = (bool) va_arg(ap, int); - context->full_time_names = option_value.b; + context->internal->full_time_names = option_value.b; } else if (strcmp(option_name, "open_share_mode") == 0) { /* @@ -239,7 +255,7 @@ smbc_option_set(SMBCCTX *context, * SMBC_open_ctx(). The default is SMBC_SHAREMODE_DENY_NONE. */ option_value.i = va_arg(ap, int); - context->share_mode = (smbc_share_mode) option_value.i; + context->internal->share_mode = (smbc_share_mode) option_value.i; } else if (strcmp(option_name, "user_data") == 0) { /* @@ -247,7 +263,7 @@ smbc_option_set(SMBCCTX *context, * with smbc_option_get() */ option_value.v = va_arg(ap, void *); - context->user_data = option_value.v; + context->internal->user_data = option_value.v; } else if (strcmp(option_name, "smb_encrypt_level") == 0) { /* * Save an encoded value for encryption level. @@ -255,11 +271,11 @@ smbc_option_set(SMBCCTX *context, */ option_value.s = va_arg(ap, const char *); if (strcmp(option_value.s, "none") == 0) { - context->smb_encryption_level = 0; + context->internal->smb_encryption_level = 0; } else if (strcmp(option_value.s, "request") == 0) { - context->smb_encryption_level = 1; + context->internal->smb_encryption_level = 1; } else if (strcmp(option_value.s, "require") == 0) { - context->smb_encryption_level = 2; + context->internal->smb_encryption_level = 2; } } else if (strcmp(option_name, "browse_max_lmb_count") == 0) { /* @@ -280,7 +296,7 @@ smbc_option_set(SMBCCTX *context, * variable is probably somewhere around 3. (Default: 3). */ option_value.i = va_arg(ap, int); - context->browse_max_lmb_count = option_value.i; + context->internal->browse_max_lmb_count = option_value.i; } else if (strcmp(option_name, "urlencode_readdir_entries") == 0) { /* @@ -307,7 +323,7 @@ smbc_option_set(SMBCCTX *context, * For backwards compatibility, this option defaults to False. */ option_value.b = (bool) va_arg(ap, int); - context->urlencode_readdir_entries = option_value.b; + context->internal->urlencode_readdir_entries = option_value.b; } else if (strcmp(option_name, "one_share_per_server") == 0) { /* @@ -321,19 +337,31 @@ smbc_option_set(SMBCCTX *context, * and issuing a new TREE CONNECT when the share is accessed. */ option_value.b = (bool) va_arg(ap, int); - context->one_share_per_server = option_value.b; + context->options.one_share_per_server = option_value.b; } else if (strcmp(option_name, "use_kerberos") == 0) { option_value.b = (bool) va_arg(ap, int); - context->use_kerberos = option_value.b; + if (option_value.b) { + context->flags.bits |= SMB_CTX_FLAG_USE_KERBEROS; + } else { + context->flags.bits &= ~SMB_CTX_FLAG_USE_KERBEROS; + } } else if (strcmp(option_name, "fallback_after_kerberos") == 0) { option_value.b = (bool) va_arg(ap, int); - context->fallback_after_kerberos = option_value.b; + if (option_value.b) { + context->flags.bits |= SMB_CTX_FLAG_FALLBACK_AFTER_KERBEROS; + } else { + context->flags.bits &= ~SMB_CTX_FLAG_FALLBACK_AFTER_KERBEROS; + } } else if (strcmp(option_name, "no_auto_anonymous_login") == 0) { option_value.b = (bool) va_arg(ap, int); - context->no_auto_anonymous_login = option_value.b; + if (option_value.b) { + context->flags.bits |= SMBCCTX_FLAG_NO_AUTO_ANONYMOUS_LOGON; + } else { + context->flags.bits &= ~SMBCCTX_FLAG_NO_AUTO_ANONYMOUS_LOGON; + } } va_end(ap); @@ -347,14 +375,16 @@ void * smbc_option_get(SMBCCTX *context, char *option_name) { + int bits; + if (strcmp(option_name, "debug_stderr") == 0) { /* * Log to standard error instead of standard output. */ #if defined(__intptr_t_defined) || defined(HAVE_INTPTR_T) - return (void *) (intptr_t) context->debug_stderr; + return (void *) (intptr_t) context->internal->debug_stderr; #else - return (void *) context->debug_stderr; + return (void *) context->internal->debug_stderr; #endif } else if (strcmp(option_name, "full_time_names") == 0) { @@ -367,9 +397,9 @@ smbc_option_get(SMBCCTX *context, * CREATE_TIME.) */ #if defined(__intptr_t_defined) || defined(HAVE_INTPTR_T) - return (void *) (intptr_t) context->full_time_names; + return (void *) (intptr_t) context->internal->full_time_names; #else - return (void *) context->full_time_names; + return (void *) context->internal->full_time_names; #endif } else if (strcmp(option_name, "user_data") == 0) { @@ -377,13 +407,13 @@ smbc_option_get(SMBCCTX *context, * Return the user data handle which was saved by the user * with smbc_option_set() */ - return context->user_data; + 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->smb_encryption_level) { + switch (context->internal->smb_encryption_level) { case 0: return (void *) "none"; case 1: @@ -402,7 +432,7 @@ smbc_option_get(SMBCCTX *context, SMBCSRV *s; unsigned int num_servers = 0; - for (s = context->servers; s; s = s->next) { + for (s = context->internal->servers; s; s = s->next) { num_servers++; if (s->cli->trans_enc_state == NULL) { return (void *)false; @@ -433,9 +463,9 @@ smbc_option_get(SMBCCTX *context, * variable is probably somewhere around 3. (Default: 3). */ #if defined(__intptr_t_defined) || defined(HAVE_INTPTR_T) - return (void *) (intptr_t) context->browse_max_lmb_count; + return (void *) (intptr_t) context->internal->browse_max_lmb_count; #else - return (void *) context->browse_max_lmb_count; + return (void *) context->internal->browse_max_lmb_count; #endif } else if (strcmp(option_name, "urlencode_readdir_entries") == 0) { @@ -463,9 +493,9 @@ smbc_option_get(SMBCCTX *context, * For backwards compatibility, this option defaults to False. */ #if defined(__intptr_t_defined) || defined(HAVE_INTPTR_T) - return (void *) (intptr_t) context->urlencode_readdir_entries; + return (void *)(intptr_t) context->internal->urlencode_readdir_entries; #else - return (void *) (bool) context->urlencode_readdir_entries; + return (void *) (bool) context->internal->urlencode_readdir_entries; #endif } else if (strcmp(option_name, "one_share_per_server") == 0) { @@ -480,30 +510,43 @@ smbc_option_get(SMBCCTX *context, * and issuing a new TREE CONNECT when the share is accessed. */ #if defined(__intptr_t_defined) || defined(HAVE_INTPTR_T) - return (void *) (intptr_t) context->one_share_per_server; + return (void *) (intptr_t) context->internal->one_share_per_server; #else - return (void *) (bool) context->one_share_per_server; + return (void *) (bool) context->internal->one_share_per_server; #endif } else if (strcmp(option_name, "use_kerberos") == 0) { + bits = context->flags.bits; #if defined(__intptr_t_defined) || defined(HAVE_INTPTR_T) - return (void *) (intptr_t) context->use_kerberos; + return (context->flags.bits & SMB_CTX_FLAG_USE_KERBEROS + ? (void *) (intptr_t) 1 + : (void *) (intptr_t) 0); #else - return (void *) (bool) context->use_kerberos; + return (context->flags.bits & SMB_CTX_FLAG_USE_KERBEROS + ? (void *) (bool) 1 + : (void *) (bool) 0); #endif } else if (strcmp(option_name, "fallback_after_kerberos") == 0) { #if defined(__intptr_t_defined) || defined(HAVE_INTPTR_T) - return (void *) (intptr_t) context->fallback_after_kerberos; + return (context->flags.bits & SMB_CTX_FLAG_FALLBACK_AFTER_KERBEROS + ? (void *) (intptr_t) 1 + : (void *) (intptr_t) 0); #else - return (void *) (bool) context->fallback_after_kerberos; + return (context->flags.bits & SMB_CTX_FLAG_FALLBACK_AFTER_KERBEROS + ? (void *) (bool) 1 + : (void *) (bool) 0); #endif } else if (strcmp(option_name, "no_auto_anonymous_login") == 0) { #if defined(__intptr_t_defined) || defined(HAVE_INTPTR_T) - return (void *) (intptr_t) context->no_auto_anonymous_login; + return (context->flags.bits & SMBCCTX_FLAG_NO_AUTO_ANONYMOUS_LOGON + ? (void *) (intptr_t) 1 + : (void *) (intptr_t) 0); #else - return (void *) (bool) context->no_auto_anonymous_login; + return (context->flags.bits & SMBCCTX_FLAG_NO_AUTO_ANONYMOUS_LOGON + ? (void *) (bool) 1 + : (void *) (bool) 0); #endif } @@ -532,13 +575,13 @@ smbc_init_context(SMBCCTX *context) } /* Do not initialise the same client twice */ - if (context->initialized) { + if (context->internal->initialized) { return 0; } if (!context->server.get_auth_data_fn || - context->debug < 0 || - context->debug > 100) { + context->config.debug < 0 || + context->config.debug > 100) { errno = EINVAL; return NULL; @@ -554,12 +597,12 @@ smbc_init_context(SMBCCTX *context) TALLOC_CTX *frame = talloc_stackframe(); /* Set this to what the user wants */ - DEBUGLEVEL = context->debug; + DEBUGLEVEL = context->config.debug; load_case_tables(); setup_logging("libsmbclient", True); - if (context->debug_stderr) { + if (context->internal->debug_stderr) { dbf = x_stderr; x_setbuf(x_stderr, NULL); } @@ -630,24 +673,24 @@ smbc_init_context(SMBCCTX *context) TALLOC_FREE(frame); } - if (!context->user) { + if (!context->config.user) { /* * FIXME: Is this the best way to get the user info? */ user = getenv("USER"); /* walk around as "guest" if no username can be found */ - if (!user) context->user = SMB_STRDUP("guest"); - else context->user = SMB_STRDUP(user); + if (!user) context->config.user = SMB_STRDUP("guest"); + else context->config.user = SMB_STRDUP(user); } - if (!context->netbios_name) { + if (!context->config.netbios_name) { /* * We try to get our netbios name from the config. If that * fails we fall back on constructing our netbios name from * our hostname etc */ if (global_myname()) { - context->netbios_name = SMB_STRDUP(global_myname()); + context->config.netbios_name = SMB_STRDUP(global_myname()); } else { /* @@ -655,39 +698,39 @@ smbc_init_context(SMBCCTX *context) * lazy for the moment */ pid = sys_getpid(); - context->netbios_name = (char *)SMB_MALLOC(17); - if (!context->netbios_name) { + context->config.netbios_name = (char *)SMB_MALLOC(17); + if (!context->config.netbios_name) { errno = ENOMEM; return NULL; } - slprintf(context->netbios_name, 16, - "smbc%s%d", context->user, pid); + slprintf(context->config.netbios_name, 16, + "smbc%s%d", context->config.user, pid); } } - DEBUG(1, ("Using netbios name %s.\n", context->netbios_name)); + DEBUG(1, ("Using netbios name %s.\n", context->config.netbios_name)); - if (!context->workgroup) { + if (!context->config.workgroup) { if (lp_workgroup()) { - context->workgroup = SMB_STRDUP(lp_workgroup()); + context->config.workgroup = SMB_STRDUP(lp_workgroup()); } else { /* TODO: Think about a decent default workgroup */ - context->workgroup = SMB_STRDUP("samba"); + context->config.workgroup = SMB_STRDUP("samba"); } } - DEBUG(1, ("Using workgroup %s.\n", context->workgroup)); + DEBUG(1, ("Using workgroup %s.\n", context->config.workgroup)); /* shortest timeout is 1 second */ - if (context->timeout > 0 && context->timeout < 1000) - context->timeout = 1000; + if (context->config.timeout > 0 && context->config.timeout < 1000) + context->config.timeout = 1000; /* * FIXME: Should we check the function pointers here? */ - context->initialized = True; + context->internal->initialized = True; return context; } @@ -705,56 +748,56 @@ smbc_version(void) char * smbc_getNetbiosName(SMBCCTX *c) { - return c->netbios_name; + return c->config.netbios_name; } /** Set the netbios name used for making connections */ void smbc_setNetbiosName(SMBCCTX *c, char * netbios_name) { - c->netbios_name = netbios_name; + c->config.netbios_name = netbios_name; } /** Get the workgroup used for making connections */ char * smbc_getWorkgroup(SMBCCTX *c) { - return c->workgroup; + return c->config.workgroup; } /** Set the workgroup used for making connections */ void smbc_setWorkgroup(SMBCCTX *c, char * workgroup) { - c->workgroup = workgroup; + c->config.workgroup = workgroup; } /** Get the username used for making connections */ char * smbc_getUser(SMBCCTX *c) { - return c->user; + return c->config.user; } /** Set the username used for making connections */ void smbc_setUser(SMBCCTX *c, char * user) { - c->user = user; + c->config.user = user; } /** Get the debug level */ int smbc_getDebug(SMBCCTX *c) { - return c->debug; + return c->config.debug; } /** Set the debug level */ void smbc_setDebug(SMBCCTX *c, int debug) { - c->debug = debug; + c->config.debug = debug; } /** @@ -764,7 +807,7 @@ smbc_setDebug(SMBCCTX *c, int debug) int smbc_getTimeout(SMBCCTX *c) { - return c->timeout; + return c->config.timeout; } /** @@ -774,7 +817,7 @@ smbc_getTimeout(SMBCCTX *c) void smbc_setTimeout(SMBCCTX *c, int timeout) { - c->timeout = timeout; + c->config.timeout = timeout; } /** Get the function for obtaining authentication data */ @@ -886,7 +929,7 @@ smbc_setFunctionRemoveCachedServer(SMBCCTX *c, smbc_purge_cached_srv_fn smbc_getFunctionPurgeCachedServers(SMBCCTX *c) { - return c->cache.purge_cached_server_fn; + return c->cache.purge_cached_servers_fn; } /** @@ -896,7 +939,7 @@ smbc_getFunctionPurgeCachedServers(SMBCCTX *c) void smbc_setFunctionPurgeCachedServers(SMBCCTX *c, smbc_purge_cached_srv_fn fn) { - c->cache.purge_cached_server_fn = fn; + c->cache.purge_cached_servers_fn = fn; } /** @@ -1014,13 +1057,13 @@ smbc_setFunctionFstat(SMBCCTX *c, smbc_fstat_fn fn) smbc_ftruncate_fn smbc_getFunctionFtruncate(SMBCCTX *c) { - return c->posix_emu.ftruncate_fn; + return c->internal->posix_emu.ftruncate_fn; } void smbc_setFunctionFtruncate(SMBCCTX *c, smbc_ftruncate_fn fn) { - c->posix_emu.ftruncate_fn = fn; + c->internal->posix_emu.ftruncate_fn = fn; } smbc_close_fn diff --git a/source3/libsmb/libsmb_dir.c b/source3/libsmb/libsmb_dir.c index 9cb3351433..25020762a2 100644 --- a/source3/libsmb/libsmb_dir.c +++ b/source3/libsmb/libsmb_dir.c @@ -356,7 +356,7 @@ SMBC_opendir_ctx(SMBCCTX *context, struct sockaddr_storage rem_ss; TALLOC_CTX *frame = talloc_stackframe(); - if (!context || !context->initialized) { + if (!context || !context->internal->initialized) { DEBUG(4, ("no valid context\n")); errno = EINVAL + 8192; TALLOC_FREE(frame); @@ -400,7 +400,7 @@ SMBC_opendir_ctx(SMBCCTX *context, } if (!user || user[0] == (char)0) { - user = talloc_strdup(frame, context->user); + user = talloc_strdup(frame, context->config.user); if (!user) { errno = ENOMEM; TALLOC_FREE(frame); @@ -446,9 +446,9 @@ SMBC_opendir_ctx(SMBCCTX *context, } /* Determine how many local master browsers to query */ - max_lmb_count = (context->browse_max_lmb_count == 0 + max_lmb_count = (context->internal->browse_max_lmb_count == 0 ? INT_MAX - : context->browse_max_lmb_count); + : context->internal->browse_max_lmb_count); memset(&u_info, '\0', sizeof(u_info)); u_info.username = talloc_strdup(frame,user); @@ -826,7 +826,7 @@ SMBC_opendir_ctx(SMBCCTX *context, } - DLIST_ADD(context->files, dir); + DLIST_ADD(context->internal->files, dir); TALLOC_FREE(frame); return dir; @@ -842,13 +842,13 @@ SMBC_closedir_ctx(SMBCCTX *context, { TALLOC_CTX *frame = talloc_stackframe(); - if (!context || !context->initialized) { + if (!context || !context->internal->initialized) { errno = EINVAL; TALLOC_FREE(frame); return -1; } - if (!dir || !SMBC_dlist_contains(context->files, dir)) { + if (!dir || !SMBC_dlist_contains(context->internal->files, dir)) { errno = EBADF; TALLOC_FREE(frame); return -1; @@ -856,7 +856,7 @@ SMBC_closedir_ctx(SMBCCTX *context, remove_dir(dir); /* Clean it up */ - DLIST_REMOVE(context->files, dir); + DLIST_REMOVE(context->internal->files, dir); if (dir) { @@ -875,7 +875,7 @@ smbc_readdir_internal(SMBCCTX * context, struct smbc_dirent *src, int max_namebuf_len) { - if (context->urlencode_readdir_entries) { + if (context->internal->urlencode_readdir_entries) { /* url-encode the name. get back remaining buffer space */ max_namebuf_len = @@ -919,7 +919,7 @@ SMBC_readdir_ctx(SMBCCTX *context, /* Check that all is ok first ... */ - if (!context || !context->initialized) { + if (!context || !context->internal->initialized) { errno = EINVAL; DEBUG(0, ("Invalid context in SMBC_readdir_ctx()\n")); @@ -928,7 +928,7 @@ SMBC_readdir_ctx(SMBCCTX *context, } - if (!dir || !SMBC_dlist_contains(context->files, dir)) { + if (!dir || !SMBC_dlist_contains(context->internal->files, dir)) { errno = EBADF; DEBUG(0, ("Invalid dir in SMBC_readdir_ctx()\n")); @@ -960,8 +960,8 @@ SMBC_readdir_ctx(SMBCCTX *context, } - dirp = (struct smbc_dirent *)context->dirent; - maxlen = (sizeof(context->dirent) - + dirp = (struct smbc_dirent *)context->internal->dirent; + maxlen = (sizeof(context->internal->dirent) - sizeof(struct smbc_dirent)); smbc_readdir_internal(context, dirp, dirent, maxlen); @@ -991,7 +991,7 @@ SMBC_getdents_ctx(SMBCCTX *context, /* Check that all is ok first ... */ - if (!context || !context->initialized) { + if (!context || !context->internal->initialized) { errno = EINVAL; TALLOC_FREE(frame); @@ -999,7 +999,7 @@ SMBC_getdents_ctx(SMBCCTX *context, } - if (!dir || !SMBC_dlist_contains(context->files, dir)) { + if (!dir || !SMBC_dlist_contains(context->internal->files, dir)) { errno = EBADF; TALLOC_FREE(frame); @@ -1033,8 +1033,8 @@ SMBC_getdents_ctx(SMBCCTX *context, } /* Do urlencoding of next entry, if so selected */ - dirent = (struct smbc_dirent *)context->dirent; - maxlen = (sizeof(context->dirent) - + dirent = (struct smbc_dirent *)context->internal->dirent; + maxlen = (sizeof(context->internal->dirent) - sizeof(struct smbc_dirent)); smbc_readdir_internal(context, dirent, dirlist->dirent, maxlen); @@ -1102,7 +1102,7 @@ SMBC_mkdir_ctx(SMBCCTX *context, struct cli_state *targetcli = NULL; TALLOC_CTX *frame = talloc_stackframe(); - if (!context || !context->initialized) { + if (!context || !context->internal->initialized) { errno = EINVAL; TALLOC_FREE(frame); return -1; @@ -1132,7 +1132,7 @@ SMBC_mkdir_ctx(SMBCCTX *context, } if (!user || user[0] == (char)0) { - user = talloc_strdup(frame, context->user); + user = talloc_strdup(frame, context->config.user); if (!user) { errno = ENOMEM; TALLOC_FREE(frame); @@ -1209,7 +1209,7 @@ SMBC_rmdir_ctx(SMBCCTX *context, struct cli_state *targetcli = NULL; TALLOC_CTX *frame = talloc_stackframe(); - if (!context || !context->initialized) { + if (!context || !context->internal->initialized) { errno = EINVAL; TALLOC_FREE(frame); return -1; @@ -1239,7 +1239,7 @@ SMBC_rmdir_ctx(SMBCCTX *context, } if (!user || user[0] == (char)0) { - user = talloc_strdup(frame, context->user); + user = talloc_strdup(frame, context->config.user); if (!user) { errno = ENOMEM; TALLOC_FREE(frame); @@ -1325,7 +1325,7 @@ SMBC_telldir_ctx(SMBCCTX *context, { TALLOC_CTX *frame = talloc_stackframe(); - if (!context || !context->initialized) { + if (!context || !context->internal->initialized) { errno = EINVAL; TALLOC_FREE(frame); @@ -1333,7 +1333,7 @@ SMBC_telldir_ctx(SMBCCTX *context, } - if (!dir || !SMBC_dlist_contains(context->files, dir)) { + if (!dir || !SMBC_dlist_contains(context->internal->files, dir)) { errno = EBADF; TALLOC_FREE(frame); @@ -1408,7 +1408,7 @@ SMBC_lseekdir_ctx(SMBCCTX *context, struct smbc_dir_list *list_ent = (struct smbc_dir_list *)NULL; TALLOC_CTX *frame = talloc_stackframe(); - if (!context || !context->initialized) { + if (!context || !context->internal->initialized) { errno = EINVAL; TALLOC_FREE(frame); @@ -1465,7 +1465,7 @@ SMBC_fstatdir_ctx(SMBCCTX *context, struct stat *st) { - if (!context || !context->initialized) { + if (!context || !context->internal->initialized) { errno = EINVAL; return -1; @@ -1490,7 +1490,7 @@ SMBC_chmod_ctx(SMBCCTX *context, uint16 mode; TALLOC_CTX *frame = talloc_stackframe(); - if (!context || !context->initialized) { + if (!context || !context->internal->initialized) { errno = EINVAL; /* Best I can think of ... */ TALLOC_FREE(frame); @@ -1521,7 +1521,7 @@ SMBC_chmod_ctx(SMBCCTX *context, } if (!user || user[0] == (char)0) { - user = talloc_strdup(frame, context->user); + user = talloc_strdup(frame, context->config.user); if (!user) { errno = ENOMEM; TALLOC_FREE(frame); @@ -1570,7 +1570,7 @@ SMBC_utimes_ctx(SMBCCTX *context, time_t write_time; TALLOC_CTX *frame = talloc_stackframe(); - if (!context || !context->initialized) { + if (!context || !context->internal->initialized) { errno = EINVAL; /* Best I can think of ... */ TALLOC_FREE(frame); @@ -1627,7 +1627,7 @@ SMBC_utimes_ctx(SMBCCTX *context, } if (!user || user[0] == (char)0) { - user = talloc_strdup(frame, context->user); + user = talloc_strdup(frame, context->config.user); if (!user) { errno = ENOMEM; TALLOC_FREE(frame); @@ -1668,7 +1668,7 @@ SMBC_unlink_ctx(SMBCCTX *context, SMBCSRV *srv = NULL; TALLOC_CTX *frame = talloc_stackframe(); - if (!context || !context->initialized) { + if (!context || !context->internal->initialized) { errno = EINVAL; /* Best I can think of ... */ TALLOC_FREE(frame); @@ -1699,7 +1699,7 @@ SMBC_unlink_ctx(SMBCCTX *context, } if (!user || user[0] == (char)0) { - user = talloc_strdup(frame, context->user); + user = talloc_strdup(frame, context->config.user); if (!user) { errno = ENOMEM; TALLOC_FREE(frame); @@ -1802,8 +1802,8 @@ SMBC_rename_ctx(SMBCCTX *ocontext, TALLOC_CTX *frame = talloc_stackframe(); if (!ocontext || !ncontext || - !ocontext->initialized || - !ncontext->initialized) { + !ocontext->internal->initialized || + !ncontext->internal->initialized) { errno = EINVAL; /* Best I can think of ... */ TALLOC_FREE(frame); @@ -1834,7 +1834,7 @@ SMBC_rename_ctx(SMBCCTX *ocontext, } if (!user1 || user1[0] == (char)0) { - user1 = talloc_strdup(frame, ocontext->user); + user1 = talloc_strdup(frame, ocontext->config.user); if (!user1) { errno = ENOMEM; TALLOC_FREE(frame); @@ -1858,7 +1858,7 @@ SMBC_rename_ctx(SMBCCTX *ocontext, } if (!user2 || user2[0] == (char)0) { - user2 = talloc_strdup(frame, ncontext->user); + user2 = talloc_strdup(frame, ncontext->config.user); if (!user2) { errno = ENOMEM; TALLOC_FREE(frame); diff --git a/source3/libsmb/libsmb_file.c b/source3/libsmb/libsmb_file.c index 619176697b..62b990ed00 100644 --- a/source3/libsmb/libsmb_file.c +++ b/source3/libsmb/libsmb_file.c @@ -46,7 +46,7 @@ SMBC_open_ctx(SMBCCTX *context, int fd; TALLOC_CTX *frame = talloc_stackframe(); - if (!context || !context->initialized) { + if (!context || !context->internal->initialized) { errno = EINVAL; /* Best I can think of ... */ TALLOC_FREE(frame); @@ -78,7 +78,7 @@ SMBC_open_ctx(SMBCCTX *context, } if (!user || user[0] == (char)0) { - user = talloc_strdup(frame, context->user); + user = talloc_strdup(frame, context->config.user); if (!user) { errno = ENOMEM; TALLOC_FREE(frame); @@ -120,7 +120,7 @@ SMBC_open_ctx(SMBCCTX *context, /*d_printf(">>>open: resolved %s as %s\n", path, targetpath);*/ if ((fd = cli_open(targetcli, targetpath, flags, - context->share_mode)) < 0) { + context->internal->share_mode)) < 0) { /* Handle the error ... */ @@ -139,7 +139,7 @@ SMBC_open_ctx(SMBCCTX *context, file->offset = 0; file->file = True; - DLIST_ADD(context->files, file); + DLIST_ADD(context->internal->files, file); /* * If the file was opened in O_APPEND mode, all write @@ -208,7 +208,7 @@ SMBC_creat_ctx(SMBCCTX *context, mode_t mode) { - if (!context || !context->initialized) { + if (!context || !context->internal->initialized) { errno = EINVAL; return NULL; @@ -246,7 +246,7 @@ SMBC_read_ctx(SMBCCTX *context, */ off_t offset; - if (!context || !context->initialized) { + if (!context || !context->internal->initialized) { errno = EINVAL; TALLOC_FREE(frame); @@ -256,7 +256,7 @@ SMBC_read_ctx(SMBCCTX *context, DEBUG(4, ("smbc_read(%p, %d)\n", file, (int)count)); - if (!file || !SMBC_dlist_contains(context->files, file)) { + if (!file || !SMBC_dlist_contains(context->internal->files, file)) { errno = EBADF; TALLOC_FREE(frame); return -1; @@ -338,7 +338,7 @@ SMBC_write_ctx(SMBCCTX *context, /* First check all pointers before dereferencing them */ - if (!context || !context->initialized) { + if (!context || !context->internal->initialized) { errno = EINVAL; TALLOC_FREE(frame); @@ -346,7 +346,7 @@ SMBC_write_ctx(SMBCCTX *context, } - if (!file || !SMBC_dlist_contains(context->files, file)) { + if (!file || !SMBC_dlist_contains(context->internal->files, file)) { errno = EBADF; TALLOC_FREE(frame); return -1; @@ -418,14 +418,14 @@ SMBC_close_ctx(SMBCCTX *context, struct cli_state *targetcli = NULL; TALLOC_CTX *frame = talloc_stackframe(); - if (!context || !context->initialized) { + if (!context || !context->internal->initialized) { errno = EINVAL; TALLOC_FREE(frame); return -1; } - if (!file || !SMBC_dlist_contains(context->files, file)) { + if (!file || !SMBC_dlist_contains(context->internal->files, file)) { errno = EBADF; TALLOC_FREE(frame); return -1; @@ -470,7 +470,7 @@ SMBC_close_ctx(SMBCCTX *context, * from the server cache if unused */ errno = SMBC_errno(context, targetcli); srv = file->srv; - DLIST_REMOVE(context->files, file); + DLIST_REMOVE(context->internal->files, file); SAFE_FREE(file->fname); SAFE_FREE(file); (context->server.remove_unused_server_fn)(context, srv); @@ -479,7 +479,7 @@ SMBC_close_ctx(SMBCCTX *context, } - DLIST_REMOVE(context->files, file); + DLIST_REMOVE(context->internal->files, file); SAFE_FREE(file->fname); SAFE_FREE(file); TALLOC_FREE(frame); @@ -509,7 +509,7 @@ SMBC_getatr(SMBCCTX * context, time_t write_time; TALLOC_CTX *frame = talloc_stackframe(); - if (!context || !context->initialized) { + if (!context || !context->internal->initialized) { errno = EINVAL; TALLOC_FREE(frame); @@ -698,14 +698,14 @@ SMBC_lseek_ctx(SMBCCTX *context, struct cli_state *targetcli = NULL; TALLOC_CTX *frame = talloc_stackframe(); - if (!context || !context->initialized) { + if (!context || !context->internal->initialized) { errno = EINVAL; TALLOC_FREE(frame); return -1; } - if (!file || !SMBC_dlist_contains(context->files, file)) { + if (!file || !SMBC_dlist_contains(context->internal->files, file)) { errno = EBADF; TALLOC_FREE(frame); @@ -803,14 +803,14 @@ SMBC_ftruncate_ctx(SMBCCTX *context, struct cli_state *targetcli = NULL; TALLOC_CTX *frame = talloc_stackframe(); - if (!context || !context->initialized) { + if (!context || !context->internal->initialized) { errno = EINVAL; TALLOC_FREE(frame); return -1; } - if (!file || !SMBC_dlist_contains(context->files, file)) { + if (!file || !SMBC_dlist_contains(context->internal->files, file)) { errno = EBADF; TALLOC_FREE(frame); return -1; diff --git a/source3/libsmb/libsmb_path.c b/source3/libsmb/libsmb_path.c index 2533f536c3..6706a59ba8 100644 --- a/source3/libsmb/libsmb_path.c +++ b/source3/libsmb/libsmb_path.c @@ -252,7 +252,8 @@ SMBC_parse_path(TALLOC_CTX *ctx, * to the workgroup in the provided context. */ if (pp_workgroup != NULL) { - *pp_workgroup = talloc_strdup(ctx, context->workgroup); + *pp_workgroup = + talloc_strdup(ctx, context->config.workgroup); } if (pp_options) { @@ -296,13 +297,13 @@ SMBC_parse_path(TALLOC_CTX *ctx, } if (*p == '/') { - int wl = strlen(context->workgroup); + int wl = strlen(context->config.workgroup); if (wl > 16) { wl = 16; } - *pp_server = talloc_strdup(ctx, context->workgroup); + *pp_server = talloc_strdup(ctx, context->config.workgroup); if (!*pp_server) { return -1; } diff --git a/source3/libsmb/libsmb_printjob.c b/source3/libsmb/libsmb_printjob.c index f106080b6f..a03c15e024 100644 --- a/source3/libsmb/libsmb_printjob.c +++ b/source3/libsmb/libsmb_printjob.c @@ -42,7 +42,7 @@ SMBC_open_print_job_ctx(SMBCCTX *context, char *path = NULL; TALLOC_CTX *frame = talloc_stackframe(); - if (!context || !context->initialized) { + if (!context || !context->internal->initialized) { errno = EINVAL; TALLOC_FREE(frame); @@ -99,8 +99,8 @@ SMBC_print_file_ctx(SMBCCTX *c_file, char buf[4096]; TALLOC_CTX *frame = talloc_stackframe(); - if (!c_file || !c_file->initialized || - !c_print || !c_print->initialized) { + if (!c_file || !c_file->internal->initialized || + !c_print || !c_print->internal->initialized) { errno = EINVAL; TALLOC_FREE(frame); @@ -189,7 +189,7 @@ SMBC_list_print_jobs_ctx(SMBCCTX *context, char *path = NULL; TALLOC_CTX *frame = talloc_stackframe(); - if (!context || !context->initialized) { + if (!context || !context->internal->initialized) { errno = EINVAL; TALLOC_FREE(frame); @@ -220,7 +220,7 @@ SMBC_list_print_jobs_ctx(SMBCCTX *context, } if (!user || user[0] == (char)0) { - user = talloc_strdup(frame, context->user); + user = talloc_strdup(frame, context->config.user); if (!user) { errno = ENOMEM; TALLOC_FREE(frame); @@ -267,7 +267,7 @@ SMBC_unlink_print_job_ctx(SMBCCTX *context, int err; TALLOC_CTX *frame = talloc_stackframe(); - if (!context || !context->initialized) { + if (!context || !context->internal->initialized) { errno = EINVAL; TALLOC_FREE(frame); @@ -298,7 +298,7 @@ SMBC_unlink_print_job_ctx(SMBCCTX *context, } if (!user || user[0] == (char)0) { - user = talloc_strdup(frame, context->user); + user = talloc_strdup(frame, context->config.user); if (!user) { errno = ENOMEM; TALLOC_FREE(frame); diff --git a/source3/libsmb/libsmb_server.c b/source3/libsmb/libsmb_server.c index 978a843d30..70e0d57273 100644 --- a/source3/libsmb/libsmb_server.c +++ b/source3/libsmb/libsmb_server.c @@ -58,12 +58,12 @@ SMBC_remove_unused_server(SMBCCTX * context, SMBCFILE * file; /* are we being fooled ? */ - if (!context || !context->initialized || !srv) { + if (!context || !context->internal->initialized || !srv) { return 1; } /* Check all open files/directories for a relation with this server */ - for (file = context->files; file; file = file->next) { + for (file = context->internal->files; file; file = file->next) { if (file->srv == srv) { /* Still used */ DEBUG(3, ("smbc_remove_usused_server: " @@ -73,7 +73,7 @@ SMBC_remove_unused_server(SMBCCTX * context, } } - DLIST_REMOVE(context->servers, srv); + DLIST_REMOVE(context->internal->servers, srv); cli_shutdown(srv->cli); srv->cli = NULL; @@ -251,7 +251,7 @@ SMBC_server(TALLOC_CTX *ctx, * If we found a connection and we're only allowed one share per * server... */ - if (srv && *share != '\0' && context->one_share_per_server) { + if (srv && *share != '\0' && context->internal->one_share_per_server) { /* * ... then if there's no current connection to the share, @@ -322,7 +322,7 @@ SMBC_server(TALLOC_CTX *ctx, return NULL; } - make_nmb_name(&calling, context->netbios_name, 0x0); + make_nmb_name(&calling, context->config.netbios_name, 0x0); make_nmb_name(&called , server, 0x20); DEBUG(4,("SMBC_server: server_n=[%s] server=[%s]\n", server_n, server)); @@ -339,14 +339,14 @@ SMBC_server(TALLOC_CTX *ctx, return NULL; } - if (context->use_kerberos) { + if (context->flags.bits & SMB_CTX_FLAG_USE_KERBEROS) { c->use_kerberos = True; } - if (context->fallback_after_kerberos) { + if (context->flags.bits & SMB_CTX_FLAG_FALLBACK_AFTER_KERBEROS) { c->fallback_after_kerberos = True; } - c->timeout = context->timeout; + c->timeout = context->config.timeout; /* * Force use of port 139 for first try if share is $IPC, empty, or @@ -428,7 +428,8 @@ SMBC_server(TALLOC_CTX *ctx, /* Failed. Try an anonymous login, if allowed by flags. */ username_used = ""; - if (context->no_auto_anonymous_login || + if ((context->flags.bits & + SMBCCTX_FLAG_NO_AUTO_ANONYMOUS_LOGON) || !NT_STATUS_IS_OK(cli_session_setup(c, username_used, *pp_password, 1, *pp_password, 0, @@ -451,7 +452,7 @@ SMBC_server(TALLOC_CTX *ctx, DEBUG(4,(" tconx ok\n")); - if (context->smb_encryption_level) { + if (context->internal->smb_encryption_level) { /* Attempt UNIX smb encryption. */ if (!NT_STATUS_IS_OK(cli_force_encryption(c, username_used, @@ -466,7 +467,7 @@ SMBC_server(TALLOC_CTX *ctx, DEBUG(4,(" SMB encrypt failed\n")); - if (context->smb_encryption_level == 2) { + if (context->internal->smb_encryption_level == 2) { cli_shutdown(c); errno = EPERM; return NULL; @@ -512,7 +513,7 @@ SMBC_server(TALLOC_CTX *ctx, DEBUG(2, ("Server connect ok: //%s/%s: %p\n", server, share, srv)); - DLIST_ADD(context->servers, srv); + DLIST_ADD(context->internal->servers, srv); return srv; failed: @@ -566,7 +567,7 @@ SMBC_attr_server(TALLOC_CTX *ctx, } flags = 0; - if (context->use_kerberos) { + if (context->flags.bits & SMB_CTX_FLAG_USE_KERBEROS) { flags |= CLI_FULL_CONNECTION_USE_KERBEROS; } @@ -586,7 +587,7 @@ SMBC_attr_server(TALLOC_CTX *ctx, return NULL; } - if (context->smb_encryption_level) { + if (context->internal->smb_encryption_level) { /* Attempt UNIX smb encryption. */ if (!NT_STATUS_IS_OK(cli_force_encryption(ipc_cli, *pp_username, @@ -602,7 +603,7 @@ SMBC_attr_server(TALLOC_CTX *ctx, DEBUG(4,(" SMB encrypt failed on IPC$\n")); - if (context->smb_encryption_level == 2) { + if (context->internal->smb_encryption_level == 2) { cli_shutdown(ipc_cli); errno = EPERM; return NULL; @@ -668,7 +669,7 @@ SMBC_attr_server(TALLOC_CTX *ctx, return NULL; } - DLIST_ADD(context->servers, ipc_srv); + DLIST_ADD(context->internal->servers, ipc_srv); } return ipc_srv; diff --git a/source3/libsmb/libsmb_stat.c b/source3/libsmb/libsmb_stat.c index 06238863b7..6072547e08 100644 --- a/source3/libsmb/libsmb_stat.c +++ b/source3/libsmb/libsmb_stat.c @@ -35,7 +35,7 @@ static ino_t generate_inode(SMBCCTX *context, const char *name) { - if (!context || !context->initialized) { + if (!context || !context->internal->initialized) { errno = EINVAL; return -1; @@ -126,7 +126,7 @@ SMBC_stat_ctx(SMBCCTX *context, SMB_INO_T ino = 0; TALLOC_CTX *frame = talloc_stackframe(); - if (!context || !context->initialized) { + if (!context || !context->internal->initialized) { errno = EINVAL; /* Best I can think of ... */ TALLOC_FREE(frame); @@ -157,7 +157,7 @@ SMBC_stat_ctx(SMBCCTX *context, } if (!user || user[0] == (char)0) { - user = talloc_strdup(frame,context->user); + user = talloc_strdup(frame,context->config.user); if (!user) { errno = ENOMEM; TALLOC_FREE(frame); @@ -222,14 +222,14 @@ SMBC_fstat_ctx(SMBCCTX *context, SMB_INO_T ino = 0; TALLOC_CTX *frame = talloc_stackframe(); - if (!context || !context->initialized) { + if (!context || !context->internal->initialized) { errno = EINVAL; TALLOC_FREE(frame); return -1; } - if (!file || !SMBC_dlist_contains(context->files, file)) { + if (!file || !SMBC_dlist_contains(context->internal->files, file)) { errno = EBADF; TALLOC_FREE(frame); return -1; diff --git a/source3/libsmb/libsmb_xattr.c b/source3/libsmb/libsmb_xattr.c index 93ca0706b2..a420299341 100644 --- a/source3/libsmb/libsmb_xattr.c +++ b/source3/libsmb/libsmb_xattr.c @@ -609,7 +609,7 @@ dos_attr_parse(SMBCCTX *context, } attr_strings; /* Determine whether to use old-style or new-style attribute names */ - if (context->full_time_names) { + if (context->internal->full_time_names) { /* new-style names */ attr_strings.create_time_attr = "CREATE_TIME"; attr_strings.access_time_attr = "ACCESS_TIME"; @@ -759,7 +759,7 @@ cacl_get(SMBCCTX *context, } excl_attr_strings; /* Determine whether to use old-style or new-style attribute names */ - if (context->full_time_names) { + if (context->internal->full_time_names) { /* new-style names */ attr_strings.create_time_attr = "CREATE_TIME"; attr_strings.access_time_attr = "ACCESS_TIME"; @@ -1689,7 +1689,7 @@ SMBC_setxattr_ctx(SMBCCTX *context, } attr_strings; TALLOC_CTX *frame = talloc_stackframe(); - if (!context || !context->initialized) { + if (!context || !context->internal->initialized) { errno = EINVAL; /* Best I can think of ... */ TALLOC_FREE(frame); @@ -1721,7 +1721,7 @@ SMBC_setxattr_ctx(SMBCCTX *context, } if (!user || user[0] == (char)0) { - user = talloc_strdup(frame, context->user); + user = talloc_strdup(frame, context->config.user); if (!user) { errno = ENOMEM; TALLOC_FREE(frame); @@ -1893,7 +1893,7 @@ SMBC_setxattr_ctx(SMBCCTX *context, } /* Determine whether to use old-style or new-style attribute names */ - if (context->full_time_names) { + if (context->internal->full_time_names) { /* new-style names */ attr_strings.create_time_attr = "system.dos_attr.CREATE_TIME"; attr_strings.access_time_attr = "system.dos_attr.ACCESS_TIME"; @@ -1984,7 +1984,7 @@ SMBC_getxattr_ctx(SMBCCTX *context, } attr_strings; TALLOC_CTX *frame = talloc_stackframe(); - if (!context || !context->initialized) { + if (!context || !context->internal->initialized) { errno = EINVAL; /* Best I can think of ... */ TALLOC_FREE(frame); @@ -2015,7 +2015,7 @@ SMBC_getxattr_ctx(SMBCCTX *context, } if (!user || user[0] == (char)0) { - user = talloc_strdup(frame, context->user); + user = talloc_strdup(frame, context->config.user); if (!user) { errno = ENOMEM; TALLOC_FREE(frame); @@ -2041,7 +2041,7 @@ SMBC_getxattr_ctx(SMBCCTX *context, } /* Determine whether to use old-style or new-style attribute names */ - if (context->full_time_names) { + if (context->internal->full_time_names) { /* new-style names */ attr_strings.create_time_attr = "system.dos_attr.CREATE_TIME"; attr_strings.access_time_attr = "system.dos_attr.ACCESS_TIME"; @@ -2118,7 +2118,7 @@ SMBC_removexattr_ctx(SMBCCTX *context, char *path = NULL; TALLOC_CTX *frame = talloc_stackframe(); - if (!context || !context->initialized) { + if (!context || !context->internal->initialized) { errno = EINVAL; /* Best I can think of ... */ TALLOC_FREE(frame); @@ -2149,7 +2149,7 @@ SMBC_removexattr_ctx(SMBCCTX *context, } if (!user || user[0] == (char)0) { - user = talloc_strdup(frame, context->user); + user = talloc_strdup(frame, context->config.user); if (!user) { errno = ENOMEM; TALLOC_FREE(frame); @@ -2270,7 +2270,7 @@ SMBC_listxattr_ctx(SMBCCTX *context, ; const char * supported; - if (context->full_time_names) { + if (context->internal->full_time_names) { supported = supported_new; retsize = sizeof(supported_new); } else { -- cgit From 223940d9a887c5b98a5c873797302a6a9407ad7f Mon Sep 17 00:00:00 2001 From: Derrell Lipman Date: Sat, 1 Mar 2008 20:44:21 -0500 Subject: Additional revamped libsmbclient documentation - Ensured that all public functions have documentation in libsmbclient.h - Reformatted for "proper" indentation - Re-added temporarily-disabled alternate authentication function capability Derrell (This used to be commit 64b7150d92849a1e1e2416b9dcc12fae8d6bea99) --- source3/libsmb/libsmb_cache.c | 54 +- source3/libsmb/libsmb_compat.c | 52 +- source3/libsmb/libsmb_context.c | 1508 +++++++++++++++++++++----------------- source3/libsmb/libsmb_dir.c | 930 +++++++++++------------ source3/libsmb/libsmb_file.c | 393 +++++----- source3/libsmb/libsmb_misc.c | 10 +- source3/libsmb/libsmb_path.c | 114 +-- source3/libsmb/libsmb_printjob.c | 178 ++--- source3/libsmb/libsmb_server.c | 275 +++---- source3/libsmb/libsmb_stat.c | 132 ++-- source3/libsmb/libsmb_xattr.c | 636 ++++++++-------- 11 files changed, 2232 insertions(+), 2050 deletions(-) (limited to 'source3/libsmb') diff --git a/source3/libsmb/libsmb_cache.c b/source3/libsmb/libsmb_cache.c index 7ff92f1b4e..ff13fd7eac 100644 --- a/source3/libsmb/libsmb_cache.c +++ b/source3/libsmb/libsmb_cache.c @@ -35,10 +35,10 @@ struct smbc_server_cache { char *workgroup; char *username; SMBCSRV *server; - + struct smbc_server_cache *next, *prev; }; - + /* @@ -54,51 +54,51 @@ SMBC_add_cached_server(SMBCCTX * context, const char * username) { struct smbc_server_cache * srvcache = NULL; - + if (!(srvcache = SMB_MALLOC_P(struct smbc_server_cache))) { errno = ENOMEM; DEBUG(3, ("Not enough space for server cache allocation\n")); return 1; } - + ZERO_STRUCTP(srvcache); - + srvcache->server = newsrv; - + srvcache->server_name = SMB_STRDUP(server); if (!srvcache->server_name) { errno = ENOMEM; goto failed; } - + srvcache->share_name = SMB_STRDUP(share); if (!srvcache->share_name) { errno = ENOMEM; goto failed; } - + srvcache->workgroup = SMB_STRDUP(workgroup); if (!srvcache->workgroup) { errno = ENOMEM; goto failed; } - + srvcache->username = SMB_STRDUP(username); if (!srvcache->username) { errno = ENOMEM; goto failed; } - + DLIST_ADD((context->cache.server_cache_data), srvcache); return 0; - - failed: + +failed: SAFE_FREE(srvcache->server_name); SAFE_FREE(srvcache->share_name); SAFE_FREE(srvcache->workgroup); SAFE_FREE(srvcache->username); SAFE_FREE(srvcache); - + return 1; } @@ -117,19 +117,19 @@ SMBC_get_cached_server(SMBCCTX * context, const char * user) { struct smbc_server_cache * srv = NULL; - + /* Search the cache lines */ for (srv = context->cache.server_cache_data; srv; srv = srv->next) { - + if (strcmp(server,srv->server_name) == 0 && strcmp(workgroup,srv->workgroup) == 0 && strcmp(user, srv->username) == 0) { - + /* If the share name matches, we're cool */ if (strcmp(share, srv->share_name) == 0) { return srv->server; } - + /* * We only return an empty share name or the attribute * server on an exact match (which would have been @@ -137,7 +137,7 @@ SMBC_get_cached_server(SMBCCTX * context, */ if (*share == '\0' || strcmp(share, "*IPC$") == 0) continue; - + /* * Never return an empty share name or the attribute * server if it wasn't what was requested. @@ -145,7 +145,7 @@ SMBC_get_cached_server(SMBCCTX * context, if (*srv->share_name == '\0' || strcmp(srv->share_name, "*IPC$") == 0) continue; - + /* * If we're only allowing one share per server, then * a connection to the server (other than the @@ -164,7 +164,7 @@ SMBC_get_cached_server(SMBCCTX * context, context->cache.remove_cached_server_fn(context, srv->server); continue; } - + /* * Save the new share name. We've * disconnected from the old share, and are @@ -179,13 +179,13 @@ SMBC_get_cached_server(SMBCCTX * context, context->cache.remove_cached_server_fn(context, srv->server); continue; } - - + + return srv->server; } } } - + return NULL; } @@ -200,10 +200,10 @@ SMBC_remove_cached_server(SMBCCTX * context, SMBCSRV * server) { struct smbc_server_cache * srv = NULL; - + for (srv = context->cache.server_cache_data; srv; srv = srv->next) { if (server == srv->server) { - + /* remove this sucker */ DLIST_REMOVE(context->cache.server_cache_data, srv); SAFE_FREE(srv->server_name); @@ -229,13 +229,13 @@ SMBC_purge_cached_servers(SMBCCTX * context) struct smbc_server_cache * srv; struct smbc_server_cache * next; int could_not_purge_all = 0; - + for (srv = context->cache.server_cache_data, next = (srv ? srv->next :NULL); srv; srv = next, next = (srv ? srv->next : NULL)) { - + if (SMBC_remove_unused_server(context, srv->server)) { /* could not be removed */ could_not_purge_all = 1; diff --git a/source3/libsmb/libsmb_compat.c b/source3/libsmb/libsmb_compat.c index 7a0536a92d..9ef5e51fa9 100644 --- a/source3/libsmb/libsmb_compat.c +++ b/source3/libsmb/libsmb_compat.c @@ -55,11 +55,11 @@ static int add_fd(SMBCFILE * file) { struct smbc_compat_fdlist * f = smbc_compat_fd_avail; - + if (f) { /* We found one that's available */ DLIST_REMOVE(smbc_compat_fd_avail, f); - + } else { /* * None were available, so allocate one. Keep the number of @@ -72,19 +72,19 @@ add_fd(SMBCFILE * file) errno = EMFILE; return -1; } - + f = SMB_MALLOC_P(struct smbc_compat_fdlist); if (!f) { errno = ENOMEM; return -1; } - + f->fd = SMBC_BASE_FD + smbc_compat_nextfd++; } - + f->file = file; DLIST_ADD(smbc_compat_fd_in_use, f); - + return f->fd; } @@ -95,13 +95,13 @@ static int del_fd(int fd) { struct smbc_compat_fdlist * f = smbc_compat_fd_in_use; - + while (f) { if (f->fd == fd) break; f = f->next; } - + if (f) { /* found */ DLIST_REMOVE(smbc_compat_fd_in_use, f); @@ -111,7 +111,7 @@ del_fd(int fd) } return 1; } - + int @@ -122,17 +122,17 @@ smbc_init(smbc_get_auth_data_fn fn, statcont = smbc_new_context(); if (!statcont) return -1; - + smbc_setDebug(statcont, debug); smbc_setFunctionAuthData(statcont, fn); - + if (!smbc_init_context(statcont)) { smbc_free_context(statcont, False); return -1; } - + smbc_compat_initialized = 1; - + return 0; } return 0; @@ -143,11 +143,11 @@ SMBCCTX * smbc_set_context(SMBCCTX * context) { SMBCCTX *old_context = statcont; - + if (context) { /* Save provided context. It must have been initialized! */ statcont = context; - + /* You'd better know what you're doing. We won't help you. */ smbc_compat_initialized = 1; } @@ -163,11 +163,11 @@ smbc_open(const char *furl, { SMBCFILE * file; int fd; - + file = smbc_getFunctionOpen(statcont)(statcont, furl, flags, mode); if (!file) return -1; - + fd = add_fd(file); if (fd == -1) smbc_getFunctionClose(statcont)(statcont, file); @@ -181,11 +181,11 @@ smbc_creat(const char *furl, { SMBCFILE * file; int fd; - + file = smbc_getFunctionCreat(statcont)(statcont, furl, mode); if (!file) return -1; - + fd = add_fd(file); if (fd == -1) { /* Hmm... should we delete the file too ? I guess we could try */ @@ -250,15 +250,15 @@ smbc_opendir(const char *durl) { SMBCFILE * file; int fd; - + file = smbc_getFunctionOpendir(statcont)(statcont, durl); if (!file) return -1; - + fd = add_fd(file); if (fd == -1) smbc_getFunctionClosedir(statcont)(statcont, file); - + return fd; } @@ -357,14 +357,14 @@ smbc_utime(const char *fname, struct utimbuf *utbuf) { struct timeval tv[2]; - + if (utbuf == NULL) return smbc_getFunctionUtimes(statcont)(statcont, fname, NULL); - + tv[0].tv_sec = utbuf->actime; tv[1].tv_sec = utbuf->modtime; tv[0].tv_usec = tv[1].tv_usec = 0; - + return smbc_getFunctionUtimes(statcont)(statcont, fname, tv); } #endif @@ -519,7 +519,7 @@ int smbc_open_print_job(const char *fname) { SMBCFILE * file; - + file = smbc_getFunctionOpenPrintJob(statcont)(statcont, fname); if (!file) return -1; return file->cli_fd; diff --git a/source3/libsmb/libsmb_context.c b/source3/libsmb/libsmb_context.c index 6b7a19e1e4..8af49d12be 100644 --- a/source3/libsmb/libsmb_context.c +++ b/source3/libsmb/libsmb_context.c @@ -40,88 +40,88 @@ static int SMBC_initialized = 0; SMBCCTX * smbc_new_context(void) { - SMBCCTX *context; - - /* - * All newly added context fields should be placed in SMBC_internal_data, - * not directly in SMBCCTX. - */ -# undef OLD -# define OLD(field) context->field -# undef NEW -# define NEW(field) context->internal->field - - context = SMB_MALLOC_P(SMBCCTX); - if (!context) { - errno = ENOMEM; - return NULL; - } - - ZERO_STRUCTP(context); - - context->internal = SMB_MALLOC_P(struct SMBC_internal_data); - if (!context->internal) { - SAFE_FREE(context); - errno = ENOMEM; - return NULL; - } - - /* Initialize the context and establish reasonable defaults */ - ZERO_STRUCTP(context->internal); - - OLD(config.debug) = 0; - OLD(config.timeout) = 20000; /* 20 seconds */ - - NEW(full_time_names) = False; - NEW(share_mode) = SMBC_SHAREMODE_DENY_NONE; - NEW(smb_encryption_level) = 0; - NEW(browse_max_lmb_count) = 3; /* # LMBs to query */ - NEW(urlencode_readdir_entries) = False; - NEW(one_share_per_server) = False; - - OLD(server.get_auth_data_fn) = SMBC_get_auth_data; - OLD(server.check_server_fn) = SMBC_check_server; - OLD(server.remove_unused_server_fn) = SMBC_remove_unused_server; - - OLD(cache.server_cache_data) = NULL; - OLD(cache.add_cached_server_fn) = SMBC_add_cached_server; - OLD(cache.get_cached_server_fn) = SMBC_get_cached_server; - OLD(cache.remove_cached_server_fn) = SMBC_remove_cached_server; - OLD(cache.purge_cached_servers_fn) = SMBC_purge_cached_servers; - - OLD(posix_emu.open_fn) = SMBC_open_ctx; - OLD(posix_emu.creat_fn) = SMBC_creat_ctx; - OLD(posix_emu.read_fn) = SMBC_read_ctx; - OLD(posix_emu.write_fn) = SMBC_write_ctx; - OLD(posix_emu.close_fn) = SMBC_close_ctx; - OLD(posix_emu.unlink_fn) = SMBC_unlink_ctx; - OLD(posix_emu.rename_fn) = SMBC_rename_ctx; - OLD(posix_emu.lseek_fn) = SMBC_lseek_ctx; - NEW(posix_emu.ftruncate_fn) = SMBC_ftruncate_ctx; - OLD(posix_emu.stat_fn) = SMBC_stat_ctx; - OLD(posix_emu.fstat_fn) = SMBC_fstat_ctx; - OLD(posix_emu.opendir_fn) = SMBC_opendir_ctx; - OLD(posix_emu.closedir_fn) = SMBC_closedir_ctx; - OLD(posix_emu.readdir_fn) = SMBC_readdir_ctx; - OLD(posix_emu.getdents_fn) = SMBC_getdents_ctx; - OLD(posix_emu.mkdir_fn) = SMBC_mkdir_ctx; - OLD(posix_emu.rmdir_fn) = SMBC_rmdir_ctx; - OLD(posix_emu.telldir_fn) = SMBC_telldir_ctx; - OLD(posix_emu.lseekdir_fn) = SMBC_lseekdir_ctx; - OLD(posix_emu.fstatdir_fn) = SMBC_fstatdir_ctx; - OLD(posix_emu.chmod_fn) = SMBC_chmod_ctx; - OLD(posix_emu.utimes_fn) = SMBC_utimes_ctx; - OLD(posix_emu.setxattr_fn) = SMBC_setxattr_ctx; - OLD(posix_emu.getxattr_fn) = SMBC_getxattr_ctx; - OLD(posix_emu.removexattr_fn) = SMBC_removexattr_ctx; - OLD(posix_emu.listxattr_fn) = SMBC_listxattr_ctx; - - OLD(printing.open_print_job_fn) = SMBC_open_print_job_ctx; - OLD(printing.print_file_fn) = SMBC_print_file_ctx; - OLD(printing.list_print_jobs_fn) = SMBC_list_print_jobs_ctx; - OLD(printing.unlink_print_job_fn) = SMBC_unlink_print_job_ctx; - - return context; + SMBCCTX *context; + + /* + * All newly added context fields should be placed in + * SMBC_internal_data, not directly in SMBCCTX. + */ +#undef OLD +#define OLD(field) context->field +#undef NEW +#define NEW(field) context->internal->field + + context = SMB_MALLOC_P(SMBCCTX); + if (!context) { + errno = ENOMEM; + return NULL; + } + + ZERO_STRUCTP(context); + + context->internal = SMB_MALLOC_P(struct SMBC_internal_data); + if (!context->internal) { + SAFE_FREE(context); + errno = ENOMEM; + return NULL; + } + + /* Initialize the context and establish reasonable defaults */ + ZERO_STRUCTP(context->internal); + + OLD(config.debug) = 0; + OLD(config.timeout) = 20000; /* 20 seconds */ + + NEW(full_time_names) = False; + NEW(share_mode) = SMBC_SHAREMODE_DENY_NONE; + NEW(smb_encryption_level) = 0; + OLD(options.browse_max_lmb_count) = 3; /* # LMBs to query */ + OLD(options.urlencode_readdir_entries) = False; + OLD(options.one_share_per_server) = False; + + OLD(server.get_auth_data_fn) = SMBC_get_auth_data; + OLD(server.check_server_fn) = SMBC_check_server; + OLD(server.remove_unused_server_fn) = SMBC_remove_unused_server; + + OLD(cache.server_cache_data) = NULL; + OLD(cache.add_cached_server_fn) = SMBC_add_cached_server; + OLD(cache.get_cached_server_fn) = SMBC_get_cached_server; + OLD(cache.remove_cached_server_fn) = SMBC_remove_cached_server; + OLD(cache.purge_cached_servers_fn) = SMBC_purge_cached_servers; + + OLD(posix_emu.open_fn) = SMBC_open_ctx; + OLD(posix_emu.creat_fn) = SMBC_creat_ctx; + OLD(posix_emu.read_fn) = SMBC_read_ctx; + OLD(posix_emu.write_fn) = SMBC_write_ctx; + OLD(posix_emu.close_fn) = SMBC_close_ctx; + OLD(posix_emu.unlink_fn) = SMBC_unlink_ctx; + OLD(posix_emu.rename_fn) = SMBC_rename_ctx; + OLD(posix_emu.lseek_fn) = SMBC_lseek_ctx; + NEW(posix_emu.ftruncate_fn) = SMBC_ftruncate_ctx; + OLD(posix_emu.stat_fn) = SMBC_stat_ctx; + OLD(posix_emu.fstat_fn) = SMBC_fstat_ctx; + OLD(posix_emu.opendir_fn) = SMBC_opendir_ctx; + OLD(posix_emu.closedir_fn) = SMBC_closedir_ctx; + OLD(posix_emu.readdir_fn) = SMBC_readdir_ctx; + OLD(posix_emu.getdents_fn) = SMBC_getdents_ctx; + OLD(posix_emu.mkdir_fn) = SMBC_mkdir_ctx; + OLD(posix_emu.rmdir_fn) = SMBC_rmdir_ctx; + OLD(posix_emu.telldir_fn) = SMBC_telldir_ctx; + OLD(posix_emu.lseekdir_fn) = SMBC_lseekdir_ctx; + OLD(posix_emu.fstatdir_fn) = SMBC_fstatdir_ctx; + OLD(posix_emu.chmod_fn) = SMBC_chmod_ctx; + OLD(posix_emu.utimes_fn) = SMBC_utimes_ctx; + OLD(posix_emu.setxattr_fn) = SMBC_setxattr_ctx; + OLD(posix_emu.getxattr_fn) = SMBC_getxattr_ctx; + OLD(posix_emu.removexattr_fn) = SMBC_removexattr_ctx; + OLD(posix_emu.listxattr_fn) = SMBC_listxattr_ctx; + + OLD(printing.open_print_job_fn) = SMBC_open_print_job_ctx; + OLD(printing.print_file_fn) = SMBC_print_file_ctx; + OLD(printing.list_print_jobs_fn) = SMBC_list_print_jobs_ctx; + OLD(printing.unlink_print_job_fn) = SMBC_unlink_print_job_ctx; + + return context; #undef OLD #undef NEW } @@ -137,420 +137,268 @@ int smbc_free_context(SMBCCTX *context, int shutdown_ctx) { - if (!context) { - errno = EBADF; - return 1; - } - - if (shutdown_ctx) { - SMBCFILE * f; - DEBUG(1,("Performing aggressive shutdown.\n")); - - f = context->internal->files; - while (f) { - (context->posix_emu.close_fn)(context, f); - f = f->next; + if (!context) { + errno = EBADF; + return 1; } - context->internal->files = NULL; - /* First try to remove the servers the nice way. */ - if (context->cache.purge_cached_servers_fn(context)) { - SMBCSRV * s; - SMBCSRV * next; - DEBUG(1, ("Could not purge all servers, " - "Nice way shutdown failed.\n")); - s = context->internal->servers; - while (s) { - DEBUG(1, ("Forced shutdown: %p (fd=%d)\n", - s, s->cli->fd)); - cli_shutdown(s->cli); - (context->cache.remove_cached_server_fn)(context, - s); - next = s->next; - DLIST_REMOVE(context->internal->servers, s); - SAFE_FREE(s); - s = next; - } - context->internal->servers = NULL; - } - } - else { - /* This is the polite way */ - if ((context->cache.purge_cached_servers_fn)(context)) { - DEBUG(1, ("Could not purge all servers, " - "free_context failed.\n")); - errno = EBUSY; - return 1; - } - if (context->internal->servers) { - DEBUG(1, ("Active servers in context, " - "free_context failed.\n")); - errno = EBUSY; - return 1; + if (shutdown_ctx) { + SMBCFILE * f; + DEBUG(1,("Performing aggressive shutdown.\n")); + + f = context->internal->files; + while (f) { + (context->posix_emu.close_fn)(context, f); + f = f->next; + } + context->internal->files = NULL; + + /* First try to remove the servers the nice way. */ + if (context->cache.purge_cached_servers_fn(context)) { + SMBCSRV * s; + SMBCSRV * next; + DEBUG(1, ("Could not purge all servers, " + "Nice way shutdown failed.\n")); + s = context->internal->servers; + while (s) { + DEBUG(1, ("Forced shutdown: %p (fd=%d)\n", + s, s->cli->fd)); + cli_shutdown(s->cli); + (context->cache.remove_cached_server_fn)(context, + s); + next = s->next; + DLIST_REMOVE(context->internal->servers, s); + SAFE_FREE(s); + s = next; + } + context->internal->servers = NULL; + } } - if (context->internal->files) { - DEBUG(1, ("Active files in context, " - "free_context failed.\n")); - errno = EBUSY; - return 1; + else { + /* This is the polite way */ + if ((context->cache.purge_cached_servers_fn)(context)) { + DEBUG(1, ("Could not purge all servers, " + "free_context failed.\n")); + errno = EBUSY; + return 1; + } + if (context->internal->servers) { + DEBUG(1, ("Active servers in context, " + "free_context failed.\n")); + errno = EBUSY; + return 1; + } + if (context->internal->files) { + DEBUG(1, ("Active files in context, " + "free_context failed.\n")); + errno = EBUSY; + return 1; + } } - } - - /* Things we have to clean up */ - SAFE_FREE(context->config.workgroup); - SAFE_FREE(context->config.netbios_name); - SAFE_FREE(context->config.user); - - DEBUG(3, ("Context %p successfully freed\n", context)); - SAFE_FREE(context); - return 0; + + /* Things we have to clean up */ + SAFE_FREE(context->config.workgroup); + SAFE_FREE(context->config.netbios_name); + SAFE_FREE(context->config.user); + + DEBUG(3, ("Context %p successfully freed\n", context)); + SAFE_FREE(context); + return 0; } -/* - * Each time the context structure is changed, we have binary backward - * compatibility issues. Instead of modifying the public portions of the - * context structure to add new options, instead, we put them in the internal - * portion of the context structure and provide a set function for these new - * options. +/** + * Deprecated interface. Do not use. Instead, use the various + * smbc_setOption*() functions or smbc_setFunctionAuthDataWithContext(). */ void smbc_option_set(SMBCCTX *context, char *option_name, ... /* option_value */) { - va_list ap; - union { - int i; - bool b; - smbc_get_auth_data_with_context_fn auth_fn; - void *v; - const char *s; - } option_value; - - va_start(ap, option_name); - - if (strcmp(option_name, "debug_to_stderr") == 0) { - /* - * Log to standard error instead of standard output. - */ - option_value.b = (bool) va_arg(ap, int); - context->internal->debug_stderr = option_value.b; - - } else if (strcmp(option_name, "full_time_names") == 0) { - /* - * Use new-style time attribute names, e.g. WRITE_TIME rather - * than the old-style names such as M_TIME. This allows also - * setting/getting CREATE_TIME which was previously - * unimplemented. (Note that the old C_TIME was supposed to - * be CHANGE_TIME but was confused and sometimes referred to - * CREATE_TIME.) - */ - option_value.b = (bool) va_arg(ap, int); - context->internal->full_time_names = option_value.b; - - } else if (strcmp(option_name, "open_share_mode") == 0) { - /* - * The share mode to use for files opened with - * SMBC_open_ctx(). The default is SMBC_SHAREMODE_DENY_NONE. - */ - option_value.i = va_arg(ap, int); - context->internal->share_mode = (smbc_share_mode) option_value.i; - - } else if (strcmp(option_name, "user_data") == 0) { - /* - * Save a user data handle which may be retrieved by the user - * with smbc_option_get() - */ - 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; - } - } else if (strcmp(option_name, "browse_max_lmb_count") == 0) { - /* - * From how many local master browsers should the list of - * workgroups be retrieved? It can take up to 12 minutes or - * longer after a server becomes a local master browser, for - * it to have the entire browse list (the list of - * workgroups/domains) from an entire network. Since a client - * never knows which local master browser will be found first, - * the one which is found first and used to retrieve a browse - * list may have an incomplete or empty browse list. By - * requesting the browse list from multiple local master - * browsers, a more complete list can be generated. For small - * networks (few workgroups), it is recommended that this - * value be set to 0, causing the browse lists from all found - * local master browsers to be retrieved and merged. For - * networks with many workgroups, a suitable value for this - * variable is probably somewhere around 3. (Default: 3). - */ - option_value.i = va_arg(ap, int); - context->internal->browse_max_lmb_count = option_value.i; + va_list ap; + union { + int i; + bool b; + smbc_get_auth_data_with_context_fn auth_fn; + void *v; + const char *s; + } option_value; - } else if (strcmp(option_name, "urlencode_readdir_entries") == 0) { - /* - * There is a difference in the desired return strings from - * smbc_readdir() depending upon whether the filenames are to - * be displayed to the user, or whether they are to be - * appended to the path name passed to smbc_opendir() to call - * a further smbc_ function (e.g. open the file with - * smbc_open()). In the former case, the filename should be - * in "human readable" form. In the latter case, the smbc_ - * functions expect a URL which must be url-encoded. Those - * functions decode the URL. If, for example, smbc_readdir() - * returned a file name of "abc%20def.txt", passing a path - * with this file name attached to smbc_open() would cause - * smbc_open to attempt to open the file "abc def.txt" since - * the %20 is decoded into a space. - * - * Set this option to True if the names returned by - * smbc_readdir() should be url-encoded such that they can be - * passed back to another smbc_ call. Set it to False if the - * names returned by smbc_readdir() are to be presented to the - * user. - * - * For backwards compatibility, this option defaults to False. - */ - option_value.b = (bool) va_arg(ap, int); - context->internal->urlencode_readdir_entries = option_value.b; + va_start(ap, option_name); - } else if (strcmp(option_name, "one_share_per_server") == 0) { - /* - * Some Windows versions appear to have a limit to the number - * of concurrent SESSIONs and/or TREE CONNECTions. In - * one-shot programs (i.e. the program runs and then quickly - * ends, thereby shutting down all connections), it is - * probably reasonable to establish a new connection for each - * share. In long-running applications, the limitation can be - * avoided by using only a single connection to each server, - * and issuing a new TREE CONNECT when the share is accessed. - */ - option_value.b = (bool) va_arg(ap, int); - context->options.one_share_per_server = option_value.b; - - } else if (strcmp(option_name, "use_kerberos") == 0) { - option_value.b = (bool) va_arg(ap, int); - if (option_value.b) { - context->flags.bits |= SMB_CTX_FLAG_USE_KERBEROS; - } else { - context->flags.bits &= ~SMB_CTX_FLAG_USE_KERBEROS; - } - - } else if (strcmp(option_name, "fallback_after_kerberos") == 0) { - option_value.b = (bool) va_arg(ap, int); - if (option_value.b) { - context->flags.bits |= SMB_CTX_FLAG_FALLBACK_AFTER_KERBEROS; - } else { - context->flags.bits &= ~SMB_CTX_FLAG_FALLBACK_AFTER_KERBEROS; + if (strcmp(option_name, "debug_to_stderr") == 0) { + option_value.b = (bool) va_arg(ap, int); + smbc_setOptionDebugToStderr(context, option_value.b); + + } else if (strcmp(option_name, "full_time_names") == 0) { + option_value.b = (bool) va_arg(ap, int); + smbc_setOptionFullTimeNames(context, option_value.b); + + } else if (strcmp(option_name, "open_share_mode") == 0) { + option_value.i = va_arg(ap, int); + smbc_setOptionOpenShareMode(context, option_value.i); + + } else if (strcmp(option_name, "auth_function") == 0) { + option_value.auth_fn = + va_arg(ap, smbc_get_auth_data_with_context_fn); + smbc_setFunctionAuthDataWithContext(context, option_value.auth_fn); + + } else if (strcmp(option_name, "user_data") == 0) { + option_value.v = va_arg(ap, void *); + smbc_setOptionUserData(context, option_value.v); + + } else if (strcmp(option_name, "smb_encrypt_level") == 0) { + option_value.s = va_arg(ap, const char *); + if (strcmp(option_value.s, "none") == 0) { + smbc_setOptionSmbEncryptionLevel(context, + SMBC_ENCRYPTLEVEL_NONE); + } else if (strcmp(option_value.s, "request") == 0) { + smbc_setOptionSmbEncryptionLevel(context, + SMBC_ENCRYPTLEVEL_REQUEST); + } else if (strcmp(option_value.s, "require") == 0) { + smbc_setOptionSmbEncryptionLevel(context, + SMBC_ENCRYPTLEVEL_REQUIRE); + } + + } else if (strcmp(option_name, "browse_max_lmb_count") == 0) { + option_value.i = va_arg(ap, int); + smbc_setOptionBrowseMaxLmbCount(context, option_value.i); + + } else if (strcmp(option_name, "urlencode_readdir_entries") == 0) { + option_value.b = (bool) va_arg(ap, int); + smbc_setOptionUrlEncodeReaddirEntries(context, option_value.b); + + } else if (strcmp(option_name, "one_share_per_server") == 0) { + option_value.b = (bool) va_arg(ap, int); + smbc_setOptionOneSharePerServer(context, option_value.b); + + } else if (strcmp(option_name, "use_kerberos") == 0) { + option_value.b = (bool) va_arg(ap, int); + smbc_setOptionUseKerberos(context, option_value.b); + + } else if (strcmp(option_name, "fallback_after_kerberos") == 0) { + option_value.b = (bool) va_arg(ap, int); + smbc_setOptionFallbackAfterKerberos(context, option_value.b); + + } else if (strcmp(option_name, "no_auto_anonymous_login") == 0) { + option_value.b = (bool) va_arg(ap, int); + smbc_setOptionNoAutoAnonymousLogin(context, option_value.b); } - } else if (strcmp(option_name, "no_auto_anonymous_login") == 0) { - option_value.b = (bool) va_arg(ap, int); - if (option_value.b) { - context->flags.bits |= SMBCCTX_FLAG_NO_AUTO_ANONYMOUS_LOGON; - } else { - context->flags.bits &= ~SMBCCTX_FLAG_NO_AUTO_ANONYMOUS_LOGON; - } - } - - va_end(ap); + va_end(ap); } /* - * Retrieve the current value of an option + * Deprecated interface. Do not use. Instead, use the various + * smbc_getOption*() functions. */ void * smbc_option_get(SMBCCTX *context, char *option_name) { - int bits; - - if (strcmp(option_name, "debug_stderr") == 0) { - /* - * Log to standard error instead of standard output. - */ + int bits; + + if (strcmp(option_name, "debug_stderr") == 0) { #if defined(__intptr_t_defined) || defined(HAVE_INTPTR_T) - return (void *) (intptr_t) context->internal->debug_stderr; + return (void *) (intptr_t) smbc_getOptionDebugToStderr(context); #else - return (void *) context->internal->debug_stderr; + return (void *) smbc_getOptionDebugToStderr(context); #endif - - } else if (strcmp(option_name, "full_time_names") == 0) { - /* - * Use new-style time attribute names, e.g. WRITE_TIME rather - * than the old-style names such as M_TIME. This allows also - * setting/getting CREATE_TIME which was previously - * unimplemented. (Note that the old C_TIME was supposed to - * be CHANGE_TIME but was confused and sometimes referred to - * CREATE_TIME.) - */ + + } else if (strcmp(option_name, "full_time_names") == 0) { #if defined(__intptr_t_defined) || defined(HAVE_INTPTR_T) - return (void *) (intptr_t) context->internal->full_time_names; + return (void *) (intptr_t) smbc_getOptionFullTimeNames(context); #else - return (void *) context->internal->full_time_names; + return (void *) smbc_getOptionFullTimeNames(context); #endif - - } else if (strcmp(option_name, "user_data") == 0) { - /* - * Return the user data handle which was saved by the user - * with smbc_option_set() - */ - 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; - } - } + + } else if (strcmp(option_name, "open_share_mode") == 0) { #if defined(__intptr_t_defined) || defined(HAVE_INTPTR_T) - return (void *) (intptr_t) (bool) (num_servers > 0); + return (void *) (intptr_t) smbc_getOptionOpenShareMode(context); #else - return (void *) (bool) (num_servers > 0); + return (void *) smbc_getOptionOpenShareMode(context); #endif - - } else if (strcmp(option_name, "browse_max_lmb_count") == 0) { - /* - * From how many local master browsers should the list of - * workgroups be retrieved? It can take up to 12 minutes or - * longer after a server becomes a local master browser, for - * it to have the entire browse list (the list of - * workgroups/domains) from an entire network. Since a client - * never knows which local master browser will be found first, - * the one which is found first and used to retrieve a browse - * list may have an incomplete or empty browse list. By - * requesting the browse list from multiple local master - * browsers, a more complete list can be generated. For small - * networks (few workgroups), it is recommended that this - * value be set to 0, causing the browse lists from all found - * local master browsers to be retrieved and merged. For - * networks with many workgroups, a suitable value for this - * variable is probably somewhere around 3. (Default: 3). - */ + + } else if (strcmp(option_name, "auth_function") == 0) { + return (void *) smbc_getFunctionAuthDataWithContext(context); + + } else if (strcmp(option_name, "user_data") == 0) { + return smbc_getOptionUserData(context); + + } else if (strcmp(option_name, "smb_encrypt_level") == 0) { + switch(smbc_getOptionSmbEncryptionLevel(context)) + { + case 0: + return (void *) "none"; + case 1: + return (void *) "request"; + case 2: + return (void *) "require"; + } + + } else if (strcmp(option_name, "smb_encrypt_on") == 0) { + 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; + } + } #if defined(__intptr_t_defined) || defined(HAVE_INTPTR_T) - return (void *) (intptr_t) context->internal->browse_max_lmb_count; + return (void *) (intptr_t) (bool) (num_servers > 0); #else - return (void *) context->internal->browse_max_lmb_count; + return (void *) (bool) (num_servers > 0); #endif - - } else if (strcmp(option_name, "urlencode_readdir_entries") == 0) { - /* - * There is a difference in the desired return strings from - * smbc_readdir() depending upon whether the filenames are to - * be displayed to the user, or whether they are to be - * appended to the path name passed to smbc_opendir() to call - * a further smbc_ function (e.g. open the file with - * smbc_open()). In the former case, the filename should be - * in "human readable" form. In the latter case, the smbc_ - * functions expect a URL which must be url-encoded. Those - * functions decode the URL. If, for example, smbc_readdir() - * returned a file name of "abc%20def.txt", passing a path - * with this file name attached to smbc_open() would cause - * smbc_open to attempt to open the file "abc def.txt" since - * the %20 is decoded into a space. - * - * Set this option to True if the names returned by - * smbc_readdir() should be url-encoded such that they can be - * passed back to another smbc_ call. Set it to False if the - * names returned by smbc_readdir() are to be presented to the - * user. - * - * For backwards compatibility, this option defaults to False. - */ + + } else if (strcmp(option_name, "browse_max_lmb_count") == 0) { #if defined(__intptr_t_defined) || defined(HAVE_INTPTR_T) - return (void *)(intptr_t) context->internal->urlencode_readdir_entries; + return (void *) (intptr_t) smbc_getOptionBrowseMaxLmbCount(context); #else - return (void *) (bool) context->internal->urlencode_readdir_entries; + return (void *) smbc_getOptionBrowseMaxLmbCount(context); #endif - - } else if (strcmp(option_name, "one_share_per_server") == 0) { - /* - * Some Windows versions appear to have a limit to the number - * of concurrent SESSIONs and/or TREE CONNECTions. In - * one-shot programs (i.e. the program runs and then quickly - * ends, thereby shutting down all connections), it is - * probably reasonable to establish a new connection for each - * share. In long-running applications, the limitation can be - * avoided by using only a single connection to each server, - * and issuing a new TREE CONNECT when the share is accessed. - */ + + } else if (strcmp(option_name, "urlencode_readdir_entries") == 0) { #if defined(__intptr_t_defined) || defined(HAVE_INTPTR_T) - return (void *) (intptr_t) context->internal->one_share_per_server; + return (void *)(intptr_t) smbc_getOptionUrlEncodeReaddirEntries(context); #else - return (void *) (bool) context->internal->one_share_per_server; + return (void *) (bool) smbc_getOptionUrlEncodeReaddirEntries(context); #endif - - } else if (strcmp(option_name, "use_kerberos") == 0) { - bits = context->flags.bits; + + } else if (strcmp(option_name, "one_share_per_server") == 0) { #if defined(__intptr_t_defined) || defined(HAVE_INTPTR_T) - return (context->flags.bits & SMB_CTX_FLAG_USE_KERBEROS - ? (void *) (intptr_t) 1 - : (void *) (intptr_t) 0); + return (void *) (intptr_t) smbc_getOptionOneSharePerServer(context); #else - return (context->flags.bits & SMB_CTX_FLAG_USE_KERBEROS - ? (void *) (bool) 1 - : (void *) (bool) 0); + return (void *) (bool) smbc_getOptionOneSharePerServer(context); #endif - - } else if (strcmp(option_name, "fallback_after_kerberos") == 0) { + + } else if (strcmp(option_name, "use_kerberos") == 0) { + bits = context->flags.bits; #if defined(__intptr_t_defined) || defined(HAVE_INTPTR_T) - return (context->flags.bits & SMB_CTX_FLAG_FALLBACK_AFTER_KERBEROS - ? (void *) (intptr_t) 1 - : (void *) (intptr_t) 0); + return (void *) (intptr_t) smbc_getOptionUseKerberos(context); #else - return (context->flags.bits & SMB_CTX_FLAG_FALLBACK_AFTER_KERBEROS - ? (void *) (bool) 1 - : (void *) (bool) 0); + return (void *) (bool) smbc_getOptionUseKerberos(context); #endif - - } else if (strcmp(option_name, "no_auto_anonymous_login") == 0) { + + } else if (strcmp(option_name, "fallback_after_kerberos") == 0) { #if defined(__intptr_t_defined) || defined(HAVE_INTPTR_T) - return (context->flags.bits & SMBCCTX_FLAG_NO_AUTO_ANONYMOUS_LOGON - ? (void *) (intptr_t) 1 - : (void *) (intptr_t) 0); + return (void *)(intptr_t) smbc_getOptionFallbackAfterKerberos(context); #else - return (context->flags.bits & SMBCCTX_FLAG_NO_AUTO_ANONYMOUS_LOGON - ? (void *) (bool) 1 - : (void *) (bool) 0); + return (void *) (bool) smbc_getOptionFallbackAfterKerberos(context); #endif - } - - return NULL; + + } else if (strcmp(option_name, "no_auto_anonymous_login") == 0) { +#if defined(__intptr_t_defined) || defined(HAVE_INTPTR_T) + return (void *) (intptr_t) smbc_getOptionNoAutoAnonymousLogin(context); +#else + return (void *) (bool) smbc_getOptionNoAutoAnonymousLogin(context); +#endif + } + + return NULL; } @@ -564,175 +412,175 @@ smbc_option_get(SMBCCTX *context, SMBCCTX * smbc_init_context(SMBCCTX *context) { - int pid; - char *user = NULL; - char *home = NULL; - extern bool in_client; - - if (!context) { - errno = EBADF; - return NULL; - } - - /* Do not initialise the same client twice */ - if (context->internal->initialized) { - return 0; - } - - if (!context->server.get_auth_data_fn || - context->config.debug < 0 || - context->config.debug > 100) { + int pid; + char *user = NULL; + char *home = NULL; + extern bool in_client; - errno = EINVAL; - return NULL; - - } - - if (!SMBC_initialized) { - /* - * Do some library-wide intializations the first time we get - * called - */ - bool conf_loaded = False; - TALLOC_CTX *frame = talloc_stackframe(); - - /* Set this to what the user wants */ - DEBUGLEVEL = context->config.debug; - - load_case_tables(); - - setup_logging("libsmbclient", True); - if (context->internal->debug_stderr) { - dbf = x_stderr; - x_setbuf(x_stderr, NULL); + if (!context) { + errno = EBADF; + return NULL; } - /* Here we would open the smb.conf file if needed ... */ + /* Do not initialise the same client twice */ + if (context->internal->initialized) { + return 0; + } - in_client = True; /* FIXME, make a param */ + if (!context->server.get_auth_data_fn || + context->config.debug < 0 || + context->config.debug > 100) { + + errno = EINVAL; + return NULL; + + } - home = getenv("HOME"); - if (home) { - char *conf = NULL; - if (asprintf(&conf, "%s/.smb/smb.conf", home) > 0) { - if (lp_load(conf, True, False, False, True)) { - conf_loaded = True; - } else { - DEBUG(5, ("Could not load config file: %s\n", - conf)); + if (!SMBC_initialized) { + /* + * Do some library-wide intializations the first time we get + * called + */ + bool conf_loaded = False; + TALLOC_CTX *frame = talloc_stackframe(); + + /* Set this to what the user wants */ + DEBUGLEVEL = context->config.debug; + + load_case_tables(); + + setup_logging("libsmbclient", True); + if (context->internal->debug_stderr) { + dbf = x_stderr; + x_setbuf(x_stderr, NULL); } - SAFE_FREE(conf); - } + + /* Here we would open the smb.conf file if needed ... */ + + in_client = True; /* FIXME, make a param */ + + home = getenv("HOME"); + if (home) { + char *conf = NULL; + if (asprintf(&conf, "%s/.smb/smb.conf", home) > 0) { + if (lp_load(conf, True, False, False, True)) { + conf_loaded = True; + } else { + DEBUG(5, ("Could not load config file: %s\n", + conf)); + } + SAFE_FREE(conf); + } + } + + if (!conf_loaded) { + /* + * Well, if that failed, try the get_dyn_CONFIGFILE + * Which points to the standard locn, and if that + * fails, silently ignore it and use the internal + * defaults ... + */ + + if (!lp_load(get_dyn_CONFIGFILE(), True, False, False, False)) { + DEBUG(5, ("Could not load config file: %s\n", + get_dyn_CONFIGFILE())); + } else if (home) { + char *conf; + /* + * We loaded the global config file. Now lets + * load user-specific modifications to the + * global config. + */ + if (asprintf(&conf, + "%s/.smb/smb.conf.append", + home) > 0) { + if (!lp_load(conf, True, False, False, False)) { + DEBUG(10, + ("Could not append config file: " + "%s\n", + conf)); + } + SAFE_FREE(conf); + } + } + } + + load_interfaces(); /* Load the list of interfaces ... */ + + reopen_logs(); /* Get logging working ... */ + + /* + * Block SIGPIPE (from lib/util_sock.c: write()) + * It is not needed and should not stop execution + */ + BlockSignals(True, SIGPIPE); + + /* Done with one-time initialisation */ + SMBC_initialized = 1; + + TALLOC_FREE(frame); } - if (!conf_loaded) { - /* - * Well, if that failed, try the get_dyn_CONFIGFILE - * Which points to the standard locn, and if that - * fails, silently ignore it and use the internal - * defaults ... - */ - - if (!lp_load(get_dyn_CONFIGFILE(), True, False, False, False)) { - DEBUG(5, ("Could not load config file: %s\n", - get_dyn_CONFIGFILE())); - } else if (home) { - char *conf; + if (!context->config.user) { /* - * We loaded the global config file. Now lets - * load user-specific modifications to the - * global config. + * FIXME: Is this the best way to get the user info? */ - if (asprintf(&conf, - "%s/.smb/smb.conf.append", - home) > 0) { - if (!lp_load(conf, True, False, False, False)) { - DEBUG(10, - ("Could not append config file: " - "%s\n", - conf)); - } - SAFE_FREE(conf); + user = getenv("USER"); + /* walk around as "guest" if no username can be found */ + if (!user) context->config.user = SMB_STRDUP("guest"); + else context->config.user = SMB_STRDUP(user); + } + + if (!context->config.netbios_name) { + /* + * We try to get our netbios name from the config. If that + * fails we fall back on constructing our netbios name from + * our hostname etc + */ + if (global_myname()) { + context->config.netbios_name = SMB_STRDUP(global_myname()); + } + else { + /* + * Hmmm, I want to get hostname as well, but I am too + * lazy for the moment + */ + pid = sys_getpid(); + context->config.netbios_name = (char *)SMB_MALLOC(17); + if (!context->config.netbios_name) { + errno = ENOMEM; + return NULL; + } + slprintf(context->config.netbios_name, 16, + "smbc%s%d", context->config.user, pid); + } + } + + DEBUG(1, ("Using netbios name %s.\n", context->config.netbios_name)); + + if (!context->config.workgroup) { + if (lp_workgroup()) { + context->config.workgroup = SMB_STRDUP(lp_workgroup()); + } + else { + /* TODO: Think about a decent default workgroup */ + context->config.workgroup = SMB_STRDUP("samba"); } - } } - load_interfaces(); /* Load the list of interfaces ... */ + DEBUG(1, ("Using workgroup %s.\n", context->config.workgroup)); - reopen_logs(); /* Get logging working ... */ + /* shortest timeout is 1 second */ + if (context->config.timeout > 0 && context->config.timeout < 1000) + context->config.timeout = 1000; /* - * Block SIGPIPE (from lib/util_sock.c: write()) - * It is not needed and should not stop execution + * FIXME: Should we check the function pointers here? */ - BlockSignals(True, SIGPIPE); - /* Done with one-time initialisation */ - SMBC_initialized = 1; + context->internal->initialized = True; - TALLOC_FREE(frame); - } - - if (!context->config.user) { - /* - * FIXME: Is this the best way to get the user info? - */ - user = getenv("USER"); - /* walk around as "guest" if no username can be found */ - if (!user) context->config.user = SMB_STRDUP("guest"); - else context->config.user = SMB_STRDUP(user); - } - - if (!context->config.netbios_name) { - /* - * We try to get our netbios name from the config. If that - * fails we fall back on constructing our netbios name from - * our hostname etc - */ - if (global_myname()) { - context->config.netbios_name = SMB_STRDUP(global_myname()); - } - else { - /* - * Hmmm, I want to get hostname as well, but I am too - * lazy for the moment - */ - pid = sys_getpid(); - context->config.netbios_name = (char *)SMB_MALLOC(17); - if (!context->config.netbios_name) { - errno = ENOMEM; - return NULL; - } - slprintf(context->config.netbios_name, 16, - "smbc%s%d", context->config.user, pid); - } - } - - DEBUG(1, ("Using netbios name %s.\n", context->config.netbios_name)); - - if (!context->config.workgroup) { - if (lp_workgroup()) { - context->config.workgroup = SMB_STRDUP(lp_workgroup()); - } - else { - /* TODO: Think about a decent default workgroup */ - context->config.workgroup = SMB_STRDUP("samba"); - } - } - - DEBUG(1, ("Using workgroup %s.\n", context->config.workgroup)); - - /* shortest timeout is 1 second */ - if (context->config.timeout > 0 && context->config.timeout < 1000) - context->config.timeout = 1000; - - /* - * FIXME: Should we check the function pointers here? - */ - - context->internal->initialized = True; - - return context; + return context; } @@ -740,7 +588,7 @@ smbc_init_context(SMBCCTX *context) const char * smbc_version(void) { - return samba_version_string(); + return samba_version_string(); } @@ -748,56 +596,56 @@ smbc_version(void) char * smbc_getNetbiosName(SMBCCTX *c) { - return c->config.netbios_name; + return c->config.netbios_name; } /** Set the netbios name used for making connections */ void smbc_setNetbiosName(SMBCCTX *c, char * netbios_name) { - c->config.netbios_name = netbios_name; + c->config.netbios_name = netbios_name; } /** Get the workgroup used for making connections */ char * smbc_getWorkgroup(SMBCCTX *c) { - return c->config.workgroup; + return c->config.workgroup; } /** Set the workgroup used for making connections */ void smbc_setWorkgroup(SMBCCTX *c, char * workgroup) { - c->config.workgroup = workgroup; + c->config.workgroup = workgroup; } /** Get the username used for making connections */ char * smbc_getUser(SMBCCTX *c) { - return c->config.user; + return c->config.user; } /** Set the username used for making connections */ void smbc_setUser(SMBCCTX *c, char * user) { - c->config.user = user; + c->config.user = user; } /** Get the debug level */ int smbc_getDebug(SMBCCTX *c) { - return c->config.debug; + return c->config.debug; } /** Set the debug level */ void smbc_setDebug(SMBCCTX *c, int debug) { - c->config.debug = debug; + c->config.debug = debug; } /** @@ -807,7 +655,7 @@ smbc_setDebug(SMBCCTX *c, int debug) int smbc_getTimeout(SMBCCTX *c) { - return c->config.timeout; + return c->config.timeout; } /** @@ -817,43 +665,339 @@ smbc_getTimeout(SMBCCTX *c) void smbc_setTimeout(SMBCCTX *c, int timeout) { - c->config.timeout = timeout; + c->config.timeout = timeout; } -/** Get the function for obtaining authentication data */ +/** Get whether to log to standard error instead of standard output */ +smbc_bool +smbc_getOptionDebugToStderr(SMBCCTX *c) +{ + return c->internal->debug_stderr; +} + +/** Set whether to log to standard error instead of standard output */ +void +smbc_setOptionDebugToStderr(SMBCCTX *c, smbc_bool b) +{ + c->internal->debug_stderr = b; +} + +/** + * Get whether to use new-style time attribute names, e.g. WRITE_TIME rather + * than the old-style names such as M_TIME. This allows also setting/getting + * CREATE_TIME which was previously unimplemented. (Note that the old C_TIME + * was supposed to be CHANGE_TIME but was confused and sometimes referred to + * CREATE_TIME.) + */ +smbc_bool +smbc_getOptionFullTimeNames(SMBCCTX *c) +{ + return c->internal->full_time_names; +} + +/** + * Set whether to use new-style time attribute names, e.g. WRITE_TIME rather + * than the old-style names such as M_TIME. This allows also setting/getting + * CREATE_TIME which was previously unimplemented. (Note that the old C_TIME + * was supposed to be CHANGE_TIME but was confused and sometimes referred to + * CREATE_TIME.) + */ +void +smbc_setOptionFullTimeNames(SMBCCTX *c, smbc_bool b) +{ + c->internal->full_time_names = b; +} + +/** + * Get the share mode to use for files opened with SMBC_open_ctx(). The + * default is SMBC_SHAREMODE_DENY_NONE. + */ +smbc_share_mode +smbc_getOptionOpenShareMode(SMBCCTX *c) +{ + return c->internal->share_mode; +} + +/** + * Set the share mode to use for files opened with SMBC_open_ctx(). The + * default is SMBC_SHAREMODE_DENY_NONE. + */ +void +smbc_setOptionOpenShareMode(SMBCCTX *c, smbc_share_mode share_mode) +{ + c->internal->share_mode = share_mode; +} + +/** Retrieve a previously set user data handle */ +void * +smbc_getOptionUserData(SMBCCTX *c) +{ + return c->internal->user_data; +} + +/** Save a user data handle */ +void +smbc_setOptionUserData(SMBCCTX *c, void *user_data) +{ + c->internal->user_data = user_data; +} +/** Get the encoded value for encryption level. */ +smbc_smb_encrypt_level +smbc_getOptionSmbEncryptionLevel(SMBCCTX *c) +{ + return c->internal->smb_encryption_level; +} + +/** Set the encoded value for encryption level. */ +void +smbc_setOptionSmbEncryptionLevel(SMBCCTX *c, smbc_smb_encrypt_level level) +{ + c->internal->smb_encryption_level = level; +} + +/** + * Get from how many local master browsers should the list of workgroups be + * retrieved. It can take up to 12 minutes or longer after a server becomes a + * local master browser, for it to have the entire browse list (the list of + * workgroups/domains) from an entire network. Since a client never knows + * which local master browser will be found first, the one which is found + * first and used to retrieve a browse list may have an incomplete or empty + * browse list. By requesting the browse list from multiple local master + * browsers, a more complete list can be generated. For small networks (few + * workgroups), it is recommended that this value be set to 0, causing the + * browse lists from all found local master browsers to be retrieved and + * merged. For networks with many workgroups, a suitable value for this + * variable is probably somewhere around 3. (Default: 3). + */ +int +smbc_getOptionBrowseMaxLmbCount(SMBCCTX *c) +{ + return c->options.browse_max_lmb_count; +} + +/** + * Set from how many local master browsers should the list of workgroups be + * retrieved. It can take up to 12 minutes or longer after a server becomes a + * local master browser, for it to have the entire browse list (the list of + * workgroups/domains) from an entire network. Since a client never knows + * which local master browser will be found first, the one which is found + * first and used to retrieve a browse list may have an incomplete or empty + * browse list. By requesting the browse list from multiple local master + * browsers, a more complete list can be generated. For small networks (few + * workgroups), it is recommended that this value be set to 0, causing the + * browse lists from all found local master browsers to be retrieved and + * merged. For networks with many workgroups, a suitable value for this + * variable is probably somewhere around 3. (Default: 3). + */ +void +smbc_setOptionBrowseMaxLmbCount(SMBCCTX *c, int count) +{ + c->options.browse_max_lmb_count = count; +} + +/** + * Get whether to url-encode readdir entries. + * + * There is a difference in the desired return strings from + * smbc_readdir() depending upon whether the filenames are to + * be displayed to the user, or whether they are to be + * appended to the path name passed to smbc_opendir() to call + * a further smbc_ function (e.g. open the file with + * smbc_open()). In the former case, the filename should be + * in "human readable" form. In the latter case, the smbc_ + * functions expect a URL which must be url-encoded. Those + * functions decode the URL. If, for example, smbc_readdir() + * returned a file name of "abc%20def.txt", passing a path + * with this file name attached to smbc_open() would cause + * smbc_open to attempt to open the file "abc def.txt" since + * the %20 is decoded into a space. + * + * Set this option to True if the names returned by + * smbc_readdir() should be url-encoded such that they can be + * passed back to another smbc_ call. Set it to False if the + * names returned by smbc_readdir() are to be presented to the + * user. + * + * For backwards compatibility, this option defaults to False. + */ +smbc_bool +smbc_getOptionUrlEncodeReaddirEntries(SMBCCTX *c) +{ + return c->options.urlencode_readdir_entries; +} + +/** + * Set whether to url-encode readdir entries. + * + * There is a difference in the desired return strings from + * smbc_readdir() depending upon whether the filenames are to + * be displayed to the user, or whether they are to be + * appended to the path name passed to smbc_opendir() to call + * a further smbc_ function (e.g. open the file with + * smbc_open()). In the former case, the filename should be + * in "human readable" form. In the latter case, the smbc_ + * functions expect a URL which must be url-encoded. Those + * functions decode the URL. If, for example, smbc_readdir() + * returned a file name of "abc%20def.txt", passing a path + * with this file name attached to smbc_open() would cause + * smbc_open to attempt to open the file "abc def.txt" since + * the %20 is decoded into a space. + * + * Set this option to True if the names returned by + * smbc_readdir() should be url-encoded such that they can be + * passed back to another smbc_ call. Set it to False if the + * names returned by smbc_readdir() are to be presented to the + * user. + * + * For backwards compatibility, this option defaults to False. + */ +void +smbc_setOptionUrlEncodeReaddirEntries(SMBCCTX *c, smbc_bool b) +{ + c->options.urlencode_readdir_entries = b; +} + +/** + * Get whether to use the same connection for all shares on a server. + * + * Some Windows versions appear to have a limit to the number + * of concurrent SESSIONs and/or TREE CONNECTions. In + * one-shot programs (i.e. the program runs and then quickly + * ends, thereby shutting down all connections), it is + * probably reasonable to establish a new connection for each + * share. In long-running applications, the limitation can be + * avoided by using only a single connection to each server, + * and issuing a new TREE CONNECT when the share is accessed. + */ +smbc_bool +smbc_getOptionOneSharePerServer(SMBCCTX *c) +{ + return c->options.one_share_per_server; +} + +/** + * Set whether to use the same connection for all shares on a server. + * + * Some Windows versions appear to have a limit to the number + * of concurrent SESSIONs and/or TREE CONNECTions. In + * one-shot programs (i.e. the program runs and then quickly + * ends, thereby shutting down all connections), it is + * probably reasonable to establish a new connection for each + * share. In long-running applications, the limitation can be + * avoided by using only a single connection to each server, + * and issuing a new TREE CONNECT when the share is accessed. + */ +void +smbc_setOptionOneSharePerServer(SMBCCTX *c, smbc_bool b) +{ + c->options.one_share_per_server = b; +} + +/** Get whether to enable use of kerberos */ +smbc_bool +smbc_getOptionUseKerberos(SMBCCTX *c) +{ + return c->flags.bits & SMB_CTX_FLAG_USE_KERBEROS ? True : False; +} + +/** Set whether to enable use of kerberos */ +void +smbc_setOptionUseKerberos(SMBCCTX *c, smbc_bool b) +{ + if (b) { + c->flags.bits |= SMB_CTX_FLAG_USE_KERBEROS; + } else { + c->flags.bits &= ~SMB_CTX_FLAG_USE_KERBEROS; + } +} + +/** Get whether to fallback after kerberos */ +smbc_bool +smbc_getOptionFallbackAfterKerberos(SMBCCTX *c) +{ + return c->flags.bits & SMB_CTX_FLAG_FALLBACK_AFTER_KERBEROS ? True : False; +} + +/** Set whether to fallback after kerberos */ +void +smbc_setOptionFallbackAfterKerberos(SMBCCTX *c, smbc_bool b) +{ + if (b) { + c->flags.bits |= SMB_CTX_FLAG_FALLBACK_AFTER_KERBEROS; + } else { + c->flags.bits &= ~SMB_CTX_FLAG_FALLBACK_AFTER_KERBEROS; + } +} + +/** Get whether to automatically select anonymous login */ +smbc_bool +smbc_getOptionNoAutoAnonymousLogin(SMBCCTX *c) +{ + return c->flags.bits & SMBCCTX_FLAG_NO_AUTO_ANONYMOUS_LOGON ? True : False; +} + +/** Set whether to automatically select anonymous login */ +void +smbc_setOptionNoAutoAnonymousLogin(SMBCCTX *c, smbc_bool b) +{ + if (b) { + c->flags.bits |= SMBCCTX_FLAG_NO_AUTO_ANONYMOUS_LOGON; + } else { + c->flags.bits &= ~SMBCCTX_FLAG_NO_AUTO_ANONYMOUS_LOGON; + } +} + +/** Get the function for obtaining authentication data */ smbc_get_auth_data_fn smbc_getFunctionAuthData(SMBCCTX *c) { - return c->server.get_auth_data_fn; + return c->server.get_auth_data_fn; } /** Set the function for obtaining authentication data */ void smbc_setFunctionAuthData(SMBCCTX *c, smbc_get_auth_data_fn fn) { - c->server.get_auth_data_fn = fn; + c->internal->auth_fn_with_context = NULL; + c->server.get_auth_data_fn = fn; +} + +/** Get the new-style authentication function which includes the context. */ +smbc_get_auth_data_with_context_fn +smbc_getFunctionAuthDataWithContext(SMBCCTX *c) +{ + return c->internal->auth_fn_with_context; +} + +/** Set the new-style authentication function which includes the context. */ +void +smbc_setFunctionAuthDataWithContext(SMBCCTX *c, + smbc_get_auth_data_with_context_fn fn) +{ + c->server.get_auth_data_fn = NULL; + c->internal->auth_fn_with_context = fn; } /** Get the function for checking if a server is still good */ smbc_check_server_fn smbc_getFunctionCheckServer(SMBCCTX *c) { - return c->server.check_server_fn; + return c->server.check_server_fn; } /** Set the function for checking if a server is still good */ void smbc_setFunctionCheckServer(SMBCCTX *c, smbc_check_server_fn fn) { - c->server.check_server_fn = fn; + c->server.check_server_fn = fn; } /** Get the function for removing a server if unused */ smbc_remove_unused_server_fn smbc_getFunctionRemoveUnusedServer(SMBCCTX *c) { - return c->server.remove_unused_server_fn; + return c->server.remove_unused_server_fn; } /** Set the function for removing a server if unused */ @@ -861,21 +1005,21 @@ void smbc_setFunctionRemoveUnusedServer(SMBCCTX *c, smbc_remove_unused_server_fn fn) { - c->server.remove_unused_server_fn = fn; + c->server.remove_unused_server_fn = fn; } /** Get the function to store private data of the server cache */ struct smbc_server_cache * smbc_getServerCacheData(SMBCCTX *c) { - return c->cache.server_cache_data; + return c->cache.server_cache_data; } /** Set the function to store private data of the server cache */ void smbc_setServerCacheData(SMBCCTX *c, struct smbc_server_cache * cache) { - c->cache.server_cache_data = cache; + c->cache.server_cache_data = cache; } @@ -883,35 +1027,35 @@ smbc_setServerCacheData(SMBCCTX *c, struct smbc_server_cache * cache) smbc_add_cached_srv_fn smbc_getFunctionAddCachedServer(SMBCCTX *c) { - return c->cache.add_cached_server_fn; + return c->cache.add_cached_server_fn; } /** Set the function for adding a cached server */ void smbc_setFunctionAddCachedServer(SMBCCTX *c, smbc_add_cached_srv_fn fn) { - c->cache.add_cached_server_fn = fn; + c->cache.add_cached_server_fn = fn; } /** Get the function for server cache lookup */ smbc_get_cached_srv_fn smbc_getFunctionGetCachedServer(SMBCCTX *c) { - return c->cache.get_cached_server_fn; + return c->cache.get_cached_server_fn; } /** Set the function for server cache lookup */ void smbc_setFunctionGetCachedServer(SMBCCTX *c, smbc_get_cached_srv_fn fn) { - c->cache.get_cached_server_fn = fn; + c->cache.get_cached_server_fn = fn; } /** Get the function for server cache removal */ smbc_remove_cached_srv_fn smbc_getFunctionRemoveCachedServer(SMBCCTX *c) { - return c->cache.remove_cached_server_fn; + return c->cache.remove_cached_server_fn; } /** Set the function for server cache removal */ @@ -919,7 +1063,7 @@ void smbc_setFunctionRemoveCachedServer(SMBCCTX *c, smbc_remove_cached_srv_fn fn) { - c->cache.remove_cached_server_fn = fn; + c->cache.remove_cached_server_fn = fn; } /** @@ -929,7 +1073,7 @@ smbc_setFunctionRemoveCachedServer(SMBCCTX *c, smbc_purge_cached_srv_fn smbc_getFunctionPurgeCachedServers(SMBCCTX *c) { - return c->cache.purge_cached_servers_fn; + return c->cache.purge_cached_servers_fn; } /** @@ -939,7 +1083,7 @@ smbc_getFunctionPurgeCachedServers(SMBCCTX *c) void smbc_setFunctionPurgeCachedServers(SMBCCTX *c, smbc_purge_cached_srv_fn fn) { - c->cache.purge_cached_servers_fn = fn; + c->cache.purge_cached_servers_fn = fn; } /** @@ -949,133 +1093,133 @@ smbc_setFunctionPurgeCachedServers(SMBCCTX *c, smbc_purge_cached_srv_fn fn) smbc_open_fn smbc_getFunctionOpen(SMBCCTX *c) { - return c->posix_emu.open_fn; + return c->posix_emu.open_fn; } void smbc_setFunctionOpen(SMBCCTX *c, smbc_open_fn fn) { - c->posix_emu.open_fn = fn; + c->posix_emu.open_fn = fn; } smbc_creat_fn smbc_getFunctionCreat(SMBCCTX *c) { - return c->posix_emu.creat_fn; + return c->posix_emu.creat_fn; } void smbc_setFunctionCreat(SMBCCTX *c, smbc_creat_fn fn) { - c->posix_emu.creat_fn = fn; + c->posix_emu.creat_fn = fn; } smbc_read_fn smbc_getFunctionRead(SMBCCTX *c) { - return c->posix_emu.read_fn; + return c->posix_emu.read_fn; } void smbc_setFunctionRead(SMBCCTX *c, smbc_read_fn fn) { - c->posix_emu.read_fn = fn; + c->posix_emu.read_fn = fn; } smbc_write_fn smbc_getFunctionWrite(SMBCCTX *c) { - return c->posix_emu.write_fn; + return c->posix_emu.write_fn; } void smbc_setFunctionWrite(SMBCCTX *c, smbc_write_fn fn) { - c->posix_emu.write_fn = fn; + c->posix_emu.write_fn = fn; } smbc_unlink_fn smbc_getFunctionUnlink(SMBCCTX *c) { - return c->posix_emu.unlink_fn; + return c->posix_emu.unlink_fn; } void smbc_setFunctionUnlink(SMBCCTX *c, smbc_unlink_fn fn) { - c->posix_emu.unlink_fn = fn; + c->posix_emu.unlink_fn = fn; } smbc_rename_fn smbc_getFunctionRename(SMBCCTX *c) { - return c->posix_emu.rename_fn; + return c->posix_emu.rename_fn; } void smbc_setFunctionRename(SMBCCTX *c, smbc_rename_fn fn) { - c->posix_emu.rename_fn = fn; + c->posix_emu.rename_fn = fn; } smbc_lseek_fn smbc_getFunctionLseek(SMBCCTX *c) { - return c->posix_emu.lseek_fn; + return c->posix_emu.lseek_fn; } void smbc_setFunctionLseek(SMBCCTX *c, smbc_lseek_fn fn) { - c->posix_emu.lseek_fn = fn; + c->posix_emu.lseek_fn = fn; } smbc_stat_fn smbc_getFunctionStat(SMBCCTX *c) { - return c->posix_emu.stat_fn; + return c->posix_emu.stat_fn; } void smbc_setFunctionStat(SMBCCTX *c, smbc_stat_fn fn) { - c->posix_emu.stat_fn = fn; + c->posix_emu.stat_fn = fn; } smbc_fstat_fn smbc_getFunctionFstat(SMBCCTX *c) { - return c->posix_emu.fstat_fn; + return c->posix_emu.fstat_fn; } void smbc_setFunctionFstat(SMBCCTX *c, smbc_fstat_fn fn) { - c->posix_emu.fstat_fn = fn; + c->posix_emu.fstat_fn = fn; } smbc_ftruncate_fn smbc_getFunctionFtruncate(SMBCCTX *c) { - return c->internal->posix_emu.ftruncate_fn; + return c->internal->posix_emu.ftruncate_fn; } void smbc_setFunctionFtruncate(SMBCCTX *c, smbc_ftruncate_fn fn) { - c->internal->posix_emu.ftruncate_fn = fn; + c->internal->posix_emu.ftruncate_fn = fn; } smbc_close_fn smbc_getFunctionClose(SMBCCTX *c) { - return c->posix_emu.close_fn; + return c->posix_emu.close_fn; } void smbc_setFunctionClose(SMBCCTX *c, smbc_close_fn fn) { - c->posix_emu.close_fn = fn; + c->posix_emu.close_fn = fn; } @@ -1086,109 +1230,109 @@ smbc_setFunctionClose(SMBCCTX *c, smbc_close_fn fn) smbc_opendir_fn smbc_getFunctionOpendir(SMBCCTX *c) { - return c->posix_emu.opendir_fn; + return c->posix_emu.opendir_fn; } void smbc_setFunctionOpendir(SMBCCTX *c, smbc_opendir_fn fn) { - c->posix_emu.opendir_fn = fn; + c->posix_emu.opendir_fn = fn; } smbc_closedir_fn smbc_getFunctionClosedir(SMBCCTX *c) { - return c->posix_emu.closedir_fn; + return c->posix_emu.closedir_fn; } void smbc_setFunctionClosedir(SMBCCTX *c, smbc_closedir_fn fn) { - c->posix_emu.closedir_fn = fn; + c->posix_emu.closedir_fn = fn; } smbc_readdir_fn smbc_getFunctionReaddir(SMBCCTX *c) { - return c->posix_emu.readdir_fn; + return c->posix_emu.readdir_fn; } void smbc_setFunctionReaddir(SMBCCTX *c, smbc_readdir_fn fn) { - c->posix_emu.readdir_fn = fn; + c->posix_emu.readdir_fn = fn; } smbc_getdents_fn smbc_getFunctionGetdents(SMBCCTX *c) { - return c->posix_emu.getdents_fn; + return c->posix_emu.getdents_fn; } void smbc_setFunctionGetdents(SMBCCTX *c, smbc_getdents_fn fn) { - c->posix_emu.getdents_fn = fn; + c->posix_emu.getdents_fn = fn; } smbc_mkdir_fn smbc_getFunctionMkdir(SMBCCTX *c) { - return c->posix_emu.mkdir_fn; + return c->posix_emu.mkdir_fn; } void smbc_setFunctionMkdir(SMBCCTX *c, smbc_mkdir_fn fn) { - c->posix_emu.mkdir_fn = fn; + c->posix_emu.mkdir_fn = fn; } smbc_rmdir_fn smbc_getFunctionRmdir(SMBCCTX *c) { - return c->posix_emu.rmdir_fn; + return c->posix_emu.rmdir_fn; } void smbc_setFunctionRmdir(SMBCCTX *c, smbc_rmdir_fn fn) { - c->posix_emu.rmdir_fn = fn; + c->posix_emu.rmdir_fn = fn; } smbc_telldir_fn smbc_getFunctionTelldir(SMBCCTX *c) { - return c->posix_emu.telldir_fn; + return c->posix_emu.telldir_fn; } void smbc_setFunctionTelldir(SMBCCTX *c, smbc_telldir_fn fn) { - c->posix_emu.telldir_fn = fn; + c->posix_emu.telldir_fn = fn; } smbc_lseekdir_fn smbc_getFunctionLseekdir(SMBCCTX *c) { - return c->posix_emu.lseekdir_fn; + return c->posix_emu.lseekdir_fn; } void smbc_setFunctionLseekdir(SMBCCTX *c, smbc_lseekdir_fn fn) { - c->posix_emu.lseekdir_fn = fn; + c->posix_emu.lseekdir_fn = fn; } smbc_fstatdir_fn smbc_getFunctionFstatdir(SMBCCTX *c) { - return c->posix_emu.fstatdir_fn; + return c->posix_emu.fstatdir_fn; } void smbc_setFunctionFstatdir(SMBCCTX *c, smbc_fstatdir_fn fn) { - c->posix_emu.fstatdir_fn = fn; + c->posix_emu.fstatdir_fn = fn; } @@ -1199,73 +1343,73 @@ smbc_setFunctionFstatdir(SMBCCTX *c, smbc_fstatdir_fn fn) smbc_chmod_fn smbc_getFunctionChmod(SMBCCTX *c) { - return c->posix_emu.chmod_fn; + return c->posix_emu.chmod_fn; } void smbc_setFunctionChmod(SMBCCTX *c, smbc_chmod_fn fn) { - c->posix_emu.chmod_fn = fn; + c->posix_emu.chmod_fn = fn; } smbc_utimes_fn smbc_getFunctionUtimes(SMBCCTX *c) { - return c->posix_emu.utimes_fn; + return c->posix_emu.utimes_fn; } void smbc_setFunctionUtimes(SMBCCTX *c, smbc_utimes_fn fn) { - c->posix_emu.utimes_fn = fn; + c->posix_emu.utimes_fn = fn; } smbc_setxattr_fn smbc_getFunctionSetxattr(SMBCCTX *c) { - return c->posix_emu.setxattr_fn; + return c->posix_emu.setxattr_fn; } void smbc_setFunctionSetxattr(SMBCCTX *c, smbc_setxattr_fn fn) { - c->posix_emu.setxattr_fn = fn; + c->posix_emu.setxattr_fn = fn; } smbc_getxattr_fn smbc_getFunctionGetxattr(SMBCCTX *c) { - return c->posix_emu.getxattr_fn; + return c->posix_emu.getxattr_fn; } void smbc_setFunctionGetxattr(SMBCCTX *c, smbc_getxattr_fn fn) { - c->posix_emu.getxattr_fn = fn; + c->posix_emu.getxattr_fn = fn; } smbc_removexattr_fn smbc_getFunctionRemovexattr(SMBCCTX *c) { - return c->posix_emu.removexattr_fn; + return c->posix_emu.removexattr_fn; } void smbc_setFunctionRemovexattr(SMBCCTX *c, smbc_removexattr_fn fn) { - c->posix_emu.removexattr_fn = fn; + c->posix_emu.removexattr_fn = fn; } smbc_listxattr_fn smbc_getFunctionListxattr(SMBCCTX *c) { - return c->posix_emu.listxattr_fn; + return c->posix_emu.listxattr_fn; } void smbc_setFunctionListxattr(SMBCCTX *c, smbc_listxattr_fn fn) { - c->posix_emu.listxattr_fn = fn; + c->posix_emu.listxattr_fn = fn; } @@ -1276,51 +1420,51 @@ smbc_setFunctionListxattr(SMBCCTX *c, smbc_listxattr_fn fn) smbc_print_file_fn smbc_getFunctionPrintFile(SMBCCTX *c) { - return c->printing.print_file_fn; + return c->printing.print_file_fn; } void smbc_setFunctionPrintFile(SMBCCTX *c, smbc_print_file_fn fn) { - c->printing.print_file_fn = fn; + c->printing.print_file_fn = fn; } smbc_open_print_job_fn smbc_getFunctionOpenPrintJob(SMBCCTX *c) { - return c->printing.open_print_job_fn; + return c->printing.open_print_job_fn; } void smbc_setFunctionOpenPrintJob(SMBCCTX *c, smbc_open_print_job_fn fn) { - c->printing.open_print_job_fn = fn; + c->printing.open_print_job_fn = fn; } smbc_list_print_jobs_fn smbc_getFunctionListPrintJobs(SMBCCTX *c) { - return c->printing.list_print_jobs_fn; + return c->printing.list_print_jobs_fn; } void smbc_setFunctionListPrintJobs(SMBCCTX *c, smbc_list_print_jobs_fn fn) { - c->printing.list_print_jobs_fn = fn; + c->printing.list_print_jobs_fn = fn; } smbc_unlink_print_job_fn smbc_getFunctionUnlinkPrintJob(SMBCCTX *c) { - return c->printing.unlink_print_job_fn; + return c->printing.unlink_print_job_fn; } void smbc_setFunctionUnlinkPrintJob(SMBCCTX *c, - smbc_unlink_print_job_fn fn) + smbc_unlink_print_job_fn fn) { - c->printing.unlink_print_job_fn = fn; + c->printing.unlink_print_job_fn = fn; } diff --git a/source3/libsmb/libsmb_dir.c b/source3/libsmb/libsmb_dir.c index 25020762a2..2ece2ab8ed 100644 --- a/source3/libsmb/libsmb_dir.c +++ b/source3/libsmb/libsmb_dir.c @@ -36,19 +36,19 @@ static void remove_dir(SMBCFILE *dir) { struct smbc_dir_list *d,*f; - + d = dir->dir_list; while (d) { - + f = d; d = d->next; - + SAFE_FREE(f->dirent); SAFE_FREE(f); - + } - + dir->dir_list = dir->dir_end = dir->dir_next = NULL; - + } static int @@ -61,63 +61,63 @@ add_dirent(SMBCFILE *dir, int size; int name_length = (name == NULL ? 0 : strlen(name)); int comment_len = (comment == NULL ? 0 : strlen(comment)); - + /* * Allocate space for the dirent, which must be increased by the * size of the name and the comment and 1 each for the null terminator. */ - + size = sizeof(struct smbc_dirent) + name_length + comment_len + 2; - + dirent = (struct smbc_dirent *)SMB_MALLOC(size); - + if (!dirent) { - + dir->dir_error = ENOMEM; return -1; - + } - + ZERO_STRUCTP(dirent); - + if (dir->dir_list == NULL) { - + dir->dir_list = SMB_MALLOC_P(struct smbc_dir_list); if (!dir->dir_list) { - + SAFE_FREE(dirent); dir->dir_error = ENOMEM; return -1; - + } ZERO_STRUCTP(dir->dir_list); - + dir->dir_end = dir->dir_next = dir->dir_list; } else { - + dir->dir_end->next = SMB_MALLOC_P(struct smbc_dir_list); - + if (!dir->dir_end->next) { - + SAFE_FREE(dirent); dir->dir_error = ENOMEM; return -1; - + } ZERO_STRUCTP(dir->dir_end->next); - + dir->dir_end = dir->dir_end->next; } - + dir->dir_end->next = NULL; dir->dir_end->dirent = dirent; - + dirent->smbc_type = type; dirent->namelen = name_length; dirent->commentlen = comment_len; dirent->dirlen = size; - + /* * dirent->namelen + 1 includes the null (no null termination needed) * Ditto for dirent->commentlen. @@ -126,9 +126,9 @@ add_dirent(SMBCFILE *dir, strncpy(dirent->name, (name?name:""), dirent->namelen + 1); dirent->comment = (char *)(&dirent->name + dirent->namelen + 1); strncpy(dirent->comment, (comment?comment:""), dirent->commentlen + 1); - + return 0; - + } static void @@ -142,18 +142,18 @@ list_unique_wg_fn(const char *name, struct smbc_dirent *dirent; int dirent_type; int do_remove = 0; - + dirent_type = dir->dir_type; - + if (add_dirent(dir, name, comment, dirent_type) < 0) { - + /* An error occurred, what do we do? */ /* FIXME: Add some code here */ } - + /* Point to the one just added */ dirent = dir->dir_end->dirent; - + /* See if this was a duplicate */ for (dir_list = dir->dir_list; dir_list != dir->dir_end; @@ -163,7 +163,7 @@ list_unique_wg_fn(const char *name, /* Duplicate. End end of list need to be removed. */ do_remove = 1; } - + if (do_remove && dir_list->next == dir->dir_end) { /* Found the end of the list. Remove it. */ dir->dir_end = dir_list; @@ -183,7 +183,7 @@ list_fn(const char *name, { SMBCFILE *dir = (SMBCFILE *)state; int dirent_type; - + /* * We need to process the type a little ... * @@ -195,27 +195,27 @@ list_fn(const char *name, * administrative shares: * ADMIN$, IPC$, C$, D$, E$ ... are type |= 0x80000000 */ - + if (dir->dir_type == SMBC_FILE_SHARE) { switch (type) { case 0 | 0x80000000: case 0: dirent_type = SMBC_FILE_SHARE; break; - + case 1: dirent_type = SMBC_PRINTER_SHARE; break; - + case 2: dirent_type = SMBC_COMMS_SHARE; break; - + case 3 | 0x80000000: case 3: dirent_type = SMBC_IPC_SHARE; break; - + default: dirent_type = SMBC_FILE_SHARE; /* FIXME, error? */ break; @@ -224,12 +224,12 @@ list_fn(const char *name, else { dirent_type = dir->dir_type; } - + if (add_dirent(dir, name, comment, dirent_type) < 0) { - + /* An error occurred, what do we do? */ /* FIXME: Add some code here */ - + } } @@ -239,16 +239,16 @@ dir_list_fn(const char *mnt, const char *mask, void *state) { - + if (add_dirent((SMBCFILE *)state, finfo->name, "", (finfo->mode&aDIR?SMBC_DIR:SMBC_FILE)) < 0) { - + /* Handle an error ... */ - + /* FIXME: Add some code ... */ - + } - + } static int @@ -270,14 +270,14 @@ net_share_enum_rpc(struct cli_state *cli, fstring comment = ""; struct rpc_pipe_client *pipe_hnd; NTSTATUS nt_status; - + /* Open the server service pipe */ pipe_hnd = cli_rpc_pipe_open_noauth(cli, PI_SRVSVC, &nt_status); if (!pipe_hnd) { DEBUG(1, ("net_share_enum_rpc pipe open fail!\n")); return -1; } - + /* Issue the NetShareEnum RPC call and retrieve the response */ init_enum_hnd(&enum_hnd, 0); result = rpccli_srvsvc_net_share_enum(pipe_hnd, @@ -286,35 +286,35 @@ net_share_enum_rpc(struct cli_state *cli, &ctr, preferred_len, &enum_hnd); - + /* Was it successful? */ if (!W_ERROR_IS_OK(result) || ctr.num_entries == 0) { /* Nope. Go clean up. */ goto done; } - + /* For each returned entry... */ for (i = 0; i < ctr.num_entries; i++) { - + /* pull out the share name */ rpcstr_pull_unistr2_fstring( name, &ctr.share.info1[i].info_1_str.uni_netname); - + /* pull out the share's comment */ rpcstr_pull_unistr2_fstring( comment, &ctr.share.info1[i].info_1_str.uni_remark); - + /* Get the type value */ type = ctr.share.info1[i].info_1.type; - + /* Add this share to the list */ (*fn)(name, type, comment, state); } - + done: /* Close the server service pipe */ cli_rpc_pipe_close(pipe_hnd); - + /* Tell 'em if it worked */ return W_ERROR_IS_OK(result) ? 0 : -1; } @@ -332,10 +332,10 @@ SMBC_check_options(char *server, DEBUG(4, ("SMBC_check_options(): server='%s' share='%s' " "path='%s' options='%s'\n", server, share, path, options)); - + /* No options at all is always ok */ if (! *options) return 0; - + /* Currently, we don't support any options. */ return -1; } @@ -346,7 +346,11 @@ SMBC_opendir_ctx(SMBCCTX *context, const char *fname) { int saved_errno; - char *server = NULL, *share = NULL, *user = NULL, *password = NULL, *options = NULL; + char *server = NULL; + char *share = NULL; + char *user = NULL; + char *password = NULL; + char *options = NULL; char *workgroup = NULL; char *path = NULL; uint16 mode; @@ -355,42 +359,42 @@ SMBC_opendir_ctx(SMBCCTX *context, SMBCFILE *dir = NULL; struct sockaddr_storage rem_ss; TALLOC_CTX *frame = talloc_stackframe(); - + if (!context || !context->internal->initialized) { DEBUG(4, ("no valid context\n")); errno = EINVAL + 8192; TALLOC_FREE(frame); return NULL; - + } - + if (!fname) { DEBUG(4, ("no valid fname\n")); errno = EINVAL + 8193; TALLOC_FREE(frame); return NULL; } - + if (SMBC_parse_path(frame, - context, - fname, - &workgroup, - &server, - &share, - &path, - &user, - &password, - &options)) { + context, + fname, + &workgroup, + &server, + &share, + &path, + &user, + &password, + &options)) { DEBUG(4, ("no valid path\n")); errno = EINVAL + 8194; TALLOC_FREE(frame); return NULL; } - + DEBUG(4, ("parsed path: fname='%s' server='%s' share='%s' " "path='%s' options='%s'\n", fname, server, share, path, options)); - + /* Ensure the options are valid */ if (SMBC_check_options(server, share, path, options)) { DEBUG(4, ("unacceptable options (%s)\n", options)); @@ -398,7 +402,7 @@ SMBC_opendir_ctx(SMBCCTX *context, TALLOC_FREE(frame); return NULL; } - + if (!user || user[0] == (char)0) { user = talloc_strdup(frame, context->config.user); if (!user) { @@ -407,35 +411,35 @@ SMBC_opendir_ctx(SMBCCTX *context, return NULL; } } - + dir = SMB_MALLOC_P(SMBCFILE); - + if (!dir) { errno = ENOMEM; TALLOC_FREE(frame); return NULL; } - + ZERO_STRUCTP(dir); - + dir->cli_fd = 0; dir->fname = SMB_STRDUP(fname); dir->srv = NULL; dir->offset = 0; dir->file = False; dir->dir_list = dir->dir_next = dir->dir_end = NULL; - + if (server[0] == (char)0) { - + int i; int count; int max_lmb_count; struct ip_service *ip_list; struct ip_service server_addr; struct user_auth_info u_info; - + if (share[0] != (char)0 || path[0] != (char)0) { - + errno = EINVAL + 8196; if (dir) { SAFE_FREE(dir->fname); @@ -444,12 +448,12 @@ SMBC_opendir_ctx(SMBCCTX *context, TALLOC_FREE(frame); return NULL; } - + /* Determine how many local master browsers to query */ - max_lmb_count = (context->internal->browse_max_lmb_count == 0 + max_lmb_count = (context->options.browse_max_lmb_count == 0 ? INT_MAX - : context->internal->browse_max_lmb_count); - + : context->options.browse_max_lmb_count); + memset(&u_info, '\0', sizeof(u_info)); u_info.username = talloc_strdup(frame,user); u_info.password = talloc_strdup(frame,password); @@ -461,7 +465,7 @@ SMBC_opendir_ctx(SMBCCTX *context, TALLOC_FREE(frame); return NULL; } - + /* * We have server and share and path empty but options * requesting that we scan all master browsers for their list @@ -470,16 +474,16 @@ SMBC_opendir_ctx(SMBCCTX *context, * doesn't work, then try our other methods which return only * a single master browser. */ - + ip_list = NULL; if (!NT_STATUS_IS_OK(name_resolve_bcast(MSBROWSE, 1, &ip_list, - &count))) + &count))) { - + SAFE_FREE(ip_list); - + if (!find_master_ip(workgroup, &server_addr.ss)) { - + if (dir) { SAFE_FREE(dir->fname); SAFE_FREE(dir); @@ -488,7 +492,7 @@ SMBC_opendir_ctx(SMBCCTX *context, TALLOC_FREE(frame); return NULL; } - + ip_list = (struct ip_service *)memdup( &server_addr, sizeof(server_addr)); if (ip_list == NULL) { @@ -498,17 +502,17 @@ SMBC_opendir_ctx(SMBCCTX *context, } count = 1; } - + for (i = 0; i < count && i < max_lmb_count; i++) { char addr[INET6_ADDRSTRLEN]; char *wg_ptr = NULL; struct cli_state *cli = NULL; - + print_sockaddr(addr, sizeof(addr), &ip_list[i].ss); DEBUG(99, ("Found master browser %d of %d: %s\n", i+1, MAX(count, max_lmb_count), addr)); - + cli = get_ipc_connect_master_ip(talloc_tos(), &ip_list[i], &u_info, @@ -518,39 +522,39 @@ SMBC_opendir_ctx(SMBCCTX *context, if (!cli) { continue; } - + workgroup = talloc_strdup(frame, wg_ptr); server = talloc_strdup(frame, cli->desthost); - + cli_shutdown(cli); - + if (!workgroup || !server) { errno = ENOMEM; TALLOC_FREE(frame); return NULL; } - + DEBUG(4, ("using workgroup %s %s\n", workgroup, server)); - + /* * For each returned master browser IP address, get a * connection to IPC$ on the server if we do not * already have one, and determine the * workgroups/domains that it knows about. */ - + srv = SMBC_server(frame, context, True, server, "IPC$", &workgroup, &user, &password); if (!srv) { continue; } - + dir->srv = srv; dir->dir_type = SMBC_WORKGROUP; - + /* Now, list the stuff ... */ - + if (!cli_NetServerEnum(srv->cli, workgroup, SV_TYPE_DOMAIN_ENUM, @@ -559,7 +563,7 @@ SMBC_opendir_ctx(SMBCCTX *context, continue; } } - + SAFE_FREE(ip_list); } else { /* @@ -568,7 +572,7 @@ SMBC_opendir_ctx(SMBCCTX *context, */ if (*share == '\0') { if (*path != '\0') { - + /* Should not have empty share with path */ errno = EINVAL + 8197; if (dir) { @@ -577,9 +581,9 @@ SMBC_opendir_ctx(SMBCCTX *context, } TALLOC_FREE(frame); return NULL; - + } - + /* * We don't know if is really a server name * or is a workgroup/domain name. If we already have @@ -588,15 +592,16 @@ SMBC_opendir_ctx(SMBCCTX *context, * <1B>, or <20> translates. We check * to see if is an IP address first. */ - + /* * See if we have an existing server. Do not * establish a connection if one does not already * exist. */ - srv = SMBC_server(frame, context, False, server, "IPC$", + srv = SMBC_server(frame, context, False, + server, "IPC$", &workgroup, &user, &password); - + /* * If no existing server and not an IP addr, look for * LMB or DMB @@ -605,20 +610,20 @@ SMBC_opendir_ctx(SMBCCTX *context, !is_ipaddress(server) && (resolve_name(server, &rem_ss, 0x1d) || /* LMB */ resolve_name(server, &rem_ss, 0x1b) )) { /* DMB */ - + fstring buserver; - + dir->dir_type = SMBC_SERVER; - + /* * Get the backup list ... */ if (!name_status_find(server, 0, 0, &rem_ss, buserver)) { - - DEBUG(0, ("Could not get name of " - "local/domain master browser " - "for server %s\n", server)); + + DEBUG(0,("Could not get name of " + "local/domain master browser " + "for server %s\n", server)); if (dir) { SAFE_FREE(dir->fname); SAFE_FREE(dir); @@ -626,16 +631,17 @@ SMBC_opendir_ctx(SMBCCTX *context, errno = EPERM; TALLOC_FREE(frame); return NULL; - + } - + /* * Get a connection to IPC$ on the server if * we do not already have one */ 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) { @@ -644,16 +650,16 @@ SMBC_opendir_ctx(SMBCCTX *context, } TALLOC_FREE(frame); return NULL; - + } - + dir->srv = srv; - + /* Now, list the servers ... */ if (!cli_NetServerEnum(srv->cli, server, 0x0000FFFE, list_fn, (void *)dir)) { - + if (dir) { SAFE_FREE(dir->fname); SAFE_FREE(dir); @@ -663,15 +669,17 @@ SMBC_opendir_ctx(SMBCCTX *context, } } else if (srv || (resolve_name(server, &rem_ss, 0x20))) { - - /* If we hadn't found the server, get one now */ + + /* + * If we hadn't found the server, get one now + */ if (!srv) { srv = SMBC_server(frame, context, True, server, "IPC$", &workgroup, &user, &password); } - + if (!srv) { if (dir) { SAFE_FREE(dir->fname); @@ -679,14 +687,14 @@ SMBC_opendir_ctx(SMBCCTX *context, } TALLOC_FREE(frame); return NULL; - + } - + dir->dir_type = SMBC_FILE_SHARE; dir->srv = srv; - + /* List the shares ... */ - + if (net_share_enum_rpc( srv->cli, list_fn, @@ -695,7 +703,7 @@ SMBC_opendir_ctx(SMBCCTX *context, srv->cli, list_fn, (void *)dir) < 0) { - + errno = cli_errno(srv->cli); if (dir) { SAFE_FREE(dir->fname); @@ -703,7 +711,7 @@ SMBC_opendir_ctx(SMBCCTX *context, } TALLOC_FREE(frame); return NULL; - + } } else { /* Neither the workgroup nor server exists */ @@ -715,7 +723,7 @@ SMBC_opendir_ctx(SMBCCTX *context, TALLOC_FREE(frame); return NULL; } - + } else { /* @@ -724,13 +732,13 @@ SMBC_opendir_ctx(SMBCCTX *context, */ char *targetpath; struct cli_state *targetcli; - + /* We connect to the server and list the directory */ dir->dir_type = SMBC_FILE_SHARE; - + srv = SMBC_server(frame, context, True, server, share, &workgroup, &user, &password); - + if (!srv) { if (dir) { SAFE_FREE(dir->fname); @@ -739,11 +747,11 @@ SMBC_opendir_ctx(SMBCCTX *context, TALLOC_FREE(frame); return NULL; } - + dir->srv = srv; - + /* Now, list the files ... */ - + p = path + strlen(path); path = talloc_asprintf_append(path, "\\*"); if (!path) { @@ -754,7 +762,7 @@ SMBC_opendir_ctx(SMBCCTX *context, TALLOC_FREE(frame); return NULL; } - + if (!cli_resolve_path(frame, "", srv->cli, path, &targetcli, &targetpath)) { d_printf("Could not resolve %s\n", path); @@ -765,47 +773,48 @@ SMBC_opendir_ctx(SMBCCTX *context, TALLOC_FREE(frame); return NULL; } - + if (cli_list(targetcli, targetpath, aDIR | aSYSTEM | aHIDDEN, dir_list_fn, (void *)dir) < 0) { - + if (dir) { SAFE_FREE(dir->fname); SAFE_FREE(dir); } saved_errno = SMBC_errno(context, targetcli); - + if (saved_errno == EINVAL) { - /* - * See if they asked to opendir something - * other than a directory. If so, the - * converted error value we got would have - * been EINVAL rather than ENOTDIR. - */ - *p = '\0'; /* restore original path */ - - if (SMBC_getatr(context, srv, path, - &mode, NULL, - NULL, NULL, NULL, NULL, - NULL) && - ! IS_DOS_DIR(mode)) { - - /* It is. Correct the error value */ - saved_errno = ENOTDIR; - } + /* + * See if they asked to opendir + * something other than a directory. + * If so, the converted error value we + * got would have been EINVAL rather + * than ENOTDIR. + */ + *p = '\0'; /* restore original path */ + + if (SMBC_getatr(context, srv, path, + &mode, NULL, + NULL, NULL, NULL, NULL, + NULL) && + ! IS_DOS_DIR(mode)) { + + /* It is. Correct the error value */ + saved_errno = ENOTDIR; + } } - + /* * If there was an error and the server is no * good any more... */ if (cli_is_error(targetcli) && (context->server.check_server_fn)(context, srv)) { - + /* ... then remove it. */ if ((context->server.remove_unused_server_fn)(context, - srv)) { + srv)) { /* * We could not remove the * server completely, remove @@ -817,19 +826,19 @@ SMBC_opendir_ctx(SMBCCTX *context, (context->cache.remove_cached_server_fn)(context, srv); } } - + errno = saved_errno; TALLOC_FREE(frame); return NULL; } } - + } - + DLIST_ADD(context->internal->files, dir); TALLOC_FREE(frame); return dir; - + } /* @@ -841,32 +850,32 @@ SMBC_closedir_ctx(SMBCCTX *context, SMBCFILE *dir) { TALLOC_CTX *frame = talloc_stackframe(); - + if (!context || !context->internal->initialized) { errno = EINVAL; TALLOC_FREE(frame); return -1; } - + if (!dir || !SMBC_dlist_contains(context->internal->files, dir)) { errno = EBADF; TALLOC_FREE(frame); return -1; } - + remove_dir(dir); /* Clean it up */ - + DLIST_REMOVE(context->internal->files, dir); - + if (dir) { - + SAFE_FREE(dir->fname); SAFE_FREE(dir); /* Free the space too */ } - + TALLOC_FREE(frame); return 0; - + } static void @@ -875,29 +884,29 @@ smbc_readdir_internal(SMBCCTX * context, struct smbc_dirent *src, int max_namebuf_len) { - if (context->internal->urlencode_readdir_entries) { - + if (context->options.urlencode_readdir_entries) { + /* url-encode the name. get back remaining buffer space */ max_namebuf_len = SMBC_urlencode(dest->name, src->name, max_namebuf_len); - + /* We now know the name length */ dest->namelen = strlen(dest->name); - + /* Save the pointer to the beginning of the comment */ dest->comment = dest->name + dest->namelen + 1; - + /* Copy the comment */ strncpy(dest->comment, src->comment, max_namebuf_len - 1); dest->comment[max_namebuf_len - 1] = '\0'; - + /* Save other fields */ dest->smbc_type = src->smbc_type; dest->commentlen = strlen(dest->comment); dest->dirlen = ((dest->comment + dest->commentlen + 1) - (char *) dest); } else { - + /* No encoding. Just copy the entry as is. */ memcpy(dest, src, src->dirlen); dest->comment = (char *)(&dest->name + src->namelen + 1); @@ -916,58 +925,58 @@ SMBC_readdir_ctx(SMBCCTX *context, int maxlen; struct smbc_dirent *dirp, *dirent; TALLOC_CTX *frame = talloc_stackframe(); - + /* Check that all is ok first ... */ - + if (!context || !context->internal->initialized) { - + errno = EINVAL; DEBUG(0, ("Invalid context in SMBC_readdir_ctx()\n")); TALLOC_FREE(frame); return NULL; - + } - + if (!dir || !SMBC_dlist_contains(context->internal->files, dir)) { - + errno = EBADF; DEBUG(0, ("Invalid dir in SMBC_readdir_ctx()\n")); TALLOC_FREE(frame); return NULL; - + } - + if (dir->file != False) { /* FIXME, should be dir, perhaps */ - + errno = ENOTDIR; DEBUG(0, ("Found file vs directory in SMBC_readdir_ctx()\n")); TALLOC_FREE(frame); return NULL; - + } - + if (!dir->dir_next) { TALLOC_FREE(frame); return NULL; } - + dirent = dir->dir_next->dirent; if (!dirent) { - + errno = ENOENT; TALLOC_FREE(frame); return NULL; - + } - + dirp = (struct smbc_dirent *)context->internal->dirent; maxlen = (sizeof(context->internal->dirent) - sizeof(struct smbc_dirent)); - + smbc_readdir_internal(context, dirp, dirent, maxlen); - + dir->dir_next = dir->dir_next->next; - + TALLOC_FREE(frame); return dirp; } @@ -988,98 +997,99 @@ SMBC_getdents_ctx(SMBCCTX *context, char *ndir = (char *)dirp; struct smbc_dir_list *dirlist; TALLOC_CTX *frame = talloc_stackframe(); - + /* Check that all is ok first ... */ - + if (!context || !context->internal->initialized) { - + errno = EINVAL; TALLOC_FREE(frame); return -1; - + } - + if (!dir || !SMBC_dlist_contains(context->internal->files, dir)) { - + errno = EBADF; TALLOC_FREE(frame); return -1; - + } - + if (dir->file != False) { /* FIXME, should be dir, perhaps */ - + errno = ENOTDIR; TALLOC_FREE(frame); return -1; - + } - + /* * Now, retrieve the number of entries that will fit in what was passed * We have to figure out if the info is in the list, or we need to * send a request to the server to get the info. */ - + while ((dirlist = dir->dir_next)) { struct smbc_dirent *dirent; - + if (!dirlist->dirent) { - + errno = ENOENT; /* Bad error */ TALLOC_FREE(frame); return -1; - + } - + /* Do urlencoding of next entry, if so selected */ dirent = (struct smbc_dirent *)context->internal->dirent; maxlen = (sizeof(context->internal->dirent) - sizeof(struct smbc_dirent)); - smbc_readdir_internal(context, dirent, dirlist->dirent, maxlen); - + smbc_readdir_internal(context, dirent, + dirlist->dirent, maxlen); + reqd = dirent->dirlen; - + if (rem < reqd) { - + if (rem < count) { /* We managed to copy something */ - + errno = 0; TALLOC_FREE(frame); return count - rem; - + } else { /* Nothing copied ... */ - + errno = EINVAL; /* Not enough space ... */ TALLOC_FREE(frame); return -1; - + } - + } - + memcpy(ndir, dirent, reqd); /* Copy the data in ... */ - + ((struct smbc_dirent *)ndir)->comment = (char *)(&((struct smbc_dirent *)ndir)->name + dirent->namelen + 1); - + ndir += reqd; - + rem -= reqd; - + dir->dir_next = dirlist = dirlist -> next; } - + TALLOC_FREE(frame); - + if (rem == count) return 0; else return count - rem; - + } /* @@ -1101,36 +1111,36 @@ SMBC_mkdir_ctx(SMBCCTX *context, char *targetpath = NULL; struct cli_state *targetcli = NULL; TALLOC_CTX *frame = talloc_stackframe(); - + if (!context || !context->internal->initialized) { errno = EINVAL; TALLOC_FREE(frame); return -1; } - + if (!fname) { errno = EINVAL; TALLOC_FREE(frame); return -1; } - + DEBUG(4, ("smbc_mkdir(%s)\n", fname)); - + if (SMBC_parse_path(frame, - context, - fname, - &workgroup, - &server, - &share, - &path, - &user, - &password, - NULL)) { + context, + fname, + &workgroup, + &server, + &share, + &path, + &user, + &password, + NULL)) { errno = EINVAL; TALLOC_FREE(frame); return -1; } - + if (!user || user[0] == (char)0) { user = talloc_strdup(frame, context->config.user); if (!user) { @@ -1139,37 +1149,37 @@ SMBC_mkdir_ctx(SMBCCTX *context, return -1; } } - + srv = SMBC_server(frame, context, True, server, share, &workgroup, &user, &password); - + if (!srv) { - + TALLOC_FREE(frame); return -1; /* errno set by SMBC_server */ - + } - + /*d_printf(">>>mkdir: resolving %s\n", path);*/ if (!cli_resolve_path(frame, "", srv->cli, path, - &targetcli, &targetpath)) { + &targetcli, &targetpath)) { d_printf("Could not resolve %s\n", path); TALLOC_FREE(frame); return -1; } /*d_printf(">>>mkdir: resolved path as %s\n", targetpath);*/ - + if (!cli_mkdir(targetcli, targetpath)) { - + errno = SMBC_errno(context, targetcli); TALLOC_FREE(frame); return -1; - + } - + TALLOC_FREE(frame); return 0; - + } /* @@ -1208,36 +1218,36 @@ SMBC_rmdir_ctx(SMBCCTX *context, char *targetpath = NULL; struct cli_state *targetcli = NULL; TALLOC_CTX *frame = talloc_stackframe(); - + if (!context || !context->internal->initialized) { errno = EINVAL; TALLOC_FREE(frame); return -1; } - + if (!fname) { errno = EINVAL; TALLOC_FREE(frame); return -1; } - + DEBUG(4, ("smbc_rmdir(%s)\n", fname)); - + if (SMBC_parse_path(frame, - context, - fname, - &workgroup, - &server, - &share, - &path, - &user, - &password, - NULL)) { + context, + fname, + &workgroup, + &server, + &share, + &path, + &user, + &password, + NULL)) { errno = EINVAL; TALLOC_FREE(frame); return -1; } - + if (!user || user[0] == (char)0) { user = talloc_strdup(frame, context->config.user); if (!user) { @@ -1246,38 +1256,38 @@ SMBC_rmdir_ctx(SMBCCTX *context, return -1; } } - + srv = SMBC_server(frame, context, True, server, share, &workgroup, &user, &password); - + if (!srv) { - + TALLOC_FREE(frame); return -1; /* errno set by SMBC_server */ - + } - + /*d_printf(">>>rmdir: resolving %s\n", path);*/ if (!cli_resolve_path(frame, "", srv->cli, path, - &targetcli, &targetpath)) { + &targetcli, &targetpath)) { d_printf("Could not resolve %s\n", path); TALLOC_FREE(frame); return -1; } /*d_printf(">>>rmdir: resolved path as %s\n", targetpath);*/ - - + + if (!cli_rmdir(targetcli, targetpath)) { - + errno = SMBC_errno(context, targetcli); - + if (errno == EACCES) { /* Check if the dir empty or not */ - + /* Local storage to avoid buffer overflows */ char *lpath; - + smbc_rmdir_dirempty = True; /* Make this so ... */ - + lpath = talloc_asprintf(frame, "%s\\*", targetpath); if (!lpath) { @@ -1285,34 +1295,34 @@ SMBC_rmdir_ctx(SMBCCTX *context, TALLOC_FREE(frame); return -1; } - + if (cli_list(targetcli, lpath, aDIR | aSYSTEM | aHIDDEN, rmdir_list_fn, NULL) < 0) { - + /* Fix errno to ignore latest error ... */ DEBUG(5, ("smbc_rmdir: " "cli_list returned an error: %d\n", SMBC_errno(context, targetcli))); errno = EACCES; - + } - + if (smbc_rmdir_dirempty) errno = EACCES; else errno = ENOTEMPTY; - + } - + TALLOC_FREE(frame); return -1; - + } - + TALLOC_FREE(frame); return 0; - + } /* @@ -1324,38 +1334,38 @@ SMBC_telldir_ctx(SMBCCTX *context, SMBCFILE *dir) { TALLOC_CTX *frame = talloc_stackframe(); - + if (!context || !context->internal->initialized) { - + errno = EINVAL; TALLOC_FREE(frame); return -1; - + } - + if (!dir || !SMBC_dlist_contains(context->internal->files, dir)) { - + errno = EBADF; TALLOC_FREE(frame); return -1; - + } - + if (dir->file != False) { /* FIXME, should be dir, perhaps */ - + errno = ENOTDIR; TALLOC_FREE(frame); return -1; - + } - + /* See if we're already at the end. */ if (dir->dir_next == NULL) { /* We are. */ TALLOC_FREE(frame); return -1; } - + /* * We return the pointer here as the offset */ @@ -1369,28 +1379,28 @@ SMBC_telldir_ctx(SMBCCTX *context, static struct smbc_dir_list * check_dir_ent(struct smbc_dir_list *list, - struct smbc_dirent *dirent) + struct smbc_dirent *dirent) { - + /* Run down the list looking for what we want */ - + if (dirent) { - + struct smbc_dir_list *tmp = list; - + while (tmp) { - + if (tmp->dirent == dirent) return tmp; - + tmp = tmp->next; - + } - + } - + return NULL; /* Not found, or an error */ - + } @@ -1407,50 +1417,50 @@ SMBC_lseekdir_ctx(SMBCCTX *context, struct smbc_dirent *dirent = (struct smbc_dirent *)l_offset; struct smbc_dir_list *list_ent = (struct smbc_dir_list *)NULL; TALLOC_CTX *frame = talloc_stackframe(); - + if (!context || !context->internal->initialized) { - + errno = EINVAL; TALLOC_FREE(frame); return -1; - + } - + if (dir->file != False) { /* FIXME, should be dir, perhaps */ - + errno = ENOTDIR; TALLOC_FREE(frame); return -1; - + } - + /* Now, check what we were passed and see if it is OK ... */ - + if (dirent == NULL) { /* Seek to the begining of the list */ - + dir->dir_next = dir->dir_list; TALLOC_FREE(frame); return 0; - + } - + if (offset == -1) { /* Seek to the end of the list */ dir->dir_next = NULL; TALLOC_FREE(frame); return 0; } - + /* Now, run down the list and make sure that the entry is OK */ /* This may need to be changed if we change the format of the list */ - + if ((list_ent = check_dir_ent(dir->dir_list, dirent)) == NULL) { errno = EINVAL; /* Bad entry */ TALLOC_FREE(frame); return -1; } - + dir->dir_next = list_ent; - + TALLOC_FREE(frame); return 0; } @@ -1464,13 +1474,13 @@ SMBC_fstatdir_ctx(SMBCCTX *context, SMBCFILE *dir, struct stat *st) { - + if (!context || !context->internal->initialized) { - + errno = EINVAL; return -1; } - + /* No code yet ... */ return 0; } @@ -1489,37 +1499,37 @@ SMBC_chmod_ctx(SMBCCTX *context, char *path = NULL; uint16 mode; TALLOC_CTX *frame = talloc_stackframe(); - + if (!context || !context->internal->initialized) { - + errno = EINVAL; /* Best I can think of ... */ TALLOC_FREE(frame); return -1; } - + if (!fname) { errno = EINVAL; TALLOC_FREE(frame); return -1; } - + DEBUG(4, ("smbc_chmod(%s, 0%3o)\n", fname, newmode)); - + if (SMBC_parse_path(frame, - context, - fname, - &workgroup, - &server, - &share, - &path, - &user, - &password, - NULL)) { + context, + fname, + &workgroup, + &server, + &share, + &path, + &user, + &password, + NULL)) { errno = EINVAL; TALLOC_FREE(frame); return -1; } - + if (!user || user[0] == (char)0) { user = talloc_strdup(frame, context->config.user); if (!user) { @@ -1528,28 +1538,28 @@ SMBC_chmod_ctx(SMBCCTX *context, return -1; } } - + srv = SMBC_server(frame, context, True, server, share, &workgroup, &user, &password); - + if (!srv) { TALLOC_FREE(frame); return -1; /* errno set by SMBC_server */ } - + mode = 0; - + if (!(newmode & (S_IWUSR | S_IWGRP | S_IWOTH))) mode |= aRONLY; if ((newmode & S_IXUSR) && lp_map_archive(-1)) mode |= aARCH; if ((newmode & S_IXGRP) && lp_map_system(-1)) mode |= aSYSTEM; if ((newmode & S_IXOTH) && lp_map_hidden(-1)) mode |= aHIDDEN; - + if (!cli_setatr(srv->cli, path, mode, 0)) { errno = SMBC_errno(context, srv->cli); TALLOC_FREE(frame); return -1; } - + TALLOC_FREE(frame); return 0; } @@ -1569,63 +1579,63 @@ SMBC_utimes_ctx(SMBCCTX *context, time_t access_time; time_t write_time; TALLOC_CTX *frame = talloc_stackframe(); - + if (!context || !context->internal->initialized) { - + errno = EINVAL; /* Best I can think of ... */ TALLOC_FREE(frame); return -1; } - + if (!fname) { errno = EINVAL; TALLOC_FREE(frame); return -1; } - + if (tbuf == NULL) { access_time = write_time = time(NULL); } else { access_time = tbuf[0].tv_sec; write_time = tbuf[1].tv_sec; } - + if (DEBUGLVL(4)) { char *p; char atimebuf[32]; char mtimebuf[32]; - + strncpy(atimebuf, ctime(&access_time), sizeof(atimebuf) - 1); atimebuf[sizeof(atimebuf) - 1] = '\0'; if ((p = strchr(atimebuf, '\n')) != NULL) { *p = '\0'; } - + strncpy(mtimebuf, ctime(&write_time), sizeof(mtimebuf) - 1); mtimebuf[sizeof(mtimebuf) - 1] = '\0'; if ((p = strchr(mtimebuf, '\n')) != NULL) { *p = '\0'; } - + dbgtext("smbc_utimes(%s, atime = %s mtime = %s)\n", fname, atimebuf, mtimebuf); } - + if (SMBC_parse_path(frame, - context, - fname, - &workgroup, - &server, - &share, - &path, - &user, - &password, - NULL)) { + context, + fname, + &workgroup, + &server, + &share, + &path, + &user, + &password, + NULL)) { errno = EINVAL; TALLOC_FREE(frame); return -1; } - + if (!user || user[0] == (char)0) { user = talloc_strdup(frame, context->config.user); if (!user) { @@ -1634,21 +1644,21 @@ SMBC_utimes_ctx(SMBCCTX *context, return -1; } } - + srv = SMBC_server(frame, context, True, server, share, &workgroup, &user, &password); - + if (!srv) { TALLOC_FREE(frame); return -1; /* errno set by SMBC_server */ } - + if (!SMBC_setatr(context, srv, path, 0, access_time, write_time, 0, 0)) { TALLOC_FREE(frame); return -1; /* errno set by SMBC_setatr */ } - + TALLOC_FREE(frame); return 0; } @@ -1661,43 +1671,47 @@ int SMBC_unlink_ctx(SMBCCTX *context, const char *fname) { - char *server = NULL, *share = NULL, *user = NULL, *password = NULL, *workgroup = 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; SMBCSRV *srv = NULL; TALLOC_CTX *frame = talloc_stackframe(); - + if (!context || !context->internal->initialized) { - + errno = EINVAL; /* Best I can think of ... */ TALLOC_FREE(frame); return -1; - + } - + if (!fname) { errno = EINVAL; TALLOC_FREE(frame); return -1; - + } - + if (SMBC_parse_path(frame, - context, - fname, - &workgroup, - &server, - &share, - &path, - &user, - &password, - NULL)) { + context, + fname, + &workgroup, + &server, + &share, + &path, + &user, + &password, + NULL)) { errno = EINVAL; TALLOC_FREE(frame); return -1; } - + if (!user || user[0] == (char)0) { user = talloc_strdup(frame, context->config.user); if (!user) { @@ -1706,31 +1720,31 @@ SMBC_unlink_ctx(SMBCCTX *context, return -1; } } - + srv = SMBC_server(frame, context, True, server, share, &workgroup, &user, &password); - + if (!srv) { TALLOC_FREE(frame); return -1; /* SMBC_server sets errno */ - + } - + /*d_printf(">>>unlink: resolving %s\n", path);*/ if (!cli_resolve_path(frame, "", srv->cli, path, - &targetcli, &targetpath)) { + &targetcli, &targetpath)) { d_printf("Could not resolve %s\n", path); TALLOC_FREE(frame); return -1; } /*d_printf(">>>unlink: resolved path as %s\n", targetpath);*/ - + if (!cli_unlink(targetcli, targetpath)) { - + errno = SMBC_errno(context, targetcli); - + if (errno == EACCES) { /* Check if the file is a directory */ - + int saverr = errno; SMB_OFF_T size = 0; uint16 mode = 0; @@ -1738,39 +1752,39 @@ SMBC_unlink_ctx(SMBCCTX *context, struct timespec access_time_ts; struct timespec change_time_ts; SMB_INO_T ino = 0; - + if (!SMBC_getatr(context, srv, path, &mode, &size, NULL, &access_time_ts, &write_time_ts, &change_time_ts, &ino)) { - + /* Hmmm, bad error ... What? */ - + errno = SMBC_errno(context, targetcli); TALLOC_FREE(frame); return -1; - + } else { - + if (IS_DOS_DIR(mode)) errno = EISDIR; else errno = saverr; /* Restore this */ - + } } - + TALLOC_FREE(frame); return -1; - + } - + TALLOC_FREE(frame); return 0; /* Success ... */ - + } /* @@ -1800,39 +1814,39 @@ SMBC_rename_ctx(SMBCCTX *ocontext, struct cli_state *targetcli2 = NULL; SMBCSRV *srv = NULL; TALLOC_CTX *frame = talloc_stackframe(); - + if (!ocontext || !ncontext || !ocontext->internal->initialized || !ncontext->internal->initialized) { - + errno = EINVAL; /* Best I can think of ... */ TALLOC_FREE(frame); return -1; } - + if (!oname || !nname) { errno = EINVAL; TALLOC_FREE(frame); return -1; } - + DEBUG(4, ("smbc_rename(%s,%s)\n", oname, nname)); - + if (SMBC_parse_path(frame, - ocontext, - oname, - &workgroup, - &server1, - &share1, - &path1, - &user1, - &password1, - NULL)) { + ocontext, + oname, + &workgroup, + &server1, + &share1, + &path1, + &user1, + &password1, + NULL)) { errno = EINVAL; TALLOC_FREE(frame); return -1; } - + if (!user1 || user1[0] == (char)0) { user1 = talloc_strdup(frame, ocontext->config.user); if (!user1) { @@ -1841,22 +1855,22 @@ SMBC_rename_ctx(SMBCCTX *ocontext, return -1; } } - + if (SMBC_parse_path(frame, - ncontext, - nname, - NULL, - &server2, - &share2, - &path2, - &user2, - &password2, - NULL)) { + ncontext, + nname, + NULL, + &server2, + &share2, + &path2, + &user2, + &password2, + NULL)) { errno = EINVAL; TALLOC_FREE(frame); return -1; } - + if (!user2 || user2[0] == (char)0) { user2 = talloc_strdup(frame, ncontext->config.user); if (!user2) { @@ -1865,7 +1879,7 @@ SMBC_rename_ctx(SMBCCTX *ocontext, return -1; } } - + if (strcmp(server1, server2) || strcmp(share1, share2) || strcmp(user1, user2)) { /* Can't rename across file systems, or users?? */ @@ -1873,18 +1887,18 @@ SMBC_rename_ctx(SMBCCTX *ocontext, TALLOC_FREE(frame); return -1; } - + srv = SMBC_server(frame, ocontext, True, server1, share1, &workgroup, &user1, &password1); if (!srv) { TALLOC_FREE(frame); return -1; - + } - + /*d_printf(">>>rename: resolving %s\n", path1);*/ if (!cli_resolve_path(frame, "", srv->cli, path1, - &targetcli1, &targetpath1)) { + &targetcli1, &targetpath1)) { d_printf("Could not resolve %s\n", path1); TALLOC_FREE(frame); return -1; @@ -1892,13 +1906,13 @@ SMBC_rename_ctx(SMBCCTX *ocontext, /*d_printf(">>>rename: resolved path as %s\n", targetpath1);*/ /*d_printf(">>>rename: resolving %s\n", path2);*/ if (!cli_resolve_path(frame, "", srv->cli, path2, - &targetcli2, &targetpath2)) { + &targetcli2, &targetpath2)) { d_printf("Could not resolve %s\n", path2); TALLOC_FREE(frame); return -1; } /*d_printf(">>>rename: resolved path as %s\n", targetpath2);*/ - + if (strcmp(targetcli1->desthost, targetcli2->desthost) || strcmp(targetcli1->share, targetcli2->share)) { @@ -1907,21 +1921,21 @@ SMBC_rename_ctx(SMBCCTX *ocontext, TALLOC_FREE(frame); return -1; } - + if (!cli_rename(targetcli1, targetpath1, targetpath2)) { int eno = SMBC_errno(ocontext, targetcli1); - + if (eno != EEXIST || !cli_unlink(targetcli1, targetpath2) || !cli_rename(targetcli1, targetpath1, targetpath2)) { - + errno = eno; TALLOC_FREE(frame); return -1; - + } } - + TALLOC_FREE(frame); return 0; /* Success */ } diff --git a/source3/libsmb/libsmb_file.c b/source3/libsmb/libsmb_file.c index 62b990ed00..73c9b96978 100644 --- a/source3/libsmb/libsmb_file.c +++ b/source3/libsmb/libsmb_file.c @@ -37,7 +37,11 @@ SMBC_open_ctx(SMBCCTX *context, int flags, mode_t mode) { - char *server = NULL, *share = NULL, *user = NULL, *password = NULL, *workgroup = 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; @@ -45,38 +49,38 @@ SMBC_open_ctx(SMBCCTX *context, SMBCFILE *file = NULL; int fd; TALLOC_CTX *frame = talloc_stackframe(); - + if (!context || !context->internal->initialized) { - + errno = EINVAL; /* Best I can think of ... */ TALLOC_FREE(frame); return NULL; - + } - + if (!fname) { - + errno = EINVAL; TALLOC_FREE(frame); return NULL; - + } - + if (SMBC_parse_path(frame, - context, - fname, - &workgroup, - &server, - &share, - &path, - &user, - &password, - NULL)) { + context, + fname, + &workgroup, + &server, + &share, + &path, + &user, + &password, + NULL)) { errno = EINVAL; TALLOC_FREE(frame); return NULL; } - + if (!user || user[0] == (char)0) { user = talloc_strdup(frame, context->config.user); if (!user) { @@ -85,62 +89,63 @@ SMBC_open_ctx(SMBCCTX *context, return NULL; } } - + srv = SMBC_server(frame, context, True, server, share, &workgroup, &user, &password); - + if (!srv) { if (errno == EPERM) errno = EACCES; TALLOC_FREE(frame); return NULL; /* SMBC_server sets errno */ } - + /* Hmmm, the test for a directory is suspect here ... FIXME */ - + if (strlen(path) > 0 && path[strlen(path) - 1] == '\\') { fd = -1; } else { file = SMB_MALLOC_P(SMBCFILE); - + if (!file) { errno = ENOMEM; TALLOC_FREE(frame); return NULL; } - + ZERO_STRUCTP(file); - + /*d_printf(">>>open: resolving %s\n", path);*/ - if (!cli_resolve_path(frame, "", srv->cli, path, &targetcli, &targetpath)) { + if (!cli_resolve_path(frame, "", srv->cli, path, + &targetcli, &targetpath)) { d_printf("Could not resolve %s\n", path); SAFE_FREE(file); TALLOC_FREE(frame); return NULL; } /*d_printf(">>>open: resolved %s as %s\n", path, targetpath);*/ - + if ((fd = cli_open(targetcli, targetpath, flags, context->internal->share_mode)) < 0) { - + /* Handle the error ... */ - + SAFE_FREE(file); errno = SMBC_errno(context, targetcli); TALLOC_FREE(frame); return NULL; - + } - + /* Fill in file struct */ - + file->cli_fd = fd; file->fname = SMB_STRDUP(fname); file->srv = srv; file->offset = 0; file->file = True; - + DLIST_ADD(context->internal->files, file); - + /* * If the file was opened in O_APPEND mode, all write * operations should be appended to the file. To do that, @@ -171,51 +176,50 @@ SMBC_open_ctx(SMBCCTX *context, return NULL; } } - + TALLOC_FREE(frame); return file; - + } - + /* Check if opendir needed ... */ - + if (fd == -1) { int eno = 0; - + eno = SMBC_errno(context, srv->cli); file = (context->posix_emu.opendir_fn)(context, fname); if (!file) errno = eno; TALLOC_FREE(frame); return file; - + } - + errno = EINVAL; /* FIXME, correct errno ? */ TALLOC_FREE(frame); return NULL; - + } /* * Routine to create a file */ -static int creat_bits = O_WRONLY | O_CREAT | O_TRUNC; /* FIXME: Do we need this */ - SMBCFILE * SMBC_creat_ctx(SMBCCTX *context, const char *path, mode_t mode) { - + if (!context || !context->internal->initialized) { - + errno = EINVAL; return NULL; - + } - - return SMBC_open_ctx(context, path, creat_bits, mode); + + return SMBC_open_ctx(context, path, + O_WRONLY | O_CREAT | O_TRUNC, mode); } /* @@ -234,7 +238,7 @@ SMBC_read_ctx(SMBCCTX *context, char *targetpath = NULL; struct cli_state *targetcli = NULL; TALLOC_CTX *frame = talloc_stackframe(); - + /* * offset: * @@ -245,51 +249,51 @@ SMBC_read_ctx(SMBCCTX *context, * retrieving data at an offset greater than 4GB. */ off_t offset; - + if (!context || !context->internal->initialized) { - + errno = EINVAL; TALLOC_FREE(frame); return -1; - + } - + DEBUG(4, ("smbc_read(%p, %d)\n", file, (int)count)); - + if (!file || !SMBC_dlist_contains(context->internal->files, file)) { errno = EBADF; TALLOC_FREE(frame); return -1; - + } - + offset = file->offset; - + /* Check that the buffer exists ... */ - + if (buf == NULL) { errno = EINVAL; TALLOC_FREE(frame); return -1; - + } - + /*d_printf(">>>read: parsing %s\n", file->fname);*/ if (SMBC_parse_path(frame, - context, - file->fname, - NULL, - &server, - &share, - &path, - &user, - &password, - NULL)) { + context, + file->fname, + NULL, + &server, + &share, + &path, + &user, + &password, + NULL)) { errno = EINVAL; TALLOC_FREE(frame); return -1; } - + /*d_printf(">>>read: resolving %s\n", path);*/ if (!cli_resolve_path(frame, "", file->srv->cli, path, &targetcli, &targetpath)) { @@ -298,24 +302,24 @@ SMBC_read_ctx(SMBCCTX *context, return -1; } /*d_printf(">>>fstat: resolved path as %s\n", targetpath);*/ - + ret = cli_read(targetcli, file->cli_fd, (char *)buf, offset, count); - + if (ret < 0) { - + errno = SMBC_errno(context, targetcli); TALLOC_FREE(frame); return -1; - + } - + file->offset += ret; - + DEBUG(4, (" --> %d\n", ret)); - + TALLOC_FREE(frame); return ret; /* Success, ret bytes of data ... */ - + } /* @@ -335,50 +339,50 @@ SMBC_write_ctx(SMBCCTX *context, char *targetpath = NULL; struct cli_state *targetcli = NULL; TALLOC_CTX *frame = talloc_stackframe(); - + /* First check all pointers before dereferencing them */ - + if (!context || !context->internal->initialized) { - + errno = EINVAL; TALLOC_FREE(frame); return -1; - + } - + if (!file || !SMBC_dlist_contains(context->internal->files, file)) { errno = EBADF; TALLOC_FREE(frame); return -1; } - + /* Check that the buffer exists ... */ - + if (buf == NULL) { errno = EINVAL; TALLOC_FREE(frame); return -1; - + } - + offset = file->offset; /* See "offset" comment in SMBC_read_ctx() */ - + /*d_printf(">>>write: parsing %s\n", file->fname);*/ if (SMBC_parse_path(frame, - context, - file->fname, - NULL, - &server, - &share, - &path, - &user, - &password, - NULL)) { + context, + file->fname, + NULL, + &server, + &share, + &path, + &user, + &password, + NULL)) { errno = EINVAL; TALLOC_FREE(frame); return -1; } - + /*d_printf(">>>write: resolving %s\n", path);*/ if (!cli_resolve_path(frame, "", file->srv->cli, path, &targetcli, &targetpath)) { @@ -387,18 +391,19 @@ SMBC_write_ctx(SMBCCTX *context, return -1; } /*d_printf(">>>write: resolved path as %s\n", targetpath);*/ - - ret = cli_write(targetcli, file->cli_fd, 0, (char *)buf, offset, count); - + + ret = cli_write(targetcli, file->cli_fd, + 0, (char *)buf, offset, count); + if (ret <= 0) { errno = SMBC_errno(context, targetcli); TALLOC_FREE(frame); return -1; - + } - + file->offset += ret; - + TALLOC_FREE(frame); return ret; /* Success, 0 bytes of data ... */ } @@ -417,42 +422,42 @@ SMBC_close_ctx(SMBCCTX *context, char *targetpath = NULL; struct cli_state *targetcli = NULL; TALLOC_CTX *frame = talloc_stackframe(); - + if (!context || !context->internal->initialized) { - + errno = EINVAL; TALLOC_FREE(frame); return -1; } - + if (!file || !SMBC_dlist_contains(context->internal->files, file)) { errno = EBADF; TALLOC_FREE(frame); return -1; } - + /* IS a dir ... */ if (!file->file) { TALLOC_FREE(frame); return (context->posix_emu.closedir_fn)(context, file); } - + /*d_printf(">>>close: parsing %s\n", file->fname);*/ if (SMBC_parse_path(frame, - context, - file->fname, - NULL, - &server, - &share, - &path, - &user, - &password, - NULL)) { + context, + file->fname, + NULL, + &server, + &share, + &path, + &user, + &password, + NULL)) { errno = EINVAL; TALLOC_FREE(frame); return -1; } - + /*d_printf(">>>close: resolving %s\n", path);*/ if (!cli_resolve_path(frame, "", file->srv->cli, path, &targetcli, &targetpath)) { @@ -461,9 +466,9 @@ SMBC_close_ctx(SMBCCTX *context, return -1; } /*d_printf(">>>close: resolved path as %s\n", targetpath);*/ - + if (!cli_close(targetcli, file->cli_fd)) { - + DEBUG(3, ("cli_close failed on %s. purging server.\n", file->fname)); /* Deallocate slot and remove the server @@ -476,14 +481,14 @@ SMBC_close_ctx(SMBCCTX *context, (context->server.remove_unused_server_fn)(context, srv); TALLOC_FREE(frame); return -1; - + } - + DLIST_REMOVE(context->internal->files, file); SAFE_FREE(file->fname); SAFE_FREE(file); TALLOC_FREE(frame); - + return 0; } @@ -508,14 +513,14 @@ SMBC_getatr(SMBCCTX * context, struct cli_state *targetcli = NULL; time_t write_time; TALLOC_CTX *frame = talloc_stackframe(); - + if (!context || !context->internal->initialized) { - + errno = EINVAL; TALLOC_FREE(frame); return -1; } - + /* path fixup for . and .. */ if (strequal(path, ".") || strequal(path, "..")) { fixedpath = talloc_strdup(frame, "\\"); @@ -535,14 +540,14 @@ SMBC_getatr(SMBCCTX * context, trim_string(fixedpath, NULL, "\\."); } DEBUG(4,("SMBC_getatr: sending qpathinfo\n")); - + if (!cli_resolve_path(frame, "", srv->cli, fixedpath, - &targetcli, &targetpath)) { + &targetcli, &targetpath)) { d_printf("Couldn't resolve %s\n", path); TALLOC_FREE(frame); return False; } - + if (!srv->no_pathinfo2 && cli_qpathinfo2(targetcli, targetpath, create_time_ts, @@ -553,45 +558,45 @@ SMBC_getatr(SMBCCTX * context, TALLOC_FREE(frame); return True; } - + /* if this is NT then don't bother with the getatr */ if (targetcli->capabilities & CAP_NT_SMBS) { errno = EPERM; TALLOC_FREE(frame); return False; } - + if (cli_getatr(targetcli, targetpath, mode, size, &write_time)) { - + struct timespec w_time_ts; - + w_time_ts = convert_time_t_to_timespec(write_time); - + if (write_time_ts != NULL) { *write_time_ts = w_time_ts; } - + 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; } - + srv->no_pathinfo2 = True; TALLOC_FREE(frame); return True; } - + errno = EPERM; TALLOC_FREE(frame); return False; - + } /* @@ -615,7 +620,7 @@ SMBC_setatr(SMBCCTX * context, SMBCSRV *srv, char *path, int fd; int ret; TALLOC_CTX *frame = talloc_stackframe(); - + /* * First, try setpathinfo (if qpathinfo succeeded), for it is the * modern function for "new code" to be using, and it works given a @@ -629,7 +634,7 @@ SMBC_setatr(SMBCCTX * context, SMBCSRV *srv, char *path, write_time, change_time, mode)) { - + /* * setpathinfo is not supported; go to plan B. * @@ -639,27 +644,27 @@ SMBC_setatr(SMBCCTX * context, SMBCSRV *srv, char *path, * cli_setattrE() which should work on all OS versions, and * supports both times. */ - + /* Don't try {q,set}pathinfo() again, with this server */ srv->no_pathinfo = True; - + /* Open the file */ if ((fd = cli_open(srv->cli, path, O_RDWR, DENY_NONE)) < 0) { - + errno = SMBC_errno(context, srv->cli); TALLOC_FREE(frame); return -1; } - + /* Set the new attributes */ ret = cli_setattrE(srv->cli, fd, change_time, access_time, write_time); - + /* Close the file */ cli_close(srv->cli, fd); - + /* * Unfortunately, setattrE() doesn't have a provision for * setting the access mode (attributes). We'll have to try @@ -669,14 +674,14 @@ SMBC_setatr(SMBCCTX * context, SMBCSRV *srv, char *path, if (ret && mode != (uint16) -1) { ret = cli_setatr(srv->cli, path, mode, 0); } - + if (! ret) { errno = SMBC_errno(context, srv->cli); TALLOC_FREE(frame); return False; } } - + TALLOC_FREE(frame); return True; } @@ -697,56 +702,56 @@ SMBC_lseek_ctx(SMBCCTX *context, char *targetpath = NULL; struct cli_state *targetcli = NULL; TALLOC_CTX *frame = talloc_stackframe(); - + if (!context || !context->internal->initialized) { - + errno = EINVAL; TALLOC_FREE(frame); return -1; } - + if (!file || !SMBC_dlist_contains(context->internal->files, file)) { - + errno = EBADF; TALLOC_FREE(frame); return -1; - + } - + if (!file->file) { - + errno = EINVAL; TALLOC_FREE(frame); return -1; /* Can't lseek a dir ... */ - + } - + switch (whence) { case SEEK_SET: file->offset = offset; break; - + case SEEK_CUR: file->offset += offset; break; - + case SEEK_END: /*d_printf(">>>lseek: parsing %s\n", file->fname);*/ if (SMBC_parse_path(frame, - context, - file->fname, - NULL, - &server, - &share, - &path, - &user, - &password, - NULL)) { + context, + file->fname, + NULL, + &server, + &share, + &path, + &user, + &password, + NULL)) { errno = EINVAL; TALLOC_FREE(frame); return -1; } - + /*d_printf(">>>lseek: resolving %s\n", path);*/ if (!cli_resolve_path(frame, "", file->srv->cli, path, &targetcli, &targetpath)) { @@ -755,32 +760,32 @@ SMBC_lseek_ctx(SMBCCTX *context, return -1; } /*d_printf(">>>lseek: resolved path as %s\n", targetpath);*/ - + if (!cli_qfileinfo(targetcli, file->cli_fd, NULL, &size, NULL, NULL, NULL, NULL, NULL)) { - SMB_OFF_T b_size = size; + SMB_OFF_T b_size = size; if (!cli_getattrE(targetcli, file->cli_fd, NULL, &b_size, NULL, NULL, NULL)) - { - errno = EINVAL; - TALLOC_FREE(frame); - return -1; - } else - size = b_size; + { + errno = EINVAL; + TALLOC_FREE(frame); + return -1; + } else + size = b_size; } file->offset = size + offset; break; - + default: errno = EINVAL; break; - + } - + TALLOC_FREE(frame); return file->offset; - + } @@ -802,26 +807,26 @@ SMBC_ftruncate_ctx(SMBCCTX *context, char *targetpath = NULL; struct cli_state *targetcli = NULL; TALLOC_CTX *frame = talloc_stackframe(); - + if (!context || !context->internal->initialized) { - + errno = EINVAL; TALLOC_FREE(frame); return -1; } - + if (!file || !SMBC_dlist_contains(context->internal->files, file)) { errno = EBADF; TALLOC_FREE(frame); return -1; } - + if (!file->file) { errno = EINVAL; TALLOC_FREE(frame); return -1; } - + /*d_printf(">>>fstat: parsing %s\n", file->fname);*/ if (SMBC_parse_path(frame, context, @@ -837,7 +842,7 @@ SMBC_ftruncate_ctx(SMBCCTX *context, TALLOC_FREE(frame); return -1; } - + /*d_printf(">>>fstat: resolving %s\n", path);*/ if (!cli_resolve_path(frame, "", file->srv->cli, path, &targetcli, &targetpath)) { @@ -846,14 +851,14 @@ SMBC_ftruncate_ctx(SMBCCTX *context, return -1; } /*d_printf(">>>fstat: resolved path as %s\n", targetpath);*/ - + if (!cli_ftruncate(targetcli, file->cli_fd, size)) { errno = EINVAL; TALLOC_FREE(frame); return -1; } - + TALLOC_FREE(frame); return 0; - + } diff --git a/source3/libsmb/libsmb_misc.c b/source3/libsmb/libsmb_misc.c index f2fd919ef6..dd7add5a61 100644 --- a/source3/libsmb/libsmb_misc.c +++ b/source3/libsmb/libsmb_misc.c @@ -50,24 +50,24 @@ SMBC_errno(SMBCCTX *context, struct cli_state *c) { int ret = cli_errno(c); - + if (cli_is_dos_error(c)) { uint8 eclass; uint32 ecode; - + cli_dos_error(c, &eclass, &ecode); DEBUG(3,("smbc_error %d %d (0x%x) -> %d\n", (int)eclass, (int)ecode, (int)ecode, ret)); } else { NTSTATUS status; - + status = cli_nt_error(c); - + DEBUG(3,("smbc errno %s -> %d\n", nt_errstr(status), ret)); } - + return ret; } diff --git a/source3/libsmb/libsmb_path.c b/source3/libsmb/libsmb_path.c index 6706a59ba8..c962f898e0 100644 --- a/source3/libsmb/libsmb_path.c +++ b/source3/libsmb/libsmb_path.c @@ -31,13 +31,13 @@ static int hex2int( unsigned int _char ) { - if ( _char >= 'A' && _char <='F') - return _char - 'A' + 10; - if ( _char >= 'a' && _char <='f') - return _char - 'a' + 10; - if ( _char >= '0' && _char <='9') - return _char - '0'; - return -1; + if ( _char >= 'A' && _char <='F') + return _char - 'A' + 10; + if ( _char >= 'a' && _char <='f') + return _char - 'a' + 10; + if ( _char >= '0' && _char <='9') + return _char - '0'; + return -1; } /* @@ -60,19 +60,19 @@ urldecode_talloc(TALLOC_CTX *ctx, char **pp_dest, const char *src) int err_count = 0; size_t newlen = 1; char *p, *dest; - + if (old_length == 0) { return 0; } - + *pp_dest = NULL; for (i = 0; i < old_length; ) { unsigned char character = src[i++]; - + if (character == '%') { int a = i+1 < old_length ? hex2int(src[i]) : -1; int b = i+1 < old_length ? hex2int(src[i+1]) : -1; - + /* Replace valid sequence */ if (a != -1 && b != -1) { /* Replace valid %xx sequence with %dd */ @@ -87,20 +87,20 @@ urldecode_talloc(TALLOC_CTX *ctx, char **pp_dest, const char *src) } newlen++; } - + dest = TALLOC_ARRAY(ctx, char, newlen); if (!dest) { return err_count; } - + err_count = 0; for (p = dest, i = 0; i < old_length; ) { unsigned char character = src[i++]; - + if (character == '%') { int a = i+1 < old_length ? hex2int(src[i]) : -1; int b = i+1 < old_length ? hex2int(src[i+1]) : -1; - + /* Replace valid sequence */ if (a != -1 && b != -1) { /* Replace valid %xx sequence with %dd */ @@ -115,7 +115,7 @@ urldecode_talloc(TALLOC_CTX *ctx, char **pp_dest, const char *src) } *p++ = character; } - + *p = '\0'; *pp_dest = dest; return err_count; @@ -129,7 +129,7 @@ SMBC_urldecode(char *dest, TALLOC_CTX *frame = talloc_stackframe(); char *pdest; int ret = urldecode_talloc(frame, &pdest, src); - + if (pdest) { strlcpy(dest, pdest, max_dest_len); } @@ -151,9 +151,9 @@ SMBC_urlencode(char *dest, int max_dest_len) { char hex[] = "0123456789ABCDEF"; - + for (; *src != '\0' && max_dest_len >= 3; src++) { - + if ((*src < '0' && *src != '-' && *src != '.') || @@ -172,10 +172,10 @@ SMBC_urlencode(char *dest, max_dest_len--; } } - + *dest++ = '\0'; max_dest_len--; - + return max_dest_len; } @@ -196,9 +196,9 @@ SMBC_urlencode(char *dest, * * The method of locating the list of workgroups varies * depending upon the setting of the context variable - * context->browse_max_lmb_count. This value determines - * the maximum number of local master browsers to query - * for the list of workgroups. In order to ensure that + * context->options.browse_max_lmb_count. This value + * determines the maximum number of local master browsers to + * query for the list of workgroups. In order to ensure that * a complete list of workgroups is obtained, all master * browsers must be queried, but if there are many * workgroups, the time spent querying can begin to add up. @@ -234,75 +234,75 @@ SMBC_parse_path(TALLOC_CTX *ctx, const char *p; char *q, *r; int len; - + /* Ensure these returns are at least valid pointers. */ *pp_server = talloc_strdup(ctx, ""); *pp_share = talloc_strdup(ctx, ""); *pp_path = talloc_strdup(ctx, ""); *pp_user = talloc_strdup(ctx, ""); *pp_password = talloc_strdup(ctx, ""); - + if (!*pp_server || !*pp_share || !*pp_path || - !*pp_user || !*pp_password) { + !*pp_user || !*pp_password) { return -1; } - + /* * Assume we wont find an authentication domain to parse, so default * to the workgroup in the provided context. */ if (pp_workgroup != NULL) { *pp_workgroup = - talloc_strdup(ctx, context->config.workgroup); + talloc_strdup(ctx, context->config.workgroup); } - + if (pp_options) { *pp_options = talloc_strdup(ctx, ""); } s = talloc_strdup(ctx, fname); - + /* see if it has the right prefix */ len = strlen(smbc_prefix); if (strncmp(s,smbc_prefix,len) || (s[len] != '/' && s[len] != 0)) { return -1; /* What about no smb: ? */ } - + p = s + len; - + /* Watch the test below, we are testing to see if we should exit */ - + if (strncmp(p, "//", 2) && strncmp(p, "\\\\", 2)) { DEBUG(1, ("Invalid path (does not begin with smb://")); return -1; } - + p += 2; /* Skip the double slash */ - + /* See if any options were specified */ if ((q = strrchr(p, '?')) != NULL ) { /* There are options. Null terminate here and point to them */ *q++ = '\0'; - + DEBUG(4, ("Found options '%s'", q)); - + /* Copy the options */ if (*pp_options != NULL) { TALLOC_FREE(*pp_options); *pp_options = talloc_strdup(ctx, q); } } - + if (*p == '\0') { goto decoding; } - + if (*p == '/') { int wl = strlen(context->config.workgroup); - + if (wl > 16) { wl = 16; } - + *pp_server = talloc_strdup(ctx, context->config.workgroup); if (!*pp_server) { return -1; @@ -310,27 +310,27 @@ SMBC_parse_path(TALLOC_CTX *ctx, *pp_server[wl] = '\0'; return 0; } - + /* * ok, its for us. Now parse out the server, share etc. * * However, we want to parse out [[domain;]user[:password]@] if it * exists ... */ - + /* check that '@' occurs before '/', if '/' exists at all */ q = strchr_m(p, '@'); r = strchr_m(p, '/'); if (q && (!r || q < r)) { char *userinfo = NULL; const char *u; - + next_token_no_ltrim_talloc(ctx, &p, &userinfo, "@"); if (!userinfo) { return -1; } u = userinfo; - + if (strchr_m(u, ';')) { char *workgroup; next_token_no_ltrim_talloc(ctx, &u, &workgroup, ";"); @@ -341,7 +341,7 @@ SMBC_parse_path(TALLOC_CTX *ctx, *pp_workgroup = workgroup; } } - + if (strchr_m(u, ':')) { next_token_no_ltrim_talloc(ctx, &u, pp_user, ":"); if (!*pp_user) { @@ -358,27 +358,27 @@ SMBC_parse_path(TALLOC_CTX *ctx, } } } - + if (!next_token_talloc(ctx, &p, pp_server, "/")) { return -1; } - + if (*p == (char)0) { goto decoding; /* That's it ... */ } - + if (!next_token_talloc(ctx, &p, pp_share, "/")) { return -1; } - + /* * Prepend a leading slash if there's a file path, as required by * NetApp filers. */ if (*p != '\0') { *pp_path = talloc_asprintf(ctx, - "\\%s", - p); + "\\%s", + p); } else { *pp_path = talloc_strdup(ctx, ""); } @@ -386,15 +386,15 @@ SMBC_parse_path(TALLOC_CTX *ctx, return -1; } string_replace(*pp_path, '/', '\\'); - - decoding: - + +decoding: + (void) urldecode_talloc(ctx, pp_path, *pp_path); (void) urldecode_talloc(ctx, pp_server, *pp_server); (void) urldecode_talloc(ctx, pp_share, *pp_share); (void) urldecode_talloc(ctx, pp_user, *pp_user); (void) urldecode_talloc(ctx, pp_password, *pp_password); - + return 0; } diff --git a/source3/libsmb/libsmb_printjob.c b/source3/libsmb/libsmb_printjob.c index a03c15e024..545225cae4 100644 --- a/source3/libsmb/libsmb_printjob.c +++ b/source3/libsmb/libsmb_printjob.c @@ -41,39 +41,39 @@ SMBC_open_print_job_ctx(SMBCCTX *context, char *password = NULL; char *path = NULL; TALLOC_CTX *frame = talloc_stackframe(); - + if (!context || !context->internal->initialized) { - + errno = EINVAL; TALLOC_FREE(frame); return NULL; } - + if (!fname) { errno = EINVAL; TALLOC_FREE(frame); return NULL; } - + DEBUG(4, ("SMBC_open_print_job_ctx(%s)\n", fname)); - + if (SMBC_parse_path(frame, - context, - fname, - NULL, - &server, - &share, - &path, - &user, - &password, - NULL)) { + context, + fname, + NULL, + &server, + &share, + &path, + &user, + &password, + NULL)) { errno = EINVAL; TALLOC_FREE(frame); return NULL; } - + /* What if the path is empty, or the file exists? */ - + TALLOC_FREE(frame); return (context->posix_emu.open_fn)(context, fname, O_WRONLY, 666); } @@ -98,77 +98,79 @@ SMBC_print_file_ctx(SMBCCTX *c_file, int tot_bytes = 0; char buf[4096]; TALLOC_CTX *frame = talloc_stackframe(); - + if (!c_file || !c_file->internal->initialized || !c_print || !c_print->internal->initialized) { - + errno = EINVAL; TALLOC_FREE(frame); return -1; - + } - + if (!fname && !printq) { - + errno = EINVAL; TALLOC_FREE(frame); return -1; - + } - + /* Try to open the file for reading ... */ - - if ((long)(fid1 = smbc_getFunctionOpen(c_file)(c_file, fname, O_RDONLY, 0666)) < 0) { + + if ((long)(fid1 = smbc_getFunctionOpen(c_file)(c_file, fname, + O_RDONLY, 0666)) < 0) { DEBUG(3, ("Error, fname=%s, errno=%i\n", fname, errno)); TALLOC_FREE(frame); return -1; /* smbc_open sets errno */ } - + /* Now, try to open the printer file for writing */ - - if ((long)(fid2 = smbc_getFunctionOpenPrintJob(c_print)(c_print, printq)) < 0) { - + + if ((long)(fid2 = smbc_getFunctionOpenPrintJob(c_print)(c_print, + printq)) < 0) { + saverr = errno; /* Save errno */ smbc_getFunctionClose(c_file)(c_file, fid1); errno = saverr; TALLOC_FREE(frame); return -1; - + } - + while ((bytes = smbc_getFunctionRead(c_file)(c_file, fid1, buf, sizeof(buf))) > 0) { - + tot_bytes += bytes; - + if ((smbc_getFunctionWrite(c_print)(c_print, fid2, buf, bytes)) < 0) { - + saverr = errno; smbc_getFunctionClose(c_file)(c_file, fid1); smbc_getFunctionClose(c_print)(c_print, fid2); errno = saverr; - + } - + } - + saverr = errno; - - smbc_getFunctionClose(c_file)(c_file, fid1); /* We have to close these anyway */ + + smbc_getFunctionClose(c_file)(c_file, fid1); smbc_getFunctionClose(c_print)(c_print, fid2); - + if (bytes < 0) { - + errno = saverr; TALLOC_FREE(frame); return -1; - + } - + TALLOC_FREE(frame); return tot_bytes; - + } /* @@ -188,37 +190,37 @@ SMBC_list_print_jobs_ctx(SMBCCTX *context, char *workgroup = NULL; char *path = NULL; TALLOC_CTX *frame = talloc_stackframe(); - + if (!context || !context->internal->initialized) { - + errno = EINVAL; TALLOC_FREE(frame); return -1; } - + if (!fname) { errno = EINVAL; TALLOC_FREE(frame); return -1; } - + DEBUG(4, ("smbc_list_print_jobs(%s)\n", fname)); - + if (SMBC_parse_path(frame, - context, - fname, - &workgroup, - &server, - &share, - &path, - &user, - &password, - NULL)) { + context, + fname, + &workgroup, + &server, + &share, + &path, + &user, + &password, + NULL)) { errno = EINVAL; TALLOC_FREE(frame); return -1; } - + if (!user || user[0] == (char)0) { user = talloc_strdup(frame, context->config.user); if (!user) { @@ -227,25 +229,25 @@ SMBC_list_print_jobs_ctx(SMBCCTX *context, return -1; } } - + srv = SMBC_server(frame, context, True, server, share, &workgroup, &user, &password); - + if (!srv) { TALLOC_FREE(frame); return -1; /* errno set by SMBC_server */ } - + if (cli_print_queue(srv->cli, (void (*)(struct print_job_info *))fn) < 0) { errno = SMBC_errno(context, srv->cli); TALLOC_FREE(frame); return -1; } - + TALLOC_FREE(frame); return 0; - + } /* @@ -266,37 +268,37 @@ SMBC_unlink_print_job_ctx(SMBCCTX *context, char *path = NULL; int err; TALLOC_CTX *frame = talloc_stackframe(); - + if (!context || !context->internal->initialized) { - + errno = EINVAL; TALLOC_FREE(frame); return -1; } - + if (!fname) { errno = EINVAL; TALLOC_FREE(frame); return -1; } - + DEBUG(4, ("smbc_unlink_print_job(%s)\n", fname)); - + if (SMBC_parse_path(frame, - context, - fname, - &workgroup, - &server, - &share, - &path, - &user, - &password, - NULL)) { + context, + fname, + &workgroup, + &server, + &share, + &path, + &user, + &password, + NULL)) { errno = EINVAL; TALLOC_FREE(frame); return -1; } - + if (!user || user[0] == (char)0) { user = talloc_strdup(frame, context->config.user); if (!user) { @@ -305,30 +307,30 @@ SMBC_unlink_print_job_ctx(SMBCCTX *context, return -1; } } - + srv = SMBC_server(frame, context, True, server, share, &workgroup, &user, &password); - + if (!srv) { - + TALLOC_FREE(frame); return -1; /* errno set by SMBC_server */ - + } - + if ((err = cli_printjob_del(srv->cli, id)) != 0) { - + if (err < 0) errno = SMBC_errno(context, srv->cli); else if (err == ERRnosuchprintjob) errno = EINVAL; TALLOC_FREE(frame); return -1; - + } - + TALLOC_FREE(frame); return 0; - + } diff --git a/source3/libsmb/libsmb_server.c b/source3/libsmb/libsmb_server.c index 70e0d57273..4f51388870 100644 --- a/source3/libsmb/libsmb_server.c +++ b/source3/libsmb/libsmb_server.c @@ -40,7 +40,7 @@ SMBC_check_server(SMBCCTX * context, { socklen_t size; struct sockaddr addr; - + size = sizeof(addr); return (getpeername(server->cli->fd, &addr, &size) == -1); } @@ -56,12 +56,12 @@ SMBC_remove_unused_server(SMBCCTX * context, SMBCSRV * srv) { SMBCFILE * file; - + /* are we being fooled ? */ if (!context || !context->internal->initialized || !srv) { return 1; } - + /* Check all open files/directories for a relation with this server */ for (file = context->internal->files; file; file = file->next) { if (file->srv == srv) { @@ -72,16 +72,16 @@ SMBC_remove_unused_server(SMBCCTX * context, return 1; } } - + DLIST_REMOVE(context->internal->servers, srv); - + cli_shutdown(srv->cli); srv->cli = NULL; - + DEBUG(3, ("smbc_remove_usused_server: %p removed.\n", srv)); - + (context->cache.remove_cached_server_fn)(context, srv); - + SAFE_FREE(srv); return 0; } @@ -101,21 +101,21 @@ SMBC_call_auth_fn(TALLOC_CTX *ctx, fstring workgroup; fstring username; fstring password; - + strlcpy(workgroup, *pp_workgroup, sizeof(workgroup)); strlcpy(username, *pp_username, sizeof(username)); strlcpy(password, *pp_password, sizeof(password)); - + (context->server.get_auth_data_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); @@ -144,23 +144,23 @@ SMBC_find_server(TALLOC_CTX *ctx, { SMBCSRV *srv; int auth_called = 0; - - check_server_cache: - + +check_server_cache: + srv = (context->cache.get_cached_server_fn)(context, server, share, *pp_workgroup, *pp_username); - + if (!auth_called && !srv && (!*pp_username || !(*pp_username)[0] || - !*pp_password || !(*pp_password)[0])) { + !*pp_password || !(*pp_password)[0])) { SMBC_call_auth_fn(ctx, context, server, share, - pp_workgroup, pp_username, pp_password); - + pp_workgroup, pp_username, pp_password); + if (!pp_workgroup || !pp_username || !pp_password) { return NULL; } - + /* * However, smbc_auth_fn may have picked up info relating to * an existing connection, so try for an existing connection @@ -168,9 +168,9 @@ SMBC_find_server(TALLOC_CTX *ctx, */ auth_called = 1; goto check_server_cache; - + } - + if (srv) { if ((context->server.check_server_fn)(context, srv)) { /* @@ -189,17 +189,17 @@ SMBC_find_server(TALLOC_CTX *ctx, (context->cache.remove_cached_server_fn)(context, srv); } - + /* * Maybe there are more cached connections to this * server */ goto check_server_cache; } - + return srv; } - + return NULL; } @@ -234,25 +234,25 @@ SMBC_server(TALLOC_CTX *ctx, int port_try_next; const char *username_used; NTSTATUS status; - + zero_addr(&ss); ZERO_STRUCT(c); - + if (server[0] == 0) { errno = EPERM; return NULL; } - + /* Look for a cached connection */ srv = SMBC_find_server(ctx, context, server, share, - pp_workgroup, pp_username, pp_password); - + pp_workgroup, pp_username, pp_password); + /* * If we found a connection and we're only allowed one share per * server... */ - if (srv && *share != '\0' && context->internal->one_share_per_server) { - + if (srv && *share != '\0' && context->options.one_share_per_server) { + /* * ... then if there's no current connection to the share, * connect to it. SMBC_find_server(), or rather the function @@ -264,8 +264,10 @@ SMBC_server(TALLOC_CTX *ctx, if (srv->cli->cnum == (uint16) -1) { /* Ensure we have accurate auth info */ SMBC_call_auth_fn(ctx, context, server, share, - pp_workgroup, pp_username, pp_password); - + pp_workgroup, + pp_username, + pp_password); + if (!*pp_workgroup || !*pp_username || !*pp_password) { errno = ENOMEM; cli_shutdown(srv->cli); @@ -274,17 +276,17 @@ SMBC_server(TALLOC_CTX *ctx, 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, "?????", - *pp_password, - strlen(*pp_password)+1)) { - + *pp_password, + strlen(*pp_password)+1)) { + errno = SMBC_errno(context, srv->cli); cli_shutdown(srv->cli); srv->cli = NULL; @@ -292,7 +294,7 @@ SMBC_server(TALLOC_CTX *ctx, srv); srv = NULL; } - + /* * Regenerate the dev value since it's based on both * server and share @@ -303,51 +305,51 @@ SMBC_server(TALLOC_CTX *ctx, } } } - + /* If we have a connection... */ if (srv) { - + /* ... then we're done here. Give 'em what they came for. */ return srv; } - + /* If we're not asked to connect when a connection doesn't exist... */ if (! connect_if_not_found) { /* ... then we're done here. */ return NULL; } - + if (!*pp_workgroup || !*pp_username || !*pp_password) { errno = ENOMEM; return NULL; } - + make_nmb_name(&calling, context->config.netbios_name, 0x0); make_nmb_name(&called , server, 0x20); - + DEBUG(4,("SMBC_server: server_n=[%s] server=[%s]\n", server_n, server)); - + DEBUG(4,(" -> server_n=[%s] server=[%s]\n", server_n, server)); - - again: - + +again: + zero_addr(&ss); - + /* have to open a new connection */ if ((c = cli_initialise()) == NULL) { errno = ENOMEM; return NULL; } - + if (context->flags.bits & SMB_CTX_FLAG_USE_KERBEROS) { c->use_kerberos = True; } if (context->flags.bits & SMB_CTX_FLAG_FALLBACK_AFTER_KERBEROS) { c->fallback_after_kerberos = True; } - + c->timeout = context->config.timeout; - + /* * Force use of port 139 for first try if share is $IPC, empty, or * null, so browse lists can work @@ -359,15 +361,15 @@ SMBC_server(TALLOC_CTX *ctx, port_try_first = 445; port_try_next = 139; } - + c->port = port_try_first; - + status = cli_connect(c, server_n, &ss); if (!NT_STATUS_IS_OK(status)) { - + /* First connection attempt failed. Try alternate port. */ c->port = port_try_next; - + status = cli_connect(c, server_n, &ss); if (!NT_STATUS_IS_OK(status)) { cli_shutdown(c); @@ -375,33 +377,36 @@ SMBC_server(TALLOC_CTX *ctx, return NULL; } } - + if (!cli_session_request(c, &calling, &called)) { cli_shutdown(c); if (strcmp(called.name, "*SMBSERVER")) { make_nmb_name(&called , "*SMBSERVER", 0x20); goto again; } else { /* Try one more time, but ensure we don't loop */ - + /* Only try this if server is an IP address ... */ - + if (is_ipaddress(server) && !tried_reverse) { fstring remote_name; struct sockaddr_storage rem_ss; - + if (!interpret_string_addr(&rem_ss, server, - NI_NUMERICHOST)) { + NI_NUMERICHOST)) { DEBUG(4, ("Could not convert IP address " - "%s to struct sockaddr_storage\n", - server)); + "%s to struct sockaddr_storage\n", + server)); errno = ETIMEDOUT; return NULL; } - + tried_reverse++; /* Yuck */ - - if (name_status_find("*", 0, 0, &rem_ss, remote_name)) { - make_nmb_name(&called, remote_name, 0x20); + + if (name_status_find("*", 0, 0, + &rem_ss, remote_name)) { + make_nmb_name(&called, + remote_name, + 0x20); goto again; } } @@ -409,64 +414,66 @@ SMBC_server(TALLOC_CTX *ctx, errno = ETIMEDOUT; return NULL; } - + DEBUG(4,(" session request ok\n")); - + if (!cli_negprot(c)) { cli_shutdown(c); errno = ETIMEDOUT; return NULL; } - + username_used = *pp_username; - + if (!NT_STATUS_IS_OK(cli_session_setup(c, username_used, - *pp_password, strlen(*pp_password), - *pp_password, strlen(*pp_password), + *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.bits & SMBCCTX_FLAG_NO_AUTO_ANONYMOUS_LOGON) || !NT_STATUS_IS_OK(cli_session_setup(c, username_used, *pp_password, 1, *pp_password, 0, *pp_workgroup))) { - + cli_shutdown(c); errno = EPERM; return NULL; } } - + DEBUG(4,(" session setup ok\n")); - + if (!cli_send_tconX(c, share, "?????", *pp_password, strlen(*pp_password)+1)) { errno = SMBC_errno(context, c); cli_shutdown(c); return NULL; } - + 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))) { - + username_used, + *pp_password, + *pp_workgroup))) { + /* * context->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; @@ -475,25 +482,25 @@ SMBC_server(TALLOC_CTX *ctx, } DEBUG(4,(" SMB encrypt ok\n")); } - + /* * Ok, we have got a nice connection * Let's allocate a server structure. */ - + srv = SMB_MALLOC_P(SMBCSRV); if (!srv) { errno = ENOMEM; goto failed; } - + ZERO_STRUCTP(srv); srv->cli = c; srv->dev = (dev_t)(str_checksum(server) ^ str_checksum(share)); srv->no_pathinfo = False; srv->no_pathinfo2 = False; srv->no_nt_session = False; - + /* now add it to the cache (internal or external) */ /* Let the cache function set errno if it wants to */ errno = 0; @@ -509,19 +516,19 @@ SMBC_server(TALLOC_CTX *ctx, } goto failed; } - + DEBUG(2, ("Server connect ok: //%s/%s: %p\n", server, share, srv)); - + DLIST_ADD(context->internal->servers, srv); return srv; - - failed: + +failed: cli_shutdown(c); if (!srv) { return NULL; } - + SAFE_FREE(srv); return NULL; } @@ -545,32 +552,34 @@ SMBC_attr_server(TALLOC_CTX *ctx, struct rpc_pipe_client *pipe_hnd; NTSTATUS nt_status; SMBCSRV *ipc_srv=NULL; - + /* * See if we've already created this special connection. Reference * our "special" share name '*IPC$', which is an impossible real share * name due to the leading asterisk. */ ipc_srv = SMBC_find_server(ctx, context, server, "*IPC$", - pp_workgroup, pp_username, pp_password); + pp_workgroup, pp_username, pp_password); if (!ipc_srv) { - + /* We didn't find a cached connection. Get the password */ if (!*pp_password || (*pp_password)[0] == '\0') { /* ... then retrieve it now. */ SMBC_call_auth_fn(ctx, context, server, share, - pp_workgroup, pp_username, pp_password); + pp_workgroup, + pp_username, + pp_password); if (!*pp_workgroup || !*pp_username || !*pp_password) { errno = ENOMEM; return NULL; } } - + flags = 0; if (context->flags.bits & SMB_CTX_FLAG_USE_KERBEROS) { flags |= CLI_FULL_CONNECTION_USE_KERBEROS; } - + zero_addr(&ss); nt_status = cli_full_connection(&ipc_cli, global_myname(), server, @@ -586,23 +595,23 @@ SMBC_attr_server(TALLOC_CTX *ctx, errno = ENOTSUP; 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))) { - + *pp_username, + *pp_password, + *pp_workgroup))) { + /* * context->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; @@ -611,49 +620,49 @@ SMBC_attr_server(TALLOC_CTX *ctx, } DEBUG(4,(" SMB encrypt ok on IPC$\n")); } - + ipc_srv = SMB_MALLOC_P(SMBCSRV); if (!ipc_srv) { errno = ENOMEM; cli_shutdown(ipc_cli); return NULL; } - + ZERO_STRUCTP(ipc_srv); ipc_srv->cli = ipc_cli; - + 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; + 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, - &ipc_srv->pol); - + 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; + 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->cache.add_cached_server_fn)(context, ipc_srv, server, @@ -668,9 +677,9 @@ SMBC_attr_server(TALLOC_CTX *ctx, free(ipc_srv); return NULL; } - + DLIST_ADD(context->internal->servers, ipc_srv); } - + return ipc_srv; } diff --git a/source3/libsmb/libsmb_stat.c b/source3/libsmb/libsmb_stat.c index 6072547e08..b733eab74f 100644 --- a/source3/libsmb/libsmb_stat.c +++ b/source3/libsmb/libsmb_stat.c @@ -33,18 +33,18 @@ static ino_t generate_inode(SMBCCTX *context, - const char *name) + const char *name) { if (!context || !context->internal->initialized) { - + errno = EINVAL; return -1; - + } - + if (!*name) return 2; /* FIXME, why 2 ??? */ return (ino_t)str_checksum(name); - + } /* @@ -54,26 +54,26 @@ generate_inode(SMBCCTX *context, static int setup_stat(SMBCCTX *context, - struct stat *st, - char *fname, - SMB_OFF_T size, - int mode) + struct stat *st, + char *fname, + SMB_OFF_T size, + int mode) { TALLOC_CTX *frame = talloc_stackframe(); - + st->st_mode = 0; - + if (IS_DOS_DIR(mode)) { st->st_mode = SMBC_DIR_MODE; } else { st->st_mode = SMBC_FILE_MODE; } - + if (IS_DOS_ARCHIVE(mode)) st->st_mode |= S_IXUSR; if (IS_DOS_SYSTEM(mode)) st->st_mode |= S_IXGRP; if (IS_DOS_HIDDEN(mode)) st->st_mode |= S_IXOTH; if (!IS_DOS_READONLY(mode)) st->st_mode |= S_IWUSR; - + st->st_size = size; #ifdef HAVE_STAT_ST_BLKSIZE st->st_blksize = 512; @@ -86,20 +86,20 @@ setup_stat(SMBCCTX *context, #endif st->st_uid = getuid(); st->st_gid = getgid(); - + if (IS_DOS_DIR(mode)) { st->st_nlink = 2; } else { st->st_nlink = 1; } - + if (st->st_ino == 0) { st->st_ino = generate_inode(context, fname); } - + TALLOC_FREE(frame); return True; /* FIXME: Is this needed ? */ - + } /* @@ -125,37 +125,37 @@ SMBC_stat_ctx(SMBCCTX *context, uint16 mode = 0; SMB_INO_T ino = 0; TALLOC_CTX *frame = talloc_stackframe(); - + if (!context || !context->internal->initialized) { - + errno = EINVAL; /* Best I can think of ... */ TALLOC_FREE(frame); return -1; } - + if (!fname) { errno = EINVAL; TALLOC_FREE(frame); return -1; } - + DEBUG(4, ("smbc_stat(%s)\n", fname)); - + if (SMBC_parse_path(frame, - context, - fname, - &workgroup, - &server, - &share, - &path, - &user, - &password, - NULL)) { + context, + fname, + &workgroup, + &server, + &share, + &path, + &user, + &password, + NULL)) { errno = EINVAL; TALLOC_FREE(frame); return -1; } - + if (!user || user[0] == (char)0) { user = talloc_strdup(frame,context->config.user); if (!user) { @@ -164,15 +164,15 @@ SMBC_stat_ctx(SMBCCTX *context, return -1; } } - + srv = SMBC_server(frame, context, True, server, share, &workgroup, &user, &password); - + if (!srv) { TALLOC_FREE(frame); return -1; /* errno set by SMBC_server */ } - + if (!SMBC_getatr(context, srv, path, &mode, &size, NULL, &access_time_ts, @@ -183,19 +183,19 @@ SMBC_stat_ctx(SMBCCTX *context, TALLOC_FREE(frame); return -1; } - + st->st_ino = ino; - + setup_stat(context, st, (char *) fname, size, mode); - + set_atimespec(st, access_time_ts); set_ctimespec(st, change_time_ts); set_mtimespec(st, write_time_ts); st->st_dev = srv->dev; - + TALLOC_FREE(frame); return 0; - + } /* @@ -221,41 +221,41 @@ SMBC_fstat_ctx(SMBCCTX *context, struct cli_state *targetcli = NULL; SMB_INO_T ino = 0; TALLOC_CTX *frame = talloc_stackframe(); - + if (!context || !context->internal->initialized) { - + errno = EINVAL; TALLOC_FREE(frame); return -1; } - + if (!file || !SMBC_dlist_contains(context->internal->files, file)) { errno = EBADF; TALLOC_FREE(frame); return -1; } - + if (!file->file) { TALLOC_FREE(frame); return (context->posix_emu.fstatdir_fn)(context, file, st); } - + /*d_printf(">>>fstat: parsing %s\n", file->fname);*/ if (SMBC_parse_path(frame, - context, - file->fname, - NULL, - &server, - &share, - &path, - &user, - &password, - NULL)) { + context, + file->fname, + NULL, + &server, + &share, + &path, + &user, + &password, + NULL)) { errno = EINVAL; TALLOC_FREE(frame); return -1; } - + /*d_printf(">>>fstat: resolving %s\n", path);*/ if (!cli_resolve_path(frame, "", file->srv->cli, path, &targetcli, &targetpath)) { @@ -264,39 +264,39 @@ SMBC_fstat_ctx(SMBCCTX *context, return -1; } /*d_printf(">>>fstat: resolved path as %s\n", targetpath);*/ - + if (!cli_qfileinfo(targetcli, file->cli_fd, &mode, &size, NULL, &access_time_ts, &write_time_ts, &change_time_ts, &ino)) { - + time_t change_time, access_time, write_time; - + if (!cli_getattrE(targetcli, file->cli_fd, &mode, &size, - &change_time, &access_time, &write_time)) { - + &change_time, &access_time, &write_time)) { + errno = EINVAL; TALLOC_FREE(frame); return -1; } - + change_time_ts = convert_time_t_to_timespec(change_time); access_time_ts = convert_time_t_to_timespec(access_time); write_time_ts = convert_time_t_to_timespec(write_time); } - + st->st_ino = ino; - + setup_stat(context, st, file->fname, size, mode); - + set_atimespec(st, access_time_ts); set_ctimespec(st, change_time_ts); set_mtimespec(st, write_time_ts); st->st_dev = file->srv->dev; - + TALLOC_FREE(frame); return 0; - + } diff --git a/source3/libsmb/libsmb_xattr.c b/source3/libsmb/libsmb_xattr.c index a420299341..3c08412d59 100644 --- a/source3/libsmb/libsmb_xattr.c +++ b/source3/libsmb/libsmb_xattr.c @@ -34,16 +34,16 @@ static struct rpc_pipe_client * find_lsa_pipe_hnd(struct cli_state *ipc_cli) { struct rpc_pipe_client *pipe_hnd; - + for (pipe_hnd = ipc_cli->pipe_list; pipe_hnd; pipe_hnd = pipe_hnd->next) { - + if (pipe_hnd->pipe_idx == PI_LSARPC) { return pipe_hnd; } } - + return NULL; } @@ -59,19 +59,19 @@ ace_compare(SEC_ACE *ace1, { bool b1; bool b2; - + /* If the ACEs are equal, we have nothing more to do. */ if (sec_ace_equal(ace1, ace2)) { return 0; } - + /* Inherited follow non-inherited */ b1 = ((ace1->flags & SEC_ACE_FLAG_INHERITED_ACE) != 0); b2 = ((ace2->flags & SEC_ACE_FLAG_INHERITED_ACE) != 0); if (b1 != b2) { return (b1 ? 1 : -1); } - + /* * What shall we do with AUDITs and ALARMs? It's undefined. We'll * sort them after DENY and ALLOW. @@ -87,7 +87,7 @@ ace_compare(SEC_ACE *ace1, if (b1 != b2) { return (b1 ? 1 : -1); } - + /* Allowed ACEs follow denied ACEs */ b1 = (ace1->type == SEC_ACE_TYPE_ACCESS_ALLOWED || ace1->type == SEC_ACE_TYPE_ACCESS_ALLOWED_OBJECT); @@ -96,7 +96,7 @@ ace_compare(SEC_ACE *ace1, if (b1 != b2) { return (b1 ? 1 : -1); } - + /* * ACEs applying to an entity's object follow those applying to the * entity itself @@ -108,34 +108,34 @@ ace_compare(SEC_ACE *ace1, if (b1 != b2) { return (b1 ? 1 : -1); } - + /* * If we get this far, the ACEs are similar as far as the * characteristics we typically care about (those defined by the * referenced MS document). We'll now sort by characteristics that * just seems reasonable. */ - + if (ace1->type != ace2->type) { return ace2->type - ace1->type; } - + if (sid_compare(&ace1->trustee, &ace2->trustee)) { return sid_compare(&ace1->trustee, &ace2->trustee); } - + if (ace1->flags != ace2->flags) { return ace1->flags - ace2->flags; } - + if (ace1->access_mask != ace2->access_mask) { return ace1->access_mask - ace2->access_mask; } - + if (ace1->size != ace2->size) { return ace1->size - ace2->size; } - + return memcmp(ace1, ace2, sizeof(SEC_ACE)); } @@ -145,10 +145,10 @@ sort_acl(SEC_ACL *the_acl) { uint32 i; if (!the_acl) return; - + qsort(the_acl->aces, the_acl->num_aces, sizeof(the_acl->aces[0]), QSORT_CAST ace_compare); - + for (i=1;inum_aces;) { if (sec_ace_equal(&the_acl->aces[i-1], &the_acl->aces[i])) { int j; @@ -175,32 +175,32 @@ convert_sid_to_string(struct cli_state *ipc_cli, enum lsa_SidType *types = NULL; struct rpc_pipe_client *pipe_hnd = find_lsa_pipe_hnd(ipc_cli); TALLOC_CTX *ctx; - + sid_to_fstring(str, sid); - + if (numeric) { return; /* no lookup desired */ } - + if (!pipe_hnd) { return; } - + /* Ask LSA to convert the sid to a name */ - + ctx = talloc_stackframe(); - + if (!NT_STATUS_IS_OK(rpccli_lsa_lookup_sids(pipe_hnd, ctx, - pol, 1, sid, &domains, - &names, &types)) || + pol, 1, sid, &domains, + &names, &types)) || !domains || !domains[0] || !names || !names[0]) { TALLOC_FREE(ctx); return; } - + TALLOC_FREE(ctx); /* Converted OK */ - + slprintf(str, sizeof(fstring) - 1, "%s%s%s", domains[0], lp_winbind_separator(), names[0]); @@ -219,31 +219,32 @@ convert_string_to_sid(struct cli_state *ipc_cli, bool result = True; TALLOC_CTX *ctx = NULL; struct rpc_pipe_client *pipe_hnd = find_lsa_pipe_hnd(ipc_cli); - + if (!pipe_hnd) { return False; } - + if (numeric) { if (strncmp(str, "S-", 2) == 0) { return string_to_sid(sid, str); } - + result = False; goto done; } - + ctx = talloc_stackframe(); if (!NT_STATUS_IS_OK(rpccli_lsa_lookup_names(pipe_hnd, ctx, - pol, 1, &str, NULL, 1, &sids, - &types))) { + pol, 1, &str, + NULL, 1, &sids, + &types))) { result = False; goto done; } - + sid_copy(sid, &sids[0]); - done: - +done: + TALLOC_FREE(ctx); return result; } @@ -271,7 +272,7 @@ parse_ace(struct cli_state *ipc_cli, uint32 mask; }; TALLOC_CTX *frame = talloc_stackframe(); - + /* These values discovered by inspection */ static const struct perm_value special_values[] = { { "R", 0x00120089 }, @@ -282,15 +283,15 @@ parse_ace(struct cli_state *ipc_cli, { "O", 0x00080000 }, { NULL, 0 }, }; - + static const struct perm_value standard_values[] = { { "READ", 0x001200a9 }, { "CHANGE", 0x001301bf }, { "FULL", 0x001f01ff }, { NULL, 0 }, }; - - + + ZERO_STRUCTP(ace); p = strchr_m(str,':'); if (!p) { @@ -300,25 +301,25 @@ parse_ace(struct cli_state *ipc_cli, *p = '\0'; p++; /* Try to parse numeric form */ - + if (sscanf(p, "%i/%i/%i", &atype, &aflags, &amask) == 3 && convert_string_to_sid(ipc_cli, pol, numeric, &sid, str)) { goto done; } - + /* Try to parse text form */ - + if (!convert_string_to_sid(ipc_cli, pol, numeric, &sid, str)) { TALLOC_FREE(frame); return false; } - + cp = p; if (!next_token_talloc(frame, &cp, &tok, "/")) { TALLOC_FREE(frame); return false; } - + if (StrnCaseCmp(tok, "ALLOWED", strlen("ALLOWED")) == 0) { atype = SEC_ACE_TYPE_ACCESS_ALLOWED; } else if (StrnCaseCmp(tok, "DENIED", strlen("DENIED")) == 0) { @@ -327,20 +328,20 @@ parse_ace(struct cli_state *ipc_cli, TALLOC_FREE(frame); return false; } - + /* Only numeric form accepted for flags at present */ - + if (!(next_token_talloc(frame, &cp, &tok, "/") && sscanf(tok, "%i", &aflags))) { TALLOC_FREE(frame); return false; } - + if (!next_token_talloc(frame, &cp, &tok, "/")) { TALLOC_FREE(frame); return false; } - + if (strncmp(tok, "0x", 2) == 0) { if (sscanf(tok, "%i", &amask) != 1) { TALLOC_FREE(frame); @@ -348,39 +349,39 @@ parse_ace(struct cli_state *ipc_cli, } goto done; } - + for (v = standard_values; v->perm; v++) { if (strcmp(tok, v->perm) == 0) { amask = v->mask; goto done; } } - + p = tok; - + while(*p) { bool found = False; - + for (v = special_values; v->perm; v++) { if (v->perm[0] == *p) { amask |= v->mask; found = True; } } - + if (!found) { TALLOC_FREE(frame); return false; } p++; } - + if (*p) { TALLOC_FREE(frame); return false; } - - done: + +done: mask = amask; init_sec_ace(ace, &sid, atype, mask, aflags); TALLOC_FREE(frame); @@ -395,13 +396,14 @@ add_ace(SEC_ACL **the_acl, { SEC_ACL *newacl; SEC_ACE *aces; - + if (! *the_acl) { (*the_acl) = make_sec_acl(ctx, 3, 1, ace); return True; } - - if ((aces = SMB_CALLOC_ARRAY(SEC_ACE, 1+(*the_acl)->num_aces)) == NULL) { + + if ((aces = SMB_CALLOC_ARRAY(SEC_ACE, + 1+(*the_acl)->num_aces)) == NULL) { return False; } memcpy(aces, (*the_acl)->aces, (*the_acl)->num_aces * sizeof(SEC_ACE)); @@ -430,17 +432,17 @@ sec_desc_parse(TALLOC_CTX *ctx, DOM_SID *owner_sid=NULL; SEC_ACL *dacl=NULL; int revision=1; - + while (next_token_talloc(ctx, &p, &tok, "\t,\r\n")) { - + if (StrnCaseCmp(tok,"REVISION:", 9) == 0) { revision = strtol(tok+9, NULL, 16); continue; } - + if (StrnCaseCmp(tok,"OWNER:", 6) == 0) { if (owner_sid) { - DEBUG(5, ("OWNER specified more than once!\n")); + DEBUG(5,("OWNER specified more than once!\n")); goto done; } owner_sid = SMB_CALLOC_ARRAY(DOM_SID, 1); @@ -453,10 +455,10 @@ sec_desc_parse(TALLOC_CTX *ctx, } continue; } - + if (StrnCaseCmp(tok,"OWNER+:", 7) == 0) { if (owner_sid) { - DEBUG(5, ("OWNER specified more than once!\n")); + DEBUG(5,("OWNER specified more than once!\n")); goto done; } owner_sid = SMB_CALLOC_ARRAY(DOM_SID, 1); @@ -469,10 +471,10 @@ sec_desc_parse(TALLOC_CTX *ctx, } continue; } - + if (StrnCaseCmp(tok,"GROUP:", 6) == 0) { if (group_sid) { - DEBUG(5, ("GROUP specified more than once!\n")); + DEBUG(5,("GROUP specified more than once!\n")); goto done; } group_sid = SMB_CALLOC_ARRAY(DOM_SID, 1); @@ -485,10 +487,10 @@ sec_desc_parse(TALLOC_CTX *ctx, } continue; } - + if (StrnCaseCmp(tok,"GROUP+:", 7) == 0) { if (group_sid) { - DEBUG(5, ("GROUP specified more than once!\n")); + DEBUG(5,("GROUP specified more than once!\n")); goto done; } group_sid = SMB_CALLOC_ARRAY(DOM_SID, 1); @@ -501,7 +503,7 @@ sec_desc_parse(TALLOC_CTX *ctx, } continue; } - + if (StrnCaseCmp(tok,"ACL:", 4) == 0) { SEC_ACE ace; if (!parse_ace(ipc_cli, pol, &ace, numeric, tok+4)) { @@ -514,7 +516,7 @@ sec_desc_parse(TALLOC_CTX *ctx, } continue; } - + if (StrnCaseCmp(tok,"ACL+:", 5) == 0) { SEC_ACE ace; if (!parse_ace(ipc_cli, pol, &ace, False, tok+5)) { @@ -527,18 +529,18 @@ sec_desc_parse(TALLOC_CTX *ctx, } continue; } - + DEBUG(5, ("Failed to parse security descriptor\n")); goto done; } - + ret = make_sec_desc(ctx, revision, SEC_DESC_SELF_RELATIVE, owner_sid, group_sid, NULL, dacl, &sd_size); - - done: + +done: SAFE_FREE(group_sid); SAFE_FREE(owner_sid); - + return ret; } @@ -558,13 +560,13 @@ dos_attr_query(SMBCCTX *context, uint16 mode = 0; SMB_INO_T inode = 0; DOS_ATTR_DESC *ret; - + ret = TALLOC_P(ctx, DOS_ATTR_DESC); if (!ret) { errno = ENOMEM; return NULL; } - + /* Obtain the DOS attributes */ if (!SMBC_getatr(context, srv, CONST_DISCARD(char *, filename), &mode, &size, @@ -577,7 +579,7 @@ dos_attr_query(SMBCCTX *context, DEBUG(5, ("dos_attr_query Failed to query old attributes\n")); return NULL; } - + ret->mode = mode; ret->size = size; ret->create_time = convert_timespec_to_time_t(create_time_ts); @@ -585,7 +587,7 @@ dos_attr_query(SMBCCTX *context, ret->write_time = convert_timespec_to_time_t(write_time_ts); ret->change_time = convert_timespec_to_time_t(change_time_ts); ret->inode = inode; - + return ret; } @@ -607,7 +609,7 @@ dos_attr_parse(SMBCCTX *context, const char * write_time_attr; const char * change_time_attr; } attr_strings; - + /* Determine whether to use old-style or new-style attribute names */ if (context->internal->full_time_names) { /* new-style names */ @@ -622,7 +624,7 @@ dos_attr_parse(SMBCCTX *context, attr_strings.write_time_attr = "M_TIME"; attr_strings.change_time_attr = "C_TIME"; } - + /* if this is to set the entire ACL... */ if (*str == '*') { /* ... then increment past the first colon if there is one */ @@ -632,7 +634,7 @@ dos_attr_parse(SMBCCTX *context, p = str; } } - + frame = talloc_stackframe(); while (next_token_talloc(frame, &p, &tok, "\t,\r\n")) { if (StrnCaseCmp(tok, "MODE:", 5) == 0) { @@ -647,30 +649,30 @@ dos_attr_parse(SMBCCTX *context, } continue; } - + if (StrnCaseCmp(tok, "SIZE:", 5) == 0) { dad->size = (SMB_OFF_T)atof(tok+5); continue; } - + n = strlen(attr_strings.access_time_attr); if (StrnCaseCmp(tok, attr_strings.access_time_attr, n) == 0) { dad->access_time = (time_t)strtol(tok+n+1, NULL, 10); continue; } - + n = strlen(attr_strings.change_time_attr); if (StrnCaseCmp(tok, attr_strings.change_time_attr, n) == 0) { dad->change_time = (time_t)strtol(tok+n+1, NULL, 10); continue; } - + n = strlen(attr_strings.write_time_attr); if (StrnCaseCmp(tok, attr_strings.write_time_attr, n) == 0) { dad->write_time = (time_t)strtol(tok+n+1, NULL, 10); continue; } - + if (attr_strings.create_time_attr != NULL) { n = strlen(attr_strings.create_time_attr); if (StrnCaseCmp(tok, attr_strings.create_time_attr, @@ -680,7 +682,7 @@ dos_attr_parse(SMBCCTX *context, continue; } } - + if (StrnCaseCmp(tok, "INODE:", 6) == 0) { dad->inode = (SMB_INO_T)atof(tok+6); continue; @@ -757,7 +759,7 @@ cacl_get(SMBCCTX *context, const char * write_time_attr; const char * change_time_attr; } excl_attr_strings; - + /* Determine whether to use old-style or new-style attribute names */ if (context->internal->full_time_names) { /* new-style names */ @@ -765,7 +767,7 @@ cacl_get(SMBCCTX *context, attr_strings.access_time_attr = "ACCESS_TIME"; attr_strings.write_time_attr = "WRITE_TIME"; attr_strings.change_time_attr = "CHANGE_TIME"; - + excl_attr_strings.create_time_attr = "CREATE_TIME"; excl_attr_strings.access_time_attr = "ACCESS_TIME"; excl_attr_strings.write_time_attr = "WRITE_TIME"; @@ -776,28 +778,28 @@ cacl_get(SMBCCTX *context, attr_strings.access_time_attr = "A_TIME"; attr_strings.write_time_attr = "M_TIME"; attr_strings.change_time_attr = "C_TIME"; - + excl_attr_strings.create_time_attr = NULL; excl_attr_strings.access_time_attr = "dos_attr.A_TIME"; excl_attr_strings.write_time_attr = "dos_attr.M_TIME"; excl_attr_strings.change_time_attr = "dos_attr.C_TIME"; } - + /* Copy name so we can strip off exclusions (if any are specified) */ strncpy(name_sandbox, attr_name, sizeof(name_sandbox) - 1); - + /* Ensure name is null terminated */ name_sandbox[sizeof(name_sandbox) - 1] = '\0'; - + /* Play in the sandbox */ name = name_sandbox; - + /* If there are any exclusions, point to them and mask them from name */ if ((pExclude = strchr(name, '!')) != NULL) { *pExclude++ = '\0'; } - + all = (StrnCaseCmp(name, "system.*", 8) == 0); all_nt = (StrnCaseCmp(name, "system.nt_sec_desc.*", 20) == 0); all_nt_acls = (StrnCaseCmp(name, "system.nt_sec_desc.acl.*", 24) == 0); @@ -805,71 +807,77 @@ cacl_get(SMBCCTX *context, some_nt = (StrnCaseCmp(name, "system.nt_sec_desc.", 19) == 0); some_dos = (StrnCaseCmp(name, "system.dos_attr.", 16) == 0); numeric = (* (name + strlen(name) - 1) != '+'); - + /* Look for exclusions from "all" requests */ if (all || all_nt || all_dos) { - + /* Exclusions are delimited by '!' */ for (; pExclude != NULL; pExclude = (p == NULL ? NULL : p + 1)) { - - /* Find end of this exclusion name */ - if ((p = strchr(pExclude, '!')) != NULL) - { - *p = '\0'; - } - - /* Which exclusion name is this? */ - if (StrCaseCmp(pExclude, "nt_sec_desc.revision") == 0) { - exclude_nt_revision = True; - } - else if (StrCaseCmp(pExclude, "nt_sec_desc.owner") == 0) { - exclude_nt_owner = True; - } - else if (StrCaseCmp(pExclude, "nt_sec_desc.group") == 0) { - exclude_nt_group = True; - } - else if (StrCaseCmp(pExclude, "nt_sec_desc.acl") == 0) { - exclude_nt_acl = True; - } - else if (StrCaseCmp(pExclude, "dos_attr.mode") == 0) { - exclude_dos_mode = True; - } - else if (StrCaseCmp(pExclude, "dos_attr.size") == 0) { - exclude_dos_size = True; - } - else if (excl_attr_strings.create_time_attr != NULL && - StrCaseCmp(pExclude, - excl_attr_strings.change_time_attr) == 0) { - exclude_dos_create_time = True; - } - else if (StrCaseCmp(pExclude, - excl_attr_strings.access_time_attr) == 0) { - exclude_dos_access_time = True; - } - else if (StrCaseCmp(pExclude, - excl_attr_strings.write_time_attr) == 0) { - exclude_dos_write_time = True; - } - else if (StrCaseCmp(pExclude, - excl_attr_strings.change_time_attr) == 0) { - exclude_dos_change_time = True; - } - else if (StrCaseCmp(pExclude, "dos_attr.inode") == 0) { - exclude_dos_inode = True; - } - else { - DEBUG(5, ("cacl_get received unknown exclusion: %s\n", - pExclude)); - errno = ENOATTR; - return -1; + + /* Find end of this exclusion name */ + if ((p = strchr(pExclude, '!')) != NULL) + { + *p = '\0'; + } + + /* Which exclusion name is this? */ + if (StrCaseCmp(pExclude, + "nt_sec_desc.revision") == 0) { + exclude_nt_revision = True; + } + else if (StrCaseCmp(pExclude, + "nt_sec_desc.owner") == 0) { + exclude_nt_owner = True; + } + else if (StrCaseCmp(pExclude, + "nt_sec_desc.group") == 0) { + exclude_nt_group = True; + } + else if (StrCaseCmp(pExclude, + "nt_sec_desc.acl") == 0) { + exclude_nt_acl = True; + } + else if (StrCaseCmp(pExclude, + "dos_attr.mode") == 0) { + exclude_dos_mode = True; + } + else if (StrCaseCmp(pExclude, + "dos_attr.size") == 0) { + exclude_dos_size = True; + } + else if (excl_attr_strings.create_time_attr != NULL && + StrCaseCmp(pExclude, + excl_attr_strings.change_time_attr) == 0) { + exclude_dos_create_time = True; + } + else if (StrCaseCmp(pExclude, + excl_attr_strings.access_time_attr) == 0) { + exclude_dos_access_time = True; + } + else if (StrCaseCmp(pExclude, + excl_attr_strings.write_time_attr) == 0) { + exclude_dos_write_time = True; + } + else if (StrCaseCmp(pExclude, + excl_attr_strings.change_time_attr) == 0) { + exclude_dos_change_time = True; + } + else if (StrCaseCmp(pExclude, "dos_attr.inode") == 0) { + exclude_dos_inode = True; + } + else { + DEBUG(5, ("cacl_get received unknown exclusion: %s\n", + pExclude)); + errno = ENOATTR; + return -1; + } } - } } - + n_used = 0; - + /* * If we are (possibly) talking to an NT or new system and some NT * attributes have been requested... @@ -877,28 +885,28 @@ cacl_get(SMBCCTX *context, if (ipc_cli && (all || some_nt || all_nt_acls)) { /* Point to the portion after "system.nt_sec_desc." */ name += 19; /* if (all) this will be invalid but unused */ - + /* ... then obtain any NT attributes which were requested */ fnum = cli_nt_create(cli, filename, CREATE_ACCESS_READ); - + if (fnum == -1) { DEBUG(5, ("cacl_get failed to open %s: %s\n", filename, cli_errstr(cli))); errno = 0; return -1; } - + sd = cli_query_secdesc(cli, fnum, ctx); - + if (!sd) { DEBUG(5, ("cacl_get Failed to query old descriptor\n")); errno = 0; return -1; } - + cli_close(cli, fnum); - + if (! exclude_nt_revision) { if (all || all_nt) { if (determine_size) { @@ -929,7 +937,7 @@ cacl_get(SMBCCTX *context, sd->revision); } } - + if (!determine_size && n > bufsize) { errno = ERANGE; return -1; @@ -939,7 +947,7 @@ cacl_get(SMBCCTX *context, bufsize -= n; n = 0; } - + if (! exclude_nt_owner) { /* Get owner and group sid */ if (sd->owner_sid) { @@ -950,7 +958,7 @@ cacl_get(SMBCCTX *context, } else { fstrcpy(sidstr, ""); } - + if (all || all_nt) { if (determine_size) { p = talloc_asprintf(ctx, ",OWNER:%s", @@ -977,7 +985,7 @@ cacl_get(SMBCCTX *context, sidstr); } } - + if (!determine_size && n > bufsize) { errno = ERANGE; return -1; @@ -987,7 +995,7 @@ cacl_get(SMBCCTX *context, bufsize -= n; n = 0; } - + if (! exclude_nt_group) { if (sd->group_sid) { convert_sid_to_string(ipc_cli, pol, @@ -996,7 +1004,7 @@ cacl_get(SMBCCTX *context, } else { fstrcpy(sidstr, ""); } - + if (all || all_nt) { if (determine_size) { p = talloc_asprintf(ctx, ",GROUP:%s", @@ -1023,7 +1031,7 @@ cacl_get(SMBCCTX *context, "%s", sidstr); } } - + if (!determine_size && n > bufsize) { errno = ERANGE; return -1; @@ -1033,16 +1041,16 @@ cacl_get(SMBCCTX *context, bufsize -= n; n = 0; } - + if (! exclude_nt_acl) { /* Add aces to value buffer */ for (i = 0; sd->dacl && i < sd->dacl->num_aces; i++) { - + SEC_ACE *ace = &sd->dacl->aces[i]; convert_sid_to_string(ipc_cli, pol, sidstr, numeric, &ace->trustee); - + if (all || all_nt) { if (determine_size) { p = talloc_asprintf( @@ -1125,15 +1133,15 @@ cacl_get(SMBCCTX *context, n = 0; } } - + /* Restore name pointer to its original value */ name -= 19; } - + if (all || some_dos) { /* Point to the portion after "system.dos_attr." */ name += 16; /* if (all) this will be invalid but unused */ - + /* Obtain the DOS attributes */ if (!SMBC_getatr(context, srv, filename, &mode, &size, &create_time_ts, @@ -1141,17 +1149,17 @@ cacl_get(SMBCCTX *context, &write_time_ts, &change_time_ts, &ino)) { - + errno = SMBC_errno(context, srv->cli); return -1; - + } - + create_time = convert_timespec_to_time_t(create_time_ts); access_time = convert_timespec_to_time_t(access_time_ts); write_time = convert_timespec_to_time_t(write_time_ts); change_time = convert_timespec_to_time_t(change_time_ts); - + if (! exclude_dos_mode) { if (all || all_dos) { if (determine_size) { @@ -1189,7 +1197,7 @@ cacl_get(SMBCCTX *context, "0x%x", mode); } } - + if (!determine_size && n > bufsize) { errno = ERANGE; return -1; @@ -1199,7 +1207,7 @@ cacl_get(SMBCCTX *context, bufsize -= n; n = 0; } - + if (! exclude_dos_size) { if (all || all_dos) { if (determine_size) { @@ -1234,7 +1242,7 @@ cacl_get(SMBCCTX *context, (double)size); } } - + if (!determine_size && n > bufsize) { errno = ERANGE; return -1; @@ -1244,7 +1252,7 @@ cacl_get(SMBCCTX *context, bufsize -= n; n = 0; } - + if (! exclude_dos_create_time && attr_strings.create_time_attr != NULL) { if (all || all_dos) { @@ -1277,7 +1285,7 @@ cacl_get(SMBCCTX *context, "%lu", create_time); } } - + if (!determine_size && n > bufsize) { errno = ERANGE; return -1; @@ -1287,7 +1295,7 @@ cacl_get(SMBCCTX *context, bufsize -= n; n = 0; } - + if (! exclude_dos_access_time) { if (all || all_dos) { if (determine_size) { @@ -1319,7 +1327,7 @@ cacl_get(SMBCCTX *context, "%lu", access_time); } } - + if (!determine_size && n > bufsize) { errno = ERANGE; return -1; @@ -1329,7 +1337,7 @@ cacl_get(SMBCCTX *context, bufsize -= n; n = 0; } - + if (! exclude_dos_write_time) { if (all || all_dos) { if (determine_size) { @@ -1361,7 +1369,7 @@ cacl_get(SMBCCTX *context, "%lu", write_time); } } - + if (!determine_size && n > bufsize) { errno = ERANGE; return -1; @@ -1371,7 +1379,7 @@ cacl_get(SMBCCTX *context, bufsize -= n; n = 0; } - + if (! exclude_dos_change_time) { if (all || all_dos) { if (determine_size) { @@ -1403,7 +1411,7 @@ cacl_get(SMBCCTX *context, "%lu", change_time); } } - + if (!determine_size && n > bufsize) { errno = ERANGE; return -1; @@ -1413,7 +1421,7 @@ cacl_get(SMBCCTX *context, bufsize -= n; n = 0; } - + if (! exclude_dos_inode) { if (all || all_dos) { if (determine_size) { @@ -1448,7 +1456,7 @@ cacl_get(SMBCCTX *context, (double) ino); } } - + if (!determine_size && n > bufsize) { errno = ERANGE; return -1; @@ -1458,16 +1466,16 @@ cacl_get(SMBCCTX *context, bufsize -= n; n = 0; } - + /* Restore name pointer to its original value */ name -= 16; } - + if (n_used == 0) { errno = ENOATTR; return -1; } - + return n_used; } @@ -1495,68 +1503,68 @@ cacl_set(TALLOC_CTX *ctx, int ret = 0; char *p; bool numeric = True; - + /* the_acl will be null for REMOVE_ALL operations */ if (the_acl) { numeric = ((p = strchr(the_acl, ':')) != NULL && p > the_acl && p[-1] != '+'); - + /* if this is to set the entire ACL... */ if (*the_acl == '*') { /* ... then increment past the first colon */ the_acl = p + 1; } - + sd = sec_desc_parse(ctx, ipc_cli, pol, numeric, CONST_DISCARD(char *, the_acl)); - + if (!sd) { errno = EINVAL; return -1; } } - + /* SMBC_XATTR_MODE_REMOVE_ALL is the only caller that doesn't deref sd */ - + if (!sd && (mode != SMBC_XATTR_MODE_REMOVE_ALL)) { errno = EINVAL; return -1; } - + /* The desired access below is the only one I could find that works with NT4, W2KP and Samba */ - + fnum = cli_nt_create(cli, filename, CREATE_ACCESS_READ); - + if (fnum == -1) { DEBUG(5, ("cacl_set failed to open %s: %s\n", filename, cli_errstr(cli))); errno = 0; return -1; } - + old = cli_query_secdesc(cli, fnum, ctx); - + if (!old) { DEBUG(5, ("cacl_set Failed to query old descriptor\n")); errno = 0; return -1; } - + cli_close(cli, fnum); - + switch (mode) { case SMBC_XATTR_MODE_REMOVE_ALL: old->dacl->num_aces = 0; dacl = old->dacl; break; - + case SMBC_XATTR_MODE_REMOVE: for (i=0;sd->dacl && idacl->num_aces;i++) { bool found = False; - + for (j=0;old->dacl && jdacl->num_aces;j++) { if (sec_ace_equal(&sd->dacl->aces[i], &old->dacl->aces[j])) { @@ -1571,7 +1579,7 @@ cacl_set(TALLOC_CTX *ctx, break; } } - + if (!found) { err = ENOATTR; ret = -1; @@ -1579,11 +1587,11 @@ cacl_set(TALLOC_CTX *ctx, } } break; - + case SMBC_XATTR_MODE_ADD: for (i=0;sd->dacl && idacl->num_aces;i++) { bool found = False; - + for (j=0;old->dacl && jdacl->num_aces;j++) { if (sid_equal(&sd->dacl->aces[i].trustee, &old->dacl->aces[j].trustee)) { @@ -1597,67 +1605,67 @@ cacl_set(TALLOC_CTX *ctx, found = True; } } - + if (!found && (flags & SMBC_XATTR_FLAG_REPLACE)) { err = ENOATTR; ret = -1; goto failed; } - + for (i=0;sd->dacl && idacl->num_aces;i++) { add_ace(&old->dacl, &sd->dacl->aces[i], ctx); } } dacl = old->dacl; break; - + case SMBC_XATTR_MODE_SET: old = sd; owner_sid = old->owner_sid; group_sid = old->group_sid; dacl = old->dacl; break; - + case SMBC_XATTR_MODE_CHOWN: owner_sid = sd->owner_sid; break; - + case SMBC_XATTR_MODE_CHGRP: group_sid = sd->group_sid; break; } - + /* Denied ACE entries must come before allowed ones */ sort_acl(old->dacl); - + /* Create new security descriptor and set it */ sd = make_sec_desc(ctx, old->revision, SEC_DESC_SELF_RELATIVE, owner_sid, group_sid, NULL, dacl, &sd_size); - + fnum = cli_nt_create(cli, filename, WRITE_DAC_ACCESS | WRITE_OWNER_ACCESS); - + if (fnum == -1) { DEBUG(5, ("cacl_set failed to open %s: %s\n", filename, cli_errstr(cli))); errno = 0; return -1; } - + if (!cli_set_secdesc(cli, fnum, sd)) { DEBUG(5, ("ERROR: secdesc set failed: %s\n", cli_errstr(cli))); ret = -1; } - + /* Clean up */ - - failed: + +failed: cli_close(cli, fnum); - + if (err != 0) { errno = err; } - + return ret; } @@ -1688,38 +1696,38 @@ SMBC_setxattr_ctx(SMBCCTX *context, const char * change_time_attr; } attr_strings; TALLOC_CTX *frame = talloc_stackframe(); - + if (!context || !context->internal->initialized) { - + errno = EINVAL; /* Best I can think of ... */ TALLOC_FREE(frame); return -1; } - + if (!fname) { errno = EINVAL; TALLOC_FREE(frame); return -1; } - + DEBUG(4, ("smbc_setxattr(%s, %s, %.*s)\n", fname, name, (int) size, (const char*)value)); - + if (SMBC_parse_path(frame, - context, - fname, - &workgroup, - &server, - &share, - &path, - &user, - &password, - NULL)) { + context, + fname, + &workgroup, + &server, + &share, + &path, + &user, + &password, + NULL)) { errno = EINVAL; TALLOC_FREE(frame); return -1; } - + if (!user || user[0] == (char)0) { user = talloc_strdup(frame, context->config.user); if (!user) { @@ -1728,14 +1736,14 @@ SMBC_setxattr_ctx(SMBCCTX *context, return -1; } } - + 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(frame, context, server, share, &workgroup, &user, &password); @@ -1745,7 +1753,7 @@ SMBC_setxattr_ctx(SMBCCTX *context, } else { ipc_srv = NULL; } - + /* * Are they asking to set the entire set of known attributes? */ @@ -1761,7 +1769,7 @@ SMBC_setxattr_ctx(SMBCCTX *context, TALLOC_FREE(frame); return -1; } - + if (ipc_srv) { ret = cacl_set(talloc_tos(), srv->cli, ipc_srv->cli, &ipc_srv->pol, path, @@ -1773,13 +1781,13 @@ SMBC_setxattr_ctx(SMBCCTX *context, } else { ret = 0; } - + /* get a DOS Attribute Descriptor with current attributes */ dad = dos_attr_query(context, talloc_tos(), path, srv); if (dad) { /* Overwrite old with new, using what was provided */ dos_attr_parse(context, dad, srv, namevalue); - + /* Set the new DOS attributes */ if (! SMBC_setatr(context, srv, path, dad->create_time, @@ -1787,12 +1795,12 @@ SMBC_setxattr_ctx(SMBCCTX *context, dad->write_time, dad->change_time, dad->mode)) { - + /* cause failure if NT failed too */ dad = NULL; } } - + /* we only fail if both NT and DOS sets failed */ if (ret < 0 && ! dad) { ret = -1; /* in case dad was null */ @@ -1800,11 +1808,11 @@ SMBC_setxattr_ctx(SMBCCTX *context, else { ret = 0; } - + TALLOC_FREE(frame); return ret; } - + /* * Are they asking to set an access control element or to set * the entire access control list? @@ -1814,12 +1822,12 @@ SMBC_setxattr_ctx(SMBCCTX *context, StrCaseCmp(name, "system.nt_sec_desc.revision") == 0 || StrnCaseCmp(name, "system.nt_sec_desc.acl", 22) == 0 || StrnCaseCmp(name, "system.nt_sec_desc.acl+", 23) == 0) { - + /* Yup. */ char *namevalue = talloc_asprintf(talloc_tos(), "%s:%s", name+19, (const char *) value); - + if (! ipc_srv) { ret = -1; /* errno set by SMBC_server() */ } @@ -1838,18 +1846,18 @@ SMBC_setxattr_ctx(SMBCCTX *context, TALLOC_FREE(frame); return ret; } - + /* * Are they asking to set the owner? */ if (StrCaseCmp(name, "system.nt_sec_desc.owner") == 0 || StrCaseCmp(name, "system.nt_sec_desc.owner+") == 0) { - + /* Yup. */ char *namevalue = talloc_asprintf(talloc_tos(), "%s:%s", name+19, (const char *) value); - + if (! ipc_srv) { ret = -1; /* errno set by SMBC_server() */ } @@ -1864,18 +1872,18 @@ SMBC_setxattr_ctx(SMBCCTX *context, TALLOC_FREE(frame); return ret; } - + /* * Are they asking to set the group? */ if (StrCaseCmp(name, "system.nt_sec_desc.group") == 0 || StrCaseCmp(name, "system.nt_sec_desc.group+") == 0) { - + /* Yup. */ char *namevalue = talloc_asprintf(talloc_tos(), "%s:%s", name+19, (const char *) value); - + if (! ipc_srv) { /* errno set by SMBC_server() */ ret = -1; @@ -1891,7 +1899,7 @@ SMBC_setxattr_ctx(SMBCCTX *context, TALLOC_FREE(frame); return ret; } - + /* Determine whether to use old-style or new-style attribute names */ if (context->internal->full_time_names) { /* new-style names */ @@ -1906,7 +1914,7 @@ SMBC_setxattr_ctx(SMBCCTX *context, attr_strings.write_time_attr = "system.dos_attr.M_TIME"; attr_strings.change_time_attr = "system.dos_attr.C_TIME"; } - + /* * Are they asking to set a DOS attribute? */ @@ -1917,7 +1925,7 @@ SMBC_setxattr_ctx(SMBCCTX *context, StrCaseCmp(name, attr_strings.access_time_attr) == 0 || StrCaseCmp(name, attr_strings.write_time_attr) == 0 || StrCaseCmp(name, attr_strings.change_time_attr) == 0) { - + /* get a DOS Attribute Descriptor with current attributes */ dad = dos_attr_query(context, talloc_tos(), path, srv); if (dad) { @@ -1930,7 +1938,7 @@ SMBC_setxattr_ctx(SMBCCTX *context, } else { /* Overwrite old with provided new params */ dos_attr_parse(context, dad, srv, namevalue); - + /* Set the new DOS attributes */ ret2 = SMBC_setatr(context, srv, path, dad->create_time, @@ -1938,7 +1946,7 @@ SMBC_setxattr_ctx(SMBCCTX *context, dad->write_time, dad->change_time, dad->mode); - + /* ret2 has True (success) / False (failure) */ if (ret2) { ret = 0; @@ -1949,11 +1957,11 @@ SMBC_setxattr_ctx(SMBCCTX *context, } else { ret = -1; } - + TALLOC_FREE(frame); return ret; } - + /* Unsupported attribute name */ errno = EINVAL; TALLOC_FREE(frame); @@ -1983,37 +1991,37 @@ SMBC_getxattr_ctx(SMBCCTX *context, const char * change_time_attr; } attr_strings; TALLOC_CTX *frame = talloc_stackframe(); - + if (!context || !context->internal->initialized) { - + errno = EINVAL; /* Best I can think of ... */ TALLOC_FREE(frame); return -1; } - + if (!fname) { errno = EINVAL; TALLOC_FREE(frame); return -1; } - + DEBUG(4, ("smbc_getxattr(%s, %s)\n", fname, name)); - + if (SMBC_parse_path(frame, - context, - fname, - &workgroup, - &server, - &share, - &path, - &user, - &password, - NULL)) { + context, + fname, + &workgroup, + &server, + &share, + &path, + &user, + &password, + NULL)) { errno = EINVAL; TALLOC_FREE(frame); return -1; } - + if (!user || user[0] == (char)0) { user = talloc_strdup(frame, context->config.user); if (!user) { @@ -2022,14 +2030,14 @@ SMBC_getxattr_ctx(SMBCCTX *context, return -1; } } - + 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(frame, context, server, share, &workgroup, &user, &password); @@ -2039,7 +2047,7 @@ SMBC_getxattr_ctx(SMBCCTX *context, } else { ipc_srv = NULL; } - + /* Determine whether to use old-style or new-style attribute names */ if (context->internal->full_time_names) { /* new-style names */ @@ -2054,7 +2062,7 @@ SMBC_getxattr_ctx(SMBCCTX *context, attr_strings.write_time_attr = "system.dos_attr.M_TIME"; attr_strings.change_time_attr = "system.dos_attr.C_TIME"; } - + /* Are they requesting a supported attribute? */ if (StrCaseCmp(name, "system.*") == 0 || StrnCaseCmp(name, "system.*!", 9) == 0 || @@ -2081,7 +2089,7 @@ SMBC_getxattr_ctx(SMBCCTX *context, StrCaseCmp(name, attr_strings.write_time_attr) == 0 || StrCaseCmp(name, attr_strings.change_time_attr) == 0 || StrCaseCmp(name, "system.dos_attr.inode") == 0) { - + /* Yup. */ ret = cacl_get(context, talloc_tos(), srv, ipc_srv == NULL ? NULL : ipc_srv->cli, @@ -2094,7 +2102,7 @@ SMBC_getxattr_ctx(SMBCCTX *context, TALLOC_FREE(frame); return ret; } - + /* Unsupported attribute name */ errno = EINVAL; TALLOC_FREE(frame); @@ -2117,37 +2125,37 @@ SMBC_removexattr_ctx(SMBCCTX *context, char *workgroup = NULL; char *path = NULL; TALLOC_CTX *frame = talloc_stackframe(); - + if (!context || !context->internal->initialized) { - + errno = EINVAL; /* Best I can think of ... */ TALLOC_FREE(frame); return -1; } - + if (!fname) { errno = EINVAL; TALLOC_FREE(frame); return -1; } - + DEBUG(4, ("smbc_removexattr(%s, %s)\n", fname, name)); - + if (SMBC_parse_path(frame, - context, - fname, - &workgroup, - &server, - &share, - &path, - &user, - &password, - NULL)) { + context, + fname, + &workgroup, + &server, + &share, + &path, + &user, + &password, + NULL)) { errno = EINVAL; TALLOC_FREE(frame); return -1; } - + if (!user || user[0] == (char)0) { user = talloc_strdup(frame, context->config.user); if (!user) { @@ -2156,14 +2164,14 @@ SMBC_removexattr_ctx(SMBCCTX *context, return -1; } } - + 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(frame, context, server, share, &workgroup, &user, &password); @@ -2173,16 +2181,16 @@ SMBC_removexattr_ctx(SMBCCTX *context, } else { ipc_srv = NULL; } - + if (! ipc_srv) { TALLOC_FREE(frame); return -1; /* errno set by SMBC_attr_server */ } - + /* Are they asking to set the entire ACL? */ if (StrCaseCmp(name, "system.nt_sec_desc.*") == 0 || StrCaseCmp(name, "system.nt_sec_desc.*+") == 0) { - + /* Yup. */ ret = cacl_set(talloc_tos(), srv->cli, ipc_srv->cli, &ipc_srv->pol, path, @@ -2190,7 +2198,7 @@ SMBC_removexattr_ctx(SMBCCTX *context, TALLOC_FREE(frame); return ret; } - + /* * Are they asking to remove one or more spceific security descriptor * attributes? @@ -2202,7 +2210,7 @@ SMBC_removexattr_ctx(SMBCCTX *context, StrCaseCmp(name, "system.nt_sec_desc.group+") == 0 || StrnCaseCmp(name, "system.nt_sec_desc.acl", 22) == 0 || StrnCaseCmp(name, "system.nt_sec_desc.acl+", 23) == 0) { - + /* Yup. */ ret = cacl_set(talloc_tos(), srv->cli, ipc_srv->cli, &ipc_srv->pol, path, @@ -2210,7 +2218,7 @@ SMBC_removexattr_ctx(SMBCCTX *context, TALLOC_FREE(frame); return ret; } - + /* Unsupported attribute name */ errno = EINVAL; TALLOC_FREE(frame); @@ -2269,7 +2277,7 @@ SMBC_listxattr_ctx(SMBCCTX *context, "system.dos_attr.change_time\0" ; const char * supported; - + if (context->internal->full_time_names) { supported = supported_new; retsize = sizeof(supported_new); @@ -2277,16 +2285,16 @@ SMBC_listxattr_ctx(SMBCCTX *context, supported = supported_old; retsize = sizeof(supported_old); } - + if (size == 0) { return retsize; } - + if (retsize > size) { errno = ERANGE; return -1; } - + /* this can't be strcpy() because there are embedded null characters */ memcpy(list, supported, retsize); return retsize; -- cgit From fc65c6698e74e40828e218dc2e6de0c094bfe6e0 Mon Sep 17 00:00:00 2001 From: Derrell Lipman Date: Sat, 1 Mar 2008 21:19:52 -0500 Subject: Return NULL, not 0, from a function which returns a pointer. (This used to be commit 23cb9c49e3724cecaa66655ef64c3111bf14c552) --- source3/libsmb/libsmb_cache.c | 1 - source3/libsmb/libsmb_context.c | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) (limited to 'source3/libsmb') diff --git a/source3/libsmb/libsmb_cache.c b/source3/libsmb/libsmb_cache.c index ff13fd7eac..c45aba4544 100644 --- a/source3/libsmb/libsmb_cache.c +++ b/source3/libsmb/libsmb_cache.c @@ -1,4 +1,3 @@ - /* Unix SMB/CIFS implementation. SMB client library implementation (server cache) diff --git a/source3/libsmb/libsmb_context.c b/source3/libsmb/libsmb_context.c index 8af49d12be..c107ab2220 100644 --- a/source3/libsmb/libsmb_context.c +++ b/source3/libsmb/libsmb_context.c @@ -424,7 +424,7 @@ smbc_init_context(SMBCCTX *context) /* Do not initialise the same client twice */ if (context->internal->initialized) { - return 0; + return NULL; } if (!context->server.get_auth_data_fn || @@ -446,7 +446,7 @@ smbc_init_context(SMBCCTX *context) /* Set this to what the user wants */ DEBUGLEVEL = context->config.debug; - + load_case_tables(); setup_logging("libsmbclient", True); -- cgit From 1363ee9d65965704f716965c6cbcfc0693ca2401 Mon Sep 17 00:00:00 2001 From: Derrell Lipman Date: Mon, 3 Mar 2008 18:13:33 -0500 Subject: Continued revamping of libsmbclient. - James suggested using gcc's "deprecated" attribute to mark the context structure fields to generate warnings. This creates a scenario with the best of all worlds. I'm able to move to an organization that more easily allows future enhancements, while avoiding any mandatory changes by applications. Thanks, James! - Updated WHATSNEW.txt so that it accurately reflects the current state of affairs. Derrell (This used to be commit a67f96fbe9683b46c2149f7cb439d13f7f0e6ecd) --- source3/libsmb/libsmb_cache.c | 16 +- source3/libsmb/libsmb_context.c | 1078 ++++---------------------------------- source3/libsmb/libsmb_dir.c | 30 +- source3/libsmb/libsmb_file.c | 8 +- source3/libsmb/libsmb_path.c | 6 +- source3/libsmb/libsmb_printjob.c | 6 +- source3/libsmb/libsmb_server.c | 75 +-- source3/libsmb/libsmb_setget.c | 905 ++++++++++++++++++++++++++++++++ source3/libsmb/libsmb_stat.c | 4 +- source3/libsmb/libsmb_xattr.c | 6 +- 10 files changed, 1091 insertions(+), 1043 deletions(-) create mode 100644 source3/libsmb/libsmb_setget.c (limited to 'source3/libsmb') diff --git a/source3/libsmb/libsmb_cache.c b/source3/libsmb/libsmb_cache.c index c45aba4544..bfacea368d 100644 --- a/source3/libsmb/libsmb_cache.c +++ b/source3/libsmb/libsmb_cache.c @@ -88,7 +88,7 @@ SMBC_add_cached_server(SMBCCTX * context, goto failed; } - DLIST_ADD((context->cache.server_cache_data), srvcache); + DLIST_ADD(context->internal->server_cache, srvcache); return 0; failed: @@ -118,7 +118,7 @@ SMBC_get_cached_server(SMBCCTX * context, struct smbc_server_cache * srv = NULL; /* Search the cache lines */ - for (srv = context->cache.server_cache_data; srv; srv = srv->next) { + for (srv = context->internal->server_cache; srv; srv = srv->next) { if (strcmp(server,srv->server_name) == 0 && strcmp(workgroup,srv->workgroup) == 0 && @@ -150,7 +150,7 @@ SMBC_get_cached_server(SMBCCTX * context, * a connection to the server (other than the * attribute server connection) is cool. */ - if (context->options.one_share_per_server) { + if (smbc_getOptionOneSharePerServer(context)) { /* * The currently connected share name * doesn't match the requested share, so @@ -160,7 +160,7 @@ SMBC_get_cached_server(SMBCCTX * context, /* Sigh. Couldn't disconnect. */ cli_shutdown(srv->server->cli); srv->server->cli = NULL; - context->cache.remove_cached_server_fn(context, srv->server); + smbc_getFunctionRemoveCachedServer(context)(context, srv->server); continue; } @@ -175,7 +175,7 @@ SMBC_get_cached_server(SMBCCTX * context, /* Out of memory. */ cli_shutdown(srv->server->cli); srv->server->cli = NULL; - context->cache.remove_cached_server_fn(context, srv->server); + smbc_getFunctionRemoveCachedServer(context)(context, srv->server); continue; } @@ -200,11 +200,11 @@ SMBC_remove_cached_server(SMBCCTX * context, { struct smbc_server_cache * srv = NULL; - for (srv = context->cache.server_cache_data; srv; srv = srv->next) { + for (srv = context->internal->server_cache; srv; srv = srv->next) { if (server == srv->server) { /* remove this sucker */ - DLIST_REMOVE(context->cache.server_cache_data, srv); + DLIST_REMOVE(context->internal->server_cache, srv); SAFE_FREE(srv->server_name); SAFE_FREE(srv->share_name); SAFE_FREE(srv->workgroup); @@ -229,7 +229,7 @@ SMBC_purge_cached_servers(SMBCCTX * context) struct smbc_server_cache * next; int could_not_purge_all = 0; - for (srv = context->cache.server_cache_data, + for (srv = context->internal->server_cache, next = (srv ? srv->next :NULL); srv; srv = next, diff --git a/source3/libsmb/libsmb_context.c b/source3/libsmb/libsmb_context.c index c107ab2220..c04f751696 100644 --- a/source3/libsmb/libsmb_context.c +++ b/source3/libsmb/libsmb_context.c @@ -46,11 +46,6 @@ smbc_new_context(void) * All newly added context fields should be placed in * SMBC_internal_data, not directly in SMBCCTX. */ -#undef OLD -#define OLD(field) context->field -#undef NEW -#define NEW(field) context->internal->field - context = SMB_MALLOC_P(SMBCCTX); if (!context) { errno = ENOMEM; @@ -69,61 +64,59 @@ smbc_new_context(void) /* Initialize the context and establish reasonable defaults */ ZERO_STRUCTP(context->internal); - OLD(config.debug) = 0; - OLD(config.timeout) = 20000; /* 20 seconds */ - - NEW(full_time_names) = False; - NEW(share_mode) = SMBC_SHAREMODE_DENY_NONE; - NEW(smb_encryption_level) = 0; - OLD(options.browse_max_lmb_count) = 3; /* # LMBs to query */ - OLD(options.urlencode_readdir_entries) = False; - OLD(options.one_share_per_server) = False; - - OLD(server.get_auth_data_fn) = SMBC_get_auth_data; - OLD(server.check_server_fn) = SMBC_check_server; - OLD(server.remove_unused_server_fn) = SMBC_remove_unused_server; - - OLD(cache.server_cache_data) = NULL; - OLD(cache.add_cached_server_fn) = SMBC_add_cached_server; - OLD(cache.get_cached_server_fn) = SMBC_get_cached_server; - OLD(cache.remove_cached_server_fn) = SMBC_remove_cached_server; - OLD(cache.purge_cached_servers_fn) = SMBC_purge_cached_servers; - - OLD(posix_emu.open_fn) = SMBC_open_ctx; - OLD(posix_emu.creat_fn) = SMBC_creat_ctx; - OLD(posix_emu.read_fn) = SMBC_read_ctx; - OLD(posix_emu.write_fn) = SMBC_write_ctx; - OLD(posix_emu.close_fn) = SMBC_close_ctx; - OLD(posix_emu.unlink_fn) = SMBC_unlink_ctx; - OLD(posix_emu.rename_fn) = SMBC_rename_ctx; - OLD(posix_emu.lseek_fn) = SMBC_lseek_ctx; - NEW(posix_emu.ftruncate_fn) = SMBC_ftruncate_ctx; - OLD(posix_emu.stat_fn) = SMBC_stat_ctx; - OLD(posix_emu.fstat_fn) = SMBC_fstat_ctx; - OLD(posix_emu.opendir_fn) = SMBC_opendir_ctx; - OLD(posix_emu.closedir_fn) = SMBC_closedir_ctx; - OLD(posix_emu.readdir_fn) = SMBC_readdir_ctx; - OLD(posix_emu.getdents_fn) = SMBC_getdents_ctx; - OLD(posix_emu.mkdir_fn) = SMBC_mkdir_ctx; - OLD(posix_emu.rmdir_fn) = SMBC_rmdir_ctx; - OLD(posix_emu.telldir_fn) = SMBC_telldir_ctx; - OLD(posix_emu.lseekdir_fn) = SMBC_lseekdir_ctx; - OLD(posix_emu.fstatdir_fn) = SMBC_fstatdir_ctx; - OLD(posix_emu.chmod_fn) = SMBC_chmod_ctx; - OLD(posix_emu.utimes_fn) = SMBC_utimes_ctx; - OLD(posix_emu.setxattr_fn) = SMBC_setxattr_ctx; - OLD(posix_emu.getxattr_fn) = SMBC_getxattr_ctx; - OLD(posix_emu.removexattr_fn) = SMBC_removexattr_ctx; - OLD(posix_emu.listxattr_fn) = SMBC_listxattr_ctx; - - OLD(printing.open_print_job_fn) = SMBC_open_print_job_ctx; - OLD(printing.print_file_fn) = SMBC_print_file_ctx; - OLD(printing.list_print_jobs_fn) = SMBC_list_print_jobs_ctx; - OLD(printing.unlink_print_job_fn) = SMBC_unlink_print_job_ctx; + smbc_setDebug(context, 0); + smbc_setTimeout(context, 20000); + + smbc_setOptionFullTimeNames(context, False); + smbc_setOptionOpenShareMode(context, SMBC_SHAREMODE_DENY_NONE); + smbc_setOptionSmbEncryptionLevel(context, SMBC_ENCRYPTLEVEL_NONE); + smbc_setOptionBrowseMaxLmbCount(context, 3); /* # LMBs to query */ + smbc_setOptionUrlEncodeReaddirEntries(context, False); + smbc_setOptionOneSharePerServer(context, False); + + smbc_setFunctionAuthData(context, SMBC_get_auth_data); + smbc_setFunctionCheckServer(context, SMBC_check_server); + smbc_setFunctionRemoveUnusedServer(context, SMBC_remove_unused_server); + + smbc_setOptionUserData(context, NULL); + smbc_setFunctionAddCachedServer(context, SMBC_add_cached_server); + smbc_setFunctionGetCachedServer(context, SMBC_get_cached_server); + smbc_setFunctionRemoveCachedServer(context, SMBC_remove_cached_server); + smbc_setFunctionPurgeCachedServers(context, SMBC_purge_cached_servers); + + smbc_setFunctionOpen(context, SMBC_open_ctx); + smbc_setFunctionCreat(context, SMBC_creat_ctx); + smbc_setFunctionRead(context, SMBC_read_ctx); + smbc_setFunctionWrite(context, SMBC_write_ctx); + smbc_setFunctionClose(context, SMBC_close_ctx); + smbc_setFunctionUnlink(context, SMBC_unlink_ctx); + smbc_setFunctionRename(context, SMBC_rename_ctx); + smbc_setFunctionLseek(context, SMBC_lseek_ctx); + smbc_setFunctionFtruncate(context, SMBC_ftruncate_ctx); + smbc_setFunctionStat(context, SMBC_stat_ctx); + smbc_setFunctionFstat(context, SMBC_fstat_ctx); + smbc_setFunctionOpendir(context, SMBC_opendir_ctx); + smbc_setFunctionClosedir(context, SMBC_closedir_ctx); + smbc_setFunctionReaddir(context, SMBC_readdir_ctx); + smbc_setFunctionGetdents(context, SMBC_getdents_ctx); + smbc_setFunctionMkdir(context, SMBC_mkdir_ctx); + smbc_setFunctionRmdir(context, SMBC_rmdir_ctx); + smbc_setFunctionTelldir(context, SMBC_telldir_ctx); + smbc_setFunctionLseekdir(context, SMBC_lseekdir_ctx); + smbc_setFunctionFstatdir(context, SMBC_fstatdir_ctx); + smbc_setFunctionChmod(context, SMBC_chmod_ctx); + smbc_setFunctionUtimes(context, SMBC_utimes_ctx); + smbc_setFunctionSetxattr(context, SMBC_setxattr_ctx); + smbc_setFunctionGetxattr(context, SMBC_getxattr_ctx); + smbc_setFunctionRemovexattr(context, SMBC_removexattr_ctx); + smbc_setFunctionListxattr(context, SMBC_listxattr_ctx); + + smbc_setFunctionOpenPrintJob(context, SMBC_open_print_job_ctx); + smbc_setFunctionPrintFile(context, SMBC_print_file_ctx); + smbc_setFunctionListPrintJobs(context, SMBC_list_print_jobs_ctx); + smbc_setFunctionUnlinkPrintJob(context, SMBC_unlink_print_job_ctx); return context; -#undef OLD -#undef NEW } /* @@ -148,13 +141,13 @@ smbc_free_context(SMBCCTX *context, f = context->internal->files; while (f) { - (context->posix_emu.close_fn)(context, f); + smbc_getFunctionClose(context)(context, f); f = f->next; } context->internal->files = NULL; /* First try to remove the servers the nice way. */ - if (context->cache.purge_cached_servers_fn(context)) { + if (smbc_getFunctionPurgeCachedServers(context)(context)) { SMBCSRV * s; SMBCSRV * next; DEBUG(1, ("Could not purge all servers, " @@ -164,7 +157,7 @@ smbc_free_context(SMBCCTX *context, DEBUG(1, ("Forced shutdown: %p (fd=%d)\n", s, s->cli->fd)); cli_shutdown(s->cli); - (context->cache.remove_cached_server_fn)(context, + smbc_getFunctionRemoveCachedServer(context)(context, s); next = s->next; DLIST_REMOVE(context->internal->servers, s); @@ -176,7 +169,7 @@ smbc_free_context(SMBCCTX *context, } else { /* This is the polite way */ - if ((context->cache.purge_cached_servers_fn)(context)) { + if (smbc_getFunctionPurgeCachedServers(context)(context)) { DEBUG(1, ("Could not purge all servers, " "free_context failed.\n")); errno = EBUSY; @@ -197,9 +190,14 @@ smbc_free_context(SMBCCTX *context, } /* Things we have to clean up */ - SAFE_FREE(context->config.workgroup); - SAFE_FREE(context->config.netbios_name); - SAFE_FREE(context->config.user); + free(smbc_getWorkgroup(context)); + smbc_setWorkgroup(context, NULL); + + free(smbc_getNetbiosName(context)); + smbc_setNetbiosName(context, NULL); + + free(smbc_getUser(context)); + smbc_setUser(context, NULL); DEBUG(3, ("Context %p successfully freed\n", context)); SAFE_FREE(context); @@ -298,8 +296,6 @@ void * smbc_option_get(SMBCCTX *context, char *option_name) { - int bits; - if (strcmp(option_name, "debug_stderr") == 0) { #if defined(__intptr_t_defined) || defined(HAVE_INTPTR_T) return (void *) (intptr_t) smbc_getOptionDebugToStderr(context); @@ -376,7 +372,6 @@ smbc_option_get(SMBCCTX *context, #endif } else if (strcmp(option_name, "use_kerberos") == 0) { - bits = context->flags.bits; #if defined(__intptr_t_defined) || defined(HAVE_INTPTR_T) return (void *) (intptr_t) smbc_getOptionUseKerberos(context); #else @@ -427,9 +422,9 @@ smbc_init_context(SMBCCTX *context) return NULL; } - if (!context->server.get_auth_data_fn || - context->config.debug < 0 || - context->config.debug > 100) { + if (!smbc_getFunctionAuthData(context) || + smbc_getDebug(context) < 0 || + smbc_getDebug(context) > 100) { errno = EINVAL; return NULL; @@ -444,9 +439,6 @@ smbc_init_context(SMBCCTX *context) bool conf_loaded = False; TALLOC_CTX *frame = talloc_stackframe(); - /* Set this to what the user wants */ - DEBUGLEVEL = context->config.debug; - load_case_tables(); setup_logging("libsmbclient", True); @@ -521,58 +513,84 @@ smbc_init_context(SMBCCTX *context) TALLOC_FREE(frame); } - if (!context->config.user) { + if (!smbc_getUser(context)) { /* * FIXME: Is this the best way to get the user info? */ user = getenv("USER"); /* walk around as "guest" if no username can be found */ - if (!user) context->config.user = SMB_STRDUP("guest"); - else context->config.user = SMB_STRDUP(user); + if (!user) { + user = SMB_STRDUP("guest"); + } else { + user = SMB_STRDUP(user); + } + + if (!user) { + errno = ENOMEM; + return NULL; + } + + smbc_setUser(context, user); } - if (!context->config.netbios_name) { + if (!smbc_getNetbiosName(context)) { /* * We try to get our netbios name from the config. If that * fails we fall back on constructing our netbios name from * our hostname etc */ + char *netbios_name; if (global_myname()) { - context->config.netbios_name = SMB_STRDUP(global_myname()); - } - else { + netbios_name = SMB_STRDUP(global_myname()); + } else { /* * Hmmm, I want to get hostname as well, but I am too * lazy for the moment */ pid = sys_getpid(); - context->config.netbios_name = (char *)SMB_MALLOC(17); - if (!context->config.netbios_name) { + netbios_name = (char *)SMB_MALLOC(17); + if (!netbios_name) { errno = ENOMEM; return NULL; } - slprintf(context->config.netbios_name, 16, - "smbc%s%d", context->config.user, pid); + slprintf(netbios_name, 16, + "smbc%s%d", smbc_getUser(context), pid); } + + if (!netbios_name) { + errno = ENOMEM; + return NULL; + } + + smbc_setNetbiosName(context, netbios_name); } - DEBUG(1, ("Using netbios name %s.\n", context->config.netbios_name)); + DEBUG(1, ("Using netbios name %s.\n", smbc_getNetbiosName(context))); - if (!context->config.workgroup) { + if (!smbc_getWorkgroup(context)) { + char *workgroup; + if (lp_workgroup()) { - context->config.workgroup = SMB_STRDUP(lp_workgroup()); + workgroup = SMB_STRDUP(lp_workgroup()); } else { /* TODO: Think about a decent default workgroup */ - context->config.workgroup = SMB_STRDUP("samba"); + workgroup = SMB_STRDUP("samba"); } + + if (!workgroup) { + errno = ENOMEM; + return NULL; + } + + smbc_setWorkgroup(context, workgroup); } - DEBUG(1, ("Using workgroup %s.\n", context->config.workgroup)); + DEBUG(1, ("Using workgroup %s.\n", smbc_getWorkgroup(context))); /* shortest timeout is 1 second */ - if (context->config.timeout > 0 && context->config.timeout < 1000) - context->config.timeout = 1000; + if (smbc_getTimeout(context) > 0 && smbc_getTimeout(context) < 1000) + smbc_setTimeout(context, 1000); /* * FIXME: Should we check the function pointers here? @@ -592,879 +610,3 @@ smbc_version(void) } -/** Get the netbios name used for making connections */ -char * -smbc_getNetbiosName(SMBCCTX *c) -{ - return c->config.netbios_name; -} - -/** Set the netbios name used for making connections */ -void -smbc_setNetbiosName(SMBCCTX *c, char * netbios_name) -{ - c->config.netbios_name = netbios_name; -} - -/** Get the workgroup used for making connections */ -char * -smbc_getWorkgroup(SMBCCTX *c) -{ - return c->config.workgroup; -} - -/** Set the workgroup used for making connections */ -void -smbc_setWorkgroup(SMBCCTX *c, char * workgroup) -{ - c->config.workgroup = workgroup; -} - -/** Get the username used for making connections */ -char * -smbc_getUser(SMBCCTX *c) -{ - return c->config.user; -} - -/** Set the username used for making connections */ -void -smbc_setUser(SMBCCTX *c, char * user) -{ - c->config.user = user; -} - -/** Get the debug level */ -int -smbc_getDebug(SMBCCTX *c) -{ - return c->config.debug; -} - -/** Set the debug level */ -void -smbc_setDebug(SMBCCTX *c, int debug) -{ - c->config.debug = debug; -} - -/** - * Get the timeout used for waiting on connections and response data - * (in milliseconds) - */ -int -smbc_getTimeout(SMBCCTX *c) -{ - return c->config.timeout; -} - -/** - * Set the timeout used for waiting on connections and response data - * (in milliseconds) - */ -void -smbc_setTimeout(SMBCCTX *c, int timeout) -{ - c->config.timeout = timeout; -} - -/** Get whether to log to standard error instead of standard output */ -smbc_bool -smbc_getOptionDebugToStderr(SMBCCTX *c) -{ - return c->internal->debug_stderr; -} - -/** Set whether to log to standard error instead of standard output */ -void -smbc_setOptionDebugToStderr(SMBCCTX *c, smbc_bool b) -{ - c->internal->debug_stderr = b; -} - -/** - * Get whether to use new-style time attribute names, e.g. WRITE_TIME rather - * than the old-style names such as M_TIME. This allows also setting/getting - * CREATE_TIME which was previously unimplemented. (Note that the old C_TIME - * was supposed to be CHANGE_TIME but was confused and sometimes referred to - * CREATE_TIME.) - */ -smbc_bool -smbc_getOptionFullTimeNames(SMBCCTX *c) -{ - return c->internal->full_time_names; -} - -/** - * Set whether to use new-style time attribute names, e.g. WRITE_TIME rather - * than the old-style names such as M_TIME. This allows also setting/getting - * CREATE_TIME which was previously unimplemented. (Note that the old C_TIME - * was supposed to be CHANGE_TIME but was confused and sometimes referred to - * CREATE_TIME.) - */ -void -smbc_setOptionFullTimeNames(SMBCCTX *c, smbc_bool b) -{ - c->internal->full_time_names = b; -} - -/** - * Get the share mode to use for files opened with SMBC_open_ctx(). The - * default is SMBC_SHAREMODE_DENY_NONE. - */ -smbc_share_mode -smbc_getOptionOpenShareMode(SMBCCTX *c) -{ - return c->internal->share_mode; -} - -/** - * Set the share mode to use for files opened with SMBC_open_ctx(). The - * default is SMBC_SHAREMODE_DENY_NONE. - */ -void -smbc_setOptionOpenShareMode(SMBCCTX *c, smbc_share_mode share_mode) -{ - c->internal->share_mode = share_mode; -} - -/** Retrieve a previously set user data handle */ -void * -smbc_getOptionUserData(SMBCCTX *c) -{ - return c->internal->user_data; -} - -/** Save a user data handle */ -void -smbc_setOptionUserData(SMBCCTX *c, void *user_data) -{ - c->internal->user_data = user_data; -} - -/** Get the encoded value for encryption level. */ -smbc_smb_encrypt_level -smbc_getOptionSmbEncryptionLevel(SMBCCTX *c) -{ - return c->internal->smb_encryption_level; -} - -/** Set the encoded value for encryption level. */ -void -smbc_setOptionSmbEncryptionLevel(SMBCCTX *c, smbc_smb_encrypt_level level) -{ - c->internal->smb_encryption_level = level; -} - -/** - * Get from how many local master browsers should the list of workgroups be - * retrieved. It can take up to 12 minutes or longer after a server becomes a - * local master browser, for it to have the entire browse list (the list of - * workgroups/domains) from an entire network. Since a client never knows - * which local master browser will be found first, the one which is found - * first and used to retrieve a browse list may have an incomplete or empty - * browse list. By requesting the browse list from multiple local master - * browsers, a more complete list can be generated. For small networks (few - * workgroups), it is recommended that this value be set to 0, causing the - * browse lists from all found local master browsers to be retrieved and - * merged. For networks with many workgroups, a suitable value for this - * variable is probably somewhere around 3. (Default: 3). - */ -int -smbc_getOptionBrowseMaxLmbCount(SMBCCTX *c) -{ - return c->options.browse_max_lmb_count; -} - -/** - * Set from how many local master browsers should the list of workgroups be - * retrieved. It can take up to 12 minutes or longer after a server becomes a - * local master browser, for it to have the entire browse list (the list of - * workgroups/domains) from an entire network. Since a client never knows - * which local master browser will be found first, the one which is found - * first and used to retrieve a browse list may have an incomplete or empty - * browse list. By requesting the browse list from multiple local master - * browsers, a more complete list can be generated. For small networks (few - * workgroups), it is recommended that this value be set to 0, causing the - * browse lists from all found local master browsers to be retrieved and - * merged. For networks with many workgroups, a suitable value for this - * variable is probably somewhere around 3. (Default: 3). - */ -void -smbc_setOptionBrowseMaxLmbCount(SMBCCTX *c, int count) -{ - c->options.browse_max_lmb_count = count; -} - -/** - * Get whether to url-encode readdir entries. - * - * There is a difference in the desired return strings from - * smbc_readdir() depending upon whether the filenames are to - * be displayed to the user, or whether they are to be - * appended to the path name passed to smbc_opendir() to call - * a further smbc_ function (e.g. open the file with - * smbc_open()). In the former case, the filename should be - * in "human readable" form. In the latter case, the smbc_ - * functions expect a URL which must be url-encoded. Those - * functions decode the URL. If, for example, smbc_readdir() - * returned a file name of "abc%20def.txt", passing a path - * with this file name attached to smbc_open() would cause - * smbc_open to attempt to open the file "abc def.txt" since - * the %20 is decoded into a space. - * - * Set this option to True if the names returned by - * smbc_readdir() should be url-encoded such that they can be - * passed back to another smbc_ call. Set it to False if the - * names returned by smbc_readdir() are to be presented to the - * user. - * - * For backwards compatibility, this option defaults to False. - */ -smbc_bool -smbc_getOptionUrlEncodeReaddirEntries(SMBCCTX *c) -{ - return c->options.urlencode_readdir_entries; -} - -/** - * Set whether to url-encode readdir entries. - * - * There is a difference in the desired return strings from - * smbc_readdir() depending upon whether the filenames are to - * be displayed to the user, or whether they are to be - * appended to the path name passed to smbc_opendir() to call - * a further smbc_ function (e.g. open the file with - * smbc_open()). In the former case, the filename should be - * in "human readable" form. In the latter case, the smbc_ - * functions expect a URL which must be url-encoded. Those - * functions decode the URL. If, for example, smbc_readdir() - * returned a file name of "abc%20def.txt", passing a path - * with this file name attached to smbc_open() would cause - * smbc_open to attempt to open the file "abc def.txt" since - * the %20 is decoded into a space. - * - * Set this option to True if the names returned by - * smbc_readdir() should be url-encoded such that they can be - * passed back to another smbc_ call. Set it to False if the - * names returned by smbc_readdir() are to be presented to the - * user. - * - * For backwards compatibility, this option defaults to False. - */ -void -smbc_setOptionUrlEncodeReaddirEntries(SMBCCTX *c, smbc_bool b) -{ - c->options.urlencode_readdir_entries = b; -} - -/** - * Get whether to use the same connection for all shares on a server. - * - * Some Windows versions appear to have a limit to the number - * of concurrent SESSIONs and/or TREE CONNECTions. In - * one-shot programs (i.e. the program runs and then quickly - * ends, thereby shutting down all connections), it is - * probably reasonable to establish a new connection for each - * share. In long-running applications, the limitation can be - * avoided by using only a single connection to each server, - * and issuing a new TREE CONNECT when the share is accessed. - */ -smbc_bool -smbc_getOptionOneSharePerServer(SMBCCTX *c) -{ - return c->options.one_share_per_server; -} - -/** - * Set whether to use the same connection for all shares on a server. - * - * Some Windows versions appear to have a limit to the number - * of concurrent SESSIONs and/or TREE CONNECTions. In - * one-shot programs (i.e. the program runs and then quickly - * ends, thereby shutting down all connections), it is - * probably reasonable to establish a new connection for each - * share. In long-running applications, the limitation can be - * avoided by using only a single connection to each server, - * and issuing a new TREE CONNECT when the share is accessed. - */ -void -smbc_setOptionOneSharePerServer(SMBCCTX *c, smbc_bool b) -{ - c->options.one_share_per_server = b; -} - -/** Get whether to enable use of kerberos */ -smbc_bool -smbc_getOptionUseKerberos(SMBCCTX *c) -{ - return c->flags.bits & SMB_CTX_FLAG_USE_KERBEROS ? True : False; -} - -/** Set whether to enable use of kerberos */ -void -smbc_setOptionUseKerberos(SMBCCTX *c, smbc_bool b) -{ - if (b) { - c->flags.bits |= SMB_CTX_FLAG_USE_KERBEROS; - } else { - c->flags.bits &= ~SMB_CTX_FLAG_USE_KERBEROS; - } -} - -/** Get whether to fallback after kerberos */ -smbc_bool -smbc_getOptionFallbackAfterKerberos(SMBCCTX *c) -{ - return c->flags.bits & SMB_CTX_FLAG_FALLBACK_AFTER_KERBEROS ? True : False; -} - -/** Set whether to fallback after kerberos */ -void -smbc_setOptionFallbackAfterKerberos(SMBCCTX *c, smbc_bool b) -{ - if (b) { - c->flags.bits |= SMB_CTX_FLAG_FALLBACK_AFTER_KERBEROS; - } else { - c->flags.bits &= ~SMB_CTX_FLAG_FALLBACK_AFTER_KERBEROS; - } -} - -/** Get whether to automatically select anonymous login */ -smbc_bool -smbc_getOptionNoAutoAnonymousLogin(SMBCCTX *c) -{ - return c->flags.bits & SMBCCTX_FLAG_NO_AUTO_ANONYMOUS_LOGON ? True : False; -} - -/** Set whether to automatically select anonymous login */ -void -smbc_setOptionNoAutoAnonymousLogin(SMBCCTX *c, smbc_bool b) -{ - if (b) { - c->flags.bits |= SMBCCTX_FLAG_NO_AUTO_ANONYMOUS_LOGON; - } else { - c->flags.bits &= ~SMBCCTX_FLAG_NO_AUTO_ANONYMOUS_LOGON; - } -} - -/** Get the function for obtaining authentication data */ -smbc_get_auth_data_fn -smbc_getFunctionAuthData(SMBCCTX *c) -{ - return c->server.get_auth_data_fn; -} - -/** Set the function for obtaining authentication data */ -void -smbc_setFunctionAuthData(SMBCCTX *c, smbc_get_auth_data_fn fn) -{ - c->internal->auth_fn_with_context = NULL; - c->server.get_auth_data_fn = fn; -} - -/** Get the new-style authentication function which includes the context. */ -smbc_get_auth_data_with_context_fn -smbc_getFunctionAuthDataWithContext(SMBCCTX *c) -{ - return c->internal->auth_fn_with_context; -} - -/** Set the new-style authentication function which includes the context. */ -void -smbc_setFunctionAuthDataWithContext(SMBCCTX *c, - smbc_get_auth_data_with_context_fn fn) -{ - c->server.get_auth_data_fn = NULL; - c->internal->auth_fn_with_context = fn; -} - -/** Get the function for checking if a server is still good */ -smbc_check_server_fn -smbc_getFunctionCheckServer(SMBCCTX *c) -{ - return c->server.check_server_fn; -} - -/** Set the function for checking if a server is still good */ -void -smbc_setFunctionCheckServer(SMBCCTX *c, smbc_check_server_fn fn) -{ - c->server.check_server_fn = fn; -} - -/** Get the function for removing a server if unused */ -smbc_remove_unused_server_fn -smbc_getFunctionRemoveUnusedServer(SMBCCTX *c) -{ - return c->server.remove_unused_server_fn; -} - -/** Set the function for removing a server if unused */ -void -smbc_setFunctionRemoveUnusedServer(SMBCCTX *c, - smbc_remove_unused_server_fn fn) -{ - c->server.remove_unused_server_fn = fn; -} - -/** Get the function to store private data of the server cache */ -struct -smbc_server_cache * smbc_getServerCacheData(SMBCCTX *c) -{ - return c->cache.server_cache_data; -} - -/** Set the function to store private data of the server cache */ -void -smbc_setServerCacheData(SMBCCTX *c, struct smbc_server_cache * cache) -{ - c->cache.server_cache_data = cache; -} - - -/** Get the function for adding a cached server */ -smbc_add_cached_srv_fn -smbc_getFunctionAddCachedServer(SMBCCTX *c) -{ - return c->cache.add_cached_server_fn; -} - -/** Set the function for adding a cached server */ -void -smbc_setFunctionAddCachedServer(SMBCCTX *c, smbc_add_cached_srv_fn fn) -{ - c->cache.add_cached_server_fn = fn; -} - -/** Get the function for server cache lookup */ -smbc_get_cached_srv_fn -smbc_getFunctionGetCachedServer(SMBCCTX *c) -{ - return c->cache.get_cached_server_fn; -} - -/** Set the function for server cache lookup */ -void -smbc_setFunctionGetCachedServer(SMBCCTX *c, smbc_get_cached_srv_fn fn) -{ - c->cache.get_cached_server_fn = fn; -} - -/** Get the function for server cache removal */ -smbc_remove_cached_srv_fn -smbc_getFunctionRemoveCachedServer(SMBCCTX *c) -{ - return c->cache.remove_cached_server_fn; -} - -/** Set the function for server cache removal */ -void -smbc_setFunctionRemoveCachedServer(SMBCCTX *c, - smbc_remove_cached_srv_fn fn) -{ - c->cache.remove_cached_server_fn = fn; -} - -/** - * Get the function for server cache purging. This function tries to - * remove all cached servers (e.g. on disconnect) - */ -smbc_purge_cached_srv_fn -smbc_getFunctionPurgeCachedServers(SMBCCTX *c) -{ - return c->cache.purge_cached_servers_fn; -} - -/** - * Set the function for server cache purging. This function tries to - * remove all cached servers (e.g. on disconnect) - */ -void -smbc_setFunctionPurgeCachedServers(SMBCCTX *c, smbc_purge_cached_srv_fn fn) -{ - c->cache.purge_cached_servers_fn = fn; -} - -/** - * Callable functions for files. - */ - -smbc_open_fn -smbc_getFunctionOpen(SMBCCTX *c) -{ - return c->posix_emu.open_fn; -} - -void -smbc_setFunctionOpen(SMBCCTX *c, smbc_open_fn fn) -{ - c->posix_emu.open_fn = fn; -} - -smbc_creat_fn -smbc_getFunctionCreat(SMBCCTX *c) -{ - return c->posix_emu.creat_fn; -} - -void -smbc_setFunctionCreat(SMBCCTX *c, smbc_creat_fn fn) -{ - c->posix_emu.creat_fn = fn; -} - -smbc_read_fn -smbc_getFunctionRead(SMBCCTX *c) -{ - return c->posix_emu.read_fn; -} - -void -smbc_setFunctionRead(SMBCCTX *c, smbc_read_fn fn) -{ - c->posix_emu.read_fn = fn; -} - -smbc_write_fn -smbc_getFunctionWrite(SMBCCTX *c) -{ - return c->posix_emu.write_fn; -} - -void -smbc_setFunctionWrite(SMBCCTX *c, smbc_write_fn fn) -{ - c->posix_emu.write_fn = fn; -} - -smbc_unlink_fn -smbc_getFunctionUnlink(SMBCCTX *c) -{ - return c->posix_emu.unlink_fn; -} - -void -smbc_setFunctionUnlink(SMBCCTX *c, smbc_unlink_fn fn) -{ - c->posix_emu.unlink_fn = fn; -} - -smbc_rename_fn -smbc_getFunctionRename(SMBCCTX *c) -{ - return c->posix_emu.rename_fn; -} - -void -smbc_setFunctionRename(SMBCCTX *c, smbc_rename_fn fn) -{ - c->posix_emu.rename_fn = fn; -} - -smbc_lseek_fn -smbc_getFunctionLseek(SMBCCTX *c) -{ - return c->posix_emu.lseek_fn; -} - -void -smbc_setFunctionLseek(SMBCCTX *c, smbc_lseek_fn fn) -{ - c->posix_emu.lseek_fn = fn; -} - -smbc_stat_fn -smbc_getFunctionStat(SMBCCTX *c) -{ - return c->posix_emu.stat_fn; -} - -void -smbc_setFunctionStat(SMBCCTX *c, smbc_stat_fn fn) -{ - c->posix_emu.stat_fn = fn; -} - -smbc_fstat_fn -smbc_getFunctionFstat(SMBCCTX *c) -{ - return c->posix_emu.fstat_fn; -} - -void -smbc_setFunctionFstat(SMBCCTX *c, smbc_fstat_fn fn) -{ - c->posix_emu.fstat_fn = fn; -} - -smbc_ftruncate_fn -smbc_getFunctionFtruncate(SMBCCTX *c) -{ - return c->internal->posix_emu.ftruncate_fn; -} - -void -smbc_setFunctionFtruncate(SMBCCTX *c, smbc_ftruncate_fn fn) -{ - c->internal->posix_emu.ftruncate_fn = fn; -} - -smbc_close_fn -smbc_getFunctionClose(SMBCCTX *c) -{ - return c->posix_emu.close_fn; -} - -void -smbc_setFunctionClose(SMBCCTX *c, smbc_close_fn fn) -{ - c->posix_emu.close_fn = fn; -} - - -/** - * Callable functions for directories. - */ - -smbc_opendir_fn -smbc_getFunctionOpendir(SMBCCTX *c) -{ - return c->posix_emu.opendir_fn; -} - -void -smbc_setFunctionOpendir(SMBCCTX *c, smbc_opendir_fn fn) -{ - c->posix_emu.opendir_fn = fn; -} - -smbc_closedir_fn -smbc_getFunctionClosedir(SMBCCTX *c) -{ - return c->posix_emu.closedir_fn; -} - -void -smbc_setFunctionClosedir(SMBCCTX *c, smbc_closedir_fn fn) -{ - c->posix_emu.closedir_fn = fn; -} - -smbc_readdir_fn -smbc_getFunctionReaddir(SMBCCTX *c) -{ - return c->posix_emu.readdir_fn; -} - -void -smbc_setFunctionReaddir(SMBCCTX *c, smbc_readdir_fn fn) -{ - c->posix_emu.readdir_fn = fn; -} - -smbc_getdents_fn -smbc_getFunctionGetdents(SMBCCTX *c) -{ - return c->posix_emu.getdents_fn; -} - -void -smbc_setFunctionGetdents(SMBCCTX *c, smbc_getdents_fn fn) -{ - c->posix_emu.getdents_fn = fn; -} - -smbc_mkdir_fn -smbc_getFunctionMkdir(SMBCCTX *c) -{ - return c->posix_emu.mkdir_fn; -} - -void -smbc_setFunctionMkdir(SMBCCTX *c, smbc_mkdir_fn fn) -{ - c->posix_emu.mkdir_fn = fn; -} - -smbc_rmdir_fn -smbc_getFunctionRmdir(SMBCCTX *c) -{ - return c->posix_emu.rmdir_fn; -} - -void -smbc_setFunctionRmdir(SMBCCTX *c, smbc_rmdir_fn fn) -{ - c->posix_emu.rmdir_fn = fn; -} - -smbc_telldir_fn -smbc_getFunctionTelldir(SMBCCTX *c) -{ - return c->posix_emu.telldir_fn; -} - -void -smbc_setFunctionTelldir(SMBCCTX *c, smbc_telldir_fn fn) -{ - c->posix_emu.telldir_fn = fn; -} - -smbc_lseekdir_fn -smbc_getFunctionLseekdir(SMBCCTX *c) -{ - return c->posix_emu.lseekdir_fn; -} - -void -smbc_setFunctionLseekdir(SMBCCTX *c, smbc_lseekdir_fn fn) -{ - c->posix_emu.lseekdir_fn = fn; -} - -smbc_fstatdir_fn -smbc_getFunctionFstatdir(SMBCCTX *c) -{ - return c->posix_emu.fstatdir_fn; -} - -void -smbc_setFunctionFstatdir(SMBCCTX *c, smbc_fstatdir_fn fn) -{ - c->posix_emu.fstatdir_fn = fn; -} - - -/** - * Callable functions applicable to both files and directories. - */ - -smbc_chmod_fn -smbc_getFunctionChmod(SMBCCTX *c) -{ - return c->posix_emu.chmod_fn; -} - -void -smbc_setFunctionChmod(SMBCCTX *c, smbc_chmod_fn fn) -{ - c->posix_emu.chmod_fn = fn; -} - -smbc_utimes_fn -smbc_getFunctionUtimes(SMBCCTX *c) -{ - return c->posix_emu.utimes_fn; -} - -void -smbc_setFunctionUtimes(SMBCCTX *c, smbc_utimes_fn fn) -{ - c->posix_emu.utimes_fn = fn; -} - -smbc_setxattr_fn -smbc_getFunctionSetxattr(SMBCCTX *c) -{ - return c->posix_emu.setxattr_fn; -} - -void -smbc_setFunctionSetxattr(SMBCCTX *c, smbc_setxattr_fn fn) -{ - c->posix_emu.setxattr_fn = fn; -} - -smbc_getxattr_fn -smbc_getFunctionGetxattr(SMBCCTX *c) -{ - return c->posix_emu.getxattr_fn; -} - -void -smbc_setFunctionGetxattr(SMBCCTX *c, smbc_getxattr_fn fn) -{ - c->posix_emu.getxattr_fn = fn; -} - -smbc_removexattr_fn -smbc_getFunctionRemovexattr(SMBCCTX *c) -{ - return c->posix_emu.removexattr_fn; -} - -void -smbc_setFunctionRemovexattr(SMBCCTX *c, smbc_removexattr_fn fn) -{ - c->posix_emu.removexattr_fn = fn; -} - -smbc_listxattr_fn -smbc_getFunctionListxattr(SMBCCTX *c) -{ - return c->posix_emu.listxattr_fn; -} - -void -smbc_setFunctionListxattr(SMBCCTX *c, smbc_listxattr_fn fn) -{ - c->posix_emu.listxattr_fn = fn; -} - - -/** - * Callable functions related to printing - */ - -smbc_print_file_fn -smbc_getFunctionPrintFile(SMBCCTX *c) -{ - return c->printing.print_file_fn; -} - -void -smbc_setFunctionPrintFile(SMBCCTX *c, smbc_print_file_fn fn) -{ - c->printing.print_file_fn = fn; -} - -smbc_open_print_job_fn -smbc_getFunctionOpenPrintJob(SMBCCTX *c) -{ - return c->printing.open_print_job_fn; -} - -void -smbc_setFunctionOpenPrintJob(SMBCCTX *c, - smbc_open_print_job_fn fn) -{ - c->printing.open_print_job_fn = fn; -} - -smbc_list_print_jobs_fn -smbc_getFunctionListPrintJobs(SMBCCTX *c) -{ - return c->printing.list_print_jobs_fn; -} - -void -smbc_setFunctionListPrintJobs(SMBCCTX *c, - smbc_list_print_jobs_fn fn) -{ - c->printing.list_print_jobs_fn = fn; -} - -smbc_unlink_print_job_fn -smbc_getFunctionUnlinkPrintJob(SMBCCTX *c) -{ - return c->printing.unlink_print_job_fn; -} - -void -smbc_setFunctionUnlinkPrintJob(SMBCCTX *c, - smbc_unlink_print_job_fn fn) -{ - c->printing.unlink_print_job_fn = fn; -} - diff --git a/source3/libsmb/libsmb_dir.c b/source3/libsmb/libsmb_dir.c index 2ece2ab8ed..1486097d51 100644 --- a/source3/libsmb/libsmb_dir.c +++ b/source3/libsmb/libsmb_dir.c @@ -404,7 +404,7 @@ SMBC_opendir_ctx(SMBCCTX *context, } if (!user || user[0] == (char)0) { - user = talloc_strdup(frame, context->config.user); + user = talloc_strdup(frame, smbc_getUser(context)); if (!user) { errno = ENOMEM; TALLOC_FREE(frame); @@ -450,9 +450,9 @@ SMBC_opendir_ctx(SMBCCTX *context, } /* Determine how many local master browsers to query */ - max_lmb_count = (context->options.browse_max_lmb_count == 0 + max_lmb_count = (smbc_getOptionBrowseMaxLmbCount(context) == 0 ? INT_MAX - : context->options.browse_max_lmb_count); + : smbc_getOptionBrowseMaxLmbCount(context)); memset(&u_info, '\0', sizeof(u_info)); u_info.username = talloc_strdup(frame,user); @@ -810,11 +810,11 @@ SMBC_opendir_ctx(SMBCCTX *context, * good any more... */ if (cli_is_error(targetcli) && - (context->server.check_server_fn)(context, srv)) { + smbc_getFunctionCheckServer(context)(context, srv)) { /* ... then remove it. */ - if ((context->server.remove_unused_server_fn)(context, - srv)) { + if (smbc_getFunctionRemoveUnusedServer(context)(context, + srv)) { /* * We could not remove the * server completely, remove @@ -823,7 +823,7 @@ SMBC_opendir_ctx(SMBCCTX *context, * will be removed when the * last file/dir is closed. */ - (context->cache.remove_cached_server_fn)(context, srv); + smbc_getFunctionRemoveCachedServer(context)(context, srv); } } @@ -884,7 +884,7 @@ smbc_readdir_internal(SMBCCTX * context, struct smbc_dirent *src, int max_namebuf_len) { - if (context->options.urlencode_readdir_entries) { + if (smbc_getOptionUrlEncodeReaddirEntries(context)) { /* url-encode the name. get back remaining buffer space */ max_namebuf_len = @@ -1142,7 +1142,7 @@ SMBC_mkdir_ctx(SMBCCTX *context, } if (!user || user[0] == (char)0) { - user = talloc_strdup(frame, context->config.user); + user = talloc_strdup(frame, smbc_getUser(context)); if (!user) { errno = ENOMEM; TALLOC_FREE(frame); @@ -1249,7 +1249,7 @@ SMBC_rmdir_ctx(SMBCCTX *context, } if (!user || user[0] == (char)0) { - user = talloc_strdup(frame, context->config.user); + user = talloc_strdup(frame, smbc_getUser(context)); if (!user) { errno = ENOMEM; TALLOC_FREE(frame); @@ -1531,7 +1531,7 @@ SMBC_chmod_ctx(SMBCCTX *context, } if (!user || user[0] == (char)0) { - user = talloc_strdup(frame, context->config.user); + user = talloc_strdup(frame, smbc_getUser(context)); if (!user) { errno = ENOMEM; TALLOC_FREE(frame); @@ -1637,7 +1637,7 @@ SMBC_utimes_ctx(SMBCCTX *context, } if (!user || user[0] == (char)0) { - user = talloc_strdup(frame, context->config.user); + user = talloc_strdup(frame, smbc_getUser(context)); if (!user) { errno = ENOMEM; TALLOC_FREE(frame); @@ -1713,7 +1713,7 @@ SMBC_unlink_ctx(SMBCCTX *context, } if (!user || user[0] == (char)0) { - user = talloc_strdup(frame, context->config.user); + user = talloc_strdup(frame, smbc_getUser(context)); if (!user) { errno = ENOMEM; TALLOC_FREE(frame); @@ -1848,7 +1848,7 @@ SMBC_rename_ctx(SMBCCTX *ocontext, } if (!user1 || user1[0] == (char)0) { - user1 = talloc_strdup(frame, ocontext->config.user); + user1 = talloc_strdup(frame, smbc_getUser(ocontext)); if (!user1) { errno = ENOMEM; TALLOC_FREE(frame); @@ -1872,7 +1872,7 @@ SMBC_rename_ctx(SMBCCTX *ocontext, } if (!user2 || user2[0] == (char)0) { - user2 = talloc_strdup(frame, ncontext->config.user); + user2 = talloc_strdup(frame, smbc_getUser(ncontext)); if (!user2) { errno = ENOMEM; TALLOC_FREE(frame); diff --git a/source3/libsmb/libsmb_file.c b/source3/libsmb/libsmb_file.c index 73c9b96978..423450b23e 100644 --- a/source3/libsmb/libsmb_file.c +++ b/source3/libsmb/libsmb_file.c @@ -82,7 +82,7 @@ SMBC_open_ctx(SMBCCTX *context, } if (!user || user[0] == (char)0) { - user = talloc_strdup(frame, context->config.user); + user = talloc_strdup(frame, smbc_getUser(context)); if (!user) { errno = ENOMEM; TALLOC_FREE(frame); @@ -188,7 +188,7 @@ SMBC_open_ctx(SMBCCTX *context, int eno = 0; eno = SMBC_errno(context, srv->cli); - file = (context->posix_emu.opendir_fn)(context, fname); + file = smbc_getFunctionOpendir(context)(context, fname); if (!file) errno = eno; TALLOC_FREE(frame); return file; @@ -439,7 +439,7 @@ SMBC_close_ctx(SMBCCTX *context, /* IS a dir ... */ if (!file->file) { TALLOC_FREE(frame); - return (context->posix_emu.closedir_fn)(context, file); + return smbc_getFunctionClosedir(context)(context, file); } /*d_printf(">>>close: parsing %s\n", file->fname);*/ @@ -478,7 +478,7 @@ SMBC_close_ctx(SMBCCTX *context, DLIST_REMOVE(context->internal->files, file); SAFE_FREE(file->fname); SAFE_FREE(file); - (context->server.remove_unused_server_fn)(context, srv); + smbc_getFunctionRemoveUnusedServer(context)(context, srv); TALLOC_FREE(frame); return -1; diff --git a/source3/libsmb/libsmb_path.c b/source3/libsmb/libsmb_path.c index c962f898e0..2c3a5f8866 100644 --- a/source3/libsmb/libsmb_path.c +++ b/source3/libsmb/libsmb_path.c @@ -253,7 +253,7 @@ SMBC_parse_path(TALLOC_CTX *ctx, */ if (pp_workgroup != NULL) { *pp_workgroup = - talloc_strdup(ctx, context->config.workgroup); + talloc_strdup(ctx, smbc_getWorkgroup(context)); } if (pp_options) { @@ -297,13 +297,13 @@ SMBC_parse_path(TALLOC_CTX *ctx, } if (*p == '/') { - int wl = strlen(context->config.workgroup); + int wl = strlen(smbc_getWorkgroup(context)); if (wl > 16) { wl = 16; } - *pp_server = talloc_strdup(ctx, context->config.workgroup); + *pp_server = talloc_strdup(ctx, smbc_getWorkgroup(context)); if (!*pp_server) { return -1; } diff --git a/source3/libsmb/libsmb_printjob.c b/source3/libsmb/libsmb_printjob.c index 545225cae4..c8d7ad039d 100644 --- a/source3/libsmb/libsmb_printjob.c +++ b/source3/libsmb/libsmb_printjob.c @@ -75,7 +75,7 @@ SMBC_open_print_job_ctx(SMBCCTX *context, /* What if the path is empty, or the file exists? */ TALLOC_FREE(frame); - return (context->posix_emu.open_fn)(context, fname, O_WRONLY, 666); + return smbc_getFunctionOpen(context)(context, fname, O_WRONLY, 666); } /* @@ -222,7 +222,7 @@ SMBC_list_print_jobs_ctx(SMBCCTX *context, } if (!user || user[0] == (char)0) { - user = talloc_strdup(frame, context->config.user); + user = talloc_strdup(frame, smbc_getUser(context)); if (!user) { errno = ENOMEM; TALLOC_FREE(frame); @@ -300,7 +300,7 @@ SMBC_unlink_print_job_ctx(SMBCCTX *context, } if (!user || user[0] == (char)0) { - user = talloc_strdup(frame, context->config.user); + user = talloc_strdup(frame, smbc_getUser(context)); if (!user) { errno = ENOMEM; TALLOC_FREE(frame); diff --git a/source3/libsmb/libsmb_server.c b/source3/libsmb/libsmb_server.c index 4f51388870..64eb1ea584 100644 --- a/source3/libsmb/libsmb_server.c +++ b/source3/libsmb/libsmb_server.c @@ -80,7 +80,7 @@ SMBC_remove_unused_server(SMBCCTX * context, DEBUG(3, ("smbc_remove_usused_server: %p removed.\n", srv)); - (context->cache.remove_cached_server_fn)(context, srv); + smbc_getFunctionRemoveCachedServer(context)(context, srv); SAFE_FREE(srv); return 0; @@ -106,11 +106,10 @@ SMBC_call_auth_fn(TALLOC_CTX *ctx, strlcpy(username, *pp_username, sizeof(username)); strlcpy(password, *pp_password, sizeof(password)); - (context->server.get_auth_data_fn)( - server, share, - workgroup, sizeof(workgroup), - username, sizeof(username), - password, sizeof(password)); + smbc_getFunctionAuthData(context)(server, share, + workgroup, sizeof(workgroup), + username, sizeof(username), + password, sizeof(password)); TALLOC_FREE(*pp_workgroup); TALLOC_FREE(*pp_username); @@ -147,10 +146,10 @@ SMBC_find_server(TALLOC_CTX *ctx, check_server_cache: - srv = (context->cache.get_cached_server_fn)(context, - server, share, - *pp_workgroup, - *pp_username); + srv = smbc_getFunctionGetCachedServer(context)(context, + server, share, + *pp_workgroup, + *pp_username); if (!auth_called && !srv && (!*pp_username || !(*pp_username)[0] || !*pp_password || !(*pp_password)[0])) { @@ -172,22 +171,22 @@ check_server_cache: } if (srv) { - if ((context->server.check_server_fn)(context, srv)) { + if (smbc_getFunctionCheckServer(context)(context, srv)) { /* * This server is no good anymore * Try to remove it and check for more possible * servers in the cache */ - if ((context->server.remove_unused_server_fn)(context, - srv)) { + if (smbc_getFunctionRemoveUnusedServer(context)(context, + srv)) { /* * We could not remove the server completely, * remove it from the cache so we will not get * it again. It will be removed when the last * file/dir is closed. */ - (context->cache.remove_cached_server_fn)(context, - srv); + smbc_getFunctionRemoveCachedServer(context)(context, + srv); } /* @@ -251,12 +250,14 @@ SMBC_server(TALLOC_CTX *ctx, * If we found a connection and we're only allowed one share per * server... */ - if (srv && *share != '\0' && context->options.one_share_per_server) { + if (srv && + *share != '\0' && + smbc_getOptionOneSharePerServer(context)) { /* * ... then if there's no current connection to the share, * connect to it. SMBC_find_server(), or rather the function - * pointed to by context->cache.get_cached_srv_fn which + * pointed to by context->get_cached_srv_fn which * was called by SMBC_find_server(), will have issued a tree * disconnect if the requested share is not the same as the * one that was already connected. @@ -272,8 +273,8 @@ SMBC_server(TALLOC_CTX *ctx, errno = ENOMEM; cli_shutdown(srv->cli); srv->cli = NULL; - (context->cache.remove_cached_server_fn)(context, - srv); + smbc_getFunctionRemoveCachedServer(context)(context, + srv); return NULL; } @@ -290,8 +291,8 @@ SMBC_server(TALLOC_CTX *ctx, errno = SMBC_errno(context, srv->cli); cli_shutdown(srv->cli); srv->cli = NULL; - (context->cache.remove_cached_server_fn)(context, - srv); + smbc_getFunctionRemoveCachedServer(context)(context, + srv); srv = NULL; } @@ -324,7 +325,7 @@ SMBC_server(TALLOC_CTX *ctx, return NULL; } - make_nmb_name(&calling, context->config.netbios_name, 0x0); + make_nmb_name(&calling, smbc_getNetbiosName(context), 0x0); make_nmb_name(&called , server, 0x20); DEBUG(4,("SMBC_server: server_n=[%s] server=[%s]\n", server_n, server)); @@ -341,14 +342,15 @@ again: return NULL; } - if (context->flags.bits & SMB_CTX_FLAG_USE_KERBEROS) { + if (smbc_getOptionUseKerberos(context)) { c->use_kerberos = True; } - if (context->flags.bits & SMB_CTX_FLAG_FALLBACK_AFTER_KERBEROS) { + + if (smbc_getOptionFallbackAfterKerberos(context)) { c->fallback_after_kerberos = True; } - c->timeout = context->config.timeout; + c->timeout = smbc_getTimeout(context); /* * Force use of port 139 for first try if share is $IPC, empty, or @@ -435,8 +437,7 @@ again: /* Failed. Try an anonymous login, if allowed by flags. */ username_used = ""; - if ((context->flags.bits & - SMBCCTX_FLAG_NO_AUTO_ANONYMOUS_LOGON) || + if (smbc_getOptionNoAutoAnonymousLogin(context) || !NT_STATUS_IS_OK(cli_session_setup(c, username_used, *pp_password, 1, *pp_password, 0, @@ -504,10 +505,10 @@ again: /* now add it to the cache (internal or external) */ /* Let the cache function set errno if it wants to */ errno = 0; - if ((context->cache.add_cached_server_fn)(context, srv, - server, share, - *pp_workgroup, - *pp_username)) { + if (smbc_getFunctionAddCachedServer(context)(context, srv, + server, share, + *pp_workgroup, + *pp_username)) { int saved_errno = errno; DEBUG(3, (" Failed to add server to cache\n")); errno = saved_errno; @@ -576,7 +577,7 @@ SMBC_attr_server(TALLOC_CTX *ctx, } flags = 0; - if (context->flags.bits & SMB_CTX_FLAG_USE_KERBEROS) { + if (smbc_getOptionUseKerberos(context)) { flags |= CLI_FULL_CONNECTION_USE_KERBEROS; } @@ -664,11 +665,11 @@ SMBC_attr_server(TALLOC_CTX *ctx, /* now add it to the cache (internal or external) */ errno = 0; /* let cache function set errno if it likes */ - if ((context->cache.add_cached_server_fn)(context, ipc_srv, - server, - "*IPC$", - *pp_workgroup, - *pp_username)) { + if (smbc_getFunctionAddCachedServer(context)(context, ipc_srv, + server, + "*IPC$", + *pp_workgroup, + *pp_username)) { DEBUG(3, (" Failed to add server to cache\n")); if (errno == 0) { errno = ENOMEM; diff --git a/source3/libsmb/libsmb_setget.c b/source3/libsmb/libsmb_setget.c new file mode 100644 index 0000000000..d0823bd77e --- /dev/null +++ b/source3/libsmb/libsmb_setget.c @@ -0,0 +1,905 @@ +/* + Unix SMB/Netbios implementation. + SMB client library implementation + Copyright (C) Andrew Tridgell 1998 + Copyright (C) Richard Sharpe 2000, 2002 + Copyright (C) John Terpstra 2000 + Copyright (C) Tom Jansen (Ninja ISD) 2002 + Copyright (C) Derrell Lipman 2003-2008 + 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 + 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 . +*/ + +#include "includes.h" +#define __LIBSMBCLIENT_INTERNAL__ +#include "libsmbclient.h" +#include "libsmb_internal.h" + + +/** Get the netbios name used for making connections */ +char * +smbc_getNetbiosName(SMBCCTX *c) +{ + return c->netbios_name; +} + +/** Set the netbios name used for making connections */ +void +smbc_setNetbiosName(SMBCCTX *c, char * netbios_name) +{ + c->netbios_name = netbios_name; +} + +/** Get the workgroup used for making connections */ +char * +smbc_getWorkgroup(SMBCCTX *c) +{ + return c->workgroup; +} + +/** Set the workgroup used for making connections */ +void +smbc_setWorkgroup(SMBCCTX *c, char * workgroup) +{ + c->workgroup = workgroup; +} + +/** Get the username used for making connections */ +char * +smbc_getUser(SMBCCTX *c) +{ + return c->user; +} + +/** Set the username used for making connections */ +void +smbc_setUser(SMBCCTX *c, char * user) +{ + c->user = user; +} + +/** Get the debug level */ +int +smbc_getDebug(SMBCCTX *c) +{ + return c->debug; +} + +/** Set the debug level */ +void +smbc_setDebug(SMBCCTX *c, int debug) +{ + c->debug = debug; + DEBUGLEVEL = debug; +} + +/** + * Get the timeout used for waiting on connections and response data + * (in milliseconds) + */ +int +smbc_getTimeout(SMBCCTX *c) +{ + return c->timeout; +} + +/** + * Set the timeout used for waiting on connections and response data + * (in milliseconds) + */ +void +smbc_setTimeout(SMBCCTX *c, int timeout) +{ + c->timeout = timeout; +} + +/** Get whether to log to standard error instead of standard output */ +smbc_bool +smbc_getOptionDebugToStderr(SMBCCTX *c) +{ + return c->internal->debug_stderr; +} + +/** Set whether to log to standard error instead of standard output */ +void +smbc_setOptionDebugToStderr(SMBCCTX *c, smbc_bool b) +{ + c->internal->debug_stderr = b; +} + +/** + * Get whether to use new-style time attribute names, e.g. WRITE_TIME rather + * than the old-style names such as M_TIME. This allows also setting/getting + * CREATE_TIME which was previously unimplemented. (Note that the old C_TIME + * was supposed to be CHANGE_TIME but was confused and sometimes referred to + * CREATE_TIME.) + */ +smbc_bool +smbc_getOptionFullTimeNames(SMBCCTX *c) +{ + return c->internal->full_time_names; +} + +/** + * Set whether to use new-style time attribute names, e.g. WRITE_TIME rather + * than the old-style names such as M_TIME. This allows also setting/getting + * CREATE_TIME which was previously unimplemented. (Note that the old C_TIME + * was supposed to be CHANGE_TIME but was confused and sometimes referred to + * CREATE_TIME.) + */ +void +smbc_setOptionFullTimeNames(SMBCCTX *c, smbc_bool b) +{ + c->internal->full_time_names = b; +} + +/** + * Get the share mode to use for files opened with SMBC_open_ctx(). The + * default is SMBC_SHAREMODE_DENY_NONE. + */ +smbc_share_mode +smbc_getOptionOpenShareMode(SMBCCTX *c) +{ + return c->internal->share_mode; +} + +/** + * Set the share mode to use for files opened with SMBC_open_ctx(). The + * default is SMBC_SHAREMODE_DENY_NONE. + */ +void +smbc_setOptionOpenShareMode(SMBCCTX *c, smbc_share_mode share_mode) +{ + c->internal->share_mode = share_mode; +} + +/** Retrieve a previously set user data handle */ +void * +smbc_getOptionUserData(SMBCCTX *c) +{ + return c->internal->user_data; +} + +/** Save a user data handle */ +void +smbc_setOptionUserData(SMBCCTX *c, void *user_data) +{ + c->internal->user_data = user_data; +} + +/** Get the encoded value for encryption level. */ +smbc_smb_encrypt_level +smbc_getOptionSmbEncryptionLevel(SMBCCTX *c) +{ + return c->internal->smb_encryption_level; +} + +/** Set the encoded value for encryption level. */ +void +smbc_setOptionSmbEncryptionLevel(SMBCCTX *c, smbc_smb_encrypt_level level) +{ + c->internal->smb_encryption_level = level; +} + +/** + * Get from how many local master browsers should the list of workgroups be + * retrieved. It can take up to 12 minutes or longer after a server becomes a + * local master browser, for it to have the entire browse list (the list of + * workgroups/domains) from an entire network. Since a client never knows + * which local master browser will be found first, the one which is found + * first and used to retrieve a browse list may have an incomplete or empty + * browse list. By requesting the browse list from multiple local master + * browsers, a more complete list can be generated. For small networks (few + * workgroups), it is recommended that this value be set to 0, causing the + * browse lists from all found local master browsers to be retrieved and + * merged. For networks with many workgroups, a suitable value for this + * variable is probably somewhere around 3. (Default: 3). + */ +int +smbc_getOptionBrowseMaxLmbCount(SMBCCTX *c) +{ + return c->options.browse_max_lmb_count; +} + +/** + * Set from how many local master browsers should the list of workgroups be + * retrieved. It can take up to 12 minutes or longer after a server becomes a + * local master browser, for it to have the entire browse list (the list of + * workgroups/domains) from an entire network. Since a client never knows + * which local master browser will be found first, the one which is found + * first and used to retrieve a browse list may have an incomplete or empty + * browse list. By requesting the browse list from multiple local master + * browsers, a more complete list can be generated. For small networks (few + * workgroups), it is recommended that this value be set to 0, causing the + * browse lists from all found local master browsers to be retrieved and + * merged. For networks with many workgroups, a suitable value for this + * variable is probably somewhere around 3. (Default: 3). + */ +void +smbc_setOptionBrowseMaxLmbCount(SMBCCTX *c, int count) +{ + c->options.browse_max_lmb_count = count; +} + +/** + * Get whether to url-encode readdir entries. + * + * There is a difference in the desired return strings from + * smbc_readdir() depending upon whether the filenames are to + * be displayed to the user, or whether they are to be + * appended to the path name passed to smbc_opendir() to call + * a further smbc_ function (e.g. open the file with + * smbc_open()). In the former case, the filename should be + * in "human readable" form. In the latter case, the smbc_ + * functions expect a URL which must be url-encoded. Those + * functions decode the URL. If, for example, smbc_readdir() + * returned a file name of "abc%20def.txt", passing a path + * with this file name attached to smbc_open() would cause + * smbc_open to attempt to open the file "abc def.txt" since + * the %20 is decoded into a space. + * + * Set this option to True if the names returned by + * smbc_readdir() should be url-encoded such that they can be + * passed back to another smbc_ call. Set it to False if the + * names returned by smbc_readdir() are to be presented to the + * user. + * + * For backwards compatibility, this option defaults to False. + */ +smbc_bool +smbc_getOptionUrlEncodeReaddirEntries(SMBCCTX *c) +{ + return c->options.urlencode_readdir_entries; +} + +/** + * Set whether to url-encode readdir entries. + * + * There is a difference in the desired return strings from + * smbc_readdir() depending upon whether the filenames are to + * be displayed to the user, or whether they are to be + * appended to the path name passed to smbc_opendir() to call + * a further smbc_ function (e.g. open the file with + * smbc_open()). In the former case, the filename should be + * in "human readable" form. In the latter case, the smbc_ + * functions expect a URL which must be url-encoded. Those + * functions decode the URL. If, for example, smbc_readdir() + * returned a file name of "abc%20def.txt", passing a path + * with this file name attached to smbc_open() would cause + * smbc_open to attempt to open the file "abc def.txt" since + * the %20 is decoded into a space. + * + * Set this option to True if the names returned by + * smbc_readdir() should be url-encoded such that they can be + * passed back to another smbc_ call. Set it to False if the + * names returned by smbc_readdir() are to be presented to the + * user. + * + * For backwards compatibility, this option defaults to False. + */ +void +smbc_setOptionUrlEncodeReaddirEntries(SMBCCTX *c, smbc_bool b) +{ + c->options.urlencode_readdir_entries = b; +} + +/** + * Get whether to use the same connection for all shares on a server. + * + * Some Windows versions appear to have a limit to the number + * of concurrent SESSIONs and/or TREE CONNECTions. In + * one-shot programs (i.e. the program runs and then quickly + * ends, thereby shutting down all connections), it is + * probably reasonable to establish a new connection for each + * share. In long-running applications, the limitation can be + * avoided by using only a single connection to each server, + * and issuing a new TREE CONNECT when the share is accessed. + */ +smbc_bool +smbc_getOptionOneSharePerServer(SMBCCTX *c) +{ + return c->options.one_share_per_server; +} + +/** + * Set whether to use the same connection for all shares on a server. + * + * Some Windows versions appear to have a limit to the number + * of concurrent SESSIONs and/or TREE CONNECTions. In + * one-shot programs (i.e. the program runs and then quickly + * ends, thereby shutting down all connections), it is + * probably reasonable to establish a new connection for each + * share. In long-running applications, the limitation can be + * avoided by using only a single connection to each server, + * and issuing a new TREE CONNECT when the share is accessed. + */ +void +smbc_setOptionOneSharePerServer(SMBCCTX *c, smbc_bool b) +{ + c->options.one_share_per_server = b; +} + +/** Get whether to enable use of kerberos */ +smbc_bool +smbc_getOptionUseKerberos(SMBCCTX *c) +{ + return c->flags & SMB_CTX_FLAG_USE_KERBEROS ? True : False; +} + +/** Set whether to enable use of kerberos */ +void +smbc_setOptionUseKerberos(SMBCCTX *c, smbc_bool b) +{ + if (b) { + c->flags |= SMB_CTX_FLAG_USE_KERBEROS; + } else { + c->flags &= ~SMB_CTX_FLAG_USE_KERBEROS; + } +} + +/** Get whether to fallback after kerberos */ +smbc_bool +smbc_getOptionFallbackAfterKerberos(SMBCCTX *c) +{ + return c->flags & SMB_CTX_FLAG_FALLBACK_AFTER_KERBEROS ? True : False; +} + +/** Set whether to fallback after kerberos */ +void +smbc_setOptionFallbackAfterKerberos(SMBCCTX *c, smbc_bool b) +{ + if (b) { + c->flags |= SMB_CTX_FLAG_FALLBACK_AFTER_KERBEROS; + } else { + c->flags &= ~SMB_CTX_FLAG_FALLBACK_AFTER_KERBEROS; + } +} + +/** Get whether to automatically select anonymous login */ +smbc_bool +smbc_getOptionNoAutoAnonymousLogin(SMBCCTX *c) +{ + return c->flags & SMBCCTX_FLAG_NO_AUTO_ANONYMOUS_LOGON ? True : False; +} + +/** Set whether to automatically select anonymous login */ +void +smbc_setOptionNoAutoAnonymousLogin(SMBCCTX *c, smbc_bool b) +{ + if (b) { + c->flags |= SMBCCTX_FLAG_NO_AUTO_ANONYMOUS_LOGON; + } else { + c->flags &= ~SMBCCTX_FLAG_NO_AUTO_ANONYMOUS_LOGON; + } +} + +/** Get the function for obtaining authentication data */ +smbc_get_auth_data_fn +smbc_getFunctionAuthData(SMBCCTX *c) +{ + return c->callbacks.auth_fn; +} + +/** Set the function for obtaining authentication data */ +void +smbc_setFunctionAuthData(SMBCCTX *c, smbc_get_auth_data_fn fn) +{ + c->internal->auth_fn_with_context = NULL; + c->callbacks.auth_fn = fn; +} + +/** Get the new-style authentication function which includes the context. */ +smbc_get_auth_data_with_context_fn +smbc_getFunctionAuthDataWithContext(SMBCCTX *c) +{ + return c->internal->auth_fn_with_context; +} + +/** Set the new-style authentication function which includes the context. */ +void +smbc_setFunctionAuthDataWithContext(SMBCCTX *c, + smbc_get_auth_data_with_context_fn fn) +{ + c->callbacks.auth_fn = NULL; + c->internal->auth_fn_with_context = fn; +} + +/** Get the function for checking if a server is still good */ +smbc_check_server_fn +smbc_getFunctionCheckServer(SMBCCTX *c) +{ + return c->callbacks.check_server_fn; +} + +/** Set the function for checking if a server is still good */ +void +smbc_setFunctionCheckServer(SMBCCTX *c, smbc_check_server_fn fn) +{ + c->callbacks.check_server_fn = fn; +} + +/** Get the function for removing a server if unused */ +smbc_remove_unused_server_fn +smbc_getFunctionRemoveUnusedServer(SMBCCTX *c) +{ + return c->callbacks.remove_unused_server_fn; +} + +/** Set the function for removing a server if unused */ +void +smbc_setFunctionRemoveUnusedServer(SMBCCTX *c, + smbc_remove_unused_server_fn fn) +{ + c->callbacks.remove_unused_server_fn = fn; +} + +/** Get the function for adding a cached server */ +smbc_add_cached_srv_fn +smbc_getFunctionAddCachedServer(SMBCCTX *c) +{ + return c->callbacks.add_cached_srv_fn; +} + +/** Set the function for adding a cached server */ +void +smbc_setFunctionAddCachedServer(SMBCCTX *c, smbc_add_cached_srv_fn fn) +{ + c->callbacks.add_cached_srv_fn = fn; +} + +/** Get the function for server cache lookup */ +smbc_get_cached_srv_fn +smbc_getFunctionGetCachedServer(SMBCCTX *c) +{ + return c->callbacks.get_cached_srv_fn; +} + +/** Set the function for server cache lookup */ +void +smbc_setFunctionGetCachedServer(SMBCCTX *c, smbc_get_cached_srv_fn fn) +{ + c->callbacks.get_cached_srv_fn = fn; +} + +/** Get the function for server cache removal */ +smbc_remove_cached_srv_fn +smbc_getFunctionRemoveCachedServer(SMBCCTX *c) +{ + return c->callbacks.remove_cached_srv_fn; +} + +/** Set the function for server cache removal */ +void +smbc_setFunctionRemoveCachedServer(SMBCCTX *c, + smbc_remove_cached_srv_fn fn) +{ + c->callbacks.remove_cached_srv_fn = fn; +} + +/** + * Get the function for server cache purging. This function tries to + * remove all cached servers (e.g. on disconnect) + */ +smbc_purge_cached_fn +smbc_getFunctionPurgeCachedServers(SMBCCTX *c) +{ + return c->callbacks.purge_cached_fn; +} + +/** Set the function to store private data of the server cache */ +void smbc_setServerCacheData(SMBCCTX *c, struct smbc_server_cache * cache) +{ + c->internal->server_cache = cache; +} + +/** Get the function to store private data of the server cache */ +struct smbc_server_cache * smbc_getServerCacheData(SMBCCTX *c) +{ + return c->internal->server_cache; +} + + +/** + * Set the function for server cache purging. This function tries to + * remove all cached servers (e.g. on disconnect) + */ +void +smbc_setFunctionPurgeCachedServers(SMBCCTX *c, smbc_purge_cached_fn fn) +{ + c->callbacks.purge_cached_fn = fn; +} + +/** + * Callable functions for files. + */ + +smbc_open_fn +smbc_getFunctionOpen(SMBCCTX *c) +{ + return c->open; +} + +void +smbc_setFunctionOpen(SMBCCTX *c, smbc_open_fn fn) +{ + c->open = fn; +} + +smbc_creat_fn +smbc_getFunctionCreat(SMBCCTX *c) +{ + return c->creat; +} + +void +smbc_setFunctionCreat(SMBCCTX *c, smbc_creat_fn fn) +{ + c->creat = fn; +} + +smbc_read_fn +smbc_getFunctionRead(SMBCCTX *c) +{ + return c->read; +} + +void +smbc_setFunctionRead(SMBCCTX *c, smbc_read_fn fn) +{ + c->read = fn; +} + +smbc_write_fn +smbc_getFunctionWrite(SMBCCTX *c) +{ + return c->write; +} + +void +smbc_setFunctionWrite(SMBCCTX *c, smbc_write_fn fn) +{ + c->write = fn; +} + +smbc_unlink_fn +smbc_getFunctionUnlink(SMBCCTX *c) +{ + return c->unlink; +} + +void +smbc_setFunctionUnlink(SMBCCTX *c, smbc_unlink_fn fn) +{ + c->unlink = fn; +} + +smbc_rename_fn +smbc_getFunctionRename(SMBCCTX *c) +{ + return c->rename; +} + +void +smbc_setFunctionRename(SMBCCTX *c, smbc_rename_fn fn) +{ + c->rename = fn; +} + +smbc_lseek_fn +smbc_getFunctionLseek(SMBCCTX *c) +{ + return c->lseek; +} + +void +smbc_setFunctionLseek(SMBCCTX *c, smbc_lseek_fn fn) +{ + c->lseek = fn; +} + +smbc_stat_fn +smbc_getFunctionStat(SMBCCTX *c) +{ + return c->stat; +} + +void +smbc_setFunctionStat(SMBCCTX *c, smbc_stat_fn fn) +{ + c->stat = fn; +} + +smbc_fstat_fn +smbc_getFunctionFstat(SMBCCTX *c) +{ + return c->fstat; +} + +void +smbc_setFunctionFstat(SMBCCTX *c, smbc_fstat_fn fn) +{ + c->fstat = fn; +} + +smbc_ftruncate_fn +smbc_getFunctionFtruncate(SMBCCTX *c) +{ + return c->internal->posix_emu.ftruncate_fn; +} + +void +smbc_setFunctionFtruncate(SMBCCTX *c, smbc_ftruncate_fn fn) +{ + c->internal->posix_emu.ftruncate_fn = fn; +} + +smbc_close_fn +smbc_getFunctionClose(SMBCCTX *c) +{ + return c->close_fn; +} + +void +smbc_setFunctionClose(SMBCCTX *c, smbc_close_fn fn) +{ + c->close_fn = fn; +} + + +/** + * Callable functions for directories. + */ + +smbc_opendir_fn +smbc_getFunctionOpendir(SMBCCTX *c) +{ + return c->opendir; +} + +void +smbc_setFunctionOpendir(SMBCCTX *c, smbc_opendir_fn fn) +{ + c->opendir = fn; +} + +smbc_closedir_fn +smbc_getFunctionClosedir(SMBCCTX *c) +{ + return c->closedir; +} + +void +smbc_setFunctionClosedir(SMBCCTX *c, smbc_closedir_fn fn) +{ + c->closedir = fn; +} + +smbc_readdir_fn +smbc_getFunctionReaddir(SMBCCTX *c) +{ + return c->readdir; +} + +void +smbc_setFunctionReaddir(SMBCCTX *c, smbc_readdir_fn fn) +{ + c->readdir = fn; +} + +smbc_getdents_fn +smbc_getFunctionGetdents(SMBCCTX *c) +{ + return c->getdents; +} + +void +smbc_setFunctionGetdents(SMBCCTX *c, smbc_getdents_fn fn) +{ + c->getdents = fn; +} + +smbc_mkdir_fn +smbc_getFunctionMkdir(SMBCCTX *c) +{ + return c->mkdir; +} + +void +smbc_setFunctionMkdir(SMBCCTX *c, smbc_mkdir_fn fn) +{ + c->mkdir = fn; +} + +smbc_rmdir_fn +smbc_getFunctionRmdir(SMBCCTX *c) +{ + return c->rmdir; +} + +void +smbc_setFunctionRmdir(SMBCCTX *c, smbc_rmdir_fn fn) +{ + c->rmdir = fn; +} + +smbc_telldir_fn +smbc_getFunctionTelldir(SMBCCTX *c) +{ + return c->telldir; +} + +void +smbc_setFunctionTelldir(SMBCCTX *c, smbc_telldir_fn fn) +{ + c->telldir = fn; +} + +smbc_lseekdir_fn +smbc_getFunctionLseekdir(SMBCCTX *c) +{ + return c->lseekdir; +} + +void +smbc_setFunctionLseekdir(SMBCCTX *c, smbc_lseekdir_fn fn) +{ + c->lseekdir = fn; +} + +smbc_fstatdir_fn +smbc_getFunctionFstatdir(SMBCCTX *c) +{ + return c->fstatdir; +} + +void +smbc_setFunctionFstatdir(SMBCCTX *c, smbc_fstatdir_fn fn) +{ + c->fstatdir = fn; +} + + +/** + * Callable functions applicable to both files and directories. + */ + +smbc_chmod_fn +smbc_getFunctionChmod(SMBCCTX *c) +{ + return c->chmod; +} + +void +smbc_setFunctionChmod(SMBCCTX *c, smbc_chmod_fn fn) +{ + c->chmod = fn; +} + +smbc_utimes_fn +smbc_getFunctionUtimes(SMBCCTX *c) +{ + return c->utimes; +} + +void +smbc_setFunctionUtimes(SMBCCTX *c, smbc_utimes_fn fn) +{ + c->utimes = fn; +} + +smbc_setxattr_fn +smbc_getFunctionSetxattr(SMBCCTX *c) +{ + return c->setxattr; +} + +void +smbc_setFunctionSetxattr(SMBCCTX *c, smbc_setxattr_fn fn) +{ + c->setxattr = fn; +} + +smbc_getxattr_fn +smbc_getFunctionGetxattr(SMBCCTX *c) +{ + return c->getxattr; +} + +void +smbc_setFunctionGetxattr(SMBCCTX *c, smbc_getxattr_fn fn) +{ + c->getxattr = fn; +} + +smbc_removexattr_fn +smbc_getFunctionRemovexattr(SMBCCTX *c) +{ + return c->removexattr; +} + +void +smbc_setFunctionRemovexattr(SMBCCTX *c, smbc_removexattr_fn fn) +{ + c->removexattr = fn; +} + +smbc_listxattr_fn +smbc_getFunctionListxattr(SMBCCTX *c) +{ + return c->listxattr; +} + +void +smbc_setFunctionListxattr(SMBCCTX *c, smbc_listxattr_fn fn) +{ + c->listxattr = fn; +} + + +/** + * Callable functions related to printing + */ + +smbc_print_file_fn +smbc_getFunctionPrintFile(SMBCCTX *c) +{ + return c->print_file; +} + +void +smbc_setFunctionPrintFile(SMBCCTX *c, smbc_print_file_fn fn) +{ + c->print_file = fn; +} + +smbc_open_print_job_fn +smbc_getFunctionOpenPrintJob(SMBCCTX *c) +{ + return c->open_print_job; +} + +void +smbc_setFunctionOpenPrintJob(SMBCCTX *c, + smbc_open_print_job_fn fn) +{ + c->open_print_job = fn; +} + +smbc_list_print_jobs_fn +smbc_getFunctionListPrintJobs(SMBCCTX *c) +{ + return c->list_print_jobs; +} + +void +smbc_setFunctionListPrintJobs(SMBCCTX *c, + smbc_list_print_jobs_fn fn) +{ + c->list_print_jobs = fn; +} + +smbc_unlink_print_job_fn +smbc_getFunctionUnlinkPrintJob(SMBCCTX *c) +{ + return c->unlink_print_job; +} + +void +smbc_setFunctionUnlinkPrintJob(SMBCCTX *c, + smbc_unlink_print_job_fn fn) +{ + c->unlink_print_job = fn; +} + diff --git a/source3/libsmb/libsmb_stat.c b/source3/libsmb/libsmb_stat.c index b733eab74f..27546f687e 100644 --- a/source3/libsmb/libsmb_stat.c +++ b/source3/libsmb/libsmb_stat.c @@ -157,7 +157,7 @@ SMBC_stat_ctx(SMBCCTX *context, } if (!user || user[0] == (char)0) { - user = talloc_strdup(frame,context->config.user); + user = talloc_strdup(frame, smbc_getUser(context)); if (!user) { errno = ENOMEM; TALLOC_FREE(frame); @@ -237,7 +237,7 @@ SMBC_fstat_ctx(SMBCCTX *context, if (!file->file) { TALLOC_FREE(frame); - return (context->posix_emu.fstatdir_fn)(context, file, st); + return smbc_getFunctionFstatdir(context)(context, file, st); } /*d_printf(">>>fstat: parsing %s\n", file->fname);*/ diff --git a/source3/libsmb/libsmb_xattr.c b/source3/libsmb/libsmb_xattr.c index 3c08412d59..e17146e611 100644 --- a/source3/libsmb/libsmb_xattr.c +++ b/source3/libsmb/libsmb_xattr.c @@ -1729,7 +1729,7 @@ SMBC_setxattr_ctx(SMBCCTX *context, } if (!user || user[0] == (char)0) { - user = talloc_strdup(frame, context->config.user); + user = talloc_strdup(frame, smbc_getUser(context)); if (!user) { errno = ENOMEM; TALLOC_FREE(frame); @@ -2023,7 +2023,7 @@ SMBC_getxattr_ctx(SMBCCTX *context, } if (!user || user[0] == (char)0) { - user = talloc_strdup(frame, context->config.user); + user = talloc_strdup(frame, smbc_getUser(context)); if (!user) { errno = ENOMEM; TALLOC_FREE(frame); @@ -2157,7 +2157,7 @@ SMBC_removexattr_ctx(SMBCCTX *context, } if (!user || user[0] == (char)0) { - user = talloc_strdup(frame, context->config.user); + user = talloc_strdup(frame, smbc_getUser(context)); if (!user) { errno = ENOMEM; TALLOC_FREE(frame); -- cgit