in reply to Re^3: Linux::usermod - user name ... already exists
in thread Linux::usermod - user name ... already exists

It looks like this is the distilled version of what I will try. The validation of the two variables takes place earlier in another function.

$ENV{'PATH'}=q(/sbin:/bin:/usr/sbin:/usr/bin); my ($um,$gm); qx/usermod --login $newname --home $newname $oldname/; $um = $?; if ($um==0) { qx/groupmod --new-name $newname $oldname/; $gm = $?; }

Ideas or corrections?

No output is produced, so I don't try to capture any. And the home directory gets reassigned and renamed elsewhere, too, since I have a little non-standard home directory arrangement for those groups.

Replies are listed 'Best First'.
Re^5: Linux::usermod - user name ... already exists
by haukex (Archbishop) on Mar 21, 2019 at 13:42 UTC

    Since you're setting a restricted PATH, are you running this under taint mode? If so, are $newname and $oldname user input? If yes, I would strongly recommend against putting them in a shell command like this (even though I assume you had to untaint them first). I'd suggest at the very least using system in the list form with more than one argument, e.g.:

    system('usermod','--login',$newname,'--home',$newname,$oldname) ==0 or die "usermod failed, \$?=$?"; system('groupmod','--new-name',$newname,$oldname) ==0 or die "groupmod failed, \$?=$?";

    I wrote more on the topic of avoiding the shell here.

      It runs under taint mode. As mentioned earlier in the thread, the script does sanitization and validation of the strings earlier on long before they get sent to the shell scripts. I would avoid using the system programs directly if possible, but Linux::usermod is missing the functions needed to proerly rename an account belonging to several groups.

      Could you please explain the advantages or differences between system() in list form and qx/ / in practice? I'm only interested in tracking if the action failed or succeeded and wish to suppress anything sent to stdin or stdout.

        Could you please explain the advantages or differences between system() in list form and qx/ / in practice?

        Other than that system doesn't capture output, it's that there is no built-in "list form" of qx//, meaning that reliably avoiding issues with shell quoting or security issues will always take extra code or a module, be it ShellQuote::Any or one of the modules I mentioned in the post I linked to earlier. IPC::System::Simple's capturex comes closest as a drop-in replacement to qx that avoids the shell.

        I'm only interested in tracking if the action failed or succeeded and wish to suppress anything sent to stdin or stdout.

        There's several options to do so, all involving external modules*. For example, the aforementioned IPC::System::Simple, although you might have to wrap that in an eval or Try::Tiny because its errors are fatal by default, or you could wrap a system call in Capture::Tiny's capture, or you could use IPC::Run3...

        * Of course it's possible to DIY by redirecting STDOUT/ERR, but then you'd just be reproducing the code that's in those modules, and most likely the code would not be as portable and not cover as many special cases as the modules do.

Re^5: Linux::usermod - user name ... already exists
by choroba (Cardinal) on Mar 20, 2019 at 15:06 UTC
    If you don't need the output, use system instead of qx. It returns the exit code directly, so no need to use $?.
    map{substr$_->[0],$_->[1]||0,1}[\*||{},3],[[]],[ref qr-1,-,-1],[{}],[sub{}^*ARGV,3]