xref: /illumos-gate/usr/src/lib/smbsrv/libsmb/common/smb_util.c (revision dc20a3024900c47dd2ee44b9707e6df38f7d62a5)
1da6c28aaSamw /*
2da6c28aaSamw  * CDDL HEADER START
3da6c28aaSamw  *
4da6c28aaSamw  * The contents of this file are subject to the terms of the
5da6c28aaSamw  * Common Development and Distribution License (the "License").
6da6c28aaSamw  * You may not use this file except in compliance with the License.
7da6c28aaSamw  *
8da6c28aaSamw  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9da6c28aaSamw  * or http://www.opensolaris.org/os/licensing.
10da6c28aaSamw  * See the License for the specific language governing permissions
11da6c28aaSamw  * and limitations under the License.
12da6c28aaSamw  *
13da6c28aaSamw  * When distributing Covered Code, include this CDDL HEADER in each
14da6c28aaSamw  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15da6c28aaSamw  * If applicable, add the following below this CDDL HEADER, with the
16da6c28aaSamw  * fields enclosed by brackets "[]" replaced with your own identifying
17da6c28aaSamw  * information: Portions Copyright [yyyy] [name of copyright owner]
18da6c28aaSamw  *
19da6c28aaSamw  * CDDL HEADER END
20da6c28aaSamw  */
21da6c28aaSamw /*
22*dc20a302Sas  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23da6c28aaSamw  * Use is subject to license terms.
24da6c28aaSamw  */
25da6c28aaSamw 
26da6c28aaSamw #pragma ident	"%Z%%M%	%I%	%E% SMI"
27da6c28aaSamw 
28da6c28aaSamw #include <ctype.h>
29da6c28aaSamw #include <stdio.h>
30da6c28aaSamw #include <string.h>
31da6c28aaSamw #include <stdlib.h>
32da6c28aaSamw #include <pthread.h>
33da6c28aaSamw #include <sys/varargs.h>
34da6c28aaSamw #include <sys/types.h>
35da6c28aaSamw #include <smbsrv/string.h>
36*dc20a302Sas #include <smbsrv/libsmb.h>
37da6c28aaSamw 
38da6c28aaSamw #define	C2H(c)		"0123456789ABCDEF"[(c)]
39da6c28aaSamw #define	H2C(c)    (((c) >= '0' && (c) <= '9') ? ((c) - '0') :     \
40da6c28aaSamw 	((c) >= 'a' && (c) <= 'f') ? ((c) - 'a' + 10) :         \
41da6c28aaSamw 	((c) >= 'A' && (c) <= 'F') ? ((c) - 'A' + 10) :         \
42da6c28aaSamw 	'\0')
43da6c28aaSamw #define	DEFAULT_SBOX_SIZE		256
44da6c28aaSamw 
45da6c28aaSamw /*
46da6c28aaSamw  *
47da6c28aaSamw  * hexdump
48da6c28aaSamw  *
49da6c28aaSamw  * Simple hex dump display function. Displays nbytes of buffer in hex and
50da6c28aaSamw  * printable format. Non-printing characters are shown as '.'. It is safe
51da6c28aaSamw  * to pass a null pointer. Each line begins with the offset. If nbytes is
52da6c28aaSamw  * 0, the line will be blank except for the offset. Example output:
53da6c28aaSamw  *
54da6c28aaSamw  * 00000000  54 68 69 73 20 69 73 20 61 20 70 72 6F 67 72 61  This is a progra
55da6c28aaSamw  * 00000010  6D 20 74 65 73 74 2E 00                          m test..
56da6c28aaSamw  *
57da6c28aaSamw  */
58da6c28aaSamw void
59*dc20a302Sas hexdump_offset(unsigned char *buffer, int nbytes, unsigned long *start)
60da6c28aaSamw {
61da6c28aaSamw 	static char *hex = "0123456789ABCDEF";
62da6c28aaSamw 	int i, count;
63da6c28aaSamw 	int offset;
64da6c28aaSamw 	unsigned char *p;
65da6c28aaSamw 	char ascbuf[64];
66da6c28aaSamw 	char hexbuf[64];
67da6c28aaSamw 	char *ap = ascbuf;
68da6c28aaSamw 	char *hp = hexbuf;
69da6c28aaSamw 
70*dc20a302Sas 	if ((p = buffer) == NULL)
71da6c28aaSamw 		return;
72da6c28aaSamw 
73da6c28aaSamw 	offset = *start;
74da6c28aaSamw 
75da6c28aaSamw 	*ap = '\0';
76da6c28aaSamw 	*hp = '\0';
77da6c28aaSamw 	count = 0;
78da6c28aaSamw 
79da6c28aaSamw 	for (i = 0; i < nbytes; ++i) {
80da6c28aaSamw 		if (i && (i % 16) == 0) {
81*dc20a302Sas 			smb_tracef("%06X %s  %s", offset, hexbuf, ascbuf);
82da6c28aaSamw 			ap = ascbuf;
83da6c28aaSamw 			hp = hexbuf;
84da6c28aaSamw 			count = 0;
85da6c28aaSamw 			offset += 16;
86da6c28aaSamw 		}
87da6c28aaSamw 
88da6c28aaSamw 		ap += sprintf(ap, "%c",
89da6c28aaSamw 		    (*p >= 0x20 && *p < 0x7F) ? *p : '.');
90da6c28aaSamw 		hp += sprintf(hp, " %c%c",
91da6c28aaSamw 		    hex[(*p >> 4) & 0x0F], hex[(*p & 0x0F)]);
92da6c28aaSamw 		++p;
93da6c28aaSamw 		++count;
94da6c28aaSamw 	}
95da6c28aaSamw 
96da6c28aaSamw 	if (count) {
97*dc20a302Sas 		smb_tracef("%06X %-48s  %s", offset, hexbuf, ascbuf);
98da6c28aaSamw 		offset += count;
99da6c28aaSamw 	}
100da6c28aaSamw 
101da6c28aaSamw 	*start = offset;
102da6c28aaSamw }
103da6c28aaSamw 
104da6c28aaSamw void
105da6c28aaSamw hexdump(unsigned char *buffer, int nbytes)
106da6c28aaSamw {
107da6c28aaSamw 	unsigned long start = 0;
108da6c28aaSamw 
109*dc20a302Sas 	hexdump_offset(buffer, nbytes, &start);
110da6c28aaSamw }
111da6c28aaSamw 
112da6c28aaSamw /*
113da6c28aaSamw  * bintohex
114da6c28aaSamw  *
115da6c28aaSamw  * Converts the given binary data (srcbuf) to
116da6c28aaSamw  * its equivalent hex chars (hexbuf).
117da6c28aaSamw  *
118da6c28aaSamw  * hexlen should be at least twice as srclen.
119da6c28aaSamw  * if hexbuf is not big enough returns 0.
120da6c28aaSamw  * otherwise returns number of valid chars in
121da6c28aaSamw  * hexbuf which is srclen * 2.
122da6c28aaSamw  */
123da6c28aaSamw size_t
124da6c28aaSamw bintohex(const char *srcbuf, size_t srclen,
125da6c28aaSamw     char *hexbuf, size_t hexlen)
126da6c28aaSamw {
127da6c28aaSamw 	size_t outlen;
128da6c28aaSamw 	char c;
129da6c28aaSamw 
130da6c28aaSamw 	outlen = srclen << 1;
131da6c28aaSamw 
132da6c28aaSamw 	if (hexlen < outlen)
133da6c28aaSamw 		return (0);
134da6c28aaSamw 
135da6c28aaSamw 	while (srclen-- > 0) {
136da6c28aaSamw 		c = *srcbuf++;
137da6c28aaSamw 		*hexbuf++ = C2H(c & 0xF);
138da6c28aaSamw 		*hexbuf++ = C2H((c >> 4) & 0xF);
139da6c28aaSamw 	}
140da6c28aaSamw 
141da6c28aaSamw 	return (outlen);
142da6c28aaSamw }
143da6c28aaSamw 
144da6c28aaSamw /*
145da6c28aaSamw  * hextobin
146da6c28aaSamw  *
147da6c28aaSamw  * Converts hex to binary.
148da6c28aaSamw  *
149da6c28aaSamw  * Assuming hexbuf only contains hex digits (chars)
150da6c28aaSamw  * this function convert every two bytes of hexbuf
151da6c28aaSamw  * to one byte and put it in dstbuf.
152da6c28aaSamw  *
153da6c28aaSamw  * hexlen should be an even number.
154da6c28aaSamw  * dstlen should be at least half of hexlen.
155da6c28aaSamw  *
156da6c28aaSamw  * Returns 0 if sizes are not correct, otherwise
157da6c28aaSamw  * returns the number of converted bytes in dstbuf
158da6c28aaSamw  * which is half of hexlen.
159da6c28aaSamw  */
160da6c28aaSamw size_t
161da6c28aaSamw hextobin(const char *hexbuf, size_t hexlen,
162da6c28aaSamw     char *dstbuf, size_t dstlen)
163da6c28aaSamw {
164da6c28aaSamw 	size_t outlen;
165da6c28aaSamw 
166da6c28aaSamw 	if ((hexlen % 2) != 0)
167da6c28aaSamw 		return (0);
168da6c28aaSamw 
169da6c28aaSamw 	outlen = hexlen >> 1;
170da6c28aaSamw 	if (dstlen < outlen)
171da6c28aaSamw 		return (0);
172da6c28aaSamw 
173da6c28aaSamw 	while (hexlen > 0) {
174da6c28aaSamw 		*dstbuf = H2C(*hexbuf) & 0x0F;
175da6c28aaSamw 		hexbuf++;
176da6c28aaSamw 		*dstbuf++ |= (H2C(*hexbuf) << 4) & 0xF0;
177da6c28aaSamw 		hexbuf++;
178da6c28aaSamw 
179da6c28aaSamw 		hexlen -= 2;
180da6c28aaSamw 	}
181da6c28aaSamw 
182da6c28aaSamw 	return (outlen);
183da6c28aaSamw }
184da6c28aaSamw 
185da6c28aaSamw /*
186da6c28aaSamw  * trim_whitespace
187da6c28aaSamw  *
188da6c28aaSamw  * Trim leading and trailing whitespace chars (as defined by isspace)
189da6c28aaSamw  * from a buffer. Example; if the input buffer contained "  text  ",
190da6c28aaSamw  * it will contain "text", when we return. We assume that the buffer
191da6c28aaSamw  * contains a null terminated string. A pointer to the buffer is
192da6c28aaSamw  * returned.
193da6c28aaSamw  */
194da6c28aaSamw char *
195da6c28aaSamw trim_whitespace(char *buf)
196da6c28aaSamw {
197da6c28aaSamw 	char *p = buf;
198da6c28aaSamw 	char *q = buf;
199da6c28aaSamw 
200*dc20a302Sas 	if (buf == NULL)
201*dc20a302Sas 		return (NULL);
202da6c28aaSamw 
203da6c28aaSamw 	while (*p && isspace(*p))
204da6c28aaSamw 		++p;
205da6c28aaSamw 
206da6c28aaSamw 	while ((*q = *p++) != 0)
207da6c28aaSamw 		++q;
208da6c28aaSamw 
209da6c28aaSamw 	if (q != buf) {
210da6c28aaSamw 		while ((--q, isspace(*q)) != 0)
211da6c28aaSamw 			*q = '\0';
212da6c28aaSamw 	}
213da6c28aaSamw 
214da6c28aaSamw 	return (buf);
215da6c28aaSamw }
216da6c28aaSamw 
217da6c28aaSamw /*
218da6c28aaSamw  * randomize
219da6c28aaSamw  *
220da6c28aaSamw  * Randomize the contents of the specified buffer.
221da6c28aaSamw  */
222da6c28aaSamw void
223da6c28aaSamw randomize(char *data, unsigned len)
224da6c28aaSamw {
225da6c28aaSamw 	unsigned dwlen = len / 4;
226da6c28aaSamw 	unsigned remlen = len % 4;
227da6c28aaSamw 	unsigned tmp;
228da6c28aaSamw 	unsigned i; /*LINTED E_BAD_PTR_CAST_ALIGN*/
229da6c28aaSamw 	unsigned *p = (unsigned *)data;
230da6c28aaSamw 
231da6c28aaSamw 	for (i = 0; i < dwlen; ++i)
232da6c28aaSamw 		*p++ = random();
233da6c28aaSamw 
234da6c28aaSamw 	if (remlen) {
235da6c28aaSamw 		tmp = random();
236da6c28aaSamw 		(void) memcpy(p, &tmp, remlen);
237da6c28aaSamw 	}
238da6c28aaSamw }
239da6c28aaSamw 
240da6c28aaSamw /*
241da6c28aaSamw  * This is the hash mechanism used to encrypt passwords for commands like
242da6c28aaSamw  * SamrSetUserInformation. It uses a 256 byte s-box.
243da6c28aaSamw  */
244da6c28aaSamw void
245da6c28aaSamw rand_hash(
246da6c28aaSamw     unsigned char *data,
247da6c28aaSamw     size_t datalen,
248da6c28aaSamw     unsigned char *key,
249da6c28aaSamw     size_t keylen)
250da6c28aaSamw {
251da6c28aaSamw 	unsigned char sbox[DEFAULT_SBOX_SIZE];
252da6c28aaSamw 	unsigned char tmp;
253da6c28aaSamw 	unsigned char index_i = 0;
254da6c28aaSamw 	unsigned char index_j = 0;
255da6c28aaSamw 	unsigned char j = 0;
256da6c28aaSamw 	int i;
257da6c28aaSamw 
258da6c28aaSamw 	for (i = 0; i < DEFAULT_SBOX_SIZE; ++i)
259da6c28aaSamw 		sbox[i] = (unsigned char)i;
260da6c28aaSamw 
261da6c28aaSamw 	for (i = 0; i < DEFAULT_SBOX_SIZE; ++i) {
262da6c28aaSamw 		j += (sbox[i] + key[i % keylen]);
263da6c28aaSamw 
264da6c28aaSamw 		tmp = sbox[i];
265da6c28aaSamw 		sbox[i] = sbox[j];
266da6c28aaSamw 		sbox[j] = tmp;
267da6c28aaSamw 	}
268da6c28aaSamw 
269da6c28aaSamw 	for (i = 0; i < datalen; ++i) {
270da6c28aaSamw 		index_i++;
271da6c28aaSamw 		index_j += sbox[index_i];
272da6c28aaSamw 
273da6c28aaSamw 		tmp = sbox[index_i];
274da6c28aaSamw 		sbox[index_i] = sbox[index_j];
275da6c28aaSamw 		sbox[index_j] = tmp;
276da6c28aaSamw 
277da6c28aaSamw 		tmp = sbox[index_i] + sbox[index_j];
278da6c28aaSamw 		data[i] = data[i] ^ sbox[tmp];
279da6c28aaSamw 	}
280da6c28aaSamw }
281da6c28aaSamw 
282da6c28aaSamw /*
283da6c28aaSamw  * strsep
284da6c28aaSamw  *
285da6c28aaSamw  * The strsep() function locates, in the string referenced by *stringp, the
286da6c28aaSamw  * first occurrence of any character in the string delim (or the terminating
287da6c28aaSamw  * `\0' character) and replaces it with a `\0'.  The location of the next
288da6c28aaSamw  * character after the delimiter character (or NULL, if the end of the
289da6c28aaSamw  * string was reached) is stored in *stringp.  The original value of
290da6c28aaSamw  * *stringp is returned.
291da6c28aaSamw  *
292da6c28aaSamw  * If *stringp is initially NULL, strsep() returns NULL.
293da6c28aaSamw  */
294da6c28aaSamw char *
295da6c28aaSamw strsep(char **stringp, const char *delim)
296da6c28aaSamw {
297da6c28aaSamw 	char *s;
298da6c28aaSamw 	const char *spanp;
299da6c28aaSamw 	int c, sc;
300da6c28aaSamw 	char *tok;
301da6c28aaSamw 
302da6c28aaSamw 	if ((s = *stringp) == NULL)
303da6c28aaSamw 		return (NULL);
304da6c28aaSamw 
305da6c28aaSamw 	for (tok = s; ; ) {
306da6c28aaSamw 		c = *s++;
307da6c28aaSamw 		spanp = delim;
308da6c28aaSamw 		do {
309da6c28aaSamw 			if ((sc = *spanp++) == c) {
310da6c28aaSamw 				if (c == 0)
311da6c28aaSamw 					s = NULL;
312da6c28aaSamw 				else
313da6c28aaSamw 					s[-1] = 0;
314da6c28aaSamw 				*stringp = s;
315da6c28aaSamw 				return (tok);
316da6c28aaSamw 			}
317da6c28aaSamw 		} while (sc != 0);
318da6c28aaSamw 	}
319da6c28aaSamw 	/* NOTREACHED */
320da6c28aaSamw }
321