diff --git a/ChangeLog b/ChangeLog index 3ef73198..e59073a0 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +2011-08-20 Jonathan Nieder + + * lib/Makefile.am: Added lib/spawn.c and lib/spawn.h. + * lib/nscd.c, lib/spawn.c, lib/spawn.h: It is not possible to + differentiate between an nscd failure, and a failure to execute + due to no nscd with posix_spawn. Use our own run_command routine. + * src/userdel.c: Use run_command() + 2011-08-15 Nicolas François * src/groupmod.c: Ignore return value from snprintf. diff --git a/lib/Makefile.am b/lib/Makefile.am index a04623cd..48da50ed 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -48,6 +48,8 @@ libshadow_la_SOURCES = \ shadowio.c \ shadowio.h \ shadowmem.c \ + spawn.c \ + spawn.h \ utent.c if WITH_TCB diff --git a/lib/nscd.c b/lib/nscd.c index d7fa2d58..8aa94046 100644 --- a/lib/nscd.c +++ b/lib/nscd.c @@ -16,7 +16,9 @@ #include #include #include +#include "exitcodes.h" #include "defines.h" +#include "spawn.h" #include "nscd.h" #define MSG_NSCD_FLUSH_CACHE_FAILED "Failed to flush the nscd cache.\n" @@ -26,37 +28,32 @@ */ int nscd_flush_cache (const char *service) { - pid_t pid, termpid; - int err, status; - char *spawnedArgs[] = {"/usr/sbin/nscd", "nscd", "-i", service, NULL}; - char *spawnedEnv[] = {NULL}; + pid_t pid; + int err, status, code; + const char *spawnedArgs[] = {"/usr/sbin/nscd", "nscd", "-i", service, NULL}; + const char *spawnedEnv[] = {NULL}; - /* spawn process */ - err = posix_spawn (&pid, spawnedArgs[0], NULL, NULL, - spawnedArgs, spawnedEnv); - if(0 != err) + err = run_command (spawnedArgs[0], spawnedArgs, spawnedEnv, &status); + if (0 != err) { + /* run_command writes its own more detailed message. */ (void) fputs (_(MSG_NSCD_FLUSH_CACHE_FAILED), stderr); - (void) fprintf (stderr, "posix_spawn() error=%d\n", err); return -1; } - - /* Wait for the spawned process to exit */ - termpid = TEMP_FAILURE_RETRY (waitpid (pid, &status, 0)); - if (-1 == termpid) + code = WIFEXITED (status) ? WEXITSTATUS (status) + : (WTERMSIG (status) + 128); + if (code == E_CMD_NOTFOUND) { + /* nscd is not installed, or it is installed but uses an + interpreter that is missing. Probably the former. */ + return 0; + } + if (code != 0) + { + (void) fprintf (stderr, "nscd exited with status %d", code); (void) fputs (_(MSG_NSCD_FLUSH_CACHE_FAILED), stderr); - perror("waitpid"); return -1; } - else if (termpid != pid) - { - (void) fputs (_(MSG_NSCD_FLUSH_CACHE_FAILED), stderr); - (void) fprintf (stderr, "waitpid returned %ld != %ld\n", - (long int) termpid, (long int) pid); - return -1; - } - return 0; } #else /* USE_NSCD */ diff --git a/lib/spawn.c b/lib/spawn.c new file mode 100644 index 00000000..afce926a --- /dev/null +++ b/lib/spawn.c @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2011, Jonathan Nieder + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FREEBSD + * PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include + +#include +#include +#include +#include +#include +#include +#include "exitcodes.h" +#include "spawn.h" + +extern char **environ; + +int run_command (const char *cmd, const char *argv[], const char *envp[], + int *status) +{ + pid_t pid, wpid; + + if (!envp) + envp = (const char **)environ; + pid = fork (); + if (pid == 0) { + execve (cmd, (char * const *) argv, (char * const *) envp); + if (errno == ENOENT) + exit (E_CMD_NOTFOUND); + perror(cmd); + exit (E_CMD_NOEXEC); + } else if ((pid_t)-1 == pid) { + int saved_errno = errno; + perror ("fork"); + errno = saved_errno; + return -1; + } + + do { + wpid = waitpid (pid, status, 0); + } while ((pid_t)-1 == wpid && errno == EINTR); + + if ((pid_t)-1 == wpid) { + int saved_errno = errno; + perror ("waitpid"); + return -1; + } else if (wpid != pid) { + (void) fprintf (stderr, "waitpid returned %ld != %ld\n", + (long int) wpid, (long int) pid); + errno = ECHILD; + return -1; + } + return 0; +} diff --git a/lib/spawn.h b/lib/spawn.h new file mode 100644 index 00000000..f975d2ce --- /dev/null +++ b/lib/spawn.h @@ -0,0 +1,7 @@ +#ifndef _SPAWN_H +#define _SPAWN_H + +extern int run_command (const char *cmd, const char *argv[], + const char *envp[], int *status); + +#endif diff --git a/src/userdel.c b/src/userdel.c index dfb70e9c..fbfb7183 100644 --- a/src/userdel.c +++ b/src/userdel.c @@ -59,6 +59,7 @@ #ifdef SHADOWGRP #include "sgroupio.h" #endif /* SHADOWGRP */ +#include "spawn.h" #ifdef WITH_TCB #include #include "tcbfuncs.h" @@ -628,6 +629,7 @@ static void update_user (void) static void user_cancel (const char *user) { const char *cmd; + const char *argv[3]; pid_t pid, wpid; int status; @@ -635,18 +637,10 @@ static void user_cancel (const char *user) if (NULL == cmd) { return; } - pid = fork (); - if (pid == 0) { - execl (cmd, cmd, user, (char *) 0); - perror (cmd); - exit (errno == ENOENT ? E_CMD_NOTFOUND : E_CMD_NOEXEC); - } else if ((pid_t)-1 == pid) { - perror ("fork"); - return; - } - do { - wpid = wait (&status); - } while ((wpid != pid) && ((pid_t)-1 != wpid)); + argv[0] = cmd; + argv[1] = user; + argv[2] = (char *)0; + (void) run_command (cmd, argv, NULL, &status); } #ifdef EXTRA_CHECK_HOME_DIR