kWill
Gast
|
|
« Antwort #3 am: 17. Juni 2003, 16:52:42 » |
|
/* * Autorun module for ProFTPd. * $Id: mod_autorun.c,v 1.7 2000/07/27 14:09:55 brett Exp brett $ */
/* * ProFTPD - FTP server daemon * Copyright (C) 2000 Brett Morgan * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. */
/* * $Log: mod_autorun.c,v $ * Revision 1.7 2000/07/27 14:09:55 brett * Followed the linux system manpage advice and used some c code instead * of system. System has some nasty signal semantics, plus I already had * the fork in place and debugged. Now invokes /bin/sh with apropriate * command line plus a minimalistic enviroment. * * Revision 1.6 2000/07/27 11:47:21 brett * It forks and execs. About to replace execl with system to allow input * and output redirection, using the shell. * * Revision 1.5 2000/07/26 13:25:25 brett * Playing with privs such that I could execute with a specified uid and * gid was too hard. I just realized that the command we run is still * going to either have saved-uid or real-uid of 0. Security * hazard. Effective uid will be the person that is logged in. * * Revision 1.4 2000/07/26 06:32:13 brett * Learning all about vsnprintf. Stopped using it inappropriatly. * * Revision 1.3 2000/07/26 04:59:51 brett * Debugged previous checkin so it now works as intended. * * Revision 1.2 2000/07/26 04:17:28 brett * Changed code from sample code, to an initial testable autorun. * Has a configuration parse element. Has a post command handler. * * Revision 1.1 2000/07/26 02:34:32 brett * Initial revision * */
#include "conf.h" #include "privs.h" #include <signal.h>
MODRET add_autorun_command(cmd_rec *cmd) { config_rec *c; struct passwd *pw; struct group *grp; /* * AutoRunCommand takes 1 arg, and can only appear in <Directory> * blocks. */
CHECK_ARGS(cmd,1); CHECK_CONF(cmd,CONF_DIR);
/* * AutoRunCommand "/path/to/command %s" * * Argument 1 is a string to execute */
/* * Arg 1 is the command string. */
c = add_config_param_str("AutoRunCommand",1,(void*)cmd->argv[1]);
/* Change of requirements. Only applies in directory for which * configuation appears. No merge down. * c->flags |= CF_MERGEDOWN; */
return HANDLED(cmd); }
static RETSIGTYPE handle_child(int sig) { pid_t cpid; int status;
cpid = wait(&status);
if(WIFEXITED(status)) { log_debug(DEBUG4, "%s:%d: Child %d exited with status %d.", __FILE__,__LINE__,cpid,WEXITSTATUS(status)); } else { log_debug(DEBUG4, "%s:%d: Child %d exited abnormally.", __FILE__,__LINE__,cpid); }
/* Re-install child signal handler. */ signal(SIGCHLD,handle_child); }
static void fork_command(char *command) { pid_t pid; sigset_t sigset; int err; char *argv[4]; char *environ[2];
sigemptyset(&sigset); sigaddset(&sigset,SIGTERM); sigaddset(&sigset,SIGCHLD); sigaddset(&sigset,SIGUSR1); sigaddset(&sigset,SIGUSR2);
sigprocmask(SIG_BLOCK,&sigset,NULL);
switch((pid = fork())) { case 0: /* child */ sigprocmask(SIG_UNBLOCK,&sigset,NULL); break; case -1: /* fork failed */ sigprocmask(SIG_UNBLOCK,&sigset,NULL); log_pri(LOG_ERR,"fork(): %s",strerror(errno)); return; default: /* parent */
log_debug(DEBUG4, "%s:%d: Successfully forked child %d", __FILE__,__LINE__,pid);
/* Should really be creating a data structure to remember * children so we can report on them. But time is too short. */ signal(SIGCHLD,handle_child);
sigprocmask(SIG_UNBLOCK,&sigset,NULL); return; }
/* Here we are the child. */
#ifdef HAVE_SETPGID setpgid(0,getpid()); #else # ifdef SETPGRP_VOID setpgrp(); # else setpgrp(0,getpid()); # endif #endif
signal(SIGUSR1, SIG_IGN); signal(SIGUSR2, SIG_IGN); signal(SIGCHLD, SIG_DFL); signal(SIGHUP, SIG_IGN);
/* Close syslog. */
block_signals(); PRIVS_ROOT;
log_closesyslog();
PRIVS_RELINQUISH; unblock_signals();
log_debug(DEBUG4, "%s:%d: Child %d forked. About to exec '%s'.", __FILE__,__LINE__,getpid(),command);
/* kill root privs */ PRIVS_REVOKE;
log_debug(DEBUG5, "%s:%d: uid: %d, gid: %d, euid: %d, egid: %d.", __FILE__,__LINE__,getuid(),getgid(),geteuid(),getegid());
/* Make sure not to pass on open file descriptors */ close (0); /* stdin */ close (1); /* stdout */ close (2); /* stderr */
/* Use /bin/sh to do our command line parsing for us */ argv[0] = "sh"; argv[1] = "-c"; argv[2] = command; argv[3] = 0;
/* Exec command with a savaged environ */ environ[0] = "PATH=/bin:/usr/bin"; environ[1] = 0;
execve("/bin/sh", argv, environ);
/* failed to exec. Log it and exit. */ log_pri(LOG_ERR, "%s:%d: failed to execve('/bin/sh',['sh','-c','%s',0]," "['PATH=/bin:/usr/bin',0]): %s", __FILE__,__LINE__,command,strerror(errno));
exit (1);
}
MODRET post_cmd_stor(cmd_rec *cmd) { char *command = ""; char *filename, *path;
char buffer[1025] = {'\0'};
command = (char*) get_param_ptr(CURRENT_CONF,"AutoRunCommand",FALSE);
/* Make sure we actually have a configuration */
if(!command) { log_debug(DEBUG4, "%s:%d: Command was null. Aborting.", __FILE__,__LINE__); return DECLINED(cmd); } if(!strcmp("",command)) { log_debug(DEBUG4, "%s:%d: Command was an empty string. Aborting.", __FILE__,__LINE__); return DECLINED(cmd); }
filename = session.xfer.filename; path = session.xfer.path;
snprintf(buffer,sizeof(buffer), command, path); buffer[1024] = '\0';
fork_command(buffer);
return DECLINED(cmd); }
static conftable autorun_config[] = { { "AutoRunCommand", add_autorun_command, }, { NULL } };
cmdtable autorun_commands[] = { { POST_CMD, C_STOR, G_NONE, post_cmd_stor, FALSE, FALSE }, { 0, NULL } };
module autorun_module = { NULL,NULL, /* Always NULL */ 0x20, /* API Version 2.0 */ "autorun", autorun_config, /* Autorun configuration handler table */ autorun_commands, /* Autorun command handler table */ NULL, /* No authentication handler table */ NULL, /* Initialization function */ NULL /* Post-fork "child mode" init */ };
|