xref: /illumos-gate/usr/src/lib/libmlrpc/common/ndr_auth.c (revision d4039345c8fe6e54a31d17d91e86e393fdcf401b)
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  */
15 
16 #include <libmlrpc.h>
17 #include <sys/sysmacros.h>
18 #include <strings.h>
19 
20 /*
21  * Initializes the sec_trailer (ndr_sec_t).
22  * The actual token is allocated and set later (in the SSP).
23  */
24 int
25 ndr_add_auth_token(ndr_auth_ctx_t *ctx, ndr_xa_t *mxa)
26 {
27 	ndr_stream_t *nds = &mxa->send_nds;
28 	ndr_sec_t *secp = &mxa->send_auth;
29 
30 	secp->auth_type = ctx->auth_type;
31 	secp->auth_level = ctx->auth_level;
32 	secp->auth_rsvd = 0;
33 
34 	/*
35 	 * [MS-RPCE] 2.2.2.12 "Authentication Tokens"
36 	 * auth_pad_len aligns the packet to 16 bytes.
37 	 */
38 	secp->auth_pad_len = P2ROUNDUP(nds->pdu_scan_offset, 16) -
39 	    nds->pdu_scan_offset;
40 	if (NDS_PAD_PDU(nds, nds->pdu_scan_offset,
41 	    secp->auth_pad_len, NULL) == 0)
42 		return (NDR_DRC_FAULT_SEC_ENCODE_TOO_BIG);
43 
44 	/* PAD_PDU doesn't adjust scan_offset */
45 	nds->pdu_scan_offset += secp->auth_pad_len;
46 	nds->pdu_body_size = nds->pdu_scan_offset -
47 	    nds->pdu_body_offset;
48 
49 	secp->auth_context_id = ctx->auth_context_id;
50 	return (NDR_DRC_OK);
51 }
52 
53 /*
54  * Does gss_init_sec_context (or equivalent) and creates
55  * the sec_trailer and the auth token.
56  *
57  * Used during binds (and alter context).
58  *
59  * Currently, only NETLOGON auth with Integrity protection is implemented.
60  */
61 int
62 ndr_add_sec_context(ndr_auth_ctx_t *ctx, ndr_xa_t *mxa)
63 {
64 	int rc;
65 
66 	if (ctx->auth_level == NDR_C_AUTHN_NONE ||
67 	    ctx->auth_type == NDR_C_AUTHN_NONE)
68 		return (NDR_DRC_OK);
69 
70 	if (ctx->auth_type != NDR_C_AUTHN_GSS_NETLOGON)
71 		return (NDR_DRC_FAULT_SEC_TYPE_UNIMPLEMENTED);
72 
73 	if (ctx->auth_level != NDR_C_AUTHN_LEVEL_PKT_INTEGRITY)
74 		return (NDR_DRC_FAULT_SEC_LEVEL_UNIMPLEMENTED);
75 
76 	if ((rc = ndr_add_auth_token(ctx, mxa)) != 0)
77 		return (rc);
78 
79 	return (ctx->auth_ops.nao_init(ctx->auth_ctx, mxa));
80 }
81 
82 /*
83  * Does response-side gss_init_sec_context (or equivalent) and validates
84  * the sec_trailer and the auth token.
85  *
86  * Used during bind (and alter context) ACKs.
87  */
88 int
89 ndr_recv_sec_context(ndr_auth_ctx_t *ctx, ndr_xa_t *mxa)
90 {
91 	ndr_sec_t *bind_secp = &mxa->send_auth;
92 	ndr_sec_t *ack_secp = &mxa->recv_auth;
93 
94 	if (ctx->auth_level == NDR_C_AUTHN_NONE ||
95 	    ctx->auth_type == NDR_C_AUTHN_NONE) {
96 		if (mxa->recv_hdr.common_hdr.auth_length != 0)
97 			return (NDR_DRC_FAULT_SEC_AUTH_LENGTH_INVALID);
98 		return (NDR_DRC_OK);
99 	} else if (mxa->recv_hdr.common_hdr.auth_length == 0) {
100 		return (NDR_DRC_FAULT_SEC_AUTH_LENGTH_INVALID);
101 	}
102 
103 	if (bind_secp->auth_type != ack_secp->auth_type)
104 		return (NDR_DRC_FAULT_SEC_AUTH_TYPE_INVALID);
105 	if (bind_secp->auth_level != ack_secp->auth_level)
106 		return (NDR_DRC_FAULT_SEC_AUTH_LEVEL_INVALID);
107 
108 	return (ctx->auth_ops.nao_recv(ctx->auth_ctx, mxa));
109 }
110 
111 /*
112  * Does gss_MICEx (or equivalent) and creates
113  * the sec_trailer and the auth token.
114  *
115  * Used upon sending a request (client)/response (server) packet.
116  */
117 int
118 ndr_add_auth(ndr_auth_ctx_t *ctx, ndr_xa_t *mxa)
119 {
120 	int rc;
121 
122 	if (ctx->auth_level == NDR_C_AUTHN_NONE ||
123 	    ctx->auth_type == NDR_C_AUTHN_NONE)
124 		return (NDR_DRC_OK);
125 
126 	if (ctx->auth_type != NDR_C_AUTHN_GSS_NETLOGON)
127 		return (NDR_DRC_FAULT_SEC_TYPE_UNIMPLEMENTED);
128 
129 	if (ctx->auth_level != NDR_C_AUTHN_LEVEL_PKT_INTEGRITY)
130 		return (NDR_DRC_FAULT_SEC_LEVEL_UNIMPLEMENTED);
131 
132 	if ((rc = ndr_add_auth_token(ctx, mxa)) != 0)
133 		return (rc);
134 
135 	return (ctx->auth_ops.nao_sign(ctx->auth_ctx, mxa));
136 }
137 
138 /*
139  * Does gss_VerifyMICEx (or equivalent) and validates
140  * the sec_trailer and the auth token.
141  *
142  * Used upon receiving a request (server)/response (client) packet.
143  *
144  * If auth_verify_resp is B_FALSE, this doesn't verify responses (but
145  * the SSP may still have side-effects).
146  */
147 int
148 ndr_check_auth(ndr_auth_ctx_t *ctx, ndr_xa_t *mxa)
149 {
150 	ndr_sec_t *secp = &mxa->recv_auth;
151 
152 	if (ctx->auth_level == NDR_C_AUTHN_NONE ||
153 	    ctx->auth_type == NDR_C_AUTHN_NONE) {
154 		if (mxa->recv_hdr.common_hdr.auth_length != 0)
155 			return (NDR_DRC_FAULT_SEC_AUTH_LENGTH_INVALID);
156 		return (NDR_DRC_OK);
157 	} else if (mxa->recv_hdr.common_hdr.auth_length == 0) {
158 		return (NDR_DRC_FAULT_SEC_AUTH_LENGTH_INVALID);
159 	}
160 
161 	if (ctx->auth_type != secp->auth_type ||
162 	    ctx->auth_type != NDR_C_AUTHN_GSS_NETLOGON)
163 		return (NDR_DRC_FAULT_SEC_AUTH_TYPE_INVALID);
164 
165 	if (ctx->auth_level != secp->auth_level ||
166 	    ctx->auth_level != NDR_C_AUTHN_LEVEL_PKT_INTEGRITY)
167 		return (NDR_DRC_FAULT_SEC_AUTH_LEVEL_INVALID);
168 
169 	return (ctx->auth_ops.nao_verify(ctx->auth_ctx, mxa,
170 	    ctx->auth_verify_resp));
171 }
172