110023SGordon.Ross@Sun.COM /* 210023SGordon.Ross@Sun.COM * CDDL HEADER START 310023SGordon.Ross@Sun.COM * 410023SGordon.Ross@Sun.COM * The contents of this file are subject to the terms of the 510023SGordon.Ross@Sun.COM * Common Development and Distribution License (the "License"). 610023SGordon.Ross@Sun.COM * You may not use this file except in compliance with the License. 710023SGordon.Ross@Sun.COM * 810023SGordon.Ross@Sun.COM * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 910023SGordon.Ross@Sun.COM * or http://www.opensolaris.org/os/licensing. 1010023SGordon.Ross@Sun.COM * See the License for the specific language governing permissions 1110023SGordon.Ross@Sun.COM * and limitations under the License. 1210023SGordon.Ross@Sun.COM * 1310023SGordon.Ross@Sun.COM * When distributing Covered Code, include this CDDL HEADER in each 1410023SGordon.Ross@Sun.COM * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 1510023SGordon.Ross@Sun.COM * If applicable, add the following below this CDDL HEADER, with the 1610023SGordon.Ross@Sun.COM * fields enclosed by brackets "[]" replaced with your own identifying 1710023SGordon.Ross@Sun.COM * information: Portions Copyright [yyyy] [name of copyright owner] 1810023SGordon.Ross@Sun.COM * 1910023SGordon.Ross@Sun.COM * CDDL HEADER END 2010023SGordon.Ross@Sun.COM */ 2110023SGordon.Ross@Sun.COM 2210023SGordon.Ross@Sun.COM /* 2310023SGordon.Ross@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 2410023SGordon.Ross@Sun.COM * Use is subject to license terms. 2510023SGordon.Ross@Sun.COM */ 2610023SGordon.Ross@Sun.COM 2710023SGordon.Ross@Sun.COM /* 2810023SGordon.Ross@Sun.COM * NetBIOS session service functions 2910023SGordon.Ross@Sun.COM */ 3010023SGordon.Ross@Sun.COM 3110023SGordon.Ross@Sun.COM #include <errno.h> 3210023SGordon.Ross@Sun.COM #include <stdio.h> 3310023SGordon.Ross@Sun.COM #include <stdlib.h> 3410023SGordon.Ross@Sun.COM #include <string.h> 3510023SGordon.Ross@Sun.COM #include <strings.h> 3610023SGordon.Ross@Sun.COM #include <libintl.h> 3710023SGordon.Ross@Sun.COM #include <xti.h> 3810023SGordon.Ross@Sun.COM #include <assert.h> 3910023SGordon.Ross@Sun.COM 4010023SGordon.Ross@Sun.COM #include <sys/types.h> 4110023SGordon.Ross@Sun.COM #include <sys/socket.h> 4210023SGordon.Ross@Sun.COM #include <sys/poll.h> 4310023SGordon.Ross@Sun.COM 4410023SGordon.Ross@Sun.COM #include <netsmb/netbios.h> 4510023SGordon.Ross@Sun.COM #include <netsmb/smb_lib.h> 4610023SGordon.Ross@Sun.COM #include <netsmb/nb_lib.h> 4710023SGordon.Ross@Sun.COM #include <netsmb/mchain.h> 4810023SGordon.Ross@Sun.COM 4910023SGordon.Ross@Sun.COM #include "private.h" 5010023SGordon.Ross@Sun.COM #include "charsets.h" 5110023SGordon.Ross@Sun.COM 5210023SGordon.Ross@Sun.COM static int nb_ssn_send(struct smb_ctx *, struct mbdata *, int, int); 5310023SGordon.Ross@Sun.COM static int nb_ssn_recv(struct smb_ctx *, struct mbdata *, int *, int *); 5410023SGordon.Ross@Sun.COM static int nb_ssn_pollin(struct smb_ctx *, int); 5510023SGordon.Ross@Sun.COM 5610023SGordon.Ross@Sun.COM /* 5710023SGordon.Ross@Sun.COM * Send a data message. 5810023SGordon.Ross@Sun.COM */ 5910023SGordon.Ross@Sun.COM int 6010023SGordon.Ross@Sun.COM smb_ssn_send(struct smb_ctx *ctx, struct mbdata *mbp) 6110023SGordon.Ross@Sun.COM { 6210023SGordon.Ross@Sun.COM return (nb_ssn_send(ctx, mbp, 0, mbp->mb_count)); 6310023SGordon.Ross@Sun.COM } 6410023SGordon.Ross@Sun.COM 6510023SGordon.Ross@Sun.COM /* 6610023SGordon.Ross@Sun.COM * Send a NetBIOS message, after 6710023SGordon.Ross@Sun.COM * prepending the 4-byte header. 6810023SGordon.Ross@Sun.COM */ 6910023SGordon.Ross@Sun.COM static int 7010023SGordon.Ross@Sun.COM nb_ssn_send(struct smb_ctx *ctx, struct mbdata *mbp, 7110023SGordon.Ross@Sun.COM int mtype, int mlen) 7210023SGordon.Ross@Sun.COM { 7310023SGordon.Ross@Sun.COM mbuf_t *m = mbp->mb_top; 7410023SGordon.Ross@Sun.COM int fd = ctx->ct_tran_fd; 7510023SGordon.Ross@Sun.COM int err, flags; 7610023SGordon.Ross@Sun.COM uint32_t hdr, hdrbuf; 7710023SGordon.Ross@Sun.COM 7810023SGordon.Ross@Sun.COM if (m == NULL) 7910023SGordon.Ross@Sun.COM return (EINVAL); 8010023SGordon.Ross@Sun.COM 8110023SGordon.Ross@Sun.COM /* 8210023SGordon.Ross@Sun.COM * Prepend the NetBIOS header. 8310023SGordon.Ross@Sun.COM * Using mbuf trickery to ensure it's 8410023SGordon.Ross@Sun.COM * not separated from the body. 8510023SGordon.Ross@Sun.COM */ 8610023SGordon.Ross@Sun.COM hdr = (mtype << 24) | mlen; 8710023SGordon.Ross@Sun.COM hdrbuf = htonl(hdr); 8810023SGordon.Ross@Sun.COM m->m_data -= 4; 8910023SGordon.Ross@Sun.COM m->m_len += 4; 9010023SGordon.Ross@Sun.COM bcopy(&hdrbuf, m->m_data, 4); 9110023SGordon.Ross@Sun.COM 9210023SGordon.Ross@Sun.COM /* Send it. */ 9310023SGordon.Ross@Sun.COM while (m) { 9410023SGordon.Ross@Sun.COM flags = (m->m_next) ? T_MORE : T_PUSH; 9510023SGordon.Ross@Sun.COM if (t_snd(fd, m->m_data, m->m_len, flags) < 0) { 9610023SGordon.Ross@Sun.COM if (t_errno == TSYSERR) 9710023SGordon.Ross@Sun.COM err = errno; 9810023SGordon.Ross@Sun.COM else 9910023SGordon.Ross@Sun.COM err = EPROTO; 10010023SGordon.Ross@Sun.COM DPRINT("t_snd: t_errno %d, err %d", t_errno, err); 10110023SGordon.Ross@Sun.COM return (err); 10210023SGordon.Ross@Sun.COM } 10310023SGordon.Ross@Sun.COM m = m->m_next; 10410023SGordon.Ross@Sun.COM } 10510023SGordon.Ross@Sun.COM return (0); 10610023SGordon.Ross@Sun.COM } 10710023SGordon.Ross@Sun.COM 10810023SGordon.Ross@Sun.COM /* 10910023SGordon.Ross@Sun.COM * Receive a data message. Discard anything else. 11010023SGordon.Ross@Sun.COM * Caller must deal with EAGAIN, EINTR. 11110023SGordon.Ross@Sun.COM */ 11210023SGordon.Ross@Sun.COM int 11310023SGordon.Ross@Sun.COM smb_ssn_recv(struct smb_ctx *ctx, struct mbdata *mbp) 11410023SGordon.Ross@Sun.COM { 11510023SGordon.Ross@Sun.COM int err, mtype, mlen; 11610023SGordon.Ross@Sun.COM err = nb_ssn_recv(ctx, mbp, &mtype, &mlen); 11710023SGordon.Ross@Sun.COM if (err) 11810023SGordon.Ross@Sun.COM return (err); 11910023SGordon.Ross@Sun.COM if (mtype != NB_SSN_MESSAGE) { 12010023SGordon.Ross@Sun.COM DPRINT("discard type 0x%x", mtype); 12110023SGordon.Ross@Sun.COM mb_done(mbp); 12210023SGordon.Ross@Sun.COM return (EAGAIN); 12310023SGordon.Ross@Sun.COM } 12410023SGordon.Ross@Sun.COM if (mlen == 0) { 12510023SGordon.Ross@Sun.COM DPRINT("zero length"); 12610023SGordon.Ross@Sun.COM mb_done(mbp); 12710023SGordon.Ross@Sun.COM return (EAGAIN); 12810023SGordon.Ross@Sun.COM } 12910023SGordon.Ross@Sun.COM 13010023SGordon.Ross@Sun.COM return (0); 13110023SGordon.Ross@Sun.COM } 13210023SGordon.Ross@Sun.COM 13310023SGordon.Ross@Sun.COM /* 13410023SGordon.Ross@Sun.COM * Receive a NetBIOS message, any type. 13510023SGordon.Ross@Sun.COM * Give caller type and length. 13610023SGordon.Ross@Sun.COM */ 13710023SGordon.Ross@Sun.COM static int 13810023SGordon.Ross@Sun.COM nb_ssn_recv(struct smb_ctx *ctx, struct mbdata *mb, 13910023SGordon.Ross@Sun.COM int *mtype, int *mlen) 14010023SGordon.Ross@Sun.COM { 14110023SGordon.Ross@Sun.COM char *buf; 14210023SGordon.Ross@Sun.COM uint32_t hdr, hdrbuf; 14310023SGordon.Ross@Sun.COM int cnt, len, err, moreflag; 14410023SGordon.Ross@Sun.COM int fd = ctx->ct_tran_fd; 14510023SGordon.Ross@Sun.COM int tmo = smb_recv_timeout * 1000; 14610023SGordon.Ross@Sun.COM 14710023SGordon.Ross@Sun.COM /* 14810023SGordon.Ross@Sun.COM * Start by getting the header 14910023SGordon.Ross@Sun.COM * (four bytes) 15010023SGordon.Ross@Sun.COM */ 15110023SGordon.Ross@Sun.COM if ((err = nb_ssn_pollin(ctx, tmo)) != 0) { 15210023SGordon.Ross@Sun.COM DPRINT("pollin err %d", err); 15310023SGordon.Ross@Sun.COM return (err); 15410023SGordon.Ross@Sun.COM } 15510023SGordon.Ross@Sun.COM moreflag = 0; 15610023SGordon.Ross@Sun.COM cnt = t_rcv(fd, &hdrbuf, sizeof (hdrbuf), &moreflag); 15710023SGordon.Ross@Sun.COM if (cnt < 0) { 15810023SGordon.Ross@Sun.COM err = get_xti_err(fd); 15910023SGordon.Ross@Sun.COM DPRINT("t_errno %d err %d", t_errno, err); 16010023SGordon.Ross@Sun.COM return (err); 16110023SGordon.Ross@Sun.COM } 16210023SGordon.Ross@Sun.COM 16310023SGordon.Ross@Sun.COM if (cnt != sizeof (hdrbuf)) { 16410023SGordon.Ross@Sun.COM DPRINT("hdr cnt %d", cnt); 16510023SGordon.Ross@Sun.COM return (EPROTO); 16610023SGordon.Ross@Sun.COM } 16710023SGordon.Ross@Sun.COM 16810023SGordon.Ross@Sun.COM /* 16910023SGordon.Ross@Sun.COM * Decode the header, get the length. 17010023SGordon.Ross@Sun.COM */ 17110023SGordon.Ross@Sun.COM hdr = ntohl(hdrbuf); 17210023SGordon.Ross@Sun.COM *mtype = (hdr >> 24) & 0xff; 17310023SGordon.Ross@Sun.COM *mlen = hdr & 0xffffff; 17410023SGordon.Ross@Sun.COM 17510023SGordon.Ross@Sun.COM if (mlen == 0) 17610023SGordon.Ross@Sun.COM return (0); 17710023SGordon.Ross@Sun.COM 17810023SGordon.Ross@Sun.COM /* 17910023SGordon.Ross@Sun.COM * Get a message buffer, read the payload 18010023SGordon.Ross@Sun.COM */ 181*11332SGordon.Ross@Sun.COM if ((err = mb_init_sz(mb, *mlen)) != 0) 18210023SGordon.Ross@Sun.COM return (err); 18310023SGordon.Ross@Sun.COM buf = mb->mb_top->m_data; 18410023SGordon.Ross@Sun.COM len = *mlen; 18510023SGordon.Ross@Sun.COM while (len > 0) { 18610023SGordon.Ross@Sun.COM if (!moreflag) { 18710023SGordon.Ross@Sun.COM if ((err = nb_ssn_pollin(ctx, tmo)) != 0) { 18810023SGordon.Ross@Sun.COM DPRINT("pollin err %d", err); 18910023SGordon.Ross@Sun.COM return (err); 19010023SGordon.Ross@Sun.COM } 19110023SGordon.Ross@Sun.COM } 19210023SGordon.Ross@Sun.COM 19310023SGordon.Ross@Sun.COM moreflag = 0; 19410023SGordon.Ross@Sun.COM cnt = t_rcv(fd, buf, len, &moreflag); 19510023SGordon.Ross@Sun.COM if (cnt < 0) { 19610023SGordon.Ross@Sun.COM err = get_xti_err(fd); 19710023SGordon.Ross@Sun.COM DPRINT("t_errno %d err %d", t_errno, err); 19810023SGordon.Ross@Sun.COM return (err); 19910023SGordon.Ross@Sun.COM } 20010023SGordon.Ross@Sun.COM buf += cnt; 20110023SGordon.Ross@Sun.COM len -= cnt; 20210023SGordon.Ross@Sun.COM } 20310023SGordon.Ross@Sun.COM mb->mb_top->m_len = *mlen; 20410023SGordon.Ross@Sun.COM mb->mb_count = *mlen; 20510023SGordon.Ross@Sun.COM 20610023SGordon.Ross@Sun.COM return (0); 20710023SGordon.Ross@Sun.COM } 20810023SGordon.Ross@Sun.COM 20910023SGordon.Ross@Sun.COM int 21010023SGordon.Ross@Sun.COM get_xti_err(int fd) 21110023SGordon.Ross@Sun.COM { 21210023SGordon.Ross@Sun.COM int look; 21310023SGordon.Ross@Sun.COM if (t_errno == TSYSERR) 21410023SGordon.Ross@Sun.COM return (errno); 21510023SGordon.Ross@Sun.COM 21610023SGordon.Ross@Sun.COM if (t_errno == TLOOK) { 21710023SGordon.Ross@Sun.COM look = t_look(fd); 21810023SGordon.Ross@Sun.COM switch (look) { 21910023SGordon.Ross@Sun.COM case T_DISCONNECT: 22010023SGordon.Ross@Sun.COM (void) t_rcvdis(fd, NULL); 22110023SGordon.Ross@Sun.COM (void) t_snddis(fd, NULL); 22210023SGordon.Ross@Sun.COM return (ECONNRESET); 22310023SGordon.Ross@Sun.COM case T_ORDREL: 22410023SGordon.Ross@Sun.COM /* Received orderly release indication */ 22510023SGordon.Ross@Sun.COM (void) t_rcvrel(fd); 22610023SGordon.Ross@Sun.COM /* Send orderly release indicator */ 22710023SGordon.Ross@Sun.COM (void) t_sndrel(fd); 22810023SGordon.Ross@Sun.COM return (ECONNRESET); 22910023SGordon.Ross@Sun.COM } 23010023SGordon.Ross@Sun.COM } 23110023SGordon.Ross@Sun.COM return (EPROTO); 23210023SGordon.Ross@Sun.COM } 23310023SGordon.Ross@Sun.COM 23410023SGordon.Ross@Sun.COM /* 23510023SGordon.Ross@Sun.COM * Wait for data we can receive. 23610023SGordon.Ross@Sun.COM * Timeout is mSec., as for poll(2) 23710023SGordon.Ross@Sun.COM */ 23810023SGordon.Ross@Sun.COM static int 23910023SGordon.Ross@Sun.COM nb_ssn_pollin(struct smb_ctx *ctx, int tmo) 24010023SGordon.Ross@Sun.COM { 24110023SGordon.Ross@Sun.COM struct pollfd pfd[1]; 24210023SGordon.Ross@Sun.COM int cnt, err; 24310023SGordon.Ross@Sun.COM 24410023SGordon.Ross@Sun.COM pfd[0].fd = ctx->ct_tran_fd; 24510023SGordon.Ross@Sun.COM pfd[0].events = POLLIN | POLLPRI; 24610023SGordon.Ross@Sun.COM pfd[0].revents = 0; 24710023SGordon.Ross@Sun.COM cnt = poll(pfd, 1, tmo); 24810023SGordon.Ross@Sun.COM switch (cnt) { 24910023SGordon.Ross@Sun.COM case 0: 25010023SGordon.Ross@Sun.COM err = ETIME; 25110023SGordon.Ross@Sun.COM break; 25210023SGordon.Ross@Sun.COM case -1: 25310023SGordon.Ross@Sun.COM err = errno; 25410023SGordon.Ross@Sun.COM break; 25510023SGordon.Ross@Sun.COM default: 25610023SGordon.Ross@Sun.COM err = 0; 25710023SGordon.Ross@Sun.COM break; 25810023SGordon.Ross@Sun.COM } 25910023SGordon.Ross@Sun.COM return (err); 26010023SGordon.Ross@Sun.COM } 26110023SGordon.Ross@Sun.COM 26210023SGordon.Ross@Sun.COM /* 26310023SGordon.Ross@Sun.COM * Send a NetBIOS session request and 26410023SGordon.Ross@Sun.COM * wait for the response. 26510023SGordon.Ross@Sun.COM */ 26610023SGordon.Ross@Sun.COM int 26710023SGordon.Ross@Sun.COM nb_ssn_request(struct smb_ctx *ctx, char *srvname) 26810023SGordon.Ross@Sun.COM { 26910023SGordon.Ross@Sun.COM struct mbdata req, res; 27010023SGordon.Ross@Sun.COM struct nb_name lcl, srv; 27110023SGordon.Ross@Sun.COM int err, mtype, mlen; 27210023SGordon.Ross@Sun.COM char *ucwks; 27310023SGordon.Ross@Sun.COM 27410023SGordon.Ross@Sun.COM bzero(&req, sizeof (req)); 27510023SGordon.Ross@Sun.COM bzero(&res, sizeof (res)); 27610023SGordon.Ross@Sun.COM 277*11332SGordon.Ross@Sun.COM if ((err = mb_init(&req)) != 0) 27810023SGordon.Ross@Sun.COM goto errout; 27910023SGordon.Ross@Sun.COM 28010023SGordon.Ross@Sun.COM ucwks = utf8_str_toupper(ctx->ct_locname); 28110023SGordon.Ross@Sun.COM if (ucwks == NULL) { 28210023SGordon.Ross@Sun.COM err = ENOMEM; 28310023SGordon.Ross@Sun.COM goto errout; 28410023SGordon.Ross@Sun.COM } 28510023SGordon.Ross@Sun.COM 28610023SGordon.Ross@Sun.COM /* Local NB name. */ 28710023SGordon.Ross@Sun.COM snprintf(lcl.nn_name, NB_NAMELEN, "%-15.15s", ucwks); 28810023SGordon.Ross@Sun.COM lcl.nn_type = NBT_WKSTA; 28910023SGordon.Ross@Sun.COM lcl.nn_scope = ctx->ct_nb->nb_scope; 29010023SGordon.Ross@Sun.COM 29110023SGordon.Ross@Sun.COM /* Server NB name */ 29210023SGordon.Ross@Sun.COM snprintf(srv.nn_name, NB_NAMELEN, "%-15.15s", srvname); 29310023SGordon.Ross@Sun.COM srv.nn_type = NBT_SERVER; 29410023SGordon.Ross@Sun.COM srv.nn_scope = ctx->ct_nb->nb_scope; 29510023SGordon.Ross@Sun.COM 29610023SGordon.Ross@Sun.COM /* 29710023SGordon.Ross@Sun.COM * Build the request. Header is prepended later. 29810023SGordon.Ross@Sun.COM */ 29910023SGordon.Ross@Sun.COM if ((err = nb_name_encode(&req, &srv)) != 0) 30010023SGordon.Ross@Sun.COM goto errout; 30110023SGordon.Ross@Sun.COM if ((err = nb_name_encode(&req, &lcl)) != 0) 30210023SGordon.Ross@Sun.COM goto errout; 30310023SGordon.Ross@Sun.COM 30410023SGordon.Ross@Sun.COM /* 30510023SGordon.Ross@Sun.COM * Send it, wait for the reply. 30610023SGordon.Ross@Sun.COM */ 30710023SGordon.Ross@Sun.COM err = nb_ssn_send(ctx, &req, NB_SSN_REQUEST, req.mb_count); 30810023SGordon.Ross@Sun.COM if (err) { 30910023SGordon.Ross@Sun.COM DPRINT("send, err %d", err); 31010023SGordon.Ross@Sun.COM goto errout; 31110023SGordon.Ross@Sun.COM } 31210023SGordon.Ross@Sun.COM err = nb_ssn_recv(ctx, &res, &mtype, &mlen); 31310023SGordon.Ross@Sun.COM if (err) { 31410023SGordon.Ross@Sun.COM DPRINT("recv, err %d", err); 31510023SGordon.Ross@Sun.COM goto errout; 31610023SGordon.Ross@Sun.COM } 31710023SGordon.Ross@Sun.COM 31810023SGordon.Ross@Sun.COM if (mtype != NB_SSN_POSRESP) { 31910023SGordon.Ross@Sun.COM DPRINT("recv, mtype 0x%x", mtype); 32010023SGordon.Ross@Sun.COM err = ECONNREFUSED; 32110023SGordon.Ross@Sun.COM goto errout; 32210023SGordon.Ross@Sun.COM } 32310023SGordon.Ross@Sun.COM 32410023SGordon.Ross@Sun.COM return (0); 32510023SGordon.Ross@Sun.COM 32610023SGordon.Ross@Sun.COM errout: 32710023SGordon.Ross@Sun.COM mb_done(&res); 32810023SGordon.Ross@Sun.COM mb_done(&req); 32910023SGordon.Ross@Sun.COM return (err); 33010023SGordon.Ross@Sun.COM } 331