dd46749a5a9386bb1f6310a26aafed67fa684e80
[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    
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 2 of the License, or
12    (at your option) any later version.
13    
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18    
19    You should have received a copy of the GNU General Public License
20    along with this program; if not, write to the Free Software
21    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 */
23
24 #include "includes.h"
25
26 #include "../include/libsmb_internal.h"
27
28 /*
29  * Functions exported by libsmb_cache.c that we need here
30  */
31 int smbc_default_cache_functions(SMBCCTX *context);
32
33 /* 
34  * check if an element is part of the list. 
35  * FIXME: Does not belong here !  
36  * Can anyone put this in a macro in dlinklist.h ?
37  * -- Tom
38  */
39 static int DLIST_CONTAINS(SMBCFILE * list, SMBCFILE *p) {
40         if (!p || !list) return False;
41         do {
42                 if (p == list) return True;
43                 list = list->next;
44         } while (list);
45         return False;
46 }
47
48 extern BOOL in_client;
49 extern pstring global_myname;
50
51 /*
52  * Is the logging working / configfile read ? 
53  */
54 static int smbc_initialized = 0;
55
56 /*
57  * Function to parse a path and turn it into components
58  *
59  * We accept smb://[[[domain;]user[:password@]]server[/share[/path[/file]]]]
60  * 
61  * smb://       means show all the workgroups
62  * smb://name/  means, if name<1D> or name<1B> exists, list servers in workgroup,
63  *              else, if name<20> exists, list all shares for server ...
64  */
65
66 static const char *smbc_prefix = "smb:";
67
68 static int
69 smbc_parse_path(SMBCCTX *context, const char *fname, char *server, char *share, char *path,
70                 char *user, char *password) /* FIXME, lengths of strings */
71 {
72         static pstring s;
73         pstring userinfo;
74         char *p;
75         char *q, *r;
76         int len;
77
78         server[0] = share[0] = path[0] = user[0] = password[0] = (char)0;
79         pstrcpy(s, fname);
80
81         /*  clean_fname(s);  causing problems ... */
82
83         /* see if it has the right prefix */
84         len = strlen(smbc_prefix);
85         if (strncmp(s,smbc_prefix,len) || 
86             (s[len] != '/' && s[len] != 0)) return -1; /* What about no smb: ? */
87
88         p = s + len;
89
90         /* Watch the test below, we are testing to see if we should exit */
91
92         if (strncmp(p, "//", 2) && strncmp(p, "\\\\", 2)) {
93
94                 return -1;
95
96         }
97
98         p += 2;  /* Skip the // or \\  */
99
100         if (*p == (char)0)
101                 return 0;
102
103         if (*p == '/') {
104
105                 strncpy(server, context->workgroup, 
106                         (strlen(context->workgroup) < 16)?strlen(context->workgroup):16);
107                 return 0;
108                 
109         }
110
111         /*
112          * ok, its for us. Now parse out the server, share etc. 
113          *
114          * However, we want to parse out [[domain;]user[:password]@] if it
115          * exists ...
116          */
117
118         /* check that '@' occurs before '/', if '/' exists at all */
119         q = strchr_m(p, '@');
120         r = strchr_m(p, '/');
121         if (q && (!r || q < r)) {
122                 pstring username, passwd, domain;
123                 char *u = userinfo;
124
125                 next_token(&p, userinfo, "@", sizeof(fstring));
126
127                 username[0] = passwd[0] = domain[0] = 0;
128
129                 if (strchr_m(u, ';')) {
130       
131                         next_token(&u, domain, ";", sizeof(fstring));
132
133                 }
134
135                 if (strchr_m(u, ':')) {
136
137                         next_token(&u, username, ":", sizeof(fstring));
138
139                         pstrcpy(passwd, u);
140
141                 }
142                 else {
143
144                         pstrcpy(username, u);
145
146                 }
147
148                 if (username[0])
149                         strncpy(user, username, sizeof(fstring));  /* FIXME, size and domain */
150
151                 if (passwd[0])
152                         strncpy(password, passwd, sizeof(fstring)); /* FIXME, size */
153
154         }
155
156         if (!next_token(&p, server, "/", sizeof(fstring))) {
157
158                 return -1;
159
160         }
161
162         if (*p == (char)0) return 0;  /* That's it ... */
163   
164         if (!next_token(&p, share, "/", sizeof(fstring))) {
165
166                 return -1;
167
168         }
169
170         pstrcpy(path, p);
171   
172         all_string_sub(path, "/", "\\", 0);
173
174         return 0;
175 }
176
177 /*
178  * Convert an SMB error into a UNIX error ...
179  */
180
181 static int smbc_errno(SMBCCTX *context, struct cli_state *c)
182 {
183         int ret = cli_errno(c);
184         
185         if (cli_is_dos_error(c)) {
186                 uint8 eclass;
187                 uint32 ecode;
188
189                 cli_dos_error(c, &eclass, &ecode);
190                 
191                 DEBUG(3,("smbc_error %d %d (0x%x) -> %d\n", 
192                          (int)eclass, (int)ecode, (int)ecode, ret));
193         } else {
194                 NTSTATUS status;
195
196                 status = cli_nt_error(c);
197
198                 DEBUG(3,("smbc errno %s -> %d\n",
199                          nt_errstr(status), ret));
200         }
201
202         return ret;
203 }
204
205 /* 
206  * Check a server_fd.
207  * returns 0 if the server is in shape. Returns 1 on error 
208  * 
209  * Also useable outside libsmbclient to enable external cache
210  * to do some checks too.
211  */
212 int smbc_check_server(SMBCCTX * context, SMBCSRV * server) 
213 {
214         if ( send_keepalive(server->cli.fd) == False )
215                 return 1;
216
217         /* connection is ok */
218         return 0;
219 }
220
221 /* 
222  * Remove a server from the cached server list it's unused.
223  * On success, 0 is returned. 1 is returned if the server could not be removed.
224  * 
225  * Also useable outside libsmbclient
226  */
227 int smbc_remove_unused_server(SMBCCTX * context, SMBCSRV * srv)
228 {
229         SMBCFILE * file;
230
231         /* are we being fooled ? */
232         if (!context || !context->internal ||
233             !context->internal->_initialized || !srv) return 1;
234
235         
236         /* Check all open files/directories for a relation with this server */
237         for (file = context->internal->_files; file; file=file->next) {
238                 if (file->srv == srv) {
239                         /* Still used */
240                         DEBUG(3, ("smbc_remove_usused_server: %p still used by %p.\n", 
241                                   srv, file));
242                         return 1;
243                 }
244         }
245
246         DLIST_REMOVE(context->internal->_servers, srv);
247
248         cli_shutdown(&srv->cli);
249
250         DEBUG(3, ("smbc_remove_usused_server: %p removed.\n", srv));
251
252         context->callbacks.remove_cached_srv_fn(context, srv);
253         
254         SAFE_FREE(srv);
255         
256         return 0;
257 }
258
259 /*
260  * Connect to a server, possibly on an existing connection
261  *
262  * Here, what we want to do is: If the server and username
263  * match an existing connection, reuse that, otherwise, establish a 
264  * new connection.
265  *
266  * If we have to create a new connection, call the auth_fn to get the
267  * info we need, unless the username and password were passed in.
268  */
269
270 SMBCSRV *smbc_server(SMBCCTX *context,
271                      char *server, char *share, 
272                      char *workgroup, char *username, 
273                      char *password)
274 {
275         SMBCSRV *srv=NULL;
276         int auth_called = 0;
277         struct cli_state c;
278         struct nmb_name called, calling;
279         char *p, *server_n = server;
280         fstring group;
281         pstring ipenv;
282         struct in_addr ip;
283         int tried_reverse = 0;
284   
285         zero_ip(&ip);
286         ZERO_STRUCT(c);
287
288         if (server[0] == 0) {
289                 errno = EPERM;
290                 return NULL;
291         }
292
293  check_server_cache:
294
295         srv = context->callbacks.get_cached_srv_fn(context, server, share, 
296                                                    workgroup, username);
297         
298         if (!auth_called && !srv && (!username[0] || !password[0])) {
299                 context->callbacks.auth_fn(server, share, workgroup, sizeof(fstring),
300                              username, sizeof(fstring), password, sizeof(fstring));
301                 /* 
302                  * However, smbc_auth_fn may have picked up info relating to an 
303                  * existing connection, so try for an existing connection again ...
304                  */
305                 auth_called = 1;
306                 goto check_server_cache;
307                 
308         }
309         
310         if (srv) {
311                 if (context->callbacks.check_server_fn(context, srv)) {
312                         /* 
313                          * This server is no good anymore 
314                          * Try to remove it and check for more possible servers in the cache 
315                          */
316                         if (context->callbacks.remove_unused_server_fn(context, srv)) { 
317                                 /* 
318                                  * We could not remove the server completely, remove it from the cache
319                                  * so we will not get it again. It will be removed when the last file/dir
320                                  * is closed.
321                                  */
322                                 context->callbacks.remove_cached_srv_fn(context, srv);
323                         }
324                         
325                         /* 
326                          * Maybe there are more cached connections to this server 
327                          */
328                         goto check_server_cache; 
329                 }
330                 return srv;
331         }
332
333         make_nmb_name(&calling, context->netbios_name, 0x0);
334         make_nmb_name(&called , server, 0x20);
335
336         DEBUG(4,("smbc_server: server_n=[%s] server=[%s]\n", server_n, server));
337   
338         if ((p=strchr_m(server_n,'#')) && 
339             (strcmp(p+1,"1D")==0 || strcmp(p+1,"01")==0)) {
340     
341                 fstrcpy(group, server_n);
342                 p = strchr_m(group,'#');
343                 *p = 0;
344                 
345         }
346
347         DEBUG(4,(" -> server_n=[%s] server=[%s]\n", server_n, server));
348
349  again:
350         slprintf(ipenv,sizeof(ipenv)-1,"HOST_%s", server_n);
351
352         zero_ip(&ip);
353
354         /* have to open a new connection */
355         if (!cli_initialise(&c)) {
356                 errno = ENOENT;
357                 return NULL;
358         }
359
360         c.timeout = context->timeout;
361
362         if (!cli_connect(&c, server_n, &ip)) {
363                 cli_shutdown(&c);
364                 errno = ENOENT;
365                 return NULL;
366         }
367
368         if (!cli_session_request(&c, &calling, &called)) {
369                 cli_shutdown(&c);
370                 if (strcmp(called.name, "*SMBSERVER")) {
371                         make_nmb_name(&called , "*SMBSERVER", 0x20);
372                         goto again;
373                 }
374                 else {  /* Try one more time, but ensure we don't loop */
375
376                   /* Only try this if server is an IP address ... */
377
378                   if (is_ipaddress(server) && !tried_reverse) {
379                     fstring remote_name;
380                     struct in_addr rem_ip;
381
382                     if ((rem_ip.s_addr=inet_addr(server)) == INADDR_NONE) {
383                       DEBUG(4, ("Could not convert IP address %s to struct in_addr\n", server));
384                       errno = ENOENT;
385                       return NULL;
386                     }
387
388                     tried_reverse++; /* Yuck */
389
390                     if (name_status_find("*", 0, 0, rem_ip, remote_name)) {
391                       make_nmb_name(&called, remote_name, 0x20);
392                       goto again;
393                     }
394
395
396                   }
397                 }
398                 errno = ENOENT;
399                 return NULL;
400         }
401   
402         DEBUG(4,(" session request ok\n"));
403   
404         if (!cli_negprot(&c)) {
405                 cli_shutdown(&c);
406                 errno = ENOENT;
407                 return NULL;
408         }
409
410         if (!cli_session_setup(&c, username, 
411                                password, strlen(password),
412                                password, strlen(password),
413                                workgroup) &&
414             /* try an anonymous login if it failed */
415             !cli_session_setup(&c, "", "", 1,"", 0, workgroup)) {
416                 cli_shutdown(&c);
417                 errno = EPERM;
418                 return NULL;
419         }
420
421         DEBUG(4,(" session setup ok\n"));
422
423         if (!cli_send_tconX(&c, share, "?????",
424                             password, strlen(password)+1)) {
425                 errno = smbc_errno(context, &c);
426                 cli_shutdown(&c);
427                 return NULL;
428         }
429   
430         DEBUG(4,(" tconx ok\n"));
431   
432         /*
433          * Ok, we have got a nice connection
434          * Let's find a free server_fd 
435          */
436
437         srv = (SMBCSRV *)malloc(sizeof(*srv));
438         if (!srv) {
439                 errno = ENOMEM;
440                 goto failed;
441         }
442
443         ZERO_STRUCTP(srv);
444         srv->cli = c;
445         srv->dev = (dev_t)(str_checksum(server) ^ str_checksum(share));
446
447         /* now add it to the cache (internal or external) */
448         if (context->callbacks.add_cached_srv_fn(context, srv, server, share, workgroup, username)) {
449                 DEBUG(3, (" Failed to add server to cache\n"));
450                 goto failed;
451         }
452
453         
454         DEBUG(2, ("Server connect ok: //%s/%s: %p\n", 
455                   server, share, srv));
456
457         return srv;
458
459  failed:
460         cli_shutdown(&c);
461         if (!srv) return NULL;
462   
463         SAFE_FREE(srv);
464         return NULL;
465 }
466
467 /*
468  * Routine to open() a file ...
469  */
470
471 static SMBCFILE *smbc_open_ctx(SMBCCTX *context, const char *fname, int flags, mode_t mode)
472 {
473         fstring server, share, user, password, workgroup;
474         pstring path;
475         SMBCSRV *srv   = NULL;
476         SMBCFILE *file = NULL;
477         int fd;
478
479         if (!context || !context->internal ||
480             !context->internal->_initialized) {
481
482                 errno = EINVAL;  /* Best I can think of ... */
483                 return NULL;
484
485         }
486
487         if (!fname) {
488
489                 errno = EINVAL;
490                 return NULL;
491
492         }
493
494         smbc_parse_path(context, fname, server, share, path, user, password); /* FIXME, check errors */
495
496         if (user[0] == (char)0) pstrcpy(user, context->user);
497
498         pstrcpy(workgroup, context->workgroup);
499
500         srv = smbc_server(context, server, share, workgroup, user, password);
501
502         if (!srv) {
503
504                 if (errno == EPERM) errno = EACCES;
505                 return NULL;  /* smbc_server sets errno */
506     
507         }
508
509         /* Hmmm, the test for a directory is suspect here ... FIXME */
510
511         if (strlen(path) > 0 && path[strlen(path) - 1] == '\\') {
512     
513                 fd = -1;
514
515         }
516         else {
517           
518                 file = malloc(sizeof(SMBCFILE));
519
520                 if (!file) {
521
522                         errno = ENOMEM;
523                         return NULL;
524
525                 }
526
527                 ZERO_STRUCTP(file);
528
529                 if ((fd = cli_open(&srv->cli, path, flags, DENY_NONE)) < 0) {
530
531                         /* Handle the error ... */
532
533                         SAFE_FREE(file);
534                         errno = smbc_errno(context, &srv->cli);
535                         return NULL;
536
537                 }
538
539                 /* Fill in file struct */
540
541                 file->cli_fd  = fd;
542                 file->fname   = strdup(fname);
543                 file->srv     = srv;
544                 file->offset  = 0;
545                 file->file    = True;
546
547                 DLIST_ADD(context->internal->_files, file);
548                 return file;
549
550         }
551
552         /* Check if opendir needed ... */
553
554         if (fd == -1) {
555                 int eno = 0;
556
557                 eno = smbc_errno(context, &srv->cli);
558                 file = context->opendir(context, fname);
559                 if (!file) errno = eno;
560                 return file;
561
562         }
563
564         errno = EINVAL; /* FIXME, correct errno ? */
565         return NULL;
566
567 }
568
569 /*
570  * Routine to create a file 
571  */
572
573 static int creat_bits = O_WRONLY | O_CREAT | O_TRUNC; /* FIXME: Do we need this */
574
575 static SMBCFILE *smbc_creat_ctx(SMBCCTX *context, const char *path, mode_t mode)
576 {
577
578         if (!context || !context->internal ||
579             !context->internal->_initialized) {
580
581                 errno = EINVAL;
582                 return NULL;
583
584         }
585
586         return smbc_open_ctx(context, path, creat_bits, mode);
587 }
588
589 /*
590  * Routine to read() a file ...
591  */
592
593 static ssize_t smbc_read_ctx(SMBCCTX *context, SMBCFILE *file, void *buf, size_t count)
594 {
595         int ret;
596
597         if (!context || !context->internal ||
598             !context->internal->_initialized) {
599
600                 errno = EINVAL;
601                 return -1;
602
603         }
604
605         DEBUG(4, ("smbc_read(%p, %d)\n", file, (int)count));
606
607         if (!file || !DLIST_CONTAINS(context->internal->_files, file)) {
608
609                 errno = EBADF;
610                 return -1;
611
612         }
613
614         /* Check that the buffer exists ... */
615
616         if (buf == NULL) {
617
618                 errno = EINVAL;
619                 return -1;
620
621         }
622
623         ret = cli_read(&file->srv->cli, file->cli_fd, buf, file->offset, count);
624
625         if (ret < 0) {
626
627                 errno = smbc_errno(context, &file->srv->cli);
628                 return -1;
629
630         }
631
632         file->offset += ret;
633
634         DEBUG(4, ("  --> %d\n", ret));
635
636         return ret;  /* Success, ret bytes of data ... */
637
638 }
639
640 /*
641  * Routine to write() a file ...
642  */
643
644 static ssize_t smbc_write_ctx(SMBCCTX *context, SMBCFILE *file, void *buf, size_t count)
645 {
646         int ret;
647
648         if (!context || !context->internal ||
649             !context->internal->_initialized) {
650
651                 errno = EINVAL;
652                 return -1;
653
654         }
655
656         if (!file || !DLIST_CONTAINS(context->internal->_files, file)) {
657
658                 errno = EBADF;
659                 return -1;
660     
661         }
662
663         /* Check that the buffer exists ... */
664
665         if (buf == NULL) {
666
667                 errno = EINVAL;
668                 return -1;
669
670         }
671
672         ret = cli_write(&file->srv->cli, file->cli_fd, 0, buf, file->offset, count);
673
674         if (ret <= 0) {
675
676                 errno = smbc_errno(context, &file->srv->cli);
677                 return -1;
678
679         }
680
681         file->offset += ret;
682
683         return ret;  /* Success, 0 bytes of data ... */
684 }
685  
686 /*
687  * Routine to close() a file ...
688  */
689
690 static int smbc_close_ctx(SMBCCTX *context, SMBCFILE *file)
691 {
692         SMBCSRV *srv; 
693
694         if (!context || !context->internal ||
695             !context->internal->_initialized) {
696
697                 errno = EINVAL;
698                 return -1;
699
700         }
701
702         if (!file || !DLIST_CONTAINS(context->internal->_files, file)) {
703    
704                 errno = EBADF;
705                 return -1;
706
707         }
708
709         /* IS a dir ... */
710         if (!file->file) {
711                 
712                 return context->closedir(context, file);
713
714         }
715
716         if (!cli_close(&file->srv->cli, file->cli_fd)) {
717
718                 DEBUG(3, ("cli_close failed on %s. purging server.\n", 
719                           file->fname));
720                 /* Deallocate slot and remove the server 
721                  * from the server cache if unused */
722                 errno = smbc_errno(context, &file->srv->cli);  
723                 srv = file->srv;
724                 DLIST_REMOVE(context->internal->_files, file);
725                 SAFE_FREE(file->fname);
726                 SAFE_FREE(file);
727                 context->callbacks.remove_unused_server_fn(context, srv);
728
729                 return -1;
730
731         }
732
733         if (!file->file) {
734
735                 return context->closedir(context, file);
736
737         }
738
739         if (!cli_close(&file->srv->cli, file->cli_fd)) {
740                 DEBUG(3, ("cli_close failed on %s. purging server.\n", 
741                           file->fname));
742                 /* Deallocate slot and remove the server 
743                  * from the server cache if unused */
744                 errno = smbc_errno(context, &file->srv->cli);  
745                 srv = file->srv;
746                 DLIST_REMOVE(context->internal->_files, file);
747                 SAFE_FREE(file->fname);
748                 SAFE_FREE(file);
749                 context->callbacks.remove_unused_server_fn(context, srv);
750
751                 return -1;
752         }
753
754         DLIST_REMOVE(context->internal->_files, file);
755         SAFE_FREE(file->fname);
756         SAFE_FREE(file);
757
758         return 0;
759 }
760
761 /*
762  * Get info from an SMB server on a file. Use a qpathinfo call first
763  * and if that fails, use getatr, as Win95 sometimes refuses qpathinfo
764  */
765 static BOOL smbc_getatr(SMBCCTX * context, SMBCSRV *srv, char *path, 
766                  uint16 *mode, size_t *size, 
767                  time_t *c_time, time_t *a_time, time_t *m_time,
768                  SMB_INO_T *ino)
769 {
770
771         if (!context || !context->internal ||
772             !context->internal->_initialized) {
773  
774                 errno = EINVAL;
775                 return -1;
776  
777         }
778
779         DEBUG(4,("smbc_getatr: sending qpathinfo\n"));
780   
781         if (!srv->no_pathinfo2 &&
782             cli_qpathinfo2(&srv->cli, path, c_time, a_time, m_time, NULL,
783                            size, mode, ino)) return True;
784
785         /* if this is NT then don't bother with the getatr */
786         if (srv->cli.capabilities & CAP_NT_SMBS) return False;
787
788         if (cli_getatr(&srv->cli, path, mode, size, m_time)) {
789                 a_time = c_time = m_time;
790                 srv->no_pathinfo2 = True;
791                 return True;
792         }
793
794         return False;
795
796 }
797
798 /*
799  * Routine to unlink() a file
800  */
801
802 static int smbc_unlink_ctx(SMBCCTX *context, const char *fname)
803 {
804         fstring server, share, user, password, workgroup;
805         pstring path;
806         SMBCSRV *srv = NULL;
807
808         if (!context || !context->internal ||
809             !context->internal->_initialized) {
810
811                 errno = EINVAL;  /* Best I can think of ... */
812                 return -1;
813
814         }
815
816         if (!fname) {
817
818                 errno = EINVAL;
819                 return -1;
820
821         }
822
823         smbc_parse_path(context, fname, server, share, path, user, password); /* FIXME, check errors */
824
825         if (user[0] == (char)0) pstrcpy(user, context->user);
826
827         pstrcpy(workgroup, context->workgroup);
828
829         srv = smbc_server(context, server, share, workgroup, user, password);
830
831         if (!srv) {
832
833                 return -1;  /* smbc_server sets errno */
834
835         }
836
837         /*  if (strncmp(srv->cli.dev, "LPT", 3) == 0) {
838
839     int job = smbc_stat_printjob(srv, path, NULL, NULL);
840     if (job == -1) {
841
842       return -1;
843
844     }
845     if ((err = cli_printjob_del(&srv->cli, job)) != 0) {
846
847     
848       return -1;
849
850     }
851     } else */
852
853         if (!cli_unlink(&srv->cli, path)) {
854
855                 errno = smbc_errno(context, &srv->cli);
856
857                 if (errno == EACCES) { /* Check if the file is a directory */
858
859                         int saverr = errno;
860                         size_t size = 0;
861                         uint16 mode = 0;
862                         time_t m_time = 0, a_time = 0, c_time = 0;
863                         SMB_INO_T ino = 0;
864
865                         if (!smbc_getatr(context, srv, path, &mode, &size,
866                                          &c_time, &a_time, &m_time, &ino)) {
867
868                                 /* Hmmm, bad error ... What? */
869
870                                 errno = smbc_errno(context, &srv->cli);
871                                 return -1;
872
873                         }
874                         else {
875
876                                 if (IS_DOS_DIR(mode))
877                                         errno = EISDIR;
878                                 else
879                                         errno = saverr;  /* Restore this */
880
881                         }
882                 }
883
884                 return -1;
885
886         }
887
888         return 0;  /* Success ... */
889
890 }
891
892 /*
893  * Routine to rename() a file
894  */
895
896 static int smbc_rename_ctx(SMBCCTX *ocontext, const char *oname, 
897                            SMBCCTX *ncontext, const char *nname)
898 {
899         fstring server1, share1, server2, share2, user1, user2, password1, password2, workgroup;
900         pstring path1, path2;
901         SMBCSRV *srv = NULL;
902
903         if (!ocontext || !ncontext || 
904             !ocontext->internal || !ncontext->internal ||
905             !ocontext->internal->_initialized || 
906             !ncontext->internal->_initialized) {
907
908                 errno = EINVAL;  /* Best I can think of ... */
909                 return -1;
910
911         }
912         
913         if (!oname || !nname) {
914
915                 errno = EINVAL;
916                 return -1;
917
918         }
919         
920         DEBUG(4, ("smbc_rename(%s,%s)\n", oname, nname));
921
922         smbc_parse_path(ocontext, oname, server1, share1, path1, user1, password1);
923
924         if (user1[0] == (char)0) pstrcpy(user1, ocontext->user);
925
926         smbc_parse_path(ncontext, nname, server2, share2, path2, user2, password2);
927
928         if (user2[0] == (char)0) pstrcpy(user2, ncontext->user);
929
930         if (strcmp(server1, server2) || strcmp(share1, share2) ||
931             strcmp(user1, user2)) {
932
933                 /* Can't rename across file systems, or users?? */
934
935                 errno = EXDEV;
936                 return -1;
937
938         }
939
940         pstrcpy(workgroup, ocontext->workgroup);
941         /* HELP !!! Which workgroup should I use ? Or are they always the same -- Tom */ 
942         srv = smbc_server(ocontext, server1, share1, workgroup, user1, password1);
943         if (!srv) {
944
945                 return -1;
946
947         }
948
949         if (!cli_rename(&srv->cli, path1, path2)) {
950                 int eno = smbc_errno(ocontext, &srv->cli);
951
952                 if (eno != EEXIST ||
953                     !cli_unlink(&srv->cli, path2) ||
954                     !cli_rename(&srv->cli, path1, path2)) {
955
956                         errno = eno;
957                         return -1;
958
959                 }
960         }
961
962         return 0; /* Success */
963
964 }
965
966 /*
967  * A routine to lseek() a file
968  */
969
970 static off_t smbc_lseek_ctx(SMBCCTX *context, SMBCFILE *file, off_t offset, int whence)
971 {
972         size_t size;
973
974         if (!context || !context->internal ||
975             !context->internal->_initialized) {
976
977                 errno = EINVAL;
978                 return -1;
979                 
980         }
981
982         if (!file || !DLIST_CONTAINS(context->internal->_files, file)) {
983
984                 errno = EBADF;
985                 return -1;
986
987         }
988
989         if (!file->file) {
990
991                 errno = EINVAL;
992                 return -1;      /* Can't lseek a dir ... */
993
994         }
995
996         switch (whence) {
997         case SEEK_SET:
998                 file->offset = offset;
999                 break;
1000
1001         case SEEK_CUR:
1002                 file->offset += offset;
1003                 break;
1004
1005         case SEEK_END:
1006                 if (!cli_qfileinfo(&file->srv->cli, file->cli_fd, NULL, &size, NULL, NULL,
1007                                    NULL, NULL, NULL) &&
1008                     !cli_getattrE(&file->srv->cli, file->cli_fd, NULL, &size, NULL, NULL,
1009                                   NULL)) {
1010
1011                         errno = EINVAL;
1012                         return -1;
1013                 }
1014                 file->offset = size + offset;
1015                 break;
1016
1017         default:
1018                 errno = EINVAL;
1019                 break;
1020
1021         }
1022
1023         return file->offset;
1024
1025 }
1026
1027 /* 
1028  * Generate an inode number from file name for those things that need it
1029  */
1030
1031 static
1032 ino_t smbc_inode(SMBCCTX *context, const char *name)
1033 {
1034
1035         if (!context || !context->internal ||
1036             !context->internal->_initialized) {
1037
1038                 errno = EINVAL;
1039                 return -1;
1040
1041         }
1042
1043         if (!*name) return 2; /* FIXME, why 2 ??? */
1044         return (ino_t)str_checksum(name);
1045
1046 }
1047
1048 /*
1049  * Routine to put basic stat info into a stat structure ... Used by stat and
1050  * fstat below.
1051  */
1052
1053 static
1054 int smbc_setup_stat(SMBCCTX *context, struct stat *st, char *fname, size_t size, int mode)
1055 {
1056         
1057         st->st_mode = 0;
1058
1059         if (IS_DOS_DIR(mode)) {
1060                 st->st_mode = SMBC_DIR_MODE;
1061         } else {
1062                 st->st_mode = SMBC_FILE_MODE;
1063         }
1064
1065         if (IS_DOS_ARCHIVE(mode)) st->st_mode |= S_IXUSR;
1066         if (IS_DOS_SYSTEM(mode)) st->st_mode |= S_IXGRP;
1067         if (IS_DOS_HIDDEN(mode)) st->st_mode |= S_IXOTH;
1068         if (!IS_DOS_READONLY(mode)) st->st_mode |= S_IWUSR;
1069
1070         st->st_size = size;
1071         st->st_blksize = 512;
1072         st->st_blocks = (size+511)/512;
1073         st->st_uid = getuid();
1074         st->st_gid = getgid();
1075
1076         if (IS_DOS_DIR(mode)) {
1077                 st->st_nlink = 2;
1078         } else {
1079                 st->st_nlink = 1;
1080         }
1081
1082         if (st->st_ino == 0) {
1083                 st->st_ino = smbc_inode(context, fname);
1084         }
1085         
1086         return True;  /* FIXME: Is this needed ? */
1087
1088 }
1089
1090 /*
1091  * Routine to stat a file given a name
1092  */
1093
1094 static int smbc_stat_ctx(SMBCCTX *context, const char *fname, struct stat *st)
1095 {
1096         SMBCSRV *srv;
1097         fstring server, share, user, password, workgroup;
1098         pstring path;
1099         time_t m_time = 0, a_time = 0, c_time = 0;
1100         size_t size = 0;
1101         uint16 mode = 0;
1102         SMB_INO_T ino = 0;
1103
1104         if (!context || !context->internal ||
1105             !context->internal->_initialized) {
1106
1107                 errno = EINVAL;  /* Best I can think of ... */
1108                 return -1;
1109     
1110         }
1111
1112         if (!fname) {
1113
1114                 errno = EINVAL;
1115                 return -1;
1116
1117         }
1118   
1119         DEBUG(4, ("smbc_stat(%s)\n", fname));
1120
1121         smbc_parse_path(context, fname, server, share, path, user, password); /*FIXME, errors*/
1122
1123         if (user[0] == (char)0) pstrcpy(user, context->user);
1124
1125         pstrcpy(workgroup, context->workgroup);
1126
1127         srv = smbc_server(context, server, share, workgroup, user, password);
1128
1129         if (!srv) {
1130
1131                 return -1;  /* errno set by smbc_server */
1132
1133         }
1134
1135         /* if (strncmp(srv->cli.dev, "IPC", 3) == 0) {
1136
1137            mode = aDIR | aRONLY;
1138
1139            }
1140            else if (strncmp(srv->cli.dev, "LPT", 3) == 0) {
1141            
1142            if (strcmp(path, "\\") == 0) {
1143            
1144            mode = aDIR | aRONLY;
1145
1146            }
1147            else {
1148
1149            mode = aRONLY;
1150            smbc_stat_printjob(srv, path, &size, &m_time);
1151            c_time = a_time = m_time;
1152
1153            }
1154            else { */
1155
1156         if (!smbc_getatr(context, srv, path, &mode, &size, 
1157                          &c_time, &a_time, &m_time, &ino)) {
1158
1159                 errno = smbc_errno(context, &srv->cli);
1160                 return -1;
1161                 
1162         }
1163
1164         st->st_ino = ino;
1165
1166         smbc_setup_stat(context, st, path, size, mode);
1167
1168         st->st_atime = a_time;
1169         st->st_ctime = c_time;
1170         st->st_mtime = m_time;
1171         st->st_dev   = srv->dev;
1172
1173         return 0;
1174
1175 }
1176
1177 /*
1178  * Routine to stat a file given an fd
1179  */
1180
1181 static int smbc_fstat_ctx(SMBCCTX *context, SMBCFILE *file, struct stat *st)
1182 {
1183         time_t c_time, a_time, m_time;
1184         size_t size;
1185         uint16 mode;
1186         SMB_INO_T ino = 0;
1187
1188         if (!context || !context->internal ||
1189             !context->internal->_initialized) {
1190
1191                 errno = EINVAL;
1192                 return -1;
1193
1194         }
1195
1196         if (!file || !DLIST_CONTAINS(context->internal->_files, file)) {
1197
1198                 errno = EBADF;
1199                 return -1;
1200
1201         }
1202
1203         if (!file->file) {
1204
1205                 return context->fstatdir(context, file, st);
1206
1207         }
1208
1209         if (!cli_qfileinfo(&file->srv->cli, file->cli_fd,
1210                            &mode, &size, &c_time, &a_time, &m_time, NULL, &ino) &&
1211             !cli_getattrE(&file->srv->cli, file->cli_fd,
1212                           &mode, &size, &c_time, &a_time, &m_time)) {
1213
1214                 errno = EINVAL;
1215                 return -1;
1216
1217         }
1218
1219         st->st_ino = ino;
1220
1221         smbc_setup_stat(context, st, file->fname, size, mode);
1222
1223         st->st_atime = a_time;
1224         st->st_ctime = c_time;
1225         st->st_mtime = m_time;
1226         st->st_dev = file->srv->dev;
1227
1228         return 0;
1229
1230 }
1231
1232 /*
1233  * Routine to open a directory
1234  *
1235  * We want to allow:
1236  *
1237  * smb: which should list all the workgroups available
1238  * smb:workgroup
1239  * smb:workgroup//server
1240  * smb://server
1241  * smb://server/share
1242  * smb://<IP-addr> which should list shares on server
1243  * smb://<IP-addr>/share which should list files on share
1244  */
1245
1246 static void smbc_remove_dir(SMBCFILE *dir)
1247 {
1248         struct smbc_dir_list *d,*f;
1249
1250         d = dir->dir_list;
1251         while (d) {
1252
1253                 f = d; d = d->next;
1254
1255                 SAFE_FREE(f->dirent);
1256                 SAFE_FREE(f);
1257
1258         }
1259
1260         dir->dir_list = dir->dir_end = dir->dir_next = NULL;
1261
1262 }
1263
1264 static int add_dirent(SMBCFILE *dir, const char *name, const char *comment, uint32 type)
1265 {
1266         struct smbc_dirent *dirent;
1267         int size;
1268
1269         /*
1270          * Allocate space for the dirent, which must be increased by the 
1271          * size of the name and the comment and 1 for the null on the comment.
1272          * The null on the name is already accounted for.
1273          */
1274
1275         size = sizeof(struct smbc_dirent) + (name?strlen(name):0) +
1276                 (comment?strlen(comment):0) + 1; 
1277     
1278         dirent = malloc(size);
1279
1280         if (!dirent) {
1281
1282                 dir->dir_error = ENOMEM;
1283                 return -1;
1284
1285         }
1286
1287         ZERO_STRUCTP(dirent);
1288
1289         if (dir->dir_list == NULL) {
1290
1291                 dir->dir_list = malloc(sizeof(struct smbc_dir_list));
1292                 if (!dir->dir_list) {
1293
1294                         SAFE_FREE(dirent);
1295                         dir->dir_error = ENOMEM;
1296                         return -1;
1297
1298                 }
1299                 ZERO_STRUCTP(dir->dir_list);
1300
1301                 dir->dir_end = dir->dir_next = dir->dir_list;
1302   
1303         }
1304         else {
1305
1306                 dir->dir_end->next = malloc(sizeof(struct smbc_dir_list));
1307                 
1308                 if (!dir->dir_end->next) {
1309                         
1310                         SAFE_FREE(dirent);
1311                         dir->dir_error = ENOMEM;
1312                         return -1;
1313
1314                 }
1315                 ZERO_STRUCTP(dir->dir_end->next);
1316
1317                 dir->dir_end = dir->dir_end->next;
1318
1319         }
1320
1321         dir->dir_end->next = NULL;
1322         dir->dir_end->dirent = dirent;
1323         
1324         dirent->smbc_type = type;
1325         dirent->namelen = (name?strlen(name):0);
1326         dirent->commentlen = (comment?strlen(comment):0);
1327         dirent->dirlen = size;
1328   
1329         strncpy(dirent->name, (name?name:""), dirent->namelen + 1);
1330
1331         dirent->comment = (char *)(&dirent->name + dirent->namelen + 1);
1332         strncpy(dirent->comment, (comment?comment:""), dirent->commentlen + 1);
1333
1334         return 0;
1335
1336 }
1337
1338 static void
1339 list_fn(const char *name, uint32 type, const char *comment, void *state)
1340 {
1341         SMBCFILE *dir = (SMBCFILE *)state;
1342         int dirent_type;
1343
1344         /* We need to process the type a little ... */
1345
1346         if (dir->dir_type == SMBC_FILE_SHARE) {
1347                 
1348                 switch (type) {
1349                 case 0: /* Directory tree */
1350                         dirent_type = SMBC_FILE_SHARE;
1351                         break;
1352
1353                 case 1:
1354                         dirent_type = SMBC_PRINTER_SHARE;
1355                         break;
1356
1357                 case 2:
1358                         dirent_type = SMBC_COMMS_SHARE;
1359                         break;
1360
1361                 case 3:
1362                         dirent_type = SMBC_IPC_SHARE;
1363                         break;
1364
1365                 default:
1366                         dirent_type = SMBC_FILE_SHARE; /* FIXME, error? */
1367                         break;
1368                 }
1369         }
1370         else dirent_type = dir->dir_type;
1371
1372         if (add_dirent(dir, name, comment, dirent_type) < 0) {
1373
1374                 /* An error occurred, what do we do? */
1375                 /* FIXME: Add some code here */
1376
1377         }
1378
1379 }
1380
1381 static void
1382 dir_list_fn(file_info *finfo, const char *mask, void *state)
1383 {
1384
1385         if (add_dirent((SMBCFILE *)state, finfo->name, "", 
1386                        (finfo->mode&aDIR?SMBC_DIR:SMBC_FILE)) < 0) {
1387
1388                 /* Handle an error ... */
1389
1390                 /* FIXME: Add some code ... */
1391
1392         } 
1393
1394 }
1395
1396 static SMBCFILE *smbc_opendir_ctx(SMBCCTX *context, const char *fname)
1397 {
1398         fstring server, share, user, password, workgroup;
1399         pstring path;
1400         SMBCSRV *srv  = NULL;
1401         SMBCFILE *dir = NULL;
1402         struct in_addr rem_ip;
1403
1404         if (!context || !context->internal ||
1405             !context->internal->_initialized) {
1406
1407                 errno = EINVAL;
1408                 return NULL;
1409
1410         }
1411
1412         if (!fname) {
1413     
1414                 errno = EINVAL;
1415                 return NULL;
1416
1417         }
1418
1419         if (smbc_parse_path(context, fname, server, share, path, user, password)) {
1420
1421                 errno = EINVAL;
1422                 return NULL;
1423
1424         }
1425
1426         if (user[0] == (char)0) pstrcpy(user, context->user);
1427
1428         pstrcpy(workgroup, context->workgroup);
1429
1430         dir = malloc(sizeof(*dir));
1431
1432         if (!dir) {
1433
1434                 errno = ENOMEM;
1435                 return NULL;
1436
1437         }
1438
1439         ZERO_STRUCTP(dir);
1440
1441         dir->cli_fd   = 0;
1442         dir->fname    = strdup(fname);
1443         dir->srv      = NULL;
1444         dir->offset   = 0;
1445         dir->file     = False;
1446         dir->dir_list = dir->dir_next = dir->dir_end = NULL;
1447
1448         if (server[0] == (char)0) {
1449
1450                 if (share[0] != (char)0 || path[0] != (char)0) {
1451     
1452                         errno = EINVAL;
1453                         if (dir) {
1454                                 SAFE_FREE(dir->fname);
1455                                 SAFE_FREE(dir);
1456                         }
1457                         return NULL;
1458
1459                 }
1460
1461                 /* We have server and share and path empty ... so list the workgroups */
1462                 /* first try to get the LMB for our workgroup, and if that fails,     */
1463                 /* try the DMB                                                        */
1464
1465                 if (!(resolve_name(context->workgroup, &rem_ip, 0x1d) ||
1466                       resolve_name(context->workgroup, &rem_ip, 0x1b))) {
1467       
1468                         errno = EINVAL;  /* Something wrong with smb.conf? */
1469                         return NULL;
1470
1471                 }
1472
1473                 dir->dir_type = SMBC_WORKGROUP;
1474
1475                 /* find the name of the server ... */
1476
1477                 if (!name_status_find("*", 0, 0, rem_ip, server)) {
1478
1479                         DEBUG(0,("Could not get the name of local/domain master browser for server %s\n", server));
1480                         errno = EINVAL;
1481                         return NULL;
1482
1483                 }
1484
1485                 /*
1486                  * Get a connection to IPC$ on the server if we do not already have one
1487                  */
1488
1489                 srv = smbc_server(context, server, "IPC$", workgroup, user, password);
1490
1491                 if (!srv) {
1492
1493                         if (dir) {
1494                                 SAFE_FREE(dir->fname);
1495                                 SAFE_FREE(dir);
1496                         }
1497                         
1498                         return NULL;
1499
1500                 }
1501
1502                 dir->srv = srv;
1503
1504                 /* Now, list the stuff ... */
1505
1506                 if (!cli_NetServerEnum(&srv->cli, workgroup, 0x80000000, list_fn,
1507                                        (void *)dir)) {
1508
1509                         if (dir) {
1510                                 SAFE_FREE(dir->fname);
1511                                 SAFE_FREE(dir);
1512                         }
1513                         errno = cli_errno(&srv->cli);
1514
1515                         return NULL;
1516
1517                 }
1518         }
1519         else { /* Server not an empty string ... Check the rest and see what gives */
1520
1521                 if (share[0] == (char)0) {
1522
1523                         if (path[0] != (char)0) { /* Should not have empty share with path */
1524
1525                                 errno = EINVAL;
1526                                 if (dir) {
1527                                         SAFE_FREE(dir->fname);
1528                                         SAFE_FREE(dir);
1529                                 }
1530                                 return NULL;
1531         
1532                         }
1533
1534                         /* Check to see if <server><1D>, <server><1B>, or <server><20> translates */
1535                         /* However, we check to see if <server> is an IP address first */
1536
1537                         if (!is_ipaddress(server) &&  /* Not an IP addr so check next */
1538                             (resolve_name(server, &rem_ip, 0x1d) ||   /* Found LMB */
1539                                     resolve_name(server, &rem_ip, 0x1b) )) { /* Found DMB */
1540                                 pstring buserver;
1541
1542                                 dir->dir_type = SMBC_SERVER;
1543
1544                                 /*
1545                                  * Get the backup list ...
1546                                  */
1547
1548
1549                                 if (!name_status_find("*", 0, 0, rem_ip, buserver)) {
1550
1551                                         DEBUG(0, ("Could not get name of local/domain master browser for server %s\n", server));
1552                                         errno = EPERM;  /* FIXME, is this correct */
1553                                         return NULL;
1554
1555                                 }
1556
1557                                 /*
1558                                  * Get a connection to IPC$ on the server if we do not already have one
1559                                  */
1560
1561                                 srv = smbc_server(context, buserver, "IPC$", workgroup, user, password);
1562
1563                                 if (!srv) {
1564
1565                                         if (dir) {
1566                                                 SAFE_FREE(dir->fname);
1567                                                 SAFE_FREE(dir);
1568                                         }
1569                                         return NULL;
1570
1571                                 }
1572
1573                                 dir->srv = srv;
1574
1575                                 /* Now, list the servers ... */
1576
1577                                 if (!cli_NetServerEnum(&srv->cli, server, 0x0000FFFE, list_fn,
1578                                                        (void *)dir)) {
1579
1580                                         if (dir) {
1581                                                 SAFE_FREE(dir->fname);
1582                                                 SAFE_FREE(dir);
1583                                         }
1584                                         errno = cli_errno(&srv->cli);
1585                                         return NULL;
1586                                         
1587                                 }
1588
1589                         }
1590                         else {
1591
1592                                 if (resolve_name(server, &rem_ip, 0x20)) {
1593
1594                                         /* Now, list the shares ... */
1595
1596                                         dir->dir_type = SMBC_FILE_SHARE;
1597
1598                                         srv = smbc_server(context, server, "IPC$", workgroup, user, password);
1599
1600                                         if (!srv) {
1601
1602                                                 if (dir) {
1603                                                         SAFE_FREE(dir->fname);
1604                                                         SAFE_FREE(dir);
1605                                                 }
1606                                                 return NULL;
1607
1608                                         }
1609
1610                                         dir->srv = srv;
1611
1612                                         /* Now, list the servers ... */
1613
1614                                         if (cli_RNetShareEnum(&srv->cli, list_fn, 
1615                                                               (void *)dir) < 0) {
1616
1617                                                 errno = cli_errno(&srv->cli);
1618                                                 if (dir) {
1619                                                         SAFE_FREE(dir->fname);
1620                                                         SAFE_FREE(dir);
1621                                                 }
1622                                                 return NULL;
1623
1624                                         }
1625
1626                                 }
1627                                 else {
1628
1629                                         errno = ENODEV;   /* Neither the workgroup nor server exists */
1630                                         if (dir) {
1631                                                 SAFE_FREE(dir->fname);
1632                                                 SAFE_FREE(dir);
1633                                         }
1634                                         return NULL;
1635
1636                                 }
1637
1638                         }
1639
1640                 }
1641                 else { /* The server and share are specified ... work from there ... */
1642
1643                         /* Well, we connect to the server and list the directory */
1644
1645                         dir->dir_type = SMBC_FILE_SHARE;
1646
1647                         srv = smbc_server(context, server, share, workgroup, user, password);
1648
1649                         if (!srv) {
1650
1651                                 if (dir) {
1652                                         SAFE_FREE(dir->fname);
1653                                         SAFE_FREE(dir);
1654                                 }
1655                                 return NULL;
1656
1657                         }
1658
1659                         dir->srv = srv;
1660
1661                         /* Now, list the files ... */
1662
1663                         pstrcat(path, "\\*");
1664
1665                         if (cli_list(&srv->cli, path, aDIR | aSYSTEM | aHIDDEN, dir_list_fn, 
1666                                      (void *)dir) < 0) {
1667
1668                                 if (dir) {
1669                                         SAFE_FREE(dir->fname);
1670                                         SAFE_FREE(dir);
1671                                 }
1672                                 errno = smbc_errno(context, &srv->cli);
1673                                 return NULL;
1674
1675                         }
1676                 }
1677
1678         }
1679
1680         DLIST_ADD(context->internal->_files, dir);
1681         return dir;
1682
1683 }
1684
1685 /*
1686  * Routine to close a directory
1687  */
1688
1689 static int smbc_closedir_ctx(SMBCCTX *context, SMBCFILE *dir)
1690 {
1691
1692         if (!context || !context->internal ||
1693             !context->internal->_initialized) {
1694
1695                 errno = EINVAL;
1696                 return -1;
1697
1698         }
1699
1700         if (!dir || !DLIST_CONTAINS(context->internal->_files, dir)) {
1701
1702                 errno = EBADF;
1703                 return -1;
1704     
1705         }
1706
1707         smbc_remove_dir(dir); /* Clean it up */
1708
1709         DLIST_REMOVE(context->internal->_files, dir);
1710
1711         if (dir) {
1712
1713                 SAFE_FREE(dir->fname);
1714                 SAFE_FREE(dir);    /* Free the space too */
1715
1716         }
1717
1718         return 0;
1719
1720 }
1721
1722 /*
1723  * Routine to get a directory entry
1724  */
1725
1726 struct smbc_dirent *smbc_readdir_ctx(SMBCCTX *context, SMBCFILE *dir)
1727 {
1728         struct smbc_dirent *dirp, *dirent;
1729
1730         /* Check that all is ok first ... */
1731
1732         if (!context || !context->internal ||
1733             !context->internal->_initialized) {
1734
1735                 errno = EINVAL;
1736                 return NULL;
1737
1738         }
1739
1740         if (!dir || !DLIST_CONTAINS(context->internal->_files, dir)) {
1741
1742                 errno = EBADF;
1743                 return NULL;
1744
1745         }
1746
1747         if (dir->file != False) { /* FIXME, should be dir, perhaps */
1748
1749                 errno = ENOTDIR;
1750                 return NULL;
1751
1752         }
1753
1754         if (!dir->dir_next)
1755                 return NULL;
1756         else {
1757
1758                 dirent = dir->dir_next->dirent;
1759
1760                 if (!dirent) {
1761
1762                         errno = ENOENT;
1763                         return NULL;
1764
1765                 }
1766
1767                 /* Hmmm, do I even need to copy it? */
1768
1769                 memcpy(context->internal->_dirent, dirent, dirent->dirlen); /* Copy the dirent */
1770                 dirp = (struct smbc_dirent *)context->internal->_dirent;
1771                 dirp->comment = (char *)(&dirp->name + dirent->namelen + 1);
1772                 dir->dir_next = dir->dir_next->next;
1773
1774                 return (struct smbc_dirent *)context->internal->_dirent;
1775         }
1776
1777 }
1778
1779 /*
1780  * Routine to get directory entries
1781  */
1782
1783 static int smbc_getdents_ctx(SMBCCTX *context, SMBCFILE *dir, struct smbc_dirent *dirp, int count)
1784 {
1785         struct smbc_dir_list *dirlist;
1786         int rem = count, reqd;
1787         char *ndir = (char *)dirp;
1788
1789         /* Check that all is ok first ... */
1790
1791         if (!context || !context->internal ||
1792             !context->internal->_initialized) {
1793
1794                 errno = EINVAL;
1795                 return -1;
1796
1797         }
1798
1799         if (!dir || !DLIST_CONTAINS(context->internal->_files, dir)) {
1800
1801                 errno = EBADF;
1802                 return -1;
1803     
1804         }
1805
1806         if (dir->file != False) { /* FIXME, should be dir, perhaps */
1807
1808                 errno = ENOTDIR;
1809                 return -1;
1810
1811         }
1812
1813         /* 
1814          * Now, retrieve the number of entries that will fit in what was passed
1815          * We have to figure out if the info is in the list, or we need to 
1816          * send a request to the server to get the info.
1817          */
1818
1819         while ((dirlist = dir->dir_next)) {
1820                 struct smbc_dirent *dirent;
1821
1822                 if (!dirlist->dirent) {
1823
1824                         errno = ENOENT;  /* Bad error */
1825                         return -1;
1826
1827                 }
1828
1829                 if (rem < (reqd = (sizeof(struct smbc_dirent) + dirlist->dirent->namelen + 
1830                                    dirlist->dirent->commentlen + 1))) {
1831
1832                         if (rem < count) { /* We managed to copy something */
1833
1834                                 errno = 0;
1835                                 return count - rem;
1836
1837                         }
1838                         else { /* Nothing copied ... */
1839
1840                                 errno = EINVAL;  /* Not enough space ... */
1841                                 return -1;
1842
1843                         }
1844
1845                 }
1846
1847                 dirent = dirlist->dirent;
1848
1849                 memcpy(ndir, dirent, reqd); /* Copy the data in ... */
1850     
1851                 ((struct smbc_dirent *)ndir)->comment = 
1852                         (char *)(&((struct smbc_dirent *)ndir)->name + dirent->namelen + 1);
1853
1854                 ndir += reqd;
1855
1856                 rem -= reqd;
1857
1858                 dir->dir_next = dirlist = dirlist -> next;
1859         }
1860
1861         if (rem == count)
1862                 return 0;
1863         else 
1864                 return count - rem;
1865
1866 }
1867
1868 /*
1869  * Routine to create a directory ...
1870  */
1871
1872 static int smbc_mkdir_ctx(SMBCCTX *context, const char *fname, mode_t mode)
1873 {
1874         SMBCSRV *srv;
1875         fstring server, share, user, password, workgroup;
1876         pstring path;
1877
1878         if (!context || !context->internal || 
1879             !context->internal->_initialized) {
1880
1881                 errno = EINVAL;
1882                 return -1;
1883
1884         }
1885
1886         if (!fname) {
1887
1888                 errno = EINVAL;
1889                 return -1;
1890
1891         }
1892   
1893         DEBUG(4, ("smbc_mkdir(%s)\n", fname));
1894
1895         smbc_parse_path(context, fname, server, share, path, user, password); /*FIXME, errors*/
1896
1897         if (user[0] == (char)0) pstrcpy(user, context->user);
1898
1899         pstrcpy(workgroup, context->workgroup);
1900
1901         srv = smbc_server(context, server, share, workgroup, user, password);
1902
1903         if (!srv) {
1904
1905                 return -1;  /* errno set by smbc_server */
1906
1907         }
1908
1909         /* if (strncmp(srv->cli.dev, "IPC", 3) == 0) {
1910
1911            mode = aDIR | aRONLY;
1912
1913            }
1914            else if (strncmp(srv->cli.dev, "LPT", 3) == 0) {
1915
1916            if (strcmp(path, "\\") == 0) {
1917
1918            mode = aDIR | aRONLY;
1919
1920            }
1921            else {
1922
1923            mode = aRONLY;
1924            smbc_stat_printjob(srv, path, &size, &m_time);
1925            c_time = a_time = m_time;
1926
1927            }
1928            else { */
1929
1930         if (!cli_mkdir(&srv->cli, path)) {
1931
1932                 errno = smbc_errno(context, &srv->cli);
1933                 return -1;
1934
1935         } 
1936
1937         return 0;
1938
1939 }
1940
1941 /*
1942  * Our list function simply checks to see if a directory is not empty
1943  */
1944
1945 static int smbc_rmdir_dirempty = True;
1946
1947 static void rmdir_list_fn(file_info *finfo, const char *mask, void *state)
1948 {
1949
1950         if (strncmp(finfo->name, ".", 1) != 0 && strncmp(finfo->name, "..", 2) != 0)
1951                 smbc_rmdir_dirempty = False;
1952
1953 }
1954
1955 /*
1956  * Routine to remove a directory
1957  */
1958
1959 static int smbc_rmdir_ctx(SMBCCTX *context, const char *fname)
1960 {
1961         SMBCSRV *srv;
1962         fstring server, share, user, password, workgroup;
1963         pstring path;
1964
1965         if (!context || !context->internal || 
1966             !context->internal->_initialized) {
1967
1968                 errno = EINVAL;
1969                 return -1;
1970
1971         }
1972
1973         if (!fname) {
1974
1975                 errno = EINVAL;
1976                 return -1;
1977
1978         }
1979   
1980         DEBUG(4, ("smbc_rmdir(%s)\n", fname));
1981
1982         smbc_parse_path(context, fname, server, share, path, user, password); /*FIXME, errors*/
1983
1984         if (user[0] == (char)0) pstrcpy(user, context->user);
1985
1986         pstrcpy(workgroup, context->workgroup);
1987
1988         srv = smbc_server(context, server, share, workgroup, user, password);
1989
1990         if (!srv) {
1991
1992                 return -1;  /* errno set by smbc_server */
1993
1994         }
1995
1996         /* if (strncmp(srv->cli.dev, "IPC", 3) == 0) {
1997
1998            mode = aDIR | aRONLY;
1999
2000            }
2001            else if (strncmp(srv->cli.dev, "LPT", 3) == 0) {
2002
2003            if (strcmp(path, "\\") == 0) {
2004
2005            mode = aDIR | aRONLY;
2006
2007            }
2008            else {
2009
2010            mode = aRONLY;
2011            smbc_stat_printjob(srv, path, &size, &m_time);
2012            c_time = a_time = m_time;
2013            
2014            }
2015            else { */
2016
2017         if (!cli_rmdir(&srv->cli, path)) {
2018
2019                 errno = smbc_errno(context, &srv->cli);
2020
2021                 if (errno == EACCES) {  /* Check if the dir empty or not */
2022
2023                         pstring lpath; /* Local storage to avoid buffer overflows */
2024
2025                         smbc_rmdir_dirempty = True;  /* Make this so ... */
2026
2027                         pstrcpy(lpath, path);
2028                         pstrcat(lpath, "\\*");
2029
2030                         if (cli_list(&srv->cli, lpath, aDIR | aSYSTEM | aHIDDEN, rmdir_list_fn,
2031                                      NULL) < 0) {
2032
2033                                 /* Fix errno to ignore latest error ... */
2034
2035                                 DEBUG(5, ("smbc_rmdir: cli_list returned an error: %d\n", 
2036                                           smbc_errno(context, &srv->cli)));
2037                                 errno = EACCES;
2038
2039                         }
2040
2041                         if (smbc_rmdir_dirempty)
2042                                 errno = EACCES;
2043                         else
2044                                 errno = ENOTEMPTY;
2045
2046                 }
2047
2048                 return -1;
2049
2050         } 
2051
2052         return 0;
2053
2054 }
2055
2056 /*
2057  * Routine to return the current directory position
2058  */
2059
2060 static off_t smbc_telldir_ctx(SMBCCTX *context, SMBCFILE *dir)
2061 {
2062
2063         if (!context || !context->internal ||
2064             !context->internal->_initialized) {
2065
2066                 errno = EINVAL;
2067                 return -1;
2068
2069         }
2070
2071         if (!dir || !DLIST_CONTAINS(context->internal->_files, dir)) {
2072
2073                 errno = EBADF;
2074                 return -1;
2075
2076         }
2077
2078         if (dir->file != False) { /* FIXME, should be dir, perhaps */
2079
2080                 errno = ENOTDIR;
2081                 return -1;
2082
2083         }
2084
2085         return (off_t) dir->dir_next;
2086
2087 }
2088
2089 /*
2090  * A routine to run down the list and see if the entry is OK
2091  */
2092
2093 struct smbc_dir_list *smbc_check_dir_ent(struct smbc_dir_list *list, 
2094                                          struct smbc_dirent *dirent)
2095 {
2096
2097         /* Run down the list looking for what we want */
2098
2099         if (dirent) {
2100
2101                 struct smbc_dir_list *tmp = list;
2102
2103                 while (tmp) {
2104
2105                         if (tmp->dirent == dirent)
2106                                 return tmp;
2107
2108                         tmp = tmp->next;
2109
2110                 }
2111
2112         }
2113
2114         return NULL;  /* Not found, or an error */
2115
2116 }
2117
2118
2119 /*
2120  * Routine to seek on a directory
2121  */
2122
2123 static int smbc_lseekdir_ctx(SMBCCTX *context, SMBCFILE *dir, off_t offset)
2124 {
2125         struct smbc_dirent *dirent = (struct smbc_dirent *)offset;
2126         struct smbc_dir_list *list_ent = NULL;
2127
2128         if (!context || !context->internal ||
2129             !context->internal->_initialized) {
2130
2131                 errno = EINVAL;
2132                 return -1;
2133
2134         }
2135
2136         if (dir->file != False) { /* FIXME, should be dir, perhaps */
2137
2138                 errno = ENOTDIR;
2139                 return -1;
2140
2141         }
2142
2143         /* Now, check what we were passed and see if it is OK ... */
2144
2145         if (dirent == NULL) {  /* Seek to the begining of the list */
2146
2147                 dir->dir_next = dir->dir_list;
2148                 return 0;
2149
2150         }
2151
2152         /* Now, run down the list and make sure that the entry is OK       */
2153         /* This may need to be changed if we change the format of the list */
2154
2155         if ((list_ent = smbc_check_dir_ent(dir->dir_list, dirent)) == NULL) {
2156
2157                 errno = EINVAL;   /* Bad entry */
2158                 return -1;
2159
2160         }
2161
2162         dir->dir_next = list_ent;
2163
2164         return 0; 
2165
2166 }
2167
2168 /*
2169  * Routine to fstat a dir
2170  */
2171
2172 static int smbc_fstatdir_ctx(SMBCCTX *context, SMBCFILE *dir, struct stat *st)
2173 {
2174
2175         if (!context || !context->internal || 
2176             !context->internal->_initialized) {
2177
2178                 errno = EINVAL;
2179                 return -1;
2180
2181         }
2182
2183         /* No code yet ... */
2184
2185         return 0;
2186
2187 }
2188
2189 /*
2190  * Open a print file to be written to by other calls
2191  */
2192
2193 static SMBCFILE *smbc_open_print_job_ctx(SMBCCTX *context, const char *fname)
2194 {
2195         fstring server, share, user, password;
2196         pstring path;
2197         
2198         if (!context || !context->internal ||
2199             !context->internal->_initialized) {
2200
2201                 errno = EINVAL;
2202                 return NULL;
2203     
2204         }
2205
2206         if (!fname) {
2207
2208                 errno = EINVAL;
2209                 return NULL;
2210
2211         }
2212   
2213         DEBUG(4, ("smbc_open_print_job_ctx(%s)\n", fname));
2214
2215         smbc_parse_path(context, fname, server, share, path, user, password); /*FIXME, errors*/
2216
2217         /* What if the path is empty, or the file exists? */
2218
2219         return context->open(context, fname, O_WRONLY, 666);
2220
2221 }
2222
2223 /*
2224  * Routine to print a file on a remote server ...
2225  *
2226  * We open the file, which we assume to be on a remote server, and then
2227  * copy it to a print file on the share specified by printq.
2228  */
2229
2230 static int smbc_print_file_ctx(SMBCCTX *c_file, const char *fname, SMBCCTX *c_print, const char *printq)
2231 {
2232         SMBCFILE *fid1, *fid2;
2233         int bytes, saverr, tot_bytes = 0;
2234         char buf[4096];
2235
2236         if (!c_file || !c_file->internal->_initialized || !c_print ||
2237             !c_print->internal->_initialized) {
2238
2239                 errno = EINVAL;
2240                 return -1;
2241
2242         }
2243
2244         if (!fname && !printq) {
2245
2246                 errno = EINVAL;
2247                 return -1;
2248
2249         }
2250
2251         /* Try to open the file for reading ... */
2252
2253         if ((fid1 = c_file->open(c_file, fname, O_RDONLY, 0666)) < 0) {
2254                 
2255                 DEBUG(3, ("Error, fname=%s, errno=%i\n", fname, errno));
2256                 return -1;  /* smbc_open sets errno */
2257                 
2258         }
2259
2260         /* Now, try to open the printer file for writing */
2261
2262         if ((fid2 = c_print->open_print_job(c_print, printq)) < 0) {
2263
2264                 saverr = errno;  /* Save errno */
2265                 c_file->close(c_file, fid1);
2266                 errno = saverr;
2267                 return -1;
2268
2269         }
2270
2271         while ((bytes = c_file->read(c_file, fid1, buf, sizeof(buf))) > 0) {
2272
2273                 tot_bytes += bytes;
2274
2275                 if ((c_print->write(c_print, fid2, buf, bytes)) < 0) {
2276
2277                         saverr = errno;
2278                         c_file->close(c_file, fid1);
2279                         c_print->close(c_print, fid2);
2280                         errno = saverr;
2281
2282                 }
2283
2284         }
2285
2286         saverr = errno;
2287
2288         c_file->close(c_file, fid1);  /* We have to close these anyway */
2289         c_print->close(c_print, fid2);
2290
2291         if (bytes < 0) {
2292
2293                 errno = saverr;
2294                 return -1;
2295
2296         }
2297
2298         return tot_bytes;
2299
2300 }
2301
2302 /*
2303  * Routine to list print jobs on a printer share ...
2304  */
2305
2306 static int smbc_list_print_jobs_ctx(SMBCCTX *context, const char *fname, smbc_list_print_job_fn fn)
2307 {
2308         SMBCSRV *srv;
2309         fstring server, share, user, password, workgroup;
2310         pstring path;
2311
2312         if (!context || !context->internal ||
2313             !context->internal->_initialized) {
2314
2315                 errno = EINVAL;
2316                 return -1;
2317
2318         }
2319
2320         if (!fname) {
2321                 
2322                 errno = EINVAL;
2323                 return -1;
2324
2325         }
2326   
2327         DEBUG(4, ("smbc_list_print_jobs(%s)\n", fname));
2328
2329         smbc_parse_path(context, fname, server, share, path, user, password); /*FIXME, errors*/
2330
2331         if (user[0] == (char)0) pstrcpy(user, context->user);
2332         
2333         pstrcpy(workgroup, context->workgroup);
2334
2335         srv = smbc_server(context, server, share, workgroup, user, password);
2336
2337         if (!srv) {
2338
2339                 return -1;  /* errno set by smbc_server */
2340
2341         }
2342
2343         if (cli_print_queue(&srv->cli, (void (*)(struct print_job_info *))fn) < 0) {
2344
2345                 errno = smbc_errno(context, &srv->cli);
2346                 return -1;
2347
2348         }
2349         
2350         return 0;
2351
2352 }
2353
2354 /*
2355  * Delete a print job from a remote printer share
2356  */
2357
2358 static int smbc_unlink_print_job_ctx(SMBCCTX *context, const char *fname, int id)
2359 {
2360         SMBCSRV *srv;
2361         fstring server, share, user, password, workgroup;
2362         pstring path;
2363         int err;
2364
2365         if (!context || !context->internal ||
2366             !context->internal->_initialized) {
2367
2368                 errno = EINVAL;
2369                 return -1;
2370
2371         }
2372
2373         if (!fname) {
2374
2375                 errno = EINVAL;
2376                 return -1;
2377
2378         }
2379   
2380         DEBUG(4, ("smbc_unlink_print_job(%s)\n", fname));
2381
2382         smbc_parse_path(context, fname, server, share, path, user, password); /*FIXME, errors*/
2383
2384         if (user[0] == (char)0) pstrcpy(user, context->user);
2385
2386         pstrcpy(workgroup, context->workgroup);
2387
2388         srv = smbc_server(context, server, share, workgroup, user, password);
2389
2390         if (!srv) {
2391
2392                 return -1;  /* errno set by smbc_server */
2393
2394         }
2395
2396         if ((err = cli_printjob_del(&srv->cli, id)) != 0) {
2397
2398                 if (err < 0)
2399                         errno = smbc_errno(context, &srv->cli);
2400                 else if (err == ERRnosuchprintjob)
2401                         errno = EINVAL;
2402                 return -1;
2403
2404         }
2405
2406         return 0;
2407
2408 }
2409
2410 /*
2411  * Get a new empty handle to fill in with your own info 
2412  */
2413 SMBCCTX * smbc_new_context(void)
2414 {
2415         SMBCCTX * context;
2416
2417         context = malloc(sizeof(SMBCCTX));
2418         if (!context) {
2419                 errno = ENOMEM;
2420                 return NULL;
2421         }
2422
2423         ZERO_STRUCTP(context);
2424
2425         context->internal = malloc(sizeof(struct smbc_internal_data));
2426         if (!context->internal) {
2427                 errno = ENOMEM;
2428                 return NULL;
2429         }
2430
2431         ZERO_STRUCTP(context->internal);
2432
2433         
2434         /* ADD REASONABLE DEFAULTS */
2435         context->debug            = 0;
2436         context->timeout          = 20000; /* 20 seconds */
2437
2438         context->open             = smbc_open_ctx;
2439         context->creat            = smbc_creat_ctx;
2440         context->read             = smbc_read_ctx;
2441         context->write            = smbc_write_ctx;
2442         context->close            = smbc_close_ctx;
2443         context->unlink           = smbc_unlink_ctx;
2444         context->rename           = smbc_rename_ctx;
2445         context->lseek            = smbc_lseek_ctx;
2446         context->stat             = smbc_stat_ctx;
2447         context->fstat            = smbc_fstat_ctx;
2448         context->opendir          = smbc_opendir_ctx;
2449         context->closedir         = smbc_closedir_ctx;
2450         context->readdir          = smbc_readdir_ctx;
2451         context->getdents         = smbc_getdents_ctx;
2452         context->mkdir            = smbc_mkdir_ctx;
2453         context->rmdir            = smbc_rmdir_ctx;
2454         context->telldir          = smbc_telldir_ctx;
2455         context->lseekdir         = smbc_lseekdir_ctx;
2456         context->fstatdir         = smbc_fstatdir_ctx;
2457         context->open_print_job   = smbc_open_print_job_ctx;
2458         context->print_file       = smbc_print_file_ctx;
2459         context->list_print_jobs  = smbc_list_print_jobs_ctx;
2460         context->unlink_print_job = smbc_unlink_print_job_ctx;
2461
2462         context->callbacks.check_server_fn      = smbc_check_server;
2463         context->callbacks.remove_unused_server_fn = smbc_remove_unused_server;
2464
2465         smbc_default_cache_functions(context);
2466
2467         return context;
2468 }
2469
2470 /* 
2471  * Free a context
2472  *
2473  * Returns 0 on success. Otherwise returns 1, the SMBCCTX is _not_ freed 
2474  * and thus you'll be leaking memory if not handled properly.
2475  *
2476  */
2477 int smbc_free_context(SMBCCTX * context, int shutdown_ctx)
2478 {
2479         if (!context) {
2480                 errno = EBADF;
2481                 return 1;
2482         }
2483         
2484         if (shutdown_ctx) {
2485                 SMBCFILE * f;
2486                 DEBUG(1,("Performing aggressive shutdown.\n"));
2487                 
2488                 f = context->internal->_files;
2489                 while (f) {
2490                         context->close(context, f);
2491                         f = f->next;
2492                 }
2493                 context->internal->_files = NULL;
2494
2495                 /* First try to remove the servers the nice way. */
2496                 if (context->callbacks.purge_cached_fn(context)) {
2497                         SMBCSRV * s;
2498                         DEBUG(1, ("Could not purge all servers, Nice way shutdown failed.\n"));
2499                         s = context->internal->_servers;
2500                         while (s) {
2501                                 cli_shutdown(&s->cli);
2502                                 context->callbacks.remove_cached_srv_fn(context, s);
2503                                 SAFE_FREE(s);
2504                                 s = s->next;
2505                         }
2506                         context->internal->_servers = NULL;
2507                 }
2508         }
2509         else {
2510                 /* This is the polite way */    
2511                 if (context->callbacks.purge_cached_fn(context)) {
2512                         DEBUG(1, ("Could not purge all servers, free_context failed.\n"));
2513                         errno = EBUSY;
2514                         return 1;
2515                 }
2516                 if (context->internal->_servers) {
2517                         DEBUG(1, ("Active servers in context, free_context failed.\n"));
2518                         errno = EBUSY;
2519                         return 1;
2520                 }
2521                 if (context->internal->_files) {
2522                         DEBUG(1, ("Active files in context, free_context failed.\n"));
2523                         errno = EBUSY;
2524                         return 1;
2525                 }               
2526         }
2527
2528         /* Things we have to clean up */
2529         SAFE_FREE(context->workgroup);
2530         SAFE_FREE(context->netbios_name);
2531         SAFE_FREE(context->user);
2532         
2533         DEBUG(3, ("Context %p succesfully freed\n", context));
2534         SAFE_FREE(context->internal);
2535         SAFE_FREE(context);
2536         return 0;
2537 }
2538
2539
2540 /*
2541  * Initialise the library etc 
2542  *
2543  * We accept a struct containing handle information.
2544  * valid values for info->debug from 0 to 100,
2545  * and insist that info->fn must be non-null.
2546  */
2547 SMBCCTX * smbc_init_context(SMBCCTX * context)
2548 {
2549         pstring conf;
2550         int pid;
2551         char *user = NULL, *home = NULL;
2552
2553         if (!context || !context->internal) {
2554                 errno = EBADF;
2555                 return NULL;
2556         }
2557
2558         /* Do not initialise the same client twice */
2559         if (context->internal->_initialized) { 
2560                 return 0;
2561         }
2562
2563         if (!context->callbacks.auth_fn || context->debug < 0 || context->debug > 100) {
2564
2565                 errno = EINVAL;
2566                 return NULL;
2567
2568         }
2569
2570         if (!smbc_initialized) {
2571                 /* Do some library wide intialisations the first time we get called */
2572
2573                 /* Do we still need this ? */
2574                 DEBUGLEVEL = 10;
2575                 
2576                 setup_logging( "libsmbclient", False);
2577
2578                 /* Here we would open the smb.conf file if needed ... */
2579                 
2580                 home = getenv("HOME");
2581
2582                 slprintf(conf, sizeof(conf), "%s/.smb/smb.conf", home);
2583                 
2584                 load_interfaces();  /* Load the list of interfaces ... */
2585                 
2586                 in_client = True; /* FIXME, make a param */
2587
2588                 if (!lp_load(conf, True, False, False)) {
2589
2590                         /*
2591                          * Hmmm, what the hell do we do here ... we could not parse the
2592                          * config file ... We must return an error ... and keep info around
2593                          * about why we failed
2594                          */
2595                         
2596                         errno = ENOENT; /* FIXME: Figure out the correct error response */
2597                         return NULL;
2598                 }
2599
2600                 reopen_logs();  /* Get logging working ... */
2601         
2602                 /* 
2603                  * Block SIGPIPE (from lib/util_sock.c: write())  
2604                  * It is not needed and should not stop execution 
2605                  */
2606                 BlockSignals(True, SIGPIPE);
2607                 
2608                 /* Done with one-time initialisation */
2609                 smbc_initialized = 1; 
2610
2611         }
2612         
2613         if (!context->user) {
2614                 /*
2615                  * FIXME: Is this the best way to get the user info? 
2616                  */
2617                 user = getenv("USER");
2618                 /* walk around as "guest" if no username can be found */
2619                 if (!user) context->user = strdup("guest");
2620                 else context->user = strdup(user);
2621         }
2622
2623         if (!context->netbios_name) {
2624                 /*
2625                  * We try to get our netbios name from the config. If that fails we fall
2626                  * back on constructing our netbios name from our hostname etc
2627                  */
2628                 if (global_myname) {
2629                         context->netbios_name = strdup(global_myname);
2630                 }
2631                 else {
2632                         /*
2633                          * Hmmm, I want to get hostname as well, but I am too lazy for the moment
2634                          */
2635                         pid = sys_getpid();
2636                         context->netbios_name = malloc(17);
2637                         if (!context->netbios_name) {
2638                                 errno = ENOMEM;
2639                                 return NULL;
2640                         }
2641                         slprintf(context->netbios_name, 16, "smbc%s%d", context->user, pid);
2642                 }
2643         }
2644         DEBUG(0,("Using netbios name %s.\n", context->netbios_name));
2645         
2646
2647         if (!context->workgroup) {
2648                 if (lp_workgroup()) {
2649                         context->workgroup = strdup(lp_workgroup());
2650                 }
2651                 else {
2652                         /* TODO: Think about a decent default workgroup */
2653                         context->workgroup = strdup("samba");
2654                 }
2655         }
2656         DEBUG(0,("Using workgroup %s.\n", context->workgroup));
2657                                         
2658         /* shortest timeout is 1 second */
2659         if (context->timeout > 0 && context->timeout < 1000) 
2660                 context->timeout = 1000;
2661
2662         /*
2663          * FIXME: Should we check the function pointers here? 
2664          */
2665
2666         context->internal->_initialized = 1;
2667         
2668         return context;
2669 }