Run command from sudo su The 2019 Stack Overflow Developer Survey Results Are In ...

How many people can fit inside Mordenkainen's Magnificent Mansion?

Semisimplicity of the category of coherent sheaves?

Does Parliament hold absolute power in the UK?

ELI5: Why do they say that Israel would have been the fourth country to land a spacecraft on the Moon and why do they call it low cost?

Make it rain characters

Did the UK government pay "millions and millions of dollars" to try to snag Julian Assange?

Can a 1st-level character have an ability score above 18?

How did passengers keep warm on sail ships?

Did God make two great lights or did He make the great light two?

Problems with Ubuntu mount /tmp

How are presidential pardons supposed to be used?

Difference between "generating set" and free product?

Scientific Reports - Significant Figures

Can withdrawing asylum be illegal?

Why did all the guest students take carriages to the Yule Ball?

How can I protect witches in combat who wear limited clothing?

Match Roman Numerals

Simulating Exploding Dice

What do you call a plan that's an alternative plan in case your initial plan fails?

How should I replace vector<uint8_t>::const_iterator in an API?

Who or what is the being for whom Being is a question for Heidegger?

"... to apply for a visa" or "... and applied for a visa"?

Do warforged have souls?

Can a novice safely splice in wire to lengthen 5V charging cable?



Run command from sudo su



The 2019 Stack Overflow Developer Survey Results Are In
Announcing the arrival of Valued Associate #679: Cesar Manara
Planned maintenance scheduled April 17/18, 2019 at 00:00UTC (8:00pm US/Eastern)SSH: execute sudo commandsudo access to view/edit a crontabsudo prompts for password over sshsudo to run command as different userAccidentally change sudo user to /bin/falseSudo user is not able to export path of antsudo-users Executing and Runnning Commands RecursivelyLast background process ID ($!) not working in sudo bash commandSudo command with password in Powershellsudo minikube returns “command not found”





.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty{ height:90px;width:728px;box-sizing:border-box;
}







1















On a machine I (tlous) have been given access to open a shell as another user (serviceAccount)



Executing: sudo su - serviceAccount has the desired effect of opening a shell as this serviceAccount user. So far so good.



This is nice, but I want to run a command as this user without opening a shell.



Let's say the command is whoami



I've tried:



sudo -u serviceAccount whoami




Sorry, user tlous is not allowed to execute '/usr/bin/whoami' as serviceAccount ...




sudo su - serviceAccount -c whoami




Sorry, user tlous is not allowed to execute '/bin/su - serviceAccount -c whoami' ...




And other variations.
What am I missing? Can this be done in a oneliner?
The reason is that I actually want to run this as an ssh command:
ssh -t tlous@server.example.com sudo su - serviceAccount -c whoami










share|improve this question







New contributor




Tom Lous is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.



























    1















    On a machine I (tlous) have been given access to open a shell as another user (serviceAccount)



    Executing: sudo su - serviceAccount has the desired effect of opening a shell as this serviceAccount user. So far so good.



    This is nice, but I want to run a command as this user without opening a shell.



    Let's say the command is whoami



    I've tried:



    sudo -u serviceAccount whoami




    Sorry, user tlous is not allowed to execute '/usr/bin/whoami' as serviceAccount ...




    sudo su - serviceAccount -c whoami




    Sorry, user tlous is not allowed to execute '/bin/su - serviceAccount -c whoami' ...




    And other variations.
    What am I missing? Can this be done in a oneliner?
    The reason is that I actually want to run this as an ssh command:
    ssh -t tlous@server.example.com sudo su - serviceAccount -c whoami










    share|improve this question







    New contributor




    Tom Lous is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
    Check out our Code of Conduct.























      1












      1








      1


      0






      On a machine I (tlous) have been given access to open a shell as another user (serviceAccount)



      Executing: sudo su - serviceAccount has the desired effect of opening a shell as this serviceAccount user. So far so good.



      This is nice, but I want to run a command as this user without opening a shell.



      Let's say the command is whoami



      I've tried:



      sudo -u serviceAccount whoami




      Sorry, user tlous is not allowed to execute '/usr/bin/whoami' as serviceAccount ...




      sudo su - serviceAccount -c whoami




      Sorry, user tlous is not allowed to execute '/bin/su - serviceAccount -c whoami' ...




      And other variations.
      What am I missing? Can this be done in a oneliner?
      The reason is that I actually want to run this as an ssh command:
      ssh -t tlous@server.example.com sudo su - serviceAccount -c whoami










      share|improve this question







      New contributor




      Tom Lous is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.












      On a machine I (tlous) have been given access to open a shell as another user (serviceAccount)



      Executing: sudo su - serviceAccount has the desired effect of opening a shell as this serviceAccount user. So far so good.



      This is nice, but I want to run a command as this user without opening a shell.



      Let's say the command is whoami



      I've tried:



      sudo -u serviceAccount whoami




      Sorry, user tlous is not allowed to execute '/usr/bin/whoami' as serviceAccount ...




      sudo su - serviceAccount -c whoami




      Sorry, user tlous is not allowed to execute '/bin/su - serviceAccount -c whoami' ...




      And other variations.
      What am I missing? Can this be done in a oneliner?
      The reason is that I actually want to run this as an ssh command:
      ssh -t tlous@server.example.com sudo su - serviceAccount -c whoami







      bash shell sudo su






      share|improve this question







      New contributor




      Tom Lous is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.











      share|improve this question







      New contributor




      Tom Lous is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.









      share|improve this question




      share|improve this question






      New contributor




      Tom Lous is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.









      asked yesterday









      Tom LousTom Lous

      1063




      1063




      New contributor




      Tom Lous is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.





      New contributor





      Tom Lous is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.






      Tom Lous is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.






















          1 Answer
          1






          active

          oldest

          votes


















          0














          Probably the sudoers file on the remote side specifies the exact command you can run and it's su - serviceAccount. One or more additional options (like -c) will make the command not qualify. Any solution should use the exact su - serviceAccount command.



          There is a way to do something about it, but it's not perfect. Start by running this on the server:



          echo whoami | sudo su - serviceAccount


          (sudo without -S will use the terminal to ask for your password (if needed) despite the redirection).



          To make the approach more general, create a script on the server:



          #!/bin/sh
          printf '%s ' "@" | sudo su - serviceAccount


          Save it as su-ser, and make it executable. Now you can test these:



          ./su-ser whoami
          ./su-ser 'whoami; whoami'
          ./su-ser ls -l
          ./su-ser 'ls -l'


          Note these quotes don't propagate to the shell spawned by su. Each time printf builds a command from arguments that the script gets, this is passed as a string and then parsed by the final shell, with word splitting, globbing and such. This means all these



          ./su-ser echo 1 2 3
          ./su-ser echo "1 2 3"
          ./su-ser "echo 1 2 3"


          will print 1 2 3. To pass a quoted string you need to quote quotes, e.g.:



          ./su-ser 'echo "1 2             3"'


          The next step is to trigger this remote script from your local computer:



          ssh -t tlous@server.example.com '"/path/to/su-ser" whoami'


          You need -t in case sudo asks for the password. From the ssh command in your question body I can tell you probably understand this.



          Note ssh also builds a command string. The above quoting would work even if /path/to/su-ser contained spaces. On the other hand, if the path is without spaces (and without characters like ;, *), a totally unquoted ssh … /path/to/su-ser whoami will work as well.



          Proper quoting is not a trivial task at this point. Let's analyze what happens to the command.




          1. At first your local shell parses the string. It uses the most outer quotes (if any) to parse it right.


          2. ssh gets its arguments as an array. The quotes used up by the shell don't get this far.


          3. ssh decides which arguments should be passed to the remote side and builds a string (in similar manner to printf in our remote script).

          4. This string is then parsed by the remote shell (the one spawned by sshd on the server). The remote shell uses the (now) most outer quotes (if any) to parse it right.


          5. su-ser gets its arguments as an array. The quotes used up by the remote shell don't get this far.


          6. su-ser builds a string.

          7. This string is then parsed by yet another shell (spawned by su on the server). The shell uses the (now) most outer quotes (if any) to parse it right.

          8. The command(s) you passed gets its arguments as an array. The quotes used up by the last shell don't get this far.


          This means sometimes you need three levels of quotes to get the right result. An uncomplicated local command like



          echo "1 2             3"


          becomes



          ssh -t tlous@server.example.com "'/path/to/su-ser' 'echo "1 2             3"'"


          where the unescaped double-quotes get stripped by the local shell, the single-quotes get stripped by the remote shell; finally the escaped double-quotes (that in fact become unescaped as soon as the local shell strips the unescaped ones) tell the shell spawned by su that the string with multiple spaces is a single argument to echo. This way the output is



          1 2             3




          Another problem is the remote script passes commands to stdin of the final shell, so you cant easily use its stdin for another purpose. E.g. cat; whoami (try it) should print back whatever lines you type (terminate it with Ctrl+D), then the output of whoami. However if you run this on the server:



          ./su-ser 'cat; whoami'


          cat will terminate immediately. This should work:



          ./su-ser 'cat /dev/tty; whoami'


          (Again, use Ctrl+D to terminate cat). Now compare the behavior of this:



          ./su-ser '
          whoami
          whoami
          whoami
          '


          to this:



          ./su-ser '
          whoami
          cat
          whoami
          '


          The same stream feeds cat and the shell; it's not a good thing. Establishing separate channels for actual commands and the real stdin may not be easy because sudo by default closes additional file descriptors and sets a new, minimal environment. I guess a contraption using temporary files/fifos would work, but this is so hairy I won't even try.



          So the script may or may not be enough for you; it depends on commands you need to run. Now you know a couple of its limitations. Good luck.






          share|improve this answer


























            Your Answer








            StackExchange.ready(function() {
            var channelOptions = {
            tags: "".split(" "),
            id: "3"
            };
            initTagRenderer("".split(" "), "".split(" "), channelOptions);

            StackExchange.using("externalEditor", function() {
            // Have to fire editor after snippets, if snippets enabled
            if (StackExchange.settings.snippets.snippetsEnabled) {
            StackExchange.using("snippets", function() {
            createEditor();
            });
            }
            else {
            createEditor();
            }
            });

            function createEditor() {
            StackExchange.prepareEditor({
            heartbeatType: 'answer',
            autoActivateHeartbeat: false,
            convertImagesToLinks: true,
            noModals: true,
            showLowRepImageUploadWarning: true,
            reputationToPostImages: 10,
            bindNavPrevention: true,
            postfix: "",
            imageUploader: {
            brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
            contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
            allowUrls: true
            },
            onDemand: true,
            discardSelector: ".discard-answer"
            ,immediatelyShowMarkdownHelp:true
            });


            }
            });






            Tom Lous is a new contributor. Be nice, and check out our Code of Conduct.










            draft saved

            draft discarded


















            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fsuperuser.com%2fquestions%2f1424578%2frun-command-from-sudo-su%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown

























            1 Answer
            1






            active

            oldest

            votes








            1 Answer
            1






            active

            oldest

            votes









            active

            oldest

            votes






            active

            oldest

            votes









            0














            Probably the sudoers file on the remote side specifies the exact command you can run and it's su - serviceAccount. One or more additional options (like -c) will make the command not qualify. Any solution should use the exact su - serviceAccount command.



            There is a way to do something about it, but it's not perfect. Start by running this on the server:



            echo whoami | sudo su - serviceAccount


            (sudo without -S will use the terminal to ask for your password (if needed) despite the redirection).



            To make the approach more general, create a script on the server:



            #!/bin/sh
            printf '%s ' "@" | sudo su - serviceAccount


            Save it as su-ser, and make it executable. Now you can test these:



            ./su-ser whoami
            ./su-ser 'whoami; whoami'
            ./su-ser ls -l
            ./su-ser 'ls -l'


            Note these quotes don't propagate to the shell spawned by su. Each time printf builds a command from arguments that the script gets, this is passed as a string and then parsed by the final shell, with word splitting, globbing and such. This means all these



            ./su-ser echo 1 2 3
            ./su-ser echo "1 2 3"
            ./su-ser "echo 1 2 3"


            will print 1 2 3. To pass a quoted string you need to quote quotes, e.g.:



            ./su-ser 'echo "1 2             3"'


            The next step is to trigger this remote script from your local computer:



            ssh -t tlous@server.example.com '"/path/to/su-ser" whoami'


            You need -t in case sudo asks for the password. From the ssh command in your question body I can tell you probably understand this.



            Note ssh also builds a command string. The above quoting would work even if /path/to/su-ser contained spaces. On the other hand, if the path is without spaces (and without characters like ;, *), a totally unquoted ssh … /path/to/su-ser whoami will work as well.



            Proper quoting is not a trivial task at this point. Let's analyze what happens to the command.




            1. At first your local shell parses the string. It uses the most outer quotes (if any) to parse it right.


            2. ssh gets its arguments as an array. The quotes used up by the shell don't get this far.


            3. ssh decides which arguments should be passed to the remote side and builds a string (in similar manner to printf in our remote script).

            4. This string is then parsed by the remote shell (the one spawned by sshd on the server). The remote shell uses the (now) most outer quotes (if any) to parse it right.


            5. su-ser gets its arguments as an array. The quotes used up by the remote shell don't get this far.


            6. su-ser builds a string.

            7. This string is then parsed by yet another shell (spawned by su on the server). The shell uses the (now) most outer quotes (if any) to parse it right.

            8. The command(s) you passed gets its arguments as an array. The quotes used up by the last shell don't get this far.


            This means sometimes you need three levels of quotes to get the right result. An uncomplicated local command like



            echo "1 2             3"


            becomes



            ssh -t tlous@server.example.com "'/path/to/su-ser' 'echo "1 2             3"'"


            where the unescaped double-quotes get stripped by the local shell, the single-quotes get stripped by the remote shell; finally the escaped double-quotes (that in fact become unescaped as soon as the local shell strips the unescaped ones) tell the shell spawned by su that the string with multiple spaces is a single argument to echo. This way the output is



            1 2             3




            Another problem is the remote script passes commands to stdin of the final shell, so you cant easily use its stdin for another purpose. E.g. cat; whoami (try it) should print back whatever lines you type (terminate it with Ctrl+D), then the output of whoami. However if you run this on the server:



            ./su-ser 'cat; whoami'


            cat will terminate immediately. This should work:



            ./su-ser 'cat /dev/tty; whoami'


            (Again, use Ctrl+D to terminate cat). Now compare the behavior of this:



            ./su-ser '
            whoami
            whoami
            whoami
            '


            to this:



            ./su-ser '
            whoami
            cat
            whoami
            '


            The same stream feeds cat and the shell; it's not a good thing. Establishing separate channels for actual commands and the real stdin may not be easy because sudo by default closes additional file descriptors and sets a new, minimal environment. I guess a contraption using temporary files/fifos would work, but this is so hairy I won't even try.



            So the script may or may not be enough for you; it depends on commands you need to run. Now you know a couple of its limitations. Good luck.






            share|improve this answer






























              0














              Probably the sudoers file on the remote side specifies the exact command you can run and it's su - serviceAccount. One or more additional options (like -c) will make the command not qualify. Any solution should use the exact su - serviceAccount command.



              There is a way to do something about it, but it's not perfect. Start by running this on the server:



              echo whoami | sudo su - serviceAccount


              (sudo without -S will use the terminal to ask for your password (if needed) despite the redirection).



              To make the approach more general, create a script on the server:



              #!/bin/sh
              printf '%s ' "@" | sudo su - serviceAccount


              Save it as su-ser, and make it executable. Now you can test these:



              ./su-ser whoami
              ./su-ser 'whoami; whoami'
              ./su-ser ls -l
              ./su-ser 'ls -l'


              Note these quotes don't propagate to the shell spawned by su. Each time printf builds a command from arguments that the script gets, this is passed as a string and then parsed by the final shell, with word splitting, globbing and such. This means all these



              ./su-ser echo 1 2 3
              ./su-ser echo "1 2 3"
              ./su-ser "echo 1 2 3"


              will print 1 2 3. To pass a quoted string you need to quote quotes, e.g.:



              ./su-ser 'echo "1 2             3"'


              The next step is to trigger this remote script from your local computer:



              ssh -t tlous@server.example.com '"/path/to/su-ser" whoami'


              You need -t in case sudo asks for the password. From the ssh command in your question body I can tell you probably understand this.



              Note ssh also builds a command string. The above quoting would work even if /path/to/su-ser contained spaces. On the other hand, if the path is without spaces (and without characters like ;, *), a totally unquoted ssh … /path/to/su-ser whoami will work as well.



              Proper quoting is not a trivial task at this point. Let's analyze what happens to the command.




              1. At first your local shell parses the string. It uses the most outer quotes (if any) to parse it right.


              2. ssh gets its arguments as an array. The quotes used up by the shell don't get this far.


              3. ssh decides which arguments should be passed to the remote side and builds a string (in similar manner to printf in our remote script).

              4. This string is then parsed by the remote shell (the one spawned by sshd on the server). The remote shell uses the (now) most outer quotes (if any) to parse it right.


              5. su-ser gets its arguments as an array. The quotes used up by the remote shell don't get this far.


              6. su-ser builds a string.

              7. This string is then parsed by yet another shell (spawned by su on the server). The shell uses the (now) most outer quotes (if any) to parse it right.

              8. The command(s) you passed gets its arguments as an array. The quotes used up by the last shell don't get this far.


              This means sometimes you need three levels of quotes to get the right result. An uncomplicated local command like



              echo "1 2             3"


              becomes



              ssh -t tlous@server.example.com "'/path/to/su-ser' 'echo "1 2             3"'"


              where the unescaped double-quotes get stripped by the local shell, the single-quotes get stripped by the remote shell; finally the escaped double-quotes (that in fact become unescaped as soon as the local shell strips the unescaped ones) tell the shell spawned by su that the string with multiple spaces is a single argument to echo. This way the output is



              1 2             3




              Another problem is the remote script passes commands to stdin of the final shell, so you cant easily use its stdin for another purpose. E.g. cat; whoami (try it) should print back whatever lines you type (terminate it with Ctrl+D), then the output of whoami. However if you run this on the server:



              ./su-ser 'cat; whoami'


              cat will terminate immediately. This should work:



              ./su-ser 'cat /dev/tty; whoami'


              (Again, use Ctrl+D to terminate cat). Now compare the behavior of this:



              ./su-ser '
              whoami
              whoami
              whoami
              '


              to this:



              ./su-ser '
              whoami
              cat
              whoami
              '


              The same stream feeds cat and the shell; it's not a good thing. Establishing separate channels for actual commands and the real stdin may not be easy because sudo by default closes additional file descriptors and sets a new, minimal environment. I guess a contraption using temporary files/fifos would work, but this is so hairy I won't even try.



              So the script may or may not be enough for you; it depends on commands you need to run. Now you know a couple of its limitations. Good luck.






              share|improve this answer




























                0












                0








                0







                Probably the sudoers file on the remote side specifies the exact command you can run and it's su - serviceAccount. One or more additional options (like -c) will make the command not qualify. Any solution should use the exact su - serviceAccount command.



                There is a way to do something about it, but it's not perfect. Start by running this on the server:



                echo whoami | sudo su - serviceAccount


                (sudo without -S will use the terminal to ask for your password (if needed) despite the redirection).



                To make the approach more general, create a script on the server:



                #!/bin/sh
                printf '%s ' "@" | sudo su - serviceAccount


                Save it as su-ser, and make it executable. Now you can test these:



                ./su-ser whoami
                ./su-ser 'whoami; whoami'
                ./su-ser ls -l
                ./su-ser 'ls -l'


                Note these quotes don't propagate to the shell spawned by su. Each time printf builds a command from arguments that the script gets, this is passed as a string and then parsed by the final shell, with word splitting, globbing and such. This means all these



                ./su-ser echo 1 2 3
                ./su-ser echo "1 2 3"
                ./su-ser "echo 1 2 3"


                will print 1 2 3. To pass a quoted string you need to quote quotes, e.g.:



                ./su-ser 'echo "1 2             3"'


                The next step is to trigger this remote script from your local computer:



                ssh -t tlous@server.example.com '"/path/to/su-ser" whoami'


                You need -t in case sudo asks for the password. From the ssh command in your question body I can tell you probably understand this.



                Note ssh also builds a command string. The above quoting would work even if /path/to/su-ser contained spaces. On the other hand, if the path is without spaces (and without characters like ;, *), a totally unquoted ssh … /path/to/su-ser whoami will work as well.



                Proper quoting is not a trivial task at this point. Let's analyze what happens to the command.




                1. At first your local shell parses the string. It uses the most outer quotes (if any) to parse it right.


                2. ssh gets its arguments as an array. The quotes used up by the shell don't get this far.


                3. ssh decides which arguments should be passed to the remote side and builds a string (in similar manner to printf in our remote script).

                4. This string is then parsed by the remote shell (the one spawned by sshd on the server). The remote shell uses the (now) most outer quotes (if any) to parse it right.


                5. su-ser gets its arguments as an array. The quotes used up by the remote shell don't get this far.


                6. su-ser builds a string.

                7. This string is then parsed by yet another shell (spawned by su on the server). The shell uses the (now) most outer quotes (if any) to parse it right.

                8. The command(s) you passed gets its arguments as an array. The quotes used up by the last shell don't get this far.


                This means sometimes you need three levels of quotes to get the right result. An uncomplicated local command like



                echo "1 2             3"


                becomes



                ssh -t tlous@server.example.com "'/path/to/su-ser' 'echo "1 2             3"'"


                where the unescaped double-quotes get stripped by the local shell, the single-quotes get stripped by the remote shell; finally the escaped double-quotes (that in fact become unescaped as soon as the local shell strips the unescaped ones) tell the shell spawned by su that the string with multiple spaces is a single argument to echo. This way the output is



                1 2             3




                Another problem is the remote script passes commands to stdin of the final shell, so you cant easily use its stdin for another purpose. E.g. cat; whoami (try it) should print back whatever lines you type (terminate it with Ctrl+D), then the output of whoami. However if you run this on the server:



                ./su-ser 'cat; whoami'


                cat will terminate immediately. This should work:



                ./su-ser 'cat /dev/tty; whoami'


                (Again, use Ctrl+D to terminate cat). Now compare the behavior of this:



                ./su-ser '
                whoami
                whoami
                whoami
                '


                to this:



                ./su-ser '
                whoami
                cat
                whoami
                '


                The same stream feeds cat and the shell; it's not a good thing. Establishing separate channels for actual commands and the real stdin may not be easy because sudo by default closes additional file descriptors and sets a new, minimal environment. I guess a contraption using temporary files/fifos would work, but this is so hairy I won't even try.



                So the script may or may not be enough for you; it depends on commands you need to run. Now you know a couple of its limitations. Good luck.






                share|improve this answer















                Probably the sudoers file on the remote side specifies the exact command you can run and it's su - serviceAccount. One or more additional options (like -c) will make the command not qualify. Any solution should use the exact su - serviceAccount command.



                There is a way to do something about it, but it's not perfect. Start by running this on the server:



                echo whoami | sudo su - serviceAccount


                (sudo without -S will use the terminal to ask for your password (if needed) despite the redirection).



                To make the approach more general, create a script on the server:



                #!/bin/sh
                printf '%s ' "@" | sudo su - serviceAccount


                Save it as su-ser, and make it executable. Now you can test these:



                ./su-ser whoami
                ./su-ser 'whoami; whoami'
                ./su-ser ls -l
                ./su-ser 'ls -l'


                Note these quotes don't propagate to the shell spawned by su. Each time printf builds a command from arguments that the script gets, this is passed as a string and then parsed by the final shell, with word splitting, globbing and such. This means all these



                ./su-ser echo 1 2 3
                ./su-ser echo "1 2 3"
                ./su-ser "echo 1 2 3"


                will print 1 2 3. To pass a quoted string you need to quote quotes, e.g.:



                ./su-ser 'echo "1 2             3"'


                The next step is to trigger this remote script from your local computer:



                ssh -t tlous@server.example.com '"/path/to/su-ser" whoami'


                You need -t in case sudo asks for the password. From the ssh command in your question body I can tell you probably understand this.



                Note ssh also builds a command string. The above quoting would work even if /path/to/su-ser contained spaces. On the other hand, if the path is without spaces (and without characters like ;, *), a totally unquoted ssh … /path/to/su-ser whoami will work as well.



                Proper quoting is not a trivial task at this point. Let's analyze what happens to the command.




                1. At first your local shell parses the string. It uses the most outer quotes (if any) to parse it right.


                2. ssh gets its arguments as an array. The quotes used up by the shell don't get this far.


                3. ssh decides which arguments should be passed to the remote side and builds a string (in similar manner to printf in our remote script).

                4. This string is then parsed by the remote shell (the one spawned by sshd on the server). The remote shell uses the (now) most outer quotes (if any) to parse it right.


                5. su-ser gets its arguments as an array. The quotes used up by the remote shell don't get this far.


                6. su-ser builds a string.

                7. This string is then parsed by yet another shell (spawned by su on the server). The shell uses the (now) most outer quotes (if any) to parse it right.

                8. The command(s) you passed gets its arguments as an array. The quotes used up by the last shell don't get this far.


                This means sometimes you need three levels of quotes to get the right result. An uncomplicated local command like



                echo "1 2             3"


                becomes



                ssh -t tlous@server.example.com "'/path/to/su-ser' 'echo "1 2             3"'"


                where the unescaped double-quotes get stripped by the local shell, the single-quotes get stripped by the remote shell; finally the escaped double-quotes (that in fact become unescaped as soon as the local shell strips the unescaped ones) tell the shell spawned by su that the string with multiple spaces is a single argument to echo. This way the output is



                1 2             3




                Another problem is the remote script passes commands to stdin of the final shell, so you cant easily use its stdin for another purpose. E.g. cat; whoami (try it) should print back whatever lines you type (terminate it with Ctrl+D), then the output of whoami. However if you run this on the server:



                ./su-ser 'cat; whoami'


                cat will terminate immediately. This should work:



                ./su-ser 'cat /dev/tty; whoami'


                (Again, use Ctrl+D to terminate cat). Now compare the behavior of this:



                ./su-ser '
                whoami
                whoami
                whoami
                '


                to this:



                ./su-ser '
                whoami
                cat
                whoami
                '


                The same stream feeds cat and the shell; it's not a good thing. Establishing separate channels for actual commands and the real stdin may not be easy because sudo by default closes additional file descriptors and sets a new, minimal environment. I guess a contraption using temporary files/fifos would work, but this is so hairy I won't even try.



                So the script may or may not be enough for you; it depends on commands you need to run. Now you know a couple of its limitations. Good luck.







                share|improve this answer














                share|improve this answer



                share|improve this answer








                edited 19 hours ago

























                answered yesterday









                Kamil MaciorowskiKamil Maciorowski

                29.2k156288




                29.2k156288






















                    Tom Lous is a new contributor. Be nice, and check out our Code of Conduct.










                    draft saved

                    draft discarded


















                    Tom Lous is a new contributor. Be nice, and check out our Code of Conduct.













                    Tom Lous is a new contributor. Be nice, and check out our Code of Conduct.












                    Tom Lous is a new contributor. Be nice, and check out our Code of Conduct.
















                    Thanks for contributing an answer to Super User!


                    • Please be sure to answer the question. Provide details and share your research!

                    But avoid



                    • Asking for help, clarification, or responding to other answers.

                    • Making statements based on opinion; back them up with references or personal experience.


                    To learn more, see our tips on writing great answers.




                    draft saved


                    draft discarded














                    StackExchange.ready(
                    function () {
                    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fsuperuser.com%2fquestions%2f1424578%2frun-command-from-sudo-su%23new-answer', 'question_page');
                    }
                    );

                    Post as a guest















                    Required, but never shown





















































                    Required, but never shown














                    Required, but never shown












                    Required, but never shown







                    Required, but never shown

































                    Required, but never shown














                    Required, but never shown












                    Required, but never shown







                    Required, but never shown







                    Popular posts from this blog

                    Couldn't open a raw socket. Error: Permission denied (13) (nmap)Is it possible to run networking commands...

                    VNC viewer RFB protocol error: bad desktop size 0x0I Cannot Type the Key 'd' (lowercase) in VNC Viewer...

                    Why not use the yoke to control yaw, as well as pitch and roll? Announcing the arrival of...