FreeBSD/Linux Kernel Cross Reference
sys/netncp/ncp_ncp.c
1 /*-
2 * Copyright (c) 1999, 2000, 2001 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. 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.
19 *
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
30 * SUCH DAMAGE.
31 *
32 * Core of NCP protocol
33 */
34
35 #include <sys/cdefs.h>
36 __FBSDID("$FreeBSD$");
37
38 #include <sys/param.h>
39 #include <sys/errno.h>
40 #include <sys/systm.h>
41 #include <sys/proc.h>
42 #include <sys/signalvar.h>
43 #include <sys/sysctl.h>
44 #include <sys/mbuf.h>
45 #include <sys/lock.h>
46 #include <sys/mutex.h>
47 #include <sys/uio.h>
48
49 #include <netipx/ipx.h>
50 #include <netipx/ipx_var.h>
51
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>
59
60 #ifdef NCP_DATA_DEBUG
61 static
62 void m_dumpm(struct mbuf *m) {
63 char *p;
64 int len;
65 printf("d=");
66 while(m) {
67 p=mtod(m,char *);
68 len=m->m_len;
69 printf("(%d)",len);
70 while(len--){
71 printf("%02x ",((int)*(p++)) & 0xff);
72 }
73 m=m->m_next;
74 };
75 printf("\n");
76 }
77 #endif /* NCP_DATA_DEBUG */
78
79 int
80 ncp_chkintr(struct ncp_conn *conn, struct thread *td)
81 {
82 struct proc *p;
83 sigset_t tmpset;
84
85 if (td == NULL)
86 return 0;
87 p = td->td_proc;
88 PROC_LOCK(p);
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)) {
96 PROC_UNLOCK(p);
97 return EINTR;
98 }
99 PROC_UNLOCK(p);
100 return 0;
101 }
102
103 /*
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
107 */
108 int
109 ncp_ncp_connect(struct ncp_conn *conn)
110 {
111 struct ncp_rq *rqp;
112 struct ncp_rphdr *rp;
113 int error;
114
115 error = ncp_rq_alloc_any(NCP_ALLOC_SLOT, 0, conn, conn->td, conn->ucred, &rqp);
116 if (error)
117 return error;
118
119 conn->flags &= ~(NCPFL_SIGNACTIVE | NCPFL_SIGNWANTED |
120 NCPFL_ATTACHED | NCPFL_LOGGED | NCPFL_INVALID);
121 conn->seq = 0;
122 error = ncp_request_int(rqp);
123 if (!error) {
124 rp = mtod(rqp->rp.md_top, struct ncp_rphdr*);
125 conn->connid = rp->conn_low + (rp->conn_high << 8);
126 }
127 ncp_rq_done(rqp);
128 if (error)
129 return error;
130 conn->flags |= NCPFL_ATTACHED | NCPFL_WASATTACHED;
131 return 0;
132 }
133
134 int
135 ncp_ncp_disconnect(struct ncp_conn *conn)
136 {
137 struct ncp_rq *rqp;
138 int error;
139
140 NCPSDEBUG("for connid=%d\n",conn->nc_id);
141 #ifdef NCPBURST
142 ncp_burst_disconnect(conn);
143 #endif
144 if (conn->flags & NCPFL_ATTACHED) {
145 error = ncp_rq_alloc_any(NCP_FREE_SLOT, 0, conn, conn->td, conn->ucred, &rqp);
146 if (!error) {
147 ncp_request_int(rqp);
148 ncp_rq_done(rqp);
149 }
150 }
151 ncp_conn_invalidate(conn);
152 ncp_sock_disconnect(conn);
153 return 0;
154 }
155
156 /*
157 * All negotiation functions expect a locked connection
158 */
159
160 int
161 ncp_negotiate_buffersize(struct ncp_conn *conn, int size, int *target)
162 {
163 struct ncp_rq *rqp;
164 u_int16_t bsize;
165 int error;
166
167 error = ncp_rq_alloc(0x21, conn, conn->td, conn->ucred, &rqp);
168 if (error)
169 return error;
170 mb_put_uint16be(&rqp->rq, size);
171 error = ncp_request(rqp);
172 if (error)
173 return error;
174 md_get_uint16be(&rqp->rp, &bsize);
175 *target = min(bsize, size);
176 ncp_rq_done(rqp);
177 return error;
178 }
179
180 static int
181 ncp_negotiate_size_and_options(struct ncp_conn *conn, int size, int options,
182 int *ret_size, u_int8_t *ret_options)
183 {
184 struct ncp_rq *rqp;
185 u_int16_t rs;
186 int error;
187
188 error = ncp_rq_alloc(0x61, conn, conn->td, conn->ucred, &rqp);
189 if (error)
190 return error;
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);
195 if (error)
196 return error;
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);
201 ncp_rq_done(rqp);
202 return error;
203 }
204
205 int
206 ncp_renegotiate_connparam(struct ncp_conn *conn, int buffsize, u_int8_t in_options)
207 {
208 u_int8_t options;
209 int neg_buffsize, error, sl, ckslevel;
210 size_t ilen;
211
212 sl = conn->li.sig_level;
213 if (sl >= 2)
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);
219 if (error)
220 return error;
221 if (ckslevel == 2)
222 in_options |= NCP_IPX_CHECKSUM;
223 }
224 error = ncp_negotiate_size_and_options(conn, buffsize, in_options,
225 &neg_buffsize, &options);
226 if (!error) {
227 if (conn->li.saddr.sa_family == AF_IPX &&
228 ((options ^ in_options) & NCP_IPX_CHECKSUM)) {
229 if (ckslevel == 2) {
230 printf("Server refuses to support IPX checksums\n");
231 return NWE_REQUESTER_FAILURE;
232 }
233 in_options |= NCP_IPX_CHECKSUM;
234 error = 1;
235 }
236 if ((options ^ in_options) & 2) {
237 if (sl == 0 || sl == 3)
238 return NWE_SIGNATURE_LEVEL_CONFLICT;
239 if (sl == 1) {
240 in_options |= NCP_SECURITY_LEVEL_SIGN_HEADERS;
241 error = 1;
242 }
243 }
244 if (error) {
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;
249 }
250 }
251 } else {
252 in_options &= ~NCP_SECURITY_LEVEL_SIGN_HEADERS;
253 error = ncp_negotiate_buffersize(conn, NCP_DEFAULT_BUFSIZE,
254 &neg_buffsize);
255 }
256 if (error) return error;
257 if ((neg_buffsize < 512) || (neg_buffsize > NCP_MAX_BUFSIZE))
258 return EINVAL;
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);
264 return 0;
265 }
266
267 void
268 ncp_check_rq(struct ncp_conn *conn)
269 {
270 return;
271 if (conn->flags & NCPFL_INTR)
272 return;
273 /* first, check for signals */
274 if (ncp_chkintr(conn, conn->td))
275 conn->flags |= NCPFL_INTR;
276 return;
277 }
278
279 int
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)
284 {
285 struct ncp_rq *rqp;
286 int error;
287
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);
293 if (error)
294 return error;
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);
298 ncp_rq_done(rqp);
299 return 0;
300 }
301
302 /*
303 * target is a 8-byte buffer
304 */
305 int
306 ncp_get_encryption_key(struct ncp_conn *conn, char *target)
307 {
308 struct ncp_rq *rqp;
309 int error;
310
311 error = ncp_rq_alloc_subfn(23, 23, conn, conn->td, conn->ucred, &rqp);
312 if (error)
313 return error;
314 rqp->nr_minrplen = 8;
315 error = ncp_request(rqp);
316 if (error)
317 return error;
318 md_get_mem(&rqp->rp, target, 8, MB_MSYSTEM);
319 ncp_rq_done(rqp);
320 return error;
321 }
322
323 /*
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.
327 */
328 static int
329 ncp_sign_start(struct ncp_conn *conn, char *logindata)
330 {
331 char msg[64];
332 u_int32_t state[4];
333
334 memcpy(msg, logindata, 24);
335 memcpy(msg + 24, "Authorized NetWare Client", 25);
336 bzero(msg + 24 + 25, sizeof(msg) - 24 - 25);
337
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;
346 return 0;
347 }
348
349
350 int
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)
354 {
355 struct ncp_rq *rqp;
356 struct mbchain *mbp;
357 u_int32_t tmpID = htonl(object->object_id);
358 u_char buf[16 + 8];
359 u_char encrypted[8];
360 int error;
361
362 nw_keyhash((u_char*)&tmpID, passwd, strlen(passwd), buf);
363 nw_encrypt(key, buf, encrypted);
364
365 error = ncp_rq_alloc_subfn(23, 24, conn, td, cred, &rqp);
366 if (error)
367 return error;
368 mbp = &rqp->rq;
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);
373 if (!error)
374 ncp_rq_done(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);
379 }
380 return error;
381 }
382
383 int
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)
387 {
388 struct ncp_rq *rqp;
389 int error;
390
391 error = ncp_rq_alloc_subfn(23, 20, conn, td, cred, &rqp);
392 if (error)
393 return error;
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);
398 if (!error)
399 ncp_rq_done(rqp);
400 return error;
401 }
402
403 int
404 ncp_read(struct ncp_conn *conn, ncp_fh *file, struct uio *uiop, struct ucred *cred)
405 {
406 struct ncp_rq *rqp;
407 struct mbchain *mbp;
408 u_int16_t retlen = 0 ;
409 int error = 0, len = 0, tsiz, burstio;
410
411 tsiz = uiop->uio_resid;
412 #ifdef NCPBURST
413 burstio = (ncp_burst_enabled && tsiz > conn->buffer_size);
414 #else
415 burstio = 0;
416 #endif
417
418 while (tsiz > 0) {
419 if (!burstio) {
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);
423 if (error)
424 break;
425 mbp = &rqp->rq;
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);
432 if (error)
433 break;
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);
438 ncp_rq_done(rqp);
439 } else {
440 #ifdef NCPBURST
441 error = ncp_burst_read(conn, file, tsiz, &len, &retlen, uiop, cred);
442 #endif
443 }
444 if (error)
445 break;
446 tsiz -= retlen;
447 if (retlen < len)
448 break;
449 }
450 return (error);
451 }
452
453 int
454 ncp_write(struct ncp_conn *conn, ncp_fh *file, struct uio *uiop, struct ucred *cred)
455 {
456 struct ncp_rq *rqp;
457 struct mbchain *mbp;
458 int error = 0, len, tsiz, backup;
459
460 if (uiop->uio_iovcnt != 1) {
461 printf("%s: can't handle iovcnt>1 !!!\n", __func__);
462 return EIO;
463 }
464 tsiz = uiop->uio_resid;
465 while (tsiz > 0) {
466 len = min(4096 - (uiop->uio_offset % 4096), tsiz);
467 len = min(len, conn->buffer_size);
468 if (len == 0) {
469 printf("gotcha!\n");
470 }
471 /* rq head */
472 error = ncp_rq_alloc(73, conn, uiop->uio_td, cred, &rqp);
473 if (error)
474 break;
475 mbp = &rqp->rq;
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);
481 if (error) {
482 ncp_rq_done(rqp);
483 break;
484 }
485 error = ncp_request(rqp);
486 if (!error)
487 ncp_rq_done(rqp);
488 if (len == 0)
489 break;
490 if (error) {
491 backup = len;
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;
497 break;
498 }
499 tsiz -= len;
500 }
501 if (error)
502 uiop->uio_resid = tsiz;
503 switch (error) {
504 case NWE_INSUFFICIENT_SPACE:
505 error = ENOSPC;
506 break;
507 }
508 return (error);
509 }
Cache object: bc2dc07aab87ec3c37323b0453d9a444
|