1ce8560eeSMatt Barden /*
2ce8560eeSMatt Barden  * This file and its contents are supplied under the terms of the
3ce8560eeSMatt Barden  * Common Development and Distribution License ("CDDL"), version 1.0.
4ce8560eeSMatt Barden  * You may only use this file in accordance with the terms of version
5ce8560eeSMatt Barden  * 1.0 of the CDDL.
6ce8560eeSMatt Barden  *
7ce8560eeSMatt Barden  * A full copy of the text of the CDDL should have accompanied this
8ce8560eeSMatt Barden  * source.  A copy of the CDDL is also available via the Internet at
9ce8560eeSMatt Barden  * http://www.illumos.org/license/CDDL.
10ce8560eeSMatt Barden  */
11ce8560eeSMatt Barden 
12ce8560eeSMatt Barden /*
13ce8560eeSMatt Barden  * Copyright 2020 Tintri by DDN, Inc. All Rights Reserved.
14*0ccfe583SMatt Barden  * Copyright 2023 RackTop Systems, Inc.
15ce8560eeSMatt Barden  */
16ce8560eeSMatt Barden 
17ce8560eeSMatt Barden #include <libmlrpc.h>
18ce8560eeSMatt Barden #include <sys/sysmacros.h>
19ce8560eeSMatt Barden #include <strings.h>
20ce8560eeSMatt Barden 
21ce8560eeSMatt Barden /*
22ce8560eeSMatt Barden  * Initializes the sec_trailer (ndr_sec_t).
23ce8560eeSMatt Barden  * The actual token is allocated and set later (in the SSP).
24ce8560eeSMatt Barden  */
25ce8560eeSMatt Barden int
ndr_add_auth_token(ndr_auth_ctx_t * ctx,ndr_xa_t * mxa)26ce8560eeSMatt Barden ndr_add_auth_token(ndr_auth_ctx_t *ctx, ndr_xa_t *mxa)
27ce8560eeSMatt Barden {
28ce8560eeSMatt Barden 	ndr_stream_t *nds = &mxa->send_nds;
29ce8560eeSMatt Barden 	ndr_sec_t *secp = &mxa->send_auth;
30ce8560eeSMatt Barden 
31ce8560eeSMatt Barden 	secp->auth_type = ctx->auth_type;
32ce8560eeSMatt Barden 	secp->auth_level = ctx->auth_level;
33ce8560eeSMatt Barden 	secp->auth_rsvd = 0;
34ce8560eeSMatt Barden 
35ce8560eeSMatt Barden 	/*
36ce8560eeSMatt Barden 	 * [MS-RPCE] 2.2.2.12 "Authentication Tokens"
37ce8560eeSMatt Barden 	 * auth_pad_len aligns the packet to 16 bytes.
38ce8560eeSMatt Barden 	 */
39ce8560eeSMatt Barden 	secp->auth_pad_len = P2ROUNDUP(nds->pdu_scan_offset, 16) -
40ce8560eeSMatt Barden 	    nds->pdu_scan_offset;
41ce8560eeSMatt Barden 	if (NDS_PAD_PDU(nds, nds->pdu_scan_offset,
42ce8560eeSMatt Barden 	    secp->auth_pad_len, NULL) == 0)
43ce8560eeSMatt Barden 		return (NDR_DRC_FAULT_SEC_ENCODE_TOO_BIG);
44ce8560eeSMatt Barden 
45ce8560eeSMatt Barden 	/* PAD_PDU doesn't adjust scan_offset */
46ce8560eeSMatt Barden 	nds->pdu_scan_offset += secp->auth_pad_len;
47ce8560eeSMatt Barden 	nds->pdu_body_size = nds->pdu_scan_offset -
48ce8560eeSMatt Barden 	    nds->pdu_body_offset;
49ce8560eeSMatt Barden 
50ce8560eeSMatt Barden 	secp->auth_context_id = ctx->auth_context_id;
51ce8560eeSMatt Barden 	return (NDR_DRC_OK);
52ce8560eeSMatt Barden }
53ce8560eeSMatt Barden 
54ce8560eeSMatt Barden /*
55ce8560eeSMatt Barden  * Does gss_init_sec_context (or equivalent) and creates
56ce8560eeSMatt Barden  * the sec_trailer and the auth token.
57ce8560eeSMatt Barden  *
58ce8560eeSMatt Barden  * Used during binds (and alter context).
59ce8560eeSMatt Barden  *
60*0ccfe583SMatt Barden  * Currently, only NETLOGON auth with Integrity/Privacy protection
61*0ccfe583SMatt Barden  * is implemented.
62ce8560eeSMatt Barden  */
63ce8560eeSMatt Barden int
ndr_add_sec_context(ndr_auth_ctx_t * ctx,ndr_xa_t * mxa)64ce8560eeSMatt Barden ndr_add_sec_context(ndr_auth_ctx_t *ctx, ndr_xa_t *mxa)
65ce8560eeSMatt Barden {
66ce8560eeSMatt Barden 	int rc;
67ce8560eeSMatt Barden 
68ce8560eeSMatt Barden 	if (ctx->auth_level == NDR_C_AUTHN_NONE ||
69ce8560eeSMatt Barden 	    ctx->auth_type == NDR_C_AUTHN_NONE)
70ce8560eeSMatt Barden 		return (NDR_DRC_OK);
71ce8560eeSMatt Barden 
72ce8560eeSMatt Barden 	if (ctx->auth_type != NDR_C_AUTHN_GSS_NETLOGON)
73ce8560eeSMatt Barden 		return (NDR_DRC_FAULT_SEC_TYPE_UNIMPLEMENTED);
74ce8560eeSMatt Barden 
75*0ccfe583SMatt Barden 	if (ctx->auth_level != NDR_C_AUTHN_LEVEL_PKT_INTEGRITY &&
76*0ccfe583SMatt Barden 	    ctx->auth_level != NDR_C_AUTHN_LEVEL_PKT_PRIVACY)
77ce8560eeSMatt Barden 		return (NDR_DRC_FAULT_SEC_LEVEL_UNIMPLEMENTED);
78ce8560eeSMatt Barden 
79ce8560eeSMatt Barden 	if ((rc = ndr_add_auth_token(ctx, mxa)) != 0)
80ce8560eeSMatt Barden 		return (rc);
81ce8560eeSMatt Barden 
82ce8560eeSMatt Barden 	return (ctx->auth_ops.nao_init(ctx->auth_ctx, mxa));
83ce8560eeSMatt Barden }
84ce8560eeSMatt Barden 
85ce8560eeSMatt Barden /*
86ce8560eeSMatt Barden  * Does response-side gss_init_sec_context (or equivalent) and validates
87ce8560eeSMatt Barden  * the sec_trailer and the auth token.
88ce8560eeSMatt Barden  *
89ce8560eeSMatt Barden  * Used during bind (and alter context) ACKs.
90ce8560eeSMatt Barden  */
91ce8560eeSMatt Barden int
ndr_recv_sec_context(ndr_auth_ctx_t * ctx,ndr_xa_t * mxa)92ce8560eeSMatt Barden ndr_recv_sec_context(ndr_auth_ctx_t *ctx, ndr_xa_t *mxa)
93ce8560eeSMatt Barden {
94ce8560eeSMatt Barden 	ndr_sec_t *bind_secp = &mxa->send_auth;
95ce8560eeSMatt Barden 	ndr_sec_t *ack_secp = &mxa->recv_auth;
96ce8560eeSMatt Barden 
97ce8560eeSMatt Barden 	if (ctx->auth_level == NDR_C_AUTHN_NONE ||
98ce8560eeSMatt Barden 	    ctx->auth_type == NDR_C_AUTHN_NONE) {
99ce8560eeSMatt Barden 		if (mxa->recv_hdr.common_hdr.auth_length != 0)
100ce8560eeSMatt Barden 			return (NDR_DRC_FAULT_SEC_AUTH_LENGTH_INVALID);
101ce8560eeSMatt Barden 		return (NDR_DRC_OK);
102ce8560eeSMatt Barden 	} else if (mxa->recv_hdr.common_hdr.auth_length == 0) {
103ce8560eeSMatt Barden 		return (NDR_DRC_FAULT_SEC_AUTH_LENGTH_INVALID);
104ce8560eeSMatt Barden 	}
105ce8560eeSMatt Barden 
106ce8560eeSMatt Barden 	if (bind_secp->auth_type != ack_secp->auth_type)
107ce8560eeSMatt Barden 		return (NDR_DRC_FAULT_SEC_AUTH_TYPE_INVALID);
108ce8560eeSMatt Barden 	if (bind_secp->auth_level != ack_secp->auth_level)
109ce8560eeSMatt Barden 		return (NDR_DRC_FAULT_SEC_AUTH_LEVEL_INVALID);
110ce8560eeSMatt Barden 
111ce8560eeSMatt Barden 	return (ctx->auth_ops.nao_recv(ctx->auth_ctx, mxa));
112ce8560eeSMatt Barden }
113ce8560eeSMatt Barden 
114ce8560eeSMatt Barden /*
115ce8560eeSMatt Barden  * Does gss_MICEx (or equivalent) and creates
116ce8560eeSMatt Barden  * the sec_trailer and the auth token.
117ce8560eeSMatt Barden  *
118ce8560eeSMatt Barden  * Used upon sending a request (client)/response (server) packet.
119ce8560eeSMatt Barden  */
120ce8560eeSMatt Barden int
ndr_add_auth(ndr_auth_ctx_t * ctx,ndr_xa_t * mxa)121ce8560eeSMatt Barden ndr_add_auth(ndr_auth_ctx_t *ctx, ndr_xa_t *mxa)
122ce8560eeSMatt Barden {
123ce8560eeSMatt Barden 	int rc;
124ce8560eeSMatt Barden 
125ce8560eeSMatt Barden 	if (ctx->auth_level == NDR_C_AUTHN_NONE ||
126ce8560eeSMatt Barden 	    ctx->auth_type == NDR_C_AUTHN_NONE)
127ce8560eeSMatt Barden 		return (NDR_DRC_OK);
128ce8560eeSMatt Barden 
129ce8560eeSMatt Barden 	if (ctx->auth_type != NDR_C_AUTHN_GSS_NETLOGON)
130ce8560eeSMatt Barden 		return (NDR_DRC_FAULT_SEC_TYPE_UNIMPLEMENTED);
131ce8560eeSMatt Barden 
132*0ccfe583SMatt Barden 	if (ctx->auth_level != NDR_C_AUTHN_LEVEL_PKT_INTEGRITY &&
133*0ccfe583SMatt Barden 	    ctx->auth_level != NDR_C_AUTHN_LEVEL_PKT_PRIVACY)
134ce8560eeSMatt Barden 		return (NDR_DRC_FAULT_SEC_LEVEL_UNIMPLEMENTED);
135ce8560eeSMatt Barden 
136ce8560eeSMatt Barden 	if ((rc = ndr_add_auth_token(ctx, mxa)) != 0)
137ce8560eeSMatt Barden 		return (rc);
138ce8560eeSMatt Barden 
139*0ccfe583SMatt Barden 	if (ctx->auth_level == NDR_C_AUTHN_LEVEL_PKT_PRIVACY)
140*0ccfe583SMatt Barden 		return (ctx->auth_ops.nao_encrypt(ctx->auth_ctx, mxa));
141ce8560eeSMatt Barden 	return (ctx->auth_ops.nao_sign(ctx->auth_ctx, mxa));
142ce8560eeSMatt Barden }
143ce8560eeSMatt Barden 
144ce8560eeSMatt Barden /*
145ce8560eeSMatt Barden  * Does gss_VerifyMICEx (or equivalent) and validates
146ce8560eeSMatt Barden  * the sec_trailer and the auth token.
147ce8560eeSMatt Barden  *
148ce8560eeSMatt Barden  * Used upon receiving a request (server)/response (client) packet.
149ce8560eeSMatt Barden  *
150ce8560eeSMatt Barden  * If auth_verify_resp is B_FALSE, this doesn't verify responses (but
151ce8560eeSMatt Barden  * the SSP may still have side-effects).
152ce8560eeSMatt Barden  */
153ce8560eeSMatt Barden int
ndr_check_auth(ndr_auth_ctx_t * ctx,ndr_xa_t * mxa)154ce8560eeSMatt Barden ndr_check_auth(ndr_auth_ctx_t *ctx, ndr_xa_t *mxa)
155ce8560eeSMatt Barden {
156ce8560eeSMatt Barden 	ndr_sec_t *secp = &mxa->recv_auth;
157ce8560eeSMatt Barden 
158ce8560eeSMatt Barden 	if (ctx->auth_level == NDR_C_AUTHN_NONE ||
159ce8560eeSMatt Barden 	    ctx->auth_type == NDR_C_AUTHN_NONE) {
160ce8560eeSMatt Barden 		if (mxa->recv_hdr.common_hdr.auth_length != 0)
161ce8560eeSMatt Barden 			return (NDR_DRC_FAULT_SEC_AUTH_LENGTH_INVALID);
162ce8560eeSMatt Barden 		return (NDR_DRC_OK);
163ce8560eeSMatt Barden 	} else if (mxa->recv_hdr.common_hdr.auth_length == 0) {
164ce8560eeSMatt Barden 		return (NDR_DRC_FAULT_SEC_AUTH_LENGTH_INVALID);
165ce8560eeSMatt Barden 	}
166ce8560eeSMatt Barden 
167ce8560eeSMatt Barden 	if (ctx->auth_type != secp->auth_type ||
168ce8560eeSMatt Barden 	    ctx->auth_type != NDR_C_AUTHN_GSS_NETLOGON)
169ce8560eeSMatt Barden 		return (NDR_DRC_FAULT_SEC_AUTH_TYPE_INVALID);
170ce8560eeSMatt Barden 
171ce8560eeSMatt Barden 	if (ctx->auth_level != secp->auth_level ||
172*0ccfe583SMatt Barden 	    (ctx->auth_level != NDR_C_AUTHN_LEVEL_PKT_INTEGRITY &&
173*0ccfe583SMatt Barden 	    ctx->auth_level != NDR_C_AUTHN_LEVEL_PKT_PRIVACY))
174ce8560eeSMatt Barden 		return (NDR_DRC_FAULT_SEC_AUTH_LEVEL_INVALID);
175ce8560eeSMatt Barden 
176*0ccfe583SMatt Barden 	if (ctx->auth_level == NDR_C_AUTHN_LEVEL_PKT_PRIVACY)
177*0ccfe583SMatt Barden 		return (ctx->auth_ops.nao_decrypt(ctx->auth_ctx, mxa,
178*0ccfe583SMatt Barden 		    ctx->auth_verify_resp));
179ce8560eeSMatt Barden 	return (ctx->auth_ops.nao_verify(ctx->auth_ctx, mxa,
180ce8560eeSMatt Barden 	    ctx->auth_verify_resp));
181ce8560eeSMatt Barden }
182