s3:auth add function to copy a netr_SamInfo3 structure
[Samba/ekacnet.git] / source3 / auth / server_info.c
blobd7ab19c58b44e60abcdfdf6e34570a8f1f59a17b
1 /*
2 Unix SMB/CIFS implementation.
3 Authentication utility functions
4 Copyright (C) Volker Lendecke 2010
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
20 #include "includes.h"
21 #include "../lib/crypto/arcfour.h"
23 #undef DBGC_CLASS
24 #define DBGC_CLASS DBGC_AUTH
26 static int server_info_dtor(struct auth_serversupplied_info *server_info)
28 TALLOC_FREE(server_info->sam_account);
29 ZERO_STRUCTP(server_info);
30 return 0;
33 /***************************************************************************
34 Make a server_info struct. Free with TALLOC_FREE().
35 ***************************************************************************/
37 struct auth_serversupplied_info *make_server_info(TALLOC_CTX *mem_ctx)
39 struct auth_serversupplied_info *result;
41 result = TALLOC_ZERO_P(mem_ctx, struct auth_serversupplied_info);
42 if (result == NULL) {
43 DEBUG(0, ("talloc failed\n"));
44 return NULL;
47 talloc_set_destructor(result, server_info_dtor);
49 /* Initialise the uid and gid values to something non-zero
50 which may save us from giving away root access if there
51 is a bug in allocating these fields. */
53 result->utok.uid = -1;
54 result->utok.gid = -1;
55 return result;
58 /*******************************************************************
59 gets a domain user's groups from their already-calculated NT_USER_TOKEN
60 ********************************************************************/
62 static NTSTATUS nt_token_to_group_list(TALLOC_CTX *mem_ctx,
63 const struct dom_sid *domain_sid,
64 size_t num_sids,
65 const struct dom_sid *sids,
66 int *numgroups,
67 struct samr_RidWithAttribute **pgids)
69 int i;
71 *numgroups=0;
72 *pgids = NULL;
74 for (i=0; i<num_sids; i++) {
75 struct samr_RidWithAttribute gid;
76 if (!sid_peek_check_rid(domain_sid, &sids[i], &gid.rid)) {
77 continue;
79 gid.attributes = (SE_GROUP_MANDATORY|SE_GROUP_ENABLED_BY_DEFAULT|
80 SE_GROUP_ENABLED);
81 ADD_TO_ARRAY(mem_ctx, struct samr_RidWithAttribute,
82 gid, pgids, numgroups);
83 if (*pgids == NULL) {
84 return NT_STATUS_NO_MEMORY;
87 return NT_STATUS_OK;
90 /****************************************************************************
91 inits a netr_SamBaseInfo structure from an auth_serversupplied_info.
92 *****************************************************************************/
94 static NTSTATUS serverinfo_to_SamInfo_base(TALLOC_CTX *mem_ctx,
95 struct auth_serversupplied_info *server_info,
96 uint8_t *pipe_session_key,
97 size_t pipe_session_key_len,
98 struct netr_SamBaseInfo *base)
100 struct samu *sampw;
101 struct samr_RidWithAttribute *gids = NULL;
102 const struct dom_sid *user_sid = NULL;
103 const struct dom_sid *group_sid = NULL;
104 struct dom_sid domain_sid;
105 uint32 user_rid, group_rid;
106 NTSTATUS status;
108 int num_gids = 0;
109 const char *my_name;
111 struct netr_UserSessionKey user_session_key;
112 struct netr_LMSessionKey lm_session_key;
114 NTTIME last_logon, last_logoff, acct_expiry, last_password_change;
115 NTTIME allow_password_change, force_password_change;
116 struct samr_RidWithAttributeArray groups;
117 int i;
118 struct dom_sid2 *sid = NULL;
120 ZERO_STRUCT(user_session_key);
121 ZERO_STRUCT(lm_session_key);
123 sampw = server_info->sam_account;
125 user_sid = pdb_get_user_sid(sampw);
126 group_sid = pdb_get_group_sid(sampw);
128 if (pipe_session_key && pipe_session_key_len != 16) {
129 DEBUG(0,("serverinfo_to_SamInfo3: invalid "
130 "pipe_session_key_len[%zu] != 16\n",
131 pipe_session_key_len));
132 return NT_STATUS_INTERNAL_ERROR;
135 if ((user_sid == NULL) || (group_sid == NULL)) {
136 DEBUG(1, ("_netr_LogonSamLogon: User without group or user SID\n"));
137 return NT_STATUS_UNSUCCESSFUL;
140 sid_copy(&domain_sid, user_sid);
141 sid_split_rid(&domain_sid, &user_rid);
143 sid = sid_dup_talloc(mem_ctx, &domain_sid);
144 if (!sid) {
145 return NT_STATUS_NO_MEMORY;
148 if (!sid_peek_check_rid(&domain_sid, group_sid, &group_rid)) {
149 DEBUG(1, ("_netr_LogonSamLogon: user %s\\%s has user sid "
150 "%s\n but group sid %s.\n"
151 "The conflicting domain portions are not "
152 "supported for NETLOGON calls\n",
153 pdb_get_domain(sampw),
154 pdb_get_username(sampw),
155 sid_string_dbg(user_sid),
156 sid_string_dbg(group_sid)));
157 return NT_STATUS_UNSUCCESSFUL;
160 if(server_info->login_server) {
161 my_name = server_info->login_server;
162 } else {
163 my_name = global_myname();
166 status = nt_token_to_group_list(mem_ctx, &domain_sid,
167 server_info->num_sids,
168 server_info->sids,
169 &num_gids, &gids);
171 if (!NT_STATUS_IS_OK(status)) {
172 return status;
175 if (server_info->user_session_key.length) {
176 memcpy(user_session_key.key,
177 server_info->user_session_key.data,
178 MIN(sizeof(user_session_key.key),
179 server_info->user_session_key.length));
180 if (pipe_session_key) {
181 arcfour_crypt(user_session_key.key, pipe_session_key, 16);
184 if (server_info->lm_session_key.length) {
185 memcpy(lm_session_key.key,
186 server_info->lm_session_key.data,
187 MIN(sizeof(lm_session_key.key),
188 server_info->lm_session_key.length));
189 if (pipe_session_key) {
190 arcfour_crypt(lm_session_key.key, pipe_session_key, 8);
194 groups.count = num_gids;
195 groups.rids = TALLOC_ARRAY(mem_ctx, struct samr_RidWithAttribute, groups.count);
196 if (!groups.rids) {
197 return NT_STATUS_NO_MEMORY;
200 for (i=0; i < groups.count; i++) {
201 groups.rids[i].rid = gids[i].rid;
202 groups.rids[i].attributes = gids[i].attributes;
205 unix_to_nt_time(&last_logon, pdb_get_logon_time(sampw));
206 unix_to_nt_time(&last_logoff, get_time_t_max());
207 unix_to_nt_time(&acct_expiry, get_time_t_max());
208 unix_to_nt_time(&last_password_change, pdb_get_pass_last_set_time(sampw));
209 unix_to_nt_time(&allow_password_change, pdb_get_pass_can_change_time(sampw));
210 unix_to_nt_time(&force_password_change, pdb_get_pass_must_change_time(sampw));
212 base->last_logon = last_logon;
213 base->last_logoff = last_logoff;
214 base->acct_expiry = acct_expiry;
215 base->last_password_change = last_password_change;
216 base->allow_password_change = allow_password_change;
217 base->force_password_change = force_password_change;
218 base->account_name.string = talloc_strdup(mem_ctx, pdb_get_username(sampw));
219 base->full_name.string = talloc_strdup(mem_ctx, pdb_get_fullname(sampw));
220 base->logon_script.string = talloc_strdup(mem_ctx, pdb_get_logon_script(sampw));
221 base->profile_path.string = talloc_strdup(mem_ctx, pdb_get_profile_path(sampw));
222 base->home_directory.string = talloc_strdup(mem_ctx, pdb_get_homedir(sampw));
223 base->home_drive.string = talloc_strdup(mem_ctx, pdb_get_dir_drive(sampw));
224 base->logon_count = 0; /* ?? */
225 base->bad_password_count = 0; /* ?? */
226 base->rid = user_rid;
227 base->primary_gid = group_rid;
228 base->groups = groups;
229 base->user_flags = NETLOGON_EXTRA_SIDS;
230 base->key = user_session_key;
231 base->logon_server.string = talloc_strdup(mem_ctx, my_name);
232 base->domain.string = talloc_strdup(mem_ctx, pdb_get_domain(sampw));
233 base->domain_sid = sid;
234 base->LMSessKey = lm_session_key;
235 base->acct_flags = pdb_get_acct_ctrl(sampw);
237 ZERO_STRUCT(user_session_key);
238 ZERO_STRUCT(lm_session_key);
240 return NT_STATUS_OK;
243 /****************************************************************************
244 inits a netr_SamInfo2 structure from an auth_serversupplied_info. sam2 must
245 already be initialized and is used as the talloc parent for its members.
246 *****************************************************************************/
248 NTSTATUS serverinfo_to_SamInfo2(struct auth_serversupplied_info *server_info,
249 uint8_t *pipe_session_key,
250 size_t pipe_session_key_len,
251 struct netr_SamInfo2 *sam2)
253 NTSTATUS status;
255 status = serverinfo_to_SamInfo_base(sam2,
256 server_info,
257 pipe_session_key,
258 pipe_session_key_len,
259 &sam2->base);
260 if (!NT_STATUS_IS_OK(status)) {
261 return status;
264 return NT_STATUS_OK;
267 /****************************************************************************
268 inits a netr_SamInfo3 structure from an auth_serversupplied_info. sam3 must
269 already be initialized and is used as the talloc parent for its members.
270 *****************************************************************************/
272 NTSTATUS serverinfo_to_SamInfo3(struct auth_serversupplied_info *server_info,
273 uint8_t *pipe_session_key,
274 size_t pipe_session_key_len,
275 struct netr_SamInfo3 *sam3)
277 NTSTATUS status;
279 status = serverinfo_to_SamInfo_base(sam3,
280 server_info,
281 pipe_session_key,
282 pipe_session_key_len,
283 &sam3->base);
284 if (!NT_STATUS_IS_OK(status)) {
285 return status;
288 sam3->sidcount = 0;
289 sam3->sids = NULL;
291 return NT_STATUS_OK;
294 /****************************************************************************
295 inits a netr_SamInfo6 structure from an auth_serversupplied_info. sam6 must
296 already be initialized and is used as the talloc parent for its members.
297 *****************************************************************************/
299 NTSTATUS serverinfo_to_SamInfo6(struct auth_serversupplied_info *server_info,
300 uint8_t *pipe_session_key,
301 size_t pipe_session_key_len,
302 struct netr_SamInfo6 *sam6)
304 NTSTATUS status;
305 struct pdb_domain_info *dominfo;
307 if ((pdb_capabilities() & PDB_CAP_ADS) == 0) {
308 DEBUG(10,("Not adding validation info level 6 "
309 "without ADS passdb backend\n"));
310 return NT_STATUS_INVALID_INFO_CLASS;
313 dominfo = pdb_get_domain_info(sam6);
314 if (dominfo == NULL) {
315 return NT_STATUS_NO_MEMORY;
318 status = serverinfo_to_SamInfo_base(sam6,
319 server_info,
320 pipe_session_key,
321 pipe_session_key_len,
322 &sam6->base);
323 if (!NT_STATUS_IS_OK(status)) {
324 return status;
327 sam6->sidcount = 0;
328 sam6->sids = NULL;
330 sam6->dns_domainname.string = talloc_strdup(sam6, dominfo->dns_domain);
331 if (sam6->dns_domainname.string == NULL) {
332 return NT_STATUS_NO_MEMORY;
335 sam6->principle.string = talloc_asprintf(sam6, "%s@%s",
336 pdb_get_username(server_info->sam_account),
337 sam6->dns_domainname.string);
338 if (sam6->principle.string == NULL) {
339 return NT_STATUS_NO_MEMORY;
342 return NT_STATUS_OK;
345 static NTSTATUS sids_to_samr_RidWithAttributeArray(
346 TALLOC_CTX *mem_ctx,
347 struct samr_RidWithAttributeArray *groups,
348 const struct dom_sid *domain_sid,
349 const struct dom_sid *sids,
350 size_t num_sids)
352 unsigned int i;
353 bool ok;
355 groups->rids = talloc_array(mem_ctx,
356 struct samr_RidWithAttribute, num_sids);
357 if (!groups->rids) {
358 return NT_STATUS_NO_MEMORY;
361 for (i = 0; i < num_sids; i++) {
362 ok = sid_peek_check_rid(domain_sid, &sids[i],
363 &groups->rids[i].rid);
364 if (!ok) continue;
366 groups->rids[i].attributes = SE_GROUP_MANDATORY |
367 SE_GROUP_ENABLED_BY_DEFAULT |
368 SE_GROUP_ENABLED;
369 groups->count++;
372 return NT_STATUS_OK;
376 #define RET_NOMEM(ptr) do { \
377 if (!ptr) { \
378 TALLOC_FREE(info3); \
379 return NT_STATUS_NO_MEMORY; \
380 } } while(0)
382 NTSTATUS samu_to_SamInfo3(TALLOC_CTX *mem_ctx,
383 struct samu *samu,
384 const char *login_server,
385 struct netr_SamInfo3 **_info3)
387 struct netr_SamInfo3 *info3;
388 const struct dom_sid *user_sid;
389 const struct dom_sid *group_sid;
390 struct dom_sid domain_sid;
391 struct dom_sid *group_sids;
392 size_t num_group_sids;
393 const char *tmp;
394 gid_t *gids;
395 NTSTATUS status;
396 bool ok;
398 user_sid = pdb_get_user_sid(samu);
399 group_sid = pdb_get_group_sid(samu);
401 if (!user_sid || !group_sid) {
402 DEBUG(1, ("Sam account is missing sids!\n"));
403 return NT_STATUS_UNSUCCESSFUL;
406 info3 = talloc_zero(mem_ctx, struct netr_SamInfo3);
407 if (!info3) {
408 return NT_STATUS_NO_MEMORY;
411 unix_to_nt_time(&info3->base.last_logon, pdb_get_logon_time(samu));
412 unix_to_nt_time(&info3->base.last_logoff, get_time_t_max());
413 unix_to_nt_time(&info3->base.acct_expiry, get_time_t_max());
414 unix_to_nt_time(&info3->base.last_password_change,
415 pdb_get_pass_last_set_time(samu));
416 unix_to_nt_time(&info3->base.allow_password_change,
417 pdb_get_pass_can_change_time(samu));
418 unix_to_nt_time(&info3->base.force_password_change,
419 pdb_get_pass_must_change_time(samu));
421 tmp = pdb_get_username(samu);
422 if (tmp) {
423 info3->base.account_name.string = talloc_strdup(info3, tmp);
424 RET_NOMEM(info3->base.account_name.string);
426 tmp = pdb_get_fullname(samu);
427 if (tmp) {
428 info3->base.full_name.string = talloc_strdup(info3, tmp);
429 RET_NOMEM(info3->base.full_name.string);
431 tmp = pdb_get_logon_script(samu);
432 if (tmp) {
433 info3->base.logon_script.string = talloc_strdup(info3, tmp);
434 RET_NOMEM(info3->base.logon_script.string);
436 if (tmp) {
437 info3->base.profile_path.string = talloc_strdup(info3, tmp);
438 RET_NOMEM(info3->base.profile_path.string);
440 if (tmp) {
441 info3->base.home_directory.string = talloc_strdup(info3, tmp);
442 RET_NOMEM(info3->base.home_directory.string);
444 if (tmp) {
445 info3->base.home_drive.string = talloc_strdup(info3, tmp);
446 RET_NOMEM(info3->base.home_drive.string);
449 info3->base.logon_count = pdb_get_logon_count(samu);
450 info3->base.bad_password_count = pdb_get_bad_password_count(samu);
452 sid_copy(&domain_sid, user_sid);
453 sid_split_rid(&domain_sid, &info3->base.rid);
455 ok = sid_peek_check_rid(&domain_sid, group_sid,
456 &info3->base.primary_gid);
457 if (!ok) {
458 DEBUG(1, ("The primary group sid domain does not"
459 "match user sid domain for user: %s\n",
460 pdb_get_username(samu)));
461 TALLOC_FREE(info3);
462 return NT_STATUS_UNSUCCESSFUL;
465 status = pdb_enum_group_memberships(mem_ctx, samu,
466 &group_sids, &gids,
467 &num_group_sids);
468 if (!NT_STATUS_IS_OK(status)) {
469 DEBUG(1, ("Failed to get groups from sam account.\n"));
470 TALLOC_FREE(info3);
471 return status;
474 status = sids_to_samr_RidWithAttributeArray(info3,
475 &info3->base.groups,
476 &domain_sid,
477 group_sids,
478 num_group_sids);
479 if (!NT_STATUS_IS_OK(status)) {
480 TALLOC_FREE(info3);
481 return status;
484 /* We don't need sids and gids after the conversion */
485 TALLOC_FREE(group_sids);
486 TALLOC_FREE(gids);
487 num_group_sids = 0;
489 /* FIXME: should we add other flags ? */
490 info3->base.user_flags = NETLOGON_EXTRA_SIDS;
492 if (login_server) {
493 info3->base.logon_server.string = talloc_strdup(info3, login_server);
494 RET_NOMEM(info3->base.logon_server.string);
497 info3->base.domain.string = talloc_strdup(info3,
498 pdb_get_domain(samu));
499 RET_NOMEM(info3->base.domain.string);
501 info3->base.domain_sid = sid_dup_talloc(info3, &domain_sid);
502 RET_NOMEM(info3->base.domain_sid);
504 info3->base.acct_flags = pdb_get_acct_ctrl(samu);
506 *_info3 = info3;
507 return NT_STATUS_OK;
510 #undef RET_NOMEM
512 #define RET_NOMEM(ptr) do { \
513 if (!ptr) { \
514 TALLOC_FREE(info3); \
515 return NULL; \
516 } } while(0)
518 struct netr_SamInfo3 *copy_netr_SamInfo3(TALLOC_CTX *mem_ctx,
519 struct netr_SamInfo3 *orig)
521 struct netr_SamInfo3 *info3;
523 info3 = talloc(mem_ctx, struct netr_SamInfo3);
524 if (!info3) return NULL;
526 /* first copy all, then realloc pointers */
527 info3->base = orig->base;
529 info3->base.account_name.string =
530 talloc_strdup(info3, orig->base.account_name.string);
531 RET_NOMEM(info3->base.account_name.string);
532 info3->base.full_name.string =
533 talloc_strdup(info3, orig->base.full_name.string);
534 RET_NOMEM(info3->base.full_name.string);
535 info3->base.logon_script.string =
536 talloc_strdup(info3, orig->base.logon_script.string);
537 RET_NOMEM(info3->base.logon_script.string);
538 info3->base.profile_path.string =
539 talloc_strdup(info3, orig->base.profile_path.string);
540 RET_NOMEM(info3->base.profile_path.string);
541 info3->base.home_directory.string =
542 talloc_strdup(info3, orig->base.home_directory.string);
543 RET_NOMEM(info3->base.home_directory.string);
544 info3->base.home_drive.string =
545 talloc_strdup(info3, orig->base.home_drive.string);
546 RET_NOMEM(info3->base.home_drive.string);
548 info3->base.groups.rids =
549 talloc_memdup(info3, orig->base.groups.rids,
550 (sizeof(struct samr_RidWithAttribute) *
551 orig->base.groups.count));
552 RET_NOMEM(info3->base.groups.rids);
554 info3->base.logon_server.string =
555 talloc_strdup(info3, orig->base.logon_server.string);
556 RET_NOMEM(info3->base.logon_server.string);
557 info3->base.domain.string =
558 talloc_strdup(info3, orig->base.domain.string);
559 RET_NOMEM(info3->base.domain.string);
561 info3->base.domain_sid = sid_dup_talloc(info3, orig->base.domain_sid);
562 RET_NOMEM(info3->base.domain_sid);
564 info3->sids = talloc_memdup(info3, orig->sids,
565 (sizeof(struct netr_SidAttr) *
566 orig->sidcount));
567 RET_NOMEM(info3->sids);
569 return info3;