/* * Frees memories allocated for the passed account fields. */ void smb_account_free(smb_account_t *account) { free(account->a_name); free(account->a_domain); smb_sid_free(account->a_sid); smb_sid_free(account->a_domsid); }
/* * smb_sd_term * * Free non-NULL members of 'sd' which has to be in * absolute (pointer) form. */ void smb_sd_term(smb_sd_t *sd) { ASSERT(sd); ASSERT((sd->sd_control & SE_SELF_RELATIVE) == 0); smb_sid_free(sd->sd_owner); smb_sid_free(sd->sd_group); smb_acl_free(sd->sd_dacl); smb_acl_free(sd->sd_sacl); bzero(sd, sizeof (smb_sd_t)); }
void smb_ids_free(smb_ids_t *ids) { smb_id_t *id; int i; if ((ids != NULL) && (ids->i_ids != NULL)) { id = ids->i_ids; for (i = 0; i < ids->i_cnt; i++, id++) smb_sid_free(id->i_sid); free(ids->i_ids); } }
/* * Lookup local SMB user account database (/var/smb/smbpasswd) * if there's a match query its SID from idmap service and make * sure the SID is a local SID. * * The memory for the returned SID must be freed by the caller. */ static uint32_t smb_sam_lookup_user(char *name, smb_sid_t **sid) { smb_passwd_t smbpw; if (smb_pwd_getpwnam(name, &smbpw) == NULL) return (NT_STATUS_NO_SUCH_USER); if (smb_idmap_getsid(smbpw.pw_uid, SMB_IDMAP_USER, sid) != IDMAP_SUCCESS) return (NT_STATUS_NONE_MAPPED); if (!smb_sid_islocal(*sid)) { smb_sid_free(*sid); return (NT_STATUS_NONE_MAPPED); } return (NT_STATUS_SUCCESS); }
void smb_acl_free(smb_acl_t *acl) { int i, size; void *ace; if (acl == NULL) return; for (i = 0; i < acl->sl_acecnt; i++) smb_sid_free(acl->sl_aces[i].se_sid); while ((ace = list_head(&acl->sl_sorted)) != NULL) list_remove(&acl->sl_sorted, ace); list_destroy(&acl->sl_sorted); size = sizeof (smb_acl_t) + (acl->sl_acecnt * sizeof (smb_ace_t)); kmem_free(acl, size); }
/* * 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); }
/* * smb_lucache_do_update * * This function takes care of updating the AVL tree. * If an entry has been updated, it'll be modified in place. * * New entries will be added to a temporary AVL tree then * passwod file is unlocked and all the new entries will * be transferred to the main cache from the temporary tree. * * This function MUST NOT be called directly */ static int smb_lucache_do_update(void) { avl_tree_t tmp_cache; smb_pwbuf_t pwbuf; smb_passwd_t smbpw; smb_ucnode_t uc_node; smb_ucnode_t *uc_newnode; smb_luser_t *user; smb_sid_t *sid; idmap_stat idm_stat; int rc = SMB_PWE_SUCCESS; void *cookie = NULL; FILE *fp; if ((rc = smb_pwd_lock()) != SMB_PWE_SUCCESS) { syslog(LOG_WARNING, "smb_pwdutil: lock failed, err=%d", rc); return (rc); } if ((fp = fopen(SMB_PASSWD, "rF")) == NULL) { syslog(LOG_WARNING, "smb_pwdutil: open failed, %m"); (void) smb_pwd_unlock(); return (SMB_PWE_OPEN_FAILED); } avl_create(&tmp_cache, smb_lucache_cmp, sizeof (smb_ucnode_t), offsetof(smb_ucnode_t, cn_link)); bzero(&pwbuf, sizeof (smb_pwbuf_t)); pwbuf.pw_pwd = &smbpw; (void) rw_rdlock(&smb_uch.uc_cache_lck); while (smb_pwd_fgetent(fp, &pwbuf, SMB_PWD_GETF_NOPWD) != NULL) { uc_node.cn_user.su_name = smbpw.pw_name; uc_newnode = avl_find(&smb_uch.uc_cache, &uc_node, NULL); if (uc_newnode) { /* update the node info */ uc_newnode->cn_user.su_ctrl = smbpw.pw_flags; continue; } /* create a new node */ if ((uc_newnode = malloc(sizeof (smb_ucnode_t))) == NULL) { rc = SMB_PWE_NO_MEMORY; break; } bzero(uc_newnode, sizeof (smb_ucnode_t)); user = &uc_newnode->cn_user; user->su_ctrl = smbpw.pw_flags; idm_stat = smb_idmap_getsid(smbpw.pw_uid, SMB_IDMAP_USER, &sid); if (idm_stat != IDMAP_SUCCESS) { syslog(LOG_WARNING, "smb_pwdutil: couldn't obtain SID " "for uid=%u (%d)", smbpw.pw_uid, idm_stat); free(uc_newnode); continue; } (void) smb_sid_getrid(sid, &user->su_rid); smb_sid_free(sid); user->su_name = strdup(smbpw.pw_name); if (user->su_name == NULL) { rc = SMB_PWE_NO_MEMORY; free(uc_newnode); break; } avl_add(&tmp_cache, uc_newnode); } (void) rw_unlock(&smb_uch.uc_cache_lck); (void) fclose(fp); (void) smb_pwd_unlock(); /* Destroy the temporary list */ (void) rw_wrlock(&smb_uch.uc_cache_lck); while ((uc_newnode = avl_destroy_nodes(&tmp_cache, &cookie)) != NULL) { avl_add(&smb_uch.uc_cache, uc_newnode); } (void) rw_unlock(&smb_uch.uc_cache_lck); avl_destroy(&tmp_cache); return (rc); }
/* * smbadm_group_delmember */ static int smbadm_group_delmember(int argc, char **argv) { lsa_account_t acct; char *gname = NULL; char **mname; char option; smb_gsid_t msid; int status; int mcnt = 0; int ret = 0; int i; mname = (char **)malloc(argc * sizeof (char *)); if (mname == NULL) { warn(gettext("failed to delete group member")); return (1); } bzero(mname, argc * sizeof (char *)); while ((option = getopt(argc, argv, "m:")) != -1) { switch (option) { case 'm': mname[mcnt++] = optarg; break; default: free(mname); smbadm_usage(B_FALSE); } } if (mcnt == 0) { (void) fprintf(stderr, gettext("missing member name\n")); free(mname); smbadm_usage(B_FALSE); } gname = argv[optind]; if (optind >= argc || gname == NULL || *gname == 0) { (void) fprintf(stderr, gettext("missing group name\n")); free(mname); smbadm_usage(B_FALSE); } for (i = 0; i < mcnt; i++) { ret = 0; if (mname[i] == NULL) continue; ret = smb_lookup_name(mname[i], SidTypeUnknown, &acct); if ((ret != 0) || (acct.a_status != NT_STATUS_SUCCESS)) { (void) fprintf(stderr, gettext("failed to remove %s: " "unable to obtain SID\n"), mname[i]); continue; } msid.gs_type = acct.a_sidtype; if ((msid.gs_sid = smb_sid_fromstr(acct.a_sid)) == NULL) { (void) fprintf(stderr, gettext("failed to remove %s: no memory\n"), mname[i]); continue; } status = smb_lgrp_del_member(gname, msid.gs_sid, msid.gs_type); smb_sid_free(msid.gs_sid); if (status != SMB_LGRP_SUCCESS) { (void) fprintf(stderr, gettext("failed to remove %s (%s)\n"), mname[i], smb_lgrp_strerror(status)); ret = 1; } else { (void) printf( gettext("'%s' has been removed from %s\n"), mname[i], gname); } } return (ret); }