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  *
   14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   24  * SUCH DAMAGE.
   25  *
   26  * Core of NCP protocol
   27  */
   28 
   29 #include <sys/cdefs.h>
   30 __FBSDID("$FreeBSD$");
   31 
   32 #include <sys/param.h>
   33 #include <sys/errno.h>
   34 #include <sys/systm.h>
   35 #include <sys/proc.h>
   36 #include <sys/signalvar.h>
   37 #include <sys/sysctl.h>
   38 #include <sys/mbuf.h>
   39 #include <sys/lock.h>
   40 #include <sys/mutex.h>
   41 #include <sys/uio.h>
   42 
   43 #include <netipx/ipx.h>
   44 #include <netipx/ipx_var.h>
   45 
   46 #include <netncp/ncp.h>
   47 #include <netncp/ncp_conn.h>
   48 #include <netncp/ncp_sock.h>
   49 #include <netncp/ncp_subr.h>
   50 #include <netncp/ncp_ncp.h>
   51 #include <netncp/ncp_rq.h>
   52 #include <netncp/nwerror.h>
   53 
   54 #ifdef NCP_DATA_DEBUG
   55 static
   56 void m_dumpm(struct mbuf *m) {
   57         char *p;
   58         int len;
   59         printf("d=");
   60         while(m) {
   61                 p=mtod(m,char *);
   62                 len=m->m_len;
   63                 printf("(%d)",len);
   64                 while(len--){
   65                         printf("%02x ",((int)*(p++)) & 0xff);
   66                 }
   67                 m=m->m_next;
   68         };
   69         printf("\n");
   70 }
   71 #endif /* NCP_DATA_DEBUG */
   72 
   73 int
   74 ncp_chkintr(struct ncp_conn *conn, struct thread *td)
   75 {
   76         struct proc *p;
   77         sigset_t tmpset;
   78 
   79         if (td == NULL)
   80                 return 0;
   81         p = td->td_proc;
   82         PROC_LOCK(p);
   83         tmpset = p->p_siglist;
   84         SIGSETOR(tmpset, td->td_siglist);
   85         SIGSETNAND(tmpset, td->td_sigmask);
   86         mtx_lock(&p->p_sigacts->ps_mtx);
   87         SIGSETNAND(tmpset, p->p_sigacts->ps_sigignore);
   88         mtx_unlock(&p->p_sigacts->ps_mtx);
   89         if (SIGNOTEMPTY(td->td_siglist) && NCP_SIGMASK(tmpset)) {
   90                 PROC_UNLOCK(p);
   91                 return EINTR;
   92         }
   93         PROC_UNLOCK(p);
   94         return 0;
   95 }
   96 
   97 /*
   98  * Process initial NCP handshake (attach)
   99  * NOTE: Since all functions below may change conn attributes, they
  100  * should be called with LOCKED connection, also they use procp & ucred
  101  */
  102 int
  103 ncp_ncp_connect(struct ncp_conn *conn)
  104 {
  105         struct ncp_rq *rqp;
  106         struct ncp_rphdr *rp;
  107         int error;
  108 
  109         error = ncp_rq_alloc_any(NCP_ALLOC_SLOT, 0, conn, conn->td, conn->ucred, &rqp);
  110         if (error)
  111                 return error;
  112 
  113         conn->flags &= ~(NCPFL_SIGNACTIVE | NCPFL_SIGNWANTED |
  114             NCPFL_ATTACHED | NCPFL_LOGGED | NCPFL_INVALID);
  115         conn->seq = 0;
  116         error = ncp_request_int(rqp);
  117         if (!error) {
  118                 rp = mtod(rqp->rp.md_top, struct ncp_rphdr*);
  119                 conn->connid = rp->conn_low + (rp->conn_high << 8);
  120         }
  121         ncp_rq_done(rqp);
  122         if (error)
  123                 return error;
  124         conn->flags |= NCPFL_ATTACHED | NCPFL_WASATTACHED;
  125         return 0;
  126 }
  127 
  128 int
  129 ncp_ncp_disconnect(struct ncp_conn *conn)
  130 {
  131         struct ncp_rq *rqp;
  132         int error;
  133 
  134         NCPSDEBUG("for connid=%d\n",conn->nc_id);
  135 #ifdef NCPBURST
  136         ncp_burst_disconnect(conn);
  137 #endif
  138         if (conn->flags & NCPFL_ATTACHED) {
  139                 error = ncp_rq_alloc_any(NCP_FREE_SLOT, 0, conn, conn->td, conn->ucred, &rqp);
  140                 if (!error) {
  141                         ncp_request_int(rqp);
  142                         ncp_rq_done(rqp);
  143                 }
  144         }
  145         ncp_conn_invalidate(conn);
  146         ncp_sock_disconnect(conn);
  147         return 0;
  148 }
  149 
  150 /*
  151  * All negotiation functions expect a locked connection
  152  */
  153 
  154 int
  155 ncp_negotiate_buffersize(struct ncp_conn *conn, int size, int *target)
  156 {
  157         struct ncp_rq *rqp;
  158         u_int16_t bsize;
  159         int error;
  160 
  161         error = ncp_rq_alloc(0x21, conn, conn->td, conn->ucred, &rqp);
  162         if (error)
  163                 return error;
  164         mb_put_uint16be(&rqp->rq, size);
  165         error = ncp_request(rqp);
  166         if (error)
  167                 return error;
  168         md_get_uint16be(&rqp->rp, &bsize);
  169         *target = min(bsize, size);
  170         ncp_rq_done(rqp);
  171         return error;
  172 }
  173 
  174 static int
  175 ncp_negotiate_size_and_options(struct ncp_conn *conn, int size, int options,
  176             int *ret_size, u_int8_t *ret_options)
  177 {
  178         struct ncp_rq *rqp;
  179         u_int16_t rs;
  180         int error;
  181 
  182         error = ncp_rq_alloc(0x61, conn, conn->td, conn->ucred, &rqp);
  183         if (error)
  184                 return error;
  185         mb_put_uint16be(&rqp->rq, size);
  186         mb_put_uint8(&rqp->rq, options);
  187         rqp->nr_minrplen = 2 + 2 + 1;
  188         error = ncp_request(rqp);
  189         if (error)
  190                 return error;
  191         md_get_uint16be(&rqp->rp, &rs);
  192         *ret_size = (rs == 0) ? size : min(rs, size);
  193         md_get_uint16be(&rqp->rp, &rs);         /* skip echo socket */
  194         md_get_uint8(&rqp->rp, ret_options);
  195         ncp_rq_done(rqp);
  196         return error;
  197 }
  198 
  199 int
  200 ncp_renegotiate_connparam(struct ncp_conn *conn, int buffsize, u_int8_t in_options)
  201 {
  202         u_int8_t options;
  203         int neg_buffsize, error, sl, ckslevel;
  204         size_t ilen;
  205 
  206         sl = conn->li.sig_level;
  207         if (sl >= 2)
  208                 in_options |= NCP_SECURITY_LEVEL_SIGN_HEADERS;
  209         if (conn->li.saddr.sa_family == AF_IPX) {
  210                 ilen = sizeof(ckslevel);
  211                 error = kernel_sysctlbyname(curthread, "net.ipx.ipx.checksum",
  212                     &ckslevel, &ilen, NULL, 0, NULL, 0);
  213                 if (error)
  214                         return error;
  215                 if (ckslevel == 2)
  216                         in_options |= NCP_IPX_CHECKSUM;
  217         }
  218         error = ncp_negotiate_size_and_options(conn, buffsize, in_options,
  219             &neg_buffsize, &options);
  220         if (!error) {
  221                 if (conn->li.saddr.sa_family == AF_IPX &&
  222                     ((options ^ in_options) & NCP_IPX_CHECKSUM)) {
  223                         if (ckslevel == 2) {
  224                                 printf("Server refuses to support IPX checksums\n");
  225                                 return NWE_REQUESTER_FAILURE;
  226                         }
  227                         in_options |= NCP_IPX_CHECKSUM;
  228                         error = 1;
  229                 }
  230                 if ((options ^ in_options) & 2) {
  231                         if (sl == 0 || sl == 3)
  232                                 return NWE_SIGNATURE_LEVEL_CONFLICT;
  233                         if (sl == 1) {
  234                                 in_options |= NCP_SECURITY_LEVEL_SIGN_HEADERS;
  235                                 error = 1;
  236                         }
  237                 }
  238                 if (error) {
  239                         error = ncp_negotiate_size_and_options(conn,
  240                             buffsize, in_options, &neg_buffsize, &options);
  241                         if ((options ^ in_options) & 3) {
  242                                 return NWE_SIGNATURE_LEVEL_CONFLICT;
  243                         }
  244                 }
  245         } else {
  246                 in_options &= ~NCP_SECURITY_LEVEL_SIGN_HEADERS;
  247                 error = ncp_negotiate_buffersize(conn, NCP_DEFAULT_BUFSIZE,
  248                               &neg_buffsize);
  249         }                         
  250         if (error) return error;
  251         if ((neg_buffsize < 512) || (neg_buffsize > NCP_MAX_BUFSIZE))
  252                 return EINVAL;
  253         conn->buffer_size = neg_buffsize;
  254         if (in_options & NCP_SECURITY_LEVEL_SIGN_HEADERS)
  255                 conn->flags |= NCPFL_SIGNWANTED;
  256         if (conn->li.saddr.sa_family == AF_IPX)
  257                 ncp_sock_checksum(conn, in_options & NCP_IPX_CHECKSUM);
  258         return 0;
  259 }
  260 
  261 void
  262 ncp_check_rq(struct ncp_conn *conn)
  263 {
  264         return;
  265         if (conn->flags & NCPFL_INTR)
  266                 return;
  267         /* first, check for signals */
  268         if (ncp_chkintr(conn, conn->td))
  269                 conn->flags |= NCPFL_INTR;
  270         return;
  271 }
  272 
  273 int
  274 ncp_get_bindery_object_id(struct ncp_conn *conn,
  275                 u_int16_t object_type, char *object_name,
  276                 struct ncp_bindery_object *target,
  277                 struct thread *td, struct ucred *cred)
  278 {
  279         struct ncp_rq *rqp;
  280         int error;
  281 
  282         error = ncp_rq_alloc_subfn(23, 53, conn, conn->td, conn->ucred, &rqp);
  283         mb_put_uint16be(&rqp->rq, object_type);
  284         ncp_rq_pstring(rqp, object_name);
  285         rqp->nr_minrplen = 54;
  286         error = ncp_request(rqp);
  287         if (error)
  288                 return error;
  289         md_get_uint32be(&rqp->rp, &target->object_id);
  290         md_get_uint16be(&rqp->rp, &target->object_type);
  291         md_get_mem(&rqp->rp, (caddr_t)target->object_name, 48, MB_MSYSTEM);
  292         ncp_rq_done(rqp);
  293         return 0;
  294 }
  295 
  296 /*
  297  * target is a 8-byte buffer
  298  */
  299 int
  300 ncp_get_encryption_key(struct ncp_conn *conn, char *target)
  301 {
  302         struct ncp_rq *rqp;
  303         int error;
  304 
  305         error = ncp_rq_alloc_subfn(23, 23, conn, conn->td, conn->ucred, &rqp);
  306         if (error)
  307                 return error;
  308         rqp->nr_minrplen = 8;
  309         error = ncp_request(rqp);
  310         if (error)
  311                 return error;
  312         md_get_mem(&rqp->rp, target, 8, MB_MSYSTEM);
  313         ncp_rq_done(rqp);
  314         return error;
  315 }
  316 
  317 /*
  318  * Initialize packet signatures. They a slightly modified MD4.
  319  * The first 16 bytes of logindata are the shuffled password,
  320  * the last 8 bytes the encryption key as received from the server.
  321  */
  322 static int
  323 ncp_sign_start(struct ncp_conn *conn, char *logindata)
  324 {
  325         char msg[64];
  326         u_int32_t state[4];
  327 
  328         memcpy(msg, logindata, 24);
  329         memcpy(msg + 24, "Authorized NetWare Client", 25);
  330         bzero(msg + 24 + 25, sizeof(msg) - 24 - 25);
  331 
  332         conn->sign_state[0] = 0x67452301;
  333         conn->sign_state[1] = 0xefcdab89;
  334         conn->sign_state[2] = 0x98badcfe;
  335         conn->sign_state[3] = 0x10325476;
  336         ncp_sign(conn->sign_state, msg, state);
  337         conn->sign_root[0] = state[0];
  338         conn->sign_root[1] = state[1];
  339         conn->flags |= NCPFL_SIGNACTIVE;
  340         return 0;
  341 }
  342 
  343 
  344 int
  345 ncp_login_encrypted(struct ncp_conn *conn, struct ncp_bindery_object *object,
  346         const u_char *key, const u_char *passwd,
  347         struct thread *td, struct ucred *cred)
  348 {
  349         struct ncp_rq *rqp;
  350         struct mbchain *mbp;
  351         u_int32_t tmpID = htonl(object->object_id);
  352         u_char buf[16 + 8];
  353         u_char encrypted[8];
  354         int error;
  355 
  356         nw_keyhash((u_char*)&tmpID, passwd, strlen(passwd), buf);
  357         nw_encrypt(key, buf, encrypted);
  358 
  359         error = ncp_rq_alloc_subfn(23, 24, conn, td, cred, &rqp);
  360         if (error)
  361                 return error;
  362         mbp = &rqp->rq;
  363         mb_put_mem(mbp, encrypted, 8, MB_MSYSTEM);
  364         mb_put_uint16be(mbp, object->object_type);
  365         ncp_rq_pstring(rqp, object->object_name);
  366         error = ncp_request(rqp);
  367         if (!error)
  368                 ncp_rq_done(rqp);
  369         if ((conn->flags & NCPFL_SIGNWANTED) &&
  370             (error == 0 || error == NWE_PASSWORD_EXPIRED)) {
  371                 bcopy(key, buf + 16, 8);
  372                 error = ncp_sign_start(conn, buf);
  373         }
  374         return error;
  375 }
  376 
  377 int
  378 ncp_login_unencrypted(struct ncp_conn *conn, u_int16_t object_type,
  379         const char *object_name, const u_char *passwd,
  380         struct thread *td, struct ucred *cred)
  381 {
  382         struct ncp_rq *rqp;
  383         int error;
  384 
  385         error = ncp_rq_alloc_subfn(23, 20, conn, td, cred, &rqp);
  386         if (error)
  387                 return error;
  388         mb_put_uint16be(&rqp->rq, object_type);
  389         ncp_rq_pstring(rqp, object_name);
  390         ncp_rq_pstring(rqp, passwd);
  391         error = ncp_request(rqp);
  392         if (!error)
  393                 ncp_rq_done(rqp);
  394         return error;
  395 }
  396 
  397 int
  398 ncp_read(struct ncp_conn *conn, ncp_fh *file, struct uio *uiop, struct ucred *cred)
  399 {
  400         struct ncp_rq *rqp;
  401         struct mbchain *mbp;
  402         u_int16_t retlen = 0 ;
  403         int error = 0, len = 0, tsiz, burstio;
  404 
  405         tsiz = uiop->uio_resid;
  406 #ifdef NCPBURST
  407         burstio = (ncp_burst_enabled && tsiz > conn->buffer_size);
  408 #else
  409         burstio = 0;
  410 #endif
  411 
  412         while (tsiz > 0) {
  413                 if (!burstio) {
  414                         len = min(4096 - (uiop->uio_offset % 4096), tsiz);
  415                         len = min(len, conn->buffer_size);
  416                         error = ncp_rq_alloc(72, conn, uiop->uio_td, cred, &rqp);
  417                         if (error)
  418                                 break;
  419                         mbp = &rqp->rq;
  420                         mb_put_uint8(mbp, 0);
  421                         mb_put_mem(mbp, (caddr_t)file, 6, MB_MSYSTEM);
  422                         mb_put_uint32be(mbp, uiop->uio_offset);
  423                         mb_put_uint16be(mbp, len);
  424                         rqp->nr_minrplen = 2;
  425                         error = ncp_request(rqp);
  426                         if (error)
  427                                 break;
  428                         md_get_uint16be(&rqp->rp, &retlen);
  429                         if (uiop->uio_offset & 1)
  430                                 md_get_mem(&rqp->rp, NULL, 1, MB_MSYSTEM);
  431                         error = md_get_uio(&rqp->rp, uiop, retlen);
  432                         ncp_rq_done(rqp);
  433                 } else {
  434 #ifdef NCPBURST
  435                         error = ncp_burst_read(conn, file, tsiz, &len, &retlen, uiop, cred);
  436 #endif
  437                 }
  438                 if (error)
  439                         break;
  440                 tsiz -= retlen;
  441                 if (retlen < len)
  442                         break;
  443         }
  444         return (error);
  445 }
  446 
  447 int
  448 ncp_write(struct ncp_conn *conn, ncp_fh *file, struct uio *uiop, struct ucred *cred)
  449 {
  450         struct ncp_rq *rqp;
  451         struct mbchain *mbp;
  452         int error = 0, len, tsiz, backup;
  453 
  454         if (uiop->uio_iovcnt != 1) {
  455                 printf("%s: can't handle iovcnt>1 !!!\n", __func__);
  456                 return EIO;
  457         }
  458         tsiz = uiop->uio_resid;
  459         while (tsiz > 0) {
  460                 len = min(4096 - (uiop->uio_offset % 4096), tsiz);
  461                 len = min(len, conn->buffer_size);
  462                 if (len == 0) {
  463                         printf("gotcha!\n");
  464                 }
  465                 /* rq head */
  466                 error = ncp_rq_alloc(73, conn, uiop->uio_td, cred, &rqp);
  467                 if (error)
  468                         break;
  469                 mbp = &rqp->rq;
  470                 mb_put_uint8(mbp, 0);
  471                 mb_put_mem(mbp, (caddr_t)file, 6, MB_MSYSTEM);
  472                 mb_put_uint32be(mbp, uiop->uio_offset);
  473                 mb_put_uint16be(mbp, len);
  474                 error = mb_put_uio(mbp, uiop, len);
  475                 if (error) {
  476                         ncp_rq_done(rqp);
  477                         break;
  478                 }
  479                 error = ncp_request(rqp);
  480                 if (!error)
  481                         ncp_rq_done(rqp);
  482                 if (len == 0)
  483                         break;
  484                 if (error) {
  485                         backup = len;
  486                         uiop->uio_iov->iov_base =
  487                             (char *)uiop->uio_iov->iov_base - backup;
  488                         uiop->uio_iov->iov_len += backup;
  489                         uiop->uio_offset -= backup;
  490                         uiop->uio_resid += backup;
  491                         break;
  492                 }
  493                 tsiz -= len;
  494         }
  495         if (error)
  496                 uiop->uio_resid = tsiz;
  497         switch (error) {
  498             case NWE_INSUFFICIENT_SPACE:
  499                 error = ENOSPC;
  500                 break;
  501         }
  502         return (error);
  503 }

Cache object: 8c899abfa65caa9c0b130b5e3dfe5281


[ 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.