2 Unix SMB/CIFS implementation.
4 lsa calls for file sharing connections
6 Copyright (C) Andrew Tridgell 2004
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
23 when dealing with ACLs the file sharing client code needs to
24 sometimes make LSA RPC calls. This code provides an easy interface
25 for doing those calls.
29 #include "libcli/raw/libcliraw.h"
30 #include "libcli/smb2/smb2.h"
31 #include "libcli/libcli.h"
32 #include "libcli/security/security.h"
33 #include "librpc/gen_ndr/ndr_lsa.h"
34 #include "librpc/gen_ndr/ndr_lsa_c.h"
35 #include "libcli/util/clilsa.h"
36 #include "libcli/smb/smbXcli_base.h"
39 struct dcerpc_binding_handle
*binding_handle
;
40 struct smbcli_tree
*ipc_tree
;
41 struct policy_handle handle
;
45 establish the lsa pipe connection
47 static NTSTATUS
smblsa_connect(struct smbcli_state
*cli
)
49 struct smblsa_state
*lsa
;
50 struct dcerpc_pipe
*lsa_pipe
;
52 struct lsa_OpenPolicy r
;
53 uint16_t system_name
= '\\';
55 struct lsa_ObjectAttribute attr
;
56 struct lsa_QosInfo qos
;
58 if (cli
->lsa
!= NULL
) {
62 lsa
= talloc(cli
, struct smblsa_state
);
64 return NT_STATUS_NO_MEMORY
;
67 lsa
->ipc_tree
= smbcli_tree_init(cli
->session
, lsa
, false);
68 if (lsa
->ipc_tree
== NULL
) {
69 return NT_STATUS_NO_MEMORY
;
73 tcon
.generic
.level
= RAW_TCON_TCONX
;
74 tcon
.tconx
.in
.flags
= TCONX_FLAG_EXTENDED_RESPONSE
;
75 tcon
.tconx
.in
.flags
|= TCONX_FLAG_EXTENDED_SIGNATURES
;
76 tcon
.tconx
.in
.password
= data_blob(NULL
, 0);
77 tcon
.tconx
.in
.path
= "ipc$";
78 tcon
.tconx
.in
.device
= "IPC";
79 status
= smb_raw_tcon(lsa
->ipc_tree
, lsa
, &tcon
);
80 if (!NT_STATUS_IS_OK(status
)) {
84 lsa
->ipc_tree
->tid
= tcon
.tconx
.out
.tid
;
86 if (tcon
.tconx
.out
.options
& SMB_EXTENDED_SIGNATURES
) {
87 smb1cli_session_protect_session_key(cli
->session
->smbXcli
);
90 lsa_pipe
= dcerpc_pipe_init(lsa
, cli
->transport
->ev
);
91 if (lsa_pipe
== NULL
) {
93 return NT_STATUS_NO_MEMORY
;
96 /* open the LSA pipe */
97 status
= dcerpc_pipe_open_smb(lsa_pipe
, lsa
->ipc_tree
, NDR_LSARPC_NAME
);
98 if (!NT_STATUS_IS_OK(status
)) {
103 /* bind to the LSA pipe */
104 status
= dcerpc_bind_auth_none(lsa_pipe
, &ndr_table_lsarpc
);
105 if (!NT_STATUS_IS_OK(status
)) {
109 lsa
->binding_handle
= lsa_pipe
->binding_handle
;
111 /* open a lsa policy handle */
113 qos
.impersonation_level
= 2;
114 qos
.context_mode
= 1;
115 qos
.effective_only
= 0;
118 attr
.root_dir
= NULL
;
119 attr
.object_name
= NULL
;
121 attr
.sec_desc
= NULL
;
124 r
.in
.system_name
= &system_name
;
126 r
.in
.access_mask
= SEC_FLAG_MAXIMUM_ALLOWED
;
127 r
.out
.handle
= &lsa
->handle
;
129 status
= dcerpc_lsa_OpenPolicy_r(lsa
->binding_handle
, lsa
, &r
);
130 if (!NT_STATUS_IS_OK(status
)) {
135 if (!NT_STATUS_IS_OK(r
.out
.result
)) {
146 static NTSTATUS
smb2lsa_connect(struct smb2_tree
*tree
)
148 struct smb2lsa_state
*lsa
= NULL
;
149 struct dcerpc_pipe
*lsa_pipe
= NULL
;
151 struct lsa_OpenPolicy2 r
= {{0}, {0}};
152 const char *system_name
= "\\";
153 struct lsa_ObjectAttribute attr
= {0};
154 struct lsa_QosInfo qos
= {0};
156 if (tree
->lsa
!= NULL
) {
160 lsa
= talloc(tree
, struct smb2lsa_state
);
162 return NT_STATUS_NO_MEMORY
;
165 lsa_pipe
= dcerpc_pipe_init(lsa
, tree
->session
->transport
->ev
);
166 if (lsa_pipe
== NULL
) {
168 return NT_STATUS_NO_MEMORY
;
171 /* open the LSA pipe */
172 status
= dcerpc_pipe_open_smb2(lsa_pipe
, tree
, NDR_LSARPC_NAME
);
173 if (!NT_STATUS_IS_OK(status
)) {
178 /* bind to the LSA pipe */
179 status
= dcerpc_bind_auth_none(lsa_pipe
, &ndr_table_lsarpc
);
180 if (!NT_STATUS_IS_OK(status
)) {
184 lsa
->binding_handle
= lsa_pipe
->binding_handle
;
186 /* open a lsa policy handle */
188 qos
.impersonation_level
= 2;
189 qos
.context_mode
= 1;
190 qos
.effective_only
= 0;
193 attr
.root_dir
= NULL
;
194 attr
.object_name
= NULL
;
196 attr
.sec_desc
= NULL
;
199 r
.in
.system_name
= system_name
;
201 r
.in
.access_mask
= SEC_FLAG_MAXIMUM_ALLOWED
;
202 r
.out
.handle
= &lsa
->handle
;
204 status
= dcerpc_lsa_OpenPolicy2_r(lsa
->binding_handle
, lsa
, &r
);
205 if (!NT_STATUS_IS_OK(status
)) {
210 if (!NT_STATUS_IS_OK(r
.out
.result
)) {
222 return the set of privileges for the given sid
224 NTSTATUS
smblsa_sid_privileges(struct smbcli_state
*cli
, struct dom_sid
*sid
,
226 struct lsa_RightSet
*rights
)
229 struct lsa_EnumAccountRights r
;
231 status
= smblsa_connect(cli
);
232 if (!NT_STATUS_IS_OK(status
)) {
236 r
.in
.handle
= &cli
->lsa
->handle
;
238 r
.out
.rights
= rights
;
240 status
= dcerpc_lsa_EnumAccountRights_r(cli
->lsa
->binding_handle
, mem_ctx
, &r
);
241 if (!NT_STATUS_IS_OK(status
)) {
249 NTSTATUS
smb2lsa_sid_privileges(struct smb2_tree
*tree
, struct dom_sid
*sid
,
251 struct lsa_RightSet
*rights
)
254 struct lsa_EnumAccountRights r
= {{0}, {0}};
256 status
= smb2lsa_connect(tree
);
257 if (!NT_STATUS_IS_OK(status
)) {
261 r
.in
.handle
= &tree
->lsa
->handle
;
263 r
.out
.rights
= rights
;
265 status
= dcerpc_lsa_EnumAccountRights_r(tree
->lsa
->binding_handle
, mem_ctx
, &r
);
266 if (!NT_STATUS_IS_OK(status
)) {
275 check if a named sid has a particular named privilege
277 NTSTATUS
smblsa_sid_check_privilege(struct smbcli_state
*cli
,
279 const char *privilege
)
281 struct lsa_RightSet rights
;
283 TALLOC_CTX
*mem_ctx
= talloc_new(cli
);
287 sid
= dom_sid_parse_talloc(mem_ctx
, sid_str
);
289 talloc_free(mem_ctx
);
290 return NT_STATUS_INVALID_SID
;
293 status
= smblsa_sid_privileges(cli
, sid
, mem_ctx
, &rights
);
294 if (!NT_STATUS_IS_OK(status
)) {
295 talloc_free(mem_ctx
);
299 for (i
=0;i
<rights
.count
;i
++) {
300 if (strcmp(rights
.names
[i
].string
, privilege
) == 0) {
301 talloc_free(mem_ctx
);
306 talloc_free(mem_ctx
);
307 return NT_STATUS_NOT_FOUND
;
311 NTSTATUS
smb2lsa_sid_check_privilege(struct smb2_tree
*tree
,
313 const char *privilege
)
315 struct lsa_RightSet rights
= {0};
317 TALLOC_CTX
*mem_ctx
= NULL
;
318 struct dom_sid
*sid
= NULL
;
321 mem_ctx
= talloc_new(tree
);
323 return NT_STATUS_NO_MEMORY
;
326 sid
= dom_sid_parse_talloc(mem_ctx
, sid_str
);
328 talloc_free(mem_ctx
);
329 return NT_STATUS_INVALID_SID
;
332 status
= smb2lsa_sid_privileges(tree
, sid
, mem_ctx
, &rights
);
333 if (!NT_STATUS_IS_OK(status
)) {
334 talloc_free(mem_ctx
);
338 for (i
=0;i
<rights
.count
;i
++) {
339 if (strcmp(rights
.names
[i
].string
, privilege
) == 0) {
340 talloc_free(mem_ctx
);
345 talloc_free(mem_ctx
);
346 return NT_STATUS_NOT_FOUND
;
351 lookup a SID, returning its name
353 NTSTATUS
smblsa_lookup_sid(struct smbcli_state
*cli
,
358 struct lsa_LookupSids r
;
359 struct lsa_TransNameArray names
;
360 struct lsa_SidArray sids
;
361 struct lsa_RefDomainList
*domains
= NULL
;
365 TALLOC_CTX
*mem_ctx2
= talloc_new(mem_ctx
);
367 status
= smblsa_connect(cli
);
368 if (!NT_STATUS_IS_OK(status
)) {
372 sid
= dom_sid_parse_talloc(mem_ctx2
, sid_str
);
374 return NT_STATUS_INVALID_SID
;
381 sids
.sids
= talloc(mem_ctx2
, struct lsa_SidPtr
);
382 sids
.sids
[0].sid
= sid
;
384 r
.in
.handle
= &cli
->lsa
->handle
;
389 r
.out
.count
= &count
;
390 r
.out
.names
= &names
;
391 r
.out
.domains
= &domains
;
393 status
= dcerpc_lsa_LookupSids_r(cli
->lsa
->binding_handle
, mem_ctx2
, &r
);
394 if (!NT_STATUS_IS_OK(status
)) {
395 talloc_free(mem_ctx2
);
398 if (!NT_STATUS_IS_OK(r
.out
.result
)) {
399 talloc_free(mem_ctx2
);
402 if (names
.count
!= 1) {
403 talloc_free(mem_ctx2
);
404 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
406 if (domains
== NULL
) {
407 talloc_free(mem_ctx2
);
408 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
410 if (domains
->count
!= 1) {
411 talloc_free(mem_ctx2
);
412 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
414 if (names
.names
[0].sid_index
!= UINT32_MAX
&&
415 names
.names
[0].sid_index
>= domains
->count
)
417 talloc_free(mem_ctx2
);
418 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
421 (*name
) = talloc_asprintf(mem_ctx
, "%s\\%s",
422 domains
->domains
[0].name
.string
,
423 names
.names
[0].name
.string
);
425 talloc_free(mem_ctx2
);
431 lookup a name, returning its sid
433 NTSTATUS
smblsa_lookup_name(struct smbcli_state
*cli
,
436 const char **sid_str
)
438 struct lsa_LookupNames r
;
439 struct lsa_TransSidArray sids
;
440 struct lsa_String names
;
441 struct lsa_RefDomainList
*domains
= NULL
;
445 TALLOC_CTX
*mem_ctx2
= talloc_new(mem_ctx
);
447 status
= smblsa_connect(cli
);
448 if (!NT_STATUS_IS_OK(status
)) {
457 r
.in
.handle
= &cli
->lsa
->handle
;
463 r
.out
.count
= &count
;
465 r
.out
.domains
= &domains
;
467 status
= dcerpc_lsa_LookupNames_r(cli
->lsa
->binding_handle
, mem_ctx2
, &r
);
468 if (!NT_STATUS_IS_OK(status
)) {
469 talloc_free(mem_ctx2
);
472 if (!NT_STATUS_IS_OK(r
.out
.result
)) {
473 talloc_free(mem_ctx2
);
476 if (sids
.count
!= 1) {
477 talloc_free(mem_ctx2
);
478 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
480 if (domains
->count
!= 1) {
481 talloc_free(mem_ctx2
);
482 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
485 sid_compose(&sid
, domains
->domains
[0].sid
, sids
.sids
[0].rid
);
487 (*sid_str
) = dom_sid_string(mem_ctx
, &sid
);
489 talloc_free(mem_ctx2
);
496 add a set of privileges to the given sid
498 NTSTATUS
smblsa_sid_add_privileges(struct smbcli_state
*cli
, struct dom_sid
*sid
,
500 struct lsa_RightSet
*rights
)
503 struct lsa_AddAccountRights r
;
505 status
= smblsa_connect(cli
);
506 if (!NT_STATUS_IS_OK(status
)) {
510 r
.in
.handle
= &cli
->lsa
->handle
;
512 r
.in
.rights
= rights
;
514 status
= dcerpc_lsa_AddAccountRights_r(cli
->lsa
->binding_handle
, mem_ctx
, &r
);
515 if (!NT_STATUS_IS_OK(status
)) {
523 remove a set of privileges from the given sid
525 NTSTATUS
smblsa_sid_del_privileges(struct smbcli_state
*cli
, struct dom_sid
*sid
,
527 struct lsa_RightSet
*rights
)
530 struct lsa_RemoveAccountRights r
;
532 status
= smblsa_connect(cli
);
533 if (!NT_STATUS_IS_OK(status
)) {
537 r
.in
.handle
= &cli
->lsa
->handle
;
540 r
.in
.rights
= rights
;
542 status
= dcerpc_lsa_RemoveAccountRights_r(cli
->lsa
->binding_handle
, mem_ctx
, &r
);
543 if (!NT_STATUS_IS_OK(status
)) {