1 #include "config.h"
2
3 struct sshdata {
4 time_t start; /* test start time */
5 time_t lastact; /* last activity */
6 int state;
7 };
8
9 #define SSH_CONNECT 1 /* doing a connect() */
10 #define SSH_WAITBAN 2 /* Waiting for the version banner */
11 #define SSH_CLIVERS "SSH-2.0-Sysmon"
12
13 /*
14 Here's the deal with ssh checks. We do this:
15
16 We connect, and do this:
17
18 server>SSH-1.99-OpenSSH_3.4p1 Debian 1:3.4p1-1
19 us<SSH-2.0-Sysmon
20
21 If we get anything else than "SSH" at the first 3 chars, we return SYSM_BAD_RESP
22
23 If inactivity on socket is more than globtimeout, we return
24 SYSM_NORESP
25
26 Yes, i know this is a pretty lame check for now but it reduces the amount of warning messages
27 from sshd like "Did not receive identification string".
28 */
29
start_test_sshd(struct monitorent * here,time_t now_t)30 void start_test_sshd(struct monitorent *here, time_t now_t)
31 {
32 struct sshdata *localstruct = NULL;
33 struct my_hostent *hp = NULL;
34 struct sockaddr_in name;
35 int serrno = -1, errcode = 0;
36
37 /* Allocate our memory */
38 here->monitordata = MALLOC(sizeof(struct sshdata), "ssh localstruct");
39
40 localstruct = here->monitordata;
41
42 localstruct->start = now_t;
43
44 localstruct->lastact = localstruct->start;
45
46 here->filedes = open_sock();
47
48 if (here->filedes == -1)
49 {
50 here->retval = here->checkent->lastcheck;
51 FREE(here->monitordata);
52 here->monitordata = NULL;
53 return;
54 }
55
56 hp = my_gethostbyname(here->checkent->hostname, AF_INET);
57
58 if (hp == NULL)
59 {
60 here->retval = SYSM_NODNS;
61 FREE(here->monitordata);
62 here->monitordata = NULL;
63 return;
64 }
65
66 /* zero out the space */
67 memset ( &name, 0, sizeof ( name ) );
68
69 /* copy data */
70 memcpy((char*)&name.sin_addr, (char*)hp->my_h_addr_v4, hp->h_length_v4);
71
72 /* set family type */
73 name.sin_family = AF_INET;
74
75 /* set the port we're connecting to */
76 name.sin_port = htons(SSH_PORTNUM);
77
78 if (debug)
79 {
80 print_err(0, "start_test_sshd() doing connect() to %s:%d",
81 here->checkent->hostname, SSH_PORTNUM);
82 }
83
84 errcode = connect(here->filedes, (struct sockaddr*)&name,
85 sizeof(struct sockaddr_in));
86 serrno = errno;
87 if (debug)
88 {
89 perror("connect() in start_sshd");
90 }
91
92 if ((errcode < 0) && (serrno != EINPROGRESS))
93 {
94 if (close(here->filedes) == -1)
95 {
96 perror("ssh.c: closing fd");
97 }
98 here->retval = errno_to_error(serrno);
99
100 /* Free memory we'd normally leak */
101 FREE(localstruct);
102 here->monitordata = NULL;
103
104 print_err(0, "ssh: retval = %d\n", here->retval);
105 return;
106 }
107
108 /* doing a connect() */
109 localstruct->state = SSH_CONNECT;
110
111 /* poll it again later */
112 return;
113 }
114
service_test_sshd(struct monitorent * here,time_t now_t)115 void service_test_sshd(struct monitorent *here, time_t now_t)
116 {
117 /* do the actual real parts of the checks after
118 it's been set up */
119
120 struct sshdata *localstruct = NULL;
121 char buffer[256];
122 int isopenretval = -1;
123 int bytes = 0;
124
125 /* Check for problems */
126 if (here == NULL)
127 {
128 return;
129 }
130
131 /* do some variable shuffling */
132
133 localstruct = here->monitordata;
134
135 if (localstruct == NULL)
136 {
137 print_err(0, "bug! localstruct == NULL in ssh.c:service_test_sshd");
138 return;
139 }
140
141 if (debug)
142 {
143 print_err(0, "in service_test_sshd and the state is %d",localstruct->state);
144 }
145
146 /* do different things based on the state */
147 switch (localstruct->state)
148 {
149 case SSH_CONNECT:
150 {
151 isopenretval = is_open(here->filedes);
152 if ((isopenretval != -1) &&
153 (isopenretval != SYSM_INPROG))
154 {
155 localstruct->lastact = now_t;
156 if (debug)
157 print_err(0, "is_open() in service_test_sshd()");
158 if (isopenretval != SYSM_OK)
159 {
160 here->retval = isopenretval;
161 close(here->filedes);
162 FREE(localstruct);
163 here->monitordata = NULL;
164 if (debug)
165 print_err(0, "ending service_test_sshd() with retval = %s", errtostr(here->retval));
166 return;
167 }
168 localstruct->state = SSH_WAITBAN;
169 if (debug)
170 print_err(0, "connected() to the ssh port of %s", here->checkent->hostname);
171 }
172 if (((now_t)-localstruct->start) >= globtimeout)
173 {
174 here->retval = SYSM_TIMEDOUT;
175 close(here->filedes);
176 FREE(localstruct);
177 here->monitordata = NULL;
178 if (debug)
179 {
180 print_err(0, "ending service_test_sshd() with retval = %s",
181 errtostr(here->retval));
182 }
183 return;
184 }
185 break;
186 }
187 case SSH_WAITBAN:
188 {
189 if (data_waiting_read(here->filedes, 0))
190 {
191 memset(buffer, 0, 256);
192 bytes =read(here->filedes, buffer, 254);
193 if (bytes != 0 && bytes != -1)
194 {
195 buffer[strlen(buffer)-1] = '\0';
196 } else if (bytes == -1) {
197 perror("ssh.c:service_test_sshd:read");
198 }
199 if(debug)
200 print_err(0, "Got: '%s'", buffer);
201
202 if (strncmp(buffer, "SSH", 3) == 0)
203 {
204 sendline(here->filedes, SSH_CLIVERS);
205 here->retval = SYSM_OK;
206 } else {
207 here->retval = SYSM_BAD_RESP;
208 }
209 }
210 break;
211 }
212 default:
213 {
214 print_err(1, "ssh.c: bug, how did we get here? localstruct->state = %d", localstruct->state);
215 break;
216 }
217 }
218 if (here->retval != -1)
219 {
220 /* insert cleanup code here */
221 close (here->filedes);
222 FREE(localstruct);
223 here->monitordata = NULL;
224 }
225 return;
226 }
227
228 void
stop_test_sshd(struct monitorent * here)229 stop_test_sshd(struct monitorent *here)
230 {
231 struct sshdata *localstruct = NULL;
232
233 localstruct = here->monitordata;
234
235 if (localstruct == NULL)
236 return;
237
238 close(here->filedes);
239 FREE(localstruct);
240 here->monitordata = NULL;
241 return;
242
243 }
244