xref: /onnv-gate/usr/src/lib/libsmbfs/smb/nb_ssn.c (revision 11332:ed3411181494)
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