xref: /illumos-gate/usr/src/lib/libmlrpc/common/ndr_auth.c (revision 0ccfe5834c3b867c1b6c273cae02ec8922bc0fd2)
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