Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 :
4 : lsa calls for file sharing connections
5 :
6 : Copyright (C) Andrew Tridgell 2004
7 :
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.
12 :
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.
17 :
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/>.
20 : */
21 :
22 : /*
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.
26 : */
27 :
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"
37 :
38 : struct smblsa_state {
39 : struct dcerpc_binding_handle *binding_handle;
40 : struct smbcli_tree *ipc_tree;
41 : struct policy_handle handle;
42 : };
43 :
44 : /*
45 : establish the lsa pipe connection
46 : */
47 110 : static NTSTATUS smblsa_connect(struct smbcli_state *cli)
48 : {
49 0 : struct smblsa_state *lsa;
50 0 : struct dcerpc_pipe *lsa_pipe;
51 0 : NTSTATUS status;
52 0 : struct lsa_OpenPolicy r;
53 110 : uint16_t system_name = '\\';
54 0 : union smb_tcon tcon;
55 0 : struct lsa_ObjectAttribute attr;
56 0 : struct lsa_QosInfo qos;
57 :
58 110 : if (cli->lsa != NULL) {
59 72 : return NT_STATUS_OK;
60 : }
61 :
62 38 : lsa = talloc(cli, struct smblsa_state);
63 38 : if (lsa == NULL) {
64 0 : return NT_STATUS_NO_MEMORY;
65 : }
66 :
67 38 : lsa->ipc_tree = smbcli_tree_init(cli->session, lsa, false);
68 38 : if (lsa->ipc_tree == NULL) {
69 0 : return NT_STATUS_NO_MEMORY;
70 : }
71 :
72 : /* connect to IPC$ */
73 38 : tcon.generic.level = RAW_TCON_TCONX;
74 38 : tcon.tconx.in.flags = TCONX_FLAG_EXTENDED_RESPONSE;
75 38 : tcon.tconx.in.flags |= TCONX_FLAG_EXTENDED_SIGNATURES;
76 38 : tcon.tconx.in.password = data_blob(NULL, 0);
77 38 : tcon.tconx.in.path = "ipc$";
78 38 : tcon.tconx.in.device = "IPC";
79 38 : status = smb_raw_tcon(lsa->ipc_tree, lsa, &tcon);
80 38 : if (!NT_STATUS_IS_OK(status)) {
81 0 : talloc_free(lsa);
82 0 : return status;
83 : }
84 38 : lsa->ipc_tree->tid = tcon.tconx.out.tid;
85 :
86 38 : if (tcon.tconx.out.options & SMB_EXTENDED_SIGNATURES) {
87 0 : smb1cli_session_protect_session_key(cli->session->smbXcli);
88 : }
89 :
90 38 : lsa_pipe = dcerpc_pipe_init(lsa, cli->transport->ev);
91 38 : if (lsa_pipe == NULL) {
92 0 : talloc_free(lsa);
93 0 : return NT_STATUS_NO_MEMORY;
94 : }
95 :
96 : /* open the LSA pipe */
97 38 : status = dcerpc_pipe_open_smb(lsa_pipe, lsa->ipc_tree, NDR_LSARPC_NAME);
98 38 : if (!NT_STATUS_IS_OK(status)) {
99 0 : talloc_free(lsa);
100 0 : return status;
101 : }
102 :
103 : /* bind to the LSA pipe */
104 38 : status = dcerpc_bind_auth_none(lsa_pipe, &ndr_table_lsarpc);
105 38 : if (!NT_STATUS_IS_OK(status)) {
106 0 : talloc_free(lsa);
107 0 : return status;
108 : }
109 38 : lsa->binding_handle = lsa_pipe->binding_handle;
110 :
111 : /* open a lsa policy handle */
112 38 : qos.len = 0;
113 38 : qos.impersonation_level = 2;
114 38 : qos.context_mode = 1;
115 38 : qos.effective_only = 0;
116 :
117 38 : attr.len = 0;
118 38 : attr.root_dir = NULL;
119 38 : attr.object_name = NULL;
120 38 : attr.attributes = 0;
121 38 : attr.sec_desc = NULL;
122 38 : attr.sec_qos = &qos;
123 :
124 38 : r.in.system_name = &system_name;
125 38 : r.in.attr = &attr;
126 38 : r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
127 38 : r.out.handle = &lsa->handle;
128 :
129 38 : status = dcerpc_lsa_OpenPolicy_r(lsa->binding_handle, lsa, &r);
130 38 : if (!NT_STATUS_IS_OK(status)) {
131 0 : talloc_free(lsa);
132 0 : return status;
133 : }
134 :
135 38 : if (!NT_STATUS_IS_OK(r.out.result)) {
136 0 : talloc_free(lsa);
137 0 : return r.out.result;
138 : }
139 :
140 38 : cli->lsa = lsa;
141 :
142 38 : return NT_STATUS_OK;
143 : }
144 :
145 :
146 6 : static NTSTATUS smb2lsa_connect(struct smb2_tree *tree)
147 : {
148 6 : struct smb2lsa_state *lsa = NULL;
149 6 : struct dcerpc_pipe *lsa_pipe = NULL;
150 0 : NTSTATUS status;
151 6 : struct lsa_OpenPolicy2 r = {{0}, {0}};
152 6 : const char *system_name = "\\";
153 6 : struct lsa_ObjectAttribute attr = {0};
154 6 : struct lsa_QosInfo qos = {0};
155 :
156 6 : if (tree->lsa != NULL) {
157 0 : return NT_STATUS_OK;
158 : }
159 :
160 6 : lsa = talloc(tree, struct smb2lsa_state);
161 6 : if (lsa == NULL) {
162 0 : return NT_STATUS_NO_MEMORY;
163 : }
164 :
165 6 : lsa_pipe = dcerpc_pipe_init(lsa, tree->session->transport->ev);
166 6 : if (lsa_pipe == NULL) {
167 0 : talloc_free(lsa);
168 0 : return NT_STATUS_NO_MEMORY;
169 : }
170 :
171 : /* open the LSA pipe */
172 6 : status = dcerpc_pipe_open_smb2(lsa_pipe, tree, NDR_LSARPC_NAME);
173 6 : if (!NT_STATUS_IS_OK(status)) {
174 6 : talloc_free(lsa);
175 6 : return status;
176 : }
177 :
178 : /* bind to the LSA pipe */
179 0 : status = dcerpc_bind_auth_none(lsa_pipe, &ndr_table_lsarpc);
180 0 : if (!NT_STATUS_IS_OK(status)) {
181 0 : talloc_free(lsa);
182 0 : return status;
183 : }
184 0 : lsa->binding_handle = lsa_pipe->binding_handle;
185 :
186 : /* open a lsa policy handle */
187 0 : qos.len = 0;
188 0 : qos.impersonation_level = 2;
189 0 : qos.context_mode = 1;
190 0 : qos.effective_only = 0;
191 :
192 0 : attr.len = 0;
193 0 : attr.root_dir = NULL;
194 0 : attr.object_name = NULL;
195 0 : attr.attributes = 0;
196 0 : attr.sec_desc = NULL;
197 0 : attr.sec_qos = &qos;
198 :
199 0 : r.in.system_name = system_name;
200 0 : r.in.attr = &attr;
201 0 : r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
202 0 : r.out.handle = &lsa->handle;
203 :
204 0 : status = dcerpc_lsa_OpenPolicy2_r(lsa->binding_handle, lsa, &r);
205 0 : if (!NT_STATUS_IS_OK(status)) {
206 0 : talloc_free(lsa);
207 0 : return status;
208 : }
209 :
210 0 : if (!NT_STATUS_IS_OK(r.out.result)) {
211 0 : talloc_free(lsa);
212 0 : return r.out.result;
213 : }
214 :
215 0 : tree->lsa = lsa;
216 :
217 0 : return NT_STATUS_OK;
218 : }
219 :
220 :
221 : /*
222 : return the set of privileges for the given sid
223 : */
224 108 : NTSTATUS smblsa_sid_privileges(struct smbcli_state *cli, struct dom_sid *sid,
225 : TALLOC_CTX *mem_ctx,
226 : struct lsa_RightSet *rights)
227 : {
228 0 : NTSTATUS status;
229 0 : struct lsa_EnumAccountRights r;
230 :
231 108 : status = smblsa_connect(cli);
232 108 : if (!NT_STATUS_IS_OK(status)) {
233 0 : return status;
234 : }
235 :
236 108 : r.in.handle = &cli->lsa->handle;
237 108 : r.in.sid = sid;
238 108 : r.out.rights = rights;
239 :
240 108 : status = dcerpc_lsa_EnumAccountRights_r(cli->lsa->binding_handle, mem_ctx, &r);
241 108 : if (!NT_STATUS_IS_OK(status)) {
242 0 : return status;
243 : }
244 :
245 108 : return r.out.result;
246 : }
247 :
248 :
249 6 : NTSTATUS smb2lsa_sid_privileges(struct smb2_tree *tree, struct dom_sid *sid,
250 : TALLOC_CTX *mem_ctx,
251 : struct lsa_RightSet *rights)
252 : {
253 0 : NTSTATUS status;
254 6 : struct lsa_EnumAccountRights r = {{0}, {0}};
255 :
256 6 : status = smb2lsa_connect(tree);
257 6 : if (!NT_STATUS_IS_OK(status)) {
258 6 : return status;
259 : }
260 :
261 0 : r.in.handle = &tree->lsa->handle;
262 0 : r.in.sid = sid;
263 0 : r.out.rights = rights;
264 :
265 0 : status = dcerpc_lsa_EnumAccountRights_r(tree->lsa->binding_handle, mem_ctx, &r);
266 0 : if (!NT_STATUS_IS_OK(status)) {
267 0 : return status;
268 : }
269 :
270 0 : return r.out.result;
271 : }
272 :
273 :
274 : /*
275 : check if a named sid has a particular named privilege
276 : */
277 108 : NTSTATUS smblsa_sid_check_privilege(struct smbcli_state *cli,
278 : const char *sid_str,
279 : const char *privilege)
280 : {
281 0 : struct lsa_RightSet rights;
282 0 : NTSTATUS status;
283 108 : TALLOC_CTX *mem_ctx = talloc_new(cli);
284 0 : struct dom_sid *sid;
285 0 : unsigned i;
286 :
287 108 : sid = dom_sid_parse_talloc(mem_ctx, sid_str);
288 108 : if (sid == NULL) {
289 0 : talloc_free(mem_ctx);
290 0 : return NT_STATUS_INVALID_SID;
291 : }
292 :
293 108 : status = smblsa_sid_privileges(cli, sid, mem_ctx, &rights);
294 108 : if (!NT_STATUS_IS_OK(status)) {
295 96 : talloc_free(mem_ctx);
296 96 : return status;
297 : }
298 :
299 60 : for (i=0;i<rights.count;i++) {
300 60 : if (strcmp(rights.names[i].string, privilege) == 0) {
301 12 : talloc_free(mem_ctx);
302 12 : return NT_STATUS_OK;
303 : }
304 : }
305 :
306 0 : talloc_free(mem_ctx);
307 0 : return NT_STATUS_NOT_FOUND;
308 : }
309 :
310 :
311 6 : NTSTATUS smb2lsa_sid_check_privilege(struct smb2_tree *tree,
312 : const char *sid_str,
313 : const char *privilege)
314 : {
315 6 : struct lsa_RightSet rights = {0};
316 0 : NTSTATUS status;
317 6 : TALLOC_CTX *mem_ctx = NULL;
318 6 : struct dom_sid *sid = NULL;
319 0 : unsigned i;
320 :
321 6 : mem_ctx = talloc_new(tree);
322 6 : if (!mem_ctx) {
323 0 : return NT_STATUS_NO_MEMORY;
324 : }
325 :
326 6 : sid = dom_sid_parse_talloc(mem_ctx, sid_str);
327 6 : if (sid == NULL) {
328 0 : talloc_free(mem_ctx);
329 0 : return NT_STATUS_INVALID_SID;
330 : }
331 :
332 6 : status = smb2lsa_sid_privileges(tree, sid, mem_ctx, &rights);
333 6 : if (!NT_STATUS_IS_OK(status)) {
334 6 : talloc_free(mem_ctx);
335 6 : return status;
336 : }
337 :
338 0 : for (i=0;i<rights.count;i++) {
339 0 : if (strcmp(rights.names[i].string, privilege) == 0) {
340 0 : talloc_free(mem_ctx);
341 0 : return NT_STATUS_OK;
342 : }
343 : }
344 :
345 0 : talloc_free(mem_ctx);
346 0 : return NT_STATUS_NOT_FOUND;
347 : }
348 :
349 :
350 : /*
351 : lookup a SID, returning its name
352 : */
353 0 : NTSTATUS smblsa_lookup_sid(struct smbcli_state *cli,
354 : const char *sid_str,
355 : TALLOC_CTX *mem_ctx,
356 : const char **name)
357 : {
358 0 : struct lsa_LookupSids r;
359 0 : struct lsa_TransNameArray names;
360 0 : struct lsa_SidArray sids;
361 0 : struct lsa_RefDomainList *domains = NULL;
362 0 : uint32_t count = 1;
363 0 : NTSTATUS status;
364 0 : struct dom_sid *sid;
365 0 : TALLOC_CTX *mem_ctx2 = talloc_new(mem_ctx);
366 :
367 0 : status = smblsa_connect(cli);
368 0 : if (!NT_STATUS_IS_OK(status)) {
369 0 : return status;
370 : }
371 :
372 0 : sid = dom_sid_parse_talloc(mem_ctx2, sid_str);
373 0 : if (sid == NULL) {
374 0 : return NT_STATUS_INVALID_SID;
375 : }
376 :
377 0 : names.count = 0;
378 0 : names.names = NULL;
379 :
380 0 : sids.num_sids = 1;
381 0 : sids.sids = talloc(mem_ctx2, struct lsa_SidPtr);
382 0 : sids.sids[0].sid = sid;
383 :
384 0 : r.in.handle = &cli->lsa->handle;
385 0 : r.in.sids = &sids;
386 0 : r.in.names = &names;
387 0 : r.in.level = 1;
388 0 : r.in.count = &count;
389 0 : r.out.count = &count;
390 0 : r.out.names = &names;
391 0 : r.out.domains = &domains;
392 :
393 0 : status = dcerpc_lsa_LookupSids_r(cli->lsa->binding_handle, mem_ctx2, &r);
394 0 : if (!NT_STATUS_IS_OK(status)) {
395 0 : talloc_free(mem_ctx2);
396 0 : return status;
397 : }
398 0 : if (!NT_STATUS_IS_OK(r.out.result)) {
399 0 : talloc_free(mem_ctx2);
400 0 : return r.out.result;
401 : }
402 0 : if (names.count != 1) {
403 0 : talloc_free(mem_ctx2);
404 0 : return NT_STATUS_INVALID_NETWORK_RESPONSE;
405 : }
406 0 : if (domains == NULL) {
407 0 : talloc_free(mem_ctx2);
408 0 : return NT_STATUS_INVALID_NETWORK_RESPONSE;
409 : }
410 0 : if (domains->count != 1) {
411 0 : talloc_free(mem_ctx2);
412 0 : return NT_STATUS_INVALID_NETWORK_RESPONSE;
413 : }
414 0 : if (names.names[0].sid_index != UINT32_MAX &&
415 0 : names.names[0].sid_index >= domains->count)
416 : {
417 0 : talloc_free(mem_ctx2);
418 0 : return NT_STATUS_INVALID_NETWORK_RESPONSE;
419 : }
420 :
421 0 : (*name) = talloc_asprintf(mem_ctx, "%s\\%s",
422 0 : domains->domains[0].name.string,
423 0 : names.names[0].name.string);
424 :
425 0 : talloc_free(mem_ctx2);
426 :
427 0 : return NT_STATUS_OK;
428 : }
429 :
430 : /*
431 : lookup a name, returning its sid
432 : */
433 2 : NTSTATUS smblsa_lookup_name(struct smbcli_state *cli,
434 : const char *name,
435 : TALLOC_CTX *mem_ctx,
436 : const char **sid_str)
437 : {
438 0 : struct lsa_LookupNames r;
439 0 : struct lsa_TransSidArray sids;
440 0 : struct lsa_String names;
441 2 : struct lsa_RefDomainList *domains = NULL;
442 2 : uint32_t count = 1;
443 0 : NTSTATUS status;
444 0 : struct dom_sid sid;
445 2 : TALLOC_CTX *mem_ctx2 = talloc_new(mem_ctx);
446 :
447 2 : status = smblsa_connect(cli);
448 2 : if (!NT_STATUS_IS_OK(status)) {
449 0 : return status;
450 : }
451 :
452 2 : sids.count = 0;
453 2 : sids.sids = NULL;
454 :
455 2 : names.string = name;
456 :
457 2 : r.in.handle = &cli->lsa->handle;
458 2 : r.in.num_names = 1;
459 2 : r.in.names = &names;
460 2 : r.in.sids = &sids;
461 2 : r.in.level = 1;
462 2 : r.in.count = &count;
463 2 : r.out.count = &count;
464 2 : r.out.sids = &sids;
465 2 : r.out.domains = &domains;
466 :
467 2 : status = dcerpc_lsa_LookupNames_r(cli->lsa->binding_handle, mem_ctx2, &r);
468 2 : if (!NT_STATUS_IS_OK(status)) {
469 0 : talloc_free(mem_ctx2);
470 0 : return status;
471 : }
472 2 : if (!NT_STATUS_IS_OK(r.out.result)) {
473 0 : talloc_free(mem_ctx2);
474 0 : return r.out.result;
475 : }
476 2 : if (sids.count != 1) {
477 0 : talloc_free(mem_ctx2);
478 0 : return NT_STATUS_INVALID_NETWORK_RESPONSE;
479 : }
480 2 : if (domains->count != 1) {
481 0 : talloc_free(mem_ctx2);
482 0 : return NT_STATUS_INVALID_NETWORK_RESPONSE;
483 : }
484 :
485 2 : sid_compose(&sid, domains->domains[0].sid, sids.sids[0].rid);
486 :
487 2 : (*sid_str) = dom_sid_string(mem_ctx, &sid);
488 :
489 2 : talloc_free(mem_ctx2);
490 :
491 2 : return NT_STATUS_OK;
492 : }
493 :
494 :
495 : /*
496 : add a set of privileges to the given sid
497 : */
498 0 : NTSTATUS smblsa_sid_add_privileges(struct smbcli_state *cli, struct dom_sid *sid,
499 : TALLOC_CTX *mem_ctx,
500 : struct lsa_RightSet *rights)
501 : {
502 0 : NTSTATUS status;
503 0 : struct lsa_AddAccountRights r;
504 :
505 0 : status = smblsa_connect(cli);
506 0 : if (!NT_STATUS_IS_OK(status)) {
507 0 : return status;
508 : }
509 :
510 0 : r.in.handle = &cli->lsa->handle;
511 0 : r.in.sid = sid;
512 0 : r.in.rights = rights;
513 :
514 0 : status = dcerpc_lsa_AddAccountRights_r(cli->lsa->binding_handle, mem_ctx, &r);
515 0 : if (!NT_STATUS_IS_OK(status)) {
516 0 : return status;
517 : }
518 :
519 0 : return r.out.result;
520 : }
521 :
522 : /*
523 : remove a set of privileges from the given sid
524 : */
525 0 : NTSTATUS smblsa_sid_del_privileges(struct smbcli_state *cli, struct dom_sid *sid,
526 : TALLOC_CTX *mem_ctx,
527 : struct lsa_RightSet *rights)
528 : {
529 0 : NTSTATUS status;
530 0 : struct lsa_RemoveAccountRights r;
531 :
532 0 : status = smblsa_connect(cli);
533 0 : if (!NT_STATUS_IS_OK(status)) {
534 0 : return status;
535 : }
536 :
537 0 : r.in.handle = &cli->lsa->handle;
538 0 : r.in.sid = sid;
539 0 : r.in.remove_all = 0;
540 0 : r.in.rights = rights;
541 :
542 0 : status = dcerpc_lsa_RemoveAccountRights_r(cli->lsa->binding_handle, mem_ctx, &r);
543 0 : if (!NT_STATUS_IS_OK(status)) {
544 0 : return status;
545 : }
546 :
547 0 : return r.out.result;
548 : }
|