Fixed a glibc glitch in smbumount.c and reenabled some debugging
[samba.git] / source3 / client / smbmount.c
1 /* 
2    Unix SMB/Netbios implementation.
3    Version 1.9.
4    SMB client
5    Copyright (C) Andrew Tridgell 1994-1998
6    
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11    
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16    
17    You should have received a copy of the GNU General Public License
18    along with this program; if not, write to the Free Software
19    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22 #define NO_SYSLOG
23
24 #include <linux/version.h>
25 #define LVERSION(major,minor,patch) (((((major)<<8)+(minor))<<8)+(patch))
26 #if LINUX_VERSION_CODE < LVERSION(2,1,70)
27 #error this code will only compile on versions of linux after 2.1.70
28 #endif
29
30 #include "includes.h"
31
32 #include <asm/types.h>
33 #include <linux/smb_fs.h>
34 static struct smb_conn_opt conn_options;
35
36 #ifndef REGISTER
37 #define REGISTER 0
38 #endif
39
40 /* Uncomment this to allow debug the smbmount daemon */
41 #define SMBFS_DEBUG 1
42
43 pstring cur_dir = "\\";
44 pstring cd_path = "";
45 extern pstring service;
46 extern pstring desthost;
47 extern pstring global_myname;
48 extern pstring myhostname;
49 extern pstring password;
50 extern pstring username;
51 extern pstring workgroup;
52 char *cmdstr="";
53 extern BOOL got_pass;
54 extern BOOL connect_as_printer;
55 extern BOOL connect_as_ipc;
56 extern struct in_addr ipzero;
57
58 extern BOOL doencrypt;
59
60 extern pstring user_socket_options;
61
62 /* 30 second timeout on most commands */
63 #define CLIENT_TIMEOUT (30*1000)
64 #define SHORT_TIMEOUT (5*1000)
65
66 /* value for unused fid field in trans2 secondary request */
67 #define FID_UNUSED (0xFFFF)
68
69 extern int name_type;
70
71 extern int max_protocol;
72 int port = SMB_PORT;
73
74 time_t newer_than = 0;
75 int archive_level = 0;
76
77 extern pstring debugf;
78 extern int DEBUGLEVEL;
79
80 BOOL translation = False;
81
82 extern uint16 cnum;
83 extern uint16 mid;
84 extern uint16 pid;
85 extern uint16 vuid;
86
87 extern BOOL have_ip;
88 extern int max_xmit;
89
90 /* clitar bits insert */
91 extern int blocksize;
92 extern BOOL tar_inc;
93 extern BOOL tar_reset;
94 /* clitar bits end */
95  
96
97 mode_t myumask = 0755;
98
99 extern pstring scope;
100
101 BOOL prompt = True;
102
103 int printmode = 1;
104
105 BOOL recurse = False;
106 BOOL lowercase = False;
107
108 struct in_addr dest_ip;
109
110 #define SEPARATORS " \t\n\r"
111
112 BOOL abort_mget = True;
113
114 extern int Protocol;
115
116 extern BOOL readbraw_supported ;
117 extern BOOL writebraw_supported;
118
119 pstring fileselection = "";
120
121 extern file_info def_finfo;
122
123 /* timing globals */
124 int get_total_size = 0;
125 int get_total_time_ms = 0;
126 int put_total_size = 0;
127 int put_total_time_ms = 0;
128
129 /* totals globals */
130 int dir_total = 0;
131
132 extern int Client;
133
134 #define USENMB
135
136 #define CNV_LANG(s) dos_to_unix(s,False)
137 #define CNV_INPUT(s) unix_to_dos(s,True)
138
139 /****************************************************************************
140 check for existance of a dir
141 ****************************************************************************/
142 static BOOL chkpath(char *path,BOOL report)
143 {
144   fstring path2;
145   pstring inbuf,outbuf;
146   char *p;
147
148   fstrcpy(path2,path);
149   trim_string(path2,NULL,"\\");
150   if (!*path2) *path2 = '\\';
151
152   memset(outbuf,'\0',smb_size);
153   set_message(outbuf,0,4 + strlen(path2),True);
154   SCVAL(outbuf,smb_com,SMBchkpth);
155   SSVAL(outbuf,smb_tid,cnum);
156   cli_setup_pkt(outbuf);
157
158   p = smb_buf(outbuf);
159   *p++ = 4;
160   fstrcpy(p,path2);
161
162 #if 0
163   {
164           /* this little bit of code can be used to extract NT error codes.
165              Just feed a bunch of "cd foo" commands to smbclient then watch
166              in netmon (tridge) */
167           static int code=0;
168           SIVAL(outbuf, smb_rcls, code | 0xC0000000);
169           SSVAL(outbuf, smb_flg2, SVAL(outbuf, smb_flg2) | (1<<14));
170           code++;
171   }
172 #endif
173
174   send_smb(Client,outbuf);
175   client_receive_smb(Client,inbuf,CLIENT_TIMEOUT);
176
177   if (report && CVAL(inbuf,smb_rcls) != 0)
178     DEBUG(2,("chkpath: %s\n",smb_errstr(inbuf)));
179
180   return(CVAL(inbuf,smb_rcls) == 0);
181 }
182
183 static void
184 exit_parent( int sig )
185 {
186         /* parent simply exits when child says go... */
187         exit(0);
188 }
189
190 static void
191 daemonize(void)
192 {
193         int j, status;
194         pid_t child_pid;
195
196         signal( SIGTERM, exit_parent );
197
198         if ((child_pid = fork()) < 0)
199         {
200                 DEBUG(0, ("could not fork\n"));
201         }
202         if (child_pid > 0)
203         {
204                 while( 1 ) {
205                         j = waitpid( child_pid, &status, 0 );
206                         if( j < 0 ) {
207                                 if( EINTR == errno ) {
208                                         continue;
209                                 }
210                                 status = errno;
211                         }
212                         break;
213                 }
214                 /* If we get here - the child exited with some error status */
215                 exit(status);
216         }
217         /* Programmers Note:
218                 Danger Will Robinson!  Danger!
219
220                 There use to be a call to setsid() here.  This does no
221                 harm to normal mount operations, but it broke automounting.
222                 The setsid call has been moved to just before the child
223                 sends the SIGTERM to the parent.  All of our deadly embrace
224                 conditions with autofs will have been cleared by then...
225                 -mhw-
226         */
227         signal( SIGTERM, SIG_DFL );
228         chdir("/");
229 }
230
231 static void
232 close_our_files(void)
233 {
234         int i;
235         for (i = 0; i < NR_OPEN; i++) {
236                 if (i == Client) {
237                         continue;
238                 }
239                 close(i);
240         }
241 }
242
243 static void
244 usr1_handler(int x)
245 {
246         return;
247 }
248
249 /*
250  * Send a login and store the connection options. This is a separate
251  * function to keep clientutil.c independent of linux kernel changes.
252  */
253 static BOOL mount_send_login(char *inbuf, char *outbuf)
254 {
255   struct connection_options opt;
256   int res = cli_send_login(inbuf, outbuf, True, True, &opt);
257
258   if (!res)
259     return res;
260
261   conn_options.protocol = opt.protocol;
262   conn_options.case_handling = CASE_LOWER;
263   conn_options.max_xmit = opt.max_xmit;
264   conn_options.server_uid = opt.server_vuid;
265   conn_options.tid = opt.tid;
266   conn_options.secmode = opt.sec_mode;
267   conn_options.maxmux = opt.max_mux;
268   conn_options.maxvcs = opt.max_vcs;
269   conn_options.rawmode = opt.rawmode;
270   conn_options.sesskey = opt.sesskey;
271   conn_options.maxraw = opt.maxraw;
272   conn_options.capabilities = opt.capabilities;
273   conn_options.serverzone = opt.serverzone;
274
275   return True;
276 }
277
278 /*
279  * Call the smbfs ioctl to install a connection socket,
280  * then wait for a signal to reconnect. Note that we do
281  * not exit after open_sockets() or send_login() errors,
282  * as the smbfs mount would then have no way to recover.
283  */
284 static void
285 send_fs_socket(char *mount_point, char *inbuf, char *outbuf)
286 {
287         int fd, closed = 0, res = 1;
288
289         pid_t parentpid = getppid();
290
291         while (1)
292         {
293                 if ((fd = open(mount_point, O_RDONLY)) < 0)
294                 {
295                         DEBUG(0, ("smbmount: can't open %s\n", mount_point));
296                         break;
297                 }               
298
299                 /*
300                  * Call the ioctl even if we couldn't get a socket ...
301                  * there's no point in making smbfs wait for a timeout.
302                  */
303                 conn_options.fd = -1;
304                 if (res)
305                         conn_options.fd = Client;
306                 res = ioctl(fd, SMB_IOC_NEWCONN, &conn_options);
307                 if (res != 0)
308                 {
309                         DEBUG(0, ("smbmount: ioctl failed, res=%d\n", res));
310                 }
311
312                 if( parentpid ) {
313                         /* Ok...  We are going to kill the parent.  Now
314                                 is the time to break the process group... */
315                         setsid();
316                         /* Send a signal to the parent to terminate */
317                         kill( parentpid, SIGTERM );
318                         parentpid = 0;
319                 }
320
321                 close_sockets();
322                 close(fd);
323                 /*
324                  * Close all open files if we haven't done so yet.
325                  */
326 #ifndef SMBFS_DEBUG
327                 if (!closed)
328                 {
329                         closed = 1;
330                         close_our_files();
331                 }
332 #endif
333
334                 /*
335                  * Wait for a signal from smbfs ...
336                  */
337                 CatchSignal(SIGUSR1, &usr1_handler);
338                 pause();
339                 DEBUG(0, ("smbmount: got signal, getting new socket\n"));
340
341                 res = cli_open_sockets(port);
342                 if (!res)
343                 {
344                         DEBUG(0, ("smbmount: can't open sockets\n"));
345                         continue;
346                 }
347
348                 res = mount_send_login(inbuf, outbuf);
349                 if (!res)
350                 {
351                         DEBUG(0, ("smbmount: login failed\n"));
352                 }
353         }
354         DEBUG(0, ("smbmount: exit\n"));
355         exit(1);
356 }
357
358 /****************************************************************************
359 mount smbfs
360 ****************************************************************************/
361 static void cmd_mount(char *inbuf,char *outbuf)
362 {
363         pstring mpoint;
364         pstring share_name;
365         pstring mount_command;
366         fstring buf;
367         int retval;
368         char mount_point[MAXPATHLEN+1];
369
370         if (!next_token(NULL, mpoint, NULL, sizeof(mpoint)))
371         {
372                 DEBUG(0,("You must supply a mount point\n"));
373                 return;
374         }
375
376         memset(mount_point, 0, sizeof(mount_point));
377
378         if (realpath(mpoint, mount_point) == NULL)
379         {
380                 DEBUG(0, ("Could not resolve mount point\n"));
381                 return;
382         }
383
384         /*
385          * Build the service name to report on the Unix side,
386          * converting '\' to '/' and ' ' to '_'.
387          */
388         pstrcpy(share_name, service);  
389         string_replace(share_name, '\\', '/');
390         string_replace(share_name, ' ', '_');
391
392         slprintf(mount_command, sizeof(mount_command)-1,"smbmnt %s -s %s", mount_point, share_name);
393
394         while(next_token(NULL, buf, NULL, sizeof(buf)))
395         {
396                 pstrcat(mount_command, " ");
397                 pstrcat(mount_command, buf);
398         }
399
400         DEBUG(3, ("mount command: %s\n", mount_command));
401
402         /*
403                 Set up to return as a daemon child and wait in the parent
404                 until the child say it's ready...
405         */
406         daemonize();
407
408         if ((retval = system(mount_command)) != 0)
409         {
410                 DEBUG(0,("mount failed\n"));
411                 exit(1);
412         }
413
414         send_fs_socket(mount_point, inbuf, outbuf);
415 }       
416
417
418 /* This defines the commands supported by this client */
419 struct
420 {
421   char *name;
422   void (*fn)();
423   char *description;
424 } commands[] = 
425 {
426   {"mount", cmd_mount, "<mount-point options> mount an smbfs file system"},
427   {"",NULL,NULL}
428 };
429
430
431 /*******************************************************************
432   lookup a command string in the list of commands, including 
433   abbreviations
434   ******************************************************************/
435 static int process_tok(fstring tok)
436 {
437   int i = 0, matches = 0;
438   int cmd=0;
439   int tok_len = strlen(tok);
440   
441   while (commands[i].fn != NULL)
442     {
443       if (strequal(commands[i].name,tok))
444         {
445           matches = 1;
446           cmd = i;
447           break;
448         }
449       else if (strnequal(commands[i].name, tok, tok_len))
450         {
451           matches++;
452           cmd = i;
453         }
454       i++;
455     }
456   
457   if (matches == 0)
458     return(-1);
459   else if (matches == 1)
460     return(cmd);
461   else
462     return(-2);
463 }
464
465 /****************************************************************************
466 help
467 ****************************************************************************/
468 void cmd_help(char *dum_in, char *dum_out)
469 {
470   int i=0,j;
471   fstring buf;
472
473   if (next_token(NULL,buf,NULL,sizeof(buf)))
474     {
475       if ((i = process_tok(buf)) >= 0)
476         DEBUG(0,("HELP %s:\n\t%s\n\n",commands[i].name,commands[i].description));                   
477     }
478   else
479     while (commands[i].description)
480       {
481         for (j=0; commands[i].description && (j<5); j++) {
482           DEBUG(0,("%-15s",commands[i].name));
483           i++;
484         }
485         DEBUG(0,("\n"));
486       }
487 }
488
489 /****************************************************************************
490 wait for keyboard activity, swallowing network packets
491 ****************************************************************************/
492 static void wait_keyboard(char *buffer)
493 {
494   fd_set fds;
495   int selrtn;
496   struct timeval timeout;
497   
498   while (1) 
499     {
500       extern int Client;
501       FD_ZERO(&fds);
502       FD_SET(Client,&fds);
503       FD_SET(fileno(stdin),&fds);
504
505       timeout.tv_sec = 20;
506       timeout.tv_usec = 0;
507       selrtn = sys_select(MAX(Client,fileno(stdin))+1,&fds,&timeout);
508       
509       if (FD_ISSET(fileno(stdin),&fds))
510         return;
511
512       /* We deliberately use receive_smb instead of
513          client_receive_smb as we want to receive
514          session keepalives and then drop them here.
515        */
516       if (FD_ISSET(Client,&fds))
517         receive_smb(Client,buffer,0);
518       
519       chkpath("\\",False);
520     }  
521 }
522
523
524 /****************************************************************************
525   process commands from the client
526 ****************************************************************************/
527 static BOOL process(char *base_directory)
528 {
529   extern FILE *dbf;
530   pstring line;
531   char *cmd;
532
533   char *InBuffer = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
534   char *OutBuffer = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
535
536   if ((InBuffer == NULL) || (OutBuffer == NULL)) 
537     return(False);
538   
539   memset(OutBuffer,'\0',smb_size);
540
541   if (!mount_send_login(InBuffer,OutBuffer))
542     return(False);
543
544   cmd = cmdstr;
545   if (cmd[0] != '\0') while (cmd[0] != '\0')
546     {
547       char *p;
548       fstring tok;
549       int i;
550
551       if ((p = strchr(cmd, ';')) == 0)
552         {
553           strncpy(line, cmd, 999);
554           line[1000] = '\0';
555           cmd += strlen(cmd);
556         }
557       else
558         {
559           if (p - cmd > 999) p = cmd + 999;
560           strncpy(line, cmd, p - cmd);
561           line[p - cmd] = '\0';
562           cmd = p + 1;
563         }
564
565       /* input language code to internal one */
566       CNV_INPUT (line);
567       
568       /* and get the first part of the command */
569       {
570         char *ptr = line;
571         if (!next_token(&ptr,tok,NULL,sizeof(tok))) continue;
572       }
573
574       if ((i = process_tok(tok)) >= 0)
575         commands[i].fn(InBuffer,OutBuffer);
576       else if (i == -2)
577         DEBUG(0,("%s: command abbreviation ambiguous\n",CNV_LANG(tok)));
578       else
579         DEBUG(0,("%s: command not found\n",CNV_LANG(tok)));
580     }
581   else while (!feof(stdin))
582     {
583       fstring tok;
584       int i;
585
586       memset(OutBuffer,'\0',smb_size);
587
588       /* display a prompt */
589       DEBUG(0,("smb: %s> ", CNV_LANG(cur_dir)));
590       dbgflush();
591
592       wait_keyboard(InBuffer);
593   
594       /* and get a response */
595       if (!fgets(line,1000,stdin))
596         break;
597
598       /* input language code to internal one */
599       CNV_INPUT (line);
600
601       /* special case - first char is ! */
602       if (*line == '!')
603         {
604           system(line + 1);
605           continue;
606         }
607       
608       /* and get the first part of the command */
609       {
610         char *ptr = line;
611         if (!next_token(&ptr,tok,NULL,sizeof(tok))) continue;
612       }
613
614       if ((i = process_tok(tok)) >= 0)
615         commands[i].fn(InBuffer,OutBuffer);
616       else if (i == -2)
617         DEBUG(0,("%s: command abbreviation ambiguous\n",CNV_LANG(tok)));
618       else
619         DEBUG(0,("%s: command not found\n",CNV_LANG(tok)));
620     }
621   
622   cli_send_logout(InBuffer,OutBuffer);
623   return(True);
624 }
625
626 /****************************************************************************
627 usage on the program
628 ****************************************************************************/
629 static void usage(char *pname)
630 {
631   DEBUG(0,("Usage: %s service <password> [-p port] [-d debuglevel] [-l log] ",
632            pname));
633
634   DEBUG(0,("\nVersion %s\n",VERSION));
635   DEBUG(0,("\t-p port               connect to the specified port\n"));
636   DEBUG(0,("\t-d debuglevel         set the debuglevel\n"));
637   DEBUG(0,("\t-l log basename.      Basename for log/debug files\n"));
638   DEBUG(0,("\t-n netbios name.      Use this name as my netbios name\n"));
639   DEBUG(0,("\t-N                    don't ask for a password\n"));
640   DEBUG(0,("\t-m max protocol       set the max protocol level\n"));
641   DEBUG(0,("\t-I dest IP            use this IP to connect to\n"));
642   DEBUG(0,("\t-E                    write messages to stderr instead of stdout\n"));
643   DEBUG(0,("\t-U username           set the network username\n"));
644   DEBUG(0,("\t-W workgroup          set the workgroup name\n"));
645   DEBUG(0,("\t-c command string     execute semicolon separated commands\n"));
646   DEBUG(0,("\t-t terminal code      terminal i/o code {sjis|euc|jis7|jis8|junet|hex}\n"));
647   DEBUG(0,("\t-D directory          start from directory\n"));
648   DEBUG(0,("\n"));
649 }
650
651 /****************************************************************************
652   main program
653 ****************************************************************************/
654  int main(int argc,char *argv[])
655 {
656   fstring base_directory;
657   char *pname = argv[0];
658   int opt;
659   extern FILE *dbf;
660   extern char *optarg;
661   extern int optind;
662   pstring query_host;
663   BOOL nt_domain_logon = False;
664   static pstring servicesf = CONFIGFILE;
665   pstring term_code;
666   char *p;
667
668 #ifdef KANJI
669   pstrcpy(term_code, KANJI);
670 #else /* KANJI */
671   *term_code = 0;
672 #endif /* KANJI */
673
674   *query_host = 0;
675   *base_directory = 0;
676
677   DEBUGLEVEL = 2;
678
679   setup_logging(pname,True);
680
681   TimeInit();
682   charset_initialise();
683
684   pid = (uint16)getpid();
685   vuid = (uint16)getuid();
686   mid = pid + 100;
687   myumask = umask(0);
688   umask(myumask);
689
690   if (getenv("USER"))
691   {
692     pstrcpy(username,getenv("USER"));
693
694     /* modification to support userid%passwd syntax in the USER var
695        25.Aug.97, jdblair@uab.edu */
696
697     if ((p=strchr(username,'%')))
698     {
699       *p = 0;
700       pstrcpy(password,p+1);
701       got_pass = True;
702       memset(strchr(getenv("USER"),'%')+1,'X',strlen(password));
703     }
704     strupper(username);
705   }
706
707  /* modification to support PASSWD environmental var
708   25.Aug.97, jdblair@uab.edu */
709
710   if (getenv("PASSWD"))
711     pstrcpy(password,getenv("PASSWD"));
712
713   if (*username == 0 && getenv("LOGNAME"))
714     {
715       pstrcpy(username,getenv("LOGNAME"));
716       strupper(username);
717     }
718
719   if (argc < 2)
720     {
721       usage(pname);
722       exit(1);
723     }
724   
725   if (*argv[1] != '-')
726     {
727
728       pstrcpy(service, argv[1]);  
729       /* Convert any '/' characters in the service name to '\' characters */
730       string_replace( service, '/','\\');
731       argc--;
732       argv++;
733
734       if (count_chars(service,'\\') < 3)
735         {
736           usage(pname);
737           printf("\n%s: Not enough '\\' characters in service\n",service);
738           exit(1);
739         }
740
741       if (argc > 1 && (*argv[1] != '-'))
742         {
743           got_pass = True;
744           pstrcpy(password,argv[1]);  
745           memset(argv[1],'X',strlen(argv[1]));
746           argc--;
747           argv++;
748         }
749     }
750
751   while ((opt = 
752           getopt(argc, argv,"s:B:O:M:S:i:Nn:d:Pp:l:hI:EB:U:L:t:m:W:T:D:c:")) != EOF)
753     switch (opt)
754       {
755       case 'm':
756         max_protocol = interpret_protocol(optarg,max_protocol);
757         break;
758       case 'O':
759         pstrcpy(user_socket_options,optarg);
760         break;  
761       case 'S':
762         pstrcpy(desthost,optarg);
763         strupper(desthost);
764         nt_domain_logon = True;
765         break;
766       case 'B':
767         iface_set_default(NULL,optarg,NULL);
768         break;
769       case 'D':
770         pstrcpy(base_directory,optarg);
771         break;
772       case 'i':
773         pstrcpy(scope,optarg);
774         break;
775       case 'U':
776         {
777           char *lp;
778         pstrcpy(username,optarg);
779         if ((lp=strchr(username,'%')))
780           {
781             *lp = 0;
782             pstrcpy(password,lp+1);
783             got_pass = True;
784             memset(strchr(optarg,'%')+1,'X',strlen(password));
785           }
786         }
787             
788         break;
789       case 'W':
790         pstrcpy(workgroup,optarg);
791         break;
792       case 'E':
793         dbf = stderr;
794         break;
795       case 'I':
796         {
797           dest_ip = *interpret_addr2(optarg);
798           if (zero_ip(dest_ip)) exit(1);
799           have_ip = True;
800         }
801         break;
802       case 'n':
803         pstrcpy(global_myname,optarg);
804         break;
805       case 'N':
806         got_pass = True;
807         break;
808       case 'd':
809         if (*optarg == 'A')
810           DEBUGLEVEL = 10000;
811         else
812           DEBUGLEVEL = atoi(optarg);
813         break;
814       case 'l':
815         slprintf(debugf,sizeof(debugf)-1,"%s.client",optarg);
816         break;
817       case 'p':
818         port = atoi(optarg);
819         break;
820       case 'c':
821         cmdstr = optarg;
822         got_pass = True;
823         break;
824       case 'h':
825         usage(pname);
826         exit(0);
827         break;
828       case 's':
829         pstrcpy(servicesf, optarg);
830         break;
831       case 't':
832         pstrcpy(term_code, optarg);
833         break;
834       default:
835         usage(pname);
836         exit(1);
837       }
838
839   if (!*query_host && !*service)
840     {
841       usage(pname);
842       exit(1);
843     }
844
845
846   DEBUG( 3, ( "Client started (version %s)\n", VERSION ) );
847
848   if(!get_myname(myhostname,NULL))
849   {
850     DEBUG(0,("Failed to get my hostname.\n"));
851   }
852
853   if (!lp_load(servicesf,True,False,False)) {
854     fprintf(stderr, "Can't load %s - run testparm to debug it\n", servicesf);
855   }
856
857   codepage_initialise(lp_client_code_page());
858
859   interpret_coding_system(term_code);
860
861   if (*workgroup == 0)
862     pstrcpy(workgroup,lp_workgroup());
863
864   load_interfaces();
865   get_myname((*global_myname)?NULL:global_myname,NULL);  
866   strupper(global_myname);
867
868   if (cli_open_sockets(port))
869     {
870       if (!process(base_directory))
871         {
872           close_sockets();
873           return(1);
874         }
875       close_sockets();
876     }
877   else
878     return(1);
879
880   return(0);
881 }