| 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 | }
 | 
|---|