gensec: Refactor gensec_security_mechs()
[samba4-gss.git] / source4 / libcli / util / clilsa.c
blob8476fd890c359fb404b4418833f1d9e5f631eb54
1 /*
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.
28 #include "includes.h"
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"
38 struct smblsa_state {
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;
51 NTSTATUS status;
52 struct lsa_OpenPolicy r;
53 uint16_t system_name = '\\';
54 union smb_tcon tcon;
55 struct lsa_ObjectAttribute attr;
56 struct lsa_QosInfo qos;
58 if (cli->lsa != NULL) {
59 return NT_STATUS_OK;
62 lsa = talloc(cli, struct smblsa_state);
63 if (lsa == NULL) {
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;
72 /* connect to IPC$ */
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)) {
81 talloc_free(lsa);
82 return 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) {
92 talloc_free(lsa);
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)) {
99 talloc_free(lsa);
100 return 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)) {
106 talloc_free(lsa);
107 return status;
109 lsa->binding_handle = lsa_pipe->binding_handle;
111 /* open a lsa policy handle */
112 qos.len = 0;
113 qos.impersonation_level = 2;
114 qos.context_mode = 1;
115 qos.effective_only = 0;
117 attr.len = 0;
118 attr.root_dir = NULL;
119 attr.object_name = NULL;
120 attr.attributes = 0;
121 attr.sec_desc = NULL;
122 attr.sec_qos = &qos;
124 r.in.system_name = &system_name;
125 r.in.attr = &attr;
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)) {
131 talloc_free(lsa);
132 return status;
135 if (!NT_STATUS_IS_OK(r.out.result)) {
136 talloc_free(lsa);
137 return r.out.result;
140 cli->lsa = lsa;
142 return NT_STATUS_OK;
146 static NTSTATUS smb2lsa_connect(struct smb2_tree *tree)
148 struct smb2lsa_state *lsa = NULL;
149 struct dcerpc_pipe *lsa_pipe = NULL;
150 NTSTATUS status;
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) {
157 return NT_STATUS_OK;
160 lsa = talloc(tree, struct smb2lsa_state);
161 if (lsa == NULL) {
162 return NT_STATUS_NO_MEMORY;
165 lsa_pipe = dcerpc_pipe_init(lsa, tree->session->transport->ev);
166 if (lsa_pipe == NULL) {
167 talloc_free(lsa);
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)) {
174 talloc_free(lsa);
175 return 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)) {
181 talloc_free(lsa);
182 return status;
184 lsa->binding_handle = lsa_pipe->binding_handle;
186 /* open a lsa policy handle */
187 qos.len = 0;
188 qos.impersonation_level = 2;
189 qos.context_mode = 1;
190 qos.effective_only = 0;
192 attr.len = 0;
193 attr.root_dir = NULL;
194 attr.object_name = NULL;
195 attr.attributes = 0;
196 attr.sec_desc = NULL;
197 attr.sec_qos = &qos;
199 r.in.system_name = system_name;
200 r.in.attr = &attr;
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)) {
206 talloc_free(lsa);
207 return status;
210 if (!NT_STATUS_IS_OK(r.out.result)) {
211 talloc_free(lsa);
212 return r.out.result;
215 tree->lsa = lsa;
217 return NT_STATUS_OK;
222 return the set of privileges for the given sid
224 NTSTATUS smblsa_sid_privileges(struct smbcli_state *cli, struct dom_sid *sid,
225 TALLOC_CTX *mem_ctx,
226 struct lsa_RightSet *rights)
228 NTSTATUS status;
229 struct lsa_EnumAccountRights r;
231 status = smblsa_connect(cli);
232 if (!NT_STATUS_IS_OK(status)) {
233 return status;
236 r.in.handle = &cli->lsa->handle;
237 r.in.sid = sid;
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)) {
242 return status;
245 return r.out.result;
249 NTSTATUS smb2lsa_sid_privileges(struct smb2_tree *tree, struct dom_sid *sid,
250 TALLOC_CTX *mem_ctx,
251 struct lsa_RightSet *rights)
253 NTSTATUS status;
254 struct lsa_EnumAccountRights r = {{0}, {0}};
256 status = smb2lsa_connect(tree);
257 if (!NT_STATUS_IS_OK(status)) {
258 return status;
261 r.in.handle = &tree->lsa->handle;
262 r.in.sid = sid;
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)) {
267 return status;
270 return r.out.result;
275 check if a named sid has a particular named privilege
277 NTSTATUS smblsa_sid_check_privilege(struct smbcli_state *cli,
278 const char *sid_str,
279 const char *privilege)
281 struct lsa_RightSet rights;
282 NTSTATUS status;
283 TALLOC_CTX *mem_ctx = talloc_new(cli);
284 struct dom_sid *sid;
285 unsigned i;
287 sid = dom_sid_parse_talloc(mem_ctx, sid_str);
288 if (sid == NULL) {
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);
296 return status;
299 for (i=0;i<rights.count;i++) {
300 if (strcmp(rights.names[i].string, privilege) == 0) {
301 talloc_free(mem_ctx);
302 return NT_STATUS_OK;
306 talloc_free(mem_ctx);
307 return NT_STATUS_NOT_FOUND;
311 NTSTATUS smb2lsa_sid_check_privilege(struct smb2_tree *tree,
312 const char *sid_str,
313 const char *privilege)
315 struct lsa_RightSet rights = {0};
316 NTSTATUS status;
317 TALLOC_CTX *mem_ctx = NULL;
318 struct dom_sid *sid = NULL;
319 unsigned i;
321 mem_ctx = talloc_new(tree);
322 if (!mem_ctx) {
323 return NT_STATUS_NO_MEMORY;
326 sid = dom_sid_parse_talloc(mem_ctx, sid_str);
327 if (sid == NULL) {
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);
335 return status;
338 for (i=0;i<rights.count;i++) {
339 if (strcmp(rights.names[i].string, privilege) == 0) {
340 talloc_free(mem_ctx);
341 return NT_STATUS_OK;
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,
354 const char *sid_str,
355 TALLOC_CTX *mem_ctx,
356 const char **name)
358 struct lsa_LookupSids r;
359 struct lsa_TransNameArray names;
360 struct lsa_SidArray sids;
361 struct lsa_RefDomainList *domains = NULL;
362 uint32_t count = 1;
363 NTSTATUS status;
364 struct dom_sid *sid;
365 TALLOC_CTX *mem_ctx2 = talloc_new(mem_ctx);
367 status = smblsa_connect(cli);
368 if (!NT_STATUS_IS_OK(status)) {
369 return status;
372 sid = dom_sid_parse_talloc(mem_ctx2, sid_str);
373 if (sid == NULL) {
374 return NT_STATUS_INVALID_SID;
377 names.count = 0;
378 names.names = NULL;
380 sids.num_sids = 1;
381 sids.sids = talloc(mem_ctx2, struct lsa_SidPtr);
382 sids.sids[0].sid = sid;
384 r.in.handle = &cli->lsa->handle;
385 r.in.sids = &sids;
386 r.in.names = &names;
387 r.in.level = 1;
388 r.in.count = &count;
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);
396 return status;
398 if (!NT_STATUS_IS_OK(r.out.result)) {
399 talloc_free(mem_ctx2);
400 return r.out.result;
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);
427 return NT_STATUS_OK;
431 lookup a name, returning its sid
433 NTSTATUS smblsa_lookup_name(struct smbcli_state *cli,
434 const char *name,
435 TALLOC_CTX *mem_ctx,
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;
442 uint32_t count = 1;
443 NTSTATUS status;
444 struct dom_sid sid;
445 TALLOC_CTX *mem_ctx2 = talloc_new(mem_ctx);
447 status = smblsa_connect(cli);
448 if (!NT_STATUS_IS_OK(status)) {
449 return status;
452 sids.count = 0;
453 sids.sids = NULL;
455 names.string = name;
457 r.in.handle = &cli->lsa->handle;
458 r.in.num_names = 1;
459 r.in.names = &names;
460 r.in.sids = &sids;
461 r.in.level = 1;
462 r.in.count = &count;
463 r.out.count = &count;
464 r.out.sids = &sids;
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);
470 return status;
472 if (!NT_STATUS_IS_OK(r.out.result)) {
473 talloc_free(mem_ctx2);
474 return r.out.result;
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);
491 return NT_STATUS_OK;
496 add a set of privileges to the given sid
498 NTSTATUS smblsa_sid_add_privileges(struct smbcli_state *cli, struct dom_sid *sid,
499 TALLOC_CTX *mem_ctx,
500 struct lsa_RightSet *rights)
502 NTSTATUS status;
503 struct lsa_AddAccountRights r;
505 status = smblsa_connect(cli);
506 if (!NT_STATUS_IS_OK(status)) {
507 return status;
510 r.in.handle = &cli->lsa->handle;
511 r.in.sid = sid;
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)) {
516 return status;
519 return r.out.result;
523 remove a set of privileges from the given sid
525 NTSTATUS smblsa_sid_del_privileges(struct smbcli_state *cli, struct dom_sid *sid,
526 TALLOC_CTX *mem_ctx,
527 struct lsa_RightSet *rights)
529 NTSTATUS status;
530 struct lsa_RemoveAccountRights r;
532 status = smblsa_connect(cli);
533 if (!NT_STATUS_IS_OK(status)) {
534 return status;
537 r.in.handle = &cli->lsa->handle;
538 r.in.sid = sid;
539 r.in.remove_all = 0;
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)) {
544 return status;
547 return r.out.result;