LCOV - code coverage report
Current view: top level - source3/libsmb - libsmb_server.c (source / functions) Hit Total Coverage
Test: coverage report for fix-15632 9995c5c2 Lines: 210 350 60.0 %
Date: 2024-04-13 12:30:31 Functions: 8 9 88.9 %

          Line data    Source code
       1             : /*
       2             :    Unix SMB/Netbios implementation.
       3             :    SMB client library implementation
       4             :    Copyright (C) Andrew Tridgell 1998
       5             :    Copyright (C) Richard Sharpe 2000, 2002
       6             :    Copyright (C) John Terpstra 2000
       7             :    Copyright (C) Tom Jansen (Ninja ISD) 2002
       8             :    Copyright (C) Derrell Lipman 2003-2008
       9             :    Copyright (C) Jeremy Allison 2007, 2008
      10             :    Copyright (C) SATOH Fumiyasu <fumiyas@osstech.co.jp> 2009.
      11             : 
      12             :    This program is free software; you can redistribute it and/or modify
      13             :    it under the terms of the GNU General Public License as published by
      14             :    the Free Software Foundation; either version 3 of the License, or
      15             :    (at your option) any later version.
      16             : 
      17             :    This program is distributed in the hope that it will be useful,
      18             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      19             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      20             :    GNU General Public License for more details.
      21             : 
      22             :    You should have received a copy of the GNU General Public License
      23             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      24             : */
      25             : 
      26             : #include "includes.h"
      27             : #include "libsmb/libsmb.h"
      28             : #include "libsmbclient.h"
      29             : #include "libsmb_internal.h"
      30             : #include "../librpc/gen_ndr/ndr_lsa.h"
      31             : #include "rpc_client/cli_pipe.h"
      32             : #include "rpc_client/cli_lsarpc.h"
      33             : #include "libcli/security/security.h"
      34             : #include "libsmb/nmblib.h"
      35             : #include "../libcli/smb/smbXcli_base.h"
      36             : 
      37             : /*
      38             :  * Check a server for being alive and well.
      39             :  * returns 0 if the server is in shape. Returns 1 on error
      40             :  *
      41             :  * Also usable outside libsmbclient to enable external cache
      42             :  * to do some checks too.
      43             :  */
      44             : int
      45        1364 : SMBC_check_server(SMBCCTX * context,
      46             :                   SMBCSRV * server)
      47             : {
      48           0 :         time_t now;
      49             : 
      50        1364 :         if (!cli_state_is_connected(server->cli)) {
      51           0 :                 return 1;
      52             :         }
      53             : 
      54        1364 :         now = time_mono(NULL);
      55             : 
      56        1364 :         if (server->last_echo_time == (time_t)0 ||
      57        1324 :                         now > server->last_echo_time +
      58        1324 :                                 (server->cli->timeout/1000)) {
      59          40 :                 unsigned char data[16] = {0};
      60          40 :                 NTSTATUS status = cli_echo(server->cli,
      61             :                                         1,
      62             :                                         data_blob_const(data, sizeof(data)));
      63          40 :                 if (!NT_STATUS_IS_OK(status)) {
      64           0 :                         bool ok = false;
      65             :                         /*
      66             :                          * Some SMB2 servers (not Samba or Windows)
      67             :                          * check the session status on SMB2_ECHO and return
      68             :                          * NT_STATUS_USER_SESSION_DELETED
      69             :                          * if the session was not set. That's OK, they still
      70             :                          * replied.
      71             :                          * BUG: https://bugzilla.samba.org/show_bug.cgi?id=13218
      72             :                          */
      73           0 :                         if (smbXcli_conn_protocol(server->cli->conn) >=
      74             :                                         PROTOCOL_SMB2_02) {
      75           0 :                                 if (NT_STATUS_EQUAL(status,
      76             :                                             NT_STATUS_USER_SESSION_DELETED)) {
      77           0 :                                         ok = true;
      78             :                                 }
      79             :                         }
      80             :                         /*
      81             :                          * Some NetApp servers return
      82             :                          * NT_STATUS_INVALID_PARAMETER.That's OK, they still
      83             :                          * replied.
      84             :                          * BUG: https://bugzilla.samba.org/show_bug.cgi?id=13007
      85             :                          */
      86           0 :                         if (NT_STATUS_EQUAL(status,
      87             :                                         NT_STATUS_INVALID_PARAMETER)) {
      88           0 :                                 ok = true;
      89             :                         }
      90           0 :                         if (!ok) {
      91           0 :                                 return 1;
      92             :                         }
      93             :                 }
      94          40 :                 server->last_echo_time = now;
      95             :         }
      96        1364 :         return 0;
      97             : }
      98             : 
      99             : /*
     100             :  * Remove a server from the cached server list it's unused.
     101             :  * On success, 0 is returned. 1 is returned if the server could not be removed.
     102             :  *
     103             :  * Also usable outside libsmbclient
     104             :  */
     105             : int
     106          34 : SMBC_remove_unused_server(SMBCCTX * context,
     107             :                           SMBCSRV * srv)
     108             : {
     109           0 :         SMBCFILE * file;
     110             : 
     111             :         /* are we being fooled ? */
     112          34 :         if (!context || !context->internal->initialized || !srv) {
     113           0 :                 return 1;
     114             :         }
     115             : 
     116             :         /* Check all open files/directories for a relation with this server */
     117          34 :         for (file = context->internal->files; file; file = file->next) {
     118           0 :                 if (file->srv == srv) {
     119             :                         /* Still used */
     120           0 :                         DEBUG(3, ("smbc_remove_usused_server: "
     121             :                                   "%p still used by %p.\n",
     122             :                                   srv, file));
     123           0 :                         return 1;
     124             :                 }
     125             :         }
     126             : 
     127          34 :         DLIST_REMOVE(context->internal->servers, srv);
     128             : 
     129          34 :         cli_shutdown(srv->cli);
     130          34 :         srv->cli = NULL;
     131             : 
     132          34 :         DEBUG(3, ("smbc_remove_usused_server: %p removed.\n", srv));
     133             : 
     134          34 :         smbc_getFunctionRemoveCachedServer(context)(context, srv);
     135             : 
     136          34 :         SAFE_FREE(srv);
     137          34 :         return 0;
     138             : }
     139             : 
     140             : /****************************************************************
     141             :  * Call the auth_fn with fixed size (fstring) buffers.
     142             :  ***************************************************************/
     143             : static void
     144         102 : SMBC_call_auth_fn(TALLOC_CTX *ctx,
     145             :                   SMBCCTX *context,
     146             :                   const char *server,
     147             :                   const char *share,
     148             :                   char **pp_workgroup,
     149             :                   char **pp_username,
     150             :                   char **pp_password)
     151             : {
     152         102 :         fstring workgroup = { 0 };
     153         102 :         fstring username = { 0 };
     154         102 :         fstring password = { 0 };
     155           0 :         smbc_get_auth_data_with_context_fn auth_with_context_fn;
     156             : 
     157         102 :         if (*pp_workgroup != NULL) {
     158         102 :                 strlcpy(workgroup, *pp_workgroup, sizeof(workgroup));
     159             :         }
     160         102 :         if (*pp_username != NULL) {
     161         102 :                 strlcpy(username, *pp_username, sizeof(username));
     162             :         }
     163         102 :         if (*pp_password != NULL) {
     164         102 :                 strlcpy(password, *pp_password, sizeof(password));
     165             :         }
     166             : 
     167             :         /* See if there's an authentication with context function provided */
     168         102 :         auth_with_context_fn = smbc_getFunctionAuthDataWithContext(context);
     169         102 :         if (auth_with_context_fn)
     170             :         {
     171          86 :             (* auth_with_context_fn)(context,
     172             :                                      server, share,
     173             :                                      workgroup, sizeof(workgroup),
     174             :                                      username, sizeof(username),
     175             :                                      password, sizeof(password));
     176             :         }
     177             :         else
     178             :         {
     179          16 :             smbc_getFunctionAuthData(context)(server, share,
     180             :                                               workgroup, sizeof(workgroup),
     181             :                                               username, sizeof(username),
     182             :                                               password, sizeof(password));
     183             :         }
     184             : 
     185         102 :         TALLOC_FREE(*pp_workgroup);
     186         102 :         TALLOC_FREE(*pp_username);
     187         102 :         TALLOC_FREE(*pp_password);
     188             : 
     189         102 :         *pp_workgroup = talloc_strdup(ctx, workgroup);
     190         102 :         *pp_username = talloc_strdup(ctx, username);
     191         102 :         *pp_password = talloc_strdup(ctx, password);
     192         102 : }
     193             : 
     194             : 
     195             : void
     196           0 : SMBC_get_auth_data(const char *server, const char *share,
     197             :                    char *workgroup_buf, int workgroup_buf_len,
     198             :                    char *username_buf, int username_buf_len,
     199             :                    char *password_buf, int password_buf_len)
     200             : {
     201             :         /* Default function just uses provided data.  Nothing to do. */
     202           0 : }
     203             : 
     204             : 
     205             : 
     206             : SMBCSRV *
     207        1484 : SMBC_find_server(TALLOC_CTX *ctx,
     208             :                  SMBCCTX *context,
     209             :                  const char *server,
     210             :                  const char *share,
     211             :                  char **pp_workgroup,
     212             :                  char **pp_username,
     213             :                  char **pp_password)
     214             : {
     215           0 :         SMBCSRV *srv;
     216        1484 :         int auth_called = 0;
     217             : 
     218        1484 :         if (!pp_workgroup || !pp_username || !pp_password) {
     219           0 :                 return NULL;
     220             :         }
     221             : 
     222        1527 : check_server_cache:
     223             : 
     224        1586 :         srv = smbc_getFunctionGetCachedServer(context)(context,
     225             :                                                        server, share,
     226             :                                                        *pp_workgroup,
     227             :                                                        *pp_username);
     228             : 
     229        1586 :         if (!auth_called && !srv && (!*pp_username || !(*pp_username)[0] ||
     230         162 :                                      !*pp_password || !(*pp_password)[0])) {
     231         102 :                 SMBC_call_auth_fn(ctx, context, server, share,
     232             :                                   pp_workgroup, pp_username, pp_password);
     233             : 
     234             :                 /*
     235             :                  * However, smbc_auth_fn may have picked up info relating to
     236             :                  * an existing connection, so try for an existing connection
     237             :                  * again ...
     238             :                  */
     239         102 :                 auth_called = 1;
     240         102 :                 goto check_server_cache;
     241             : 
     242             :         }
     243             : 
     244        1484 :         if (srv) {
     245        1364 :                 if (smbc_getFunctionCheckServer(context)(context, srv)) {
     246             :                         /*
     247             :                          * This server is no good anymore
     248             :                          * Try to remove it and check for more possible
     249             :                          * servers in the cache
     250             :                          */
     251           0 :                         if (smbc_getFunctionRemoveUnusedServer(context)(context,
     252             :                                                                         srv)) {
     253             :                                 /*
     254             :                                  * We could not remove the server completely,
     255             :                                  * remove it from the cache so we will not get
     256             :                                  * it again. It will be removed when the last
     257             :                                  * file/dir is closed.
     258             :                                  */
     259           0 :                                 smbc_getFunctionRemoveCachedServer(context)(context,
     260             :                                                                             srv);
     261             :                         }
     262             : 
     263             :                         /*
     264             :                          * Maybe there are more cached connections to this
     265             :                          * server
     266             :                          */
     267           0 :                         goto check_server_cache;
     268             :                 }
     269             : 
     270        1364 :                 return srv;
     271             :         }
     272             : 
     273         120 :         return NULL;
     274             : }
     275             : 
     276         100 : static struct cli_credentials *SMBC_auth_credentials(TALLOC_CTX *mem_ctx,
     277             :                                                      SMBCCTX *context,
     278             :                                                      const char *domain,
     279             :                                                      const char *username,
     280             :                                                      const char *password)
     281             : {
     282         100 :         struct cli_credentials *creds = NULL;
     283         100 :         bool use_kerberos = false;
     284         100 :         bool fallback_after_kerberos = false;
     285         100 :         bool use_ccache = false;
     286         100 :         bool pw_nt_hash = false;
     287             : 
     288         100 :         use_kerberos = smbc_getOptionUseKerberos(context);
     289         100 :         fallback_after_kerberos = smbc_getOptionFallbackAfterKerberos(context);
     290         100 :         use_ccache = smbc_getOptionUseCCache(context);
     291         100 :         pw_nt_hash = smbc_getOptionUseNTHash(context);
     292             : 
     293         100 :         creds = cli_session_creds_init(mem_ctx,
     294             :                                        username,
     295             :                                        domain,
     296             :                                        NULL, /* realm */
     297             :                                        password,
     298             :                                        use_kerberos,
     299             :                                        fallback_after_kerberos,
     300             :                                        use_ccache,
     301             :                                        pw_nt_hash);
     302         100 :         if (creds == NULL) {
     303           0 :                 return NULL;
     304             :         }
     305             : 
     306         100 :         switch (context->internal->smb_encryption_level) {
     307          96 :         case SMBC_ENCRYPTLEVEL_DEFAULT:
     308             :                 /* Use the config option */
     309          96 :                 break;
     310           0 :         case SMBC_ENCRYPTLEVEL_NONE:
     311           0 :                 (void)cli_credentials_set_smb_encryption(
     312             :                                 creds,
     313             :                                 SMB_ENCRYPTION_OFF,
     314             :                                 CRED_SPECIFIED);
     315           0 :                 break;
     316           0 :         case SMBC_ENCRYPTLEVEL_REQUEST:
     317           0 :                 (void)cli_credentials_set_smb_encryption(
     318             :                                 creds,
     319             :                                 SMB_ENCRYPTION_DESIRED,
     320             :                                 CRED_SPECIFIED);
     321           0 :                 break;
     322           4 :         case SMBC_ENCRYPTLEVEL_REQUIRE:
     323             :         default:
     324           4 :                 (void)cli_credentials_set_smb_encryption(
     325             :                                 creds,
     326             :                                 SMB_ENCRYPTION_REQUIRED,
     327             :                                 CRED_SPECIFIED);
     328           4 :                 break;
     329             :         }
     330             : 
     331             : 
     332         100 :         return creds;
     333             : }
     334             : 
     335             : /*
     336             :  * Connect to a server, possibly on an existing connection
     337             :  *
     338             :  * Here, what we want to do is: If the server and username
     339             :  * match an existing connection, reuse that, otherwise, establish a
     340             :  * new connection.
     341             :  *
     342             :  * If we have to create a new connection, call the auth_fn to get the
     343             :  * info we need, unless the username and password were passed in.
     344             :  */
     345             : 
     346             : static SMBCSRV *
     347        1472 : SMBC_server_internal(TALLOC_CTX *ctx,
     348             :             SMBCCTX *context,
     349             :             bool connect_if_not_found,
     350             :             const char *server,
     351             :             uint16_t port,
     352             :             const char *share,
     353             :             char **pp_workgroup,
     354             :             char **pp_username,
     355             :             char **pp_password,
     356             :             bool *in_cache)
     357             : {
     358        1472 :         SMBCSRV *srv=NULL;
     359        1472 :         char *workgroup = NULL;
     360        1472 :         struct cli_state *c = NULL;
     361        1472 :         const char *server_n = server;
     362        1472 :         int is_ipc = (share != NULL && strcmp(share, "IPC$") == 0);
     363        1472 :         uint32_t fs_attrs = 0;
     364        1472 :         const char *username_used = NULL;
     365        1472 :         const char *password_used = NULL;
     366           0 :         NTSTATUS status;
     367           0 :         char *newserver, *newshare;
     368        1472 :         int flags = 0;
     369        1472 :         struct smbXcli_tcon *tcon = NULL;
     370        1472 :         int signing_state = SMB_SIGNING_DEFAULT;
     371        1472 :         struct cli_credentials *creds = NULL;
     372             : 
     373        1472 :         *in_cache = false;
     374             : 
     375        1472 :         if (server[0] == 0) {
     376           0 :                 errno = EPERM;
     377           0 :                 return NULL;
     378             :         }
     379             : 
     380             :         /* Look for a cached connection */
     381        1472 :         srv = SMBC_find_server(ctx, context, server, share,
     382             :                                pp_workgroup, pp_username, pp_password);
     383             : 
     384             :         /*
     385             :          * If we found a connection and we're only allowed one share per
     386             :          * server...
     387             :          */
     388        1472 :         if (srv &&
     389        2712 :             share != NULL && *share != '\0' &&
     390        1356 :             smbc_getOptionOneSharePerServer(context)) {
     391             : 
     392             :                 /*
     393             :                  * ... then if there's no current connection to the share,
     394             :                  * connect to it.  SMBC_find_server(), or rather the function
     395             :                  * pointed to by context->get_cached_srv_fn which
     396             :                  * was called by SMBC_find_server(), will have issued a tree
     397             :                  * disconnect if the requested share is not the same as the
     398             :                  * one that was already connected.
     399             :                  */
     400             : 
     401             :                 /*
     402             :                  * Use srv->cli->desthost and srv->cli->share instead of
     403             :                  * server and share below to connect to the actual share,
     404             :                  * i.e., a normal share or a referred share from
     405             :                  * 'msdfs proxy' share.
     406             :                  */
     407           0 :                 if (!cli_state_has_tcon(srv->cli)) {
     408             :                         /* Ensure we have accurate auth info */
     409           0 :                         SMBC_call_auth_fn(ctx, context,
     410           0 :                                           smbXcli_conn_remote_name(srv->cli->conn),
     411           0 :                                           srv->cli->share,
     412             :                                           pp_workgroup,
     413             :                                           pp_username,
     414             :                                           pp_password);
     415             : 
     416           0 :                         if (!*pp_workgroup || !*pp_username || !*pp_password) {
     417           0 :                                 errno = ENOMEM;
     418           0 :                                 cli_shutdown(srv->cli);
     419           0 :                                 srv->cli = NULL;
     420           0 :                                 smbc_getFunctionRemoveCachedServer(context)(context,
     421             :                                                                             srv);
     422           0 :                                 return NULL;
     423             :                         }
     424             : 
     425             :                         /*
     426             :                          * We don't need to renegotiate encryption
     427             :                          * here as the encryption context is not per
     428             :                          * tid.
     429             :                          */
     430             : 
     431           0 :                         status = cli_tree_connect(srv->cli,
     432           0 :                                                   srv->cli->share,
     433             :                                                   "?????",
     434             :                                                   *pp_password);
     435           0 :                         if (!NT_STATUS_IS_OK(status)) {
     436           0 :                                 cli_shutdown(srv->cli);
     437           0 :                                 errno = map_errno_from_nt_status(status);
     438           0 :                                 srv->cli = NULL;
     439           0 :                                 smbc_getFunctionRemoveCachedServer(context)(context,
     440             :                                                                             srv);
     441           0 :                                 srv = NULL;
     442           0 :                                 goto not_found;
     443             :                         }
     444             : 
     445             :                         /* Determine if this share supports case sensitivity */
     446           0 :                         if (is_ipc) {
     447           0 :                                 DEBUG(4,
     448             :                                       ("IPC$ so ignore case sensitivity\n"));
     449           0 :                                 status = NT_STATUS_OK;
     450             :                         } else {
     451           0 :                                 status = cli_get_fs_attr_info(srv->cli, &fs_attrs);
     452             :                         }
     453             : 
     454           0 :                         if (!NT_STATUS_IS_OK(status)) {
     455           0 :                                 DEBUG(4, ("Could not retrieve "
     456             :                                           "case sensitivity flag: %s.\n",
     457             :                                           nt_errstr(status)));
     458             : 
     459             :                                 /*
     460             :                                  * We can't determine the case sensitivity of
     461             :                                  * the share. We have no choice but to use the
     462             :                                  * user-specified case sensitivity setting.
     463             :                                  */
     464           0 :                                 if (smbc_getOptionCaseSensitive(context)) {
     465           0 :                                         cli_set_case_sensitive(srv->cli, true);
     466             :                                 } else {
     467           0 :                                         cli_set_case_sensitive(srv->cli, false);
     468             :                                 }
     469           0 :                         } else if (!is_ipc) {
     470           0 :                                 DEBUG(4,
     471             :                                       ("Case sensitive: %s\n",
     472             :                                        (fs_attrs & FILE_CASE_SENSITIVE_SEARCH
     473             :                                         ? "True"
     474             :                                         : "False")));
     475           0 :                                 cli_set_case_sensitive(
     476             :                                         srv->cli,
     477             :                                         (fs_attrs & FILE_CASE_SENSITIVE_SEARCH
     478             :                                          ? True
     479           0 :                                          : False));
     480             :                         }
     481             : 
     482             :                         /*
     483             :                          * Regenerate the dev value since it's based on both
     484             :                          * server and share
     485             :                          */
     486           0 :                         if (srv) {
     487           0 :                                 const char *remote_name =
     488           0 :                                         smbXcli_conn_remote_name(srv->cli->conn);
     489             : 
     490           0 :                                 srv->dev = (dev_t)(str_checksum(remote_name) ^
     491           0 :                                                    str_checksum(srv->cli->share));
     492             :                         }
     493             :                 }
     494             :         }
     495             : 
     496        1472 :  not_found:
     497             : 
     498             :         /* If we have a connection... */
     499        1472 :         if (srv) {
     500             : 
     501             :                 /* ... then we're done here.  Give 'em what they came for. */
     502        1356 :                 *in_cache = true;
     503        1356 :                 goto done;
     504             :         }
     505             : 
     506             :         /* If we're not asked to connect when a connection doesn't exist... */
     507         116 :         if (! connect_if_not_found) {
     508             :                 /* ... then we're done here. */
     509          16 :                 return NULL;
     510             :         }
     511             : 
     512         100 :         if (!*pp_workgroup || !*pp_username || !*pp_password) {
     513           0 :                 errno = ENOMEM;
     514           0 :                 return NULL;
     515             :         }
     516             : 
     517         100 :         DEBUG(4,("SMBC_server: server_n=[%s] server=[%s]\n", server_n, server));
     518             : 
     519         100 :         DEBUG(4,(" -> server_n=[%s] server=[%s]\n", server_n, server));
     520             : 
     521         100 :         status = NT_STATUS_UNSUCCESSFUL;
     522             : 
     523         100 :         if (context->internal->smb_encryption_level > SMBC_ENCRYPTLEVEL_NONE) {
     524           4 :                 signing_state = SMB_SIGNING_REQUIRED;
     525             :         }
     526             : 
     527         100 :         if (port == 0) {
     528         100 :                 if (share == NULL || *share == '\0' || is_ipc) {
     529             :                         /*
     530             :                          * Try 139 first for IPC$
     531             :                          */
     532          18 :                         status = cli_connect_nb(server_n, NULL, NBT_SMB_PORT, 0x20,
     533             :                                         smbc_getNetbiosName(context),
     534             :                                         signing_state, flags, &c);
     535             :                 }
     536             :         }
     537             : 
     538         100 :         if (!NT_STATUS_IS_OK(status)) {
     539             :                 /*
     540             :                  * No IPC$ or 139 did not work
     541             :                  */
     542          82 :                 status = cli_connect_nb(server_n, NULL, port, 0x20,
     543             :                                         smbc_getNetbiosName(context),
     544             :                                         signing_state, flags, &c);
     545             :         }
     546             : 
     547         100 :         if (!NT_STATUS_IS_OK(status)) {
     548           0 :                 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED)) {
     549           0 :                         DBG_ERR("NetBIOS support disabled, unable to connect\n");
     550             :                 }
     551             : 
     552           0 :                 errno = map_errno_from_nt_status(status);
     553           0 :                 return NULL;
     554             :         }
     555             : 
     556         100 :         cli_set_timeout(c, smbc_getTimeout(context));
     557             : 
     558         100 :         status = smbXcli_negprot(c->conn,
     559         100 :                                  c->timeout,
     560         100 :                                  lp_client_min_protocol(),
     561         100 :                                  lp_client_max_protocol(),
     562             :                                  NULL,
     563             :                                  NULL,
     564             :                                  NULL);
     565         100 :         if (!NT_STATUS_IS_OK(status)) {
     566           4 :                 cli_shutdown(c);
     567           4 :                 errno = map_errno_from_nt_status(status);
     568           4 :                 return NULL;
     569             :         }
     570             : 
     571          96 :         if (smbXcli_conn_protocol(c->conn) >= PROTOCOL_SMB2_02) {
     572             :                 /* Ensure we ask for some initial credits. */
     573          73 :                 smb2cli_conn_set_max_credits(c->conn, DEFAULT_SMB2_MAX_CREDITS);
     574             :         }
     575             : 
     576          96 :         username_used = *pp_username;
     577          96 :         password_used = *pp_password;
     578             : 
     579          96 :         creds = SMBC_auth_credentials(c,
     580             :                                       context,
     581             :                                       *pp_workgroup,
     582             :                                       username_used,
     583             :                                       password_used);
     584          96 :         if (creds == NULL) {
     585           0 :                 cli_shutdown(c);
     586           0 :                 errno = ENOMEM;
     587           0 :                 return NULL;
     588             :         }
     589             : 
     590          96 :         status = cli_session_setup_creds(c, creds);
     591          96 :         if (!NT_STATUS_IS_OK(status)) {
     592             : 
     593             :                 /* Failed.  Try an anonymous login, if allowed by flags. */
     594           2 :                 username_used = "";
     595           2 :                 password_used = "";
     596             : 
     597           2 :                 if (smbc_getOptionNoAutoAnonymousLogin(context) ||
     598           2 :                     !NT_STATUS_IS_OK(cli_session_setup_anon(c))) {
     599             : 
     600           0 :                         cli_shutdown(c);
     601           0 :                         errno = map_errno_from_nt_status(status);
     602           0 :                         return NULL;
     603             :                 }
     604             :         }
     605             : 
     606          96 :         DEBUG(4,(" session setup ok\n"));
     607             : 
     608             :         /* here's the fun part....to support 'msdfs proxy' shares
     609             :            (on Samba or windows) we have to issues a TRANS_GET_DFS_REFERRAL
     610             :            here before trying to connect to the original share.
     611             :            cli_check_msdfs_proxy() will fail if it is a normal share. */
     612             : 
     613         192 :         if (smbXcli_conn_dfs_supported(c->conn) &&
     614          96 :                         cli_check_msdfs_proxy(ctx, c, share,
     615             :                                 &newserver, &newshare,
     616             :                                 creds)) {
     617           0 :                 cli_shutdown(c);
     618           0 :                 srv = SMBC_server_internal(ctx, context, connect_if_not_found,
     619             :                                 newserver, port, newshare, pp_workgroup,
     620             :                                 pp_username, pp_password, in_cache);
     621           0 :                 TALLOC_FREE(newserver);
     622           0 :                 TALLOC_FREE(newshare);
     623           0 :                 return srv;
     624             :         }
     625             : 
     626             :         /* must be a normal share */
     627             : 
     628          96 :         status = cli_tree_connect_creds(c, share, "?????", creds);
     629          96 :         if (!NT_STATUS_IS_OK(status)) {
     630           0 :                 cli_shutdown(c);
     631           0 :                 errno = map_errno_from_nt_status(status);
     632           0 :                 return NULL;
     633             :         }
     634             : 
     635          96 :         DEBUG(4,(" tconx ok\n"));
     636             : 
     637          96 :         if (smbXcli_conn_protocol(c->conn) >= PROTOCOL_SMB2_02) {
     638          73 :                 tcon = c->smb2.tcon;
     639             :         } else {
     640          23 :                 tcon = c->smb1.tcon;
     641             :         }
     642             : 
     643             :         /* Determine if this share supports case sensitivity */
     644          96 :         if (is_ipc) {
     645          14 :                 DEBUG(4, ("IPC$ so ignore case sensitivity\n"));
     646          14 :                 status = NT_STATUS_OK;
     647             :         } else {
     648          82 :                 status = cli_get_fs_attr_info(c, &fs_attrs);
     649             :         }
     650             : 
     651          96 :         if (!NT_STATUS_IS_OK(status)) {
     652           0 :                 DEBUG(4, ("Could not retrieve case sensitivity flag: %s.\n",
     653             :                           nt_errstr(status)));
     654             : 
     655             :                 /*
     656             :                  * We can't determine the case sensitivity of the share. We
     657             :                  * have no choice but to use the user-specified case
     658             :                  * sensitivity setting.
     659             :                  */
     660           0 :                 if (smbc_getOptionCaseSensitive(context)) {
     661           0 :                         cli_set_case_sensitive(c, True);
     662             :                 } else {
     663           0 :                         cli_set_case_sensitive(c, False);
     664             :                 }
     665          96 :         } else if (!is_ipc) {
     666          82 :                 DEBUG(4, ("Case sensitive: %s\n",
     667             :                           (fs_attrs & FILE_CASE_SENSITIVE_SEARCH
     668             :                            ? "True"
     669             :                            : "False")));
     670          82 :                 smbXcli_tcon_set_fs_attributes(tcon, fs_attrs);
     671             :         }
     672             : 
     673             :         /*
     674             :          * Ok, we have got a nice connection
     675             :          * Let's allocate a server structure.
     676             :          */
     677             : 
     678          96 :         srv = SMB_MALLOC_P(SMBCSRV);
     679          96 :         if (!srv) {
     680           0 :                 cli_shutdown(c);
     681           0 :                 errno = ENOMEM;
     682           0 :                 return NULL;
     683             :         }
     684             : 
     685          96 :         ZERO_STRUCTP(srv);
     686          96 :         DLIST_ADD(srv->cli, c);
     687          96 :         srv->dev = (dev_t)(str_checksum(server) ^ str_checksum(share));
     688          96 :         srv->no_pathinfo = False;
     689          96 :         srv->no_pathinfo2 = False;
     690          96 :         srv->no_pathinfo3 = False;
     691          96 :         srv->no_nt_session = False;
     692             : 
     693        1452 : done:
     694        1452 :         if (!pp_workgroup || !*pp_workgroup || !**pp_workgroup) {
     695          10 :                 workgroup = talloc_strdup(ctx, smbc_getWorkgroup(context));
     696             :         } else {
     697        1442 :                 workgroup = *pp_workgroup;
     698             :         }
     699        1452 :         if(!workgroup) {
     700           0 :                 if (c != NULL) {
     701           0 :                         cli_shutdown(c);
     702             :                 }
     703           0 :                 SAFE_FREE(srv);
     704           0 :                 return NULL;
     705             :         }
     706             : 
     707             :         /* set the credentials to make DFS work */
     708        1452 :         smbc_set_credentials_with_fallback(context,
     709             :                                            workgroup,
     710             :                                            *pp_username,
     711             :                                            *pp_password);
     712             : 
     713        1452 :         return srv;
     714             : }
     715             : 
     716             : SMBCSRV *
     717        1472 : SMBC_server(TALLOC_CTX *ctx,
     718             :                 SMBCCTX *context,
     719             :                 bool connect_if_not_found,
     720             :                 const char *server,
     721             :                 uint16_t port,
     722             :                 const char *share,
     723             :                 char **pp_workgroup,
     724             :                 char **pp_username,
     725             :                 char **pp_password)
     726             : {
     727        1472 :         SMBCSRV *srv=NULL;
     728        1472 :         bool in_cache = false;
     729             : 
     730        1472 :         srv = SMBC_server_internal(ctx, context, connect_if_not_found,
     731             :                         server, port, share, pp_workgroup,
     732             :                         pp_username, pp_password, &in_cache);
     733             : 
     734        1472 :         if (!srv) {
     735          20 :                 return NULL;
     736             :         }
     737        1452 :         if (in_cache) {
     738        1356 :                 return srv;
     739             :         }
     740             : 
     741             :         /* Now add it to the cache (internal or external)  */
     742             :         /* Let the cache function set errno if it wants to */
     743          96 :         errno = 0;
     744          96 :         if (smbc_getFunctionAddCachedServer(context)(context, srv,
     745             :                                                 server, share,
     746             :                                                 *pp_workgroup,
     747             :                                                 *pp_username)) {
     748           0 :                 int saved_errno = errno;
     749           0 :                 DEBUG(3, (" Failed to add server to cache\n"));
     750           0 :                 errno = saved_errno;
     751           0 :                 if (errno == 0) {
     752           0 :                         errno = ENOMEM;
     753             :                 }
     754           0 :                 SAFE_FREE(srv);
     755           0 :                 return NULL;
     756             :         }
     757             : 
     758          96 :         DEBUG(2, ("Server connect ok: //%s/%s: %p\n",
     759             :                 server, share, srv));
     760             : 
     761          96 :         DLIST_ADD(context->internal->servers, srv);
     762          96 :         return srv;
     763             : }
     764             : 
     765             : /*
     766             :  * Connect to a server for getting/setting attributes, possibly on an existing
     767             :  * connection.  This works similarly to SMBC_server().
     768             :  */
     769             : SMBCSRV *
     770          12 : SMBC_attr_server(TALLOC_CTX *ctx,
     771             :                  SMBCCTX *context,
     772             :                  const char *server,
     773             :                  uint16_t port,
     774             :                  const char *share,
     775             :                  char **pp_workgroup,
     776             :                  char **pp_username,
     777             :                  char **pp_password)
     778             : {
     779           0 :         int flags;
     780          12 :         struct cli_state *ipc_cli = NULL;
     781          12 :         struct rpc_pipe_client *pipe_hnd = NULL;
     782           0 :         NTSTATUS nt_status;
     783          12 :         SMBCSRV *srv=NULL;
     784          12 :         SMBCSRV *ipc_srv=NULL;
     785             : 
     786             :         /*
     787             :          * Use srv->cli->desthost and srv->cli->share instead of
     788             :          * server and share below to connect to the actual share,
     789             :          * i.e., a normal share or a referred share from
     790             :          * 'msdfs proxy' share.
     791             :          */
     792          12 :         srv = SMBC_server(ctx, context, true, server, port, share,
     793             :                         pp_workgroup, pp_username, pp_password);
     794          12 :         if (!srv) {
     795           0 :                 return NULL;
     796             :         }
     797          12 :         server = smbXcli_conn_remote_name(srv->cli->conn);
     798          12 :         share = srv->cli->share;
     799             : 
     800             :         /*
     801             :          * See if we've already created this special connection.  Reference
     802             :          * our "special" share name '*IPC$', which is an impossible real share
     803             :          * name due to the leading asterisk.
     804             :          */
     805          12 :         ipc_srv = SMBC_find_server(ctx, context, server, "*IPC$",
     806             :                                    pp_workgroup, pp_username, pp_password);
     807          12 :         if (!ipc_srv) {
     808           4 :                 struct cli_credentials *creds = NULL;
     809             : 
     810             :                 /* We didn't find a cached connection.  Get the password */
     811           4 :                 if (!*pp_password || (*pp_password)[0] == '\0') {
     812             :                         /* ... then retrieve it now. */
     813           0 :                         SMBC_call_auth_fn(ctx, context, server, share,
     814             :                                           pp_workgroup,
     815             :                                           pp_username,
     816             :                                           pp_password);
     817           0 :                         if (!*pp_workgroup || !*pp_username || !*pp_password) {
     818           0 :                                 errno = ENOMEM;
     819           0 :                                 return NULL;
     820             :                         }
     821             :                 }
     822             : 
     823           4 :                 flags = 0;
     824             : 
     825           4 :                 creds = SMBC_auth_credentials(NULL,
     826             :                                               context,
     827             :                                               *pp_workgroup,
     828             :                                               *pp_username,
     829             :                                               *pp_password);
     830           4 :                 if (creds == NULL) {
     831           0 :                         errno = ENOMEM;
     832           0 :                         return NULL;
     833             :                 }
     834             : 
     835           4 :                 nt_status = cli_full_connection_creds(&ipc_cli,
     836             :                                                 lp_netbios_name(), server,
     837             :                                                 NULL, 0, "IPC$", "?????",
     838             :                                                 creds,
     839             :                                                 flags);
     840           4 :                 if (! NT_STATUS_IS_OK(nt_status)) {
     841           0 :                         TALLOC_FREE(creds);
     842           0 :                         DEBUG(1,("cli_full_connection failed! (%s)\n",
     843             :                                  nt_errstr(nt_status)));
     844           0 :                         errno = ENOTSUP;
     845           0 :                         return NULL;
     846             :                 }
     847           4 :                 talloc_steal(ipc_cli, creds);
     848             : 
     849           4 :                 ipc_srv = SMB_MALLOC_P(SMBCSRV);
     850           4 :                 if (!ipc_srv) {
     851           0 :                         errno = ENOMEM;
     852           0 :                         cli_shutdown(ipc_cli);
     853           0 :                         return NULL;
     854             :                 }
     855             : 
     856           4 :                 ZERO_STRUCTP(ipc_srv);
     857           4 :                 DLIST_ADD(ipc_srv->cli, ipc_cli);
     858             : 
     859           4 :                 nt_status = cli_rpc_pipe_open_noauth(
     860             :                         ipc_srv->cli, &ndr_table_lsarpc, &pipe_hnd);
     861           4 :                 if (!NT_STATUS_IS_OK(nt_status)) {
     862           0 :                         DEBUG(1, ("cli_nt_session_open fail!\n"));
     863           0 :                         errno = ENOTSUP;
     864           0 :                         cli_shutdown(ipc_srv->cli);
     865           0 :                         free(ipc_srv);
     866           0 :                         return NULL;
     867             :                 }
     868             : 
     869             :                 /*
     870             :                  * Some systems don't support
     871             :                  * SEC_FLAG_MAXIMUM_ALLOWED, but NT sends 0x2000000
     872             :                  * so we might as well do it too.
     873             :                  */
     874             : 
     875           4 :                 nt_status = rpccli_lsa_open_policy(
     876             :                         pipe_hnd,
     877             :                         talloc_tos(),
     878             :                         True,
     879             :                         GENERIC_EXECUTE_ACCESS,
     880             :                         &ipc_srv->pol);
     881             : 
     882           4 :                 if (!NT_STATUS_IS_OK(nt_status)) {
     883           0 :                         cli_shutdown(ipc_srv->cli);
     884           0 :                         free(ipc_srv);
     885           0 :                         errno = cli_status_to_errno(nt_status);
     886           0 :                         return NULL;
     887             :                 }
     888             : 
     889             :                 /* now add it to the cache (internal or external) */
     890             : 
     891           4 :                 errno = 0;      /* let cache function set errno if it likes */
     892           4 :                 if (smbc_getFunctionAddCachedServer(context)(context, ipc_srv,
     893             :                                                              server,
     894             :                                                              "*IPC$",
     895             :                                                              *pp_workgroup,
     896             :                                                              *pp_username)) {
     897           0 :                         DEBUG(3, (" Failed to add server to cache\n"));
     898           0 :                         if (errno == 0) {
     899           0 :                                 errno = ENOMEM;
     900             :                         }
     901           0 :                         cli_shutdown(ipc_srv->cli);
     902           0 :                         free(ipc_srv);
     903           0 :                         return NULL;
     904             :                 }
     905             : 
     906           4 :                 DLIST_ADD(context->internal->servers, ipc_srv);
     907             :         }
     908             : 
     909          12 :         return ipc_srv;
     910             : }

Generated by: LCOV version 1.14