Gammu internals  1.38.0
proxy.c
Go to the documentation of this file.
1 #define _GNU_SOURCE /* For asprintf */
2 
3 #include "../../gsmstate.h"
4 
5 #include <signal.h>
6 #include <stdlib.h>
7 #include <stdio.h>
8 #include <fcntl.h>
9 #include <errno.h>
10 #include <string.h>
11 
12 #include "../../gsmcomon.h"
13 #include "../devfunc.h"
14 #include "proxy.h"
15 
16 #include "../../../helper/string.h"
17 
18 /* Expand a proxy command */
19 static char *
20 expand_proxy_command(const char *proxy_command)
21 {
22  char *ret;
23 
24  ret = NULL;
25  if (asprintf(&ret, "exec %s", proxy_command) < 0) {
26  return NULL;
27  }
28  return ret;
29 }
30 
31 #ifndef _PATH_BSHELL
32 # define _PATH_BSHELL "/bin/sh"
33 #endif
34 
35 /*
36  * Connect to the given ssh server using a proxy command.
37  */
38 static GSM_Error
39 proxy_connect(GSM_StateMachine *s, GSM_Device_ProxyData *proxydata, const char *proxy_command)
40 {
41  char *command_string;
42  int pin[2], pout[2];
43  pid_t pid;
44  const char *shell;
45 
46  if ((shell = getenv("SHELL")) == NULL || *shell == '\0') {
47  shell = _PATH_BSHELL;
48  }
49 
50  /* Create pipes for communicating with the proxy. */
51  if (pipe(pin) < 0 || pipe(pout) < 0) {
52  GSM_OSErrorInfo(s, "Could not create pipes to communicate with the proxy");
53  return ERR_DEVICEOPENERROR;
54  }
55 
56  command_string = expand_proxy_command(proxy_command);
57  if (command_string == NULL) {
58  return ERR_MOREMEMORY;
59  }
60  dbgprintf(NULL, "Executing proxy command: %.500s", command_string);
61 
62  /* Fork and execute the proxy command. */
63  if ((pid = fork()) == 0) {
64  const char * argv[10];
65 
66  /* Child. Permanently give up superuser privileges. */
67  //permanently_drop_suid(original_real_uid);
68 
69  /* Redirect stdin and stdout. */
70  close(pin[1]);
71  if (pin[0] != 0) {
72  if (dup2(pin[0], 0) < 0)
73  perror("dup2 stdin");
74  close(pin[0]);
75  }
76  close(pout[0]);
77  if (dup2(pout[1], 1) < 0)
78  perror("dup2 stdout");
79  /* Cannot be 1 because pin allocated two descriptors. */
80  close(pout[1]);
81 
82  /* Stderr is left as it is so that error messages get
83  printed on the user's terminal. */
84  argv[0] = shell;
85  argv[1] = "-c";
86  argv[2] = command_string;
87  argv[3] = NULL;
88 
89  /* Execute the proxy command. Note that we gave up any
90  extra privileges above. */
91  signal(SIGPIPE, SIG_DFL);
92  execv(argv[0], (char **)argv);
93  perror(argv[0]);
94  exit(1);
95  }
96  /* Parent. */
97  if (pid < 0) {
98  GSM_OSErrorInfo(s, "fork failed");
99  return ERR_DEVICEOPENERROR;
100  } else
101  proxydata->hProcess = pid; /* save pid to clean up later */
102 
103  /* Close child side of the descriptors. */
104  close(pin[0]);
105  close(pout[1]);
106 
107  /* Free the command name. */
108  free(command_string);
109 
110  /* Set the connection file descriptors. */
111  proxydata->hRead = pout[0];
112  proxydata->hWrite = pin[1];
113 
114  /* Indicate OK return */
115  return ERR_NONE;
116 }
117 
118 void
119 kill_proxy_command(pid_t proxy_command_pid)
120 {
121  /*
122  * Send SIGHUP to proxy command if used. We don't wait() in
123  * case it hangs and instead rely on init to reap the child
124  */
125  if (proxy_command_pid > 1)
126  kill(proxy_command_pid, SIGHUP);
127 }
128 
129 
131 {
132  return proxy_connect(s, &s->Device.Data.Proxy, s->CurrentConfig->Device);
133 }
134 
135 int proxy_read(GSM_StateMachine *s, void *buf, size_t nbytes)
136 {
138  struct timeval timeout2;
139  fd_set readfds;
140  int actual = 0;
141 
142  FD_ZERO(&readfds);
143  FD_SET(d->hRead, &readfds);
144 
145  timeout2.tv_sec = 0;
146  timeout2.tv_usec = 50000;
147 
148  if (select(d->hRead+1, &readfds, NULL, NULL, &timeout2)) {
149  actual = read(d->hRead, buf, nbytes);
150  if (actual == -1) GSM_OSErrorInfo(s,"proxy_read");
151  }
152  return actual;
153 }
154 
155 static
156 ssize_t write_nosigpipe(int fd, const void *buf, size_t len)
157 {
158  sigset_t oldset, newset;
159  ssize_t result;
160  siginfo_t si;
161  struct timespec ts = {0};
162 
163  sigemptyset(&newset);
164  sigaddset(&newset, SIGPIPE);
165  pthread_sigmask(SIG_BLOCK, &newset, &oldset);
166 
167  result = write(fd, buf, len);
168 
169  while (sigtimedwait(&newset, &si, &ts)>=0 || errno != EAGAIN);
170  pthread_sigmask(SIG_SETMASK, &oldset, 0);
171 
172  return result;
173 }
174 
175 int proxy_write(GSM_StateMachine *s, const void *buf, size_t nbytes)
176 {
178  int ret;
179  size_t actual = 0;
180  const unsigned char *buffer = (const unsigned char *)buf; /* Just to have correct type */
181 
182  do {
183  ret = write_nosigpipe(d->hWrite, buffer, nbytes - actual);
184  if (ret < 0) {
185  if (errno == EAGAIN) {
186  usleep(1000);
187  continue;
188  }
189  if (actual != nbytes) {
190  GSM_OSErrorInfo(s, "proxy_write");
191  smprintf(s, "Wanted to write %ld bytes, but %ld were written\n",
192  (long)nbytes, (long)actual);
193  }
194  return actual;
195  }
196  actual += ret;
197  buffer += ret;
198  if (s->ConnectionType == GCT_FBUS2PL2303) usleep(1000);
199  } while (actual < nbytes);
200  return actual;
201 }
202 
204 {
206  close(s->Device.Data.Proxy.hRead);
207  close(s->Device.Data.Proxy.hWrite);
208  return ERR_NONE;
209 }
210 
211 // aaa
213  proxy_open,
214  proxy_close,
215  NONEFUNCTION,
216  NONEFUNCTION,
217  NONEFUNCTION,
218  proxy_read,
220 };
221 
222 /* How should editor hadle tabs in this file? Add editor commands here.
223  * vim: noexpandtab sw=8 ts=8 sts=8:
224  */
GSM_Config * CurrentConfig
Definition: gsmstate.h:1415
void kill_proxy_command(pid_t proxy_command_pid)
Definition: proxy.c:119
static char * expand_proxy_command(const char *proxy_command)
Definition: proxy.c:20
GSM_Device_ProxyData Proxy
Definition: gsmstate.h:329
GSM_Error proxy_close(GSM_StateMachine *s)
Definition: proxy.c:203
union GSM_Device::@0 Data
GSM_ConnectionType ConnectionType
Definition: gsmstate.h:1402
static ssize_t write_nosigpipe(int fd, const void *buf, size_t len)
Definition: proxy.c:156
#define NONEFUNCTION
Definition: gsmcomon.h:12
GSM_Error
Definition: gammu-error.h:23
pid_t hProcess
Definition: proxy.h:9
GSM_Error proxy_open(GSM_StateMachine *s)
Definition: proxy.c:130
int proxy_write(GSM_StateMachine *s, const void *buf, size_t nbytes)
Definition: proxy.c:175
#define _PATH_BSHELL
Definition: proxy.c:32
static GSM_Error proxy_connect(GSM_StateMachine *s, GSM_Device_ProxyData *proxydata, const char *proxy_command)
Definition: proxy.c:39
int proxy_read(GSM_StateMachine *s, void *buf, size_t nbytes)
Definition: proxy.c:135
void GSM_OSErrorInfo(GSM_StateMachine *s, const char *description)
Definition: gsmstate.c:1593
GSM_Device_Functions ProxyDevice
Definition: proxy.c:212
#define dbgprintf
Definition: debug.h:72
GSM_Device Device
Definition: gsmstate.h:1429
int smprintf(GSM_StateMachine *s, const char *format,...)
Definition: debug.c:261