LCOV - code coverage report
Current view: top level - source3/libsmb - libsmb_server.c (source / functions) Hit Total Coverage
Test: coverage report for master 98b443d9 Lines: 210 350 60.0 %
Date: 2024-05-31 13:13:24 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          31 : SMBC_remove_unused_server(SMBCCTX * context,
     107             :                           SMBCSRV * srv)
     108             : {
     109           0 :         SMBCFILE * file;
     110             : 
     111             :         /* are we being fooled ? */
     112          31 :         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          31 :         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          31 :         DLIST_REMOVE(context->internal->servers, srv);
     128             : 
     129          31 :         cli_shutdown(srv->cli);
     130          31 :         srv->cli = NULL;
     131             : 
     132          31 :         DEBUG(3, ("smbc_remove_usused_server: %p removed.\n", srv));
     133             : 
     134          31 :         smbc_getFunctionRemoveCachedServer(context)(context, srv);
     135             : 
     136          31 :         SAFE_FREE(srv);
     137          31 :         return 0;
     138             : }
     139             : 
     140             : /****************************************************************
     141             :  * Call the auth_fn with fixed size (fstring) buffers.
     142             :  ***************************************************************/
     143             : static void
     144          99 : 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          99 :         fstring workgroup = { 0 };
     153          99 :         fstring username = { 0 };
     154          99 :         fstring password = { 0 };
     155           0 :         smbc_get_auth_data_with_context_fn auth_with_context_fn;
     156             : 
     157          99 :         if (*pp_workgroup != NULL) {
     158          99 :                 strlcpy(workgroup, *pp_workgroup, sizeof(workgroup));
     159             :         }
     160          99 :         if (*pp_username != NULL) {
     161          99 :                 strlcpy(username, *pp_username, sizeof(username));
     162             :         }
     163          99 :         if (*pp_password != NULL) {
     164          99 :                 strlcpy(password, *pp_password, sizeof(password));
     165             :         }
     166             : 
     167             :         /* See if there's an authentication with context function provided */
     168          99 :         auth_with_context_fn = smbc_getFunctionAuthDataWithContext(context);
     169          99 :         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          13 :             smbc_getFunctionAuthData(context)(server, share,
     180             :                                               workgroup, sizeof(workgroup),
     181             :                                               username, sizeof(username),
     182             :                                               password, sizeof(password));
     183             :         }
     184             : 
     185          99 :         TALLOC_FREE(*pp_workgroup);
     186          99 :         TALLOC_FREE(*pp_username);
     187          99 :         TALLOC_FREE(*pp_password);
     188             : 
     189          99 :         *pp_workgroup = talloc_strdup(ctx, workgroup);
     190          99 :         *pp_username = talloc_strdup(ctx, username);
     191          99 :         *pp_password = talloc_strdup(ctx, password);
     192          99 : }
     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        1481 : 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        1481 :         int auth_called = 0;
     217             : 
     218        1481 :         if (!pp_workgroup || !pp_username || !pp_password) {
     219           0 :                 return NULL;
     220             :         }
     221             : 
     222        1524 : check_server_cache:
     223             : 
     224        1580 :         srv = smbc_getFunctionGetCachedServer(context)(context,
     225             :                                                        server, share,
     226             :                                                        *pp_workgroup,
     227             :                                                        *pp_username);
     228             : 
     229        1580 :         if (!auth_called && !srv && (!*pp_username || !(*pp_username)[0] ||
     230         159 :                                      !*pp_password || !(*pp_password)[0])) {
     231          99 :                 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          99 :                 auth_called = 1;
     240          99 :                 goto check_server_cache;
     241             : 
     242             :         }
     243             : 
     244        1481 :         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         117 :         return NULL;
     274             : }
     275             : 
     276          97 : 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          97 :         struct cli_credentials *creds = NULL;
     283          97 :         bool use_kerberos = false;
     284          97 :         bool fallback_after_kerberos = false;
     285          97 :         bool use_ccache = false;
     286          97 :         bool pw_nt_hash = false;
     287             : 
     288          97 :         use_kerberos = smbc_getOptionUseKerberos(context);
     289          97 :         fallback_after_kerberos = smbc_getOptionFallbackAfterKerberos(context);
     290          97 :         use_ccache = smbc_getOptionUseCCache(context);
     291          97 :         pw_nt_hash = smbc_getOptionUseNTHash(context);
     292             : 
     293          97 :         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          97 :         if (creds == NULL) {
     303           0 :                 return NULL;
     304             :         }
     305             : 
     306          97 :         switch (context->internal->smb_encryption_level) {
     307          93 :         case SMBC_ENCRYPTLEVEL_DEFAULT:
     308             :                 /* Use the config option */
     309          93 :                 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          97 :         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        1469 : 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        1469 :         SMBCSRV *srv=NULL;
     359        1469 :         char *workgroup = NULL;
     360        1469 :         struct cli_state *c = NULL;
     361        1469 :         const char *server_n = server;
     362        1469 :         int is_ipc = (share != NULL && strcmp(share, "IPC$") == 0);
     363        1469 :         uint32_t fs_attrs = 0;
     364        1469 :         const char *username_used = NULL;
     365        1469 :         const char *password_used = NULL;
     366           0 :         NTSTATUS status;
     367           0 :         char *newserver, *newshare;
     368        1469 :         int flags = 0;
     369        1469 :         struct smbXcli_tcon *tcon = NULL;
     370        1469 :         int signing_state = SMB_SIGNING_DEFAULT;
     371        1469 :         struct cli_credentials *creds = NULL;
     372             : 
     373        1469 :         *in_cache = false;
     374             : 
     375        1469 :         if (server[0] == 0) {
     376           0 :                 errno = EPERM;
     377           0 :                 return NULL;
     378             :         }
     379             : 
     380             :         /* Look for a cached connection */
     381        1469 :         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        1469 :         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        1469 :  not_found:
     497             : 
     498             :         /* If we have a connection... */
     499        1469 :         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         113 :         if (! connect_if_not_found) {
     508             :                 /* ... then we're done here. */
     509          16 :                 return NULL;
     510             :         }
     511             : 
     512          97 :         if (!*pp_workgroup || !*pp_username || !*pp_password) {
     513           0 :                 errno = ENOMEM;
     514           0 :                 return NULL;
     515             :         }
     516             : 
     517          97 :         DEBUG(4,("SMBC_server: server_n=[%s] server=[%s]\n", server_n, server));
     518             : 
     519          97 :         DEBUG(4,(" -> server_n=[%s] server=[%s]\n", server_n, server));
     520             : 
     521          97 :         status = NT_STATUS_UNSUCCESSFUL;
     522             : 
     523          97 :         if (context->internal->smb_encryption_level > SMBC_ENCRYPTLEVEL_NONE) {
     524           4 :                 signing_state = SMB_SIGNING_REQUIRED;
     525             :         }
     526             : 
     527          97 :         if (port == 0) {
     528          97 :                 if (share == NULL || *share == '\0' || is_ipc) {
     529             :                         /*
     530             :                          * Try 139 first for IPC$
     531             :                          */
     532          15 :                         status = cli_connect_nb(NULL,
     533             :                                                 server_n,
     534             :                                                 NULL,
     535             :                                                 NBT_SMB_PORT,
     536             :                                                 0x20,
     537             :                                                 smbc_getNetbiosName(context),
     538             :                                                 signing_state,
     539             :                                                 flags,
     540             :                                                 &c);
     541             :                 }
     542             :         }
     543             : 
     544          97 :         if (!NT_STATUS_IS_OK(status)) {
     545             :                 /*
     546             :                  * No IPC$ or 139 did not work
     547             :                  */
     548          82 :                 status = cli_connect_nb(NULL,
     549             :                                         server_n,
     550             :                                         NULL,
     551             :                                         port,
     552             :                                         0x20,
     553             :                                         smbc_getNetbiosName(context),
     554             :                                         signing_state,
     555             :                                         flags,
     556             :                                         &c);
     557             :         }
     558             : 
     559          97 :         if (!NT_STATUS_IS_OK(status)) {
     560           0 :                 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED)) {
     561           0 :                         DBG_ERR("NetBIOS support disabled, unable to connect\n");
     562             :                 }
     563             : 
     564           0 :                 errno = map_errno_from_nt_status(status);
     565           0 :                 return NULL;
     566             :         }
     567             : 
     568          97 :         cli_set_timeout(c, smbc_getTimeout(context));
     569             : 
     570          97 :         status = smbXcli_negprot(c->conn,
     571          97 :                                  c->timeout,
     572          97 :                                  lp_client_min_protocol(),
     573          97 :                                  lp_client_max_protocol(),
     574             :                                  NULL,
     575             :                                  NULL,
     576             :                                  NULL);
     577          97 :         if (!NT_STATUS_IS_OK(status)) {
     578           4 :                 cli_shutdown(c);
     579           4 :                 errno = map_errno_from_nt_status(status);
     580           4 :                 return NULL;
     581             :         }
     582             : 
     583          93 :         if (smbXcli_conn_protocol(c->conn) >= PROTOCOL_SMB2_02) {
     584             :                 /* Ensure we ask for some initial credits. */
     585          72 :                 smb2cli_conn_set_max_credits(c->conn, DEFAULT_SMB2_MAX_CREDITS);
     586             :         }
     587             : 
     588          93 :         username_used = *pp_username;
     589          93 :         password_used = *pp_password;
     590             : 
     591          93 :         creds = SMBC_auth_credentials(c,
     592             :                                       context,
     593             :                                       *pp_workgroup,
     594             :                                       username_used,
     595             :                                       password_used);
     596          93 :         if (creds == NULL) {
     597           0 :                 cli_shutdown(c);
     598           0 :                 errno = ENOMEM;
     599           0 :                 return NULL;
     600             :         }
     601             : 
     602          93 :         status = cli_session_setup_creds(c, creds);
     603          93 :         if (!NT_STATUS_IS_OK(status)) {
     604             : 
     605             :                 /* Failed.  Try an anonymous login, if allowed by flags. */
     606           2 :                 username_used = "";
     607           2 :                 password_used = "";
     608             : 
     609           2 :                 if (smbc_getOptionNoAutoAnonymousLogin(context) ||
     610           2 :                     !NT_STATUS_IS_OK(cli_session_setup_anon(c))) {
     611             : 
     612           0 :                         cli_shutdown(c);
     613           0 :                         errno = map_errno_from_nt_status(status);
     614           0 :                         return NULL;
     615             :                 }
     616             :         }
     617             : 
     618          93 :         DEBUG(4,(" session setup ok\n"));
     619             : 
     620             :         /* here's the fun part....to support 'msdfs proxy' shares
     621             :            (on Samba or windows) we have to issues a TRANS_GET_DFS_REFERRAL
     622             :            here before trying to connect to the original share.
     623             :            cli_check_msdfs_proxy() will fail if it is a normal share. */
     624             : 
     625         186 :         if (smbXcli_conn_dfs_supported(c->conn) &&
     626          93 :                         cli_check_msdfs_proxy(ctx, c, share,
     627             :                                 &newserver, &newshare,
     628             :                                 creds)) {
     629           0 :                 cli_shutdown(c);
     630           0 :                 srv = SMBC_server_internal(ctx, context, connect_if_not_found,
     631             :                                 newserver, port, newshare, pp_workgroup,
     632             :                                 pp_username, pp_password, in_cache);
     633           0 :                 TALLOC_FREE(newserver);
     634           0 :                 TALLOC_FREE(newshare);
     635           0 :                 return srv;
     636             :         }
     637             : 
     638             :         /* must be a normal share */
     639             : 
     640          93 :         status = cli_tree_connect_creds(c, share, "?????", creds);
     641          93 :         if (!NT_STATUS_IS_OK(status)) {
     642           0 :                 cli_shutdown(c);
     643           0 :                 errno = map_errno_from_nt_status(status);
     644           0 :                 return NULL;
     645             :         }
     646             : 
     647          93 :         DEBUG(4,(" tconx ok\n"));
     648             : 
     649          93 :         if (smbXcli_conn_protocol(c->conn) >= PROTOCOL_SMB2_02) {
     650          72 :                 tcon = c->smb2.tcon;
     651             :         } else {
     652          21 :                 tcon = c->smb1.tcon;
     653             :         }
     654             : 
     655             :         /* Determine if this share supports case sensitivity */
     656          93 :         if (is_ipc) {
     657          11 :                 DEBUG(4, ("IPC$ so ignore case sensitivity\n"));
     658          11 :                 status = NT_STATUS_OK;
     659             :         } else {
     660          82 :                 status = cli_get_fs_attr_info(c, &fs_attrs);
     661             :         }
     662             : 
     663          93 :         if (!NT_STATUS_IS_OK(status)) {
     664           0 :                 DEBUG(4, ("Could not retrieve case sensitivity flag: %s.\n",
     665             :                           nt_errstr(status)));
     666             : 
     667             :                 /*
     668             :                  * We can't determine the case sensitivity of the share. We
     669             :                  * have no choice but to use the user-specified case
     670             :                  * sensitivity setting.
     671             :                  */
     672           0 :                 if (smbc_getOptionCaseSensitive(context)) {
     673           0 :                         cli_set_case_sensitive(c, True);
     674             :                 } else {
     675           0 :                         cli_set_case_sensitive(c, False);
     676             :                 }
     677          93 :         } else if (!is_ipc) {
     678          82 :                 DEBUG(4, ("Case sensitive: %s\n",
     679             :                           (fs_attrs & FILE_CASE_SENSITIVE_SEARCH
     680             :                            ? "True"
     681             :                            : "False")));
     682          82 :                 smbXcli_tcon_set_fs_attributes(tcon, fs_attrs);
     683             :         }
     684             : 
     685             :         /*
     686             :          * Ok, we have got a nice connection
     687             :          * Let's allocate a server structure.
     688             :          */
     689             : 
     690          93 :         srv = SMB_MALLOC_P(SMBCSRV);
     691          93 :         if (!srv) {
     692           0 :                 cli_shutdown(c);
     693           0 :                 errno = ENOMEM;
     694           0 :                 return NULL;
     695             :         }
     696             : 
     697          93 :         ZERO_STRUCTP(srv);
     698          93 :         DLIST_ADD(srv->cli, c);
     699          93 :         srv->dev = (dev_t)(str_checksum(server) ^ str_checksum(share));
     700          93 :         srv->no_pathinfo = False;
     701          93 :         srv->no_pathinfo2 = False;
     702          93 :         srv->no_pathinfo3 = False;
     703          93 :         srv->no_nt_session = False;
     704             : 
     705        1449 : done:
     706        1449 :         if (!pp_workgroup || !*pp_workgroup || !**pp_workgroup) {
     707          10 :                 workgroup = talloc_strdup(ctx, smbc_getWorkgroup(context));
     708             :         } else {
     709        1439 :                 workgroup = *pp_workgroup;
     710             :         }
     711        1449 :         if(!workgroup) {
     712           0 :                 if (c != NULL) {
     713           0 :                         cli_shutdown(c);
     714             :                 }
     715           0 :                 SAFE_FREE(srv);
     716           0 :                 return NULL;
     717             :         }
     718             : 
     719             :         /* set the credentials to make DFS work */
     720        1449 :         smbc_set_credentials_with_fallback(context,
     721             :                                            workgroup,
     722             :                                            *pp_username,
     723             :                                            *pp_password);
     724             : 
     725        1449 :         return srv;
     726             : }
     727             : 
     728             : SMBCSRV *
     729        1469 : SMBC_server(TALLOC_CTX *ctx,
     730             :                 SMBCCTX *context,
     731             :                 bool connect_if_not_found,
     732             :                 const char *server,
     733             :                 uint16_t port,
     734             :                 const char *share,
     735             :                 char **pp_workgroup,
     736             :                 char **pp_username,
     737             :                 char **pp_password)
     738             : {
     739        1469 :         SMBCSRV *srv=NULL;
     740        1469 :         bool in_cache = false;
     741             : 
     742        1469 :         srv = SMBC_server_internal(ctx, context, connect_if_not_found,
     743             :                         server, port, share, pp_workgroup,
     744             :                         pp_username, pp_password, &in_cache);
     745             : 
     746        1469 :         if (!srv) {
     747          20 :                 return NULL;
     748             :         }
     749        1449 :         if (in_cache) {
     750        1356 :                 return srv;
     751             :         }
     752             : 
     753             :         /* Now add it to the cache (internal or external)  */
     754             :         /* Let the cache function set errno if it wants to */
     755          93 :         errno = 0;
     756          93 :         if (smbc_getFunctionAddCachedServer(context)(context, srv,
     757             :                                                 server, share,
     758             :                                                 *pp_workgroup,
     759             :                                                 *pp_username)) {
     760           0 :                 int saved_errno = errno;
     761           0 :                 DEBUG(3, (" Failed to add server to cache\n"));
     762           0 :                 errno = saved_errno;
     763           0 :                 if (errno == 0) {
     764           0 :                         errno = ENOMEM;
     765             :                 }
     766           0 :                 SAFE_FREE(srv);
     767           0 :                 return NULL;
     768             :         }
     769             : 
     770          93 :         DEBUG(2, ("Server connect ok: //%s/%s: %p\n",
     771             :                 server, share, srv));
     772             : 
     773          93 :         DLIST_ADD(context->internal->servers, srv);
     774          93 :         return srv;
     775             : }
     776             : 
     777             : /*
     778             :  * Connect to a server for getting/setting attributes, possibly on an existing
     779             :  * connection.  This works similarly to SMBC_server().
     780             :  */
     781             : SMBCSRV *
     782          12 : SMBC_attr_server(TALLOC_CTX *ctx,
     783             :                  SMBCCTX *context,
     784             :                  const char *server,
     785             :                  uint16_t port,
     786             :                  const char *share,
     787             :                  char **pp_workgroup,
     788             :                  char **pp_username,
     789             :                  char **pp_password)
     790             : {
     791           0 :         int flags;
     792          12 :         struct cli_state *ipc_cli = NULL;
     793          12 :         struct rpc_pipe_client *pipe_hnd = NULL;
     794           0 :         NTSTATUS nt_status;
     795          12 :         SMBCSRV *srv=NULL;
     796          12 :         SMBCSRV *ipc_srv=NULL;
     797             : 
     798             :         /*
     799             :          * Use srv->cli->desthost and srv->cli->share instead of
     800             :          * server and share below to connect to the actual share,
     801             :          * i.e., a normal share or a referred share from
     802             :          * 'msdfs proxy' share.
     803             :          */
     804          12 :         srv = SMBC_server(ctx, context, true, server, port, share,
     805             :                         pp_workgroup, pp_username, pp_password);
     806          12 :         if (!srv) {
     807           0 :                 return NULL;
     808             :         }
     809          12 :         server = smbXcli_conn_remote_name(srv->cli->conn);
     810          12 :         share = srv->cli->share;
     811             : 
     812             :         /*
     813             :          * See if we've already created this special connection.  Reference
     814             :          * our "special" share name '*IPC$', which is an impossible real share
     815             :          * name due to the leading asterisk.
     816             :          */
     817          12 :         ipc_srv = SMBC_find_server(ctx, context, server, "*IPC$",
     818             :                                    pp_workgroup, pp_username, pp_password);
     819          12 :         if (!ipc_srv) {
     820           4 :                 struct cli_credentials *creds = NULL;
     821             : 
     822             :                 /* We didn't find a cached connection.  Get the password */
     823           4 :                 if (!*pp_password || (*pp_password)[0] == '\0') {
     824             :                         /* ... then retrieve it now. */
     825           0 :                         SMBC_call_auth_fn(ctx, context, server, share,
     826             :                                           pp_workgroup,
     827             :                                           pp_username,
     828             :                                           pp_password);
     829           0 :                         if (!*pp_workgroup || !*pp_username || !*pp_password) {
     830           0 :                                 errno = ENOMEM;
     831           0 :                                 return NULL;
     832             :                         }
     833             :                 }
     834             : 
     835           4 :                 flags = 0;
     836             : 
     837           4 :                 creds = SMBC_auth_credentials(NULL,
     838             :                                               context,
     839             :                                               *pp_workgroup,
     840             :                                               *pp_username,
     841             :                                               *pp_password);
     842           4 :                 if (creds == NULL) {
     843           0 :                         errno = ENOMEM;
     844           0 :                         return NULL;
     845             :                 }
     846             : 
     847           4 :                 nt_status = cli_full_connection_creds(NULL,
     848             :                                                       &ipc_cli,
     849             :                                                       lp_netbios_name(),
     850             :                                                       server,
     851             :                                                       NULL,
     852             :                                                       0,
     853             :                                                       "IPC$",
     854             :                                                       "?????",
     855             :                                                       creds,
     856             :                                                       flags);
     857           4 :                 if (! NT_STATUS_IS_OK(nt_status)) {
     858           0 :                         TALLOC_FREE(creds);
     859           0 :                         DEBUG(1,("cli_full_connection failed! (%s)\n",
     860             :                                  nt_errstr(nt_status)));
     861           0 :                         errno = ENOTSUP;
     862           0 :                         return NULL;
     863             :                 }
     864           4 :                 talloc_steal(ipc_cli, creds);
     865             : 
     866           4 :                 ipc_srv = SMB_MALLOC_P(SMBCSRV);
     867           4 :                 if (!ipc_srv) {
     868           0 :                         errno = ENOMEM;
     869           0 :                         cli_shutdown(ipc_cli);
     870           0 :                         return NULL;
     871             :                 }
     872             : 
     873           4 :                 ZERO_STRUCTP(ipc_srv);
     874           4 :                 DLIST_ADD(ipc_srv->cli, ipc_cli);
     875             : 
     876           4 :                 nt_status = cli_rpc_pipe_open_noauth(
     877             :                         ipc_srv->cli, &ndr_table_lsarpc, &pipe_hnd);
     878           4 :                 if (!NT_STATUS_IS_OK(nt_status)) {
     879           0 :                         DEBUG(1, ("cli_nt_session_open fail!\n"));
     880           0 :                         errno = ENOTSUP;
     881           0 :                         cli_shutdown(ipc_srv->cli);
     882           0 :                         free(ipc_srv);
     883           0 :                         return NULL;
     884             :                 }
     885             : 
     886             :                 /*
     887             :                  * Some systems don't support
     888             :                  * SEC_FLAG_MAXIMUM_ALLOWED, but NT sends 0x2000000
     889             :                  * so we might as well do it too.
     890             :                  */
     891             : 
     892           4 :                 nt_status = rpccli_lsa_open_policy(
     893             :                         pipe_hnd,
     894             :                         talloc_tos(),
     895             :                         True,
     896             :                         GENERIC_EXECUTE_ACCESS,
     897             :                         &ipc_srv->pol);
     898             : 
     899           4 :                 if (!NT_STATUS_IS_OK(nt_status)) {
     900           0 :                         cli_shutdown(ipc_srv->cli);
     901           0 :                         free(ipc_srv);
     902           0 :                         errno = cli_status_to_errno(nt_status);
     903           0 :                         return NULL;
     904             :                 }
     905             : 
     906             :                 /* now add it to the cache (internal or external) */
     907             : 
     908           4 :                 errno = 0;      /* let cache function set errno if it likes */
     909           4 :                 if (smbc_getFunctionAddCachedServer(context)(context, ipc_srv,
     910             :                                                              server,
     911             :                                                              "*IPC$",
     912             :                                                              *pp_workgroup,
     913             :                                                              *pp_username)) {
     914           0 :                         DEBUG(3, (" Failed to add server to cache\n"));
     915           0 :                         if (errno == 0) {
     916           0 :                                 errno = ENOMEM;
     917             :                         }
     918           0 :                         cli_shutdown(ipc_srv->cli);
     919           0 :                         free(ipc_srv);
     920           0 :                         return NULL;
     921             :                 }
     922             : 
     923           4 :                 DLIST_ADD(context->internal->servers, ipc_srv);
     924             :         }
     925             : 
     926          12 :         return ipc_srv;
     927             : }

Generated by: LCOV version 1.14