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