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 /* 225772Sas200622 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 235331Samw * Use is subject to license terms. 245331Samw */ 255331Samw 265331Samw /* 275331Samw * Utility functions to support the RPC interface library. 285331Samw */ 295331Samw 305331Samw #include <stdio.h> 315331Samw #include <stdarg.h> 325331Samw #include <strings.h> 335331Samw #include <unistd.h> 345331Samw #include <netdb.h> 355331Samw #include <stdlib.h> 365331Samw 375331Samw #include <sys/time.h> 385331Samw #include <sys/systm.h> 395331Samw 405331Samw #include <smbsrv/libsmb.h> 415331Samw #include <smbsrv/libsmbrdr.h> 425331Samw #include <smbsrv/libsmbns.h> 435331Samw #include <smbsrv/libmlsvc.h> 445331Samw 455331Samw #include <smbsrv/smbinfo.h> 465331Samw #include <smbsrv/lsalib.h> 475331Samw #include <smbsrv/samlib.h> 485331Samw #include <smbsrv/mlsvc_util.h> 495331Samw #include <smbsrv/mlsvc.h> 505331Samw 515772Sas200622 /* Domain join support (using MS-RPC) */ 525772Sas200622 static boolean_t mlsvc_ntjoin_support = B_FALSE; 535772Sas200622 545331Samw extern int netr_open(char *, char *, mlsvc_handle_t *); 555331Samw extern int netr_close(mlsvc_handle_t *); 565331Samw extern DWORD netlogon_auth(char *, mlsvc_handle_t *, DWORD); 575331Samw extern int mlsvc_user_getauth(char *, char *, smb_auth_info_t *); 585331Samw 595331Samw /* 605331Samw * Compare the supplied domain name with the local hostname. 615331Samw * We need to deal with both server names and fully-qualified 625331Samw * domain names. 635331Samw * 645331Samw * Returns: 655331Samw * 0 The specified domain is not the local domain, 665331Samw * 1 The Specified domain is the local domain. 675331Samw * -1 Invalid parameter or unable to get the local 685331Samw * system information. 695331Samw */ 705331Samw int 715331Samw mlsvc_is_local_domain(const char *domain) 725331Samw { 735331Samw char hostname[MAXHOSTNAMELEN]; 745331Samw int rc; 755331Samw 765772Sas200622 if (smb_config_get_secmode() == SMB_SECMODE_WORKGRP) 775772Sas200622 return (1); 785772Sas200622 795331Samw if (strchr(domain, '.') != NULL) 805331Samw rc = smb_getfqhostname(hostname, MAXHOSTNAMELEN); 81*7961SNatalie.Li@Sun.COM else { 82*7961SNatalie.Li@Sun.COM if (strlen(domain) < NETBIOS_NAME_SZ) 83*7961SNatalie.Li@Sun.COM rc = smb_getnetbiosname(hostname, MAXHOSTNAMELEN); 84*7961SNatalie.Li@Sun.COM else 85*7961SNatalie.Li@Sun.COM rc = smb_gethostname(hostname, MAXHOSTNAMELEN, 1); 86*7961SNatalie.Li@Sun.COM } 875331Samw 885331Samw if (rc != 0) 895331Samw return (-1); 905331Samw 915772Sas200622 if (strcasecmp(domain, hostname) == 0) 925331Samw return (1); 935331Samw 945331Samw return (0); 955331Samw } 965331Samw 975331Samw /* 985331Samw * mlsvc_lookup_name 995331Samw * 1005772Sas200622 * This is just a wrapper for lsa_lookup_name. 1015331Samw * 1025772Sas200622 * The memory for the sid is allocated using malloc so the caller should 1035772Sas200622 * call free when it is no longer required. 1045331Samw */ 1055772Sas200622 uint32_t 1066432Sas200622 mlsvc_lookup_name(char *account, smb_sid_t **sid, uint16_t *sid_type) 1075331Samw { 1085772Sas200622 smb_userinfo_t *ainfo; 1095772Sas200622 uint32_t status; 1105331Samw 1115772Sas200622 if ((ainfo = mlsvc_alloc_user_info()) == NULL) 1125772Sas200622 return (NT_STATUS_NO_MEMORY); 1135331Samw 1145772Sas200622 status = lsa_lookup_name(NULL, account, *sid_type, ainfo); 1155772Sas200622 if (status == NT_STATUS_SUCCESS) { 1165772Sas200622 *sid = ainfo->user_sid; 1175772Sas200622 ainfo->user_sid = NULL; 1185772Sas200622 *sid_type = ainfo->sid_name_use; 1195772Sas200622 } 1205331Samw 1215772Sas200622 mlsvc_free_user_info(ainfo); 1225772Sas200622 return (status); 1235331Samw } 1245331Samw 1255331Samw /* 1265331Samw * mlsvc_lookup_sid 1275331Samw * 1285772Sas200622 * This is just a wrapper for lsa_lookup_sid. 1295772Sas200622 * 1305772Sas200622 * The allocated memory for the returned name must be freed by caller upon 1315772Sas200622 * successful return. 1325331Samw */ 1335772Sas200622 uint32_t 1346432Sas200622 mlsvc_lookup_sid(smb_sid_t *sid, char **name) 1355331Samw { 1365772Sas200622 smb_userinfo_t *ainfo; 1375772Sas200622 uint32_t status; 1385772Sas200622 int namelen; 1395331Samw 1405772Sas200622 if ((ainfo = mlsvc_alloc_user_info()) == NULL) 1415772Sas200622 return (NT_STATUS_NO_MEMORY); 1425331Samw 1435772Sas200622 status = lsa_lookup_sid(sid, ainfo); 1445772Sas200622 if (status == NT_STATUS_SUCCESS) { 1455772Sas200622 namelen = strlen(ainfo->domain_name) + strlen(ainfo->name) + 2; 1465772Sas200622 if ((*name = malloc(namelen)) == NULL) { 1475772Sas200622 mlsvc_free_user_info(ainfo); 1485772Sas200622 return (NT_STATUS_NO_MEMORY); 1495331Samw } 1505772Sas200622 (void) snprintf(*name, namelen, "%s\\%s", 1515772Sas200622 ainfo->domain_name, ainfo->name); 1525331Samw } 1535331Samw 1545772Sas200622 mlsvc_free_user_info(ainfo); 1555772Sas200622 return (status); 1565331Samw } 1575331Samw 1585331Samw /* 1595331Samw * mlsvc_alloc_user_info 1605331Samw * 1615331Samw * Allocate a user_info structure and set the contents to zero. A 1625331Samw * pointer to the user_info structure is returned. 1635331Samw */ 1645331Samw smb_userinfo_t * 1655331Samw mlsvc_alloc_user_info(void) 1665331Samw { 1675331Samw smb_userinfo_t *user_info; 1685331Samw 1695331Samw user_info = (smb_userinfo_t *)malloc(sizeof (smb_userinfo_t)); 1705331Samw if (user_info == NULL) 1715331Samw return (NULL); 1725331Samw 1735331Samw bzero(user_info, sizeof (smb_userinfo_t)); 1745331Samw return (user_info); 1755331Samw } 1765331Samw 1775331Samw /* 1785331Samw * mlsvc_free_user_info 1795331Samw * 1805331Samw * Free a user_info structure. This function ensures that the contents 1815331Samw * of the user_info are freed as well as the user_info itself. 1825331Samw */ 1835331Samw void 1845331Samw mlsvc_free_user_info(smb_userinfo_t *user_info) 1855331Samw { 1865331Samw if (user_info) { 1875331Samw mlsvc_release_user_info(user_info); 1885331Samw free(user_info); 1895331Samw } 1905331Samw } 1915331Samw 1925331Samw /* 1935331Samw * mlsvc_release_user_info 1945331Samw * 1955331Samw * Release the contents of a user_info structure and zero out the 1965331Samw * elements but do not free the user_info structure itself. This 1975331Samw * function cleans out the structure so that it can be reused without 1985331Samw * worrying about stale contents. 1995331Samw */ 2005331Samw void 2015331Samw mlsvc_release_user_info(smb_userinfo_t *user_info) 2025331Samw { 2035331Samw int i; 2045331Samw 2055331Samw if (user_info == NULL) 2065331Samw return; 2075331Samw 2085331Samw free(user_info->name); 2095331Samw free(user_info->domain_sid); 2105331Samw free(user_info->domain_name); 2115331Samw free(user_info->groups); 2125331Samw 2135331Samw if (user_info->n_other_grps) { 2145331Samw for (i = 0; i < user_info->n_other_grps; i++) 2155331Samw free(user_info->other_grps[i].sid); 2165331Samw 2175331Samw free(user_info->other_grps); 2185331Samw } 2195331Samw 2206849Sjb150015 free(user_info->session_key); 2215331Samw free(user_info->user_sid); 2225331Samw free(user_info->pgrp_sid); 2235331Samw bzero(user_info, sizeof (smb_userinfo_t)); 2245331Samw } 2255331Samw 2265331Samw /* 2275331Samw * mlsvc_setadmin_user_info 2285331Samw * 2295331Samw * Determines if the given user is the domain Administrator or a 2305331Samw * member of Domain Admins or Administrators group and set the 2315331Samw * user_info->flags accordingly. 2325331Samw */ 2335331Samw void 2345331Samw mlsvc_setadmin_user_info(smb_userinfo_t *user_info) 2355331Samw { 2365331Samw nt_domain_t *domain; 2375772Sas200622 smb_group_t grp; 2385772Sas200622 int rc, i; 2395331Samw 2405331Samw if ((domain = nt_domain_lookupbytype(NT_DOMAIN_PRIMARY)) == NULL) 2415331Samw return; 2425331Samw 2436432Sas200622 if (!smb_sid_cmp((smb_sid_t *)user_info->domain_sid, domain->sid)) 2445331Samw return; 2455331Samw 2465331Samw if (user_info->rid == DOMAIN_USER_RID_ADMIN) 2475331Samw user_info->flags |= SMB_UINFO_FLAG_DADMIN; 2485331Samw else if (user_info->primary_group_rid == DOMAIN_GROUP_RID_ADMINS) 2495331Samw user_info->flags |= SMB_UINFO_FLAG_DADMIN; 2505331Samw else { 2515331Samw for (i = 0; i < user_info->n_groups; i++) 2525331Samw if (user_info->groups[i].rid == DOMAIN_GROUP_RID_ADMINS) 2535331Samw user_info->flags |= SMB_UINFO_FLAG_DADMIN; 2545331Samw } 2555331Samw 2565772Sas200622 rc = smb_lgrp_getbyname("Administrators", &grp); 2575772Sas200622 if (rc == SMB_LGRP_SUCCESS) { 2585772Sas200622 if (smb_lgrp_is_member(&grp, user_info->user_sid)) 2595331Samw user_info->flags |= SMB_UINFO_FLAG_LADMIN; 2605772Sas200622 smb_lgrp_free(&grp); 2615331Samw } 2625331Samw } 2635331Samw 2645331Samw /* 2655331Samw * mlsvc_string_save 2665331Samw * 2675331Samw * This is a convenience function to prepare strings for an RPC call. 2685331Samw * An ms_string_t is set up with the appropriate lengths and str is 2695331Samw * set up to point to a copy of the original string on the heap. The 2705331Samw * macro MLRPC_HEAP_STRSAVE is an alias for mlrpc_heap_strsave, which 2715331Samw * extends the heap and copies the string into the new area. 2725331Samw */ 2735331Samw int 2745331Samw mlsvc_string_save(ms_string_t *ms, char *str, struct mlrpc_xaction *mxa) 2755331Samw { 2765521Sas200622 if (str == NULL) 2775331Samw return (0); 2785331Samw 2795521Sas200622 ms->length = mts_wcequiv_strlen(str); 2805521Sas200622 ms->allosize = ms->length + sizeof (mts_wchar_t); 2815331Samw 2825521Sas200622 if ((ms->str = MLRPC_HEAP_STRSAVE(mxa, str)) == NULL) 2835521Sas200622 return (0); 2845331Samw 2855331Samw return (1); 2865331Samw } 2875331Samw 2885331Samw /* 2895331Samw * mlsvc_sid_save 2905331Samw * 2915331Samw * Expand the heap and copy the sid into the new area. 2925331Samw * Returns a pointer to the copy of the sid on the heap. 2935331Samw */ 2946432Sas200622 smb_sid_t * 2956432Sas200622 mlsvc_sid_save(smb_sid_t *sid, struct mlrpc_xaction *mxa) 2965331Samw { 2976432Sas200622 smb_sid_t *heap_sid; 2985331Samw unsigned size; 2995331Samw 3005331Samw if (sid == NULL) 3015331Samw return (NULL); 3025331Samw 3036432Sas200622 size = smb_sid_len(sid); 3045331Samw 3056432Sas200622 if ((heap_sid = (smb_sid_t *)MLRPC_HEAP_MALLOC(mxa, size)) == NULL) 3065331Samw return (0); 3075331Samw 3085331Samw bcopy(sid, heap_sid, size); 3095331Samw return (heap_sid); 3105331Samw } 3115331Samw 3125331Samw /* 3135331Samw * mlsvc_is_null_handle 3145331Samw * 3155331Samw * Check a handle against a null handle. Returns 1 if the handle is 3165331Samw * null. Otherwise returns 0. 3175331Samw */ 3185331Samw int 3195331Samw mlsvc_is_null_handle(mlsvc_handle_t *handle) 3205331Samw { 3215331Samw static ms_handle_t zero_handle; 3225331Samw 3235331Samw if (handle == NULL || handle->context == NULL) 3245331Samw return (1); 3255331Samw 3265331Samw if (!memcmp(&handle->handle, &zero_handle, sizeof (ms_handle_t))) 3275331Samw return (1); 3285331Samw 3295331Samw return (0); 3305331Samw } 3315331Samw 3326139Sjb150015 DWORD 3336139Sjb150015 mlsvc_netlogon(char *server, char *domain) 3346139Sjb150015 { 3356139Sjb150015 mlsvc_handle_t netr_handle; 3366139Sjb150015 DWORD status; 3376139Sjb150015 3386139Sjb150015 if (netr_open(server, domain, &netr_handle) == 0) { 3396139Sjb150015 status = netlogon_auth(server, &netr_handle, 3406139Sjb150015 NETR_FLG_INIT); 3416139Sjb150015 (void) netr_close(&netr_handle); 3426139Sjb150015 } else { 3436139Sjb150015 status = NT_STATUS_OPEN_FAILED; 3446139Sjb150015 } 3456139Sjb150015 3466139Sjb150015 return (status); 3476139Sjb150015 } 3486139Sjb150015 3495331Samw /* 3505521Sas200622 * mlsvc_join 3515331Samw * 3525331Samw * Returns NT status codes. 3535331Samw */ 3545331Samw DWORD 3555521Sas200622 mlsvc_join(char *server, char *domain, char *plain_user, char *plain_text) 3565331Samw { 3575331Samw smb_auth_info_t auth; 3585331Samw smb_ntdomain_t *di; 3595331Samw int erc; 3605331Samw DWORD status; 3615331Samw char machine_passwd[MLSVC_MACHINE_ACCT_PASSWD_MAX]; 3625772Sas200622 char fqdn[MAXHOSTNAMELEN]; 3635331Samw 3645331Samw machine_passwd[0] = '\0'; 3655331Samw 3665331Samw /* 3675331Samw * Ensure that the domain name is uppercase. 3685331Samw */ 3695331Samw (void) utf8_strupr(domain); 3705331Samw 3715331Samw /* 3725331Samw * There is no point continuing if the domain information is 3735331Samw * not available. Wait for up to 10 seconds and then give up. 3745331Samw */ 3755331Samw if ((di = smb_getdomaininfo(10)) == 0) { 3765331Samw status = NT_STATUS_CANT_ACCESS_DOMAIN_INFO; 3775331Samw return (status); 3785331Samw } 3795331Samw 3805331Samw if (strcasecmp(domain, di->domain) != 0) { 3815331Samw status = NT_STATUS_INVALID_PARAMETER; 3825331Samw return (status); 3835331Samw } 3845331Samw 3855521Sas200622 erc = mlsvc_logon(server, domain, plain_user); 3865331Samw 3875331Samw if (erc == AUTH_USER_GRANT) { 3885772Sas200622 if (mlsvc_ntjoin_support == B_FALSE) { 3895772Sas200622 if (smb_resolve_fqdn(domain, fqdn, MAXHOSTNAMELEN) != 1) 3905772Sas200622 return (NT_STATUS_INVALID_PARAMETER); 3915331Samw 3927052Samw if (smb_ads_join(fqdn, plain_user, plain_text, 3935772Sas200622 machine_passwd, sizeof (machine_passwd)) 3947052Samw == SMB_ADJOIN_SUCCESS) 3955331Samw status = NT_STATUS_SUCCESS; 3965521Sas200622 else 3975331Samw status = NT_STATUS_UNSUCCESSFUL; 3985331Samw } else { 3995331Samw if (mlsvc_user_getauth(server, plain_user, &auth) 4005331Samw != 0) { 4015331Samw status = NT_STATUS_INVALID_PARAMETER; 4025331Samw return (status); 4035331Samw } 4045331Samw 4055331Samw status = sam_create_trust_account(server, domain, 4065331Samw &auth); 4075331Samw if (status == NT_STATUS_SUCCESS) { 408*7961SNatalie.Li@Sun.COM (void) smb_getnetbiosname(machine_passwd, 409*7961SNatalie.Li@Sun.COM sizeof (machine_passwd)); 4105331Samw (void) utf8_strlwr(machine_passwd); 4115331Samw } 4125331Samw } 4135331Samw 4145331Samw if (status == NT_STATUS_SUCCESS) { 4156139Sjb150015 erc = smb_setdomainprops(NULL, server, 4165772Sas200622 machine_passwd); 4176139Sjb150015 if (erc != 0) 4185331Samw return (NT_STATUS_UNSUCCESSFUL); 4195331Samw 4206139Sjb150015 status = mlsvc_netlogon(server, domain); 4215331Samw } 4225331Samw } else { 4235331Samw status = NT_STATUS_LOGON_FAILURE; 4245331Samw } 4255331Samw 4265331Samw return (status); 4275331Samw } 428