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