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