root/source4/client/smbmount.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. exit_parent
  2. daemonize
  3. close_our_files
  4. usr1_handler
  5. do_connection
  6. smb_umount
  7. send_fs_socket
  8. init_mount
  9. get_password_file
  10. read_credentials_file
  11. usage
  12. parse_mount_smb
  13. 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 }

/* [<][>][^][v][top][bottom][index][help] */