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 2 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, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 */
22
23 /*
24 when dealing with ACLs the file sharing client code needs to
25 sometimes make LSA RPC calls. This code provides an easy interface
26 for doing those calls.
27 */
28
29 #include "includes.h"
30 #include "libcli/raw/libcliraw.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
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 */
smblsa_connect(struct smbcli_state * cli)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->conn, lsa->ipc_tree, DCERPC_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, &dcerpc_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(lsa->pipe, lsa, &r);
122 if (!NT_STATUS_IS_OK(status)) {
123 talloc_free(lsa);
124 return status;
125 }
126
127 cli->lsa = lsa;
128
129 return NT_STATUS_OK;
130 }
131
132
133 /*
134 return the set of privileges for the given sid
135 */
smblsa_sid_privileges(struct smbcli_state * cli,struct dom_sid * sid,TALLOC_CTX * mem_ctx,struct lsa_RightSet * rights)136 NTSTATUS smblsa_sid_privileges(struct smbcli_state *cli, struct dom_sid *sid,
137 TALLOC_CTX *mem_ctx,
138 struct lsa_RightSet *rights)
139 {
140 NTSTATUS status;
141 struct lsa_EnumAccountRights r;
142
143 status = smblsa_connect(cli);
144 if (!NT_STATUS_IS_OK(status)) {
145 return status;
146 }
147
148 r.in.handle = &cli->lsa->handle;
149 r.in.sid = sid;
150 r.out.rights = rights;
151
152 return dcerpc_lsa_EnumAccountRights(cli->lsa->pipe, mem_ctx, &r);
153 }
154
155
156 /*
157 check if a named sid has a particular named privilege
158 */
smblsa_sid_check_privilege(struct smbcli_state * cli,const char * sid_str,const char * privilege)159 NTSTATUS smblsa_sid_check_privilege(struct smbcli_state *cli,
160 const char *sid_str,
161 const char *privilege)
162 {
163 struct lsa_RightSet rights;
164 NTSTATUS status;
165 TALLOC_CTX *mem_ctx = talloc_new(cli);
166 struct dom_sid *sid;
167 unsigned i;
168
169 sid = dom_sid_parse_talloc(mem_ctx, sid_str);
170 if (sid == NULL) {
171 talloc_free(mem_ctx);
172 return NT_STATUS_INVALID_SID;
173 }
174
175 status = smblsa_sid_privileges(cli, sid, mem_ctx, &rights);
176 if (!NT_STATUS_IS_OK(status)) {
177 talloc_free(mem_ctx);
178 return status;
179 }
180
181 for (i=0;i<rights.count;i++) {
182 if (strcmp(rights.names[i].string, privilege) == 0) {
183 talloc_free(mem_ctx);
184 return NT_STATUS_OK;
185 }
186 }
187
188 talloc_free(mem_ctx);
189 return NT_STATUS_NOT_FOUND;
190 }
191
192
193 /*
194 lookup a SID, returning its name
195 */
smblsa_lookup_sid(struct smbcli_state * cli,const char * sid_str,TALLOC_CTX * mem_ctx,const char ** name)196 NTSTATUS smblsa_lookup_sid(struct smbcli_state *cli,
197 const char *sid_str,
198 TALLOC_CTX *mem_ctx,
199 const char **name)
200 {
201 struct lsa_LookupSids r;
202 struct lsa_TransNameArray names;
203 struct lsa_SidArray sids;
204 uint32_t count = 1;
205 NTSTATUS status;
206 struct dom_sid *sid;
207 TALLOC_CTX *mem_ctx2 = talloc_new(mem_ctx);
208
209 status = smblsa_connect(cli);
210 if (!NT_STATUS_IS_OK(status)) {
211 return status;
212 }
213
214 sid = dom_sid_parse_talloc(mem_ctx2, sid_str);
215 if (sid == NULL) {
216 return NT_STATUS_INVALID_SID;
217 }
218
219 names.count = 0;
220 names.names = NULL;
221
222 sids.num_sids = 1;
223 sids.sids = talloc(mem_ctx2, struct lsa_SidPtr);
224 sids.sids[0].sid = sid;
225
226 r.in.handle = &cli->lsa->handle;
227 r.in.sids = &sids;
228 r.in.names = &names;
229 r.in.level = 1;
230 r.in.count = &count;
231 r.out.count = &count;
232 r.out.names = &names;
233
234 status = dcerpc_lsa_LookupSids(cli->lsa->pipe, mem_ctx2, &r);
235 if (!NT_STATUS_IS_OK(status)) {
236 talloc_free(mem_ctx2);
237 return status;
238 }
239 if (names.count != 1) {
240 talloc_free(mem_ctx2);
241 return NT_STATUS_UNSUCCESSFUL;
242 }
243
244 (*name) = talloc_asprintf(mem_ctx, "%s\\%s",
245 r.out.domains->domains[0].name.string,
246 names.names[0].name.string);
247
248 talloc_free(mem_ctx2);
249
250 return NT_STATUS_OK;
251 }
252
253 /*
254 lookup a name, returning its sid
255 */
smblsa_lookup_name(struct smbcli_state * cli,const char * name,TALLOC_CTX * mem_ctx,const char ** sid_str)256 NTSTATUS smblsa_lookup_name(struct smbcli_state *cli,
257 const char *name,
258 TALLOC_CTX *mem_ctx,
259 const char **sid_str)
260 {
261 struct lsa_LookupNames r;
262 struct lsa_TransSidArray sids;
263 struct lsa_String names;
264 uint32_t count = 1;
265 NTSTATUS status;
266 struct dom_sid *sid;
267 TALLOC_CTX *mem_ctx2 = talloc_new(mem_ctx);
268 uint32_t rid;
269
270 status = smblsa_connect(cli);
271 if (!NT_STATUS_IS_OK(status)) {
272 return status;
273 }
274
275 sids.count = 0;
276 sids.sids = NULL;
277
278 names.string = name;
279
280 r.in.handle = &cli->lsa->handle;
281 r.in.num_names = 1;
282 r.in.names = &names;
283 r.in.sids = &sids;
284 r.in.level = 1;
285 r.in.count = &count;
286 r.out.count = &count;
287 r.out.sids = &sids;
288
289 status = dcerpc_lsa_LookupNames(cli->lsa->pipe, mem_ctx2, &r);
290 if (!NT_STATUS_IS_OK(status)) {
291 talloc_free(mem_ctx2);
292 return status;
293 }
294 if (sids.count != 1) {
295 talloc_free(mem_ctx2);
296 return NT_STATUS_UNSUCCESSFUL;
297 }
298
299 sid = r.out.domains->domains[0].sid;
300 rid = sids.sids[0].rid;
301
302 (*sid_str) = talloc_asprintf(mem_ctx, "%s-%u",
303 dom_sid_string(mem_ctx2, sid), rid);
304
305 talloc_free(mem_ctx2);
306
307 return NT_STATUS_OK;
308 }
309
310
311 /*
312 add a set of privileges to the given sid
313 */
smblsa_sid_add_privileges(struct smbcli_state * cli,struct dom_sid * sid,TALLOC_CTX * mem_ctx,struct lsa_RightSet * rights)314 NTSTATUS smblsa_sid_add_privileges(struct smbcli_state *cli, struct dom_sid *sid,
315 TALLOC_CTX *mem_ctx,
316 struct lsa_RightSet *rights)
317 {
318 NTSTATUS status;
319 struct lsa_AddAccountRights r;
320
321 status = smblsa_connect(cli);
322 if (!NT_STATUS_IS_OK(status)) {
323 return status;
324 }
325
326 r.in.handle = &cli->lsa->handle;
327 r.in.sid = sid;
328 r.in.rights = rights;
329
330 return dcerpc_lsa_AddAccountRights(cli->lsa->pipe, mem_ctx, &r);
331 }
332
333 /*
334 remove a set of privileges from the given sid
335 */
smblsa_sid_del_privileges(struct smbcli_state * cli,struct dom_sid * sid,TALLOC_CTX * mem_ctx,struct lsa_RightSet * rights)336 NTSTATUS smblsa_sid_del_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_RemoveAccountRights 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.unknown = 0;
351 r.in.rights = rights;
352
353 return dcerpc_lsa_RemoveAccountRights(cli->lsa->pipe, mem_ctx, &r);
354 }
355