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