~ubuntu-branches/debian/sid/botan/sid

« back to all changes in this revision

Viewing changes to modules/es_unix/unix_cmd.cpp

  • Committer: Package Import Robot
  • Author(s): Laszlo Boszormenyi (GCS)
  • Date: 2018-03-01 22:23:25 UTC
  • mfrom: (1.2.2)
  • Revision ID: package-import@ubuntu.com-20180301222325-7p7vc45gu3hta34d
Tags: 2.4.0-2
* Don't remove .doctrees from the manual if it doesn't exist.
* Don't specify parallel to debhelper.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*************************************************
2
 
* Unix Command Execution Source File             *
3
 
* (C) 1999-2007 The Botan Project                *
4
 
*************************************************/
5
 
 
6
 
#ifndef _XOPEN_SOURCE
7
 
  #define _XOPEN_SOURCE 500
8
 
#endif
9
 
 
10
 
#ifndef _XOPEN_SOURCE_EXTENDED
11
 
  #define _XOPEN_SOURCE_EXTENDED 1
12
 
#endif
13
 
 
14
 
#include <botan/unix_cmd.h>
15
 
#include <botan/parsing.h>
16
 
#include <sys/time.h>
17
 
#include <sys/types.h>
18
 
#include <sys/wait.h>
19
 
#include <stdlib.h>
20
 
#include <unistd.h>
21
 
#include <signal.h>
22
 
 
23
 
namespace Botan {
24
 
 
25
 
namespace {
26
 
 
27
 
/*************************************************
28
 
* Attempt to execute the command                 *
29
 
************************************************/
30
 
void do_exec(const std::vector<std::string>& arg_list,
31
 
             const std::vector<std::string>& paths)
32
 
   {
33
 
   const u32bit args = arg_list.size() - 1;
34
 
 
35
 
   const char* arg1 = (args >= 1) ? arg_list[1].c_str() : 0;
36
 
   const char* arg2 = (args >= 2) ? arg_list[2].c_str() : 0;
37
 
   const char* arg3 = (args >= 3) ? arg_list[3].c_str() : 0;
38
 
   const char* arg4 = (args >= 4) ? arg_list[4].c_str() : 0;
39
 
 
40
 
   for(u32bit j = 0; j != paths.size(); j++)
41
 
      {
42
 
      const std::string full_path = paths[j] + "/" + arg_list[0];
43
 
      const char* fsname = full_path.c_str();
44
 
      execl(fsname, fsname, arg1, arg2, arg3, arg4, 0);
45
 
      }
46
 
   }
47
 
 
48
 
}
49
 
 
50
 
/*************************************************
51
 
* Local information about the pipe               *
52
 
*************************************************/
53
 
struct pipe_wrapper
54
 
   {
55
 
   int fd;
56
 
   pid_t pid;
57
 
   pipe_wrapper() { fd = -1; pid = 0; }
58
 
   };
59
 
 
60
 
/*************************************************
61
 
* Read from the pipe                             *
62
 
*************************************************/
63
 
u32bit DataSource_Command::read(byte buf[], u32bit length)
64
 
   {
65
 
   if(end_of_data())
66
 
      return 0;
67
 
 
68
 
   fd_set set;
69
 
   FD_ZERO(&set);
70
 
   FD_SET(pipe->fd, &set);
71
 
 
72
 
   struct timeval tv;
73
 
   tv.tv_sec = 0;
74
 
   tv.tv_usec = MAX_BLOCK_USECS;
75
 
 
76
 
   ssize_t got = 0;
77
 
   if(select(pipe->fd + 1, &set, 0, 0, &tv) == 1)
78
 
      {
79
 
      if(FD_ISSET(pipe->fd, &set))
80
 
         got = ::read(pipe->fd, buf, length);
81
 
      }
82
 
 
83
 
   if(got <= 0)
84
 
      {
85
 
      shutdown_pipe();
86
 
      return 0;
87
 
      }
88
 
 
89
 
   return (u32bit)got;
90
 
   }
91
 
 
92
 
/*************************************************
93
 
* Peek at the pipe contents                      *
94
 
*************************************************/
95
 
u32bit DataSource_Command::peek(byte[], u32bit, u32bit) const
96
 
   {
97
 
   if(end_of_data())
98
 
      throw Invalid_State("DataSource_Command: Cannot peek when out of data");
99
 
   throw Stream_IO_Error("Cannot peek/seek on a command pipe");
100
 
   }
101
 
 
102
 
/*************************************************
103
 
* Check if we reached EOF                        *
104
 
*************************************************/
105
 
bool DataSource_Command::end_of_data() const
106
 
   {
107
 
   return (pipe) ? false : true;
108
 
   }
109
 
 
110
 
/*************************************************
111
 
* Return the Unix file descriptor of the pipe    *
112
 
*************************************************/
113
 
int DataSource_Command::fd() const
114
 
   {
115
 
   if(!pipe)
116
 
      return -1;
117
 
   return pipe->fd;
118
 
   }
119
 
 
120
 
/*************************************************
121
 
* Return a human-readable ID for this stream     *
122
 
*************************************************/
123
 
std::string DataSource_Command::id() const
124
 
   {
125
 
   return "Unix command: " + arg_list[0];
126
 
   }
127
 
 
128
 
/*************************************************
129
 
* Create the pipe                                *
130
 
*************************************************/
131
 
void DataSource_Command::create_pipe(const std::string& path)
132
 
   {
133
 
   const std::vector<std::string> paths = split_on(path, ':');
134
 
 
135
 
   bool found_something = false;
136
 
   for(u32bit j = 0; j != paths.size(); j++)
137
 
      {
138
 
      const std::string full_path = paths[j] + "/" + arg_list[0];
139
 
      if(access(full_path.c_str(), X_OK) == 0)
140
 
         {
141
 
         found_something = true;
142
 
         break;
143
 
         }
144
 
      }
145
 
   if(!found_something)
146
 
      return;
147
 
 
148
 
   int pipe_fd[2];
149
 
   if(::pipe(pipe_fd) != 0)
150
 
      return;
151
 
 
152
 
   pid_t pid = fork();
153
 
 
154
 
   if(pid == -1)
155
 
      {
156
 
      close(pipe_fd[0]);
157
 
      close(pipe_fd[1]);
158
 
      }
159
 
   else if(pid > 0)
160
 
      {
161
 
      pipe = new pipe_wrapper;
162
 
      pipe->fd = pipe_fd[0];
163
 
      pipe->pid = pid;
164
 
      close(pipe_fd[1]);
165
 
      }
166
 
   else
167
 
      {
168
 
      if(dup2(pipe_fd[1], STDOUT_FILENO) == -1)
169
 
         exit(127);
170
 
      if(close(pipe_fd[0]) != 0 || close(pipe_fd[1]) != 0)
171
 
         exit(127);
172
 
      if(close(STDERR_FILENO) != 0)
173
 
         exit(127);
174
 
 
175
 
      do_exec(arg_list, paths);
176
 
      exit(127);
177
 
      }
178
 
   }
179
 
 
180
 
/*************************************************
181
 
* Shutdown the pipe                              *
182
 
*************************************************/
183
 
void DataSource_Command::shutdown_pipe()
184
 
   {
185
 
   if(pipe)
186
 
      {
187
 
      pid_t reaped = waitpid(pipe->pid, 0, WNOHANG);
188
 
 
189
 
      if(reaped == 0)
190
 
         {
191
 
         kill(pipe->pid, SIGTERM);
192
 
 
193
 
         struct timeval tv;
194
 
         tv.tv_sec = 0;
195
 
         tv.tv_usec = KILL_WAIT;
196
 
         select(0, 0, 0, 0, &tv);
197
 
 
198
 
         reaped = waitpid(pipe->pid, 0, WNOHANG);
199
 
 
200
 
         if(reaped == 0)
201
 
            {
202
 
            kill(pipe->pid, SIGKILL);
203
 
            do
204
 
               reaped = waitpid(pipe->pid, 0, 0);
205
 
            while(reaped == -1);
206
 
            }
207
 
         }
208
 
 
209
 
      close(pipe->fd);
210
 
      delete pipe;
211
 
      pipe = 0;
212
 
      }
213
 
   }
214
 
 
215
 
/*************************************************
216
 
* DataSource_Command Constructor                 *
217
 
*************************************************/
218
 
DataSource_Command::DataSource_Command(const std::string& prog_and_args,
219
 
                                       const std::string& path) :
220
 
   MAX_BLOCK_USECS(100000), KILL_WAIT(10000)
221
 
   {
222
 
   arg_list = split_on(prog_and_args, ' ');
223
 
 
224
 
   if(arg_list.size() == 0)
225
 
      throw Invalid_Argument("DataSource_Command: No command given");
226
 
   if(arg_list.size() > 5)
227
 
      throw Invalid_Argument("DataSource_Command: Too many args");
228
 
 
229
 
   pipe = 0;
230
 
   create_pipe(path);
231
 
   }
232
 
 
233
 
/*************************************************
234
 
* DataSource_Command Destructor                  *
235
 
*************************************************/
236
 
DataSource_Command::~DataSource_Command()
237
 
   {
238
 
   if(!end_of_data())
239
 
      shutdown_pipe();
240
 
   }
241
 
 
242
 
}