/* All ow library closeup */ void LibClose(void) { Globals.exitmode = exit_early ; LEVEL_CALL("Starting Library cleanup"); LibStop(); PIDstop(); DeviceDestroy(); Detail_Close() ; ArgFree() ; _MUTEX_ATTR_DESTROY(Mutex.mattr); #if OW_ZERO // Used by browse and announce OW_Free_dnssd_library(); #endif LEVEL_CALL("Finished Library cleanup"); if (log_available) { closelog(); log_available = 0; } SAFEFREE(Globals.announce_name) ; SAFEFREE(Globals.fatal_debug_file) ; LEVEL_DEBUG("Libraries closed"); }
static void test_split_empty(void **state) { char **s = ArgSplitCommand(""); assert_true(s); assert_false(*s); ArgFree(s); }
static void test_complex_quoting(void **state) { char **s = ArgSplitCommand("\"foo`'bar\""); assert_string_equal(s[0], "foo`'bar"); assert_false(s[1]); ArgFree(s); }
static void test_arguments_resize(void **state) { char **s = ArgSplitCommand("0 1 2 3 4 5 6 7 8"); assert_string_equal(s[7], "7"); assert_string_equal(s[8], "8"); assert_false(s[9]); ArgFree(s); }
static void test_split_quoted_end(void **state) { char **s = ArgSplitCommand("atend 'quoted string'"); assert_string_equal(s[0], "atend"); assert_string_equal(s[1], "quoted string"); assert_false(s[2]); ArgFree(s); }
static void test_split_quoted_beginning(void **state) { char **s = ArgSplitCommand("\"quoted string\" atbeginning"); assert_string_equal(s[0], "quoted string"); assert_string_equal(s[1], "atbeginning"); assert_false(s[2]); ArgFree(s); }
static void test_arguments_resize_for_null(void **state) { /* This test checks that extending returned argument list for NULL terminator * works correctly */ char **s = ArgSplitCommand("0 1 2 3 4 5 6 7"); assert_string_equal(s[7], "7"); assert_false(s[8]); ArgFree(s); }
static void test_split_quoted_middle(void **state) { char **s = ArgSplitCommand("at `quoted string` middle"); assert_string_equal(s[0], "at"); assert_string_equal(s[1], "quoted string"); assert_string_equal(s[2], "middle"); assert_false(s[3]); ArgFree(s); }
static void test_split_easy(void **state) { char **s = ArgSplitCommand("zero one two"); assert_string_equal(s[0], "zero"); assert_string_equal(s[1], "one"); assert_string_equal(s[2], "two"); assert_false(s[3]); ArgFree(s); }
static FILE *Unix_cf_popensetuid(char *command, char *type, uid_t uid, gid_t gid, char *chdirv, char *chrootv) { int i, pd[2]; char **argv; pid_t pid; FILE *pp = NULL; CfDebug("Unix_cf_popensetuid(%s,%s,%d,%d)\n", command, type, uid, gid); if ((*type != 'r' && *type != 'w') || (type[1] != '\0')) { errno = EINVAL; return NULL; } if (!ThreadLock(cft_count)) { return NULL; } if (CHILDREN == NULL) /* first time */ { CHILDREN = xcalloc(MAX_FD, sizeof(pid_t)); } ThreadUnlock(cft_count); if (pipe(pd) < 0) /* Create a pair of descriptors to this process */ { return NULL; } if ((pid = fork()) == -1) { close(pd[0]); close(pd[1]); return NULL; } signal(SIGCHLD, SIG_DFL); ALARM_PID = (pid != 0 ? pid : -1); if (pid == 0) { switch (*type) { case 'r': close(pd[0]); /* Don't need output from parent */ if (pd[1] != 1) { dup2(pd[1], 1); /* Attach pp=pd[1] to our stdout */ dup2(pd[1], 2); /* Merge stdout/stderr */ close(pd[1]); } break; case 'w': close(pd[1]); if (pd[0] != 0) { dup2(pd[0], 0); close(pd[0]); } } for (i = 0; i < MAX_FD; i++) { if (CHILDREN[i] > 0) { close(i); } } argv = ArgSplitCommand(command); if (chrootv && strlen(chrootv) != 0) { if (chroot(chrootv) == -1) { CfOut(cf_error, "chroot", "Couldn't chroot to %s\n", chrootv); ArgFree(argv); return NULL; } } if (chdirv && strlen(chdirv) != 0) { if (chdir(chdirv) == -1) { CfOut(cf_error, "chdir", "Couldn't chdir to %s\n", chdirv); ArgFree(argv); return NULL; } } if (!CfSetuid(uid, gid)) { _exit(1); } if (execv(argv[0], argv) == -1) { CfOut(cf_error, "execv", "Couldn't run %s", argv[0]); } _exit(1); } else { switch (*type) { case 'r': close(pd[1]); if ((pp = fdopen(pd[0], type)) == NULL) { cf_pwait(pid); return NULL; } break; case 'w': close(pd[0]); if ((pp = fdopen(pd[1], type)) == NULL) { cf_pwait(pid); return NULL; } } if (fileno(pp) >= MAX_FD) { CfOut(cf_error, "", "File descriptor %d of child %d higher than MAX_FD in Unix_cf_popensetuid, check for defunct children", fileno(pp), pid); } else { ThreadLock(cft_count); CHILDREN[fileno(pp)] = pid; ThreadUnlock(cft_count); } return pp; } return NULL; /* cannot reach here */ }
/** * ParseLineArgV * * Parses and processes a line which was sent by the server. * * @param argc number of tokens * @param argv the tokens */ bool CIRCConnection::ParseLineArgV(int argc, const char **argv) { CChannel *Channel; CClientConnection *Client; m_LastResponse = g_CurrentTime; if (argc < 2) { return true; } const char *Reply = argv[0]; const char *Raw = argv[1]; char *Nick = ::NickFromHostmask(Reply); int iRaw = atoi(Raw); bool b_Me = false; if (m_CurrentNick != NULL && Nick != NULL && strcasecmp(Nick, m_CurrentNick) == 0) { b_Me = true; } free(Nick); Client = GetOwner()->GetClientConnectionMultiplexer(); // HASH values CHashCompare hashRaw(argv[1]); static CHashCompare hashPrivmsg("PRIVMSG"); static CHashCompare hashNotice("NOTICE"); static CHashCompare hashJoin("JOIN"); static CHashCompare hashPart("PART"); static CHashCompare hashKick("KICK"); static CHashCompare hashNick("NICK"); static CHashCompare hashQuit("QUIT"); static CHashCompare hashMode("MODE"); static CHashCompare hashTopic("TOPIC"); static CHashCompare hashPong("PONG"); // END of HASH values if (argc > 3 && iRaw == 433) { bool ReturnValue = ModuleEvent(argc, argv); if (ReturnValue) { if (GetCurrentNick() == NULL) { WriteLine("NICK :%s_", argv[3]); } if (m_NickCatchTimer == NULL) { m_NickCatchTimer = new CTimer(30, false, NickCatchTimer, this); } } return ReturnValue; } else if (argc > 3 && hashRaw == hashPrivmsg && Client == NULL) { const char *Host; const char *Dest = argv[2]; char *Nick = ::NickFromHostmask(Reply); Channel = GetChannel(Dest); if (Channel != NULL) { CNick *User = Channel->GetNames()->Get(Nick); if (User != NULL) { User->SetIdleSince(g_CurrentTime); } Channel->AddBacklogLine(argv[0], argv[3]); } if (!ModuleEvent(argc, argv)) { free(Nick); return false; } /* don't log ctcp requests */ if (argv[3][0] != '\1' && argv[3][strlen(argv[3]) - 1] != '\1' && Dest != NULL && Nick != NULL && m_CurrentNick != NULL && strcasecmp(Dest, m_CurrentNick) == 0 && strcasecmp(Nick, m_CurrentNick) != 0) { char *Dup; char *Delim; Dup = strdup(Reply); if (AllocFailed(Dup)) { free(Nick); return true; } Delim = strchr(Dup, '!'); if (Delim != NULL) { *Delim = '\0'; Host = Delim + 1; } GetOwner()->Log("%s (%s): %s", Dup, Delim ? Host : "<unknown host>", argv[3]); free(Dup); } free(Nick); UpdateHostHelper(Reply); return true; } else if (argc > 3 && hashRaw == hashPrivmsg && Client != NULL) { Channel = GetChannel(argv[2]); if (Channel != NULL) { Channel->AddBacklogLine(argv[0], argv[3]); } } else if (argc > 3 && hashRaw == hashNotice && Client == NULL) { const char *Dest = argv[2]; char *Nick; if (!ModuleEvent(argc, argv)) { return false; } Nick = ::NickFromHostmask(Reply); /* don't log ctcp replies */ if (argv[3][0] != '\1' && argv[3][strlen(argv[3]) - 1] != '\1' && Dest != NULL && Nick != NULL && m_CurrentNick != NULL && strcasecmp(Dest, m_CurrentNick) == 0 && strcasecmp(Nick, m_CurrentNick) != 0) { GetOwner()->Log("%s (notice): %s", Reply, argv[3]); } free(Nick); return true; } else if (argc > 2 && hashRaw == hashJoin) { if (b_Me) { AddChannel(argv[2]); /* GetOwner() can be NULL if AddChannel failed */ if (GetOwner() != NULL && Client == NULL) { WriteLine("MODE %s", argv[2]); } } Channel = GetChannel(argv[2]); if (Channel != NULL) { Nick = NickFromHostmask(Reply); if (AllocFailed(Nick)) { return false; } Channel->AddUser(Nick, '\0'); free(Nick); } UpdateHostHelper(Reply); } else if (argc > 2 && hashRaw == hashPart) { bool bRet = ModuleEvent(argc, argv); if (b_Me) { RemoveChannel(argv[2]); } else { Channel = GetChannel(argv[2]); if (Channel != NULL) { Nick = ::NickFromHostmask(Reply); if (AllocFailed(Nick)) { return false; } Channel->RemoveUser(Nick); free(Nick); } } UpdateHostHelper(Reply); return bRet; } else if (argc > 3 && hashRaw == hashKick) { bool bRet = ModuleEvent(argc, argv); if (m_CurrentNick != NULL && strcasecmp(argv[3], m_CurrentNick) == 0) { RemoveChannel(argv[2]); if (Client == NULL) { char *Dup = strdup(Reply); if (AllocFailed(Dup)) { return bRet; } char *Delim = strchr(Dup, '!'); const char *Host = NULL; if (Delim) { *Delim = '\0'; Host = Delim + 1; } GetOwner()->Log("%s (%s) kicked you from %s (%s)", Dup, Delim ? Host : "<unknown host>", argv[2], argc > 4 ? argv[4] : ""); free(Dup); } } else { Channel = GetChannel(argv[2]); if (Channel != NULL) { Channel->RemoveUser(argv[3]); } } UpdateHostHelper(Reply); return bRet; } else if (argc > 2 && iRaw == 1) { if (Client != NULL) { if (strcmp(Client->GetNick(), argv[2]) != 0) { Client->WriteLine(":%s!%s NICK :%s", Client->GetNick(), m_Site ? m_Site : "*****@*****.**", argv[2]); } } free(m_CurrentNick); m_CurrentNick = strdup(argv[2]); free(m_Server); m_Server = strdup(Reply); } else if (argc > 2 && hashRaw == hashNick) { if (b_Me) { free(m_CurrentNick); m_CurrentNick = strdup(argv[2]); } Nick = NickFromHostmask(argv[0]); int i = 0; if (!b_Me && GetOwner()->GetClientConnectionMultiplexer() == NULL) { const char *AwayNick = GetOwner()->GetAwayNick(); if (AwayNick != NULL && strcasecmp(AwayNick, Nick) == 0) { WriteLine("NICK %s", AwayNick); } } while (hash_t<CChannel *> *ChannelHash = m_Channels->Iterate(i++)) { ChannelHash->Value->RenameUser(Nick, argv[2]); } free(Nick); } else if (argc > 1 && hashRaw == hashQuit) { bool bRet = ModuleEvent(argc, argv); Nick = NickFromHostmask(argv[0]); int i = 0; while (hash_t<CChannel *> *ChannelHash = m_Channels->Iterate(i++)) { ChannelHash->Value->RemoveUser(Nick); } free(Nick); return bRet; } else if (argc > 1 && (iRaw == 422 || iRaw == 376)) { int DelayJoin = GetOwner()->GetDelayJoin(); if (m_State != State_Connected) { const CVector<CModule *> *Modules = g_Bouncer->GetModules(); for (int i = 0; i < Modules->GetLength(); i++) { (*Modules)[i]->ServerLogon(GetOwner()->GetUsername()); } const char *ClientNick; if (Client != NULL) { ClientNick = Client->GetNick(); if (strcmp(m_CurrentNick, ClientNick) != 0) { Client->ChangeNick(m_CurrentNick); } } GetOwner()->Log("You were successfully connected to an IRC server."); g_Bouncer->Log("User %s connected to an IRC server.", GetOwner()->GetUsername()); } if (DelayJoin == 1) { m_DelayJoinTimer = g_Bouncer->CreateTimer(5, false, DelayJoinTimer, this); } else if (DelayJoin == 0) { JoinChannels(); } if (Client == NULL) { bool AppendTS = (GetOwner()->GetConfig()->ReadInteger("user.ts") != 0); const char *AwayReason = GetOwner()->GetAwayText(); if (AwayReason != NULL) { WriteLine(AppendTS ? "AWAY :%s (Away since the dawn of time)" : "AWAY :%s", AwayReason); } } const char *AutoModes = GetOwner()->GetAutoModes(); const char *DropModes = GetOwner()->GetDropModes(); if (AutoModes != NULL) { WriteLine("MODE %s +%s", GetCurrentNick(), AutoModes); } if (DropModes != NULL && Client == NULL) { WriteLine("MODE %s -%s", GetCurrentNick(), DropModes); } m_State = State_Connected; } else if (argc > 1 && strcasecmp(Reply, "ERROR") == 0) { if (strstr(Raw, "throttle") != NULL) { GetOwner()->ScheduleReconnect(120); } else { GetOwner()->ScheduleReconnect(5); } if (GetCurrentNick() != NULL && GetSite() != NULL) { g_Bouncer->LogUser(GetUser(), "Error received for user %s [%s!%s]: %s", GetOwner()->GetUsername(), GetCurrentNick(), GetSite(), argv[1]); } else { g_Bouncer->LogUser(GetUser(), "Error received for user %s: %s", GetOwner()->GetUsername(), argv[1]); } } else if (argc > 3 && iRaw == 465) { if (GetCurrentNick() != NULL && GetSite() != NULL) { g_Bouncer->LogUser(GetUser(), "G/K-line reason for user %s [%s!%s]: %s", GetOwner()->GetUsername(), GetCurrentNick(), GetSite(), argv[3]); } else { g_Bouncer->LogUser(GetUser(), "G/K-line reason for user %s: %s", GetOwner()->GetUsername(), argv[3]); } } else if (argc > 5 && iRaw == 351) { free(m_ServerVersion); m_ServerVersion = strdup(argv[3]); free(m_ServerFeat); m_ServerFeat = strdup(argv[5]); } else if (argc > 3 && iRaw == 5) { for (int i = 3; i < argc - 1; i++) { char *Dup = strdup(argv[i]); if (AllocFailed(Dup)) { return false; } char *Eq = strchr(Dup, '='); if (strcasecmp(Dup, "NAMESX") == 0) { WriteLine("PROTOCTL NAMESX"); } char *Value; if (Eq) { *Eq = '\0'; Value = strdup(++Eq); } else { Value = strdup(""); } m_ISupport->Add(Dup, Value); free(Dup); } } else if (argc > 4 && iRaw == 324) { Channel = GetChannel(argv[3]); if (Channel != NULL) { Channel->ClearModes(); Channel->ParseModeChange(argv[0], argv[4], argc - 5, &argv[5]); Channel->SetModesValid(true); } } else if (argc > 3 && hashRaw == hashMode) { Channel = GetChannel(argv[2]); if (Channel != NULL) { Channel->ParseModeChange(argv[0], argv[3], argc - 4, &argv[4]); } else if (strcmp(m_CurrentNick, argv[2]) == 0) { bool Flip = true, WasNull; const char *Modes = argv[3]; size_t Length = strlen(Modes) + 1; if (m_Usermodes != NULL) { Length += strlen(m_Usermodes); } WasNull = (m_Usermodes != NULL) ? false : true; m_Usermodes = (char *)realloc(m_Usermodes, Length); if (AllocFailed(m_Usermodes)) { return false; } if (WasNull) { m_Usermodes[0] = '\0'; } while (*Modes != '\0') { if (*Modes == '+') { Flip = true; } else if (*Modes == '-') { Flip = false; } else { if (Flip) { size_t Position = strlen(m_Usermodes); m_Usermodes[Position] = *Modes; m_Usermodes[Position + 1] = '\0'; } else { char *CurrentModes = m_Usermodes; size_t a = 0; while (*CurrentModes != '\0') { *CurrentModes = m_Usermodes[a]; if (*CurrentModes != *Modes) { CurrentModes++; } a++; } } } Modes++; } } UpdateHostHelper(Reply); } else if (argc > 4 && iRaw == 329) { Channel = GetChannel(argv[3]); if (Channel != NULL) { Channel->SetCreationTime(atoi(argv[4])); } } else if (argc > 4 && iRaw == 332) { Channel = GetChannel(argv[3]); if (Channel != NULL) { Channel->SetTopic(argv[4]); } } else if (argc > 5 && iRaw == 333) { Channel = GetChannel(argv[3]); if (Channel != NULL) { Channel->SetTopicNick(argv[4]); Channel->SetTopicStamp(atoi(argv[5])); } } else if (argc > 3 && iRaw == 331) { Channel = GetChannel(argv[3]); if (Channel != NULL) { Channel->SetNoTopic(); } } else if (argc > 3 && hashRaw == hashTopic) { Channel = GetChannel(argv[2]); if (Channel != NULL) { Channel->SetTopic(argv[3]); Channel->SetTopicStamp(g_CurrentTime); Channel->SetTopicNick(argv[0]); } UpdateHostHelper(Reply); } else if (argc > 5 && iRaw == 353) { Channel = GetChannel(argv[4]); if (Channel != NULL) { const char *nicks; const char **nickv; nicks = ArgTokenize(argv[5]); if (AllocFailed(nicks)) { return false; } nickv = ArgToArray(nicks); if (AllocFailed(nickv)) { ArgFree(nicks); return false; } int nickc = ArgCount(nicks); for (int i = 0; i < nickc; i++) { char *Nick = strdup(nickv[i]); char *BaseNick = Nick; if (AllocFailed(Nick)) { ArgFree(nicks); return false; } StrTrim(Nick, ' '); while (IsNickPrefix(*Nick)) { Nick++; } char *Modes = NULL; if (BaseNick != Nick) { Modes = (char *)malloc(Nick - BaseNick + 1); if (!AllocFailed(Modes)) { strmcpy(Modes, BaseNick, Nick - BaseNick + 1); } } Channel->AddUser(Nick, Modes); free(BaseNick); free(Modes); } ArgFreeArray(nickv); ArgFree(nicks); } } else if (argc > 3 && iRaw == 366) { Channel = GetChannel(argv[3]); if (Channel != NULL) { Channel->SetHasNames(); } } else if (argc > 9 && iRaw == 352) { const char *Ident = argv[4]; const char *Host = argv[5]; const char *Server = argv[6]; const char *Nick = argv[7]; const char *Realname = argv[9]; char *Mask; int rc = asprintf(&Mask, "%s!%s@%s", Nick, Ident, Host); if (!RcFailed(rc)) { UpdateHostHelper(Mask); UpdateWhoHelper(Nick, Realname, Server); free(Mask); } } else if (argc > 6 && iRaw == 367) { Channel = GetChannel(argv[3]); if (Channel != NULL) { Channel->GetBanlist()->SetBan(argv[4], argv[5], atoi(argv[6])); } } else if (argc > 3 && iRaw == 368) { Channel = GetChannel(argv[3]); if (Channel != NULL) { Channel->SetHasBans(); } } else if (argc > 3 && iRaw == 396) { free(m_Site); m_Site = strdup(argv[3]); if (AllocFailed(m_Site)) {} } else if (argc > 3 && hashRaw == hashPong && m_Server != NULL && strcasecmp(argv[2], m_Server) == 0 && m_EatPong) { m_EatPong = false; return false; } else if (argc > 3 && iRaw == 421) { m_FloodControl->Unplug(); return false; } if (GetOwner() != NULL) { return ModuleEvent(argc, argv); } else { return true; } }
FILE *cf_popensetuid(const char *command, char *type, uid_t uid, gid_t gid, char *chdirv, char *chrootv, int background) { int pd[2]; char **argv; pid_t pid; FILE *pp = NULL; CfDebug("cf_popensetuid(%s,%s,%" PRIuMAX ",%" PRIuMAX ")\n", command, type, (uintmax_t)uid, (uintmax_t)gid); pid = CreatePipeAndFork(type, pd); if (pid == -1) { return NULL; } if (pid == 0) { switch (*type) { case 'r': close(pd[0]); /* Don't need output from parent */ if (pd[1] != 1) { dup2(pd[1], 1); /* Attach pp=pd[1] to our stdout */ dup2(pd[1], 2); /* Merge stdout/stderr */ close(pd[1]); } break; case 'w': close(pd[1]); if (pd[0] != 0) { dup2(pd[0], 0); close(pd[0]); } } CloseChildrenFD(); argv = ArgSplitCommand(command); if (chrootv && (strlen(chrootv) != 0)) { if (chroot(chrootv) == -1) { CfOut(cf_error, "chroot", "Couldn't chroot to %s\n", chrootv); ArgFree(argv); return NULL; } } if (chdirv && (strlen(chdirv) != 0)) { if (chdir(chdirv) == -1) { CfOut(cf_error, "chdir", "Couldn't chdir to %s\n", chdirv); ArgFree(argv); return NULL; } } if (!CfSetuid(uid, gid)) { _exit(1); } if (execv(argv[0], argv) == -1) { CfOut(cf_error, "execv", "Couldn't run %s", argv[0]); } _exit(1); } else { switch (*type) { case 'r': close(pd[1]); if ((pp = fdopen(pd[0], type)) == NULL) { cf_pwait(pid); return NULL; } break; case 'w': close(pd[0]); if ((pp = fdopen(pd[1], type)) == NULL) { cf_pwait(pid); return NULL; } } SetChildFD(fileno(pp), pid); return pp; } return NULL; /* cannot reach here */ }
/** * CCore * * Creates a new shroudBNC application object. * * @param Config the main config object * @param argc argument counts * @param argv program arguments */ CCore::CCore(CConfig *Config, int argc, char **argv) { int i; m_Log = NULL; m_PidFile = NULL; WritePidFile(); m_Config = Config; m_SSLContext = NULL; m_SSLClientContext = NULL; m_Status = Status_Running; CacheInitialize(m_ConfigCache, Config, "system."); char *SourcePath = strdup(BuildPathLog("sbnc.log")); rename(SourcePath, BuildPathLog("sbnc.log.old")); free(SourcePath); m_PollFds.Preallocate(SFD_SETSIZE); m_Log = new CLog("sbnc.log", true); if (m_Log == NULL) { printf("Log system could not be initialized. Shutting down."); exit(EXIT_FAILURE); } m_Log->Clear(); Log("Log system initialized."); g_Bouncer = this; m_Config = Config; m_Args.SetList(argv, argc); m_Ident = new CIdentSupport(); m_Config = new CConfig("sbnc.conf", NULL); CacheInitialize(m_ConfigCache, m_Config, "system."); const char *Users; CUser *User; if ((Users = m_Config->ReadString("system.users")) == NULL) { if (!MakeConfig()) { Log("Configuration file could not be created."); Fatal(); } printf("Configuration has been successfully saved. Please restart shroudBNC now.\n"); exit(EXIT_SUCCESS); } const char *Args; int Count; Args = ArgTokenize(Users); if (AllocFailed(Args)) { Fatal(); } Count = ArgCount(Args); for (i = 0; i < Count; i++) { const char *Name = ArgGet(Args, i + 1); User = new CUser(Name); if (AllocFailed(User)) { Fatal(); } m_Users.Add(Name, User); } ArgFree(Args); m_Listener = NULL; m_ListenerV6 = NULL; m_SSLListener = NULL; m_SSLListenerV6 = NULL; time(&m_Startup); m_LoadingModules = false; m_LoadingListeners = false; InitializeSocket(); m_Capabilities = new CVector<const char *>(); m_Capabilities->Insert("multi-prefix"); m_Capabilities->Insert("znc.in/server-time-iso"); }
FILE *cf_popensetuid(const char *command, const char *type, uid_t uid, gid_t gid, char *chdirv, char *chrootv, ARG_UNUSED int background) { int pd[2]; char **argv; pid_t pid; FILE *pp = NULL; pid = CreatePipeAndFork(type, pd); if (pid == -1) { return NULL; } if (pid == 0) { switch (*type) { case 'r': close(pd[0]); /* Don't need output from parent */ if (pd[1] != 1) { dup2(pd[1], 1); /* Attach pp=pd[1] to our stdout */ dup2(pd[1], 2); /* Merge stdout/stderr */ close(pd[1]); } break; case 'w': close(pd[1]); if (pd[0] != 0) { dup2(pd[0], 0); close(pd[0]); } } CloseChildrenFD(); argv = ArgSplitCommand(command); if (chrootv && (strlen(chrootv) != 0)) { if (chroot(chrootv) == -1) { Log(LOG_LEVEL_ERR, "Couldn't chroot to '%s'. (chroot: %s)", chrootv, GetErrorStr()); ArgFree(argv); return NULL; } } if (chdirv && (strlen(chdirv) != 0)) { if (safe_chdir(chdirv) == -1) { Log(LOG_LEVEL_ERR, "Couldn't chdir to '%s'. (chdir: %s)", chdirv, GetErrorStr()); ArgFree(argv); return NULL; } } if (!CfSetuid(uid, gid)) { _exit(EXIT_FAILURE); } if (execv(argv[0], argv) == -1) { Log(LOG_LEVEL_ERR, "Couldn't run '%s'. (execv: %s)", argv[0], GetErrorStr()); } _exit(EXIT_FAILURE); } else { switch (*type) { case 'r': close(pd[1]); if ((pp = fdopen(pd[0], type)) == NULL) { cf_pwait(pid); return NULL; } break; case 'w': close(pd[0]); if ((pp = fdopen(pd[1], type)) == NULL) { cf_pwait(pid); return NULL; } } SetChildFD(fileno(pp), pid); return pp; } return NULL; /* cannot reach here */ }