1/*
2 * Copyright (c) 2000, Boris Popov
3 * All rights reserved.
4 *
5 * Portions Copyright (C) 2001 - 2010 Apple Inc. All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 *    must display the following acknowledgement:
17 *    This product includes software developed by Boris Popov.
18 * 4. Neither the name of the author nor the names of any co-contributors
19 *    may be used to endorse or promote products derived from this software
20 *    without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 *
34 * $Id: nb_name.c,v 1.12 2005/05/06 23:16:29 lindak Exp $
35 */
36#include <netsmb/netbios.h>
37#include <sys/smb_byte_order.h>
38#include <netsmb/smb_lib.h>
39#include <netsmb/nb_lib.h>
40
41static int nb_snballoc(int namelen, struct sockaddr_nb **dst)
42{
43	struct sockaddr_nb *snb;
44	int slen;
45
46	slen = namelen + (int)sizeof(*snb) - (int)sizeof(snb->snb_name);
47	snb = malloc(slen);
48	if (snb == NULL)
49		return ENOMEM;
50	bzero(snb, slen);
51	snb->snb_family = AF_NETBIOS;
52	snb->snb_len = slen;
53	*dst = snb;
54	return 0;
55}
56
57/*
58 * Create a NetBIOS address, we expect the name to already be in the correct
59 * case.
60 */
61int nb_sockaddr(struct sockaddr *peer, const char *name, unsigned type,
62				struct sockaddr **dst)
63
64{
65	struct nb_name nn;
66	struct nb_name *np = &nn;
67	struct sockaddr_nb *snb;
68	int nmlen, error;
69
70	if (peer && (peer->sa_family != AF_INET))
71		return EPROTONOSUPPORT;
72
73	strlcpy((char *)nn.nn_name, name, sizeof(nn.nn_name));
74	nn.nn_type = type;
75
76	nmlen = NB_ENCNAMELEN + 2;
77	error = nb_snballoc(nmlen, &snb);
78	if (error)
79		return error;
80	nb_name_encode(np, snb->snb_name);
81	if (peer)
82		memcpy(&snb->snb_addrin, peer, peer->sa_len);
83	*dst = (struct sockaddr *)snb;
84	return 0;
85}
86
87/*
88 * Convert a sockaddr into a sockaddr_nb. We always assume the type is server. On
89 * error we leave the sockaddr in its original state.
90 */
91void convertToNetBIOSaddr(struct sockaddr_storage *storage, const char *name)
92{
93	struct sockaddr *peer = (struct sockaddr *)storage;
94	struct sockaddr *dst = NULL;
95
96	if (nb_sockaddr(peer, name, NBT_SERVER, &dst) == 0) {
97        if ((peer != NULL) && (dst != NULL)) {
98            memcpy(peer, dst, dst->sa_len);
99        }
100
101        if (dst != NULL) {
102            free(dst);
103        }
104	}
105}
106
107int
108nb_encname_len(const char *str)
109{
110	const u_char *cp = (const u_char *)str;
111	int len, blen;
112
113	if ((cp[0] & 0xc0) == 0xc0)
114		return -1;	/* first two bytes are offset to name */
115
116	len = 1;
117	for (;;) {
118		blen = *cp;
119		if (blen++ == 0)
120			break;
121		len += blen;
122		cp += blen;
123	}
124	return len;
125}
126
127/* B4BP (7/23/01 sent to BP) endian fix! */
128#define	NBENCODE(c)	(htoles((u_short)(((u_char)(c) >> 4) | \
129			 (((u_char)(c) & 0xf) << 8)) + 0x4141))
130
131static void
132memsetw(char *dst, int n, u_short word)
133{
134	while (n--) {
135		*(u_short*)((void *)dst) = word;
136		dst += 2;
137	}
138}
139
140/*
141 * We never uppercase in this routine any more. If the calling process wants
142 * it uppercased then it shoud make sure nn_name is uppercase before entering
143 * this routine. There is no way for us to get that correct in the routine.
144 */
145void nb_name_encode(struct nb_name *np, u_char *dst)
146{
147	u_char *name;
148	u_char *cp = dst;
149	int i;
150
151	*cp++ = NB_ENCNAMELEN;
152	name = np->nn_name;
153	if (name[0] == '*' && name[1] == 0) {
154		*(u_short*)((void *)cp) = NBENCODE('*');
155		memsetw((char *)cp + 2, NB_NAMELEN - 1, NBENCODE((char)0));
156		cp += NB_ENCNAMELEN;
157	} else {
158		/* freebsd bug: system names must be truncated to 15 chars not 16 */
159		for (i = 0; *name && i < NB_NAMELEN - 1; i++, cp += 2, name++)
160				*(u_short*)((void *)cp) = NBENCODE(*name);
161
162		i = NB_NAMELEN - i - 1;
163		if (i > 0) {
164			memsetw((char *)cp, i, NBENCODE(' '));
165			cp += i * 2;
166		}
167		*(u_short*)((void *)cp) = NBENCODE(np->nn_type);
168		cp += 2;
169	}
170	*cp = 0;
171}
172
173