~ubuntu-branches/ubuntu/lucid/samba/lucid-security

« back to all changes in this revision

Viewing changes to .pc/CVE-2011-1678.patch/source3/client/mount.cifs.c

  • Committer: Package Import Robot
  • Author(s): Marc Deslauriers
  • Date: 2011-09-30 11:51:06 UTC
  • Revision ID: package-import@ubuntu.com-20110930115106-i2gtgkiwu0p1p3yu
Tags: 2:3.4.7~dfsg-1ubuntu3.8
* SECURITY UPDATE: denial of service via stale mtab lockfile
  - debian/patches/security-mask-signals.patch: mask signals while
    updating the mtab file in source3/client/mount.cifs.c.
  - CVE-2011-3585
* SECURITY UPDATE: mtab corruption via resource limits
  - debian/patches/CVE-2011-1678.patch: truncate mtab file if updating it
    failed in source3/client/{mount.cifs.c,mount.h,mtab.c}.
  - CVE-2011-1678
* SECURITY UPDATE: mtab corruption via incorrect new line check
  - debian/patches/CVE-2011-2724.patch: check proper return codes in
    source3/client/mount.cifs.c.
  - CVE-2011-2724

Show diffs side-by-side

added added

removed removed

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