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