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