Merge branch 'v3-2-test' of git://git.samba.org/samba into v3-2-test
[ira/wip.git] / source3 / libsmb / libsmbclient.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, 2004
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
27 #include "include/libsmb_internal.h"
28
29 struct smbc_dirent *smbc_readdir_ctx(SMBCCTX *context, SMBCFILE *dir);
30 struct smbc_dir_list *smbc_check_dir_ent(struct smbc_dir_list *list, 
31                                          struct smbc_dirent *dirent);
32
33 /*
34  * DOS Attribute values (used internally)
35  */
36 typedef struct DOS_ATTR_DESC {
37         int mode;
38         SMB_OFF_T size;
39         time_t create_time;
40         time_t access_time;
41         time_t write_time;
42         time_t change_time;
43         SMB_INO_T inode;
44 } DOS_ATTR_DESC;
45
46
47 /*
48  * Internal flags for extended attributes
49  */
50
51 /* internal mode values */
52 #define SMBC_XATTR_MODE_ADD          1
53 #define SMBC_XATTR_MODE_REMOVE       2
54 #define SMBC_XATTR_MODE_REMOVE_ALL   3
55 #define SMBC_XATTR_MODE_SET          4
56 #define SMBC_XATTR_MODE_CHOWN        5
57 #define SMBC_XATTR_MODE_CHGRP        6
58
59 #define CREATE_ACCESS_READ      READ_CONTROL_ACCESS
60
61 /*We should test for this in configure ... */
62 #ifndef ENOTSUP
63 #define ENOTSUP EOPNOTSUPP
64 #endif
65
66 /*
67  * Functions exported by libsmb_cache.c that we need here
68  */
69 int smbc_default_cache_functions(SMBCCTX *context);
70
71 /* 
72  * check if an element is part of the list. 
73  * FIXME: Does not belong here !  
74  * Can anyone put this in a macro in dlinklist.h ?
75  * -- Tom
76  */
77 static int DLIST_CONTAINS(SMBCFILE * list, SMBCFILE *p) {
78         if (!p || !list) return False;
79         do {
80                 if (p == list) return True;
81                 list = list->next;
82         } while (list);
83         return False;
84 }
85
86 /*
87  * Find an lsa pipe handle associated with a cli struct.
88  */
89 static struct rpc_pipe_client *
90 find_lsa_pipe_hnd(struct cli_state *ipc_cli)
91 {
92         struct rpc_pipe_client *pipe_hnd;
93
94         for (pipe_hnd = ipc_cli->pipe_list;
95              pipe_hnd;
96              pipe_hnd = pipe_hnd->next) {
97             
98                 if (pipe_hnd->pipe_idx == PI_LSARPC) {
99                         return pipe_hnd;
100                 }
101         }
102
103         return NULL;
104 }
105
106 static int
107 smbc_close_ctx(SMBCCTX *context,
108                SMBCFILE *file);
109 static off_t
110 smbc_lseek_ctx(SMBCCTX *context,
111                SMBCFILE *file,
112                off_t offset,
113                int whence);
114
115 extern bool in_client;
116
117 /*
118  * Is the logging working / configfile read ? 
119  */
120 static int smbc_initialized = 0;
121
122 static int 
123 hex2int( unsigned int _char )
124 {
125     if ( _char >= 'A' && _char <='F')
126         return _char - 'A' + 10;
127     if ( _char >= 'a' && _char <='f')
128         return _char - 'a' + 10;
129     if ( _char >= '0' && _char <='9')
130         return _char - '0';
131     return -1;
132 }
133
134 /*
135  * smbc_urldecode()
136  * and smbc_urldecode_talloc() (internal fn.)
137  *
138  * Convert strings of %xx to their single character equivalent.  Each 'x' must
139  * be a valid hexadecimal digit, or that % sequence is left undecoded.
140  *
141  * dest may, but need not be, the same pointer as src.
142  *
143  * Returns the number of % sequences which could not be converted due to lack
144  * of two following hexadecimal digits.
145  */
146 static int
147 smbc_urldecode_talloc(TALLOC_CTX *ctx, char **pp_dest, const char *src)
148 {
149         int old_length = strlen(src);
150         int i = 0;
151         int err_count = 0;
152         size_t newlen = 1;
153         char *p, *dest;
154
155         if (old_length == 0) {
156                 return 0;
157         }
158
159         *pp_dest = NULL;
160         for (i = 0; i < old_length; ) {
161                 unsigned char character = src[i++];
162
163                 if (character == '%') {
164                         int a = i+1 < old_length ? hex2int(src[i]) : -1;
165                         int b = i+1 < old_length ? hex2int(src[i+1]) : -1;
166
167                         /* Replace valid sequence */
168                         if (a != -1 && b != -1) {
169                                 /* Replace valid %xx sequence with %dd */
170                                 character = (a * 16) + b;
171                                 if (character == '\0') {
172                                         break; /* Stop at %00 */
173                                 }
174                                 i += 2;
175                         } else {
176                                 err_count++;
177                         }
178                 }
179                 newlen++;
180         }
181
182         dest = TALLOC_ARRAY(ctx, char, newlen);
183         if (!dest) {
184                 return err_count;
185         }
186
187         err_count = 0;
188         for (p = dest, i = 0; i < old_length; ) {
189                 unsigned char character = src[i++];
190
191                 if (character == '%') {
192                         int a = i+1 < old_length ? hex2int(src[i]) : -1;
193                         int b = i+1 < old_length ? hex2int(src[i+1]) : -1;
194
195                         /* Replace valid sequence */
196                         if (a != -1 && b != -1) {
197                                 /* Replace valid %xx sequence with %dd */
198                                 character = (a * 16) + b;
199                                 if (character == '\0') {
200                                         break; /* Stop at %00 */
201                                 }
202                                 i += 2;
203                         } else {
204                                 err_count++;
205                         }
206                 }
207                 *p++ = character;
208         }
209
210         *p = '\0';
211         *pp_dest = dest;
212         return err_count;
213 }
214
215 int
216 smbc_urldecode(char *dest, char *src, size_t max_dest_len)
217 {
218         TALLOC_CTX *frame = talloc_stackframe();
219         char *pdest;
220         int ret = smbc_urldecode_talloc(frame, &pdest, src);
221
222         if (pdest) {
223                 strlcpy(dest, pdest, max_dest_len);
224         }
225         TALLOC_FREE(frame);
226         return ret;
227 }
228
229 /*
230  * smbc_urlencode()
231  *
232  * Convert any characters not specifically allowed in a URL into their %xx
233  * equivalent.
234  *
235  * Returns the remaining buffer length.
236  */
237 int
238 smbc_urlencode(char *dest, char *src, int max_dest_len)
239 {
240         char hex[] = "0123456789ABCDEF";
241
242         for (; *src != '\0' && max_dest_len >= 3; src++) {
243
244                 if ((*src < '0' &&
245                      *src != '-' &&
246                      *src != '.') ||
247                     (*src > '9' &&
248                      *src < 'A') ||
249                     (*src > 'Z' &&
250                      *src < 'a' &&
251                      *src != '_') ||
252                     (*src > 'z')) {
253                         *dest++ = '%';
254                         *dest++ = hex[(*src >> 4) & 0x0f];
255                         *dest++ = hex[*src & 0x0f];
256                         max_dest_len -= 3;
257                 } else {
258                         *dest++ = *src;
259                         max_dest_len--;
260                 }
261         }
262
263         *dest++ = '\0';
264         max_dest_len--;
265
266         return max_dest_len;
267 }
268
269 /*
270  * Function to parse a path and turn it into components
271  *
272  * The general format of an SMB URI is explain in Christopher Hertel's CIFS
273  * book, at http://ubiqx.org/cifs/Appendix-D.html.  We accept a subset of the
274  * general format ("smb:" only; we do not look for "cifs:").
275  *
276  *
277  * We accept:
278  *  smb://[[[domain;]user[:password]@]server[/share[/path[/file]]]][?options]
279  *
280  * Meaning of URLs:
281  *
282  * smb://           Show all workgroups.
283  *
284  *                  The method of locating the list of workgroups varies
285  *                  depending upon the setting of the context variable
286  *                  context->options.browse_max_lmb_count.  This value
287  *                  determine the maximum number of local master browsers to
288  *                  query for the list of workgroups.  In order to ensure that
289  *                  a complete list of workgroups is obtained, all master
290  *                  browsers must be queried, but if there are many
291  *                  workgroups, the time spent querying can begin to add up.
292  *                  For small networks (not many workgroups), it is suggested
293  *                  that this variable be set to 0, indicating query all local
294  *                  master browsers.  When the network has many workgroups, a
295  *                  reasonable setting for this variable might be around 3.
296  *
297  * smb://name/      if name<1D> or name<1B> exists, list servers in
298  *                  workgroup, else, if name<20> exists, list all shares
299  *                  for server ...
300  *
301  * If "options" are provided, this function returns the entire option list as a
302  * string, for later parsing by the caller.  Note that currently, no options
303  * are supported.
304  */
305
306 static const char *smbc_prefix = "smb:";
307
308 static int
309 smbc_parse_path(TALLOC_CTX *ctx,
310                 SMBCCTX *context,
311                 const char *fname,
312                 char **pp_workgroup,
313                 char **pp_server,
314                 char **pp_share,
315                 char **pp_path,
316                 char **pp_user,
317                 char **pp_password,
318                 char **pp_options)
319 {
320         char *s;
321         const char *p;
322         char *q, *r;
323         int len;
324
325         /* Ensure these returns are at least valid pointers. */
326         *pp_server = talloc_strdup(ctx, "");
327         *pp_share = talloc_strdup(ctx, "");
328         *pp_path = talloc_strdup(ctx, "");
329         *pp_user = talloc_strdup(ctx, "");
330         *pp_password = talloc_strdup(ctx, "");
331
332         if (!*pp_server || !*pp_share || !*pp_path ||
333                         !*pp_user || !*pp_password) {
334                 return -1;
335         }
336
337         /*
338          * Assume we wont find an authentication domain to parse, so default
339          * to the workgroup in the provided context.
340          */
341         if (pp_workgroup != NULL) {
342                 *pp_workgroup = talloc_strdup(ctx, context->workgroup);
343         }
344
345         if (pp_options) {
346                 *pp_options = talloc_strdup(ctx, "");
347         }
348         s = talloc_strdup(ctx, fname);
349
350         /* see if it has the right prefix */
351         len = strlen(smbc_prefix);
352         if (strncmp(s,smbc_prefix,len) || (s[len] != '/' && s[len] != 0)) {
353                 return -1; /* What about no smb: ? */
354         }
355
356         p = s + len;
357
358         /* Watch the test below, we are testing to see if we should exit */
359
360         if (strncmp(p, "//", 2) && strncmp(p, "\\\\", 2)) {
361                 DEBUG(1, ("Invalid path (does not begin with smb://"));
362                 return -1;
363         }
364
365         p += 2;  /* Skip the double slash */
366
367         /* See if any options were specified */
368         if ((q = strrchr(p, '?')) != NULL ) {
369                 /* There are options.  Null terminate here and point to them */
370                 *q++ = '\0';
371
372                 DEBUG(4, ("Found options '%s'", q));
373
374                 /* Copy the options */
375                 if (*pp_options != NULL) {
376                         TALLOC_FREE(*pp_options);
377                         *pp_options = talloc_strdup(ctx, q);
378                 }
379         }
380
381         if (*p == '\0') {
382                 goto decoding;
383         }
384
385         if (*p == '/') {
386                 int wl = strlen(context->workgroup);
387
388                 if (wl > 16) {
389                         wl = 16;
390                 }
391
392                 *pp_server = talloc_strdup(ctx, context->workgroup);
393                 if (!*pp_server) {
394                         return -1;
395                 }
396                 *pp_server[wl] = '\0';
397                 return 0;
398         }
399
400         /*
401          * ok, its for us. Now parse out the server, share etc.
402          *
403          * However, we want to parse out [[domain;]user[:password]@] if it
404          * exists ...
405          */
406
407         /* check that '@' occurs before '/', if '/' exists at all */
408         q = strchr_m(p, '@');
409         r = strchr_m(p, '/');
410         if (q && (!r || q < r)) {
411                 char *userinfo = NULL;
412                 const char *u;
413
414                 next_token_no_ltrim_talloc(ctx, &p, &userinfo, "@");
415                 if (!userinfo) {
416                         return -1;
417                 }
418                 u = userinfo;
419
420                 if (strchr_m(u, ';')) {
421                         char *workgroup;
422                         next_token_no_ltrim_talloc(ctx, &u, &workgroup, ";");
423                         if (!workgroup) {
424                                 return -1;
425                         }
426                         if (pp_workgroup) {
427                                 *pp_workgroup = workgroup;
428                         }
429                 }
430
431                 if (strchr_m(u, ':')) {
432                         next_token_no_ltrim_talloc(ctx, &u, pp_user, ":");
433                         if (!*pp_user) {
434                                 return -1;
435                         }
436                         *pp_password = talloc_strdup(ctx, u);
437                         if (!*pp_password) {
438                                 return -1;
439                         }
440                 } else {
441                         *pp_user = talloc_strdup(ctx, u);
442                         if (!*pp_user) {
443                                 return -1;
444                         }
445                 }
446         }
447
448         if (!next_token_talloc(ctx, &p, pp_server, "/")) {
449                 return -1;
450         }
451
452         if (*p == (char)0) {
453                 goto decoding;  /* That's it ... */
454         }
455
456         if (!next_token_talloc(ctx, &p, pp_share, "/")) {
457                 return -1;
458         }
459
460         /*
461          * Prepend a leading slash if there's a file path, as required by
462          * NetApp filers.
463          */
464         if (*p != '\0') {
465                 *pp_path = talloc_asprintf(ctx,
466                                         "\\%s",
467                                         p);
468         } else {
469                 *pp_path = talloc_strdup(ctx, "");
470         }
471         if (!*pp_path) {
472                 return -1;
473         }
474         string_replace(*pp_path, '/', '\\');
475
476  decoding:
477
478         (void) smbc_urldecode_talloc(ctx, pp_path, *pp_path);
479         (void) smbc_urldecode_talloc(ctx, pp_server, *pp_server);
480         (void) smbc_urldecode_talloc(ctx, pp_share, *pp_share);
481         (void) smbc_urldecode_talloc(ctx, pp_user, *pp_user);
482         (void) smbc_urldecode_talloc(ctx, pp_password, *pp_password);
483
484         return 0;
485 }
486
487 /*
488  * Verify that the options specified in a URL are valid
489  */
490 static int
491 smbc_check_options(char *server,
492                    char *share,
493                    char *path,
494                    char *options)
495 {
496         DEBUG(4, ("smbc_check_options(): server='%s' share='%s' "
497                   "path='%s' options='%s'\n",
498                   server, share, path, options));
499
500         /* No options at all is always ok */
501         if (! *options) return 0;
502
503         /* Currently, we don't support any options. */
504         return -1;
505 }
506
507 /*
508  * Convert an SMB error into a UNIX error ...
509  */
510 static int
511 smbc_errno(SMBCCTX *context,
512            struct cli_state *c)
513 {
514         int ret = cli_errno(c);
515         
516         if (cli_is_dos_error(c)) {
517                 uint8 eclass;
518                 uint32 ecode;
519
520                 cli_dos_error(c, &eclass, &ecode);
521                 
522                 DEBUG(3,("smbc_error %d %d (0x%x) -> %d\n", 
523                          (int)eclass, (int)ecode, (int)ecode, ret));
524         } else {
525                 NTSTATUS status;
526
527                 status = cli_nt_error(c);
528
529                 DEBUG(3,("smbc errno %s -> %d\n",
530                          nt_errstr(status), ret));
531         }
532
533         return ret;
534 }
535
536 /* 
537  * Check a server for being alive and well.
538  * returns 0 if the server is in shape. Returns 1 on error 
539  * 
540  * Also useable outside libsmbclient to enable external cache
541  * to do some checks too.
542  */
543 static int
544 smbc_check_server(SMBCCTX * context,
545                   SMBCSRV * server) 
546 {
547         socklen_t size;
548         struct sockaddr addr;
549
550         size = sizeof(addr);
551         return (getpeername(server->cli->fd, &addr, &size) == -1);
552 }
553
554 /* 
555  * Remove a server from the cached server list it's unused.
556  * On success, 0 is returned. 1 is returned if the server could not be removed.
557  * 
558  * Also useable outside libsmbclient
559  */
560 int
561 smbc_remove_unused_server(SMBCCTX * context,
562                           SMBCSRV * srv)
563 {
564         SMBCFILE * file;
565
566         /* are we being fooled ? */
567         if (!context || !context->internal ||
568             !context->internal->_initialized || !srv) return 1;
569
570         
571         /* Check all open files/directories for a relation with this server */
572         for (file = context->internal->_files; file; file=file->next) {
573                 if (file->srv == srv) {
574                         /* Still used */
575                         DEBUG(3, ("smbc_remove_usused_server: "
576                                   "%p still used by %p.\n",
577                                   srv, file));
578                         return 1;
579                 }
580         }
581
582         DLIST_REMOVE(context->internal->_servers, srv);
583
584         cli_shutdown(srv->cli);
585         srv->cli = NULL;
586
587         DEBUG(3, ("smbc_remove_usused_server: %p removed.\n", srv));
588
589         (context->callbacks.remove_cached_srv_fn)(context, srv);
590
591         SAFE_FREE(srv);
592         return 0;
593 }
594
595 static SMBCSRV *
596 find_server(SMBCCTX *context,
597                 const char *server,
598                 const char *share,
599                 char *workgroup,
600                 char *username,
601                 char *password)
602 {
603         SMBCSRV *srv;
604         int auth_called = 0;
605
606  check_server_cache:
607
608         srv = (context->callbacks.get_cached_srv_fn)(context, server, share,
609                                                      workgroup, username);
610
611         if (!auth_called && !srv && (!username[0] || !password[0])) {
612                 if (context->internal->_auth_fn_with_context != NULL) {
613                         (context->internal->_auth_fn_with_context)(
614                                 context,
615                                 server, share,
616                                 workgroup, strlen(workgroup)+1,
617                                 username, strlen(username)+1,
618                                 password, strlen(password)+1);
619                 } else {
620                         (context->callbacks.auth_fn)(
621                                 server, share,
622                                 workgroup, strlen(workgroup)+1,
623                                 username, strlen(username)+1,
624                                 password, strlen(password)+1);
625                 }
626
627                 /*
628                  * However, smbc_auth_fn may have picked up info relating to
629                  * an existing connection, so try for an existing connection
630                  * again ...
631                  */
632                 auth_called = 1;
633                 goto check_server_cache;
634
635         }
636
637         if (srv) {
638                 if ((context->callbacks.check_server_fn)(context, srv)) {
639                         /*
640                          * This server is no good anymore
641                          * Try to remove it and check for more possible
642                          * servers in the cache
643                          */
644                         if ((context->callbacks.remove_unused_server_fn)(context,
645                                                                          srv)) { 
646                                 /*
647                                  * We could not remove the server completely,
648                                  * remove it from the cache so we will not get
649                                  * it again. It will be removed when the last
650                                  * file/dir is closed.
651                                  */
652                                 (context->callbacks.remove_cached_srv_fn)(context,
653                                                                           srv);
654                         }
655                         
656                         /*
657                          * Maybe there are more cached connections to this
658                          * server
659                          */
660                         goto check_server_cache; 
661                 }
662
663                 return srv;
664         }
665
666         return NULL;
667 }
668
669 /*
670  * Connect to a server, possibly on an existing connection
671  *
672  * Here, what we want to do is: If the server and username
673  * match an existing connection, reuse that, otherwise, establish a
674  * new connection.
675  *
676  * If we have to create a new connection, call the auth_fn to get the
677  * info we need, unless the username and password were passed in.
678  */
679
680 static SMBCSRV *
681 smbc_server(SMBCCTX *context,
682                 bool connect_if_not_found,
683                 const char *server,
684                 const char *share,
685                 char *workgroup,
686                 char *username,
687                 char *password)
688 {
689         SMBCSRV *srv=NULL;
690         struct cli_state *c;
691         struct nmb_name called, calling;
692         const char *server_n = server;
693         struct sockaddr_storage ss;
694         int tried_reverse = 0;
695         int port_try_first;
696         int port_try_next;
697         const char *username_used;
698         NTSTATUS status;
699
700         zero_addr(&ss);
701         ZERO_STRUCT(c);
702
703         if (server[0] == 0) {
704                 errno = EPERM;
705                 return NULL;
706         }
707
708         /* Look for a cached connection */
709         srv = find_server(context, server, share,
710                           workgroup, username, password);
711
712         /*
713          * If we found a connection and we're only allowed one share per
714          * server...
715          */
716         if (srv && *share != '\0' && context->options.one_share_per_server) {
717
718                 /*
719                  * ... then if there's no current connection to the share,
720                  * connect to it.  find_server(), or rather the function
721                  * pointed to by context->callbacks.get_cached_srv_fn which
722                  * was called by find_server(), will have issued a tree
723                  * disconnect if the requested share is not the same as the
724                  * one that was already connected.
725                  */
726                 if (srv->cli->cnum == (uint16) -1) {
727                         /* Ensure we have accurate auth info */
728                         if (context->internal->_auth_fn_with_context != NULL) {
729                                 (context->internal->_auth_fn_with_context)(
730                                         context,
731                                         server, share,
732                                         workgroup, strlen(workgroup)+1,
733                                         username, strlen(username)+1,
734                                         password, strlen(password)+1);
735                         } else {
736                                 (context->callbacks.auth_fn)(
737                                         server, share,
738                                         workgroup, strlen(workgroup)+1,
739                                         username, strlen(username)+1,
740                                         password, strlen(password)+1);
741                         }
742
743                         /*
744                          * We don't need to renegotiate encryption
745                          * here as the encryption context is not per
746                          * tid.
747                          */
748
749                         if (! cli_send_tconX(srv->cli, share, "?????",
750                                              password, strlen(password)+1)) {
751
752                                 errno = smbc_errno(context, srv->cli);
753                                 cli_shutdown(srv->cli);
754                                 srv->cli = NULL;
755                                 (context->callbacks.remove_cached_srv_fn)(context,
756                                                                           srv);
757                                 srv = NULL;
758                         }
759
760                         /*
761                          * Regenerate the dev value since it's based on both
762                          * server and share
763                          */
764                         if (srv) {
765                                 srv->dev = (dev_t)(str_checksum(server) ^
766                                                    str_checksum(share));
767                         }
768                 }
769         }
770
771         /* If we have a connection... */
772         if (srv) {
773
774                 /* ... then we're done here.  Give 'em what they came for. */
775                 return srv;
776         }
777
778         /* If we're not asked to connect when a connection doesn't exist... */
779         if (! connect_if_not_found) {
780                 /* ... then we're done here. */
781                 return NULL;
782         }
783
784         make_nmb_name(&calling, context->netbios_name, 0x0);
785         make_nmb_name(&called , server, 0x20);
786
787         DEBUG(4,("smbc_server: server_n=[%s] server=[%s]\n", server_n, server));
788
789         DEBUG(4,(" -> server_n=[%s] server=[%s]\n", server_n, server));
790
791  again:
792
793         zero_addr(&ss);
794
795         /* have to open a new connection */
796         if ((c = cli_initialise()) == NULL) {
797                 errno = ENOMEM;
798                 return NULL;
799         }
800
801         if (context->flags & SMB_CTX_FLAG_USE_KERBEROS) {
802                 c->use_kerberos = True;
803         }
804         if (context->flags & SMB_CTX_FLAG_FALLBACK_AFTER_KERBEROS) {
805                 c->fallback_after_kerberos = True;
806         }
807
808         c->timeout = context->timeout;
809
810         /*
811          * Force use of port 139 for first try if share is $IPC, empty, or
812          * null, so browse lists can work
813          */
814         if (share == NULL || *share == '\0' || strcmp(share, "IPC$") == 0) {
815                 port_try_first = 139;
816                 port_try_next = 445;
817         } else {
818                 port_try_first = 445;
819                 port_try_next = 139;
820         }
821
822         c->port = port_try_first;
823
824         status = cli_connect(c, server_n, &ss);
825         if (!NT_STATUS_IS_OK(status)) {
826
827                 /* First connection attempt failed.  Try alternate port. */
828                 c->port = port_try_next;
829
830                 status = cli_connect(c, server_n, &ss);
831                 if (!NT_STATUS_IS_OK(status)) {
832                         cli_shutdown(c);
833                         errno = ETIMEDOUT;
834                         return NULL;
835                 }
836         }
837
838         if (!cli_session_request(c, &calling, &called)) {
839                 cli_shutdown(c);
840                 if (strcmp(called.name, "*SMBSERVER")) {
841                         make_nmb_name(&called , "*SMBSERVER", 0x20);
842                         goto again;
843                 } else {  /* Try one more time, but ensure we don't loop */
844
845                         /* Only try this if server is an IP address ... */
846
847                         if (is_ipaddress(server) && !tried_reverse) {
848                                 fstring remote_name;
849                                 struct sockaddr_storage rem_ss;
850
851                                 if (!interpret_string_addr(&rem_ss, server,
852                                                         NI_NUMERICHOST)) {
853                                         DEBUG(4, ("Could not convert IP address "
854                                                 "%s to struct sockaddr_storage\n",
855                                                 server));
856                                         errno = ETIMEDOUT;
857                                         return NULL;
858                                 }
859
860                                 tried_reverse++; /* Yuck */
861
862                                 if (name_status_find("*", 0, 0, &rem_ss, remote_name)) {
863                                         make_nmb_name(&called, remote_name, 0x20);
864                                         goto again;
865                                 }
866                         }
867                 }
868                 errno = ETIMEDOUT;
869                 return NULL;
870         }
871
872         DEBUG(4,(" session request ok\n"));
873
874         if (!cli_negprot(c)) {
875                 cli_shutdown(c);
876                 errno = ETIMEDOUT;
877                 return NULL;
878         }
879
880         username_used = username;
881
882         if (!NT_STATUS_IS_OK(cli_session_setup(c, username_used,
883                                                password, strlen(password),
884                                                password, strlen(password),
885                                                workgroup))) {
886
887                 /* Failed.  Try an anonymous login, if allowed by flags. */
888                 username_used = "";
889
890                 if ((context->flags & SMBCCTX_FLAG_NO_AUTO_ANONYMOUS_LOGON) ||
891                      !NT_STATUS_IS_OK(cli_session_setup(c, username_used,
892                                                         password, 1,
893                                                         password, 0,
894                                                         workgroup))) {
895
896                         cli_shutdown(c);
897                         errno = EPERM;
898                         return NULL;
899                 }
900         }
901
902         DEBUG(4,(" session setup ok\n"));
903
904         if (!cli_send_tconX(c, share, "?????",
905                             password, strlen(password)+1)) {
906                 errno = smbc_errno(context, c);
907                 cli_shutdown(c);
908                 return NULL;
909         }
910
911         DEBUG(4,(" tconx ok\n"));
912
913         if (context->internal->_smb_encryption_level) {
914                 /* Attempt UNIX smb encryption. */
915                 if (!NT_STATUS_IS_OK(cli_force_encryption(c,
916                                                 username_used,
917                                                 password,
918                                                 workgroup))) {
919
920                         /*
921                          * context->internal->_smb_encryption_level == 1
922                          * means don't fail if encryption can't be negotiated,
923                          * == 2 means fail if encryption can't be negotiated.
924                          */
925
926                         DEBUG(4,(" SMB encrypt failed\n"));
927
928                         if (context->internal->_smb_encryption_level == 2) {
929                                 cli_shutdown(c);
930                                 errno = EPERM;
931                                 return NULL;
932                         }
933                 }
934                 DEBUG(4,(" SMB encrypt ok\n"));
935         }
936
937         /*
938          * Ok, we have got a nice connection
939          * Let's allocate a server structure.
940          */
941
942         srv = SMB_MALLOC_P(SMBCSRV);
943         if (!srv) {
944                 errno = ENOMEM;
945                 goto failed;
946         }
947
948         ZERO_STRUCTP(srv);
949         srv->cli = c;
950         srv->dev = (dev_t)(str_checksum(server) ^ str_checksum(share));
951         srv->no_pathinfo = False;
952         srv->no_pathinfo2 = False;
953         srv->no_nt_session = False;
954
955         /* now add it to the cache (internal or external)  */
956         /* Let the cache function set errno if it wants to */
957         errno = 0;
958         if ((context->callbacks.add_cached_srv_fn)(context, srv,
959                                                    server, share,
960                                                    workgroup, username)) {
961                 int saved_errno = errno;
962                 DEBUG(3, (" Failed to add server to cache\n"));
963                 errno = saved_errno;
964                 if (errno == 0) {
965                         errno = ENOMEM;
966                 }
967                 goto failed;
968         }
969
970         DEBUG(2, ("Server connect ok: //%s/%s: %p\n",
971                   server, share, srv));
972
973         DLIST_ADD(context->internal->_servers, srv);
974         return srv;
975
976  failed:
977         cli_shutdown(c);
978         if (!srv) {
979                 return NULL;
980         }
981
982         SAFE_FREE(srv);
983         return NULL;
984 }
985
986 /*
987  * Connect to a server for getting/setting attributes, possibly on an existing
988  * connection.  This works similarly to smbc_server().
989  */
990 static SMBCSRV *
991 smbc_attr_server(SMBCCTX *context,
992                  const char *server,
993                  const char *share,
994                  char *workgroup,
995                  char *username,
996                  char *password,
997                  POLICY_HND *pol)
998 {
999         int flags;
1000         struct sockaddr_storage ss;
1001         struct cli_state *ipc_cli;
1002         struct rpc_pipe_client *pipe_hnd;
1003         NTSTATUS nt_status;
1004         SMBCSRV *ipc_srv=NULL;
1005
1006         /*
1007          * See if we've already created this special connection.  Reference
1008          * our "special" share name '*IPC$', which is an impossible real share
1009          * name due to the leading asterisk.
1010          */
1011         ipc_srv = find_server(context, server, "*IPC$",
1012                               workgroup, username, password);
1013         if (!ipc_srv) {
1014
1015                 /* We didn't find a cached connection.  Get the password */
1016                 if (*password == '\0') {
1017                         /* ... then retrieve it now. */
1018                         if (context->internal->_auth_fn_with_context != NULL) {
1019                                 (context->internal->_auth_fn_with_context)(
1020                                         context,
1021                                         server, share,
1022                                         workgroup, strlen(workgroup)+1,
1023                                         username, strlen(username)+1,
1024                                         password, strlen(password)+1);
1025                         } else {
1026                                 (context->callbacks.auth_fn)(
1027                                         server, share,
1028                                         workgroup, strlen(workgroup)+1,
1029                                         username, strlen(username)+1,
1030                                         password, strlen(password)+1);
1031                         }
1032                 }
1033
1034                 flags = 0;
1035                 if (context->flags & SMB_CTX_FLAG_USE_KERBEROS) {
1036                         flags |= CLI_FULL_CONNECTION_USE_KERBEROS;
1037                 }
1038
1039                 zero_addr(&ss);
1040                 nt_status = cli_full_connection(&ipc_cli,
1041                                                 global_myname(), server,
1042                                                 &ss, 0, "IPC$", "?????",
1043                                                 username, workgroup,
1044                                                 password, flags,
1045                                                 Undefined, NULL);
1046                 if (! NT_STATUS_IS_OK(nt_status)) {
1047                         DEBUG(1,("cli_full_connection failed! (%s)\n",
1048                                  nt_errstr(nt_status)));
1049                         errno = ENOTSUP;
1050                         return NULL;
1051                 }
1052
1053                 if (context->internal->_smb_encryption_level) {
1054                         /* Attempt UNIX smb encryption. */
1055                         if (!NT_STATUS_IS_OK(cli_force_encryption(ipc_cli,
1056                                                 username,
1057                                                 password,
1058                                                 workgroup))) {
1059
1060                                 /*
1061                                  * context->internal->_smb_encryption_level == 1
1062                                  * means don't fail if encryption can't be negotiated,
1063                                  * == 2 means fail if encryption can't be negotiated.
1064                                  */
1065
1066                                 DEBUG(4,(" SMB encrypt failed on IPC$\n"));
1067
1068                                 if (context->internal->_smb_encryption_level == 2) {
1069                                         cli_shutdown(ipc_cli);
1070                                         errno = EPERM;
1071                                         return NULL;
1072                                 }
1073                         }
1074                         DEBUG(4,(" SMB encrypt ok on IPC$\n"));
1075                 }
1076
1077                 ipc_srv = SMB_MALLOC_P(SMBCSRV);
1078                 if (!ipc_srv) {
1079                         errno = ENOMEM;
1080                         cli_shutdown(ipc_cli);
1081                         return NULL;
1082                 }
1083
1084                 ZERO_STRUCTP(ipc_srv);
1085                 ipc_srv->cli = ipc_cli;
1086
1087                 if (pol) {
1088                         pipe_hnd = cli_rpc_pipe_open_noauth(ipc_srv->cli,
1089                                                             PI_LSARPC,
1090                                                             &nt_status);
1091                         if (!pipe_hnd) {
1092                                 DEBUG(1, ("cli_nt_session_open fail!\n"));
1093                                 errno = ENOTSUP;
1094                                 cli_shutdown(ipc_srv->cli);
1095                                 free(ipc_srv);
1096                                 return NULL;
1097                         }
1098
1099                         /*
1100                          * Some systems don't support
1101                          * SEC_RIGHTS_MAXIMUM_ALLOWED, but NT sends 0x2000000
1102                          * so we might as well do it too.
1103                          */
1104         
1105                         nt_status = rpccli_lsa_open_policy(
1106                                 pipe_hnd,
1107                                 talloc_tos(),
1108                                 True, 
1109                                 GENERIC_EXECUTE_ACCESS,
1110                                 pol);
1111         
1112                         if (!NT_STATUS_IS_OK(nt_status)) {
1113                                 errno = smbc_errno(context, ipc_srv->cli);
1114                                 cli_shutdown(ipc_srv->cli);
1115                                 return NULL;
1116                         }
1117                 }
1118
1119                 /* now add it to the cache (internal or external) */
1120
1121                 errno = 0;      /* let cache function set errno if it likes */
1122                 if ((context->callbacks.add_cached_srv_fn)(context, ipc_srv,
1123                                                            server,
1124                                                            "*IPC$",
1125                                                            workgroup,
1126                                                            username)) {
1127                         DEBUG(3, (" Failed to add server to cache\n"));
1128                         if (errno == 0) {
1129                                 errno = ENOMEM;
1130                         }
1131                         cli_shutdown(ipc_srv->cli);
1132                         free(ipc_srv);
1133                         return NULL;
1134                 }
1135
1136                 DLIST_ADD(context->internal->_servers, ipc_srv);
1137         }
1138
1139         return ipc_srv;
1140 }
1141
1142 /*
1143  * Routine to open() a file ...
1144  */
1145
1146 static SMBCFILE *
1147 smbc_open_ctx(SMBCCTX *context,
1148               const char *fname,
1149               int flags,
1150               mode_t mode)
1151 {
1152         char *server, *share, *user, *password, *workgroup;
1153         char *path;
1154         char *targetpath = NULL;
1155         struct cli_state *targetcli;
1156         SMBCSRV *srv   = NULL;
1157         SMBCFILE *file = NULL;
1158         int fd;
1159         TALLOC_CTX *frame = talloc_stackframe();
1160
1161         if (!context || !context->internal ||
1162             !context->internal->_initialized) {
1163
1164                 errno = EINVAL;  /* Best I can think of ... */
1165                 TALLOC_FREE(frame);
1166                 return NULL;
1167
1168         }
1169
1170         if (!fname) {
1171
1172                 errno = EINVAL;
1173                 TALLOC_FREE(frame);
1174                 return NULL;
1175
1176         }
1177
1178         if (smbc_parse_path(frame,
1179                                 context,
1180                                 fname,
1181                                 &workgroup,
1182                                 &server,
1183                                 &share,
1184                                 &path,
1185                                 &user,
1186                                 &password,
1187                                 NULL)) {
1188                 errno = EINVAL;
1189                 TALLOC_FREE(frame);
1190                 return NULL;
1191         }
1192
1193         if (!user || user[0] == (char)0) {
1194                 user = talloc_strdup(frame, context->user);
1195                 if (!user) {
1196                         errno = ENOMEM;
1197                         TALLOC_FREE(frame);
1198                         return NULL;
1199                 }
1200         }
1201
1202         srv = smbc_server(context, True,
1203                           server, share, workgroup, user, password);
1204
1205         if (!srv) {
1206                 if (errno == EPERM) errno = EACCES;
1207                 TALLOC_FREE(frame);
1208                 return NULL;  /* smbc_server sets errno */
1209         }
1210
1211         /* Hmmm, the test for a directory is suspect here ... FIXME */
1212
1213         if (strlen(path) > 0 && path[strlen(path) - 1] == '\\') {
1214                 fd = -1;
1215         } else {
1216                 file = SMB_MALLOC_P(SMBCFILE);
1217
1218                 if (!file) {
1219                         errno = ENOMEM;
1220                         TALLOC_FREE(frame);
1221                         return NULL;
1222                 }
1223
1224                 ZERO_STRUCTP(file);
1225
1226                 /*d_printf(">>>open: resolving %s\n", path);*/
1227                 if (!cli_resolve_path(frame, "", srv->cli, path, &targetcli, &targetpath)) {
1228                         d_printf("Could not resolve %s\n", path);
1229                         SAFE_FREE(file);
1230                         TALLOC_FREE(frame);
1231                         return NULL;
1232                 }
1233                 /*d_printf(">>>open: resolved %s as %s\n", path, targetpath);*/
1234
1235                 if ((fd = cli_open(targetcli, targetpath, flags,
1236                                    context->internal->_share_mode)) < 0) {
1237
1238                         /* Handle the error ... */
1239
1240                         SAFE_FREE(file);
1241                         errno = smbc_errno(context, targetcli);
1242                         TALLOC_FREE(frame);
1243                         return NULL;
1244
1245                 }
1246
1247                 /* Fill in file struct */
1248
1249                 file->cli_fd  = fd;
1250                 file->fname   = SMB_STRDUP(fname);
1251                 file->srv     = srv;
1252                 file->offset  = 0;
1253                 file->file    = True;
1254
1255                 DLIST_ADD(context->internal->_files, file);
1256
1257                 /*
1258                  * If the file was opened in O_APPEND mode, all write
1259                  * operations should be appended to the file.  To do that,
1260                  * though, using this protocol, would require a getattrE()
1261                  * call for each and every write, to determine where the end
1262                  * of the file is. (There does not appear to be an append flag
1263                  * in the protocol.)  Rather than add all of that overhead of
1264                  * retrieving the current end-of-file offset prior to each
1265                  * write operation, we'll assume that most append operations
1266                  * will continuously write, so we'll just set the offset to
1267                  * the end of the file now and hope that's adequate.
1268                  *
1269                  * Note to self: If this proves inadequate, and O_APPEND
1270                  * should, in some cases, be forced for each write, add a
1271                  * field in the context options structure, for
1272                  * "strict_append_mode" which would select between the current
1273                  * behavior (if FALSE) or issuing a getattrE() prior to each
1274                  * write and forcing the write to the end of the file (if
1275                  * TRUE).  Adding that capability will likely require adding
1276                  * an "append" flag into the _SMBCFILE structure to track
1277                  * whether a file was opened in O_APPEND mode.  -- djl
1278                  */
1279                 if (flags & O_APPEND) {
1280                         if (smbc_lseek_ctx(context, file, 0, SEEK_END) < 0) {
1281                                 (void) smbc_close_ctx(context, file);
1282                                 errno = ENXIO;
1283                                 TALLOC_FREE(frame);
1284                                 return NULL;
1285                         }
1286                 }
1287
1288                 TALLOC_FREE(frame);
1289                 return file;
1290
1291         }
1292
1293         /* Check if opendir needed ... */
1294
1295         if (fd == -1) {
1296                 int eno = 0;
1297
1298                 eno = smbc_errno(context, srv->cli);
1299                 file = (context->opendir)(context, fname);
1300                 if (!file) errno = eno;
1301                 TALLOC_FREE(frame);
1302                 return file;
1303
1304         }
1305
1306         errno = EINVAL; /* FIXME, correct errno ? */
1307         TALLOC_FREE(frame);
1308         return NULL;
1309
1310 }
1311
1312 /*
1313  * Routine to create a file 
1314  */
1315
1316 static int creat_bits = O_WRONLY | O_CREAT | O_TRUNC; /* FIXME: Do we need this */
1317
1318 static SMBCFILE *
1319 smbc_creat_ctx(SMBCCTX *context,
1320                const char *path,
1321                mode_t mode)
1322 {
1323
1324         if (!context || !context->internal ||
1325             !context->internal->_initialized) {
1326
1327                 errno = EINVAL;
1328                 return NULL;
1329
1330         }
1331
1332         return smbc_open_ctx(context, path, creat_bits, mode);
1333 }
1334
1335 /*
1336  * Routine to read() a file ...
1337  */
1338
1339 static ssize_t
1340 smbc_read_ctx(SMBCCTX *context,
1341               SMBCFILE *file,
1342               void *buf,
1343               size_t count)
1344 {
1345         int ret;
1346         char *server, *share, *user, *password;
1347         char *path;
1348         char *targetpath = NULL;
1349         struct cli_state *targetcli;
1350         TALLOC_CTX *frame = talloc_stackframe();
1351
1352         /*
1353          * offset:
1354          *
1355          * Compiler bug (possibly) -- gcc (GCC) 3.3.5 (Debian 1:3.3.5-2) --
1356          * appears to pass file->offset (which is type off_t) differently than
1357          * a local variable of type off_t.  Using local variable "offset" in
1358          * the call to cli_read() instead of file->offset fixes a problem
1359          * retrieving data at an offset greater than 4GB.
1360          */
1361         off_t offset;
1362
1363         if (!context || !context->internal ||
1364             !context->internal->_initialized) {
1365                 errno = EINVAL;
1366                 TALLOC_FREE(frame);
1367                 return -1;
1368
1369         }
1370
1371         DEBUG(4, ("smbc_read(%p, %d)\n", file, (int)count));
1372
1373         if (!file || !DLIST_CONTAINS(context->internal->_files, file)) {
1374                 errno = EBADF;
1375                 TALLOC_FREE(frame);
1376                 return -1;
1377
1378         }
1379
1380         offset = file->offset;
1381
1382         /* Check that the buffer exists ... */
1383
1384         if (buf == NULL) {
1385                 errno = EINVAL;
1386                 TALLOC_FREE(frame);
1387                 return -1;
1388
1389         }
1390
1391         /*d_printf(">>>read: parsing %s\n", file->fname);*/
1392         if (smbc_parse_path(frame,
1393                                 context,
1394                                 file->fname,
1395                                 NULL,
1396                                 &server,
1397                                 &share,
1398                                 &path,
1399                                 &user,
1400                                 &password,
1401                                 NULL)) {
1402                 errno = EINVAL;
1403                 TALLOC_FREE(frame);
1404                 return -1;
1405         }
1406
1407         /*d_printf(">>>read: resolving %s\n", path);*/
1408         if (!cli_resolve_path(frame, "", file->srv->cli, path,
1409                               &targetcli, &targetpath)) {
1410                 d_printf("Could not resolve %s\n", path);
1411                 TALLOC_FREE(frame);
1412                 return -1;
1413         }
1414         /*d_printf(">>>fstat: resolved path as %s\n", targetpath);*/
1415
1416         ret = cli_read(targetcli, file->cli_fd, (char *)buf, offset, count);
1417
1418         if (ret < 0) {
1419
1420                 errno = smbc_errno(context, targetcli);
1421                 TALLOC_FREE(frame);
1422                 return -1;
1423
1424         }
1425
1426         file->offset += ret;
1427
1428         DEBUG(4, ("  --> %d\n", ret));
1429
1430         TALLOC_FREE(frame);
1431         return ret;  /* Success, ret bytes of data ... */
1432
1433 }
1434
1435 /*
1436  * Routine to write() a file ...
1437  */
1438
1439 static ssize_t
1440 smbc_write_ctx(SMBCCTX *context,
1441                SMBCFILE *file,
1442                void *buf,
1443                size_t count)
1444 {
1445         int ret;
1446         off_t offset;
1447         char *server, *share, *user, *password;
1448         char *path;
1449         char *targetpath = NULL;
1450         struct cli_state *targetcli;
1451         TALLOC_CTX *frame = talloc_stackframe();
1452
1453         /* First check all pointers before dereferencing them */
1454
1455         if (!context || !context->internal ||
1456             !context->internal->_initialized) {
1457                 errno = EINVAL;
1458                 TALLOC_FREE(frame);
1459                 return -1;
1460
1461         }
1462
1463         if (!file || !DLIST_CONTAINS(context->internal->_files, file)) {
1464                 errno = EBADF;
1465                 TALLOC_FREE(frame);
1466                 return -1;
1467         }
1468
1469         /* Check that the buffer exists ... */
1470
1471         if (buf == NULL) {
1472                 errno = EINVAL;
1473                 TALLOC_FREE(frame);
1474                 return -1;
1475
1476         }
1477
1478         offset = file->offset; /* See "offset" comment in smbc_read_ctx() */
1479
1480         /*d_printf(">>>write: parsing %s\n", file->fname);*/
1481         if (smbc_parse_path(frame,
1482                                 context,
1483                                 file->fname,
1484                                 NULL,
1485                                 &server,
1486                                 &share,
1487                                 &path,
1488                                 &user,
1489                                 &password,
1490                                 NULL)) {
1491                 errno = EINVAL;
1492                 TALLOC_FREE(frame);
1493                 return -1;
1494         }
1495
1496         /*d_printf(">>>write: resolving %s\n", path);*/
1497         if (!cli_resolve_path(frame, "", file->srv->cli, path,
1498                               &targetcli, &targetpath)) {
1499                 d_printf("Could not resolve %s\n", path);
1500                 TALLOC_FREE(frame);
1501                 return -1;
1502         }
1503         /*d_printf(">>>write: resolved path as %s\n", targetpath);*/
1504
1505         ret = cli_write(targetcli, file->cli_fd, 0, (char *)buf, offset, count);
1506
1507         if (ret <= 0) {
1508                 errno = smbc_errno(context, targetcli);
1509                 TALLOC_FREE(frame);
1510                 return -1;
1511
1512         }
1513
1514         file->offset += ret;
1515
1516         TALLOC_FREE(frame);
1517         return ret;  /* Success, 0 bytes of data ... */
1518 }
1519
1520 /*
1521  * Routine to close() a file ...
1522  */
1523
1524 static int
1525 smbc_close_ctx(SMBCCTX *context,
1526                SMBCFILE *file)
1527 {
1528         SMBCSRV *srv;
1529         char *server, *share, *user, *password;
1530         char *path;
1531         char *targetpath = NULL;
1532         struct cli_state *targetcli;
1533         TALLOC_CTX *frame = talloc_stackframe();
1534
1535         if (!context || !context->internal ||
1536             !context->internal->_initialized) {
1537
1538                 errno = EINVAL;
1539                 TALLOC_FREE(frame);
1540                 return -1;
1541         }
1542
1543         if (!file || !DLIST_CONTAINS(context->internal->_files, file)) {
1544                 errno = EBADF;
1545                 TALLOC_FREE(frame);
1546                 return -1;
1547         }
1548
1549         /* IS a dir ... */
1550         if (!file->file) {
1551                 TALLOC_FREE(frame);
1552                 return (context->closedir)(context, file);
1553         }
1554
1555         /*d_printf(">>>close: parsing %s\n", file->fname);*/
1556         if (smbc_parse_path(frame,
1557                                 context,
1558                                 file->fname,
1559                                 NULL,
1560                                 &server,
1561                                 &share,
1562                                 &path,
1563                                 &user,
1564                                 &password,
1565                                 NULL)) {
1566                 errno = EINVAL;
1567                 TALLOC_FREE(frame);
1568                 return -1;
1569         }
1570
1571         /*d_printf(">>>close: resolving %s\n", path);*/
1572         if (!cli_resolve_path(frame, "", file->srv->cli, path,
1573                               &targetcli, &targetpath)) {
1574                 d_printf("Could not resolve %s\n", path);
1575                 TALLOC_FREE(frame);
1576                 return -1;
1577         }
1578         /*d_printf(">>>close: resolved path as %s\n", targetpath);*/
1579
1580         if (!cli_close(targetcli, file->cli_fd)) {
1581
1582                 DEBUG(3, ("cli_close failed on %s. purging server.\n", 
1583                           file->fname));
1584                 /* Deallocate slot and remove the server 
1585                  * from the server cache if unused */
1586                 errno = smbc_errno(context, targetcli);
1587                 srv = file->srv;
1588                 DLIST_REMOVE(context->internal->_files, file);
1589                 SAFE_FREE(file->fname);
1590                 SAFE_FREE(file);
1591                 (context->callbacks.remove_unused_server_fn)(context, srv);
1592                 TALLOC_FREE(frame);
1593                 return -1;
1594
1595         }
1596
1597         DLIST_REMOVE(context->internal->_files, file);
1598         SAFE_FREE(file->fname);
1599         SAFE_FREE(file);
1600         TALLOC_FREE(frame);
1601
1602         return 0;
1603 }
1604
1605 /*
1606  * Get info from an SMB server on a file. Use a qpathinfo call first
1607  * and if that fails, use getatr, as Win95 sometimes refuses qpathinfo
1608  */
1609 static bool
1610 smbc_getatr(SMBCCTX * context,
1611             SMBCSRV *srv,
1612             char *path,
1613             uint16 *mode,
1614             SMB_OFF_T *size,
1615             struct timespec *create_time_ts,
1616             struct timespec *access_time_ts,
1617             struct timespec *write_time_ts,
1618             struct timespec *change_time_ts,
1619             SMB_INO_T *ino)
1620 {
1621         char *fixedpath;
1622         char *targetpath = NULL;
1623         struct cli_state *targetcli;
1624         time_t write_time;
1625         TALLOC_CTX *frame = talloc_stackframe();
1626
1627         if (!context || !context->internal ||
1628             !context->internal->_initialized) {
1629                 errno = EINVAL;
1630                 TALLOC_FREE(frame);
1631                 return -1;
1632         }
1633
1634         /* path fixup for . and .. */
1635         if (strequal(path, ".") || strequal(path, "..")) {
1636                 fixedpath = talloc_strdup(frame, "\\");
1637                 if (!fixedpath) {
1638                         errno = ENOMEM;
1639                         TALLOC_FREE(frame);
1640                         return -1;
1641                 }
1642         } else {
1643                 fixedpath = talloc_strdup(frame, path);
1644                 if (!fixedpath) {
1645                         errno = ENOMEM;
1646                         TALLOC_FREE(frame);
1647                         return -1;
1648                 }
1649                 trim_string(fixedpath, NULL, "\\..");
1650                 trim_string(fixedpath, NULL, "\\.");
1651         }
1652         DEBUG(4,("smbc_getatr: sending qpathinfo\n"));
1653
1654         if (!cli_resolve_path(frame, "", srv->cli, fixedpath,
1655                                 &targetcli, &targetpath)) {
1656                 d_printf("Couldn't resolve %s\n", path);
1657                 TALLOC_FREE(frame);
1658                 return False;
1659         }
1660
1661         if (!srv->no_pathinfo2 &&
1662             cli_qpathinfo2(targetcli, targetpath,
1663                            create_time_ts,
1664                            access_time_ts,
1665                            write_time_ts,
1666                            change_time_ts,
1667                            size, mode, ino)) {
1668                 TALLOC_FREE(frame);
1669                 return True;
1670         }
1671
1672         /* if this is NT then don't bother with the getatr */
1673         if (targetcli->capabilities & CAP_NT_SMBS) {
1674                 errno = EPERM;
1675                 TALLOC_FREE(frame);
1676                 return False;
1677         }
1678
1679         if (cli_getatr(targetcli, targetpath, mode, size, &write_time)) {
1680
1681                 struct timespec w_time_ts;
1682
1683                 w_time_ts = convert_time_t_to_timespec(write_time);
1684
1685                 if (write_time_ts != NULL) {
1686                         *write_time_ts = w_time_ts;
1687                 }
1688
1689                 if (create_time_ts != NULL) {
1690                         *create_time_ts = w_time_ts;
1691                 }
1692                 
1693                 if (access_time_ts != NULL) {
1694                         *access_time_ts = w_time_ts;
1695                 }
1696                 
1697                 if (change_time_ts != NULL) {
1698                         *change_time_ts = w_time_ts;
1699                 }
1700
1701                 srv->no_pathinfo2 = True;
1702                 TALLOC_FREE(frame);
1703                 return True;
1704         }
1705
1706         errno = EPERM;
1707         TALLOC_FREE(frame);
1708         return False;
1709
1710 }
1711
1712 /*
1713  * Set file info on an SMB server.  Use setpathinfo call first.  If that
1714  * fails, use setattrE..
1715  *
1716  * Access and modification time parameters are always used and must be
1717  * provided.  Create time, if zero, will be determined from the actual create
1718  * time of the file.  If non-zero, the create time will be set as well.
1719  *
1720  * "mode" (attributes) parameter may be set to -1 if it is not to be set.
1721  */
1722 static bool
1723 smbc_setatr(SMBCCTX * context, SMBCSRV *srv, char *path, 
1724             time_t create_time,
1725             time_t access_time,
1726             time_t write_time,
1727             time_t change_time,
1728             uint16 mode)
1729 {
1730         int fd;
1731         int ret;
1732         TALLOC_CTX *frame = talloc_stackframe();
1733
1734         /*
1735          * First, try setpathinfo (if qpathinfo succeeded), for it is the
1736          * modern function for "new code" to be using, and it works given a
1737          * filename rather than requiring that the file be opened to have its
1738          * attributes manipulated.
1739          */
1740         if (srv->no_pathinfo ||
1741             ! cli_setpathinfo(srv->cli, path,
1742                               create_time,
1743                               access_time,
1744                               write_time,
1745                               change_time,
1746                               mode)) {
1747
1748                 /*
1749                  * setpathinfo is not supported; go to plan B. 
1750                  *
1751                  * cli_setatr() does not work on win98, and it also doesn't
1752                  * support setting the access time (only the modification
1753                  * time), so in all cases, we open the specified file and use
1754                  * cli_setattrE() which should work on all OS versions, and
1755                  * supports both times.
1756                  */
1757
1758                 /* Don't try {q,set}pathinfo() again, with this server */
1759                 srv->no_pathinfo = True;
1760
1761                 /* Open the file */
1762                 if ((fd = cli_open(srv->cli, path, O_RDWR, DENY_NONE)) < 0) {
1763
1764                         errno = smbc_errno(context, srv->cli);
1765                         TALLOC_FREE(frame);
1766                         return -1;
1767                 }
1768
1769                 /* Set the new attributes */
1770                 ret = cli_setattrE(srv->cli, fd,
1771                                    change_time,
1772                                    access_time,
1773                                    write_time);
1774
1775                 /* Close the file */
1776                 cli_close(srv->cli, fd);
1777
1778                 /*
1779                  * Unfortunately, setattrE() doesn't have a provision for
1780                  * setting the access mode (attributes).  We'll have to try
1781                  * cli_setatr() for that, and with only this parameter, it
1782                  * seems to work on win98.
1783                  */
1784                 if (ret && mode != (uint16) -1) {
1785                         ret = cli_setatr(srv->cli, path, mode, 0);
1786                 }
1787
1788                 if (! ret) {
1789                         errno = smbc_errno(context, srv->cli);
1790                         TALLOC_FREE(frame);
1791                         return False;
1792                 }
1793         }
1794
1795         TALLOC_FREE(frame);
1796         return True;
1797 }
1798
1799  /*
1800   * Routine to unlink() a file
1801   */
1802
1803 static int
1804 smbc_unlink_ctx(SMBCCTX *context,
1805                 const char *fname)
1806 {
1807         char *server, *share, *user, *password, *workgroup;
1808         char *path;
1809         char *targetpath;
1810         struct cli_state *targetcli;
1811         SMBCSRV *srv = NULL;
1812         TALLOC_CTX *frame = talloc_stackframe();
1813
1814         if (!context || !context->internal ||
1815             !context->internal->_initialized) {
1816                 errno = EINVAL;  /* Best I can think of ... */
1817                 TALLOC_FREE(frame);
1818                 return -1;
1819
1820         }
1821
1822         if (!fname) {
1823                 errno = EINVAL;
1824                 TALLOC_FREE(frame);
1825                 return -1;
1826
1827         }
1828
1829         if (smbc_parse_path(frame,
1830                                 context,
1831                                 fname,
1832                                 &workgroup,
1833                                 &server,
1834                                 &share,
1835                                 &path,
1836                                 &user,
1837                                 &password,
1838                                 NULL)) {
1839                 errno = EINVAL;
1840                 TALLOC_FREE(frame);
1841                 return -1;
1842         }
1843
1844         if (!user || user[0] == (char)0) {
1845                 user = talloc_strdup(frame, context->user);
1846                 if (!user) {
1847                         errno = ENOMEM;
1848                         TALLOC_FREE(frame);
1849                         return -1;
1850                 }
1851         }
1852
1853         srv = smbc_server(context, True,
1854                           server, share, workgroup, user, password);
1855
1856         if (!srv) {
1857                 TALLOC_FREE(frame);
1858                 return -1;  /* smbc_server sets errno */
1859
1860         }
1861
1862         /*d_printf(">>>unlink: resolving %s\n", path);*/
1863         if (!cli_resolve_path(frame, "", srv->cli, path,
1864                                 &targetcli, &targetpath)) {
1865                 d_printf("Could not resolve %s\n", path);
1866                 TALLOC_FREE(frame);
1867                 return -1;
1868         }
1869         /*d_printf(">>>unlink: resolved path as %s\n", targetpath);*/
1870
1871         if (!cli_unlink(targetcli, targetpath)) {
1872
1873                 errno = smbc_errno(context, targetcli);
1874
1875                 if (errno == EACCES) { /* Check if the file is a directory */
1876
1877                         int saverr = errno;
1878                         SMB_OFF_T size = 0;
1879                         uint16 mode = 0;
1880                         struct timespec write_time_ts;
1881                         struct timespec access_time_ts;
1882                         struct timespec change_time_ts;
1883                         SMB_INO_T ino = 0;
1884
1885                         if (!smbc_getatr(context, srv, path, &mode, &size,
1886                                          NULL,
1887                                          &access_time_ts,
1888                                          &write_time_ts,
1889                                          &change_time_ts,
1890                                          &ino)) {
1891
1892                                 /* Hmmm, bad error ... What? */
1893
1894                                 errno = smbc_errno(context, targetcli);
1895                                 TALLOC_FREE(frame);
1896                                 return -1;
1897
1898                         }
1899                         else {
1900
1901                                 if (IS_DOS_DIR(mode))
1902                                         errno = EISDIR;
1903                                 else
1904                                         errno = saverr;  /* Restore this */
1905
1906                         }
1907                 }
1908
1909                 TALLOC_FREE(frame);
1910                 return -1;
1911
1912         }
1913
1914         TALLOC_FREE(frame);
1915         return 0;  /* Success ... */
1916
1917 }
1918
1919 /*
1920  * Routine to rename() a file
1921  */
1922
1923 static int
1924 smbc_rename_ctx(SMBCCTX *ocontext,
1925                 const char *oname, 
1926                 SMBCCTX *ncontext,
1927                 const char *nname)
1928 {
1929         char *server1;
1930         char *share1;
1931         char *server2;
1932         char *share2;
1933         char *user1;
1934         char *user2;
1935         char *password1;
1936         char *password2;
1937         char *workgroup;
1938         char *path1;
1939         char *path2;
1940         char *targetpath1;
1941         char *targetpath2;
1942         struct cli_state *targetcli1;
1943         struct cli_state *targetcli2;
1944         SMBCSRV *srv = NULL;
1945         TALLOC_CTX *frame = talloc_stackframe();
1946
1947         if (!ocontext || !ncontext ||
1948             !ocontext->internal || !ncontext->internal ||
1949             !ocontext->internal->_initialized ||
1950             !ncontext->internal->_initialized) {
1951                 errno = EINVAL;  /* Best I can think of ... */
1952                 TALLOC_FREE(frame);
1953                 return -1;
1954         }
1955
1956         if (!oname || !nname) {
1957                 errno = EINVAL;
1958                 TALLOC_FREE(frame);
1959                 return -1;
1960         }
1961
1962         DEBUG(4, ("smbc_rename(%s,%s)\n", oname, nname));
1963
1964         if (smbc_parse_path(frame,
1965                         ocontext,
1966                         oname,
1967                         &workgroup,
1968                         &server1,
1969                         &share1,
1970                         &path1,
1971                         &user1,
1972                         &password1,
1973                         NULL)) {
1974                 errno = EINVAL;
1975                 TALLOC_FREE(frame);
1976                 return -1;
1977         }
1978
1979         if (!user1 || user1[0] == (char)0) {
1980                 user1 = talloc_strdup(frame, ocontext->user);
1981                 if (!user1) {
1982                         errno = ENOMEM;
1983                         TALLOC_FREE(frame);
1984                         return -1;
1985                 }
1986         }
1987
1988         if (smbc_parse_path(frame,
1989                                 ncontext,
1990                                 nname,
1991                                 NULL,
1992                                 &server2,
1993                                 &share2,
1994                                 &path2,
1995                                 &user2,
1996                                 &password2,
1997                                 NULL)) {
1998                 errno = EINVAL;
1999                 TALLOC_FREE(frame);
2000                 return -1;
2001         }
2002
2003         if (!user2 || user2[0] == (char)0) {
2004                 user2 = talloc_strdup(frame, ncontext->user);
2005                 if (!user2) {
2006                         errno = ENOMEM;
2007                         TALLOC_FREE(frame);
2008                         return -1;
2009                 }
2010         }
2011
2012         if (strcmp(server1, server2) || strcmp(share1, share2) ||
2013             strcmp(user1, user2)) {
2014                 /* Can't rename across file systems, or users?? */
2015                 errno = EXDEV;
2016                 TALLOC_FREE(frame);
2017                 return -1;
2018         }
2019
2020         srv = smbc_server(ocontext, True,
2021                           server1, share1, workgroup, user1, password1);
2022         if (!srv) {
2023                 TALLOC_FREE(frame);
2024                 return -1;
2025
2026         }
2027
2028         /*d_printf(">>>rename: resolving %s\n", path1);*/
2029         if (!cli_resolve_path(frame, "", srv->cli, path1,
2030                                 &targetcli1, &targetpath1)) {
2031                 d_printf("Could not resolve %s\n", path1);
2032                 TALLOC_FREE(frame);
2033                 return -1;
2034         }
2035         /*d_printf(">>>rename: resolved path as %s\n", targetpath1);*/
2036         /*d_printf(">>>rename: resolving %s\n", path2);*/
2037         if (!cli_resolve_path(frame, "", srv->cli, path2,
2038                                 &targetcli2, &targetpath2)) {
2039                 d_printf("Could not resolve %s\n", path2);
2040                 TALLOC_FREE(frame);
2041                 return -1;
2042         }
2043         /*d_printf(">>>rename: resolved path as %s\n", targetpath2);*/
2044
2045         if (strcmp(targetcli1->desthost, targetcli2->desthost) ||
2046             strcmp(targetcli1->share, targetcli2->share))
2047         {
2048                 /* can't rename across file systems */
2049                 errno = EXDEV;
2050                 TALLOC_FREE(frame);
2051                 return -1;
2052         }
2053
2054         if (!cli_rename(targetcli1, targetpath1, targetpath2)) {
2055                 int eno = smbc_errno(ocontext, targetcli1);
2056
2057                 if (eno != EEXIST ||
2058                     !cli_unlink(targetcli1, targetpath2) ||
2059                     !cli_rename(targetcli1, targetpath1, targetpath2)) {
2060
2061                         errno = eno;
2062                         TALLOC_FREE(frame);
2063                         return -1;
2064
2065                 }
2066         }
2067
2068         TALLOC_FREE(frame);
2069         return 0; /* Success */
2070 }
2071
2072 /*
2073  * A routine to lseek() a file
2074  */
2075
2076 static off_t
2077 smbc_lseek_ctx(SMBCCTX *context,
2078                SMBCFILE *file,
2079                off_t offset,
2080                int whence)
2081 {
2082         SMB_OFF_T size;
2083         char *server, *share, *user, *password;
2084         char *path;
2085         char *targetpath;
2086         struct cli_state *targetcli;
2087         TALLOC_CTX *frame = talloc_stackframe();
2088
2089         if (!context || !context->internal ||
2090             !context->internal->_initialized) {
2091                 errno = EINVAL;
2092                 TALLOC_FREE(frame);
2093                 return -1;
2094         }
2095
2096         if (!file || !DLIST_CONTAINS(context->internal->_files, file)) {
2097
2098                 errno = EBADF;
2099                 TALLOC_FREE(frame);
2100                 return -1;
2101
2102         }
2103
2104         if (!file->file) {
2105
2106                 errno = EINVAL;
2107                 TALLOC_FREE(frame);
2108                 return -1;      /* Can't lseek a dir ... */
2109
2110         }
2111
2112         switch (whence) {
2113         case SEEK_SET:
2114                 file->offset = offset;
2115                 break;
2116
2117         case SEEK_CUR:
2118                 file->offset += offset;
2119                 break;
2120
2121         case SEEK_END:
2122                 /*d_printf(">>>lseek: parsing %s\n", file->fname);*/
2123                 if (smbc_parse_path(frame,
2124                                         context,
2125                                         file->fname,
2126                                         NULL,
2127                                         &server,
2128                                         &share,
2129                                         &path,
2130                                         &user,
2131                                         &password,
2132                                         NULL)) {
2133                         errno = EINVAL;
2134                         TALLOC_FREE(frame);
2135                         return -1;
2136                 }
2137
2138                 /*d_printf(">>>lseek: resolving %s\n", path);*/
2139                 if (!cli_resolve_path(frame, "", file->srv->cli, path,
2140                                       &targetcli, &targetpath)) {
2141                         d_printf("Could not resolve %s\n", path);
2142                         TALLOC_FREE(frame);
2143                         return -1;
2144                 }
2145                 /*d_printf(">>>lseek: resolved path as %s\n", targetpath);*/
2146
2147                 if (!cli_qfileinfo(targetcli, file->cli_fd, NULL,
2148                                    &size, NULL, NULL, NULL, NULL, NULL))
2149                 {
2150                     SMB_OFF_T b_size = size;
2151                         if (!cli_getattrE(targetcli, file->cli_fd,
2152                                           NULL, &b_size, NULL, NULL, NULL))
2153                     {
2154                         errno = EINVAL;
2155                         TALLOC_FREE(frame);
2156                         return -1;
2157                     } else
2158                         size = b_size;
2159                 }
2160                 file->offset = size + offset;
2161                 break;
2162
2163         default:
2164                 errno = EINVAL;
2165                 break;
2166
2167         }
2168
2169         TALLOC_FREE(frame);
2170         return file->offset;
2171
2172 }
2173
2174 /* 
2175  * Generate an inode number from file name for those things that need it
2176  */
2177
2178 static ino_t
2179 smbc_inode(SMBCCTX *context,
2180            const char *name)
2181 {
2182         if (!context || !context->internal ||
2183             !context->internal->_initialized) {
2184
2185                 errno = EINVAL;
2186                 return -1;
2187
2188         }
2189
2190         if (!*name) return 2; /* FIXME, why 2 ??? */
2191         return (ino_t)str_checksum(name);
2192
2193 }
2194
2195 /*
2196  * Routine to put basic stat info into a stat structure ... Used by stat and
2197  * fstat below.
2198  */
2199
2200 static int
2201 smbc_setup_stat(SMBCCTX *context,
2202                 struct stat *st,
2203                 char *fname,
2204                 SMB_OFF_T size,
2205                 int mode)
2206 {
2207         TALLOC_CTX *frame = talloc_stackframe();
2208         
2209         st->st_mode = 0;
2210
2211         if (IS_DOS_DIR(mode)) {
2212                 st->st_mode = SMBC_DIR_MODE;
2213         } else {
2214                 st->st_mode = SMBC_FILE_MODE;
2215         }
2216
2217         if (IS_DOS_ARCHIVE(mode)) st->st_mode |= S_IXUSR;
2218         if (IS_DOS_SYSTEM(mode)) st->st_mode |= S_IXGRP;
2219         if (IS_DOS_HIDDEN(mode)) st->st_mode |= S_IXOTH;
2220         if (!IS_DOS_READONLY(mode)) st->st_mode |= S_IWUSR;
2221
2222         st->st_size = size;
2223 #ifdef HAVE_STAT_ST_BLKSIZE
2224         st->st_blksize = 512;
2225 #endif
2226 #ifdef HAVE_STAT_ST_BLOCKS
2227         st->st_blocks = (size+511)/512;
2228 #endif
2229         st->st_uid = getuid();
2230         st->st_gid = getgid();
2231
2232         if (IS_DOS_DIR(mode)) {
2233                 st->st_nlink = 2;
2234         } else {
2235                 st->st_nlink = 1;
2236         }
2237
2238         if (st->st_ino == 0) {
2239                 st->st_ino = smbc_inode(context, fname);
2240         }
2241         
2242         TALLOC_FREE(frame);
2243         return True;  /* FIXME: Is this needed ? */
2244
2245 }
2246
2247 /*
2248  * Routine to stat a file given a name
2249  */
2250
2251 static int
2252 smbc_stat_ctx(SMBCCTX *context,
2253               const char *fname,
2254               struct stat *st)
2255 {
2256         SMBCSRV *srv;
2257         char *server;
2258         char *share;
2259         char *user;
2260         char *password;
2261         char *workgroup;
2262         char *path;
2263         struct timespec write_time_ts;
2264         struct timespec access_time_ts;
2265         struct timespec change_time_ts;
2266         SMB_OFF_T size = 0;
2267         uint16 mode = 0;
2268         SMB_INO_T ino = 0;
2269         TALLOC_CTX *frame = talloc_stackframe();
2270
2271         if (!context || !context->internal ||
2272             !context->internal->_initialized) {
2273
2274                 errno = EINVAL;  /* Best I can think of ... */
2275                 TALLOC_FREE(frame);
2276                 return -1;
2277         }
2278
2279         if (!fname) {
2280                 errno = EINVAL;
2281                 TALLOC_FREE(frame);
2282                 return -1;
2283         }
2284
2285         DEBUG(4, ("smbc_stat(%s)\n", fname));
2286
2287         if (smbc_parse_path(frame,
2288                                 context,
2289                                 fname,
2290                                 &workgroup,
2291                                 &server,
2292                                 &share,
2293                                 &path,
2294                                 &user,
2295                                 &password,
2296                                 NULL)) {
2297                 errno = EINVAL;
2298                 TALLOC_FREE(frame);
2299                 return -1;
2300         }
2301
2302         if (!user || user[0] == (char)0) {
2303                 user = talloc_strdup(frame,context->user);
2304                 if (!user) {
2305                         errno = ENOMEM;
2306                         TALLOC_FREE(frame);
2307                         return -1;
2308                 }
2309         }
2310
2311         srv = smbc_server(context, True,
2312                           server, share, workgroup, user, password);
2313
2314         if (!srv) {
2315                 TALLOC_FREE(frame);
2316                 return -1;  /* errno set by smbc_server */
2317         }
2318
2319         if (!smbc_getatr(context, srv, path, &mode, &size,
2320                          NULL,
2321                          &access_time_ts,
2322                          &write_time_ts,
2323                          &change_time_ts,
2324                          &ino)) {
2325                 errno = smbc_errno(context, srv->cli);
2326                 TALLOC_FREE(frame);
2327                 return -1;
2328         }
2329
2330         st->st_ino = ino;
2331
2332         smbc_setup_stat(context, st, path, size, mode);
2333
2334         set_atimespec(st, access_time_ts);
2335         set_ctimespec(st, change_time_ts);
2336         set_mtimespec(st, write_time_ts);
2337         st->st_dev   = srv->dev;
2338
2339         TALLOC_FREE(frame);
2340         return 0;
2341
2342 }
2343
2344 /*
2345  * Routine to stat a file given an fd
2346  */
2347
2348 static int
2349 smbc_fstat_ctx(SMBCCTX *context,
2350                SMBCFILE *file,
2351                struct stat *st)
2352 {
2353         struct timespec change_time_ts;
2354         struct timespec access_time_ts;
2355         struct timespec write_time_ts;
2356         SMB_OFF_T size;
2357         uint16 mode;
2358         char *server;
2359         char *share;
2360         char *user;
2361         char *password;
2362         char *path;
2363         char *targetpath;
2364         struct cli_state *targetcli;
2365         SMB_INO_T ino = 0;
2366         TALLOC_CTX *frame = talloc_stackframe();
2367
2368         if (!context || !context->internal ||
2369             !context->internal->_initialized) {
2370                 errno = EINVAL;
2371                 TALLOC_FREE(frame);
2372                 return -1;
2373         }
2374
2375         if (!file || !DLIST_CONTAINS(context->internal->_files, file)) {
2376                 errno = EBADF;
2377                 TALLOC_FREE(frame);
2378                 return -1;
2379         }
2380
2381         if (!file->file) {
2382                 TALLOC_FREE(frame);
2383                 return (context->fstatdir)(context, file, st);
2384         }
2385
2386         /*d_printf(">>>fstat: parsing %s\n", file->fname);*/
2387         if (smbc_parse_path(frame,
2388                                 context,
2389                                 file->fname,
2390                                 NULL,
2391                                 &server,
2392                                 &share,
2393                                 &path,
2394                                 &user,
2395                                 &password,
2396                                 NULL)) {
2397                 errno = EINVAL;
2398                 TALLOC_FREE(frame);
2399                 return -1;
2400         }
2401
2402         /*d_printf(">>>fstat: resolving %s\n", path);*/
2403         if (!cli_resolve_path(frame, "", file->srv->cli, path,
2404                               &targetcli, &targetpath)) {
2405                 d_printf("Could not resolve %s\n", path);
2406                 TALLOC_FREE(frame);
2407                 return -1;
2408         }
2409         /*d_printf(">>>fstat: resolved path as %s\n", targetpath);*/
2410
2411         if (!cli_qfileinfo(targetcli, file->cli_fd, &mode, &size,
2412                            NULL,
2413                            &access_time_ts,
2414                            &write_time_ts,
2415                            &change_time_ts,
2416                            &ino)) {
2417
2418                 time_t change_time, access_time, write_time;
2419
2420                 if (!cli_getattrE(targetcli, file->cli_fd, &mode, &size,
2421                                 &change_time, &access_time, &write_time)) {
2422
2423                         errno = EINVAL;
2424                         TALLOC_FREE(frame);
2425                         return -1;
2426                 }
2427
2428                 change_time_ts = convert_time_t_to_timespec(change_time);
2429                 access_time_ts = convert_time_t_to_timespec(access_time);
2430                 write_time_ts = convert_time_t_to_timespec(write_time);
2431         }
2432
2433         st->st_ino = ino;
2434
2435         smbc_setup_stat(context, st, file->fname, size, mode);
2436
2437         set_atimespec(st, access_time_ts);
2438         set_ctimespec(st, change_time_ts);
2439         set_mtimespec(st, write_time_ts);
2440         st->st_dev = file->srv->dev;
2441
2442         TALLOC_FREE(frame);
2443         return 0;
2444
2445 }
2446
2447 /*
2448  * Routine to open a directory
2449  * We accept the URL syntax explained in smbc_parse_path(), above.
2450  */
2451
2452 static void
2453 smbc_remove_dir(SMBCFILE *dir)
2454 {
2455         struct smbc_dir_list *d,*f;
2456
2457         d = dir->dir_list;
2458         while (d) {
2459
2460                 f = d; d = d->next;
2461
2462                 SAFE_FREE(f->dirent);
2463                 SAFE_FREE(f);
2464
2465         }
2466
2467         dir->dir_list = dir->dir_end = dir->dir_next = NULL;
2468
2469 }
2470
2471 static int
2472 add_dirent(SMBCFILE *dir,
2473            const char *name,
2474            const char *comment,
2475            uint32 type)
2476 {
2477         struct smbc_dirent *dirent;
2478         int size;
2479         int name_length = (name == NULL ? 0 : strlen(name));
2480         int comment_len = (comment == NULL ? 0 : strlen(comment));
2481
2482         /*
2483          * Allocate space for the dirent, which must be increased by the 
2484          * size of the name and the comment and 1 each for the null terminator.
2485          */
2486
2487         size = sizeof(struct smbc_dirent) + name_length + comment_len + 2;
2488     
2489         dirent = (struct smbc_dirent *)SMB_MALLOC(size);
2490
2491         if (!dirent) {
2492
2493                 dir->dir_error = ENOMEM;
2494                 return -1;
2495
2496         }
2497
2498         ZERO_STRUCTP(dirent);
2499
2500         if (dir->dir_list == NULL) {
2501
2502                 dir->dir_list = SMB_MALLOC_P(struct smbc_dir_list);
2503                 if (!dir->dir_list) {
2504
2505                         SAFE_FREE(dirent);
2506                         dir->dir_error = ENOMEM;
2507                         return -1;
2508
2509                 }
2510                 ZERO_STRUCTP(dir->dir_list);
2511
2512                 dir->dir_end = dir->dir_next = dir->dir_list;
2513         }
2514         else {
2515
2516                 dir->dir_end->next = SMB_MALLOC_P(struct smbc_dir_list);
2517                 
2518                 if (!dir->dir_end->next) {
2519                         
2520                         SAFE_FREE(dirent);
2521                         dir->dir_error = ENOMEM;
2522                         return -1;
2523
2524                 }
2525                 ZERO_STRUCTP(dir->dir_end->next);
2526
2527                 dir->dir_end = dir->dir_end->next;
2528         }
2529
2530         dir->dir_end->next = NULL;
2531         dir->dir_end->dirent = dirent;
2532         
2533         dirent->smbc_type = type;
2534         dirent->namelen = name_length;
2535         dirent->commentlen = comment_len;
2536         dirent->dirlen = size;
2537   
2538         /*
2539          * dirent->namelen + 1 includes the null (no null termination needed)
2540          * Ditto for dirent->commentlen.
2541          * The space for the two null bytes was allocated.
2542          */
2543         strncpy(dirent->name, (name?name:""), dirent->namelen + 1);
2544         dirent->comment = (char *)(&dirent->name + dirent->namelen + 1);
2545         strncpy(dirent->comment, (comment?comment:""), dirent->commentlen + 1);
2546         
2547         return 0;
2548
2549 }
2550
2551 static void
2552 list_unique_wg_fn(const char *name,
2553                   uint32 type,
2554                   const char *comment,
2555                   void *state)
2556 {
2557         SMBCFILE *dir = (SMBCFILE *)state;
2558         struct smbc_dir_list *dir_list;
2559         struct smbc_dirent *dirent;
2560         int dirent_type;
2561         int do_remove = 0;
2562
2563         dirent_type = dir->dir_type;
2564
2565         if (add_dirent(dir, name, comment, dirent_type) < 0) {
2566
2567                 /* An error occurred, what do we do? */
2568                 /* FIXME: Add some code here */
2569         }
2570
2571         /* Point to the one just added */
2572         dirent = dir->dir_end->dirent;
2573
2574         /* See if this was a duplicate */
2575         for (dir_list = dir->dir_list;
2576              dir_list != dir->dir_end;
2577              dir_list = dir_list->next) {
2578                 if (! do_remove &&
2579                     strcmp(dir_list->dirent->name, dirent->name) == 0) {
2580                         /* Duplicate.  End end of list need to be removed. */
2581                         do_remove = 1;
2582                 }
2583
2584                 if (do_remove && dir_list->next == dir->dir_end) {
2585                         /* Found the end of the list.  Remove it. */
2586                         dir->dir_end = dir_list;
2587                         free(dir_list->next);
2588                         free(dirent);
2589                         dir_list->next = NULL;
2590                         break;
2591                 }
2592         }
2593 }
2594
2595 static void
2596 list_fn(const char *name,
2597         uint32 type,
2598         const char *comment,
2599         void *state)
2600 {
2601         SMBCFILE *dir = (SMBCFILE *)state;
2602         int dirent_type;
2603
2604         /*
2605          * We need to process the type a little ...
2606          *
2607          * Disk share     = 0x00000000
2608          * Print share    = 0x00000001
2609          * Comms share    = 0x00000002 (obsolete?)
2610          * IPC$ share     = 0x00000003
2611          *
2612          * administrative shares:
2613          * ADMIN$, IPC$, C$, D$, E$ ...  are type |= 0x80000000
2614          */
2615
2616         if (dir->dir_type == SMBC_FILE_SHARE) {
2617                 switch (type) {
2618                 case 0 | 0x80000000:
2619                 case 0:
2620                         dirent_type = SMBC_FILE_SHARE;
2621                         break;
2622
2623                 case 1:
2624                         dirent_type = SMBC_PRINTER_SHARE;
2625                         break;
2626
2627                 case 2:
2628                         dirent_type = SMBC_COMMS_SHARE;
2629                         break;
2630
2631                 case 3 | 0x80000000:
2632                 case 3:
2633                         dirent_type = SMBC_IPC_SHARE;
2634                         break;
2635
2636                 default:
2637                         dirent_type = SMBC_FILE_SHARE; /* FIXME, error? */
2638                         break;
2639                 }
2640         }
2641         else {
2642                 dirent_type = dir->dir_type;
2643         }
2644
2645         if (add_dirent(dir, name, comment, dirent_type) < 0) {
2646
2647                 /* An error occurred, what do we do? */
2648                 /* FIXME: Add some code here */
2649
2650         }
2651 }
2652
2653 static void
2654 dir_list_fn(const char *mnt,
2655             file_info *finfo,
2656             const char *mask,
2657             void *state)
2658 {
2659
2660         if (add_dirent((SMBCFILE *)state, finfo->name, "", 
2661                        (finfo->mode&aDIR?SMBC_DIR:SMBC_FILE)) < 0) {
2662
2663                 /* Handle an error ... */
2664
2665                 /* FIXME: Add some code ... */
2666
2667         } 
2668
2669 }
2670
2671 static int
2672 net_share_enum_rpc(struct cli_state *cli,
2673                    void (*fn)(const char *name,
2674                               uint32 type,
2675                               const char *comment,
2676                               void *state),
2677                    void *state)
2678 {
2679         int i;
2680         WERROR result;
2681         ENUM_HND enum_hnd;
2682         uint32 info_level = 1;
2683         uint32 preferred_len = 0xffffffff;
2684         uint32 type;
2685         SRV_SHARE_INFO_CTR ctr;
2686         fstring name = "";
2687         fstring comment = "";
2688         struct rpc_pipe_client *pipe_hnd;
2689         NTSTATUS nt_status;
2690
2691         /* Open the server service pipe */
2692         pipe_hnd = cli_rpc_pipe_open_noauth(cli, PI_SRVSVC, &nt_status);
2693         if (!pipe_hnd) {
2694                 DEBUG(1, ("net_share_enum_rpc pipe open fail!\n"));
2695                 return -1;
2696         }
2697
2698         /* Issue the NetShareEnum RPC call and retrieve the response */
2699         init_enum_hnd(&enum_hnd, 0);
2700         result = rpccli_srvsvc_net_share_enum(pipe_hnd,
2701                                               talloc_tos(),
2702                                               info_level,
2703                                               &ctr,
2704                                               preferred_len,
2705                                               &enum_hnd);
2706
2707         /* Was it successful? */
2708         if (!W_ERROR_IS_OK(result) || ctr.num_entries == 0) {
2709                 /*  Nope.  Go clean up. */
2710                 goto done;
2711         }
2712
2713         /* For each returned entry... */
2714         for (i = 0; i < ctr.num_entries; i++) {
2715
2716                 /* pull out the share name */
2717                 rpcstr_pull_unistr2_fstring(
2718                         name, &ctr.share.info1[i].info_1_str.uni_netname);
2719
2720                 /* pull out the share's comment */
2721                 rpcstr_pull_unistr2_fstring(
2722                         comment, &ctr.share.info1[i].info_1_str.uni_remark);
2723
2724                 /* Get the type value */
2725                 type = ctr.share.info1[i].info_1.type;
2726
2727                 /* Add this share to the list */
2728                 (*fn)(name, type, comment, state);
2729         }
2730
2731 done:
2732         /* Close the server service pipe */
2733         cli_rpc_pipe_close(pipe_hnd);
2734
2735         /* Tell 'em if it worked */
2736         return W_ERROR_IS_OK(result) ? 0 : -1;
2737 }
2738
2739
2740
2741 static SMBCFILE *
2742 smbc_opendir_ctx(SMBCCTX *context,
2743                  const char *fname)
2744 {
2745         int saved_errno;
2746         char *server, *share, *user, *password, *options;
2747         char *workgroup;
2748         char *path;
2749         uint16 mode;
2750         char *p;
2751         SMBCSRV *srv  = NULL;
2752         SMBCFILE *dir = NULL;
2753         struct _smbc_callbacks *cb;
2754         struct sockaddr_storage rem_ss;
2755         TALLOC_CTX *frame = talloc_stackframe();
2756
2757         if (!context || !context->internal ||
2758             !context->internal->_initialized) {
2759                 DEBUG(4, ("no valid context\n"));
2760                 errno = EINVAL + 8192;
2761                 TALLOC_FREE(frame);
2762                 return NULL;
2763
2764         }
2765
2766         if (!fname) {
2767                 DEBUG(4, ("no valid fname\n"));
2768                 errno = EINVAL + 8193;
2769                 TALLOC_FREE(frame);
2770                 return NULL;
2771         }
2772
2773         if (smbc_parse_path(frame,
2774                                 context,
2775                                 fname,
2776                                 &workgroup,
2777                                 &server,
2778                                 &share,
2779                                 &path,
2780                                 &user,
2781                                 &password,
2782                                 &options)) {
2783                 DEBUG(4, ("no valid path\n"));
2784                 errno = EINVAL + 8194;
2785                 TALLOC_FREE(frame);
2786                 return NULL;
2787         }
2788
2789         DEBUG(4, ("parsed path: fname='%s' server='%s' share='%s' "
2790                   "path='%s' options='%s'\n",
2791                   fname, server, share, path, options));
2792
2793         /* Ensure the options are valid */
2794         if (smbc_check_options(server, share, path, options)) {
2795                 DEBUG(4, ("unacceptable options (%s)\n", options));
2796                 errno = EINVAL + 8195;
2797                 TALLOC_FREE(frame);
2798                 return NULL;
2799         }
2800
2801         if (!user || user[0] == (char)0) {
2802                 user = talloc_strdup(frame, context->user);
2803                 if (!user) {
2804                         errno = ENOMEM;
2805                         TALLOC_FREE(frame);
2806                         return NULL;
2807                 }
2808         }
2809
2810         dir = SMB_MALLOC_P(SMBCFILE);
2811
2812         if (!dir) {
2813                 errno = ENOMEM;
2814                 TALLOC_FREE(frame);
2815                 return NULL;
2816         }
2817
2818         ZERO_STRUCTP(dir);
2819
2820         dir->cli_fd   = 0;
2821         dir->fname    = SMB_STRDUP(fname);
2822         dir->srv      = NULL;
2823         dir->offset   = 0;
2824         dir->file     = False;
2825         dir->dir_list = dir->dir_next = dir->dir_end = NULL;
2826
2827         if (server[0] == (char)0) {
2828
2829                 int i;
2830                 int count;
2831                 int max_lmb_count;
2832                 struct ip_service *ip_list;
2833                 struct ip_service server_addr;
2834                 struct user_auth_info u_info;
2835
2836                 if (share[0] != (char)0 || path[0] != (char)0) {
2837
2838                         errno = EINVAL + 8196;
2839                         if (dir) {
2840                                 SAFE_FREE(dir->fname);
2841                                 SAFE_FREE(dir);
2842                         }
2843                         TALLOC_FREE(frame);
2844                         return NULL;
2845                 }
2846
2847                 /* Determine how many local master browsers to query */
2848                 max_lmb_count = (context->options.browse_max_lmb_count == 0
2849                                  ? INT_MAX
2850                                  : context->options.browse_max_lmb_count);
2851
2852                 memset(&u_info, '\0', sizeof(u_info));
2853                 u_info.username = talloc_strdup(frame,user);
2854                 u_info.password = talloc_strdup(frame,password);
2855                 if (!u_info.username || !u_info.password) {
2856                         if (dir) {
2857                                 SAFE_FREE(dir->fname);
2858                                 SAFE_FREE(dir);
2859                         }
2860                         TALLOC_FREE(frame);
2861                         return NULL;
2862                 }
2863
2864                 /*
2865                  * We have server and share and path empty but options
2866                  * requesting that we scan all master browsers for their list
2867                  * of workgroups/domains.  This implies that we must first try
2868                  * broadcast queries to find all master browsers, and if that
2869                  * doesn't work, then try our other methods which return only
2870                  * a single master browser.
2871                  */
2872
2873                 ip_list = NULL;
2874                 if (!NT_STATUS_IS_OK(name_resolve_bcast(MSBROWSE, 1, &ip_list,
2875                                      &count)))
2876                 {
2877
2878                         SAFE_FREE(ip_list);
2879
2880                         if (!find_master_ip(workgroup, &server_addr.ss)) {
2881
2882                                 if (dir) {
2883                                         SAFE_FREE(dir->fname);
2884                                         SAFE_FREE(dir);
2885                                 }
2886                                 errno = ENOENT;
2887                                 TALLOC_FREE(frame);
2888                                 return NULL;
2889                         }
2890
2891                         ip_list = (struct ip_service *)memdup(
2892                                 &server_addr, sizeof(server_addr));
2893                         if (ip_list == NULL) {
2894                                 errno = ENOMEM;
2895                                 TALLOC_FREE(frame);
2896                                 return NULL;
2897                         }
2898                         count = 1;
2899                 }
2900
2901                 for (i = 0; i < count && i < max_lmb_count; i++) {
2902                         char addr[INET6_ADDRSTRLEN];
2903                         char *wg_ptr = NULL;
2904                         struct cli_state *cli = NULL;
2905
2906                         print_sockaddr(addr, sizeof(addr), &ip_list[i].ss);
2907                         DEBUG(99, ("Found master browser %d of %d: %s\n",
2908                                    i+1, MAX(count, max_lmb_count),
2909                                    addr));
2910
2911                         cli = get_ipc_connect_master_ip(talloc_tos(),
2912                                                         &ip_list[i],
2913                                                         &u_info,
2914                                                         &wg_ptr);
2915                         /* cli == NULL is the master browser refused to talk or
2916                            could not be found */
2917                         if (!cli) {
2918                                 continue;
2919                         }
2920
2921                         workgroup = talloc_strdup(frame, wg_ptr);
2922                         server = talloc_strdup(frame, cli->desthost);
2923
2924                         cli_shutdown(cli);
2925
2926                         if (!workgroup || !server) {
2927                                 errno = ENOMEM;
2928                                 TALLOC_FREE(frame);
2929                                 return NULL;
2930                         }
2931
2932                         DEBUG(4, ("using workgroup %s %s\n",
2933                                   workgroup, server));
2934
2935                         /*
2936                          * For each returned master browser IP address, get a
2937                          * connection to IPC$ on the server if we do not
2938                          * already have one, and determine the
2939                          * workgroups/domains that it knows about.
2940                          */
2941
2942                         srv = smbc_server(context, True, server, "IPC$",
2943                                           workgroup, user, password);
2944                         if (!srv) {
2945                                 continue;
2946                         }
2947
2948                         dir->srv = srv;
2949                         dir->dir_type = SMBC_WORKGROUP;
2950
2951                         /* Now, list the stuff ... */
2952
2953                         if (!cli_NetServerEnum(srv->cli,
2954                                                workgroup,
2955                                                SV_TYPE_DOMAIN_ENUM,
2956                                                list_unique_wg_fn,
2957                                                (void *)dir)) {
2958                                 continue;
2959                         }
2960                 }
2961
2962                 SAFE_FREE(ip_list);
2963         } else {
2964                 /*
2965                  * Server not an empty string ... Check the rest and see what
2966                  * gives
2967                  */
2968                 if (*share == '\0') {
2969                         if (*path != '\0') {
2970
2971                                 /* Should not have empty share with path */
2972                                 errno = EINVAL + 8197;
2973                                 if (dir) {
2974                                         SAFE_FREE(dir->fname);
2975                                         SAFE_FREE(dir);
2976                                 }
2977                                 TALLOC_FREE(frame);
2978                                 return NULL;
2979
2980                         }
2981
2982                         /*
2983                          * We don't know if <server> is really a server name
2984                          * or is a workgroup/domain name.  If we already have
2985                          * a server structure for it, we'll use it.
2986                          * Otherwise, check to see if <server><1D>,
2987                          * <server><1B>, or <server><20> translates.  We check
2988                          * to see if <server> is an IP address first.
2989                          */
2990
2991                         /*
2992                          * See if we have an existing server.  Do not
2993                          * establish a connection if one does not already
2994                          * exist.
2995                          */
2996                         srv = smbc_server(context, False, server, "IPC$",
2997                                           workgroup, user, password);
2998
2999                         /*
3000                          * If no existing server and not an IP addr, look for
3001                          * LMB or DMB
3002                          */
3003                         if (!srv &&
3004                             !is_ipaddress(server) &&
3005                             (resolve_name(server, &rem_ss, 0x1d) ||   /* LMB */
3006                              resolve_name(server, &rem_ss, 0x1b) )) { /* DMB */
3007
3008                                 fstring buserver;
3009
3010                                 dir->dir_type = SMBC_SERVER;
3011
3012                                 /*
3013                                  * Get the backup list ...
3014                                  */
3015                                 if (!name_status_find(server, 0, 0,
3016                                                       &rem_ss, buserver)) {
3017
3018                                         DEBUG(0, ("Could not get name of "
3019                                                   "local/domain master browser "
3020                                                   "for server %s\n", server));
3021                                         if (dir) {
3022                                                 SAFE_FREE(dir->fname);
3023                                                 SAFE_FREE(dir);
3024                                         }
3025                                         errno = EPERM;
3026                                         TALLOC_FREE(frame);
3027                                         return NULL;
3028
3029                                 }
3030
3031                                 /*
3032                                  * Get a connection to IPC$ on the server if
3033                                  * we do not already have one
3034                                  */
3035                                 srv = smbc_server(context, True,
3036                                                   buserver, "IPC$",
3037                                                   workgroup, user, password);
3038                                 if (!srv) {
3039                                         DEBUG(0, ("got no contact to IPC$\n"));
3040                                         if (dir) {
3041                                                 SAFE_FREE(dir->fname);
3042                                                 SAFE_FREE(dir);
3043                                         }
3044                                         TALLOC_FREE(frame);
3045                                         return NULL;
3046
3047                                 }
3048
3049                                 dir->srv = srv;
3050
3051                                 /* Now, list the servers ... */
3052                                 if (!cli_NetServerEnum(srv->cli, server,
3053                                                        0x0000FFFE, list_fn,
3054                                                        (void *)dir)) {
3055
3056                                         if (dir) {
3057                                                 SAFE_FREE(dir->fname);
3058                                                 SAFE_FREE(dir);
3059                                         }
3060                                         TALLOC_FREE(frame);
3061                                         return NULL;
3062                                 }
3063                         } else if (srv ||
3064                                    (resolve_name(server, &rem_ss, 0x20))) {
3065
3066                                 /* If we hadn't found the server, get one now */
3067                                 if (!srv) {
3068                                         srv = smbc_server(context, True,
3069                                                           server, "IPC$",
3070                                                           workgroup,
3071                                                           user, password);
3072                                 }
3073
3074                                 if (!srv) {
3075                                         if (dir) {
3076                                                 SAFE_FREE(dir->fname);
3077                                                 SAFE_FREE(dir);
3078                                         }
3079                                         TALLOC_FREE(frame);
3080                                         return NULL;
3081
3082                                 }
3083
3084                                 dir->dir_type = SMBC_FILE_SHARE;
3085                                 dir->srv = srv;
3086
3087                                 /* List the shares ... */
3088
3089                                 if (net_share_enum_rpc(
3090                                             srv->cli,
3091                                             list_fn,
3092                                             (void *) dir) < 0 &&
3093                                     cli_RNetShareEnum(
3094                                             srv->cli,
3095                                             list_fn,
3096                                             (void *)dir) < 0) {
3097
3098                                         errno = cli_errno(srv->cli);
3099                                         if (dir) {
3100                                                 SAFE_FREE(dir->fname);
3101                                                 SAFE_FREE(dir);
3102                                         }
3103                                         TALLOC_FREE(frame);
3104                                         return NULL;
3105
3106                                 }
3107                         } else {