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