0599c76f69429652923eaae93642372a035a2963
[samba.git] / source4 / libcli / util / clilsa.c
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/libcli.h"
31 #include "libcli/security/security.h"
32 #include "librpc/gen_ndr/ndr_lsa.h"
33 #include "librpc/gen_ndr/ndr_lsa_c.h"
34 #include "libcli/util/clilsa.h"
35 #include "libcli/smb/smbXcli_base.h"
36
37 struct smblsa_state {
38         struct dcerpc_binding_handle *binding_handle;
39         struct smbcli_tree *ipc_tree;
40         struct policy_handle handle;
41 };
42
43 /*
44   establish the lsa pipe connection
45 */
46 static NTSTATUS smblsa_connect(struct smbcli_state *cli)
47 {
48         struct smblsa_state *lsa;
49         struct dcerpc_pipe *lsa_pipe;
50         NTSTATUS status;
51         struct lsa_OpenPolicy r;
52         uint16_t system_name = '\\';
53         union smb_tcon tcon;
54         struct lsa_ObjectAttribute attr;
55         struct lsa_QosInfo qos;
56
57         if (cli->lsa != NULL) {
58                 return NT_STATUS_OK;
59         }
60
61         lsa = talloc(cli, struct smblsa_state);
62         if (lsa == NULL) {
63                 return NT_STATUS_NO_MEMORY;
64         }
65
66         lsa->ipc_tree = smbcli_tree_init(cli->session, lsa, false);
67         if (lsa->ipc_tree == NULL) {
68                 return NT_STATUS_NO_MEMORY;
69         }
70
71         /* connect to IPC$ */
72         tcon.generic.level = RAW_TCON_TCONX;
73         tcon.tconx.in.flags = TCONX_FLAG_EXTENDED_RESPONSE;
74         tcon.tconx.in.flags |= TCONX_FLAG_EXTENDED_SIGNATURES;
75         tcon.tconx.in.password = data_blob(NULL, 0);
76         tcon.tconx.in.path = "ipc$";
77         tcon.tconx.in.device = "IPC";   
78         status = smb_raw_tcon(lsa->ipc_tree, lsa, &tcon);
79         if (!NT_STATUS_IS_OK(status)) {
80                 talloc_free(lsa);
81                 return status;
82         }
83         lsa->ipc_tree->tid = tcon.tconx.out.tid;
84
85         if (tcon.tconx.out.options & SMB_EXTENDED_SIGNATURES) {
86                 smb1cli_session_protect_session_key(cli->session->smbXcli);
87         }
88
89         lsa_pipe = dcerpc_pipe_init(lsa, cli->transport->ev);
90         if (lsa_pipe == NULL) {
91                 talloc_free(lsa);
92                 return NT_STATUS_NO_MEMORY;
93         }
94
95         /* open the LSA pipe */
96         status = dcerpc_pipe_open_smb(lsa_pipe, lsa->ipc_tree, NDR_LSARPC_NAME);
97         if (!NT_STATUS_IS_OK(status)) {
98                 talloc_free(lsa);
99                 return status;
100         }
101
102         /* bind to the LSA pipe */
103         status = dcerpc_bind_auth_none(lsa_pipe, &ndr_table_lsarpc);
104         if (!NT_STATUS_IS_OK(status)) {
105                 talloc_free(lsa);
106                 return status;
107         }
108         lsa->binding_handle = lsa_pipe->binding_handle;
109
110         /* open a lsa policy handle */
111         qos.len = 0;
112         qos.impersonation_level = 2;
113         qos.context_mode = 1;
114         qos.effective_only = 0;
115
116         attr.len = 0;
117         attr.root_dir = NULL;
118         attr.object_name = NULL;
119         attr.attributes = 0;
120         attr.sec_desc = NULL;
121         attr.sec_qos = &qos;
122
123         r.in.system_name = &system_name;
124         r.in.attr = &attr;
125         r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
126         r.out.handle = &lsa->handle;
127
128         status = dcerpc_lsa_OpenPolicy_r(lsa->binding_handle, lsa, &r);
129         if (!NT_STATUS_IS_OK(status)) {
130                 talloc_free(lsa);
131                 return status;
132         }
133
134         if (!NT_STATUS_IS_OK(r.out.result)) {
135                 talloc_free(lsa);
136                 return r.out.result;
137         }
138
139         cli->lsa = lsa;
140         
141         return NT_STATUS_OK;
142 }
143
144
145 /*
146   return the set of privileges for the given sid
147 */
148 NTSTATUS smblsa_sid_privileges(struct smbcli_state *cli, struct dom_sid *sid, 
149                                TALLOC_CTX *mem_ctx,
150                                struct lsa_RightSet *rights)
151 {
152         NTSTATUS status;
153         struct lsa_EnumAccountRights r;
154
155         status = smblsa_connect(cli);
156         if (!NT_STATUS_IS_OK(status)) {
157                 return status;
158         }
159
160         r.in.handle = &cli->lsa->handle;
161         r.in.sid = sid;
162         r.out.rights = rights;
163
164         status = dcerpc_lsa_EnumAccountRights_r(cli->lsa->binding_handle, mem_ctx, &r);
165         if (!NT_STATUS_IS_OK(status)) {
166                 return status;
167         }
168
169         return r.out.result;
170 }
171
172
173 /*
174   check if a named sid has a particular named privilege
175 */
176 NTSTATUS smblsa_sid_check_privilege(struct smbcli_state *cli, 
177                                     const char *sid_str,
178                                     const char *privilege)
179 {
180         struct lsa_RightSet rights;
181         NTSTATUS status;
182         TALLOC_CTX *mem_ctx = talloc_new(cli);
183         struct dom_sid *sid;
184         unsigned i;
185
186         sid = dom_sid_parse_talloc(mem_ctx, sid_str);
187         if (sid == NULL) {
188                 talloc_free(mem_ctx);
189                 return NT_STATUS_INVALID_SID;
190         }
191
192         status = smblsa_sid_privileges(cli, sid, mem_ctx, &rights);
193         if (!NT_STATUS_IS_OK(status)) {
194                 talloc_free(mem_ctx);
195                 return status;
196         }
197
198         for (i=0;i<rights.count;i++) {
199                 if (strcmp(rights.names[i].string, privilege) == 0) {
200                         talloc_free(mem_ctx);
201                         return NT_STATUS_OK;
202                 }
203         }
204
205         talloc_free(mem_ctx);
206         return NT_STATUS_NOT_FOUND;
207 }
208
209
210 /*
211   lookup a SID, returning its name
212 */
213 NTSTATUS smblsa_lookup_sid(struct smbcli_state *cli, 
214                            const char *sid_str,
215                            TALLOC_CTX *mem_ctx,
216                            const char **name)
217 {
218         struct lsa_LookupSids r;
219         struct lsa_TransNameArray names;
220         struct lsa_SidArray sids;
221         struct lsa_RefDomainList *domains = NULL;
222         uint32_t count = 1;
223         NTSTATUS status;
224         struct dom_sid *sid;
225         TALLOC_CTX *mem_ctx2 = talloc_new(mem_ctx);
226
227         status = smblsa_connect(cli);
228         if (!NT_STATUS_IS_OK(status)) {
229                 return status;
230         }
231
232         sid = dom_sid_parse_talloc(mem_ctx2, sid_str);
233         if (sid == NULL) {
234                 return NT_STATUS_INVALID_SID;
235         }
236
237         names.count = 0;
238         names.names = NULL;
239
240         sids.num_sids = 1;
241         sids.sids = talloc(mem_ctx2, struct lsa_SidPtr);
242         sids.sids[0].sid = sid;
243
244         r.in.handle = &cli->lsa->handle;
245         r.in.sids = &sids;
246         r.in.names = &names;
247         r.in.level = 1;
248         r.in.count = &count;
249         r.out.count = &count;
250         r.out.names = &names;
251         r.out.domains = &domains;
252
253         status = dcerpc_lsa_LookupSids_r(cli->lsa->binding_handle, mem_ctx2, &r);
254         if (!NT_STATUS_IS_OK(status)) {
255                 talloc_free(mem_ctx2);
256                 return status;
257         }
258         if (!NT_STATUS_IS_OK(r.out.result)) {
259                 talloc_free(mem_ctx2);
260                 return r.out.result;
261         }
262         if (names.count != 1) {
263                 talloc_free(mem_ctx2);
264                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
265         }
266         if (domains == NULL) {
267                 talloc_free(mem_ctx2);
268                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
269         }
270         if (domains->count != 1) {
271                 talloc_free(mem_ctx2);
272                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
273         }
274         if (names.names[0].sid_index != UINT32_MAX &&
275             names.names[0].sid_index >= domains->count)
276         {
277                 talloc_free(mem_ctx2);
278                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
279         }
280
281         (*name) = talloc_asprintf(mem_ctx, "%s\\%s", 
282                                   domains->domains[0].name.string,
283                                   names.names[0].name.string);
284
285         talloc_free(mem_ctx2);
286
287         return NT_STATUS_OK;    
288 }
289
290 /*
291   lookup a name, returning its sid
292 */
293 NTSTATUS smblsa_lookup_name(struct smbcli_state *cli, 
294                             const char *name,
295                             TALLOC_CTX *mem_ctx,
296                             const char **sid_str)
297 {
298         struct lsa_LookupNames r;
299         struct lsa_TransSidArray sids;
300         struct lsa_String names;
301         struct lsa_RefDomainList *domains = NULL;
302         uint32_t count = 1;
303         NTSTATUS status;
304         struct dom_sid *sid;
305         TALLOC_CTX *mem_ctx2 = talloc_new(mem_ctx);
306         uint32_t rid;
307
308         status = smblsa_connect(cli);
309         if (!NT_STATUS_IS_OK(status)) {
310                 return status;
311         }
312
313         sids.count = 0;
314         sids.sids = NULL;
315
316         names.string = name;
317
318         r.in.handle = &cli->lsa->handle;
319         r.in.num_names = 1;
320         r.in.names = &names;
321         r.in.sids = &sids;
322         r.in.level = 1;
323         r.in.count = &count;
324         r.out.count = &count;
325         r.out.sids = &sids;
326         r.out.domains = &domains;
327
328         status = dcerpc_lsa_LookupNames_r(cli->lsa->binding_handle, mem_ctx2, &r);
329         if (!NT_STATUS_IS_OK(status)) {
330                 talloc_free(mem_ctx2);
331                 return status;
332         }
333         if (!NT_STATUS_IS_OK(r.out.result)) {
334                 talloc_free(mem_ctx2);
335                 return r.out.result;
336         }
337         if (sids.count != 1) {
338                 talloc_free(mem_ctx2);
339                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
340         }
341         if (domains->count != 1) {
342                 talloc_free(mem_ctx2);
343                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
344         }
345
346         sid = domains->domains[0].sid;
347         rid = sids.sids[0].rid;
348         
349         (*sid_str) = talloc_asprintf(mem_ctx, "%s-%u", 
350                                      dom_sid_string(mem_ctx2, sid), rid);
351
352         talloc_free(mem_ctx2);
353
354         return NT_STATUS_OK;    
355 }
356
357
358 /*
359   add a set of privileges to the given sid
360 */
361 NTSTATUS smblsa_sid_add_privileges(struct smbcli_state *cli, struct dom_sid *sid, 
362                                    TALLOC_CTX *mem_ctx,
363                                    struct lsa_RightSet *rights)
364 {
365         NTSTATUS status;
366         struct lsa_AddAccountRights r;
367
368         status = smblsa_connect(cli);
369         if (!NT_STATUS_IS_OK(status)) {
370                 return status;
371         }
372
373         r.in.handle = &cli->lsa->handle;
374         r.in.sid = sid;
375         r.in.rights = rights;
376
377         status = dcerpc_lsa_AddAccountRights_r(cli->lsa->binding_handle, mem_ctx, &r);
378         if (!NT_STATUS_IS_OK(status)) {
379                 return status;
380         }
381
382         return r.out.result;
383 }
384
385 /*
386   remove a set of privileges from the given sid
387 */
388 NTSTATUS smblsa_sid_del_privileges(struct smbcli_state *cli, struct dom_sid *sid, 
389                                    TALLOC_CTX *mem_ctx,
390                                    struct lsa_RightSet *rights)
391 {
392         NTSTATUS status;
393         struct lsa_RemoveAccountRights r;
394
395         status = smblsa_connect(cli);
396         if (!NT_STATUS_IS_OK(status)) {
397                 return status;
398         }
399
400         r.in.handle = &cli->lsa->handle;
401         r.in.sid = sid;
402         r.in.remove_all = 0;
403         r.in.rights = rights;
404
405         status = dcerpc_lsa_RemoveAccountRights_r(cli->lsa->binding_handle, mem_ctx, &r);
406         if (!NT_STATUS_IS_OK(status)) {
407                 return status;
408         }
409
410         return r.out.result;
411 }