1/*-
2 * Copyright (c) 2005-2010 Daniel Braniss <danny@cs.huji.ac.il>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 *
26 */
27
28/*
29 | $Id: misc.c,v 2.1 2006/11/12 08:06:51 danny Exp $
30 */
31
32#include <sys/cdefs.h>
33__FBSDID("$FreeBSD$");
34
35#include <sys/param.h>
36#include <sys/types.h>
37#include <sys/socket.h>
38#include <sys/sysctl.h>
39
40#include <netinet/in.h>
41#include <netinet/tcp.h>
42#include <arpa/inet.h>
43#include <stdlib.h>
44#include <stdio.h>
45#include <string.h>
46
47#include <dev/iscsi_initiator/iscsi.h>
48#include "iscontrol.h"
49
50static inline char
51c2b(unsigned char c)
52{
53     switch(c) {
54     case '0' ... '9':
55	  return c - '0';
56     case 'a' ... 'f':
57	  return c - 'a' + 10;
58     case 'A' ... 'F':
59	  return c - 'A' + 10;
60     }
61     return 0;
62}
63
64static char 	base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
65	                   "abcdefghijklmnopqrstuvwxyz"
66	                   "0123456789+/";
67
68static __inline unsigned char
69c64tobin(unsigned char c64)
70{
71     int	i;
72     for(i = 0; i < 64; i++)
73	  if(base64[i] == c64)
74	       break;
75     return i;
76}
77/*
78 | according to rfc3720, the binary string
79 | cannot be larger than 1024 - but i can't find it :-) XXX
80 | not enforced yet.
81 */
82int
83str2bin(char *str, char **rsp)
84{
85     char	*src, *dst, *tmp;
86     int	i, len = 0;
87
88     src = str;
89     tmp = NULL;
90     if(strncasecmp("0x", src, 2) == 0) {
91	  src += 2;
92	  len = strlen(src);
93
94	  if((tmp = malloc((len+1)/2)) == NULL) {
95	       // XXX: print some error?
96	       return 0;
97	  }
98	  dst = tmp;
99	  if(len & 1)
100	       *dst++ = c2b(*src++);
101	  while(*src) {
102	       *dst = c2b(*src++) << 4;
103	       *dst++ |= c2b(*src++);
104	  }
105	  len = dst - tmp;
106     } else
107     if(strncasecmp("0b", src , 2) == 0) {
108	  // base64
109	  unsigned char b6;
110
111	  src += 2;
112	  len = strlen(src) / 4 * 3;
113	  if((tmp = malloc(len)) == NULL) {
114	       // XXX: print some error?
115	       return 0;
116	  }
117	  dst = tmp;
118	  i = 0;
119	  while(*src && ((b6 = c64tobin(*src++)) != 64)) {
120	       switch(i % 4) {
121	       case 0:
122		    *dst = b6 << 2;
123		    break;
124	       case 1:
125		    *dst++ |= b6 >> 4;
126		    *dst = b6 << 4;
127		    break;
128	       case 2:
129		    *dst++ |= b6 >> 2;
130		    *dst = b6 << 6;
131		    break;
132	       case 3:
133		    *dst++ |= b6;
134		    break;
135	       }
136	       i++;
137	  }
138	  len = dst - tmp;
139     }
140     else {
141	  /*
142	   | assume it to be an ascii string, so just copy it
143	   */
144	  len = strlen(str);
145	  if((tmp = malloc(len)) == NULL)
146	       return 0;
147	  dst = tmp;
148	  src = str;
149	  while(*src)
150	       *dst++ = *src++;
151     }
152
153     *rsp = tmp;
154     return len;
155}
156
157char *
158bin2str(char *encoding, unsigned char *md, int blen)
159{
160     int	len;
161     char	*dst, *ds;
162     unsigned char *cp;
163
164     if(strncasecmp(encoding, "0x", 2) == 0) {
165	  char	ofmt[5];
166
167	  len = blen * 2;
168	  dst = malloc(len + 3);
169	  strcpy(dst, encoding);
170	  ds = dst + 2;
171	  cp = md;
172	  sprintf(ofmt, "%%02%c", encoding[1]);
173	  while(blen-- > 0) {
174	       sprintf(ds, ofmt, *cp++);
175	       ds += 2;
176	  }
177	  *ds = 0;
178	  return dst;
179     }
180     if(strncasecmp(encoding, "0b", 2) == 0) {
181	  int i, b6;
182
183	  len = (blen + 2) * 4 / 3;
184	  dst = malloc(len + 3);
185	  strcpy(dst, encoding);
186	  ds = dst + 2;
187	  cp = md;
188	  b6 = 0; // to keep compiler happy.
189	  for(i = 0; i < blen; i++) {
190	       switch(i % 3) {
191	       case 0:
192		    *ds++ = base64[*cp >> 2];
193		    b6 = (*cp & 0x3) << 4;
194		    break;
195	       case 1:
196		    b6 += (*cp >> 4);
197		    *ds++ = base64[b6];
198		    b6 = (*cp & 0xf) << 2;
199		    break;
200	       case 2:
201		    b6 += (*cp >> 6);
202		    *ds++ = base64[b6];
203		    *ds++ = base64[*cp & 0x3f];
204	       }
205	       cp++;
206	  }
207	  switch(blen % 3) {
208	  case 0:
209	       break;
210	  case 1:
211	       *ds++ = base64[b6];
212	       *ds++ = '=';
213	       *ds++ = '=';
214	       break;
215	  case 2:
216	       *ds++ = base64[b6];
217	       *ds++ = '=';
218	       break;
219	  }
220
221	  *ds = 0;
222	  return dst;
223     }
224
225     return NULL;
226}
227