/* Hook to allow GENSEC to handle blob-based authentication * mechanisms, without directly linking the mechansim code */ static NTSTATUS prepare_gensec(TALLOC_CTX *mem_ctx, struct gensec_security **gensec_context) { NTSTATUS status; struct loadparm_context *lp_ctx; struct tevent_context *event_ctx; TALLOC_CTX *frame = talloc_stackframe(); struct gensec_security *gensec_ctx; struct imessaging_context *msg_ctx; struct cli_credentials *server_credentials; lp_ctx = loadparm_init_s3(frame, loadparm_s3_context()); if (lp_ctx == NULL) { DEBUG(1, ("loadparm_init_s3 failed\n")); TALLOC_FREE(frame); return NT_STATUS_INVALID_SERVER_STATE; } event_ctx = s4_event_context_init(mem_ctx); if (event_ctx == NULL) { DEBUG(1, ("s4_event_context_init failed\n")); TALLOC_FREE(frame); return NT_STATUS_INVALID_SERVER_STATE; } msg_ctx = imessaging_client_init(frame, lpcfg_imessaging_path(frame, lp_ctx), event_ctx); if (msg_ctx == NULL) { DEBUG(1, ("imessaging_init failed\n")); TALLOC_FREE(frame); return NT_STATUS_INVALID_SERVER_STATE; } server_credentials = cli_credentials_init(frame); if (!server_credentials) { DEBUG(1, ("Failed to init server credentials")); TALLOC_FREE(frame); return NT_STATUS_INVALID_SERVER_STATE; } cli_credentials_set_conf(server_credentials, lp_ctx); status = cli_credentials_set_machine_account(server_credentials, lp_ctx); if (!NT_STATUS_IS_OK(status)) { DEBUG(10, ("Failed to obtain server credentials, perhaps a standalone server?: %s\n", nt_errstr(status))); talloc_free(server_credentials); server_credentials = NULL; } status = samba_server_gensec_start(mem_ctx, event_ctx, msg_ctx, lp_ctx, server_credentials, "cifs", &gensec_ctx); if (!NT_STATUS_IS_OK(status)) { DEBUG(1, ("Failed to start GENSEC server code: %s\n", nt_errstr(status))); TALLOC_FREE(frame); return status; } talloc_reparent(frame, gensec_ctx, msg_ctx); talloc_reparent(frame, gensec_ctx, event_ctx); talloc_reparent(frame, gensec_ctx, lp_ctx); talloc_reparent(frame, gensec_ctx, server_credentials); gensec_want_feature(gensec_ctx, GENSEC_FEATURE_SESSION_KEY); gensec_want_feature(gensec_ctx, GENSEC_FEATURE_UNIX_TOKEN); *gensec_context = gensec_ctx; TALLOC_FREE(frame); return status; }
/* Return the members of this group (which may be a domain group or an alias) */ NTSTATUS dsdb_enum_group_mem(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn *dn, struct dom_sid **members_out, unsigned int *pnum_members) { struct ldb_message *msg; unsigned int i, j; int ret; struct dom_sid *members; struct ldb_message_element *member_el; const char *attrs[] = { "member", NULL }; NTSTATUS status; TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx); NT_STATUS_HAVE_NO_MEMORY(tmp_ctx); ret = dsdb_search_one(ldb, tmp_ctx, &msg, dn, LDB_SCOPE_BASE, attrs, DSDB_SEARCH_SHOW_EXTENDED_DN, NULL); if (ret == LDB_ERR_NO_SUCH_OBJECT) { talloc_free(tmp_ctx); return NT_STATUS_OBJECT_NAME_NOT_FOUND; } if (ret != LDB_SUCCESS) { DEBUG(1, ("dsdb_enum_group_mem: dsdb_search for %s failed: %s\n", ldb_dn_get_linearized(dn), ldb_errstring(ldb))); return NT_STATUS_INTERNAL_DB_CORRUPTION; } member_el = ldb_msg_find_element(msg, "member"); if (!member_el) { *members_out = NULL; *pnum_members = 0; talloc_free(tmp_ctx); return NT_STATUS_OK; } members = talloc_array(mem_ctx, struct dom_sid, member_el->num_values); if (members == NULL) { return NT_STATUS_NO_MEMORY; } j = 0; for (i=0; i <member_el->num_values; i++) { struct ldb_dn *member_dn = ldb_dn_from_ldb_val(tmp_ctx, ldb, &member_el->values[i]); if (!member_dn || !ldb_dn_validate(member_dn)) { DEBUG(1, ("Could not parse %*.*s as a DN\n", (int)member_el->values[i].length, (int)member_el->values[i].length, (const char *)member_el->values[i].data)); talloc_free(tmp_ctx); return NT_STATUS_INTERNAL_DB_CORRUPTION; } status = dsdb_get_extended_dn_sid(member_dn, &members[j], "SID"); if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) { /* If we fail finding a SID then this is no error since * it could be a non SAM object - e.g. a contact */ continue; } else if (!NT_STATUS_IS_OK(status)) { DEBUG(1, ("When parsing DN '%s' we failed to parse it's SID component, so we cannot fetch the membership: %s\n", ldb_dn_get_extended_linearized(tmp_ctx, member_dn, 1), nt_errstr(status))); talloc_free(tmp_ctx); return status; } ++j; } *members_out = talloc_steal(mem_ctx, members); *pnum_members = j; talloc_free(tmp_ctx); return NT_STATUS_OK; }
NTSTATUS sec_access_check_ds(const struct security_descriptor *sd, const struct security_token *token, uint32_t access_desired, uint32_t *access_granted, struct object_tree *tree, struct dom_sid *replace_sid) { uint32_t i; uint32_t bits_remaining; struct object_tree *node; const struct GUID *type; struct dom_sid *ps_sid = dom_sid_parse_talloc(NULL, SID_NT_SELF); *access_granted = access_desired; bits_remaining = access_desired; /* handle the maximum allowed flag */ if (access_desired & SEC_FLAG_MAXIMUM_ALLOWED) { access_desired |= access_check_max_allowed(sd, token); access_desired &= ~SEC_FLAG_MAXIMUM_ALLOWED; *access_granted = access_desired; bits_remaining = access_desired; } if (access_desired & SEC_FLAG_SYSTEM_SECURITY) { if (security_token_has_privilege(token, SEC_PRIV_SECURITY)) { bits_remaining &= ~SEC_FLAG_SYSTEM_SECURITY; } else { talloc_free(ps_sid); return NT_STATUS_PRIVILEGE_NOT_HELD; } } /* the owner always gets SEC_STD_WRITE_DAC and SEC_STD_READ_CONTROL */ if ((bits_remaining & (SEC_STD_WRITE_DAC|SEC_STD_READ_CONTROL)) && security_token_has_sid(token, sd->owner_sid)) { bits_remaining &= ~(SEC_STD_WRITE_DAC|SEC_STD_READ_CONTROL); } /* TODO: remove this, as it is file server specific */ if ((bits_remaining & SEC_RIGHTS_PRIV_RESTORE) && security_token_has_privilege(token, SEC_PRIV_RESTORE)) { bits_remaining &= ~(SEC_RIGHTS_PRIV_RESTORE); } if ((bits_remaining & SEC_RIGHTS_PRIV_BACKUP) && security_token_has_privilege(token, SEC_PRIV_BACKUP)) { bits_remaining &= ~(SEC_RIGHTS_PRIV_BACKUP); } /* a NULL dacl allows access */ if ((sd->type & SEC_DESC_DACL_PRESENT) && sd->dacl == NULL) { *access_granted = access_desired; talloc_free(ps_sid); return NT_STATUS_OK; } if (sd->dacl == NULL) { goto done; } /* check each ace in turn. */ for (i=0; bits_remaining && i < sd->dacl->num_aces; i++) { struct dom_sid *trustee; struct security_ace *ace = &sd->dacl->aces[i]; if (ace->flags & SEC_ACE_FLAG_INHERIT_ONLY) { continue; } if (dom_sid_equal(&ace->trustee, ps_sid) && replace_sid) { trustee = replace_sid; } else { trustee = &ace->trustee; } if (!security_token_has_sid(token, trustee)) { continue; } switch (ace->type) { case SEC_ACE_TYPE_ACCESS_ALLOWED: if (tree) object_tree_modify_access(tree, ace->access_mask); bits_remaining &= ~ace->access_mask; break; case SEC_ACE_TYPE_ACCESS_DENIED: if (bits_remaining & ace->access_mask) { talloc_free(ps_sid); return NT_STATUS_ACCESS_DENIED; } break; case SEC_ACE_TYPE_ACCESS_DENIED_OBJECT: case SEC_ACE_TYPE_ACCESS_ALLOWED_OBJECT: /* check only in case we have provided a tree, * the ACE has an object type and that type * is in the tree */ type = get_ace_object_type(ace); if (!tree) continue; if (!type) node = tree; else if (!(node = get_object_tree_by_GUID(tree, type))) continue; if (ace->type == SEC_ACE_TYPE_ACCESS_ALLOWED_OBJECT) { object_tree_modify_access(node, ace->access_mask); if (node->remaining_access == 0) { talloc_free(ps_sid); return NT_STATUS_OK; } } else { if (node->remaining_access & ace->access_mask){ talloc_free(ps_sid); return NT_STATUS_ACCESS_DENIED; } } break; default: /* Other ACE types not handled/supported */ break; } } done: talloc_free(ps_sid); if (bits_remaining != 0) { return NT_STATUS_ACCESS_DENIED; } return NT_STATUS_OK; }
bool torture_samba3_checkfsp(struct torture_context *torture) { struct smbcli_state *cli; const char *fname = "test.txt"; const char *dirname = "testdir"; int fnum; NTSTATUS status; bool ret = true; TALLOC_CTX *mem_ctx; ssize_t nread; char buf[16]; struct smbcli_tree *tree2; if ((mem_ctx = talloc_init("torture_samba3_checkfsp")) == NULL) { d_printf("talloc_init failed\n"); return false; } if (!torture_open_connection_share( torture, &cli, torture, torture_setting_string(torture, "host", NULL), torture_setting_string(torture, "share", NULL), torture->ev)) { d_printf("torture_open_connection_share failed\n"); ret = false; goto done; } smbcli_deltree(cli->tree, dirname); status = torture_second_tcon(torture, cli->session, torture_setting_string(torture, "share", NULL), &tree2); CHECK_STATUS(status, NT_STATUS_OK); if (!NT_STATUS_IS_OK(status)) goto done; /* Try a read on an invalid FID */ nread = smbcli_read(cli->tree, 4711, buf, 0, sizeof(buf)); CHECK_STATUS(smbcli_nt_error(cli->tree), NT_STATUS_INVALID_HANDLE); /* Try a read on a directory handle */ status = smbcli_mkdir(cli->tree, dirname); if (!NT_STATUS_IS_OK(status)) { d_printf("smbcli_mkdir failed: %s\n", nt_errstr(status)); ret = false; goto done; } /* Open the directory */ { union smb_open io; io.generic.level = RAW_OPEN_NTCREATEX; io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED; io.ntcreatex.in.root_fid = 0; io.ntcreatex.in.security_flags = 0; io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE; io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL; io.ntcreatex.in.alloc_size = 0; io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_DIRECTORY; io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_NONE; io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN; io.ntcreatex.in.create_options = 0; io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS; io.ntcreatex.in.fname = dirname; status = smb_raw_open(cli->tree, mem_ctx, &io); if (!NT_STATUS_IS_OK(status)) { d_printf("smb_open on the directory failed: %s\n", nt_errstr(status)); ret = false; goto done; } fnum = io.ntcreatex.out.file.fnum; } /* Try a read on the directory */ nread = smbcli_read(cli->tree, fnum, buf, 0, sizeof(buf)); if (nread >= 0) { d_printf("smbcli_read on a directory succeeded, expected " "failure\n"); ret = false; } CHECK_STATUS(smbcli_nt_error(cli->tree), NT_STATUS_INVALID_DEVICE_REQUEST); /* Same test on the second tcon */ nread = smbcli_read(tree2, fnum, buf, 0, sizeof(buf)); if (nread >= 0) { d_printf("smbcli_read on a directory succeeded, expected " "failure\n"); ret = false; } CHECK_STATUS(smbcli_nt_error(tree2), NT_STATUS_INVALID_HANDLE); smbcli_close(cli->tree, fnum); /* Try a normal file read on a second tcon */ fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE); if (fnum == -1) { d_printf("Failed to create %s - %s\n", fname, smbcli_errstr(cli->tree)); ret = false; goto done; } nread = smbcli_read(tree2, fnum, buf, 0, sizeof(buf)); CHECK_STATUS(smbcli_nt_error(tree2), NT_STATUS_INVALID_HANDLE); smbcli_close(cli->tree, fnum); done: smbcli_deltree(cli->tree, dirname); torture_close_connection(cli); talloc_free(mem_ctx); return ret; }
/* Add a user, SAMR style, including the correct transaction * semantics. Used by the SAMR server and by pdb_samba4 */ NTSTATUS dsdb_add_user(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const char *account_name, uint32_t acct_flags, const struct dom_sid *forced_sid, struct dom_sid **sid, struct ldb_dn **dn) { const char *name; struct ldb_message *msg; int ret; const char *container, *obj_class=NULL; char *cn_name; size_t cn_name_len; const char *attrs[] = { "objectSid", "userAccountControl", NULL }; uint32_t user_account_control; struct ldb_dn *account_dn; struct dom_sid *account_sid; TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx); NT_STATUS_HAVE_NO_MEMORY(tmp_ctx); /* * Start a transaction, so we can query and do a subsequent atomic * modify */ ret = ldb_transaction_start(ldb); if (ret != LDB_SUCCESS) { DEBUG(0,("Failed to start a transaction for user creation: %s\n", ldb_errstring(ldb))); talloc_free(tmp_ctx); return NT_STATUS_LOCK_NOT_GRANTED; } /* check if the user already exists */ name = samdb_search_string(ldb, tmp_ctx, NULL, "sAMAccountName", "(&(sAMAccountName=%s)(objectclass=user))", ldb_binary_encode_string(tmp_ctx, account_name)); if (name != NULL) { ldb_transaction_cancel(ldb); talloc_free(tmp_ctx); return NT_STATUS_USER_EXISTS; } cn_name = talloc_strdup(tmp_ctx, account_name); if (!cn_name) { ldb_transaction_cancel(ldb); talloc_free(tmp_ctx); return NT_STATUS_NO_MEMORY; } cn_name_len = strlen(cn_name); if (cn_name_len < 1) { ldb_transaction_cancel(ldb); talloc_free(tmp_ctx); return NT_STATUS_INVALID_PARAMETER; } msg = ldb_msg_new(tmp_ctx); if (msg == NULL) { ldb_transaction_cancel(ldb); talloc_free(tmp_ctx); return NT_STATUS_NO_MEMORY; } /* This must be one of these values *only* */ if (acct_flags == ACB_NORMAL) { container = "CN=Users"; obj_class = "user"; } else if (acct_flags == ACB_WSTRUST) { if (cn_name[cn_name_len - 1] != '$') { ldb_transaction_cancel(ldb); return NT_STATUS_FOOBAR; } cn_name[cn_name_len - 1] = '\0'; container = "CN=Computers"; obj_class = "computer"; } else if (acct_flags == ACB_SVRTRUST) { if (cn_name[cn_name_len - 1] != '$') { ldb_transaction_cancel(ldb); return NT_STATUS_FOOBAR; } cn_name[cn_name_len - 1] = '\0'; container = "OU=Domain Controllers"; obj_class = "computer"; } else if (acct_flags == ACB_DOMTRUST) { DEBUG(3, ("Invalid account flags specified: cannot create domain trusts via this interface (must use LSA CreateTrustedDomain calls\n")); ldb_transaction_cancel(ldb); talloc_free(tmp_ctx); return NT_STATUS_INVALID_PARAMETER; } else { DEBUG(3, ("Invalid account flags specified 0x%08X, must be exactly one of \n" "ACB_NORMAL (0x%08X) ACB_WSTRUST (0x%08X) or ACB_SVRTRUST (0x%08X)\n", acct_flags, ACB_NORMAL, ACB_WSTRUST, ACB_SVRTRUST)); ldb_transaction_cancel(ldb); talloc_free(tmp_ctx); return NT_STATUS_INVALID_PARAMETER; } /* add core elements to the ldb_message for the user */ msg->dn = ldb_dn_copy(msg, ldb_get_default_basedn(ldb)); if ( ! ldb_dn_add_child_fmt(msg->dn, "CN=%s,%s", cn_name, container)) { ldb_transaction_cancel(ldb); talloc_free(tmp_ctx); return NT_STATUS_FOOBAR; } ldb_msg_add_string(msg, "sAMAccountName", account_name); ldb_msg_add_string(msg, "objectClass", obj_class); /* This is only here for migrations using pdb_samba4, the * caller and the samldb are responsible for ensuring it makes * sense */ if (forced_sid) { ret = samdb_msg_add_dom_sid(ldb, msg, msg, "objectSID", forced_sid); if (ret != LDB_SUCCESS) { ldb_transaction_cancel(ldb); talloc_free(tmp_ctx); return NT_STATUS_INTERNAL_ERROR; } } /* create the user */ ret = ldb_add(ldb, msg); switch (ret) { case LDB_SUCCESS: break; case LDB_ERR_ENTRY_ALREADY_EXISTS: ldb_transaction_cancel(ldb); DEBUG(0,("Failed to create user record %s: %s\n", ldb_dn_get_linearized(msg->dn), ldb_errstring(ldb))); talloc_free(tmp_ctx); return NT_STATUS_USER_EXISTS; case LDB_ERR_UNWILLING_TO_PERFORM: case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS: ldb_transaction_cancel(ldb); DEBUG(0,("Failed to create user record %s: %s\n", ldb_dn_get_linearized(msg->dn), ldb_errstring(ldb))); talloc_free(tmp_ctx); return NT_STATUS_ACCESS_DENIED; default: ldb_transaction_cancel(ldb); DEBUG(0,("Failed to create user record %s: %s\n", ldb_dn_get_linearized(msg->dn), ldb_errstring(ldb))); talloc_free(tmp_ctx); return NT_STATUS_INTERNAL_DB_CORRUPTION; } account_dn = msg->dn; /* retrieve the sid and account control bits for the user just created */ ret = dsdb_search_one(ldb, tmp_ctx, &msg, account_dn, LDB_SCOPE_BASE, attrs, 0, NULL); if (ret != LDB_SUCCESS) { ldb_transaction_cancel(ldb); DEBUG(0,("Can't locate the account we just created %s: %s\n", ldb_dn_get_linearized(account_dn), ldb_errstring(ldb))); talloc_free(tmp_ctx); return NT_STATUS_INTERNAL_DB_CORRUPTION; } account_sid = samdb_result_dom_sid(tmp_ctx, msg, "objectSid"); if (account_sid == NULL) { ldb_transaction_cancel(ldb); DEBUG(0,("Apparently we failed to get the objectSid of the just created account record %s\n", ldb_dn_get_linearized(msg->dn))); talloc_free(tmp_ctx); return NT_STATUS_INTERNAL_DB_CORRUPTION; } /* Change the account control to be the correct account type. * The default is for a workstation account */ user_account_control = ldb_msg_find_attr_as_uint(msg, "userAccountControl", 0); user_account_control = (user_account_control & ~(UF_NORMAL_ACCOUNT | UF_INTERDOMAIN_TRUST_ACCOUNT | UF_WORKSTATION_TRUST_ACCOUNT | UF_SERVER_TRUST_ACCOUNT)); user_account_control |= ds_acb2uf(acct_flags); talloc_free(msg); msg = ldb_msg_new(tmp_ctx); if (msg == NULL) { ldb_transaction_cancel(ldb); talloc_free(tmp_ctx); return NT_STATUS_NO_MEMORY; } msg->dn = account_dn; if (samdb_msg_add_uint(ldb, tmp_ctx, msg, "userAccountControl", user_account_control) != LDB_SUCCESS) { ldb_transaction_cancel(ldb); talloc_free(tmp_ctx); return NT_STATUS_NO_MEMORY; } /* modify the samdb record */ ret = dsdb_replace(ldb, msg, 0); if (ret != LDB_SUCCESS) { DEBUG(0,("Failed to modify account record %s to set userAccountControl: %s\n", ldb_dn_get_linearized(msg->dn), ldb_errstring(ldb))); ldb_transaction_cancel(ldb); talloc_free(tmp_ctx); /* we really need samdb.c to return NTSTATUS */ return NT_STATUS_UNSUCCESSFUL; } ret = ldb_transaction_commit(ldb); if (ret != LDB_SUCCESS) { DEBUG(0,("Failed to commit transaction to add and modify account record %s: %s\n", ldb_dn_get_linearized(msg->dn), ldb_errstring(ldb))); talloc_free(tmp_ctx); return NT_STATUS_INTERNAL_DB_CORRUPTION; } *dn = talloc_steal(mem_ctx, account_dn); if (sid) { *sid = talloc_steal(mem_ctx, account_sid); } talloc_free(tmp_ctx); return NT_STATUS_OK; }
static NTSTATUS sldb_set(struct share_context *ctx, const char *name, struct share_info *info, int count) { struct ldb_context *ldb; struct ldb_message *msg; TALLOC_CTX *tmp_ctx; NTSTATUS ret; bool do_rename = false; char *newname; int err, i; if (!name) { return NT_STATUS_INVALID_PARAMETER; } tmp_ctx = talloc_new(NULL); if (!tmp_ctx) { DEBUG(0,("ERROR: Out of memory!\n")); return NT_STATUS_NO_MEMORY; } ldb = talloc_get_type(ctx->priv_data, struct ldb_context); msg = ldb_msg_new(tmp_ctx); if (!msg) { DEBUG(0,("ERROR: Out of memory!\n")); ret = NT_STATUS_NO_MEMORY; goto done; } /* TODO: escape name */ msg->dn = ldb_dn_new_fmt(tmp_ctx, ldb, "CN=%s,CN=SHARES", name); if (!msg->dn) { DEBUG(0,("ERROR: Out of memory!\n")); ret = NT_STATUS_NO_MEMORY; goto done; } for (i = 0; i < count; i++) { if (strcasecmp(info[i].name, SHARE_NAME) == 0) { if (strcasecmp(name, (char *)info[i].value) != 0) { do_rename = true; newname = (char *)info[i].value; SHARE_MOD_STRING("cn", (char *)info[i].value); } } switch (info[i].type) { case SHARE_INFO_STRING: SHARE_MOD_STRING(info[i].name, (char *)info[i].value); break; case SHARE_INFO_INT: SHARE_MOD_INT(info[i].name, *((int *)info[i].value)); break; case SHARE_INFO_BLOB: SHARE_MOD_BLOB(info[i].name, (DATA_BLOB *)info[i].value); break; default: DEBUG(2,("ERROR: Invalid share info type for %s\n", info[i].name)); ret = NT_STATUS_INVALID_PARAMETER; goto done; } } if (do_rename) { struct ldb_dn *olddn, *newdn; olddn = msg->dn; /* TODO: escape newname */ newdn = ldb_dn_new_fmt(tmp_ctx, ldb, "CN=%s,CN=SHARES", newname); if (!newdn) { DEBUG(0,("ERROR: Out of memory!\n")); ret = NT_STATUS_NO_MEMORY; goto done; } err = ldb_rename(ldb, olddn, newdn); if (err != LDB_SUCCESS) { DEBUG(2,("ERROR: unable to rename share %s (to %s)\n" " err=%d [%s]\n", name, newname, err, ldb_errstring(ldb))); if (err == LDB_ERR_NO_SUCH_OBJECT) { ret = NT_STATUS_OBJECT_NAME_COLLISION; } else { ret = NT_STATUS_UNSUCCESSFUL; } goto done; } msg->dn = newdn; } err = ldb_modify(ldb, msg); if (err != LDB_SUCCESS) { DEBUG(2,("ERROR: unable to add share %s to share.ldb\n" " err=%d [%s]\n", name, err, ldb_errstring(ldb))); if (err == LDB_ERR_NO_SUCH_OBJECT) { ret = NT_STATUS_OBJECT_NAME_COLLISION; } else { ret = NT_STATUS_UNSUCCESSFUL; } goto done; } ret = NT_STATUS_OK; done: talloc_free(tmp_ctx); return ret; }
static NTSTATUS raw_smbcli_t2open(struct smbcli_tree *tree, const char *fname, int flags, int share_mode, int *fnum) { union smb_open io; uint_t openfn=0; uint_t accessmode=0; TALLOC_CTX *mem_ctx; NTSTATUS status; mem_ctx = talloc_init("raw_t2open"); if (!mem_ctx) return NT_STATUS_NO_MEMORY; if (flags & O_CREAT) { openfn |= OPENX_OPEN_FUNC_CREATE; } if (!(flags & O_EXCL)) { if (flags & O_TRUNC) { openfn |= OPENX_OPEN_FUNC_TRUNC; } else { openfn |= OPENX_OPEN_FUNC_OPEN; } } accessmode = (share_mode<<OPENX_MODE_DENY_SHIFT); if ((flags & O_ACCMODE) == O_RDWR) { accessmode |= OPENX_MODE_ACCESS_RDWR; } else if ((flags & O_ACCMODE) == O_WRONLY) { accessmode |= OPENX_MODE_ACCESS_WRITE; } else if ((flags & O_ACCMODE) == O_RDONLY) { accessmode |= OPENX_MODE_ACCESS_READ; } #if defined(O_SYNC) if ((flags & O_SYNC) == O_SYNC) { accessmode |= OPENX_MODE_WRITE_THRU; } #endif if (share_mode == DENY_FCB) { accessmode = OPENX_MODE_ACCESS_FCB | OPENX_MODE_DENY_FCB; } memset(&io, '\0', sizeof(io)); io.t2open.level = RAW_OPEN_T2OPEN; io.t2open.in.flags = 0; io.t2open.in.open_mode = accessmode; io.t2open.in.search_attrs = FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN; io.t2open.in.file_attrs = 0; io.t2open.in.write_time = 0; io.t2open.in.open_func = openfn; io.t2open.in.size = 0; io.t2open.in.timeout = 0; io.t2open.in.fname = fname; io.t2open.in.num_eas = 1; io.t2open.in.eas = talloc_array(mem_ctx, struct ea_struct, io.t2open.in.num_eas); io.t2open.in.eas[0].flags = 0; io.t2open.in.eas[0].name.s = ".CLASSINFO"; io.t2open.in.eas[0].value = data_blob_talloc(mem_ctx, "first value", 11); status = smb_raw_open(tree, mem_ctx, &io); talloc_free(mem_ctx); if (fnum && NT_STATUS_IS_OK(status)) { *fnum = io.openx.out.file.fnum; } return status; }
static char *xlat_aprint(TALLOC_CTX *ctx, REQUEST *request, xlat_exp_t const * const node, RADIUS_ESCAPE_STRING escape, void *escape_ctx, int lvl) { ssize_t rcode; char *str = NULL, *child; REQUEST *ref; XLAT_DEBUG("%.*sxlat aprint %d", lvl, xlat_spaces, node->type); switch (node->type) { /* * Don't escape this. */ case XLAT_LITERAL: return talloc_strdup(ctx, node->fmt); /* * Do a one-character expansion. */ case XLAT_PERCENT: { char const *p; char *nl; size_t freespace = 256; struct tm *TM, s_TM; time_t when; str = talloc_array(ctx, char, freespace); /* @todo do better allocation */ p = node->fmt; when = request->timestamp; if (request->packet) { when = request->packet->timestamp.tv_sec; } switch (*p) { case '%': str[0] = '%'; str[1] = '\0'; break; case 'd': /* request day */ TM = localtime_r(&when, &s_TM); strftime(str, freespace, "%d", TM); break; case 'l': /* request timestamp */ snprintf(str, freespace, "%lu", (unsigned long) when); break; case 'm': /* request month */ TM = localtime_r(&when, &s_TM); strftime(str, freespace, "%m", TM); break; case 't': /* request timestamp */ CTIME_R(&when, str, freespace); nl = strchr(str, '\n'); if (nl) *nl = '\0'; break; case 'D': /* request date */ TM = localtime_r(&when, &s_TM); strftime(str, freespace, "%Y%m%d", TM); break; case 'G': /* request minute */ TM = localtime_r(&when, &s_TM); strftime(str, freespace, "%M", TM); break; case 'H': /* request hour */ TM = localtime_r(&when, &s_TM); strftime(str, freespace, "%H", TM); break; case 'I': /* Request ID */ if (request->packet) { snprintf(str, freespace, "%i", request->packet->id); } break; case 'S': /* request timestamp in SQL format*/ TM = localtime_r(&when, &s_TM); strftime(str, freespace, "%Y-%m-%d %H:%M:%S", TM); break; case 'T': /* request timestamp */ TM = localtime_r(&when, &s_TM); strftime(str, freespace, "%Y-%m-%d-%H.%M.%S.000000", TM); break; case 'Y': /* request year */ TM = localtime_r(&when, &s_TM); strftime(str, freespace, "%Y", TM); break; default: rad_assert(0 == 1); break; } } break; case XLAT_ATTRIBUTE: ref = request; if (radius_request(&ref, node->ref) < 0) { return NULL; } /* * Some attributes are virtual <sigh> */ str = xlat_getvp(ctx, ref, node->list, node->da, node->tag, true); if (!str) { str = talloc_zero_array(ctx, char, 1); } XLAT_DEBUG("expand attr %s --> '%s'", node->da->name, str); break; case XLAT_VIRTUAL: str = talloc_array(ctx, char, 1024); /* FIXME: have the module call talloc_asprintf */ rcode = node->xlat->func(node->xlat->instance, request, NULL, str, 1024); if (rcode < 0) { talloc_free(str); return NULL; } break; case XLAT_MODULE: rad_assert(node->child != NULL); if (xlat_process(&child, request, node->child, node->xlat->escape, node->xlat->instance) == 0) { return NULL; } XLAT_DEBUG("%.*sexpand mod %s --> '%s'", lvl, xlat_spaces, node->fmt, child); str = talloc_array(ctx, char, 1024); /* FIXME: have the module call talloc_asprintf */ *str = '\0'; /* Be sure the string is NULL terminated, we now only free on error */ rcode = node->xlat->func(node->xlat->instance, request, child, str, 1024); talloc_free(child); if (rcode < 0) { talloc_free(str); return NULL; } break; #ifdef HAVE_REGEX_H case XLAT_REGEX: child = request_data_reference(request, request, REQUEST_DATA_REGEX | node->num); if (!child) return NULL; str = talloc_strdup(ctx, child); break; #endif case XLAT_ALTERNATE: rad_assert(node->child != NULL); rad_assert(node->alternate != NULL); /* * Special-case first situation being an * attribute. */ if (node->child->type == XLAT_ATTRIBUTE) { str = NULL; ref = request; if (radius_request(&ref, node->child->ref) >= 0) { str = xlat_getvp(ctx, ref, node->child->list, node->child->da, node->child->tag, true); } } else { str = xlat_aprint(ctx, request, node->child, escape, escape_ctx, lvl); } if (str) break; str = xlat_aprint(ctx, request, node->alternate, escape, escape_ctx, lvl); break; }
static ssize_t xlat_tokenize_alternation(TALLOC_CTX *ctx, char *fmt, xlat_exp_t **head, char const **error) { ssize_t slen; char *p; xlat_exp_t *node; rad_assert(fmt[0] == '%'); rad_assert(fmt[1] == '{'); rad_assert(fmt[2] == '%'); rad_assert(fmt[3] == '{'); XLAT_DEBUG("ALTERNATE: %s", fmt); node = talloc_zero(ctx, xlat_exp_t); node->type = XLAT_ALTERNATE; p = fmt + 2; slen = xlat_tokenize_expansion(node, p, &node->child, error); if (slen <= 0) { talloc_free(node); return slen - (p - fmt); } p += slen; if (p[0] != ':') { talloc_free(node); *error = "Expected ':' after first expansion"; return -(p - fmt); } p++; if (p[0] != '-') { talloc_free(node); *error = "Expected '-' after ':'"; return -(p - fmt); } p++; /* * Allow the RHS to be empty as a special case. */ if (*p == '}') { /* * Hack up an empty string. */ node->alternate = talloc_zero(node, xlat_exp_t); node->alternate->type = XLAT_LITERAL; node->alternate->fmt = talloc_strdup(node->alternate, ""); *(p++) = '\0'; } else { slen = xlat_tokenize_literal(node, p, &node->alternate, true, error); if (slen <= 0) { talloc_free(node); return slen - (p - fmt); } if (!node->alternate) { talloc_free(node); *error = "Empty expansion is invalid"; return -(p - fmt); } p += slen; } *head = node; return p - fmt; }
static void manage_gensec_request(enum stdio_helper_mode stdio_helper_mode, struct loadparm_context *lp_ctx, char *buf, int length, void **private1, unsigned int mux_id, void **private2) { DATA_BLOB in; DATA_BLOB out = data_blob(NULL, 0); char *out_base64 = NULL; const char *reply_arg = NULL; struct gensec_ntlm_state { struct gensec_security *gensec_state; const char *set_password; }; struct gensec_ntlm_state *state; struct tevent_context *ev; struct messaging_context *msg; NTSTATUS nt_status; bool first = false; const char *reply_code; struct cli_credentials *creds; static char *want_feature_list = NULL; static DATA_BLOB session_key; TALLOC_CTX *mem_ctx; if (*private1) { state = (struct gensec_ntlm_state *)*private1; } else { state = talloc_zero(NULL, struct gensec_ntlm_state); if (!state) { mux_printf(mux_id, "BH No Memory\n"); exit(1); } *private1 = state; if (opt_password) { state->set_password = opt_password; } } if (strlen(buf) < 2) { DEBUG(1, ("query [%s] invalid", buf)); mux_printf(mux_id, "BH Query invalid\n"); return; } if (strlen(buf) > 3) { if(strncmp(buf, "SF ", 3) == 0) { DEBUG(10, ("Setting flags to negotiate\n")); talloc_free(want_feature_list); want_feature_list = talloc_strndup(state, buf+3, strlen(buf)-3); mux_printf(mux_id, "OK\n"); return; } in = base64_decode_data_blob(NULL, buf + 3); } else { in = data_blob(NULL, 0); } if (strncmp(buf, "YR", 2) == 0) { if (state->gensec_state) { talloc_free(state->gensec_state); state->gensec_state = NULL; } } else if ( (strncmp(buf, "OK", 2) == 0)) { /* Just return BH, like ntlm_auth from Samba 3 does. */ mux_printf(mux_id, "BH Command expected\n"); data_blob_free(&in); return; } else if ( (strncmp(buf, "TT ", 3) != 0) && (strncmp(buf, "KK ", 3) != 0) && (strncmp(buf, "AF ", 3) != 0) && (strncmp(buf, "NA ", 3) != 0) && (strncmp(buf, "UG", 2) != 0) && (strncmp(buf, "PW ", 3) != 0) && (strncmp(buf, "GK", 2) != 0) && (strncmp(buf, "GF", 2) != 0)) { DEBUG(1, ("SPNEGO request [%s] invalid\n", buf)); mux_printf(mux_id, "BH SPNEGO request invalid\n"); data_blob_free(&in); return; } ev = s4_event_context_init(state); if (!ev) { exit(1); } mem_ctx = talloc_named(NULL, 0, "manage_gensec_request internal mem_ctx"); /* setup gensec */ if (!(state->gensec_state)) { switch (stdio_helper_mode) { case GSS_SPNEGO_CLIENT: case NTLMSSP_CLIENT_1: /* setup the client side */ nt_status = gensec_client_start(NULL, &state->gensec_state, ev, lpcfg_gensec_settings(NULL, lp_ctx)); if (!NT_STATUS_IS_OK(nt_status)) { talloc_free(mem_ctx); exit(1); } break; case GSS_SPNEGO_SERVER: case SQUID_2_5_NTLMSSP: { const char *winbind_method[] = { "winbind", NULL }; struct auth_context *auth_context; msg = messaging_client_init(state, lpcfg_messaging_path(state, lp_ctx), ev); if (!msg) { talloc_free(mem_ctx); exit(1); } nt_status = auth_context_create_methods(mem_ctx, winbind_method, ev, msg, lp_ctx, NULL, &auth_context); if (!NT_STATUS_IS_OK(nt_status)) { talloc_free(mem_ctx); exit(1); } if (!NT_STATUS_IS_OK(gensec_server_start(state, ev, lpcfg_gensec_settings(state, lp_ctx), auth_context, &state->gensec_state))) { talloc_free(mem_ctx); exit(1); } break; } default: talloc_free(mem_ctx); abort(); } creds = cli_credentials_init(state->gensec_state); cli_credentials_set_conf(creds, lp_ctx); if (opt_username) { cli_credentials_set_username(creds, opt_username, CRED_SPECIFIED); } if (opt_domain) { cli_credentials_set_domain(creds, opt_domain, CRED_SPECIFIED); } if (state->set_password) { cli_credentials_set_password(creds, state->set_password, CRED_SPECIFIED); } else { cli_credentials_set_password_callback(creds, get_password); creds->priv_data = (void*)(uintptr_t)mux_id; } if (opt_workstation) { cli_credentials_set_workstation(creds, opt_workstation, CRED_SPECIFIED); } switch (stdio_helper_mode) { case GSS_SPNEGO_SERVER: case SQUID_2_5_NTLMSSP: cli_credentials_set_machine_account(creds, lp_ctx); break; default: break; } gensec_set_credentials(state->gensec_state, creds); gensec_want_feature_list(state->gensec_state, want_feature_list); switch (stdio_helper_mode) { case GSS_SPNEGO_CLIENT: case GSS_SPNEGO_SERVER: nt_status = gensec_start_mech_by_oid(state->gensec_state, GENSEC_OID_SPNEGO); if (!in.length) { first = true; } break; case NTLMSSP_CLIENT_1: if (!in.length) { first = true; } /* fall through */ case SQUID_2_5_NTLMSSP: nt_status = gensec_start_mech_by_oid(state->gensec_state, GENSEC_OID_NTLMSSP); break; default: talloc_free(mem_ctx); abort(); } if (!NT_STATUS_IS_OK(nt_status)) { DEBUG(1, ("GENSEC mech failed to start: %s\n", nt_errstr(nt_status))); mux_printf(mux_id, "BH GENSEC mech failed to start\n"); talloc_free(mem_ctx); return; } } /* update */ if (strncmp(buf, "PW ", 3) == 0) { state->set_password = talloc_strndup(state, (const char *)in.data, in.length); cli_credentials_set_password(gensec_get_credentials(state->gensec_state), state->set_password, CRED_SPECIFIED); mux_printf(mux_id, "OK\n"); data_blob_free(&in); talloc_free(mem_ctx); return; } if (strncmp(buf, "UG", 2) == 0) { int i; char *grouplist = NULL; struct auth_session_info *session_info; nt_status = gensec_session_info(state->gensec_state, &session_info); if (!NT_STATUS_IS_OK(nt_status)) { DEBUG(1, ("gensec_session_info failed: %s\n", nt_errstr(nt_status))); mux_printf(mux_id, "BH %s\n", nt_errstr(nt_status)); data_blob_free(&in); talloc_free(mem_ctx); return; } /* get the string onto the context */ grouplist = talloc_strdup(mem_ctx, ""); for (i=0; i<session_info->security_token->num_sids; i++) { struct security_token *token = session_info->security_token; const char *sidstr = dom_sid_string(session_info, &token->sids[i]); grouplist = talloc_asprintf_append_buffer(grouplist, "%s,", sidstr); } mux_printf(mux_id, "GL %s\n", grouplist); talloc_free(session_info); data_blob_free(&in); talloc_free(mem_ctx); return; } if (strncmp(buf, "GK", 2) == 0) { char *base64_key; DEBUG(10, ("Requested session key\n")); nt_status = gensec_session_key(state->gensec_state, &session_key); if(!NT_STATUS_IS_OK(nt_status)) { DEBUG(1, ("gensec_session_key failed: %s\n", nt_errstr(nt_status))); mux_printf(mux_id, "BH No session key\n"); talloc_free(mem_ctx); return; } else { base64_key = base64_encode_data_blob(state, session_key); mux_printf(mux_id, "GK %s\n", base64_key); talloc_free(base64_key); } talloc_free(mem_ctx); return; } if (strncmp(buf, "GF", 2) == 0) { struct ntlmssp_state *ntlmssp_state; uint32_t neg_flags; ntlmssp_state = talloc_get_type(state->gensec_state->private_data, struct ntlmssp_state); neg_flags = ntlmssp_state->neg_flags; DEBUG(10, ("Requested negotiated feature flags\n")); mux_printf(mux_id, "GF 0x%08x\n", neg_flags); return; } nt_status = gensec_update(state->gensec_state, mem_ctx, in, &out); /* don't leak 'bad password'/'no such user' info to the network client */ nt_status = nt_status_squash(nt_status); if (out.length) { out_base64 = base64_encode_data_blob(mem_ctx, out); } else { out_base64 = NULL; } if (NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) { reply_arg = "*"; if (first) { reply_code = "YR"; } else if (state->gensec_state->gensec_role == GENSEC_CLIENT) { reply_code = "KK"; } else if (state->gensec_state->gensec_role == GENSEC_SERVER) { reply_code = "TT"; } else { abort(); } } else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_ACCESS_DENIED)) { reply_code = "BH NT_STATUS_ACCESS_DENIED"; reply_arg = nt_errstr(nt_status); DEBUG(1, ("GENSEC login failed: %s\n", nt_errstr(nt_status))); } else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_UNSUCCESSFUL)) { reply_code = "BH NT_STATUS_UNSUCCESSFUL"; reply_arg = nt_errstr(nt_status); DEBUG(1, ("GENSEC login failed: %s\n", nt_errstr(nt_status))); } else if (!NT_STATUS_IS_OK(nt_status)) { reply_code = "NA"; reply_arg = nt_errstr(nt_status); DEBUG(1, ("GENSEC login failed: %s\n", nt_errstr(nt_status))); } else if /* OK */ (state->gensec_state->gensec_role == GENSEC_SERVER) { struct auth_session_info *session_info; nt_status = gensec_session_info(state->gensec_state, &session_info); if (!NT_STATUS_IS_OK(nt_status)) { reply_code = "BH Failed to retrive session info"; reply_arg = nt_errstr(nt_status); DEBUG(1, ("GENSEC failed to retrieve the session info: %s\n", nt_errstr(nt_status))); } else { reply_code = "AF"; reply_arg = talloc_asprintf(state->gensec_state, "%s%s%s", session_info->info->domain_name, lpcfg_winbind_separator(lp_ctx), session_info->info->account_name); talloc_free(session_info); } } else if (state->gensec_state->gensec_role == GENSEC_CLIENT) { reply_code = "AF"; reply_arg = out_base64; } else { abort(); } switch (stdio_helper_mode) { case GSS_SPNEGO_SERVER: mux_printf(mux_id, "%s %s %s\n", reply_code, out_base64 ? out_base64 : "*", reply_arg ? reply_arg : "*"); break; default: if (out_base64) { mux_printf(mux_id, "%s %s\n", reply_code, out_base64); } else if (reply_arg) { mux_printf(mux_id, "%s %s\n", reply_code, reply_arg); } else { mux_printf(mux_id, "%s\n", reply_code); } } talloc_free(mem_ctx); return; }
static void manage_squid_request(struct loadparm_context *lp_ctx, enum stdio_helper_mode helper_mode, stdio_helper_function fn, void **private2) { char *buf; char tmp[INITIAL_BUFFER_SIZE+1]; unsigned int mux_id = 0; int length, buf_size = 0; char *c; struct mux_private { unsigned int max_mux; void **private_pointers; }; static struct mux_private *mux_private; static void *normal_private; void **private1; buf = talloc_strdup(NULL, ""); if (buf == NULL) { DEBUG(0, ("Failed to allocate memory for reading the input " "buffer.\n")); x_fprintf(x_stdout, "ERR\n"); return; } do { /* this is not a typo - x_fgets doesn't work too well under * squid */ if (fgets(tmp, INITIAL_BUFFER_SIZE, stdin) == NULL) { if (ferror(stdin)) { DEBUG(1, ("fgets() failed! dying..... errno=%d " "(%s)\n", ferror(stdin), strerror(ferror(stdin)))); exit(1); /* BIIG buffer */ } exit(0); } buf = talloc_strdup_append_buffer(buf, tmp); buf_size += INITIAL_BUFFER_SIZE; if (buf_size > MAX_BUFFER_SIZE) { DEBUG(0, ("Invalid Request (too large)\n")); x_fprintf(x_stdout, "ERR\n"); talloc_free(buf); return; } c = strchr(buf, '\n'); } while (c == NULL); *c = '\0'; length = c-buf; DEBUG(10, ("Got '%s' from squid (length: %d).\n",buf,length)); if (buf[0] == '\0') { DEBUG(0, ("Invalid Request (empty)\n")); x_fprintf(x_stdout, "ERR\n"); talloc_free(buf); return; } if (opt_multiplex) { if (sscanf(buf, "%u ", &mux_id) != 1) { DEBUG(0, ("Invalid Request - no multiplex id\n")); x_fprintf(x_stdout, "ERR\n"); talloc_free(buf); return; } if (!mux_private) { mux_private = talloc(NULL, struct mux_private); mux_private->max_mux = 0; mux_private->private_pointers = NULL; } c=strchr(buf,' '); if (!c) { DEBUG(0, ("Invalid Request - no data after multiplex id\n")); x_fprintf(x_stdout, "ERR\n"); talloc_free(buf); return; } c++; if (mux_id >= mux_private->max_mux) { unsigned int prev_max = mux_private->max_mux; mux_private->max_mux = mux_id + 1; mux_private->private_pointers = talloc_realloc(mux_private, mux_private->private_pointers, void *, mux_private->max_mux); memset(&mux_private->private_pointers[prev_max], '\0', (sizeof(*mux_private->private_pointers) * (mux_private->max_mux - prev_max))); };
static NTSTATUS local_pw_check_specified(struct loadparm_context *lp_ctx, const char *username, const char *domain, const char *workstation, const DATA_BLOB *challenge, const DATA_BLOB *lm_response, const DATA_BLOB *nt_response, uint32_t flags, DATA_BLOB *lm_session_key, DATA_BLOB *user_session_key, char **error_string, char **unix_name) { NTSTATUS nt_status; struct samr_Password lm_pw, nt_pw; struct samr_Password *lm_pwd, *nt_pwd; TALLOC_CTX *mem_ctx = talloc_init("local_pw_check_specified"); if (!mem_ctx) { nt_status = NT_STATUS_NO_MEMORY; } else { E_md4hash(opt_password, nt_pw.hash); if (E_deshash(opt_password, lm_pw.hash)) { lm_pwd = &lm_pw; } else { lm_pwd = NULL; } nt_pwd = &nt_pw; nt_status = ntlm_password_check(mem_ctx, lpcfg_lanman_auth(lp_ctx), lpcfg_ntlm_auth(lp_ctx), MSV1_0_ALLOW_SERVER_TRUST_ACCOUNT | MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT, challenge, lm_response, nt_response, username, username, domain, lm_pwd, nt_pwd, user_session_key, lm_session_key); if (NT_STATUS_IS_OK(nt_status)) { if (unix_name) { if (asprintf(unix_name, "%s%c%s", domain, *lpcfg_winbind_separator(lp_ctx), username) < 0) { nt_status = NT_STATUS_NO_MEMORY; } } } else { DEBUG(3, ("Login for user [%s]\\[%s]@[%s] failed due to [%s]\n", domain, username, workstation, nt_errstr(nt_status))); } talloc_free(mem_ctx); } if (error_string) { *error_string = strdup(nt_errstr(nt_status)); } return nt_status; }
/* * given a radius request with many attributes in the EAP-SIM range, build * them all into a single EAP-SIM body. * */ int map_eapsim_basictypes(RADIUS_PACKET *r, eap_packet_t *ep) { VALUE_PAIR *vp; int encoded_size; uint8_t *encodedmsg, *attr; unsigned int id, eapcode; uint8_t *macspace; uint8_t const *append; int appendlen; unsigned char subtype; vp_cursor_t cursor; macspace = NULL; append = NULL; appendlen = 0; /* * encodedmsg is now an EAP-SIM message. * it might be too big for putting into an EAP-Type-SIM * */ subtype = (vp = fr_pair_find_by_num(r->vps, 0, PW_EAP_SIM_SUBTYPE, TAG_ANY)) ? vp->vp_integer : EAPSIM_START; id = (vp = fr_pair_find_by_num(r->vps, 0, PW_EAP_ID, TAG_ANY)) ? vp->vp_integer : ((int)getpid() & 0xff); eapcode = (vp = fr_pair_find_by_num(r->vps, 0, PW_EAP_CODE, TAG_ANY)) ? vp->vp_integer : PW_EAP_REQUEST; /* * take a walk through the attribute list to see how much space * that we need to encode all of this. */ encoded_size = 0; for (vp = fr_cursor_init(&cursor, &r->vps); vp; vp = fr_cursor_next(&cursor)) { int roundedlen; int vplen; if ((vp->da->attr < PW_EAP_SIM_BASE) || (vp->da->attr >= (PW_EAP_SIM_BASE + 256))) { continue; } vplen = vp->vp_length; /* * the AT_MAC attribute is a bit different, when we get to this * attribute, we pull the contents out, save it for later * processing, set the size to 16 bytes (plus 2 bytes padding). * * At this point, we only care about the size. */ if(vp->da->attr == PW_EAP_SIM_MAC) { vplen = 18; } /* round up to next multiple of 4, after taking in * account the type and length bytes */ roundedlen = (vplen + 2 + 3) & ~3; encoded_size += roundedlen; } if (ep->code != PW_EAP_SUCCESS) { ep->code = eapcode; } ep->id = (id & 0xff); ep->type.num = PW_EAP_SIM; /* * if no attributes were found, do very little. * */ if (encoded_size == 0) { encodedmsg = talloc_array(ep, uint8_t, 3); /* FIX: could be NULL */ encodedmsg[0] = subtype; encodedmsg[1] = 0; encodedmsg[2] = 0; ep->type.length = 3; ep->type.data = encodedmsg; return 0; } /* * figured out the length, so allocate some space for the results. * * Note that we do not bother going through an "EAP" stage, which * is a bit strange compared to the unmap, which expects to see * an EAP-SIM virtual attributes. * * EAP is 1-code, 1-identifier, 2-length, 1-type = 5 overhead. * * SIM code adds a subtype, and 2 bytes of reserved = 3. * */ encoded_size += 3; encodedmsg = talloc_array(ep, uint8_t, encoded_size); if (!encodedmsg) { return 0; } memset(encodedmsg, 0, encoded_size); /* * now walk the attributes again, sticking them in. * * we go three bytes into the encoded message, because there are two * bytes of reserved, and we will fill the "subtype" in later. * */ attr = encodedmsg+3; for (vp = fr_cursor_first(&cursor); vp; vp = fr_cursor_next(&cursor)) { int roundedlen; if(vp->da->attr < PW_EAP_SIM_BASE || vp->da->attr >= PW_EAP_SIM_BASE + 256) { continue; } /* * the AT_MAC attribute is a bit different, when we get to this * attribute, we pull the contents out, save it for later * processing, set the size to 16 bytes (plus 2 bytes padding). * * At this point, we put in zeros, and remember where the * sixteen bytes go. */ if(vp->da->attr == PW_EAP_SIM_MAC) { roundedlen = 20; memset(&attr[2], 0, 18); macspace = &attr[4]; append = vp->vp_octets; appendlen = vp->vp_length; } else { roundedlen = (vp->vp_length + 2 + 3) & ~3; memset(attr, 0, roundedlen); memcpy(&attr[2], vp->vp_strvalue, vp->vp_length); } attr[0] = vp->da->attr - PW_EAP_SIM_BASE; attr[1] = roundedlen >> 2; attr += roundedlen; } encodedmsg[0] = subtype; ep->type.length = encoded_size; ep->type.data = encodedmsg; /* * if macspace was set and we have a key, * then we should calculate the HMAC-SHA1 of the resulting EAP-SIM * packet, appended with the value of append. */ vp = fr_pair_find_by_num(r->vps, 0, PW_EAP_SIM_KEY, TAG_ANY); if(macspace != NULL && vp != NULL) { unsigned char *buffer; eap_packet_raw_t *hdr; uint16_t hmaclen, total_length = 0; unsigned char sha1digest[20]; total_length = EAP_HEADER_LEN + 1 + encoded_size; hmaclen = total_length + appendlen; buffer = talloc_array(r, uint8_t, hmaclen); hdr = (eap_packet_raw_t *) buffer; if (!hdr) { talloc_free(encodedmsg); return 0; } hdr->code = eapcode & 0xFF; hdr->id = (id & 0xFF); total_length = htons(total_length); memcpy(hdr->length, &total_length, sizeof(total_length)); hdr->data[0] = PW_EAP_SIM; /* copy the data */ memcpy(&hdr->data[1], encodedmsg, encoded_size); /* copy the nonce */ memcpy(&hdr->data[encoded_size+1], append, appendlen); /* HMAC it! */ fr_hmac_sha1(sha1digest, buffer, hmaclen, vp->vp_octets, vp->vp_length); /* done with the buffer, free it */ talloc_free(buffer); /* now copy the digest to where it belongs in the AT_MAC */ /* note that it is truncated to 128-bits */ memcpy(macspace, sha1digest, 16); } /* if we had an AT_MAC and no key, then fail */ if ((macspace != NULL) && !vp) { if (encodedmsg != NULL) { talloc_free(encodedmsg); } return 0; } return 1; }
/* * calculate the MAC for the EAP message, given the key. * The "extra" will be appended to the EAP message and included in the * HMAC. * */ int eapsim_checkmac(TALLOC_CTX *ctx, VALUE_PAIR *rvps, uint8_t key[EAPSIM_AUTH_SIZE], uint8_t *extra, int extralen, uint8_t calcmac[20]) { int ret; eap_packet_raw_t *e; uint8_t *buffer; int elen,len; VALUE_PAIR *mac; mac = fr_pair_find_by_num(rvps, 0, PW_EAP_SIM_MAC, TAG_ANY); if(!mac || mac->vp_length != 18) { /* can't check a packet with no AT_MAC attribute */ return 0; } /* get original copy of EAP message, note that it was sanitized * to have a valid length, which we depend upon. */ e = eap_vp2packet(ctx, rvps); if (!e) return 0; /* make copy big enough for everything */ elen = (e->length[0] * 256) + e->length[1]; len = elen + extralen; buffer = talloc_array(ctx, uint8_t, len); if (!buffer) { talloc_free(e); return 0; } memcpy(buffer, e, elen); memcpy(buffer + elen, extra, extralen); /* * now look for the AT_MAC attribute in the copy of the buffer * and make sure that the checksum is zero. * */ { uint8_t *attr; /* first attribute is 8 bytes into the EAP packet. * 4 bytes for EAP, 1 for type, 1 for subtype, 2 reserved. */ attr = buffer+8; while(attr < (buffer+elen)) { if (attr[0] == (PW_EAP_SIM_MAC - PW_EAP_SIM_BASE)) { /* zero the data portion, after making sure * the size is >=5. Maybe future versions. * will use more bytes, so be liberal. */ if(attr[1] < 5) { ret = 0; goto done; } memset(&attr[4], 0, (attr[1]-1)*4); } /* advance the pointer */ attr += attr[1]*4; } } /* now, HMAC-SHA1 it with the key. */ fr_hmac_sha1(calcmac, buffer, len, key, 16); ret = memcmp(&mac->vp_strvalue[2], calcmac, 16) == 0 ? 1 : 0; done: talloc_free(e); talloc_free(buffer); return(ret); }
int m_config_parse(m_config_t *config, const char *location, bstr data, char *initial_section, int flags) { m_profile_t *profile = m_config_add_profile(config, initial_section); void *tmp = talloc_new(NULL); int line_no = 0; int errors = 0; bstr_eatstart0(&data, "\xEF\xBB\xBF"); // skip BOM while (data.len) { talloc_free_children(tmp); bool ok = false; line_no++; char loc[512]; snprintf(loc, sizeof(loc), "%s:%d:", location, line_no); bstr line = bstr_strip_linebreaks(bstr_getline(data, &data)); if (!skip_ws(&line)) continue; // Profile declaration if (bstr_eatstart0(&line, "[")) { bstr profilename; if (!bstr_split_tok(line, "]", &profilename, &line)) { MP_ERR(config, "%s missing closing ]\n", loc); goto error; } if (skip_ws(&line)) { MP_ERR(config, "%s unparseable extra characters: '%.*s'\n", loc, BSTR_P(line)); goto error; } profile = m_config_add_profile(config, bstrto0(tmp, profilename)); continue; } bstr_eatstart0(&line, "--"); bstr option = line; while (line.len && (mp_isalnum(line.start[0]) || line.start[0] == '_' || line.start[0] == '-')) line = bstr_cut(line, 1); option.len = option.len - line.len; skip_ws(&line); bstr value = {0}; if (bstr_eatstart0(&line, "=")) { skip_ws(&line); if (line.len && (line.start[0] == '"' || line.start[0] == '\'')) { // Simple quoting, like "value" char term[2] = {line.start[0], 0}; line = bstr_cut(line, 1); if (!bstr_split_tok(line, term, &value, &line)) { MP_ERR(config, "%s unterminated quote\n", loc); goto error; } } else if (bstr_eatstart0(&line, "%")) { // Quoting with length, like %5%value bstr rest; long long len = bstrtoll(line, &rest, 10); if (rest.len == line.len || !bstr_eatstart0(&rest, "%") || len > rest.len) { MP_ERR(config, "%s fixed-length quoting expected - put " "\"quotes\" around the option value if you did not " "intend to use this, but your option value starts " "with '%%'\n", loc); goto error; } value = bstr_splice(rest, 0, len); line = bstr_cut(rest, len); } else { // No quoting; take everything until the comment or end of line int end = bstrchr(line, '#'); value = bstr_strip(end < 0 ? line : bstr_splice(line, 0, end)); line.len = 0; } } if (skip_ws(&line)) { MP_ERR(config, "%s unparseable extra characters: '%.*s'\n", loc, BSTR_P(line)); goto error; } int res; if (bstr_equals0(option, "profile-desc")) { m_profile_set_desc(profile, value); res = 0; } else { res = m_config_set_profile_option(config, profile, option, value); } if (res < 0) { MP_ERR(config, "%s setting option %.*s='%.*s' failed.\n", loc, BSTR_P(option), BSTR_P(value)); goto error; } ok = true; error: if (!ok) errors++; if (errors > 16) { MP_ERR(config, "%s: too many errors, stopping.\n", location); break; } } if (config->recursion_depth == 0) m_config_finish_default_profile(config, flags); talloc_free(tmp); return 1; }
static ssize_t xlat_tokenize_expansion(TALLOC_CTX *ctx, char *fmt, xlat_exp_t **head, char const **error) { ssize_t slen; char *p, *q, *brace; char const *attrname; xlat_exp_t *node; rad_assert(fmt[0] == '%'); rad_assert(fmt[1] == '{'); /* * %{%{...}:-bar} */ if ((fmt[2] == '%') && (fmt[3] == '{')) { return xlat_tokenize_alternation(ctx, fmt, head, error); } XLAT_DEBUG("EXPANSION: %s", fmt); node = talloc_zero(ctx, xlat_exp_t); attrname = node->fmt = fmt + 2; node->len = 0; #ifdef HAVE_REGEX_H /* * Handle regex's specially. */ if (isdigit((int) fmt[2]) && (fmt[3] == '}')) { if (fmt[2] == '9') { talloc_free(node); *error = "Invalid regex reference"; return -2; } XLAT_DEBUG("REGEX: %s", fmt); fmt[3] = '\0'; node->num = fmt[2] - '0'; /* ASCII */ node->type = XLAT_REGEX; *head = node; return 4; } #endif /* HAVE_REGEX_H */ /* * %{Attr-Name} * %{Attr-Name[#]} * %{Tunnel-Password:1} * %{Tunnel-Password:1[#]} * %{request:Attr-Name} * %{request:Tunnel-Password:1} * %{request:Tunnel-Password:1[#]} * %{mod:foo} */ q = brace = NULL; for (p = fmt + 2; *p != '\0'; p++) { if (*p == ':') break; if (isspace((int) *p)) break; if (*p == '[') break; if (*p == '}') break; } if (*p != ':') p = NULL; /* * Might be a module name reference. */ if (p) { *p = '\0'; /* * %{mod:foo} */ node->xlat = xlat_find(node->fmt); if (node->xlat) { node->type = XLAT_MODULE; XLAT_DEBUG("MOD: %s --> %s", node->fmt, p); slen = xlat_tokenize_literal(node, p + 1, &node->child, true, error); if (slen <= 0) { talloc_free(node); return slen - (p - fmt); } p += slen + 1; *head = node; rad_assert(node->next == NULL); return p - fmt; } /* * Modules can have '}' in their RHS, so we * didn't check for that until now. * * As of now, node->fmt MUST be a reference to an * attribute, however complicated. So it MUST have a closing brace. */ brace = strchr(p + 1, '}'); if (!brace) goto no_brace; *brace = '\0'; /* * %{User-Name} * %{User-Name[1]} * %{Tunnel-Password:1} * %{request:Tunnel-Password:1} * * <sigh> The syntax is fairly poor. */ XLAT_DEBUG("Looking for list in '%s'", attrname); /* * Not a module. Has to be an attribute * reference. * * As of v3, we've removed %{request: ..>} as * internally registered xlats. */ *p = ':'; node->ref = radius_request_name(&attrname, REQUEST_CURRENT); rad_assert(node->ref != REQUEST_UNKNOWN); node->list = radius_list_name(&attrname, PAIR_LIST_REQUEST); if (node->list == PAIR_LIST_UNKNOWN) { talloc_free(node); *error = "Unknown module"; return -2; } /* * Check for a trailing tag. */ p = strchr(attrname, ':'); if (p) *p = '\0'; } else { brace = strchr(attrname, '}'); if (!brace) { no_brace: talloc_free(node); *error = "No matching closing brace"; return -1; /* second character of format string */ } *brace = '\0'; node->ref = REQUEST_CURRENT; node->list = PAIR_LIST_REQUEST; } *brace = '\0'; XLAT_DEBUG("Looking for attribute name in %s", attrname); /* * Allow for an array reference. They come AFTER the * tag, if the tag exists. Otherwise, they come after * the attribute name. */ if (p) { q = strchr(p + 1, '['); } else { q = strchr(attrname, '['); } if (q) *(q++) = '\0'; if (!*attrname) { talloc_free(node); *error = "Empty expression is invalid"; return -(attrname - fmt); } /* * It's either an attribute name, or a Tunnel-Password:TAG * with the ':' already set to NULL. */ node->da = dict_attrbyname(attrname); if (!node->da) { /* * Foreach. Maybe other stuff, too. */ node->xlat = xlat_find(attrname); if (node->xlat) { node->type = XLAT_VIRTUAL; node->fmt = attrname; XLAT_DEBUG("VIRTUAL: %s --> %s", node->fmt); *head = node; rad_assert(node->next == NULL); brace++; return brace - fmt; } talloc_free(node); *error = "Unknown attribute"; return -(attrname - fmt); } /* * Parse the tag. */ if (p) { unsigned long tag; char *end; if (!node->da->flags.has_tag) { talloc_free(node); *error = "Attribute cannot have a tag"; return - (p - fmt); } tag = strtoul(p + 1, &end, 10); p++; if (tag == ULONG_MAX) { talloc_free(node); *error = "Invalid tag value"; return - (p - fmt); } node->tag = tag; p = end; if (*p) { talloc_free(node); *error = "Unexpected text after tag"; return - (p - fmt); } } else { node->tag = TAG_ANY; /* leave p alone */ } /* * Check for array reference */ if (q) { unsigned long num; char *end; p = q; if (*p== '#') { node->num = 65536; p++; } else if (*p == '*') { node->num = 65537; p++; } else if (isdigit((int) *p)) { num = strtoul(p, &end, 10); if ((num == ULONG_MAX) || (num > 65535)) { talloc_free(node); *error = "Invalid number"; return - (p - fmt); } p = end; DEBUG("END %s", p); node->num = num; } else { talloc_free(node); *error = "Invalid array reference"; return - (p - fmt); } if (*p != ']') { talloc_free(node); *error = "Expected ']'"; return - (p - fmt); } p++; if (*p) { talloc_free(node); *error = "Unexpected text after array reference"; return - (p - fmt); } } rad_assert(!p || (p == brace)); node->type = XLAT_ATTRIBUTE; p = brace + 1; *head = node; rad_assert(node->next == NULL); return p - fmt; }
static NTSTATUS sldb_create(struct share_context *ctx, const char *name, struct share_info *info, int count) { struct ldb_context *ldb; struct ldb_message *msg; TALLOC_CTX *tmp_ctx; NTSTATUS ret; int err, i, j; for (i = 0, j = 0; i < count && j != 0x03; i++) { if (strcasecmp(info[i].name, SHARE_TYPE) == 0) j |= 0x02; if (strcasecmp(info[i].name, SHARE_PATH) == 0) j |= 0x01; if (strcasecmp(info[i].name, SHARE_NAME) == 0) { if (strcasecmp(name, (char *)info[i].value) != 0) { return NT_STATUS_INVALID_PARAMETER; } } } if (!name || j != 0x03) { return NT_STATUS_INVALID_PARAMETER; } tmp_ctx = talloc_new(NULL); if (!tmp_ctx) { DEBUG(0,("ERROR: Out of memory!\n")); return NT_STATUS_NO_MEMORY; } ldb = talloc_get_type(ctx->priv_data, struct ldb_context); msg = ldb_msg_new(tmp_ctx); if (!msg) { DEBUG(0,("ERROR: Out of memory!\n")); ret = NT_STATUS_NO_MEMORY; goto done; } /* TODO: escape info->name */ msg->dn = ldb_dn_new_fmt(tmp_ctx, ldb, "CN=%s,CN=SHARES", name); if (!msg->dn) { DEBUG(0,("ERROR: Out of memory!\n")); ret = NT_STATUS_NO_MEMORY; goto done; } SHARE_ADD_STRING("objectClass", "top"); SHARE_ADD_STRING("objectClass", "share"); SHARE_ADD_STRING("cn", name); SHARE_ADD_STRING(SHARE_NAME, name); for (i = 0; i < count; i++) { if (strcasecmp(info[i].name, SHARE_NAME) == 0) continue; switch (info[i].type) { case SHARE_INFO_STRING: SHARE_ADD_STRING(info[i].name, (char *)info[i].value); break; case SHARE_INFO_INT: SHARE_ADD_INT(info[i].name, *((int *)info[i].value)); break; case SHARE_INFO_BLOB: SHARE_ADD_BLOB(info[i].name, (DATA_BLOB *)info[i].value); break; default: DEBUG(2,("ERROR: Invalid share info type for %s\n", info[i].name)); ret = NT_STATUS_INVALID_PARAMETER; goto done; } } /* TODO: Security Descriptor */ SHARE_ADD_STRING(SHARE_AVAILABLE, "true"); SHARE_ADD_STRING(SHARE_BROWSEABLE, "true"); SHARE_ADD_STRING(SHARE_READONLY, "false"); SHARE_ADD_STRING(SHARE_NTVFS_HANDLER, "unixuid"); SHARE_ADD_STRING(SHARE_NTVFS_HANDLER, "posix"); err = ldb_add(ldb, msg); if (err != LDB_SUCCESS) { DEBUG(2,("ERROR: unable to add share %s to share.ldb\n" " err=%d [%s]\n", name, err, ldb_errstring(ldb))); if (err == LDB_ERR_NO_SUCH_OBJECT) { ret = NT_STATUS_OBJECT_NAME_NOT_FOUND; } else if (err == LDB_ERR_ENTRY_ALREADY_EXISTS) { ret = NT_STATUS_OBJECT_NAME_COLLISION; } else { ret = NT_STATUS_UNSUCCESSFUL; } goto done; } ret = NT_STATUS_OK; done: talloc_free(tmp_ctx); return ret; }
static ssize_t xlat_tokenize_literal(TALLOC_CTX *ctx, char *fmt, xlat_exp_t **head, int brace, char const **error) { char *p, *q; xlat_exp_t *node; if (!*fmt) return 0; XLAT_DEBUG("LITERAL: %s", fmt); node = talloc_zero(ctx, xlat_exp_t); node->fmt = fmt; node->len = 0; node->type = XLAT_LITERAL; p = fmt; q = fmt; while (*p) { /* * Convert \n to it's literal representation. */ if (p[0] == '\\') switch (p[1]) { case 't': *(q++) = '\t'; p += 2; node->len++; continue; case 'n': *(q++) = '\n'; p += 2; node->len++; continue; case 'x': p += 2; if (!p[0] || !p[1]) { talloc_free(node); *error = "Hex expansion requires two hex digits"; return -(p - fmt); } if (!fr_hex2bin(p, (uint8_t *) q, 2)) { talloc_free(node); *error = "Invalid hex characters"; return -(p - fmt); } /* * Don't let people shoot themselves in the foot. * \x00 is forbidden. */ if (!*q) { talloc_free(node); *error = "Cannot add zero byte to printable string"; return -(p - fmt); } p += 2; q++; node->len++; continue; default: *(q++) = *p; p += 2; node->len++; continue; } /* * Process the expansion. */ if ((p[0] == '%') && (p[1] == '{')) { ssize_t slen; XLAT_DEBUG("LITERAL: %s --> %s", node->fmt, p); slen = xlat_tokenize_expansion(node, p, &node->next, error); if (slen <= 0) { talloc_free(node); return slen - (p - fmt); } *p = '\0'; /* end the literal */ p += slen; rad_assert(node->next != NULL); /* * Short-circuit the recursive call. * This saves another function call and * memory allocation. */ if (!*p) break; /* * "foo %{User-Name} bar" * LITERAL "foo " * EXPANSION User-Name * LITERAL " bar" */ slen = xlat_tokenize_literal(node->next, p, &(node->next->next), brace, error); rad_assert(slen != 0); if (slen < 0) { talloc_free(node); return slen - (p - fmt); } p += slen; break; /* stop processing the string */ } /* * Check for valid single-character expansions. */ if (p[0] == '%') { ssize_t slen; xlat_exp_t *next; if (!p[1] || !strchr("%dlmtDGHISTY", p[1])) { talloc_free(node); *error = "Invalid variable expansion"; p++; return - (p - fmt); } XLAT_DEBUG("PERCENT: %s --> %c", node->fmt, p[1]); next = talloc_zero(node, xlat_exp_t); next->fmt = p + 1; next->len = 1; next->type = XLAT_PERCENT; node->next = next; *p = '\0'; p += 2; if (!*p) break; /* * And recurse. */ slen = xlat_tokenize_literal(node->next, p, &(node->next->next), brace, error); rad_assert(slen != 0); if (slen < 0) { talloc_free(node); return slen - (p - fmt); } p += slen; break; /* stop processing the string */ } /* * If required, eat the brace. */ if (brace && (*p == '}')) { *q = '\0'; p++; break; } *(q++) = *(p++); node->len++; } /* * Squash zero-width literals */ if (node->len > 0) { *head = node; } else { (void) talloc_steal(ctx, node->next); *head = node->next; talloc_free(node); } return p - fmt; }
static NTSTATUS raw_smbcli_open(struct smbcli_tree *tree, const char *fname, int flags, int share_mode, int *fnum) { union smb_open open_parms; uint_t openfn=0; uint_t accessmode=0; TALLOC_CTX *mem_ctx; NTSTATUS status; mem_ctx = talloc_init("raw_open"); if (!mem_ctx) return NT_STATUS_NO_MEMORY; if (flags & O_CREAT) { openfn |= OPENX_OPEN_FUNC_CREATE; } if (!(flags & O_EXCL)) { if (flags & O_TRUNC) { openfn |= OPENX_OPEN_FUNC_TRUNC; } else { openfn |= OPENX_OPEN_FUNC_OPEN; } } accessmode = (share_mode<<OPENX_MODE_DENY_SHIFT); if ((flags & O_ACCMODE) == O_RDWR) { accessmode |= OPENX_MODE_ACCESS_RDWR; } else if ((flags & O_ACCMODE) == O_WRONLY) { accessmode |= OPENX_MODE_ACCESS_WRITE; } else if ((flags & O_ACCMODE) == O_RDONLY) { accessmode |= OPENX_MODE_ACCESS_READ; } #if defined(O_SYNC) if ((flags & O_SYNC) == O_SYNC) { accessmode |= OPENX_MODE_WRITE_THRU; } #endif if (share_mode == DENY_FCB) { accessmode = OPENX_MODE_ACCESS_FCB | OPENX_MODE_DENY_FCB; } open_parms.openx.level = RAW_OPEN_OPENX; open_parms.openx.in.flags = 0; open_parms.openx.in.open_mode = accessmode; open_parms.openx.in.search_attrs = FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN; open_parms.openx.in.file_attrs = 0; open_parms.openx.in.write_time = 0; open_parms.openx.in.open_func = openfn; open_parms.openx.in.size = 0; open_parms.openx.in.timeout = 0; open_parms.openx.in.fname = fname; status = smb_raw_open(tree, mem_ctx, &open_parms); talloc_free(mem_ctx); if (fnum && NT_STATUS_IS_OK(status)) { *fnum = open_parms.openx.out.file.fnum; } return status; }
int ldb_msg_find_duplicate_val(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const struct ldb_message_element *el, struct ldb_val **duplicate, uint32_t options) { unsigned int i, j; struct ldb_val *val; if (options != 0) { return LDB_ERR_OPERATIONS_ERROR; } *duplicate = NULL; /* If there are not many values, it is best to avoid the talloc overhead and just do a brute force search. */ if (el->num_values < LDB_DUP_QUADRATIC_THRESHOLD) { for (j = 0; j < el->num_values; j++) { val = &el->values[j]; for ( i = j + 1; i < el->num_values; i++) { if (ldb_val_equal_exact(val, &el->values[i])) { *duplicate = val; return LDB_SUCCESS; } } } } else { struct ldb_val *values; values = talloc_array(mem_ctx, struct ldb_val, el->num_values); if (values == NULL) { return LDB_ERR_OPERATIONS_ERROR; } memcpy(values, el->values, el->num_values * sizeof(struct ldb_val)); TYPESAFE_QSORT(values, el->num_values, ldb_val_cmp); for (i = 1; i < el->num_values; i++) { if (ldb_val_equal_exact(&values[i], &values[i - 1])) { /* find the original location */ for (j = 0; j < el->num_values; j++) { if (ldb_val_equal_exact(&values[i], &el->values[j]) ) { *duplicate = &el->values[j]; break; } } talloc_free(values); if (*duplicate == NULL) { /* how we got here, I don't know */ return LDB_ERR_OPERATIONS_ERROR; } return LDB_SUCCESS; } } talloc_free(values); } return LDB_SUCCESS; }
bool torture_samba3_badpath(struct torture_context *torture) { struct smbcli_state *cli_nt; struct smbcli_state *cli_dos; const char *fname = "test.txt"; const char *fname1 = "test1.txt"; const char *dirname = "testdir"; char *fpath; char *fpath1; int fnum; NTSTATUS status; bool ret = true; TALLOC_CTX *mem_ctx; bool nt_status_support; if (!(mem_ctx = talloc_init("torture_samba3_badpath"))) { d_printf("talloc_init failed\n"); return false; } nt_status_support = lp_nt_status_support(torture->lp_ctx); if (!lp_set_cmdline(torture->lp_ctx, "nt status support", "yes")) { printf("Could not set 'nt status support = yes'\n"); goto fail; } if (!torture_open_connection(&cli_nt, torture, 0)) { goto fail; } if (!lp_set_cmdline(torture->lp_ctx, "nt status support", "no")) { printf("Could not set 'nt status support = yes'\n"); goto fail; } if (!torture_open_connection(&cli_dos, torture, 1)) { goto fail; } if (!lp_set_cmdline(torture->lp_ctx, "nt status support", nt_status_support ? "yes":"no")) { printf("Could not reset 'nt status support = yes'"); goto fail; } smbcli_deltree(cli_nt->tree, dirname); status = smbcli_mkdir(cli_nt->tree, dirname); if (!NT_STATUS_IS_OK(status)) { d_printf("smbcli_mkdir failed: %s\n", nt_errstr(status)); ret = false; goto done; } status = smbcli_chkpath(cli_nt->tree, dirname); CHECK_STATUS(status, NT_STATUS_OK); status = smbcli_chkpath(cli_nt->tree, talloc_asprintf(mem_ctx, "%s\\bla", dirname)); CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND); status = smbcli_chkpath(cli_dos->tree, talloc_asprintf(mem_ctx, "%s\\bla", dirname)); CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS, ERRbadpath)); status = smbcli_chkpath(cli_nt->tree, talloc_asprintf(mem_ctx, "%s\\bla\\blub", dirname)); CHECK_STATUS(status, NT_STATUS_OBJECT_PATH_NOT_FOUND); status = smbcli_chkpath(cli_dos->tree, talloc_asprintf(mem_ctx, "%s\\bla\\blub", dirname)); CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS, ERRbadpath)); if (!(fpath = talloc_asprintf(mem_ctx, "%s\\%s", dirname, fname))) { goto fail; } fnum = smbcli_open(cli_nt->tree, fpath, O_RDWR | O_CREAT, DENY_NONE); if (fnum == -1) { d_printf("Could not create file %s: %s\n", fpath, smbcli_errstr(cli_nt->tree)); goto fail; } smbcli_close(cli_nt->tree, fnum); if (!(fpath1 = talloc_asprintf(mem_ctx, "%s\\%s", dirname, fname1))) { goto fail; } fnum = smbcli_open(cli_nt->tree, fpath1, O_RDWR | O_CREAT, DENY_NONE); if (fnum == -1) { d_printf("Could not create file %s: %s\n", fpath1, smbcli_errstr(cli_nt->tree)); goto fail; } smbcli_close(cli_nt->tree, fnum); /* * Do a whole bunch of error code checks on chkpath */ status = smbcli_chkpath(cli_nt->tree, fpath); CHECK_STATUS(status, NT_STATUS_NOT_A_DIRECTORY); status = smbcli_chkpath(cli_dos->tree, fpath); CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS, ERRbadpath)); status = smbcli_chkpath(cli_nt->tree, ".."); CHECK_STATUS(status, NT_STATUS_OBJECT_PATH_SYNTAX_BAD); status = smbcli_chkpath(cli_dos->tree, ".."); CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS, ERRinvalidpath)); status = smbcli_chkpath(cli_nt->tree, "."); CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID); status = smbcli_chkpath(cli_dos->tree, "."); CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS, ERRbadpath)); status = smbcli_chkpath(cli_nt->tree, "\t"); CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID); status = smbcli_chkpath(cli_dos->tree, "\t"); CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS, ERRbadpath)); status = smbcli_chkpath(cli_nt->tree, "\t\\bla"); CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID); status = smbcli_chkpath(cli_dos->tree, "\t\\bla"); CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS, ERRbadpath)); status = smbcli_chkpath(cli_nt->tree, "<"); CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID); status = smbcli_chkpath(cli_dos->tree, "<"); CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS, ERRbadpath)); status = smbcli_chkpath(cli_nt->tree, "<\\bla"); CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID); status = smbcli_chkpath(cli_dos->tree, "<\\bla"); CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS, ERRbadpath)); /* * .... And the same gang against getatr. Note that the DOS error codes * differ.... */ status = smbcli_getatr(cli_nt->tree, fpath, NULL, NULL, NULL); CHECK_STATUS(status, NT_STATUS_OK); status = smbcli_getatr(cli_dos->tree, fpath, NULL, NULL, NULL); CHECK_STATUS(status, NT_STATUS_OK); status = smbcli_getatr(cli_nt->tree, "..", NULL, NULL, NULL); CHECK_STATUS(status, NT_STATUS_OBJECT_PATH_SYNTAX_BAD); status = smbcli_getatr(cli_dos->tree, "..", NULL, NULL, NULL); CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS, ERRinvalidpath)); status = smbcli_getatr(cli_nt->tree, ".", NULL, NULL, NULL); CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID); status = smbcli_getatr(cli_dos->tree, ".", NULL, NULL, NULL); CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS, ERRinvalidname)); status = smbcli_getatr(cli_nt->tree, "\t", NULL, NULL, NULL); CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID); status = smbcli_getatr(cli_dos->tree, "\t", NULL, NULL, NULL); CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS, ERRinvalidname)); status = smbcli_getatr(cli_nt->tree, "\t\\bla", NULL, NULL, NULL); CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID); status = smbcli_getatr(cli_dos->tree, "\t\\bla", NULL, NULL, NULL); CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS, ERRinvalidname)); status = smbcli_getatr(cli_nt->tree, "<", NULL, NULL, NULL); CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID); status = smbcli_getatr(cli_dos->tree, "<", NULL, NULL, NULL); CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS, ERRinvalidname)); status = smbcli_getatr(cli_nt->tree, "<\\bla", NULL, NULL, NULL); CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID); status = smbcli_getatr(cli_dos->tree, "<\\bla", NULL, NULL, NULL); CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS, ERRinvalidname)); /* Try the same set with openX. */ status = raw_smbcli_open(cli_nt->tree, "..", O_RDONLY, DENY_NONE, NULL); CHECK_STATUS(status, NT_STATUS_OBJECT_PATH_SYNTAX_BAD); status = raw_smbcli_open(cli_dos->tree, "..", O_RDONLY, DENY_NONE, NULL); CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS, ERRinvalidpath)); status = raw_smbcli_open(cli_nt->tree, ".", O_RDONLY, DENY_NONE, NULL); CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID); status = raw_smbcli_open(cli_dos->tree, ".", O_RDONLY, DENY_NONE, NULL); CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS, ERRinvalidname)); status = raw_smbcli_open(cli_nt->tree, "\t", O_RDONLY, DENY_NONE, NULL); CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID); status = raw_smbcli_open(cli_dos->tree, "\t", O_RDONLY, DENY_NONE, NULL); CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS, ERRinvalidname)); status = raw_smbcli_open(cli_nt->tree, "\t\\bla", O_RDONLY, DENY_NONE, NULL); CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID); status = raw_smbcli_open(cli_dos->tree, "\t\\bla", O_RDONLY, DENY_NONE, NULL); CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS, ERRinvalidname)); status = raw_smbcli_open(cli_nt->tree, "<", O_RDONLY, DENY_NONE, NULL); CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID); status = raw_smbcli_open(cli_dos->tree, "<", O_RDONLY, DENY_NONE, NULL); CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS, ERRinvalidname)); status = raw_smbcli_open(cli_nt->tree, "<\\bla", O_RDONLY, DENY_NONE, NULL); CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_INVALID); status = raw_smbcli_open(cli_dos->tree, "<\\bla", O_RDONLY, DENY_NONE, NULL); CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS, ERRinvalidname)); /* Let's test EEXIST error code mapping. */ status = raw_smbcli_open(cli_nt->tree, fpath, O_RDONLY | O_CREAT| O_EXCL, DENY_NONE, NULL); CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_COLLISION); status = raw_smbcli_open(cli_dos->tree, fpath, O_RDONLY | O_CREAT| O_EXCL, DENY_NONE, NULL); CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS,ERRfilexists)); status = raw_smbcli_t2open(cli_nt->tree, fpath, O_RDONLY | O_CREAT| O_EXCL, DENY_NONE, NULL); if (!NT_STATUS_EQUAL(status, NT_STATUS_EAS_NOT_SUPPORTED) || !torture_setting_bool(torture, "samba3", false)) { /* Against samba3, treat EAS_NOT_SUPPORTED as acceptable */ CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_COLLISION); } status = raw_smbcli_t2open(cli_dos->tree, fpath, O_RDONLY | O_CREAT| O_EXCL, DENY_NONE, NULL); if (!NT_STATUS_EQUAL(status, NT_STATUS_DOS(ERRDOS,ERReasnotsupported)) || !torture_setting_bool(torture, "samba3", false)) { /* Against samba3, treat EAS_NOT_SUPPORTED as acceptable */ CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS,ERRfilexists)); } status = raw_smbcli_ntcreate(cli_nt->tree, fpath, NULL); CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_COLLISION); status = raw_smbcli_ntcreate(cli_dos->tree, fpath, NULL); CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS,ERRfilexists)); /* Try the rename test. */ { union smb_rename io; memset(&io, '\0', sizeof(io)); io.rename.in.pattern1 = fpath1; io.rename.in.pattern2 = fpath; /* Try with SMBmv rename. */ status = smb_raw_rename(cli_nt->tree, &io); CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_COLLISION); status = smb_raw_rename(cli_dos->tree, &io); CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS,ERRrename)); /* Try with NT rename. */ io.generic.level = RAW_RENAME_NTRENAME; io.ntrename.in.old_name = fpath1; io.ntrename.in.new_name = fpath; io.ntrename.in.attrib = 0; io.ntrename.in.cluster_size = 0; io.ntrename.in.flags = RENAME_FLAG_RENAME; status = smb_raw_rename(cli_nt->tree, &io); CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_COLLISION); status = smb_raw_rename(cli_dos->tree, &io); CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS,ERRrename)); } goto done; fail: ret = false; done: if (cli_nt != NULL) { smbcli_deltree(cli_nt->tree, dirname); torture_close_connection(cli_nt); } if (cli_dos != NULL) { torture_close_connection(cli_dos); } talloc_free(mem_ctx); return ret; }
krb5_error_code kinit_to_ccache(TALLOC_CTX *parent_ctx, struct cli_credentials *credentials, struct smb_krb5_context *smb_krb5_context, krb5_ccache ccache) { krb5_error_code ret; const char *password; time_t kdc_time = 0; krb5_principal princ; int tries; TALLOC_CTX *mem_ctx = talloc_new(parent_ctx); if (!mem_ctx) { return ENOMEM; } ret = principal_from_credentials(mem_ctx, credentials, smb_krb5_context, &princ); if (ret) { talloc_free(mem_ctx); return ret; } password = cli_credentials_get_password(credentials); tries = 2; while (tries--) { if (password) { ret = kerberos_kinit_password_cc(smb_krb5_context->krb5_context, ccache, princ, password, NULL, &kdc_time); } else { /* No password available, try to use a keyblock instead */ krb5_keyblock keyblock; const struct samr_Password *mach_pwd; mach_pwd = cli_credentials_get_nt_hash(credentials, mem_ctx); if (!mach_pwd) { talloc_free(mem_ctx); DEBUG(1, ("kinit_to_ccache: No password available for kinit\n")); return EINVAL; } ret = krb5_keyblock_init(smb_krb5_context->krb5_context, ETYPE_ARCFOUR_HMAC_MD5, mach_pwd->hash, sizeof(mach_pwd->hash), &keyblock); if (ret == 0) { ret = kerberos_kinit_keyblock_cc(smb_krb5_context->krb5_context, ccache, princ, &keyblock, NULL, &kdc_time); krb5_free_keyblock_contents(smb_krb5_context->krb5_context, &keyblock); } } if (ret == KRB5KRB_AP_ERR_SKEW || ret == KRB5_KDCREP_SKEW) { /* Perhaps we have been given an invalid skew, so try again without it */ time_t t = time(NULL); krb5_set_real_time(smb_krb5_context->krb5_context, t, 0); } else { /* not a skew problem */ break; } } if (ret == KRB5KRB_AP_ERR_SKEW || ret == KRB5_KDCREP_SKEW) { DEBUG(1,("kinit for %s failed (%s)\n", cli_credentials_get_principal(credentials, mem_ctx), smb_get_krb5_error_message(smb_krb5_context->krb5_context, ret, mem_ctx))); talloc_free(mem_ctx); return ret; } /* cope with ticket being in the future due to clock skew */ if ((unsigned)kdc_time > time(NULL)) { time_t t = time(NULL); int time_offset =(unsigned)kdc_time-t; DEBUG(4,("Advancing clock by %d seconds to cope with clock skew\n", time_offset)); krb5_set_real_time(smb_krb5_context->krb5_context, t + time_offset + 1, 0); } if (ret == KRB5KDC_ERR_PREAUTH_FAILED && cli_credentials_wrong_password(credentials)) { ret = kinit_to_ccache(parent_ctx, credentials, smb_krb5_context, ccache); } if (ret) { DEBUG(1,("kinit for %s failed (%s)\n", cli_credentials_get_principal(credentials, mem_ctx), smb_get_krb5_error_message(smb_krb5_context->krb5_context, ret, mem_ctx))); talloc_free(mem_ctx); return ret; } talloc_free(mem_ctx); return 0; }
/* called by samr_CreateDomainGroup and pdb_samba4 */ NTSTATUS dsdb_add_domain_group(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const char *groupname, struct dom_sid **sid, struct ldb_dn **dn) { const char *name; struct ldb_message *msg; struct dom_sid *group_sid; int ret; TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx); NT_STATUS_HAVE_NO_MEMORY(tmp_ctx); /* check if the group already exists */ name = samdb_search_string(ldb, tmp_ctx, NULL, "sAMAccountName", "(&(sAMAccountName=%s)(objectclass=group))", ldb_binary_encode_string(tmp_ctx, groupname)); if (name != NULL) { return NT_STATUS_GROUP_EXISTS; } msg = ldb_msg_new(tmp_ctx); if (msg == NULL) { return NT_STATUS_NO_MEMORY; } /* add core elements to the ldb_message for the user */ msg->dn = ldb_dn_copy(tmp_ctx, ldb_get_default_basedn(ldb)); ldb_dn_add_child_fmt(msg->dn, "CN=%s,CN=Users", groupname); if (!msg->dn) { talloc_free(tmp_ctx); return NT_STATUS_NO_MEMORY; } ldb_msg_add_string(msg, "sAMAccountName", groupname); ldb_msg_add_string(msg, "objectClass", "group"); /* create the group */ ret = ldb_add(ldb, msg); switch (ret) { case LDB_SUCCESS: break; case LDB_ERR_ENTRY_ALREADY_EXISTS: DEBUG(0,("Failed to create group record %s: %s\n", ldb_dn_get_linearized(msg->dn), ldb_errstring(ldb))); talloc_free(tmp_ctx); return NT_STATUS_GROUP_EXISTS; case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS: DEBUG(0,("Failed to create group record %s: %s\n", ldb_dn_get_linearized(msg->dn), ldb_errstring(ldb))); talloc_free(tmp_ctx); return NT_STATUS_ACCESS_DENIED; default: DEBUG(0,("Failed to create group record %s: %s\n", ldb_dn_get_linearized(msg->dn), ldb_errstring(ldb))); talloc_free(tmp_ctx); return NT_STATUS_INTERNAL_DB_CORRUPTION; } /* retrieve the sid for the group just created */ group_sid = samdb_search_dom_sid(ldb, tmp_ctx, msg->dn, "objectSid", NULL); if (group_sid == NULL) { return NT_STATUS_UNSUCCESSFUL; } *dn = talloc_steal(mem_ctx, msg->dn); *sid = talloc_steal(mem_ctx, group_sid); talloc_free(tmp_ctx); return NT_STATUS_OK; }
static krb5_error_code keytab_add_keys(TALLOC_CTX *parent_ctx, const char *princ_string, krb5_principal princ, krb5_principal salt_princ, int kvno, const char *password_s, struct smb_krb5_context *smb_krb5_context, const char **enctype_strings, krb5_keytab keytab) { int i; krb5_error_code ret; krb5_data password; TALLOC_CTX *mem_ctx = talloc_new(parent_ctx); if (!mem_ctx) { return ENOMEM; } password.data = discard_const_p(char *, password_s); password.length = strlen(password_s); for (i=0; enctype_strings[i]; i++) { krb5_keytab_entry entry; krb5_enctype enctype; ret = krb5_string_to_enctype(smb_krb5_context->krb5_context, enctype_strings[i], &enctype); if (ret != 0) { DEBUG(1, ("Failed to interpret %s as a krb5 encryption type: %s\n", enctype_strings[i], smb_get_krb5_error_message(smb_krb5_context->krb5_context, ret, mem_ctx))); talloc_free(mem_ctx); return ret; } ret = create_kerberos_key_from_string(smb_krb5_context->krb5_context, salt_princ, &password, &entry.keyblock, enctype); if (ret != 0) { talloc_free(mem_ctx); return ret; } entry.principal = princ; entry.vno = kvno; ret = krb5_kt_add_entry(smb_krb5_context->krb5_context, keytab, &entry); if (ret != 0) { DEBUG(1, ("Failed to add %s entry for %s(kvno %d) to keytab: %s\n", enctype_strings[i], princ_string, kvno, smb_get_krb5_error_message(smb_krb5_context->krb5_context, ret, mem_ctx))); talloc_free(mem_ctx); krb5_free_keyblock_contents(smb_krb5_context->krb5_context, &entry.keyblock); return ret; } DEBUG(5, ("Added %s(kvno %d) to keytab (%s)\n", princ_string, kvno, enctype_strings[i])); krb5_free_keyblock_contents(smb_krb5_context->krb5_context, &entry.keyblock); } talloc_free(mem_ctx); return 0; }
NTSTATUS dsdb_add_domain_alias(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const char *alias_name, struct dom_sid **sid, struct ldb_dn **dn) { const char *name; struct ldb_message *msg; struct dom_sid *alias_sid; int ret; TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx); NT_STATUS_HAVE_NO_MEMORY(tmp_ctx); if (ldb_transaction_start(ldb) != LDB_SUCCESS) { DEBUG(0, ("Failed to start transaction in dsdb_add_domain_alias(): %s\n", ldb_errstring(ldb))); return NT_STATUS_INTERNAL_ERROR; } /* Check if alias already exists */ name = samdb_search_string(ldb, tmp_ctx, NULL, "sAMAccountName", "(sAMAccountName=%s)(objectclass=group))", ldb_binary_encode_string(mem_ctx, alias_name)); if (name != NULL) { talloc_free(tmp_ctx); ldb_transaction_cancel(ldb); return NT_STATUS_ALIAS_EXISTS; } msg = ldb_msg_new(tmp_ctx); if (msg == NULL) { talloc_free(tmp_ctx); ldb_transaction_cancel(ldb); return NT_STATUS_NO_MEMORY; } /* add core elements to the ldb_message for the alias */ msg->dn = ldb_dn_copy(mem_ctx, ldb_get_default_basedn(ldb)); ldb_dn_add_child_fmt(msg->dn, "CN=%s,CN=Users", alias_name); if (!msg->dn) { talloc_free(tmp_ctx); ldb_transaction_cancel(ldb); return NT_STATUS_NO_MEMORY; } ldb_msg_add_string(msg, "sAMAccountName", alias_name); ldb_msg_add_string(msg, "objectClass", "group"); samdb_msg_add_int(ldb, mem_ctx, msg, "groupType", GTYPE_SECURITY_DOMAIN_LOCAL_GROUP); /* create the alias */ ret = ldb_add(ldb, msg); switch (ret) { case LDB_SUCCESS: break; case LDB_ERR_ENTRY_ALREADY_EXISTS: talloc_free(tmp_ctx); ldb_transaction_cancel(ldb); return NT_STATUS_ALIAS_EXISTS; case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS: talloc_free(tmp_ctx); ldb_transaction_cancel(ldb); return NT_STATUS_ACCESS_DENIED; default: DEBUG(0,("Failed to create alias record %s: %s\n", ldb_dn_get_linearized(msg->dn), ldb_errstring(ldb))); talloc_free(tmp_ctx); ldb_transaction_cancel(ldb); return NT_STATUS_INTERNAL_DB_CORRUPTION; } /* retrieve the sid for the alias just created */ alias_sid = samdb_search_dom_sid(ldb, tmp_ctx, msg->dn, "objectSid", NULL); if (ldb_transaction_commit(ldb) != LDB_SUCCESS) { DEBUG(0, ("Failed to commit transaction in dsdb_add_domain_alias(): %s\n", ldb_errstring(ldb))); return NT_STATUS_INTERNAL_ERROR; } *dn = talloc_steal(mem_ctx, msg->dn); *sid = talloc_steal(mem_ctx, alias_sid); talloc_free(tmp_ctx); return NT_STATUS_OK; }
static int create_keytab(TALLOC_CTX *parent_ctx, struct cli_credentials *machine_account, struct smb_krb5_context *smb_krb5_context, const char **enctype_strings, krb5_keytab keytab, BOOL add_old) { krb5_error_code ret; const char *password_s; const char *old_secret; int kvno; krb5_principal salt_princ; krb5_principal princ; const char *princ_string; TALLOC_CTX *mem_ctx = talloc_new(parent_ctx); if (!mem_ctx) { return ENOMEM; } princ_string = cli_credentials_get_principal(machine_account, mem_ctx); /* Get the principal we will store the new keytab entries under */ ret = principal_from_credentials(mem_ctx, machine_account, smb_krb5_context, &princ); if (ret) { DEBUG(1,("create_keytab: makeing krb5 principal failed (%s)\n", smb_get_krb5_error_message(smb_krb5_context->krb5_context, ret, mem_ctx))); talloc_free(mem_ctx); return ret; } /* The salt used to generate these entries may be different however, fetch that */ ret = salt_principal_from_credentials(mem_ctx, machine_account, smb_krb5_context, &salt_princ); if (ret) { DEBUG(1,("create_keytab: makeing salt principal failed (%s)\n", smb_get_krb5_error_message(smb_krb5_context->krb5_context, ret, mem_ctx))); talloc_free(mem_ctx); return ret; } /* Finally, do the dance to get the password to put in the entry */ password_s = cli_credentials_get_password(machine_account); if (!password_s) { krb5_keytab_entry entry; const struct samr_Password *mach_pwd; if (!str_list_check(enctype_strings, "arcfour-hmac-md5")) { DEBUG(1, ("Asked to create keytab, but with only an NT hash supplied, " "but not listing arcfour-hmac-md5 as an enc type to include in the keytab!\n")); talloc_free(mem_ctx); return EINVAL; } /* If we don't have the plaintext password, try for * the MD4 password hash */ mach_pwd = cli_credentials_get_nt_hash(machine_account, mem_ctx); if (!mach_pwd) { /* OK, nothing to do here */ talloc_free(mem_ctx); return 0; } ret = krb5_keyblock_init(smb_krb5_context->krb5_context, ETYPE_ARCFOUR_HMAC_MD5, mach_pwd->hash, sizeof(mach_pwd->hash), &entry.keyblock); if (ret) { DEBUG(1, ("create_keytab: krb5_keyblock_init failed: %s\n", smb_get_krb5_error_message(smb_krb5_context->krb5_context, ret, mem_ctx))); talloc_free(mem_ctx); return ret; } entry.principal = princ; entry.vno = cli_credentials_get_kvno(machine_account); ret = krb5_kt_add_entry(smb_krb5_context->krb5_context, keytab, &entry); if (ret) { DEBUG(1, ("Failed to add ARCFOUR_HMAC (only) entry for %s to keytab: %s", cli_credentials_get_principal(machine_account, mem_ctx), smb_get_krb5_error_message(smb_krb5_context->krb5_context, ret, mem_ctx))); talloc_free(mem_ctx); krb5_free_keyblock_contents(smb_krb5_context->krb5_context, &entry.keyblock); return ret; } DEBUG(5, ("Added %s(kvno %d) to keytab (arcfour-hmac-md5)\n", cli_credentials_get_principal(machine_account, mem_ctx), cli_credentials_get_kvno(machine_account))); krb5_free_keyblock_contents(smb_krb5_context->krb5_context, &entry.keyblock); /* Can't go any further, we only have this one key */ talloc_free(mem_ctx); return 0; } kvno = cli_credentials_get_kvno(machine_account); /* good, we actually have the real plaintext */ ret = keytab_add_keys(mem_ctx, princ_string, princ, salt_princ, kvno, password_s, smb_krb5_context, enctype_strings, keytab); if (!ret) { talloc_free(mem_ctx); return ret; } if (!add_old || kvno == 0) { talloc_free(mem_ctx); return 0; } old_secret = cli_credentials_get_old_password(machine_account); if (!old_secret) { talloc_free(mem_ctx); return 0; } ret = keytab_add_keys(mem_ctx, princ_string, princ, salt_princ, kvno - 1, old_secret, smb_krb5_context, enctype_strings, keytab); if (!ret) { talloc_free(mem_ctx); return ret; } talloc_free(mem_ctx); return 0; }
NTSTATUS dsdb_lookup_rids(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const struct dom_sid *domain_sid, unsigned int num_rids, uint32_t *rids, const char **names, enum lsa_SidType *lsa_attrs) { const char *attrs[] = { "sAMAccountType", "sAMAccountName", NULL }; unsigned int i, num_mapped; TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx); NT_STATUS_HAVE_NO_MEMORY(tmp_ctx); num_mapped = 0; for (i=0; i<num_rids; i++) { struct ldb_message *msg; struct ldb_dn *dn; uint32_t attr; int rc; lsa_attrs[i] = SID_NAME_UNKNOWN; dn = ldb_dn_new_fmt(tmp_ctx, ldb, "<SID=%s>", dom_sid_string(tmp_ctx, dom_sid_add_rid(tmp_ctx, domain_sid, rids[i]))); if (dn == NULL) { talloc_free(tmp_ctx); return NT_STATUS_NO_MEMORY; } rc = dsdb_search_one(ldb, tmp_ctx, &msg, dn, LDB_SCOPE_BASE, attrs, 0, "samAccountName=*"); if (rc == LDB_ERR_NO_SUCH_OBJECT) { continue; } else if (rc != LDB_SUCCESS) { talloc_free(tmp_ctx); return NT_STATUS_INTERNAL_DB_CORRUPTION; } names[i] = ldb_msg_find_attr_as_string(msg, "samAccountName", NULL); if (names[i] == NULL) { DEBUG(10, ("no samAccountName\n")); continue; } talloc_steal(names, names[i]); attr = ldb_msg_find_attr_as_uint(msg, "samAccountType", 0); lsa_attrs[i] = ds_atype_map(attr); if (lsa_attrs[i] == SID_NAME_UNKNOWN) { continue; } num_mapped += 1; } talloc_free(tmp_ctx); if (num_mapped == 0) { return NT_STATUS_NONE_MAPPED; } if (num_mapped < num_rids) { return STATUS_SOME_UNMAPPED; } return NT_STATUS_OK; }
static krb5_error_code remove_old_entries(TALLOC_CTX *parent_ctx, struct cli_credentials *machine_account, struct smb_krb5_context *smb_krb5_context, krb5_keytab keytab, BOOL *found_previous) { krb5_error_code ret, ret2; krb5_kt_cursor cursor; krb5_principal princ; int kvno; TALLOC_CTX *mem_ctx = talloc_new(parent_ctx); const char *princ_string; if (!mem_ctx) { return ENOMEM; } *found_previous = False; princ_string = cli_credentials_get_principal(machine_account, mem_ctx); /* Get the principal we will store the new keytab entries under */ ret = principal_from_credentials(mem_ctx, machine_account, smb_krb5_context, &princ); if (ret) { DEBUG(1,("update_keytab: makeing krb5 principal failed (%s)\n", smb_get_krb5_error_message(smb_krb5_context->krb5_context, ret, mem_ctx))); talloc_free(mem_ctx); return ret; } kvno = cli_credentials_get_kvno(machine_account); /* for each entry in the keytab */ ret = krb5_kt_start_seq_get(smb_krb5_context->krb5_context, keytab, &cursor); switch (ret) { case 0: break; case HEIM_ERR_OPNOTSUPP: case ENOENT: case KRB5_KT_END: /* no point enumerating if there isn't anything here */ talloc_free(mem_ctx); return 0; default: DEBUG(1,("failed to open keytab for read of old entries: %s\n", smb_get_krb5_error_message(smb_krb5_context->krb5_context, ret, mem_ctx))); talloc_free(mem_ctx); return ret; } while (!ret) { krb5_keytab_entry entry; ret = krb5_kt_next_entry(smb_krb5_context->krb5_context, keytab, &entry, &cursor); if (ret) { break; } /* if it matches our principal */ if (!krb5_kt_compare(smb_krb5_context->krb5_context, &entry, princ, 0, 0)) { /* Free the entry, it wasn't the one we were looking for anyway */ krb5_kt_free_entry(smb_krb5_context->krb5_context, &entry); continue; } /* delete it, if it is not kvno -1 */ if (entry.vno != (kvno - 1 )) { /* Release the enumeration. We are going to * have to start this from the top again, * because deletes during enumeration may not * always be consistant. * * Also, the enumeration locks a FILE: keytab */ krb5_kt_end_seq_get(smb_krb5_context->krb5_context, keytab, &cursor); ret = krb5_kt_remove_entry(smb_krb5_context->krb5_context, keytab, &entry); krb5_kt_free_entry(smb_krb5_context->krb5_context, &entry); /* Deleted: Restart from the top */ ret2 = krb5_kt_start_seq_get(smb_krb5_context->krb5_context, keytab, &cursor); if (ret2) { krb5_kt_free_entry(smb_krb5_context->krb5_context, &entry); DEBUG(1,("failed to restart enumeration of keytab: %s\n", smb_get_krb5_error_message(smb_krb5_context->krb5_context, ret, mem_ctx))); talloc_free(mem_ctx); return ret2; } if (ret) { break; } } else { *found_previous = True; } /* Free the entry, we don't need it any more */ krb5_kt_free_entry(smb_krb5_context->krb5_context, &entry); } krb5_kt_end_seq_get(smb_krb5_context->krb5_context, keytab, &cursor); switch (ret) { case 0: break; case ENOENT: case KRB5_KT_END: ret = 0; break; default: DEBUG(1,("failed in deleting old entries for principal: %s: %s\n", princ_string, smb_get_krb5_error_message(smb_krb5_context->krb5_context, ret, mem_ctx))); } talloc_free(mem_ctx); return ret; }
int main (int argc, char *argv[]) { void *local; command_t *command; alias_t *alias; unsigned int i, j; const char **argv_local; talloc_enable_null_tracking (); local = talloc_new (NULL); g_mime_init (0); g_type_init (); if (argc == 1) return notmuch (local); if (STRNCMP_LITERAL (argv[1], "--help") == 0) return notmuch_help_command (NULL, 0, NULL); if (STRNCMP_LITERAL (argv[1], "--version") == 0) { printf ("notmuch " STRINGIFY(NOTMUCH_VERSION) "\n"); return 0; } for (i = 0; i < ARRAY_SIZE (aliases); i++) { alias = &aliases[i]; if (strcmp (argv[1], alias->name) == 0) { int substitutions; argv_local = talloc_size (local, sizeof (char *) * (argc + MAX_ALIAS_SUBSTITUTIONS - 1)); if (argv_local == NULL) { fprintf (stderr, "Out of memory.\n"); return 1; } /* Copy all substution arguments from the alias. */ argv_local[0] = argv[0]; for (j = 0; j < MAX_ALIAS_SUBSTITUTIONS; j++) { if (alias->substitutions[j] == NULL) break; argv_local[j+1] = alias->substitutions[j]; } substitutions = j; /* And copy all original arguments (skipping the argument * that matched the alias of course. */ for (j = 2; j < (unsigned) argc; j++) { argv_local[substitutions+j-1] = argv[j]; } argc += substitutions - 1; argv = (char **) argv_local; } } for (i = 0; i < ARRAY_SIZE (commands); i++) { command = &commands[i]; if (strcmp (argv[1], command->name) == 0) return (command->function) (local, argc - 2, &argv[2]); } fprintf (stderr, "Error: Unknown command '%s' (see \"notmuch help\")\n", argv[1]); talloc_free (local); return 1; }
static NTSTATUS check_samba4_security(const struct auth_context *auth_context, void *my_private_data, TALLOC_CTX *mem_ctx, const struct auth_usersupplied_info *user_info, struct auth_serversupplied_info **server_info) { TALLOC_CTX *frame = talloc_stackframe(); struct netr_SamInfo3 *info3 = NULL; NTSTATUS nt_status; struct auth_user_info_dc *user_info_dc; struct auth4_context *auth4_context; struct loadparm_context *lp_ctx; lp_ctx = loadparm_init_s3(frame, loadparm_s3_context()); if (lp_ctx == NULL) { DEBUG(10, ("loadparm_init_s3 failed\n")); talloc_free(frame); return NT_STATUS_INVALID_SERVER_STATE; } /* We create a private tevent context here to avoid nested loops in * the s3 one, as that may not be expected */ nt_status = auth_context_create(mem_ctx, s4_event_context_init(frame), NULL, lp_ctx, &auth4_context); NT_STATUS_NOT_OK_RETURN(nt_status); nt_status = auth_context_set_challenge(auth4_context, auth_context->challenge.data, "auth_samba4"); NT_STATUS_NOT_OK_RETURN_AND_FREE(nt_status, auth4_context); nt_status = auth_check_password(auth4_context, auth4_context, user_info, &user_info_dc); NT_STATUS_NOT_OK_RETURN_AND_FREE(nt_status, auth4_context); nt_status = auth_convert_user_info_dc_saminfo3(mem_ctx, user_info_dc, &info3); if (NT_STATUS_IS_OK(nt_status)) { /* We need the strings from the server_info to be valid as long as the info3 is around */ talloc_steal(info3, user_info_dc); } talloc_free(auth4_context); if (!NT_STATUS_IS_OK(nt_status)) { goto done; } nt_status = make_server_info_info3(mem_ctx, user_info->client.account_name, user_info->mapped.domain_name, server_info, info3); if (!NT_STATUS_IS_OK(nt_status)) { DEBUG(10, ("make_server_info_info3 failed: %s\n", nt_errstr(nt_status))); TALLOC_FREE(frame); return nt_status; } nt_status = NT_STATUS_OK; done: TALLOC_FREE(frame); return nt_status; }