s4:dsdb/samdb: optimize samldb_prim_group_change()
[Samba/gbeck.git] / source4 / auth / auth_sam_reply.c
blob0c03e78493d098040cadf3b0e5d8e193980b909e
1 /*
2 Unix SMB/CIFS implementation.
4 Convert a server info struct into the form for PAC and NETLOGON replies
6 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004
7 Copyright (C) Stefan Metzmacher <metze@samba.org> 2005
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
23 #include "includes.h"
24 #include "auth/auth.h"
25 #include "libcli/security/security.h"
26 #include "auth/auth_sam_reply.h"
28 NTSTATUS auth_convert_server_info_sambaseinfo(TALLOC_CTX *mem_ctx,
29 struct auth_serversupplied_info *server_info,
30 struct netr_SamBaseInfo **_sam)
32 struct netr_SamBaseInfo *sam = talloc_zero(mem_ctx, struct netr_SamBaseInfo);
33 NT_STATUS_HAVE_NO_MEMORY(sam);
35 sam->domain_sid = dom_sid_dup(mem_ctx, server_info->account_sid);
36 NT_STATUS_HAVE_NO_MEMORY(sam->domain_sid);
37 sam->domain_sid->num_auths--;
39 sam->last_logon = server_info->last_logon;
40 sam->last_logoff = server_info->last_logoff;
41 sam->acct_expiry = server_info->acct_expiry;
42 sam->last_password_change = server_info->last_password_change;
43 sam->allow_password_change = server_info->allow_password_change;
44 sam->force_password_change = server_info->force_password_change;
46 sam->account_name.string = server_info->account_name;
47 sam->full_name.string = server_info->full_name;
48 sam->logon_script.string = server_info->logon_script;
49 sam->profile_path.string = server_info->profile_path;
50 sam->home_directory.string = server_info->home_directory;
51 sam->home_drive.string = server_info->home_drive;
53 sam->logon_count = server_info->logon_count;
54 sam->bad_password_count = sam->bad_password_count;
55 sam->rid = server_info->account_sid->sub_auths[server_info->account_sid->num_auths-1];
56 sam->primary_gid = server_info->primary_group_sid->sub_auths[server_info->primary_group_sid->num_auths-1];
58 sam->groups.count = 0;
59 sam->groups.rids = NULL;
61 if (server_info->n_domain_groups > 0) {
62 size_t i;
63 sam->groups.rids = talloc_array(sam, struct samr_RidWithAttribute,
64 server_info->n_domain_groups);
66 if (sam->groups.rids == NULL)
67 return NT_STATUS_NO_MEMORY;
69 for (i=0; i<server_info->n_domain_groups; i++) {
70 struct dom_sid *group_sid = server_info->domain_groups[i];
71 if (!dom_sid_in_domain(sam->domain_sid, group_sid)) {
72 /* We handle this elsewhere */
73 continue;
75 sam->groups.rids[sam->groups.count].rid =
76 group_sid->sub_auths[group_sid->num_auths-1];
78 sam->groups.rids[sam->groups.count].attributes =
79 SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED;
80 sam->groups.count += 1;
84 sam->user_flags = 0; /* w2k3 uses NETLOGON_EXTRA_SIDS | NETLOGON_NTLMV2_ENABLED */
85 sam->acct_flags = server_info->acct_flags;
86 sam->logon_server.string = server_info->logon_server;
87 sam->domain.string = server_info->domain_name;
89 ZERO_STRUCT(sam->unknown);
91 ZERO_STRUCT(sam->key);
92 if (server_info->user_session_key.length == sizeof(sam->key.key)) {
93 memcpy(sam->key.key, server_info->user_session_key.data, sizeof(sam->key.key));
96 ZERO_STRUCT(sam->LMSessKey);
97 if (server_info->lm_session_key.length == sizeof(sam->LMSessKey.key)) {
98 memcpy(sam->LMSessKey.key, server_info->lm_session_key.data,
99 sizeof(sam->LMSessKey.key));
102 *_sam = sam;
104 return NT_STATUS_OK;
107 /* Note that the validity of the _sam3 structure is only as long as
108 * the server_info it was generated from */
109 NTSTATUS auth_convert_server_info_saminfo3(TALLOC_CTX *mem_ctx,
110 struct auth_serversupplied_info *server_info,
111 struct netr_SamInfo3 **_sam3)
113 struct netr_SamBaseInfo *sam;
114 struct netr_SamInfo3 *sam3 = talloc_zero(mem_ctx, struct netr_SamInfo3);
115 NTSTATUS status;
116 size_t i;
117 NT_STATUS_HAVE_NO_MEMORY(sam3);
119 status = auth_convert_server_info_sambaseinfo(mem_ctx, server_info, &sam);
120 if (!NT_STATUS_IS_OK(status)) {
121 return status;
123 sam3->base = *sam;
124 sam3->sidcount = 0;
125 sam3->sids = NULL;
128 sam3->sids = talloc_array(sam, struct netr_SidAttr,
129 server_info->n_domain_groups);
130 NT_STATUS_HAVE_NO_MEMORY(sam3->sids);
132 for (i=0; i<server_info->n_domain_groups; i++) {
133 if (dom_sid_in_domain(sam->domain_sid, server_info->domain_groups[i])) {
134 continue;
136 sam3->sids[sam3->sidcount].sid = talloc_reference(sam3->sids,server_info->domain_groups[i]);
137 sam3->sids[sam3->sidcount].attributes =
138 SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED;
139 sam3->sidcount += 1;
141 if (sam3->sidcount) {
142 sam3->base.user_flags |= NETLOGON_EXTRA_SIDS;
143 } else {
144 sam3->sids = NULL;
146 *_sam3 = sam3;
148 return NT_STATUS_OK;
152 * Make a server_info struct from the info3 returned by a domain logon
154 NTSTATUS make_server_info_netlogon_validation(TALLOC_CTX *mem_ctx,
155 const char *account_name,
156 uint16_t validation_level,
157 union netr_Validation *validation,
158 struct auth_serversupplied_info **_server_info)
160 struct auth_serversupplied_info *server_info;
161 struct netr_SamBaseInfo *base = NULL;
162 uint32_t i;
164 switch (validation_level) {
165 case 2:
166 if (!validation || !validation->sam2) {
167 return NT_STATUS_INVALID_PARAMETER;
169 base = &validation->sam2->base;
170 break;
171 case 3:
172 if (!validation || !validation->sam3) {
173 return NT_STATUS_INVALID_PARAMETER;
175 base = &validation->sam3->base;
176 break;
177 case 6:
178 if (!validation || !validation->sam6) {
179 return NT_STATUS_INVALID_PARAMETER;
181 base = &validation->sam6->base;
182 break;
183 default:
184 return NT_STATUS_INVALID_LEVEL;
187 server_info = talloc(mem_ctx, struct auth_serversupplied_info);
188 NT_STATUS_HAVE_NO_MEMORY(server_info);
191 Here is where we should check the list of
192 trusted domains, and verify that the SID
193 matches.
195 server_info->account_sid = dom_sid_add_rid(server_info, base->domain_sid, base->rid);
196 NT_STATUS_HAVE_NO_MEMORY(server_info->account_sid);
199 server_info->primary_group_sid = dom_sid_add_rid(server_info, base->domain_sid, base->primary_gid);
200 NT_STATUS_HAVE_NO_MEMORY(server_info->primary_group_sid);
202 server_info->n_domain_groups = base->groups.count;
203 if (base->groups.count) {
204 server_info->domain_groups = talloc_array(server_info, struct dom_sid*, base->groups.count);
205 NT_STATUS_HAVE_NO_MEMORY(server_info->domain_groups);
206 } else {
207 server_info->domain_groups = NULL;
210 for (i = 0; i < base->groups.count; i++) {
211 server_info->domain_groups[i] = dom_sid_add_rid(server_info->domain_groups, base->domain_sid, base->groups.rids[i].rid);
212 NT_STATUS_HAVE_NO_MEMORY(server_info->domain_groups[i]);
215 /* Copy 'other' sids. We need to do sid filtering here to
216 prevent possible elevation of privileges. See:
218 http://www.microsoft.com/windows2000/techinfo/administration/security/sidfilter.asp
221 if (validation_level == 3) {
222 struct dom_sid **dgrps = server_info->domain_groups;
223 size_t sidcount = server_info->n_domain_groups + validation->sam3->sidcount;
224 size_t n_dgrps = server_info->n_domain_groups;
226 if (validation->sam3->sidcount > 0) {
227 dgrps = talloc_realloc(server_info, dgrps, struct dom_sid*, sidcount);
228 NT_STATUS_HAVE_NO_MEMORY(dgrps);
230 for (i = 0; i < validation->sam3->sidcount; i++) {
231 dgrps[n_dgrps + i] = talloc_reference(dgrps, validation->sam3->sids[i].sid);
235 server_info->n_domain_groups = sidcount;
236 server_info->domain_groups = dgrps;
238 /* Where are the 'global' sids?... */
241 if (base->account_name.string) {
242 server_info->account_name = talloc_reference(server_info, base->account_name.string);
243 } else {
244 server_info->account_name = talloc_strdup(server_info, account_name);
245 NT_STATUS_HAVE_NO_MEMORY(server_info->account_name);
248 server_info->domain_name = talloc_reference(server_info, base->domain.string);
249 server_info->full_name = talloc_reference(server_info, base->full_name.string);
250 server_info->logon_script = talloc_reference(server_info, base->logon_script.string);
251 server_info->profile_path = talloc_reference(server_info, base->profile_path.string);
252 server_info->home_directory = talloc_reference(server_info, base->home_directory.string);
253 server_info->home_drive = talloc_reference(server_info, base->home_drive.string);
254 server_info->logon_server = talloc_reference(server_info, base->logon_server.string);
255 server_info->last_logon = base->last_logon;
256 server_info->last_logoff = base->last_logoff;
257 server_info->acct_expiry = base->acct_expiry;
258 server_info->last_password_change = base->last_password_change;
259 server_info->allow_password_change = base->allow_password_change;
260 server_info->force_password_change = base->force_password_change;
261 server_info->logon_count = base->logon_count;
262 server_info->bad_password_count = base->bad_password_count;
263 server_info->acct_flags = base->acct_flags;
265 server_info->authenticated = true;
267 /* ensure we are never given NULL session keys */
269 if (all_zero(base->key.key, sizeof(base->key.key))) {
270 server_info->user_session_key = data_blob(NULL, 0);
271 } else {
272 server_info->user_session_key = data_blob_talloc(server_info, base->key.key, sizeof(base->key.key));
273 NT_STATUS_HAVE_NO_MEMORY(server_info->user_session_key.data);
276 if (all_zero(base->LMSessKey.key, sizeof(base->LMSessKey.key))) {
277 server_info->lm_session_key = data_blob(NULL, 0);
278 } else {
279 server_info->lm_session_key = data_blob_talloc(server_info, base->LMSessKey.key, sizeof(base->LMSessKey.key));
280 NT_STATUS_HAVE_NO_MEMORY(server_info->lm_session_key.data);
283 ZERO_STRUCT(server_info->pac_srv_sig);
284 ZERO_STRUCT(server_info->pac_kdc_sig);
286 *_server_info = server_info;
287 return NT_STATUS_OK;
291 * Make a server_info struct from the PAC_LOGON_INFO supplied in the krb5 logon
293 NTSTATUS make_server_info_pac(TALLOC_CTX *mem_ctx,
294 struct PAC_LOGON_INFO *pac_logon_info,
295 struct auth_serversupplied_info **_server_info)
297 uint32_t i;
298 NTSTATUS nt_status;
299 union netr_Validation validation;
300 struct auth_serversupplied_info *server_info;
302 validation.sam3 = &pac_logon_info->info3;
304 nt_status = make_server_info_netlogon_validation(mem_ctx, "", 3, &validation, &server_info);
305 if (!NT_STATUS_IS_OK(nt_status)) {
306 return nt_status;
309 if (pac_logon_info->res_groups.count > 0) {
310 struct dom_sid **rgrps;
311 size_t sidcount = server_info->n_domain_groups + pac_logon_info->res_groups.count;
312 server_info->domain_groups = rgrps
313 = talloc_realloc(server_info, server_info->domain_groups, struct dom_sid *, sidcount);
314 NT_STATUS_HAVE_NO_MEMORY(rgrps);
316 for (i = 0; pac_logon_info->res_group_dom_sid && i < pac_logon_info->res_groups.count; i++) {
317 size_t sid_idx = server_info->n_domain_groups + i;
318 rgrps[sid_idx]
319 = dom_sid_add_rid(rgrps, pac_logon_info->res_group_dom_sid,
320 pac_logon_info->res_groups.rids[i].rid);
321 NT_STATUS_HAVE_NO_MEMORY(rgrps[server_info->n_domain_groups + sid_idx]);
324 *_server_info = server_info;
325 return NT_STATUS_OK;