]> andersk Git - moira.git/blame - lib/mr_connect.c
Prevent against format string attack by adding third arg to syslog()
[moira.git] / lib / mr_connect.c
CommitLineData
fa59b86f 1/* $Id$
e2a67c78 2 *
7ac48069 3 * This routine is part of the client library. It handles
4 * creating a connection to the moira server.
5eaef520 5 *
7ac48069 6 * Copyright (C) 1987-1998 by the Massachusetts Institute of Technology
7 * For copying and distribution information, please see the file
8 * <mit-copyright.h>.
e2a67c78 9 */
10
babbc197 11#include <mit-copyright.h>
7ac48069 12#include <moira.h>
8defc06b 13#include <moira_site.h>
7ac48069 14#include "mr_private.h"
15
85330553 16#include <sys/types.h>
85330553 17
7ac48069 18#include <errno.h>
a43ce477 19#include <stdlib.h>
7ac48069 20#include <string.h>
533bacb3 21
22#ifdef HAVE_UNISTD_H
85330553 23#include <unistd.h>
533bacb3 24#endif
25
26#ifndef _WIN32
27#include <sys/socket.h>
28#include <netinet/in.h>
29#include <netdb.h>
30#ifndef closesocket
31#define closesocket close
32#endif
33#ifndef SOCKET_ERROR
34#define SOCKET_ERROR -1
35#endif
36#endif
7ac48069 37
ea0caf4a 38#ifdef HAVE_HESIOD
a43ce477 39#include <hesiod.h>
ea0caf4a 40#endif
05fb8281 41
7ac48069 42RCSID("$Header$");
43
533bacb3 44#define DEFAULT_SERV "moira_db"
45#define DEFAULT_PORT 775
46
85330553 47int _mr_conn = 0;
48static char *mr_server_host = NULL;
49
50/* mrgdb compatibility magic
51
52 The data looks like this:
53
54 client -> server
55 00000036 [length of rest of packet]
56 00000004 [number of fields]
57 01 01 01 01 [types of fields: 4 strings]
58 "server_id\0parms\0host\0user\0" [field names]
59 00000001 [length of null-terminated server_id]
60 "\0" [server_id: ignored anyway]
61 00000001 [length of null-terminated parms]
62 "\0" [parms: ignored anyway]
63 00000001 [length of null-terminated client host]
64 "\0" [host: ignored anyway]
65 00000001 [length of null-terminated client name]
66 "\0" [user: ignored anyway]
67
68 server -> client
69 00000031 [length of rest of packet]
70 00000003 [number of fields]
71 00 01 01 [types of fields: int and 2 strings]
72 "disposition\0server_id\0parms\0" [field names]
73 00000001 [GDB_ACCEPTED]
74 00000001 [length of null-terminated server_id]
75 "\0" [server_id: ignored anyway]
76 00000001 [length of null-terminated parms]
77 "\0" [parms: ignored anyway]
78
79*/
80
81static char challenge[58] = "\0\0\0\066\0\0\0\004\001\001\001\001server_id\0parms\0host\0user\0\0\0\0\001\0\0\0\0\001\0\0\0\0\001\0\0\0\0\001\0";
82static char response[53] = "\0\0\0\061\0\0\0\003\0\001\001disposition\0server_id\0parms\0\0\0\0\001\0\0\0\001\0\0\0\0\001\0";
e2a67c78 83
84/*
85330553 85 * Open a connection to the moira server. Looks for the server name
5450e3a1 86 * 1) passed as an argument, 2) in environment variable, 3) by hesiod
85330553 87 * 4) compiled in default
e2a67c78 88 */
89
5eaef520 90int mr_connect(char *server)
e2a67c78 91{
85330553 92 char *port, **pp, *sbuf = NULL;
5eaef520 93
5eaef520 94 if (_mr_conn)
95 return MR_ALREADY_CONNECTED;
85330553 96 if (!mr_inited)
97 mr_init();
5eaef520 98
99 if (!server || (strlen(server) == 0))
100 server = getenv("MOIRASERVER");
5450e3a1 101
ea0caf4a 102#ifdef HAVE_HESIOD
5eaef520 103 if (!server || (strlen(server) == 0))
104 {
105 pp = hes_resolve("moira", "sloc");
106 if (pp)
107 server = *pp;
5450e3a1 108 }
a43ce477 109#endif
5450e3a1 110
5eaef520 111 if (!server || (strlen(server) == 0))
112 server = MOIRA_SERVER;
5450e3a1 113
85330553 114 if (strchr(server, ':'))
5eaef520 115 {
85330553 116 int len = strcspn(server, ":");
117 sbuf = malloc(len + 1);
118 strncpy(sbuf, server, len);
b59b20cd 119 sbuf[len] = '\0';
85330553 120 port = strchr(server, ':') + 1;
b59b20cd 121 server = sbuf;
85330553 122 }
123 else
124 port = strchr(MOIRA_SERVER, ':') + 1;
125
126 _mr_conn = mr_connect_internal(server, port);
127 free(sbuf);
128 if (!_mr_conn)
129 return MR_CANT_CONNECT;
130
85330553 131 return MR_SUCCESS;
132}
133
134int mr_connect_internal(char *server, char *port)
135{
533bacb3 136 int size, more;
85330553 137 struct sockaddr_in target;
138 struct hostent *shost;
139 char actualresponse[53];
533bacb3 140 char *host = NULL;
141 int fd = SOCKET_ERROR;
142 int ok = 0;
85330553 143
144 shost = gethostbyname(server);
145 if (!shost)
533bacb3 146 goto cleanup;
147
148 /* Get the host info in case some library decides to clobber shost. */
149 memcpy(&target.sin_addr, shost->h_addr, shost->h_length);
150 target.sin_family = shost->h_addrtype;
151 host = strdup(shost->h_name);
85330553 152
153 if (port[0] == '#')
533bacb3 154 target.sin_port = htons((unsigned short)atoi(port + 1));
85330553 155 else
156 {
157 struct servent *s;
533bacb3 158 target.sin_port = 0;
85330553 159 s = getservbyname(port, "tcp");
160 if (s)
161 target.sin_port = s->s_port;
88a72f00 162#ifdef HAVE_HESIOD
533bacb3 163 if (!target.sin_port)
88a72f00 164 {
165 s = hes_getservbyname(port, "tcp");
166 if (s)
167 target.sin_port = s->s_port;
88a72f00 168 }
88a72f00 169#endif
533bacb3 170 if (!target.sin_port && !strcasecmp(port, DEFAULT_SERV))
171 target.sin_port = htons(DEFAULT_PORT);
172 if (!target.sin_port)
173 goto cleanup;
5450e3a1 174 }
175
85330553 176 fd = socket(AF_INET, SOCK_STREAM, 0);
177 if (fd < 0)
533bacb3 178 goto cleanup;
85330553 179
180 if (connect(fd, (struct sockaddr *)&target, sizeof(target)) < 0)
533bacb3 181 goto cleanup;
05fb8281 182
85330553 183 /* Do magic mrgdb initialization */
533bacb3 184 size = send(fd, challenge, sizeof(challenge), 0);
85330553 185 if (size != sizeof(challenge))
533bacb3 186 goto cleanup;
85330553 187 for (size = 0; size < sizeof(actualresponse); size += more)
188 {
533bacb3 189 more = recv(fd, actualresponse + size, sizeof(actualresponse) - size, 0);
12cbd6bd 190 if (more <= 0)
85330553 191 break;
192 }
193 if (size != sizeof(actualresponse))
533bacb3 194 goto cleanup;
85330553 195 if (memcmp(actualresponse, response, sizeof(actualresponse)))
533bacb3 196 goto cleanup;
197
198 ok = 1;
199 mr_server_host = host;
200
201 cleanup:
202 if (!ok)
85330553 203 {
533bacb3 204 if (host)
205 free(host);
206 if (fd != SOCKET_ERROR)
207 closesocket(fd);
85330553 208 return 0;
209 }
85330553 210 /* You win */
211 return fd;
e2a67c78 212}
5eaef520 213
214int mr_disconnect(void)
e2a67c78 215{
5eaef520 216 CHECK_CONNECTED;
533bacb3 217 closesocket(_mr_conn);
85330553 218 _mr_conn = 0;
5eaef520 219 free(mr_server_host);
85330553 220 mr_server_host = NULL;
221 return MR_SUCCESS;
e2a67c78 222}
223
5eaef520 224int mr_host(char *host, int size)
05fb8281 225{
5eaef520 226 CHECK_CONNECTED;
05fb8281 227
5eaef520 228 /* If we are connected, mr_server_host points to a valid string. */
229 strncpy(host, mr_server_host, size);
85330553 230 host[size - 1] = '\0';
231 return MR_SUCCESS;
05fb8281 232}
233
5eaef520 234int mr_noop(void)
e2a67c78 235{
5eaef520 236 int status;
85330553 237 mr_params params, reply;
5eaef520 238
239 CHECK_CONNECTED;
85330553 240 params.u.mr_procno = MR_NOOP;
241 params.mr_argc = 0;
242 params.mr_argl = NULL;
243 params.mr_argv = NULL;
5eaef520 244
85330553 245 if ((status = mr_do_call(&params, &reply)) == MR_SUCCESS)
246 status = reply.u.mr_status;
5eaef520 247
248 mr_destroy_reply(reply);
249
250 return status;
6c00b7c4 251}
85330553 252
253
254/* Server side */
255
256int mr_listen(char *port)
257{
258 struct sockaddr_in sin;
259 int s, on = 1;
260
261 memset(&sin, 0, sizeof(sin));
262 if (port[0] == '#')
263 sin.sin_port = atoi(port + 1);
264 else
265 {
266 struct servent *s;
267 s = getservbyname(port, "tcp");
268 if (s)
269 sin.sin_port = s->s_port;
270 else
271 return -1;
272 }
273
274 s = socket(AF_INET, SOCK_STREAM, 0);
275 if (s < 0)
276 return -1;
277 if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(int)) < 0)
278 {
533bacb3 279 closesocket(s);
85330553 280 return -1;
281 }
282 if (bind(s, (struct sockaddr *)&sin, sizeof(sin)) < 0)
283 {
533bacb3 284 closesocket(s);
85330553 285 return -1;
286 }
287 if (listen(s, 5) < 0)
288 {
533bacb3 289 closesocket(s);
85330553 290 return -1;
291 }
292
293 return s;
294}
295
12cbd6bd 296/* mr_accept returns -1 on accept() error, 0 on bad connection,
297 or connection fd on success */
298
85330553 299int mr_accept(int s, struct sockaddr_in *sin)
300{
78eea87c 301 int conn = -1, addrlen = sizeof(struct sockaddr_in), nread, status;
767253c8 302 char *buf = NULL;
85330553 303
78eea87c 304 while (conn < 0)
305 {
306 conn = accept(s, (struct sockaddr *)sin, &addrlen);
f237ecc9 307 if (conn < 0 && errno != EINTR
308#ifdef ERESTART
309 && errno != ERESTART
310#endif
311 )
78eea87c 312 return -1;
313 }
85330553 314
12cbd6bd 315 do
316 status = mr_cont_accept(conn, &buf, &nread);
317 while (status == -1);
85330553 318
12cbd6bd 319 return status;
320}
85330553 321
88381def 322/* mr_cont_accept returns 0 if it has failed, an fd if it has succeeded,
323 or -1 if it is still making progress */
324
12cbd6bd 325int mr_cont_accept(int conn, char **buf, int *nread)
326{
327 long len, more;
328
329 if (!*buf)
85330553 330 {
12cbd6bd 331 char lbuf[4];
533bacb3 332 if (recv(conn, lbuf, 4, 0) != 4)
12cbd6bd 333 {
533bacb3 334 closesocket(conn);
88381def 335 return 0;
12cbd6bd 336 }
337 getlong(lbuf, len);
338 len += 4;
339
340 *buf = malloc(len);
341 if (!*buf || len < 58)
342 {
533bacb3 343 closesocket(conn);
767253c8 344 free(*buf);
12cbd6bd 345 return 0;
346 }
347 putlong(*buf, len);
348 *nread = 4;
85330553 349 return -1;
350 }
12cbd6bd 351 else
352 getlong(*buf, len);
85330553 353
533bacb3 354 more = recv(conn, *buf + *nread, len - *nread, 0);
12cbd6bd 355
356 if (more == -1 && errno != EINTR)
85330553 357 {
533bacb3 358 closesocket(conn);
12cbd6bd 359 free(*buf);
85330553 360 return 0;
361 }
362
12cbd6bd 363 *nread += more;
364
365 if (*nread != len)
366 return -1;
367
368 if (memcmp(*buf + 4, challenge + 4, 34))
85330553 369 {
533bacb3 370 closesocket(conn);
12cbd6bd 371 free(*buf);
85330553 372 return 0;
373 }
374
375 /* good enough */
12cbd6bd 376 free(*buf);
85330553 377
533bacb3 378 if (send(conn, response, sizeof(response), 0) != sizeof(response))
85330553 379 {
533bacb3 380 closesocket(conn);
12cbd6bd 381 return 0;
85330553 382 }
383 return conn;
384}
This page took 0.174654 seconds and 5 git commands to generate.