1fe1c642dSBill Krier /* 2fe1c642dSBill Krier * CDDL HEADER START 3fe1c642dSBill Krier * 4fe1c642dSBill Krier * The contents of this file are subject to the terms of the 5fe1c642dSBill Krier * Common Development and Distribution License (the "License"). 6fe1c642dSBill Krier * You may not use this file except in compliance with the License. 7fe1c642dSBill Krier * 8fe1c642dSBill Krier * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9fe1c642dSBill Krier * or http://www.opensolaris.org/os/licensing. 10fe1c642dSBill Krier * See the License for the specific language governing permissions 11fe1c642dSBill Krier * and limitations under the License. 12fe1c642dSBill Krier * 13fe1c642dSBill Krier * When distributing Covered Code, include this CDDL HEADER in each 14fe1c642dSBill Krier * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15fe1c642dSBill Krier * If applicable, add the following below this CDDL HEADER, with the 16fe1c642dSBill Krier * fields enclosed by brackets "[]" replaced with your own identifying 17fe1c642dSBill Krier * information: Portions Copyright [yyyy] [name of copyright owner] 18fe1c642dSBill Krier * 19fe1c642dSBill Krier * CDDL HEADER END 20fe1c642dSBill Krier */ 21148c5f43SAlan Wright 22fe1c642dSBill Krier /* 23148c5f43SAlan Wright * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. 24*b3700b07SGordon Ross * Copyright 2014 Nexenta Systems, Inc. All rights reserved. 25fe1c642dSBill Krier */ 26fe1c642dSBill Krier 27fe1c642dSBill Krier /* 28fe1c642dSBill Krier * Security Accounts Manager RPC (SAMR) client-side interface. 29fe1c642dSBill Krier * 30fe1c642dSBill Krier * The SAM is a hierarchical database: 31fe1c642dSBill Krier * - If you want to talk to the SAM you need a SAM handle. 32fe1c642dSBill Krier * - If you want to work with a domain, use the SAM handle. 33fe1c642dSBill Krier * to obtain a domain handle. 34fe1c642dSBill Krier * - Use domain handles to obtain user handles etc. 35fe1c642dSBill Krier * 36fe1c642dSBill Krier * Be careful about returning null handles to the application. Use of a 37fe1c642dSBill Krier * null handle may crash the domain controller if you attempt to use it. 38fe1c642dSBill Krier */ 39fe1c642dSBill Krier 40fe1c642dSBill Krier #include <stdio.h> 41fe1c642dSBill Krier #include <strings.h> 42fe1c642dSBill Krier #include <stdlib.h> 43fe1c642dSBill Krier #include <unistd.h> 44fe1c642dSBill Krier #include <netdb.h> 45fe1c642dSBill Krier #include <sys/param.h> 46fe1c642dSBill Krier 47fe1c642dSBill Krier #include <smbsrv/libsmb.h> 48fe1c642dSBill Krier #include <smbsrv/libmlrpc.h> 49fe1c642dSBill Krier #include <smbsrv/libmlsvc.h> 50fe1c642dSBill Krier #include <smbsrv/smbinfo.h> 51fe1c642dSBill Krier #include <smbsrv/ntaccess.h> 52fe1c642dSBill Krier #include <smbsrv/smb_sid.h> 53fe1c642dSBill Krier #include <samlib.h> 54fe1c642dSBill Krier 55fe1c642dSBill Krier static DWORD samr_connect2(char *, char *, char *, DWORD, mlsvc_handle_t *); 56fe1c642dSBill Krier static DWORD samr_connect4(char *, char *, char *, DWORD, mlsvc_handle_t *); 57cb174861Sjoyce mcintosh static DWORD samr_connect5(char *, char *, char *, DWORD, mlsvc_handle_t *); 58fe1c642dSBill Krier 59fe1c642dSBill Krier typedef DWORD (*samr_connop_t)(char *, char *, char *, DWORD, 60fe1c642dSBill Krier mlsvc_handle_t *); 61fe1c642dSBill Krier 62fe1c642dSBill Krier static int samr_setup_user_info(WORD, struct samr_QueryUserInfo *, 63fe1c642dSBill Krier union samr_user_info *); 64fe1c642dSBill Krier 65fe1c642dSBill Krier /* 66fe1c642dSBill Krier * samr_open 67fe1c642dSBill Krier * 68fe1c642dSBill Krier * Wrapper round samr_connect to ensure that we connect using the server 69fe1c642dSBill Krier * and domain. We default to the resource domain if the caller doesn't 70fe1c642dSBill Krier * supply a server name and a domain name. 71fe1c642dSBill Krier * 72fe1c642dSBill Krier * If username argument is NULL, an anonymous connection will be established. 73fe1c642dSBill Krier * Otherwise, an authenticated connection will be established. 74fe1c642dSBill Krier * 75fe1c642dSBill Krier * On success 0 is returned. Otherwise a -ve error code. 76fe1c642dSBill Krier */ 771ed6b69aSGordon Ross DWORD 78fe1c642dSBill Krier samr_open(char *server, char *domain, char *username, DWORD access_mask, 79fe1c642dSBill Krier mlsvc_handle_t *samr_handle) 80fe1c642dSBill Krier { 81fe1c642dSBill Krier smb_domainex_t di; 821ed6b69aSGordon Ross DWORD status; 83fe1c642dSBill Krier 84fe1c642dSBill Krier if (server == NULL || domain == NULL) { 85fe1c642dSBill Krier if (!smb_domain_getinfo(&di)) 861ed6b69aSGordon Ross return (NT_STATUS_INTERNAL_ERROR); 87*b3700b07SGordon Ross server = di.d_dci.dc_name; 88fe1c642dSBill Krier domain = di.d_primary.di_nbname; 89fe1c642dSBill Krier } 90fe1c642dSBill Krier 91fe1c642dSBill Krier if (username == NULL) 92fe1c642dSBill Krier username = MLSVC_ANON_USER; 93fe1c642dSBill Krier 941ed6b69aSGordon Ross status = samr_connect(server, domain, username, access_mask, 951ed6b69aSGordon Ross samr_handle); 961ed6b69aSGordon Ross 971ed6b69aSGordon Ross return (status); 98fe1c642dSBill Krier } 99fe1c642dSBill Krier 100fe1c642dSBill Krier 101fe1c642dSBill Krier /* 102fe1c642dSBill Krier * samr_connect 103fe1c642dSBill Krier * 104fe1c642dSBill Krier * Connect to the SAMR service on the specified server (domain controller). 105fe1c642dSBill Krier * New SAM connect calls have been added to Windows over time: 106fe1c642dSBill Krier * 107fe1c642dSBill Krier * Windows NT3.x: SamrConnect 108fe1c642dSBill Krier * Windows NT4.0: SamrConnect2 109cb174861Sjoyce mcintosh * Windows 2000: SamrConnect4 110cb174861Sjoyce mcintosh * Windows XP: SamrConnect5 111fe1c642dSBill Krier * 112fe1c642dSBill Krier * Try the calls from most recent to oldest until the server responds with 113fe1c642dSBill Krier * something other than an RPC protocol error. We don't use the original 114fe1c642dSBill Krier * connect call because all supported servers should support SamrConnect2. 115fe1c642dSBill Krier */ 1161ed6b69aSGordon Ross DWORD 117fe1c642dSBill Krier samr_connect(char *server, char *domain, char *username, DWORD access_mask, 118fe1c642dSBill Krier mlsvc_handle_t *samr_handle) 119fe1c642dSBill Krier { 120fe1c642dSBill Krier static samr_connop_t samr_connop[] = { 121cb174861Sjoyce mcintosh samr_connect5, 122fe1c642dSBill Krier samr_connect4, 123fe1c642dSBill Krier samr_connect2 124fe1c642dSBill Krier }; 125fe1c642dSBill Krier 126fe1c642dSBill Krier int n_op = (sizeof (samr_connop) / sizeof (samr_connop[0])); 127fe1c642dSBill Krier DWORD status; 128fe1c642dSBill Krier int i; 129fe1c642dSBill Krier 1301ed6b69aSGordon Ross status = ndr_rpc_bind(samr_handle, server, domain, username, "SAMR"); 1311ed6b69aSGordon Ross if (status) 1321ed6b69aSGordon Ross return (status); 133fe1c642dSBill Krier 134fe1c642dSBill Krier for (i = 0; i < n_op; ++i) { 135fe1c642dSBill Krier status = (*samr_connop[i])(server, domain, username, 136fe1c642dSBill Krier access_mask, samr_handle); 137fe1c642dSBill Krier 138cb174861Sjoyce mcintosh if (status == NT_STATUS_SUCCESS) 1391ed6b69aSGordon Ross return (status); 140fe1c642dSBill Krier } 141fe1c642dSBill Krier 142fe1c642dSBill Krier ndr_rpc_unbind(samr_handle); 143fe1c642dSBill Krier return (status); 144fe1c642dSBill Krier } 145fe1c642dSBill Krier 146fe1c642dSBill Krier /* 147fe1c642dSBill Krier * samr_connect2 148fe1c642dSBill Krier * 149fe1c642dSBill Krier * Connect to the SAM on a Windows NT 4.0 server (domain controller). 150fe1c642dSBill Krier * We need the domain controller name and, if everything works, we 151fe1c642dSBill Krier * return a handle. This function adds the double backslash prefx to 152fe1c642dSBill Krier * make it easy for applications. 153fe1c642dSBill Krier * 154fe1c642dSBill Krier * Returns 0 on success. Otherwise returns a -ve error code. 155fe1c642dSBill Krier */ 156fe1c642dSBill Krier /*ARGSUSED*/ 157fe1c642dSBill Krier static DWORD 158fe1c642dSBill Krier samr_connect2(char *server, char *domain, char *username, DWORD access_mask, 159fe1c642dSBill Krier mlsvc_handle_t *samr_handle) 160fe1c642dSBill Krier { 161cb174861Sjoyce mcintosh struct samr_Connect2 arg; 162fe1c642dSBill Krier int opnum; 163fe1c642dSBill Krier DWORD status; 164fe1c642dSBill Krier int len; 165fe1c642dSBill Krier 166cb174861Sjoyce mcintosh bzero(&arg, sizeof (struct samr_Connect2)); 167cb174861Sjoyce mcintosh opnum = SAMR_OPNUM_Connect2; 168fe1c642dSBill Krier status = NT_STATUS_SUCCESS; 169fe1c642dSBill Krier 170fe1c642dSBill Krier len = strlen(server) + 4; 171fe1c642dSBill Krier arg.servername = ndr_rpc_malloc(samr_handle, len); 172fe1c642dSBill Krier (void) snprintf((char *)arg.servername, len, "\\\\%s", server); 173fe1c642dSBill Krier arg.access_mask = access_mask; 174fe1c642dSBill Krier 175fe1c642dSBill Krier if (ndr_rpc_call(samr_handle, opnum, &arg) != 0) { 176fe1c642dSBill Krier status = NT_STATUS_UNSUCCESSFUL; 177fe1c642dSBill Krier } else if (arg.status != 0) { 178fe1c642dSBill Krier status = NT_SC_VALUE(arg.status); 179fe1c642dSBill Krier } else { 180fe1c642dSBill Krier (void) memcpy(&samr_handle->handle, &arg.handle, 181fe1c642dSBill Krier sizeof (ndr_hdid_t)); 182fe1c642dSBill Krier 183fe1c642dSBill Krier if (ndr_is_null_handle(samr_handle)) 184fe1c642dSBill Krier status = NT_STATUS_INVALID_HANDLE; 185fe1c642dSBill Krier } 186fe1c642dSBill Krier 187fe1c642dSBill Krier ndr_rpc_release(samr_handle); 188fe1c642dSBill Krier return (status); 189fe1c642dSBill Krier } 190fe1c642dSBill Krier 191fe1c642dSBill Krier /* 192cb174861Sjoyce mcintosh * samr_connect4 193fe1c642dSBill Krier * 194fe1c642dSBill Krier * Connect to the SAM on a Windows 2000 domain controller. 195fe1c642dSBill Krier */ 196fe1c642dSBill Krier /*ARGSUSED*/ 197fe1c642dSBill Krier static DWORD 198cb174861Sjoyce mcintosh samr_connect4(char *server, char *domain, char *username, DWORD access_mask, 199fe1c642dSBill Krier mlsvc_handle_t *samr_handle) 200fe1c642dSBill Krier { 201cb174861Sjoyce mcintosh struct samr_Connect4 arg; 202fe1c642dSBill Krier int opnum; 203fe1c642dSBill Krier DWORD status; 204fe1c642dSBill Krier int len; 205fe1c642dSBill Krier 206cb174861Sjoyce mcintosh bzero(&arg, sizeof (struct samr_Connect4)); 207cb174861Sjoyce mcintosh opnum = SAMR_OPNUM_Connect4; 208fe1c642dSBill Krier status = NT_STATUS_SUCCESS; 209fe1c642dSBill Krier 210fe1c642dSBill Krier len = strlen(server) + 4; 211fe1c642dSBill Krier arg.servername = ndr_rpc_malloc(samr_handle, len); 212fe1c642dSBill Krier (void) snprintf((char *)arg.servername, len, "\\\\%s", server); 213fe1c642dSBill Krier arg.revision = SAMR_REVISION_2; 214fe1c642dSBill Krier arg.access_mask = access_mask; 215fe1c642dSBill Krier 216fe1c642dSBill Krier if (ndr_rpc_call(samr_handle, opnum, &arg) != 0) { 217fe1c642dSBill Krier status = NT_STATUS_UNSUCCESSFUL; 218fe1c642dSBill Krier } else if (arg.status != 0) { 219fe1c642dSBill Krier status = NT_SC_VALUE(arg.status); 220fe1c642dSBill Krier } else { 221fe1c642dSBill Krier (void) memcpy(&samr_handle->handle, &arg.handle, 222fe1c642dSBill Krier sizeof (ndr_hdid_t)); 223fe1c642dSBill Krier 224fe1c642dSBill Krier if (ndr_is_null_handle(samr_handle)) 225fe1c642dSBill Krier status = NT_STATUS_INVALID_HANDLE; 226fe1c642dSBill Krier } 227fe1c642dSBill Krier 228fe1c642dSBill Krier ndr_rpc_release(samr_handle); 229fe1c642dSBill Krier return (status); 230fe1c642dSBill Krier } 231fe1c642dSBill Krier 232fe1c642dSBill Krier /* 233cb174861Sjoyce mcintosh * samr_connect5 234fe1c642dSBill Krier * 235fe1c642dSBill Krier * Connect to the SAM on a Windows XP domain controller. On Windows 236fe1c642dSBill Krier * XP, the server should be the fully qualified DNS domain name with 237fe1c642dSBill Krier * a double backslash prefix. At this point, it is assumed that we 238fe1c642dSBill Krier * need to add the prefix and the DNS domain name here. 239fe1c642dSBill Krier * 240fe1c642dSBill Krier * If this call succeeds, a SAMR handle is placed in samr_handle and 241fe1c642dSBill Krier * zero is returned. Otherwise, a -ve error code is returned. 242fe1c642dSBill Krier */ 243fe1c642dSBill Krier /*ARGSUSED*/ 244fe1c642dSBill Krier static DWORD 245cb174861Sjoyce mcintosh samr_connect5(char *server, char *domain, char *username, DWORD access_mask, 246fe1c642dSBill Krier mlsvc_handle_t *samr_handle) 247fe1c642dSBill Krier { 248cb174861Sjoyce mcintosh struct samr_Connect5 arg; 249fe1c642dSBill Krier int len; 250fe1c642dSBill Krier int opnum; 251fe1c642dSBill Krier DWORD status; 252fe1c642dSBill Krier 253cb174861Sjoyce mcintosh bzero(&arg, sizeof (struct samr_Connect5)); 254cb174861Sjoyce mcintosh opnum = SAMR_OPNUM_Connect5; 255fe1c642dSBill Krier status = NT_STATUS_SUCCESS; 256fe1c642dSBill Krier 2571ed6b69aSGordon Ross len = strlen(server) + 4; 258fe1c642dSBill Krier arg.servername = ndr_rpc_malloc(samr_handle, len); 259fe1c642dSBill Krier (void) snprintf((char *)arg.servername, len, "\\\\%s", server); 260fe1c642dSBill Krier 261fe1c642dSBill Krier arg.access_mask = SAM_ENUM_LOCAL_DOMAIN; 262fe1c642dSBill Krier arg.unknown2_00000001 = 0x00000001; 263fe1c642dSBill Krier arg.unknown3_00000001 = 0x00000001; 264fe1c642dSBill Krier arg.unknown4_00000003 = 0x00000003; 265fe1c642dSBill Krier arg.unknown5_00000000 = 0x00000000; 266fe1c642dSBill Krier 267fe1c642dSBill Krier if (ndr_rpc_call(samr_handle, opnum, &arg) != 0) { 268fe1c642dSBill Krier status = NT_STATUS_UNSUCCESSFUL; 269fe1c642dSBill Krier } else if (arg.status != 0) { 270fe1c642dSBill Krier status = NT_SC_VALUE(arg.status); 271fe1c642dSBill Krier } else { 272fe1c642dSBill Krier 273fe1c642dSBill Krier (void) memcpy(&samr_handle->handle, &arg.handle, 274fe1c642dSBill Krier sizeof (ndr_hdid_t)); 275fe1c642dSBill Krier 276fe1c642dSBill Krier if (ndr_is_null_handle(samr_handle)) 277fe1c642dSBill Krier status = NT_STATUS_INVALID_HANDLE; 278fe1c642dSBill Krier } 279fe1c642dSBill Krier 280fe1c642dSBill Krier ndr_rpc_release(samr_handle); 281fe1c642dSBill Krier return (status); 282fe1c642dSBill Krier } 283fe1c642dSBill Krier 284fe1c642dSBill Krier 285fe1c642dSBill Krier /* 286fe1c642dSBill Krier * samr_close_handle 287fe1c642dSBill Krier * 288fe1c642dSBill Krier * This is function closes any valid handle, i.e. sam, domain, user etc. 289fe1c642dSBill Krier * If the handle being closed is the top level connect handle, we unbind. 290fe1c642dSBill Krier * Then we zero out the handle to invalidate it. 291fe1c642dSBill Krier */ 2921ed6b69aSGordon Ross void 293fe1c642dSBill Krier samr_close_handle(mlsvc_handle_t *samr_handle) 294fe1c642dSBill Krier { 295fe1c642dSBill Krier struct samr_CloseHandle arg; 296fe1c642dSBill Krier int opnum; 297fe1c642dSBill Krier 298fe1c642dSBill Krier if (ndr_is_null_handle(samr_handle)) 2991ed6b69aSGordon Ross return; 300fe1c642dSBill Krier 301fe1c642dSBill Krier opnum = SAMR_OPNUM_CloseHandle; 302fe1c642dSBill Krier bzero(&arg, sizeof (struct samr_CloseHandle)); 303fe1c642dSBill Krier (void) memcpy(&arg.handle, &samr_handle->handle, sizeof (ndr_hdid_t)); 304fe1c642dSBill Krier 305fe1c642dSBill Krier (void) ndr_rpc_call(samr_handle, opnum, &arg); 306fe1c642dSBill Krier ndr_rpc_release(samr_handle); 307fe1c642dSBill Krier 308fe1c642dSBill Krier if (ndr_is_bind_handle(samr_handle)) 309fe1c642dSBill Krier ndr_rpc_unbind(samr_handle); 310fe1c642dSBill Krier 311fe1c642dSBill Krier bzero(samr_handle, sizeof (mlsvc_handle_t)); 312fe1c642dSBill Krier } 313fe1c642dSBill Krier 314fe1c642dSBill Krier /* 315fe1c642dSBill Krier * samr_open_domain 316fe1c642dSBill Krier * 317fe1c642dSBill Krier * We use a SAM handle to obtain a handle for a domain, specified by 318fe1c642dSBill Krier * the SID. The SID can be obtain via the LSA interface. A handle for 319fe1c642dSBill Krier * the domain is returned in domain_handle. 320fe1c642dSBill Krier */ 321fe1c642dSBill Krier DWORD 322fe1c642dSBill Krier samr_open_domain(mlsvc_handle_t *samr_handle, DWORD access_mask, 323fe1c642dSBill Krier struct samr_sid *sid, mlsvc_handle_t *domain_handle) 324fe1c642dSBill Krier { 325fe1c642dSBill Krier struct samr_OpenDomain arg; 326fe1c642dSBill Krier int opnum; 327fe1c642dSBill Krier DWORD status; 328fe1c642dSBill Krier 329fe1c642dSBill Krier if (ndr_is_null_handle(samr_handle) || 330fe1c642dSBill Krier sid == NULL || domain_handle == NULL) { 331fe1c642dSBill Krier return (NT_STATUS_INVALID_PARAMETER); 332fe1c642dSBill Krier } 333fe1c642dSBill Krier 334fe1c642dSBill Krier opnum = SAMR_OPNUM_OpenDomain; 335fe1c642dSBill Krier bzero(&arg, sizeof (struct samr_OpenDomain)); 336fe1c642dSBill Krier (void) memcpy(&arg.handle, &samr_handle->handle, sizeof (ndr_hdid_t)); 337fe1c642dSBill Krier 338fe1c642dSBill Krier arg.access_mask = access_mask; 339fe1c642dSBill Krier arg.sid = sid; 340fe1c642dSBill Krier 341fe1c642dSBill Krier if (ndr_rpc_call(samr_handle, opnum, &arg) != 0) { 342fe1c642dSBill Krier status = NT_STATUS_UNSUCCESSFUL; 343fe1c642dSBill Krier } else if (arg.status != 0) { 344fe1c642dSBill Krier status = arg.status; 345fe1c642dSBill Krier } else { 346fe1c642dSBill Krier status = NT_STATUS_SUCCESS; 347fe1c642dSBill Krier ndr_inherit_handle(domain_handle, samr_handle); 348fe1c642dSBill Krier 349fe1c642dSBill Krier (void) memcpy(&domain_handle->handle, &arg.domain_handle, 350fe1c642dSBill Krier sizeof (ndr_hdid_t)); 351fe1c642dSBill Krier 352fe1c642dSBill Krier if (ndr_is_null_handle(domain_handle)) 353fe1c642dSBill Krier status = NT_STATUS_INVALID_HANDLE; 354fe1c642dSBill Krier } 355fe1c642dSBill Krier 356fe1c642dSBill Krier if (status != NT_STATUS_SUCCESS) 357fe1c642dSBill Krier ndr_rpc_status(samr_handle, opnum, status); 358fe1c642dSBill Krier 359fe1c642dSBill Krier ndr_rpc_release(samr_handle); 360fe1c642dSBill Krier return (status); 361fe1c642dSBill Krier } 362fe1c642dSBill Krier 363fe1c642dSBill Krier /* 364fe1c642dSBill Krier * samr_open_user 365fe1c642dSBill Krier * 366fe1c642dSBill Krier * Use a domain handle to obtain a handle for a user, specified by the 367fe1c642dSBill Krier * user RID. A user RID (effectively a uid) can be obtained via the 368fe1c642dSBill Krier * LSA interface. A handle for the user is returned in user_handle. 369fe1c642dSBill Krier * Once you have a user handle it should be possible to query the SAM 370fe1c642dSBill Krier * for information on that user. 371fe1c642dSBill Krier */ 372fe1c642dSBill Krier DWORD 373fe1c642dSBill Krier samr_open_user(mlsvc_handle_t *domain_handle, DWORD access_mask, DWORD rid, 374fe1c642dSBill Krier mlsvc_handle_t *user_handle) 375fe1c642dSBill Krier { 376fe1c642dSBill Krier struct samr_OpenUser arg; 377fe1c642dSBill Krier int opnum; 378fe1c642dSBill Krier DWORD status = NT_STATUS_SUCCESS; 379fe1c642dSBill Krier 380fe1c642dSBill Krier if (ndr_is_null_handle(domain_handle) || user_handle == NULL) 381fe1c642dSBill Krier return (NT_STATUS_INVALID_PARAMETER); 382fe1c642dSBill Krier 383fe1c642dSBill Krier opnum = SAMR_OPNUM_OpenUser; 384fe1c642dSBill Krier bzero(&arg, sizeof (struct samr_OpenUser)); 385fe1c642dSBill Krier (void) memcpy(&arg.handle, &domain_handle->handle, 386fe1c642dSBill Krier sizeof (ndr_hdid_t)); 387fe1c642dSBill Krier arg.access_mask = access_mask; 388fe1c642dSBill Krier arg.rid = rid; 389fe1c642dSBill Krier 390fe1c642dSBill Krier if (ndr_rpc_call(domain_handle, opnum, &arg) != 0) { 391fe1c642dSBill Krier status = NT_STATUS_UNSUCCESSFUL; 392fe1c642dSBill Krier } else if (arg.status != 0) { 393fe1c642dSBill Krier ndr_rpc_status(domain_handle, opnum, arg.status); 394fe1c642dSBill Krier status = NT_SC_VALUE(arg.status); 395fe1c642dSBill Krier } else { 396fe1c642dSBill Krier ndr_inherit_handle(user_handle, domain_handle); 397fe1c642dSBill Krier 398fe1c642dSBill Krier (void) memcpy(&user_handle->handle, &arg.user_handle, 399fe1c642dSBill Krier sizeof (ndr_hdid_t)); 400fe1c642dSBill Krier 401fe1c642dSBill Krier if (ndr_is_null_handle(user_handle)) 402fe1c642dSBill Krier status = NT_STATUS_INVALID_HANDLE; 403fe1c642dSBill Krier } 404fe1c642dSBill Krier 405fe1c642dSBill Krier ndr_rpc_release(domain_handle); 406fe1c642dSBill Krier return (status); 407fe1c642dSBill Krier } 408fe1c642dSBill Krier 409fe1c642dSBill Krier /* 410fe1c642dSBill Krier * samr_delete_user 411fe1c642dSBill Krier * 412fe1c642dSBill Krier * Delete the user specified by the user_handle. 413fe1c642dSBill Krier */ 414fe1c642dSBill Krier DWORD 415fe1c642dSBill Krier samr_delete_user(mlsvc_handle_t *user_handle) 416fe1c642dSBill Krier { 417fe1c642dSBill Krier struct samr_DeleteUser arg; 418fe1c642dSBill Krier int opnum; 419fe1c642dSBill Krier DWORD status; 420fe1c642dSBill Krier 421fe1c642dSBill Krier if (ndr_is_null_handle(user_handle)) 422fe1c642dSBill Krier return (NT_STATUS_INVALID_PARAMETER); 423fe1c642dSBill Krier 424fe1c642dSBill Krier opnum = SAMR_OPNUM_DeleteUser; 425fe1c642dSBill Krier bzero(&arg, sizeof (struct samr_DeleteUser)); 426fe1c642dSBill Krier (void) memcpy(&arg.user_handle, &user_handle->handle, 427fe1c642dSBill Krier sizeof (ndr_hdid_t)); 428fe1c642dSBill Krier 429fe1c642dSBill Krier if (ndr_rpc_call(user_handle, opnum, &arg) != 0) { 430fe1c642dSBill Krier status = NT_STATUS_INVALID_PARAMETER; 431fe1c642dSBill Krier } else if (arg.status != 0) { 432fe1c642dSBill Krier ndr_rpc_status(user_handle, opnum, arg.status); 433fe1c642dSBill Krier status = NT_SC_VALUE(arg.status); 434fe1c642dSBill Krier } else { 435fe1c642dSBill Krier status = 0; 436fe1c642dSBill Krier } 437fe1c642dSBill Krier 438fe1c642dSBill Krier ndr_rpc_release(user_handle); 439fe1c642dSBill Krier return (status); 440fe1c642dSBill Krier } 441fe1c642dSBill Krier 442fe1c642dSBill Krier /* 443fe1c642dSBill Krier * samr_open_group 444fe1c642dSBill Krier * 445fe1c642dSBill Krier * Use a domain handle to obtain a handle for a group, specified by the 446fe1c642dSBill Krier * group RID. A group RID (effectively a gid) can be obtained via the 447fe1c642dSBill Krier * LSA interface. A handle for the group is returned in group_handle. 448fe1c642dSBill Krier * Once you have a group handle it should be possible to query the SAM 449fe1c642dSBill Krier * for information on that group. 450fe1c642dSBill Krier */ 451fe1c642dSBill Krier int 452fe1c642dSBill Krier samr_open_group( 453fe1c642dSBill Krier mlsvc_handle_t *domain_handle, 454fe1c642dSBill Krier DWORD rid, 455fe1c642dSBill Krier mlsvc_handle_t *group_handle) 456fe1c642dSBill Krier { 457fe1c642dSBill Krier struct samr_OpenGroup arg; 458fe1c642dSBill Krier int opnum; 459fe1c642dSBill Krier int rc; 460fe1c642dSBill Krier 461fe1c642dSBill Krier if (ndr_is_null_handle(domain_handle) || group_handle == NULL) 462fe1c642dSBill Krier return (-1); 463fe1c642dSBill Krier 464fe1c642dSBill Krier opnum = SAMR_OPNUM_OpenGroup; 465fe1c642dSBill Krier bzero(&arg, sizeof (struct samr_OpenUser)); 466fe1c642dSBill Krier (void) memcpy(&arg.handle, &domain_handle->handle, 467fe1c642dSBill Krier sizeof (ndr_hdid_t)); 468fe1c642dSBill Krier arg.access_mask = SAM_LOOKUP_INFORMATION | SAM_ACCESS_USER_READ; 469fe1c642dSBill Krier arg.rid = rid; 470fe1c642dSBill Krier 471fe1c642dSBill Krier if ((rc = ndr_rpc_call(domain_handle, opnum, &arg)) != 0) 472fe1c642dSBill Krier return (-1); 473fe1c642dSBill Krier 474fe1c642dSBill Krier if (arg.status != 0) { 475fe1c642dSBill Krier ndr_rpc_status(domain_handle, opnum, arg.status); 476fe1c642dSBill Krier rc = -1; 477fe1c642dSBill Krier } else { 478fe1c642dSBill Krier ndr_inherit_handle(group_handle, domain_handle); 479fe1c642dSBill Krier 480fe1c642dSBill Krier (void) memcpy(&group_handle->handle, &arg.group_handle, 481fe1c642dSBill Krier sizeof (ndr_hdid_t)); 482fe1c642dSBill Krier 483fe1c642dSBill Krier if (ndr_is_null_handle(group_handle)) 484fe1c642dSBill Krier rc = -1; 485fe1c642dSBill Krier } 486fe1c642dSBill Krier 487fe1c642dSBill Krier ndr_rpc_release(domain_handle); 488fe1c642dSBill Krier return (rc); 489fe1c642dSBill Krier } 490fe1c642dSBill Krier 491fe1c642dSBill Krier /* 492fe1c642dSBill Krier * samr_create_user 493fe1c642dSBill Krier * 494fe1c642dSBill Krier * Create a user in the domain specified by the domain handle. If this 495fe1c642dSBill Krier * call is successful, the server will return the RID for the user and 496fe1c642dSBill Krier * a user handle, which may be used to set or query the SAM. 497fe1c642dSBill Krier * 498fe1c642dSBill Krier * Observed status codes: 499fe1c642dSBill Krier * NT_STATUS_INVALID_PARAMETER 500fe1c642dSBill Krier * NT_STATUS_INVALID_ACCOUNT_NAME 501fe1c642dSBill Krier * NT_STATUS_ACCESS_DENIED 502fe1c642dSBill Krier * NT_STATUS_USER_EXISTS 503fe1c642dSBill Krier * 504fe1c642dSBill Krier * Returns 0 on success. Otherwise returns an NT status code. 505fe1c642dSBill Krier */ 506fe1c642dSBill Krier DWORD 507fe1c642dSBill Krier samr_create_user(mlsvc_handle_t *domain_handle, char *username, 508fe1c642dSBill Krier DWORD account_flags, DWORD *rid, mlsvc_handle_t *user_handle) 509fe1c642dSBill Krier { 510fe1c642dSBill Krier struct samr_CreateUser arg; 511fe1c642dSBill Krier ndr_heap_t *heap; 512fe1c642dSBill Krier int opnum; 513fe1c642dSBill Krier int rc; 514fe1c642dSBill Krier DWORD status = 0; 515fe1c642dSBill Krier 516fe1c642dSBill Krier if (ndr_is_null_handle(domain_handle) || 517fe1c642dSBill Krier username == NULL || rid == NULL) { 518fe1c642dSBill Krier return (NT_STATUS_INVALID_PARAMETER); 519fe1c642dSBill Krier } 520fe1c642dSBill Krier 521fe1c642dSBill Krier opnum = SAMR_OPNUM_CreateUser; 522fe1c642dSBill Krier 523fe1c642dSBill Krier bzero(&arg, sizeof (struct samr_CreateUser)); 524fe1c642dSBill Krier (void) memcpy(&arg.handle, &domain_handle->handle, 525fe1c642dSBill Krier sizeof (ndr_hdid_t)); 526fe1c642dSBill Krier 527fe1c642dSBill Krier heap = ndr_rpc_get_heap(domain_handle); 528fe1c642dSBill Krier ndr_heap_mkvcs(heap, username, (ndr_vcstr_t *)&arg.username); 529fe1c642dSBill Krier 530fe1c642dSBill Krier arg.account_flags = account_flags; 531fe1c642dSBill Krier arg.desired_access = 0xE00500B0; 532fe1c642dSBill Krier 533fe1c642dSBill Krier rc = ndr_rpc_call(domain_handle, opnum, &arg); 534fe1c642dSBill Krier if (rc != 0) { 535fe1c642dSBill Krier status = NT_STATUS_INVALID_PARAMETER; 536fe1c642dSBill Krier } else if (arg.status != 0) { 537fe1c642dSBill Krier status = NT_SC_VALUE(arg.status); 538fe1c642dSBill Krier 539fe1c642dSBill Krier if (status != NT_STATUS_USER_EXISTS) { 5401ed6b69aSGordon Ross smb_tracef("SamrCreateUser[%s]: %s", 5411ed6b69aSGordon Ross username, xlate_nt_status(status)); 542fe1c642dSBill Krier } 543fe1c642dSBill Krier } else { 544fe1c642dSBill Krier ndr_inherit_handle(user_handle, domain_handle); 545fe1c642dSBill Krier 546fe1c642dSBill Krier (void) memcpy(&user_handle->handle, &arg.user_handle, 547fe1c642dSBill Krier sizeof (ndr_hdid_t)); 548fe1c642dSBill Krier 549fe1c642dSBill Krier *rid = arg.rid; 550fe1c642dSBill Krier 551fe1c642dSBill Krier if (ndr_is_null_handle(user_handle)) 552fe1c642dSBill Krier status = NT_STATUS_INVALID_HANDLE; 553fe1c642dSBill Krier else 554fe1c642dSBill Krier status = 0; 555fe1c642dSBill Krier } 556fe1c642dSBill Krier 557fe1c642dSBill Krier ndr_rpc_release(domain_handle); 558fe1c642dSBill Krier return (status); 559fe1c642dSBill Krier } 560fe1c642dSBill Krier 561fe1c642dSBill Krier /* 562fe1c642dSBill Krier * samr_lookup_domain 563fe1c642dSBill Krier * 564fe1c642dSBill Krier * Lookup up the domain SID for the specified domain name. The handle 565fe1c642dSBill Krier * should be one returned from samr_connect. The allocated memory for 566fe1c642dSBill Krier * the returned SID must be freed by caller. 567fe1c642dSBill Krier */ 568fe1c642dSBill Krier smb_sid_t * 569fe1c642dSBill Krier samr_lookup_domain(mlsvc_handle_t *samr_handle, char *domain_name) 570fe1c642dSBill Krier { 571fe1c642dSBill Krier struct samr_LookupDomain arg; 572fe1c642dSBill Krier smb_sid_t *domsid = NULL; 573fe1c642dSBill Krier int opnum; 574fe1c642dSBill Krier size_t length; 575fe1c642dSBill Krier 576fe1c642dSBill Krier if (ndr_is_null_handle(samr_handle) || domain_name == NULL) 577fe1c642dSBill Krier return (NULL); 578fe1c642dSBill Krier 579fe1c642dSBill Krier opnum = SAMR_OPNUM_LookupDomain; 580fe1c642dSBill Krier bzero(&arg, sizeof (struct samr_LookupDomain)); 581fe1c642dSBill Krier 582fe1c642dSBill Krier (void) memcpy(&arg.handle, &samr_handle->handle, 583fe1c642dSBill Krier sizeof (samr_handle_t)); 584fe1c642dSBill Krier 585fe1c642dSBill Krier length = smb_wcequiv_strlen(domain_name); 586fe1c642dSBill Krier length += sizeof (smb_wchar_t); 587fe1c642dSBill Krier 588fe1c642dSBill Krier arg.domain_name.length = length; 589fe1c642dSBill Krier arg.domain_name.allosize = length; 590fe1c642dSBill Krier arg.domain_name.str = (unsigned char *)domain_name; 591fe1c642dSBill Krier 592fe1c642dSBill Krier if (ndr_rpc_call(samr_handle, opnum, &arg) == 0) 593fe1c642dSBill Krier domsid = smb_sid_dup((smb_sid_t *)arg.sid); 594fe1c642dSBill Krier 595fe1c642dSBill Krier ndr_rpc_release(samr_handle); 596fe1c642dSBill Krier return (domsid); 597fe1c642dSBill Krier } 598fe1c642dSBill Krier 599fe1c642dSBill Krier /* 600fe1c642dSBill Krier * samr_enum_local_domains 601fe1c642dSBill Krier * 602fe1c642dSBill Krier * Get the list of local domains supported by a server. 603fe1c642dSBill Krier * 604fe1c642dSBill Krier * Returns NT status codes. 605fe1c642dSBill Krier */ 606fe1c642dSBill Krier DWORD 607fe1c642dSBill Krier samr_enum_local_domains(mlsvc_handle_t *samr_handle) 608fe1c642dSBill Krier { 609fe1c642dSBill Krier struct samr_EnumLocalDomain arg; 610fe1c642dSBill Krier int opnum; 611fe1c642dSBill Krier DWORD status; 612fe1c642dSBill Krier 613fe1c642dSBill Krier if (ndr_is_null_handle(samr_handle)) 614fe1c642dSBill Krier return (NT_STATUS_INVALID_PARAMETER); 615fe1c642dSBill Krier 616fe1c642dSBill Krier opnum = SAMR_OPNUM_EnumLocalDomains; 617fe1c642dSBill Krier bzero(&arg, sizeof (struct samr_EnumLocalDomain)); 618fe1c642dSBill Krier 619fe1c642dSBill Krier (void) memcpy(&arg.handle, &samr_handle->handle, 620fe1c642dSBill Krier sizeof (samr_handle_t)); 621fe1c642dSBill Krier arg.enum_context = 0; 622fe1c642dSBill Krier arg.max_length = 0x00002000; /* Value used by NT */ 623fe1c642dSBill Krier 624fe1c642dSBill Krier if (ndr_rpc_call(samr_handle, opnum, &arg) != 0) { 625fe1c642dSBill Krier status = NT_STATUS_INVALID_PARAMETER; 626fe1c642dSBill Krier } else { 627fe1c642dSBill Krier status = NT_SC_VALUE(arg.status); 628fe1c642dSBill Krier 629fe1c642dSBill Krier /* 630fe1c642dSBill Krier * Handle none-mapped status quietly. 631fe1c642dSBill Krier */ 632fe1c642dSBill Krier if (status != NT_STATUS_NONE_MAPPED) 633fe1c642dSBill Krier ndr_rpc_status(samr_handle, opnum, arg.status); 634fe1c642dSBill Krier } 635fe1c642dSBill Krier 636fe1c642dSBill Krier ndr_rpc_release(samr_handle); 637fe1c642dSBill Krier return (status); 638fe1c642dSBill Krier } 639fe1c642dSBill Krier 640fe1c642dSBill Krier /* 641fe1c642dSBill Krier * samr_lookup_domain_names 642fe1c642dSBill Krier * 643fe1c642dSBill Krier * Lookup up the given name in the domain specified by domain_handle. 644fe1c642dSBill Krier * Upon a successful lookup the information is returned in the account 645fe1c642dSBill Krier * arg and caller must free allocated memories by calling smb_account_free(). 646fe1c642dSBill Krier * 647fe1c642dSBill Krier * Returns NT status codes. 648fe1c642dSBill Krier */ 649fe1c642dSBill Krier uint32_t 650fe1c642dSBill Krier samr_lookup_domain_names(mlsvc_handle_t *domain_handle, char *name, 651fe1c642dSBill Krier smb_account_t *account) 652fe1c642dSBill Krier { 653fe1c642dSBill Krier struct samr_LookupNames arg; 654fe1c642dSBill Krier int opnum; 655fe1c642dSBill Krier uint32_t status; 656fe1c642dSBill Krier size_t length; 657fe1c642dSBill Krier 658fe1c642dSBill Krier if (ndr_is_null_handle(domain_handle) || 659fe1c642dSBill Krier name == NULL || account == NULL) { 660fe1c642dSBill Krier return (NT_STATUS_INVALID_PARAMETER); 661fe1c642dSBill Krier } 662fe1c642dSBill Krier 663fe1c642dSBill Krier bzero(account, sizeof (smb_account_t)); 664fe1c642dSBill Krier opnum = SAMR_OPNUM_LookupNames; 665fe1c642dSBill Krier bzero(&arg, sizeof (struct samr_LookupNames)); 666fe1c642dSBill Krier 667fe1c642dSBill Krier (void) memcpy(&arg.handle, &domain_handle->handle, 668fe1c642dSBill Krier sizeof (samr_handle_t)); 669fe1c642dSBill Krier arg.n_entry = 1; 670fe1c642dSBill Krier arg.max_n_entry = 1000; 671fe1c642dSBill Krier arg.index = 0; 672fe1c642dSBill Krier arg.total = 1; 673fe1c642dSBill Krier 674fe1c642dSBill Krier length = smb_wcequiv_strlen(name); 675fe1c642dSBill Krier length += sizeof (smb_wchar_t); 676fe1c642dSBill Krier 677fe1c642dSBill Krier arg.name.length = length; 678fe1c642dSBill Krier arg.name.allosize = length; 679fe1c642dSBill Krier arg.name.str = (unsigned char *)name; 680fe1c642dSBill Krier 681fe1c642dSBill Krier if (ndr_rpc_call(domain_handle, opnum, &arg) != 0) { 682fe1c642dSBill Krier status = NT_STATUS_INVALID_PARAMETER; 683fe1c642dSBill Krier } else if (arg.status != NT_STATUS_SUCCESS) { 684fe1c642dSBill Krier status = NT_SC_VALUE(arg.status); 685fe1c642dSBill Krier 686fe1c642dSBill Krier /* 687fe1c642dSBill Krier * Handle none-mapped status quietly. 688fe1c642dSBill Krier */ 689fe1c642dSBill Krier if (status != NT_STATUS_NONE_MAPPED) 690fe1c642dSBill Krier ndr_rpc_status(domain_handle, opnum, arg.status); 691fe1c642dSBill Krier } else { 692fe1c642dSBill Krier account->a_type = arg.rid_types.rid_type[0]; 693fe1c642dSBill Krier account->a_rid = arg.rids.rid[0]; 694fe1c642dSBill Krier status = NT_STATUS_SUCCESS; 695fe1c642dSBill Krier } 696fe1c642dSBill Krier 697fe1c642dSBill Krier ndr_rpc_release(domain_handle); 698fe1c642dSBill Krier return (status); 699fe1c642dSBill Krier } 700fe1c642dSBill Krier 701fe1c642dSBill Krier /* 702fe1c642dSBill Krier * samr_query_user_info 703fe1c642dSBill Krier * 704fe1c642dSBill Krier * Query information on a specific user. The handle must be a valid 705fe1c642dSBill Krier * user handle obtained via samr_open_user. 706fe1c642dSBill Krier * 7071ed6b69aSGordon Ross * Returns 0 on success, otherwise returns NT status code. 708fe1c642dSBill Krier */ 7091ed6b69aSGordon Ross DWORD 710fe1c642dSBill Krier samr_query_user_info(mlsvc_handle_t *user_handle, WORD switch_value, 711fe1c642dSBill Krier union samr_user_info *user_info) 712fe1c642dSBill Krier { 713fe1c642dSBill Krier struct samr_QueryUserInfo arg; 714fe1c642dSBill Krier int opnum; 715fe1c642dSBill Krier 716fe1c642dSBill Krier if (ndr_is_null_handle(user_handle) || user_info == 0) 7171ed6b69aSGordon Ross return (NT_STATUS_INTERNAL_ERROR); 718fe1c642dSBill Krier 719fe1c642dSBill Krier opnum = SAMR_OPNUM_QueryUserInfo; 720fe1c642dSBill Krier bzero(&arg, sizeof (struct samr_QueryUserInfo)); 721fe1c642dSBill Krier 722fe1c642dSBill Krier (void) memcpy(&arg.user_handle, &user_handle->handle, 723fe1c642dSBill Krier sizeof (samr_handle_t)); 724fe1c642dSBill Krier arg.switch_value = switch_value; 725fe1c642dSBill Krier 7261ed6b69aSGordon Ross if (ndr_rpc_call(user_handle, opnum, &arg) != 0) 7271ed6b69aSGordon Ross arg.status = RPC_NT_CALL_FAILED; 728fe1c642dSBill Krier 7291ed6b69aSGordon Ross if (arg.status == 0) 7301ed6b69aSGordon Ross (void) samr_setup_user_info(switch_value, &arg, user_info); 731fe1c642dSBill Krier 7321ed6b69aSGordon Ross return (arg.status); 733fe1c642dSBill Krier } 734fe1c642dSBill Krier 735fe1c642dSBill Krier /* 736fe1c642dSBill Krier * samr_setup_user_info 737fe1c642dSBill Krier * 738fe1c642dSBill Krier * Private function to set up the samr_user_info data. Dependent on 739fe1c642dSBill Krier * the switch value this function may use strdup which will malloc 740fe1c642dSBill Krier * memory. The caller is responsible for deallocating this memory. 741fe1c642dSBill Krier * 742fe1c642dSBill Krier * Returns 0 on success, otherwise returns -1. 743fe1c642dSBill Krier */ 744fe1c642dSBill Krier static int 745fe1c642dSBill Krier samr_setup_user_info(WORD switch_value, 746fe1c642dSBill Krier struct samr_QueryUserInfo *arg, union samr_user_info *user_info) 747fe1c642dSBill Krier { 748fe1c642dSBill Krier struct samr_QueryUserInfo1 *info1; 749fe1c642dSBill Krier struct samr_QueryUserInfo6 *info6; 750fe1c642dSBill Krier 751fe1c642dSBill Krier switch (switch_value) { 752fe1c642dSBill Krier case 1: 753fe1c642dSBill Krier info1 = &arg->ru.info1; 754fe1c642dSBill Krier user_info->info1.username = strdup( 755fe1c642dSBill Krier (char const *)info1->username.str); 756fe1c642dSBill Krier user_info->info1.fullname = strdup( 757fe1c642dSBill Krier (char const *)info1->fullname.str); 758fe1c642dSBill Krier user_info->info1.description = strdup( 759fe1c642dSBill Krier (char const *)info1->description.str); 760fe1c642dSBill Krier user_info->info1.unknown = 0; 761fe1c642dSBill Krier user_info->info1.group_rid = info1->group_rid; 762fe1c642dSBill Krier return (0); 763fe1c642dSBill Krier 764fe1c642dSBill Krier case 6: 765fe1c642dSBill Krier info6 = &arg->ru.info6; 766fe1c642dSBill Krier user_info->info6.username = strdup( 767fe1c642dSBill Krier (char const *)info6->username.str); 768fe1c642dSBill Krier user_info->info6.fullname = strdup( 769fe1c642dSBill Krier (char const *)info6->fullname.str); 770fe1c642dSBill Krier return (0); 771fe1c642dSBill Krier 772fe1c642dSBill Krier case 7: 773fe1c642dSBill Krier user_info->info7.username = strdup( 774fe1c642dSBill Krier (char const *)arg->ru.info7.username.str); 775fe1c642dSBill Krier return (0); 776fe1c642dSBill Krier 777fe1c642dSBill Krier case 8: 778fe1c642dSBill Krier user_info->info8.fullname = strdup( 779fe1c642dSBill Krier (char const *)arg->ru.info8.fullname.str); 780fe1c642dSBill Krier return (0); 781fe1c642dSBill Krier 782fe1c642dSBill Krier case 9: 783fe1c642dSBill Krier user_info->info9.group_rid = arg->ru.info9.group_rid; 784fe1c642dSBill Krier return (0); 785fe1c642dSBill Krier 786fe1c642dSBill Krier case 16: 7871ed6b69aSGordon Ross user_info->info16.acct_ctrl = 7881ed6b69aSGordon Ross arg->ru.info16.UserAccountControl; 789fe1c642dSBill Krier return (0); 790fe1c642dSBill Krier 791fe1c642dSBill Krier default: 792fe1c642dSBill Krier break; 793fe1c642dSBill Krier }; 794fe1c642dSBill Krier 795fe1c642dSBill Krier return (-1); 796fe1c642dSBill Krier } 797fe1c642dSBill Krier 798fe1c642dSBill Krier /* 799fe1c642dSBill Krier * samr_query_user_groups 800fe1c642dSBill Krier * 801fe1c642dSBill Krier * Query the groups for a specific user. The handle must be a valid 802fe1c642dSBill Krier * user handle obtained via samr_open_user. The list of groups is 803fe1c642dSBill Krier * returned in group_info. Note that group_info->groups is allocated 804fe1c642dSBill Krier * using malloc. The caller is responsible for deallocating this 805fe1c642dSBill Krier * memory when it is no longer required. If group_info->n_entry is 0 806fe1c642dSBill Krier * then no memory was allocated. 807fe1c642dSBill Krier * 808fe1c642dSBill Krier * Returns 0 on success, otherwise returns -1. 809fe1c642dSBill Krier */ 810fe1c642dSBill Krier int 811fe1c642dSBill Krier samr_query_user_groups(mlsvc_handle_t *user_handle, int *n_groups, 812fe1c642dSBill Krier struct samr_UserGroups **groups) 813fe1c642dSBill Krier { 814fe1c642dSBill Krier struct samr_QueryUserGroups arg; 815fe1c642dSBill Krier int opnum; 816fe1c642dSBill Krier int rc; 817fe1c642dSBill Krier int nbytes; 818fe1c642dSBill Krier 819fe1c642dSBill Krier if (ndr_is_null_handle(user_handle)) 820fe1c642dSBill Krier return (-1); 821fe1c642dSBill Krier 822fe1c642dSBill Krier opnum = SAMR_OPNUM_QueryUserGroups; 823fe1c642dSBill Krier bzero(&arg, sizeof (struct samr_QueryUserGroups)); 824fe1c642dSBill Krier 825fe1c642dSBill Krier (void) memcpy(&arg.user_handle, &user_handle->handle, 826fe1c642dSBill Krier sizeof (samr_handle_t)); 827fe1c642dSBill Krier 828fe1c642dSBill Krier rc = ndr_rpc_call(user_handle, opnum, &arg); 829fe1c642dSBill Krier if (rc == 0) { 830fe1c642dSBill Krier if (arg.info == 0) { 831fe1c642dSBill Krier rc = -1; 832fe1c642dSBill Krier } else { 833fe1c642dSBill Krier nbytes = arg.info->n_entry * 834fe1c642dSBill Krier sizeof (struct samr_UserGroups); 835fe1c642dSBill Krier 836fe1c642dSBill Krier if ((*groups = malloc(nbytes)) == NULL) { 837fe1c642dSBill Krier *n_groups = 0; 838fe1c642dSBill Krier rc = -1; 839fe1c642dSBill Krier } else { 840fe1c642dSBill Krier *n_groups = arg.info->n_entry; 841fe1c642dSBill Krier bcopy(arg.info->groups, *groups, nbytes); 842fe1c642dSBill Krier } 843fe1c642dSBill Krier } 844fe1c642dSBill Krier } 845fe1c642dSBill Krier 846fe1c642dSBill Krier ndr_rpc_release(user_handle); 847fe1c642dSBill Krier return (rc); 848fe1c642dSBill Krier } 849fe1c642dSBill Krier 850fe1c642dSBill Krier /* 851fe1c642dSBill Krier * samr_get_user_pwinfo 852fe1c642dSBill Krier * 853fe1c642dSBill Krier * Get some user password info. I'm not sure what this is yet but it is 854fe1c642dSBill Krier * part of the create user sequence. The handle must be a valid user 855fe1c642dSBill Krier * handle. Since I don't know what this is returning, I haven't provided 856fe1c642dSBill Krier * any return data yet. 857fe1c642dSBill Krier * 858fe1c642dSBill Krier * Returns 0 on success. Otherwise returns an NT status code. 859fe1c642dSBill Krier */ 860fe1c642dSBill Krier DWORD 861fe1c642dSBill Krier samr_get_user_pwinfo(mlsvc_handle_t *user_handle) 862fe1c642dSBill Krier { 863fe1c642dSBill Krier struct samr_GetUserPwInfo arg; 864fe1c642dSBill Krier int opnum; 865fe1c642dSBill Krier DWORD status; 866fe1c642dSBill Krier 867fe1c642dSBill Krier if (ndr_is_null_handle(user_handle)) 868fe1c642dSBill Krier return (NT_STATUS_INVALID_PARAMETER); 869fe1c642dSBill Krier 870fe1c642dSBill Krier opnum = SAMR_OPNUM_GetUserPwInfo; 871fe1c642dSBill Krier bzero(&arg, sizeof (struct samr_GetUserPwInfo)); 872fe1c642dSBill Krier (void) memcpy(&arg.user_handle, &user_handle->handle, 873fe1c642dSBill Krier sizeof (samr_handle_t)); 874fe1c642dSBill Krier 875fe1c642dSBill Krier if (ndr_rpc_call(user_handle, opnum, &arg) != 0) { 876fe1c642dSBill Krier status = NT_STATUS_INVALID_PARAMETER; 877fe1c642dSBill Krier } else if (arg.status != 0) { 878fe1c642dSBill Krier ndr_rpc_status(user_handle, opnum, arg.status); 879fe1c642dSBill Krier status = NT_SC_VALUE(arg.status); 880fe1c642dSBill Krier } else { 881fe1c642dSBill Krier status = 0; 882fe1c642dSBill Krier } 883fe1c642dSBill Krier 884fe1c642dSBill Krier ndr_rpc_release(user_handle); 885fe1c642dSBill Krier return (status); 886fe1c642dSBill Krier } 887fe1c642dSBill Krier 8881ed6b69aSGordon Ross DECL_FIXUP_STRUCT(samr_SetUserInfo_u); 8891ed6b69aSGordon Ross DECL_FIXUP_STRUCT(samr_SetUserInfo_s); 8901ed6b69aSGordon Ross DECL_FIXUP_STRUCT(samr_SetUserInfo); 8911ed6b69aSGordon Ross 892fe1c642dSBill Krier /* 893fe1c642dSBill Krier * samr_set_user_info 894fe1c642dSBill Krier * 895fe1c642dSBill Krier * Returns 0 on success. Otherwise returns an NT status code. 896fe1c642dSBill Krier * NT status codes observed so far: 897fe1c642dSBill Krier * NT_STATUS_WRONG_PASSWORD 898fe1c642dSBill Krier */ 899fe1c642dSBill Krier DWORD 9001ed6b69aSGordon Ross samr_set_user_info( 9011ed6b69aSGordon Ross mlsvc_handle_t *user_handle, 9021ed6b69aSGordon Ross int info_level, 9031ed6b69aSGordon Ross void *info_buf) 904fe1c642dSBill Krier { 905fe1c642dSBill Krier struct samr_SetUserInfo arg; 9061ed6b69aSGordon Ross uint16_t usize, tsize; 907fe1c642dSBill Krier int opnum; 908fe1c642dSBill Krier 909fe1c642dSBill Krier if (ndr_is_null_handle(user_handle)) 9101ed6b69aSGordon Ross return (NT_STATUS_INTERNAL_ERROR); 911fe1c642dSBill Krier 9121ed6b69aSGordon Ross /* 9131ed6b69aSGordon Ross * Only support a few levels 9141ed6b69aSGordon Ross * MS-SAMR: UserInternal4Information 9151ed6b69aSGordon Ross */ 9161ed6b69aSGordon Ross switch (info_level) { 9171ed6b69aSGordon Ross case 16: /* samr_SetUserInfo16 */ 9181ed6b69aSGordon Ross usize = sizeof (struct samr_SetUserInfo16); 9191ed6b69aSGordon Ross break; 9201ed6b69aSGordon Ross case 21: /* samr_SetUserInfo21 */ 9211ed6b69aSGordon Ross usize = sizeof (struct samr_SetUserInfo21); 9221ed6b69aSGordon Ross break; 9231ed6b69aSGordon Ross case 23: /* samr_SetUserInfo23 */ 9241ed6b69aSGordon Ross usize = sizeof (struct samr_SetUserInfo23); 9251ed6b69aSGordon Ross break; 9261ed6b69aSGordon Ross case 24: /* samr_SetUserInfo24 */ 9271ed6b69aSGordon Ross usize = sizeof (struct samr_SetUserInfo24); 9281ed6b69aSGordon Ross break; 9291ed6b69aSGordon Ross default: 9301ed6b69aSGordon Ross return (NT_STATUS_INVALID_LEVEL); 9311ed6b69aSGordon Ross } 9321ed6b69aSGordon Ross 9331ed6b69aSGordon Ross /* 9341ed6b69aSGordon Ross * OK, now this gets really ugly, because 9351ed6b69aSGordon Ross * ndrgen doesn't do unions correctly. 9361ed6b69aSGordon Ross */ 9371ed6b69aSGordon Ross FIXUP_PDU_SIZE(samr_SetUserInfo_u, usize); 9381ed6b69aSGordon Ross tsize = usize + (2 * sizeof (WORD)); 9391ed6b69aSGordon Ross FIXUP_PDU_SIZE(samr_SetUserInfo_s, tsize); 9401ed6b69aSGordon Ross tsize += sizeof (ndr_request_hdr_t) + sizeof (DWORD); 9411ed6b69aSGordon Ross FIXUP_PDU_SIZE(samr_SetUserInfo, tsize); 942fe1c642dSBill Krier 943fe1c642dSBill Krier opnum = SAMR_OPNUM_SetUserInfo; 9441ed6b69aSGordon Ross bzero(&arg, sizeof (arg)); 945fe1c642dSBill Krier (void) memcpy(&arg.user_handle, &user_handle->handle, 946fe1c642dSBill Krier sizeof (samr_handle_t)); 9471ed6b69aSGordon Ross arg.info.info_level = info_level; 9481ed6b69aSGordon Ross arg.info.switch_value = info_level; 9491ed6b69aSGordon Ross (void) memcpy(&arg.info.ru, info_buf, usize); 950fe1c642dSBill Krier 9511ed6b69aSGordon Ross if (ndr_rpc_call(user_handle, opnum, &arg) != 0) 9521ed6b69aSGordon Ross arg.status = RPC_NT_CALL_FAILED; 9531ed6b69aSGordon Ross else if (arg.status != 0) 954fe1c642dSBill Krier ndr_rpc_status(user_handle, opnum, arg.status); 955fe1c642dSBill Krier 956fe1c642dSBill Krier ndr_rpc_release(user_handle); 9571ed6b69aSGordon Ross return (arg.status); 958fe1c642dSBill Krier } 959fe1c642dSBill Krier 960fe1c642dSBill Krier /* 9611ed6b69aSGordon Ross * Client side wrapper for SamrUnicodeChangePasswordUser2 9621ed6b69aSGordon Ross * [MS-SAMR 3.1.5.10.3] 963fe1c642dSBill Krier */ 9641ed6b69aSGordon Ross 9651ed6b69aSGordon Ross DWORD 9661ed6b69aSGordon Ross samr_change_password( 9671ed6b69aSGordon Ross mlsvc_handle_t *handle, 9681ed6b69aSGordon Ross char *server, 9691ed6b69aSGordon Ross char *account, 9701ed6b69aSGordon Ross struct samr_encr_passwd *newpw, 9711ed6b69aSGordon Ross struct samr_encr_hash *oldpw) 972fe1c642dSBill Krier { 9731ed6b69aSGordon Ross static struct samr_encr_passwd zero_newpw; 9741ed6b69aSGordon Ross static struct samr_encr_hash zero_oldpw; 9751ed6b69aSGordon Ross struct samr_ChangePasswordUser2 arg; 9761ed6b69aSGordon Ross int opnum = SAMR_OPNUM_ChangePasswordUser2; 9771ed6b69aSGordon Ross char *slashserver; 9781ed6b69aSGordon Ross int len; 979fe1c642dSBill Krier 9801ed6b69aSGordon Ross (void) memset(&arg, 0, sizeof (arg)); 981fe1c642dSBill Krier 9821ed6b69aSGordon Ross /* Need server name with slashes */ 9831ed6b69aSGordon Ross len = 2 + strlen(server) + 1; 9841ed6b69aSGordon Ross slashserver = ndr_rpc_malloc(handle, len); 9851ed6b69aSGordon Ross if (slashserver == NULL) 9861ed6b69aSGordon Ross return (NT_STATUS_NO_MEMORY); 9871ed6b69aSGordon Ross (void) snprintf(slashserver, len, "\\\\%s", server); 988fe1c642dSBill Krier 9891ed6b69aSGordon Ross arg.servername = ndr_rpc_malloc(handle, sizeof (samr_string_t)); 9901ed6b69aSGordon Ross if (arg.servername == NULL) 9911ed6b69aSGordon Ross return (NT_STATUS_NO_MEMORY); 9921ed6b69aSGordon Ross len = smb_wcequiv_strlen(slashserver); 9931ed6b69aSGordon Ross if (len < 1) 9941ed6b69aSGordon Ross return (NT_STATUS_INVALID_PARAMETER); 9951ed6b69aSGordon Ross len += 2; /* the WC null */ 9961ed6b69aSGordon Ross arg.servername->length = len; 9971ed6b69aSGordon Ross arg.servername->allosize = len; 9981ed6b69aSGordon Ross arg.servername->str = (uint8_t *)slashserver; 999fe1c642dSBill Krier 10001ed6b69aSGordon Ross arg.username = ndr_rpc_malloc(handle, sizeof (samr_string_t)); 10011ed6b69aSGordon Ross if (arg.username == NULL) 10021ed6b69aSGordon Ross return (NT_STATUS_NO_MEMORY); 10031ed6b69aSGordon Ross len = smb_wcequiv_strlen(account); 10041ed6b69aSGordon Ross if (len < 1) 10051ed6b69aSGordon Ross return (NT_STATUS_INVALID_PARAMETER); 10061ed6b69aSGordon Ross len += 2; /* the WC null */ 10071ed6b69aSGordon Ross arg.username->length = len; 10081ed6b69aSGordon Ross arg.username->allosize = len; 10091ed6b69aSGordon Ross arg.username->str = (uint8_t *)account; 1010fe1c642dSBill Krier 10111ed6b69aSGordon Ross arg.nt_newpw = newpw; 10121ed6b69aSGordon Ross arg.nt_oldpw = oldpw; 1013fe1c642dSBill Krier 10141ed6b69aSGordon Ross arg.lm_newpw = &zero_newpw; 10151ed6b69aSGordon Ross arg.lm_oldpw = &zero_oldpw; 10161ed6b69aSGordon Ross 10171ed6b69aSGordon Ross if (ndr_rpc_call(handle, opnum, &arg) != 0) 10181ed6b69aSGordon Ross arg.status = RPC_NT_CALL_FAILED; 10191ed6b69aSGordon Ross else if (arg.status != 0) 10201ed6b69aSGordon Ross ndr_rpc_status(handle, opnum, arg.status); 10211ed6b69aSGordon Ross 10221ed6b69aSGordon Ross ndr_rpc_release(handle); 10231ed6b69aSGordon Ross return (arg.status); 1024fe1c642dSBill Krier } 1025