2 * Copyright (c) 1999, 2000, 2001 Boris Popov
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by Boris Popov.
16 * 4. Neither the name of the author nor the names of any co-contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * Core of NCP protocol
35 #include <sys/cdefs.h>
36 __FBSDID("$FreeBSD$");
38 #include <sys/param.h>
39 #include <sys/errno.h>
40 #include <sys/systm.h>
42 #include <sys/signalvar.h>
43 #include <sys/sysctl.h>
46 #include <sys/mutex.h>
49 #include <netipx/ipx.h>
50 #include <netipx/ipx_var.h>
52 #include <netncp/ncp.h>
53 #include <netncp/ncp_conn.h>
54 #include <netncp/ncp_sock.h>
55 #include <netncp/ncp_subr.h>
56 #include <netncp/ncp_ncp.h>
57 #include <netncp/ncp_rq.h>
58 #include <netncp/nwerror.h>
62 void m_dumpm(struct mbuf *m) {
71 printf("%02x ",((int)*(p++)) & 0xff);
77 #endif /* NCP_DATA_DEBUG */
80 ncp_chkintr(struct ncp_conn *conn, struct thread *td)
89 tmpset = p->p_siglist;
90 SIGSETOR(tmpset, td->td_siglist);
91 SIGSETNAND(tmpset, td->td_sigmask);
92 mtx_lock(&p->p_sigacts->ps_mtx);
93 SIGSETNAND(tmpset, p->p_sigacts->ps_sigignore);
94 mtx_unlock(&p->p_sigacts->ps_mtx);
95 if (SIGNOTEMPTY(td->td_siglist) && NCP_SIGMASK(tmpset)) {
104 * Process initial NCP handshake (attach)
105 * NOTE: Since all functions below may change conn attributes, they
106 * should be called with LOCKED connection, also they use procp & ucred
109 ncp_ncp_connect(struct ncp_conn *conn)
112 struct ncp_rphdr *rp;
115 error = ncp_rq_alloc_any(NCP_ALLOC_SLOT, 0, conn, conn->td, conn->ucred, &rqp);
119 conn->flags &= ~(NCPFL_SIGNACTIVE | NCPFL_SIGNWANTED |
120 NCPFL_ATTACHED | NCPFL_LOGGED | NCPFL_INVALID);
122 error = ncp_request_int(rqp);
124 rp = mtod(rqp->rp.md_top, struct ncp_rphdr*);
125 conn->connid = rp->conn_low + (rp->conn_high << 8);
130 conn->flags |= NCPFL_ATTACHED | NCPFL_WASATTACHED;
135 ncp_ncp_disconnect(struct ncp_conn *conn)
140 NCPSDEBUG("for connid=%d\n",conn->nc_id);
142 ncp_burst_disconnect(conn);
144 if (conn->flags & NCPFL_ATTACHED) {
145 error = ncp_rq_alloc_any(NCP_FREE_SLOT, 0, conn, conn->td, conn->ucred, &rqp);
147 ncp_request_int(rqp);
151 ncp_conn_invalidate(conn);
152 ncp_sock_disconnect(conn);
157 * All negotiation functions expect a locked connection
161 ncp_negotiate_buffersize(struct ncp_conn *conn, int size, int *target)
167 error = ncp_rq_alloc(0x21, conn, conn->td, conn->ucred, &rqp);
170 mb_put_uint16be(&rqp->rq, size);
171 error = ncp_request(rqp);
174 md_get_uint16be(&rqp->rp, &bsize);
175 *target = min(bsize, size);
181 ncp_negotiate_size_and_options(struct ncp_conn *conn, int size, int options,
182 int *ret_size, u_int8_t *ret_options)
188 error = ncp_rq_alloc(0x61, conn, conn->td, conn->ucred, &rqp);
191 mb_put_uint16be(&rqp->rq, size);
192 mb_put_uint8(&rqp->rq, options);
193 rqp->nr_minrplen = 2 + 2 + 1;
194 error = ncp_request(rqp);
197 md_get_uint16be(&rqp->rp, &rs);
198 *ret_size = (rs == 0) ? size : min(rs, size);
199 md_get_uint16be(&rqp->rp, &rs); /* skip echo socket */
200 md_get_uint8(&rqp->rp, ret_options);
206 ncp_renegotiate_connparam(struct ncp_conn *conn, int buffsize, u_int8_t in_options)
209 int neg_buffsize, error, sl, ckslevel;
212 sl = conn->li.sig_level;
214 in_options |= NCP_SECURITY_LEVEL_SIGN_HEADERS;
215 if (conn->li.saddr.sa_family == AF_IPX) {
216 ilen = sizeof(ckslevel);
217 error = kernel_sysctlbyname(curthread, "net.ipx.ipx.checksum",
218 &ckslevel, &ilen, NULL, 0, NULL, 0);
222 in_options |= NCP_IPX_CHECKSUM;
224 error = ncp_negotiate_size_and_options(conn, buffsize, in_options,
225 &neg_buffsize, &options);
227 if (conn->li.saddr.sa_family == AF_IPX &&
228 ((options ^ in_options) & NCP_IPX_CHECKSUM)) {
230 printf("Server refuses to support IPX checksums\n");
231 return NWE_REQUESTER_FAILURE;
233 in_options |= NCP_IPX_CHECKSUM;
236 if ((options ^ in_options) & 2) {
237 if (sl == 0 || sl == 3)
238 return NWE_SIGNATURE_LEVEL_CONFLICT;
240 in_options |= NCP_SECURITY_LEVEL_SIGN_HEADERS;
245 error = ncp_negotiate_size_and_options(conn,
246 buffsize, in_options, &neg_buffsize, &options);
247 if ((options ^ in_options) & 3) {
248 return NWE_SIGNATURE_LEVEL_CONFLICT;
252 in_options &= ~NCP_SECURITY_LEVEL_SIGN_HEADERS;
253 error = ncp_negotiate_buffersize(conn, NCP_DEFAULT_BUFSIZE,
256 if (error) return error;
257 if ((neg_buffsize < 512) || (neg_buffsize > NCP_MAX_BUFSIZE))
259 conn->buffer_size = neg_buffsize;
260 if (in_options & NCP_SECURITY_LEVEL_SIGN_HEADERS)
261 conn->flags |= NCPFL_SIGNWANTED;
262 if (conn->li.saddr.sa_family == AF_IPX)
263 ncp_sock_checksum(conn, in_options & NCP_IPX_CHECKSUM);
268 ncp_check_rq(struct ncp_conn *conn)
271 if (conn->flags & NCPFL_INTR)
273 /* first, check for signals */
274 if (ncp_chkintr(conn, conn->td))
275 conn->flags |= NCPFL_INTR;
280 ncp_get_bindery_object_id(struct ncp_conn *conn,
281 u_int16_t object_type, char *object_name,
282 struct ncp_bindery_object *target,
283 struct thread *td, struct ucred *cred)
288 error = ncp_rq_alloc_subfn(23, 53, conn, conn->td, conn->ucred, &rqp);
289 mb_put_uint16be(&rqp->rq, object_type);
290 ncp_rq_pstring(rqp, object_name);
291 rqp->nr_minrplen = 54;
292 error = ncp_request(rqp);
295 md_get_uint32be(&rqp->rp, &target->object_id);
296 md_get_uint16be(&rqp->rp, &target->object_type);
297 md_get_mem(&rqp->rp, (caddr_t)target->object_name, 48, MB_MSYSTEM);
303 * target is a 8-byte buffer
306 ncp_get_encryption_key(struct ncp_conn *conn, char *target)
311 error = ncp_rq_alloc_subfn(23, 23, conn, conn->td, conn->ucred, &rqp);
314 rqp->nr_minrplen = 8;
315 error = ncp_request(rqp);
318 md_get_mem(&rqp->rp, target, 8, MB_MSYSTEM);
324 * Initialize packet signatures. They a slightly modified MD4.
325 * The first 16 bytes of logindata are the shuffled password,
326 * the last 8 bytes the encryption key as received from the server.
329 ncp_sign_start(struct ncp_conn *conn, char *logindata)
334 memcpy(msg, logindata, 24);
335 memcpy(msg + 24, "Authorized NetWare Client", 25);
336 bzero(msg + 24 + 25, sizeof(msg) - 24 - 25);
338 conn->sign_state[0] = 0x67452301;
339 conn->sign_state[1] = 0xefcdab89;
340 conn->sign_state[2] = 0x98badcfe;
341 conn->sign_state[3] = 0x10325476;
342 ncp_sign(conn->sign_state, msg, state);
343 conn->sign_root[0] = state[0];
344 conn->sign_root[1] = state[1];
345 conn->flags |= NCPFL_SIGNACTIVE;
351 ncp_login_encrypted(struct ncp_conn *conn, struct ncp_bindery_object *object,
352 const u_char *key, const u_char *passwd,
353 struct thread *td, struct ucred *cred)
357 u_int32_t tmpID = htonl(object->object_id);
362 nw_keyhash((u_char*)&tmpID, passwd, strlen(passwd), buf);
363 nw_encrypt(key, buf, encrypted);
365 error = ncp_rq_alloc_subfn(23, 24, conn, td, cred, &rqp);
369 mb_put_mem(mbp, encrypted, 8, MB_MSYSTEM);
370 mb_put_uint16be(mbp, object->object_type);
371 ncp_rq_pstring(rqp, object->object_name);
372 error = ncp_request(rqp);
375 if ((conn->flags & NCPFL_SIGNWANTED) &&
376 (error == 0 || error == NWE_PASSWORD_EXPIRED)) {
377 bcopy(key, buf + 16, 8);
378 error = ncp_sign_start(conn, buf);
384 ncp_login_unencrypted(struct ncp_conn *conn, u_int16_t object_type,
385 const char *object_name, const u_char *passwd,
386 struct thread *td, struct ucred *cred)
391 error = ncp_rq_alloc_subfn(23, 20, conn, td, cred, &rqp);
394 mb_put_uint16be(&rqp->rq, object_type);
395 ncp_rq_pstring(rqp, object_name);
396 ncp_rq_pstring(rqp, passwd);
397 error = ncp_request(rqp);
404 ncp_read(struct ncp_conn *conn, ncp_fh *file, struct uio *uiop, struct ucred *cred)
408 u_int16_t retlen = 0 ;
409 int error = 0, len = 0, tsiz, burstio;
411 tsiz = uiop->uio_resid;
413 burstio = (ncp_burst_enabled && tsiz > conn->buffer_size);
420 len = min(4096 - (uiop->uio_offset % 4096), tsiz);
421 len = min(len, conn->buffer_size);
422 error = ncp_rq_alloc(72, conn, uiop->uio_td, cred, &rqp);
426 mb_put_uint8(mbp, 0);
427 mb_put_mem(mbp, (caddr_t)file, 6, MB_MSYSTEM);
428 mb_put_uint32be(mbp, uiop->uio_offset);
429 mb_put_uint16be(mbp, len);
430 rqp->nr_minrplen = 2;
431 error = ncp_request(rqp);
434 md_get_uint16be(&rqp->rp, &retlen);
435 if (uiop->uio_offset & 1)
436 md_get_mem(&rqp->rp, NULL, 1, MB_MSYSTEM);
437 error = md_get_uio(&rqp->rp, uiop, retlen);
441 error = ncp_burst_read(conn, file, tsiz, &len, &retlen, uiop, cred);
454 ncp_write(struct ncp_conn *conn, ncp_fh *file, struct uio *uiop, struct ucred *cred)
458 int error = 0, len, tsiz, backup;
460 if (uiop->uio_iovcnt != 1) {
461 printf("%s: can't handle iovcnt>1 !!!\n", __func__);
464 tsiz = uiop->uio_resid;
466 len = min(4096 - (uiop->uio_offset % 4096), tsiz);
467 len = min(len, conn->buffer_size);
472 error = ncp_rq_alloc(73, conn, uiop->uio_td, cred, &rqp);
476 mb_put_uint8(mbp, 0);
477 mb_put_mem(mbp, (caddr_t)file, 6, MB_MSYSTEM);
478 mb_put_uint32be(mbp, uiop->uio_offset);
479 mb_put_uint16be(mbp, len);
480 error = mb_put_uio(mbp, uiop, len);
485 error = ncp_request(rqp);
492 uiop->uio_iov->iov_base =
493 (char *)uiop->uio_iov->iov_base - backup;
494 uiop->uio_iov->iov_len += backup;
495 uiop->uio_offset -= backup;
496 uiop->uio_resid += backup;
502 uiop->uio_resid = tsiz;
504 case NWE_INSUFFICIENT_SPACE: