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 #include <strings.h> 27 #include <smbsrv/libsmb.h> 28 29 extern int smb_pwd_num(void); 30 extern int smb_lgrp_numbydomain(smb_gdomain_t, int *); 31 32 static uint32_t smb_sam_lookup_user(char *, smb_sid_t **); 33 static uint32_t smb_sam_lookup_group(char *, smb_sid_t **); 34 35 /* 36 * Looks up the given name in local account databases: 37 * 38 * SMB Local users are looked up in /var/smb/smbpasswd 39 * SMB Local groups are looked up in /var/smb/smbgroup.db 40 * 41 * If the account is found, its information is populated 42 * in the passed smb_account_t structure. Caller must free 43 * allocated memories by calling smb_account_free() upon 44 * successful return. 45 * 46 * The type of account is specified by 'type', which can be user, 47 * alias (local group) or unknown. If the caller doesn't know 48 * whether the name is a user or group name then SidTypeUnknown 49 * should be passed. 50 * 51 * If a local user and group have the same name, the user will 52 * always be picked. Note that this situation cannot happen on 53 * Windows systems. 54 * 55 * If a SMB local user/group is found but it turns out that 56 * it'll be mapped to a domain user/group the lookup is considered 57 * failed and NT_STATUS_NONE_MAPPED is returned. 58 * 59 * Return status: 60 * 61 * NT_STATUS_NOT_FOUND This is not a local account 62 * NT_STATUS_NONE_MAPPED It's a local account but cannot be 63 * translated. 64 * other error status codes. 65 */ 66 uint32_t 67 smb_sam_lookup_name(char *domain, char *name, uint16_t type, 68 smb_account_t *account) 69 { 70 char hostname[MAXHOSTNAMELEN]; 71 smb_sid_t *sid; 72 uint32_t status; 73 74 bzero(account, sizeof (smb_account_t)); 75 (void) smb_getnetbiosname(hostname, sizeof (hostname)); 76 77 if (domain != NULL) { 78 if (!smb_ishostname(domain)) 79 return (NT_STATUS_NOT_FOUND); 80 81 /* Only Netbios hostname is accepted */ 82 if (utf8_strcasecmp(domain, hostname) != 0) 83 return (NT_STATUS_NONE_MAPPED); 84 } 85 86 switch (type) { 87 case SidTypeUser: 88 status = smb_sam_lookup_user(name, &sid); 89 if (status != NT_STATUS_SUCCESS) 90 return (status); 91 break; 92 93 case SidTypeAlias: 94 status = smb_sam_lookup_group(name, &sid); 95 if (status != NT_STATUS_SUCCESS) 96 return (status); 97 break; 98 99 case SidTypeUnknown: 100 type = SidTypeUser; 101 status = smb_sam_lookup_user(name, &sid); 102 if (status == NT_STATUS_SUCCESS) 103 break; 104 105 if (status == NT_STATUS_NONE_MAPPED) 106 return (status); 107 108 type = SidTypeAlias; 109 status = smb_sam_lookup_group(name, &sid); 110 if (status != NT_STATUS_SUCCESS) 111 return (status); 112 break; 113 114 default: 115 return (NT_STATUS_INVALID_PARAMETER); 116 } 117 118 account->a_name = strdup(name); 119 account->a_sid = sid; 120 account->a_domain = strdup(hostname); 121 account->a_domsid = smb_sid_split(sid, &account->a_rid); 122 account->a_type = type; 123 124 if (!smb_account_validate(account)) { 125 smb_account_free(account); 126 return (NT_STATUS_NO_MEMORY); 127 } 128 129 return (NT_STATUS_SUCCESS); 130 } 131 132 /* 133 * Looks up the given SID in local account databases: 134 * 135 * SMB Local users are looked up in /var/smb/smbpasswd 136 * SMB Local groups are looked up in /var/smb/smbgroup.db 137 * 138 * If the account is found, its information is populated 139 * in the passed smb_account_t structure. Caller must free 140 * allocated memories by calling smb_account_free() upon 141 * successful return. 142 * 143 * Return status: 144 * 145 * NT_STATUS_NOT_FOUND This is not a local account 146 * NT_STATUS_NONE_MAPPED It's a local account but cannot be 147 * translated. 148 * other error status codes. 149 */ 150 uint32_t 151 smb_sam_lookup_sid(smb_sid_t *sid, smb_account_t *account) 152 { 153 char hostname[MAXHOSTNAMELEN]; 154 smb_passwd_t smbpw; 155 smb_group_t grp; 156 uint32_t rid; 157 uid_t id; 158 int id_type; 159 int rc; 160 161 bzero(account, sizeof (smb_account_t)); 162 163 if (!smb_sid_islocal(sid)) 164 return (NT_STATUS_NOT_FOUND); 165 166 id_type = SMB_IDMAP_UNKNOWN; 167 if (smb_idmap_getid(sid, &id, &id_type) != IDMAP_SUCCESS) 168 return (NT_STATUS_NONE_MAPPED); 169 170 switch (id_type) { 171 case SMB_IDMAP_USER: 172 account->a_type = SidTypeUser; 173 if (smb_pwd_getpwuid(id, &smbpw) == NULL) 174 return (NT_STATUS_NO_SUCH_USER); 175 176 account->a_name = strdup(smbpw.pw_name); 177 break; 178 179 case SMB_IDMAP_GROUP: 180 account->a_type = SidTypeAlias; 181 (void) smb_sid_getrid(sid, &rid); 182 rc = smb_lgrp_getbyrid(rid, SMB_LGRP_LOCAL, &grp); 183 if (rc != SMB_LGRP_SUCCESS) 184 return (NT_STATUS_NO_SUCH_ALIAS); 185 186 account->a_name = strdup(grp.sg_name); 187 smb_lgrp_free(&grp); 188 break; 189 190 default: 191 return (NT_STATUS_NONE_MAPPED); 192 } 193 194 if (smb_getnetbiosname(hostname, MAXHOSTNAMELEN) == 0) 195 account->a_domain = strdup(hostname); 196 account->a_sid = smb_sid_dup(sid); 197 account->a_domsid = smb_sid_split(sid, &account->a_rid); 198 199 if (!smb_account_validate(account)) { 200 smb_account_free(account); 201 return (NT_STATUS_NO_MEMORY); 202 } 203 204 return (NT_STATUS_SUCCESS); 205 } 206 207 /* 208 * Returns number of SMB users, i.e. users who have entry 209 * in /var/smb/smbpasswd 210 */ 211 int 212 smb_sam_usr_cnt(void) 213 { 214 return (smb_pwd_num()); 215 } 216 217 /* 218 * Returns a list of local groups which the given user is 219 * their member. A pointer to an array of smb_ids_t 220 * structure is returned which must be freed by caller. 221 */ 222 uint32_t 223 smb_sam_usr_groups(smb_sid_t *user_sid, smb_ids_t *gids) 224 { 225 smb_id_t *ids; 226 smb_giter_t gi; 227 smb_group_t lgrp; 228 int total_cnt, gcnt; 229 230 gcnt = 0; 231 if (smb_lgrp_iteropen(&gi) != SMB_LGRP_SUCCESS) 232 return (NT_STATUS_INTERNAL_ERROR); 233 234 while (smb_lgrp_iterate(&gi, &lgrp) == SMB_LGRP_SUCCESS) { 235 if (smb_lgrp_is_member(&lgrp, user_sid)) 236 gcnt++; 237 smb_lgrp_free(&lgrp); 238 } 239 smb_lgrp_iterclose(&gi); 240 241 if (gcnt == 0) 242 return (NT_STATUS_SUCCESS); 243 244 total_cnt = gids->i_cnt + gcnt; 245 gids->i_ids = realloc(gids->i_ids, total_cnt * sizeof (smb_id_t)); 246 if (gids->i_ids == NULL) 247 return (NT_STATUS_NO_MEMORY); 248 249 if (smb_lgrp_iteropen(&gi) != SMB_LGRP_SUCCESS) 250 return (NT_STATUS_INTERNAL_ERROR); 251 252 ids = gids->i_ids + gids->i_cnt; 253 while (smb_lgrp_iterate(&gi, &lgrp) == SMB_LGRP_SUCCESS) { 254 if (gcnt == 0) { 255 smb_lgrp_free(&lgrp); 256 break; 257 } 258 if (smb_lgrp_is_member(&lgrp, user_sid)) { 259 ids->i_sid = smb_sid_dup(lgrp.sg_id.gs_sid); 260 if (ids->i_sid == NULL) { 261 smb_lgrp_free(&lgrp); 262 return (NT_STATUS_NO_MEMORY); 263 } 264 ids->i_attrs = lgrp.sg_attr; 265 gids->i_cnt++; 266 gcnt--; 267 ids++; 268 } 269 smb_lgrp_free(&lgrp); 270 } 271 smb_lgrp_iterclose(&gi); 272 273 return (NT_STATUS_SUCCESS); 274 } 275 276 /* 277 * Returns the number of built-in or local groups stored 278 * in /var/smb/smbgroup.db 279 */ 280 int 281 smb_sam_grp_cnt(nt_domain_type_t dtype) 282 { 283 int grpcnt; 284 int rc; 285 286 switch (dtype) { 287 case NT_DOMAIN_BUILTIN: 288 rc = smb_lgrp_numbydomain(SMB_LGRP_BUILTIN, &grpcnt); 289 break; 290 291 case NT_DOMAIN_LOCAL: 292 rc = smb_lgrp_numbydomain(SMB_LGRP_LOCAL, &grpcnt); 293 break; 294 295 default: 296 rc = SMB_LGRP_INVALID_ARG; 297 } 298 299 return ((rc == SMB_LGRP_SUCCESS) ? grpcnt : 0); 300 } 301 302 /* 303 * Determines whether the given SID is a member of the group 304 * specified by gname. 305 */ 306 boolean_t 307 smb_sam_grp_ismember(const char *gname, smb_sid_t *sid) 308 { 309 smb_group_t grp; 310 boolean_t ismember = B_FALSE; 311 312 if (smb_lgrp_getbyname((char *)gname, &grp) == SMB_LGRP_SUCCESS) { 313 ismember = smb_lgrp_is_member(&grp, sid); 314 smb_lgrp_free(&grp); 315 } 316 317 return (ismember); 318 } 319 320 /* 321 * Frees memories allocated for the passed account fields. 322 */ 323 void 324 smb_account_free(smb_account_t *account) 325 { 326 free(account->a_name); 327 free(account->a_domain); 328 smb_sid_free(account->a_sid); 329 smb_sid_free(account->a_domsid); 330 } 331 332 /* 333 * Validates the given account. 334 */ 335 boolean_t 336 smb_account_validate(smb_account_t *account) 337 { 338 return ((account->a_name != NULL) && (account->a_sid != NULL) && 339 (account->a_domain != NULL) && (account->a_domsid != NULL)); 340 } 341 342 /* 343 * Lookup local SMB user account database (/var/smb/smbpasswd) 344 * if there's a match query its SID from idmap service and make 345 * sure the SID is a local SID. 346 * 347 * The memory for the returned SID must be freed by the caller. 348 */ 349 static uint32_t 350 smb_sam_lookup_user(char *name, smb_sid_t **sid) 351 { 352 smb_passwd_t smbpw; 353 354 if (smb_pwd_getpwnam(name, &smbpw) == NULL) 355 return (NT_STATUS_NO_SUCH_USER); 356 357 if (smb_idmap_getsid(smbpw.pw_uid, SMB_IDMAP_USER, sid) 358 != IDMAP_SUCCESS) 359 return (NT_STATUS_NONE_MAPPED); 360 361 if (!smb_sid_islocal(*sid)) { 362 smb_sid_free(*sid); 363 return (NT_STATUS_NONE_MAPPED); 364 } 365 366 return (NT_STATUS_SUCCESS); 367 } 368 369 /* 370 * Lookup local SMB group account database (/var/smb/smbgroup.db) 371 * The memory for the returned SID must be freed by the caller. 372 */ 373 static uint32_t 374 smb_sam_lookup_group(char *name, smb_sid_t **sid) 375 { 376 smb_group_t grp; 377 378 if (smb_lgrp_getbyname(name, &grp) != SMB_LGRP_SUCCESS) 379 return (NT_STATUS_NO_SUCH_ALIAS); 380 381 *sid = smb_sid_dup(grp.sg_id.gs_sid); 382 smb_lgrp_free(&grp); 383 384 return ((*sid == NULL) ? NT_STATUS_NO_MEMORY : NT_STATUS_SUCCESS); 385 } 386