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