Merge branch 'v4-0-local' of git://git.id10ts.net/samba into v4-0-gmake3
[tprouty/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 static pstring credentials;
28 static pstring my_netbios_name;
29 static pstring password;
30 static pstring username;
31 static pstring workgroup;
32 static pstring mpoint;
33 static pstring service;
34 static pstring options;
35
36 static struct in_addr dest_ip;
37 static bool have_ip;
38 static int smb_port = 0;
39 static bool got_user;
40 static bool got_pass;
41 static uid_t mount_uid;
42 static gid_t mount_gid;
43 static int mount_ro;
44 static uint_t mount_fmask;
45 static uint_t mount_dmask;
46 static bool use_kerberos;
47 /* TODO: Add code to detect smbfs version in kernel */
48 static bool status32_smbfs = false;
49
50 static void usage(void);
51
52 static void exit_parent(int sig)
53 {
54         /* parent simply exits when child says go... */
55         exit(0);
56 }
57
58 static void daemonize(void)
59 {
60         int j, status;
61         pid_t child_pid;
62
63         signal( SIGTERM, exit_parent );
64
65         if ((child_pid = sys_fork()) < 0) {
66                 DEBUG(0,("could not fork\n"));
67         }
68
69         if (child_pid > 0) {
70                 while( 1 ) {
71                         j = waitpid( child_pid, &status, 0 );
72                         if( j < 0 ) {
73                                 if( EINTR == errno ) {
74                                         continue;
75                                 }
76                                 status = errno;
77                         }
78                         break;
79                 }
80
81                 /* If we get here - the child exited with some error status */
82                 if (WIFSIGNALED(status))
83                         exit(128 + WTERMSIG(status));
84                 else
85                         exit(WEXITSTATUS(status));
86         }
87
88         signal( SIGTERM, SIG_DFL );
89         chdir("/");
90 }
91
92 static void close_our_files(int client_fd)
93 {
94         int i;
95         struct rlimit limits;
96
97         getrlimit(RLIMIT_NOFILE,&limits);
98         for (i = 0; i< limits.rlim_max; i++) {
99                 if (i == client_fd)
100                         continue;
101                 close(i);
102         }
103 }
104
105 static void usr1_handler(int x)
106 {
107         return;
108 }
109
110
111 /***************************************************** 
112 return a connection to a server
113 *******************************************************/
114 static struct smbcli_state *do_connection(const char *the_service, bool unicode, int maxprotocol)
115 {
116         struct smbcli_state *c;
117         struct nmb_name called, calling;
118         char *server_n;
119         struct in_addr ip;
120         pstring server;
121         char *share;
122
123         if (the_service[0] != '\\' || the_service[1] != '\\') {
124                 usage();
125                 exit(1);
126         }
127
128         pstrcpy(server, the_service+2);
129         share = strchr_m(server,'\\');
130         if (!share) {
131                 usage();
132                 exit(1);
133         }
134         *share = 0;
135         share++;
136
137         server_n = server;
138
139         make_nmb_name(&calling, my_netbios_name, 0x0);
140         choose_called_name(&called, server, 0x20);
141
142  again:
143         zero_ip(&ip);
144         if (have_ip) ip = dest_ip;
145
146         /* have to open a new connection */
147         if (!(c=smbcli_initialise(NULL)) || (smbcli_set_port(c, smb_port) != smb_port) ||
148             !smbcli_connect(c, server_n, &ip)) {
149                 DEBUG(0,("%d: Connection to %s failed\n", sys_getpid(), server_n));
150                 if (c) {
151                         talloc_free(c);
152                 }
153                 return NULL;
154         }
155
156         /* SPNEGO doesn't work till we get NTSTATUS error support */
157         /* But it is REQUIRED for kerberos authentication */
158         if(!use_kerberos) c->use_spnego = false;
159
160         /* The kernel doesn't yet know how to sign it's packets */
161         c->sign_info.allow_smb_signing = false;
162
163         /* Use kerberos authentication if specified */
164         c->use_kerberos = use_kerberos;
165
166         if (!smbcli_session_request(c, &calling, &called)) {
167                 char *p;
168                 DEBUG(0,("%d: session request to %s failed (%s)\n", 
169                          sys_getpid(), called.name, smbcli_errstr(c)));
170                 talloc_free(c);
171                 if ((p=strchr_m(called.name, '.'))) {
172                         *p = 0;
173                         goto again;
174                 }
175                 if (strcmp(called.name, "*SMBSERVER")) {
176                         make_nmb_name(&called , "*SMBSERVER", 0x20);
177                         goto again;
178                 }
179                 return NULL;
180         }
181
182         DEBUG(4,("%d: session request ok\n", sys_getpid()));
183
184         if (!smbcli_negprot(c, unicode, maxprotocol)) {
185                 DEBUG(0,("%d: protocol negotiation failed\n", sys_getpid()));
186                 talloc_free(c);
187                 return NULL;
188         }
189
190         if (!got_pass) {
191                 char *pass = getpass("Password: ");
192                 if (pass) {
193                         pstrcpy(password, pass);
194                 }
195         }
196
197         /* This should be right for current smbfs. Future versions will support
198           large files as well as unicode and oplocks. */
199         if (status32_smbfs) {
200             c->capabilities &= ~(CAP_UNICODE | CAP_LARGE_FILES | CAP_NT_SMBS |
201                                  CAP_NT_FIND | CAP_LEVEL_II_OPLOCKS);
202         }
203         else {
204             c->capabilities &= ~(CAP_UNICODE | CAP_LARGE_FILES | CAP_NT_SMBS |
205                                  CAP_NT_FIND | CAP_STATUS32 |
206                                  CAP_LEVEL_II_OPLOCKS);
207             c->force_dos_errors = true;
208         }
209
210         if (!smbcli_session_setup(c, username, 
211                                password, strlen(password),
212                                password, strlen(password),
213                                workgroup)) {
214                 /* if a password was not supplied then try again with a
215                         null username */
216                 if (password[0] || !username[0] ||
217                                 !smbcli_session_setup(c, "", "", 0, "", 0, workgroup)) {
218                         DEBUG(0,("%d: session setup failed: %s\n",
219                                 sys_getpid(), smbcli_errstr(c)));
220                         talloc_free(c);
221                         return NULL;
222                 }
223                 DEBUG(0,("Anonymous login successful\n"));
224         }
225
226         DEBUG(4,("%d: session setup ok\n", sys_getpid()));
227
228         if (!smbcli_tconX(c, share, "?????", password, strlen(password)+1)) {
229                 DEBUG(0,("%d: tree connect failed: %s\n",
230                          sys_getpid(), smbcli_errstr(c)));
231                 talloc_free(c);
232                 return NULL;
233         }
234
235         DEBUG(4,("%d: tconx ok\n", sys_getpid()));
236
237         got_pass = true;
238
239         return c;
240 }
241
242
243 /****************************************************************************
244 unmount smbfs  (this is a bailout routine to clean up if a reconnect fails)
245         Code blatently stolen from smbumount.c
246                 -mhw-
247 ****************************************************************************/
248 static void smb_umount(const char *mount_point)
249 {
250         int fd;
251         struct mntent *mnt;
252         FILE* mtab;
253         FILE* new_mtab;
254
255         /* Programmers Note:
256                 This routine only gets called to the scene of a disaster
257                 to shoot the survivors...  A connection that was working
258                 has now apparently failed.  We have an active mount point
259                 (presumably) that we need to dump.  If we get errors along
260                 the way - make some noise, but we are already turning out
261                 the lights to exit anyways...
262         */
263         if (umount(mount_point) != 0) {
264                 DEBUG(0,("%d: Could not umount %s: %s\n",
265                          sys_getpid(), mount_point, strerror(errno)));
266                 return;
267         }
268
269         if ((fd = open(MOUNTED"~", O_RDWR|O_CREAT|O_EXCL, 0600)) == -1) {
270                 DEBUG(0,("%d: Can't get "MOUNTED"~ lock file", sys_getpid()));
271                 return;
272         }
273
274         close(fd);
275         
276         if ((mtab = setmntent(MOUNTED, "r")) == NULL) {
277                 DEBUG(0,("%d: Can't open " MOUNTED ": %s\n",
278                          sys_getpid(), strerror(errno)));
279                 return;
280         }
281
282 #define MOUNTED_TMP MOUNTED".tmp"
283
284         if ((new_mtab = setmntent(MOUNTED_TMP, "w")) == NULL) {
285                 DEBUG(0,("%d: Can't open " MOUNTED_TMP ": %s\n",
286                          sys_getpid(), strerror(errno)));
287                 endmntent(mtab);
288                 return;
289         }
290
291         while ((mnt = getmntent(mtab)) != NULL) {
292                 if (strcmp(mnt->mnt_dir, mount_point) != 0) {
293                         addmntent(new_mtab, mnt);
294                 }
295         }
296
297         endmntent(mtab);
298
299         if (fchmod (fileno (new_mtab), S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH) < 0) {
300                 DEBUG(0,("%d: Error changing mode of %s: %s\n",
301                          sys_getpid(), MOUNTED_TMP, strerror(errno)));
302                 return;
303         }
304
305         endmntent(new_mtab);
306
307         if (rename(MOUNTED_TMP, MOUNTED) < 0) {
308                 DEBUG(0,("%d: Cannot rename %s to %s: %s\n",
309                          sys_getpid(), MOUNTED, MOUNTED_TMP, strerror(errno)));
310                 return;
311         }
312
313         if (unlink(MOUNTED"~") == -1) {
314                 DEBUG(0,("%d: Can't remove "MOUNTED"~", sys_getpid()));
315                 return;
316         }
317 }
318
319
320 /*
321  * Call the smbfs ioctl to install a connection socket,
322  * then wait for a signal to reconnect. Note that we do
323  * not exit after open_sockets() or send_login() errors,
324  * as the smbfs mount would then have no way to recover.
325  */
326 static void send_fs_socket(struct loadparm_context *lp_ctx,
327                            const char *the_service, const char *mount_point, struct smbcli_state *c)
328 {
329         int fd, closed = 0, res = 1;
330         pid_t parentpid = getppid();
331         struct smb_conn_opt conn_options;
332
333         memset(&conn_options, 0, sizeof(conn_options));
334
335         while (1) {
336                 if ((fd = open(mount_point, O_RDONLY)) < 0) {
337                         DEBUG(0,("mount.smbfs[%d]: can't open %s\n",
338                                  sys_getpid(), mount_point));
339                         break;
340                 }
341
342                 conn_options.fd = c->fd;
343                 conn_options.protocol = c->protocol;
344                 conn_options.case_handling = SMB_CASE_DEFAULT;
345                 conn_options.max_xmit = c->max_xmit;
346                 conn_options.server_uid = c->vuid;
347                 conn_options.tid = c->cnum;
348                 conn_options.secmode = c->sec_mode;
349                 conn_options.rawmode = 0;
350                 conn_options.sesskey = c->sesskey;
351                 conn_options.maxraw = 0;
352                 conn_options.capabilities = c->capabilities;
353                 conn_options.serverzone = c->serverzone/60;
354
355                 res = ioctl(fd, SMB_IOC_NEWCONN, &conn_options);
356                 if (res != 0) {
357                         DEBUG(0,("mount.smbfs[%d]: ioctl failed, res=%d\n",
358                                  sys_getpid(), res));
359                         close(fd);
360                         break;
361                 }
362
363                 if (parentpid) {
364                         /* Ok...  We are going to kill the parent.  Now
365                                 is the time to break the process group... */
366                         setsid();
367                         /* Send a signal to the parent to terminate */
368                         kill(parentpid, SIGTERM);
369                         parentpid = 0;
370                 }
371
372                 close(fd);
373
374                 /* This looks wierd but we are only closing the userspace
375                    side, the connection has already been passed to smbfs and 
376                    it has increased the usage count on the socket.
377
378                    If we don't do this we will "leak" sockets and memory on
379                    each reconnection we have to make. */
380                 talloc_free(c);
381                 c = NULL;
382
383                 if (!closed) {
384                         /* redirect stdout & stderr since we can't know that
385                            the library functions we use are using DEBUG. */
386                         if ( (fd = open("/dev/null", O_WRONLY)) < 0)
387                                 DEBUG(2,("mount.smbfs: can't open /dev/null\n"));
388                         close_our_files(fd);
389                         if (fd >= 0) {
390                                 dup2(fd, STDOUT_FILENO);
391                                 dup2(fd, STDERR_FILENO);
392                                 close(fd);
393                         }
394
395                         /* here we are no longer interactive */
396                         set_remote_machine_name("smbmount");    /* sneaky ... */
397                         setup_logging("mount.smbfs", DEBUG_STDERR);
398                         reopen_logs();
399                         DEBUG(0, ("mount.smbfs: entering daemon mode for service %s, pid=%d\n", the_service, sys_getpid()));
400
401                         closed = 1;
402                 }
403
404                 /* Wait for a signal from smbfs ... but don't continue
405                    until we actually get a new connection. */
406                 while (!c) {
407                         CatchSignal(SIGUSR1, &usr1_handler);
408                         pause();
409                         DEBUG(2,("mount.smbfs[%d]: got signal, getting new socket\n", sys_getpid()));
410                         c = do_connection(the_service, 
411                                           lp_unicode(lp_ctx), 
412                                           lp_cli_maxprotocol(lp_ctx));
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(struct loadparm_context *lp_ctx)
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, lp_unicode(lp_ctx), lp_cli_maxprotocol(lp_ctx));
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)) {
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(lp_ctx, 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 = 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         struct loadparm_context *lp_ctx;
857
858         DEBUGLEVEL = 1;
859
860         /* here we are interactive, even if run from autofs */
861         setup_logging("mount.smbfs",DEBUG_STDERR);
862
863 #if 0 /* JRA - Urban says not needed ? */
864         /* CLI_FORCE_ASCII=false makes smbmount negotiate unicode. The default
865            is to not announce any unicode capabilities as current smbfs does
866            not support it. */
867         p = getenv("CLI_FORCE_ASCII");
868         if (p && !strcmp(p, "false"))
869                 unsetenv("CLI_FORCE_ASCII");
870         else
871                 setenv("CLI_FORCE_ASCII", "true", 1);
872 #endif
873
874         if (getenv("USER")) {
875                 pstrcpy(username,getenv("USER"));
876
877                 if ((p=strchr_m(username,'%'))) {
878                         *p = 0;
879                         pstrcpy(password,p+1);
880                         got_pass = true;
881                         memset(strchr_m(getenv("USER"),'%')+1,'X',strlen(password));
882                 }
883                 strupper(username);
884         }
885
886         if (getenv("PASSWD")) {
887                 pstrcpy(password, getenv("PASSWD"));
888                 got_pass = true;
889         }
890
891         if (getenv("PASSWD_FD") || getenv("PASSWD_FILE")) {
892                 get_password_file();
893                 got_pass = true;
894         }
895
896         if (*username == 0 && getenv("LOGNAME")) {
897                 pstrcpy(username,getenv("LOGNAME"));
898         }
899
900         lp_ctx = loadparm_init(talloc_autofree_context());
901
902         if (!lp_load(lp_ctx, dyn_CONFIGFILE)) {
903                 fprintf(stderr, "Can't load %s - run testparm to debug it\n", 
904                         lp_config_file());
905         }
906
907         parse_mount_smb(argc, argv);
908
909         if (use_kerberos && !got_user) {
910                 got_pass = true;
911         }
912
913         if (*credentials != 0) {
914                 read_credentials_file(credentials);
915         }
916
917         DEBUG(3,("mount.smbfs started (version %s)\n", VERSION));
918
919         if (*workgroup == 0) {
920                 pstrcpy(workgroup, lp_workgroup());
921         }
922
923         if (!*my_netbios_name) {
924                 pstrcpy(my_netbios_name, myhostname());
925         }
926         strupper(my_netbios_name);
927
928         init_mount(lp_ctx);
929         return 0;
930 }