--- src/smbmount.c.orig Sun Jun 9 09:58:43 2002 +++ src/smbmount.c Fri Apr 11 16:55:26 2003 @@ -16,6 +16,9 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +#include +#include +#include #include #include #include @@ -70,6 +73,9 @@ } UMOUNT_STRUCT; static GSList *umountlist = NULL; +void split_arguments(char * arguments, char * argv[], int * argnr, GSList ** strlist); +char * storeInBuffer(const char * s, GSList ** strlist); +void execvp_with_password(const char * path, char * const argv[], const char * passwd, GSList * strlist); char suprompt[] = "Passw"; @@ -322,6 +328,7 @@ int pipe2_nok,pipe3_nok=1; int sumount,argnr=-1,passw_lf; char commandstr[MAXMNTCOMMANDL],commandstr1[MAXMNTCOMMANDL]; + char num1[10], num2[10], num3[10], num4[10], tmp[MAXMNTCOMMANDL]; char opt_group[MAXMNTCOMMANDL]; char dummysmbpasswd[64]; /*#ifdef LINUX2_0 */ @@ -345,6 +352,7 @@ sumount=(supasswd!=NULL); passw_lf=(*smbpasswd==0) && !linux2_0; /*smbmount 2.0.3 always waits for password, even if called with -Uuser% or -N if server is in user level security*/ + passw_lf=1; if (sumount|| passw_lf) if (pipe(fdstdin)) { @@ -418,96 +426,53 @@ else { /* no sumount */ - if(linux2_0) { - argv[++argnr]="smbmount"; - argv[++argnr]=servicename; - argv[++argnr]=mount_point; - argv[++argnr]="-c"; - argv[++argnr]=clientname; - argv[++argnr]="-I"; - argv[++argnr]=ipaddr; - if (*group_name) + // bugfix: mount command might consist of more than one word (example: sudo mount_smbfs) + split_arguments(pref_get_smbmount_exe(), argv, &argnr, &strlist); { - argv[++argnr]="-D"; - argv[++argnr]=group_name; - } - argv[++argnr]="-U"; - argv[++argnr]=smbuser; - argv[++argnr]="-f";sprintf(filemodestr,"%d",filemode); - argv[++argnr]=filemodestr; - argv[++argnr]="-d";sprintf(dirmodestr,"%d",dirmode); - argv[++argnr]=dirmodestr; - argv[++argnr]="-u";sprintf(uidstr,"%d",uid); - argv[++argnr]=uidstr; - argv[++argnr]="-g";sprintf(gidstr,"%d",gid); - argv[++argnr]=gidstr; - if (*smbpasswd==0) - argv[++argnr]="-n"; - else - { - argv[++argnr]="-P"; - argv[++argnr]=smbpasswd; - } - argv[++argnr]=NULL; - } - else - { - /* linux 2.2/2.4 */ - argv[++argnr]=pref_get_smbmount_exe(); - argv[++argnr]=servicename; - if (pref.v.smbmount_version>SMBMOUNT_204) argv[++argnr]=mount_point; - if (pref.v.smbmount_version 2) + strcat(commandstr1, servicename+2); + argv[++argnr]="-f"; + argv[++argnr]=num1; + argv[++argnr]="-d"; + argv[++argnr]=num2; + argv[++argnr]="-u"; + argv[++argnr]=num3; + argv[++argnr]="-g"; + argv[++argnr]=num4; argv[++argnr]="-I"; - argv[++argnr]=ipaddr; + strcpy(tmp, ipaddr); + argv[++argnr]=tmp; if (*group_name) { argv[++argnr]="-W"; - argv[++argnr]=group_name; - } - sprintf(userpasswd,"-U%s%%%s",smbuser,smbpasswd); - argv[++argnr]=userpasswd; - argv[++argnr]="-d0"; - if (pref.v.smbmount_version =SMBMOUNT_206*/ - { - argv[++argnr]="-o"; - argv[++argnr]=commandstr; - sprintf(commandstr,"username=%s%%%s,fmask=%d,dmask=%d,uid=%d,gid=%d,ip=%s,debug=0", - smbuser,smbpasswd,filemode,dirmode,uid,gid,ipaddr); - if (*group_name) - { - strcat(commandstr,",workgroup="); - strcat(commandstr,escape_str(group_name,&strlist)); + argv[++argnr]= escape_str(group_name,&strlist); } if ( (port >= 0) && (port < 65536) ) { - string_ncat(commandstr, ",port=", MAXMNTCOMMANDL); - string_ncat(commandstr, port_str, MAXMNTCOMMANDL); + strcat(tmp, ":"); + strcat(tmp, port_str); } if ( !is_empty_string(pref.v.smbmount_arg) ) { - if ( pref.v.smbmount_arg[0] != ',' ) - string_ncat(commandstr, ",", MAXMNTCOMMANDL); - string_ncat(commandstr, escape_str(pref.v.smbmount_arg,&strlist), MAXMNTCOMMANDL); + split_arguments(pref.v.smbmount_arg, argv, &argnr, &strlist); } } + argv[++argnr]=commandstr1; + argv[++argnr]=mount_point; argv[++argnr]=NULL; } } - slist_free_with_data(&strlist); mountdat=g_malloc(sizeof(MOUNT_STRUCT)); if((pipe2_nok=pipe(fdstdout))|| (pipe3_nok=pipe(fdstderr))|| (mountdat->childpid =fork())== -1) @@ -521,7 +486,6 @@ g_print(_("smbmount pipe,fork error\n")); return; } - if (!mountdat->childpid) { close(fdstdout[0]); @@ -536,7 +500,7 @@ if (sumount) execvp("su",argv); else - execvp(pref_get_smbmount_exe(),argv); + execvp_with_password(argv[0], argv, smbpasswd, strlist); write(STDERR_FILENO,notfound,sizeof(notfound)-1); _exit(0); } @@ -547,9 +511,9 @@ else { i=0; - while(argv[i+1]) + while(argv[i]) { - mountdat->arglist[i]=g_strdup(argv[i+1]); + mountdat->arglist[i]=g_strdup(argv[i]); i++; } mountdat->arglist[i]=NULL; @@ -611,46 +575,9 @@ } else { - if(linux2_0) - { - if (*smbpasswd!=0) argv[argnr-1]=dummysmbpasswd; - } - else - { - if (pref.v.smbmount_versionchildpid,NULL,WNOHANG)) - write(fdstdin[1], "\n",1); + log_execvp_str(argv[0],argv); close(fdstdin[1]); } - } - - log_execvp_str(pref_get_smbmount_exe(),argv); - } mountlist=g_slist_append(mountlist,mountdat); mountdat->linepos=0; mountdat->linepos2=0; mountdat->linenum=0; @@ -901,17 +828,13 @@ } else { - argv[0]=smb ? "smbumount":"umount"; - argv[1]=mount_point; + // bugfix: mount command might consist of more than one word (example: sudo mount_smbfs) + int argnr = -1; + split_arguments(pref_get_smbumount_exe(), argv, &argnr, &strlist); if ( !is_empty_string(pref.v.smbumount_arg) ) - { - argv[2] = pref.v.smbumount_arg; - argv[3] = NULL; - } - else - { - argv[2]=NULL; - } + split_arguments(pref.v.smbumount_arg, argv, &argnr, &strlist); + argv[++argnr]=mount_point; + argv[++argnr] = NULL; } if((pipe2_nok=pipe(fdstdout))|| (pipe3_nok=pipe(fdstderr))|| (childpid =fork())== -1) @@ -938,7 +861,7 @@ execvp("su",argv); } else - execvp(smb ? pref_get_smbumount_exe():"umount",argv); + execvp_with_password(argv[0], argv, "", strlist); write(STDERR_FILENO,notfound,sizeof(notfound)-1); _exit(0); } @@ -958,7 +881,7 @@ gui_log_window_insert_string("*",0); } else - log_execvp_str(smb ? pref_get_smbumount_exe():"umount",argv); + log_execvp_str(argv[0], argv); mountdat=g_malloc(sizeof(UMOUNT_STRUCT)); umountlist=g_slist_append(umountlist,mountdat); mountdat->childpid=childpid; @@ -1015,6 +938,198 @@ slist_free_with_data(&umountlist); } +void split_arguments(char * arguments, char * argv[], int * argnr, GSList ** strlist) +{ + char * c = argv[++*argnr] = storeInBuffer(arguments, strlist); + while(c = strchr(c, ' ')) + { + char *d = c+1; + while(*d && *d == ' ') + d++; + *c = 0; + c = d; + if (!*c) + break; + argv[++*argnr] = storeInBuffer(c, strlist); + } +} + +char * storeInBuffer(const char * s, GSList ** strlist) +{ + int n; + char * ss; + + if (*s==0) return 0; + n = strlen(s); + ss=g_malloc(n+1); + strcpy(ss, s); + *strlist=g_slist_append(*strlist,ss); + return ss; +} + + +// this looks like a global variable. But each forked execvp_with_password +// process has one copy of it. So it as a process local varible storing the +// process ID of the forked child process, which actaully execs mount_smbfs +int _childPid = 0; + +// called, if the child proces is killed. Kills its child process as well +void stopMountSignalHandler (int sig) +{ + kill(_childPid, SIGINT); + waitpid(_childPid, 0, WUNTRACED); + _exit(0); +} + +// replaces execvp to call mount_smbfs. If mount smbfs asks for a password, it is provided. +// This can not be sent to stdin, because BSD gets the password directly from the terminal. +// Therfore another process with a pseudo terminal is created. +void execvp_with_password(const char * path, char * const argv[], const char * passwd, GSList *strlist) +{ + int master, i; + char terminal[MAXPATHLEN] = ""; + char * pw = NULL; + int slave; + char password[1024], result[1024]; + char * passwordText = "password:"; + int passwordTextLen = strlen(passwordText); + char * resp_pos = result; + int fdstderr[2]; + + // create a pipe to the child process for stderr. For stdout the pseudo terminal is used + if(pipe(fdstderr)) + { + fdstderr[0] = 0; + fdstderr[1] = 0; + } + + // create the child process and the pseudo terminal + _childPid = forkpty(&master, terminal, NULL, NULL); + + if (_childPid < 0) + { + if (errno == ENOENT) + printf("Error: Out of ptys\n"); + else + printf(result, "Error: Forkpty\n"); + _exit(1); + } + else if (_childPid == 0) + { + // prepare stderr pipe + if (fdstderr[0]) + { + close(fdstderr[0]); + dup2(fdstderr[1], STDERR_FILENO); + } + + // prepare the pseudo terminal + close(master); + slave = open(terminal, O_RDWR); + if (slave < 0) + { + printf("open() failed: %s", strerror(errno)); + kill(_childPid, SIGINT); + waitpid(_childPid, 0, WUNTRACED); + _exit(1); + } + // launch application (mount_smbfs) + execvp(path, argv); + printf("error: %d (%s)\n", errno, strerror(errno)); + } + else + { + // prepare the stderr pipe + if (fdstderr[1]) + close(fdstderr[1]); + // install the SIGIN (ctrl-c) handler + if (signal(SIGINT, stopMountSignalHandler) == SIG_ERR) + printf("error: can not install SIGINT handler\n"); + errno = 0; + *resp_pos = 0; + + // main loop: wait for childs response + while (!errno) + { + // prepare a poll, wich waits for output from the pseudo terminal and from stderr + int pollnum = 1; + struct pollfd polldat[2]; + polldat[0].fd = master; + polldat[0].events = POLLIN | POLLRDNORM | POLLRDBAND | POLLPRI; + if (fdstderr[0]) + { + pollnum = 2; + polldat[1].fd = fdstderr[0]; + polldat[1].events = POLLIN | POLLRDNORM | POLLRDBAND | POLLPRI; + } + + // sleep until the child terminates or sends something + if (poll(polldat, pollnum, 1000) < 0) + break; + // response from childs stderr? + if (pollnum == 2 && polldat[1].revents) + { + // read response and send it to this process' stderr. It is connected + // with another pipe with the main process! + char s[1024]; + int i = read(fdstderr[0], s, 1024); + if (errno) + break; + if (i > 0) + { + s[i] = 0; + write(STDERR_FILENO, s, i); + } + } + + // response from childs stdout? + if (polldat[0].revents) + { + // read response and send it to this process' stdout. It is connected + // with another pipe with the main process. If the string 'password' + // was send, provide the password + char c; + if (read(master, &c, 1) <= 0 || errno) + break; + if (resp_pos - result < sizeof(result)) + *resp_pos++ = c; + *resp_pos = 0; + if (c == '\n') + { + printf("%s", result); + resp_pos = result; + } + *resp_pos = 0; + if (resp_pos - result >= passwordTextLen && !strcasecmp(resp_pos-passwordTextLen, passwordText)) + { + // prepare the password and send it through the pseudo terminal + strcpy(password, passwd); + strcat(password, "\n"); + resp_pos = result; + *resp_pos = 0; + write(master, password, strlen(password)); + } + } + // if the child is dead, end main loop + if (waitpid(_childPid,NULL,WNOHANG)) + break; + } + + // if there is unsend response, send it to the main process + printf("%s", result); + + // free resources + if (fdstderr[0]) + close(fdstderr[0]); + close(master); + slist_free_with_data(&strlist); + + // get childs return code to avoid zombies + waitpid(_childPid, 0, WUNTRACED); + _exit(0); + } + _exit(-1); // can not be reached +}