/* [<][>][^][v][top][bottom][index][help] */
DEFINITIONS
This source file includes following definitions.
- exit_parent
- daemonize
- close_our_files
- usr1_handler
- do_connection
- smb_umount
- send_fs_socket
- init_mount
- get_password_file
- read_credentials_file
- usage
- parse_mount_smb
- main
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)
/* [<][>][^][v][top][bottom][index][help] */
56 {
57 /* parent simply exits when child says go... */
58 exit(0);
59 }
60
61 static void daemonize(void)
/* [<][>][^][v][top][bottom][index][help] */
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)
/* [<][>][^][v][top][bottom][index][help] */
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)
/* [<][>][^][v][top][bottom][index][help] */
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,
/* [<][>][^][v][top][bottom][index][help] */
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)
/* [<][>][^][v][top][bottom][index][help] */
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,
/* [<][>][^][v][top][bottom][index][help] */
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)
/* [<][>][^][v][top][bottom][index][help] */
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)
/* [<][>][^][v][top][bottom][index][help] */
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)
/* [<][>][^][v][top][bottom][index][help] */
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)
/* [<][>][^][v][top][bottom][index][help] */
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)
/* [<][>][^][v][top][bottom][index][help] */
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[])
/* [<][>][^][v][top][bottom][index][help] */
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 }