LCOV - code coverage report
Current view: top level - source3/libsmb - libsmb_dir.c (source / functions) Hit Total Coverage
Test: coverage report for master 98b443d9 Lines: 580 1303 44.5 %
Date: 2024-05-31 13:13:24 Functions: 23 33 69.7 %

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

Generated by: LCOV version 1.14