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 2009 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 * mlsvc_lookup_name 58 * 59 * This is just a wrapper for lsa_lookup_name. 60 * 61 * The memory for the sid is allocated using malloc so the caller should 62 * call free when it is no longer required. 63 */ 64 uint32_t 65 mlsvc_lookup_name(char *account, smb_sid_t **sid, uint16_t *sid_type) 66 { 67 smb_userinfo_t *ainfo; 68 uint32_t status; 69 70 if ((ainfo = mlsvc_alloc_user_info()) == NULL) 71 return (NT_STATUS_NO_MEMORY); 72 73 status = lsa_lookup_name(account, *sid_type, ainfo); 74 if (status == NT_STATUS_SUCCESS) { 75 *sid = ainfo->user_sid; 76 ainfo->user_sid = NULL; 77 *sid_type = ainfo->sid_name_use; 78 } 79 80 mlsvc_free_user_info(ainfo); 81 return (status); 82 } 83 84 /* 85 * mlsvc_lookup_sid 86 * 87 * This is just a wrapper for lsa_lookup_sid. 88 * 89 * The allocated memory for the returned name must be freed by caller upon 90 * successful return. 91 */ 92 uint32_t 93 mlsvc_lookup_sid(smb_sid_t *sid, char **name) 94 { 95 smb_userinfo_t *ainfo; 96 uint32_t status; 97 int namelen; 98 99 if ((ainfo = mlsvc_alloc_user_info()) == NULL) 100 return (NT_STATUS_NO_MEMORY); 101 102 status = lsa_lookup_sid(sid, ainfo); 103 if (status == NT_STATUS_SUCCESS) { 104 namelen = strlen(ainfo->domain_name) + strlen(ainfo->name) + 2; 105 if ((*name = malloc(namelen)) == NULL) { 106 mlsvc_free_user_info(ainfo); 107 return (NT_STATUS_NO_MEMORY); 108 } 109 (void) snprintf(*name, namelen, "%s\\%s", 110 ainfo->domain_name, ainfo->name); 111 } 112 113 mlsvc_free_user_info(ainfo); 114 return (status); 115 } 116 117 /* 118 * mlsvc_alloc_user_info 119 * 120 * Allocate a user_info structure and set the contents to zero. A 121 * pointer to the user_info structure is returned. 122 */ 123 smb_userinfo_t * 124 mlsvc_alloc_user_info(void) 125 { 126 smb_userinfo_t *user_info; 127 128 user_info = (smb_userinfo_t *)malloc(sizeof (smb_userinfo_t)); 129 if (user_info == NULL) 130 return (NULL); 131 132 bzero(user_info, sizeof (smb_userinfo_t)); 133 return (user_info); 134 } 135 136 /* 137 * mlsvc_free_user_info 138 * 139 * Free a user_info structure. This function ensures that the contents 140 * of the user_info are freed as well as the user_info itself. 141 */ 142 void 143 mlsvc_free_user_info(smb_userinfo_t *user_info) 144 { 145 if (user_info) { 146 mlsvc_release_user_info(user_info); 147 free(user_info); 148 } 149 } 150 151 /* 152 * mlsvc_release_user_info 153 * 154 * Release the contents of a user_info structure and zero out the 155 * elements but do not free the user_info structure itself. This 156 * function cleans out the structure so that it can be reused without 157 * worrying about stale contents. 158 */ 159 void 160 mlsvc_release_user_info(smb_userinfo_t *user_info) 161 { 162 int i; 163 164 if (user_info == NULL) 165 return; 166 167 free(user_info->name); 168 free(user_info->domain_sid); 169 free(user_info->domain_name); 170 free(user_info->groups); 171 172 if (user_info->n_other_grps) { 173 for (i = 0; i < user_info->n_other_grps; i++) 174 free(user_info->other_grps[i].sid); 175 176 free(user_info->other_grps); 177 } 178 179 free(user_info->session_key); 180 free(user_info->user_sid); 181 free(user_info->pgrp_sid); 182 bzero(user_info, sizeof (smb_userinfo_t)); 183 } 184 185 /* 186 * mlsvc_setadmin_user_info 187 * 188 * Determines if the given user is the domain Administrator or a 189 * member of Domain Admins or Administrators group and set the 190 * user_info->flags accordingly. 191 */ 192 void 193 mlsvc_setadmin_user_info(smb_userinfo_t *user_info) 194 { 195 nt_domain_t *domain; 196 smb_group_t grp; 197 int rc, i; 198 199 if ((domain = nt_domain_lookupbytype(NT_DOMAIN_PRIMARY)) == NULL) 200 return; 201 202 if (!smb_sid_cmp((smb_sid_t *)user_info->domain_sid, domain->sid)) 203 return; 204 205 if (user_info->rid == DOMAIN_USER_RID_ADMIN) 206 user_info->flags |= SMB_UINFO_FLAG_DADMIN; 207 else if (user_info->primary_group_rid == DOMAIN_GROUP_RID_ADMINS) 208 user_info->flags |= SMB_UINFO_FLAG_DADMIN; 209 else { 210 for (i = 0; i < user_info->n_groups; i++) 211 if (user_info->groups[i].rid == DOMAIN_GROUP_RID_ADMINS) 212 user_info->flags |= SMB_UINFO_FLAG_DADMIN; 213 } 214 215 rc = smb_lgrp_getbyname("Administrators", &grp); 216 if (rc == SMB_LGRP_SUCCESS) { 217 if (smb_lgrp_is_member(&grp, user_info->user_sid)) 218 user_info->flags |= SMB_UINFO_FLAG_LADMIN; 219 smb_lgrp_free(&grp); 220 } 221 } 222 223 DWORD 224 mlsvc_netlogon(char *server, char *domain) 225 { 226 mlsvc_handle_t netr_handle; 227 DWORD status; 228 229 if (netr_open(server, domain, &netr_handle) == 0) { 230 status = netlogon_auth(server, &netr_handle, 231 NETR_FLG_INIT); 232 (void) netr_close(&netr_handle); 233 } else { 234 status = NT_STATUS_OPEN_FAILED; 235 } 236 237 return (status); 238 } 239 240 /* 241 * mlsvc_join 242 * 243 * Returns NT status codes. 244 */ 245 DWORD 246 mlsvc_join(smb_domain_t *dinfo, char *user, char *plain_text) 247 { 248 smb_auth_info_t auth; 249 int erc; 250 DWORD status; 251 char machine_passwd[NETR_MACHINE_ACCT_PASSWD_MAX]; 252 253 machine_passwd[0] = '\0'; 254 255 /* 256 * Ensure that the domain name is uppercase. 257 */ 258 (void) utf8_strupr(dinfo->d_nbdomain); 259 260 erc = mlsvc_logon(dinfo->d_dc, dinfo->d_nbdomain, user); 261 262 if (erc == AUTH_USER_GRANT) { 263 if (mlsvc_ntjoin_support == B_FALSE) { 264 265 if (smb_ads_join(dinfo->d_fqdomain, user, plain_text, 266 machine_passwd, sizeof (machine_passwd)) 267 == SMB_ADJOIN_SUCCESS) 268 status = NT_STATUS_SUCCESS; 269 else 270 status = NT_STATUS_UNSUCCESSFUL; 271 } else { 272 if (mlsvc_user_getauth(dinfo->d_dc, user, &auth) 273 != 0) { 274 status = NT_STATUS_INVALID_PARAMETER; 275 return (status); 276 } 277 278 status = sam_create_trust_account(dinfo->d_dc, 279 dinfo->d_nbdomain, &auth); 280 if (status == NT_STATUS_SUCCESS) { 281 (void) smb_getnetbiosname(machine_passwd, 282 sizeof (machine_passwd)); 283 (void) utf8_strlwr(machine_passwd); 284 } 285 } 286 287 if (status == NT_STATUS_SUCCESS) { 288 erc = smb_setdomainprops(NULL, dinfo->d_dc, 289 machine_passwd); 290 if (erc != 0) 291 return (NT_STATUS_UNSUCCESSFUL); 292 293 status = mlsvc_netlogon(dinfo->d_dc, dinfo->d_nbdomain); 294 } 295 } else { 296 status = NT_STATUS_LOGON_FAILURE; 297 } 298 299 return (status); 300 } 301