1 /* forward_api_calls.c: forward XMLRPC calls to the Node Manager
2 * Used as a shell, this code works in tandem with sshd
3 * to allow authenticated remote access to a localhost-only service.
6 * Doesn't handle Unicode properly. UTF-8 is probably OK.
9 * 2007/05/02: [deisenst] Increased buffer space to 1MiB.
10 * Increased TIMEOUT_SECS to 2min.
11 * 2006/10/30: [deisenst] Changed location of Unix socket.
12 * 2006/09/14: [deisenst] Switched to PF_UNIX sockets so that SO_PEERCRED works
13 * 2006/09/08: [deisenst] First version.
16 static const int TIMEOUT_SECS = 120;
17 const char *API_addr = "/tmp/sliver_mgr.api";
19 static const char *Header =
21 "Content-Type: text/xml\r\n"
22 "Content-Length: %d\r\n"
25 static const char *Error_template =
26 "<?xml version='1.0'?>\n"
31 "<name>faultCode</name>\n"
32 "<value><int>1</int></value>\n"
35 "<name>faultString</name>\n"
36 "<value><string>%s: %s</string></value>\n"
40 "</methodResponse>\n";
47 #include <sys/socket.h>
48 #include <sys/types.h>
52 static void ERROR(const char *s) {
53 printf(Error_template, s, strerror(errno));
57 int main(int argc, char **argv, char **envp) {
59 char header_buf[1<<20];
60 char content_buf[1<<20];
63 struct sockaddr_un addr;
64 int consecutive_newlines;
68 /* read xmlrpc request from stdin
69 * 4 KiB ought to be enough for anyone
70 * 2007/05/02: [deisenst] It wasn't.
73 while(content_len < sizeof content_buf) {
75 content_buf + content_len,
76 sizeof content_buf - content_len);
77 if(len < 0) ERROR("read()");
78 else if(0 == len) break;
82 /* connect to the API server */
83 sockfd = socket(PF_UNIX, SOCK_STREAM, 0);
86 memset(&addr, 0, sizeof addr);
87 addr.sun_family = AF_UNIX;
88 strncpy(addr.sun_path, API_addr, sizeof addr.sun_path);
89 if(connect(sockfd, (struct sockaddr *)&addr, sizeof addr) < 0)
92 /* send the request */
93 snprintf(header_buf, sizeof header_buf, Header, content_len, &len);
94 write(sockfd, header_buf, len);
95 write(sockfd, content_buf, content_len);
96 shutdown(sockfd, SHUT_WR);
98 /* forward the response */
99 consecutive_newlines = 0;
100 while((len = read(sockfd, content_buf, sizeof content_buf)) != 0) {
101 size_t processed_len = 0;
103 /* "Connection reset by peer" is not worth bothering the user. */
104 if(ECONNRESET == errno) break;
105 else ERROR("read()");
109 while(consecutive_newlines < 2 && processed_len < content_len) {
110 char ch = content_buf[processed_len++];
111 if(ch == '\n') consecutive_newlines++;
112 else if(!isspace(ch)) consecutive_newlines = 0;
115 if(processed_len < content_len) {
116 len = fwrite(content_buf + processed_len, sizeof (char),
117 content_len - processed_len, stdout);
118 /* make sure faults don't mess up previously sent xml */
119 if(len < content_len - processed_len) ERROR("fwrite()");
124 shutdown(sockfd, SHUT_RD);