4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
24 * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
25 */
26
27 /*
28 * NETR SamLogon and SamLogoff RPC client functions.
29 */
30
31 #include <stdio.h>
32 #include <strings.h>
33 #include <stdlib.h>
34 #include <time.h>
35 #include <alloca.h>
36 #include <unistd.h>
37 #include <netdb.h>
38 #include <thread.h>
39
40 #include <smbsrv/libsmb.h>
41 #include <smbsrv/libmlrpc.h>
42 #include <smbsrv/libmlsvc.h>
43 #include <smbsrv/ndl/netlogon.ndl>
44 #include <smbsrv/netrauth.h>
45 #include <smbsrv/smbinfo.h>
46 #include <smbsrv/smb_token.h>
47 #include <mlsvc.h>
48
49 #define NETLOGON_ATTEMPTS 2
50
51 static uint32_t netlogon_logon(smb_logon_t *, smb_token_t *);
52 static uint32_t netr_server_samlogon(mlsvc_handle_t *, netr_info_t *, char *,
53 smb_logon_t *, smb_token_t *);
54 static void netr_invalidate_chain(void);
55 static void netr_interactive_samlogon(netr_info_t *, smb_logon_t *,
56 struct netr_logon_info1 *);
57 static void netr_network_samlogon(ndr_heap_t *, netr_info_t *,
58 smb_logon_t *, struct netr_logon_info2 *);
59 static void netr_setup_identity(ndr_heap_t *, smb_logon_t *,
60 netr_logon_id_t *);
61 static boolean_t netr_isadmin(struct netr_validation_info3 *);
62 static uint32_t netr_setup_domain_groups(struct netr_validation_info3 *,
63 smb_ids_t *);
64 static uint32_t netr_setup_token_info3(struct netr_validation_info3 *,
65 smb_token_t *);
66 static uint32_t netr_setup_token_wingrps(struct netr_validation_info3 *,
67 smb_token_t *);
68
69 /*
70 * Shared with netr_auth.c
71 */
72 extern netr_info_t netr_global_info;
73
74 static mutex_t netlogon_mutex;
75 static cond_t netlogon_cv;
76 static boolean_t netlogon_busy = B_FALSE;
77 static boolean_t netlogon_abort = B_FALSE;
78
79 /*
80 * Helper for Kerberos authentication
81 */
82 uint32_t
83 smb_decode_krb5_pac(smb_token_t *token, char *data, uint_t len)
84 {
85 struct krb5_validation_info info;
86 ndr_buf_t *nbuf;
87 uint32_t status = NT_STATUS_NO_MEMORY;
88 int rc;
89
90 bzero(&info, sizeof (info));
91
92 /* Need to keep this until we're done with &info */
93 nbuf = ndr_buf_init(&TYPEINFO(netr_interface));
94 if (nbuf == NULL)
95 goto out;
96
97 rc = ndr_buf_decode(nbuf, NDR_PTYPE_PAC,
98 NETR_OPNUM_decode_krb5_pac, data, len, &info);
99 if (rc != NDR_DRC_OK) {
100 status = RPC_NT_PROTOCOL_ERROR;
101 goto out;
102 }
103
104 status = netr_setup_token_info3(&info.info3, token);
105
106 /* Deal with the "resource groups"? */
107
108
109 out:
110 if (nbuf != NULL)
111 ndr_buf_fini(nbuf);
112
113 return (status);
114 }
115
116 /*
117 * Code factored out of netr_setup_token()
118 */
119 static uint32_t
120 netr_setup_token_info3(struct netr_validation_info3 *info3,
121 smb_token_t *token)
122 {
123 smb_sid_t *domsid;
124
125 domsid = (smb_sid_t *)info3->LogonDomainId;
126
127 token->tkn_user.i_sid = smb_sid_splice(domsid,
128 info3->UserId);
129 if (token->tkn_user.i_sid == NULL)
130 goto errout;
131
132 token->tkn_primary_grp.i_sid = smb_sid_splice(domsid,
133 info3->PrimaryGroupId);
134 if (token->tkn_primary_grp.i_sid == NULL)
135 goto errout;
136
137 if (info3->EffectiveName.str) {
138 token->tkn_account_name =
139 strdup((char *)info3->EffectiveName.str);
140 if (token->tkn_account_name == NULL)
141 goto errout;
142 }
143
144 if (info3->LogonDomainName.str) {
145 token->tkn_domain_name =
146 strdup((char *)info3->LogonDomainName.str);
147 if (token->tkn_domain_name == NULL)
148 goto errout;
149 }
150
151 return (netr_setup_token_wingrps(info3, token));
152 errout:
153 return (NT_STATUS_INSUFF_SERVER_RESOURCES);
154 }
155
156 /*
157 * Abort impending domain logon requests.
158 */
159 void
160 smb_logon_abort(void)
161 {
162 (void) mutex_lock(&netlogon_mutex);
163 if (netlogon_busy && !netlogon_abort)
164 syslog(LOG_DEBUG, "logon abort");
165 netlogon_abort = B_TRUE;
166 (void) cond_broadcast(&netlogon_cv);
167 (void) mutex_unlock(&netlogon_mutex);
168 }
169
170 /*
171 * This is the entry point for authenticating domain users.
172 *
173 * If we are not going to attempt to authenticate the user,
174 * this function must return without updating the status.
175 *
176 * If the user is successfully authenticated, we build an
177 * access token and the status will be NT_STATUS_SUCCESS.
178 * Otherwise, the token contents are invalid.
179 */
180 void
181 smb_logon_domain(smb_logon_t *user_info, smb_token_t *token)
182 {
183 uint32_t status;
184 int i;
185
186 if (user_info->lg_secmode != SMB_SECMODE_DOMAIN)
187 return;
188
189 if (user_info->lg_domain_type == SMB_DOMAIN_LOCAL)
190 return;
191
192 for (i = 0; i < NETLOGON_ATTEMPTS; ++i) {
193 (void) mutex_lock(&netlogon_mutex);
194 while (netlogon_busy && !netlogon_abort)
195 (void) cond_wait(&netlogon_cv, &netlogon_mutex);
196
197 if (netlogon_abort) {
198 (void) mutex_unlock(&netlogon_mutex);
199 user_info->lg_status = NT_STATUS_REQUEST_ABORTED;
200 return;
201 }
202
203 netlogon_busy = B_TRUE;
204 (void) mutex_unlock(&netlogon_mutex);
205
206 status = netlogon_logon(user_info, token);
207
208 (void) mutex_lock(&netlogon_mutex);
209 netlogon_busy = B_FALSE;
210 if (netlogon_abort)
211 status = NT_STATUS_REQUEST_ABORTED;
212 (void) cond_signal(&netlogon_cv);
213 (void) mutex_unlock(&netlogon_mutex);
214
215 if (status != NT_STATUS_CANT_ACCESS_DOMAIN_INFO)
216 break;
217 }
218
219 if (status != NT_STATUS_SUCCESS)
220 syslog(LOG_INFO, "logon[%s\\%s]: %s", user_info->lg_e_domain,
221 user_info->lg_e_username, xlate_nt_status(status));
222
223 user_info->lg_status = status;
224 }
225
226 static uint32_t
227 netlogon_logon(smb_logon_t *user_info, smb_token_t *token)
228 {
229 char resource_domain[SMB_PI_MAX_DOMAIN];
230 char server[MAXHOSTNAMELEN];
231 mlsvc_handle_t netr_handle;
232 smb_domainex_t di;
233 uint32_t status;
234 int retries = 0;
235
236 (void) smb_getdomainname(resource_domain, SMB_PI_MAX_DOMAIN);
237
238 /* Avoid interfering with DC discovery. */
239 if (smb_ddiscover_wait() != 0 ||
240 !smb_domain_getinfo(&di)) {
241 netr_invalidate_chain();
242 return (NT_STATUS_CANT_ACCESS_DOMAIN_INFO);
243 }
244
245 do {
246 if (netr_open(di.d_dci.dc_name, di.d_primary.di_nbname,
247 &netr_handle) != 0)
248 return (NT_STATUS_OPEN_FAILED);
249
250 if (di.d_dci.dc_name[0] != '\0' &&
251 (*netr_global_info.server != '\0')) {
252 (void) snprintf(server, sizeof (server),
253 "\\\\%s", di.d_dci.dc_name);
254 if (strncasecmp(netr_global_info.server,
255 server, strlen(server)) != 0)
256 netr_invalidate_chain();
257 }
258
259 if ((netr_global_info.flags & NETR_FLG_VALID) == 0 ||
260 !smb_match_netlogon_seqnum()) {
261 status = netlogon_auth(di.d_dci.dc_name, &netr_handle,
262 NETR_FLG_NULL);
263
264 if (status != 0) {
265 (void) netr_close(&netr_handle);
266 return (NT_STATUS_LOGON_FAILURE);
267 }
268
269 netr_global_info.flags |= NETR_FLG_VALID;
270 }
271
272 status = netr_server_samlogon(&netr_handle,
273 &netr_global_info, di.d_dci.dc_name, user_info, token);
274
275 (void) netr_close(&netr_handle);
276 } while (status == NT_STATUS_INSUFFICIENT_LOGON_INFO && retries++ < 3);
277
278 if (retries >= 3)
279 status = NT_STATUS_LOGON_FAILURE;
280
281 return (status);
282 }
283
284 static uint32_t
285 netr_setup_token(struct netr_validation_info3 *info3, smb_logon_t *user_info,
286 netr_info_t *netr_info, smb_token_t *token)
287 {
288 char *username, *domain;
289 unsigned char rc4key[SMBAUTH_SESSION_KEY_SZ];
290 smb_sid_t *domsid;
291 uint32_t status;
292 char nbdomain[NETBIOS_NAME_SZ];
293
294 domsid = (smb_sid_t *)info3->LogonDomainId;
295
296 token->tkn_user.i_sid = smb_sid_splice(domsid, info3->UserId);
297 if (token->tkn_user.i_sid == NULL)
298 return (NT_STATUS_NO_MEMORY);
299
300 token->tkn_primary_grp.i_sid = smb_sid_splice(domsid,
305 username = (info3->EffectiveName.str)
306 ? (char *)info3->EffectiveName.str : user_info->lg_e_username;
307
308 if (info3->LogonDomainName.str) {
309 domain = (char *)info3->LogonDomainName.str;
310 } else if (*user_info->lg_e_domain != '\0') {
311 domain = user_info->lg_e_domain;
312 } else {
313 (void) smb_getdomainname(nbdomain, sizeof (nbdomain));
314 domain = nbdomain;
315 }
316
317 if (username)
318 token->tkn_account_name = strdup(username);
319 if (domain)
320 token->tkn_domain_name = strdup(domain);
321
322 if (token->tkn_account_name == NULL || token->tkn_domain_name == NULL)
323 return (NT_STATUS_NO_MEMORY);
324
325 status = netr_setup_token_wingrps(info3, token);
326 if (status != NT_STATUS_SUCCESS)
327 return (status);
328
329 /*
330 * The UserSessionKey in NetrSamLogon RPC is obfuscated using the
331 * session key obtained in the NETLOGON credential chain.
332 * An 8 byte session key is zero extended to 16 bytes. This 16 byte
333 * key is the key to the RC4 algorithm. The RC4 byte stream is
334 * exclusively ored with the 16 byte UserSessionKey to recover
335 * the the clear form.
336 */
337 if ((token->tkn_ssnkey.val = malloc(SMBAUTH_SESSION_KEY_SZ)) == NULL)
338 return (NT_STATUS_NO_MEMORY);
339 token->tkn_ssnkey.len = SMBAUTH_SESSION_KEY_SZ;
340 bzero(rc4key, SMBAUTH_SESSION_KEY_SZ);
341 bcopy(netr_info->session_key.key, rc4key, netr_info->session_key.len);
342 bcopy(info3->UserSessionKey.data, token->tkn_ssnkey.val,
343 SMBAUTH_SESSION_KEY_SZ);
344 rand_hash((unsigned char *)token->tkn_ssnkey.val,
694 MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT;
695 identity->logon_id.LowPart = logon_id;
696 identity->logon_id.HighPart = 0;
697
698 ndr_heap_mkvcs(heap, user_info->lg_domain,
699 (ndr_vcstr_t *)&identity->domain_name);
700
701 ndr_heap_mkvcs(heap, user_info->lg_username,
702 (ndr_vcstr_t *)&identity->username);
703
704 /*
705 * Some systems prefix the client workstation name with \\.
706 * It doesn't seem to make any difference whether it's there
707 * or not.
708 */
709 ndr_heap_mkvcs(heap, user_info->lg_workstation,
710 (ndr_vcstr_t *)&identity->workstation);
711 }
712
713 /*
714 * Sets up domain, local and well-known group membership for the given
715 * token. Two assumptions have been made here:
716 *
717 * a) token already contains a valid user SID so that group
718 * memberships can be established
719 *
720 * b) token belongs to a domain user
721 */
722 static uint32_t
723 netr_setup_token_wingrps(struct netr_validation_info3 *info3,
724 smb_token_t *token)
725 {
726 smb_ids_t tkn_grps;
727 uint32_t status;
728
729 tkn_grps.i_cnt = 0;
730 tkn_grps.i_ids = NULL;
731
732 status = netr_setup_domain_groups(info3, &tkn_grps);
733 if (status != NT_STATUS_SUCCESS) {
734 smb_ids_free(&tkn_grps);
735 return (status);
736 }
737
738 status = smb_sam_usr_groups(token->tkn_user.i_sid, &tkn_grps);
739 if (status != NT_STATUS_SUCCESS) {
740 smb_ids_free(&tkn_grps);
741 return (status);
742 }
743
744 if (netr_isadmin(info3))
745 token->tkn_flags |= SMB_ATF_ADMIN;
746
747 status = smb_wka_token_groups(token->tkn_flags, &tkn_grps);
748 if (status == NT_STATUS_SUCCESS)
749 token->tkn_win_grps = tkn_grps;
750 else
751 smb_ids_free(&tkn_grps);
752
753 return (status);
754 }
755
756 /*
757 * Converts groups information in the returned structure by domain controller
758 * (info3) to an internal representation (gids)
759 */
760 static uint32_t
761 netr_setup_domain_groups(struct netr_validation_info3 *info3, smb_ids_t *gids)
762 {
763 smb_sid_t *domain_sid;
764 smb_id_t *ids;
765 int i, total_cnt;
766
767 if ((i = info3->GroupCount) == 0)
768 i++;
769 i += info3->SidCount;
770
771 total_cnt = gids->i_cnt + i;
793 if (ids->i_sid == NULL)
794 return (NT_STATUS_NO_MEMORY);
795
796 ids->i_attrs = 0x7;
797 gids->i_cnt++;
798 ids++;
799 }
800
801 /* Add the extra SIDs */
802 for (i = 0; i < info3->SidCount; i++, gids->i_cnt++, ids++) {
803 ids->i_sid = smb_sid_dup((smb_sid_t *)info3->ExtraSids[i].sid);
804 if (ids->i_sid == NULL)
805 return (NT_STATUS_NO_MEMORY);
806
807 ids->i_attrs = info3->ExtraSids[i].attributes;
808 }
809
810 return (NT_STATUS_SUCCESS);
811 }
812
813 /*
814 * Determines if the given user is the domain Administrator or a
815 * member of Domain Admins
816 */
817 static boolean_t
818 netr_isadmin(struct netr_validation_info3 *info3)
819 {
820 smb_domain_t di;
821 int i;
822
823 if (!smb_domain_lookup_sid((smb_sid_t *)info3->LogonDomainId, &di))
824 return (B_FALSE);
825
826 if (di.di_type != SMB_DOMAIN_PRIMARY)
827 return (B_FALSE);
828
829 if ((info3->UserId == DOMAIN_USER_RID_ADMIN) ||
830 (info3->PrimaryGroupId == DOMAIN_GROUP_RID_ADMINS))
831 return (B_TRUE);
832
|
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
24 * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
25 */
26
27 /*
28 * NETR SamLogon and SamLogoff RPC client functions.
29 */
30
31 #include <stdio.h>
32 #include <strings.h>
33 #include <stdlib.h>
34 #include <time.h>
35 #include <alloca.h>
36 #include <unistd.h>
37 #include <netdb.h>
38 #include <thread.h>
39
40 #include <libmlrpc/libmlrpc.h>
41 #include <smbsrv/libsmb.h>
42 #include <smbsrv/libmlsvc.h>
43 #include <smbsrv/ndl/netlogon.ndl>
44 #include <smbsrv/netrauth.h>
45 #include <smbsrv/smbinfo.h>
46 #include <smbsrv/smb_token.h>
47 #include <mlsvc.h>
48
49 static uint32_t netlogon_logon(smb_logon_t *, smb_token_t *, smb_domainex_t *);
50 static uint32_t netr_server_samlogon(mlsvc_handle_t *, netr_info_t *, char *,
51 smb_logon_t *, smb_token_t *);
52 static void netr_invalidate_chain(void);
53 static void netr_interactive_samlogon(netr_info_t *, smb_logon_t *,
54 struct netr_logon_info1 *);
55 static void netr_network_samlogon(ndr_heap_t *, netr_info_t *,
56 smb_logon_t *, struct netr_logon_info2 *);
57 static void netr_setup_identity(ndr_heap_t *, smb_logon_t *,
58 netr_logon_id_t *);
59 static boolean_t netr_isadmin(struct netr_validation_info3 *);
60 static uint32_t netr_setup_domain_groups(struct netr_validation_info3 *,
61 smb_ids_t *);
62 static uint32_t netr_setup_krb5res_groups(struct krb5_validation_info *,
63 smb_ids_t *);
64 static uint32_t netr_setup_token_wingrps(struct netr_validation_info3 *,
65 smb_token_t *);
66
67 /*
68 * Shared with netr_auth.c
69 */
70 extern netr_info_t netr_global_info;
71
72 static mutex_t netlogon_mutex;
73 static cond_t netlogon_cv;
74 static boolean_t netlogon_busy = B_FALSE;
75 static boolean_t netlogon_abort = B_FALSE;
76
77 /*
78 * Helper for Kerberos authentication
79 */
80 uint32_t
81 smb_decode_krb5_pac(smb_token_t *token, char *data, uint_t len)
82 {
83 struct krb5_validation_info info;
84 ndr_buf_t *nbuf;
85 smb_sid_t *domsid;
86 uint32_t status = NT_STATUS_NO_MEMORY;
87 int rc;
88
89 bzero(&info, sizeof (info));
90
91 /* Need to keep this until we're done with &info */
92 nbuf = ndr_buf_init(&TYPEINFO(netr_interface));
93 if (nbuf == NULL)
94 goto out;
95
96 rc = ndr_buf_decode(nbuf, NDR_PTYPE_PAC,
97 NETR_OPNUM_decode_krb5_pac, data, len, &info);
98 if (rc != NDR_DRC_OK) {
99 status = RPC_NT_PROTOCOL_ERROR;
100 goto out;
101 }
102
103 /*
104 * Copy the decoded info into the token,
105 * similar to netr_setup_token()
106 */
107 domsid = (smb_sid_t *)info.info3.LogonDomainId;
108
109 token->tkn_user.i_sid = smb_sid_splice(domsid,
110 info.info3.UserId);
111 if (token->tkn_user.i_sid == NULL)
112 goto out;
113
114 token->tkn_primary_grp.i_sid = smb_sid_splice(domsid,
115 info.info3.PrimaryGroupId);
116 if (token->tkn_primary_grp.i_sid == NULL)
117 goto out;
118
119 if (info.info3.EffectiveName.str) {
120 token->tkn_account_name =
121 strdup((char *)info.info3.EffectiveName.str);
122 if (token->tkn_account_name == NULL)
123 goto out;
124 }
125
126 if (info.info3.LogonDomainName.str) {
127 token->tkn_domain_name =
128 strdup((char *)info.info3.LogonDomainName.str);
129 if (token->tkn_domain_name == NULL)
130 goto out;
131 }
132
133 status = netr_setup_domain_groups(&info.info3, &token->tkn_win_grps);
134 if (status != NT_STATUS_SUCCESS)
135 goto out;
136
137 if (info.rg_rid_cnt != 0) {
138 status = netr_setup_krb5res_groups(&info, &token->tkn_win_grps);
139 if (status != NT_STATUS_SUCCESS)
140 goto out;
141 }
142
143 status = netr_setup_token_wingrps(&info.info3, token);
144
145 out:
146 if (nbuf != NULL)
147 ndr_buf_fini(nbuf);
148
149 return (status);
150 }
151
152 /*
153 * Abort impending domain logon requests.
154 */
155 void
156 smb_logon_abort(void)
157 {
158 (void) mutex_lock(&netlogon_mutex);
159 if (netlogon_busy && !netlogon_abort)
160 syslog(LOG_DEBUG, "logon abort");
161 netlogon_abort = B_TRUE;
162 (void) cond_broadcast(&netlogon_cv);
163 (void) mutex_unlock(&netlogon_mutex);
164 }
165
166 /*
167 * This is the entry point for authenticating domain users.
168 *
169 * If we are not going to attempt to authenticate the user,
170 * this function must return without updating the status.
171 *
172 * If the user is successfully authenticated, we build an
173 * access token and the status will be NT_STATUS_SUCCESS.
174 * Otherwise, the token contents are invalid.
175 *
176 * This will retry a few times for errors indicating that the
177 * current DC might have gone off-line or become too busy etc.
178 * With such errors, smb_ddiscover_bad_dc is called and then
179 * the smb_domain_getinfo call here waits for new DC info.
180 */
181 int smb_netr_logon_retries = 3;
182 void
183 smb_logon_domain(smb_logon_t *user_info, smb_token_t *token)
184 {
185 smb_domainex_t di;
186 uint32_t status;
187 int retries = smb_netr_logon_retries;
188
189 if (user_info->lg_secmode != SMB_SECMODE_DOMAIN)
190 return;
191
192 if (user_info->lg_domain_type == SMB_DOMAIN_LOCAL)
193 return;
194
195 while (--retries > 0) {
196
197 if (!smb_domain_getinfo(&di)) {
198 syslog(LOG_ERR, "logon DC getinfo failed");
199 status = NT_STATUS_NO_LOGON_SERVERS;
200 goto out;
201 }
202
203 (void) mutex_lock(&netlogon_mutex);
204 while (netlogon_busy && !netlogon_abort)
205 (void) cond_wait(&netlogon_cv, &netlogon_mutex);
206
207 if (netlogon_abort) {
208 (void) mutex_unlock(&netlogon_mutex);
209 status = NT_STATUS_REQUEST_ABORTED;
210 goto out;
211 }
212
213 netlogon_busy = B_TRUE;
214 (void) mutex_unlock(&netlogon_mutex);
215
216 status = netlogon_logon(user_info, token, &di);
217
218 (void) mutex_lock(&netlogon_mutex);
219 netlogon_busy = B_FALSE;
220 if (netlogon_abort)
221 status = NT_STATUS_REQUEST_ABORTED;
222 (void) cond_signal(&netlogon_cv);
223 (void) mutex_unlock(&netlogon_mutex);
224
225 switch (status) {
226 case NT_STATUS_BAD_NETWORK_PATH:
227 case NT_STATUS_BAD_NETWORK_NAME:
228 case RPC_NT_SERVER_TOO_BUSY:
229 /*
230 * May retry with a new DC, or if we're
231 * out of retries, will return...
232 */
233 status = NT_STATUS_NO_LOGON_SERVERS;
234 break;
235 default:
236 goto out;
237 }
238 }
239
240 out:
241 if (status != NT_STATUS_SUCCESS)
242 syslog(LOG_INFO, "logon[%s\\%s]: %s", user_info->lg_e_domain,
243 user_info->lg_e_username, xlate_nt_status(status));
244 user_info->lg_status = status;
245 }
246
247 /*
248 * Run a netr_server_samlogon call, dealing with the possible need to
249 * re-establish the NetLogon credential chain. If that fails, return
250 * NT_STATUS_DOMAIN_TRUST_INCONSISTENT indicating the machine account
251 * needs it's password reset (or whatever). Other errors are from the
252 * netr_server_samlogon() call including the many possibilities listed
253 * above that function.
254 */
255 static uint32_t
256 netlogon_logon(smb_logon_t *user_info, smb_token_t *token, smb_domainex_t *di)
257 {
258 char server[MAXHOSTNAMELEN];
259 mlsvc_handle_t netr_handle;
260 uint32_t status;
261 boolean_t did_reauth = B_FALSE;
262
263 /*
264 * This netr_open call does the work to connect to the DC,
265 * get the IPC share, open the named pipe, RPC bind, etc.
266 */
267 status = netr_open(di->d_dci.dc_name, di->d_primary.di_nbname,
268 &netr_handle);
269 if (status != 0) {
270 syslog(LOG_ERR, "netlogon remote open failed (%s)",
271 xlate_nt_status(status));
272 return (status);
273 }
274
275 if (di->d_dci.dc_name[0] != '\0' &&
276 (*netr_global_info.server != '\0')) {
277 (void) snprintf(server, sizeof (server),
278 "\\\\%s", di->d_dci.dc_name);
279 if (strncasecmp(netr_global_info.server,
280 server, strlen(server)) != 0)
281 netr_invalidate_chain();
282 }
283
284 reauth:
285 if ((netr_global_info.flags & NETR_FLG_VALID) == 0 ||
286 !smb_match_netlogon_seqnum()) {
287 /*
288 * This does netr_server_req_challenge() and
289 * netr_server_authenticate2(), updating the
290 * current netlogon sequence number.
291 */
292 status = netlogon_auth(di->d_dci.dc_name, &netr_handle,
293 NETR_FLG_NULL);
294
295 if (status != 0) {
296 syslog(LOG_ERR, "netlogon remote auth failed (%s)",
297 xlate_nt_status(status));
298 (void) netr_close(&netr_handle);
299 return (NT_STATUS_DOMAIN_TRUST_INCONSISTENT);
300 }
301
302 netr_global_info.flags |= NETR_FLG_VALID;
303 }
304
305 status = netr_server_samlogon(&netr_handle,
306 &netr_global_info, di->d_dci.dc_name, user_info, token);
307
308 if (status == NT_STATUS_INSUFFICIENT_LOGON_INFO) {
309 if (!did_reauth) {
310 /* Call netlogon_auth() again, just once. */
311 did_reauth = B_TRUE;
312 goto reauth;
313 }
314 status = NT_STATUS_DOMAIN_TRUST_INCONSISTENT;
315 }
316
317 (void) netr_close(&netr_handle);
318
319 return (status);
320 }
321
322 /*
323 * Helper for mlsvc_netlogon
324 *
325 * Call netlogon_auth with appropriate locks etc.
326 * Serialize like smb_logon_domain does for
327 * netlogon_logon / netlogon_auth
328 */
329 uint32_t
330 smb_netlogon_check(char *server, char *domain)
331 {
332 mlsvc_handle_t netr_handle;
333 uint32_t status;
334
335 (void) mutex_lock(&netlogon_mutex);
336 while (netlogon_busy)
337 (void) cond_wait(&netlogon_cv, &netlogon_mutex);
338
339 netlogon_busy = B_TRUE;
340 (void) mutex_unlock(&netlogon_mutex);
341
342 /*
343 * This section like netlogon_logon(), but only does
344 * one pass and no netr_server_samlogon call.
345 */
346
347 status = netr_open(server, domain,
348 &netr_handle);
349 if (status != 0) {
350 syslog(LOG_ERR, "netlogon remote open failed (%s)",
351 xlate_nt_status(status));
352 goto unlock_out;
353 }
354
355 if ((netr_global_info.flags & NETR_FLG_VALID) == 0 ||
356 !smb_match_netlogon_seqnum()) {
357 /*
358 * This does netr_server_req_challenge() and
359 * netr_server_authenticate2(), updating the
360 * current netlogon sequence number.
361 */
362 status = netlogon_auth(server, &netr_handle,
363 NETR_FLG_NULL);
364 if (status != 0) {
365 syslog(LOG_ERR, "netlogon remote auth failed (%s)",
366 xlate_nt_status(status));
367 } else {
368 netr_global_info.flags |= NETR_FLG_VALID;
369 }
370 }
371
372 (void) netr_close(&netr_handle);
373
374 unlock_out:
375 (void) mutex_lock(&netlogon_mutex);
376 netlogon_busy = B_FALSE;
377 (void) cond_signal(&netlogon_cv);
378 (void) mutex_unlock(&netlogon_mutex);
379
380 return (status);
381 }
382
383 static uint32_t
384 netr_setup_token(struct netr_validation_info3 *info3, smb_logon_t *user_info,
385 netr_info_t *netr_info, smb_token_t *token)
386 {
387 char *username, *domain;
388 unsigned char rc4key[SMBAUTH_SESSION_KEY_SZ];
389 smb_sid_t *domsid;
390 uint32_t status;
391 char nbdomain[NETBIOS_NAME_SZ];
392
393 domsid = (smb_sid_t *)info3->LogonDomainId;
394
395 token->tkn_user.i_sid = smb_sid_splice(domsid, info3->UserId);
396 if (token->tkn_user.i_sid == NULL)
397 return (NT_STATUS_NO_MEMORY);
398
399 token->tkn_primary_grp.i_sid = smb_sid_splice(domsid,
404 username = (info3->EffectiveName.str)
405 ? (char *)info3->EffectiveName.str : user_info->lg_e_username;
406
407 if (info3->LogonDomainName.str) {
408 domain = (char *)info3->LogonDomainName.str;
409 } else if (*user_info->lg_e_domain != '\0') {
410 domain = user_info->lg_e_domain;
411 } else {
412 (void) smb_getdomainname(nbdomain, sizeof (nbdomain));
413 domain = nbdomain;
414 }
415
416 if (username)
417 token->tkn_account_name = strdup(username);
418 if (domain)
419 token->tkn_domain_name = strdup(domain);
420
421 if (token->tkn_account_name == NULL || token->tkn_domain_name == NULL)
422 return (NT_STATUS_NO_MEMORY);
423
424 status = netr_setup_domain_groups(info3, &token->tkn_win_grps);
425 if (status != NT_STATUS_SUCCESS)
426 return (status);
427
428 status = netr_setup_token_wingrps(info3, token);
429 if (status != NT_STATUS_SUCCESS)
430 return (status);
431
432 /*
433 * The UserSessionKey in NetrSamLogon RPC is obfuscated using the
434 * session key obtained in the NETLOGON credential chain.
435 * An 8 byte session key is zero extended to 16 bytes. This 16 byte
436 * key is the key to the RC4 algorithm. The RC4 byte stream is
437 * exclusively ored with the 16 byte UserSessionKey to recover
438 * the the clear form.
439 */
440 if ((token->tkn_ssnkey.val = malloc(SMBAUTH_SESSION_KEY_SZ)) == NULL)
441 return (NT_STATUS_NO_MEMORY);
442 token->tkn_ssnkey.len = SMBAUTH_SESSION_KEY_SZ;
443 bzero(rc4key, SMBAUTH_SESSION_KEY_SZ);
444 bcopy(netr_info->session_key.key, rc4key, netr_info->session_key.len);
445 bcopy(info3->UserSessionKey.data, token->tkn_ssnkey.val,
446 SMBAUTH_SESSION_KEY_SZ);
447 rand_hash((unsigned char *)token->tkn_ssnkey.val,
797 MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT;
798 identity->logon_id.LowPart = logon_id;
799 identity->logon_id.HighPart = 0;
800
801 ndr_heap_mkvcs(heap, user_info->lg_domain,
802 (ndr_vcstr_t *)&identity->domain_name);
803
804 ndr_heap_mkvcs(heap, user_info->lg_username,
805 (ndr_vcstr_t *)&identity->username);
806
807 /*
808 * Some systems prefix the client workstation name with \\.
809 * It doesn't seem to make any difference whether it's there
810 * or not.
811 */
812 ndr_heap_mkvcs(heap, user_info->lg_workstation,
813 (ndr_vcstr_t *)&identity->workstation);
814 }
815
816 /*
817 * Add local and well-known group membership to the given
818 * token. Called after domain groups have been added.
819 */
820 static uint32_t
821 netr_setup_token_wingrps(struct netr_validation_info3 *info3,
822 smb_token_t *token)
823 {
824 uint32_t status;
825
826 status = smb_sam_usr_groups(token->tkn_user.i_sid,
827 &token->tkn_win_grps);
828 if (status != NT_STATUS_SUCCESS)
829 return (status);
830
831 if (netr_isadmin(info3))
832 token->tkn_flags |= SMB_ATF_ADMIN;
833
834 status = smb_wka_token_groups(token->tkn_flags, &token->tkn_win_grps);
835
836 return (status);
837 }
838
839 /*
840 * Converts groups information in the returned structure by domain controller
841 * (info3) to an internal representation (gids)
842 */
843 static uint32_t
844 netr_setup_domain_groups(struct netr_validation_info3 *info3, smb_ids_t *gids)
845 {
846 smb_sid_t *domain_sid;
847 smb_id_t *ids;
848 int i, total_cnt;
849
850 if ((i = info3->GroupCount) == 0)
851 i++;
852 i += info3->SidCount;
853
854 total_cnt = gids->i_cnt + i;
876 if (ids->i_sid == NULL)
877 return (NT_STATUS_NO_MEMORY);
878
879 ids->i_attrs = 0x7;
880 gids->i_cnt++;
881 ids++;
882 }
883
884 /* Add the extra SIDs */
885 for (i = 0; i < info3->SidCount; i++, gids->i_cnt++, ids++) {
886 ids->i_sid = smb_sid_dup((smb_sid_t *)info3->ExtraSids[i].sid);
887 if (ids->i_sid == NULL)
888 return (NT_STATUS_NO_MEMORY);
889
890 ids->i_attrs = info3->ExtraSids[i].attributes;
891 }
892
893 return (NT_STATUS_SUCCESS);
894 }
895
896 /*
897 * Converts additional "resource" groups (from krb5_validation_info)
898 * into the internal representation (gids), appending to the list
899 * already put in place by netr_setup_domain_groups().
900 */
901 static uint32_t netr_setup_krb5res_groups(struct krb5_validation_info *info,
902 smb_ids_t *gids)
903 {
904 smb_sid_t *domain_sid;
905 smb_id_t *ids;
906 int i, total_cnt;
907
908 total_cnt = gids->i_cnt + info->rg_rid_cnt;
909
910 gids->i_ids = realloc(gids->i_ids, total_cnt * sizeof (smb_id_t));
911 if (gids->i_ids == NULL)
912 return (NT_STATUS_NO_MEMORY);
913
914 domain_sid = (smb_sid_t *)info->rg_dom_sid;
915
916 ids = gids->i_ids + gids->i_cnt;
917 for (i = 0; i < info->rg_rid_cnt; i++, gids->i_cnt++, ids++) {
918 ids->i_sid = smb_sid_splice(domain_sid, info->rg_rids[i].rid);
919 if (ids->i_sid == NULL)
920 return (NT_STATUS_NO_MEMORY);
921 ids->i_attrs = info->rg_rids[i].attributes;
922 }
923
924 return (0);
925 }
926
927 /*
928 * Determines if the given user is the domain Administrator or a
929 * member of Domain Admins
930 */
931 static boolean_t
932 netr_isadmin(struct netr_validation_info3 *info3)
933 {
934 smb_domain_t di;
935 int i;
936
937 if (!smb_domain_lookup_sid((smb_sid_t *)info3->LogonDomainId, &di))
938 return (B_FALSE);
939
940 if (di.di_type != SMB_DOMAIN_PRIMARY)
941 return (B_FALSE);
942
943 if ((info3->UserId == DOMAIN_USER_RID_ADMIN) ||
944 (info3->PrimaryGroupId == DOMAIN_GROUP_RID_ADMINS))
945 return (B_TRUE);
946
|