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