The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/netncp/ncp_ncp.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    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: releng/7.3/sys/netncp/ncp_ncp.c 139823 2005-01-07 01:45:51Z imp $");
   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: e0cb5346e417f1f5f01f1411c0ae7e32


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.