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