1998-01-06 01:56:29 +03:00
/*
1999-12-13 16:27:58 +03:00
* smbmnt . c
1998-01-06 01:56:29 +03:00
*
1998-01-22 16:27:43 +03:00
* Copyright ( C ) 1995 - 1998 by Paal - Kr . Engstad and Volker Lendecke
1999-12-13 16:27:58 +03:00
* extensively modified by Tridge
1998-01-06 01:56:29 +03:00
*
2005-06-22 11:00:26 +04:00
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
* Foundation , Inc . , 675 Mass Ave , Cambridge , MA 0213 9 , USA .
*
1998-01-06 01:56:29 +03:00
*/
2005-05-06 19:22:05 +04:00
# define SMBMOUNT_MALLOC 1
1998-09-28 23:18:21 +04:00
# include "includes.h"
1998-01-06 01:56:29 +03:00
# include <mntent.h>
2001-03-10 22:50:36 +03:00
# include <sys/utsname.h>
1998-01-06 01:56:29 +03:00
1998-09-28 23:18:21 +04:00
# include <asm/types.h>
# include <asm/posix_types.h>
1998-01-06 01:56:29 +03:00
# include <linux/smb.h>
# include <linux/smb_mount.h>
# include <asm/unistd.h>
1998-09-28 23:18:21 +04:00
# ifndef MS_MGC_VAL
/* This may look strange but MS_MGC_VAL is what we are looking for and
is what we need from < linux / fs . h > under libc systems and is
provided in standard includes on glibc systems . So . . . We
switch on what we need . . . */
# include <linux/fs.h>
# endif
1999-12-13 16:27:58 +03:00
static uid_t mount_uid ;
static gid_t mount_gid ;
static int mount_ro ;
static unsigned mount_fmask ;
static unsigned mount_dmask ;
static int user_mount ;
2001-03-10 22:50:36 +03:00
static char * options ;
1998-01-06 01:56:29 +03:00
static void
help ( void )
{
printf ( " \n " ) ;
2001-03-10 22:50:36 +03:00
printf ( " Usage: smbmnt mount-point [options] \n " ) ;
2003-08-20 21:13:38 +04:00
printf ( " Version %s \n \n " , SAMBA_VERSION_STRING ) ;
1999-12-13 16:27:58 +03:00
printf ( " -s share share name on server \n "
" -r mount read-only \n "
" -u uid mount as uid \n "
" -g gid mount as gid \n "
" -f mask permission mask for files \n "
" -d mask permission mask for directories \n "
2001-03-10 22:50:36 +03:00
" -o options name=value, list of options \n "
1998-01-06 01:56:29 +03:00
" -h print this help text \n " ) ;
}
static int
1998-01-22 06:47:48 +03:00
parse_args ( int argc , char * argv [ ] , struct smb_mount_data * data , char * * share )
1998-01-06 01:56:29 +03:00
{
int opt ;
2001-03-10 22:50:36 +03:00
while ( ( opt = getopt ( argc , argv , " s:u:g:rf:d:o: " ) ) ! = EOF )
1998-01-06 01:56:29 +03:00
{
switch ( opt )
{
1999-12-13 16:27:58 +03:00
case ' s ' :
* share = optarg ;
break ;
1998-01-06 01:56:29 +03:00
case ' u ' :
1999-12-13 16:27:58 +03:00
if ( ! user_mount ) {
mount_uid = strtol ( optarg , NULL , 0 ) ;
}
1998-01-06 01:56:29 +03:00
break ;
case ' g ' :
1999-12-13 16:27:58 +03:00
if ( ! user_mount ) {
mount_gid = strtol ( optarg , NULL , 0 ) ;
}
break ;
case ' r ' :
mount_ro = 1 ;
1998-01-06 01:56:29 +03:00
break ;
case ' f ' :
1999-12-13 16:27:58 +03:00
mount_fmask = strtol ( optarg , NULL , 8 ) ;
1998-01-06 01:56:29 +03:00
break ;
case ' d ' :
1999-12-13 16:27:58 +03:00
mount_dmask = strtol ( optarg , NULL , 8 ) ;
1998-01-22 06:47:48 +03:00
break ;
2001-03-10 22:50:36 +03:00
case ' o ' :
options = optarg ;
break ;
1998-01-06 01:56:29 +03:00
default :
return - 1 ;
}
}
return 0 ;
}
static char *
fullpath ( const char * p )
{
2003-08-06 23:30:42 +04:00
char path [ PATH_MAX + 1 ] ;
1998-01-06 01:56:29 +03:00
2003-08-06 23:30:42 +04:00
if ( strlen ( p ) > PATH_MAX ) {
1998-01-06 01:56:29 +03:00
return NULL ;
}
1999-12-13 16:27:58 +03:00
if ( realpath ( p , path ) = = NULL ) {
2005-02-07 18:35:42 +03:00
fprintf ( stderr , " Failed to find real path for mount point %s: %s \n " ,
p , strerror ( errno ) ) ;
1999-12-13 16:27:58 +03:00
exit ( 1 ) ;
1998-01-06 01:56:29 +03:00
}
return strdup ( path ) ;
}
1999-12-13 16:27:58 +03:00
/* Check whether user is allowed to mount on the specified mount point. If it's
OK then we change into that directory - this prevents race conditions */
static int mount_ok ( char * mount_point )
1998-01-06 01:56:29 +03:00
{
2002-07-15 14:35:28 +04:00
struct stat st ;
1999-12-13 16:27:58 +03:00
if ( chdir ( mount_point ) ! = 0 ) {
return - 1 ;
}
2002-07-15 14:35:28 +04:00
if ( stat ( " . " , & st ) ! = 0 ) {
1999-12-13 16:27:58 +03:00
return - 1 ;
}
if ( ! S_ISDIR ( st . st_mode ) ) {
1998-01-06 01:56:29 +03:00
errno = ENOTDIR ;
return - 1 ;
}
1999-12-13 16:27:58 +03:00
if ( ( getuid ( ) ! = 0 ) & &
( ( getuid ( ) ! = st . st_uid ) | |
( ( st . st_mode & S_IRWXU ) ! = S_IRWXU ) ) ) {
1998-01-06 01:56:29 +03:00
errno = EPERM ;
return - 1 ;
}
return 0 ;
}
2001-03-10 22:50:36 +03:00
/* Tries to mount using the appropriate format. For 2.2 the struct,
for 2.4 the ascii version . */
static int
do_mount ( char * share_name , unsigned int flags , struct smb_mount_data * data )
{
pstring opts ;
struct utsname uts ;
char * release , * major , * minor ;
char * data1 , * data2 ;
uname ( & uts ) ;
release = uts . release ;
2002-09-25 19:19:00 +04:00
major = strtok ( release , " . " ) ;
minor = strtok ( NULL , " . " ) ;
2001-03-10 22:50:36 +03:00
if ( major & & minor & & atoi ( major ) = = 2 & & atoi ( minor ) < 4 ) {
/* < 2.4, assume struct */
data1 = ( char * ) data ;
data2 = opts ;
} else {
/* >= 2.4, assume ascii but fall back on struct */
data1 = opts ;
data2 = ( char * ) data ;
}
2001-04-09 00:22:39 +04:00
slprintf ( opts , sizeof ( opts ) - 1 ,
2001-03-10 22:50:36 +03:00
" version=7,uid=%d,gid=%d,file_mode=0%o,dir_mode=0%o,%s " ,
2005-02-04 03:25:33 +03:00
mount_uid , mount_gid , data - > file_mode , data - > dir_mode , options ) ;
2001-03-10 22:50:36 +03:00
if ( mount ( share_name , " . " , " smbfs " , flags , data1 ) = = 0 )
return 0 ;
return mount ( share_name , " . " , " smbfs " , flags , data2 ) ;
}
1999-12-13 16:27:58 +03:00
int main ( int argc , char * argv [ ] )
1998-01-06 01:56:29 +03:00
{
1998-01-22 06:47:48 +03:00
char * mount_point , * share_name = NULL ;
FILE * mtab ;
1999-12-13 16:27:58 +03:00
int fd ;
1998-01-06 01:56:29 +03:00
unsigned int flags ;
1998-01-22 06:47:48 +03:00
struct smb_mount_data data ;
struct mntent ment ;
1998-01-06 01:56:29 +03:00
memset ( & data , 0 , sizeof ( struct smb_mount_data ) ) ;
1999-12-13 16:27:58 +03:00
if ( argc < 2 ) {
1998-01-06 01:56:29 +03:00
help ( ) ;
1999-12-13 16:27:58 +03:00
exit ( 1 ) ;
}
if ( argv [ 1 ] [ 0 ] = = ' - ' ) {
help ( ) ;
exit ( 1 ) ;
}
if ( getuid ( ) ! = 0 ) {
user_mount = 1 ;
1998-01-06 01:56:29 +03:00
}
if ( geteuid ( ) ! = 0 ) {
1999-12-13 16:27:58 +03:00
fprintf ( stderr , " smbmnt must be installed suid root for direct user mounts (%d,%d) \n " , getuid ( ) , geteuid ( ) ) ;
1998-01-06 01:56:29 +03:00
exit ( 1 ) ;
}
1999-12-13 16:27:58 +03:00
mount_uid = getuid ( ) ;
mount_gid = getgid ( ) ;
mount_fmask = umask ( 0 ) ;
umask ( mount_fmask ) ;
mount_fmask = ~ mount_fmask ;
1998-01-06 01:56:29 +03:00
1999-12-13 16:27:58 +03:00
mount_point = fullpath ( argv [ 1 ] ) ;
1998-01-06 01:56:29 +03:00
argv + = 1 ;
argc - = 1 ;
1999-12-13 16:27:58 +03:00
if ( mount_ok ( mount_point ) ! = 0 ) {
1998-01-06 01:56:29 +03:00
fprintf ( stderr , " cannot mount on %s: %s \n " ,
mount_point , strerror ( errno ) ) ;
exit ( 1 ) ;
}
data . version = SMB_MOUNT_VERSION ;
/* getuid() gives us the real uid, who may umount the fs */
data . mounted_uid = getuid ( ) ;
1998-01-22 06:47:48 +03:00
if ( parse_args ( argc , argv , & data , & share_name ) ! = 0 ) {
1999-12-13 16:27:58 +03:00
help ( ) ;
1998-01-06 01:56:29 +03:00
return - 1 ;
}
2005-02-04 03:25:33 +03:00
data . uid = mount_uid ; // truncates to 16-bits here!!!
1999-12-13 16:27:58 +03:00
data . gid = mount_gid ;
data . file_mode = ( S_IRWXU | S_IRWXG | S_IRWXO ) & mount_fmask ;
data . dir_mode = ( S_IRWXU | S_IRWXG | S_IRWXO ) & mount_dmask ;
if ( mount_dmask = = 0 ) {
1998-01-06 01:56:29 +03:00
data . dir_mode = data . file_mode ;
if ( ( data . dir_mode & S_IRUSR ) ! = 0 )
data . dir_mode | = S_IXUSR ;
if ( ( data . dir_mode & S_IRGRP ) ! = 0 )
data . dir_mode | = S_IXGRP ;
if ( ( data . dir_mode & S_IROTH ) ! = 0 )
data . dir_mode | = S_IXOTH ;
}
2004-02-13 20:32:20 +03:00
flags = MS_MGC_VAL | MS_NOSUID | MS_NODEV ;
1998-01-06 01:56:29 +03:00
1999-12-13 16:27:58 +03:00
if ( mount_ro ) flags | = MS_RDONLY ;
2001-03-10 22:50:36 +03:00
if ( do_mount ( share_name , flags , & data ) < 0 ) {
1999-12-13 16:27:58 +03:00
switch ( errno ) {
case ENODEV :
fprintf ( stderr , " ERROR: smbfs filesystem not supported by the kernel \n " ) ;
break ;
default :
perror ( " mount error " ) ;
}
fprintf ( stderr , " Please refer to the smbmnt(8) manual page \n " ) ;
1998-01-06 01:56:29 +03:00
return - 1 ;
}
1998-01-22 06:47:48 +03:00
ment . mnt_fsname = share_name ? share_name : " none " ;
1999-12-13 16:27:58 +03:00
ment . mnt_dir = mount_point ;
1998-01-06 01:56:29 +03:00
ment . mnt_type = " smbfs " ;
ment . mnt_opts = " " ;
ment . mnt_freq = 0 ;
ment . mnt_passno = 0 ;
mount_point = ment . mnt_dir ;
if ( mount_point = = NULL )
{
fprintf ( stderr , " Mount point too long \n " ) ;
return - 1 ;
}
if ( ( fd = open ( MOUNTED " ~ " , O_RDWR | O_CREAT | O_EXCL , 0600 ) ) = = - 1 )
{
fprintf ( stderr , " Can't get " MOUNTED " ~ lock file " ) ;
return 1 ;
}
close ( fd ) ;
if ( ( mtab = setmntent ( MOUNTED , " a+ " ) ) = = NULL )
{
fprintf ( stderr , " Can't open " MOUNTED ) ;
return 1 ;
}
if ( addmntent ( mtab , & ment ) = = 1 )
{
fprintf ( stderr , " Can't write mount entry " ) ;
return 1 ;
}
if ( fchmod ( fileno ( mtab ) , 0644 ) = = - 1 )
{
fprintf ( stderr , " Can't set perms on " MOUNTED ) ;
return 1 ;
}
endmntent ( mtab ) ;
if ( unlink ( MOUNTED " ~ " ) = = - 1 )
{
fprintf ( stderr , " Can't remove " MOUNTED " ~ " ) ;
return 1 ;
}
return 0 ;
}