root/source3/client/mount.cifs.c

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

DEFINITIONS

This source file includes following definitions.
  1. strlcpy
  2. strlcat
  3. mount_cifs_usage
  4. getusername
  5. open_cred_file
  6. get_password_from_file
  7. parse_options
  8. check_for_comma
  9. check_for_domain
  10. replace_char
  11. parse_server
  12. uppercase_string
  13. print_cifs_mount_version
  14. check_newline
  15. check_mtab
  16. main

   1 /* 
   2    Mount helper utility for Linux CIFS VFS (virtual filesystem) client
   3    Copyright (C) 2003,2008 Steve French  (sfrench@us.ibm.com)
   4    Copyright (C) 2008 Jeremy Allison (jra@samba.org)
   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 #ifndef _GNU_SOURCE
  20 #define _GNU_SOURCE
  21 #endif
  22 
  23 #include <stdlib.h>
  24 #include <stdio.h>
  25 #include <unistd.h>
  26 #include <pwd.h>
  27 #include <grp.h>
  28 #include <ctype.h>
  29 #include <sys/types.h>
  30 #include <sys/mount.h>
  31 #include <sys/stat.h>
  32 #include <sys/utsname.h>
  33 #include <sys/socket.h>
  34 #include <arpa/inet.h>
  35 #include <getopt.h>
  36 #include <errno.h>
  37 #include <netdb.h>
  38 #include <string.h>
  39 #include <mntent.h>
  40 #include <fcntl.h>
  41 #include <limits.h>
  42 #include "mount.h"
  43 
  44 #define MOUNT_CIFS_VERSION_MAJOR "1"
  45 #define MOUNT_CIFS_VERSION_MINOR "12"
  46 
  47 #ifndef MOUNT_CIFS_VENDOR_SUFFIX
  48  #ifdef _SAMBA_BUILD_
  49   #include "include/version.h"
  50   #ifdef SAMBA_VERSION_VENDOR_SUFFIX
  51    #define MOUNT_CIFS_VENDOR_SUFFIX "-"SAMBA_VERSION_OFFICIAL_STRING"-"SAMBA_VERSION_VENDOR_SUFFIX
  52   #else
  53    #define MOUNT_CIFS_VENDOR_SUFFIX "-"SAMBA_VERSION_OFFICIAL_STRING
  54   #endif /* SAMBA_VERSION_OFFICIAL_STRING and SAMBA_VERSION_VENDOR_SUFFIX */
  55  #else
  56    #define MOUNT_CIFS_VENDOR_SUFFIX ""
  57  #endif /* _SAMBA_BUILD_ */
  58 #endif /* MOUNT_CIFS_VENDOR_SUFFIX */
  59 
  60 #ifdef _SAMBA_BUILD_
  61 #include "include/config.h"
  62 #endif
  63 
  64 #ifndef MS_MOVE 
  65 #define MS_MOVE 8192 
  66 #endif 
  67 
  68 #ifndef MS_BIND
  69 #define MS_BIND 4096
  70 #endif
  71 
  72 #define MAX_UNC_LEN 1024
  73 
  74 #define CONST_DISCARD(type, ptr)      ((type) ((void *) (ptr)))
  75 
  76 #ifndef SAFE_FREE
  77 #define SAFE_FREE(x) do { if ((x) != NULL) {free(x); x=NULL;} } while(0)
  78 #endif
  79 
  80 #define MOUNT_PASSWD_SIZE 64
  81 #define DOMAIN_SIZE 64
  82 
  83 /* currently maximum length of IPv6 address string */
  84 #define MAX_ADDRESS_LEN INET6_ADDRSTRLEN
  85 
  86 const char *thisprogram;
  87 int verboseflag = 0;
  88 int fakemnt = 0;
  89 static int got_password = 0;
  90 static int got_user = 0;
  91 static int got_domain = 0;
  92 static int got_ip = 0;
  93 static int got_unc = 0;
  94 static int got_uid = 0;
  95 static int got_gid = 0;
  96 static char * user_name = NULL;
  97 static char * mountpassword = NULL;
  98 char * domain_name = NULL;
  99 char * prefixpath = NULL;
 100 
 101 /* glibc doesn't have strlcpy, strlcat. Ensure we do. JRA. We
 102  * don't link to libreplace so need them here. */
 103 
 104 /* like strncpy but does not 0 fill the buffer and always null
 105  *    terminates. bufsize is the size of the destination buffer */
 106 
 107 #ifndef HAVE_STRLCPY
 108 static size_t strlcpy(char *d, const char *s, size_t bufsize)
     /* [<][>][^][v][top][bottom][index][help] */
 109 {
 110         size_t len = strlen(s);
 111         size_t ret = len;
 112         if (bufsize <= 0) return 0;
 113         if (len >= bufsize) len = bufsize-1;
 114         memcpy(d, s, len);
 115         d[len] = 0;
 116         return ret;
 117 }
 118 #endif
 119 
 120 /* like strncat but does not 0 fill the buffer and always null
 121  *    terminates. bufsize is the length of the buffer, which should
 122  *       be one more than the maximum resulting string length */
 123 
 124 #ifndef HAVE_STRLCAT
 125 static size_t strlcat(char *d, const char *s, size_t bufsize)
     /* [<][>][^][v][top][bottom][index][help] */
 126 {
 127         size_t len1 = strlen(d);
 128         size_t len2 = strlen(s);
 129         size_t ret = len1 + len2;
 130 
 131         if (len1+len2 >= bufsize) {
 132                 if (bufsize < (len1+1)) {
 133                         return ret;
 134                 }
 135                 len2 = bufsize - (len1+1);
 136         }
 137         if (len2 > 0) {
 138                 memcpy(d+len1, s, len2);
 139                 d[len1+len2] = 0;
 140         }
 141         return ret;
 142 }
 143 #endif
 144 
 145 /* BB finish BB
 146 
 147         cifs_umount
 148         open nofollow - avoid symlink exposure? 
 149         get owner of dir see if matches self or if root
 150         call system(umount argv) etc.
 151                 
 152 BB end finish BB */
 153 
 154 static char * check_for_domain(char **);
 155 
 156 
 157 static void mount_cifs_usage(void)
     /* [<][>][^][v][top][bottom][index][help] */
 158 {
 159         printf("\nUsage:  %s <remotetarget> <dir> -o <options>\n", thisprogram);
 160         printf("\nMount the remote target, specified as a UNC name,");
 161         printf(" to a local directory.\n\nOptions:\n");
 162         printf("\tuser=<arg>\n\tpass=<arg>\n\tdom=<arg>\n");
 163         printf("\nLess commonly used options:");
 164         printf("\n\tcredentials=<filename>,guest,perm,noperm,setuids,nosetuids,rw,ro,");
 165         printf("\n\tsep=<char>,iocharset=<codepage>,suid,nosuid,exec,noexec,serverino,");
 166         printf("\n\tmapchars,nomapchars,nolock,servernetbiosname=<SRV_RFC1001NAME>");
 167         printf("\n\tdirectio,nounix,cifsacl,sec=<authentication mechanism>,sign");
 168         printf("\n\nOptions not needed for servers supporting CIFS Unix extensions");
 169         printf("\n\t(e.g. unneeded for mounts to most Samba versions):");
 170         printf("\n\tuid=<uid>,gid=<gid>,dir_mode=<mode>,file_mode=<mode>,sfu");
 171         printf("\n\nRarely used options:");
 172         printf("\n\tport=<tcpport>,rsize=<size>,wsize=<size>,unc=<unc_name>,ip=<ip_address>,");
 173         printf("\n\tdev,nodev,nouser_xattr,netbiosname=<OUR_RFC1001NAME>,hard,soft,intr,");
 174         printf("\n\tnointr,ignorecase,noposixpaths,noacl,prefixpath=<path>,nobrl");
 175         printf("\n\tin6_addr");
 176         printf("\n\nOptions are described in more detail in the manual page");
 177         printf("\n\tman 8 mount.cifs\n");
 178         printf("\nTo display the version number of the mount helper:");
 179         printf("\n\t%s -V\n",thisprogram);
 180 
 181         SAFE_FREE(mountpassword);
 182 }
 183 
 184 /* caller frees username if necessary */
 185 static char * getusername(void) {
     /* [<][>][^][v][top][bottom][index][help] */
 186         char *username = NULL;
 187         struct passwd *password = getpwuid(getuid());
 188 
 189         if (password) {
 190                 username = password->pw_name;
 191         }
 192         return username;
 193 }
 194 
 195 static int open_cred_file(char * file_name)
     /* [<][>][^][v][top][bottom][index][help] */
 196 {
 197         char * line_buf;
 198         char * temp_val;
 199         FILE * fs;
 200         int i, length;
 201 
 202         i = access(file_name, R_OK);
 203         if (i)
 204                 return i;
 205 
 206         fs = fopen(file_name,"r");
 207         if(fs == NULL)
 208                 return errno;
 209         line_buf = (char *)malloc(4096);
 210         if(line_buf == NULL) {
 211                 fclose(fs);
 212                 return ENOMEM;
 213         }
 214 
 215         while(fgets(line_buf,4096,fs)) {
 216                 /* parse line from credential file */
 217 
 218                 /* eat leading white space */
 219                 for(i=0;i<4086;i++) {
 220                         if((line_buf[i] != ' ') && (line_buf[i] != '\t'))
 221                                 break;
 222                         /* if whitespace - skip past it */
 223                 }
 224                 if (strncasecmp("username",line_buf+i,8) == 0) {
 225                         temp_val = strchr(line_buf + i,'=');
 226                         if(temp_val) {
 227                                 /* go past equals sign */
 228                                 temp_val++;
 229                                 for(length = 0;length<4087;length++) {
 230                                         if ((temp_val[length] == '\n')
 231                                             || (temp_val[length] == '\0')) {
 232                                                 temp_val[length] = '\0';
 233                                                 break;
 234                                         }
 235                                 }
 236                                 if(length > 4086) {
 237                                         printf("mount.cifs failed due to malformed username in credentials file");
 238                                         memset(line_buf,0,4096);
 239                                         exit(EX_USAGE);
 240                                 } else {
 241                                         got_user = 1;
 242                                         user_name = (char *)calloc(1 + length,1);
 243                                         /* BB adding free of user_name string before exit,
 244                                                 not really necessary but would be cleaner */
 245                                         strlcpy(user_name,temp_val, length+1);
 246                                 }
 247                         }
 248                 } else if (strncasecmp("password",line_buf+i,8) == 0) {
 249                         temp_val = strchr(line_buf+i,'=');
 250                         if(temp_val) {
 251                                 /* go past equals sign */
 252                                 temp_val++;
 253                                 for(length = 0;length<MOUNT_PASSWD_SIZE+1;length++) {
 254                                         if ((temp_val[length] == '\n')
 255                                             || (temp_val[length] == '\0')) {
 256                                                 temp_val[length] = '\0';
 257                                                 break;
 258                                         }
 259                                 }
 260                                 if(length > MOUNT_PASSWD_SIZE) {
 261                                         printf("mount.cifs failed: password in credentials file too long\n");
 262                                         memset(line_buf,0, 4096);
 263                                         exit(EX_USAGE);
 264                                 } else {
 265                                         if(mountpassword == NULL) {
 266                                                 mountpassword = (char *)calloc(MOUNT_PASSWD_SIZE+1,1);
 267                                         } else
 268                                                 memset(mountpassword,0,MOUNT_PASSWD_SIZE);
 269                                         if(mountpassword) {
 270                                                 strlcpy(mountpassword,temp_val,MOUNT_PASSWD_SIZE+1);
 271                                                 got_password = 1;
 272                                         }
 273                                 }
 274                         }
 275                 } else if (strncasecmp("domain",line_buf+i,6) == 0) {
 276                         temp_val = strchr(line_buf+i,'=');
 277                         if(temp_val) {
 278                                 /* go past equals sign */
 279                                 temp_val++;
 280                                 if(verboseflag)
 281                                         printf("\nDomain %s\n",temp_val);
 282                                 for(length = 0;length<DOMAIN_SIZE+1;length++) {
 283                                         if ((temp_val[length] == '\n')
 284                                             || (temp_val[length] == '\0')) {
 285                                                 temp_val[length] = '\0';
 286                                                 break;
 287                                         }
 288                                 }
 289                                 if(length > DOMAIN_SIZE) {
 290                                         printf("mount.cifs failed: domain in credentials file too long\n");
 291                                         exit(EX_USAGE);
 292                                 } else {
 293                                         if(domain_name == NULL) {
 294                                                 domain_name = (char *)calloc(DOMAIN_SIZE+1,1);
 295                                         } else
 296                                                 memset(domain_name,0,DOMAIN_SIZE);
 297                                         if(domain_name) {
 298                                                 strlcpy(domain_name,temp_val,DOMAIN_SIZE+1);
 299                                                 got_domain = 1;
 300                                         }
 301                                 }
 302                         }
 303                 }
 304 
 305         }
 306         fclose(fs);
 307         SAFE_FREE(line_buf);
 308         return 0;
 309 }
 310 
 311 static int get_password_from_file(int file_descript, char * filename)
     /* [<][>][^][v][top][bottom][index][help] */
 312 {
 313         int rc = 0;
 314         int i;
 315         char c;
 316 
 317         if(mountpassword == NULL)
 318                 mountpassword = (char *)calloc(MOUNT_PASSWD_SIZE+1,1);
 319         else 
 320                 memset(mountpassword, 0, MOUNT_PASSWD_SIZE);
 321 
 322         if (mountpassword == NULL) {
 323                 printf("malloc failed\n");
 324                 exit(EX_SYSERR);
 325         }
 326 
 327         if(filename != NULL) {
 328                 rc = access(filename, R_OK);
 329                 if (rc) {
 330                         fprintf(stderr, "mount.cifs failed: access check of %s failed: %s\n",
 331                                         filename, strerror(errno));
 332                         exit(EX_SYSERR);
 333                 }
 334                 file_descript = open(filename, O_RDONLY);
 335                 if(file_descript < 0) {
 336                         printf("mount.cifs failed. %s attempting to open password file %s\n",
 337                                    strerror(errno),filename);
 338                         exit(EX_SYSERR);
 339                 }
 340         }
 341         /* else file already open and fd provided */
 342 
 343         for(i=0;i<MOUNT_PASSWD_SIZE;i++) {
 344                 rc = read(file_descript,&c,1);
 345                 if(rc < 0) {
 346                         printf("mount.cifs failed. Error %s reading password file\n",strerror(errno));
 347                         if(filename != NULL)
 348                                 close(file_descript);
 349                         exit(EX_SYSERR);
 350                 } else if(rc == 0) {
 351                         if(mountpassword[0] == 0) {
 352                                 if(verboseflag)
 353                                         printf("\nWarning: null password used since cifs password file empty");
 354                         }
 355                         break;
 356                 } else /* read valid character */ {
 357                         if((c == 0) || (c == '\n')) {
 358                                 mountpassword[i] = '\0';
 359                                 break;
 360                         } else 
 361                                 mountpassword[i] = c;
 362                 }
 363         }
 364         if((i == MOUNT_PASSWD_SIZE) && (verboseflag)) {
 365                 printf("\nWarning: password longer than %d characters specified in cifs password file",
 366                         MOUNT_PASSWD_SIZE);
 367         }
 368         got_password = 1;
 369         if(filename != NULL) {
 370                 close(file_descript);
 371         }
 372 
 373         return rc;
 374 }
 375 
 376 static int parse_options(char ** optionsp, int * filesys_flags)
     /* [<][>][^][v][top][bottom][index][help] */
 377 {
 378         const char * data;
 379         char * percent_char = NULL;
 380         char * value = NULL;
 381         char * next_keyword = NULL;
 382         char * out = NULL;
 383         int out_len = 0;
 384         int word_len;
 385         int rc = 0;
 386         char user[32];
 387         char group[32];
 388 
 389         if (!optionsp || !*optionsp)
 390                 return 1;
 391         data = *optionsp;
 392 
 393         /* BB fixme check for separator override BB */
 394 
 395         if (getuid()) {
 396                 got_uid = 1;
 397                 snprintf(user,sizeof(user),"%u",getuid());
 398                 got_gid = 1;
 399                 snprintf(group,sizeof(group),"%u",getgid());
 400         }
 401 
 402 /* while ((data = strsep(&options, ",")) != NULL) { */
 403         while(data != NULL) {
 404                 /*  check if ends with trailing comma */
 405                 if(*data == 0)
 406                         break;
 407 
 408                 /* format is keyword=value,keyword2=value2,keyword3=value3 etc.) */
 409                 /* data  = next keyword */
 410                 /* value = next value ie stuff after equal sign */
 411 
 412                 next_keyword = strchr(data,','); /* BB handle sep= */
 413         
 414                 /* temporarily null terminate end of keyword=value pair */
 415                 if(next_keyword)
 416                         *next_keyword++ = 0;
 417 
 418                 /* temporarily null terminate keyword to make keyword and value distinct */
 419                 if ((value = strchr(data, '=')) != NULL) {
 420                         *value = '\0';
 421                         value++;
 422                 }
 423 
 424                 if (strncmp(data, "users",5) == 0) {
 425                         if(!value || !*value) {
 426                                 goto nocopy;
 427                         }
 428                 } else if (strncmp(data, "user_xattr",10) == 0) {
 429                    /* do nothing - need to skip so not parsed as user name */
 430                 } else if (strncmp(data, "user", 4) == 0) {
 431 
 432                         if (!value || !*value) {
 433                                 if(data[4] == '\0') {
 434                                         if(verboseflag)
 435                                                 printf("\nskipping empty user mount parameter\n");
 436                                         /* remove the parm since it would otherwise be confusing
 437                                         to the kernel code which would think it was a real username */
 438                                         goto nocopy;
 439                                 } else {
 440                                         printf("username specified with no parameter\n");
 441                                         SAFE_FREE(out);
 442                                         return 1;       /* needs_arg; */
 443                                 }
 444                         } else {
 445                                 if (strnlen(value, 260) < 260) {
 446                                         got_user=1;
 447                                         percent_char = strchr(value,'%');
 448                                         if(percent_char) {
 449                                                 *percent_char = ',';
 450                                                 if(mountpassword == NULL)
 451                                                         mountpassword = (char *)calloc(MOUNT_PASSWD_SIZE+1,1);
 452                                                 if(mountpassword) {
 453                                                         if(got_password)
 454                                                                 printf("\nmount.cifs warning - password specified twice\n");
 455                                                         got_password = 1;
 456                                                         percent_char++;
 457                                                         strlcpy(mountpassword, percent_char,MOUNT_PASSWD_SIZE+1);
 458                                                 /*  remove password from username */
 459                                                         while(*percent_char != 0) {
 460                                                                 *percent_char = ',';
 461                                                                 percent_char++;
 462                                                         }
 463                                                 }
 464                                         }
 465                                         /* this is only case in which the user
 466                                         name buf is not malloc - so we have to
 467                                         check for domain name embedded within
 468                                         the user name here since the later
 469                                         call to check_for_domain will not be
 470                                         invoked */
 471                                         domain_name = check_for_domain(&value);
 472                                 } else {
 473                                         printf("username too long\n");
 474                                         SAFE_FREE(out);
 475                                         return 1;
 476                                 }
 477                         }
 478                 } else if (strncmp(data, "pass", 4) == 0) {
 479                         if (!value || !*value) {
 480                                 if(got_password) {
 481                                         fprintf(stderr, "\npassword specified twice, ignoring second\n");
 482                                 } else
 483                                         got_password = 1;
 484                         } else if (strnlen(value, MOUNT_PASSWD_SIZE) < MOUNT_PASSWD_SIZE) {
 485                                 if (got_password) {
 486                                         fprintf(stderr, "\nmount.cifs warning - password specified twice\n");
 487                                 } else {
 488                                         mountpassword = strndup(value, MOUNT_PASSWD_SIZE);
 489                                         if (!mountpassword) {
 490                                                 fprintf(stderr, "mount.cifs error: %s", strerror(ENOMEM));
 491                                                 SAFE_FREE(out);
 492                                                 return 1;
 493                                         }
 494                                         got_password = 1;
 495                                 }
 496                         } else {
 497                                 fprintf(stderr, "password too long\n");
 498                                 SAFE_FREE(out);
 499                                 return 1;
 500                         }
 501                         goto nocopy;
 502                 } else if (strncmp(data, "sec", 3) == 0) {
 503                         if (value) {
 504                                 if (!strncmp(value, "none", 4) ||
 505                                     !strncmp(value, "krb5", 4))
 506                                         got_password = 1;
 507                         }
 508                 } else if (strncmp(data, "ip", 2) == 0) {
 509                         if (!value || !*value) {
 510                                 printf("target ip address argument missing");
 511                         } else if (strnlen(value, MAX_ADDRESS_LEN) <= MAX_ADDRESS_LEN) {
 512                                 if(verboseflag)
 513                                         printf("ip address %s override specified\n",value);
 514                                 got_ip = 1;
 515                         } else {
 516                                 printf("ip address too long\n");
 517                                 SAFE_FREE(out);
 518                                 return 1;
 519                         }
 520                 } else if ((strncmp(data, "unc", 3) == 0)
 521                    || (strncmp(data, "target", 6) == 0)
 522                    || (strncmp(data, "path", 4) == 0)) {
 523                         if (!value || !*value) {
 524                                 printf("invalid path to network resource\n");
 525                                 SAFE_FREE(out);
 526                                 return 1;  /* needs_arg; */
 527                         } else if(strnlen(value,5) < 5) {
 528                                 printf("UNC name too short");
 529                         }
 530 
 531                         if (strnlen(value, 300) < 300) {
 532                                 got_unc = 1;
 533                                 if (strncmp(value, "//", 2) == 0) {
 534                                         if(got_unc)
 535                                                 printf("unc name specified twice, ignoring second\n");
 536                                         else
 537                                                 got_unc = 1;
 538                                 } else if (strncmp(value, "\\\\", 2) != 0) {                       
 539                                         printf("UNC Path does not begin with // or \\\\ \n");
 540                                         SAFE_FREE(out);
 541                                         return 1;
 542                                 } else {
 543                                         if(got_unc)
 544                                                 printf("unc name specified twice, ignoring second\n");
 545                                         else
 546                                                 got_unc = 1;
 547                                 }
 548                         } else {
 549                                 printf("CIFS: UNC name too long\n");
 550                                 SAFE_FREE(out);
 551                                 return 1;
 552                         }
 553                 } else if ((strncmp(data, "dom" /* domain */, 3) == 0)
 554                            || (strncmp(data, "workg", 5) == 0)) {
 555                         /* note this allows for synonyms of "domain"
 556                            such as "DOM" and "dom" and "workgroup"
 557                            and "WORKGRP" etc. */
 558                         if (!value || !*value) {
 559                                 printf("CIFS: invalid domain name\n");
 560                                 SAFE_FREE(out);
 561                                 return 1;       /* needs_arg; */
 562                         }
 563                         if (strnlen(value, DOMAIN_SIZE+1) < DOMAIN_SIZE+1) {
 564                                 got_domain = 1;
 565                         } else {
 566                                 printf("domain name too long\n");
 567                                 SAFE_FREE(out);
 568                                 return 1;
 569                         }
 570                 } else if (strncmp(data, "cred", 4) == 0) {
 571                         if (value && *value) {
 572                                 rc = open_cred_file(value);
 573                                 if(rc) {
 574                                         printf("error %d (%s) opening credential file %s\n",
 575                                                 rc, strerror(rc), value);
 576                                         SAFE_FREE(out);
 577                                         return 1;
 578                                 }
 579                         } else {
 580                                 printf("invalid credential file name specified\n");
 581                                 SAFE_FREE(out);
 582                                 return 1;
 583                         }
 584                 } else if (strncmp(data, "uid", 3) == 0) {
 585                         if (value && *value) {
 586                                 got_uid = 1;
 587                                 if (!isdigit(*value)) {
 588                                         struct passwd *pw;
 589 
 590                                         if (!(pw = getpwnam(value))) {
 591                                                 printf("bad user name \"%s\"\n", value);
 592                                                 exit(EX_USAGE);
 593                                         }
 594                                         snprintf(user, sizeof(user), "%u", pw->pw_uid);
 595                                 } else {
 596                                         strlcpy(user,value,sizeof(user));
 597                                 }
 598                         }
 599                         goto nocopy;
 600                 } else if (strncmp(data, "gid", 3) == 0) {
 601                         if (value && *value) {
 602                                 got_gid = 1;
 603                                 if (!isdigit(*value)) {
 604                                         struct group *gr;
 605 
 606                                         if (!(gr = getgrnam(value))) {
 607                                                 printf("bad group name \"%s\"\n", value);
 608                                                 exit(EX_USAGE);
 609                                         }
 610                                         snprintf(group, sizeof(group), "%u", gr->gr_gid);
 611                                 } else {
 612                                         strlcpy(group,value,sizeof(group));
 613                                 }
 614                         }
 615                         goto nocopy;
 616        /* fmask and dmask synonyms for people used to smbfs syntax */
 617                 } else if (strcmp(data, "file_mode") == 0 || strcmp(data, "fmask")==0) {
 618                         if (!value || !*value) {
 619                                 printf ("Option '%s' requires a numerical argument\n", data);
 620                                 SAFE_FREE(out);
 621                                 return 1;
 622                         }
 623 
 624                         if (value[0] != '0') {
 625                                 printf ("WARNING: '%s' not expressed in octal.\n", data);
 626                         }
 627 
 628                         if (strcmp (data, "fmask") == 0) {
 629                                 printf ("WARNING: CIFS mount option 'fmask' is deprecated. Use 'file_mode' instead.\n");
 630                                 data = "file_mode"; /* BB fix this */
 631                         }
 632                 } else if (strcmp(data, "dir_mode") == 0 || strcmp(data, "dmask")==0) {
 633                         if (!value || !*value) {
 634                                 printf ("Option '%s' requires a numerical argument\n", data);
 635                                 SAFE_FREE(out);
 636                                 return 1;
 637                         }
 638 
 639                         if (value[0] != '0') {
 640                                 printf ("WARNING: '%s' not expressed in octal.\n", data);
 641                         }
 642 
 643                         if (strcmp (data, "dmask") == 0) {
 644                                 printf ("WARNING: CIFS mount option 'dmask' is deprecated. Use 'dir_mode' instead.\n");
 645                                 data = "dir_mode";
 646                         }
 647                         /* the following eight mount options should be
 648                         stripped out from what is passed into the kernel
 649                         since these eight options are best passed as the
 650                         mount flags rather than redundantly to the kernel 
 651                         and could generate spurious warnings depending on the
 652                         level of the corresponding cifs vfs kernel code */
 653                 } else if (strncmp(data, "nosuid", 6) == 0) {
 654                         *filesys_flags |= MS_NOSUID;
 655                 } else if (strncmp(data, "suid", 4) == 0) {
 656                         *filesys_flags &= ~MS_NOSUID;
 657                 } else if (strncmp(data, "nodev", 5) == 0) {
 658                         *filesys_flags |= MS_NODEV;
 659                 } else if ((strncmp(data, "nobrl", 5) == 0) || 
 660                            (strncmp(data, "nolock", 6) == 0)) {
 661                         *filesys_flags &= ~MS_MANDLOCK;
 662                 } else if (strncmp(data, "dev", 3) == 0) {
 663                         *filesys_flags &= ~MS_NODEV;
 664                 } else if (strncmp(data, "noexec", 6) == 0) {
 665                         *filesys_flags |= MS_NOEXEC;
 666                 } else if (strncmp(data, "exec", 4) == 0) {
 667                         *filesys_flags &= ~MS_NOEXEC;
 668                 } else if (strncmp(data, "guest", 5) == 0) {
 669                         user_name = (char *)calloc(1, 1);
 670                         got_user = 1;
 671                         got_password = 1;
 672                 } else if (strncmp(data, "ro", 2) == 0) {
 673                         *filesys_flags |= MS_RDONLY;
 674                 } else if (strncmp(data, "rw", 2) == 0) {
 675                         *filesys_flags &= ~MS_RDONLY;
 676                 } else if (strncmp(data, "remount", 7) == 0) {
 677                         *filesys_flags |= MS_REMOUNT;
 678                 } /* else if (strnicmp(data, "port", 4) == 0) {
 679                         if (value && *value) {
 680                                 vol->port =
 681                                         simple_strtoul(value, &value, 0);
 682                         }
 683                 } else if (strnicmp(data, "rsize", 5) == 0) {
 684                         if (value && *value) {
 685                                 vol->rsize =
 686                                         simple_strtoul(value, &value, 0);
 687                         }
 688                 } else if (strnicmp(data, "wsize", 5) == 0) {
 689                         if (value && *value) {
 690                                 vol->wsize =
 691                                         simple_strtoul(value, &value, 0);
 692                         }
 693                 } else if (strnicmp(data, "version", 3) == 0) {
 694                 } else {
 695                         printf("CIFS: Unknown mount option %s\n",data);
 696                 } */ /* nothing to do on those four mount options above.
 697                         Just pass to kernel and ignore them here */
 698 
 699                 /* Copy (possibly modified) option to out */
 700                 word_len = strlen(data);
 701                 if (value)
 702                         word_len += 1 + strlen(value);
 703 
 704                 out = (char *)realloc(out, out_len + word_len + 2);
 705                 if (out == NULL) {
 706                         perror("malloc");
 707                         exit(EX_SYSERR);
 708                 }
 709 
 710                 if (out_len) {
 711                         strlcat(out, ",", out_len + word_len + 2);
 712                         out_len++;
 713                 }
 714 
 715                 if (value)
 716                         snprintf(out + out_len, word_len + 1, "%s=%s", data, value);
 717                 else
 718                         snprintf(out + out_len, word_len + 1, "%s", data);
 719                 out_len = strlen(out);
 720 
 721 nocopy:
 722                 data = next_keyword;
 723         }
 724 
 725         /* special-case the uid and gid */
 726         if (got_uid) {
 727                 word_len = strlen(user);
 728 
 729                 out = (char *)realloc(out, out_len + word_len + 6);
 730                 if (out == NULL) {
 731                         perror("malloc");
 732                         exit(EX_SYSERR);
 733                 }
 734 
 735                 if (out_len) {
 736                         strlcat(out, ",", out_len + word_len + 6);
 737                         out_len++;
 738                 }
 739                 snprintf(out + out_len, word_len + 5, "uid=%s", user);
 740                 out_len = strlen(out);
 741         }
 742         if (got_gid) {
 743                 word_len = strlen(group);
 744 
 745                 out = (char *)realloc(out, out_len + 1 + word_len + 6);
 746                 if (out == NULL) {
 747                 perror("malloc");
 748                         exit(EX_SYSERR);
 749                 }
 750 
 751                 if (out_len) {
 752                         strlcat(out, ",", out_len + word_len + 6);
 753                         out_len++;
 754                 }
 755                 snprintf(out + out_len, word_len + 5, "gid=%s", group);
 756                 out_len = strlen(out);
 757         }
 758 
 759         SAFE_FREE(*optionsp);
 760         *optionsp = out;
 761         return 0;
 762 }
 763 
 764 /* replace all (one or more) commas with double commas */
 765 static void check_for_comma(char ** ppasswrd)
     /* [<][>][^][v][top][bottom][index][help] */
 766 {
 767         char *new_pass_buf;
 768         char *pass;
 769         int i,j;
 770         int number_of_commas = 0;
 771         int len;
 772 
 773         if(ppasswrd == NULL)
 774                 return;
 775         else 
 776                 (pass = *ppasswrd);
 777 
 778         len = strlen(pass);
 779 
 780         for(i=0;i<len;i++)  {
 781                 if(pass[i] == ',')
 782                         number_of_commas++;
 783         }
 784 
 785         if(number_of_commas == 0)
 786                 return;
 787         if(number_of_commas > MOUNT_PASSWD_SIZE) {
 788                 /* would otherwise overflow the mount options buffer */
 789                 printf("\nInvalid password. Password contains too many commas.\n");
 790                 return;
 791         }
 792 
 793         new_pass_buf = (char *)malloc(len+number_of_commas+1);
 794         if(new_pass_buf == NULL)
 795                 return;
 796 
 797         for(i=0,j=0;i<len;i++,j++) {
 798                 new_pass_buf[j] = pass[i];
 799                 if(pass[i] == ',') {
 800                         j++;
 801                         new_pass_buf[j] = pass[i];
 802                 }
 803         }
 804         new_pass_buf[len+number_of_commas] = 0;
 805 
 806         SAFE_FREE(*ppasswrd);
 807         *ppasswrd = new_pass_buf;
 808         
 809         return;
 810 }
 811 
 812 /* Usernames can not have backslash in them and we use
 813    [BB check if usernames can have forward slash in them BB] 
 814    backslash as domain\user separator character
 815 */
 816 static char * check_for_domain(char **ppuser)
     /* [<][>][^][v][top][bottom][index][help] */
 817 {
 818         char * original_string;
 819         char * usernm;
 820         char * domainnm;
 821         int    original_len;
 822         int    len;
 823         int    i;
 824 
 825         if(ppuser == NULL)
 826                 return NULL;
 827 
 828         original_string = *ppuser;
 829 
 830         if (original_string == NULL)
 831                 return NULL;
 832         
 833         original_len = strlen(original_string);
 834 
 835         usernm = strchr(*ppuser,'/');
 836         if (usernm == NULL) {
 837                 usernm = strchr(*ppuser,'\\');
 838                 if (usernm == NULL)
 839                         return NULL;
 840         }
 841 
 842         if(got_domain) {
 843                 printf("Domain name specified twice. Username probably malformed\n");
 844                 return NULL;
 845         }
 846 
 847         usernm[0] = 0;
 848         domainnm = *ppuser;
 849         if (domainnm[0] != 0) {
 850                 got_domain = 1;
 851         } else {
 852                 printf("null domain\n");
 853         }
 854         len = strlen(domainnm);
 855         /* reset domainm to new buffer, and copy
 856         domain name into it */
 857         domainnm = (char *)malloc(len+1);
 858         if(domainnm == NULL)
 859                 return NULL;
 860 
 861         strlcpy(domainnm,*ppuser,len+1);
 862 
 863 /*      move_string(*ppuser, usernm+1) */
 864         len = strlen(usernm+1);
 865 
 866         if(len >= original_len) {
 867                 /* should not happen */
 868                 return domainnm;
 869         }
 870 
 871         for(i=0;i<original_len;i++) {
 872                 if(i<len)
 873                         original_string[i] = usernm[i+1];
 874                 else /* stuff with commas to remove last parm */
 875                         original_string[i] = ',';
 876         }
 877 
 878         /* BB add check for more than one slash? 
 879           strchr(*ppuser,'/');
 880           strchr(*ppuser,'\\') 
 881         */
 882         
 883         return domainnm;
 884 }
 885 
 886 /* replace all occurances of "from" in a string with "to" */
 887 static void replace_char(char *string, char from, char to, int maxlen)
     /* [<][>][^][v][top][bottom][index][help] */
 888 {
 889         char *lastchar = string + maxlen;
 890         while (string) {
 891                 string = strchr(string, from);
 892                 if (string) {
 893                         *string = to;
 894                         if (string >= lastchar)
 895                                 return;
 896                 }
 897         }
 898 }
 899 
 900 /* Note that caller frees the returned buffer if necessary */
 901 static struct addrinfo *
 902 parse_server(char ** punc_name)
     /* [<][>][^][v][top][bottom][index][help] */
 903 {
 904         char * unc_name = *punc_name;
 905         int length = strnlen(unc_name, MAX_UNC_LEN);
 906         char * share;
 907         struct addrinfo *addrlist;
 908         int rc;
 909 
 910         if(length > (MAX_UNC_LEN - 1)) {
 911                 printf("mount error: UNC name too long");
 912                 return NULL;
 913         }
 914         if ((strncasecmp("cifs://", unc_name, 7) == 0) ||
 915             (strncasecmp("smb://", unc_name, 6) == 0)) {
 916                 printf("\nMounting cifs URL not implemented yet. Attempt to mount %s\n", unc_name);
 917                 return NULL;
 918         }
 919 
 920         if(length < 3) {
 921                 /* BB add code to find DFS root here */
 922                 printf("\nMounting the DFS root for domain not implemented yet\n");
 923                 return NULL;
 924         } else {
 925                 if(strncmp(unc_name,"//",2) && strncmp(unc_name,"\\\\",2)) {
 926                         /* check for nfs syntax ie server:share */
 927                         share = strchr(unc_name,':');
 928                         if(share) {
 929                                 *punc_name = (char *)malloc(length+3);
 930                                 if(*punc_name == NULL) {
 931                                         /* put the original string back  if 
 932                                            no memory left */
 933                                         *punc_name = unc_name;
 934                                         return NULL;
 935                                 }
 936                                 *share = '/';
 937                                 strlcpy((*punc_name)+2,unc_name,length+1);
 938                                 SAFE_FREE(unc_name);
 939                                 unc_name = *punc_name;
 940                                 unc_name[length+2] = 0;
 941                                 goto continue_unc_parsing;
 942                         } else {
 943                                 printf("mount error: improperly formatted UNC name.");
 944                                 printf(" %s does not begin with \\\\ or //\n",unc_name);
 945                                 return NULL;
 946                         }
 947                 } else {
 948 continue_unc_parsing:
 949                         unc_name[0] = '/';
 950                         unc_name[1] = '/';
 951                         unc_name += 2;
 952 
 953                         /* allow for either delimiter between host and sharename */
 954                         if ((share = strpbrk(unc_name, "/\\"))) {
 955                                 *share = 0;  /* temporarily terminate the string */
 956                                 share += 1;
 957                                 if(got_ip == 0) {
 958                                         rc = getaddrinfo(unc_name, NULL, NULL, &addrlist);
 959                                         if (rc != 0) {
 960                                                 printf("mount error: could not resolve address for %s: %s\n",
 961                                                         unc_name, gai_strerror(rc));
 962                                                 addrlist = NULL;
 963                                         }
 964                                 }
 965                                 *(share - 1) = '/'; /* put delimiter back */
 966 
 967                                 /* we don't convert the prefixpath delimiters since '\\' is a valid char in posix paths */
 968                                 if ((prefixpath = strpbrk(share, "/\\"))) {
 969                                         *prefixpath = 0;  /* permanently terminate the string */
 970                                         if (!strlen(++prefixpath))
 971                                                 prefixpath = NULL; /* this needs to be done explicitly */
 972                                 }
 973                                 if(got_ip) {
 974                                         if(verboseflag)
 975                                                 printf("ip address specified explicitly\n");
 976                                         return NULL;
 977                                 }
 978                                 /* BB should we pass an alternate version of the share name as Unicode */
 979 
 980                                 return addrlist; 
 981                         } else {
 982                                 /* BB add code to find DFS root (send null path on get DFS Referral to specified server here */
 983                                 printf("Mounting the DFS root for a particular server not implemented yet\n");
 984                                 return NULL;
 985                         }
 986                 }
 987         }
 988 }
 989 
 990 static struct option longopts[] = {
 991         { "all", 0, NULL, 'a' },
 992         { "help",0, NULL, 'h' },
 993         { "move",0, NULL, 'm' },
 994         { "bind",0, NULL, 'b' },
 995         { "read-only", 0, NULL, 'r' },
 996         { "ro", 0, NULL, 'r' },
 997         { "verbose", 0, NULL, 'v' },
 998         { "version", 0, NULL, 'V' },
 999         { "read-write", 0, NULL, 'w' },
1000         { "rw", 0, NULL, 'w' },
1001         { "options", 1, NULL, 'o' },
1002         { "type", 1, NULL, 't' },
1003         { "rsize",1, NULL, 'R' },
1004         { "wsize",1, NULL, 'W' },
1005         { "uid", 1, NULL, '1'},
1006         { "gid", 1, NULL, '2'},
1007         { "user",1,NULL,'u'},
1008         { "username",1,NULL,'u'},
1009         { "dom",1,NULL,'d'},
1010         { "domain",1,NULL,'d'},
1011         { "password",1,NULL,'p'},
1012         { "pass",1,NULL,'p'},
1013         { "credentials",1,NULL,'c'},
1014         { "port",1,NULL,'P'},
1015         /* { "uuid",1,NULL,'U'}, */ /* BB unimplemented */
1016         { NULL, 0, NULL, 0 }
1017 };
1018 
1019 /* convert a string to uppercase. return false if the string
1020  * wasn't ASCII. Return success on a NULL ptr */
1021 static int
1022 uppercase_string(char *string)
     /* [<][>][^][v][top][bottom][index][help] */
1023 {
1024         if (!string)
1025                 return 1;
1026 
1027         while (*string) {
1028                 /* check for unicode */
1029                 if ((unsigned char) string[0] & 0x80)
1030                         return 0;
1031                 *string = toupper((unsigned char) *string);
1032                 string++;
1033         }
1034 
1035         return 1;
1036 }
1037 
1038 static void print_cifs_mount_version(void)
     /* [<][>][^][v][top][bottom][index][help] */
1039 {
1040         printf("mount.cifs version: %s.%s%s\n",
1041                 MOUNT_CIFS_VERSION_MAJOR,
1042                 MOUNT_CIFS_VERSION_MINOR,
1043                 MOUNT_CIFS_VENDOR_SUFFIX);
1044 }
1045 
1046 /*
1047  * This function borrowed from fuse-utils...
1048  *
1049  * glibc's addmntent (at least as of 2.10 or so) doesn't properly encode
1050  * newlines embedded within the text fields. To make sure no one corrupts
1051  * the mtab, fail the mount if there are embedded newlines.
1052  */
1053 static int check_newline(const char *progname, const char *name)
     /* [<][>][^][v][top][bottom][index][help] */
1054 {
1055     char *s;
1056     for (s = "\n"; *s; s++) {
1057         if (strchr(name, *s)) {
1058             fprintf(stderr, "%s: illegal character 0x%02x in mount entry\n",
1059                     progname, *s);
1060             return EX_USAGE;
1061         }
1062     }
1063     return 0;
1064 }
1065 
1066 static int check_mtab(const char *progname, const char *devname,
     /* [<][>][^][v][top][bottom][index][help] */
1067                         const char *dir)
1068 {
1069         if (check_newline(progname, devname) == -1 ||
1070             check_newline(progname, dir) == -1)
1071                 return EX_USAGE;
1072         return 0;
1073 }
1074 
1075 
1076 int main(int argc, char ** argv)
     /* [<][>][^][v][top][bottom][index][help] */
1077 {
1078         int c;
1079         int flags = MS_MANDLOCK; /* no need to set legacy MS_MGC_VAL */
1080         char * orgoptions = NULL;
1081         char * share_name = NULL;
1082         const char * ipaddr = NULL;
1083         char * uuid = NULL;
1084         char * mountpoint = NULL;
1085         char * options = NULL;
1086         char * optionstail;
1087         char * resolved_path = NULL;
1088         char * temp;
1089         char * dev_name;
1090         int rc = 0;
1091         int rsize = 0;
1092         int wsize = 0;
1093         int nomtab = 0;
1094         int uid = 0;
1095         int gid = 0;
1096         int optlen = 0;
1097         int orgoptlen = 0;
1098         size_t options_size = 0;
1099         size_t current_len;
1100         int retry = 0; /* set when we have to retry mount with uppercase */
1101         struct addrinfo *addrhead = NULL, *addr;
1102         struct stat statbuf;
1103         struct utsname sysinfo;
1104         struct mntent mountent;
1105         struct sockaddr_in *addr4;
1106         struct sockaddr_in6 *addr6;
1107         FILE * pmntfile;
1108 
1109         /* setlocale(LC_ALL, "");
1110         bindtextdomain(PACKAGE, LOCALEDIR);
1111         textdomain(PACKAGE); */
1112 
1113         if(argc && argv) {
1114                 thisprogram = argv[0];
1115         } else {
1116                 mount_cifs_usage();
1117                 exit(EX_USAGE);
1118         }
1119 
1120         if(thisprogram == NULL)
1121                 thisprogram = "mount.cifs";
1122 
1123         uname(&sysinfo);
1124         /* BB add workstation name and domain and pass down */
1125 
1126 /* #ifdef _GNU_SOURCE
1127         printf(" node: %s machine: %s sysname %s domain %s\n", sysinfo.nodename,sysinfo.machine,sysinfo.sysname,sysinfo.domainname);
1128 #endif */
1129         if(argc > 2) {
1130                 dev_name = argv[1];
1131                 share_name = strndup(argv[1], MAX_UNC_LEN);
1132                 if (share_name == NULL) {
1133                         fprintf(stderr, "%s: %s", argv[0], strerror(ENOMEM));
1134                         exit(EX_SYSERR);
1135                 }
1136                 mountpoint = argv[2];
1137         } else if (argc == 2) {
1138                 if ((strcmp(argv[1], "-V") == 0) ||
1139                     (strcmp(argv[1], "--version") == 0))
1140                 {
1141                         print_cifs_mount_version();
1142                         exit(0);
1143                 }
1144 
1145                 if ((strcmp(argv[1], "-h") == 0) ||
1146                     (strcmp(argv[1], "-?") == 0) ||
1147                     (strcmp(argv[1], "--help") == 0))
1148                 {
1149                         mount_cifs_usage();
1150                         exit(0);
1151                 }
1152 
1153                 mount_cifs_usage();
1154                 exit(EX_USAGE);
1155         } else {
1156                 mount_cifs_usage();
1157                 exit(EX_USAGE);
1158         }
1159 
1160         /* add sharename in opts string as unc= parm */
1161 
1162         while ((c = getopt_long (argc, argv, "afFhilL:no:O:rsSU:vVwt:",
1163                          longopts, NULL)) != -1) {
1164                 switch (c) {
1165 /* No code to do the following  options yet */
1166 /*      case 'l':
1167                 list_with_volumelabel = 1;
1168                 break;
1169         case 'L':
1170                 volumelabel = optarg;
1171                 break; */
1172 /*      case 'a':              
1173                 ++mount_all;
1174                 break; */
1175 
1176                 case '?':
1177                 case 'h':        /* help */
1178                         mount_cifs_usage ();
1179                         exit(0);
1180                 case 'n':
1181                         ++nomtab;
1182                         break;
1183                 case 'b':
1184 #ifdef MS_BIND
1185                         flags |= MS_BIND;
1186 #else
1187                         fprintf(stderr,
1188                                 "option 'b' (MS_BIND) not supported\n");
1189 #endif
1190                         break;
1191                 case 'm':
1192 #ifdef MS_MOVE                
1193                         flags |= MS_MOVE;
1194 #else
1195                         fprintf(stderr,
1196                                 "option 'm' (MS_MOVE) not supported\n");
1197 #endif
1198                         break;
1199                 case 'o':
1200                         orgoptions = strdup(optarg);
1201                     break;
1202                 case 'r':  /* mount readonly */
1203                         flags |= MS_RDONLY;
1204                         break;
1205                 case 'U':
1206                         uuid = optarg;
1207                         break;
1208                 case 'v':
1209                         ++verboseflag;
1210                         break;
1211                 case 'V':
1212                         print_cifs_mount_version();
1213                         exit (0);
1214                 case 'w':
1215                         flags &= ~MS_RDONLY;
1216                         break;
1217                 case 'R':
1218                         rsize = atoi(optarg) ;
1219                         break;
1220                 case 'W':
1221                         wsize = atoi(optarg);
1222                         break;
1223                 case '1':
1224                         if (isdigit(*optarg)) {
1225                                 char *ep;
1226 
1227                                 uid = strtoul(optarg, &ep, 10);
1228                                 if (*ep) {
1229                                         printf("bad uid value \"%s\"\n", optarg);
1230                                         exit(EX_USAGE);
1231                                 }
1232                         } else {
1233                                 struct passwd *pw;
1234 
1235                                 if (!(pw = getpwnam(optarg))) {
1236                                         printf("bad user name \"%s\"\n", optarg);
1237                                         exit(EX_USAGE);
1238                                 }
1239                                 uid = pw->pw_uid;
1240                                 endpwent();
1241                         }
1242                         break;
1243                 case '2':
1244                         if (isdigit(*optarg)) {
1245                                 char *ep;
1246 
1247                                 gid = strtoul(optarg, &ep, 10);
1248                                 if (*ep) {
1249                                         printf("bad gid value \"%s\"\n", optarg);
1250                                         exit(EX_USAGE);
1251                                 }
1252                         } else {
1253                                 struct group *gr;
1254 
1255                                 if (!(gr = getgrnam(optarg))) {
1256                                         printf("bad user name \"%s\"\n", optarg);
1257                                         exit(EX_USAGE);
1258                                 }
1259                                 gid = gr->gr_gid;
1260                                 endpwent();
1261                         }
1262                         break;
1263                 case 'u':
1264                         got_user = 1;
1265                         user_name = optarg;
1266                         break;
1267                 case 'd':
1268                         domain_name = optarg; /* BB fix this - currently ignored */
1269                         got_domain = 1;
1270                         break;
1271                 case 'p':
1272                         if(mountpassword == NULL)
1273                                 mountpassword = (char *)calloc(MOUNT_PASSWD_SIZE+1,1);
1274                         if(mountpassword) {
1275                                 got_password = 1;
1276                                 strlcpy(mountpassword,optarg,MOUNT_PASSWD_SIZE+1);
1277                         }
1278                         break;
1279                 case 'S':
1280                         get_password_from_file(0 /* stdin */,NULL);
1281                         break;
1282                 case 't':
1283                         break;
1284                 case 'f':
1285                         ++fakemnt;
1286                         break;
1287                 default:
1288                         printf("unknown mount option %c\n",c);
1289                         mount_cifs_usage();
1290                         exit(EX_USAGE);
1291                 }
1292         }
1293 
1294         if((argc < 3) || (dev_name == NULL) || (mountpoint == NULL)) {
1295                 mount_cifs_usage();
1296                 exit(EX_USAGE);
1297         }
1298 
1299         if (getenv("PASSWD")) {
1300                 if(mountpassword == NULL)
1301                         mountpassword = (char *)calloc(MOUNT_PASSWD_SIZE+1,1);
1302                 if(mountpassword) {
1303                         strlcpy(mountpassword,getenv("PASSWD"),MOUNT_PASSWD_SIZE+1);
1304                         got_password = 1;
1305                 }
1306         } else if (getenv("PASSWD_FD")) {
1307                 get_password_from_file(atoi(getenv("PASSWD_FD")),NULL);
1308         } else if (getenv("PASSWD_FILE")) {
1309                 get_password_from_file(0, getenv("PASSWD_FILE"));
1310         }
1311 
1312         if (orgoptions && parse_options(&orgoptions, &flags)) {
1313                 rc = EX_USAGE;
1314                 goto mount_exit;
1315         }
1316         addrhead = addr = parse_server(&share_name);
1317         if((addrhead == NULL) && (got_ip == 0)) {
1318                 printf("No ip address specified and hostname not found\n");
1319                 rc = EX_USAGE;
1320                 goto mount_exit;
1321         }
1322         
1323         /* BB save off path and pop after mount returns? */
1324         resolved_path = (char *)malloc(PATH_MAX+1);
1325         if(resolved_path) {
1326                 /* Note that if we can not canonicalize the name, we get
1327                 another chance to see if it is valid when we chdir to it */
1328                 if (realpath(mountpoint, resolved_path)) {
1329                         mountpoint = resolved_path; 
1330                 }
1331         }
1332         if(chdir(mountpoint)) {
1333                 printf("mount error: can not change directory into mount target %s\n",mountpoint);
1334                 rc = EX_USAGE;
1335                 goto mount_exit;
1336         }
1337 
1338         if(stat (".", &statbuf)) {
1339                 printf("mount error: mount point %s does not exist\n",mountpoint);
1340                 rc = EX_USAGE;
1341                 goto mount_exit;
1342         }
1343 
1344         if (S_ISDIR(statbuf.st_mode) == 0) {
1345                 printf("mount error: mount point %s is not a directory\n",mountpoint);
1346                 rc = EX_USAGE;
1347                 goto mount_exit;
1348         }
1349 
1350         if((getuid() != 0) && (geteuid() == 0)) {
1351                 if((statbuf.st_uid == getuid()) && (S_IRWXU == (statbuf.st_mode & S_IRWXU))) {
1352 #ifndef CIFS_ALLOW_USR_SUID
1353                         /* Do not allow user mounts to control suid flag
1354                         for mount unless explicitly built that way */
1355                         flags |= MS_NOSUID | MS_NODEV;
1356 #endif                                          
1357                 } else {
1358                         printf("mount error: permission denied or not superuser and mount.cifs not installed SUID\n"); 
1359                         exit(EX_USAGE);
1360                 }
1361         }
1362 
1363         if(got_user == 0) {
1364                 /* Note that the password will not be retrieved from the
1365                    USER env variable (ie user%password form) as there is
1366                    already a PASSWD environment varaible */
1367                 if (getenv("USER"))
1368                         user_name = strdup(getenv("USER"));
1369                 if (user_name == NULL)
1370                         user_name = getusername();
1371                 got_user = 1;
1372         }
1373        
1374         if(got_password == 0) {
1375                 char *tmp_pass = getpass("Password: "); /* BB obsolete sys call but
1376                                                            no good replacement yet. */
1377                 mountpassword = (char *)calloc(MOUNT_PASSWD_SIZE+1,1);
1378                 if (!tmp_pass || !mountpassword) {
1379                         printf("Password not entered, exiting\n");
1380                         exit(EX_USAGE);
1381                 }
1382                 strlcpy(mountpassword, tmp_pass, MOUNT_PASSWD_SIZE+1);
1383                 got_password = 1;
1384         }
1385         /* FIXME launch daemon (handles dfs name resolution and credential change) 
1386            remember to clear parms and overwrite password field before launching */
1387         if(orgoptions) {
1388                 optlen = strlen(orgoptions);
1389                 orgoptlen = optlen;
1390         } else
1391                 optlen = 0;
1392         if(share_name)
1393                 optlen += strlen(share_name) + 4;
1394         else {
1395                 printf("No server share name specified\n");
1396                 printf("\nMounting the DFS root for server not implemented yet\n");
1397                 exit(EX_USAGE);
1398         }
1399         if(user_name)
1400                 optlen += strlen(user_name) + 6;
1401         optlen += MAX_ADDRESS_LEN + 4;
1402         if(mountpassword)
1403                 optlen += strlen(mountpassword) + 6;
1404 mount_retry:
1405         SAFE_FREE(options);
1406         options_size = optlen + 10 + DOMAIN_SIZE;
1407         options = (char *)malloc(options_size /* space for commas in password */ + 8 /* space for domain=  , domain name itself was counted as part of the length username string above */);
1408 
1409         if(options == NULL) {
1410                 printf("Could not allocate memory for mount options\n");
1411                 exit(EX_SYSERR);
1412         }
1413 
1414         strlcpy(options, "unc=", options_size);
1415         strlcat(options,share_name,options_size);
1416         /* scan backwards and reverse direction of slash */
1417         temp = strrchr(options, '/');
1418         if(temp > options + 6)
1419                 *temp = '\\';
1420         if(user_name) {
1421                 /* check for syntax like user=domain\user */
1422                 if(got_domain == 0)
1423                         domain_name = check_for_domain(&user_name);
1424                 strlcat(options,",user=",options_size);
1425                 strlcat(options,user_name,options_size);
1426         }
1427         if(retry == 0) {
1428                 if(domain_name) {
1429                         /* extra length accounted for in option string above */
1430                         strlcat(options,",domain=",options_size);
1431                         strlcat(options,domain_name,options_size);
1432                 }
1433         }
1434 
1435         strlcat(options,",ver=",options_size);
1436         strlcat(options,MOUNT_CIFS_VERSION_MAJOR,options_size);
1437 
1438         if(orgoptions) {
1439                 strlcat(options,",",options_size);
1440                 strlcat(options,orgoptions,options_size);
1441         }
1442         if(prefixpath) {
1443                 strlcat(options,",prefixpath=",options_size);
1444                 strlcat(options,prefixpath,options_size); /* no need to cat the / */
1445         }
1446 
1447         /* convert all '\\' to '/' in share portion so that /proc/mounts looks pretty */
1448         replace_char(dev_name, '\\', '/', strlen(share_name));
1449 
1450         if (!got_ip && addr) {
1451                 strlcat(options, ",ip=", options_size);
1452                 current_len = strnlen(options, options_size);
1453                 optionstail = options + current_len;
1454                 switch (addr->ai_addr->sa_family) {
1455                 case AF_INET6:
1456                         addr6 = (struct sockaddr_in6 *) addr->ai_addr;
1457                         ipaddr = inet_ntop(AF_INET6, &addr6->sin6_addr, optionstail,
1458                                            options_size - current_len);
1459                         break;
1460                 case AF_INET:
1461                         addr4 = (struct sockaddr_in *) addr->ai_addr;
1462                         ipaddr = inet_ntop(AF_INET, &addr4->sin_addr, optionstail,
1463                                            options_size - current_len);
1464                         break;
1465                 }
1466 
1467                 /* if the address looks bogus, try the next one */
1468                 if (!ipaddr) {
1469                         addr = addr->ai_next;
1470                         if (addr)
1471                                 goto mount_retry;
1472                         rc = EX_SYSERR;
1473                         goto mount_exit;
1474                 }
1475         }
1476 
1477         if(verboseflag)
1478                 fprintf(stderr, "\nmount.cifs kernel mount options: %s", options);
1479 
1480         if (mountpassword) {
1481                 /*
1482                  * Commas have to be doubled, or else they will
1483                  * look like the parameter separator
1484                  */
1485                 if(retry == 0)
1486                         check_for_comma(&mountpassword);
1487                 strlcat(options,",pass=",options_size);
1488                 strlcat(options,mountpassword,options_size);
1489                 if (verboseflag)
1490                         fprintf(stderr, ",pass=********");
1491         }
1492 
1493         if (verboseflag)
1494                 fprintf(stderr, "\n");
1495 
1496         rc = check_mtab(thisprogram, dev_name, mountpoint);
1497         if (rc)
1498                 goto mount_exit;
1499 
1500         if (!fakemnt && mount(dev_name, mountpoint, "cifs", flags, options)) {
1501                 switch (errno) {
1502                 case ECONNREFUSED:
1503                 case EHOSTUNREACH:
1504                         if (addr) {
1505                                 addr = addr->ai_next;
1506                                 if (addr)
1507                                         goto mount_retry;
1508                         }
1509                         break;
1510                 case ENODEV:
1511                         printf("mount error: cifs filesystem not supported by the system\n");
1512                         break;
1513                 case ENXIO:
1514                         if(retry == 0) {
1515                                 retry = 1;
1516                                 if (uppercase_string(dev_name) &&
1517                                     uppercase_string(share_name) &&
1518                                     uppercase_string(prefixpath)) {
1519                                         printf("retrying with upper case share name\n");
1520                                         goto mount_retry;
1521                                 }
1522                         }
1523                 }
1524                 printf("mount error(%d): %s\n", errno, strerror(errno));
1525                 printf("Refer to the mount.cifs(8) manual page (e.g. man "
1526                        "mount.cifs)\n");
1527                 rc = EX_FAIL;
1528                 goto mount_exit;
1529         }
1530 
1531         if (nomtab)
1532                 goto mount_exit;
1533         atexit(unlock_mtab);
1534         rc = lock_mtab();
1535         if (rc) {
1536                 printf("cannot lock mtab");
1537                 goto mount_exit;
1538         }
1539         pmntfile = setmntent(MOUNTED, "a+");
1540         if (!pmntfile) {
1541                 printf("could not update mount table\n");
1542                 unlock_mtab();
1543                 rc = EX_FILEIO;
1544                 goto mount_exit;
1545         }
1546         mountent.mnt_fsname = dev_name;
1547         mountent.mnt_dir = mountpoint;
1548         mountent.mnt_type = CONST_DISCARD(char *,"cifs");
1549         mountent.mnt_opts = (char *)malloc(220);
1550         if(mountent.mnt_opts) {
1551                 char * mount_user = getusername();
1552                 memset(mountent.mnt_opts,0,200);
1553                 if(flags & MS_RDONLY)
1554                         strlcat(mountent.mnt_opts,"ro",220);
1555                 else
1556                         strlcat(mountent.mnt_opts,"rw",220);
1557                 if(flags & MS_MANDLOCK)
1558                         strlcat(mountent.mnt_opts,",mand",220);
1559                 if(flags & MS_NOEXEC)
1560                         strlcat(mountent.mnt_opts,",noexec",220);
1561                 if(flags & MS_NOSUID)
1562                         strlcat(mountent.mnt_opts,",nosuid",220);
1563                 if(flags & MS_NODEV)
1564                         strlcat(mountent.mnt_opts,",nodev",220);
1565                 if(flags & MS_SYNCHRONOUS)
1566                         strlcat(mountent.mnt_opts,",sync",220);
1567                 if(mount_user) {
1568                         if(getuid() != 0) {
1569                                 strlcat(mountent.mnt_opts,
1570                                         ",user=", 220);
1571                                 strlcat(mountent.mnt_opts,
1572                                         mount_user, 220);
1573                         }
1574                 }
1575         }
1576         mountent.mnt_freq = 0;
1577         mountent.mnt_passno = 0;
1578         rc = addmntent(pmntfile,&mountent);
1579         endmntent(pmntfile);
1580         unlock_mtab();
1581         SAFE_FREE(mountent.mnt_opts);
1582         if (rc)
1583                 rc = EX_FILEIO;
1584 mount_exit:
1585         if(mountpassword) {
1586                 int len = strlen(mountpassword);
1587                 memset(mountpassword,0,len);
1588                 SAFE_FREE(mountpassword);
1589         }
1590 
1591         if (addrhead)
1592                 freeaddrinfo(addrhead);
1593         SAFE_FREE(options);
1594         SAFE_FREE(orgoptions);
1595         SAFE_FREE(resolved_path);
1596         SAFE_FREE(share_name);
1597         exit(rc);
1598 }

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