1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 /* 29 * Utility functions to support the RPC interface library. 30 */ 31 32 #include <stdio.h> 33 #include <stdarg.h> 34 #include <strings.h> 35 #include <unistd.h> 36 #include <netdb.h> 37 #include <stdlib.h> 38 39 #include <sys/time.h> 40 #include <sys/systm.h> 41 42 #include <smbsrv/libsmb.h> 43 #include <smbsrv/libsmbrdr.h> 44 #include <smbsrv/libsmbns.h> 45 #include <smbsrv/libmlsvc.h> 46 47 #include <smbsrv/smbinfo.h> 48 #include <smbsrv/lsalib.h> 49 #include <smbsrv/samlib.h> 50 #include <smbsrv/mlsvc_util.h> 51 #include <smbsrv/mlsvc.h> 52 53 /* Domain join support (using MS-RPC) */ 54 static boolean_t mlsvc_ntjoin_support = B_FALSE; 55 56 extern int netr_open(char *, char *, mlsvc_handle_t *); 57 extern int netr_close(mlsvc_handle_t *); 58 extern DWORD netlogon_auth(char *, mlsvc_handle_t *, DWORD); 59 extern int mlsvc_user_getauth(char *, char *, smb_auth_info_t *); 60 61 /* 62 * Compare the supplied domain name with the local hostname. 63 * We need to deal with both server names and fully-qualified 64 * domain names. 65 * 66 * Returns: 67 * 0 The specified domain is not the local domain, 68 * 1 The Specified domain is the local domain. 69 * -1 Invalid parameter or unable to get the local 70 * system information. 71 */ 72 int 73 mlsvc_is_local_domain(const char *domain) 74 { 75 char hostname[MAXHOSTNAMELEN]; 76 int rc; 77 78 if (smb_config_get_secmode() == SMB_SECMODE_WORKGRP) 79 return (1); 80 81 if (strchr(domain, '.') != NULL) 82 rc = smb_getfqhostname(hostname, MAXHOSTNAMELEN); 83 else 84 rc = smb_gethostname(hostname, MAXHOSTNAMELEN, 1); 85 86 if (rc != 0) 87 return (-1); 88 89 if (strcasecmp(domain, hostname) == 0) 90 return (1); 91 92 return (0); 93 } 94 95 /* 96 * mlsvc_lookup_name 97 * 98 * This is just a wrapper for lsa_lookup_name. 99 * 100 * The memory for the sid is allocated using malloc so the caller should 101 * call free when it is no longer required. 102 */ 103 uint32_t 104 mlsvc_lookup_name(char *account, smb_sid_t **sid, uint16_t *sid_type) 105 { 106 smb_userinfo_t *ainfo; 107 uint32_t status; 108 109 if ((ainfo = mlsvc_alloc_user_info()) == NULL) 110 return (NT_STATUS_NO_MEMORY); 111 112 status = lsa_lookup_name(NULL, account, *sid_type, ainfo); 113 if (status == NT_STATUS_SUCCESS) { 114 *sid = ainfo->user_sid; 115 ainfo->user_sid = NULL; 116 *sid_type = ainfo->sid_name_use; 117 } 118 119 mlsvc_free_user_info(ainfo); 120 return (status); 121 } 122 123 /* 124 * mlsvc_lookup_sid 125 * 126 * This is just a wrapper for lsa_lookup_sid. 127 * 128 * The allocated memory for the returned name must be freed by caller upon 129 * successful return. 130 */ 131 uint32_t 132 mlsvc_lookup_sid(smb_sid_t *sid, char **name) 133 { 134 smb_userinfo_t *ainfo; 135 uint32_t status; 136 int namelen; 137 138 if ((ainfo = mlsvc_alloc_user_info()) == NULL) 139 return (NT_STATUS_NO_MEMORY); 140 141 status = lsa_lookup_sid(sid, ainfo); 142 if (status == NT_STATUS_SUCCESS) { 143 namelen = strlen(ainfo->domain_name) + strlen(ainfo->name) + 2; 144 if ((*name = malloc(namelen)) == NULL) { 145 mlsvc_free_user_info(ainfo); 146 return (NT_STATUS_NO_MEMORY); 147 } 148 (void) snprintf(*name, namelen, "%s\\%s", 149 ainfo->domain_name, ainfo->name); 150 } 151 152 mlsvc_free_user_info(ainfo); 153 return (status); 154 } 155 156 /* 157 * mlsvc_alloc_user_info 158 * 159 * Allocate a user_info structure and set the contents to zero. A 160 * pointer to the user_info structure is returned. 161 */ 162 smb_userinfo_t * 163 mlsvc_alloc_user_info(void) 164 { 165 smb_userinfo_t *user_info; 166 167 user_info = (smb_userinfo_t *)malloc(sizeof (smb_userinfo_t)); 168 if (user_info == NULL) 169 return (NULL); 170 171 bzero(user_info, sizeof (smb_userinfo_t)); 172 return (user_info); 173 } 174 175 /* 176 * mlsvc_free_user_info 177 * 178 * Free a user_info structure. This function ensures that the contents 179 * of the user_info are freed as well as the user_info itself. 180 */ 181 void 182 mlsvc_free_user_info(smb_userinfo_t *user_info) 183 { 184 if (user_info) { 185 mlsvc_release_user_info(user_info); 186 free(user_info); 187 } 188 } 189 190 /* 191 * mlsvc_release_user_info 192 * 193 * Release the contents of a user_info structure and zero out the 194 * elements but do not free the user_info structure itself. This 195 * function cleans out the structure so that it can be reused without 196 * worrying about stale contents. 197 */ 198 void 199 mlsvc_release_user_info(smb_userinfo_t *user_info) 200 { 201 int i; 202 203 if (user_info == NULL) 204 return; 205 206 free(user_info->name); 207 free(user_info->domain_sid); 208 free(user_info->domain_name); 209 free(user_info->groups); 210 211 if (user_info->n_other_grps) { 212 for (i = 0; i < user_info->n_other_grps; i++) 213 free(user_info->other_grps[i].sid); 214 215 free(user_info->other_grps); 216 } 217 218 free(user_info->user_sid); 219 free(user_info->pgrp_sid); 220 bzero(user_info, sizeof (smb_userinfo_t)); 221 } 222 223 /* 224 * mlsvc_setadmin_user_info 225 * 226 * Determines if the given user is the domain Administrator or a 227 * member of Domain Admins or Administrators group and set the 228 * user_info->flags accordingly. 229 */ 230 void 231 mlsvc_setadmin_user_info(smb_userinfo_t *user_info) 232 { 233 nt_domain_t *domain; 234 smb_group_t grp; 235 int rc, i; 236 237 if ((domain = nt_domain_lookupbytype(NT_DOMAIN_PRIMARY)) == NULL) 238 return; 239 240 if (!smb_sid_cmp((smb_sid_t *)user_info->domain_sid, domain->sid)) 241 return; 242 243 if (user_info->rid == DOMAIN_USER_RID_ADMIN) 244 user_info->flags |= SMB_UINFO_FLAG_DADMIN; 245 else if (user_info->primary_group_rid == DOMAIN_GROUP_RID_ADMINS) 246 user_info->flags |= SMB_UINFO_FLAG_DADMIN; 247 else { 248 for (i = 0; i < user_info->n_groups; i++) 249 if (user_info->groups[i].rid == DOMAIN_GROUP_RID_ADMINS) 250 user_info->flags |= SMB_UINFO_FLAG_DADMIN; 251 } 252 253 rc = smb_lgrp_getbyname("Administrators", &grp); 254 if (rc == SMB_LGRP_SUCCESS) { 255 if (smb_lgrp_is_member(&grp, user_info->user_sid)) 256 user_info->flags |= SMB_UINFO_FLAG_LADMIN; 257 smb_lgrp_free(&grp); 258 } 259 } 260 261 /* 262 * mlsvc_string_save 263 * 264 * This is a convenience function to prepare strings for an RPC call. 265 * An ms_string_t is set up with the appropriate lengths and str is 266 * set up to point to a copy of the original string on the heap. The 267 * macro MLRPC_HEAP_STRSAVE is an alias for mlrpc_heap_strsave, which 268 * extends the heap and copies the string into the new area. 269 */ 270 int 271 mlsvc_string_save(ms_string_t *ms, char *str, struct mlrpc_xaction *mxa) 272 { 273 if (str == NULL) 274 return (0); 275 276 ms->length = mts_wcequiv_strlen(str); 277 ms->allosize = ms->length + sizeof (mts_wchar_t); 278 279 if ((ms->str = MLRPC_HEAP_STRSAVE(mxa, str)) == NULL) 280 return (0); 281 282 return (1); 283 } 284 285 /* 286 * mlsvc_sid_save 287 * 288 * Expand the heap and copy the sid into the new area. 289 * Returns a pointer to the copy of the sid on the heap. 290 */ 291 smb_sid_t * 292 mlsvc_sid_save(smb_sid_t *sid, struct mlrpc_xaction *mxa) 293 { 294 smb_sid_t *heap_sid; 295 unsigned size; 296 297 if (sid == NULL) 298 return (NULL); 299 300 size = smb_sid_len(sid); 301 302 if ((heap_sid = (smb_sid_t *)MLRPC_HEAP_MALLOC(mxa, size)) == NULL) 303 return (0); 304 305 bcopy(sid, heap_sid, size); 306 return (heap_sid); 307 } 308 309 /* 310 * mlsvc_is_null_handle 311 * 312 * Check a handle against a null handle. Returns 1 if the handle is 313 * null. Otherwise returns 0. 314 */ 315 int 316 mlsvc_is_null_handle(mlsvc_handle_t *handle) 317 { 318 static ms_handle_t zero_handle; 319 320 if (handle == NULL || handle->context == NULL) 321 return (1); 322 323 if (!memcmp(&handle->handle, &zero_handle, sizeof (ms_handle_t))) 324 return (1); 325 326 return (0); 327 } 328 329 DWORD 330 mlsvc_netlogon(char *server, char *domain) 331 { 332 mlsvc_handle_t netr_handle; 333 DWORD status; 334 335 if (netr_open(server, domain, &netr_handle) == 0) { 336 status = netlogon_auth(server, &netr_handle, 337 NETR_FLG_INIT); 338 (void) netr_close(&netr_handle); 339 } else { 340 status = NT_STATUS_OPEN_FAILED; 341 } 342 343 return (status); 344 } 345 346 /* 347 * mlsvc_join 348 * 349 * Returns NT status codes. 350 */ 351 DWORD 352 mlsvc_join(char *server, char *domain, char *plain_user, char *plain_text) 353 { 354 smb_auth_info_t auth; 355 smb_ntdomain_t *di; 356 int erc; 357 DWORD status; 358 char machine_passwd[MLSVC_MACHINE_ACCT_PASSWD_MAX]; 359 char fqdn[MAXHOSTNAMELEN]; 360 361 machine_passwd[0] = '\0'; 362 363 /* 364 * Ensure that the domain name is uppercase. 365 */ 366 (void) utf8_strupr(domain); 367 368 /* 369 * There is no point continuing if the domain information is 370 * not available. Wait for up to 10 seconds and then give up. 371 */ 372 if ((di = smb_getdomaininfo(10)) == 0) { 373 status = NT_STATUS_CANT_ACCESS_DOMAIN_INFO; 374 return (status); 375 } 376 377 if (strcasecmp(domain, di->domain) != 0) { 378 status = NT_STATUS_INVALID_PARAMETER; 379 return (status); 380 } 381 382 erc = mlsvc_logon(server, domain, plain_user); 383 384 if (erc == AUTH_USER_GRANT) { 385 if (mlsvc_ntjoin_support == B_FALSE) { 386 if (smb_resolve_fqdn(domain, fqdn, MAXHOSTNAMELEN) != 1) 387 return (NT_STATUS_INVALID_PARAMETER); 388 389 if (ads_join(fqdn, plain_user, plain_text, 390 machine_passwd, sizeof (machine_passwd)) 391 == ADJOIN_SUCCESS) 392 status = NT_STATUS_SUCCESS; 393 else 394 status = NT_STATUS_UNSUCCESSFUL; 395 } else { 396 if (mlsvc_user_getauth(server, plain_user, &auth) 397 != 0) { 398 status = NT_STATUS_INVALID_PARAMETER; 399 return (status); 400 } 401 402 status = sam_create_trust_account(server, domain, 403 &auth); 404 if (status == NT_STATUS_SUCCESS) { 405 (void) smb_gethostname(machine_passwd, 406 sizeof (machine_passwd), 0); 407 (void) utf8_strlwr(machine_passwd); 408 } 409 } 410 411 if (status == NT_STATUS_SUCCESS) { 412 erc = smb_setdomainprops(NULL, server, 413 machine_passwd); 414 if (erc != 0) 415 return (NT_STATUS_UNSUCCESSFUL); 416 417 status = mlsvc_netlogon(server, domain); 418 } 419 } else { 420 status = NT_STATUS_LOGON_FAILURE; 421 } 422 423 return (status); 424 } 425