r1897: added a choose_called_name() function that allows us to more sanely
[jelmer/samba4-debian.git] / source / client / smbmount.c
1 /* 
2    Unix SMB/CIFS implementation.
3    SMBFS mount program
4    Copyright (C) Andrew Tridgell 1999
5    
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 2 of the License, or
9    (at your option) any later version.
10    
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15    
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, write to the Free Software
18    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20
21 #include "includes.h"
22
23 #include <mntent.h>
24 #include <asm/types.h>
25 #include <linux/smb_fs.h>
26
27 extern BOOL in_client;
28
29 static pstring credentials;
30 static pstring my_netbios_name;
31 static pstring password;
32 static pstring username;
33 static pstring workgroup;
34 static pstring mpoint;
35 static pstring service;
36 static pstring options;
37
38 static struct in_addr dest_ip;
39 static BOOL have_ip;
40 static int smb_port = 0;
41 static BOOL got_user;
42 static BOOL got_pass;
43 static uid_t mount_uid;
44 static gid_t mount_gid;
45 static int mount_ro;
46 static uint_t mount_fmask;
47 static uint_t mount_dmask;
48 static BOOL use_kerberos;
49 /* TODO: Add code to detect smbfs version in kernel */
50 static BOOL status32_smbfs = False;
51
52 static void usage(void);
53
54 static void exit_parent(int sig)
55 {
56         /* parent simply exits when child says go... */
57         exit(0);
58 }
59
60 static void daemonize(void)
61 {
62         int j, status;
63         pid_t child_pid;
64
65         signal( SIGTERM, exit_parent );
66
67         if ((child_pid = sys_fork()) < 0) {
68                 DEBUG(0,("could not fork\n"));
69         }
70
71         if (child_pid > 0) {
72                 while( 1 ) {
73                         j = waitpid( child_pid, &status, 0 );
74                         if( j < 0 ) {
75                                 if( EINTR == errno ) {
76                                         continue;
77                                 }
78                                 status = errno;
79                         }
80                         break;
81                 }
82
83                 /* If we get here - the child exited with some error status */
84                 if (WIFSIGNALED(status))
85                         exit(128 + WTERMSIG(status));
86                 else
87                         exit(WEXITSTATUS(status));
88         }
89
90         signal( SIGTERM, SIG_DFL );
91         chdir("/");
92 }
93
94 static void close_our_files(int client_fd)
95 {
96         int i;
97         struct rlimit limits;
98
99         getrlimit(RLIMIT_NOFILE,&limits);
100         for (i = 0; i< limits.rlim_max; i++) {
101                 if (i == client_fd)
102                         continue;
103                 close(i);
104         }
105 }
106
107 static void usr1_handler(int x)
108 {
109         return;
110 }
111
112
113 /***************************************************** 
114 return a connection to a server
115 *******************************************************/
116 static struct smbcli_state *do_connection(char *the_service)
117 {
118         struct smbcli_state *c;
119         struct nmb_name called, calling;
120         char *server_n;
121         struct in_addr ip;
122         pstring server;
123         char *share;
124
125         if (the_service[0] != '\\' || the_service[1] != '\\') {
126                 usage();
127                 exit(1);
128         }
129
130         pstrcpy(server, the_service+2);
131         share = strchr_m(server,'\\');
132         if (!share) {
133                 usage();
134                 exit(1);
135         }
136         *share = 0;
137         share++;
138
139         server_n = server;
140
141         make_nmb_name(&calling, my_netbios_name, 0x0);
142         choose_called_name(&called, server, 0x20);
143
144  again:
145         zero_ip(&ip);
146         if (have_ip) ip = dest_ip;
147
148         /* have to open a new connection */
149         if (!(c=smbcli_initialise(NULL)) || (smbcli_set_port(c, smb_port) != smb_port) ||
150             !smbcli_connect(c, server_n, &ip)) {
151                 DEBUG(0,("%d: Connection to %s failed\n", sys_getpid(), server_n));
152                 if (c) {
153                         smbcli_shutdown(c);
154                 }
155                 return NULL;
156         }
157
158         /* SPNEGO doesn't work till we get NTSTATUS error support */
159         /* But it is REQUIRED for kerberos authentication */
160         if(!use_kerberos) c->use_spnego = False;
161
162         /* The kernel doesn't yet know how to sign it's packets */
163         c->sign_info.allow_smb_signing = False;
164
165         /* Use kerberos authentication if specified */
166         c->use_kerberos = use_kerberos;
167
168         if (!smbcli_session_request(c, &calling, &called)) {
169                 char *p;
170                 DEBUG(0,("%d: session request to %s failed (%s)\n", 
171                          sys_getpid(), called.name, smbcli_errstr(c)));
172                 smbcli_shutdown(c);
173                 if ((p=strchr_m(called.name, '.'))) {
174                         *p = 0;
175                         goto again;
176                 }
177                 if (strcmp(called.name, "*SMBSERVER")) {
178                         make_nmb_name(&called , "*SMBSERVER", 0x20);
179                         goto again;
180                 }
181                 return NULL;
182         }
183
184         DEBUG(4,("%d: session request ok\n", sys_getpid()));
185
186         if (!smbcli_negprot(c)) {
187                 DEBUG(0,("%d: protocol negotiation failed\n", sys_getpid()));
188                 smbcli_shutdown(c);
189                 return NULL;
190         }
191
192         if (!got_pass) {
193                 char *pass = getpass("Password: ");
194                 if (pass) {
195                         pstrcpy(password, pass);
196                 }
197         }
198
199         /* This should be right for current smbfs. Future versions will support
200           large files as well as unicode and oplocks. */
201         if (status32_smbfs) {
202             c->capabilities &= ~(CAP_UNICODE | CAP_LARGE_FILES | CAP_NT_SMBS |
203                                  CAP_NT_FIND | CAP_LEVEL_II_OPLOCKS);
204         }
205         else {
206             c->capabilities &= ~(CAP_UNICODE | CAP_LARGE_FILES | CAP_NT_SMBS |
207                                  CAP_NT_FIND | CAP_STATUS32 |
208                                  CAP_LEVEL_II_OPLOCKS);
209             c->force_dos_errors = True;
210         }
211
212         if (!smbcli_session_setup(c, username, 
213                                password, strlen(password),
214                                password, strlen(password),
215                                workgroup)) {
216                 /* if a password was not supplied then try again with a
217                         null username */
218                 if (password[0] || !username[0] ||
219                                 !smbcli_session_setup(c, "", "", 0, "", 0, workgroup)) {
220                         DEBUG(0,("%d: session setup failed: %s\n",
221                                 sys_getpid(), smbcli_errstr(c)));
222                         smbcli_shutdown(c);
223                         return NULL;
224                 }
225                 DEBUG(0,("Anonymous login successful\n"));
226         }
227
228         DEBUG(4,("%d: session setup ok\n", sys_getpid()));
229
230         if (!smbcli_send_tconX(c, share, "?????",
231                             password, strlen(password)+1)) {
232                 DEBUG(0,("%d: tree connect failed: %s\n",
233                          sys_getpid(), smbcli_errstr(c)));
234                 smbcli_shutdown(c);
235                 return NULL;
236         }
237
238         DEBUG(4,("%d: tconx ok\n", sys_getpid()));
239
240         got_pass = True;
241
242         return c;
243 }
244
245
246 /****************************************************************************
247 unmount smbfs  (this is a bailout routine to clean up if a reconnect fails)
248         Code blatently stolen from smbumount.c
249                 -mhw-
250 ****************************************************************************/
251 static void smb_umount(char *mount_point)
252 {
253         int fd;
254         struct mntent *mnt;
255         FILE* mtab;
256         FILE* new_mtab;
257
258         /* Programmers Note:
259                 This routine only gets called to the scene of a disaster
260                 to shoot the survivors...  A connection that was working
261                 has now apparently failed.  We have an active mount point
262                 (presumably) that we need to dump.  If we get errors along
263                 the way - make some noise, but we are already turning out
264                 the lights to exit anyways...
265         */
266         if (umount(mount_point) != 0) {
267                 DEBUG(0,("%d: Could not umount %s: %s\n",
268                          sys_getpid(), mount_point, strerror(errno)));
269                 return;
270         }
271
272         if ((fd = open(MOUNTED"~", O_RDWR|O_CREAT|O_EXCL, 0600)) == -1) {
273                 DEBUG(0,("%d: Can't get "MOUNTED"~ lock file", sys_getpid()));
274                 return;
275         }
276
277         close(fd);
278         
279         if ((mtab = setmntent(MOUNTED, "r")) == NULL) {
280                 DEBUG(0,("%d: Can't open " MOUNTED ": %s\n",
281                          sys_getpid(), strerror(errno)));
282                 return;
283         }
284
285 #define MOUNTED_TMP MOUNTED".tmp"
286
287         if ((new_mtab = setmntent(MOUNTED_TMP, "w")) == NULL) {
288                 DEBUG(0,("%d: Can't open " MOUNTED_TMP ": %s\n",
289                          sys_getpid(), strerror(errno)));
290                 endmntent(mtab);
291                 return;
292         }
293
294         while ((mnt = getmntent(mtab)) != NULL) {
295                 if (strcmp(mnt->mnt_dir, mount_point) != 0) {
296                         addmntent(new_mtab, mnt);
297                 }
298         }
299
300         endmntent(mtab);
301
302         if (fchmod (fileno (new_mtab), S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH) < 0) {
303                 DEBUG(0,("%d: Error changing mode of %s: %s\n",
304                          sys_getpid(), MOUNTED_TMP, strerror(errno)));
305                 return;
306         }
307
308         endmntent(new_mtab);
309
310         if (rename(MOUNTED_TMP, MOUNTED) < 0) {
311                 DEBUG(0,("%d: Cannot rename %s to %s: %s\n",
312                          sys_getpid(), MOUNTED, MOUNTED_TMP, strerror(errno)));
313                 return;
314         }
315
316         if (unlink(MOUNTED"~") == -1) {
317                 DEBUG(0,("%d: Can't remove "MOUNTED"~", sys_getpid()));
318                 return;
319         }
320 }
321
322
323 /*
324  * Call the smbfs ioctl to install a connection socket,
325  * then wait for a signal to reconnect. Note that we do
326  * not exit after open_sockets() or send_login() errors,
327  * as the smbfs mount would then have no way to recover.
328  */
329 static void send_fs_socket(char *the_service, char *mount_point, struct smbcli_state *c)
330 {
331         int fd, closed = 0, res = 1;
332         pid_t parentpid = getppid();
333         struct smb_conn_opt conn_options;
334
335         memset(&conn_options, 0, sizeof(conn_options));
336
337         while (1) {
338                 if ((fd = open(mount_point, O_RDONLY)) < 0) {
339                         DEBUG(0,("mount.smbfs[%d]: can't open %s\n",
340                                  sys_getpid(), mount_point));
341                         break;
342                 }
343
344                 conn_options.fd = c->fd;
345                 conn_options.protocol = c->protocol;
346                 conn_options.case_handling = SMB_CASE_DEFAULT;
347                 conn_options.max_xmit = c->max_xmit;
348                 conn_options.server_uid = c->vuid;
349                 conn_options.tid = c->cnum;
350                 conn_options.secmode = c->sec_mode;
351                 conn_options.rawmode = 0;
352                 conn_options.sesskey = c->sesskey;
353                 conn_options.maxraw = 0;
354                 conn_options.capabilities = c->capabilities;
355                 conn_options.serverzone = c->serverzone/60;
356
357                 res = ioctl(fd, SMB_IOC_NEWCONN, &conn_options);
358                 if (res != 0) {
359                         DEBUG(0,("mount.smbfs[%d]: ioctl failed, res=%d\n",
360                                  sys_getpid(), res));
361                         close(fd);
362                         break;
363                 }
364
365                 if (parentpid) {
366                         /* Ok...  We are going to kill the parent.  Now
367                                 is the time to break the process group... */
368                         setsid();
369                         /* Send a signal to the parent to terminate */
370                         kill(parentpid, SIGTERM);
371                         parentpid = 0;
372                 }
373
374                 close(fd);
375
376                 /* This looks wierd but we are only closing the userspace
377                    side, the connection has already been passed to smbfs and 
378                    it has increased the usage count on the socket.
379
380                    If we don't do this we will "leak" sockets and memory on
381                    each reconnection we have to make. */
382                 smbcli_shutdown(c);
383                 c = NULL;
384
385                 if (!closed) {
386                         /* redirect stdout & stderr since we can't know that
387                            the library functions we use are using DEBUG. */
388                         if ( (fd = open("/dev/null", O_WRONLY)) < 0)
389                                 DEBUG(2,("mount.smbfs: can't open /dev/null\n"));
390                         close_our_files(fd);
391                         if (fd >= 0) {
392                                 dup2(fd, STDOUT_FILENO);
393                                 dup2(fd, STDERR_FILENO);
394                                 close(fd);
395                         }
396
397                         /* here we are no longer interactive */
398                         set_remote_machine_name("smbmount");    /* sneaky ... */
399                         setup_logging("mount.smbfs", DEBUG_STDERR);
400                         reopen_logs();
401                         DEBUG(0, ("mount.smbfs: entering daemon mode for service %s, pid=%d\n", the_service, sys_getpid()));
402
403                         closed = 1;
404                 }
405
406                 /* Wait for a signal from smbfs ... but don't continue
407                    until we actually get a new connection. */
408                 while (!c) {
409                         CatchSignal(SIGUSR1, &usr1_handler);
410                         pause();
411                         DEBUG(2,("mount.smbfs[%d]: got signal, getting new socket\n", sys_getpid()));
412                         c = do_connection(the_service);
413                 }
414         }
415
416         smb_umount(mount_point);
417         DEBUG(2,("mount.smbfs[%d]: exit\n", sys_getpid()));
418         exit(1);
419 }
420
421
422 /**
423  * Mount a smbfs
424  **/
425 static void init_mount(void)
426 {
427         char mount_point[MAXPATHLEN+1];
428         pstring tmp;
429         pstring svc2;
430         struct smbcli_state *c;
431         char *args[20];
432         int i, status;
433
434         if (realpath(mpoint, mount_point) == NULL) {
435                 fprintf(stderr, "Could not resolve mount point %s\n", mpoint);
436                 return;
437         }
438
439
440         c = do_connection(service);
441         if (!c) {
442                 fprintf(stderr,"SMB connection failed\n");
443                 exit(1);
444         }
445
446         /*
447                 Set up to return as a daemon child and wait in the parent
448                 until the child say it's ready...
449         */
450         daemonize();
451
452         pstrcpy(svc2, service);
453         string_replace(svc2, '\\','/');
454         string_replace(svc2, ' ','_');
455
456         memset(args, 0, sizeof(args[0])*20);
457
458         i=0;
459         args[i++] = "smbmnt";
460
461         args[i++] = mount_point;
462         args[i++] = "-s";
463         args[i++] = svc2;
464
465         if (mount_ro) {
466                 args[i++] = "-r";
467         }
468         if (mount_uid) {
469                 slprintf(tmp, sizeof(tmp)-1, "%d", mount_uid);
470                 args[i++] = "-u";
471                 args[i++] = smb_xstrdup(tmp);
472         }
473         if (mount_gid) {
474                 slprintf(tmp, sizeof(tmp)-1, "%d", mount_gid);
475                 args[i++] = "-g";
476                 args[i++] = smb_xstrdup(tmp);
477         }
478         if (mount_fmask) {
479                 slprintf(tmp, sizeof(tmp)-1, "0%o", mount_fmask);
480                 args[i++] = "-f";
481                 args[i++] = smb_xstrdup(tmp);
482         }
483         if (mount_dmask) {
484                 slprintf(tmp, sizeof(tmp)-1, "0%o", mount_dmask);
485                 args[i++] = "-d";
486                 args[i++] = smb_xstrdup(tmp);
487         }
488         if (options) {
489                 args[i++] = "-o";
490                 args[i++] = options;
491         }
492
493         if (sys_fork() == 0) {
494                 char *smbmnt_path;
495
496                 asprintf(&smbmnt_path, "%s/smbmnt", dyn_BINDIR);
497                 
498                 if (file_exist(smbmnt_path, NULL)) {
499                         execv(smbmnt_path, args);
500                         fprintf(stderr,
501                                 "smbfs/init_mount: execv of %s failed. Error was %s.",
502                                 smbmnt_path, strerror(errno));
503                 } else {
504                         execvp("smbmnt", args);
505                         fprintf(stderr,
506                                 "smbfs/init_mount: execv of %s failed. Error was %s.",
507                                 "smbmnt", strerror(errno));
508                 }
509                 free(smbmnt_path);
510                 exit(1);
511         }
512
513         if (waitpid(-1, &status, 0) == -1) {
514                 fprintf(stderr,"waitpid failed: Error was %s", strerror(errno) );
515                 /* FIXME: do some proper error handling */
516                 exit(1);
517         }
518
519         if (WIFEXITED(status) && WEXITSTATUS(status) != 0) {
520                 fprintf(stderr,"smbmnt failed: %d\n", WEXITSTATUS(status));
521                 /* FIXME: do some proper error handling */
522                 exit(1);
523         } else if (WIFSIGNALED(status)) {
524                 fprintf(stderr, "smbmnt killed by signal %d\n", WTERMSIG(status));
525                 exit(1);
526         }
527
528         /* Ok...  This is the rubicon for that mount point...  At any point
529            after this, if the connections fail and can not be reconstructed
530            for any reason, we will have to unmount the mount point.  There
531            is no exit from the next call...
532         */
533         send_fs_socket(service, mount_point, c);
534 }
535
536
537 /****************************************************************************
538 get a password from a a file or file descriptor
539 exit on failure (from smbclient, move to libsmb or shared .c file?)
540 ****************************************************************************/
541 static void get_password_file(void)
542 {
543         int fd = -1;
544         char *p;
545         BOOL close_it = False;
546         pstring spec;
547         char pass[128];
548
549         if ((p = getenv("PASSWD_FD")) != NULL) {
550                 pstrcpy(spec, "descriptor ");
551                 pstrcat(spec, p);
552                 sscanf(p, "%d", &fd);
553                 close_it = False;
554         } else if ((p = getenv("PASSWD_FILE")) != NULL) {
555                 fd = sys_open(p, O_RDONLY, 0);
556                 pstrcpy(spec, p);
557                 if (fd < 0) {
558                         fprintf(stderr, "Error opening PASSWD_FILE %s: %s\n",
559                                 spec, strerror(errno));
560                         exit(1);
561                 }
562                 close_it = True;
563         }
564
565         for(p = pass, *p = '\0'; /* ensure that pass is null-terminated */
566             p && p - pass < sizeof(pass);) {
567                 switch (read(fd, p, 1)) {
568                 case 1:
569                         if (*p != '\n' && *p != '\0') {
570                                 *++p = '\0'; /* advance p, and null-terminate pass */
571                                 break;
572                         }
573                 case 0:
574                         if (p - pass) {
575                                 *p = '\0'; /* null-terminate it, just in case... */
576                                 p = NULL; /* then force the loop condition to become false */
577                                 break;
578                         } else {
579                                 fprintf(stderr, "Error reading password from file %s: %s\n",
580                                         spec, "empty password\n");
581                                 exit(1);
582                         }
583
584                 default:
585                         fprintf(stderr, "Error reading password from file %s: %s\n",
586                                 spec, strerror(errno));
587                         exit(1);
588                 }
589         }
590         pstrcpy(password, pass);
591         if (close_it)
592                 close(fd);
593 }
594
595 /****************************************************************************
596 get username and password from a credentials file
597 exit on failure (from smbclient, move to libsmb or shared .c file?)
598 ****************************************************************************/
599 static void read_credentials_file(char *filename)
600 {
601         FILE *auth;
602         fstring buf;
603         uint16_t len = 0;
604         char *ptr, *val, *param;
605
606         if ((auth=sys_fopen(filename, "r")) == NULL)
607         {
608                 /* fail if we can't open the credentials file */
609                 DEBUG(0,("ERROR: Unable to open credentials file!\n"));
610                 exit (-1);
611         }
612
613         while (!feof(auth))
614         {
615                 /* get a line from the file */
616                 if (!fgets (buf, sizeof(buf), auth))
617                         continue;
618                 len = strlen(buf);
619
620                 if ((len) && (buf[len-1]=='\n'))
621                 {
622                         buf[len-1] = '\0';
623                         len--;
624                 }
625                 if (len == 0)
626                         continue;
627
628                 /* break up the line into parameter & value.
629                    will need to eat a little whitespace possibly */
630                 param = buf;
631                 if (!(ptr = strchr (buf, '=')))
632                         continue;
633                 val = ptr+1;
634                 *ptr = '\0';
635
636                 /* eat leading white space */
637                 while ((*val!='\0') && ((*val==' ') || (*val=='\t')))
638                         val++;
639
640                 if (strwicmp("password", param) == 0)
641                 {
642                         pstrcpy(password, val);
643                         got_pass = True;
644                 }
645                 else if (strwicmp("username", param) == 0) {
646                         pstrcpy(username, val);
647                 }
648
649                 memset(buf, 0, sizeof(buf));
650         }
651         fclose(auth);
652 }
653
654
655 /****************************************************************************
656 usage on the program
657 ****************************************************************************/
658 static void usage(void)
659 {
660         printf("Usage: mount.smbfs service mountpoint [-o options,...]\n");
661
662         printf("Version %s\n\n",VERSION);
663
664         printf(
665 "Options:\n\
666       username=<arg>                  SMB username\n\
667       password=<arg>                  SMB password\n\
668       credentials=<filename>          file with username/password\n\
669       krb                             use kerberos (active directory)\n\
670       netbiosname=<arg>               source NetBIOS name\n\
671       uid=<arg>                       mount uid or username\n\
672       gid=<arg>                       mount gid or groupname\n\
673       port=<arg>                      remote SMB port number\n\
674       fmask=<arg>                     file umask\n\
675       dmask=<arg>                     directory umask\n\
676       debug=<arg>                     debug level\n\
677       ip=<arg>                        destination host or IP address\n\
678       workgroup=<arg>                 workgroup on destination\n\
679       sockopt=<arg>                   TCP socket options\n\
680       scope=<arg>                     NetBIOS scope\n\
681       iocharset=<arg>                 Linux charset (iso8859-1, utf8)\n\
682       codepage=<arg>                  server codepage (cp850)\n\
683       ttl=<arg>                       dircache time to live\n\
684       guest                           don't prompt for a password\n\
685       ro                              mount read-only\n\
686       rw                              mount read-write\n\
687 \n\
688 This command is designed to be run from within /bin/mount by giving\n\
689 the option '-t smbfs'. For example:\n\
690   mount -t smbfs -o username=tridge,password=foobar //fjall/test /data/test\n\
691 ");
692 }
693
694
695 /****************************************************************************
696   Argument parsing for mount.smbfs interface
697   mount will call us like this:
698     mount.smbfs device mountpoint -o <options>
699   
700   <options> is never empty, containing at least rw or ro
701  ****************************************************************************/
702 static void parse_mount_smb(int argc, char **argv)
703 {
704         int opt;
705         char *opts;
706         char *opteq;
707         extern char *optarg;
708         int val;
709         char *p;
710
711         /* FIXME: This function can silently fail if the arguments are
712          * not in the expected order.
713
714         > The arguments syntax of smbmount 2.2.3a (smbfs of Debian stable)
715         > requires that one gives "-o" before further options like username=...
716         > . Without -o, the username=.. setting is *silently* ignored. I've
717         > spent about an hour trying to find out why I couldn't log in now..
718
719         */
720
721
722         if (argc < 2 || argv[1][0] == '-') {
723                 usage();
724                 exit(1);
725         }
726         
727         pstrcpy(service, argv[1]);
728         pstrcpy(mpoint, argv[2]);
729
730         /* Convert any '/' characters in the service name to
731            '\' characters */
732         string_replace(service, '/','\\');
733         argc -= 2;
734         argv += 2;
735
736         opt = getopt(argc, argv, "o:");
737         if(opt != 'o') {
738                 return;
739         }
740
741         options[0] = 0;
742         p = options;
743
744         /*
745          * option parsing from nfsmount.c (util-linux-2.9u)
746          */
747         for (opts = strtok(optarg, ","); opts; opts = strtok(NULL, ",")) {
748                 DEBUG(3, ("opts: %s\n", opts));
749                 if ((opteq = strchr_m(opts, '='))) {
750                         val = atoi(opteq + 1);
751                         *opteq = '\0';
752
753                         if (!strcmp(opts, "username") || 
754                             !strcmp(opts, "logon")) {
755                                 char *lp;
756                                 got_user = True;
757                                 pstrcpy(username,opteq+1);
758                                 if ((lp=strchr_m(username,'%'))) {
759                                         *lp = 0;
760                                         pstrcpy(password,lp+1);
761                                         got_pass = True;
762                                         memset(strchr_m(opteq+1,'%')+1,'X',strlen(password));
763                                 }
764                                 if ((lp=strchr_m(username,'/'))) {
765                                         *lp = 0;
766                                         pstrcpy(workgroup,lp+1);
767                                 }
768                         } else if(!strcmp(opts, "passwd") ||
769                                   !strcmp(opts, "password")) {
770                                 pstrcpy(password,opteq+1);
771                                 got_pass = True;
772                                 memset(opteq+1,'X',strlen(password));
773                         } else if(!strcmp(opts, "credentials")) {
774                                 pstrcpy(credentials,opteq+1);
775                         } else if(!strcmp(opts, "netbiosname")) {
776                                 pstrcpy(my_netbios_name,opteq+1);
777                         } else if(!strcmp(opts, "uid")) {
778                                 mount_uid = nametouid(opteq+1);
779                         } else if(!strcmp(opts, "gid")) {
780                                 mount_gid = nametogid(opteq+1);
781                         } else if(!strcmp(opts, "port")) {
782                                 smb_port = val;
783                         } else if(!strcmp(opts, "fmask")) {
784                                 mount_fmask = strtol(opteq+1, NULL, 8);
785                         } else if(!strcmp(opts, "dmask")) {
786                                 mount_dmask = strtol(opteq+1, NULL, 8);
787                         } else if(!strcmp(opts, "debug")) {
788                                 DEBUGLEVEL = val;
789                         } else if(!strcmp(opts, "ip")) {
790                                 dest_ip = *interpret_addr2(opteq+1);
791                                 if (is_zero_ip(dest_ip)) {
792                                         fprintf(stderr,"Can't resolve address %s\n", opteq+1);
793                                         exit(1);
794                                 }
795                                 have_ip = True;
796                         } else if(!strcmp(opts, "workgroup")) {
797                                 pstrcpy(workgroup,opteq+1);
798                         } else if(!strcmp(opts, "sockopt")) {
799                                 lp_set_cmdline("socket options", opteq+1);
800                         } else if(!strcmp(opts, "scope")) {
801                                 lp_set_cmdline("netbios scope", opteq+1);
802                         } else {
803                                 slprintf(p, sizeof(pstring) - (p - options) - 1, "%s=%s,", opts, opteq+1);
804                                 p += strlen(p);
805                         }
806                 } else {
807                         val = 1;
808                         if(!strcmp(opts, "nocaps")) {
809                                 fprintf(stderr, "Unhandled option: %s\n", opteq+1);
810                                 exit(1);
811                         } else if(!strcmp(opts, "guest")) {
812                                 *password = '\0';
813                                 got_pass = True;
814                         } else if(!strcmp(opts, "krb")) {
815 #ifdef HAVE_KRB5
816
817                                 use_kerberos = True;
818                                 if(!status32_smbfs)
819                                         fprintf(stderr, "Warning: kerberos support will only work for samba servers\n");
820 #else
821                                 fprintf(stderr,"No kerberos support compiled in\n");
822                                 exit(1);
823 #endif
824                         } else if(!strcmp(opts, "rw")) {
825                                 mount_ro = 0;
826                         } else if(!strcmp(opts, "ro")) {
827                                 mount_ro = 1;
828                         } else {
829                                 strncpy(p, opts, sizeof(pstring) - (p - options) - 1);
830                                 p += strlen(opts);
831                                 *p++ = ',';
832                                 *p = 0;
833                         }
834                 }
835         }
836
837         if (!*service) {
838                 usage();
839                 exit(1);
840         }
841
842         if (p != options) {
843                 *(p-1) = 0;     /* remove trailing , */
844                 DEBUG(3,("passthrough options '%s'\n", options));
845         }
846 }
847
848 /****************************************************************************
849   main program
850 ****************************************************************************/
851  int main(int argc,char *argv[])
852 {
853         extern char *optarg;
854         extern int optind;
855         char *p;
856
857         DEBUGLEVEL = 1;
858
859         /* here we are interactive, even if run from autofs */
860         setup_logging("mount.smbfs",DEBUG_STDERR);
861
862 #if 0 /* JRA - Urban says not needed ? */
863         /* CLI_FORCE_ASCII=false makes smbmount negotiate unicode. The default
864            is to not announce any unicode capabilities as current smbfs does
865            not support it. */
866         p = getenv("CLI_FORCE_ASCII");
867         if (p && !strcmp(p, "false"))
868                 unsetenv("CLI_FORCE_ASCII");
869         else
870                 setenv("CLI_FORCE_ASCII", "true", 1);
871 #endif
872
873         in_client = True;   /* Make sure that we tell lp_load we are */
874
875         if (getenv("USER")) {
876                 pstrcpy(username,getenv("USER"));
877
878                 if ((p=strchr_m(username,'%'))) {
879                         *p = 0;
880                         pstrcpy(password,p+1);
881                         got_pass = True;
882                         memset(strchr_m(getenv("USER"),'%')+1,'X',strlen(password));
883                 }
884                 strupper(username);
885         }
886
887         if (getenv("PASSWD")) {
888                 pstrcpy(password,getenv("PASSWD"));
889                 got_pass = True;
890         }
891
892         if (getenv("PASSWD_FD") || getenv("PASSWD_FILE")) {
893                 get_password_file();
894                 got_pass = True;
895         }
896
897         if (*username == 0 && getenv("LOGNAME")) {
898                 pstrcpy(username,getenv("LOGNAME"));
899         }
900
901         if (!lp_load(dyn_CONFIGFILE,True,False,False)) {
902                 fprintf(stderr, "Can't load %s - run testparm to debug it\n", 
903                         dyn_CONFIGFILE);
904         }
905
906         parse_mount_smb(argc, argv);
907
908         if (use_kerberos && !got_user) {
909                 got_pass = True;
910         }
911
912         if (*credentials != 0) {
913                 read_credentials_file(credentials);
914         }
915
916         DEBUG(3,("mount.smbfs started (version %s)\n", VERSION));
917
918         if (*workgroup == 0) {
919                 pstrcpy(workgroup,lp_workgroup());
920         }
921
922         load_interfaces();
923         if (!*my_netbios_name) {
924                 pstrcpy(my_netbios_name, myhostname());
925         }
926         strupper(my_netbios_name);
927
928         init_mount();
929         return 0;
930 }