1/*
2 * Copyright (c) 1999, Boris Popov
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 * 3. Neither the name of the author nor the names of any co-contributors
14 *    may be used to endorse or promote products derived from this software
15 *    without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
29
30#include <sys/cdefs.h>
31__FBSDID("$FreeBSD$");
32
33#include <sys/types.h>
34#include <arpa/inet.h>
35#include <errno.h>
36#include <string.h>
37#include <netncp/ncp_lib.h>
38
39static void nw_passencrypt(char *old, char *new, char *out);
40
41int
42ncp_get_bindery_object_id(NWCONN_HANDLE connid, u_int16_t object_type,
43	const char *object_name, struct ncp_bindery_object *target)
44{
45	int error;
46	DECLARE_RQ;
47
48	ncp_init_request_s(conn, 53);
49	ncp_add_word_hl(conn, object_type);
50	ncp_add_pstring(conn, object_name);
51
52	if ((error = ncp_request(connid, 23, conn)) != 0) {
53		return error;
54	}
55	if (conn->rpsize < 54) {
56		return EACCES;
57	}
58	target->object_id = ncp_reply_dword_hl(conn, 0);
59	target->object_type = ncp_reply_word_hl(conn, 4);
60	memcpy(target->object_name, ncp_reply_data(conn, 6), 48);
61	return 0;
62}
63
64int
65ncp_read_property_value(NWCONN_HANDLE connid, int object_type,
66	const char *object_name, int segment, const char *prop_name,
67	struct nw_property *target)
68{
69	int error;
70	struct ncp_buf conn;
71	ncp_init_request_s(&conn, 61);
72	ncp_add_word_hl(&conn, object_type);
73	ncp_add_pstring(&conn, object_name);
74	ncp_add_byte(&conn, segment);
75	ncp_add_pstring(&conn, prop_name);
76
77	if ((error = ncp_request(connid,23,&conn)) != 0) {
78		return error;
79	}
80	memcpy(&(target->value), ncp_reply_data(&conn, 0), 128);
81	target->more_flag = ncp_reply_byte(&conn, 128);
82	target->property_flag = ncp_reply_byte(&conn, 129);
83	return 0;
84}
85
86int
87ncp_scan_bindery_object(NWCONN_HANDLE connid, u_int32_t last_id,
88	u_int16_t object_type, char *search_string,
89	struct ncp_bindery_object *target)
90{
91	int error;
92	DECLARE_RQ;
93
94	ncp_init_request_s(conn, 55);
95	ncp_add_dword_hl(conn, last_id);
96	ncp_add_word_hl(conn, object_type);
97	ncp_add_pstring(conn, search_string);
98	error = ncp_request(connid, 23, conn);
99	if (error) return error;
100	target->object_id = ncp_reply_dword_hl(conn, 0);
101	target->object_type = ncp_reply_word_hl(conn, 4);
102	memcpy(target->object_name, ncp_reply_data(conn, 6),NCP_BINDERY_NAME_LEN);
103	target->object_flags = ncp_reply_byte(conn, 54);
104	target->object_security = ncp_reply_byte(conn, 55);
105	target->object_has_prop = ncp_reply_byte(conn, 56);
106	return 0;
107}
108
109int
110ncp_get_bindery_object_name(NWCONN_HANDLE connid, u_int32_t object_id,
111	struct ncp_bindery_object *target)
112{
113	int error;
114	DECLARE_RQ;
115
116	ncp_init_request_s(conn, 54);
117	ncp_add_dword_hl(conn, object_id);
118	if ((error = ncp_request(connid, 23, conn)) != 0)
119		return error;
120	target->object_id = ncp_reply_dword_hl(conn, 0);
121	target->object_type = ncp_reply_word_hl(conn, 4);
122	memcpy(target->object_name, ncp_reply_data(conn, 6), 48);
123	return 0;
124}
125
126int
127ncp_change_obj_passwd(NWCONN_HANDLE connid,
128	const struct ncp_bindery_object *object,
129	const u_char *key,
130	const u_char *oldpasswd,
131	const u_char *newpasswd)
132{
133	long id = htonl(object->object_id);
134	u_char cryptkey[8];
135	u_char newpwd[16];	/* new passwd as stored by server */
136	u_char oldpwd[16];	/* old passwd as stored by server */
137	u_char len;
138	DECLARE_RQ;
139
140	memcpy(cryptkey, key, 8);
141	nw_keyhash((u_char *)&id, oldpasswd, strlen(oldpasswd), oldpwd);
142	nw_keyhash((u_char *)&id, newpasswd, strlen(newpasswd), newpwd);
143	nw_encrypt(cryptkey, oldpwd, cryptkey);
144	nw_passencrypt(oldpwd, newpwd, newpwd);
145	nw_passencrypt(oldpwd + 8, newpwd + 8, newpwd + 8);
146	if ((len = strlen(newpasswd)) > 63) {
147		len = 63;
148	}
149	len = ((len ^ oldpwd[0] ^ oldpwd[1]) & 0x7f) | 0x40;
150
151	ncp_init_request_s(conn, 75);
152	ncp_add_mem(conn, cryptkey, 8);
153	ncp_add_word_hl(conn, object->object_type);
154	ncp_add_pstring(conn, object->object_name);
155	ncp_add_byte(conn, len);
156	ncp_add_mem(conn, newpwd, 16);
157	return ncp_request(connid, 23, conn);
158}
159
160/*
161 * target is a 8-byte buffer
162 */
163int
164ncp_get_encryption_key(NWCONN_HANDLE cH, char *target) {
165	int error;
166	DECLARE_RQ;
167
168	ncp_init_request_s(conn, 23);
169
170	error = ncp_request(cH, 23, conn);
171	if (error)
172		return error;
173	if (conn->rpsize < 8)
174		return EACCES;
175	memcpy(target, ncp_reply_data(conn, 0), 8);
176	return 0;
177}
178
179int
180ncp_keyed_verify_password(NWCONN_HANDLE cH, char *key, char *passwd,
181	struct ncp_bindery_object *objinfo)
182{
183	u_long id = htonl(objinfo->object_id);
184	u_char cryptkey[8];
185	u_char buf[128];
186	DECLARE_RQ;
187
188	nw_keyhash((u_char *)&id, passwd, strlen(passwd), buf);
189	nw_encrypt(key, buf, cryptkey);
190
191	ncp_init_request_s(conn, 74);
192	ncp_add_mem(conn, cryptkey, sizeof(cryptkey));
193	ncp_add_word_hl(conn, objinfo->object_type);
194	ncp_add_pstring(conn, objinfo->object_name);
195
196	return ncp_request(cH, 23, conn);
197}
198
199static char passkeys[256 + 16] = {
200	0x0f, 0x08, 0x05, 0x07, 0x0c, 0x02, 0x0e, 0x09,
201	0x00, 0x01, 0x06, 0x0d, 0x03, 0x04, 0x0b, 0x0a,
202	0x02, 0x0c, 0x0e, 0x06, 0x0f, 0x00, 0x01, 0x08,
203	0x0d, 0x03, 0x0a, 0x04, 0x09, 0x0b, 0x05, 0x07,
204	0x05, 0x02, 0x09, 0x0f, 0x0c, 0x04, 0x0d, 0x00,
205	0x0e, 0x0a, 0x06, 0x08, 0x0b, 0x01, 0x03, 0x07,
206	0x0f, 0x0d, 0x02, 0x06, 0x07, 0x08, 0x05, 0x09,
207	0x00, 0x04, 0x0c, 0x03, 0x01, 0x0a, 0x0b, 0x0e,
208	0x05, 0x0e, 0x02, 0x0b, 0x0d, 0x0a, 0x07, 0x00,
209	0x08, 0x06, 0x04, 0x01, 0x0f, 0x0c, 0x03, 0x09,
210	0x08, 0x02, 0x0f, 0x0a, 0x05, 0x09, 0x06, 0x0c,
211	0x00, 0x0b, 0x01, 0x0d, 0x07, 0x03, 0x04, 0x0e,
212	0x0e, 0x08, 0x00, 0x09, 0x04, 0x0b, 0x02, 0x07,
213	0x0c, 0x03, 0x0a, 0x05, 0x0d, 0x01, 0x06, 0x0f,
214	0x01, 0x04, 0x08, 0x0a, 0x0d, 0x0b, 0x07, 0x0e,
215	0x05, 0x0f, 0x03, 0x09, 0x00, 0x02, 0x06, 0x0c,
216	0x05, 0x03, 0x0c, 0x08, 0x0b, 0x02, 0x0e, 0x0a,
217	0x04, 0x01, 0x0d, 0x00, 0x06, 0x07, 0x0f, 0x09,
218	0x06, 0x00, 0x0b, 0x0e, 0x0d, 0x04, 0x0c, 0x0f,
219	0x07, 0x02, 0x08, 0x0a, 0x01, 0x05, 0x03, 0x09,
220	0x0b, 0x05, 0x0a, 0x0e, 0x0f, 0x01, 0x0c, 0x00,
221	0x06, 0x04, 0x02, 0x09, 0x03, 0x0d, 0x07, 0x08,
222	0x07, 0x02, 0x0a, 0x00, 0x0e, 0x08, 0x0f, 0x04,
223	0x0c, 0x0b, 0x09, 0x01, 0x05, 0x0d, 0x03, 0x06,
224	0x07, 0x04, 0x0f, 0x09, 0x05, 0x01, 0x0c, 0x0b,
225	0x00, 0x03, 0x08, 0x0e, 0x02, 0x0a, 0x06, 0x0d,
226	0x09, 0x04, 0x08, 0x00, 0x0a, 0x03, 0x01, 0x0c,
227	0x05, 0x0f, 0x07, 0x02, 0x0b, 0x0e, 0x06, 0x0d,
228	0x09, 0x05, 0x04, 0x07, 0x0e, 0x08, 0x03, 0x01,
229	0x0d, 0x0b, 0x0c, 0x02, 0x00, 0x0f, 0x06, 0x0a,
230	0x09, 0x0a, 0x0b, 0x0d, 0x05, 0x03, 0x0f, 0x00,
231	0x01, 0x0c, 0x08, 0x07, 0x06, 0x04, 0x0e, 0x02,
232	0x03, 0x0e, 0x0f, 0x02, 0x0d, 0x0c, 0x04, 0x05,
233	0x09, 0x06, 0x00, 0x01, 0x0b, 0x07, 0x0a, 0x08
234};
235
236static void
237nw_passencrypt(char *old, char *new, char *out)
238{
239	char *p, v;
240	char copy[8];
241	int i, di, ax;
242
243#define HIGH(x)	(((x) >> 4) & 0xf)
244#define LOW(x)	((x) & 0xf)
245	memcpy(copy, new, 8);
246
247	for (i = 0; i < 16; i++) {
248		for (di = 0, ax = 0, p = old; di < 8; di++, ax += 0x20, p++) {
249			v = copy[di] ^ *p;
250			copy[di] = (passkeys[HIGH(v) + ax + 0x10] << 4) |
251				   passkeys[LOW(v) + ax];
252		}
253		v = old[7];
254		for (p = old + 7; p > old; p--) {
255			*p = HIGH(p[-1]) | ((*p) << 4);
256		}
257		*old = HIGH(v) | (*old) << 4;
258		bzero(out, 8);
259
260		for (di = 0; di < 16; di++) {
261			v = passkeys[di + 0x100];
262			v = (v & 1) ? HIGH(copy[v / 2]) : LOW(copy[v / 2]);
263			out[di / 2] |= ((di & 1) ? v << 4 : v);
264		}
265		memcpy(copy, out, 8);
266	}
267}
268