LCOV - code coverage report
Current view: top level - source3/libsmb - libsmb_dir.c (source / functions) Hit Total Coverage
Test: coverage report for master 2b515b7d Lines: 598 1305 45.8 %
Date: 2024-02-28 12:06:22 Functions: 24 33 72.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          58 : static void remove_dirplus(SMBCFILE *dir)
      45             : {
      46          58 :         struct smbc_dirplus_list *d = NULL;
      47             : 
      48          58 :         d = dir->dirplus_list;
      49        1584 :         while (d != NULL) {
      50        1526 :                 struct smbc_dirplus_list *f = d;
      51        1526 :                 d = d->next;
      52             : 
      53        1526 :                 SAFE_FREE(f->smb_finfo->short_name);
      54        1526 :                 SAFE_FREE(f->smb_finfo->name);
      55        1526 :                 SAFE_FREE(f->smb_finfo);
      56        1526 :                 SAFE_FREE(f);
      57             :         }
      58             : 
      59          58 :         dir->dirplus_list = NULL;
      60          58 :         dir->dirplus_end = NULL;
      61          58 :         dir->dirplus_next = NULL;
      62          58 : }
      63             : 
      64             : static void
      65          58 : remove_dir(SMBCFILE *dir)
      66             : {
      67           0 :         struct smbc_dir_list *d,*f;
      68             : 
      69          58 :         d = dir->dir_list;
      70        2226 :         while (d) {
      71             : 
      72        2168 :                 f = d; d = d->next;
      73             : 
      74        2168 :                 SAFE_FREE(f->dirent);
      75        2168 :                 SAFE_FREE(f);
      76             : 
      77             :         }
      78             : 
      79          58 :         dir->dir_list = dir->dir_end = dir->dir_next = NULL;
      80             : 
      81          58 : }
      82             : 
      83             : static int
      84        2168 : add_dirent(SMBCFILE *dir,
      85             :            const char *name,
      86             :            const char *comment,
      87             :            uint32_t type)
      88             : {
      89           0 :         struct smbc_dirent *dirent;
      90           0 :         int size;
      91        2168 :         int name_length = (name == NULL ? 0 : strlen(name));
      92        2168 :         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        2168 :         size = sizeof(struct smbc_dirent) + name_length + comment_len + 2;
     100             : 
     101        2168 :         dirent = (struct smbc_dirent *)SMB_MALLOC(size);
     102             : 
     103        2168 :         if (!dirent) {
     104             : 
     105           0 :                 dir->dir_error = ENOMEM;
     106           0 :                 return -1;
     107             : 
     108             :         }
     109             : 
     110        2168 :         ZERO_STRUCTP(dirent);
     111             : 
     112        2168 :         if (dir->dir_list == NULL) {
     113             : 
     114          55 :                 dir->dir_list = SMB_MALLOC_P(struct smbc_dir_list);
     115          55 :                 if (!dir->dir_list) {
     116             : 
     117           0 :                         SAFE_FREE(dirent);
     118           0 :                         dir->dir_error = ENOMEM;
     119           0 :                         return -1;
     120             : 
     121             :                 }
     122          55 :                 ZERO_STRUCTP(dir->dir_list);
     123             : 
     124          55 :                 dir->dir_end = dir->dir_next = dir->dir_list;
     125             :         }
     126             :         else {
     127             : 
     128        2113 :                 dir->dir_end->next = SMB_MALLOC_P(struct smbc_dir_list);
     129             : 
     130        2113 :                 if (!dir->dir_end->next) {
     131             : 
     132           0 :                         SAFE_FREE(dirent);
     133           0 :                         dir->dir_error = ENOMEM;
     134           0 :                         return -1;
     135             : 
     136             :                 }
     137        2113 :                 ZERO_STRUCTP(dir->dir_end->next);
     138             : 
     139        2113 :                 dir->dir_end = dir->dir_end->next;
     140             :         }
     141             : 
     142        2168 :         dir->dir_end->next = NULL;
     143        2168 :         dir->dir_end->dirent = dirent;
     144             : 
     145        2168 :         dirent->smbc_type = type;
     146        2168 :         dirent->namelen = name_length;
     147        2168 :         dirent->commentlen = comment_len;
     148        2168 :         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        2168 :         strncpy(dirent->name, (name?name:""), dirent->namelen + 1);
     156        2168 :         dirent->comment = (char *)(&dirent->name + dirent->namelen + 1);
     157        2168 :         strncpy(dirent->comment, (comment?comment:""), dirent->commentlen + 1);
     158             : 
     159        2168 :         return 0;
     160             : 
     161             : }
     162             : 
     163        1526 : static int add_dirplus(SMBCFILE *dir, struct file_info *finfo)
     164             : {
     165        1526 :         struct smbc_dirplus_list *new_entry = NULL;
     166        1526 :         struct libsmb_file_info *info = NULL;
     167             : 
     168        1526 :         new_entry = SMB_MALLOC_P(struct smbc_dirplus_list);
     169        1526 :         if (new_entry == NULL) {
     170           0 :                 dir->dir_error = ENOMEM;
     171           0 :                 return -1;
     172             :         }
     173        1526 :         ZERO_STRUCTP(new_entry);
     174        1526 :         new_entry->ino = finfo->ino;
     175             : 
     176        1526 :         info = SMB_MALLOC_P(struct libsmb_file_info);
     177        1526 :         if (info == NULL) {
     178           0 :                 SAFE_FREE(new_entry);
     179           0 :                 dir->dir_error = ENOMEM;
     180           0 :                 return -1;
     181             :         }
     182             : 
     183        1526 :         ZERO_STRUCTP(info);
     184             : 
     185        1526 :         info->btime_ts = finfo->btime_ts;
     186        1526 :         info->atime_ts = finfo->atime_ts;
     187        1526 :         info->ctime_ts = finfo->ctime_ts;
     188        1526 :         info->mtime_ts = finfo->mtime_ts;
     189        1526 :         info->gid = finfo->gid;
     190        1526 :         info->attrs = finfo->attr;
     191        1526 :         info->size = finfo->size;
     192        1526 :         info->uid = finfo->uid;
     193        1526 :         info->name = SMB_STRDUP(finfo->name);
     194        1526 :         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        1526 :         if (finfo->short_name) {
     202        1042 :                 info->short_name = SMB_STRDUP(finfo->short_name);
     203             :         } else {
     204         484 :                 info->short_name = SMB_STRDUP("");
     205             :         }
     206             : 
     207        1526 :         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        1526 :         new_entry->smb_finfo = info;
     215             : 
     216             :         /* Now add to the list. */
     217        1526 :         if (dir->dirplus_list == NULL) {
     218             :                 /* Empty list - point everything at new_entry. */
     219          48 :                 dir->dirplus_list = new_entry;
     220          48 :                 dir->dirplus_end = new_entry;
     221          48 :                 dir->dirplus_next = new_entry;
     222             :         } else {
     223             :                 /* Append to list but leave the ->next cursor alone. */
     224        1478 :                 dir->dirplus_end->next = new_entry;
     225        1478 :                 dir->dirplus_end = new_entry;
     226             :         }
     227             : 
     228        1526 :         return 0;
     229             : }
     230             : 
     231             : static void
     232           4 : list_unique_wg_fn(const char *name,
     233             :                   uint32_t type,
     234             :                   const char *comment,
     235             :                   void *state)
     236             : {
     237           4 :         SMBCFILE *dir = (SMBCFILE *)state;
     238           0 :         struct smbc_dir_list *dir_list;
     239           0 :         struct smbc_dirent *dirent;
     240           0 :         int dirent_type;
     241           4 :         int do_remove = 0;
     242             : 
     243           4 :         dirent_type = dir->dir_type;
     244             : 
     245           4 :         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           0 :         }
     251             : 
     252             :         /* Point to the one just added */
     253           4 :         dirent = dir->dir_end->dirent;
     254             : 
     255             :         /* See if this was a duplicate */
     256           4 :         for (dir_list = dir->dir_list;
     257          10 :              dir_list != dir->dir_end;
     258           6 :              dir_list = dir_list->next) {
     259           6 :                 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           4 : }
     275             : 
     276             : static void
     277         638 : list_fn(const char *name,
     278             :         uint32_t type,
     279             :         const char *comment,
     280             :         void *state)
     281             : {
     282         638 :         SMBCFILE *dir = (SMBCFILE *)state;
     283           0 :         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         638 :         if (dir->dir_type == SMBC_FILE_SHARE) {
     298         636 :                 switch (type) {
     299         612 :                 case 0 | 0x80000000:
     300             :                 case 0:
     301         612 :                         dirent_type = SMBC_FILE_SHARE;
     302         612 :                         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           2 :                 dirent_type = dir->dir_type;
     324             :         }
     325             : 
     326         638 :         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           0 :         }
     332         638 : }
     333             : 
     334             : static NTSTATUS
     335        1526 : dir_list_fn(struct file_info *finfo,
     336             :             const char *mask,
     337             :             void *state)
     338             : {
     339        1526 :         SMBCFILE *dirp = (SMBCFILE *)state;
     340           0 :         int ret;
     341             : 
     342        1526 :         if (add_dirent((SMBCFILE *)state, finfo->name, "",
     343        1526 :                        (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        1526 :         ret = add_dirplus(dirp, finfo);
     348        1526 :         if (ret < 0) {
     349           0 :                 return map_nt_error_from_unix(dirp->dir_error);
     350             :         }
     351        1526 :         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           0 :         uint32_t i;
     363           0 :         WERROR result;
     364           4 :         uint32_t preferred_len = 0xffffffff;
     365           0 :         uint32_t type;
     366           0 :         struct srvsvc_NetShareInfoCtr info_ctr;
     367           0 :         struct srvsvc_NetShareCtr1 ctr1;
     368           4 :         fstring name = "";
     369           4 :         fstring comment = "";
     370           4 :         struct rpc_pipe_client *pipe_hnd = NULL;
     371           0 :         NTSTATUS nt_status;
     372           4 :         uint32_t resume_handle = 0;
     373           4 :         uint32_t total_entries = 0;
     374           0 :         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         640 :         for (i = 0; i < info_ctr.ctr.ctr1->count; i++) {
     421             : 
     422             :                 /* pull out the share name */
     423         636 :                 fstrcpy(name, info_ctr.ctr.ctr1->array[i].name);
     424             : 
     425             :                 /* pull out the share's comment */
     426         636 :                 fstrcpy(comment, info_ctr.ctr.ctr1->array[i].comment);
     427             : 
     428             :                 /* Get the type value */
     429         636 :                 type = info_ctr.ctr.ctr1->array[i].type;
     430             : 
     431             :                 /* Add this share to the list */
     432         636 :                 (*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          68 : SMBC_check_options(char *server,
     449             :                    char *share,
     450             :                    char *path,
     451             :                    char *options)
     452             : {
     453          68 :         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          68 :         if (! *options) return 0;
     459             : 
     460             :         /* Currently, we don't support any options. */
     461           0 :         return -1;
     462             : }
     463             : 
     464             : 
     465             : SMBCFILE *
     466         120 : SMBC_opendir_ctx(SMBCCTX *context,
     467             :                  const char *fname)
     468             : {
     469         120 :         char *server = NULL;
     470         120 :         char *share = NULL;
     471         120 :         char *user = NULL;
     472         120 :         char *password = NULL;
     473         120 :         char *options = NULL;
     474         120 :         char *workgroup = NULL;
     475         120 :         char *path = NULL;
     476         120 :         size_t path_len = 0;
     477         120 :         uint16_t port = 0;
     478         120 :         SMBCSRV *srv  = NULL;
     479         120 :         SMBCFILE *dir = NULL;
     480           0 :         struct sockaddr_storage rem_ss;
     481         120 :         TALLOC_CTX *frame = talloc_stackframe();
     482             : 
     483         120 :         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         120 :         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         116 :         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          68 :         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          68 :         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          68 :         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          68 :         dir = SMB_MALLOC_P(SMBCFILE);
     537             : 
     538          68 :         if (!dir) {
     539           0 :                 TALLOC_FREE(frame);
     540           0 :                 errno = ENOMEM;
     541           0 :                 return NULL;
     542             :         }
     543             : 
     544          68 :         ZERO_STRUCTP(dir);
     545             : 
     546          68 :         dir->cli_fd   = 0;
     547          68 :         dir->fname    = SMB_STRDUP(fname);
     548          68 :         if (dir->fname == NULL) {
     549           0 :                 SAFE_FREE(dir);
     550           0 :                 TALLOC_FREE(frame);
     551           0 :                 errno = ENOMEM;
     552           0 :                 return NULL;
     553             :         }
     554          68 :         dir->srv      = NULL;
     555          68 :         dir->offset   = 0;
     556          68 :         dir->file     = False;
     557          68 :         dir->dir_list = dir->dir_next = dir->dir_end = NULL;
     558             : 
     559          68 :         if (server[0] == (char)0) {
     560             : 
     561           0 :                 size_t i;
     562           4 :                 size_t count = 0;
     563           0 :                 size_t max_lmb_count;
     564           0 :                 struct sockaddr_storage *ip_list;
     565           0 :                 struct sockaddr_storage server_addr;
     566           4 :                 struct cli_credentials *creds = NULL;
     567           0 :                 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           4 :                 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           0 :                         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          12 :                         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          11 :                                 continue;
     663             :                         }
     664             : 
     665           3 :                         workgroup = talloc_strdup(frame, wg_ptr);
     666           3 :                         server = talloc_strdup(frame, smbXcli_conn_remote_name(cli->conn));
     667             : 
     668           3 :                         cli_shutdown(cli);
     669             : 
     670           3 :                         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           3 :                         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           3 :                         srv = SMBC_server(frame, context, True, server, port, "IPC$",
     691             :                                           &workgroup, &user, &password);
     692           3 :                         if (!srv) {
     693           0 :                                 continue;
     694             :                         }
     695             : 
     696           3 :                         if (smbXcli_conn_protocol(srv->cli->conn) > PROTOCOL_NT1) {
     697           2 :                                 continue;
     698             :                         }
     699             : 
     700           1 :                         dir->srv = srv;
     701           1 :                         dir->dir_type = SMBC_WORKGROUP;
     702             : 
     703             :                         /* Now, list the stuff ... */
     704             : 
     705           1 :                         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          64 :                 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          16 :                         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           0 :                                 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           0 :                                         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           0 :                                 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           0 :                         char *targetpath;
     916           0 :                         struct cli_state *targetcli;
     917          48 :                         struct cli_credentials *creds = NULL;
     918           0 :                         NTSTATUS status;
     919             : 
     920             :                         /* We connect to the server and list the directory */
     921          48 :                         dir->dir_type = SMBC_FILE_SHARE;
     922             : 
     923          48 :                         srv = SMBC_server(frame, context, True, server, port, share,
     924             :                                           &workgroup, &user, &password);
     925             : 
     926          48 :                         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          48 :                         dir->srv = srv;
     936             : 
     937             :                         /* Now, list the files ... */
     938             : 
     939          48 :                         path_len = strlen(path);
     940          48 :                         path = talloc_asprintf_append(path, "\\*");
     941          48 :                         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          48 :                         creds = context->internal->creds;
     951             : 
     952          48 :                         status = cli_resolve_path(
     953             :                                 frame, "",
     954             :                                 creds,
     955             :                                 srv->cli, path, &targetcli, &targetpath);
     956          48 :                         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          48 :                         status = cli_list(targetcli, targetpath,
     967             :                                           FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN,
     968             :                                           dir_list_fn, (void *)dir);
     969          48 :                         if (!NT_STATUS_IS_OK(status)) {
     970           0 :                                 int saved_errno;
     971           0 :                                 if (dir) {
     972           0 :                                         SAFE_FREE(dir->fname);
     973           0 :                                         SAFE_FREE(dir);
     974             :                                 }
     975           0 :                                 saved_errno = cli_status_to_errno(status);
     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 :                                         status = SMBC_getatr(
     989             :                                                 context,
     990             :                                                 srv,
     991             :                                                 path,
     992             :                                                 &sb);
     993           0 :                                         if (NT_STATUS_IS_OK(status) &&
     994           0 :                                             !S_ISDIR(sb.st_mode)) {
     995             : 
     996             :                                                 /* It is.  Correct the error value */
     997           0 :                                                 saved_errno = ENOTDIR;
     998             :                                         }
     999             :                                 }
    1000             : 
    1001             :                                 /*
    1002             :                                  * If there was an error and the server is no
    1003             :                                  * good any more...
    1004             :                                  */
    1005           0 :                                 if (cli_is_error(targetcli) &&
    1006           0 :                                     smbc_getFunctionCheckServer(context)(context, srv)) {
    1007             : 
    1008             :                                         /* ... then remove it. */
    1009           0 :                                         if (smbc_getFunctionRemoveUnusedServer(context)(context,
    1010             :                                                                                         srv)) {
    1011             :                                                 /*
    1012             :                                                  * We could not remove the
    1013             :                                                  * server completely, remove
    1014             :                                                  * it from the cache so we
    1015             :                                                  * will not get it again. It
    1016             :                                                  * will be removed when the
    1017             :                                                  * last file/dir is closed.
    1018             :                                                  */
    1019           0 :                                                 smbc_getFunctionRemoveCachedServer(context)(context, srv);
    1020             :                                         }
    1021             :                                 }
    1022             : 
    1023           0 :                                 TALLOC_FREE(frame);
    1024           0 :                                 errno = saved_errno;
    1025           0 :                                 return NULL;
    1026             :                         }
    1027             :                 }
    1028             : 
    1029             :         }
    1030             : 
    1031          58 :         DLIST_ADD(context->internal->files, dir);
    1032          58 :         TALLOC_FREE(frame);
    1033          58 :         return dir;
    1034             : 
    1035             : }
    1036             : 
    1037             : /*
    1038             :  * Routine to close a directory
    1039             :  */
    1040             : 
    1041             : int
    1042          58 : SMBC_closedir_ctx(SMBCCTX *context,
    1043             :                   SMBCFILE *dir)
    1044             : {
    1045          58 :         TALLOC_CTX *frame = NULL;
    1046             : 
    1047          58 :         if (!context || !context->internal->initialized) {
    1048           0 :                 errno = EINVAL;
    1049           0 :                 return -1;
    1050             :         }
    1051             : 
    1052          58 :         if (dir == NULL) {
    1053           0 :                 return 0;
    1054             :         }
    1055             : 
    1056          58 :         frame = talloc_stackframe();
    1057             : 
    1058          58 :         if (!SMBC_dlist_contains(context->internal->files, dir)) {
    1059           0 :                 errno = EBADF;
    1060           0 :                 TALLOC_FREE(frame);
    1061           0 :                 return -1;
    1062             :         }
    1063             : 
    1064          58 :         remove_dir(dir); /* Clean it up */
    1065          58 :         remove_dirplus(dir);
    1066             : 
    1067          58 :         DLIST_REMOVE(context->internal->files, dir);
    1068             : 
    1069          58 :         SAFE_FREE(dir->fname);
    1070          58 :         SAFE_FREE(dir);    /* Free the space too */
    1071             : 
    1072          58 :         TALLOC_FREE(frame);
    1073          58 :         return 0;
    1074             : 
    1075             : }
    1076             : 
    1077             : static int
    1078        1270 : smbc_readdir_internal(SMBCCTX * context,
    1079             :                       struct smbc_dirent *dest,
    1080             :                       struct smbc_dirent *src,
    1081             :                       int max_namebuf_len)
    1082             : {
    1083        1270 :         if (smbc_getOptionUrlEncodeReaddirEntries(context)) {
    1084           0 :                 int remaining_len;
    1085             : 
    1086             :                 /* url-encode the name.  get back remaining buffer space */
    1087           0 :                 remaining_len =
    1088           0 :                         smbc_urlencode(dest->name, src->name, max_namebuf_len);
    1089             : 
    1090             :                 /* -1 means no null termination. */
    1091           0 :                 if (remaining_len < 0) {
    1092           0 :                         return -1;
    1093             :                 }
    1094             : 
    1095             :                 /* We now know the name length */
    1096           0 :                 dest->namelen = strlen(dest->name);
    1097             : 
    1098           0 :                 if (dest->namelen + 1 < 1) {
    1099             :                         /* Integer wrap. */
    1100           0 :                         return -1;
    1101             :                 }
    1102             : 
    1103           0 :                 if (dest->namelen + 1 >= max_namebuf_len) {
    1104             :                         /* Out of space for comment. */
    1105           0 :                         return -1;
    1106             :                 }
    1107             : 
    1108             :                 /* Save the pointer to the beginning of the comment */
    1109           0 :                 dest->comment = dest->name + dest->namelen + 1;
    1110             : 
    1111           0 :                 if (remaining_len < 1) {
    1112             :                         /* No room for comment null termination. */
    1113           0 :                         return -1;
    1114             :                 }
    1115             : 
    1116             :                 /* Copy the comment */
    1117           0 :                 strlcpy(dest->comment, src->comment, remaining_len);
    1118             : 
    1119             :                 /* Save other fields */
    1120           0 :                 dest->smbc_type = src->smbc_type;
    1121           0 :                 dest->commentlen = strlen(dest->comment);
    1122           0 :                 dest->dirlen = ((dest->comment + dest->commentlen + 1) -
    1123             :                                 (char *) dest);
    1124             :         } else {
    1125             : 
    1126             :                 /* No encoding.  Just copy the entry as is. */
    1127        1270 :                 if (src->dirlen > max_namebuf_len) {
    1128           0 :                         return -1;
    1129             :                 }
    1130        1270 :                 memcpy(dest, src, src->dirlen);
    1131        1270 :                 if (src->namelen + 1 < 1) {
    1132             :                         /* Integer wrap */
    1133           0 :                         return -1;
    1134             :                 }
    1135        1270 :                 if (src->namelen + 1 >= max_namebuf_len) {
    1136             :                         /* Comment off the end. */
    1137           0 :                         return -1;
    1138             :                 }
    1139        1270 :                 dest->comment = (char *)(&dest->name + src->namelen + 1);
    1140             :         }
    1141        1270 :         return 0;
    1142             : }
    1143             : 
    1144             : /*
    1145             :  * Routine to get a directory entry
    1146             :  */
    1147             : 
    1148             : struct smbc_dirent *
    1149        1154 : SMBC_readdir_ctx(SMBCCTX *context,
    1150             :                  SMBCFILE *dir)
    1151             : {
    1152           0 :         int maxlen;
    1153           0 :         int ret;
    1154           0 :         struct smbc_dirent *dirp, *dirent;
    1155        1154 :         TALLOC_CTX *frame = talloc_stackframe();
    1156             : 
    1157             :         /* Check that all is ok first ... */
    1158             : 
    1159        1154 :         if (!context || !context->internal->initialized) {
    1160             : 
    1161           0 :                 errno = EINVAL;
    1162           0 :                 DEBUG(0, ("Invalid context in SMBC_readdir_ctx()\n"));
    1163           0 :                 TALLOC_FREE(frame);
    1164           0 :                 return NULL;
    1165             : 
    1166             :         }
    1167             : 
    1168        1154 :         if (!SMBC_dlist_contains(context->internal->files, dir)) {
    1169             : 
    1170           0 :                 errno = EBADF;
    1171           0 :                 DEBUG(0, ("Invalid dir in SMBC_readdir_ctx()\n"));
    1172           0 :                 TALLOC_FREE(frame);
    1173           0 :                 return NULL;
    1174             : 
    1175             :         }
    1176             : 
    1177        1154 :         if (dir->file != False) { /* FIXME, should be dir, perhaps */
    1178             : 
    1179           0 :                 errno = ENOTDIR;
    1180           0 :                 DEBUG(0, ("Found file vs directory in SMBC_readdir_ctx()\n"));
    1181           0 :                 TALLOC_FREE(frame);
    1182           0 :                 return NULL;
    1183             : 
    1184             :         }
    1185             : 
    1186        1154 :         if (!dir->dir_next) {
    1187          40 :                 TALLOC_FREE(frame);
    1188          40 :                 return NULL;
    1189             :         }
    1190             : 
    1191        1114 :         dirent = dir->dir_next->dirent;
    1192        1114 :         if (!dirent) {
    1193             : 
    1194           0 :                 errno = ENOENT;
    1195           0 :                 TALLOC_FREE(frame);
    1196           0 :                 return NULL;
    1197             : 
    1198             :         }
    1199             : 
    1200        1114 :         dirp = &context->internal->dirent;
    1201        1114 :         maxlen = sizeof(context->internal->_dirent_name);
    1202             : 
    1203        1114 :         ret = smbc_readdir_internal(context, dirp, dirent, maxlen);
    1204        1114 :         if (ret == -1) {
    1205           0 :                 errno = EINVAL;
    1206           0 :                 TALLOC_FREE(frame);
    1207           0 :                 return NULL;
    1208             :         }
    1209             : 
    1210        1114 :         dir->dir_next = dir->dir_next->next;
    1211             : 
    1212             :         /*
    1213             :          * If we are returning file entries, we
    1214             :          * have a duplicate list in dirplus.
    1215             :          *
    1216             :          * Update dirplus_next also so readdir and
    1217             :          * readdirplus are kept in sync.
    1218             :          */
    1219        1114 :         if (dir->dirplus_list != NULL) {
    1220         478 :                 dir->dirplus_next = dir->dirplus_next->next;
    1221             :         }
    1222             : 
    1223        1114 :         TALLOC_FREE(frame);
    1224        1114 :         return dirp;
    1225             : }
    1226             : 
    1227             : /*
    1228             :  * Routine to get a directory entry with all attributes
    1229             :  */
    1230             : 
    1231             : const struct libsmb_file_info *
    1232         739 : SMBC_readdirplus_ctx(SMBCCTX *context,
    1233             :                      SMBCFILE *dir)
    1234             : {
    1235         739 :         struct libsmb_file_info *smb_finfo = NULL;
    1236         739 :         TALLOC_CTX *frame = talloc_stackframe();
    1237             : 
    1238             :         /* Check that all is ok first ... */
    1239             : 
    1240         739 :         if (context == NULL || !context->internal->initialized) {
    1241           0 :                 DBG_ERR("Invalid context in SMBC_readdirplus_ctx()\n");
    1242           0 :                 TALLOC_FREE(frame);
    1243           0 :                 errno = EINVAL;
    1244           0 :                 return NULL;
    1245             :         }
    1246             : 
    1247         739 :         if (!SMBC_dlist_contains(context->internal->files, dir)) {
    1248           0 :                 DBG_ERR("Invalid dir in SMBC_readdirplus_ctx()\n");
    1249           0 :                 TALLOC_FREE(frame);
    1250           0 :                 errno = EBADF;
    1251           0 :                 return NULL;
    1252             :         }
    1253             : 
    1254         739 :         if (dir->dirplus_next == NULL) {
    1255           0 :                 TALLOC_FREE(frame);
    1256           0 :                 return NULL;
    1257             :         }
    1258             : 
    1259         739 :         smb_finfo = dir->dirplus_next->smb_finfo;
    1260         739 :         if (smb_finfo == NULL) {
    1261           0 :                 TALLOC_FREE(frame);
    1262           0 :                 errno = ENOENT;
    1263           0 :                 return NULL;
    1264             :         }
    1265         739 :         dir->dirplus_next = dir->dirplus_next->next;
    1266             : 
    1267             :         /*
    1268             :          * If we are returning file entries, we
    1269             :          * have a duplicate list in dir_list
    1270             :          *
    1271             :          * Update dir_next also so readdir and
    1272             :          * readdirplus are kept in sync.
    1273             :          */
    1274         739 :         if (dir->dir_list) {
    1275         739 :                 dir->dir_next = dir->dir_next->next;
    1276             :         }
    1277             : 
    1278         739 :         TALLOC_FREE(frame);
    1279         739 :         return smb_finfo;
    1280             : }
    1281             : 
    1282             : /*
    1283             :  * Routine to get a directory entry plus a filled in stat structure if
    1284             :  * requested.
    1285             :  */
    1286             : 
    1287         127 : const struct libsmb_file_info *SMBC_readdirplus2_ctx(SMBCCTX *context,
    1288             :                         SMBCFILE *dir,
    1289             :                         struct stat *st)
    1290             : {
    1291         127 :         struct libsmb_file_info *smb_finfo = NULL;
    1292         127 :         struct smbc_dirplus_list *dp_list = NULL;
    1293           0 :         ino_t ino;
    1294         127 :         char *full_pathname = NULL;
    1295         127 :         char *workgroup = NULL;
    1296         127 :         char *server = NULL;
    1297         127 :         uint16_t port = 0;
    1298         127 :         char *share = NULL;
    1299         127 :         char *path = NULL;
    1300         127 :         char *user = NULL;
    1301         127 :         char *password = NULL;
    1302         127 :         char *options = NULL;
    1303           0 :         int rc;
    1304         127 :         TALLOC_CTX *frame = NULL;
    1305             : 
    1306             :         /*
    1307             :          * Allow caller to pass in NULL for stat pointer if
    1308             :          * required. This makes this call identical to
    1309             :          * smbc_readdirplus().
    1310             :          */
    1311             : 
    1312         127 :         if (st == NULL) {
    1313           0 :                 return SMBC_readdirplus_ctx(context, dir);
    1314             :         }
    1315             : 
    1316         127 :         frame = talloc_stackframe();
    1317             : 
    1318             :         /* Check that all is ok first ... */
    1319         127 :         if (context == NULL || !context->internal->initialized) {
    1320           0 :                 DBG_ERR("Invalid context in SMBC_readdirplus2_ctx()\n");
    1321           0 :                 TALLOC_FREE(frame);
    1322           0 :                 errno = EINVAL;
    1323           0 :                 return NULL;
    1324             :         }
    1325             : 
    1326         127 :         if (!SMBC_dlist_contains(context->internal->files, dir)) {
    1327           0 :                 DBG_ERR("Invalid dir in SMBC_readdirplus2_ctx()\n");
    1328           0 :                 TALLOC_FREE(frame);
    1329           0 :                 errno = EBADF;
    1330           0 :                 return NULL;
    1331             :         }
    1332             : 
    1333         127 :         dp_list = dir->dirplus_next;
    1334         127 :         if (dp_list == NULL) {
    1335           0 :                 TALLOC_FREE(frame);
    1336           0 :                 return NULL;
    1337             :         }
    1338             : 
    1339         127 :         ino = (ino_t)dp_list->ino;
    1340             : 
    1341         127 :         smb_finfo = dp_list->smb_finfo;
    1342         127 :         if (smb_finfo == NULL) {
    1343           0 :                 TALLOC_FREE(frame);
    1344           0 :                 errno = ENOENT;
    1345           0 :                 return NULL;
    1346             :         }
    1347             : 
    1348         127 :         full_pathname = talloc_asprintf(frame,
    1349             :                                 "%s/%s",
    1350             :                                 dir->fname,
    1351             :                                 smb_finfo->name);
    1352         127 :         if (full_pathname == NULL) {
    1353           0 :                 TALLOC_FREE(frame);
    1354           0 :                 errno = ENOENT;
    1355           0 :                 return NULL;
    1356             :         }
    1357             : 
    1358         127 :         rc = SMBC_parse_path(frame,
    1359             :                              context,
    1360             :                              full_pathname,
    1361             :                              &workgroup,
    1362             :                              &server,
    1363             :                              &port,
    1364             :                              &share,
    1365             :                              &path,
    1366             :                              &user,
    1367             :                              &password,
    1368             :                              &options);
    1369         127 :         if (rc != 0) {
    1370           0 :                 TALLOC_FREE(frame);
    1371           0 :                 errno = ENOENT;
    1372           0 :                 return NULL;
    1373             :         }
    1374             : 
    1375         127 :         setup_stat(st,
    1376             :                 path,
    1377         127 :                 smb_finfo->size,
    1378         127 :                 smb_finfo->attrs,
    1379             :                 ino,
    1380         127 :                 dir->srv->dev,
    1381             :                 smb_finfo->atime_ts,
    1382             :                 smb_finfo->ctime_ts,
    1383             :                 smb_finfo->mtime_ts);
    1384             : 
    1385         127 :         TALLOC_FREE(full_pathname);
    1386             : 
    1387         127 :         dir->dirplus_next = dir->dirplus_next->next;
    1388             : 
    1389             :         /*
    1390             :          * If we are returning file entries, we
    1391             :          * have a duplicate list in dir_list
    1392             :          *
    1393             :          * Update dir_next also so readdir and
    1394             :          * readdirplus are kept in sync.
    1395             :          */
    1396         127 :         if (dir->dir_list) {
    1397         127 :                 dir->dir_next = dir->dir_next->next;
    1398             :         }
    1399             : 
    1400         127 :         TALLOC_FREE(frame);
    1401         127 :         return smb_finfo;
    1402             : }
    1403             : 
    1404             : /*
    1405             :  * Routine to get directory entries
    1406             :  */
    1407             : 
    1408             : int
    1409           8 : SMBC_getdents_ctx(SMBCCTX *context,
    1410             :                   SMBCFILE *dir,
    1411             :                   struct smbc_dirent *dirp,
    1412             :                   int count)
    1413             : {
    1414           8 :         int rem = count;
    1415           0 :         int reqd;
    1416           0 :         int maxlen;
    1417           8 :         char *ndir = (char *)dirp;
    1418           0 :         struct smbc_dir_list *dirlist;
    1419           8 :         TALLOC_CTX *frame = talloc_stackframe();
    1420             : 
    1421             :         /* Check that all is ok first ... */
    1422             : 
    1423           8 :         if (!context || !context->internal->initialized) {
    1424             : 
    1425           0 :                 errno = EINVAL;
    1426           0 :                 TALLOC_FREE(frame);
    1427           0 :                 return -1;
    1428             : 
    1429             :         }
    1430             : 
    1431           8 :         if (!SMBC_dlist_contains(context->internal->files, dir)) {
    1432             : 
    1433           0 :                 errno = EBADF;
    1434           0 :                 TALLOC_FREE(frame);
    1435           0 :                 return -1;
    1436             : 
    1437             :         }
    1438             : 
    1439           8 :         if (dir->file != False) { /* FIXME, should be dir, perhaps */
    1440             : 
    1441           0 :                 errno = ENOTDIR;
    1442           0 :                 TALLOC_FREE(frame);
    1443           0 :                 return -1;
    1444             : 
    1445             :         }
    1446             : 
    1447             :         /*
    1448             :          * Now, retrieve the number of entries that will fit in what was passed
    1449             :          * We have to figure out if the info is in the list, or we need to
    1450             :          * send a request to the server to get the info.
    1451             :          */
    1452             : 
    1453         156 :         while ((dirlist = dir->dir_next)) {
    1454           0 :                 int ret;
    1455           0 :                 struct smbc_dirent *dirent;
    1456         156 :                 struct smbc_dirent *currentEntry = (struct smbc_dirent *)ndir;
    1457             : 
    1458         156 :                 if (!dirlist->dirent) {
    1459             : 
    1460           0 :                         errno = ENOENT;  /* Bad error */
    1461           0 :                         TALLOC_FREE(frame);
    1462           0 :                         return -1;
    1463             : 
    1464             :                 }
    1465             : 
    1466             :                 /* Do urlencoding of next entry, if so selected */
    1467         156 :                 dirent = &context->internal->dirent;
    1468         156 :                 maxlen = sizeof(context->internal->_dirent_name);
    1469         156 :                 ret = smbc_readdir_internal(context, dirent,
    1470             :                                       dirlist->dirent, maxlen);
    1471         156 :                 if (ret == -1) {
    1472           0 :                         errno = EINVAL;
    1473           0 :                         TALLOC_FREE(frame);
    1474           0 :                         return -1;
    1475             :                 }
    1476             : 
    1477         156 :                 reqd = dirent->dirlen;
    1478             : 
    1479         156 :                 if (rem < reqd) {
    1480             : 
    1481           8 :                         if (rem < count) { /* We managed to copy something */
    1482             : 
    1483           8 :                                 errno = 0;
    1484           8 :                                 TALLOC_FREE(frame);
    1485           8 :                                 return count - rem;
    1486             : 
    1487             :                         }
    1488             :                         else { /* Nothing copied ... */
    1489             : 
    1490           0 :                                 errno = EINVAL;  /* Not enough space ... */
    1491           0 :                                 TALLOC_FREE(frame);
    1492           0 :                                 return -1;
    1493             : 
    1494             :                         }
    1495             : 
    1496             :                 }
    1497             : 
    1498         148 :                 memcpy(currentEntry, dirent, reqd); /* Copy the data in ... */
    1499             : 
    1500         148 :                 currentEntry->comment = &currentEntry->name[0] +
    1501         148 :                                                 dirent->namelen + 1;
    1502             : 
    1503         148 :                 ndir += reqd;
    1504         148 :                 rem -= reqd;
    1505             : 
    1506             :                 /* Try and align the struct for the next entry
    1507             :                    on a valid pointer boundary by appending zeros */
    1508        1080 :                 while((rem > 0) && ((uintptr_t)ndir & (sizeof(void*) - 1))) {
    1509         932 :                         *ndir = '\0';
    1510         932 :                         rem--;
    1511         932 :                         ndir++;
    1512         932 :                         currentEntry->dirlen++;
    1513             :                 }
    1514             : 
    1515         148 :                 dir->dir_next = dirlist = dirlist -> next;
    1516             : 
    1517             :                 /*
    1518             :                  * If we are returning file entries, we
    1519             :                  * have a duplicate list in dirplus.
    1520             :                  *
    1521             :                  * Update dirplus_next also so readdir and
    1522             :                  * readdirplus are kept in sync.
    1523             :                  */
    1524         148 :                 if (dir->dirplus_list != NULL) {
    1525         148 :                         dir->dirplus_next = dir->dirplus_next->next;
    1526             :                 }
    1527             :         }
    1528             : 
    1529           0 :         TALLOC_FREE(frame);
    1530             : 
    1531           0 :         if (rem == count)
    1532           0 :                 return 0;
    1533             :         else
    1534           0 :                 return count - rem;
    1535             : 
    1536             : }
    1537             : 
    1538             : /*
    1539             :  * Routine to create a directory ...
    1540             :  */
    1541             : 
    1542             : int
    1543           4 : SMBC_mkdir_ctx(SMBCCTX *context,
    1544             :                const char *fname,
    1545             :                mode_t mode)
    1546             : {
    1547           4 :         SMBCSRV *srv = NULL;
    1548           4 :         char *server = NULL;
    1549           4 :         char *share = NULL;
    1550           4 :         char *user = NULL;
    1551           4 :         char *password = NULL;
    1552           4 :         char *workgroup = NULL;
    1553           4 :         char *path = NULL;
    1554           4 :         char *targetpath = NULL;
    1555           4 :         uint16_t port = 0;
    1556           4 :         struct cli_state *targetcli = NULL;
    1557           4 :         struct cli_credentials *creds = NULL;
    1558           4 :         TALLOC_CTX *frame = talloc_stackframe();
    1559           0 :         NTSTATUS status;
    1560             : 
    1561           4 :         if (!context || !context->internal->initialized) {
    1562           0 :                 errno = EINVAL;
    1563           0 :                 TALLOC_FREE(frame);
    1564           0 :                 return -1;
    1565             :         }
    1566             : 
    1567           4 :         if (!fname) {
    1568           0 :                 errno = EINVAL;
    1569           0 :                 TALLOC_FREE(frame);
    1570           0 :                 return -1;
    1571             :         }
    1572             : 
    1573           4 :         DEBUG(4, ("smbc_mkdir(%s)\n", fname));
    1574             : 
    1575           4 :         if (SMBC_parse_path(frame,
    1576             :                             context,
    1577             :                             fname,
    1578             :                             &workgroup,
    1579             :                             &server,
    1580             :                             &port,
    1581             :                             &share,
    1582             :                             &path,
    1583             :                             &user,
    1584             :                             &password,
    1585             :                             NULL)) {
    1586           0 :                 errno = EINVAL;
    1587           0 :                 TALLOC_FREE(frame);
    1588           0 :                 return -1;
    1589             :         }
    1590             : 
    1591           4 :         if (!user || user[0] == (char)0) {
    1592           0 :                 user = talloc_strdup(frame, smbc_getUser(context));
    1593           0 :                 if (!user) {
    1594           0 :                         errno = ENOMEM;
    1595           0 :                         TALLOC_FREE(frame);
    1596           0 :                         return -1;
    1597             :                 }
    1598             :         }
    1599             : 
    1600           4 :         srv = SMBC_server(frame, context, True,
    1601             :                           server, port, share, &workgroup, &user, &password);
    1602             : 
    1603           4 :         if (!srv) {
    1604             : 
    1605           0 :                 TALLOC_FREE(frame);
    1606           0 :                 return -1;  /* errno set by SMBC_server */
    1607             : 
    1608             :         }
    1609             : 
    1610           4 :         creds = context->internal->creds;
    1611             : 
    1612             :         /*d_printf(">>>mkdir: resolving %s\n", path);*/
    1613           4 :         status = cli_resolve_path(frame, "",
    1614             :                                   creds,
    1615             :                                   srv->cli, path, &targetcli, &targetpath);
    1616           4 :         if (!NT_STATUS_IS_OK(status)) {
    1617           0 :                 d_printf("Could not resolve %s\n", path);
    1618           0 :                 errno = ENOENT;
    1619           0 :                 TALLOC_FREE(frame);
    1620           0 :                 return -1;
    1621             :         }
    1622             :         /*d_printf(">>>mkdir: resolved path as %s\n", targetpath);*/
    1623             : 
    1624           4 :         status = cli_mkdir(targetcli, targetpath);
    1625           4 :         if (!NT_STATUS_IS_OK(status)) {
    1626           0 :                 TALLOC_FREE(frame);
    1627           0 :                 errno = cli_status_to_errno(status);
    1628           0 :                 return -1;
    1629             : 
    1630             :         }
    1631             : 
    1632           4 :         TALLOC_FREE(frame);
    1633           4 :         return 0;
    1634             : 
    1635             : }
    1636             : 
    1637             : /*
    1638             :  * Our list function simply checks to see if a directory is not empty
    1639             :  */
    1640             : 
    1641             : static NTSTATUS
    1642           0 : rmdir_list_fn(struct file_info *finfo,
    1643             :               const char *mask,
    1644             :               void *state)
    1645             : {
    1646           0 :         if (strncmp(finfo->name, ".", 1) != 0 &&
    1647           0 :             strncmp(finfo->name, "..", 2) != 0) {
    1648           0 :                 bool *smbc_rmdir_dirempty = (bool *)state;
    1649           0 :                 *smbc_rmdir_dirempty = false;
    1650             :         }
    1651           0 :         return NT_STATUS_OK;
    1652             : }
    1653             : 
    1654             : /*
    1655             :  * Routine to remove a directory
    1656             :  */
    1657             : 
    1658             : int
    1659           8 : SMBC_rmdir_ctx(SMBCCTX *context,
    1660             :                const char *fname)
    1661             : {
    1662           8 :         SMBCSRV *srv = NULL;
    1663           8 :         char *server = NULL;
    1664           8 :         char *share = NULL;
    1665           8 :         char *user = NULL;
    1666           8 :         char *password = NULL;
    1667           8 :         char *workgroup = NULL;
    1668           8 :         char *path = NULL;
    1669           8 :         char *targetpath = NULL;
    1670           8 :         uint16_t port = 0;
    1671           8 :         struct cli_state *targetcli = NULL;
    1672           8 :         struct cli_credentials *creds = NULL;
    1673           8 :         TALLOC_CTX *frame = talloc_stackframe();
    1674           0 :         NTSTATUS status;
    1675             : 
    1676           8 :         if (!context || !context->internal->initialized) {
    1677           0 :                 errno = EINVAL;
    1678           0 :                 TALLOC_FREE(frame);
    1679           0 :                 return -1;
    1680             :         }
    1681             : 
    1682           8 :         if (!fname) {
    1683           0 :                 errno = EINVAL;
    1684           0 :                 TALLOC_FREE(frame);
    1685           0 :                 return -1;
    1686             :         }
    1687             : 
    1688           8 :         DEBUG(4, ("smbc_rmdir(%s)\n", fname));
    1689             : 
    1690           8 :         if (SMBC_parse_path(frame,
    1691             :                             context,
    1692             :                             fname,
    1693             :                             &workgroup,
    1694             :                             &server,
    1695             :                             &port,
    1696             :                             &share,
    1697             :                             &path,
    1698             :                             &user,
    1699             :                             &password,
    1700             :                             NULL)) {
    1701           0 :                 errno = EINVAL;
    1702           0 :                 TALLOC_FREE(frame);
    1703           0 :                 return -1;
    1704             :         }
    1705             : 
    1706           8 :         if (!user || user[0] == (char)0) {
    1707           0 :                 user = talloc_strdup(frame, smbc_getUser(context));
    1708           0 :                 if (!user) {
    1709           0 :                         errno = ENOMEM;
    1710           0 :                         TALLOC_FREE(frame);
    1711           0 :                         return -1;
    1712             :                 }
    1713             :         }
    1714             : 
    1715           8 :         srv = SMBC_server(frame, context, True,
    1716             :                           server, port, share, &workgroup, &user, &password);
    1717             : 
    1718           8 :         if (!srv) {
    1719             : 
    1720           0 :                 TALLOC_FREE(frame);
    1721           0 :                 return -1;  /* errno set by SMBC_server */
    1722             : 
    1723             :         }
    1724             : 
    1725           8 :         creds = context->internal->creds;
    1726             : 
    1727             :         /*d_printf(">>>rmdir: resolving %s\n", path);*/
    1728           8 :         status = cli_resolve_path(frame, "",
    1729             :                                   creds,
    1730             :                                   srv->cli, path, &targetcli, &targetpath);
    1731           8 :         if (!NT_STATUS_IS_OK(status)) {
    1732           0 :                 d_printf("Could not resolve %s\n", path);
    1733           0 :                 errno = ENOENT;
    1734           0 :                 TALLOC_FREE(frame);
    1735           0 :                 return -1;
    1736             :         }
    1737             :         /*d_printf(">>>rmdir: resolved path as %s\n", targetpath);*/
    1738             : 
    1739           8 :         status = cli_rmdir(targetcli, targetpath);
    1740             : 
    1741           8 :         if (!NT_STATUS_IS_OK(status)) {
    1742             : 
    1743           4 :                 errno = cli_status_to_errno(status);
    1744             : 
    1745           4 :                 if (errno == EACCES) {  /* Check if the dir empty or not */
    1746             : 
    1747             :                         /* Local storage to avoid buffer overflows */
    1748           0 :                         char *lpath;
    1749           0 :                         bool smbc_rmdir_dirempty = true;
    1750             : 
    1751           0 :                         lpath = talloc_asprintf(frame, "%s\\*",
    1752             :                                                 targetpath);
    1753           0 :                         if (!lpath) {
    1754           0 :                                 errno = ENOMEM;
    1755           0 :                                 TALLOC_FREE(frame);
    1756           0 :                                 return -1;
    1757             :                         }
    1758             : 
    1759           0 :                         status = cli_list(targetcli, lpath,
    1760             :                                           FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN,
    1761             :                                           rmdir_list_fn,
    1762             :                                           &smbc_rmdir_dirempty);
    1763             : 
    1764           0 :                         if (!NT_STATUS_IS_OK(status)) {
    1765             :                                 /* Fix errno to ignore latest error ... */
    1766           0 :                                 DBG_INFO("cli_list returned an error: %s\n",
    1767             :                                          nt_errstr(status));
    1768           0 :                                 errno = EACCES;
    1769             : 
    1770             :                         }
    1771             : 
    1772           0 :                         if (smbc_rmdir_dirempty)
    1773           0 :                                 errno = EACCES;
    1774             :                         else
    1775           0 :                                 errno = ENOTEMPTY;
    1776             : 
    1777             :                 }
    1778             : 
    1779           4 :                 TALLOC_FREE(frame);
    1780           4 :                 return -1;
    1781             : 
    1782             :         }
    1783             : 
    1784           4 :         TALLOC_FREE(frame);
    1785           4 :         return 0;
    1786             : 
    1787             : }
    1788             : 
    1789             : /*
    1790             :  * Routine to return the current directory position
    1791             :  */
    1792             : 
    1793             : off_t
    1794           8 : SMBC_telldir_ctx(SMBCCTX *context,
    1795             :                  SMBCFILE *dir)
    1796             : {
    1797           8 :         TALLOC_CTX *frame = talloc_stackframe();
    1798             : 
    1799           8 :         if (!context || !context->internal->initialized) {
    1800             : 
    1801           0 :                 errno = EINVAL;
    1802           0 :                 TALLOC_FREE(frame);
    1803           0 :                 return -1;
    1804             : 
    1805             :         }
    1806             : 
    1807           8 :         if (!SMBC_dlist_contains(context->internal->files, dir)) {
    1808             : 
    1809           0 :                 errno = EBADF;
    1810           0 :                 TALLOC_FREE(frame);
    1811           0 :                 return -1;
    1812             : 
    1813             :         }
    1814             : 
    1815           8 :         if (dir->file != False) { /* FIXME, should be dir, perhaps */
    1816             : 
    1817           0 :                 errno = ENOTDIR;
    1818           0 :                 TALLOC_FREE(frame);
    1819           0 :                 return -1;
    1820             : 
    1821             :         }
    1822             : 
    1823             :         /* See if we're already at the end. */
    1824           8 :         if (dir->dir_next == NULL) {
    1825             :                 /* We are. */
    1826           0 :                 TALLOC_FREE(frame);
    1827           0 :                 return -1;
    1828             :         }
    1829             : 
    1830             :         /*
    1831             :          * We return the pointer here as the offset
    1832             :          */
    1833           8 :         TALLOC_FREE(frame);
    1834           8 :         return (off_t)(long)dir->dir_next->dirent;
    1835             : }
    1836             : 
    1837             : /*
    1838             :  * A routine to run down the list and see if the entry is OK
    1839             :  * Modifies the dir list and the dirplus list (if it exists)
    1840             :  * to point at the correct next entry on success.
    1841             :  */
    1842             : 
    1843          16 : static bool update_dir_ents(SMBCFILE *dir, struct smbc_dirent *dirent)
    1844             : {
    1845          16 :         struct smbc_dir_list *tmp_dir = dir->dir_list;
    1846          16 :         struct smbc_dirplus_list *tmp_dirplus = dir->dirplus_list;
    1847             : 
    1848             :         /*
    1849             :          * Run down the list looking for what we want.
    1850             :          * If we're enumerating files both dir_list
    1851             :          * and dirplus_list contain the same entry
    1852             :          * list, as they were seeded from the same
    1853             :          * cli_list callback.
    1854             :          *
    1855             :          * If we're enumerating servers then
    1856             :          * dirplus_list will be NULL, so don't
    1857             :          * update in that case.
    1858             :          */
    1859             : 
    1860         448 :         while (tmp_dir != NULL) {
    1861         448 :                 if (tmp_dir->dirent == dirent) {
    1862          16 :                         dir->dir_next = tmp_dir;
    1863          16 :                         if (tmp_dirplus != NULL) {
    1864          16 :                                 dir->dirplus_next = tmp_dirplus;
    1865             :                         }
    1866          16 :                         return true;
    1867             :                 }
    1868         432 :                 tmp_dir = tmp_dir->next;
    1869         432 :                 if (tmp_dirplus != NULL) {
    1870         432 :                         tmp_dirplus = tmp_dirplus->next;
    1871             :                 }
    1872             :         }
    1873           0 :         return false;
    1874             : }
    1875             : 
    1876             : /*
    1877             :  * Routine to seek on a directory
    1878             :  */
    1879             : 
    1880             : int
    1881          20 : SMBC_lseekdir_ctx(SMBCCTX *context,
    1882             :                   SMBCFILE *dir,
    1883             :                   off_t offset)
    1884             : {
    1885          20 :         long int l_offset = offset;  /* Handle problems of size */
    1886          20 :         struct smbc_dirent *dirent = (struct smbc_dirent *)l_offset;
    1887          20 :         TALLOC_CTX *frame = talloc_stackframe();
    1888           0 :         bool ok;
    1889             : 
    1890          20 :         if (!context || !context->internal->initialized) {
    1891             : 
    1892           0 :                 errno = EINVAL;
    1893           0 :                 TALLOC_FREE(frame);
    1894           0 :                 return -1;
    1895             : 
    1896             :         }
    1897             : 
    1898          20 :         if (dir->file != False) { /* FIXME, should be dir, perhaps */
    1899             : 
    1900           0 :                 errno = ENOTDIR;
    1901           0 :                 TALLOC_FREE(frame);
    1902           0 :                 return -1;
    1903             : 
    1904             :         }
    1905             : 
    1906             :         /* Now, check what we were passed and see if it is OK ... */
    1907             : 
    1908          20 :         if (dirent == NULL) {  /* Seek to the beginning of the list */
    1909             : 
    1910           4 :                 dir->dir_next = dir->dir_list;
    1911             : 
    1912             :                 /* Do the same for dirplus. */
    1913           4 :                 dir->dirplus_next = dir->dirplus_list;
    1914             : 
    1915           4 :                 TALLOC_FREE(frame);
    1916           4 :                 return 0;
    1917             : 
    1918             :         }
    1919             : 
    1920          16 :         if (offset == -1) {     /* Seek to the end of the list */
    1921           0 :                 dir->dir_next = NULL;
    1922             : 
    1923             :                 /* Do the same for dirplus. */
    1924           0 :                 dir->dirplus_next = NULL;
    1925             : 
    1926           0 :                 TALLOC_FREE(frame);
    1927           0 :                 return 0;
    1928             :         }
    1929             : 
    1930             :         /*
    1931             :          * Run down the list and make sure that the entry is OK.
    1932             :          * Update the position of both dir and dirplus lists.
    1933             :          */
    1934             : 
    1935          16 :         ok = update_dir_ents(dir, dirent);
    1936          16 :         if (!ok) {
    1937           0 :                 errno = EINVAL;   /* Bad entry */
    1938           0 :                 TALLOC_FREE(frame);
    1939           0 :                 return -1;
    1940             :         }
    1941             : 
    1942          16 :         TALLOC_FREE(frame);
    1943          16 :         return 0;
    1944             : }
    1945             : 
    1946             : /*
    1947             :  * Routine to fstat a dir
    1948             :  */
    1949             : 
    1950             : int
    1951           0 : SMBC_fstatdir_ctx(SMBCCTX *context,
    1952             :                   SMBCFILE *dir,
    1953             :                   struct stat *st)
    1954             : {
    1955             : 
    1956           0 :         if (!context || !context->internal->initialized) {
    1957             : 
    1958           0 :                 errno = EINVAL;
    1959           0 :                 return -1;
    1960             :         }
    1961             : 
    1962             :         /* No code yet ... */
    1963           0 :         return 0;
    1964             : }
    1965             : 
    1966             : int
    1967           0 : SMBC_chmod_ctx(SMBCCTX *context,
    1968             :                const char *fname,
    1969             :                mode_t newmode)
    1970             : {
    1971           0 :         SMBCSRV *srv = NULL;
    1972           0 :         char *server = NULL;
    1973           0 :         char *share = NULL;
    1974           0 :         char *user = NULL;
    1975           0 :         char *password = NULL;
    1976           0 :         char *workgroup = NULL;
    1977           0 :         char *targetpath = NULL;
    1978           0 :         struct cli_state *targetcli = NULL;
    1979           0 :         char *path = NULL;
    1980           0 :         uint32_t attr;
    1981           0 :         uint16_t port = 0;
    1982           0 :         struct cli_credentials *creds = NULL;
    1983           0 :         TALLOC_CTX *frame = talloc_stackframe();
    1984           0 :         NTSTATUS status;
    1985             : 
    1986           0 :         if (!context || !context->internal->initialized) {
    1987             : 
    1988           0 :                 errno = EINVAL;  /* Best I can think of ... */
    1989           0 :                 TALLOC_FREE(frame);
    1990           0 :                 return -1;
    1991             :         }
    1992             : 
    1993           0 :         if (!fname) {
    1994           0 :                 errno = EINVAL;
    1995           0 :                 TALLOC_FREE(frame);
    1996           0 :                 return -1;
    1997             :         }
    1998             : 
    1999           0 :         DEBUG(4, ("smbc_chmod(%s, 0%3o)\n", fname, (unsigned int)newmode));
    2000             : 
    2001           0 :         if (SMBC_parse_path(frame,
    2002             :                             context,
    2003             :                             fname,
    2004             :                             &workgroup,
    2005             :                             &server,
    2006             :                             &port,
    2007             :                             &share,
    2008             :                             &path,
    2009             :                             &user,
    2010             :                             &password,
    2011             :                             NULL)) {
    2012           0 :                 errno = EINVAL;
    2013           0 :                 TALLOC_FREE(frame);
    2014           0 :                 return -1;
    2015             :         }
    2016             : 
    2017           0 :         if (!user || user[0] == (char)0) {
    2018           0 :                 user = talloc_strdup(frame, smbc_getUser(context));
    2019           0 :                 if (!user) {
    2020           0 :                         errno = ENOMEM;
    2021           0 :                         TALLOC_FREE(frame);
    2022           0 :                         return -1;
    2023             :                 }
    2024             :         }
    2025             : 
    2026           0 :         srv = SMBC_server(frame, context, True,
    2027             :                           server, port, share, &workgroup, &user, &password);
    2028             : 
    2029           0 :         if (!srv) {
    2030           0 :                 TALLOC_FREE(frame);
    2031           0 :                 return -1;  /* errno set by SMBC_server */
    2032             :         }
    2033             :         
    2034           0 :         creds = context->internal->creds;
    2035             : 
    2036             :         /*d_printf(">>>unlink: resolving %s\n", path);*/
    2037           0 :         status = cli_resolve_path(frame, "",
    2038             :                                   creds,
    2039             :                                   srv->cli, path, &targetcli, &targetpath);
    2040           0 :         if (!NT_STATUS_IS_OK(status)) {
    2041           0 :                 d_printf("Could not resolve %s\n", path);
    2042           0 :                 errno = ENOENT;
    2043           0 :                 TALLOC_FREE(frame);
    2044           0 :                 return -1;
    2045             :         }
    2046             : 
    2047           0 :         attr = 0;
    2048             : 
    2049           0 :         if (!(newmode & (S_IWUSR | S_IWGRP | S_IWOTH))) attr |= FILE_ATTRIBUTE_READONLY;
    2050           0 :         if ((newmode & S_IXUSR) && lp_map_archive(-1)) attr |= FILE_ATTRIBUTE_ARCHIVE;
    2051           0 :         if ((newmode & S_IXGRP) && lp_map_system(-1)) attr |= FILE_ATTRIBUTE_SYSTEM;
    2052           0 :         if ((newmode & S_IXOTH) && lp_map_hidden(-1)) attr |= FILE_ATTRIBUTE_HIDDEN;
    2053             : 
    2054           0 :         status = cli_setatr(targetcli, targetpath, attr, 0);
    2055           0 :         if (!NT_STATUS_IS_OK(status)) {
    2056           0 :                 TALLOC_FREE(frame);
    2057           0 :                 errno = cli_status_to_errno(status);
    2058           0 :                 return -1;
    2059             :         }
    2060             : 
    2061           0 :         TALLOC_FREE(frame);
    2062           0 :         return 0;
    2063             : }
    2064             : 
    2065             : int
    2066           4 : SMBC_utimes_ctx(SMBCCTX *context,
    2067             :                 const char *fname,
    2068             :                 struct timeval *tbuf)
    2069             : {
    2070           4 :         SMBCSRV *srv = NULL;
    2071           4 :         char *server = NULL;
    2072           4 :         char *share = NULL;
    2073           4 :         char *user = NULL;
    2074           4 :         char *password = NULL;
    2075           4 :         char *workgroup = NULL;
    2076           4 :         char *path = NULL;
    2077           0 :         struct timespec access_time, write_time;
    2078           4 :         uint16_t port = 0;
    2079           4 :         TALLOC_CTX *frame = talloc_stackframe();
    2080           0 :         bool ok;
    2081             : 
    2082           4 :         if (!context || !context->internal->initialized) {
    2083             : 
    2084           0 :                 errno = EINVAL;  /* Best I can think of ... */
    2085           0 :                 TALLOC_FREE(frame);
    2086           0 :                 return -1;
    2087             :         }
    2088             : 
    2089           4 :         if (!fname) {
    2090           0 :                 errno = EINVAL;
    2091           0 :                 TALLOC_FREE(frame);
    2092           0 :                 return -1;
    2093             :         }
    2094             : 
    2095           4 :         if (tbuf == NULL) {
    2096           0 :                 access_time = write_time = timespec_current();
    2097             :         } else {
    2098           4 :                 access_time = convert_timeval_to_timespec(tbuf[0]);
    2099           4 :                 write_time = convert_timeval_to_timespec(tbuf[1]);
    2100             :         }
    2101             : 
    2102           4 :         if (DEBUGLVL(4)) {
    2103           0 :                 struct timeval_buf abuf, wbuf;
    2104             : 
    2105           0 :                 dbgtext("smbc_utimes(%s, atime = %s mtime = %s)\n",
    2106             :                         fname,
    2107             :                         timespec_string_buf(&access_time, false, &abuf),
    2108             :                         timespec_string_buf(&write_time, false, &wbuf));
    2109             :         }
    2110             : 
    2111           4 :         if (SMBC_parse_path(frame,
    2112             :                             context,
    2113             :                             fname,
    2114             :                             &workgroup,
    2115             :                             &server,
    2116             :                             &port,
    2117             :                             &share,
    2118             :                             &path,
    2119             :                             &user,
    2120             :                             &password,
    2121             :                             NULL)) {
    2122           0 :                 errno = EINVAL;
    2123           0 :                 TALLOC_FREE(frame);
    2124           0 :                 return -1;
    2125             :         }
    2126             : 
    2127           4 :         if (!user || user[0] == (char)0) {
    2128           0 :                 user = talloc_strdup(frame, smbc_getUser(context));
    2129           0 :                 if (!user) {
    2130           0 :                         errno = ENOMEM;
    2131           0 :                         TALLOC_FREE(frame);
    2132           0 :                         return -1;
    2133             :                 }
    2134             :         }
    2135             : 
    2136           4 :         srv = SMBC_server(frame, context, True,
    2137             :                           server, port, share, &workgroup, &user, &password);
    2138             : 
    2139           4 :         if (!srv) {
    2140           0 :                 TALLOC_FREE(frame);
    2141           0 :                 return -1;      /* errno set by SMBC_server */
    2142             :         }
    2143             : 
    2144           4 :         ok = SMBC_setatr(
    2145             :                 context,
    2146             :                 srv,
    2147             :                 path,
    2148           4 :                 (struct timespec) { .tv_nsec = SAMBA_UTIME_OMIT },
    2149             :                 access_time,
    2150             :                 write_time,
    2151           4 :                 (struct timespec) { .tv_nsec = SAMBA_UTIME_OMIT },
    2152             :                 0);
    2153           4 :         if (!ok) {
    2154           0 :                 TALLOC_FREE(frame);
    2155           0 :                 return -1;      /* errno set by SMBC_setatr */
    2156             :         }
    2157             : 
    2158           4 :         TALLOC_FREE(frame);
    2159           4 :         return 0;
    2160             : }
    2161             : 
    2162             : /*
    2163             :  * Routine to unlink() a file
    2164             :  */
    2165             : 
    2166             : int
    2167         848 : SMBC_unlink_ctx(SMBCCTX *context,
    2168             :                 const char *fname)
    2169             : {
    2170         848 :         char *server = NULL;
    2171         848 :         char *share = NULL;
    2172         848 :         char *user = NULL;
    2173         848 :         char *password = NULL;
    2174         848 :         char *workgroup = NULL;
    2175         848 :         char *path = NULL;
    2176         848 :         char *targetpath = NULL;
    2177         848 :         uint16_t port = 0;
    2178         848 :         struct cli_state *targetcli = NULL;
    2179         848 :         SMBCSRV *srv = NULL;
    2180         848 :         struct cli_credentials *creds = NULL;
    2181         848 :         TALLOC_CTX *frame = talloc_stackframe();
    2182           0 :         NTSTATUS status;
    2183             : 
    2184         848 :         if (!context || !context->internal->initialized) {
    2185             : 
    2186           0 :                 errno = EINVAL;  /* Best I can think of ... */
    2187           0 :                 TALLOC_FREE(frame);
    2188           0 :                 return -1;
    2189             : 
    2190             :         }
    2191             : 
    2192         848 :         if (!fname) {
    2193           0 :                 errno = EINVAL;
    2194           0 :                 TALLOC_FREE(frame);
    2195           0 :                 return -1;
    2196             : 
    2197             :         }
    2198             : 
    2199         848 :         if (SMBC_parse_path(frame,
    2200             :                             context,
    2201             :                             fname,
    2202             :                             &workgroup,
    2203             :                             &server,
    2204             :                             &port,
    2205             :                             &share,
    2206             :                             &path,
    2207             :                             &user,
    2208             :                             &password,
    2209             :                             NULL)) {
    2210           0 :                 errno = EINVAL;
    2211           0 :                 TALLOC_FREE(frame);
    2212           0 :                 return -1;
    2213             :         }
    2214             : 
    2215         848 :         if (!user || user[0] == (char)0) {
    2216           0 :                 user = talloc_strdup(frame, smbc_getUser(context));
    2217           0 :                 if (!user) {
    2218           0 :                         errno = ENOMEM;
    2219           0 :                         TALLOC_FREE(frame);
    2220           0 :                         return -1;
    2221             :                 }
    2222             :         }
    2223             : 
    2224         848 :         srv = SMBC_server(frame, context, True,
    2225             :                           server, port, share, &workgroup, &user, &password);
    2226             : 
    2227         848 :         if (!srv) {
    2228           0 :                 TALLOC_FREE(frame);
    2229           0 :                 return -1;  /* SMBC_server sets errno */
    2230             : 
    2231             :         }
    2232             : 
    2233         848 :         creds = context->internal->creds;
    2234             : 
    2235             :         /*d_printf(">>>unlink: resolving %s\n", path);*/
    2236         848 :         status = cli_resolve_path(frame, "",
    2237             :                                   creds,
    2238             :                                   srv->cli, path, &targetcli, &targetpath);
    2239         848 :         if (!NT_STATUS_IS_OK(status)) {
    2240           0 :                 d_printf("Could not resolve %s\n", path);
    2241           0 :                 errno = ENOENT;
    2242           0 :                 TALLOC_FREE(frame);
    2243           0 :                 return -1;
    2244             :         }
    2245             :         /*d_printf(">>>unlink: resolved path as %s\n", targetpath);*/
    2246             : 
    2247         848 :         status = cli_unlink(
    2248             :                 targetcli,
    2249             :                 targetpath,
    2250             :                 FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN);
    2251             : 
    2252         848 :         if (!NT_STATUS_IS_OK(status)) {
    2253             : 
    2254         428 :                 errno = cli_status_to_errno(status);
    2255             : 
    2256         428 :                 if (errno == EACCES) { /* Check if the file is a directory */
    2257             : 
    2258           0 :                         int saverr = errno;
    2259           0 :                         struct stat sb = {0};
    2260             : 
    2261           0 :                         status = SMBC_getatr(context, srv, path, &sb);
    2262           0 :                         if (!NT_STATUS_IS_OK(status)) {
    2263             :                                 /* Hmmm, bad error ... What? */
    2264             : 
    2265           0 :                                 TALLOC_FREE(frame);
    2266           0 :                                 errno = cli_status_to_errno(status);
    2267           0 :                                 return -1;
    2268             : 
    2269             :                         }
    2270             :                         else {
    2271             : 
    2272           0 :                                 if (S_ISDIR(sb.st_mode))
    2273           0 :                                         errno = EISDIR;
    2274             :                                 else
    2275           0 :                                         errno = saverr;  /* Restore this */
    2276             : 
    2277             :                         }
    2278             :                 }
    2279             : 
    2280         428 :                 TALLOC_FREE(frame);
    2281         428 :                 return -1;
    2282             : 
    2283             :         }
    2284             : 
    2285         420 :         TALLOC_FREE(frame);
    2286         420 :         return 0;  /* Success ... */
    2287             : 
    2288             : }
    2289             : 
    2290             : /*
    2291             :  * Routine to rename() a file
    2292             :  */
    2293             : 
    2294             : int
    2295           4 : SMBC_rename_ctx(SMBCCTX *ocontext,
    2296             :                 const char *oname,
    2297             :                 SMBCCTX *ncontext,
    2298             :                 const char *nname)
    2299             : {
    2300           4 :         char *server1 = NULL;
    2301           4 :         char *share1 = NULL;
    2302           4 :         char *server2 = NULL;
    2303           4 :         char *share2 = NULL;
    2304           4 :         char *user1 = NULL;
    2305           4 :         char *user2 = NULL;
    2306           4 :         char *password1 = NULL;
    2307           4 :         char *password2 = NULL;
    2308           4 :         char *workgroup = NULL;
    2309           4 :         char *path1 = NULL;
    2310           4 :         char *path2 = NULL;
    2311           4 :         char *targetpath1 = NULL;
    2312           4 :         char *targetpath2 = NULL;
    2313           4 :         struct cli_state *targetcli1 = NULL;
    2314           4 :         struct cli_state *targetcli2 = NULL;
    2315           4 :         SMBCSRV *srv = NULL;
    2316           4 :         uint16_t port1 = 0;
    2317           4 :         uint16_t port2 = 0;
    2318           4 :         struct cli_credentials *ocreds = NULL;
    2319           4 :         struct cli_credentials *ncreds = NULL;
    2320           4 :         TALLOC_CTX *frame = talloc_stackframe();
    2321           0 :         NTSTATUS status;
    2322             : 
    2323           4 :         if (!ocontext || !ncontext ||
    2324           4 :             !ocontext->internal->initialized ||
    2325           4 :             !ncontext->internal->initialized) {
    2326             : 
    2327           0 :                 errno = EINVAL;  /* Best I can think of ... */
    2328           0 :                 TALLOC_FREE(frame);
    2329           0 :                 return -1;
    2330             :         }
    2331             : 
    2332           4 :         if (!oname || !nname) {
    2333           0 :                 errno = EINVAL;
    2334           0 :                 TALLOC_FREE(frame);
    2335           0 :                 return -1;
    2336             :         }
    2337             : 
    2338           4 :         DEBUG(4, ("smbc_rename(%s,%s)\n", oname, nname));
    2339             : 
    2340           4 :         if (SMBC_parse_path(frame,
    2341             :                             ocontext,
    2342             :                             oname,
    2343             :                             &workgroup,
    2344             :                             &server1,
    2345             :                             &port1,
    2346             :                             &share1,
    2347             :                             &path1,
    2348             :                             &user1,
    2349             :                             &password1,
    2350             :                             NULL)) {
    2351           0 :                 errno = EINVAL;
    2352           0 :                 TALLOC_FREE(frame);
    2353           0 :                 return -1;
    2354             :         }
    2355             : 
    2356           4 :         if (!user1 || user1[0] == (char)0) {
    2357           0 :                 user1 = talloc_strdup(frame, smbc_getUser(ocontext));
    2358           0 :                 if (!user1) {
    2359           0 :                         errno = ENOMEM;
    2360           0 :                         TALLOC_FREE(frame);
    2361           0 :                         return -1;
    2362             :                 }
    2363             :         }
    2364             : 
    2365           4 :         if (SMBC_parse_path(frame,
    2366             :                             ncontext,
    2367             :                             nname,
    2368             :                             NULL,
    2369             :                             &server2,
    2370             :                             &port2,
    2371             :                             &share2,
    2372             :                             &path2,
    2373             :                             &user2,
    2374             :                             &password2,
    2375             :                             NULL)) {
    2376           0 :                 errno = EINVAL;
    2377           0 :                 TALLOC_FREE(frame);
    2378           0 :                 return -1;
    2379             :         }
    2380             : 
    2381           4 :         if (!user2 || user2[0] == (char)0) {
    2382           0 :                 user2 = talloc_strdup(frame, smbc_getUser(ncontext));
    2383           0 :                 if (!user2) {
    2384           0 :                         errno = ENOMEM;
    2385           0 :                         TALLOC_FREE(frame);
    2386           0 :                         return -1;
    2387             :                 }
    2388             :         }
    2389             : 
    2390           4 :         if (strcmp(server1, server2) || strcmp(share1, share2) ||
    2391           4 :             strcmp(user1, user2)) {
    2392             :                 /* Can't rename across file systems, or users?? */
    2393           0 :                 errno = EXDEV;
    2394           0 :                 TALLOC_FREE(frame);
    2395           0 :                 return -1;
    2396             :         }
    2397             : 
    2398           4 :         srv = SMBC_server(frame, ocontext, True,
    2399             :                           server1, port1, share1, &workgroup, &user1, &password1);
    2400           4 :         if (!srv) {
    2401           0 :                 TALLOC_FREE(frame);
    2402           0 :                 return -1;
    2403             : 
    2404             :         }
    2405             : 
    2406             :         /* set the credentials to make DFS work */
    2407           4 :         smbc_set_credentials_with_fallback(ocontext,
    2408             :                                            workgroup,
    2409             :                                            user1,
    2410             :                                            password1);
    2411             : 
    2412             :         /*d_printf(">>>rename: resolving %s\n", path1);*/
    2413           4 :         ocreds = ocontext->internal->creds;
    2414             : 
    2415           4 :         status = cli_resolve_path(frame, "",
    2416             :                                   ocreds,
    2417             :                                   srv->cli, path1, &targetcli1, &targetpath1);
    2418           4 :         if (!NT_STATUS_IS_OK(status)) {
    2419           0 :                 d_printf("Could not resolve %s\n", path1);
    2420           0 :                 errno = ENOENT;
    2421           0 :                 TALLOC_FREE(frame);
    2422           0 :                 return -1;
    2423             :         }
    2424             :         
    2425             :         /* set the credentials to make DFS work */
    2426           4 :         smbc_set_credentials_with_fallback(ncontext,
    2427             :                                            workgroup,
    2428             :                                            user2,
    2429             :                                            password2);
    2430             :         
    2431             :         /*d_printf(">>>rename: resolved path as %s\n", targetpath1);*/
    2432             :         /*d_printf(">>>rename: resolving %s\n", path2);*/
    2433           4 :         ncreds = ncontext->internal->creds;
    2434             : 
    2435           4 :         status = cli_resolve_path(frame, "",
    2436             :                                   ncreds,
    2437             :                                   srv->cli, path2, &targetcli2, &targetpath2);
    2438           4 :         if (!NT_STATUS_IS_OK(status)) {
    2439           0 :                 d_printf("Could not resolve %s\n", path2);
    2440           0 :                 errno = ENOENT;
    2441           0 :                 TALLOC_FREE(frame);
    2442           0 :                 return -1;
    2443             :         }
    2444             :         /*d_printf(">>>rename: resolved path as %s\n", targetpath2);*/
    2445             : 
    2446           4 :         if (strcmp(smbXcli_conn_remote_name(targetcli1->conn), smbXcli_conn_remote_name(targetcli2->conn)) ||
    2447           4 :             strcmp(targetcli1->share, targetcli2->share))
    2448             :         {
    2449             :                 /* can't rename across file systems */
    2450           0 :                 errno = EXDEV;
    2451           0 :                 TALLOC_FREE(frame);
    2452           0 :                 return -1;
    2453             :         }
    2454             : 
    2455           4 :         status = cli_rename(targetcli1, targetpath1, targetpath2, false);
    2456           4 :         if (!NT_STATUS_IS_OK(status)) {
    2457           4 :                 int eno = cli_status_to_errno(status);
    2458             : 
    2459           4 :                 if (eno != EEXIST ||
    2460           4 :                     !NT_STATUS_IS_OK(cli_unlink(targetcli1, targetpath2,
    2461             :                                                 FILE_ATTRIBUTE_SYSTEM |
    2462           4 :                                                     FILE_ATTRIBUTE_HIDDEN)) ||
    2463           4 :                     !NT_STATUS_IS_OK(cli_rename(targetcli1, targetpath1,
    2464             :                                                 targetpath2, false))) {
    2465             : 
    2466           0 :                         errno = eno;
    2467           0 :                         TALLOC_FREE(frame);
    2468           0 :                         return -1;
    2469             : 
    2470             :                 }
    2471             :         }
    2472             : 
    2473           4 :         TALLOC_FREE(frame);
    2474           4 :         return 0; /* Success */
    2475             : }
    2476             : 
    2477             : struct smbc_notify_cb_state {
    2478             :         struct tevent_context *ev;
    2479             :         struct cli_state *cli;
    2480             :         uint16_t fnum;
    2481             :         bool recursive;
    2482             :         uint32_t completion_filter;
    2483             :         unsigned callback_timeout_ms;
    2484             :         smbc_notify_callback_fn cb;
    2485             :         void *private_data;
    2486             : };
    2487             : 
    2488             : static void smbc_notify_cb_got_changes(struct tevent_req *subreq);
    2489             : static void smbc_notify_cb_timedout(struct tevent_req *subreq);
    2490             : 
    2491           0 : static struct tevent_req *smbc_notify_cb_send(
    2492             :         TALLOC_CTX *mem_ctx, struct tevent_context *ev, struct cli_state *cli,
    2493             :         uint16_t fnum, bool recursive, uint32_t completion_filter,
    2494             :         unsigned callback_timeout_ms,
    2495             :         smbc_notify_callback_fn cb, void *private_data)
    2496             : {
    2497           0 :         struct tevent_req *req, *subreq;
    2498           0 :         struct smbc_notify_cb_state *state;
    2499             : 
    2500           0 :         req = tevent_req_create(mem_ctx, &state, struct smbc_notify_cb_state);
    2501           0 :         if (req == NULL) {
    2502           0 :                 return NULL;
    2503             :         }
    2504           0 :         state->ev = ev;
    2505           0 :         state->cli = cli;
    2506           0 :         state->fnum = fnum;
    2507           0 :         state->recursive = recursive;
    2508           0 :         state->completion_filter = completion_filter;
    2509           0 :         state->callback_timeout_ms = callback_timeout_ms;
    2510           0 :         state->cb = cb;
    2511           0 :         state->private_data = private_data;
    2512             : 
    2513           0 :         subreq = cli_notify_send(
    2514           0 :                 state, state->ev, state->cli, state->fnum, 1000,
    2515           0 :                 state->completion_filter, state->recursive);
    2516           0 :         if (tevent_req_nomem(subreq, req)) {
    2517           0 :                 return tevent_req_post(req, ev);
    2518             :         }
    2519           0 :         tevent_req_set_callback(subreq, smbc_notify_cb_got_changes, req);
    2520             : 
    2521           0 :         if (state->callback_timeout_ms == 0) {
    2522           0 :                 return req;
    2523             :         }
    2524             : 
    2525           0 :         subreq = tevent_wakeup_send(
    2526           0 :                 state, state->ev,
    2527           0 :                 tevent_timeval_current_ofs(state->callback_timeout_ms/1000,
    2528           0 :                                            state->callback_timeout_ms*1000));
    2529           0 :         if (tevent_req_nomem(subreq, req)) {
    2530           0 :                 return tevent_req_post(req, ev);
    2531             :         }
    2532           0 :         tevent_req_set_callback(subreq, smbc_notify_cb_timedout, req);
    2533             : 
    2534           0 :         return req;
    2535             : }
    2536             : 
    2537           0 : static void smbc_notify_cb_got_changes(struct tevent_req *subreq)
    2538             : {
    2539           0 :         struct tevent_req *req = tevent_req_callback_data(
    2540             :                 subreq, struct tevent_req);
    2541           0 :         struct smbc_notify_cb_state *state = tevent_req_data(
    2542             :                 req, struct smbc_notify_cb_state);
    2543           0 :         uint32_t num_changes;
    2544           0 :         struct notify_change *changes;
    2545           0 :         NTSTATUS status;
    2546           0 :         int cb_ret;
    2547             : 
    2548           0 :         status = cli_notify_recv(subreq, state, &num_changes, &changes);
    2549           0 :         TALLOC_FREE(subreq);
    2550           0 :         if (tevent_req_nterror(req, status)) {
    2551           0 :                 return;
    2552             :         }
    2553             : 
    2554           0 :         {
    2555           0 :                 struct smbc_notify_callback_action actions[num_changes];
    2556           0 :                 uint32_t i;
    2557             : 
    2558           0 :                 for (i=0; i<num_changes; i++) {
    2559           0 :                         actions[i].action = changes[i].action;
    2560           0 :                         actions[i].filename = changes[i].name;
    2561             :                 }
    2562             : 
    2563           0 :                 cb_ret = state->cb(actions, num_changes, state->private_data);
    2564             :         }
    2565             : 
    2566           0 :         TALLOC_FREE(changes);
    2567             : 
    2568           0 :         if (cb_ret != 0) {
    2569           0 :                 tevent_req_done(req);
    2570           0 :                 return;
    2571             :         }
    2572             : 
    2573           0 :         subreq = cli_notify_send(
    2574           0 :                 state, state->ev, state->cli, state->fnum, 1000,
    2575           0 :                 state->completion_filter, state->recursive);
    2576           0 :         if (tevent_req_nomem(subreq, req)) {
    2577           0 :                 return;
    2578             :         }
    2579           0 :         tevent_req_set_callback(subreq, smbc_notify_cb_got_changes, req);
    2580             : }
    2581             : 
    2582           0 : static void smbc_notify_cb_timedout(struct tevent_req *subreq)
    2583             : {
    2584           0 :         struct tevent_req *req = tevent_req_callback_data(
    2585             :                 subreq, struct tevent_req);
    2586           0 :         struct smbc_notify_cb_state *state = tevent_req_data(
    2587             :                 req, struct smbc_notify_cb_state);
    2588           0 :         int cb_ret;
    2589           0 :         bool ok;
    2590             : 
    2591           0 :         ok = tevent_wakeup_recv(subreq);
    2592           0 :         TALLOC_FREE(subreq);
    2593           0 :         if (!ok) {
    2594           0 :                 tevent_req_oom(req);
    2595           0 :                 return;
    2596             :         }
    2597             : 
    2598           0 :         cb_ret = state->cb(NULL, 0, state->private_data);
    2599           0 :         if (cb_ret != 0) {
    2600           0 :                 tevent_req_done(req);
    2601           0 :                 return;
    2602             :         }
    2603             : 
    2604           0 :         subreq = tevent_wakeup_send(
    2605             :                 state, state->ev,
    2606           0 :                 tevent_timeval_current_ofs(state->callback_timeout_ms/1000,
    2607           0 :                                            state->callback_timeout_ms*1000));
    2608           0 :         if (tevent_req_nomem(subreq, req)) {
    2609           0 :                 return;
    2610             :         }
    2611           0 :         tevent_req_set_callback(subreq, smbc_notify_cb_timedout, req);
    2612             : }
    2613             : 
    2614           0 : static NTSTATUS smbc_notify_cb_recv(struct tevent_req *req)
    2615             : {
    2616           0 :         return tevent_req_simple_recv_ntstatus(req);
    2617             : }
    2618             : 
    2619           0 : static NTSTATUS smbc_notify_cb(struct cli_state *cli, uint16_t fnum,
    2620             :                                bool recursive, uint32_t completion_filter,
    2621             :                                unsigned callback_timeout_ms,
    2622             :                                smbc_notify_callback_fn cb, void *private_data)
    2623             : {
    2624           0 :         TALLOC_CTX *frame = talloc_stackframe();
    2625           0 :         struct tevent_context *ev;
    2626           0 :         struct tevent_req *req;
    2627           0 :         NTSTATUS status = NT_STATUS_NO_MEMORY;
    2628             : 
    2629           0 :         ev = samba_tevent_context_init(frame);
    2630           0 :         if (ev == NULL) {
    2631           0 :                 goto fail;
    2632             :         }
    2633           0 :         req = smbc_notify_cb_send(frame, ev, cli, fnum, recursive,
    2634             :                                   completion_filter,
    2635             :                                   callback_timeout_ms, cb, private_data);
    2636           0 :         if (req == NULL) {
    2637           0 :                 goto fail;
    2638             :         }
    2639           0 :         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
    2640           0 :                 goto fail;
    2641             :         }
    2642           0 :         status = smbc_notify_cb_recv(req);
    2643           0 :         TALLOC_FREE(req);
    2644           0 : fail:
    2645           0 :         TALLOC_FREE(frame);
    2646           0 :         return status;
    2647             : }
    2648             : 
    2649             : int
    2650           0 : SMBC_notify_ctx(SMBCCTX *context, SMBCFILE *dir, smbc_bool recursive,
    2651             :                 uint32_t completion_filter, unsigned callback_timeout_ms,
    2652             :                 smbc_notify_callback_fn cb, void *private_data)
    2653             : {
    2654           0 :         TALLOC_CTX *frame = talloc_stackframe();
    2655           0 :         struct cli_state *cli;
    2656           0 :         char *server = NULL;
    2657           0 :         char *share = NULL;
    2658           0 :         char *user = NULL;
    2659           0 :         char *password = NULL;
    2660           0 :         char *options = NULL;
    2661           0 :         char *workgroup = NULL;
    2662           0 :         char *path = NULL;
    2663           0 :         uint16_t port;
    2664           0 :         NTSTATUS status;
    2665           0 :         uint16_t fnum;
    2666             : 
    2667           0 :         if ((context == NULL) || !context->internal->initialized) {
    2668           0 :                 TALLOC_FREE(frame);
    2669           0 :                 errno = EINVAL;
    2670           0 :                 return -1;
    2671             :         }
    2672           0 :         if (!SMBC_dlist_contains(context->internal->files, dir)) {
    2673           0 :                 TALLOC_FREE(frame);
    2674           0 :                 errno = EBADF;
    2675           0 :                 return -1;
    2676             :         }
    2677             : 
    2678           0 :         if (SMBC_parse_path(frame,
    2679             :                             context,
    2680           0 :                             dir->fname,
    2681             :                             &workgroup,
    2682             :                             &server,
    2683             :                             &port,
    2684             :                             &share,
    2685             :                             &path,
    2686             :                             &user,
    2687             :                             &password,
    2688             :                             &options)) {
    2689           0 :                 DEBUG(4, ("no valid path\n"));
    2690           0 :                 TALLOC_FREE(frame);
    2691           0 :                 errno = EINVAL + 8194;
    2692           0 :                 return -1;
    2693             :         }
    2694             : 
    2695           0 :         DEBUG(4, ("parsed path: fname='%s' server='%s' share='%s' "
    2696             :                   "path='%s' options='%s'\n",
    2697             :                   dir->fname, server, share, path, options));
    2698             : 
    2699           0 :         DEBUG(4, ("%s(%p, %d, %"PRIu32")\n", __func__, dir,
    2700             :                   (int)recursive, completion_filter));
    2701             : 
    2702           0 :         cli = dir->srv->cli;
    2703           0 :         status = cli_ntcreate(
    2704             :                 cli, path, 0, FILE_READ_DATA, 0,
    2705             :                 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
    2706             :                 FILE_OPEN, 0, 0, &fnum, NULL);
    2707           0 :         if (!NT_STATUS_IS_OK(status)) {
    2708           0 :                 TALLOC_FREE(frame);
    2709           0 :                 errno = cli_status_to_errno(status);
    2710           0 :                 return -1;
    2711             :         }
    2712             : 
    2713           0 :         status = smbc_notify_cb(cli, fnum, recursive != 0, completion_filter,
    2714             :                                 callback_timeout_ms, cb, private_data);
    2715           0 :         if (!NT_STATUS_IS_OK(status)) {
    2716           0 :                 cli_close(cli, fnum);
    2717           0 :                 TALLOC_FREE(frame);
    2718           0 :                 errno = cli_status_to_errno(status);
    2719           0 :                 return -1;
    2720             :         }
    2721             : 
    2722           0 :         cli_close(cli, fnum);
    2723             : 
    2724           0 :         TALLOC_FREE(frame);
    2725           0 :         return 0;
    2726             : }

Generated by: LCOV version 1.14