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