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 */ 21*148c5f43SAlan Wright 22fe1c642dSBill Krier /* 23*148c5f43SAlan Wright * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. 24fe1c642dSBill Krier */ 25fe1c642dSBill Krier 26fe1c642dSBill Krier /* 27fe1c642dSBill Krier * Security Accounts Manager RPC (SAMR) client-side interface. 28fe1c642dSBill Krier * 29fe1c642dSBill Krier * The SAM is a hierarchical database: 30fe1c642dSBill Krier * - If you want to talk to the SAM you need a SAM handle. 31fe1c642dSBill Krier * - If you want to work with a domain, use the SAM handle. 32fe1c642dSBill Krier * to obtain a domain handle. 33fe1c642dSBill Krier * - Use domain handles to obtain user handles etc. 34fe1c642dSBill Krier * 35fe1c642dSBill Krier * Be careful about returning null handles to the application. Use of a 36fe1c642dSBill Krier * null handle may crash the domain controller if you attempt to use it. 37fe1c642dSBill Krier */ 38fe1c642dSBill Krier 39fe1c642dSBill Krier #include <stdio.h> 40fe1c642dSBill Krier #include <strings.h> 41fe1c642dSBill Krier #include <stdlib.h> 42fe1c642dSBill Krier #include <unistd.h> 43fe1c642dSBill Krier #include <netdb.h> 44fe1c642dSBill Krier #include <sys/param.h> 45fe1c642dSBill Krier 46fe1c642dSBill Krier #include <smbsrv/libsmb.h> 47fe1c642dSBill Krier #include <smbsrv/libmlrpc.h> 48fe1c642dSBill Krier #include <smbsrv/libmlsvc.h> 49fe1c642dSBill Krier #include <smbsrv/smbinfo.h> 50fe1c642dSBill Krier #include <smbsrv/ntaccess.h> 51fe1c642dSBill Krier #include <smbsrv/smb_sid.h> 52fe1c642dSBill Krier #include <samlib.h> 53fe1c642dSBill Krier 54fe1c642dSBill Krier /*LINTED E_STATIC_UNUSED*/ 55fe1c642dSBill Krier static DWORD samr_connect1(char *, char *, char *, DWORD, mlsvc_handle_t *); 56fe1c642dSBill Krier static DWORD samr_connect2(char *, char *, char *, DWORD, mlsvc_handle_t *); 57fe1c642dSBill Krier static DWORD samr_connect3(char *, char *, char *, DWORD, mlsvc_handle_t *); 58fe1c642dSBill Krier static DWORD samr_connect4(char *, char *, char *, DWORD, mlsvc_handle_t *); 59fe1c642dSBill Krier 60fe1c642dSBill Krier typedef DWORD (*samr_connop_t)(char *, char *, char *, DWORD, 61fe1c642dSBill Krier mlsvc_handle_t *); 62fe1c642dSBill Krier 63fe1c642dSBill Krier static int samr_setup_user_info(WORD, struct samr_QueryUserInfo *, 64fe1c642dSBill Krier union samr_user_info *); 65fe1c642dSBill Krier static void samr_set_user_unknowns(struct samr_SetUserInfo23 *); 66fe1c642dSBill Krier static void samr_set_user_logon_hours(struct samr_SetUserInfo *); 67fe1c642dSBill Krier static int samr_set_user_password(unsigned char *, BYTE *); 68fe1c642dSBill Krier 69fe1c642dSBill Krier /* 70fe1c642dSBill Krier * samr_open 71fe1c642dSBill Krier * 72fe1c642dSBill Krier * Wrapper round samr_connect to ensure that we connect using the server 73fe1c642dSBill Krier * and domain. We default to the resource domain if the caller doesn't 74fe1c642dSBill Krier * supply a server name and a domain name. 75fe1c642dSBill Krier * 76fe1c642dSBill Krier * If username argument is NULL, an anonymous connection will be established. 77fe1c642dSBill Krier * Otherwise, an authenticated connection will be established. 78fe1c642dSBill Krier * 79fe1c642dSBill Krier * On success 0 is returned. Otherwise a -ve error code. 80fe1c642dSBill Krier */ 81fe1c642dSBill Krier int 82fe1c642dSBill Krier samr_open(char *server, char *domain, char *username, DWORD access_mask, 83fe1c642dSBill Krier mlsvc_handle_t *samr_handle) 84fe1c642dSBill Krier { 85fe1c642dSBill Krier smb_domainex_t di; 86fe1c642dSBill Krier int rc; 87fe1c642dSBill Krier 88fe1c642dSBill Krier if (server == NULL || domain == NULL) { 89fe1c642dSBill Krier if (!smb_domain_getinfo(&di)) 90fe1c642dSBill Krier return (-1); 91fe1c642dSBill Krier 92fe1c642dSBill Krier server = di.d_dc; 93fe1c642dSBill Krier domain = di.d_primary.di_nbname; 94fe1c642dSBill Krier } 95fe1c642dSBill Krier 96fe1c642dSBill Krier if (username == NULL) 97fe1c642dSBill Krier username = MLSVC_ANON_USER; 98fe1c642dSBill Krier 99fe1c642dSBill Krier rc = samr_connect(server, domain, username, access_mask, samr_handle); 100fe1c642dSBill Krier return (rc); 101fe1c642dSBill Krier } 102fe1c642dSBill Krier 103fe1c642dSBill Krier 104fe1c642dSBill Krier /* 105fe1c642dSBill Krier * samr_connect 106fe1c642dSBill Krier * 107fe1c642dSBill Krier * Connect to the SAMR service on the specified server (domain controller). 108fe1c642dSBill Krier * New SAM connect calls have been added to Windows over time: 109fe1c642dSBill Krier * 110fe1c642dSBill Krier * Windows NT3.x: SamrConnect 111fe1c642dSBill Krier * Windows NT4.0: SamrConnect2 112fe1c642dSBill Krier * Windows 2000: SamrConnect3 113fe1c642dSBill Krier * Windows XP: SamrConnect4 114fe1c642dSBill Krier * 115fe1c642dSBill Krier * Try the calls from most recent to oldest until the server responds with 116fe1c642dSBill Krier * something other than an RPC protocol error. We don't use the original 117fe1c642dSBill Krier * connect call because all supported servers should support SamrConnect2. 118fe1c642dSBill Krier */ 119fe1c642dSBill Krier int 120fe1c642dSBill Krier samr_connect(char *server, char *domain, char *username, DWORD access_mask, 121fe1c642dSBill Krier mlsvc_handle_t *samr_handle) 122fe1c642dSBill Krier { 123fe1c642dSBill Krier static samr_connop_t samr_connop[] = { 124fe1c642dSBill Krier samr_connect4, 125fe1c642dSBill Krier samr_connect3, 126fe1c642dSBill Krier samr_connect2 127fe1c642dSBill Krier }; 128fe1c642dSBill Krier 129fe1c642dSBill Krier int n_op = (sizeof (samr_connop) / sizeof (samr_connop[0])); 130fe1c642dSBill Krier DWORD status; 131fe1c642dSBill Krier int i; 132fe1c642dSBill Krier 133fe1c642dSBill Krier if (ndr_rpc_bind(samr_handle, server, domain, username, "SAMR") < 0) 134fe1c642dSBill Krier return (-1); 135fe1c642dSBill Krier 136fe1c642dSBill Krier for (i = 0; i < n_op; ++i) { 137fe1c642dSBill Krier status = (*samr_connop[i])(server, domain, username, 138fe1c642dSBill Krier access_mask, samr_handle); 139fe1c642dSBill Krier 140fe1c642dSBill Krier if (status != NT_STATUS_UNSUCCESSFUL) 141fe1c642dSBill Krier break; 142fe1c642dSBill Krier } 143fe1c642dSBill Krier 144fe1c642dSBill Krier if (status != NT_STATUS_SUCCESS) { 145fe1c642dSBill Krier ndr_rpc_unbind(samr_handle); 146fe1c642dSBill Krier return (-1); 147fe1c642dSBill Krier } 148fe1c642dSBill Krier 149fe1c642dSBill Krier return (0); 150fe1c642dSBill Krier } 151fe1c642dSBill Krier 152fe1c642dSBill Krier /* 153fe1c642dSBill Krier * samr_connect1 154fe1c642dSBill Krier * 155fe1c642dSBill Krier * Original SAMR connect call; probably used on Windows NT 3.51. 156fe1c642dSBill Krier * Windows 95 uses this call with the srvmgr tools update. 157fe1c642dSBill Krier * Servername appears to be a dword rather than a string. 158fe1c642dSBill Krier * The first word contains '\' and the second word contains 0x001, 159fe1c642dSBill Krier * (which is probably uninitialized junk: 0x0001005c. 160fe1c642dSBill Krier */ 161fe1c642dSBill Krier /*ARGSUSED*/ 162fe1c642dSBill Krier static DWORD 163fe1c642dSBill Krier samr_connect1(char *server, char *domain, char *username, DWORD access_mask, 164fe1c642dSBill Krier mlsvc_handle_t *samr_handle) 165fe1c642dSBill Krier { 166fe1c642dSBill Krier struct samr_ConnectAnon arg; 167fe1c642dSBill Krier int opnum; 168fe1c642dSBill Krier DWORD status; 169fe1c642dSBill Krier 170fe1c642dSBill Krier bzero(&arg, sizeof (struct samr_ConnectAnon)); 171fe1c642dSBill Krier opnum = SAMR_OPNUM_ConnectAnon; 172fe1c642dSBill Krier status = NT_STATUS_SUCCESS; 173fe1c642dSBill Krier 174fe1c642dSBill Krier arg.servername = ndr_rpc_malloc(samr_handle, sizeof (DWORD)); 175fe1c642dSBill Krier *(arg.servername) = 0x0001005c; 176fe1c642dSBill Krier arg.access_mask = access_mask; 177fe1c642dSBill Krier 178fe1c642dSBill Krier if (ndr_rpc_call(samr_handle, opnum, &arg) != 0) { 179fe1c642dSBill Krier status = NT_STATUS_UNSUCCESSFUL; 180fe1c642dSBill Krier } else if (arg.status != 0) { 181fe1c642dSBill Krier status = NT_SC_VALUE(arg.status); 182fe1c642dSBill Krier } else { 183fe1c642dSBill Krier (void) memcpy(&samr_handle->handle, &arg.handle, 184fe1c642dSBill Krier sizeof (ndr_hdid_t)); 185fe1c642dSBill Krier 186fe1c642dSBill Krier if (ndr_is_null_handle(samr_handle)) 187fe1c642dSBill Krier status = NT_STATUS_INVALID_HANDLE; 188fe1c642dSBill Krier } 189fe1c642dSBill Krier 190fe1c642dSBill Krier ndr_rpc_release(samr_handle); 191fe1c642dSBill Krier return (status); 192fe1c642dSBill Krier } 193fe1c642dSBill Krier 194fe1c642dSBill Krier /* 195fe1c642dSBill Krier * samr_connect2 196fe1c642dSBill Krier * 197fe1c642dSBill Krier * Connect to the SAM on a Windows NT 4.0 server (domain controller). 198fe1c642dSBill Krier * We need the domain controller name and, if everything works, we 199fe1c642dSBill Krier * return a handle. This function adds the double backslash prefx to 200fe1c642dSBill Krier * make it easy for applications. 201fe1c642dSBill Krier * 202fe1c642dSBill Krier * Returns 0 on success. Otherwise returns a -ve error code. 203fe1c642dSBill Krier */ 204fe1c642dSBill Krier /*ARGSUSED*/ 205fe1c642dSBill Krier static DWORD 206fe1c642dSBill Krier samr_connect2(char *server, char *domain, char *username, DWORD access_mask, 207fe1c642dSBill Krier mlsvc_handle_t *samr_handle) 208fe1c642dSBill Krier { 209fe1c642dSBill Krier struct samr_Connect arg; 210fe1c642dSBill Krier int opnum; 211fe1c642dSBill Krier DWORD status; 212fe1c642dSBill Krier int len; 213fe1c642dSBill Krier 214fe1c642dSBill Krier bzero(&arg, sizeof (struct samr_Connect)); 215fe1c642dSBill Krier opnum = SAMR_OPNUM_Connect; 216fe1c642dSBill Krier status = NT_STATUS_SUCCESS; 217fe1c642dSBill Krier 218fe1c642dSBill Krier len = strlen(server) + 4; 219fe1c642dSBill Krier arg.servername = ndr_rpc_malloc(samr_handle, len); 220fe1c642dSBill Krier (void) snprintf((char *)arg.servername, len, "\\\\%s", server); 221fe1c642dSBill Krier arg.access_mask = access_mask; 222fe1c642dSBill Krier 223fe1c642dSBill Krier if (ndr_rpc_call(samr_handle, opnum, &arg) != 0) { 224fe1c642dSBill Krier status = NT_STATUS_UNSUCCESSFUL; 225fe1c642dSBill Krier } else if (arg.status != 0) { 226fe1c642dSBill Krier status = NT_SC_VALUE(arg.status); 227fe1c642dSBill Krier } else { 228fe1c642dSBill Krier (void) memcpy(&samr_handle->handle, &arg.handle, 229fe1c642dSBill Krier sizeof (ndr_hdid_t)); 230fe1c642dSBill Krier 231fe1c642dSBill Krier if (ndr_is_null_handle(samr_handle)) 232fe1c642dSBill Krier status = NT_STATUS_INVALID_HANDLE; 233fe1c642dSBill Krier } 234fe1c642dSBill Krier 235fe1c642dSBill Krier ndr_rpc_release(samr_handle); 236fe1c642dSBill Krier return (status); 237fe1c642dSBill Krier } 238fe1c642dSBill Krier 239fe1c642dSBill Krier /* 240fe1c642dSBill Krier * samr_connect3 241fe1c642dSBill Krier * 242fe1c642dSBill Krier * Connect to the SAM on a Windows 2000 domain controller. 243fe1c642dSBill Krier */ 244fe1c642dSBill Krier /*ARGSUSED*/ 245fe1c642dSBill Krier static DWORD 246fe1c642dSBill Krier samr_connect3(char *server, char *domain, char *username, DWORD access_mask, 247fe1c642dSBill Krier mlsvc_handle_t *samr_handle) 248fe1c642dSBill Krier { 249fe1c642dSBill Krier struct samr_Connect3 arg; 250fe1c642dSBill Krier int opnum; 251fe1c642dSBill Krier DWORD status; 252fe1c642dSBill Krier int len; 253fe1c642dSBill Krier 254fe1c642dSBill Krier bzero(&arg, sizeof (struct samr_Connect3)); 255fe1c642dSBill Krier opnum = SAMR_OPNUM_Connect3; 256fe1c642dSBill Krier status = NT_STATUS_SUCCESS; 257fe1c642dSBill Krier 258fe1c642dSBill Krier len = strlen(server) + 4; 259fe1c642dSBill Krier arg.servername = ndr_rpc_malloc(samr_handle, len); 260fe1c642dSBill Krier (void) snprintf((char *)arg.servername, len, "\\\\%s", server); 261fe1c642dSBill Krier arg.revision = SAMR_REVISION_2; 262fe1c642dSBill Krier arg.access_mask = access_mask; 263fe1c642dSBill Krier 264fe1c642dSBill Krier if (ndr_rpc_call(samr_handle, opnum, &arg) != 0) { 265fe1c642dSBill Krier status = NT_STATUS_UNSUCCESSFUL; 266fe1c642dSBill Krier } else if (arg.status != 0) { 267fe1c642dSBill Krier status = NT_SC_VALUE(arg.status); 268fe1c642dSBill Krier } else { 269fe1c642dSBill Krier (void) memcpy(&samr_handle->handle, &arg.handle, 270fe1c642dSBill Krier sizeof (ndr_hdid_t)); 271fe1c642dSBill Krier 272fe1c642dSBill Krier if (ndr_is_null_handle(samr_handle)) 273fe1c642dSBill Krier status = NT_STATUS_INVALID_HANDLE; 274fe1c642dSBill Krier } 275fe1c642dSBill Krier 276fe1c642dSBill Krier ndr_rpc_release(samr_handle); 277fe1c642dSBill Krier return (status); 278fe1c642dSBill Krier } 279fe1c642dSBill Krier 280fe1c642dSBill Krier /* 281fe1c642dSBill Krier * samr_connect4 282fe1c642dSBill Krier * 283fe1c642dSBill Krier * Connect to the SAM on a Windows XP domain controller. On Windows 284fe1c642dSBill Krier * XP, the server should be the fully qualified DNS domain name with 285fe1c642dSBill Krier * a double backslash prefix. At this point, it is assumed that we 286fe1c642dSBill Krier * need to add the prefix and the DNS domain name here. 287fe1c642dSBill Krier * 288fe1c642dSBill Krier * If this call succeeds, a SAMR handle is placed in samr_handle and 289fe1c642dSBill Krier * zero is returned. Otherwise, a -ve error code is returned. 290fe1c642dSBill Krier */ 291fe1c642dSBill Krier /*ARGSUSED*/ 292fe1c642dSBill Krier static DWORD 293fe1c642dSBill Krier samr_connect4(char *server, char *domain, char *username, DWORD access_mask, 294fe1c642dSBill Krier mlsvc_handle_t *samr_handle) 295fe1c642dSBill Krier { 296fe1c642dSBill Krier struct samr_Connect4 arg; 297fe1c642dSBill Krier int len; 298fe1c642dSBill Krier int opnum; 299fe1c642dSBill Krier DWORD status; 300fe1c642dSBill Krier smb_domainex_t dinfo; 301fe1c642dSBill Krier 302fe1c642dSBill Krier bzero(&arg, sizeof (struct samr_Connect4)); 303fe1c642dSBill Krier opnum = SAMR_OPNUM_Connect; 304fe1c642dSBill Krier status = NT_STATUS_SUCCESS; 305fe1c642dSBill Krier 306fe1c642dSBill Krier if (!smb_domain_getinfo(&dinfo)) 307fe1c642dSBill Krier return (NT_STATUS_CANT_ACCESS_DOMAIN_INFO); 308fe1c642dSBill Krier 309fe1c642dSBill Krier len = strlen(server) + strlen(dinfo.d_primary.di_fqname) + 4; 310fe1c642dSBill Krier arg.servername = ndr_rpc_malloc(samr_handle, len); 311fe1c642dSBill Krier 312fe1c642dSBill Krier if (*dinfo.d_primary.di_fqname != '\0') 313fe1c642dSBill Krier (void) snprintf((char *)arg.servername, len, "\\\\%s.%s", 314fe1c642dSBill Krier server, dinfo.d_primary.di_fqname); 315fe1c642dSBill Krier else 316fe1c642dSBill Krier (void) snprintf((char *)arg.servername, len, "\\\\%s", server); 317fe1c642dSBill Krier 318fe1c642dSBill Krier arg.access_mask = SAM_ENUM_LOCAL_DOMAIN; 319fe1c642dSBill Krier arg.unknown2_00000001 = 0x00000001; 320fe1c642dSBill Krier arg.unknown3_00000001 = 0x00000001; 321fe1c642dSBill Krier arg.unknown4_00000003 = 0x00000003; 322fe1c642dSBill Krier arg.unknown5_00000000 = 0x00000000; 323fe1c642dSBill Krier 324fe1c642dSBill Krier if (ndr_rpc_call(samr_handle, opnum, &arg) != 0) { 325fe1c642dSBill Krier status = NT_STATUS_UNSUCCESSFUL; 326fe1c642dSBill Krier } else if (arg.status != 0) { 327fe1c642dSBill Krier status = NT_SC_VALUE(arg.status); 328fe1c642dSBill Krier } else { 329fe1c642dSBill Krier 330fe1c642dSBill Krier (void) memcpy(&samr_handle->handle, &arg.handle, 331fe1c642dSBill Krier sizeof (ndr_hdid_t)); 332fe1c642dSBill Krier 333fe1c642dSBill Krier if (ndr_is_null_handle(samr_handle)) 334fe1c642dSBill Krier status = NT_STATUS_INVALID_HANDLE; 335fe1c642dSBill Krier } 336fe1c642dSBill Krier 337fe1c642dSBill Krier ndr_rpc_release(samr_handle); 338fe1c642dSBill Krier return (status); 339fe1c642dSBill Krier } 340fe1c642dSBill Krier 341fe1c642dSBill Krier 342fe1c642dSBill Krier /* 343fe1c642dSBill Krier * samr_close_handle 344fe1c642dSBill Krier * 345fe1c642dSBill Krier * This is function closes any valid handle, i.e. sam, domain, user etc. 346fe1c642dSBill Krier * If the handle being closed is the top level connect handle, we unbind. 347fe1c642dSBill Krier * Then we zero out the handle to invalidate it. 348fe1c642dSBill Krier */ 349fe1c642dSBill Krier int 350fe1c642dSBill Krier samr_close_handle(mlsvc_handle_t *samr_handle) 351fe1c642dSBill Krier { 352fe1c642dSBill Krier struct samr_CloseHandle arg; 353fe1c642dSBill Krier int opnum; 354fe1c642dSBill Krier 355fe1c642dSBill Krier if (ndr_is_null_handle(samr_handle)) 356fe1c642dSBill Krier return (-1); 357fe1c642dSBill Krier 358fe1c642dSBill Krier opnum = SAMR_OPNUM_CloseHandle; 359fe1c642dSBill Krier bzero(&arg, sizeof (struct samr_CloseHandle)); 360fe1c642dSBill Krier (void) memcpy(&arg.handle, &samr_handle->handle, sizeof (ndr_hdid_t)); 361fe1c642dSBill Krier 362fe1c642dSBill Krier (void) ndr_rpc_call(samr_handle, opnum, &arg); 363fe1c642dSBill Krier ndr_rpc_release(samr_handle); 364fe1c642dSBill Krier 365fe1c642dSBill Krier if (ndr_is_bind_handle(samr_handle)) 366fe1c642dSBill Krier ndr_rpc_unbind(samr_handle); 367fe1c642dSBill Krier 368fe1c642dSBill Krier bzero(samr_handle, sizeof (mlsvc_handle_t)); 369fe1c642dSBill Krier return (0); 370fe1c642dSBill Krier } 371fe1c642dSBill Krier 372fe1c642dSBill Krier /* 373fe1c642dSBill Krier * samr_open_domain 374fe1c642dSBill Krier * 375fe1c642dSBill Krier * We use a SAM handle to obtain a handle for a domain, specified by 376fe1c642dSBill Krier * the SID. The SID can be obtain via the LSA interface. A handle for 377fe1c642dSBill Krier * the domain is returned in domain_handle. 378fe1c642dSBill Krier */ 379fe1c642dSBill Krier DWORD 380fe1c642dSBill Krier samr_open_domain(mlsvc_handle_t *samr_handle, DWORD access_mask, 381fe1c642dSBill Krier struct samr_sid *sid, mlsvc_handle_t *domain_handle) 382fe1c642dSBill Krier { 383fe1c642dSBill Krier struct samr_OpenDomain arg; 384fe1c642dSBill Krier int opnum; 385fe1c642dSBill Krier DWORD status; 386fe1c642dSBill Krier 387fe1c642dSBill Krier if (ndr_is_null_handle(samr_handle) || 388fe1c642dSBill Krier sid == NULL || domain_handle == NULL) { 389fe1c642dSBill Krier return (NT_STATUS_INVALID_PARAMETER); 390fe1c642dSBill Krier } 391fe1c642dSBill Krier 392fe1c642dSBill Krier opnum = SAMR_OPNUM_OpenDomain; 393fe1c642dSBill Krier bzero(&arg, sizeof (struct samr_OpenDomain)); 394fe1c642dSBill Krier (void) memcpy(&arg.handle, &samr_handle->handle, sizeof (ndr_hdid_t)); 395fe1c642dSBill Krier 396fe1c642dSBill Krier arg.access_mask = access_mask; 397fe1c642dSBill Krier arg.sid = sid; 398fe1c642dSBill Krier 399fe1c642dSBill Krier if (ndr_rpc_call(samr_handle, opnum, &arg) != 0) { 400fe1c642dSBill Krier status = NT_STATUS_UNSUCCESSFUL; 401fe1c642dSBill Krier } else if (arg.status != 0) { 402fe1c642dSBill Krier status = arg.status; 403fe1c642dSBill Krier } else { 404fe1c642dSBill Krier status = NT_STATUS_SUCCESS; 405fe1c642dSBill Krier ndr_inherit_handle(domain_handle, samr_handle); 406fe1c642dSBill Krier 407fe1c642dSBill Krier (void) memcpy(&domain_handle->handle, &arg.domain_handle, 408fe1c642dSBill Krier sizeof (ndr_hdid_t)); 409fe1c642dSBill Krier 410fe1c642dSBill Krier if (ndr_is_null_handle(domain_handle)) 411fe1c642dSBill Krier status = NT_STATUS_INVALID_HANDLE; 412fe1c642dSBill Krier } 413fe1c642dSBill Krier 414fe1c642dSBill Krier if (status != NT_STATUS_SUCCESS) 415fe1c642dSBill Krier ndr_rpc_status(samr_handle, opnum, status); 416fe1c642dSBill Krier 417fe1c642dSBill Krier ndr_rpc_release(samr_handle); 418fe1c642dSBill Krier return (status); 419fe1c642dSBill Krier } 420fe1c642dSBill Krier 421fe1c642dSBill Krier /* 422fe1c642dSBill Krier * samr_open_user 423fe1c642dSBill Krier * 424fe1c642dSBill Krier * Use a domain handle to obtain a handle for a user, specified by the 425fe1c642dSBill Krier * user RID. A user RID (effectively a uid) can be obtained via the 426fe1c642dSBill Krier * LSA interface. A handle for the user is returned in user_handle. 427fe1c642dSBill Krier * Once you have a user handle it should be possible to query the SAM 428fe1c642dSBill Krier * for information on that user. 429fe1c642dSBill Krier */ 430fe1c642dSBill Krier DWORD 431fe1c642dSBill Krier samr_open_user(mlsvc_handle_t *domain_handle, DWORD access_mask, DWORD rid, 432fe1c642dSBill Krier mlsvc_handle_t *user_handle) 433fe1c642dSBill Krier { 434fe1c642dSBill Krier struct samr_OpenUser arg; 435fe1c642dSBill Krier int opnum; 436fe1c642dSBill Krier DWORD status = NT_STATUS_SUCCESS; 437fe1c642dSBill Krier 438fe1c642dSBill Krier if (ndr_is_null_handle(domain_handle) || user_handle == NULL) 439fe1c642dSBill Krier return (NT_STATUS_INVALID_PARAMETER); 440fe1c642dSBill Krier 441fe1c642dSBill Krier opnum = SAMR_OPNUM_OpenUser; 442fe1c642dSBill Krier bzero(&arg, sizeof (struct samr_OpenUser)); 443fe1c642dSBill Krier (void) memcpy(&arg.handle, &domain_handle->handle, 444fe1c642dSBill Krier sizeof (ndr_hdid_t)); 445fe1c642dSBill Krier arg.access_mask = access_mask; 446fe1c642dSBill Krier arg.rid = rid; 447fe1c642dSBill Krier 448fe1c642dSBill Krier if (ndr_rpc_call(domain_handle, opnum, &arg) != 0) { 449fe1c642dSBill Krier status = NT_STATUS_UNSUCCESSFUL; 450fe1c642dSBill Krier } else if (arg.status != 0) { 451fe1c642dSBill Krier ndr_rpc_status(domain_handle, opnum, arg.status); 452fe1c642dSBill Krier status = NT_SC_VALUE(arg.status); 453fe1c642dSBill Krier } else { 454fe1c642dSBill Krier ndr_inherit_handle(user_handle, domain_handle); 455fe1c642dSBill Krier 456fe1c642dSBill Krier (void) memcpy(&user_handle->handle, &arg.user_handle, 457fe1c642dSBill Krier sizeof (ndr_hdid_t)); 458fe1c642dSBill Krier 459fe1c642dSBill Krier if (ndr_is_null_handle(user_handle)) 460fe1c642dSBill Krier status = NT_STATUS_INVALID_HANDLE; 461fe1c642dSBill Krier } 462fe1c642dSBill Krier 463fe1c642dSBill Krier ndr_rpc_release(domain_handle); 464fe1c642dSBill Krier return (status); 465fe1c642dSBill Krier } 466fe1c642dSBill Krier 467fe1c642dSBill Krier /* 468fe1c642dSBill Krier * samr_delete_user 469fe1c642dSBill Krier * 470fe1c642dSBill Krier * Delete the user specified by the user_handle. 471fe1c642dSBill Krier */ 472fe1c642dSBill Krier DWORD 473fe1c642dSBill Krier samr_delete_user(mlsvc_handle_t *user_handle) 474fe1c642dSBill Krier { 475fe1c642dSBill Krier struct samr_DeleteUser arg; 476fe1c642dSBill Krier int opnum; 477fe1c642dSBill Krier DWORD status; 478fe1c642dSBill Krier 479fe1c642dSBill Krier if (ndr_is_null_handle(user_handle)) 480fe1c642dSBill Krier return (NT_STATUS_INVALID_PARAMETER); 481fe1c642dSBill Krier 482fe1c642dSBill Krier opnum = SAMR_OPNUM_DeleteUser; 483fe1c642dSBill Krier bzero(&arg, sizeof (struct samr_DeleteUser)); 484fe1c642dSBill Krier (void) memcpy(&arg.user_handle, &user_handle->handle, 485fe1c642dSBill Krier sizeof (ndr_hdid_t)); 486fe1c642dSBill Krier 487fe1c642dSBill Krier if (ndr_rpc_call(user_handle, opnum, &arg) != 0) { 488fe1c642dSBill Krier status = NT_STATUS_INVALID_PARAMETER; 489fe1c642dSBill Krier } else if (arg.status != 0) { 490fe1c642dSBill Krier ndr_rpc_status(user_handle, opnum, arg.status); 491fe1c642dSBill Krier status = NT_SC_VALUE(arg.status); 492fe1c642dSBill Krier } else { 493fe1c642dSBill Krier status = 0; 494fe1c642dSBill Krier } 495fe1c642dSBill Krier 496fe1c642dSBill Krier ndr_rpc_release(user_handle); 497fe1c642dSBill Krier return (status); 498fe1c642dSBill Krier } 499fe1c642dSBill Krier 500fe1c642dSBill Krier /* 501fe1c642dSBill Krier * samr_open_group 502fe1c642dSBill Krier * 503fe1c642dSBill Krier * Use a domain handle to obtain a handle for a group, specified by the 504fe1c642dSBill Krier * group RID. A group RID (effectively a gid) can be obtained via the 505fe1c642dSBill Krier * LSA interface. A handle for the group is returned in group_handle. 506fe1c642dSBill Krier * Once you have a group handle it should be possible to query the SAM 507fe1c642dSBill Krier * for information on that group. 508fe1c642dSBill Krier */ 509fe1c642dSBill Krier int 510fe1c642dSBill Krier samr_open_group( 511fe1c642dSBill Krier mlsvc_handle_t *domain_handle, 512fe1c642dSBill Krier DWORD rid, 513fe1c642dSBill Krier mlsvc_handle_t *group_handle) 514fe1c642dSBill Krier { 515fe1c642dSBill Krier struct samr_OpenGroup arg; 516fe1c642dSBill Krier int opnum; 517fe1c642dSBill Krier int rc; 518fe1c642dSBill Krier 519fe1c642dSBill Krier if (ndr_is_null_handle(domain_handle) || group_handle == NULL) 520fe1c642dSBill Krier return (-1); 521fe1c642dSBill Krier 522fe1c642dSBill Krier opnum = SAMR_OPNUM_OpenGroup; 523fe1c642dSBill Krier bzero(&arg, sizeof (struct samr_OpenUser)); 524fe1c642dSBill Krier (void) memcpy(&arg.handle, &domain_handle->handle, 525fe1c642dSBill Krier sizeof (ndr_hdid_t)); 526fe1c642dSBill Krier arg.access_mask = SAM_LOOKUP_INFORMATION | SAM_ACCESS_USER_READ; 527fe1c642dSBill Krier arg.rid = rid; 528fe1c642dSBill Krier 529fe1c642dSBill Krier if ((rc = ndr_rpc_call(domain_handle, opnum, &arg)) != 0) 530fe1c642dSBill Krier return (-1); 531fe1c642dSBill Krier 532fe1c642dSBill Krier if (arg.status != 0) { 533fe1c642dSBill Krier ndr_rpc_status(domain_handle, opnum, arg.status); 534fe1c642dSBill Krier rc = -1; 535fe1c642dSBill Krier } else { 536fe1c642dSBill Krier ndr_inherit_handle(group_handle, domain_handle); 537fe1c642dSBill Krier 538fe1c642dSBill Krier (void) memcpy(&group_handle->handle, &arg.group_handle, 539fe1c642dSBill Krier sizeof (ndr_hdid_t)); 540fe1c642dSBill Krier 541fe1c642dSBill Krier if (ndr_is_null_handle(group_handle)) 542fe1c642dSBill Krier rc = -1; 543fe1c642dSBill Krier } 544fe1c642dSBill Krier 545fe1c642dSBill Krier ndr_rpc_release(domain_handle); 546fe1c642dSBill Krier return (rc); 547fe1c642dSBill Krier } 548fe1c642dSBill Krier 549fe1c642dSBill Krier /* 550fe1c642dSBill Krier * samr_create_user 551fe1c642dSBill Krier * 552fe1c642dSBill Krier * Create a user in the domain specified by the domain handle. If this 553fe1c642dSBill Krier * call is successful, the server will return the RID for the user and 554fe1c642dSBill Krier * a user handle, which may be used to set or query the SAM. 555fe1c642dSBill Krier * 556fe1c642dSBill Krier * Observed status codes: 557fe1c642dSBill Krier * NT_STATUS_INVALID_PARAMETER 558fe1c642dSBill Krier * NT_STATUS_INVALID_ACCOUNT_NAME 559fe1c642dSBill Krier * NT_STATUS_ACCESS_DENIED 560fe1c642dSBill Krier * NT_STATUS_USER_EXISTS 561fe1c642dSBill Krier * 562fe1c642dSBill Krier * Returns 0 on success. Otherwise returns an NT status code. 563fe1c642dSBill Krier */ 564fe1c642dSBill Krier DWORD 565fe1c642dSBill Krier samr_create_user(mlsvc_handle_t *domain_handle, char *username, 566fe1c642dSBill Krier DWORD account_flags, DWORD *rid, mlsvc_handle_t *user_handle) 567fe1c642dSBill Krier { 568fe1c642dSBill Krier struct samr_CreateUser arg; 569fe1c642dSBill Krier ndr_heap_t *heap; 570fe1c642dSBill Krier int opnum; 571fe1c642dSBill Krier int rc; 572fe1c642dSBill Krier DWORD status = 0; 573fe1c642dSBill Krier 574fe1c642dSBill Krier if (ndr_is_null_handle(domain_handle) || 575fe1c642dSBill Krier username == NULL || rid == NULL) { 576fe1c642dSBill Krier return (NT_STATUS_INVALID_PARAMETER); 577fe1c642dSBill Krier } 578fe1c642dSBill Krier 579fe1c642dSBill Krier opnum = SAMR_OPNUM_CreateUser; 580fe1c642dSBill Krier 581fe1c642dSBill Krier bzero(&arg, sizeof (struct samr_CreateUser)); 582fe1c642dSBill Krier (void) memcpy(&arg.handle, &domain_handle->handle, 583fe1c642dSBill Krier sizeof (ndr_hdid_t)); 584fe1c642dSBill Krier 585fe1c642dSBill Krier heap = ndr_rpc_get_heap(domain_handle); 586fe1c642dSBill Krier ndr_heap_mkvcs(heap, username, (ndr_vcstr_t *)&arg.username); 587fe1c642dSBill Krier 588fe1c642dSBill Krier arg.account_flags = account_flags; 589fe1c642dSBill Krier arg.desired_access = 0xE00500B0; 590fe1c642dSBill Krier 591fe1c642dSBill Krier rc = ndr_rpc_call(domain_handle, opnum, &arg); 592fe1c642dSBill Krier if (rc != 0) { 593fe1c642dSBill Krier status = NT_STATUS_INVALID_PARAMETER; 594fe1c642dSBill Krier } else if (arg.status != 0) { 595fe1c642dSBill Krier status = NT_SC_VALUE(arg.status); 596fe1c642dSBill Krier 597fe1c642dSBill Krier if (status != NT_STATUS_USER_EXISTS) { 598fe1c642dSBill Krier smb_tracef("SamrCreateUser[%s]: %s", username, 599fe1c642dSBill Krier xlate_nt_status(status)); 600fe1c642dSBill Krier } 601fe1c642dSBill Krier } else { 602fe1c642dSBill Krier ndr_inherit_handle(user_handle, domain_handle); 603fe1c642dSBill Krier 604fe1c642dSBill Krier (void) memcpy(&user_handle->handle, &arg.user_handle, 605fe1c642dSBill Krier sizeof (ndr_hdid_t)); 606fe1c642dSBill Krier 607fe1c642dSBill Krier *rid = arg.rid; 608fe1c642dSBill Krier 609fe1c642dSBill Krier if (ndr_is_null_handle(user_handle)) 610fe1c642dSBill Krier status = NT_STATUS_INVALID_HANDLE; 611fe1c642dSBill Krier else 612fe1c642dSBill Krier status = 0; 613fe1c642dSBill Krier } 614fe1c642dSBill Krier 615fe1c642dSBill Krier ndr_rpc_release(domain_handle); 616fe1c642dSBill Krier return (status); 617fe1c642dSBill Krier } 618fe1c642dSBill Krier 619fe1c642dSBill Krier /* 620fe1c642dSBill Krier * samr_lookup_domain 621fe1c642dSBill Krier * 622fe1c642dSBill Krier * Lookup up the domain SID for the specified domain name. The handle 623fe1c642dSBill Krier * should be one returned from samr_connect. The allocated memory for 624fe1c642dSBill Krier * the returned SID must be freed by caller. 625fe1c642dSBill Krier */ 626fe1c642dSBill Krier smb_sid_t * 627fe1c642dSBill Krier samr_lookup_domain(mlsvc_handle_t *samr_handle, char *domain_name) 628fe1c642dSBill Krier { 629fe1c642dSBill Krier struct samr_LookupDomain arg; 630fe1c642dSBill Krier smb_sid_t *domsid = NULL; 631fe1c642dSBill Krier int opnum; 632fe1c642dSBill Krier size_t length; 633fe1c642dSBill Krier 634fe1c642dSBill Krier if (ndr_is_null_handle(samr_handle) || domain_name == NULL) 635fe1c642dSBill Krier return (NULL); 636fe1c642dSBill Krier 637fe1c642dSBill Krier opnum = SAMR_OPNUM_LookupDomain; 638fe1c642dSBill Krier bzero(&arg, sizeof (struct samr_LookupDomain)); 639fe1c642dSBill Krier 640fe1c642dSBill Krier (void) memcpy(&arg.handle, &samr_handle->handle, 641fe1c642dSBill Krier sizeof (samr_handle_t)); 642fe1c642dSBill Krier 643fe1c642dSBill Krier length = smb_wcequiv_strlen(domain_name); 644fe1c642dSBill Krier if (ndr_rpc_server_os(samr_handle) == NATIVE_OS_WIN2000) 645fe1c642dSBill Krier length += sizeof (smb_wchar_t); 646fe1c642dSBill Krier 647fe1c642dSBill Krier arg.domain_name.length = length; 648fe1c642dSBill Krier arg.domain_name.allosize = length; 649fe1c642dSBill Krier arg.domain_name.str = (unsigned char *)domain_name; 650fe1c642dSBill Krier 651fe1c642dSBill Krier if (ndr_rpc_call(samr_handle, opnum, &arg) == 0) 652fe1c642dSBill Krier domsid = smb_sid_dup((smb_sid_t *)arg.sid); 653fe1c642dSBill Krier 654fe1c642dSBill Krier ndr_rpc_release(samr_handle); 655fe1c642dSBill Krier return (domsid); 656fe1c642dSBill Krier } 657fe1c642dSBill Krier 658fe1c642dSBill Krier /* 659fe1c642dSBill Krier * samr_enum_local_domains 660fe1c642dSBill Krier * 661fe1c642dSBill Krier * Get the list of local domains supported by a server. 662fe1c642dSBill Krier * 663fe1c642dSBill Krier * Returns NT status codes. 664fe1c642dSBill Krier */ 665fe1c642dSBill Krier DWORD 666fe1c642dSBill Krier samr_enum_local_domains(mlsvc_handle_t *samr_handle) 667fe1c642dSBill Krier { 668fe1c642dSBill Krier struct samr_EnumLocalDomain arg; 669fe1c642dSBill Krier int opnum; 670fe1c642dSBill Krier DWORD status; 671fe1c642dSBill Krier 672fe1c642dSBill Krier if (ndr_is_null_handle(samr_handle)) 673fe1c642dSBill Krier return (NT_STATUS_INVALID_PARAMETER); 674fe1c642dSBill Krier 675fe1c642dSBill Krier opnum = SAMR_OPNUM_EnumLocalDomains; 676fe1c642dSBill Krier bzero(&arg, sizeof (struct samr_EnumLocalDomain)); 677fe1c642dSBill Krier 678fe1c642dSBill Krier (void) memcpy(&arg.handle, &samr_handle->handle, 679fe1c642dSBill Krier sizeof (samr_handle_t)); 680fe1c642dSBill Krier arg.enum_context = 0; 681fe1c642dSBill Krier arg.max_length = 0x00002000; /* Value used by NT */ 682fe1c642dSBill Krier 683fe1c642dSBill Krier if (ndr_rpc_call(samr_handle, opnum, &arg) != 0) { 684fe1c642dSBill Krier status = NT_STATUS_INVALID_PARAMETER; 685fe1c642dSBill Krier } else { 686fe1c642dSBill Krier status = NT_SC_VALUE(arg.status); 687fe1c642dSBill Krier 688fe1c642dSBill Krier /* 689fe1c642dSBill Krier * Handle none-mapped status quietly. 690fe1c642dSBill Krier */ 691fe1c642dSBill Krier if (status != NT_STATUS_NONE_MAPPED) 692fe1c642dSBill Krier ndr_rpc_status(samr_handle, opnum, arg.status); 693fe1c642dSBill Krier } 694fe1c642dSBill Krier 695fe1c642dSBill Krier ndr_rpc_release(samr_handle); 696fe1c642dSBill Krier return (status); 697fe1c642dSBill Krier } 698fe1c642dSBill Krier 699fe1c642dSBill Krier /* 700fe1c642dSBill Krier * samr_lookup_domain_names 701fe1c642dSBill Krier * 702fe1c642dSBill Krier * Lookup up the given name in the domain specified by domain_handle. 703fe1c642dSBill Krier * Upon a successful lookup the information is returned in the account 704fe1c642dSBill Krier * arg and caller must free allocated memories by calling smb_account_free(). 705fe1c642dSBill Krier * 706fe1c642dSBill Krier * Returns NT status codes. 707fe1c642dSBill Krier */ 708fe1c642dSBill Krier uint32_t 709fe1c642dSBill Krier samr_lookup_domain_names(mlsvc_handle_t *domain_handle, char *name, 710fe1c642dSBill Krier smb_account_t *account) 711fe1c642dSBill Krier { 712fe1c642dSBill Krier struct samr_LookupNames arg; 713fe1c642dSBill Krier int opnum; 714fe1c642dSBill Krier uint32_t status; 715fe1c642dSBill Krier size_t length; 716fe1c642dSBill Krier 717fe1c642dSBill Krier if (ndr_is_null_handle(domain_handle) || 718fe1c642dSBill Krier name == NULL || account == NULL) { 719fe1c642dSBill Krier return (NT_STATUS_INVALID_PARAMETER); 720fe1c642dSBill Krier } 721fe1c642dSBill Krier 722fe1c642dSBill Krier bzero(account, sizeof (smb_account_t)); 723fe1c642dSBill Krier opnum = SAMR_OPNUM_LookupNames; 724fe1c642dSBill Krier bzero(&arg, sizeof (struct samr_LookupNames)); 725fe1c642dSBill Krier 726fe1c642dSBill Krier (void) memcpy(&arg.handle, &domain_handle->handle, 727fe1c642dSBill Krier sizeof (samr_handle_t)); 728fe1c642dSBill Krier arg.n_entry = 1; 729fe1c642dSBill Krier arg.max_n_entry = 1000; 730fe1c642dSBill Krier arg.index = 0; 731fe1c642dSBill Krier arg.total = 1; 732fe1c642dSBill Krier 733fe1c642dSBill Krier length = smb_wcequiv_strlen(name); 734fe1c642dSBill Krier if (ndr_rpc_server_os(domain_handle) == NATIVE_OS_WIN2000) 735fe1c642dSBill Krier length += sizeof (smb_wchar_t); 736fe1c642dSBill Krier 737fe1c642dSBill Krier arg.name.length = length; 738fe1c642dSBill Krier arg.name.allosize = length; 739fe1c642dSBill Krier arg.name.str = (unsigned char *)name; 740fe1c642dSBill Krier 741fe1c642dSBill Krier if (ndr_rpc_call(domain_handle, opnum, &arg) != 0) { 742fe1c642dSBill Krier status = NT_STATUS_INVALID_PARAMETER; 743fe1c642dSBill Krier } else if (arg.status != NT_STATUS_SUCCESS) { 744fe1c642dSBill Krier status = NT_SC_VALUE(arg.status); 745fe1c642dSBill Krier 746fe1c642dSBill Krier /* 747fe1c642dSBill Krier * Handle none-mapped status quietly. 748fe1c642dSBill Krier */ 749fe1c642dSBill Krier if (status != NT_STATUS_NONE_MAPPED) 750fe1c642dSBill Krier ndr_rpc_status(domain_handle, opnum, arg.status); 751fe1c642dSBill Krier } else { 752fe1c642dSBill Krier account->a_type = arg.rid_types.rid_type[0]; 753fe1c642dSBill Krier account->a_rid = arg.rids.rid[0]; 754fe1c642dSBill Krier status = NT_STATUS_SUCCESS; 755fe1c642dSBill Krier } 756fe1c642dSBill Krier 757fe1c642dSBill Krier ndr_rpc_release(domain_handle); 758fe1c642dSBill Krier return (status); 759fe1c642dSBill Krier } 760fe1c642dSBill Krier 761fe1c642dSBill Krier /* 762fe1c642dSBill Krier * samr_query_user_info 763fe1c642dSBill Krier * 764fe1c642dSBill Krier * Query information on a specific user. The handle must be a valid 765fe1c642dSBill Krier * user handle obtained via samr_open_user. 766fe1c642dSBill Krier * 767fe1c642dSBill Krier * Returns 0 on success, otherwise returns -ve error code. 768fe1c642dSBill Krier */ 769fe1c642dSBill Krier int 770fe1c642dSBill Krier samr_query_user_info(mlsvc_handle_t *user_handle, WORD switch_value, 771fe1c642dSBill Krier union samr_user_info *user_info) 772fe1c642dSBill Krier { 773fe1c642dSBill Krier struct samr_QueryUserInfo arg; 774fe1c642dSBill Krier int opnum; 775fe1c642dSBill Krier int rc; 776fe1c642dSBill Krier 777fe1c642dSBill Krier if (ndr_is_null_handle(user_handle) || user_info == 0) 778fe1c642dSBill Krier return (-1); 779fe1c642dSBill Krier 780fe1c642dSBill Krier opnum = SAMR_OPNUM_QueryUserInfo; 781fe1c642dSBill Krier bzero(&arg, sizeof (struct samr_QueryUserInfo)); 782fe1c642dSBill Krier 783fe1c642dSBill Krier (void) memcpy(&arg.user_handle, &user_handle->handle, 784fe1c642dSBill Krier sizeof (samr_handle_t)); 785fe1c642dSBill Krier arg.switch_value = switch_value; 786fe1c642dSBill Krier 787fe1c642dSBill Krier if (ndr_rpc_call(user_handle, opnum, &arg) != 0) { 788fe1c642dSBill Krier ndr_rpc_release(user_handle); 789fe1c642dSBill Krier return (-1); 790fe1c642dSBill Krier } 791fe1c642dSBill Krier 792fe1c642dSBill Krier if (arg.status != 0) 793fe1c642dSBill Krier rc = -1; 794fe1c642dSBill Krier else 795fe1c642dSBill Krier rc = samr_setup_user_info(switch_value, &arg, user_info); 796fe1c642dSBill Krier 797fe1c642dSBill Krier ndr_rpc_release(user_handle); 798fe1c642dSBill Krier return (rc); 799fe1c642dSBill Krier } 800fe1c642dSBill Krier 801fe1c642dSBill Krier /* 802fe1c642dSBill Krier * samr_setup_user_info 803fe1c642dSBill Krier * 804fe1c642dSBill Krier * Private function to set up the samr_user_info data. Dependent on 805fe1c642dSBill Krier * the switch value this function may use strdup which will malloc 806fe1c642dSBill Krier * memory. The caller is responsible for deallocating this memory. 807fe1c642dSBill Krier * 808fe1c642dSBill Krier * Returns 0 on success, otherwise returns -1. 809fe1c642dSBill Krier */ 810fe1c642dSBill Krier static int 811fe1c642dSBill Krier samr_setup_user_info(WORD switch_value, 812fe1c642dSBill Krier struct samr_QueryUserInfo *arg, union samr_user_info *user_info) 813fe1c642dSBill Krier { 814fe1c642dSBill Krier struct samr_QueryUserInfo1 *info1; 815fe1c642dSBill Krier struct samr_QueryUserInfo6 *info6; 816fe1c642dSBill Krier 817fe1c642dSBill Krier switch (switch_value) { 818fe1c642dSBill Krier case 1: 819fe1c642dSBill Krier info1 = &arg->ru.info1; 820fe1c642dSBill Krier user_info->info1.username = strdup( 821fe1c642dSBill Krier (char const *)info1->username.str); 822fe1c642dSBill Krier user_info->info1.fullname = strdup( 823fe1c642dSBill Krier (char const *)info1->fullname.str); 824fe1c642dSBill Krier user_info->info1.description = strdup( 825fe1c642dSBill Krier (char const *)info1->description.str); 826fe1c642dSBill Krier user_info->info1.unknown = 0; 827fe1c642dSBill Krier user_info->info1.group_rid = info1->group_rid; 828fe1c642dSBill Krier return (0); 829fe1c642dSBill Krier 830fe1c642dSBill Krier case 6: 831fe1c642dSBill Krier info6 = &arg->ru.info6; 832fe1c642dSBill Krier user_info->info6.username = strdup( 833fe1c642dSBill Krier (char const *)info6->username.str); 834fe1c642dSBill Krier user_info->info6.fullname = strdup( 835fe1c642dSBill Krier (char const *)info6->fullname.str); 836fe1c642dSBill Krier return (0); 837fe1c642dSBill Krier 838fe1c642dSBill Krier case 7: 839fe1c642dSBill Krier user_info->info7.username = strdup( 840fe1c642dSBill Krier (char const *)arg->ru.info7.username.str); 841fe1c642dSBill Krier return (0); 842fe1c642dSBill Krier 843fe1c642dSBill Krier case 8: 844fe1c642dSBill Krier user_info->info8.fullname = strdup( 845fe1c642dSBill Krier (char const *)arg->ru.info8.fullname.str); 846fe1c642dSBill Krier return (0); 847fe1c642dSBill Krier 848fe1c642dSBill Krier case 9: 849fe1c642dSBill Krier user_info->info9.group_rid = arg->ru.info9.group_rid; 850fe1c642dSBill Krier return (0); 851fe1c642dSBill Krier 852fe1c642dSBill Krier case 16: 853fe1c642dSBill Krier return (0); 854fe1c642dSBill Krier 855fe1c642dSBill Krier default: 856fe1c642dSBill Krier break; 857fe1c642dSBill Krier }; 858fe1c642dSBill Krier 859fe1c642dSBill Krier return (-1); 860fe1c642dSBill Krier } 861fe1c642dSBill Krier 862fe1c642dSBill Krier /* 863fe1c642dSBill Krier * samr_query_user_groups 864fe1c642dSBill Krier * 865fe1c642dSBill Krier * Query the groups for a specific user. The handle must be a valid 866fe1c642dSBill Krier * user handle obtained via samr_open_user. The list of groups is 867fe1c642dSBill Krier * returned in group_info. Note that group_info->groups is allocated 868fe1c642dSBill Krier * using malloc. The caller is responsible for deallocating this 869fe1c642dSBill Krier * memory when it is no longer required. If group_info->n_entry is 0 870fe1c642dSBill Krier * then no memory was allocated. 871fe1c642dSBill Krier * 872fe1c642dSBill Krier * Returns 0 on success, otherwise returns -1. 873fe1c642dSBill Krier */ 874fe1c642dSBill Krier int 875fe1c642dSBill Krier samr_query_user_groups(mlsvc_handle_t *user_handle, int *n_groups, 876fe1c642dSBill Krier struct samr_UserGroups **groups) 877fe1c642dSBill Krier { 878fe1c642dSBill Krier struct samr_QueryUserGroups arg; 879fe1c642dSBill Krier int opnum; 880fe1c642dSBill Krier int rc; 881fe1c642dSBill Krier int nbytes; 882fe1c642dSBill Krier 883fe1c642dSBill Krier if (ndr_is_null_handle(user_handle)) 884fe1c642dSBill Krier return (-1); 885fe1c642dSBill Krier 886fe1c642dSBill Krier opnum = SAMR_OPNUM_QueryUserGroups; 887fe1c642dSBill Krier bzero(&arg, sizeof (struct samr_QueryUserGroups)); 888fe1c642dSBill Krier 889fe1c642dSBill Krier (void) memcpy(&arg.user_handle, &user_handle->handle, 890fe1c642dSBill Krier sizeof (samr_handle_t)); 891fe1c642dSBill Krier 892fe1c642dSBill Krier rc = ndr_rpc_call(user_handle, opnum, &arg); 893fe1c642dSBill Krier if (rc == 0) { 894fe1c642dSBill Krier if (arg.info == 0) { 895fe1c642dSBill Krier rc = -1; 896fe1c642dSBill Krier } else { 897fe1c642dSBill Krier nbytes = arg.info->n_entry * 898fe1c642dSBill Krier sizeof (struct samr_UserGroups); 899fe1c642dSBill Krier 900fe1c642dSBill Krier if ((*groups = malloc(nbytes)) == NULL) { 901fe1c642dSBill Krier *n_groups = 0; 902fe1c642dSBill Krier rc = -1; 903fe1c642dSBill Krier } else { 904fe1c642dSBill Krier *n_groups = arg.info->n_entry; 905fe1c642dSBill Krier bcopy(arg.info->groups, *groups, nbytes); 906fe1c642dSBill Krier } 907fe1c642dSBill Krier } 908fe1c642dSBill Krier } 909fe1c642dSBill Krier 910fe1c642dSBill Krier ndr_rpc_release(user_handle); 911fe1c642dSBill Krier return (rc); 912fe1c642dSBill Krier } 913fe1c642dSBill Krier 914fe1c642dSBill Krier /* 915fe1c642dSBill Krier * samr_get_user_pwinfo 916fe1c642dSBill Krier * 917fe1c642dSBill Krier * Get some user password info. I'm not sure what this is yet but it is 918fe1c642dSBill Krier * part of the create user sequence. The handle must be a valid user 919fe1c642dSBill Krier * handle. Since I don't know what this is returning, I haven't provided 920fe1c642dSBill Krier * any return data yet. 921fe1c642dSBill Krier * 922fe1c642dSBill Krier * Returns 0 on success. Otherwise returns an NT status code. 923fe1c642dSBill Krier */ 924fe1c642dSBill Krier DWORD 925fe1c642dSBill Krier samr_get_user_pwinfo(mlsvc_handle_t *user_handle) 926fe1c642dSBill Krier { 927fe1c642dSBill Krier struct samr_GetUserPwInfo arg; 928fe1c642dSBill Krier int opnum; 929fe1c642dSBill Krier DWORD status; 930fe1c642dSBill Krier 931fe1c642dSBill Krier if (ndr_is_null_handle(user_handle)) 932fe1c642dSBill Krier return (NT_STATUS_INVALID_PARAMETER); 933fe1c642dSBill Krier 934fe1c642dSBill Krier opnum = SAMR_OPNUM_GetUserPwInfo; 935fe1c642dSBill Krier bzero(&arg, sizeof (struct samr_GetUserPwInfo)); 936fe1c642dSBill Krier (void) memcpy(&arg.user_handle, &user_handle->handle, 937fe1c642dSBill Krier sizeof (samr_handle_t)); 938fe1c642dSBill Krier 939fe1c642dSBill Krier if (ndr_rpc_call(user_handle, opnum, &arg) != 0) { 940fe1c642dSBill Krier status = NT_STATUS_INVALID_PARAMETER; 941fe1c642dSBill Krier } else if (arg.status != 0) { 942fe1c642dSBill Krier ndr_rpc_status(user_handle, opnum, arg.status); 943fe1c642dSBill Krier status = NT_SC_VALUE(arg.status); 944fe1c642dSBill Krier } else { 945fe1c642dSBill Krier status = 0; 946fe1c642dSBill Krier } 947fe1c642dSBill Krier 948fe1c642dSBill Krier ndr_rpc_release(user_handle); 949fe1c642dSBill Krier return (status); 950fe1c642dSBill Krier } 951fe1c642dSBill Krier 952fe1c642dSBill Krier /* 953fe1c642dSBill Krier * samr_set_user_info 954fe1c642dSBill Krier * 955fe1c642dSBill Krier * Returns 0 on success. Otherwise returns an NT status code. 956fe1c642dSBill Krier * NT status codes observed so far: 957fe1c642dSBill Krier * NT_STATUS_WRONG_PASSWORD 958fe1c642dSBill Krier */ 959fe1c642dSBill Krier /*ARGSUSED*/ 960fe1c642dSBill Krier DWORD 961fe1c642dSBill Krier samr_set_user_info(mlsvc_handle_t *user_handle) 962fe1c642dSBill Krier { 963fe1c642dSBill Krier unsigned char ssn_key[SMBAUTH_SESSION_KEY_SZ]; 964fe1c642dSBill Krier struct samr_SetUserInfo arg; 965fe1c642dSBill Krier int opnum; 966fe1c642dSBill Krier DWORD status = 0; 967fe1c642dSBill Krier 968fe1c642dSBill Krier if (ndr_is_null_handle(user_handle)) 969fe1c642dSBill Krier return (NT_STATUS_INVALID_PARAMETER); 970fe1c642dSBill Krier 971fe1c642dSBill Krier if (ndr_rpc_get_ssnkey(user_handle, ssn_key, sizeof (ssn_key))) 972fe1c642dSBill Krier return (NT_STATUS_INVALID_PARAMETER); 973fe1c642dSBill Krier 974fe1c642dSBill Krier opnum = SAMR_OPNUM_SetUserInfo; 975fe1c642dSBill Krier bzero(&arg, sizeof (struct samr_SetUserInfo)); 976fe1c642dSBill Krier (void) memcpy(&arg.user_handle, &user_handle->handle, 977fe1c642dSBill Krier sizeof (samr_handle_t)); 978fe1c642dSBill Krier 979fe1c642dSBill Krier arg.info.index = SAMR_SET_USER_INFO_23; 980fe1c642dSBill Krier arg.info.switch_value = SAMR_SET_USER_INFO_23; 981fe1c642dSBill Krier 982fe1c642dSBill Krier samr_set_user_unknowns(&arg.info.ru.info23); 983fe1c642dSBill Krier samr_set_user_logon_hours(&arg); 984fe1c642dSBill Krier 985fe1c642dSBill Krier if (samr_set_user_password(ssn_key, arg.info.ru.info23.password) < 0) 986fe1c642dSBill Krier status = NT_STATUS_INTERNAL_ERROR; 987fe1c642dSBill Krier 988fe1c642dSBill Krier if (ndr_rpc_call(user_handle, opnum, &arg) != 0) { 989fe1c642dSBill Krier status = NT_STATUS_INVALID_PARAMETER; 990fe1c642dSBill Krier } else if (arg.status != 0) { 991fe1c642dSBill Krier ndr_rpc_status(user_handle, opnum, arg.status); 992fe1c642dSBill Krier status = NT_SC_VALUE(arg.status); 993fe1c642dSBill Krier } 994fe1c642dSBill Krier 995fe1c642dSBill Krier ndr_rpc_release(user_handle); 996fe1c642dSBill Krier return (status); 997fe1c642dSBill Krier } 998fe1c642dSBill Krier 999fe1c642dSBill Krier static void 1000fe1c642dSBill Krier samr_set_user_unknowns(struct samr_SetUserInfo23 *info) 1001fe1c642dSBill Krier { 1002fe1c642dSBill Krier bzero(info, sizeof (struct samr_SetUserInfo23)); 1003fe1c642dSBill Krier 1004fe1c642dSBill Krier info->sd.length = 0; 1005fe1c642dSBill Krier info->sd.data = 0; 1006fe1c642dSBill Krier info->user_rid = 0; 1007fe1c642dSBill Krier info->group_rid = DOMAIN_GROUP_RID_USERS; 1008fe1c642dSBill Krier 1009fe1c642dSBill Krier /* 1010fe1c642dSBill Krier * The trust account value used here should probably 1011fe1c642dSBill Krier * match the one used to create the trust account. 1012fe1c642dSBill Krier */ 1013fe1c642dSBill Krier info->acct_info = SAMR_AF_WORKSTATION_TRUST_ACCOUNT; 1014fe1c642dSBill Krier info->flags = 0x09F827FA; 1015fe1c642dSBill Krier } 1016fe1c642dSBill Krier 1017fe1c642dSBill Krier /* 1018fe1c642dSBill Krier * samr_set_user_logon_hours 1019fe1c642dSBill Krier * 1020fe1c642dSBill Krier * SamrSetUserInfo appears to contain some logon hours information, which 1021fe1c642dSBill Krier * looks like a varying, conformant array. The top level contains a value 1022fe1c642dSBill Krier * (units), which probably indicates the how to interpret the array. The 1023fe1c642dSBill Krier * array definition looks like it contains a maximum size, an initial 1024fe1c642dSBill Krier * offset and a bit length (units/8), followed by the bitmap. 1025fe1c642dSBill Krier * 1026fe1c642dSBill Krier * (info) 1027fe1c642dSBill Krier * +-------+ 1028fe1c642dSBill Krier * | units | 1029fe1c642dSBill Krier * +-------+ (hours) 1030fe1c642dSBill Krier * | hours |-->+-----------+ 1031fe1c642dSBill Krier * +-------+ | max_is | 1032fe1c642dSBill Krier * +-----------+ 1033fe1c642dSBill Krier * | first_is | 1034fe1c642dSBill Krier * +-----------+ 1035fe1c642dSBill Krier * | length_is | 1036fe1c642dSBill Krier * +------------------------+ 1037fe1c642dSBill Krier * | bitmap[length_is] | 1038fe1c642dSBill Krier * +---------+--------------+ 1039fe1c642dSBill Krier * 1040fe1c642dSBill Krier * 10080 minutes/week => 10080/8 = 1260 (0x04EC) bytes. 1041fe1c642dSBill Krier * 168 hours/week => 168/8 = 21 (0xA8) bytes. 1042fe1c642dSBill Krier * In the netmon examples seen so far, all bits are set to 1, i.e. 1043fe1c642dSBill Krier * an array containing 0xff. This is probably the default setting. 1044fe1c642dSBill Krier * 1045fe1c642dSBill Krier * ndrgen has a problem with complex [size_is] statements (length/8). 1046fe1c642dSBill Krier * So, for now, we fake it using two separate components. 1047fe1c642dSBill Krier */ 1048fe1c642dSBill Krier static void 1049fe1c642dSBill Krier samr_set_user_logon_hours(struct samr_SetUserInfo *sui) 1050fe1c642dSBill Krier { 1051fe1c642dSBill Krier sui->logon_hours.size = SAMR_HOURS_MAX_SIZE; 1052fe1c642dSBill Krier sui->logon_hours.first = 0; 1053fe1c642dSBill Krier sui->logon_hours.length = SAMR_SET_USER_HOURS_SZ; 1054fe1c642dSBill Krier (void) memset(sui->logon_hours.bitmap, 0xFF, SAMR_SET_USER_HOURS_SZ); 1055fe1c642dSBill Krier 1056fe1c642dSBill Krier sui->info.ru.info23.logon_info.units = SAMR_HOURS_PER_WEEK; 1057fe1c642dSBill Krier sui->info.ru.info23.logon_info.hours = 1058fe1c642dSBill Krier (DWORD)(uintptr_t)sui->logon_hours.bitmap; 1059fe1c642dSBill Krier } 1060fe1c642dSBill Krier 1061fe1c642dSBill Krier /* 1062fe1c642dSBill Krier * samr_set_user_password 1063fe1c642dSBill Krier * 1064fe1c642dSBill Krier * Set the initial password for the user. 1065fe1c642dSBill Krier * 1066fe1c642dSBill Krier * Returns 0 if everything goes well, -1 if there is trouble generating a 1067fe1c642dSBill Krier * key. 1068fe1c642dSBill Krier */ 1069fe1c642dSBill Krier static int 1070fe1c642dSBill Krier samr_set_user_password(unsigned char *nt_key, BYTE *oem_password) 1071fe1c642dSBill Krier { 1072fe1c642dSBill Krier char hostname[NETBIOS_NAME_SZ]; 1073fe1c642dSBill Krier 1074fe1c642dSBill Krier randomize((char *)oem_password, SAMR_SET_USER_DATA_SZ); 1075fe1c642dSBill Krier 1076fe1c642dSBill Krier /* 1077fe1c642dSBill Krier * The new password is going to be the NetBIOS name of the system 1078fe1c642dSBill Krier * in lower case. 1079fe1c642dSBill Krier */ 1080fe1c642dSBill Krier if (smb_getnetbiosname(hostname, sizeof (hostname)) != 0) 1081fe1c642dSBill Krier return (-1); 1082fe1c642dSBill Krier 1083fe1c642dSBill Krier (void) smb_strlwr(hostname); 1084fe1c642dSBill Krier 1085fe1c642dSBill Krier /* 1086fe1c642dSBill Krier * Generate the OEM password from the hostname and the user session 1087fe1c642dSBill Krier * key(nt_key). 1088fe1c642dSBill Krier */ 1089fe1c642dSBill Krier /*LINTED E_BAD_PTR_CAST_ALIGN*/ 1090fe1c642dSBill Krier (void) sam_oem_password((oem_password_t *)oem_password, 1091fe1c642dSBill Krier (unsigned char *)hostname, nt_key); 1092fe1c642dSBill Krier return (0); 1093fe1c642dSBill Krier } 1094