1    	// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2    	// vim: ts=8 sw=2 smarttab
3    	/*
4    	 * Ceph - scalable distributed file system
5    	 *
6    	 * Copyright (C) 2011 New Dream Network
7    	 *
8    	 * This is free software; you can redistribute it and/or
9    	 * modify it under the terms of the GNU Lesser General Public
10   	 * License version 2.1, as published by the Free Software
11   	 * Foundation.  See file COPYING.
12   	 *
13   	 */
14   	
15   	#include <arpa/inet.h>
16   	#include <fcntl.h>
17   	#include <sys/socket.h>
18   	#include <sys/un.h>
19   	
20   	#include "common/admin_socket.h"
21   	#include "common/errno.h"
22   	#include "common/safe_io.h"
23   	#include "common/admin_socket_client.h"
24   	
25   	#include "include/compat.h"
26   	#include "include/sock_compat.h"
27   	
28   	using std::ostringstream;
29   	
30   	const char* get_rand_socket_path()
31   	{
32   	  static char *g_socket_path = NULL;
33   	
34   	  if (g_socket_path == NULL) {
35   	    char buf[512];
36   	    const char *tdir = getenv("TMPDIR");
37   	    if (tdir == NULL) {
38   	      tdir = "/tmp";
39   	    }
40   	    snprintf(buf, sizeof(((struct sockaddr_un*)0)->sun_path),
41   		     "%s/perfcounters_test_socket.%ld.%ld",
42   		     tdir, (long int)getpid(), time(NULL));
43   	    g_socket_path = (char*)strdup(buf);
44   	  }
45   	  return g_socket_path;
46   	}
47   	
48   	static std::string asok_connect(const std::string &path, int *fd)
49   	{
50   	  int socket_fd = socket_cloexec(PF_UNIX, SOCK_STREAM, 0);
51   	  if(socket_fd < 0) {
52   	    int err = errno;
53   	    ostringstream oss;
54   	    oss << "socket(PF_UNIX, SOCK_STREAM, 0) failed: " << cpp_strerror(err);
55   	    return oss.str();
56   	  }
57   	
58   	  struct sockaddr_un address;
59   	  memset(&address, 0, sizeof(struct sockaddr_un));
60   	  address.sun_family = AF_UNIX;
61   	  snprintf(address.sun_path, sizeof(address.sun_path), "%s", path.c_str());
62   	
63   	  if (::connect(socket_fd, (struct sockaddr *) &address, 
64   		sizeof(struct sockaddr_un)) != 0) {
65   	    int err = errno;
66   	    ostringstream oss;
67   	    oss << "connect(" << socket_fd << ") failed: " << cpp_strerror(err);
68   	    close(socket_fd);
69   	    return oss.str();
70   	  }
71   	
72   	  struct timeval timer;
73   	  timer.tv_sec = 5;
74   	  timer.tv_usec = 0;
75   	  if (::setsockopt(socket_fd, SOL_SOCKET, SO_RCVTIMEO, &timer, sizeof(timer))) {
76   	    int err = errno;
77   	    ostringstream oss;
78   	    oss << "setsockopt(" << socket_fd << ", SO_RCVTIMEO) failed: "
79   		<< cpp_strerror(err);
80   	    close(socket_fd);
81   	    return oss.str();
82   	  }
83   	  timer.tv_sec = 5;
84   	  timer.tv_usec = 0;
85   	  if (::setsockopt(socket_fd, SOL_SOCKET, SO_SNDTIMEO, &timer, sizeof(timer))) {
86   	    int err = errno;
87   	    ostringstream oss;
88   	    oss << "setsockopt(" << socket_fd << ", SO_SNDTIMEO) failed: "
89   		<< cpp_strerror(err);
90   	    close(socket_fd);
91   	    return oss.str();
92   	  }
93   	
94   	  *fd = socket_fd;
95   	  return "";
96   	}
97   	
98   	static std::string asok_request(int socket_fd, std::string request)
99   	{
100  	  ssize_t res = safe_write(socket_fd, request.c_str(), request.length() + 1);
101  	  if (res < 0) {
102  	    int err = res;
103  	    ostringstream oss;
104  	    oss << "safe_write(" << socket_fd << ") failed to write request code: "
105  		<< cpp_strerror(err);
106  	    return oss.str();
107  	  }
108  	  return "";
109  	}
110  	
111  	AdminSocketClient::
112  	AdminSocketClient(const std::string &path)
113  	  : m_path(path)
114  	{
115  	}
116  	
117  	std::string AdminSocketClient::ping(bool *ok)
118  	{
119  	  std::string version;
120  	  std::string result = do_request("{\"prefix\":\"0\"}", &version);
121  	  *ok = result == "" && version.length() == 1;
122  	  return result;
123  	}
124  	
125  	std::string AdminSocketClient::do_request(std::string request, std::string *result)
126  	{
127  	  int socket_fd = 0, res;
128  	  std::string buffer;
129  	  uint32_t message_size_raw, message_size;
130  	
131  	  std::string err = asok_connect(m_path, &socket_fd);
(1) Event cond_false: Condition "!err.empty()", taking false branch.
132  	  if (!err.empty()) {
133  	    goto out;
(2) Event if_end: End of if statement.
134  	  }
135  	  err = asok_request(socket_fd, request);
(3) Event cond_false: Condition "!err.empty()", taking false branch.
136  	  if (!err.empty()) {
137  	    goto done;
(4) Event if_end: End of if statement.
138  	  }
(5) Event tainted_data_argument: Calling function "safe_read_exact" taints argument "message_size_raw". [details]
Also see events: [tainted_data_transitive][var_assign][tainted_data]
139  	  res = safe_read_exact(socket_fd, &message_size_raw,
140  					sizeof(message_size_raw));
(6) Event cond_false: Condition "res < 0", taking false branch.
141  	  if (res < 0) {
142  	    int e = res;
143  	    ostringstream oss;
144  	    oss << "safe_read(" << socket_fd << ") failed to read message size: "
145  		<< cpp_strerror(e);
146  	    err = oss.str();
147  	    goto done;
(7) Event if_end: End of if statement.
148  	  }
(8) Event tainted_data_transitive: Call to function "ntohl" with tainted argument "message_size_raw" returns tainted data.
(9) Event var_assign: Assigning: "message_size" = "ntohl", which taints "message_size".
Also see events: [tainted_data_argument][tainted_data]
149  	  message_size = ntohl(message_size_raw);
150  	  buffer.resize(message_size, 0);
(10) Event tainted_data: Passing tainted variable "message_size" to a tainted sink. [details]
Also see events: [tainted_data_argument][tainted_data_transitive][var_assign]
151  	  res = safe_read_exact(socket_fd, &buffer[0], message_size);
152  	  if (res < 0) {
153  	    int e = res;
154  	    ostringstream oss;
155  	    oss << "safe_read(" << socket_fd << ") failed: " << cpp_strerror(e);
156  	    err = oss.str();
157  	    goto done;
158  	  }
159  	  //printf("MESSAGE FROM SERVER: %s\n", buffer.c_str());
160  	  std::swap(*result, buffer);
161  	done:
162  	  close(socket_fd);
163  	 out:
164  	  return err;
165  	}
166