2 * Unix SMB/Netbios implementation.
4 * RPC Pipe client / server routines
5 * Copyright (C) Andrew Tridgell 1992-1997,
6 * Copyright (C) Luke Kenneth Casson Leighton 1996-1997,
7 * Copyright (C) Paul Ashton 1997.
8 * Copyright (C) Jeremy Allison 2001.
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 /* This is the implementation of the lsa server code. */
29 extern DOM_SID global_sam_sid
;
30 extern fstring global_myworkgroup
;
31 extern pstring global_myname
;
33 static PRIVS privs
[] = {
34 {SE_PRIV_NONE
, "no_privs", "No privilege"},
35 {SE_PRIV_ADD_USERS
, "add_users", "add users"},
36 {SE_PRIV_ADD_MACHINES
, "add_computers", "add computers to domain"},
37 {SE_PRIV_PRINT_OPERATOR
, "print_op", "printer operator"},
38 {SE_PRIV_ALL
, "all_privs", "all privileges"}
46 /*******************************************************************
47 Function to free the per handle data.
48 ********************************************************************/
50 static void free_lsa_info(void *ptr
)
52 struct lsa_info
*lsa
= (struct lsa_info
*)ptr
;
57 /***************************************************************************
59 ***************************************************************************/
61 static void init_dom_query(DOM_QUERY
*d_q
, char *dom_name
, DOM_SID
*dom_sid
)
63 int domlen
= (dom_name
!= NULL
) ? strlen(dom_name
) : 0;
66 * I'm not sure why this really odd combination of length
67 * values works, but it does appear to. I need to look at
68 * this *much* more closely - but at the moment leave alone
69 * until it's understood. This allows a W2k client to join
70 * a domain with both odd and even length names... JRA.
73 d_q
->uni_dom_str_len
= domlen
? ((domlen
+ 1) * 2) : 0;
74 d_q
->uni_dom_max_len
= domlen
* 2;
75 d_q
->buffer_dom_name
= domlen
!= 0 ? 1 : 0; /* domain buffer pointer */
76 d_q
->buffer_dom_sid
= dom_sid
!= NULL
? 1 : 0; /* domain sid pointer */
78 /* this string is supposed to be character short */
79 init_unistr2(&d_q
->uni_domain_name
, dom_name
, domlen
);
80 d_q
->uni_domain_name
.uni_max_len
++;
83 init_dom_sid2(&d_q
->dom_sid
, dom_sid
);
86 /***************************************************************************
87 init_dom_ref - adds a domain if it's not already in, returns the index.
88 ***************************************************************************/
90 static int init_dom_ref(DOM_R_REF
*ref
, char *dom_name
, DOM_SID
*dom_sid
)
95 if (dom_name
!= NULL
) {
96 for (num
= 0; num
< ref
->num_ref_doms_1
; num
++) {
98 fstrcpy(domname
, dos_unistr2_to_str(&ref
->ref_dom
[num
].uni_dom_name
));
99 if (strequal(domname
, dom_name
))
103 num
= ref
->num_ref_doms_1
;
106 if (num
>= MAX_REF_DOMAINS
) {
107 /* index not found, already at maximum domain limit */
111 ref
->num_ref_doms_1
= num
+1;
112 ref
->ptr_ref_dom
= 1;
113 ref
->max_entries
= MAX_REF_DOMAINS
;
114 ref
->num_ref_doms_2
= num
+1;
116 len
= (dom_name
!= NULL
) ? strlen(dom_name
) : 0;
117 if(dom_name
!= NULL
&& len
== 0)
120 init_uni_hdr(&ref
->hdr_ref_dom
[num
].hdr_dom_name
, len
);
121 ref
->hdr_ref_dom
[num
].ptr_dom_sid
= dom_sid
!= NULL
? 1 : 0;
123 init_unistr2(&ref
->ref_dom
[num
].uni_dom_name
, dom_name
, len
);
124 init_dom_sid2(&ref
->ref_dom
[num
].ref_dom
, dom_sid
);
129 /***************************************************************************
131 ***************************************************************************/
133 static void init_lsa_rid2s(DOM_R_REF
*ref
, DOM_RID2
*rid2
,
134 int num_entries
, UNISTR2
*name
,
135 uint32
*mapped_count
, BOOL endian
)
141 SMB_ASSERT(num_entries
<= MAX_LOOKUP_SIDS
);
143 for (i
= 0; i
< num_entries
; i
++) {
146 uint32 rid
= 0xffffffff;
149 fstring dom_name
, user
;
150 enum SID_NAME_USE name_type
= SID_NAME_UNKNOWN
;
152 /* Split name into domain and user component */
154 pstrcpy(full_name
, dos_unistr2_to_str(&name
[i
]));
155 split_domain_name(full_name
, dom_name
, user
);
159 DEBUG(5, ("init_lsa_rid2s: looking up name %s\n", full_name
));
161 status
= lookup_name(full_name
, &sid
, &name_type
);
163 DEBUG(5, ("init_lsa_rid2s: %s\n", status
? "found" :
167 sid_split_rid(&sid
, &rid
);
168 dom_idx
= init_dom_ref(ref
, dom_name
, &sid
);
173 name_type
= SID_NAME_UNKNOWN
;
176 init_dom_rid2(&rid2
[total
], rid
, name_type
, dom_idx
);
181 /***************************************************************************
182 init_reply_lookup_names
183 ***************************************************************************/
185 static void init_reply_lookup_names(LSA_R_LOOKUP_NAMES
*r_l
,
186 DOM_R_REF
*ref
, uint32 num_entries
,
187 DOM_RID2
*rid2
, uint32 mapped_count
)
189 r_l
->ptr_dom_ref
= 1;
192 r_l
->num_entries
= num_entries
;
193 r_l
->ptr_entries
= 1;
194 r_l
->num_entries2
= num_entries
;
197 r_l
->mapped_count
= mapped_count
;
199 if (mapped_count
== 0)
200 r_l
->status
= NT_STATUS_NONE_MAPPED
;
202 r_l
->status
= NT_STATUS_OK
;
205 /***************************************************************************
206 Init lsa_trans_names.
207 ***************************************************************************/
209 static void init_lsa_trans_names(TALLOC_CTX
*ctx
, DOM_R_REF
*ref
, LSA_TRANS_NAME_ENUM
*trn
,
210 int num_entries
, DOM_SID2
*sid
,
211 uint32
*mapped_count
)
217 /* Allocate memory for list of names */
219 if (num_entries
> 0) {
220 if (!(trn
->name
= (LSA_TRANS_NAME
*)talloc(ctx
, sizeof(LSA_TRANS_NAME
) *
222 DEBUG(0, ("init_lsa_trans_names(): out of memory\n"));
226 if (!(trn
->uni_name
= (UNISTR2
*)talloc(ctx
, sizeof(UNISTR2
) *
228 DEBUG(0, ("init_lsa_trans_names(): out of memory\n"));
233 for (i
= 0; i
< num_entries
; i
++) {
235 DOM_SID find_sid
= sid
[i
].sid
;
236 uint32 rid
= 0xffffffff;
238 fstring name
, dom_name
;
239 enum SID_NAME_USE sid_name_use
= (enum SID_NAME_USE
)0;
241 sid_to_string(name
, &find_sid
);
242 DEBUG(5, ("init_lsa_trans_names: looking up sid %s\n", name
));
244 /* Lookup sid from winbindd */
246 memset(dom_name
, '\0', sizeof(dom_name
));
247 memset(name
, '\0', sizeof(name
));
249 status
= lookup_sid(&find_sid
, dom_name
, name
, &sid_name_use
);
251 DEBUG(5, ("init_lsa_trans_names: %s\n", status
? "found" :
255 sid_name_use
= SID_NAME_UNKNOWN
;
258 /* Store domain sid in ref array */
260 if (find_sid
.num_auths
== 5) {
261 sid_split_rid(&find_sid
, &rid
);
264 /* unistr routines take dos codepage strings */
266 unix_to_dos(dom_name
, True
);
267 unix_to_dos(name
, True
);
269 dom_idx
= init_dom_ref(ref
, dom_name
, &find_sid
);
271 DEBUG(10,("init_lsa_trans_names: added user '%s\\%s' to "
272 "referenced list.\n", dom_name
, name
));
276 init_lsa_trans_name(&trn
->name
[total
], &trn
->uni_name
[total
],
277 sid_name_use
, name
, dom_idx
);
281 trn
->num_entries
= total
;
282 trn
->ptr_trans_names
= 1;
283 trn
->num_entries2
= total
;
286 /***************************************************************************
287 Init_reply_lookup_sids.
288 ***************************************************************************/
290 static void init_reply_lookup_sids(LSA_R_LOOKUP_SIDS
*r_l
,
291 DOM_R_REF
*ref
, LSA_TRANS_NAME_ENUM
*names
,
294 r_l
->ptr_dom_ref
= 1;
297 r_l
->mapped_count
= mapped_count
;
299 if (mapped_count
== 0)
300 r_l
->status
= NT_STATUS_NONE_MAPPED
;
302 r_l
->status
= NT_STATUS_OK
;
305 /***************************************************************************
307 ***************************************************************************/
309 NTSTATUS
_lsa_open_policy2(pipes_struct
*p
, LSA_Q_OPEN_POL2
*q_u
, LSA_R_OPEN_POL2
*r_u
)
311 /* lkclXXXX having decoded it, ignore all fields in the open policy! */
313 /* set up the LSA QUERY INFO response */
314 if (!create_policy_hnd(p
, &r_u
->pol
, NULL
, NULL
))
315 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
320 /***************************************************************************
322 ***************************************************************************/
324 NTSTATUS
_lsa_open_policy(pipes_struct
*p
, LSA_Q_OPEN_POL
*q_u
, LSA_R_OPEN_POL
*r_u
)
326 /* lkclXXXX having decoded it, ignore all fields in the open policy! */
328 /* set up the LSA QUERY INFO response */
329 if (!create_policy_hnd(p
, &r_u
->pol
, NULL
, NULL
))
330 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
335 /***************************************************************************
336 _lsa_enum_trust_dom - this needs fixing to do more than return NULL ! JRA.
337 ***************************************************************************/
339 NTSTATUS
_lsa_enum_trust_dom(pipes_struct
*p
, LSA_Q_ENUM_TRUST_DOM
*q_u
, LSA_R_ENUM_TRUST_DOM
*r_u
)
341 uint32 enum_context
= 0;
342 char *dom_name
= NULL
;
343 DOM_SID
*dom_sid
= NULL
;
345 if (!find_policy_by_hnd(p
, &q_u
->pol
, NULL
))
346 return NT_STATUS_INVALID_HANDLE
;
348 /* set up the LSA QUERY INFO response */
349 init_r_enum_trust_dom(p
->mem_ctx
, r_u
, enum_context
, dom_name
, dom_sid
,
350 dom_name
!= NULL
? NT_STATUS_OK
: NT_STATUS_NO_MORE_ENTRIES
);
355 /***************************************************************************
356 _lsa_query_info. See the POLICY_INFOMATION_CLASS docs at msdn.
357 ***************************************************************************/
359 NTSTATUS
_lsa_query_info(pipes_struct
*p
, LSA_Q_QUERY_INFO
*q_u
, LSA_R_QUERY_INFO
*r_u
)
361 LSA_INFO_UNION
*info
= &r_u
->dom
;
367 r_u
->status
= NT_STATUS_OK
;
369 if (!find_policy_by_hnd(p
, &q_u
->pol
, NULL
))
370 return NT_STATUS_INVALID_HANDLE
;
372 fstrcpy(dos_domain
, global_myworkgroup
);
373 unix_to_dos(dos_domain
, True
);
375 switch (q_u
->info_class
) {
379 /* fake info: We audit everything. ;) */
380 info
->id2
.auditing_enabled
= 1;
381 info
->id2
.count1
= 7;
382 info
->id2
.count2
= 7;
383 if ((info
->id2
.auditsettings
= (uint32
*)talloc(p
->mem_ctx
,7*sizeof(uint32
))) == NULL
)
384 return NT_STATUS_NO_MEMORY
;
385 for (i
= 0; i
< 7; i
++)
386 info
->id2
.auditsettings
[i
] = 3;
390 /* Request PolicyPrimaryDomainInformation. */
391 switch (lp_server_role()) {
392 case ROLE_DOMAIN_PDC
:
393 case ROLE_DOMAIN_BDC
:
395 sid
= &global_sam_sid
;
397 case ROLE_DOMAIN_MEMBER
:
399 /* We need to return the Domain SID here. */
400 if (secrets_fetch_domain_sid(dos_domain
,
404 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO
;
406 case ROLE_STANDALONE
:
408 sid
= NULL
; /* Tell it we're not in a domain. */
411 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO
;
413 init_dom_query(&r_u
->dom
.id3
, name
, sid
);
416 /* Request PolicyAccountDomainInformation. */
417 switch (lp_server_role()) {
418 case ROLE_DOMAIN_PDC
:
419 case ROLE_DOMAIN_BDC
:
421 sid
= &global_sam_sid
;
423 case ROLE_DOMAIN_MEMBER
:
425 sid
= &global_sam_sid
;
427 case ROLE_STANDALONE
:
429 sid
= &global_sam_sid
;
432 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO
;
434 init_dom_query(&r_u
->dom
.id5
, name
, sid
);
437 switch (lp_server_role()) {
438 case ROLE_DOMAIN_BDC
:
440 * only a BDC is a backup controller
441 * of the domain, it controls.
443 info
->id6
.server_role
= 2;
447 * any other role is a primary
448 * of the domain, it controls.
450 info
->id6
.server_role
= 3;
455 DEBUG(0,("_lsa_query_info: unknown info level in Lsa Query: %d\n", q_u
->info_class
));
456 r_u
->status
= NT_STATUS_INVALID_INFO_CLASS
;
460 if (NT_STATUS_IS_OK(r_u
->status
)) {
461 r_u
->undoc_buffer
= 0x22000000; /* bizarre */
462 r_u
->info_class
= q_u
->info_class
;
468 /***************************************************************************
470 ***************************************************************************/
472 NTSTATUS
_lsa_lookup_sids(pipes_struct
*p
, LSA_Q_LOOKUP_SIDS
*q_u
, LSA_R_LOOKUP_SIDS
*r_u
)
474 DOM_SID2
*sid
= q_u
->sids
.sid
;
475 int num_entries
= q_u
->sids
.num_entries
;
476 DOM_R_REF
*ref
= NULL
;
477 LSA_TRANS_NAME_ENUM
*names
= NULL
;
478 uint32 mapped_count
= 0;
480 if (!find_policy_by_hnd(p
, &q_u
->pol
, NULL
))
481 return NT_STATUS_INVALID_HANDLE
;
483 ref
= (DOM_R_REF
*)talloc_zero(p
->mem_ctx
, sizeof(DOM_R_REF
));
484 names
= (LSA_TRANS_NAME_ENUM
*)talloc_zero(p
->mem_ctx
, sizeof(LSA_TRANS_NAME_ENUM
));
487 return NT_STATUS_NO_MEMORY
;
489 /* set up the LSA Lookup SIDs response */
490 init_lsa_trans_names(p
->mem_ctx
, ref
, names
, num_entries
, sid
, &mapped_count
);
491 init_reply_lookup_sids(r_u
, ref
, names
, mapped_count
);
496 /***************************************************************************
497 lsa_reply_lookup_names
498 ***************************************************************************/
500 NTSTATUS
_lsa_lookup_names(pipes_struct
*p
,LSA_Q_LOOKUP_NAMES
*q_u
, LSA_R_LOOKUP_NAMES
*r_u
)
502 UNISTR2
*names
= q_u
->uni_name
;
503 int num_entries
= q_u
->num_entries
;
506 uint32 mapped_count
= 0;
508 if (!find_policy_by_hnd(p
, &q_u
->pol
, NULL
))
509 return NT_STATUS_INVALID_HANDLE
;
511 ref
= (DOM_R_REF
*)talloc_zero(p
->mem_ctx
, sizeof(DOM_R_REF
));
512 rids
= (DOM_RID2
*)talloc_zero(p
->mem_ctx
, sizeof(DOM_RID2
)*MAX_LOOKUP_SIDS
);
515 return NT_STATUS_NO_MEMORY
;
517 /* set up the LSA Lookup RIDs response */
518 init_lsa_rid2s(ref
, rids
, num_entries
, names
, &mapped_count
, p
->endian
);
519 init_reply_lookup_names(r_u
, ref
, num_entries
, rids
, mapped_count
);
524 /***************************************************************************
525 _lsa_close. Also weird - needs to check if lsa handle is correct. JRA.
526 ***************************************************************************/
528 NTSTATUS
_lsa_close(pipes_struct
*p
, LSA_Q_CLOSE
*q_u
, LSA_R_CLOSE
*r_u
)
530 if (!find_policy_by_hnd(p
, &q_u
->pol
, NULL
))
531 return NT_STATUS_INVALID_HANDLE
;
533 close_policy_hnd(p
, &q_u
->pol
);
537 /***************************************************************************
538 "No more secrets Marty...." :-).
539 ***************************************************************************/
541 NTSTATUS
_lsa_open_secret(pipes_struct
*p
, LSA_Q_OPEN_SECRET
*q_u
, LSA_R_OPEN_SECRET
*r_u
)
543 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
546 /***************************************************************************
548 ***************************************************************************/
550 NTSTATUS
_lsa_enum_privs(pipes_struct
*p
, LSA_Q_ENUM_PRIVS
*q_u
, LSA_R_ENUM_PRIVS
*r_u
)
554 uint32 enum_context
=q_u
->enum_context
;
555 LSA_PRIV_ENTRY
*entry
;
556 LSA_PRIV_ENTRY
*entries
;
558 if (!find_policy_by_hnd(p
, &q_u
->pol
, NULL
))
559 return NT_STATUS_INVALID_HANDLE
;
561 if (enum_context
>= PRIV_ALL_INDEX
)
562 return NT_STATUS_UNABLE_TO_FREE_VM
;
564 entries
= (LSA_PRIV_ENTRY
*)talloc_zero(p
->mem_ctx
, sizeof(LSA_PRIV_ENTRY
) * (PRIV_ALL_INDEX
-enum_context
));
566 return NT_STATUS_NO_MEMORY
;
569 for (i
= 0; i
< PRIV_ALL_INDEX
-enum_context
; i
++, entry
++) {
570 init_uni_hdr(&entry
->hdr_name
, strlen(privs
[i
+1-enum_context
].priv
));
571 init_unistr2(&entry
->name
, privs
[i
+1-enum_context
].priv
, strlen(privs
[i
+1-enum_context
].priv
) );
572 entry
->luid_low
= privs
[i
+1-enum_context
].se_priv
;
573 entry
->luid_high
= 1;
576 init_lsa_r_enum_privs(r_u
, i
+enum_context
, PRIV_ALL_INDEX
-enum_context
, entries
);
581 /***************************************************************************
582 _lsa_priv_get_dispname.
583 ***************************************************************************/
585 NTSTATUS
_lsa_priv_get_dispname(pipes_struct
*p
, LSA_Q_PRIV_GET_DISPNAME
*q_u
, LSA_R_PRIV_GET_DISPNAME
*r_u
)
591 if (!find_policy_by_hnd(p
, &q_u
->pol
, NULL
))
592 return NT_STATUS_INVALID_HANDLE
;
594 unistr2_to_ascii(name_asc
, &q_u
->name
, sizeof(name_asc
));
596 DEBUG(0,("_lsa_priv_get_dispname: %s", name_asc
));
598 for (i
=1; privs
[i
].se_priv
!=SE_PRIV_ALL
; i
++) {
599 if ( strcmp(name_asc
, privs
[i
].priv
)) {
601 fstrcpy(desc_asc
, privs
[i
].description
);
605 DEBUG(0,(": %s\n", desc_asc
));
607 init_uni_hdr(&r_u
->hdr_desc
, strlen(desc_asc
));
608 init_unistr2(&r_u
->desc
, desc_asc
, strlen(desc_asc
) );
610 r_u
->ptr_info
=0xdeadbeef;
611 r_u
->lang_id
=q_u
->lang_id
;
616 NTSTATUS
_lsa_unk_get_connuser(pipes_struct
*p
, LSA_Q_UNK_GET_CONNUSER
*q_u
, LSA_R_UNK_GET_CONNUSER
*r_u
)
618 fstring username
, domname
;
620 user_struct
*vuser
= get_valid_user_struct(p
->vuid
);
623 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO
;
625 fstrcpy(username
, vuser
->user
.smb_name
);
626 fstrcpy(domname
, vuser
->user
.domain
);
628 ulen
= strlen(username
) + 1;
629 dlen
= strlen(domname
) + 1;
631 init_uni_hdr(&r_u
->hdr_user_name
, ulen
);
632 r_u
->ptr_user_name
= 1;
633 init_unistr2(&r_u
->uni2_user_name
, username
, ulen
);
637 init_uni_hdr(&r_u
->hdr_dom_name
, dlen
);
638 r_u
->ptr_dom_name
= 1;
639 init_unistr2(&r_u
->uni2_dom_name
, domname
, dlen
);
641 r_u
->status
= NT_STATUS_OK
;
646 /***************************************************************************
648 ***************************************************************************/
650 NTSTATUS
_lsa_open_account(pipes_struct
*p
, LSA_Q_OPENACCOUNT
*q_u
, LSA_R_OPENACCOUNT
*r_u
)
652 struct lsa_info
*info
;
654 r_u
->status
= NT_STATUS_OK
;
656 /* find the connection policy handle. */
657 if (!find_policy_by_hnd(p
, &q_u
->pol
, NULL
))
658 return NT_STATUS_INVALID_HANDLE
;
660 /* associate the user/group SID with the (unique) handle. */
661 if ((info
= (struct lsa_info
*)malloc(sizeof(struct lsa_info
))) == NULL
)
662 return NT_STATUS_NO_MEMORY
;
665 info
->sid
= q_u
->sid
.sid
;
666 info
->access
= q_u
->access
;
668 /* get a (unique) handle. open a policy on it. */
669 if (!create_policy_hnd(p
, &r_u
->pol
, free_lsa_info
, (void *)info
))
670 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
675 /***************************************************************************
677 ***************************************************************************/
679 NTSTATUS
_lsa_getsystemaccount(pipes_struct
*p
, LSA_Q_GETSYSTEMACCOUNT
*q_u
, LSA_R_GETSYSTEMACCOUNT
*r_u
)
681 r_u
->status
= NT_STATUS_OK
;
683 /* find the connection policy handle. */
684 if (!find_policy_by_hnd(p
, &q_u
->pol
, NULL
))
685 return NT_STATUS_INVALID_HANDLE
;