LCOV - code coverage report
Current view: top level - source3/libsmb - libsmb_dir.c (source / functions) Hit Total Coverage
Test: coverage report for abartlet/fix-coverage dd10fb34 Lines: 542 1234 43.9 %
Date: 2021-09-23 10:06:22 Functions: 23 33 69.7 %

          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             : 
      11             :    This program is free software; you can redistribute it and/or modify
      12             :    it under the terms of the GNU General Public License as published by
      13             :    the Free Software Foundation; either version 3 of the License, or
      14             :    (at your option) any later version.
      15             : 
      16             :    This program is distributed in the hope that it will be useful,
      17             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      18             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      19             :    GNU General Public License for more details.
      20             : 
      21             :    You should have received a copy of the GNU General Public License
      22             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      23             : */
      24             : 
      25             : #include "includes.h"
      26             : #include "libsmb/namequery.h"
      27             : #include "libsmb/libsmb.h"
      28             : #include "libsmbclient.h"
      29             : #include "libsmb_internal.h"
      30             : #include "rpc_client/cli_pipe.h"
      31             : #include "../librpc/gen_ndr/ndr_srvsvc_c.h"
      32             : #include "libsmb/nmblib.h"
      33             : #include "../libcli/smb/smbXcli_base.h"
      34             : #include "../libcli/security/security.h"
      35             : #include "lib/util/tevent_ntstatus.h"
      36             : #include "lib/util/time_basic.h"
      37             : #include "lib/util/string_wrappers.h"
      38             : 
      39             : /*
      40             :  * Routine to open a directory
      41             :  * We accept the URL syntax explained in SMBC_parse_path(), above.
      42             :  */
      43             : 
      44          52 : static void remove_dirplus(SMBCFILE *dir)
      45             : {
      46          52 :         struct smbc_dirplus_list *d = NULL;
      47             : 
      48          52 :         d = dir->dirplus_list;
      49        1186 :         while (d != NULL) {
      50        1082 :                 struct smbc_dirplus_list *f = d;
      51        1082 :                 d = d->next;
      52             : 
      53        1082 :                 SAFE_FREE(f->smb_finfo->short_name);
      54        1082 :                 SAFE_FREE(f->smb_finfo->name);
      55        1082 :                 SAFE_FREE(f->smb_finfo);
      56        1082 :                 SAFE_FREE(f);
      57             :         }
      58             : 
      59          52 :         dir->dirplus_list = NULL;
      60          52 :         dir->dirplus_end = NULL;
      61          52 :         dir->dirplus_next = NULL;
      62          52 : }
      63             : 
      64             : static void
      65          52 : remove_dir(SMBCFILE *dir)
      66             : {
      67             :         struct smbc_dir_list *d,*f;
      68             : 
      69          52 :         d = dir->dir_list;
      70        1766 :         while (d) {
      71             : 
      72        1662 :                 f = d; d = d->next;
      73             : 
      74        1662 :                 SAFE_FREE(f->dirent);
      75        1662 :                 SAFE_FREE(f);
      76             : 
      77             :         }
      78             : 
      79          52 :         dir->dir_list = dir->dir_end = dir->dir_next = NULL;
      80             : 
      81          52 : }
      82             : 
      83             : static int
      84        1662 : add_dirent(SMBCFILE *dir,
      85             :            const char *name,
      86             :            const char *comment,
      87             :            uint32_t type)
      88             : {
      89             :         struct smbc_dirent *dirent;
      90             :         int size;
      91        1662 :         int name_length = (name == NULL ? 0 : strlen(name));
      92        1662 :         int comment_len = (comment == NULL ? 0 : strlen(comment));
      93             : 
      94             :         /*
      95             :          * Allocate space for the dirent, which must be increased by the
      96             :          * size of the name and the comment and 1 each for the null terminator.
      97             :          */
      98             : 
      99        1662 :         size = sizeof(struct smbc_dirent) + name_length + comment_len + 2;
     100             : 
     101        1662 :         dirent = (struct smbc_dirent *)SMB_MALLOC(size);
     102             : 
     103        1662 :         if (!dirent) {
     104             : 
     105           0 :                 dir->dir_error = ENOMEM;
     106           0 :                 return -1;
     107             : 
     108             :         }
     109             : 
     110        1662 :         ZERO_STRUCTP(dirent);
     111             : 
     112        1662 :         if (dir->dir_list == NULL) {
     113             : 
     114          50 :                 dir->dir_list = SMB_MALLOC_P(struct smbc_dir_list);
     115          50 :                 if (!dir->dir_list) {
     116             : 
     117           0 :                         SAFE_FREE(dirent);
     118           0 :                         dir->dir_error = ENOMEM;
     119           0 :                         return -1;
     120             : 
     121             :                 }
     122          50 :                 ZERO_STRUCTP(dir->dir_list);
     123             : 
     124          50 :                 dir->dir_end = dir->dir_next = dir->dir_list;
     125             :         }
     126             :         else {
     127             : 
     128        1612 :                 dir->dir_end->next = SMB_MALLOC_P(struct smbc_dir_list);
     129             : 
     130        1612 :                 if (!dir->dir_end->next) {
     131             : 
     132           0 :                         SAFE_FREE(dirent);
     133           0 :                         dir->dir_error = ENOMEM;
     134           0 :                         return -1;
     135             : 
     136             :                 }
     137        1612 :                 ZERO_STRUCTP(dir->dir_end->next);
     138             : 
     139        1612 :                 dir->dir_end = dir->dir_end->next;
     140             :         }
     141             : 
     142        1662 :         dir->dir_end->next = NULL;
     143        1662 :         dir->dir_end->dirent = dirent;
     144             : 
     145        1662 :         dirent->smbc_type = type;
     146        1662 :         dirent->namelen = name_length;
     147        1662 :         dirent->commentlen = comment_len;
     148        1662 :         dirent->dirlen = size;
     149             : 
     150             :         /*
     151             :          * dirent->namelen + 1 includes the null (no null termination needed)
     152             :          * Ditto for dirent->commentlen.
     153             :          * The space for the two null bytes was allocated.
     154             :          */
     155        1662 :         strncpy(dirent->name, (name?name:""), dirent->namelen + 1);
     156        1662 :         dirent->comment = (char *)(&dirent->name + dirent->namelen + 1);
     157        1662 :         strncpy(dirent->comment, (comment?comment:""), dirent->commentlen + 1);
     158             : 
     159        1662 :         return 0;
     160             : 
     161             : }
     162             : 
     163        1082 : static int add_dirplus(SMBCFILE *dir, struct file_info *finfo)
     164             : {
     165        1082 :         struct smbc_dirplus_list *new_entry = NULL;
     166        1082 :         struct libsmb_file_info *info = NULL;
     167             : 
     168        1082 :         new_entry = SMB_MALLOC_P(struct smbc_dirplus_list);
     169        1082 :         if (new_entry == NULL) {
     170           0 :                 dir->dir_error = ENOMEM;
     171           0 :                 return -1;
     172             :         }
     173        1082 :         ZERO_STRUCTP(new_entry);
     174        1082 :         new_entry->ino = finfo->ino;
     175             : 
     176        1082 :         info = SMB_MALLOC_P(struct libsmb_file_info);
     177        1082 :         if (info == NULL) {
     178           0 :                 SAFE_FREE(new_entry);
     179           0 :                 dir->dir_error = ENOMEM;
     180           0 :                 return -1;
     181             :         }
     182             : 
     183        1082 :         ZERO_STRUCTP(info);
     184             : 
     185        1082 :         info->btime_ts = finfo->btime_ts;
     186        1082 :         info->atime_ts = finfo->atime_ts;
     187        1082 :         info->ctime_ts = finfo->ctime_ts;
     188        1082 :         info->mtime_ts = finfo->mtime_ts;
     189        1082 :         info->gid = finfo->gid;
     190        1082 :         info->attrs = finfo->attr;
     191        1082 :         info->size = finfo->size;
     192        1082 :         info->uid = finfo->uid;
     193        1082 :         info->name = SMB_STRDUP(finfo->name);
     194        1082 :         if (info->name == NULL) {
     195           0 :                 SAFE_FREE(info);
     196           0 :                 SAFE_FREE(new_entry);
     197           0 :                 dir->dir_error = ENOMEM;
     198           0 :                 return -1;
     199             :         }
     200             : 
     201        1082 :         if (finfo->short_name) {
     202         772 :                 info->short_name = SMB_STRDUP(finfo->short_name);
     203             :         } else {
     204         310 :                 info->short_name = SMB_STRDUP("");
     205             :         }
     206             : 
     207        1082 :         if (info->short_name == NULL) {
     208           0 :                 SAFE_FREE(info->name);
     209           0 :                 SAFE_FREE(info);
     210           0 :                 SAFE_FREE(new_entry);
     211           0 :                 dir->dir_error = ENOMEM;
     212           0 :                 return -1;
     213             :         }
     214        1082 :         new_entry->smb_finfo = info;
     215             : 
     216             :         /* Now add to the list. */
     217        1082 :         if (dir->dirplus_list == NULL) {
     218             :                 /* Empty list - point everything at new_entry. */
     219          42 :                 dir->dirplus_list = new_entry;
     220          42 :                 dir->dirplus_end = new_entry;
     221          42 :                 dir->dirplus_next = new_entry;
     222             :         } else {
     223             :                 /* Append to list but leave the ->next cursor alone. */
     224        1040 :                 dir->dirplus_end->next = new_entry;
     225        1040 :                 dir->dirplus_end = new_entry;
     226             :         }
     227             : 
     228        1082 :         return 0;
     229             : }
     230             : 
     231             : static void
     232           6 : list_unique_wg_fn(const char *name,
     233             :                   uint32_t type,
     234             :                   const char *comment,
     235             :                   void *state)
     236             : {
     237           6 :         SMBCFILE *dir = (SMBCFILE *)state;
     238             :         struct smbc_dir_list *dir_list;
     239             :         struct smbc_dirent *dirent;
     240             :         int dirent_type;
     241           6 :         int do_remove = 0;
     242             : 
     243           6 :         dirent_type = dir->dir_type;
     244             : 
     245           6 :         if (add_dirent(dir, name, comment, dirent_type) < 0) {
     246             :                 /* An error occurred, what do we do? */
     247             :                 /* FIXME: Add some code here */
     248             :                 /* Change cli_NetServerEnum to take a fn
     249             :                    returning NTSTATUS... JRA. */
     250             :         }
     251             : 
     252             :         /* Point to the one just added */
     253           6 :         dirent = dir->dir_end->dirent;
     254             : 
     255             :         /* See if this was a duplicate */
     256          18 :         for (dir_list = dir->dir_list;
     257          12 :              dir_list != dir->dir_end;
     258           6 :              dir_list = dir_list->next) {
     259          12 :                 if (! do_remove &&
     260           6 :                     strcmp(dir_list->dirent->name, dirent->name) == 0) {
     261             :                         /* Duplicate.  End end of list need to be removed. */
     262           0 :                         do_remove = 1;
     263             :                 }
     264             : 
     265           6 :                 if (do_remove && dir_list->next == dir->dir_end) {
     266             :                         /* Found the end of the list.  Remove it. */
     267           0 :                         dir->dir_end = dir_list;
     268           0 :                         free(dir_list->next);
     269           0 :                         free(dirent);
     270           0 :                         dir_list->next = NULL;
     271           0 :                         break;
     272             :                 }
     273             :         }
     274           6 : }
     275             : 
     276             : static void
     277         574 : list_fn(const char *name,
     278             :         uint32_t type,
     279             :         const char *comment,
     280             :         void *state)
     281             : {
     282         574 :         SMBCFILE *dir = (SMBCFILE *)state;
     283             :         int dirent_type;
     284             : 
     285             :         /*
     286             :          * We need to process the type a little ...
     287             :          *
     288             :          * Disk share     = 0x00000000
     289             :          * Print share    = 0x00000001
     290             :          * Comms share    = 0x00000002 (obsolete?)
     291             :          * IPC$ share     = 0x00000003
     292             :          *
     293             :          * administrative shares:
     294             :          * ADMIN$, IPC$, C$, D$, E$ ...  are type |= 0x80000000
     295             :          */
     296             : 
     297         574 :         if (dir->dir_type == SMBC_FILE_SHARE) {
     298         568 :                 switch (type) {
     299         544 :                 case 0 | 0x80000000:
     300             :                 case 0:
     301         544 :                         dirent_type = SMBC_FILE_SHARE;
     302         544 :                         break;
     303             : 
     304          20 :                 case 1:
     305          20 :                         dirent_type = SMBC_PRINTER_SHARE;
     306          20 :                         break;
     307             : 
     308           0 :                 case 2:
     309           0 :                         dirent_type = SMBC_COMMS_SHARE;
     310           0 :                         break;
     311             : 
     312           4 :                 case 3 | 0x80000000:
     313             :                 case 3:
     314           4 :                         dirent_type = SMBC_IPC_SHARE;
     315           4 :                         break;
     316             : 
     317           0 :                 default:
     318           0 :                         dirent_type = SMBC_FILE_SHARE; /* FIXME, error? */
     319           0 :                         break;
     320             :                 }
     321             :         }
     322             :         else {
     323           6 :                 dirent_type = dir->dir_type;
     324             :         }
     325             : 
     326         574 :         if (add_dirent(dir, name, comment, dirent_type) < 0) {
     327             :                 /* An error occurred, what do we do? */
     328             :                 /* FIXME: Add some code here */
     329             :                 /* Change cli_NetServerEnum to take a fn
     330             :                    returning NTSTATUS... JRA. */
     331             :         }
     332         574 : }
     333             : 
     334             : static NTSTATUS
     335        1082 : dir_list_fn(struct file_info *finfo,
     336             :             const char *mask,
     337             :             void *state)
     338             : {
     339        1082 :         SMBCFILE *dirp = (SMBCFILE *)state;
     340             :         int ret;
     341             : 
     342        1082 :         if (add_dirent((SMBCFILE *)state, finfo->name, "",
     343        1082 :                        (finfo->attr&FILE_ATTRIBUTE_DIRECTORY?SMBC_DIR:SMBC_FILE)) < 0) {
     344           0 :                 SMBCFILE *dir = (SMBCFILE *)state;
     345           0 :                 return map_nt_error_from_unix(dir->dir_error);
     346             :         }
     347        1082 :         ret = add_dirplus(dirp, finfo);
     348        1082 :         if (ret < 0) {
     349           0 :                 return map_nt_error_from_unix(dirp->dir_error);
     350             :         }
     351        1082 :         return NT_STATUS_OK;
     352             : }
     353             : 
     354             : static NTSTATUS
     355           4 : net_share_enum_rpc(struct cli_state *cli,
     356             :                    void (*fn)(const char *name,
     357             :                               uint32_t type,
     358             :                               const char *comment,
     359             :                               void *state),
     360             :                    void *state)
     361             : {
     362             :         uint32_t i;
     363             :         WERROR result;
     364           4 :         uint32_t preferred_len = 0xffffffff;
     365             :         uint32_t type;
     366             :         struct srvsvc_NetShareInfoCtr info_ctr;
     367             :         struct srvsvc_NetShareCtr1 ctr1;
     368           4 :         fstring name = "";
     369           4 :         fstring comment = "";
     370           4 :         struct rpc_pipe_client *pipe_hnd = NULL;
     371             :         NTSTATUS nt_status;
     372           4 :         uint32_t resume_handle = 0;
     373           4 :         uint32_t total_entries = 0;
     374             :         struct dcerpc_binding_handle *b;
     375             : 
     376             :         /* Open the server service pipe */
     377           4 :         nt_status = cli_rpc_pipe_open_noauth(cli, &ndr_table_srvsvc,
     378             :                                              &pipe_hnd);
     379           4 :         if (!NT_STATUS_IS_OK(nt_status)) {
     380           0 :                 DEBUG(1, ("net_share_enum_rpc pipe open fail!\n"));
     381           0 :                 goto done;
     382             :         }
     383             : 
     384           4 :         ZERO_STRUCT(info_ctr);
     385           4 :         ZERO_STRUCT(ctr1);
     386             : 
     387           4 :         info_ctr.level = 1;
     388           4 :         info_ctr.ctr.ctr1 = &ctr1;
     389             : 
     390           4 :         b = pipe_hnd->binding_handle;
     391             : 
     392             :         /* Issue the NetShareEnum RPC call and retrieve the response */
     393           4 :         nt_status = dcerpc_srvsvc_NetShareEnumAll(b, talloc_tos(),
     394           4 :                                                   pipe_hnd->desthost,
     395             :                                                   &info_ctr,
     396             :                                                   preferred_len,
     397             :                                                   &total_entries,
     398             :                                                   &resume_handle,
     399             :                                                   &result);
     400             : 
     401             :         /* Was it successful? */
     402           4 :         if (!NT_STATUS_IS_OK(nt_status)) {
     403             :                 /*  Nope.  Go clean up. */
     404           0 :                 goto done;
     405             :         }
     406             : 
     407           4 :         if (!W_ERROR_IS_OK(result)) {
     408             :                 /*  Nope.  Go clean up. */
     409           0 :                 nt_status = werror_to_ntstatus(result);
     410           0 :                 goto done;
     411             :         }
     412             : 
     413           4 :         if (total_entries == 0) {
     414             :                 /*  Nope.  Go clean up. */
     415           0 :                 nt_status = NT_STATUS_NOT_FOUND;
     416           0 :                 goto done;
     417             :         }
     418             : 
     419             :         /* For each returned entry... */
     420         572 :         for (i = 0; i < info_ctr.ctr.ctr1->count; i++) {
     421             : 
     422             :                 /* pull out the share name */
     423         568 :                 fstrcpy(name, info_ctr.ctr.ctr1->array[i].name);
     424             : 
     425             :                 /* pull out the share's comment */
     426         568 :                 fstrcpy(comment, info_ctr.ctr.ctr1->array[i].comment);
     427             : 
     428             :                 /* Get the type value */
     429         568 :                 type = info_ctr.ctr.ctr1->array[i].type;
     430             : 
     431             :                 /* Add this share to the list */
     432         568 :                 (*fn)(name, type, comment, state);
     433             :         }
     434             : 
     435           4 : done:
     436             :         /* Close the server service pipe */
     437           4 :         TALLOC_FREE(pipe_hnd);
     438             : 
     439             :         /* Tell 'em if it worked */
     440           4 :         return nt_status;
     441             : }
     442             : 
     443             : 
     444             : /*
     445             :  * Verify that the options specified in a URL are valid
     446             :  */
     447             : int
     448          62 : SMBC_check_options(char *server,
     449             :                    char *share,
     450             :                    char *path,
     451             :                    char *options)
     452             : {
     453          62 :         DEBUG(4, ("SMBC_check_options(): server='%s' share='%s' "
     454             :                   "path='%s' options='%s'\n",
     455             :                   server, share, path, options));
     456             : 
     457             :         /* No options at all is always ok */
     458          62 :         if (! *options) return 0;
     459             : 
     460             :         /* Currently, we don't support any options. */
     461           0 :         return -1;
     462             : }
     463             : 
     464             : 
     465             : SMBCFILE *
     466         114 : SMBC_opendir_ctx(SMBCCTX *context,
     467             :                  const char *fname)
     468             : {
     469         114 :         char *server = NULL;
     470         114 :         char *share = NULL;
     471         114 :         char *user = NULL;
     472         114 :         char *password = NULL;
     473         114 :         char *options = NULL;
     474         114 :         char *workgroup = NULL;
     475         114 :         char *path = NULL;
     476         114 :         size_t path_len = 0;
     477         114 :         uint16_t port = 0;
     478         114 :         SMBCSRV *srv  = NULL;
     479         114 :         SMBCFILE *dir = NULL;
     480             :         struct sockaddr_storage rem_ss;
     481         114 :         TALLOC_CTX *frame = talloc_stackframe();
     482             : 
     483         114 :         if (!context || !context->internal->initialized) {
     484           0 :                 DEBUG(4, ("no valid context\n"));
     485           0 :                 TALLOC_FREE(frame);
     486           0 :                 errno = EINVAL + 8192;
     487           0 :                 return NULL;
     488             : 
     489             :         }
     490             : 
     491         114 :         if (!fname) {
     492           4 :                 DEBUG(4, ("no valid fname\n"));
     493           4 :                 TALLOC_FREE(frame);
     494           4 :                 errno = EINVAL + 8193;
     495           4 :                 return NULL;
     496             :         }
     497             : 
     498         110 :         if (SMBC_parse_path(frame,
     499             :                             context,
     500             :                             fname,
     501             :                             &workgroup,
     502             :                             &server,
     503             :                             &port,
     504             :                             &share,
     505             :                             &path,
     506             :                             &user,
     507             :                             &password,
     508             :                             &options)) {
     509          48 :                 DEBUG(4, ("no valid path\n"));
     510          48 :                 TALLOC_FREE(frame);
     511          48 :                 errno = EINVAL + 8194;
     512          48 :                 return NULL;
     513             :         }
     514             : 
     515          62 :         DEBUG(4, ("parsed path: fname='%s' server='%s' share='%s' "
     516             :                   "path='%s' options='%s'\n",
     517             :                   fname, server, share, path, options));
     518             : 
     519             :         /* Ensure the options are valid */
     520          62 :         if (SMBC_check_options(server, share, path, options)) {
     521           0 :                 DEBUG(4, ("unacceptable options (%s)\n", options));
     522           0 :                 TALLOC_FREE(frame);
     523           0 :                 errno = EINVAL + 8195;
     524           0 :                 return NULL;
     525             :         }
     526             : 
     527          62 :         if (!user || user[0] == (char)0) {
     528          46 :                 user = talloc_strdup(frame, smbc_getUser(context));
     529          46 :                 if (!user) {
     530           0 :                         TALLOC_FREE(frame);
     531           0 :                         errno = ENOMEM;
     532           0 :                         return NULL;
     533             :                 }
     534             :         }
     535             : 
     536          62 :         dir = SMB_MALLOC_P(SMBCFILE);
     537             : 
     538          62 :         if (!dir) {
     539           0 :                 TALLOC_FREE(frame);
     540           0 :                 errno = ENOMEM;
     541           0 :                 return NULL;
     542             :         }
     543             : 
     544          62 :         ZERO_STRUCTP(dir);
     545             : 
     546          62 :         dir->cli_fd   = 0;
     547          62 :         dir->fname    = SMB_STRDUP(fname);
     548          62 :         if (dir->fname == NULL) {
     549           0 :                 SAFE_FREE(dir);
     550           0 :                 TALLOC_FREE(frame);
     551           0 :                 errno = ENOMEM;
     552           0 :                 return NULL;
     553             :         }
     554          62 :         dir->srv      = NULL;
     555          62 :         dir->offset   = 0;
     556          62 :         dir->file     = False;
     557          62 :         dir->dir_list = dir->dir_next = dir->dir_end = NULL;
     558             : 
     559          62 :         if (server[0] == (char)0) {
     560             : 
     561             :                 size_t i;
     562           4 :                 size_t count = 0;
     563             :                 size_t max_lmb_count;
     564             :                 struct sockaddr_storage *ip_list;
     565             :                 struct sockaddr_storage server_addr;
     566           4 :                 struct cli_credentials *creds = NULL;
     567             :                 NTSTATUS status;
     568             : 
     569           4 :                 if (share[0] != (char)0 || path[0] != (char)0) {
     570             : 
     571           0 :                         if (dir) {
     572           0 :                                 SAFE_FREE(dir->fname);
     573           0 :                                 SAFE_FREE(dir);
     574             :                         }
     575           0 :                         TALLOC_FREE(frame);
     576           0 :                         errno = EINVAL + 8196;
     577           0 :                         return NULL;
     578             :                 }
     579             : 
     580             :                 /* Determine how many local master browsers to query */
     581           8 :                 max_lmb_count = (smbc_getOptionBrowseMaxLmbCount(context) == 0
     582             :                                  ? INT_MAX
     583           4 :                                  : smbc_getOptionBrowseMaxLmbCount(context));
     584             : 
     585           4 :                 creds = cli_credentials_init(frame);
     586           4 :                 if (creds == NULL) {
     587           0 :                         if (dir) {
     588           0 :                                 SAFE_FREE(dir->fname);
     589           0 :                                 SAFE_FREE(dir);
     590             :                         }
     591           0 :                         TALLOC_FREE(frame);
     592           0 :                         errno = ENOMEM;
     593           0 :                         return NULL;
     594             :                 }
     595             : 
     596           4 :                 (void)cli_credentials_set_username(creds, user, CRED_SPECIFIED);
     597           4 :                 (void)cli_credentials_set_password(creds, password, CRED_SPECIFIED);
     598             : 
     599             :                 /*
     600             :                  * We have server and share and path empty but options
     601             :                  * requesting that we scan all master browsers for their list
     602             :                  * of workgroups/domains.  This implies that we must first try
     603             :                  * broadcast queries to find all master browsers, and if that
     604             :                  * doesn't work, then try our other methods which return only
     605             :                  * a single master browser.
     606             :                  */
     607             : 
     608           4 :                 ip_list = NULL;
     609           4 :                 status = name_resolve_bcast(talloc_tos(),
     610             :                                             MSBROWSE,
     611             :                                             1,
     612             :                                             &ip_list,
     613             :                                             &count);
     614           4 :                 if (!NT_STATUS_IS_OK(status))
     615             :                 {
     616             : 
     617           0 :                         TALLOC_FREE(ip_list);
     618             : 
     619           0 :                         if (!find_master_ip(workgroup, &server_addr)) {
     620             : 
     621           0 :                                 if (dir) {
     622           0 :                                         SAFE_FREE(dir->fname);
     623           0 :                                         SAFE_FREE(dir);
     624             :                                 }
     625           0 :                                 TALLOC_FREE(frame);
     626           0 :                                 errno = ENOENT;
     627           0 :                                 return NULL;
     628             :                         }
     629             : 
     630           0 :                         ip_list = (struct sockaddr_storage *)talloc_memdup(
     631             :                                 talloc_tos(), &server_addr,
     632             :                                 sizeof(server_addr));
     633           0 :                         if (ip_list == NULL) {
     634           0 :                                 if (dir) {
     635           0 :                                         SAFE_FREE(dir->fname);
     636           0 :                                         SAFE_FREE(dir);
     637             :                                 }
     638           0 :                                 TALLOC_FREE(frame);
     639           0 :                                 errno = ENOMEM;
     640           0 :                                 return NULL;
     641             :                         }
     642           0 :                         count = 1;
     643             :                 }
     644             : 
     645          16 :                 for (i = 0; i < count && i < max_lmb_count; i++) {
     646             :                         char addr[INET6_ADDRSTRLEN];
     647          12 :                         char *wg_ptr = NULL;
     648          12 :                         struct cli_state *cli = NULL;
     649             : 
     650          12 :                         print_sockaddr(addr, sizeof(addr), &ip_list[i]);
     651          12 :                         DEBUG(99, ("Found master browser %zu of %zu: %s\n",
     652             :                                    i+1, MAX(count, max_lmb_count),
     653             :                                    addr));
     654             : 
     655          24 :                         cli = get_ipc_connect_master_ip(talloc_tos(),
     656          12 :                                                         &ip_list[i],
     657             :                                                         creds,
     658             :                                                         &wg_ptr);
     659             :                         /* cli == NULL is the master browser refused to talk or
     660             :                            could not be found */
     661          12 :                         if (!cli) {
     662          18 :                                 continue;
     663             :                         }
     664             : 
     665           4 :                         workgroup = talloc_strdup(frame, wg_ptr);
     666           4 :                         server = talloc_strdup(frame, smbXcli_conn_remote_name(cli->conn));
     667             : 
     668           4 :                         cli_shutdown(cli);
     669             : 
     670           4 :                         if (!workgroup || !server) {
     671           0 :                                 if (dir) {
     672           0 :                                         SAFE_FREE(dir->fname);
     673           0 :                                         SAFE_FREE(dir);
     674             :                                 }
     675           0 :                                 TALLOC_FREE(frame);
     676           0 :                                 errno = ENOMEM;
     677           0 :                                 return NULL;
     678             :                         }
     679             : 
     680           4 :                         DEBUG(4, ("using workgroup %s %s\n",
     681             :                                   workgroup, server));
     682             : 
     683             :                         /*
     684             :                          * For each returned master browser IP address, get a
     685             :                          * connection to IPC$ on the server if we do not
     686             :                          * already have one, and determine the
     687             :                          * workgroups/domains that it knows about.
     688             :                          */
     689             : 
     690           4 :                         srv = SMBC_server(frame, context, True, server, port, "IPC$",
     691             :                                           &workgroup, &user, &password);
     692           4 :                         if (!srv) {
     693           0 :                                 continue;
     694             :                         }
     695             : 
     696           4 :                         if (smbXcli_conn_protocol(srv->cli->conn) > PROTOCOL_NT1) {
     697           2 :                                 continue;
     698             :                         }
     699             : 
     700           2 :                         dir->srv = srv;
     701           2 :                         dir->dir_type = SMBC_WORKGROUP;
     702             : 
     703             :                         /* Now, list the stuff ... */
     704             : 
     705           2 :                         if (!cli_NetServerEnum(srv->cli,
     706             :                                                workgroup,
     707             :                                                SV_TYPE_DOMAIN_ENUM,
     708             :                                                list_unique_wg_fn,
     709             :                                                (void *)dir)) {
     710           0 :                                 continue;
     711             :                         }
     712             :                 }
     713             : 
     714           4 :                 TALLOC_FREE(ip_list);
     715             :         } else {
     716             :                 /*
     717             :                  * Server not an empty string ... Check the rest and see what
     718             :                  * gives
     719             :                  */
     720          58 :                 if (*share == '\0') {
     721          16 :                         if (*path != '\0') {
     722             : 
     723             :                                 /* Should not have empty share with path */
     724           0 :                                 if (dir) {
     725           0 :                                         SAFE_FREE(dir->fname);
     726           0 :                                         SAFE_FREE(dir);
     727             :                                 }
     728           0 :                                 TALLOC_FREE(frame);
     729           0 :                                 errno = EINVAL + 8197;
     730           0 :                                 return NULL;
     731             : 
     732             :                         }
     733             : 
     734             :                         /*
     735             :                          * We don't know if <server> is really a server name
     736             :                          * or is a workgroup/domain name.  If we already have
     737             :                          * a server structure for it, we'll use it.
     738             :                          * Otherwise, check to see if <server><1D>,
     739             :                          * <server><1B>, or <server><20> translates.  We check
     740             :                          * to see if <server> is an IP address first.
     741             :                          */
     742             : 
     743             :                         /*
     744             :                          * See if we have an existing server.  Do not
     745             :                          * establish a connection if one does not already
     746             :                          * exist.
     747             :                          */
     748          16 :                         srv = SMBC_server(frame, context, False,
     749             :                                           server, port, "IPC$",
     750             :                                           &workgroup, &user, &password);
     751             : 
     752             :                         /*
     753             :                          * If no existing server and not an IP addr, look for
     754             :                          * LMB or DMB
     755             :                          */
     756          32 :                         if (!srv &&
     757          32 :                             !is_ipaddress(server) &&
     758          20 :                             (resolve_name(server, &rem_ss, 0x1d, false) ||   /* LMB */
     759           6 :                              resolve_name(server, &rem_ss, 0x1b, false) )) { /* DMB */
     760             :                                 /*
     761             :                                  * "server" is actually a workgroup name,
     762             :                                  * not a server. Make this clear.
     763             :                                  */
     764          12 :                                 char *wgroup = server;
     765             :                                 fstring buserver;
     766             : 
     767          12 :                                 dir->dir_type = SMBC_SERVER;
     768             : 
     769             :                                 /*
     770             :                                  * Get the backup list ...
     771             :                                  */
     772          12 :                                 if (!name_status_find(wgroup, 0, 0,
     773             :                                                       &rem_ss, buserver)) {
     774             :                                         char addr[INET6_ADDRSTRLEN];
     775             : 
     776           0 :                                         print_sockaddr(addr, sizeof(addr), &rem_ss);
     777           0 :                                         DEBUG(0,("Could not get name of "
     778             :                                                 "local/domain master browser "
     779             :                                                 "for workgroup %s from "
     780             :                                                 "address %s\n",
     781             :                                                 wgroup,
     782             :                                                 addr));
     783           0 :                                         if (dir) {
     784           0 :                                                 SAFE_FREE(dir->fname);
     785           0 :                                                 SAFE_FREE(dir);
     786             :                                         }
     787           0 :                                         TALLOC_FREE(frame);
     788           0 :                                         errno = EPERM;
     789           0 :                                         return NULL;
     790             : 
     791             :                                 }
     792             : 
     793             :                                 /*
     794             :                                  * Get a connection to IPC$ on the server if
     795             :                                  * we do not already have one
     796             :                                  */
     797          12 :                                 srv = SMBC_server(frame, context, True,
     798             :                                                   buserver, port, "IPC$",
     799             :                                                   &workgroup,
     800             :                                                   &user, &password);
     801          12 :                                 if (!srv) {
     802           4 :                                         DEBUG(0, ("got no contact to IPC$\n"));
     803           4 :                                         if (dir) {
     804           4 :                                                 SAFE_FREE(dir->fname);
     805           4 :                                                 SAFE_FREE(dir);
     806             :                                         }
     807           4 :                                         TALLOC_FREE(frame);
     808           4 :                                         return NULL;
     809             : 
     810             :                                 }
     811             : 
     812           8 :                                 dir->srv = srv;
     813             : 
     814           8 :                                 if (smbXcli_conn_protocol(srv->cli->conn) > PROTOCOL_NT1) {
     815           6 :                                         if (dir) {
     816           6 :                                                 SAFE_FREE(dir->fname);
     817           6 :                                                 SAFE_FREE(dir);
     818             :                                         }
     819           6 :                                         TALLOC_FREE(frame);
     820           6 :                                         return NULL;
     821             :                                 }
     822             : 
     823             :                                 /* Now, list the servers ... */
     824           2 :                                 if (!cli_NetServerEnum(srv->cli, wgroup,
     825             :                                                        0x0000FFFE, list_fn,
     826             :                                                        (void *)dir)) {
     827             : 
     828           0 :                                         if (dir) {
     829           0 :                                                 SAFE_FREE(dir->fname);
     830           0 :                                                 SAFE_FREE(dir);
     831             :                                         }
     832           0 :                                         TALLOC_FREE(frame);
     833           0 :                                         return NULL;
     834             :                                 }
     835           8 :                         } else if (srv ||
     836           8 :                                    (resolve_name(server, &rem_ss, 0x20, false))) {
     837             :                                 NTSTATUS status;
     838             : 
     839             :                                 /*
     840             :                                  * If we hadn't found the server, get one now
     841             :                                  */
     842           4 :                                 if (!srv) {
     843           4 :                                         srv = SMBC_server(frame, context, True,
     844             :                                                           server, port, "IPC$",
     845             :                                                           &workgroup,
     846             :                                                           &user, &password);
     847             :                                 }
     848             : 
     849           4 :                                 if (!srv) {
     850           0 :                                         if (dir) {
     851           0 :                                                 SAFE_FREE(dir->fname);
     852           0 :                                                 SAFE_FREE(dir);
     853             :                                         }
     854           0 :                                         TALLOC_FREE(frame);
     855           0 :                                         return NULL;
     856             : 
     857             :                                 }
     858             : 
     859           4 :                                 dir->dir_type = SMBC_FILE_SHARE;
     860           4 :                                 dir->srv = srv;
     861             : 
     862             :                                 /* List the shares ... */
     863             : 
     864           4 :                                 status = net_share_enum_rpc(srv->cli,
     865             :                                                         list_fn,
     866             :                                                         (void *)dir);
     867           4 :                                 if (!NT_STATUS_IS_OK(status) &&
     868           0 :                                     smbXcli_conn_protocol(srv->cli->conn) <=
     869             :                                                 PROTOCOL_NT1) {
     870             :                                         /*
     871             :                                          * Only call cli_RNetShareEnum()
     872             :                                          * on SMB1 connections, not SMB2+.
     873             :                                          */
     874           0 :                                         int rc = cli_RNetShareEnum(srv->cli,
     875             :                                                                list_fn,
     876             :                                                                (void *)dir);
     877           0 :                                         if (rc != 0) {
     878           0 :                                                 status = cli_nt_error(srv->cli);
     879             :                                         } else {
     880           0 :                                                 status = NT_STATUS_OK;
     881             :                                         }
     882             :                                 }
     883           4 :                                 if (!NT_STATUS_IS_OK(status)) {
     884             :                                         /*
     885             :                                          * Set cli->raw_status so SMBC_errno()
     886             :                                          * will correctly return the error.
     887             :                                          */
     888           0 :                                         srv->cli->raw_status = status;
     889           0 :                                         if (dir != NULL) {
     890           0 :                                                 SAFE_FREE(dir->fname);
     891           0 :                                                 SAFE_FREE(dir);
     892             :                                         }
     893           0 :                                         TALLOC_FREE(frame);
     894           0 :                                         errno = map_errno_from_nt_status(
     895             :                                                                 status);
     896           0 :                                         return NULL;
     897             :                                 }
     898             :                         } else {
     899             :                                 /* Neither the workgroup nor server exists */
     900           0 :                                 errno = ECONNREFUSED;
     901           0 :                                 if (dir) {
     902           0 :                                         SAFE_FREE(dir->fname);
     903           0 :                                         SAFE_FREE(dir);
     904             :                                 }
     905           0 :                                 TALLOC_FREE(frame);
     906           0 :                                 return NULL;
     907             :                         }
     908             : 
     909             :                 }
     910             :                 else {
     911             :                         /*
     912             :                          * The server and share are specified ... work from
     913             :                          * there ...
     914             :                          */
     915             :                         char *targetpath;
     916             :                         struct cli_state *targetcli;
     917          42 :                         struct cli_credentials *creds = NULL;
     918             :                         NTSTATUS status;
     919             : 
     920             :                         /* We connect to the server and list the directory */
     921          42 :                         dir->dir_type = SMBC_FILE_SHARE;
     922             : 
     923          42 :                         srv = SMBC_server(frame, context, True, server, port, share,
     924             :                                           &workgroup, &user, &password);
     925             : 
     926          42 :                         if (!srv) {
     927           0 :                                 if (dir) {
     928           0 :                                         SAFE_FREE(dir->fname);
     929           0 :                                         SAFE_FREE(dir);
     930             :                                 }
     931           0 :                                 TALLOC_FREE(frame);
     932           0 :                                 return NULL;
     933             :                         }
     934             : 
     935          42 :                         dir->srv = srv;
     936             : 
     937             :                         /* Now, list the files ... */
     938             : 
     939          42 :                         path_len = strlen(path);
     940          42 :                         path = talloc_asprintf_append(path, "\\*");
     941          42 :                         if (!path) {
     942           0 :                                 if (dir) {
     943           0 :                                         SAFE_FREE(dir->fname);
     944           0 :                                         SAFE_FREE(dir);
     945             :                                 }
     946           0 :                                 TALLOC_FREE(frame);
     947           0 :                                 return NULL;
     948             :                         }
     949             : 
     950          42 :                         creds = context->internal->creds;
     951             : 
     952          42 :                         status = cli_resolve_path(
     953             :                                 frame, "",
     954             :                                 creds,
     955             :                                 srv->cli, path, &targetcli, &targetpath);
     956          42 :                         if (!NT_STATUS_IS_OK(status)) {
     957           0 :                                 d_printf("Could not resolve %s\n", path);
     958           0 :                                 if (dir) {
     959           0 :                                         SAFE_FREE(dir->fname);
     960           0 :                                         SAFE_FREE(dir);
     961             :                                 }
     962           0 :                                 TALLOC_FREE(frame);
     963           0 :                                 return NULL;
     964             :                         }
     965             : 
     966          42 :                         status = cli_list(targetcli, targetpath,
     967             :                                           FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN,
     968             :                                           dir_list_fn, (void *)dir);
     969          42 :                         if (!NT_STATUS_IS_OK(status)) {
     970             :                                 int saved_errno;
     971           0 :                                 if (dir) {
     972           0 :                                         SAFE_FREE(dir->fname);
     973           0 :                                         SAFE_FREE(dir);
     974             :                                 }
     975           0 :                                 saved_errno = SMBC_errno(context, targetcli);
     976             : 
     977           0 :                                 if (saved_errno == EINVAL) {
     978           0 :                                         struct stat sb = {0};
     979             :                                         /*
     980             :                                          * See if they asked to opendir
     981             :                                          * something other than a directory.
     982             :                                          * If so, the converted error value we
     983             :                                          * got would have been EINVAL rather
     984             :                                          * than ENOTDIR.
     985             :                                          */
     986           0 :                                         path[path_len] = '\0'; /* restore original path */
     987             : 
     988           0 :                                         if (SMBC_getatr(context,
     989             :                                                         srv,
     990             :                                                         path,
     991           0 :                                                         &sb) &&
     992           0 :                                             !S_ISDIR(sb.st_mode)) {
     993             : 
     994             :                                                 /* It is.  Correct the error value */
     995           0 :                                                 saved_errno = ENOTDIR;
     996             :                                         }
     997             :                                 }
     998             : 
     999             :                                 /*
    1000             :                                  * If there was an error and the server is no
    1001             :                                  * good any more...
    1002             :                                  */
    1003           0 :                                 if (cli_is_error(targetcli) &&
    1004           0 :                                     smbc_getFunctionCheckServer(context)(context, srv)) {
    1005             : 
    1006             :                                         /* ... then remove it. */
    1007           0 :                                         if (smbc_getFunctionRemoveUnusedServer(context)(context,
    1008             :                                                                                         srv)) {
    1009             :                                                 /*
    1010             :                                                  * We could not remove the
    1011             :                                                  * server completely, remove
    1012             :                                                  * it from the cache so we
    1013             :                                                  * will not get it again. It
    1014             :                                                  * will be removed when the
    1015             :                                                  * last file/dir is closed.
    1016             :                                                  */
    1017           0 :                                                 smbc_getFunctionRemoveCachedServer(context)(context, srv);
    1018             :                                         }
    1019             :                                 }
    1020             : 
    1021           0 :                                 TALLOC_FREE(frame);
    1022           0 :                                 errno = saved_errno;
    1023           0 :                                 return NULL;
    1024             :                         }
    1025             :                 }
    1026             : 
    1027             :         }
    1028             : 
    1029          52 :         DLIST_ADD(context->internal->files, dir);
    1030          52 :         TALLOC_FREE(frame);
    1031          52 :         return dir;
    1032             : 
    1033             : }
    1034             : 
    1035             : /*
    1036             :  * Routine to close a directory
    1037             :  */
    1038             : 
    1039             : int
    1040          52 : SMBC_closedir_ctx(SMBCCTX *context,
    1041             :                   SMBCFILE *dir)
    1042             : {
    1043          52 :         TALLOC_CTX *frame = NULL;
    1044             : 
    1045          52 :         if (!context || !context->internal->initialized) {
    1046           0 :                 errno = EINVAL;
    1047           0 :                 return -1;
    1048             :         }
    1049             : 
    1050          52 :         if (dir == NULL) {
    1051           0 :                 return 0;
    1052             :         }
    1053             : 
    1054          52 :         frame = talloc_stackframe();
    1055             : 
    1056          52 :         if (!SMBC_dlist_contains(context->internal->files, dir)) {
    1057           0 :                 errno = EBADF;
    1058           0 :                 TALLOC_FREE(frame);
    1059           0 :                 return -1;
    1060             :         }
    1061             : 
    1062          52 :         remove_dir(dir); /* Clean it up */
    1063          52 :         remove_dirplus(dir);
    1064             : 
    1065          52 :         DLIST_REMOVE(context->internal->files, dir);
    1066             : 
    1067          52 :         SAFE_FREE(dir->fname);
    1068          52 :         SAFE_FREE(dir);    /* Free the space too */
    1069             : 
    1070          52 :         TALLOC_FREE(frame);
    1071          52 :         return 0;
    1072             : 
    1073             : }
    1074             : 
    1075             : static int
    1076         834 : smbc_readdir_internal(SMBCCTX * context,
    1077             :                       struct smbc_dirent *dest,
    1078             :                       struct smbc_dirent *src,
    1079             :                       int max_namebuf_len)
    1080             : {
    1081         834 :         if (smbc_getOptionUrlEncodeReaddirEntries(context)) {
    1082             :                 int remaining_len;
    1083             : 
    1084             :                 /* url-encode the name.  get back remaining buffer space */
    1085           0 :                 remaining_len =
    1086           0 :                         smbc_urlencode(dest->name, src->name, max_namebuf_len);
    1087             : 
    1088             :                 /* -1 means no null termination. */
    1089           0 :                 if (remaining_len < 0) {
    1090           0 :                         return -1;
    1091             :                 }
    1092             : 
    1093             :                 /* We now know the name length */
    1094           0 :                 dest->namelen = strlen(dest->name);
    1095             : 
    1096           0 :                 if (dest->namelen + 1 < 1) {
    1097             :                         /* Integer wrap. */
    1098           0 :                         return -1;
    1099             :                 }
    1100             : 
    1101           0 :                 if (dest->namelen + 1 >= max_namebuf_len) {
    1102             :                         /* Out of space for comment. */
    1103           0 :                         return -1;
    1104             :                 }
    1105             : 
    1106             :                 /* Save the pointer to the beginning of the comment */
    1107           0 :                 dest->comment = dest->name + dest->namelen + 1;
    1108             : 
    1109           0 :                 if (remaining_len < 1) {
    1110             :                         /* No room for comment null termination. */
    1111           0 :                         return -1;
    1112             :                 }
    1113             : 
    1114             :                 /* Copy the comment */
    1115           0 :                 strlcpy(dest->comment, src->comment, remaining_len);
    1116             : 
    1117             :                 /* Save other fields */
    1118           0 :                 dest->smbc_type = src->smbc_type;
    1119           0 :                 dest->commentlen = strlen(dest->comment);
    1120           0 :                 dest->dirlen = ((dest->comment + dest->commentlen + 1) -
    1121             :                                 (char *) dest);
    1122             :         } else {
    1123             : 
    1124             :                 /* No encoding.  Just copy the entry as is. */
    1125         834 :                 if (src->dirlen > max_namebuf_len) {
    1126           0 :                         return -1;
    1127             :                 }
    1128         834 :                 memcpy(dest, src, src->dirlen);
    1129         834 :                 if (src->namelen + 1 < 1) {
    1130             :                         /* Integer wrap */
    1131           0 :                         return -1;
    1132             :                 }
    1133         834 :                 if (src->namelen + 1 >= max_namebuf_len) {
    1134             :                         /* Comment off the end. */
    1135           0 :                         return -1;
    1136             :                 }
    1137         834 :                 dest->comment = (char *)(&dest->name + src->namelen + 1);
    1138             :         }
    1139         834 :         return 0;
    1140             : }
    1141             : 
    1142             : /*
    1143             :  * Routine to get a directory entry
    1144             :  */
    1145             : 
    1146             : struct smbc_dirent *
    1147         708 : SMBC_readdir_ctx(SMBCCTX *context,
    1148             :                  SMBCFILE *dir)
    1149             : {
    1150             :         int maxlen;
    1151             :         int ret;
    1152             :         struct smbc_dirent *dirp, *dirent;
    1153         708 :         TALLOC_CTX *frame = talloc_stackframe();
    1154             : 
    1155             :         /* Check that all is ok first ... */
    1156             : 
    1157         708 :         if (!context || !context->internal->initialized) {
    1158             : 
    1159           0 :                 errno = EINVAL;
    1160           0 :                 DEBUG(0, ("Invalid context in SMBC_readdir_ctx()\n"));
    1161           0 :                 TALLOC_FREE(frame);
    1162           0 :                 return NULL;
    1163             : 
    1164             :         }
    1165             : 
    1166         708 :         if (!SMBC_dlist_contains(context->internal->files, dir)) {
    1167             : 
    1168           0 :                 errno = EBADF;
    1169           0 :                 DEBUG(0, ("Invalid dir in SMBC_readdir_ctx()\n"));
    1170           0 :                 TALLOC_FREE(frame);
    1171           0 :                 return NULL;
    1172             : 
    1173             :         }
    1174             : 
    1175         708 :         if (dir->file != False) { /* FIXME, should be dir, perhaps */
    1176             : 
    1177           0 :                 errno = ENOTDIR;
    1178           0 :                 DEBUG(0, ("Found file vs directory in SMBC_readdir_ctx()\n"));
    1179           0 :                 TALLOC_FREE(frame);
    1180           0 :                 return NULL;
    1181             : 
    1182             :         }
    1183             : 
    1184         708 :         if (!dir->dir_next) {
    1185          34 :                 TALLOC_FREE(frame);
    1186          34 :                 return NULL;
    1187             :         }
    1188             : 
    1189         674 :         dirent = dir->dir_next->dirent;
    1190         674 :         if (!dirent) {
    1191             : 
    1192           0 :                 errno = ENOENT;
    1193           0 :                 TALLOC_FREE(frame);
    1194           0 :                 return NULL;
    1195             : 
    1196             :         }
    1197             : 
    1198         674 :         dirp = &context->internal->dirent;
    1199         674 :         maxlen = sizeof(context->internal->_dirent_name);
    1200             : 
    1201         674 :         ret = smbc_readdir_internal(context, dirp, dirent, maxlen);
    1202         674 :         if (ret == -1) {
    1203           0 :                 errno = EINVAL;
    1204           0 :                 TALLOC_FREE(frame);
    1205           0 :                 return NULL;
    1206             :         }
    1207             : 
    1208         674 :         dir->dir_next = dir->dir_next->next;
    1209             : 
    1210             :         /*
    1211             :          * If we are returning file entries, we
    1212             :          * have a duplicate list in dirplus.
    1213             :          *
    1214             :          * Update dirplus_next also so readdir and
    1215             :          * readdirplus are kept in sync.
    1216             :          */
    1217         674 :         if (dir->dirplus_list != NULL) {
    1218         106 :                 dir->dirplus_next = dir->dirplus_next->next;
    1219             :         }
    1220             : 
    1221         674 :         TALLOC_FREE(frame);
    1222         674 :         return dirp;
    1223             : }
    1224             : 
    1225             : /*
    1226             :  * Routine to get a directory entry with all attributes
    1227             :  */
    1228             : 
    1229             : const struct libsmb_file_info *
    1230         902 : SMBC_readdirplus_ctx(SMBCCTX *context,
    1231             :                      SMBCFILE *dir)
    1232             : {
    1233         902 :         struct libsmb_file_info *smb_finfo = NULL;
    1234         902 :         TALLOC_CTX *frame = talloc_stackframe();
    1235             : 
    1236             :         /* Check that all is ok first ... */
    1237             : 
    1238         902 :         if (context == NULL || !context->internal->initialized) {
    1239           0 :                 DBG_ERR("Invalid context in SMBC_readdirplus_ctx()\n");
    1240           0 :                 TALLOC_FREE(frame);
    1241           0 :                 errno = EINVAL;
    1242           0 :                 return NULL;
    1243             :         }
    1244             : 
    1245         902 :         if (!SMBC_dlist_contains(context->internal->files, dir)) {
    1246           0 :                 DBG_ERR("Invalid dir in SMBC_readdirplus_ctx()\n");
    1247           0 :                 TALLOC_FREE(frame);
    1248           0 :                 errno = EBADF;
    1249           0 :                 return NULL;
    1250             :         }
    1251             : 
    1252         902 :         if (dir->dirplus_next == NULL) {
    1253           0 :                 TALLOC_FREE(frame);
    1254           0 :                 return NULL;
    1255             :         }
    1256             : 
    1257         902 :         smb_finfo = dir->dirplus_next->smb_finfo;
    1258         902 :         if (smb_finfo == NULL) {
    1259           0 :                 TALLOC_FREE(frame);
    1260           0 :                 errno = ENOENT;
    1261           0 :                 return NULL;
    1262             :         }
    1263         902 :         dir->dirplus_next = dir->dirplus_next->next;
    1264             : 
    1265             :         /*
    1266             :          * If we are returning file entries, we
    1267             :          * have a duplicate list in dir_list
    1268             :          *
    1269             :          * Update dir_next also so readdir and
    1270             :          * readdirplus are kept in sync.
    1271             :          */
    1272         902 :         if (dir->dir_list) {
    1273         902 :                 dir->dir_next = dir->dir_next->next;
    1274             :         }
    1275             : 
    1276         902 :         TALLOC_FREE(frame);
    1277         902 :         return smb_finfo;
    1278             : }
    1279             : 
    1280             : /*
    1281             :  * Routine to get a directory entry plus a filled in stat structure if
    1282             :  * requested.
    1283             :  */
    1284             : 
    1285         290 : const struct libsmb_file_info *SMBC_readdirplus2_ctx(SMBCCTX *context,
    1286             :                         SMBCFILE *dir,
    1287             :                         struct stat *st)
    1288             : {
    1289         290 :         struct libsmb_file_info *smb_finfo = NULL;
    1290         290 :         struct smbc_dirplus_list *dp_list = NULL;
    1291             :         ino_t ino;
    1292         290 :         char *full_pathname = NULL;
    1293         290 :         char *workgroup = NULL;
    1294         290 :         char *server = NULL;
    1295         290 :         uint16_t port = 0;
    1296         290 :         char *share = NULL;
    1297         290 :         char *path = NULL;
    1298         290 :         char *user = NULL;
    1299         290 :         char *password = NULL;
    1300         290 :         char *options = NULL;
    1301             :         int rc;
    1302         290 :         TALLOC_CTX *frame = NULL;
    1303             : 
    1304             :         /*
    1305             :          * Allow caller to pass in NULL for stat pointer if
    1306             :          * required. This makes this call identical to
    1307             :          * smbc_readdirplus().
    1308             :          */
    1309             : 
    1310         290 :         if (st == NULL) {
    1311           0 :                 return SMBC_readdirplus_ctx(context, dir);
    1312             :         }
    1313             : 
    1314         290 :         frame = talloc_stackframe();
    1315             : 
    1316             :         /* Check that all is ok first ... */
    1317         290 :         if (context == NULL || !context->internal->initialized) {
    1318           0 :                 DBG_ERR("Invalid context in SMBC_readdirplus2_ctx()\n");
    1319           0 :                 TALLOC_FREE(frame);
    1320           0 :                 errno = EINVAL;
    1321           0 :                 return NULL;
    1322             :         }
    1323             : 
    1324         290 :         if (!SMBC_dlist_contains(context->internal->files, dir)) {
    1325           0 :                 DBG_ERR("Invalid dir in SMBC_readdirplus2_ctx()\n");
    1326           0 :                 TALLOC_FREE(frame);
    1327           0 :                 errno = EBADF;
    1328           0 :                 return NULL;
    1329             :         }
    1330             : 
    1331         290 :         dp_list = dir->dirplus_next;
    1332         290 :         if (dp_list == NULL) {
    1333           0 :                 TALLOC_FREE(frame);
    1334           0 :                 return NULL;
    1335             :         }
    1336             : 
    1337         290 :         ino = (ino_t)dp_list->ino;
    1338             : 
    1339         290 :         smb_finfo = dp_list->smb_finfo;
    1340         290 :         if (smb_finfo == NULL) {
    1341           0 :                 TALLOC_FREE(frame);
    1342           0 :                 errno = ENOENT;
    1343           0 :                 return NULL;
    1344             :         }
    1345             : 
    1346         290 :         full_pathname = talloc_asprintf(frame,
    1347             :                                 "%s/%s",
    1348             :                                 dir->fname,
    1349             :                                 smb_finfo->name);
    1350         290 :         if (full_pathname == NULL) {
    1351           0 :                 TALLOC_FREE(frame);
    1352           0 :                 errno = ENOENT;
    1353           0 :                 return NULL;
    1354             :         }
    1355             : 
    1356         290 :         rc = SMBC_parse_path(frame,
    1357             :                              context,
    1358             :                              full_pathname,
    1359             :                              &workgroup,
    1360             :                              &server,
    1361             :                              &port,
    1362             :                              &share,
    1363             :                              &path,
    1364             :                              &user,
    1365             :                              &password,
    1366             :                              &options);
    1367         290 :         if (rc != 0) {
    1368           0 :                 TALLOC_FREE(frame);
    1369           0 :                 errno = ENOENT;
    1370           0 :                 return NULL;
    1371             :         }
    1372             : 
    1373         870 :         setup_stat(st,
    1374             :                 path,
    1375         290 :                 smb_finfo->size,
    1376         290 :                 smb_finfo->attrs,
    1377             :                 ino,
    1378         290 :                 dir->srv->dev,
    1379             :                 smb_finfo->atime_ts,
    1380             :                 smb_finfo->ctime_ts,
    1381             :                 smb_finfo->mtime_ts);
    1382             : 
    1383         290 :         TALLOC_FREE(full_pathname);
    1384             : 
    1385         290 :         dir->dirplus_next = dir->dirplus_next->next;
    1386             : 
    1387             :         /*
    1388             :          * If we are returning file entries, we
    1389             :          * have a duplicate list in dir_list
    1390             :          *
    1391             :          * Update dir_next also so readdir and
    1392             :          * readdirplus are kept in sync.
    1393             :          */
    1394         290 :         if (dir->dir_list) {
    1395         290 :                 dir->dir_next = dir->dir_next->next;
    1396             :         }
    1397             : 
    1398         290 :         TALLOC_FREE(frame);
    1399         290 :         return smb_finfo;
    1400             : }
    1401             : 
    1402             : /*
    1403             :  * Routine to get directory entries
    1404             :  */
    1405             : 
    1406             : int
    1407           8 : SMBC_getdents_ctx(SMBCCTX *context,
    1408             :                   SMBCFILE *dir,
    1409             :                   struct smbc_dirent *dirp,
    1410             :                   int count)
    1411             : {
    1412           8 :         int rem = count;
    1413             :         int reqd;
    1414             :         int maxlen;
    1415           8 :         char *ndir = (char *)dirp;
    1416             :         struct smbc_dir_list *dirlist;
    1417           8 :         TALLOC_CTX *frame = talloc_stackframe();
    1418             : 
    1419             :         /* Check that all is ok first ... */
    1420             : 
    1421           8 :         if (!context || !context->internal->initialized) {
    1422             : 
    1423           0 :                 errno = EINVAL;
    1424           0 :                 TALLOC_FREE(frame);
    1425           0 :                 return -1;
    1426             : 
    1427             :         }
    1428             : 
    1429           8 :         if (!SMBC_dlist_contains(context->internal->files, dir)) {
    1430             : 
    1431           0 :                 errno = EBADF;
    1432           0 :                 TALLOC_FREE(frame);
    1433           0 :                 return -1;
    1434             : 
    1435             :         }
    1436             : 
    1437           8 :         if (dir->file != False) { /* FIXME, should be dir, perhaps */
    1438             : 
    1439           0 :                 errno = ENOTDIR;
    1440           0 :                 TALLOC_FREE(frame);
    1441           0 :                 return -1;
    1442             : 
    1443             :         }
    1444             : 
    1445             :         /*
    1446             :          * Now, retrieve the number of entries that will fit in what was passed
    1447             :          * We have to figure out if the info is in the list, or we need to
    1448             :          * send a request to the server to get the info.
    1449             :          */
    1450             : 
    1451         168 :         while ((dirlist = dir->dir_next)) {
    1452             :                 int ret;
    1453             :                 struct smbc_dirent *dirent;
    1454         160 :                 struct smbc_dirent *currentEntry = (struct smbc_dirent *)ndir;
    1455             : 
    1456         160 :                 if (!dirlist->dirent) {
    1457             : 
    1458           0 :                         errno = ENOENT;  /* Bad error */
    1459           0 :                         TALLOC_FREE(frame);
    1460           0 :                         return -1;
    1461             : 
    1462             :                 }
    1463             : 
    1464             :                 /* Do urlencoding of next entry, if so selected */
    1465         160 :                 dirent = &context->internal->dirent;
    1466         160 :                 maxlen = sizeof(context->internal->_dirent_name);
    1467         160 :                 ret = smbc_readdir_internal(context, dirent,
    1468             :                                       dirlist->dirent, maxlen);
    1469         160 :                 if (ret == -1) {
    1470           0 :                         errno = EINVAL;
    1471           0 :                         TALLOC_FREE(frame);
    1472           0 :                         return -1;
    1473             :                 }
    1474             : 
    1475         160 :                 reqd = dirent->dirlen;
    1476             : 
    1477         160 :                 if (rem < reqd) {
    1478             : 
    1479           8 :                         if (rem < count) { /* We managed to copy something */
    1480             : 
    1481           8 :                                 errno = 0;
    1482           8 :                                 TALLOC_FREE(frame);
    1483           8 :                                 return count - rem;
    1484             : 
    1485             :                         }
    1486             :                         else { /* Nothing copied ... */
    1487             : 
    1488           0 :                                 errno = EINVAL;  /* Not enough space ... */
    1489           0 :                                 TALLOC_FREE(frame);
    1490           0 :                                 return -1;
    1491             : 
    1492             :                         }
    1493             : 
    1494             :                 }
    1495             : 
    1496         152 :                 memcpy(currentEntry, dirent, reqd); /* Copy the data in ... */
    1497             : 
    1498         304 :                 currentEntry->comment = &currentEntry->name[0] +
    1499         152 :                                                 dirent->namelen + 1;
    1500             : 
    1501         152 :                 ndir += reqd;
    1502         152 :                 rem -= reqd;
    1503             : 
    1504             :                 /* Try and align the struct for the next entry
    1505             :                    on a valid pointer boundary by appending zeros */
    1506        1068 :                 while((rem > 0) && ((uintptr_t)ndir & (sizeof(void*) - 1))) {
    1507         764 :                         *ndir = '\0';
    1508         764 :                         rem--;
    1509         764 :                         ndir++;
    1510         764 :                         currentEntry->dirlen++;
    1511             :                 }
    1512             : 
    1513         152 :                 dir->dir_next = dirlist = dirlist -> next;
    1514             : 
    1515             :                 /*
    1516             :                  * If we are returning file entries, we
    1517             :                  * have a duplicate list in dirplus.
    1518             :                  *
    1519             :                  * Update dirplus_next also so readdir and
    1520             :                  * readdirplus are kept in sync.
    1521             :                  */
    1522         152 :                 if (dir->dirplus_list != NULL) {
    1523         152 :                         dir->dirplus_next = dir->dirplus_next->next;
    1524             :                 }
    1525             :         }
    1526             : 
    1527           0 :         TALLOC_FREE(frame);
    1528             : 
    1529           0 :         if (rem == count)
    1530           0 :                 return 0;
    1531             :         else
    1532           0 :                 return count - rem;
    1533             : 
    1534             : }
    1535             : 
    1536             : /*
    1537             :  * Routine to create a directory ...
    1538             :  */
    1539             : 
    1540             : int
    1541           4 : SMBC_mkdir_ctx(SMBCCTX *context,
    1542             :                const char *fname,
    1543             :                mode_t mode)
    1544             : {
    1545           4 :         SMBCSRV *srv = NULL;
    1546           4 :         char *server = NULL;
    1547           4 :         char *share = NULL;
    1548           4 :         char *user = NULL;
    1549           4 :         char *password = NULL;
    1550           4 :         char *workgroup = NULL;
    1551           4 :         char *path = NULL;
    1552           4 :         char *targetpath = NULL;
    1553           4 :         uint16_t port = 0;
    1554           4 :         struct cli_state *targetcli = NULL;
    1555           4 :         struct cli_credentials *creds = NULL;
    1556           4 :         TALLOC_CTX *frame = talloc_stackframe();
    1557             :         NTSTATUS status;
    1558             : 
    1559           4 :         if (!context || !context->internal->initialized) {
    1560           0 :                 errno = EINVAL;
    1561           0 :                 TALLOC_FREE(frame);
    1562           0 :                 return -1;
    1563             :         }
    1564             : 
    1565           4 :         if (!fname) {
    1566           0 :                 errno = EINVAL;
    1567           0 :                 TALLOC_FREE(frame);
    1568           0 :                 return -1;
    1569             :         }
    1570             : 
    1571           4 :         DEBUG(4, ("smbc_mkdir(%s)\n", fname));
    1572             : 
    1573           4 :         if (SMBC_parse_path(frame,
    1574             :                             context,
    1575             :                             fname,
    1576             :                             &workgroup,
    1577             :                             &server,
    1578             :                             &port,
    1579             :                             &share,
    1580             :                             &path,
    1581             :                             &user,
    1582             :                             &password,
    1583             :                             NULL)) {
    1584           0 :                 errno = EINVAL;
    1585           0 :                 TALLOC_FREE(frame);
    1586           0 :                 return -1;
    1587             :         }
    1588             : 
    1589           4 :         if (!user || user[0] == (char)0) {
    1590           0 :                 user = talloc_strdup(frame, smbc_getUser(context));
    1591           0 :                 if (!user) {
    1592           0 :                         errno = ENOMEM;
    1593           0 :                         TALLOC_FREE(frame);
    1594           0 :                         return -1;
    1595             :                 }
    1596             :         }
    1597             : 
    1598           4 :         srv = SMBC_server(frame, context, True,
    1599             :                           server, port, share, &workgroup, &user, &password);
    1600             : 
    1601           4 :         if (!srv) {
    1602             : 
    1603           0 :                 TALLOC_FREE(frame);
    1604           0 :                 return -1;  /* errno set by SMBC_server */
    1605             : 
    1606             :         }
    1607             : 
    1608           4 :         creds = context->internal->creds;
    1609             : 
    1610             :         /*d_printf(">>>mkdir: resolving %s\n", path);*/
    1611           4 :         status = cli_resolve_path(frame, "",
    1612             :                                   creds,
    1613             :                                   srv->cli, path, &targetcli, &targetpath);
    1614           4 :         if (!NT_STATUS_IS_OK(status)) {
    1615           0 :                 d_printf("Could not resolve %s\n", path);
    1616           0 :                 errno = ENOENT;
    1617           0 :                 TALLOC_FREE(frame);
    1618           0 :                 return -1;
    1619             :         }
    1620             :         /*d_printf(">>>mkdir: resolved path as %s\n", targetpath);*/
    1621             : 
    1622           4 :         status = cli_mkdir(targetcli, targetpath);
    1623           4 :         if (!NT_STATUS_IS_OK(status)) {
    1624           0 :                 TALLOC_FREE(frame);
    1625           0 :                 errno = cli_status_to_errno(status);
    1626           0 :                 return -1;
    1627             : 
    1628             :         }
    1629             : 
    1630           4 :         TALLOC_FREE(frame);
    1631           4 :         return 0;
    1632             : 
    1633             : }
    1634             : 
    1635             : /*
    1636             :  * Our list function simply checks to see if a directory is not empty
    1637             :  */
    1638             : 
    1639             : static NTSTATUS
    1640           0 : rmdir_list_fn(struct file_info *finfo,
    1641             :               const char *mask,
    1642             :               void *state)
    1643             : {
    1644           0 :         if (strncmp(finfo->name, ".", 1) != 0 &&
    1645           0 :             strncmp(finfo->name, "..", 2) != 0) {
    1646           0 :                 bool *smbc_rmdir_dirempty = (bool *)state;
    1647           0 :                 *smbc_rmdir_dirempty = false;
    1648             :         }
    1649           0 :         return NT_STATUS_OK;
    1650             : }
    1651             : 
    1652             : /*
    1653             :  * Routine to remove a directory
    1654             :  */
    1655             : 
    1656             : int
    1657           8 : SMBC_rmdir_ctx(SMBCCTX *context,
    1658             :                const char *fname)
    1659             : {
    1660           8 :         SMBCSRV *srv = NULL;
    1661           8 :         char *server = NULL;
    1662           8 :         char *share = NULL;
    1663           8 :         char *user = NULL;
    1664           8 :         char *password = NULL;
    1665           8 :         char *workgroup = NULL;
    1666           8 :         char *path = NULL;
    1667           8 :         char *targetpath = NULL;
    1668           8 :         uint16_t port = 0;
    1669           8 :         struct cli_state *targetcli = NULL;
    1670           8 :         struct cli_credentials *creds = NULL;
    1671           8 :         TALLOC_CTX *frame = talloc_stackframe();
    1672             :         NTSTATUS status;
    1673             : 
    1674           8 :         if (!context || !context->internal->initialized) {
    1675           0 :                 errno = EINVAL;
    1676           0 :                 TALLOC_FREE(frame);
    1677           0 :                 return -1;
    1678             :         }
    1679             : 
    1680           8 :         if (!fname) {
    1681           0 :                 errno = EINVAL;
    1682           0 :                 TALLOC_FREE(frame);
    1683           0 :                 return -1;
    1684             :         }
    1685             : 
    1686           8 :         DEBUG(4, ("smbc_rmdir(%s)\n", fname));
    1687             : 
    1688           8 :         if (SMBC_parse_path(frame,
    1689             :                             context,
    1690             :                             fname,
    1691             :                             &workgroup,
    1692             :                             &server,
    1693             :                             &port,
    1694             :                             &share,
    1695             :                             &path,
    1696             :                             &user,
    1697             :                             &password,
    1698             :                             NULL)) {
    1699           0 :                 errno = EINVAL;
    1700           0 :                 TALLOC_FREE(frame);
    1701           0 :                 return -1;
    1702             :         }
    1703             : 
    1704           8 :         if (!user || user[0] == (char)0) {
    1705           0 :                 user = talloc_strdup(frame, smbc_getUser(context));
    1706           0 :                 if (!user) {
    1707           0 :                         errno = ENOMEM;
    1708           0 :                         TALLOC_FREE(frame);
    1709           0 :                         return -1;
    1710             :                 }
    1711             :         }
    1712             : 
    1713           8 :         srv = SMBC_server(frame, context, True,
    1714             :                           server, port, share, &workgroup, &user, &password);
    1715             : 
    1716           8 :         if (!srv) {
    1717             : 
    1718           0 :                 TALLOC_FREE(frame);
    1719           0 :                 return -1;  /* errno set by SMBC_server */
    1720             : 
    1721             :         }
    1722             : 
    1723           8 :         creds = context->internal->creds;
    1724             : 
    1725             :         /*d_printf(">>>rmdir: resolving %s\n", path);*/
    1726           8 :         status = cli_resolve_path(frame, "",
    1727             :                                   creds,
    1728             :                                   srv->cli, path, &targetcli, &targetpath);
    1729           8 :         if (!NT_STATUS_IS_OK(status)) {
    1730           0 :                 d_printf("Could not resolve %s\n", path);
    1731           0 :                 errno = ENOENT;
    1732           0 :                 TALLOC_FREE(frame);
    1733           0 :                 return -1;
    1734             :         }
    1735             :         /*d_printf(">>>rmdir: resolved path as %s\n", targetpath);*/
    1736             : 
    1737           8 :         if (!NT_STATUS_IS_OK(cli_rmdir(targetcli, targetpath))) {
    1738             : 
    1739           4 :                 errno = SMBC_errno(context, targetcli);
    1740             : 
    1741           4 :                 if (errno == EACCES) {  /* Check if the dir empty or not */
    1742             : 
    1743             :                         /* Local storage to avoid buffer overflows */
    1744             :                         char *lpath;
    1745           0 :                         bool smbc_rmdir_dirempty = true;
    1746             : 
    1747           0 :                         lpath = talloc_asprintf(frame, "%s\\*",
    1748             :                                                 targetpath);
    1749           0 :                         if (!lpath) {
    1750           0 :                                 errno = ENOMEM;
    1751           0 :                                 TALLOC_FREE(frame);
    1752           0 :                                 return -1;
    1753             :                         }
    1754             : 
    1755           0 :                         status = cli_list(targetcli, lpath,
    1756             :                                           FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN,
    1757             :                                           rmdir_list_fn,
    1758             :                                           &smbc_rmdir_dirempty);
    1759             : 
    1760           0 :                         if (!NT_STATUS_IS_OK(status)) {
    1761             :                                 /* Fix errno to ignore latest error ... */
    1762           0 :                                 DEBUG(5, ("smbc_rmdir: "
    1763             :                                           "cli_list returned an error: %d\n",
    1764             :                                           SMBC_errno(context, targetcli)));
    1765           0 :                                 errno = EACCES;
    1766             : 
    1767             :                         }
    1768             : 
    1769           0 :                         if (smbc_rmdir_dirempty)
    1770           0 :                                 errno = EACCES;
    1771             :                         else
    1772           0 :                                 errno = ENOTEMPTY;
    1773             : 
    1774             :                 }
    1775             : 
    1776           4 :                 TALLOC_FREE(frame);
    1777           4 :                 return -1;
    1778             : 
    1779             :         }
    1780             : 
    1781           4 :         TALLOC_FREE(frame);
    1782           4 :         return 0;
    1783             : 
    1784             : }
    1785             : 
    1786             : /*
    1787             :  * Routine to return the current directory position
    1788             :  */
    1789             : 
    1790             : off_t
    1791           8 : SMBC_telldir_ctx(SMBCCTX *context,
    1792             :                  SMBCFILE *dir)
    1793             : {
    1794           8 :         TALLOC_CTX *frame = talloc_stackframe();
    1795             : 
    1796           8 :         if (!context || !context->internal->initialized) {
    1797             : 
    1798           0 :                 errno = EINVAL;
    1799           0 :                 TALLOC_FREE(frame);
    1800           0 :                 return -1;
    1801             : 
    1802             :         }
    1803             : 
    1804           8 :         if (!SMBC_dlist_contains(context->internal->files, dir)) {
    1805             : 
    1806           0 :                 errno = EBADF;
    1807           0 :                 TALLOC_FREE(frame);
    1808           0 :                 return -1;
    1809             : 
    1810             :         }
    1811             : 
    1812           8 :         if (dir->file != False) { /* FIXME, should be dir, perhaps */
    1813             : 
    1814           0 :                 errno = ENOTDIR;
    1815           0 :                 TALLOC_FREE(frame);
    1816           0 :                 return -1;
    1817             : 
    1818             :         }
    1819             : 
    1820             :         /* See if we're already at the end. */
    1821           8 :         if (dir->dir_next == NULL) {
    1822             :                 /* We are. */
    1823           0 :                 TALLOC_FREE(frame);
    1824           0 :                 return -1;
    1825             :         }
    1826             : 
    1827             :         /*
    1828             :          * We return the pointer here as the offset
    1829             :          */
    1830           8 :         TALLOC_FREE(frame);
    1831           8 :         return (off_t)(long)dir->dir_next->dirent;
    1832             : }
    1833             : 
    1834             : /*
    1835             :  * A routine to run down the list and see if the entry is OK
    1836             :  * Modifies the dir list and the dirplus list (if it exists)
    1837             :  * to point at the correct next entry on success.
    1838             :  */
    1839             : 
    1840          16 : static bool update_dir_ents(SMBCFILE *dir, struct smbc_dirent *dirent)
    1841             : {
    1842          16 :         struct smbc_dir_list *tmp_dir = dir->dir_list;
    1843          16 :         struct smbc_dirplus_list *tmp_dirplus = dir->dirplus_list;
    1844             : 
    1845             :         /*
    1846             :          * Run down the list looking for what we want.
    1847             :          * If we're enumerating files both dir_list
    1848             :          * and dirplus_list contain the same entry
    1849             :          * list, as they were seeded from the same
    1850             :          * cli_list callback.
    1851             :          *
    1852             :          * If we're enumerating servers then
    1853             :          * dirplus_list will be NULL, so don't
    1854             :          * update in that case.
    1855             :          */
    1856             : 
    1857         476 :         while (tmp_dir != NULL) {
    1858         460 :                 if (tmp_dir->dirent == dirent) {
    1859          16 :                         dir->dir_next = tmp_dir;
    1860          16 :                         if (tmp_dirplus != NULL) {
    1861          16 :                                 dir->dirplus_next = tmp_dirplus;
    1862             :                         }
    1863          16 :                         return true;
    1864             :                 }
    1865         444 :                 tmp_dir = tmp_dir->next;
    1866         444 :                 if (tmp_dirplus != NULL) {
    1867         444 :                         tmp_dirplus = tmp_dirplus->next;
    1868             :                 }
    1869             :         }
    1870           0 :         return false;
    1871             : }
    1872             : 
    1873             : /*
    1874             :  * Routine to seek on a directory
    1875             :  */
    1876             : 
    1877             : int
    1878          20 : SMBC_lseekdir_ctx(SMBCCTX *context,
    1879             :                   SMBCFILE *dir,
    1880             :                   off_t offset)
    1881             : {
    1882          20 :         long int l_offset = offset;  /* Handle problems of size */
    1883          20 :         struct smbc_dirent *dirent = (struct smbc_dirent *)l_offset;
    1884          20 :         TALLOC_CTX *frame = talloc_stackframe();
    1885             :         bool ok;
    1886             : 
    1887          20 :         if (!context || !context->internal->initialized) {
    1888             : 
    1889           0 :                 errno = EINVAL;
    1890           0 :                 TALLOC_FREE(frame);
    1891           0 :                 return -1;
    1892             : 
    1893             :         }
    1894             : 
    1895          20 :         if (dir->file != False) { /* FIXME, should be dir, perhaps */
    1896             : 
    1897           0 :                 errno = ENOTDIR;
    1898           0 :                 TALLOC_FREE(frame);
    1899           0 :                 return -1;
    1900             : 
    1901             :         }
    1902             : 
    1903             :         /* Now, check what we were passed and see if it is OK ... */
    1904             : 
    1905          20 :         if (dirent == NULL) {  /* Seek to the beginning of the list */
    1906             : 
    1907           4 :                 dir->dir_next = dir->dir_list;
    1908             : 
    1909             :                 /* Do the same for dirplus. */
    1910           4 :                 dir->dirplus_next = dir->dirplus_list;
    1911             : 
    1912           4 :                 TALLOC_FREE(frame);
    1913           4 :                 return 0;
    1914             : 
    1915             :         }
    1916             : 
    1917          16 :         if (offset == -1) {     /* Seek to the end of the list */
    1918           0 :                 dir->dir_next = NULL;
    1919             : 
    1920             :                 /* Do the same for dirplus. */
    1921           0 :                 dir->dirplus_next = NULL;
    1922             : 
    1923           0 :                 TALLOC_FREE(frame);
    1924           0 :                 return 0;
    1925             :         }
    1926             : 
    1927             :         /*
    1928             :          * Run down the list and make sure that the entry is OK.
    1929             :          * Update the position of both dir and dirplus lists.
    1930             :          */
    1931             : 
    1932          16 :         ok = update_dir_ents(dir, dirent);
    1933          16 :         if (!ok) {
    1934           0 :                 errno = EINVAL;   /* Bad entry */
    1935           0 :                 TALLOC_FREE(frame);
    1936           0 :                 return -1;
    1937             :         }
    1938             : 
    1939          16 :         TALLOC_FREE(frame);
    1940          16 :         return 0;
    1941             : }
    1942             : 
    1943             : /*
    1944             :  * Routine to fstat a dir
    1945             :  */
    1946             : 
    1947             : int
    1948           0 : SMBC_fstatdir_ctx(SMBCCTX *context,
    1949             :                   SMBCFILE *dir,
    1950             :                   struct stat *st)
    1951             : {
    1952             : 
    1953           0 :         if (!context || !context->internal->initialized) {
    1954             : 
    1955           0 :                 errno = EINVAL;
    1956           0 :                 return -1;
    1957             :         }
    1958             : 
    1959             :         /* No code yet ... */
    1960           0 :         return 0;
    1961             : }
    1962             : 
    1963             : int
    1964           0 : SMBC_chmod_ctx(SMBCCTX *context,
    1965             :                const char *fname,
    1966             :                mode_t newmode)
    1967             : {
    1968           0 :         SMBCSRV *srv = NULL;
    1969           0 :         char *server = NULL;
    1970           0 :         char *share = NULL;
    1971           0 :         char *user = NULL;
    1972           0 :         char *password = NULL;
    1973           0 :         char *workgroup = NULL;
    1974           0 :         char *targetpath = NULL;
    1975           0 :         struct cli_state *targetcli = NULL;
    1976           0 :         char *path = NULL;
    1977             :         uint32_t attr;
    1978           0 :         uint16_t port = 0;
    1979           0 :         struct cli_credentials *creds = NULL;
    1980           0 :         TALLOC_CTX *frame = talloc_stackframe();
    1981             :         NTSTATUS status;
    1982             : 
    1983           0 :         if (!context || !context->internal->initialized) {
    1984             : 
    1985           0 :                 errno = EINVAL;  /* Best I can think of ... */
    1986           0 :                 TALLOC_FREE(frame);
    1987           0 :                 return -1;
    1988             :         }
    1989             : 
    1990           0 :         if (!fname) {
    1991           0 :                 errno = EINVAL;
    1992           0 :                 TALLOC_FREE(frame);
    1993           0 :                 return -1;
    1994             :         }
    1995             : 
    1996           0 :         DEBUG(4, ("smbc_chmod(%s, 0%3o)\n", fname, (unsigned int)newmode));
    1997             : 
    1998           0 :         if (SMBC_parse_path(frame,
    1999             :                             context,
    2000             :                             fname,
    2001             :                             &workgroup,
    2002             :                             &server,
    2003             :                             &port,
    2004             :                             &share,
    2005             :                             &path,
    2006             :                             &user,
    2007             :                             &password,
    2008             :                             NULL)) {
    2009           0 :                 errno = EINVAL;
    2010           0 :                 TALLOC_FREE(frame);
    2011           0 :                 return -1;
    2012             :         }
    2013             : 
    2014           0 :         if (!user || user[0] == (char)0) {
    2015           0 :                 user = talloc_strdup(frame, smbc_getUser(context));
    2016           0 :                 if (!user) {
    2017           0 :                         errno = ENOMEM;
    2018           0 :                         TALLOC_FREE(frame);
    2019           0 :                         return -1;
    2020             :                 }
    2021             :         }
    2022             : 
    2023           0 :         srv = SMBC_server(frame, context, True,
    2024             :                           server, port, share, &workgroup, &user, &password);
    2025             : 
    2026           0 :         if (!srv) {
    2027           0 :                 TALLOC_FREE(frame);
    2028           0 :                 return -1;  /* errno set by SMBC_server */
    2029             :         }
    2030             :         
    2031           0 :         creds = context->internal->creds;
    2032             : 
    2033             :         /*d_printf(">>>unlink: resolving %s\n", path);*/
    2034           0 :         status = cli_resolve_path(frame, "",
    2035             :                                   creds,
    2036             :                                   srv->cli, path, &targetcli, &targetpath);
    2037           0 :         if (!NT_STATUS_IS_OK(status)) {
    2038           0 :                 d_printf("Could not resolve %s\n", path);
    2039           0 :                 errno = ENOENT;
    2040           0 :                 TALLOC_FREE(frame);
    2041           0 :                 return -1;
    2042             :         }
    2043             : 
    2044           0 :         attr = 0;
    2045             : 
    2046           0 :         if (!(newmode & (S_IWUSR | S_IWGRP | S_IWOTH))) attr |= FILE_ATTRIBUTE_READONLY;
    2047           0 :         if ((newmode & S_IXUSR) && lp_map_archive(-1)) attr |= FILE_ATTRIBUTE_ARCHIVE;
    2048           0 :         if ((newmode & S_IXGRP) && lp_map_system(-1)) attr |= FILE_ATTRIBUTE_SYSTEM;
    2049           0 :         if ((newmode & S_IXOTH) && lp_map_hidden(-1)) attr |= FILE_ATTRIBUTE_HIDDEN;
    2050             : 
    2051           0 :         status = cli_setatr(targetcli, targetpath, attr, 0);
    2052           0 :         if (!NT_STATUS_IS_OK(status)) {
    2053           0 :                 TALLOC_FREE(frame);
    2054           0 :                 errno = cli_status_to_errno(status);
    2055           0 :                 return -1;
    2056             :         }
    2057             : 
    2058           0 :         TALLOC_FREE(frame);
    2059           0 :         return 0;
    2060             : }
    2061             : 
    2062             : int
    2063           4 : SMBC_utimes_ctx(SMBCCTX *context,
    2064             :                 const char *fname,
    2065             :                 struct timeval *tbuf)
    2066             : {
    2067           4 :         SMBCSRV *srv = NULL;
    2068           4 :         char *server = NULL;
    2069           4 :         char *share = NULL;
    2070           4 :         char *user = NULL;
    2071           4 :         char *password = NULL;
    2072           4 :         char *workgroup = NULL;
    2073           4 :         char *path = NULL;
    2074             :         struct timespec access_time, write_time;
    2075           4 :         uint16_t port = 0;
    2076           4 :         TALLOC_CTX *frame = talloc_stackframe();
    2077             :         bool ok;
    2078             : 
    2079           4 :         if (!context || !context->internal->initialized) {
    2080             : 
    2081           0 :                 errno = EINVAL;  /* Best I can think of ... */
    2082           0 :                 TALLOC_FREE(frame);
    2083           0 :                 return -1;
    2084             :         }
    2085             : 
    2086           4 :         if (!fname) {
    2087           0 :                 errno = EINVAL;
    2088           0 :                 TALLOC_FREE(frame);
    2089           0 :                 return -1;
    2090             :         }
    2091             : 
    2092           4 :         if (tbuf == NULL) {
    2093           0 :                 access_time = write_time = timespec_current();
    2094             :         } else {
    2095           4 :                 access_time = convert_timeval_to_timespec(tbuf[0]);
    2096           4 :                 write_time = convert_timeval_to_timespec(tbuf[1]);
    2097             :         }
    2098             : 
    2099           4 :         if (DEBUGLVL(4)) {
    2100             :                 struct timeval_buf abuf, wbuf;
    2101             : 
    2102           0 :                 dbgtext("smbc_utimes(%s, atime = %s mtime = %s)\n",
    2103             :                         fname,
    2104             :                         timespec_string_buf(&access_time, false, &abuf),
    2105             :                         timespec_string_buf(&write_time, false, &wbuf));
    2106             :         }
    2107             : 
    2108           4 :         if (SMBC_parse_path(frame,
    2109             :                             context,
    2110             :                             fname,
    2111             :                             &workgroup,
    2112             :                             &server,
    2113             :                             &port,
    2114             :                             &share,
    2115             :                             &path,
    2116             :                             &user,
    2117             :                             &password,
    2118             :                             NULL)) {
    2119           0 :                 errno = EINVAL;
    2120           0 :                 TALLOC_FREE(frame);
    2121           0 :                 return -1;
    2122             :         }
    2123             : 
    2124           4 :         if (!user || user[0] == (char)0) {
    2125           0 :                 user = talloc_strdup(frame, smbc_getUser(context));
    2126           0 :                 if (!user) {
    2127           0 :                         errno = ENOMEM;
    2128           0 :                         TALLOC_FREE(frame);
    2129           0 :                         return -1;
    2130             :                 }
    2131             :         }
    2132             : 
    2133           4 :         srv = SMBC_server(frame, context, True,
    2134             :                           server, port, share, &workgroup, &user, &password);
    2135             : 
    2136           4 :         if (!srv) {
    2137           0 :                 TALLOC_FREE(frame);
    2138           0 :                 return -1;      /* errno set by SMBC_server */
    2139             :         }
    2140             : 
    2141           4 :         ok = SMBC_setatr(
    2142             :                 context,
    2143             :                 srv,
    2144             :                 path,
    2145           4 :                 (struct timespec) { .tv_nsec = SAMBA_UTIME_OMIT },
    2146             :                 access_time,
    2147             :                 write_time,
    2148           4 :                 (struct timespec) { .tv_nsec = SAMBA_UTIME_OMIT },
    2149             :                 0);
    2150           4 :         if (!ok) {
    2151           0 :                 TALLOC_FREE(frame);
    2152           0 :                 return -1;      /* errno set by SMBC_setatr */
    2153             :         }
    2154             : 
    2155           4 :         TALLOC_FREE(frame);
    2156           4 :         return 0;
    2157             : }
    2158             : 
    2159             : /*
    2160             :  * Routine to unlink() a file
    2161             :  */
    2162             : 
    2163             : int
    2164         820 : SMBC_unlink_ctx(SMBCCTX *context,
    2165             :                 const char *fname)
    2166             : {
    2167         820 :         char *server = NULL;
    2168         820 :         char *share = NULL;
    2169         820 :         char *user = NULL;
    2170         820 :         char *password = NULL;
    2171         820 :         char *workgroup = NULL;
    2172         820 :         char *path = NULL;
    2173         820 :         char *targetpath = NULL;
    2174         820 :         uint16_t port = 0;
    2175         820 :         struct cli_state *targetcli = NULL;
    2176         820 :         SMBCSRV *srv = NULL;
    2177         820 :         struct cli_credentials *creds = NULL;
    2178         820 :         TALLOC_CTX *frame = talloc_stackframe();
    2179             :         NTSTATUS status;
    2180             : 
    2181         820 :         if (!context || !context->internal->initialized) {
    2182             : 
    2183           0 :                 errno = EINVAL;  /* Best I can think of ... */
    2184           0 :                 TALLOC_FREE(frame);
    2185           0 :                 return -1;
    2186             : 
    2187             :         }
    2188             : 
    2189         820 :         if (!fname) {
    2190           0 :                 errno = EINVAL;
    2191           0 :                 TALLOC_FREE(frame);
    2192           0 :                 return -1;
    2193             : 
    2194             :         }
    2195             : 
    2196         820 :         if (SMBC_parse_path(frame,
    2197             :                             context,
    2198             :                             fname,
    2199             :                             &workgroup,
    2200             :                             &server,
    2201             :                             &port,
    2202             :                             &share,
    2203             :                             &path,
    2204             :                             &user,
    2205             :                             &password,
    2206             :                             NULL)) {
    2207           0 :                 errno = EINVAL;
    2208           0 :                 TALLOC_FREE(frame);
    2209           0 :                 return -1;
    2210             :         }
    2211             : 
    2212         820 :         if (!user || user[0] == (char)0) {
    2213           0 :                 user = talloc_strdup(frame, smbc_getUser(context));
    2214           0 :                 if (!user) {
    2215           0 :                         errno = ENOMEM;
    2216           0 :                         TALLOC_FREE(frame);
    2217           0 :                         return -1;
    2218             :                 }
    2219             :         }
    2220             : 
    2221         820 :         srv = SMBC_server(frame, context, True,
    2222             :                           server, port, share, &workgroup, &user, &password);
    2223             : 
    2224         820 :         if (!srv) {
    2225           0 :                 TALLOC_FREE(frame);
    2226           0 :                 return -1;  /* SMBC_server sets errno */
    2227             : 
    2228             :         }
    2229             : 
    2230         820 :         creds = context->internal->creds;
    2231             : 
    2232             :         /*d_printf(">>>unlink: resolving %s\n", path);*/
    2233         820 :         status = cli_resolve_path(frame, "",
    2234             :                                   creds,
    2235             :                                   srv->cli, path, &targetcli, &targetpath);
    2236         820 :         if (!NT_STATUS_IS_OK(status)) {
    2237           0 :                 d_printf("Could not resolve %s\n", path);
    2238           0 :                 errno = ENOENT;
    2239           0 :                 TALLOC_FREE(frame);
    2240           0 :                 return -1;
    2241             :         }
    2242             :         /*d_printf(">>>unlink: resolved path as %s\n", targetpath);*/
    2243             : 
    2244         820 :         if (!NT_STATUS_IS_OK(cli_unlink(targetcli, targetpath, FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN))) {
    2245             : 
    2246         408 :                 errno = SMBC_errno(context, targetcli);
    2247             : 
    2248         408 :                 if (errno == EACCES) { /* Check if the file is a directory */
    2249             : 
    2250           0 :                         int saverr = errno;
    2251           0 :                         struct stat sb = {0};
    2252             :                         bool ok;
    2253             : 
    2254           0 :                         ok = SMBC_getatr(context, srv, path, &sb);
    2255           0 :                         if (!ok) {
    2256             :                                 /* Hmmm, bad error ... What? */
    2257             : 
    2258           0 :                                 errno = SMBC_errno(context, targetcli);
    2259           0 :                                 TALLOC_FREE(frame);
    2260           0 :                                 return -1;
    2261             : 
    2262             :                         }
    2263             :                         else {
    2264             : 
    2265           0 :                                 if (S_ISDIR(sb.st_mode))
    2266           0 :                                         errno = EISDIR;
    2267             :                                 else
    2268           0 :                                         errno = saverr;  /* Restore this */
    2269             : 
    2270             :                         }
    2271             :                 }
    2272             : 
    2273         408 :                 TALLOC_FREE(frame);
    2274         408 :                 return -1;
    2275             : 
    2276             :         }
    2277             : 
    2278         412 :         TALLOC_FREE(frame);
    2279         412 :         return 0;  /* Success ... */
    2280             : 
    2281             : }
    2282             : 
    2283             : /*
    2284             :  * Routine to rename() a file
    2285             :  */
    2286             : 
    2287             : int
    2288           0 : SMBC_rename_ctx(SMBCCTX *ocontext,
    2289             :                 const char *oname,
    2290             :                 SMBCCTX *ncontext,
    2291             :                 const char *nname)
    2292             : {
    2293           0 :         char *server1 = NULL;
    2294           0 :         char *share1 = NULL;
    2295           0 :         char *server2 = NULL;
    2296           0 :         char *share2 = NULL;
    2297           0 :         char *user1 = NULL;
    2298           0 :         char *user2 = NULL;
    2299           0 :         char *password1 = NULL;
    2300           0 :         char *password2 = NULL;
    2301           0 :         char *workgroup = NULL;
    2302           0 :         char *path1 = NULL;
    2303           0 :         char *path2 = NULL;
    2304           0 :         char *targetpath1 = NULL;
    2305           0 :         char *targetpath2 = NULL;
    2306           0 :         struct cli_state *targetcli1 = NULL;
    2307           0 :         struct cli_state *targetcli2 = NULL;
    2308           0 :         SMBCSRV *srv = NULL;
    2309           0 :         uint16_t port1 = 0;
    2310           0 :         uint16_t port2 = 0;
    2311           0 :         struct cli_credentials *ocreds = NULL;
    2312           0 :         struct cli_credentials *ncreds = NULL;
    2313           0 :         TALLOC_CTX *frame = talloc_stackframe();
    2314             :         NTSTATUS status;
    2315             : 
    2316           0 :         if (!ocontext || !ncontext ||
    2317           0 :             !ocontext->internal->initialized ||
    2318           0 :             !ncontext->internal->initialized) {
    2319             : 
    2320           0 :                 errno = EINVAL;  /* Best I can think of ... */
    2321           0 :                 TALLOC_FREE(frame);
    2322           0 :                 return -1;
    2323             :         }
    2324             : 
    2325           0 :         if (!oname || !nname) {
    2326           0 :                 errno = EINVAL;
    2327           0 :                 TALLOC_FREE(frame);
    2328           0 :                 return -1;
    2329             :         }
    2330             : 
    2331           0 :         DEBUG(4, ("smbc_rename(%s,%s)\n", oname, nname));
    2332             : 
    2333           0 :         if (SMBC_parse_path(frame,
    2334             :                             ocontext,
    2335             :                             oname,
    2336             :                             &workgroup,
    2337             :                             &server1,
    2338             :                             &port1,
    2339             :                             &share1,
    2340             :                             &path1,
    2341             :                             &user1,
    2342             :                             &password1,
    2343             :                             NULL)) {
    2344           0 :                 errno = EINVAL;
    2345           0 :                 TALLOC_FREE(frame);
    2346           0 :                 return -1;
    2347             :         }
    2348             : 
    2349           0 :         if (!user1 || user1[0] == (char)0) {
    2350           0 :                 user1 = talloc_strdup(frame, smbc_getUser(ocontext));
    2351           0 :                 if (!user1) {
    2352           0 :                         errno = ENOMEM;
    2353           0 :                         TALLOC_FREE(frame);
    2354           0 :                         return -1;
    2355             :                 }
    2356             :         }
    2357             : 
    2358           0 :         if (SMBC_parse_path(frame,
    2359             :                             ncontext,
    2360             :                             nname,
    2361             :                             NULL,
    2362             :                             &server2,
    2363             :                             &port2,
    2364             :                             &share2,
    2365             :                             &path2,
    2366             :                             &user2,
    2367             :                             &password2,
    2368             :                             NULL)) {
    2369           0 :                 errno = EINVAL;
    2370           0 :                 TALLOC_FREE(frame);
    2371           0 :                 return -1;
    2372             :         }
    2373             : 
    2374           0 :         if (!user2 || user2[0] == (char)0) {
    2375           0 :                 user2 = talloc_strdup(frame, smbc_getUser(ncontext));
    2376           0 :                 if (!user2) {
    2377           0 :                         errno = ENOMEM;
    2378           0 :                         TALLOC_FREE(frame);
    2379           0 :                         return -1;
    2380             :                 }
    2381             :         }
    2382             : 
    2383           0 :         if (strcmp(server1, server2) || strcmp(share1, share2) ||
    2384           0 :             strcmp(user1, user2)) {
    2385             :                 /* Can't rename across file systems, or users?? */
    2386           0 :                 errno = EXDEV;
    2387           0 :                 TALLOC_FREE(frame);
    2388           0 :                 return -1;
    2389             :         }
    2390             : 
    2391           0 :         srv = SMBC_server(frame, ocontext, True,
    2392             :                           server1, port1, share1, &workgroup, &user1, &password1);
    2393           0 :         if (!srv) {
    2394           0 :                 TALLOC_FREE(frame);
    2395           0 :                 return -1;
    2396             : 
    2397             :         }
    2398             : 
    2399             :         /* set the credentials to make DFS work */
    2400           0 :         smbc_set_credentials_with_fallback(ocontext,
    2401             :                                            workgroup,
    2402             :                                            user1,
    2403             :                                            password1);
    2404             : 
    2405             :         /*d_printf(">>>rename: resolving %s\n", path1);*/
    2406           0 :         ocreds = ocontext->internal->creds;
    2407             : 
    2408           0 :         status = cli_resolve_path(frame, "",
    2409             :                                   ocreds,
    2410             :                                   srv->cli, path1, &targetcli1, &targetpath1);
    2411           0 :         if (!NT_STATUS_IS_OK(status)) {
    2412           0 :                 d_printf("Could not resolve %s\n", path1);
    2413           0 :                 errno = ENOENT;
    2414           0 :                 TALLOC_FREE(frame);
    2415           0 :                 return -1;
    2416             :         }
    2417             :         
    2418             :         /* set the credentials to make DFS work */
    2419           0 :         smbc_set_credentials_with_fallback(ncontext,
    2420             :                                            workgroup,
    2421             :                                            user2,
    2422             :                                            password2);
    2423             :         
    2424             :         /*d_printf(">>>rename: resolved path as %s\n", targetpath1);*/
    2425             :         /*d_printf(">>>rename: resolving %s\n", path2);*/
    2426           0 :         ncreds = ncontext->internal->creds;
    2427             : 
    2428           0 :         status = cli_resolve_path(frame, "",
    2429             :                                   ncreds,
    2430             :                                   srv->cli, path2, &targetcli2, &targetpath2);
    2431           0 :         if (!NT_STATUS_IS_OK(status)) {
    2432           0 :                 d_printf("Could not resolve %s\n", path2);
    2433           0 :                 errno = ENOENT;
    2434           0 :                 TALLOC_FREE(frame);
    2435           0 :                 return -1;
    2436             :         }
    2437             :         /*d_printf(">>>rename: resolved path as %s\n", targetpath2);*/
    2438             : 
    2439           0 :         if (strcmp(smbXcli_conn_remote_name(targetcli1->conn), smbXcli_conn_remote_name(targetcli2->conn)) ||
    2440           0 :             strcmp(targetcli1->share, targetcli2->share))
    2441             :         {
    2442             :                 /* can't rename across file systems */
    2443           0 :                 errno = EXDEV;
    2444           0 :                 TALLOC_FREE(frame);
    2445           0 :                 return -1;
    2446             :         }
    2447             : 
    2448           0 :         if (!NT_STATUS_IS_OK(
    2449             :                 cli_rename(targetcli1, targetpath1, targetpath2, false))) {
    2450           0 :                 int eno = SMBC_errno(ocontext, targetcli1);
    2451             : 
    2452           0 :                 if (eno != EEXIST ||
    2453           0 :                     !NT_STATUS_IS_OK(cli_unlink(targetcli1, targetpath2,
    2454             :                                                 FILE_ATTRIBUTE_SYSTEM |
    2455           0 :                                                     FILE_ATTRIBUTE_HIDDEN)) ||
    2456           0 :                     !NT_STATUS_IS_OK(cli_rename(targetcli1, targetpath1,
    2457             :                                                 targetpath2, false))) {
    2458             : 
    2459           0 :                         errno = eno;
    2460           0 :                         TALLOC_FREE(frame);
    2461           0 :                         return -1;
    2462             : 
    2463             :                 }
    2464             :         }
    2465             : 
    2466           0 :         TALLOC_FREE(frame);
    2467           0 :         return 0; /* Success */
    2468             : }
    2469             : 
    2470             : struct smbc_notify_cb_state {
    2471             :         struct tevent_context *ev;
    2472             :         struct cli_state *cli;
    2473             :         uint16_t fnum;
    2474             :         bool recursive;
    2475             :         uint32_t completion_filter;
    2476             :         unsigned callback_timeout_ms;
    2477             :         smbc_notify_callback_fn cb;
    2478             :         void *private_data;
    2479             : };
    2480             : 
    2481             : static void smbc_notify_cb_got_changes(struct tevent_req *subreq);
    2482             : static void smbc_notify_cb_timedout(struct tevent_req *subreq);
    2483             : 
    2484           0 : static struct tevent_req *smbc_notify_cb_send(
    2485             :         TALLOC_CTX *mem_ctx, struct tevent_context *ev, struct cli_state *cli,
    2486             :         uint16_t fnum, bool recursive, uint32_t completion_filter,
    2487             :         unsigned callback_timeout_ms,
    2488             :         smbc_notify_callback_fn cb, void *private_data)
    2489             : {
    2490             :         struct tevent_req *req, *subreq;
    2491             :         struct smbc_notify_cb_state *state;
    2492             : 
    2493           0 :         req = tevent_req_create(mem_ctx, &state, struct smbc_notify_cb_state);
    2494           0 :         if (req == NULL) {
    2495           0 :                 return NULL;
    2496             :         }
    2497           0 :         state->ev = ev;
    2498           0 :         state->cli = cli;
    2499           0 :         state->fnum = fnum;
    2500           0 :         state->recursive = recursive;
    2501           0 :         state->completion_filter = completion_filter;
    2502           0 :         state->callback_timeout_ms = callback_timeout_ms;
    2503           0 :         state->cb = cb;
    2504           0 :         state->private_data = private_data;
    2505             : 
    2506           0 :         subreq = cli_notify_send(
    2507           0 :                 state, state->ev, state->cli, state->fnum, 1000,
    2508           0 :                 state->completion_filter, state->recursive);
    2509           0 :         if (tevent_req_nomem(subreq, req)) {
    2510           0 :                 return tevent_req_post(req, ev);
    2511             :         }
    2512           0 :         tevent_req_set_callback(subreq, smbc_notify_cb_got_changes, req);
    2513             : 
    2514           0 :         if (state->callback_timeout_ms == 0) {
    2515           0 :                 return req;
    2516             :         }
    2517             : 
    2518           0 :         subreq = tevent_wakeup_send(
    2519           0 :                 state, state->ev,
    2520           0 :                 tevent_timeval_current_ofs(state->callback_timeout_ms/1000,
    2521           0 :                                            state->callback_timeout_ms*1000));
    2522           0 :         if (tevent_req_nomem(subreq, req)) {
    2523           0 :                 return tevent_req_post(req, ev);
    2524             :         }
    2525           0 :         tevent_req_set_callback(subreq, smbc_notify_cb_timedout, req);
    2526             : 
    2527           0 :         return req;
    2528             : }
    2529             : 
    2530           0 : static void smbc_notify_cb_got_changes(struct tevent_req *subreq)
    2531             : {
    2532           0 :         struct tevent_req *req = tevent_req_callback_data(
    2533             :                 subreq, struct tevent_req);
    2534           0 :         struct smbc_notify_cb_state *state = tevent_req_data(
    2535             :                 req, struct smbc_notify_cb_state);
    2536             :         uint32_t num_changes;
    2537             :         struct notify_change *changes;
    2538             :         NTSTATUS status;
    2539             :         int cb_ret;
    2540             : 
    2541           0 :         status = cli_notify_recv(subreq, state, &num_changes, &changes);
    2542           0 :         TALLOC_FREE(subreq);
    2543           0 :         if (tevent_req_nterror(req, status)) {
    2544           0 :                 return;
    2545             :         }
    2546             : 
    2547           0 :         {
    2548           0 :                 struct smbc_notify_callback_action actions[num_changes];
    2549             :                 uint32_t i;
    2550             : 
    2551           0 :                 for (i=0; i<num_changes; i++) {
    2552           0 :                         actions[i].action = changes[i].action;
    2553           0 :                         actions[i].filename = changes[i].name;
    2554             :                 }
    2555             : 
    2556           0 :                 cb_ret = state->cb(actions, num_changes, state->private_data);
    2557             :         }
    2558             : 
    2559           0 :         TALLOC_FREE(changes);
    2560             : 
    2561           0 :         if (cb_ret != 0) {
    2562           0 :                 tevent_req_done(req);
    2563           0 :                 return;
    2564             :         }
    2565             : 
    2566           0 :         subreq = cli_notify_send(
    2567           0 :                 state, state->ev, state->cli, state->fnum, 1000,
    2568           0 :                 state->completion_filter, state->recursive);
    2569           0 :         if (tevent_req_nomem(subreq, req)) {
    2570           0 :                 return;
    2571             :         }
    2572           0 :         tevent_req_set_callback(subreq, smbc_notify_cb_got_changes, req);
    2573             : }
    2574             : 
    2575           0 : static void smbc_notify_cb_timedout(struct tevent_req *subreq)
    2576             : {
    2577           0 :         struct tevent_req *req = tevent_req_callback_data(
    2578             :                 subreq, struct tevent_req);
    2579           0 :         struct smbc_notify_cb_state *state = tevent_req_data(
    2580             :                 req, struct smbc_notify_cb_state);
    2581             :         int cb_ret;
    2582             :         bool ok;
    2583             : 
    2584           0 :         ok = tevent_wakeup_recv(subreq);
    2585           0 :         TALLOC_FREE(subreq);
    2586           0 :         if (!ok) {
    2587           0 :                 tevent_req_oom(req);
    2588           0 :                 return;
    2589             :         }
    2590             : 
    2591           0 :         cb_ret = state->cb(NULL, 0, state->private_data);
    2592           0 :         if (cb_ret != 0) {
    2593           0 :                 tevent_req_done(req);
    2594           0 :                 return;
    2595             :         }
    2596             : 
    2597           0 :         subreq = tevent_wakeup_send(
    2598             :                 state, state->ev,
    2599           0 :                 tevent_timeval_current_ofs(state->callback_timeout_ms/1000,
    2600           0 :                                            state->callback_timeout_ms*1000));
    2601           0 :         if (tevent_req_nomem(subreq, req)) {
    2602           0 :                 return;
    2603             :         }
    2604           0 :         tevent_req_set_callback(subreq, smbc_notify_cb_timedout, req);
    2605             : }
    2606             : 
    2607           0 : static NTSTATUS smbc_notify_cb_recv(struct tevent_req *req)
    2608             : {
    2609           0 :         return tevent_req_simple_recv_ntstatus(req);
    2610             : }
    2611             : 
    2612           0 : static NTSTATUS smbc_notify_cb(struct cli_state *cli, uint16_t fnum,
    2613             :                                bool recursive, uint32_t completion_filter,
    2614             :                                unsigned callback_timeout_ms,
    2615             :                                smbc_notify_callback_fn cb, void *private_data)
    2616             : {
    2617           0 :         TALLOC_CTX *frame = talloc_stackframe();
    2618             :         struct tevent_context *ev;
    2619             :         struct tevent_req *req;
    2620           0 :         NTSTATUS status = NT_STATUS_NO_MEMORY;
    2621             : 
    2622           0 :         ev = samba_tevent_context_init(frame);
    2623           0 :         if (ev == NULL) {
    2624           0 :                 goto fail;
    2625             :         }
    2626           0 :         req = smbc_notify_cb_send(frame, ev, cli, fnum, recursive,
    2627             :                                   completion_filter,
    2628             :                                   callback_timeout_ms, cb, private_data);
    2629           0 :         if (req == NULL) {
    2630           0 :                 goto fail;
    2631             :         }
    2632           0 :         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
    2633           0 :                 goto fail;
    2634             :         }
    2635           0 :         status = smbc_notify_cb_recv(req);
    2636           0 :         TALLOC_FREE(req);
    2637           0 : fail:
    2638           0 :         TALLOC_FREE(frame);
    2639           0 :         return status;
    2640             : }
    2641             : 
    2642             : int
    2643           0 : SMBC_notify_ctx(SMBCCTX *context, SMBCFILE *dir, smbc_bool recursive,
    2644             :                 uint32_t completion_filter, unsigned callback_timeout_ms,
    2645             :                 smbc_notify_callback_fn cb, void *private_data)
    2646             : {
    2647           0 :         TALLOC_CTX *frame = talloc_stackframe();
    2648             :         struct cli_state *cli;
    2649           0 :         char *server = NULL;
    2650           0 :         char *share = NULL;
    2651           0 :         char *user = NULL;
    2652           0 :         char *password = NULL;
    2653           0 :         char *options = NULL;
    2654           0 :         char *workgroup = NULL;
    2655           0 :         char *path = NULL;
    2656             :         uint16_t port;
    2657             :         NTSTATUS status;
    2658             :         uint16_t fnum;
    2659             : 
    2660           0 :         if ((context == NULL) || !context->internal->initialized) {
    2661           0 :                 TALLOC_FREE(frame);
    2662           0 :                 errno = EINVAL;
    2663           0 :                 return -1;
    2664             :         }
    2665           0 :         if (!SMBC_dlist_contains(context->internal->files, dir)) {
    2666           0 :                 TALLOC_FREE(frame);
    2667           0 :                 errno = EBADF;
    2668           0 :                 return -1;
    2669             :         }
    2670             : 
    2671           0 :         if (SMBC_parse_path(frame,
    2672             :                             context,
    2673           0 :                             dir->fname,
    2674             :                             &workgroup,
    2675             :                             &server,
    2676             :                             &port,
    2677             :                             &share,
    2678             :                             &path,
    2679             :                             &user,
    2680             :                             &password,
    2681             :                             &options)) {
    2682           0 :                 DEBUG(4, ("no valid path\n"));
    2683           0 :                 TALLOC_FREE(frame);
    2684           0 :                 errno = EINVAL + 8194;
    2685           0 :                 return -1;
    2686             :         }
    2687             : 
    2688           0 :         DEBUG(4, ("parsed path: fname='%s' server='%s' share='%s' "
    2689             :                   "path='%s' options='%s'\n",
    2690             :                   dir->fname, server, share, path, options));
    2691             : 
    2692           0 :         DEBUG(4, ("%s(%p, %d, %"PRIu32")\n", __func__, dir,
    2693             :                   (int)recursive, completion_filter));
    2694             : 
    2695           0 :         cli = dir->srv->cli;
    2696           0 :         status = cli_ntcreate(
    2697             :                 cli, path, 0, FILE_READ_DATA, 0,
    2698             :                 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
    2699             :                 FILE_OPEN, 0, 0, &fnum, NULL);
    2700           0 :         if (!NT_STATUS_IS_OK(status)) {
    2701           0 :                 TALLOC_FREE(frame);
    2702           0 :                 errno = cli_status_to_errno(status);
    2703           0 :                 return -1;
    2704             :         }
    2705             : 
    2706           0 :         status = smbc_notify_cb(cli, fnum, recursive != 0, completion_filter,
    2707             :                                 callback_timeout_ms, cb, private_data);
    2708           0 :         if (!NT_STATUS_IS_OK(status)) {
    2709           0 :                 cli_close(cli, fnum);
    2710           0 :                 TALLOC_FREE(frame);
    2711           0 :                 errno = cli_status_to_errno(status);
    2712           0 :                 return -1;
    2713             :         }
    2714             : 
    2715           0 :         cli_close(cli, fnum);
    2716             : 
    2717           0 :         TALLOC_FREE(frame);
    2718           0 :         return 0;
    2719             : }

Generated by: LCOV version 1.13