15331Samw /* 25331Samw * CDDL HEADER START 35331Samw * 45331Samw * The contents of this file are subject to the terms of the 55331Samw * Common Development and Distribution License (the "License"). 65331Samw * You may not use this file except in compliance with the License. 75331Samw * 85331Samw * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 95331Samw * or http://www.opensolaris.org/os/licensing. 105331Samw * See the License for the specific language governing permissions 115331Samw * and limitations under the License. 125331Samw * 135331Samw * When distributing Covered Code, include this CDDL HEADER in each 145331Samw * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 155331Samw * If applicable, add the following below this CDDL HEADER, with the 165331Samw * fields enclosed by brackets "[]" replaced with your own identifying 175331Samw * information: Portions Copyright [yyyy] [name of copyright owner] 185331Samw * 195331Samw * CDDL HEADER END 205331Samw */ 215331Samw /* 22*5772Sas200622 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 235331Samw * Use is subject to license terms. 245331Samw */ 255331Samw 265331Samw #pragma ident "%Z%%M% %I% %E% SMI" 275331Samw 285331Samw /* 295331Samw * Utility functions to support the RPC interface library. 305331Samw */ 315331Samw 325331Samw #include <stdio.h> 335331Samw #include <stdarg.h> 345331Samw #include <strings.h> 355331Samw #include <unistd.h> 365331Samw #include <netdb.h> 375331Samw #include <stdlib.h> 385331Samw 395331Samw #include <sys/time.h> 405331Samw #include <sys/systm.h> 415331Samw 425331Samw #include <smbsrv/libsmb.h> 435331Samw #include <smbsrv/libsmbrdr.h> 445331Samw #include <smbsrv/libsmbns.h> 455331Samw #include <smbsrv/libmlsvc.h> 465331Samw 475331Samw #include <smbsrv/smbinfo.h> 485331Samw #include <smbsrv/ntsid.h> 495331Samw #include <smbsrv/lsalib.h> 505331Samw #include <smbsrv/samlib.h> 515331Samw #include <smbsrv/mlsvc_util.h> 525331Samw #include <smbsrv/mlsvc.h> 535331Samw 54*5772Sas200622 /* Domain join support (using MS-RPC) */ 55*5772Sas200622 static boolean_t mlsvc_ntjoin_support = B_FALSE; 56*5772Sas200622 575331Samw extern int netr_open(char *, char *, mlsvc_handle_t *); 585331Samw extern int netr_close(mlsvc_handle_t *); 595331Samw extern DWORD netlogon_auth(char *, mlsvc_handle_t *, DWORD); 605331Samw extern int mlsvc_user_getauth(char *, char *, smb_auth_info_t *); 615331Samw 625331Samw /* 635331Samw * Compare the supplied domain name with the local hostname. 645331Samw * We need to deal with both server names and fully-qualified 655331Samw * domain names. 665331Samw * 675331Samw * Returns: 685331Samw * 0 The specified domain is not the local domain, 695331Samw * 1 The Specified domain is the local domain. 705331Samw * -1 Invalid parameter or unable to get the local 715331Samw * system information. 725331Samw */ 735331Samw int 745331Samw mlsvc_is_local_domain(const char *domain) 755331Samw { 765331Samw char hostname[MAXHOSTNAMELEN]; 775331Samw int rc; 785331Samw 79*5772Sas200622 if (smb_config_get_secmode() == SMB_SECMODE_WORKGRP) 80*5772Sas200622 return (1); 81*5772Sas200622 825331Samw if (strchr(domain, '.') != NULL) 835331Samw rc = smb_getfqhostname(hostname, MAXHOSTNAMELEN); 845331Samw else 855331Samw rc = smb_gethostname(hostname, MAXHOSTNAMELEN, 1); 865331Samw 875331Samw if (rc != 0) 885331Samw return (-1); 895331Samw 90*5772Sas200622 if (strcasecmp(domain, hostname) == 0) 915331Samw return (1); 925331Samw 935331Samw return (0); 945331Samw } 955331Samw 965331Samw /* 975331Samw * mlsvc_lookup_name 985331Samw * 99*5772Sas200622 * This is just a wrapper for lsa_lookup_name. 1005331Samw * 101*5772Sas200622 * The memory for the sid is allocated using malloc so the caller should 102*5772Sas200622 * call free when it is no longer required. 1035331Samw */ 104*5772Sas200622 uint32_t 105*5772Sas200622 mlsvc_lookup_name(char *account, nt_sid_t **sid, uint16_t *sid_type) 1065331Samw { 107*5772Sas200622 smb_userinfo_t *ainfo; 108*5772Sas200622 uint32_t status; 1095331Samw 110*5772Sas200622 if ((ainfo = mlsvc_alloc_user_info()) == NULL) 111*5772Sas200622 return (NT_STATUS_NO_MEMORY); 1125331Samw 113*5772Sas200622 status = lsa_lookup_name(NULL, account, *sid_type, ainfo); 114*5772Sas200622 if (status == NT_STATUS_SUCCESS) { 115*5772Sas200622 *sid = ainfo->user_sid; 116*5772Sas200622 ainfo->user_sid = NULL; 117*5772Sas200622 *sid_type = ainfo->sid_name_use; 118*5772Sas200622 } 1195331Samw 120*5772Sas200622 mlsvc_free_user_info(ainfo); 121*5772Sas200622 return (status); 1225331Samw } 1235331Samw 1245331Samw /* 1255331Samw * mlsvc_lookup_sid 1265331Samw * 127*5772Sas200622 * This is just a wrapper for lsa_lookup_sid. 128*5772Sas200622 * 129*5772Sas200622 * The allocated memory for the returned name must be freed by caller upon 130*5772Sas200622 * successful return. 1315331Samw */ 132*5772Sas200622 uint32_t 133*5772Sas200622 mlsvc_lookup_sid(nt_sid_t *sid, char **name) 1345331Samw { 135*5772Sas200622 smb_userinfo_t *ainfo; 136*5772Sas200622 uint32_t status; 137*5772Sas200622 int namelen; 1385331Samw 139*5772Sas200622 if ((ainfo = mlsvc_alloc_user_info()) == NULL) 140*5772Sas200622 return (NT_STATUS_NO_MEMORY); 1415331Samw 142*5772Sas200622 status = lsa_lookup_sid(sid, ainfo); 143*5772Sas200622 if (status == NT_STATUS_SUCCESS) { 144*5772Sas200622 namelen = strlen(ainfo->domain_name) + strlen(ainfo->name) + 2; 145*5772Sas200622 if ((*name = malloc(namelen)) == NULL) { 146*5772Sas200622 mlsvc_free_user_info(ainfo); 147*5772Sas200622 return (NT_STATUS_NO_MEMORY); 1485331Samw } 149*5772Sas200622 (void) snprintf(*name, namelen, "%s\\%s", 150*5772Sas200622 ainfo->domain_name, ainfo->name); 1515331Samw } 1525331Samw 153*5772Sas200622 mlsvc_free_user_info(ainfo); 154*5772Sas200622 return (status); 1555331Samw } 1565331Samw 1575331Samw /* 1585331Samw * mlsvc_alloc_user_info 1595331Samw * 1605331Samw * Allocate a user_info structure and set the contents to zero. A 1615331Samw * pointer to the user_info structure is returned. 1625331Samw */ 1635331Samw smb_userinfo_t * 1645331Samw mlsvc_alloc_user_info(void) 1655331Samw { 1665331Samw smb_userinfo_t *user_info; 1675331Samw 1685331Samw user_info = (smb_userinfo_t *)malloc(sizeof (smb_userinfo_t)); 1695331Samw if (user_info == NULL) 1705331Samw return (NULL); 1715331Samw 1725331Samw bzero(user_info, sizeof (smb_userinfo_t)); 1735331Samw return (user_info); 1745331Samw } 1755331Samw 1765331Samw /* 1775331Samw * mlsvc_free_user_info 1785331Samw * 1795331Samw * Free a user_info structure. This function ensures that the contents 1805331Samw * of the user_info are freed as well as the user_info itself. 1815331Samw */ 1825331Samw void 1835331Samw mlsvc_free_user_info(smb_userinfo_t *user_info) 1845331Samw { 1855331Samw if (user_info) { 1865331Samw mlsvc_release_user_info(user_info); 1875331Samw free(user_info); 1885331Samw } 1895331Samw } 1905331Samw 1915331Samw /* 1925331Samw * mlsvc_release_user_info 1935331Samw * 1945331Samw * Release the contents of a user_info structure and zero out the 1955331Samw * elements but do not free the user_info structure itself. This 1965331Samw * function cleans out the structure so that it can be reused without 1975331Samw * worrying about stale contents. 1985331Samw */ 1995331Samw void 2005331Samw mlsvc_release_user_info(smb_userinfo_t *user_info) 2015331Samw { 2025331Samw int i; 2035331Samw 2045331Samw if (user_info == NULL) 2055331Samw return; 2065331Samw 2075331Samw free(user_info->name); 2085331Samw free(user_info->domain_sid); 2095331Samw free(user_info->domain_name); 2105331Samw free(user_info->groups); 2115331Samw 2125331Samw if (user_info->n_other_grps) { 2135331Samw for (i = 0; i < user_info->n_other_grps; i++) 2145331Samw free(user_info->other_grps[i].sid); 2155331Samw 2165331Samw free(user_info->other_grps); 2175331Samw } 2185331Samw 2195331Samw free(user_info->user_sid); 2205331Samw free(user_info->pgrp_sid); 2215331Samw bzero(user_info, sizeof (smb_userinfo_t)); 2225331Samw } 2235331Samw 2245331Samw /* 2255331Samw * mlsvc_setadmin_user_info 2265331Samw * 2275331Samw * Determines if the given user is the domain Administrator or a 2285331Samw * member of Domain Admins or Administrators group and set the 2295331Samw * user_info->flags accordingly. 2305331Samw */ 2315331Samw void 2325331Samw mlsvc_setadmin_user_info(smb_userinfo_t *user_info) 2335331Samw { 2345331Samw nt_domain_t *domain; 235*5772Sas200622 smb_group_t grp; 236*5772Sas200622 int rc, i; 2375331Samw 2385331Samw if ((domain = nt_domain_lookupbytype(NT_DOMAIN_PRIMARY)) == NULL) 2395331Samw return; 2405331Samw 2415331Samw if (!nt_sid_is_equal((nt_sid_t *)user_info->domain_sid, domain->sid)) 2425331Samw return; 2435331Samw 2445331Samw if (user_info->rid == DOMAIN_USER_RID_ADMIN) 2455331Samw user_info->flags |= SMB_UINFO_FLAG_DADMIN; 2465331Samw else if (user_info->primary_group_rid == DOMAIN_GROUP_RID_ADMINS) 2475331Samw user_info->flags |= SMB_UINFO_FLAG_DADMIN; 2485331Samw else { 2495331Samw for (i = 0; i < user_info->n_groups; i++) 2505331Samw if (user_info->groups[i].rid == DOMAIN_GROUP_RID_ADMINS) 2515331Samw user_info->flags |= SMB_UINFO_FLAG_DADMIN; 2525331Samw } 2535331Samw 254*5772Sas200622 rc = smb_lgrp_getbyname("Administrators", &grp); 255*5772Sas200622 if (rc == SMB_LGRP_SUCCESS) { 256*5772Sas200622 if (smb_lgrp_is_member(&grp, user_info->user_sid)) 2575331Samw user_info->flags |= SMB_UINFO_FLAG_LADMIN; 258*5772Sas200622 smb_lgrp_free(&grp); 2595331Samw } 2605331Samw } 2615331Samw 2625331Samw /* 2635331Samw * mlsvc_string_save 2645331Samw * 2655331Samw * This is a convenience function to prepare strings for an RPC call. 2665331Samw * An ms_string_t is set up with the appropriate lengths and str is 2675331Samw * set up to point to a copy of the original string on the heap. The 2685331Samw * macro MLRPC_HEAP_STRSAVE is an alias for mlrpc_heap_strsave, which 2695331Samw * extends the heap and copies the string into the new area. 2705331Samw */ 2715331Samw int 2725331Samw mlsvc_string_save(ms_string_t *ms, char *str, struct mlrpc_xaction *mxa) 2735331Samw { 2745521Sas200622 if (str == NULL) 2755331Samw return (0); 2765331Samw 2775521Sas200622 ms->length = mts_wcequiv_strlen(str); 2785521Sas200622 ms->allosize = ms->length + sizeof (mts_wchar_t); 2795331Samw 2805521Sas200622 if ((ms->str = MLRPC_HEAP_STRSAVE(mxa, str)) == NULL) 2815521Sas200622 return (0); 2825331Samw 2835331Samw return (1); 2845331Samw } 2855331Samw 2865331Samw /* 2875331Samw * mlsvc_sid_save 2885331Samw * 2895331Samw * Expand the heap and copy the sid into the new area. 2905331Samw * Returns a pointer to the copy of the sid on the heap. 2915331Samw */ 2925331Samw nt_sid_t * 2935331Samw mlsvc_sid_save(nt_sid_t *sid, struct mlrpc_xaction *mxa) 2945331Samw { 2955331Samw nt_sid_t *heap_sid; 2965331Samw unsigned size; 2975331Samw 2985331Samw if (sid == NULL) 2995331Samw return (NULL); 3005331Samw 3015331Samw size = nt_sid_length(sid); 3025331Samw 3035331Samw if ((heap_sid = (nt_sid_t *)MLRPC_HEAP_MALLOC(mxa, size)) == NULL) 3045331Samw return (0); 3055331Samw 3065331Samw bcopy(sid, heap_sid, size); 3075331Samw return (heap_sid); 3085331Samw } 3095331Samw 3105331Samw /* 3115331Samw * mlsvc_is_null_handle 3125331Samw * 3135331Samw * Check a handle against a null handle. Returns 1 if the handle is 3145331Samw * null. Otherwise returns 0. 3155331Samw */ 3165331Samw int 3175331Samw mlsvc_is_null_handle(mlsvc_handle_t *handle) 3185331Samw { 3195331Samw static ms_handle_t zero_handle; 3205331Samw 3215331Samw if (handle == NULL || handle->context == NULL) 3225331Samw return (1); 3235331Samw 3245331Samw if (!memcmp(&handle->handle, &zero_handle, sizeof (ms_handle_t))) 3255331Samw return (1); 3265331Samw 3275331Samw return (0); 3285331Samw } 3295331Samw 3305331Samw /* 3315521Sas200622 * mlsvc_join 3325331Samw * 3335331Samw * Returns NT status codes. 3345331Samw */ 3355331Samw DWORD 3365521Sas200622 mlsvc_join(char *server, char *domain, char *plain_user, char *plain_text) 3375331Samw { 3385331Samw smb_auth_info_t auth; 3395331Samw smb_ntdomain_t *di; 3405331Samw int erc; 3415331Samw DWORD status; 3425331Samw mlsvc_handle_t netr_handle; 3435331Samw char machine_passwd[MLSVC_MACHINE_ACCT_PASSWD_MAX]; 344*5772Sas200622 char fqdn[MAXHOSTNAMELEN]; 3455331Samw 3465331Samw machine_passwd[0] = '\0'; 3475331Samw 3485331Samw /* 3495331Samw * Ensure that the domain name is uppercase. 3505331Samw */ 3515331Samw (void) utf8_strupr(domain); 3525331Samw 3535331Samw /* 3545331Samw * There is no point continuing if the domain information is 3555331Samw * not available. Wait for up to 10 seconds and then give up. 3565331Samw */ 3575331Samw if ((di = smb_getdomaininfo(10)) == 0) { 3585331Samw status = NT_STATUS_CANT_ACCESS_DOMAIN_INFO; 3595331Samw return (status); 3605331Samw } 3615331Samw 3625331Samw if (strcasecmp(domain, di->domain) != 0) { 3635331Samw status = NT_STATUS_INVALID_PARAMETER; 3645331Samw return (status); 3655331Samw } 3665331Samw 3675521Sas200622 erc = mlsvc_logon(server, domain, plain_user); 3685331Samw 3695331Samw if (erc == AUTH_USER_GRANT) { 370*5772Sas200622 if (mlsvc_ntjoin_support == B_FALSE) { 371*5772Sas200622 if (smb_resolve_fqdn(domain, fqdn, MAXHOSTNAMELEN) != 1) 372*5772Sas200622 return (NT_STATUS_INVALID_PARAMETER); 3735331Samw 374*5772Sas200622 if (ads_join(fqdn, plain_user, plain_text, 375*5772Sas200622 machine_passwd, sizeof (machine_passwd)) 376*5772Sas200622 == ADJOIN_SUCCESS) 3775331Samw status = NT_STATUS_SUCCESS; 3785521Sas200622 else 3795331Samw status = NT_STATUS_UNSUCCESSFUL; 3805331Samw } else { 3815331Samw if (mlsvc_user_getauth(server, plain_user, &auth) 3825331Samw != 0) { 3835331Samw status = NT_STATUS_INVALID_PARAMETER; 3845331Samw return (status); 3855331Samw } 3865331Samw 3875331Samw status = sam_create_trust_account(server, domain, 3885331Samw &auth); 3895331Samw if (status == NT_STATUS_SUCCESS) { 3905331Samw (void) smb_gethostname(machine_passwd, 3915331Samw sizeof (machine_passwd), 0); 3925331Samw (void) utf8_strlwr(machine_passwd); 3935331Samw } 3945331Samw } 3955331Samw 3965331Samw if (status == NT_STATUS_SUCCESS) { 397*5772Sas200622 erc = smb_config_setstr(SMB_CI_MACHINE_PASSWD, 398*5772Sas200622 machine_passwd); 399*5772Sas200622 if (erc != SMBD_SMF_OK) 4005331Samw return (NT_STATUS_UNSUCCESSFUL); 4015331Samw 4025331Samw /* 4035331Samw * If we successfully create a trust account, we mark 4045331Samw * ourselves as a domain member in the environment so 4055331Samw * that we use the SAMLOGON version of the NETLOGON 4065331Samw * PDC location protocol. 4075331Samw */ 408*5772Sas200622 (void) smb_config_setbool(SMB_CI_DOMAIN_MEMB, B_TRUE); 4095331Samw 4105331Samw if (netr_open(server, domain, &netr_handle) == 0) { 4115331Samw status = netlogon_auth(server, &netr_handle, 4125331Samw NETR_FLG_INIT); 4135331Samw (void) netr_close(&netr_handle); 4145331Samw } else { 4155331Samw status = NT_STATUS_OPEN_FAILED; 4165331Samw } 4175331Samw } 4185331Samw } else { 4195331Samw status = NT_STATUS_LOGON_FAILURE; 4205331Samw } 4215331Samw 4225331Samw return (status); 4235331Samw } 424