From 382e64543fc138a5cf29592c508358fa68ead7a8 Mon Sep 17 00:00:00 2001 From: Daniel Markstedt Date: Mon, 29 Jan 2024 22:19:22 +0900 Subject: [PATCH] Fuse improvements by RJVB - use ssh-askpass for password requests when not connected to a terminal & allow options for fusermount - export appropriate filesystem and subvolume names --- fuse/afp_server.h | 1 + fuse/client.c | 42 ++++++++++++++++--- fuse/commands.c | 97 ++++++++++++++++++++++++++++++++++++++++++-- fuse/fuse_internal.h | 2 +- 4 files changed, 131 insertions(+), 11 deletions(-) diff --git a/fuse/afp_server.h b/fuse/afp_server.h index afe0bdd..5e2e3fe 100644 --- a/fuse/afp_server.h +++ b/fuse/afp_server.h @@ -35,6 +35,7 @@ struct afp_server_mount_request { unsigned int volume_options; unsigned int map; int changeuid; + char fuse_options[256]; }; struct afp_server_status_request { diff --git a/fuse/client.c b/fuse/client.c index 5361f18..609fbe3 100644 --- a/fuse/client.c +++ b/fuse/client.c @@ -1,3 +1,4 @@ +#define _GNU_SOURCE #include #include #include @@ -156,6 +157,7 @@ static void usage(void) " \"DHCAST128\", \"Client Krb v2\", \"DHX2\" \n\n" " -m, --map : use this uid/gid mapping method, one of:\n" " \"Common user directory\", \"Login ids\"\n" +" -O, --options : FUSE mount options, see man mount.fuse\n" " status: get status of the AFP daemon\n\n" " unmount : unmount\n\n" " suspend : terminates the connection to the server, but\n" @@ -166,6 +168,30 @@ static void usage(void) } +static char *get_password(const char *prompt) +{ + if( isatty(fileno(stdin)) ){ + return getpass(prompt); + } + else{ + char *askpass = NULL; + static char pwd[AFP_MAX_PASSWORD_LEN+1]; + FILE *fp; + asprintf( &askpass, "ssh-askpass %s", prompt ); + if( (fp = popen( askpass, "r" )) ){ + fread( pwd, 1, sizeof(pwd), fp ); + pclose(fp); + // ssh-askpass always adds a newline: chop it. + pwd[strlen(pwd) - 1] = '\0'; + } + else{ + perror(askpass); + memset( pwd, (int) sizeof(pwd), (0) ); + } + return pwd; + } +} + static int send_command(int sock, char * msg,int len) { @@ -281,6 +307,7 @@ static int do_mount(int argc, char ** argv) {"port",1,0,'o'}, {"uam",1,0,'a'}, {"map",1,0,'m'}, + {"options",1,0,'O'}, {0,0,0,0}, }; @@ -295,10 +322,11 @@ static int do_mount(int argc, char ** argv) outgoing_buffer[0]=AFP_SERVER_COMMAND_MOUNT; req->url.port=548; req->map=AFP_MAPPING_UNKNOWN; + req->fuse_options[0] = '\0'; while(1) { optnum++; - c = getopt_long(argc,argv,"a:u:m:o:p:v:V:", + c = getopt_long(argc,argv,"a:u:m:o:p:v:V:O:", long_options,&option_index); if (c==-1) break; switch(c) { @@ -326,16 +354,19 @@ static int do_mount(int argc, char ** argv) case 'v': req->url.requested_version=strtol(optarg,NULL,10); break; + case 'O': + snprintf( req->fuse_options, sizeof(req->fuse_options), "%s", optarg ); + break; } } if (strcmp(req->url.password, "-") == 0) { - char *p = getpass("AFP Password: "); + char *p = get_password("AFP Password: "); if (p) snprintf(req->url.password,AFP_MAX_PASSWORD_LEN,"%s",p); } if (strcmp(req->url.volpassword, "-") == 0) { - char *p = getpass("Password for volume: "); + char *p = get_password("Password for volume: "); if (p) snprintf(req->url.volpassword,9,"%s",p); } @@ -365,7 +396,6 @@ static int do_mount(int argc, char ** argv) snprintf(req->mountpoint,255,"%s",argv[optnum++]); - return 0; } @@ -462,13 +492,13 @@ static int handle_mount_afp(int argc, char * argv[]) return -1; } if (strcmp(req->url.password,"-")==0) { - char *p = getpass("AFP Password: "); + char *p = get_password("AFP Password: "); if (p) snprintf(req->url.password,AFP_MAX_PASSWORD_LEN,"%s",p); } if (volpass && (strcmp(volpass,"-")==0)) { - volpass = getpass("Password for volume: "); + volpass = get_password("Password for volume: "); } if (volpass) snprintf(req->url.volpassword,9,"%s",volpass); diff --git a/fuse/commands.c b/fuse/commands.c index aaed1e7..af263f0 100644 --- a/fuse/commands.c +++ b/fuse/commands.c @@ -5,6 +5,7 @@ * */ +#define _GNU_SOURCE #include #include #include @@ -35,11 +36,14 @@ #include "fuse_internal.h" #ifdef __linux -#define FUSE_DEVICE "/dev/fuse" +# define FUSE_DEVICE "/dev/fuse" #else -#define FUSE_DEVICE "/dev/fuse0" +# define FUSE_DEVICE "/dev/fuse0" #endif +# define FUSE_USE_VERSION 29 + +#include static int fuse_log_method=LOG_METHOD_SYSLOG; @@ -185,9 +189,46 @@ struct start_fuse_thread_arg { int fuse_result; int fuse_errno; int changeuid; + char *fuse_options; }; -static void * start_fuse_thread(void * other) +/* + * Remove commas from fsname, as it confuses the fuse option parser. + * Copied from sshfs.c + */ +static void fsname_remove_commas(char *fsname) +{ + if (strchr(fsname, ',') != NULL) { + char *s = fsname; + char *d = s; + + for (; *s; s++) { + if (*s != ',') + *d++ = *s; + } + *d = *s; + } +} + +// * Copied from sshfs.c +static char *fsname_escape_commas(char *fsnameold) +{ + char *fsname = malloc(strlen(fsnameold) * 2 + 1); + char *d = fsname; + char *s; + + for (s = fsnameold; *s; s++) { + if (*s == '\\' || *s == ',') + *d++ = '\\'; + *d++ = *s; + } + *d = '\0'; + free(fsnameold); + + return fsname; +} + +static void * start_fuse_thread(void * other) { int fuseargc=0; const char *fuseargv[200]; @@ -197,6 +238,8 @@ static void * start_fuse_thread(void * other) struct afp_volume * volume = arg->volume; struct fuse_client * c = arg->client; struct afp_server * server = volume->server; + char *fsname, *fsoption = NULL; + int libver = fuse_version(); /* Check to see if we have permissions to access the mountpoint */ @@ -222,6 +265,44 @@ static void * start_fuse_thread(void * other) fuseargv[fuseargc]="allow_other"; fuseargc++; } +// fuseargv[fuseargc] = "-osubtype=afpfs,fsname=foo@host"; +// fuseargc++; + asprintf( &fsname, "%s@%s:%s", server->username, server->server_name, volume->volume_name ); + if( libver >= 27 ){ + if( libver >= 28 ){ + fsname = fsname_escape_commas(fsname); + } + else{ + fsname_remove_commas(fsname); + } + asprintf( &fuseargv[fuseargc], "-osubtype=afpfs,fsname=%s", fsname ); + } + else{ + fsname_remove_commas(fsname); + asprintf( &fuseargv[fuseargc], "-ofsname=afpfs#%s", fsname ); + } + fsoption = fuseargv[fuseargc]; + fuseargc++; + + { int i; + char *msg = NULL; + asprintf( &msg, "\tfuse version=%d args={'%s'", + fuse_version(), fuseargv[0] ); + for( i = 1 ; i < fuseargc ; ++i ){ + asprintf( &msg, "%s,'%s'", msg, fuseargv[i] ); + } + log_for_client((void *) c, AFPFSD, LOG_WARNING, + "%s}\n", msg ); + if( msg ){ + free(msg); + } + } + if ( arg->fuse_options && strlen(arg->fuse_options) ) { + fuseargv[fuseargc]="-o"; + fuseargc++; + fuseargv[fuseargc] = arg->fuse_options; + fuseargc++; + } /* #ifdef USE_SINGLE_THREAD */ @@ -244,7 +325,14 @@ static void * start_fuse_thread(void * other) "Unmounting volume %s from %s\n", volume->volume_name_printable, volume->mountpoint); - + if( fsname ){ + free(fsname); + fsname = NULL; + } + if( fsoption ){ + free(fsoption); + fsoption = NULL; + } return NULL; } @@ -485,6 +573,7 @@ static int process_mount(struct fuse_client * c) arg.volume = volume; arg.wait = 1; arg.changeuid=req->changeuid; + arg.fuse_options = req->fuse_options; gettimeofday(&tv,NULL); ts.tv_sec=tv.tv_sec; diff --git a/fuse/fuse_internal.h b/fuse/fuse_internal.h index c25c759..734f554 100644 --- a/fuse/fuse_internal.h +++ b/fuse/fuse_internal.h @@ -1,7 +1,7 @@ #ifndef __FUSE_INTERNAL_H_ #define __FUSE_INTERNAL_H_ -#define AFP_CLIENT_INCOMING_BUF 2048 +#define AFP_CLIENT_INCOMING_BUF 2048+256 struct fuse_client {