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