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