Support for -s. More comments. Removed out of date documentation and bwcap.
[nodemanager.git] / forward_api_calls.c
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.
4  *
5  * Bugs:
6  * Doesn't handle Unicode properly.  UTF-8 is probably OK.
7  *
8  * Change History:
9  * 2006/10/30: [deisenst] Changed location of Unix socket.
10  * 2006/09/14: [deisenst] Switched to PF_UNIX sockets so that SO_PEERCRED works
11  * 2006/09/08: [deisenst] First version.
12  */
13
14 static const int TIMEOUT_SECS = 30;
15 const char *API_addr = "/tmp/sliver_mgr.api";
16
17 static const char *Header =
18   "POST / HTTP/1.0\r\n"
19   "Content-Type: text/xml\r\n"
20   "Content-Length: %d\r\n"
21   "\r\n%n";
22
23 static const char *Error_template =
24   "<?xml version='1.0'?>\n"
25   "<methodResponse>\n"
26   "<fault>\n"
27   "<value><struct>\n"
28   "<member>\n"
29   "<name>faultCode</name>\n"
30   "<value><int>1</int></value>\n"
31   "</member>\n"
32   "<member>\n"
33   "<name>faultString</name>\n"
34   "<value><string>%s: %s</string></value>\n"
35   "</member>\n"
36   "</struct></value>\n"
37   "</fault>\n"
38   "</methodResponse>\n";
39
40 #include <ctype.h>
41 #include <errno.h>
42 #include <stdio.h>
43 #include <stdlib.h>
44 #include <string.h>
45 #include <sys/socket.h>
46 #include <sys/types.h>
47 #include <sys/un.h>
48 #include <unistd.h>
49
50 static void ERROR(const char *s) {
51   printf(Error_template, s, strerror(errno));
52   exit(1);
53 }
54
55 int main(int argc, char **argv, char **envp) {
56   ssize_t len;
57   char header_buf[4096];
58   char content_buf[4096];
59   size_t content_len;
60   int sockfd;
61   struct sockaddr_un addr;
62   int consecutive_newlines;
63
64   alarm(TIMEOUT_SECS);
65
66   /* read xmlrpc request from stdin
67    * 4 KiB ought to be enough for anyone
68    */
69   content_len = 0;
70   while(content_len < sizeof content_buf) {
71     len = read(0,
72                content_buf + content_len,
73                sizeof content_buf - content_len);
74     if(len < 0) ERROR("read()");
75     else if(0 == len) break;
76     content_len += len;
77   }
78
79   /* connect to the API server */
80   sockfd = socket(PF_UNIX, SOCK_STREAM, 0);
81   if(sockfd < 0)
82     ERROR("socket()");
83   memset(&addr, 0, sizeof addr);
84   addr.sun_family = AF_UNIX;
85   strncpy(addr.sun_path, API_addr, sizeof addr.sun_path);
86   if(connect(sockfd, (struct sockaddr *)&addr, sizeof addr) < 0)
87     ERROR("connect()");
88
89   /* send the request */
90   snprintf(header_buf, sizeof header_buf, Header, content_len, &len);
91   write(sockfd, header_buf, len);
92   write(sockfd, content_buf, content_len);
93   shutdown(sockfd, SHUT_WR);
94
95   /* forward the response */
96   consecutive_newlines = 0;
97   while((len = read(sockfd, content_buf, sizeof content_buf)) != 0) {
98     size_t processed_len = 0;
99     if(len < 0) {
100       /* "Connection reset by peer" is not worth bothering the user. */
101       if(ECONNRESET == errno) break;
102       else ERROR("read()");
103     }
104     content_len = len;
105
106     while(consecutive_newlines < 2 && processed_len < content_len) {
107       char ch = content_buf[processed_len++];
108       if(ch == '\n') consecutive_newlines++;
109       else if(!isspace(ch)) consecutive_newlines = 0;
110     }
111
112     if(processed_len < content_len) {
113       len = fwrite(content_buf + processed_len, sizeof (char),
114                    content_len - processed_len, stdout);
115       /* make sure faults don't mess up previously sent xml */
116       if(len < content_len - processed_len) ERROR("fwrite()");
117     }
118   }
119
120   /* goodbye */
121   shutdown(sockfd, SHUT_RD);
122   close(sockfd);
123
124   return 0;
125 }