xref: /illumos-gate/usr/src/lib/smbsrv/libsmb/common/smb_util.c (revision 89a7715a55deca73d03076f5c24463717f0aaa91)
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 2007 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 <syslog.h>
34 #include <sys/varargs.h>
35 #include <sys/types.h>
36 #include <smbsrv/string.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, int log)
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) == 0) {
71 		if (log)
72 			syslog(LOG_DEBUG, "hexdump: (null)");
73 		else
74 			(void) printf("hexdump: (null)\n");
75 		return;
76 	}
77 
78 	offset = *start;
79 
80 	*ap = '\0';
81 	*hp = '\0';
82 	count = 0;
83 
84 	for (i = 0; i < nbytes; ++i) {
85 		if (i && (i % 16) == 0) {
86 			if (log)
87 				syslog(LOG_DEBUG,
88 				    "%06X %s  %s", offset, hexbuf, ascbuf);
89 			else
90 				(void) printf("%06X %s  %s\n",
91 				    offset, hexbuf, ascbuf);
92 			ap = ascbuf;
93 			hp = hexbuf;
94 			count = 0;
95 			offset += 16;
96 		}
97 
98 		ap += sprintf(ap, "%c",
99 		    (*p >= 0x20 && *p < 0x7F) ? *p : '.');
100 		hp += sprintf(hp, " %c%c",
101 		    hex[(*p >> 4) & 0x0F], hex[(*p & 0x0F)]);
102 		++p;
103 		++count;
104 	}
105 
106 	if (count) {
107 		if (log)
108 			syslog(LOG_DEBUG,
109 			    "%06X %-48s  %s", offset, hexbuf, ascbuf);
110 		else
111 			(void) printf("%06X %-48s  %s\n",
112 			    offset, hexbuf, ascbuf);
113 
114 		offset += count;
115 	}
116 
117 	*start = offset;
118 }
119 
120 void
121 hexdump(unsigned char *buffer, int nbytes)
122 {
123 	unsigned long start = 0;
124 
125 	hexdump_offset(buffer, nbytes, &start, 1);
126 }
127 
128 /*
129  * bintohex
130  *
131  * Converts the given binary data (srcbuf) to
132  * its equivalent hex chars (hexbuf).
133  *
134  * hexlen should be at least twice as srclen.
135  * if hexbuf is not big enough returns 0.
136  * otherwise returns number of valid chars in
137  * hexbuf which is srclen * 2.
138  */
139 size_t
140 bintohex(const char *srcbuf, size_t srclen,
141     char *hexbuf, size_t hexlen)
142 {
143 	size_t outlen;
144 	char c;
145 
146 	outlen = srclen << 1;
147 
148 	if (hexlen < outlen)
149 		return (0);
150 
151 	while (srclen-- > 0) {
152 		c = *srcbuf++;
153 		*hexbuf++ = C2H(c & 0xF);
154 		*hexbuf++ = C2H((c >> 4) & 0xF);
155 	}
156 
157 	return (outlen);
158 }
159 
160 /*
161  * hextobin
162  *
163  * Converts hex to binary.
164  *
165  * Assuming hexbuf only contains hex digits (chars)
166  * this function convert every two bytes of hexbuf
167  * to one byte and put it in dstbuf.
168  *
169  * hexlen should be an even number.
170  * dstlen should be at least half of hexlen.
171  *
172  * Returns 0 if sizes are not correct, otherwise
173  * returns the number of converted bytes in dstbuf
174  * which is half of hexlen.
175  */
176 size_t
177 hextobin(const char *hexbuf, size_t hexlen,
178     char *dstbuf, size_t dstlen)
179 {
180 	size_t outlen;
181 
182 	if ((hexlen % 2) != 0)
183 		return (0);
184 
185 	outlen = hexlen >> 1;
186 	if (dstlen < outlen)
187 		return (0);
188 
189 	while (hexlen > 0) {
190 		*dstbuf = H2C(*hexbuf) & 0x0F;
191 		hexbuf++;
192 		*dstbuf++ |= (H2C(*hexbuf) << 4) & 0xF0;
193 		hexbuf++;
194 
195 		hexlen -= 2;
196 	}
197 
198 	return (outlen);
199 }
200 
201 /*
202  * trim_whitespace
203  *
204  * Trim leading and trailing whitespace chars (as defined by isspace)
205  * from a buffer. Example; if the input buffer contained "  text  ",
206  * it will contain "text", when we return. We assume that the buffer
207  * contains a null terminated string. A pointer to the buffer is
208  * returned.
209  */
210 char *
211 trim_whitespace(char *buf)
212 {
213 	char *p = buf;
214 	char *q = buf;
215 
216 	if (buf == 0)
217 		return (0);
218 
219 	while (*p && isspace(*p))
220 		++p;
221 
222 	while ((*q = *p++) != 0)
223 		++q;
224 
225 	if (q != buf) {
226 		while ((--q, isspace(*q)) != 0)
227 			*q = '\0';
228 	}
229 
230 	return (buf);
231 }
232 
233 /*
234  * randomize
235  *
236  * Randomize the contents of the specified buffer.
237  */
238 void
239 randomize(char *data, unsigned len)
240 {
241 	unsigned dwlen = len / 4;
242 	unsigned remlen = len % 4;
243 	unsigned tmp;
244 	unsigned i; /*LINTED E_BAD_PTR_CAST_ALIGN*/
245 	unsigned *p = (unsigned *)data;
246 
247 	for (i = 0; i < dwlen; ++i)
248 		*p++ = random();
249 
250 	if (remlen) {
251 		tmp = random();
252 		(void) memcpy(p, &tmp, remlen);
253 	}
254 }
255 
256 /*
257  * This is the hash mechanism used to encrypt passwords for commands like
258  * SamrSetUserInformation. It uses a 256 byte s-box.
259  */
260 void
261 rand_hash(
262     unsigned char *data,
263     size_t datalen,
264     unsigned char *key,
265     size_t keylen)
266 {
267 	unsigned char sbox[DEFAULT_SBOX_SIZE];
268 	unsigned char tmp;
269 	unsigned char index_i = 0;
270 	unsigned char index_j = 0;
271 	unsigned char j = 0;
272 	int i;
273 
274 	for (i = 0; i < DEFAULT_SBOX_SIZE; ++i)
275 		sbox[i] = (unsigned char)i;
276 
277 	for (i = 0; i < DEFAULT_SBOX_SIZE; ++i) {
278 		j += (sbox[i] + key[i % keylen]);
279 
280 		tmp = sbox[i];
281 		sbox[i] = sbox[j];
282 		sbox[j] = tmp;
283 	}
284 
285 	for (i = 0; i < datalen; ++i) {
286 		index_i++;
287 		index_j += sbox[index_i];
288 
289 		tmp = sbox[index_i];
290 		sbox[index_i] = sbox[index_j];
291 		sbox[index_j] = tmp;
292 
293 		tmp = sbox[index_i] + sbox[index_j];
294 		data[i] = data[i] ^ sbox[tmp];
295 	}
296 }
297 
298 /*
299  * strsep
300  *
301  * The strsep() function locates, in the string referenced by *stringp, the
302  * first occurrence of any character in the string delim (or the terminating
303  * `\0' character) and replaces it with a `\0'.  The location of the next
304  * character after the delimiter character (or NULL, if the end of the
305  * string was reached) is stored in *stringp.  The original value of
306  * *stringp is returned.
307  *
308  * If *stringp is initially NULL, strsep() returns NULL.
309  */
310 char *
311 strsep(char **stringp, const char *delim)
312 {
313 	char *s;
314 	const char *spanp;
315 	int c, sc;
316 	char *tok;
317 
318 	if ((s = *stringp) == NULL)
319 		return (NULL);
320 
321 	for (tok = s; ; ) {
322 		c = *s++;
323 		spanp = delim;
324 		do {
325 			if ((sc = *spanp++) == c) {
326 				if (c == 0)
327 					s = NULL;
328 				else
329 					s[-1] = 0;
330 				*stringp = s;
331 				return (tok);
332 			}
333 		} while (sc != 0);
334 	}
335 	/* NOTREACHED */
336 }
337