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 /* 27 * Utility functions to support the RPC interface library. 28 */ 29 30 #include <stdio.h> 31 #include <stdarg.h> 32 #include <strings.h> 33 #include <unistd.h> 34 #include <netdb.h> 35 #include <stdlib.h> 36 #include <sys/time.h> 37 #include <sys/systm.h> 38 39 #include <smbsrv/libsmb.h> 40 #include <smbsrv/libsmbrdr.h> 41 #include <smbsrv/libsmbns.h> 42 #include <smbsrv/libmlsvc.h> 43 #include <smbsrv/smbinfo.h> 44 #include <lsalib.h> 45 #include <samlib.h> 46 #include <smbsrv/netrauth.h> 47 48 /* Domain join support (using MS-RPC) */ 49 static boolean_t mlsvc_ntjoin_support = B_FALSE; 50 51 extern int netr_open(char *, char *, mlsvc_handle_t *); 52 extern int netr_close(mlsvc_handle_t *); 53 extern DWORD netlogon_auth(char *, mlsvc_handle_t *, DWORD); 54 extern int mlsvc_user_getauth(char *, char *, smb_auth_info_t *); 55 56 /* 57 * Compare the supplied domain name with the local hostname. 58 * We need to deal with both server names and fully-qualified 59 * domain names. 60 * 61 * Returns: 62 * 0 The specified domain is not the local domain, 63 * 1 The Specified domain is the local domain. 64 * -1 Invalid parameter or unable to get the local 65 * system information. 66 */ 67 int 68 mlsvc_is_local_domain(const char *domain) 69 { 70 char hostname[MAXHOSTNAMELEN]; 71 int rc; 72 73 if (smb_config_get_secmode() == SMB_SECMODE_WORKGRP) 74 return (1); 75 76 if (strchr(domain, '.') != NULL) 77 rc = smb_getfqhostname(hostname, MAXHOSTNAMELEN); 78 else { 79 if (strlen(domain) < NETBIOS_NAME_SZ) 80 rc = smb_getnetbiosname(hostname, MAXHOSTNAMELEN); 81 else 82 rc = smb_gethostname(hostname, MAXHOSTNAMELEN, 1); 83 } 84 85 if (rc != 0) 86 return (-1); 87 88 if (strcasecmp(domain, hostname) == 0) 89 return (1); 90 91 return (0); 92 } 93 94 /* 95 * mlsvc_lookup_name 96 * 97 * This is just a wrapper for lsa_lookup_name. 98 * 99 * The memory for the sid is allocated using malloc so the caller should 100 * call free when it is no longer required. 101 */ 102 uint32_t 103 mlsvc_lookup_name(char *account, smb_sid_t **sid, uint16_t *sid_type) 104 { 105 smb_userinfo_t *ainfo; 106 uint32_t status; 107 108 if ((ainfo = mlsvc_alloc_user_info()) == NULL) 109 return (NT_STATUS_NO_MEMORY); 110 111 status = lsa_lookup_name(account, *sid_type, ainfo); 112 if (status == NT_STATUS_SUCCESS) { 113 *sid = ainfo->user_sid; 114 ainfo->user_sid = NULL; 115 *sid_type = ainfo->sid_name_use; 116 } 117 118 mlsvc_free_user_info(ainfo); 119 return (status); 120 } 121 122 /* 123 * mlsvc_lookup_sid 124 * 125 * This is just a wrapper for lsa_lookup_sid. 126 * 127 * The allocated memory for the returned name must be freed by caller upon 128 * successful return. 129 */ 130 uint32_t 131 mlsvc_lookup_sid(smb_sid_t *sid, char **name) 132 { 133 smb_userinfo_t *ainfo; 134 uint32_t status; 135 int namelen; 136 137 if ((ainfo = mlsvc_alloc_user_info()) == NULL) 138 return (NT_STATUS_NO_MEMORY); 139 140 status = lsa_lookup_sid(sid, ainfo); 141 if (status == NT_STATUS_SUCCESS) { 142 namelen = strlen(ainfo->domain_name) + strlen(ainfo->name) + 2; 143 if ((*name = malloc(namelen)) == NULL) { 144 mlsvc_free_user_info(ainfo); 145 return (NT_STATUS_NO_MEMORY); 146 } 147 (void) snprintf(*name, namelen, "%s\\%s", 148 ainfo->domain_name, ainfo->name); 149 } 150 151 mlsvc_free_user_info(ainfo); 152 return (status); 153 } 154 155 /* 156 * mlsvc_alloc_user_info 157 * 158 * Allocate a user_info structure and set the contents to zero. A 159 * pointer to the user_info structure is returned. 160 */ 161 smb_userinfo_t * 162 mlsvc_alloc_user_info(void) 163 { 164 smb_userinfo_t *user_info; 165 166 user_info = (smb_userinfo_t *)malloc(sizeof (smb_userinfo_t)); 167 if (user_info == NULL) 168 return (NULL); 169 170 bzero(user_info, sizeof (smb_userinfo_t)); 171 return (user_info); 172 } 173 174 /* 175 * mlsvc_free_user_info 176 * 177 * Free a user_info structure. This function ensures that the contents 178 * of the user_info are freed as well as the user_info itself. 179 */ 180 void 181 mlsvc_free_user_info(smb_userinfo_t *user_info) 182 { 183 if (user_info) { 184 mlsvc_release_user_info(user_info); 185 free(user_info); 186 } 187 } 188 189 /* 190 * mlsvc_release_user_info 191 * 192 * Release the contents of a user_info structure and zero out the 193 * elements but do not free the user_info structure itself. This 194 * function cleans out the structure so that it can be reused without 195 * worrying about stale contents. 196 */ 197 void 198 mlsvc_release_user_info(smb_userinfo_t *user_info) 199 { 200 int i; 201 202 if (user_info == NULL) 203 return; 204 205 free(user_info->name); 206 free(user_info->domain_sid); 207 free(user_info->domain_name); 208 free(user_info->groups); 209 210 if (user_info->n_other_grps) { 211 for (i = 0; i < user_info->n_other_grps; i++) 212 free(user_info->other_grps[i].sid); 213 214 free(user_info->other_grps); 215 } 216 217 free(user_info->session_key); 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 DWORD 262 mlsvc_netlogon(char *server, char *domain) 263 { 264 mlsvc_handle_t netr_handle; 265 DWORD status; 266 267 if (netr_open(server, domain, &netr_handle) == 0) { 268 status = netlogon_auth(server, &netr_handle, 269 NETR_FLG_INIT); 270 (void) netr_close(&netr_handle); 271 } else { 272 status = NT_STATUS_OPEN_FAILED; 273 } 274 275 return (status); 276 } 277 278 /* 279 * mlsvc_join 280 * 281 * Returns NT status codes. 282 */ 283 DWORD 284 mlsvc_join(smb_domain_t *dinfo, char *user, char *plain_text) 285 { 286 smb_auth_info_t auth; 287 int erc; 288 DWORD status; 289 char machine_passwd[NETR_MACHINE_ACCT_PASSWD_MAX]; 290 291 machine_passwd[0] = '\0'; 292 293 /* 294 * Ensure that the domain name is uppercase. 295 */ 296 (void) utf8_strupr(dinfo->d_nbdomain); 297 298 erc = mlsvc_logon(dinfo->d_dc, dinfo->d_nbdomain, user); 299 300 if (erc == AUTH_USER_GRANT) { 301 if (mlsvc_ntjoin_support == B_FALSE) { 302 303 if (smb_ads_join(dinfo->d_fqdomain, user, plain_text, 304 machine_passwd, sizeof (machine_passwd)) 305 == SMB_ADJOIN_SUCCESS) 306 status = NT_STATUS_SUCCESS; 307 else 308 status = NT_STATUS_UNSUCCESSFUL; 309 } else { 310 if (mlsvc_user_getauth(dinfo->d_dc, user, &auth) 311 != 0) { 312 status = NT_STATUS_INVALID_PARAMETER; 313 return (status); 314 } 315 316 status = sam_create_trust_account(dinfo->d_dc, 317 dinfo->d_nbdomain, &auth); 318 if (status == NT_STATUS_SUCCESS) { 319 (void) smb_getnetbiosname(machine_passwd, 320 sizeof (machine_passwd)); 321 (void) utf8_strlwr(machine_passwd); 322 } 323 } 324 325 if (status == NT_STATUS_SUCCESS) { 326 erc = smb_setdomainprops(NULL, dinfo->d_dc, 327 machine_passwd); 328 if (erc != 0) 329 return (NT_STATUS_UNSUCCESSFUL); 330 331 status = mlsvc_netlogon(dinfo->d_dc, dinfo->d_nbdomain); 332 } 333 } else { 334 status = NT_STATUS_LOGON_FAILURE; 335 } 336 337 return (status); 338 } 339