11638Srgrimes/*
21638Srgrimes * Copyright (c) 1999, Boris Popov
31638Srgrimes * All rights reserved.
41638Srgrimes *
51638Srgrimes * Redistribution and use in source and binary forms, with or without
61638Srgrimes * modification, are permitted provided that the following conditions
71638Srgrimes * are met:
81638Srgrimes * 1. Redistributions of source code must retain the above copyright
91638Srgrimes *    notice, this list of conditions and the following disclaimer.
101638Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
111638Srgrimes *    notice, this list of conditions and the following disclaimer in the
121638Srgrimes *    documentation and/or other materials provided with the distribution.
131638Srgrimes * 3. Neither the name of the author nor the names of any co-contributors
141638Srgrimes *    may be used to endorse or promote products derived from this software
151638Srgrimes *    without specific prior written permission.
161638Srgrimes *
171638Srgrimes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
181638Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
191638Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
201638Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
211638Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
221638Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
231638Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
241638Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
251638Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
261638Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
271638Srgrimes * SUCH DAMAGE.
281638Srgrimes */
291638Srgrimes
301638Srgrimes#include <sys/cdefs.h>
311638Srgrimes__FBSDID("$FreeBSD$");
321638Srgrimes
331638Srgrimes#include <sys/types.h>
341638Srgrimes#include <arpa/inet.h>
351638Srgrimes#include <errno.h>
361638Srgrimes#include <string.h>
371638Srgrimes#include <netncp/ncp_lib.h>
381638Srgrimes
391638Srgrimesstatic void nw_passencrypt(char *old, char *new, char *out);
401638Srgrimes
411638Srgrimesint
421638Srgrimesncp_get_bindery_object_id(NWCONN_HANDLE connid, u_int16_t object_type,
431638Srgrimes	const char *object_name, struct ncp_bindery_object *target)
441638Srgrimes{
451638Srgrimes	int error;
461638Srgrimes	DECLARE_RQ;
471638Srgrimes
481638Srgrimes	ncp_init_request_s(conn, 53);
491638Srgrimes	ncp_add_word_hl(conn, object_type);
501638Srgrimes	ncp_add_pstring(conn, object_name);
511638Srgrimes
521638Srgrimes	if ((error = ncp_request(connid, 23, conn)) != 0) {
531638Srgrimes		return error;
541638Srgrimes	}
551638Srgrimes	if (conn->rpsize < 54) {
561638Srgrimes		return EACCES;
571638Srgrimes	}
581638Srgrimes	target->object_id = ncp_reply_dword_hl(conn, 0);
591638Srgrimes	target->object_type = ncp_reply_word_hl(conn, 4);
601638Srgrimes	memcpy(target->object_name, ncp_reply_data(conn, 6), 48);
611638Srgrimes	return 0;
621638Srgrimes}
631638Srgrimes
641638Srgrimesint
651638Srgrimesncp_read_property_value(NWCONN_HANDLE connid, int object_type,
661638Srgrimes	const char *object_name, int segment, const char *prop_name,
671638Srgrimes	struct nw_property *target)
681638Srgrimes{
691638Srgrimes	int error;
701638Srgrimes	struct ncp_buf conn;
711638Srgrimes	ncp_init_request_s(&conn, 61);
721638Srgrimes	ncp_add_word_hl(&conn, object_type);
731638Srgrimes	ncp_add_pstring(&conn, object_name);
741638Srgrimes	ncp_add_byte(&conn, segment);
751638Srgrimes	ncp_add_pstring(&conn, prop_name);
761638Srgrimes
771638Srgrimes	if ((error = ncp_request(connid,23,&conn)) != 0) {
781638Srgrimes		return error;
791638Srgrimes	}
801638Srgrimes	memcpy(&(target->value), ncp_reply_data(&conn, 0), 128);
811638Srgrimes	target->more_flag = ncp_reply_byte(&conn, 128);
821638Srgrimes	target->property_flag = ncp_reply_byte(&conn, 129);
831638Srgrimes	return 0;
841638Srgrimes}
851638Srgrimes
861638Srgrimesint
871638Srgrimesncp_scan_bindery_object(NWCONN_HANDLE connid, u_int32_t last_id,
881638Srgrimes	u_int16_t object_type, char *search_string,
891638Srgrimes	struct ncp_bindery_object *target)
9016398Swosch{
9116398Swosch	int error;
9216398Swosch	DECLARE_RQ;
931638Srgrimes
941638Srgrimes	ncp_init_request_s(conn, 55);
951638Srgrimes	ncp_add_dword_hl(conn, last_id);
961638Srgrimes	ncp_add_word_hl(conn, object_type);
971638Srgrimes	ncp_add_pstring(conn, search_string);
981638Srgrimes	error = ncp_request(connid, 23, conn);
991638Srgrimes	if (error) return error;
1001638Srgrimes	target->object_id = ncp_reply_dword_hl(conn, 0);
1011638Srgrimes	target->object_type = ncp_reply_word_hl(conn, 4);
1021638Srgrimes	memcpy(target->object_name, ncp_reply_data(conn, 6),NCP_BINDERY_NAME_LEN);
1031638Srgrimes	target->object_flags = ncp_reply_byte(conn, 54);
1041638Srgrimes	target->object_security = ncp_reply_byte(conn, 55);
1051638Srgrimes	target->object_has_prop = ncp_reply_byte(conn, 56);
1061638Srgrimes	return 0;
1071638Srgrimes}
1081638Srgrimes
1091638Srgrimesint
1101638Srgrimesncp_get_bindery_object_name(NWCONN_HANDLE connid, u_int32_t object_id,
1111638Srgrimes	struct ncp_bindery_object *target)
1121638Srgrimes{
1131638Srgrimes	int error;
1141638Srgrimes	DECLARE_RQ;
1151638Srgrimes
1161638Srgrimes	ncp_init_request_s(conn, 54);
1171638Srgrimes	ncp_add_dword_hl(conn, object_id);
1181638Srgrimes	if ((error = ncp_request(connid, 23, conn)) != 0)
1191638Srgrimes		return error;
1201638Srgrimes	target->object_id = ncp_reply_dword_hl(conn, 0);
1211638Srgrimes	target->object_type = ncp_reply_word_hl(conn, 4);
1221638Srgrimes	memcpy(target->object_name, ncp_reply_data(conn, 6), 48);
1231638Srgrimes	return 0;
1241638Srgrimes}
1251638Srgrimes
1261638Srgrimesint
1271638Srgrimesncp_change_obj_passwd(NWCONN_HANDLE connid,
1281638Srgrimes	const struct ncp_bindery_object *object,
1291638Srgrimes	const u_char *key,
1301638Srgrimes	const u_char *oldpasswd,
13116398Swosch	const u_char *newpasswd)
1321638Srgrimes{
1331638Srgrimes	long id = htonl(object->object_id);
1341638Srgrimes	u_char cryptkey[8];
1351638Srgrimes	u_char newpwd[16];	/* new passwd as stored by server */
1361638Srgrimes	u_char oldpwd[16];	/* old passwd as stored by server */
1371638Srgrimes	u_char len;
1381638Srgrimes	DECLARE_RQ;
1391638Srgrimes
1401638Srgrimes	memcpy(cryptkey, key, 8);
1411638Srgrimes	nw_keyhash((u_char *)&id, oldpasswd, strlen(oldpasswd), oldpwd);
1421638Srgrimes	nw_keyhash((u_char *)&id, newpasswd, strlen(newpasswd), newpwd);
1431638Srgrimes	nw_encrypt(cryptkey, oldpwd, cryptkey);
1441638Srgrimes	nw_passencrypt(oldpwd, newpwd, newpwd);
1451638Srgrimes	nw_passencrypt(oldpwd + 8, newpwd + 8, newpwd + 8);
1461638Srgrimes	if ((len = strlen(newpasswd)) > 63) {
1471638Srgrimes		len = 63;
1481638Srgrimes	}
1491638Srgrimes	len = ((len ^ oldpwd[0] ^ oldpwd[1]) & 0x7f) | 0x40;
1501638Srgrimes
1511638Srgrimes	ncp_init_request_s(conn, 75);
1521638Srgrimes	ncp_add_mem(conn, cryptkey, 8);
1531638Srgrimes	ncp_add_word_hl(conn, object->object_type);
1541638Srgrimes	ncp_add_pstring(conn, object->object_name);
1551638Srgrimes	ncp_add_byte(conn, len);
1561638Srgrimes	ncp_add_mem(conn, newpwd, 16);
1571638Srgrimes	return ncp_request(connid, 23, conn);
1581638Srgrimes}
1591638Srgrimes
1601638Srgrimes/*
1611638Srgrimes * target is a 8-byte buffer
1621638Srgrimes */
1631638Srgrimesint
1641638Srgrimesncp_get_encryption_key(NWCONN_HANDLE cH, char *target) {
1651638Srgrimes	int error;
1661638Srgrimes	DECLARE_RQ;
1671638Srgrimes
1681638Srgrimes	ncp_init_request_s(conn, 23);
1691638Srgrimes
1701638Srgrimes	error = ncp_request(cH, 23, conn);
1711638Srgrimes	if (error)
1721638Srgrimes		return error;
1731638Srgrimes	if (conn->rpsize < 8)
1741638Srgrimes		return EACCES;
1751638Srgrimes	memcpy(target, ncp_reply_data(conn, 0), 8);
1761638Srgrimes	return 0;
1771638Srgrimes}
1781638Srgrimes
1791638Srgrimesint
1801638Srgrimesncp_keyed_verify_password(NWCONN_HANDLE cH, char *key, char *passwd,
1811638Srgrimes	struct ncp_bindery_object *objinfo)
1821638Srgrimes{
1831638Srgrimes	u_long id = htonl(objinfo->object_id);
1841638Srgrimes	u_char cryptkey[8];
1851638Srgrimes	u_char buf[128];
1861638Srgrimes	DECLARE_RQ;
1871638Srgrimes
1881638Srgrimes	nw_keyhash((u_char *)&id, passwd, strlen(passwd), buf);
1891638Srgrimes	nw_encrypt(key, buf, cryptkey);
1901638Srgrimes
1911638Srgrimes	ncp_init_request_s(conn, 74);
1921638Srgrimes	ncp_add_mem(conn, cryptkey, sizeof(cryptkey));
1931638Srgrimes	ncp_add_word_hl(conn, objinfo->object_type);
1941638Srgrimes	ncp_add_pstring(conn, objinfo->object_name);
1951638Srgrimes
1961638Srgrimes	return ncp_request(cH, 23, conn);
1971638Srgrimes}
1981638Srgrimes
1991638Srgrimesstatic char passkeys[256 + 16] = {
2001638Srgrimes	0x0f, 0x08, 0x05, 0x07, 0x0c, 0x02, 0x0e, 0x09,
2011638Srgrimes	0x00, 0x01, 0x06, 0x0d, 0x03, 0x04, 0x0b, 0x0a,
2021638Srgrimes	0x02, 0x0c, 0x0e, 0x06, 0x0f, 0x00, 0x01, 0x08,
2031638Srgrimes	0x0d, 0x03, 0x0a, 0x04, 0x09, 0x0b, 0x05, 0x07,
2041638Srgrimes	0x05, 0x02, 0x09, 0x0f, 0x0c, 0x04, 0x0d, 0x00,
2051638Srgrimes	0x0e, 0x0a, 0x06, 0x08, 0x0b, 0x01, 0x03, 0x07,
2061638Srgrimes	0x0f, 0x0d, 0x02, 0x06, 0x07, 0x08, 0x05, 0x09,
2071638Srgrimes	0x00, 0x04, 0x0c, 0x03, 0x01, 0x0a, 0x0b, 0x0e,
2081638Srgrimes	0x05, 0x0e, 0x02, 0x0b, 0x0d, 0x0a, 0x07, 0x00,
2091638Srgrimes	0x08, 0x06, 0x04, 0x01, 0x0f, 0x0c, 0x03, 0x09,
2101638Srgrimes	0x08, 0x02, 0x0f, 0x0a, 0x05, 0x09, 0x06, 0x0c,
2111638Srgrimes	0x00, 0x0b, 0x01, 0x0d, 0x07, 0x03, 0x04, 0x0e,
2121638Srgrimes	0x0e, 0x08, 0x00, 0x09, 0x04, 0x0b, 0x02, 0x07,
2131638Srgrimes	0x0c, 0x03, 0x0a, 0x05, 0x0d, 0x01, 0x06, 0x0f,
2141638Srgrimes	0x01, 0x04, 0x08, 0x0a, 0x0d, 0x0b, 0x07, 0x0e,
2151638Srgrimes	0x05, 0x0f, 0x03, 0x09, 0x00, 0x02, 0x06, 0x0c,
2161638Srgrimes	0x05, 0x03, 0x0c, 0x08, 0x0b, 0x02, 0x0e, 0x0a,
2171638Srgrimes	0x04, 0x01, 0x0d, 0x00, 0x06, 0x07, 0x0f, 0x09,
2181638Srgrimes	0x06, 0x00, 0x0b, 0x0e, 0x0d, 0x04, 0x0c, 0x0f,
2191638Srgrimes	0x07, 0x02, 0x08, 0x0a, 0x01, 0x05, 0x03, 0x09,
2201638Srgrimes	0x0b, 0x05, 0x0a, 0x0e, 0x0f, 0x01, 0x0c, 0x00,
2211638Srgrimes	0x06, 0x04, 0x02, 0x09, 0x03, 0x0d, 0x07, 0x08,
2221638Srgrimes	0x07, 0x02, 0x0a, 0x00, 0x0e, 0x08, 0x0f, 0x04,
2231638Srgrimes	0x0c, 0x0b, 0x09, 0x01, 0x05, 0x0d, 0x03, 0x06,
2241638Srgrimes	0x07, 0x04, 0x0f, 0x09, 0x05, 0x01, 0x0c, 0x0b,
2251638Srgrimes	0x00, 0x03, 0x08, 0x0e, 0x02, 0x0a, 0x06, 0x0d,
2261638Srgrimes	0x09, 0x04, 0x08, 0x00, 0x0a, 0x03, 0x01, 0x0c,
2271638Srgrimes	0x05, 0x0f, 0x07, 0x02, 0x0b, 0x0e, 0x06, 0x0d,
2281638Srgrimes	0x09, 0x05, 0x04, 0x07, 0x0e, 0x08, 0x03, 0x01,
2291638Srgrimes	0x0d, 0x0b, 0x0c, 0x02, 0x00, 0x0f, 0x06, 0x0a,
2301638Srgrimes	0x09, 0x0a, 0x0b, 0x0d, 0x05, 0x03, 0x0f, 0x00,
2311638Srgrimes	0x01, 0x0c, 0x08, 0x07, 0x06, 0x04, 0x0e, 0x02,
2321638Srgrimes	0x03, 0x0e, 0x0f, 0x02, 0x0d, 0x0c, 0x04, 0x05,
2331638Srgrimes	0x09, 0x06, 0x00, 0x01, 0x0b, 0x07, 0x0a, 0x08
2341638Srgrimes};
23516398Swosch
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