1613a2f6bSGordon Ross /* 2613a2f6bSGordon Ross * CDDL HEADER START 3613a2f6bSGordon Ross * 4613a2f6bSGordon Ross * The contents of this file are subject to the terms of the 5613a2f6bSGordon Ross * Common Development and Distribution License (the "License"). 6613a2f6bSGordon Ross * You may not use this file except in compliance with the License. 7613a2f6bSGordon Ross * 8613a2f6bSGordon Ross * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9613a2f6bSGordon Ross * or http://www.opensolaris.org/os/licensing. 10613a2f6bSGordon Ross * See the License for the specific language governing permissions 11613a2f6bSGordon Ross * and limitations under the License. 12613a2f6bSGordon Ross * 13613a2f6bSGordon Ross * When distributing Covered Code, include this CDDL HEADER in each 14613a2f6bSGordon Ross * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15613a2f6bSGordon Ross * If applicable, add the following below this CDDL HEADER, with the 16613a2f6bSGordon Ross * fields enclosed by brackets "[]" replaced with your own identifying 17613a2f6bSGordon Ross * information: Portions Copyright [yyyy] [name of copyright owner] 18613a2f6bSGordon Ross * 19613a2f6bSGordon Ross * CDDL HEADER END 20613a2f6bSGordon Ross */ 21613a2f6bSGordon Ross 22613a2f6bSGordon Ross /* 23*15359501SGordon Ross * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. 24613a2f6bSGordon Ross */ 25613a2f6bSGordon Ross 26613a2f6bSGordon Ross /* 27613a2f6bSGordon Ross * NetBIOS session service functions 28613a2f6bSGordon Ross */ 29613a2f6bSGordon Ross 30613a2f6bSGordon Ross #include <errno.h> 31613a2f6bSGordon Ross #include <stdio.h> 32613a2f6bSGordon Ross #include <stdlib.h> 33613a2f6bSGordon Ross #include <string.h> 34613a2f6bSGordon Ross #include <strings.h> 35613a2f6bSGordon Ross #include <libintl.h> 36613a2f6bSGordon Ross #include <xti.h> 37613a2f6bSGordon Ross #include <assert.h> 38613a2f6bSGordon Ross 39613a2f6bSGordon Ross #include <sys/types.h> 40613a2f6bSGordon Ross #include <sys/socket.h> 41613a2f6bSGordon Ross #include <sys/poll.h> 42613a2f6bSGordon Ross 43613a2f6bSGordon Ross #include <netsmb/netbios.h> 44613a2f6bSGordon Ross #include <netsmb/smb_lib.h> 45613a2f6bSGordon Ross #include <netsmb/nb_lib.h> 46613a2f6bSGordon Ross #include <netsmb/mchain.h> 47613a2f6bSGordon Ross 48613a2f6bSGordon Ross #include "private.h" 49613a2f6bSGordon Ross #include "charsets.h" 50613a2f6bSGordon Ross 51613a2f6bSGordon Ross static int nb_ssn_send(struct smb_ctx *, struct mbdata *, int, int); 52613a2f6bSGordon Ross static int nb_ssn_recv(struct smb_ctx *, struct mbdata *, int *, int *); 53613a2f6bSGordon Ross static int nb_ssn_pollin(struct smb_ctx *, int); 54613a2f6bSGordon Ross 55613a2f6bSGordon Ross /* 56613a2f6bSGordon Ross * Send a data message. 57613a2f6bSGordon Ross */ 58613a2f6bSGordon Ross int 59613a2f6bSGordon Ross smb_ssn_send(struct smb_ctx *ctx, struct mbdata *mbp) 60613a2f6bSGordon Ross { 61613a2f6bSGordon Ross return (nb_ssn_send(ctx, mbp, 0, mbp->mb_count)); 62613a2f6bSGordon Ross } 63613a2f6bSGordon Ross 64613a2f6bSGordon Ross /* 65613a2f6bSGordon Ross * Send a NetBIOS message, after 66613a2f6bSGordon Ross * prepending the 4-byte header. 67613a2f6bSGordon Ross */ 68613a2f6bSGordon Ross static int 69613a2f6bSGordon Ross nb_ssn_send(struct smb_ctx *ctx, struct mbdata *mbp, 70613a2f6bSGordon Ross int mtype, int mlen) 71613a2f6bSGordon Ross { 72*15359501SGordon Ross mbuf_t *m; 73613a2f6bSGordon Ross uint32_t hdr, hdrbuf; 74*15359501SGordon Ross int err; 75613a2f6bSGordon Ross 76*15359501SGordon Ross m = mbp->mb_top; 77613a2f6bSGordon Ross if (m == NULL) 78613a2f6bSGordon Ross return (EINVAL); 79613a2f6bSGordon Ross 80613a2f6bSGordon Ross /* 81613a2f6bSGordon Ross * Prepend the NetBIOS header. 82*15359501SGordon Ross * Our mbufs leave space for this. 83613a2f6bSGordon Ross */ 84613a2f6bSGordon Ross hdr = (mtype << 24) | mlen; 85613a2f6bSGordon Ross hdrbuf = htonl(hdr); 86613a2f6bSGordon Ross m->m_data -= 4; 87613a2f6bSGordon Ross m->m_len += 4; 88613a2f6bSGordon Ross bcopy(&hdrbuf, m->m_data, 4); 89613a2f6bSGordon Ross 90*15359501SGordon Ross /* 91*15359501SGordon Ross * Get contiguous data (so TCP won't fragment) 92*15359501SGordon Ross * Note: replaces mb_top. 93*15359501SGordon Ross */ 94*15359501SGordon Ross err = m_lineup(mbp->mb_top, &mbp->mb_top); 95*15359501SGordon Ross if (err) 96*15359501SGordon Ross return (err); 97*15359501SGordon Ross m = mbp->mb_top; 98*15359501SGordon Ross 99*15359501SGordon Ross /* 100*15359501SGordon Ross * Send it. 101*15359501SGordon Ross */ 102*15359501SGordon Ross if (t_snd(ctx->ct_tran_fd, m->m_data, m->m_len, 0) < 0) { 103613a2f6bSGordon Ross if (t_errno == TSYSERR) 104613a2f6bSGordon Ross err = errno; 105613a2f6bSGordon Ross else 106613a2f6bSGordon Ross err = EPROTO; 107613a2f6bSGordon Ross DPRINT("t_snd: t_errno %d, err %d", t_errno, err); 108613a2f6bSGordon Ross return (err); 109613a2f6bSGordon Ross } 110*15359501SGordon Ross 111613a2f6bSGordon Ross return (0); 112613a2f6bSGordon Ross } 113613a2f6bSGordon Ross 114613a2f6bSGordon Ross /* 115613a2f6bSGordon Ross * Receive a data message. Discard anything else. 116613a2f6bSGordon Ross * Caller must deal with EAGAIN, EINTR. 117613a2f6bSGordon Ross */ 118613a2f6bSGordon Ross int 119613a2f6bSGordon Ross smb_ssn_recv(struct smb_ctx *ctx, struct mbdata *mbp) 120613a2f6bSGordon Ross { 121613a2f6bSGordon Ross int err, mtype, mlen; 122613a2f6bSGordon Ross err = nb_ssn_recv(ctx, mbp, &mtype, &mlen); 123613a2f6bSGordon Ross if (err) 124613a2f6bSGordon Ross return (err); 125613a2f6bSGordon Ross if (mtype != NB_SSN_MESSAGE) { 126613a2f6bSGordon Ross DPRINT("discard type 0x%x", mtype); 127613a2f6bSGordon Ross mb_done(mbp); 128613a2f6bSGordon Ross return (EAGAIN); 129613a2f6bSGordon Ross } 130613a2f6bSGordon Ross if (mlen == 0) { 131613a2f6bSGordon Ross DPRINT("zero length"); 132613a2f6bSGordon Ross mb_done(mbp); 133613a2f6bSGordon Ross return (EAGAIN); 134613a2f6bSGordon Ross } 135613a2f6bSGordon Ross 136613a2f6bSGordon Ross return (0); 137613a2f6bSGordon Ross } 138613a2f6bSGordon Ross 139613a2f6bSGordon Ross /* 140613a2f6bSGordon Ross * Receive a NetBIOS message, any type. 141613a2f6bSGordon Ross * Give caller type and length. 142613a2f6bSGordon Ross */ 143613a2f6bSGordon Ross static int 144613a2f6bSGordon Ross nb_ssn_recv(struct smb_ctx *ctx, struct mbdata *mb, 145613a2f6bSGordon Ross int *mtype, int *mlen) 146613a2f6bSGordon Ross { 147613a2f6bSGordon Ross char *buf; 148613a2f6bSGordon Ross uint32_t hdr, hdrbuf; 149613a2f6bSGordon Ross int cnt, len, err, moreflag; 150613a2f6bSGordon Ross int fd = ctx->ct_tran_fd; 151613a2f6bSGordon Ross int tmo = smb_recv_timeout * 1000; 152613a2f6bSGordon Ross 153613a2f6bSGordon Ross /* 154613a2f6bSGordon Ross * Start by getting the header 155613a2f6bSGordon Ross * (four bytes) 156613a2f6bSGordon Ross */ 157613a2f6bSGordon Ross if ((err = nb_ssn_pollin(ctx, tmo)) != 0) { 158613a2f6bSGordon Ross DPRINT("pollin err %d", err); 159613a2f6bSGordon Ross return (err); 160613a2f6bSGordon Ross } 161613a2f6bSGordon Ross moreflag = 0; 162613a2f6bSGordon Ross cnt = t_rcv(fd, &hdrbuf, sizeof (hdrbuf), &moreflag); 163613a2f6bSGordon Ross if (cnt < 0) { 164613a2f6bSGordon Ross err = get_xti_err(fd); 165613a2f6bSGordon Ross DPRINT("t_errno %d err %d", t_errno, err); 166613a2f6bSGordon Ross return (err); 167613a2f6bSGordon Ross } 168613a2f6bSGordon Ross 169613a2f6bSGordon Ross if (cnt != sizeof (hdrbuf)) { 170613a2f6bSGordon Ross DPRINT("hdr cnt %d", cnt); 171613a2f6bSGordon Ross return (EPROTO); 172613a2f6bSGordon Ross } 173613a2f6bSGordon Ross 174613a2f6bSGordon Ross /* 175613a2f6bSGordon Ross * Decode the header, get the length. 176613a2f6bSGordon Ross */ 177613a2f6bSGordon Ross hdr = ntohl(hdrbuf); 178613a2f6bSGordon Ross *mtype = (hdr >> 24) & 0xff; 179613a2f6bSGordon Ross *mlen = hdr & 0xffffff; 180613a2f6bSGordon Ross 181613a2f6bSGordon Ross if (mlen == 0) 182613a2f6bSGordon Ross return (0); 183613a2f6bSGordon Ross 184613a2f6bSGordon Ross /* 185613a2f6bSGordon Ross * Get a message buffer, read the payload 186613a2f6bSGordon Ross */ 18702d09e03SGordon Ross if ((err = mb_init_sz(mb, *mlen)) != 0) 188613a2f6bSGordon Ross return (err); 189613a2f6bSGordon Ross buf = mb->mb_top->m_data; 190613a2f6bSGordon Ross len = *mlen; 191613a2f6bSGordon Ross while (len > 0) { 192613a2f6bSGordon Ross if (!moreflag) { 193613a2f6bSGordon Ross if ((err = nb_ssn_pollin(ctx, tmo)) != 0) { 194613a2f6bSGordon Ross DPRINT("pollin err %d", err); 195613a2f6bSGordon Ross return (err); 196613a2f6bSGordon Ross } 197613a2f6bSGordon Ross } 198613a2f6bSGordon Ross 199613a2f6bSGordon Ross moreflag = 0; 200613a2f6bSGordon Ross cnt = t_rcv(fd, buf, len, &moreflag); 201613a2f6bSGordon Ross if (cnt < 0) { 202613a2f6bSGordon Ross err = get_xti_err(fd); 203613a2f6bSGordon Ross DPRINT("t_errno %d err %d", t_errno, err); 204613a2f6bSGordon Ross return (err); 205613a2f6bSGordon Ross } 206613a2f6bSGordon Ross buf += cnt; 207613a2f6bSGordon Ross len -= cnt; 208613a2f6bSGordon Ross } 209613a2f6bSGordon Ross mb->mb_top->m_len = *mlen; 210613a2f6bSGordon Ross mb->mb_count = *mlen; 211613a2f6bSGordon Ross 212613a2f6bSGordon Ross return (0); 213613a2f6bSGordon Ross } 214613a2f6bSGordon Ross 215613a2f6bSGordon Ross int 216613a2f6bSGordon Ross get_xti_err(int fd) 217613a2f6bSGordon Ross { 218613a2f6bSGordon Ross int look; 219613a2f6bSGordon Ross if (t_errno == TSYSERR) 220613a2f6bSGordon Ross return (errno); 221613a2f6bSGordon Ross 222613a2f6bSGordon Ross if (t_errno == TLOOK) { 223613a2f6bSGordon Ross look = t_look(fd); 224613a2f6bSGordon Ross switch (look) { 225613a2f6bSGordon Ross case T_DISCONNECT: 226613a2f6bSGordon Ross (void) t_rcvdis(fd, NULL); 227613a2f6bSGordon Ross (void) t_snddis(fd, NULL); 228613a2f6bSGordon Ross return (ECONNRESET); 229613a2f6bSGordon Ross case T_ORDREL: 230613a2f6bSGordon Ross /* Received orderly release indication */ 231613a2f6bSGordon Ross (void) t_rcvrel(fd); 232613a2f6bSGordon Ross /* Send orderly release indicator */ 233613a2f6bSGordon Ross (void) t_sndrel(fd); 234613a2f6bSGordon Ross return (ECONNRESET); 235613a2f6bSGordon Ross } 236613a2f6bSGordon Ross } 237613a2f6bSGordon Ross return (EPROTO); 238613a2f6bSGordon Ross } 239613a2f6bSGordon Ross 240613a2f6bSGordon Ross /* 241613a2f6bSGordon Ross * Wait for data we can receive. 242613a2f6bSGordon Ross * Timeout is mSec., as for poll(2) 243613a2f6bSGordon Ross */ 244613a2f6bSGordon Ross static int 245613a2f6bSGordon Ross nb_ssn_pollin(struct smb_ctx *ctx, int tmo) 246613a2f6bSGordon Ross { 247613a2f6bSGordon Ross struct pollfd pfd[1]; 248613a2f6bSGordon Ross int cnt, err; 249613a2f6bSGordon Ross 250613a2f6bSGordon Ross pfd[0].fd = ctx->ct_tran_fd; 251613a2f6bSGordon Ross pfd[0].events = POLLIN | POLLPRI; 252613a2f6bSGordon Ross pfd[0].revents = 0; 253613a2f6bSGordon Ross cnt = poll(pfd, 1, tmo); 254613a2f6bSGordon Ross switch (cnt) { 255613a2f6bSGordon Ross case 0: 256613a2f6bSGordon Ross err = ETIME; 257613a2f6bSGordon Ross break; 258613a2f6bSGordon Ross case -1: 259613a2f6bSGordon Ross err = errno; 260613a2f6bSGordon Ross break; 261613a2f6bSGordon Ross default: 262613a2f6bSGordon Ross err = 0; 263613a2f6bSGordon Ross break; 264613a2f6bSGordon Ross } 265613a2f6bSGordon Ross return (err); 266613a2f6bSGordon Ross } 267613a2f6bSGordon Ross 268613a2f6bSGordon Ross /* 269613a2f6bSGordon Ross * Send a NetBIOS session request and 270613a2f6bSGordon Ross * wait for the response. 271613a2f6bSGordon Ross */ 272613a2f6bSGordon Ross int 273613a2f6bSGordon Ross nb_ssn_request(struct smb_ctx *ctx, char *srvname) 274613a2f6bSGordon Ross { 275613a2f6bSGordon Ross struct mbdata req, res; 276613a2f6bSGordon Ross struct nb_name lcl, srv; 277613a2f6bSGordon Ross int err, mtype, mlen; 278613a2f6bSGordon Ross char *ucwks; 279613a2f6bSGordon Ross 280613a2f6bSGordon Ross bzero(&req, sizeof (req)); 281613a2f6bSGordon Ross bzero(&res, sizeof (res)); 282613a2f6bSGordon Ross 28302d09e03SGordon Ross if ((err = mb_init(&req)) != 0) 284613a2f6bSGordon Ross goto errout; 285613a2f6bSGordon Ross 286613a2f6bSGordon Ross ucwks = utf8_str_toupper(ctx->ct_locname); 287613a2f6bSGordon Ross if (ucwks == NULL) { 288613a2f6bSGordon Ross err = ENOMEM; 289613a2f6bSGordon Ross goto errout; 290613a2f6bSGordon Ross } 291613a2f6bSGordon Ross 292613a2f6bSGordon Ross /* Local NB name. */ 293613a2f6bSGordon Ross snprintf(lcl.nn_name, NB_NAMELEN, "%-15.15s", ucwks); 294613a2f6bSGordon Ross lcl.nn_type = NBT_WKSTA; 295613a2f6bSGordon Ross lcl.nn_scope = ctx->ct_nb->nb_scope; 296613a2f6bSGordon Ross 297613a2f6bSGordon Ross /* Server NB name */ 298613a2f6bSGordon Ross snprintf(srv.nn_name, NB_NAMELEN, "%-15.15s", srvname); 299613a2f6bSGordon Ross srv.nn_type = NBT_SERVER; 300613a2f6bSGordon Ross srv.nn_scope = ctx->ct_nb->nb_scope; 301613a2f6bSGordon Ross 302613a2f6bSGordon Ross /* 303613a2f6bSGordon Ross * Build the request. Header is prepended later. 304613a2f6bSGordon Ross */ 305613a2f6bSGordon Ross if ((err = nb_name_encode(&req, &srv)) != 0) 306613a2f6bSGordon Ross goto errout; 307613a2f6bSGordon Ross if ((err = nb_name_encode(&req, &lcl)) != 0) 308613a2f6bSGordon Ross goto errout; 309613a2f6bSGordon Ross 310613a2f6bSGordon Ross /* 311613a2f6bSGordon Ross * Send it, wait for the reply. 312613a2f6bSGordon Ross */ 313613a2f6bSGordon Ross err = nb_ssn_send(ctx, &req, NB_SSN_REQUEST, req.mb_count); 314613a2f6bSGordon Ross if (err) { 315613a2f6bSGordon Ross DPRINT("send, err %d", err); 316613a2f6bSGordon Ross goto errout; 317613a2f6bSGordon Ross } 318613a2f6bSGordon Ross err = nb_ssn_recv(ctx, &res, &mtype, &mlen); 319613a2f6bSGordon Ross if (err) { 320613a2f6bSGordon Ross DPRINT("recv, err %d", err); 321613a2f6bSGordon Ross goto errout; 322613a2f6bSGordon Ross } 323613a2f6bSGordon Ross 324613a2f6bSGordon Ross if (mtype != NB_SSN_POSRESP) { 325613a2f6bSGordon Ross DPRINT("recv, mtype 0x%x", mtype); 326613a2f6bSGordon Ross err = ECONNREFUSED; 327613a2f6bSGordon Ross goto errout; 328613a2f6bSGordon Ross } 329613a2f6bSGordon Ross 330613a2f6bSGordon Ross return (0); 331613a2f6bSGordon Ross 332613a2f6bSGordon Ross errout: 333613a2f6bSGordon Ross mb_done(&res); 334613a2f6bSGordon Ross mb_done(&req); 335613a2f6bSGordon Ross return (err); 336613a2f6bSGordon Ross } 337