| 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 | cli->transport->iconv_convenience);
|
|---|
| 84 | if (lsa->pipe == NULL) {
|
|---|
| 85 | talloc_free(lsa);
|
|---|
| 86 | return NT_STATUS_NO_MEMORY;
|
|---|
| 87 | }
|
|---|
| 88 |
|
|---|
| 89 | /* open the LSA pipe */
|
|---|
| 90 | status = dcerpc_pipe_open_smb(lsa->pipe, lsa->ipc_tree, NDR_LSARPC_NAME);
|
|---|
| 91 | if (!NT_STATUS_IS_OK(status)) {
|
|---|
| 92 | talloc_free(lsa);
|
|---|
| 93 | return status;
|
|---|
| 94 | }
|
|---|
| 95 |
|
|---|
| 96 | /* bind to the LSA pipe */
|
|---|
| 97 | status = dcerpc_bind_auth_none(lsa->pipe, &ndr_table_lsarpc);
|
|---|
| 98 | if (!NT_STATUS_IS_OK(status)) {
|
|---|
| 99 | talloc_free(lsa);
|
|---|
| 100 | return status;
|
|---|
| 101 | }
|
|---|
| 102 |
|
|---|
| 103 |
|
|---|
| 104 | /* open a lsa policy handle */
|
|---|
| 105 | qos.len = 0;
|
|---|
| 106 | qos.impersonation_level = 2;
|
|---|
| 107 | qos.context_mode = 1;
|
|---|
| 108 | qos.effective_only = 0;
|
|---|
| 109 |
|
|---|
| 110 | attr.len = 0;
|
|---|
| 111 | attr.root_dir = NULL;
|
|---|
| 112 | attr.object_name = NULL;
|
|---|
| 113 | attr.attributes = 0;
|
|---|
| 114 | attr.sec_desc = NULL;
|
|---|
| 115 | attr.sec_qos = &qos;
|
|---|
| 116 |
|
|---|
| 117 | r.in.system_name = &system_name;
|
|---|
| 118 | r.in.attr = &attr;
|
|---|
| 119 | r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
|
|---|
| 120 | r.out.handle = &lsa->handle;
|
|---|
| 121 |
|
|---|
| 122 | status = dcerpc_lsa_OpenPolicy(lsa->pipe, lsa, &r);
|
|---|
| 123 | if (!NT_STATUS_IS_OK(status)) {
|
|---|
| 124 | talloc_free(lsa);
|
|---|
| 125 | return status;
|
|---|
| 126 | }
|
|---|
| 127 |
|
|---|
| 128 | cli->lsa = lsa;
|
|---|
| 129 |
|
|---|
| 130 | return NT_STATUS_OK;
|
|---|
| 131 | }
|
|---|
| 132 |
|
|---|
| 133 |
|
|---|
| 134 | /*
|
|---|
| 135 | return the set of privileges for the given sid
|
|---|
| 136 | */
|
|---|
| 137 | NTSTATUS smblsa_sid_privileges(struct smbcli_state *cli, struct dom_sid *sid,
|
|---|
| 138 | TALLOC_CTX *mem_ctx,
|
|---|
| 139 | struct lsa_RightSet *rights)
|
|---|
| 140 | {
|
|---|
| 141 | NTSTATUS status;
|
|---|
| 142 | struct lsa_EnumAccountRights r;
|
|---|
| 143 |
|
|---|
| 144 | status = smblsa_connect(cli);
|
|---|
| 145 | if (!NT_STATUS_IS_OK(status)) {
|
|---|
| 146 | return status;
|
|---|
| 147 | }
|
|---|
| 148 |
|
|---|
| 149 | r.in.handle = &cli->lsa->handle;
|
|---|
| 150 | r.in.sid = sid;
|
|---|
| 151 | r.out.rights = rights;
|
|---|
| 152 |
|
|---|
| 153 | return dcerpc_lsa_EnumAccountRights(cli->lsa->pipe, mem_ctx, &r);
|
|---|
| 154 | }
|
|---|
| 155 |
|
|---|
| 156 |
|
|---|
| 157 | /*
|
|---|
| 158 | check if a named sid has a particular named privilege
|
|---|
| 159 | */
|
|---|
| 160 | NTSTATUS smblsa_sid_check_privilege(struct smbcli_state *cli,
|
|---|
| 161 | const char *sid_str,
|
|---|
| 162 | const char *privilege)
|
|---|
| 163 | {
|
|---|
| 164 | struct lsa_RightSet rights;
|
|---|
| 165 | NTSTATUS status;
|
|---|
| 166 | TALLOC_CTX *mem_ctx = talloc_new(cli);
|
|---|
| 167 | struct dom_sid *sid;
|
|---|
| 168 | unsigned i;
|
|---|
| 169 |
|
|---|
| 170 | sid = dom_sid_parse_talloc(mem_ctx, sid_str);
|
|---|
| 171 | if (sid == NULL) {
|
|---|
| 172 | talloc_free(mem_ctx);
|
|---|
| 173 | return NT_STATUS_INVALID_SID;
|
|---|
| 174 | }
|
|---|
| 175 |
|
|---|
| 176 | status = smblsa_sid_privileges(cli, sid, mem_ctx, &rights);
|
|---|
| 177 | if (!NT_STATUS_IS_OK(status)) {
|
|---|
| 178 | talloc_free(mem_ctx);
|
|---|
| 179 | return status;
|
|---|
| 180 | }
|
|---|
| 181 |
|
|---|
| 182 | for (i=0;i<rights.count;i++) {
|
|---|
| 183 | if (strcmp(rights.names[i].string, privilege) == 0) {
|
|---|
| 184 | talloc_free(mem_ctx);
|
|---|
| 185 | return NT_STATUS_OK;
|
|---|
| 186 | }
|
|---|
| 187 | }
|
|---|
| 188 |
|
|---|
| 189 | talloc_free(mem_ctx);
|
|---|
| 190 | return NT_STATUS_NOT_FOUND;
|
|---|
| 191 | }
|
|---|
| 192 |
|
|---|
| 193 |
|
|---|
| 194 | /*
|
|---|
| 195 | lookup a SID, returning its name
|
|---|
| 196 | */
|
|---|
| 197 | NTSTATUS smblsa_lookup_sid(struct smbcli_state *cli,
|
|---|
| 198 | const char *sid_str,
|
|---|
| 199 | TALLOC_CTX *mem_ctx,
|
|---|
| 200 | const char **name)
|
|---|
| 201 | {
|
|---|
| 202 | struct lsa_LookupSids r;
|
|---|
| 203 | struct lsa_TransNameArray names;
|
|---|
| 204 | struct lsa_SidArray sids;
|
|---|
| 205 | struct lsa_RefDomainList *domains = NULL;
|
|---|
| 206 | uint32_t count = 1;
|
|---|
| 207 | NTSTATUS status;
|
|---|
| 208 | struct dom_sid *sid;
|
|---|
| 209 | TALLOC_CTX *mem_ctx2 = talloc_new(mem_ctx);
|
|---|
| 210 |
|
|---|
| 211 | status = smblsa_connect(cli);
|
|---|
| 212 | if (!NT_STATUS_IS_OK(status)) {
|
|---|
| 213 | return status;
|
|---|
| 214 | }
|
|---|
| 215 |
|
|---|
| 216 | sid = dom_sid_parse_talloc(mem_ctx2, sid_str);
|
|---|
| 217 | if (sid == NULL) {
|
|---|
| 218 | return NT_STATUS_INVALID_SID;
|
|---|
| 219 | }
|
|---|
| 220 |
|
|---|
| 221 | names.count = 0;
|
|---|
| 222 | names.names = NULL;
|
|---|
| 223 |
|
|---|
| 224 | sids.num_sids = 1;
|
|---|
| 225 | sids.sids = talloc(mem_ctx2, struct lsa_SidPtr);
|
|---|
| 226 | sids.sids[0].sid = sid;
|
|---|
| 227 |
|
|---|
| 228 | r.in.handle = &cli->lsa->handle;
|
|---|
| 229 | r.in.sids = &sids;
|
|---|
| 230 | r.in.names = &names;
|
|---|
| 231 | r.in.level = 1;
|
|---|
| 232 | r.in.count = &count;
|
|---|
| 233 | r.out.count = &count;
|
|---|
| 234 | r.out.names = &names;
|
|---|
| 235 | r.out.domains = &domains;
|
|---|
| 236 |
|
|---|
| 237 | status = dcerpc_lsa_LookupSids(cli->lsa->pipe, mem_ctx2, &r);
|
|---|
| 238 | if (!NT_STATUS_IS_OK(status)) {
|
|---|
| 239 | talloc_free(mem_ctx2);
|
|---|
| 240 | return status;
|
|---|
| 241 | }
|
|---|
| 242 | if (names.count != 1) {
|
|---|
| 243 | talloc_free(mem_ctx2);
|
|---|
| 244 | return NT_STATUS_UNSUCCESSFUL;
|
|---|
| 245 | }
|
|---|
| 246 |
|
|---|
| 247 | (*name) = talloc_asprintf(mem_ctx, "%s\\%s",
|
|---|
| 248 | domains->domains[0].name.string,
|
|---|
| 249 | names.names[0].name.string);
|
|---|
| 250 |
|
|---|
| 251 | talloc_free(mem_ctx2);
|
|---|
| 252 |
|
|---|
| 253 | return NT_STATUS_OK;
|
|---|
| 254 | }
|
|---|
| 255 |
|
|---|
| 256 | /*
|
|---|
| 257 | lookup a name, returning its sid
|
|---|
| 258 | */
|
|---|
| 259 | NTSTATUS smblsa_lookup_name(struct smbcli_state *cli,
|
|---|
| 260 | const char *name,
|
|---|
| 261 | TALLOC_CTX *mem_ctx,
|
|---|
| 262 | const char **sid_str)
|
|---|
| 263 | {
|
|---|
| 264 | struct lsa_LookupNames r;
|
|---|
| 265 | struct lsa_TransSidArray sids;
|
|---|
| 266 | struct lsa_String names;
|
|---|
| 267 | struct lsa_RefDomainList *domains = NULL;
|
|---|
| 268 | uint32_t count = 1;
|
|---|
| 269 | NTSTATUS status;
|
|---|
| 270 | struct dom_sid *sid;
|
|---|
| 271 | TALLOC_CTX *mem_ctx2 = talloc_new(mem_ctx);
|
|---|
| 272 | uint32_t rid;
|
|---|
| 273 |
|
|---|
| 274 | status = smblsa_connect(cli);
|
|---|
| 275 | if (!NT_STATUS_IS_OK(status)) {
|
|---|
| 276 | return status;
|
|---|
| 277 | }
|
|---|
| 278 |
|
|---|
| 279 | sids.count = 0;
|
|---|
| 280 | sids.sids = NULL;
|
|---|
| 281 |
|
|---|
| 282 | names.string = name;
|
|---|
| 283 |
|
|---|
| 284 | r.in.handle = &cli->lsa->handle;
|
|---|
| 285 | r.in.num_names = 1;
|
|---|
| 286 | r.in.names = &names;
|
|---|
| 287 | r.in.sids = &sids;
|
|---|
| 288 | r.in.level = 1;
|
|---|
| 289 | r.in.count = &count;
|
|---|
| 290 | r.out.count = &count;
|
|---|
| 291 | r.out.sids = &sids;
|
|---|
| 292 | r.out.domains = &domains;
|
|---|
| 293 |
|
|---|
| 294 | status = dcerpc_lsa_LookupNames(cli->lsa->pipe, mem_ctx2, &r);
|
|---|
| 295 | if (!NT_STATUS_IS_OK(status)) {
|
|---|
| 296 | talloc_free(mem_ctx2);
|
|---|
| 297 | return status;
|
|---|
| 298 | }
|
|---|
| 299 | if (sids.count != 1) {
|
|---|
| 300 | talloc_free(mem_ctx2);
|
|---|
| 301 | return NT_STATUS_UNSUCCESSFUL;
|
|---|
| 302 | }
|
|---|
| 303 |
|
|---|
| 304 | sid = domains->domains[0].sid;
|
|---|
| 305 | rid = sids.sids[0].rid;
|
|---|
| 306 |
|
|---|
| 307 | (*sid_str) = talloc_asprintf(mem_ctx, "%s-%u",
|
|---|
| 308 | dom_sid_string(mem_ctx2, sid), rid);
|
|---|
| 309 |
|
|---|
| 310 | talloc_free(mem_ctx2);
|
|---|
| 311 |
|
|---|
| 312 | return NT_STATUS_OK;
|
|---|
| 313 | }
|
|---|
| 314 |
|
|---|
| 315 |
|
|---|
| 316 | /*
|
|---|
| 317 | add a set of privileges to the given sid
|
|---|
| 318 | */
|
|---|
| 319 | NTSTATUS smblsa_sid_add_privileges(struct smbcli_state *cli, struct dom_sid *sid,
|
|---|
| 320 | TALLOC_CTX *mem_ctx,
|
|---|
| 321 | struct lsa_RightSet *rights)
|
|---|
| 322 | {
|
|---|
| 323 | NTSTATUS status;
|
|---|
| 324 | struct lsa_AddAccountRights r;
|
|---|
| 325 |
|
|---|
| 326 | status = smblsa_connect(cli);
|
|---|
| 327 | if (!NT_STATUS_IS_OK(status)) {
|
|---|
| 328 | return status;
|
|---|
| 329 | }
|
|---|
| 330 |
|
|---|
| 331 | r.in.handle = &cli->lsa->handle;
|
|---|
| 332 | r.in.sid = sid;
|
|---|
| 333 | r.in.rights = rights;
|
|---|
| 334 |
|
|---|
| 335 | return dcerpc_lsa_AddAccountRights(cli->lsa->pipe, mem_ctx, &r);
|
|---|
| 336 | }
|
|---|
| 337 |
|
|---|
| 338 | /*
|
|---|
| 339 | remove a set of privileges from the given sid
|
|---|
| 340 | */
|
|---|
| 341 | NTSTATUS smblsa_sid_del_privileges(struct smbcli_state *cli, struct dom_sid *sid,
|
|---|
| 342 | TALLOC_CTX *mem_ctx,
|
|---|
| 343 | struct lsa_RightSet *rights)
|
|---|
| 344 | {
|
|---|
| 345 | NTSTATUS status;
|
|---|
| 346 | struct lsa_RemoveAccountRights r;
|
|---|
| 347 |
|
|---|
| 348 | status = smblsa_connect(cli);
|
|---|
| 349 | if (!NT_STATUS_IS_OK(status)) {
|
|---|
| 350 | return status;
|
|---|
| 351 | }
|
|---|
| 352 |
|
|---|
| 353 | r.in.handle = &cli->lsa->handle;
|
|---|
| 354 | r.in.sid = sid;
|
|---|
| 355 | r.in.remove_all = 0;
|
|---|
| 356 | r.in.rights = rights;
|
|---|
| 357 |
|
|---|
| 358 | return dcerpc_lsa_RemoveAccountRights(cli->lsa->pipe, mem_ctx, &r);
|
|---|
| 359 | }
|
|---|