summaryrefslogtreecommitdiff
path: root/usr/src/lib/libmlrpc/common/ndr_auth.c
blob: 6976f2b908a5eff13f383ecf8cb9130cc8e1bdd8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
/*
 * This file and its contents are supplied under the terms of the
 * Common Development and Distribution License ("CDDL"), version 1.0.
 * You may only use this file in accordance with the terms of version
 * 1.0 of the CDDL.
 *
 * A full copy of the text of the CDDL should have accompanied this
 * source.  A copy of the CDDL is also available via the Internet at
 * http://www.illumos.org/license/CDDL.
 */

/*
 * Copyright 2020 Tintri by DDN, Inc. All Rights Reserved.
 */

#include <libmlrpc.h>
#include <sys/sysmacros.h>
#include <strings.h>

/*
 * Initializes the sec_trailer (ndr_sec_t).
 * The actual token is allocated and set later (in the SSP).
 */
int
ndr_add_auth_token(ndr_auth_ctx_t *ctx, ndr_xa_t *mxa)
{
	ndr_stream_t *nds = &mxa->send_nds;
	ndr_sec_t *secp = &mxa->send_auth;

	secp->auth_type = ctx->auth_type;
	secp->auth_level = ctx->auth_level;
	secp->auth_rsvd = 0;

	/*
	 * [MS-RPCE] 2.2.2.12 "Authentication Tokens"
	 * auth_pad_len aligns the packet to 16 bytes.
	 */
	secp->auth_pad_len = P2ROUNDUP(nds->pdu_scan_offset, 16) -
	    nds->pdu_scan_offset;
	if (NDS_PAD_PDU(nds, nds->pdu_scan_offset,
	    secp->auth_pad_len, NULL) == 0)
		return (NDR_DRC_FAULT_SEC_ENCODE_TOO_BIG);

	/* PAD_PDU doesn't adjust scan_offset */
	nds->pdu_scan_offset += secp->auth_pad_len;
	nds->pdu_body_size = nds->pdu_scan_offset -
	    nds->pdu_body_offset;

	secp->auth_context_id = ctx->auth_context_id;
	return (NDR_DRC_OK);
}

/*
 * Does gss_init_sec_context (or equivalent) and creates
 * the sec_trailer and the auth token.
 *
 * Used during binds (and alter context).
 *
 * Currently, only NETLOGON auth with Integrity protection is implemented.
 */
int
ndr_add_sec_context(ndr_auth_ctx_t *ctx, ndr_xa_t *mxa)
{
	int rc;

	if (ctx->auth_level == NDR_C_AUTHN_NONE ||
	    ctx->auth_type == NDR_C_AUTHN_NONE)
		return (NDR_DRC_OK);

	if (ctx->auth_type != NDR_C_AUTHN_GSS_NETLOGON)
		return (NDR_DRC_FAULT_SEC_TYPE_UNIMPLEMENTED);

	if (ctx->auth_level != NDR_C_AUTHN_LEVEL_PKT_INTEGRITY)
		return (NDR_DRC_FAULT_SEC_LEVEL_UNIMPLEMENTED);

	if ((rc = ndr_add_auth_token(ctx, mxa)) != 0)
		return (rc);

	return (ctx->auth_ops.nao_init(ctx->auth_ctx, mxa));
}

/*
 * Does response-side gss_init_sec_context (or equivalent) and validates
 * the sec_trailer and the auth token.
 *
 * Used during bind (and alter context) ACKs.
 */
int
ndr_recv_sec_context(ndr_auth_ctx_t *ctx, ndr_xa_t *mxa)
{
	ndr_sec_t *bind_secp = &mxa->send_auth;
	ndr_sec_t *ack_secp = &mxa->recv_auth;

	if (ctx->auth_level == NDR_C_AUTHN_NONE ||
	    ctx->auth_type == NDR_C_AUTHN_NONE) {
		if (mxa->recv_hdr.common_hdr.auth_length != 0)
			return (NDR_DRC_FAULT_SEC_AUTH_LENGTH_INVALID);
		return (NDR_DRC_OK);
	} else if (mxa->recv_hdr.common_hdr.auth_length == 0) {
		return (NDR_DRC_FAULT_SEC_AUTH_LENGTH_INVALID);
	}

	if (bind_secp->auth_type != ack_secp->auth_type)
		return (NDR_DRC_FAULT_SEC_AUTH_TYPE_INVALID);
	if (bind_secp->auth_level != ack_secp->auth_level)
		return (NDR_DRC_FAULT_SEC_AUTH_LEVEL_INVALID);

	return (ctx->auth_ops.nao_recv(ctx->auth_ctx, mxa));
}

/*
 * Does gss_MICEx (or equivalent) and creates
 * the sec_trailer and the auth token.
 *
 * Used upon sending a request (client)/response (server) packet.
 */
int
ndr_add_auth(ndr_auth_ctx_t *ctx, ndr_xa_t *mxa)
{
	int rc;

	if (ctx->auth_level == NDR_C_AUTHN_NONE ||
	    ctx->auth_type == NDR_C_AUTHN_NONE)
		return (NDR_DRC_OK);

	if (ctx->auth_type != NDR_C_AUTHN_GSS_NETLOGON)
		return (NDR_DRC_FAULT_SEC_TYPE_UNIMPLEMENTED);

	if (ctx->auth_level != NDR_C_AUTHN_LEVEL_PKT_INTEGRITY)
		return (NDR_DRC_FAULT_SEC_LEVEL_UNIMPLEMENTED);

	if ((rc = ndr_add_auth_token(ctx, mxa)) != 0)
		return (rc);

	return (ctx->auth_ops.nao_sign(ctx->auth_ctx, mxa));
}

/*
 * Does gss_VerifyMICEx (or equivalent) and validates
 * the sec_trailer and the auth token.
 *
 * Used upon receiving a request (server)/response (client) packet.
 *
 * If auth_verify_resp is B_FALSE, this doesn't verify responses (but
 * the SSP may still have side-effects).
 */
int
ndr_check_auth(ndr_auth_ctx_t *ctx, ndr_xa_t *mxa)
{
	ndr_sec_t *secp = &mxa->recv_auth;

	if (ctx->auth_level == NDR_C_AUTHN_NONE ||
	    ctx->auth_type == NDR_C_AUTHN_NONE) {
		if (mxa->recv_hdr.common_hdr.auth_length != 0)
			return (NDR_DRC_FAULT_SEC_AUTH_LENGTH_INVALID);
		return (NDR_DRC_OK);
	} else if (mxa->recv_hdr.common_hdr.auth_length == 0) {
		return (NDR_DRC_FAULT_SEC_AUTH_LENGTH_INVALID);
	}

	if (ctx->auth_type != secp->auth_type ||
	    ctx->auth_type != NDR_C_AUTHN_GSS_NETLOGON)
		return (NDR_DRC_FAULT_SEC_AUTH_TYPE_INVALID);

	if (ctx->auth_level != secp->auth_level ||
	    ctx->auth_level != NDR_C_AUTHN_LEVEL_PKT_INTEGRITY)
		return (NDR_DRC_FAULT_SEC_AUTH_LEVEL_INVALID);

	return (ctx->auth_ops.nao_verify(ctx->auth_ctx, mxa,
	    ctx->auth_verify_resp));
}