/* * Lookup local SMB group account database (/var/smb/smbgroup.db) * The memory for the returned SID must be freed by the caller. */ static uint32_t smb_sam_lookup_group(char *name, smb_sid_t **sid) { smb_group_t grp; if (smb_lgrp_getbyname(name, &grp) != SMB_LGRP_SUCCESS) return (NT_STATUS_NO_SUCH_ALIAS); *sid = smb_sid_dup(grp.sg_id.gs_sid); smb_lgrp_free(&grp); return ((*sid == NULL) ? NT_STATUS_NO_MEMORY : NT_STATUS_SUCCESS); }
/* * Determines whether the given SID is a member of the group * specified by gname. */ boolean_t smb_sam_grp_ismember(const char *gname, smb_sid_t *sid) { smb_group_t grp; boolean_t ismember = B_FALSE; if (smb_lgrp_getbyname((char *)gname, &grp) == SMB_LGRP_SUCCESS) { ismember = smb_lgrp_is_member(&grp, sid); smb_lgrp_free(&grp); } return (ismember); }
/* * Looks up the given SID in local account databases: * * SMB Local users are looked up in /var/smb/smbpasswd * SMB Local groups are looked up in /var/smb/smbgroup.db * * If the account is found, its information is populated * in the passed smb_account_t structure. Caller must free * allocated memories by calling smb_account_free() upon * successful return. * * Return status: * * NT_STATUS_NOT_FOUND This is not a local account * NT_STATUS_NONE_MAPPED It's a local account but cannot be * translated. * other error status codes. */ uint32_t smb_sam_lookup_sid(smb_sid_t *sid, smb_account_t *account) { char hostname[MAXHOSTNAMELEN]; smb_passwd_t smbpw; smb_group_t grp; smb_lwka_t *lwka; smb_domain_t di; uint32_t rid; uid_t id; int id_type; int rc; bzero(account, sizeof (smb_account_t)); if (!smb_domain_lookup_type(SMB_DOMAIN_LOCAL, &di)) return (NT_STATUS_CANT_ACCESS_DOMAIN_INFO); if (smb_sid_cmp(sid, di.di_binsid)) { /* This is the local domain SID */ account->a_type = SidTypeDomain; account->a_name = strdup(""); account->a_domain = strdup(di.di_nbname); account->a_sid = smb_sid_dup(sid); account->a_domsid = smb_sid_dup(sid); account->a_rid = (uint32_t)-1; if (!smb_account_validate(account)) { smb_account_free(account); return (NT_STATUS_NO_MEMORY); } return (NT_STATUS_SUCCESS); } if (!smb_sid_indomain(di.di_binsid, sid)) { /* This is not a local SID */ return (NT_STATUS_NOT_FOUND); } if ((lwka = smb_lwka_lookup_sid(sid)) != NULL) { account->a_type = lwka->lwka_type; account->a_name = strdup(lwka->lwka_name); } else { id_type = SMB_IDMAP_UNKNOWN; if (smb_idmap_getid(sid, &id, &id_type) != IDMAP_SUCCESS) return (NT_STATUS_NONE_MAPPED); switch (id_type) { case SMB_IDMAP_USER: account->a_type = SidTypeUser; if (smb_pwd_getpwuid(id, &smbpw) == NULL) return (NT_STATUS_NO_SUCH_USER); account->a_name = strdup(smbpw.pw_name); break; case SMB_IDMAP_GROUP: account->a_type = SidTypeAlias; (void) smb_sid_getrid(sid, &rid); rc = smb_lgrp_getbyrid(rid, SMB_DOMAIN_LOCAL, &grp); if (rc != SMB_LGRP_SUCCESS) return (NT_STATUS_NO_SUCH_ALIAS); account->a_name = strdup(grp.sg_name); smb_lgrp_free(&grp); break; default: return (NT_STATUS_NONE_MAPPED); } } if (smb_getnetbiosname(hostname, MAXHOSTNAMELEN) == 0) account->a_domain = strdup(hostname); account->a_sid = smb_sid_dup(sid); account->a_domsid = smb_sid_split(sid, &account->a_rid); if (!smb_account_validate(account)) { smb_account_free(account); return (NT_STATUS_NO_MEMORY); } return (NT_STATUS_SUCCESS); }
/* * Updates a list of groups in which the given user is a member * by adding any local (SAM) groups. * * We are a member of local groups where the local group * contains either the user's primary SID, or any of their * other SIDs such as from domain groups, SID history, etc. * We can have indirect membership via domain groups. */ uint32_t smb_sam_usr_groups(smb_sid_t *user_sid, smb_ids_t *gids) { smb_ids_t new_gids; smb_id_t *ids, *new_ids; smb_giter_t gi; smb_group_t lgrp; int i, gcnt, total_cnt; uint32_t ret; boolean_t member; /* * First pass: count groups to be added (gcnt) */ gcnt = 0; if (smb_lgrp_iteropen(&gi) != SMB_LGRP_SUCCESS) return (NT_STATUS_INTERNAL_ERROR); while (smb_lgrp_iterate(&gi, &lgrp) == SMB_LGRP_SUCCESS) { member = B_FALSE; if (smb_lgrp_is_member(&lgrp, user_sid)) member = B_TRUE; else for (i = 0, ids = gids->i_ids; i < gids->i_cnt; i++, ids++) { if (smb_lgrp_is_member(&lgrp, ids->i_sid)) { member = B_TRUE; break; } } /* Careful: only count lgrp once */ if (member) gcnt++; smb_lgrp_free(&lgrp); } smb_lgrp_iterclose(&gi); if (gcnt == 0) return (NT_STATUS_SUCCESS); /* * Second pass: add to groups list. * Do not modify gcnt after here. */ if (smb_lgrp_iteropen(&gi) != SMB_LGRP_SUCCESS) return (NT_STATUS_INTERNAL_ERROR); /* * Expand the list (copy to a new, larger one) * Note: were're copying pointers from the old * array to the new (larger) array, and then * adding new pointers after what we copied. */ ret = 0; new_gids.i_cnt = gids->i_cnt; total_cnt = gids->i_cnt + gcnt; new_gids.i_ids = malloc(total_cnt * sizeof (smb_id_t)); if (new_gids.i_ids == NULL) { ret = NT_STATUS_NO_MEMORY; goto out; } (void) memcpy(new_gids.i_ids, gids->i_ids, gids->i_cnt * sizeof (smb_id_t)); new_ids = new_gids.i_ids + gids->i_cnt; (void) memset(new_ids, 0, gcnt * sizeof (smb_id_t)); /* * Add group SIDs starting at the end of the * previous list. (new_ids) */ while (smb_lgrp_iterate(&gi, &lgrp) == SMB_LGRP_SUCCESS) { member = B_FALSE; if (smb_lgrp_is_member(&lgrp, user_sid)) member = B_TRUE; else for (i = 0, ids = gids->i_ids; i < gids->i_cnt; i++, ids++) { if (smb_lgrp_is_member(&lgrp, ids->i_sid)) { member = B_TRUE; break; } } if (member && (new_gids.i_cnt < (gids->i_cnt + gcnt))) { new_ids->i_sid = smb_sid_dup(lgrp.sg_id.gs_sid); if (new_ids->i_sid == NULL) { smb_lgrp_free(&lgrp); ret = NT_STATUS_NO_MEMORY; goto out; } new_ids->i_attrs = lgrp.sg_attr; new_ids++; new_gids.i_cnt++; } smb_lgrp_free(&lgrp); } out: smb_lgrp_iterclose(&gi); if (ret != 0) { if (new_gids.i_ids != NULL) { /* * Free only the new sids we added. * The old ones were copied ptrs. */ ids = new_gids.i_ids + gids->i_cnt; for (i = 0; i < gcnt; i++, ids++) { smb_sid_free(ids->i_sid); } free(new_gids.i_ids); } return (ret); } /* * Success! Update passed gids and * free the old array. */ free(gids->i_ids); *gids = new_gids; return (NT_STATUS_SUCCESS); }
/* * smbadm_group_show * */ static int smbadm_group_show(int argc, char **argv) { char *gname = NULL; boolean_t show_privs; boolean_t show_members; char option; int status; smb_group_t grp; smb_giter_t gi; show_privs = show_members = B_FALSE; while ((option = getopt(argc, argv, "mp")) != -1) { switch (option) { case 'm': show_members = B_TRUE; break; case 'p': show_privs = B_TRUE; break; default: smbadm_usage(B_FALSE); } } gname = argv[optind]; if (optind >= argc || gname == NULL || *gname == '\0') gname = "*"; if (strcmp(gname, "*")) { status = smb_lgrp_getbyname(gname, &grp); if (status == SMB_LGRP_SUCCESS) { smbadm_group_dump(&grp, show_members, show_privs); smb_lgrp_free(&grp); } else { (void) fprintf(stderr, gettext("failed to find %s (%s)\n"), gname, smb_lgrp_strerror(status)); } return (status); } if ((status = smb_lgrp_iteropen(&gi)) != SMB_LGRP_SUCCESS) { (void) fprintf(stderr, gettext("failed to list groups (%s)\n"), smb_lgrp_strerror(status)); return (status); } while ((status = smb_lgrp_iterate(&gi, &grp)) == SMB_LGRP_SUCCESS) { smbadm_group_dump(&grp, show_members, show_privs); smb_lgrp_free(&grp); } smb_lgrp_iterclose(&gi); if ((status != SMB_LGRP_NO_MORE) || smb_lgrp_itererror(&gi)) { if (status != SMB_LGRP_NO_MORE) syslog(LOG_ERR, "smb_lgrp_iterate: %s", smb_lgrp_strerror(status)); (void) fprintf(stderr, gettext("\nAn error occurred while retrieving group data.\n" "Check the system log for more information.\n")); return (status); } return (0); }