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