vendor.c revision 1.1
1/*	$OpenBSD:	*/
2/*
3 * Copyright (c) 2006 Hans-Joerg Hoexer <hshoexer@openbsd.org>
4 *
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17
18#include <sys/types.h>
19#include <stdlib.h>
20#include <string.h>
21
22#include "exchange.h"
23#include "hash.h"
24#include "log.h"
25#include "message.h"
26#include "vendor.h"
27
28static struct vendor_cap openbsd_vendor_cap[] = {
29	{ "OpenBSD-4.0", NULL, 0 },
30};
31
32#define NUMVIDS	(sizeof openbsd_vendor_cap / sizeof openbsd_vendor_cap[0])
33
34static int
35setup_vendor_hashes(void)
36{
37	struct hash	*hash;
38	int		 i, n = NUMVIDS;
39
40	hash = hash_get(HASH_MD5);
41	if (!hash) {
42		log_print("setup_vendor_hashes: could not find MD5 hash");
43		return (-1);
44	}
45
46	for (i = 0; i < n; i++) {
47		openbsd_vendor_cap[i].hashsize = hash->hashsize;
48		openbsd_vendor_cap[i].hash = calloc(hash->hashsize,
49		    sizeof(u_int8_t));
50		if (openbsd_vendor_cap[i].hash == NULL) {
51			log_error("setup_vendor_hashes: calloc failed");
52			goto errout;
53		}
54
55		hash->Init(hash->ctx);
56		hash->Update(hash->ctx,
57		    (unsigned char *)openbsd_vendor_cap[i].text,
58		    strlen(openbsd_vendor_cap[i].text));
59		hash->Final(openbsd_vendor_cap[i].hash, hash->ctx);
60
61		LOG_DBG((LOG_EXCHANGE, 50, "setup_vendor_hashes: "
62		    "MD5(\"%s\") (%lu bytes)", openbsd_vendor_cap[i].text,
63		    (unsigned long)hash->hashsize));
64		LOG_DBG_BUF((LOG_EXCHANGE, 50, "setup_vendor_hashes",
65		    openbsd_vendor_cap[i].hash, hash->hashsize));
66	}
67	return (0);
68
69errout:
70	for (i = 0; i < n; i++)
71		if (openbsd_vendor_cap[i].hash)
72			free(openbsd_vendor_cap[i].hash);
73	return (-1);
74}
75
76void
77vendor_init(void)
78{
79	setup_vendor_hashes();
80}
81
82int
83add_vendor_openbsd(struct message *msg)
84{
85	u_int8_t	*buf;
86	size_t		 buflen;
87	int		 i, n = NUMVIDS;
88
89	for (i = 0; i < n; i++) {
90		buflen = openbsd_vendor_cap[i].hashsize + ISAKMP_GEN_SZ;
91		if ((buf = calloc(buflen, sizeof(char))) == NULL) {
92			log_error("add_vendor_payload: calloc(%lu) failed",
93			    (unsigned long)buflen);
94			return (-1);
95		}
96
97		SET_ISAKMP_GEN_LENGTH(buf, buflen);
98		memcpy(buf + ISAKMP_VENDOR_ID_OFF, openbsd_vendor_cap[i].hash,
99		    openbsd_vendor_cap[i].hashsize);
100		if (message_add_payload(msg, ISAKMP_PAYLOAD_VENDOR, buf,
101		    buflen, 1)) {
102			free(buf);
103			return (-1);
104		}
105	}
106
107	return (0);
108}
109
110void
111check_vendor_openbsd(struct message *msg, struct payload *p)
112{
113	u_int8_t	*pbuf = p->p;
114	ssize_t		 vlen;
115	int		 i, n = NUMVIDS;
116
117	if (msg->exchange->flags & EXCHANGE_FLAG_OPENBSD) {
118		p->flags |= PL_MARK;
119		return;
120	}
121
122	vlen = GET_ISAKMP_GEN_LENGTH(pbuf) - ISAKMP_GEN_SZ;
123
124	for (i = 0; i < n; i++) {
125		if (vlen != openbsd_vendor_cap[i].hashsize) {
126			LOG_DBG((LOG_EXCHANGE, 90,
127			    "check_vendor_openbsd: bad size %lu != %lu",
128			    (unsigned long)vlen,
129			    (unsigned long)openbsd_vendor_cap[i].hashsize));
130			continue;
131		}
132		if (memcmp(openbsd_vendor_cap[i].hash, pbuf + ISAKMP_GEN_SZ,
133		    vlen) == 0) {
134			msg->exchange->flags |= EXCHANGE_FLAG_OPENBSD;
135			LOG_DBG((LOG_EXCHANGE, 10, "check_vendor_openbsd: "
136			    "OpenBSD (%s)", openbsd_vendor_cap[i].text));
137		}
138		p->flags |= PL_MARK;
139	}
140}
141